From e982bb637b65f19c53ca12249b6a469f02618e9e Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 6 Aug 2015 11:39:10 +0200 Subject: [PATCH] Revert "Cleanups" This reverts commit d368ee005485221f70c438f2c6782d0272355809. --- Makefile.common | 24 +- src/drivers/libretro/fceu/fceu-endian.c | 123 ++++ src/drivers/libretro/fceu/fceu-endian.h | 18 + src/drivers/libretro/fceu/fceu-memory.c | 63 ++ src/drivers/libretro/fceu/fceu-memory.h | 50 ++ src/drivers/libretro/fceu/fceu.c | 550 ++++++++++++++++ src/drivers/libretro/fceu/fds.c | 772 ++++++++++++++++++++++ src/drivers/libretro/fceu/file.c | 185 ++++++ src/drivers/libretro/fceu/general.c | 162 +++++ src/drivers/libretro/fceu/ines.c | 839 ++++++++++++++++++++++++ src/drivers/libretro/fceu/input.c | 378 +++++++++++ src/drivers/libretro/fceu/misc.c | 20 + src/drivers/libretro/fceu/nsf.c | 519 +++++++++++++++ src/drivers/libretro/fceu/state.c | 365 +++++++++++ src/drivers/libretro/fceu/unif.c | 626 ++++++++++++++++++ src/drivers/libretro/fceu/video.c | 109 +++ src/drivers/libretro/griffin.c | 22 +- src/fceu-endian.c | 130 ++-- src/fceu-endian.h | 4 - src/fceu-memory.c | 79 ++- src/fceu-memory.h | 7 +- src/fceu.c | 295 ++++----- src/fds.c | 6 +- src/file.c | 536 +++++++++++---- src/general.c | 213 +++--- src/ines.c | 2 +- src/input.c | 495 +++++++------- src/state.c | 498 +++++++------- src/unif.c | 2 +- src/video.c | 264 ++++++-- 30 files changed, 6380 insertions(+), 976 deletions(-) create mode 100644 src/drivers/libretro/fceu/fceu-endian.c create mode 100644 src/drivers/libretro/fceu/fceu-endian.h create mode 100644 src/drivers/libretro/fceu/fceu-memory.c create mode 100644 src/drivers/libretro/fceu/fceu-memory.h create mode 100644 src/drivers/libretro/fceu/fceu.c create mode 100644 src/drivers/libretro/fceu/fds.c create mode 100644 src/drivers/libretro/fceu/file.c create mode 100644 src/drivers/libretro/fceu/general.c create mode 100644 src/drivers/libretro/fceu/ines.c create mode 100644 src/drivers/libretro/fceu/input.c create mode 100644 src/drivers/libretro/fceu/misc.c create mode 100644 src/drivers/libretro/fceu/nsf.c create mode 100644 src/drivers/libretro/fceu/state.c create mode 100644 src/drivers/libretro/fceu/unif.c create mode 100644 src/drivers/libretro/fceu/video.c diff --git a/Makefile.common b/Makefile.common index 9e512ec..f4e545c 100644 --- a/Makefile.common +++ b/Makefile.common @@ -2,7 +2,7 @@ INCFLAGS := -I$(CORE_DIR)/drivers/libretro -I$(CORE_DIR) -I$(CORE_DIR)/input -I$ FCEU_SRC_DIRS := $(CORE_DIR)/boards $(CORE_DIR)/input $(CORE_DIR)/mappers SOURCES_C := $(foreach dir,$(FCEU_SRC_DIRS),$(wildcard $(dir)/*.c)) -SOURCES_C += $(CORE_DIR)/ines.c $(CORE_DIR)/unif.c $(CORE_DIR)/x6502.c +SOURCES_C += $(CORE_DIR)/drivers/libretro/fceu/ines.c $(CORE_DIR)/drivers/libretro/fceu/unif.c $(CORE_DIR)/x6502.c ifeq ($(WANT_GRIFFIN),1) SOURCES_C += \ @@ -16,21 +16,21 @@ SOURCES_C += \ $(CORE_DIR)/cheat.c \ $(CORE_DIR)/crc32.c \ $(CORE_DIR)/debug.c \ - $(CORE_DIR)/fceu-endian.c \ - $(CORE_DIR)/fceu-memory.c \ - $(CORE_DIR)/misc.c \ - $(CORE_DIR)/fceu.c \ - $(CORE_DIR)/fds.c \ - $(CORE_DIR)/file.c \ + $(CORE_DIR)/drivers/libretro/fceu/fceu-endian.c \ + $(CORE_DIR)/drivers/libretro/fceu/fceu-memory.c \ + $(CORE_DIR)/drivers/libretro/fceu/misc.c \ + $(CORE_DIR)/drivers/libretro/fceu/fceu.c \ + $(CORE_DIR)/drivers/libretro/fceu/fds.c \ + $(CORE_DIR)/drivers/libretro/fceu/file.c \ $(CORE_DIR)/filter.c \ - $(CORE_DIR)/general.c \ - $(CORE_DIR)/input.c \ - $(CORE_DIR)/nsf.c \ + $(CORE_DIR)/drivers/libretro/fceu/general.c \ + $(CORE_DIR)/drivers/libretro/fceu/input.c \ + $(CORE_DIR)/drivers/libretro/fceu/nsf.c \ $(CORE_DIR)/md5.c \ $(CORE_DIR)/palette.c \ $(CORE_DIR)/ppu.c \ $(CORE_DIR)/sound.c \ $(CORE_DIR)/vsuni.c \ - $(CORE_DIR)/state.c \ - $(CORE_DIR)/video.c + $(CORE_DIR)/drivers/libretro/fceu/state.c \ + $(CORE_DIR)/drivers/libretro/fceu/video.c endif diff --git a/src/drivers/libretro/fceu/fceu-endian.c b/src/drivers/libretro/fceu/fceu-endian.c new file mode 100644 index 0000000..754489f --- /dev/null +++ b/src/drivers/libretro/fceu/fceu-endian.c @@ -0,0 +1,123 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Contains file I/O functions that write/read data */ +/* LSB first. */ + +#include +#include "fceu-memory.h" +#include "fceu-types.h" +#include "fceu-endian.h" + +void FlipByteOrder(uint8 *src, uint32 count) +{ + uint8 *start = src; + uint8 *end = src + count - 1; + + while(start < end) + { + uint8 tmp; + + tmp = *end; + *end = *start; + *start = tmp; + end--; + start++; + } +} + +int write16le(uint16 b, FILE *fp) +{ + uint8 s[2]; + s[0] = b; + s[1] = b >> 8; + return((fwrite(s, 1, 2, fp) < 2) ? 0 : 2); +} + +int write32le(uint32 b, FILE *fp) +{ + uint8 s[4]; + s[0] = b; + s[1] = b >> 8; + s[2] = b >> 16; + s[3] = b >> 24; + return((fwrite(s, 1, 4, fp) < 4) ? 0 : 4); +} + +int read32le(uint32 *Bufo, FILE *fp) +{ + uint32 buf; + if (fread(&buf, 1, 4, fp) < 4) + return 0; +#ifdef MSB_FIRST + *(uint32*)Bufo = ((buf & 0xFF) << 24) | ((buf & 0xFF00) << 8) | ((buf & 0xFF0000) >> 8) | ((buf & 0xFF000000) >> 24); +#else + *(uint32*)Bufo = buf; +#endif + return 1; +} + +int write32le_mem(uint32 b, memstream_t *mem) +{ + uint8 s[4]; + s[0]=b; + s[1]=b>>8; + s[2]=b>>16; + s[3]=b>>24; + return((memstream_write(mem, s, 4)<4)?0:4); +} + +int read32le_mem(uint32 *Bufo, memstream_t *mem) +{ + uint32 buf; + if(memstream_read(mem, &buf, 4)<4) + return 0; +#ifdef MSB_FIRST + *(uint32*)Bufo=((buf&0xFF)<<24)|((buf&0xFF00)<<8)|((buf&0xFF0000)>>8)|((buf&0xFF000000)>>24); +#else + *(uint32*)Bufo=buf; +#endif + return 1; +} + +int read16le(char *d, FILE *fp) +{ +#ifdef MSB_FIRST + int ret; + ret = fread(d + 1, 1, 1, fp); + ret += fread(d, 1, 1, fp); + return ret < 2 ? 0 : 2; +#else + return((fread(d, 1, 2, fp) < 2) ? 0 : 2); +#endif +} + +void FCEU_en32lsb(uint8 *buf, uint32 morp) +{ + buf[0] = morp; + buf[1] = morp >> 8; + buf[2] = morp >> 16; + buf[3] = morp >> 24; +} + +uint32 FCEU_de32lsb(uint8 *morp) +{ + return(morp[0] | (morp[1] << 8) | (morp[2] << 16) | (morp[3] << 24)); +} diff --git a/src/drivers/libretro/fceu/fceu-endian.h b/src/drivers/libretro/fceu/fceu-endian.h new file mode 100644 index 0000000..db19b37 --- /dev/null +++ b/src/drivers/libretro/fceu/fceu-endian.h @@ -0,0 +1,18 @@ +#ifndef _FCEU_ENDIAN_H +#define _FCEU_ENDIAN_H + +#include "fceu-memory.h" +#include "../memstream.h" + +int write32le_mem(uint32 b, memstream_t *mem); +int read32le_mem(uint32 *Bufo, memstream_t *mem); + +int write16le(uint16 b, FILE *fp); +int write32le(uint32 b, FILE *fp); +int read32le(uint32 *Bufo, FILE *fp); +void FlipByteOrder(uint8 *src, uint32 count); + +void FCEU_en32lsb(uint8 *, uint32); +uint32 FCEU_de32lsb(uint8 *); + +#endif diff --git a/src/drivers/libretro/fceu/fceu-memory.c b/src/drivers/libretro/fceu/fceu-memory.c new file mode 100644 index 0000000..0c97a5d --- /dev/null +++ b/src/drivers/libretro/fceu/fceu-memory.c @@ -0,0 +1,63 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "fceu-types.h" +#include "fceu.h" +#include "fceu-memory.h" +#include "general.h" + +void *FCEU_gmalloc(uint32 size) +{ + void *ret; + ret = malloc(size); + if (!ret) + { + FCEU_PrintError("Error allocating memory! Doing a hard exit."); + exit(1); + } + return ret; +} + +void *FCEU_malloc(uint32 size) +{ + int retval = 0; + void *ret; + ret = (void*)malloc(size); + + if (!ret) + { + FCEU_PrintError("Error allocating memory!"); + ret = 0; + } + + return ret; +} + +void FCEU_free(void *ptr) +{ + free(ptr); +} + +void FCEU_gfree(void *ptr) +{ + free(ptr); +} diff --git a/src/drivers/libretro/fceu/fceu-memory.h b/src/drivers/libretro/fceu/fceu-memory.h new file mode 100644 index 0000000..e8cd246 --- /dev/null +++ b/src/drivers/libretro/fceu/fceu-memory.h @@ -0,0 +1,50 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Various macros for faster memory stuff + (at least that's the idea) +*/ + +#ifndef _FCEU_MEMORY_H_ +#define _FCEU_MEMORY_H_ + +#include "fceu-types.h" +#include "../memstream.h" + +#define FCEU_dwmemset(d, c, n) { int _x; for (_x = n - 4; _x >= 0; _x -= 4) *(uint32*)& (d)[_x] = c; } + +#define HAVE_MEMSTREAM +#define MEM_TYPE memstream_t + +#define fwrite(ptr, size, nmemb, stream) memstream_write((stream), (ptr), (nmemb)) +#define fclose(fp) memstream_close((fp)) +#define fgetc(stream) memstream_getc((stream)) +#define fputc(c, stream) memstream_putc((stream), (c)) +#define ftell(a) memstream_pos((a)) +#define fread(ptr, size, nmemb, stream) memstream_read((stream), (ptr), (nmemb)) +#define fseek(stream, offset, whence) memstream_seek((stream), (offset), (whence)) + +void *FCEU_malloc(uint32 size); +void *FCEU_gmalloc(uint32 size); +void FCEU_gfree(void *ptr); +void FCEU_free(void *ptr); +void FASTAPASS(3) FCEU_memmove(void *d, void *s, uint32 l); + +#endif diff --git a/src/drivers/libretro/fceu/fceu.c b/src/drivers/libretro/fceu/fceu.c new file mode 100644 index 0000000..ffabf10 --- /dev/null +++ b/src/drivers/libretro/fceu/fceu.c @@ -0,0 +1,550 @@ +/* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +#include "fceu-types.h" +#include "x6502.h" +#include "fceu.h" +#include "ppu.h" +#include "sound.h" +#include "netplay.h" +#include "general.h" +#include "fceu-endian.h" +#include "fceu-memory.h" + +#include "cart.h" +#include "nsf.h" +#include "fds.h" +#include "ines.h" +#include "unif.h" +#include "cheat.h" +#include "palette.h" +#include "state.h" +#include "video.h" +#include "input.h" +#include "file.h" +#include "crc32.h" +#include "vsuni.h" + +uint64 timestampbase; + + +FCEUGI *GameInfo = NULL; +void (*GameInterface)(int h); + +void (*GameStateRestore)(int version); + +readfunc ARead[0x10000]; +writefunc BWrite[0x10000]; +static readfunc *AReadG; +static writefunc *BWriteG; +static int RWWrap = 0; + +static DECLFW(BNull) +{ +} + +static DECLFR(ANull) +{ + return(X.DB); +} + +int AllocGenieRW(void) +{ + if (!(AReadG = (readfunc*)FCEU_malloc(0x8000 * sizeof(readfunc)))) + return 0; + if (!(BWriteG = (writefunc*)FCEU_malloc(0x8000 * sizeof(writefunc)))) + return 0; + RWWrap = 1; + return 1; +} + +void FlushGenieRW(void) +{ + int32 x; + + if (RWWrap) + { + for (x = 0; x < 0x8000; x++) + { + ARead[x + 0x8000] = AReadG[x]; + BWrite[x + 0x8000] = BWriteG[x]; + } + free(AReadG); + free(BWriteG); + AReadG = 0; + BWriteG = 0; + } + RWWrap = 0; +} + +readfunc FASTAPASS(1) GetReadHandler(int32 a) +{ + if (a >= 0x8000 && RWWrap) + return AReadG[a - 0x8000]; + else + return ARead[a]; +} + +void FASTAPASS(3) SetReadHandler(int32 start, int32 end, readfunc func) +{ + int32 x; + + if (!func) + func = ANull; + + if (RWWrap) + for (x = end; x >= start; x--) + { + if (x >= 0x8000) + AReadG[x - 0x8000] = func; + else + ARead[x] = func; + } + else + for (x = end; x >= start; x--) + ARead[x] = func; +} + +writefunc FASTAPASS(1) GetWriteHandler(int32 a) +{ + if (RWWrap && a >= 0x8000) + return BWriteG[a - 0x8000]; + else + return BWrite[a]; +} + +void FASTAPASS(3) SetWriteHandler(int32 start, int32 end, writefunc func) +{ + int32 x; + + if (!func) + func = BNull; + + if (RWWrap) + for (x = end; x >= start; x--) + { + if (x >= 0x8000) + BWriteG[x - 0x8000] = func; + else + BWrite[x] = func; + } + else + for (x = end; x >= start; x--) + BWrite[x] = func; +} + +#ifdef COPYFAMI +uint8 RAM[0x4000]; +#else +uint8 RAM[0x800]; +#endif + +uint8 PAL = 0; + +static DECLFW(BRAML) +{ + RAM[A] = V; +} + +static DECLFR(ARAML) +{ + return RAM[A]; +} + +#ifndef COPYFAMI +static DECLFW(BRAMH) +{ + RAM[A & 0x7FF] = V; +} + +static DECLFR(ARAMH) +{ + return RAM[A & 0x7FF]; +} +#endif + +void FCEUI_CloseGame(void) +{ + if (!GameInfo) + return; + + if (GameInfo->name) + free(GameInfo->name); + GameInfo->name = 0; + if (GameInfo->type != GIT_NSF) + FCEU_FlushGameCheats(0, 0); + GameInterface(GI_CLOSE); + ResetExState(0, 0); + FCEU_CloseGenie(); + free(GameInfo); + GameInfo = 0; +} + +void ResetGameLoaded(void) +{ + if (GameInfo) + FCEUI_CloseGame(); + + GameStateRestore = NULL; + PPU_hook = NULL; + GameHBIRQHook = NULL; + + if (GameExpSound.Kill) + GameExpSound.Kill(); + memset(&GameExpSound, 0, sizeof(GameExpSound)); + + MapIRQHook = NULL; + MMC5Hack = 0; + PEC586Hack = 0; + PAL &= 1; + pale = 0; +} + +int UNIFLoad(const char *name, FCEUFILE *fp); +int iNESLoad(const char *name, FCEUFILE *fp); +int FDSLoad(const char *name, FCEUFILE *fp); +int NSFLoad(FCEUFILE *fp); + +FCEUGI *FCEUI_LoadGame(const char *name, uint8_t *databuf, size_t databufsize) +{ + FCEUFILE *fp; + + ResetGameLoaded(); + + GameInfo = malloc(sizeof(FCEUGI)); + memset(GameInfo, 0, sizeof(FCEUGI)); + + GameInfo->soundchan = 0; + GameInfo->soundrate = 0; + GameInfo->name = 0; + GameInfo->type = GIT_CART; + GameInfo->vidsys = GIV_USER; + GameInfo->input[0] = GameInfo->input[1] = -1; + GameInfo->inputfc = -1; + GameInfo->cspecial = 0; + + FCEU_printf("Loading %s...\n\n", name); + + GetFileBase(name); + + fp = FCEU_fopen(name, NULL, "rb", 0, databuf, databufsize); + + if (!fp) { + FCEU_PrintError("Error opening \"%s\"!", name); + return 0; + } + + if (iNESLoad(name, fp)) + goto endlseq; + if (NSFLoad(fp)) + goto endlseq; + if (UNIFLoad(name, fp)) + goto endlseq; + if (FDSLoad(name, fp)) + goto endlseq; + + FCEU_PrintError("An error occurred while loading the file."); + FCEU_fclose(fp); + return 0; + +endlseq: + FCEU_fclose(fp); + + FCEU_ResetVidSys(); + if (GameInfo->type != GIT_NSF) + if (FSettings.GameGenie) + FCEU_OpenGenie(); + + PowerNES(); + FCEUSS_CheckStates(); + + if (GameInfo->type != GIT_NSF) { + FCEU_LoadGamePalette(); + FCEU_LoadGameCheats(0); + } + + FCEU_ResetPalette(); + FCEU_ResetMessages(); // Save state, status messages, etc. + + return(GameInfo); +} + +int CopyFamiLoad(void); + +FCEUGI *FCEUI_CopyFamiStart(void) +{ + ResetGameLoaded(); + + GameInfo = (FCEUGI*)malloc(sizeof(FCEUGI)); + memset(GameInfo, 0, sizeof(FCEUGI)); + + GameInfo->soundchan = 0; + GameInfo->soundrate = 0; + GameInfo->name = "copyfami"; + GameInfo->type = GIT_CART; + GameInfo->vidsys = GIV_USER; + GameInfo->input[0] = GameInfo->input[1] = -1; + GameInfo->inputfc = -1; + GameInfo->cspecial = 0; + + FCEU_printf("Starting CopyFamicom...\n\n"); + + if (!CopyFamiLoad()) { + FCEU_PrintError("An error occurred while starting CopyFamicom."); + return 0; + } + + FCEU_ResetVidSys(); + if (GameInfo->type != GIT_NSF) + if (FSettings.GameGenie) + FCEU_OpenGenie(); + + PowerNES(); + FCEUSS_CheckStates(); + + if (GameInfo->type != GIT_NSF) { + FCEU_LoadGamePalette(); + FCEU_LoadGameCheats(0); + } + + FCEU_ResetPalette(); + FCEU_ResetMessages(); // Save state, status messages, etc. + + return(GameInfo); +} + +int FCEUI_Initialize(void) { + if (!FCEU_InitVirtualVideo()) + return 0; + memset(&FSettings, 0, sizeof(FSettings)); + FSettings.UsrFirstSLine[0] = 8; + FSettings.UsrFirstSLine[1] = 0; + FSettings.UsrLastSLine[0] = 231; + FSettings.UsrLastSLine[1] = 239; + FSettings.SoundVolume = 100; + FCEUPPU_Init(); + X6502_Init(); + return 1; +} + +void FCEUI_Kill(void) { + FCEU_KillVirtualVideo(); + FCEU_KillGenie(); +} + +void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int skip) { + int r, ssize; + + FCEU_UpdateInput(); + if (geniestage != 1) FCEU_ApplyPeriodicCheats(); + r = FCEUPPU_Loop(skip); + + ssize = FlushEmulateSound(); + + timestampbase += timestamp; + + timestamp = 0; + + *pXBuf = skip ? 0 : XBuf; + *SoundBuf = WaveFinal; + *SoundBufSize = ssize; +} + + +void ResetNES(void) +{ + if (!GameInfo) + return; + GameInterface(GI_RESETM2); + FCEUSND_Reset(); + FCEUPPU_Reset(); + X6502_Reset(); +} + +void FCEU_MemoryRand(uint8 *ptr, uint32 size) +{ + int x = 0; + while (size) { +// *ptr = (x & 4) ? 0xFF : 0x00; // Huang Di DEBUG MODE enabled by default + // Cybernoid NO MUSIC by default +// *ptr = (x & 4) ? 0x7F : 0x00; // Huang Di DEBUG MODE enabled by default + // Minna no Taabou no Nakayoshi Daisakusen DOESN'T BOOT + // Cybernoid NO MUSIC by default +// *ptr = (x & 1) ? 0x55 : 0xAA; // F-15 Sity War HISCORE is screwed... + // 1942 SCORE/HISCORE is screwed... + *ptr = 0xFF; + x++; + size--; + ptr++; + } +} + +void hand(X6502 *X, int type, uint32 A) +{ +} + +void PowerNES(void) +{ + if (!GameInfo) + return; + + FCEU_CheatResetRAM(); + FCEU_CheatAddRAM(2, 0, RAM); + + FCEU_GeniePower(); + +#ifndef COPYFAMI + FCEU_MemoryRand(RAM, 0x800); +#endif + + SetReadHandler(0x0000, 0xFFFF, ANull); + SetWriteHandler(0x0000, 0xFFFF, BNull); + +#ifdef COPYFAMI + SetReadHandler(0, 0x3FFF, ARAML); + SetWriteHandler(0, 0x3FFF, BRAML); +#else + SetReadHandler(0, 0x7FF, ARAML); + SetWriteHandler(0, 0x7FF, BRAML); + + SetReadHandler(0x800, 0x1FFF, ARAMH); /* Part of a little */ + SetWriteHandler(0x800, 0x1FFF, BRAMH); /* hack for a small speed boost. */ +#endif + InitializeInput(); + FCEUSND_Power(); + 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); + if (GameInfo->type == GIT_VSUNI) + FCEU_VSUniPower(); + + timestampbase = 0; + X6502_Power(); + FCEU_PowerCheats(); +} + +void FCEU_ResetVidSys(void) +{ + int w; + + if (GameInfo->vidsys == GIV_NTSC) + w = 0; + else if (GameInfo->vidsys == GIV_PAL) + w = 1; + else + w = FSettings.PAL; + + PAL = w ? 1 : 0; + + FCEUPPU_SetVideoSystem(w); + SetSoundVariables(); +} + +FCEUS FSettings; + +void FCEU_printf(char *format, ...) +{ + char temp[2048]; + + va_list ap; + + va_start(ap, format); + vsprintf(temp, format, ap); + FCEUD_Message(temp); + + va_end(ap); +} + +void FCEU_PrintError(char *format, ...) +{ + char temp[2048]; + + va_list ap; + + va_start(ap, format); + vsprintf(temp, format, ap); + FCEUD_PrintError(temp); + + va_end(ap); +} + +void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall) +{ + FSettings.UsrFirstSLine[0] = ntscf; + FSettings.UsrLastSLine[0] = ntscl; + FSettings.UsrFirstSLine[1] = palf; + FSettings.UsrLastSLine[1] = pall; + if (PAL) + { + FSettings.FirstSLine = FSettings.UsrFirstSLine[1]; + FSettings.LastSLine = FSettings.UsrLastSLine[1]; + } + else + { + FSettings.FirstSLine = FSettings.UsrFirstSLine[0]; + FSettings.LastSLine = FSettings.UsrLastSLine[0]; + } +} + +void FCEUI_SetVidSystem(int a) +{ + FSettings.PAL = a ? 1 : 0; + + if (!GameInfo) + return; + + FCEU_ResetVidSys(); + FCEU_ResetPalette(); +} + +int FCEUI_GetCurrentVidSystem(int *slstart, int *slend) +{ + if (slstart) + *slstart = FSettings.FirstSLine; + if (slend) + *slend = FSettings.LastSLine; + return(PAL); +} + +void FCEUI_SetGameGenie(int a) +{ + FSettings.GameGenie = a ? 1 : 0; +} + +void FCEUI_SetSnapName(int a) +{ + FSettings.SnapName = a; +} + +int32 FCEUI_GetDesiredFPS(void) +{ + if (PAL) + return(838977920); // ~50.007 + else + return(1008307711); // ~60.1 +} diff --git a/src/drivers/libretro/fceu/fds.c b/src/drivers/libretro/fceu/fds.c new file mode 100644 index 0000000..97a1654 --- /dev/null +++ b/src/drivers/libretro/fceu/fds.c @@ -0,0 +1,772 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "fceu-types.h" +#include "x6502.h" +#include "fceu.h" +#include "fds.h" +#include "sound.h" +#include "general.h" +#include "state.h" +#include "file.h" +#include "fceu-memory.h" +#include "cart.h" +#include "md5.h" +#include "netplay.h" + +// TODO: Add code to put a delay in between the time a disk is inserted +// and the when it can be successfully read/written to. This should +// prevent writes to wrong places OR add code to prevent disk ejects +// when the virtual motor is on(mmm...virtual motor). + +static DECLFR(FDSRead4030); +static DECLFR(FDSRead4031); +static DECLFR(FDSRead4032); +static DECLFR(FDSRead4033); + +static DECLFW(FDSWrite); + +static DECLFW(FDSWaveWrite); +static DECLFR(FDSWaveRead); + +static DECLFR(FDSSRead); +static DECLFW(FDSSWrite); + +static void FDSInit(void); +static void FDSClose(void); + +static void FP_FASTAPASS(1) FDSFix(int a); + +static uint8 FDSRegs[6]; +static int32 IRQLatch, IRQCount; +static uint8 IRQa; + +static uint8 *FDSRAM = NULL; +static uint32 FDSRAMSize; +static uint8 *FDSBIOS = NULL; +static uint32 FDSBIOSsize; +static uint8 *CHRRAM = NULL; +static uint32 CHRRAMSize; + +/* Original disk data backup, to help in creating save states. */ +static uint8 *diskdatao[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +static uint8 *diskdata[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +static uint32 TotalSides; +static uint8 DiskWritten = 0; /* Set to 1 if disk was written to. */ +static uint8 writeskip; +static int32 DiskPtr; +static int32 DiskSeekIRQ; +static uint8 SelectDisk, InDisk; + +uint32 lastDiskPtrRead, lastDiskPtrWrite; + +#define DC_INC 1 + +void FDSGI(int h) { + switch (h) { + case GI_CLOSE: FDSClose(); break; + case GI_POWER: FDSInit(); break; + } +} + +static void FDSStateRestore(int version) { + int x; + + setmirror(((FDSRegs[5] & 8) >> 3) ^ 1); + + if (version >= 9810) + for (x = 0; x < TotalSides; x++) { + int b; + for (b = 0; b < 65500; b++) + diskdata[x][b] ^= diskdatao[x][b]; + } +} + +void FDSSound(); +void FDSSoundReset(void); +void FDSSoundStateAdd(void); +static void RenderSound(void); +static void RenderSoundHQ(void); + +static void FDSInit(void) { + memset(FDSRegs, 0, sizeof(FDSRegs)); + lastDiskPtrRead = lastDiskPtrWrite = writeskip = DiskPtr = DiskSeekIRQ = 0; + + setmirror(1); + setprg8(0xE000, 0); // BIOS + setprg32r(1, 0x6000, 0); // 32KB RAM + setchr8(0); // 8KB CHR RAM + + MapIRQHook = FDSFix; + GameStateRestore = FDSStateRestore; + + SetReadHandler(0x4030, 0x4030, FDSRead4030); + SetReadHandler(0x4031, 0x4031, FDSRead4031); + SetReadHandler(0x4032, 0x4032, FDSRead4032); + SetReadHandler(0x4033, 0x4033, FDSRead4033); + + SetWriteHandler(0x4020, 0x4025, FDSWrite); + + SetWriteHandler(0x6000, 0xDFFF, CartBW); + SetReadHandler(0x6000, 0xFFFF, CartBR); + + IRQCount = IRQLatch = IRQa = 0; + + FDSSoundReset(); + InDisk = 0; + SelectDisk = 0; +} + +void FCEU_FDSInsert(int oride) { + if (InDisk == 255) { + FCEU_DispMessage("Disk %d Side %s Inserted", SelectDisk >> 1, (SelectDisk & 1) ? "B" : "A"); + InDisk = SelectDisk; + } else { + FCEU_DispMessage("Disk %d Side %s Ejected", SelectDisk >> 1, (SelectDisk & 1) ? "B" : "A"); + InDisk = 255; + } +} + +void FCEU_FDSEject(void) { + InDisk = 255; +} + +void FCEU_FDSSelect(void) { + if (InDisk != 255) { + FCEU_DispMessage("Eject disk before selecting."); + return; + } + SelectDisk = ((SelectDisk + 1) % TotalSides) & 3; + FCEU_DispMessage("Disk %d Side %s Selected", SelectDisk >> 1, (SelectDisk & 1) ? "B" : "A"); +} + +static void FP_FASTAPASS(1) FDSFix(int a) { + if ((IRQa & 2) && IRQCount) { + IRQCount -= a; + if (IRQCount <= 0) { + if (!(IRQa & 1)) { + IRQa &= ~2; + IRQCount = IRQLatch = 0; + } else + IRQCount = IRQLatch; + X6502_IRQBegin(FCEU_IQEXT); + } + } + if (DiskSeekIRQ > 0) { + DiskSeekIRQ -= a; + if (DiskSeekIRQ <= 0) { + if (FDSRegs[5] & 0x80) { + X6502_IRQBegin(FCEU_IQEXT2); + } + } + } +} + +static DECLFR(FDSRead4030) { + uint8 ret = 0; + + /* Cheap hack. */ + if (X.IRQlow & FCEU_IQEXT) ret |= 1; + if (X.IRQlow & FCEU_IQEXT2) ret |= 2; + + #ifdef FCEUDEF_DEBUGGER + if (!fceuindbg) + #endif + { + X6502_IRQEnd(FCEU_IQEXT); + X6502_IRQEnd(FCEU_IQEXT2); + } + return ret; +} + +static DECLFR(FDSRead4031) { + static uint8 z = 0; + if (InDisk != 255) { + z = diskdata[InDisk][DiskPtr]; + lastDiskPtrRead = DiskPtr; + #ifdef FCEUDEF_DEBUGGER + if (!fceuindbg) + #endif + { + if (DiskPtr < 64999) DiskPtr++; + DiskSeekIRQ = 150; + X6502_IRQEnd(FCEU_IQEXT2); + } + } + return z; +} +static DECLFR(FDSRead4032) { + uint8 ret; + + ret = X.DB & ~7; + if (InDisk == 255) + ret |= 5; + + if (InDisk == 255 || !(FDSRegs[5] & 1) || (FDSRegs[5] & 2)) + ret |= 2; + return ret; +} + +static DECLFR(FDSRead4033) { + return 0x80; // battery +} + +/* Begin FDS sound */ + +#define FDSClock (1789772.7272727272727272 / 2) + +typedef struct { + int64 cycles; // Cycles per PCM sample + int64 count; // Cycle counter + int64 envcount; // Envelope cycle counter + uint32 b19shiftreg60; + uint32 b24adder66; + uint32 b24latch68; + uint32 b17latch76; + int32 clockcount; // Counter to divide frequency by 8. + uint8 b8shiftreg88; // Modulation register. + uint8 amplitude[2]; // Current amplitudes. + uint8 speedo[2]; + uint8 mwcount; + uint8 mwstart; + uint8 mwave[0x20]; // Modulation waveform + uint8 cwave[0x40]; // Game-defined waveform(carrier) + uint8 SPSG[0xB]; +} FDSSOUND; + +static FDSSOUND fdso; + +#define SPSG fdso.SPSG +#define b19shiftreg60 fdso.b19shiftreg60 +#define b24adder66 fdso.b24adder66 +#define b24latch68 fdso.b24latch68 +#define b17latch76 fdso.b17latch76 +#define b8shiftreg88 fdso.b8shiftreg88 +#define clockcount fdso.clockcount +#define amplitude fdso.amplitude +#define speedo fdso.speedo + +void FDSSoundStateAdd(void) { + AddExState(fdso.cwave, 64, 0, "WAVE"); + AddExState(fdso.mwave, 32, 0, "MWAV"); + AddExState(amplitude, 2, 0, "AMPL"); + AddExState(SPSG, 0xB, 0, "SPSG"); + + AddExState(&b8shiftreg88, 1, 0, "B88"); + + AddExState(&clockcount, 4, 1, "CLOC"); + AddExState(&b19shiftreg60, 4, 1, "B60"); + AddExState(&b24adder66, 4, 1, "B66"); + AddExState(&b24latch68, 4, 1, "B68"); + AddExState(&b17latch76, 4, 1, "B76"); +} + +static DECLFR(FDSSRead) { + switch (A & 0xF) { + case 0x0: return(amplitude[0] | (X.DB & 0xC0)); + case 0x2: return(amplitude[1] | (X.DB & 0xC0)); + } + return(X.DB); +} + +static DECLFW(FDSSWrite) { + if (FSettings.SndRate) { + if (FSettings.soundq >= 1) + RenderSoundHQ(); + else + RenderSound(); + } + A -= 0x4080; + switch (A) { + case 0x0: + case 0x4: + if (V & 0x80) + amplitude[(A & 0xF) >> 2] = V & 0x3F; + break; + case 0x7: + b17latch76 = 0; + SPSG[0x5] = 0; + break; + case 0x8: + b17latch76 = 0; + fdso.mwave[SPSG[0x5] & 0x1F] = V & 0x7; + SPSG[0x5] = (SPSG[0x5] + 1) & 0x1F; + break; + } + SPSG[A] = V; +} + +// $4080 - Fundamental wave amplitude data register 92 +// $4082 - Fundamental wave frequency data register 58 +// $4083 - Same as $4082($4083 is the upper 4 bits). + +// $4084 - Modulation amplitude data register 78 +// $4086 - Modulation frequency data register 72 +// $4087 - Same as $4086($4087 is the upper 4 bits) + + +static void DoEnv() { + int x; + + for (x = 0; x < 2; x++) + if (!(SPSG[x << 2] & 0x80) && !(SPSG[0x3] & 0x40)) { + static int counto[2] = { 0, 0 }; + + if (counto[x] <= 0) { + if (!(SPSG[x << 2] & 0x80)) { + if (SPSG[x << 2] & 0x40) { + if (amplitude[x] < 0x3F) + amplitude[x]++; + } else { + if (amplitude[x] > 0) + amplitude[x]--; + } + } + counto[x] = (SPSG[x << 2] & 0x3F); + } else + counto[x]--; + } +} + +static DECLFR(FDSWaveRead) { + return(fdso.cwave[A & 0x3f] | (X.DB & 0xC0)); +} + +static DECLFW(FDSWaveWrite) { + if (SPSG[0x9] & 0x80) + fdso.cwave[A & 0x3f] = V & 0x3F; +} + +static int ta; +static INLINE void ClockRise(void) { + if (!clockcount) { + ta++; + + b19shiftreg60 = (SPSG[0x2] | ((SPSG[0x3] & 0xF) << 8)); + b17latch76 = (SPSG[0x6] | ((SPSG[0x07] & 0xF) << 8)) + b17latch76; + + if (!(SPSG[0x7] & 0x80)) { + int t = fdso.mwave[(b17latch76 >> 13) & 0x1F] & 7; + int t2 = amplitude[1]; + int adj = 0; + + if ((t & 3)) { + if ((t & 4)) + adj -= (t2 * ((4 - (t & 3)))); + else + adj += (t2 * ((t & 3))); + } + adj *= 2; + if (adj > 0x7F) adj = 0x7F; + if (adj < -0x80) adj = -0x80; + b8shiftreg88 = 0x80 + adj; + } else { + b8shiftreg88 = 0x80; + } + } else { + b19shiftreg60 <<= 1; + b8shiftreg88 >>= 1; + } + b24adder66 = (b24latch68 + b19shiftreg60) & 0x1FFFFFF; +} + +static INLINE void ClockFall(void) { + if ((b8shiftreg88 & 1)) + b24latch68 = b24adder66; + clockcount = (clockcount + 1) & 7; +} + +static INLINE int32 FDSDoSound(void) { + fdso.count += fdso.cycles; + if (fdso.count >= ((int64)1 << 40)) { + dogk: + fdso.count -= (int64)1 << 40; + ClockRise(); + ClockFall(); + fdso.envcount--; + if (fdso.envcount <= 0) { + fdso.envcount += SPSG[0xA] * 3; + DoEnv(); + } + } + if (fdso.count >= 32768) goto dogk; + + // Might need to emulate applying the amplitude to the waveform a bit better... + { + int k = amplitude[0]; + if (k > 0x20) k = 0x20; + return (fdso.cwave[b24latch68 >> 19] * k) * 4 / ((SPSG[0x9] & 0x3) + 2); + } +} + +static int32 FBC = 0; + +static void RenderSound(void) { + int32 end, start; + int32 x; + + start = FBC; + end = (SOUNDTS << 16) / soundtsinc; + if (end <= start) + return; + FBC = end; + + if (!(SPSG[0x9] & 0x80)) + for (x = start; x < end; x++) { + uint32 t = FDSDoSound(); + t += t >> 1; + t >>= 4; + Wave[x >> 4] += t; //(t>>2)-(t>>3); //>>3; + } +} + +static void RenderSoundHQ(void) { + uint32 x; + + if (!(SPSG[0x9] & 0x80)) + for (x = FBC; x < SOUNDTS; x++) { + uint32 t = FDSDoSound(); + t += t >> 1; + WaveHi[x] += t; //(t<<2)-(t<<1); + } + FBC = SOUNDTS; +} + +static void HQSync(int32 ts) { + FBC = ts; +} + +void FDSSound(int c) { + RenderSound(); + FBC = c; +} + +static void FDS_ESI(void) { + if (FSettings.SndRate) { + if (FSettings.soundq >= 1) { + fdso.cycles = (int64)1 << 39; + } else { + fdso.cycles = ((int64)1 << 40) * FDSClock; + fdso.cycles /= FSettings.SndRate * 16; + } + } + SetReadHandler(0x4040, 0x407f, FDSWaveRead); + SetWriteHandler(0x4040, 0x407f, FDSWaveWrite); + SetWriteHandler(0x4080, 0x408A, FDSSWrite); + SetReadHandler(0x4090, 0x4092, FDSSRead); +} + +void FDSSoundReset(void) { + memset(&fdso, 0, sizeof(fdso)); + FDS_ESI(); + GameExpSound.HiSync = HQSync; + GameExpSound.HiFill = RenderSoundHQ; + GameExpSound.Fill = FDSSound; + GameExpSound.RChange = FDS_ESI; +} + +static DECLFW(FDSWrite) { + switch (A) { + case 0x4020: + X6502_IRQEnd(FCEU_IQEXT); + IRQLatch &= 0xFF00; + IRQLatch |= V; + break; + case 0x4021: + X6502_IRQEnd(FCEU_IQEXT); + IRQLatch &= 0xFF; + IRQLatch |= V << 8; + break; + case 0x4022: + X6502_IRQEnd(FCEU_IQEXT); + IRQCount = IRQLatch; + IRQa = V & 3; + break; + case 0x4024: + if ((InDisk != 255) && !(FDSRegs[5] & 0x4) && (FDSRegs[3] & 0x1)) { + if (DiskPtr >= 0 && DiskPtr < 65500) { + if (writeskip) + writeskip--; + else if (DiskPtr >= 2) { + DiskWritten = 1; + diskdata[InDisk][DiskPtr - 2] = V; + lastDiskPtrWrite = DiskPtr - 2; + } + } + } + break; + case 0x4025: + X6502_IRQEnd(FCEU_IQEXT2); + if (InDisk != 255) { + if (!(V & 0x40)) { + if ((FDSRegs[5] & 0x40) && !(V & 0x10)) { + DiskSeekIRQ = 200; + DiskPtr -= 2; + } + if (DiskPtr < 0) DiskPtr = 0; + } + if (!(V & 0x4)) writeskip = 2; + if (V & 2) { + DiskPtr = 0; DiskSeekIRQ = 200; + } + if (V & 0x40) DiskSeekIRQ = 200; + } + setmirror(((V >> 3) & 1) ^ 1); + break; + } + FDSRegs[A & 7] = V; +} + +static void FreeFDSMemory(void) { + int x; + + for (x = 0; x < TotalSides; x++) + if (diskdata[x]) { + free(diskdata[x]); + diskdata[x] = 0; + } +} + +static int SubLoad(FCEUFILE *fp) { + struct md5_context md5; + uint8 header[16]; + int x; + + FCEU_fread(header, 16, 1, fp); + + if (memcmp(header, "FDS\x1a", 4)) { + if (!(memcmp(header + 1, "*NINTENDO-HVC*", 14))) { + long t; + t = FCEU_fgetsize(fp); + if (t < 65500) + t = 65500; + TotalSides = t / 65500; + FCEU_fseek(fp, 0, SEEK_SET); + } else + return(0); + } else + TotalSides = header[4]; + + md5_starts(&md5); + + if (TotalSides > 8) TotalSides = 8; + if (TotalSides < 1) TotalSides = 1; + + for (x = 0; x < TotalSides; x++) { + diskdata[x] = (uint8*)FCEU_malloc(65500); + if (!diskdata[x]) { + int zol; + for (zol = 0; zol < x; zol++) + free(diskdata[zol]); + return 0; + } + FCEU_fread(diskdata[x], 1, 65500, fp); + md5_update(&md5, diskdata[x], 65500); + } + md5_finish(&md5, GameInfo->MD5); + return(1); +} + +static void PreSave(void) { + int x; + for (x = 0; x < TotalSides; x++) { + int b; + for (b = 0; b < 65500; b++) + diskdata[x][b] ^= diskdatao[x][b]; + } +} + +static void PostSave(void) { + int x; + for (x = 0; x < TotalSides; x++) { + int b; + for (b = 0; b < 65500; b++) + diskdata[x][b] ^= diskdatao[x][b]; + } +} + +int FDSLoad(const char *name, FCEUFILE *fp) { + FILE *zp; + int x; + + char *fn = FCEU_MakeFName(FCEUMKF_FDSROM, 0, 0); + + if (!(zp = fopen(fn, "rb"))) { + FCEU_PrintError("FDS BIOS ROM image missing!"); + free(fn); + return 0; + } + + free(fn); + + ResetCartMapping(); + + if (FDSBIOS) + free(FDSBIOS); + FDSBIOS = NULL; + if (FDSRAM) + free(FDSRAM); + FDSRAM = NULL; + if (CHRRAM) + free(CHRRAM); + CHRRAM = NULL; + + FDSBIOSsize = 8192; + FDSBIOS = (uint8*)FCEU_gmalloc(FDSBIOSsize); + SetupCartPRGMapping(0, FDSBIOS, FDSBIOSsize, 0); + + if (fread(FDSBIOS, 1, FDSBIOSsize, zp) != FDSBIOSsize) { + if (FDSBIOS) + free(FDSBIOS); + FDSBIOS = NULL; + fclose(zp); + FCEU_PrintError("Error reading FDS BIOS ROM image."); + return 0; + } + + fclose(zp); + + FCEU_fseek(fp, 0, SEEK_SET); + + FreeFDSMemory(); + if (!SubLoad(fp)) { + if (FDSBIOS) + free(FDSBIOS); + FDSBIOS = NULL; + return(0); + } + + { + FCEUFILE *tp; + char *fn = FCEU_MakeFName(FCEUMKF_FDS, 0, 0); + + int x; + for (x = 0; x < TotalSides; x++) { + diskdatao[x] = (uint8*)FCEU_malloc(65500); + memcpy(diskdatao[x], diskdata[x], 65500); + } + + if ((tp = FCEU_fopen(fn, 0, "rb", 0, NULL, 0))) { + FCEU_printf("Disk was written. Auxillary FDS file open \"%s\".\n", fn); + FreeFDSMemory(); + if (!SubLoad(tp)) { + FCEU_PrintError("Error reading auxillary FDS file."); + if (FDSBIOS) + free(FDSBIOS); + FDSBIOS = NULL; + free(fn); + return(0); + } + FCEU_fclose(tp); + DiskWritten = 1; /* For save state handling. */ + } + free(fn); + } + + GameInfo->type = GIT_FDS; + GameInterface = FDSGI; + + SelectDisk = 0; + InDisk = 255; + + ResetExState(PreSave, PostSave); + FDSSoundStateAdd(); + + for (x = 0; x < TotalSides; x++) { + char temp[5]; + sprintf(temp, "DDT%d", x); + AddExState(diskdata[x], 65500, 0, temp); + } + + AddExState(FDSRegs, sizeof(FDSRegs), 0, "FREG"); + AddExState(&IRQCount, 4, 1, "IRQC"); + AddExState(&IRQLatch, 4, 1, "IQL1"); + AddExState(&IRQa, 1, 0, "IRQA"); + AddExState(&writeskip, 1, 0, "WSKI"); + AddExState(&DiskPtr, 4, 1, "DPTR"); + AddExState(&DiskSeekIRQ, 4, 1, "DSIR"); + AddExState(&SelectDisk, 1, 0, "SELD"); + AddExState(&InDisk, 1, 0, "INDI"); + AddExState(&DiskWritten, 1, 0, "DSKW"); + + CHRRAMSize = 8192; + CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSize); + memset(CHRRAM, 0, CHRRAMSize); + SetupCartCHRMapping(0, CHRRAM, CHRRAMSize, 1); + AddExState(CHRRAM, CHRRAMSize, 0, "CHRR"); + + FDSRAMSize = 32768; + FDSRAM = (uint8*)FCEU_gmalloc(FDSRAMSize); + memset(FDSRAM, 0, FDSRAMSize); + SetupCartPRGMapping(1, FDSRAM, FDSRAMSize, 1); + AddExState(FDSRAM, FDSRAMSize, 0, "FDSR"); + + SetupCartMirroring(0, 0, 0); + + FCEU_printf(" Sides: %d\n\n", TotalSides); + return 1; +} + +void FDSClose(void) { + FILE *fp; + int x; + char *fn = FCEU_MakeFName(FCEUMKF_FDS, 0, 0); + + if (!DiskWritten) return; + + if (!(fp = fopen(fn, "wb"))) { + free(fn); + return; + } + FCEU_printf("FDS Save \"%s\"\n", fn); + free(fn); + + for (x = 0; x < TotalSides; x++) { + if (fwrite(diskdata[x], 1, 65500, fp) != 65500) { + FCEU_PrintError("Error saving FDS image!"); + fclose(fp); + return; + } + } + + for (x = 0; x < TotalSides; x++) + if (diskdatao[x]) { + free(diskdatao[x]); + diskdatao[x] = 0; + } + + FreeFDSMemory(); + if (FDSBIOS) + free(FDSBIOS); + FDSBIOS = NULL; + if (FDSRAM) + free(FDSRAM); + FDSRAM = NULL; + if (CHRRAM) + free(CHRRAM); + CHRRAM = NULL; + fclose(fp); +} diff --git a/src/drivers/libretro/fceu/file.c b/src/drivers/libretro/fceu/file.c new file mode 100644 index 0000000..5c8cf05 --- /dev/null +++ b/src/drivers/libretro/fceu/file.c @@ -0,0 +1,185 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#ifdef _WIN32 +#include +#else +#include +#endif + +#include "fceu-types.h" +#include "file.h" +#include "fceu-endian.h" +#include "fceu-memory.h" +#include "driver.h" +#include "general.h" + +#ifndef __GNUC__ + #define strcasecmp strcmp +#endif + +static MEMWRAP *MakeMemWrap(void *tz, int type) +{ + MEMWRAP *tmp; + + if (!(tmp = (MEMWRAP*)FCEU_malloc(sizeof(MEMWRAP)))) + goto doret; + tmp->location = 0; + + fseek((FILE*)tz, 0, SEEK_END); + tmp->size = ftell((FILE*)tz); + fseek((FILE*)tz, 0, SEEK_SET); + if (!(tmp->data = (uint8*)FCEU_malloc(tmp->size))) + { + free(tmp); + tmp = 0; + goto doret; + } + fread(tmp->data, 1, tmp->size, (FILE*)tz); + +doret: + if (type == 0) + fclose((FILE*)tz); + return tmp; +} + +static MEMWRAP *MakeMemWrapBuffer(void *tz, int type, uint8 *buffer, size_t bufsize) +{ + MEMWRAP *tmp = (MEMWRAP*)FCEU_malloc(sizeof(MEMWRAP)); + + if (!tmp) + return NULL; + + tmp->location = 0; + tmp->size = bufsize; + tmp->data = buffer; + + return tmp; +} + +FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn, + char *mode, char *ext, uint8 *buffer, size_t bufsize) +{ + FCEUFILE *fceufp = (FCEUFILE*)malloc(sizeof(FCEUFILE)); + void *t = fopen(path, mode); + + if (!t) + { + free(fceufp); + return 0; + } + + fseek((FILE*)t, 0, SEEK_SET); + fceufp->type = 0; + if (buffer) + fceufp->fp = MakeMemWrapBuffer(t, 0, buffer, bufsize); + else + fceufp->fp = MakeMemWrap(t, 0); + return fceufp; +} + +int FCEU_fclose(FCEUFILE *fp) +{ + if (fp->fp) + free(fp->fp); + fp->fp = NULL; + free(fp); + fp = 0; + return 1; +} + +uint64 FCEU_fread(void *ptr, size_t element_size, size_t nmemb, FCEUFILE *fp) +{ + uint32_t total = nmemb * element_size; + + if (fp->fp->location >= fp->fp->size) + return 0; + + if((fp->fp->location + total) > fp->fp->size) + { + int64_t ak = fp->fp->size - fp->fp->location; + + memcpy((uint8_t*)ptr, fp->fp->data + fp->fp->location, ak); + + fp->fp->location = fp->fp->size; + + return (ak / element_size); + } + + memcpy((uint8_t*)ptr, fp->fp->data + fp->fp->location, total); + + fp->fp->location += total; + + return nmemb; +} + +int FCEU_fseek(FCEUFILE *fp, long offset, int whence) +{ + switch (whence) + { + case SEEK_SET: + if (offset >= fp->fp->size) + return -1; + + fp->fp->location = offset; + break; + case SEEK_CUR: + if ((offset + fp->fp->location) > fp->fp->size) + return -1; + + fp->fp->location += offset; + break; + } + + return 0; +} + +int FCEU_read32le(uint32 *Bufo, FCEUFILE *fp) +{ + if ((fp->fp->location + 4) > fp->fp->size) + return 0; + + *Bufo = FCEU_de32lsb(fp->fp->data + fp->fp->location); + + fp->fp->location += 4; + + return 1; +} + +int FCEU_fgetc(FCEUFILE *fp) +{ + if (fp->fp->location < fp->fp->size) + return fp->fp->data[fp->fp->location++]; + + return EOF; +} + +uint64 FCEU_ftell(FCEUFILE *fp) +{ + return fp->fp->location; +} + +uint64 FCEU_fgetsize(FCEUFILE *fp) +{ + return fp->fp->size; +} diff --git a/src/drivers/libretro/fceu/general.c b/src/drivers/libretro/fceu/general.c new file mode 100644 index 0000000..0cc96dd --- /dev/null +++ b/src/drivers/libretro/fceu/general.c @@ -0,0 +1,162 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +#include +#include +#ifdef _WIN32 +#include +#else +#include +#endif + +#include "fceu-types.h" +#include "fceu.h" + +#include "general.h" +#include "state.h" + +#include "driver.h" + +#include "md5.h" + +static char BaseDirectory[2048]; +static char FileBase[2048]; +static char FileExt[2048]; /* Includes the . character, as in ".nes" */ + +static char FileBaseDirectory[2048]; + +void FCEUI_SetBaseDirectory(char *dir) +{ + strncpy(BaseDirectory, dir, 2047); + BaseDirectory[2047] = 0; +} + +static char *odirs[FCEUIOD__COUNT] = { 0, 0, 0, 0, 0, 0 }; // odirs, odors. ^_^ + +void FCEUI_SetDirOverride(int which, char *n) +{ + odirs[which] = n; + + /* Rebuild cache of present states/movies. */ + if (GameInfo) + { + if (which == FCEUIOD_STATE) + FCEUSS_CheckStates(); + } +} + +#ifndef HAVE_ASPRINTF +static int asprintf(char **strp, const char *fmt, ...) { + va_list ap; + int ret; + + va_start(ap, fmt); + if (!(*strp = malloc(2048))) + return(0); + ret = vsnprintf(*strp, 2048, fmt, ap); + va_end(ap); + return(ret); +} +#endif + +char *FCEU_MakeFName(int type, int id1, char *cd1) +{ + char *ret = 0; + struct stat tmpstat; + + switch (type) + { + case FCEUMKF_GGROM: + asprintf(&ret, "%s"PSS "gg.rom", BaseDirectory); + break; + case FCEUMKF_FDSROM: + asprintf(&ret, "%s"PSS "disksys.rom", BaseDirectory); + break; + case FCEUMKF_PALETTE: + if (odirs[FCEUIOD_MISC]) + asprintf(&ret, "%s"PSS "%s.pal", odirs[FCEUIOD_MISC], FileBase); + else + asprintf(&ret, "%s"PSS "gameinfo"PSS "%s.pal", BaseDirectory, FileBase); + break; + default: + ret = malloc(1); + *ret = '\0'; + } + return(ret); +} + +void GetFileBase(const char *f) +{ + const char *tp1, *tp3; + +#if PSS_STYLE == 4 + tp1 = ((char*)strrchr(f, ':')); +#elif PSS_STYLE == 1 + tp1 = ((char*)strrchr(f, '/')); +#else + tp1 = ((char*)strrchr(f, '\\')); +#if PSS_STYLE != 3 + tp3 = ((char*)strrchr(f, '/')); + if (tp1 < tp3) tp1 = tp3; +#endif +#endif + if (!tp1) + { + tp1 = f; + strcpy(FileBaseDirectory, "."); + } + else + { + memcpy(FileBaseDirectory, f, tp1 - f); + FileBaseDirectory[tp1 - f] = 0; + tp1++; + } + + if (((tp3 = strrchr(f, '.')) != NULL) && (tp3 > tp1)) + { + memcpy(FileBase, tp1, tp3 - tp1); + FileBase[tp3 - tp1] = 0; + strcpy(FileExt, tp3); + } + else + { + strcpy(FileBase, tp1); + FileExt[0] = 0; + } +} + +uint32 uppow2(uint32 n) +{ + int x; + + for (x = 31; x >= 0; x--) + if (n & (1 << x)) + { + if ((1 << x) != n) + return(1 << (x + 1)); + break; + } + return n; +} diff --git a/src/drivers/libretro/fceu/ines.c b/src/drivers/libretro/fceu/ines.c new file mode 100644 index 0000000..f78b9c1 --- /dev/null +++ b/src/drivers/libretro/fceu/ines.c @@ -0,0 +1,839 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 1998 BERO + * Copyright (C) 2002 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "fceu-types.h" +#include "x6502.h" +#include "fceu.h" +#include "cart.h" +#include "ppu.h" + +#include "ines.h" +#include "unif.h" +#include "state.h" +#include "file.h" +#include "general.h" +#include "fceu-memory.h" +#include "crc32.h" +#include "md5.h" +#include "cheat.h" +#include "vsuni.h" + +extern SFORMAT FCEUVSUNI_STATEINFO[]; + +uint8 *trainerpoo = NULL; +uint8 *ROM = NULL; +uint8 *VROM = NULL; +uint8 *ExtraNTARAM = NULL; +iNES_HEADER head; + +CartInfo iNESCart; + +uint8 Mirroring = 0; +uint32 ROM_size = 0; +uint32 VROM_size = 0; + +static int CHRRAMSize = -1; +static int iNES_Init(int num); + +static int MapperNo = 0; + +static DECLFR(TrainerRead) { + return(trainerpoo[A & 0x1FF]); +} + +static void iNES_ExecPower() { + if (iNESCart.Power) + iNESCart.Power(); + + if (trainerpoo) { + int x; + for (x = 0; x < 512; x++) { + X6502_DMW(0x7000 + x, trainerpoo[x]); + if (X6502_DMR(0x7000 + x) != trainerpoo[x]) { + SetReadHandler(0x7000, 0x71FF, TrainerRead); + break; + } + } + } +} + +static void iNESGI(int h) { + switch (h) { + case GI_RESETM2: + if (iNESCart.Reset) + iNESCart.Reset(); + break; + case GI_POWER: + iNES_ExecPower(); + break; + case GI_CLOSE: + { + FCEU_SaveGameSave(&iNESCart); + if (iNESCart.Close) + iNESCart.Close(); + if (ROM) { + free(ROM); + ROM = NULL; + } + if (VROM) { + free(VROM); + VROM = NULL; + } + if (trainerpoo) { + free(trainerpoo); + trainerpoo = NULL; + } + if (ExtraNTARAM) { + free(ExtraNTARAM); + ExtraNTARAM = NULL; + } + } + break; + } +} + +uint32 iNESGameCRC32 = 0; + +struct CRCMATCH { + uint32 crc; + char *name; +}; + +struct INPSEL { + uint32 crc32; + int input1; + int input2; + int inputfc; +}; + +static void SetInput(void) { + static struct INPSEL moo[] = + { + {0x19b0a9f1, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // 6-in-1 (MGC-023)(Unl)[!] + {0x29de87af, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Aerobics Studio + {0xd89e5a67, SI_UNSET, SI_UNSET, SIFC_ARKANOID }, // Arkanoid (J) + {0x0f141525, SI_UNSET, SI_UNSET, SIFC_ARKANOID }, // Arkanoid 2(J) + {0x32fb0583, SI_UNSET, SI_ARKANOID, SIFC_NONE }, // Arkanoid(NES) + {0x60ad090a, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Athletic World + {0x48ca0ee1, SI_GAMEPAD, SI_GAMEPAD, SIFC_BWORLD }, // Barcode World + {0x4318a2f8, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Barker Bill's Trick Shooting + {0x6cca1c1f, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Dai Undoukai + {0x24598791, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Duck Hunt + {0xd5d6eac4, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Edu (As) + {0xe9a7fe9e, SI_UNSET, SI_MOUSE, SIFC_NONE }, // Educational Computer 2000 + {0x8f7b1669, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // FP BASIC 3.3 by maxzhou88 + {0xf7606810, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC 2.0A + {0x895037bc, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC 2.1a + {0xb2530afc, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC 3.0 + {0xea90f3e2, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Family Trainer: Running Stadium + {0xbba58be5, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Family Trainer: Manhattan Police + {0x3e58a87e, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Freedom Force + {0xd9f45be9, SI_GAMEPAD, SI_GAMEPAD, SIFC_QUIZKING }, // Gimme a Break ... + {0x1545bd13, SI_GAMEPAD, SI_GAMEPAD, SIFC_QUIZKING }, // Gimme a Break ... 2 + {0x4e959173, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Gotcha! - The Sport! + {0xbeb8ab01, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Gumshoe + {0xff24d794, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Hogan's Alley + {0x21f85681, SI_GAMEPAD, SI_GAMEPAD, SIFC_HYPERSHOT }, // Hyper Olympic (Gentei Ban) + {0x980be936, SI_GAMEPAD, SI_GAMEPAD, SIFC_HYPERSHOT }, // Hyper Olympic + {0x915a53a7, SI_GAMEPAD, SI_GAMEPAD, SIFC_HYPERSHOT }, // Hyper Sports + {0x9fae4d46, SI_GAMEPAD, SI_GAMEPAD, SIFC_MAHJONG }, // Ide Yousuke Meijin no Jissen Mahjong + {0x7b44fb2a, SI_GAMEPAD, SI_GAMEPAD, SIFC_MAHJONG }, // Ide Yousuke Meijin no Jissen Mahjong 2 + {0x2f128512, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Jogging Race + {0xbb33196f, SI_UNSET, SI_UNSET, SIFC_FKB }, // Keyboard Transformer + {0x8587ee00, SI_UNSET, SI_UNSET, SIFC_FKB }, // Keyboard Transformer + {0x543ab532, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // LIKO Color Lines + {0x368c19a8, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // LIKO Study Cartridge + {0x5ee6008e, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Mechanized Attack + {0x370ceb65, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Meiro Dai Sakusen + {0x3a1694f9, SI_GAMEPAD, SI_GAMEPAD, SIFC_4PLAYER }, // Nekketsu Kakutou Densetsu + {0x9d048ea4, SI_GAMEPAD, SI_GAMEPAD, SIFC_OEKAKIDS }, // Oeka Kids + {0x2a6559a1, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Operation Wolf (J) + {0xedc3662b, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Operation Wolf + {0x912989dc, SI_UNSET, SI_UNSET, SIFC_FKB }, // Playbox BASIC + {0x9044550e, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Rairai Kyonshizu + {0xea90f3e2, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Running Stadium + {0x851eb9be, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // Shooting Range + {0x6435c095, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, // Short Order/Eggsplode + {0xc043a8df, SI_UNSET, SI_MOUSE, SIFC_NONE }, // Shu Qi Yu - Shu Xue Xiao Zhuan Yuan (Ch) + {0x2cf5db05, SI_UNSET, SI_MOUSE, SIFC_NONE }, // Shu Qi Yu - Zhi Li Xiao Zhuan Yuan (Ch) + {0xad9c63e2, SI_GAMEPAD, SI_UNSET, SIFC_SHADOW }, // Space Shadow + {0x61d86167, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, // Street Cop + {0xabb2f974, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Study and Game 32-in-1 + {0x41ef9ac4, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor + {0x8b265862, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor + {0x82f1fb96, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor 1.0 Russian + {0x9f8f200a, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERA }, // Super Mogura Tataki!! - Pokkun Moguraa + {0xd74b2719, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, // Super Team Games + {0x74bea652, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // Supergun 3-in-1 + {0x5e073a1b, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Supor English (Chinese) + {0x589b6b0d, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // SuporV20 + {0x41401c6d, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // SuporV40 + {0x23d17f5e, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // The Lone Ranger + {0xc3c0811d, SI_GAMEPAD, SI_GAMEPAD, SIFC_OEKAKIDS }, // The two "Oeka Kids" games + {0xde8fd935, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // To the Earth + {0x47232739, SI_GAMEPAD, SI_GAMEPAD, SIFC_TOPRIDER }, // Top Rider + {0x8a12a7d9, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Totsugeki Fuuun Takeshi Jou + {0xb8b9aca3, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Wild Gunman + {0x5112dc21, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Wild Gunman + {0xaf4010ea, SI_GAMEPAD, SI_POWERPADB, SIFC_UNSET }, // World Class Track Meet + {0x00000000, SI_UNSET, SI_UNSET, SIFC_UNSET } + }; + int x = 0; + + while (moo[x].input1 >= 0 || moo[x].input2 >= 0 || moo[x].inputfc >= 0) { + if (moo[x].crc32 == iNESGameCRC32) { + GameInfo->input[0] = moo[x].input1; + GameInfo->input[1] = moo[x].input2; + GameInfo->inputfc = moo[x].inputfc; + break; + } + x++; + } +} + +#define INESB_INCOMPLETE 1 +#define INESB_CORRUPT 2 +#define INESB_HACKED 4 + +struct BADINF { + uint64 md5partial; + uint8 *name; + uint32 type; +}; + +static struct BADINF BadROMImages[] = +{ + #include "ines-bad.h" +}; + +void CheckBad(uint64 md5partial) { + int32 x = 0; + while (BadROMImages[x].name) { + if (BadROMImages[x].md5partial == md5partial) { + FCEU_PrintError("The copy game you have loaded, \"%s\", is bad, and will not work properly in FCE Ultra.", BadROMImages[x].name); + return; + } + x++; + } +} + + +struct CHINF { + uint32 crc32; + int32 mapper; + int32 mirror; +}; + +static void CheckHInfo(void) { + /* ROM images that have the battery-backed bit set in the header that really + don't have battery-backed RAM is not that big of a problem, so I'll + treat this differently by only listing games that should have battery-backed RAM. + + Lower 64 bits of the MD5 hash. + */ + + static uint64 savie[] = + { + 0xc04361e499748382LL, /* AD&D Heroes of the Lance */ + 0xb72ee2337ced5792LL, /* AD&D Hillsfar */ + 0x2b7103b7a27bd72fLL, /* AD&D Pool of Radiance */ + 0x498c10dc463cfe95LL, /* Battle Fleet */ + 0x854d7947a3177f57LL, /* Crystalis */ + 0x4a1f5336b86851b6LL, /* DW */ + 0xb0bcc02c843c1b79LL, /* DW */ + 0x2dcf3a98c7937c22LL, /* DW 2 */ + 0x98e55e09dfcc7533LL, /* DW 4*/ + 0x733026b6b72f2470LL, /* Dw 3 */ + 0x6917ffcaca2d8466LL, /* Famista '90 */ + 0x8da46db592a1fcf4LL, /* Faria */ + 0xedba17a2c4608d20LL, /* Final Fantasy */ + 0x91a6846d3202e3d6LL, /* Final Fantasy */ + 0x012df596e2b31174LL, /* Final Fantasy 1+2 */ + 0xf6b359a720549ecdLL, /* Final Fantasy 2 */ + 0x5a30da1d9b4af35dLL, /* Final Fantasy 3 */ + 0xd63dcc68c2b20adcLL, /* Final Fantasy J */ + 0x2ee3417ba8b69706LL, /* Hydlide 3*/ + 0xebbce5a54cf3ecc0LL, /* Justbreed */ + 0x6a858da551ba239eLL, /* Kaijuu Monogatari */ + 0x2db8f5d16c10b925LL, /* Kyonshiizu 2 */ + 0x04a31647de80fdabLL, /* Legend of Zelda */ + 0x94b9484862a26cbaLL, /* Legend of Zelda */ + 0xa40666740b7d22feLL, /* Mindseeker */ + 0x82000965f04a71bbLL, /* Mirai Shinwa Jarvas */ + 0x77b811b2760104b9LL, /* Mouryou Senki Madara */ + 0x11b69122efe86e8cLL, /* RPG Jinsei Game */ + 0x9aa1dc16c05e7de5LL, /* Startropics */ + 0x1b084107d0878bd0LL, /* Startropics 2*/ + 0xa70b495314f4d075LL, /* Ys 3 */ + 0x836c0ff4f3e06e45LL, /* Zelda 2 */ + 0 /* Abandon all hope if the game has 0 in the lower 64-bits of its MD5 hash */ + }; + + static struct CHINF moo[] = + { + #include "ines-correct.h" + }; + int32 tofix = 0, x; + uint64 partialmd5 = 0; + + for (x = 0; x < 8; x++) + partialmd5 |= (uint64)iNESCart.MD5[15 - x] << (x * 8); + CheckBad(partialmd5); + + x = 0; + do { + if (moo[x].crc32 == iNESGameCRC32) { + if (moo[x].mapper >= 0) { + if (moo[x].mapper & 0x800 && VROM_size) { + VROM_size = 0; + free(VROM); + VROM = NULL; + tofix |= 8; + } + if (MapperNo != (moo[x].mapper & 0xFF)) { + tofix |= 1; + MapperNo = moo[x].mapper & 0xFF; + } + } + if (moo[x].mirror >= 0) { + if (moo[x].mirror == 8) { + if (Mirroring == 2) { /* Anything but hard-wired(four screen). */ + tofix |= 2; + Mirroring = 0; + } + } else if (Mirroring != moo[x].mirror) { + if (Mirroring != (moo[x].mirror & ~4)) + if ((moo[x].mirror & ~4) <= 2) /* Don't complain if one-screen mirroring + needs to be set(the iNES header can't + hold this information). + */ + tofix |= 2; + Mirroring = moo[x].mirror; + } + } + break; + } + x++; + } while (moo[x].mirror >= 0 || moo[x].mapper >= 0); + + x = 0; + while (savie[x] != 0) { + if (savie[x] == partialmd5) { + if (!(head.ROM_type & 2)) { + tofix |= 4; + head.ROM_type |= 2; + } + } + x++; + } + + /* Games that use these iNES mappers tend to have the four-screen bit set + when it should not be. + */ + if ((MapperNo == 118 || MapperNo == 24 || MapperNo == 26) && (Mirroring == 2)) { + Mirroring = 0; + tofix |= 2; + } + + /* Four-screen mirroring implicitly set. */ + if (MapperNo == 99) + Mirroring = 2; + + if (tofix) { + char gigastr[768]; + strcpy(gigastr, "The iNES header contains incorrect information. For now, the information will be corrected in RAM. "); + if (tofix & 1) + sprintf(gigastr + strlen(gigastr), "The mapper number should be set to %d. ", MapperNo); + if (tofix & 2) { + uint8 *mstr[3] = { "Horizontal", "Vertical", "Four-screen" }; + sprintf(gigastr + strlen(gigastr), "Mirroring should be set to \"%s\". ", mstr[Mirroring & 3]); + } + if (tofix & 4) + strcat(gigastr, "The battery-backed bit should be set. "); + if (tofix & 8) + strcat(gigastr, "This game should not have any CHR ROM. "); + strcat(gigastr, "\n"); + FCEU_printf("%s", gigastr); + } +} + +typedef struct { + int32 mapper; + void (*init)(CartInfo *); +} NewMI; + +typedef struct { + uint8 *name; + int32 number; + void (*init)(CartInfo *); +} BMAPPINGLocal; + +static BMAPPINGLocal bmap[] = { + {"NROM", 0, NROM_Init}, + {"MMC1", 1, Mapper1_Init}, + {"UNROM", 2, UNROM_Init}, + {"CNROM", 3, CNROM_Init}, + {"MMC3", 4, Mapper4_Init}, + {"MMC5", 5, Mapper5_Init}, + {"FFE Rev. A", 6, Mapper6_Init}, + {"ANROM", 7, ANROM_Init}, + {"", 8, Mapper8_Init}, // Nogaems, it's worthless + {"MMC2", 9, Mapper9_Init}, + {"MMC4", 10, Mapper10_Init}, + {"Color Dreams", 11, Mapper11_Init}, + {"REX DBZ 5", 12, Mapper12_Init}, + {"CPROM", 13, CPROM_Init}, + {"REX SL-1632", 14, UNLSL1632_Init}, + {"100-in-1", 15, Mapper15_Init}, + {"BANDAI 24C02", 16, Mapper16_Init}, + {"FFE Rev. B", 17, Mapper17_Init}, + {"JALECO SS880006", 18, Mapper18_Init}, // JF-NNX (EB89018-30007) boards + {"Namcot 106", 19, Mapper19_Init}, +// {"", 20, Mapper20_Init}, + {"Konami VRC2/VRC4 A", 21, Mapper21_Init}, + {"Konami VRC2/VRC4 B", 22, Mapper22_Init}, + {"Konami VRC2/VRC4 C", 23, Mapper23_Init}, + {"Konami VRC6 Rev. A", 24, Mapper24_Init}, + {"Konami VRC2/VRC4 D", 25, Mapper25_Init}, + {"Konami VRC6 Rev. B", 26, Mapper26_Init}, + {"CC-21 MI HUN CHE", 27, UNLCC21_Init}, // Former dupe for VRC2/VRC4 mapper, redefined with crc to mihunche boards +// {"", 28, Mapper28_Init}, // Custom Multidiscrete mapper for PDs +// {"", 29, Mapper29_Init}, +// {"", 30, Mapper30_Init}, +// {"", 31, Mapper31_Init}, + {"IREM G-101", 32, Mapper32_Init}, + {"TC0190FMC/TC0350FMR", 33, Mapper33_Init}, + {"IREM I-IM/BNROM", 34, Mapper34_Init}, + {"Wario Land 2", 35, UNLSC127_Init}, + {"TXC Policeman", 36, Mapper36_Init}, + {"PAL-ZZ SMB/TETRIS/NWC",37, Mapper37_Init}, + {"Bit Corp.", 38, Mapper38_Init}, // Crime Busters +// {"", 39, Mapper39_Init}, + {"SMB2j FDS", 40, Mapper40_Init}, + {"CALTRON 6-in-1", 41, Mapper41_Init}, + {"BIO MIRACLE FDS", 42, Mapper42_Init}, + {"FDS SMB2j LF36", 43, Mapper43_Init}, + {"MMC3 BMC PIRATE A", 44, Mapper44_Init}, + {"MMC3 BMC PIRATE B", 45, Mapper45_Init}, + {"RUMBLESTATION 15-in-1",46, Mapper46_Init}, + {"NES-QJ SSVB/NWC", 47, Mapper47_Init}, + {"TAITO TCxxx", 48, Mapper48_Init}, + {"MMC3 BMC PIRATE C", 49, Mapper49_Init}, + {"SMB2j FDS Rev. A", 50, Mapper50_Init}, + {"11-in-1 BALL SERIES", 51, Mapper51_Init}, // 1993 year version + {"MMC3 BMC PIRATE D", 52, Mapper52_Init}, + {"SUPERVISION 16-in-1", 53, Supervision16_Init}, +// {"", 54, Mapper54_Init}, +// {"", 55, Mapper55_Init}, +// {"", 56, Mapper56_Init}, + {"SIMBPLE BMC PIRATE A", 57, Mapper57_Init}, + {"SIMBPLE BMC PIRATE B", 58, BMCGK192_Init}, + {"", 59, Mapper59_Init}, // Check this out + {"SIMBPLE BMC PIRATE C", 60, BMCD1038_Init}, + {"20-in-1 KAISER Rev. A",61, Mapper61_Init}, + {"700-in-1", 62, Mapper62_Init}, +// {"", 63, Mapper63_Init}, + {"TENGEN RAMBO1", 64, Mapper64_Init}, + {"IREM-H3001", 65, Mapper65_Init}, + {"MHROM", 66, MHROM_Init}, + {"SUNSOFT-FZII", 67, Mapper67_Init}, + {"Sunsoft Mapper #4", 68, Mapper68_Init}, + {"SUNSOFT-5/FME-7", 69, Mapper69_Init}, + {"BA KAMEN DISCRETE", 70, Mapper70_Init}, + {"CAMERICA BF9093", 71, Mapper71_Init}, + {"JALECO JF-17", 72, Mapper72_Init}, + {"KONAMI VRC3", 73, Mapper73_Init}, + {"TW MMC3+VRAM Rev. A", 74, Mapper74_Init}, + {"KONAMI VRC1", 75, Mapper75_Init}, + {"NAMCOT 108 Rev. A", 76, Mapper76_Init}, + {"IREM LROG017", 77, Mapper77_Init}, + {"Irem 74HC161/32", 78, Mapper78_Init}, + {"AVE/C&E/TXC BOARD", 79, Mapper79_Init}, + {"TAITO X1-005 Rev. A", 80, Mapper80_Init}, +// {"", 81, Mapper81_Init}, + {"TAITO X1-017", 82, Mapper82_Init}, + {"YOKO VRC Rev. B", 83, Mapper83_Init}, +// {"", 84, Mapper84_Init}, + {"KONAMI VRC7", 85, Mapper85_Init}, + {"JALECO JF-13", 86, Mapper86_Init}, + {"74*139/74 DISCRETE", 87, Mapper87_Init}, + {"NAMCO 3433", 88, Mapper88_Init}, + {"SUNSOFT-3", 89, Mapper89_Init}, // SUNSOFT-2 mapper + {"HUMMER/JY BOARD", 90, Mapper90_Init}, + {"EARLY HUMMER/JY BOARD",91, Mapper91_Init}, + {"JALECO JF-19", 92, Mapper92_Init}, + {"SUNSOFT-3R", 93, SUNSOFT_UNROM_Init},// SUNSOFT-2 mapper with VRAM, different wiring + {"HVC-UN1ROM", 94, Mapper94_Init}, + {"NAMCOT 108 Rev. B", 95, Mapper95_Init}, + {"BANDAI OEKAKIDS", 96, Mapper96_Init}, + {"IREM TAM-S1", 97, Mapper97_Init}, +// {"", 98, Mapper98_Init}, + {"VS Uni/Dual- system", 99, Mapper99_Init}, +// {"", 100, Mapper100_Init}, + {"", 101, Mapper101_Init}, +// {"", 102, Mapper102_Init}, + {"FDS DOKIDOKI FULL", 103, Mapper103_Init}, +// {"", 104, Mapper104_Init}, + {"NES-EVENT NWC1990", 105, Mapper105_Init}, + {"SMB3 PIRATE A", 106, Mapper106_Init}, + {"MAGIC CORP A", 107, Mapper107_Init}, + {"FDS UNROM BOARD", 108, Mapper108_Init}, +// {"", 109, Mapper109_Init}, +// {"", 110, Mapper110_Init}, +// {"", 111, Mapper111_Init}, + {"ASDER/NTDEC BOARD", 112, Mapper112_Init}, + {"HACKER/SACHEN BOARD", 113, Mapper113_Init}, + {"MMC3 SG PROT. A", 114, Mapper114_Init}, + {"MMC3 PIRATE A", 115, Mapper115_Init}, + {"MMC1/MMC3/VRC PIRATE",116, UNLSL12_Init}, + {"FUTURE MEDIA BOARD", 117, Mapper117_Init}, + {"TSKROM", 118, TKSROM_Init}, + {"NES-TQROM", 119, Mapper119_Init}, + {"FDS TOBIDASE", 120, Mapper120_Init}, + {"MMC3 PIRATE PROT. A", 121, Mapper121_Init}, +// {"", 122, Mapper122_Init}, + {"MMC3 PIRATE H2288", 123, UNLH2288_Init}, +// {"", 124, Mapper124_Init}, + {"FDS LH32", 125, LH32_Init}, +// {"", 126, Mapper126_Init}, +// {"", 127, Mapper127_Init}, +// {"", 128, Mapper128_Init}, +// {"", 129, Mapper129_Init}, +// {"", 130, Mapper130_Init}, +// {"", 131, Mapper131_Init}, + {"TXC/MGENIUS 22111", 132, UNL22211_Init}, + {"SA72008", 133, SA72008_Init}, + {"MMC3 BMC PIRATE", 134, Mapper134_Init}, +// {"", 135, Mapper135_Init}, + {"TCU02", 136, TCU02_Init}, + {"S8259D", 137, S8259D_Init}, + {"S8259B", 138, S8259B_Init}, + {"S8259C", 139, S8259C_Init}, + {"JALECO JF-11/14", 140, Mapper140_Init}, + {"S8259A", 141, S8259A_Init}, + {"UNLKS7032", 142, UNLKS7032_Init}, + {"TCA01", 143, TCA01_Init}, + {"AGCI 50282", 144, Mapper144_Init}, + {"SA72007", 145, SA72007_Init}, + {"SA0161M", 146, SA0161M_Init}, + {"TCU01", 147, TCU01_Init}, + {"SA0037", 148, SA0037_Init}, + {"SA0036", 149, SA0036_Init}, + {"S74LS374N", 150, S74LS374N_Init}, + {"", 151, Mapper151_Init}, + {"", 152, Mapper152_Init}, + {"BANDAI SRAM", 153, Mapper153_Init}, // Bandai board 16 with SRAM instead of EEPROM + {"", 154, Mapper154_Init}, + {"", 155, Mapper155_Init}, + {"", 156, Mapper156_Init}, + {"BANDAI BARCODE", 157, Mapper157_Init}, +// {"", 158, Mapper158_Init}, + {"BANDAI 24C01", 159, Mapper159_Init}, // Different type of EEPROM on the bandai board + {"SA009", 160, SA009_Init}, +// {"", 161, Mapper161_Init}, + {"", 162, UNLFS304_Init}, + {"", 163, Mapper163_Init}, + {"", 164, Mapper164_Init}, + {"", 165, Mapper165_Init}, + {"SUBOR Rev. A", 166, Mapper166_Init}, + {"SUBOR Rev. B", 167, Mapper167_Init}, + {"", 168, Mapper168_Init}, +// {"", 169, Mapper169_Init}, + {"", 170, Mapper170_Init}, + {"", 171, Mapper171_Init}, + {"", 172, Mapper172_Init}, + {"", 173, Mapper173_Init}, +// {"", 174, Mapper174_Init}, + {"", 175, Mapper175_Init}, + {"BMCFK23C", 176, BMCFK23C_Init}, // zero 26-may-2012 - well, i have some WXN junk games that use 176 for instance ????. i dont know what game uses this BMCFK23C as mapper 176. we'll have to make a note when we find it. + {"", 177, Mapper177_Init}, + {"", 178, Mapper178_Init}, +// {"", 179, Mapper179_Init}, + {"", 180, Mapper180_Init}, + {"", 181, Mapper181_Init}, +// {"", 182, Mapper182_Init}, // Deprecated, dupe + {"", 183, Mapper183_Init}, + {"", 184, Mapper184_Init}, + {"", 185, Mapper185_Init}, + {"", 186, Mapper186_Init}, + {"", 187, Mapper187_Init}, + {"", 188, Mapper188_Init}, + {"", 189, Mapper189_Init}, +// {"", 190, Mapper190_Init}, + {"", 191, Mapper191_Init}, + {"TW MMC3+VRAM Rev. B", 192, Mapper192_Init}, + {"NTDEC TC-112", 193, Mapper193_Init}, // War in the Gulf + {"TW MMC3+VRAM Rev. C", 194, Mapper194_Init}, + {"TW MMC3+VRAM Rev. D", 195, Mapper195_Init}, + {"", 196, Mapper196_Init}, + {"", 197, Mapper197_Init}, + {"TW MMC3+VRAM Rev. E", 198, Mapper198_Init}, + {"", 199, Mapper199_Init}, + {"", 200, Mapper200_Init}, + {"", 201, Mapper201_Init}, + {"", 202, Mapper202_Init}, + {"", 203, Mapper203_Init}, + {"", 204, Mapper204_Init}, + {"", 205, Mapper205_Init}, + {"NAMCOT 108 Rev. C", 206, Mapper206_Init}, // Deprecated, Used to be "DEIROM" whatever it means, but actually simple version of MMC3 + {"TAITO X1-005 Rev. B", 207, Mapper207_Init}, + {"", 208, Mapper208_Init}, + {"", 209, Mapper209_Init}, + {"", 210, Mapper210_Init}, + {"", 211, Mapper211_Init}, + {"", 212, Mapper212_Init}, + {"", 213, Mapper213_Init}, + {"", 214, Mapper214_Init}, + {"", 215, UNL8237_Init}, + {"", 216, Mapper216_Init}, + {"", 217, Mapper217_Init}, // Redefined to a new Discrete BMC mapper +// {"", 218, Mapper218_Init}, + {"UNLA9746", 219, UNLA9746_Init}, + {"Debug Mapper", 220, UNLPEC586Init}, // UNLKS7057_Init}, + {"UNLN625092", 221, UNLN625092_Init}, + {"", 222, Mapper222_Init}, +// {"", 223, Mapper223_Init}, +// {"", 224, Mapper224_Init}, + {"", 225, Mapper225_Init}, + {"BMC 22+20-in-1", 226, Mapper226_Init}, + {"", 227, Mapper227_Init}, + {"", 228, Mapper228_Init}, + {"", 229, Mapper229_Init}, + {"BMC Contra+22-in-1", 230, Mapper230_Init}, + {"", 231, Mapper231_Init}, + {"BMC QUATTRO", 232, Mapper232_Init}, + {"BMC 22+20-in-1 RST", 233, Mapper233_Init}, + {"BMC MAXI", 234, Mapper234_Init}, + {"", 235, Mapper235_Init}, +// {"", 236, Mapper236_Init}, +// {"", 237, Mapper237_Init}, + {"UNL6035052", 238, UNL6035052_Init}, +// {"", 239, Mapper239_Init}, + {"", 240, Mapper240_Init}, + {"", 241, Mapper241_Init}, + {"", 242, Mapper242_Init}, + {"S74LS374NA", 243, S74LS374NA_Init}, + {"DECATHLON", 244, Mapper244_Init}, + {"", 245, Mapper245_Init}, + {"FONG SHEN BANG", 246, Mapper246_Init}, +// {"", 247, Mapper247_Init}, +// {"", 248, Mapper248_Init}, + {"", 249, Mapper249_Init}, + {"", 250, Mapper250_Init}, +// {"", 251, Mapper251_Init}, // No good dumps for this mapper, use UNIF version + {"SAN GUO ZHI PIRATE", 252, Mapper252_Init}, + {"DRAGON BALL PIRATE", 253, Mapper253_Init}, + {"", 254, Mapper254_Init}, +// {"", 255, Mapper255_Init}, // No good dumps for this mapper + {"", 0, NULL} +}; + +int iNESLoad(const char *name, FCEUFILE *fp) { + struct md5_context md5; + char* mappername; + uint32 mappertest; + + if (FCEU_fread(&head, 1, 16, fp) != 16) + return 0; + + if (memcmp(&head, "NES\x1a", 4)) + return 0; + + memset(&iNESCart, 0, sizeof(iNESCart)); + + if (!memcmp((char*)(&head) + 0x7, "DiskDude", 8)) { + memset((char*)(&head) + 0x7, 0, 0x9); + } + + if (!memcmp((char*)(&head) + 0x7, "demiforce", 9)) { + memset((char*)(&head) + 0x7, 0, 0x9); + } + + if (!memcmp((char*)(&head) + 0xA, "Ni03", 4)) { + if (!memcmp((char*)(&head) + 0x7, "Dis", 3)) + memset((char*)(&head) + 0x7, 0, 0x9); + else + memset((char*)(&head) + 0xA, 0, 0x6); + } + + MapperNo = (head.ROM_type >> 4); + MapperNo |= (head.ROM_type2 & 0xF0); + if (head.ROM_type & 8) { + Mirroring = 2; + } else + Mirroring = (head.ROM_type & 1); + + if (!head.ROM_size) + ROM_size = 256; + else + ROM_size = uppow2(head.ROM_size); + + VROM_size = uppow2(head.VROM_size); + + + if ((ROM = (uint8*)FCEU_malloc(ROM_size << 14)) == NULL) + return 0; + memset(ROM, 0xFF, ROM_size << 14); + + if (VROM_size) { + if ((VROM = (uint8*)FCEU_malloc(VROM_size << 13)) == NULL) { + free(ROM); + ROM = NULL; + return 0; + } + memset(VROM, 0xFF, VROM_size << 13); + } + + if (head.ROM_type & 4) { /* Trainer */ + trainerpoo = (uint8*)FCEU_gmalloc(512); + FCEU_fread(trainerpoo, 512, 1, fp); + } + + ResetCartMapping(); + ResetExState(0, 0); + + SetupCartPRGMapping(0, ROM, ROM_size << 14, 0); + + if (head.ROM_size) + FCEU_fread(ROM, 0x4000, head.ROM_size, fp); + else + FCEU_fread(ROM, 0x4000, ROM_size, fp); + + if (VROM_size) + FCEU_fread(VROM, 0x2000, VROM_size, fp); + + md5_starts(&md5); + md5_update(&md5, ROM, ROM_size << 14); + + iNESGameCRC32 = CalcCRC32(0, ROM, ROM_size << 14); + + if (VROM_size) { + iNESGameCRC32 = CalcCRC32(iNESGameCRC32, VROM, VROM_size << 13); + md5_update(&md5, VROM, VROM_size << 13); + } + md5_finish(&md5, iNESCart.MD5); + memcpy(&GameInfo->MD5, &iNESCart.MD5, sizeof(iNESCart.MD5)); + + iNESCart.CRC32 = iNESGameCRC32; + + FCEU_printf(" PRG ROM: %3d x 16KiB\n", ROM_size); + FCEU_printf(" CHR ROM: %3d x 8KiB\n", head.VROM_size); + FCEU_printf(" ROM CRC32: 0x%08lx\n", iNESGameCRC32); + FCEU_printf(" ROM MD5: 0x%s\n", md5_asciistr(iNESCart.MD5)); + mappername = "Not Listed"; + + for (mappertest = 0; mappertest < (sizeof bmap / sizeof bmap[0]) - 1; mappertest++) { + if (bmap[mappertest].number == MapperNo) { + mappername = bmap[mappertest].name; + break; + } + } + + FCEU_printf(" Mapper #: %d\n", MapperNo); + FCEU_printf(" Mapper name: %s\n", mappername); + FCEU_printf(" Mirroring: %s\n", Mirroring == 2 ? "None (Four-screen)" : Mirroring ? "Vertical" : "Horizontal"); + FCEU_printf(" Battery-backed: %s\n", (head.ROM_type & 2) ? "Yes" : "No"); + FCEU_printf(" Trained: %s\n", (head.ROM_type & 4) ? "Yes" : "No"); + + SetInput(); + CheckHInfo(); + { + int x; + uint64 partialmd5 = 0; + + for (x = 0; x < 8; x++) { + partialmd5 |= (uint64)iNESCart.MD5[7 - x] << (x * 8); + } + + FCEU_VSUniCheck(partialmd5, &MapperNo, &Mirroring); + } + /* Must remain here because above functions might change value of + VROM_size and free(VROM). + */ + if (VROM_size) + SetupCartCHRMapping(0, VROM, VROM_size * 0x2000, 0); + + if (Mirroring == 2) { + ExtraNTARAM = (uint8*)FCEU_gmalloc(2048); + SetupCartMirroring(4, 1, ExtraNTARAM); + } else if (Mirroring >= 0x10) + SetupCartMirroring(2 + (Mirroring & 1), 1, 0); + else + SetupCartMirroring(Mirroring & 1, (Mirroring & 4) >> 2, 0); + + iNESCart.battery = (head.ROM_type & 2) ? 1 : 0; + iNESCart.mirror = Mirroring; + + if (!iNES_Init(MapperNo)) + FCEU_PrintError("iNES mapper #%d is not supported at all.", MapperNo); + + FCEU_LoadGameSave(&iNESCart); + + GameInterface = iNESGI; + FCEU_printf("\n"); + + if (strstr(name, "(E)") || strstr(name, "(e)") + || strstr(name, "(Europe)") || strstr(name, "(PAL)") + || strstr(name, "(F)") || strstr(name, "(f)") + || strstr(name, "(G)") || strstr(name, "(g)") + || strstr(name, "(I)") || strstr(name, "(i)")) + GameInfo->vidsys = GIV_PAL; + + return 1; +} + +static int iNES_Init(int num) { + BMAPPINGLocal *tmp = bmap; + + CHRRAMSize = -1; + + if (GameInfo->type == GIT_VSUNI) + AddExState(FCEUVSUNI_STATEINFO, ~0, 0, 0); + + while (tmp->init) { + if (num == tmp->number) { + UNIFchrrama = 0; // need here for compatibility with UNIF mapper code + if (!VROM_size) { + switch (num) { // FIXME, mapper or game data base with the board parameters and ROM/RAM sizes + case 13: CHRRAMSize = 16 * 1024; break; + case 6: + case 96: CHRRAMSize = 32 * 1024; break; + case 176: CHRRAMSize = 256 * 1024; break; + default: CHRRAMSize = 8 * 1024; break; + } + if ((VROM = (uint8*)malloc(CHRRAMSize)) == NULL) return 0; + UNIFchrrama = VROM; + SetupCartCHRMapping(0, VROM, CHRRAMSize, 1); + AddExState(VROM, CHRRAMSize, 0, "CHRR"); + } + if (head.ROM_type & 8) + AddExState(ExtraNTARAM, 2048, 0, "EXNR"); + tmp->init(&iNESCart); + return 1; + } + tmp++; + } + return 0; +} diff --git a/src/drivers/libretro/fceu/input.c b/src/drivers/libretro/fceu/input.c new file mode 100644 index 0000000..918d41b --- /dev/null +++ b/src/drivers/libretro/fceu/input.c @@ -0,0 +1,378 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 1998 BERO + * Copyright (C) 2002 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include + +#include "fceu-types.h" +#include "x6502.h" + +#include "fceu.h" +#include "netplay.h" +#include "input.h" +#include "vsuni.h" +#include "fds.h" + +extern INPUTC *FCEU_InitJoyPad(int w); +extern INPUTC *FCEU_InitZapper(int w); +extern INPUTC *FCEU_InitMouse(int w); +extern INPUTC *FCEU_InitPowerpadA(int w); +extern INPUTC *FCEU_InitPowerpadB(int w); +extern INPUTC *FCEU_InitArkanoid(int w); + +extern INPUTCFC *FCEU_InitFami4(void); +extern INPUTCFC *FCEU_InitArkanoidFC(void); +extern INPUTCFC *FCEU_InitSpaceShadow(void); +extern INPUTCFC *FCEU_InitFKB(void); +extern INPUTCFC *FCEU_InitSuborKB(void); +extern INPUTCFC *FCEU_InitPEC586KB(void); +extern INPUTCFC *FCEU_InitHS(void); +extern INPUTCFC *FCEU_InitMahjong(void); +extern INPUTCFC *FCEU_InitQuizKing(void); +extern INPUTCFC *FCEU_InitFamilyTrainerA(void); +extern INPUTCFC *FCEU_InitFamilyTrainerB(void); +extern INPUTCFC *FCEU_InitOekaKids(void); +extern INPUTCFC *FCEU_InitTopRider(void); +extern INPUTCFC *FCEU_InitBarcodeWorld(void); + +extern uint8 coinon; + +static void *InputDataPtr[2]; +uint8 LastStrobe; + +static int JPAttrib[2] = { 0, 0 }; +static int JPType[2] = { 0, 0 }; +static INPUTC DummyJPort = { 0, 0, 0, 0, 0 }; +static INPUTC *JPorts[2] = { &DummyJPort, &DummyJPort }; + +static int JPAttribFC = 0; +static int JPTypeFC = 0; +static void *InputDataPtrFC; +static INPUTCFC *FCExp = 0; + +void (*InputScanlineHook)(uint8 *bg, uint8 *spr, uint32 linets, int final); + +static DECLFR(JPRead) +{ + uint8 ret = 0; + + if (JPorts[A & 1]->Read) + ret |= JPorts[A & 1]->Read(A & 1); + + if (FCExp) + if (FCExp->Read) + ret = FCExp->Read(A & 1, ret); + + ret |= X.DB & 0xC0; + + return(ret); +} + +static DECLFW(B4016) +{ + if (FCExp) + if (FCExp->Write) + FCExp->Write(V & 7); + + if (JPorts[0]->Write) + JPorts[0]->Write(V & 1); + if (JPorts[1]->Write) + JPorts[1]->Write(V & 1); + + if ((LastStrobe & 1) && (!(V & 1))) + { + if (JPorts[0]->Strobe) + JPorts[0]->Strobe(0); + if (JPorts[1]->Strobe) + JPorts[1]->Strobe(1); + if (FCExp) + if (FCExp->Strobe) + FCExp->Strobe(); + } + LastStrobe = V & 0x1; +} + +void FCEU_DrawInput(uint8 *buf) +{ + int x; + for (x = 0; x < 2; x++) + if (JPorts[x]->Draw) + JPorts[x]->Draw(x, buf, JPAttrib[x]); + if (FCExp) + if (FCExp->Draw) + FCExp->Draw(buf, JPAttribFC); +} + +void FCEU_UpdateInput(void) +{ + int x; + + for (x = 0; x < 2; x++) + { + if (JPorts[x] && JPorts[x]->Update) + JPorts[x]->Update(x, InputDataPtr[x], JPAttrib[x]); + } + + if (FCExp && FCExp->Update) + FCExp->Update(InputDataPtrFC, JPAttribFC); + + if (GameInfo && GameInfo->type == GIT_VSUNI) + if (coinon) coinon--; +} + +static DECLFR(VSUNIRead0) +{ + uint8 ret = 0; + + if (JPorts[0]->Read) + ret |= (JPorts[0]->Read(0)) & 1; + + ret |= (vsdip & 3) << 3; + if (coinon) + ret |= 0x4; + return ret; +} + +static DECLFR(VSUNIRead1) +{ + uint8 ret = 0; + + if (JPorts[1] && JPorts[1]->Read) + ret |= (JPorts[1]->Read(1)) & 1; + ret |= vsdip & 0xFC; + return ret; +} + +static void SLHLHook(uint8 *bg, uint8 *spr, uint32 linets, int final) +{ + int x; + + for (x = 0; x < 2; x++) + if (JPorts[x] && JPorts[x]->SLHook) + JPorts[x]->SLHook(x, bg, spr, linets, final); + + if (FCExp && FCExp->SLHook) + FCExp->SLHook(bg, spr, linets, final); +} + +static void CheckSLHook(void) +{ + InputScanlineHook = 0; + + if (JPorts[0] && JPorts[0]->SLHook || JPorts[1] && JPorts[1]->SLHook) + InputScanlineHook = SLHLHook; + + if (FCExp && FCExp->SLHook) + InputScanlineHook = SLHLHook; +} + +static void FASTAPASS(1) SetInputStuff(int x) +{ + switch (JPType[x]) + { + case SI_NONE: + JPorts[x] = &DummyJPort; + break; + case SI_GAMEPAD: + JPorts[x] = FCEU_InitJoyPad(x); + break; + case SI_ARKANOID: + JPorts[x] = FCEU_InitArkanoid(x); + break; + case SI_MOUSE: + JPorts[x] = FCEU_InitMouse(x); + break; + case SI_ZAPPER: + JPorts[x] = FCEU_InitZapper(x); + break; + case SI_POWERPADA: + JPorts[x] = FCEU_InitPowerpadA(x); + break; + case SI_POWERPADB: + JPorts[x] = FCEU_InitPowerpadB(x); + break; + } + CheckSLHook(); +} + +static void SetInputStuffFC(void) +{ + switch (JPTypeFC) + { + case SIFC_NONE: + FCExp = 0; + break; + case SIFC_ARKANOID: + FCExp = FCEU_InitArkanoidFC(); + break; + case SIFC_SHADOW: + FCExp = FCEU_InitSpaceShadow(); + break; + case SIFC_OEKAKIDS: + FCExp = FCEU_InitOekaKids(); + break; + case SIFC_4PLAYER: + FCExp = FCEU_InitFami4(); + break; + case SIFC_FKB: + FCExp = FCEU_InitFKB(); + break; + case SIFC_SUBORKB: + FCExp = FCEU_InitSuborKB(); + break; + case SIFC_PEC586KB: + FCExp = FCEU_InitPEC586KB(); + break; + case SIFC_HYPERSHOT: + FCExp = FCEU_InitHS(); + break; + case SIFC_MAHJONG: + FCExp = FCEU_InitMahjong(); + break; + case SIFC_QUIZKING: + FCExp = FCEU_InitQuizKing(); + break; + case SIFC_FTRAINERA: + FCExp = FCEU_InitFamilyTrainerA(); + break; + case SIFC_FTRAINERB: + FCExp = FCEU_InitFamilyTrainerB(); + break; + case SIFC_BWORLD: + FCExp = FCEU_InitBarcodeWorld(); + break; + case SIFC_TOPRIDER: + FCExp = FCEU_InitTopRider(); + break; + } + CheckSLHook(); +} + +void InitializeInput(void) +{ + LastStrobe = 0; + + if (GameInfo && GameInfo->type == GIT_VSUNI) + { + SetReadHandler(0x4016, 0x4016, VSUNIRead0); + SetReadHandler(0x4017, 0x4017, VSUNIRead1); + } + else + SetReadHandler(0x4016, 0x4017, JPRead); + + SetWriteHandler(0x4016, 0x4016, B4016); + + SetInputStuff(0); + SetInputStuff(1); + SetInputStuffFC(); +} + +void FCEUI_SetInput(int port, int type, void *ptr, int attrib) +{ + JPAttrib[port] = attrib; + JPType[port] = type; + InputDataPtr[port] = ptr; + SetInputStuff(port); +} + +void FCEUI_SetInputFC(int type, void *ptr, int attrib) +{ + JPAttribFC = attrib; + JPTypeFC = type; + InputDataPtrFC = ptr; + SetInputStuffFC(); +} + +void FCEU_DoSimpleCommand(int cmd) +{ + switch (cmd) + { + case FCEUNPCMD_FDSINSERT: + FCEU_FDSInsert(-1); + break; + case FCEUNPCMD_FDSSELECT: + FCEU_FDSSelect(); + break; + case FCEUNPCMD_FDSEJECT: + FCEU_FDSEject(); + break; + case FCEUNPCMD_VSUNICOIN: + FCEU_VSUniCoin(); + break; + case FCEUNPCMD_VSUNIDIP0: + case (FCEUNPCMD_VSUNIDIP0 + 1): + case (FCEUNPCMD_VSUNIDIP0 + 2): + case (FCEUNPCMD_VSUNIDIP0 + 3): + case (FCEUNPCMD_VSUNIDIP0 + 4): + case (FCEUNPCMD_VSUNIDIP0 + 5): + case (FCEUNPCMD_VSUNIDIP0 + 6): + case (FCEUNPCMD_VSUNIDIP0 + 7): + FCEU_VSUniToggleDIP(cmd - FCEUNPCMD_VSUNIDIP0); + break; + case FCEUNPCMD_POWER: + PowerNES(); + break; + case FCEUNPCMD_RESET: + ResetNES(); + break; + } +} + +void FCEU_QSimpleCommand(int cmd) +{ + FCEU_DoSimpleCommand(cmd); +} + +void FCEUI_FDSSelect(void) +{ + FCEU_QSimpleCommand(FCEUNPCMD_FDSSELECT); +} + +int FCEUI_FDSInsert(int oride) +{ + FCEU_QSimpleCommand(FCEUNPCMD_FDSINSERT); + return(1); +} + +int FCEUI_FDSEject(void) +{ + FCEU_QSimpleCommand(FCEUNPCMD_FDSEJECT); + return(1); +} + +void FCEUI_VSUniToggleDIP(int w) +{ + FCEU_QSimpleCommand(FCEUNPCMD_VSUNIDIP0 + w); +} + +void FCEUI_VSUniCoin(void) +{ + FCEU_QSimpleCommand(FCEUNPCMD_VSUNICOIN); +} + +void FCEUI_ResetNES(void) +{ + FCEU_QSimpleCommand(FCEUNPCMD_RESET); +} + +void FCEUI_PowerNES(void) +{ + FCEU_QSimpleCommand(FCEUNPCMD_POWER); +} + diff --git a/src/drivers/libretro/fceu/misc.c b/src/drivers/libretro/fceu/misc.c new file mode 100644 index 0000000..4888983 --- /dev/null +++ b/src/drivers/libretro/fceu/misc.c @@ -0,0 +1,20 @@ +#include + +#include "fceu-types.h" +#include "fceu.h" + +#include "driver.h" + +/* wave.c */ + +void FCEU_WriteWaveData(int32 *Buffer, int Count) { } +int FCEUI_EndWaveRecord(void) { return 0; } +int FCEUI_BeginWaveRecord(char *fn) { return 0; } + +/* netplay.c */ +int FCEUNET_SendFile(uint8 cmd, char *fn) { return 0; } + +/* movie.c */ +void FCEUMOV_AddJoy(uint8 *js) { } +void FCEUMOV_Stop(void) {} +void FCEUI_SelectMovie(int w) { } diff --git a/src/drivers/libretro/fceu/nsf.c b/src/drivers/libretro/fceu/nsf.c new file mode 100644 index 0000000..5c54535 --- /dev/null +++ b/src/drivers/libretro/fceu/nsf.c @@ -0,0 +1,519 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +#include "fceu-types.h" +#include "x6502.h" +#include "fceu.h" +#include "video.h" +#include "sound.h" +#include "nsf.h" +#include "general.h" +#include "fceu-memory.h" +#include "file.h" +#include "fds.h" +#include "cart.h" +#include "input.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +static uint8 SongReload; +static int CurrentSong; + +static DECLFW(NSF_write); +static DECLFR(NSF_read); + +static int vismode = 1; + +static uint8 NSFROM[0x30 + 6] = +{ +/* 0x00 - NMI */ + 0x8D, 0xF4, 0x3F, /* Stop play routine NMIs. */ + 0xA2, 0xFF, 0x9A, /* Initialize the stack pointer. */ + 0xAD, 0xF0, 0x3F, /* See if we need to init. */ + 0xF0, 0x09, /* If 0, go to play routine playing. */ + + 0xAD, 0xF1, 0x3F, /* Confirm and load A */ + 0xAE, 0xF3, 0x3F, /* Load X with PAL/NTSC byte */ + + 0x20, 0x00, 0x00, /* JSR to init routine */ + + 0xA9, 0x00, + 0xAA, + 0xA8, + 0x20, 0x00, 0x00, /* JSR to play routine */ + 0x8D, 0xF5, 0x3F, /* Start play routine NMIs. */ + 0x90, 0xFE, /* Loopie time. */ + +/* 0x20 */ + 0x8D, 0xF3, 0x3F, /* Init init NMIs */ + 0x18, + 0x90, 0xFE /* Loopie time. */ +}; + +static DECLFR(NSFROMRead) { + return (NSFROM - 0x3800)[A]; +} + +static int doreset = 0; +static int NSFNMIFlags; +static uint8 *NSFDATA = 0; +static int NSFMaxBank; + +static int NSFSize; +static uint8 BSon; +static uint16 PlayAddr; +static uint16 InitAddr; +static uint16 LoadAddr; + +static NSF_HEADER NSFHeader; + +void NSFMMC5_Close(void); +static uint8 *ExWRAM = 0; + +void NSFGI(int h) { + switch (h) { + case GI_CLOSE: + if (NSFDATA) { + free(NSFDATA); NSFDATA = 0; + } + if (ExWRAM) { + free(ExWRAM); ExWRAM = 0; + } + if (NSFHeader.SoundChip & 1) { +// NSFVRC6_Init(); + } else if (NSFHeader.SoundChip & 2) { +// NSFVRC7_Init(); + } else if (NSFHeader.SoundChip & 4) { +// FDSSoundReset(); + } else if (NSFHeader.SoundChip & 8) { + NSFMMC5_Close(); + } else if (NSFHeader.SoundChip & 0x10) { +// NSFN106_Init(); + } else if (NSFHeader.SoundChip & 0x20) { +// NSFAY_Init(); + } + break; + case GI_RESETM2: + case GI_POWER: NSF_init(); break; + } +} + +// First 32KB is reserved for sound chip emulation in the iNES mapper code. + +static INLINE void BANKSET(uint32 A, uint32 bank) { + bank &= NSFMaxBank; + if (NSFHeader.SoundChip & 4) + memcpy(ExWRAM + (A - 0x6000), NSFDATA + (bank << 12), 4096); + else + setprg4(A, bank); +} + +int NSFLoad(FCEUFILE *fp) { + int x; + + FCEU_fseek(fp, 0, SEEK_SET); + FCEU_fread(&NSFHeader, 1, 0x80, fp); + if (memcmp(NSFHeader.ID, "NESM\x1a", 5)) + return 0; + NSFHeader.SongName[31] = NSFHeader.Artist[31] = NSFHeader.Copyright[31] = 0; + + LoadAddr = NSFHeader.LoadAddressLow; + LoadAddr |= NSFHeader.LoadAddressHigh << 8; + + if (LoadAddr < 0x6000) { + FCEUD_PrintError("Invalid load address."); + return(0); + } + InitAddr = NSFHeader.InitAddressLow; + InitAddr |= NSFHeader.InitAddressHigh << 8; + + PlayAddr = NSFHeader.PlayAddressLow; + PlayAddr |= NSFHeader.PlayAddressHigh << 8; + + NSFSize = FCEU_fgetsize(fp) - 0x80; + + NSFMaxBank = ((NSFSize + (LoadAddr & 0xfff) + 4095) / 4096); + NSFMaxBank = uppow2(NSFMaxBank); + + if (!(NSFDATA = (uint8*)FCEU_malloc(NSFMaxBank * 4096))) + return 0; + + FCEU_fseek(fp, 0x80, SEEK_SET); + memset(NSFDATA, 0x00, NSFMaxBank * 4096); + FCEU_fread(NSFDATA + (LoadAddr & 0xfff), 1, NSFSize, fp); + + NSFMaxBank--; + + BSon = 0; + for (x = 0; x < 8; x++) + BSon |= NSFHeader.BankSwitch[x]; + + GameInfo->type = GIT_NSF; + GameInfo->input[0] = GameInfo->input[1] = SI_GAMEPAD; + GameInfo->cspecial = SIS_NSF; + + for (x = 0;; x++) { + if (NSFROM[x] == 0x20) { + NSFROM[x + 1] = InitAddr & 0xFF; + NSFROM[x + 2] = InitAddr >> 8; + NSFROM[x + 8] = PlayAddr & 0xFF; + NSFROM[x + 9] = PlayAddr >> 8; + break; + } + } + + if (NSFHeader.VideoSystem == 0) + GameInfo->vidsys = GIV_NTSC; + else if (NSFHeader.VideoSystem == 1) + GameInfo->vidsys = GIV_PAL; + + GameInterface = NSFGI; + + FCEU_printf("NSF Loaded. File information:\n\n"); + FCEU_printf(" Name: %s\n Artist: %s\n Copyright: %s\n\n", NSFHeader.SongName, NSFHeader.Artist, NSFHeader.Copyright); + if (NSFHeader.SoundChip) { + static char *tab[6] = { "Konami VRCVI", "Konami VRCVII", "Nintendo FDS", "Nintendo MMC5", "Namco 106", "Sunsoft FME-07" }; + + for (x = 0; x < 6; x++) + if (NSFHeader.SoundChip & (1 << x)) { + FCEU_printf(" Expansion hardware: %s\n", tab[x]); + NSFHeader.SoundChip = 1 << x; /* Prevent confusing weirdness if more than one bit is set. */ + break; + } + } + if (BSon) + FCEU_printf(" Bank-switched.\n"); + FCEU_printf(" Load address: $%04x\n Init address: $%04x\n Play address: $%04x\n", LoadAddr, InitAddr, PlayAddr); + FCEU_printf(" %s\n", (NSFHeader.VideoSystem & 1) ? "PAL" : "NTSC"); + FCEU_printf(" Starting song: %d / %d\n\n", NSFHeader.StartingSong, NSFHeader.TotalSongs); + + if (NSFHeader.SoundChip & 4) + ExWRAM = FCEU_gmalloc(32768 + 8192); + else + ExWRAM = FCEU_gmalloc(8192); + return 1; +} + +static DECLFR(NSFVectorRead) { + if (((NSFNMIFlags & 1) && SongReload) || (NSFNMIFlags & 2) || doreset) { + if (A == 0xFFFA) return(0x00); + else if (A == 0xFFFB) return(0x38); + else if (A == 0xFFFC) return(0x20); + else if (A == 0xFFFD) { + doreset = 0; return(0x38); + } + return(X.DB); + } else + return(CartBR(A)); +} + +void NSFVRC6_Init(void); +void NSFVRC7_Init(void); +void NSFMMC5_Init(void); +void NSFN106_Init(void); +void NSFAY_Init(void); + +void NSF_init(void) { + doreset = 1; + + ResetCartMapping(); + if (NSFHeader.SoundChip & 4) { + SetupCartPRGMapping(0, ExWRAM, 32768 + 8192, 1); + setprg32(0x6000, 0); + setprg8(0xE000, 4); + memset(ExWRAM, 0x00, 32768 + 8192); + SetWriteHandler(0x6000, 0xDFFF, CartBW); + SetReadHandler(0x6000, 0xFFFF, CartBR); + } else { + memset(ExWRAM, 0x00, 8192); + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + SetupCartPRGMapping(0, NSFDATA, ((NSFMaxBank + 1) * 4096), 0); + SetupCartPRGMapping(1, ExWRAM, 8192, 1); + setprg8r(1, 0x6000, 0); + SetReadHandler(0x8000, 0xFFFF, CartBR); + } + + if (BSon) { + int32 x; + for (x = 0; x < 8; x++) { + if (NSFHeader.SoundChip & 4 && x >= 6) + BANKSET(0x6000 + (x - 6) * 4096, NSFHeader.BankSwitch[x]); + BANKSET(0x8000 + x * 4096, NSFHeader.BankSwitch[x]); + } + } else { + int32 x; + for (x = (LoadAddr & 0xF000); x < 0x10000; x += 0x1000) + BANKSET(x, ((x - (LoadAddr & 0x7000)) >> 12)); + } + + SetReadHandler(0xFFFA, 0xFFFD, NSFVectorRead); + + SetWriteHandler(0x2000, 0x3fff, 0); + SetReadHandler(0x2000, 0x37ff, 0); + SetReadHandler(0x3836, 0x3FFF, 0); + SetReadHandler(0x3800, 0x3835, NSFROMRead); + + SetWriteHandler(0x5ff6, 0x5fff, NSF_write); + + SetWriteHandler(0x3ff0, 0x3fff, NSF_write); + SetReadHandler(0x3ff0, 0x3fff, NSF_read); + + + if (NSFHeader.SoundChip & 1) { + NSFVRC6_Init(); + } else if (NSFHeader.SoundChip & 2) { + NSFVRC7_Init(); + } else if (NSFHeader.SoundChip & 4) { + FDSSoundReset(); + } else if (NSFHeader.SoundChip & 8) { + NSFMMC5_Init(); + } else if (NSFHeader.SoundChip & 0x10) { + NSFN106_Init(); + } else if (NSFHeader.SoundChip & 0x20) { + NSFAY_Init(); + } + CurrentSong = NSFHeader.StartingSong; + SongReload = 0xFF; + NSFNMIFlags = 0; +} + +static DECLFW(NSF_write) { + switch (A) { + case 0x3FF3: NSFNMIFlags |= 1; break; + case 0x3FF4: NSFNMIFlags &= ~2; break; + case 0x3FF5: NSFNMIFlags |= 2; break; + + case 0x5FF6: + case 0x5FF7: if (!(NSFHeader.SoundChip & 4)) return; + case 0x5FF8: + case 0x5FF9: + case 0x5FFA: + case 0x5FFB: + case 0x5FFC: + case 0x5FFD: + case 0x5FFE: + case 0x5FFF: if (!BSon) return; + A &= 0xF; + BANKSET((A * 4096), V); + break; + } +} + +static DECLFR(NSF_read) { + int x; + + switch (A) { + case 0x3ff0: x = SongReload; + #ifdef FCEUDEF_DEBUGGER + if (!fceuindbg) + #endif + SongReload = 0; + return x; + case 0x3ff1: + #ifdef FCEUDEF_DEBUGGER + if (!fceuindbg) + #endif + { + memset(RAM, 0x00, 0x800); + + BWrite[0x4015](0x4015, 0x0); + for (x = 0; x < 0x14; x++) + BWrite[0x4000 + x](0x4000 + x, 0); + BWrite[0x4015](0x4015, 0xF); + + if (NSFHeader.SoundChip & 4) { + BWrite[0x4017](0x4017, 0xC0); /* FDS BIOS writes $C0 */ + BWrite[0x4089](0x4089, 0x80); + BWrite[0x408A](0x408A, 0xE8); + } else { + memset(ExWRAM, 0x00, 8192); + BWrite[0x4017](0x4017, 0xC0); + BWrite[0x4017](0x4017, 0xC0); + BWrite[0x4017](0x4017, 0x40); + } + + if (BSon) { + for (x = 0; x < 8; x++) + BANKSET(0x8000 + x * 4096, NSFHeader.BankSwitch[x]); + } + return(CurrentSong - 1); + } + case 0x3FF3: return PAL; + } + return 0; +} + +uint8 FCEU_GetJoyJoy(void); + +static int special = 0; + +void DrawNSF(uint8 *XBuf) { + char snbuf[16]; + int x; + + if (vismode == 0) return; + + memset(XBuf, 0, 256 * 240); + + + { + int32 *Bufpl; + int32 mul = 0; + + int l; + l = GetSoundBuffer(&Bufpl); + + if (special == 0) { + if (FSettings.SoundVolume) + mul = 8192 * 240 / (16384 * FSettings.SoundVolume / 50); + for (x = 0; x < 256; x++) { + uint32 y; + y = 142 + ((Bufpl[(x * l) >> 8] * mul) >> 14); + if (y < 240) + XBuf[x + y * 256] = 3; + } + } else if (special == 1) { + if (FSettings.SoundVolume) + mul = 8192 * 240 / (8192 * FSettings.SoundVolume / 50); + for (x = 0; x < 256; x++) { + double r; + uint32 xp, yp; + + r = (Bufpl[(x * l) >> 8] * mul) >> 14; + xp = 128 + r*cos(x*M_PI*2 / 256); + yp = 120 + r*sin(x*M_PI*2 / 256); + xp &= 255; + yp %= 240; + XBuf[xp + yp * 256] = 3; + } + } else if (special == 2) { + static double theta = 0; + if (FSettings.SoundVolume) + mul = 8192 * 240 / (16384 * FSettings.SoundVolume / 50); + for (x = 0; x < 128; x++) { + double xc, yc; + double r, t; + uint32 m, n; + + xc = (double)128 - x; + yc = 0 - ((double)(((Bufpl[(x * l) >> 8]) * mul) >> 14)); + t = M_PI + atan(yc / xc); + r = sqrt(xc * xc + yc * yc); + + t += theta; + m = 128 + r*cos(t); + n = 120 + r*sin(t); + + if (m < 256 && n < 240) + XBuf[m + n * 256] = 3; + } + for (x = 128; x < 256; x++) { + double xc, yc; + double r, t; + uint32 m, n; + + xc = (double)x - 128; + yc = (double)((Bufpl[(x * l) >> 8] * mul) >> 14); + t = atan(yc / xc); + r = sqrt(xc * xc + yc * yc); + + t += theta; + m = 128 + r*cos(t); + n = 120 + r*sin(t); + + if (m < 256 && n < 240) + XBuf[m + n * 256] = 3; + } + theta += (double)M_PI / 256; + } + } + + DrawTextTrans(XBuf + 10 * 256 + 4 + (((31 - strlen((char*)NSFHeader.SongName)) << 2)), 256, NSFHeader.SongName, 6); + DrawTextTrans(XBuf + 26 * 256 + 4 + (((31 - strlen((char*)NSFHeader.Artist)) << 2)), 256, NSFHeader.Artist, 6); + DrawTextTrans(XBuf + 42 * 256 + 4 + (((31 - strlen((char*)NSFHeader.Copyright)) << 2)), 256, NSFHeader.Copyright, 6); + + DrawTextTrans(XBuf + 70 * 256 + 4 + (((31 - strlen("Song:")) << 2)), 256, (uint8*)"Song:", 6); + sprintf(snbuf, "<%d/%d>", CurrentSong, NSFHeader.TotalSongs); + DrawTextTrans(XBuf + 82 * 256 + 4 + (((31 - strlen(snbuf)) << 2)), 256, (uint8*)snbuf, 6); + + { + static uint8 last = 0; + uint8 tmp; + tmp = FCEU_GetJoyJoy(); + if ((tmp & JOY_RIGHT) && !(last & JOY_RIGHT)) { + if (CurrentSong < NSFHeader.TotalSongs) { + CurrentSong++; + SongReload = 0xFF; + } + } else if ((tmp & JOY_LEFT) && !(last & JOY_LEFT)) { + if (CurrentSong > 1) { + CurrentSong--; + SongReload = 0xFF; + } + } else if ((tmp & JOY_UP) && !(last & JOY_UP)) { + CurrentSong += 10; + if (CurrentSong > NSFHeader.TotalSongs) CurrentSong = NSFHeader.TotalSongs; + SongReload = 0xFF; + } else if ((tmp & JOY_DOWN) && !(last & JOY_DOWN)) { + CurrentSong -= 10; + if (CurrentSong < 1) CurrentSong = 1; + SongReload = 0xFF; + } else if ((tmp & JOY_START) && !(last & JOY_START)) + SongReload = 0xFF; + else if ((tmp & JOY_A) && !(last & JOY_A)) { + special = (special + 1) % 3; + } + last = tmp; + } +} + +void DoNSFFrame(void) { + if (((NSFNMIFlags & 1) && SongReload) || (NSFNMIFlags & 2)) + TriggerNMI(); +} + +void FCEUI_NSFSetVis(int mode) { + vismode = mode; +} + +int FCEUI_NSFChange(int amount) { + CurrentSong += amount; + if (CurrentSong < 1) CurrentSong = 1; + else if (CurrentSong > NSFHeader.TotalSongs) CurrentSong = NSFHeader.TotalSongs; + SongReload = 0xFF; + + return(CurrentSong); +} + +/* Returns total songs */ +int FCEUI_NSFGetInfo(uint8 *name, uint8 *artist, uint8 *copyright, int maxlen) { + strncpy(name, NSFHeader.SongName, maxlen); + strncpy(artist, NSFHeader.Artist, maxlen); + strncpy(copyright, NSFHeader.Copyright, maxlen); + return(NSFHeader.TotalSongs); +} diff --git a/src/drivers/libretro/fceu/state.c b/src/drivers/libretro/fceu/state.c new file mode 100644 index 0000000..5958970 --- /dev/null +++ b/src/drivers/libretro/fceu/state.c @@ -0,0 +1,365 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#ifdef _WIN32 +#include +#else +#include +#endif + +#include "fceu-types.h" +#include "x6502.h" +#include "fceu.h" +#include "sound.h" +#include "fceu-endian.h" +#include "fds.h" +#include "general.h" +#include "state.h" +#include "movie.h" +#include "fceu-memory.h" +#include "ppu.h" +#include "netplay.h" +#include "video.h" + +static void (*SPreSave)(void); +static void (*SPostSave)(void); + +static int SaveStateStatus[10]; + +static SFORMAT SFMDATA[64]; +static int SFEXINDEX; + +#define RLSB FCEUSTATE_RLSB //0x80000000 + +extern SFORMAT FCEUPPU_STATEINFO[]; +extern SFORMAT FCEUSND_STATEINFO[]; +extern SFORMAT FCEUCTRL_STATEINFO[]; + + +SFORMAT SFCPU[] = { + { &X.PC, 2 | RLSB, "PC\0" }, + { &X.A, 1, "A\0\0" }, + { &X.X, 1, "X\0\0" }, + { &X.Y, 1, "Y\0\0" }, + { &X.S, 1, "S\0\0" }, + { &X.P, 1, "P\0\0" }, + { &X.DB, 1, "DB"}, +#ifdef COPYFAMI + { RAM, 0x4000, "RAM" }, +#else + { RAM, 0x800, "RAM" }, +#endif + { 0 } +}; + +SFORMAT SFCPUC[] = { + { &X.jammed, 1, "JAMM" }, + { &X.IRQlow, 4 | RLSB, "IQLB" }, + { &X.tcount, 4 | RLSB, "ICoa" }, + { &X.count, 4 | RLSB, "ICou" }, + { ×tampbase, sizeof(timestampbase) | RLSB, "TSBS" }, + { 0 } +}; + +static int SubWrite(memstream_t *mem, SFORMAT *sf) +{ + uint32 acc=0; + + while(sf->v) + { + if(sf->s==~0) /* Link to another struct. */ + { + uint32 tmp; + + if(!(tmp=SubWrite(mem, (SFORMAT *)sf->v))) + return(0); + acc+=tmp; + sf++; + continue; + } + + acc+=8; /* Description + size */ + acc+=sf->s&(~RLSB); + + if(mem) /* Are we writing or calculating the size of this block? */ + { + memstream_write(mem, sf->desc, 4); + write32le_mem(sf->s&(~RLSB), mem); + +#ifdef MSB_FIRST + if(sf->s&RLSB) + FlipByteOrder(sf->v,sf->s&(~RLSB)); +#endif + + memstream_write(mem, (uint8 *)sf->v, sf->s&(~RLSB)); + /* Now restore the original byte order. */ +#ifdef MSB_FIRST + if(sf->s&RLSB) + FlipByteOrder(sf->v,sf->s&(~RLSB)); +#endif + } + sf++; + } + + return acc; +} + +static int WriteStateChunk(memstream_t *mem, int type, SFORMAT *sf) +{ + int bsize; + + memstream_putc(mem, type); + + bsize = SubWrite(0,sf); + write32le_mem(bsize, mem); + + if (!SubWrite(mem, sf)) + return 0; + return bsize + 5; +} + +static SFORMAT *CheckS(SFORMAT *sf, uint32 tsize, char *desc) +{ + while (sf->v) + { + if (sf->s == ~0) + { /* Link to another SFORMAT structure. */ + SFORMAT *tmp; + if ((tmp = CheckS((SFORMAT*)sf->v, tsize, desc))) + return(tmp); + sf++; + continue; + } + if (!strncmp(desc, sf->desc, 4)) + { + if (tsize != (sf->s & (~RLSB))) + return(0); + return(sf); + } + sf++; + } + return(0); +} + +static int ReadStateChunk(memstream_t *mem, SFORMAT *sf, int size) +{ + SFORMAT *tmp; + int temp; + temp=memstream_pos(mem); + + while(memstream_pos(mem)v, tmp->s&(~RLSB)); + +#ifdef MSB_FIRST + if(tmp->s&RLSB) + FlipByteOrder(tmp->v,tmp->s&(~RLSB)); +#endif + } + else + memstream_seek(mem,tsize,SEEK_CUR); + } + return 1; +} + +static int ReadStateChunks(memstream_t *st, int32 totalsize) +{ + int t; + uint32 size; + int ret = 1; + + while (totalsize > 0) + { + t = memstream_getc(st); + if (t == EOF) + break; + if (!read32le_mem(&size,st)) + break; + totalsize -= size + 5; + + switch(t) + { + case 1: + if (!ReadStateChunk(st, SFCPU, size)) + ret = 0; + break; + case 2: + if (!ReadStateChunk(st, SFCPUC, size)) + ret = 0; + else + X.mooPI = X.P; // Quick and dirty hack. + break; + case 3: + if (!ReadStateChunk(st, FCEUPPU_STATEINFO, size)) + ret = 0; + break; + case 4: + if (!ReadStateChunk(st, FCEUCTRL_STATEINFO, size)) + ret = 0; + break; + case 5: + if (!ReadStateChunk(st, FCEUSND_STATEINFO, size)) + ret = 0; + break; + case 0x10: + if (!ReadStateChunk(st, SFMDATA, size)) + ret = 0; + break; + default: + if (memstream_seek(st, size, SEEK_CUR) < 0) + goto endo; + break; + } + } +endo: + return ret; +} + +int CurrentState = 0; +extern int geniestage; + +void FCEUSS_Save_Mem(void) +{ + memstream_t *mem = memstream_open(1); + + uint32 totalsize; + uint8 header[16] = {0}; + + header[0] = 'F'; + header[1] = 'C'; + header[2] = 'S'; + header[3] = 0xFF; + + FCEU_en32lsb(header + 8, FCEU_VERSION_NUMERIC); + memstream_write(mem, header, 16); + + FCEUPPU_SaveState(); + totalsize = WriteStateChunk(mem, 1, SFCPU); + totalsize += WriteStateChunk(mem, 2, SFCPUC); + totalsize += WriteStateChunk(mem, 3, FCEUPPU_STATEINFO); + totalsize += WriteStateChunk(mem, 4, FCEUCTRL_STATEINFO); + totalsize += WriteStateChunk(mem, 5, FCEUSND_STATEINFO); + + if (SPreSave) + SPreSave(); + + totalsize += WriteStateChunk(mem, 0x10, SFMDATA); + + if (SPreSave) + SPostSave(); + + memstream_seek(mem, 4, SEEK_SET); + write32le_mem(totalsize, mem); + + memstream_close(mem); +} + +void FCEUSS_Load_Mem(void) +{ + memstream_t *mem = memstream_open(0); + + uint8 header[16]; + int stateversion; + int x; + + memstream_read(mem, header, 16); + + if (memcmp(header,"FCS",3) != 0) + return; + + if (header[3] == 0xFF) + stateversion = FCEU_de32lsb(header + 8); + else + stateversion = header[3] * 100; + + x = ReadStateChunks(mem, *(uint32*)(header + 4)); + + if (stateversion < 9500) + X.IRQlow=0; + + if (GameStateRestore) + GameStateRestore(stateversion); + + if (x) + { + FCEUPPU_LoadState(stateversion); + FCEUSND_LoadState(stateversion); + } + + memstream_close(mem); +} + +void FCEUSS_CheckStates(void) +{ + MEM_TYPE *st = NULL; + char *fn; + int ssel; + + for (ssel = 0; ssel < 10; ssel++) + { + st = fopen(fn = FCEU_MakeFName(FCEUMKF_STATE, ssel, 0), "rb"); + free(fn); + if (st) + { + SaveStateStatus[ssel] = 1; + fclose(st); + } + else + SaveStateStatus[ssel] = 0; + } + + CurrentState = 0; +} + +void ResetExState(void (*PreSave)(void), void (*PostSave)(void)) +{ + SPreSave = PreSave; + SPostSave = PostSave; + SFEXINDEX = 0; +} + +void AddExState(void *v, uint32 s, int type, char *desc) +{ + memset(SFMDATA[SFEXINDEX].desc, 0, sizeof(SFMDATA[SFEXINDEX].desc)); + if (desc) + strncpy(SFMDATA[SFEXINDEX].desc, desc, sizeof(SFMDATA[SFEXINDEX].desc)); + SFMDATA[SFEXINDEX].v = v; + SFMDATA[SFEXINDEX].s = s; + if (type) SFMDATA[SFEXINDEX].s |= RLSB; + if (SFEXINDEX < 63) SFEXINDEX++; + SFMDATA[SFEXINDEX].v = 0; // End marker. +} + +void FCEU_DrawSaveStates(uint8 *XBuf) +{ +} + diff --git a/src/drivers/libretro/fceu/unif.c b/src/drivers/libretro/fceu/unif.c new file mode 100644 index 0000000..0c1c6da --- /dev/null +++ b/src/drivers/libretro/fceu/unif.c @@ -0,0 +1,626 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* TODO: Battery backup file saving, mirror force */ +/* **INCOMPLETE** */ +/* Override stuff: CHR RAM instead of CHR ROM, mirroring. */ + +#include +#include +#include + + +#include "fceu-types.h" +#include "fceu.h" +#include "cart.h" +#include "unif.h" +#include "ines.h" +#include "general.h" +#include "state.h" +#include "fceu-endian.h" +#include "file.h" +#include "fceu-memory.h" +#include "input.h" +#include "md5.h" + +typedef struct { + char ID[4]; + uint32 info; +} UNIF_HEADER; + +typedef struct { + char *name; + void (*init)(CartInfo *); + int flags; +} BMAPPING; + +typedef struct { + char *name; + int (*init)(FCEUFILE *fp); +} BFMAPPING; + +CartInfo UNIFCart; + +static int vramo; +static int mirrortodo; +static uint8 *boardname; +static uint8 *sboardname; + +static uint32 CHRRAMSize; +uint8 *UNIFchrrama = 0; + +static UNIF_HEADER unhead; +static UNIF_HEADER uchead; + + +static uint8 *malloced[32]; +static uint32 mallocedsizes[32]; + +static int FixRomSize(uint32 size, uint32 minimum) { + uint32 x = 1; + + if (size < minimum) + return minimum; + while (x < size) + x <<= 1; + return x; +} + +static void FreeUNIF(void) { + int x; + if (UNIFchrrama) { + free(UNIFchrrama); UNIFchrrama = 0; + } + if (boardname) { + free(boardname); boardname = 0; + } + for (x = 0; x < 32; x++) { + if (malloced[x]) { + free(malloced[x]); malloced[x] = 0; + } + } +} + +static void ResetUNIF(void) { + int x; + for (x = 0; x < 32; x++) + malloced[x] = 0; + vramo = 0; + boardname = 0; + mirrortodo = 0; + memset(&UNIFCart, 0, sizeof(UNIFCart)); + UNIFchrrama = 0; +} + +static uint8 exntar[2048]; + +static void MooMirroring(void) { + if (mirrortodo < 0x4) + SetupCartMirroring(mirrortodo, 1, 0); + else if (mirrortodo == 0x4) { + SetupCartMirroring(4, 1, exntar); + AddExState(exntar, 2048, 0, "EXNR"); + } else + SetupCartMirroring(0, 0, 0); +} + +static int DoMirroring(FCEUFILE *fp) { + int t; + uint32 i; + if (uchead.info == 1) { + if ((t = FCEU_fgetc(fp)) == EOF) + return(0); + mirrortodo = t; + { + static char *stuffo[6] = { "Horizontal", "Vertical", "$2000", "$2400", "\"Four-screen\"", "Controlled by Mapper Hardware" }; + if (t < 6) + FCEU_printf(" Name/Attribute Table Mirroring: %s\n", stuffo[t]); + } + } else { + FCEU_printf(" Incorrect Mirroring Chunk Size (%d). Data is:", uchead.info); + for (i = 0; i < uchead.info; i++) { + if ((t = FCEU_fgetc(fp)) == EOF) + return(0); + FCEU_printf(" %02x", t); + } + FCEU_printf("\n Default Name/Attribute Table Mirroring: Horizontal\n", uchead.info); + mirrortodo = 0; + } + return(1); +} + +static int NAME(FCEUFILE *fp) { + char namebuf[100]; + int index; + int t; + + FCEU_printf(" Name: "); + index = 0; + + while ((t = FCEU_fgetc(fp)) > 0) + if (index < 99) + namebuf[index++] = t; + + namebuf[index] = 0; + FCEU_printf("%s\n", namebuf); + + if (!GameInfo->name) { + GameInfo->name = malloc(strlen(namebuf) + 1); + strcpy(GameInfo->name, namebuf); + } + return(1); +} + +static int DINF(FCEUFILE *fp) { + char name[100], method[100]; + uint8 d, m; + uint16 y; + int t; + + if (FCEU_fread(name, 1, 100, fp) != 100) + return(0); + if ((t = FCEU_fgetc(fp)) == EOF) return(0); + d = t; + if ((t = FCEU_fgetc(fp)) == EOF) return(0); + m = t; + if ((t = FCEU_fgetc(fp)) == EOF) return(0); + y = t; + if ((t = FCEU_fgetc(fp)) == EOF) return(0); + y |= t << 8; + if (FCEU_fread(method, 1, 100, fp) != 100) + return(0); + name[99] = method[99] = 0; + FCEU_printf(" Dumped by: %s\n", name); + FCEU_printf(" Dumped with: %s\n", method); + { + char *months[12] = { + "January", "February", "March", "April", "May", "June", "July", + "August", "September", "October", "November", "December" + }; + FCEU_printf(" Dumped on: %s %d, %d\n", months[(m - 1) % 12], d, y); + } + return(1); +} + +static int CTRL(FCEUFILE *fp) { + int t; + uint32 i; + if (uchead.info == 1) { + if ((t = FCEU_fgetc(fp)) == EOF) + return(0); + /* The information stored in this byte isn't very helpful, but it's + better than nothing...maybe. + */ + + if (t & 1) + GameInfo->input[0] = GameInfo->input[1] = SI_GAMEPAD; + else + GameInfo->input[0] = GameInfo->input[1] = SI_NONE; + if (t & 2) + GameInfo->input[1] = SI_ZAPPER; + } else { + FCEU_printf(" Incorrect Control Chunk Size (%d). Data is:", uchead.info); + for (i = 0; i < uchead.info; i++) { + t = FCEU_fgetc(fp); + FCEU_printf(" %02x", t); + } + FCEU_printf("\n"); + GameInfo->input[0] = GameInfo->input[1] = SI_GAMEPAD; + } + return(1); +} + +static int TVCI(FCEUFILE *fp) { + int t; + if ((t = FCEU_fgetc(fp)) == EOF) + return(0); + if (t <= 2) { + char *stuffo[3] = { "NTSC", "PAL", "NTSC and PAL" }; + if (t == 0) + GameInfo->vidsys = GIV_NTSC; + else if (t == 1) + GameInfo->vidsys = GIV_PAL; + FCEU_printf(" TV Standard Compatibility: %s\n", stuffo[t]); + } + return(1); +} + +static int EnableBattery(FCEUFILE *fp) { + FCEU_printf(" Battery-backed.\n"); + if (FCEU_fgetc(fp) == EOF) + return(0); + UNIFCart.battery = 1; + return(1); +} + +static int LoadPRG(FCEUFILE *fp) { + int z, t; + z = uchead.ID[3] - '0'; + + if (z < 0 || z > 15) + return(0); + FCEU_printf(" PRG ROM %d size: %d", z, (int)uchead.info); + if (malloced[z]) + free(malloced[z]); + t = FixRomSize(uchead.info, 2048); + if (!(malloced[z] = (uint8*)FCEU_malloc(t))) + return(0); + mallocedsizes[z] = t; + memset(malloced[z] + uchead.info, 0xFF, t - uchead.info); + if (FCEU_fread(malloced[z], 1, uchead.info, fp) != uchead.info) { + FCEU_printf("Read Error!\n"); + return(0); + } else + FCEU_printf("\n"); + + SetupCartPRGMapping(z, malloced[z], t, 0); + return(1); +} + +static int SetBoardName(FCEUFILE *fp) { + if (!(boardname = (uint8*)FCEU_malloc(uchead.info + 1))) + return(0); + FCEU_fread(boardname, 1, uchead.info, fp); + boardname[uchead.info] = 0; + FCEU_printf(" Board name: %s\n", boardname); + sboardname = boardname; + if (!memcmp(boardname, "NES-", 4) || !memcmp(boardname, "UNL-", 4) || !memcmp(boardname, "HVC-", 4) || !memcmp(boardname, "BTL-", 4) || !memcmp(boardname, "BMC-", 4)) + sboardname += 4; + return(1); +} + +static int LoadCHR(FCEUFILE *fp) { + int z, t; + z = uchead.ID[3] - '0'; + if (z < 0 || z > 15) + return(0); + FCEU_printf(" CHR ROM %d size: %d", z, (int)uchead.info); + if (malloced[16 + z]) + free(malloced[16 + z]); + t = FixRomSize(uchead.info, 8192); + if (!(malloced[16 + z] = (uint8*)FCEU_malloc(t))) + return(0); + mallocedsizes[16 + z] = t; + memset(malloced[16 + z] + uchead.info, 0xFF, t - uchead.info); + if (FCEU_fread(malloced[16 + z], 1, uchead.info, fp) != uchead.info) { + FCEU_printf("Read Error!\n"); + return(0); + } else + FCEU_printf("\n"); + + SetupCartCHRMapping(z, malloced[16 + z], t, 0); + return(1); +} + +#define BMCFLAG_FORCE4 0x01 +#define BMCFLAG_16KCHRR 0x02 +#define BMCFLAG_32KCHRR 0x04 +#define BMCFLAG_128KCHRR 0x08 +#define BMCFLAG_256KCHRR 0x10 + +static BMAPPING bmap[] = { + { "11160", BMC11160_Init, 0 }, + { "12-IN-1", BMC12IN1_Init, 0 }, + { "13in1JY110", BMC13in1JY110_Init, 0 }, + { "190in1", BMC190in1_Init, 0 }, + { "22211", UNL22211_Init, 0 }, + { "3D-BLOCK", UNL3DBlock_Init, 0 }, + { "411120-C", BMC411120C_Init, 0 }, + { "42in1ResetSwitch", Mapper226_Init, 0 }, + { "43272", UNL43272_Init, 0 }, + { "603-5052", UNL6035052_Init, 0 }, + { "64in1NoRepeat", BMC64in1nr_Init, 0 }, + { "70in1", BMC70in1_Init, 0 }, + { "70in1B", BMC70in1B_Init, 0 }, + { "810544-C-A1", BMC810544CA1_Init, 0 }, + { "8157", UNL8157_Init, 0 }, + { "8237", UNL8237_Init, 0 }, + { "8237A", UNL8237A_Init, 0 }, + { "830118C", BMC830118C_Init, 0 }, + { "A65AS", BMCA65AS_Init, 0 }, + { "AC08", AC08_Init, 0 }, + { "ANROM", ANROM_Init, 0 }, + { "AX5705", UNLAX5705_Init, 0 }, + { "BB", UNLBB_Init, 0 }, + { "BS-5", BMCBS5_Init, 0 }, + { "CC-21", UNLCC21_Init, 0 }, + { "CITYFIGHT", UNLCITYFIGHT_Init, 0 }, + { "10-24-C-A1", BMC1024CA1_Init, 0 }, + { "CNROM", CNROM_Init, 0 }, + { "CPROM", CPROM_Init, BMCFLAG_16KCHRR }, + { "D1038", BMCD1038_Init, 0 }, + { "DANCE", UNLOneBus_Init, 0 }, // redundant + { "DANCE2000", UNLD2000_Init, 0 }, + { "DREAMTECH01", DreamTech01_Init, 0 }, + { "EDU2000", UNLEDU2000_Init, 0 }, + { "EKROM", EKROM_Init, 0 }, + { "ELROM", ELROM_Init, 0 }, + { "ETROM", ETROM_Init, 0 }, + { "EWROM", EWROM_Init, 0 }, + { "FK23C", BMCFK23C_Init, BMCFLAG_256KCHRR }, + { "FK23CA", BMCFK23CA_Init, BMCFLAG_256KCHRR }, + { "FS304", UNLFS304_Init, 0 }, + { "G-146", BMCG146_Init, 0 }, + { "GK-192", BMCGK192_Init, 0 }, + { "GS-2004", BMCGS2004_Init, 0 }, + { "GS-2013", BMCGS2013_Init, 0 }, + { "Ghostbusters63in1", BMCGhostbusters63in1_Init, 0 }, + { "H2288", UNLH2288_Init, 0 }, + { "HKROM", HKROM_Init, 0 }, + { "KOF97", UNLKOF97_Init, 0 }, + { "KONAMI-QTAI", Mapper190_Init, 0 }, + { "KS7012", UNLKS7012_Init, 0 }, + { "KS7013B", UNLKS7013B_Init, 0 }, + { "KS7017", UNLKS7017_Init, 0 }, + { "KS7030", UNLKS7030_Init, 0 }, + { "KS7031", UNLKS7031_Init, 0 }, + { "KS7032", UNLKS7032_Init, 0 }, + { "KS7037", UNLKS7037_Init, 0 }, + { "KS7057", UNLKS7057_Init, 0 }, + { "LE05", LE05_Init, 0 }, + { "LH10", LH10_Init, 0 }, + { "LH32", LH32_Init, 0 }, + { "LH53", LH53_Init, 0 }, + { "MALISB", UNLMaliSB_Init, 0 }, + { "MARIO1-MALEE2", MALEE_Init, 0 }, + { "MHROM", MHROM_Init, 0 }, + { "N625092", UNLN625092_Init, 0 }, + { "NROM", NROM_Init, 0 }, + { "NROM-128", NROM_Init, 0 }, + { "NROM-256", NROM_Init, 0 }, + { "NTBROM", Mapper68_Init, 0 }, + { "NTD-03", BMCNTD03_Init, 0 }, + { "NovelDiamond9999999in1", Novel_Init, 0 }, + { "OneBus", UNLOneBus_Init, 0 }, + { "PEC-586", UNLPEC586Init, 0 }, + { "RROM", NROM_Init, 0 }, + { "RROM-128", NROM_Init, 0 }, + { "SA-002", TCU02_Init, 0 }, + { "SA-0036", SA0036_Init, 0 }, + { "SA-0037", SA0037_Init, 0 }, + { "SA-009", SA009_Init, 0 }, + { "SA-016-1M", SA0161M_Init, 0 }, + { "SA-72007", SA72007_Init, 0 }, + { "SA-72008", SA72008_Init, 0 }, + { "SA-9602B", SA9602B_Init, BMCFLAG_32KCHRR }, + { "SA-NROM", TCA01_Init, 0 }, + { "SAROM", SAROM_Init, 0 }, + { "SBROM", SBROM_Init, 0 }, + { "SC-127", UNLSC127_Init, 0 }, + { "SCROM", SCROM_Init, 0 }, + { "SEROM", SEROM_Init, 0 }, + { "SGROM", SGROM_Init, 0 }, + { "SHERO", UNLSHeroes_Init, 0 }, + { "SKROM", SKROM_Init, 0 }, + { "SL12", UNLSL12_Init, 0 }, + { "SL1632", UNLSL1632_Init, 0 }, + { "SL1ROM", SL1ROM_Init, 0 }, + { "SLROM", SLROM_Init, 0 }, + { "SMB2J", UNLSMB2J_Init, 0 }, + { "SNROM", SNROM_Init, 0 }, + { "SOROM", SOROM_Init, 0 }, + { "SSS-NROM-256", SSSNROM_Init, 0 }, + { "SUNSOFT_UNROM", SUNSOFT_UNROM_Init, 0 }, // fix me, real pcb name, real pcb type + { "Sachen-74LS374N", S74LS374N_Init, 0 }, + { "Sachen-74LS374NA", S74LS374NA_Init, 0 }, //seems to be custom mapper + { "Sachen-8259A", S8259A_Init, 0 }, + { "Sachen-8259B", S8259B_Init, 0 }, + { "Sachen-8259C", S8259C_Init, 0 }, + { "Sachen-8259D", S8259D_Init, 0 }, + { "Super24in1SC03", Super24_Init, 0 }, + { "SuperHIK8in1", Mapper45_Init, 0 }, + { "Supervision16in1", Supervision16_Init, 0 }, + { "T-227-1", BMCT2271_Init, 0 }, + { "T-230", UNLT230_Init, 0 }, + { "T-262", BMCT262_Init, 0 }, + { "TBROM", TBROM_Init, 0 }, + { "TC-U01-1.5M", TCU01_Init, 0 }, + { "TEK90", Mapper90_Init, 0 }, + { "TEROM", TEROM_Init, 0 }, + { "TF1201", UNLTF1201_Init, 0 }, + { "TFROM", TFROM_Init, 0 }, + { "TGROM", TGROM_Init, 0 }, + { "TKROM", TKROM_Init, 0 }, + { "TKSROM", TKSROM_Init, 0 }, + { "TLROM", TLROM_Init, 0 }, + { "TLSROM", TLSROM_Init, 0 }, + { "TQROM", TQROM_Init, 0 }, + { "TR1ROM", TFROM_Init, BMCFLAG_FORCE4 }, + { "TSROM", TSROM_Init, 0 }, + { "TVROM", TLROM_Init, BMCFLAG_FORCE4 }, + { "Transformer", Transformer_Init, 0 }, + { "UNROM", UNROM_Init, 0 }, + { "UOROM", UNROM_Init, 0 }, + { "VRC7", UNLVRC7_Init, 0 }, + { "YOKO", UNLYOKO_Init, 0 }, + { "COOLBOY", COOLBOY_Init, BMCFLAG_256KCHRR }, + { "158B", UNL158B_Init, 0 }, + { "DRAGONFIGHTER", UNLBMW8544_Init, 0}, + +#ifdef COPYFAMI + { "COPYFAMI_MMC3", MapperCopyFamiMMC3_Init, 0 }, + { "COPYFAMI", MapperCopyFami_Init, 0 }, +#endif + + { NULL, NULL, 0 } +}; + +static BFMAPPING bfunc[] = { + { "CTRL", CTRL }, + { "TVCI", TVCI }, + { "BATR", EnableBattery }, + { "MIRR", DoMirroring }, + { "PRG", LoadPRG }, + { "CHR", LoadCHR }, + { "NAME", NAME }, + { "MAPR", SetBoardName }, + { "DINF", DINF }, + { NULL, NULL } +}; + +int LoadUNIFChunks(FCEUFILE *fp) { + int x; + int t; + for (;; ) { + t = FCEU_fread(&uchead, 1, 4, fp); + if (t < 4) { + if (t > 0) + return 0; + return 1; + } + if (!(FCEU_read32le(&uchead.info, fp))) + return 0; + t = 0; + x = 0; + while (bfunc[x].name) { + if (!memcmp(&uchead, bfunc[x].name, strlen(bfunc[x].name))) { + if (!bfunc[x].init(fp)) + return 0; + t = 1; + break; + } + x++; + } + if (!t) + if (FCEU_fseek(fp, uchead.info, SEEK_CUR)) + return(0); + } +} + +static int InitializeBoard(void) { + int x = 0; + + if (!sboardname) return(0); + + while (bmap[x].name) { + if (!strcmp((char*)sboardname, (char*)bmap[x].name)) { + if (!malloced[16]) { + if (bmap[x].flags & BMCFLAG_16KCHRR) + CHRRAMSize = 16; + else if (bmap[x].flags & BMCFLAG_32KCHRR) + CHRRAMSize = 32; + else if (bmap[x].flags & BMCFLAG_128KCHRR) + CHRRAMSize = 128; + else if (bmap[x].flags & BMCFLAG_256KCHRR) + CHRRAMSize = 256; + else + CHRRAMSize = 8; + CHRRAMSize <<= 10; + if ((UNIFchrrama = (uint8*)FCEU_malloc(CHRRAMSize))) { + SetupCartCHRMapping(0, UNIFchrrama, CHRRAMSize, 1); + AddExState(UNIFchrrama, CHRRAMSize, 0, "CHRR"); + } else + return(-1); + } + if (bmap[x].flags & BMCFLAG_FORCE4) + mirrortodo = 4; + MooMirroring(); + bmap[x].init(&UNIFCart); + return(1); + } + x++; + } + FCEU_PrintError("Board type not supported."); + return(0); +} + +static void UNIFGI(int h) { + switch (h) { + case GI_RESETM2: + if (UNIFCart.Reset) + UNIFCart.Reset(); + break; + case GI_POWER: + if (UNIFCart.Power) + UNIFCart.Power(); + if (UNIFchrrama) memset(UNIFchrrama, 0, 8192); + break; + case GI_CLOSE: + FCEU_SaveGameSave(&UNIFCart); + if (UNIFCart.Close) + UNIFCart.Close(); + FreeUNIF(); + break; + } +} + +int UNIFLoad(const char *name, FCEUFILE *fp) { + FCEU_fseek(fp, 0, SEEK_SET); + FCEU_fread(&unhead, 1, 4, fp); + if (memcmp(&unhead, "UNIF", 4)) + return 0; + + ResetCartMapping(); + + ResetExState(0, 0); + ResetUNIF(); + if (!FCEU_read32le(&unhead.info, fp)) + goto aborto; + if (FCEU_fseek(fp, 0x20, SEEK_SET) < 0) + goto aborto; + if (!LoadUNIFChunks(fp)) + goto aborto; + { + int x; + struct md5_context md5; + + md5_starts(&md5); + + for (x = 0; x < 32; x++) + if (malloced[x]) { + md5_update(&md5, malloced[x], mallocedsizes[x]); + } + md5_finish(&md5, UNIFCart.MD5); + FCEU_printf(" ROM MD5: 0x%s\n", md5_asciistr(UNIFCart.MD5)); + memcpy(GameInfo->MD5, UNIFCart.MD5, sizeof(UNIFCart.MD5)); + } + + if (!InitializeBoard()) + goto aborto; + + FCEU_LoadGameSave(&UNIFCart); + GameInterface = UNIFGI; + return 1; + + aborto: + + FreeUNIF(); + ResetUNIF(); + return 0; +} + +int CopyFamiLoad() { + ResetCartMapping(); + ResetExState(0, 0); + + sboardname = "COPYFAMI"; + if (!InitializeBoard()) + goto aborto; + + FCEU_LoadGameSave(&UNIFCart); + GameInterface = UNIFGI; + return 1; + + aborto: + + FreeUNIF(); + ResetUNIF(); + return 0; +} diff --git a/src/drivers/libretro/fceu/video.c b/src/drivers/libretro/fceu/video.c new file mode 100644 index 0000000..076579a --- /dev/null +++ b/src/drivers/libretro/fceu/video.c @@ -0,0 +1,109 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +#include "fceu-types.h" +#include "video.h" +#include "fceu.h" +#include "general.h" +#include "fceu-memory.h" +#include "crc32.h" +#include "state.h" +#include "palette.h" +#include "nsf.h" +#include "input.h" +#include "vsuni.h" + +uint8 *XBuf = NULL; + +void FCEU_KillVirtualVideo(void) +{ + if (XBuf) + free(XBuf); + XBuf = 0; +} + +int FCEU_InitVirtualVideo(void) +{ + // 256 bytes per scanline, * 240 scanline maximum, +8 for alignment, + if (!XBuf) + XBuf = (uint8*)(FCEU_malloc(256 * 256 + 8)); + + if (!XBuf) + return 0; + + if (sizeof(uint8*) == 4) + { + uintptr_t m; + m = (uintptr_t)*XBuf; + m = (4 - m) & 3; + XBuf += m; + } + memset(XBuf, 128, 256 * 256); + return 1; +} + +static int howlong; +static char errmsg[65]; + +#include "drawing.h" + +void FCEUI_SaveSnapshot(void) { } + +void FCEU_PutImage(void) +{ + if (GameInfo->type == GIT_NSF) + DrawNSF(XBuf); + else + { + if (GameInfo->type == GIT_VSUNI) + FCEU_VSUniDraw(XBuf); + } + if (howlong) howlong--; +} + +void FCEU_PutImageDummy(void) +{ +} + +void FCEU_DispMessage(char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vsprintf(errmsg, format, ap); + va_end(ap); + + howlong = 180; +} + +void FCEU_ResetMessages(void) +{ + howlong = 180; +} + +int SaveSnapshot(void) +{ + return(0); +} diff --git a/src/drivers/libretro/griffin.c b/src/drivers/libretro/griffin.c index b39209e..d910141 100644 --- a/src/drivers/libretro/griffin.c +++ b/src/drivers/libretro/griffin.c @@ -8,22 +8,22 @@ #include "cheat.c" #include "crc32.c" #include "debug.c" -#include "fceu-endian.c" -#include "fceu-memory.c" -#include "misc.c" -#include "fceu.c" -#include "fds.c" -#include "file.c" +#include "drivers/libretro/fceu/fceu-endian.c" +#include "drivers/libretro/fceu/fceu-memory.c" +#include "drivers/libretro/fceu/misc.c" +#include "drivers/libretro/fceu/fceu.c" +#include "drivers/libretro/fceu/fds.c" +#include "drivers/libretro/fceu/file.c" #include "filter.c" -#include "general.c" -#include "input.c" +#include "drivers/libretro/fceu/general.c" +#include "drivers/libretro/fceu/input.c" #include "md5.c" -#include "nsf.c" +#include "drivers/libretro/fceu/nsf.c" #include "palette.c" #include "ppu.c" #include "sound.c" -#include "state.c" -#include "video.c" +#include "drivers/libretro/fceu/state.c" +#include "drivers/libretro/fceu/video.c" #include "vsuni.c" #endif diff --git a/src/fceu-endian.c b/src/fceu-endian.c index 754489f..fcdd64c 100644 --- a/src/fceu-endian.c +++ b/src/fceu-endian.c @@ -26,98 +26,70 @@ #include "fceu-types.h" #include "fceu-endian.h" -void FlipByteOrder(uint8 *src, uint32 count) -{ - uint8 *start = src; - uint8 *end = src + count - 1; +void FlipByteOrder(uint8 *src, uint32 count) { + uint8 *start = src; + uint8 *end = src + count - 1; - while(start < end) - { - uint8 tmp; + if ((count & 1) || !count) return; /* This shouldn't happen. */ - tmp = *end; - *end = *start; - *start = tmp; - end--; - start++; - } + while (count--) { + uint8 tmp; + + tmp = *end; + *end = *start; + *start = tmp; + end--; + start++; + } } -int write16le(uint16 b, FILE *fp) -{ - uint8 s[2]; - s[0] = b; - s[1] = b >> 8; - return((fwrite(s, 1, 2, fp) < 2) ? 0 : 2); +int write16le(uint16 b, FILE *fp) { + uint8 s[2]; + s[0] = b; + s[1] = b >> 8; + return((fwrite(s, 1, 2, fp) < 2) ? 0 : 2); } -int write32le(uint32 b, FILE *fp) -{ - uint8 s[4]; - s[0] = b; - s[1] = b >> 8; - s[2] = b >> 16; - s[3] = b >> 24; - return((fwrite(s, 1, 4, fp) < 4) ? 0 : 4); +int write32le(uint32 b, FILE *fp) { + uint8 s[4]; + s[0] = b; + s[1] = b >> 8; + s[2] = b >> 16; + s[3] = b >> 24; + return((fwrite(s, 1, 4, fp) < 4) ? 0 : 4); } -int read32le(uint32 *Bufo, FILE *fp) -{ - uint32 buf; - if (fread(&buf, 1, 4, fp) < 4) - return 0; -#ifdef MSB_FIRST - *(uint32*)Bufo = ((buf & 0xFF) << 24) | ((buf & 0xFF00) << 8) | ((buf & 0xFF0000) >> 8) | ((buf & 0xFF000000) >> 24); -#else - *(uint32*)Bufo = buf; -#endif - return 1; +int read32le(uint32 *Bufo, FILE *fp) { + uint32 buf; + if (fread(&buf, 1, 4, fp) < 4) + return 0; + #ifdef MSB_FIRST + *(uint32*)Bufo = ((buf & 0xFF) << 24) | ((buf & 0xFF00) << 8) | ((buf & 0xFF0000) >> 8) | ((buf & 0xFF000000) >> 24); + #else + *(uint32*)Bufo = buf; + #endif + return 1; } -int write32le_mem(uint32 b, memstream_t *mem) -{ - uint8 s[4]; - s[0]=b; - s[1]=b>>8; - s[2]=b>>16; - s[3]=b>>24; - return((memstream_write(mem, s, 4)<4)?0:4); +int read16le(char *d, FILE *fp) { + #ifdef MSB_FIRST + int ret; + ret = fread(d + 1, 1, 1, fp); + ret += fread(d, 1, 1, fp); + return ret < 2 ? 0 : 2; + #else + return((fread(d, 1, 2, fp) < 2) ? 0 : 2); + #endif } -int read32le_mem(uint32 *Bufo, memstream_t *mem) -{ - uint32 buf; - if(memstream_read(mem, &buf, 4)<4) - return 0; -#ifdef MSB_FIRST - *(uint32*)Bufo=((buf&0xFF)<<24)|((buf&0xFF00)<<8)|((buf&0xFF0000)>>8)|((buf&0xFF000000)>>24); -#else - *(uint32*)Bufo=buf; -#endif - return 1; +void FCEU_en32lsb(uint8 *buf, uint32 morp) { + buf[0] = morp; + buf[1] = morp >> 8; + buf[2] = morp >> 16; + buf[3] = morp >> 24; } -int read16le(char *d, FILE *fp) -{ -#ifdef MSB_FIRST - int ret; - ret = fread(d + 1, 1, 1, fp); - ret += fread(d, 1, 1, fp); - return ret < 2 ? 0 : 2; -#else - return((fread(d, 1, 2, fp) < 2) ? 0 : 2); -#endif +uint32 FCEU_de32lsb(uint8 *morp) { + return(morp[0] | (morp[1] << 8) | (morp[2] << 16) | (morp[3] << 24)); } -void FCEU_en32lsb(uint8 *buf, uint32 morp) -{ - buf[0] = morp; - buf[1] = morp >> 8; - buf[2] = morp >> 16; - buf[3] = morp >> 24; -} - -uint32 FCEU_de32lsb(uint8 *morp) -{ - return(morp[0] | (morp[1] << 8) | (morp[2] << 16) | (morp[3] << 24)); -} diff --git a/src/fceu-endian.h b/src/fceu-endian.h index 7ed551a..00d2a3d 100644 --- a/src/fceu-endian.h +++ b/src/fceu-endian.h @@ -2,10 +2,6 @@ #define _FCEU_ENDIAN_H #include "fceu-memory.h" -#include - -int write32le_mem(uint32 b, memstream_t *mem); -int read32le_mem(uint32 *Bufo, memstream_t *mem); int write16le(uint16 b, FILE *fp); int write32le(uint32 b, FILE *fp); diff --git a/src/fceu-memory.c b/src/fceu-memory.c index 0c97a5d..e48972a 100644 --- a/src/fceu-memory.c +++ b/src/fceu-memory.c @@ -25,39 +25,64 @@ #include "fceu-memory.h" #include "general.h" -void *FCEU_gmalloc(uint32 size) -{ - void *ret; - ret = malloc(size); - if (!ret) - { - FCEU_PrintError("Error allocating memory! Doing a hard exit."); - exit(1); - } - return ret; +void *FCEU_gmalloc(uint32 size) { + void *ret; + ret = malloc(size); + if (!ret) { + FCEU_PrintError("Error allocating memory! Doing a hard exit."); + exit(1); + } + return ret; } -void *FCEU_malloc(uint32 size) -{ - int retval = 0; - void *ret; - ret = (void*)malloc(size); - - if (!ret) - { - FCEU_PrintError("Error allocating memory!"); - ret = 0; - } - - return ret; +void *FCEU_malloc(uint32 size) { + void *ret; + ret = malloc(size); + if (!ret) { + FCEU_PrintError("Error allocating memory!"); + return(0); + } + return ret; } -void FCEU_free(void *ptr) -{ +void FCEU_free(void *ptr) { // Might do something with this and FCEU_malloc later... free(ptr); } -void FCEU_gfree(void *ptr) -{ +void FCEU_gfree(void *ptr) { free(ptr); } + +void FASTAPASS(3) FCEU_memmove(void *d, void *s, uint32 l) { + uint32 x; + int t; + + /* Type really doesn't matter. */ + t = (int)d; + t |= (int)s; + t |= (int)l; + + if (t & 3) { // Not 4-byte aligned and/or length is not a multiple of 4. + uint8 *tmpd, *tmps; + + tmpd = (uint8*)d; + tmps = (uint8*)s; + + for (x = l; x; x--) { // This could be optimized further, though(more tests could be performed). + *tmpd = *tmps; + tmpd++; + tmps++; + } + } else { + uint32 *tmpd, *tmps; + + tmpd = (uint32*)d; + tmps = (uint32*)s; + + for (x = l >> 2; x; x--) { + *tmpd = *tmps; + tmpd++; + tmps++; + } + } +} diff --git a/src/fceu-memory.h b/src/fceu-memory.h index 48158f8..b0808e3 100644 --- a/src/fceu-memory.h +++ b/src/fceu-memory.h @@ -26,10 +26,12 @@ #define _FCEU_MEMORY_H_ #include "fceu-types.h" -#include #define FCEU_dwmemset(d, c, n) { int _x; for (_x = n - 4; _x >= 0; _x -= 4) *(uint32*)& (d)[_x] = c; } +#if defined(STATE_LIBRETRO) || defined(ENDIAN_LIBRETRO) || defined(GENERAL_LIBRETRO) +#include "drivers/libretro/memstream.h" + #define HAVE_MEMSTREAM #define MEM_TYPE memstream_t @@ -40,6 +42,9 @@ #define ftell(a) memstream_pos((a)) #define fread(ptr, size, nmemb, stream) memstream_read((stream), (ptr), (nmemb)) #define fseek(stream, offset, whence) memstream_seek((stream), (offset), (whence)) +#else +#define MEM_TYPE FILE +#endif void *FCEU_malloc(uint32 size); void *FCEU_gmalloc(uint32 size); diff --git a/src/fceu.c b/src/fceu.c index ffabf10..1b26ee9 100644 --- a/src/fceu.c +++ b/src/fceu.c @@ -41,6 +41,7 @@ #include "cheat.h" #include "palette.h" #include "state.h" +#include "movie.h" #include "video.h" #include "input.h" #include "file.h" @@ -61,17 +62,14 @@ static readfunc *AReadG; static writefunc *BWriteG; static int RWWrap = 0; -static DECLFW(BNull) -{ +static DECLFW(BNull) { } -static DECLFR(ANull) -{ +static DECLFR(ANull) { return(X.DB); } -int AllocGenieRW(void) -{ +int AllocGenieRW(void) { if (!(AReadG = (readfunc*)FCEU_malloc(0x8000 * sizeof(readfunc)))) return 0; if (!(BWriteG = (writefunc*)FCEU_malloc(0x8000 * sizeof(writefunc)))) @@ -80,71 +78,62 @@ int AllocGenieRW(void) return 1; } -void FlushGenieRW(void) -{ - int32 x; +void FlushGenieRW(void) { + int32 x; - if (RWWrap) - { - for (x = 0; x < 0x8000; x++) - { - ARead[x + 0x8000] = AReadG[x]; - BWrite[x + 0x8000] = BWriteG[x]; - } - free(AReadG); - free(BWriteG); - AReadG = 0; - BWriteG = 0; - } - RWWrap = 0; + if (RWWrap) { + for (x = 0; x < 0x8000; x++) { + ARead[x + 0x8000] = AReadG[x]; + BWrite[x + 0x8000] = BWriteG[x]; + } + free(AReadG); + free(BWriteG); + AReadG = 0; + BWriteG = 0; + RWWrap = 0; + } } -readfunc FASTAPASS(1) GetReadHandler(int32 a) -{ +readfunc FASTAPASS(1) GetReadHandler(int32 a) { if (a >= 0x8000 && RWWrap) return AReadG[a - 0x8000]; else return ARead[a]; } -void FASTAPASS(3) SetReadHandler(int32 start, int32 end, readfunc func) -{ +void FASTAPASS(3) SetReadHandler(int32 start, int32 end, readfunc func) { int32 x; if (!func) func = ANull; if (RWWrap) - for (x = end; x >= start; x--) - { - if (x >= 0x8000) - AReadG[x - 0x8000] = func; - else - ARead[x] = func; - } + for (x = end; x >= start; x--) { + if (x >= 0x8000) + AReadG[x - 0x8000] = func; + else + ARead[x] = func; + } else for (x = end; x >= start; x--) ARead[x] = func; } -writefunc FASTAPASS(1) GetWriteHandler(int32 a) -{ +writefunc FASTAPASS(1) GetWriteHandler(int32 a) { if (RWWrap && a >= 0x8000) return BWriteG[a - 0x8000]; else return BWrite[a]; } -void FASTAPASS(3) SetWriteHandler(int32 start, int32 end, writefunc func) -{ +void FASTAPASS(3) SetWriteHandler(int32 start, int32 end, writefunc func) { int32 x; if (!func) func = BNull; if (RWWrap) - for (x = end; x >= start; x--) - { + for (x = end; x >= start; x--) { if (x >= 0x8000) BWriteG[x - 0x8000] = func; else @@ -163,58 +152,50 @@ uint8 RAM[0x800]; uint8 PAL = 0; -static DECLFW(BRAML) -{ +static DECLFW(BRAML) { RAM[A] = V; } -static DECLFR(ARAML) -{ +static DECLFR(ARAML) { return RAM[A]; } #ifndef COPYFAMI -static DECLFW(BRAMH) -{ +static DECLFW(BRAMH) { RAM[A & 0x7FF] = V; } -static DECLFR(ARAMH) -{ +static DECLFR(ARAMH) { return RAM[A & 0x7FF]; } #endif -void FCEUI_CloseGame(void) -{ - if (!GameInfo) - return; - - if (GameInfo->name) - free(GameInfo->name); - GameInfo->name = 0; - if (GameInfo->type != GIT_NSF) - FCEU_FlushGameCheats(0, 0); - GameInterface(GI_CLOSE); - ResetExState(0, 0); - FCEU_CloseGenie(); - free(GameInfo); - GameInfo = 0; +static void CloseGame(void) { + if (GameInfo) { + if (FCEUnetplay) + FCEUD_NetworkClose(); + if (GameInfo->name) { + free(GameInfo->name); + GameInfo->name = 0; + } + if (GameInfo->type != GIT_NSF) + FCEU_FlushGameCheats(0, 0); + GameInterface(GI_CLOSE); + ResetExState(0, 0); + FCEU_CloseGenie(); + free(GameInfo); + GameInfo = 0; + } } -void ResetGameLoaded(void) -{ - if (GameInfo) - FCEUI_CloseGame(); - +void ResetGameLoaded(void) { + if (GameInfo) CloseGame(); GameStateRestore = NULL; PPU_hook = NULL; GameHBIRQHook = NULL; - if (GameExpSound.Kill) GameExpSound.Kill(); memset(&GameExpSound, 0, sizeof(GameExpSound)); - MapIRQHook = NULL; MMC5Hack = 0; PEC586Hack = 0; @@ -227,77 +208,79 @@ int iNESLoad(const char *name, FCEUFILE *fp); int FDSLoad(const char *name, FCEUFILE *fp); int NSFLoad(FCEUFILE *fp); -FCEUGI *FCEUI_LoadGame(const char *name, uint8_t *databuf, size_t databufsize) -{ - FCEUFILE *fp; +FCEUGI *FCEUI_LoadGame(const char *name) { + FCEUFILE *fp; + char *ipsfn; - ResetGameLoaded(); + ResetGameLoaded(); - GameInfo = malloc(sizeof(FCEUGI)); - memset(GameInfo, 0, sizeof(FCEUGI)); + GameInfo = malloc(sizeof(FCEUGI)); + memset(GameInfo, 0, sizeof(FCEUGI)); - GameInfo->soundchan = 0; - GameInfo->soundrate = 0; - GameInfo->name = 0; - GameInfo->type = GIT_CART; - GameInfo->vidsys = GIV_USER; - GameInfo->input[0] = GameInfo->input[1] = -1; - GameInfo->inputfc = -1; - GameInfo->cspecial = 0; + GameInfo->soundchan = 0; + GameInfo->soundrate = 0; + GameInfo->name = 0; + GameInfo->type = GIT_CART; + GameInfo->vidsys = GIV_USER; + GameInfo->input[0] = GameInfo->input[1] = -1; + GameInfo->inputfc = -1; + GameInfo->cspecial = 0; - FCEU_printf("Loading %s...\n\n", name); + FCEU_printf("Loading %s...\n\n", name); - GetFileBase(name); + GetFileBase(name); - fp = FCEU_fopen(name, NULL, "rb", 0, databuf, databufsize); + ipsfn = FCEU_MakeFName(FCEUMKF_IPS, 0, 0); + fp = FCEU_fopen(name, ipsfn, "rb", 0); + free(ipsfn); - if (!fp) { - FCEU_PrintError("Error opening \"%s\"!", name); - return 0; - } + if (!fp) { + FCEU_PrintError("Error opening \"%s\"!", name); + return 0; + } - if (iNESLoad(name, fp)) - goto endlseq; - if (NSFLoad(fp)) - goto endlseq; - if (UNIFLoad(name, fp)) - goto endlseq; - if (FDSLoad(name, fp)) - goto endlseq; + if (iNESLoad(name, fp)) + goto endlseq; + if (NSFLoad(fp)) + goto endlseq; + if (UNIFLoad(name, fp)) + goto endlseq; + if (FDSLoad(name, fp)) + goto endlseq; - FCEU_PrintError("An error occurred while loading the file."); - FCEU_fclose(fp); - return 0; + FCEU_PrintError("An error occurred while loading the file."); + FCEU_fclose(fp); + return 0; -endlseq: - FCEU_fclose(fp); + endlseq: + FCEU_fclose(fp); - FCEU_ResetVidSys(); - if (GameInfo->type != GIT_NSF) - if (FSettings.GameGenie) - FCEU_OpenGenie(); + FCEU_ResetVidSys(); + if (GameInfo->type != GIT_NSF) + if (FSettings.GameGenie) + FCEU_OpenGenie(); - PowerNES(); - FCEUSS_CheckStates(); + PowerNES(); + FCEUSS_CheckStates(); + FCEUMOV_CheckMovies(); - if (GameInfo->type != GIT_NSF) { - FCEU_LoadGamePalette(); - FCEU_LoadGameCheats(0); - } + if (GameInfo->type != GIT_NSF) { + FCEU_LoadGamePalette(); + FCEU_LoadGameCheats(0); + } - FCEU_ResetPalette(); - FCEU_ResetMessages(); // Save state, status messages, etc. + FCEU_ResetPalette(); + FCEU_ResetMessages(); // Save state, status messages, etc. - return(GameInfo); + return(GameInfo); } int CopyFamiLoad(void); -FCEUGI *FCEUI_CopyFamiStart(void) -{ +FCEUGI *FCEUI_CopyFamiStart(void) { ResetGameLoaded(); - GameInfo = (FCEUGI*)malloc(sizeof(FCEUGI)); + GameInfo = malloc(sizeof(FCEUGI)); memset(GameInfo, 0, sizeof(FCEUGI)); GameInfo->soundchan = 0; @@ -323,6 +306,7 @@ FCEUGI *FCEUI_CopyFamiStart(void) PowerNES(); FCEUSS_CheckStates(); + FCEUMOV_CheckMovies(); if (GameInfo->type != GIT_NSF) { FCEU_LoadGamePalette(); @@ -372,19 +356,20 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski *SoundBufSize = ssize; } +void FCEUI_CloseGame(void) { + CloseGame(); +} -void ResetNES(void) -{ - if (!GameInfo) - return; +void ResetNES(void) { + FCEUMOV_AddCommand(FCEUNPCMD_RESET); + if (!GameInfo) return; GameInterface(GI_RESETM2); FCEUSND_Reset(); FCEUPPU_Reset(); X6502_Reset(); } -void FCEU_MemoryRand(uint8 *ptr, uint32 size) -{ +void FCEU_MemoryRand(uint8 *ptr, uint32 size) { int x = 0; while (size) { // *ptr = (x & 4) ? 0xFF : 0x00; // Huang Di DEBUG MODE enabled by default @@ -401,14 +386,12 @@ void FCEU_MemoryRand(uint8 *ptr, uint32 size) } } -void hand(X6502 *X, int type, uint32 A) -{ +void hand(X6502 *X, int type, uint32 A) { } -void PowerNES(void) -{ - if (!GameInfo) - return; +void PowerNES(void) { + FCEUMOV_AddCommand(FCEUNPCMD_POWER); + if (!GameInfo) return; FCEU_CheatResetRAM(); FCEU_CheatAddRAM(2, 0, RAM); @@ -443,13 +426,13 @@ void PowerNES(void) if (GameInfo->type == GIT_VSUNI) FCEU_VSUniPower(); + timestampbase = 0; X6502_Power(); FCEU_PowerCheats(); } -void FCEU_ResetVidSys(void) -{ +void FCEU_ResetVidSys(void) { int w; if (GameInfo->vidsys == GIV_NTSC) @@ -467,8 +450,8 @@ void FCEU_ResetVidSys(void) FCEUS FSettings; -void FCEU_printf(char *format, ...) -{ +void FCEU_printf(char *format, ...) { + FILE *ofile; char temp[2048]; va_list ap; @@ -477,11 +460,14 @@ void FCEU_printf(char *format, ...) vsprintf(temp, format, ap); FCEUD_Message(temp); + ofile = fopen("stdout.txt", "ab"); + fwrite(temp, 1, strlen(temp), ofile); + fclose(ofile); + va_end(ap); } -void FCEU_PrintError(char *format, ...) -{ +void FCEU_PrintError(char *format, ...) { char temp[2048]; va_list ap; @@ -493,37 +479,29 @@ void FCEU_PrintError(char *format, ...) va_end(ap); } -void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall) -{ +void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall) { FSettings.UsrFirstSLine[0] = ntscf; FSettings.UsrLastSLine[0] = ntscl; FSettings.UsrFirstSLine[1] = palf; FSettings.UsrLastSLine[1] = pall; - if (PAL) - { + if (PAL) { FSettings.FirstSLine = FSettings.UsrFirstSLine[1]; FSettings.LastSLine = FSettings.UsrLastSLine[1]; - } - else - { + } else { FSettings.FirstSLine = FSettings.UsrFirstSLine[0]; FSettings.LastSLine = FSettings.UsrLastSLine[0]; } } -void FCEUI_SetVidSystem(int a) -{ +void FCEUI_SetVidSystem(int a) { FSettings.PAL = a ? 1 : 0; - - if (!GameInfo) - return; - - FCEU_ResetVidSys(); - FCEU_ResetPalette(); + if (GameInfo) { + FCEU_ResetVidSys(); + FCEU_ResetPalette(); + } } -int FCEUI_GetCurrentVidSystem(int *slstart, int *slend) -{ +int FCEUI_GetCurrentVidSystem(int *slstart, int *slend) { if (slstart) *slstart = FSettings.FirstSLine; if (slend) @@ -531,18 +509,15 @@ int FCEUI_GetCurrentVidSystem(int *slstart, int *slend) return(PAL); } -void FCEUI_SetGameGenie(int a) -{ +void FCEUI_SetGameGenie(int a) { FSettings.GameGenie = a ? 1 : 0; } -void FCEUI_SetSnapName(int a) -{ +void FCEUI_SetSnapName(int a) { FSettings.SnapName = a; } -int32 FCEUI_GetDesiredFPS(void) -{ +int32 FCEUI_GetDesiredFPS(void) { if (PAL) return(838977920); // ~50.007 else diff --git a/src/fds.c b/src/fds.c index 97a1654..7c054df 100644 --- a/src/fds.c +++ b/src/fds.c @@ -614,7 +614,7 @@ int FDSLoad(const char *name, FCEUFILE *fp) { char *fn = FCEU_MakeFName(FCEUMKF_FDSROM, 0, 0); - if (!(zp = fopen(fn, "rb"))) { + if (!(zp = FCEUD_UTF8fopen(fn, "rb"))) { FCEU_PrintError("FDS BIOS ROM image missing!"); free(fn); return 0; @@ -669,7 +669,7 @@ int FDSLoad(const char *name, FCEUFILE *fp) { memcpy(diskdatao[x], diskdata[x], 65500); } - if ((tp = FCEU_fopen(fn, 0, "rb", 0, NULL, 0))) { + if ((tp = FCEU_fopen(fn, 0, "rb", 0))) { FCEU_printf("Disk was written. Auxillary FDS file open \"%s\".\n", fn); FreeFDSMemory(); if (!SubLoad(tp)) { @@ -737,7 +737,7 @@ void FDSClose(void) { if (!DiskWritten) return; - if (!(fp = fopen(fn, "wb"))) { + if (!(fp = FCEUD_UTF8fopen(fn, "wb"))) { free(fn); return; } diff --git a/src/file.c b/src/file.c index 5c8cf05..784dd49 100644 --- a/src/file.c +++ b/src/file.c @@ -27,6 +27,9 @@ #include #endif +#include "zlib.h" +#include "unzip.h" + #include "fceu-types.h" #include "file.h" #include "fceu-endian.h" @@ -34,152 +37,451 @@ #include "driver.h" #include "general.h" +typedef struct { + uint8 *data; + uint32 size; + uint32 location; +} MEMWRAP; + +void ApplyIPS(FILE *ips, MEMWRAP *dest) { + uint8 header[5]; + uint32 count = 0; + + FCEU_printf(" Applying IPS...\n"); + if (fread(header, 1, 5, ips) != 5) { + fclose(ips); + return; + } + if (memcmp(header, "PATCH", 5)) { + fclose(ips); + return; + } + + while (fread(header, 1, 3, ips) == 3) { + uint32 offset = (header[0] << 16) | (header[1] << 8) | header[2]; + uint16 size; + + if (!memcmp(header, "EOF", 3)) { + FCEU_printf(" IPS EOF: Did %d patches\n\n", count); + fclose(ips); + return; + } + + size = fgetc(ips) << 8; + size |= fgetc(ips); + if (!size) { /* RLE */ + uint8 *start; + uint8 b; + size = fgetc(ips) << 8; + size |= fgetc(ips); + + //FCEU_printf(" Offset: %8d Size: %5d RLE\n",offset,size); + + if ((offset + size) > dest->size) { + uint8 *tmp; + + // Probably a little slow. + tmp = (uint8*)realloc(dest->data, offset + size); + if (!tmp) { + FCEU_printf(" Oops. IPS patch %d(type RLE) goes beyond end of file. Could not allocate memory.\n", count); + fclose(ips); + return; + } + dest->size = offset + size; + dest->data = tmp; + memset(dest->data + dest->size, 0, offset + size - dest->size); + } + b = fgetc(ips); + start = dest->data + offset; + do { + *start = b; + start++; + } while (--size); + } else { /* Normal patch */ + //FCEU_printf(" Offset: %8d Size: %5d\n",offset,size); + if ((offset + size) > dest->size) { + uint8 *tmp; + + // Probably a little slow. + tmp = (uint8*)realloc(dest->data, offset + size); + if (!tmp) { + FCEU_printf(" Oops. IPS patch %d(type normal) goes beyond end of file. Could not allocate memory.\n", count); + fclose(ips); + return; + } + dest->data = tmp; + memset(dest->data + dest->size, 0, offset + size - dest->size); + } + fread(dest->data + offset, 1, size, ips); + } + count++; + } + fclose(ips); + FCEU_printf(" Hard IPS end!\n"); +} + +static MEMWRAP *MakeMemWrap(void *tz, int type) { + MEMWRAP *tmp; + + if (!(tmp = (MEMWRAP*)FCEU_malloc(sizeof(MEMWRAP)))) + goto doret; + tmp->location = 0; + + if (type == 0) { + fseek((FILE*)tz, 0, SEEK_END); + tmp->size = ftell((FILE*)tz); + fseek((FILE*)tz, 0, SEEK_SET); + if (!(tmp->data = (uint8*)FCEU_malloc(tmp->size))) { + free(tmp); + tmp = 0; + goto doret; + } + fread(tmp->data, 1, tmp->size, (FILE*)tz); + } + else if (type == 1) { + /* Bleck. The gzip file format has the size of the uncompressed data, + but I can't get to the info with the zlib interface(?). */ + for (tmp->size = 0; gzgetc(tz) != EOF; tmp->size++) ; + gzseek(tz, 0, SEEK_SET); + if (!(tmp->data = (uint8*)FCEU_malloc(tmp->size))) { + free(tmp); + tmp = 0; + goto doret; + } + gzread(tz, tmp->data, tmp->size); + } else if (type == 2) { + unz_file_info ufo; + unzGetCurrentFileInfo(tz, &ufo, 0, 0, 0, 0, 0, 0); + + tmp->size = ufo.uncompressed_size; + if (!(tmp->data = (uint8*)FCEU_malloc(ufo.uncompressed_size))) { + free(tmp); + tmp = 0; + goto doret; + } + unzReadCurrentFile(tz, tmp->data, ufo.uncompressed_size); + } + + doret: + if (type == 0) { + fclose((FILE*)tz); + } + else if (type == 1) { + gzclose(tz); + } else if (type == 2) { + unzCloseCurrentFile(tz); + unzClose(tz); + } + return tmp; +} + #ifndef __GNUC__ #define strcasecmp strcmp #endif -static MEMWRAP *MakeMemWrap(void *tz, int type) -{ - MEMWRAP *tmp; - if (!(tmp = (MEMWRAP*)FCEU_malloc(sizeof(MEMWRAP)))) - goto doret; - tmp->location = 0; +FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn, char *mode, char *ext) { + FILE *ipsfile = 0; + FCEUFILE *fceufp; + void *t; - fseek((FILE*)tz, 0, SEEK_END); - tmp->size = ftell((FILE*)tz); - fseek((FILE*)tz, 0, SEEK_SET); - if (!(tmp->data = (uint8*)FCEU_malloc(tmp->size))) - { - free(tmp); - tmp = 0; - goto doret; - } - fread(tmp->data, 1, tmp->size, (FILE*)tz); + if (strchr(mode, 'r')) + ipsfile = FCEUD_UTF8fopen(ipsfn, "rb"); -doret: - if (type == 0) - fclose((FILE*)tz); - return tmp; + fceufp = (FCEUFILE*)malloc(sizeof(FCEUFILE)); + + { + unzFile tz; + if ((tz = unzOpen(path))) { // If it's not a zip file, use regular file handlers. + // Assuming file type by extension usually works, + // but I don't like it. :) + if (unzGoToFirstFile(tz) == UNZ_OK) { + for (;; ) { + char tempu[512];// Longer filenames might be possible, but I don't + // think people would name files that long in zip files... + unzGetCurrentFileInfo(tz, 0, tempu, 512, 0, 0, 0, 0); + tempu[511] = 0; + if (strlen(tempu) >= 4) { + char *za = tempu + strlen(tempu) - 4; + + if (!ext) { + if (!strcasecmp(za, ".nes") || !strcasecmp(za, ".fds") || + !strcasecmp(za, ".nsf") || !strcasecmp(za, ".unf") || + !strcasecmp(za, ".nez")) + break; + } else if (!strcasecmp(za, ext)) + break; + } + if (strlen(tempu) >= 5) { + if (!strcasecmp(tempu + strlen(tempu) - 5, ".unif")) + break; + } + if (unzGoToNextFile(tz) != UNZ_OK) { + if (unzGoToFirstFile(tz) != UNZ_OK) goto zpfail; + break; + } + } + if (unzOpenCurrentFile(tz) != UNZ_OK) + goto zpfail; + } else { + zpfail: + free(fceufp); + unzClose(tz); + return 0; + } + if (!(fceufp->fp = MakeMemWrap(tz, 2))) { + free(fceufp); + return(0); + } + fceufp->type = 2; + if (ipsfile) + ApplyIPS(ipsfile, (MEMWRAP*)fceufp->fp); + return(fceufp); + } + } + + if ((t = FCEUD_UTF8fopen(path, "rb"))) { + uint32 magic; + + magic = fgetc((FILE*)t); + magic |= fgetc((FILE*)t) << 8; + magic |= fgetc((FILE*)t) << 16; + + if (magic != 0x088b1f) /* Not gzip... */ + fclose((FILE*)t); + else { /* Probably gzip */ + int fd; + + fd = dup(fileno((FILE*)t)); + + fclose(t); + + lseek(fd, 0, SEEK_SET); + + if ((t = gzdopen(fd, mode))) { + fceufp->type = 1; + fceufp->fp = t; + if (ipsfile) { + fceufp->fp = MakeMemWrap(t, 1); + gzclose(t); + + if (fceufp->fp) { + free(fceufp); + return(0); + } + + fceufp->type = 3; + ApplyIPS(ipsfile, (MEMWRAP*)fceufp->fp); + } + return(fceufp); + } + close(fd); + } + } + + if ((t = FCEUD_UTF8fopen(path, mode))) { + fseek((FILE*)t, 0, SEEK_SET); + fceufp->type = 0; + fceufp->fp = t; + if (ipsfile) { + if (!(fceufp->fp = MakeMemWrap(t, 0))) { + free(fceufp); + return(0); + } + fceufp->type = 3; + ApplyIPS(ipsfile, (MEMWRAP*)fceufp->fp); + } + return(fceufp); + } + + free(fceufp); + return 0; } -static MEMWRAP *MakeMemWrapBuffer(void *tz, int type, uint8 *buffer, size_t bufsize) -{ - MEMWRAP *tmp = (MEMWRAP*)FCEU_malloc(sizeof(MEMWRAP)); - - if (!tmp) - return NULL; - - tmp->location = 0; - tmp->size = bufsize; - tmp->data = buffer; - - return tmp; -} - -FCEUFILE * FCEU_fopen(const char *path, const char *ipsfn, - char *mode, char *ext, uint8 *buffer, size_t bufsize) -{ - FCEUFILE *fceufp = (FCEUFILE*)malloc(sizeof(FCEUFILE)); - void *t = fopen(path, mode); - - if (!t) - { - free(fceufp); - return 0; - } - - fseek((FILE*)t, 0, SEEK_SET); - fceufp->type = 0; - if (buffer) - fceufp->fp = MakeMemWrapBuffer(t, 0, buffer, bufsize); - else - fceufp->fp = MakeMemWrap(t, 0); - return fceufp; -} - -int FCEU_fclose(FCEUFILE *fp) -{ - if (fp->fp) - free(fp->fp); - fp->fp = NULL; +int FCEU_fclose(FCEUFILE *fp) { + if (fp->type == 1) { + gzclose(fp->fp); + } else if (fp->type >= 2) { + free(((MEMWRAP*)(fp->fp))->data); + ((MEMWRAP*)(fp->fp))->data = 0; + free(fp->fp); + fp->fp = 0; + } else + { + fclose((FILE*)fp->fp); + } free(fp); fp = 0; return 1; } -uint64 FCEU_fread(void *ptr, size_t element_size, size_t nmemb, FCEUFILE *fp) -{ - uint32_t total = nmemb * element_size; +uint64 FCEU_fread(void *ptr, size_t size, size_t nmemb, FCEUFILE *fp) { + if (fp->type == 1) { + return gzread(fp->fp, ptr, size * nmemb); + } else if (fp->type >= 2) { + MEMWRAP *wz; + uint32 total = size * nmemb; - if (fp->fp->location >= fp->fp->size) - return 0; + wz = (MEMWRAP*)fp->fp; + if (wz->location >= wz->size) return 0; - if((fp->fp->location + total) > fp->fp->size) - { - int64_t ak = fp->fp->size - fp->fp->location; - - memcpy((uint8_t*)ptr, fp->fp->data + fp->fp->location, ak); - - fp->fp->location = fp->fp->size; - - return (ak / element_size); - } - - memcpy((uint8_t*)ptr, fp->fp->data + fp->fp->location, total); - - fp->fp->location += total; - - return nmemb; + if ((wz->location + total) > wz->size) { + int ak = wz->size - wz->location; + memcpy((uint8*)ptr, wz->data + wz->location, ak); + wz->location = wz->size; + return(ak / size); + } else { + memcpy((uint8*)ptr, wz->data + wz->location, total); + wz->location += total; + return nmemb; + } + } else + { + return fread(ptr, size, nmemb, (FILE*)fp->fp); + } } -int FCEU_fseek(FCEUFILE *fp, long offset, int whence) -{ - switch (whence) - { - case SEEK_SET: - if (offset >= fp->fp->size) - return -1; +uint64 FCEU_fwrite(void *ptr, size_t size, size_t nmemb, FCEUFILE *fp) { + if (fp->type == 1) { + return gzwrite(fp->fp, ptr, size * nmemb); + } else if (fp->type >= 2) { + return 0; + } else + return fwrite(ptr, size, nmemb, (FILE*)fp->fp); +} - fp->fp->location = offset; - break; - case SEEK_CUR: - if ((offset + fp->fp->location) > fp->fp->size) - return -1; +int FCEU_fseek(FCEUFILE *fp, long offset, int whence) { + if (fp->type == 1) { + return((gzseek(fp->fp, offset, whence) > 0) ? 0 : -1); + } else if (fp->type >= 2) { + MEMWRAP *wz; + wz = (MEMWRAP*)fp->fp; - fp->fp->location += offset; - break; - } + switch (whence) { + case SEEK_SET: if (offset >= wz->size) + return(-1); + wz->location = offset; break; + case SEEK_CUR: if (offset + wz->location > wz->size) + return(-1); + wz->location += offset; + break; + } + return 0; + } else + return fseek((FILE*)fp->fp, offset, whence); +} - return 0; +uint64 FCEU_ftell(FCEUFILE *fp) { + if (fp->type == 1) { + return gztell(fp->fp); + } else if (fp->type >= 2) { + return(((MEMWRAP*)(fp->fp))->location); + } else + return ftell((FILE*)fp->fp); +} + +void FCEU_rewind(FCEUFILE *fp) { + if (fp->type == 1) { + gzrewind(fp->fp); + } else if (fp->type >= 2) { + ((MEMWRAP*)(fp->fp))->location = 0; + } else + /* Rewind */ + fseek(fp->fp, 0, SEEK_SET); +} + +int FCEU_read16le(uint16 *val, FCEUFILE *fp) { + uint8 t[2]; + + if (fp->type >= 1) { + if (fp->type >= 2) { + MEMWRAP *wz; + wz = (MEMWRAP*)fp->fp; + if (wz->location + 2 > wz->size) { + return 0; + } + *(uint32*)t = *(uint32*)(wz->data + wz->location); + wz->location += 2; + } else if (fp->type == 1) + if (gzread(fp->fp, &t, 2) != 2) return(0); + return(1); + } else + { + if (fread(t, 1, 2, (FILE*)fp->fp) != 2) return(0); + } + *val = t[0] | (t[1] << 8); + return(1); } int FCEU_read32le(uint32 *Bufo, FCEUFILE *fp) { - if ((fp->fp->location + 4) > fp->fp->size) - return 0; - - *Bufo = FCEU_de32lsb(fp->fp->data + fp->fp->location); - - fp->fp->location += 4; - - return 1; + if (fp->type >= 1) { + uint8 t[4]; + #ifdef MSB_FIRST + uint8 x[4]; + #endif + if (fp->type >= 2) { + MEMWRAP *wz; + wz = (MEMWRAP*)fp->fp; + if (wz->location + 4 > wz->size) { + return 0; + } + *(uint32*)t = *(uint32*)(wz->data + wz->location); + wz->location += 4; + } else if (fp->type == 1) + gzread(fp->fp, &t, 4); + #ifdef MSB_FIRST + x[0] = t[3]; + x[1] = t[2]; + x[2] = t[1]; + x[3] = t[0]; + *(uint32*)Bufo = *(uint32*)x; + #else + *(uint32*)Bufo = *(uint32*)t; + #endif + return 1; + } else + { + return read32le(Bufo, (FILE*)fp->fp); + } } -int FCEU_fgetc(FCEUFILE *fp) -{ - if (fp->fp->location < fp->fp->size) - return fp->fp->data[fp->fp->location++]; - - return EOF; +int FCEU_fgetc(FCEUFILE *fp) { + if (fp->type == 1) + return gzgetc(fp->fp); + else if (fp->type >= 2) { + MEMWRAP *wz; + wz = (MEMWRAP*)fp->fp; + if (wz->location < wz->size) + return wz->data[wz->location++]; + return EOF; + } else + return fgetc((FILE*)fp->fp); } -uint64 FCEU_ftell(FCEUFILE *fp) -{ - return fp->fp->location; +uint64 FCEU_fgetsize(FCEUFILE *fp) { + if (fp->type == 1) { + int x, t; + t = gztell(fp->fp); + gzrewind(fp->fp); + for (x = 0; gzgetc(fp->fp) != EOF; x++) ; + gzseek(fp->fp, t, SEEK_SET); + return(x); + } else if (fp->type >= 2) + return ((MEMWRAP*)(fp->fp))->size; + else + { + long t, r; + t = ftell((FILE*)fp->fp); + fseek((FILE*)fp->fp, 0, SEEK_END); + r = ftell((FILE*)fp->fp); + fseek((FILE*)fp->fp, t, SEEK_SET); + return r; + } } -uint64 FCEU_fgetsize(FCEUFILE *fp) -{ - return fp->fp->size; +int FCEU_fisarchive(FCEUFILE *fp) { + if (fp->type == 2) + return 1; + return 0; } diff --git a/src/general.c b/src/general.c index 0cc96dd..aa115b3 100644 --- a/src/general.c +++ b/src/general.c @@ -36,6 +36,7 @@ #include "general.h" #include "state.h" +#include "movie.h" #include "driver.h" @@ -47,24 +48,22 @@ static char FileExt[2048]; /* Includes the . character, as in ".nes" */ static char FileBaseDirectory[2048]; -void FCEUI_SetBaseDirectory(char *dir) -{ +void FCEUI_SetBaseDirectory(char *dir) { strncpy(BaseDirectory, dir, 2047); BaseDirectory[2047] = 0; } static char *odirs[FCEUIOD__COUNT] = { 0, 0, 0, 0, 0, 0 }; // odirs, odors. ^_^ -void FCEUI_SetDirOverride(int which, char *n) -{ +void FCEUI_SetDirOverride(int which, char *n) { odirs[which] = n; - /* Rebuild cache of present states/movies. */ - if (GameInfo) - { - if (which == FCEUIOD_STATE) - FCEUSS_CheckStates(); - } + if (GameInfo) { /* Rebuild cache of present states/movies. */ + if (which == FCEUIOD_STATE) + FCEUSS_CheckStates(); + else if (which == FCEUIOD_MOVIE) + FCEUMOV_CheckMovies(); + } } #ifndef HAVE_ASPRINTF @@ -81,82 +80,136 @@ static int asprintf(char **strp, const char *fmt, ...) { } #endif -char *FCEU_MakeFName(int type, int id1, char *cd1) -{ - char *ret = 0; - struct stat tmpstat; +char *FCEU_MakeFName(int type, int id1, char *cd1) { + char *ret = 0; + struct stat tmpstat; - switch (type) - { - case FCEUMKF_GGROM: - asprintf(&ret, "%s"PSS "gg.rom", BaseDirectory); - break; - case FCEUMKF_FDSROM: - asprintf(&ret, "%s"PSS "disksys.rom", BaseDirectory); - break; - case FCEUMKF_PALETTE: - if (odirs[FCEUIOD_MISC]) - asprintf(&ret, "%s"PSS "%s.pal", odirs[FCEUIOD_MISC], FileBase); - else - asprintf(&ret, "%s"PSS "gameinfo"PSS "%s.pal", BaseDirectory, FileBase); - break; - default: - ret = malloc(1); - *ret = '\0'; - } - return(ret); + switch (type) { + case FCEUMKF_NPTEMP: asprintf(&ret, "%s"PSS "m590plqd94fo.tmp", BaseDirectory); break; + case FCEUMKF_MOVIE: + if (odirs[FCEUIOD_STATE]) + asprintf(&ret, "%s"PSS "%s.%d.fcm", odirs[FCEUIOD_STATE], FileBase, id1); + else + asprintf(&ret, "%s"PSS "fcs"PSS "%s.%d.fcm", BaseDirectory, FileBase, id1); + if (stat(ret, &tmpstat) == -1) { + if (odirs[FCEUIOD_STATE]) + asprintf(&ret, "%s"PSS "%s.%s.%d.fcm", odirs[FCEUIOD_STATE], FileBase, md5_asciistr(GameInfo->MD5), id1); + else + asprintf(&ret, "%s"PSS "fcs"PSS "%s.%s.%d.fcm", BaseDirectory, FileBase, md5_asciistr(GameInfo->MD5), id1); + } + break; + case FCEUMKF_STATE: + if (odirs[FCEUIOD_STATE]) + asprintf(&ret, "%s"PSS "%s.fc%d", odirs[FCEUIOD_STATE], FileBase, id1); + else + asprintf(&ret, "%s"PSS "fcs"PSS "%s.fc%d", BaseDirectory, FileBase, id1); + if (stat(ret, &tmpstat) == -1) { +// if(odirs[FCEUIOD_STATE]) +// asprintf(&ret,"%s"PSS"%s.%s.fc%d",odirs[FCEUIOD_STATE],FileBase,md5_asciistr(GameInfo->MD5),id1); +// else +// asprintf(&ret,"%s"PSS"fcs"PSS"%s.%s.fc%d",BaseDirectory,FileBase,md5_asciistr(GameInfo->MD5),id1); + if (odirs[FCEUIOD_STATE]) + asprintf(&ret, "%s"PSS "%s.fc%d", odirs[FCEUIOD_STATE], FileBase, id1); + else + asprintf(&ret, "%s"PSS "fcs"PSS "%s.fc%d", BaseDirectory, FileBase, id1); + } + break; + case FCEUMKF_SNAP: + if (FSettings.SnapName) { + if (odirs[FCEUIOD_SNAPS]) + asprintf(&ret, "%s"PSS "%s-%d.%s", odirs[FCEUIOD_SNAPS], FileBase, id1, cd1); + else + asprintf(&ret, "%s"PSS "snaps"PSS "%s-%d.%s", BaseDirectory, FileBase, id1, cd1); + } else { + if (odirs[FCEUIOD_SNAPS]) + asprintf(&ret, "%s"PSS "%d.%s", odirs[FCEUIOD_SNAPS], id1, cd1); + else + asprintf(&ret, "%s"PSS "snaps"PSS "%d.%s", BaseDirectory, id1, cd1); + } + break; + case FCEUMKF_FDS: + if (odirs[FCEUIOD_NV]) + asprintf(&ret, "%s"PSS "%s.%s.fds", odirs[FCEUIOD_NV], FileBase, md5_asciistr(GameInfo->MD5)); + else + asprintf(&ret, "%s"PSS "sav"PSS "%s.%s.fds", BaseDirectory, FileBase, md5_asciistr(GameInfo->MD5)); + break; + case FCEUMKF_SAV: + if (odirs[FCEUIOD_NV]) + asprintf(&ret, "%s"PSS "%s.%s", odirs[FCEUIOD_NV], FileBase, cd1); + else + asprintf(&ret, "%s"PSS "sav"PSS "%s.%s", BaseDirectory, FileBase, cd1); + if (stat(ret, &tmpstat) == -1) { + if (odirs[FCEUIOD_NV]) + asprintf(&ret, "%s"PSS "%s.%s.%s", odirs[FCEUIOD_NV], FileBase, md5_asciistr(GameInfo->MD5), cd1); + else + asprintf(&ret, "%s"PSS "sav"PSS "%s.%s.%s", BaseDirectory, FileBase, md5_asciistr(GameInfo->MD5), cd1); + } + break; + case FCEUMKF_CHEAT: + if (odirs[FCEUIOD_CHEATS]) + asprintf(&ret, "%s"PSS "%s.cht", odirs[FCEUIOD_CHEATS], FileBase); + else + asprintf(&ret, "%s"PSS "cheats"PSS "%s.cht", BaseDirectory, FileBase); + break; + case FCEUMKF_IPS: asprintf(&ret, "%s"PSS "%s%s.ips", FileBaseDirectory, FileBase, FileExt); + break; + case FCEUMKF_GGROM: asprintf(&ret, "%s"PSS "gg.rom", BaseDirectory); break; + case FCEUMKF_FDSROM: asprintf(&ret, "%s"PSS "disksys.rom", BaseDirectory); break; + case FCEUMKF_PALETTE: + if (odirs[FCEUIOD_MISC]) + asprintf(&ret, "%s"PSS "%s.pal", odirs[FCEUIOD_MISC], FileBase); + else + asprintf(&ret, "%s"PSS "gameinfo"PSS "%s.pal", BaseDirectory, FileBase); + break; + default: + ret = malloc(1); + *ret = '\0'; + } + return(ret); } -void GetFileBase(const char *f) -{ - const char *tp1, *tp3; +void GetFileBase(const char *f) { + const char *tp1, *tp3; -#if PSS_STYLE == 4 - tp1 = ((char*)strrchr(f, ':')); -#elif PSS_STYLE == 1 - tp1 = ((char*)strrchr(f, '/')); -#else - tp1 = ((char*)strrchr(f, '\\')); -#if PSS_STYLE != 3 - tp3 = ((char*)strrchr(f, '/')); - if (tp1 < tp3) tp1 = tp3; -#endif -#endif - if (!tp1) - { - tp1 = f; - strcpy(FileBaseDirectory, "."); - } - else - { - memcpy(FileBaseDirectory, f, tp1 - f); - FileBaseDirectory[tp1 - f] = 0; - tp1++; - } + #if PSS_STYLE == 4 + tp1 = ((char*)strrchr(f, ':')); + #elif PSS_STYLE == 1 + tp1 = ((char*)strrchr(f, '/')); + #else + tp1 = ((char*)strrchr(f, '\\')); + #if PSS_STYLE != 3 + tp3 = ((char*)strrchr(f, '/')); + if (tp1 < tp3) tp1 = tp3; + #endif + #endif + if (!tp1) { + tp1 = f; + strcpy(FileBaseDirectory, "."); + } else { + memcpy(FileBaseDirectory, f, tp1 - f); + FileBaseDirectory[tp1 - f] = 0; + tp1++; + } - if (((tp3 = strrchr(f, '.')) != NULL) && (tp3 > tp1)) - { - memcpy(FileBase, tp1, tp3 - tp1); - FileBase[tp3 - tp1] = 0; - strcpy(FileExt, tp3); - } - else - { - strcpy(FileBase, tp1); - FileExt[0] = 0; - } + if (((tp3 = strrchr(f, '.')) != NULL) && (tp3 > tp1)) { + memcpy(FileBase, tp1, tp3 - tp1); + FileBase[tp3 - tp1] = 0; + strcpy(FileExt, tp3); + } else { + strcpy(FileBase, tp1); + FileExt[0] = 0; + } } -uint32 uppow2(uint32 n) -{ - int x; +uint32 uppow2(uint32 n) { + int x; - for (x = 31; x >= 0; x--) - if (n & (1 << x)) - { - if ((1 << x) != n) - return(1 << (x + 1)); - break; - } - return n; + for (x = 31; x >= 0; x--) + if (n & (1 << x)) { + if ((1 << x) != n) + return(1 << (x + 1)); + break; + } + return n; } + diff --git a/src/ines.c b/src/ines.c index f78b9c1..8120a70 100644 --- a/src/ines.c +++ b/src/ines.c @@ -48,7 +48,7 @@ uint8 *VROM = NULL; uint8 *ExtraNTARAM = NULL; iNES_HEADER head; -CartInfo iNESCart; +static CartInfo iNESCart; uint8 Mirroring = 0; uint32 ROM_size = 0; diff --git a/src/input.c b/src/input.c index 918d41b..27c340a 100644 --- a/src/input.c +++ b/src/input.c @@ -25,6 +25,8 @@ #include "fceu.h" #include "netplay.h" +#include "movie.h" + #include "input.h" #include "vsuni.h" #include "fds.h" @@ -68,8 +70,127 @@ static INPUTCFC *FCExp = 0; void (*InputScanlineHook)(uint8 *bg, uint8 *spr, uint32 linets, int final); -static DECLFR(JPRead) -{ +/* +#define DI 01 +#define CLK 02 +#define CS 04 +#define OUT0 01 +#define D3 01 +#define D4 02 + +typedef struct { + uint8 state; + uint8 cmd; + uint8 addr; + uint8 iswritable; + uint16 acc; + uint16 data[128]; +} EEPROM; + +EEPROM serialROM[2]; +uint8 oldCLK, bankFlip, DIFlip, OUT0state; + +uint8 serialROMautomat(uint8 chip, uint16 data) { + uint8 resp = 1; + chip &= 1; + if (!(data & CS)) { + if (!(data & CLK)) { + uint8 state = serialROM[chip].state; + uint8 mask, i; + FCEU_printf("> state = %02x\n", serialROM[chip].state); + switch (serialROM[chip].cmd) { + case 0x00: + mask = ~(1 << (state & 7)); + if (state < 8) { + serialROM[chip].addr &= mask; + serialROM[chip].addr |= ((data & 1) << (state & 7)); + if (state == 7) + FCEU_printf("> addr = %02x\n", serialROM[chip].addr); + } else if (state < 15) { + serialROM[chip].acc &= mask; + serialROM[chip].acc |= ((data & 1) << (state & 7)); + } else { + serialROM[chip].acc &= mask; + serialROM[chip].acc |= ((data & 1) << (state & 7)); + serialROM[chip].cmd = serialROM[chip].acc; + FCEU_printf("> cmd = %02x\n", serialROM[chip].cmd); + } + break; + case 0x01: + if (state < 30) + resp = (serialROM[chip].data[serialROM[chip].addr] >> (state & 15)) & 1; + else { + resp = (serialROM[chip].data[serialROM[chip].addr] >> (state & 15)) & 1; + serialROM[chip].cmd = 0; + } + break; + case 0x06: + mask = ~(1 << (state & 15)); + if (state < 30) { + serialROM[chip].acc &= mask; + serialROM[chip].acc |= ((data & 1) << (state & 15)); + } else { + serialROM[chip].acc &= mask; + serialROM[chip].acc |= ((data & 1) << (state & 15)); + if (serialROM[chip].iswritable) + serialROM[chip].data[serialROM[chip].addr] = serialROM[chip].acc; + serialROM[chip].cmd = 0; + } + break; + case 0x0C: + for (i = 0; i < 128; i++) + serialROM[chip].data[i] = 0xFFFF; + serialROM[chip].cmd = 0; + resp = 1; + break; + case 0x0D: + serialROM[chip].cmd = 0; + resp = 1; + break; + case 0x09: + serialROM[chip].cmd = 0; + serialROM[chip].iswritable = 1; + break; + case 0x0B: + serialROM[chip].cmd = 0; + serialROM[chip].iswritable = 0; + break; + default: + serialROM[chip].cmd = 0; + serialROM[chip].state = 0; + break; + } + } else { + if (serialROM[chip].cmd == 0) { + if (serialROM[chip].state > 15) + serialROM[chip].state = 0; + } else + serialROM[chip].state++; + } + } else { + serialROM[chip].cmd = 0; + serialROM[chip].state = 0; + } + return resp; +} + +uint8 serialROMstate(uint8 linestate) { + uint8 answ = 0, newCLK = linestate & CLK; + if ((!oldCLK) && newCLK) { + DIFlip ^= 1; + if (linestate && OUT0) { + serialROMautomat(bankFlip, 04 + DIFlip); + bankFlip ^= 1; + serialROMautomat(bankFlip, 02 + DIFlip); + } + } + answ = DIFlip ^ 1; + answ |= (serialROMautomat(bankFlip, newCLK + DIFlip) << 1); + oldCLK = newCLK; + return answ << 3; +}*/ + +static DECLFR(JPRead) { uint8 ret = 0; if (JPorts[A & 1]->Read) @@ -81,11 +202,21 @@ static DECLFR(JPRead) ret |= X.DB & 0xC0; +// if(A==0x4017) +//{ +// ret |= serialROMstate(OUT0); +// serialROMstate(OUT0|CLK); +// FCEU_printf("> 4017 read %02x\n",ret); +// } + return(ret); } -static DECLFW(B4016) -{ +static DECLFW(B4016) { +// OUT0state = V; +// serialROMstate(OUT0state|CLK); +// FCEU_printf("> 4016 write %02x\n",V); + if (FCExp) if (FCExp->Write) FCExp->Write(V & 7); @@ -95,284 +226,208 @@ static DECLFW(B4016) if (JPorts[1]->Write) JPorts[1]->Write(V & 1); - if ((LastStrobe & 1) && (!(V & 1))) - { - if (JPorts[0]->Strobe) - JPorts[0]->Strobe(0); - if (JPorts[1]->Strobe) - JPorts[1]->Strobe(1); - if (FCExp) - if (FCExp->Strobe) - FCExp->Strobe(); - } + if ((LastStrobe & 1) && (!(V & 1))) { +// FCEUD_UpdateInput(); + if (JPorts[0]->Strobe) + JPorts[0]->Strobe(0); + if (JPorts[1]->Strobe) + JPorts[1]->Strobe(1); + if (FCExp) + if (FCExp->Strobe) + FCExp->Strobe(); + } LastStrobe = V & 0x1; } -void FCEU_DrawInput(uint8 *buf) -{ - int x; - for (x = 0; x < 2; x++) - if (JPorts[x]->Draw) - JPorts[x]->Draw(x, buf, JPAttrib[x]); - if (FCExp) - if (FCExp->Draw) - FCExp->Draw(buf, JPAttribFC); +void FCEU_DrawInput(uint8 *buf) { + int x; + for (x = 0; x < 2; x++) + if (JPorts[x]->Draw) + JPorts[x]->Draw(x, buf, JPAttrib[x]); + if (FCExp) + if (FCExp->Draw) + FCExp->Draw(buf, JPAttribFC); } -void FCEU_UpdateInput(void) -{ - int x; +void FCEU_UpdateInput(void) { + int x; - for (x = 0; x < 2; x++) - { - if (JPorts[x] && JPorts[x]->Update) - JPorts[x]->Update(x, InputDataPtr[x], JPAttrib[x]); - } + for (x = 0; x < 2; x++) { + if (JPorts[x]->Update) + JPorts[x]->Update(x, InputDataPtr[x], JPAttrib[x]); + } + if (FCExp) + if (FCExp->Update) + FCExp->Update(InputDataPtrFC, JPAttribFC); - if (FCExp && FCExp->Update) - FCExp->Update(InputDataPtrFC, JPAttribFC); - - if (GameInfo && GameInfo->type == GIT_VSUNI) - if (coinon) coinon--; + if (GameInfo->type == GIT_VSUNI) + if (coinon) coinon--; } -static DECLFR(VSUNIRead0) -{ - uint8 ret = 0; - - if (JPorts[0]->Read) - ret |= (JPorts[0]->Read(0)) & 1; - - ret |= (vsdip & 3) << 3; - if (coinon) - ret |= 0x4; - return ret; -} - -static DECLFR(VSUNIRead1) -{ +static DECLFR(VSUNIRead0) { uint8 ret = 0; - if (JPorts[1] && JPorts[1]->Read) + if (JPorts[0]->Read) + ret |= (JPorts[0]->Read(0)) & 1; + + ret |= (vsdip & 3) << 3; + if (coinon) + ret |= 0x4; + return ret; +} + +static DECLFR(VSUNIRead1) { + uint8 ret = 0; + + if (JPorts[1]->Read) ret |= (JPorts[1]->Read(1)) & 1; ret |= vsdip & 0xFC; return ret; } -static void SLHLHook(uint8 *bg, uint8 *spr, uint32 linets, int final) -{ - int x; - - for (x = 0; x < 2; x++) - if (JPorts[x] && JPorts[x]->SLHook) - JPorts[x]->SLHook(x, bg, spr, linets, final); - - if (FCExp && FCExp->SLHook) - FCExp->SLHook(bg, spr, linets, final); +static void SLHLHook(uint8 *bg, uint8 *spr, uint32 linets, int final) { + int x; + for (x = 0; x < 2; x++) + if (JPorts[x]->SLHook) + JPorts[x]->SLHook(x, bg, spr, linets, final); + if (FCExp) + if (FCExp->SLHook) + FCExp->SLHook(bg, spr, linets, final); } -static void CheckSLHook(void) -{ - InputScanlineHook = 0; - - if (JPorts[0] && JPorts[0]->SLHook || JPorts[1] && JPorts[1]->SLHook) - InputScanlineHook = SLHLHook; - - if (FCExp && FCExp->SLHook) - InputScanlineHook = SLHLHook; +static void CheckSLHook(void) { + InputScanlineHook = 0; + if (JPorts[0]->SLHook || JPorts[1]->SLHook) + InputScanlineHook = SLHLHook; + if (FCExp) + if (FCExp->SLHook) + InputScanlineHook = SLHLHook; } -static void FASTAPASS(1) SetInputStuff(int x) -{ - switch (JPType[x]) - { - case SI_NONE: - JPorts[x] = &DummyJPort; - break; - case SI_GAMEPAD: - JPorts[x] = FCEU_InitJoyPad(x); - break; - case SI_ARKANOID: - JPorts[x] = FCEU_InitArkanoid(x); - break; - case SI_MOUSE: - JPorts[x] = FCEU_InitMouse(x); - break; - case SI_ZAPPER: - JPorts[x] = FCEU_InitZapper(x); - break; - case SI_POWERPADA: - JPorts[x] = FCEU_InitPowerpadA(x); - break; - case SI_POWERPADB: - JPorts[x] = FCEU_InitPowerpadB(x); - break; - } +static void FASTAPASS(1) SetInputStuff(int x) { + switch (JPType[x]) { + case SI_NONE: JPorts[x] = &DummyJPort; break; + case SI_GAMEPAD: JPorts[x] = FCEU_InitJoyPad(x); break; + case SI_ARKANOID: JPorts[x] = FCEU_InitArkanoid(x); break; + case SI_MOUSE: JPorts[x] = FCEU_InitMouse(x); break; + case SI_ZAPPER: JPorts[x] = FCEU_InitZapper(x); break; + case SI_POWERPADA: JPorts[x] = FCEU_InitPowerpadA(x); break; + case SI_POWERPADB: JPorts[x] = FCEU_InitPowerpadB(x); break; + } CheckSLHook(); } -static void SetInputStuffFC(void) -{ - switch (JPTypeFC) - { - case SIFC_NONE: - FCExp = 0; - break; - case SIFC_ARKANOID: - FCExp = FCEU_InitArkanoidFC(); - break; - case SIFC_SHADOW: - FCExp = FCEU_InitSpaceShadow(); - break; - case SIFC_OEKAKIDS: - FCExp = FCEU_InitOekaKids(); - break; - case SIFC_4PLAYER: - FCExp = FCEU_InitFami4(); - break; - case SIFC_FKB: - FCExp = FCEU_InitFKB(); - break; - case SIFC_SUBORKB: - FCExp = FCEU_InitSuborKB(); - break; - case SIFC_PEC586KB: - FCExp = FCEU_InitPEC586KB(); - break; - case SIFC_HYPERSHOT: - FCExp = FCEU_InitHS(); - break; - case SIFC_MAHJONG: - FCExp = FCEU_InitMahjong(); - break; - case SIFC_QUIZKING: - FCExp = FCEU_InitQuizKing(); - break; - case SIFC_FTRAINERA: - FCExp = FCEU_InitFamilyTrainerA(); - break; - case SIFC_FTRAINERB: - FCExp = FCEU_InitFamilyTrainerB(); - break; - case SIFC_BWORLD: - FCExp = FCEU_InitBarcodeWorld(); - break; - case SIFC_TOPRIDER: - FCExp = FCEU_InitTopRider(); - break; - } +static void SetInputStuffFC(void) { + switch (JPTypeFC) { + case SIFC_NONE: FCExp = 0; break; + case SIFC_ARKANOID: FCExp = FCEU_InitArkanoidFC(); break; + case SIFC_SHADOW: FCExp = FCEU_InitSpaceShadow(); break; + case SIFC_OEKAKIDS: FCExp = FCEU_InitOekaKids(); break; + case SIFC_4PLAYER: FCExp = FCEU_InitFami4(); break; + case SIFC_FKB: FCExp = FCEU_InitFKB(); break; + case SIFC_SUBORKB: FCExp = FCEU_InitSuborKB(); break; + case SIFC_PEC586KB: FCExp = FCEU_InitPEC586KB(); break; + case SIFC_HYPERSHOT: FCExp = FCEU_InitHS(); break; + case SIFC_MAHJONG: FCExp = FCEU_InitMahjong(); break; + case SIFC_QUIZKING: FCExp = FCEU_InitQuizKing(); break; + case SIFC_FTRAINERA: FCExp = FCEU_InitFamilyTrainerA(); break; + case SIFC_FTRAINERB: FCExp = FCEU_InitFamilyTrainerB(); break; + case SIFC_BWORLD: FCExp = FCEU_InitBarcodeWorld(); break; + case SIFC_TOPRIDER: FCExp = FCEU_InitTopRider(); break; + } CheckSLHook(); } -void InitializeInput(void) -{ - LastStrobe = 0; +void InitializeInput(void) { + LastStrobe = 0; + if (GameInfo->type == GIT_VSUNI) { + SetReadHandler(0x4016, 0x4016, VSUNIRead0); + SetReadHandler(0x4017, 0x4017, VSUNIRead1); + } else + SetReadHandler(0x4016, 0x4017, JPRead); - if (GameInfo && GameInfo->type == GIT_VSUNI) - { - SetReadHandler(0x4016, 0x4016, VSUNIRead0); - SetReadHandler(0x4017, 0x4017, VSUNIRead1); - } - else - SetReadHandler(0x4016, 0x4017, JPRead); + SetWriteHandler(0x4016, 0x4016, B4016); - SetWriteHandler(0x4016, 0x4016, B4016); - - SetInputStuff(0); - SetInputStuff(1); - SetInputStuffFC(); + SetInputStuff(0); + SetInputStuff(1); + SetInputStuffFC(); } -void FCEUI_SetInput(int port, int type, void *ptr, int attrib) -{ - JPAttrib[port] = attrib; - JPType[port] = type; - InputDataPtr[port] = ptr; - SetInputStuff(port); +void FCEUI_SetInput(int port, int type, void *ptr, int attrib) { + JPAttrib[port] = attrib; + JPType[port] = type; + InputDataPtr[port] = ptr; + SetInputStuff(port); } -void FCEUI_SetInputFC(int type, void *ptr, int attrib) -{ +void FCEUI_SetInputFC(int type, void *ptr, int attrib) { JPAttribFC = attrib; JPTypeFC = type; InputDataPtrFC = ptr; SetInputStuffFC(); } -void FCEU_DoSimpleCommand(int cmd) -{ - switch (cmd) - { - case FCEUNPCMD_FDSINSERT: - FCEU_FDSInsert(-1); - break; - case FCEUNPCMD_FDSSELECT: - FCEU_FDSSelect(); - break; - case FCEUNPCMD_FDSEJECT: - FCEU_FDSEject(); - break; - case FCEUNPCMD_VSUNICOIN: - FCEU_VSUniCoin(); - break; - case FCEUNPCMD_VSUNIDIP0: - case (FCEUNPCMD_VSUNIDIP0 + 1): - case (FCEUNPCMD_VSUNIDIP0 + 2): - case (FCEUNPCMD_VSUNIDIP0 + 3): - case (FCEUNPCMD_VSUNIDIP0 + 4): - case (FCEUNPCMD_VSUNIDIP0 + 5): - case (FCEUNPCMD_VSUNIDIP0 + 6): - case (FCEUNPCMD_VSUNIDIP0 + 7): - FCEU_VSUniToggleDIP(cmd - FCEUNPCMD_VSUNIDIP0); - break; - case FCEUNPCMD_POWER: - PowerNES(); - break; - case FCEUNPCMD_RESET: - ResetNES(); - break; - } +void FCEU_DoSimpleCommand(int cmd) { + switch (cmd) { + case FCEUNPCMD_FDSINSERT: FCEU_FDSInsert(-1); break; + case FCEUNPCMD_FDSSELECT: FCEU_FDSSelect(); break; + case FCEUNPCMD_FDSEJECT: FCEU_FDSEject(); break; + case FCEUNPCMD_VSUNICOIN: FCEU_VSUniCoin(); break; + case FCEUNPCMD_VSUNIDIP0: + case (FCEUNPCMD_VSUNIDIP0 + 1): + case (FCEUNPCMD_VSUNIDIP0 + 2): + case (FCEUNPCMD_VSUNIDIP0 + 3): + case (FCEUNPCMD_VSUNIDIP0 + 4): + case (FCEUNPCMD_VSUNIDIP0 + 5): + case (FCEUNPCMD_VSUNIDIP0 + 6): + case (FCEUNPCMD_VSUNIDIP0 + 7): + FCEU_VSUniToggleDIP(cmd - FCEUNPCMD_VSUNIDIP0); break; + case FCEUNPCMD_POWER: PowerNES(); break; + case FCEUNPCMD_RESET: ResetNES(); break; + } } -void FCEU_QSimpleCommand(int cmd) -{ - FCEU_DoSimpleCommand(cmd); +void FCEU_QSimpleCommand(int cmd) { +#ifdef NETWORK + if (FCEUnetplay) + FCEUNET_SendCommand(cmd, 0); + else +#endif + { + if (!FCEUMOV_IsPlaying()) + FCEU_DoSimpleCommand(cmd); + else + FCEUMOV_AddCommand(cmd); + } } -void FCEUI_FDSSelect(void) -{ +void FCEUI_FDSSelect(void) { FCEU_QSimpleCommand(FCEUNPCMD_FDSSELECT); } -int FCEUI_FDSInsert(int oride) -{ +int FCEUI_FDSInsert(int oride) { FCEU_QSimpleCommand(FCEUNPCMD_FDSINSERT); return(1); } -int FCEUI_FDSEject(void) -{ +int FCEUI_FDSEject(void) { FCEU_QSimpleCommand(FCEUNPCMD_FDSEJECT); return(1); } -void FCEUI_VSUniToggleDIP(int w) -{ +void FCEUI_VSUniToggleDIP(int w) { FCEU_QSimpleCommand(FCEUNPCMD_VSUNIDIP0 + w); } -void FCEUI_VSUniCoin(void) -{ +void FCEUI_VSUniCoin(void) { FCEU_QSimpleCommand(FCEUNPCMD_VSUNICOIN); } -void FCEUI_ResetNES(void) -{ +void FCEUI_ResetNES(void) { FCEU_QSimpleCommand(FCEUNPCMD_RESET); } -void FCEUI_PowerNES(void) -{ +void FCEUI_PowerNES(void) { FCEU_QSimpleCommand(FCEUNPCMD_POWER); } diff --git a/src/state.c b/src/state.c index 5958970..7089353 100644 --- a/src/state.c +++ b/src/state.c @@ -18,6 +18,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +/* TODO: Add (better) file io error checking */ +/* TODO: Change save state file format. */ + #include #include #include @@ -45,12 +48,15 @@ static void (*SPreSave)(void); static void (*SPostSave)(void); static int SaveStateStatus[10]; +static int StateShow; + static SFORMAT SFMDATA[64]; static int SFEXINDEX; #define RLSB FCEUSTATE_RLSB //0x80000000 + extern SFORMAT FCEUPPU_STATEINFO[]; extern SFORMAT FCEUSND_STATEINFO[]; extern SFORMAT FCEUCTRL_STATEINFO[]; @@ -81,274 +87,281 @@ SFORMAT SFCPUC[] = { { 0 } }; -static int SubWrite(memstream_t *mem, SFORMAT *sf) -{ - uint32 acc=0; +static int SubWrite(MEM_TYPE *st, SFORMAT *sf) { + uint32 acc = 0; - while(sf->v) - { - if(sf->s==~0) /* Link to another struct. */ - { - uint32 tmp; + while (sf->v) { + if (sf->s == ~0) { // Link to another struct. + uint32 tmp; - if(!(tmp=SubWrite(mem, (SFORMAT *)sf->v))) - return(0); - acc+=tmp; - sf++; - continue; - } + if (!(tmp = SubWrite(st, (SFORMAT*)sf->v))) + return(0); + acc += tmp; + sf++; + continue; + } - acc+=8; /* Description + size */ - acc+=sf->s&(~RLSB); + acc += 8; // Description + size + acc += sf->s & (~RLSB); - if(mem) /* Are we writing or calculating the size of this block? */ - { - memstream_write(mem, sf->desc, 4); - write32le_mem(sf->s&(~RLSB), mem); + if (st) { // Are we writing or calculating the size of this block? */ + fwrite(sf->desc, 1, 4, st); + write32le(sf->s & (~RLSB), st); -#ifdef MSB_FIRST - if(sf->s&RLSB) - FlipByteOrder(sf->v,sf->s&(~RLSB)); -#endif + #ifdef MSB_FIRST + if (sf->s & RLSB) + FlipByteOrder(sf->v, sf->s & (~RLSB)); + #endif - memstream_write(mem, (uint8 *)sf->v, sf->s&(~RLSB)); - /* Now restore the original byte order. */ -#ifdef MSB_FIRST - if(sf->s&RLSB) - FlipByteOrder(sf->v,sf->s&(~RLSB)); -#endif - } - sf++; - } + fwrite((uint8*)sf->v, 1, sf->s & (~RLSB), st); + /* Now restore the original byte order. */ + #ifdef MSB_FIRST + if (sf->s & RLSB) + FlipByteOrder(sf->v, sf->s & (~RLSB)); + #endif + } + sf++; + } - return acc; + return(acc); } -static int WriteStateChunk(memstream_t *mem, int type, SFORMAT *sf) -{ - int bsize; +static int WriteStateChunk(MEM_TYPE *st, int type, SFORMAT *sf) { + int bsize; - memstream_putc(mem, type); + fputc(type, st); - bsize = SubWrite(0,sf); - write32le_mem(bsize, mem); + bsize = SubWrite(0, sf); + write32le(bsize, st); - if (!SubWrite(mem, sf)) - return 0; - return bsize + 5; + if (!SubWrite(st, sf)) return(0); + return(bsize + 5); } -static SFORMAT *CheckS(SFORMAT *sf, uint32 tsize, char *desc) -{ - while (sf->v) - { - if (sf->s == ~0) - { /* Link to another SFORMAT structure. */ - SFORMAT *tmp; - if ((tmp = CheckS((SFORMAT*)sf->v, tsize, desc))) - return(tmp); - sf++; - continue; - } - if (!strncmp(desc, sf->desc, 4)) - { - if (tsize != (sf->s & (~RLSB))) - return(0); - return(sf); - } - sf++; - } - return(0); +static SFORMAT *CheckS(SFORMAT *sf, uint32 tsize, char *desc) { + while (sf->v) { + if (sf->s == ~0) { /* Link to another SFORMAT structure. */ + SFORMAT *tmp; + if ((tmp = CheckS((SFORMAT*)sf->v, tsize, desc))) + return(tmp); + sf++; + continue; + } + if (!strncmp(desc, sf->desc, 4)) { + if (tsize != (sf->s & (~RLSB))) + return(0); + return(sf); + } + sf++; + } + return(0); } -static int ReadStateChunk(memstream_t *mem, SFORMAT *sf, int size) -{ - SFORMAT *tmp; - int temp; - temp=memstream_pos(mem); +static int ReadStateChunk(MEM_TYPE *st, SFORMAT *sf, int size) { + SFORMAT *tmp; + int temp; + temp = ftell(st); - while(memstream_pos(mem)v, tmp->s&(~RLSB)); + if ((tmp = CheckS(sf, tsize, toa))) { + fread((uint8*)tmp->v, 1, tmp->s & (~RLSB), st); -#ifdef MSB_FIRST - if(tmp->s&RLSB) - FlipByteOrder(tmp->v,tmp->s&(~RLSB)); -#endif - } - else - memstream_seek(mem,tsize,SEEK_CUR); - } - return 1; + #ifdef MSB_FIRST + if (tmp->s & RLSB) + FlipByteOrder(tmp->v, tmp->s & (~RLSB)); + #endif + } else + fseek(st, tsize, SEEK_CUR); + } // while(...) + return 1; } -static int ReadStateChunks(memstream_t *st, int32 totalsize) -{ - int t; - uint32 size; - int ret = 1; +static int ReadStateChunks(MEM_TYPE *st, int32 totalsize) { + int t; + uint32 size; + int ret = 1; - while (totalsize > 0) - { - t = memstream_getc(st); - if (t == EOF) - break; - if (!read32le_mem(&size,st)) - break; - totalsize -= size + 5; + while (totalsize > 0) { + t = fgetc(st); + if (t == EOF) break; + if (!read32le(&size, st)) break; + totalsize -= size + 5; - switch(t) - { - case 1: - if (!ReadStateChunk(st, SFCPU, size)) - ret = 0; - break; - case 2: - if (!ReadStateChunk(st, SFCPUC, size)) - ret = 0; - else - X.mooPI = X.P; // Quick and dirty hack. - break; - case 3: - if (!ReadStateChunk(st, FCEUPPU_STATEINFO, size)) - ret = 0; - break; - case 4: - if (!ReadStateChunk(st, FCEUCTRL_STATEINFO, size)) - ret = 0; - break; - case 5: - if (!ReadStateChunk(st, FCEUSND_STATEINFO, size)) - ret = 0; - break; - case 0x10: - if (!ReadStateChunk(st, SFMDATA, size)) - ret = 0; - break; - default: - if (memstream_seek(st, size, SEEK_CUR) < 0) - goto endo; - break; - } - } -endo: - return ret; + switch (t) { + case 1: if (!ReadStateChunk(st, SFCPU, size)) ret = 0; break; + case 2: + if (!ReadStateChunk(st, SFCPUC, size)) + ret = 0; + else { + X.mooPI = X.P; // Quick and dirty hack. + } + break; + case 3: if (!ReadStateChunk(st, FCEUPPU_STATEINFO, size)) ret = 0; break; + case 4: if (!ReadStateChunk(st, FCEUCTRL_STATEINFO, size)) ret = 0; break; + case 5: if (!ReadStateChunk(st, FCEUSND_STATEINFO, size)) ret = 0; break; + case 0x10: if (!ReadStateChunk(st, SFMDATA, size)) ret = 0; + break; + default: if (fseek(st, size, SEEK_CUR) < 0) goto endo; break; + } + } + endo: + return ret; } + int CurrentState = 0; extern int geniestage; -void FCEUSS_Save_Mem(void) -{ - memstream_t *mem = memstream_open(1); +int FCEUSS_SaveFP(MEM_TYPE *st) { + static uint32 totalsize; + uint8 header[16] = { 0 }; - uint32 totalsize; - uint8 header[16] = {0}; - - header[0] = 'F'; - header[1] = 'C'; - header[2] = 'S'; - header[3] = 0xFF; + header[0] = 'F'; + header[1] = 'C'; + header[2] = 'S'; + header[3] = 0xFF; - FCEU_en32lsb(header + 8, FCEU_VERSION_NUMERIC); - memstream_write(mem, header, 16); + header[3] = 0xFF; + FCEU_en32lsb(header + 8, FCEU_VERSION_NUMERIC); + fwrite(header, 1, 16, st); + FCEUPPU_SaveState(); + FCEUSND_SaveState(); + totalsize = WriteStateChunk(st, 1, SFCPU); + totalsize += WriteStateChunk(st, 2, SFCPUC); + totalsize += WriteStateChunk(st, 3, FCEUPPU_STATEINFO); + totalsize += WriteStateChunk(st, 4, FCEUCTRL_STATEINFO); + totalsize += WriteStateChunk(st, 5, FCEUSND_STATEINFO); + if (SPreSave) SPreSave(); + totalsize += WriteStateChunk(st, 0x10, SFMDATA); + if (SPreSave) SPostSave(); - FCEUPPU_SaveState(); - totalsize = WriteStateChunk(mem, 1, SFCPU); - totalsize += WriteStateChunk(mem, 2, SFCPUC); - totalsize += WriteStateChunk(mem, 3, FCEUPPU_STATEINFO); - totalsize += WriteStateChunk(mem, 4, FCEUCTRL_STATEINFO); - totalsize += WriteStateChunk(mem, 5, FCEUSND_STATEINFO); - - if (SPreSave) - SPreSave(); - - totalsize += WriteStateChunk(mem, 0x10, SFMDATA); - - if (SPreSave) - SPostSave(); - - memstream_seek(mem, 4, SEEK_SET); - write32le_mem(totalsize, mem); - - memstream_close(mem); + fseek(st, 4, SEEK_SET); + write32le(totalsize, st); + return(1); } -void FCEUSS_Load_Mem(void) -{ - memstream_t *mem = memstream_open(0); +void FCEUSS_Save(char *fname) { + MEM_TYPE *st = NULL; + char *fn; - uint8 header[16]; - int stateversion; - int x; - - memstream_read(mem, header, 16); + if (geniestage == 1) { + FCEU_DispMessage("Cannot save FCS in GG screen."); + return; + } - if (memcmp(header,"FCS",3) != 0) - return; + if (fname) + st = FCEUD_UTF8fopen(fname, "wb"); + else { + st = FCEUD_UTF8fopen(fn = FCEU_MakeFName(FCEUMKF_STATE, CurrentState, 0), "wb"); + free(fn); + } - if (header[3] == 0xFF) - stateversion = FCEU_de32lsb(header + 8); - else - stateversion = header[3] * 100; + if (st == NULL) { + FCEU_DispMessage("State %d save error.", CurrentState); + return; + } - x = ReadStateChunks(mem, *(uint32*)(header + 4)); + FCEUSS_SaveFP(st); - if (stateversion < 9500) - X.IRQlow=0; - - if (GameStateRestore) - GameStateRestore(stateversion); - - if (x) - { - FCEUPPU_LoadState(stateversion); - FCEUSND_LoadState(stateversion); - } - - memstream_close(mem); + SaveStateStatus[CurrentState] = 1; + fclose(st); + FCEU_DispMessage("State %d saved.", CurrentState); } -void FCEUSS_CheckStates(void) -{ - MEM_TYPE *st = NULL; - char *fn; - int ssel; +int FCEUSS_LoadFP(MEM_TYPE *st) { + int x; + uint8 header[16]; + int stateversion; - for (ssel = 0; ssel < 10; ssel++) - { - st = fopen(fn = FCEU_MakeFName(FCEUMKF_STATE, ssel, 0), "rb"); - free(fn); - if (st) - { - SaveStateStatus[ssel] = 1; - fclose(st); - } - else - SaveStateStatus[ssel] = 0; - } + fread(&header, 1, 16, st); + if (memcmp(header, "FCS", 3)) + return(0); - CurrentState = 0; + if (header[3] == 0xFF) + stateversion = FCEU_de32lsb(header + 8); + else + stateversion = header[3] * 100; + + x = ReadStateChunks(st, *(uint32*)(header + 4)); + if (stateversion < 9500) X.IRQlow = 0; + + if (GameStateRestore) GameStateRestore(stateversion); + if (x) { + FCEUPPU_LoadState(stateversion); + FCEUSND_LoadState(stateversion); + } + return(x); } -void ResetExState(void (*PreSave)(void), void (*PostSave)(void)) -{ +int FCEUSS_Load(char *fname) { + MEM_TYPE *st; + char *fn; + + if (geniestage == 1) { + FCEU_DispMessage("Cannot load FCS in GG screen."); + return(0); + } + + if (fname) + st = FCEUD_UTF8fopen(fname, "rb"); + else { + st = FCEUD_UTF8fopen(fn = FCEU_MakeFName(FCEUMKF_STATE, CurrentState, fname), "rb"); + free(fn); + } + + if (st == NULL) { + FCEU_DispMessage("State %d load error.", CurrentState); + SaveStateStatus[CurrentState] = 0; + return(0); + } + + if (FCEUSS_LoadFP(st)) { + SaveStateStatus[CurrentState] = 1; + FCEU_DispMessage("State %d loaded.", CurrentState); + SaveStateStatus[CurrentState] = 1; + fclose(st); + return(1); + } else { + SaveStateStatus[CurrentState] = 1; + FCEU_DispMessage("Error(s) reading state %d!", CurrentState); + fclose(st); + return(0); + } +} + +void FCEUSS_CheckStates(void) { + MEM_TYPE *st = NULL; + char *fn; + int ssel; + + for (ssel = 0; ssel < 10; ssel++) { + st = FCEUD_UTF8fopen(fn = FCEU_MakeFName(FCEUMKF_STATE, ssel, 0), "rb"); + free(fn); + if (st) { + SaveStateStatus[ssel] = 1; + fclose(st); + } else + SaveStateStatus[ssel] = 0; + } + + CurrentState = 0; + StateShow = 0; +} + +void ResetExState(void (*PreSave)(void), void (*PostSave)(void)) { SPreSave = PreSave; SPostSave = PostSave; SFEXINDEX = 0; } -void AddExState(void *v, uint32 s, int type, char *desc) -{ +void AddExState(void *v, uint32 s, int type, char *desc) { memset(SFMDATA[SFEXINDEX].desc, 0, sizeof(SFMDATA[SFEXINDEX].desc)); if (desc) strncpy(SFMDATA[SFEXINDEX].desc, desc, sizeof(SFMDATA[SFEXINDEX].desc)); @@ -359,7 +372,52 @@ void AddExState(void *v, uint32 s, int type, char *desc) SFMDATA[SFEXINDEX].v = 0; // End marker. } -void FCEU_DrawSaveStates(uint8 *XBuf) -{ +void FCEUI_SelectState(int w) { + if (w == -1) { + StateShow = 0; return; + } + FCEUI_SelectMovie(-1); + + CurrentState = w; + StateShow = 180; + FCEU_DispMessage("-select state-"); +} + +void FCEUI_SaveState(char *fname) { + StateShow = 0; + FCEUSS_Save(fname); +} + +void FCEUI_LoadState(char *fname) { + StateShow = 0; + + FCEUMOV_Stop(); + + /* For network play, be load the state locally, and then save the state to a temporary file, + and send that. This insures that if an older state is loaded that is missing some + information expected in newer save states, desynchronization won't occur(at least not + from this ;)). + */ + if (FCEUSS_Load(fname)) + if (FCEUnetplay) { + char *fn = FCEU_MakeFName(FCEUMKF_NPTEMP, 0, 0); + MEM_TYPE *fp; + + if ((fp = fopen(fn, "wb"))) { + if (FCEUSS_SaveFP(fp)) { + fclose(fp); + FCEUNET_SendFile(FCEUNPCMD_LOADSTATE, fn); + } else fclose(fp); + unlink(fn); + } + free(fn); + } +} + +void FCEU_DrawSaveStates(uint8 *XBuf) { + if (!StateShow) return; + + FCEU_DrawNumberRow(XBuf, SaveStateStatus, CurrentState); + StateShow--; } diff --git a/src/unif.c b/src/unif.c index 0c1c6da..5b305c3 100644 --- a/src/unif.c +++ b/src/unif.c @@ -56,7 +56,7 @@ typedef struct { int (*init)(FCEUFILE *fp); } BFMAPPING; -CartInfo UNIFCart; +static CartInfo UNIFCart; static int vramo; static int mirrortodo; diff --git a/src/video.c b/src/video.c index 076579a..7739be9 100644 --- a/src/video.c +++ b/src/video.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "fceu-types.h" #include "video.h" @@ -30,65 +31,102 @@ #include "fceu-memory.h" #include "crc32.h" #include "state.h" +#include "movie.h" #include "palette.h" #include "nsf.h" #include "input.h" #include "vsuni.h" uint8 *XBuf = NULL; +static uint8 *xbsave = NULL; -void FCEU_KillVirtualVideo(void) -{ - if (XBuf) - free(XBuf); - XBuf = 0; +void FCEU_KillVirtualVideo(void) { + if (xbsave) { + free(xbsave); + xbsave = 0; + } } -int FCEU_InitVirtualVideo(void) -{ - // 256 bytes per scanline, * 240 scanline maximum, +8 for alignment, - if (!XBuf) - XBuf = (uint8*)(FCEU_malloc(256 * 256 + 8)); +int FCEU_InitVirtualVideo(void) { + if (!XBuf) // Some driver code may allocate XBuf externally. + // 256 bytes per scanline, * 240 scanline maximum, +8 for alignment, + if (!(XBuf = (uint8*)(FCEU_malloc(256 * 256 + 8)))) + return 0; + xbsave = XBuf; - if (!XBuf) - return 0; - - if (sizeof(uint8*) == 4) - { - uintptr_t m; - m = (uintptr_t)*XBuf; - m = (4 - m) & 3; - XBuf += m; - } - memset(XBuf, 128, 256 * 256); - return 1; + if (sizeof(uint8*) == 4) { + uint32 m; + m = (uint32)XBuf; + m = (4 - m) & 3; + XBuf += m; + } + memset(XBuf, 128, 256 * 256); + return 1; } static int howlong; static char errmsg[65]; #include "drawing.h" +#ifdef FRAMESKIP -void FCEUI_SaveSnapshot(void) { } +//#define SHOWFPS +void ShowFPS(void); +void FCEU_PutImageDummy(void) { + #ifdef SHOWFPS + ShowFPS(); + #endif + if (GameInfo->type != GIT_NSF) { + FCEU_DrawNTSCControlBars(XBuf); + FCEU_DrawSaveStates(XBuf); + FCEU_DrawMovies(XBuf); + } + if (howlong) howlong--; /* DrawMessage() */ +} +#endif -void FCEU_PutImage(void) -{ - if (GameInfo->type == GIT_NSF) +static int dosnapsave = 0; +void FCEUI_SaveSnapshot(void) { + dosnapsave = 1; +} + +static void ReallySnap(void) { + int x = SaveSnapshot(); + if (!x) + FCEU_DispMessage("Error saving screen snapshot."); + else + FCEU_DispMessage("Screen snapshot %d saved.", x - 1); +} + +void FCEU_PutImage(void) { + #ifdef SHOWFPS + ShowFPS(); + #endif + if (GameInfo->type == GIT_NSF) { DrawNSF(XBuf); - else - { + // Save snapshot after NSF screen is drawn. Why would we want to + // do it before? + if (dosnapsave) { + ReallySnap(); + dosnapsave = 0; + } + } else { + // Save snapshot before overlay stuff is written. + if (dosnapsave) { + ReallySnap(); + dosnapsave = 0; + } if (GameInfo->type == GIT_VSUNI) FCEU_VSUniDraw(XBuf); + FCEU_DrawSaveStates(XBuf); + FCEU_DrawMovies(XBuf); + FCEU_DrawNTSCControlBars(XBuf); } - if (howlong) howlong--; + DrawMessage(); + FCEU_DrawInput(XBuf); } -void FCEU_PutImageDummy(void) -{ -} - -void FCEU_DispMessage(char *format, ...) -{ +void FCEU_DispMessage(char *format, ...) { va_list ap; va_start(ap, format); @@ -98,12 +136,158 @@ void FCEU_DispMessage(char *format, ...) howlong = 180; } -void FCEU_ResetMessages(void) -{ - howlong = 180; +void FCEU_ResetMessages(void) { + howlong = 0; } -int SaveSnapshot(void) -{ + +static int WritePNGChunk(FILE *fp, uint32 size, char *type, uint8 *data) { + uint32 crc; + + uint8 tempo[4]; + + tempo[0] = size >> 24; + tempo[1] = size >> 16; + tempo[2] = size >> 8; + tempo[3] = size; + + if (fwrite(tempo, 4, 1, fp) != 1) + return 0; + if (fwrite(type, 4, 1, fp) != 1) + return 0; + + if (size) + if (fwrite(data, 1, size, fp) != size) + return 0; + + crc = CalcCRC32(0, (uint8*)type, 4); + if (size) + crc = CalcCRC32(crc, data, size); + + tempo[0] = crc >> 24; + tempo[1] = crc >> 16; + tempo[2] = crc >> 8; + tempo[3] = crc; + + if (fwrite(tempo, 4, 1, fp) != 1) + return 0; + return 1; +} + +int SaveSnapshot(void) { + static uint32 lastu = 0; + + char *fn = 0; + int totallines = FSettings.LastSLine - FSettings.FirstSLine + 1; + int x, u, y; + FILE *pp = NULL; + uint8 *compmem = NULL; + uLongf compmemsize = totallines * 263 + 12; + + if (!(compmem = (uint8*)FCEU_malloc(compmemsize))) + return 0; + + for (u = lastu; u < 99999; u++) { + pp = FCEUD_UTF8fopen((fn = FCEU_MakeFName(FCEUMKF_SNAP, u, "png")), "rb"); + if (pp == NULL) break; + fclose(pp); + } + + lastu = u; + + if (!(pp = FCEUD_UTF8fopen(fn, "wb"))) { + free(fn); + return 0; + } + free(fn); + { + static uint8 header[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; + if (fwrite(header, 8, 1, pp) != 1) + goto PNGerr; + } + + { + uint8 chunko[13]; + + chunko[0] = chunko[1] = chunko[3] = 0; + chunko[2] = 0x1; // Width of 256 + + chunko[4] = chunko[5] = chunko[6] = 0; + chunko[7] = totallines; // Height + + chunko[8] = 8; // bit depth + chunko[9] = 3; // Color type; indexed 8-bit + chunko[10] = 0; // compression: deflate + chunko[11] = 0; // Basic adapative filter set(though none are used). + chunko[12] = 0; // No interlace. + + if (!WritePNGChunk(pp, 13, "IHDR", chunko)) + goto PNGerr; + } + + { + uint8 pdata[256 * 3]; + for (x = 0; x < 256; x++) + FCEUD_GetPalette(x, pdata + x * 3, pdata + x * 3 + 1, pdata + x * 3 + 2); + if (!WritePNGChunk(pp, 256 * 3, "PLTE", pdata)) + goto PNGerr; + } + + { + uint8 *tmp = XBuf + FSettings.FirstSLine * 256; + uint8 *dest, *mal, *mork; + + if (!(mal = mork = dest = (uint8*)malloc((totallines << 8) + totallines))) + goto PNGerr; +// mork=dest=XBuf; + + for (y = 0; y < totallines; y++) { + *dest = 0; // No filter. + dest++; + for (x = 256; x; x--, tmp++, dest++) + *dest = *tmp; + } + + if (compress(compmem, &compmemsize, mork, (totallines << 8) + totallines) != Z_OK) { + if (mal) free(mal); + goto PNGerr; + } + if (mal) free(mal); + if (!WritePNGChunk(pp, compmemsize, "IDAT", compmem)) + goto PNGerr; + } + if (!WritePNGChunk(pp, 0, "IEND", 0)) + goto PNGerr; + + free(compmem); + fclose(pp); + + return u + 1; + + PNGerr: + if (compmem) + free(compmem); + if (pp) + fclose(pp); return(0); } + +#ifdef SHOWFPS +uint64 FCEUD_GetTime(void); +uint64 FCEUD_GetTimeFreq(void); + +static uint64 boop[60]; +static int boopcount = 0; + +void ShowFPS(void) { + uint64 da = FCEUD_GetTime() - boop[boopcount]; + char fpsmsg[16]; + int booplimit = PAL ? 50 : 60; + boop[boopcount] = FCEUD_GetTime(); + + sprintf(fpsmsg, "%8.1f", (double)booplimit / ((double)da / FCEUD_GetTimeFreq())); + DrawTextTrans(XBuf + (256 - 8 - 8 * 8) + (FSettings.FirstSLine + 4) * 256, 256, fpsmsg, 4); + // It's not averaging FPS over exactly 1 second, but it's close enough. + boopcount = (boopcount + 1) % booplimit; +} +#endif