/*
 * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
 *
 * (c) Copyright 1996 - 2001 Gary Henderson (gary.henderson@ntlworld.com) and
 *                           Jerremy Koot (jkoot@snes9x.com)
 *
 * Super FX C emulator code 
 * (c) Copyright 1997 - 1999 Ivar (ivar@snes9x.com) and
 *                           Gary Henderson.
 * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_.
 *
 * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson.
 * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_.
 * C4 C code (c) Copyright 2001 Gary Henderson (gary.henderson@ntlworld.com).
 *
 * DOS port code contains the works of other authors. See headers in
 * individual files.
 *
 * Snes9x homepage: http://www.snes9x.com
 *
 * Permission to use, copy, modify and distribute Snes9x in both binary and
 * source form, for non-commercial purposes, is hereby granted without fee,
 * providing that this license information and copyright notice appear with
 * all copies and any derived work.
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event shall the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Snes9x is freeware for PERSONAL USE only. Commercial users should
 * seek permission of the copyright holders first. Commercial use includes
 * charging money for Snes9x or software derived from Snes9x.
 *
 * The copyright holders request that bug fixes and improvements to the code
 * should be forwarded to them so everyone can benefit from the modifications
 * in future versions.
 *
 * Super NES and Super Nintendo Entertainment System are trademarks of
 * Nintendo Co., Limited and its subsidiary companies.
 */
#include "snes9x.h"
#include "memmap.h"
#include "ppu.h"
#include "cpuexec.h"
#include "missing.h"
#include "apu.h"
#include "dma.h"
#include "gfx.h"
#include "display.h"
#include "sa1.h"
#if not (defined(__os9x__)||defined(__PSP__))
#include "netplay.h"
#endif
#include "sdd1.h"
#include "srtc.h"

extern uint32 os9x_gammavalue;
extern char str_tmp[256];
extern unsigned char gammatab[10][32];

#ifndef ZSNES_FX
#include "fxemu.h"
#include "fxinst.h"
extern struct FxInit_s SuperFX;
#else
EXTERN_C void S9xSuperFXWriteReg (uint8, uint32);
EXTERN_C uint8 S9xSuperFXReadReg (uint32);
#endif



void S9xUpdateHTimer ()
{
    if (PPUPack.PPU.HTimerEnabled)
    {
#ifdef DEBUGGER
	missing.hirq_pos = PPUPack.PPU.IRQHBeamPos;
#endif
	PPUPack.PPU.HTimerPosition = PPUPack.PPU.IRQHBeamPos * Settings.H_Max / SNES_HCOUNTER_MAX;
	if (PPUPack.PPU.HTimerPosition == Settings.H_Max ||
	    PPUPack.PPU.HTimerPosition == Settings.HBlankStart)
	{
	    PPUPack.PPU.HTimerPosition--;
	}

	if (!PPUPack.PPU.VTimerEnabled || CPUPack.CPU.V_Counter == PPUPack.PPU.IRQVBeamPos)
	{
	    if (PPUPack.PPU.HTimerPosition < CPUPack.CPU.Cycles)
	    {
		// Missed the IRQ on this line already
		if (CPUPack.CPU.WhichEvent == HBLANK_END_EVENT ||
		    CPUPack.CPU.WhichEvent == HTIMER_AFTER_EVENT)
		{
		    CPUPack.CPU.WhichEvent = HBLANK_END_EVENT;
		    S9x_Current_HBlank_Event=S9xDoHBlankProcessing_HBLANK_END_EVENT;
		    CPUPack.CPU.NextEvent = Settings.H_Max;
		}
		else
		{
		    CPUPack.CPU.WhichEvent = HBLANK_START_EVENT;
		    S9x_Current_HBlank_Event=S9xDoHBlankProcessing_HBLANK_START_EVENT;
		    CPUPack.CPU.NextEvent = Settings.HBlankStart;
		}
	    }
	    else
	    {
		if (CPUPack.CPU.WhichEvent == HTIMER_BEFORE_EVENT ||
		    CPUPack.CPU.WhichEvent == HBLANK_START_EVENT)
		{
		    if (PPUPack.PPU.HTimerPosition > Settings.HBlankStart)
		    {
			// HTimer was to trigger before h-blank start,
			// now triggers after start of h-blank
			CPUPack.CPU.NextEvent = Settings.HBlankStart;
			CPUPack.CPU.WhichEvent = HBLANK_START_EVENT;
			S9x_Current_HBlank_Event=S9xDoHBlankProcessing_HBLANK_START_EVENT;
		    }
		    else
		    {
			CPUPack.CPU.NextEvent = PPUPack.PPU.HTimerPosition;
			CPUPack.CPU.WhichEvent = HTIMER_BEFORE_EVENT;
			S9x_Current_HBlank_Event=S9xDoHBlankProcessing_HTIMER_BEFORE_EVENT;
		    }
		}
		else
		{
		    CPUPack.CPU.WhichEvent = HTIMER_AFTER_EVENT;
		    S9x_Current_HBlank_Event=S9xDoHBlankProcessing_HTIMER_AFTER_EVENT;
		    CPUPack.CPU.NextEvent = PPUPack.PPU.HTimerPosition;
		}
	    }
	}
    }
}



void S9xFixColourBrightness ()
{
    PPUPack.IPPU.XB = mul_brightness [PPUPack.PPU.Brightness];
	for (int i = 0; i < 256; i++)
	{
	    PPUPack.IPPU.Red [i] = gammatab[os9x_gammavalue][PPUPack.IPPU.XB [PPUPack.PPU.CGDATA [i] & 0x1f]];
		PPUPack.IPPU.Green [i] = gammatab[os9x_gammavalue][PPUPack.IPPU.XB [(PPUPack.PPU.CGDATA [i] >> 5) & 0x1f]];
		PPUPack.IPPU.Blue [i] = gammatab[os9x_gammavalue][PPUPack.IPPU.XB [(PPUPack.PPU.CGDATA [i] >> 10) & 0x1f]];
		PPUPack.IPPU.ScreenColors [i]=BUILD_PIXEL(PPUPack.IPPU.Red [i],PPUPack.IPPU.Green [i],PPUPack.IPPU.Blue [i]);
	}
	//YOYO
	os9x_ColorsChanged=1;
}

