X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libpcsxcore%2Fpsxcounters.c;h=35823dacdafc3cd34ab92c66c84d00285b538957;hb=HEAD;hp=c9f293156dbee4bbb2b7fd078a8d9bf0f7118e6e;hpb=c62b43c9f32d79116225247acf09ccd30d4d658b;p=pcsx_rearmed.git diff --git a/libpcsxcore/psxcounters.c b/libpcsxcore/psxcounters.c index c9f29315..887fe8a4 100644 --- a/libpcsxcore/psxcounters.c +++ b/libpcsxcore/psxcounters.c @@ -22,23 +22,21 @@ */ #include "psxcounters.h" +#include "psxevents.h" +#include "gpu.h" +//#include "debug.h" +#define DebugVSync() /******************************************************************************/ -typedef struct Rcnt -{ - u16 mode, target; - u32 rate, irq, counterState, irqState; - u32 cycle, cycleStart; -} Rcnt; - enum { - Rc0Gate = 0x0001, // 0 not implemented - Rc1Gate = 0x0001, // 0 not implemented - Rc2Disable = 0x0001, // 0 partially implemented - RcUnknown1 = 0x0002, // 1 ? - RcUnknown2 = 0x0004, // 2 ? + RcSyncModeEnable = 0x0001, // 0 + Rc01BlankPause = 0 << 1, // 1,2 + Rc01UnblankReset = 1 << 1, // 1,2 + Rc01UnblankReset2 = 2 << 1, // 1,2 + Rc2Stop = 0 << 1, // 1,2 + Rc2Stop2 = 3 << 1, // 1,2 RcCountToTarget = 0x0008, // 3 RcIrqOnTarget = 0x0010, // 4 RcIrqOnOverflow = 0x0020, // 5 @@ -64,24 +62,63 @@ enum static const u32 CountToOverflow = 0; static const u32 CountToTarget = 1; -static const u32 FrameRate[] = { 60, 50 }; -static const u32 VBlankStart[] = { 240, 256 }; -static const u32 HSyncTotal[] = { 262, 312 }; -static const u32 SpuUpdInterval[] = { 23, 22 }; +static const u32 HSyncTotal[] = { 263, 314 }; +#define VBlankStart 240 // todo: depend on the actual GPU setting -static const s32 VerboseLevel = 0; +#define VERBOSE_LEVEL 0 /******************************************************************************/ - -static Rcnt rcnts[ CounterQuantity ]; - -static u32 hSyncCount = 0; -static u32 spuSyncCount = 0; +#ifdef DRC_DISABLE +Rcnt rcnts[ CounterQuantity ]; +#endif +u32 hSyncCount = 0; +u32 frame_counter = 0; +static u32 hsync_steps = 0; u32 psxNextCounter = 0, psxNextsCounter = 0; /******************************************************************************/ +#define FPS_FRACTIONAL_PAL (53203425/314./3406) // ~49.75 +#define FPS_FRACTIONAL_NTSC (53693175/263./3413) // ~59.81 + +static inline +u32 frameCycles(void) +{ + int ff = Config.FractionalFramerate >= 0 + ? Config.FractionalFramerate : Config.hacks.fractional_Framerate; + if (ff) + { + if (Config.PsxType) + return (u32)(PSXCLK / FPS_FRACTIONAL_PAL); + else + return (u32)(PSXCLK / FPS_FRACTIONAL_NTSC); + } + return Config.PsxType ? (PSXCLK / 50) : (PSXCLK / 60); +} + +// used to inform the frontend about the exact framerate +double psxGetFps() +{ + int ff = Config.FractionalFramerate >= 0 + ? Config.FractionalFramerate : Config.hacks.fractional_Framerate; + if (ff) + return Config.PsxType ? FPS_FRACTIONAL_PAL : FPS_FRACTIONAL_NTSC; + else + return Config.PsxType ? 50.0 : 60.0; +} + +// to inform the frontend about the exact famerate +static inline +u32 lineCycles(void) +{ + // should be more like above, but our timing is already poor anyway + if (Config.PsxType) + return PSXCLK / 50 / HSyncTotal[1]; + else + return PSXCLK / 60 / HSyncTotal[0]; +} + static inline void setIrq( u32 irq ) { @@ -89,9 +126,10 @@ void setIrq( u32 irq ) } static -void verboseLog( s32 level, const char *str, ... ) +void verboseLog( u32 level, const char *str, ... ) { - if( level <= VerboseLevel ) +#if VERBOSE_LEVEL > 0 + if( level <= VERBOSE_LEVEL ) { va_list va; char buf[ 4096 ]; @@ -100,9 +138,10 @@ void verboseLog( s32 level, const char *str, ... ) vsprintf( buf, str, va ); va_end( va ); - printf( buf ); + printf( "%s", buf ); fflush( stdout ); } +#endif } /******************************************************************************/ @@ -110,11 +149,7 @@ void verboseLog( s32 level, const char *str, ... ) static inline void _psxRcntWcount( u32 index, u32 value ) { - if( value > 0xffff ) - { - verboseLog( 1, "[RCNT %i] wcount > 0xffff: %x\n", index, value ); - value &= 0xffff; - } + value &= 0xffff; rcnts[index].cycleStart = psxRegs.cycle; rcnts[index].cycleStart -= value * rcnts[index].rate; @@ -127,7 +162,7 @@ void _psxRcntWcount( u32 index, u32 value ) } else { - rcnts[index].cycle = 0xffff * rcnts[index].rate; + rcnts[index].cycle = 0x10000 * rcnts[index].rate; rcnts[index].counterState = CountToOverflow; } } @@ -139,17 +174,65 @@ u32 _psxRcntRcount( u32 index ) count = psxRegs.cycle; count -= rcnts[index].cycleStart; - count /= rcnts[index].rate; + if (rcnts[index].rate > 1) + count /= rcnts[index].rate; - if( count > 0xffff ) + if( count > 0x10000 ) { - verboseLog( 1, "[RCNT %i] rcount > 0xffff: %x\n", index, count ); - count &= 0xffff; + verboseLog( 1, "[RCNT %i] rcount > 0x10000: %x\n", index, count ); } + count &= 0xffff; return count; } +static +void _psxRcntWmode( u32 index, u32 value ) +{ + rcnts[index].mode = value; + + switch( index ) + { + case 0: + if( value & Rc0PixelClock ) + { + rcnts[index].rate = 5; + } + else + { + rcnts[index].rate = 1; + } + break; + case 1: + if( value & Rc1HSyncClock ) + { + rcnts[index].rate = lineCycles(); + } + else + { + rcnts[index].rate = 1; + } + break; + case 2: + if( value & Rc2OneEighthClock ) + { + rcnts[index].rate = 8; + } + else + { + rcnts[index].rate = 1; + } + + // TODO: wcount must work. + if( (value & 7) == (RcSyncModeEnable | Rc2Stop) || + (value & 7) == (RcSyncModeEnable | Rc2Stop2) ) + { + rcnts[index].rate = 0xffffffff; + } + break; + } +} + /******************************************************************************/ static @@ -176,6 +259,8 @@ void psxRcntSet() psxNextCounter = countToUpdate; } } + + set_event(PSXINT_RCNT, psxNextCounter); } /******************************************************************************/ @@ -183,50 +268,58 @@ void psxRcntSet() static void psxRcntReset( u32 index ) { - u32 count; + u32 rcycles; + + rcnts[index].mode |= RcUnknown10; if( rcnts[index].counterState == CountToTarget ) { + rcycles = psxRegs.cycle - rcnts[index].cycleStart; if( rcnts[index].mode & RcCountToTarget ) { - count = psxRegs.cycle; - count -= rcnts[index].cycleStart; - count /= rcnts[index].rate; - count -= rcnts[index].target; + rcycles -= rcnts[index].target * rcnts[index].rate; + rcnts[index].cycleStart = psxRegs.cycle - rcycles; } else { - count = _psxRcntRcount( index ); + rcnts[index].cycle = 0x10000 * rcnts[index].rate; + rcnts[index].counterState = CountToOverflow; } - _psxRcntWcount( index, count ); - if( rcnts[index].mode & RcIrqOnTarget ) { if( (rcnts[index].mode & RcIrqRegenerate) || (!rcnts[index].irqState) ) { - verboseLog( 3, "[RCNT %i] irq: %x\n", index, count ); + verboseLog( 3, "[RCNT %i] irq\n", index ); setIrq( rcnts[index].irq ); rcnts[index].irqState = 1; } } rcnts[index].mode |= RcCountEqTarget; + + if( rcycles < 0x10000 * rcnts[index].rate ) + return; } - else if( rcnts[index].counterState == CountToOverflow ) + + if( rcnts[index].counterState == CountToOverflow ) { - count = psxRegs.cycle; - count -= rcnts[index].cycleStart; - count /= rcnts[index].rate; - count -= 0xffff; + rcycles = psxRegs.cycle - rcnts[index].cycleStart; + rcycles -= 0x10000 * rcnts[index].rate; + + rcnts[index].cycleStart = psxRegs.cycle - rcycles; - _psxRcntWcount( index, count ); + if( rcycles < rcnts[index].target * rcnts[index].rate ) + { + rcnts[index].cycle = rcnts[index].target * rcnts[index].rate; + rcnts[index].counterState = CountToTarget; + } if( rcnts[index].mode & RcIrqOnOverflow ) { if( (rcnts[index].mode & RcIrqRegenerate) || (!rcnts[index].irqState) ) { - verboseLog( 3, "[RCNT %i] irq: %x\n", index, count ); + verboseLog( 3, "[RCNT %i] irq\n", index ); setIrq( rcnts[index].irq ); rcnts[index].irqState = 1; } @@ -234,32 +327,61 @@ void psxRcntReset( u32 index ) rcnts[index].mode |= RcOverflow; } +} - rcnts[index].mode |= RcUnknown10; +static void scheduleRcntBase(void) +{ + // Schedule next call, in hsyncs + if (hSyncCount < VBlankStart) + hsync_steps = VBlankStart - hSyncCount; + else + hsync_steps = HSyncTotal[Config.PsxType] - hSyncCount; - psxRcntSet(); + if (hSyncCount + hsync_steps == HSyncTotal[Config.PsxType]) + { + rcnts[3].cycle = frameCycles(); + } + else + { + // clk / 50 / 314 ~= 2157.25 + // clk / 60 / 263 ~= 2146.31 + u32 mult = Config.PsxType ? 8836089 : 8791293; + rcnts[3].cycle = hsync_steps * mult >> 12; + } } void psxRcntUpdate() { - u32 cycle; + u32 cycle, cycles_passed; cycle = psxRegs.cycle; // rcnt 0. - if( cycle - rcnts[0].cycleStart >= rcnts[0].cycle ) + cycles_passed = cycle - rcnts[0].cycleStart; + while( cycles_passed >= rcnts[0].cycle ) { - psxRcntReset( 0 ); + if (((rcnts[0].mode & 7) == (RcSyncModeEnable | Rc01UnblankReset) || + (rcnts[0].mode & 7) == (RcSyncModeEnable | Rc01UnblankReset2)) + && cycles_passed > lineCycles()) + { + u32 q = cycles_passed / (lineCycles() + 1u); + rcnts[0].cycleStart += q * lineCycles(); + break; + } + else + psxRcntReset( 0 ); + + cycles_passed = cycle - rcnts[0].cycleStart; } // rcnt 1. - if( cycle - rcnts[1].cycleStart >= rcnts[1].cycle ) + while( cycle - rcnts[1].cycleStart >= rcnts[1].cycle ) { psxRcntReset( 1 ); } // rcnt 2. - if( cycle - rcnts[2].cycleStart >= rcnts[2].cycle ) + while( cycle - rcnts[2].cycleStart >= rcnts[2].cycle ) { psxRcntReset( 2 ); } @@ -267,45 +389,70 @@ void psxRcntUpdate() // rcnt base. if( cycle - rcnts[3].cycleStart >= rcnts[3].cycle ) { - psxRcntReset( 3 ); - - spuSyncCount++; - hSyncCount++; + hSyncCount += hsync_steps; - // Update spu. - if( spuSyncCount >= SpuUpdInterval[Config.PsxType] ) + // VSync irq. + if( hSyncCount == VBlankStart ) { - spuSyncCount = 0; + HW_GPU_STATUS &= SWAP32(~PSXGPU_LCF); + GPU_vBlank( 1, 0 ); + setIrq( 0x01 ); + + EmuUpdate(); + GPU_updateLace(); if( SPU_async ) { - SPU_async( SpuUpdInterval[Config.PsxType] * rcnts[3].target ); + SPU_async( cycle, 1 ); } } - // VSync irq. - if( hSyncCount == VBlankStart[Config.PsxType] ) - { - GPU_vBlank( 1 ); - - // For the best times. :D - //setIrq( 0x01 ); - } - - // Update lace. (with InuYasha fix) - if( hSyncCount >= (Config.VSyncWA ? HSyncTotal[Config.PsxType] / BIAS : HSyncTotal[Config.PsxType]) ) + // Update lace. + if( hSyncCount >= HSyncTotal[Config.PsxType] ) { + u32 status, field = 0; + rcnts[3].cycleStart += frameCycles(); hSyncCount = 0; + frame_counter++; + + gpuSyncPluginSR(); + status = SWAP32(HW_GPU_STATUS) | PSXGPU_FIELD; + if ((status & PSXGPU_ILACE_BITS) == PSXGPU_ILACE_BITS) { + field = frame_counter & 1; + status |= field << 31; + status ^= field << 13; + } + HW_GPU_STATUS = SWAP32(status); + GPU_vBlank(0, field); + if ((s32)(psxRegs.gpuIdleAfter - psxRegs.cycle) < 0) + psxRegs.gpuIdleAfter = psxRegs.cycle - 1; // prevent overflow - GPU_vBlank( 0 ); - setIrq( 0x01 ); + if ((rcnts[0].mode & 7) == (RcSyncModeEnable | Rc01UnblankReset) || + (rcnts[0].mode & 7) == (RcSyncModeEnable | Rc01UnblankReset2)) + { + rcnts[0].cycleStart = rcnts[3].cycleStart; + } - GPU_updateLace(); - EmuUpdate(); + if ((rcnts[1].mode & 7) == (RcSyncModeEnable | Rc01UnblankReset) || + (rcnts[1].mode & 7) == (RcSyncModeEnable | Rc01UnblankReset2)) + { + rcnts[1].cycleStart = rcnts[3].cycleStart; + } + else if (rcnts[1].mode & Rc1HSyncClock) + { + // adjust to remove the rounding error + _psxRcntWcount(1, (psxRegs.cycle - rcnts[1].cycleStart) / rcnts[1].rate); + } } + + scheduleRcntBase(); } + psxRcntSet(); + +#if 0 //ndef NDEBUG DebugVSync(); +#endif } /******************************************************************************/ @@ -314,8 +461,6 @@ void psxRcntWcount( u32 index, u32 value ) { verboseLog( 2, "[RCNT %i] wcount: %x\n", index, value ); - psxRcntUpdate(); - _psxRcntWcount( index, value ); psxRcntSet(); } @@ -324,52 +469,10 @@ void psxRcntWmode( u32 index, u32 value ) { verboseLog( 1, "[RCNT %i] wmode: %x\n", index, value ); - psxRcntUpdate(); + _psxRcntWmode( index, value ); + _psxRcntWcount( index, 0 ); - rcnts[index].mode = value; rcnts[index].irqState = 0; - - switch( index ) - { - case 0: - if( value & Rc0PixelClock ) - { - rcnts[index].rate = 5; - } - else - { - rcnts[index].rate = 1; - } - break; - case 1: - if( value & Rc1HSyncClock ) - { - rcnts[index].rate = (PSXCLK / (FrameRate[Config.PsxType] * HSyncTotal[Config.PsxType])); - } - else - { - rcnts[index].rate = 1; - } - break; - case 2: - if( value & Rc2OneEighthClock ) - { - rcnts[index].rate = 8; - } - else - { - rcnts[index].rate = 1; - } - - // TODO: wcount must work. - if( value & Rc2Disable ) - { - rcnts[index].rate = 0xffffffff; - } - break; - } - - _psxRcntWcount( index, 0 ); psxRcntSet(); } @@ -377,8 +480,6 @@ void psxRcntWtarget( u32 index, u32 value ) { verboseLog( 1, "[RCNT %i] wtarget: %x\n", index, value ); - psxRcntUpdate(); - rcnts[index].target = value; _psxRcntWcount( index, _psxRcntRcount( index ) ); @@ -387,27 +488,47 @@ void psxRcntWtarget( u32 index, u32 value ) /******************************************************************************/ -u32 psxRcntRcount( u32 index ) +u32 psxRcntRcount0() { + u32 index = 0; u32 count; - psxRcntUpdate(); + if ((rcnts[0].mode & 7) == (RcSyncModeEnable | Rc01UnblankReset) || + (rcnts[0].mode & 7) == (RcSyncModeEnable | Rc01UnblankReset2)) + { + count = psxRegs.cycle - rcnts[index].cycleStart; + //count = ((16u * count) % (16u * PSXCLK / 60 / 263)) / 16u; + count = count % lineCycles(); + rcnts[index].cycleStart = psxRegs.cycle - count; + } + else + count = _psxRcntRcount( index ); + + verboseLog( 2, "[RCNT 0] rcount: %04x m: %04x\n", count, rcnts[index].mode); + + return count; +} + +u32 psxRcntRcount1() +{ + u32 index = 1; + u32 count; count = _psxRcntRcount( index ); - // Parasite Eve 2 fix. - if( Config.RCntFix ) - { - if( index == 2 ) - { - if( rcnts[index].counterState == CountToTarget ) - { - count /= BIAS; - } - } - } + verboseLog( 2, "[RCNT 1] rcount: %04x m: %04x\n", count, rcnts[index].mode); + + return count; +} + +u32 psxRcntRcount2() +{ + u32 index = 2; + u32 count; + + count = _psxRcntRcount( index ); - verboseLog( 2, "[RCNT %i] rcount: %x\n", index, count ); + verboseLog( 2, "[RCNT 2] rcount: %04x m: %04x\n", count, rcnts[index].mode); return count; } @@ -416,8 +537,6 @@ u32 psxRcntRmode( u32 index ) { u16 mode; - psxRcntUpdate(); - mode = rcnts[index].mode; rcnts[index].mode &= 0xe7ff; @@ -453,8 +572,6 @@ void psxRcntInit() // rcnt base. rcnts[3].rate = 1; - rcnts[3].mode = RcCountToTarget; - rcnts[3].target = (PSXCLK / (FrameRate[Config.PsxType] * HSyncTotal[Config.PsxType])); for( i = 0; i < CounterQuantity; ++i ) { @@ -462,22 +579,42 @@ void psxRcntInit() } hSyncCount = 0; - spuSyncCount = 0; + hsync_steps = 1; + scheduleRcntBase(); psxRcntSet(); } /******************************************************************************/ -s32 psxRcntFreeze( gzFile f, s32 Mode ) +s32 psxRcntFreeze( void *f, s32 Mode ) { - gzfreeze( &rcnts, sizeof(rcnts) ); + u32 spuSyncCount = 0; + u32 count; + s32 i; + + gzfreeze( &rcnts, sizeof(Rcnt) * CounterQuantity ); gzfreeze( &hSyncCount, sizeof(hSyncCount) ); gzfreeze( &spuSyncCount, sizeof(spuSyncCount) ); gzfreeze( &psxNextCounter, sizeof(psxNextCounter) ); gzfreeze( &psxNextsCounter, sizeof(psxNextsCounter) ); + if (Mode == 0) + { + rcnts[3].rate = 1; + for( i = 0; i < CounterQuantity - 1; ++i ) + { + _psxRcntWmode( i, rcnts[i].mode ); + count = (psxRegs.cycle - rcnts[i].cycleStart) / rcnts[i].rate; + if (count > 0x1000) + _psxRcntWcount( i, count & 0xffff ); + } + scheduleRcntBase(); + psxRcntSet(); + } + return 0; } /******************************************************************************/ +// vim:ts=4:shiftwidth=4:expandtab