]> Shamusworld >> Repos - virtualjaguar/blobdiff - src/dsp.cpp
Fixed RISC division algorithm; thanks to SPCPD for the info.
[virtualjaguar] / src / dsp.cpp
index 53a7d0889f9c6fbd76f6b208d1c4b6a591b8b0d4..b3ca25e6f88698807edc0c09f77b3540d8ae7829 100644 (file)
@@ -310,7 +310,7 @@ static void dsp_opcode_subqmod(void);
 static void dsp_opcode_subqt(void);
 static void dsp_opcode_illegal(void);
 
-uint8_t dsp_opcode_cycles[64] =
+/*uint8_t dsp_opcode_cycles[64] =
 {
        3,  3,  3,  3,  3,  3,  3,  3,
        3,  3,  3,  3,  3,  3,  3,  3,
@@ -325,7 +325,10 @@ uint8_t dsp_opcode_cycles[64] =
 //This is wrong, wrong, WRONG, but it seems to work for the time being...
 //(That is, it fixes Flip Out which relies on GPU timing rather than semaphores. Bad developers! Bad!)
 //What's needed here is a way to take pipeline effects into account (including pipeline stalls!)...
-/*uint8_t dsp_opcode_cycles[64] =
+// Yup, without cheating like this, the sound in things like Rayman, FACTS, &
+// Tripper Getem get starved for time and sounds like crap. So we have to figure
+// out how to fix that. :-/
+uint8_t dsp_opcode_cycles[64] =
 {
        1,  1,  1,  1,  1,  1,  1,  1,
        1,  1,  1,  1,  1,  1,  1,  1,
@@ -755,80 +758,6 @@ SET32(ram2, offset, data);
                        DSPUpdateRegisterBanks();
                        dsp_control &= ~((dsp_flags & CINT04FLAGS) >> 3);
                        dsp_control &= ~((dsp_flags & CINT5FLAG) >> 1);
-
-// NB: This is just a wild hairy-assed guess as to what the playback frequency is.
-//     It can be timed to anything really, anything that writes to L/RTXD at a regular
-//     interval. Most things seem to use either the I2S interrupt or the TIMER 0
-//     interrupt, so that's what we check for here. Just know that this approach
-//     can be easily fooled!
-//     Note also that if both interrupts are enabled, the I2S freq will win. :-P
-
-// Further Note:
-// The impetus for this "fix" was Cybermorph, which sets the SCLK to 7 which is an
-// audio frequency > 48 KHz. However, it stuffs the L/RTXD registers using TIMER0.
-// So, while this works, it's a by-product of the lame way in which audio is currently
-// handled. Hopefully, once we run the DSP in the host audio IRQ, this problem will
-// go away of its own accord. :-P
-// Or does it? It seems the I2S interrupt isn't on with Cybermorph, so something
-// weird is going on here...
-// Maybe it works like this: It acknowledges the 1st interrupt, but never clears it.
-// So subsequent interrupts come into the chip, but they're never serviced but the
-// I2S subsystem keeps going.
-// After some testing on real hardware, it seems that if you enable TIMER0 and EXTERNAL
-// IRQs on J_INT ($F10020), you don't have to run an I2S interrupt on the DSP. Also,
-// It seems that it's only stable for values of SCLK <= 9.
-
-// All of the preceeding is moot now; we run the DSP in the host audio IRQ. This means
-// that we don't actually need this stuff anymore. :-D
-#if 0
-                       if (data & INT_ENA1) // I2S interrupt
-                       {
-                               int freq = GetCalculatedFrequency();
-//This happens too often to be useful...
-//                             WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
-                               DACSetNewFrequency(freq);
-                       }
-                       else if (data & INT_ENA2) // TIMER 0 interrupt
-                       {
-                               int freq = JERRYGetPIT1Frequency();
-//This happens too often to be useful...
-//                             WriteLog("DSP: Setting audio freqency to %u Hz...\n", freq);
-                               DACSetNewFrequency(freq);
-                       }
-#endif
-
-/*                     if (IMASKCleared)                                               // If IMASK was cleared,
-#ifdef DSP_DEBUG_IRQ
-                       {
-                               WriteLog("DSP: Finished interrupt.\n");
-#endif
-                               DSPHandleIRQs();                                        // see if any other interrupts need servicing!
-#ifdef DSP_DEBUG_IRQ
-                       }
-#endif//*/
-#if 0
-                       if (/*4-8, 16*/data & 0x101F0)
-                               WriteLog("DSP: %s is enabling interrupts %s%s%s%s%s%s\n", whoName[who],
-                                       (data & 0x010 ? "CPU " : ""), (data & 0x020 ? "I2S " : ""),
-                                       (data & 0x040 ? "TIMER0 " : ""), (data & 0x080 ? "TIMER1 " : ""),
-                                       (data & 0x100 ? "EXT0 " : ""), (data & 0x10000 ? "EXT1" : ""));
-/*if (data & 0x00020) // CD BIOS DSP code...
-{
-//001AC1BA: movea.l #$1AC200, A0
-//001AC1C0: move.l  #$1AC68C, D0
-       char buffer[512];
-
-       WriteLog("\n---[DSP code at 00F1B97C]---------------------------\n");
-       uint32_t j = 0xF1B97C;//0x1AC200;
-       while (j <= 0xF1BE08)//0x1AC68C)
-       {
-               uint32_t oldj = j;
-               j += dasmjag(JAGUAR_DSP, buffer, j);
-//             WriteLog("\t%08X: %s\n", oldj+0xD6F77C, buffer);
-               WriteLog("\t%08X: %s\n", oldj, buffer);
-       }
-}//*/
-#endif
                        break;
                }
                case 0x04:
