/* FCE Ultra - NES/Famicom Emulator
*
* Copyright notice for this file:
- * Copyright (C) 1998 BERO
+ * Copyright (C) 1998 BERO
* Copyright (C) 2002 Ben Parnell
*
* This program is free software; you can redistribute it and/or modify
#include "types.h"
#include "x6502.h"
#include "fce.h"
+#include "fceu098.h"
#include "sound.h"
-#include "svga.h"
+#include "svga.h"
#include "netplay.h"
#include "general.h"
#include "endian.h"
#include "fds.h"
#include "ines.h"
#include "unif.h"
+#include "vsuni.h"
#include "cheat.h"
#include "state.h"
#include "input.h"
#include "file.h"
#include "crc32.h"
+#include "ppu.h"
+#include "ppu098.h"
+
+#include "palette.h"
+#include "movie.h"
+
+#include "dprintf.h"
+
+#ifdef __arm__
+#include "drivers/arm/asmutils.h"
+#endif
#define Pal (PALRAM)
-static void FetchSpriteData(void);
-static void FASTAPASS(1) RefreshLine(uint8 *target);
+
+static void (*RefreshLine)(uint8 *P, uint32 vofs) = NULL;
static void PRefreshLine(void);
-static void FASTAPASS(1) RefreshSprite(uint8 *target);
+
static void ResetPPU(void);
static void PowerPPU(void);
uint64 timestampbase=0;
+int ppudead=1;
+int kook=0;
+
int MMC5Hack;
uint32 MMC5HackVROMMask;
uint8 *MMC5HackExNTARAMPtr;
uint8 *MMC5HackVROMPTR;
-uint8 MMC5HackCHRMode=0;
+uint8 MMC5HackCHRMode=0;
uint8 MMC5HackSPMode;
uint8 MMC5HackSPScroll;
uint8 MMC5HackSPPage;
static uint8 deemp=0;
static int deempcnt[8];
-static int tosprite=256;
-
FCEUGI FCEUGameInfo;
-void (*GameInterface)(int h);
+void (*GameInterface)(int h, void *param);
void FP_FASTAPASS(1) (*PPU_hook)(uint32 A);
void (*GameStateRestore)(int version);
-void (*GameHBIRQHook)(void);
+void (*GameHBIRQHook)(void), (*GameHBIRQHook2)(void);
readfunc ARead[0x10000];
writefunc BWrite[0x10000];
static writefunc *BWriteG;
static int RWWrap=0;
+#ifdef ASM_6502
+#ifdef DEBUG_ASM_6502
+extern uint8 nes_internal_ram[0x800];
+#else
+static void asmcpu_update(int32 cycles)
+{
+ // some code from x6502.c
+ fhcnt-=cycles;
+ if(fhcnt<=0)
+ {
+ FrameSoundUpdate();
+ fhcnt+=fhinc;
+ }
+
+ if(PCMIRQCount>0)
+ {
+ PCMIRQCount-=cycles;
+ if(PCMIRQCount<=0)
+ {
+ vdis=1;
+ if((PSG[0x10]&0x80) && !(PSG[0x10]&0x40))
+ {
+ extern uint8 SIRQStat;
+ SIRQStat|=0x80;
+ X6502_IRQBegin(FCEU_IQDPCM);
+ }
+ }
+ }
+}
+#endif
+
+void asmcpu_unpack(void)
+{
+ nes_registers[0] = X.A << 24;
+ nes_registers[1] = X.X;
+ nes_registers[2] = X.Y;
+ pc_base = 0;
+ nes_registers[3] = X.PC;
+ X6502_Rebase_a();
+ nes_registers[4] = X.S << 24;
+ nes_registers[4]|= X.IRQlow << 8;
+ if (MapIRQHook)
+ nes_registers[4] |= 1<<16; // MapIRQHook set bit
+ nes_registers[7] = (uint32)X.count << 16;
+
+ // NVUB DIZC
+ nes_registers[4]|= X.P & 0x5d;
+ nes_registers[5] = X.P << 24; // N
+ if (!(X.P&0x02)) nes_registers[5] |= 1; // Z
+
+#ifdef DEBUG_ASM_6502
+ memcpy(nes_internal_ram, RAM, 0x800);
+#endif
+}
+
+void asmcpu_pack(void)
+{
+ X.A = nes_registers[0] >> 24;
+ X.X = nes_registers[1];
+ X.Y = nes_registers[2];
+ X.PC= nes_registers[3] - pc_base;
+ X.S = nes_registers[4] >> 24;
+ X.IRQlow = nes_registers[4] >> 8;
+ X.count = (int32) nes_registers[7] >> 16;
+
+ // NVUB DIZC
+ X.P = nes_registers[4] & 0x5d;
+ if ( nes_registers[5]&0x80000000) X.P |= 0x80; // N
+ if (!(nes_registers[5]&0x000000ff)) X.P |= 0x02; // Z
+}
+#endif
+
DECLFW(BNull)
{
DECLFR(ANull)
{
+ //printf("open [%04x] %02x @ %04x (%04x)\n", A, X.DB, X.PC, X.PC&0x7ff);
return(X.DB);
}
ARead[x+0x8000]=AReadG[x];
BWrite[x+0x8000]=BWriteG[x];
}
+#ifdef ASM_6502
+ GenieSetPages(1);
+#endif
free(AReadG);
free(BWriteG);
AReadG=0;
uint32 TempAddr,RefreshAddr;
-static int maxsprites=8;
/* scanline is equal to the current visible scanline we're on. */
int scanline;
-static uint32 scanlines_per_frame;
+
+uint8 GameMemBlock[131072] __attribute__ ((aligned (4)));
+uint8 NTARAM[0x800] __attribute__ ((aligned (4)));
+uint8 PALRAM[0x20] __attribute__ ((aligned (4)));
+#if !defined(ASM_6502) || defined(DEBUG_ASM_6502)
+uint8 RAM[0x800] __attribute__ ((aligned (4)));
+#endif
uint8 PPU[4];
uint8 PPUSPL;
-uint8 GameMemBlock[131072];
-uint8 NTARAM[0x800],PALRAM[0x20],SPRAM[0x100],SPRBUF[0x100];
-uint8 RAM[0x800];
-
uint8 PAL=0;
-#define MMC5SPRVRAMADR(V) &MMC5SPRVPage[(V)>>10][(V)]
+
#define MMC5BGVRAMADR(V) &MMC5BGVPage[(V)>>10][(V)]
#define VRAMADR(V) &VPage[(V)>>10][(V)]
-
+
+static int linestartts;
+static int tofix=0;
+
+static uint8 *Plinef;
+
+extern uint8 sprlinebuf[256+8];
+extern int32 sphitx;
+extern uint8 sphitdata;
+
+extern int spork; /* spork the world. Any sprites on this line?
+ Then this will be set to 1. Needed for zapper
+ emulation and *gasp* sprite emulation.
+ */
+
+static void ResetRL(uint8 *target)
+{
+ if(InputScanlineHook)
+ InputScanlineHook(0,0,0,0);
+ Plinef=target;
+ linestartts=timestamp*48+X6502_GetCycleCount();
+ tofix=1;
+}
+
+static INLINE void Fixit1(void);
+
+/* faking FCEUPPU_LineUpdate() from later versions of the emu */
+static void FakedLineUpdate(void)
+{
+ #define TOFIXNUM (272-0x4)
+ int lastpixel;
+
+ if (scanline >= 240) return;
+
+ if (tofix || sphitx != 0x100)
+ {
+ lastpixel = (timestamp*48-linestartts)>>4;
+ if (PAL) lastpixel += lastpixel>>4;
+ //printf("lastpixel: %i\n", lastpixel);
+ }
+
+ if (tofix && lastpixel>=TOFIXNUM)
+ {
+ Fixit1();
+ tofix=0;
+ }
+
+ // CheckSpriteHit()
+ if(sphitx!=0x100)
+ {
+ int l=lastpixel-16;
+ int x;
+
+ for(x=sphitx;x<(sphitx+8) && x<l;x++)
+ {
+ if((sphitdata&(0x80>>(x-sphitx))) && !(Plinef[x]&64))
+ {
+ PPU_status|=0x40;
+ sphitx=0x100;
+ break;
+ }
+ }
+ }
+}
+
+
static DECLFW(BRAML)
-{
+{
RAM[A]=V;
}
return RAM[A&0x7FF];
}
-
+
static DECLFR(A2002)
{
+ /* merged */
uint8 ret;
+
+ FakedLineUpdate();
ret = PPU_status;
+ ret|=PPUGenLatch&0x1F;
vtoggle=0;
PPU_status&=0x7F;
- return ret|(PPUGenLatch&0x1F);
+ PPUGenLatch=ret;
+ //dprintf("r [2002] %02x",ret);
+ return ret;
}
static DECLFR(A200x)
{
+ /* merged */
+ FakedLineUpdate();
return PPUGenLatch;
}
static DECLFR(A2007)
{
+ /* merged */
uint8 ret;
uint32 tmp=RefreshAddr&0x3FFF;
- PPUGenLatch=ret=VRAMBuffer;
+ FakedLineUpdate();
+
+ ret=VRAMBuffer;
+
if(PPU_hook) PPU_hook(tmp);
- if(tmp<0x2000)
+ PPUGenLatch=VRAMBuffer;
+ if(tmp<0x2000)
{
VRAMBuffer=VPage[tmp>>10][tmp];
}
- else
+ else
{
VRAMBuffer=vnapage[(tmp>>10)&0x3][tmp&0x3FF];
}
if (INC32) RefreshAddr+=32;
else RefreshAddr++;
if(PPU_hook) PPU_hook(RefreshAddr&0x3fff);
+ dprintf("r [2007] %02x",ret);
return ret;
}
static DECLFW(B2000)
{
+ /* NMI2? */
+ FakedLineUpdate();
PPUGenLatch=V;
PPU[0]=V;
TempAddr&=0xF3FF;
static DECLFW(B2001)
{
+ /* merged */
+ FakedLineUpdate();
PPUGenLatch=V;
PPU[1]=V;
if(V&0xE0)
static DECLFW(B2002)
{
+ /* merged */
PPUGenLatch=V;
}
static DECLFW(B2003)
{
+ /* merged */
PPUGenLatch=V;
PPU[3]=V;
PPUSPL=V&0x7;
static DECLFW(B2004)
{
+ /* merged */
PPUGenLatch=V;
- //SPRAM[PPU[3]++]=V;
- if(PPUSPL&8)
+ if(PPUSPL>=8)
{
if(PPU[3]>=8)
SPRAM[PPU[3]]=V;
{
//printf("$%02x:$%02x\n",PPUSPL,V);
SPRAM[PPUSPL]=V;
- PPUSPL++;
}
PPU[3]++;
+ PPUSPL++;
+
}
static DECLFW(B2005)
{
+ /* merged */
uint32 tmp=TempAddr;
-
+ FakedLineUpdate();
PPUGenLatch=V;
if (!vtoggle)
{
static DECLFW(B2006)
{
+ /* merged */
+ FakedLineUpdate();
+
PPUGenLatch=V;
if(!vtoggle)
{
{
TempAddr&=0xFF00;
TempAddr|=V;
- RefreshAddr=TempAddr;
+ RefreshAddr=TempAddr;
if(PPU_hook)
PPU_hook(RefreshAddr);
}
}
static DECLFW(B2007)
-{
+{
+ /* merged */
uint32 tmp=RefreshAddr&0x3FFF;
-
PPUGenLatch=V;
if(tmp>=0x3F00)
{
- // hmmm....
- if(!(tmp&0xf))
- PALRAM[0x00]=PALRAM[0x04]=PALRAM[0x08]=PALRAM[0x0C]=
- PALRAM[0x10]=PALRAM[0x14]=PALRAM[0x18]=PALRAM[0x1c]=V&0x3f;
- else if(tmp&3) PALRAM[(tmp&0x1f)]=V&0x3f;
+ // hmmm....
+ if(!(tmp&0xf))
+ PALRAM[0x00]=PALRAM[0x04]=PALRAM[0x08]=PALRAM[0x0C]=V&0x3f;
+ else if(tmp&3) PALRAM[(tmp&0x1f)]=V&0x3f;
}
else if(tmp<0x2000)
{
VPage[tmp>>10][tmp]=V;
}
else
- {
+ {
if(PPUNTARAM&(1<<((tmp&0xF00)>>10)))
vnapage[((tmp&0xF00)>>10)][tmp&0x3FF]=V;
}
}
static DECLFW(B4014)
-{
+{
uint32 t=V<<8;
int x;
+
for(x=0;x<256;x++)
B2004(0x2004,X.DB=ARead[t+x](t+x));
X6502_AddCycles(512);
}
-static void FASTAPASS(1) BGRender(uint8 *target)
+void BGRender(uint8 *target)
{
- uint32 tem;
- RefreshLine(target);
+ uint32 tem, vofs;
+ vofs=((PPU[0]&0x10)<<8) | ((RefreshAddr>>12)&7);
+
+ Pal[0]|=64;
+ Pal[4]|=64;
+ Pal[8]|=64;
+ Pal[0xC]|=64;
+ RefreshLine(target-XOffset, vofs);
+ Pal[0]&=63;
+ Pal[4]&=63;
+ Pal[8]&=63;
+ Pal[0xC]&=63;
+
if(!(PPU[1]&2))
{
- tem=Pal[0]|(Pal[0]<<8)|(Pal[0]<<16)|(Pal[0]<<24);
- tem|=0x40404040;
+ tem=Pal[0]|0x40;
+ tem|=tem<<8;
+ tem|=tem<<16;
*(uint32 *)target=*(uint32 *)(target+4)=tem;
}
}
#ifdef FRAMESKIP
-static int FSkip=0;
+int FSkip=0;
void FCEUI_FrameSkip(int x)
{
FSkip=x;
#endif
/* This is called at the beginning of each visible scanline */
-static void Loop6502(void)
+static void LineUpdate(uint8 *target)
{
uint32 tem;
- int x;
- uint8 *target=XBuf+(scanline<<8)+(scanline<<4)+8;
+ int y;
- if(ScreenON || SpriteON)
- {
- /* PRefreshLine() will not get called on skipped frames. This
- could cause a problem, but the solution would be rather complex,
- due to the current sprite 0 hit code.
+ /* PRefreshLine() will not get called on skipped frames. This
+ * could cause a problem, but the solution would be rather complex,
+ * due to the current sprite 0 hit code.
*/
- #ifdef FRAMESKIP
- if(!FSkip)
- {
- #endif
- if(ScreenON)
- {
- if(scanline>=FSettings.FirstSLine && scanline<=FSettings.LastSLine)
- BGRender(target);
- else
- {
- if(PPU_hook)
- PRefreshLine();
- }
- }
- else
- {
- tem=Pal[0]|(Pal[0]<<8)|(Pal[0]<<16)|(Pal[0]<<24);
- tem|=0x40404040;
- FCEU_dwmemset(target,tem,264);
- }
- #ifdef FRAMESKIP
- }
- #endif
- if (SpriteON && scanline)
- RefreshSprite(target);
- #ifdef FRAMESKIP
- if(!FSkip)
- {
- #endif
- if(PPU[1]&0x01)
- {
- for(x=63;x>=0;x--)
- *(uint32 *)&target[x<<2]=(*(uint32*)&target[x<<2])&0xF0F0F0F0;
- }
- if((PPU[1]>>5)==0x7)
- for(x=63;x>=0;x--)
- *(uint32 *)&target[x<<2]=((*(uint32*)&target[x<<2])&0x3f3f3f3f)|0x40404040;
- else if(PPU[1]&0xE0)
- for(x=63;x>=0;x--)
- *(uint32 *)&target[x<<2]=(*(uint32*)&target[x<<2])|0xC0C0C0C0;
- else
- for(x=63;x>=0;x--)
- *(uint32 *)&target[x<<2]=(*(uint32*)&target[x<<2])&0x3f3f3f3f;
-
- #ifdef FRAMESKIP
- }
- #endif
+ if(FSkip)
+ {
+ y=(int)SPRAM[0] + 1;
+ if(scanline==y && SpriteON) PPU_status|=0x40; // hack
+ return;
+ }
+
+ if(!ScreenON)
+ {
+ tem=Pal[0]|0x40;
+ tem|=tem << 8;
+ tem|=tem << 16;
+ FCEU_dwmemset(target,tem,256);
+ }
+ else if(scanline < FSettings.FirstSLine || scanline > FSettings.LastSLine)
+ {
+ if(PPU_hook)
+ PRefreshLine();
+ y=(int)SPRAM[0] + 1;
+ if(scanline==y && SpriteON) PPU_status|=0x40;
}
else
{
- tem=Pal[0]|(Pal[0]<<8)|(Pal[0]<<16)|(Pal[0]<<24);
- FCEU_dwmemset(target,tem,256);
- }
+ BGRender(target);
+ }
+
if(InputScanlineHook)
- InputScanlineHook(target, scanline);
+ InputScanlineHook(target,spork?sprlinebuf:0,linestartts,256);
+}
+
+
+static void LineUpdateEnd(uint8 *target)
+{
+#ifdef __arm__
+ if(ScreenON || SpriteON) // Yes, very el-cheapo.
+ {
+ if(PPU[1]&0x01)
+ block_and(target, 256, 0x30);
+ }
+ if((PPU[1]>>5)==0x7)
+ block_or(target, 256, 0xc0);
+ else if(PPU[1]&0xE0)
+ block_or(target, 256, 0x40);
+ else
+ block_andor(target, 256, 0x3f, 0x80);
+#else
+ int x;
+
+ if(ScreenON || SpriteON) // Yes, very el-cheapo.
+ {
+ if(PPU[1]&0x01)
+ {
+ for(x=63;x>=0;x--)
+ *(uint32 *)&target[x<<2]=(*(uint32*)&target[x<<2])&0x30303030;
+ }
+ }
+ if((PPU[1]>>5)==0x7)
+ {
+ for(x=63;x>=0;x--)
+ *(uint32 *)&target[x<<2]=((*(uint32*)&target[x<<2])&0x3f3f3f3f)|0xc0c0c0c0;
+ }
+ else if(PPU[1]&0xE0)
+ for(x=63;x>=0;x--)
+ *(uint32 *)&target[x<<2]=(*(uint32*)&target[x<<2])|0x40404040;
+ else
+ for(x=63;x>=0;x--)
+ *(uint32 *)&target[x<<2]=((*(uint32*)&target[x<<2])&0x3f3f3f3f)|0x80808080;
+#endif
+
+ // black borders
+ ((uint32 *)target)[-2]=((uint32 *)target)[-1]=0;
+ ((uint32 *)target)[64]=((uint32 *)target)[65]=0;
}
#define PAL(c) ((c)+cc)
static void PRefreshLine(void)
{
- uint32 vofs;
- uint8 X1;
+ uint32 vofs;
+ int X1;
+ vofs=((PPU[0]&0x10)<<8) | ((RefreshAddr>>12)&7);
+ void (*PPU_hook_)(uint32 A) = PPU_hook;
+
+
+ for(X1=33;X1;X1--)
+ {
+ uint32 zz2;
+ uint32 vadr;
- vofs = 0;
- if (BGAdrHI) vofs = 0x1000;
+ zz2=(RefreshAddr>>10)&3;
+ PPU_hook_(0x2000|(RefreshAddr&0xFFF));
- vofs+=(RefreshAddr>>12)&7;
+ vadr=(vnapage[zz2][RefreshAddr&0x3ff]<<4)+vofs;
+
+ PPU_hook_(vadr);
- for(X1=33;X1;X1--)
- {
- register uint8 no;
- register uint8 zz2;
- zz2=(uint8)((RefreshAddr>>10)&3);
- PPU_hook(0x2000|(RefreshAddr&0xFFF));
- no = vnapage[zz2][(RefreshAddr&0x3ff)];
- PPU_hook((no<<4)+vofs);
if((RefreshAddr&0x1f)==0x1f)
RefreshAddr^=0x41F;
else
RefreshAddr++;
- }
+ }
}
-/* Total of 33 tiles(32 + 1 extra) */
-static void FASTAPASS(1) RefreshLine(uint8 *target)
+/* This high-level graphics MMC5 emulation code was written
+ for MMC5 carts in "CL" mode. It's probably not totally
+ correct for carts in "SL" mode.
+ */
+static void RefreshLine_MMC5Hack1(uint8 *P, uint32 vofs)
{
- uint32 vofs;
- int X1;
- register uint8 *P=target;
-
- vofs=0;
-
- Pal[0]|=64;
- Pal[4]|=64;
- Pal[8]|=64;
- Pal[0xC]|=64;
-
- vofs=((PPU[0]&0x10)<<8) | ((RefreshAddr>>12)&7);
- P-=XOffset;
-
- /* This high-level graphics MMC5 emulation code was written
- for MMC5 carts in "CL" mode. It's probably not totally
- correct for carts in "SL" mode.
- */
- if(MMC5Hack && geniestage!=1)
- {
- if(MMC5HackCHRMode==0 && (MMC5HackSPMode&0x80))
- {
- int8 tochange;
+ int8 tochange, X1;
tochange=MMC5HackSPMode&0x1F;
for(X1=33;X1;X1--,P+=8)
{
uint8 *C;
- register uint8 cc,zz,zz2;
+ uint8 cc,zz,zz2;
uint32 vadr;
- if((tochange<=0 && MMC5HackSPMode&0x40) ||
+ if((tochange<=0 && MMC5HackSPMode&0x40) ||
(tochange>0 && !(MMC5HackSPMode&0x40)))
{
uint8 xs,ys;
- xs=33-X1;
+ xs=33-X1;
ys=((scanline>>3)+MMC5HackSPScroll)&0x1F;
if(ys>=0x1E) ys-=0x1E;
vadr=(MMC5HackExNTARAMPtr[xs|(ys<<5)]<<4)+(vofs&7);
RefreshAddr++;
tochange--;
}
- }
- else if(MMC5HackCHRMode==1 && (MMC5HackSPMode&0x80))
- {
- int8 tochange;
+}
+
+static void RefreshLine_MMC5Hack2(uint8 *P, uint32 vofs)
+{
+ int8 tochange, X1;
tochange=MMC5HackSPMode&0x1F;
for(X1=33;X1;X1--,P+=8)
{
uint8 *C;
- register uint8 cc;
- register uint8 zz2;
+ uint8 cc;
+ uint8 zz2;
uint32 vadr;
if((tochange<=0 && MMC5HackSPMode&0x40) ||
{
uint8 xs,ys;
- xs=33-X1;
+ xs=33-X1;
ys=((scanline>>3)+MMC5HackSPScroll)&0x1F;
if(ys>=0x1E) ys-=0x1E;
vadr=(MMC5HackExNTARAMPtr[xs|(ys<<5)]<<4)+(vofs&7);
RefreshAddr++;
tochange--;
}
- }
+}
+
+static void RefreshLine_MMC5Hack3(uint8 *P, uint32 vofs)
+{
+ int8 X1;
- else if(MMC5HackCHRMode==1)
- {
for(X1=33;X1;X1--,P+=8)
{
- uint8 *C;
- register uint8 cc;
- register uint8 zz2;
- uint32 vadr;
+ uint8 *C;
+ uint8 cc;
+ uint8 zz2;
+ uint32 vadr;
C=MMC5HackVROMPTR;
zz2=(RefreshAddr>>10)&3;
vadr = (vnapage[zz2][RefreshAddr & 0x3ff] << 4) + vofs;
- C += (((MMC5HackExNTARAMPtr[RefreshAddr & 0x3ff]) & 0x3f &
+ C += (((MMC5HackExNTARAMPtr[RefreshAddr & 0x3ff]) & 0x3f &
MMC5HackVROMMask) << 12) + (vadr & 0xfff);
vadr = (MMC5HackExNTARAMPtr[RefreshAddr & 0x3ff] & 0xC0)>> 4;
cc = vadr;
else
RefreshAddr++;
}
- }
- else
- {
+}
+
+static void RefreshLine_MMC5Hack4(uint8 *P, uint32 vofs)
+{
+ int8 X1;
+
for(X1=33;X1;X1--,P+=8)
{
uint8 *C;
- register uint8 cc,zz,zz2;
+ uint8 cc,zz,zz2;
uint32 vadr;
zz=RefreshAddr&0x1F;
cc=((cc >> ((zz&2) + ((RefreshAddr&0x40)>>4))) &3) <<2;
#include "fceline.h"
-
+
if((RefreshAddr&0x1f)==0x1f)
RefreshAddr^=0x41F;
else
RefreshAddr++;
- }
- }
- } // End if(MMC5Hack)
+ }
+}
+
+static void RefreshLine_PPU_hook(uint8 *P, uint32 vofs)
+{
+ int8 X1;
+ void (*PPU_hook_)(uint32 A) = PPU_hook;
+ uint32 rfraddr = RefreshAddr;
+ uint8 *page = vnapage[(rfraddr>>10)&3];
- else if(PPU_hook)
- {
for(X1=33;X1;X1--,P+=8)
{
- uint8 *C;
- register uint8 cc,zz,zz2;
- uint32 vadr;
+ uint8 *C;
+ uint8 cc,zz;
+ uint32 vadr;
- zz=RefreshAddr&0x1F;
- zz2=(RefreshAddr>>10)&3;
- PPU_hook(0x2000|(RefreshAddr&0xFFF));
- cc=vnapage[zz2][0x3c0+(zz>>2)+((RefreshAddr&0x380)>>4)];
- cc=((cc >> ((zz&2) + ((RefreshAddr&0x40)>>4))) &3) <<2;
- vadr=(vnapage[zz2][RefreshAddr&0x3ff]<<4)+vofs;
+ zz=rfraddr&0x1F;
+ PPU_hook_(0x2000|(rfraddr&0xFFF));
+ cc=page[0x3c0+(zz>>2)+((rfraddr&0x380)>>4)];
+ cc=((cc >> ((zz&2) + ((rfraddr&0x40)>>4))) &3) <<2;
+ vadr=(page[rfraddr&0x3ff]<<4)+vofs;
C = VRAMADR(vadr);
#include "fceline.h"
- PPU_hook(vadr);
+ PPU_hook_(vadr);
- if((RefreshAddr&0x1f)==0x1f)
- RefreshAddr^=0x41F;
- else
- RefreshAddr++;
+ if((rfraddr&0x1f)==0x1f) {
+ rfraddr^=0x41F;
+ page = vnapage[(rfraddr>>10)&3];
+ } else
+ rfraddr++;
}
- }
- else
- {
- for(X1=33;X1;X1--,P+=8)
+ RefreshAddr = rfraddr;
+}
+
+static void RefreshLine_normal(uint8 *P, uint32 vofs) // vofs is 0x107 max
+{
+ int8 X1;
+ uint32 rfraddr = RefreshAddr;
+ uint8 *page = vnapage[(rfraddr>>10)&3];
+ uint32 cc2=0;
+
+ if ((rfraddr&0xc)!=0)
+ cc2=*(uint32 *) (page + ((rfraddr&0x380)>>4) + ((rfraddr&0x10)>>2) + 0x3c0);
+
+ for (X1=33;X1;X1--,P+=8)
{
- uint8 *C;
- register uint8 cc,zz,zz2;
+ uint8 cc,*C;
uint32 vadr;
- zz=RefreshAddr&0x1F;
- zz2=(RefreshAddr>>10)&3;
- vadr=(vnapage[zz2][RefreshAddr&0x3ff]<<4)+vofs;
+ vadr=(page[rfraddr&0x3ff]<<4)+vofs;
C = VRAMADR(vadr);
- cc=vnapage[zz2][0x3c0+(zz>>2)+((RefreshAddr&0x380)>>4)];
- cc=((cc >> ((zz&2) + ((RefreshAddr&0x40)>>4))) &3) <<2;
- #include "fceline.h"
-
- if((RefreshAddr&0x1f)==0x1f)
- RefreshAddr^=0x41F;
- else
- RefreshAddr++;
- }
- }
+ if ((rfraddr&0xc)==0)
+ cc2=*(uint32 *) (page + ((rfraddr&0x380)>>4) + ((rfraddr&0x10)>>2) + 0x3c0);
+ cc=((cc2 >> ((rfraddr&2) + ((rfraddr&0x40)>>4) + ((rfraddr&0xc)<<1))) & 3) << 2;
- #undef vofs
+ #include "fceline.h"
- Pal[0]&=63;
- Pal[4]&=63;
- Pal[8]&=63;
- Pal[0xC]&=63;
+ if((rfraddr&0x1f)==0x1f) {
+ rfraddr^=0x41F;
+ page = vnapage[(rfraddr>>10)&3];
+ } else
+ rfraddr++;
+ }
+ RefreshAddr = rfraddr;
}
-static INLINE void Fixit2(void)
+static void SetRefreshLine(void)
+{
+ if(MMC5Hack && geniestage!=1)
+ {
+ if(MMC5HackCHRMode==0 && (MMC5HackSPMode&0x80))
+ {
+ if (RefreshLine != RefreshLine_MMC5Hack1) printf("set refr RefreshLine_MMC5Hack1\n");
+ RefreshLine = RefreshLine_MMC5Hack1;
+ }
+ else if(MMC5HackCHRMode==1 && (MMC5HackSPMode&0x80))
+ {
+ if (RefreshLine != RefreshLine_MMC5Hack2) printf("set refr RefreshLine_MMC5Hack2\n");
+ RefreshLine = RefreshLine_MMC5Hack2;
+ }
+ else if(MMC5HackCHRMode==1)
+ {
+ if (RefreshLine != RefreshLine_MMC5Hack3) printf("set refr RefreshLine_MMC5Hack3\n");
+ RefreshLine = RefreshLine_MMC5Hack3;
+ }
+ else
+ {
+ if (RefreshLine != RefreshLine_MMC5Hack4) printf("set refr RefreshLine_MMC5Hack4\n");
+ RefreshLine = RefreshLine_MMC5Hack4;
+ }
+ } // End if(MMC5Hack)
+ else if(PPU_hook)
+ {
+ if (RefreshLine != RefreshLine_PPU_hook) printf("set refr RefreshLine_PPU_hook\n");
+ RefreshLine = RefreshLine_PPU_hook;
+ }
+ else
+ {
+ if (RefreshLine != RefreshLine_normal) printf("set refr RefreshLine_normal\n");
+ RefreshLine = RefreshLine_normal;
+ }
+}
+
+static INLINE
+void Fixit2(void)
{
if(ScreenON || SpriteON)
{
}
}
-static INLINE void Fixit1(void)
+static INLINE
+void Fixit1(void)
{
if(ScreenON || SpriteON)
{
}
}
-/* This is called at the beginning of all h-blanks on visible lines. */
-static void DoHBlank(void)
-{
- if(ScreenON || SpriteON)
- FetchSpriteData();
- if(GameHBIRQHook && (ScreenON || SpriteON))
- {
- X6502_Run(12);
- GameHBIRQHook();
- X6502_Run(25-12);
- Fixit2();
- X6502_Run(85-25);
- }
- else
- {
- X6502_Run(25); // Tried 65, caused problems with Slalom(maybe others)
- Fixit2();
- X6502_Run(85-25);
- }
- //PPU_hook(0,-1);
- //fprintf(stderr,"%3d: $%04x\n",scanline,RefreshAddr);
-}
-#define V_FLIP 0x80
-#define H_FLIP 0x40
-#define SP_BACK 0x20
-
-typedef struct {
- uint8 y,no,atr,x;
-} SPR;
-
-typedef struct {
- uint8 ca[2],atr,x;
-} SPRB;
-
-uint8 sprlinebuf[256+8];
-
-void FCEUI_DisableSpriteLimitation(int a)
-{
- maxsprites=a?64:8;
-}
-
-static uint8 nosprites,SpriteBlurp;
-
-static void FetchSpriteData(void)
-{
- SPR *spr;
- uint8 H;
- int n,vofs;
-
- spr=(SPR *)SPRAM;
- H=8;
-
- nosprites=SpriteBlurp=0;
-
- vofs=(unsigned int)(PPU[0]&0x8&(((PPU[0]&0x20)^0x20)>>2))<<9;
- H+=(PPU[0]&0x20)>>2;
-
- if(!PPU_hook)
- for(n=63;n>=0;n--,spr++)
- {
- if((unsigned int)(scanline-spr->y)>=H) continue;
-
- if(nosprites<maxsprites)
- {
- if(n==63) SpriteBlurp=1;
-
- {
- SPRB dst;
- uint8 *C;
- int t;
- unsigned int vadr;
-
- t = (int)scanline-(spr->y);
-
- if (Sprite16)
- vadr = ((spr->no&1)<<12) + ((spr->no&0xFE)<<4);
- else
- vadr = (spr->no<<4)+vofs;
-
- if (spr->atr&V_FLIP)
- {
- vadr+=7;
- vadr-=t;
- vadr+=(PPU[0]&0x20)>>1;
- vadr-=t&8;
- }
- else
- {
- vadr+=t;
- vadr+=t&8;
- }
-
- /* Fix this geniestage hack */
- if(MMC5Hack && geniestage!=1) C = MMC5SPRVRAMADR(vadr);
- else C = VRAMADR(vadr);
-
-
- dst.ca[0]=C[0];
- dst.ca[1]=C[8];
- dst.x=spr->x;
- dst.atr=spr->atr;
-
-
- *(uint32 *)&SPRBUF[nosprites<<2]=*(uint32 *)&dst;
- }
-
- nosprites++;
- }
- else
- {
- PPU_status|=0x20;
- break;
- }
- }
- else
- for(n=63;n>=0;n--,spr++)
- {
- if((unsigned int)(scanline-spr->y)>=H) continue;
-
- if(nosprites<maxsprites)
- {
- if(n==63) SpriteBlurp=1;
-
- {
- SPRB dst;
- uint8 *C;
- int t;
- unsigned int vadr;
-
- t = (int)scanline-(spr->y);
-
- if (Sprite16)
- vadr = ((spr->no&1)<<12) + ((spr->no&0xFE)<<4);
- else
- vadr = (spr->no<<4)+vofs;
-
- if (spr->atr&V_FLIP)
- {
- vadr+=7;
- vadr-=t;
- vadr+=(PPU[0]&0x20)>>1;
- vadr-=t&8;
- }
- else
- {
- vadr+=t;
- vadr+=t&8;
- }
-
- if(MMC5Hack) C = MMC5SPRVRAMADR(vadr);
- else C = VRAMADR(vadr);
- dst.ca[0]=C[0];
- PPU_hook(vadr);
- dst.ca[1]=C[8];
- PPU_hook(vadr|8);
- dst.x=spr->x;
- dst.atr=spr->atr;
-
-
- *(uint32 *)&SPRBUF[nosprites<<2]=*(uint32 *)&dst;
- }
-
- nosprites++;
- }
- else
- {
- PPU_status|=0x20;
- break;
- }
- }
-}
-
-static void FASTAPASS(1) RefreshSprite(uint8 *target)
-{
- int n;
- SPRB *spr;
- uint8 *P=target;
-
- if(!nosprites) return;
- #ifdef FRAMESKIP
- if(FSkip)
- {
- if(!SpriteBlurp)
- {
- nosprites=0;
- return;
- }
- else
- nosprites=1;
- }
- #endif
-
- FCEU_dwmemset(sprlinebuf,0x80808080,256);
- nosprites--;
- spr = (SPRB*)SPRBUF+nosprites;
-
- for(n=nosprites;n>=0;n--,spr--)
- {
- register uint8 J,atr,c1,c2;
- int x=spr->x;
- uint8 *C;
- uint8 *VB;
-
- P+=x;
-
- c1=((spr->ca[0]>>1)&0x55)|(spr->ca[1]&0xAA);
- c2=(spr->ca[0]&0x55)|((spr->ca[1]<<1)&0xAA);
-
- J=spr->ca[0]|spr->ca[1];
- atr=spr->atr;
-
- if(J)
- {
- if(n==0 && SpriteBlurp && !(PPU_status&0x40))
- {
- int z,ze=x+8;
- if(ze>256) {ze=256;}
- if(ScreenON && (scanline<FSettings.FirstSLine || scanline>FSettings.LastSLine
- #ifdef FRAMESKIP
- || FSkip
- #endif
- ))
- BGRender(target);
-
- if(!(atr&H_FLIP))
- {
- for(z=x;z<ze;z++)
- {
- if(J&(0x80>>(z-x)))
- {
- if(!(target[z]&64))
- tosprite=z;
- }
- }
- }
- else
- {
- for(z=x;z<ze;z++)
- {
- if(J&(1<<(z-x)))
- {
- if(!(target[z]&64))
- tosprite=z;
- }
- }
- }
- //FCEU_DispMessage("%d, %d:%d",scanline,x,tosprite);
- }
-
- C = sprlinebuf+x;
- VB = (PALRAM+0x10)+((atr&3)<<2);
-
- if(atr&SP_BACK)
- {
- if (atr&H_FLIP)
- {
- if (J&0x02) C[1]=VB[c1&3]|0x40;
- if (J&0x01) *C=VB[c2&3]|0x40;
- c1>>=2;c2>>=2;
- if (J&0x08) C[3]=VB[c1&3]|0x40;;
- if (J&0x04) C[2]=VB[c2&3]|0x40;;
- c1>>=2;c2>>=2;
- if (J&0x20) C[5]=VB[c1&3]|0x40;;
- if (J&0x10) C[4]=VB[c2&3]|0x40;;
- c1>>=2;c2>>=2;
- if (J&0x80) C[7]=VB[c1]|0x40;;
- if (J&0x40) C[6]=VB[c2]|0x40;;
- } else {
- if (J&0x02) C[6]=VB[c1&3]|0x40;
- if (J&0x01) C[7]=VB[c2&3]|0x40;
- c1>>=2;c2>>=2;
- if (J&0x08) C[4]=VB[c1&3]|0x40;
- if (J&0x04) C[5]=VB[c2&3]|0x40;
- c1>>=2;c2>>=2;
- if (J&0x20) C[2]=VB[c1&3]|0x40;
- if (J&0x10) C[3]=VB[c2&3]|0x40;
- c1>>=2;c2>>=2;
- if (J&0x80) *C=VB[c1]|0x40;
- if (J&0x40) C[1]=VB[c2]|0x40;
- }
- } else {
- if (atr&H_FLIP)
- {
- if (J&0x02) C[1]=VB[(c1&3)];
- if (J&0x01) *C=VB[(c2&3)];
- c1>>=2;c2>>=2;
- if (J&0x08) C[3]=VB[(c1&3)];
- if (J&0x04) C[2]=VB[(c2&3)];
- c1>>=2;c2>>=2;
- if (J&0x20) C[5]=VB[(c1&3)];
- if (J&0x10) C[4]=VB[(c2&3)];
- c1>>=2;c2>>=2;
- if (J&0x80) C[7]=VB[c1];
- if (J&0x40) C[6]=VB[c2];
- }else{
- if (J&0x02) C[6]=VB[(c1&3)];
- if (J&0x01) C[7]=VB[(c2&3)];
- c1>>=2;c2>>=2;
- if (J&0x08) C[4]=VB[(c1&3)];
- if (J&0x04) C[5]=VB[(c2&3)];
- c1>>=2;c2>>=2;
- if (J&0x20) C[2]=VB[(c1&3)];
- if (J&0x10) C[3]=VB[(c2&3)];
- c1>>=2;c2>>=2;
- if (J&0x80) *C=VB[c1];
- if (J&0x40) C[1]=VB[c2];
- }
- }
- }
- P-=x;
- }
-
- nosprites=0;
- #ifdef FRAMESKIP
- if(FSkip) return;
- #endif
-
- {
- uint8 n=((PPU[1]&4)^4)<<1;
- loopskie:
- {
- uint32 t=*(uint32 *)(sprlinebuf+n);
- if(t!=0x80808080)
- {
- #ifdef LSB_FIRST
- if(!(t&0x80))
- {
- if(!(t&0x40)) // Normal sprite
- P[n]=sprlinebuf[n];
- else if(P[n]&64) // behind bg sprite
- P[n]=sprlinebuf[n];
- }
-
- if(!(t&0x8000))
- {
- if(!(t&0x4000)) // Normal sprite
- P[n+1]=(sprlinebuf+1)[n];
- else if(P[n+1]&64) // behind bg sprite
- P[n+1]=(sprlinebuf+1)[n];
- }
-
- if(!(t&0x800000))
- {
- if(!(t&0x400000)) // Normal sprite
- P[n+2]=(sprlinebuf+2)[n];
- else if(P[n+2]&64) // behind bg sprite
- P[n+2]=(sprlinebuf+2)[n];
- }
-
- if(!(t&0x80000000))
- {
- if(!(t&0x40000000)) // Normal sprite
- P[n+3]=(sprlinebuf+3)[n];
- else if(P[n+3]&64) // behind bg sprite
- P[n+3]=(sprlinebuf+3)[n];
- }
- #else
- if(!(t&0x80000000))
- {
- if(!(t&0x40)) // Normal sprite
- P[n]=sprlinebuf[n];
- else if(P[n]&64) // behind bg sprite
- P[n]=sprlinebuf[n];
- }
-
- if(!(t&0x800000))
- {
- if(!(t&0x4000)) // Normal sprite
- P[n+1]=(sprlinebuf+1)[n];
- else if(P[n+1]&64) // behind bg sprite
- P[n+1]=(sprlinebuf+1)[n];
- }
-
- if(!(t&0x8000))
- {
- if(!(t&0x400000)) // Normal sprite
- P[n+2]=(sprlinebuf+2)[n];
- else if(P[n+2]&64) // behind bg sprite
- P[n+2]=(sprlinebuf+2)[n];
- }
-
- if(!(t&0x80))
- {
- if(!(t&0x40000000)) // Normal sprite
- P[n+3]=(sprlinebuf+3)[n];
- else if(P[n+3]&64) // behind bg sprite
- P[n+3]=(sprlinebuf+3)[n];
- }
- #endif
- }
- }
- n+=4;
- if(n) goto loopskie;
- }
-}
+// ============================//
+// end of new code
+// ===========================//
void ResetMapping(void)
{
int GameLoaded=0;
void CloseGame(void)
{
+ FCEUI_StopMovie();
if(GameLoaded)
{
if(FCEUGameInfo.type!=GIT_NSF)
- FlushGameCheats();
+ FCEU_FlushGameCheats(0,0);
#ifdef NETWORK
if(FSettings.NetworkPlay) KillNetplay();
- #endif
- GameInterface(GI_CLOSE);
+ #endif
+ GameInterface(GI_CLOSE, 0);
CloseGenie();
GameLoaded=0;
}
if(GameLoaded) CloseGame();
GameStateRestore=0;
PPU_hook=0;
- GameHBIRQHook=0;
+ GameHBIRQHook=GameHBIRQHook2=0;
GameExpSound.Fill=0;
GameExpSound.RChange=0;
if(GameExpSound.Kill)
FCEUGameInfo.vidsys=GIV_USER;
FCEUGameInfo.input[0]=FCEUGameInfo.input[1]=-1;
FCEUGameInfo.inputfc=-1;
+
+ FCEUGameInfo.soundchan=0;
+ FCEUGameInfo.soundrate=0;
+ FCEUGameInfo.cspecial=0;
}
+char lastLoadedGameName [2048];
+int LoadGameLastError = 0;
+int UNIFLoad(const char *name, int fp);
+int iNESLoad(const char *name, int fp);
+int FDSLoad(const char *name, int fp);
+int NSFLoad(int fp);
+
FCEUGI *FCEUI_LoadGame(char *name)
{
+ char name2[512];
+ int have_movie = 0, have_ips = 0;
int fp;
- Exit=1;
+ //Exit=1;
+ LoadGameLastError = 0;
ResetGameLoaded();
- fp=FCEU_fopen(name,"rb");
+ strncpy(name2, name, sizeof(name2));
+ name2[sizeof(name2)-1] = 0;
+
+ fp=FCEU_fopen(name2,"rb");
if(!fp)
{
FCEU_PrintError("Error opening \"%s\"!",name);
+ LoadGameLastError = 1;
return 0;
}
- GetFileBase(name);
- if(iNESLoad(name,fp))
+ {
+ char *p = name2 + strlen(name2) - 4;
+ if (strcasecmp(p, ".fcm") == 0) printf("movie detected\n"), have_movie = 1;
+ if (strcasecmp(p, ".ips") == 0) printf("ips detected\n"), have_ips = 1;
+ if (have_movie || have_ips)
+ {
+ // movie detected
+ FCEU_fclose(fp);
+ *p = 0;
+ fp=FCEU_fopen(name2,"rb");
+ if (!fp && p - name2 > 2)
+ {
+ for (p--; p > name2 && *p != '.'; p--);
+ *p = 0;
+ fp=FCEU_fopen(name2,"rb");
+ }
+ if (!fp) {
+ printf("no ROM for ips/movie\n");
+ LoadGameLastError = 2;
+ return 0;
+ }
+ }
+ }
+
+ // do IPS patch
+ if (have_ips)
+ {
+ FCEU_fclose(fp);
+ FILE *ips = fopen(name, "rb");
+ if (!ips) return 0;
+ fp=FCEU_fopen_forcemem(name2);
+ if (!fp) { fclose(ips); return 0; }
+ ApplyIPS(ips, fp); // closes ips
+ }
+
+ GetFileBase(name2);
+ if(iNESLoad(name2,fp))
goto endlseq;
if(NSFLoad(fp))
goto endlseq;
- if(FDSLoad(name,fp))
+ if(FDSLoad(name2,fp))
goto endlseq;
- if(UNIFLoad(name,fp))
+ if(UNIFLoad(name2,fp))
goto endlseq;
FCEU_PrintError("An error occurred while loading the file.");
FCEU_fclose(fp);
+ // format handlers may set LoadGameLastError themselves.
+ if (LoadGameLastError == 0) LoadGameLastError = 3;
return 0;
endlseq:
FCEU_fclose(fp);
- GameLoaded=1;
+ GameLoaded=1;
FCEU_ResetVidSys();
if(FCEUGameInfo.type!=GIT_NSF)
SaveStateRefresh();
if(FCEUGameInfo.type!=GIT_NSF)
{
- LoadGamePalette();
- LoadGameCheats();
+ FCEU_LoadGamePalette();
+ FCEU_LoadGameCheats(0);
}
-
+
FCEU_ResetPalette();
Exit=0;
+
+ if (have_movie)
+ FCEUI_LoadMovie(name, 1);
+
+ strcpy(lastLoadedGameName, name2);
+
return(&FCEUGameInfo);
}
if(w)
{
PAL=1;
- scanlines_per_frame=312;
FSettings.FirstSLine=FSettings.UsrFirstSLine[1];
FSettings.LastSLine=FSettings.UsrLastSLine[1];
}
else
{
PAL=0;
- scanlines_per_frame=262;
FSettings.FirstSLine=FSettings.UsrFirstSLine[0];
FSettings.LastSLine=FSettings.UsrLastSLine[0];
}
+ printf("ResetVidSys: PAL = %i\n", PAL);
SetSoundVariables();
}
FSettings.UsrFirstSLine[0]=8;
FSettings.UsrFirstSLine[1]=0;
FSettings.UsrLastSLine[0]=FSettings.UsrLastSLine[1]=239;
- FSettings.SoundVolume=65536; // 100%
+ FSettings.SoundVolume=100;
+
+ FCEUI_Initialize098();
+ FCEUI_SetEmuMode(0);
+
return 1;
}
-#define harko 0xe //0x9
-static INLINE void Thingo(void)
+void FCEUI_Kill(void)
{
- Loop6502();
+ FCEU_KillGenie();
+}
+
+static void EmLoop(void);
- if(tosprite>=256)
- {
- X6502_Run(256-harko);
- Fixit1();
- X6502_Run(harko);
+int use098code = 0;
+void (*ResetNES)(void) = 0;
+void (*FCEUI_Emulate)(void) = 0;
+
+void FCEUI_SetEmuMode(int is_new)
+{
+ use098code = is_new;
+ if (is_new)
+ {
+ ResetNES=ResetNES098;
+ FCEUI_Emulate=FCEUI_Emulate098;
}
else
{
- if(tosprite<=240)
- {
- X6502_Run(tosprite);
- PPU[2]|=0x40;
- X6502_Run(256-tosprite-harko);
- Fixit1();
- X6502_Run(harko);
- }
- else
- {
- X6502_Run(256-harko);
- Fixit1();
- X6502_Run(tosprite-(256-harko));
- PPU[2]|=0x40;
- X6502_Run(256-tosprite);
- }
- tosprite=256;
+ ResetNES=ResetNES081;
+ FCEUI_Emulate=EmLoop;
}
- DoHBlank();
}
-#undef harko
-void EmLoop(void)
+void MMC5_hb(int); /* Ugh ugh ugh. */
+static void DoLine(void)
+{
+ uint8 *target=XBuf+scanline*320+32;
+
+ LineUpdate(target);
+
+ if(MMC5Hack && (ScreenON || SpriteON)) MMC5_hb(scanline);
+
+ X6502_Run(256);
+
+ // check: Battletoads & Double Dragon, Addams Family
+ // sky glitches in SMB1 if done wrong
+ FakedLineUpdate();
+
+#ifdef FRAMESKIP
+ if(!FSkip)
+#endif
+ if(scanline>=FSettings.FirstSLine && scanline<=FSettings.LastSLine)
+ {
+ if(SpriteON && spork)
+ CopySprites(target);
+
+ LineUpdateEnd(target);
+ }
+ sphitx=0x100;
+
+ if(ScreenON || SpriteON)
+ FetchSpriteData();
+
+ // DoHBlank();
+ if(GameHBIRQHook && (ScreenON || SpriteON) && ((PPU[0]&0x38)!=0x18))
+ {
+ X6502_Run(6);
+ Fixit2();
+ X6502_Run(4);
+ GameHBIRQHook();
+ X6502_Run(85-10-16);
+ }
+ else
+ {
+ X6502_Run(6); // Tried 65, caused problems with Slalom(maybe others)
+ Fixit2();
+ X6502_Run(85-6-16);
+ }
+
+ if(SpriteON)
+ RefreshSprites();
+ if(GameHBIRQHook2 && (ScreenON || SpriteON))
+ GameHBIRQHook2();
+ scanline++;
+ if (scanline<240)
+ ResetRL(XBuf+scanline*320+32);
+ X6502_Run(16);
+}
+
+
+static void EmLoop(void)
{
for(;;)
{
- ApplyPeriodicCheats();
+ int x;
+ uint32 scanlines_per_frame = PAL ? 312 : 262;
+ UpdateInput();
+ FCEU_ApplyPeriodicCheats();
+
+ // FCEUPPU_Loop:
+ if(ppudead) /* Needed for Knight Rider, possibly others. */
+ {
+ //memset(XBuf, 0, 320*240);
+ //X6502_Run(scanlines_per_frame*(256+85));
+ int lines;
+ for (lines=scanlines_per_frame;lines;lines--)
+ X6502_Run(256+85);
+ ppudead--;
+ goto update;
+ }
+
X6502_Run(256+85);
PPU[2]|=0x80;
breaks a Super Donkey Kong game. */
X6502_Run(12); /* I need to figure out the true nature and length
- of this delay.
+ of this delay.
*/
if(FCEUGameInfo.type==GIT_NSF)
- TriggerNMINSF();
+ DoNSFFrame();
else if(VBlankON)
TriggerNMI();
- X6502_Run((scanlines_per_frame-242)*(256+85)-12);
-
+ // Note: this is needed for asm core
+ // Warning: using 'scanline' var here breaks Castlevania III
+ {
+ int lines;
+ X6502_Run(256+85-12);
+ for (lines=scanlines_per_frame-242-1;lines;lines--)
+ X6502_Run(256+85);
+ }
+ // X6502_Run((scanlines_per_frame-242)*(256+85)-12);
PPU_status&=0x1f;
-
X6502_Run(256);
+
{
- static int kook=0;
if(ScreenON || SpriteON)
+ {
if(GameHBIRQHook)
GameHBIRQHook();
+ if(PPU_hook)
+ for(x=0;x<42;x++) {PPU_hook(0x2000); PPU_hook(0);} // ugh
+ if(GameHBIRQHook2)
+ GameHBIRQHook2();
+ }
+
+ X6502_Run(85-16);
+
+ if(ScreenON || SpriteON)
+ {
+ RefreshAddr=TempAddr;
+ if(PPU_hook) PPU_hook(RefreshAddr&0x3fff);
+ }
+ spork=0;
+ ResetRL(XBuf+32);
- X6502_Run(85-kook);
- kook=(kook+1)&1;
+ X6502_Run(16-kook);
+ kook ^= 1;
}
- if(ScreenON || SpriteON)
+ if(FCEUGameInfo.type==GIT_NSF)
{
- RefreshAddr=TempAddr;
- if(PPU_hook) PPU_hook(RefreshAddr&0x3fff);
+ // run scanlines for asm core to fuction
+ for(scanline=0;scanline<240;scanline++)
+ X6502_Run(256+85);
}
- if(FCEUGameInfo.type==GIT_NSF)
- X6502_Run((256+85)*240);
else
{
int x,max,maxref;
deemp=PPU[1]>>5;
- for(scanline=0;scanline<240;scanline++)
+ SetRefreshLine();
+ for(scanline=0;scanline<240;) // scanline is incremented in DoLine. Evil. :/
{
deempcnt[deemp]++;
- Thingo();
+ DoLine();
}
+ if(MMC5Hack && (ScreenON || SpriteON)) MMC5_hb(scanline);
for(x=1,max=0,maxref=0;x<7;x++)
{
if(deempcnt[x]>max)
}
deempcnt[x]=0;
}
- //FCEU_DispMessage("%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x %d",deempcnt[0],deempcnt[1],deempcnt[2],deempcnt[3],deempcnt[4],deempcnt[5],deempcnt[6],deempcnt[7],maxref);
- //memset(deempcnt,0,sizeof(deempcnt));
SetNESDeemph(maxref,0);
}
+update:
+ if(Exit)
+ {
+ //CloseGame();
+ break;
+ }
+
{
int ssize;
ssize=FlushEmulateSound();
+ timestampbase += timestamp;
+ timestamp = 0;
+
#ifdef FRAMESKIP
if(FSkip)
{
FCEU_PutImageDummy();
FSkip--;
- FCEUD_Update(0,WaveFinal,ssize);
+ FCEUD_Update(0,WaveFinalMono,ssize);
}
else
#endif
{
FCEU_PutImage();
- FCEUD_Update(XBuf+8,WaveFinal,ssize);
+ FCEUD_Update(XBuf+8,WaveFinalMono,ssize);
}
- UpdateInput();
- }
-
- if(Exit)
- {
- CloseGame();
- break;
}
- }
-}
-
-#ifdef FPS
-#include <sys/time.h>
-uint64 frcount;
-#endif
-void FCEUI_Emulate(void)
-{
- #ifdef FPS
- uint64 starttime,end;
- struct timeval tv;
- frcount=0;
- gettimeofday(&tv,0);
- starttime=((uint64)tv.tv_sec*1000000)+tv.tv_usec;
- #endif
- EmLoop();
-
- #ifdef FPS
- // Probably won't work well on Windows port; for
- // debugging/speed testing.
- {
- uint64 w;
- int i,frac;
- gettimeofday(&tv,0);
- end=((uint64)tv.tv_sec*1000000)+tv.tv_usec;
- w=frcount*10000000000LL/(end-starttime);
- i=w/10000;
- frac=w-i*10000;
- printf("Average FPS: %d.%04d\n",i,frac);
- }
- #endif
-
+ } // for
}
void FCEUI_CloseGame(void)
PPUGenLatch=0;
RefreshAddr=TempAddr=0;
vtoggle = 0;
+ ppudead = 2;
+ kook = 0;
}
static void PowerPPU(void)
ResetPPU();
}
-void ResetNES(void)
+void ResetNES081(void)
{
- if(!GameLoaded || (FCEUGameInfo.type==GIT_NSF)) return;
- GameInterface(GI_RESETM2);
+ if(!GameLoaded) return;
+ GameInterface(GI_RESETM2, 0);
ResetSound();
ResetPPU();
X6502_Reset();
}
-void PowerNES(void)
+#ifndef DEBUG_ASM_6502
+static void FCEU_MemoryRand(uint8 *ptr, uint32 size)
+{
+ int x=0;
+ while(size)
+ {
+ *ptr=(x&4)?0xFF:0x00;
+ x++;
+ size--;
+ ptr++;
+ }
+}
+#endif
+
+void PowerNES(void)
{
if(!GameLoaded) return;
GeniePower();
+#ifndef DEBUG_ASM_6502
+ FCEU_MemoryRand(RAM,0x800);
+#else
memset(RAM,0x00,0x800);
+ memset(nes_internal_ram,0x00,0x800);
+#endif
ResetMapping();
- GameInterface(GI_POWER);
PowerSound();
PowerPPU();
+
+ if (use098code)
+ FCEUPPU_Power();
+
+ /* Have the external game hardware "powered" after the internal NES stuff.
+ Needed for the NSF code and VS System code.
+ */
+ GameInterface(GI_POWER, 0);
+ if(FCEUGameInfo.type==GIT_VSUNI)
+ FCEU_VSUniPower();
+#ifdef ASM_6502
+ if (geniestage)
+ GenieSetPages(0);
+#endif
timestampbase=0;
X6502_Power();
+ FCEU_PowerCheats();
}
+
+/* savestate stuff */
+uint16 TempAddrT,RefreshAddrT;
+
+SFORMAT FCEUPPU_STATEINFO[]={
+ { NTARAM, 0x800, "NTAR"},
+ { PALRAM, 0x20, "PRAM"},
+ { SPRAM, 0x100, "SPRA"},
+ { PPU, 0x4, "PPUR"},
+ { &XOffset, 1, "XOFF"},
+ { &vtoggle, 1, "VTOG"},
+ { &RefreshAddrT, 2|RLSB, "RADD"},
+ { &TempAddrT, 2|RLSB, "TADD"},
+ { &VRAMBuffer, 1, "VBUF"},
+ { &PPUGenLatch, 1, "PGEN"},
+ // from 0.98.15
+ { &kook, 1, "KOOK"},
+ { &ppudead, 1, "DEAD"},
+ { &PPUSPL, 1, "PSPL"},
+ { 0 }
+ };
+
+