/**********************************************************************************************/
/* S9xSetPPU()                                                                                   */
/* This function sets a PPU Register to a specific byte                                       */
/**********************************************************************************************/
void S9xSetPPU (uint8 Byte, uint16 Address)
{
    if (Address <= 0x2183)
    {
    switch (Address)
    {
    case 0x2100:
	// Brightness and screen blank bit
	if (Byte != FillRAM [0x2100])
	{
		INFO_FLUSH_REDRAW("2100");
	    FLUSH_REDRAW ();
	    if (PPUPack.PPU.Brightness != (Byte & 0xF))
	    {
		PPUPack.IPPU.ColorsChanged = TRUE;
		PPUPack.IPPU.DirectColourMapsNeedRebuild = TRUE;
		PPUPack.PPU.Brightness = Byte & 0xF;
		S9xFixColourBrightness ();
		if (PPUPack.PPU.Brightness > PPUPack.IPPU.MaxBrightness)
		    PPUPack.IPPU.MaxBrightness = PPUPack.PPU.Brightness;
	    }
	    if ((FillRAM[0x2100] & 0x80) != (Byte & 0x80))
	    {
		PPUPack.IPPU.ColorsChanged = TRUE;
		PPUPack.PPU.ForcedBlanking = (Byte >> 7) & 1;
	    }
	}
	break;

    case 0x2101:
	// Sprite (OBJ) tile address
	if (Byte != FillRAM [0x2101])
	{
		INFO_FLUSH_REDRAW("2101");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.OBJNameBase   = (Byte & 3) << 14;
	    PPUPack.PPU.OBJNameSelect = ((Byte >> 3) & 3) << 13;
	    PPUPack.PPU.OBJSizeSelect = (Byte >> 5) & 7;
	    PPUPack.IPPU.OBJChanged = TRUE;
	}
	break;

    case 0x2102:
	// Sprite write address (low)
	PPUPack.PPU.OAMAddr = Byte;
	PPUPack.PPU.OAMFlip = 2;
	PPUPack.PPU.OAMReadFlip = 0;
	PPUPack.PPU.SavedOAMAddr = PPUPack.PPU.OAMAddr;
	if (PPUPack.PPU.OAMPriorityRotation)
	{
	    PPUPack.PPU.FirstSprite = PPUPack.PPU.OAMAddr & 0x7f;
	}
	break;

    case 0x2103:
	// Sprite register write address (high), sprite priority rotation
	// bit.
	if ((PPUPack.PPU.OAMPriorityRotation = (Byte & 0x80) == 0 ? 0 : 1))
	{
	    PPUPack.PPU.FirstSprite = PPUPack.PPU.OAMAddr & 0x7f;
	}
	// Only update the sprite write address top bit if the low byte has
	// been written to first.
	if (PPUPack.PPU.OAMFlip & 2)
	{
	    PPUPack.PPU.OAMAddr &= 0x00FF;
	    PPUPack.PPU.OAMAddr |= (Byte & 1) << 8;
	}
	PPUPack.PPU.OAMFlip = 0;
	PPUPack.PPU.OAMReadFlip = 0;
	PPUPack.PPU.SavedOAMAddr = PPUPack.PPU.OAMAddr;
	break;

    case 0x2104:
	// Sprite register write
	REGISTER_2104(Byte);
	break;

    case 0x2105:
	// Screen mode (0 - 7), background tile sizes and background 3
	// priority
	if (Byte != FillRAM [0x2105])
	{
		INFO_FLUSH_REDRAW("2105");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.BG3Priority  = (Byte >> 3) & 1;
	    PPUPack.PPU.BG[0].BGSize = (Byte >> 4) & 1;
	    PPUPack.PPU.BG[1].BGSize = (Byte >> 5) & 1;
	    PPUPack.PPU.BG[2].BGSize = (Byte >> 6) & 1;
	    PPUPack.PPU.BG[3].BGSize = (Byte >> 7) & 1;
	    PPUPack.PPU.BGMode = Byte & 7;
	}
	break;

    case 0x2106:
	// Mosaic pixel size and enable
	if (Byte != FillRAM [0x2106])
	{
		INFO_FLUSH_REDRAW("2106");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.Mosaic = (Byte >> 4) + 1;
	    PPUPack.PPU.BGMosaic [0] = (Byte & 1) && PPUPack.PPU.Mosaic > 1;
	    PPUPack.PPU.BGMosaic [1] = (Byte & 2) && PPUPack.PPU.Mosaic > 1;
	    PPUPack.PPU.BGMosaic [2] = (Byte & 4) && PPUPack.PPU.Mosaic > 1;
	    PPUPack.PPU.BGMosaic [3] = (Byte & 8) && PPUPack.PPU.Mosaic > 1;
	}
	break;
    case 0x2107:		// [BG0SC]
	if (Byte != FillRAM [0x2107])
	{
		INFO_FLUSH_REDRAW("2107");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.BG[0].SCSize = Byte & 3;
	    PPUPack.PPU.BG[0].SCBase = (Byte & 0x7c) << 8;
	}
	break;

    case 0x2108:		// [BG1SC]
	if (Byte != FillRAM [0x2108])
	{
		INFO_FLUSH_REDRAW("2108");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.BG[1].SCSize = Byte & 3;
	    PPUPack.PPU.BG[1].SCBase = (Byte & 0x7c) << 8;
	}
	break;

    case 0x2109:		// [BG2SC]
	if (Byte != FillRAM [0x2109])
	{
		INFO_FLUSH_REDRAW("2109");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.BG[2].SCSize = Byte & 3;
	    PPUPack.PPU.BG[2].SCBase = (Byte & 0x7c) << 8;
	}
	break;

    case 0x210A:		// [BG3SC]
	if (Byte != FillRAM [0x210a])
	{
		INFO_FLUSH_REDRAW("210A");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.BG[3].SCSize = Byte & 3;
	    PPUPack.PPU.BG[3].SCBase = (Byte & 0x7c) << 8;
	}
	break;

    case 0x210B:		// [BG01NBA]
	if (Byte != FillRAM [0x210b])
	{
		INFO_FLUSH_REDRAW("210B");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.BG[0].NameBase    = (Byte & 7) << 12;
	    PPUPack.PPU.BG[1].NameBase    = ((Byte >> 4) & 7) << 12;
	}
	break;

    case 0x210C:		// [BG23NBA]
	if (Byte != FillRAM [0x210c])
	{
		INFO_FLUSH_REDRAW("210C");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.BG[2].NameBase    = (Byte & 7) << 12;
	    PPUPack.PPU.BG[3].NameBase    = ((Byte >> 4) & 7) << 12;
	}
	break;

    case 0x210D:
	PPUPack.PPU.BG[0].HOffset = PPUPack.PPU.BG[0].HOffset_Byte[HIGHBYTE] | ((uint16) Byte << 8);
	break;

    case 0x210E:
	PPUPack.PPU.BG[0].VOffset = PPUPack.PPU.BG[0].VOffset_Byte[HIGHBYTE] | ((uint16) Byte << 8);
	break;
    case 0x210F:
	PPUPack.PPU.BG[1].HOffset = PPUPack.PPU.BG[1].HOffset_Byte[HIGHBYTE] | ((uint16) Byte << 8);
	break;

    case 0x2110:
	PPUPack.PPU.BG[1].VOffset = PPUPack.PPU.BG[1].VOffset_Byte[HIGHBYTE] | ((uint16) Byte << 8);
	break;

    case 0x2111:
	PPUPack.PPU.BG[2].HOffset = PPUPack.PPU.BG[2].HOffset_Byte[HIGHBYTE] | ((uint16) Byte << 8);
	break;

    case 0x2112:
	PPUPack.PPU.BG[2].VOffset = PPUPack.PPU.BG[2].VOffset_Byte[HIGHBYTE] | ((uint16) Byte << 8);
	break;

    case 0x2113:
	PPUPack.PPU.BG[3].HOffset = PPUPack.PPU.BG[3].HOffset_Byte[HIGHBYTE] | ((uint16) Byte << 8);
	break;

    case 0x2114:
	PPUPack.PPU.BG[3].VOffset = PPUPack.PPU.BG[3].VOffset_Byte[HIGHBYTE] | ((uint16) Byte << 8);
	break;

    case 0x2115:
	// VRAM byte/word access flag and increment
	PPUPack.PPU.VMA.High = (Byte & 0x80) == 0 ? FALSE : TRUE;
	switch (Byte & 3)
	{
	case 0:
	    PPUPack.PPU.VMA.Increment = 1;
	    break;
	case 1:
	    PPUPack.PPU.VMA.Increment = 32;
	    break;
	case 2:
	    PPUPack.PPU.VMA.Increment = 128;
	    break;
	case 3:
	    PPUPack.PPU.VMA.Increment = 128;
	    break;
	}
#ifdef DEBUGGER
	if ((Byte & 3) != 0)
	    missing.vram_inc = Byte & 3;
#endif
	if (Byte & 0x0c)
	{
	    static uint8 IncCount [4] = { 0, 32, 64, 128 };
	    static uint8 Shift [4] = { 0, 5, 6, 7 };
#ifdef DEBUGGER
	    missing.vram_full_graphic_inc = (Byte & 0x0c) >> 2;
#endif
	    PPUPack.PPU.VMA.Increment = 1;
	    uint8 i = (Byte & 0x0c) >> 2;
	    PPUPack.PPU.VMA.FullGraphicCount = IncCount [i];
	    PPUPack.PPU.VMA.Mask1 = IncCount [i] * 8 - 1;
	    PPUPack.PPU.VMA.Shift = Shift [i];
	}
	else
	    PPUPack.PPU.VMA.FullGraphicCount = 0;
	break;

    case 0x2116:
	// VRAM read/write address (low)
	PPUPack.PPU.VMA.Address &= 0xFF00;
	PPUPack.PPU.VMA.Address |= Byte;
	PPUPack.IPPU.FirstVRAMRead = TRUE;
	break;

    case 0x2117:
	// VRAM read/write address (high)
	PPUPack.PPU.VMA.Address &= 0x00FF;
	PPUPack.PPU.VMA.Address |= Byte << 8;
	PPUPack.IPPU.FirstVRAMRead = TRUE;
	break;

    case 0x2118:
	// VRAM write data (low)
	PPUPack.IPPU.FirstVRAMRead = TRUE;
	REGISTER_2118(Byte);
	break;

    case 0x2119:
	// VRAM write data (high)
	PPUPack.IPPU.FirstVRAMRead = TRUE;
	REGISTER_2119(Byte);
	break;

    case 0x211a:
	// Mode 7 outside rotation area display mode and flipping
	if (Byte != FillRAM [0x211a])
	{
		INFO_FLUSH_REDRAW("211A");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.Mode7Repeat = Byte >> 6;
	    PPUPack.PPU.Mode7VFlip = (Byte & 2) >> 1;
	    PPUPack.PPU.Mode7HFlip = Byte & 1;
	}
	break;
    case 0x211b:
	// Mode 7 matrix A (low & high)
	PPUPack.PPU.MatrixA = PPUPack.PPU.MatrixA_Byte[HIGHBYTE] | (Byte << 8);
	PPUPack.PPU.Need16x8Mulitply = TRUE;
	break;
    case 0x211c:
	// Mode 7 matrix B (low & high)
	PPUPack.PPU.MatrixB = PPUPack.PPU.MatrixB_Byte[HIGHBYTE] | (Byte << 8);
	PPUPack.PPU.Need16x8Mulitply = TRUE;
	break;
    case 0x211d:
	// Mode 7 matrix C (low & high)
	PPUPack.PPU.MatrixC = PPUPack.PPU.MatrixC_Byte[HIGHBYTE] | (Byte << 8);
	break;
    case 0x211e:
	// Mode 7 matrix D (low & high)
	PPUPack.PPU.MatrixD = PPUPack.PPU.MatrixD_Byte[HIGHBYTE] | (Byte << 8);
	break;
    case 0x211f:
	// Mode 7 centre of rotation X (low & high)
	PPUPack.PPU.CentreX = PPUPack.PPU.CentreX_Byte[HIGHBYTE] | (Byte << 8);
	break;
    case 0x2120:
	// Mode 7 centre of rotation Y (low & high)
	PPUPack.PPU.CentreY = PPUPack.PPU.CentreY_Byte[HIGHBYTE] | (Byte << 8);
	break;

    case 0x2121:
	// CG-RAM address
	PPUPack.PPU.CGFLIP = 0;
	PPUPack.PPU.CGFLIPRead = 0;
	PPUPack.PPU.CGADD = Byte;
	break;

    case 0x2122:
	REGISTER_2122(Byte);
	break;

    case 0x2123:
	// Window 1 and 2 enable for backgrounds 1 and 2
	if (Byte != FillRAM [0x2123])
	{
		if (os9x_hack&PPU_IGNORE_WINDOW) return;
		INFO_FLUSH_REDRAW("2123");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.ClipWindow1Enable [0] = !!(Byte & 0x02);
	    PPUPack.PPU.ClipWindow1Enable [1] = !!(Byte & 0x20);
	    PPUPack.PPU.ClipWindow2Enable [0] = !!(Byte & 0x08);
	    PPUPack.PPU.ClipWindow2Enable [1] = !!(Byte & 0x80);
	    PPUPack.PPU.ClipWindow1Inside [0] = !(Byte & 0x01);
	    PPUPack.PPU.ClipWindow1Inside [1] = !(Byte & 0x10);
	    PPUPack.PPU.ClipWindow2Inside [0] = !(Byte & 0x04);
	    PPUPack.PPU.ClipWindow2Inside [1] = !(Byte & 0x40);
	    PPUPack.PPU.RecomputeClipWindows = TRUE;
	}
	break;
    case 0x2124:
	// Window 1 and 2 enable for backgrounds 3 and 4
	if (Byte != FillRAM [0x2124])
	{
		if (os9x_hack&PPU_IGNORE_WINDOW) return;
		INFO_FLUSH_REDRAW("2124");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.ClipWindow1Enable [2] = !!(Byte & 0x02);
	    PPUPack.PPU.ClipWindow1Enable [3] = !!(Byte & 0x20);
	    PPUPack.PPU.ClipWindow2Enable [2] = !!(Byte & 0x08);
	    PPUPack.PPU.ClipWindow2Enable [3] = !!(Byte & 0x80);
	    PPUPack.PPU.ClipWindow1Inside [2] = !(Byte & 0x01);
	    PPUPack.PPU.ClipWindow1Inside [3] = !(Byte & 0x10);
	    PPUPack.PPU.ClipWindow2Inside [2] = !(Byte & 0x04);
	    PPUPack.PPU.ClipWindow2Inside [3] = !(Byte & 0x40);
	    PPUPack.PPU.RecomputeClipWindows = TRUE;
	}
	break;
    case 0x2125:
	// Window 1 and 2 enable for objects and colour window
	if (Byte != FillRAM [0x2125])
	{
		if (os9x_hack&PPU_IGNORE_WINDOW) return;
		INFO_FLUSH_REDRAW("2125");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.ClipWindow1Enable [4] = !!(Byte & 0x02);
	    PPUPack.PPU.ClipWindow1Enable [5] = !!(Byte & 0x20);
	    PPUPack.PPU.ClipWindow2Enable [4] = !!(Byte & 0x08);
	    PPUPack.PPU.ClipWindow2Enable [5] = !!(Byte & 0x80);
	    PPUPack.PPU.ClipWindow1Inside [4] = !(Byte & 0x01);
	    PPUPack.PPU.ClipWindow1Inside [5] = !(Byte & 0x10);
	    PPUPack.PPU.ClipWindow2Inside [4] = !(Byte & 0x04);
	    PPUPack.PPU.ClipWindow2Inside [5] = !(Byte & 0x40);
	    PPUPack.PPU.RecomputeClipWindows = TRUE;
	}
	break;
    case 0x2126:
	// Window 1 left position
	if (Byte != FillRAM [0x2126])
	{
		if (os9x_hack&PPU_IGNORE_WINDOW) return;
		INFO_FLUSH_REDRAW("2126");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.Window1Left = Byte;
	    PPUPack.PPU.RecomputeClipWindows = TRUE;
	}
	break;
    case 0x2127:
	// Window 1 right position
	if (Byte != FillRAM [0x2127])
	{
		if (os9x_hack&PPU_IGNORE_WINDOW) return;
		INFO_FLUSH_REDRAW("2127");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.Window1Right = Byte;
	    PPUPack.PPU.RecomputeClipWindows = TRUE;
	}
	break;
    case 0x2128:
	// Window 2 left position
	if (Byte != FillRAM [0x2128])
	{
		if (os9x_hack&PPU_IGNORE_WINDOW) return;
		INFO_FLUSH_REDRAW("2128");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.Window2Left = Byte;
	    PPUPack.PPU.RecomputeClipWindows = TRUE;
	}
	break;
    case 0x2129:
	// Window 2 right position
	if (Byte != FillRAM [0x2129])
	{
		if (os9x_hack&PPU_IGNORE_WINDOW) return;
		INFO_FLUSH_REDRAW("2129");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.Window2Right = Byte;
	    PPUPack.PPU.RecomputeClipWindows = TRUE;
	}
	break;
    case 0x212a:
	// Windows 1 & 2 overlap logic for backgrounds 1 - 4
	if (Byte != FillRAM [0x212a])
	{
		if (os9x_hack&PPU_IGNORE_WINDOW) return;
		INFO_FLUSH_REDRAW("212A");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.ClipWindowOverlapLogic [0] = (Byte & 0x03);
	    PPUPack.PPU.ClipWindowOverlapLogic [1] = (Byte & 0x0c) >> 2;
	    PPUPack.PPU.ClipWindowOverlapLogic [2] = (Byte & 0x30) >> 4;
	    PPUPack.PPU.ClipWindowOverlapLogic [3] = (Byte & 0xc0) >> 6;
	    PPUPack.PPU.RecomputeClipWindows = TRUE;
	}
	break;
    case 0x212b:
	// Windows 1 & 2 overlap logic for objects and colour window
	if (Byte != FillRAM [0x212b])
	{
		if (os9x_hack&PPU_IGNORE_WINDOW) return;
		INFO_FLUSH_REDRAW("212B");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.ClipWindowOverlapLogic [4] = Byte & 0x03;
	    PPUPack.PPU.ClipWindowOverlapLogic [5] = (Byte & 0x0c) >> 2;
	    PPUPack.PPU.RecomputeClipWindows = TRUE;
	}
	break;
    case 0x212c:
	// Main screen designation (backgrounds 1 - 4 and objects)
	if (Byte != FillRAM [0x212c])
	{
		INFO_FLUSH_REDRAW("212C");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.RecomputeClipWindows = TRUE;
	    FillRAM [Address] = Byte;
	    return;
	}
	break;
    case 0x212d:
	// Sub-screen designation (backgrounds 1 - 4 and objects)
	if (Byte != FillRAM [0x212d])
	{
		INFO_FLUSH_REDRAW("212D");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.RecomputeClipWindows = TRUE;
	    FillRAM [Address] = Byte;
	    return;
	}
	break;
    case 0x212e:
	// Window mask designation for main screen ?
	if (Byte != FillRAM [0x212e])
	{
		INFO_FLUSH_REDRAW("212E");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.RecomputeClipWindows = TRUE;
	}
	break;
    case 0x212f:
	// Window mask designation for sub-screen ?
	if (Byte != FillRAM [0x212f])
	{
		INFO_FLUSH_REDRAW("212F");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.RecomputeClipWindows = TRUE;
	}
	break;
    case 0x2130:
	// Fixed colour addition or screen addition
	if (Byte != FillRAM [0x2130])
	{
		if (os9x_hack&PPU_IGNORE_ADDSUB) return;
		INFO_FLUSH_REDRAW("2130");
	    FLUSH_REDRAW ();
	    PPUPack.PPU.RecomputeClipWindows = TRUE;
	}
	break;
    case 0x2131:
	// Colour addition or subtraction select
	if (Byte != FillRAM[0x2131])
	{
		if (os9x_hack&PPU_IGNORE_ADDSUB) return;
		INFO_FLUSH_REDRAW("2131");
		
	    FLUSH_REDRAW ();
	    // Backgrounds 1 - 4, objects and backdrop colour add/sub enable
	    FillRAM[0x2131] = Byte;
	}
	break;
    case 0x2132:
	if (Byte != FillRAM [0x2132])
	{
		int redraw_needed=0;
		int new_fixedcol;
	    //FLUSH_REDRAW ();
	    // Colour data for fixed colour addition/subtraction
	    if (Byte & 0x80) {
	    	//PPUPack.PPU.FixedColourBlue = Byte & 0x1f;
	    	new_fixedcol=(Byte & 0x1f);
	    	if (new_fixedcol!=PPUPack.PPU.FixedColourBlue) {if (!(os9x_hack&PPU_IGNORE_FIXEDCOLCHANGES)) {INFO_FLUSH_REDRAW("2132");FLUSH_REDRAW();}PPUPack.PPU.FixedColourBlue=new_fixedcol;}
	    }
	    if (Byte & 0x40) {
	    	//PPUPack.PPU.FixedColourGreen = Byte & 0x1f;
	    	new_fixedcol=(Byte & 0x1f);
	    	if (new_fixedcol!=PPUPack.PPU.FixedColourGreen) {if (!(os9x_hack&PPU_IGNORE_FIXEDCOLCHANGES)) {INFO_FLUSH_REDRAW("2132");FLUSH_REDRAW();}PPUPack.PPU.FixedColourGreen=new_fixedcol;}
	    }
	    if (Byte & 0x20) {
	    	//PPUPack.PPU.FixedColourRed = Byte & 0x1f;
	    	new_fixedcol=(Byte & 0x1f);
	    	if (new_fixedcol!=PPUPack.PPU.FixedColourRed) {if (!(os9x_hack&PPU_IGNORE_FIXEDCOLCHANGES)) {INFO_FLUSH_REDRAW("2132");FLUSH_REDRAW();}PPUPack.PPU.FixedColourRed=new_fixedcol;}
	    }
	}
	break;
    case 0x2133:
	// Screen settings
	if (Byte != FillRAM [0x2133])
	{
	    if (Byte & 0x04)
	    {
		PPUPack.PPU.ScreenHeight = SNES_HEIGHT_EXTENDED;
	    }
	    else
	        PPUPack.PPU.ScreenHeight = (Settings.PAL?SNES_HEIGHT_PAL:SNES_HEIGHT_NTSC);
	}
	break;
    case 0x2134:
    case 0x2135:
    case 0x2136:
	// Matrix 16bit x 8bit multiply result (read-only)
	return;

    case 0x2137:
	// Software latch for horizontal and vertical timers (read-only)
	return;
    case 0x2138:
	// OAM read data (read-only)
	return;
    case 0x2139:
    case 0x213a:
	// VRAM read data (read-only)
	return;
    case 0x213b:
	// CG-RAM read data (read-only)
	return;
    case 0x213c:
    case 0x213d:
	// Horizontal and vertical (low/high) read counter (read-only)
	return;
    case 0x213e:
	// PPU status (time over and range over)
	return;
    case 0x213f:
	// NTSC/PAL select and field (read-only)
	return;
    case 0x2140: case 0x2141: case 0x2142: case 0x2143:
    case 0x2144: case 0x2145: case 0x2146: case 0x2147:
    case 0x2148: case 0x2149: case 0x214a: case 0x214b:
    case 0x214c: case 0x214d: case 0x214e: case 0x214f:
    case 0x2150: case 0x2151: case 0x2152: case 0x2153:
    case 0x2154: case 0x2155: case 0x2156: case 0x2157:
    case 0x2158: case 0x2159: case 0x215a: case 0x215b:
    case 0x215c: case 0x215d: case 0x215e: case 0x215f:
    case 0x2160: case 0x2161: case 0x2162: case 0x2163:
    case 0x2164: case 0x2165: case 0x2166: case 0x2167:
    case 0x2168: case 0x2169: case 0x216a: case 0x216b:
    case 0x216c: case 0x216d: case 0x216e: case 0x216f:
    case 0x2170: case 0x2171: case 0x2172: case 0x2173:
    case 0x2174: case 0x2175: case 0x2176: case 0x2177:
    case 0x2178: case 0x2179: case 0x217a: case 0x217b:
    case 0x217c: case 0x217d: case 0x217e: case 0x217f:
    	
    if (os9x_hack&APU_FIX) {
    	switch (Address&3) {
    		case 0: //0x2140
    			APUI00a=Byte;
    			break;
    		case 1: //0x2141
    			APUI01a=Byte;
    			APUI01b=0;
    			break;
    		case 2: //0x2142
    			APUI02a=Byte;
    			APUI02b=0;
    			break;
    		case 3: //0x2143
    			APUI03a=Byte;
    			APUI03b=0;
    			break;
    	}
    }
    	
//	CPUPack.CPU.Flags |= DEBUG_MODE_FLAG;
	FillRAM [Address] = Byte;
	
	APU_EXECUTE2 ();
	//(IAPUuncached->RAM) [(Address & 3) + 0xf4] = Byte;
	SAPUEVENTS *pEvent = (SAPUEVENTS *)UNCACHE_PTR(&stAPUEvents);\
	int apuwriteptr = pEvent->apu_ram_write_cpt2;
	pEvent->apu_ram_write_log[apuwriteptr & 0xFFFF]=(Address << 8)|Byte;
	pEvent->apu_ram_write_cpt2= apuwriteptr + 1;
	break;
    case 0x2180:
	REGISTER_2180(Byte);
	break;
    case 0x2181:
	PPUPack.PPU.WRAM &= 0x1FF00;
	PPUPack.PPU.WRAM |= Byte;
	break;
    case 0x2182:
	PPUPack.PPU.WRAM &= 0x100FF;
	PPUPack.PPU.WRAM |= Byte << 8;
	break;
    case 0x2183:
	PPUPack.PPU.WRAM &= 0x0FFFF;
	PPUPack.PPU.WRAM |= Byte << 16;
	PPUPack.PPU.WRAM &= 0x1FFFF;
	break;
    }
    }
    else
    {
	if (Settings.SA1)
	{
	    if (Address >= 0x2200 && Address <0x23ff)
		S9xSetSA1 (Byte, Address);
	    else
		FillRAM [Address] = Byte;
	    return;
	}
	else
	// Dai Kaijyu Monogatari II
	if (Address == 0x2801 && Settings.SRTC)
	    S9xSetSRTC (Byte, Address);
	else
	if (Address >= 0x3000 && Address < 0x3000 + 768)
	{
	    if (!Settings.SuperFX)
		return;
	    
#ifdef ZSNES_FX
	    FillRAM [Address] = Byte;
	    if (Address < 0x3040)
		S9xSuperFXWriteReg (Byte, Address);
#else
	    switch (Address)
	    {
	    case 0x3030:
		if ((FillRAM [0x3030] ^ Byte) & FLG_G)
		{
		    FillRAM [Address] = Byte;
		    // Go flag has been changed
		    if (Byte & FLG_G)
			S9xSuperFXExec ();
		    else
			FxFlushCache ();
		}
		else
		    FillRAM [Address] = Byte;
		break;

	    case 0x3031:
		FillRAM [Address] = Byte;
		break;
	    case 0x3033:
		FillRAM [Address] = Byte;
		break;
	    case 0x3034:
		FillRAM [Address] = Byte & 0x7f;
		break;
	    case 0x3036:
		FillRAM [Address] = Byte & 0x7f;
		break;
	    case 0x3037:
		FillRAM [Address] = Byte;
		break;
	    case 0x3038:
		FillRAM [Address] = Byte;
		break;
	    case 0x3039:
		FillRAM [Address] = Byte;
		break;
	    case 0x303a:
		FillRAM [Address] = Byte;
		break;
	    case 0x303b:
		break;
	    case 0x303f:
		FillRAM [Address] = Byte;
		break;
	    case 0x301f:
		FillRAM [Address] = Byte;
		FillRAM [0x3000 + GSU_SFR] |= FLG_G;
		S9xSuperFXExec ();
		return;

	    default:
		FillRAM[Address] = Byte;
		if (Address >= 0x3100)
		{
		    FxCacheWriteAccess (Address);
		}
		break;
	    }
#endif
	    return;
	}
    }
    FillRAM[Address] = Byte;
}