@@ -867,10 +796,9 @@ WriteLog("Write to DSP CTRL by %s: %08X (DSP PC=$%08X)\n", whoName[who], data, d
 #ifdef DSP_DEBUG
                                WriteLog("DSP: DSP -> CPU interrupt\n");
 #endif
-// This was WRONG
-// Why do we check for a valid handler at 64? Isn't that the Jag programmer's responsibility? (YES)
+
 #warning "!!! DSP IRQs that go to the 68K have to be routed thru TOM !!! FIX !!!"
-                               if (JERRYIRQEnabled(IRQ2_DSP))// && jaguar_interrupt_handler_is_valid(64))
+                               if (JERRYIRQEnabled(IRQ2_DSP))
                                {
                                        JERRYSetPendingIRQ(IRQ2_DSP);
                                        DSPReleaseTimeslice();
@@ -1711,6 +1639,7 @@ if ((dsp_pc < 0xF1B000 || dsp_pc > 0xF1CFFE) && !tripwire)
        dsp_in_exec--;
 }
 
+
 //
 // DSP opcode handlers
 //
@@ -1753,6 +1682,7 @@ const char * condition[32] =
 #endif
 }
 
+
 static void dsp_opcode_jr(void)
 {
 #ifdef DSP_DIS_JR
@@ -1789,6 +1719,7 @@ const char * condition[32] =
 #endif
 }
 
+
 static void dsp_opcode_add(void)
 {
 #ifdef DSP_DIS_ADD
@@ -1804,6 +1735,7 @@ static void dsp_opcode_add(void)
 #endif
 }
 
+
 static void dsp_opcode_addc(void)
 {
 #ifdef DSP_DIS_ADDC
@@ -1822,6 +1754,7 @@ static void dsp_opcode_addc(void)
 #endif
 }
 
+
 static void dsp_opcode_addq(void)
 {
 #ifdef DSP_DIS_ADDQ
@@ -1838,6 +1771,7 @@ static void dsp_opcode_addq(void)
 #endif
 }
 
+
 static void dsp_opcode_sub(void)
 {
 #ifdef DSP_DIS_SUB
@@ -1853,22 +1787,26 @@ static void dsp_opcode_sub(void)
 #endif
 }
 
+
 static void dsp_opcode_subc(void)
 {
 #ifdef DSP_DIS_SUBC
        if (doDSPDis)
                WriteLog("%06X: SUBC   R%02u, R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
 #endif
-       uint32_t res = RN - RM - dsp_flag_c;
-       uint32_t borrow = dsp_flag_c;
-       SET_ZNC_SUB(RN - borrow, RM, res);
-       RN = res;
+       // This is how the DSP ALU does it--Two's complement with inverted carry
+       uint64_t res = (uint64_t)RN + (uint64_t)(RM ^ 0xFFFFFFFF) + (dsp_flag_c ^ 1);
+       // Carry out of the result is inverted too
+       dsp_flag_c = ((res >> 32) & 0x01) ^ 1;
+       RN = (res & 0xFFFFFFFF);
+       SET_ZN(RN);
 #ifdef DSP_DIS_SUBC
        if (doDSPDis)
                WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_1, RM, IMM_2, RN);
 #endif
 }
 
