From f6864c422f219c9a06cb431535d84d7e71a612fe Mon Sep 17 00:00:00 2001 From: Brandon Wright Date: Fri, 18 May 2018 14:53:27 -0500 Subject: [PATCH] Different IRQ handling. --- cpu.cpp | 3 +-- cpuexec.cpp | 11 +++----- cpuexec.h | 42 ------------------------------ cpuops.cpp | 2 +- dma.cpp | 2 +- getset.h | 4 --- ppu.cpp | 72 ++++++++++++++++++++++++++++++++++++++++------------ ppu.h | 2 +- snapshot.cpp | 1 + snes9x.h | 1 + 10 files changed, 66 insertions(+), 74 deletions(-) diff --git a/cpu.cpp b/cpu.cpp index d0258c11..94057dc1 100644 --- a/cpu.cpp +++ b/cpu.cpp @@ -229,8 +229,6 @@ static void S9xSoftResetCPU (void) CPU.PCBase = NULL; CPU.NMIPending = FALSE; CPU.IRQLine = FALSE; - CPU.IRQTransition = FALSE; - CPU.IRQLastState = FALSE; CPU.IRQExternal = FALSE; CPU.IRQPending = Timings.IRQPendCount; CPU.MemSpeed = SLOW_ONE_CYCLE; @@ -268,6 +266,7 @@ static void S9xSoftResetCPU (void) Timings.H_Max = Timings.H_Max_Master; Timings.V_Max = Timings.V_Max_Master; Timings.NMITriggerPos = 0xffff; + Timings.NextTimer = 0xffff; if (Model->_5A22 == 2) Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2; else diff --git a/cpuexec.cpp b/cpuexec.cpp index ef1e03bd..70d72ee7 100644 --- a/cpuexec.cpp +++ b/cpuexec.cpp @@ -229,7 +229,7 @@ void S9xMainLoop (void) } } - if (CPU.IRQTransition || CPU.IRQExternal) + if (CPU.Cycles >= Timings.NextTimer || CPU.IRQExternal) { if (CPU.IRQPending) CPU.IRQPending--; @@ -241,7 +241,7 @@ void S9xMainLoop (void) Registers.PCw++; } - CPU.IRQTransition = FALSE; + S9xUpdateIRQPositions(); CPU.IRQPending = Timings.IRQPendCount; if (!CheckFlag(IRQ)) @@ -288,9 +288,7 @@ void S9xMainLoop (void) if (CPU.PCBase) { Op = CPU.PCBase[Registers.PCw]; - CPU.PrevCycles = CPU.Cycles; CPU.Cycles += CPU.MemSpeed; - S9xCheckInterrupts(); Opcodes = ICPU.S9xOpcodes; } else @@ -414,9 +412,10 @@ void S9xDoHEventProcessing (void) S9xAPUEndScanline(); CPU.Cycles -= Timings.H_Max; - CPU.PrevCycles -= Timings.H_Max; if (Timings.NMITriggerPos != 0xffff) Timings.NMITriggerPos -= Timings.H_Max; + if (Timings.NextTimer != 0xffff) + Timings.NextTimer -= Timings.H_Max; S9xAPUSetReferenceTime(CPU.Cycles); CPU.V_Counter++; @@ -557,9 +556,7 @@ void S9xDoHEventProcessing (void) S9xTraceFormattedMessage("*** WRAM Refresh HC:%04d", CPU.Cycles); #endif - CPU.PrevCycles = CPU.Cycles; CPU.Cycles += SNES_WRAM_REFRESH_CYCLES; - S9xCheckInterrupts(); S9xReschedule(); diff --git a/cpuexec.h b/cpuexec.h index 1a56d2cd..01a9a25c 100644 --- a/cpuexec.h +++ b/cpuexec.h @@ -287,46 +287,4 @@ static inline void S9xFixCycles (void) } } -static inline void S9xCheckInterrupts (void) -{ - bool8 thisIRQ = PPU.HTimerEnabled | PPU.VTimerEnabled; - - if (CPU.IRQLine & thisIRQ) - CPU.IRQTransition = TRUE; - - if (PPU.HTimerEnabled) - { - int32 htimepos = PPU.HTimerPosition; - if ((CPU.Cycles >= Timings.H_Max) & (htimepos < CPU.PrevCycles)) - htimepos += Timings.H_Max; - - if ((CPU.PrevCycles >= htimepos) | (CPU.Cycles < htimepos)) - thisIRQ = FALSE; - } - - if (PPU.VTimerEnabled) - { - int32 vcounter = CPU.V_Counter; - if ((CPU.Cycles >= Timings.H_Max) & ((!PPU.HTimerEnabled) | (PPU.HTimerPosition < CPU.PrevCycles))) { - vcounter++; - if(vcounter >= Timings.V_Max) - vcounter = 0; - } - - if (vcounter != PPU.VTimerPosition) - thisIRQ = FALSE; - } - - if ((!CPU.IRQLastState) & thisIRQ) - { -#ifdef DEBUGGER - S9xTraceFormattedMessage("--- /IRQ High->Low prev HC:%04d curr HC:%04d HTimer:%d Pos:%04d VTimer:%d Pos:%03d", - CPU.PrevCycles, CPU.Cycles, PPU.HTimerEnabled, PPU.HTimerPosition, PPU.VTimerEnabled, PPU.VTimerPosition); -#endif - CPU.IRQLine = TRUE; - } - - CPU.IRQLastState = thisIRQ; -} - #endif diff --git a/cpuops.cpp b/cpuops.cpp index 98a61675..d2cc497a 100644 --- a/cpuops.cpp +++ b/cpuops.cpp @@ -205,7 +205,7 @@ #ifdef SA1_OPCODES #define AddCycles(n) { SA1.Cycles += (n); } #else -#define AddCycles(n) { CPU.PrevCycles = CPU.Cycles; CPU.Cycles += (n); S9xCheckInterrupts(); while (CPU.Cycles >= CPU.NextEvent) S9xDoHEventProcessing(); } +#define AddCycles(n) { CPU.Cycles += (n); while (CPU.Cycles >= CPU.NextEvent) S9xDoHEventProcessing(); } #endif #include "cpuaddr.h" diff --git a/dma.cpp b/dma.cpp index b079b8cc..6f21fee5 100644 --- a/dma.cpp +++ b/dma.cpp @@ -200,7 +200,7 @@ #include "missing.h" #endif -#define ADD_CYCLES(n) { CPU.PrevCycles = CPU.Cycles; CPU.Cycles += (n); S9xCheckInterrupts(); } +#define ADD_CYCLES(n) { CPU.Cycles += (n); } extern uint8 *HDMAMemPointers[8]; extern int HDMA_ModeByteCounts[8]; diff --git a/getset.h b/getset.h index e2b70461..9778803e 100644 --- a/getset.h +++ b/getset.h @@ -206,9 +206,7 @@ #define addCyclesInMemoryAccess \ if (!CPU.InDMAorHDMA) \ { \ - CPU.PrevCycles = CPU.Cycles; \ CPU.Cycles += speed; \ - S9xCheckInterrupts(); \ while (CPU.Cycles >= CPU.NextEvent) \ S9xDoHEventProcessing(); \ } @@ -216,9 +214,7 @@ #define addCyclesInMemoryAccess_x2 \ if (!CPU.InDMAorHDMA) \ { \ - CPU.PrevCycles = CPU.Cycles; \ CPU.Cycles += speed << 1; \ - S9xCheckInterrupts(); \ while (CPU.Cycles >= CPU.NextEvent) \ S9xDoHEventProcessing(); \ } diff --git a/ppu.cpp b/ppu.cpp index 4d05d512..3375919a 100644 --- a/ppu.cpp +++ b/ppu.cpp @@ -269,7 +269,43 @@ static inline void S9xTryGunLatch (bool force) } } -void S9xUpdateHVTimerPosition (void) +static int CyclesUntilNext (int hc, int vc) +{ + int32 total = 0; + int vpos = CPU.V_Counter; + + // Advance to next hc + total = (hc - CPU.Cycles); + if (total < 0) + { + total += Timings.H_Max; + vpos++; + } + + if (vc - vpos >= 0) + { + // It's still in this frame */ + // Add number of lines + total += (vc - vpos) * Timings.H_Max; + // If line 240 is in there and we're odd, subtract a dot + if (vpos <= 240 && vc > 240 && Timings.InterlaceField) + total -= ONE_DOT_CYCLE; + } + else + { + total += (Timings.V_Max - vpos) * Timings.H_Max; + if (vpos <= 240 && Timings.InterlaceField) + total -= ONE_DOT_CYCLE; + + total += (vc) * Timings.H_Max; + if (vc > 240 && !Timings.InterlaceField) + total -= ONE_DOT_CYCLE; + } + + return total; +} + +void S9xUpdateIRQPositions (void) { PPU.HTimerPosition = PPU.IRQHBeamPos * ONE_DOT_CYCLE + Timings.IRQTriggerCycles; if (Timings.H_Max == Timings.H_Max_Master) // 1364 @@ -291,6 +327,16 @@ void S9xUpdateHVTimerPosition (void) PPU.VTimerPosition = 0; } + if (!PPU.HTimerEnabled && !PPU.VTimerEnabled) + { + Timings.NextTimer = 0xffff; + } + else + { + Timings.NextTimer = + CyclesUntilNext (PPU.HTimerEnabled ? PPU.HTimerPosition : 0, + PPU.VTimerEnabled ? PPU.VTimerPosition : 0); + } #ifdef DEBUGGER S9xTraceFormattedMessage("--- IRQ Timer set HTimer:%d Pos:%04d VTimer:%d Pos:%03d", PPU.HTimerEnabled, PPU.HTimerPosition, PPU.VTimerEnabled, PPU.VTimerPosition); @@ -1502,14 +1548,10 @@ void S9xSetCPU (uint8 Byte, uint16 Address) else PPU.HTimerEnabled = FALSE; - if (CPU.IRQLine && !PPU.HTimerEnabled && PPU.VTimerEnabled) - CPU.IRQTransition = TRUE; - - if (!PPU.HTimerEnabled && !PPU.VTimerEnabled) - { + if (!(Byte & 0x10) && !(Byte & 0x20)) CPU.IRQLine = FALSE; - CPU.IRQTransition = FALSE; - } + + S9xUpdateIRQPositions(); // NMI can trigger immediately during VBlank as long as NMI_read ($4210) wasn't cleard. if ((Byte & 0x80) && !(Memory.FillRAM[0x4200] & 0x80) && @@ -1576,7 +1618,7 @@ if (Settings.TraceHCEvent) pos = PPU.IRQHBeamPos; PPU.IRQHBeamPos = (PPU.IRQHBeamPos & 0xff00) | Byte; if (PPU.IRQHBeamPos != pos) - S9xUpdateHVTimerPosition(); + S9xUpdateIRQPositions(); #ifdef DEBUGGER missing.hirq_pos = PPU.IRQHBeamPos; #endif @@ -1586,7 +1628,7 @@ if (Settings.TraceHCEvent) pos = PPU.IRQHBeamPos; PPU.IRQHBeamPos = (PPU.IRQHBeamPos & 0xff) | ((Byte & 1) << 8); if (PPU.IRQHBeamPos != pos) - S9xUpdateHVTimerPosition(); + S9xUpdateIRQPositions(); #ifdef DEBUGGER missing.hirq_pos = PPU.IRQHBeamPos; #endif @@ -1596,7 +1638,7 @@ if (Settings.TraceHCEvent) pos = PPU.IRQVBeamPos; PPU.IRQVBeamPos = (PPU.IRQVBeamPos & 0xff00) | Byte; if (PPU.IRQVBeamPos != pos) - S9xUpdateHVTimerPosition(); + S9xUpdateIRQPositions(); #ifdef DEBUGGER missing.virq_pos = PPU.IRQVBeamPos; #endif @@ -1606,7 +1648,7 @@ if (Settings.TraceHCEvent) pos = PPU.IRQVBeamPos; PPU.IRQVBeamPos = (PPU.IRQVBeamPos & 0xff) | ((Byte & 1) << 8); if (PPU.IRQVBeamPos != pos) - S9xUpdateHVTimerPosition(); + S9xUpdateIRQPositions(); #ifdef DEBUGGER missing.virq_pos = PPU.IRQVBeamPos; #endif @@ -1617,9 +1659,7 @@ if (Settings.TraceHCEvent) return; // XXX: Not quite right... if (Byte) { - CPU.PrevCycles = CPU.Cycles; - CPU.Cycles += Timings.DMACPUSync; - S9xCheckInterrupts(); + CPU.Cycles += Timings.DMACPUSync; } if (Byte & 0x01) S9xDoDMA(0); @@ -1795,7 +1835,7 @@ uint8 S9xGetCPU (uint16 Address) case 0x4211: // TIMEUP byte = CPU.IRQLine ? 0x80 : 0; CPU.IRQLine = FALSE; - CPU.IRQTransition = FALSE; + S9xUpdateIRQPositions(); return (byte | (OpenBus & 0x7f)); diff --git a/ppu.h b/ppu.h index cff1e721..f519c14e 100644 --- a/ppu.h +++ b/ppu.h @@ -389,7 +389,7 @@ void S9xSetPPU (uint8, uint16); uint8 S9xGetPPU (uint16); void S9xSetCPU (uint8, uint16); uint8 S9xGetCPU (uint16); -void S9xUpdateHVTimerPosition (void); +void S9xUpdateIRQPositions (void); void S9xFixColourBrightness (void); void S9xDoAutoJoypad (void); diff --git a/snapshot.cpp b/snapshot.cpp index 2aee63a9..5200da8c 100644 --- a/snapshot.cpp +++ b/snapshot.cpp @@ -1780,6 +1780,7 @@ int S9xUnfreezeFromStream (STREAM stream) ICPU.ShiftedDB = Registers.DB << 16; S9xSetPCBase(Registers.PBPC); S9xUnpackStatus(); + S9xUpdateIRQPositions(); S9xFixCycles(); for (int d = 0; d < 8; d++) diff --git a/snes9x.h b/snes9x.h index 6428f825..1bf0f778 100644 --- a/snes9x.h +++ b/snes9x.h @@ -346,6 +346,7 @@ struct STimings int32 HDMAInit; int32 HDMAStart; int32 NMITriggerPos; + int32 NextTimer; int32 IRQTriggerCycles; int32 WRAMRefreshPos; int32 RenderPos;