diff --git a/.travis.yml b/.travis.yml index 451cdd7..e652e3c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ env: - PLATFORM=linux_x64 - PLATFORM=ngc - PLATFORM=wii - - PLATFORM=wiiu +# - PLATFORM=wiiu before_script: - pwd - mkdir -p ~/bin diff --git a/Makefile.common b/Makefile.common index 9ee013b..1d7a7b6 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1,19 +1,8 @@ +ifeq ($(LIBRETRO_COMM_DIR),) LIBRETRO_COMM_DIR := $(CORE_DIR)/drivers/libretro/libretro-common -INCFLAGS := -I$(CORE_DIR)/drivers/libretro -I$(LIBRETRO_COMM_DIR)/include -I$(CORE_DIR) -I$(CORE_DIR)/input -I$(CORE_DIR)/boards -I$(CORE_DIR)/mappers -COREDEFINES = -D__LIBRETRO__ -DSOUND_QUALITY=0 -DPATH_MAX=1024 -DFCEU_VERSION_NUMERIC=9813 -DFRONTEND_SUPPORTS_RGB565 - -INCLUDE_STDINT = 0 -ifneq (,$(findstring msvc200,$(platform))) -INCLUDE_STDINT = 1 -endif - -ifeq ($(INCLUDE_STDINT), 1) -INCFLAGS += -I$(LIBRETRO_COMM_DIR)/include/compat/msvc -endif - -ifneq (,$(findstring msvc,$(platform))) -COREDEFINES += -DINLINE=_inline endif +INCFLAGS := -I$(CORE_DIR)/drivers/libretro -I$(LIBRETRO_COMM_DIR)/include -I$(CORE_DIR) -I$(CORE_DIR)/input -I$(CORE_DIR)/boards +COREDEFINES = -D__LIBRETRO__ -DSOUND_QUALITY=0 -DPATH_MAX=1024 -DFCEU_VERSION_NUMERIC=9813 -DFRONTEND_SUPPORTS_RGB565 ifeq ($(PSS_STYLE),2) COREDEFINES += -DPSS_STYLE=2 @@ -21,8 +10,12 @@ else COREDEFINES += -DPSS_STYLE=1 endif +ifeq ($(TUP_CWD),) FCEU_SRC_DIRS := $(CORE_DIR)/boards $(CORE_DIR)/input $(CORE_DIR)/mappers SOURCES_C := $(foreach dir,$(FCEU_SRC_DIRS),$(wildcard $(dir)/*.c)) +else +SOURCES_C = $(CORE_DIR)/boards/*.c $(CORE_DIR)/input/*.c +endif ifeq ($(HAVE_GRIFFIN),1) SOURCES_C += $(CORE_DIR)/drivers/libretro/griffin.c @@ -63,4 +56,5 @@ endif SOURCES_C += \ $(CORE_DIR)/ines.c \ - $(CORE_DIR)/unif.c $(CORE_DIR)/x6502.c + $(CORE_DIR)/unif.c $(CORE_DIR)/x6502.c \ + $(CORE_DIR)/drivers/libretro/libretro_dipswitch.c diff --git a/Makefile.libretro b/Makefile.libretro index 044a6d7..b4c90c1 100644 --- a/Makefile.libretro +++ b/Makefile.libretro @@ -279,7 +279,7 @@ else ifeq ($(platform), wiiu) TARGET := $(TARGET_NAME)_libretro_$(platform).a CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT) AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT) - PLATFORM_DEFINES := -DGEKKO -DHW_RVL -mwup -mcpu=750 -meabi -mhard-float + PLATFORM_DEFINES := -DGEKKO -DHW_RVL -mcpu=750 -meabi -mhard-float PLATFORM_DEFINES += -U__INT32_TYPE__ -U __UINT32_TYPE__ -D__INT32_TYPE__=int ENDIANNESS_DEFINES += -DMSB_FIRST STATIC_LINKING=1 @@ -417,16 +417,6 @@ else ifeq ($(platform), gcw0) PLATFORM_DEFINES += -ffast-math -march=mips32 -mtune=mips32r2 -mhard-float EXTERNAL_ZLIB = 1 -# Genode -else ifeq ($(platform), genode) - TARGET := $(TARGET_NAME)_libretro.lib.so - CC := $(shell pkg-config genode-base --variable=cc) - LD := $(shell pkg-config genode-base --variable=ld) - CFLAGS += $(shell pkg-config --cflags genode-libc) - LDFLAGS += -shared --version-script=src/drivers/libretro/link.T - LDFLAGS += $(shell pkg-config --libs genode-lib genode-libc) - LIBM = - # Windows MSVC 2017 all architectures else ifneq (,$(findstring windows_msvc2017,$(platform))) CC = cl.exe @@ -653,7 +643,7 @@ CFLAGS += -D_CRT_SECURE_NO_DEPRECATE # Windows else TARGET := $(TARGET_NAME)_libretro.dll - CC = gcc + CC ?= gcc SHARED := -shared -static-libgcc -static-libstdc++ -s -Wl,--version-script=src/drivers/libretro/link.T PSS_STYLE :=2 endif @@ -692,6 +682,12 @@ else endif endif +ifneq ($(SANITIZER),) +CFLAGS += -fsanitize=$(SANITIZER) +CXXFLAGS += -fsanitize=$(SANITIZER) +LDFLAGS += -fsanitize=$(SANITIZER) +endif + ifeq ($(EXTERNAL_ZLIB), 1) CFLAGS += -DHAVE_EXTERNAL_ZLIB endif @@ -704,6 +700,19 @@ CORE_DIR := src include Makefile.common +INCLUDE_STDINT = 0 +ifneq (,$(findstring msvc200,$(platform))) +INCLUDE_STDINT = 1 +endif + +ifeq ($(INCLUDE_STDINT), 1) +INCFLAGS += -I$(LIBRETRO_COMM_DIR)/include/compat/msvc +endif + +ifneq (,$(findstring msvc,$(platform))) +COREDEFINES += -DINLINE=_inline +endif + CFLAGS += -DWANT_GRIFFIN OBJECTS := $(SOURCES_C:.c=.o) @@ -724,7 +733,7 @@ else WARNING_DEFINES = -Wno-write-strings endif -CFLAGS += $(COREDEFINES) $(fpic) $(WARNING_DEFINES) $(DEFINES) $(ENDIANNESS_DEFINES) +CFLAGS += $(fpic) $(WARNING_DEFINES) $(DEFINES) $(ENDIANNESS_DEFINES) LDFLAGS += $(LIBM) ifeq ($(platform), psp1) @@ -745,9 +754,6 @@ else ifeq ($(platform), switch) OBJOUT = -o LINKOUT = -o # libtransistor.mk sets LD for us -else ifeq ($(platform), genode) - OBJOUT = -o - LINKOUT = -o else OBJOUT = -o LINKOUT = -o diff --git a/Tupfile b/Tupfile new file mode 100644 index 0000000..b0e54a8 --- /dev/null +++ b/Tupfile @@ -0,0 +1,3 @@ +TARGET_NAME=fceumm +CORE_DIR=$(TUP_CWD)/src +include_rules diff --git a/src/boards/09-034a.c b/src/boards/09-034a.c index b39d595..12e5b79 100644 --- a/src/boards/09-034a.c +++ b/src/boards/09-034a.c @@ -44,7 +44,7 @@ static SFORMAT StateRegs[] = }; static void Sync(void) { - setprg8r(1, 0x6000, prg); + setprg8(0x6000, 4 | prg); setprg32(0x8000, 0); setchr8(0); } diff --git a/src/boards/126.c b/src/boards/126.c new file mode 100644 index 0000000..0a93910 --- /dev/null +++ b/src/boards/126.c @@ -0,0 +1,105 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2019 Libretro Team + * + * 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 + */ + +/* Mapper 126, PowerJoy 84-in-1 Multicart (PJ-008*/ +/* reference from nestopia since not available in nesdev */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint16 GetExChrExBank() { + uint16 bank = (uint16)EXPREGS[0]; + return ((~bank << 0 & 0x080 & ((uint16)EXPREGS[2])) | (bank << 4 & 0x080 & bank) | + (bank << 3 & 0x100) | (bank << 5 & 0x200)); +} + +static void UpdateChrBank(void) { + uint16 bank = (uint16)EXPREGS[2] & 0x0F; + bank |= GetExChrExBank() >> 3; + setchr8(bank); +} + +static void M126CW(uint32 A, uint8 V) { + if (!(EXPREGS[3] & 0x10)) { + uint16 bank = (uint16)V & (((uint16)EXPREGS[0] & 0x80) - 1); + bank |= GetExChrExBank(); + setchr1(A, bank); + } +} + +static void M126PW(uint32 A, uint8 V) { + uint16 bank = (uint16)V; + uint16 preg = (uint16)EXPREGS[0]; + bank &= ((~preg >> 2) & 0x10) | 0x0F; + bank |= ((preg & (0x06 | (preg & 0x40) >> 6)) << 4) | ((preg & 0x10) << 3); + if (!(EXPREGS[3] & 0x03)) + setprg8(A, bank); + else if ((A - 0x8000) == ((MMC3_cmd << 8) & 0x4000)) { /* TODO: Clean this */ + if ((EXPREGS[3] & 0x3) == 0x3) + setprg32(0x8000, (bank >> 2)); + else { + setprg16(0x8000, (bank >> 1)); + setprg16(0xc000, (bank >> 1)); + } + } +} + +static DECLFW(M126Write) { + A &= 0x03; + if(A == 0x01 || A == 0x02 || ((A == 0x00 || A == 0x03) && !(EXPREGS[3] & 0x80))) { + if (EXPREGS[A] != V) { + EXPREGS[A] = V; + if (EXPREGS[3] & 0x10) + UpdateChrBank(); + else + FixMMC3CHR(MMC3_cmd); + FixMMC3PRG(MMC3_cmd); + } + } +} + +void M126StateRestore(int v) { + FixMMC3CHR(MMC3_cmd); + FixMMC3PRG(MMC3_cmd); + + if (EXPREGS[3] & 0x10) + UpdateChrBank(); +} + +static void M126Reset(void) { + EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; + MMC3RegReset(); +} + +static void M126Power(void) { + EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; + GenMMC3Power(); + SetWriteHandler(0x6000, 0x7FFF, M126Write); +} + +void Mapper126_Init(CartInfo *info) { + GenMMC3_Init(info, 2048, 1023, 0, 0); + cwrap = M126CW; + pwrap = M126PW; + info->Power = M126Power; + info->Reset = M126Reset; + GameStateRestore = M126StateRestore; + AddExState(EXPREGS, 4, 0, "EXPR"); +} diff --git a/src/boards/177.c b/src/boards/177.c index bc87196..38828f8 100644 --- a/src/boards/177.c +++ b/src/boards/177.c @@ -59,6 +59,11 @@ static void M177Close(void) { WRAM = NULL; } +static void M177Reset(void) { + reg = 0; + Sync(); +} + static void StateRestore(int version) { Sync(); } @@ -66,6 +71,7 @@ static void StateRestore(int version) { void Mapper177_Init(CartInfo *info) { info->Power = M177Power; info->Close = M177Close; + info->Reset = M177Reset; GameStateRestore = StateRestore; WRAMSIZE = 8192; diff --git a/src/boards/224.c b/src/boards/224.c new file mode 100644 index 0000000..7c885b7 --- /dev/null +++ b/src/boards/224.c @@ -0,0 +1,50 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2019 Libretro Team + * + * 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 + */ + +/* 2019-05-29 - Mapper 224, KT-008 + * iNES Mapper 224 is used for the 晶科泰 (Jncota) KT-008 PCB. + * It's an MMC3 clone that supports 1024 KiB of PRG-ROM through an additional + * outer bank register at $5000. + * http://wiki.nesdev.com/w/index.php/INES_Mapper_224 */ + +#include "mapinc.h" +#include "mmc3.h" + +static void M224PW(uint32 A, uint8 V) { + setprg8(A, (V & 0x3f) | ((EXPREGS[0] << 4) & 0x40)); +} + +static DECLFW(Mapper224Write) { + EXPREGS[0] = V; + FixMMC3PRG(MMC3_cmd); +} + +static void M224Power(void) { + EXPREGS[0] = 0; + GenMMC3Power(); + SetWriteHandler(0x5000, 0x5000, Mapper224Write); +} + +void Mapper224_Init(CartInfo *info) { + GenMMC3_Init(info, 1024, 0, 8, 0); + pwrap = M224PW; + info->Power = M224Power; + AddExState(EXPREGS, 1, 0, "EXPR"); +} diff --git a/src/boards/237.c b/src/boards/237.c new file mode 100644 index 0000000..e2b784a --- /dev/null +++ b/src/boards/237.c @@ -0,0 +1,91 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2019 Libretro Team + * + * 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 + */ + +/* Mapper 237 - "Teletubbies / Y2K" 420-in-1 pirate multicart. + * Dipswitch settings: + * 0: 42-in-1 + * 1: 5,000-in-1 + * 2: 420-in-1 + * 3: 10,000,000-in-1 (lol) + */ + +#include "mapinc.h" + +static uint8 reg[2]; +static uint8 dipswitch; + +static SFORMAT StateRegs[] = +{ + { ®[0], 1, "REG0" }, + { ®[1], 1, "REG1" }, + { &dipswitch, 1, "DPSW" }, + { 0 } +}; + +static void Sync(void) { + uint8 bank = (reg[1] & 0x07); + uint8 base = (reg[1] & 0x18) | ((reg[0] & 0x04) << 3); + uint8 mode = (reg[1] & 0xC0) >> 6; + + setchr8(0); + setprg16(0x8000, base | (bank & ~(mode & 1))); + setprg16(0xC000, base | ((mode & 0x02) ? (bank | (mode & 0x01)) : 0x07)); + setmirror(((reg[1] & 0x20) >> 5) ^ 1); +} + +static DECLFW(M237Write) { + if (!(reg[0] & 0x02)) { + reg[0] = A & 0x0F; + reg[1] = (reg[1] & 0x07) | (V & 0xF8); + } + reg[1] = (reg[1] & 0xF8) | (V & 0x07); + Sync(); +} + +static DECLFR(M237Read) { + if (!(reg[0] & 0x02) && (reg[0] & 0x01)) + return dipswitch; + return CartBR(A); +} + +static void M237Power(void) { + Sync(); + SetReadHandler (0x8000, 0xFFFF, M237Read); + SetWriteHandler(0x8000, 0xFFFF, M237Write); +} + +static void M237Reset(void) { + reg[0] = reg[1] = 0; + Sync(); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper237_Init(CartInfo *info) { + dipswitch = 0; + if ((info->CRC32) == 0x272709b9) /* Teletubbies Y2K (420-in-1) */ + dipswitch = 2; + info->Power = M237Power; + info->Reset = M237Reset; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/255.c b/src/boards/255.c new file mode 100644 index 0000000..fc7f28c --- /dev/null +++ b/src/boards/255.c @@ -0,0 +1,79 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright (C) 2019 Libretro Team + * + * 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 + */ + +/* added 2019-5-23 + * Mapper 255 + * https://wiki.nesdev.com/w/index.php/INES_Mapper_225 + * 115-in-1 [p1][!] CRC32 0xb39d30b4 + * Seems to handle up to last game in the multicarts than m225 but causes + * graphics garbage past it, else games works fine */ + +#include "mapinc.h" + +static uint8 preg, creg, mode, mirr; + +static SFORMAT StateRegs[] = +{ + { &preg, 1, "PRG0" }, + { &creg, 1, "CHR0" }, + { &mode, 1, "MODE" }, + { &mirr, 1, "MIRR" }, + { 0 } +}; + +static void Sync(void) { + setprg16(0x8000, preg & ~mode); + setprg16(0xC000, preg | mode); + setchr8(creg); + setmirror(mirr ^ 1); +} + +static DECLFW(M255Write) { + uint32 bank = (A >> 8 & 0x40); + preg = bank | ((A >> 6) & 0x3F); + creg = bank | (A & 0x3F); + mirr = (A >> 13) & 1; + mode = ((~A) >> 12 & 1); + Sync(); +} + +static void M255Power(void) { + preg = 0; + mode = 1; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M255Write); +} + +static void M255Reset(void) { + preg = 0; + mode = 1; + Sync(); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper255_Init(CartInfo *info) { + info->Reset = M255Reset; + info->Power = M255Power; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/28.c b/src/boards/28.c new file mode 100644 index 0000000..4fdd088 --- /dev/null +++ b/src/boards/28.c @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2012-2017 FCEUX team + * + * 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. + * + */ + +/* added 2019-5-23 + * Mapper 28 - Action 53 + * http://wiki.nesdev.com/w/index.php/INES_Mapper_028 */ + +#include "mapinc.h" + +static uint8 prg_mask_16k; +static uint8 reg, chr, prg, mode, outer; + +static SFORMAT StateRegs[] = { + {®, 1, "REG"}, + {&chr, 1, "CHR"}, + {&prg, 1, "PRG"}, + {&mode, 1, "MODE"}, + {&outer, 1, "OUTR"}, + {0} +}; + +void SyncMirror() { + switch (mode & 3) { + case 0: setmirror(MI_0); break; + case 1: setmirror(MI_1); break; + case 2: setmirror(MI_V); break; + case 3: setmirror(MI_H); break; + } +} + +void Mirror(uint8 value) +{ + if ((mode & 2) == 0) { + mode &= 0xfe; + mode |= value >> 4 & 1; + } + SyncMirror(); +} + + +static void Sync() { + uint8 prglo; + uint8 prghi; + + uint8 outb = outer << 1; + + /* this can probably be rolled up, but i have no motivation to do so + * until it's been tested */ + switch (mode & 0x3c) { + /* 32K modes */ + case 0x00: + case 0x04: + prglo = outb; + prghi = outb | 1; + break; + case 0x10: + case 0x14: + prglo = (outb & ~2) | (prg << 1 & 2); + prghi = (outb & ~2) | (prg << 1 & 2) | 1; + break; + case 0x20: + case 0x24: + prglo = (outb & ~6) | (prg << 1 & 6); + prghi = (outb & ~6) | (prg << 1 & 6) | 1; + break; + case 0x30: + case 0x34: + prglo = (outb & ~14) | (prg << 1 & 14); + prghi = (outb & ~14) | (prg << 1 & 14) | 1; + break; + /* bottom fixed modes */ + case 0x08: + prglo = outb; + prghi = outb | (prg & 1); + break; + case 0x18: + prglo = outb; + prghi = (outb & ~2) | (prg & 3); + break; + case 0x28: + prglo = outb; + prghi = (outb & ~6) | (prg & 7); + break; + case 0x38: + prglo = outb; + prghi = (outb & ~14) | (prg & 15); + break; + /* top fixed modes */ + case 0x0c: + prglo = outb | (prg & 1); + prghi = outb | 1; + break; + case 0x1c: + prglo = (outb & ~2) | (prg & 3); + prghi = outb | 1; + break; + case 0x2c: + prglo = (outb & ~6) | (prg & 7); + prghi = outb | 1; + break; + case 0x3c: + prglo = (outb & ~14) | (prg & 15); + prghi = outb | 1; + break; + } + + prglo &= prg_mask_16k; + prghi &= prg_mask_16k; + + setprg16(0x8000, prglo); + setprg16(0xC000, prghi); + setchr8(chr); +} + +static DECLFW(WriteEXP) { + reg = V & 0x81; +} + +static DECLFW(WritePRG) { + switch (reg) { + case 0x00: + chr = V & 3; + Mirror(V); + Sync(); + break; + case 0x01: + prg = V & 15; + Mirror(V); + Sync(); + break; + case 0x80: + mode = V & 63; + SyncMirror(); + Sync(); + break; + case 0x81: + outer = V & 63; + Sync(); + break; + } +} + +static void M28Power(void) { + outer = 63; + prg = 15; + Sync(); + prg_mask_16k = PRGsize[0] - 1; + SetWriteHandler(0x5000,0x5FFF,WriteEXP); + SetWriteHandler(0x8000,0xFFFF,WritePRG); + SetReadHandler(0x8000,0xFFFF,CartBR); + SetReadHandler(0x6000,0x7FFF,CartBR); + SetWriteHandler(0x6000,0x7FFF,CartBW); +} + +static void M28Reset(void) { + outer = 63; + prg = 15; + Sync(); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper28_Init(CartInfo* info) { + info->Power=M28Power; + info->Reset=M28Reset; + GameStateRestore=StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/31.c b/src/boards/31.c new file mode 100644 index 0000000..17777ab --- /dev/null +++ b/src/boards/31.c @@ -0,0 +1,66 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright (C) 2019 Libretro Team + * + * 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 + */ + +/* added 2019-5-23 + * Mapper 31 - custom mapper by infiniteneslives + * https://wiki.nesdev.com/w/index.php/INES_Mapper_031 */ + +#include "mapinc.h" + +static uint8 preg[8]; + +static SFORMAT StateRegs[] = +{ + { preg, 8, "PREG" }, + { 0 } +}; + +static void Sync(void) { + setprg4(0x8000, preg[0]); + setprg4(0x9000, preg[1]); + setprg4(0xA000, preg[2]); + setprg4(0xB000, preg[3]); + setprg4(0xC000, preg[4]); + setprg4(0xD000, preg[5]); + setprg4(0xE000, preg[6]); + setprg4(0xF000, preg[7]); + setchr8(0); +} + +static DECLFW(M31Write) { + preg[A & 7] = V; + Sync(); +} + +static void M31Power(void) { + preg[7] = ~0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x5000, 0x5FFF, M31Write); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper31_Init(CartInfo *info) { + info->Power = M31Power; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/36.c b/src/boards/36.c index 9ffed93..afc1c87 100644 --- a/src/boards/36.c +++ b/src/boards/36.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2019 Libretro Team * * 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 @@ -18,38 +19,65 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * TXC/Micro Genius simplified mapper + * updated 06-2019 http://wiki.nesdev.com/w/index.php/INES_Mapper_036 + * + * Known games: + * - Strike Wolf (Asia) (Unl) + * - Policeman (Gluk Video) (unl) + * - F-15 City War (Spain) (Gluk Video) (Unl) */ #include "mapinc.h" -static uint8 latche; +static uint8 regs[5]; static SFORMAT StateRegs[] = { - { &latche, 1, "LATC" }, + { regs, 5, "REGS" }, { 0 } }; static void Sync(void) { - setprg32(0x8000, latche >> 4); - setchr8(latche & 0xf); + setprg32(0x8000, regs[0] >> 4); + setchr8(regs[4] & 0x0F); } -static DECLFW(M36Write) { - latche = V; +static DECLFW(M36Write4100) { + switch(A & 0xE103) { + case 0x4100: + if(regs[3] & 0x10) + regs[0]++; + else + regs[0] = regs[2]; + break; + case 0x4101: + case 0x4102: + case 0x4103: + regs[A & 0x03] = V; + break; + } +} + +static DECLFW(M36Write4200) { + regs[4] = V; + Sync(); +} + +static DECLFW(M36WriteHi) { Sync(); } static DECLFR(M36Read) { - return latche; /* Need by Strike Wolf, being simplified mapper, this cart still uses some TCX mapper features andrely on it */ + return ((X.DB & 0xCF) | (regs[0] & 0x30)); } static void M36Power(void) { - latche = 0; Sync(); SetReadHandler(0x4100, 0x4100, M36Read); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFE, M36Write); /* Actually, BUS conflict there preventing from triggering the wrong banks */ + SetWriteHandler(0x4100, 0x4103, M36Write4100); + SetWriteHandler(0x4200, 0x4200, M36Write4200); + SetWriteHandler(0x8000, 0xFFFF, M36WriteHi); } static void M36Restore(int version) { diff --git a/src/boards/411120-c.c b/src/boards/411120-c.c index a4c30e0..a21a898 100644 --- a/src/boards/411120-c.c +++ b/src/boards/411120-c.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2008 CaH4e3 + * Copyright (C) 2019 Libretro Team * * 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 @@ -18,25 +19,38 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* actually cart ID is 811120-C, sorry ;) K-3094 - another ID */ +/* NES 2.0 Mapper 287 + * BMC-411120-C, actually cart ID is 811120-C, sorry ;) K-3094 - another ID + * - 4-in-1 (411120-C) + * - 4-in-1 (811120-C,411120-C) [p4][U] + * + * BMC-K-3088, similar to BMC-411120-C but without jumper or dipswitch + * - 19-in-1(K-3088)(810849-C)(Unl) + */ #include "mapinc.h" #include "mmc3.h" static uint8 reset_flag = 0; +static uint8 isK3088; static void BMC411120CCW(uint32 A, uint8 V) { - setchr1(A, V | ((EXPREGS[0] & 3) << 7)); + uint32 mask = isK3088 ? 0x07 : 0x03; + setchr1(A, V | ((EXPREGS[0] & mask) << 7)); } static void BMC411120CPW(uint32 A, uint8 V) { - if (EXPREGS[0] & (8 | reset_flag)) - setprg32(0x8000, ((EXPREGS[0] >> 4) & 3) | (0x0C)); - else - setprg8(A, (V & 0x0F) | ((EXPREGS[0] & 3) << 4)); + uint32 mask = isK3088 ? 0x07 : 0x03; + if (EXPREGS[0] & (isK3088 ? 8 : (8 | reset_flag))) { /* 32K Mode */ + if (A == 0x8000) + /* bit 0-1 of register should be used as outer bank regardless of banking modes */ + setprg32(A, ((EXPREGS[0] >> 4) & 3) | ((EXPREGS[0] & mask) << 2)); + } else /* MMC3 Mode */ + setprg8(A, (V & 0x0F) | ((EXPREGS[0] & mask) << 4)); } static DECLFW(BMC411120CLoWrite) { +/* printf("Wr: A:%04x V:%02x\n", A, V); */ EXPREGS[0] = A; FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); @@ -55,6 +69,17 @@ static void BMC411120CPower(void) { } void BMC411120C_Init(CartInfo *info) { + isK3088 = 0; + GenMMC3_Init(info, 128, 128, 8, 0); + pwrap = BMC411120CPW; + cwrap = BMC411120CCW; + info->Power = BMC411120CPower; + info->Reset = BMC411120CReset; + AddExState(EXPREGS, 1, 0, "EXPR"); +} + +void BMCK3088_Init(CartInfo *info) { + isK3088 = 1; GenMMC3_Init(info, 128, 128, 8, 0); pwrap = BMC411120CPW; cwrap = BMC411120CCW; diff --git a/src/boards/68.c b/src/boards/68.c index 19da627..2e0ec8f 100644 --- a/src/boards/68.c +++ b/src/boards/68.c @@ -73,7 +73,7 @@ static void Sync(void) { setchr2(0x1800, chr_reg[3]); setprg8r(0x10, 0x6000, 0); setprg16r((PRGptr[1]) ? kogame : 0, 0x8000, prg_reg); - setprg16(0xC000, ~0); + setprg16(0xC000, 0x07); } static DECLFR(M68Read) { diff --git a/src/boards/69.c b/src/boards/69.c index 2a7093b..3117106 100644 --- a/src/boards/69.c +++ b/src/boards/69.c @@ -135,7 +135,6 @@ static DECLFW(M69SWrite0) { } static DECLFW(M69SWrite1) { - int x; GameExpSound.Fill = AYSound; GameExpSound.HiFill = AYSoundHQ; switch (sndcmd) { diff --git a/src/boards/8157.c b/src/boards/8157.c index 8a95353..eb9224f 100644 --- a/src/boards/8157.c +++ b/src/boards/8157.c @@ -36,13 +36,9 @@ static void Sync(void) { uint32 base = ((cmdreg & 0x060) | ((cmdreg & 0x100) >> 1)) >> 2; uint32 bank = (cmdreg & 0x01C) >> 2; uint32 lbank = (cmdreg & 0x200) ? 7 : ((cmdreg & 0x80) ? bank : 0); - if (PRGptr[1]) { - setprg16r(base >> 3, 0x8000, bank); /* for versions with split ROMs */ - setprg16r(base >> 3, 0xC000, lbank); - } else { - setprg16(0x8000, base | bank); - setprg16(0xC000, base | lbank); - } + + setprg16(0x8000, base | bank); + setprg16(0xC000, base | lbank); setmirror(((cmdreg & 2) >> 1) ^ 1); } diff --git a/src/boards/830134C.c b/src/boards/830134C.c new file mode 100644 index 0000000..5637c7a --- /dev/null +++ b/src/boards/830134C.c @@ -0,0 +1,70 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2019 Libretro Team + * + * 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 + */ + +/* NES 2.0 Mapper 315 + * BMC-830134C + * Used for multicarts using 820732C- and 830134C-numbered PCBs such as 4-in-1 Street Blaster 5 + * http://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_315 + */ + +#include "mapinc.h" +#include "mmc3.h" + +static void BMC830134CCW(uint32 A, uint8 V) { + setchr1(A, (V & 0xFF) | ((EXPREGS[0] & 0x01) << 8) | ((EXPREGS[0] & 0x02) << 6) | ((EXPREGS[0] & 0x08) << 3)); +} + +static void BMC830134CPW(uint32 A, uint8 V) { + if ((EXPREGS[0] & 0x06) == 0x06) { + if (A == 0x8000) { + setprg8(A, (V & 0x0F) | ((EXPREGS[0] & 0x06) << 3)); + setprg8(0xC000, (V & 0x0F) | 0x32); + } else if (A == 0xA000) { + setprg8(A, (V & 0x0F) | ((EXPREGS[0] & 0x06) << 3)); + setprg8(0xE000, (V & 0x0F) | 0x32); + } + } else + setprg8(A, (V & 0x0F) | ((EXPREGS[0] & 0x06) << 3)); +} + +static DECLFW(BMC830134CWrite) { + EXPREGS[0] = V; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static void BMC830134CReset(void) { + EXPREGS[0] = 0; + MMC3RegReset(); +} + +static void BMC830134CPower(void) { + GenMMC3Power(); + SetWriteHandler(0x6800, 0x68FF, BMC830134CWrite); +} + +void BMC830134C_Init(CartInfo *info) { + GenMMC3_Init(info, 128, 256, 1, 0); + pwrap = BMC830134CPW; + cwrap = BMC830134CCW; + info->Power = BMC830134CPower; + info->Reset = BMC830134CReset; + AddExState(EXPREGS, 1, 0, "EXPR"); +} diff --git a/src/boards/90.c b/src/boards/90.c index bdbd3a0..ff2b0b4 100644 --- a/src/boards/90.c +++ b/src/boards/90.c @@ -3,6 +3,7 @@ * Copyright notice for this file: * Copyright (C) 2002 Xodnizel * Copyright (C) 2005 CaH4e3 + * Copyright (C) 2019 Libretro Team * * 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 @@ -25,10 +26,12 @@ /* Mapper 090 is simpliest mapper hardware and have not extended nametable control and latched chr banks in 4k mode * Mapper 209 much compicated hardware with decribed above features disabled by default and switchable by command * Mapper 211 the same mapper 209 but with forced nametable control + * Mapper 281 PRG ($8000-$8FFF) and CHR ($9000-$AFFF) bank select register bits that select 256 KiB banks are masked off. */ static int is209; static int is211; +static int is281; static uint8 IRQMode; /* from $c001 */ static uint8 IRQPre; /* from $c004 */ @@ -73,7 +76,7 @@ static SFORMAT Tek_StateRegs[] = { }; static void mira(void) { - if ((tkcom[0] & 0x20 && is209) || is211) { + if (((tkcom[0] & 0x20) && is209) || is211 || ((tkcom[1] & 0x08) && is281)) { int x; if (tkcom[0] & 0x40) { /* Name tables are ROM-only */ for (x = 0; x < 4; x++) @@ -96,56 +99,64 @@ static void mira(void) { } } +static uint8 invertprg(uint8 bank, uint8 reverse) { + if (reverse) + return ((bank & 0x01) << 6 | (bank & 0x02) << 4 | (bank & 0x04) << 2 | + (bank & 0x10) >> 2 | (bank & 0x20) >> 4 | (bank & 0x40) >> 6); + else + return bank; +} + static void tekprom(void) { - uint32 bankmode = ((tkcom[3] & 6) << 5); - switch (tkcom[0] & 7) { - case 00: + uint8 prgshift = 0, prgmask = 0x3F, outb_sel = 0x06, last_bank = 0x3F; + uint8 prgmode = tkcom[0] & 0x03; + uint8 invert = (tkcom[0] & 0x03) == 0x03 ? 1 : 0; + uint32 bankmode = 0; + + switch (tkcom[0] & 0x03) { + case 0x00: prgshift = 3; prgmask = 0x0F; break; + case 0x01: prgshift = 4; prgmask = 0x1F; break; + default: prgshift = 5; prgmask = 0x3F; break; + } + + if (is281) { + prgmask >>= 1; + outb_sel = 0x01; + } + + bankmode = ((tkcom[3] & outb_sel) << prgshift); + last_bank = (tkcom[0] & 0x04) ? prgb[3] : prgmask; + switch (prgmode) { + case 0x00: if (tkcom[0] & 0x80) setprg8(0x6000, (((prgb[3] << 2) + 3) & 0x3F) | bankmode); - setprg32(0x8000, 0x0F | ((tkcom[3] & 6) << 3)); + setprg32(0x8000, (last_bank & prgmask) | bankmode); break; - case 01: + case 0x01: if (tkcom[0] & 0x80) setprg8(0x6000, (((prgb[3] << 1) + 1) & 0x3F) | bankmode); - setprg16(0x8000, (prgb[1] & 0x1F) | ((tkcom[3] & 6) << 4)); - setprg16(0xC000, 0x1F | ((tkcom[3] & 6) << 4)); + setprg16(0x8000, (prgb[1] & prgmask) | bankmode); + setprg16(0xC000, (last_bank & prgmask) | bankmode); break; - case 03: /* bit reversion */ - case 02: + case 0x02: + case 0x03: if (tkcom[0] & 0x80) - setprg8(0x6000, (prgb[3] & 0x3F) | bankmode); - setprg8(0x8000, (prgb[0] & 0x3F) | bankmode); - setprg8(0xa000, (prgb[1] & 0x3F) | bankmode); - setprg8(0xc000, (prgb[2] & 0x3F) | bankmode); - setprg8(0xe000, 0x3F | bankmode); - break; - case 04: - if (tkcom[0] & 0x80) - setprg8(0x6000, (((prgb[3] << 2) + 3) & 0x3F) | bankmode); - setprg32(0x8000, (prgb[3] & 0x0F) | ((tkcom[3] & 6) << 3)); - break; - case 05: - if (tkcom[0] & 0x80) - setprg8(0x6000, (((prgb[3] << 1) + 1) & 0x3F) | bankmode); - setprg16(0x8000, (prgb[1] & 0x1F) | ((tkcom[3] & 6) << 4)); - setprg16(0xC000, (prgb[3] & 0x1F) | ((tkcom[3] & 6) << 4)); - break; - case 07: /* bit reversion */ - case 06: - if (tkcom[0] & 0x80) - setprg8(0x6000, (prgb[3] & 0x3F) | bankmode); - setprg8(0x8000, (prgb[0] & 0x3F) | bankmode); - setprg8(0xa000, (prgb[1] & 0x3F) | bankmode); - setprg8(0xc000, (prgb[2] & 0x3F) | bankmode); - setprg8(0xe000, (prgb[3] & 0x3F) | bankmode); + setprg8(0x6000, (invertprg(prgb[3], invert) & 0x3F) | bankmode); + setprg8(0x8000, (invertprg(prgb[0], invert) & prgmask) | bankmode); + setprg8(0xa000, (invertprg(prgb[1], invert) & prgmask) | bankmode); + setprg8(0xc000, (invertprg(prgb[2], invert) & prgmask) | bankmode); + setprg8(0xe000, (invertprg(last_bank, invert) & prgmask) | bankmode); break; } } static void tekvrom(void) { int x, bank = 0, mask = 0xFFFF; - if (!(tkcom[3] & 0x20)) { - bank = (tkcom[3] & 1) | ((tkcom[3] & 0x18) >> 2); + if (!(tkcom[3] & 0x20) || is281) { + if (is281) + bank = tkcom[3] & 1; + else + bank = (tkcom[3] & 1) | ((tkcom[3] & 0x18) >> 2); switch (tkcom[0] & 0x18) { case 0x00: bank <<= 5; mask = 0x1F; break; case 0x08: bank <<= 6; mask = 0x3F; break; @@ -445,6 +456,7 @@ static void M90Power(void) { void Mapper90_Init(CartInfo *info) { is211 = 0; is209 = 0; + is281 = 0; info->Reset = togglie; info->Power = M90Power; PPU_hook = M90PPU; @@ -457,6 +469,7 @@ void Mapper90_Init(CartInfo *info) { void Mapper209_Init(CartInfo *info) { is211 = 0; is209 = 1; + is281 = 0; info->Reset = togglie; info->Power = M90Power; PPU_hook = M90PPU; @@ -468,6 +481,20 @@ void Mapper209_Init(CartInfo *info) { void Mapper211_Init(CartInfo *info) { is211 = 1; + is281 = 0; + info->Reset = togglie; + info->Power = M90Power; + PPU_hook = M90PPU; + MapIRQHook = CPUWrap; + GameHBIRQHook2 = SLWrap; + GameStateRestore = M90Restore; + AddExState(Tek_StateRegs, ~0, 0, 0); +} + +void Mapper281_Init(CartInfo *info) { + is211 = 0; + is209 = 0; + is281 = 1; info->Reset = togglie; info->Power = M90Power; PPU_hook = M90PPU; diff --git a/src/boards/ks7016.c b/src/boards/KS7016.c similarity index 100% rename from src/boards/ks7016.c rename to src/boards/KS7016.c diff --git a/src/boards/KS7017.c b/src/boards/KS7017.c index 64812a4..b1c9d87 100644 --- a/src/boards/KS7017.c +++ b/src/boards/KS7017.c @@ -23,7 +23,7 @@ #include "mapinc.h" -static uint8 reg, mirr; +static uint8 latche, reg, mirr; static int32 IRQa, IRQCount, IRQLatch; static uint8 *WRAM = NULL; static uint32 WRAMSIZE; @@ -35,6 +35,7 @@ static SFORMAT StateRegs[] = { &IRQa, 4, "IRQA" }, { &IRQCount, 4, "IRQC" }, { &IRQLatch, 4, "IRQL" }, + { &latche, 1, "LATC" }, { 0 } }; @@ -47,8 +48,9 @@ static void Sync(void) { static DECLFW(UNLKS7017Write) { /* FCEU_printf("bs %04x %02x\n",A,V); */ if ((A & 0xFF00) == 0x4A00) { - reg = ((A >> 2) & 3) | ((A >> 4) & 4); + latche = ((A >> 2) & 3) | ((A >> 4) & 4); } else if ((A & 0xFF00) == 0x5100) { + reg = latche; Sync(); } else if (A == 0x4020) { X6502_IRQEnd(FCEU_IQEXT); diff --git a/src/boards/KS7032.c b/src/boards/KS7032.c index 7958a0c..8e123e5 100644 --- a/src/boards/KS7032.c +++ b/src/boards/KS7032.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2007 CaH4e3 + * Copyright (C) 2019 Libretro Team * * 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 @@ -21,43 +22,99 @@ * */ +/* added 2019-5-23 + * - Mapper 56 - UNL KS202 + * FDS Conversion: Super Mario Bros. 3 (Pirate, Alt) + * similar to M142 but use WRAM instead? $D000 additional IRQ trigger + * - fix IRQ counter, noticeable in status bars of both SMB2J(KS7032) and SMB3J(KS202) + */ + #include "mapinc.h" -static uint8 reg[8], cmd, IRQa = 0, isirqused = 0; -static int32 IRQCount; +static uint8 reg[8], creg[8], mirr, cmd, IRQa = 0; +static int32 IRQCount, IRQLatch; +static uint8 KS7032; +static uint8 *WRAM = NULL; +static uint32 WRAMSIZE; -static SFORMAT StateRegs[] = +static SFORMAT StateRegsKS7032[] = { { &cmd, 1, "CMD" }, { reg, 8, "REGS" }, { &IRQa, 1, "IRQA" }, - { &IRQCount, 4, "IRQC" }, + { &IRQCount, 4 | FCEUSTATE_RLSB, "IRQC" }, + { 0 } +}; + +static SFORMAT StateRegsKS202[] = +{ + { creg, 8, "CREG" }, + { &mirr, 1, "MIRR" }, { 0 } }; static void Sync(void) { - setprg8(0x6000, reg[4]); - setprg8(0x8000, reg[1]); - setprg8(0xA000, reg[2]); - setprg8(0xC000, reg[3]); + setprg8(0x8000, reg[0]); + setprg8(0xA000, reg[1]); + setprg8(0xC000, reg[2]); setprg8(0xE000, ~0); setchr8(0); + if (KS7032) + setprg8(0x6000, reg[3]); + else { + setprg8r(0x10, 0x6000, 0); + setchr1(0x0000, creg[0]); + setchr1(0x0400, creg[1]); + setchr1(0x0800, creg[2]); + setchr1(0x0C00, creg[3]); + setchr1(0x1000, creg[4]); + setchr1(0x1400, creg[5]); + setchr1(0x1800, creg[6]); + setchr1(0x1C00, creg[7]); + setmirror(mirr); + } } static DECLFW(UNLKS7032Write) { /* FCEU_printf("bs %04x %02x\n",A,V); */ switch (A & 0xF000) { /* case 0x8FFF: reg[4]=V; Sync(); break; */ - case 0x8000: X6502_IRQEnd(FCEU_IQEXT); IRQCount = (IRQCount & 0x000F) | (V & 0x0F); isirqused = 1; break; - case 0x9000: X6502_IRQEnd(FCEU_IQEXT); IRQCount = (IRQCount & 0x00F0) | ((V & 0x0F) << 4); isirqused = 1; break; - case 0xA000: X6502_IRQEnd(FCEU_IQEXT); IRQCount = (IRQCount & 0x0F00) | ((V & 0x0F) << 8); isirqused = 1; break; - case 0xB000: X6502_IRQEnd(FCEU_IQEXT); IRQCount = (IRQCount & 0xF000) | (V << 12); isirqused = 1; break; - case 0xC000: if (isirqused) { - X6502_IRQEnd(FCEU_IQEXT); IRQa = 1; - } - break; + case 0x8000: IRQLatch = (IRQLatch & 0xFFF0) | (V & 0x0F); break; + case 0x9000: IRQLatch = (IRQLatch & 0xFF0F) | ((V & 0x0F) << 4); break; + case 0xA000: IRQLatch = (IRQLatch & 0xF0FF) | ((V & 0x0F) << 8); break; + case 0xB000: IRQLatch = (IRQLatch & 0x0FFF) | (V << 12); break; + case 0xC000: + IRQa = (V & 0xF); + if (IRQa) + IRQCount = IRQLatch; + X6502_IRQEnd(FCEU_IQEXT); break; + case 0xD000: X6502_IRQEnd(FCEU_IQEXT); break; case 0xE000: cmd = V & 7; break; - case 0xF000: reg[cmd] = V; Sync(); break; + case 0xF000: { + uint8 bank = (cmd - 1); + if (bank < 3) + reg[bank] = (reg[bank] & 0x10) | (V & 0x0F); + else if (bank < 4) + reg[bank] = V; + Sync(); + switch (A & 0xFC00) { + case 0xF000: + A &= 3; + if (A < 3) + reg[bank] = (reg[bank] & 0x0F) | (V & 0x10); + Sync(); + break; + case 0xF800: + mirr = (V & 1); + Sync(); + break; + case 0xFC00: + creg[A & 7] = V; + Sync(); + break; + } + } + break; } } @@ -65,8 +122,7 @@ static void FP_FASTAPASS(1) UNLSMB2JIRQHook(int a) { if (IRQa) { IRQCount += a; if (IRQCount >= 0xFFFF) { - IRQa = 0; - IRQCount = 0; + IRQCount = IRQLatch; X6502_IRQBegin(FCEU_IQEXT); } } @@ -77,6 +133,10 @@ static void UNLKS7032Power(void) { SetReadHandler(0x6000, 0x7FFF, CartBR); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x4020, 0xFFFF, UNLKS7032Write); + if (!KS7032) { + SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + } } static void StateRestore(int version) { @@ -84,8 +144,27 @@ static void StateRestore(int version) { } void UNLKS7032_Init(CartInfo *info) { + KS7032 = 1; info->Power = UNLKS7032Power; MapIRQHook = UNLSMB2JIRQHook; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(&StateRegsKS7032, ~0, 0, 0); +} + +void UNLKS202_Init(CartInfo *info) { + KS7032 = 0; + info->Power = UNLKS7032Power; + MapIRQHook = UNLSMB2JIRQHook; + GameStateRestore = StateRestore; + AddExState(&StateRegsKS7032, ~0, 0, 0); + AddExState(&StateRegsKS202, ~0, 0, 0); + + WRAMSIZE = 8192; + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); } diff --git a/src/boards/SA-9602B.c b/src/boards/SA-9602B.c index 7acd049..10b4315 100644 --- a/src/boards/SA-9602B.c +++ b/src/boards/SA-9602B.c @@ -22,12 +22,12 @@ #include "mmc3.h" static void SA9602BPW(uint32 A, uint8 V) { - setprg8r(EXPREGS[1], A, V & 0x3F); + setprg8(A, (EXPREGS[1] & 0xC0) | (V & 0x3F)); if (MMC3_cmd & 0x40) - setprg8r(0, 0x8000, ~(1)); + setprg8(0x8000, 62); else - setprg8r(0, 0xc000, ~(1)); - setprg8r(0, 0xe000, ~(0)); + setprg8(0xc000, 62); + setprg8(0xe000, 63); } static DECLFW(SA9602BWrite) { @@ -35,7 +35,7 @@ static DECLFW(SA9602BWrite) { case 0x8000: EXPREGS[0] = V; break; case 0x8001: if ((EXPREGS[0] & 7) < 6) { - EXPREGS[1] = V >> 6; + EXPREGS[1] = V; FixMMC3PRG(MMC3_cmd); } break; diff --git a/src/boards/ac-08.c b/src/boards/ac-08.c index 8dd16eb..081512e 100644 --- a/src/boards/ac-08.c +++ b/src/boards/ac-08.c @@ -34,7 +34,7 @@ static SFORMAT StateRegs[] = static void Sync(void) { setprg8(0x6000, reg); - setprg32r(1, 0x8000, 0); + setprg32(0x8000, 4); setchr8(0); setmirror(mirr); } diff --git a/src/boards/addrlatch.c b/src/boards/addrlatch.c index b9efe6d..473559e 100644 --- a/src/boards/addrlatch.c +++ b/src/boards/addrlatch.c @@ -195,6 +195,41 @@ void Mapper61_Init(CartInfo *info) { Latch_Init(info, M61Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0); } +/*------------------ Map 063 ---------------------------*/ +/* added 2019-5-23 + * Mapper 63 NTDEC-Multicart + * http://wiki.nesdev.com/w/index.php/INES_Mapper_063 + * - Powerful 250-in-1 + * - Hello Kitty 255-in-1 */ + +static uint16 openBus; + +static DECLFR(M63Read) { + if (A < 0xC000) + if (openBus) + return X.DB; + return CartBR(A); +} + +static void M63Sync(void) { + uint16 mode = latche & 2; + uint16 prg_bank = (latche & 0x3F8) >> 1; + uint16 prg16 = (latche & 4) >> 1; + + openBus = ((latche & 0x300) == 0x300); + setprg8(0x8000, (prg_bank | (mode ? 0 : prg16 | 0))); + setprg8(0xA000, (prg_bank | (mode ? 1 : prg16 | 1))); + setprg8(0xC000, (prg_bank | (mode ? 2 : prg16 | 0))); + setprg8(0xE000, ((latche & 0x800) ? ((latche & 0x7C) | ((latche & 6) ? 3 : 1)) : + (prg_bank | (mode ? 3 : (prg16 | 1))))); + setchr8(0); + setmirror((latche & 1) ^ 1); +} + +void Mapper63_Init(CartInfo *info) { + Latch_Init(info, M63Sync, M63Read, 0x0000, 0x8000, 0xFFFF, 0); +} + /*------------------ Map 092 ---------------------------*/ /* Another two-in-one mapper, two Jaleco carts uses similar * hardware, but with different wiring. @@ -506,3 +541,36 @@ static void BMCG146Sync(void) { void BMCG146_Init(CartInfo *info) { Latch_Init(info, BMCG146Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0); } + +/*-------------- BMC-TJ-03 ------------------------*/ +/* NES 2.0 mapper 341 is used for a simple 4-in-1 multicart */ + +static void BMCTJ03Sync(void) { + uint8 mirr = ((latche >> 1) & 1) ^ 1; + uint8 bank = (latche >> 8) & 7; + + setprg32(0x8000, bank); + setchr8(bank); + + if (bank == 3) mirr ^= 1; /* Twin Bee has incorrect mirroring */ + setmirror(mirr); +} + +void BMCTJ03_Init(CartInfo *info) { + Latch_Init(info, BMCTJ03Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0); +} + +/*-------------- BMC-SA005-A ------------------------*/ +/* NES 2.0 mapper 338 is used for a 16-in-1 and a 200/300/600/1000-in-1 multicart. + * http://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_338 */ + +static void BMCSA005ASync(void) { + setprg16(0x8000, latche & 0x0F); + setprg16(0xC000, latche & 0x0F); + setchr8(latche & 0x0F); + setmirror((latche >> 3) & 1); +} + +void BMCSA005A_Init(CartInfo *info) { + Latch_Init(info, BMCSA005ASync, NULL, 0x0000, 0x8000, 0xFFFF, 0); +} diff --git a/src/boards/ax40g.c b/src/boards/ax40g.c new file mode 100644 index 0000000..b372574 --- /dev/null +++ b/src/boards/ax40g.c @@ -0,0 +1,90 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2019 Libretro Team + * + * 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 + */ + +/* NES 2.0 Mapper 527 is used for a bootleg version of + * Taito's 不動明王伝 (Fudō Myōō Den). + * Its UNIF board name is UNL-AX-40G. The original INES Mapper 207 is + * replaced with a VRC2 clone (A0/A1, i.e. VRC2b) while retaining + * Mapper 207's extended mirroring. + */ + +#include "mapinc.h" + +static uint8 preg[2], creg[8], NT[2]; + +static SFORMAT StateRegs[] = +{ + { preg, 2, "PREG" }, + { creg, 8, "CREG" }, + { NT, 2, "NMT" }, + { 0 } +}; + +static void Sync(void) { + uint8 i; + setprg8(0x8000, preg[0]); + setprg8(0xA000, preg[1]); + setprg8(0xC000, 0x1E); + setprg8(0xE000, 0x1F); + for (i = 0; i < 8; i++) + setchr1(i << 10, creg[i]); + setmirrorw(NT[0], NT[0], NT[1], NT[1]); +} + +static DECLFW(UNLAX40GWrite8) { + A &= 0xF003; + preg[0] = V & 0x1F; + Sync(); +} + +static DECLFW(UNLAX40GWriteA) { + A &= 0xF003; + preg[1] = V & 0x1F; + Sync(); +} + +static DECLFW(UNLAX40GWriteB) { + uint16 i, shift; + A &= 0xF003; + i = ((A >> 1) & 1) | ((A - 0xB000) >> 11); + shift = ((A & 1) << 2); + creg[i] = (creg[i] & (0xF0 >> shift)) | ((V & 0xF) << shift); + if (i < 2) + NT[i] = (creg[i] & 0x80) >> 7; + Sync(); +} + +static void UNLAX40GPower(void) { + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0x8FFF, UNLAX40GWrite8); + SetWriteHandler(0xA000, 0xAFFF, UNLAX40GWriteA); + SetWriteHandler(0xB000, 0xEFFF, UNLAX40GWriteB); +} + +static void StateRestore(int version) { + Sync(); +} + +void UNLAX40G_Init(CartInfo *info) { + info->Power = UNLAX40GPower; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/bj56.c b/src/boards/bj56.c new file mode 100644 index 0000000..a73a2ce --- /dev/null +++ b/src/boards/bj56.c @@ -0,0 +1,119 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2019 Libretro Team + * + * 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 + */ + +/* NES 2.0 Mapper 526 is used for a bootleg version of Namco's 三国志: 中原の覇者 (Sangokushi: Chūgen no Hasha). + * Its UNIF board name is UNL-BJ-56. + * Mirroring seems to be hard-wired (to vertical). + * https://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_526 + */ + +#include "mapinc.h" + +static uint8 preg[4], creg[8]; +static uint32 IRQCount; +static uint8 *WRAM = NULL; +static uint32 WRAMSIZE; + +static SFORMAT StateRegs[] = +{ + { preg, 4, "PREG" }, + { creg, 8, "CREG" }, + { &IRQCount, 4, "IRQC" }, + { 0 } +}; + +static void Sync(void) { + uint8 i; + setprg8r(0x10, 0x6000, 0); + setprg8(0x8000, preg[0]); + setprg8(0xA000, preg[1]); + setprg8(0xC000, preg[2]); + setprg8(0xE000, preg[3]); + for (i = 0; i < 8; i++) + setchr1((i << 10), creg[i]); + setmirror(MI_V); +} + +static DECLFW(UNLBJ56Write) { +/* FCEU_printf("Wr: A:%04x V:%02x\n", A, V); */ + A &= 0xF00F; + if (A <= 0x8007) { + creg[A & 0x07] = V; + Sync(); + } else if (A <= 0x800B) { + preg[A & 0x03] = V; + Sync(); + } else { + switch (A & 0x0F) { + case 0x0D: + case 0x0F: + /* One of these two acknowledges a pending IRQ, and the other + * resets to IRQ counter to zero. Because they are always written + * to one after the other, it's not clear which one does which. */ + X6502_IRQEnd(FCEU_IQEXT); + IRQCount = 0; + break; + } + } +} + +static void FP_FASTAPASS(1) UNLBJ56IRQHook(int a) { + IRQCount += a; + if (IRQCount & 4096) + X6502_IRQBegin(FCEU_IQEXT); +} + +static void UNLBJ56Close(void) { + if (WRAM) + FCEU_gfree(WRAM); + WRAM = NULL; +} + +static void UNLBJ56Power(void) { + preg[0] = ~3; + preg[1] = ~2; + preg[2] = ~1; + preg[3] = ~0; + Sync(); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + SetWriteHandler(0x8000, 0x800F, UNLBJ56Write); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); +} + +static void StateRestore(int version) { + Sync(); +} + +void UNLBJ56_Init(CartInfo *info) { + info->Power = UNLBJ56Power; + info->Close = UNLBJ56Close; + MapIRQHook = UNLBJ56IRQHook; + GameStateRestore = StateRestore; + WRAMSIZE = 8192; + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/bmc42in1r.c b/src/boards/bmc42in1r.c index 6f7a2b3..ce66030 100644 --- a/src/boards/bmc42in1r.c +++ b/src/boards/bmc42in1r.c @@ -3,6 +3,7 @@ * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 * Copyright (C) 2009 qeed + * Copyright (C) 2019 Libretro Team * * 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 @@ -22,10 +23,18 @@ * */ +/* Updated 2019-07-12 + * Mapper 266 - Updated and combine UNIF Ghostbusters63in1 board (1.5 MB carts), different bank order + * - some 1MB carts can switch game lists using Select + * Mapper 233 - UNIF 42in1ResetSwitch - reset-based switching + */ + #include "mapinc.h" +static uint8 reorder_banks = 0; static uint8 isresetbased = 0; static uint8 latche[2], reset; +static uint8 banks[4] = { 0, 0, 1, 2 }; static SFORMAT StateRegs[] = { { &reset, 1, "RST" }, @@ -34,11 +43,17 @@ static SFORMAT StateRegs[] = }; static void Sync(void) { - uint8 bank; + uint8 bank = 0; + uint8 base = ((latche[0] & 0x80) >> 7) | ((latche[1] & 1) << 1); + if (isresetbased) bank = (latche[0] & 0x1f) | (reset << 5) | ((latche[1] & 1) << 6); - else - bank = (latche[0] & 0x1f) | ((latche[0] & 0x80) >> 2) | ((latche[1] & 1) << 6); + else { + if (reorder_banks) /* for 1536 KB prg roms */ + base = banks[base]; + bank = (base << 5) | (latche[0] & 0x1f); + } + if (!(latche[0] & 0x20)) setprg32(0x8000, bank >> 1); else { @@ -65,19 +80,29 @@ static void StateRestore(int version) { Sync(); } +static void M226Reset(void) { + latche[0] = latche[1] = reset = 0; + Sync(); +} + void Mapper226_Init(CartInfo *info) { isresetbased = 0; + /* 1536KiB PRG roms have different bank order */ + reorder_banks = ((info->prgRom * 16) == 1536) ? 1 : 0; info->Power = M226Power; + info->Reset = M226Reset; AddExState(&StateRegs, ~0, 0, 0); GameStateRestore = StateRestore; } static void M233Reset(void) { + latche[0] = latche[1] = 0; reset ^= 1; Sync(); } void Mapper233_Init(CartInfo *info) { + reorder_banks = 0; isresetbased = 1; info->Power = M226Power; info->Reset = M233Reset; diff --git a/src/boards/bmc60311c.c b/src/boards/bmc60311c.c new file mode 100644 index 0000000..03eaf11 --- /dev/null +++ b/src/boards/bmc60311c.c @@ -0,0 +1,110 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright (C) 2019 Libretro Team + * + * 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 + */ + +/* added 2019-5-23 + * UNIF: BMC-60311C: + * https://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_289 + */ + +#include "mapinc.h" + +static uint8 inner_bank, outer_bank, mode; + +static SFORMAT StateRegs[] = +{ + { &inner_bank, 1, "INB0" }, + { &outer_bank, 1, "OUTB" }, + { &mode, 1, "MODE" }, + { 0 } +}; + +static void Sync(void) { + uint8 bbank = (mode & 4) ? 0 : (inner_bank & 7); + uint8 bank = outer_bank | bbank; + uint8 preg[2]; + + /* 0: NROM-128: Same inner/outer 16 KiB bank at CPU $8000-$BFFF + * and $C000-$FFFF + * 1: NROM-256: 32 kiB bank at CPU $8000-$FFFF (Selected inner/outer bank SHR 1) + * 2: UNROM: Inner/outer bank at CPU $8000-BFFF, + * fixed inner bank 7 within outer bank at $C000-$FFFF + * 3: Unknown + * + * The combined inner/outer bank is simply the inner bank, selected by the + * latch at $8000-$FFFF (or 0 if the latch is disabled) ORed with the + * outer bank selected by $6001, without any bit shifting. + */ + + preg[0] = bank; + switch (mode & 3) { + case 0x00: + case 0x01: + preg[1] = bank | ((mode & 1) ? 1 : 0); + break; + case 0x02: + preg[1] = outer_bank | 7; + case 0x03: + break; + } + + setchr8(0); + setprg16(0x8000, preg[0]); + setprg16(0xC000, preg[1]); + setmirror(((mode & 8) >> 3) ^ 1); +} + +static DECLFW(Write0) { + mode = V; + Sync(); +} + +static DECLFW(Write1) { + outer_bank = V; + Sync(); +} + +static DECLFW(Write8) { + inner_bank = V; + Sync(); +} + +static void BMC60311CPower(void) { + inner_bank = outer_bank = mode = 0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x6000, Write0); + SetWriteHandler(0x6001, 0x6001, Write1); + SetWriteHandler(0x8000, 0xFFFF, Write8); +} + +static void BMC60311CReset(void) { + inner_bank = outer_bank = mode = 0; + Sync(); +} + +static void BMC60311CRestore(int version) { + Sync(); +} + +void BMC60311C_Init(CartInfo *info) { + info->Power = BMC60311CPower; + info->Reset = BMC60311CReset; + GameStateRestore = BMC60311CRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/bmc80013b.c b/src/boards/bmc80013b.c new file mode 100644 index 0000000..2966bde --- /dev/null +++ b/src/boards/bmc80013b.c @@ -0,0 +1,77 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright (C) 2019 Libretro Team + * + * 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 + */ + +/* NES 2.0 Mapper 274 is used for the 90-in-1 Hwang Shinwei multicart. + * Its UNIF board name is BMC-80013-B. + * https://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_274 */ + +#include "mapinc.h" + +static uint8 regs[2], mode; + +static SFORMAT StateRegs[] = +{ + { ®s[0], 1, "REG0" }, + { ®s[1], 1, "REG1" }, + { &mode, 1, "MODE" }, + { 0 } +}; + +static void Sync(void) { + if (mode & 0x02) + setprg16(0x8000, (regs[0] & 0x0F) | (regs[1] & 0x70)); + else + setprg16(0x8000, (regs[0] & 0x0F) | 0x80); + setprg16(0xC000, regs[1]); + setmirror(((regs[0] >> 4) & 1) ^ 1); +} + +static DECLFW(BMC80013BWrite) { + uint8 reg = (A >> 13) & 0x03; + if (!reg) + regs[0] = V & 0x1F; + else { + regs[1] = V & 0x7F; + mode = reg; + } + Sync(); +} + +static void BMC80013BPower(void) { + Sync(); + setchr8(0); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, BMC80013BWrite); +} + +static void BMC80013BReset(void) { + regs[0] = regs[1] = mode = 0; + Sync(); +} + +static void BMC80013BRestore(int version) { + Sync(); +} + +void BMC80013B_Init(CartInfo *info) { + info->Power = BMC80013BPower; + info->Reset = BMC80013BReset; + GameStateRestore = BMC80013BRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/bmc830425C4391t.c b/src/boards/bmc830425C4391t.c new file mode 100644 index 0000000..108425a --- /dev/null +++ b/src/boards/bmc830425C4391t.c @@ -0,0 +1,80 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright (C) 2019 Libretro Team + * + * 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 + * + */ + +/* NES 2.0 Mapper 320 is used for the Super HiK 6-in-1 A-030 multicart. + * Basically UxROM with an address-latch-based outer bank register. + * UNIF board name is BMC-830425C-4391T. Mirroring is hard-wired. + * http://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_320 + */ + +#include "mapinc.h" + +static uint8 bank_size; +static uint8 inner_bank; +static uint8 outer_bank; + +static SFORMAT StateRegs[] = +{ + { &inner_bank, 1, "INNB" }, + { &outer_bank, 1, "OUTB" }, + { &bank_size, 1, "SIZE" }, + { 0 } +}; + +static void Sync(void) { + setprg16(0x8000, (outer_bank << 3) | (inner_bank & bank_size)); + setprg16(0xC000, (outer_bank << 3) | bank_size); + setchr8(0); +} + +static DECLFW(M320Write) { + /* address mask is inconsistent with that is in the wiki. Mask should be + * 0xFFE0 or Mermaid game will not work. */ + if ((A & 0xFFE0) == 0xF0E0) { + outer_bank = (A & 0x0F); + bank_size = (A & 0x10) ? 0x07 : 0x0F; + } + inner_bank = (V & 0x0F); + Sync(); +} + +static void M320Power(void) { + bank_size = 0x0F; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M320Write); +} + +static void M320Reset(void) { + inner_bank = outer_bank = 0; + bank_size = 0x0F; + Sync(); +} + +static void StateRestore(int version) { + Sync(); +} + +void BMC830425C4391T_Init(CartInfo *info) { + info->Power = M320Power; + info->Reset = M320Reset; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/bmcctc09.c b/src/boards/bmcctc09.c new file mode 100644 index 0000000..8651ad9 --- /dev/null +++ b/src/boards/bmcctc09.c @@ -0,0 +1,74 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright (C) 2019 Libretro Team + * + * 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 + * + */ + +/* NES 2.0 mapper 335 is used for a 10-in-1 multicart. + * Its UNIF board name is BMC-CTC-09. + * http://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_335 */ + +#include "mapinc.h" + +#define PRG 0 +#define CHR 1 + +static uint8 regs[2]; + +static SFORMAT StateRegs[] = +{ + { regs, 2, "REGS" }, + { 0 } +}; + +static void Sync(void) { + if (regs[PRG] & 0x10) { + setprg16(0x8000, ((regs[PRG] & 0x07) << 1) | ((regs[PRG] >> 3) & 1)); + setprg16(0xC000, ((regs[PRG] & 0x07) << 1) | ((regs[PRG] >> 3) & 1)); + } else + setprg32(0x8000, regs[PRG] & 0x07); + + setchr8(regs[CHR] & 0x0F); + setmirror(((regs[PRG] >> 5) & 1) ^ 1); +} + +static DECLFW(WritePRG) { + regs[PRG] = V; + Sync(); +} + +static DECLFW(WriteCHR) { + regs[CHR] = V; + Sync(); +} + +static void BMCCTC09Power(void) { + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xBFFF, WriteCHR); + SetWriteHandler(0xC000, 0xFFFF, WritePRG); +} + +static void StateRestore(int version) { + Sync(); +} + +void BMCCTC09_Init(CartInfo *info) { + info->Power = BMCCTC09Power; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/bmcgamecard.c b/src/boards/bmcgamecard.c new file mode 100644 index 0000000..aab0e4c --- /dev/null +++ b/src/boards/bmcgamecard.c @@ -0,0 +1,95 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2019 Libretro Team + * + * 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 + */ + +/* NES 2.0 Mapper 337 - BMC-CTC-12IN1 + * 12-in-1 Game Card multicart + * https://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_337 + + * NES 2.0 Mapper 350 - BMC-891227 + * Super 15-in-1 Game Card + * https://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_350 + */ + +#include "mapinc.h" + +static uint8 latche, m350; + +static SFORMAT StateRegs[] = +{ + { &latche, 1, "LATC" }, + { &m350, 1, "M350" }, + { 0 } +}; + +static void Sync(void) { + uint8 mirroring = m350 ? ((latche >> 7) & 1) : ((latche >> 5) & 1); + uint8 mode = m350 ? ((latche >> 5) & 0x03) : ((latche >> 6) & 0x03); + uint8 base = m350 ? ((latche & 0x40) ? (latche & 0x20) : 0) : 0; + + setchr8(0); + setprg8(0x6000, 1); + setprg16r(0, 0x8000, base | (latche & 0x1F)); + setprg16r(0, 0xC000, base | ((latche & 0x1F) | ((mode & 2) ? 0x07 : (mode & 1)))); + setmirror(mirroring ^ 1); +} + +static DECLFW(BMCCTC12IN1Write8) { + latche = (latche & 7) | (V & ~7); + Sync(); +} + +static DECLFW(BMCCTC12IN1WriteC) { + latche = (latche & ~7) | (V & 7); + Sync(); +} + +static void BMCCTC12IN1Power(void) { + Sync(); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xBFFF, BMCCTC12IN1Write8); + SetWriteHandler(0xC000, 0xFFFF, BMCCTC12IN1WriteC); +} + +static void BMCCTC12IN1Reset(void) { + latche = 0; + Sync(); +} + +static void StateRestore(int version) { + Sync(); +} + +/* Mapper 337 - BMC-CTC-12IN1 */ +void BMCCTC12IN1_Init(CartInfo *info) { + m350 = 0; + info->Power = BMCCTC12IN1Power; + info->Reset = BMCCTC12IN1Reset; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} + +/* Mapper 350 - BMC-891227 */ +void BMC891227_Init(CartInfo *info) { + m350 = 1; + info->Power = BMCCTC12IN1Power; + info->Reset = BMCCTC12IN1Reset; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/bmck3006.c b/src/boards/bmck3006.c new file mode 100644 index 0000000..ab3e539 --- /dev/null +++ b/src/boards/bmck3006.c @@ -0,0 +1,70 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright (C) 2019 Libretro Team + * + * 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 + * + */ + +/* NES 2.0 mapper 339 is used for a 21-in-1 multicart. + * Its UNIF board name is BMC-K-3006. + * http://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_339 + */ + +#include "mapinc.h" +#include "mmc3.h" + +static void BMCK3006CW(uint32 A, uint8 V) { + setchr1(A, (V & 0x7F) | (EXPREGS[0] & 0x18) << 4); +} + +static void BMCK3006PW(uint32 A, uint8 V) { + if (EXPREGS[0] & 0x20) { /* MMC3 mode */ + setprg8(A, (V & 0x0F) | (EXPREGS[0] & 0x18) << 1); + } else { + if ((EXPREGS[0] & 0x07) == 0x06) { /* NROM-256 */ + setprg32(0x8000, (EXPREGS[0] >> 1) & 0x0F); + } else { /* NROM-128 */ + setprg16(0x8000, EXPREGS[0] & 0x1F); + setprg16(0xC000, EXPREGS[0] & 0x1F); + } + } +} + +static DECLFW(BMCK3006Write) { + EXPREGS[0] = A & 0x3F; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static void BMCK3006Reset(void) { + EXPREGS[0] = 0; + MMC3RegReset(); +} + +static void BMCK3006Power(void) { + EXPREGS[0] = 0; + GenMMC3Power(); + SetWriteHandler(0x6000, 0x7FFF, BMCK3006Write); +} + +void BMCK3006_Init(CartInfo *info) { + GenMMC3_Init(info, 512, 512, 8, 0); + pwrap = BMCK3006PW; + cwrap = BMCK3006CW; + info->Power = BMCK3006Power; + info->Reset = BMCK3006Reset; + AddExState(EXPREGS, 1, 0, "EXPR"); +} diff --git a/src/boards/bmck3033.c b/src/boards/bmck3033.c new file mode 100644 index 0000000..686d278 --- /dev/null +++ b/src/boards/bmck3033.c @@ -0,0 +1,93 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2019 Libretro Team + * + * 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 + */ + +/* NES 2.0 Mapper 322 + * BMC-K-3033 + * 35-in-1 (K-3033) + * http://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_322 + */ + +#include "mapinc.h" +#include "mmc3.h" + +static void BMCK3033CW(uint32 A, uint8 V) { + if (EXPREGS[2]) { + if (EXPREGS[3]) { +/* FCEU_printf("MMC3-256: A:%04x V:%02x R1:%02x\n", A, V, EXPREGS[1]); */ + setchr1(A, (EXPREGS[1] << 8) | (V & 0xFF)); + } else { +/* FCEU_printf("MMC3-128: A:%04x V:%02x R1:%02x\n", A, V, EXPREGS[1]); */ + setchr1(A, (EXPREGS[1] << 7) | (V & 0x7F)); + } + } else { +/* FCEU_printf("NROM: A:%04x V:%02x R1:%02x\n", A, V, EXPREGS[1]); */ + setchr1(A, (V & 0x7F)); + } +} + +static void BMCK3033PW(uint32 A, uint8 V) { + if (EXPREGS[2]) { + if (EXPREGS[3] ) { +/* FCEU_printf("MMC3-256 A:%04x V:%02x chip:%02x\n", A, V, EXPREGS[1] & ~0x01); */ + setprg8(A, (EXPREGS[1] << 5) | (V & 0x1F)); + } else { +/* FCEU_printf("MMC3-128 A:%04x V:%02x chip:%02x\n", A, V, EXPREGS[1]); */ + setprg8(A, (EXPREGS[1] << 4) | (V & 0x0F)); + } + } else { + uint32 base = (EXPREGS[1] << 3); + if (EXPREGS[0] & 0x03) { +/* FCEU_printf("NROM-256 base:%02x chip:%02x\n", EXPREGS[0] >> 1, EXPREGS[1]); */ + setprg32(0x8000, base | EXPREGS[0] >> 1); + } else { +/* FCEU_printf("NROM-128 base:%02x chip:%02x\n", EXPREGS[0], EXPREGS[1]); */ + setprg16(0x8000, base | EXPREGS[0]); + setprg16(0xC000, base | EXPREGS[0]); + } + } +} + +static DECLFW(BMCK3033Write) { + EXPREGS[0] = (A & 0x07); + EXPREGS[1] = ((A & 0x18) >> 3) | ((A & 0x40) >> 4); + EXPREGS[2] = (A & 0x20); + EXPREGS[3] = (A & 0x80); + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static void BMCK3033Power(void) { + GenMMC3Power(); + SetWriteHandler(0x6000, 0x7FFF, BMCK3033Write); +} + +static void BMCK3033Reset(void) { + EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; + MMC3RegReset(); +} + +void BMCK3033_Init(CartInfo *info) { + GenMMC3_Init(info, 256, 256, 1, 0); + pwrap = BMCK3033PW; + cwrap = BMCK3033CW; + info->Power = BMCK3033Power; + info->Reset = BMCK3033Reset; + AddExState(EXPREGS, 4, 0, "EXPR"); +} diff --git a/src/boards/bmck3036.c b/src/boards/bmck3036.c new file mode 100644 index 0000000..bd72ca3 --- /dev/null +++ b/src/boards/bmck3036.c @@ -0,0 +1,79 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright (C) 2019 Libretro Team + * + * 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 + * + */ + +/* NES 2.0 mapper 340 is used for a 35-in-1 multicart. + * Its UNIF board name is BMC-K-3036. + * http://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_340 + * TODO: Some games are not working... + */ + +#include "mapinc.h" + +static uint8 regs[2], mirr, mode; + +static SFORMAT StateRegs[] = +{ + { regs, 2, "REGS" }, + { &mode, 1, "MODE" }, + { &mirr, 1, "MIRR" }, + { 0 } +}; + +static void Sync(void) { + if (mode) { /* NROM-128 */ + setprg16(0x8000, regs[0]); + setprg16(0xC000, regs[0]); + } else { /* UNROM */ + setprg16(0x8000, regs[0] | regs[1]); + setprg16(0xC000, regs[0] | 0x07); + } + setchr8(0); + setmirror(mirr); +} + +static DECLFW(M340Write) { + regs[0] = A & 0x1F; + regs[1] = V & 0x07; + mode = A & 0x20; + mirr = ((A & 0x25) == 0x25) ? 0 : 1; + Sync(); +} + +static void BMCK3036Power(void) { + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M340Write); +} + +static void BMCK3036Reset(void) { + regs[0] = regs[1] = mode = mirr = 0; + Sync(); +} + +static void StateRestore(int version) { + Sync(); +} + +void BMCK3036_Init(CartInfo *info) { + info->Power = BMCK3036Power; + info->Reset = BMCK3036Reset; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/bmcl6in1.c b/src/boards/bmcl6in1.c new file mode 100644 index 0000000..f788537 --- /dev/null +++ b/src/boards/bmcl6in1.c @@ -0,0 +1,74 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2019 Libretro Team + * + * 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 + */ + +/* NES 2.0 Mapper 345 + * BMC-L6IN1 + * New Star 6-in-1 Game Cartridge + * https://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_345 + */ + +#include "mapinc.h" +#include "mmc3.h" + +static void BMCL6IN1CW(uint32 A, uint8 V) { + setchr8(V); +} + +static void BMCL6IN1PW(uint32 A, uint8 V) { + if (EXPREGS[0] & 0x0C) + setprg8(A, (V & 0x0F) | (EXPREGS[0] & 0xC0) >> 2); + else + setprg32(0x8000, ((EXPREGS[0] & 0xC0) >> 4) | (EXPREGS[0] & 0x03)); +} + +static void BMCL6IN1MW(uint8 V) { + if (EXPREGS[0] & 0x20) + setmirror(MI_0 + ((EXPREGS[0] & 0x10) >> 1)); + else { + A000B = V; + setmirror((V & 1) ^ 1); + } +} + +static DECLFW(BMCL6IN1Write) { + EXPREGS[0] = V; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static void BMCL6IN1Reset(void) { + EXPREGS[0] = 0; + MMC3RegReset(); +} + +static void BMCL6IN1Power(void) { + GenMMC3Power(); + SetWriteHandler(0x6000, 0x7FFF, BMCL6IN1Write); +} + +void BMCL6IN1_Init(CartInfo *info) { + GenMMC3_Init(info, 512, 0, 1, 0); + pwrap = BMCL6IN1PW; + cwrap = BMCL6IN1CW; + mwrap = BMCL6IN1MW; + info->Power = BMCL6IN1Power; + info->Reset = BMCL6IN1Reset; + AddExState(EXPREGS, 1, 0, "EXPR"); +} diff --git a/src/boards/coolboy.c b/src/boards/coolboy.c index b0f8649..5482550 100644 --- a/src/boards/coolboy.c +++ b/src/boards/coolboy.c @@ -42,7 +42,7 @@ static void COOLBOYCW(uint32 A, uint8 V) { } } /* Highest bit goes from MMC3 registers when EXPREGS[3]&0x80==0 or from EXPREGS[0]&0x08 otherwise */ - setchr1(A, + setchr1(A, (V & 0x80 & mask) | ((((EXPREGS[0] & 0x08) << 4) & ~mask)) /* 7th bit */ | ((EXPREGS[2] & 0x0F) << 3) /* 6-3 bits */ | ((A >> 10) & 7) /* 2-0 bits */ @@ -107,7 +107,7 @@ static DECLFW(COOLBOYWrite) { CartBW(A,V); /* Deny any further writes when 7th bit is 1 AND 4th is 0 */ - if ((EXPREGS[3] & 0x90) != 0x80) { + if ((EXPREGS[3] & 0x90) != 0x80) { EXPREGS[A & 3] = V; FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); @@ -150,3 +150,27 @@ void COOLBOY_Init(CartInfo *info) { info->Reset = COOLBOYReset; AddExState(EXPREGS, 4, 0, "EXPR"); } + +/*------------------ MINDKIDS ---------------------------*/ +/* A COOLBOY variant that works identically but puts the outer bank registers + * in the $5xxx range instead of the $6xxx range. + * The UNIF board name is MINDKIDS (submapper 1). + * http://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_268 + */ + +static void MINDKIDSPower(void) { + GenMMC3Power(); + EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + SetWriteHandler(0x5000, 0x5fff, COOLBOYWrite); +} + +void MINDKIDS_Init(CartInfo *info) { + GenMMC3_Init(info, 2048, 256, 8, info->battery); + pwrap = COOLBOYPW; + cwrap = COOLBOYCW; + info->Power = MINDKIDSPower; + info->Reset = COOLBOYReset; + AddExState(EXPREGS, 4, 0, "EXPR"); +} diff --git a/src/boards/datalatch.c b/src/boards/datalatch.c index 3ed37be..c221310 100644 --- a/src/boards/datalatch.c +++ b/src/boards/datalatch.c @@ -94,7 +94,7 @@ static DECLFW(NROMWrite) { static void NROMPower(void) { setprg8r(0x10, 0x6000, 0); /* Famili BASIC (v3.0) need it (uses only 4KB), FP-BASIC uses 8KB */ setprg16(0x8000, 0); - setprg16(0xC000, ~0); + setprg16(0xC000, 1); setchr8(0); SetReadHandler(0x6000, 0x7FFF, CartBR); @@ -153,24 +153,29 @@ static void CNROMSync(void) { } void CNROM_Init(CartInfo *info) { + unsigned _no_busc, _busc; + + _busc = 1; /* by default, CNROM is set to emulate bus conflicts to all games */ + _no_busc = 0; + + if (GameInfo->cspecial == 1) + _no_busc = 1; + /* TODO: move these to extended database when implemented. */ - int _busc, x; - uint64 partialmd5 = 0; - _busc = 1; - for (x = 0; x < 8; x++) - partialmd5 |= (uint64)info->MD5[15 - x] << (x * 8); - if (partialmd5 == 0x117181328eb1ad23LL) /* 75 Bingo (Sachen-English) [U].unf */ - _busc = 0; - else - switch (info->CRC32) { - case 0xf283cf58: /* Colorful Dragon (Asia) (PAL) (Unl).nes */ - case 0x2915faf0: /* Incantation (Asia) (Unl).nes */ - case 0xebd0644d: /* Dao Shuai (Asia) (Unl).nes */ - case 0x8f154a0d: /* Pu Ke Jing Ling (China) (Unl).nes */ - case 0xd04a40e6: /* Bingo 75 (Asia) (Unl).nes */ - _busc = 0; - break; + switch (info->CRC32) { + case 0xf283cf58: /* Colorful Dragon (Asia) (PAL) (Unl).nes */ + case 0x2915faf0: /* Incantation (Asia) (Unl).nes */ + case 0xebd0644d: /* Dao Shuai (Asia) (Unl).nes */ + case 0x8f154a0d: /* Pu Ke Jing Ling (China) (Unl).nes */ + case 0xd04a40e6: /* Bingo 75 (Asia) (Unl).nes */ + case 0xe41b440f: /* Sidewinder (Joy Van) */ + case 0xb0c871c5: /* Wei Lai Xiao Zi (Joy Van) */ + case 0xb3be2f71: /* Yanshan Chess (Unl) */ + _no_busc = 1; + break; } + + if (_no_busc == 1) _busc = 0; Latch_Init(info, CNROMSync, 0, 0x8000, 0xFFFF, 1, _busc); } @@ -225,6 +230,22 @@ void CPROM_Init(CartInfo *info) { Latch_Init(info, CPROMSync, 0, 0x8000, 0xFFFF, 0, 0); } +/*------------------ Map 29 ---------------------------*/ +/* added 2019-5-23 + * Mapper 28, used by homebrew game Glider + * https://wiki.nesdev.com/w/index.php/INES_Mapper_029 */ + +static void M29Sync(void) { + setprg16(0x8000, (latche >> 2) & 7); + setprg16(0xc000, ~0); + setchr8r(0, latche & 3); + setprg8r(0x10, 0x6000, 0); +} + +void Mapper29_Init(CartInfo *info) { + Latch_Init(info, M29Sync, 0x0000, 0x6000, 0xFFFF, 1, 0); +} + /*------------------ Map 38 ---------------------------*/ static void M38Sync(void) { @@ -476,22 +497,32 @@ void Mapper241_Init(CartInfo *info) { * 16 bankswitching mode and normal mirroring... But there is no any * correlations between modes and they can be used in one mapper code. */ - +static int A65ASsubmapper; static void BMCA65ASSync(void) { if (latche & 0x40) setprg32(0x8000, (latche >> 1) & 0x0F); else { - setprg16(0x8000, ((latche & 0x30) >> 1) | (latche & 7)); - setprg16(0xC000, ((latche & 0x30) >> 1) | 7); + if (A65ASsubmapper == 1) { + setprg16(0x8000, ((latche & 0x38) >> 0) | (latche & 7)); + setprg16(0xC000, ((latche & 0x38) >> 0) | 7); + } else { + setprg16(0x8000, ((latche & 0x30) >> 1) | (latche & 7)); + setprg16(0xC000, ((latche & 0x30) >> 1) | 7); + } } setchr8(0); if (latche & 0x80) setmirror(MI_0 + (((latche >> 5) & 1))); - else - setmirror(((latche >> 3) & 1) ^ 1); + else { + if (A65ASsubmapper == 1) /* added as workaround since games for this cart uses vertical mirroring */ + setmirror(MI_V); + else + setmirror(((latche >> 3) & 1) ^ 1); + } } void BMCA65AS_Init(CartInfo *info) { + A65ASsubmapper = info->submapper; /* not a real submapper */ Latch_Init(info, BMCA65ASSync, 0, 0x8000, 0xFFFF, 0, 0); } @@ -508,3 +539,17 @@ static void BMC11160Sync(void) { void BMC11160_Init(CartInfo *info) { Latch_Init(info, BMC11160Sync, 0, 0x8000, 0xFFFF, 0, 0); } + +/*------------------ BMC-K-3046 ---------------------------*/ +/* NES 2.0 mapper 336 is used for an 11-in-1 multicart + * http://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_336 */ + +static void BMCK3046Sync(void) { + setprg16(0x8000, latche); + setprg16(0xC000, latche | 0x07); + setchr8(0); +} + +void BMCK3046_Init(CartInfo *info) { + Latch_Init(info, BMCK3046Sync, 0, 0x8000, 0xFFFF, 0, 0); +} diff --git a/src/boards/eh8813a.c b/src/boards/eh8813a.c index ab15b39..d8998a3 100644 --- a/src/boards/eh8813a.c +++ b/src/boards/eh8813a.c @@ -18,36 +18,40 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + /* Updated 6-27-19 */ + #include "mapinc.h" -static uint16 addrlatch; -static uint8 datalatch, hw_mode; +static uint8 datalatch, addrlatch, lock, hw_mode; static SFORMAT StateRegs[] = { - { &addrlatch, 2, "ADRL" }, + { &addrlatch, 1, "ADRL" }, { &datalatch, 1, "DATL" }, - { &hw_mode, 1, "HWMO" }, + { &hw_mode, 1, "HWMO" }, + { &lock, 1, "LOCK" }, { 0 } }; static void Sync(void) { - uint8 prg = (addrlatch & 7); + uint8 prg = (addrlatch & 0x3F); setchr8(datalatch); - if(addrlatch & 0x80) { + if (addrlatch & 0x80) { setprg16(0x8000,prg); setprg16(0xC000,prg); } else { setprg32(0x8000,prg >> 1); } - setmirror(MI_V); + setmirror(((datalatch >> 7) & 1) ^ 1); } static DECLFW(EH8813AWrite) { - if((addrlatch & 0x100) == 0) { - addrlatch = A & 0x1FF; - datalatch = V & 0xF; + if (lock == 0) { + addrlatch = A & 0xFF; + datalatch = V & 0xFC; + lock = (A & 0x100) >> 8; } + datalatch = (datalatch & ~0x03) | (V & 0x03); Sync(); } @@ -56,16 +60,16 @@ static DECLFR(EH8813ARead) { A= (A & 0xFFF0) + hw_mode; return CartBR(A); } - + static void EH8813APower(void) { - addrlatch = datalatch = hw_mode = 0; + addrlatch = datalatch = hw_mode = lock = 0; Sync(); SetReadHandler(0x8000, 0xFFFF, EH8813ARead); SetWriteHandler(0x8000, 0xFFFF, EH8813AWrite); } static void EH8813AReset(void) { - addrlatch = datalatch = 0; + addrlatch = datalatch = lock = 0; hw_mode = (hw_mode + 1) & 0xF; FCEU_printf("Hardware Switch is %01X\n", hw_mode); Sync(); diff --git a/src/boards/emu2413.c b/src/boards/emu2413.c index 5350695..a9fabb3 100644 --- a/src/boards/emu2413.c +++ b/src/boards/emu2413.c @@ -49,22 +49,23 @@ #include "emu2413.h" static const unsigned char default_inst[15][8] = { - /* VRC7 instruments, January 17, 2004 update -Xodnizel */ - { 0x03, 0x21, 0x04, 0x06, 0x8D, 0xF2, 0x42, 0x17 }, - { 0x13, 0x41, 0x05, 0x0E, 0x99, 0x96, 0x63, 0x12 }, - { 0x31, 0x11, 0x10, 0x0A, 0xF0, 0x9C, 0x32, 0x02 }, - { 0x21, 0x61, 0x1D, 0x07, 0x9F, 0x64, 0x20, 0x27 }, - { 0x22, 0x21, 0x1E, 0x06, 0xF0, 0x76, 0x08, 0x28 }, - { 0x02, 0x01, 0x06, 0x00, 0xF0, 0xF2, 0x03, 0x95 }, - { 0x21, 0x61, 0x1C, 0x07, 0x82, 0x81, 0x16, 0x07 }, - { 0x23, 0x21, 0x1A, 0x17, 0xEF, 0x82, 0x25, 0x15 }, - { 0x25, 0x11, 0x1F, 0x00, 0x86, 0x41, 0x20, 0x11 }, - { 0x85, 0x01, 0x1F, 0x0F, 0xE4, 0xA2, 0x11, 0x12 }, - { 0x07, 0xC1, 0x2B, 0x45, 0xB4, 0xF1, 0x24, 0xF4 }, - { 0x61, 0x23, 0x11, 0x06, 0x96, 0x96, 0x13, 0x16 }, - { 0x01, 0x02, 0xD3, 0x05, 0x82, 0xA2, 0x31, 0x51 }, - { 0x61, 0x22, 0x0D, 0x02, 0xC3, 0x7F, 0x24, 0x05 }, - { 0x21, 0x62, 0x0E, 0x00, 0xA1, 0xA0, 0x44, 0x17 }, + /* 2019-03-19 VRC7 instrument patchset dumped by Nuke.YKT */ + /* https://wiki.nesdev.com/w/index.php/VRC7_audio */ + { 0x03, 0x21, 0x05, 0x06, 0xE8, 0x81, 0x42, 0x27 }, + { 0x13, 0x41, 0x14, 0x0D, 0xD8, 0xF6, 0x23, 0x12 }, + { 0x11, 0x11, 0x08, 0x08, 0xFA, 0xB2, 0x20, 0x12 }, + { 0x31, 0x61, 0x0C, 0x07, 0xA8, 0x64, 0x61, 0x27 }, + { 0x32, 0x21, 0x1E, 0x06, 0xE1, 0x76, 0x01, 0x28 }, + { 0x02, 0x01, 0x06, 0x00, 0xA3, 0xE2, 0xF4, 0xF4 }, + { 0x21, 0x61, 0x1D, 0x07, 0x82, 0x81, 0x11, 0x07 }, + { 0x23, 0x21, 0x22, 0x17, 0xA2, 0x72, 0x01, 0x17 }, + { 0x35, 0x11, 0x25, 0x00, 0x40, 0x73, 0x72, 0x01 }, + { 0xB5, 0x01, 0x0F, 0x0F, 0xA8, 0xA5, 0x51, 0x02 }, + { 0x17, 0xC1, 0x24, 0x07, 0xF8, 0xF8, 0x22, 0x12 }, + { 0x71, 0x23, 0x11, 0x06, 0x65, 0x74, 0x18, 0x16 }, + { 0x01, 0x02, 0xD3, 0x05, 0xC9, 0x95, 0x03, 0x02 }, + { 0x61, 0x63, 0x0C, 0x00, 0x94, 0xC0, 0x33, 0xF6 }, + { 0x21, 0x72, 0x0D, 0x00, 0xC1, 0xD5, 0x56, 0x06 } }; /* Size of Sintable ( 8 -- 18 can be used. 9 recommended.)*/ diff --git a/src/boards/faridunrom.c b/src/boards/faridunrom.c new file mode 100644 index 0000000..219b8d7 --- /dev/null +++ b/src/boards/faridunrom.c @@ -0,0 +1,70 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2019 Libretro Team + * + * 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 + */ + +/* NES 2.0 Mapper 324 + * FARID_UNROM_8-IN-1 + * https://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_324 + */ + +#include "mapinc.h" + +static uint8 latch; + +static SFORMAT StateRegs[] = +{ + { &latch, 1, "LATC" }, + { 0 } +}; + +static void Sync(void) { + setchr8(0); + setprg16(0x8000, ((latch & 0x70) >> 1) | (latch & 0x07)); + setprg16(0xC000, ((latch & 0x70) >> 1) | 0x07 ); +} + +static DECLFW(FARIDUNROMWrite) { + V &= CartBR(A); + if ((V & 0x80) && !(latch & 0x80) && !(latch & 0x08)) + latch = (latch & 0x87) | (V & 0x78); + latch = (latch & 0x78) | (V & 0x87); + Sync(); +} + +static void FARIDUNROMPower(void) { + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, FARIDUNROMWrite); +} + +static void FARIDUNROMReset(void) { + latch &= ~0x78; + Sync(); +} + +static void StateRestore(int version) { + Sync(); +} + +void FARIDUNROM_Init(CartInfo *info) { + info->Power = FARIDUNROMPower; + info->Reset = FARIDUNROMReset; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/ghostbusters63in1.c b/src/boards/ghostbusters63in1.c deleted file mode 100644 index 2ca6ee1..0000000 --- a/src/boards/ghostbusters63in1.c +++ /dev/null @@ -1,96 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2007 CaH4e3 - * - * 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 - * 63in1 ghostbusters - */ - -#include "mapinc.h" - -static uint8 reg[2], bank; -static uint8 banks[4] = { 0, 0, 1, 2 }; -static uint8 *CHRROM = NULL; -static uint32 CHRROMSIZE; - -static SFORMAT StateRegs[] = -{ - { reg, 2, "REGS" }, - { &bank, 1, "BANK" }, - { 0 } -}; - -static void Sync(void) { - if (reg[0] & 0x20) { - setprg16r(banks[bank], 0x8000, reg[0] & 0x1F); - setprg16r(banks[bank], 0xC000, reg[0] & 0x1F); - } else - setprg32r(banks[bank], 0x8000, (reg[0] >> 1) & 0x0F); - if (reg[1] & 2) - setchr8r(0x10, 0); - else - setchr8(0); - setmirror((reg[0] & 0x40) >> 6); -} - -static DECLFW(BMCGhostbusters63in1Write) { - reg[A & 1] = V; - bank = ((reg[0] & 0x80) >> 7) | ((reg[1] & 1) << 1); -/* FCEU_printf("reg[0]=%02x, reg[1]=%02x, bank=%02x\n",reg[0],reg[1],bank); */ - Sync(); -} - -static DECLFR(BMCGhostbusters63in1Read) { - if (bank == 1) - return X.DB; - else - return CartBR(A); -} - -static void BMCGhostbusters63in1Power(void) { - reg[0] = reg[1] = 0; - Sync(); - SetReadHandler(0x8000, 0xFFFF, BMCGhostbusters63in1Read); - SetWriteHandler(0x8000, 0xFFFF, BMCGhostbusters63in1Write); -} - -static void BMCGhostbusters63in1Reset(void) { - reg[0] = reg[1] = 0; -} - -static void StateRestore(int version) { - Sync(); -} - -static void BMCGhostbusters63in1Close(void) { - if (CHRROM) - FCEU_gfree(CHRROM); - CHRROM = NULL; -} - -void BMCGhostbusters63in1_Init(CartInfo *info) { - info->Reset = BMCGhostbusters63in1Reset; - info->Power = BMCGhostbusters63in1Power; - info->Close = BMCGhostbusters63in1Close; - - CHRROMSIZE = 8192; /* dummy CHRROM, VRAM disable */ - CHRROM = (uint8*)FCEU_gmalloc(CHRROMSIZE); - SetupCartPRGMapping(0x10, CHRROM, CHRROMSIZE, 0); - AddExState(CHRROM, CHRROMSIZE, 0, "CROM"); - - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/gn26.c b/src/boards/gn26.c new file mode 100644 index 0000000..0af480b --- /dev/null +++ b/src/boards/gn26.c @@ -0,0 +1,69 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2019 Libretro Team + * + * 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 + */ + +/* NES 2.0 Mapper 344 + * BMC-GN-26 + * Kuai Da Jin Ka Zhong Ji Tiao Zhan 3-in-1 (3-in-1,6-in-1,Unl) + */ + +#include "mapinc.h" +#include "mmc3.h" + +static void BMCGN26CW(uint32 A, uint8 V) { + uint32 base = (EXPREGS[0] & 0x03) << 7; + setchr1(A, base | (V & 0xFF)); +} + +static void BMCGN26PW(uint32 A, uint8 V) { + /* Re-ordered -> 0:SF4 1:Contra Force 2:Revolution Hero */ + uint32 table[] = { 0, 0, 1, 2 }; + uint32 base = table[(EXPREGS[0] & 0x03)]; + + if (EXPREGS[0] & 4) { + if (A == 0x8000) + setprg32(0x8000, (base << 2) | (V >> 2)); + } else + setprg8(A, (base << 4) | (V & 0x0F)); +} + +static DECLFW(BMCGN26Write) { + EXPREGS[0] = A & 0x0F; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static void BMCGN26Reset(void) { + EXPREGS[0] = 0; + MMC3RegReset(); +} + +static void BMCGN26Power(void) { + GenMMC3Power(); + SetWriteHandler(0x6800, 0x68FF, BMCGN26Write); +} + +void BMCGN26_Init(CartInfo *info) { + GenMMC3_Init(info, 128, 256, 1, 0); + pwrap = BMCGN26PW; + cwrap = BMCGN26CW; + info->Power = BMCGN26Power; + info->Reset = BMCGN26Reset; + AddExState(EXPREGS, 1, 0, "EXPR"); +} diff --git a/src/boards/gs-2004.c b/src/boards/gs-2004.c index b292d90..fd964e5 100644 --- a/src/boards/gs-2004.c +++ b/src/boards/gs-2004.c @@ -29,7 +29,7 @@ static SFORMAT StateRegs[] = }; static void Sync(void) { - setprg8r(1, 0x6000, 0); + setprg8(0x6000, 32); setprg32(0x8000, reg); setchr8(0); } @@ -40,7 +40,7 @@ static DECLFW(BMCGS2004Write) { } static void BMCGS2004Power(void) { - reg = ~0; + reg = 0x07; Sync(); SetReadHandler(0x6000, 0x7FFF, CartBR); SetReadHandler(0x8000, 0xFFFF, CartBR); @@ -48,7 +48,7 @@ static void BMCGS2004Power(void) { } static void BMCGS2004Reset(void) { - reg = ~0; + reg = 0x07; } static void StateRestore(int version) { diff --git a/src/boards/gs-2013.c b/src/boards/gs-2013.c index fe81a53..e7cda5f 100644 --- a/src/boards/gs-2013.c +++ b/src/boards/gs-2013.c @@ -29,8 +29,8 @@ static SFORMAT StateRegs[] = }; static void Sync(void) { - setprg8r(0, 0x6000, ~0); - setprg32r((reg & 8) >> 3, 0x8000, reg); + setprg8(0x6000, 31); + setprg32(0x8000, reg); setchr8(0); } @@ -40,7 +40,7 @@ static DECLFW(BMCGS2013Write) { } static void BMCGS2013Power(void) { - reg = ~0; + reg = 0; Sync(); SetReadHandler(0x6000, 0x7FFF, CartBR); SetReadHandler(0x8000, 0xFFFF, CartBR); @@ -48,7 +48,7 @@ static void BMCGS2013Power(void) { } static void BMCGS2013Reset(void) { - reg = ~0; + reg = 0; } static void StateRestore(int version) { diff --git a/src/boards/hp10xx_hp20xx.c b/src/boards/hp10xx_hp20xx.c new file mode 100644 index 0000000..c18c9d1 --- /dev/null +++ b/src/boards/hp10xx_hp20xx.c @@ -0,0 +1,171 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2017 CaH4e3 + * + * 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 "mapinc.h" +#include "mmc3.h" +#include "../ines.h" + +/* added on 2019-5-23 - NES 2.0 Mapper 260 + * HP10xx/HP20xx - a simplified version of FK23C mapper with pretty strict and better + * organized banking behaviour. It seems that some 176 mapper assigned game may be + * actually this kind of board instead but in common they aren't compatible at all, + * the games on the regular FK23C boards couldn't run on this mapper and vice versa... + */ + +static uint8 unromchr, lock; +static uint32 dipswitch; + +static void BMCHPxxCW(uint32 A, uint8 V) { + if (EXPREGS[0] & 4) { /* custom banking */ + switch(EXPREGS[0] & 3) { + case 0: + case 1: + setchr8(EXPREGS[2] & 0x3F); +/* FCEU_printf("\tCHR8 %02X\n",EXPREGS[2]&0x3F); */ + break; + case 2: + setchr8((EXPREGS[2] & 0x3E) | (unromchr & 1)); +/* FCEU_printf("\tCHR8 %02X\n",(EXPREGS[2]&0x3E)|(unromchr&1)); */ + break; + case 3: + setchr8((EXPREGS[2] & 0x3C) | (unromchr & 3)); +/* FCEU_printf("\tCHR8 %02X\n",(EXPREGS[2]&0x3C)|(unromchr&3)); */ + break; + } + } else { /* mmc3 banking */ + int base, mask; + if(EXPREGS[0] & 1) { /* 128K mode */ + base = EXPREGS[2] & 0x30; + mask = 0x7F; + } else { /* 256K mode */ + base = EXPREGS[2] & 0x20; + mask = 0xFF; + } +/* FCEU_printf("\tCHR1 %04x:%02X\n",A,(V&mask)|(base<<3)); */ + setchr1(A, (V & mask) | (base << 3)); + } +} + +/* PRG wrapper */ +static void BMCHPxxPW(uint32 A, uint8 V) { + if(EXPREGS[0] & 4) { /* custom banking */ + if((EXPREGS[0] & 0xF) == 4) { /* 16K mode */ +/* FCEU_printf("\tPRG16 %02X\n",EXPREGS[1]&0x1F); */ + setprg16(0x8000, EXPREGS[1] & 0x1F); + setprg16(0xC000, EXPREGS[1] & 0x1F); + } else { /* 32K modes */ +/* FCEU_printf("\tPRG32 %02X\n",(EXPREGS[1]&0x1F)>>1); */ + setprg32(0x8000, (EXPREGS[1] & 0x1F) >> 1); + } + } else { /* mmc3 banking */ + uint8 base, mask; + if(EXPREGS[0] & 2) { /* 128K mode */ + base = EXPREGS[1] & 0x18; + mask = 0x0F; + } else { /* 256K mode */ + base = EXPREGS[1] & 0x10; + mask = 0x1F; + } +/* FCEU_printf("\tPRG8 %02X\n",(V&mask)|(base<<1)); */ + setprg8(A, (V & mask) | (base << 1)); + setprg8r(0x10, 0x6000, A001B & 3); + } +} + +/* MIRROR wrapper */ +static void BMCHPxxMW(uint8 V) { + if(EXPREGS[0] & 4) { /* custom banking */ +/* FCEU_printf("CUSTOM MIRR: %d\n",(unromchr>>2)&1); */ + setmirror(((unromchr >> 2) & 1) ^ 1); + } else { /* mmc3 banking */ +/* FCEU_printf("MMC3 MIRR: %d\n",(V&1)^1); */ + A000B = V; + setmirror((A000B & 1) ^ 1); + } +} + +/* PRG handler ($8000-$FFFF) */ +static DECLFW(BMCHPxxHiWrite) { +/* FCEU_printf("HI WRITE %04X:%02X\n",A,V); */ + if(EXPREGS[0] & 4) { /* custom banking */ +/* FCEU_printf("CUSTOM\n"); */ + unromchr = V; + FixMMC3CHR(MMC3_cmd); + } else { /* mmc3 banking */ +/* FCEU_printf("MMC3\n"); */ + if(A<0xC000) { + MMC3_CMDWrite(A, V); + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + } else { + MMC3_IRQWrite(A, V); + } + } +} + +/* EXP handler ($5000-$5FFF) */ +static DECLFW(BMCHPxxWrite) { + if (!lock) { +/* FCEU_printf("LO WRITE %04X:%02X\n",A,V); */ + EXPREGS[A & 3] = V; + lock = V & 0x80; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + } +} + +static DECLFR(BMCHPxxRead) { + return dipswitch; +} + +static void BMCHPxxReset(void) { + dipswitch++; + dipswitch &= 0xF; + lock = 0; +/* FCEU_printf("BMCHPxx dipswitch set to %d\n",dipswitch); */ + EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; + MMC3RegReset(); + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static void BMCHPxxPower(void) { + GenMMC3Power(); + dipswitch = lock = 0; + EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + SetReadHandler(0x5000, 0x5fff, BMCHPxxRead); + SetWriteHandler(0x5000, 0x5fff, BMCHPxxWrite); + SetWriteHandler(0x8000, 0xffff, BMCHPxxHiWrite); +} + +void BMCHPxx_Init(CartInfo *info) { + GenMMC3_Init(info, 256, 256, 8, 0); + cwrap = BMCHPxxCW; + pwrap = BMCHPxxPW; + mwrap = BMCHPxxMW; + info->Power = BMCHPxxPower; + info->Reset = BMCHPxxReset; + AddExState(EXPREGS, 8, 0, "EXPR"); + AddExState(&unromchr, 1, 0, "UCHR"); + AddExState(&dipswitch, 1, 0, "DPSW"); + AddExState(&lock, 1, 0, "LOCK"); +} diff --git a/src/boards/lh51.c b/src/boards/lh51.c new file mode 100644 index 0000000..3236485 --- /dev/null +++ b/src/boards/lh51.c @@ -0,0 +1,87 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2019 Libretro Team + * + * 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 + */ + +/* FDS Conversion + * NES 2.0 Mapper 309 is used for Whirlwind Manu's ROM cartridge conversion + * of game 愛戦士ニコル (Ai Senshi Nicol, cartridge code LH51). + * Its UNIF board name is UNL-LH51. + * https://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_309 + */ + +#include "mapinc.h" + +static uint8 reg, mirr; +static uint8 *WRAM = NULL; +static uint32 WRAMSIZE; + +static SFORMAT StateRegs[] = +{ + { ®, 1, "REG" }, + { &mirr, 1, "MIRR" }, + { 0 } +}; + +static void Sync(void) { + setchr8(0); + setprg8r(0x10, 0x6000, 0); + setprg8(0x8000, reg & 0x0F); + setprg8(0xA000, 13); + setprg8(0xC000, 14); + setprg8(0xE000, 15); + setmirror(((mirr >> 3) & 1) ^ 1); +} + +static DECLFW(LH51Write) { + switch (A & 0xF000) { + case 0x8000: reg = V; Sync(); break; + case 0xF000: mirr = V; Sync(); break; + } +} + +static void LH51Power(void) { + Sync(); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + SetWriteHandler(0x8000, 0xFFFF, LH51Write); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); +} + +static void LH51Close(void) { + if (WRAM) + FCEU_gfree(WRAM); + WRAM = NULL; +} + +static void StateRestore(int version) { + Sync(); +} + +void LH51_Init(CartInfo *info) { + info->Power = LH51Power; + info->Close = LH51Close; + GameStateRestore = StateRestore; + + WRAMSIZE = 8192; + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/malee.c b/src/boards/malee.c index 84c353a..a4a0721 100644 --- a/src/boards/malee.c +++ b/src/boards/malee.c @@ -31,7 +31,7 @@ static void MALEEPower(void) { SetReadHandler(0x6000, 0x67FF, CartBR); SetReadHandler(0x7000, 0x77FF, CartBR); SetWriteHandler(0x7000, 0x77FF, CartBW); - setprg2r(1, 0x6000, 0); + setprg2(0x6000, 16); setprg32(0x8000, 0); setchr8(0); } diff --git a/src/boards/mmc1.c b/src/boards/mmc1.c index d05b29a..f3ef3c1 100644 --- a/src/boards/mmc1.c +++ b/src/boards/mmc1.c @@ -36,13 +36,17 @@ static uint8 *WRAM = NULL; static uint8 *CHRRAM = NULL; static int is155, is171; +static uint8 MMC1WRAMEnabled(void) { + return !(DRegs[3] & 0x10); +} + static DECLFW(MBWRAM) { - if (!(DRegs[3] & 0x10) || is155) + if (MMC1WRAMEnabled() || is155) Page[A >> 11][A] = V; /* WRAM is enabled. */ } static DECLFR(MAWRAM) { - if ((DRegs[3] & 0x10) && !is155) + if (!MMC1WRAMEnabled() && !is155) return X.DB; /* WRAM is disabled */ return(Page[A >> 11][A]); } @@ -201,12 +205,12 @@ static int DetectMMC1WRAMSize(uint32 crc32) { static uint32 NWCIRQCount; static uint8 NWCRec; -#define NWCDIP 0xE +static int32 nwcdip = 0x4; static void NWCIRQHook(int a) { if (!(NWCRec & 0x10)) { NWCIRQCount += a; - if ((NWCIRQCount | (NWCDIP << 25)) >= 0x3e000000) { + if (NWCIRQCount >= (0x20000000 | (nwcdip << 25))) { NWCIRQCount = 0; X6502_IRQBegin(FCEU_IQEXT); } @@ -236,6 +240,11 @@ static void NWCPRGHook(uint32 A, uint8 V) { static void NWCPower(void) { GenMMC1Power(); setchr8r(0, 0); + nwcdip = (int32)GameInfo->cspecial; +} + +static void NWCReset(void) { + nwcdip = (int32)GameInfo->cspecial; } void Mapper105_Init(CartInfo *info) { @@ -244,6 +253,7 @@ void Mapper105_Init(CartInfo *info) { MMC1PRGHook16 = NWCPRGHook; MapIRQHook = NWCIRQHook; info->Power = NWCPower; + info->Reset = NWCReset; } static void GenMMC1Power(void) { @@ -389,4 +399,47 @@ void SOROM_Init(CartInfo *info) { GenMMC1Init(info, 256, 0, 16, info->battery); } +/* ----------------------- FARID_SLROM_8-IN-1 -----------------------*/ +/* NES 2.0 Mapper 323 - UNIF FARID_SLROM_8-IN-1 */ + +static uint8 reg, lock; + +static void FARIDSLROM8IN1PRGHook(uint32 A, uint8 V) { + setprg16(A, (V & 0x07) | (reg << 3)); +} + +static void FARIDSLROM8IN1CHRHook(uint32 A, uint8 V) { + setchr4(A, (V & 0x1F) | (reg << 5)); +} + +static DECLFW(FARIDSLROM8IN1Write) { + if (MMC1WRAMEnabled() && !lock) { + lock = (V & 0x08) >> 3; + reg = (V & 0xF0) >> 4; + MMC1MIRROR(); + MMC1CHR(); + MMC1PRG(); + } +} + +static void FARIDSLROM8IN1Power(void) { + reg = lock = 0; + GenMMC1Power(); + SetWriteHandler(0x6000, 0x7FFF, FARIDSLROM8IN1Write); +} + +static void FARIDSLROM8IN1Reset(void) { + reg = lock = 0; + MMC1CMReset(); +} + +void FARIDSLROM8IN1_Init(CartInfo *info) { + GenMMC1Init(info, 1024, 256, 8, 0); + MMC1CHRHook4 = FARIDSLROM8IN1CHRHook; + MMC1PRGHook16 = FARIDSLROM8IN1PRGHook; + info->Power = FARIDSLROM8IN1Power; + info->Reset = FARIDSLROM8IN1Reset; + AddExState(&lock, 1, 0, "LOCK"); + AddExState(®, 1, 0, "REG6"); +} diff --git a/src/boards/mmc3.c b/src/boards/mmc3.c index d2d3369..5c498fc 100644 --- a/src/boards/mmc3.c +++ b/src/boards/mmc3.c @@ -236,8 +236,9 @@ static void GENPWRAP(uint32 A, uint8 V) { /* [NJ102] Mo Dao Jie (C) has 1024Mb MMC3 BOARD, maybe something other will be broken * also HengGe BBC-2x boards enables this mode as default board mode at boot up */ - setprg8(A, (V & 0x7F) | ((kt_extra & 4) << 4)); + setprg8(A, (V & 0x7F)/* | ((kt_extra & 4) << 4)*/); /* KT-008 boards hack 2-in-1, TODO assign to new ines mapper, most dump of KT-boards on the net are mapper 4, so need database or goodnes fix support */ + /* KT-008 boards should be assigned to mapper 224 */ } static void GENMWRAP(uint8 V) { @@ -265,7 +266,7 @@ void GenMMC3Power(void) { SetReadHandler(0x8000, 0xFFFF, CartBR); /* KT-008 boards hack 2-in-1, TODO assign to new ines mapper, most dump of KT-boards on the net are mapper 4, so need database or goodnes fix support */ - SetWriteHandler(0x5000,0x5FFF, KT008HackWrite); + /* SetWriteHandler(0x5000,0x5FFF, KT008HackWrite); */ /* KT-008 boards should be assigned to mapper 224 */ A001B = A000B = 0; setmirror(1); @@ -321,6 +322,7 @@ void GenMMC3_Init(CartInfo *info, int prg, int chr, int wram, int battery) { } /* KT-008 boards hack 2-in-1, TODO assign to new ines mapper, most dump of KT-boards on the net are mapper 4, so need database or goodnes fix support */ + /* KT-008 boards should be assigned to mapper 224 */ AddExState(&kt_extra, 1, 0, "KTEX"); AddExState(MMC3_StateRegs, ~0, 0, 0); @@ -597,6 +599,12 @@ void Mapper47_Init(CartInfo *info) { } /* ---------------------------- Mapper 49 ------------------------------- */ +/* -------------------- BMC-STREETFIGTER-GAME4IN1 ----------------------- */ +/* added 6-24-19: + * BMC-STREETFIGTER-GAME4IN1 - Sic. $6000 set to $41 rather than $00 on power-up. + */ + +static uint8 isUNIF = 0; static void M49PW(uint32 A, uint8 V) { if (EXPREGS[0] & 1) { @@ -623,11 +631,12 @@ static DECLFW(M49Write) { } static void M49Reset(void) { - EXPREGS[0] = 0; + EXPREGS[0] = isUNIF ? 0x41 : 0; MMC3RegReset(); } static void M49Power(void) { + EXPREGS[0] = isUNIF ? 0x41 : 0; M49Reset(); GenMMC3Power(); SetWriteHandler(0x6000, 0x7FFF, M49Write); @@ -635,6 +644,7 @@ static void M49Power(void) { } void Mapper49_Init(CartInfo *info) { + isUNIF = 0; GenMMC3_Init(info, 512, 256, 0, 0); cwrap = M49CW; pwrap = M49PW; @@ -643,6 +653,16 @@ void Mapper49_Init(CartInfo *info) { AddExState(EXPREGS, 1, 0, "EXPR"); } +void BMCSFGAME4IN1_Init(CartInfo *info) { + isUNIF = 1; + GenMMC3_Init(info, 512, 512, 0, 0); + cwrap = M49CW; + pwrap = M49PW; + info->Reset = M49Reset; + info->Power = M49Power; + AddExState(EXPREGS, 1, 0, "EXPR"); +} + /* ---------------------------- Mapper 52 ------------------------------- */ static void M52PW(uint32 A, uint8 V) { uint32 mask = 0x1F ^ ((EXPREGS[0] & 8) << 1); @@ -720,18 +740,24 @@ void Mapper74_Init(CartInfo *info) { /* ---------------------------- Mapper 114 ------------------------------ */ -static uint8 cmdin; +static uint8 cmdin, type_Boogerman = 0; +uint8 boogerman_perm[8] = { 0, 2, 5, 3, 6, 1, 7, 4 }; uint8 m114_perm[8] = { 0, 3, 1, 5, 6, 7, 2, 4 }; static void M114PWRAP(uint32 A, uint8 V) { if (EXPREGS[0] & 0x80) { -/* FCEU_printf("8000-C000:%02X\n",EXPREGS[0]&0xF); */ - setprg16(0x8000, EXPREGS[0] & 0xF); - setprg16(0xC000, EXPREGS[0] & 0xF); - } else { -/* FCEU_printf("%04X:%02X\n",A,V&0x3F); */ - setprg8(A, V & 0x3F); - } + if (EXPREGS[0] & 0x20) + setprg32(0x8000, (EXPREGS[0] & 0x0F) >> 1); + else { + setprg16(0x8000, (EXPREGS[0] & 0x0F)); + setprg16(0xC000, (EXPREGS[0] & 0x0F)); + } + } else + setprg8(A, V); +} + +static void M114CWRAP(uint32 A, uint8 V) { + setchr1(A, (uint32)V | ((EXPREGS[1] & 1) << 8)); } static DECLFW(M114Write) { @@ -746,28 +772,52 @@ static DECLFW(M114Write) { } } +static DECLFW(BoogermanWrite) { + switch (A & 0xE001) { + case 0x8001: if (!cmdin) break; MMC3_CMDWrite(0x8001, V); cmdin = 0; break; + case 0xA000: MMC3_CMDWrite(0x8000, (V & 0xC0) | (boogerman_perm[V & 7])); cmdin = 1; break; + case 0xA001: IRQReload = 1; break; + case 0xC000: MMC3_CMDWrite(0xA000, V); break; + case 0xC001: IRQLatch = V; break; + case 0xE000: X6502_IRQEnd(FCEU_IQEXT); IRQa = 0; break; + case 0xE001: IRQa = 1; break; + } +} + static DECLFW(M114ExWrite) { if (A <= 0x7FFF) { - EXPREGS[0] = V; + if (A & 1) + EXPREGS[1] = V; + else + EXPREGS[0] = V; FixMMC3PRG(MMC3_cmd); } } static void M114Power(void) { + EXPREGS[0] = EXPREGS[1] = 0; GenMMC3Power(); + SetWriteHandler(0x6000, 0x7FFF, M114ExWrite); SetWriteHandler(0x8000, 0xFFFF, M114Write); - SetWriteHandler(0x5000, 0x7FFF, M114ExWrite); + if (type_Boogerman) + SetWriteHandler(0x8000, 0xFFFF, BoogermanWrite); } static void M114Reset(void) { - EXPREGS[0] = 0; + EXPREGS[0] = EXPREGS[1] = 0; MMC3RegReset(); } void Mapper114_Init(CartInfo *info) { isRevB = 0; + type_Boogerman = 0; + if (info->CRC32 == 0x80eb1839 || /* Boogerman (Sugar Softec) (Unl) [!] - submapper 1 */ + info->CRC32 == 0x071e4ee8) /* 114 test-rom https://forums.nesdev.com/viewtopic.php?f=3&t=17391 */ + type_Boogerman = 1; + GenMMC3_Init(info, 256, 256, 0, 0); pwrap = M114PWRAP; + cwrap = M114CWRAP; info->Power = M114Power; info->Reset = M114Reset; AddExState(EXPREGS, 1, 0, "EXPR"); @@ -855,13 +905,19 @@ void Mapper119_Init(CartInfo *info) { } /* ---------------------------- Mapper 134 ------------------------------ */ +/* ---------------------------- UNL-T4A54A ------------------------------ */ + +/* UNL-T4A54A, functionally the same as mapper 134. + * Writes @ $6801. Menu @ prg $20000, chr $00000 */ static void M134PW(uint32 A, uint8 V) { - setprg8(A, (V & 0x1F) | ((EXPREGS[0] & 2) << 4)); + uint8 mask = (EXPREGS[0] & 0x04) ? 0x0F : 0x1F; + setprg8(A, (V & mask) | ((EXPREGS[0] & 3) << 4)); } static void M134CW(uint32 A, uint8 V) { - setchr1(A, (V & 0xFF) | ((EXPREGS[0] & 0x20) << 3)); + uint8 mask = (EXPREGS[0] & 0x04) ? 0x7F : 0xFF; + setchr1(A, (V & mask) | ((EXPREGS[0] & 0x30) << 3)); } static DECLFW(M134Write) { @@ -871,13 +927,14 @@ static DECLFW(M134Write) { } static void M134Power(void) { - EXPREGS[0] = 0; + EXPREGS[0] = 0x01; GenMMC3Power(); SetWriteHandler(0x6001, 0x6001, M134Write); + SetWriteHandler(0x6801, 0x6801, M134Write); } static void M134Reset(void) { - EXPREGS[0] = 0; + EXPREGS[0] = 0x01; MMC3RegReset(); } @@ -1137,19 +1194,73 @@ void Mapper198_Init(CartInfo *info) { } /* ---------------------------- Mapper 205 ------------------------------ */ -/* GN-45 BOARD */ +/* UNIF boardname BMC-JC-016-2 +https://wiki.nesdev.com/w/index.php/INES_Mapper_205 */ static void M205PW(uint32 A, uint8 V) { + uint8 bank = V & ((EXPREGS[0] & 0x02) ? 0x0F : 0x1F); + setprg8(A, EXPREGS[0] << 4 | bank); +} + +static void M205CW(uint32 A, uint8 V) { + uint8 bank = V & ((EXPREGS[0] & 0x02) ? 0x7F : 0xFF); + setchr1(A, (EXPREGS[0] << 7) | bank); +} + +static DECLFW(M205Write0) { + if (EXPREGS[1] == 0) { + EXPREGS[0] = V & 0x03; + EXPREGS[1] = A & 0x80; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + } else + CartBW(A, V); +} + +static DECLFW(M205Write1) { + if (EXPREGS[1] == 0) { + EXPREGS[0] = V & 0xF0; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + } else + CartBW(A, V); +} + +static void M205Reset(void) { + EXPREGS[0] = EXPREGS[1] = 0; + MMC3RegReset(); +} + +static void M205Power(void) { + EXPREGS[0] = EXPREGS[1] = 0; + GenMMC3Power(); + SetWriteHandler(0x6000, 0x6fff, M205Write0); + SetWriteHandler(0x7000, 0x7fff, M205Write1); /* OK-411 boards, the same logic, but data latched, 2-in-1 frankenstein */ +} + +void Mapper205_Init(CartInfo *info) { + GenMMC3_Init(info, 256, 128, 8, 0); + pwrap = M205PW; + cwrap = M205CW; + info->Power = M205Power; + info->Reset = M205Reset; + AddExState(EXPREGS, 1, 0, "EXPR"); +} + +/* --------------------------- GN-45 BOARD ------------------------------ */ + +/* Mapper 361 and 366, previously assigned as Mapper 205 */ +static void GN45PW(uint32 A, uint8 V) { /* GN-30A - \ED\E0\F7\E0\EB\FC\ED\E0\FF \EC\E0\F1\EA\E0 \E4\EE\EB\E6\ED\E0 \E1\FB\F2\FC 1F + \E0\EF\EF\E0\F0\E0\F2\ED\FB\E9 \EF\E5\F0\E5\EA\EB\FE\F7\E0\F2\E5\EB\FC \ED\E0 \F8\E8\ED\E5 \E0\E4\F0\E5\F1\E0 */ setprg8(A, (V & 0x0f) | EXPREGS[0]); } -static void M205CW(uint32 A, uint8 V) { +static void GN45CW(uint32 A, uint8 V) { /* GN-30A - \ED\E0\F7\E0\EB\FC\ED\E0\FF \EC\E0\F1\EA\E0 \E4\EE\EB\E6\ED\E0 \E1\FB\F2\FC FF */ setchr1(A, (V & 0x7F) | (EXPREGS[0] << 3)); } -static DECLFW(M205Write0) { +static DECLFW(GN45Write0) { if (EXPREGS[2] == 0) { EXPREGS[0] = A & 0x30; EXPREGS[2] = A & 0x80; @@ -1159,7 +1270,7 @@ static DECLFW(M205Write0) { CartBW(A, V); } -static DECLFW(M205Write1) { +static DECLFW(GN45Write1) { if (EXPREGS[2] == 0) { EXPREGS[0] = V & 0x30; FixMMC3PRG(MMC3_cmd); @@ -1168,23 +1279,23 @@ static DECLFW(M205Write1) { CartBW(A, V); } -static void M205Reset(void) { +static void GN45Reset(void) { EXPREGS[0] = EXPREGS[2] = 0; MMC3RegReset(); } -static void M205Power(void) { +static void GN45Power(void) { GenMMC3Power(); - SetWriteHandler(0x6000, 0x6fff, M205Write0); - SetWriteHandler(0x7000, 0x7fff, M205Write1); /* OK-411 boards, the same logic, but data latched, 2-in-1 frankenstein */ + SetWriteHandler(0x6000, 0x6fff, GN45Write0); + SetWriteHandler(0x7000, 0x7fff, GN45Write1); /* OK-411 boards, the same logic, but data latched, 2-in-1 frankenstein */ } -void Mapper205_Init(CartInfo *info) { +void GN45_Init(CartInfo *info) { GenMMC3_Init(info, 128, 128, 8, 0); - pwrap = M205PW; - cwrap = M205CW; - info->Power = M205Power; - info->Reset = M205Reset; + pwrap = GN45PW; + cwrap = GN45CW; + info->Power = GN45Power; + info->Reset = GN45Reset; AddExState(EXPREGS, 1, 0, "EXPR"); } diff --git a/src/boards/resetnromxin1.c b/src/boards/resetnromxin1.c new file mode 100644 index 0000000..0f0372f --- /dev/null +++ b/src/boards/resetnromxin1.c @@ -0,0 +1,75 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2019 Libretro Team + * + * 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 + */ + +/* NES 2.0 Mapper 343 + * BMC-RESETNROM-XIN1 + * - Sheng Tian 2-in-1(Unl,ResetBase)[p1] - Kung Fu (Spartan X), Super Mario Bros (alt) + * - Sheng Tian 2-in-1(Unl,ResetBase)[p2] - B-Wings, Twin-bee + * + * BMC-KS106C + * - Kaiser 4-in-1(Unl,KS106C)[p1] - B-Wings, Kung Fu, 1942, SMB1 (wrong mirroring) + */ + +#include "mapinc.h" + +static uint8 gameblock, limit; + +static SFORMAT StateRegs[] = +{ + { &gameblock, 1, "GAME" }, + { 0 } +}; + +static void Sync(void) { + setchr8(gameblock); + setprg32(0x8000, gameblock); +} + +static void BMCRESETNROMXIN1Power(void) { + gameblock = 0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); +} + +static void BMCRESETNROMXIN1Reset(void) { + gameblock++; + gameblock &= limit; + Sync(); +} + +static void StateRestore(int version) { + Sync(); +} + +void BMCRESETNROMXIN1_Init(CartInfo *info) { + limit = 0x01; + info->Power = BMCRESETNROMXIN1Power; + info->Reset = BMCRESETNROMXIN1Reset; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} + +void BMCKS106C_Init(CartInfo *info) { + limit = 0x03; + info->Power = BMCRESETNROMXIN1Power; + info->Reset = BMCRESETNROMXIN1Reset; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/resettxrom.c b/src/boards/resettxrom.c new file mode 100644 index 0000000..910c8a2 --- /dev/null +++ b/src/boards/resettxrom.c @@ -0,0 +1,57 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2019 Libretro Team + * + * 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 + */ + +/* NES 2.0 Mapper 313 is used for MMC3-based multicarts that switch + * between 128 KiB PRG-ROM/128 KiB CHR-ROM-sized games on each reset and + * thus require no additional registers. + * Its UNIF board name is BMC-RESET-TXROM. + */ + +#include "mapinc.h" +#include "mmc3.h" + +static void M313CW(uint32 A, uint8 V) { + setchr1(A, (EXPREGS[0] << 7) | (V & 0x7F)); +} + +static void M313PW(uint32 A, uint8 V) { + setprg8(A, (EXPREGS[0] << 4) | (V & 0x0F)); +} + +static void M313Reset(void) { + EXPREGS[0]++; + EXPREGS[0] &= 0x03; + MMC3RegReset(); +} + +static void M313Power(void) { + EXPREGS[0] = 0; + GenMMC3Power(); +} + +/* NES 2.0 313, UNIF BMC-RESET-TXROM */ +void BMCRESETTXROM_Init(CartInfo *info) { + GenMMC3_Init(info, 128, 128, 0, 0); + cwrap = M313CW; + pwrap = M313PW; + info->Power = M313Power; + info->Reset = M313Reset; + AddExState(EXPREGS, 1, 0, "EXPR"); +} diff --git a/src/boards/super40in1.c b/src/boards/super40in1.c new file mode 100644 index 0000000..ef5a5e1 --- /dev/null +++ b/src/boards/super40in1.c @@ -0,0 +1,74 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright (C) 2019 Libretro Team + * + * 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 + */ + +/* added 2019-5-23 + * BMC-WS Used for Super 40-in-1 multicart + * https://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_332 */ + +#include "mapinc.h" + +static uint8 preg, creg; + +static SFORMAT StateRegs[] = +{ + { &preg, 1, "PREG" }, + { &creg, 1, "CREG" }, + { 0 } +}; + +static void Sync(void) { + if (preg & 8) { + setprg16(0x8000, preg & 7); + setprg16(0xc000, preg & 7); + } + else + setprg32(0x8000, (preg & 6) >> 1); + setchr8(creg); + setmirror(((preg >> 4) & 1) ^ 1); +} + +static DECLFW(BMCWSWrite) { + if (preg & 0x20) + return; + + switch (A & 1) { + case 0: preg = V; Sync(); break; + case 1: creg = V; Sync(); break; + } +} + +static void MBMCWSPower(void) { + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x6001, BMCWSWrite); +} + +static void BMCWSReset(void) { +} + +static void StateRestore(int version) { + Sync(); +} + +void BMCWS_Init(CartInfo *info) { + info->Reset = BMCWSReset; + info->Power = MBMCWSPower; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/supervision.c b/src/boards/supervision.c index 46be8ed..43b67f5 100644 --- a/src/boards/supervision.c +++ b/src/boards/supervision.c @@ -30,23 +30,12 @@ static SFORMAT StateRegs[] = static void Sync(void) { setchr8(0); - if (PRGptr[1]) - setprg8r((cmd0 & 0xC) >> 2, 0x6000, ((cmd0 & 0x3) << 4) | 0xF); - else - setprg8(0x6000, (((cmd0 & 0xF) << 4) | 0xF) + 4); + setprg8(0x6000, (((cmd0 & 0xF) << 4) | 0xF) + 4); if (cmd0 & 0x10) { - if (PRGptr[1]) { - setprg16r((cmd0 & 0xC) >> 2, 0x8000, ((cmd0 & 0x3) << 3) | (cmd1 & 7)); - setprg16r((cmd0 & 0xC) >> 2, 0xc000, ((cmd0 & 0x3) << 3) | 7); - } else { setprg16(0x8000, (((cmd0 & 0xF) << 3) | (cmd1 & 7)) + 2); setprg16(0xc000, (((cmd0 & 0xF) << 3) | 7) + 2); - } } else - if (PRGptr[4]) - setprg32r(4, 0x8000, 0); - else - setprg32(0x8000, 0); + setprg32(0x8000, 0); setmirror(((cmd0 & 0x20) >> 5) ^ 1); } diff --git a/src/boards/unrom512.c b/src/boards/unrom512.c index 59ac51d..5e703b0 100644 --- a/src/boards/unrom512.c +++ b/src/boards/unrom512.c @@ -217,9 +217,9 @@ void UNROM512_Init(CartInfo *info) { flash_bank = 0; flash_save = info->battery; - if (info->vram_size == 8192) + if (info->chrRam == 8192) chrram_mask = 0; - else if (info->vram_size == 16384) + else if (info->chrRam == 16384) chrram_mask = 0x20; else chrram_mask = 0x60; @@ -236,7 +236,7 @@ void UNROM512_Init(CartInfo *info) { SetupCartMirroring(MI_0, 0, NULL); break; case 3: /* hard four screen, last 8k of 32k RAM (flags: 4-screen + vertical) */ - SetupCartMirroring(4, 1, VROM + (info->vram_size - 8192)); + SetupCartMirroring(4, 1, VROM + (info->chrRam - 8192)); break; } bus_conflict = !info->battery; diff --git a/src/boards/vrc2and4.c b/src/boards/vrc2and4.c index 7ff7ce7..9749d48 100644 --- a/src/boards/vrc2and4.c +++ b/src/boards/vrc2and4.c @@ -31,7 +31,6 @@ static uint8 prgreg[2], chrreg[8]; static uint16 chrhi[8]; static uint8 regcmd, irqcmd, mirr, big_bank; static uint16 acount = 0; -static uint16 weirdo = 0; static uint8 *WRAM = NULL; static uint32 WRAMSIZE; @@ -65,15 +64,8 @@ static void Sync(void) { setchr8(0); else { uint8 i; - /* if (!weirdo) */ - for (i = 0; i < 8; i++) - setchr1(i << 10, (chrhi[i] | chrreg[i]) >> is22); - /* else { - setchr1(0x0000, 0xFC); - setchr1(0x0400, 0xFD); - setchr1(0x0800, 0xFF); - weirdo--; - } */ + for (i = 0; i < 8; i++) + setchr1(i << 10, (chrhi[i] | chrreg[i]) >> is22); } switch (mirr & 0x3) { case 0: setmirror(MI_V); break; @@ -158,14 +150,20 @@ static DECLFW(M23Write) { VRC24Write(A, V); } -static void M21Power(void) { +static void VRC24PowerCommon(void (*WRITEFUNC)(uint32 A, uint8 V)) { Sync(); - setprg8r(0x10, 0x6000, 0); + setprg8r(0x10, 0x6000, 0); /* Only two Goemon games are have battery backed RAM, three more shooters + * (Parodius Da!, Gradius 2 and Crisis Force uses 2k or SRAM at 6000-67FF only + */ SetReadHandler(0x6000, 0x7FFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, M21Write); + SetWriteHandler(0x8000, 0xFFFF, WRITEFUNC); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); +} + +static void M21Power(void) { + VRC24PowerCommon(M21Write); } static void M22Power(void) { @@ -176,26 +174,12 @@ static void M22Power(void) { static void M23Power(void) { big_bank = 0x20; - Sync(); - setprg8r(0x10, 0x6000, 0); /* Only two Goemon games are have battery backed RAM, three more shooters - * (Parodius Da!, Gradius 2 and Crisis Force uses 2k or SRAM at 6000-67FF only - */ - SetReadHandler(0x6000, 0x7FFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, M23Write); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + VRC24PowerCommon(M23Write); } static void M25Power(void) { big_bank = 0x20; - Sync(); - setprg8r(0x10, 0x6000, 0); - SetReadHandler(0x6000, 0x7FFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, M22Write); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + VRC24PowerCommon(M22Write); } void FP_FASTAPASS(1) VRC24IRQHook(int a) { @@ -279,3 +263,99 @@ void UNLT230_Init(CartInfo *info) { info->Power = M23Power; VRC24_Init(info); } + +/* -------------------- UNL-TH2131-1 -------------------- */ +/* https://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_308 + * NES 2.0 Mapper 308 is used for a bootleg version of the Sunsoft game Batman + * similar to Mapper 23 Submapper 3) with custom IRQ functionality. + * UNIF board name is UNL-TH2131-1. + */ + +static DECLFW(TH2131Write) { + switch (A & 0xF003) { + case 0xF000: X6502_IRQEnd(FCEU_IQEXT); IRQa = 0; IRQCount = 0; break; + case 0xF001: IRQa = 1; break; + case 0xF003: IRQLatch = (V & 0xF0) >> 4; break; + } +} + +void FP_FASTAPASS(1) TH2131IRQHook(int a) { + int count; + + if (!IRQa) + return; + + for (count = 0; count < a; count++) { + IRQCount++; + if ((IRQCount & 0x0FFF) == 2048) + IRQLatch--; + if (!IRQLatch && (IRQCount & 0x0FFF) < 2048) + X6502_IRQBegin(FCEU_IQEXT); + } +} + +static void TH2131Power(void) { + VRC24PowerCommon(VRC24Write); + SetWriteHandler(0xF000, 0xFFFF, TH2131Write); +} + +void UNLTH21311_Init(CartInfo *info) { + info->Power = TH2131Power; + VRC24_Init(info); + MapIRQHook = TH2131IRQHook; +} + +/* -------------------- UNL-KS7021A -------------------- */ +/* http://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_525 + * NES 2.0 Mapper 525 is used for a bootleg version of versions of Contra and 月風魔伝 (Getsu Fūma Den). + * Its similar to Mapper 23 Submapper 3) with non-nibblized CHR-ROM bank registers. + */ + +static DECLFW(KS7021AWrite) { + switch (A & 0xB000) { + case 0xB000: chrreg[A & 0x07] = V; Sync(); break; + } +} + +static void KS7021APower(void) { + VRC24PowerCommon(VRC24Write); + SetWriteHandler(0xB000, 0xBFFF, KS7021AWrite); +} + +void UNLKS7021A_Init(CartInfo *info) { + info->Power = KS7021APower; + VRC24_Init(info); +} + +/* -------------------- BTL-900218 -------------------- */ +/* http://wiki.nesdev.com/w/index.php/UNIF/900218 + * NES 2.0 Mapper 524 describes the PCB used for the pirate port Lord of King or Axe of Fight. + * UNIF board name is BTL-900218. + */ + +static DECLFW(BTL900218Write) { + switch (A & 0xF00C) { + case 0xF008: IRQa = 1; break; + case 0xF00C: X6502_IRQEnd(FCEU_IQEXT); IRQa = 0; IRQCount = 0; break; + } +} + +void FP_FASTAPASS(1) BTL900218IRQHook(int a) { + if (!IRQa) + return; + + IRQCount += a; + if (IRQCount & 1024) + X6502_IRQBegin(FCEU_IQEXT); +} + +static void BTL900218Power(void) { + VRC24PowerCommon(VRC24Write); + SetWriteHandler(0xF000, 0xFFFF, BTL900218Write); +} + +void BTL900218_Init(CartInfo *info) { + info->Power = BTL900218Power; + VRC24_Init(info); + MapIRQHook = BTL900218IRQHook; +} diff --git a/src/cart.c b/src/cart.c index 911cb0c..d0b7cd1 100644 --- a/src/cart.c +++ b/src/cart.c @@ -53,6 +53,9 @@ static int PRGram[32]; uint8 *PRGptr[32]; uint8 *CHRptr[32]; +uint32 PRGchip_max; +uint32 CHRchip_max; + uint32 PRGsize[32]; uint32 CHRsize[32]; @@ -104,6 +107,8 @@ void ResetCartMapping(void) { for (x = 0; x < 8; x++) { MMC5SPRVPage[x] = MMC5BGVPage[x] = VPageR[x] = nothing - 0x400 * x; } + PRGchip_max = 0; + CHRchip_max = 0; } void SetupCartPRGMapping(int chip, uint8 *p, uint32 size, int ram) { diff --git a/src/cart.h b/src/cart.h index 7a7c2c4..56875da 100644 --- a/src/cart.h +++ b/src/cart.h @@ -10,6 +10,9 @@ typedef struct { uint32 SaveGameLen[4]; /* How much memory to save/load. */ /* Set by iNES/UNIF loading code. */ + int iNES2; /* iNES version */ + int mapper; /* mapper used */ + int submapper; /* submapper used */ /* TODO: */ int mirror; /* As set in the header or chunk. * iNES/UNIF specific. Intended * to help support games like "Karnov" @@ -17,7 +20,14 @@ typedef struct { * set to mapper 4. */ int battery; /* Presence of an actual battery. */ - int vram_size; + int prgRom; /* total prg rom size in 16 K chunks */ + int chrRom; /* total chr rom size in 8 K chunks */ + int prgRam; /* prg ram size (volatile) */ + int chrRam; /* chr ram size (volatile) */ + int prgRam_battery; /* prg ram size (non-volatile or battery backed) */ + int chrRam_battery; /* chr ram size (non-volatile or battery backed) */ + int region; /* video system timing (ntsc, pal, dendy */ + uint8 MD5[16]; uint32 CRC32; /* Should be set by the iNES/UNIF loading * code, used by mapper/board code, maybe @@ -39,6 +49,9 @@ DECLFW(CartBW); extern uint8 *PRGptr[32]; extern uint8 *CHRptr[32]; +extern uint32 PRGchip_max; +extern uint32 CHRchip_max; + extern uint32 PRGsize[32]; extern uint32 CHRsize[32]; diff --git a/src/drivers/libretro/libretro-common/compat/compat_snprintf.c b/src/drivers/libretro/libretro-common/compat/compat_snprintf.c index 40734a6..b69ad04 100644 --- a/src/drivers/libretro/libretro-common/compat/compat_snprintf.c +++ b/src/drivers/libretro/libretro-common/compat/compat_snprintf.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2017 The RetroArch team +/* Copyright (C) 2010-2018 The RetroArch team * * --------------------------------------------------------------------------------------- * The following license statement only applies to this file (compat_snprintf.c). @@ -23,9 +23,7 @@ /* THIS FILE HAS NOT BEEN VALIDATED ON PLATFORMS BESIDES MSVC */ #ifdef _MSC_VER -#include - -#include /* added for _vsnprintf_s and _vscprintf on VS2015 and VS2017 */ +#include #include #if _MSC_VER < 1800 @@ -53,14 +51,23 @@ int c99_vsnprintf_retro__(char *outBuf, size_t size, const char *format, va_list int count = -1; if (size != 0) + { #if (_MSC_VER <= 1310) - count = _vsnprintf(outBuf, size, format, ap); + count = _vsnprintf(outBuf, size - 1, format, ap); #else - count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); + count = _vsnprintf_s(outBuf, size, size - 1, format, ap); #endif + } + if (count == -1) count = _vscprintf(format, ap); + if (count == size) + { + /* there was no room for a NULL, so truncate the last character */ + outBuf[size - 1] = '\0'; + } + return count; } diff --git a/src/drivers/libretro/libretro-common/include/compat/msvc.h b/src/drivers/libretro/libretro-common/include/compat/msvc.h index fea4b53..4681b12 100644 --- a/src/drivers/libretro/libretro-common/include/compat/msvc.h +++ b/src/drivers/libretro/libretro-common/include/compat/msvc.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2017 The RetroArch team +/* Copyright (C) 2010-2018 The RetroArch team * * --------------------------------------------------------------------------------------- * The following license statement only applies to this file (msvc.h). @@ -39,8 +39,8 @@ extern "C" { int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...); #endif -/* Pre-MSVC 2010 compilers don't implement vsnprintf in a cross-platform manner? Not sure about this one. */ -#if _MSC_VER < 1600 +/* Pre-MSVC 2008 compilers don't implement vsnprintf in a cross-platform manner? Not sure about this one. */ +#if _MSC_VER < 1500 #include #include #ifndef vsnprintf @@ -56,6 +56,8 @@ extern "C" { #undef UNICODE /* Do not bother with UNICODE at this time. */ #include #include + +#define _USE_MATH_DEFINES #include /* Python headers defines ssize_t and sets HAVE_SSIZE_T. @@ -125,4 +127,3 @@ typedef int ssize_t; #endif #endif - diff --git a/src/drivers/libretro/libretro-common/include/compat/msvc/stdint.h b/src/drivers/libretro/libretro-common/include/compat/msvc/stdint.h index c791176..7c91a68 100644 --- a/src/drivers/libretro/libretro-common/include/compat/msvc/stdint.h +++ b/src/drivers/libretro/libretro-common/include/compat/msvc/stdint.h @@ -67,7 +67,6 @@ extern "C" { # endif #endif - /* 7.18.1 Integer types. */ /* 7.18.1.1 Exact-width integer types. */ @@ -94,7 +93,6 @@ extern "C" { typedef signed __int64 int64_t; typedef unsigned __int64 uint64_t; - /* 7.18.1.2 Minimum-width integer types. */ typedef int8_t int_least8_t; typedef int16_t int_least16_t; @@ -255,4 +253,3 @@ typedef uint64_t uintmax_t; #endif #endif - diff --git a/src/drivers/libretro/libretro-common/include/libretro.h b/src/drivers/libretro/libretro-common/include/libretro.h index 4e1a978..1fd2f5b 100644 --- a/src/drivers/libretro/libretro-common/include/libretro.h +++ b/src/drivers/libretro/libretro-common/include/libretro.h @@ -202,6 +202,8 @@ extern "C" { #define RETRO_DEVICE_ID_JOYPAD_L3 14 #define RETRO_DEVICE_ID_JOYPAD_R3 15 +#define RETRO_DEVICE_ID_JOYPAD_MASK 256 + /* Index / Id values for ANALOG device. */ #define RETRO_DEVICE_INDEX_ANALOG_LEFT 0 #define RETRO_DEVICE_INDEX_ANALOG_RIGHT 1 @@ -248,6 +250,7 @@ extern "C" { #define RETRO_DEVICE_ID_POINTER_X 0 #define RETRO_DEVICE_ID_POINTER_Y 1 #define RETRO_DEVICE_ID_POINTER_PRESSED 2 +#define RETRO_DEVICE_ID_POINTER_COUNT 3 /* Returned from retro_get_region(). */ #define RETRO_REGION_NTSC 0 @@ -274,6 +277,7 @@ enum retro_language RETRO_LANGUAGE_VIETNAMESE = 15, RETRO_LANGUAGE_ARABIC = 16, RETRO_LANGUAGE_GREEK = 17, + RETRO_LANGUAGE_TURKISH = 18, RETRO_LANGUAGE_LAST, /* Ensure sizeof(enum) == sizeof(int) */ @@ -485,11 +489,13 @@ enum retro_mod /* Environment commands. */ #define RETRO_ENVIRONMENT_SET_ROTATION 1 /* const unsigned * -- * Sets screen rotation of graphics. - * Is only implemented if rotation can be accelerated by hardware. * Valid values are 0, 1, 2, 3, which rotates screen by 0, 90, 180, * 270 degrees counter-clockwise respectively. */ #define RETRO_ENVIRONMENT_GET_OVERSCAN 2 /* bool * -- + * NOTE: As of 2019 this callback is considered deprecated in favor of + * using core options to manage overscan in a more nuanced, core-specific way. + * * Boolean value whether or not the implementation should use overscan, * or crop away overscan. */ @@ -608,7 +614,7 @@ enum retro_mod * Afterward it may be called again for the core to communicate * updated options to the frontend, but the number of core * options must not change from the number in the initial call. - * + * * 'data' points to an array of retro_variable structs * terminated by a { NULL, NULL } element. * retro_variable::key should be namespaced to not collide @@ -875,12 +881,12 @@ enum retro_mod * types already defined in the libretro API. * * The core must pass an array of const struct retro_controller_info which - * is terminated with a blanked out struct. Each element of the + * is terminated with a blanked out struct. Each element of the * retro_controller_info struct corresponds to the ascending port index * that is passed to retro_set_controller_port_device() when that function * is called to indicate to the core that the frontend has changed the * active device subclass. SEE ALSO: retro_set_controller_port_device() - * + * * The ascending input port indexes provided by the core in the struct * are generally presented by frontends as ascending User # or Player #, * such as Player 1, Player 2, Player 3, etc. Which device subclasses are @@ -892,7 +898,7 @@ enum retro_mod * User or Player, beginning with the generic Libretro device that the * subclasses are derived from. The second inner element of each entry is the * total number of subclasses that are listed in the retro_controller_description. - * + * * NOTE: Even if special device types are set in the libretro core, * libretro should only poll input based on the base input device types. */ @@ -1079,10 +1085,173 @@ enum retro_mod * fastforwarding mode. */ +#define RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE (50 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* float * -- + * Float value that lets us know what target refresh rate + * is curently in use by the frontend. + * + * The core can use the returned value to set an ideal + * refresh rate/framerate. + */ + +#define RETRO_ENVIRONMENT_GET_INPUT_BITMASKS (51 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* bool * -- + * Boolean value that indicates whether or not the frontend supports + * input bitmasks being returned by retro_input_state_t. The advantage + * of this is that retro_input_state_t has to be only called once to + * grab all button states instead of multiple times. + * + * If it returns true, you can pass RETRO_DEVICE_ID_JOYPAD_MASK as 'id' + * to retro_input_state_t (make sure 'device' is set to RETRO_DEVICE_JOYPAD). + * It will return a bitmask of all the digital buttons. + */ + +#define RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION 52 + /* unsigned * -- + * Unsigned value is the API version number of the core options + * interface supported by the frontend. If callback return false, + * API version is assumed to be 0. + * + * In legacy code, core options are set by passing an array of + * retro_variable structs to RETRO_ENVIRONMENT_SET_VARIABLES. + * This may be still be done regardless of the core options + * interface version. + * + * If version is 1 however, core options may instead be set by + * passing an array of retro_core_option_definition structs to + * RETRO_ENVIRONMENT_SET_CORE_OPTIONS, or a 2D array of + * retro_core_option_definition structs to RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL. + * This allows the core to additionally set option sublabel information + * and/or provide localisation support. + */ + +#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS 53 + /* const struct retro_core_option_definition ** -- + * Allows an implementation to signal the environment + * which variables it might want to check for later using + * GET_VARIABLE. + * This allows the frontend to present these variables to + * a user dynamically. + * This should only be called if RETRO_ENVIRONMENT_GET_ENHANCED_CORE_OPTIONS + * returns an API version of 1. + * This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES. + * This should be called the first time as early as + * possible (ideally in retro_set_environment). + * Afterwards it may be called again for the core to communicate + * updated options to the frontend, but the number of core + * options must not change from the number in the initial call. + * + * 'data' points to an array of retro_core_option_definition structs + * terminated by a { NULL, NULL, NULL, {{0}}, NULL } element. + * retro_core_option_definition::key should be namespaced to not collide + * with other implementations' keys. e.g. A core called + * 'foo' should use keys named as 'foo_option'. + * retro_core_option_definition::desc should contain a human readable + * description of the key. + * retro_core_option_definition::info should contain any additional human + * readable information text that a typical user may need to + * understand the functionality of the option. + * retro_core_option_definition::values is an array of retro_core_option_value + * structs terminated by a { NULL, NULL } element. + * > retro_core_option_definition::values[index].value is an expected option + * value. + * > retro_core_option_definition::values[index].label is a human readable + * label used when displaying the value on screen. If NULL, + * the value itself is used. + * retro_core_option_definition::default_value is the default core option + * setting. It must match one of the expected option values in the + * retro_core_option_definition::values array. If it does not, or the + * default value is NULL, the first entry in the + * retro_core_option_definition::values array is treated as the default. + * + * The number of possible options should be very limited, + * and must be less than RETRO_NUM_CORE_OPTION_VALUES_MAX. + * i.e. it should be feasible to cycle through options + * without a keyboard. + * + * First entry should be treated as a default. + * + * Example entry: + * { + * "foo_option", + * "Speed hack coprocessor X", + * "Provides increased performance at the expense of reduced accuracy", + * { + * { "false", NULL }, + * { "true", NULL }, + * { "unstable", "Turbo (Unstable)" }, + * { NULL, NULL }, + * }, + * "false" + * } + * + * Only strings are operated on. The possible values will + * generally be displayed and stored as-is by the frontend. + */ + +#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL 54 + /* const struct retro_core_options_intl * -- + * Allows an implementation to signal the environment + * which variables it might want to check for later using + * GET_VARIABLE. + * This allows the frontend to present these variables to + * a user dynamically. + * This should only be called if RETRO_ENVIRONMENT_GET_ENHANCED_CORE_OPTIONS + * returns an API version of 1. + * This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES. + * This should be called the first time as early as + * possible (ideally in retro_set_environment). + * Afterwards it may be called again for the core to communicate + * updated options to the frontend, but the number of core + * options must not change from the number in the initial call. + * + * This is fundamentally the same as RETRO_ENVIRONMENT_SET_CORE_OPTIONS, + * with the addition of localisation support. The description of the + * RETRO_ENVIRONMENT_SET_CORE_OPTIONS callback should be consulted + * for further details. + * + * 'data' points to a retro_core_options_intl struct. + * + * retro_core_options_intl::us is a pointer to an array of + * retro_core_option_definition structs defining the US English + * core options implementation. It must point to a valid array. + * + * retro_core_options_intl::local is a pointer to an array of + * retro_core_option_definition structs defining core options for + * the current frontend language. It may be NULL (in which case + * retro_core_options_intl::us is used by the frontend). Any items + * missing from this array will be read from retro_core_options_intl::us + * instead. + * + * NOTE: Default core option values are always taken from the + * retro_core_options_intl::us array. Any default values in + * retro_core_options_intl::local array will be ignored. + */ + +#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY 55 + /* struct retro_core_option_display * -- + * + * Allows an implementation to signal the environment to show + * or hide a variable when displaying core options. This is + * considered a *suggestion*. The frontend is free to ignore + * this callback, and its implementation not considered mandatory. + * + * 'data' points to a retro_core_option_display struct + * + * retro_core_option_display::key is a variable identifier + * which has already been set by SET_VARIABLES/SET_CORE_OPTIONS. + * + * retro_core_option_display::visible is a boolean, specifying + * whether variable should be displayed + * + * Note that all core option variables will be set visible by + * default when calling SET_VARIABLES/SET_CORE_OPTIONS. + */ + /* VFS functionality */ /* File paths: - * File paths passed as parameters when using this api shall be well formed unix-style, + * File paths passed as parameters when using this API shall be well formed UNIX-style, * using "/" (unquoted forward slash) as directory separator regardless of the platform's native separator. * Paths shall also include at least one forward slash ("game.bin" is an invalid path, use "./game.bin" instead). * Other than the directory separator, cores shall not make assumptions about path format: @@ -1100,6 +1269,10 @@ enum retro_mod * Introduced in VFS API v1 */ struct retro_vfs_file_handle; +/* Opaque directory handle + * Introduced in VFS API v3 */ +struct retro_vfs_dir_handle; + /* File open flags * Introduced in VFS API v1 */ #define RETRO_VFS_FILE_ACCESS_READ (1 << 0) /* Read only mode */ @@ -1119,6 +1292,12 @@ struct retro_vfs_file_handle; #define RETRO_VFS_SEEK_POSITION_CURRENT 1 #define RETRO_VFS_SEEK_POSITION_END 2 +/* stat() result flags + * Introduced in VFS API v3 */ +#define RETRO_VFS_STAT_IS_VALID (1 << 0) +#define RETRO_VFS_STAT_IS_DIRECTORY (1 << 1) +#define RETRO_VFS_STAT_IS_CHARACTER_SPECIAL (1 << 2) + /* Get path from opaque handle. Returns the exact same path passed to file_open when getting the handle * Introduced in VFS API v1 */ typedef const char *(RETRO_CALLCONV *retro_vfs_get_path_t)(struct retro_vfs_file_handle *stream); @@ -1128,7 +1307,7 @@ typedef const char *(RETRO_CALLCONV *retro_vfs_get_path_t)(struct retro_vfs_file * Introduced in VFS API v1 */ typedef struct retro_vfs_file_handle *(RETRO_CALLCONV *retro_vfs_open_t)(const char *path, unsigned mode, unsigned hints); -/* Close the file and release its resources. Must be called if open_file returns non-NULL. Returns 0 on succes, -1 on failure. +/* Close the file and release its resources. Must be called if open_file returns non-NULL. Returns 0 on success, -1 on failure. * Whether the call succeeds ot not, the handle passed as parameter becomes invalid and should no longer be used. * Introduced in VFS API v1 */ typedef int (RETRO_CALLCONV *retro_vfs_close_t)(struct retro_vfs_file_handle *stream); @@ -1141,7 +1320,7 @@ typedef int64_t (RETRO_CALLCONV *retro_vfs_size_t)(struct retro_vfs_file_handle * Introduced in VFS API v2 */ typedef int64_t (RETRO_CALLCONV *retro_vfs_truncate_t)(struct retro_vfs_file_handle *stream, int64_t length); -/* Get the current read / write position for the file. Returns - 1 for error. +/* Get the current read / write position for the file. Returns -1 for error. * Introduced in VFS API v1 */ typedef int64_t (RETRO_CALLCONV *retro_vfs_tell_t)(struct retro_vfs_file_handle *stream); @@ -1169,6 +1348,39 @@ typedef int (RETRO_CALLCONV *retro_vfs_remove_t)(const char *path); * Introduced in VFS API v1 */ typedef int (RETRO_CALLCONV *retro_vfs_rename_t)(const char *old_path, const char *new_path); +/* Stat the specified file. Retruns a bitmask of RETRO_VFS_STAT_* flags, none are set if path was not valid. + * Additionally stores file size in given variable, unless NULL is given. + * Introduced in VFS API v3 */ +typedef int (RETRO_CALLCONV *retro_vfs_stat_t)(const char *path, int32_t *size); + +/* Create the specified directory. Returns 0 on success, -1 on unknown failure, -2 if already exists. + * Introduced in VFS API v3 */ +typedef int (RETRO_CALLCONV *retro_vfs_mkdir_t)(const char *dir); + +/* Open the specified directory for listing. Returns the opaque dir handle, or NULL for error. + * Support for the include_hidden argument may vary depending on the platform. + * Introduced in VFS API v3 */ +typedef struct retro_vfs_dir_handle *(RETRO_CALLCONV *retro_vfs_opendir_t)(const char *dir, bool include_hidden); + +/* Read the directory entry at the current position, and move the read pointer to the next position. + * Returns true on success, false if already on the last entry. + * Introduced in VFS API v3 */ +typedef bool (RETRO_CALLCONV *retro_vfs_readdir_t)(struct retro_vfs_dir_handle *dirstream); + +/* Get the name of the last entry read. Returns a string on success, or NULL for error. + * The returned string pointer is valid until the next call to readdir or closedir. + * Introduced in VFS API v3 */ +typedef const char *(RETRO_CALLCONV *retro_vfs_dirent_get_name_t)(struct retro_vfs_dir_handle *dirstream); + +/* Check if the last entry read was a directory. Returns true if it was, false otherwise (or on error). + * Introduced in VFS API v3 */ +typedef bool (RETRO_CALLCONV *retro_vfs_dirent_is_dir_t)(struct retro_vfs_dir_handle *dirstream); + +/* Close the directory and release its resources. Must be called if opendir returns non-NULL. Returns 0 on success, -1 on failure. + * Whether the call succeeds ot not, the handle passed as parameter becomes invalid and should no longer be used. + * Introduced in VFS API v3 */ +typedef int (RETRO_CALLCONV *retro_vfs_closedir_t)(struct retro_vfs_dir_handle *dirstream); + struct retro_vfs_interface { /* VFS API v1 */ @@ -1185,6 +1397,14 @@ struct retro_vfs_interface retro_vfs_rename_t rename; /* VFS API v2 */ retro_vfs_truncate_t truncate; + /* VFS API v3 */ + retro_vfs_stat_t stat; + retro_vfs_mkdir_t mkdir; + retro_vfs_opendir_t opendir; + retro_vfs_readdir_t readdir; + retro_vfs_dirent_get_name_t dirent_get_name; + retro_vfs_dirent_is_dir_t dirent_is_dir; + retro_vfs_closedir_t closedir; }; struct retro_vfs_interface_info @@ -1207,6 +1427,7 @@ enum retro_hw_render_interface_type RETRO_HW_RENDER_INTERFACE_D3D10 = 2, RETRO_HW_RENDER_INTERFACE_D3D11 = 3, RETRO_HW_RENDER_INTERFACE_D3D12 = 4, + RETRO_HW_RENDER_INTERFACE_GSKIT_PS2 = 5, RETRO_HW_RENDER_INTERFACE_DUMMY = INT_MAX }; @@ -2272,6 +2493,64 @@ struct retro_variable const char *value; }; +struct retro_core_option_display +{ + /* Variable to configure in RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY */ + const char *key; + + /* Specifies whether variable should be displayed + * when presenting core options to the user */ + bool visible; +}; + +/* Maximum number of values permitted for a core option + * NOTE: This may be increased on a core-by-core basis + * if required (doing so has no effect on the frontend) */ +#define RETRO_NUM_CORE_OPTION_VALUES_MAX 128 + +struct retro_core_option_value +{ + /* Expected option value */ + const char *value; + + /* Human-readable value label. If NULL, value itself + * will be displayed by the frontend */ + const char *label; +}; + +struct retro_core_option_definition +{ + /* Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE. */ + const char *key; + + /* Human-readable core option description (used as menu label) */ + const char *desc; + + /* Human-readable core option information (used as menu sublabel) */ + const char *info; + + /* Array of retro_core_option_value structs, terminated by NULL */ + struct retro_core_option_value values[RETRO_NUM_CORE_OPTION_VALUES_MAX]; + + /* Default core option value. Must match one of the values + * in the retro_core_option_value array, otherwise will be + * ignored */ + const char *default_value; +}; + +struct retro_core_options_intl +{ + /* Pointer to an array of retro_core_option_definition structs + * - US English implementation + * - Must point to a valid array */ + struct retro_core_option_definition *us; + + /* Pointer to an array of retro_core_option_definition structs + * - Implementation for current frontend language + * - May be NULL */ + struct retro_core_option_definition *local; +}; + struct retro_game_info { const char *path; /* Path to game, UTF-8 encoded. diff --git a/src/drivers/libretro/libretro-common/include/retro_common.h b/src/drivers/libretro/libretro-common/include/retro_common.h index 5938bea..9a1fd5f 100644 --- a/src/drivers/libretro/libretro-common/include/retro_common.h +++ b/src/drivers/libretro/libretro-common/include/retro_common.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2017 The RetroArch team +/* Copyright (C) 2010-2018 The RetroArch team * * --------------------------------------------------------------------------------------- * The following license statement only applies to this file (retro_common.h). @@ -34,4 +34,3 @@ in a public API, you may need this. #include #endif - diff --git a/src/drivers/libretro/libretro-common/include/retro_common_api.h b/src/drivers/libretro/libretro-common/include/retro_common_api.h index ff38f98..fc4f745 100644 --- a/src/drivers/libretro/libretro-common/include/retro_common_api.h +++ b/src/drivers/libretro/libretro-common/include/retro_common_api.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2017 The RetroArch team +/* Copyright (C) 2010-2018 The RetroArch team * * --------------------------------------------------------------------------------------- * The following license statement only applies to this file (retro_common_api.h). @@ -113,6 +113,5 @@ Of course, another school of thought is that you should do as little damage as p in as few places as possible... */ - /* _LIBRETRO_COMMON_RETRO_COMMON_API_H */ #endif diff --git a/src/drivers/libretro/libretro-common/include/retro_inline.h b/src/drivers/libretro/libretro-common/include/retro_inline.h new file mode 100644 index 0000000..e4a21f6 --- /dev/null +++ b/src/drivers/libretro/libretro-common/include/retro_inline.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2010-2018 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (retro_inline.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_INLINE_H +#define __LIBRETRO_SDK_INLINE_H + +#ifndef INLINE + +#if defined(_WIN32) || defined(__INTEL_COMPILER) +#define INLINE __inline +#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L +#define INLINE inline +#elif defined(__GNUC__) +#define INLINE __inline__ +#else +#define INLINE +#endif + +#endif +#endif diff --git a/src/drivers/libretro/libretro-common/include/streams/memory_stream.h b/src/drivers/libretro/libretro-common/include/streams/memory_stream.h index fba8783..c594808 100644 --- a/src/drivers/libretro/libretro-common/include/streams/memory_stream.h +++ b/src/drivers/libretro/libretro-common/include/streams/memory_stream.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2017 The RetroArch team +/* Copyright (C) 2010-2018 The RetroArch team * * --------------------------------------------------------------------------------------- * The following license statement only applies to this file (memory_stream.h). diff --git a/src/drivers/libretro/libretro-common/streams/memory_stream.c b/src/drivers/libretro/libretro-common/streams/memory_stream.c index 784d0fe..77a2c00 100644 --- a/src/drivers/libretro/libretro-common/streams/memory_stream.c +++ b/src/drivers/libretro/libretro-common/streams/memory_stream.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2017 The RetroArch team +/* Copyright (C) 2010-2018 The RetroArch team * * --------------------------------------------------------------------------------------- * The following license statement only applies to this file (memory_stream.c). diff --git a/src/drivers/libretro/libretro.c b/src/drivers/libretro/libretro.c index 28e1796..342902a 100644 --- a/src/drivers/libretro/libretro.c +++ b/src/drivers/libretro/libretro.c @@ -29,6 +29,8 @@ #endif #include "libretro-common/include/streams/memory_stream.h" +#include "libretro_dipswitch.h" +#include "libretro_core_options.h" #define MAX_PLAYERS 4 /* max supported players */ #define MAX_PORTS 2 /* max controller ports, @@ -63,7 +65,7 @@ static retro_video_refresh_t video_cb = NULL; static retro_input_poll_t poll_cb = NULL; static retro_input_state_t input_cb = NULL; static retro_audio_sample_batch_t audio_batch_cb = NULL; -static retro_environment_t environ_cb = NULL; +retro_environment_t environ_cb = NULL; #ifdef PSP static bool use_overscan; #else @@ -77,7 +79,9 @@ static bool enable_4player = false; static unsigned turbo_enabler[MAX_PLAYERS] = {0}; static unsigned turbo_delay = 0; static unsigned input_type[MAX_PLAYERS + 1] = {0}; /* 4-players + famicom expansion */ -static unsigned lightgun_enabled = 1; /* 0=mouse 1=lightgun(default) */ +enum RetroZapperInputModes{RetroLightgun, RetroMouse, RetroPointer}; +static enum RetroZapperInputModes zappermode = RetroLightgun; +static unsigned show_advance_sound_options; /* emulator-specific variables */ @@ -133,6 +137,7 @@ extern uint8 *XBuf; extern CartInfo iNESCart; extern CartInfo UNIFCart; extern int show_crosshair; +extern int option_ramstate; /* emulator-specific callback functions */ @@ -561,6 +566,8 @@ struct st_palettes palettes[] = { } }; +static bool libretro_supports_bitmasks = false; + unsigned retro_api_version(void) { return RETRO_API_VERSION; @@ -687,7 +694,7 @@ static unsigned fc_to_libretro(int d) void retro_set_controller_port_device(unsigned port, unsigned device) { - if ((port < 5) && (input_type[port] != device)) + if (port < 5) { if (port < 2) /* player 1-2 */ { @@ -737,39 +744,29 @@ void retro_set_controller_port_device(unsigned port, unsigned device) } } +static void set_variables(void) +{ + unsigned i = 0, index = 0; + + /* Initialize main core option struct */ + for (i = 0; i < MAX_CORE_OPTIONS; i++) + option_defs_us[i] = option_defs_empty; + + /* Write common core options to main struct */ + while (option_defs_common[index].key) { + option_defs_us[index] = option_defs_common[index]; + index++; + } + + /* Append dipswitch settings to core options if available */ + index += set_dipswitch_variables(index, option_defs_us); + option_defs_us[index] = option_defs_empty; + + libretro_set_core_options(environ_cb); +} + void retro_set_environment(retro_environment_t cb) { - static const struct retro_variable vars[] = { - { "fceumm_region", "Region Override; Auto|NTSC|PAL|Dendy" }, - { "fceumm_aspect", "Preferred aspect ratio; 8:7 PAR|4:3" }, - { "fceumm_palette", "Color Palette; default|asqrealc|nintendo-vc|rgb|yuv-v3|unsaturated-final|sony-cxa2025as-us|pal|bmf-final2|bmf-final3|smooth-fbx|composite-direct-fbx|pvm-style-d93-fbx|ntsc-hardware-fbx|nes-classic-fbx-fs|nescap|wavebeam|raw|custom" }, - { "fceumm_up_down_allowed", "Allow Opposing Directions; disabled|enabled" }, -#ifdef PSP - { "fceumm_overscan", "Crop Overscan; enabled|disabled" }, -#else - { "fceumm_overscan_h", "Crop Overscan (Horizontal); disabled|enabled" }, - { "fceumm_overscan_v", "Crop Overscan (Vertical); enabled|disabled" }, -#endif - { "fceumm_nospritelimit", "No Sprite Limit; disabled|enabled" }, - { "fceumm_sndvolume", "Sound Volume; 150|160|170|180|190|200|210|220|230|240|250|0|10|20|30|40|50|60|70|80|90|100|110|120|130|140" }, - { "fceumm_sndquality", "Sound Quality; Low|High|Very High" }, - { "fceumm_swapduty", "Swap Duty Cycles; disabled|enabled" }, -#ifdef DEBUG - { "fceumm_apu_1", "Enable Sound Channel 1 (Square 1); enabled|disabled" }, - { "fceumm_apu_2", "Enable Sound Channel 2 (Square 2); enabled|disabled" }, - { "fceumm_apu_3", "Enable Sound Channel 3 (Triangle); enabled|disabled" }, - { "fceumm_apu_4", "Enable Sound Channel 4 (Noise); enabled|disabled" }, - { "fceumm_apu_5", "Enable Sound Channel 5 (PCM); enabled|disabled" }, -#endif - { "fceumm_turbo_enable", "Turbo Enable; None|Player 1|Player 2|Both" }, - { "fceumm_turbo_delay", "Turbo Delay (in frames); 3|5|10|15|30|60|1|2" }, - { "fceumm_zapper_mode", "Zapper Mode; lightgun|mouse" }, - { "fceumm_show_crosshair", "Show Crosshair; enabled|disabled" }, - { "fceumm_overclocking", "Overclocking; disabled|2x-Postrender|2x-VBlank" }, - { "fceumm_ramstate", "RAM power up state (Restart); fill $ff|fill $00|random" }, - { NULL, NULL }, - }; - static const struct retro_controller_description pads1[] = { { "Auto", RETRO_DEVICE_AUTO }, { "Gamepad", RETRO_DEVICE_GAMEPAD }, @@ -816,8 +813,7 @@ void retro_set_environment(retro_environment_t cb) }; environ_cb = cb; - cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void*)vars); - cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports); + environ_cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports); } void retro_get_system_info(struct retro_system_info *info) @@ -876,19 +872,8 @@ void retro_init(void) log_cb.log(RETRO_LOG_INFO, "Frontend supports RGB565 - will use that instead of XRGB1555.\n"); #endif - /* initialize some of the default variables */ -#ifdef GEKKO - sndsamplerate = 32000; -#else - sndsamplerate = 48000; -#endif - sndquality = 0; - sndvolume = 150; - swapDuty = 0; - - /* Wii: initialize this or else last variable is passed through - * when loading another rom causing save state size change. */ - serialize_size = 0; + if (environ_cb(RETRO_ENVIRONMENT_GET_INPUT_BITMASKS, NULL)) + libretro_supports_bitmasks = true; } static void retro_set_custom_palette(void) @@ -1002,7 +987,8 @@ void retro_deinit (void) #if defined(RENDER_GSKIT_PS2) ps2 = NULL; #endif - + libretro_supports_bitmasks = false; + DPSW_Cleanup(); } void retro_reset(void) @@ -1016,16 +1002,6 @@ typedef struct unsigned nes; } keymap; -static const keymap bindmap[] = { - { RETRO_DEVICE_ID_JOYPAD_A, JOY_A }, - { RETRO_DEVICE_ID_JOYPAD_B, JOY_B }, - { RETRO_DEVICE_ID_JOYPAD_SELECT, JOY_SELECT }, - { RETRO_DEVICE_ID_JOYPAD_START, JOY_START }, - { RETRO_DEVICE_ID_JOYPAD_UP, JOY_UP }, - { RETRO_DEVICE_ID_JOYPAD_DOWN, JOY_DOWN }, - { RETRO_DEVICE_ID_JOYPAD_LEFT, JOY_LEFT }, - { RETRO_DEVICE_ID_JOYPAD_RIGHT, JOY_RIGHT }, -}; static const keymap turbomap[] = { { RETRO_DEVICE_ID_JOYPAD_X, JOY_A }, @@ -1049,6 +1025,18 @@ static void check_variables(bool startup) char key[256]; int i, enable_apu; + var.key = "fceumm_ramstate"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "random")) + option_ramstate = 2; + else if (!strcmp(var.value, "fill $00")) + option_ramstate = 1; + else + option_ramstate = 0; + } + var.key = "fceumm_palette"; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) @@ -1161,8 +1149,9 @@ static void check_variables(bool startup) if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { - if (!strcmp(var.value, "mouse")) lightgun_enabled = 0; - else lightgun_enabled = 1; /*default setting*/ + if (!strcmp(var.value, "mouse")) zappermode = RetroMouse; + else if (!strcmp(var.value, "touchscreen")) zappermode = RetroPointer; + else zappermode = RetroLightgun; /*default setting*/ } var.key = "fceumm_show_crosshair"; @@ -1216,8 +1205,6 @@ static void check_variables(bool startup) if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { - unsigned i; - turbo_enabler[0] = 0; turbo_enabler[1] = 0; @@ -1292,7 +1279,8 @@ static void check_variables(bool startup) if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { - sndvolume = atoi(var.value); + int val = (int)(atof(var.value) * 25.6); + sndvolume = val; FCEUD_SoundToggle(); } @@ -1333,6 +1321,7 @@ static void check_variables(bool startup) set_apu_channels(0xff); #endif + update_dipswitch(); } static int mzx = 0, mzy = 0; @@ -1353,7 +1342,7 @@ void get_mouse_input(unsigned port, uint32_t *zapdata) max_height = 240; zapdata[2] = 0; /* reset click state */ - if (!lightgun_enabled) /* mouse device */ + if (zappermode == RetroMouse) /* mouse device */ { min_width = (adjx ? 8 : 0) + 1; min_height = (adjy ? 8 : 0) + 1; @@ -1379,6 +1368,27 @@ void get_mouse_input(unsigned port, uint32_t *zapdata) if (input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_RIGHT)) zapdata[2] |= 0x2; } + else if (zappermode == RetroPointer) { + int offset_x = (adjx ? 0X8FF : 0); + int offset_y = (adjy ? 0X999 : 0); + + int _x = input_cb(port, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X); + int _y = input_cb(port, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y); + + if (_x == 0 && _y == 0) + { + zapdata[0] = 0; + zapdata[1] = 0; + } + else + { + zapdata[0] = (_x + (0x7FFF + offset_x)) * max_width / ((0x7FFF + offset_x) * 2); + zapdata[1] = (_y + (0x7FFF + offset_y)) * max_height / ((0x7FFF + offset_y) * 2); + } + + if (input_cb(port, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED)) + zapdata[2] |= 0x1; + } else /* lightgun device */ { int offset_x = (adjx ? 0X8FF : 0); @@ -1440,9 +1450,45 @@ static void FCEUD_UpdateInput(void) if (player_enabled) { - for (i = 0; i < MAX_BUTTONS; i++) - input_buf |= input_cb(player, RETRO_DEVICE_JOYPAD, 0, - bindmap[i].retro) ? bindmap[i].nes : 0; + int16_t ret; + + if (libretro_supports_bitmasks) + { + ret = input_cb(player, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_MASK); + + if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_A)) + input_buf |= JOY_A; + if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_B)) + input_buf |= JOY_B; + if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_SELECT)) + input_buf |= JOY_SELECT; + if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_START)) + input_buf |= JOY_START; + if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_UP)) + input_buf |= JOY_UP; + if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_DOWN)) + input_buf |= JOY_DOWN; + if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_LEFT)) + input_buf |= JOY_LEFT; + if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_RIGHT)) + input_buf |= JOY_RIGHT; + } + else + { + static const keymap bindmap[] = { + { RETRO_DEVICE_ID_JOYPAD_A, JOY_A }, + { RETRO_DEVICE_ID_JOYPAD_B, JOY_B }, + { RETRO_DEVICE_ID_JOYPAD_SELECT, JOY_SELECT }, + { RETRO_DEVICE_ID_JOYPAD_START, JOY_START }, + { RETRO_DEVICE_ID_JOYPAD_UP, JOY_UP }, + { RETRO_DEVICE_ID_JOYPAD_DOWN, JOY_DOWN }, + { RETRO_DEVICE_ID_JOYPAD_LEFT, JOY_LEFT }, + { RETRO_DEVICE_ID_JOYPAD_RIGHT, JOY_RIGHT }, + }; + for (i = 0; i < MAX_BUTTONS; i++) + input_buf |= input_cb(player, RETRO_DEVICE_JOYPAD, 0, + bindmap[i].retro) ? bindmap[i].nes : 0; + } /* Turbo A and Turbo B buttons are * mapped to Joypad X and Joypad Y @@ -1587,7 +1633,7 @@ static void retro_run_blit(uint8_t *gfx) } if (ps2->interface_version != RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION) { - printf("HW render interface mismatch, expected %u, got %u!\n", + printf("HW render interface mismatch, expected %u, got %u!\n", RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION, ps2->interface_version); return; } @@ -1597,9 +1643,9 @@ static void retro_run_blit(uint8_t *gfx) ps2->coreTexture->PSM = GS_PSM_T8; ps2->coreTexture->ClutPSM = GS_PSM_CT16; ps2->coreTexture->Filter = GS_FILTER_LINEAR; - ps2->padding = (struct retro_hw_ps2_insets){ overscan_v ? 8.0f : 0.0f, - overscan_h ? 8.0f : 0.0f, - overscan_v ? 8.0f : 0.0f, + ps2->padding = (struct retro_hw_ps2_insets){ overscan_v ? 8.0f : 0.0f, + overscan_h ? 8.0f : 0.0f, + overscan_v ? 8.0f : 0.0f, overscan_h ? 8.0f : 0.0f}; } @@ -1985,7 +2031,6 @@ static char slash = '/'; #endif extern uint32_t iNESGameCRC32; -extern int option_ramstate; bool retro_load_game(const struct retro_game_info *game) { @@ -2048,24 +2093,23 @@ bool retro_load_game(const struct retro_game_info *game) struct retro_memory_descriptor descs[64]; struct retro_memory_map mmaps; - struct retro_variable var = {0}; if (!game) return false; - var.value = 0; - var.key = "fceumm_ramstate"; + /* initialize some of the default variables */ +#ifdef GEKKO + sndsamplerate = 32000; +#else + sndsamplerate = 48000; +#endif + sndquality = 0; + sndvolume = 150; + swapDuty = 0; - /* set this variable before calling PowerNES() */ - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - if (!strcmp(var.value, "random")) - option_ramstate = 2; - else if (!strcmp(var.value, "fill $00")) - option_ramstate = 1; - else - option_ramstate = 0; - } + /* Wii: initialize this or else last variable is passed through + * when loading another rom causing save state size change. */ + serialize_size = 0; PowerNES(); check_system_specs(); @@ -2103,7 +2147,7 @@ bool retro_load_game(const struct retro_game_info *game) for (i = 0; i < MAX_PORTS; i++) { FCEUI_SetInput(i, SI_GAMEPAD, &JSReturn, 0); - input_type[i] == RETRO_DEVICE_JOYPAD; + input_type[i] = RETRO_DEVICE_JOYPAD; } external_palette_exist = ipalette; @@ -2113,9 +2157,10 @@ bool retro_load_game(const struct retro_game_info *game) is_PAL = retro_get_region(); /* Save current loaded region info */ retro_set_custom_palette(); - FCEUD_SoundToggle(); + set_variables(); check_variables(true); + PowerNES(); FCEUI_DisableFourScore(1); diff --git a/src/drivers/libretro/libretro_core_options.h b/src/drivers/libretro/libretro_core_options.h new file mode 100644 index 0000000..39760bd --- /dev/null +++ b/src/drivers/libretro/libretro_core_options.h @@ -0,0 +1,563 @@ +#ifndef LIBRETRO_CORE_OPTIONS_H__ +#define LIBRETRO_CORE_OPTIONS_H__ + +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + ******************************** + * Core Option Definitions + ******************************** +*/ + +/* RETRO_LANGUAGE_ENGLISH */ + +/* Default language: + * - All other languages must include the same keys and values + * - Will be used as a fallback in the event that frontend language + * is not available + * - Will be used as a fallback for any missing entries in + * frontend language definition */ + +#define MAX_CORE_OPTIONS 32 + +struct retro_core_option_definition option_defs_common[] = { + { + "fceumm_region", + "Region Override", + "Force core to use NTSC, PAL or Dendy region timings.", + { + { "Auto", NULL }, + { "NTSC", NULL }, + { "PAL", NULL }, + { "Dendy", NULL }, + { NULL, NULL}, + }, + "Auto", + }, + { + "fceumm_aspect", + "Preferred aspect ratio", + "Choose preferred aspect ratio.", + { + { "8:7 PAR", NULL }, + { "4:3", NULL }, + { NULL, NULL}, + }, + "8:7 PAR", + }, + { + "fceumm_palette", + "Color Palette", + "Choose from pre-generated palettes, a custom 64x3 palette from file or raw format (needs to use a nes-decoder shader).", + { + { "default", NULL }, + { "asqrealc", NULL }, + { "nintendo-vc", NULL }, + { "rgb", NULL }, + { "yuv-v3", NULL }, + { "unsaturated-final", NULL }, + { "sony-cxa2025as-us", NULL }, + { "pal", NULL }, + { "bmf-final2", NULL }, + { "bmf-final3", NULL }, + { "smooth-fbx", NULL }, + { "composite-direct-fbx", NULL }, + { "pvm-style-d93-fbx", NULL }, + { "ntsc-hardware-fbx", NULL }, + { "nes-classic-fbx-fs", NULL }, + { "nescap", NULL }, + { "wavebeam", NULL }, + { "raw", NULL }, + { "custom", NULL }, + { NULL, NULL}, + }, + "default", + }, + { + "fceumm_up_down_allowed", + "Allow Opposing Directions", + "Allows simultaneous UP+DOWN or LEFT+RIGHT button combinations which can create different effects in some games.", + { + { "disabled", NULL }, + { "enabled", NULL }, + { NULL, NULL}, + }, + "disabled", + }, + +#ifdef PSP + { + "fceumm_overscan", + "Crop Overscan", + "Removes 8 pixel overscan from all sides", + { + { "enabled", NULL }, + { "disabled", NULL }, + { NULL, NULL}, + }, + "enabled", + }, +#else + { + "fceumm_overscan_h", + "Crop Overscan (Horizontal)", + "Removes 8 pixel from left and right side of the screen to simulate overscan seen on standard CRT television.", + { + { "disabled", NULL }, + { "enabled", NULL }, + { NULL, NULL}, + }, + "disabled", + }, + { + "fceumm_overscan_v", + "Crop Overscan (Vertical)", + "Removes 8 pixel from the top and bottom of the screen to simulate overscan seen on standard CRT television.", + { + { "disabled", NULL }, + { "enabled", NULL }, + { NULL, NULL}, + }, + "enabled", + }, +#endif + { + "fceumm_nospritelimit", + "No Sprite Limit", + "Removes the 8-per-scanline hardware limit. This reduces sprite flickering but can cause some games to glitch since some use this for effects.", + { + { "disabled", NULL }, + { "enabled", NULL }, + { NULL, NULL}, + }, + "disabled", + }, + { + "fceumm_sndvolume", + "Sound Volume", + "Change master volume level", + { + { "0", NULL }, + { "1", NULL }, + { "2", NULL }, + { "3", NULL }, + { "4", NULL }, + { "5", NULL }, + { "6", NULL }, + { "7", NULL }, + { "8", NULL }, + { "9", NULL }, + { "10", NULL }, + { NULL, NULL}, + }, + "7", + }, + { + "fceumm_sndquality", + "Sound Quality", + "Enable higher quality sounds in exchange for more processing power required", + { + { "Low", NULL }, + { "High", NULL }, + { "Very High", NULL }, + { NULL, NULL}, + }, + "Low", + }, + { + "fceumm_swapduty", + "Swap Duty Cycles", + "Simulates the sound from famiclones has the pulse wave channels duty cycle bits reversed.", + { + { "disabled", NULL }, + { "enabled", NULL }, + { NULL, NULL}, + }, + "disabled", + }, + { + "fceumm_turbo_enable", + "Turbo Enable", + "Enables or disables turbo buttons.", + { + { "None", NULL }, + { "Player 1", NULL }, + { "Player 2", NULL }, + { "Both", NULL }, + { NULL, NULL}, + }, + "None", + }, + { + "fceumm_turbo_delay", + "Turbo Delay (in frames)", + "Repeat rate of turbo buttons in frames.", + { + { "1", NULL }, + { "2", NULL }, + { "3", NULL }, + { "5", NULL }, + { "10", NULL }, + { "15", NULL }, + { "30", NULL }, + { "60", NULL }, + { NULL, NULL}, + }, + "3", + }, + { + "fceumm_zapper_mode", + "Zapper Mode", + "Selects device to use for zapper games.", + { + { "lightgun", NULL }, + { "touchscreen", NULL }, + { "mouse", NULL }, + { NULL, NULL}, + }, + "lightgun", + }, + { + "fceumm_show_crosshair", + "Show Crosshair", + "Shows or hides on-screen crosshairs when using a zapper.", + { + { "enabled", NULL }, + { "disabled", NULL }, + { NULL, NULL}, + }, + "enabled", + }, + { + "fceumm_overclocking", + "Overclocking", + "Enables or disables overclocking which can reduce slowdowns in some games. Postrender method is more compatible with every game with Vblank more effective for games like Contra Force.", + { + { "disabled", NULL }, + { "2x-Postrender", NULL }, + { "2x-VBlank", NULL }, + { NULL, NULL}, + }, + "disabled", + }, + { + "fceumm_ramstate", + "RAM power up state (Restart)", + "Choose RAM startup during power up. Some games rely on initial ram values for random generator as an example.", + { + { "fill $ff", NULL }, + { "fill $00", NULL }, + { "random", NULL }, + { NULL, NULL}, + }, + "fill $ff", + }, +#ifdef DEBUG + { + "fceumm_apu_1", + "Channel 1 (Square 1)", + "Enables or disables pulse wave generator audio output 1.", + { + { "enabled", NULL }, + { "disabled", NULL }, + { NULL, NULL}, + }, + "enabled", + }, + { + "fceumm_apu_2", + "Channel 2 (Square 2)", + "Enables or disables pulse wave generator audio output 2.", + { + { "enabled", NULL }, + { "disabled", NULL }, + { NULL, NULL}, + }, + "enabled", + }, + { + "fceumm_apu_3", + "Channel 3 (Triangle)", + "Enables or disables triangle wave generator audio output.", + { + { "enabled", NULL }, + { "disabled", NULL }, + { NULL, NULL}, + }, + "enabled", + }, + { + "fceumm_apu_4", + "Channel 4 (Noise)", + "Enables or disables noise generator audio output.", + { + { "enabled", NULL }, + { "disabled", NULL }, + { NULL, NULL}, + }, + "enabled", + }, + { + "fceumm_apu_5", + "Channel 5 (PCM)", + "Enables or disables delta modulation channel audio output.", + { + { "enabled", NULL }, + { "disabled", NULL }, + { NULL, NULL}, + }, + "enabled", + }, +#endif + + { NULL, NULL, NULL, { {0} }, NULL }, +}; + +struct retro_core_option_definition option_defs_empty = { + NULL, NULL, NULL, { {0} }, NULL +}; + +struct retro_core_option_definition option_defs_us[MAX_CORE_OPTIONS]; + +/* RETRO_LANGUAGE_JAPANESE */ + +/* RETRO_LANGUAGE_FRENCH */ + +/* RETRO_LANGUAGE_SPANISH */ + +/* RETRO_LANGUAGE_GERMAN */ + +/* RETRO_LANGUAGE_ITALIAN */ + +/* RETRO_LANGUAGE_DUTCH */ + +/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */ + +/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */ + +/* RETRO_LANGUAGE_RUSSIAN */ + +/* RETRO_LANGUAGE_KOREAN */ + +/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */ + +/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */ + +/* RETRO_LANGUAGE_ESPERANTO */ + +/* RETRO_LANGUAGE_POLISH */ + +/* RETRO_LANGUAGE_VIETNAMESE */ + +/* RETRO_LANGUAGE_ARABIC */ + +/* RETRO_LANGUAGE_GREEK */ + +/* RETRO_LANGUAGE_TURKISH */ + +/* + ******************************** + * Language Mapping + ******************************** +*/ + +struct retro_core_option_definition *option_defs_intl[RETRO_LANGUAGE_LAST] = { + option_defs_us, /* RETRO_LANGUAGE_ENGLISH */ + NULL, /* RETRO_LANGUAGE_JAPANESE */ + NULL, /* RETRO_LANGUAGE_FRENCH */ + NULL, /* RETRO_LANGUAGE_SPANISH */ + NULL, /* RETRO_LANGUAGE_GERMAN */ + NULL, /* RETRO_LANGUAGE_ITALIAN */ + NULL, /* RETRO_LANGUAGE_DUTCH */ + NULL, /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */ + NULL, /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */ + NULL, /* RETRO_LANGUAGE_RUSSIAN */ + NULL, /* RETRO_LANGUAGE_KOREAN */ + NULL, /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */ + NULL, /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */ + NULL, /* RETRO_LANGUAGE_ESPERANTO */ + NULL, /* RETRO_LANGUAGE_POLISH */ + NULL, /* RETRO_LANGUAGE_VIETNAMESE */ + NULL, /* RETRO_LANGUAGE_ARABIC */ + NULL, /* RETRO_LANGUAGE_GREEK */ + NULL, /* RETRO_LANGUAGE_TURKISH */ +}; + +/* + ******************************** + * Functions + ******************************** +*/ + +/* Handles configuration/setting of core options. + * Should only be called inside retro_set_environment(). + * > We place the function body in the header to avoid the + * necessity of adding more .c files (i.e. want this to + * be as painless as possible for core devs) + */ + +static INLINE void libretro_set_core_options(retro_environment_t environ_cb) +{ + unsigned version = 0; + + if (!environ_cb) + return; + + if (environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version) && (version == 1)) + { + struct retro_core_options_intl core_options_intl; + unsigned language = 0; + + core_options_intl.us = option_defs_us; + core_options_intl.local = NULL; + + if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) && + (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH)) + core_options_intl.local = option_defs_intl[language]; + + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_intl); + } + else + { + size_t i; + size_t option_index = 0; + size_t num_options = 0; + struct retro_variable *variables = NULL; + char **values_buf = NULL; + + /* Determine number of options + * > Note: We are going to skip a number of irrelevant + * core options when building the retro_variable array, + * but we'll allocate space for all of them. The difference + * in resource usage is negligible, and this allows us to + * keep the code 'cleaner' */ + while (true) + { + if (option_defs_us[num_options].key) + num_options++; + else + break; + } + + /* Allocate arrays */ + variables = (struct retro_variable *)calloc(num_options + 1, sizeof(struct retro_variable)); + values_buf = (char **)calloc(num_options, sizeof(char *)); + + if (!variables || !values_buf) + goto error; + + /* Copy parameters from option_defs_us array */ + for (i = 0; i < num_options; i++) + { + const char *key = option_defs_us[i].key; + const char *desc = option_defs_us[i].desc; + const char *default_value = option_defs_us[i].default_value; + struct retro_core_option_value *values = option_defs_us[i].values; + size_t buf_len = 3; + size_t default_index = 0; + + values_buf[i] = NULL; + + /* Skip options that are irrelevant when using the + * old style core options interface */ + if ((strcmp(key, "fceumm_advance_sound_options") == 0)) + continue; + + if (desc) + { + size_t num_values = 0; + + /* Determine number of values */ + while (true) + { + if (values[num_values].value) + { + /* Check if this is the default value */ + if (default_value) + if (strcmp(values[num_values].value, default_value) == 0) + default_index = num_values; + + buf_len += strlen(values[num_values].value); + num_values++; + } + else + break; + } + + /* Build values string */ + if (num_values > 1) + { + size_t j; + + buf_len += num_values - 1; + buf_len += strlen(desc); + + values_buf[i] = (char *)calloc(buf_len, sizeof(char)); + if (!values_buf[i]) + goto error; + + strcpy(values_buf[i], desc); + strcat(values_buf[i], "; "); + + /* Default value goes first */ + strcat(values_buf[i], values[default_index].value); + + /* Add remaining values */ + for (j = 0; j < num_values; j++) + { + if (j != default_index) + { + strcat(values_buf[i], "|"); + strcat(values_buf[i], values[j].value); + } + } + } + } + + variables[option_index].key = key; + variables[option_index].value = values_buf[i]; + option_index++; + } + + /* Set variables */ + environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables); + +error: + + /* Clean up */ + if (values_buf) + { + for (i = 0; i < num_options; i++) + { + if (values_buf[i]) + { + free(values_buf[i]); + values_buf[i] = NULL; + } + } + + free(values_buf); + values_buf = NULL; + } + + if (variables) + { + free(variables); + variables = NULL; + } + } +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/drivers/libretro/libretro_dipswitch.c b/src/drivers/libretro/libretro_dipswitch.c new file mode 100644 index 0000000..fb778c5 --- /dev/null +++ b/src/drivers/libretro/libretro_dipswitch.c @@ -0,0 +1,1403 @@ +#include +#include +#include + +#include "../../fceu.h" +#include "../../fceu-types.h" +#include "../../vsuni.h" +#include "../../git.h" +#include "../../driver.h" +#include "../../cart.h" + +#include "libretro_dipswitch.h" + +#define MAX_CORE_OPTIONS 8 +#define MAX_VALUES 10 + +extern CartInfo iNESCart; + +typedef struct { + const char *name; + uint8 value; +} SETTING; + +typedef struct { + const char *option_name; + SETTING settings[MAX_VALUES]; +} DIPSWITCH; + +typedef struct { + unsigned game_id; + const char *game_name; + DIPSWITCH core_options[MAX_CORE_OPTIONS]; +} VSUNIGAME; + +static VSUNIGAME dipswitch_battlecity = { + VS_BATTLECITY, "battlecity", + { + { "Credits for 2 Players", + { + { "2", 0x01 }, + { "1", 0x00 }, + { NULL, 0 }, + }, + }, + { "Lives", + { + { "5", 0x02 }, + { "3", 0x00 }, + { NULL, 0 }, + }, + }, + { "Demo Sounds", + { + { "disabled", 0x04 }, + { "enabled", 0x00 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + }, +}; + +static VSUNIGAME dipswitch_castlevania = { + VS_CASTLEVANIA, "castlevania", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x04 }, + { "1 Coin 3 Credits", 0x02 }, + { "2 Coins 1 Credit", 0x06 }, + { "3 Coins 1 Credit", 0x01 }, + { "4 Coins 1 Credit", 0x05 }, + { "5 Coins 1 Credit", 0x03 }, + { "Free Play", 0x07 }, + { NULL, 0 }, + }, + }, + { "Lives", + { + { "3", 0x00 }, + { "2", 0x08 }, + { NULL, 0 }, + } + }, + { "Bonus", + { + { "100k", 0x00 }, + { "200k", 0x20 }, + { "300k", 0x10 }, + { "400k", 0x30 }, + { NULL, 0 }, + }, + }, + { "Difficulty", + { + { "Normal", 0x00 }, + { "Hard", 0x40 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_clucluland = { + VS_CLUCLULAND, "clucluland", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x04 }, + { "1 Coin 3 Credits", 0x02 }, + { "1 Coin 4 Credits", 0x06 }, + { "2 Coins 1 Credit", 0x01 }, + { "3 Coins 1 Credit", 0x05 }, + { "4 Coins 1 Credit", 0x03 }, + { "Free Play", 0x07 }, + { NULL, 0 }, + }, + }, + { "Lives", + { + { "3", 0x00 }, + { "4", 0x40 }, + { "5", 0x20 }, + { "2", 0x60 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_drmario = { + VS_DRMARIO, "drmario", + { + { "Drop Rate Increase After", + { + { "7 Pills", 0x00 }, + { "8 Pills", 0x01 }, + { "9 Pills", 0x02 }, + { "10 Pills", 0x03 }, + { NULL, 0 }, + }, + }, + { "Virus Level", + { + { "1", 0x00 }, + { "3", 0x04 }, + { "5", 0x08 }, + { "7", 0x0c }, + { NULL, 0 }, + }, + }, + { "Drop Speed Up", + { + { "Slow", 0x00 }, + { "Medium", 0x10 }, + { "Fast", 0x20 }, + { "Fastest", 0x30 }, + { NULL, 0 }, + }, + }, + { "Free Play", + { + { "disabled", 0x00 }, + { "enabled", 0x40 }, + { NULL, 0 }, + }, + }, + { "Demo Sounds", + { + { "enabled", 0x80 }, + { "disabled", 0x00 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_duckhunt = { + VS_DUCKHUNT, "duckhunt", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x04 }, + { "1 Coin 3 Credits", 0x02 }, + { "2 Coins 1 Credit", 0x06 }, + { "3 Coins 1 Credit", 0x01 }, + { "4 Coins 1 Credit", 0x05 }, + { "5 Coins 1 Credit", 0x03 }, + { "Free Play", 0x07 }, + { NULL, 0 }, + }, + }, + { "Difficulty", + { + { "Normal", 0x08 }, + { "Medium", 0x10 }, + { "Hard", 0x18 }, + { "Easy", 0x00 }, + { NULL, 0 }, + }, + }, + { "Miss per game", + { + { "5", 0x20 }, + { "3", 0x00 }, + { NULL, 0 }, + }, + }, + { "Bonus Life", + { + { "30000", 0x00 }, + { "50000", 0x40 }, + { "80000", 0x80 }, + { "100000", 0xc0 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_excitebike = { + VS_EXITEBIKE, "excitebike", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x04 }, + { "1 Coin 3 Credits", 0x02 }, + { "1 Coin 4 Credits", 0x06 }, + { "2 Coins 1 Credit", 0x01 }, + { "3 Coins 1 Credit", 0x05 }, + { "4 Coins 1 Credit", 0x03 }, + { "Free Play", 0x07 }, + { NULL, 0 }, + }, + }, + { "Bonus Bike", + { + { "100k and Every 50k", 0x00 }, + { "100k Only", 0x08 }, + { "Every 100k", 0x10 }, + { "None", 0x18 }, + { NULL, 0 }, + }, + }, + { "1st Qualifying Time", + { + { "Easy", 0x00 }, + { "Hard", 0x20 }, + { NULL, 0 }, + }, + }, + { "2nd Qualifying Time", + { + { "Easy", 0x00 }, + { "Hard", 0x40 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_freedomforce = { + VS_FREEDOMFORCE, "freedomforce", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x04 }, + { "1 Coin 3 Credits", 0x02 }, + { "2 Coins 1 Credit", 0x06 }, + { "3 Coins 1 Credit", 0x01 }, + { "4 Coins 1 Credit", 0x05 }, + { "5 Coins 1 Credit", 0x03 }, + { "Free Play", 0x07 }, + { NULL, 0 }, + }, + }, + { "Health Awarded At", + { + { "10k 50k", 0x10 }, + { "20k 60k", 0x00 }, + { "20k 60k Every 60k", 0x08 }, + { "10k 50k Every 50k", 0x18 }, + { NULL, 0 }, + }, + }, + { "Difficulty (Damage)", + { + { "Normal", 0x00 }, + { "Easy", 0x40 }, + { "Hard", 0x20 }, + { "Hardest", 0x60 }, + { NULL, 0 }, + }, + }, + { "Difficulty (Enemy)", + { + { "Normal", 0x80 }, + { "Hard", 0x00 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_goonies = { + VS_GOONIES, "goonies", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x04 }, + { "1 Coin 3 Credits", 0x02 }, + { "2 Coins 1 Credit", 0x06 }, + { "3 Coins 1 Credit", 0x01 }, + { "4 Coins 1 Credit", 0x05 }, + { "5 Coins 1 Credit", 0x03 }, + { "Free Play", 0x07 }, + { NULL, 0 }, + }, + }, + { "Lives", + { + { "3", 0x08 }, + { "4", 0x00 }, + { NULL, 0 }, + }, + }, + { "Bonus", + { + { "40000", 0x00 }, + { "50000", 0x20 }, + { "60000", 0x10 }, + { "70000", 0x30 }, + { NULL, 0 }, + }, + }, + { "Timer", + { + { "Slow", 0x00 }, + { "Fast", 0x40 }, + { NULL, 0 }, + }, + }, + { "Demo Sounds", + { + { "enabled", 0x80 }, + { "disabled", 0x00 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_gradius = { + VS_GRADIUS, "gradius", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x04 }, + { "1 Coin 3 Credits", 0x02 }, + { "2 Coins 1 Credit", 0x06 }, + { "3 Coins 1 Credit", 0x01 }, + { "4 Coins 1 Credit", 0x05 }, + { "5 Coins 1 Credit", 0x03 }, + { "Free Play", 0x07 }, + { NULL, 0 }, + }, + }, + { "Lives", + { + { "3", 0x08 }, + { "4", 0x00 }, + { NULL, 0 }, + }, + }, + { "Bonus", + { + { "100k", 0x00 }, + { "200k", 0x20 }, + { "300k", 0x10 }, + { "400k", 0x30 }, + { NULL, 0 }, + }, + }, + { "Difficulty", + { + { "Normal", 0x00 }, + { "Hard", 0x40 }, + { NULL, 0 }, + }, + }, + { "Demo Sounds", + { + { "enabled", 0x80 }, + { "disabled", 0x00 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_gumshoe = { + VS_GUMSHOE, "gumshoe", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x04 }, + { "1 Coin 3 Credits", 0x02 }, + { "2 Coins 1 Credit", 0x06 }, + { "3 Coins 1 Credit", 0x01 }, + { "4 Coins 1 Credit", 0x05 }, + { "5 Coins 1 Credit", 0x03 }, + { "Free Play", 0x07 }, + { NULL, 0 }, + }, + }, + { "Difficulty", + { + { "Normal", 0x08 }, + { "Easy", 0x00 }, + { "Hard", 0x10 }, + { "Hardest", 0x18 }, + { NULL, 0 }, + }, + }, + { "Lives", + { + { "3", 0x20 }, + { "5", 0x00 }, + { NULL, 0 }, + }, + }, + { "Bullets per Balloon", + { + { "3", 0x00 }, + { "2", 0x40 }, + { NULL, 0 }, + }, + }, + { "Bonus Man Awarded", + { + { "At 50000", 0x00 }, + { "None", 0x80 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_hogansalley = { + VS_HOGANSALLEY, "hogansalley", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x04 }, + { "1 Coin 3 Credits", 0x02 }, + { "2 Coins 1 Credit", 0x06 }, + { "3 Coins 1 Credit", 0x01 }, + { "4 Coins 1 Credit", 0x05 }, + { "5 Coins 1 Credit", 0x03 }, + { "Free Play", 0x07 }, + { NULL, 0 }, + }, + }, + { "Difficulty", + { + { "Normal", 0x08 }, + { "Easy", 0x00 }, + { "Hard", 0x10 }, + { "Hardest", 0x18 }, + { NULL, 0 }, + }, + }, + { "Misses Per Game", + { + { "5", 0x20 }, + { "3", 0x00 }, + { NULL, 0 }, + }, + }, + { "Bonus Life", + { + { "30000", 0x00 }, + { "50000", 0x40 }, + { "80000", 0x80 }, + { "100000", 0xc0 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_iceclimber = { + VS_ICECLIMBER, "iceclimber", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x04 }, + { "1 Coin 3 Credits", 0x02 }, + { "1 Coin 4 Credits", 0x06 }, + { "2 Coins 1 Credit", 0x01 }, + { "3 Coins 1 Credit", 0x05 }, + { "4 Coins 1 Credit", 0x03 }, + { "Free Play", 0x07 }, + { NULL, 0 }, + }, + }, + { "Lives", + { + { "3", 0x00 }, + { "4", 0x10 }, + { "5", 0x08 }, + { "7", 0x18 }, + { NULL, 0 }, + }, + }, + { "Difficulty", + { + { "Easy", 0x00 }, + { "Hard", 0x20 }, + { NULL, 0 }, + }, + }, + { "Time before bear appears", + { + { "Long", 0x00 }, + { "Short", 0x40 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_jajamaru = { + VS_JAJAMARU, "jajamaru", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x04 }, + { "1 Coin 3 Credits", 0x02 }, + { "1 Coin 4 Credits", 0x06 }, + { "2 Coins 1 Credit", 0x01 }, + { "3 Coins 1 Credit", 0x05 }, + { "4 Coins 1 Credit", 0x03 }, + { "Free Play", 0x07 }, + { NULL, 0 }, + }, + }, + { "Lives", + { + { "3", 0x00 }, + { "4", 0x10 }, + { "5", 0x08 }, + { NULL, 0 }, + }, + }, + { "Demo Sounds", + { + { "enabled", 0x80 }, + { "disabled", 0x00 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_machrider = { + VS_MACHRIDER, "machrider", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x04 }, + { "1 Coin 3 Credits", 0x02 }, + { "1 Coin 4 Credits", 0x06 }, + { "2 Coins 1 Credit", 0x01 }, + { "3 Coins 1 Credit", 0x05 }, + { "4 Coins 1 Credit", 0x03 }, + { "Free Play", 0x07 }, + { NULL, 0 }, + }, + }, + { "Time", + { + { "280 (Easy)", 0x00 }, + { "250", 0x10 }, + { "220", 0x08 }, + { "200 (Hard)", 0x18 }, + { NULL, 0 }, + }, + }, + { "Enemies", + { + { "Less", 0x00 }, + { "More", 0x40 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_mightybj = { + VS_MIGHTYBOMBJACK, "mightybj", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x04 }, + { "1 Coin 3 Credits", 0x02 }, + { "1 Coin 4 Credits", 0x06 }, + { "2 Coins 1 Credit", 0x01 }, + { "3 Coins 1 Credit", 0x05 }, + { "4 Coins 1 Credit", 0x03 }, + { "5 Coins 1 Credit", 0x07 }, + { NULL, 0 }, + }, + }, + { "Lives", + { + { "3", 0x00 }, + { "4", 0x08 }, + { "5", 0x18 }, + { "2", 0x10 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_pinball = { + VS_PINBALL, "pinball", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x01 }, + { "1 Coin 2 Credits", 0x06 }, + { "1 Coin 3 Credits", 0x02 }, + { "1 Coin 4 Credits", 0x04 }, + { "2 Coins 1 Credit", 0x05 }, + { "3 Coins 1 Credit", 0x03 }, + { "4 Coins 1 Credit", 0x07 }, + { "Free Play", 0x00 }, + { NULL, 0 }, + }, + }, + { "Side Drain Walls", + { + { "High", 0x00 }, + { "Low", 0x08 }, + { NULL, 0 }, + }, + }, + { "Bonus Life", + { + { "50000", 0x00 }, + { "70000", 0x10 }, + { NULL, 0 }, + }, + }, + { "Balls", + { + { "3", 0x00 }, + { "4", 0x40 }, + { "5", 0x20 }, + { "2", 0x60 }, + { NULL, 0 }, + } + }, + { "Ball Speed", + { + { "Slow", 0x00 }, + { "Fast", 0x80 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_platoon = { + VS_PLATOON, "platoon", + { + { "Demo Sounds", + { + { "enabled", 0x00 }, + { "disabled", 0x04 }, + { NULL, 0 }, + }, + }, + { "Difficulty", + { + { "Normal", 0x08 }, + { "Medium", 0x10 }, + { "Hard", 0x18 }, + { "Easy", 0x00 }, + { NULL, 0 }, + } + }, + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x20 }, + { "1 Coin 3 Credits", 0x40 }, + { "2 Coins 1 Credit", 0x60 }, + { "3 Coins 1 Credit", 0x80 }, + { "4 Coins 1 Credit", 0xa0 }, + { "5 Coins 1 Credit", 0xc0 }, + { "Free Play", 0xe0 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_rbibaseball = { + VS_RBIBASEBALL, "atari_rbibb", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x01 }, + { "2 Coins 1 Credit", 0x02 }, + { "3 Coins 1 Credit", 0x03 }, + { NULL, 0 }, + }, + }, + { "1p-inn 2p-inn time-min", + { + { "2 2 4", 0x0c }, + { "3 2 6", 0x00 }, + { "4 3 7", 0x08 }, + { "2 1 3", 0x04 }, + { NULL, 0 }, + } + }, + { "Demo Sounds", + { + { "enabled", 0x00 }, + { "disabled", 0x10 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_slalom = { + VS_SLALOM, "slalom", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x04 }, + { "1 Coin 3 Credits", 0x02 }, + { "2 Coins 1 Credit", 0x06 }, + { "3 Coins 1 Credit", 0x01 }, + { "4 Coins 1 Credit", 0x05 }, + { "5 Coins 1 Credit", 0x03 }, + { "Free Play", 0x07 }, + { NULL, 0 }, + }, + }, + { "Freestyle Points", + { + { "Hold Time", 0x08 }, + { "Left Right", 0x00 }, + { NULL, 0 }, + }, + }, + { "Difficulty", + { + { "Normal", 0x10 }, + { "Medium", 0x20 }, + { "Hard", 0x30 }, + { "Easy", 0x00 }, + { NULL, 0 }, + }, + }, + { "Allow Continue", + { + { "enabled", 0x00 }, + { "disabled", 0x40 }, + { NULL, 0 }, + }, + }, + { "Inverted Input", + { + { "disabled", 0x00 }, + { "enabled", 0x80 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_smb = { + VS_SMB, "smb", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x06 }, + { "1 Coin 3 Credits", 0x01 }, + { "1 Coin 4 Credits", 0x05 }, + { "1 Coin 5 Credits", 0x03 }, + { "2 Coins 1 Credit", 0x04 }, + { "3 Coins 1 Credit", 0x02 }, + { "Free Play", 0x07 }, + { NULL, 0 }, + }, + }, + { "Lives", + { + { "3", 0x00 }, + { "2", 0x08 }, + { NULL, 0 }, + }, + }, + { "Bonus Life", + { + { "100 coins", 0x00 }, + { "150 coins", 0x20 }, + { "200 coins", 0x10 }, + { "250 coins", 0x30 }, + { NULL, 0 }, + }, + }, + { "Timer", + { + { "Slow", 0x00 }, + { "Fast", 0x40 }, + { NULL, 0 }, + }, + }, + { "Continue Lives", + { + { "3", 0x80 }, + { "4", 0x00 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_soccer = { + VS_SOCCER, "soccer", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x04 }, + { "1 Coin 3 Credits", 0x02 }, + { "1 Coin 4 Credits", 0x06 }, + { "2 Coins 1 Credit", 0x01 }, + { "3 Coins 1 Credit", 0x05 }, + { "4 Coins 1 Credit", 0x03 }, + { "Free Play", 0x07 }, + { NULL, 0 }, + }, + }, + { "Points Timer", + { + { "1000 Pts", 0x08 }, + { "1200 Pts", 0x18 }, + { "600 Pts", 0x00 }, + { "800 Pts", 0x10 }, + { NULL, 0 }, + }, + }, + { "Difficulty", + { + { "Normal", 0x40 }, + { "Medium", 0x20 }, + { "Hard", 0x60 }, + { "Easy", 0x00 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_starluster = { + VS_STARLUSTER, "starluster", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x02 }, + { "2 Coins 1 Credit", 0x01 }, + { "3 Coins 1 Credit", 0x03 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_superskykid = { + VS_SUPERSKYKID, "superskykid", + { + { "Difficulty", + { + + { "Normal", 0x01 }, + { "Medium", 0x02 }, + { "Hard", 0x03 }, + { "Easy", 0x00 }, + { NULL, 0 }, + } + }, + { "Lives", + { + { "3", 0x04 }, + { "2", 0x00 }, + { NULL, 0 }, + }, + }, + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x08 }, + { "2 Coins 1 Credit", 0x10 }, + { "3 Coins 1 Credit", 0x18 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_superxevious = { + VS_SUPERXEVIOUS, "superxevious", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x10 }, + { "2 Coins 1 Credit", 0x20 }, + { "3 Coins 1 Credit", 0x30 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_tetris = { + VS_TETRIS, "tetris", + { + { "Difficulty", + { + { "Normal", 0x04 }, + { "Medium", 0x08 }, + { "Hard", 0x0c }, + { "Easy", 0x00 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_tkoboxing = { + VS_TKOBOXING, "tkoboxing", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x01 }, + { "2 Coins 1 Credit", 0x02 }, + { "3 Coins 1 Credit", 0x03 }, + { NULL, 0 }, + }, + }, + { "Difficulty", + { + { "Normal", 0x04 }, + { "Hard", 0x08 }, + { "Very Hard", 0x0c }, + { "Easy", 0x00 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +static VSUNIGAME dipswitch_topgun = { + VS_TOPGUN, "topgun", + { + { "Coinage", + { + { "1 Coin 1 Credit", 0x00 }, + { "1 Coin 2 Credits", 0x04 }, + { "1 Coin 3 Credits", 0x02 }, + { "2 Coins 1 Credit", 0x01 }, + { "3 Coins 1 Credit", 0x05 }, + { "4 Coins 1 Credit", 0x06 }, + { "5 Coins 1 Credit", 0x03 }, + { "Free Play", 0x07 }, + { NULL, 0 }, + }, + }, + { "Lives per Coin", + { + { "3-12 Max", 0x00 }, + { "2-9 Max", 0x08 }, + { NULL, 0 }, + }, + }, + { "Bonus Life", + { + { "30k and Every 50k", 0x00 }, + { "50k and Every 100k", 0x20 }, + { "100k and Every 150k", 0x10 }, + { "200k and Every 200k", 0x30 }, + { NULL, 0 }, + }, + }, + { "Difficulty", + { + { "Easy", 0x00 }, + { "Hard", 0x40 }, + { NULL, 0 }, + }, + }, + { "Demo Sounds", + { + { "enabled", 0x80 }, + { "disabled", 0x00 }, + { NULL, 0 }, + }, + }, + { NULL, { {0} } }, + } +}; + +enum { + DPSW_NONE = 0, + DPSW_VSUNI, + DPSW_NWC, +}; + +static struct retro_core_option_definition option_defs_empty = { + NULL, NULL, NULL, { {0} }, NULL +}; + +static struct retro_core_option_definition vscoreopt[MAX_CORE_OPTIONS]; +static VSUNIGAME *vsgame = NULL; + +static char *core_key[MAX_CORE_OPTIONS]; +static unsigned dipswitch_type = DPSW_NONE; +static unsigned numCoreOptions = 0; +static unsigned numValues[MAX_VALUES] = {0}; +static uint8 dipswitchPreset = 0; + +static const char *str_to_corekey(char *s) +{ + char *str = s; + unsigned i = 0; + + while (str[i] != '\0') + { + if (str[i] == ' ') + str[i] = '_'; + i++; + } + str[i] = '\0'; + + return str; +} + +static void make_core_options(struct retro_core_option_definition *vs_core_options) +{ + unsigned i, j; + + for (i = 0; i < numCoreOptions; i++) + { + struct retro_core_option_value vars_empty = { NULL, NULL }; + const char *game_name = vsgame->game_name; + const char *option_name = vsgame->core_options[i].option_name; + char key[100] = {0}; + + /* Set core key and sanitize string */ + sprintf(key, "fceumm_dipswitch_%s-%s", game_name, option_name); + core_key[i] = calloc(strlen(key) + 1, sizeof(char)); + strcpy(core_key[i], key); + vs_core_options[i].key = str_to_corekey(core_key[i]); + + /* Set desc */ + vs_core_options[i].desc = option_name; + + /* Set info */ + vs_core_options[i].info = NULL; + + /* Set core values */ + for (j = 0; j < numValues[i]; j++) { + const char *var_value = vsgame->core_options[i].settings[j].name; + vs_core_options[i].values[j].value = var_value; + } + + vs_core_options[i].values[j] = vars_empty; + + /* Set default value. Top entry used as default */ + vs_core_options[i].default_value = vsgame->core_options[i].settings[0].name; + } +} + +static VSUNIGAME *get_vsuni_dipswitch(unsigned id) +{ + switch (id) { + case VS_BATTLECITY: + return (&dipswitch_battlecity); + case VS_CASTLEVANIA: + return (&dipswitch_castlevania); + case VS_CLUCLULAND: + return (&dipswitch_clucluland); + case VS_DRMARIO: + return (&dipswitch_drmario); + case VS_DUCKHUNT: + return (&dipswitch_duckhunt); + case VS_EXITEBIKE: + return (&dipswitch_excitebike); + case VS_FREEDOMFORCE: + return (&dipswitch_freedomforce); + case VS_GOONIES: + return (&dipswitch_goonies); + case VS_GRADIUS: + return (&dipswitch_gradius); + case VS_GUMSHOE: + return (&dipswitch_gumshoe); + case VS_HOGANSALLEY: + return (&dipswitch_hogansalley); + case VS_ICECLIMBER: + return (&dipswitch_iceclimber); + case VS_JAJAMARU: + return (&dipswitch_jajamaru); + /* case VS_LADIESGOLF: */ + /* case VS_STROKEANDMATCHGOLF: */ + case VS_MACHRIDER: + return (&dipswitch_machrider); + case VS_MIGHTYBOMBJACK: + return (&dipswitch_mightybj); + case VS_PINBALL: + return (&dipswitch_pinball); + case VS_PLATOON: + return (&dipswitch_platoon); + case VS_RBIBASEBALL: + return (&dipswitch_rbibaseball); + case VS_SLALOM: + return (&dipswitch_slalom); + case VS_SMB: + return (&dipswitch_smb); + case VS_SOCCER: + return (&dipswitch_soccer); + case VS_STARLUSTER: + return (&dipswitch_starluster); + case VS_SUPERSKYKID: + return (&dipswitch_superskykid); + case VS_SUPERXEVIOUS: + return (&dipswitch_superxevious); + case VS_TETRIS: + return (&dipswitch_tetris); + case VS_TKOBOXING: + return (&dipswitch_tkoboxing); + case VS_TOPGUN: + return (&dipswitch_topgun); + } + + FCEU_printf("No dipsettings found. %d\n", id); + return (NULL); +} + +static void update_dipswitch_vsuni(void) +{ + unsigned index_key; + uint8 vsdip_new = 0; + uint8 last_vsdip = FCEUI_VSUniGetDIPs(); + + for (index_key = 0; index_key < numCoreOptions; index_key++) + { + struct retro_variable var = { NULL, NULL }; + const char *key = vscoreopt[index_key].key; + unsigned index_value; + + var.key = key; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) == 0) + continue; + + for (index_value = 0; index_value < numValues[index_key]; index_value++) + { + const char *var_value = vscoreopt[index_key].values[index_value].value; + uint8 value = 0; + + if (strcmp(var.value, var_value) != 0) + continue; + + value = vsgame->core_options[index_key].settings[index_value].value; + vsdip_new |= value; + } + } + + vsdip_new |= dipswitchPreset; /* Append any default preset to new value */ + if (last_vsdip != vsdip_new) + { + vsdip = vsdip_new; +#ifdef DEBUG + FCEU_printf("Dipswitch changed %d%d%d%d%d%d%d%d\n", + (vsdip >> 0) & 1, (vsdip >> 1) & 1, (vsdip >> 2) & 1, (vsdip >> 3) & 1, + (vsdip >> 4) & 1, (vsdip >> 5) & 1, (vsdip >> 6) & 1, (vsdip >> 7) & 1); +#endif + } +} + +/* Nintendo World Championship */ +static struct retro_core_option_definition dipswitch_nwc[] = { + { + "fceumm_dipswitch_nwc_swa", + "Dipswitch SW1 (+18.7secs)", + "Adds 18.7 seconds to total time. Total time = 5 mins + enabled dipswitches.", + { + { "disabled", NULL }, + { "enabled", NULL }, + { NULL, NULL}, + }, + "disabled", + }, + { + "fceumm_dipswitch_nwc_swb", + "Dipswitch SW1 (+37.5s)", + "Adds 37.5 seconds to total time. Total time = 5 mins + enabled dipswitches.", + { + { "disabled", NULL }, + { "enabled", NULL }, + { NULL, NULL}, + }, + "disabled", + }, + { + "fceumm_dipswitch_nwc_swc", + "Dipswitch SW1 (+1m 15s)", + "Adds 1 minute and 15 seconds to total time. Total time = 5 mins + enabled dipswitches.", + { + { "disabled", NULL }, + { "enabled", NULL }, + { NULL, NULL}, + }, + "enabled", + }, + { + "fceumm_dipswitch_nwc_swd", + "Dipswitch SW1 (+2m 30s)", + "Adds 2 minutes and 30 seconds to total time. Total time = 5 mins + time of enabled dipswitches.", + { + { "disabled", NULL }, + { "enabled", NULL }, + { NULL, NULL}, + }, + "disabled", + }, + + { NULL, NULL, NULL, { {0} }, NULL }, +}; + +static void update_dipswitch_nwc(void) +{ + unsigned i, dips = 0x00; + + for (i = 0; i < 4; i++) + { + struct retro_variable var = { NULL, NULL }; + const char *key = dipswitch_nwc[i].key; + + var.key = key; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) == 0) + continue; + if (strcmp(var.value, "enabled") != 0) + continue; + dips |= (1 << i); + } + + if (GameInfo->cspecial != dips) + { + GameInfo->cspecial = dips; +#ifdef DEBUG + FCEU_printf("Dipswitch changed = %d%d%d%d\n", (dips >> 0) & 1, + (dips >> 1) & 1, (dips >> 2) & 1, (dips >> 3) & 1); +#endif + } +} + +size_t set_dipswitch_variables(unsigned current_index, struct retro_core_option_definition *vars) +{ + unsigned index = current_index; + int dipsw_size = 0; + + /* VSUNI Dipswitch */ + if (GameInfo->type == GIT_VSUNI) + { + dipswitchPreset = FCEUI_VSUniGetDIPs(); + vsgame = get_vsuni_dipswitch(GameInfo->gameid); + if (vsgame) + { + unsigned i, j; + + numCoreOptions = 0; + dipswitch_type = DPSW_VSUNI; + + /* Initialize dipswitch struct with empty values */ + for (i = 0; i < MAX_CORE_OPTIONS; i++) + vscoreopt[i] = option_defs_empty; + + /* Count number of core options and the number of values for each */ + for (i = 0; i < MAX_CORE_OPTIONS; i++) { + if (vsgame->core_options[i].option_name) { + for (j = 0; j < MAX_VALUES; j++) { + if (vsgame->core_options[i].settings[j].name) + numValues[i]++; + } + numCoreOptions++; + } + } + + make_core_options(vscoreopt); + + /* Append dipswitch struct to main core options struct */ + while (vscoreopt[dipsw_size].key) { + vars[index] = vscoreopt[dipsw_size]; + index++; + dipsw_size++; + } + } + return (dipsw_size); + } + + /* Nintendo World Championship cart (Mapper 105)*/ + if (iNESCart.mapper == 105) + { + dipswitch_type = DPSW_NWC; + + while (dipswitch_nwc[dipsw_size].key) { + vars[index] = dipswitch_nwc[dipsw_size]; + index++; + dipsw_size++; + } + return (dipsw_size); + } + + dipswitch_type = DPSW_NONE; + return (0); +} + +void update_dipswitch(void) +{ + switch (dipswitch_type) { + case DPSW_VSUNI: + update_dipswitch_vsuni(); + break; + case DPSW_NWC: + update_dipswitch_nwc(); + break; + } +} + +void DPSW_Cleanup(void) +{ + unsigned i; + + for (i = 0; i < MAX_CORE_OPTIONS; i++) { + if (core_key[i]) { + free(core_key[i]); + core_key[i] = NULL; + } + } +} diff --git a/src/drivers/libretro/libretro_dipswitch.h b/src/drivers/libretro/libretro_dipswitch.h new file mode 100644 index 0000000..bf6ace7 --- /dev/null +++ b/src/drivers/libretro/libretro_dipswitch.h @@ -0,0 +1,12 @@ +#ifndef __VSUNI_DIPSWITCH__ +#define __VSUNI_DIPSWITCH__ + +#include + +size_t set_dipswitch_variables(unsigned current_index, struct retro_core_option_definition *vars); +void update_dipswitch(void); +void DPSW_Cleanup(void); + +extern retro_environment_t environ_cb; + +#endif /* __VSUNI_DIPSWITCH__ */ diff --git a/src/git.h b/src/git.h index 3645168..d14e792 100644 --- a/src/git.h +++ b/src/git.h @@ -25,6 +25,7 @@ typedef struct { uint8 MD5[16]; int soundrate; /* For Ogg Vorbis expansion sound wacky support. 0 for default. */ int soundchan; /* Number of sound channels. */ + int gameid; /* Currently used for VS game id for per-game dipswitch */ } FCEUGI; #endif diff --git a/src/ines-correct.h b/src/ines-correct.h index 359c7e9..b18c35f 100644 --- a/src/ines-correct.h +++ b/src/ines-correct.h @@ -49,7 +49,7 @@ {0x52ab2d17, 1, 8}, /* Toukyou Pachi-Slot Adventure (Japan) (Rev 0) */ {0x934db14a, 1, -1},/* All-Pro Basketball */ {0xf74dfc91, 1, -1},/* Win, Lose, or Draw */ - {0xe6a477b2, 2, 0}, /* 3-D WorldRunner (USA) */ + {0xe6a477b2, 2, 1}, /* 3-D WorldRunner (USA) */ {0x9ea1dc76, 2, 0}, /* Rainbow Islands */ {0x6d65cac6, 2, 0}, /* Terra Cresta */ {0xe1b260da, 2, 1}, /* Argos no Senshi */ @@ -79,7 +79,7 @@ {0xbc065fc3, 3, 1}, /* Pipe Dream */ {0xc9ee15a7, 3, -1}, /* 3 is probably best. 41 WILL NOT WORK. */ {0x97b6cb19, 4, -1},/* Aladdin (SuperGame) (Mapper 4) [!] */ - {0xd97c31b0, 4, 1}, /* Rasaaru Ishii no Childs Quest (J) */ + {0xd97c31b0, 206, 1}, /* Rasaaru Ishii no Childs Quest (J) */ {0x404b2e8b, 4, 2}, /* Rad Racer 2 */ {0x15141401, 4, 8}, /* Asmik Kun Land */ {0x4cccd878, 4, 8}, /* Cat Ninden Teyandee */ @@ -116,24 +116,36 @@ {0x5555fca3, 32, 8}, {0x283ad224, 32, 8}, /* Ai Sensei no Oshiete */ {0x243a8735, 32, 0x10|4}, /* Major League */ - {0xbc7b1d0f, 33, -1}, /* Bakushou!! Jinsei Gekijou 2 (J) [!] */ + {0x8a7d0abe, 33, 8}, /* Akira (J) [!] */ + {0x376138d8, 33, 8}, /* Akira (J) [a1] */ + {0xadf606f6, 33, 8}, /* Bakushou!! Jinsei Gekijou (J) [!] */ + {0xbc7b1d0f, 33, 8}, /* Bakushou!! Jinsei Gekijou 2 (J) [!] */ + {0x7a497ae3, 33, 8}, /* Don Doko Don (J) [!] */ + {0xbaca10a9, 33, 8}, /* Golf Ko Open (J) [!] */ + {0xf80bdc50, 33, 8}, /* Insector X (J) [!] */ + {0x2a6559a1, 33, 8}, /* Operation Wolf (J) [!] */ + {0xaeb7fce9, 33, 8}, /* Power Blazer (J) [!] */ + {0xd920f9df, 33, 8}, /* Takeshi no Sengoku Fuuunji (J) [!] */ + {0x3cd4b420, 33, 8}, /* Takeshi no Sengoku Fuuunji (Japan) (Beta) */ {0x4c7c1af3, 34, 1}, /* Caesar's Palace */ {0x932ff06e, 34, 1}, /* Classic Concentration */ {0xf46ef39a, 37, -1}, /* Super Mario Bros. + Tetris + Nintendo World Cup (E) [!] */ {0x7ccb12a3, 43, -1}, /* SMB2j */ {0x6c71feae, 45, -1}, /* Kunio 8-in-1 */ - {0xe2c94bc2, 48, -1}, /* Super Bros 8 (Unl) [!] */ - {0xaebd6549, 48, 8}, /* Bakushou!! Jinsei Gekijou 3 */ - {0x6cdc0cd9, 48, 8}, /* Bubble Bobble 2 */ - {0x99c395f9, 48, 8}, /* Captain Saver */ - {0xa7b0536c, 48, 8}, /* Don Doko Don 2 */ {0x40c0ad47, 48, 8}, /* Flintstones 2 */ - {0x1500e835, 48, 8}, /* Jetsons (J) */ + {0xaebd6549, 48, 8}, /* Bakushou!! Jinsei Gekijou 3 (J) [!] */ + {0x6cdc0cd9, 48, 8}, /* Bubble Bobble 2 (J) */ + {0x99c395f9, 48, 8}, /* Captain Saver (J) */ + {0xa7b0536c, 48, 8}, /* Don Doko Don 2 (J) [!] */ + {0xb17c828a, 48, 8}, /* Don Doko Don 2 (J) [a1] */ + {0x10e24006, 48, 8}, /* Flintstones, The - The Rescue of Dino & Hoppy (J) */ + {0x1500e835, 48, 8}, /* Jetsons, The - Cogswell's Caper! (J) */ + {0xe2c94bc2, 48, 8}, /* Super Bros 8 (Unl) [!] */ {0xa912b064, 51|0x800, 8}, /* 11-in-1 Ball Games(has CHR ROM when it shouldn't) */ {0x39ab0fc7, 64, 8}, /* Hard Drivin' (USA) (Proto) (Unl) */ {0xb19a55dd, 64, 8}, /* Road Runner */ {0xf92be3ec, 64, -1}, /* Rolling Thunder */ - {0xd114f544, 66, 1}, /* AV Super Real Pachinko (Japan) (Unl) */ + {0xd114f544, 66, 0}, /* AV Super Real Pachinko (Japan) (Unl) */ {0xe84274c5, 66, 1}, /* Mississippi Satsujin Jiken (J) [h2] */ {0xbde3ae9b, 66, 1}, /* Doraemon */ {0x9552e8df, 66, 1}, /* Dragon Ball */ @@ -142,7 +154,7 @@ {0xdd8ed0f7, 70, 1}, /* Kamen Rider Club */ {0xbba58be5, 70, -1}, /* Family Trainer - Manhattan Police */ {0x370ceb65, 70, -1}, /* Family Trainer - Meiro Dai Sakusen */ - {0x86be4746, 71, -1}, /* Dooly Bravo Land (Korea) (Unl) */ + {0x86be4746, 2, -1}, /* Dooly Bravo Land (Korea) (Unl) */ {0xe62e3382, 71, -1}, /* Mig-29 Soviet Fighter */ {0xac7b0742, 71, -1}, /* Golden KTV (Ch) [!], not actually 71, but UNROM without BUS conflict */ {0x054bd3e9, 74, -1}, /* Di 4 Ci - Ji Qi Ren Dai Zhan (As) */ @@ -159,7 +171,8 @@ {0xd2699893, 88, 0}, /* Dragon Spirit */ {0xbb7c5f7a, 89, 8}, /* Mito Koumon or something similar */ {0x10119e6b, 93, 8}, /* Fantasy Zone (Japan) */ - {0x0da5e32e, 101, -1}, /* Uruusey Yatsura */ + {0x2b750bf9, 101, 1}, /* Urusei Yatsura - Lum no Wedding Bell (Japan) (Beta) */ + {0x0da5e32e, 101, 1}, /* Urusei Yatsura - Lum no Wedding Bell (Japan) */ {0x6096f84e, 104, 1}, /* Pegasus 5-in-1 (Golden Five) (Unl) */ {0x3d3ff543, 113, 0}, /* Kazama Jun to Asama Yuuko no AV Dragon Mahjong (Japan) (Unl) */ {0x68379fdb, 113, 1}, /* Pipemania (Australia) (HES) (Unl) */ @@ -167,7 +180,6 @@ {0x0d98db53, 114, -1}, /* Pocahontas */ {0x4e7729ff, 114, -1}, /* Super Donkey Kong */ {0xc5e5c5b2, 115, -1}, /* Bao Qing Tian (As).nes */ - {0xa1dc16c0, 116, -1}, /* Street Heroes (Sachen) [b1] */ {0xe40dfb7e, 116, -1}, /* Somari (P conf.) */ {0xc9371ebb, 116, -1}, /* Somari (W conf.) */ {0x78b657ac, 118, -1}, /* Armadillo */ @@ -296,7 +308,7 @@ {0x2447e03b, 210, 1}, /* Top Striker */ {0x1dc0f740, 210, 1}, /* Wagyan Land 2 */ {0xd323b806, 210, 1}, /* Wagyan Land 3 */ - {0xbd523011, 210, 0}, /* Dream Master */ + {0xbd523011, 210, 0}, /* Namco Prism Zone - Dream Master (Japan) */ {0x5daae69a, 211, -1}, /* Aladdin - Return of Jaffar, The (Unl) [!] */ {0x1ec1dfeb, 217, -1}, /* 255-in-1 (Cut version) [p1] */ {0x046d70cc, 217, -1}, /* 500-in-1 (Anim Splash, Alt Mapper)[p1][!] */ @@ -305,18 +317,63 @@ {0x62ef6c79, 232, 8}, /* Quattro Sports -Aladdin */ {0x2705eaeb, 234, -1}, /* Maxi 15 */ {0x6f12afc5, 235, -1}, /* Golden Game 150-in-1 */ - {0xfb2b6b10, 241, -1}, /* Fan Kong Jing Ying (Ch) */ - {0xb5e83c9a, 241, -1}, /* Xing Ji Zheng Ba (Ch) */ {0x2537b3e6, 241, -1}, /* Dance Xtreme - Prima (Unl) */ {0x11611e89, 241, -1}, /* Darkseed (Unl) [p1] */ {0x81a37827, 241, -1}, /* Darkseed (Unl) [p1][b1] */ - {0xc2730c30, 241, -1}, /* Deadly Towers (U) [!] */ - {0xa21e675c, 241, -1}, /* Mashou (J) [!] */ + {0xfb2b6b10, 241, -1}, /* Fan Kong Jing Ying (Ch) */ + {0xb5e83c9a, 241, -1}, /* Xing Ji Zheng Ba (Ch) */ {0x368c19a8, 241, -1}, /* LIKO Study Cartridge 3-in-1 (Unl) [!] */ {0x54d98b79, 241, -1}, /* Titanic 1912 (Unl) */ + {0xc2730c30, 34, 0}, /* Deadly Towers (U) [!] */ + {0xa21e675c, 34, 0}, /* Mashou (J) [!] */ {0x6bea1235, 245, -1}, /* MMC3 cart, but with nobanking applied to CHR-RAM, so let it be there */ {0x345ee51a, 245, -1}, /* DQ4c */ {0x57514c6c, 245, -1}, /* Yong Zhe Dou E Long - Dragon Quest VI (Ch) */ + {0xdb9d71b7, 114, -1}, /* Super Donkey Kong (Unl) [o1] */ + {0x61fc4d20, 224, 0}, /* Pokemon HeartGold (KT-008 PCB)(Ch)[!] */ + {0x4d735cb1, 224, 0}, /* Pokemon Platinum (KT-008 PCB)(Ch)[!] */ + {0x4f427110, 224, 0}, /* Pokemon Platinum Alt title 1 (KT-008 PCB)(Ch)[!] */ + {0xe001de16, 224, 0}, /* Pokemon Platinum Alt title 2 (KT-008 PCB)(Ch)[!] */ + {0xbdbe3c96, 238, 1}, /* Contra Fighter (Unl) */ + {0xcfe02ada, 1, -1}, /* Darkman (E) [!] */ + {0xcb53c523, 11, 1}, /* King Neptune's Adventure (Color Dreams) [!] */ + {0x6e149729, 189, -1}, /* Master Fighter II (Unl) [a1] */ + {0x60bfeb0c, 90, -1}, /* Mortal Kombat 2 (Unl) [!] */ + {0x247cc73d, 150, -1}, /* Poker II (Sachen) [!] */ + {0xe41b440f, 3, 0}, /* Sidewinder (Joy Van) */ + {0x1f1326d4, 121, 0}, /* Super Sonic 5 (1997) (Unl) [!] */ + {0xb0c871c5, 3, 1}, /* Wei Lai Xiao Zi (Joy Van) */ + {0xb3be2f71, 3, 0}, /* Yanshan Chess (Unl) */ + {0x8dedea07, 3, 1}, /* Shui Guo Li (Ch) [a1] */ + {0x1a71fd06, 1, 1}, /* Kujaku Ou (J) [T+Eng1.1_Snark] */ + {0x99748230, 215, 0}, /* EarthWorm Jim 2 (SuperGame) */ + {0x37876ac7, 215, 0}, /* Golden Card 6-in-1 (Unl) [!] */ + {0x1a3320a3, 215, 0}, /* Mortal Kombat 3 (SuperGame) */ + {0x80eb1839, 114, 0}, /* Boogerman (Sugar Softec) (Unl) [!] */ + {0x071e4ee8, 114, 0}, /* m114,submapper 1 test rom */ + {0xfe3e03a1, 197, -1}, /* Mortal Kombat III Special (YY-030) (Ch) [!] */ + {0x9151d311, 197, -1}, /* Mortal Kombat III 28 Peoples (NT-328) (Ch) [!] */ + {0x272709b9, 237, -1}, /* Teletubbies Y2K (420-in-1) */ + {0x2e27e0af, 227, -1}, /* Bio Hazard (No-Bug) (Unl).nes */ + {0x0e7e9309, 189, -1}, /* Street Fighter II - The World Warrior (Unl) [a1].nes */ + {0xa3ac0095, 189, -1}, /* Street Fighter II - The World Warrior (Unl) [a2].nes */ + {0xeced5899, 121, -1}, /* Ultimate Mortal Kombat 4 (Unl) [!].nes */ + + /* ines mappers that uses iNes 2.0 numbers */ + + {0xf6bd8e31, 281, 0}, /* 1997 Super HIK 4-in-1 (JY-052) [p1][!] */ + {0x5aa23a15, 361, 0}, /* 4-in-1 (OK-411)[p1][!] */ + {0xf6b9d088, 366, 0}, /* 4-in-1 (K-3131GS, GN-45) [p1][!] */ + {0x503566b2, 366, 0}, /* 4-in-1 (K-3131SS, GN-45) [p1][!] */ + + /* ines mappers that uses unif boards */ + + {0x0073dbd8, 260, -1}, /* 2-in-1 - Mortal Kombat V Turbo 30 + Super Aladdin (Unl) [p1][!] */ + {0x4dc6107d, 260, -1}, /* 2-in-1 - Boogerman + Flintstones, The (Unl) [p1][!] */ + {0xb72b2cf4, 260, -1}, /* 2-in-1 - Aladdin + Lion King, The (Unl) [p1][!] */ + {0xa1dc16c0, 262, -1}, /* Street Heroes (Asia) (Ja) (Unl */ + {0x1df10182, 263, -1}, /* Boogerman II (Rex-Soft) [!].nes */ + {0xf956fcea, 521, -1}, /* Korean Igo (Korea) (Unl) */ {0x00000000, -1, -1} diff --git a/src/ines.c b/src/ines.c index 9bb3ef7..781f4d3 100644 --- a/src/ines.c +++ b/src/ines.c @@ -57,7 +57,9 @@ uint32 VROM_size = 0; static int CHRRAMSize = -1; static int iNES_Init(int num); +static int iNES2 = 0; static int MapperNo = 0; +static int subMapper = 0; static DECLFR(TrainerRead) { return(trainerpoo[A & 0x1FF]); @@ -237,7 +239,6 @@ void CheckBad(uint64 md5partial) { } } - struct CHINF { uint32 crc32; int32 mapper; @@ -295,6 +296,8 @@ static void CheckHInfo(void) { }; int32 tofix = 0, x; uint64 partialmd5 = 0; + int32 current_mapper = 0; + int32 cur_mirr = 0; for (x = 0; x < 8; x++) partialmd5 |= (uint64)iNESCart.MD5[15 - x] << (x * 8); @@ -310,12 +313,14 @@ static void CheckHInfo(void) { VROM = NULL; tofix |= 8; } - if (MapperNo != (moo[x].mapper & 0xFF)) { + if (MapperNo != (moo[x].mapper & 0xFFF)) { tofix |= 1; - MapperNo = moo[x].mapper & 0xFF; + current_mapper = MapperNo; + MapperNo = moo[x].mapper & 0xFFF; } } if (moo[x].mirror >= 0) { + cur_mirr = Mirroring; if (moo[x].mirror == 8) { if (Mirroring == 2) { /* Anything but hard-wired(four screen). */ tofix |= 2; @@ -361,19 +366,19 @@ static void CheckHInfo(void) { if (tofix) { char gigastr[768]; - strcpy(gigastr, "The iNES header contains incorrect information. For now, the information will be corrected in RAM. "); + 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); + sprintf(gigastr + strlen(gigastr), "Current mapper # is %d. The mapper number should be set to %d. ", current_mapper, MapperNo); if (tofix & 2) { uint8 *mstr[3] = { (uint8_t*)"Horizontal", (uint8_t*)"Vertical", (uint8_t*)"Four-screen" }; - sprintf(gigastr + strlen(gigastr), "Mirroring should be set to \"%s\". ", mstr[Mirroring & 3]); + sprintf(gigastr + strlen(gigastr), "Current mirroring is %s. Mirroring should be set to \"%s\". ", mstr[cur_mirr & 3], 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); + FCEU_printf("%s\n", gigastr); } } @@ -417,10 +422,10 @@ static BMAPPINGLocal bmap[] = { {(uint8_t*)"Konami VRC2/VRC4 D", 25, Mapper25_Init}, {(uint8_t*)"Konami VRC6 Rev. B", 26, Mapper26_Init}, {(uint8_t*)"CC-21 MI HUN CHE", 27, UNLCC21_Init}, /* Former dupe for VRC2/VRC4 mapper, redefined with crc to mihunche boards */ -/* {(uint8_t*)"", 28, Mapper28_Init}, */ /* Custom Multidiscrete mapper for PDs */ -/* {(uint8_t*)"", 29, Mapper29_Init}, */ + {(uint8_t*)"Action 53", 28, Mapper28_Init}, + {(uint8_t*)"", 29, Mapper29_Init}, {(uint8_t*)"UNROM 512", 30, UNROM512_Init}, -/* {(uint8_t*)"", 31, Mapper31_Init}, */ + {(uint8_t*)"infineteNesLives-NSF", 31, Mapper31_Init}, {(uint8_t*)"IREM G-101", 32, Mapper32_Init}, {(uint8_t*)"TC0190FMC/TC0350FMR", 33, Mapper33_Init}, {(uint8_t*)"IREM I-IM/BNROM", 34, Mapper34_Init}, @@ -445,14 +450,14 @@ static BMAPPINGLocal bmap[] = { {(uint8_t*)"SUPERVISION 16-in-1", 53, Supervision16_Init}, /* {(uint8_t*)"", 54, Mapper54_Init}, */ /* {(uint8_t*)"", 55, Mapper55_Init}, */ -/* {(uint8_t*)"", 56, Mapper56_Init}, */ + {(uint8_t*)"UNLKS202", 56, UNLKS202_Init}, {(uint8_t*)"SIMBPLE BMC PIRATE A", 57, Mapper57_Init}, {(uint8_t*)"SIMBPLE BMC PIRATE B", 58, BMCGK192_Init}, {(uint8_t*)"", 59, Mapper59_Init}, /* Check this out */ {(uint8_t*)"SIMBPLE BMC PIRATE C", 60, BMCD1038_Init}, {(uint8_t*)"20-in-1 KAISER Rev. A",61, Mapper61_Init}, {(uint8_t*)"700-in-1", 62, Mapper62_Init}, -/* {(uint8_t*)"", 63, Mapper63_Init}, */ + {(uint8_t*)"", 63, Mapper63_Init}, {(uint8_t*)"TENGEN RAMBO1", 64, Mapper64_Init}, {(uint8_t*)"IREM-H3001", 65, Mapper65_Init}, {(uint8_t*)"MHROM", 66, MHROM_Init}, @@ -515,7 +520,7 @@ static BMAPPINGLocal bmap[] = { {(uint8_t*)"MMC3 PIRATE H2288", 123, UNLH2288_Init}, /* {(uint8_t*)"", 124, Mapper124_Init}, */ {(uint8_t*)"FDS LH32", 125, LH32_Init}, -/* {(uint8_t*)"", 126, Mapper126_Init}, */ + {(uint8_t*)"PowerJoy 84-in-1 PJ-008", 126, Mapper126_Init}, /* {(uint8_t*)"", 127, Mapper127_Init}, */ /* {(uint8_t*)"", 128, Mapper128_Init}, */ /* {(uint8_t*)"", 129, Mapper129_Init}, */ @@ -571,7 +576,7 @@ static BMAPPINGLocal bmap[] = { /* {(uint8_t*)"", 179, Mapper179_Init}, */ {(uint8_t*)"", 180, Mapper180_Init}, {(uint8_t*)"", 181, Mapper181_Init}, -/* {(uint8_t*)"", 182, Mapper182_Init}, */ /* Deprecated, dupe */ +/* {(uint8_t*)"", 182, Mapper182_Init}, */ /* Deprecated, dupe of Mapper 114 */ {(uint8_t*)"", 183, Mapper183_Init}, {(uint8_t*)"", 184, Mapper184_Init}, {(uint8_t*)"", 185, Mapper185_Init}, @@ -594,7 +599,7 @@ static BMAPPINGLocal bmap[] = { {(uint8_t*)"", 202, Mapper202_Init}, {(uint8_t*)"", 203, Mapper203_Init}, {(uint8_t*)"", 204, Mapper204_Init}, - {(uint8_t*)"", 205, Mapper205_Init}, + {(uint8_t*)"BMC 15-in-1/3-in-1", 205, Mapper205_Init}, {(uint8_t*)"NAMCOT 108 Rev. C", 206, Mapper206_Init}, /* Deprecated, Used to be "DEIROM" whatever it means, but actually simple version of MMC3 */ {(uint8_t*)"TAITO X1-005 Rev. B", 207, Mapper207_Init}, {(uint8_t*)"", 208, Mapper208_Init}, @@ -604,7 +609,7 @@ static BMAPPINGLocal bmap[] = { {(uint8_t*)"", 212, Mapper212_Init}, {(uint8_t*)"", 213, Mapper213_Init}, {(uint8_t*)"", 214, Mapper214_Init}, - {(uint8_t*)"", 215, UNL8237_Init}, + {(uint8_t*)"UNL-8237", 215, UNL8237_Init}, {(uint8_t*)"", 216, Mapper216_Init}, {(uint8_t*)"", 217, Mapper217_Init}, /* Redefined to a new Discrete BMC mapper */ /* {(uint8_t*)"", 218, Mapper218_Init}, */ @@ -613,7 +618,7 @@ static BMAPPINGLocal bmap[] = { {(uint8_t*)"UNLN625092", 221, UNLN625092_Init}, {(uint8_t*)"", 222, Mapper222_Init}, /* {(uint8_t*)"", 223, Mapper223_Init}, */ -/* {(uint8_t*)"", 224, Mapper224_Init}, */ + {(uint8_t*)"KT-008", 224, Mapper224_Init}, {(uint8_t*)"", 225, Mapper225_Init}, {(uint8_t*)"BMC 22+20-in-1", 226, Mapper226_Init}, {(uint8_t*)"", 227, Mapper227_Init}, @@ -626,7 +631,7 @@ static BMAPPINGLocal bmap[] = { {(uint8_t*)"BMC MAXI", 234, Mapper234_Init}, {(uint8_t*)"", 235, Mapper235_Init}, /* {(uint8_t*)"", 236, Mapper236_Init}, */ -/* {(uint8_t*)"", 237, Mapper237_Init}, */ + {(uint8_t*)"Teletubbies / Y2K", 237, Mapper237_Init}, {(uint8_t*)"UNL6035052", 238, UNL6035052_Init}, /* {(uint8_t*)"", 239, Mapper239_Init}, */ {(uint8_t*)"", 240, Mapper240_Init}, @@ -644,20 +649,115 @@ static BMAPPINGLocal bmap[] = { {(uint8_t*)"SAN GUO ZHI PIRATE", 252, Mapper252_Init}, {(uint8_t*)"DRAGON BALL PIRATE", 253, Mapper253_Init}, {(uint8_t*)"", 254, Mapper254_Init}, -/* {(uint8_t*)"", 255, Mapper255_Init}, */ /* No good dumps for this mapper */ - {(uint8_t*)"", 0, NULL} + {(uint8_t*)"", 255, Mapper255_Init}, /* Duplicate of M225? */ + + /* -------------- ----NES 2.0 -------------------------- */ + + /* NES 2.0 BOARDS THAT DO NOT HAVE UNIF ASSOCIATION */ + + {(uint8_t*)"OK-411", 361, GN45_Init}, /* OK-411 is emulated together with GN-45 */ + {(uint8_t*)"HUMMER/JY-052", 281, Mapper281_Init}, + {(uint8_t*)"GN-45", 366, GN45_Init}, + + /* UNIF to NES 2.0 BOARDS */ + + {(uint8_t*)"OneBus", 256, UNLOneBus_Init }, + {(uint8_t*)"158B", 258, UNL158B_Init }, + {(uint8_t*)"F-15", 259, BMCF15_Init }, + {(uint8_t*)"HPxx / HP2018-A", 260, BMCHPxx_Init }, + {(uint8_t*)"810544-C-A1", 261, BMC810544CA1_Init }, + {(uint8_t*)"SHERO", 262, UNLSHeroes_Init }, + {(uint8_t*)"KOF97", 263, UNLKOF97_Init }, + {(uint8_t*)"YOKO", 264, UNLYOKO_Init }, + {(uint8_t*)"T-262", 265, BMCT262_Init }, + {(uint8_t*)"CITYFIGHT", 266, UNLCITYFIGHT_Init }, + {(uint8_t*)"COOLBOY", 268, COOLBOY_Init }, +/* {(uint8_t*)"MINDKIDS", 268, MINDKIDS_Init }, */ + {(uint8_t*)"80013-B", 274, BMC80013B_Init }, + {(uint8_t*)"GS-2004", 283, BMCGS2004_Init }, +/* {(uint8_t*)"GS-2013", 283, BMCGS2013_Init }, */ + {(uint8_t*)"A65AS", 285, BMCA65AS_Init }, + {(uint8_t*)"BS-5", 286, BMCBS5_Init }, + {(uint8_t*)"411120-C", 287, BMC411120C_Init }, +/* {(uint8_t*)"K-3088", 287, BMCK3088_Init }, */ + {(uint8_t*)"60311C", 289, BMC60311C_Init }, + {(uint8_t*)"NTD-03", 290, BMCNTD03_Init }, + {(uint8_t*)"DRAGONFIGHTER", 292, UNLBMW8544_Init }, + {(uint8_t*)"13in1JY110", 295, BMC13in1JY110_Init }, + {(uint8_t*)"TF1201", 298, UNLTF1201_Init }, + {(uint8_t*)"11160", 299, BMC11160_Init }, + {(uint8_t*)"190in1", 300, BMC190in1_Init }, + {(uint8_t*)"8157", 301, UNL8157_Init }, + {(uint8_t*)"KS7057", 302, UNLKS7057_Init }, + {(uint8_t*)"KS7017", 303, UNLKS7017_Init }, + {(uint8_t*)"SMB2J", 304, UNLSMB2J_Init }, + {(uint8_t*)"KS7031", 305, UNLKS7031_Init }, + {(uint8_t*)"KS7016", 306, UNLKS7016_Init }, + {(uint8_t*)"KS7037", 307, UNLKS7037_Init }, + {(uint8_t*)"TH2131-1", 308, UNLTH21311_Init }, + {(uint8_t*)"LH51", 309, LH51_Init }, + {(uint8_t*)"KS7013B", 312, UNLKS7013B_Init }, + {(uint8_t*)"RESET-TXROM", 313, BMCRESETTXROM_Init }, + {(uint8_t*)"64in1NoRepeat", 314, BMC64in1nr_Init }, + {(uint8_t*)"830134C", 315, BMC830134C_Init }, + {(uint8_t*)"HP898F", 319, BMCHP898F_Init }, + {(uint8_t*)"830425C-4391T", 320, BMC830425C4391T_Init }, + {(uint8_t*)"K-3033", 322, BMCK3033_Init }, + {(uint8_t*)"FARID_SLROM_8-IN-1", 323, FARIDSLROM8IN1_Init }, + {(uint8_t*)"FARID_UNROM_8-IN-1", 324, FARIDUNROM_Init }, + {(uint8_t*)"MALISB", 325, UNLMaliSB_Init }, + {(uint8_t*)"10-24-C-A1", 327, BMC1024CA1_Init }, + {(uint8_t*)"RT-01", 328, UNLRT01_Init }, + {(uint8_t*)"EDU2000", 329, UNLEDU2000_Init }, + {(uint8_t*)"12-IN-1", 331, BMC12IN1_Init }, + {(uint8_t*)"WS", 332, BMCWS_Init }, + {(uint8_t*)"NEWSTAR-GRM070-8IN1", 333, BMC8IN1_Init }, + {(uint8_t*)"CTC-09", 335, BMCCTC09_Init }, + {(uint8_t*)"K-3046", 336, BMCK3046_Init }, + {(uint8_t*)"CTC-12IN1", 337, BMCCTC12IN1_Init }, + {(uint8_t*)"SA005-A", 338, BMCSA005A_Init }, + {(uint8_t*)"K-3006", 339, BMCK3006_Init }, + {(uint8_t*)"K-3036", 340, BMCK3036_Init }, + {(uint8_t*)"TJ-03", 341, BMCTJ03_Init }, + {(uint8_t*)"GN-26", 344, BMCGN26_Init }, + {(uint8_t*)"L6IN1", 345, BMCL6IN1_Init }, + {(uint8_t*)"KS7012", 346, UNLKS7012_Init }, + {(uint8_t*)"KS7030", 347, UNLKS7030_Init }, + {(uint8_t*)"830118C", 348, BMC830118C_Init }, + {(uint8_t*)"G-146", 349, BMCG146_Init }, + {(uint8_t*)"891227", 350, BMC891227_Init }, + {(uint8_t*)"3D-BLOCK", 355, UNL3DBlock_Init }, + {(uint8_t*)"SA-9602B", 513, SA9602B_Init }, + {(uint8_t*)"DANCE2000", 518, UNLD2000_Init }, + {(uint8_t*)"EH8813A", 519, UNLEH8813A_Init }, + {(uint8_t*)"DREAMTECH01", 521, DreamTech01_Init }, + {(uint8_t*)"LH10", 522, LH10_Init }, + {(uint8_t*)"900218", 524, BTL900218_Init }, + {(uint8_t*)"KS7021A", 525, UNLKS7021A_Init }, + {(uint8_t*)"BJ-56", 526, UNLBJ56_Init }, + {(uint8_t*)"AX-40G", 527, UNLAX40G_Init }, + {(uint8_t*)"T-230", 529, UNLT230_Init }, + {(uint8_t*)"AX5705", 530, UNLAX5705_Init }, + {(uint8_t*)"LH53", 535, LH53_Init }, + + {(uint8_t*)"", 0, NULL} }; int iNESLoad(const char *name, FCEUFILE *fp) { struct md5_context md5; - char* mappername; - uint32 mappertest; + char* mappername = NULL; + uint32 filesize = fp->fp->size; + uint32 mappertest = 0; + uint32 prgRom = 0; + uint32 chrRom = 0; if (FCEU_fread(&head, 1, 16, fp) != 16) return 0; + filesize -= 16; /* remove header size from total size */ + if (memcmp(&head, "NES\x1a", 4)) { - FCEU_PrintError("Missing header or invalid iNES format file!\n"); + FCEU_PrintError("Not an iNES file!\n"); return 0; } @@ -678,20 +778,54 @@ int iNESLoad(const char *name, FCEUFILE *fp) { 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); + Mirroring = 0; + ROM_size = 0; + VROM_size = 0; + iNES2 = 0; + MapperNo = 0; + subMapper = 0; - if (!head.ROM_size) - ROM_size = 256; - else - ROM_size = uppow2(head.ROM_size); + MapperNo = (head.ROM_type >> 4) | (head.ROM_type2 & 0xF0); + Mirroring = (head.ROM_type & 8) ? 2 : (head.ROM_type & 1); + prgRom = head.ROM_size; + chrRom = head.VROM_size; - VROM_size = uppow2(head.VROM_size); + if ((head.ROM_type2 & 0x0C) == 0x08) { + iNES2 = 1; + MapperNo |= ((uint32)head.ROM_type3 << 8) & 0xF00; + prgRom |= ((uint32)head.upper_PRG_CHR_size << 8) & 0xF00; + chrRom |= ((uint32)head.upper_PRG_CHR_size << 4) & 0xF00; + subMapper = head.ROM_type3 >> 4 & 0x0F; + iNESCart.prgRam = (head.PRGRAM_size & 0x0F) ? (64 << (head.PRGRAM_size & 0x0F)) : 0; + iNESCart.chrRam = (head.CHRRAM_size & 0x0F) ? (64 << (head.CHRRAM_size & 0x0F)) : 0; + iNESCart.prgRam_battery = (head.PRGRAM_size & 0xF0) ? (64 << ((head.PRGRAM_size & 0xF0) >> 4)) : 0; + iNESCart.chrRam_battery = (head.CHRRAM_size & 0xF0) ? (64 << ((head.CHRRAM_size & 0xF0) >> 4)) : 0; + iNESCart.region = head.Region; + } else { + if (!prgRom) + prgRom = 256; + } + + if (head.ROM_type & 4) { /* Trainer */ + trainerpoo = (uint8*)FCEU_gmalloc(512); + FCEU_fread(trainerpoo, 512, 1, fp); + filesize -= 512; + } + + if (((prgRom * 0x4000) + (chrRom * 0x2000)) > filesize) { + FCEU_PrintError(" File length is too short to contain all data reported from header by %llu\n", ((prgRom * 0x4000) + (chrRom * 0x2000)) - filesize); + return 0; + } else if (((prgRom * 0x4000) + (chrRom * 0x2000)) < filesize) + FCEU_PrintError(" File contains %llu bytes of unused data\n", filesize - ((prgRom * 0x4000) + (chrRom * 0x2000))); + + iNESCart.prgRom = prgRom; + iNESCart.chrRom = chrRom; + + ROM_size = uppow2(prgRom); + + if (chrRom) + VROM_size = uppow2(chrRom); if ((ROM = (uint8*)FCEU_malloc(ROM_size << 14)) == NULL) return 0; @@ -706,63 +840,32 @@ int iNESLoad(const char *name, FCEUFILE *fp) { 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); + FCEU_fread(ROM, 0x4000, prgRom, fp); if (VROM_size) - FCEU_fread(VROM, 0x2000, VROM_size, fp); + FCEU_fread(VROM, 0x2000, chrRom, fp); md5_starts(&md5); - if (head.ROM_size) { - md5_update(&md5, ROM, head.ROM_size << 14); - iNESGameCRC32 = CalcCRC32(0, ROM, head.ROM_size << 14); - } else { - md5_update(&md5, ROM, ROM_size << 14); - iNESGameCRC32 = CalcCRC32(0, ROM, ROM_size << 14); - } + md5_update(&md5, ROM, prgRom << 14); + iNESGameCRC32 = CalcCRC32(0, ROM, prgRom << 14); if (VROM_size) { - iNESGameCRC32 = CalcCRC32(iNESGameCRC32, VROM, VROM_size << 13); - md5_update(&md5, VROM, VROM_size << 13); + iNESGameCRC32 = CalcCRC32(iNESGameCRC32, VROM, chrRom << 13); + md5_update(&md5, VROM, chrRom << 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", head.ROM_size ? head.ROM_size : 256); - 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 = (char*)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; @@ -787,30 +890,92 @@ int iNESLoad(const char *name, FCEUFILE *fp) { else SetupCartMirroring(Mirroring & 1, (Mirroring & 4) >> 2, 0); + iNESCart.iNES2 = iNES2; + iNESCart.mapper = MapperNo; + iNESCart.submapper = subMapper; 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); + mappername = "Not Listed"; + + for (mappertest = 0; mappertest < (sizeof bmap / sizeof bmap[0]) - 1; mappertest++) { + if (bmap[mappertest].number == MapperNo) { + mappername = (char*)bmap[mappertest].name; + break; + } + } + + if (iNES2) FCEU_printf(" NES 2.0 extended iNES.\n"); + FCEU_printf(" ROM CRC32: 0x%08lx\n", iNESGameCRC32); + FCEU_printf(" ROM MD5: 0x%s\n", md5_asciistr(iNESCart.MD5)); + FCEU_printf(" PRG ROM: %3d x 16KiB\n", prgRom); + FCEU_printf(" CHR ROM: %3d x 8KiB\n", chrRom); + + if (iNES2) { + const char *tv_region[] = { "NTSC", "PAL", "Multi-region", "Dendy" }; + unsigned PRGRAM = iNESCart.prgRam + iNESCart.prgRam_battery; + unsigned CHRRAM = iNESCart.chrRam + iNESCart.chrRam_battery; + + FCEU_printf(" Mapper #: %3d\n", MapperNo); + FCEU_printf(" Sub Mapper #: %3d\n", subMapper); + FCEU_printf(" Mapper name: %s\n", mappername); + if (PRGRAM || CHRRAM) { + FCEU_printf(" PRG RAM: %d KiB\n", PRGRAM / 1024); + FCEU_printf(" CHR RAM: %d KiB\n", CHRRAM / 1024); + if (head.ROM_type & 0x02) { + FCEU_printf(" PRG RAM backed by battery: %d KiB\n", iNESCart.prgRam_battery / 1024); + FCEU_printf(" CHR RAM backed by battery: %d KiB\n", iNESCart.chrRam_battery / 1024); + } + } + FCEU_printf(" Mirroring: %s\n", Mirroring == 2 ? "None (Four-screen)" : Mirroring ? "Vertical" : "Horizontal"); + FCEU_printf(" System: %s\n", tv_region[(iNESCart.region & 3)]); + FCEU_printf(" Trained: %s\n", (head.ROM_type & 4) ? "Yes" : "No"); + } else { + FCEU_printf(" Mapper #: %3d\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"); + } + + if (!iNES_Init(MapperNo)) { + FCEU_printf("\n"); + FCEU_PrintError(" iNES mapper #%d is not supported at all.\n", MapperNo); + return 0; + } 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)") - || strstr(name, "(S)") || strstr(name, "(s)") - || strstr(name, "(France)") || strstr(name, "(Germany)") - || strstr(name, "(Italy)") || strstr(name, "(Spain)") - || strstr(name, "(Sweden)") || strstr(name, "(Sw)") - || strstr(name, "(Australia)") || strstr(name, "(A)") - || strstr(name, "(a)")) { - FCEUI_SetVidSystem(1); + if (iNES2) { + switch (iNESCart.region & 0x03) { + /* 0: RP2C02 ("NTSC NES") + * 1: RP2C07 ("Licensed PAL NES") + * 2: Multiple-region + * 3: UMC 6527P ("Dendy") + */ + case 0: case 2: FCEUI_SetVidSystem(0); break; + case 1: FCEUI_SetVidSystem(1); break; + case 3: dendy = 1; FCEUI_SetVidSystem(0); break; + } + } else { + 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)") || + strstr(name, "(S)") || strstr(name, "(s)") || + strstr(name, "(France)") || strstr(name, "(Germany)") || + strstr(name, "(Italy)") || strstr(name, "(Spain)") || + strstr(name, "(Sweden)") || strstr(name, "(Sw)") || + strstr(name, "(Australia)") || strstr(name, "(A)") || + strstr(name, "(a)")) { + iNESCart.region = 1; + FCEUI_SetVidSystem(1); + } else { + iNESCart.region = 0; + FCEUI_SetVidSystem(0); + } } - else - FCEUI_SetVidSystem(0); return 1; } @@ -827,21 +992,32 @@ static int iNES_Init(int num) { 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 30: - case 45: - case 96: CHRRAMSize = 32 * 1024; break; - case 176: CHRRAMSize = 128 * 1024; break; - default: CHRRAMSize = 8 * 1024; break; + if (iNESCart.iNES2) { + CHRRAMSize = iNESCart.chrRam + iNESCart.chrRam_battery; + } else { + 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 28: + case 29: + case 30: + case 45: + case 96: + case 513: CHRRAMSize = 32 * 1024; break; + case 176: CHRRAMSize = 128 * 1024; break; + case 268: CHRRAMSize = 256 * 1024; break; + default: CHRRAMSize = 8 * 1024; break; + } + iNESCart.chrRam = CHRRAMSize; + FCEU_printf(" CHR-RAM: %3d KiB\n", CHRRAMSize / 1024); + } + if (CHRRAMSize) { /* TODO: CHR-RAM are sometimes handled in mappers e.g. MMC1 using submapper 1/2/4 and CHR-RAM can be zero here */ + if ((VROM = (uint8*)malloc(CHRRAMSize)) == NULL) return 0; + FCEU_MemoryRand(VROM, CHRRAMSize); + UNIFchrrama = VROM; + SetupCartCHRMapping(0, VROM, CHRRAMSize, 1); + AddExState(VROM, CHRRAMSize, 0, "CHRR"); } - iNESCart.vram_size = CHRRAMSize; - if ((VROM = (uint8*)malloc(CHRRAMSize)) == NULL) return 0; - FCEU_MemoryRand(VROM, CHRRAMSize); - UNIFchrrama = VROM; - SetupCartCHRMapping(0, VROM, CHRRAMSize, 1); - AddExState(VROM, CHRRAMSize, 0, "CHRR"); } if (head.ROM_type & 8) AddExState(ExtraNTARAM, 2048, 0, "EXNR"); diff --git a/src/ines.h b/src/ines.h index b3d07ba..2b29b29 100644 --- a/src/ines.h +++ b/src/ines.h @@ -28,7 +28,14 @@ typedef struct { uint8 VROM_size; uint8 ROM_type; uint8 ROM_type2; - uint8 reserve[8]; + uint8 ROM_type3; + uint8 upper_PRG_CHR_size; + uint8 PRGRAM_size; + uint8 CHRRAM_size; + uint8 Region; + uint8 VS_hardware; + uint8 MiscRoms; + uint8 ExpDevice; } iNES_HEADER; extern uint8 *ROM; @@ -63,7 +70,9 @@ void Mapper23_Init(CartInfo *); void Mapper24_Init(CartInfo *); void Mapper25_Init(CartInfo *); void Mapper26_Init(CartInfo *); -void UNROM512_Init(CartInfo *); /* Mapper #30 */ +void Mapper28_Init(CartInfo *); +void Mapper29_Init(CartInfo *); +void Mapper31_Init(CartInfo *); void Mapper32_Init(CartInfo *); void Mapper33_Init(CartInfo *); void Mapper34_Init(CartInfo *); @@ -87,6 +96,7 @@ void Mapper57_Init(CartInfo *); void Mapper59_Init(CartInfo *); void Mapper61_Init(CartInfo *); void Mapper62_Init(CartInfo *); +void Mapper63_Init(CartInfo *); void Mapper64_Init(CartInfo *); void Mapper65_Init(CartInfo *); void Mapper67_Init(CartInfo *); @@ -136,6 +146,7 @@ void Mapper119_Init(CartInfo *); void Mapper120_Init(CartInfo *); void Mapper121_Init(CartInfo *); void Mapper125_Init(CartInfo *); +void Mapper126_Init(CartInfo *); void Mapper134_Init(CartInfo *); void Mapper140_Init(CartInfo *); void Mapper144_Init(CartInfo *); @@ -198,6 +209,7 @@ void Mapper216_Init(CartInfo *); void Mapper217_Init(CartInfo *); void Mapper220_Init(CartInfo *); void Mapper222_Init(CartInfo *); +void Mapper224_Init(CartInfo *); void Mapper225_Init(CartInfo *); void Mapper226_Init(CartInfo *); void Mapper227_Init(CartInfo *); @@ -222,5 +234,9 @@ void Mapper250_Init(CartInfo *); void Mapper252_Init(CartInfo *); void Mapper253_Init(CartInfo *); void Mapper254_Init(CartInfo *); +void Mapper255_Init(CartInfo *); + +void GN45_Init(CartInfo *info); /* m361, m366 */ +void Mapper281_Init(CartInfo *); #endif diff --git a/src/sound.c b/src/sound.c index 03646af..7ba8d84 100644 --- a/src/sound.c +++ b/src/sound.c @@ -1233,7 +1233,8 @@ SFORMAT FCEUSND_STATEINFO[] = { * issues loading states with this. Increasing it only helps a few games. * Disabling this state variable for Wii/WiiU/GC for now. */ /* TODO: fix this for better runahead feature for big-endian */ -#ifndef GEKKO +/* UPDATE: Try to ignore this for all big-endian for now */ +#ifndef MSB_FIRST /* wave buffer is used for filtering, only need first 17 values from it */ { &Wave, 32 * sizeof(int32), "WAVE"}, #endif diff --git a/src/unif.c b/src/unif.c index 4622f3a..51502a4 100644 --- a/src/unif.c +++ b/src/unif.c @@ -47,6 +47,7 @@ typedef struct { typedef struct { char *name; + int ines_mapper; void (*init)(CartInfo *); int flags; } BMAPPING; @@ -60,6 +61,8 @@ CartInfo UNIFCart; static int vramo; static int mirrortodo; +static int submapper; +static int cspecial; static uint8 *boardname; static uint8 *sboardname; @@ -72,6 +75,15 @@ static UNIF_HEADER uchead; static uint8 *malloced[32]; static uint32 mallocedsizes[32]; +/* used to preserve the rom order as found in the rom file + * at least one mapper has bank 4 at the beginning for e.g. */ +static uint32 prg_idx[16]; +static uint32 chr_idx[16]; + +static uint32 prg_chip_count; +static uint32 chr_chip_count; + +static uint64 UNIF_PRGROMSize, UNIF_CHRROMSize; static int FixRomSize(uint32 size, uint32 minimum) { uint32 x = 1; @@ -96,24 +108,39 @@ static void FreeUNIF(void) { free(malloced[x]); malloced[x] = 0; } } + if (ROM) { + free(ROM); ROM = 0; + } + if (VROM) { + free(VROM); VROM = 0; + } } static void ResetUNIF(void) { int x; for (x = 0; x < 32; x++) malloced[x] = 0; + for (x = 0; x < 16; x++) + prg_idx[x] = chr_idx[x] = 0; vramo = 0; boardname = 0; mirrortodo = 0; memset(&UNIFCart, 0, sizeof(UNIFCart)); UNIFchrrama = 0; + prg_chip_count = 0; + chr_chip_count = 0; + UNIF_PRGROMSize = 0; + UNIF_CHRROMSize = 0; + ROM_size = 0; + VROM_size = 0; } static uint8 exntar[2048]; static void MooMirroring(void) { if (mirrortodo < 0x4) - SetupCartMirroring(mirrortodo, 1, 0); + /* 06-22-19 Allow override when using vertical/horizontal mirroring. */ + SetupCartMirroring(mirrortodo, (mirrortodo >> 1) & 1, 0); else if (mirrortodo == 0x4) { SetupCartMirroring(4, 1, exntar); AddExState(exntar, 2048, 0, "EXNR"); @@ -259,7 +286,7 @@ static int LoadPRG(FCEUFILE *fp) { FCEU_printf(" PRG ROM %d size: %d\n", z, (int)uchead.info); if (malloced[z]) free(malloced[z]); - t = FixRomSize(uchead.info, 2048); + t = uchead.info; if (!(malloced[z] = (uint8*)FCEU_malloc(t))) return(0); mallocedsizes[z] = t; @@ -267,10 +294,12 @@ static int LoadPRG(FCEUFILE *fp) { if (FCEU_fread(malloced[z], 1, uchead.info, fp) != uchead.info) { FCEU_printf("Read Error!\n"); return(0); - } /* else - FCEU_printf("\n"); */ + } + + UNIF_PRGROMSize += t; + prg_idx[prg_chip_count] = z; + prg_chip_count++; - SetupCartPRGMapping(z, malloced[z], t, 0); return(1); } @@ -294,7 +323,7 @@ static int LoadCHR(FCEUFILE *fp) { FCEU_printf(" CHR ROM %d size: %d\n", z, (int)uchead.info); if (malloced[16 + z]) free(malloced[16 + z]); - t = FixRomSize(uchead.info, 8192); + t = uchead.info; if (!(malloced[16 + z] = (uint8*)FCEU_malloc(t))) return(0); mallocedsizes[16 + z] = t; @@ -302,13 +331,75 @@ static int LoadCHR(FCEUFILE *fp) { if (FCEU_fread(malloced[16 + z], 1, uchead.info, fp) != uchead.info) { FCEU_printf("Read Error!\n"); return(0); - } /* else - FCEU_printf("\n"); */ + } + + UNIF_CHRROMSize += t; + chr_idx[chr_chip_count] = z; + chr_chip_count++; - SetupCartCHRMapping(z, malloced[16 + z], t, 0); return(1); } +#define NO_BUSC 1 + +struct _unif_db { + uint64 partialMD5; + char *boardname; + int submapper; + int mirroring; + int special; /* TODO: for bus conflicts, set 1 for no bus_conflict */ +}; + +static struct _unif_db unif_db[] = { + { 0x8ebad077d08e6c78ULL, "A65AS", 1, -1 }, /* 3-in-1 (N080) [p1][U][!], not a real submapper */ + { 0x117181328eb1ad23ULL, "CNROM", 0, MI_H, NO_BUSC }, /* 75 Bingo (Sachen-English) [U] */ + { 0x616851e56946893bULL, "RESETNROM-XIN1", 0, MI_V }, /* Sheng Tian 2-in-1(Unl,ResetBase)[p1].unf */ + { 0x4cd729b5ae23a3cfULL, "RESETNROM-XIN1", 0, MI_H }, /* Sheng Tian 2-in-1(Unl,ResetBase)[p2].unf */ + + { 0, NULL, -1, -1, -1 } /* end of the line */ +}; + +static void CheckHashInfo(void) { + unsigned x = 0; + uint64 partialMD5 = 0; + + for (x = 0; x < 8; x++) + partialMD5 |= (uint64)UNIFCart.MD5[15 - x] << (x * 8); + + x = 0; + do { + if (partialMD5 == unif_db[x].partialMD5) { + FCEU_printf("\n"); + FCEU_PrintError(" The UNIF header contains incorrect information.\n"); + FCEU_PrintError(" For now, the information will be corrected in RAM.\n"); + if (unif_db[x].boardname != NULL && strcmp((char*)unif_db[x].boardname, (char*)sboardname) != 0) { + FCEU_printf(" Boardname should be set to %s\n", unif_db[x].boardname); + sboardname = (uint8*)unif_db[x].boardname; + } + if (unif_db[x].submapper >= 0 && unif_db[x].submapper != submapper) { + FCEU_PrintError(" Submapper should be set to %d\n", unif_db[x].submapper); + submapper = unif_db[x].submapper; + } + if (unif_db[x].mirroring >= 0 && unif_db[x].mirroring != mirrortodo) { + static char *stuffo[6] = { "Horizontal", "Vertical", "$2000", "$2400", "\"Four-screen\"", "Controlled by Mapper Hardware" }; + FCEU_PrintError(" Mirroring should be set to %s\n", stuffo[unif_db[x].mirroring]); + mirrortodo = unif_db[x].mirroring; + } + if (unif_db[x].special >= 0 && unif_db[x].special != cspecial) { + if (!(strcmp((char*)sboardname, "CNROM"))) { + FCEU_PrintError(" Special flags applied, No bus conflict.\n"); + cspecial = unif_db[x].special; + } + } + /* todo special case aka, dipswitches, busc-like in fk23c/a, etc */ + FCEU_printf("\n"); + } + x++; + } while (unif_db[x].partialMD5 > 0); + +} + +#define NO_INES -1 #define BMCFLAG_FORCE4 0x01 #define BMCFLAG_16KCHRR 0x02 #define BMCFLAG_32KCHRR 0x04 @@ -316,160 +407,202 @@ static int LoadCHR(FCEUFILE *fp) { #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 }, - { "KS7016", UNLKS7016_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 }, - { "UNROM-512-8", UNROM512_Init, 0 }, - { "UNROM-512-16", UNROM512_Init, BMCFLAG_16KCHRR }, - { "UNROM-512-32", UNROM512_Init, BMCFLAG_32KCHRR }, - { "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 }, - { "EH8813A", UNLEH8813A_Init, 0 }, - { "HP898F", BMCHP898F_Init, 0 }, - { "F-15", BMCF15_Init, 0 }, - { "RT-01", UNLRT01_Init, 0 }, - { "81-01-31-C", BMC810131C_Init, 0 }, - { "8-IN-1", BMC8IN1_Init, 0 }, + { "11160", 299, BMC11160_Init, 0 }, + { "12-IN-1", 331, BMC12IN1_Init, 0 }, + { "13in1JY110", 295, BMC13in1JY110_Init, 0 }, + { "190in1", 300, BMC190in1_Init, 0 }, + { "22211", 132, UNL22211_Init, 0 }, + { "3D-BLOCK", 355, UNL3DBlock_Init, 0 }, + { "411120-C", 287, BMC411120C_Init, 0 }, + { "42in1ResetSwitch", 233, Mapper233_Init, 0 }, + { "43272", 227, UNL43272_Init, 0 }, + { "603-5052", 238, UNL6035052_Init, 0 }, + { "64in1NoRepeat", 314, BMC64in1nr_Init, 0 }, + { "70in1", 236, BMC70in1_Init, 0 }, + { "70in1B", 236, BMC70in1B_Init, 0 }, + { "810544-C-A1", 261, BMC810544CA1_Init, 0 }, + { "8157", 301, UNL8157_Init, 0 }, + { "8237", 215, UNL8237_Init, 0 }, + { "8237A", 215, UNL8237A_Init, 0 }, + { "830118C", 348, BMC830118C_Init, 0 }, + { "A65AS", 285, BMCA65AS_Init, 0 }, + { "AC08", NO_INES, AC08_Init, 0 }, /* Mapper 42.. but not.. Used for Green Beret */ + { "ANROM", 7, ANROM_Init, 0 }, + { "AX5705", 530, UNLAX5705_Init, 0 }, + { "BB", 108, UNLBB_Init, 0 }, + { "BS-5", 286, BMCBS5_Init, 0 }, + { "CC-21", 27, UNLCC21_Init, 0 }, + { "CITYFIGHT", 266, UNLCITYFIGHT_Init, 0 }, + { "10-24-C-A1", 327, BMC1024CA1_Init, 0 }, + { "CNROM", 3, CNROM_Init, 0 }, + { "CPROM", 13, CPROM_Init, BMCFLAG_16KCHRR }, + { "D1038", 59, BMCD1038_Init, 0 }, + { "DANCE", 256, UNLOneBus_Init, 0 }, /* redundant */ + { "DANCE2000", 518, UNLD2000_Init, 0 }, + { "DREAMTECH01", 521, DreamTech01_Init, 0 }, + { "EDU2000", 329, UNLEDU2000_Init, 0 }, + { "EKROM", 5, EKROM_Init, 0 }, + { "ELROM", 5, ELROM_Init, 0 }, + { "ETROM", 5, ETROM_Init, 0 }, + { "EWROM", 5, EWROM_Init, 0 }, + { "FK23C", 176, BMCFK23C_Init, BMCFLAG_256KCHRR }, + { "FK23CA", 176, BMCFK23CA_Init, BMCFLAG_256KCHRR }, + { "FS304", 162, UNLFS304_Init, 0 }, + { "G-146", 349, BMCG146_Init, 0 }, + { "GK-192", NO_INES, BMCGK192_Init, 0 }, /* mapper 58? */ + { "GS-2004", 283, BMCGS2004_Init, 0 }, + { "GS-2013", 283, BMCGS2013_Init, 0 }, + { "Ghostbusters63in1", 226, Mapper226_Init, 0 }, + { "H2288", 123, UNLH2288_Init, 0 }, + { "HKROM", 4, HKROM_Init, 0 }, + { "KOF97", 263, UNLKOF97_Init, 0 }, + { "KONAMI-QTAI", NO_INES, Mapper190_Init, 0 }, + { "KS7012", 346, UNLKS7012_Init, 0 }, + { "KS7013B", 312, UNLKS7013B_Init, 0 }, + { "KS7016", 306, UNLKS7016_Init, 0 }, + { "KS7017", 303, UNLKS7017_Init, 0 }, + { "KS7030", 347, UNLKS7030_Init, 0 }, + { "KS7031", 305, UNLKS7031_Init, 0 }, + { "KS7032", 142, UNLKS7032_Init, 0 }, + { "KS7037", 307, UNLKS7037_Init, 0 }, + { "KS7057", 302, UNLKS7057_Init, 0 }, + { "LE05", NO_INES, LE05_Init, 0 }, + { "LH10", 522, LH10_Init, 0 }, + { "LH32", 125, LH32_Init, 0 }, + { "LH53", 535, LH53_Init, 0 }, + { "MALISB", 325, UNLMaliSB_Init, 0 }, + { "MARIO1-MALEE2", 42, MALEE_Init, 0 }, + { "MHROM", 66, MHROM_Init, 0 }, + { "N625092", 221, UNLN625092_Init, 0 }, + { "NROM", 0, NROM_Init, 0 }, + { "NROM-128", 0, NROM_Init, 0 }, + { "NROM-256", 0, NROM_Init, 0 }, + { "NTBROM", 68, Mapper68_Init, 0 }, + { "NTD-03", 290, BMCNTD03_Init, 0 }, + { "NovelDiamond9999999in1", 201, Novel_Init, 0 }, + { "OneBus", 256, UNLOneBus_Init, 0 }, + { "PEC-586", NO_INES, UNLPEC586Init, 0 }, + { "RROM", 0, NROM_Init, 0 }, + { "RROM-128", 0, NROM_Init, 0 }, + { "SA-002", 136, TCU02_Init, 0 }, + { "SA-0036", 149, SA0036_Init, 0 }, + { "SA-0037", 148, SA0037_Init, 0 }, + { "SA-009", 160, SA009_Init, 0 }, + { "SA-016-1M", 146, SA0161M_Init, 0 }, + { "SA-72007", 145, SA72007_Init, 0 }, + { "SA-72008", 133, SA72008_Init, 0 }, + { "SA-9602B", 513, SA9602B_Init, BMCFLAG_32KCHRR }, + { "SA-NROM", 143, TCA01_Init, 0 }, + { "SAROM", 1, SAROM_Init, 0 }, + { "SBROM", 1, SBROM_Init, 0 }, + { "SC-127", 35, UNLSC127_Init, 0 }, + { "SCROM", 1, SCROM_Init, 0 }, + { "SEROM", 1, SEROM_Init, 0 }, + { "SGROM", 1, SGROM_Init, 0 }, + { "SHERO", 262, UNLSHeroes_Init, 0 }, + { "SKROM", 1, SKROM_Init, 0 }, + { "SL12", 116, UNLSL12_Init, 0 }, + { "SL1632", 14, UNLSL1632_Init, 0 }, + { "SL1ROM", 1, SL1ROM_Init, 0 }, + { "SLROM", 1, SLROM_Init, 0 }, + { "SMB2J", 304, UNLSMB2J_Init, 0 }, + { "SNROM", 1, SNROM_Init, 0 }, + { "SOROM", 1, SOROM_Init, 0 }, + { "SSS-NROM-256", NO_INES, SSSNROM_Init, 0 }, + { "SUNSOFT_UNROM", 93, SUNSOFT_UNROM_Init, 0 }, /* fix me, real pcb name, real pcb type */ + { "Sachen-74LS374N", 150, S74LS374N_Init, 0 }, + { "Sachen-74LS374NA", 243, S74LS374NA_Init, 0 }, /* seems to be custom mapper */ + { "Sachen-8259A", 141, S8259A_Init, 0 }, + { "Sachen-8259B", 138, S8259B_Init, 0 }, + { "Sachen-8259C", 139, S8259C_Init, 0 }, + { "Sachen-8259D", 137, S8259D_Init, 0 }, + { "Super24in1SC03", 176, Super24_Init, 0 }, + { "Super24in1SC03", 176, Super24_Init, 0 }, + { "SuperHIK8in1", 45, Mapper45_Init, 0 }, + { "Supervision16in1", 53, Supervision16_Init, 0 }, + { "T-227-1", NO_INES, BMCT2271_Init, 0 }, + { "T-230", 529, UNLT230_Init, 0 }, + { "T-262", 265, BMCT262_Init, 0 }, + { "TBROM", 4, TBROM_Init, 0 }, + { "TC-U01-1.5M", 147, TCU01_Init, 0 }, + { "TEK90", 90, Mapper90_Init, 0 }, + { "TEROM", 4, TEROM_Init, 0 }, + { "TF1201", 298, UNLTF1201_Init, 0 }, + { "TFROM", 4, TFROM_Init, 0 }, + { "TGROM", 4, TGROM_Init, 0 }, + { "TKROM", 4, TKROM_Init, 0 }, + { "TKSROM", 118, TKSROM_Init, 0 }, + { "TLROM", 4, TLROM_Init, 0 }, + { "TLSROM", 118, TLSROM_Init, 0 }, + { "TQROM", 119, TQROM_Init, 0 }, + { "TR1ROM", 4, TFROM_Init, BMCFLAG_FORCE4 }, + { "TSROM", 4, TSROM_Init, 0 }, + { "TVROM", 4, TLROM_Init, BMCFLAG_FORCE4 }, + { "Transformer", NO_INES, Transformer_Init, 0 }, + { "UNROM", 2, UNROM_Init, 0 }, + { "UNROM-512-8", 30, UNROM512_Init, 0 }, + { "UNROM-512-16", 30, UNROM512_Init, BMCFLAG_16KCHRR }, + { "UNROM-512-32", 30, UNROM512_Init, BMCFLAG_32KCHRR }, + { "UOROM", 2, UNROM_Init, 0 }, + { "VRC7", 85, UNLVRC7_Init, 0 }, + { "YOKO", 264, UNLYOKO_Init, 0 }, + { "COOLBOY", 268, COOLBOY_Init, BMCFLAG_256KCHRR }, + { "158B", 258, UNL158B_Init, 0 }, + { "DRAGONFIGHTER", 292, UNLBMW8544_Init, 0 }, + { "EH8813A", 519, UNLEH8813A_Init, 0 }, + { "HP898F", 319, BMCHP898F_Init, 0 }, + { "F-15", 259, BMCF15_Init, 0 }, + { "RT-01", 328, UNLRT01_Init, 0 }, + { "81-01-31-C", NO_INES, BMC810131C_Init, 0 }, + { "8-IN-1", 333, BMC8IN1_Init, 0 }, + { "RET-CUFROM", 29, Mapper29_Init, BMCFLAG_32KCHRR }, + { "60311C", 289, BMC60311C_Init, 0 }, + { "WS", 332, BMCWS_Init, 0 }, + { "HPxx", 260, BMCHPxx_Init, 0 }, + { "HP2018-A", 260, BMCHPxx_Init, 0 }, + { "CHINA_ER_SAN2", 19, Mapper19_Init, 0 }, + { "WAIXING-FW01", 227, Mapper227_Init, 0 }, + { "WAIXING-FS005", 176, BMCFK23C_Init, 0 }, + { "80013-B", 274, BMC80013B_Init, 0 }, + { "TH2131-1", 308, UNLTH21311_Init, 0 }, + { "LH51", 309, LH51_Init, 0 }, + { "RESETNROM-XIN1", NO_INES, BMCRESETNROMXIN1_Init, 0 }, /* split roms */ + { " BMC-RESET-TXROM", 313, BMCRESETTXROM_Init, 0 }, + { "RESET-TXROM", 313, BMCRESETTXROM_Init, 0 }, + { "K-3088", 287, BMCK3088_Init, 0 }, + { "FARID_SLROM_8-IN-1", 323, FARIDSLROM8IN1_Init, 0 }, + { "830425C-4391T", 320, BMC830425C4391T_Init, 0 }, + { "TJ-03", 341, BMCTJ03_Init, 0 }, + { "CTC-09", 335, BMCCTC09_Init, 0 }, + { "K-3046", 336, BMCK3046_Init, 0 }, + { "SA005-A", 338, BMCSA005A_Init, 0 }, + { "K-3006", 339, BMCK3006_Init, 0 }, + { "K-3036", 340, BMCK3036_Init, 0 }, + { "MINDKIDS", 268, MINDKIDS_Init, BMCFLAG_256KCHRR }, + { "KS7021A", 525, UNLKS7021A_Init, 0 }, + { "KS106C", NO_INES, BMCKS106C_Init, 0 }, /* split roms */ + { "900218", 524, BTL900218_Init, 0 }, + { "JC-016-2", 205, Mapper205_Init, 0 }, + { "AX-40G", 527, UNLAX40G_Init, 0 }, + { " BMC-STREETFIGTER-GAME4IN1", NO_INES, BMCSFGAME4IN1_Init, 0 }, /* mapper 49? submapper 1*/ + { "G631", 226, Mapper226_Init, 0 }, /* duplicate, probably wrong name */ + { "BJ-56", 526, UNLBJ56_Init, 0 }, + { "L6IN1", 345, BMCL6IN1_Init, 0 }, + { "CTC-12IN1", 337, BMCCTC12IN1_Init, 0 }, + { "891227", 350, BMC891227_Init, 0 }, + { "NEWSTAR-GRM070-8IN1", 333, BMC8IN1_Init, 0 }, + { "FARID_UNROM_8-IN-1", 324, FARIDUNROM_Init, 0 }, + { "K-3033", 322, BMCK3033_Init, 0 }, + { "830134C", 315, BMC830134C_Init, 0 }, + { "GN-26", 344, BMCGN26_Init, 0 }, + { "T4A54A", 134, Mapper134_Init, 0 }, #ifdef COPYFAMI - { "COPYFAMI_MMC3", MapperCopyFamiMMC3_Init, 0 }, - { "COPYFAMI", MapperCopyFami_Init, 0 }, + { "COPYFAMI_MMC3", NO_INES, MapperCopyFamiMMC3_Init, 0 }, + { "COPYFAMI", NO_INES, MapperCopyFami_Init, 0 }, #endif - { NULL, NULL, 0 } + { NULL, NO_INES, NULL, 0 } }; static BFMAPPING bfunc[] = { @@ -521,7 +654,7 @@ static int InitializeBoard(void) { while (bmap[x].name) { if (!strcmp((char*)sboardname, (char*)bmap[x].name)) { - if (!malloced[16]) { + if (VROM_size == 0) { if (bmap[x].flags & BMCFLAG_16KCHRR) CHRRAMSize = 16; else if (bmap[x].flags & BMCFLAG_32KCHRR) @@ -542,12 +675,19 @@ static int InitializeBoard(void) { if (bmap[x].flags & BMCFLAG_FORCE4) mirrortodo = 4; MooMirroring(); + + PRGchip_max = prg_chip_count - 1; + if (chr_chip_count) + CHRchip_max = chr_chip_count - 1; + UNIFCart.submapper = submapper; + GameInfo->cspecial = cspecial; + bmap[x].init(&UNIFCart); return(1); } x++; } - FCEU_PrintError("Board type not supported."); + FCEU_PrintError("Board type not supported, '%s'.", boardname); return(0); } @@ -571,6 +711,10 @@ static void UNIFGI(int h) { } int UNIFLoad(const char *name, FCEUFILE *fp) { + struct md5_context md5; + uint32 x = 0; + uint64 PRGptr = 0, CHRptr = 0; + FCEU_fseek(fp, 0, SEEK_SET); FCEU_fread(&unhead, 1, 4, fp); if (memcmp(&unhead, "UNIF", 4)) @@ -586,21 +730,54 @@ int UNIFLoad(const char *name, FCEUFILE *fp) { goto aborto; if (!LoadUNIFChunks(fp)) goto aborto; - { - int x; - struct md5_context md5; - md5_starts(&md5); + UNIFCart.prgRom = (UNIF_PRGROMSize / 0x1000) + ((UNIF_PRGROMSize % 0x1000) ? 1 : 0); + UNIFCart.prgRom = (UNIFCart.prgRom >> 2) + ((UNIFCart.prgRom & 3) ? 1: 0); + UNIFCart.chrRom = (UNIF_CHRROMSize / 0x400) + ((UNIF_CHRROMSize % 0x400) ? 1 : 0); + UNIFCart.chrRom = (UNIFCart.chrRom >> 3) + ((UNIFCart.chrRom & 7) ? 1: 0); - 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)); + ROM_size = FixRomSize(UNIF_PRGROMSize, 2048); + if (UNIF_CHRROMSize) + VROM_size = FixRomSize(UNIF_CHRROMSize, 8192); + + ROM = (uint8*)malloc(ROM_size); + if (VROM_size) + VROM = (uint8*)malloc(VROM_size); + + for (x = 0; x < 16; x++) { + if (malloced[prg_idx[x]]) { + memcpy(ROM + PRGptr, malloced[(prg_idx[x])], mallocedsizes[(prg_idx[x])]); + PRGptr += mallocedsizes[(prg_idx[x])]; + free(malloced[(prg_idx[x])]); + malloced[(prg_idx[x])] = 0; + } + + if (malloced[16 + (chr_idx[x])]) { + memcpy(VROM + CHRptr, malloced[16 + (chr_idx[x])], mallocedsizes[16 + (chr_idx[x])]); + CHRptr += mallocedsizes[16 + (chr_idx[x])]; + free(malloced[16 + (chr_idx[x])]); + malloced[16 + (chr_idx[x])] = 0; + } } + FCEU_printf(" PRG ROM: %d KiB\n", UNIF_PRGROMSize / 1024); + if (VROM_size) + FCEU_printf(" CHR ROM: %d KiB\n", UNIF_CHRROMSize / 1024); + + md5_starts(&md5); + md5_update(&md5, ROM, UNIF_PRGROMSize); + if (VROM_size) + md5_update(&md5, VROM, UNIF_CHRROMSize); + md5_finish(&md5, UNIFCart.MD5); + FCEU_printf(" ROM MD5: 0x%s\n", md5_asciistr(UNIFCart.MD5)); + memcpy(GameInfo->MD5, UNIFCart.MD5, sizeof(UNIFCart.MD5)); + + CheckHashInfo(); + + SetupCartPRGMapping(0, ROM, ROM_size, 0); + if (VROM_size) + SetupCartCHRMapping(0, VROM, VROM_size, 0); + if (!InitializeBoard()) goto aborto; diff --git a/src/unif.h b/src/unif.h index f7df71d..661fff3 100644 --- a/src/unif.h +++ b/src/unif.h @@ -157,6 +157,40 @@ void BMCF15_Init(CartInfo *info); void UNLRT01_Init(CartInfo *info); void BMC810131C_Init(CartInfo *info); void BMC8IN1_Init(CartInfo *info); +void BMC80013B_Init(CartInfo *info); +void BMC60311C_Init(CartInfo *info); /* m289 */ +void BMCWS_Init(CartInfo *info); /* m332 */ +void UNLKS202_Init(CartInfo *info); /* m056 */ +void BMCHPxx_Init(CartInfo *info); /* m260 */ + +void BMCRESETNROMXIN1_Init(CartInfo *info); +void BMCKS106C_Init(CartInfo *info); +void UNLTH21311_Init(CartInfo *info); /* m308 */ +void LH51_Init(CartInfo *info); /* m309 */ +void BMCRESETTXROM_Init(CartInfo *info); /* m313 */ +void FARIDSLROM8IN1_Init(CartInfo *info); /* m323 */ +void BMC830425C4391T_Init(CartInfo *info); /* m320 */ +void BMCTJ03_Init(CartInfo *info); /* m341 */ +void BMCCTC09_Init(CartInfo *info); /* m335 */ +void BMCK3046_Init(CartInfo *info); /* m336 */ +void BMCSA005A_Init(CartInfo *info); /* m338 */ +void BMCK3006_Init(CartInfo *info); /* m339 */ +void BMCK3036_Init(CartInfo *info); /* m340 */ +void MINDKIDS_Init(CartInfo *info); /* m268 */ +void UNLKS7021A_Init(CartInfo *info); /* m525 */ +void BTL900218_Init(CartInfo *info); /* m524 */ +void UNLAX40G_Init(CartInfo *info); /* m527 */ +void BMCK3088_Init(CartInfo *info); /* m287 */ +void BMCSFGAME4IN1_Init(CartInfo *info); /* m049 */ +void UNLBJ56_Init(CartInfo *info); /* m526 */ +void BMCL6IN1_Init(CartInfo *info); /* m345 */ + +void BMCCTC12IN1_Init(CartInfo *info); /* m337 */ +void BMC891227_Init(CartInfo *info); /* m350 */ +void FARIDUNROM_Init(CartInfo *info); /* m324 */ +void BMCK3033_Init(CartInfo *info); /* mm22 */ +void BMC830134C_Init(CartInfo *info); /* m315 */ +void BMCGN26_Init(CartInfo *info); /* m344 */ #ifdef COPYFAMI void MapperCopyFamiMMC3_Init(CartInfo *info); diff --git a/src/vsuni.c b/src/vsuni.c index 2da1562..b75f3fc 100644 --- a/src/vsuni.c +++ b/src/vsuni.c @@ -34,6 +34,7 @@ typedef struct { char *name; + int gameid; uint64 md5partial; int mapper; int mirroring; @@ -245,48 +246,45 @@ RC2C05-04: VSUNIENTRY VSUniGames[] = { - { "Baseball", 0x691d4200ea42be45LL, 99, 2, RP2C04_0001, 0 }, - { "Battle City", 0x8540949d74c4d0ebLL, 99, 2, RP2C04_0001, 0 }, - { "Battle City(Bootleg)", 0x8093cbe7137ac031LL, 99, 2, RP2C04_0001, 0 }, - - { "Clu Clu Land", 0x1b8123218f62b1eeLL, 99, 2, RP2C04_0004, IOPTION_SWAPDIRAB }, - { "Dr Mario", 0xe1af09c477dc0081LL, 1, 0, RP2C04_0003, IOPTION_SWAPDIRAB }, - { "Duck Hunt", 0x47735d1e5f1205bbLL, 99, 2, RCP2C03B, IOPTION_GUN }, - { "Excitebike", 0x3dcd1401bcafde77LL, 99, 2, RP2C04_0003, 0 }, - { "Excitebike (J)", 0x7ea51c9d007375f0LL, 99, 2, RP2C04_0004, 0 }, - { "Freedom Force", 0xed96436bd1b5e688LL, 4, 0, RP2C04_0001, IOPTION_GUN }, /* Wrong color in game select screen? */ - { "Stroke and Match Golf", 0x612325606e82bc66LL, 99, 2, RP2C04_0002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x01 }, - - { "Goonies", 0xb4032d694e1d2733LL, 151, 1, RP2C04_0003, 0 }, - { "Gradius", 0x50687ae63bdad976LL, 151, 1, RP2C04_0001, IOPTION_SWAPDIRAB }, - { "Gumshoe", 0x87161f8ee37758d3LL, 99, 2, RC2C05_03, IOPTION_GUN }, - { "Gumshoe", 0xb8500780bf69ce29LL, 99, 2, RC2C05_03, IOPTION_GUN }, - { "Gumshoe", 0xa6bf132ba11d0a8cLL, 99, 2, RC2C05_03, IOPTION_GUN }, /* Gumshoe (VS).nes added: 2017-9-5*/ - { "Hogan's Alley", 0xd78b7f0bb621fb45LL, 99, 2, RP2C04_0001, IOPTION_GUN }, - { "Ice Climber", 0xd21e999513435e2aLL, 99, 2, RP2C04_0004, IOPTION_SWAPDIRAB }, - { "Ladies Golf", 0x781b24be57ef6785LL, 99, 2, RP2C04_0002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1 }, - - { "Mach Rider", 0x015672618af06441LL, 99, 2, RP2C04_0002, 0 }, - { "Mach Rider (J)", 0xa625afb399811a8aLL, 99, 2, RP2C04_0001, 0 }, - { "Mighty Bomb Jack", 0xe6a89f4873fac37bLL, 0, 2, RC2C05_02, 0 }, - { "Ninja Jajamaru Kun", 0xb26a2c31474099c0LL, 99, 2, RC2C05_01, IOPTION_SWAPDIRAB }, - { "Pinball", 0xc5f49d3de7f2e9b8LL, 99, 2, RP2C04_0001, IOPTION_PREDIP, 0x01 }, - { "Pinball (J)", 0x66ab1a3828cc901cLL, 99, 2, RCP2C03B, IOPTION_PREDIP, 0x1 }, - { "Platoon", 0x160f237351c19f1fLL, 68, 1, RP2C04_0001, 0 }, - { "RBI Baseball", 0x6a02d345812938afLL, 4, 1, RP2C04_0001, IOPTION_SWAPDIRAB }, - { "Soccer", 0xd4e7a9058780eda3LL, 99, 2, RP2C04_0003, IOPTION_SWAPDIRAB }, - { "Star Luster", 0x8360e134b316d94cLL, 99, 2, RCP2C03B, 0 }, - { "Stroke and Match Golf (J)", 0x869bb83e02509747LL, 99, 2, RCP2C03B, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1 }, - { "Super Sky Kid", 0x78d04c1dd4ec0101LL, 4, 1, RCP2C03B, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x20 }, - - { "Super Xevious", 0x2d396247cf58f9faLL, 206, 0, RP2C04_0001, 0 }, - { "Tetris", 0x531a5e8eea4ce157LL, 99, 2, RCP2C03B, IOPTION_PREDIP, 0x20 }, - { "Top Gun", 0xf1dea36e6a7b531dLL, 2, 0, RC2C05_04, 0 }, - { "VS Castlevania", 0x92fd6909c81305b9LL, 2, 1, RP2C04_0002, 0 }, - { "VS Slalom", 0x4889b5a50a623215LL, 0, 1, RP2C04_0002, 0 }, - { "VS Super Mario Bros", 0x39d8cfa788e20b6cLL, 99, 2, RP2C04_0004, 0 }, - { "VS Super Mario Bros [a1]", 0xfc182e5aefbce14dLL, 99, 2, RP2C04_0004, 0 }, - { "VS TKO Boxing", 0x6e1ee06171d8ce3aLL, 4, 1, RP2C04_0003, IOPTION_PREDIP, 0x00 }, + { "Baseball", VS_BASEBALL, 0x691d4200ea42be45LL, 99, 2, RP2C04_0001, 0 }, + { "Battle City", VS_BATTLECITY, 0x8540949d74c4d0ebLL, 99, 2, RP2C04_0001, 0 }, + { "Battle City(Bootleg)", VS_BATTLECITY, 0x8093cbe7137ac031LL, 99, 2, RP2C04_0001, 0 }, + { "Clu Clu Land", VS_CLUCLULAND, 0x1b8123218f62b1eeLL, 99, 2, RP2C04_0004, IOPTION_SWAPDIRAB }, + { "Dr Mario", VS_DRMARIO, 0xe1af09c477dc0081LL, 1, 0, RP2C04_0003, IOPTION_SWAPDIRAB }, + { "Duck Hunt", VS_DUCKHUNT, 0x47735d1e5f1205bbLL, 99, 2, RCP2C03B, IOPTION_GUN }, + { "Excitebike", VS_EXITEBIKE, 0x3dcd1401bcafde77LL, 99, 2, RP2C04_0003, 0 }, + { "Excitebike (J)", VS_EXITEBIKE, 0x7ea51c9d007375f0LL, 99, 2, RP2C04_0004, 0 }, + { "Freedom Force", VS_FREEDOMFORCE, 0xed96436bd1b5e688LL, 4, 0, RP2C04_0001, IOPTION_GUN }, /* Wrong color in game select screen? */ + { "Stroke and Match Golf", VS_STROKEANDMATCHGOLF, 0x612325606e82bc66LL, 99, 2, RP2C04_0002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x01 }, + { "Goonies", VS_GOONIES, 0xb4032d694e1d2733LL, 151, 1, RP2C04_0003, 0 }, + { "Gradius", VS_GRADIUS, 0x50687ae63bdad976LL, 151, 1, RP2C04_0001, IOPTION_SWAPDIRAB }, + { "Gumshoe", VS_GUMSHOE, 0x87161f8ee37758d3LL, 99, 2, RC2C05_03, IOPTION_GUN }, + { "Gumshoe", VS_GUMSHOE, 0xb8500780bf69ce29LL, 99, 2, RC2C05_03, IOPTION_GUN }, + { "Gumshoe", VS_GUMSHOE, 0xa6bf132ba11d0a8cLL, 99, 2, RC2C05_03, IOPTION_GUN }, /* Gumshoe (VS).nes added: 2017-9-5*/ + { "Hogan's Alley", VS_HOGANSALLEY, 0xd78b7f0bb621fb45LL, 99, 2, RP2C04_0001, IOPTION_GUN }, + { "Ice Climber", VS_ICECLIMBER, 0xd21e999513435e2aLL, 99, 2, RP2C04_0004, IOPTION_SWAPDIRAB }, + { "Ladies Golf", VS_LADIESGOLF, 0x781b24be57ef6785LL, 99, 2, RP2C04_0002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1 }, + { "Mach Rider", VS_MACHRIDER, 0x015672618af06441LL, 99, 2, RP2C04_0002, 0 }, + { "Mach Rider (J)", VS_MACHRIDER, 0xa625afb399811a8aLL, 99, 2, RP2C04_0001, 0 }, + { "Mighty Bomb Jack", VS_MIGHTYBOMBJACK, 0xe6a89f4873fac37bLL, 0, 2, RC2C05_02, 0 }, + { "Ninja Jajamaru Kun", VS_JAJAMARU, 0xb26a2c31474099c0LL, 99, 2, RC2C05_01, IOPTION_SWAPDIRAB }, + { "Pinball", VS_PINBALL, 0xc5f49d3de7f2e9b8LL, 99, 2, RP2C04_0001, IOPTION_PREDIP, 0x01 }, + { "Pinball (J)", VS_PINBALL, 0x66ab1a3828cc901cLL, 99, 2, RCP2C03B, IOPTION_PREDIP, 0x1 }, + { "Platoon", VS_PLATOON, 0x160f237351c19f1fLL, 68, 1, RP2C04_0001, 0 }, + { "RBI Baseball", VS_RBIBASEBALL, 0x6a02d345812938afLL, 4, 1, RP2C04_0001, IOPTION_SWAPDIRAB }, + { "Soccer", VS_SOCCER, 0xd4e7a9058780eda3LL, 99, 2, RP2C04_0003, IOPTION_SWAPDIRAB }, + { "Star Luster", VS_STARLUSTER, 0x8360e134b316d94cLL, 99, 2, RCP2C03B, 0 }, + { "Stroke and Match Golf (J)", VS_STROKEANDMATCHGOLF, 0x869bb83e02509747LL, 99, 2, RCP2C03B, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1 }, + { "Super Sky Kid", VS_SUPERSKYKID, 0x78d04c1dd4ec0101LL, 4, 1, RCP2C03B, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x20 }, + { "Super Xevious", VS_SUPERXEVIOUS, 0x2d396247cf58f9faLL, 206, 0, RP2C04_0001, 0 }, + { "Tetris", VS_TETRIS, 0x531a5e8eea4ce157LL, 99, 2, RCP2C03B, IOPTION_PREDIP, 0x20 }, + { "Top Gun", VS_TOPGUN, 0xf1dea36e6a7b531dLL, 2, 0, RC2C05_04, 0 }, + { "VS Castlevania", VS_CASTLEVANIA, 0x92fd6909c81305b9LL, 2, 1, RP2C04_0002, 0 }, + { "VS Slalom", VS_SLALOM, 0x4889b5a50a623215LL, 0, 1, RP2C04_0002, 0 }, + { "VS Super Mario Bros", VS_SMB, 0x39d8cfa788e20b6cLL, 99, 2, RP2C04_0004, 0 }, + { "VS Super Mario Bros [a1]", VS_SMB, 0xfc182e5aefbce14dLL, 99, 2, RP2C04_0004, 0 }, + { "VS TKO Boxing", VS_TKOBOXING, 0x6e1ee06171d8ce3aLL, 206, 1, RP2C04_0003, IOPTION_PREDIP, 0x00 }, + { "VS TKO Boxing [a1]", VS_TKOBOXING, 0xa1c694ce147bc1edLL, 206, 1, RP2C04_0003, IOPTION_PREDIP, 0x00 }, { 0 } }; @@ -302,18 +300,19 @@ void FCEU_VSUniCheck(uint64 md5partial, int *MapperNo, uint8 *Mirroring) { GameInfo->type = GIT_VSUNI; GameInfo->cspecial = SIS_VSUNISYSTEM; GameInfo->inputfc = SIFC_NONE; + GameInfo->gameid = vs->gameid; curppu = vs->ppu; curmd5 = md5partial; + FCEU_printf(" System: VS-UniSystem\n"); + FCEU_printf(" Name: %s\n", vs->name); + secptr = 0; - { - static int64 tko = 0x6e1ee06171d8ce3aULL, rbi = 0x6a02d345812938afULL; - if (md5partial == tko) - secptr = secdata[0]; - if (md5partial == rbi) - secptr = secdata[1]; - } + if (vs->gameid == VS_TKOBOXING) + secptr = secdata[0]; + if (vs->gameid == VS_RBIBASEBALL) + secptr = secdata[1]; vsdip = 0x0; if (vs->ioption & IOPTION_PREDIP) { diff --git a/src/vsuni.h b/src/vsuni.h index 8457bb7..8248885 100644 --- a/src/vsuni.h +++ b/src/vsuni.h @@ -9,4 +9,37 @@ void FCEU_VSUniToggleDIP(int); /* For movies and netplay */ void FCEU_VSUniCoin(void); void FCEU_VSUniSwap(uint8 *j0, uint8 *j1); +enum { + VS_BASEBALL = 1, + VS_BATTLECITY, + VS_CASTLEVANIA, + VS_CLUCLULAND, + VS_DRMARIO, + VS_DUCKHUNT, + VS_EXITEBIKE, + VS_FREEDOMFORCE, + VS_GOONIES, + VS_GRADIUS, + VS_GUMSHOE, + VS_HOGANSALLEY, + VS_ICECLIMBER, + VS_JAJAMARU, + VS_LADIESGOLF, + VS_MACHRIDER, + VS_MIGHTYBOMBJACK, + VS_PINBALL, + VS_PLATOON, + VS_RBIBASEBALL, + VS_SLALOM, + VS_SMB, + VS_SOCCER, + VS_STARLUSTER, + VS_STROKEANDMATCHGOLF, + VS_SUPERSKYKID, + VS_SUPERXEVIOUS, + VS_TETRIS, + VS_TKOBOXING, + VS_TOPGUN +}; + #endif