*/
#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
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;
/******************************************************************************/
+static inline
+u32 lineCycles(void)
+{
+ if (Config.PsxType)
+ return PSXCLK / 50 / HSyncTotal[1];
+ else
+ return PSXCLK / 60 / HSyncTotal[0];
+}
+
static inline
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 ];
vsprintf( buf, str, va );
va_end( va );
- printf( buf );
+ printf( "%s", buf );
fflush( stdout );
}
+#endif
}
/******************************************************************************/
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;
}
else
{
- rcnts[index].cycle = 0xffff * rcnts[index].rate;
+ rcnts[index].cycle = 0x10000 * rcnts[index].rate;
rcnts[index].counterState = CountToOverflow;
}
}
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
psxNextCounter = countToUpdate;
}
}
+
+ set_event(PSXINT_RCNT, psxNextCounter);
}
/******************************************************************************/
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;
- _psxRcntWcount( index, count );
+ rcnts[index].cycleStart = psxRegs.cycle - rcycles;
+
+ 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;
}
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 = Config.PsxType ? PSXCLK / 50 : PSXCLK / 60;
+ }
+ 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 );
}
// 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 += Config.PsxType ? PSXCLK / 50 : PSXCLK / 60;
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
}
/******************************************************************************/
{
verboseLog( 2, "[RCNT %i] wcount: %x\n", index, value );
- psxRcntUpdate();
-
_psxRcntWcount( index, value );
psxRcntSet();
}
{
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();
}
{
verboseLog( 1, "[RCNT %i] wtarget: %x\n", index, value );
- psxRcntUpdate();
-
rcnts[index].target = value;
_psxRcntWcount( index, _psxRcntRcount( index ) );
/******************************************************************************/
-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;
}
{
u16 mode;
- psxRcntUpdate();
-
mode = rcnts[index].mode;
rcnts[index].mode &= 0xe7ff;
// 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 );
}
+ hSyncCount = 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