diff --git a/Source/Core/DSPCore/Src/DSPAccelerator.cpp b/Source/Core/DSPCore/Src/DSPAccelerator.cpp index 75e1821476..f4739a0910 100644 --- a/Source/Core/DSPCore/Src/DSPAccelerator.cpp +++ b/Source/Core/DSPCore/Src/DSPAccelerator.cpp @@ -72,11 +72,11 @@ u16 dsp_read_aram_d3() u32 Address = (g_dsp.ifx_regs[DSP_ACCAH] << 16) | g_dsp.ifx_regs[DSP_ACCAL]; u16 val = 0; switch (g_dsp.ifx_regs[DSP_FORMAT]) { - case 0x5: // unsigned 8-bit reads .. I think. + case 0x5: // u8 reads val = DSPHost_ReadHostMemory(Address); Address++; break; - case 0x6: // unsigned 16-bit reads .. I think. + case 0x6: // u16 reads val = (DSPHost_ReadHostMemory(Address) << 8) | DSPHost_ReadHostMemory(Address + 1); Address += 2; break; @@ -132,24 +132,22 @@ u16 dsp_read_accelerator() case 0x00: // ADPCM audio val = ADPCM_Step(Address); break; - case 0x0A: // 16-bit PCM audio val = (DSPHost_ReadHostMemory(Address) << 8) | DSPHost_ReadHostMemory(Address + 1); - g_dsp.ifx_regs[DSP_YN2] = g_dsp.ifx_regs[DSP_YN1]; g_dsp.ifx_regs[DSP_YN1] = val; - Address += 2; break; - default: - val = (DSPHost_ReadHostMemory(Address) << 8) | DSPHost_ReadHostMemory(Address + 1); - Address += 2; - ERROR_LOG(DSPLLE, "Unknown DSP Format %i", g_dsp.ifx_regs[DSP_FORMAT]); + ERROR_LOG(DSPLLE, "Unknown DSP Format %x", g_dsp.ifx_regs[DSP_FORMAT]); break; } // TODO: Take GAIN into account, whatever it is. + if (g_dsp.ifx_regs[DSP_GAIN] > 0) + { + //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]); + } // Check for loop. if (Address >= EndAddress) diff --git a/Source/Core/DSPCore/Src/DSPCore.h b/Source/Core/DSPCore/Src/DSPCore.h index 0e093f57d4..b38aa7b7e6 100644 --- a/Source/Core/DSPCore/Src/DSPCore.h +++ b/Source/Core/DSPCore/Src/DSPCore.h @@ -150,19 +150,22 @@ // SR bits -#define SR_CARRY 0x0001 -#define SR_OVERFLOW 0x0002 -#define SR_ARITH_ZERO 0x0004 -#define SR_SIGN 0x0008 -#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_80 0x0080 // Unknown, set by add, sub -#define SR_INT_ENABLE 0x0200 // Not 100% sure but duddie says so. This should replace the hack, if so. +#define SR_CARRY 0x0001 +#define SR_OVERFLOW 0x0002 +#define SR_ARITH_ZERO 0x0004 +#define SR_SIGN 0x0008 +#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_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 #define SR_EXT_INT_ENABLE 0x0800 // Appears in zelda - seems to disable external interupts -#define SR_MUL_MODIFY 0x2000 // 1 = normal. 0 = x2 (M0, M2) -#define SR_40_MODE_BIT 0x4000 // 0 = "16", 1 = "40" (SET16, SET40) Controls sign extension when loading mid accums. -#define SR_MUL_UNSIGNED 0x8000 // 0 = normal. 1 = unsigned (CLR15, SET15) If set, treats operands as unsigned. Tested with mulx only so far. +#define SR_1000 0x1000 // unknown +#define SR_MUL_MODIFY 0x2000 // 1 = normal. 0 = x2 (M0, M2) +#define SR_40_MODE_BIT 0x4000 // 0 = "16", 1 = "40" (SET16, SET40) Controls sign extension when loading mid accums. +#define SR_MUL_UNSIGNED 0x8000 // 0 = normal. 1 = unsigned (CLR15, SET15) If set, treats operands as unsigned. Tested with mulx only so far. // This should be the bits affected by CMP. Does not include logic zero. #define SR_CMP_MASK 0x3f diff --git a/Source/Core/DSPCore/Src/DSPHWInterface.cpp b/Source/Core/DSPCore/Src/DSPHWInterface.cpp index 9ffeb9158a..e8c7aefc58 100644 --- a/Source/Core/DSPCore/Src/DSPHWInterface.cpp +++ b/Source/Core/DSPCore/Src/DSPHWInterface.cpp @@ -133,7 +133,7 @@ void gdsp_ifx_write(u16 addr, u16 val) if (val & 0x1) DSPHost_InterruptRequest(); else - ERROR_LOG(DSPLLE, "Unknown Interrupt Request pc=%04x (%04x)", g_dsp.pc, val); + INFO_LOG(DSPLLE, "Unknown Interrupt Request pc=%04x (%04x)", g_dsp.pc, val); break; case 0xfc: // DMBH @@ -156,14 +156,14 @@ void gdsp_ifx_write(u16 addr, u16 val) g_dsp.ifx_regs[DSP_DSCR] &= ~0x0004; break; - case 0xd3: // ZeldaUnk (accelerator WRITE) - // NOTICE_LOG(DSPLLE, "Write To ZeldaUnk pc=%04x (%04x)", g_dsp.pc, val); + case 0xd3: // Accelerator write (Zelda type) - "UnkZelda" dsp_write_aram_d3(val); break; - case 0xde: - //if (val) - // PanicAlert("Gain written: %04x", val); // BMX XXX does, and sounds HORRIBLE. + case 0xde: // BMX XXX does, and sounds HORRIBLE. / Spyro - A Hero's Tail / Sega GC games / Wiiware - World of Goo + if (val) { + INFO_LOG(DSPLLE,"Gain Written: 0x%04x", val); + } case 0xcd: case 0xce: case 0xcf: @@ -210,8 +210,7 @@ u16 gdsp_ifx_read(u16 addr) case 0xdd: // ADPCM Accelerator reads return dsp_read_accelerator(); - case 0xd3: - //NOTICE_LOG(DSPLLE, "Read from ZeldaUnk pc=%04x", g_dsp.pc); + case 0xd3: // Accelerator reads (Zelda type) - "UnkZelda" return dsp_read_aram_d3(); default: diff --git a/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp b/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp index c62aa25637..b5b2366196 100644 --- a/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp +++ b/Source/Core/DSPCore/Src/DSPIntCCUtil.cpp @@ -28,7 +28,6 @@ namespace DSPInterpreter { void Update_SR_Register64(s64 _Value, bool carry, bool overflow) { - // TODO: recheck 0x1,0x2,even 0x80... implement... g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK; // 0x01 @@ -37,10 +36,11 @@ void Update_SR_Register64(s64 _Value, bool carry, bool overflow) g_dsp.r[DSP_REG_SR] |= SR_CARRY; } - // 0x02 + // 0x02 and 0x80 if (overflow) { g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW; + g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW_SPECIAL; } // 0x04 @@ -66,16 +66,11 @@ void Update_SR_Register64(s64 _Value, bool carry, bool overflow) { g_dsp.r[DSP_REG_SR] |= SR_TOP2BITS; } - - // 0x80 - { - } } void Update_SR_Register16(s16 _Value, bool carry, bool overflow, bool overS32) { - // TODO: recheck 0x1,0x2,even 0x80... implement... g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK; // 0x01 @@ -84,12 +79,13 @@ void Update_SR_Register16(s16 _Value, bool carry, bool overflow, bool overS32) g_dsp.r[DSP_REG_SR] |= SR_CARRY; } - // 0x02 + // 0x02 and 0x80 if (overflow) { g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW; + g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW_SPECIAL; } - + // 0x04 if (_Value == 0) { @@ -113,10 +109,6 @@ void Update_SR_Register16(s16 _Value, bool carry, bool overflow, bool overS32) { g_dsp.r[DSP_REG_SR] |= SR_TOP2BITS; } - - // 0x80 - { - } } void Update_SR_LZ(bool value) { diff --git a/Source/Core/DSPCore/Src/DSPIntCCUtil.h b/Source/Core/DSPCore/Src/DSPIntCCUtil.h index b1b622de85..0684cea2ba 100644 --- a/Source/Core/DSPCore/Src/DSPIntCCUtil.h +++ b/Source/Core/DSPCore/Src/DSPIntCCUtil.h @@ -34,12 +34,12 @@ void Update_SR_Register16(s16 _Value, bool carry = false, bool overflow = false, void Update_SR_Register64(s64 _Value, bool carry = false, bool overflow = false); void Update_SR_LZ(bool value); -inline bool isAddCarry(u64 val, u64 result) { - return (val > result); +inline bool isCarry(u64 val, u64 result) { + return (val>result); } -inline bool isSubCarry(u64 val, u64 result) { - return (val < result); +inline bool isCarry2(u64 val, u64 result) { + return (val>=result); } inline bool isOverflow(s64 val1, s64 val2, s64 res) { diff --git a/Source/Core/DSPCore/Src/DSPIntExtOps.cpp b/Source/Core/DSPCore/Src/DSPIntExtOps.cpp index e707c4750d..76a30b4e61 100644 --- a/Source/Core/DSPCore/Src/DSPIntExtOps.cpp +++ b/Source/Core/DSPCore/Src/DSPIntExtOps.cpp @@ -480,7 +480,27 @@ void zeroWriteBackLog() { // always make sure to have an extra entry at the end w/ -1 to avoid // infinitive loops - for (int i = 0; writeBackLogIdx[i] != -1; i++) + for (int i = 0; writeBackLogIdx[i] != -1; i++) { dsp_op_write_reg(writeBackLogIdx[i], 0); + } } +//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... +void zeroWriteBackLogPreserveAcc(u8 acc) +{ + for (int i = 0; writeBackLogIdx[i] != -1; i++) { + + // acc0 + if ((acc == 0) && + ((writeBackLogIdx[i] == DSP_REG_ACL0) || (writeBackLogIdx[i] == DSP_REG_ACM0) || (writeBackLogIdx[i] == DSP_REG_ACH0))) + continue; + + // acc1 + if ((acc == 1) && + ((writeBackLogIdx[i] == DSP_REG_ACL1) || (writeBackLogIdx[i] == DSP_REG_ACM1) || (writeBackLogIdx[i] == DSP_REG_ACH1))) + continue; + + dsp_op_write_reg(writeBackLogIdx[i], 0); + } +} diff --git a/Source/Core/DSPCore/Src/DSPIntUtil.h b/Source/Core/DSPCore/Src/DSPIntUtil.h index 8d63aa578e..bb34326c2c 100644 --- a/Source/Core/DSPCore/Src/DSPIntUtil.h +++ b/Source/Core/DSPCore/Src/DSPIntUtil.h @@ -37,6 +37,7 @@ // --------------------------------------------------------------------------------------- // --- SR // --------------------------------------------------------------------------------------- + inline void dsp_SR_set_flag(int flag) { g_dsp.r[DSP_REG_SR] |= flag; @@ -47,9 +48,13 @@ inline bool dsp_SR_is_flag_set(int flag) return (g_dsp.r[DSP_REG_SR] & flag) != 0; } - +// --------------------------------------------------------------------------------------- +// --- AR increments, decrements +// --------------------------------------------------------------------------------------- +// // HORRIBLE UGLINESS, someone please fix. // See http://code.google.com/p/dolphin-emu/source/detail?r=3125 + inline u16 ToMask(u16 a) { a = a | (a >> 8); @@ -112,6 +117,24 @@ inline s16 dsp_increase_addr_reg(int reg, s16 value) return tmp; } +inline s16 dsp_decrease_addr_reg(int reg, s16 value) +{ + s16 tmp = - 1; + + // TODO: DO RIGHT! + if (value > 0) { + for (int i = 0; i < value; i++) { + tmp = dsp_decrement_addr_reg(reg, tmp); + } + } else if (value < 0) { + for (int i = 0; i < (int)(-value); i++) { + tmp = dsp_increment_addr_reg(reg, tmp); + } + } else + tmp = g_dsp.r[reg]; + + return tmp; +} // --------------------------------------------------------------------------------------- // --- reg @@ -143,18 +166,8 @@ inline void dsp_op_write_reg(int reg, u16 val) case DSP_REG_ACM0: case DSP_REG_ACM1: g_dsp.r[reg] = val; - // Enabling the below sign extension code breaks things. - // There's probably some condition that enable it, maybe one of - // the status flags like M2. - // Or maybe it only happens when this call is a result of 'l and similar extended opcodes. - - // Sign extend the loaded register. ACM0 - // g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACH0] = ((s16)val < 0 ? 0xFFFF : 0); - // g_dsp.r[reg - DSP_REG_ACM0 + DSP_REG_ACL0] = 0; // ? break; - // There might also be something similar for AX.L but I'm not at all sure about that. - // Stack registers. case DSP_REG_ST0: case DSP_REG_ST1: @@ -262,21 +275,18 @@ inline s16 dsp_get_acc_l(int _reg) return g_dsp.r[DSP_REG_ACL0 + _reg]; } - inline s16 dsp_get_acc_m(int _reg) { _assert_(_reg < 2); return g_dsp.r[DSP_REG_ACM0 + _reg]; } - inline s16 dsp_get_acc_h(int _reg) { _assert_(_reg < 2); return g_dsp.r[DSP_REG_ACH0 + _reg]; } - // --------------------------------------------------------------------------------------- // --- AX - extra accumulators (32-bit) // --------------------------------------------------------------------------------------- diff --git a/Source/Core/DSPCore/Src/DSPInterpreter.cpp b/Source/Core/DSPCore/Src/DSPInterpreter.cpp index de226c62c8..9d77f41d1e 100644 --- a/Source/Core/DSPCore/Src/DSPInterpreter.cpp +++ b/Source/Core/DSPCore/Src/DSPInterpreter.cpp @@ -73,6 +73,7 @@ u16 ReadCR() void Step() { + DSPCore_CheckExternalInterrupt(); DSPCore_CheckExceptions(); g_dsp.step_counter++; @@ -91,12 +92,7 @@ void Step() ProfilerDump(g_dsp.step_counter); } #endif -/* - //Pikmin GC (US) - if (g_dsp.pc == 0x0506) - NOTICE_LOG(DSPLLE,"-> FORMAT JUMPTABLE --> pc:=%04x,ac0.m:=%04x,ac1.m:=%04x", g_dsp.pc, dsp_get_acc_m(0), dsp_get_acc_m(1)); -*/ - + u16 opc = dsp_fetch_code(); ExecuteInstruction(UDSPInstruction(opc)); HandleLoop(); @@ -141,7 +137,7 @@ int RunCyclesDebug(int cycles) return 0; } - DSPCore_CheckExternalInterrupt(); + //DSPCore_CheckExternalInterrupt(); // Now, let's run a few cycles with idle skipping. for (int i = 0; i < 8; i++) @@ -181,23 +177,7 @@ int RunCyclesDebug(int cycles) // Used by non-thread mode. Meant to be efficient. int RunCycles(int cycles) { - DSPCore_CheckExternalInterrupt(); - - if (cycles < 18) - { - for (int i = 0; i < cycles; i++) - { - if (g_dsp.cr & CR_HALT) - return 0; - if (DSPAnalyzer::code_flags[g_dsp.pc] & DSPAnalyzer::CODE_IDLE_SKIP) - return 0; - Step(); - cycles--; - } - return cycles; - } - - DSPCore_CheckExternalInterrupt(); + //DSPCore_CheckExternalInterrupt(); // First, let's run a few cycles with no idle skipping so that things can progress a bit. for (int i = 0; i < 8; i++) diff --git a/Source/Core/DSPCore/Src/DSPInterpreter.h b/Source/Core/DSPCore/Src/DSPInterpreter.h index 133725eb72..84a575e82a 100644 --- a/Source/Core/DSPCore/Src/DSPInterpreter.h +++ b/Source/Core/DSPCore/Src/DSPInterpreter.h @@ -20,6 +20,8 @@ #include "DSPTables.h" +#define PRECISE_SR_FLAGS + #define DSP_REG_MASK 0x1f namespace DSPInterpreter { @@ -95,7 +97,6 @@ void lsrnrx(const UDSPInstruction& opc); void asrnrx(const UDSPInstruction& opc); void lsrnr(const UDSPInstruction& opc); void asrnr(const UDSPInstruction& opc); -void orf(const UDSPInstruction& opc); void add(const UDSPInstruction& opc); void addp(const UDSPInstruction& opc); void cmpis(const UDSPInstruction& opc); @@ -126,7 +127,7 @@ void lsrn(const UDSPInstruction& opc); void asrn(const UDSPInstruction& opc); void dar(const UDSPInstruction& opc); void iar(const UDSPInstruction& opc); -void xar(const UDSPInstruction& opc); +void subarn(const UDSPInstruction& opc); void sbclr(const UDSPInstruction& opc); void sbset(const UDSPInstruction& opc); void mov(const UDSPInstruction& opc); @@ -161,22 +162,12 @@ void andf(const UDSPInstruction& opc); void xori(const UDSPInstruction& opc); void andi(const UDSPInstruction& opc); void ori(const UDSPInstruction& opc); +void srbith(const UDSPInstruction& opc); void mulaxh(const UDSPInstruction& opc); void tstprod(const UDSPInstruction& opc); -// FIXME inside -void srbith(const UDSPInstruction& opc); - -// END OF FIXMEs - -// TODO: PENDING IMPLEMENTATION / UNIMPLEMENTED -void tstaxl(const UDSPInstruction& opc); -// The mysterious a100 - -// END OF UNIMPLEMENTED - -// Helpers -inline void tsta(int reg); +//mia +void a100(const UDSPInstruction& opc); } // namespace diff --git a/Source/Core/DSPCore/Src/DSPTables.cpp b/Source/Core/DSPCore/Src/DSPTables.cpp index 247f4027de..6c126bc123 100644 --- a/Source/Core/DSPCore/Src/DSPTables.cpp +++ b/Source/Core/DSPCore/Src/DSPTables.cpp @@ -31,18 +31,13 @@ void nop(const UDSPInstruction& opc) DSPInterpreter::unknown(opc); } -// Unknown Ops -// All AX games: a100 - -// TODO: Fill up the tables with the corresponding instructions const DSPOPCTemplate opcodes[] = { - {"NOP", 0x0000, 0xffff, nop, nop, 1, 0, {}, false}, + {"NOP", 0x0000, 0xfffc, nop, nop, 1, 0, {}, false}, {"DAR", 0x0004, 0xfffc, DSPInterpreter::dar, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false}, {"IAR", 0x0008, 0xfffc, DSPInterpreter::iar, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false}, - {"XAR", 0x000c, 0xfffc, DSPInterpreter::xar, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false}, - + {"SUBARN", 0x000c, 0xfffc, DSPInterpreter::subarn, nop, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false}, {"ADDARN", 0x0010, 0xfff0, DSPInterpreter::addarn, nop, 1, 2, {{P_REG, 1, 0, 0, 0x0003}, {P_REG04, 1, 0, 2, 0x000c}}, false}, {"HALT", 0x0021, 0xffff, DSPInterpreter::halt, nop, 1, 0, {}, false}, @@ -120,8 +115,8 @@ const DSPOPCTemplate opcodes[] = {"CALLRLZ", 0x171d, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false}, {"CALLR", 0x171f, 0xff1f, DSPInterpreter::callr, nop, 1, 1, {{P_REG, 1, 0, 5, 0x00e0}}, false}, - {"SBCLR", 0x1200, 0xfff8, DSPInterpreter::sbclr, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, false}, - {"SBSET", 0x1300, 0xfff8, DSPInterpreter::sbset, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, false}, + {"SBCLR", 0x1200, 0xff00, DSPInterpreter::sbclr, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, false}, + {"SBSET", 0x1300, 0xff00, DSPInterpreter::sbset, nop, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, false}, {"LSL", 0x1400, 0xfec0, DSPInterpreter::lsl, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, false}, {"LSR", 0x1440, 0xfec0, DSPInterpreter::lsr, nop, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, false}, @@ -151,7 +146,6 @@ const DSPOPCTemplate opcodes[] = {"ANDF", 0x02a0, 0xfeff, DSPInterpreter::andf, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false}, {"ANDCF", 0x02c0, 0xfeff, DSPInterpreter::andcf, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false}, - {"ORF", 0x02e0, 0xfeff, DSPInterpreter::orf, nop, 2, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_IMM, 2, 1, 0, 0xffff}}, false}, // Hermes: ??? (has it commented out) {"ILRR", 0x0210, 0xfefc, DSPInterpreter::ilrr, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, false}, {"ILRRD", 0x0214, 0xfefc, DSPInterpreter::ilrrd, nop, 1, 2, {{P_ACCM, 1, 0, 8, 0x0100}, {P_PRG, 1, 0, 0, 0x0003}}, false}, // Hermes doesn't list this @@ -244,14 +238,13 @@ 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 (!!!retest TST/TSTAXL!!!) + //a-b (!figure out 0xa100/0xa900!) {"MULX", 0xa000, 0xe700, DSPInterpreter::mulx, nop, 1 | P_EXT, 2, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}}, true}, - {"TST", 0xa100, 0xe700, DSPInterpreter::tst, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, true}, - //{"TSTAXL", 0xa100, 0xff00, DSPInterpreter::tstaxl, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, true}, //Definitely not TSTAXL, it affects one of the accumulators - //{"TST", 0xb100, 0xf700, DSPInterpreter::tst, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 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 {"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}, + {"TST", 0xb100, 0xf700, DSPInterpreter::tst, nop, 1 | P_EXT, 1, {{P_ACC, 1, 0, 11, 0x0800}}, true}, //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}, diff --git a/Source/Core/DSPCore/Src/DSPTables.h b/Source/Core/DSPCore/Src/DSPTables.h index 8f687a65fc..6180d2543c 100644 --- a/Source/Core/DSPCore/Src/DSPTables.h +++ b/Source/Core/DSPCore/Src/DSPTables.h @@ -155,6 +155,7 @@ const char *pdregnamelong(int val); void InitInstructionTable(); void applyWriteBackLog(); void zeroWriteBackLog(); +void zeroWriteBackLogPreserveAcc(u8 acc); inline void ExecuteInstruction(const UDSPInstruction& inst) { diff --git a/Source/Core/DSPCore/Src/DspIntArithmetic.cpp b/Source/Core/DSPCore/Src/DspIntArithmetic.cpp index 3c02cf8176..20fff1ae41 100644 --- a/Source/Core/DSPCore/Src/DspIntArithmetic.cpp +++ b/Source/Core/DSPCore/Src/DspIntArithmetic.cpp @@ -28,81 +28,724 @@ namespace DSPInterpreter { // CLR $acR // 1000 r001 xxxx xxxx // Clears accumulator $acR +// +// flags out: --10 0100 void clr(const UDSPInstruction& opc) { u8 reg = (opc.hex >> 11) & 0x1; dsp_set_long_acc(reg, 0); +#ifdef PRECISE_SR_FLAGS Update_SR_Register64(0); +#endif zeroWriteBackLog(); } // CLRL $acR.l // 1111 110r xxxx xxxx // Clears $acR.l - low 16 bits of accumulator $acR. +// +// flags out: --xx xx00 void clrl(const UDSPInstruction& opc) { u8 reg = (opc.hex >> 8) & 0x1; - g_dsp.r[DSP_REG_ACL0 + reg] = 0; - Update_SR_Register64(dsp_get_long_acc(reg)); - zeroWriteBackLog(); + g_dsp.r[DSP_REG_ACL0 + reg] = 0; +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(reg)); +#endif + zeroWriteBackLogPreserveAcc(reg); } +//---- -// ADDAXL $acD, $axS.l -// 0111 00sd xxxx xxxx -// Adds secondary accumulator $axS.l to accumulator register $acD. -void addaxl(const UDSPInstruction& opc) +// ANDCF $acD.m, #I +// 0000 001r 1100 0000 +// iiii iiii iiii iiii +// Set logic zero (LZ) flag in status register $sr if result of logic AND of +// accumulator mid part $acD.m with immediate value I is equal I. +// +// flags out: -x-- ---- +void andcf(const UDSPInstruction& opc) { - u8 sreg = (opc.hex >> 9) & 0x1; - u8 dreg = (opc.hex >> 8) & 0x1; + u8 reg = (opc.hex >> 8) & 0x1; - u64 acc = (u64)dsp_get_long_acc(dreg); - u16 acx = (u16)dsp_get_ax_l(sreg); + u16 imm = dsp_fetch_code(); + u16 val = dsp_get_acc_m(reg); + Update_SR_LZ(((val & imm) == imm) ? true : false); +} - acc += acx; +// ANDF $acD.m, #I +// 0000 001r 1010 0000 +// iiii iiii iiii iiii +// Set logic zero (LZ) flag in status register $sr if result of logical AND +// operation of accumulator mid part $acD.m with immediate value I is equal +// immediate value 0. +// +// flags out: -x-- ---- +void andf(const UDSPInstruction& opc) +{ + u8 reg = (opc.hex >> 8) & 0x1; + u16 imm = dsp_fetch_code(); + u16 val = dsp_get_acc_m(reg); + Update_SR_LZ(((val & imm) == 0) ? true : false); +} + +//---- + +// TST +// 1011 r001 xxxx xxxx +// Test accumulator %acR. +// +// flags out: xx xx00 +void tst(const UDSPInstruction& opc) +{ + u8 reg = (opc.hex >> 11) & 0x1; + + s64 acc = dsp_get_long_acc(reg); + Update_SR_Register64(acc); zeroWriteBackLog(); - - dsp_set_long_acc(dreg, (s64)acc); - Update_SR_Register64((s64)acc); } // TSTAXH $axR.h // 1000 011r xxxx xxxx // Test high part of secondary accumulator $axR.h. +// +// flags out: --x0 xx00 void tstaxh(const UDSPInstruction& opc) { u8 reg = (opc.hex >> 8) & 0x1; - s16 val = dsp_get_ax_h(reg); + s16 val = dsp_get_ax_h(reg); Update_SR_Register16(val); zeroWriteBackLog(); } +//---- + +// CMP +// 1000 0010 xxxx xxxx +// Compares accumulator $ac0 with accumulator $ac1. +// +// flags out: x-xx xxxx +void cmp(const UDSPInstruction& opc) +{ + s64 acc0 = dsp_get_long_acc(0); + 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)); + zeroWriteBackLog(); +} + +// CMPAR $acS axR.h +// 1100 0001 xxxx xxxx +// Compares accumulator $acS with accumulator axR.h. +// Not described by Duddie's doc - at least not as a separate instruction. +// +// flags out: x-xx xxxx +void cmpar(const UDSPInstruction& opc) +{ + u8 rreg = ((opc.hex >> 12) & 0x1) + DSP_REG_AXH0; + u8 sreg = (opc.hex >> 11) & 0x1; + + s64 sr = dsp_get_long_acc(sreg); + s64 rr = (s16)g_dsp.r[rreg]; + rr <<= 16; + s64 res = dsp_convert_long_acc(sr - rr); + + Update_SR_Register64(res, isCarry2(sr, res), isOverflow(sr, -rr, res)); + zeroWriteBackLog(); +} + +// CMPI $amD, #I +// 0000 001r 1000 0000 +// iiii iiii iiii iiii +// Compares mid accumulator $acD.hm ($amD) with sign extended immediate value I. +// Although flags are being set regarding whole accumulator register. +// +// flags out: x-xx xxxx +void cmpi(const UDSPInstruction& opc) +{ + u8 reg = (opc.hex >> 8) & 0x1; + + s64 val = dsp_get_long_acc(reg); + s64 imm = (s64)(s16)dsp_fetch_code() << 16; // Immediate is considered to be at M level in the 40-bit accumulator. + s64 res = dsp_convert_long_acc(val - imm); + + Update_SR_Register64(res, isCarry2(val, res), isOverflow(val, -imm, res)); +} + +// CMPIS $acD, #I +// 0000 011d iiii iiii +// Compares accumulator with short immediate. Comaprison is executed +// by subtracting short immediate (8bit sign extended) from mid accumulator +// $acD.hm and computing flags based on whole accumulator $acD. +// +// flags out: x-xx xxxx +void cmpis(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(areg); + s64 val = (s8)opc.hex; + val <<= 16; + s64 res = dsp_convert_long_acc(acc - val); + + Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -val, res)); +} + +//---- + +// XORR $acD.m, $axS.h +// 0011 00sd 0xxx xxxx +// Logic XOR (exclusive or) middle part of accumulator $acD.m with +// high part of secondary accumulator $axS.h. +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void xorr(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + u8 sreg = (opc.hex >> 9) & 0x1; + u16 accm = g_dsp.r[DSP_REG_ACM0 + dreg] ^ g_dsp.r[DSP_REG_AXH0 + sreg]; + + zeroWriteBackLogPreserveAcc(dreg); + + g_dsp.r[DSP_REG_ACM0 + dreg] = accm; +#ifdef PRECISE_SR_FLAGS + Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); +#endif +} + +// ANDR $acD.m, $axS.h +// 0011 01sd 0xxx xxxx +// Logic AND middle part of accumulator $acD.m with high part of +// secondary accumulator $axS.h. +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void andr(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + u8 sreg = (opc.hex >> 9) & 0x1; + u16 accm = g_dsp.r[DSP_REG_ACM0 + dreg] & g_dsp.r[DSP_REG_AXH0 + sreg]; + + zeroWriteBackLogPreserveAcc(dreg); + + g_dsp.r[DSP_REG_ACM0 + dreg] = accm; + Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); +} + +// ORR $acD.m, $axS.h +// 0011 10sd 0xxx xxxx +// Logic OR middle part of accumulator $acD.m with high part of +// secondary accumulator $axS.h. +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void orr(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + u8 sreg = (opc.hex >> 9) & 0x1; + u16 accm = g_dsp.r[DSP_REG_ACM0 + dreg] | g_dsp.r[DSP_REG_AXH0 + sreg]; + + zeroWriteBackLogPreserveAcc(dreg); + + g_dsp.r[DSP_REG_ACM0 + dreg] = accm; +#ifdef PRECISE_SR_FLAGS + Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); +#endif +} + +// ANDC $acD.m, $ac(1-D).m +// 0011 110d 0xxx xxxx +// Logic AND middle part of accumulator $acD.m with middle part of +// accumulator $ac(1-D).m +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void andc(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + u16 accm = g_dsp.r[DSP_REG_ACM0 + dreg] & g_dsp.r[DSP_REG_ACM0 + (1 - dreg)]; + + zeroWriteBackLogPreserveAcc(dreg); + + g_dsp.r[DSP_REG_ACM0 + dreg] = accm; +#ifdef PRECISE_SR_FLAGS + Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); +#endif +} + +// ORC $acD.m, $ac(1-D).m +// 0011 111d 0xxx xxxx +// Logic OR middle part of accumulator $acD.m with middle part of +// accumulator $ac(1-D).m. +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void orc(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + u16 accm = g_dsp.r[DSP_REG_ACM0 + dreg] | g_dsp.r[DSP_REG_ACM0 + (1 - dreg)]; + + zeroWriteBackLogPreserveAcc(dreg); + + g_dsp.r[DSP_REG_ACM0 + dreg] = accm; +#ifdef PRECISE_SR_FLAGS + Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); +#endif +} + +// XORC $acD.m +// 0011 000d 1xxx xxxx +// Logic XOR (exclusive or) middle part of accumulator $acD.m with $ac(1-D).m +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void xorc(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + u16 accm = g_dsp.r[DSP_REG_ACM0 + dreg] ^ g_dsp.r[DSP_REG_ACM0 + (1 - dreg)]; + + zeroWriteBackLogPreserveAcc(dreg); + + g_dsp.r[DSP_REG_ACM0 + dreg] = accm; +#ifdef PRECISE_SR_FLAGS + Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); +#endif +} + +// NOT $acD.m +// 0011 001d 1xxx xxxx +// Invert all bits in dest reg, aka xor with 0xffff +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +void notc(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + u16 accm = g_dsp.r[DSP_REG_ACM0 + dreg] ^ 0xffff; + + zeroWriteBackLogPreserveAcc(dreg); + + g_dsp.r[DSP_REG_ACM0 + dreg] = accm; +#ifdef PRECISE_SR_FLAGS + Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); +#endif +} + +// XORI $acD.m, #I +// 0000 001r 0010 0000 +// iiii iiii iiii iiii +// Logic exclusive or (XOR) of accumulator mid part $acD.m with +// immediate value I. +// +// flags out: --xx xx00 +void xori(const UDSPInstruction& opc) +{ + u8 reg = (opc.hex >> 8) & 0x1; + u16 imm = dsp_fetch_code(); + g_dsp.r[DSP_REG_ACM0 + reg] ^= imm; + +#ifdef PRECISE_SR_FLAGS + Update_SR_Register16((s16)g_dsp.r[DSP_REG_ACM0 + reg], false, false, isOverS32(dsp_get_long_acc(reg))); +#endif +} + +// ANDI $acD.m, #I +// 0000 001r 0100 0000 +// iiii iiii iiii iiii +// Logic AND of accumulator mid part $acD.m with immediate value I. +// +// flags out: --xx xx00 +void andi(const UDSPInstruction& opc) +{ + u8 reg = (opc.hex >> 8) & 0x1; + u16 imm = dsp_fetch_code(); + g_dsp.r[DSP_REG_ACM0 + reg] &= imm; + + Update_SR_Register16((s16)g_dsp.r[DSP_REG_ACM0 + reg], false, false, isOverS32(dsp_get_long_acc(reg))); +} + +// ORI $acD.m, #I +// 0000 001r 0110 0000 +// iiii iiii iiii iiii +// Logic OR of accumulator mid part $acD.m with immediate value I. +// +// flags out: --xx xx00 +void ori(const UDSPInstruction& opc) +{ + u8 reg = (opc.hex >> 8) & 0x1; + u16 imm = dsp_fetch_code(); + g_dsp.r[DSP_REG_ACM0 + reg] |= imm; +#ifdef PRECISE_SR_FLAGS + Update_SR_Register16((s16)g_dsp.r[DSP_REG_ACM0 + reg], false, false, isOverS32(dsp_get_long_acc(reg))); +#endif +} + +//---- + +// ADDR $acD.M, $axS.L +// 0100 0ssd xxxx xxxx +// Adds register $axS.L to accumulator $acD.M register. +// +// flags out: x-xx xxxx +void addr(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0; + + s64 acc = dsp_get_long_acc(dreg); + s64 ax = (s16)g_dsp.r[sreg]; + ax <<= 16; + s64 res = acc + ax; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); +#ifdef PRECISE_SR_FLAGS + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); +#endif +} + +// ADDAX $acD, $axS +// 0100 10sd xxxx xxxx +// Adds secondary accumulator $axS to accumulator register $acD. +// +// flags out: x-xx xxxx +void addax(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + u8 sreg = (opc.hex >> 9) & 0x1; + + s64 acc = dsp_get_long_acc(dreg); + s64 ax = dsp_get_long_acx(sreg); + s64 res = acc + ax; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); +#ifdef PRECISE_SR_FLAGS + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); +#endif +} + +// ADD $acD, $ac(1-D) +// 0100 110d xxxx xxxx +// Adds accumulator $ac(1-D) to accumulator register $acD. +// +// flags out: x-xx xxxx +void add(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 acc0 = dsp_get_long_acc(dreg); + s64 acc1 = dsp_get_long_acc(1 - dreg); + s64 res = acc0 + acc1; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); +#ifdef PRECISE_SR_FLAGS + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry(acc0, res), isOverflow(acc0, acc1, res)); +#endif +} + +// ADDP $acD +// 0100 111d xxxx xxxx +// Adds product register to accumulator register. +// +// flags out: x-xx xxxx - CF?? +void addp(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(dreg); + s64 prod = dsp_get_long_prod(); + s64 res = acc + prod; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); +#ifdef PRECISE_SR_FLAGS + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, prod, res)); +#endif +} + +// ADDAXL $acD, $axS.l +// 0111 00sd xxxx xxxx +// Adds secondary accumulator $axS.l to accumulator register $acD. +// should be unsigned values!! +// +// flags out: x-xx xxxx +void addaxl(const UDSPInstruction& opc) +{ + u8 sreg = (opc.hex >> 9) & 0x1; + u8 dreg = (opc.hex >> 8) & 0x1; + + u64 acc = dsp_get_long_acc(dreg); + u16 acx = (u16)dsp_get_ax_l(sreg); + + u64 res = acc + acx; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, (s64)res); +#ifdef PRECISE_SR_FLAGS + res = dsp_get_long_acc(dreg); + Update_SR_Register64((s64)res, isCarry(acc, res), isOverflow((s64)acc, (s64)acx, (s64)res)); +#endif +} + +// ADDI $amR, #I +// 0000 001r 0000 0000 +// iiii iiii iiii iiii +// Adds immediate (16-bit sign extended) to mid accumulator $acD.hm. +// +// flags out: x-xx xxxx +void addi(const UDSPInstruction& opc) +{ + u8 areg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(areg); + s64 imm = (s16)dsp_fetch_code(); + imm <<= 16; + s64 res = acc + imm; + + dsp_set_long_acc(areg, res); +#ifdef PRECISE_SR_FLAGS + res = dsp_get_long_acc(areg); + Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); +#endif +} + +// ADDIS $acD, #I +// 0000 010d iiii iiii +// Adds short immediate (8-bit sign extended) to mid accumulator $acD.hm. +// +// flags out: x-xx xxxx +void addis(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(dreg); + s64 imm = (s8)(u8)opc.hex; + imm <<= 16; + s64 res = acc + imm; + + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); +} + +// INCM $acsD +// 0111 010d xxxx xxxx +// Increment 24-bit mid-accumulator $acsD. +// +// flags out: x-xx xxxx +void incm(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 sub = 0x10000; + s64 acc = dsp_get_long_acc(dreg); + s64 res = acc + sub; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, sub, res)); +} + +// INC $acD +// 0111 011d xxxx xxxx +// Increment accumulator $acD. +// +// flags out: x-xx xxxx +void inc(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(dreg); + s64 res = acc + 1; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); +#ifdef PRECISE_SR_FLAGS + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, 1, res)); +#endif +} + +//---- + +// SUBR $acD.M, $axS.L +// 0101 0ssd xxxx xxxx +// Subtracts register $axS.L from accumulator $acD.M register. +// +// flags out: xx xx00 +void subr(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0; + + s64 acc = dsp_get_long_acc(dreg); + s64 ax = (s16)g_dsp.r[sreg]; + ax <<= 16; + s64 res = acc - ax; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -ax, res)); +} + +// SUBAX $acD, $axS +// 0101 10sd xxxx xxxx +// Subtracts secondary accumulator $axS from accumulator register $acD. +// +// flags out: x-xx xxxx +void subax(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + u8 sreg = (opc.hex >> 9) & 0x1; + + s64 acc = dsp_get_long_acc(dreg); + s64 acx = dsp_get_long_acx(sreg); + s64 res = acc - acx; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -acx, res)); +} + // SUB $acD, $ac(1-D) // 0101 110d xxxx xxxx // Subtracts accumulator $ac(1-D) from accumulator register $acD. +// +// flags out: x-xx xxxx void sub(const UDSPInstruction& opc) { - u8 D = (opc.hex >> 8) & 0x1; - s64 acc1 = dsp_get_long_acc(D); - s64 acc2 = dsp_get_long_acc(1 - D); + u8 dreg = (opc.hex >> 8) & 0x1; - acc1 -= acc2; + s64 acc1 = dsp_get_long_acc(dreg); + s64 acc2 = dsp_get_long_acc(1 - dreg); + s64 res = acc1 - acc2; zeroWriteBackLog(); - dsp_set_long_acc(D, acc1); - Update_SR_Register64(acc1); + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry2(acc1, res), isOverflow(acc1, -acc2, res)); } +// SUBP $acD +// 0101 111d xxxx xxxx +// Subtracts product register from accumulator register. +// +// flags out: x-xx xxxx +void subp(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(dreg); + s64 prod = dsp_get_long_prod(); + s64 res = acc - prod; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); +#ifdef PRECISE_SR_FLAGS + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -prod, res)); +#endif +} + +// DECM $acsD +// 0111 100d xxxx xxxx +// Decrement 24-bit mid-accumulator $acsD. +// +// flags out: x-xx xxxx +void decm(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x01; + + s64 sub = 0x10000; + s64 acc = dsp_get_long_acc(dreg); + s64 res = acc - sub; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -sub, res)); +} + +// DEC $acD +// 0111 101d xxxx xxxx +// Decrement accumulator $acD. +// +// flags out: x-xx xxxx +void dec(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x01; + + s64 acc = dsp_get_long_acc(dreg); + s64 res = acc - 1; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, res); +#ifdef PRECISE_SR_FLAGS + res = dsp_get_long_acc(dreg); + Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -1, res)); +#endif +} + +//---- + +// NEG $acD +// 0111 110d xxxx xxxx +// Negate accumulator $acD. +// +// flags out: --xx xx00 +void neg(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x1; + + s64 acc = dsp_get_long_acc(dreg); + acc = 0 - acc; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(dreg)); +#endif +} + +//---- + // MOVR $acD, $axS.R // 0110 0srd xxxx xxxx // Moves register $axS.R (sign extended) to middle accumulator $acD.hm. // Sets $acD.l to 0. // TODO: Check what happens to acD.h. +// +// flags out: --xx xx00 void movr(const UDSPInstruction& opc) { u8 areg = (opc.hex >> 8) & 0x1; @@ -115,12 +758,16 @@ void movr(const UDSPInstruction& opc) zeroWriteBackLog(); dsp_set_long_acc(areg, acc); +#ifdef PRECISE_SR_FLAGS Update_SR_Register64(acc); +#endif } // MOVAX $acD, $axS // 0110 10sd xxxx xxxx // Moves secondary accumulator $axS to accumulator $axD. +// +// flags out: --xx xx00 void movax(const UDSPInstruction& opc) { u8 dreg = (opc.hex >> 8) & 0x1; @@ -131,497 +778,36 @@ void movax(const UDSPInstruction& opc) zeroWriteBackLog(); dsp_set_long_acc(dreg, acx); +#ifdef PRECISE_SR_FLAGS Update_SR_Register64(acx); +#endif } -// 0x3... - -// XORR $acD.m, $axS.h -// 0011 00sd 0xxx xxxx -// Logic XOR (exclusive or) middle part of accumulator $acD.m with -// high part of secondary accumulator $axS.h. -// x = extension (7 bits!!) -void xorr(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x1; - u8 sreg = (opc.hex >> 9) & 0x1; - u16 accm = g_dsp.r[DSP_REG_ACM0 + dreg] ^ g_dsp.r[DSP_REG_AXH0 + sreg]; - - zeroWriteBackLog(); - - g_dsp.r[DSP_REG_ACM0 + dreg] = accm; - Update_SR_Register16((s16)accm); -} - -// ANDR $acD.m, $axS.h -// 0011 01sd 0xxx xxxx -// Logic AND middle part of accumulator $acD.m with high part of -// secondary accumulator $axS.h. -// x = extension (7 bits!!) -void andr(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x1; - u8 sreg = (opc.hex >> 9) & 0x1; - u16 accm = g_dsp.r[DSP_REG_ACM0 + dreg] & g_dsp.r[DSP_REG_AXH0 + sreg]; - - zeroWriteBackLog(); - - g_dsp.r[DSP_REG_ACM0 + dreg] = accm; - Update_SR_Register16((s16)accm); -} - -// ORR $acD.m, $axS.h -// 0011 10sd 0xxx xxxx -// Logic OR middle part of accumulator $acD.m with high part of -// secondary accumulator $axS.h. -// x = extension (7 bits!!) -void orr(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x1; - u8 sreg = (opc.hex >> 9) & 0x1; - u16 accm = g_dsp.r[DSP_REG_ACM0 + dreg] | g_dsp.r[DSP_REG_AXH0 + sreg]; - - zeroWriteBackLog(); - - g_dsp.r[DSP_REG_ACM0 + dreg] = accm; - Update_SR_Register16((s16)accm); -} - -// ANDC $acD.m, $ac(1-D).m -// 0011 110d 0xxx xxxx -// Logic AND middle part of accumulator $acD.m with middle part of -// accumulator $ac(1-D).m -// x = extension (7 bits!!) -void andc(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x1; - u16 accm = g_dsp.r[DSP_REG_ACM0 + dreg] & g_dsp.r[DSP_REG_ACM0 + (1 - dreg)]; - - zeroWriteBackLog(); - - g_dsp.r[DSP_REG_ACM0 + dreg] = accm; - Update_SR_Register16((s16)accm); -} - -// ORC $acD.m, $ac(1-D).m -// 0011 111d 0xxx xxxx -// Logic OR middle part of accumulator $acD.m with middle part of -// accumulator $ac(1-D).m. -// x = extension (7 bits!!) -void orc(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x1; - u16 accm = g_dsp.r[DSP_REG_ACM0 + dreg] | g_dsp.r[DSP_REG_ACM0 + (1 - dreg)]; - - zeroWriteBackLog(); - - g_dsp.r[DSP_REG_ACM0 + dreg] = accm; - Update_SR_Register16((s16)accm); -} - -// XORC $acD.m -// 0011 000d 1xxx xxxx -// Logic XOR (exclusive or) middle part of accumulator $acD.m with $ac(1-D).m -// x = extension (7 bits!!) -void xorc(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x1; - u16 accm = g_dsp.r[DSP_REG_ACM0 + dreg] ^ g_dsp.r[DSP_REG_ACM0 + (1 - dreg)]; - - zeroWriteBackLog(); - - g_dsp.r[DSP_REG_ACM0 + dreg] = accm; - Update_SR_Register16((s16)accm); -} - -// NOT $acD.m -// 0011 001d 1xxx xxxx -// Invert all bits in dest reg, aka xor with 0xffff -// x = extension (7 bits!!) -void notc(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x1; - u16 accm = g_dsp.r[DSP_REG_ACM0 + dreg] ^ 0xffff; - - zeroWriteBackLog(); - - g_dsp.r[DSP_REG_ACM0 + dreg] = accm; - Update_SR_Register16((s16)accm); -} - -void orf(const UDSPInstruction& opc) -{ - ERROR_LOG(DSPLLE, "orf not implemented"); -} - -// ANDCF $acD.m, #I -// 0000 001r 1100 0000 -// iiii iiii iiii iiii -// Set logic zero (LZ) flag in status register $sr if result of logic AND of -// accumulator mid part $acD.m with immediate value I is equal I. -void andcf(const UDSPInstruction& opc) -{ - u8 reg = (opc.hex >> 8) & 0x1; - u16 imm = dsp_fetch_code(); - u16 val = dsp_get_acc_m(reg); - - Update_SR_LZ(((val & imm) == imm) ? true : false); -} - -// ANDF $acD.m, #I -// 0000 001r 1010 0000 -// iiii iiii iiii iiii -// Set logic zero (LZ) flag in status register $sr if result of logical AND -// operation of accumulator mid part $acD.m with immediate value I is equal -// immediate value 0. -void andf(const UDSPInstruction& opc) -{ - u8 reg = (opc.hex >> 8) & 0x1; - u16 imm = dsp_fetch_code(); - u16 val = dsp_get_acc_m(reg); - - Update_SR_LZ(((val & imm) == 0) ? true : false); -} - -// CMPI $amD, #I -// 0000 001r 1000 0000 -// iiii iiii iiii iiii -// Compares mid accumulator $acD.hm ($amD) with sign extended immediate value I. -// Although flags are being set regarding whole accumulator register. -void cmpi(const UDSPInstruction& opc) -{ - int reg = (opc.hex >> 8) & 0x1; - - // Immediate is considered to be at M level in the 40-bit accumulator. - s64 imm = (s64)(s16)dsp_fetch_code() << 16; - s64 val = dsp_get_long_acc(reg); - Update_SR_Register64(val - imm); -} - -// XORI $acD.m, #I -// 0000 001r 0010 0000 -// iiii iiii iiii iiii -// Logic exclusive or (XOR) of accumulator mid part $acD.m with -// immediate value I. -void xori(const UDSPInstruction& opc) -{ - u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1); - u16 imm = dsp_fetch_code(); - - g_dsp.r[reg] ^= imm; - - Update_SR_Register16((s16)g_dsp.r[reg]); -} - -// ANDI $acD.m, #I -// 0000 001r 0100 0000 -// iiii iiii iiii iiii -// Logic AND of accumulator mid part $acD.m with immediate value I. -void andi(const UDSPInstruction& opc) -{ - u8 reg = DSP_REG_ACM0 + ((opc.hex >> 8) & 0x1); - u16 imm = dsp_fetch_code(); - - g_dsp.r[reg] &= imm; - - Update_SR_Register16((s16)g_dsp.r[reg]); -} - - -// ORI $acD.m, #I -// 0000 001r 0110 0000 -// iiii iiii iiii iiii -// Logic OR of accumulator mid part $acD.m with immediate value I. -void ori(const UDSPInstruction& opc) -{ - u8 reg = (opc.hex >> 8) & 0x1; - u16 imm = dsp_fetch_code(); - - g_dsp.r[DSP_REG_ACM0 + reg] |= imm; - - Update_SR_Register16((s16)g_dsp.r[DSP_REG_ACM0 + reg], false, false, isOverS32(dsp_get_long_acc(reg))); -} - -//------------------------------------------------------------- - - -// ADD $acD, $ac(1-D) -// 0100 110d xxxx xxxx -// Adds accumulator $ac(1-D) to accumulator register $acD. -void add(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x1; - - s64 acc0 = dsp_get_long_acc(dreg); - s64 acc1 = dsp_get_long_acc(1 - dreg); - s64 res = acc0 + acc1; - - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, res); - res = dsp_get_long_acc(dreg); - - Update_SR_Register64(res, isAddCarry(acc0, res), isOverflow(acc0, acc1, res)); -} - -// ADDP $acD -// 0100 111d xxxx xxxx -// Adds product register to accumulator register. -void addp(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x1; - s64 acc = dsp_get_long_acc(dreg); - acc += dsp_get_long_prod(); - - zeroWriteBackLog(); - dsp_set_long_acc(dreg, acc); - - Update_SR_Register64(acc); -} - -// SUBP $acD -// 0101 111d xxxx xxxx -// Subtracts product register from accumulator register. -void subp(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x1; - s64 acc = dsp_get_long_acc(dreg); - acc -= dsp_get_long_prod(); - - zeroWriteBackLog(); - dsp_set_long_acc(dreg, acc); - - Update_SR_Register64(acc); -} - - -// CMPIS $acD, #I -// 0000 011d iiii iiii -// Compares accumulator with short immediate. Comaprison is executed -// by subtracting short immediate (8bit sign extended) from mid accumulator -// $acD.hm and computing flags based on whole accumulator $acD. -void cmpis(const UDSPInstruction& opc) -{ - u8 areg = (opc.hex >> 8) & 0x1; - - s64 acc = dsp_get_long_acc(areg); - s64 val = (s8)opc.hex; - val <<= 16; - - s64 res = acc - val; - - Update_SR_Register64(res); -} - - -// DECM $acsD -// 0111 100d xxxx xxxx -// Decrement 24-bit mid-accumulator $acsD. -void decm(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x01; - - s64 sub = 0x10000; - s64 acc = dsp_get_long_acc(dreg); - acc -= sub; - - zeroWriteBackLog(); - dsp_set_long_acc(dreg, acc); - - Update_SR_Register64(acc); -} - -// DEC $acD -// 0111 101d xxxx xxxx -// Decrement accumulator $acD. -void dec(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x01; - - s64 acc = dsp_get_long_acc(dreg) - 1; - - zeroWriteBackLog(); - dsp_set_long_acc(dreg, acc); - - Update_SR_Register64(acc); -} - -// INCM $acsD -// 0111 010d xxxx xxxx -// Increment 24-bit mid-accumulator $acsD. -void incm(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x1; - - s64 sub = 0x10000; - s64 acc = dsp_get_long_acc(dreg); - acc += sub; - - zeroWriteBackLog(); - dsp_set_long_acc(dreg, acc); - - Update_SR_Register64(acc); -} - -// INC $acD -// 0111 011d xxxx xxxx -// Increment accumulator $acD. -void inc(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x1; - - s64 acc = dsp_get_long_acc(dreg) + 1; - - zeroWriteBackLog(); - dsp_set_long_acc(dreg, acc); - - Update_SR_Register64(acc); -} - -// NEG $acD -// 0111 110d xxxx xxxx -// Negate accumulator $acD. -void neg(const UDSPInstruction& opc) -{ - u8 areg = (opc.hex >> 8) & 0x1; - - s64 acc = dsp_get_long_acc(areg); - acc = 0 - acc; - - zeroWriteBackLog(); - dsp_set_long_acc(areg, acc); - - Update_SR_Register64(acc); -} - // MOV $acD, $ac(1-D) // 0110 110d xxxx xxxx // Moves accumulator $ax(1-D) to accumulator $axD. +// +// flags out: --x0 xx00 void mov(const UDSPInstruction& opc) { - u8 D = (opc.hex >> 8) & 0x1; - u64 acc = dsp_get_long_acc(1 - D); + u8 dreg = (opc.hex >> 8) & 0x1; + u64 acc = dsp_get_long_acc(1 - dreg); zeroWriteBackLog(); - dsp_set_long_acc(D, acc); + dsp_set_long_acc(dreg, acc); +#ifdef PRECISE_SR_FLAGS Update_SR_Register64(acc); +#endif } -// ADDAX $acD, $axS -// 0100 10sd xxxx xxxx -// Adds secondary accumulator $axS to accumulator register $acD. -void addax(const UDSPInstruction& opc) -{ - u8 areg = (opc.hex >> 8) & 0x1; - u8 sreg = (opc.hex >> 9) & 0x1; - - s64 ax = dsp_get_long_acx(sreg); - s64 acc = dsp_get_long_acc(areg); - acc += ax; - - zeroWriteBackLog(); - dsp_set_long_acc(areg, acc); - - Update_SR_Register64(acc); -} - -// ADDR $acD.M, $axS.L -// 0100 0ssd xxxx xxxx -// Adds register $axS.L to accumulator $acD.M register. -void addr(const UDSPInstruction& opc) -{ - u8 areg = (opc.hex >> 8) & 0x1; - u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0; - - s64 ax = (s16)g_dsp.r[sreg]; - ax <<= 16; - - s64 acc = dsp_get_long_acc(areg); - acc += ax; - - zeroWriteBackLog(); - dsp_set_long_acc(areg, acc); - - Update_SR_Register64(acc); -} - -// SUBR $acD.M, $axS.L -// 0101 0ssd xxxx xxxx -// Subtracts register $axS.L from accumulator $acD.M register. -// NOTE: It is seen in DSP_UCODE_ZELDA that AXs.H can also be subtracted -void subr(const UDSPInstruction& opc) -{ - u8 areg = (opc.hex >> 8) & 0x1; - u8 sreg = ((opc.hex >> 9) & 0x3) + DSP_REG_AXL0; - - s64 ax = (s16)g_dsp.r[sreg]; - ax <<= 16; - - s64 acc = dsp_get_long_acc(areg); - acc -= ax; - - zeroWriteBackLog(); - dsp_set_long_acc(areg, acc); - - Update_SR_Register64(acc); -} - -// SUBAX $acD, $axS -// 0101 10sd xxxx xxxx -// Subtracts secondary accumulator $axS from accumulator register $acD. -void subax(const UDSPInstruction& opc) -{ - int regD = (opc.hex >> 8) & 0x1; - int regS = (opc.hex >> 9) & 0x1; - - s64 acc = dsp_get_long_acc(regD) - dsp_get_long_acx(regS); - - zeroWriteBackLog(); - dsp_set_long_acc(regD, acc); - Update_SR_Register64(acc); -} - -// ADDIS $acD, #I -// 0000 010d iiii iiii -// Adds short immediate (8-bit sign extended) to mid accumulator $acD.hm. -void addis(const UDSPInstruction& opc) -{ - u8 areg = (opc.hex >> 8) & 0x1; - - s64 Imm = (s8)(u8)opc.hex; - Imm <<= 16; - s64 acc = dsp_get_long_acc(areg); - acc += Imm; - - dsp_set_long_acc(areg, acc); - - Update_SR_Register64(acc); -} - -// ADDI $amR, #I -// 0000 001r 0000 0000 -// iiii iiii iiii iiii -// Adds immediate (16-bit sign extended) to mid accumulator $acD.hm. -void addi(const UDSPInstruction& opc) -{ - u8 areg = (opc.hex >> 8) & 0x1; - - s64 sub = (s16)dsp_fetch_code(); - sub <<= 16; - s64 acc = dsp_get_long_acc(areg); - acc += sub; - - dsp_set_long_acc(areg, acc); - - Update_SR_Register64(acc); -} - -// shifts +//---- // LSL16 $acR // 1111 000r xxxx xxxx // Logically shifts left accumulator $acR by 16. +// +// flags out: --xx xx00 void lsl16(const UDSPInstruction& opc) { u8 areg = (opc.hex >> 8) & 0x1; @@ -630,162 +816,230 @@ void lsl16(const UDSPInstruction& opc) acc <<= 16; zeroWriteBackLog(); + dsp_set_long_acc(areg, acc); - Update_SR_Register64(acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(areg)); +#endif } // LSR16 $acR // 1111 010r xxxx xxxx // Logically shifts right accumulator $acR by 16. +// +// flags out: --xx xx00 void lsr16(const UDSPInstruction& opc) { u8 areg = (opc.hex >> 8) & 0x1; u64 acc = dsp_get_long_acc(areg); - acc &= 0x000000FFFFFFFFFFULL; - acc >>= 16; + acc &= 0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum causes + acc >>= 16; zeroWriteBackLog(); - dsp_set_long_acc(areg, acc); - Update_SR_Register64(acc); + + dsp_set_long_acc(areg, (s64)acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(areg)); +#endif } // ASR16 $acR // 1001 r001 xxxx xxxx // Arithmetically shifts right accumulator $acR by 16. +// +// flags out: --xx xx00 void asr16(const UDSPInstruction& opc) { u8 areg = (opc.hex >> 11) & 0x1; s64 acc = dsp_get_long_acc(areg); - acc >>= 16; zeroWriteBackLog(); - dsp_set_long_acc(areg, acc); - Update_SR_Register64(acc); + dsp_set_long_acc(areg, acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(areg)); +#endif } // LSL $acR, #I // 0001 010r 00ii iiii // Logically shifts left accumulator $acR by number specified by value I. +// +// flags out: --xx xx00 void lsl(const UDSPInstruction& opc) { u8 rreg = (opc.hex >> 8) & 0x01; u16 shift = opc.hex & 0x3f; u64 acc = dsp_get_long_acc(rreg); - acc <<= shift; - if (shift != 0x0) - dsp_set_long_acc(rreg, acc); - Update_SR_Register64((s64)acc); + acc <<= shift; + + dsp_set_long_acc(rreg, acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(rreg)); +#endif } // LSR $acR, #I // 0001 010r 01ii iiii // Logically shifts left accumulator $acR by number specified by value // calculated by negating sign extended bits 0-6. +// +// flags out: --xx xx00 void lsr(const UDSPInstruction& opc) { u8 rreg = (opc.hex >> 8) & 0x01; - u16 shift = 0x40 - (opc.hex & 0x3f); - + u16 shift; u64 acc = dsp_get_long_acc(rreg); acc &= 0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum causes + + if ((opc.hex & 0x3f) == 0) + shift = 0; + else + shift = 0x40 - (opc.hex & 0x3f); + acc >>= shift; dsp_set_long_acc(rreg, (s64)acc); - Update_SR_Register64((s64)acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(rreg)); +#endif } // ASL $acR, #I // 0001 010r 10ii iiii // Logically shifts left accumulator $acR by number specified by value I. +// +// flags out: --xx xx00 void asl(const UDSPInstruction& opc) { u8 rreg = (opc.hex >> 8) & 0x01; u16 shift = opc.hex & 0x3f; - u64 acc = dsp_get_long_acc(rreg); + acc <<= shift; - // arithmetic shift - if (shift != 0x0) - dsp_set_long_acc(rreg, acc); - - Update_SR_Register64((s64)acc); + dsp_set_long_acc(rreg, acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(rreg)); +#endif } // ASR $acR, #I // 0001 010r 11ii iiii // Arithmetically shifts right accumulator $acR by number specified by // value calculated by negating sign extended bits 0-6. +// +// flags out: --xx xx00 void asr(const UDSPInstruction& opc) { - u8 rreg = (opc.hex >> 8) & 0x01; - u16 shift = 0x40 - (opc.hex & 0x3f); + u8 dreg = (opc.hex >> 8) & 0x01; + u16 shift; + + if ((opc.hex & 0x3f) == 0) + shift = 0; + else + shift = 0x40 - (opc.hex & 0x3f); // arithmetic shift - s64 acc = dsp_get_long_acc(rreg); + s64 acc = dsp_get_long_acc(dreg); acc >>= shift; - dsp_set_long_acc(rreg, acc); - Update_SR_Register64(acc); + dsp_set_long_acc(dreg, acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(dreg)); +#endif } - -// (NEW) // LSRN (fixed parameters) // 0000 0010 1100 1010 -// Logically shifts right accumulator $ACC0 by signed 16-bit value $AC1.M +// Logically shifts right accumulator $ACC0 by lower 7-bit (signed) value in $AC1.M // (if value negative, becomes left shift). +// +// flags out: --xx xx00 void lsrn(const UDSPInstruction& opc) { - s16 shift = dsp_get_acc_m(1); + s16 shift; + u16 accm = (u16)dsp_get_acc_m(1); u64 acc = dsp_get_long_acc(0); - // Lop off the extraneous sign extension our 64-bit fake accum causes acc &= 0x000000FFFFFFFFFFULL; + + if ((accm & 0x3f) == 0) + shift = 0; + else if (accm & 0x40) + shift = -0x40 + (accm & 0x3f); + else + shift = accm & 0x3f; + if (shift > 0) { acc >>= shift; } else if (shift < 0) { acc <<= -shift; } + dsp_set_long_acc(0, (s64)acc); - Update_SR_Register64(acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(0)); +#endif } -// (NEW) // ASRN (fixed parameters) // 0000 0010 1100 1011 -// Arithmetically shifts right accumulator $ACC0 by signed 16-bit value $AC1.M +// Arithmetically shifts right accumulator $ACC0 by lower 7-bit (signed) value in $AC1.M // (if value negative, becomes left shift). +// +// flags out: --xx xx00 void asrn(const UDSPInstruction& opc) { - s16 shift = dsp_get_acc_m(1); + s16 shift; + u16 accm = (u16)dsp_get_acc_m(1); s64 acc = dsp_get_long_acc(0); + + if ((accm & 0x3f) == 0) + shift = 0; + else if (accm & 0x40) + shift = -0x40 + (accm & 0x3f); + else + shift = accm & 0x3f; + if (shift > 0) { acc >>= shift; } else if (shift < 0) { acc <<= -shift; } + dsp_set_long_acc(0, acc); - Update_SR_Register64(acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(0)); +#endif } -// LSRNRX +// LSRNRX $acD, $axS.h // 0011 01sd 1xxx xxxx -// Logically shifts left/right accumulator $ACC[D] by signed 16-bit value $AX[S].H +// Logically shifts left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AX[S].H // x = extension (7 bits!!) +// +// flags out: --xx xx00 void lsrnrx(const UDSPInstruction& opc) { u8 dreg = (opc.hex >> 8) & 0x1; u8 sreg = (opc.hex >> 9) & 0x1; - s16 shift = g_dsp.r[DSP_REG_AXH0 + sreg]; + s16 shift; + u16 axh = g_dsp.r[DSP_REG_AXH0 + sreg]; u64 acc = dsp_get_long_acc(dreg); acc &= 0x000000FFFFFFFFFFULL; + if ((axh & 0x3f) == 0) + shift = 0; + else if (axh & 0x40) + shift = -0x40 + (axh & 0x3f); + else + shift = axh & 0x3f; + if (shift > 0) { acc <<= shift; } else if (shift < 0) { @@ -795,21 +1049,33 @@ void lsrnrx(const UDSPInstruction& opc) zeroWriteBackLog(); dsp_set_long_acc(dreg, (s64)acc); - Update_SR_Register64((s64)acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(dreg)); +#endif } -// ASRNRX +// ASRNRX $acD, $axS.h // 0011 10sd 1xxx xxxx -// Arithmetically shifts left/right accumulator $ACC[D] by signed 16-bit value $AX[S].H +// Arithmetically shifts left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AX[S].H // x = extension (7 bits!!) +// +// flags out: --xx xx00 void asrnrx(const UDSPInstruction& opc) { u8 dreg = (opc.hex >> 8) & 0x1; u8 sreg = (opc.hex >> 9) & 0x1; - s16 shift = g_dsp.r[DSP_REG_AXH0 + sreg]; + s16 shift; + u16 axh = g_dsp.r[DSP_REG_AXH0 + sreg]; s64 acc = dsp_get_long_acc(dreg); + if ((axh & 0x3f) == 0) + shift = 0; + else if (axh & 0x40) + shift = -0x40 + (axh & 0x3f); + else + shift = axh & 0x3f; + if (shift > 0) { acc <<= shift; } else if (shift < 0) { @@ -819,97 +1085,94 @@ void asrnrx(const UDSPInstruction& opc) zeroWriteBackLog(); dsp_set_long_acc(dreg, acc); - Update_SR_Register64(acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(dreg)); +#endif } // LSRNR $acD // 0011 110d 1xxx xxxx -// Logically shifts left/right accumulator $ACC[D] by signed 16-bit value $AC[1-D].M +// Logically shifts left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AC[1-D].M // x = extension (7 bits!!) +// +// flags out: --xx xx00 void lsrnr(const UDSPInstruction& opc) { - u8 dreg = (opc.hex >> 8) & 0x1; + u8 dreg = (opc.hex >> 8) & 0x1; - s16 shift = dsp_get_acc_m(1 - dreg); - u64 acc = dsp_get_long_acc(dreg); - acc &= 0x000000FFFFFFFFFFULL; - - if (shift > 0) { - acc <<= shift; - } else if (shift < 0) { - acc >>= -shift; - } + s16 shift; + u16 accm = (u16)dsp_get_acc_m(1 - dreg); + u64 acc = dsp_get_long_acc(dreg); + acc &= 0x000000FFFFFFFFFFULL; - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, (s64)acc); - Update_SR_Register64((s64)acc); + if ((accm & 0x3f) == 0) + shift = 0; + else if (accm & 0x40) + shift = -0x40 + (accm & 0x3f); + else + shift = accm & 0x3f; + + if (shift > 0) + acc <<= shift; + else if (shift < 0) + acc >>= -shift; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, (s64)acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(dreg)); +#endif } // ASRNR $acD // 0011 111d 1xxx xxxx -// Arithmeticaly shift left/right accumulator $ACC[D] by signed 16-bit value $AC[1-D].M +// Arithmeticaly shift left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AC[1-D].M // x = extension (7 bits!!) +// +// flags out: --xx xx00 void asrnr(const UDSPInstruction& opc) { - u8 dreg = (opc.hex >> 8) & 0x1; + u8 dreg = (opc.hex >> 8) & 0x1; - s16 shift = dsp_get_acc_m(1 - dreg); - s64 acc = dsp_get_long_acc(dreg); + s16 shift; + u16 accm = (u16)dsp_get_acc_m(1 - dreg); + s64 acc = dsp_get_long_acc(dreg); - if (shift > 0) { - acc <<= shift; - } else if (shift < 0) { - acc >>= -shift; - } + if ((accm & 0x3f) == 0) + shift = 0; + else if (accm & 0x40) + shift = -0x40 + (accm & 0x3f); + else + shift = accm & 0x3f; - zeroWriteBackLog(); - - dsp_set_long_acc(dreg, acc); - Update_SR_Register64(acc); + if (shift > 0) + acc <<= shift; + else if (shift < 0) + acc >>= -shift; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(dreg)); +#endif } -// CMPAR $acS axR.h -// 1100 0001 xxxx xxxx -// Compares accumulator $acS with accumulator axR.h. -// Not described by Duddie's doc - at least not as a separate instruction. -void cmpar(const UDSPInstruction& opc) +//---- + +// A100 $acD +// 1010 d001 xxxx xxxx +// +// MIA!! - needed for AX/AXWII +// +void a100(const UDSPInstruction& opc) { - u8 rreg = ((opc.hex >> 12) & 0x1) + DSP_REG_AXH0; - u8 sreg = (opc.hex >> 11) & 0x1; + u8 dreg = (opc.hex >> 11) & 0x1; + //it changes target ACC sometimes! - // we compare - s64 rr = (s16)g_dsp.r[rreg]; - rr <<= 16; - - s64 sr = dsp_get_long_acc(sreg); - - Update_SR_Register64(sr - rr); - zeroWriteBackLog(); -} - -// CMP -// 1000 0010 xxxx xxxx -// Compares accumulator $ac0 with accumulator $ac1. -void cmp(const UDSPInstruction& opc) -{ - s64 acc0 = dsp_get_long_acc(0); - s64 acc1 = dsp_get_long_acc(1); - - Update_SR_Register64(acc0 - acc1); - zeroWriteBackLog(); -} - -// TST -// 1011 r001 xxxx xxxx -// Test accumulator %acR. -void tst(const UDSPInstruction& opc) -{ - u8 reg = (opc.hex >> 11) & 0x1; - s64 acc = dsp_get_long_acc(reg); - - Update_SR_Register64(acc); zeroWriteBackLog(); + Update_SR_Register64(dsp_get_long_acc(dreg)); } } // namespace diff --git a/Source/Core/DSPCore/Src/DspIntMisc.cpp b/Source/Core/DSPCore/Src/DspIntMisc.cpp index ce27fd085b..f400a6df08 100644 --- a/Source/Core/DSPCore/Src/DspIntMisc.cpp +++ b/Source/Core/DSPCore/Src/DspIntMisc.cpp @@ -25,12 +25,6 @@ namespace DSPInterpreter { -void unknown(const UDSPInstruction& opc) -{ - //_assert_msg_(MASTER_LOG, !g_dsp.exception_in_progress_hack, "assert while exception"); - ERROR_LOG(DSPLLE, "LLE: Unrecognized opcode 0x%04x, pc 0x%04x", opc.hex, g_dsp.pc); -} - // MRR $D, $S // 0001 11dd ddds ssss // Move value from register $S to register $D. @@ -50,7 +44,7 @@ void mrr(const UDSPInstruction& opc) // iiii iiii iiii iiii // Load immediate value I to register $D. // FIXME: Perform additional operation depending on destination register. - +// // DSPSpy discovery: This, and possibly other instructions that load a // register, has a different behaviour in S40 mode if loaded to AC0.M: The // value gets sign extended to the whole accumulator! This does not happen in @@ -75,45 +69,21 @@ void lris(const UDSPInstruction& opc) dsp_conditional_extend_accum(reg); } - -// TSTAXL $acR -// 1000 r001 xxxx xxxx -// r specifies one of the main accumulators. -// Definitely not a test instruction - it changes the accums. -// Not affected by m0/m2. Not affected by s16/s40. -void tstaxl(const UDSPInstruction& opc) -{ - // This is probably all wrong. - //u8 reg = (opc.hex >> 8) & 0x1; - //s16 val = dsp_get_ax_l(reg); - //Update_SR_Register16(val); -} - -// ADDARN $arD, $ixS -// 0000 0000 0001 ssdd -// Adds indexing register $ixS to an addressing register $arD. -void addarn(const UDSPInstruction& opc) -{ - u8 dreg = opc.hex & 0x3; - u8 sreg = (opc.hex >> 2) & 0x3; - - g_dsp.r[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg]); - - // It is critical for the Zelda ucode that this one wraps correctly. -} +//---- // NX // 1000 -000 xxxx xxxx // No operation, but can be extended with extended opcode. +// This opcode is supposed to do nothing - it's used if you want to use +// an opcode extension but not do anything. At least according to duddie. void nx(const UDSPInstruction& opc) { zeroWriteBackLog(); - // This opcode is supposed to do nothing - it's used if you want to use - // an opcode extension but not do anything. At least according to duddie. } -//------------------------------------------------------------- -// DAR $arD ? +//---- + +// DAR $arD // 0000 0000 0000 01dd // Decrement address register $arD. void dar(const UDSPInstruction& opc) @@ -121,7 +91,7 @@ void dar(const UDSPInstruction& opc) g_dsp.r[opc.hex & 0x3] = dsp_decrement_addr_reg(opc.hex & 0x3); } -// IAR $arD ? +// IAR $arD // 0000 0000 0000 10dd // Increment address register $arD. void iar(const UDSPInstruction& opc) @@ -129,37 +99,49 @@ void iar(const UDSPInstruction& opc) g_dsp.r[opc.hex & 0x3] = dsp_increment_addr_reg(opc.hex & 0x3); } -// XAR $arD ? +// SUBARN $arD // 0000 0000 0000 11dd -// $arD result somehow depends on $wrD -// unknown atm -// used in IPL ucode -void xar(const UDSPInstruction& opc) +// Subtract indexing register $ixD from an addressing register $arD. +// used only in IPL-NTSC ucode +void subarn(const UDSPInstruction& opc) { -// u8 dreg = opc.hex & 0x3; + u8 dreg = opc.hex & 0x3; + g_dsp.r[dreg] = dsp_decrease_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + dreg]); } +// ADDARN $arD, $ixS +// 0000 0000 0001 ssdd +// Adds indexing register $ixS to an addressing register $arD. +// It is critical for the Zelda ucode that this one wraps correctly. +void addarn(const UDSPInstruction& opc) +{ + u8 dreg = opc.hex & 0x3; + u8 sreg = (opc.hex >> 2) & 0x3; + g_dsp.r[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg]); +} + +//---- + // SBCLR #I -// 0001 0011 0000 0iii +// 0001 0011 aaaa aiii // bit of status register $sr. Bit number is calculated by adding 6 to // immediate value I. void sbclr(const UDSPInstruction& opc) { - u8 bit = (opc.hex & 0xff) + 6; + u8 bit = (opc.hex & 0x7) + 6; g_dsp.r[DSP_REG_SR] &= ~(1 << bit); } // SBSET #I -// 0001 0010 0000 0iii +// 0001 0010 aaaa aiii // Set bit of status register $sr. Bit number is calculated by adding 6 to // immediate value I. void sbset(const UDSPInstruction& opc) { - u8 bit = (opc.hex & 0xff) + 6; + u8 bit = (opc.hex & 0x7) + 6; g_dsp.r[DSP_REG_SR] |= (1 << bit); } - // This is a bunch of flag setters, flipping bits in SR. So far so good, // but it's harder to know exactly what effect they have. void srbith(const UDSPInstruction& opc) @@ -199,4 +181,11 @@ void srbith(const UDSPInstruction& opc) } } +//---- + +void unknown(const UDSPInstruction& opc) +{ + ERROR_LOG(DSPLLE, "LLE: Unrecognized opcode 0x%04x, pc 0x%04x", opc.hex, g_dsp.pc); +} + } // namespace diff --git a/Source/Core/DSPCore/Src/DspIntMultiplier.cpp b/Source/Core/DSPCore/Src/DspIntMultiplier.cpp index a671b6e710..7f6141d38b 100644 --- a/Source/Core/DSPCore/Src/DspIntMultiplier.cpp +++ b/Source/Core/DSPCore/Src/DspIntMultiplier.cpp @@ -46,35 +46,25 @@ inline s64 dsp_get_multiply_prod(u16 a, u16 b, bool sign) return prod; } -// Sets prod as a side effect. s64 dsp_multiply(u16 a, u16 b, bool sign = false) { s64 prod = dsp_get_multiply_prod(a, b, sign); - - // Store the product, and return it, in case the caller wants to read it. - // dsp_set_long_prod(prod); return prod; } s64 dsp_multiply_add(u16 a, u16 b, bool sign = false) { - s64 prod = dsp_get_multiply_prod(a, b, sign) + dsp_get_long_prod(); - - // Store the product, and return it, in case the caller wants to read it. - // dsp_set_long_prod(prod); + s64 prod = dsp_get_long_prod() + dsp_get_multiply_prod(a, b, sign); return prod; } s64 dsp_multiply_sub(u16 a, u16 b, bool sign = false) { s64 prod = dsp_get_long_prod() - dsp_get_multiply_prod(a, b, sign); - - // Store the product, and return it, in case the caller wants to read it. - // dsp_set_long_prod(prod); return prod; } - +//---- // CLRP // 1000 0100 xxxx xxxx @@ -91,40 +81,87 @@ void clrp(const UDSPInstruction& opc) // 00ff_(fff0 + 0010)_0000 = 0100_0000_0000, conveniently, lower 40bits = 0 } +// TSTPROD +// 1000 0101 xxxx xxxx +// Test prod regs value. +// +// flags out: xx xx0x <- CF?? +void tstprod(const UDSPInstruction& opc) +{ + s64 prod = dsp_get_long_prod(); + Update_SR_Register64(prod); + zeroWriteBackLog(); +} + +//---- + // MOVP $acD // 0110 111d xxxx xxxx // Moves multiply product from $prod register to accumulator $acD register. +// +// flags out: xx xx00 void movp(const UDSPInstruction& opc) { u8 dreg = (opc.hex >> 8) & 0x1; - s64 prod = dsp_get_long_prod(); - zeroWriteBackLog(); - dsp_set_long_acc(dreg, prod); + s64 acc = dsp_get_long_prod(); - Update_SR_Register64(prod); + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(acc); +#endif } // MOVNP $acD // 0111 111d xxxx xxxx // Moves negative of multiply product from $prod register to accumulator // $acD register. +// +// flags out: xx xx0x <- CF?? void movnp(const UDSPInstruction& opc) { u8 dreg = (opc.hex >> 8) & 0x1; - s64 prod = dsp_get_long_prod(); - s64 acc = -prod; + s64 acc = -dsp_get_long_prod(); + zeroWriteBackLog(); + dsp_set_long_acc(dreg, acc); - +#ifdef PRECISE_SR_FLAGS Update_SR_Register64(acc); +#endif +} + +// MOVPZ $acD +// 1111 111d xxxx xxxx +// Moves multiply product from $prod register to accumulator $acD +// register and sets $acD.l to 0 +// +// flags out: xx xx0x <- CF?? +void movpz(const UDSPInstruction& opc) +{ + u8 dreg = (opc.hex >> 8) & 0x01; + + s64 acc = dsp_get_long_prod() & ~0xffff; + + zeroWriteBackLog(); + + dsp_set_long_acc(dreg, acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(acc); +#endif } // ADDPAXZ $acD, $axS // 1111 10sd xxxx xxxx // Adds secondary accumulator $axS to product register and stores result // in accumulator register. Low 16-bits of $acD ($acD.l) are set to 0. +// +// flags out: x-xx xxxx +// +// TEST THIS!! void addpaxz(const UDSPInstruction& opc) { u8 dreg = (opc.hex >> 8) & 0x1; @@ -135,28 +172,15 @@ void addpaxz(const UDSPInstruction& opc) s64 acc = (prod + ax) & ~0xffff; zeroWriteBackLog(); - dsp_set_long_acc(dreg, acc); - Update_SR_Register64(acc); + dsp_set_long_acc(dreg, acc); +#ifdef PRECISE_SR_FLAGS + acc = dsp_get_long_acc(dreg); + Update_SR_Register64(acc, isCarry2(prod, acc), isOverflow(prod, ax, acc)); +#endif } -// MOVPZ $acD -// 1111 111d xxxx xxxx -// Moves multiply product from $prod register to accumulator $acD -// register and sets $acD.l to 0 -void movpz(const UDSPInstruction& opc) -{ - u8 dreg = (opc.hex >> 8) & 0x01; - - // overwrite acc and clear low part - s64 prod = dsp_get_long_prod(); - s64 acc = prod & ~0xffff; - - zeroWriteBackLog(); - dsp_set_long_acc(dreg, acc); - - Update_SR_Register64(acc); -} +//---- // MULAXH // 1000 0011 xxxx xxxx @@ -164,28 +188,223 @@ void movpz(const UDSPInstruction& opc) void mulaxh(const UDSPInstruction& opc) { s64 prod = dsp_multiply(dsp_get_ax_h(0), dsp_get_ax_h(0)); + zeroWriteBackLog(); + dsp_set_long_prod(prod); } -// TSTPROD -// 1000 0101 xxxx xxxx -// Test prod regs value. -void tstprod(const UDSPInstruction& opc) +//---- + +// MUL $axS.l, $axS.h +// 1001 s000 xxxx xxxx +// Multiply low part $axS.l of secondary accumulator $axS by high part +// $axS.h of secondary accumulator $axS (treat them both as signed). +void mul(const UDSPInstruction& opc) { - s64 prod = dsp_get_long_prod(); - Update_SR_Register64(prod); + u8 sreg = (opc.hex >> 11) & 0x1; + + u16 axl = dsp_get_ax_l(sreg); + u16 axh = dsp_get_ax_h(sreg); + s64 prod = dsp_multiply(axh, axl); + zeroWriteBackLog(); + + dsp_set_long_prod(prod); } +// MULAC $axS.l, $axS.h, $acR +// 1001 s10r xxxx xxxx +// Add product register to accumulator register $acR. Multiply low part +// $axS.l of secondary accumulator $axS by high part $axS.h of secondary +// accumulator $axS (treat them both as signed). +// +// flags out: xx xx00 +void mulac(const UDSPInstruction& opc) +{ + u8 rreg = (opc.hex >> 8) & 0x1; + u8 sreg = (opc.hex >> 11) & 0x1; + + s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); + u16 axl = dsp_get_ax_l(sreg); + u16 axh = dsp_get_ax_h(sreg); + s64 prod = dsp_multiply(axl, axh); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(rreg)); +#endif +} + +// MULMV $axS.l, $axS.h, $acR +// 1001 s11r xxxx xxxx +// Move product register to accumulator register $acR. Multiply low part +// $axS.l of secondary accumulator $axS by high part $axS.h of secondary +// accumulator $axS (treat them both as signed). +// +// flags out: xx xx00 +void mulmv(const UDSPInstruction& opc) +{ + u8 rreg = (opc.hex >> 8) & 0x1; + u8 sreg = ((opc.hex >> 11) & 0x1); + + s64 acc = dsp_get_long_prod(); + u16 axl = dsp_get_ax_l(sreg); + u16 axh = dsp_get_ax_h(sreg); + s64 prod = dsp_multiply(axl, axh); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(rreg)); +#endif +} + +// MULMVZ $axS.l, $axS.h, $acR +// 1001 s01r xxxx xxxx +// Move product register to accumulator register $acR and clear low part +// of accumulator register $acR.l. Multiply low part $axS.l of secondary +// accumulator $axS by high part $axS.h of secondary accumulator $axS (treat +// them both as signed). +// +// flags out: xx xx00 +void mulmvz(const UDSPInstruction& opc) +{ + u8 rreg = (opc.hex >> 8) & 0x1; + u8 sreg = (opc.hex >> 11) & 0x1; + + s64 acc = dsp_get_long_prod() & ~0xffff; + u16 axl = dsp_get_ax_l(sreg); + u16 axh = dsp_get_ax_h(sreg); + s64 prod = dsp_multiply(axl, axh); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(rreg)); +#endif +} + +//---- + +// MULX $ax0.S, $ax1.T +// 101s t000 xxxx xxxx +// Multiply one part $ax0 by one part $ax1 (treat them both as signed). +// Part is selected by S and T bits. Zero selects low part, one selects high part. +void mulx(const UDSPInstruction& opc) +{ + u8 treg = ((opc.hex >> 11) & 0x1); + u8 sreg = ((opc.hex >> 12) & 0x1); + + 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 = dsp_multiply(val1, val2, true); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); +} + +// MULXAC $ax0.S, $ax1.T, $acR +// 101s t01r xxxx xxxx +// Add product register to accumulator register $acR. Multiply one part +// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and +// T bits. Zero selects low part, one selects high part. +// +// flags out: xx xx00 +void mulxac(const UDSPInstruction& opc) +{ + u8 rreg = (opc.hex >> 8) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + u8 sreg = (opc.hex >> 12) & 0x1; + + 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 = dsp_multiply(val1, val2, true); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(rreg)); +#endif +} + +// MULXMV $ax0.S, $ax1.T, $acR +// 101s t11r xxxx xxxx +// Move product register to accumulator register $acR. Multiply one part +// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and +// T bits. Zero selects low part, one selects high part. +// +// flags out: xx xx00 +void mulxmv(const UDSPInstruction& opc) +{ + u8 rreg = ((opc.hex >> 8) & 0x1); + u8 treg = (opc.hex >> 11) & 0x1; + u8 sreg = (opc.hex >> 12) & 0x1; + + s64 acc = dsp_get_long_prod(); + s16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); + s16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); + s64 prod = dsp_multiply(val1, val2, true); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(rreg)); +#endif +} + +// MULXMV $ax0.S, $ax1.T, $acR +// 101s t01r xxxx xxxx +// Move product register to accumulator register $acR and clear low part +// of accumulator register $acR.l. Multiply one part $ax0 by one part $ax1 (treat +// them both as signed). Part is selected by S and T bits. Zero selects low part, +// one selects high part. +// +// flags out: xx xx00 +void mulxmvz(const UDSPInstruction& opc) +{ + u8 rreg = (opc.hex >> 8) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + u8 sreg = (opc.hex >> 12) & 0x1; + + s64 acc = dsp_get_long_prod() & ~0xffff; + 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 = dsp_multiply(val1, val2, true); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(rreg)); +#endif +} + +//---- + // MULC $acS.m, $axT.h // 110s t000 xxxx xxxx // Multiply mid part of accumulator register $acS.m by high part $axS.h of // secondary accumulator $axS (treat them both as signed). void mulc(const UDSPInstruction& opc) { - u8 sreg = (opc.hex >> 12) & 0x1; u8 treg = (opc.hex >> 11) & 0x1; + u8 sreg = (opc.hex >> 12) & 0x1; + u16 accm = dsp_get_acc_m(sreg); u16 axh = dsp_get_ax_h(treg); s64 prod = dsp_multiply(accm, axh); @@ -193,7 +412,61 @@ void mulc(const UDSPInstruction& opc) zeroWriteBackLog(); dsp_set_long_prod(prod); - Update_SR_Register64(prod); +} + +// MULCAC $acS.m, $axT.h, $acR +// 110s t10r xxxx xxxx +// Multiply mid part of accumulator register $acS.m by high part $axS.h of +// secondary accumulator $axS (treat them both as signed). Add product +// register before multiplication to accumulator $acR. +// +// flags out: xx xx00 +void mulcac(const UDSPInstruction& opc) +{ + u8 rreg = (opc.hex >> 8) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + u8 sreg = (opc.hex >> 12) & 0x1; + + s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod(); + u16 accm = dsp_get_acc_m(sreg); + u16 axh = dsp_get_ax_h(treg); + s64 prod = dsp_multiply(accm, axh); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(rreg)); +#endif +} + +// MULCMV $acS.m, $axT.h, $acR +// 110s t11r xxxx xxxx +// Multiply mid part of accumulator register $acS.m by high part $axT.h of +// secondary accumulator $axT (treat them both as signed). Move product +// register before multiplication to accumulator $acR. +// possible mistake in duddie's doc axT.h rather than axS.h +// +// flags out: xx xx00 +void mulcmv(const UDSPInstruction& opc) +{ + u8 rreg = (opc.hex >> 8) & 0x1; + u8 treg = (opc.hex >> 11) & 0x1; + u8 sreg = (opc.hex >> 12) & 0x1; + + s64 acc = dsp_get_long_prod(); + u16 accm = dsp_get_acc_m(sreg); + u16 axh = dsp_get_ax_h(treg); + s64 prod = dsp_multiply(accm, axh); + + zeroWriteBackLog(); + + dsp_set_long_prod(prod); + dsp_set_long_acc(rreg, acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(rreg)); +#endif } // MULCMVZ $acS.m, $axT.h, $acR @@ -203,265 +476,29 @@ void mulc(const UDSPInstruction& opc) // secondary accumulator $axT (treat them both as signed). Move product // register before multiplication to accumulator $acR, set low part of // accumulator $acR.l to zero. +// +// flags out: xx xx00 void mulcmvz(const UDSPInstruction& opc) { - s64 TempProd = dsp_get_long_prod(); - - // update prod - u8 sreg = (opc.hex >> 12) & 0x1; + u8 rreg = (opc.hex >> 8) & 0x1; u8 treg = (opc.hex >> 11) & 0x1; + u8 sreg = (opc.hex >> 12) & 0x1; + s64 acc = dsp_get_long_prod() & ~0xffff; u16 accm = dsp_get_acc_m(sreg); u16 axh = dsp_get_ax_h(treg); s64 prod = dsp_multiply(accm, axh); zeroWriteBackLog(); - dsp_set_long_prod(prod); - // update acc - u8 rreg = (opc.hex >> 8) & 0x1; - s64 acc = TempProd & ~0xffff; // clear lower 4 bytes + dsp_set_long_prod(prod); dsp_set_long_acc(rreg, acc); - - Update_SR_Register64(acc); +#ifdef PRECISE_SR_FLAGS + Update_SR_Register64(dsp_get_long_acc(rreg)); +#endif } -// MULCMV $acS.m, $axT.h, $acR -// 110s t11r xxxx xxxx -// Multiply mid part of accumulator register $acS.m by high part $axT.h of -// secondary accumulator $axT (treat them both as signed). Move product -// register before multiplication to accumulator $acR. -// possible mistake in duddie's doc axT.h rather than axS.h -void mulcmv(const UDSPInstruction& opc) -{ - s64 old_prod = dsp_get_long_prod(); - - // update prod - u8 sreg = (opc.hex >> 12) & 0x1; - u8 treg = (opc.hex >> 11) & 0x1; - u16 accm = dsp_get_acc_m(sreg); - u16 axh = dsp_get_ax_h(treg); - u8 rreg = (opc.hex >> 8) & 0x1; - s64 prod = dsp_multiply(accm, axh); - - zeroWriteBackLog(); - - dsp_set_long_prod(prod); - // update acc - dsp_set_long_acc(rreg, old_prod); - - Update_SR_Register64(old_prod); -} - -// MULCAC $acS.m, $axT.h, $acR -// 110s t10r xxxx xxxx -// Multiply mid part of accumulator register $acS.m by high part $axS.h of -// secondary accumulator $axS (treat them both as signed). Add product -// register before multiplication to accumulator $acR. -void mulcac(const UDSPInstruction& opc) -{ - s64 old_prod = dsp_get_long_prod(); - - // update prod - u8 sreg = (opc.hex >> 12) & 0x1; - u8 treg = (opc.hex >> 11) & 0x1; - u16 accm = dsp_get_acc_m(sreg); - u16 axh = dsp_get_ax_h(treg); - s64 prod = dsp_multiply(accm, axh); - u8 rreg = (opc.hex >> 8) & 0x1; - s64 acc = old_prod + dsp_get_long_acc(rreg); - - zeroWriteBackLog(); - dsp_set_long_prod(prod); - // update acc - dsp_set_long_acc(rreg, acc); - - Update_SR_Register64(acc); -} - - -// MUL $axS.l, $axS.h -// 1001 s000 xxxx xxxx -// Multiply low part $axS.l of secondary accumulator $axS by high part -// $axS.h of secondary accumulator $axS (treat them both as signed). -void mul(const UDSPInstruction& opc) -{ - u8 sreg = (opc.hex >> 11) & 0x1; - u16 axl = dsp_get_ax_l(sreg); - u16 axh = dsp_get_ax_h(sreg); - s64 prod = dsp_multiply(axh, axl); - - zeroWriteBackLog(); - - dsp_set_long_prod(prod); - // FIXME: no update in duddie's docs - Update_SR_Register64(prod); -} - -// MULAC $axS.l, $axS.h, $acR -// 1001 s10r xxxx xxxx -// Add product register to accumulator register $acR. Multiply low part -// $axS.l of secondary accumulator $axS by high part $axS.h of secondary -// accumulator $axS (treat them both as signed). -void mulac(const UDSPInstruction& opc) -{ - // add old prod to acc - u8 rreg = (opc.hex >> 8) & 0x1; - u8 sreg = (opc.hex >> 11) & 0x1; - - s64 acR = dsp_get_long_acc(rreg) + dsp_get_long_prod(); - u16 axl = dsp_get_ax_l(sreg); - u16 axh = dsp_get_ax_h(sreg); - s64 prod = dsp_multiply(axl, axh); - - zeroWriteBackLog(); - - dsp_set_long_acc(rreg, acR); - dsp_set_long_prod(prod); - - // FIXME: no update in duddie's docs - Update_SR_Register64(prod); -} - -// MULMV $axS.l, $axS.h, $acR -// 1001 s11r xxxx xxxx -// Move product register to accumulator register $acR. Multiply low part -// $axS.l of secondary accumulator $axS by high part $axS.h of secondary -// accumulator $axS (treat them both as signed). -void mulmv(const UDSPInstruction& opc) -{ - u8 rreg = (opc.hex >> 8) & 0x1; - u8 sreg = ((opc.hex >> 11) & 0x1); - s64 acc = dsp_get_long_prod(); - u16 axl = dsp_get_ax_l(sreg); - u16 axh = dsp_get_ax_h(sreg); - s64 prod = dsp_multiply(axl, axh); - - zeroWriteBackLog(); - dsp_set_long_acc(rreg, acc); - dsp_set_long_prod(prod); - Update_SR_Register64(prod); -} - -// MULMVZ $axS.l, $axS.h, $acR -// 1001 s01r xxxx xxxx -// Move product register to accumulator register $acR and clear low part -// of accumulator register $acR.l. Multiply low part $axS.l of secondary -// accumulator $axS by high part $axS.h of secondary accumulator $axS (treat -// them both as signed). -void mulmvz(const UDSPInstruction& opc) -{ - u8 sreg = (opc.hex >> 11) & 0x1; - u8 rreg = (opc.hex >> 8) & 0x1; - - // overwrite acc and clear low part - s64 acc = dsp_get_long_prod() & ~0xffff; - u16 axl = dsp_get_ax_l(sreg); - u16 axh = dsp_get_ax_h(sreg); - s64 prod = dsp_multiply(axl, axh); - - zeroWriteBackLog(); - - dsp_set_long_acc(rreg, acc); - dsp_set_long_prod(prod); - Update_SR_Register64(prod); -} - -// MULX $ax0.S, $ax1.T -// 101s t000 xxxx xxxx -// Multiply one part $ax0 by one part $ax1 (treat them both as signed). -// Part is selected by S and T bits. Zero selects low part, one selects high part. -void mulx(const UDSPInstruction& opc) -{ - u8 sreg = ((opc.hex >> 12) & 0x1); - u8 treg = ((opc.hex >> 11) & 0x1); - - 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 = dsp_multiply(val1, val2, true); - - zeroWriteBackLog(); - dsp_set_long_prod(prod); - Update_SR_Register64(prod); -} - -// MULXAC $ax0.S, $ax1.T, $acR -// 101s t01r xxxx xxxx -// Add product register to accumulator register $acR. Multiply one part -// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and -// T bits. Zero selects low part, one selects high part. -void mulxac(const UDSPInstruction& opc) -{ - // add old prod to acc - u8 rreg = (opc.hex >> 8) & 0x1; - s64 acR = dsp_get_long_acc(rreg) + dsp_get_long_prod(); - - // math new prod - u8 sreg = (opc.hex >> 12) & 0x1; - u8 treg = (opc.hex >> 11) & 0x1; - - 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 = dsp_multiply(val1, val2, true); - - zeroWriteBackLog(); - dsp_set_long_acc(rreg, acR); - dsp_set_long_prod(prod); - Update_SR_Register64(prod); -} - -// MULXMV $ax0.S, $ax1.T, $acR -// 101s t11r xxxx xxxx -// Move product register to accumulator register $acR. Multiply one part -// $ax0 by one part $ax1 (treat them both as signed). Part is selected by S and -// T bits. Zero selects low part, one selects high part. -void mulxmv(const UDSPInstruction& opc) -{ - // add old prod to acc - u8 rreg = ((opc.hex >> 8) & 0x1); - s64 acR = dsp_get_long_prod(); - - // math new prod - u8 sreg = (opc.hex >> 12) & 0x1; - u8 treg = (opc.hex >> 11) & 0x1; - - s16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0); - s16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1); - s64 prod = dsp_multiply(val1, val2, true); - - zeroWriteBackLog(); - dsp_set_long_acc(rreg, acR); - dsp_set_long_prod(prod); - Update_SR_Register64(prod); -} - -// MULXMV $ax0.S, $ax1.T, $acR -// 101s t01r xxxx xxxx -// Move product register to accumulator register $acR and clear low part -// of accumulator register $acR.l. Multiply one part $ax0 by one part $ax1 (treat -// them both as signed). Part is selected by S and T bits. Zero selects low part, -// one selects high part. -void mulxmvz(const UDSPInstruction& opc) -{ - // overwrite acc and clear low part - u8 rreg = (opc.hex >> 8) & 0x1; - s64 acc = dsp_get_long_prod() & ~0xffff; - - // math prod - u8 sreg = (opc.hex >> 12) & 0x1; - u8 treg = (opc.hex >> 11) & 0x1; - - 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 = dsp_multiply(val1, val2, true); - - zeroWriteBackLog(); - - dsp_set_long_acc(rreg, acc); - dsp_set_long_prod(prod); - Update_SR_Register64(prod); -} +//---- // MADDX ax0.S ax1.T // 1110 00st xxxx xxxx @@ -470,16 +507,16 @@ void mulxmvz(const UDSPInstruction& opc) // signed) and add result to product register. void maddx(const UDSPInstruction& opc) { - u8 sreg = (opc.hex >> 9) & 0x1; u8 treg = (opc.hex >> 8) & 0x1; + u8 sreg = (opc.hex >> 9) & 0x1; 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 = dsp_multiply_add(val1, val2); zeroWriteBackLog(); + dsp_set_long_prod(prod); - Update_SR_Register64(prod); } // MSUBX $(0x18+S*2), $(0x19+T*2) @@ -489,16 +526,16 @@ void maddx(const UDSPInstruction& opc) // signed) and subtract result from product register. void msubx(const UDSPInstruction& opc) { - u8 sreg = (opc.hex >> 9) & 0x1; u8 treg = (opc.hex >> 8) & 0x1; + u8 sreg = (opc.hex >> 9) & 0x1; 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 = dsp_multiply_sub(val1, val2); zeroWriteBackLog(); + dsp_set_long_prod(prod); - Update_SR_Register64(prod); } // MADDC $acS.m, $axT.h @@ -508,8 +545,9 @@ void msubx(const UDSPInstruction& opc) // register. void maddc(const UDSPInstruction& opc) { - u32 sreg = (opc.hex >> 9) & 0x1; - u32 treg = (opc.hex >> 8) & 0x1; + u8 treg = (opc.hex >> 8) & 0x1; + u8 sreg = (opc.hex >> 9) & 0x1; + u16 accm = dsp_get_acc_m(sreg); u16 axh = dsp_get_ax_h(treg); s64 prod = dsp_multiply_add(accm, axh); @@ -517,7 +555,6 @@ void maddc(const UDSPInstruction& opc) zeroWriteBackLog(); dsp_set_long_prod(prod); - Update_SR_Register64(prod); } // MSUBC $acS.m, $axT.h @@ -527,15 +564,16 @@ void maddc(const UDSPInstruction& opc) // product register. void msubc(const UDSPInstruction& opc) { - u32 sreg = (opc.hex >> 9) & 0x1; - u32 treg = (opc.hex >> 8) & 0x1; + u8 treg = (opc.hex >> 8) & 0x1; + u8 sreg = (opc.hex >> 9) & 0x1; + u16 accm = dsp_get_acc_m(sreg); u16 axh = dsp_get_ax_h(treg); s64 prod = dsp_multiply_sub(accm, axh); zeroWriteBackLog(); + dsp_set_long_prod(prod); - Update_SR_Register64(prod); } // MADD $axS.l, $axS.h @@ -546,13 +584,14 @@ void msubc(const UDSPInstruction& opc) void madd(const UDSPInstruction& opc) { u8 sreg = (opc.hex >> 8) & 0x1; + u16 axl = dsp_get_ax_l(sreg); u16 axh = dsp_get_ax_h(sreg); s64 prod = dsp_multiply_add(axl, axh); zeroWriteBackLog(); + dsp_set_long_prod(prod); - Update_SR_Register64(prod); } // MSUB $axS.l, $axS.h @@ -563,13 +602,14 @@ void madd(const UDSPInstruction& opc) void msub(const UDSPInstruction& opc) { u8 sreg = (opc.hex >> 8) & 0x1; + u16 axl = dsp_get_ax_l(sreg); u16 axh = dsp_get_ax_h(sreg); s64 prod = dsp_multiply_sub(axl, axh); zeroWriteBackLog(); + dsp_set_long_prod(prod); - Update_SR_Register64(prod); } } // namespace