Example #1
0
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;
    }
}
Example #2
0
void S9xDoHEventProcessing (void)
{
	uint8 tmp;

	switch (CPU.WhichEvent)
	{
		case HC_HBLANK_START_EVENT:
			if (PPU.HTimerPosition == Timings.HBlankStart)
				S9xCheckMissingHTimerPosition();
			S9xReschedule();
			break;

		case HC_HDMA_START_EVENT:
			if (PPU.HTimerPosition == Timings.HDMAStart)
				S9xCheckMissingHTimerPosition();
			S9xReschedule();

			if (PPU.HDMA && CPU.V_Counter <= PPU.ScreenHeight)
				PPU.HDMA = S9xDoHDMA(PPU.HDMA);

			break;

		case HC_HCOUNTER_MAX_EVENT:
			if (Settings.SuperFX && !SuperFX.oneLineDone && CHECK_EXEC_SUPERFX())
				S9xSuperFXExec();
			SuperFX.oneLineDone = FALSE; // do this even without SFX

			S9xAPUExecute();
			CPU.Cycles -= Timings.H_Max;
			S9xAPUSetReferenceTime(CPU.Cycles);

			if ((Timings.NMITriggerPos != 0xffff) && (Timings.NMITriggerPos >= Timings.H_Max))
				Timings.NMITriggerPos -= Timings.H_Max;

			CPU.V_Counter++;
			if (CPU.V_Counter >= Timings.V_Max)	/* V ranges from 0 to Timings.V_Max - 1 */
			{
				CPU.V_Counter = 0;
				Timings.InterlaceField ^= 1;

				/* From byuu:
				   [NTSC]
				   interlace mode has 525 scanlines: 263 on 
				   the even frame, and 262 on the odd.

				   non-interlace mode has 524 scanlines: 
				   262 scanlines on both even and odd frames.
				   
				   [PAL] <PAL info is unverified on hardware>
				   interlace mode has 625 scanlines: 313 on 
				   the even frame, and 312 on the odd.
				   
				   non-interlace mode has 624 scanlines: 
				   312 scanlines on both even and odd frames. */

				Timings.V_Max = Timings.V_Max_Master;	/* 262 (NTSC), 312?(PAL) */

				if (IPPU.Interlace && !Timings.InterlaceField)
					Timings.V_Max += 1;	/* 263 (NTSC), 313?(PAL) */

				Memory.FillRAM[0x213F] ^= 0x80;
				PPU.RangeTimeOver = 0;

				/* FIXME: reading $4210 will wait 2 cycles, 
				then perform reading, then wait 4 more cycles. */

				Memory.FillRAM[0x4210] = MAX_5A22_VERSION;
				CPU.Flags &= ~NMI_FLAG;
				Timings.NMITriggerPos = 0xffff;

				ICPU.Frame++;
				PPU.HVBeamCounterLatched = 0;
				CPU.Flags |= SCAN_KEYS_FLAG;
			}

			/* From byuu:
			   In non-interlace mode, there are 341 dots 
			   per scanline, and 262 scanlines per frame.
			   
			   On odd frames, scanline 240 is one dot short.
			   In interlace mode, there are always 341 dots 
			   per scanline. Even frames have 263 scanlines,
			   and odd frames have 262 scanlines.
			   
			   Interlace mode scanline 240 on odd frames is 
			   not missing a dot. */

			Timings.H_Max = Timings.H_Max_Master;					/* HC=1364 */

			if (CPU.V_Counter == 240 && !IPPU.Interlace && Timings.InterlaceField)	/* V=240 */
				Timings.H_Max -= ONE_DOT_CYCLE;					/* HC=1360 */

			if (CPU.V_Counter != 240 || IPPU.Interlace || !Timings.InterlaceField)	/* V=240 */
			{
				if (Timings.WRAMRefreshPos == SNES_WRAM_REFRESH_HC_v2_MIN_ONE_DOT_CYCLE) /* HC=534 */
					Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2; /* HC=538 */
				else
					Timings.WRAMRefreshPos = SNES_WRAM_REFRESH_HC_v2_MIN_ONE_DOT_CYCLE; /* HC=534 */
			}

			if (PPU.HTimerPosition == 0)
				S9xCheckMissingHTimerPosition();

			if (CPU.V_Counter == PPU.ScreenHeight + FIRST_VISIBLE_LINE) /* VBlank starts from V=225(240). */
			{
				S9xEndScreenRefresh();
				PPU.HDMA = 0;
				/* Bits 7 and 6 of $4212 are computed when read in S9xGetPPU. */
				PPU.ForcedBlanking = (Memory.FillRAM[0x2100] >> 7) & 1;

				if (!PPU.ForcedBlanking)
				{
					PPU.OAMAddr = PPU.SavedOAMAddr;

					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;
				}

				/* FIXME: writing to $4210 will wait 6 cycles. */
				Memory.FillRAM[0x4210] = 0x80 | MAX_5A22_VERSION;
				if (Memory.FillRAM[0x4200] & 0x80)
				{
					/* FIXME: triggered at HC=6, checked just 
					before the final CPU cycle, then, when to 
					call S9xOpcode_NMI()? */
					CPU.Flags |= NMI_FLAG;
					Timings.NMITriggerPos = 6 + 6;
				}

			}