void Apu0D() { // PUSH PSW S9xAPUPackStatus(); Push(IAPU.Registers.P); IAPU.PC++; }
void Apu0F() { // BRK SPC700_PushW(IAPU.PC + 1 - IAPU.RAM); S9xAPUPackStatus(); Push(IAPU.Registers.P); APUSetBreak(); APUClearInterrupt(); // XXX:Where is the BRK vector ??? IAPU.PC = IAPU.RAM + APU.ExtraRAM[0x20] + (APU.ExtraRAM[0x21] << 8); }
static void SPCPlayExec(void) { for (int v = 0; v < Timings.V_Max; v++) { S9xAPUExecute(); APU.Cycles -= (Timings.H_Max << SNES_APU_ACCURACY); IAPU.NextAPUTimerPos -= (Timings.H_Max << SNES_APU_ACCURACY); } APURegisters.PC = IAPU.PC - IAPU.RAM; S9xAPUPackStatus(); }
void S9xMainLoop(void) { #ifndef ASMCPU if (Settings.APUEnabled == 1) { #ifdef USE_SA1 if (Settings.SA1) S9xMainLoop_SA1_APU(); else #endif S9xMainLoop_NoSA1_APU(); } else { #ifdef USE_SA1 if (Settings.SA1) S9xMainLoop_SA1_NoAPU(); else #endif S9xMainLoop_NoSA1_NoAPU(); } #else #ifdef ASM_SPC700 if (Settings.asmspc700) asmMainLoop_spcAsm(&CPU); else #endif asmMainLoop_spcC(&CPU); #endif Registers.PC = CPU.PC - CPU.PCBase; #ifndef ASMCPU S9xPackStatus(); #endif S9xAPUPackStatus(); //if (CPU.Flags & SCAN_KEYS_FLAG) // { CPU.Flags &= ~SCAN_KEYS_FLAG; //} if (CPU.BRKTriggered && Settings.SuperFX && !CPU.TriedInterleavedMode2) { CPU.TriedInterleavedMode2 = TRUE; CPU.BRKTriggered = FALSE; S9xDeinterleaveMode2(); } }
void Apu0F() { // BRK #if 0 STOP("BRK"); #else PushW((IAPU.PC + 1 - IAPU.RAM)); S9xAPUPackStatus(); Push(IAPU.P); APUSetBreak(); APUClearInterrupt(); // XXX:Where is the BRK vector ??? IAPU.PC = IAPU.RAM + APU.ExtraRAM[0x20] + (APU.ExtraRAM[0x21] << 8); #endif }
/* get samples ---------------------------------------------------------------- */ void SPC_update(unsigned char *buf) { // APU_LOOP int c, ic; #if 1 for (c = 0; c < 2048000 / 32 / RATE; c ++) { for (ic = 0; ic < 32; ic ++) APU_EXECUTE1(); IAPU.TimerErrorCounter ++; DoTimer(); } #else for (APU.Cycles = 0; APU.Cycles < 204800 / RATE; APU.Cycles ++) { APU_EXECUTE1(); ++ IAPU.TimerErrorCounter; if ((IAPU.TimerErrorCounter & 31) == 0) DoTimer(); APURegisters.PC = IAPU.PC - IAPU.RAM; S9xAPUPackStatus(); } #endif S9xMixSamples ((unsigned char *)buf, samples_per_mix); }
void S9xMainLoop (void) { for (;;) { APU_EXECUTE(); if (CPU.Flags) { if (CPU.Flags & NMI_FLAG) { if (Timings.NMITriggerPos <= CPU.Cycles) { CPU.Flags &= ~NMI_FLAG; Timings.NMITriggerPos = 0xffff; if (CPU.WaitingForInterrupt) { CPU.WaitingForInterrupt = FALSE; Registers.PCw++; } S9xOpcode_NMI(); } } #ifdef DEBUGGER if ((CPU.Flags & BREAK_FLAG) && !(CPU.Flags & SINGLE_STEP_FLAG)) { for (int Break = 0; Break != 6; Break++) { if (S9xBreakpoint[Break].Enabled && S9xBreakpoint[Break].Bank == Registers.PB && S9xBreakpoint[Break].Address == Registers.PCw) { if (S9xBreakpoint[Break].Enabled == 2) S9xBreakpoint[Break].Enabled = TRUE; else CPU.Flags |= DEBUG_MODE_FLAG; } } } #endif CHECK_SOUND(); if (CPU.Flags & IRQ_PENDING_FLAG) { if (CPU.WaitingForInterrupt) { CPU.WaitingForInterrupt = FALSE; Registers.PCw++; } if (CPU.IRQActive && !Settings.DisableIRQ) { if (!CheckFlag(IRQ)) S9xOpcode_IRQ(); } else CPU.Flags &= ~IRQ_PENDING_FLAG; } if (CPU.Flags & SCAN_KEYS_FLAG) break; #ifdef DEBUGGER if (CPU.Flags & DEBUG_MODE_FLAG) break; if (CPU.Flags & TRACE_FLAG) S9xTrace(); if (CPU.Flags & SINGLE_STEP_FLAG) { CPU.Flags &= ~SINGLE_STEP_FLAG; CPU.Flags |= DEBUG_MODE_FLAG; } #endif } #ifdef CPU_SHUTDOWN CPU.PBPCAtOpcodeStart = Registers.PBPC; #endif register uint8 Op; register struct SOpcodes *Opcodes; if (CPU.PCBase) { Op = CPU.PCBase[Registers.PCw]; CPU.Cycles += CPU.MemSpeed; Opcodes = ICPU.S9xOpcodes; } else { Op = S9xGetByte(Registers.PBPC); OpenBus = Op; Opcodes = S9xOpcodesSlow; } if ((Registers.PCw&MEMMAP_MASK) + ICPU.S9xOpLengths[Op] >= MEMMAP_BLOCK_SIZE) { uint8 *oldPCBase = CPU.PCBase; CPU.PCBase = GetBasePointer(ICPU.ShiftedPB + ((uint16) (Registers.PCw + 4))); if (oldPCBase!=CPU.PCBase || (Registers.PCw&~MEMMAP_MASK) == (0xffff & ~MEMMAP_MASK)) Opcodes = S9xOpcodesSlow; } Registers.PCw++; (*Opcodes[Op].S9xOpcode)(); S9xUpdateAPUTimer(); if (SA1.Executing) S9xSA1MainLoop(); if (CPU.Cycles >= CPU.NextEvent) S9xDoHEventProcessing(); } S9xPackStatus(); APURegisters.PC = IAPU.PC - IAPU.RAM; S9xAPUPackStatus(); if (CPU.Flags & SCAN_KEYS_FLAG) { #ifdef DEBUGGER if (!(CPU.Flags & FRAME_ADVANCE_FLAG)) #endif S9xSyncSpeed(); CPU.Flags &= ~SCAN_KEYS_FLAG; } }
void S9xDoHBlankProcessing () { #ifdef CPU_SHUTDOWN CPU.WaitCounter++; #endif switch (CPU.WhichEvent) { case HBLANK_START_EVENT: if (IPPU.HDMA && CPU.V_Counter <= PPU.ScreenHeight) IPPU.HDMA = S9xDoHDMA (IPPU.HDMA); break; case HBLANK_END_EVENT: S9xSuperFXExec (); #ifndef STORM if (Settings.SoundSync) S9xGenerateSound (); #endif CPU.Cycles -= Settings.H_Max; IAPU.NextAPUTimerPos -= (Settings.H_Max * 10000L); if (IAPU.APUExecuting) { APU.Cycles -= Settings.H_Max; #ifdef MK_APU S9xCatchupCount(); #endif } else APU.Cycles = 0; CPU.NextEvent = -1; ICPU.Scanline++; if (++CPU.V_Counter >= (Settings.PAL ? SNES_MAX_PAL_VCOUNTER : SNES_MAX_NTSC_VCOUNTER)) { CPU.V_Counter = 0; Memory.FillRAM[0x213F]^=0x80; PPU.RangeTimeOver = 0; CPU.NMIActive = FALSE; ICPU.Frame++; PPU.HVBeamCounterLatched = 0; CPU.Flags |= SCAN_KEYS_FLAG; S9xStartHDMA (); } if (PPU.VTimerEnabled && !PPU.HTimerEnabled && CPU.V_Counter == PPU.IRQVBeamPos) { S9xSetIRQ (PPU_V_BEAM_IRQ_SOURCE); } if (CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE) { // Start of V-blank S9xEndScreenRefresh (); IPPU.HDMA = 0; // Bits 7 and 6 of $4212 are computed when read in S9xGetPPU. #ifndef OPTI missing.dma_this_frame = 0; #endif // OPTI IPPU.MaxBrightness = PPU.Brightness; PPU.ForcedBlanking = (Memory.FillRAM [0x2100] >> 7) & 1; if(!PPU.ForcedBlanking){ PPU.OAMAddr = PPU.SavedOAMAddr; { uint8 tmp = 0; if(PPU.OAMPriorityRotation) tmp = (PPU.OAMAddr&0xFE)>>1; if((PPU.OAMFlip&1) || PPU.FirstSprite!=tmp){ PPU.FirstSprite=tmp; IPPU.OBJChanged=TRUE; } } PPU.OAMFlip = 0; } Memory.FillRAM[0x4210] = 0x80 |Model->_5A22; if (Memory.FillRAM[0x4200] & 0x80) { CPU.NMIActive = TRUE; CPU.Flags |= NMI_FLAG; CPU.NMICycleCount = CPU.NMITriggerPoint; } #ifdef OLD_SNAPSHOT_CODE if (CPU.Flags & SAVE_SNAPSHOT_FLAG) { CPU.Flags &= ~SAVE_SNAPSHOT_FLAG; Registers.PC = CPU.PC - CPU.PCBase; S9xPackStatus (); S9xAPUPackStatus (); Snapshot (NULL); } #endif }
void S9xMainLoop (void) { for (;;) { #ifdef DEBUG_MAXCOUNT CPU.GlobalLoopCount++; if(Settings.MaxCount && CPU.GlobalLoopCount == Settings.MaxCount) { fprintf(stderr, "Max loop count reached: %ld \n", Settings.MaxCount); S9xExit(); } #endif APU_EXECUTE (); if (CPU.Flags) { if (CPU.Flags & NMI_FLAG) { if (--CPU.NMICycleCount == 0) { CPU.Flags &= ~NMI_FLAG; if (CPU.WaitingForInterrupt) { CPU.WaitingForInterrupt = FALSE; CPU.PC++; } S9xOpcode_NMI (); } } #ifdef DEBUGGER if ((CPU.Flags & BREAK_FLAG) && !(CPU.Flags & SINGLE_STEP_FLAG)) { for (int Break = 0; Break != 6; Break++) { if (S9xBreakpoint[Break].Enabled && S9xBreakpoint[Break].Bank == Registers.PB && S9xBreakpoint[Break].Address == CPU.PC - CPU.PCBase) { if (S9xBreakpoint[Break].Enabled == 2) S9xBreakpoint[Break].Enabled = TRUE; else CPU.Flags |= DEBUG_MODE_FLAG; } } } #endif CHECK_SOUND (); if (CPU.Flags & IRQ_PENDING_FLAG) { if (CPU.IRQCycleCount == 0) { if (CPU.WaitingForInterrupt) { CPU.WaitingForInterrupt = FALSE; CPU.PC++; } if (CPU.IRQActive && !Settings.DisableIRQ) { if (!CheckFlag (IRQ)) S9xOpcode_IRQ (); } else CPU.Flags &= ~IRQ_PENDING_FLAG; } else { if(--CPU.IRQCycleCount==0 && CheckFlag (IRQ)) CPU.IRQCycleCount=1; } } #ifdef DEBUGGER if (CPU.Flags & DEBUG_MODE_FLAG) break; #endif if (CPU.Flags & SCAN_KEYS_FLAG) break; #ifdef DEBUGGER if (CPU.Flags & TRACE_FLAG) S9xTrace (); if (CPU.Flags & SINGLE_STEP_FLAG) { CPU.Flags &= ~SINGLE_STEP_FLAG; CPU.Flags |= DEBUG_MODE_FLAG; } #endif } #ifdef CPU_SHUTDOWN CPU.PCAtOpcodeStart = CPU.PC; #endif CPU.Cycles += CPU.MemSpeed; (*ICPU.S9xOpcodes [*CPU.PC++].S9xOpcode) (); S9xUpdateAPUTimer(); if (SA1.Executing) S9xSA1MainLoop (); DO_HBLANK_CHECK(); } Registers.PC = CPU.PC - CPU.PCBase; S9xPackStatus (); APURegisters.PC = IAPU.PC - IAPU.RAM; S9xAPUPackStatus (); if (CPU.Flags & SCAN_KEYS_FLAG) { #ifdef DEBUGGER if (!(CPU.Flags & FRAME_ADVANCE_FLAG)) #endif S9xSyncSpeed (); CPU.Flags &= ~SCAN_KEYS_FLAG; } #ifdef DETECT_NASTY_FX_INTERLEAVE if (CPU.BRKTriggered && Settings.SuperFX && !CPU.TriedInterleavedMode2) { CPU.TriedInterleavedMode2 = TRUE; CPU.BRKTriggered = FALSE; S9xDeinterleaveMode2 (); } #endif }
void S9xMainLoop (void) { if(ICPU.SavedAtOp) { ICPU.SavedAtOp = FALSE; Registers.PCw = CPU.PBPCAtOpcodeStart; if(CPU.PCBase) CPU.Cycles -= CPU.MemSpeed; goto doOp; } for (;;) { if (CPU.Flags) { if (CPU.Flags & NMI_FLAG) { if (Timings.NMITriggerPos <= CPU.Cycles) { CPU.Flags &= ~NMI_FLAG; Timings.NMITriggerPos = 0xffff; if (CPU.WaitingForInterrupt) { CPU.WaitingForInterrupt = FALSE; Registers.PCw++; } S9xOpcode_NMI(); } } #ifdef DEBUGGER if ((CPU.Flags & BREAK_FLAG) && !(CPU.Flags & SINGLE_STEP_FLAG)) { for (int Break = 0; Break != 6; Break++) { if (S9xBreakpoint[Break].Enabled && S9xBreakpoint[Break].Bank == Registers.PB && S9xBreakpoint[Break].Address == Registers.PCw) { if (S9xBreakpoint[Break].Enabled == 2) S9xBreakpoint[Break].Enabled = TRUE; else CPU.Flags |= DEBUG_MODE_FLAG; } } } #endif CHECK_SOUND(); if (CPU.Flags & IRQ_FLAG) { if (CPU.IRQPending) // FIXME: In case of IRQ during WRAM refresh CPU.IRQPending = 0; else { if (CPU.WaitingForInterrupt) { CPU.WaitingForInterrupt = FALSE; Registers.PCw++; } if (CPU.IRQActive && !Settings.DisableIRQ) { if (!CheckFlag(IRQ)) // in IRQ handler $4211 is supposed to be read, so IRQ_FLAG should be cleared. S9xOpcode_IRQ(); } else CPU.Flags &= ~IRQ_FLAG; } } if (CPU.Flags & SCAN_KEYS_FLAG) break; #ifdef DEBUGGER if (CPU.Flags & DEBUG_MODE_FLAG) break; if (CPU.Flags & TRACE_FLAG) S9xTrace(); if (CPU.Flags & SINGLE_STEP_FLAG) { CPU.Flags &= ~SINGLE_STEP_FLAG; CPU.Flags |= DEBUG_MODE_FLAG; } #endif } #ifdef CPU_SHUTDOWN CPU.PBPCAtOpcodeStart = Registers.PBPC; #endif doOp: register uint8 Op; register struct SOpcodes *Opcodes; CPU.PrevCycles = CPU.Cycles; if (CPU.PCBase) { Op = CPU.PCBase[Registers.PCw]; CPU.Cycles += CPU.MemSpeed; Opcodes = ICPU.S9xOpcodes; } else { Op = S9xGetByte(Registers.PBPC); OpenBus = Op; Opcodes = S9xOpcodesSlow; } if ((Registers.PCw&MEMMAP_MASK) + ICPU.S9xOpLengths[Op] >= MEMMAP_BLOCK_SIZE) { uint8 *oldPCBase = CPU.PCBase; CPU.PCBase = GetBasePointer(ICPU.ShiftedPB + ((uint16) (Registers.PCw + 4))); if (oldPCBase!=CPU.PCBase || (Registers.PCw&~MEMMAP_MASK) == (0xffff & ~MEMMAP_MASK)) Opcodes = S9xOpcodesSlow; } Registers.PCw++; (*Opcodes[Op].S9xOpcode)(); if(ICPU.SavedAtOp) { ICPU.SavedAtOp = false; continue; } S9xAPUExecute(); if (SA1.Executing) S9xSA1MainLoop(); while (CPU.Cycles >= CPU.NextEvent) S9xDoHEventProcessing(); } S9xPackStatus(); APURegisters.PC = IAPU.PC - IAPU.RAM; S9xAPUPackStatus(); if (CPU.Flags & SCAN_KEYS_FLAG) { #ifdef DEBUGGER if (!(CPU.Flags & FRAME_ADVANCE_FLAG)) #endif S9xSyncSpeed(); CPU.Flags &= ~SCAN_KEYS_FLAG; } }
void S9xDoHBlankProcessing (struct SCPUState *cpu, struct SAPU *apu, struct SIAPU *iapu) { struct SPPU *ppu = &PPU; struct InternalPPU *ippu = &IPPU; #ifdef CPU_SHUTDOWN cpu->WaitCounter++; #endif switch (cpu->WhichEvent) { case HBLANK_START_EVENT: if (ippu->HDMA && cpu->V_Counter <= ppu->ScreenHeight) ippu->HDMA = S9xDoHDMA (ippu, ppu, cpu); break; case HBLANK_END_EVENT: #ifndef _ZAURUS S9xSuperFXExec (); #endif #ifndef STORM #endif cpu->Cycles -= Settings.H_Max; if (iapu->APUExecuting) apu->Cycles -= Settings.H_Max; else apu->Cycles = 0; cpu->NextEvent = -1; ICPU.Scanline++; if (++cpu->V_Counter > (Settings.PAL ? SNES_MAX_PAL_VCOUNTER : SNES_MAX_NTSC_VCOUNTER)) { ppu->OAMAddr = ppu->SavedOAMAddr; ppu->OAMFlip = 0; cpu->V_Counter = 0; cpu->NMIActive = FALSE; ICPU.Frame++; ppu->HVBeamCounterLatched = 0; cpu->Flags |= SCAN_KEYS_FLAG; S9xStartHDMA (); } if (ppu->VTimerEnabled && !ppu->HTimerEnabled && cpu->V_Counter == ppu->IRQVBeamPos) { S9xSetIRQ (PPU_V_BEAM_IRQ_SOURCE, cpu); } if (cpu->V_Counter == ppu->ScreenHeight + FIRST_VISIBLE_LINE) { // Start of V-blank S9xEndScreenRefresh (ppu); ppu->FirstSprite = 0; ippu->HDMA = 0; // Bits 7 and 6 of $4212 are computed when read in S9xGetPPU. missing.dma_this_frame = 0; ippu->MaxBrightness = ppu->Brightness; ppu->ForcedBlanking = (Memory.FillRAM [0x2100] >> 7) & 1; Memory.FillRAM[0x4210] = 0x80; if (Memory.FillRAM[0x4200] & 0x80) { cpu->NMIActive = TRUE; cpu->Flags |= NMI_FLAG; cpu->NMICycleCount = cpu->NMITriggerPoint; } #ifdef OLD_SNAPSHOT_CODE if (cpu->Flags & SAVE_SNAPSHOT_FLAG) { cpu->Flags &= ~SAVE_SNAPSHOT_FLAG; Registers.PC = cpu->PC - cpu->PCBase; S9xPackStatus (); S9xAPUPackStatus (); Snapshot (NULL); } #endif } if (cpu->V_Counter == ppu->ScreenHeight + 3) S9xUpdateJoypads (&IPPU); if (cpu->V_Counter == FIRST_VISIBLE_LINE) { Memory.FillRAM[0x4210] = 0; cpu->Flags &= ~NMI_FLAG; S9xStartScreenRefresh (); } if (cpu->V_Counter >= FIRST_VISIBLE_LINE && cpu->V_Counter < ppu->ScreenHeight + FIRST_VISIBLE_LINE) { RenderLine (cpu->V_Counter - FIRST_VISIBLE_LINE, ppu); } // Use TimerErrorCounter to skip update of SPC700 timers once // every 128 updates. Needed because this section of code is called // once every emulated 63.5 microseconds, which coresponds to // 15.750KHz, but the SPC700 timers need to be updated at multiples // of 8KHz, hence the error correction. // IAPU.TimerErrorCounter++; // if (IAPU.TimerErrorCounter >= ) // IAPU.TimerErrorCounter = 0; // else { if (apu->TimerEnabled [2]) { apu->Timer [2] += 4; while (apu->Timer [2] >= apu->TimerTarget [2]) { iapu->RAM [0xff] = (iapu->RAM [0xff] + 1) & 0xf; apu->Timer [2] -= apu->TimerTarget [2]; #ifdef SPC700_SHUTDOWN iapu->WaitCounter++; iapu->APUExecuting = TRUE; #endif } } if (cpu->V_Counter & 1) { if (apu->TimerEnabled [0]) { apu->Timer [0]++; if (apu->Timer [0] >= apu->TimerTarget [0]) { iapu->RAM [0xfd] = (iapu->RAM [0xfd] + 1) & 0xf; apu->Timer [0] = 0; #ifdef SPC700_SHUTDOWN iapu->WaitCounter++; iapu->APUExecuting = TRUE; #endif } } if (apu->TimerEnabled [1]) { apu->Timer [1]++; if (apu->Timer [1] >= apu->TimerTarget [1]) { iapu->RAM [0xfe] = (iapu->RAM [0xfe] + 1) & 0xf; apu->Timer [1] = 0; #ifdef SPC700_SHUTDOWN iapu->WaitCounter++; iapu->APUExecuting = TRUE; #endif } } } } break; //HBLANK_END_EVENT case HTIMER_BEFORE_EVENT: case HTIMER_AFTER_EVENT: if (ppu->HTimerEnabled && (!ppu->VTimerEnabled || cpu->V_Counter == ppu->IRQVBeamPos)) { S9xSetIRQ (PPU_H_BEAM_IRQ_SOURCE, cpu); } break; }
void S9xMainLoop (void) { for (;;) { APU_EXECUTE (); if (CPU.Flags) { if (CPU.Flags & NMI_FLAG) { if (--CPU.NMICycleCount == 0) { CPU.Flags &= ~NMI_FLAG; if (CPU.WaitingForInterrupt) { CPU.WaitingForInterrupt = FALSE; CPU.PC++; } S9xOpcode_NMI (); } } if (CPU.Flags & IRQ_PENDING_FLAG) { if (CPU.IRQCycleCount == 0) { if (CPU.WaitingForInterrupt) { CPU.WaitingForInterrupt = FALSE; CPU.PC++; } if (CPU.IRQActive && !Settings.DisableIRQ) { if (!CheckFlag (IRQ)) S9xOpcode_IRQ (); } else CPU.Flags &= ~IRQ_PENDING_FLAG; } else CPU.IRQCycleCount--; } if (CPU.Flags & SCAN_KEYS_FLAG) break; } #ifdef CPU_SHUTDOWN CPU.PCAtOpcodeStart = CPU.PC; #endif CPU.Cycles += CPU.MemSpeed; (*ICPU.S9xOpcodes[*CPU.PC++].S9xOpcode) (); S9xUpdateAPUTimer (); if (SA1.Executing) S9xSA1MainLoop (); DO_HBLANK_CHECK (); } Registers.PC = CPU.PC - CPU.PCBase; S9xPackStatus (); (APURegistersUncached->PC) = (IAPUuncached->PC) - (IAPUuncached->RAM); S9xAPUPackStatus (); if (CPU.Flags & SCAN_KEYS_FLAG) { S9xSyncSpeed (); CPU.Flags &= ~SCAN_KEYS_FLAG; } if (CPU.BRKTriggered && Settings.SuperFX && !CPU.TriedInterleavedMode2) { CPU.TriedInterleavedMode2 = TRUE; CPU.BRKTriggered = FALSE; S9xDeinterleaveMode2 (); } }
void S9xMainLoop (struct SRegisters * reg, struct SICPU * icpu, struct SCPUState * cpu) { #else void S9xMainLoop (void) { struct SICPU * icpu = &ICPU; struct SCPUState * cpu = &CPU; struct SRegisters * reg = &Registers; #endif for (;;) { APU_EXECUTE (); if (CPU.Flags) { if (CPU.Flags & NMI_FLAG) { if (--CPU.NMICycleCount == 0) { CPU.Flags &= ~NMI_FLAG; if (CPU.WaitingForInterrupt) { CPU.WaitingForInterrupt = FALSE; ++CPU.PC; } S9xOpcode_NMI (); } } #ifdef DEBUGGER if ((CPU.Flags & BREAK_FLAG) && !(CPU.Flags & SINGLE_STEP_FLAG)) { for (int Break = 0; Break != 6; Break++) { if (S9xBreakpoint[Break].Enabled && S9xBreakpoint[Break].Bank == Registers.PB && S9xBreakpoint[Break].Address == CPU.PC - CPU.PCBase) { if (S9xBreakpoint[Break].Enabled == 2) S9xBreakpoint[Break].Enabled = TRUE; else CPU.Flags |= DEBUG_MODE_FLAG; } } } #endif CHECK_SOUND (); if (CPU.Flags & IRQ_PENDING_FLAG) { if (CPU.IRQCycleCount == 0) { if (CPU.WaitingForInterrupt) { CPU.WaitingForInterrupt = FALSE; CPU.PC++; } if (CPU.IRQActive && !Settings.DisableIRQ) { if (!CHECKFLAG (IRQ)) S9xOpcode_IRQ (); } else CPU.Flags &= ~IRQ_PENDING_FLAG; } else CPU.IRQCycleCount--; } #ifdef DEBUGGER if (CPU.Flags & DEBUG_MODE_FLAG) break; #endif if (CPU.Flags & SCAN_KEYS_FLAG) break; #ifdef DEBUGGER if (CPU.Flags & TRACE_FLAG) S9xTrace (); if (CPU.Flags & SINGLE_STEP_FLAG) { CPU.Flags &= ~SINGLE_STEP_FLAG; CPU.Flags |= DEBUG_MODE_FLAG; } #endif } //if (CPU.Flags) #ifdef CPU_SHUTDOWN CPU.PCAtOpcodeStart = CPU.PC; #endif #ifdef VAR_CYCLES CPU.Cycles += CPU.MemSpeed; #else CPU.Cycles += ICPU.Speed [*CPU.PC]; #endif (*ICPU.S9xOpcodes [*CPU.PC++].S9xOpcode) (&Registers, &ICPU, &CPU); if (SA1.Executing) S9xSA1MainLoop (); DO_HBLANK_CHECK(); } // for(;;) Registers.PC = CPU.PC - CPU.PCBase; S9xPackStatus (); APURegisters.PC = IAPU.PC - IAPU.RAM; S9xAPUPackStatus (); if (CPU.Flags & SCAN_KEYS_FLAG) { #ifdef DEBUGGER if (!(CPU.Flags & FRAME_ADVANCE_FLAG)) #endif S9xSyncSpeed (); CPU.Flags &= ~SCAN_KEYS_FLAG; } if (CPU.BRKTriggered && Settings.SuperFX && !CPU.TriedInterleavedMode2) { CPU.TriedInterleavedMode2 = TRUE; CPU.BRKTriggered = FALSE; S9xDeinterleaveMode2 (); } } void S9xSetIRQ (uint32 source) { CPU.IRQActive |= source; CPU.Flags |= IRQ_PENDING_FLAG; CPU.IRQCycleCount = 3; if (CPU.WaitingForInterrupt) { // Force IRQ to trigger immediately after WAI - // Final Fantasy Mystic Quest crashes without this. CPU.IRQCycleCount = 0; CPU.WaitingForInterrupt = FALSE; CPU.PC++; } }
void S9xDoHBlankProcessing () { #ifdef CPU_SHUTDOWN CPU.WaitCounter++; #endif switch (CPU.WhichEvent) { case HBLANK_START_EVENT: if (IPPU.HDMA && CPU.V_Counter <= PPU.ScreenHeight) IPPU.HDMA = S9xDoHDMA (IPPU.HDMA); break; case HBLANK_END_EVENT: S9xSuperFXExec (); #ifndef STORM if (Settings.SoundSync) S9xGenerateSound (); #endif CPU.Cycles -= Settings.H_Max; if (IAPU.APUExecuting) APU.Cycles -= Settings.H_Max; else APU.Cycles = 0; CPU.NextEvent = -1; ICPU.Scanline++; if (++CPU.V_Counter > (Settings.PAL ? SNES_MAX_PAL_VCOUNTER : SNES_MAX_NTSC_VCOUNTER)) { PPU.OAMAddr = PPU.SavedOAMAddr; PPU.OAMFlip = 0; CPU.V_Counter = 0; CPU.NMIActive = FALSE; ICPU.Frame++; PPU.HVBeamCounterLatched = 0; CPU.Flags |= SCAN_KEYS_FLAG; S9xStartHDMA (); } if (PPU.VTimerEnabled && !PPU.HTimerEnabled && CPU.V_Counter == PPU.IRQVBeamPos) { S9xSetIRQ (PPU_V_BEAM_IRQ_SOURCE); } if (CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE) { // Start of V-blank S9xEndScreenRefresh (); PPU.FirstSprite = 0; IPPU.HDMA = 0; // Bits 7 and 6 of $4212 are computed when read in S9xGetPPU. missing.dma_this_frame = 0; IPPU.MaxBrightness = PPU.Brightness; PPU.ForcedBlanking = (Memory.FillRAM [0x2100] >> 7) & 1; Memory.FillRAM[0x4210] = 0x80; if (Memory.FillRAM[0x4200] & 0x80) { CPU.NMIActive = TRUE; CPU.Flags |= NMI_FLAG; CPU.NMICycleCount = CPU.NMITriggerPoint; } #ifdef OLD_SNAPSHOT_CODE if (CPU.Flags & SAVE_SNAPSHOT_FLAG) { CPU.Flags &= ~SAVE_SNAPSHOT_FLAG; Registers.PC = CPU.PC - CPU.PCBase; S9xPackStatus (); S9xAPUPackStatus (); Snapshot (NULL); } #endif } if (CPU.V_Counter == PPU.ScreenHeight + 3) S9xUpdateJoypads (); if (CPU.V_Counter == FIRST_VISIBLE_LINE) { Memory.FillRAM[0x4210] = 0; CPU.Flags &= ~NMI_FLAG; S9xStartScreenRefresh (); } if (CPU.V_Counter >= FIRST_VISIBLE_LINE && CPU.V_Counter < PPU.ScreenHeight + FIRST_VISIBLE_LINE) { RenderLine (CPU.V_Counter - FIRST_VISIBLE_LINE); } // Use TimerErrorCounter to skip update of SPC700 timers once // every 128 updates. Needed because this section of code is called // once every emulated 63.5 microseconds, which coresponds to // 15.750KHz, but the SPC700 timers need to be updated at multiples // of 8KHz, hence the error correction. // IAPU.TimerErrorCounter++; // if (IAPU.TimerErrorCounter >= ) // IAPU.TimerErrorCounter = 0; // else { if (APU.TimerEnabled [2]) { APU.Timer [2] += 4; while (APU.Timer [2] >= APU.TimerTarget [2]) { IAPU.RAM [0xff] = (IAPU.RAM [0xff] + 1) & 0xf; APU.Timer [2] -= APU.TimerTarget [2]; #ifdef SPC700_SHUTDOWN IAPU.WaitCounter++; IAPU.APUExecuting = TRUE; #endif } } if (CPU.V_Counter & 1) { if (APU.TimerEnabled [0]) { APU.Timer [0]++; if (APU.Timer [0] >= APU.TimerTarget [0]) { IAPU.RAM [0xfd] = (IAPU.RAM [0xfd] + 1) & 0xf; APU.Timer [0] = 0; #ifdef SPC700_SHUTDOWN IAPU.WaitCounter++; IAPU.APUExecuting = TRUE; #endif } } if (APU.TimerEnabled [1]) { APU.Timer [1]++; if (APU.Timer [1] >= APU.TimerTarget [1]) { IAPU.RAM [0xfe] = (IAPU.RAM [0xfe] + 1) & 0xf; APU.Timer [1] = 0; #ifdef SPC700_SHUTDOWN IAPU.WaitCounter++; IAPU.APUExecuting = TRUE; #endif } } } } break; //HBLANK_END_EVENT case HTIMER_BEFORE_EVENT: case HTIMER_AFTER_EVENT: if (PPU.HTimerEnabled && (!PPU.VTimerEnabled || CPU.V_Counter == PPU.IRQVBeamPos)) { S9xSetIRQ (PPU_H_BEAM_IRQ_SOURCE); } break; }