From: notaz Date: Sun, 17 Jun 2007 19:11:07 +0000 (+0000) Subject: 098 renderer added X-Git-Tag: r1~22 X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6244011fd85a10400accd6d8e7d941144f92aa5b;p=fceu.git 098 renderer added git-svn-id: file:///home/notaz/opt/svn/fceu@166 be3aeb3a-fb24-0410-a615-afba39da0efa --- diff --git a/Makefile.gp2x b/Makefile.gp2x index 05908ae..fe002c1 100644 --- a/Makefile.gp2x +++ b/Makefile.gp2x @@ -30,7 +30,8 @@ include zlib/Makefile OBJDRIVER = ${B}minimal.o ${B}cpuctrl.o ${B}squidgehack.o ${B}asmutils.o ${B}gp2x.o ${B}main.o ${B}throttle.o \ ${B}unix-netplay.o ${B}gp2x-sound.o ${B}gp2x-video.o ${B}usbjoy.o ${B}menu.o ${B}fonts.o ${B}readpng.o \ - drivers/common/cheat.o drivers/common/config.o drivers/common/args.o drivers/common/vidblit.o ${UNZIPOBJS} ppu.o movie.o + drivers/common/cheat.o drivers/common/config.o drivers/common/args.o drivers/common/vidblit.o ${UNZIPOBJS} \ + ppu.o movie.o fceu098.o ppu098.o LDRIVER += -lm -lz -lpng -static -Wl,-Map=fceu.map ifeq ($(asm_6502),1) diff --git a/Makefile.gp2x_test b/Makefile.gp2x_test index 75df487..94414bb 100644 --- a/Makefile.gp2x_test +++ b/Makefile.gp2x_test @@ -29,7 +29,8 @@ include zlib/Makefile OBJDRIVER = drivers/gp2x_test/minimal.o drivers/gp2x_test/throttle.o ${B}gp2x.o ${B}main.o \ ${B}unix-netplay.o ${B}gp2x-sound.o ${B}gp2x-video.o ${B}usbjoy.o ${B}menu.o ${B}fonts.o ${B}readpng.o \ - drivers/common/cheat.o drivers/common/config.o drivers/common/args.o drivers/common/vidblit.o ${UNZIPOBJS} ppu.o movie.o + drivers/common/cheat.o drivers/common/config.o drivers/common/args.o drivers/common/vidblit.o ${UNZIPOBJS} \ + ppu.o movie.o fceu098.o ppu098.o LDRIVER += -lm -lz -lpng `sdl-config --libs` OBJDRIVER += x6502.o diff --git a/cart.c b/cart.c index 0dd8fee..b159f39 100644 --- a/cart.c +++ b/cart.c @@ -29,6 +29,7 @@ #include "types.h" #include "fce.h" #include "ppu.h" +#include "ppu098.h" #include "cart.h" #include "memory.h" @@ -39,8 +40,6 @@ #include "svga.h" #include "file.h" -#define FCEUPPU_LineUpdate(...) - /* This file contains all code for coordinating the mapping in of the address space external to the NES. diff --git a/driver.h b/driver.h index 1d47e50..ed321fd 100644 --- a/driver.h +++ b/driver.h @@ -109,8 +109,11 @@ extern int LoadGameLastError; /* allocates memory. 0 on failure, 1 on success. */ int FCEUI_Initialize(void); +void FCEUI_Kill(void); +void FCEUI_SetEmuMode(int is_new); + /* begins emulation. Returns after FCEUI_CloseGame() is called */ -void FCEUI_Emulate(void); +extern void (*FCEUI_Emulate)(void); /* Closes currently loaded game, causes FCEUI_Emulate to return */ void FCEUI_CloseGame(void); diff --git a/drivers/gp2x/gp2x.h b/drivers/gp2x/gp2x.h index 20cadd5..b0861a9 100644 --- a/drivers/gp2x/gp2x.h +++ b/drivers/gp2x/gp2x.h @@ -16,6 +16,7 @@ typedef struct { int ramtimings; int gamma; int perfect_vsync; + int accurate_mode; } DSETTINGS; extern DSETTINGS Settings; diff --git a/drivers/gp2x/main.c b/drivers/gp2x/main.c index 92094c0..b15098c 100644 --- a/drivers/gp2x/main.c +++ b/drivers/gp2x/main.c @@ -379,11 +379,12 @@ int CLImain(int argc, char *argv[]) { if (fceugi) CloseGame(); + LoadConfig(lastLoadedGameName); + FCEUI_SetEmuMode(Settings.accurate_mode); fceugi=FCEUI_LoadGame(lastLoadedGameName); if (fceugi) { char infostring[32]; - LoadConfig(lastLoadedGameName); if (Settings.region_force) FCEUI_SetVidSystem(Settings.region_force - 1); ParseGI(fceugi); @@ -438,6 +439,7 @@ int CLImain(int argc, char *argv[]) CloseGame(); SaveLLGN(); + FCEUI_Kill(); DriverKill(); return 0; } diff --git a/drivers/gp2x/menu.c b/drivers/gp2x/menu.c index 11cca13..aef6a93 100644 --- a/drivers/gp2x/menu.c +++ b/drivers/gp2x/menu.c @@ -1058,7 +1058,7 @@ static void fcemenu_loop_options(void) static void draw_menu_options(int menu_sel) { - int tl_x = 25, tl_y = 32, y; + int tl_x = 25, tl_y = 20, y; char strframeskip[8], *strscaling, *strssconfirm; char *mms = mmuhack_status ? "active) " : "inactive)"; @@ -1084,26 +1084,35 @@ static void draw_menu_options(int menu_sel) gp2x_text_out15(tl_x, y, "Scaling: %s", strscaling); // 0 gp2x_text_out15(tl_x, (y+=10), "Show FPS %s", Settings.showfps?"ON":"OFF"); // 1 gp2x_text_out15(tl_x, (y+=10), "Frameskip %s", strframeskip); // 2 + gp2x_text_out15(tl_x, (y+=10), "Accurate mode (slow) %s", Settings.accurate_mode?"ON":"OFF"); gp2x_text_out15(tl_x, (y+=10), "Enable sound %s", soundvol?"ON":"OFF"); - gp2x_text_out15(tl_x, (y+=10), "Sound Rate: %5iHz", Settings.sound_rate); // 4 + gp2x_text_out15(tl_x, (y+=10), "Sound Rate: %5iHz", Settings.sound_rate); // 5 gp2x_text_out15(tl_x, (y+=10), "Force Region: %s", - Settings.region_force == 2 ? "PAL" : Settings.region_force == 1 ? "NTSC" : "OFF"); // 5 + Settings.region_force == 2 ? "PAL" : Settings.region_force == 1 ? "NTSC" : "OFF"); // 6 gp2x_text_out15(tl_x, (y+=10), "Turbo rate %iHz", (Settings.turbo_rate_add*60/2) >> 24); - gp2x_text_out15(tl_x, (y+=10), "Confirm savestate %s", strssconfirm); // 7 + gp2x_text_out15(tl_x, (y+=10), "Confirm savestate %s", strssconfirm); // 8 gp2x_text_out15(tl_x, (y+=10), "Save slot %i", CurrentState); gp2x_text_out15(tl_x, (y+=10), "Faster RAM timings %s", Settings.ramtimings?"ON":"OFF"); - gp2x_text_out15(tl_x, (y+=10), "squidgehack (now %s %s", mms, Settings.mmuhack?"ON":"OFF"); // 10 + gp2x_text_out15(tl_x, (y+=10), "squidgehack (now %s %s", mms, Settings.mmuhack?"ON":"OFF"); // 11 gp2x_text_out15(tl_x, (y+=10), "Gamma correction %i.%02i", Settings.gamma / 100, Settings.gamma%100); gp2x_text_out15(tl_x, (y+=10), "Perfect VSYNC %s", Settings.perfect_vsync?"ON":"OFF"); - gp2x_text_out15(tl_x, (y+=10), "GP2X CPU clock %iMhz", Settings.cpuclock); // 13 + gp2x_text_out15(tl_x, (y+=10), "GP2X CPU clock %iMhz", Settings.cpuclock); // 14 gp2x_text_out15(tl_x, (y+=10), "[FCE Ultra options]"); - gp2x_text_out15(tl_x, (y+=10), "Save cfg as default"); // 15 + gp2x_text_out15(tl_x, (y+=10), "Save cfg as default"); // 16 if (fceugi) gp2x_text_out15(tl_x, (y+=10), "Save cfg for current game only"); // draw cursor gp2x_text_out15(tl_x - 16, tl_y + menu_sel*10, ">"); + if (menu_sel == 3) { + gp2x_text_out15(tl_x, 210, "Must reload ROM for this"); + gp2x_text_out15(tl_x, 220, "setting to take effect"); + } else if (menu_sel == 10 || menu_sel == 11) { + gp2x_text_out15(tl_x, 210, "Must restart emu for this"); + gp2x_text_out15(tl_x, 220, "setting to take effect"); + } + menu_darken_text_bg(); menu_flip(); } @@ -1130,7 +1139,7 @@ static void config_commit(void) static int menu_loop_options(void) { static int menu_sel = 0; - int menu_sel_max = 15; + int menu_sel_max = 16; unsigned long inp = 0; if (fceugi) menu_sel_max++; @@ -1143,17 +1152,18 @@ static int menu_loop_options(void) if(inp & GP2X_DOWN) { menu_sel++; if (menu_sel > menu_sel_max) menu_sel = 0; } if((inp& GP2X_B)||(inp&GP2X_LEFT)||(inp&GP2X_RIGHT)) { // toggleable options switch (menu_sel) { - case 1: Settings.showfps = !Settings.showfps; break; - case 3: soundvol = soundvol ? 0 : 50; break; - case 9: Settings.ramtimings = !Settings.ramtimings; break; - case 10: Settings.mmuhack = !Settings.mmuhack; break; - case 12: Settings.perfect_vsync = !Settings.perfect_vsync; break; - case 14: fcemenu_loop_options(); break; - case 15: // done (update and write) + case 1: Settings.showfps = !Settings.showfps; break; + case 3: Settings.accurate_mode = !Settings.accurate_mode; break; + case 4: soundvol = soundvol ? 0 : 50; break; + case 10: Settings.ramtimings = !Settings.ramtimings; break; + case 11: Settings.mmuhack = !Settings.mmuhack; break; + case 13: Settings.perfect_vsync = !Settings.perfect_vsync; break; + case 15: fcemenu_loop_options(); break; + case 16: // done (update and write) config_commit(); SaveConfig(NULL); return 1; - case 16: // done (update and write for current game) + case 17: // done (update and write for current game) config_commit(); if (lastLoadedGameName[0]) SaveConfig(lastLoadedGameName); @@ -1168,21 +1178,21 @@ static int menu_loop_options(void) switch (menu_sel) { case 0: int_incdec(&Settings.scaling, (inp & GP2X_LEFT) ? -1 : 1, 0, 3); break; case 2: int_incdec(&Settings.frameskip, (inp & GP2X_LEFT) ? -1 : 1, -1, 32); break; - case 4: + case 5: Settings.sound_rate = sndrate_prevnext(Settings.sound_rate, inp & GP2X_RIGHT); InitSound(); break; - case 5: int_incdec(&Settings.region_force, (inp & GP2X_LEFT) ? -1 : 1, 0, 2); break; - case 6: { + case 6: int_incdec(&Settings.region_force, (inp & GP2X_LEFT) ? -1 : 1, 0, 2); break; + case 7: { int hz = Settings.turbo_rate_add*60/2 >> 24; int_incdec(&hz, (inp & GP2X_LEFT) ? -1 : 1, 1, 30); Settings.turbo_rate_add = (hz*2 << 24) / 60 + 1; break; } - case 7: int_incdec(&Settings.sstate_confirm, (inp & GP2X_LEFT) ? -1 : 1, 0, 3); break; - case 8: int_incdec(&CurrentState, (inp & GP2X_LEFT) ? -1 : 1, 0, 9); break; - case 11: int_incdec(&Settings.gamma, (inp & GP2X_LEFT) ? -1 : 1, 0, 300); break; - case 13: + case 8: int_incdec(&Settings.sstate_confirm, (inp & GP2X_LEFT) ? -1 : 1, 0, 3); break; + case 9: int_incdec(&CurrentState, (inp & GP2X_LEFT) ? -1 : 1, 0, 9); break; + case 12: int_incdec(&Settings.gamma, (inp & GP2X_LEFT) ? -1 : 1, 0, 300); break; + case 14: while ((inp = gp2x_joystick_read(1)) & (GP2X_LEFT|GP2X_RIGHT)) { Settings.cpuclock += (inp & GP2X_LEFT) ? -1 : 1; if (Settings.cpuclock < 0) Settings.cpuclock = 0; // 0 ~ do not change diff --git a/fce.c b/fce.c index 89a54a3..2e4af6d 100644 --- a/fce.c +++ b/fce.c @@ -26,6 +26,7 @@ #include "types.h" #include "x6502.h" #include "fce.h" +#include "fceu098.h" #include "sound.h" #include "svga.h" #include "netplay.h" @@ -69,8 +70,8 @@ static void PowerPPU(void); uint64 timestampbase=0; -static int ppudead=1; -static int kook=0; +int ppudead=1; +int kook=0; int MMC5Hack; uint32 MMC5HackVROMMask; @@ -1097,6 +1098,10 @@ void ResetGameLoaded(void) 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]; @@ -1246,9 +1251,40 @@ int FCEUI_Initialize(void) FSettings.UsrFirstSLine[1]=0; FSettings.UsrLastSLine[0]=FSettings.UsrLastSLine[1]=239; FSettings.SoundVolume=100; + + FCEUI_Initialize098(); + FCEUI_SetEmuMode(0); + return 1; } +void FCEUI_Kill(void) +{ + FCEU_KillGenie(); +} + +static void EmLoop(void); + +void (*ResetNES)(void) = 0; +void (*PowerNES)(void) = 0; +void (*FCEUI_Emulate)(void) = 0; + +void FCEUI_SetEmuMode(int is_new) +{ + if (is_new) + { + ResetNES=ResetNES098; + PowerNES=PowerNES098; + FCEUI_Emulate=FCEUI_Emulate098; + } + else + { + ResetNES=ResetNES081; + PowerNES=PowerNES081; + FCEUI_Emulate=EmLoop; + } +} + void MMC5_hb(int); /* Ugh ugh ugh. */ static void DoLine(void) { @@ -1306,7 +1342,7 @@ static void DoLine(void) } -void EmLoop(void) +static void EmLoop(void) { for(;;) { @@ -1440,38 +1476,6 @@ update: } // for } -#ifdef FPS -#include -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 - -} - void FCEUI_CloseGame(void) { Exit=1; @@ -1496,7 +1500,7 @@ static void PowerPPU(void) ResetPPU(); } -void ResetNES(void) +void ResetNES081(void) { if(!GameLoaded) return; GameInterface(GI_RESETM2, 0); @@ -1517,7 +1521,7 @@ static void FCEU_MemoryRand(uint8 *ptr, uint32 size) } } -void PowerNES(void) +void PowerNES081(void) { if(!GameLoaded) return; diff --git a/fce.h b/fce.h index 7914fc4..8061008 100644 --- a/fce.h +++ b/fce.h @@ -24,8 +24,12 @@ void FlushGenieRW(void); void FCEU_ResetVidSys(void); void ResetMapping(void); -void ResetNES(void); -void PowerNES(void); + +extern void (*ResetNES)(void); +extern void (*PowerNES)(void); + +void ResetNES081(void); +void PowerNES081(void); extern uint64 timestampbase; diff --git a/fceu098.c b/fceu098.c new file mode 100644 index 0000000..75a8900 --- /dev/null +++ b/fceu098.c @@ -0,0 +1,97 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2003 Xodnizel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "types.h" +#include "fce.h" +#include "ppu098.h" +#include "sound.h" +#include "input.h" +#include "cart.h" +#include "cheat.h" +#include "x6502.h" +#include "video.h" +#include "svga.h" + + +int FCEUI_Initialize098(void) +{ + FCEUPPU_Init(); + return 1; +} + + +#ifdef FRAMESKIP +extern int FSkip; +#endif + +void FCEUI_Emulate098(void) +{ + for(;;) + { + int ssize; + + UpdateInput(); + if(geniestage!=1) FCEU_ApplyPeriodicCheats(); + FCEUPPU_Loop(FSkip); + + if(Exit) + { + break; + } + + ssize=FlushEmulateSound(); // TODO 098? + + timestampbase += timestamp; + timestamp = 0; + + #ifdef FRAMESKIP + if(FSkip) + { + FCEU_PutImageDummy(); + FSkip--; + FCEUD_Update(0,WaveFinalMono,ssize); + } + else + #endif + { + FCEU_PutImage(); + FCEUD_Update(XBuf+8,WaveFinalMono,ssize); + } + } // for +} + + +void ResetNES098(void) +{ + ResetNES081(); +//TODO FCEUSND_Reset(); + FCEUPPU_Reset(); +} + + +void PowerNES098(void) +{ + PowerNES081(); +//TODO FCEUSND_Power(); + FCEUPPU_Power(); +} + diff --git a/fceu098.h b/fceu098.h new file mode 100644 index 0000000..827eb58 --- /dev/null +++ b/fceu098.h @@ -0,0 +1,5 @@ +int FCEUI_Initialize098(void); +void FCEUI_Emulate098(void); +void ResetNES098(void); +void PowerNES098(void); + diff --git a/input/shadow.c b/input/shadow.c index 2a5fd8d..1c38045 100644 --- a/input/shadow.c +++ b/input/shadow.c @@ -86,7 +86,7 @@ static void FP_FASTAPASS(3) ZapperFrapper(uint8 *bg, uint8 *spr, uint32 linets, static INLINE int CheckColor(void) { - //FCEUPPU_LineUpdate(); + FCEUPPU_LineUpdate(); if((ZD.zaphit+10)>=(timestampbase+timestamp)) return(0); diff --git a/input/share.h b/input/share.h index adfeca9..19babd2 100644 --- a/input/share.h +++ b/input/share.h @@ -2,6 +2,7 @@ #include "../input.h" #include "../fce.h" #include "../ppu.h" +#include "../ppu098.h" #include "../x6502.h" #include "../palette.h" diff --git a/input/zapper.c b/input/zapper.c index 1caaff0..faf6a29 100644 --- a/input/zapper.c +++ b/input/zapper.c @@ -86,7 +86,7 @@ static void FP_FASTAPASS(3) ZapperFrapper(int w, uint8 *bg, uint8 *spr, uint32 l static INLINE int CheckColor(int w) { - //FCEUPPU_LineUpdate(); + FCEUPPU_LineUpdate(); if((ZD[w].zaphit+100)>=(timestampbase+timestamp) && !(ZD[w].mzb&2)) return(0); diff --git a/palette.h b/palette.h index 8560d9d..5784377 100644 --- a/palette.h +++ b/palette.h @@ -8,3 +8,5 @@ void FCEU_ResetPalette(void); void FCEU_ResetMessages(); void FCEU_LoadGamePalette(void); void FCEU_DrawNTSCControlBars(uint8 *XBuf); + +void SetNESDeemph(uint8 d, int force); diff --git a/ppu.c b/ppu.c index 0fedcac..3fe957e 100644 --- a/ppu.c +++ b/ppu.c @@ -33,10 +33,10 @@ #define H_FLIP 0x40 #define SP_BACK 0x20 -uint8 SPRAM[0x100]; -static uint8 SPRBUF[0x100]; +uint8 SPRAM[0x100] __attribute__ ((aligned (4))); +uint8 SPRBUF[0x100] __attribute__ ((aligned (4))); -uint8 sprlinebuf[256+8]; +uint8 sprlinebuf[256+8] __attribute__ ((aligned (4))); int32 sphitx; uint8 sphitdata; @@ -49,7 +49,7 @@ int spork=0; /* spork the world. Any sprites on this line? extern void BGRender(uint8 *target); -static int maxsprites=8; +int maxsprites=8; static int sprlinebuf_empty=0; diff --git a/ppu098.c b/ppu098.c new file mode 100644 index 0000000..62f78c5 --- /dev/null +++ b/ppu098.c @@ -0,0 +1,1312 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 1998 BERO + * Copyright (C) 2003 Xodnizel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "types.h" +#include "x6502.h" +#include "fce.h" +#include "ppu098.h" +#include "nsf.h" +#include "sound.h" // TODO 098? +#include "memory.h" + +#include "cart.h" +#include "palette.h" +#include "video.h" +#include "input.h" + +#define Pal (PALRAM) + +static void FetchSpriteData098(void); +static void FASTAPASS(1) RefreshLine098(int lastpixel); +static void RefreshSprites098(void); +static void CopySprites098(uint8 *target); + +static void Fixit1(void); +static uint32 ppulut1[256]; +static uint32 ppulut2[256]; +static uint32 ppulut3[128]; + +static void makeppulut(void) +{ + int x; + int y; + + for(x=0;x<256;x++) + { + ppulut1[x]=0; + for(y=0;y<8;y++) + ppulut1[x]|=((x>>(7-y))&1)<<(y*4); + ppulut2[x]=ppulut1[x]<<1; + } + + { + + int cc,xo,pixel; + + for(cc=0;cc<16;cc++) + { + for(xo=0;xo<8;xo++) + { + ppulut3[xo|(cc<<3)]=0; + for(pixel=0;pixel<8;pixel++) + { + int shiftr; + shiftr=(pixel+xo)/8; + shiftr*=2; + ppulut3[xo|(cc<<3)]|=(( cc>>shiftr )&3)<<(2+pixel*4); + } +// printf("%08x\n",ppulut3[xo|(cc<<3)]); + } + } + + } +} + +// TODO: make this compatible with the new sound code +#ifdef ASM_6502 +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 + +extern int ppudead; +extern int kook; + +/* Color deemphasis emulation. Joy... */ +static uint8 deemp=0; +static int deempcnt[8]; + +extern int maxsprites; + +extern uint8 PPUSPL; +extern uint8 SPRAM[0x100]; +extern uint8 SPRBUF[0x100]; + + +#define MMC5SPRVRAMADR(V) &MMC5SPRVPage[(V)>>10][(V)] +#define MMC5BGVRAMADR(V) &MMC5BGVPage[(V)>>10][(V)] +#define VRAMADR(V) &VPage[(V)>>10][(V)] + + +static DECLFR(A2002) +{ + uint8 ret; + + FCEUPPU_LineUpdate098(); + ret = PPU_status; + ret|=PPUGenLatch&0x1F; + + { + vtoggle=0; + PPU_status&=0x7F; + PPUGenLatch=ret; + } + return ret; +} + +static DECLFR(A200x) /* Not correct for $2004 reads. */ +{ + FCEUPPU_LineUpdate098(); + return PPUGenLatch; +} + +/* +static DECLFR(A2004) +{ + uint8 ret; + + FCEUPPU_LineUpdate098(); + ret = SPRAM[PPU[3]]; + + if(PPUSPL>=8) + { + if(PPU[3]>=8) + ret = SPRAM[PPU[3]]; + } + else + { + //printf("$%02x:$%02x\n",PPUSPL,V); + ret = SPRAM[PPUSPL]; + } + PPU[3]++; + PPUSPL++; + PPUGenLatch = ret; + printf("%d, %02x\n",scanline,ret); + return(ret); +} +*/ +static DECLFR(A2007) +{ + uint8 ret; + uint32 tmp=RefreshAddr&0x3FFF; + + FCEUPPU_LineUpdate098(); + + ret=VRAMBuffer; + + { + if(PPU_hook) PPU_hook(tmp); + PPUGenLatch=VRAMBuffer; + if(tmp<0x2000) + { + VRAMBuffer=VPage[tmp>>10][tmp]; + } + else + { + VRAMBuffer=vnapage[(tmp>>10)&0x3][tmp&0x3FF]; + } + } + { + if(INC32) RefreshAddr+=32; + else RefreshAddr++; + if(PPU_hook) PPU_hook(RefreshAddr&0x3fff); + } + return ret; +} + +static DECLFW(B2000) +{ +// FCEU_printf("%04x:%02x, (%d) %02x, %02x\n",A,V,scanline,PPU[0],PPU_status); + + FCEUPPU_LineUpdate098(); + PPUGenLatch=V; + if(!(PPU[0]&0x80) && (V&0x80) && (PPU_status&0x80)) + { +// FCEU_printf("Trigger NMI, %d, %d\n",timestamp,ppudead); +// TriggerNMI2(); + TriggerNMI(); + } + PPU[0]=V; + TempAddr&=0xF3FF; + TempAddr|=(V&3)<<10; +} + +static DECLFW(B2001) +{ + //printf("%04x:$%02x, %d\n",A,V,scanline); + FCEUPPU_LineUpdate098(); + PPUGenLatch=V; + PPU[1]=V; + if(V&0xE0) + deemp=V>>5; +} + +static DECLFW(B2002) +{ + PPUGenLatch=V; +} + +static DECLFW(B2003) +{ + //printf("$%04x:$%02x, %d, %d\n",A,V,timestamp,scanline); + PPUGenLatch=V; + PPU[3]=V; + PPUSPL=V&0x7; +} + +static DECLFW(B2004) +{ + //printf("Wr: %04x:$%02x\n",A,V); + + PPUGenLatch=V; + if(PPUSPL>=8) + { + if(PPU[3]>=8) + SPRAM[PPU[3]]=V; + } + else + { + //printf("$%02x:$%02x\n",PPUSPL,V); + SPRAM[PPUSPL]=V; + } + PPU[3]++; + PPUSPL++; + +} + +static DECLFW(B2005) +{ + uint32 tmp=TempAddr; + FCEUPPU_LineUpdate098(); + PPUGenLatch=V; + if(!vtoggle) + { + tmp&=0xFFE0; + tmp|=V>>3; + XOffset=V&7; + } + else + { + tmp&=0x8C1F; + tmp|=((V&~0x7)<<2); + tmp|=(V&7)<<12; + } + TempAddr=tmp; + vtoggle^=1; +} + + +static DECLFW(B2006) +{ + FCEUPPU_LineUpdate098(); + + PPUGenLatch=V; + if(!vtoggle) + { + TempAddr&=0x00FF; + TempAddr|=(V&0x3f)<<8; + } + else + { + TempAddr&=0xFF00; + TempAddr|=V; + + RefreshAddr=TempAddr; + if(PPU_hook) + PPU_hook(RefreshAddr); + //printf("%d, %04x\n",scanline,RefreshAddr); + } + vtoggle^=1; +} + +static DECLFW(B2007) +{ + uint32 tmp=RefreshAddr&0x3FFF; + PPUGenLatch=V; + if(tmp>=0x3F00) + { + // 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) + { + if(PPUCHRRAM&(1<<(tmp>>10))) + VPage[tmp>>10][tmp]=V; + } + else + { + if(PPUNTARAM&(1<<((tmp&0xF00)>>10))) + vnapage[((tmp&0xF00)>>10)][tmp&0x3FF]=V; + } +// FCEU_printf("ppu (%04x) %04x:%04x %d, %d\n",X.PC,RefreshAddr,PPUGenLatch,scanline,timestamp); + if(INC32) RefreshAddr+=32; + else RefreshAddr++; + if(PPU_hook) PPU_hook(RefreshAddr&0x3fff); +} + +static DECLFW(B4014) +{ + uint32 t=V<<8; + int x; + + //for(x=0;x<256;x++) + // X6502_DMW(0x2004,X6502_DMR(t+x)); + for(x=0;x<256;x++) + B2004(0x2004,X.DB=ARead[t+x](t+x)); + X6502_AddCycles(512); +} + +#define PAL(c) ((c)+cc) + +#define GETLASTPIXEL (PAL?((timestamp*48-linestartts)/15) : ((timestamp*48-linestartts)>>4) ) + +static uint8 *Pline=0,*Plinef; +static int firsttile; +static int linestartts; +static int tofix=0; + +static void ResetRL(uint8 *target) +{ + memset(target,0xFF,256); + if(InputScanlineHook) + InputScanlineHook(0,0,0,0); + Plinef=target; + Pline=target; + firsttile=0; + linestartts=timestamp*48+X.count; + tofix=0; + FCEUPPU_LineUpdate098(); + tofix=1; +} + +extern uint8 sprlinebuf[256+8]; + +void FCEUPPU_LineUpdate098(void) +{ + if(Pline) + { + int l=GETLASTPIXEL; + RefreshLine098(l); + } +} + +static int rendis = 0; + +void FCEUI_SetRenderDisable(int sprites, int bg) +{ + //printf("%d, %d\n",sprites,bg); + if(sprites >= 0) + { + if(sprites == 2) rendis ^= 1; + else rendis = (rendis &~1) | sprites?1:0; + } + if(bg >= 0) + { + if(bg == 2) rendis ^= 2; + else rendis = (rendis &~2) | bg?2:0; + } +} + +static void CheckSpriteHit(int p); + +static void EndRL(void) +{ + RefreshLine098(272); + if(tofix) + Fixit1(); + CheckSpriteHit(272); + Pline=0; +} + +static int32 sphitx; +static uint8 sphitdata; + +static void CheckSpriteHit(int p) +{ + int l=p-16; + int x; + + if(sphitx==0x100) return; + + for(x=sphitx;x<(sphitx+8) && x>(x-sphitx))) && !(Plinef[x]&64)) + { + PPU_status|=0x40; + //printf("Ha: %d, %d, Hita: %d, %d, %d, %d, %d\n",p,p&~7,scanline,GETLASTPIXEL-16,&Plinef[x],Pline,Pline-Plinef); + //printf("%d\n",GETLASTPIXEL-16); + //if(Plinef[x] == 0xFF) + //printf("PL: %d, %02x\n",scanline, Plinef[x]); + sphitx=0x100; + break; + } + } +} +static int spork=0; /* spork the world. Any sprites on this line? + Then this will be set to 1. Needed for zapper + emulation and *gasp* sprite emulation. + */ + +// lasttile is really "second to last tile." +static void FASTAPASS(1) RefreshLine098(int lastpixel) +{ + static uint32 pshift[2]; + static uint32 atlatch; + uint32 smorkus=RefreshAddr; + + #define RefreshAddr smorkus + uint32 vofs; + int X1; + + register uint8 *P=Pline; + int lasttile=lastpixel>>3; + int numtiles; + static int norecurse=0; /* Yeah, recursion would be bad. + PPU_hook() functions can call + mirroring/chr bank switching functions, + which call FCEUPPU_LineUpdate, which call this + function. */ + if(norecurse) return; + + if(sphitx != 0x100 && !(PPU_status&0x40)) + { + if((sphitx < (lastpixel-16)) && !(sphitx < ((lasttile - 2)*8))) + { + //printf("OK: %d\n",scanline); + lasttile++; + } + + } + + if(lasttile>34) lasttile=34; + numtiles=lasttile-firsttile; + + if(numtiles<=0) return; + + P=Pline; + + vofs=0; + + vofs=((PPU[0]&0x10)<<8) | ((RefreshAddr>>12)&7); + + if(!ScreenON && !SpriteON) + { + uint32 tem; + tem=Pal[0]|(Pal[0]<<8)|(Pal[0]<<16)|(Pal[0]<<24); + tem|=0x40404040; + FCEU_dwmemset(Pline,tem,numtiles*8); + P+=numtiles*8; + Pline=P; + + firsttile=lasttile; + + #define TOFIXNUM (272-0x4) + if(lastpixel>=TOFIXNUM && tofix) + { + Fixit1(); + tofix=0; + } + + if(InputScanlineHook && (lastpixel-16)>=0) + { + InputScanlineHook(Plinef,spork?sprlinebuf:0,linestartts,lasttile*8-16); + } + return; + } + + /* Priority bits, needed for sprite emulation. */ + Pal[0]|=64; + Pal[4]|=64; + Pal[8]|=64; + Pal[0xC]|=64; + + /* 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. + */ + + #define PPUT_MMC5 + if(MMC5Hack && geniestage!=1) + { + if(MMC5HackCHRMode==0 && (MMC5HackSPMode&0x80)) + { + int tochange=MMC5HackSPMode&0x1F; + tochange-=firsttile; + for(X1=firsttile;X10 && !(MMC5HackSPMode&0x40))) + { + #define PPUT_MMC5SP + #include "pputile098.h" + #undef PPUT_MMC5SP + } + else + { + #include "pputile098.h" + } + tochange--; + } + } + else if(MMC5HackCHRMode==1 && (MMC5HackSPMode&0x80)) + { + int tochange=MMC5HackSPMode&0x1F; + tochange-=firsttile; + + #define PPUT_MMC5SP + #define PPUT_MMC5CHR1 + for(X1=firsttile;X10) + FCEU_dwmemset(Plinef+tstart*8,tem,tcount*8); + } + + if(lastpixel>=TOFIXNUM && tofix) + { + //puts("Fixed"); + Fixit1(); + tofix=0; + } + + //CheckSpriteHit(lasttile*8); //lasttile*8); //lastpixel); + + CheckSpriteHit(lastpixel); /* This only works right because + of a hack earlier in this function. + */ + if(InputScanlineHook && (lastpixel-16)>=0) + { + InputScanlineHook(Plinef,spork?sprlinebuf:0,linestartts,lasttile*8-16); + } + Pline=P; + firsttile=lasttile; +} + +static INLINE void Fixit2(void) +{ + if(ScreenON || SpriteON) + { + uint32 rad=RefreshAddr; + rad&=0xFBE0; + rad|=TempAddr&0x041f; + RefreshAddr=rad; + //PPU_hook(RefreshAddr); + //PPU_hook(RefreshAddr,-1); + } +} + +static void Fixit1(void) +{ + if(ScreenON || SpriteON) + { + uint32 rad=RefreshAddr; + + if((rad&0x7000)==0x7000) + { + rad^=0x7000; + if((rad&0x3E0)==0x3A0) + { + rad^=0x3A0; + rad^=0x800; + } + else + { + if((rad&0x3E0)==0x3e0) + rad^=0x3e0; + else rad+=0x20; + } + } + else + rad+=0x1000; + RefreshAddr=rad; + //PPU_hook(RefreshAddr); //,-1); + } +} + +void MMC5_hb(int); /* Ugh ugh ugh. */ +static void DoLine(void) +{ + int x; + uint8 *target=XBuf+scanline*320+32; + + if(MMC5Hack && (ScreenON || SpriteON)) MMC5_hb(scanline); + + X6502_Run(256); + EndRL(); + + if(rendis & 2) /* User asked to not display background data. */ + { + uint32 tem; + tem=Pal[0]|(Pal[0]<<8)|(Pal[0]<<16)|(Pal[0]<<24); + tem|=0x40404040; + FCEU_dwmemset(target,tem,256); + } + + if(SpriteON) + CopySprites098(target); + + 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; + + sphitx=0x100; + + if(ScreenON || SpriteON) + FetchSpriteData098(); + + if(GameHBIRQHook && (ScreenON || SpriteON) && ((PPU[0]&0x38)!=0x18)) + { + X6502_Run(6); + Fixit2(); + X6502_Run(4); + GameHBIRQHook(); + X6502_Run(85-16-10); + } + else + { + X6502_Run(6); // Tried 65, caused problems with Slalom(maybe others) + Fixit2(); + X6502_Run(85-6-16); + + // A semi-hack for Star Trek: 25th Anniversary + if(GameHBIRQHook && (ScreenON || SpriteON) && ((PPU[0]&0x38)!=0x18)) + GameHBIRQHook(); + } + + if(SpriteON) + RefreshSprites098(); + if(GameHBIRQHook2 && (ScreenON || SpriteON)) + GameHBIRQHook2(); + scanline++; + if(scanline<240) + { + ResetRL(XBuf+scanline*320+32); + } + X6502_Run(16); +} + +#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; + +static uint8 numsprites,SpriteBlurp; +static void FetchSpriteData098(void) +{ + uint8 ns,sb; + SPR *spr; + uint8 H; + int n; + int vofs; + uint8 P0=PPU[0]; + + spr=(SPR *)SPRAM; + H=8; + + ns=sb=0; + + vofs=(unsigned int)(P0&0x8&(((P0&0x20)^0x20)>>2))<<9; + H+=(P0&0x20)>>2; + + if(!PPU_hook) + for(n=63;n>=0;n--,spr++) + { + if((unsigned int)(scanline-spr->y)>=H) continue; + //printf("%d, %u\n",scanline,(unsigned int)(scanline-spr->y)); + if(nsy); + + 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+=(P0&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[ns<<2]=*(uint32 *)&dst; + } + + ns++; + } + else + { + PPU_status|=0x20; + break; + } + } + else + for(n=63;n>=0;n--,spr++) + { + if((unsigned int)(scanline-spr->y)>=H) continue; + + if(nsy); + + 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+=(P0&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]; + if(ns<8) + { + PPU_hook(0x2000); + PPU_hook(vadr); + } + dst.ca[1]=C[8]; + dst.x=spr->x; + dst.atr=spr->atr; + + + *(uint32 *)&SPRBUF[ns<<2]=*(uint32 *)&dst; + } + + ns++; + } + else + { + PPU_status|=0x20; + break; + } + } + //if(ns>=7) + //printf("%d %d\n",scanline,ns); + if(ns>8) PPU_status|=0x20; /* Handle case when >8 sprites per + scanline option is enabled. */ + else if(PPU_hook) + { + for(n=0;n<(8-ns);n++) + { + PPU_hook(0x2000); + PPU_hook(vofs); + } + } + numsprites=ns; + SpriteBlurp=sb; +} + +static void RefreshSprites098(void) +{ + int n; + SPRB *spr; + + spork=0; + if(!numsprites) return; + + FCEU_dwmemset(sprlinebuf,0x80808080,256); + numsprites--; + spr = (SPRB*)SPRBUF+numsprites; + + for(n=numsprites;n>=0;n--,spr--) + { + //#ifdef C80x86 + //register uint32 pixdata asm ("eax"); + //register uint8 J, atr; + //#else + register uint32 pixdata; + register uint8 J,atr; + //#endif + + int x=spr->x; + uint8 *C; + uint8 *VB; + + pixdata=ppulut1[spr->ca[0]]|ppulut2[spr->ca[1]]; + J=spr->ca[0]|spr->ca[1]; + atr=spr->atr; + + if(J) + { + if(n==0 && SpriteBlurp && !(PPU_status&0x40)) + { + sphitx=x; + sphitdata=J; + if(atr&H_FLIP) + sphitdata= ((J<<7)&0x80) | + ((J<<5)&0x40) | + ((J<<3)&0x20) | + ((J<<1)&0x10) | + ((J>>1)&0x08) | + ((J>>3)&0x04) | + ((J>>5)&0x02) | + ((J>>7)&0x01); + } + + C = sprlinebuf+x; + VB = (PALRAM+0x10)+((atr&3)<<2); + + if(atr&SP_BACK) + { + if(atr&H_FLIP) + { + if(J&0x80) C[7]=VB[pixdata&3]|0x40; + pixdata>>=4; + if(J&0x40) C[6]=VB[pixdata&3]|0x40; + pixdata>>=4; + if(J&0x20) C[5]=VB[pixdata&3]|0x40; + pixdata>>=4; + if(J&0x10) C[4]=VB[pixdata&3]|0x40; + pixdata>>=4; + if(J&0x08) C[3]=VB[pixdata&3]|0x40; + pixdata>>=4; + if(J&0x04) C[2]=VB[pixdata&3]|0x40; + pixdata>>=4; + if(J&0x02) C[1]=VB[pixdata&3]|0x40; + pixdata>>=4; + if(J&0x01) C[0]=VB[pixdata]|0x40; + } else { + if(J&0x80) C[0]=VB[pixdata&3]|0x40; + pixdata>>=4; + if(J&0x40) C[1]=VB[pixdata&3]|0x40; + pixdata>>=4; + if(J&0x20) C[2]=VB[pixdata&3]|0x40; + pixdata>>=4; + if(J&0x10) C[3]=VB[pixdata&3]|0x40; + pixdata>>=4; + if(J&0x08) C[4]=VB[pixdata&3]|0x40; + pixdata>>=4; + if(J&0x04) C[5]=VB[pixdata&3]|0x40; + pixdata>>=4; + if(J&0x02) C[6]=VB[pixdata&3]|0x40; + pixdata>>=4; + if(J&0x01) C[7]=VB[pixdata]|0x40; + } + } else { + if(atr&H_FLIP) + { + if(J&0x80) C[7]=VB[pixdata&3]; + pixdata>>=4; + if(J&0x40) C[6]=VB[pixdata&3]; + pixdata>>=4; + if(J&0x20) C[5]=VB[pixdata&3]; + pixdata>>=4; + if(J&0x10) C[4]=VB[pixdata&3]; + pixdata>>=4; + if(J&0x08) C[3]=VB[pixdata&3]; + pixdata>>=4; + if(J&0x04) C[2]=VB[pixdata&3]; + pixdata>>=4; + if(J&0x02) C[1]=VB[pixdata&3]; + pixdata>>=4; + if(J&0x01) C[0]=VB[pixdata]; + }else{ + if(J&0x80) C[0]=VB[pixdata&3]; + pixdata>>=4; + if(J&0x40) C[1]=VB[pixdata&3]; + pixdata>>=4; + if(J&0x20) C[2]=VB[pixdata&3]; + pixdata>>=4; + if(J&0x10) C[3]=VB[pixdata&3]; + pixdata>>=4; + if(J&0x08) C[4]=VB[pixdata&3]; + pixdata>>=4; + if(J&0x04) C[5]=VB[pixdata&3]; + pixdata>>=4; + if(J&0x02) C[6]=VB[pixdata&3]; + pixdata>>=4; + if(J&0x01) C[7]=VB[pixdata]; + } + } + } + } + SpriteBlurp=0; + spork=1; +} + +static void CopySprites098(uint8 *target) +{ + uint8 n=((PPU[1]&4)^4)<<1; + uint8 *P=target; + + if(!spork) return; + spork=0; + + if(rendis & 1) return; /* User asked to not display sprites. */ + + loopskie: + { + uint32 t=*(uint32 *)(sprlinebuf+n); + + if(t!=0x80808080) + { + #ifdef LSB_FIRST + if(!(t&0x80)) + { + if(!(t&0x40) || (P[n]&0x40)) // Normal sprite || behind bg sprite + P[n]=sprlinebuf[n]; + } + + if(!(t&0x8000)) + { + if(!(t&0x4000) || (P[n+1]&0x40)) // Normal sprite || behind bg sprite + P[n+1]=(sprlinebuf+1)[n]; + } + + if(!(t&0x800000)) + { + if(!(t&0x400000) || (P[n+2]&0x40)) // Normal sprite || behind bg sprite + P[n+2]=(sprlinebuf+2)[n]; + } + + if(!(t&0x80000000)) + { + if(!(t&0x40000000) || (P[n+3]&0x40)) // Normal sprite || behind bg sprite + P[n+3]=(sprlinebuf+3)[n]; + } + #else + /* TODO: Simplify */ + if(!(t&0x80000000)) + { + if(!(t&0x40000000)) // Normal sprite + P[n]=sprlinebuf[n]; + else if(P[n]&64) // behind bg sprite + P[n]=sprlinebuf[n]; + } + + if(!(t&0x800000)) + { + if(!(t&0x400000)) // 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&0x4000)) // 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&0x40)) // 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; +} + +void FCEUPPU_Init(void) +{ + makeppulut(); +} + +void FCEUPPU_Reset(void) +{ + VRAMBuffer=PPU[0]=PPU[1]=PPU_status=PPU[3]=0; + PPUSPL=0; + PPUGenLatch=0; + RefreshAddr=TempAddr=0; + vtoggle = 0; + ppudead = 2; + kook = 0; + +// XOffset=0; +} + +void FCEUPPU_Power(void) +{ + int x; + + memset(NTARAM,0x00,0x800); + memset(PALRAM,0x00,0x20); + memset(SPRAM,0x00,0x100); + FCEUPPU_Reset(); + + for(x=0x2000;x<0x4000;x+=8) + { + ARead[x]=A200x; + BWrite[x]=B2000; + ARead[x+1]=A200x; + BWrite[x+1]=B2001; + ARead[x+2]=A2002; + BWrite[x+2]=B2002; + ARead[x+3]=A200x; + BWrite[x+3]=B2003; + ARead[x+4]=A200x; //A2004; + BWrite[x+4]=B2004; + ARead[x+5]=A200x; + BWrite[x+5]=B2005; + ARead[x+6]=A200x; + BWrite[x+6]=B2006; + ARead[x+7]=A2007; + BWrite[x+7]=B2007; + } + BWrite[0x4014]=B4014; +} + + +void FCEUPPU_Loop(int skip) +{ + uint32 scanlines_per_frame = PAL ? 312 : 262; + + if(ppudead) /* Needed for Knight Rider, possibly others. */ + { + //memset(XBuf, 0x80, 256*240); + X6502_Run(scanlines_per_frame*(256+85)); + ppudead--; + } + else + { + X6502_Run(256+85); + PPU_status |= 0x80; + PPU[3]=PPUSPL=0; /* Not sure if this is correct. According + to Matt Conte and my own tests, it is. Timing is probably + off, though. NOTE: Not having this here + breaks a Super Donkey Kong game. */ + /* I need to figure out the true nature and length + of this delay. + */ + X6502_Run(12); + if(FCEUGameInfo.type==GIT_NSF) + DoNSFFrame(); + else + { + if(VBlankON) + TriggerNMI(); + } + X6502_Run((scanlines_per_frame-242)*(256+85)-12); //-12); + PPU_status&=0x1f; + X6502_Run(256); + + { + int x; + + if(ScreenON || SpriteON) + { + if(GameHBIRQHook && ((PPU[0]&0x38)!=0x18)) + GameHBIRQHook(); + if(PPU_hook) + for(x=0;x<42;x++) {PPU_hook(0x2000); PPU_hook(0);} + if(GameHBIRQHook2) + GameHBIRQHook2(); + } + X6502_Run(85-16); + if(ScreenON || SpriteON) + { + RefreshAddr=TempAddr; + if(PPU_hook) PPU_hook(RefreshAddr&0x3fff); + } + + /* Clean this stuff up later. */ + spork=numsprites=0; + ResetRL(XBuf+32); + + X6502_Run(16-kook); + kook ^= 1; + } + if(FCEUGameInfo.type==GIT_NSF) + { + X6502_Run((256+85)*240); + } + #ifdef FRAMESKIP + else if(skip) + { + int y; + + y=SPRAM[0]; + y++; + + PPU_status|=0x20; // Fixes "Bee 52". Does it break anything? + if(GameHBIRQHook) + { + X6502_Run(256); + for(scanline=0;scanline<240;scanline++) + { + if(ScreenON || SpriteON) + GameHBIRQHook(); + if(scanline==y && SpriteON) PPU_status|=0x40; + X6502_Run((scanline==239)?85:(256+85)); + } + } + else if(y<240) + { + X6502_Run((256+85)*y); + if(SpriteON) PPU_status|=0x40; // Quick and very dirty hack. + X6502_Run((256+85)*(240-y)); + } + else + X6502_Run((256+85)*240); + } + #endif + else + { + int x,max,maxref; + + deemp=PPU[1]>>5; + for(scanline=0;scanline<240;) //scanline is incremented in DoLine. Evil. :/ + { + deempcnt[deemp]++; +#ifdef WIN32 + if((PPUViewer) && (scanline == PPUViewScanline)) UpdatePPUView(1); +#endif + DoLine(); + } + if(MMC5Hack && (ScreenON || SpriteON)) MMC5_hb(scanline); + for(x=1,max=0,maxref=0;x<7;x++) + { + if(deempcnt[x]>max) + { + max=deempcnt[x]; + maxref=x; + } + 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); + } + } /* else... to if(ppudead) */ +} + + diff --git a/ppu098.h b/ppu098.h new file mode 100644 index 0000000..8353a6c --- /dev/null +++ b/ppu098.h @@ -0,0 +1,10 @@ +void FCEUPPU_Init(void); +void FCEUPPU_Reset(void); +void FCEUPPU_Power(void); +void FCEUPPU_Loop(int skip); + +void FCEUPPU_LineUpdate098(); + +void PowerNES098(void); +#define FCEUPPU_LineUpdate() \ + if (PowerNES == PowerNES098) FCEUPPU_LineUpdate098() diff --git a/pputile098.h b/pputile098.h new file mode 100644 index 0000000..6da930c --- /dev/null +++ b/pputile098.h @@ -0,0 +1,157 @@ + uint8 *C; + register uint8 cc; + uint32 vadr; + + #ifndef PPUT_MMC5SP + register uint8 zz; + #else + uint8 xs,ys; + xs=X1; + ys=((scanline>>3)+MMC5HackSPScroll)&0x1F; + if(ys>=0x1E) ys-=0x1E; + #endif + + if(X1>=2) + { + uint8 *S=PALRAM; + uint32 pixdata; + + pixdata=ppulut1[(pshift[0]>>(8-XOffset))&0xFF]|ppulut2[(pshift[1]>>(8-XOffset))&0xFF]; + + pixdata|=ppulut3[XOffset|(atlatch<<3)]; + //printf("%02x ",ppulut3[XOffset|(atlatch<<3)]); + + #ifdef C80x86 + asm volatile( + "movl %%ebx,%%eax\n\t" + "andl $15,%%eax\n\t" + "movb (%%esi,%%eax),%%cl\n\t" + "shrl $4, %%ebx\n\t" + "movb %%cl, (%%edi)\n\t" + + "movl %%ebx,%%eax\n\t" + "andl $15,%%eax\n\t" + "movb (%%esi,%%eax),%%cl\n\t" + "shrl $4, %%ebx\n\t" + "movb %%cl, 1(%%edi)\n\t" + + "movl %%ebx,%%eax\n\t" + "andl $15,%%eax\n\t" + "movb (%%esi,%%eax),%%cl\n\t" + "shrl $4, %%ebx\n\t" + "movb %%cl, 2(%%edi)\n\t" + + "movl %%ebx,%%eax\n\t" + "andl $15,%%eax\n\t" + "movb (%%esi,%%eax),%%cl\n\t" + "shrl $4, %%ebx\n\t" + "movb %%cl, 3(%%edi)\n\t" + + "movl %%ebx,%%eax\n\t" + "andl $15,%%eax\n\t" + "movb (%%esi,%%eax),%%cl\n\t" + "shrl $4, %%ebx\n\t" + "movb %%cl, 4(%%edi)\n\t" + + "movl %%ebx,%%eax\n\t" + "andl $15,%%eax\n\t" + "movb (%%esi,%%eax),%%cl\n\t" + "shrl $4, %%ebx\n\t" + "movb %%cl, 5(%%edi)\n\t" + + "movl %%ebx,%%eax\n\t" + "andl $15,%%eax\n\t" + "movb (%%esi,%%eax),%%cl\n\t" + "shrl $4, %%ebx\n\t" + "movb %%cl, 6(%%edi)\n\t" + + //"movl %%ebx,%%eax\n\t" + //"andl $15,%%eax\n\t" + //"movb (%%esi,%%eax),%%cl\n\t" + //"movb %%cl, 7(%%edi)\n\t" + "movb (%%esi, %%ebx),%%cl\n\t" + "movb %%cl, 7(%%edi)\n\t" + : + : "S" (S), "D" (P), "b" (pixdata) + : "eax", "cl" ); + #else + P[0]=S[pixdata&0xF]; + pixdata>>=4; + P[1]=S[pixdata&0xF]; + pixdata>>=4; + P[2]=S[pixdata&0xF]; + pixdata>>=4; + P[3]=S[pixdata&0xF]; + pixdata>>=4; + P[4]=S[pixdata&0xF]; + pixdata>>=4; + P[5]=S[pixdata&0xF]; + pixdata>>=4; + P[6]=S[pixdata&0xF]; + pixdata>>=4; + P[7]=S[pixdata&0xF]; + #endif + P+=8; + } + + #ifdef PPUT_MMC5SP + vadr=(MMC5HackExNTARAMPtr[xs|(ys<<5)]<<4)+(vofs&7); + #else + zz=RefreshAddr&0x1F; + C=vnapage[(RefreshAddr>>10)&3]; + vadr=(C[RefreshAddr&0x3ff]<<4)+vofs; /* Fetch name table byte. */ + #endif + + #ifdef PPUT_HOOK + PPU_hook(0x2000|(RefreshAddr&0xfff)); + #endif + + #ifdef PPUT_MMC5SP + cc=MMC5HackExNTARAMPtr[0x3c0+(xs>>2)+((ys&0x1C)<<1)]; + cc=((cc >> ((xs&2) + ((ys&0x2)<<1))) &3); + #else + #ifdef PPUT_MMC5CHR1 + cc=(MMC5HackExNTARAMPtr[RefreshAddr & 0x3ff] & 0xC0)>>6; + #else + cc=C[0x3c0+(zz>>2)+((RefreshAddr&0x380)>>4)]; /* Fetch attribute table byte. */ + cc=((cc >> ((zz&2) + ((RefreshAddr&0x40)>>4))) &3); + #endif + #endif + + atlatch>>=2; + atlatch|=cc<<2; + + pshift[0]<<=8; + pshift[1]<<=8; + + #ifdef PPUT_MMC5SP + C = MMC5HackVROMPTR+vadr; + C += ((MMC5HackSPPage & 0x3f & MMC5HackVROMMask) << 12); + #else + #ifdef PPUT_MMC5CHR1 + C = MMC5HackVROMPTR; + C += (((MMC5HackExNTARAMPtr[RefreshAddr & 0x3ff]) & 0x3f & + MMC5HackVROMMask) << 12) + (vadr & 0xfff); + #elif defined(PPUT_MMC5) + C=MMC5BGVRAMADR(vadr); + #else + C = VRAMADR(vadr); + #endif + #endif + + #ifdef PPUT_HOOK + PPU_hook(vadr); + #endif + + pshift[0]|=C[0]; + pshift[1]|=C[8]; + + if((RefreshAddr&0x1f)==0x1f) + RefreshAddr^=0x41F; + else + RefreshAddr++; + + #ifdef PPUT_HOOK + PPU_hook(0x2000|(RefreshAddr&0xfff)); + #endif + diff --git a/svga.h b/svga.h index 9d8cbf9..b18787d 100644 --- a/svga.h +++ b/svga.h @@ -49,7 +49,6 @@ void FCEU_PrintError(char *format, ...); void FCEU_DispMessage(char *format, ...); #define FCEU_printf printf -void SetNESDeemph(uint8 d, int force); void DrawTextTrans(uint8 *dest, uint32 width, uint8 *textmsg, uint8 fgcolor); void FCEU_PutImage(void); #ifdef FRAMESKIP @@ -59,7 +58,6 @@ void FCEU_PutImageDummy(void); extern uint8 Exit; extern uint8 pale; extern uint8 vsdip; -void SetNESPalette(void); #define JOY_A 1 #define JOY_B 2