+
 static void dsp_opcode_subq(void)
 {
 #ifdef DSP_DIS_SUBQ
@@ -1885,6 +1823,7 @@ static void dsp_opcode_subq(void)
 #endif
 }
 
+
 static void dsp_opcode_cmp(void)
 {
 #ifdef DSP_DIS_CMP
@@ -1899,6 +1838,7 @@ static void dsp_opcode_cmp(void)
 #endif
 }
 
+
 static void dsp_opcode_cmpq(void)
 {
        static int32_t sqtable[32] =
@@ -1916,6 +1856,7 @@ static void dsp_opcode_cmpq(void)
 #endif
 }
 
+
 static void dsp_opcode_and(void)
 {
 #ifdef DSP_DIS_AND
@@ -1930,6 +1871,7 @@ static void dsp_opcode_and(void)
 #endif
 }
 
+
 static void dsp_opcode_or(void)
 {
 #ifdef DSP_DIS_OR
@@ -1944,6 +1886,7 @@ static void dsp_opcode_or(void)
 #endif
 }
 
+
 static void dsp_opcode_xor(void)
 {
 #ifdef DSP_DIS_XOR
@@ -1958,6 +1901,7 @@ static void dsp_opcode_xor(void)
 #endif
 }
 
+
 static void dsp_opcode_not(void)
 {
 #ifdef DSP_DIS_NOT
@@ -1972,11 +1916,13 @@ static void dsp_opcode_not(void)
 #endif
 }
 
+
 static void dsp_opcode_move_pc(void)
 {
        RN = dsp_pc - 2;
 }
 
+
 static void dsp_opcode_store_r14_indexed(void)
 {
 #ifdef DSP_DIS_STORE14I
@@ -1990,6 +1936,7 @@ static void dsp_opcode_store_r14_indexed(void)
 #endif
 }
 
+
 static void dsp_opcode_store_r15_indexed(void)
 {
 #ifdef DSP_DIS_STORE15I
@@ -2003,6 +1950,7 @@ static void dsp_opcode_store_r15_indexed(void)
 #endif
 }
 
+
 static void dsp_opcode_load_r14_ri(void)
 {
 #ifdef DSP_DIS_LOAD14R
@@ -2020,6 +1968,7 @@ static void dsp_opcode_load_r14_ri(void)
 #endif
 }
 
+
 static void dsp_opcode_load_r15_ri(void)
 {
 #ifdef DSP_DIS_LOAD15R
@@ -2037,16 +1986,19 @@ static void dsp_opcode_load_r15_ri(void)
 #endif
 }
 
+
 static void dsp_opcode_store_r14_ri(void)
 {
        DSPWriteLong(dsp_reg[14] + RM, RN, DSP);
 }
 
+
 static void dsp_opcode_store_r15_ri(void)
 {
        DSPWriteLong(dsp_reg[15] + RM, RN, DSP);
 }
 
+
 static void dsp_opcode_nop(void)
 {
 #ifdef DSP_DIS_NOP
@@ -2055,6 +2007,7 @@ static void dsp_opcode_nop(void)
 #endif
 }
 
+
 static void dsp_opcode_storeb(void)
 {
 #ifdef DSP_DIS_STOREB
@@ -2067,6 +2020,7 @@ static void dsp_opcode_storeb(void)
                JaguarWriteByte(RM, RN, DSP);
 }
 
+
 static void dsp_opcode_storew(void)
 {
 #ifdef DSP_DIS_STOREW
@@ -2086,6 +2040,7 @@ static void dsp_opcode_storew(void)
 #endif
 }
 
+
 static void dsp_opcode_store(void)
 {
 #ifdef DSP_DIS_STORE
@@ -2099,6 +2054,7 @@ static void dsp_opcode_store(void)
 #endif
 }
 
+
 static void dsp_opcode_loadb(void)
 {
 #ifdef DSP_DIS_LOADB
@@ -2115,6 +2071,7 @@ static void dsp_opcode_loadb(void)
 #endif
 }
 
+
 static void dsp_opcode_loadw(void)
 {
 #ifdef DSP_DIS_LOADW
@@ -2138,6 +2095,7 @@ static void dsp_opcode_loadw(void)
 #endif
 }
 
