diff --git a/Makefile.common b/Makefile.common index e65879e..e9416cc 100644 --- a/Makefile.common +++ b/Makefile.common @@ -2,4 +2,4 @@ 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)/drivers/libretro/griffin.c $(CORE_DIR)/ines.c $(CORE_DIR)/unif.c $(CORE_DIR)/x6502.c +SOURCES_C += $(CORE_DIR)/drivers/libretro/griffin.c $(CORE_DIR)/drivers/libretro/fceu/ines.c $(CORE_DIR)/drivers/libretro/fceu/unif.c $(CORE_DIR)/x6502.c diff --git a/src/drivers/libretro/fceu/fds.c b/src/drivers/libretro/fceu/fds.c new file mode 100644 index 0000000..7c054df --- /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 = FCEUD_UTF8fopen(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))) { + 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 = FCEUD_UTF8fopen(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/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/unif.c b/src/drivers/libretro/fceu/unif.c new file mode 100644 index 0000000..8d0fea7 --- /dev/null +++ b/src/drivers/libretro/fceu/unif.c @@ -0,0 +1,618 @@ +/* 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 1 +#define BMCFLAG_16KCHRR 2 +#define BMCFLAG_32KCHRR 4 +#define BMCFLAG_EXPCHRR 8 + +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 }, + { "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_EXPCHRR }, + { "FK23CA", BMCFK23CA_Init, BMCFLAG_EXPCHRR }, + { "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 }, + +#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 = 16384; + else if (bmap[x].flags & BMCFLAG_32KCHRR) + CHRRAMSize = 32768; + else if (bmap[x].flags & BMCFLAG_EXPCHRR) + CHRRAMSize = 256 * 1024; + else + CHRRAMSize = 8192; + 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/griffin.c b/src/drivers/libretro/griffin.c index ca6c75a..3175662 100644 --- a/src/drivers/libretro/griffin.c +++ b/src/drivers/libretro/griffin.c @@ -13,7 +13,7 @@ #include "drivers/libretro/fceu/misc.c" #include "drivers/libretro/fceu/fceu.c" //#include "fceustr.c" -#include "fds.c" +#include "drivers/libretro/fceu/fds.c" #include "drivers/libretro/fceu/file.c" #include "filter.c" #include "drivers/libretro/fceu/general.c" diff --git a/src/ines.c b/src/ines.c index cce884e..8120a70 100644 --- a/src/ines.c +++ b/src/ines.c @@ -48,11 +48,7 @@ uint8 *VROM = NULL; uint8 *ExtraNTARAM = NULL; iNES_HEADER head; -#ifdef __LIBRETRO__ -CartInfo iNESCart; -#else static CartInfo iNESCart; -#endif uint8 Mirroring = 0; uint32 ROM_size = 0; diff --git a/src/unif.c b/src/unif.c index a818f2c..4e81292 100644 --- a/src/unif.c +++ b/src/unif.c @@ -56,11 +56,7 @@ typedef struct { int (*init)(FCEUFILE *fp); } BFMAPPING; -#ifdef __LIBRETRO__ -CartInfo UNIFCart; -#else static CartInfo UNIFCart; -#endif static int vramo; static int mirrortodo;