/**********************************************************************************************/
/* S9xGetPPU()                                                                                   */
/* This function retrieves a PPU Register                                                     */
/**********************************************************************************************/
uint8 S9xGetPPU (uint16 Address)
{
    uint8 byte = 0;

    if (Address <= 0x2190)
    {
	switch (Address)
	{
	case 0x2100:
	case 0x2101:
	
	    return (FillRAM[Address]);
	case 0x2102:
	    return (uint8)(PPUPack.PPU.OAMAddr);
	case 0x2103:
	    return (((PPUPack.PPU.OAMAddr >> 8) & 1) | (PPUPack.PPU.OAMPriorityRotation << 7));
	case 0x2104:
	case 0x2105:
	case 0x2106:
	case 0x2107:
	case 0x2108:
	case 0x2109:
	case 0x210a:
	case 0x210b:
	case 0x210c:
	    return (FillRAM[Address]);	    
	case 0x210d:
	case 0x210e:
	case 0x210f:
	case 0x2110:
	case 0x2111:
	case 0x2112:
	case 0x2113:
	case 0x2114:
	    return (FillRAM[Address]);
	case 0x2115:
	    return (FillRAM[Address]);
	case 0x2116:
	    return (uint8)(PPUPack.PPU.VMA.Address);
	case 0x2117:
	    return (PPUPack.PPU.VMA.Address >> 8);
	case 0x2118:
	case 0x2119:
	case 0x211a:
	    return (FillRAM[Address]);
	case 0x211b:
	case 0x211c:
	case 0x211d:
	case 0x211e:
	case 0x211f:
	case 0x2120:
	    return (FillRAM[Address]);
	case 0x2121:
	    return (PPUPack.PPU.CGADD);
	case 0x2122:
	case 0x2123:
	case 0x2124:
	case 0x2125:
	case 0x2126:
	case 0x2127:
	case 0x2128:
	case 0x2129:
	case 0x212a:
	case 0x212b:
	case 0x212c:
	case 0x212d:
	case 0x212e:
	case 0x212f:
	case 0x2130:
	case 0x2131:
	case 0x2132:
	case 0x2133:
	    return (FillRAM[Address]);

	case 0x2134:
	case 0x2135:
	case 0x2136:
	    // 16bit x 8bit multiply read result.
	    if (PPUPack.PPU.Need16x8Mulitply)
	    {
		int32 r = (int32) PPUPack.PPU.MatrixA * (int32) (PPUPack.PPU.MatrixB >> 8);

		FillRAM[0x2134] = (uint8) r;
		FillRAM[0x2135] = (uint8)(r >> 8);
		FillRAM[0x2136] = (uint8)(r >> 16);
		PPUPack.PPU.Need16x8Mulitply = FALSE;
	    }
	    return (FillRAM[Address]);
	case 0x2137:
	    // Latch h and v counters
	    PPUPack.PPU.HVBeamCounterLatched = 1;
	    PPUPack.PPU.VBeamPosLatched = (uint16) CPUPack.CPU.V_Counter;
	    PPUPack.PPU.HBeamPosLatched = (uint16) ((CPUPack.CPU.Cycles * SNES_HCOUNTER_MAX) / Settings.H_Max);
	    
	    // Causes screen flicker for Yoshi's Island if uncommented
	    //CLEAR_IRQ_SOURCE (PPU_V_BEAM_IRQ_SOURCE | PPU_H_BEAM_IRQ_SOURCE);

	    if (SNESGameFixes.NeedInit0x2137)
		PPUPack.PPU.VBeamFlip = 0;   //jyam sword world sfc2 & godzill		
	    return (0);
	case 0x2138:
	    // Read OAM (sprite) control data
	    if (!PPUPack.PPU.OAMReadFlip)
	    {
		byte = PPUPack.PPU.OAMData [PPUPack.PPU.OAMAddr << 1];
	    }
	    else
	    {
		byte = PPUPack.PPU.OAMData [(PPUPack.PPU.OAMAddr << 1) + 1];
		if (++PPUPack.PPU.OAMAddr >= 0x110)
		    PPUPack.PPU.OAMAddr = 0;
		
	    }
	    PPUPack.PPU.OAMReadFlip ^= 1;
	    return (byte);

	case 0x2139:
	    // Read vram low byte
	    if (PPUPack.IPPU.FirstVRAMRead)
		byte = VRAM[PPUPack.PPU.VMA.Address << 1];
	    else
	    if (PPUPack.PPU.VMA.FullGraphicCount)
	    {
		uint32 addr = PPUPack.PPU.VMA.Address - 1;
		uint32 rem = addr & PPUPack.PPU.VMA.Mask1;
		uint32 address = (addr & ~PPUPack.PPU.VMA.Mask1) +
				 (rem >> PPUPack.PPU.VMA.Shift) +
				 ((rem & (PPUPack.PPU.VMA.FullGraphicCount - 1)) << 3);
		byte = VRAM [((address << 1) - 2) & 0xFFFF];
	    }
	    else
		byte = VRAM[((PPUPack.PPU.VMA.Address << 1) - 2) & 0xffff];

	    if (!PPUPack.PPU.VMA.High)
	    {
		PPUPack.PPU.VMA.Address += PPUPack.PPU.VMA.Increment;
		PPUPack.IPPU.FirstVRAMRead = FALSE;
	    }
	    break;
	case 0x213A:
	    // Read vram high byte
	    if (PPUPack.IPPU.FirstVRAMRead)
		byte = VRAM[((PPUPack.PPU.VMA.Address << 1) + 1) & 0xffff];
	    else
	    if (PPUPack.PPU.VMA.FullGraphicCount)
	    {
		uint32 addr = PPUPack.PPU.VMA.Address - 1;
		uint32 rem = addr & PPUPack.PPU.VMA.Mask1;
		uint32 address = (addr & ~PPUPack.PPU.VMA.Mask1) +
				 (rem >> PPUPack.PPU.VMA.Shift) +
				 ((rem & (PPUPack.PPU.VMA.FullGraphicCount - 1)) << 3);
		byte = VRAM [((address << 1) - 1) & 0xFFFF];
	    }
	    else
		byte = VRAM[((PPUPack.PPU.VMA.Address << 1) - 1) & 0xFFFF];
	    if (PPUPack.PPU.VMA.High)
	    {
		PPUPack.PPU.VMA.Address += PPUPack.PPU.VMA.Increment;
		PPUPack.IPPU.FirstVRAMRead = FALSE;
	    }
	    break;

	case 0x213B:
	    // Read palette data
	    if (PPUPack.PPU.CGFLIPRead)
		byte = PPUPack.PPU.CGDATA [PPUPack.PPU.CGADD++] >> 8;
	    else
		byte = PPUPack.PPU.CGDATA [PPUPack.PPU.CGADD] & 0xff;

	    PPUPack.PPU.CGFLIPRead ^= 1;
	    
	    return (byte);
	    
	case 0x213C:
	    // Horizontal counter value 0-339
	    if (PPUPack.PPU.HBeamFlip)
		byte = PPUPack.PPU.HBeamPosLatched >> 8;
	    else
		byte = (uint8)PPUPack.PPU.HBeamPosLatched;
	    PPUPack.PPU.HBeamFlip ^= 1;
	    break;
	case 0x213D:
	    // Vertical counter value 0-262
	    if (PPUPack.PPU.VBeamFlip)
		byte = PPUPack.PPU.VBeamPosLatched >> 8;
	    else
		byte = (uint8)PPUPack.PPU.VBeamPosLatched;
	    PPUPack.PPU.VBeamFlip ^= 1;
	    break;
	case 0x213E:
	    // PPU time and range over flags
	    return (SNESGameFixes._0x213E_ReturnValue);

	case 0x213F:
	    // NTSC/PAL and which field flags
	    PPUPack.PPU.VBeamFlip = PPUPack.PPU.HBeamFlip = 0;
	    
	    return ((Settings.PAL ? 0x10 : 0) | (FillRAM[0x213f] & 0xc0));

	case 0x2140: case 0x2141: case 0x2142: case 0x2143:
	case 0x2144: case 0x2145: case 0x2146: case 0x2147:
	case 0x2148: case 0x2149: case 0x214a: case 0x214b:
	case 0x214c: case 0x214d: case 0x214e: case 0x214f:
	case 0x2150: case 0x2151: case 0x2152: case 0x2153:
	case 0x2154: case 0x2155: case 0x2156: case 0x2157:
	case 0x2158: case 0x2159: case 0x215a: case 0x215b:
	case 0x215c: case 0x215d: case 0x215e: case 0x215f:
	case 0x2160: case 0x2161: case 0x2162: case 0x2163:
	case 0x2164: case 0x2165: case 0x2166: case 0x2167:
	case 0x2168: case 0x2169: case 0x216a: case 0x216b:
	case 0x216c: case 0x216d: case 0x216e: case 0x216f:
	case 0x2170: case 0x2171: case 0x2172: case 0x2173:
	case 0x2174: case 0x2175: case 0x2176: case 0x2177:
	case 0x2178: case 0x2179: case 0x217a: case 0x217b:
	case 0x217c: case 0x217d: case 0x217e: case 0x217f:
	    if (Settings.APUEnabled)
	    {
		APU_EXECUTE2 ();
		
		SAPUEVENTS *pEvent = (SAPUEVENTS *)UNCACHE_PTR(&stAPUEvents);\
		return (pEvent->APU_OutPorts[Address & 3]);
	    }
	    
	    if (os9x_hack&APU_FIX) {
			switch (Address&3) {
				case 0:			//0x2140
					switch (APUI00b) {
						case 0:					
							APUI00b++;APUI01b=0;
							return CPUPack.Registers.AL;
						case 1:				
							APUI00b++;APUI01b=1;
							return CPUPack.Registers.XL;
						case 2:
							APUI00b++;APUI01b=2;
							return CPUPack.Registers.YL;
						case 3:
							APUI00b++;
							return 0x00;
						case 4:
							APUI00b++;
							return 0xFF;
						case 5:
							APUI00b++;
							return 0x55;
						case 6:
							APUI00b++;APUI01b=6;
							return 0x01;
						case 7:
							APUI00b++;
							return 0xAA;
						case 8:
							APUI00b++;
							return APUI00a;
						case 9:{
							uint8 retval=APUI00c;
							APUI00c++;
							APUI01b=0x0B;
							if (!APUI00c) {
								APUI00b=0;
								APUI01c++;
								APUI01b=0;
							}
							return retval;
						}
					}
				case 1:			//0x2141			
					switch (APUI01b) {
						case 0:					
							APUI01b++;
							return CPUPack.Registers.AH;
						case 1:				
							APUI01b++;
							return CPUPack.Registers.XH;
						case 2:
							APUI01b++;
							return CPUPack.Registers.YH;						
						case 3:
							APUI01b++;
							return CPUPack.Registers.AL;
						case 4:
							APUI01b++;
							return CPUPack.Registers.XL;
						case 5:
							APUI01b++;
							return CPUPack.Registers.YL;
						case 6:							
							APUI01b++;
							return 0xBB;
						case 7:
							APUI01b++;
							return 0x00;
						case 8:
							APUI01b++;
							return 0xFF;						
						case 9:
							APUI01b++;
							return 0x55;
						case 10:
							APUI01b=0;
							return APUI01a;
						case 11:
							return APUI01c;
					}
				case 2:			//0x2142
					switch (APUI02b) {
						case 0:					
							APUI02b++;APUI03b=0;
							return CPUPack.Registers.AL;
						case 1:				
							APUI02b++;APUI03b=1;
							return CPUPack.Registers.XL;
						case 2:
							APUI02b++;APUI03b=2;
							return CPUPack.Registers.YL;
						case 3:
							APUI02b++;
							return 0x00;
						case 4:
							APUI02b++;
							return 0xFF;
						case 5:
							APUI02b++;
							return 0x55;
						case 6:
							APUI02b++;APUI03b=6;
							return 0xAA;						
						case 7:
							APUI02b=0;
							return APUI02a;						
					}
				case 3:			 //0x2143
					switch (APUI03b) {
						case 0:					
							APUI03b++;
							return CPUPack.Registers.AH;
						case 1:				
							APUI03b++;
							return CPUPack.Registers.XH;
						case 2:
							APUI03b++;
							return CPUPack.Registers.YH;						
						case 3:
							APUI03b++;
							return CPUPack.Registers.AL;
						case 4:
							APUI03b++;
							return CPUPack.Registers.XL;
						case 5:
							APUI03b++;
							return CPUPack.Registers.YL;
						case 6:							
							APUI03b++;
							return 0xBB;
						case 7:
							APUI03b++;
							return 0x00;
						case 8:
							APUI03b++;
							return 0xFF;						
						case 9:
							APUI03b++;
							return 0x55;
						case 10:
							APUI03b=0;
							return APUI01a;						
					}
			}
		}
		CPUPack.CPU.BranchSkip = TRUE;
	    if (Address & 3 < 2)
	    {
		int r = yo_rand ();
		if (r & 2)
		{		
		    if (r & 4){
	    
			return (Address & 3 == 1 ? 0xaa : 0xbb);}
		    else{
		    
			return ((r >> 3) & 0xff);}
		}
	    }
	    else
	    {
		int r = yo_rand ();
		if (r & 2){
			
		    return ((r >> 3) & 0xff);}
	    }
	    return (FillRAM[Address]);

	case 0x2180:
	    // Read WRAM
	    byte = RAM [PPUPack.PPU.WRAM++];
	    PPUPack.PPU.WRAM &= 0x1FFFF;
	    break;
	case 0x2181:
	case 0x2182:
	case 0x2183:
	    return (FillRAM [Address]);
	case 0x2190:
	    return (1);
	}
    }
    else
    {
	if (Settings.SA1){
	    return (S9xGetSA1 (Address));}

	if (Address <= 0x2fff || Address >= 0x3000 + 768)
	{
	    switch (Address)
	    {
	    case 0x21c2:
	    
	        return (0x20);
	    case 0x21c3:
	    
	        return (0);
	    case 0x2800:
		// For Dai Kaijyu Monogatari II
		if (Settings.SRTC){
		
		    return (S9xGetSRTC (Address));}
		/*FALL*/
			    
	    default:
		// XXX:
		
	        return (0); //FillRAM[Address]);
	    }
	}
	
	if (!Settings.SuperFX){
	
	    return (0x30);}
#ifdef ZSNES_FX
	if (Address < 0x3040)
	    byte = S9xSuperFXReadReg (Address);
	else
	    byte = FillRAM [Address];

#ifdef CPU_SHUTDOWN
	if (Address == 0x3030)
	    CPUPack.CPU.WaitAddress = CPUPack.CPU.PCAtOpcodeStart;
#endif	
	if (Address == 0x3031)
	    CLEAR_IRQ_SOURCE (GSU_IRQ_SOURCE);
#else
	byte = FillRAM [Address];

//if (Address != 0x3030 && Address != 0x3031)
//printf ("%04x\n", Address);
#ifdef CPU_SHUTDOWN
	if (Address == 0x3030)
	{
	    CPUPack.CPU.WaitAddress = CPUPack.CPU.PCAtOpcodeStart;
	}
	else
#endif
	if (Address == 0x3031)
	{
	    CLEAR_IRQ_SOURCE (GSU_IRQ_SOURCE);
	    FillRAM [0x3031] = byte & 0x7f;
	}
	return (byte);
#endif
    }

    return (byte);
}

