diff options
| author | SND\edgbla_cp <SND\edgbla_cp@e17a0e51-4ae3-4d35-97c3-1a29b211df97> | 2010-05-02 16:52:05 +0000 |
|---|---|---|
| committer | SND\edgbla_cp <SND\edgbla_cp@e17a0e51-4ae3-4d35-97c3-1a29b211df97> | 2010-05-02 16:52:05 +0000 |
| commit | 462adb75586b96728d66698bb20a934f38dd674d (patch) | |
| tree | 5a5ed9684f69c53e5896f0b6f1e15fb08203eed4 /libpcsxcore/psxcounters.c | |
| parent | 3adece8b48417154bcb6d6d0932db74458e6835c (diff) | |
| download | pcsxr-462adb75586b96728d66698bb20a934f38dd674d.tar.gz | |
Root counters code was written from scratch.
Final Fantasy 8/9, Vandal Hearts 1/2, Wipeout, Lifeforce Tenka work properly now.
Parasite Eve 2 and InuYasha weren't fixed - it's impossible right now, an overall
emulator's precision is too low. It's needed to count the proper CPU timing and to get rid of BIAS.
Because of the same reason it's useless to set the vsync interrupt on vblank, even if it
would fix some games - Pandemonium for example, but would also broke the
others - Final Fantasy IX for example, I've chosen the last one.
Savestate compatibility is lost.
git-svn-id: https://pcsxr.svn.codeplex.com/svn/pcsxr@47077 e17a0e51-4ae3-4d35-97c3-1a29b211df97
Diffstat (limited to 'libpcsxcore/psxcounters.c')
| -rw-r--r-- | libpcsxcore/psxcounters.c | 600 |
1 files changed, 411 insertions, 189 deletions
diff --git a/libpcsxcore/psxcounters.c b/libpcsxcore/psxcounters.c index 34710299..2b7acaf1 100644 --- a/libpcsxcore/psxcounters.c +++ b/libpcsxcore/psxcounters.c @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * Copyright (C) 2010 by Blade_Arma * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -18,230 +18,452 @@ ***************************************************************************/ /* -* Internal PSX counters. -*/ + * Internal PSX counters. + */ #include "psxcounters.h" #include "cheat.h" -static int cnts = 4; -psxCounter psxCounters[5]; - -static void psxRcntUpd(unsigned long index) { - psxCounters[index].sCycle = psxRegs.cycle; - if (((!(psxCounters[index].mode & 1)) || (index!=2)) && - psxCounters[index].mode & 0x30) { - if (psxCounters[index].mode & 0x10) { // Interrupt on target - psxCounters[index].Cycle = ((psxCounters[index].target - psxCounters[index].count) * psxCounters[index].rate) / BIAS; - } else { // Interrupt on 0xffff - psxCounters[index].Cycle = ((0xffff - psxCounters[index].count) * psxCounters[index].rate) / BIAS; - } - } else psxCounters[index].Cycle = 0xffffffff; -// if (index == 2) SysPrintf("Cycle %x\n", psxCounters[index].Cycle); +/******************************************************************************/ + +typedef struct +{ + 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 not implemented + RcUnknown1 = 0x0002, // 1 ? + RcUnknown2 = 0x0004, // 2 ? + RcCountToTarget = 0x0008, // 3 + RcIrqOnTarget = 0x0010, // 4 + RcIrqOnOverflow = 0x0020, // 5 + RcIrqRegenerate = 0x0040, // 6 + RcUnknown7 = 0x0080, // 7 ? + Rc0PixelClock = 0x0100, // 8 fake implementation + Rc1HSyncClock = 0x0100, // 8 + Rc2Unknown8 = 0x0100, // 8 ? + Rc0Unknown9 = 0x0200, // 9 ? + Rc1Unknown9 = 0x0200, // 9 ? + Rc2OneEighthClock = 0x0200, // 9 + RcUnknown10 = 0x0400, // 10 ? + RcCountEqTarget = 0x0800, // 11 + RcOverflow = 0x1000, // 12 + RcUnknown13 = 0x2000, // 13 ? (always zero) + RcUnknown14 = 0x4000, // 14 ? (always zero) + RcUnknown15 = 0x8000, // 15 ? (always zero) +}; + +#define CounterQuantity ( 4 ) +//static const u32 CounterQuantity = 4; + +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 s32 VerboseLevel = 0; + +/******************************************************************************/ + +static Rcnt rcnts[ CounterQuantity ]; + +static u32 hSyncCount; +static u32 spuSyncCount; + +/******************************************************************************/ + +static inline +void setIrq( u32 irq ) +{ + psxHu32ref(0x1070) |= SWAPu32(irq); + psxRegs.interrupt |= 0x80000000; } -static void psxRcntReset(unsigned long index) { -// SysPrintf("psxRcntReset %x (mode=%x)\n", index, psxCounters[index].mode); - psxCounters[index].count = 0; - psxRcntUpd(index); - -// if (index == 2) SysPrintf("rcnt2 %x\n", psxCounters[index].mode); - psxHu32ref(0x1070)|= SWAPu32(psxCounters[index].interrupt); - psxRegs.interrupt|= 0x80000000; - if (!(psxCounters[index].mode & 0x40)) { // Only 1 interrupt - psxCounters[index].Cycle = 0xffffffff; - } // else Continuos interrupt mode +static +void verboseLog( s32 level, const s8 *str, ... ) +{ + if( level <= VerboseLevel ) + { + va_list va; + char buf[ 4096 ]; + + va_start( va, str ); + vsprintf( buf, str, va ); + va_end( va ); + + printf( buf ); + fflush( stdout ); + } } -static void psxRcntSet() { - int i; - - psxNextCounter = 0x7fffffff; - psxNextsCounter = psxRegs.cycle; - - for (i=0; i<cnts; i++) { - s32 count; +/******************************************************************************/ + +static inline +void _psxRcntWcount( u32 index, u32 value ) +{ + if( value > 0xffff ) + { + verboseLog( 1, "[RCNT %i] wcount > 0xffff: %x\n", index, value ); + value &= 0xffff; + } + + rcnts[index].cycleStart = psxRegs.cycle * BIAS; + rcnts[index].cycleStart -= value * rcnts[index].rate; + + // TODO: <= + if( value < rcnts[index].target ) + { + rcnts[index].cycle = rcnts[index].target * rcnts[index].rate; + rcnts[index].counterState = CountToTarget; + } + else + { + rcnts[index].cycle = 0xffff * rcnts[index].rate; + rcnts[index].counterState = CountToOverflow; + } +} - if (psxCounters[i].Cycle == 0xffffffff) continue; +static inline +u32 _psxRcntRcount( u32 index ) +{ + u32 count; - count = psxCounters[i].Cycle - (psxRegs.cycle - psxCounters[i].sCycle); + count = psxRegs.cycle * BIAS; + count -= rcnts[index].cycleStart; + count /= rcnts[index].rate; - if (count < 0) { - psxNextCounter = 0; break; - } + if( count > 0xffff ) + { + verboseLog( 1, "[RCNT %i] rcount > 0xffff: %x\n", index, count ); + count &= 0xffff; + } - if (count < (s32)psxNextCounter) { - psxNextCounter = count; - } - } + return count; } -void psxRcntInit() { +/******************************************************************************/ + +static +void psxRcntSet() +{ + s32 countToUpdate; + u32 i; - memset(psxCounters, 0, sizeof(psxCounters)); + psxNextsCounter = psxRegs.cycle * BIAS; + psxNextCounter = 0x7fffffff; - psxCounters[0].rate = 1; psxCounters[0].interrupt = 0x10; - psxCounters[1].rate = 1; psxCounters[1].interrupt = 0x20; - psxCounters[2].rate = 1; psxCounters[2].interrupt = 0x40; + for( i = 0; i < CounterQuantity; ++i ) + { + countToUpdate = rcnts[i].cycle - (psxNextsCounter - rcnts[i].cycleStart); - psxCounters[3].interrupt = 1; - psxCounters[3].mode = 0x58; // The VSync counter mode - psxCounters[3].target = 1; - psxUpdateVSyncRate(); + if( countToUpdate < 0 ) + { + psxNextCounter = 0; + break; + } - if (SPU_async != NULL) { - cnts = 5; + if( countToUpdate < (s32)psxNextCounter ) + { + psxNextCounter = countToUpdate; + } + } +} - psxCounters[4].rate = 768 * 64; - psxCounters[4].target = 1; - psxCounters[4].mode = 0x58; - } else cnts = 4; +/******************************************************************************/ + +static +void psxRcntReset( u32 index ) +{ + u32 count; + + if( rcnts[index].counterState == CountToTarget ) + { + if( rcnts[index].mode & RcCountToTarget ) + { + count = psxRegs.cycle * BIAS; + count -= rcnts[index].cycleStart; + count /= rcnts[index].rate; + count -= rcnts[index].target; + } + else + { + count = _psxRcntRcount( index ); + } + + _psxRcntWcount( index, count ); + + if( rcnts[index].mode & RcIrqOnTarget ) + { + if( (rcnts[index].mode & RcIrqRegenerate) || (!rcnts[index].irqState) ) + { + setIrq( rcnts[index].irq ); + rcnts[index].irqState = 1; + } + } + + rcnts[index].mode |= RcCountEqTarget; + } + else if( rcnts[index].counterState == CountToOverflow ) + { + count = psxRegs.cycle * BIAS; + count -= rcnts[index].cycleStart; + count /= rcnts[index].rate; + count -= 0xffff; + + _psxRcntWcount( index, count ); + + if( rcnts[index].mode & RcIrqOnOverflow ) + { + if( (rcnts[index].mode & RcIrqRegenerate) || (!rcnts[index].irqState) ) + { + setIrq( rcnts[index].irq ); + rcnts[index].irqState = 1; + } + } + + rcnts[index].mode |= RcOverflow; + } + + rcnts[index].mode |= RcUnknown10; + + psxRcntSet(); +} - psxRcntUpd(0); psxRcntUpd(1); psxRcntUpd(2); psxRcntUpd(3); - psxRcntSet(); +void psxRcntUpdate() +{ + u32 cycle; + + cycle = psxRegs.cycle * BIAS; + + // rcnt 0. + if( cycle - rcnts[0].cycleStart >= rcnts[0].cycle ) + { + psxRcntReset( 0 ); + } + + // rcnt 1. + if( cycle - rcnts[1].cycleStart >= rcnts[1].cycle ) + { + psxRcntReset( 1 ); + } + + // rcnt 2. + if( cycle - rcnts[2].cycleStart >= rcnts[2].cycle ) + { + psxRcntReset( 2 ); + } + + // rcnt base. + if( cycle - rcnts[3].cycleStart >= rcnts[3].cycle ) + { + psxRcntReset( 3 ); + + spuSyncCount++; + hSyncCount++; + + // Update spu. + if( spuSyncCount == SpuUpdInterval[Config.PsxType] ) + { + spuSyncCount = 0; + + if( SPU_async ) + { + SPU_async( SpuUpdInterval[Config.PsxType] * rcnts[3].target ); + } + } + /* + // For the best times. :D + // VSync irq. + if( hSyncCount == VBlankStart[Config.PsxType] ) + { + setIrq( 0x01 ); + } + */ + // Update lace. (with InuYasha fix) + if( hSyncCount == (Config.VSyncWA ? HSyncTotal[Config.PsxType] / 2 : HSyncTotal[Config.PsxType]) ) + { + hSyncCount = 0; + + setIrq( 0x01 ); + + GPU_updateLace(); + SysUpdate(); + ApplyCheats(); + } + } + + DebugVSync(); } -void psxUpdateVSyncRate() { - if (Config.PsxType) // ntsc - 0 | pal - 1 - psxCounters[3].rate = (PSXCLK / 50);// / BIAS; - else psxCounters[3].rate = (PSXCLK / 60);// / BIAS; - psxCounters[3].rate-= (psxCounters[3].rate / 262) * 22; - if (Config.VSyncWA) psxCounters[3].rate/= 2; +/******************************************************************************/ + +void psxRcntWcount( u32 index, u32 value ) +{ + verboseLog( 2, "[RCNT %i] wcount: %x\n", index, value ); + + psxRcntUpdate(); + + _psxRcntWcount( index, value ); + psxRcntSet(); } -void psxUpdateVSyncRateEnd() { - if (Config.PsxType) // ntsc - 0 | pal - 1 - psxCounters[3].rate = (PSXCLK / 50);// / BIAS; - else psxCounters[3].rate = (PSXCLK / 60);// / BIAS; - psxCounters[3].rate = (psxCounters[3].rate / 262) * 22; - if (Config.VSyncWA) psxCounters[3].rate/= 2; +void psxRcntWmode( u32 index, u32 value ) +{ + verboseLog( 1, "[RCNT %i] wmode: %x\n", index, value ); + + psxRcntUpdate(); + + 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; + } + break; + } + + _psxRcntWcount( index, 0 ); + psxRcntSet(); } -void psxRcntUpdate() { - if ((psxRegs.cycle - psxCounters[3].sCycle) >= psxCounters[3].Cycle) { - if (psxCounters[3].mode & 0x10000) { // VSync End (22 hsyncs) - psxCounters[3].mode&=~0x10000; - psxUpdateVSyncRate(); - psxRcntUpd(3); - GPU_updateLace(); // updateGPU - SysUpdate(); - ApplyCheats(); -#ifdef GTE_LOG - GTE_LOG("VSync\n"); -#endif - } else { // VSync Start (240 hsyncs) - psxCounters[3].mode|= 0x10000; - psxUpdateVSyncRateEnd(); - psxRcntUpd(3); - psxHu32ref(0x1070)|= SWAPu32(1); - psxRegs.interrupt|= 0x80000000; - } - } - - if ((psxRegs.cycle - psxCounters[0].sCycle) >= psxCounters[0].Cycle) { - psxRcntReset(0); - } - - if ((psxRegs.cycle - psxCounters[1].sCycle) >= psxCounters[1].Cycle) { - psxRcntReset(1); - } - - if ((psxRegs.cycle - psxCounters[2].sCycle) >= psxCounters[2].Cycle) { - psxRcntReset(2); - } - - if (cnts >= 5) { - if ((psxRegs.cycle - psxCounters[4].sCycle) >= psxCounters[4].Cycle) { - SPU_async((psxRegs.cycle - psxCounters[4].sCycle) * BIAS); - psxRcntReset(4); - } - } - - psxRcntSet(); - DebugVSync(); +void psxRcntWtarget( u32 index, u32 value ) +{ + verboseLog( 1, "[RCNT %i] wtarget: %x\n", index, value ); + + psxRcntUpdate(); + + rcnts[index].target = value; + + _psxRcntWcount( index, _psxRcntRcount( index ) ); + psxRcntSet(); } -void psxRcntWcount(u32 index, u32 value) { -// SysPrintf("writeCcount[%d] = %x\n", index, value); -// PSXCPU_LOG("writeCcount[%d] = %x\n", index, value); - psxCounters[index].count = value; - psxRcntUpd(index); - psxRcntSet(); +/******************************************************************************/ + +u32 psxRcntRcount( u32 index ) +{ + u32 count; + + psxRcntUpdate(); + + count = _psxRcntRcount( index ); + + // Parasite Eve 2 fix. + if( index == 2 ) + { + if( Config.RCntFix ) + { + if( rcnts[index].counterState == CountToTarget ) + { + count /= BIAS; + } + } + } + + verboseLog( 2, "[RCNT %i] rcount: %x\n", index, count ); + + return count; } -void psxRcntWmode(u32 index, u32 value) { -// SysPrintf("writeCmode[%ld] = %lx\n", index, value); - psxCounters[index].mode = value; - psxCounters[index].count = 0; - if(index == 0) { - switch (value & 0x300) { - case 0x100: - psxCounters[index].rate = ((psxCounters[3].rate /** BIAS*/) / 386) / 262; // seems ok - break; - default: - psxCounters[index].rate = 1; - } - } - else if(index == 1) { - switch (value & 0x300) { - case 0x100: - psxCounters[index].rate = (psxCounters[3].rate /** BIAS*/) / 262; // seems ok - break; - default: - psxCounters[index].rate = 1; - } - } - else if(index == 2) { - switch (value & 0x300) { - case 0x200: - psxCounters[index].rate = 8; // 1/8 speed - break; - default: - psxCounters[index].rate = 1; // normal speed - } - } - - // Need to set a rate and target - psxRcntUpd(index); - psxRcntSet(); +u32 psxRcntRmode( u32 index ) +{ + u16 mode; + + psxRcntUpdate(); + + mode = rcnts[index].mode; + rcnts[index].mode &= 0xe7ff; + + verboseLog( 2, "[RCNT %i] rmode: %x\n", index, mode ); + + return mode; } -void psxRcntWtarget(u32 index, u32 value) { -// SysPrintf("writeCtarget[%ld] = %lx\n", index, value); - psxCounters[index].target = value; - psxRcntUpd(index); - psxRcntSet(); +u32 psxRcntRtarget( u32 index ) +{ + verboseLog( 2, "[RCNT %i] rtarget: %x\n", index, rcnts[index].target ); + + return rcnts[index].target; } -u32 psxRcntRcount(u32 index) { - u32 ret; - -// if ((!(psxCounters[index].mode & 1)) || (index!=2)) { - if (psxCounters[index].mode & 0x08) { // Wrap at target - if (Config.RCntFix) { // Parasite Eve 2 - ret = (psxCounters[index].count + /*BIAS **/ ((psxRegs.cycle - psxCounters[index].sCycle) / psxCounters[index].rate)) & 0xffff; - } else { - ret = (psxCounters[index].count + BIAS * ((psxRegs.cycle - psxCounters[index].sCycle) / psxCounters[index].rate)) & 0xffff; - } - } else { // Wrap at 0xffff - ret = (psxCounters[index].count + BIAS * (psxRegs.cycle / psxCounters[index].rate)) & 0xffff; - if (Config.RCntFix) { // Vandal Hearts 1/2 - ret/= 16; - } - } -// return (psxCounters[index].count + BIAS * ((psxRegs.cycle - psxCounters[index].sCycle) / psxCounters[index].rate)) & 0xffff; -// } else return 0; - -// SysPrintf("readCcount[%ld] = %lx (mode %lx, target %lx, cycle %lx)\n", index, ret, psxCounters[index].mode, psxCounters[index].target, psxRegs.cycle); - - return ret; +/******************************************************************************/ + +void psxRcntInit() +{ + s32 i; + + // rcnt0. + rcnts[0].rate = 1; + rcnts[0].irq = 0x10; + + // rcnt1. + rcnts[1].rate = 1; + rcnts[1].irq = 0x20; + + // rcnt2. + rcnts[2].rate = 1; + rcnts[2].irq = 0x40; + + // 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 ) + { + _psxRcntWcount( i, 0 ); + } + + psxRcntSet(); } -int psxRcntFreeze(gzFile f, int Mode) { - char Unused[4096 - sizeof(psxCounter)]; +/******************************************************************************/ - gzfreezel(psxCounters); - gzfreezel(Unused); +s32 psxRcntFreeze( gzFile f, s32 Mode ) +{ + s8 unused[ 4096 - sizeof(rcnts) ]; - return 0; + gzfreezel( rcnts ); + gzfreezel( unused ); + + return 0; } + +/******************************************************************************/ |