+
 static void dsp_opcode_load(void)
 {
 #ifdef DSP_DIS_LOAD
@@ -2155,6 +2113,7 @@ static void dsp_opcode_load(void)
 #endif
 }
 
+
 static void dsp_opcode_load_r14_indexed(void)
 {
 #ifdef DSP_DIS_LOAD14I
@@ -2172,6 +2131,7 @@ static void dsp_opcode_load_r14_indexed(void)
 #endif
 }
 
+
 static void dsp_opcode_load_r15_indexed(void)
 {
 #ifdef DSP_DIS_LOAD15I
@@ -2189,6 +2149,7 @@ static void dsp_opcode_load_r15_indexed(void)
 #endif
 }
 
+
 static void dsp_opcode_movei(void)
 {
 #ifdef DSP_DIS_MOVEI
@@ -2204,6 +2165,7 @@ static void dsp_opcode_movei(void)
 #endif
 }
 
+
 static void dsp_opcode_moveta(void)
 {
 #ifdef DSP_DIS_MOVETA
@@ -2217,6 +2179,7 @@ static void dsp_opcode_moveta(void)
 #endif
 }
 
+
 static void dsp_opcode_movefa(void)
 {
 #ifdef DSP_DIS_MOVEFA
@@ -2230,6 +2193,7 @@ static void dsp_opcode_movefa(void)
 #endif
 }
 
+
 static void dsp_opcode_move(void)
 {
 #ifdef DSP_DIS_MOVE
@@ -2243,6 +2207,7 @@ static void dsp_opcode_move(void)
 #endif
 }
 
+
 static void dsp_opcode_moveq(void)
 {
 #ifdef DSP_DIS_MOVEQ
@@ -2256,6 +2221,7 @@ static void dsp_opcode_moveq(void)
 #endif
 }
 
+
 static void dsp_opcode_resmac(void)
 {
 #ifdef DSP_DIS_RESMAC
@@ -2269,6 +2235,7 @@ static void dsp_opcode_resmac(void)
 #endif
 }
 
+
 static void dsp_opcode_imult(void)
 {
 #ifdef DSP_DIS_IMULT
@@ -2283,6 +2250,7 @@ static void dsp_opcode_imult(void)
 #endif
 }
 
+
 static void dsp_opcode_mult(void)
 {
 #ifdef DSP_DIS_MULT
@@ -2297,6 +2265,7 @@ static void dsp_opcode_mult(void)
 #endif
 }
 
+
 static void dsp_opcode_bclr(void)
 {
 #ifdef DSP_DIS_BCLR
@@ -2312,6 +2281,7 @@ static void dsp_opcode_bclr(void)
 #endif
 }
 
+
 static void dsp_opcode_btst(void)
 {
 #ifdef DSP_DIS_BTST
@@ -2325,6 +2295,7 @@ static void dsp_opcode_btst(void)
 #endif
 }
 
+
 static void dsp_opcode_bset(void)
 {
 #ifdef DSP_DIS_BSET
@@ -2340,6 +2311,7 @@ static void dsp_opcode_bset(void)
 #endif
 }
 
+
 static void dsp_opcode_subqt(void)
 {
 #ifdef DSP_DIS_SUBQT
@@ -2353,6 +2325,7 @@ static void dsp_opcode_subqt(void)
 #endif
 }
 
+
 static void dsp_opcode_addqt(void)
 {
 #ifdef DSP_DIS_ADDQT
@@ -2366,6 +2339,7 @@ static void dsp_opcode_addqt(void)
 #endif
 }
 
+
 static void dsp_opcode_imacn(void)
 {
 #ifdef DSP_DIS_IMACN
@@ -2381,12 +2355,14 @@ static void dsp_opcode_imacn(void)
 #endif
 }
 
+
 static void dsp_opcode_mtoi(void)
 {
        RN = (((int32_t)RM >> 8) & 0xFF800000) | (RM & 0x007FFFFF);
        SET_ZN(RN);
 }
 
+
 static void dsp_opcode_normi(void)
 {
        uint32_t _Rm = RM;
@@ -2409,6 +2385,7 @@ static void dsp_opcode_normi(void)
        SET_ZN(RN);
 }
 