/**********************************************************************************************/
/* S9xSetCPU()                                                                                   */
/* This function sets a CPUPack.CPU/DMA Register to a specific byte                                   */
/**********************************************************************************************/
void S9xSetCPU (uint8 byte, uint16 Address)
{
    int d;
    
    if (Address < 0x4200)
    {
#ifdef VAR_CYCLES
	CPUPack.CPU.Cycles += ONE_CYCLE;
#endif
	switch (Address)
	{
	case 0x4016:
	    // S9xReset reading of old-style joypads
	    if ((byte & 1) && !(FillRAM [Address] & 1))
	    {
		PPUPack.PPU.Joypad1ButtonReadPos = 0;
		PPUPack.PPU.Joypad2ButtonReadPos = 0;
		PPUPack.PPU.Joypad3ButtonReadPos = 0;
	    }
	    break;
	case 0x4017:
	    break;
	default:
	    break;
	}
    }
    else
    switch (Address)
    {
    case 0x4200:
	// NMI, V & H IRQ and joypad reading enable flags
	if ((byte & 0x20) && 
	    (!SNESGameFixes.umiharakawaseFix || PPUPack.PPU.IRQVBeamPos < 209))
	{
	    if (!PPUPack.PPU.VTimerEnabled)
	    {
		PPUPack.PPU.VTimerEnabled = TRUE;
		if (PPUPack.PPU.HTimerEnabled)
		    S9xUpdateHTimer ();
		else
		if (PPUPack.PPU.IRQVBeamPos == CPUPack.CPU.V_Counter)
		    S9xSetIRQ (PPU_V_BEAM_IRQ_SOURCE);
	    }
	}
	else
	{
	    PPUPack.PPU.VTimerEnabled = FALSE;
	    if (SNESGameFixes.umiharakawaseFix)
		byte &= ~0x20;
	}

	if (byte & 0x10)
	{
	    if (!PPUPack.PPU.HTimerEnabled)
	    {
		PPUPack.PPU.HTimerEnabled = TRUE;
		S9xUpdateHTimer ();
	    }
	}
	else
	{
	    // No need to check for HTimer being disabled as the scanline
	    // event trigger code won't trigger an H-IRQ unless its enabled.
	    PPUPack.PPU.HTimerEnabled = FALSE;
	    PPUPack.PPU.HTimerPosition = Settings.H_Max + 1;
	}
	if (!Settings.DaffyDuck)
	    CLEAR_IRQ_SOURCE (PPU_V_BEAM_IRQ_SOURCE | PPU_H_BEAM_IRQ_SOURCE);

	if ((byte & 0x80) && 
	    !(FillRAM [0x4200] & 0x80) &&
	    CPUPack.CPU.V_Counter >= PPUPack.PPU.ScreenHeight + FIRST_VISIBLE_LINE &&
	    CPUPack.CPU.V_Counter <= PPUPack.PPU.ScreenHeight + 
		    (SNESGameFixes.alienVSpredetorFix ? 25 : 15) &&   //jyam 15->25 alien vs predetor
// Panic Bomberman clears the NMI pending flag @ scanline 230 before enabling
// NMIs again. The NMI routine crashes the CPUPack.CPU if it is called without the NMI
// pending flag being set...
	    (FillRAM [0x4210] & 0x80) &&
	    !CPUPack.CPU.NMIActive)
	{
	    CPUPack.CPU.Flags |= NMI_FLAG;
	    CPUPack.CPU.NMIActive = TRUE;
	    CPUPack.CPU.NMICycleCount = CPUPack.CPU.NMITriggerPoint;
	}
	break;
    case 0x4201:
	// I/O port output 
    case 0x4202:
	// Multiplier (for multply)
	break;
    case 0x4203:
	{
	    // Multiplicand
	    uint32 res = FillRAM[0x4202] * byte;

		*((uint16*)(FillRAM +0x4216)) = (uint16) res;
//	    FillRAM[0x4216] = (uint8) res;
//	    FillRAM[0x4217] = (uint8) (res >> 8);
	    break;
	}
    case 0x4204:
    case 0x4205:
	// Low and high muliplier (for divide)
	break;
    case 0x4206:
	{
	    // Divisor
	    uint16 a = FillRAM[0x4204] + (FillRAM[0x4205] << 8);
	    uint16 div = byte ? a / byte : 0xffff;
	    uint16 rem = byte ? a % byte : a;

		*((uint16*)(FillRAM +0x4214)) = (uint16) div;
		*((uint16*)(FillRAM +0x4216)) = (uint16) rem;
//	    FillRAM[0x4214] = (uint8)div;
//	    FillRAM[0x4215] = div >> 8;
//	    FillRAM[0x4216] = (uint8)rem;
//	    FillRAM[0x4217] = rem >> 8;
	    break;
	}
    case 0x4207:
	d = PPUPack.PPU.IRQHBeamPos;
	PPUPack.PPU.IRQHBeamPos = (PPUPack.PPU.IRQHBeamPos & 0xFF00) | byte;

	if (PPUPack.PPU.HTimerEnabled && PPUPack.PPU.IRQHBeamPos != d)
	    S9xUpdateHTimer ();
	break;

    case 0x4208:
	d = PPUPack.PPU.IRQHBeamPos;
	PPUPack.PPU.IRQHBeamPos = (PPUPack.PPU.IRQHBeamPos & 0xFF) | ((byte & 1) << 8);

	if (PPUPack.PPU.HTimerEnabled && PPUPack.PPU.IRQHBeamPos != d)
	    S9xUpdateHTimer ();

	break;

    case 0x4209:
	d = PPUPack.PPU.IRQVBeamPos;
	PPUPack.PPU.IRQVBeamPos = (PPUPack.PPU.IRQVBeamPos & 0xFF00) | byte;
	if (PPUPack.PPU.VTimerEnabled && PPUPack.PPU.IRQVBeamPos != d)
	{
	    if (PPUPack.PPU.HTimerEnabled)
		S9xUpdateHTimer ();
	    else
	    {
		if (PPUPack.PPU.IRQVBeamPos == CPUPack.CPU.V_Counter)
		    S9xSetIRQ (PPU_V_BEAM_IRQ_SOURCE);
	    }
	}
	break;

    case 0x420A:
	d = PPUPack.PPU.IRQVBeamPos;
	PPUPack.PPU.IRQVBeamPos = (PPUPack.PPU.IRQVBeamPos & 0xFF) | ((byte & 1) << 8);
	if (PPUPack.PPU.VTimerEnabled && PPUPack.PPU.IRQVBeamPos != d)
	{
	    if (PPUPack.PPU.HTimerEnabled)
		S9xUpdateHTimer ();
	    else
	    {
		if (PPUPack.PPU.IRQVBeamPos == CPUPack.CPU.V_Counter)
		    S9xSetIRQ (PPU_V_BEAM_IRQ_SOURCE);
	    }
	}
	break;

    case 0x420B:
	if ((byte & 0x01) != 0)
	    S9xDoDMA (0);
	if ((byte & 0x02) != 0)
	    S9xDoDMA (1);
	if ((byte & 0x04) != 0)
	    S9xDoDMA (2);
	if ((byte & 0x08) != 0)
	    S9xDoDMA (3);
	if ((byte & 0x10) != 0)
	    S9xDoDMA (4);
	if ((byte & 0x20) != 0)
	    S9xDoDMA (5);
	if ((byte & 0x40) != 0)
	    S9xDoDMA (6);
	if ((byte & 0x80) != 0)
	    S9xDoDMA (7);
	break;
    case 0x420C:
	if (Settings.DisableHDMA)
	    byte = 0;
	FillRAM[0x420c] = byte;
	PPUPack.IPPU.HDMA = byte;
	break;

    case 0x420d:
	// Cycle speed 0 - 2.68Mhz, 1 - 3.58Mhz (banks 0x80 +)
	if ((byte & 1) != (FillRAM [0x420d] & 1))
	{
	    if (byte & 1)
	    {
		CPUPack.CPU.FastROMSpeed = ONE_CYCLE;
	    }
	    else
		CPUPack.CPU.FastROMSpeed = SLOW_ONE_CYCLE;

	    Memory.FixROMSpeed ();
	}
	/* FALL */
    case 0x420e:
    case 0x420f:
	// --->>> Unknown
	break;
    case 0x4210:
	// NMI ocurred flag (reset on read or write)
	FillRAM[0x4210] = 0;
	return;
    case 0x4211:
	// IRQ ocurred flag (reset on read or write)
	CLEAR_IRQ_SOURCE (PPU_V_BEAM_IRQ_SOURCE | PPU_H_BEAM_IRQ_SOURCE);
	break;
    case 0x4212:
	// v-blank, h-blank and joypad being scanned flags (read-only)
    case 0x4213:
	// I/O Port (read-only)
    case 0x4214:
    case 0x4215:
	// Quotent of divide (read-only)
    case 0x4216:
    case 0x4217:
	// Multiply product (read-only)
	return;
    case 0x4218:
    case 0x4219:
    case 0x421a:
    case 0x421b:
    case 0x421c:
    case 0x421d:
    case 0x421e:
    case 0x421f:
	// Joypad values (read-only)
	return;

    case 0x4300:
    case 0x4310:
    case 0x4320:
    case 0x4330:
    case 0x4340:
    case 0x4350:
    case 0x4360:
    case 0x4370:
	d = (Address >> 4) & 0x7;
	DMA[d].TransferDirection = (byte & 128) != 0 ? 1 : 0;
	DMA[d].HDMAIndirectAddressing = (byte & 64) != 0 ? 1 : 0;
	DMA[d].AAddressDecrement = (byte & 16) != 0 ? 1 : 0;
	DMA[d].AAddressFixed = (byte & 8) != 0 ? 1 : 0;
	DMA[d].TransferMode = (byte & 7);
	break;

    case 0x4301:
    case 0x4311:
    case 0x4321:
    case 0x4331:
    case 0x4341:
    case 0x4351:
    case 0x4361:
    case 0x4371:
	DMA[((Address >> 4) & 0x7)].BAddress = byte;
	break;

    case 0x4302:
    case 0x4312:
    case 0x4322:
    case 0x4332:
    case 0x4342:
    case 0x4352:
    case 0x4362:
    case 0x4372:
	d = (Address >> 4) & 0x7;
	DMA[d].AAddress &= 0xFF00;
	DMA[d].AAddress |= byte;
	break;

    case 0x4303:
    case 0x4313:
    case 0x4323:
    case 0x4333:
    case 0x4343:
    case 0x4353:
    case 0x4363:
    case 0x4373:
	d = (Address >> 4) & 0x7;
	DMA[d].AAddress &= 0xFF;
	DMA[d].AAddress |= byte << 8;
	break;

    case 0x4304:
    case 0x4314:
    case 0x4324:
    case 0x4334:
    case 0x4344:
    case 0x4354:
    case 0x4364:
    case 0x4374:
	DMA[((Address >> 4) & 0x7)].ABank = byte;
	break;

    case 0x4305:
    case 0x4315:
    case 0x4325:
    case 0x4335:
    case 0x4345:
    case 0x4355:
    case 0x4365:
    case 0x4375:
	d = (Address >> 4) & 0x7;
	DMA[d].TransferBytes &= 0xFF00;
	DMA[d].TransferBytes |= byte;
	DMA[d].IndirectAddress &= 0xff00;
	DMA[d].IndirectAddress |= byte;
	break;

    case 0x4306:
    case 0x4316:
    case 0x4326:
    case 0x4336:
    case 0x4346:
    case 0x4356:
    case 0x4366:
    case 0x4376:
	d = (Address >> 4) & 0x7;
	DMA[d].TransferBytes &= 0xFF;
	DMA[d].TransferBytes |= byte << 8;
	DMA[d].IndirectAddress &= 0xff;
	DMA[d].IndirectAddress |= byte << 8;
	break;

    case 0x4307:
    case 0x4317:
    case 0x4327:
    case 0x4337:
    case 0x4347:
    case 0x4357:
    case 0x4367:
    case 0x4377:
	DMA[d = ((Address >> 4) & 0x7)].IndirectBank = byte;
	break;

    case 0x4308:
    case 0x4318:
    case 0x4328:
    case 0x4338:
    case 0x4348:
    case 0x4358:
    case 0x4368:
    case 0x4378:
	d = (Address >> 4) & 7;
	DMA[d].Address &= 0xff00;
	DMA[d].Address |= byte;
	break;

    case 0x4309:
    case 0x4319:
    case 0x4329:
    case 0x4339:
    case 0x4349:
    case 0x4359:
    case 0x4369:
    case 0x4379:
	d = (Address >> 4) & 0x7;
	DMA[d].Address &= 0xff;
	DMA[d].Address |= byte << 8;
	break;

    case 0x430A:
    case 0x431A:
    case 0x432A:
    case 0x433A:
    case 0x434A:
    case 0x435A:
    case 0x436A:
    case 0x437A:
	d = (Address >> 4) & 0x7;
	DMA[d].LineCount = byte & 0x7f;
	DMA[d].Repeat = !(byte & 0x80);
	break;

    case 0x4800:
    case 0x4801:
    case 0x4802:
    case 0x4803:
//printf ("%02x->%04x\n", byte, Address);
	break;

    case 0x4804:
    case 0x4805:
    case 0x4806:
    case 0x4807:
//printf ("%02x->%04x\n", byte, Address);

	S9xSetSDD1MemoryMap (Address - 0x4804, byte & 7);
	break;
    default:
	break;
    }
    FillRAM [Address] = byte;
}

