X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdsp.cpp;h=b3ca25e6f88698807edc0c09f77b3540d8ae7829;hb=39ab246ce68e50df4757bbe395d6722ada582927;hp=53a7d0889f9c6fbd76f6b208d1c4b6a591b8b0d4;hpb=5d76d651dfc3aa0a2e810e6b6db2ae8a2e34c53e;p=virtualjaguar diff --git a/src/dsp.cpp b/src/dsp.cpp index 53a7d08..b3ca25e 100644 --- a/src/dsp.cpp +++ b/src/dsp.cpp @@ -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;