+
 static void dsp_opcode_mmult(void)
 {
        int count       = dsp_matrix_control&0x0f;
@@ -2450,6 +2427,7 @@ static void dsp_opcode_mmult(void)
        SET_ZN(RN);
 }
 
+
 static void dsp_opcode_abs(void)
 {
 #ifdef DSP_DIS_ABS
@@ -2473,32 +2451,57 @@ static void dsp_opcode_abs(void)
 #endif
 }
 
+
 static void dsp_opcode_div(void)
 {
-       uint32_t _Rm=RM;
-       uint32_t _Rn=RN;
-
-       if (_Rm)
+#if 0
+       if (RM)
        {
-               if (dsp_div_control & 1)
+               if (dsp_div_control & 0x01)             // 16.16 division
                {
-                       dsp_remain = (((uint64_t)_Rn) << 16) % _Rm;
-                       if (dsp_remain&0x80000000)
-                               dsp_remain-=_Rm;
-                       RN = (((uint64_t)_Rn) << 16) / _Rm;
+                       dsp_remain = ((uint64_t)RN << 16) % RM;
+                       RN = ((uint64_t)RN << 16) / RM;
                }
                else
                {
-                       dsp_remain = _Rn % _Rm;
-                       if (dsp_remain&0x80000000)
-                               dsp_remain-=_Rm;
-                       RN/=_Rm;
+                       // We calculate the remainder first because we destroy RN after
+                       // this by assigning it to itself.
+                       dsp_remain = RN % RM;
+                       RN = RN / RM;
                }
+
        }
        else
-               RN=0xffffffff;
+       {
+               // This is what happens according to SCPCD. NYAN!
+               RN = 0xFFFFFFFF;
+               dsp_remain = 0;
+       }
+#else
+       // Real algorithm, courtesy of SCPCD: NYAN!
+       uint32_t q = RN;
+       uint32_t r = 0;
+
+       // If 16.16 division, stuff top 16 bits of RN into remainder and put the
+       // bottom 16 of RN in top 16 of quotient
+       if (dsp_div_control & 0x01)
+               q <<= 16, r = RN >> 16;
+
+       for(int i=0; i<32; i++)
+       {
+//             uint32_t sign = (r >> 31) & 0x01;
+               uint32_t sign = r & 0x80000000;
+               r = (r << 1) | ((q >> 31) & 0x01);
+               r += (sign ? RM : -RM);
+               q = (q << 1) | (((~r) >> 31) & 0x01);
+       }
+
+       RN = q;
+       dsp_remain = r;
+#endif
 }
 
+
 static void dsp_opcode_imultn(void)
 {
 #ifdef DSP_DIS_IMULTN
@@ -2515,6 +2518,7 @@ static void dsp_opcode_imultn(void)
 #endif
 }
 
+
 static void dsp_opcode_neg(void)
 {
 #ifdef DSP_DIS_NEG
@@ -2530,6 +2534,7 @@ static void dsp_opcode_neg(void)
 #endif
 }
 
+
 static void dsp_opcode_shlq(void)
 {
 #ifdef DSP_DIS_SHLQ
@@ -2547,6 +2552,7 @@ static void dsp_opcode_shlq(void)
 #endif
 }
 
+
 static void dsp_opcode_shrq(void)
 {
 #ifdef DSP_DIS_SHRQ
@@ -2563,6 +2569,7 @@ static void dsp_opcode_shrq(void)
 #endif
 }
 
+
 static void dsp_opcode_ror(void)
 {
 #ifdef DSP_DIS_ROR
@@ -2579,6 +2586,7 @@ static void dsp_opcode_ror(void)
 #endif
 }
 
+
 static void dsp_opcode_rorq(void)
 {
 #ifdef DSP_DIS_RORQ
@@ -2596,6 +2604,7 @@ static void dsp_opcode_rorq(void)
 #endif
 }
 
+
 static void dsp_opcode_sha(void)
 {
        int32_t sRm=(int32_t)RM;
@@ -2627,6 +2636,7 @@ static void dsp_opcode_sha(void)
        SET_ZN(RN);
 }
 
+
 static void dsp_opcode_sharq(void)
 {
 #ifdef DSP_DIS_SHARQ
@@ -2642,6 +2652,7 @@ static void dsp_opcode_sharq(void)
 #endif
 }
 
+
 static void dsp_opcode_sh(void)
 {
        int32_t sRm=(int32_t)RM;