/**********************************************************************************************/
/* S9xGetCPU()                                                                                   */
/* This function retrieves a CPUPack.CPU/DMA Register                                                 */
/**********************************************************************************************/
uint8 S9xGetCPU (uint16 Address)
{
    uint8 byte;

    if (Address < 0x4200) 
    {
#ifdef VAR_CYCLES
		CPUPack.CPU.Cycles += ONE_CYCLE;
#endif
		switch (Address)
		{
		// Secret of the Evermore
		case 0x4000:
		case 0x4001:
			return (0x40);

		case 0x4016:
			{
#ifndef NOT_SUPPORT_MOUSE
				if (FillRAM [0x4016] & 1)
				{
				if ((!Settings.SwapJoypads &&
					 PPUPack.IPPU.Controller == SNES_MOUSE_SWAPPED) ||
					(Settings.SwapJoypads &&
					 PPUPack.IPPU.Controller == SNES_MOUSE))
				{
					if (++PPUPack.PPU.MouseSpeed [0] > 2)
					PPUPack.PPU.MouseSpeed [0] = 0;
				}
				return (0);
				}
#endif				
				//int ind = Settings.SwapJoypads ? 1 : 0;
				byte = PPUPack.IPPU.Joypads[0] >> (PPUPack.PPU.Joypad1ButtonReadPos ^ 15);
				PPUPack.PPU.Joypad1ButtonReadPos++;
				return (byte & 1);
			}
		case 0x4017:
			{
			if (FillRAM [0x4016] & 1)
			{
			// MultiPlayer5 adaptor is only allowed to be plugged into port 2
			switch (PPUPack.IPPU.Controller)
			{
			case SNES_MULTIPLAYER5:
				return (2);
#ifndef NOT_SUPPORT_MOUSE
			case SNES_MOUSE_SWAPPED:
				if (Settings.SwapJoypads && ++PPUPack.PPU.MouseSpeed [0] > 2)
				PPUPack.PPU.MouseSpeed [0] = 0;
				break;
				
			case SNES_MOUSE:
				if (!Settings.SwapJoypads && ++PPUPack.PPU.MouseSpeed [0] > 2)
				PPUPack.PPU.MouseSpeed [0] = 0;
				break;
#endif
			}
			return (0x00);
			}

			if (PPUPack.IPPU.Controller == SNES_MULTIPLAYER5)
			{
			if (FillRAM [0x4201] & 0x80)
			{
				byte = ((PPUPack.IPPU.Joypads[0] >> (PPUPack.PPU.Joypad2ButtonReadPos ^ 15)) & 1) |
					(((PPUPack.IPPU.Joypads[2] >> (PPUPack.PPU.Joypad2ButtonReadPos ^ 15)) & 1) << 1);
				PPUPack.PPU.Joypad2ButtonReadPos++;
				return (byte);
			}
			else
			{
				byte = ((PPUPack.IPPU.Joypads[3] >> (PPUPack.PPU.Joypad3ButtonReadPos ^ 15)) & 1) |
					(((PPUPack.IPPU.Joypads[4] >> (PPUPack.PPU.Joypad3ButtonReadPos ^ 15)) & 1) << 1);
				PPUPack.PPU.Joypad3ButtonReadPos++;
				return (byte);
			}
			}
			return ((PPUPack.IPPU.Joypads[0] >> (PPUPack.PPU.Joypad2ButtonReadPos++ ^ 15)) & 1);
			}
		default:
			break;
		}
		return (FillRAM [Address]);
    }
    else
    switch (Address)
    {
	// BS Dynami Tracer! needs to be able to check if NMIs are enabled
	// already, otherwise the game locks up.
    case 0x4200:
	// NMI, h & v timers and joypad reading enable
	if (SNESGameFixes.Old_Read0x4200)
	{
#ifdef CPU_SHUTDOWN
           CPUPack.CPU.WaitAddress = CPUPack.CPU.PCAtOpcodeStart;
#endif
           return (REGISTER_4212());
	}
    case 0x4201:
	// I/O port (output - write only?)
    case 0x4202:
    case 0x4203:
	// Multiplier and multiplicand (write)
    case 0x4204:
    case 0x4205:
    case 0x4206:
	// Divisor and dividend (write)
	return (FillRAM[Address]);
    case 0x4207:
	return (uint8)(PPUPack.PPU.IRQHBeamPos);
    case 0x4208:
	return (PPUPack.PPU.IRQHBeamPos >> 8);
    case 0x4209:
	return (uint8)(PPUPack.PPU.IRQVBeamPos);
    case 0x420a:
	return (PPUPack.PPU.IRQVBeamPos >> 8);
    case 0x420b:
	// General purpose DMA enable
	// Super Formation Soccer 95 della Serie A UCC Xaqua requires this
	// register should not always return zero.
	// .. But Aero 2 waits until this register goes zero..
	// Just keep toggling the value for now in the hope that it breaks
	// the game out of its wait loop...
	FillRAM [0x420b] = !FillRAM [0x420b];
	return (FillRAM [0x420b]);
    case 0x420c:
	// H-DMA enable
	return (PPUPack.IPPU.HDMA);
    case 0x420d:
	// Cycle speed 0 - 2.68Mhz, 1 - 3.58Mhz (banks 0x80 +)
	return (FillRAM[Address]);
    case 0x420e:
    case 0x420f:
	// --->>> Unknown
	return (FillRAM[Address]);
    case 0x4210:
#ifdef CPU_SHUTDOWN
	CPUPack.CPU.WaitAddress = CPUPack.CPU.PCAtOpcodeStart;
#endif	
	byte = FillRAM[0x4210];
	FillRAM[0x4210] = 0;
	return (byte);
    case 0x4211:
	byte = (CPUPack.CPU.IRQActive & (PPU_V_BEAM_IRQ_SOURCE | PPU_H_BEAM_IRQ_SOURCE)) ? 0x80 : 0;
	// Super Robot Wars Ex ROM bug requires this.
	byte |= CPUPack.CPU.Cycles >= Settings.HBlankStart ? 0x40 : 0;
	CLEAR_IRQ_SOURCE (PPU_V_BEAM_IRQ_SOURCE | PPU_H_BEAM_IRQ_SOURCE);
	return (byte);
    case 0x4212:
	// V-blank, h-blank and joypads being read flags (read-only)
#ifdef CPU_SHUTDOWN
	CPUPack.CPU.WaitAddress = CPUPack.CPU.PCAtOpcodeStart;
#endif
	return (REGISTER_4212());
    case 0x4213:
	// I/O port input
    case 0x4214:
    case 0x4215:
	// Quotient of divide result
    case 0x4216:
    case 0x4217:
	// Multiplcation result (for multiply) or remainder of
	// divison.
	return (FillRAM[Address]);
    case 0x4218:
    case 0x4219:
    case 0x421a:
    case 0x421b:
    case 0x421c:
    case 0x421d:
    case 0x421e:
    case 0x421f:
	// Joypads 1-4 button and direction state.
	return (FillRAM [Address]);

    case 0x4300:
    case 0x4310:
    case 0x4320:
    case 0x4330:
    case 0x4340:
    case 0x4350:
    case 0x4360:
    case 0x4370:
	// DMA direction, address type, fixed flag,
	return (FillRAM[Address]);
    case 0x4301:
    case 0x4311:
    case 0x4321:
    case 0x4331:
    case 0x4341:
    case 0x4351:
    case 0x4361:
    case 0x4371:
	return (FillRAM[Address]);

    case 0x4302:
    case 0x4312:
    case 0x4322:
    case 0x4332:
    case 0x4342:
    case 0x4352:
    case 0x4362:
    case 0x4372:
	return (FillRAM[Address]);

    case 0x4303:
    case 0x4313:
    case 0x4323:
    case 0x4333:
    case 0x4343:
    case 0x4353:
    case 0x4363:
    case 0x4373:
	return (FillRAM[Address]);

    case 0x4304:
    case 0x4314:
    case 0x4324:
    case 0x4334:
    case 0x4344:
    case 0x4354:
    case 0x4364:
    case 0x4374:
	return (FillRAM[Address]);

    case 0x4305:
    case 0x4315:
    case 0x4325:
    case 0x4335:
    case 0x4345:
    case 0x4355:
    case 0x4365:
    case 0x4375:
	return (FillRAM[Address]);

    case 0x4306:
    case 0x4316:
    case 0x4326:
    case 0x4336:
    case 0x4346:
    case 0x4356:
    case 0x4366:
    case 0x4376:
	return (FillRAM[Address]);

    case 0x4307:
    case 0x4317:
    case 0x4327:
    case 0x4337:
    case 0x4347:
    case 0x4357:
    case 0x4367:
    case 0x4377:
	return (DMA[(Address >> 4) & 7].IndirectBank);

    case 0x4308:
    case 0x4318:
    case 0x4328:
    case 0x4338:
    case 0x4348:
    case 0x4358:
    case 0x4368:
    case 0x4378:
	return (FillRAM[Address]);

    case 0x4309:
    case 0x4319:
    case 0x4329:
    case 0x4339:
    case 0x4349:
    case 0x4359:
    case 0x4369:
    case 0x4379:
	return (FillRAM[Address]);

    case 0x430A:
    case 0x431A:
    case 0x432A:
    case 0x433A:
    case 0x434A:
    case 0x435A:
    case 0x436A:
    case 0x437A:
    {
	int d = (Address & 0x70) >> 4;
	if (PPUPack.IPPU.HDMA & (1 << d))
	{
	    return (DMA[d].LineCount);
	}
	return (FillRAM[Address]);
    }
    default:
	break;
    }
    return (FillRAM[Address]);
}

void S9xResetPPU ()
{
    PPUPack.PPU.BGMode = 0;
    PPUPack.PPU.BG3Priority = 0;
    PPUPack.PPU.Brightness = 0;
    PPUPack.PPU.VMA.High = 0;
    PPUPack.PPU.VMA.Increment = 1;
    PPUPack.PPU.VMA.Address = 0;
    PPUPack.PPU.VMA.FullGraphicCount = 0;
    PPUPack.PPU.VMA.Shift = 0;

    for (uint8 B = 0; B != 4; B++)
    {
	PPUPack.PPU.BG[B].SCBase = 0;
	PPUPack.PPU.BG[B].VOffset = 0;
	PPUPack.PPU.BG[B].HOffset = 0;
	PPUPack.PPU.BG[B].BGSize = 0;
	PPUPack.PPU.BG[B].NameBase = 0;
	PPUPack.PPU.BG[B].SCSize = 0;

	PPUPack.PPU.ClipCounts[B] = 0;
	PPUPack.PPU.ClipWindowOverlapLogic [B] = CLIP_OR;
	PPUPack.PPU.ClipWindow1Enable[B] = FALSE;
	PPUPack.PPU.ClipWindow2Enable[B] = FALSE;
	PPUPack.PPU.ClipWindow1Inside[B] = TRUE;
	PPUPack.PPU.ClipWindow2Inside[B] = TRUE;
    }

    PPUPack.PPU.ClipCounts[4] = 0;
    PPUPack.PPU.ClipCounts[5] = 0;
    PPUPack.PPU.ClipWindowOverlapLogic[4] = PPUPack.PPU.ClipWindowOverlapLogic[5] = CLIP_OR;
    PPUPack.PPU.ClipWindow1Enable[4] = PPUPack.PPU.ClipWindow1Enable[5] = FALSE;
    PPUPack.PPU.ClipWindow2Enable[4] = PPUPack.PPU.ClipWindow2Enable[5] = FALSE;
    PPUPack.PPU.ClipWindow1Inside[4] = PPUPack.PPU.ClipWindow1Inside[5] = TRUE;
    PPUPack.PPU.ClipWindow2Inside[4] = PPUPack.PPU.ClipWindow2Inside[5] = TRUE;
    
    PPUPack.PPU.CGFLIP = 0;
    int c;
    for (c = 0; c < 256; c++)
    {
	PPUPack.IPPU.Red [c] = (c & 7) << 2;
	PPUPack.IPPU.Green [c] = ((c >> 3) & 7) << 2;
	PPUPack.IPPU.Blue [c] = ((c >> 6) & 2) << 3;
	PPUPack.PPU.CGDATA [c] = PPUPack.IPPU.Red [c] | (PPUPack.IPPU.Green [c] << 5) |
			 (PPUPack.IPPU.Blue [c] << 10);
    }

    PPUPack.PPU.FirstSprite = 0;
    PPUPack.PPU.LastSprite = 127;
    for (int Sprite = 0; Sprite < 128; Sprite++)
    {
	PPUPack.PPU.OBJ[Sprite].HPos = 0;
	PPUPack.PPU.OBJ[Sprite].VPos = 0;
	PPUPack.PPU.OBJ[Sprite].VFlip = 0;
	PPUPack.PPU.OBJ[Sprite].HFlip = 0;
	PPUPack.PPU.OBJ[Sprite].Priority = 0;
	PPUPack.PPU.OBJ[Sprite].Palette = 0;
	PPUPack.PPU.OBJ[Sprite].Name = 0;
	PPUPack.PPU.OBJ[Sprite].Size = 0;
    }
    PPUPack.PPU.OAMPriorityRotation = 0;
    PPUPack.PPU.OAMFlip = 0;
    PPUPack.PPU.OAMTileAddress = 0;
    PPUPack.PPU.OAMAddr = 0;
    PPUPack.PPU.IRQVBeamPos = 0;
    PPUPack.PPU.IRQHBeamPos = 0;
    PPUPack.PPU.VBeamPosLatched = 0;
    PPUPack.PPU.HBeamPosLatched = 0;

    PPUPack.PPU.HBeamFlip = 0;
    PPUPack.PPU.VBeamFlip = 0;
    PPUPack.PPU.HVBeamCounterLatched = 0;

    PPUPack.PPU.MatrixA = PPUPack.PPU.MatrixB = PPUPack.PPU.MatrixC = PPUPack.PPU.MatrixD = 0;
    PPUPack.PPU.CentreX = PPUPack.PPU.CentreY = 0;
    PPUPack.PPU.Joypad1ButtonReadPos = 0;
    PPUPack.PPU.Joypad2ButtonReadPos = 0;
    PPUPack.PPU.Joypad3ButtonReadPos = 0;

    PPUPack.PPU.CGADD = 0;
    PPUPack.PPU.FixedColourRed = PPUPack.PPU.FixedColourGreen = PPUPack.PPU.FixedColourBlue = 0;
    PPUPack.PPU.SavedOAMAddr = 0;
    PPUPack.PPU.ScreenHeight = (Settings.PAL?SNES_HEIGHT_PAL:SNES_HEIGHT_NTSC);
    PPUPack.PPU.WRAM = 0;
    PPUPack.PPU.BG_Forced = 0;
    PPUPack.PPU.ForcedBlanking = TRUE;
    PPUPack.PPU.OBJThroughMain = FALSE;
    PPUPack.PPU.OBJThroughSub = FALSE;
    PPUPack.PPU.OBJSizeSelect = 0;
    PPUPack.PPU.OBJNameSelect = 0;
    PPUPack.PPU.OBJNameBase = 0;
    PPUPack.PPU.OBJAddition = FALSE;
    PPUPack.PPU.OAMReadFlip = 0;
    ZeroMemory (PPUPack.PPU.OAMData, 512 + 32);
    
    PPUPack.PPU.VTimerEnabled = FALSE;
    PPUPack.PPU.HTimerEnabled = FALSE;
    PPUPack.PPU.HTimerPosition = Settings.H_Max + 1;
    PPUPack.PPU.Mosaic = 0;
    PPUPack.PPU.BGMosaic [0] = PPUPack.PPU.BGMosaic [1] = FALSE;
    PPUPack.PPU.BGMosaic [2] = PPUPack.PPU.BGMosaic [3] = FALSE;
    PPUPack.PPU.Mode7HFlip = FALSE;
    PPUPack.PPU.Mode7VFlip = FALSE;
    PPUPack.PPU.Mode7Repeat = 0;
    PPUPack.PPU.Window1Left = 1;
    PPUPack.PPU.Window1Right = 0;
    PPUPack.PPU.Window2Left = 1;
    PPUPack.PPU.Window2Right = 0;
    PPUPack.PPU.RecomputeClipWindows = TRUE;
    PPUPack.PPU.CGFLIPRead = 0;
    PPUPack.PPU.Need16x8Mulitply = FALSE;
    PPUPack.PPU.MouseSpeed[0] = PPUPack.PPU.MouseSpeed[1] = 0;

    PPUPack.IPPU.ColorsChanged = TRUE;
    PPUPack.IPPU.HDMA = 0;
    PPUPack.IPPU.HDMAStarted = FALSE;
    PPUPack.IPPU.MaxBrightness = 0;
    PPUPack.IPPU.LatchedBlanking = 0;
    PPUPack.IPPU.OBJChanged = TRUE;
    PPUPack.IPPU.RenderThisFrame = TRUE;
    PPUPack.IPPU.DirectColourMapsNeedRebuild = TRUE;
    PPUPack.IPPU.FrameCount = 0;
    PPUPack.IPPU.RenderedFramesCount = 0;
    PPUPack.IPPU.DisplayedRenderedFrameCount = 0;
    PPUPack.IPPU.SkippedFrames = 0;
    PPUPack.IPPU.FrameSkip = 0;

    ZeroMemory (PPUPack.IPPU.TileCached [TILE_2BIT], MAX_2BIT_TILES<<1);
    ZeroMemory (PPUPack.IPPU.TileCached [TILE_4BIT], MAX_4BIT_TILES<<1);
    ZeroMemory (PPUPack.IPPU.TileCached [TILE_8BIT], MAX_8BIT_TILES<<1);
    
    tile_askforreset(-1);
		

    PPUPack.IPPU.FirstVRAMRead = FALSE;
    PPUPack.IPPU.LatchedInterlace = FALSE;
    PPUPack.IPPU.DoubleWidthPixels = FALSE;
    PPUPack.IPPU.RenderedScreenWidth = SNES_WIDTH;
    PPUPack.IPPU.RenderedScreenHeight = (Settings.PAL?SNES_HEIGHT_PAL:SNES_HEIGHT_NTSC);
    PPUPack.IPPU.XB = NULL;
    for (c = 0; c < 256; c++)
	PPUPack.IPPU.ScreenColors [c] = c;
    S9xFixColourBrightness ();
    PPUPack.IPPU.PreviousLine = PPUPack.IPPU.CurrentLine = 0;
    PPUPack.IPPU.Joypads[0] = PPUPack.IPPU.Joypads[1] = PPUPack.IPPU.Joypads[2] = 0;
    PPUPack.IPPU.Joypads[3] = PPUPack.IPPU.Joypads[4] = 0;
    PPUPack.IPPU.SuperScope = 0;
    PPUPack.IPPU.Mouse[0] = PPUPack.IPPU.Mouse[1] = 0;
    PPUPack.IPPU.PrevMouseX[0] = PPUPack.IPPU.PrevMouseX[1] = 256 / 2;
    PPUPack.IPPU.PrevMouseY[0] = PPUPack.IPPU.PrevMouseY[1] = 224 / 2;

    if (Settings.ControllerOption == 0)
	PPUPack.IPPU.Controller = SNES_MAX_CONTROLLER_OPTIONS - 1;
    else
	PPUPack.IPPU.Controller = Settings.ControllerOption - 1;
    S9xNextController ();

    for (c = 0; c < 2; c++)
	memset (&PPUPack.IPPU.Clip [c], 0, sizeof (struct ClipData));

#ifndef NOT_SUPPORT_MOUSE
    if (Settings.MouseMaster)
    {
	S9xProcessMouse (0);
	S9xProcessMouse (1);
    }
#endif
    for (c = 0; c < 0x8000; c += 0x100)
	memset (&FillRAM [c], c >> 8, 0x100);

    ZeroMemory (&FillRAM [0x2100], 0x100);
    ZeroMemory (&FillRAM [0x4200], 0x100);
    ZeroMemory (&FillRAM [0x4000], 0x100);
    // For BS Suttehakkun 2...
    ZeroMemory (&FillRAM [0x1000], 0x1000);
}

#ifndef NOT_SUPPORT_MOUSE
void S9xProcessMouse (int which1)
{
    int x, y;
    uint32 buttons;
    
    if ((PPUPack.IPPU.Controller == SNES_MOUSE || PPUPack.IPPU.Controller == SNES_MOUSE_SWAPPED) &&
	S9xReadMousePosition (which1, x, y, buttons))
    {
	int delta_x, delta_y;
#define MOUSE_SIGNATURE 0x1
	PPUPack.IPPU.Mouse [which1] = MOUSE_SIGNATURE | 
			      (PPUPack.PPU.MouseSpeed [which1] << 4) |
		              ((buttons & 1) << 6) | ((buttons & 2) << 6);

	delta_x = x - PPUPack.IPPU.PrevMouseX[which1];
	delta_y = y - PPUPack.IPPU.PrevMouseY[which1];

	if (delta_x > 63)
	{
	    delta_x = 63;
	    PPUPack.IPPU.PrevMouseX[which1] += 63;
	}
	else
	if (delta_x < -63)
	{
	    delta_x = -63;
	    PPUPack.IPPU.PrevMouseX[which1] -= 63;
	}
	else
	    PPUPack.IPPU.PrevMouseX[which1] = x;

	if (delta_y > 63)
	{
	    delta_y = 63;
	    PPUPack.IPPU.PrevMouseY[which1] += 63;
	}
	else
	if (delta_y < -63)
	{
	    delta_y = -63;
	    PPUPack.IPPU.PrevMouseY[which1] -= 63;
	}
	else
	    PPUPack.IPPU.PrevMouseY[which1] = y;

	if (delta_x < 0)
	{
	    delta_x = -delta_x;
	    PPUPack.IPPU.Mouse [which1] |= (delta_x | 0x80) << 16;
	}
	else
	    PPUPack.IPPU.Mouse [which1] |= delta_x << 16;

	if (delta_y < 0)
	{
	    delta_y = -delta_y;
	    PPUPack.IPPU.Mouse [which1] |= (delta_y | 0x80) << 24;
	}
	else
	    PPUPack.IPPU.Mouse [which1] |= delta_y << 24;

	if (PPUPack.IPPU.Controller == SNES_MOUSE_SWAPPED)
	    PPUPack.IPPU.Joypads [0] = PPUPack.IPPU.Mouse [which1];
	else
	    PPUPack.IPPU.Joypads [1] = PPUPack.IPPU.Mouse [which1];
    }
}
#endif

#ifndef NOT_SUPPORT_SUPRESCOPE
void ProcessSuperScope ()
{
    int x, y;
    uint32 buttons;
    
    if (PPUPack.IPPU.Controller == SNES_SUPERSCOPE &&
	S9xReadSuperScopePosition (x, y, buttons))
    {
#define SUPERSCOPE_SIGNATURE 0x00ff
	uint32 scope;
	
	scope = SUPERSCOPE_SIGNATURE | ((buttons & 1) << (7 + 8)) |
		((buttons & 2) << (5 + 8)) | ((buttons & 4) << (3 + 8)) |
		((buttons & 8) << (1 + 8));
	if (x > 255)
	    x = 255;
	if (x < 0)
	    x = 0;
	if (y > PPUPack.PPU.ScreenHeight - 1)
	    y = PPUPack.PPU.ScreenHeight - 1;
	if (y < 0)
	    y = 0;

	PPUPack.PPU.VBeamPosLatched = (uint16) (y + 1);
	PPUPack.PPU.HBeamPosLatched = (uint16) x;
	PPUPack.PPU.HVBeamCounterLatched = TRUE;
	FillRAM [0x213F] |= 0x40;
	PPUPack.IPPU.Joypads [1] = scope;
    }
}
#endif
void S9xNextController ()
{
    switch (PPUPack.IPPU.Controller)
    {
    case SNES_MULTIPLAYER5:
	PPUPack.IPPU.Controller = SNES_JOYPAD;
	break;
    case SNES_JOYPAD:
	if (Settings.MouseMaster)
	{
	    PPUPack.IPPU.Controller = SNES_MOUSE_SWAPPED;
	    break;
	}
    case SNES_MOUSE_SWAPPED:
	if (Settings.MouseMaster)
	{
	    PPUPack.IPPU.Controller = SNES_MOUSE;
	    break;
	}
    case SNES_MOUSE:
	if (Settings.SuperScopeMaster)
	{
	    PPUPack.IPPU.Controller = SNES_SUPERSCOPE;
	    break;
	}
    case SNES_SUPERSCOPE:
	if (Settings.MultiPlayer5Master)
	{
	    PPUPack.IPPU.Controller = SNES_MULTIPLAYER5;
	    break;
	}
    default:
	PPUPack.IPPU.Controller = SNES_JOYPAD;
	break;
    }
}

void S9xUpdateJoypads ()
{
    int i;

    for (i = 0; i < 5; i++)
    {
		PPUPack.IPPU.Joypads [i] = S9xReadJoypad (i);
		if (PPUPack.IPPU.Joypads [i] & SNES_LEFT_MASK)
			PPUPack.IPPU.Joypads [i] &= ~SNES_RIGHT_MASK;
		if (PPUPack.IPPU.Joypads [i] & SNES_UP_MASK)
			PPUPack.IPPU.Joypads [i] &= ~SNES_DOWN_MASK;
	}

	//touhaiden controller Fix
	if (SNESGameFixes.TouhaidenControllerFix && 
		(PPUPack.IPPU.Controller == SNES_JOYPAD || PPUPack.IPPU.Controller == SNES_MULTIPLAYER5))
	{
		for (i = 0; i < 5; i++)
		{
			if (PPUPack.IPPU.Joypads [i])
			PPUPack.IPPU.Joypads [i] |= 0xffff0000;
		}
	}
#ifndef NOT_SUPPORT_MOUSE
	// Read mouse position if enabled
	if (Settings.MouseMaster)
	{
		for (i = 0; i < 2; i++)
			S9xProcessMouse (i);
	}
#endif

#ifndef NOT_SUPPORT_SUPRESCOPE
	// Read SuperScope if enabled
	if (Settings.SuperScopeMaster)
	ProcessSuperScope ();
#endif

	if (FillRAM [0x4200] & 1)
	{
		PPUPack.PPU.Joypad1ButtonReadPos = 16;
		if (FillRAM [0x4201] & 0x80)
		{
			PPUPack.PPU.Joypad2ButtonReadPos = 16;
			PPUPack.PPU.Joypad3ButtonReadPos = 0;
		}
		else
		{
			PPUPack.PPU.Joypad2ButtonReadPos = 0;
			PPUPack.PPU.Joypad3ButtonReadPos = 16;
		}
//		int ind = Settings.SwapJoypads ? 1 : 0;

//		FillRAM [0x4218] = (uint8) PPUPack.IPPU.Joypads [ind];
//		FillRAM [0x4219] = (uint8) (PPUPack.IPPU.Joypads [ind] >> 8);
//		FillRAM [0x421a] = (uint8) PPUPack.IPPU.Joypads [ind ^ 1];
//		FillRAM [0x421b] = (uint8) (PPUPack.IPPU.Joypads [ind ^ 1] >> 8);
		*((uint16*)(FillRAM +0x4218)) = (uint16) PPUPack.IPPU.Joypads [0];
		*((uint16*)(FillRAM +0x421a)) = (uint16) PPUPack.IPPU.Joypads [1];
		if (FillRAM [0x4201] & 0x80)
		{
			*((uint16*)(FillRAM +0x421c)) = (uint16) PPUPack.IPPU.Joypads [0];
			*((uint16*)(FillRAM +0x421e)) = (uint16) PPUPack.IPPU.Joypads [2];
//			FillRAM [0x421c] = (uint8) PPUPack.IPPU.Joypads [ind];
//			FillRAM [0x421d] = (uint8) (PPUPack.IPPU.Joypads [ind] >> 8);
//			FillRAM [0x421e] = (uint8) PPUPack.IPPU.Joypads [2];
//			FillRAM [0x421f] = (uint8) (PPUPack.IPPU.Joypads [2] >> 8);
		}
		else
		{
			*((uint16*)(FillRAM +0x421c)) = (uint16) PPUPack.IPPU.Joypads [3];
			*((uint16*)(FillRAM +0x421e)) = (uint16) PPUPack.IPPU.Joypads [4];
//			FillRAM [0x421c] = (uint8) PPUPack.IPPU.Joypads [3];
//			FillRAM [0x421d] = (uint8) (PPUPack.IPPU.Joypads [3] >> 8);
//			FillRAM [0x421e] = (uint8) PPUPack.IPPU.Joypads [4];
//			FillRAM [0x421f] = (uint8) (PPUPack.IPPU.Joypads [4] >> 8);
		}
    }
}

#ifndef ZSNES_FX
void S9xSuperFXExec ()
{
#if 1
    /*if (Settings.SuperFX)*/
    {
	if ((FillRAM [0x3000 + GSU_SFR] & FLG_G) &&
	    (FillRAM [0x3000 + GSU_SCMR] & 0x18) == 0x18)
	{
	    if (!Settings.WinterGold||Settings.StarfoxHack)
		FxEmulate (~0);
	    else
		FxEmulate ((FillRAM [0x3000 + GSU_CLSR] & 1) ? 700 : 350);
	    int GSUStatus = FillRAM [0x3000 + GSU_SFR] |
			    (FillRAM [0x3000 + GSU_SFR + 1] << 8);
	    if ((GSUStatus & (FLG_G | FLG_IRQ)) == FLG_IRQ)
	    {
		// Trigger a GSU IRQ.
		S9xSetIRQ (GSU_IRQ_SOURCE);
	    }
	}
    }
#else
    uint32 tmp =  (FillRAM[0x3034] << 16) + *(uint16 *) &FillRAM [0x301e];

#if 0
    if (tmp == 0x018428)
    {
	*(uint16 *) &SRAM [0x0064] = 0xbc00;
	*(uint16 *) &SRAM [0x002c] = 0x8000;
    }
#endif
    if (tmp == -1)//0x018428) //0x01bfc3) //0x09edaf) //-1) //0x57edaf)
    {
	while (FillRAM [0x3030] & 0x20)
	{
	    int i;
	    int32 vError;
	    uint8 avReg[0x40];
	    char tmp[128];
	    uint8 vPipe;
	    uint8 vColr;
	    uint8 vPor;

	    FxPipeString (tmp);
	    /* Make the string 32 chars long */
	    if(strlen(tmp) < 32) { memset(&tmp[strlen(tmp)],' ',32-strlen(tmp)); tmp[32] = 0; }

	    /* Copy registers (so we can see if any changed) */
	    vColr = FxGetColorRegister();
	    vPor = FxGetPlotOptionRegister();
	    memcpy(avReg,SuperFX.pvRegisters,0x40);

	    /* Print the pipe string */
	    printf(tmp);

	    /* Execute the instruction in the pipe */
	    vPipe = FxPipe();
	    vError = FxEmulate(1);

	    /* Check if any registers changed (and print them if they did) */
	    for(i=0; i<16; i++)
	    {
		uint32 a = 0;
		uint32 r1 = ((uint32)avReg[i*2]) | (((uint32)avReg[(i*2)+1])<<8);
		uint32 r2 = (uint32)(SuperFX.pvRegisters[i*2]) | (((uint32)SuperFX.pvRegisters[(i*2)+1])<<8);
		if(i==15)
		    a = OPCODE_BYTES(vPipe);
		if(((r1+a)&0xffff) != r2)
		    printf(" r%d=$%04x",i,r2);
	    }
	    {
		/* Check SFR */
		uint32 r1 = ((uint32)avReg[0x30]) | (((uint32)avReg[0x31])<<8);
		uint32 r2 = (uint32)(SuperFX.pvRegisters[0x30]) | (((uint32)SuperFX.pvRegisters[0x31])<<8);
		if((r1&(1<<1)) != (r2&(1<<1)))
		    printf(" Z=%d",(uint32)(!!(r2&(1<<1))));
		if((r1&(1<<2)) != (r2&(1<<2)))
		    printf(" CY=%d",(uint32)(!!(r2&(1<<2))));
		if((r1&(1<<3)) != (r2&(1<<3)))
		    printf(" S=%d",(uint32)(!!(r2&(1<<3))));
		if((r1&(1<<4)) != (r2&(1<<4)))
		    printf(" OV=%d",(uint32)(!!(r2&(1<<4))));
		if((r1&(1<<5)) != (r2&(1<<5)))
		    printf(" G=%d",(uint32)(!!(r2&(1<<5))));
		if((r1&(1<<6)) != (r2&(1<<6)))
		    printf(" R=%d",(uint32)(!!(r2&(1<<6))));
		if((r1&(1<<8)) != (r2&(1<<8)))
		    printf(" ALT1=%d",(uint32)(!!(r2&(1<<8))));
		if((r1&(1<<9)) != (r2&(1<<9)))
		    printf(" ALT2=%d",(uint32)(!!(r2&(1<<9))));
		if((r1&(1<<10)) != (r2&(1<<10)))
		    printf(" IL=%d",(uint32)(!!(r2&(1<<10))));
		if((r1&(1<<11)) != (r2&(1<<11)))
		    printf(" IH=%d",(uint32)(!!(r2&(1<<11))));
		if((r1&(1<<12)) != (r2&(1<<12)))
		    printf(" B=%d",(uint32)(!!(r2&(1<<12))));
		if((r1&(1<<15)) != (r2&(1<<15)))
		    printf(" IRQ=%d",(uint32)(!!(r2&(1<<15))));
	    }
	    {
		/* Check PBR */
		uint32 r1 = ((uint32)avReg[0x34]);
		uint32 r2 = (uint32)(SuperFX.pvRegisters[0x34]);
		if(r1 != r2)
		    printf(" PBR=$%02x",r2);
	    }
	    {
		/* Check ROMBR */
		uint32 r1 = ((uint32)avReg[0x36]);
		uint32 r2 = (uint32)(SuperFX.pvRegisters[0x36]);
		if(r1 != r2)
		    printf(" ROMBR=$%02x",r2);
	    }
	    {
		/* Check RAMBR */
		uint32 r1 = ((uint32)avReg[0x3c]);
		uint32 r2 = (uint32)(SuperFX.pvRegisters[0x3c]);
		if(r1 != r2)
		    printf(" RAMBR=$%02x",r2);
	    }
	    {
		/* Check CBR */
		uint32 r1 = ((uint32)avReg[0x3e]) | (((uint32)avReg[0x3f])<<8);
		uint32 r2 = (uint32)(SuperFX.pvRegisters[0x3e]) | (((uint32)SuperFX.pvRegisters[0x3f])<<8);
		if(r1 != r2)
		    printf(" CBR=$%04x",r2);
	    }
	    {
		/* Check COLR */
		if(vColr != FxGetColorRegister())
		    printf(" COLR=$%02x",FxGetColorRegister());
	    }
	    {
		/* Check POR */
		if(vPor != FxGetPlotOptionRegister())
		    printf(" POR=$%02x",FxGetPlotOptionRegister());
	    }
	    printf ("\n");
	}
	S9xExit ();
    }
    else
    {
	uint32 t = (FillRAM [0x3034] << 16) +
		   (FillRAM [0x301f] << 8) +
		   (FillRAM [0x301e] << 0);

	printf ("%06x: %d\n", t, FxEmulate (2000000));
//	FxEmulate (2000000);
    }
#if 0
    if (!(CPUPack.CPU.Flags & TRACE_FLAG))
    {
	static int z = 1;
	if (z == 0)
	{
	    extern FILE *trace;
	    CPUPack.CPU.Flags |= TRACE_FLAG;
	    trace = fopen ("trace.log", "wb");
	}
	else
	z--;
    }
#endif
    FillRAM [0x3030] &= ~0x20;
    if (FillRAM [0x3031] & 0x80)
    {
	S9xSetIRQ (GSU_IRQ_SOURCE);
    }
#endif
}


#endif
