diff --git a/.github/workflows/crowdin_prep.yml b/.github/workflows/crowdin_prep.yml index 165f24b13..47c88f18c 100644 --- a/.github/workflows/crowdin_prep.yml +++ b/.github/workflows/crowdin_prep.yml @@ -8,7 +8,7 @@ on: branches: - master paths: - - 'src/drivers/libretro/libretro_core_options.h' + - 'libretro/libretro_core_options.h' jobs: upload_source_file: @@ -30,4 +30,4 @@ jobs: env: CROWDIN_API_KEY: ${{ secrets.CROWDIN_API_KEY }} run: | - python3 intl/upload_workflow.py $CROWDIN_API_KEY "libretro-fceumm" "src/drivers/libretro/libretro_core_options.h" + python3 intl/upload_workflow.py $CROWDIN_API_KEY "libretro-fceumm" "libretro/libretro_core_options.h" \ No newline at end of file diff --git a/.github/workflows/crowdin_translate.yml b/.github/workflows/crowdin_translate.yml index cb8972eb3..0892399a4 100644 --- a/.github/workflows/crowdin_translate.yml +++ b/.github/workflows/crowdin_translate.yml @@ -30,17 +30,17 @@ jobs: env: CROWDIN_API_KEY: ${{ secrets.CROWDIN_API_KEY }} run: | - python3 intl/download_workflow.py $CROWDIN_API_KEY "libretro-fceumm" "src/drivers/libretro/libretro_core_options_intl.h" + python3 intl/download_workflow.py $CROWDIN_API_KEY "libretro-fceumm" "libretro/libretro_core_options_intl.h" - name: Commit files run: | git config --local user.email "github-actions@github.com" git config --local user.name "github-actions[bot]" - git add intl/*_workflow.py "src/drivers/libretro/libretro_core_options_intl.h" + git add intl/*_workflow.py "libretro/libretro_core_options_intl.h" git commit -m "Fetch translations & Recreate libretro_core_options_intl.h" - name: GitHub Push uses: ad-m/github-push-action@v0.6.0 with: github_token: ${{ secrets.GITHUB_TOKEN }} - branch: ${{ github.ref }} + branch: ${{ github.ref }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 407bd5ba3..88a63f7d8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.a *.so .vscode +.clang-format \ No newline at end of file diff --git a/Makefile.common b/Makefile.common index d0ca21d0a..8def8f38d 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1,11 +1,13 @@ -LIBRETRO_COMM_DIR := $(CORE_DIR)/drivers/libretro/libretro-common +LIBRETRO_COMM_DIR := $(LIBRETRO_DIR)/libretro-common INCFLAGS := \ - -I$(CORE_DIR)/drivers/libretro \ + -I$(LIBRETRO_DIR) \ -I$(LIBRETRO_COMM_DIR)/include \ - -I$(CORE_DIR) \ - -I$(CORE_DIR)/input \ - -I$(CORE_DIR)/boards + -I$(SOURCE_DIR) \ + -I$(SOURCE_DIR)/input \ + -I$(SOURCE_DIR)/mappers \ + -I$(SOURCE_DIR)/mappers/hw \ + -I$(SOURCE_DIR)/mappers/sound ifneq (,$(findstring msvc2003,$(platform))) INCFLAGS += -I$(LIBRETRO_COMM_DIR)/include/compat/msvc @@ -14,63 +16,75 @@ endif COREDEFINES = \ -D__LIBRETRO__ \ -DPATH_MAX=1024 \ - -DFCEU_VERSION_NUMERIC=9813 \ -DFRONTEND_SUPPORTS_RGB565 FCEU_SRC_DIRS := \ - $(CORE_DIR)/boards \ - $(CORE_DIR)/input + $(SOURCE_DIR)/mappers \ + $(SOURCE_DIR)/mappers/hw \ + $(SOURCE_DIR)/mappers/sound \ + $(SOURCE_DIR)/input SOURCES_C := $(foreach dir,$(FCEU_SRC_DIRS),$(wildcard $(dir)/*.c)) ifeq ($(HAVE_NTSC),1) COREDEFINES += \ -DHAVE_NTSC_FILTER \ - -I$(CORE_DIR)/ntsc - SOURCES_C += $(CORE_DIR)/ntsc/nes_ntsc.c + -I$(SOURCE_DIR)/ntsc + SOURCES_C += \ + $(SOURCE_DIR)/ntsc/nes_ntsc.c endif SOURCES_C += \ - $(CORE_DIR)/drivers/libretro/libretro.c \ - $(CORE_DIR)/drivers/libretro/libretro_dipswitch.c \ - $(CORE_DIR)/cart.c \ - $(CORE_DIR)/cheat.c \ - $(CORE_DIR)/crc32.c \ - $(CORE_DIR)/fceu-endian.c \ - $(CORE_DIR)/fceu-memory.c \ - $(CORE_DIR)/fceu.c \ - $(CORE_DIR)/fds.c \ - $(CORE_DIR)/fds_apu.c \ - $(CORE_DIR)/file.c \ - $(CORE_DIR)/filter.c \ - $(CORE_DIR)/general.c \ - $(CORE_DIR)/input.c \ - $(CORE_DIR)/md5.c \ - $(CORE_DIR)/nsf.c \ - $(CORE_DIR)/palette.c \ - $(CORE_DIR)/ppu.c \ - $(CORE_DIR)/sound.c \ - $(CORE_DIR)/state.c \ - $(CORE_DIR)/video.c \ - $(CORE_DIR)/vsuni.c \ - $(CORE_DIR)/ines.c \ - $(CORE_DIR)/unif.c \ - $(CORE_DIR)/x6502.c + $(SOURCE_DIR)/cart.c \ + $(SOURCE_DIR)/cheat.c \ + $(SOURCE_DIR)/crc32.c \ + $(SOURCE_DIR)/drawing.c \ + $(SOURCE_DIR)/fceu-endian.c \ + $(SOURCE_DIR)/fceu-memory.c \ + $(SOURCE_DIR)/fceu.c \ + $(SOURCE_DIR)/fds.c \ + $(SOURCE_DIR)/file.c \ + $(SOURCE_DIR)/filter.c \ + $(SOURCE_DIR)/gamegenie.c \ + $(SOURCE_DIR)/general.c \ + $(SOURCE_DIR)/input.c \ + $(SOURCE_DIR)/mappers.c \ + $(SOURCE_DIR)/md5.c \ + $(SOURCE_DIR)/nsf.c \ + $(SOURCE_DIR)/nsfe.c \ + $(SOURCE_DIR)/palette.c \ + $(SOURCE_DIR)/ppu.c \ + $(SOURCE_DIR)/sound.c \ + $(SOURCE_DIR)/state.c \ + $(SOURCE_DIR)/video.c \ + $(SOURCE_DIR)/vsuni.c \ + $(SOURCE_DIR)/ines.c \ + $(SOURCE_DIR)/unif.c \ + $(SOURCE_DIR)/x6502.c ifneq ($(STATIC_LINKING), 1) SOURCES_C += \ $(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \ - $(LIBRETRO_COMM_DIR)/compat/compat_snprintf.c \ $(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \ $(LIBRETRO_COMM_DIR)/compat/compat_strl.c \ $(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \ $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \ $(LIBRETRO_COMM_DIR)/file/file_path.c \ $(LIBRETRO_COMM_DIR)/file/file_path_io.c \ + $(LIBRETRO_COMM_DIR)/memmap/memalign.c \ $(LIBRETRO_COMM_DIR)/streams/file_stream.c \ $(LIBRETRO_COMM_DIR)/streams/file_stream_transforms.c \ $(LIBRETRO_COMM_DIR)/streams/memory_stream.c \ $(LIBRETRO_COMM_DIR)/string/stdstring.c \ $(LIBRETRO_COMM_DIR)/time/rtime.c \ $(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c +ifdef _MSC_VER + SOURCES_C += \ + $(LIBRETRO_COMM_DIR)/compat/compat_snprintf.c +endif endif + +SOURCES_C += \ + $(LIBRETRO_DIR)/libretro_input.c \ + $(LIBRETRO_DIR)/libretro_dipswitch.c \ + $(LIBRETRO_DIR)/libretro.c diff --git a/Makefile.libretro b/Makefile.libretro index c6eb5a929..31a792aa0 100644 --- a/Makefile.libretro +++ b/Makefile.libretro @@ -4,6 +4,8 @@ STATIC_LINKING=0 ENDIANNESS_DEFINES= SIGNED_CHAR=0 HAVE_NTSC=1 +C89_BUILD=1 +V=0 SPACE := SPACE := $(SPACE) $(SPACE) @@ -48,6 +50,10 @@ else ifneq ($(findstring MINGW,$(shell uname -a)),) system_platform = win endif +ifneq ($(V),1) + Q := @ +endif + TARGET_NAME := fceumm GIT_VERSION := " $(shell git rev-parse --short HEAD || echo unknown)" ifneq ($(GIT_VERSION)," unknown") @@ -69,13 +75,13 @@ ifneq ($(findstring SunOS,$(shell uname -a)),) CC = gcc SHARED := -shared -z defs else - SHARED := -shared -Wl,--version-script=src/drivers/libretro/link.T -Wl,-no-undefined + SHARED := -shared -Wl,--version-script=libretro/link.T -Wl,-no-undefined endif else ifeq ($(platform), linux-portable) TARGET := $(TARGET_NAME)_libretro.so fpic := -fPIC -nostdlib - SHARED := -shared -Wl,--version-script=src/drivers/libretro/link.T + SHARED := -shared -Wl,--version-script=libretro/link.T LIBM := # OS X else ifeq ($(platform), osx) @@ -149,7 +155,7 @@ else ifeq ($(platform), theos_ios) else ifeq ($(platform), qnx) TARGET := $(TARGET_NAME)_libretro_qnx.so fpic := -fPIC - SHARED := -shared -Wl,--version-script=src/drivers/libretro/link.T -Wl,-no-undefined + SHARED := -shared -Wl,--version-script=libretro/link.T -Wl,-no-undefined CC = qcc -Vgcc_ntoarmv7le AR = qcc -Vgcc_ntoarmv7le PLATFORM_DEFINES := -D__BLACKBERRY_QNX__ -marm -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp @@ -159,7 +165,7 @@ else ifeq ($(platform), ps2) TARGET := $(TARGET_NAME)_libretro_$(platform).a CC = mips64r5900el-ps2-elf-gcc$(EXE_EXT) AR = mips64r5900el-ps2-elf-ar$(EXE_EXT) - FCEU_DEFINES := -DPATH_MAX=1024 -DINLINE=inline -DFCEU_VERSION_NUMERIC=9813 -DHAVE_ASPRINTF + FCEU_DEFINES := -DPATH_MAX=1024 -DINLINE=inline -DHAVE_ASPRINTF ENDIANNESS_DEFINES := -DLSB_FIRST -DLOCAL_LE=1 PLATFORM_DEFINES := -DPS2 -D_EE -G0 -DFRONTEND_SUPPORTS_ABGR1555 -DRENDER_GSKIT_PS2 PLATFORM_DEFINES += -I$(PS2SDK)/ee/include -I$(PS2SDK)/common/include -I$(PS2DEV)/gsKit/include @@ -167,6 +173,7 @@ else ifeq ($(platform), ps2) EXTERNAL_ZLIB=1 HAVE_NTSC = 0 + C89_BUILD = 0 # PSP else ifeq ($(platform), psp1) TARGET := $(TARGET_NAME)_libretro_$(platform).a @@ -215,7 +222,7 @@ else ifeq ($(platform), ctr) else ifeq ($(platform), rpi1) TARGET := $(TARGET_NAME)_libretro.so fpic := -fPIC - SHARED := -shared -Wl,--version-script=src/drivers/libretro/link.T -Wl,-no-undefined + SHARED := -shared -Wl,--version-script=libretro/link.T -Wl,-no-undefined CFLAGS += -DARM11 CFLAGS += -marm -march=armv6j -mfpu=vfp -mfloat-abi=hard -funsafe-math-optimizations CFLAGS += -fomit-frame-pointer -fstrict-aliasing -ffast-math @@ -224,7 +231,7 @@ else ifeq ($(platform), rpi1) else ifeq ($(platform), rpi2) TARGET := $(TARGET_NAME)_libretro.so fpic := -fPIC - SHARED := -shared -Wl,--version-script=src/drivers/libretro/link.T -Wl,-no-undefined + SHARED := -shared -Wl,--version-script=libretro/link.T -Wl,-no-undefined CFLAGS += -DARM CFLAGS += -marm -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -funsafe-math-optimizations CFLAGS += -fomit-frame-pointer -fstrict-aliasing -ffast-math @@ -233,7 +240,7 @@ else ifeq ($(platform), rpi2) else ifeq ($(platform), rpi3) TARGET := $(TARGET_NAME)_libretro.so fpic := -fPIC - SHARED := -shared -Wl,--version-script=src/drivers/libretro/link.T -Wl,-no-undefined + SHARED := -shared -Wl,--version-script=libretro/link.T -Wl,-no-undefined CFLAGS += -DARM CFLAGS += -marm -mcpu=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard -funsafe-math-optimizations CFLAGS += -fomit-frame-pointer -fstrict-aliasing -ffast-math @@ -242,7 +249,7 @@ else ifeq ($(platform), rpi3) else ifeq ($(platform), rpi3_64) TARGET := $(TARGET_NAME)_libretro.so fpic := -fPIC - SHARED := -shared -Wl,--version-script=src/drivers/libretro/link.T -Wl,-no-undefined + SHARED := -shared -Wl,--version-script=libretro/link.T -Wl,-no-undefined CFLAGS += -mcpu=cortex-a53 -mtune=cortex-a53 -funsafe-math-optimizations CFLAGS += -fomit-frame-pointer -fstrict-aliasing -ffast-math @@ -250,7 +257,7 @@ else ifeq ($(platform), rpi3_64) else ifeq ($(platform), rpi4) TARGET := $(TARGET_NAME)_libretro.so fpic := -fPIC - SHARED := -shared -Wl,--version-script=src/drivers/libretro/link.T -Wl,-no-undefined + SHARED := -shared -Wl,--version-script=libretro/link.T -Wl,-no-undefined CFLAGS += -mcpu=cortex-a72 -mtune=cortex-a72 -funsafe-math-optimizations CFLAGS += -fomit-frame-pointer -fstrict-aliasing -ffast-math @@ -348,7 +355,7 @@ else ifeq ($(platform), libnx) else ifeq ($(platform), classic_armv7_a7) TARGET := $(TARGET_NAME)_libretro.so fpic := -fPIC - SHARED := -shared -Wl,--version-script=src/drivers/libretro/link.T -Wl,-no-undefined + SHARED := -shared -Wl,--version-script=libretro/link.T -Wl,-no-undefined CFLAGS += -Ofast \ -flto=4 -fwhole-program -fuse-linker-plugin \ -fdata-sections -ffunction-sections -Wl,--gc-sections \ @@ -379,7 +386,7 @@ else ifeq ($(platform), classic_armv7_a7) else ifeq ($(platform), classic_armv8_a35) TARGET := $(TARGET_NAME)_libretro.so fpic := -fPIC - SHARED := -shared -Wl,--version-script=src/drivers/libretro/link.T -Wl,-no-undefined + SHARED := -shared -Wl,--version-script=libretro/link.T -Wl,-no-undefined CFLAGS += -Ofast \ -flto=4 -fwhole-program -fuse-linker-plugin \ -fdata-sections -ffunction-sections -Wl,--gc-sections \ @@ -402,7 +409,7 @@ else ifeq ($(platform), classic_armv8_a35) # ARM else ifneq (,$(findstring armv,$(platform))) TARGET := $(TARGET_NAME)_libretro.so - SHARED := -shared -Wl,--version-script=src/drivers/libretro/link.T -Wl,-no-undefined + SHARED := -shared -Wl,--version-script=libretro/link.T -Wl,-no-undefined fpic := -fPIC ifneq (,$(findstring cortexa5,$(platform))) PLATFORM_DEFINES += -marm -mcpu=cortex-a5 @@ -435,7 +442,7 @@ else ifeq ($(platform), gcw0) CXX = /opt/gcw0-toolchain/usr/bin/mipsel-linux-g++ AR = /opt/gcw0-toolchain/usr/bin/mipsel-linux-ar fpic := -fPIC - SHARED := -shared -Wl,--version-script=src/drivers/libretro/link.T -Wl,-no-undefined + SHARED := -shared -Wl,--version-script=libretro/link.T -Wl,-no-undefined PLATFORM_DEFINES += -ffast-math -march=mips32 -mtune=mips32r2 -mhard-float -fomit-frame-pointer EXTERNAL_ZLIB = 1 @@ -446,7 +453,7 @@ else ifeq ($(platform), retrofw) CXX = /opt/retrofw-toolchain/usr/bin/mipsel-linux-g++ AR = /opt/retrofw-toolchain/usr/bin/mipsel-linux-ar fpic := -fPIC - SHARED := -shared -Wl,--version-script=src/drivers/libretro/link.T -Wl,-no-undefined + SHARED := -shared -Wl,--version-script=libretro/link.T -Wl,-no-undefined PLATFORM_DEFINES += -ffast-math -march=mips32 -mtune=mips32 -mhard-float -fomit-frame-pointer EXTERNAL_ZLIB = 1 @@ -457,7 +464,7 @@ else ifeq ($(platform), miyoo) CXX = /opt/miyoo/usr/bin/arm-linux-g++ AR = /opt/miyoo/usr/bin/arm-linux-ar fpic := -fPIC - SHARED := -shared -Wl,--version-script=src/drivers/libretro/link.T -Wl,-no-undefined + SHARED := -shared -Wl,--version-script=libretro/link.T -Wl,-no-undefined PLATFORM_DEFINES += -fomit-frame-pointer -ffast-math -mcpu=arm926ej-s EXTERNAL_ZLIB = 1 @@ -695,7 +702,7 @@ CFLAGS += -D_CRT_SECURE_NO_DEPRECATE else TARGET := $(TARGET_NAME)_libretro.dll CC ?= gcc - SHARED := -shared -static-libgcc -static-libstdc++ -s -Wl,--version-script=src/drivers/libretro/link.T + SHARED := -shared -static-libgcc -static-libstdc++ -s -Wl,--version-script=libretro/link.T endif ifeq ($(DEBUG), 1) @@ -733,7 +740,8 @@ ifeq ($(SIGNED_CHAR), 1) CFLAGS += -fsigned-char endif -CORE_DIR := src +SOURCE_DIR := src +LIBRETRO_DIR := libretro include Makefile.common @@ -750,7 +758,7 @@ ifneq (,$(findstring msvc,$(platform))) COREDEFINES += -DINLINE=_inline endif -OBJECTS := $(SOURCES_C:.c=.o) +OBJECTS := $(SOURCES_CXX:.cpp=.o) $(SOURCES_C:.c=.o) OBJECTS += $(RETROARCH_OBJECTS) DEFINES := $(COREDEFINES) $(PLATFORM_DEFINES) @@ -768,7 +776,10 @@ else WARNING_DEFINES = -Wall -Wno-write-strings endif -CFLAGS += -Werror=implicit-function-declaration +ifeq ($(C89_BUILD),1) + CFLAGS += -std=c89 -ansi -pedantic -Werror=implicit-function-declaration -Wimplicit-fallthrough -Wno-long-long -Werror=declaration-after-statement + CFLAGS += -D_GNU_SOURCE +endif CFLAGS += $(fpic) $(WARNING_DEFINES) $(DEFINES) $(ENDIANNESS_DEFINES) LDFLAGS += $(LIBM) @@ -777,6 +788,7 @@ ifeq ($(platform), psp1) INCFLAGS += -I$(shell psp-config --pspsdk-path)/include endif +CXXFLAGS += $(CFLAGS) ifneq (,$(findstring msvc,$(platform))) OBJOUT = -Fo @@ -814,18 +826,26 @@ else $(AR) rcs $@ $(OBJECTS) endif else - $(LD) $(LINKOUT)$@ $(SHARED) $(OBJECTS) $(LDFLAGS) $(LIBS) + @$(if $(Q), $(shell echo echo LD $@),) + $(Q)$(LD) $(LINKOUT)$@ $(SHARED) $(OBJECTS) $(LDFLAGS) $(LIBS) endif +%.o: %.cpp + @$(if $(Q), $(shell echo echo CXX $<),) + $(Q)$(CXX) -c $(OBJOUT)$@ $< $(CXXFLAGS) $(INCFLAGS) + %.o: %.c - $(CC) -c $(OBJOUT)$@ $< $(CFLAGS) $(INCFLAGS) + @$(if $(Q), $(shell echo echo CC $<),) + $(Q)$(CC) -c $(OBJOUT)$@ $< $(CFLAGS) $(INCFLAGS) clean-objs: rm -f $(OBJECTS) clean: - rm -f $(OBJECTS) - rm -f $(TARGET) + @$(if $(Q), $(shell echo echo rm -rf *.o),) + $(Q)rm -f $(OBJECTS) + @$(if $(Q), $(shell echo echo rm -rf $(TARGET)),) + $(Q)rm -f $(TARGET) .PHONY: clean clean-objs endif diff --git a/README.md b/README.md index 3c1d4d76e..756a3e414 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,46 @@ [![Build Status](https://travis-ci.org/libretro/libretro-fceumm.svg?branch=master)](https://travis-ci.org/libretro/libretro-fceumm) [![Build status](https://ci.appveyor.com/api/projects/status/etk1vcouybahdbkt/branch/master?svg=true)](https://ci.appveyor.com/project/bparker06/libretro-fceumm/branch/master) -# FCE Ultra mappers modified +# FCE Ultra mappers modified (FCEUmm) FCEU "mappers modified" is an unofficial build of FCEU Ultra by CaH4e3, which supports a lot of new mappers including some obscure mappers such as one for unlicensed NES ROM's. +##### Some notable changes and updates (in no particular order): +- additional mappers support +- mapper fixes and updates +- additional input options (SNES Mouse, SNES Gamepad, PowerPad A/B, VirtualBoy Controller etc) +- variable overscan cropping options, including separate top, bottom, left, right overscan cropping +- replaced on/off audio options to volume controls +- add volume controls for expansion audio (FDS, MMC5, VRC6, VRC7, Namco163, Sunsoft5B) +- fix to audio controls not muting some channels when in low quality mode +- add missing state variables, fixing runahead compatibility +- Assign F12 as Hard Reset (PowerNES) hotkey +- Write instructions now update the databus (backport https://github.com/TASEmulators/fceux/pull/659) +- Apply bisqwit's deemphasis method +- support for 512-palettes and apply bisqwit's deemphasis (fceux) +- fix possible buffer overflow caused by emphasis buffer not initialized to zero +- Vs. System rework, fix input issues and missing palettes, reworked inputs, update preexisting database and other updates. +- Fix low volume issue +- Use NES 2.0 info for supported input types (when available) +- Propagate FCEU_MemoryRand() to initialize mapper WRAM,CHRRAM and other cartridge memory types. +- FCEU_gmalloc default init state is based on FCEU_MemoryRand() settings. +- Replace Sunsoft 5B with emu2149 +- NSF: Fix waveform visualizer +- NSF: add support for multiple audio chip (wip) +- Add NSFE support +- misc changes under the hood (libretro, sound, etc) + +##### Button/Key Changes/Additions: +* F12 - Hard-Reset +* L1 - Change Disk Side in FDS +* R1 - Insert/Eject Disk in FDS +* L2/R2 - Insert Coins for slot 1/2 respectively in Vs. Unisystem and some coin-operated mappers. +* holding L2 and pressing LEFT or RIGHT will change internal palette + +The core can be compiled similarly to libretro-fceumm. and be a drop-in replacement. + +##### NOTE: +This core is a work-in-progress! Expect breakage or regressions. +With the massive changes, savestates will not be compatible between versions or commits. SRAM or battery saves are mostly compatible though unless on eeprom-based saves. +NES 2.0 headered rom is prefered. + +PS2/PSP targets are special cases and may not include some enhancements. diff --git a/jni/Android.mk b/jni/Android.mk index 6054d2d73..73cadaec2 100644 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -1,12 +1,12 @@ LOCAL_PATH := $(call my-dir) -CORE_DIR := $(LOCAL_PATH)/../src +CORE_DIR := $(LOCAL_PATH)/.. HAVE_NTSC := 1 include $(LOCAL_PATH)/../Makefile.common -COREFLAGS := $(COREDEFINES) -DPSS_STYLE=1 $(INCFLAGS) +COREFLAGS := $(COREDEFINES) $(INCFLAGS) GIT_VERSION := " $(shell git rev-parse --short HEAD || echo unknown)" ifneq ($(GIT_VERSION)," unknown") diff --git a/src/drivers/libretro/libretro-common/compat/compat_posix_string.c b/libretro/libretro-common/compat/compat_posix_string.c similarity index 100% rename from src/drivers/libretro/libretro-common/compat/compat_posix_string.c rename to libretro/libretro-common/compat/compat_posix_string.c diff --git a/src/drivers/libretro/libretro-common/compat/compat_snprintf.c b/libretro/libretro-common/compat/compat_snprintf.c similarity index 100% rename from src/drivers/libretro/libretro-common/compat/compat_snprintf.c rename to libretro/libretro-common/compat/compat_snprintf.c diff --git a/src/drivers/libretro/libretro-common/compat/compat_strcasestr.c b/libretro/libretro-common/compat/compat_strcasestr.c similarity index 100% rename from src/drivers/libretro/libretro-common/compat/compat_strcasestr.c rename to libretro/libretro-common/compat/compat_strcasestr.c diff --git a/src/drivers/libretro/libretro-common/compat/compat_strl.c b/libretro/libretro-common/compat/compat_strl.c similarity index 100% rename from src/drivers/libretro/libretro-common/compat/compat_strl.c rename to libretro/libretro-common/compat/compat_strl.c diff --git a/src/drivers/libretro/libretro-common/compat/fopen_utf8.c b/libretro/libretro-common/compat/fopen_utf8.c similarity index 100% rename from src/drivers/libretro/libretro-common/compat/fopen_utf8.c rename to libretro/libretro-common/compat/fopen_utf8.c diff --git a/src/drivers/libretro/libretro-common/encodings/encoding_utf.c b/libretro/libretro-common/encodings/encoding_utf.c similarity index 100% rename from src/drivers/libretro/libretro-common/encodings/encoding_utf.c rename to libretro/libretro-common/encodings/encoding_utf.c diff --git a/src/drivers/libretro/libretro-common/file/file_path.c b/libretro/libretro-common/file/file_path.c similarity index 88% rename from src/drivers/libretro/libretro-common/file/file_path.c rename to libretro/libretro-common/file/file_path.c index 8f49c0d39..edbb5c496 100644 --- a/src/drivers/libretro/libretro-common/file/file_path.c +++ b/libretro/libretro-common/file/file_path.c @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -68,6 +69,33 @@ #endif +/* Time format strings with AM-PM designation require special + * handling due to platform dependence */ +void strftime_am_pm(char *s, size_t len, const char* format, + const void *ptr) +{ +#if !(defined(__linux__) && !defined(ANDROID)) + char *local = NULL; +#endif + const struct tm *timeptr = (const struct tm*)ptr; + + /* Ensure correct locale is set + * > Required for localised AM/PM strings */ + setlocale(LC_TIME, ""); + + strftime(s, len, format, timeptr); +#if !(defined(__linux__) && !defined(ANDROID)) + if ((local = local_to_utf8_string_alloc(s))) + { + if (!string_is_empty(local)) + strlcpy(s, local, len); + + free(local); + local = NULL; + } +#endif +} + /** * Create a new linked list with one node in it * The path on this node will be set to NULL @@ -172,9 +200,9 @@ const char *path_get_archive_delim(const char *path) string_to_lower(buf); /* Check if this is a '.zip', '.apk' or '.7z' file */ - if (string_is_equal(buf, ".zip") || - string_is_equal(buf, ".apk") || - string_is_equal(buf + 1, ".7z")) + if ( string_is_equal(buf, ".zip") + || string_is_equal(buf, ".apk") + || string_is_equal(buf + 1, ".7z")) return delim; } else if (delim - path > 3) @@ -208,7 +236,7 @@ const char *path_get_archive_delim(const char *path) const char *path_get_extension(const char *path) { const char *ext; - if (!string_is_empty(path) && ((ext = strrchr(path_basename(path), '.')))) + if (!string_is_empty(path) && ((ext = (char*)strrchr(path_basename(path), '.')))) return ext + 1; return ""; } @@ -228,7 +256,7 @@ const char *path_get_extension(const char *path) char *path_get_extension_mutable(const char *path) { char *ext = NULL; - if (!string_is_empty(path) && ((ext = strrchr(path_basename(path), '.')))) + if (!string_is_empty(path) && ((ext = (char*)strrchr(path_basename(path), '.')))) return ext; return NULL; } @@ -302,14 +330,16 @@ bool path_is_compressed_file(const char* path) size_t fill_pathname(char *out_path, const char *in_path, const char *replace, size_t size) { + size_t _len; char tmp_path[PATH_MAX_LENGTH]; char *tok = NULL; strlcpy(tmp_path, in_path, sizeof(tmp_path)); if ((tok = (char*)strrchr(path_basename(tmp_path), '.'))) *tok = '\0'; - strlcpy(out_path, tmp_path, size); - return strlcat(out_path, replace, size); + _len = strlcpy(out_path, tmp_path, size); + _len += strlcpy(out_path + _len, replace, size - _len); + return _len; } @@ -319,21 +349,20 @@ size_t fill_pathname(char *out_path, const char *in_path, * @size : size of path * * Find last slash in path. Tries to find - * a backslash on Windows too which takes precedence - * over regular slash. + * a backslash as used for Windows paths, + * otherwise checks for a regular slash. * @return pointer to last slash/backslash found in @str. **/ char *find_last_slash(const char *str) { const char *slash = strrchr(str, '/'); -#ifdef _WIN32 const char *backslash = strrchr(str, '\\'); if (!slash || (backslash > slash)) return (char*)backslash; -#endif - return (char*)slash; + else + return (char*)slash; } /** @@ -344,24 +373,20 @@ char *find_last_slash(const char *str) * Assumes path is a directory. Appends a slash * if not already there. **/ -void fill_pathname_slash(char *path, size_t size) +size_t fill_pathname_slash(char *path, size_t size) { size_t path_len; const char *last_slash = find_last_slash(path); - if (!last_slash) - { - strlcat(path, PATH_DEFAULT_SLASH(), size); - return; - } - - path_len = strlen(path); + return strlcat(path, PATH_DEFAULT_SLASH(), size); + path_len = strlen(path); /* Try to preserve slash type. */ if (last_slash != (path + path_len - 1)) { - path[path_len] = last_slash[0]; - path[path_len+1] = '\0'; + path[ path_len] = last_slash[0]; + path[++path_len] = '\0'; } + return path_len; } /** @@ -384,12 +409,11 @@ void fill_pathname_slash(char *path, size_t size) size_t fill_pathname_dir(char *in_dir, const char *in_basename, const char *replace, size_t size) { - const char *base = NULL; - - fill_pathname_slash(in_dir, size); - base = path_basename(in_basename); - strlcat(in_dir, base, size); - return strlcat(in_dir, replace, size); + size_t _len = fill_pathname_slash(in_dir, size); + const char *base = path_basename(in_basename); + _len += strlcpy(in_dir + _len, base, size - _len); + _len += strlcpy(in_dir + _len, replace, size - _len); + return _len; } /** @@ -514,14 +538,14 @@ void fill_pathname_parent_dir(char *out_dir, size_t fill_dated_filename(char *out_filename, const char *ext, size_t size) { - time_t cur_time = time(NULL); + size_t _len; struct tm tm_; - + time_t cur_time = time(NULL); rtime_localtime(&cur_time, &tm_); - - strftime(out_filename, size, + _len = strftime(out_filename, size, "RetroArch-%m%d-%H%M%S", &tm_); - return strlcat(out_filename, ext, size); + _len += strlcpy(out_filename + _len, ext, size - _len); + return _len; } /** @@ -542,21 +566,24 @@ size_t fill_dated_filename(char *out_filename, size_t fill_str_dated_filename(char *out_filename, const char *in_str, const char *ext, size_t size) { - char format[NAME_MAX_LENGTH]; struct tm tm_; + char format[NAME_MAX_LENGTH]; + size_t _len = 0; time_t cur_time = time(NULL); - rtime_localtime(&cur_time, &tm_); - - strlcpy(out_filename, in_str, size); + _len = strlcpy(out_filename, in_str, size); if (string_is_empty(ext)) { strftime(format, sizeof(format), "-%y%m%d-%H%M%S", &tm_); - return strlcat(out_filename, format, size); + _len += strlcpy(out_filename + _len, format, size - _len); } - strftime(format, sizeof(format), "-%y%m%d-%H%M%S.", &tm_); - strlcat(out_filename, format, size); - return strlcat(out_filename, ext, size); + else + { + strftime(format, sizeof(format), "-%y%m%d-%H%M%S.", &tm_); + _len += strlcpy(out_filename + _len, format, size - _len); + _len += strlcpy(out_filename + _len, ext, size - _len); + } + return _len; } /** @@ -626,18 +653,12 @@ void path_parent_dir(char *path, size_t len) **/ const char *path_basename(const char *path) { - /* We cut at the first compression-related hash */ - const char *delim = path_get_archive_delim(path); - if (delim) - return delim + 1; - - { - /* We cut at the last slash */ - const char *last = find_last_slash(path); - if (last) - return last + 1; - } - + /* We cut either at the first compression-related hash, + * or we cut at the last slash */ + const char *ptr = NULL; + if ( (ptr = path_get_archive_delim(path)) + || (ptr = find_last_slash(path))) + return ptr + 1; return path; } @@ -670,24 +691,23 @@ const char *path_basename_nocompression(const char *path) **/ bool path_is_absolute(const char *path) { - if (string_is_empty(path)) - return false; - - if (path[0] == '/') - return true; - + if (!string_is_empty(path)) + { + if (path[0] == '/') + return true; #if defined(_WIN32) - /* Many roads lead to Rome... - * Note: Drive letter can only be 1 character long */ - return ( string_starts_with_size(path, "\\\\", STRLEN_CONST("\\\\")) - || string_starts_with_size(path + 1, ":/", STRLEN_CONST(":/")) - || string_starts_with_size(path + 1, ":\\", STRLEN_CONST(":\\"))); + /* Many roads lead to Rome... + * Note: Drive letter can only be 1 character long */ + return ( string_starts_with_size(path, "\\\\", STRLEN_CONST("\\\\")) + || string_starts_with_size(path + 1, ":/", STRLEN_CONST(":/")) + || string_starts_with_size(path + 1, ":\\", STRLEN_CONST(":\\"))); #elif defined(__wiiu__) || defined(VITA) - { - const char *seperator = strchr(path, ':'); - return (seperator && (seperator[1] == '/')); - } + { + const char *seperator = strchr(path, ':'); + return (seperator && (seperator[1] == '/')); + } #endif + } return false; } @@ -713,7 +733,7 @@ char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks) { #if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL) #ifdef _WIN32 - char *ret = NULL; + char *ret = NULL; wchar_t *rel_path = utf8_to_utf16_string_alloc(buf); if (rel_path) @@ -767,13 +787,13 @@ char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks) { size_t len; /* rebase on working directory */ - if (!getcwd(tmp, PATH_MAX_LENGTH-1)) + if (!getcwd(tmp, PATH_MAX_LENGTH - 1)) return NULL; len = strlen(tmp); - t += len; + t += len; - if (tmp[len-1] != '/') + if (tmp[len - 1] != '/') tmp[t++] = '/'; if (string_is_empty(buf)) @@ -804,8 +824,8 @@ char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks) return NULL; /* delete previous segment in tmp by adjusting size t - * tmp[t-1] == '/', find '/' before that */ - t = t-2; + * tmp[t - 1] == '/', find '/' before that */ + t -= 2; while (tmp[t] != '/') t--; t++; @@ -817,7 +837,7 @@ char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks) else { /* fail when truncating */ - if (t + next-p+1 > PATH_MAX_LENGTH-1) + if (t + next - p + 1 > PATH_MAX_LENGTH - 1) return NULL; while (p <= next) @@ -936,11 +956,13 @@ void fill_pathname_resolve_relative(char *out_path, size_t fill_pathname_join(char *out_path, const char *dir, const char *path, size_t size) { + size_t _len = 0; if (out_path != dir) - strlcpy(out_path, dir, size); + _len = strlcpy(out_path, dir, size); if (*out_path) - fill_pathname_slash(out_path, size); - return strlcat(out_path, path, size); + _len = fill_pathname_slash(out_path, size); + _len += strlcpy(out_path + _len, path, size - _len); + return _len; } /** @@ -974,18 +996,19 @@ size_t fill_pathname_join_special(char *out_path, /* Try to preserve slash type. */ if (last_slash != (out_path + len - 1)) { - out_path[len] = last_slash[0]; - out_path[len+1] = '\0'; + out_path[ len] = last_slash[0]; + out_path[++len] = '\0'; } } else { - out_path[len] = PATH_DEFAULT_SLASH_C(); - out_path[len+1] = '\0'; + out_path[ len] = PATH_DEFAULT_SLASH_C(); + out_path[++len] = '\0'; } } - return strlcat(out_path, path, size); + len += strlcpy(out_path + len, path, size - len); + return len; } size_t fill_pathname_join_special_ext(char *out_path, @@ -993,12 +1016,12 @@ size_t fill_pathname_join_special_ext(char *out_path, const char *last, const char *ext, size_t size) { - fill_pathname_join(out_path, dir, path, size); + size_t _len = fill_pathname_join(out_path, dir, path, size); if (*out_path) - fill_pathname_slash(out_path, size); - - strlcat(out_path, last, size); - return strlcat(out_path, ext, size); + _len = fill_pathname_slash(out_path, size); + _len += strlcpy(out_path + _len, last, size - _len); + _len += strlcpy(out_path + _len, ext, size - _len); + return _len; } /** @@ -1015,19 +1038,19 @@ size_t fill_pathname_join_special_ext(char *out_path, size_t fill_pathname_join_delim(char *out_path, const char *dir, const char *path, const char delim, size_t size) { - size_t copied; - /* behavior of strlcpy is undefined if dst and src overlap */ + size_t _len; + /* Behavior of strlcpy is undefined if dst and src overlap */ if (out_path == dir) - copied = strlen(dir); + _len = strlen(dir); else - copied = strlcpy(out_path, dir, size); + _len = strlcpy(out_path, dir, size); - out_path[copied] = delim; - out_path[copied+1] = '\0'; + out_path[_len] = delim; + out_path[_len+1] = '\0'; if (path) return strlcat(out_path, path, size); - return copied; + return _len; } size_t fill_pathname_expand_special(char *out_path, @@ -1135,12 +1158,12 @@ size_t fill_pathname_abbreviate_special(char *out_path, * * Leaf function. * - * Changes the slashes to the correct kind for the os + * Changes the slashes to the correct kind for the OS * So forward slash on linux and backslash on Windows **/ void pathname_conform_slashes_to_os(char *path) { - /* Conform slashes to os standard so we get proper matching */ + /* Conform slashes to OS standard so we get proper matching */ char *p; for (p = path; *p; p++) if (*p == '/' || *p == '\\') @@ -1158,7 +1181,7 @@ void pathname_conform_slashes_to_os(char *path) **/ void pathname_make_slashes_portable(char *path) { - /* Conform slashes to os standard so we get proper matching */ + /* Conform slashes to OS standard so we get proper matching */ char *p; for (p = path; *p; p++) if (*p == '/' || *p == '\\') @@ -1334,8 +1357,8 @@ void fill_pathname_application_path(char *s, size_t len) if (realpath(s, resolved_bundle_dir_buf)) { size_t _len = strlcpy(s, resolved_bundle_dir_buf, len - 1); - s[_len ] = '/'; - s[_len+1] = '\0'; + s[ _len] = '/'; + s[++_len] = '\0'; } } #endif diff --git a/src/drivers/libretro/libretro-common/file/file_path_io.c b/libretro/libretro-common/file/file_path_io.c similarity index 99% rename from src/drivers/libretro/libretro-common/file/file_path_io.c rename to libretro/libretro-common/file/file_path_io.c index 0003e785d..d8f8187c8 100644 --- a/src/drivers/libretro/libretro-common/file/file_path_io.c +++ b/libretro/libretro-common/file/file_path_io.c @@ -29,7 +29,6 @@ #include #include -#include #include #include #include diff --git a/src/drivers/libretro/libretro-common/include/boolean.h b/libretro/libretro-common/include/boolean.h similarity index 100% rename from src/drivers/libretro/libretro-common/include/boolean.h rename to libretro/libretro-common/include/boolean.h diff --git a/src/drivers/libretro/libretro-common/include/compat/fopen_utf8.h b/libretro/libretro-common/include/compat/fopen_utf8.h similarity index 100% rename from src/drivers/libretro/libretro-common/include/compat/fopen_utf8.h rename to libretro/libretro-common/include/compat/fopen_utf8.h diff --git a/src/drivers/libretro/libretro-common/include/compat/msvc.h b/libretro/libretro-common/include/compat/msvc.h similarity index 100% rename from src/drivers/libretro/libretro-common/include/compat/msvc.h rename to libretro/libretro-common/include/compat/msvc.h diff --git a/src/drivers/libretro/libretro-common/include/compat/msvc/stdint.h b/libretro/libretro-common/include/compat/msvc/stdint.h similarity index 100% rename from src/drivers/libretro/libretro-common/include/compat/msvc/stdint.h rename to libretro/libretro-common/include/compat/msvc/stdint.h diff --git a/src/drivers/libretro/libretro-common/include/compat/posix_string.h b/libretro/libretro-common/include/compat/posix_string.h similarity index 100% rename from src/drivers/libretro/libretro-common/include/compat/posix_string.h rename to libretro/libretro-common/include/compat/posix_string.h diff --git a/src/drivers/libretro/libretro-common/include/compat/strcasestr.h b/libretro/libretro-common/include/compat/strcasestr.h similarity index 100% rename from src/drivers/libretro/libretro-common/include/compat/strcasestr.h rename to libretro/libretro-common/include/compat/strcasestr.h diff --git a/src/drivers/libretro/libretro-common/include/compat/strl.h b/libretro/libretro-common/include/compat/strl.h similarity index 100% rename from src/drivers/libretro/libretro-common/include/compat/strl.h rename to libretro/libretro-common/include/compat/strl.h diff --git a/src/drivers/libretro/libretro-common/include/encodings/utf.h b/libretro/libretro-common/include/encodings/utf.h similarity index 100% rename from src/drivers/libretro/libretro-common/include/encodings/utf.h rename to libretro/libretro-common/include/encodings/utf.h diff --git a/src/drivers/libretro/libretro-common/include/file/file_path.h b/libretro/libretro-common/include/file/file_path.h similarity index 98% rename from src/drivers/libretro/libretro-common/include/file/file_path.h rename to libretro/libretro-common/include/file/file_path.h index 5a81aa236..d410cc43b 100644 --- a/src/drivers/libretro/libretro-common/include/file/file_path.h +++ b/libretro/libretro-common/include/file/file_path.h @@ -323,10 +323,10 @@ size_t fill_dated_filename(char *out_filename, * Hidden non-leaf function cost: * - Calls time * - Calls rtime_localtime() - * - Calls strlcpy + * - Calls strlcpy 2x * - Calls string_is_empty() * - Calls strftime - * - Calls strlcat at least 2x + * - Calls strlcat * * @return Length of the string copied into @out_path **/ @@ -369,7 +369,7 @@ char *find_last_slash(const char *str); * Hidden non-leaf function cost: * - Calls fill_pathname_slash() * - Calls path_basename() - * - Calls strlcat 2x + * - Calls strlcpy 2x **/ size_t fill_pathname_dir(char *in_dir, const char *in_basename, const char *replace, size_t size); @@ -470,9 +470,8 @@ void fill_pathname_resolve_relative(char *out_path, const char *in_refpath, * between directory and path. * * Hidden non-leaf function cost: - * - calls strlcpy + * - calls strlcpy at least once * - calls fill_pathname_slash() - * - calls strlcat * * Deprecated. Use fill_pathname_join_special() instead * if you can ensure @dir != @out_path @@ -499,9 +498,8 @@ size_t fill_pathname_join(char *out_path, const char *dir, * between directory and path. * * Hidden non-leaf function cost: - * - calls strlcpy + * - calls strlcpy 2x * - calls find_last_slash() - * - calls strlcat * * @return Length of the string copied into @out_path **/ @@ -627,7 +625,7 @@ void path_basedir_wrapper(char *path); * - can call strlcat once if it returns false * - calls strlen **/ -void fill_pathname_slash(char *path, size_t size); +size_t fill_pathname_slash(char *path, size_t size); #if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL) void fill_pathname_application_path(char *buf, size_t size); @@ -664,6 +662,11 @@ bool path_mkdir(const char *dir); */ bool path_is_directory(const char *path); +/* Time format strings with AM-PM designation require special + * handling due to platform dependence */ +void strftime_am_pm(char *s, size_t len, const char* format, + const void* timeptr); + bool path_is_character_special(const char *path); int path_stat(const char *path); diff --git a/src/drivers/libretro/libretro-common/include/libretro.h b/libretro/libretro-common/include/libretro.h similarity index 89% rename from src/drivers/libretro/libretro-common/include/libretro.h rename to libretro/libretro-common/include/libretro.h index 4bd3f2f0c..347f9da64 100644 --- a/src/drivers/libretro/libretro-common/include/libretro.h +++ b/libretro/libretro-common/include/libretro.h @@ -291,6 +291,7 @@ enum retro_language RETRO_LANGUAGE_CATALAN = 29, RETRO_LANGUAGE_BRITISH_ENGLISH = 30, RETRO_LANGUAGE_HUNGARIAN = 31, + RETRO_LANGUAGE_BELARUSIAN = 32, RETRO_LANGUAGE_LAST, /* Ensure sizeof(enum) == sizeof(int) */ @@ -928,8 +929,6 @@ enum retro_mod * anything else. * It is recommended to expose all relevant pointers through * retro_get_memory_* as well. - * - * Can be called from retro_init and retro_load_game. */ #define RETRO_ENVIRONMENT_SET_GEOMETRY 37 /* const struct retro_game_geometry * -- @@ -1767,6 +1766,93 @@ enum retro_mod * (see enum retro_savestate_context) */ +#define RETRO_ENVIRONMENT_GET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_SUPPORT (73 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* struct retro_hw_render_context_negotiation_interface * -- + * Before calling SET_HW_RNEDER_CONTEXT_NEGOTIATION_INTERFACE, a core can query + * which version of the interface is supported. + * + * Frontend looks at interface_type and returns the maximum supported + * context negotiation interface version. + * If the interface_type is not supported or recognized by the frontend, a version of 0 + * must be returned in interface_version and true is returned by frontend. + * + * If this environment call returns true with interface_version greater than 0, + * a core can always use a negotiation interface version larger than what the frontend returns, but only + * earlier versions of the interface will be used by the frontend. + * A frontend must not reject a negotiation interface version that is larger than + * what the frontend supports. Instead, the frontend will use the older entry points that it recognizes. + * If this is incompatible with a particular core's requirements, it can error out early. + * + * Backwards compatibility note: + * This environment call was introduced after Vulkan v1 context negotiation. + * If this environment call is not supported by frontend - i.e. the environment call returns false - + * only Vulkan v1 context negotiation is supported (if Vulkan HW rendering is supported at all). + * If a core uses Vulkan negotiation interface with version > 1, negotiation may fail unexpectedly. + * All future updates to the context negotiation interface implies that frontend must support + * this environment call to query support. + */ + +#define RETRO_ENVIRONMENT_GET_JIT_CAPABLE 74 + /* bool * -- + * Result is set to true if the frontend has already verified JIT can be + * used, mainly for use iOS/tvOS. On other platforms the result is true. + */ + +#define RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE (75 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* struct retro_microphone_interface * -- + * Returns an interface that can be used to receive input from the microphone driver. + * + * Returns true if microphone support is available, + * even if no microphones are plugged in. + * Returns false if mic support is disabled or unavailable. + * + * This callback can be invoked at any time, + * even before the microphone driver is ready. + */ + + /* Environment 76 was an obsolete version of RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE. + * It was not used by any known core at the time, and was removed from the API. */ + +#define RETRO_ENVIRONMENT_GET_DEVICE_POWER (77 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* struct retro_device_power * -- + * Returns the device's current power state as reported by the frontend. + * This is useful for emulating the battery level in handheld consoles, + * or for reducing power consumption when on battery power. + * + * The return value indicates whether the frontend can provide this information, + * even if the parameter is NULL. + * + * If the frontend does not support this functionality, + * then the provided argument will remain unchanged. + * + * Note that this environment call describes the power state for the entire device, + * not for individual peripherals like controllers. + */ + +#define RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE 78 + /* const struct retro_netpacket_callback * -- + * When set, a core gains control over network packets sent and + * received during a multiplayer session. This can be used to + * emulate multiplayer games that were originally played on two + * or more separate consoles or computers connected together. + * + * The frontend will take care of connecting players together, + * and the core only needs to send the actual data as needed for + * the emulation, while handshake and connection management happen + * in the background. + * + * When two or more players are connected and this interface has + * been set, time manipulation features (such as pausing, slow motion, + * fast forward, rewinding, save state loading, etc.) are disabled to + * avoid interrupting communication. + * + * Should be set in either retro_init or retro_load_game, but not both. + * + * When not set, a frontend may use state serialization-based + * multiplayer, where a deterministic core supporting multiple + * input devices does not need to take any action on its own. + */ + /* VFS functionality */ /* File paths: @@ -1941,13 +2027,13 @@ struct retro_vfs_interface_info enum retro_hw_render_interface_type { - RETRO_HW_RENDER_INTERFACE_VULKAN = 0, - RETRO_HW_RENDER_INTERFACE_D3D9 = 1, - RETRO_HW_RENDER_INTERFACE_D3D10 = 2, - RETRO_HW_RENDER_INTERFACE_D3D11 = 3, - RETRO_HW_RENDER_INTERFACE_D3D12 = 4, + RETRO_HW_RENDER_INTERFACE_VULKAN = 0, + RETRO_HW_RENDER_INTERFACE_D3D9 = 1, + 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 + RETRO_HW_RENDER_INTERFACE_DUMMY = INT_MAX }; /* Base struct. All retro_hw_render_interface_* types @@ -2723,9 +2809,17 @@ enum retro_hw_context_type /* Vulkan, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE. */ RETRO_HW_CONTEXT_VULKAN = 6, - /* Direct3D, set version_major to select the type of interface - * returned by RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */ - RETRO_HW_CONTEXT_DIRECT3D = 7, + /* Direct3D11, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */ + RETRO_HW_CONTEXT_D3D11 = 7, + + /* Direct3D10, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */ + RETRO_HW_CONTEXT_D3D10 = 8, + + /* Direct3D12, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */ + RETRO_HW_CONTEXT_D3D12 = 9, + + /* Direct3D9, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */ + RETRO_HW_CONTEXT_D3D9 = 10, RETRO_HW_CONTEXT_DUMMY = INT_MAX }; @@ -2980,6 +3074,118 @@ struct retro_disk_control_ext_callback retro_get_image_label_t get_image_label; /* Optional - may be NULL */ }; +/* Definitions for RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE. + * A core can set it if sending and receiving custom network packets + * during a multiplayer session is desired. + */ + +/* Netpacket flags for retro_netpacket_send_t */ +#define RETRO_NETPACKET_UNRELIABLE 0 /* Packet to be sent unreliable, depending on network quality it might not arrive. */ +#define RETRO_NETPACKET_RELIABLE (1 << 0) /* Reliable packets are guaranteed to arrive at the target in the order they were sent. */ +#define RETRO_NETPACKET_UNSEQUENCED (1 << 1) /* Packet will not be sequenced with other packets and may arrive out of order. Cannot be set on reliable packets. */ +#define RETRO_NETPACKET_FLUSH_HINT (1 << 2) /* Request the packet and any previously buffered ones to be sent immediately */ + +/* Broadcast client_id for retro_netpacket_send_t */ +#define RETRO_NETPACKET_BROADCAST 0xFFFF + +/* Used by the core to send a packet to one or all connected players. + * A single packet sent via this interface can contain up to 64 KB of data. + * + * The client_id RETRO_NETPACKET_BROADCAST sends the packet as a broadcast to + * all connected players. This is supported from the host as well as clients. +* Otherwise, the argument indicates the player to send the packet to. + * + * A frontend must support sending reliable packets (RETRO_NETPACKET_RELIABLE). + * Unreliable packets might not be supported by the frontend, but the flags can + * still be specified. Reliable transmission will be used instead. + * + * Calling this with the flag RETRO_NETPACKET_FLUSH_HINT will send off the + * packet and any previously buffered ones immediately and without blocking. + * To only flush previously queued packets, buf or len can be passed as NULL/0. + * + * This function is not guaranteed to be thread-safe and must be called during + * retro_run or any of the netpacket callbacks passed with this interface. + */ +typedef void (RETRO_CALLCONV *retro_netpacket_send_t)(int flags, const void* buf, size_t len, uint16_t client_id); + +/* Optionally read any incoming packets without waiting for the end of the + * frame. While polling, retro_netpacket_receive_t and retro_netpacket_stop_t + * can be called. The core can perform this in a loop to do a blocking read, + * i.e., wait for incoming data, but needs to handle stop getting called and + * also give up after a short while to avoid freezing on a connection problem. + * It is a good idea to manually flush outgoing packets before calling this. + * + * This function is not guaranteed to be thread-safe and must be called during + * retro_run or any of the netpacket callbacks passed with this interface. + */ +typedef void (RETRO_CALLCONV *retro_netpacket_poll_receive_t)(void); + +/* Called by the frontend to signify that a multiplayer session has started. + * If client_id is 0 the local player is the host of the session and at this + * point no other player has connected yet. + * + * If client_id is > 0 the local player is a client connected to a host and + * at this point is already fully connected to the host. + * + * The core must store the function pointer send_fn and use it whenever it + * wants to send a packet. Optionally poll_receive_fn can be stored and used + * when regular receiving between frames is not enough. These function pointers + * remain valid until the frontend calls retro_netpacket_stop_t. + */ +typedef void (RETRO_CALLCONV *retro_netpacket_start_t)(uint16_t client_id, retro_netpacket_send_t send_fn, retro_netpacket_poll_receive_t poll_receive_fn); + +/* Called by the frontend when a new packet arrives which has been sent from + * another player with retro_netpacket_send_t. The client_id argument indicates + * who has sent the packet. + */ +typedef void (RETRO_CALLCONV *retro_netpacket_receive_t)(const void* buf, size_t len, uint16_t client_id); + +/* Called by the frontend when the multiplayer session has ended. + * Once this gets called the function pointers passed to + * retro_netpacket_start_t will not be valid anymore. + */ +typedef void (RETRO_CALLCONV *retro_netpacket_stop_t)(void); + +/* Called by the frontend every frame (between calls to retro_run while + * updating the state of the multiplayer session. + * This is a good place for the core to call retro_netpacket_send_t from. + */ +typedef void (RETRO_CALLCONV *retro_netpacket_poll_t)(void); + +/* Called by the frontend when a new player connects to the hosted session. + * This is only called on the host side, not for clients connected to the host. + * If this function returns false, the newly connected player gets dropped. + * This can be used for example to limit the number of players. + */ +typedef bool (RETRO_CALLCONV *retro_netpacket_connected_t)(uint16_t client_id); + +/* Called by the frontend when a player leaves or disconnects from the hosted session. + * This is only called on the host side, not for clients connected to the host. + */ +typedef void (RETRO_CALLCONV *retro_netpacket_disconnected_t)(uint16_t client_id); + +/** + * A callback interface for giving a core the ability to send and receive custom + * network packets during a multiplayer session between two or more instances + * of a libretro frontend. + * + * Normally during connection handshake the frontend will compare library_version + * used by both parties and show a warning if there is a difference. When the core + * supplies protocol_version, the frontend will check against this instead. + * + * @see RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE + */ +struct retro_netpacket_callback +{ + retro_netpacket_start_t start; + retro_netpacket_receive_t receive; + retro_netpacket_stop_t stop; /* Optional - may be NULL */ + retro_netpacket_poll_t poll; /* Optional - may be NULL */ + retro_netpacket_connected_t connected; /* Optional - may be NULL */ + retro_netpacket_disconnected_t disconnected; /* Optional - may be NULL */ + const char* protocol_version; /* Optional - if not NULL will be used instead of core version to decide if communication is compatible */ +}; + enum retro_pixel_format { /* 0RGB1555, native endian. @@ -3782,6 +3988,289 @@ struct retro_throttle_state float rate; }; +/** + * Opaque handle to a microphone that's been opened for use. + * The underlying object is accessed or created with \c retro_microphone_interface_t. + */ +typedef struct retro_microphone retro_microphone_t; + +/** + * Parameters for configuring a microphone. + * Some of these might not be honored, + * depending on the available hardware and driver configuration. + */ +typedef struct retro_microphone_params +{ + /** + * The desired sample rate of the microphone's input, in Hz. + * The microphone's input will be resampled, + * so cores can ask for whichever frequency they need. + * + * If zero, some reasonable default will be provided by the frontend + * (usually from its config file). + * + * @see retro_get_mic_rate_t + */ + unsigned rate; +} retro_microphone_params_t; + +/** + * @copydoc retro_microphone_interface::open_mic + */ +typedef retro_microphone_t *(RETRO_CALLCONV *retro_open_mic_t)(const retro_microphone_params_t *params); + +/** + * @copydoc retro_microphone_interface::close_mic + */ +typedef void (RETRO_CALLCONV *retro_close_mic_t)(retro_microphone_t *microphone); + +/** + * @copydoc retro_microphone_interface::get_params + */ +typedef bool (RETRO_CALLCONV *retro_get_mic_params_t)(const retro_microphone_t *microphone, retro_microphone_params_t *params); + +/** + * @copydoc retro_microphone_interface::set_mic_state + */ +typedef bool (RETRO_CALLCONV *retro_set_mic_state_t)(retro_microphone_t *microphone, bool state); + +/** + * @copydoc retro_microphone_interface::get_mic_state + */ +typedef bool (RETRO_CALLCONV *retro_get_mic_state_t)(const retro_microphone_t *microphone); + +/** + * @copydoc retro_microphone_interface::read_mic + */ +typedef int (RETRO_CALLCONV *retro_read_mic_t)(retro_microphone_t *microphone, int16_t* samples, size_t num_samples); + +/** + * The current version of the microphone interface. + * Will be incremented whenever \c retro_microphone_interface or \c retro_microphone_params_t + * receive new fields. + * + * Frontends using cores built against older mic interface versions + * should not access fields introduced in newer versions. + */ +#define RETRO_MICROPHONE_INTERFACE_VERSION 1 + +/** + * An interface for querying the microphone and accessing data read from it. + * + * @see RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE + */ +struct retro_microphone_interface +{ + /** + * The version of this microphone interface. + * Set by the core to request a particular version, + * and set by the frontend to indicate the returned version. + * 0 indicates that the interface is invalid or uninitialized. + */ + unsigned interface_version; + + /** + * Initializes a new microphone. + * Assuming that microphone support is enabled and provided by the frontend, + * cores may call this function whenever necessary. + * A microphone could be opened throughout a core's lifetime, + * or it could wait until a microphone is plugged in to the emulated device. + * + * The returned handle will be valid until it's freed, + * even if the audio driver is reinitialized. + * + * This function is not guaranteed to be thread-safe. + * + * @param args[in] Parameters used to create the microphone. + * May be \c NULL, in which case the default value of each parameter will be used. + * + * @returns Pointer to the newly-opened microphone, + * or \c NULL if one couldn't be opened. + * This likely means that no microphone is plugged in and recognized, + * or the maximum number of supported microphones has been reached. + * + * @note Microphones are \em inactive by default; + * to begin capturing audio, call \c set_mic_state. + * @see retro_microphone_params_t + */ + retro_open_mic_t open_mic; + + /** + * Closes a microphone that was initialized with \c open_mic. + * Calling this function will stop all microphone activity + * and free up the resources that it allocated. + * Afterwards, the handle is invalid and must not be used. + * + * A frontend may close opened microphones when unloading content, + * but this behavior is not guaranteed. + * Cores should close their microphones when exiting, just to be safe. + * + * @param microphone Pointer to the microphone that was allocated by \c open_mic. + * If \c NULL, this function does nothing. + * + * @note The handle might be reused if another microphone is opened later. + */ + retro_close_mic_t close_mic; + + /** + * Returns the configured parameters of this microphone. + * These may differ from what was requested depending on + * the driver and device configuration. + * + * Cores should check these values before they start fetching samples. + * + * Will not change after the mic was opened. + * + * @param microphone[in] Opaque handle to the microphone + * whose parameters will be retrieved. + * @param params[out] The parameters object that the + * microphone's parameters will be copied to. + * + * @return \c true if the parameters were retrieved, + * \c false if there was an error. + */ + retro_get_mic_params_t get_params; + + /** + * Enables or disables the given microphone. + * Microphones are disabled by default + * and must be explicitly enabled before they can be used. + * Disabled microphones will not process incoming audio samples, + * and will therefore have minimal impact on overall performance. + * Cores may enable microphones throughout their lifetime, + * or only for periods where they're needed. + * + * Cores that accept microphone input should be able to operate without it; + * we suggest substituting silence in this case. + * + * @param microphone Opaque handle to the microphone + * whose state will be adjusted. + * This will have been provided by \c open_mic. + * @param state \c true if the microphone should receive audio input, + * \c false if it should be idle. + * @returns \c true if the microphone's state was successfully set, + * \c false if \c microphone is invalid + * or if there was an error. + */ + retro_set_mic_state_t set_mic_state; + + /** + * Queries the active state of a microphone at the given index. + * Will return whether the microphone is enabled, + * even if the driver is paused. + * + * @param microphone Opaque handle to the microphone + * whose state will be queried. + * @return \c true if the provided \c microphone is valid and active, + * \c false if not or if there was an error. + */ + retro_get_mic_state_t get_mic_state; + + /** + * Retrieves the input processed by the microphone since the last call. + * \em Must be called every frame unless \c microphone is disabled, + * similar to how \c retro_audio_sample_batch_t works. + * + * @param[in] microphone Opaque handle to the microphone + * whose recent input will be retrieved. + * @param[out] samples The buffer that will be used to store the microphone's data. + * Microphone input is in mono (i.e. one number per sample). + * Should be large enough to accommodate the expected number of samples per frame; + * for example, a 44.1kHz sample rate at 60 FPS would require space for 735 samples. + * @param[in] num_samples The size of the data buffer in samples (\em not bytes). + * Microphone input is in mono, so a "frame" and a "sample" are equivalent in length here. + * + * @return The number of samples that were copied into \c samples. + * If \c microphone is pending driver initialization, + * this function will copy silence of the requested length into \c samples. + * + * Will return -1 if the microphone is disabled, + * the audio driver is paused, + * or there was an error. + */ + retro_read_mic_t read_mic; +}; + +/** + * Describes how a device is being powered. + * @see RETRO_ENVIRONMENT_GET_DEVICE_POWER + */ +enum retro_power_state +{ + /** + * Indicates that the frontend cannot report its power state at this time, + * most likely due to a lack of support. + * + * \c RETRO_ENVIRONMENT_GET_DEVICE_POWER will not return this value; + * instead, the environment callback will return \c false. + */ + RETRO_POWERSTATE_UNKNOWN = 0, + + /** + * Indicates that the device is running on its battery. + * Usually applies to portable devices such as handhelds, laptops, and smartphones. + */ + RETRO_POWERSTATE_DISCHARGING, + + /** + * Indicates that the device's battery is currently charging. + */ + RETRO_POWERSTATE_CHARGING, + + /** + * Indicates that the device is connected to a power source + * and that its battery has finished charging. + */ + RETRO_POWERSTATE_CHARGED, + + /** + * Indicates that the device is connected to a power source + * and that it does not have a battery. + * This usually suggests a desktop computer or a non-portable game console. + */ + RETRO_POWERSTATE_PLUGGED_IN +}; + +/** + * Indicates that an estimate is not available for the battery level or time remaining, + * even if the actual power state is known. + */ +#define RETRO_POWERSTATE_NO_ESTIMATE (-1) + +/** + * Describes the power state of the device running the frontend. + * @see RETRO_ENVIRONMENT_GET_DEVICE_POWER + */ +struct retro_device_power +{ + /** + * The current state of the frontend's power usage. + */ + enum retro_power_state state; + + /** + * A rough estimate of the amount of time remaining (in seconds) + * before the device powers off. + * This value depends on a variety of factors, + * so it is not guaranteed to be accurate. + * + * Will be set to \c RETRO_POWERSTATE_NO_ESTIMATE if \c state does not equal \c RETRO_POWERSTATE_DISCHARGING. + * May still be set to \c RETRO_POWERSTATE_NO_ESTIMATE if the frontend is unable to provide an estimate. + */ + int seconds; + + /** + * The approximate percentage of battery charge, + * ranging from 0 to 100 (inclusive). + * The device may power off before this reaches 0. + * + * The user might have configured their device + * to stop charging before the battery is full, + * so do not assume that this will be 100 in the \c RETRO_POWERSTATE_CHARGED state. + */ + int8_t percent; +}; + /* Callbacks */ /* Environment callback. Gives implementations a way of performing diff --git a/src/drivers/libretro/libretro-common/include/libretro_gskit_ps2.h b/libretro/libretro-common/include/libretro_gskit_ps2.h similarity index 100% rename from src/drivers/libretro/libretro-common/include/libretro_gskit_ps2.h rename to libretro/libretro-common/include/libretro_gskit_ps2.h diff --git a/libretro/libretro-common/include/memalign.h b/libretro/libretro-common/include/memalign.h new file mode 100644 index 000000000..59ffbd743 --- /dev/null +++ b/libretro/libretro-common/include/memalign.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2010-2020 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (memalign.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_MEMALIGN_H +#define _LIBRETRO_MEMALIGN_H + +#include + +#include + +RETRO_BEGIN_DECLS + +void *memalign_alloc(size_t boundary, size_t size); + +void *memalign_alloc_aligned(size_t size); + +void memalign_free(void *ptr); + +RETRO_END_DECLS + +#endif diff --git a/src/drivers/libretro/libretro-common/include/retro_assert.h b/libretro/libretro-common/include/retro_assert.h similarity index 100% rename from src/drivers/libretro/libretro-common/include/retro_assert.h rename to libretro/libretro-common/include/retro_assert.h diff --git a/src/drivers/libretro/libretro-common/include/retro_common.h b/libretro/libretro-common/include/retro_common.h similarity index 100% rename from src/drivers/libretro/libretro-common/include/retro_common.h rename to libretro/libretro-common/include/retro_common.h diff --git a/src/drivers/libretro/libretro-common/include/retro_common_api.h b/libretro/libretro-common/include/retro_common_api.h similarity index 85% rename from src/drivers/libretro/libretro-common/include/retro_common_api.h rename to libretro/libretro-common/include/retro_common_api.h index 0f68b7d98..ebb645d8d 100644 --- a/src/drivers/libretro/libretro-common/include/retro_common_api.h +++ b/libretro/libretro-common/include/retro_common_api.h @@ -101,6 +101,26 @@ typedef int ssize_t; #define STRING_REP_UINT64 "%" PRIu64 #define STRING_REP_USIZE "%" PRIuPTR +/* Wrap a declaration in RETRO_DEPRECATED() to produce a compiler warning when +it's used. This is intended for developer machines, so it won't work on ancient +or obscure compilers */ +#if defined(_MSC_VER) +#if _MSC_VER >= 1400 /* Visual C 2005 or later */ +#define RETRO_DEPRECATED(decl) __declspec(deprecated) decl +#endif +#elif defined(__GNUC__) +#if __GNUC__ >= 3 /* GCC 3 or later */ +#define RETRO_DEPRECATED(decl) decl __attribute__((deprecated)) +#endif +#elif defined(__clang__) +#if __clang_major__ >= 3 /* clang 3 or later */ +#define RETRO_DEPRECATED(decl) decl __attribute__((deprecated)) +#endif +#endif +#ifndef RETRO_DEPRECATED /* Unsupported compilers */ +#define RETRO_DEPRECATED(decl) decl +#endif + /* I would like to see retro_inline.h moved in here; possibly boolean too. diff --git a/src/drivers/libretro/libretro-common/include/retro_environment.h b/libretro/libretro-common/include/retro_environment.h similarity index 100% rename from src/drivers/libretro/libretro-common/include/retro_environment.h rename to libretro/libretro-common/include/retro_environment.h diff --git a/src/drivers/libretro/libretro-common/include/retro_inline.h b/libretro/libretro-common/include/retro_inline.h similarity index 100% rename from src/drivers/libretro/libretro-common/include/retro_inline.h rename to libretro/libretro-common/include/retro_inline.h diff --git a/src/drivers/libretro/libretro-common/include/retro_miscellaneous.h b/libretro/libretro-common/include/retro_miscellaneous.h similarity index 98% rename from src/drivers/libretro/libretro-common/include/retro_miscellaneous.h rename to libretro/libretro-common/include/retro_miscellaneous.h index a3d2854f0..a42ed176b 100644 --- a/src/drivers/libretro/libretro-common/include/retro_miscellaneous.h +++ b/libretro/libretro-common/include/retro_miscellaneous.h @@ -49,6 +49,10 @@ #include #endif +#ifdef IOS +#include +#endif + static INLINE void bits_or_bits(uint32_t *a, uint32_t *b, uint32_t count) { uint32_t i; @@ -86,7 +90,7 @@ static INLINE bool bits_any_different(uint32_t *a, uint32_t *b, uint32_t count) } #ifndef PATH_MAX_LENGTH -#if defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(__PSL1GHT__) || defined(__PS3__) +#if defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(__PSL1GHT__) || defined(__PS3__) || defined(HAVE_EMSCRIPTEN) #define PATH_MAX_LENGTH 512 #else #define PATH_MAX_LENGTH 4096 diff --git a/src/drivers/libretro/libretro-common/include/streams/file_stream.h b/libretro/libretro-common/include/streams/file_stream.h similarity index 100% rename from src/drivers/libretro/libretro-common/include/streams/file_stream.h rename to libretro/libretro-common/include/streams/file_stream.h diff --git a/src/drivers/libretro/libretro-common/include/streams/file_stream_transforms.h b/libretro/libretro-common/include/streams/file_stream_transforms.h similarity index 100% rename from src/drivers/libretro/libretro-common/include/streams/file_stream_transforms.h rename to libretro/libretro-common/include/streams/file_stream_transforms.h diff --git a/src/drivers/libretro/libretro-common/include/streams/memory_stream.h b/libretro/libretro-common/include/streams/memory_stream.h similarity index 100% rename from src/drivers/libretro/libretro-common/include/streams/memory_stream.h rename to libretro/libretro-common/include/streams/memory_stream.h diff --git a/src/drivers/libretro/libretro-common/include/string/stdstring.h b/libretro/libretro-common/include/string/stdstring.h similarity index 98% rename from src/drivers/libretro/libretro-common/include/string/stdstring.h rename to libretro/libretro-common/include/string/stdstring.h index 79fa40955..4e38e8d4c 100644 --- a/src/drivers/libretro/libretro-common/include/string/stdstring.h +++ b/libretro/libretro-common/include/string/stdstring.h @@ -48,7 +48,7 @@ RETRO_BEGIN_DECLS #define TOUPPER(c) ((c) & ~(lr_char_props[(unsigned char)(c)] & 0x20)) /* C standard says \f \v are space, but this one disagrees */ -#define ISSPACE(c) (lr_char_props[(unsigned char)(c)] & 0x80) +#define ISSPACE(c) (lr_char_props[(unsigned char)(c)] & 0x80) #define ISDIGIT(c) (lr_char_props[(unsigned char)(c)] & 0x40) #define ISALPHA(c) (lr_char_props[(unsigned char)(c)] & 0x20) @@ -204,7 +204,7 @@ char *string_trim_whitespace(char *const s); * correctly any text containing so-called 'wide' Unicode * characters (e.g. CJK languages, emojis, etc.). **/ -void word_wrap(char *dst, size_t dst_size, const char *src, size_t src_len, +size_t word_wrap(char *dst, size_t dst_size, const char *src, size_t src_len, int line_width, int wideglyph_width, unsigned max_lines); /** @@ -241,7 +241,7 @@ void word_wrap(char *dst, size_t dst_size, const char *src, size_t src_len, * on-screen pixel width deviates greatly from the set * @wideglyph_width value. **/ -void word_wrap_wideglyph( +size_t word_wrap_wideglyph( char *dst, size_t dst_size, const char *src, size_t src_len, int line_width, int wideglyph_width, @@ -331,7 +331,7 @@ int string_count_occurrences_single_character(const char *str, char c); /** * string_replace_whitespace_with_single_character: - * + * * Leaf function. * * Replaces all spaces with given character @c. diff --git a/src/drivers/libretro/libretro-common/include/time/rtime.h b/libretro/libretro-common/include/time/rtime.h similarity index 100% rename from src/drivers/libretro/libretro-common/include/time/rtime.h rename to libretro/libretro-common/include/time/rtime.h diff --git a/src/drivers/libretro/libretro-common/include/vfs/vfs.h b/libretro/libretro-common/include/vfs/vfs.h similarity index 100% rename from src/drivers/libretro/libretro-common/include/vfs/vfs.h rename to libretro/libretro-common/include/vfs/vfs.h diff --git a/src/drivers/libretro/libretro-common/include/vfs/vfs_implementation.h b/libretro/libretro-common/include/vfs/vfs_implementation.h similarity index 100% rename from src/drivers/libretro/libretro-common/include/vfs/vfs_implementation.h rename to libretro/libretro-common/include/vfs/vfs_implementation.h diff --git a/libretro/libretro-common/memmap/memalign.c b/libretro/libretro-common/memmap/memalign.c new file mode 100644 index 000000000..14eaeffdb --- /dev/null +++ b/libretro/libretro-common/memmap/memalign.c @@ -0,0 +1,63 @@ +/* Copyright (C) 2010-2020 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (memalign.c). + * --------------------------------------------------------------------------------------- + * + * 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. + */ + +#include +#include + +#include + +void *memalign_alloc(size_t boundary, size_t size) +{ + void **place = NULL; + uintptr_t addr = 0; + void *ptr = (void*)malloc(boundary + size + sizeof(uintptr_t)); + if (!ptr) + return NULL; + + addr = ((uintptr_t)ptr + sizeof(uintptr_t) + boundary) + & ~(boundary - 1); + place = (void**)addr; + place[-1] = ptr; + + return (void*)addr; +} + +void memalign_free(void *ptr) +{ + void **p = NULL; + if (!ptr) + return; + + p = (void**)ptr; + free(p[-1]); +} + +void *memalign_alloc_aligned(size_t size) +{ +#if defined(__x86_64__) || defined(__LP64) || defined(__IA64__) || defined(_M_X64) || defined(_M_X64) || defined(_WIN64) + return memalign_alloc(64, size); +#elif defined(__i386__) || defined(__i486__) || defined(__i686__) || defined(GEKKO) || defined(_M_IX86) + return memalign_alloc(32, size); +#else + return memalign_alloc(32, size); +#endif +} diff --git a/src/drivers/libretro/libretro-common/streams/file_stream.c b/libretro/libretro-common/streams/file_stream.c similarity index 99% rename from src/drivers/libretro/libretro-common/streams/file_stream.c rename to libretro/libretro-common/streams/file_stream.c index 3956f087d..befb31c70 100644 --- a/src/drivers/libretro/libretro-common/streams/file_stream.c +++ b/libretro/libretro-common/streams/file_stream.c @@ -221,7 +221,7 @@ int filestream_vscanf(RFILE *stream, const char* format, va_list *args) va_list args_copy; const char *bufiter = buf; int ret = 0; - int64_t startpos = 0; + int64_t startpos = filestream_tell(stream); int64_t maxlen = filestream_read(stream, buf, sizeof(buf)-1); if (maxlen <= 0) @@ -330,7 +330,6 @@ int filestream_vscanf(RFILE *stream, const char* format, va_list *args) } va_end(args_copy); - startpos = filestream_tell(stream); filestream_seek(stream, startpos + (bufiter - buf), RETRO_VFS_SEEK_POSITION_START); diff --git a/src/drivers/libretro/libretro-common/streams/file_stream_transforms.c b/libretro/libretro-common/streams/file_stream_transforms.c similarity index 100% rename from src/drivers/libretro/libretro-common/streams/file_stream_transforms.c rename to libretro/libretro-common/streams/file_stream_transforms.c diff --git a/src/drivers/libretro/libretro-common/streams/memory_stream.c b/libretro/libretro-common/streams/memory_stream.c similarity index 100% rename from src/drivers/libretro/libretro-common/streams/memory_stream.c rename to libretro/libretro-common/streams/memory_stream.c diff --git a/src/drivers/libretro/libretro-common/string/stdstring.c b/libretro/libretro-common/string/stdstring.c similarity index 95% rename from src/drivers/libretro/libretro-common/string/stdstring.c rename to libretro/libretro-common/string/stdstring.c index 4b36deb77..7f05883d0 100644 --- a/src/drivers/libretro/libretro-common/string/stdstring.c +++ b/libretro/libretro-common/string/stdstring.c @@ -217,27 +217,24 @@ char *string_trim_whitespace(char *const s) * correctly any text containing so-called 'wide' Unicode * characters (e.g. CJK languages, emojis, etc.). **/ -void word_wrap( +size_t word_wrap( char *dst, size_t dst_size, const char *src, size_t src_len, int line_width, int wideglyph_width, unsigned max_lines) { - char *lastspace = NULL; + char *last_space = NULL; unsigned counter = 0; unsigned lines = 1; const char *src_end = src + src_len; /* Prevent buffer overflow */ if (dst_size < src_len + 1) - return; + return 0; /* Early return if src string length is less * than line width */ if (src_len < (size_t)line_width) - { - strlcpy(dst, src, dst_size); - return; - } + return strlcpy(dst, src, dst_size); while (*src != '\0') { @@ -245,21 +242,18 @@ void word_wrap( counter++; if (*src == ' ') - lastspace = dst; /* Remember the location of the whitespace */ + last_space = dst; /* Remember the location of the whitespace */ else if (*src == '\n') { /* If newlines embedded in the input, * reset the index */ lines++; - counter = 0; + counter = 0; /* Early return if remaining src string * length is less than line width */ if (src_end - src <= line_width) - { - strlcpy(dst, src, dst_size); - return; - } + return strlcpy(dst, src, dst_size); } while (char_len--) @@ -269,29 +263,27 @@ void word_wrap( { counter = 0; - if (lastspace && (max_lines == 0 || lines < max_lines)) + if (last_space && (max_lines == 0 || lines < max_lines)) { /* Replace nearest (previous) whitespace * with newline character */ - *lastspace = '\n'; + *last_space = '\n'; lines++; - src -= dst - lastspace - 1; - dst = lastspace + 1; - lastspace = NULL; + src -= dst - last_space - 1; + dst = last_space + 1; + last_space = NULL; /* Early return if remaining src string * length is less than line width */ if (src_end - src < line_width) - { - strlcpy(dst, src, dst_size); - return; - } + return strlcpy(dst, src, dst_size); } } } *dst = '\0'; + return 0; } /** @@ -327,7 +319,7 @@ void word_wrap( * on-screen pixel width deviates greatly from the set * @wideglyph_width value. **/ -void word_wrap_wideglyph(char *dst, size_t dst_size, +size_t word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, size_t src_len, int line_width, int wideglyph_width, unsigned max_lines) { @@ -359,14 +351,11 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, unsigned counter_normalized = 0; int line_width_normalized = line_width * 100; int additional_counter_normalized = wideglyph_width - 100; - + /* Early return if src string length is less * than line width */ if (src_end - src < line_width) - { - strlcpy(dst, src, dst_size); - return; - } + return strlcpy(dst, src, dst_size); while (*src != '\0') { @@ -389,10 +378,7 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, /* Early return if remaining src string * length is less than line width */ if (src_end - src <= line_width) - { - strlcpy(dst, src, dst_size); - return; - } + return strlcpy(dst, src, dst_size); } else if (char_len >= 3) { @@ -424,10 +410,7 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, /* Early return if remaining src string * length is less than line width */ if (src_end - src <= line_width) - { - strlcpy(dst, src, dst_size); - return; - } + return strlcpy(dst, src, dst_size); } else if (lastspace) { @@ -442,15 +425,13 @@ void word_wrap_wideglyph(char *dst, size_t dst_size, /* Early return if remaining src string * length is less than line width */ if (src_end - src < line_width) - { - strlcpy(dst, src, dst_size); - return; - } + return strlcpy(dst, src, dst_size); } } } *dst = '\0'; + return 0; } /** @@ -592,7 +573,7 @@ unsigned string_hex_to_unsigned(const char *str) if (str[0] != '\0' && str[1] != '\0') { if ( (str[0] == '0') && - ((str[1] == 'x') || + ((str[1] == 'x') || (str[1] == 'X'))) { hex_str = str + 2; @@ -635,7 +616,7 @@ int string_count_occurrences_single_character(const char *str, char c) /** * string_replace_whitespace_with_single_character: - * + * * Leaf function. * * Replaces all spaces with given character @c. diff --git a/src/drivers/libretro/libretro-common/time/rtime.c b/libretro/libretro-common/time/rtime.c similarity index 97% rename from src/drivers/libretro/libretro-common/time/rtime.c rename to libretro/libretro-common/time/rtime.c index d66c228fb..fee0dabcb 100644 --- a/src/drivers/libretro/libretro-common/time/rtime.c +++ b/libretro/libretro-common/time/rtime.c @@ -22,7 +22,6 @@ #ifdef HAVE_THREADS #include -#include #include #endif @@ -41,8 +40,6 @@ void rtime_init(void) #ifdef HAVE_THREADS if (!rtime_localtime_lock) rtime_localtime_lock = slock_new(); - - retro_assert(rtime_localtime_lock); #endif } diff --git a/src/drivers/libretro/libretro-common/vfs/vfs_implementation.c b/libretro/libretro-common/vfs/vfs_implementation.c similarity index 84% rename from src/drivers/libretro/libretro-common/vfs/vfs_implementation.c rename to libretro/libretro-common/vfs/vfs_implementation.c index ec3529d25..2d958fe05 100644 --- a/src/drivers/libretro/libretro-common/vfs/vfs_implementation.c +++ b/libretro/libretro-common/vfs/vfs_implementation.c @@ -120,9 +120,60 @@ #endif #if defined(__PS3__) || defined(__PSL1GHT__) -#include -#if defined(__PSL1GHT__) +#define FS_SUCCEEDED 0 +#define FS_TYPE_DIR 1 +#ifdef __PSL1GHT__ #include +#ifndef O_RDONLY +#define O_RDONLY SYS_O_RDONLY +#endif +#ifndef O_WRONLY +#define O_WRONLY SYS_O_WRONLY +#endif +#ifndef O_CREAT +#define O_CREAT SYS_O_CREAT +#endif +#ifndef O_TRUNC +#define O_TRUNC SYS_O_TRUNC +#endif +#ifndef O_RDWR +#define O_RDWR SYS_O_RDWR +#endif +#else +#include +#ifndef O_RDONLY +#define O_RDONLY CELL_FS_O_RDONLY +#endif +#ifndef O_WRONLY +#define O_WRONLY CELL_FS_O_WRONLY +#endif +#ifndef O_CREAT +#define O_CREAT CELL_FS_O_CREAT +#endif +#ifndef O_TRUNC +#define O_TRUNC CELL_FS_O_TRUNC +#endif +#ifndef O_RDWR +#define O_RDWR CELL_FS_O_RDWR +#endif +#ifndef sysFsStat +#define sysFsStat cellFsStat +#endif +#ifndef sysFSDirent +#define sysFSDirent CellFsDirent +#endif +#ifndef sysFsOpendir +#define sysFsOpendir cellFsOpendir +#endif +#ifndef sysFsReaddir +#define sysFsReaddir cellFsReaddir +#endif +#ifndef sysFSDirent +#define sysFSDirent CellFsDirent +#endif +#ifndef sysFsClosedir +#define sysFsClosedir cellFsClosedir +#endif #endif #endif @@ -250,7 +301,7 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl( { int flags = 0; const char *mode_str = NULL; - libretro_vfs_implementation_file *stream = + libretro_vfs_implementation_file *stream = (libretro_vfs_implementation_file*) malloc(sizeof(*stream)); @@ -401,14 +452,14 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl( * * https://www.freebsd.org/cgi/man.cgi?query=setvbuf&apropos=0&sektion=0&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html * - * If the size argument is not zero but buf is NULL, + * If the size argument is not zero but buf is NULL, * a buffer of the given size will be allocated immediately, and * released on close. This is an extension to ANSI C. * - * Since C89 does not support specifying a NULL buffer + * Since C89 does not support specifying a NULL buffer * with a non-zero size, we create and track our own buffer for it. */ - /* TODO: this is only useful for a few platforms, + /* TODO: this is only useful for a few platforms, * find which and add ifdef */ #if defined(_3DS) if (stream->scheme != VFS_SCHEME_CDROM) @@ -597,7 +648,7 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream) #ifdef HAVE_MMAP /* Need to check stream->mapped because this function * is called in filestream_open() */ - if (stream->mapped && stream->hints & + if (stream->mapped && stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS) return stream->mappos; #endif @@ -648,15 +699,15 @@ int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream, int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file *stream, const void *s, uint64_t len) { - int64_t pos = 0; - size_t result = -1; + int64_t pos = 0; + ssize_t result = -1; if (!stream) return -1; if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) { - pos = retro_vfs_file_tell_impl(stream); + pos = retro_vfs_file_tell_impl(stream); result = fwrite(s, 1, (size_t)len, stream->fp); if (result != -1 && pos + result > stream->size) @@ -669,7 +720,7 @@ int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file *stream, cons return -1; #endif - pos = retro_vfs_file_tell_impl(stream); + pos = retro_vfs_file_tell_impl(stream); result = write(stream->fd, s, (size_t)len); if (result != -1 && pos + result > stream->size) @@ -687,39 +738,40 @@ int retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream) int retro_vfs_file_remove_impl(const char *path) { + if (path && *path) + { + int ret = -1; #if defined(_WIN32) && !defined(_XBOX) - /* Win32 (no Xbox) */ - + /* Win32 (no Xbox) */ #if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 - char *path_local = NULL; + char *path_local = NULL; + if ((path_local = utf8_to_local_string_alloc(path))) + { + /* We need to check if path is a directory */ + if ((retro_vfs_stat_impl(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0) + ret = _rmdir(path_local); + else + ret = remove(path_local); + free(path_local); + } #else - wchar_t *path_wide = NULL; + wchar_t *path_wide = NULL; + if ((path_wide = utf8_to_utf16_string_alloc(path))) + { + /* We need to check if path is a directory */ + if ((retro_vfs_stat_impl(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0) + ret = _wrmdir(path_wide); + else + ret = _wremove(path_wide); + free(path_wide); + } #endif - if (!path || !*path) - return -1; -#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 - if ((path_local = utf8_to_local_string_alloc(path))) - { - int ret = remove(path_local); - free(path_local); - - if (ret == 0) - return 0; - } #else - if ((path_wide = utf8_to_utf16_string_alloc(path))) - { - int ret = _wremove(path_wide); - free(path_wide); - + ret = remove(path); +#endif if (ret == 0) return 0; } -#endif -#else - if (remove(path) == 0) - return 0; -#endif return -1; } @@ -791,132 +843,118 @@ const char *retro_vfs_file_get_path_impl( int retro_vfs_stat_impl(const char *path, int32_t *size) { - bool is_dir = false; - bool is_character_special = false; -#if defined(VITA) - /* Vita / PSP */ - SceIoStat buf; - int dir_ret; - char *tmp = NULL; - size_t len = 0; + int ret = RETRO_VFS_STAT_IS_VALID; if (!path || !*path) return 0; + { +#if defined(VITA) + /* Vita / PSP */ + SceIoStat stat_buf; + int dir_ret; + char *tmp = strdup(path); + size_t len = strlen(tmp); + if (tmp[len-1] == '/') + tmp[len-1] = '\0'; + + dir_ret = sceIoGetstat(tmp, &stat_buf); + free(tmp); + if (dir_ret < 0) + return 0; - tmp = strdup(path); - len = strlen(tmp); - if (tmp[len-1] == '/') - tmp[len-1] = '\0'; - - dir_ret = sceIoGetstat(tmp, &buf); - free(tmp); - if (dir_ret < 0) - return 0; - - if (size) - *size = (int32_t)buf.st_size; + if (size) + *size = (int32_t)stat_buf.st_size; - is_dir = FIO_S_ISDIR(buf.st_mode); + if (FIO_S_ISDIR(stat_buf.st_mode)) + ret |= RETRO_VFS_STAT_IS_DIRECTORY; #elif defined(__PSL1GHT__) || defined(__PS3__) - /* Lowlevel Lv2 */ - sysFSStat buf; + /* Lowlevel Lv2 */ + sysFSStat stat_buf; - if (!path || !*path) - return 0; - if (sysFsStat(path, &buf) < 0) - return 0; + if (sysFsStat(path, &stat_buf) < 0) + return 0; - if (size) - *size = (int32_t)buf.st_size; + if (size) + *size = (int32_t)stat_buf.st_size; - is_dir = ((buf.st_mode & S_IFMT) == S_IFDIR); + if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) + ret |= RETRO_VFS_STAT_IS_DIRECTORY; #elif defined(_WIN32) - /* Windows */ - DWORD file_info; - struct _stat buf; + /* Windows */ + struct _stat stat_buf; #if defined(LEGACY_WIN32) - char *path_local = NULL; -#else - wchar_t *path_wide = NULL; -#endif + char *path_local = utf8_to_local_string_alloc(path); + DWORD file_info = GetFileAttributes(path_local); - if (!path || !*path) - return 0; + if (!string_is_empty(path_local)) + _stat(path_local, &stat_buf); -#if defined(LEGACY_WIN32) - path_local = utf8_to_local_string_alloc(path); - file_info = GetFileAttributes(path_local); - - if (!string_is_empty(path_local)) - _stat(path_local, &buf); - - if (path_local) - free(path_local); + if (path_local) + free(path_local); #else - path_wide = utf8_to_utf16_string_alloc(path); - file_info = GetFileAttributesW(path_wide); + wchar_t *path_wide = utf8_to_utf16_string_alloc(path); + DWORD file_info = GetFileAttributesW(path_wide); - _wstat(path_wide, &buf); + _wstat(path_wide, &stat_buf); - if (path_wide) - free(path_wide); + if (path_wide) + free(path_wide); #endif + if (file_info == INVALID_FILE_ATTRIBUTES) + return 0; - if (file_info == INVALID_FILE_ATTRIBUTES) - return 0; - - if (size) - *size = (int32_t)buf.st_size; - - is_dir = (file_info & FILE_ATTRIBUTE_DIRECTORY); + if (size) + *size = (int32_t)stat_buf.st_size; + if (file_info & FILE_ATTRIBUTE_DIRECTORY) + ret |= RETRO_VFS_STAT_IS_DIRECTORY; #elif defined(GEKKO) - /* On GEKKO platforms, paths cannot have - * trailing slashes - we must therefore - * remove them */ - char *path_buf = NULL; - int stat_ret = -1; - struct stat stat_buf; - size_t len; - - if (string_is_empty(path)) - return 0; - - if (!(path_buf = strdup(path))) - return 0; - - if ((len = strlen(path_buf)) > 0) - if (path_buf[len - 1] == '/') - path_buf[len - 1] = '\0'; - - stat_ret = stat(path_buf, &stat_buf); - free(path_buf); + /* On GEKKO platforms, paths cannot have + * trailing slashes - we must therefore + * remove them */ + size_t len; + char *path_buf = NULL; + struct stat stat_buf; + + if (!(path_buf = strdup(path))) + return 0; - if (stat_ret < 0) - return 0; + if ((len = strlen(path_buf)) > 0) + if (path_buf[len - 1] == '/') + path_buf[len - 1] = '\0'; - if (size) - *size = (int32_t)stat_buf.st_size; + if (stat(path_buf, &stat_buf) < 0) + { + free(path_buf); + return 0; + } - is_dir = S_ISDIR(stat_buf.st_mode); - is_character_special = S_ISCHR(stat_buf.st_mode); + free(path_buf); + + if (size) + *size = (int32_t)stat_buf.st_size; + if (S_ISDIR(stat_buf.st_mode)) + ret |= RETRO_VFS_STAT_IS_DIRECTORY; + if (S_ISCHR(stat_buf.st_mode)) + ret |= RETRO_VFS_STAT_IS_CHARACTER_SPECIAL; #else - /* Every other platform */ - struct stat buf; + /* Every other platform */ + struct stat stat_buf; - if (!path || !*path) - return 0; - if (stat(path, &buf) < 0) - return 0; + if (stat(path, &stat_buf) < 0) + return 0; - if (size) - *size = (int32_t)buf.st_size; + if (size) + *size = (int32_t)stat_buf.st_size; - is_dir = S_ISDIR(buf.st_mode); - is_character_special = S_ISCHR(buf.st_mode); + if (S_ISDIR(stat_buf.st_mode)) + ret |= RETRO_VFS_STAT_IS_DIRECTORY; + if (S_ISCHR(stat_buf.st_mode)) + ret |= RETRO_VFS_STAT_IS_CHARACTER_SPECIAL; #endif - return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0); + } + return ret; } #if defined(VITA) diff --git a/libretro/libretro.c b/libretro/libretro.c new file mode 100644 index 000000000..0bd39e51c --- /dev/null +++ b/libretro/libretro.c @@ -0,0 +1,2029 @@ +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "../src/fceu.h" +#include "../src/fceu-endian.h" +#include "../src/input.h" +#include "../src/state.h" +#include "../src/ppu.h" +#include "../src/cart.h" +#include "../src/x6502.h" +#include "../src/git.h" +#include "../src/palette.h" +#include "../src/sound.h" +#include "../src/file.h" +#include "../src/cheat.h" +#include "../src/ines.h" +#include "../src/unif.h" +#include "../src/fds.h" +#include "../src/vsuni.h" +#include "../src/video.h" +#include "../src/gamegenie.h" + +#include "libretro_input.h" +#include "paldef.h" + +#if defined(PSP) +#include "pspgu.h" +#endif + +#if defined(PS2) +#include "libretro-common/include/libretro_gskit_ps2.h" +#endif + +#define NES_8_7_PAR(w, h) (((w) * (8.0 / 7.0)) / (h)) +#define NES_4_3(w, h) (((w) / ((h) * (NES_WIDTH / NES_HEIGHT))) * 4.0 / 3.0) +#define NES_PP(w, h) (((w) / ((h) * (NES_WIDTH / NES_HEIGHT))) * 16.0 / 15.0) +#define NES_TARGET_FPS ((double)FCEUI_GetDesiredFPS() / 16777215.0) + +#if defined(_3DS) +void *linearMemAlign(size_t size, size_t alignment); +void linearFree(void *mem); +#endif + +#if defined(PS2) +RETRO_HW_RENDER_INTEFACE_GSKIT_PS2 *ps2 = NULL; +#endif + +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; +static struct retro_log_callback log_cb = { 0 }; + +#if defined(PSP) +static bool crop_overscan; +#endif + +static unsigned overscan_left = 0; +static unsigned overscan_right = 0; +static unsigned overscan_top = 0; +static unsigned overscan_bottom = 0; +static unsigned aspect_ratio_par = 0; + +static bool use_raw_palette = false; + +bool libretro_supports_bitmasks = false; +static bool libretro_supports_option_categories = false; +static unsigned libretro_msg_interface_version = 0; + +/* emulator-specific variables */ + +const size_t PPU_BIT = 1ULL << 31ULL; + +static uint8 opt_region = 0; +static bool opt_showAdvSoundOptions = true; +static bool opt_showAdvSystemOptions = true; +static bool input_needs_update = false; + +#if defined(PSP) || defined(PS2) +static __attribute__((aligned(16))) uint16_t retro_palette[256]; +#else +static uint16_t retro_palette_full[512]; +#endif +#if defined(PSP) || defined(PS2) +/* not used because of hw buffers? */ +/* static uint8_t* fceu_video_out; */ +#else +static uint16_t *fceu_video_out; +#endif + +/* Some timing-related variables. */ +static uint8 sndquality; + +static uint32_t current_palette = 0; +static unsigned serialize_size; + +/* extern forward decls.*/ +void FCEU_ZapperSetTolerance(int t); +void FCEU_ZapperSetMode(int mode); +void FCEU_ZapperInvertTrigger(int invert); +void FCEU_ZapperInvertSensor(int invert); + +extern FCEUGI *GameInfo; + +extern uint8 NTARAM[0x800]; +extern uint8 PALRAM[0x20]; +extern uint8 SPRAM[0x100]; +extern uint8 PPU[4]; + +extern int palette_game_available; +extern int palette_user_available; + +/* emulator-specific callback functions */ +const char *GetKeyboard(void); +const char *GetKeyboard(void) { + return ""; +} + +#define BUILD_PIXEL_RGB565(R, G, B) (((int)((R)&0x1f) << RED_SHIFT) | ((int)((G)&0x3f) << GREEN_SHIFT) | ((int)((B)&0x1f) << BLUE_SHIFT)) + +#if defined(PSP) +#define RED_SHIFT 0 +#define GREEN_SHIFT 5 +#define BLUE_SHIFT 11 +#define RED_EXPAND 3 +#define GREEN_EXPAND 2 +#define BLUE_EXPAND 3 +#elif defined(FRONTEND_SUPPORTS_ABGR1555) +#define RED_SHIFT 0 +#define GREEN_SHIFT 5 +#define BLUE_SHIFT 10 +#define RED_EXPAND 3 +#define GREEN_EXPAND 3 +#define BLUE_EXPAND 3 +#define RED_MASK 0x1F +#define GREEN_MASK 0x3E0 +#define BLUE_MASK 0x7C00 +#elif defined(FRONTEND_SUPPORTS_RGB565) +#define RED_SHIFT 11 +#define GREEN_SHIFT 5 +#define BLUE_SHIFT 0 +#define RED_EXPAND 3 +#define GREEN_EXPAND 2 +#define BLUE_EXPAND 3 +#define RED_MASK 0xF800 +#define GREEN_MASK 0x7e0 +#define BLUE_MASK 0x1f +#else +#define RED_SHIFT 10 +#define GREEN_SHIFT 5 +#define BLUE_SHIFT 0 +#define RED_EXPAND 3 +#define GREEN_EXPAND 3 +#define BLUE_EXPAND 3 +#endif + +void FCEUD_SetPalette(int index, uint8_t r, uint8_t g, uint8_t b) { +#if defined(PSP) || defined(PS2) + unsigned char index_to_write = index; +#if defined(PS2) + /* Index correction for PS2 GS */ + int modi = index & 63; + if ((modi >= 8 && modi < 16) || (modi >= 40 && modi < 48)) { + index_to_write += 8; + } else if ((modi >= 16 && modi < 24) || (modi >= 48 && modi < 56)) { + index_to_write -= 8; + } +#endif + +#if defined(FRONTEND_SUPPORTS_RGB565) + retro_palette[index_to_write] = BUILD_PIXEL_RGB565(r >> RED_EXPAND, g >> GREEN_EXPAND, b >> BLUE_EXPAND); +#else + retro_palette[index_to_write] = ((r >> RED_EXPAND) << RED_SHIFT) | ((g >> GREEN_EXPAND) << GREEN_SHIFT) | ((b >> BLUE_EXPAND) << BLUE_SHIFT); +#endif +#endif +} + +void FCEUD_SetPaletteFull(int index, uint8_t r, uint8_t g, uint8_t b) { +#if defined(PSP) || defined(PS2) +#else +#if defined(FRONTEND_SUPPORTS_RGB565) + retro_palette_full[index] = BUILD_PIXEL_RGB565(r >> RED_EXPAND, g >> GREEN_EXPAND, b >> BLUE_EXPAND); +#else + retro_palette_full[index] = ((r >> RED_EXPAND) << RED_SHIFT) | ((g >> GREEN_EXPAND) << GREEN_SHIFT) | ((b >> BLUE_EXPAND) << BLUE_SHIFT); +#endif +#endif +} + +static void default_logger(enum retro_log_level level, const char *fmt, ...) { +} + +void FCEUD_PrintError(char *c) { + log_cb.log(RETRO_LOG_WARN, "%s", c); +} + +void FCEUD_PrintDebug(char *c) { + log_cb.log(RETRO_LOG_DEBUG, "%s", c); +} + +void FCEUD_Message(char *s) { + log_cb.log(RETRO_LOG_INFO, "%s", s); +} + +void FCEUD_DispMessage(enum retro_log_level level, unsigned duration, const char *str) { + if (!environ_cb) + return; + + if (libretro_msg_interface_version >= 1) { + struct retro_message_ext msg; + unsigned priority; + + switch (level) { + case RETRO_LOG_ERROR: + priority = 5; + break; + case RETRO_LOG_WARN: + priority = 4; + break; + case RETRO_LOG_INFO: + priority = 3; + break; + case RETRO_LOG_DEBUG: + default: + priority = 1; + break; + } + + msg.msg = str; + msg.duration = duration; + msg.priority = priority; + msg.level = level; + msg.target = RETRO_MESSAGE_TARGET_OSD; + msg.type = RETRO_MESSAGE_TYPE_NOTIFICATION_ALT; + msg.progress = -1; + + environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE_EXT, &msg); + } else { + float fps = NES_TARGET_FPS; + unsigned frames = (unsigned)(((float)duration * fps / 1000.0f) + 0.5f); + struct retro_message msg; + + msg.msg = str; + msg.frames = frames; + + environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, &msg); + } +} + +/*palette for FCEU*/ +static bool external_palette_exist = 0; + +/* ======================================== + * Palette switching START + * ======================================== */ + +/* Period in frames between palette switches + * when holding RetroPad L2 + Left/Right */ +#define PALETTE_SWITCH_PERIOD 30 + +bool palette_switch_enabled = false; +static bool libretro_supports_set_variable = false; +static unsigned palette_switch_counter = 0; +struct retro_core_option_value *palette_opt_values = NULL; +static const char *palette_labels[PALETTE_TOTAL_COUNT] = { 0 }; + +static uint32_t palette_switch_get_current_index(void) { + if (current_palette < PALETTE_COUNT) + return current_palette + 1; + + switch (current_palette) { + case PALETTE_INTERNAL: + return 0; + case PALETTE_RAW: + case PALETTE_CUSTOM: + return current_palette - 1; + default: + break; + } + + /* Cannot happen */ + return 0; +} + +static void palette_switch_init(void) { + size_t i; + struct retro_core_option_v2_definition *opt_defs = option_defs; + struct retro_core_option_v2_definition *opt_def = NULL; +#ifndef HAVE_NO_LANGEXTRA + struct retro_core_option_v2_definition *opt_defs_intl = NULL; + struct retro_core_option_v2_definition *opt_def_intl = NULL; + unsigned language = 0; +#endif + + libretro_supports_set_variable = false; + if (environ_cb(RETRO_ENVIRONMENT_SET_VARIABLE, NULL)) + libretro_supports_set_variable = true; + + palette_switch_enabled = libretro_supports_set_variable; + palette_switch_counter = 0; + +#ifndef HAVE_NO_LANGEXTRA + if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) && (language < RETRO_LANGUAGE_LAST) && + (language != RETRO_LANGUAGE_ENGLISH) && options_intl[language]) + opt_defs_intl = options_intl[language]->definitions; +#endif + + /* Find option corresponding to palettes key */ + for (opt_def = opt_defs; opt_def->key; opt_def++) + if (!strcmp(opt_def->key, "fceumm_palette")) + break; + + /* Cache option values array for fast access + * when setting palette index */ + palette_opt_values = opt_def->values; + + /* Loop over all palette values and fetch + * palette labels for notification purposes */ + for (i = 0; i < PALETTE_TOTAL_COUNT; i++) { + const char *value = opt_def->values[i].value; + const char *value_label = NULL; + + /* Check if we have a localised palette label */ +#ifndef HAVE_NO_LANGEXTRA + if (opt_defs_intl) { + /* Find localised option corresponding to key */ + for (opt_def_intl = opt_defs_intl; opt_def_intl->key; opt_def_intl++) { + if (!strcmp(opt_def_intl->key, "fceumm_palette")) { + size_t j = 0; + + /* Search for current option value */ + for (;;) { + const char *value_intl = opt_def_intl->values[j].value; + + if (!value_intl) + break; + + if (!strcmp(value, value_intl)) { + /* We have a match; fetch localised label */ + value_label = opt_def_intl->values[j].label; + break; + } + + j++; + } + + break; + } + } + } +#endif + /* If localised palette label is unset, + * use label from option_defs_us or fallback + * to value itself */ + if (!value_label) + value_label = opt_def->values[i].label; + if (!value_label) + value_label = value; + + palette_labels[i] = value_label; + } +} + +static void palette_switch_deinit(void) { + libretro_supports_set_variable = false; + palette_switch_enabled = false; + palette_switch_counter = 0; + palette_opt_values = NULL; +} + +static void palette_switch_set_index(uint32_t palette_index) { + struct retro_variable var = { 0 }; + + if (palette_index >= PALETTE_TOTAL_COUNT) + palette_index = PALETTE_TOTAL_COUNT - 1; + + /* Notify frontend of option value changes */ + var.key = "fceumm_palette"; + var.value = palette_opt_values[palette_index].value; + environ_cb(RETRO_ENVIRONMENT_SET_VARIABLE, &var); + + /* Display notification message */ + FCEUD_DispMessage(RETRO_LOG_INFO, 2000, palette_labels[palette_index]); +} + +/* ======================================== + * Palette switching END + * ======================================== */ + +/* ======================================== + * Stereo Filter START + * ======================================== */ + +enum stereo_filter_type { STEREO_FILTER_NULL = 0, STEREO_FILTER_DELAY }; +static enum stereo_filter_type current_stereo_filter = STEREO_FILTER_NULL; + +#define STEREO_FILTER_DELAY_MS_DEFAULT 15.0f +typedef struct { + int32_t *samples; + size_t samples_size; + size_t samples_pos; + size_t delay_count; +} stereo_filter_delay_t; +static stereo_filter_delay_t stereo_filter_delay; +static float stereo_filter_delay_ms = STEREO_FILTER_DELAY_MS_DEFAULT; + +static void stereo_filter_apply_null(int32_t *sound_buffer, size_t size) { + size_t i; + /* Each element of sound_buffer is a 16 bit mono sample + * stored in a 32 bit value. We convert this to stereo + * by copying the mono sample to both the high and low + * 16 bit regions of the value and casting sound_buffer + * to int16_t when uploading to the frontend */ + for (i = 0; i < size; i++) + sound_buffer[i] = (sound_buffer[i] << 16) | (sound_buffer[i] & 0xFFFF); +} + +static void stereo_filter_apply_delay(int32_t *sound_buffer, size_t size) { + size_t delay_capacity = stereo_filter_delay.samples_size - stereo_filter_delay.samples_pos; + size_t i; + + /* Copy current samples into the delay buffer + * (resizing if required) */ + if (delay_capacity < size) { + int32_t *tmp_buffer = NULL; + size_t tmp_buffer_size; + + tmp_buffer_size = stereo_filter_delay.samples_size + (size - delay_capacity); + tmp_buffer_size = (tmp_buffer_size << 1) - (tmp_buffer_size >> 1); + tmp_buffer = (int32_t *)malloc(tmp_buffer_size * sizeof(int32_t)); + + memcpy(tmp_buffer, stereo_filter_delay.samples, stereo_filter_delay.samples_pos * sizeof(int32_t)); + + free(stereo_filter_delay.samples); + + stereo_filter_delay.samples = tmp_buffer; + stereo_filter_delay.samples_size = tmp_buffer_size; + } + + for (i = 0; i < size; i++) + stereo_filter_delay.samples[i + stereo_filter_delay.samples_pos] = sound_buffer[i]; + + stereo_filter_delay.samples_pos += size; + + /* If we have enough samples in the delay + * buffer, mix them into the output */ + if (stereo_filter_delay.samples_pos > stereo_filter_delay.delay_count) { + size_t delay_index = 0; + size_t samples_to_mix = stereo_filter_delay.samples_pos - stereo_filter_delay.delay_count; + samples_to_mix = (samples_to_mix > size) ? size : samples_to_mix; + + /* Perform 'null' filtering for any samples for + * which a delay buffer entry is unavailable */ + if (size > samples_to_mix) + for (i = 0; i < size - samples_to_mix; i++) + sound_buffer[i] = (sound_buffer[i] << 16) | (sound_buffer[i] & 0xFFFF); + + /* Each element of sound_buffer is a 16 bit mono sample + * stored in a 32 bit value. We convert this to stereo + * by copying the mono sample to the high (left channel) + * 16 bit region and the delayed sample to the low + * (right channel) region, casting sound_buffer + * to int16_t when uploading to the frontend */ + for (i = size - samples_to_mix; i < size; i++) + sound_buffer[i] = (sound_buffer[i] << 16) | (stereo_filter_delay.samples[delay_index++] & 0xFFFF); + + /* Remove the mixed samples from the delay buffer */ + memmove(stereo_filter_delay.samples, stereo_filter_delay.samples + samples_to_mix, + (stereo_filter_delay.samples_pos - samples_to_mix) * sizeof(int32_t)); + stereo_filter_delay.samples_pos -= samples_to_mix; + } + /* Otherwise apply the regular 'null' filter */ + else + for (i = 0; i < size; i++) + sound_buffer[i] = (sound_buffer[i] << 16) | (sound_buffer[i] & 0xFFFF); +} + +static void (*stereo_filter_apply)(int32_t *sound_buffer, size_t size) = stereo_filter_apply_null; + +static void stereo_filter_deinit_delay(void) { + if (stereo_filter_delay.samples) + free(stereo_filter_delay.samples); + + stereo_filter_delay.samples = NULL; + stereo_filter_delay.samples_size = 0; + stereo_filter_delay.samples_pos = 0; + stereo_filter_delay.delay_count = 0; +} + +static void stereo_filter_init_delay(void) { + size_t initial_samples_size; + + /* Convert delay (ms) to number of samples */ + stereo_filter_delay.delay_count = (size_t)((stereo_filter_delay_ms / 1000.0f) * (float)FSettings.SndRate); + + /* Preallocate delay_count + worst case expected + * samples per frame to minimise reallocation of + * the samples buffer during runtime */ + initial_samples_size = stereo_filter_delay.delay_count + (size_t)((float)FSettings.SndRate / NES_TARGET_FPS) + 1; + + stereo_filter_delay.samples = (int32_t *)malloc(initial_samples_size * sizeof(int32_t)); + stereo_filter_delay.samples_size = initial_samples_size; + stereo_filter_delay.samples_pos = 0; + + /* Assign function pointer */ + stereo_filter_apply = stereo_filter_apply_delay; +} + +static void stereo_filter_deinit(void) { + /* Clean up */ + stereo_filter_deinit_delay(); + /* Assign default function pointer */ + stereo_filter_apply = stereo_filter_apply_null; +} + +static void stereo_filter_init(void) { + stereo_filter_deinit(); + + /* Use a case statement to simplify matters + * if more filter types are added in the + * future... */ + switch (current_stereo_filter) { + case STEREO_FILTER_DELAY: + stereo_filter_init_delay(); + break; + default: + break; + } +} + +/* ======================================== + * Stereo Filter END + * ======================================== */ + +/* ======================================== + * NTSC Video Filter START + * ======================================== */ + +#if defined(HAVE_NTSC_FILTER) +enum nes_ntsc_type { NTSC_NONE, NTSC_COMPOSITE, NTSC_SVIDEO, NTSC_RGB, NTSC_MONOCHROME }; +static enum nes_ntsc_type use_ntsc_filter = NTSC_NONE; +#endif + +#if defined(HAVE_NTSC_FILTER) +#include "nes_ntsc.h" +/* NOTE: Determine which platform requires buffer alignment */ +/* #define NES_NTSC_WIDTH (((NES_NTSC_OUT_WIDTH(256) + 3) >> 2) << 2) */ +#define NES_NTSC_WIDTH 602 + +static nes_ntsc_t *nes_ntsc = NULL; +static uint16_t *ntscblit = NULL; /* for ntsc blit buffer */ + +static void ntsc_filter_deinit(void) { + if (ntscblit) + free(ntscblit); + ntscblit = NULL; + if (nes_ntsc) + free(nes_ntsc); + nes_ntsc = NULL; + use_ntsc_filter = NTSC_NONE; +} + +static void ntsc_set_filter(void) { + nes_ntsc_setup_t ntsc_setup = { 0 }; + + switch (use_ntsc_filter) { + case NTSC_COMPOSITE: + ntsc_setup = nes_ntsc_composite; + break; + case NTSC_SVIDEO: + ntsc_setup = nes_ntsc_svideo; + break; + case NTSC_RGB: + ntsc_setup = nes_ntsc_rgb; + break; + case NTSC_MONOCHROME: + ntsc_setup = nes_ntsc_monochrome; + break; + default: + break; + } + + if ((GameInfo && (GameInfo->type == GIT_VSUNI)) || (current_palette < PALETTE_INTERNAL) || + (current_palette == PALETTE_CUSTOM)) { + ntsc_setup.palette = (unsigned char const *)palo; + } + + nes_ntsc = (nes_ntsc_t *)malloc(sizeof(nes_ntsc_t)); + if (nes_ntsc) { + nes_ntsc_init(nes_ntsc, &ntsc_setup); + ntscblit = (uint16_t *)malloc(NES_NTSC_WIDTH * (2 * NES_HEIGHT) * sizeof(uint16_t)); + } + + if (!nes_ntsc && !ntscblit) { + use_ntsc_filter = NTSC_NONE; + } +} +#endif + +/* ======================================== + * NTSC Video Filter END + * ======================================== */ + +static void ResetPalette(void); +static void set_user_palette(void); + +static void ResetPalette(void) { + set_user_palette(); +#if defined(HAVE_NTSC_FILTER) + ntsc_set_filter(); +#endif +} + +/* Core options 'update display' callback */ +static bool update_option_visibility(void) { + struct retro_variable var = { 0 }; + bool updated = false; + + /* If frontend supports core option categories, + * then fceumm_show_adv_system_options and + * fceumm_show_adv_sound_options are ignored + * and no options should be hidden */ + if (libretro_supports_option_categories) + return false; + + var.key = "fceumm_show_adv_system_options"; + var.value = NULL; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + bool opt_showAdvSystemOptions_prev = opt_showAdvSystemOptions; + + opt_showAdvSystemOptions = true; + if (strcmp(var.value, "disabled") == 0) + opt_showAdvSystemOptions = false; + + if (opt_showAdvSystemOptions != opt_showAdvSystemOptions_prev) { + struct retro_core_option_display option_display; + unsigned i; + unsigned size; + char options_list[][25] = { + "fceumm_overclocking", + "fceumm_ramstate", + "fceumm_nospritelimit", + "fceumm_up_down_allowed", + "fceumm_show_crosshair" + }; + + option_display.visible = opt_showAdvSystemOptions; + size = sizeof(options_list) / sizeof(options_list[0]); + for (i = 0; i < size; i++) { + option_display.key = options_list[i]; + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display); + } + + updated = true; + } + } + + var.key = "fceumm_show_adv_sound_options"; + var.value = NULL; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + bool opt_showAdvSoundOptions_prev = opt_showAdvSoundOptions; + + opt_showAdvSoundOptions = true; + if (strcmp(var.value, "disabled") == 0) + opt_showAdvSoundOptions = false; + + if (opt_showAdvSoundOptions != opt_showAdvSoundOptions_prev) { + struct retro_core_option_display option_display; + unsigned i; + unsigned size; + char options_list[][25] = { + "fceumm_sndvolume", + "fceumm_sndquality", + "fceumm_sndlowpass", + "fceumm_sndstereodelay", + "fceumm_swapduty", + "fceumm_apu_1", + "fceumm_apu_2", + "fceumm_apu_3", + "fceumm_apu_4", + "fceumm_apu_5" + }; + + option_display.visible = opt_showAdvSoundOptions; + size = sizeof(options_list) / sizeof(options_list[0]); + for (i = 0; i < size; i++) { + option_display.key = options_list[i]; + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display); + } + + updated = true; + } + } + + return updated; +} + +static void set_variables(void) { + struct retro_core_option_display option_display; + unsigned index = 0; + + option_display.visible = false; + + /* Initialize main core option struct */ + memset(&option_defs_us, 0, sizeof(option_defs_us)); + + /* Write common core options to main struct */ + while (option_defs[index].key) { + memcpy(&option_defs_us[index], &option_defs[index], sizeof(struct retro_core_option_v2_definition)); + index++; + } + + /* Append dipswitch settings to core options if available */ + set_dipswitch_variables(&environ_cb, index, option_defs_us); + + libretro_supports_option_categories = false; + libretro_set_core_options(environ_cb, &libretro_supports_option_categories); + + /* If frontend supports core option categories, + * fceumm_show_adv_system_options and + * fceumm_show_adv_sound_options are unused + * and should be hidden */ + if (libretro_supports_option_categories) { + option_display.key = "fceumm_show_adv_system_options"; + + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display); + + option_display.key = "fceumm_show_adv_sound_options"; + + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display); + } + /* If frontend does not support core option + * categories, core options may be shown/hidden + * at runtime. In this case, register 'update + * display' callback, so frontend can update + * core options menu without calling retro_run() */ + else { + struct retro_core_options_update_display_callback update_display_cb; + update_display_cb.callback = update_option_visibility; + + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK, &update_display_cb); + } + + /* VS UNISystem games use internal palette regardless + * of user setting, so hide fceumm_palette option */ + if (GameInfo && (GameInfo->type == GIT_VSUNI)) { + option_display.key = "fceumm_palette"; + + environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display); + + /* Additionally disable gamepad palette + * switching */ + palette_switch_enabled = false; + } +} + +/* Game Genie add-on must be enabled before + * loading content, so we cannot parse this + * option inside check_variables() */ +static void check_game_genie_variable(void) { + struct retro_variable var = { 0 }; + int game_genie_enabled = 0; + + var.key = "fceumm_game_genie"; + + /* Game Genie is only enabled for regular + * cartridges (excludes arcade content, + * FDS games, etc.) */ + if ((GameInfo && (GameInfo->type == GIT_CART)) && + (iNESCart.mapper != 105) && /* Nintendo World Championship cart (Mapper 105)*/ + environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value && !strcmp(var.value, "enabled")) + game_genie_enabled = 1; + + FCEUI_SetGameGenie(game_genie_enabled); +} + +/* Callback passed to FCEUI_LoadGame() + * > Required since we must set and check + * core options immediately after ROM + * is loaded, before FCEUI_LoadGame() + * returns */ +static void frontend_post_load_init(void) { + set_variables(); + check_game_genie_variable(); +} + +static double get_aspect_ratio(unsigned width, unsigned height) { + if (aspect_ratio_par == 2) + return (double)NES_4_3(width, height); + else if (aspect_ratio_par == 3) + return (double)NES_PP(width, height); + else + return (double)NES_8_7_PAR(width, height); +} + +static void set_user_palette(void) { + unsigned i; + + palette_game_available = false; + palette_user_available = false; + use_raw_palette = false; + + /* VS UNISystem uses internal palette presets regardless of options */ + if (GameInfo && (GameInfo->type == GIT_VSUNI)) { + FCEU_ResetPalette(); + } + /* Reset and choose between default internal or external custom palette */ + /* if palette_game_available is set to 1, external palette + * is loaded, else it will load default NES palette. + * FCEUI_SetPaletteUser() both resets the palette array to + * internal default palette and then chooses which one to use. */ + else if (current_palette == PALETTE_INTERNAL) { + FCEUI_SetPaletteUser(NULL, 0); + } else if ((current_palette == PALETTE_CUSTOM) && external_palette_exist) { + palette_game_available = true; + FCEUI_SetPaletteUser(NULL, 0); + } + + /* setup raw palette */ + else if (current_palette == PALETTE_RAW) { + pal color; + use_raw_palette = true; + for (i = 0; i < 64; i++) { + color.r = (((i >> 0) & 0xF) * 255) / 15; + color.g = (((i >> 4) & 0x3) * 255) / 3; + color.b = 0; +#if defined(PSP) || defined(PS2) + FCEUD_SetPalette(i, color.r, color.g, color.b); +#else + FCEUD_SetPaletteFull(i, color.r, color.g, color.b); +#endif + } + } + + /* setup palette presets */ + else { + FCEUI_SetPaletteUser(palettes[current_palette].data, 64); + } +} + +/* Set variables for NTSC(1) / PAL(2) / Dendy(3) + * Dendy has PAL framerate and resolution, but ~NTSC timings, + * and has 50 dummy scanlines to force 50 fps. + */ +static void set_system_region(unsigned region) { + bool pal = false; + bool dendy = false; + + switch (region) { + case 0: /* AUTO */ + if (iNESCart.region == DENDY) { + dendy = true; + } else { + pal = iNESCart.region == NES_PAL; + } + break; + case 1: /* NTSC */ + FCEUD_DispMessage(RETRO_LOG_INFO, 2000, "System: NTSC"); + break; + case 2: /* PAL */ + pal = true; + FCEUD_DispMessage(RETRO_LOG_INFO, 2000, "System: PAL"); + break; + case 3: /* Dendy */ + dendy = true; + FCEUD_DispMessage(RETRO_LOG_INFO, 2000, "System: Dendy"); + break; + } + + isDendy = dendy; + FCEUI_SetVidSystem(pal); + ResetPalette(); +} + +#define VOLUME_MAX 256 + +static void check_variables_volume_levels(void) { + struct { + int channel; + char *name; + } apu_channels[] = { + { SND_SQUARE1, "fceumm_apu_square_1" }, + { SND_SQUARE2, "fceumm_apu_square_2" }, + { SND_TRIANGLE, "fceumm_apu_triangle" }, + { SND_NOISE, "fceumm_apu_noise" }, + { SND_DMC, "fceumm_apu_dpcm" }, + { SND_FDS, "fceumm_apu_fds" }, + { SND_S5B, "fceumm_apu_s5b" }, + { SND_N163, "fceumm_apu_n163" }, + { SND_VRC6, "fceumm_apu_vrc6" }, + { SND_VRC7, "fceumm_apu_vrc7" }, + { SND_MMC5, "fceumm_apu_mmc5" }, + }; + struct retro_variable var = { 0 }; + int i = 0; + int ssize = sizeof(apu_channels) / sizeof(apu_channels[0]); + + for (i = 0; i < ssize; i++) { + int channel = apu_channels[i].channel; + var.key = apu_channels[i].name; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + int newval = VOLUME_MAX * atoi(var.value) / 100; + if (FCEUI_GetSoundVolume(channel) != newval) { + FCEUI_SetSoundVolume(channel, newval); + } + } + } +} + +static void check_variables(bool startup) { + struct retro_variable var = { 0 }; + bool stereo_filter_updated = false; + int nes_sprites = 1, nes_background = 1; + + /* 1 = Performs only geometry update: e.g. overscans */ + /* 2 = Performs video/geometry update when needed and timing changes: e.g. region and filter change */ + int audio_video_updated = 0; + + var.key = "fceumm_ramstate"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + if (!strcmp(var.value, "random")) + FSettings.RamInitState = 2; + else if (!strcmp(var.value, "fill $00")) + FSettings.RamInitState = 1; + else + FSettings.RamInitState = 0; + } + +#if defined(HAVE_NTSC_FILTER) + var.key = "fceumm_ntsc_filter"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + unsigned orig_value = use_ntsc_filter; + if (strcmp(var.value, "disabled") == 0) + use_ntsc_filter = NTSC_NONE; + else if (strcmp(var.value, "composite") == 0) + use_ntsc_filter = NTSC_COMPOSITE; + else if (strcmp(var.value, "svideo") == 0) + use_ntsc_filter = NTSC_SVIDEO; + else if (strcmp(var.value, "rgb") == 0) + use_ntsc_filter = NTSC_RGB; + else if (strcmp(var.value, "monochrome") == 0) + use_ntsc_filter = NTSC_MONOCHROME; + if (use_ntsc_filter != orig_value) { + ResetPalette(); + audio_video_updated = 2; + } + } +#endif /* HAVE_NTSC_FILTER */ + + FCEUI_GetRenderPlanes(&nes_sprites, &nes_background); + + var.key = "fceumm_hide_sprites"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + nes_sprites = strcmp(var.value, "enabled"); + } + + var.key = "fceumm_hide_background"; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + nes_background = strcmp(var.value, "enabled"); + } + + FCEUI_SetRenderPlanes(nes_sprites, nes_background); + + var.key = "fceumm_palette"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + unsigned orig_value = current_palette; + + if (!strcmp(var.value, "default")) + current_palette = PALETTE_INTERNAL; + else if (!strcmp(var.value, "raw")) + current_palette = PALETTE_RAW; + else if (!strcmp(var.value, "custom")) + current_palette = PALETTE_CUSTOM; + else if (!strcmp(var.value, "asqrealc")) + current_palette = 0; + else if (!strcmp(var.value, "nintendo-vc")) + current_palette = 1; + else if (!strcmp(var.value, "rgb")) + current_palette = 2; + else if (!strcmp(var.value, "sony-cxa2025as-us")) + current_palette = 3; + else if (!strcmp(var.value, "pal")) + current_palette = 4; + else if (!strcmp(var.value, "bmf-final2")) + current_palette = 5; + else if (!strcmp(var.value, "bmf-final3")) + current_palette = 6; + else if (!strcmp(var.value, "nescap")) + current_palette = 7; + else if (!strcmp(var.value, "wavebeam")) + current_palette = 8; + else if (!strcmp(var.value, "digital-prime-fbx")) + current_palette = 9; + else if (!strcmp(var.value, "magnum-fbx")) + current_palette = 10; + else if (!strcmp(var.value, "smooth-v2-fbx")) + current_palette = 11; + else if (!strcmp(var.value, "nes-classic-fbx")) + current_palette = 12; + + if (current_palette != orig_value) { + audio_video_updated = 1; + ResetPalette(); + } + } + + var.key = "fceumm_up_down_allowed"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + bool value = !strcmp(var.value, "enabled") ? true : false; + input_allow_updown_leftright(value); + } + + var.key = "fceumm_nospritelimit"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + int no_sprite_limit = (!strcmp(var.value, "enabled")) ? 1 : 0; + FCEUI_DisableSpriteLimitation(no_sprite_limit); + } + + var.key = "fceumm_overclocking"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + bool do_reinit = false; + + if (!strcmp(var.value, "disabled") && FSettings.PPUOverclockEnabled != 0) { + FSettings.PPUOverclockEnabled = 0; + FSettings.SkipDMC7BitOverclock = 1; + ppu.overclock.postrender_scanlines = 0; + ppu.overclock.vblank_scanlines = 0; + do_reinit = true; + } else if (!strcmp(var.value, "2x-Postrender")) { + FSettings.PPUOverclockEnabled = 1; + FSettings.SkipDMC7BitOverclock = 1; + ppu.overclock.postrender_scanlines = 266; + ppu.overclock.vblank_scanlines = 0; + do_reinit = true; + } else if (!strcmp(var.value, "2x-VBlank")) { + FSettings.PPUOverclockEnabled = 1; + FSettings.SkipDMC7BitOverclock = 1; + ppu.overclock.postrender_scanlines = 0; + ppu.overclock.vblank_scanlines = 266; + do_reinit = true; + } + + ppu.normal_scanlines = isDendy ? 290 : 240; + ppu.totalscanlines = ppu.normal_scanlines + (FSettings.PPUOverclockEnabled ? ppu.overclock.postrender_scanlines : 0); + + if (do_reinit && startup) { + FCEU_KillVirtualVideo(); + FCEU_InitVirtualVideo(); + } + } + + var.key = "fceumm_zapper_mode"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + if (!strcmp(var.value, "mouse")) { + input_set_zapper_mode(RetroMouse); + FCEU_ZapperSetMode(false); + } else if (!strcmp(var.value, "touchscreen")) { + input_set_zapper_mode(RetroPointer); + FCEU_ZapperSetMode(false); + } else if (!strcmp(var.value, "stlightgun")) { + input_set_zapper_mode(RetroSTLightgun); + FCEU_ZapperSetMode(true); + } else { + input_set_zapper_mode(RetroLightgun); /*default setting*/ + FCEU_ZapperSetMode(false); + } + } + + var.key = "fceumm_zapper_tolerance"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + FCEU_ZapperSetTolerance(atoi(var.value)); + } + + var.key = "fceumm_zapper_trigger"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + if (!strcmp(var.value, "enabled")) + FCEU_ZapperInvertTrigger(true); + else if (!strcmp(var.value, "disabled")) + FCEU_ZapperInvertTrigger(false); + } + + var.key = "fceumm_zapper_sensor"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + if (!strcmp(var.value, "enabled")) + FCEU_ZapperInvertSensor(true); + else if (!strcmp(var.value, "disabled")) + FCEU_ZapperInvertSensor(false); + } + + var.key = "fceumm_arkanoid_mode"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + if (!strcmp(var.value, "touchscreen")) { + input_set_arkanoid_mode(RetroArkanoidPointer); + } else if (!strcmp(var.value, "abs_mouse")) { + input_set_arkanoid_mode(RetroArkanoidAbsMouse); + } else if (!strcmp(var.value, "stelladaptor")) { + input_set_arkanoid_mode(RetroArkanoidStelladaptor); + } else { + input_set_arkanoid_mode(RetroArkanoidMouse); /*default setting*/ + } + } + + var.key = "fceumm_mouse_sensitivity"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + double value = atof(var.value); + input_set_mousesensitivity(value); + } + + var.key = "fceumm_show_crosshair"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + if (!strcmp(var.value, "enabled")) + FSettings.ShowCrosshair = 1; + else if (!strcmp(var.value, "disabled")) + FSettings.ShowCrosshair = 0; + } + +#if defined(PSP) + var.key = "fceumm_overscan"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + bool newval = (!strcmp(var.value, "enabled")); + if (newval != crop_overscan) { + overscan_left = (newval == true ? 8 : 0); + overscan_right = (newval == true ? 8 : 0); + overscan_top = (newval == true ? 8 : 0); + overscan_bottom = (newval == true ? 8 : 0); + + crop_overscan = newval; + audio_video_updated = 1; + } + } +#else + var.key = "fceumm_overscan_left"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + unsigned newval = atoi(var.value); + if (newval != overscan_left) { + overscan_left = newval; + audio_video_updated = 1; + } + } + + var.key = "fceumm_overscan_right"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + unsigned newval = atoi(var.value); + if (newval != overscan_right) { + overscan_right = newval; + audio_video_updated = 1; + } + } + + var.key = "fceumm_overscan_top"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + unsigned newval = atoi(var.value); + if (newval != overscan_top) { + overscan_top = newval; + audio_video_updated = 1; + } + } + + var.key = "fceumm_overscan_bottom"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + unsigned newval = atoi(var.value); + if (newval != overscan_bottom) { + overscan_bottom = newval; + audio_video_updated = 1; + } + } +#endif + + var.key = "fceumm_aspect"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + unsigned oldval = aspect_ratio_par; + if (!strcmp(var.value, "8:7 PAR")) { + aspect_ratio_par = 1; + } else if (!strcmp(var.value, "4:3")) { + aspect_ratio_par = 2; + } else if (!strcmp(var.value, "PP")) { + aspect_ratio_par = 3; + } + if (aspect_ratio_par != oldval) + audio_video_updated = 1; + } + + var.key = "fceumm_turbo_enable"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + if (!strcmp(var.value, "Player 1")) { + input_enable_turbo_buttons(0, true); + } else if (!strcmp(var.value, "Player 2")) { + input_enable_turbo_buttons(1, true); + } else if (!strcmp(var.value, "Players 1 and 2")) { + input_enable_turbo_buttons(0, true); + input_enable_turbo_buttons(1, true); + } else { + input_enable_turbo_buttons(0, false); + input_enable_turbo_buttons(1, false); + } + } + + var.key = "fceumm_turbo_delay"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + int value = atoi(var.value); + input_set_turbo_delay(value); + } + + var.key = "fceumm_region"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + uint8 oldval = opt_region; + if (!strcmp(var.value, "Auto")) + opt_region = 0; + else if (!strcmp(var.value, "NTSC")) + opt_region = 1; + else if (!strcmp(var.value, "PAL")) + opt_region = 2; + else if (!strcmp(var.value, "Dendy")) + opt_region = 3; + if (opt_region != oldval) { + set_system_region(opt_region); + audio_video_updated = 2; + } + } + + var.key = "fceumm_sndquality"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + uint8 oldval = sndquality; + if (!strcmp(var.value, "Low")) + sndquality = 0; + else if (!strcmp(var.value, "High")) + sndquality = 1; + else if (!strcmp(var.value, "Very High")) + sndquality = 2; + if (sndquality != oldval) + FCEUI_SetSoundQuality(sndquality); + } + + var.key = "fceumm_sndlowpass"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + int lowpass = (!strcmp(var.value, "disabled")) ? 0 : atoi(var.value); + FCEUI_SetLowPass(lowpass); + } + + var.key = "fceumm_sndstereodelay"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + enum stereo_filter_type filter_type = STEREO_FILTER_NULL; + float filter_delay_ms = STEREO_FILTER_DELAY_MS_DEFAULT; + + if (strcmp(var.value, "disabled") && (strlen(var.value) > 1)) { + filter_type = STEREO_FILTER_DELAY; + filter_delay_ms = (float)atoi(var.value); + + filter_delay_ms = (filter_delay_ms < 1.0f) ? 1.0f : filter_delay_ms; + filter_delay_ms = (filter_delay_ms > 32.0f) ? 32.0f : filter_delay_ms; + } + + if ((filter_type != current_stereo_filter) || + ((filter_type == STEREO_FILTER_DELAY) && (filter_delay_ms != stereo_filter_delay_ms))) { + current_stereo_filter = filter_type; + stereo_filter_delay_ms = filter_delay_ms; + stereo_filter_updated = true; + } + } + + var.key = "fceumm_sndvolume"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + int val = (int)((float)VOLUME_MAX * atof(var.value) / 200.0f); + FCEUI_SetSoundVolume(SND_MASTER, val); + } + + var.key = "fceumm_swapduty"; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + bool newval = (!strcmp(var.value, "enabled")); + FSettings.SwapDutyCycles = newval; + } + + if ((stereo_filter_updated || (audio_video_updated == 2)) && !startup) { + stereo_filter_init(); + } + + if (audio_video_updated && !startup) { + struct retro_system_av_info av_info; + retro_get_system_av_info(&av_info); + if (audio_video_updated == 2) + environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &av_info); + else + environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &av_info); + } + + check_variables_volume_levels(); + check_dipswitch_variables(); + update_option_visibility(); +} + +void input_palette_switch(bool palette_next, bool palette_prev) { + if (palette_prev || palette_next) { + if (palette_switch_counter == 0) { + int new_palette_index = palette_switch_get_current_index(); + + if (palette_prev) { + if (new_palette_index > 0) + new_palette_index--; + else + new_palette_index = PALETTE_TOTAL_COUNT - 1; + } else { /* palette_next */ + if (new_palette_index < PALETTE_TOTAL_COUNT - 1) + new_palette_index++; + else + new_palette_index = 0; + } + + palette_switch_set_index(new_palette_index); + } + + palette_switch_counter++; + if (palette_switch_counter >= PALETTE_SWITCH_PERIOD) + palette_switch_counter = 0; + } else + palette_switch_counter = 0; +} + +#if defined(PSP) +static void retro_run_blit_psp(uint8_t *gfx) { + static unsigned int __attribute__((aligned(16))) d_list[32]; + void *texture_vram_p = NULL; + + unsigned width = 256; + unsigned height = 240; + + int x, y; + + if (crop_overscan) { + width -= 16; + height -= 16; + } + texture_vram_p = (void *)(0x44200000 - (256 * 256)); /* max VRAM address - frame size */ + + sceKernelDcacheWritebackRange(retro_palette, 256 * 2); + sceKernelDcacheWritebackRange(gfx, 256 * 240); + + sceGuStart(GU_DIRECT, d_list); + + /* sceGuCopyImage doesnt seem to work correctly with GU_PSM_T8 + * so we use GU_PSM_4444 ( 2 Bytes per pixel ) instead + * with half the values for pitch / width / x offset + */ + if (crop_overscan) + sceGuCopyImage(GU_PSM_4444, 4, 4, 120, 224, 128, gfx, 0, 0, 128, texture_vram_p); + else + sceGuCopyImage(GU_PSM_4444, 0, 0, 128, 240, 128, gfx, 0, 0, 128, texture_vram_p); + + sceGuTexSync(); + sceGuTexImage(0, 256, 256, 256, texture_vram_p); + sceGuTexMode(GU_PSM_T8, 0, 0, GU_FALSE); + sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB); + sceGuDisable(GU_BLEND); + sceGuClutMode(GU_PSM_5650, 0, 0xFF, 0); + sceGuClutLoad(32, retro_palette); + + sceGuFinish(); + + video_cb(texture_vram_p, width, height, 256); +} +#elif defined(PS2) + +static void retro_run_blit_ps2(uint8_t *gfx) { + unsigned width = 256; + unsigned height = 240; + unsigned pitch = 512; + + uint32_t *buf = (uint32_t *)RETRO_HW_FRAME_BUFFER_VALID; + + if (!ps2) { + if (!environ_cb(RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE, (void **)&ps2) || !ps2) { + FCEU_printf(" Failed to get HW rendering interface!\n"); + return; + } + + if (ps2->interface_version != RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION) { + FCEU_printf(" HW render interface mismatch, expected %u, got %u!\n", + RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION, ps2->interface_version); + return; + } + + ps2->coreTexture->Width = width; + ps2->coreTexture->Height = height; + 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) { (float)overscan_top, (float)overscan_left, (float)overscan_bottom, + (float)overscan_right }; + } + + ps2->coreTexture->Clut = (u32 *)retro_palette; + ps2->coreTexture->Mem = (u32 *)gfx; + + video_cb(buf, width, height, pitch); +} +#else +#if defined(HAVE_NTSC_FILTER) +static void retro_run_blit_ntsc(uint8_t *gfx, uint8 *emp) { + int width = NES_NTSC_OUT_WIDTH(NES_WIDTH - overscan_left - overscan_right); + int height = NES_HEIGHT - overscan_top - overscan_bottom; + int pitch = width * sizeof(uint16_t); + + static int burst_count = 0; + static int burst_phase = 0; + double div = 1.5f; + + nes_ntsc_blit(nes_ntsc, (NES_NTSC_IN_T const *)gfx, (NES_NTSC_IN_T const *)emp, NES_WIDTH, burst_phase, NES_WIDTH, + NES_HEIGHT, ntscblit, NES_NTSC_WIDTH * sizeof(uint16_t)); + + burst_phase = (int)((double)burst_count / div); + burst_count = (burst_count + 1) % 3; + + { + int y = 0; + int x_offset = overscan_left ? NES_NTSC_OUT_WIDTH(overscan_left) : 0; + + uint16 *out_scanline = fceu_video_out; + const uint16 *in_scanline = ntscblit + x_offset + overscan_top * NES_NTSC_WIDTH; + + for (y = height; --y >= 0; in_scanline += NES_NTSC_WIDTH, out_scanline += 2 * width) { + memcpy(out_scanline, in_scanline, pitch); + memcpy(out_scanline + width, in_scanline, pitch); + } + } + + video_cb(fceu_video_out, width, height * 2, pitch); +} +#endif /* HAVE_NTSC_FILTER */ + +static void retro_run_blit(uint8_t *gfx, uint8 *emp) { + int width = NES_WIDTH - overscan_left - overscan_right; + int height = NES_HEIGHT - overscan_top - overscan_bottom; + int pitch = width * sizeof(uint16_t); + int shift = use_raw_palette ? 2 : 6; + + uint16_t *out_scanline = fceu_video_out; + uint8_t *in_scanline = gfx + overscan_left + overscan_top * NES_WIDTH; + uint8_t *in_emp = emp + overscan_left + overscan_top * NES_WIDTH; + + int x = 0, y = 0; + + for (y = height; --y >= 0; out_scanline += width, in_scanline += NES_WIDTH, in_emp += NES_WIDTH) { + for (x = 0; x < width; x++) { + out_scanline[x] = retro_palette_full[(in_scanline[x] & 0x3f) | (in_emp[x] << shift)]; + } + } + + video_cb(fceu_video_out, width, height, pitch); +} +#endif + +static bool checkGG(char c) { + static const char lets[16] = { 'A', 'P', 'Z', 'L', 'G', 'I', 'T', 'Y', 'E', 'O', 'X', 'U', 'K', 'S', 'V', 'N' }; + int x; + + for (x = 0; x < 16; x++) + if (lets[x] == toupper(c)) + return true; + return false; +} + +static bool GGisvalid(const char *code) { + size_t len = strlen(code); + uint32 i; + + if (len != 6 && len != 8) + return false; + + for (i = 0; i < len; i++) + if (!checkGG(code[i])) + return false; + return true; +} + +/* Start of Libretro API */ + +void retro_set_environment(retro_environment_t cb) { + struct retro_vfs_interface_info vfs_iface_info; + static const struct retro_system_content_info_override content_overrides[] = { + { + "fds|nes|unf|unif", /* extensions */ + false, /* need_fullpath */ + false /* persistent_data */ + }, + { NULL, false, false } + }; + + environ_cb = cb; + + vfs_iface_info.required_interface_version = 1; + vfs_iface_info.iface = NULL; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VFS_INTERFACE, &vfs_iface_info)) + filestream_vfs_init(&vfs_iface_info); + + environ_cb(RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE, (void *)content_overrides); +} + +void retro_set_video_refresh(retro_video_refresh_t cb) { + video_cb = cb; +} + +void retro_set_audio_sample(retro_audio_sample_t cb) { } + +void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) { + audio_batch_cb = cb; +} + +void retro_set_input_poll(retro_input_poll_t cb) { + poll_cb = cb; +} + +void retro_set_input_state(retro_input_state_t cb) { + input_cb = cb; +} + +void retro_init(void) { + bool achievements = true; + log_cb.log = default_logger; + environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log_cb); + + environ_cb(RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS, &achievements); + + if (environ_cb(RETRO_ENVIRONMENT_GET_INPUT_BITMASKS, NULL)) + libretro_supports_bitmasks = true; + + environ_cb(RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION, &libretro_msg_interface_version); + + palette_switch_init(); +} + +void retro_deinit(void) { + FCEUI_CloseGame(); + FCEUI_Sound(0); + FCEUI_Kill(); +#if defined(_3DS) + linearFree(fceu_video_out); +#elif !defined(PS2) && !defined(PSP) + if (fceu_video_out) + free(fceu_video_out); + fceu_video_out = NULL; +#endif +#if defined(PS2) + ps2 = NULL; +#endif + libretro_supports_bitmasks = false; + libretro_msg_interface_version = 0; + dipswitch_close(); +#if defined(HAVE_NTSC_FILTER) + ntsc_filter_deinit(); +#endif + palette_switch_deinit(); + stereo_filter_deinit(); +} + +unsigned retro_api_version(void) { + return RETRO_API_VERSION; +} + +void retro_get_system_info(struct retro_system_info *info) { + info->need_fullpath = true; + info->valid_extensions = "fds|nes|unf|unif"; +#ifdef GIT_VERSION + info->library_version = "(SVN)" GIT_VERSION; +#else + info->library_version = "(SVN)"; +#endif + info->library_name = "FCEUmm"; + info->block_extract = false; +} + +void retro_get_system_av_info(struct retro_system_av_info *info) { + unsigned width = NES_WIDTH - overscan_left - overscan_right; + unsigned height = NES_HEIGHT - overscan_top - overscan_bottom; + unsigned max_width = NES_WIDTH; + unsigned max_height = NES_HEIGHT; + +#if defined(HAVE_NTSC_FILTER) + width = (use_ntsc_filter != NTSC_NONE) ? NES_NTSC_OUT_WIDTH(width) : width; + height = (use_ntsc_filter != NTSC_NONE) ? height * 2 : height; + max_width = (use_ntsc_filter != NTSC_NONE) ? NES_NTSC_WIDTH : NES_WIDTH; + max_height = (use_ntsc_filter != NTSC_NONE) ? NES_HEIGHT * 2 : NES_HEIGHT; +#endif + + info->geometry.base_width = width; + info->geometry.max_width = max_width; + info->geometry.base_height = height; + info->geometry.max_height = max_height; + info->geometry.aspect_ratio = get_aspect_ratio(width, height); + info->timing.sample_rate = (double)FSettings.SndRate; + info->timing.fps = NES_TARGET_FPS; +} + +void retro_set_controller_port_device(unsigned port, unsigned device) { + if (port >= 5) + return; + + input_set_controller_port_device(port, device); +} + +void retro_reset(void) { + FCEUI_ResetNES(); +} + +void retro_run(void) { + uint8_t *gfx; + uint8_t *emp; + int32_t *sound; + int32_t ssize; + bool updated = false; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) + check_variables(false); + + if (input_needs_update) { + /* since you can only update input descriptors all at once, its better to place this callback here, + * so descriptor labels can be updated in real-time when inputs gets changed */ + input_needs_update = false; + input_update_descriptors(); + } + + poll_cb(); + + input_update(&input_cb); + FCEUI_Emulate(&gfx, &emp, &sound, &ssize, 0); + +#if defined(PSP) + retro_run_blit_psp(gfx); +#elif defined(PS2) + retro_run_blit_ps2(gfx); +#else +#if defined(HAVE_NTSC_FILTER) + if (use_ntsc_filter != NTSC_NONE) { + retro_run_blit_ntsc(gfx, emp); + } else +#endif /* HAVE_NTSC_FILTER */ + { + retro_run_blit(gfx, emp); + } +#endif + + stereo_filter_apply(sound, ssize); + audio_batch_cb((const int16_t *)sound, ssize); +} + +size_t retro_serialize_size(void) { + if (serialize_size == 0) { + /* Something arbitrarily big.*/ + uint8_t *buffer = (uint8_t *)malloc(1000000); + memstream_set_buffer(buffer, 1000000); + + FCEUSS_Save_Mem(); + serialize_size = memstream_get_last_size(); + free(buffer); + } + + return serialize_size; +} + +bool retro_serialize(void *data, size_t size) { + /* Cannot save state while Game Genie + * screen is open */ + if (geniestage == 1) + return false; + + if (size != retro_serialize_size()) + return false; + + memstream_set_buffer((uint8_t *)data, size); + FCEUSS_Save_Mem(); + return true; +} + +bool retro_unserialize(const void *data, size_t size) { + /* Cannot load state while Game Genie + * screen is open */ + if (geniestage == 1) + return false; + + if (size != retro_serialize_size()) + return false; + + memstream_set_buffer((uint8_t *)data, size); + FCEUSS_Load_Mem(); + return true; +} + +void retro_cheat_reset(void) { + FCEU_ResetCheats(); +} + +void retro_cheat_set(unsigned index, bool enabled, const char *code) { + char name[256]; + char temp[256]; + char *codepart; + uint16 a; + uint8 v; + int c; + int type = 1; + + if (code == NULL) + return; + + sprintf(name, "N/A"); + strcpy(temp, code); + codepart = strtok(temp, "+,;._ "); + + while (codepart) { + if ((strlen(codepart) == 7) && (codepart[4] == ':')) { + /* raw code in xxxx:xx format */ + log_cb.log(RETRO_LOG_DEBUG, "Cheat code added: '%s' (Raw)\n", codepart); + codepart[4] = '\0'; + a = strtoul(codepart, NULL, 16); + v = strtoul(codepart + 5, NULL, 16); + c = -1; + /* Zero-page addressing modes don't go through the normal read/write handlers in FCEU, so + * we must do the old hacky method of RAM cheats. */ + if (a < 0x0100) + type = 0; + FCEUI_AddCheat(name, a, v, c, type); + } else if ((strlen(codepart) == 10) && (codepart[4] == '?') && (codepart[7] == ':')) { + /* raw code in xxxx?xx:xx */ + log_cb.log(RETRO_LOG_DEBUG, "Cheat code added: '%s' (Raw)\n", codepart); + codepart[4] = '\0'; + codepart[7] = '\0'; + a = strtoul(codepart, NULL, 16); + v = strtoul(codepart + 8, NULL, 16); + c = strtoul(codepart + 5, NULL, 16); + /* Zero-page addressing modes don't go through the normal read/write handlers in FCEU, so + * we must do the old hacky method of RAM cheats. */ + if (a < 0x0100) + type = 0; + FCEUI_AddCheat(name, a, v, c, type); + } else if (GGisvalid(codepart) && FCEUI_DecodeGG(codepart, &a, &v, &c)) { + FCEUI_AddCheat(name, a, v, c, type); + log_cb.log(RETRO_LOG_DEBUG, "Cheat code added: '%s' (GG)\n", codepart); + } else if (FCEUI_DecodePAR(codepart, &a, &v, &c, &type)) { + FCEUI_AddCheat(name, a, v, c, type); + log_cb.log(RETRO_LOG_DEBUG, "Cheat code added: '%s' (PAR)\n", codepart); + } else + log_cb.log(RETRO_LOG_DEBUG, "Invalid or unknown code: '%s'\n", codepart); + codepart = strtok(NULL, "+,;._ "); + } +} + +static void check_system_specs(void) { + /* TODO - when we get it running at fullspeed on PSP, set to 4 */ + unsigned level = 5; + environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level); +} + +bool retro_load_game(const struct retro_game_info *info) { + unsigned i, j; + const char *system_dir = NULL; + enum retro_pixel_format rgb565; + + size_t desc_base = 64; + struct retro_memory_descriptor descs[64 + 4]; + struct retro_memory_map mmaps; + + struct retro_game_info_ext *info_ext = NULL; + const uint8_t *content_data = NULL; + size_t content_size = 0; + char content_path[2048] = { 0 }; + + if (!FCEUI_Initialize()) { + return false; + } + +#if defined(FRONTEND_SUPPORTS_RGB565) + rgb565 = RETRO_PIXEL_FORMAT_RGB565; + if (environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &rgb565)) + log_cb.log(RETRO_LOG_INFO, " Frontend supports RGB565 - will use that instead of XRGB1555.\n"); +#endif + + input_init_env(&environ_cb); + + if (environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &system_dir) && system_dir) + FCEUI_SetBaseDirectory(system_dir); + + /* Attempt to fetch extended game info */ + if (environ_cb(RETRO_ENVIRONMENT_GET_GAME_INFO_EXT, &info_ext) && info_ext) { + content_data = (const uint8_t *)info_ext->data; + content_size = info_ext->size; + + if (info_ext->file_in_archive) { + /* We don't have a 'physical' file in this + * case, but the core still needs a filename + * in order to detect the region of iNES v1.0 + * ROMs. We therefore fake it, using the content + * directory, canonical content name, and content + * file extension */ + snprintf(content_path, sizeof(content_path), "%s%c%s.%s", info_ext->dir, PATH_DEFAULT_SLASH_C(), + info_ext->name, info_ext->ext); + } else + strlcpy(content_path, info_ext->full_path, sizeof(content_path)); + } else { + if (!info || string_is_empty(info->path)) + return false; + + strlcpy(content_path, info->path, sizeof(content_path)); + } + + /* initialize some of the default variables */ + sndquality = -1; + opt_region = -1; + + isDendy = false; + + /* Wii: initialize this or else last variable is passed through + * when loading another rom causing save state size change. */ + serialize_size = 0; + + check_system_specs(); +#if defined(_3DS) + fceu_video_out = (uint16_t *)linearMemAlign(256 * 240 * sizeof(uint16_t), 128); +#elif !defined(PS2) && !defined(PSP) /* PS2 targets uses hw buffers for video */ +#if defined(HAVE_NTSC_FILTER) +#define FB_WIDTH 768 +#define FB_HEIGHT 512 +#else /* !HAVE_NTSC_FILTER */ +#define FB_WIDTH NES_WIDTH +#define FB_HEIGHT NES_HEIGHT +#endif + fceu_video_out = (uint16_t *)malloc(FB_WIDTH * FB_HEIGHT * sizeof(uint16_t)); +#endif /* !PS2 */ + + set_variables(); + check_variables(true); + + FCEUI_SetSoundVolume(SND_MASTER, 100); + FCEUI_Sound(44100); + + if (!(GameInfo = (FCEUGI *)FCEUI_LoadGame(content_path, content_data, content_size, frontend_post_load_init))) { + return false; + } + + external_palette_exist = palette_game_available ? true : false; + if (external_palette_exist) + FCEU_printf(" Loading custom palette: %s%cnes.pal\n", system_dir, PATH_DEFAULT_SLASH_C()); + current_palette = 0; + + check_variables(true); + stereo_filter_init(); + + input_set_defaults(); + input_update_descriptors(); + + i = 0; + memset(descs, 0, sizeof(descs)); + + for (j = 0; j < desc_base; j++) { + if (MMapPtrs[j] != NULL) { + descs[i].ptr = MMapPtrs[j]; + descs[i].start = j * 1024; + descs[i].len = 1024; + descs[i].select = 0; + if (descs[i].start < 0x2000) { + descs[i].addrspace = "RAM"; + } else if (descs[i].start < 0x4000) { + descs[i].addrspace = "PPU"; + } else if (descs[i].start < 0x4020) { + descs[i].addrspace = "APU/IO"; + } else { + descs[i].addrspace = "WRAM/CART"; + } + i++; + } + } + /* This doesn't map in 2004--2007 but those aren't really + * worthwhile to read from on a vblank anyway + */ + descs[i].flags = 0; + descs[i].ptr = PPU; + descs[i].offset = 0; + descs[i].start = 0x2000; + descs[i].select = 0; + descs[i].disconnect = 0; + descs[i].len = 4; + descs[i].addrspace = "PPUREG"; + i++; + /* In the future, it would be good to map pattern tables 1 and 2, + * but these must be remapped often + */ + /* descs[i] = (struct retro_memory_descriptor){0, ????, 0, 0x0000 | PPU_BIT, PPU_BIT, PPU_BIT, 0x1000, "PAT0"}; */ + /* i++; */ + /* descs[i] = (struct retro_memory_descriptor){0, ????, 0, 0x1000 | PPU_BIT, PPU_BIT, PPU_BIT, 0x1000, "PAT1"}; */ + /* i++; */ + /* Likewise it would be better to use "vnapage" for this but + * RetroArch API is inconvenient for handles like that, so we'll + * just blithely assume the client will handle mapping and that + * we'll ignore those carts that have extra NTARAM. + */ + descs[i].flags = 0; + descs[i].ptr = NTARAM; + descs[i].offset = 0; + descs[i].start = PPU_BIT | 0x2000; + descs[i].select = PPU_BIT; + descs[i].disconnect = PPU_BIT; + descs[i].len = 0x0800; + descs[i].addrspace = "NTARAM"; + i++; + descs[i].flags = 0; + descs[i].ptr = PALRAM; + descs[i].offset = 0; + descs[i].start = PPU_BIT | 0x3000; + descs[i].select = PPU_BIT; + descs[i].disconnect = PPU_BIT; + descs[i].len = 0x020; + descs[i].addrspace = "PALRAM"; + i++; + /* OAM doesn't really live anywhere in address space so I'll put it at 0x4000. */ + descs[i].flags = 0; + descs[i].ptr = SPRAM; + descs[i].offset = 0; + descs[i].start = PPU_BIT | 0x4000; + descs[i].select = PPU_BIT; + descs[i].disconnect = PPU_BIT; + descs[i].len = 0x100; + descs[i].addrspace = "OAM"; + i++; + mmaps.descriptors = descs; + mmaps.num_descriptors = i; + environ_cb(RETRO_ENVIRONMENT_SET_MEMORY_MAPS, &mmaps); + + return true; +} + +bool retro_load_game_special(unsigned game_type, const struct retro_game_info *info, size_t num_info) { + return false; +} + +void retro_unload_game(void) { + FCEUI_CloseGame(); +#if defined(_3DS) + if (fceu_video_out) + linearFree(fceu_video_out); +#elif !defined(PS2) && !defined(PSP) + if (fceu_video_out) + free(fceu_video_out); + fceu_video_out = NULL; +#endif +#if defined(PS2) + ps2 = NULL; +#endif +#if defined(HAVE_NTSC_FILTER) + ntsc_filter_deinit(); +#endif +} + +unsigned retro_get_region(void) { + return FSettings.PAL ? RETRO_REGION_PAL : RETRO_REGION_NTSC; +} + +void *retro_get_memory_data(unsigned type) { + switch (type) { + case RETRO_MEMORY_SAVE_RAM: + if (iNESCart.battery && iNESCart.SaveGame[0] && iNESCart.SaveGameLen[0]) { + return iNESCart.SaveGame[0]; + } else if (GameInfo->type == GIT_FDS) { + return FDSROM_ptr(); + } + break; + case RETRO_MEMORY_SYSTEM_RAM: + return RAM; + } + + return NULL; +} + +size_t retro_get_memory_size(unsigned type) { + switch (type) { + case RETRO_MEMORY_SAVE_RAM: + if (iNESCart.battery && iNESCart.SaveGame[0] && iNESCart.SaveGameLen[0]) { + return iNESCart.SaveGameLen[0]; + } else if (GameInfo->type == GIT_FDS) { + return FDSROM_size(); + } + break; + case RETRO_MEMORY_SYSTEM_RAM: + return RAM_SIZE; + } + + return 0; +} diff --git a/src/drivers/libretro/libretro_core_options.h b/libretro/libretro_core_options.h similarity index 69% rename from src/drivers/libretro/libretro_core_options.h rename to libretro/libretro_core_options.h index bb92d4f94..5666a4d8d 100644 --- a/src/drivers/libretro/libretro_core_options.h +++ b/libretro/libretro_core_options.h @@ -7,6 +7,8 @@ #include #include +#define HAVE_NO_LANGEXTRA /* its a maintenance hell to keep updated with default options */ + #ifndef HAVE_NO_LANGEXTRA #include "libretro_core_options_intl.h" #endif @@ -21,7 +23,7 @@ extern "C" { ******************************** */ -#define MAX_CORE_OPTIONS 37 +#define MAX_CORE_OPTIONS 48 /* RETRO_LANGUAGE_ENGLISH */ @@ -168,13 +170,13 @@ struct retro_core_option_v2_definition option_defs[] = { NULL, "video", { - { "0", NULL }, - { "4", NULL }, - { "8", NULL }, - { "12", NULL }, - { "16", NULL }, - { "20", NULL }, - { "24", NULL }, + { "0", "0px" }, + { "4", "4px" }, + { "8", "8px" }, + { "12", "12px" }, + { "16", "16px" }, + { "20", "20px" }, + { "24", "24px" }, { NULL, NULL }, }, "0", @@ -187,13 +189,13 @@ struct retro_core_option_v2_definition option_defs[] = { NULL, "video", { - { "0", NULL }, - { "4", NULL }, - { "8", NULL }, - { "12", NULL }, - { "16", NULL }, - { "20", NULL }, - { "24", NULL }, + { "0", "0px" }, + { "4", "4px" }, + { "8", "8px" }, + { "12", "12px" }, + { "16", "16px" }, + { "20", "20px" }, + { "24", "24px" }, { NULL, NULL }, }, "0", @@ -206,13 +208,13 @@ struct retro_core_option_v2_definition option_defs[] = { NULL, "video", { - { "0", NULL }, - { "4", NULL }, - { "8", NULL }, - { "12", NULL }, - { "16", NULL }, - { "20", NULL }, - { "24", NULL }, + { "0", "0px" }, + { "4", "4px" }, + { "8", "8px" }, + { "12", "12px" }, + { "16", "16px" }, + { "20", "20px" }, + { "24", "24px" }, { NULL, NULL }, }, "8", @@ -225,13 +227,13 @@ struct retro_core_option_v2_definition option_defs[] = { NULL, "video", { - { "0", NULL }, - { "4", NULL }, - { "8", NULL }, - { "12", NULL }, - { "16", NULL }, - { "20", NULL }, - { "24", NULL }, + { "0", "0px" }, + { "4", "4px" }, + { "8", "8px" }, + { "12", "12px" }, + { "16", "16px" }, + { "20", "20px" }, + { "24", "24px" }, { NULL, NULL }, }, "8", @@ -284,6 +286,34 @@ struct retro_core_option_v2_definition option_defs[] = { "disabled" }, #endif + { + "fceumm_hide_sprites", + "Hide Sprites", + NULL, + "Show or hide sprites.", + NULL, + "video", + { + { "enabled", NULL }, + { "disabled", NULL }, + { NULL, NULL }, + }, + "disabled" + }, + { + "fceumm_hide_background", + "Hide Background.", + NULL, + "Show or hide background.", + NULL, + "video", + { + { "enabled", NULL }, + { "disabled", NULL }, + { NULL, NULL }, + }, + "disabled" + }, { "fceumm_sndquality", "Sound Quality", @@ -301,14 +331,16 @@ struct retro_core_option_v2_definition option_defs[] = { }, { "fceumm_sndlowpass", - "Audio RF Filter", + "Audio Low-pass Filter", NULL, "Apply a low pass audio filter to simulate the 'muted' sound of the NES when connected to a television via the RF modulator.", NULL, "audio", { { "disabled", NULL }, - { "enabled", NULL }, + { "3", NULL }, + { "2", NULL }, + { "1", NULL }, { NULL, NULL }, }, "disabled", @@ -376,94 +408,417 @@ struct retro_core_option_v2_definition option_defs[] = { "fceumm_sndvolume", "Master Volume", NULL, - "Change master volume level.", + "Change master volume level %.", NULL, "audio", { - { "0", "0%" }, - { "1", "10%" }, - { "2", "20%" }, - { "3", "30%" }, - { "4", "40%" }, - { "5", "50%" }, - { "6", "60%" }, - { "7", "70%" }, - { "8", "80%" }, - { "9", "90%" }, - { "10", "100%" }, + { "0", NULL }, + { "5", NULL }, + { "10", NULL }, + { "15", NULL }, + { "20", NULL }, + { "25", NULL }, + { "30", NULL }, + { "35", NULL }, + { "40", NULL }, + { "45", NULL }, + { "50", NULL }, + { "55", NULL }, + { "60", NULL }, + { "65", NULL }, + { "70", NULL }, + { "75", NULL }, + { "80", NULL }, + { "85", NULL }, + { "90", NULL }, + { "95", NULL }, + { "100", NULL }, + { "105", NULL }, + { "110", NULL }, + { "115", NULL }, + { "120", NULL }, + { "125", NULL }, + { "130", NULL }, + { "135", NULL }, + { "140", NULL }, + { "145", NULL }, + { "150", NULL }, + { "155", NULL }, + { "160", NULL }, + { "165", NULL }, + { "170", NULL }, + { "175", NULL }, + { "180", NULL }, + { "185", NULL }, + { "190", NULL }, + { "195", NULL }, + { "200", NULL }, { NULL, NULL }, }, - "7", + "100", }, { - "fceumm_apu_1", - "Audio Channel 1 (Square 1)", - "Channel 1 (Square 1)", - "Enables or disables pulse wave generator audio output 1.", + "fceumm_apu_square_1", + "Channel Volume (Square 1)", + NULL, + "Change pulse wave generator 1 audio output.", NULL, "audio", { - { "enabled", NULL }, - { "disabled", NULL }, - { NULL, NULL }, + { "0", NULL }, + { "5", NULL }, + { "10", NULL }, + { "15", NULL }, + { "20", NULL }, + { "25", NULL }, + { "30", NULL }, + { "35", NULL }, + { "40", NULL }, + { "45", NULL }, + { "50", NULL }, + { "55", NULL }, + { "60", NULL }, + { "65", NULL }, + { "70", NULL }, + { "75", NULL }, + { "80", NULL }, + { "85", NULL }, + { "90", NULL }, + { "95", NULL }, + { "100", NULL }, + { NULL, NULL }, }, - "enabled", + "100", }, { - "fceumm_apu_2", - "Audio Channel 2 (Square 2)", - "Channel 2 (Square 2)", - "Enables or disables pulse wave generator audio output 2.", + "fceumm_apu_square_2", + "Channel Volume (Square 2)", + NULL, + "Change pulse wave generator 2 audio output.", NULL, "audio", { - { "enabled", NULL }, - { "disabled", NULL }, - { NULL, NULL }, + { "0", NULL }, + { "5", NULL }, + { "10", NULL }, + { "15", NULL }, + { "20", NULL }, + { "25", NULL }, + { "30", NULL }, + { "35", NULL }, + { "40", NULL }, + { "45", NULL }, + { "50", NULL }, + { "55", NULL }, + { "60", NULL }, + { "65", NULL }, + { "70", NULL }, + { "75", NULL }, + { "80", NULL }, + { "85", NULL }, + { "90", NULL }, + { "95", NULL }, + { "100", NULL }, + { NULL, NULL }, }, - "enabled", + "100", }, { - "fceumm_apu_3", - "Audio Channel 3 (Triangle)", - "Channel 3 (Triangle)", - "Enables or disables triangle wave generator audio output.", + "fceumm_apu_triangle", + "Channel Volume (Triangle)", + NULL, + "Modify triangle wave generator audio output.", NULL, "audio", { - { "enabled", NULL }, - { "disabled", NULL }, - { NULL, NULL }, + { "0", NULL }, + { "5", NULL }, + { "10", NULL }, + { "15", NULL }, + { "20", NULL }, + { "25", NULL }, + { "30", NULL }, + { "35", NULL }, + { "40", NULL }, + { "45", NULL }, + { "50", NULL }, + { "55", NULL }, + { "60", NULL }, + { "65", NULL }, + { "70", NULL }, + { "75", NULL }, + { "80", NULL }, + { "85", NULL }, + { "90", NULL }, + { "95", NULL }, + { "100", NULL }, + { NULL, NULL }, }, - "enabled", + "100", }, { - "fceumm_apu_4", - "Audio Channel 4 (Noise)", - "Channel 4 (Noise)", - "Enables or disables noise generator audio output.", + "fceumm_apu_noise", + "Channel Volume (Noise)", + NULL, + "Change noise generator audio output.", NULL, "audio", { - { "enabled", NULL }, - { "disabled", NULL }, - { NULL, NULL }, + { "0", NULL }, + { "5", NULL }, + { "10", NULL }, + { "15", NULL }, + { "20", NULL }, + { "25", NULL }, + { "30", NULL }, + { "35", NULL }, + { "40", NULL }, + { "45", NULL }, + { "50", NULL }, + { "55", NULL }, + { "60", NULL }, + { "65", NULL }, + { "70", NULL }, + { "75", NULL }, + { "80", NULL }, + { "85", NULL }, + { "90", NULL }, + { "95", NULL }, + { "100", NULL }, + { NULL, NULL }, }, - "enabled", + "100", }, { - "fceumm_apu_5", - "Audio Channel 5 (PCM)", - "Channel 5 (PCM)", - "Enables or disables delta modulation channel audio output.", + "fceumm_apu_dpcm", + "Channel Volume (DPCM)", + NULL, + "Change delta modulation channel audio output.", NULL, "audio", { - { "enabled", NULL }, - { "disabled", NULL }, - { NULL, NULL }, + { "0", NULL }, + { "5", NULL }, + { "10", NULL }, + { "15", NULL }, + { "20", NULL }, + { "25", NULL }, + { "30", NULL }, + { "35", NULL }, + { "40", NULL }, + { "45", NULL }, + { "50", NULL }, + { "55", NULL }, + { "60", NULL }, + { "65", NULL }, + { "70", NULL }, + { "75", NULL }, + { "80", NULL }, + { "85", NULL }, + { "90", NULL }, + { "95", NULL }, + { "100", NULL }, + { NULL, NULL }, }, - "enabled", + "100", + }, + { + "fceumm_apu_fds", + "Channel Volume (FDS)", + NULL, + "Change FDS expansion audio output.", + NULL, + "audio", + { + { "0", NULL }, + { "5", NULL }, + { "10", NULL }, + { "15", NULL }, + { "20", NULL }, + { "25", NULL }, + { "30", NULL }, + { "35", NULL }, + { "40", NULL }, + { "45", NULL }, + { "50", NULL }, + { "55", NULL }, + { "60", NULL }, + { "65", NULL }, + { "70", NULL }, + { "75", NULL }, + { "80", NULL }, + { "85", NULL }, + { "90", NULL }, + { "95", NULL }, + { "100", NULL }, + { NULL, NULL }, + }, + "100", + }, + { + "fceumm_apu_s5b", + "Channel Volume (S5B)", + NULL, + "Change Sunsoft S5B expansion audio output.", + NULL, + "audio", + { + { "0", NULL }, + { "5", NULL }, + { "10", NULL }, + { "15", NULL }, + { "20", NULL }, + { "25", NULL }, + { "30", NULL }, + { "35", NULL }, + { "40", NULL }, + { "45", NULL }, + { "50", NULL }, + { "55", NULL }, + { "60", NULL }, + { "65", NULL }, + { "70", NULL }, + { "75", NULL }, + { "80", NULL }, + { "85", NULL }, + { "90", NULL }, + { "95", NULL }, + { "100", NULL }, + { NULL, NULL }, + }, + "100", + }, + { + "fceumm_apu_n163", + "Channel Volume (N163)", + NULL, + "Chnage Namco 163 expansion audio output.", + NULL, + "audio", + { + { "0", NULL }, + { "5", NULL }, + { "10", NULL }, + { "15", NULL }, + { "20", NULL }, + { "25", NULL }, + { "30", NULL }, + { "35", NULL }, + { "40", NULL }, + { "45", NULL }, + { "50", NULL }, + { "55", NULL }, + { "60", NULL }, + { "65", NULL }, + { "70", NULL }, + { "75", NULL }, + { "80", NULL }, + { "85", NULL }, + { "90", NULL }, + { "95", NULL }, + { "100", NULL }, + { NULL, NULL }, + }, + "100", + }, + { + "fceumm_apu_vrc6", + "Channel Volume (VRC6)", + NULL, + "Change VRC6 expansion audio output.", + NULL, + "audio", + { + { "0", NULL }, + { "5", NULL }, + { "10", NULL }, + { "15", NULL }, + { "20", NULL }, + { "25", NULL }, + { "30", NULL }, + { "35", NULL }, + { "40", NULL }, + { "45", NULL }, + { "50", NULL }, + { "55", NULL }, + { "60", NULL }, + { "65", NULL }, + { "70", NULL }, + { "75", NULL }, + { "80", NULL }, + { "85", NULL }, + { "90", NULL }, + { "95", NULL }, + { "100", NULL }, + { NULL, NULL }, + }, + "100", + }, + { + "fceumm_apu_vrc7", + "Channel Volume (VRC7)", + NULL, + "Change VRC7 expansion audio output.", + NULL, + "audio", + { + { "0", NULL }, + { "5", NULL }, + { "10", NULL }, + { "15", NULL }, + { "20", NULL }, + { "25", NULL }, + { "30", NULL }, + { "35", NULL }, + { "40", NULL }, + { "45", NULL }, + { "50", NULL }, + { "55", NULL }, + { "60", NULL }, + { "65", NULL }, + { "70", NULL }, + { "75", NULL }, + { "80", NULL }, + { "85", NULL }, + { "90", NULL }, + { "95", NULL }, + { "100", NULL }, + { NULL, NULL }, + }, + "100", + }, + { + "fceumm_apu_mmc5", + "Channel Volume (MMC5)", + NULL, + "Change MMC5 expansion audio output.", + NULL, + "audio", + { + { "0", NULL }, + { "5", NULL }, + { "10", NULL }, + { "15", NULL }, + { "20", NULL }, + { "25", NULL }, + { "30", NULL }, + { "35", NULL }, + { "40", NULL }, + { "45", NULL }, + { "50", NULL }, + { "55", NULL }, + { "60", NULL }, + { "65", NULL }, + { "70", NULL }, + { "75", NULL }, + { "80", NULL }, + { "85", NULL }, + { "90", NULL }, + { "95", NULL }, + { "100", NULL }, + { NULL, NULL }, + }, + "100", }, { "fceumm_turbo_enable", @@ -476,7 +831,7 @@ struct retro_core_option_v2_definition option_defs[] = { { "None", NULL }, { "Player 1", NULL }, { "Player 2", NULL }, - { "Both", NULL }, + { "Players 1 and 2", NULL }, { NULL, NULL }, }, "None", @@ -503,13 +858,14 @@ struct retro_core_option_v2_definition option_defs[] = { }, { "fceumm_zapper_mode", - "Zapper Mode", + "Zapper/Mouse Mode", NULL, - "Selects device to use for Zapper games.", + "Selects device to use for Zapper or Mouse/Pointer games.", NULL, "input", { - { "lightgun", "Light gun" }, + { "lightgun", "Crosshair Light gun" }, + { "stlightgun", "Seqencial Target Light gun" }, { "touchscreen", "Touchscreen" }, { "mouse", "Mouse" }, { NULL, NULL }, @@ -530,6 +886,34 @@ struct retro_core_option_v2_definition option_defs[] = { }, "enabled", }, + { + "fceumm_zapper_trigger", + "Invert Zapper Trigger Signal", + NULL, + "Inverts trigger logic when using a Zapper. Disabling it resembles original hardware behavior.", + NULL, + "input", + { + { "enabled", NULL }, + { "disabled", NULL }, + { NULL, NULL }, + }, + "disabled", + }, + { + "fceumm_zapper_sensor", + "Invert Zapper Sensor Signal", + NULL, + "Inverts sensor logic when using a Zapper (Sequential Targets Light gun mode only). Disabling it resembles original NES/FC hardware behavior.", + NULL, + "input", + { + { "enabled", NULL }, + { "disabled", NULL }, + { NULL, NULL }, + }, + "enabled", + }, { "fceumm_zapper_tolerance", "Zapper Tolerance", diff --git a/src/drivers/libretro/libretro_core_options_intl.h b/libretro/libretro_core_options_intl.h similarity index 100% rename from src/drivers/libretro/libretro_core_options_intl.h rename to libretro/libretro_core_options_intl.h diff --git a/src/drivers/libretro/libretro_dipswitch.c b/libretro/libretro_dipswitch.c similarity index 90% rename from src/drivers/libretro/libretro_dipswitch.c rename to libretro/libretro_dipswitch.c index 1521d0331..b4253354f 100644 --- a/src/drivers/libretro/libretro_dipswitch.c +++ b/libretro/libretro_dipswitch.c @@ -15,8 +15,6 @@ #define MAX_CORE_OPTIONS 8 #define MAX_VALUES 10 -extern CartInfo iNESCart; - typedef struct { const char *name; uint8 value; @@ -1067,7 +1065,8 @@ static VSUNIGAME dipswitch_topgun = { enum { DPSW_NONE = 0, DPSW_VSUNI, - DPSW_NWC + DPSW_NES_EVENT, + DPSW_NES_EVENT2 }; static struct retro_core_option_v2_definition vscoreopt[MAX_CORE_OPTIONS]; @@ -1079,6 +1078,8 @@ static unsigned numCoreOptions = 0; static unsigned numValues[MAX_VALUES] = {0}; static uint8 dipswitchPreset = 0; +static retro_environment_t environ_cb; /* cached inset_dipswitch_variables */ + static const char *str_to_corekey(char *s) { char *str = s; @@ -1192,11 +1193,10 @@ static VSUNIGAME *get_vsuni_dipswitch(unsigned id) return (&dipswitch_topgun); } - FCEU_printf("No dipsettings found. %d\n", id); return (NULL); } -static void update_dipswitch_vsuni(void) +static void check_dipswitch_vsuni(void) { unsigned index_key; uint8 vsdip_new = 0; @@ -1228,19 +1228,73 @@ static void update_dipswitch_vsuni(void) vsdip_new |= dipswitchPreset; /* Append any default preset to new value */ if (last_vsdip != vsdip_new) { - vsdip = vsdip_new; + vsuni_system.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); + (vsuni_system.vsdip >> 0) & 1, (vsuni_system.vsdip >> 1) & 1, (vsuni_system.vsdip >> 2) & 1, (vsuni_system.vsdip >> 3) & 1, + (vsuni_system.vsdip >> 4) & 1, (vsuni_system.vsdip >> 5) & 1, (vsuni_system.vsdip >> 6) & 1, (vsuni_system.vsdip >> 7) & 1); #endif } } /* Nintendo World Championships 1990 */ -static struct retro_core_option_v2_definition dipswitch_nwc[] = { +static struct retro_core_option_v2_definition dipswitch_nes_event[] = { + { + "fceumm_dipswitch_nes_event", + "Gameplay Duration in minutes (Restart)", + NULL, + "Sets the game timer in minutes.", + NULL, + "dip_switch", + { + { "0", "5:00" }, + { "1", "5:19" }, + { "2", "5:38" }, + { "3", "5:56" }, + { "4", "6:15 (Tournament)" }, + { "5", "6:34" }, + { "6", "6:53" }, + { "7", "7:11" }, + { "8", "7:30" }, + { "9", "7:49" }, + { "10", "8:08" }, + { "11", "8:27" }, + { "12", "8:45" }, + { "13", "9:04" }, + { "14", "9:23" }, + { "15", "9:42" }, + { NULL, NULL }, + }, + "4", + }, + { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL }, +}; + +static void check_dipswitch_nes_event(void) +{ + int dpsw_nes_event = 0x00; + struct retro_variable var = { + "fceumm_dipswitch_nes_event", + NULL + }; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + dpsw_nes_event = atoi(var.value); + + if (GameInfo->cspecial != dpsw_nes_event) + { + GameInfo->cspecial = dpsw_nes_event; +#ifdef DEBUG + FCEU_printf("Dipswitch changed = %d%d%d%d\n", (dpsw_nes_event >> 0) & 1, + (dpsw_nes_event >> 1) & 1, (dpsw_nes_event >> 2) & 1, (dpsw_nes_event >> 3) & 1); +#endif + } +} + +/* Nintendo Campus Challenge 1991 */ +static struct retro_core_option_v2_definition dipswitch_nes_event2[] = { { - "fceumm_dipswitch_nwc", + "fceumm_dipswitch_nes_event2", "Gameplay Duration in minutes (Restart)", NULL, "Sets the game timer in minutes.", @@ -1270,37 +1324,39 @@ static struct retro_core_option_v2_definition dipswitch_nwc[] = { { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL }, }; -static void update_dipswitch_nwc(void) +static void check_dipswitch_nes_event2(void) { - int dpsw_nwc = 0x00; + int dpsw_nes_event2 = 0x00; struct retro_variable var = { - "fceumm_dipswitch_nwc", + "fceumm_dipswitch_nes_event2", NULL }; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - dpsw_nwc = atoi(var.value); + dpsw_nes_event2 = atoi(var.value); - if (GameInfo->cspecial != dpsw_nwc) + if (GameInfo->cspecial != dpsw_nes_event2) { - GameInfo->cspecial = dpsw_nwc; + GameInfo->cspecial = dpsw_nes_event2; #ifdef DEBUG - FCEU_printf("Dipswitch changed = %d%d%d%d\n", (dpsw_nwc >> 0) & 1, - (dpsw_nwc >> 1) & 1, (dpsw_nwc >> 2) & 1, (dpsw_nwc >> 3) & 1); + FCEU_printf("NES-EVENT2 Dipswitch changed = %d%d%d%d\n", (dpsw_nes_event2 >> 0) & 1, + (dpsw_nes_event2 >> 1) & 1, (dpsw_nes_event2 >> 2) & 1, (dpsw_nes_event2 >> 3) & 1); #endif } } -void set_dipswitch_variables(unsigned current_index, struct retro_core_option_v2_definition *vars) +void set_dipswitch_variables(retro_environment_t *_environ_cb, unsigned current_index, struct retro_core_option_v2_definition *vars) { unsigned index = current_index; int dipsw_size = 0; + environ_cb = *_environ_cb; + /* VSUNI Dipswitch */ - if (GameInfo->type == GIT_VSUNI) + if (GameInfo && (GameInfo->type == GIT_VSUNI)) { dipswitchPreset = FCEUI_VSUniGetDIPs(); - vsgame = get_vsuni_dipswitch(GameInfo->gameid); + vsgame = get_vsuni_dipswitch(vsuni_system.gameid); if (vsgame) { unsigned i, j; @@ -1338,10 +1394,23 @@ void set_dipswitch_variables(unsigned current_index, struct retro_core_option_v2 /* Nintendo World Championship cart (Mapper 105)*/ if (iNESCart.mapper == 105) { - dipswitch_type = DPSW_NWC; + dipswitch_type = DPSW_NES_EVENT; + + while (dipswitch_nes_event[dipsw_size].key) { + memcpy(&vars[index], &dipswitch_nes_event[dipsw_size], + sizeof(struct retro_core_option_v2_definition)); + index++; + dipsw_size++; + } + return; + } + + if (iNESCart.mapper == 555) + { + dipswitch_type = DPSW_NES_EVENT2; - while (dipswitch_nwc[dipsw_size].key) { - memcpy(&vars[index], &dipswitch_nwc[dipsw_size], + while (dipswitch_nes_event2[dipsw_size].key) { + memcpy(&vars[index], &dipswitch_nes_event2[dipsw_size], sizeof(struct retro_core_option_v2_definition)); index++; dipsw_size++; @@ -1353,19 +1422,22 @@ void set_dipswitch_variables(unsigned current_index, struct retro_core_option_v2 return; } -void update_dipswitch(void) +void check_dipswitch_variables(void) { switch (dipswitch_type) { case DPSW_VSUNI: - update_dipswitch_vsuni(); + check_dipswitch_vsuni(); + break; + case DPSW_NES_EVENT: + check_dipswitch_nes_event(); break; - case DPSW_NWC: - update_dipswitch_nwc(); + case DPSW_NES_EVENT2: + check_dipswitch_nes_event2(); break; } } -void DPSW_Cleanup(void) +void dipswitch_close(void) { unsigned i; diff --git a/libretro/libretro_dipswitch.h b/libretro/libretro_dipswitch.h new file mode 100644 index 000000000..36283da0a --- /dev/null +++ b/libretro/libretro_dipswitch.h @@ -0,0 +1,10 @@ +#ifndef __VSUNI_DIPSWITCH__ +#define __VSUNI_DIPSWITCH__ + +#include + +void set_dipswitch_variables(retro_environment_t *_environ_cb, unsigned current_index, struct retro_core_option_v2_definition *vars); +void check_dipswitch_variables(void); +void dipswitch_close(void); + +#endif /* __VSUNI_DIPSWITCH__ */ diff --git a/libretro/libretro_input.c b/libretro/libretro_input.c new file mode 100644 index 000000000..0fa46ef4f --- /dev/null +++ b/libretro/libretro_input.c @@ -0,0 +1,996 @@ +#include "libretro_input.h" + +#include "../src/fceu.h" +#include "../src/cart.h" +#include "../src/fds.h" +#include "../src/input.h" +#include "../src/vsuni.h" + +#define DEVICE_AUTO RETRO_DEVICE_JOYPAD +#define DEVICE_SI_GAMEPAD RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 0) +#define DEVICE_SI_SNESGAMEPAD RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 1) +#define DEVICE_SI_VIRTUALBOY RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 2) +#define DEVICE_SI_POWERPADA RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 3) +#define DEVICE_SI_POWERPADB RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 4) +#define DEVICE_SIFC_HYPERSHOT RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 5) +#define DEVICE_SIFC_FTRAINERA RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 6) +#define DEVICE_SIFC_FTRAINERB RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 7) +#define DEVICE_SIFC_QUIZKING RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 8) +#define DEVICE_SIFC_4PLAYER RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 9) +#define DEVICE_SIFC_HORI4PLAYER RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 10) +#define DEVICE_SI_ZAPPER RETRO_DEVICE_LIGHTGUN +#define DEVICE_SIFC_ZAPPER RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 0) +#define DEVICE_SIFC_SHADOW RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 1) +#define DEVICE_SI_ARKANOID RETRO_DEVICE_MOUSE +#define DEVICE_SI_SNESMOUSE RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_MOUSE, 0) +#define DEVICE_SIFC_ARKANOID RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_MOUSE, 1) +#define DEVICE_SIFC_OEKAKIDS RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_MOUSE, 2) + +static const struct retro_controller_description pads_nes[10] = { + { "Auto", DEVICE_AUTO }, + { "Gamepad", DEVICE_SI_GAMEPAD }, + { "Arkanoid", DEVICE_SI_ARKANOID }, + { "Zapper", DEVICE_SI_ZAPPER }, + { "Power Pad A", DEVICE_SI_POWERPADA }, + { "Power Pad B", DEVICE_SI_POWERPADB }, + { "SNES Pad", DEVICE_SI_SNESGAMEPAD }, + { "SNES Mouse", DEVICE_SI_SNESMOUSE }, + { "Virtual Boy", DEVICE_SI_VIRTUALBOY }, + { NULL, 0 }, +}; + +static const struct retro_controller_description pads_fc[] = { + { "Auto", DEVICE_AUTO }, + { "Arkanoid", DEVICE_SIFC_ARKANOID }, + { "Hyper Shot Gun", DEVICE_SIFC_SHADOW }, + { "HyperShot Pads", DEVICE_SIFC_HYPERSHOT }, + { "Oeka Kids Tablet", DEVICE_SIFC_OEKAKIDS }, + { "4-Player Adapter (Simple)", DEVICE_SIFC_4PLAYER }, + { "Hori 4-Player Adapter", DEVICE_SIFC_HORI4PLAYER }, + { "Family Trainer A", DEVICE_SIFC_FTRAINERA }, + { "Family Trainer B", DEVICE_SIFC_FTRAINERB }, + { "Quiz King", DEVICE_SIFC_QUIZKING }, + { NULL, 0 }, +}; + +static const struct retro_controller_info ports[6] = { + { pads_nes, 10 }, + { pads_nes, 10 }, + { pads_nes, 2 }, + { pads_nes, 2 }, + { pads_fc, 11 }, + { 0, 0 }, +}; + +/* + * Flags to keep track of whether turbo + * buttons toggled on or off. + * + * There are two values in array + * for Turbo A and Turbo B for + * each player + */ + +#define MAX_BUTTONS 9 +#define TURBO_BUTTONS 2 + +uint8 turbo_button_toggle[MAX_CONTROLLERS][TURBO_BUTTONS] = { { 0 } }; + +typedef struct { + unsigned retro; + unsigned nes; +} keymap; + +static const keymap turbomap[] = { + { RETRO_DEVICE_ID_JOYPAD_X, JOY_A }, + { RETRO_DEVICE_ID_JOYPAD_Y, JOY_B }, +}; + +static NES_INPUT_T nes_input = { 0 }; + +static uint32_t Dummy = 0; + +/* cached during input_init_env() */ +static retro_environment_t environ_cb; + +/* cached during input_update() */ +static retro_input_state_t input_cb; + +static void addDesc(struct retro_input_descriptor *p, unsigned port, unsigned id, const char *description) { + p->port = port; + p->device = RETRO_DEVICE_JOYPAD; + p->index = 0; + p->id = id; + p->description = description; +} + +static void set_input(unsigned port) { + int type = 0; + int attrib = 0; + void *inputDPtr = NULL; + + if (port <= 1) { + switch (nes_input.type[port]) { + case RETRO_DEVICE_NONE: + type = SI_UNSET; + inputDPtr = &Dummy; + FCEU_printf(" Player %u: none\n", port + 1); + break; + case RETRO_DEVICE_JOYPAD: + case DEVICE_SI_GAMEPAD: + type = SI_GAMEPAD; + inputDPtr = &nes_input.JSReturn; + FCEU_printf(" Player %u: Gamepad\n", port + 1); + break; + case DEVICE_SI_ARKANOID: + type = SI_ARKANOID; + inputDPtr = &nes_input.MouseData[port]; + FCEU_printf(" Player %u: Arkanoid Paddle\n", port + 1); + break; + case DEVICE_SI_ZAPPER: + type = SI_ZAPPER; + attrib = 1; + inputDPtr = &nes_input.MouseData[port]; + FCEU_printf(" Player %u: Zapper\n", port + 1); + break; + case DEVICE_SI_POWERPADA: + type = SI_POWERPADA; + inputDPtr = &nes_input.PowerPadData[port]; + FCEU_printf(" Player %u: Power Pad A\n", port + 1); + break; + case DEVICE_SI_POWERPADB: + type = SI_POWERPADB; + inputDPtr = &nes_input.PowerPadData[port]; + FCEU_printf(" Player %u: Power Pad B\n", port + 1); + break; + case DEVICE_SI_SNESGAMEPAD: + type = SI_SNES_GAMEPAD; + inputDPtr = &nes_input.JoyButtons[port]; + FCEU_printf(" Player %u: SNES Pad\n", port + 1); + break; + case DEVICE_SI_SNESMOUSE: + type = SI_SNES_MOUSE; + inputDPtr = &nes_input.MouseData[port]; + FCEU_printf(" Player %u: SNES Mouse\n", port + 1); + break; + case DEVICE_SI_VIRTUALBOY: + type = SI_VIRTUALBOY; + inputDPtr = &nes_input.JoyButtons[port]; + FCEU_printf(" Player %u: Virtual Boy\n", port + 1); + break; + } + + FCEUI_SetInput(port, type, inputDPtr, attrib); + } else if (port < MAX_CONTROLLERS) { + if (nes_input.type[port] == DEVICE_SI_GAMEPAD) { + FCEU_printf(" Player %u: Gamepad\n", port + 1); + } else { + FCEU_printf(" Player %u: None\n", port + 1); + } + } else { + /* famicom expansion port */ + switch (nes_input.type[4]) { + case DEVICE_SIFC_ARKANOID: + type = SIFC_ARKANOID; + inputDPtr = nes_input.FamicomData; + FCEU_printf(" Famicom Expansion: Arkanoid Paddle\n"); + break; + case DEVICE_SIFC_SHADOW: + type = SIFC_SHADOW; + inputDPtr = nes_input.FamicomData; + attrib = 1; + FCEU_printf(" Famicom Expansion: Hyper Shot Gun\n"); + break; + case DEVICE_SIFC_OEKAKIDS: + type = SIFC_OEKAKIDS; + inputDPtr = nes_input.FamicomData; + attrib = 1; + FCEU_printf(" Famicom Expansion: Oeka Kids Tablet\n"); + break; + case DEVICE_SIFC_4PLAYER: + type = SIFC_4PLAYER; + inputDPtr = &nes_input.JSReturn; + FCEU_printf(" Famicom Expansion: 4-Player Adapter\n"); + break; + case DEVICE_SIFC_HORI4PLAYER: + type = SIFC_HORI4PLAYER; + inputDPtr = &nes_input.JSReturn; + FCEU_printf(" Famicom Expansion: Hori 4-Player Adapter\n"); + break; + case DEVICE_SIFC_HYPERSHOT: + type = SIFC_HYPERSHOT; + inputDPtr = nes_input.FamicomData; + FCEU_printf(" Famicom Expansion: HyperShot Pads\n"); + break; + case DEVICE_SIFC_FTRAINERA: + type = SIFC_FTRAINERA; + inputDPtr = &nes_input.FTrainerData; + FCEU_printf(" Famicom Expansion: Family Trainer A\n"); + break; + case DEVICE_SIFC_FTRAINERB: + type = SIFC_FTRAINERB; + inputDPtr = &nes_input.FTrainerData; + FCEU_printf(" Famicom Expansion: Family Trainer B\n"); + break; + case DEVICE_SIFC_QUIZKING: + type = SIFC_QUIZKING; + inputDPtr = &nes_input.QuizKingData; + FCEU_printf(" Famicom Expansion: Quiz King\n"); + break; + case RETRO_DEVICE_NONE: + default: + type = SIFC_NONE, inputDPtr = &Dummy; + FCEU_printf(" Famicom Expansion: none\n"); + break; + } + + FCEUI_SetInputFC(type, inputDPtr, attrib); + } + + FCEUI_SetInputFourScore(FALSE); + if (iNESCart.InputTypes == 0x02) { /* NES Four Score input is set */ + FCEUI_SetInputFourScore(TRUE); + } +} + +void input_update_descriptors(void) { + struct retro_input_descriptor desc[128] = { 0 }; + + int i, port; + + for (i = 0, port = 0; port < 5; port++) { + if (nes_input.type[port] == DEVICE_SI_GAMEPAD || nes_input.type[port] == RETRO_DEVICE_JOYPAD || + nes_input.type[port] == DEVICE_SI_SNESGAMEPAD) { + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right"); + if (nes_input.type[port] == DEVICE_SI_SNESGAMEPAD) { + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_A, "A"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_B, "B"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_X, "X"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_Y, "Y"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_L, "L"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_R, "R"); + } else { + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_B, "B"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_A, "A"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_X, "Turbo A"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_Y, "Turbo B"); + } + + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_START, "Start"); + + if (port == 0) { + addDesc(&desc[i++], 0, RETRO_DEVICE_ID_JOYPAD_L3, "(Famicom) Microphone (P2)"); + + if (GameInfo->type == GIT_FDS) { + addDesc(&desc[i++], 0, RETRO_DEVICE_ID_JOYPAD_L, "(FDS) Disk Side Change"); + addDesc(&desc[i++], 0, RETRO_DEVICE_ID_JOYPAD_R, "(FDS) Insert/Eject Disk"); + } + + if (palette_switch_enabled) + addDesc(&desc[i++], 0, RETRO_DEVICE_ID_JOYPAD_L2, "Switch Palette (+ Left/Right)"); + } + + if (GameInfo->type == GIT_VSUNI) { + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_L2, "(VS) Insert Coin (slot 1)"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_R2, "(VS) Insert Coin (slot 2)"); + } + + if (iNESCart.mapper == 124) { + addDesc(&desc[i++], 0, RETRO_DEVICE_ID_JOYPAD_L2, "Insert Coin"); + addDesc(&desc[i++], 0, RETRO_DEVICE_ID_JOYPAD_R2, "Insert Coin"); + } + } else if (nes_input.type[port] == DEVICE_SIFC_FTRAINERA || nes_input.type[port] == DEVICE_SIFC_FTRAINERB || + nes_input.type[port] == DEVICE_SI_POWERPADA || nes_input.type[port] == DEVICE_SI_POWERPADB) { + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_B, "B1"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_A, "B2"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_Y, "B3"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_X, "B4"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_L, "B5"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_R, "B6"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_LEFT, "B7"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_RIGHT, "B8"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_UP, "B9"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_DOWN, "B10"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_SELECT, "B11"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_START, "B12"); + } else if (nes_input.type[port] == DEVICE_SIFC_QUIZKING) { + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_B, "B1"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_A, "B2"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_Y, "B3"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_X, "B4"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_L, "B5"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_R, "B6"); + } else if (nes_input.type[port] == DEVICE_SI_VIRTUALBOY) { + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_B, "Right D-Pad Down"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_Y, "Right D-Pad Left"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_START, "Start"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_UP, "Left D-Pad Up"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_DOWN, "Left D-Pad Down"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left D-Pad Left"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Left D-Pad Right"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_A, "Right D-Pad Right"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_X, "Right D-Pad Up"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_L, "Left Trigger"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_R, "Right Trigger"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_L2, "B"); + addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_R2, "A"); + } + } + + environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc); +} + +static const unsigned powerpad_map[] = { + RETRO_DEVICE_ID_JOYPAD_B, + RETRO_DEVICE_ID_JOYPAD_A, + RETRO_DEVICE_ID_JOYPAD_Y, + RETRO_DEVICE_ID_JOYPAD_X, + RETRO_DEVICE_ID_JOYPAD_L, + RETRO_DEVICE_ID_JOYPAD_R, + RETRO_DEVICE_ID_JOYPAD_LEFT, + RETRO_DEVICE_ID_JOYPAD_RIGHT, + RETRO_DEVICE_ID_JOYPAD_UP, + RETRO_DEVICE_ID_JOYPAD_DOWN, + RETRO_DEVICE_ID_JOYPAD_SELECT, + RETRO_DEVICE_ID_JOYPAD_START, +}; + +static const unsigned ftrainer_map[] = { + RETRO_DEVICE_ID_JOYPAD_B, + RETRO_DEVICE_ID_JOYPAD_A, + RETRO_DEVICE_ID_JOYPAD_Y, + RETRO_DEVICE_ID_JOYPAD_X, + RETRO_DEVICE_ID_JOYPAD_L, + RETRO_DEVICE_ID_JOYPAD_R, + RETRO_DEVICE_ID_JOYPAD_LEFT, + RETRO_DEVICE_ID_JOYPAD_RIGHT, + RETRO_DEVICE_ID_JOYPAD_UP, + RETRO_DEVICE_ID_JOYPAD_DOWN, + RETRO_DEVICE_ID_JOYPAD_SELECT, + RETRO_DEVICE_ID_JOYPAD_START, +}; + +static const unsigned quizking_map[] = { + RETRO_DEVICE_ID_JOYPAD_B, + RETRO_DEVICE_ID_JOYPAD_A, + RETRO_DEVICE_ID_JOYPAD_Y, + RETRO_DEVICE_ID_JOYPAD_X, + RETRO_DEVICE_ID_JOYPAD_L, + RETRO_DEVICE_ID_JOYPAD_R, +}; + +static uint32 update_PowerPad(int w) { + int x; + uint32 r = 0; + + for (x = 0; x < 12; x++) + r |= input_cb(w, RETRO_DEVICE_JOYPAD, 0, powerpad_map[x]) ? (1 << x) : 0; + + return r; +} + +static void update_FTrainer(void) { + int x; + uint32 r = 0; + + for (x = 0; x < 12; x++) + r |= input_cb(4, RETRO_DEVICE_JOYPAD, 0, ftrainer_map[x]) ? (1 << x) : 0; + + nes_input.FTrainerData = r; +} + +static void update_QuizKing(void) { + int x; + uint8 r = 0; + + for (x = 0; x < 6; x++) + r |= input_cb(4, RETRO_DEVICE_JOYPAD, 0, quizking_map[x]) ? (1 << x) : 0; + + nes_input.QuizKingData = r; +} + +static void update_HyperShotPad(void) { + static int toggle; + int i; + + nes_input.FamicomData[0] = 0; + toggle ^= 1; + for (i = 0; i < 2; i++) { + if (input_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B)) + nes_input.FamicomData[0] |= 0x02 << (i * 2); + else if (input_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y)) { + if (toggle) + nes_input.FamicomData[0] |= 0x02 << (i * 2); + else + nes_input.FamicomData[0] &= ~(0x02 << (i * 2)); + } + if (input_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A)) + nes_input.FamicomData[0] |= 0x04 << (i * 2); + else if (input_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X)) { + if (toggle) + nes_input.FamicomData[0] |= 0x04 << (i * 2); + else + nes_input.FamicomData[0] &= ~(0x04 << (i * 2)); + } + } +} + +static void update_Arkanoid(int port, enum RetroArkanoidInputModes mode, uint32_t *data) { + static int mzx = 0, mzy = 0; + int _x, _y, _pressed; + + data[2] = 0; + + switch (mode) { + case RetroArkanoidMouse: + mzx += (int)((double)nes_input.mouseSensitivity * + (double)input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X) / 100.0); + mzy += (int)((double)nes_input.mouseSensitivity * + (double)input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y) / 100.0); + + if (mzx < 0) + mzx = 0; + else if (mzx > 240) + mzx = 240; + + if (mzy < 0) + mzy = 0; + else if (mzy > NES_HEIGHT) + mzy = NES_HEIGHT; + + data[0] = mzx; + data[1] = mzy; + + if (input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT)) + data[2] |= 0x1; + if (input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_RIGHT)) + data[2] |= 0x2; + break; + + case RetroArkanoidAbsMouse: + case RetroArkanoidPointer: + _x = input_cb(port, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X); + _y = input_cb(port, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y); + + if (_x != 0 || _y != 0) { + int32 raw = (_x + 0x7FFF) * NES_WIDTH / (0x7FFF * 2); + if (nes_input.arkanoidMode == RetroArkanoidAbsMouse) { + /* remap so full screen movement ends up within the encoder range 0-240 */ + /* game board: 176 wide */ + /* paddle: 32 */ + /* range of movement: 176-32 = 144 */ + /* left edge: 16 */ + /* right edge: 64 */ + + /* increase movement by 10 to allow edges to be reached in case of problems */ + raw = (raw - 128) * 140 / 128 + 128; + if (raw < 0) + raw = 0; + else if (raw > 255) + raw = 255; + + data[0] = raw * 240 / 255; + } else { + /* remap so full board movement ends up within the encoder range 0-240 */ + if (data[0] < 16 + (32 / 2)) + data[0] = 0; + else + data[0] -= 16 + (32 / 2); + if (data[0] > 144) + data[0] = 144; + data[0] = raw * 240 / 144; + } + } + + if (input_cb(port, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED)) + data[2] |= 0x1; + + break; + + case RetroArkanoidStelladaptor: + _x = input_cb(port, RETRO_DEVICE_ANALOG, 0, RETRO_DEVICE_ID_ANALOG_X); + _pressed = input_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A) | + input_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B); + + data[0] = (_x + 32768) * 240 / 65535; + + if (_pressed) + data[2] |= 0x1; + + break; + } +} + +static void update_Zapper(unsigned port, enum RetroZapperInputModes mode, uint32_t *data) { + static int mzx = 0, mzy = 0; + int _x, _y; + + data[2] = 0; /* reset click state */ + + switch (mode) { + case RetroMouse: /* mouse device */ + /* TODO: Add some sort of mouse sensitivity */ + mzx += (int)((double)nes_input.mouseSensitivity * + (double)input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X) / 100.0); + mzy += (int)((double)nes_input.mouseSensitivity * + (double)input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y) / 100.0); + + /* Set crosshair within the limits of current screen resolution */ + if (mzx < 0) + mzx = 0; + else if (mzx > NES_WIDTH) + mzx = NES_WIDTH; + + if (mzy < 0) + mzy = 0; + else if (mzy > NES_HEIGHT) + mzy = NES_HEIGHT; + + data[0] = mzx; + data[1] = mzy; + + if (input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT)) + data[2] |= 0x1; + if (input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_RIGHT)) + data[2] |= 0x2; + break; + + case RetroPointer: + _x = input_cb(port, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X); + _y = input_cb(port, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y); + + if (_x == 0 && _y == 0) { + data[0] = 0; + data[1] = 0; + } else { + data[0] = (_x + 0x7FFF) * NES_WIDTH / (0x7FFF * 2); + data[1] = (_y + 0x7FFF) * NES_HEIGHT / (0x7FFF * 2); + } + + if (input_cb(port, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED)) + data[2] |= 0x1; + break; + + case RetroLightgun: /* crosshair lightgun device */ + { + int offscreen = input_cb(port, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN); + int offscreen_shot = input_cb(port, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_RELOAD); + int trigger = input_cb(port, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_TRIGGER); + + if (offscreen || offscreen_shot) { + data[0] = 0; + data[1] = 0; + } else { + int _x = input_cb(port, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X); + int _y = input_cb(port, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y); + + data[0] = (_x + 0x7FFF) * NES_WIDTH / (0x7FFF * 2); + data[1] = (_y + 0x7FFF) * NES_HEIGHT / (0x7FFF * 2); + } + + if (trigger || offscreen_shot) + data[2] |= 0x1; + + break; + } + + case RetroSTLightgun: /* Sequential targets lightgun device integration */ + data[2] = input_cb(port, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_TRIGGER); + data[3] = input_cb(port, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_AUX_A); + break; + } +} + +void input_update(retro_input_state_t *_input_cb) { + unsigned player, port; + bool palette_prev = false; + bool palette_next = false; + + input_cb = *_input_cb; + + /* Reset input states */ + nes_input.JSReturn = 0; + + /* nes gamepad */ + for (player = 0; player < MAX_CONTROLLERS; player++) { + int i = 0; + uint8_t input_buf = 0; + bool player_enabled = + (nes_input.type[player] == DEVICE_SI_GAMEPAD) || (nes_input.type[player] == RETRO_DEVICE_JOYPAD); + + if (player_enabled) { + int16_t ret = 0; + bool dpad_enabled = true; + static int last_pressed_keys = 0; + + if (libretro_supports_bitmasks) { + ret = input_cb(player, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_MASK); + } else { + for (i = 0; i <= RETRO_DEVICE_ID_JOYPAD_R3; i++) + ret |= input_cb(player, RETRO_DEVICE_JOYPAD, 0, i) ? (1 << i) : 0; + } + + /* If palette switching is enabled, check if + * player 1 has the L2 button held down */ + if ((player == 0) && palette_switch_enabled && (ret & (1 << RETRO_DEVICE_ID_JOYPAD_L2))) { + /* D-Pad left/right are used to switch palettes */ + palette_prev = (bool)(ret & (1 << RETRO_DEVICE_ID_JOYPAD_LEFT)); + palette_next = (bool)(ret & (1 << RETRO_DEVICE_ID_JOYPAD_RIGHT)); + + /* Regular D-Pad input is disabled */ + dpad_enabled = false; + } + + 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 (dpad_enabled) { + 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; + } + + if (player == 0) { + if (!(last_pressed_keys & (1 << RETRO_DEVICE_ID_JOYPAD_L3)) && (ret & (1 << RETRO_DEVICE_ID_JOYPAD_L3))) + FSettings.ReplaceP2StartWithMicrophone = !FSettings.ReplaceP2StartWithMicrophone; + last_pressed_keys = ret; + } + + /* Turbo A and Turbo B buttons are + * mapped to Joypad X and Joypad Y + * in RetroArch joypad. + * + * We achieve this by keeping track of + * the number of times it increments + * the toggle counter and fire or not fire + * depending on whether the delay value has + * been reached. + * + * Each turbo button is activated by + * corresponding mapped button + * OR mapped Turbo A+B button. + * This allows Turbo A+B button to use + * the same toggle counters as Turbo A + * and Turbo B buttons use separately. + */ + + if (nes_input.turbo_enabled[player]) { + /* Handle Turbo A, B & A+B buttons */ + for (i = 0; i < TURBO_BUTTONS; i++) { + if (input_cb(player, RETRO_DEVICE_JOYPAD, 0, turbomap[i].retro)) { + if (!turbo_button_toggle[player][i]) + input_buf |= turbomap[i].nes; + turbo_button_toggle[player][i]++; + turbo_button_toggle[player][i] %= nes_input.turbo_delay + 1; + } else + /* If the button is not pressed, just reset the toggle */ + turbo_button_toggle[player][i] = 0; + } + } + } + + if (!nes_input.allow_updown_leftright) { + if ((input_buf & JOY_UP) && (input_buf & JOY_DOWN)) + input_buf &= ~(JOY_UP | JOY_DOWN); + if ((input_buf & JOY_LEFT) && (input_buf & JOY_RIGHT)) + input_buf &= ~(JOY_LEFT | JOY_RIGHT); + } + + nes_input.JSReturn |= (input_buf & 0xff) << (player << 3); + } + + /* other inputs*/ + for (port = 0; port < MAX_PORTS; port++) { + int device = nes_input.type[port]; + + switch (device) { + case DEVICE_SI_SNESMOUSE: { + int dx = input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X); + int dy = input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y); + int mb = ((input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT) ? 1 : 0) | + (input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_RIGHT) ? 2 : 0)); + nes_input.MouseData[port][0] = dx; + nes_input.MouseData[port][1] = dy; + nes_input.MouseData[port][2] = mb; + } break; + case DEVICE_SI_ARKANOID: + update_Arkanoid(port, nes_input.arkanoidMode, nes_input.MouseData[port]); + break; + case DEVICE_SI_ZAPPER: + update_Zapper(port, nes_input.zapperMode, nes_input.MouseData[port]); + break; + case DEVICE_SI_POWERPADA: + case DEVICE_SI_POWERPADB: + nes_input.PowerPadData[port] = update_PowerPad(port); + break; + case DEVICE_SI_SNESGAMEPAD: + case DEVICE_SI_VIRTUALBOY: { + int i; + int ret = 0; + nes_input.JoyButtons[port] = 0; + for (i = 0; i <= RETRO_DEVICE_ID_JOYPAD_R3; i++) + ret |= input_cb(port, RETRO_DEVICE_JOYPAD, 0, i) ? (1 << i) : 0; + nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_UP)) ? JOY_UP : 0; + nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_DOWN)) ? JOY_DOWN : 0; + nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_LEFT)) ? JOY_LEFT : 0; + nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_RIGHT)) ? JOY_RIGHT : 0; + if (!nes_input.allow_updown_leftright) { + if ((nes_input.JoyButtons[port] & JOY_UP) && (nes_input.JoyButtons[port] & JOY_DOWN)) + nes_input.JoyButtons[port] &= ~(JOY_UP | JOY_DOWN); + if ((nes_input.JoyButtons[port] & JOY_LEFT) && (nes_input.JoyButtons[port] & JOY_RIGHT)) + nes_input.JoyButtons[port] &= ~(JOY_LEFT | JOY_RIGHT); + } + if (nes_input.type[port] == DEVICE_SI_SNESGAMEPAD) { + nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_B)) ? (1 << 0) : 0; + nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_Y)) ? (1 << 1) : 0; + nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_A)) ? (1 << 8) : 0; + nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_X)) ? (1 << 9) : 0; + nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_L)) ? (1 << 10) : 0; + nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_R)) ? (1 << 11) : 0; + } else if (nes_input.type[port] == DEVICE_SI_VIRTUALBOY) { +#define RIGHT_DPAD_DOWN (1 << 0) +#define RIGHT_DPAD_LEFT (1 << 1) +#define RIGHT_DPAD_RIGHT (1 << 8) +#define RIGHT_DPAD_UP (1 << 9) + nes_input.JoyButtons[port] |= + (ret & (1 << RETRO_DEVICE_ID_JOYPAD_B)) ? (1 << 0) : 0; /* Right D-pad Down */ + nes_input.JoyButtons[port] |= + (ret & (1 << RETRO_DEVICE_ID_JOYPAD_Y)) ? (1 << 1) : 0; /* Right D-pad Left */ + nes_input.JoyButtons[port] |= + (ret & (1 << RETRO_DEVICE_ID_JOYPAD_A)) ? (1 << 8) : 0; /* Right D-pad Right */ + nes_input.JoyButtons[port] |= + (ret & (1 << RETRO_DEVICE_ID_JOYPAD_X)) ? (1 << 9) : 0; /* Right D-pad Up */ + nes_input.JoyButtons[port] |= + (ret & (1 << RETRO_DEVICE_ID_JOYPAD_L)) ? (1 << 10) : 0; /* Rear Left Trigger */ + nes_input.JoyButtons[port] |= + (ret & (1 << RETRO_DEVICE_ID_JOYPAD_R)) ? (1 << 11) : 0; /* Rear Left Trigger */ + nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_L2)) ? (1 << 12) : 0; /* B */ + nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_R2)) ? (1 << 13) : 0; /* A */ + + if (!nes_input.allow_updown_leftright) { + if ((nes_input.JoyButtons[port] & RIGHT_DPAD_DOWN) && (nes_input.JoyButtons[port] & RIGHT_DPAD_UP)) + nes_input.JoyButtons[port] &= ~(RIGHT_DPAD_DOWN | RIGHT_DPAD_UP); + if ((nes_input.JoyButtons[port] & RIGHT_DPAD_LEFT) && + (nes_input.JoyButtons[port] & RIGHT_DPAD_RIGHT)) + nes_input.JoyButtons[port] &= ~(RIGHT_DPAD_LEFT | RIGHT_DPAD_RIGHT); + } +#undef RIGHT_DPAD_DOWN +#undef RIGHT_DPAD_LEFT +#undef RIGHT_DPAD_RIGHT +#undef RIGHT_DPAD_UP + } + + nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_SELECT)) ? JOY_SELECT : 0; + nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_START)) ? JOY_START : 0; + + } break; + default: + break; + } + } + + /* famicom inputs */ + switch (nes_input.type[4]) { + case DEVICE_SIFC_ARKANOID: + update_Arkanoid(0, nes_input.arkanoidMode, nes_input.FamicomData); + break; + case DEVICE_SIFC_OEKAKIDS: /* mouse device */ + case DEVICE_SIFC_SHADOW: + update_Zapper(0, nes_input.zapperMode, nes_input.FamicomData); + break; + case DEVICE_SIFC_FTRAINERA: + case DEVICE_SIFC_FTRAINERB: + update_FTrainer(); + break; + case DEVICE_SIFC_QUIZKING: + update_QuizKing(); + break; + case DEVICE_SIFC_HYPERSHOT: { + update_HyperShotPad(); + break; + } + } + + for (port = 0; port < 2; port++) { + if (input_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2)) + FCEUI_VSUniCoin(); /* Insert Coin VS System slot 1 */ + if (input_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2)) + FCEUI_VSUniCoin2(); /* Insert Coin VS System slot 2 */ + } + + if (GameInfo->type == GIT_FDS) /* Famicom Disk System */ + { + bool curL = input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L); + bool curR = input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R); + static bool prevL = false, prevR = false; + + if (curL && !prevL) + FCEUI_FDSSelect(); /* Swap FDisk side */ + prevL = curL; + + if (curR && !prevR) + FCEUI_FDSInsert(); /* Insert or eject the disk */ + prevR = curR; + } + + /* Handle internal palette switching */ + input_palette_switch(palette_next, palette_prev); + + /* Power Switch on F12 */ + if (input_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_F12)) { + FCEUI_PowerNES(); + } +} + +void input_init_env(retro_environment_t *_environ_cb) { + environ_cb = *_environ_cb; + environ_cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void *)ports); +} + +void input_set_controller_port_device(unsigned port, unsigned device) { + if (device == DEVICE_AUTO) { + if (port <= 1) { + switch (GameInfo->input[port]) { + case SI_GAMEPAD: + nes_input.type[port] = DEVICE_SI_GAMEPAD; + break; + case SI_ZAPPER: + nes_input.type[port] = DEVICE_SI_ZAPPER; + break; + case SI_ARKANOID: + nes_input.type[port] = DEVICE_SI_ARKANOID; + break; + case SI_POWERPADA: + nes_input.type[port] = DEVICE_SI_POWERPADA; + break; + case SI_POWERPADB: + nes_input.type[port] = DEVICE_SI_POWERPADB; + break; + case SI_SNES_GAMEPAD: + nes_input.type[port] = DEVICE_SI_SNESGAMEPAD; + break; + case SI_SNES_MOUSE: + nes_input.type[port] = DEVICE_SI_SNESMOUSE; + break; + case SI_VIRTUALBOY: + nes_input.type[port] = DEVICE_SI_VIRTUALBOY; + break; + default: + case SI_UNSET: + case SI_NONE: + case SI_MOUSE: + /* unsupported devices */ + nes_input.type[port] = DEVICE_SI_GAMEPAD; + break; + } + } else if (port <= 3) { + if (!nes_input.enable_4player && + ((nes_input.type[4] == DEVICE_SIFC_4PLAYER) || + (nes_input.type[4] == DEVICE_SIFC_HORI4PLAYER) || + (iNESCart.InputTypes == 0x02))) { + nes_input.enable_4player = TRUE; + } + if (nes_input.enable_4player) { + nes_input.type[port] = DEVICE_SI_GAMEPAD; + } else { + nes_input.type[port] = RETRO_DEVICE_NONE; + } + } else { + /* famicom expansion port */ + switch (GameInfo->inputfc) { + case SIFC_UNSET: + case SIFC_NONE: + nes_input.type[4] = RETRO_DEVICE_NONE; + break; + case SIFC_ARKANOID: + nes_input.type[4] = DEVICE_SI_ARKANOID; + break; + case SIFC_SHADOW: + nes_input.type[4] = DEVICE_SIFC_SHADOW; + break; + case SIFC_4PLAYER: + nes_input.type[4] = DEVICE_SIFC_4PLAYER; + break; + case SIFC_HORI4PLAYER: + nes_input.type[4] = DEVICE_SIFC_HORI4PLAYER; + break; + case SIFC_HYPERSHOT: + nes_input.type[4] = DEVICE_SIFC_HYPERSHOT; + break; + case SIFC_OEKAKIDS: + nes_input.type[4] = DEVICE_SIFC_OEKAKIDS; + break; + case SIFC_FTRAINERA: + nes_input.type[4] = DEVICE_SIFC_FTRAINERA; + break; + case SIFC_FTRAINERB: + nes_input.type[4] = DEVICE_SIFC_FTRAINERB; + break; + case SIFC_QUIZKING: + nes_input.type[4] = DEVICE_SIFC_QUIZKING; + break; + default: + /* unsupported input device */ + nes_input.type[4] = RETRO_DEVICE_NONE; + break; + } + } + } else { + nes_input.type[port] = device; + } + + set_input(port); + + nes_input.needs_update = true; +} + +void input_set_defaults(void) { + int i; + for (i = 0; i < MAX_PORTS; i++) { + FCEUI_SetInput(i, SI_GAMEPAD, &nes_input.JSReturn, 0); + nes_input.type[i] = RETRO_DEVICE_JOYPAD; + } + + FCEUI_SetInputFourScore(FALSE); + + for (i = 0; i < fourscore_len; i++) { + if (fourscore_db_list[i].crc == iNESCart.CRC32) { + FCEUI_SetInputFourScore(TRUE); + nes_input.enable_4player = true; + FCEU_printf(" NES Four Score compatible game found.\n"); + FCEU_printf(" Name: %s\n", fourscore_db_list[i].title); + break; + } + } + + for (i = 0; i < famicom_4p_len; i++) { + if (famicom_4p_db_list[i].crc == iNESCart.CRC32) { + GameInfo->inputfc = SIFC_4PLAYER; + FCEUI_SetInputFC(SIFC_4PLAYER, &nes_input.JSReturn, 0); + nes_input.enable_4player = true; + FCEU_printf(" Famicom 4-Player Adaptor compatible game found.\n"); + FCEU_printf(" Name: %s\n", famicom_4p_db_list[i].title); + break; + } + } +} + +void input_allow_updown_leftright(bool value) { + nes_input.allow_updown_leftright = value; +} + +void input_set_zapper_mode(enum RetroZapperInputModes value) { + nes_input.zapperMode = value; +} + +void input_set_arkanoid_mode(enum RetroArkanoidInputModes value) { + nes_input.arkanoidMode = value; +} + +void input_set_mousesensitivity(double value) { + nes_input.mouseSensitivity = value; +} + +void input_enable_turbo_buttons(int port, bool value) { + nes_input.turbo_enabled[port] = value; +} + +void input_set_turbo_delay(int value) { + nes_input.turbo_delay = value; +} diff --git a/libretro/libretro_input.h b/libretro/libretro_input.h new file mode 100644 index 000000000..8096d35a2 --- /dev/null +++ b/libretro/libretro_input.h @@ -0,0 +1,144 @@ +#ifndef __LIBRETRO_INPUT_H +#define __LIBRETRO_INPUT_H + +#include + +#define fourscore_len (int)(sizeof(fourscore_db_list) / sizeof(fourscore_db_list[0])) +#define famicom_4p_len (int)(sizeof(famicom_4p_db_list) / sizeof(famicom_4p_db_list[0])) + +typedef struct cartridge_db { + uint32_t crc; + char title[256]; +} cartridge_db_t; + +static const struct cartridge_db fourscore_db_list[] = { + { 0x1EBB5B42, "Bomberman II (USA)" }, +#if 0 + { 0xeac38105, "Championship Bowling (USA)" }, +#endif + { 0xF99E37EB, "Chris Evert & Ivan Lendl in Top Players' Tennis (USA)" }, +#if 0 + { "Crash 'n' the Boys - Street Challenge (USA)", 0xc7f0c457 }, +#endif + { 0x48B8EE58, "Four Players' Tennis (Europe)" }, + { 0x27CA0679, "Danny Sullivan's Indy Heat (Europe)" }, + { 0x79F688BC, "Gauntlet II (Europe)" }, + { 0x1B71CCDB, "Gauntlet II (USA)" }, + { 0x1352F1B9, "Greg Norman's Golf Power (USA)" }, + { 0x2E6EE98D, "Harlem Globetrotters (USA)" }, + { 0x05104517, "Ivan 'Ironman' Stewart's Super Off Road (Europe)" }, + { 0x4B041B6B, "Ivan 'Ironman' Stewart's Super Off Road (USA)" }, + { 0xF54B34BD, "Kings of the Beach - Professional Beach Volleyball (USA)" }, + { 0xC6C2EDB5, "Magic Johnson's Fast Break (USA)" }, + { 0x0939852F, "M.U.L.E. (USA)" }, + { 0x4E6B9078, "Micro Mages" }, + { 0x2F698C4D, "Monster Truck Rally (USA)" }, + { 0xB9B4D9E0, "NES Play Action Football (USA)" }, + { 0xDA2CB59A, "Nightmare on Elm Street, A (USA)" }, + { 0x8DA6667D, "Nintendo World Cup (Europe)" }, + { 0x7C16F819, "Nintendo World Cup (Europe) (Rev A)" }, + { 0x7F08D0D9, "Nintendo World Cup (Europe) (Rev B)" }, + { 0xA22657FA, "Nintendo World Cup (USA)" }, + { 0x308DA987, "R.C. Pro-Am II (Europe)" }, + { 0x9EDD2159, "R.C. Pro-Am II (USA)" }, + { 0x8FA6E92C, "Rackets & Rivals (Europe)" }, + { 0xAD0394F0, "Roundball - 2-on-2 Challenge (Europe)" }, + { 0x6E4DCFD2, "Roundball - 2-on-2 Challenge (USA)" }, + { 0x0ABDD5CA, "Spot - The Video Game (Japan)" }, + { 0xCFAE9DFA, "Spot - The Video Game (USA)" }, + { 0x0B8F8128, "Smash T.V. (Europe)" }, + { 0x6EE94D32, "Smash T.V. (USA)" }, + { 0xCF4487A2, "Super Jeopardy! (USA)" }, + { 0xC05A63B2, "Super Spike V'Ball (Europe)" }, + { 0xE840FD21, "Super Spike V'Ball (USA)" }, + { 0x407D6FFD, "Super Spike V'Ball + Nintendo World Cup (USA)" }, + { 0xD153CAF6, "Swords and Serpents (Europe)" }, + { 0x46135141, "Swords and Serpents (France)" }, + { 0x3417EC46, "Swords and Serpents (USA)" }, + { 0x69977C9E, "Battle City (Japan) (4 Players Hack) http://www.romhacking.net/hacks/2142/" }, + { 0x2DA5ECE0, "Bomberman 3 (Homebrew) http://tempect.de/senil/games.html" }, + { 0x90D2E9F0, "K.Y.F.F. (Homebrew) http://slydogstudios.org/index.php/k-y-f-f/" }, + { 0x1394DED0, "Super PakPak (Homebrew) http://wiki.nesdev.com/w/index.php/Super_PakPak" }, + { 0x73298C87, "Super Mario Bros. + Tetris + Nintendo World Cup (Europe)" }, + { 0xF46EF39A, "Super Mario Bros. + Tetris + Nintendo World Cup (Europe) (Rev A)" }, +}; + +static const struct cartridge_db famicom_4p_db_list[] = { + { 0xC39B3BB2, "Bakutoushi Patton-Kun (Japan) (FDS)" }, + { 0x0C401790, "Bomber Man II (Japan)" }, + { 0x9992F445, "Championship Bowling (Japan)" }, + { 0x3E470FE0, "Downtown - Nekketsu Koushinkyoku - Soreyuke Daiundoukai (Japan)" }, + { 0x4F032933, "Ike Ike! Nekketsu Hockey-bu - Subette Koronde Dairantou (Japan)" }, + { 0x4B5177E9, "Kunio-kun no Nekketsu Soccer League (Japan)" }, + { 0x9F03B11F, "Moero TwinBee - Cinnamon Hakase o Sukue! (Japan)" }, + { 0x13205221, "Moero TwinBee - Cinnamon Hakase wo Sukue! (Japan) (FDS)" }, + { 0x37E24797, "Nekketsu Kakutou Densetsu (Japan)" }, + { 0x62C67984, "Nekketsu Koukou Dodgeball-bu (Japan)" }, + { 0x88062D9A, "Nekketsu! Street Basket - Ganbare Dunk Heroes (Japan)" }, + { 0x689971F9, "Super Dodge Ball (USA) (3-4p with Game Genie code GEUOLZZA)" }, + { 0x4FF17864, "Super Dodge Ball (USA) (patched) http://www.romhacking.net/hacks/71/" }, + { 0x213CB3FB, "U.S. Championship V'Ball (Japan)" }, + { 0xD7077D96, "U.S. Championship V'Ball (Japan) (Beta)" }, + { 0xB1B16B8A, "Wit's (Japan)" }, +}; + +#define MAX_CONTROLLERS 4 /* max supported players */ +#define MAX_PORTS 2 /* max controller ports. port 0 for player 1/3, port 1 for player 2/4 */ + +enum RetroZapperInputModes { + RetroLightgun, + RetroSTLightgun, + RetroMouse, + RetroPointer +}; + +enum RetroArkanoidInputModes { + RetroArkanoidMouse, + RetroArkanoidPointer, + RetroArkanoidAbsMouse, + RetroArkanoidStelladaptor +}; + +typedef struct NES_INPUT_T { + bool enable_4player; /* four-score / 4-player adapter used */ + bool allow_updown_leftright; /* disabled simultaneous up+down and left+right dpad combinations */ + bool needs_update; + + /* turbo related */ + bool turbo_enabled[MAX_CONTROLLERS]; + int turbo_delay; + + int type[MAX_CONTROLLERS + 1]; /* 4-players + famicom expansion */ + + /* input data */ + uint32_t JSReturn; /* player input data, 1 byte per player (1-4) */ + uint32_t JoyButtons[2]; + uint32_t MouseData[MAX_PORTS][4]; /* nes mouse data */ + uint32_t FamicomData[3]; /* Famicom expansion port data */ + uint32_t PowerPadData[2]; /* NES Power Pad data */ + uint32_t FTrainerData; /* Expansion: Family Trainer Data */ + uint8_t QuizKingData; /* Expansion: Quiz King Data */ + + enum RetroZapperInputModes zapperMode; + enum RetroArkanoidInputModes arkanoidMode; + double mouseSensitivity; +} NES_INPUT_T; + +void input_init_env(retro_environment_t *_environ_cb); +void input_set_controller_port_device(unsigned port, unsigned device); +void input_update_descriptors(void); +void input_update(retro_input_state_t *input_cb); +void input_set_defaults(void); +void input_palette_switch(bool, bool); + +void input_allow_updown_leftright(bool); +void input_set_zapper_mode(enum RetroZapperInputModes mode); +void input_set_arkanoid_mode(enum RetroArkanoidInputModes mode); +void input_set_mousesensitivity(double value); +void input_enable_turbo_buttons(int port, bool enable); +void input_set_turbo_delay(int value); + +extern bool libretro_supports_bitmasks; +extern bool palette_switch_enabled; + +#endif /* __LIBRETRO_INPUT_H */ \ No newline at end of file diff --git a/src/drivers/libretro/link.T b/libretro/link.T similarity index 100% rename from src/drivers/libretro/link.T rename to libretro/link.T diff --git a/libretro/paldef.h b/libretro/paldef.h new file mode 100644 index 000000000..96f2ad471 --- /dev/null +++ b/libretro/paldef.h @@ -0,0 +1,305 @@ +#ifndef _PALDEF_H +#define _PALDEF_H + +#define PALETTE_COUNT (int)(sizeof(palettes) / sizeof(palettes[0])) /* Number of palettes in palettes[] */ +#define PALETTE_INTERNAL (PALETTE_COUNT + 1) +#define PALETTE_RAW (PALETTE_COUNT + 2) +#define PALETTE_CUSTOM (PALETTE_COUNT + 3) +#define PALETTE_TOTAL_COUNT PALETTE_CUSTOM + +struct st_palettes { + char name[32]; + char desc[32]; + pal data[64]; +}; + +static struct st_palettes palettes[] = { + { "asqrealc", "AspiringSquire's Real palette", { + { 0x6C, 0x6C, 0x6C }, { 0x00, 0x26, 0x8E }, { 0x00, 0x00, 0xA8 }, { 0x40, 0x00, 0x94 }, + { 0x70, 0x00, 0x70 }, { 0x78, 0x00, 0x40 }, { 0x70, 0x00, 0x00 }, { 0x62, 0x16, 0x00 }, + { 0x44, 0x24, 0x00 }, { 0x34, 0x34, 0x00 }, { 0x00, 0x50, 0x00 }, { 0x00, 0x44, 0x44 }, + { 0x00, 0x40, 0x60 }, { 0x00, 0x00, 0x00 }, { 0x10, 0x10, 0x10 }, { 0x10, 0x10, 0x10 }, + + { 0xBA, 0xBA, 0xBA }, { 0x20, 0x5C, 0xDC }, { 0x38, 0x38, 0xFF }, { 0x80, 0x20, 0xF0 }, + { 0xC0, 0x00, 0xC0 }, { 0xD0, 0x14, 0x74 }, { 0xD0, 0x20, 0x20 }, { 0xAC, 0x40, 0x14 }, + { 0x7C, 0x54, 0x00 }, { 0x58, 0x64, 0x00 }, { 0x00, 0x88, 0x00 }, { 0x00, 0x74, 0x68 }, + { 0x00, 0x74, 0x9C }, { 0x20, 0x20, 0x20 }, { 0x10, 0x10, 0x10 }, { 0x10, 0x10, 0x10 }, + + { 0xFF, 0xFF, 0xFF }, { 0x4C, 0xA0, 0xFF }, { 0x88, 0x88, 0xFF }, { 0xC0, 0x6C, 0xFF }, + { 0xFF, 0x50, 0xFF }, { 0xFF, 0x64, 0xB8 }, { 0xFF, 0x78, 0x78 }, { 0xFF, 0x96, 0x38 }, + { 0xDB, 0xAB, 0x00 }, { 0xA2, 0xCA, 0x20 }, { 0x4A, 0xDC, 0x4A }, { 0x2C, 0xCC, 0xA4 }, + { 0x1C, 0xC2, 0xEA }, { 0x58, 0x58, 0x58 }, { 0x10, 0x10, 0x10 }, { 0x10, 0x10, 0x10 }, + + { 0xFF, 0xFF, 0xFF }, { 0xB0, 0xD4, 0xFF }, { 0xC4, 0xC4, 0xFF }, { 0xE8, 0xB8, 0xFF }, + { 0xFF, 0xB0, 0xFF }, { 0xFF, 0xB8, 0xE8 }, { 0xFF, 0xC4, 0xC4 }, { 0xFF, 0xD4, 0xA8 }, + { 0xFF, 0xE8, 0x90 }, { 0xF0, 0xF4, 0xA4 }, { 0xC0, 0xFF, 0xC0 }, { 0xAC, 0xF4, 0xF0 }, + { 0xA0, 0xE8, 0xFF }, { 0xC2, 0xC2, 0xC2 }, { 0x20, 0x20, 0x20 }, { 0x10, 0x10, 0x10 } + } + }, + { "nintendo-vc", "Virtual Console palette", { + { 0x49, 0x49, 0x49 }, { 0x00, 0x00, 0x6A }, { 0x09, 0x00, 0x63 }, { 0x29, 0x00, 0x59 }, + { 0x42, 0x00, 0x4A }, { 0x49, 0x00, 0x00 }, { 0x42, 0x00, 0x00 }, { 0x29, 0x11, 0x00 }, + { 0x18, 0x27, 0x00 }, { 0x00, 0x30, 0x10 }, { 0x00, 0x30, 0x00 }, { 0x00, 0x29, 0x10 }, + { 0x01, 0x20, 0x43 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0x74, 0x71, 0x74 }, { 0x00, 0x30, 0x84 }, { 0x31, 0x01, 0xAC }, { 0x4B, 0x01, 0x94 }, + { 0x64, 0x00, 0x7B }, { 0x6B, 0x00, 0x39 }, { 0x6B, 0x21, 0x01 }, { 0x5A, 0x2F, 0x00 }, + { 0x42, 0x49, 0x00 }, { 0x18, 0x59, 0x01 }, { 0x10, 0x59, 0x01 }, { 0x01, 0x59, 0x32 }, + { 0x01, 0x49, 0x5A }, { 0x10, 0x10, 0x10 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xAD, 0xAD, 0xAD }, { 0x4A, 0x71, 0xB6 }, { 0x64, 0x58, 0xD5 }, { 0x84, 0x50, 0xE6 }, + { 0xA4, 0x51, 0xAD }, { 0xAD, 0x49, 0x84 }, { 0xB5, 0x62, 0x4A }, { 0x94, 0x71, 0x32 }, + { 0x7B, 0x72, 0x2A }, { 0x5A, 0x86, 0x01 }, { 0x38, 0x8E, 0x31 }, { 0x31, 0x8E, 0x5A }, + { 0x39, 0x8E, 0x8D }, { 0x38, 0x38, 0x38 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xB6, 0xB6, 0xB6 }, { 0x8C, 0x9D, 0xB5 }, { 0x8D, 0x8E, 0xAE }, { 0x9C, 0x8E, 0xBC }, + { 0xA6, 0x87, 0xBC }, { 0xAD, 0x8D, 0x9D }, { 0xAE, 0x96, 0x8C }, { 0x9C, 0x8F, 0x7C }, + { 0x9C, 0x9E, 0x72 }, { 0x94, 0xA6, 0x7C }, { 0x84, 0xA7, 0x7B }, { 0x7C, 0x9D, 0x84 }, + { 0x73, 0x96, 0x8D }, { 0xDE, 0xDE, 0xDE }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 } + } + }, + { "rgb", "Nintendo RGB PPU palette", { + { 0x6D, 0x6D, 0x6D }, { 0x00, 0x24, 0x92 }, { 0x00, 0x00, 0xDB }, { 0x6D, 0x49, 0xDB }, + { 0x92, 0x00, 0x6D }, { 0xB6, 0x00, 0x6D }, { 0xB6, 0x24, 0x00 }, { 0x92, 0x49, 0x00 }, + { 0x6D, 0x49, 0x00 }, { 0x24, 0x49, 0x00 }, { 0x00, 0x6D, 0x24 }, { 0x00, 0x92, 0x00 }, + { 0x00, 0x49, 0x49 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xB6, 0xB6, 0xB6 }, { 0x00, 0x6D, 0xDB }, { 0x00, 0x49, 0xFF }, { 0x92, 0x00, 0xFF }, + { 0xB6, 0x00, 0xFF }, { 0xFF, 0x00, 0x92 }, { 0xFF, 0x00, 0x00 }, { 0xDB, 0x6D, 0x00 }, + { 0x92, 0x6D, 0x00 }, { 0x24, 0x92, 0x00 }, { 0x00, 0x92, 0x00 }, { 0x00, 0xB6, 0x6D }, + { 0x00, 0x92, 0x92 }, { 0x24, 0x24, 0x24 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xFF, 0xFF, 0xFF }, { 0x6D, 0xB6, 0xFF }, { 0x92, 0x92, 0xFF }, { 0xDB, 0x6D, 0xFF }, + { 0xFF, 0x00, 0xFF }, { 0xFF, 0x6D, 0xFF }, { 0xFF, 0x92, 0x00 }, { 0xFF, 0xB6, 0x00 }, + { 0xDB, 0xDB, 0x00 }, { 0x6D, 0xDB, 0x00 }, { 0x00, 0xFF, 0x00 }, { 0x49, 0xFF, 0xDB }, + { 0x00, 0xFF, 0xFF }, { 0x49, 0x49, 0x49 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xFF, 0xFF, 0xFF }, { 0xB6, 0xDB, 0xFF }, { 0xDB, 0xB6, 0xFF }, { 0xFF, 0xB6, 0xFF }, + { 0xFF, 0x92, 0xFF }, { 0xFF, 0xB6, 0xB6 }, { 0xFF, 0xDB, 0x92 }, { 0xFF, 0xFF, 0x49 }, + { 0xFF, 0xFF, 0x6D }, { 0xB6, 0xFF, 0x49 }, { 0x92, 0xFF, 0x6D }, { 0x49, 0xFF, 0xDB }, + { 0x92, 0xDB, 0xFF }, { 0x92, 0x92, 0x92 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 } + } + }, + { "sony-cxa2025as-us", "Sony CXA2025AS US palette", { + { 0x58, 0x58, 0x58 }, { 0x00, 0x23, 0x8C }, { 0x00, 0x13, 0x9B }, { 0x2D, 0x05, 0x85 }, + { 0x5D, 0x00, 0x52 }, { 0x7A, 0x00, 0x17 }, { 0x7A, 0x08, 0x00 }, { 0x5F, 0x18, 0x00 }, + { 0x35, 0x2A, 0x00 }, { 0x09, 0x39, 0x00 }, { 0x00, 0x3F, 0x00 }, { 0x00, 0x3C, 0x22 }, + { 0x00, 0x32, 0x5D }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xA1, 0xA1, 0xA1 }, { 0x00, 0x53, 0xEE }, { 0x15, 0x3C, 0xFE }, { 0x60, 0x28, 0xE4 }, + { 0xA9, 0x1D, 0x98 }, { 0xD4, 0x1E, 0x41 }, { 0xD2, 0x2C, 0x00 }, { 0xAA, 0x44, 0x00 }, + { 0x6C, 0x5E, 0x00 }, { 0x2D, 0x73, 0x00 }, { 0x00, 0x7D, 0x06 }, { 0x00, 0x78, 0x52 }, + { 0x00, 0x69, 0xA9 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xFF, 0xFF, 0xFF }, { 0x1F, 0xA5, 0xFE }, { 0x5E, 0x89, 0xFE }, { 0xB5, 0x72, 0xFE }, + { 0xFE, 0x65, 0xF6 }, { 0xFE, 0x67, 0x90 }, { 0xFE, 0x77, 0x3C }, { 0xFE, 0x93, 0x08 }, + { 0xC4, 0xB2, 0x00 }, { 0x79, 0xCA, 0x10 }, { 0x3A, 0xD5, 0x4A }, { 0x11, 0xD1, 0xA4 }, + { 0x06, 0xBF, 0xFE }, { 0x42, 0x42, 0x42 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xFF, 0xFF, 0xFF }, { 0xA0, 0xD9, 0xFE }, { 0xBD, 0xCC, 0xFE }, { 0xE1, 0xC2, 0xFE }, + { 0xFE, 0xBC, 0xFB }, { 0xFE, 0xBD, 0xD0 }, { 0xFE, 0xC5, 0xA9 }, { 0xFE, 0xD1, 0x8E }, + { 0xE9, 0xDE, 0x86 }, { 0xC7, 0xE9, 0x92 }, { 0xA8, 0xEE, 0xB0 }, { 0x95, 0xEC, 0xD9 }, + { 0x91, 0xE4, 0xFE }, { 0xAC, 0xAC, 0xAC }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 } + } + }, + { "pal", "PAL palette", { + { 0x80, 0x80, 0x80 }, { 0x00, 0x00, 0xBA }, { 0x37, 0x00, 0xBF }, { 0x84, 0x00, 0xA6 }, + { 0xBB, 0x00, 0x6A }, { 0xB7, 0x00, 0x1E }, { 0xB3, 0x00, 0x00 }, { 0x91, 0x26, 0x00 }, + { 0x7B, 0x2B, 0x00 }, { 0x00, 0x3E, 0x00 }, { 0x00, 0x48, 0x0D }, { 0x00, 0x3C, 0x22 }, + { 0x00, 0x2F, 0x66 }, { 0x00, 0x00, 0x00 }, { 0x05, 0x05, 0x05 }, { 0x05, 0x05, 0x05 }, + + { 0xC8, 0xC8, 0xC8 }, { 0x00, 0x59, 0xFF }, { 0x44, 0x3C, 0xFF }, { 0xB7, 0x33, 0xCC }, + { 0xFE, 0x33, 0xAA }, { 0xFE, 0x37, 0x5E }, { 0xFE, 0x37, 0x1A }, { 0xD5, 0x4B, 0x00 }, + { 0xC4, 0x62, 0x00 }, { 0x3C, 0x7B, 0x00 }, { 0x1D, 0x84, 0x15 }, { 0x00, 0x95, 0x66 }, + { 0x00, 0x84, 0xC4 }, { 0x11, 0x11, 0x11 }, { 0x09, 0x09, 0x09 }, { 0x09, 0x09, 0x09 }, + + { 0xFE, 0xFE, 0xFE }, { 0x00, 0x95, 0xFF }, { 0x6F, 0x84, 0xFF }, { 0xD5, 0x6F, 0xFF }, + { 0xFE, 0x77, 0xCC }, { 0xFE, 0x6F, 0x99 }, { 0xFE, 0x7B, 0x59 }, { 0xFE, 0x91, 0x5F }, + { 0xFE, 0xA2, 0x33 }, { 0xA6, 0xBF, 0x00 }, { 0x51, 0xD9, 0x6A }, { 0x4D, 0xD5, 0xAE }, + { 0x00, 0xD9, 0xFF }, { 0x66, 0x66, 0x66 }, { 0x0D, 0x0D, 0x0D }, { 0x0D, 0x0D, 0x0D }, + + { 0xFE, 0xFE, 0xFE }, { 0x84, 0xBF, 0xFF }, { 0xBB, 0xBB, 0xFF }, { 0xD0, 0xBB, 0xFF }, + { 0xFE, 0xBF, 0xEA }, { 0xFE, 0xBF, 0xCC }, { 0xFE, 0xC4, 0xB7 }, { 0xFE, 0xCC, 0xAE }, + { 0xFE, 0xD9, 0xA2 }, { 0xCC, 0xE1, 0x99 }, { 0xAE, 0xEE, 0xB7 }, { 0xAA, 0xF8, 0xEE }, + { 0xB3, 0xEE, 0xFF }, { 0xDD, 0xDD, 0xDD }, { 0x11, 0x11, 0x11 }, { 0x11, 0x11, 0x11 } + } + }, + { "bmf-final2", "BMF's Final 2 palette", { + { 0x52, 0x52, 0x52 }, { 0x00, 0x00, 0x80 }, { 0x08, 0x00, 0x8A }, { 0x2C, 0x00, 0x7E }, + { 0x4A, 0x00, 0x4E }, { 0x50, 0x00, 0x06 }, { 0x44, 0x00, 0x00 }, { 0x26, 0x08, 0x00 }, + { 0x0A, 0x20, 0x00 }, { 0x00, 0x2E, 0x00 }, { 0x00, 0x32, 0x00 }, { 0x00, 0x26, 0x0A }, + { 0x00, 0x1C, 0x48 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xA4, 0xA4, 0xA4 }, { 0x00, 0x38, 0xCE }, { 0x34, 0x16, 0xEC }, { 0x5E, 0x04, 0xDC }, + { 0x8C, 0x00, 0xB0 }, { 0x9A, 0x00, 0x4C }, { 0x90, 0x18, 0x00 }, { 0x70, 0x36, 0x00 }, + { 0x4C, 0x54, 0x00 }, { 0x0E, 0x6C, 0x00 }, { 0x00, 0x74, 0x00 }, { 0x00, 0x6C, 0x2C }, + { 0x00, 0x5E, 0x84 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xFF, 0xFF, 0xFF }, { 0x4C, 0x9C, 0xFF }, { 0x7C, 0x78, 0xFF }, { 0xA6, 0x64, 0xFF }, + { 0xDA, 0x5A, 0xFF }, { 0xF0, 0x54, 0xC0 }, { 0xF0, 0x6A, 0x56 }, { 0xD6, 0x86, 0x10 }, + { 0xBA, 0xA4, 0x00 }, { 0x76, 0xC0, 0x00 }, { 0x46, 0xCC, 0x1A }, { 0x2E, 0xC8, 0x66 }, + { 0x34, 0xC2, 0xBE }, { 0x3A, 0x3A, 0x3A }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xFF, 0xFF, 0xFF }, { 0xB6, 0xDA, 0xFF }, { 0xC8, 0xCA, 0xFF }, { 0xDA, 0xC2, 0xFF }, + { 0xF0, 0xBE, 0xFF }, { 0xFC, 0xBC, 0xEE }, { 0xFA, 0xC2, 0xC0 }, { 0xF2, 0xCC, 0xA2 }, + { 0xE6, 0xDA, 0x92 }, { 0xCC, 0xE6, 0x8E }, { 0xB8, 0xEE, 0xA2 }, { 0xAE, 0xEA, 0xBE }, + { 0xAE, 0xE8, 0xE2 }, { 0xB0, 0xB0, 0xB0 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 } + } + }, + { "bmf-final3", "BMF's Final 3 palette", { + { 0x68, 0x68, 0x68 }, { 0x00, 0x12, 0x99 }, { 0x1A, 0x08, 0xAA }, { 0x51, 0x02, 0x9A }, + { 0x7E, 0x00, 0x69 }, { 0x8E, 0x00, 0x1C }, { 0x7E, 0x03, 0x01 }, { 0x51, 0x18, 0x00 }, + { 0x1F, 0x37, 0x00 }, { 0x01, 0x4E, 0x00 }, { 0x00, 0x5A, 0x00 }, { 0x00, 0x50, 0x1C }, + { 0x00, 0x40, 0x61 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xB9, 0xB9, 0xB9 }, { 0x0C, 0x5C, 0xD7 }, { 0x50, 0x35, 0xF0 }, { 0x89, 0x19, 0xE0 }, + { 0xBB, 0x0C, 0xB3 }, { 0xCE, 0x0C, 0x61 }, { 0xC0, 0x2B, 0x0E }, { 0x95, 0x4D, 0x01 }, + { 0x61, 0x6F, 0x00 }, { 0x1F, 0x8B, 0x00 }, { 0x01, 0x98, 0x0C }, { 0x00, 0x93, 0x4B }, + { 0x00, 0x81, 0x9B }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xFF, 0xFF, 0xFF }, { 0x63, 0xB4, 0xFF }, { 0x9B, 0x91, 0xFF }, { 0xD3, 0x77, 0xFF }, + { 0xEF, 0x6A, 0xFF }, { 0xF9, 0x68, 0xC0 }, { 0xF9, 0x7D, 0x6C }, { 0xED, 0x9B, 0x2D }, + { 0xBD, 0xBD, 0x16 }, { 0x7C, 0xDA, 0x1C }, { 0x4B, 0xE8, 0x47 }, { 0x35, 0xE5, 0x91 }, + { 0x3F, 0xD9, 0xDD }, { 0x60, 0x60, 0x60 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xFF, 0xFF, 0xFF }, { 0xAC, 0xE7, 0xFF }, { 0xD5, 0xCD, 0xFF }, { 0xED, 0xBA, 0xFF }, + { 0xF8, 0xB0, 0xFF }, { 0xFE, 0xB0, 0xEC }, { 0xFD, 0xBD, 0xB5 }, { 0xF9, 0xD2, 0x8E }, + { 0xE8, 0xEB, 0x7C }, { 0xBB, 0xF3, 0x82 }, { 0x99, 0xF7, 0xA2 }, { 0x8A, 0xF5, 0xD0 }, + { 0x92, 0xF4, 0xF1 }, { 0xBE, 0xBE, 0xBE }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 } + } + }, + { "nescap", "RGBSource's NESCAP palette", { + { 0x64, 0x63, 0x65 }, { 0x00, 0x15, 0x80 }, { 0x1D, 0x00, 0x90 }, { 0x38, 0x00, 0x82 }, + { 0x56, 0x00, 0x5D }, { 0x5A, 0x00, 0x1A }, { 0x4F, 0x09, 0x00 }, { 0x38, 0x1B, 0x00 }, + { 0x1E, 0x31, 0x00 }, { 0x00, 0x3D, 0x00 }, { 0x00, 0x41, 0x00 }, { 0x00, 0x3A, 0x1B }, + { 0x00, 0x2F, 0x55 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xAF, 0xAD, 0xAF }, { 0x16, 0x4B, 0xCA }, { 0x47, 0x2A, 0xE7 }, { 0x6B, 0x1B, 0xDB }, + { 0x96, 0x17, 0xB0 }, { 0x9F, 0x18, 0x5B }, { 0x96, 0x30, 0x01 }, { 0x7B, 0x48, 0x00 }, + { 0x5A, 0x66, 0x00 }, { 0x23, 0x78, 0x00 }, { 0x01, 0x7F, 0x00 }, { 0x00, 0x78, 0x3D }, + { 0x00, 0x6C, 0x8C }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xFF, 0xFF, 0xFF }, { 0x60, 0xA6, 0xFF }, { 0x8F, 0x84, 0xFF }, { 0xB4, 0x73, 0xFF }, + { 0xE2, 0x6C, 0xFF }, { 0xF2, 0x68, 0xC3 }, { 0xEF, 0x7E, 0x61 }, { 0xD8, 0x95, 0x27 }, + { 0xBA, 0xB3, 0x07 }, { 0x81, 0xC8, 0x07 }, { 0x57, 0xD4, 0x3D }, { 0x47, 0xCF, 0x7E }, + { 0x4B, 0xC5, 0xCD }, { 0x4C, 0x4B, 0x4D }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xFF, 0xFF, 0xFF }, { 0xC2, 0xE0, 0xFF }, { 0xD5, 0xD2, 0xFF }, { 0xE3, 0xCB, 0xFF }, + { 0xF7, 0xC8, 0xFF }, { 0xFE, 0xC6, 0xEE }, { 0xFE, 0xCE, 0xC6 }, { 0xF6, 0xD7, 0xAE }, + { 0xE9, 0xE4, 0x9F }, { 0xD3, 0xED, 0x9D }, { 0xC0, 0xF2, 0xB2 }, { 0xB9, 0xF1, 0xCC }, + { 0xBA, 0xED, 0xED }, { 0xBA, 0xB9, 0xBB }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 } + } + }, + { "wavebeam", "nakedarthur's Wavebeam palette", { + { 0x6B, 0x6B, 0x6B }, { 0x00, 0x1B, 0x88 }, { 0x21, 0x00, 0x9A }, { 0x40, 0x00, 0x8C }, + { 0x60, 0x00, 0x67 }, { 0x64, 0x00, 0x1E }, { 0x59, 0x08, 0x00 }, { 0x48, 0x16, 0x00 }, + { 0x28, 0x36, 0x00 }, { 0x00, 0x45, 0x00 }, { 0x00, 0x49, 0x08 }, { 0x00, 0x42, 0x1D }, + { 0x00, 0x36, 0x59 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xB4, 0xB4, 0xB4 }, { 0x15, 0x55, 0xD3 }, { 0x43, 0x37, 0xEF }, { 0x74, 0x25, 0xDF }, + { 0x9C, 0x19, 0xB9 }, { 0xAC, 0x0F, 0x64 }, { 0xAA, 0x2C, 0x00 }, { 0x8A, 0x4B, 0x00 }, + { 0x66, 0x6B, 0x00 }, { 0x21, 0x83, 0x00 }, { 0x00, 0x8A, 0x00 }, { 0x00, 0x81, 0x44 }, + { 0x00, 0x76, 0x91 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xFF, 0xFF, 0xFF }, { 0x63, 0xB2, 0xFF }, { 0x7C, 0x9C, 0xFF }, { 0xC0, 0x7D, 0xFE }, + { 0xE9, 0x77, 0xFF }, { 0xF5, 0x72, 0xCD }, { 0xF4, 0x88, 0x6B }, { 0xDD, 0xA0, 0x29 }, + { 0xBD, 0xBD, 0x0A }, { 0x89, 0xD2, 0x0E }, { 0x5C, 0xDE, 0x3E }, { 0x4B, 0xD8, 0x86 }, + { 0x4D, 0xCF, 0xD2 }, { 0x52, 0x52, 0x52 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xFF, 0xFF, 0xFF }, { 0xBC, 0xDF, 0xFF }, { 0xD2, 0xD2, 0xFF }, { 0xE1, 0xC8, 0xFF }, + { 0xEF, 0xC7, 0xFF }, { 0xFF, 0xC3, 0xE1 }, { 0xFF, 0xCA, 0xC6 }, { 0xF2, 0xDA, 0xAD }, + { 0xEB, 0xE3, 0xA0 }, { 0xD2, 0xED, 0xA2 }, { 0xBC, 0xF4, 0xB4 }, { 0xB5, 0xF1, 0xCE }, + { 0xB6, 0xEC, 0xF1 }, { 0xBF, 0xBF, 0xBF }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 } + } + }, + { "digital-prime-fbx", "FBX's Digital Prime palette", { + { 0x61, 0x61, 0x61 }, { 0x00, 0x00, 0x88 }, { 0x1F, 0x0D, 0x99 }, { 0x37, 0x13, 0x79 }, + { 0x56, 0x12, 0x60 }, { 0x5D, 0x00, 0x10 }, { 0x52, 0x0E, 0x00 }, { 0x3A, 0x23, 0x08 }, + { 0x21, 0x35, 0x0C }, { 0x0D, 0x41, 0x0E }, { 0x17, 0x44, 0x17 }, { 0x00, 0x3A, 0x1F }, + { 0x00, 0x2F, 0x57 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xAA, 0xAA, 0xAA }, { 0x0D, 0x4D, 0xC4 }, { 0x4B, 0x24, 0xDE }, { 0x69, 0x12, 0xCF }, + { 0x90, 0x14, 0xAD }, { 0x9D, 0x1C, 0x48 }, { 0x92, 0x34, 0x04 }, { 0x73, 0x50, 0x05 }, + { 0x5D, 0x69, 0x13 }, { 0x16, 0x7A, 0x11 }, { 0x13, 0x80, 0x08 }, { 0x12, 0x76, 0x49 }, + { 0x1C, 0x66, 0x91 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xFC, 0xFC, 0xFC }, { 0x63, 0x9A, 0xFC }, { 0x8A, 0x7E, 0xFC }, { 0xB0, 0x6A, 0xFC }, + { 0xDD, 0x6D, 0xF2 }, { 0xE7, 0x71, 0xAB }, { 0xE3, 0x86, 0x58 }, { 0xCC, 0x9E, 0x22 }, + { 0xA8, 0xB1, 0x00 }, { 0x72, 0xC1, 0x00 }, { 0x5A, 0xCD, 0x4E }, { 0x34, 0xC2, 0x8E }, + { 0x4F, 0xBE, 0xCE }, { 0x42, 0x42, 0x42 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xFC, 0xFC, 0xFC }, { 0xBE, 0xD4, 0xFC }, { 0xCA, 0xCA, 0xFC }, { 0xD9, 0xC4, 0xFC }, + { 0xEC, 0xC1, 0xFC }, { 0xFA, 0xC3, 0xE7 }, { 0xF7, 0xCE, 0xC3 }, { 0xE2, 0xCD, 0xA7 }, + { 0xDA, 0xDB, 0x9C }, { 0xC8, 0xE3, 0x9E }, { 0xBF, 0xE5, 0xB8 }, { 0xB2, 0xEB, 0xC8 }, + { 0xB7, 0xE5, 0xEB }, { 0xAC, 0xAC, 0xAC }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 } + } + }, + { "magnum-fbx", "FBX's Magnum palette", { + { 0x69, 0x69, 0x69 }, { 0x00, 0x14, 0x8F }, { 0x1E, 0x02, 0x9B }, { 0x3F, 0x00, 0x8A }, + { 0x60, 0x00, 0x60 }, { 0x66, 0x00, 0x17 }, { 0x57, 0x0D, 0x00 }, { 0x45, 0x1B, 0x00 }, + { 0x24, 0x34, 0x00 }, { 0x00, 0x42, 0x00 }, { 0x00, 0x45, 0x00 }, { 0x00, 0x3C, 0x1F }, + { 0x00, 0x31, 0x5C }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xAF, 0xAF, 0xAF }, { 0x0F, 0x51, 0xDD }, { 0x44, 0x2F, 0xF3 }, { 0x72, 0x20, 0xE2 }, + { 0xA3, 0x19, 0xB3 }, { 0xAE, 0x1C, 0x51 }, { 0xA4, 0x34, 0x00 }, { 0x88, 0x4D, 0x00 }, + { 0x67, 0x6D, 0x00 }, { 0x20, 0x80, 0x00 }, { 0x00, 0x8B, 0x00 }, { 0x00, 0x7F, 0x42 }, + { 0x00, 0x6C, 0x97 }, { 0x01, 0x01, 0x01 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xFF, 0xFF, 0xFF }, { 0x65, 0xAA, 0xFF }, { 0x8C, 0x96, 0xFF }, { 0xB9, 0x83, 0xFF }, + { 0xDD, 0x6F, 0xFF }, { 0xEA, 0x6F, 0xBD }, { 0xEB, 0x84, 0x66 }, { 0xDC, 0xA2, 0x1F }, + { 0xBA, 0xB4, 0x03 }, { 0x7E, 0xCB, 0x07 }, { 0x54, 0xD3, 0x3E }, { 0x3C, 0xD2, 0x84 }, + { 0x3E, 0xC7, 0xCC }, { 0x4B, 0x4B, 0x4B }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xFF, 0xFF, 0xFF }, { 0xBD, 0xE2, 0xFF }, { 0xCE, 0xCF, 0xFF }, { 0xE6, 0xC2, 0xFF }, + { 0xF6, 0xBC, 0xFF }, { 0xF9, 0xC2, 0xED }, { 0xFA, 0xCF, 0xC6 }, { 0xF8, 0xDE, 0xAC }, + { 0xEE, 0xE9, 0xA1 }, { 0xD0, 0xF5, 0x9F }, { 0xBB, 0xF5, 0xAF }, { 0xB3, 0xF5, 0xCD }, + { 0xB9, 0xED, 0xF0 }, { 0xB9, 0xB9, 0xB9 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 } + } + }, + { "smooth-v2-fbx", "FBX's Smooth V2 palette", { + { 0x6A, 0x6A, 0x6A }, { 0x00, 0x14, 0x8F }, { 0x1E, 0x02, 0x9B }, { 0x3F, 0x00, 0x8A }, + { 0x60, 0x00, 0x60 }, { 0x66, 0x00, 0x17 }, { 0x57, 0x0D, 0x00 }, { 0x3C, 0x1F, 0x00 }, + { 0x1B, 0x33, 0x00 }, { 0x00, 0x42, 0x00 }, { 0x00, 0x45, 0x00 }, { 0x00, 0x3C, 0x1F }, + { 0x00, 0x31, 0x5C }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xB9, 0xB9, 0xB9 }, { 0x0F, 0x4B, 0xD4 }, { 0x41, 0x2D, 0xEB }, { 0x6C, 0x1D, 0xD9 }, + { 0x9C, 0x17, 0xAB }, { 0xA7, 0x1A, 0x4D }, { 0x99, 0x32, 0x00 }, { 0x7C, 0x4A, 0x00 }, + { 0x54, 0x64, 0x00 }, { 0x1A, 0x78, 0x00 }, { 0x00, 0x7F, 0x00 }, { 0x00, 0x76, 0x3E }, + { 0x00, 0x67, 0x8F }, { 0x01, 0x01, 0x01 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + { 0xFF, 0xFF, 0xFF }, { 0x68, 0xA6, 0xFF }, { 0x8C, 0x9C, 0xFF }, { 0xB5, 0x86, 0xFF }, + + { 0xD9, 0x75, 0xFD }, { 0xE3, 0x77, 0xB9 }, { 0xE5, 0x8D, 0x68 }, { 0xD4, 0x9D, 0x29 }, + { 0xB3, 0xAF, 0x0C }, { 0x7B, 0xC2, 0x11 }, { 0x55, 0xCA, 0x47 }, { 0x46, 0xCB, 0x81 }, + { 0x47, 0xC1, 0xC5 }, { 0x4A, 0x4A, 0x4A }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + { 0xFF, 0xFF, 0xFF }, { 0xCC, 0xEA, 0xFF }, { 0xDD, 0xDE, 0xFF }, { 0xEC, 0xDA, 0xFF }, + + { 0xF8, 0xD7, 0xFE }, { 0xFC, 0xD6, 0xF5 }, { 0xFD, 0xDB, 0xCF }, { 0xF9, 0xE7, 0xB5 }, + { 0xF1, 0xF0, 0xAA }, { 0xDA, 0xFA, 0xA9 }, { 0xC9, 0xFF, 0xBC }, { 0xC3, 0xFB, 0xD7 }, + { 0xC4, 0xF6, 0xF6 }, { 0xBE, 0xBE, 0xBE }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 } + } + }, + { "nes-classic-fbx", "FBX's NES Classic palette", { + { 0x61, 0x61, 0x61 }, { 0x00, 0x00, 0x88 }, { 0x1F, 0x0D, 0x99 }, { 0x37, 0x13, 0x79 }, + { 0x56, 0x12, 0x60 }, { 0x5D, 0x00, 0x10 }, { 0x52, 0x0E, 0x00 }, { 0x3A, 0x23, 0x08 }, + { 0x21, 0x35, 0x0C }, { 0x0D, 0x41, 0x0E }, { 0x17, 0x44, 0x17 }, { 0x00, 0x3A, 0x1F }, + { 0x00, 0x2F, 0x57 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xAA, 0xAA, 0xAA }, { 0x0D, 0x4D, 0xC4 }, { 0x4B, 0x24, 0xDE }, { 0x69, 0x12, 0xCF }, + { 0x90, 0x14, 0xAD }, { 0x9D, 0x1C, 0x48 }, { 0x92, 0x34, 0x04 }, { 0x73, 0x50, 0x05 }, + { 0x5D, 0x69, 0x13 }, { 0x16, 0x7A, 0x11 }, { 0x13, 0x80, 0x08 }, { 0x12, 0x76, 0x49 }, + { 0x1C, 0x66, 0x91 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xFC, 0xFC, 0xFC }, { 0x63, 0x9A, 0xFC }, { 0x8A, 0x7E, 0xFC }, { 0xB0, 0x6A, 0xFC }, + { 0xDD, 0x6D, 0xF2 }, { 0xE7, 0x71, 0xAB }, { 0xE3, 0x86, 0x58 }, { 0xCC, 0x9E, 0x22 }, + { 0xA8, 0xB1, 0x00 }, { 0x72, 0xC1, 0x00 }, { 0x5A, 0xCD, 0x4E }, { 0x34, 0xC2, 0x8E }, + { 0x4F, 0xBE, 0xCE }, { 0x42, 0x42, 0x42 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, + + { 0xFC, 0xFC, 0xFC }, { 0xBE, 0xD4, 0xFC }, { 0xCA, 0xCA, 0xFC }, { 0xD9, 0xC4, 0xFC }, + { 0xEC, 0xC1, 0xFC }, { 0xFA, 0xC3, 0xE7 }, { 0xF7, 0xCE, 0xC3 }, { 0xE2, 0xCD, 0xA7 }, + { 0xDA, 0xDB, 0x9C }, { 0xC8, 0xE3, 0x9E }, { 0xBF, 0xE5, 0xB8 }, { 0xB2, 0xEB, 0xC8 }, + { 0xB7, 0xE5, 0xEB }, { 0xAC, 0xAC, 0xAC }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 } + } + } +}; + +#endif /* _PALDEF_H */ \ No newline at end of file diff --git a/src/boards/BMW8544.c b/src/boards/BMW8544.c deleted file mode 100644 index 649cca0d6..000000000 --- a/src/boards/BMW8544.c +++ /dev/null @@ -1,84 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2015 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 - * - * NES 2.0 Mapper 292 - UNIF UNL-DRAGONFIGHTER - * "Dragon Fighter" protected MMC3 based custom mapper board - * mostly hacky implementation, I can't verify if this mapper can read a RAM of the - * console or watches the bus writes somehow. - * - * TODO: needs updating - * - */ - -#include "mapinc.h" -#include "mmc3.h" - -static void UNLBMW8544PW(uint32 A, uint8 V) { - if (A == 0x8000) - setprg8(A, mmc3.expregs[0] & 0x1F); /* the real hardware has this bank overrided with it's own register, - * but MMC3 prg swap still works and you can actually change bank C000 at the - * same time if use 0x46 cmd - */ - else - setprg8(A, V); -} - -static void UNLBMW8544CW(uint32 A, uint8 V) { - if (A == 0x0000) - setchr2(0x0000, (V >> 1) ^ mmc3.expregs[1]); - else if (A == 0x0800) - setchr2(0x0800, (V >> 1) | ((mmc3.expregs[2] & 0x40) << 1)); - else if (A == 0x1000) - setchr4(0x1000, mmc3.expregs[2] & 0x3F); -} - -static DECLFW(UNLBMW8544ProtWrite) { - if (!(A & 1)) { - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); - } -} - -static DECLFR(UNLBMW8544ProtRead) { - if (!fceuindbg) { - if (!(A & 1)) { - if ((mmc3.expregs[0] & 0xE0) == 0xC0) { - mmc3.expregs[1] = ARead[0x6a](0x6a); /* program can latch some data from the BUS, but I can't say how exactly, */ - } else { /* without more equipment and skills ;) probably here we can try to get any write */ - mmc3.expregs[2] = ARead[0xff](0xff); /* before the read operation */ - } - FixMMC3CHR(mmc3.cmd & 0x7F); /* there are more different behaviour of the board that's not used by game itself, so unimplemented here and */ - } /* actually will break the current logic ;) */ - } - return 0; -} - -static void UNLBMW8544Power(void) { - GenMMC3Power(); - SetWriteHandler(0x6000, 0x6FFF, UNLBMW8544ProtWrite); - SetReadHandler(0x6000, 0x6FFF, UNLBMW8544ProtRead); -} - -void UNLBMW8544_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 256, 0, 0); - mmc3.pwrap = UNLBMW8544PW; - mmc3.cwrap = UNLBMW8544CW; - info->Power = UNLBMW8544Power; - AddExState(mmc3.expregs, 3, 0, "EXPR"); -} diff --git a/src/boards/KS7030.c b/src/boards/KS7030.c deleted file mode 100644 index a35b18499..000000000 --- a/src/boards/KS7030.c +++ /dev/null @@ -1,156 +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 - * - * FDS Conversion - Yume Koujou: Doki Doki Panic - * - * Logical bank layot 32 K BANK 0, 64K BANK 1, 32K ~0 hardwired, 8K is missing - * need redump from MASKROM! - * probably need refix mapper after hard dump - * - */ - -/* 2020-3-6 - update mirroring - * PRG-ROM Bank Select #1/Mirroring Select ($8000-$8FFF, write) - * A~FEDC BA98 7654 3210 - * ------------------- - * 1000 .... .... MBBB - * |+++- Select 4 KiB PRG-ROM bank at CPU $7000-$7FFF - * +---- Select nametable mirroring type - * 0: Vertical - * 1: Horizontal - */ - -#include "mapinc.h" -#include "../fds_apu.h" - -static uint8 reg0, reg1; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; - -static SFORMAT StateRegs[] = -{ - { ®0, 1, "REG0" }, - { ®1, 1, "REG1" }, - { 0 } -}; - -static void Sync(void) { - setchr8(0); - setprg32(0x8000, ~0); - setprg4(0xb800, reg0 & 0x07); - setprg4(0xc800, 8 + reg1); - setmirror(((reg0 >> 3) & 1) ^ 1); -} - -/* 6000 - 6BFF - RAM - * 6C00 - 6FFF - BANK 1K REG1 - * 7000 - 7FFF - BANK 4K REG0 - */ - -static DECLFW(UNLKS7030RamWrite0) { - if ((A >= 0x6000) && A <= 0x6BFF) { - WRAM[A - 0x6000] = V; - } else if ((A >= 0x6C00) && A <= 0x6FFF) { - CartBW(0xC800 + (A - 0x6C00), V); - } else if ((A >= 0x7000) && A <= 0x7FFF) { - CartBW(0xB800 + (A - 0x7000), V); - } -} - -static DECLFR(UNLKS7030RamRead0) { - if ((A >= 0x6000) && A <= 0x6BFF) { - return WRAM[A - 0x6000]; - } else if ((A >= 0x6C00) && A <= 0x6FFF) { - return CartBR(0xC800 + (A - 0x6C00)); - } else if ((A >= 0x7000) && A <= 0x7FFF) { - return CartBR(0xB800 + (A - 0x7000)); - } - return 0; -} - -/* B800 - BFFF - RAM - * C000 - CBFF - BANK 3K - * CC00 - D7FF - RAM - */ - -static DECLFW(UNLKS7030RamWrite1) { - if ((A >= 0xB800) && A <= 0xBFFF) { - WRAM[0x0C00 + (A - 0xB800)] = V; - } else if ((A >= 0xC000) && A <= 0xCBFF) { - CartBW(0xCC00 + (A - 0xC000), V); - } else if ((A >= 0xCC00) && A <= 0xD7FF) { - WRAM[0x1400 + (A - 0xCC00)] = V; - } -} - -static DECLFR(UNLKS7030RamRead1) { - if ((A >= 0xB800) && A <= 0xBFFF) { - return WRAM[0x0C00 + (A - 0xB800)]; - } else if ((A >= 0xC000) && A <= 0xCBFF) { - return CartBR(0xCC00 + (A - 0xC000)); - } else if ((A >= 0xCC00) && A <= 0xD7FF) { - return WRAM[0x1400 + (A - 0xCC00)]; - } - return 0; -} - -static DECLFW(UNLKS7030Write0) { - reg0 = A & 0xF; - Sync(); -} - -static DECLFW(UNLKS7030Write1) { - reg1 = A & 0xF; - Sync(); -} - -static void UNLKS7030Power(void) { - FDSSoundPower(); - reg0 = reg1 = ~0; - Sync(); - SetReadHandler(0x6000, 0x7FFF, UNLKS7030RamRead0); - SetWriteHandler(0x6000, 0x7FFF, UNLKS7030RamWrite0); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0x8FFF, UNLKS7030Write0); - SetWriteHandler(0x9000, 0x9FFF, UNLKS7030Write1); - SetReadHandler(0xB800, 0xD7FF, UNLKS7030RamRead1); - SetWriteHandler(0xB800, 0xD7FF, UNLKS7030RamWrite1); -} - -static void UNLKS7030Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -static void StateRestore(int version) { - Sync(); -} - -void UNLKS7030_Init(CartInfo *info) { - info->Power = UNLKS7030Power; - info->Close = UNLKS7030Close; - GameStateRestore = StateRestore; - - WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/KS7032.c b/src/boards/KS7032.c deleted file mode 100644 index 612a6d33c..000000000 --- a/src/boards/KS7032.c +++ /dev/null @@ -1,178 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * 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 - * 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 - * - */ - -/* 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], creg[8], mirr, cmd, IRQa = 0; -static int32 IRQCount, IRQLatch; -static uint8 KS7032; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; - -static SFORMAT StateRegsKS7032[] = -{ - { &cmd, 1, "CMD" }, - { reg, 8, "REGS" }, - { &IRQa, 1, "IRQA" }, - { &IRQCount, 4, "IRQC" }, - { 0 } -}; - -static SFORMAT StateRegsKS202[] = -{ - { creg, 8, "CREG" }, - { &mirr, 1, "MIRR" }, - { 0 } -}; - -static void Sync(void) { - 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: 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: { - 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; - } -} - -static void FP_FASTAPASS(1) UNLSMB2JIRQHook(int a) { - if (IRQa) { - IRQCount += a; - if (IRQCount >= 0xFFFF) { - IRQCount = IRQLatch; - X6502_IRQBegin(FCEU_IQEXT); - } - } -} - -static void UNLKS7032Power(void) { - Sync(); - 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 UNLKS7032Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -static void StateRestore(int version) { - Sync(); -} - -void UNLKS7032_Init(CartInfo *info) { - KS7032 = 1; - info->Power = UNLKS7032Power; - info->Close = UNLKS7032Close; - MapIRQHook = UNLSMB2JIRQHook; - GameStateRestore = StateRestore; - AddExState(&StateRegsKS7032, ~0, 0, 0); -} - -void UNLKS202_Init(CartInfo *info) { - KS7032 = 0; - info->Power = UNLKS7032Power; - info->Close = UNLKS7032Close; - 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/KS7037.c b/src/boards/KS7037.c deleted file mode 100644 index 0c73c3676..000000000 --- a/src/boards/KS7037.c +++ /dev/null @@ -1,128 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2011 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 - * - * FDS Conversion - Metroid - Jin Ji Zhi Ling (Kaiser)(KS7037)[U][!] - * - */ - -#include "mapinc.h" -#include "../fds_apu.h" - -static uint8 reg[8], cmd; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; - -static void (*WSync)(void); - -static SFORMAT StateRegs[] = -{ - { &cmd, 1, "CMD" }, - { reg, 8, "REGS" }, - { 0 } -}; - -static void SyncKS7037(void) { - setprg4r(0x10, 0x6000, 0); - setprg4(0x7000, 15); - setprg8(0x8000, reg[6]); - setprg4(0xA000, ~3); - setprg4r(0x10, 0xB000, 1); - setprg8(0xC000, reg[7]); - setprg8(0xE000, ~0); - setchr8(0); - setmirrorw(reg[2] & 1, reg[4] & 1, reg[3] & 1, reg[5] & 1); -} - -static void SyncLH10(void) { - setprg8(0x6000, ~1); - setprg8(0x8000, reg[6]); - setprg8(0xA000, reg[7]); - setprg8r(0x10, 0xC000, 0); - setprg8(0xE000, ~0); - setchr8(0); - setmirror(0); -} - -static DECLFW(UNLKS7037Write) { - switch (A & 0xE001) { - case 0x8000: cmd = V & 7; break; - case 0x8001: reg[cmd] = V; WSync(); break; - } -} - -static void UNLKS7037Power(void) { - FDSSoundPower(); - reg[0] = reg[1] = reg[2] = reg[3] = reg[4] = reg[5] = reg[6] = reg[7] = 0; - WSync(); - SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetWriteHandler(0x8000, 0x9FFF, UNLKS7037Write); - SetWriteHandler(0xA000, 0xBFFF, CartBW); - SetWriteHandler(0xC000, 0xFFFF, UNLKS7037Write); -} - -static void LH10Power(void) { - reg[0] = reg[1] = reg[2] = reg[3] = reg[4] = reg[5] = reg[6] = reg[7] = 0; - WSync(); - SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xBFFF, UNLKS7037Write); - SetWriteHandler(0xC000, 0xDFFF, CartBW); - SetWriteHandler(0xE000, 0xFFFF, UNLKS7037Write); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); -} - -static void Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -static void StateRestore(int version) { - WSync(); -} - -void UNLKS7037_Init(CartInfo *info) { - info->Power = UNLKS7037Power; - info->Close = Close; - - WSync = SyncKS7037; - - WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} - -void LH10_Init(CartInfo *info) { - info->Power = LH10Power; - info->Close = Close; - - WSync = SyncLH10; - - WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/KS7057.c b/src/boards/KS7057.c deleted file mode 100644 index be32d24b4..000000000 --- a/src/boards/KS7057.c +++ /dev/null @@ -1,97 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2011 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 - * - * FDS Conversion - * - */ - -#include "mapinc.h" - -static uint8 reg[8], mirror; -static SFORMAT StateRegs[] = -{ - { reg, 8, "PRG" }, - { &mirror, 1, "MIRR" }, - { 0 } -}; - -static void Sync(void) { - setprg2(0x6000, reg[4]); - setprg2(0x6800, reg[5]); - setprg2(0x7000, reg[6]); - setprg2(0x7800, reg[7]); - setprg2(0x8000, reg[0]); - setprg2(0x8800, reg[1]); - setprg2(0x9000, reg[2]); - setprg2(0x9800, reg[3]); - setprg8(0xA000, 0xd); - setprg16(0xC000, 7); - setchr8(0); - setmirror(mirror); -} - -static DECLFW(UNLKS7057Write) { - switch (A & 0xF003) { - case 0x8000: - case 0x8001: - case 0x8002: - case 0x8003: - case 0x9000: - case 0x9001: - case 0x9002: - case 0x9003: mirror = V & 1; Sync(); break; - case 0xB000: reg[0] = (reg[0] & 0xF0) | (V & 0x0F); Sync(); break; - case 0xB001: reg[0] = (reg[0] & 0x0F) | (V << 4); Sync(); break; - case 0xB002: reg[1] = (reg[1] & 0xF0) | (V & 0x0F); Sync(); break; - case 0xB003: reg[1] = (reg[1] & 0x0F) | (V << 4); Sync(); break; - case 0xC000: reg[2] = (reg[2] & 0xF0) | (V & 0x0F); Sync(); break; - case 0xC001: reg[2] = (reg[2] & 0x0F) | (V << 4); Sync(); break; - case 0xC002: reg[3] = (reg[3] & 0xF0) | (V & 0x0F); Sync(); break; - case 0xC003: reg[3] = (reg[3] & 0x0F) | (V << 4); Sync(); break; - case 0xD000: reg[4] = (reg[4] & 0xF0) | (V & 0x0F); Sync(); break; - case 0xD001: reg[4] = (reg[4] & 0x0F) | (V << 4); Sync(); break; - case 0xD002: reg[5] = (reg[5] & 0xF0) | (V & 0x0F); Sync(); break; - case 0xD003: reg[5] = (reg[5] & 0x0F) | (V << 4); Sync(); break; - case 0xE000: reg[6] = (reg[6] & 0xF0) | (V & 0x0F); Sync(); break; - case 0xE001: reg[6] = (reg[6] & 0x0F) | (V << 4); Sync(); break; - case 0xE002: reg[7] = (reg[7] & 0xF0) | (V & 0x0F); Sync(); break; - case 0xE003: reg[7] = (reg[7] & 0x0F) | (V << 4); Sync(); break; - } -} - -static void UNLKS7057Power(void) { - Sync(); - SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, UNLKS7057Write); -} - -static void UNLKS7057Reset(void) { - Sync(); -} - -static void StateRestore(int version) { - Sync(); -} - -void UNLKS7057_Init(CartInfo *info) { - info->Power = UNLKS7057Power; - info->Reset = UNLKS7057Reset; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/__dummy_mapper.c b/src/boards/__dummy_mapper.c deleted file mode 100644 index 0e257eb1e..000000000 --- a/src/boards/__dummy_mapper.c +++ /dev/null @@ -1,98 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2013 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" - -static uint8 reg[8]; -static uint8 IRQa; -static int16 IRQCount, IRQLatch; -/* -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; -static uint8 *CHRRAM = NULL; -static uint32 CHRRAMSIZE; -*/ - -static SFORMAT StateRegs[] = -{ - { reg, 8, "REGS" }, - { &IRQa, 1, "IRQA" }, - { &IRQCount, 2, "IRQC" }, - { &IRQLatch, 2, "IRQL" }, - { 0 } -}; - -static void Sync(void) { -} - -static DECLFW(MNNNWrite) { -} - -static void MNNNPower(void) { -/* SetReadHandler(0x6000, 0x7fff, CartBR); */ -/* SetWriteHandler(0x6000, 0x7fff, CartBW); */ - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, MNNNWrite); -} - -static void MNNNReset(void) { -} - -/* -static void MNNNClose(void) { - if (WRAM) - FCEU_gfree(WRAM); - if (CHRRAM) - FCEU_gfree(CHRRAM); - WRAM = CHRRAM = NULL; -} -*/ - -static void MNNNIRQHook(void) { - X6502_IRQBegin(FCEU_IQEXT); -} - -static void StateRestore(int version) { - Sync(); -} - -void MapperNNN_Init(CartInfo *info) { - info->Reset = MNNNReset; - info->Power = MNNNPower; -/* info->Close = MNNNClose; */ - GameHBIRQHook = MNNNIRQHook; - GameStateRestore = StateRestore; -#if 0 - CHRRAMSIZE = 8192; - CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSIZE); - SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); - AddExState(CHRRAM, CHRRAMSIZE, 0, "CRAM"); - - WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; - } -#endif - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/__serial.c b/src/boards/__serial.c deleted file mode 100644 index db5684174..000000000 --- a/src/boards/__serial.c +++ /dev/null @@ -1,151 +0,0 @@ -#include -#include "__serial.h" - -#if defined(_WIN32) && !defined(_XBOX) && !defined(__LIBRETRO__) - -HANDLE SerialPort = NULL; /* Handle of SerialPort itself. */ - -BOOL SerialOpen(int port, int baud) { - HANDLE Comport; - DCB myDCB; - COMMTIMEOUTS CTout; - char str[100]; - - if (port > 9) - sprintf(str, "\\\\.\\COM%d", port); - else - sprintf(str, "COM%d", port); - - /* Open the serial port */ - if ((Comport = CreateFile(str, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) - return FALSE; - - /* Configure Serial port (Setup Comm) */ - - /* Buffer sizes */ - if (!SetupComm(Comport, 128, 128)) - return FALSE; - - /* Setup DCB using current values */ - if (!GetCommState(Comport, &myDCB)) - return FALSE; - - myDCB.fInX = FALSE; /* Turn off xon/xoff handler */ - myDCB.fOutX = FALSE; - myDCB.fOutxDsrFlow = FALSE; - myDCB.fOutxCtsFlow = FALSE; /* no hardware flow control. */ - myDCB.BaudRate = baud; - myDCB.DCBlength = sizeof(DCB); - myDCB.fBinary = 1; - myDCB.fParity = 0; - myDCB.fDtrControl = DTR_CONTROL_DISABLE; - myDCB.fDsrSensitivity = 0; - myDCB.fTXContinueOnXoff = 1; - myDCB.fNull = 0; - myDCB.fRtsControl = RTS_CONTROL_DISABLE; - myDCB.fDummy2 = 0; - myDCB.wReserved = 0; - myDCB.Parity = NOPARITY; - myDCB.StopBits = ONESTOPBIT; - myDCB.wReserved1 = 0; - myDCB.ByteSize = 8; - - if (!SetCommState(Comport, &myDCB)) - return FALSE; - - /* Set timeouts */ - CTout.ReadIntervalTimeout = 0xffffffff; - CTout.ReadTotalTimeoutMultiplier = 0; - CTout.ReadTotalTimeoutConstant = 0; - CTout.WriteTotalTimeoutMultiplier = 0; - CTout.WriteTotalTimeoutConstant = 5000; /* don't hang if CTS is locked, for example */ - - SetCommTimeouts(Comport, &CTout); - EscapeCommFunction(Comport, SETDTR); - PurgeComm(Comport, PURGE_TXCLEAR | PURGE_RXCLEAR); - - SerialPort = Comport; - - return TRUE; -} - -void SerialClose(void) { - if (SerialPort == NULL) return; - - PurgeComm(SerialPort, PURGE_TXCLEAR | PURGE_RXCLEAR); - CloseHandle(SerialPort); - - SerialPort = NULL; -} - -BOOL SerialSendChar(int c) { - DWORD cr; - if (WriteFile(SerialPort, &c, 1, (LPDWORD)&cr, NULL) && cr) - return TRUE; - else - return FALSE; -} - -int SerialIsOpen(void) { - return(SerialPort != NULL); -} - -int SerialGetChar(void) { - uint8 ch; - DWORD cr; - if (SerialPort != NULL) { - if (ReadFile(SerialPort, &ch, 1, (LPDWORD)&cr, NULL) && cr) - return (int)ch; - } - return EOF; -} - -void SendCmd(uint8 *cmd, int size) { - int i; - for (i = 0; i < size; i++) { - SerialSendChar(cmd[i]); - } -} - -int ReadResp(uint8 *resp, int size) { - int i = 0, sum = 0, data; - while (i < size) { - while ((data = SerialGetChar()) == EOF) { - } - resp[i] = data & 0xff; - sum += (data & 0xff); - i++; - } - return sum; -} -#else - -/* code is not portable, so make stubs for now */ - -BOOL SerialOpen(int port, int baud) { - return FALSE; -} - -void SerialClose(void) { -} - -BOOL SerialSendChar(int c) { - return FALSE; -} - -int SerialIsOpen(void) { - return FALSE; -} - -int SerialGetChar(void) { - return EOF; -} - -void SendCmd(uint8 *cmd, int size) { -} - -int ReadResp(uint8 *resp, int size) { - return 0; -} - -#endif diff --git a/src/boards/__serial.h b/src/boards/__serial.h deleted file mode 100644 index 56d35c3e5..000000000 --- a/src/boards/__serial.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef __SERIAL_H -#define __SERIAL_H - -typedef int BOOL; - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -#include "../fceu-types.h" - -void SendCmd(uint8 *cmd, int size); -int ReadResp(uint8 *resp, int size); - -#define SEND(cmd) SendCmd((uint8*)&cmd[0], sizeof(cmd)) -#define GET(buf, size) ReadResp((uint8*)&buf, size) -#define SENDGET(cmd, buf, size) SEND(cmd); GET(buf, size) - -BOOL SerialOpen(int port, int baud); -void SerialClose(void); -BOOL SerialSendChar(int c); -int SerialIsOpen(void); -int SerialGetChar(void); - -#endif diff --git a/src/boards/a9746.c b/src/boards/a9746.c deleted file mode 100644 index bfe02dc02..000000000 --- a/src/boards/a9746.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 - */ - -#include "mapinc.h" -#include "mmc3.h" - -static void UNLA9746PWrap(uint32 A, uint8 V) { - setprg8(A, (mmc3.expregs[1] << 4) | (V & 0x0F)); -} - -static void UNLA9746CWrap(uint32 A, uint8 V) { - setchr1(A, (mmc3.expregs[1] << 7) | (V & 0x7F)); -} - -static DECLFW(UNLA9746WriteOuter) { - switch (A & 1) { - case 0: - mmc3.expregs[1] = (mmc3.expregs[1] & ~1) | ((V >> 3) & 1); - break; - case 1: - mmc3.expregs[1] = (mmc3.expregs[1] & ~2) | ((V >> 4) & 2); - break; - } - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); -} - -static DECLFW(UNLA9746WriteASIC) { - int index; - - if (A & 1) { /* Register data */ - if (~mmc3.expregs[0] & 0x20) { /* Scrambled mode inactive */ - MMC3_CMDWrite(A, V); - } else { /* Scrambled mode active */ - if ((mmc3.cmd >= 0x08) && (mmc3.cmd <= 0x1F)) { /* Scrambled CHR register */ - index = (mmc3.cmd - 8) >> 2; - if (mmc3.cmd & 1) { /* LSB nibble */ - mmc3.regs[index] &= ~0x0F; - mmc3.regs[index] |= ((V >> 1) & 0x0F); - } else { /* MSB nibble */ - mmc3.regs[index] &= ~0xF0; - mmc3.regs[index] |= ((V << 4) & 0xF0); - } - FixMMC3CHR(mmc3.cmd); - } else if ((mmc3.cmd >= 0x25) && (mmc3.cmd <= 0x26)) { /* Scrambled PRG register */ - mmc3.regs[6 | (mmc3.cmd & 1)] = ((V >> 5) & 1) | ((V >> 3) & 2) | ((V >> 1) & 4) | ((V << 1) & 8); - FixMMC3PRG(mmc3.cmd); - } - } - } else { /* Register index */ - MMC3_CMDWrite(A, V); - if (A & 2) - mmc3.expregs[0] = V; - } -} - -static void UNLA9746Power(void) { - GenMMC3Power(); - SetWriteHandler(0x5000, 0x5FFF, UNLA9746WriteOuter); - SetWriteHandler(0x8000, 0x9FFF, UNLA9746WriteASIC); - mmc3.expregs[0] = 0; - mmc3.expregs[1] = 3; - MMC3RegReset(); -} - -static void UNLA9746Reset(void) { - mmc3.expregs[0] = 0; - mmc3.expregs[1] = 3; - MMC3RegReset(); -} - -void UNLA9746_Init(CartInfo *info) { - GenMMC3_Init(info, 64, 512, 0, 0); - mmc3.pwrap = UNLA9746PWrap; - mmc3.cwrap = UNLA9746CWrap; - info->Power = UNLA9746Power; - info->Reset = UNLA9746Reset; - AddExState(mmc3.expregs, 2, 0, "EXPR"); -} diff --git a/src/boards/ac-08.c b/src/boards/ac-08.c deleted file mode 100644 index c9ac32db9..000000000 --- a/src/boards/ac-08.c +++ /dev/null @@ -1,77 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2011 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 - * - * FDS Conversion - * - [UNIF] Green Beret (FDS Conversion, LH09) (Unl) [U][!][t1] (160K PRG) - * - Green Beret (FDS Conversion) (Unl) (256K PRG) - * - */ - -#include "mapinc.h" -#include "../fds_apu.h" - -static uint8 reg, mirr; - -static SFORMAT StateRegs[] = -{ - { ®, 1, "REG" }, - { &mirr, 1, "MIRR" }, - { 0 } -}; - -static void Sync(void) { - uint8 prg = (ROM_size & 0x0F) ? 4 : 7; - setprg8(0x6000, reg); - setprg32(0x8000, prg); - setchr8(0); - setmirror(mirr); -} - -static DECLFW(AC08Mirr) { - mirr = ((V & 8) >> 3) ^ 1; - Sync(); -} - -static DECLFW(AC08Write) { - if (A == 0x8001) /* Green Berret prg switching is only 100x xxxx xxxx xxx1 mask */ - reg = (V >> 1) & 0xf; - else - reg = V & - 0xf; /* Sad But True, 2-in-1 mapper, Green Berret need value shifted left one byte, Castlevania doesn't */ - Sync(); -} - -static void AC08Power(void) { - FDSSoundPower(); - reg = 0; - Sync(); - SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x4025, 0x4025, AC08Mirr); - SetWriteHandler(0x8000, 0xFFFF, AC08Write); -} - -static void StateRestore(int version) { - Sync(); -} - -void AC08_Init(CartInfo *info) { - info->Power = AC08Power; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/addrlatch.c b/src/boards/addrlatch.c deleted file mode 100644 index 35bd7d53b..000000000 --- a/src/boards/addrlatch.c +++ /dev/null @@ -1,747 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2006 CaH4e3 - * Copyright (C) 2023 - * - * 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 "latch.h" - -static uint32 dipswitch = 0; -static uint32 submapper = 0; - -/*------------------ BMCD1038 ---------------------------*/ -/* iNES Mapper 59 */ - -static void BMCD1038Sync(void) { - if (latch.addr & 0x80) { - setprg16(0x8000, (latch.addr & 0x70) >> 4); - setprg16(0xC000, (latch.addr & 0x70) >> 4); - } else { - setprg32(0x8000, (latch.addr & 0x60) >> 5); - } - setchr8(latch.addr & 7); - setmirror(((latch.addr & 8) >> 3) ^ 1); -} - -static DECLFR(BMCD1038Read) { - if (latch.addr & 0x100) { - return (X.DB & ~3) | (dipswitch & 3); - } - return CartBR(A); -} - -static DECLFW(BMCD1038Write) { - /* Only recognize the latch write if the lock bit has not been set. */ - /* Needed for NT-234 "Road Fighter" */ - if (~latch.addr & 0x200) { - LatchWrite(A, V); - } -} - -static void BMCD1038Reset(void) { - dipswitch++; - /* Always reset to menu */ - latch.addr = 0; - BMCD1038Sync(); -} - -static void BMCD1038Power(void) { - LatchPower(); - - /* Trap latch writes to enforce the "Lock" bit */ - SetWriteHandler(0x8000, 0xFFFF, BMCD1038Write); -} - -void BMCD1038_Init(CartInfo *info) { - Latch_Init(info, BMCD1038Sync, BMCD1038Read, 0, 0); - info->Reset = BMCD1038Reset; - info->Power = BMCD1038Power; - AddExState(&dipswitch, 1, 0, "DIPSW"); -} - -/*------------------ Map 058 ---------------------------*/ - -static void M58Sync(void) { - if (latch.addr & 0x40) { - setprg16(0x8000, latch.addr & 7); - setprg16(0xC000, latch.addr & 7); - } else { - setprg32(0x8000, (latch.addr >> 1) & 3); - } - setchr8((latch.addr >> 3) & 7); - setmirror(((latch.addr & 0x80) >> 7) ^ 1); -} - -void Mapper58_Init(CartInfo *info) { - Latch_Init(info, M58Sync, NULL, 0, 0); - info->Reset = LatchHardReset; -} - -/*------------------ Map 061 ---------------------------*/ -static void M61Sync(void) { - if (latch.addr & 0x10) { - setprg16(0x8000, ((latch.addr & 0xF) << 1) | ((latch.addr & 0x20) >> 5)); - setprg16(0xC000, ((latch.addr & 0xF) << 1) | ((latch.addr & 0x20) >> 5)); - } else { - setprg32(0x8000, latch.addr & 0xF); - } - setchr8(0); - setmirror(((latch.addr >> 7) & 1) ^ 1); -} - -void Mapper61_Init(CartInfo *info) { - Latch_Init(info, M61Sync, NULL, 0, 0); - info->Reset = LatchHardReset; -} - -/*------------------ 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 = 0; -static uint8 hasBattery = 0; - -static DECLFR(M63Read) { - if (openBus) - return X.DB; - return CartBR(A); -} - -static void M63Sync(void) { - uint8 prg_mask = (submapper == 0) ? 0xFF : 0x7F; - uint8 prg_bank = (latch.addr >> 2) & prg_mask; - uint8 chr_protect = (latch.addr & ((submapper == 0) ? 0x400 : 0x200)) == 0; - if (latch.addr & 2) { - setprg32(0x8000, prg_bank >> 1); - } else { - setprg16(0x8000, prg_bank); - setprg16(0xC000, prg_bank); - } - setchr8(0); - setmirror((latch.addr & 1) ^ 1); - /* return openbus for unpopulated rom banks */ - openBus = prg_bank >= ROM_size; - /* chr-ram protect */ - SetupCartCHRMapping(0, CHRptr[0], 0x2000, chr_protect); -} - -void Mapper63_Init(CartInfo *info) { - Latch_Init(info, M63Sync, M63Read, 0, 0); - info->Reset = LatchHardReset; - submapper = info->submapper; -} - -/*------------------ Map 092 ---------------------------*/ -/* Another two-in-one mapper, two Jaleco carts uses similar - * hardware, but with different wiring. - * Original code provided by LULU - * Additionally, PCB contains DSP extra sound chip, used for voice samples (unemulated) - */ - -static void M92Sync(void) { - uint8 reg = latch.addr & 0xF0; - setprg16(0x8000, 0); - if (latch.addr >= 0x9000) { - switch (reg) { - case 0xD0: - setprg16(0xc000, latch.addr & 15); - break; - case 0xE0: - setchr8(latch.addr & 15); - break; - } - } else { - switch (reg) { - case 0xB0: - setprg16(0xc000, latch.addr & 15); - break; - case 0x70: - setchr8(latch.addr & 15); - break; - } - } -} - -static void M92Power() { - LatchPower(); - latch.addr = 0x80B0; - M92Sync(); -} - -void Mapper92_Init(CartInfo *info) { - Latch_Init(info, M92Sync, NULL, 0, 0); - info->Power = M92Power; -} - -/*------------------ Map 200 ---------------------------*/ - -static void M200Sync(void) { - setprg16(0x8000, latch.addr & 7); - setprg16(0xC000, latch.addr & 7); - setchr8(latch.addr & 7); - setmirror(((latch.addr >> ((submapper == 0) ? 3 : 2)) & 1) ^ 1); -} - -void Mapper200_Init(CartInfo *info) { - Latch_Init(info, M200Sync, NULL, 0, 0); - submapper = info->submapper; -} - -/*------------------ Map 201 ---------------------------*/ - -static void M201Sync(void) { - setprg32(0x8000, latch.addr); - setchr8(latch.addr); -} - -void Mapper201_Init(CartInfo *info) { - Latch_Init(info, M201Sync, NULL, 0, 0); - info->Reset = LatchHardReset; -} - -/*------------------ Map 202 ---------------------------*/ - -static void M202Sync(void) { - if ((latch.addr & 0x9) == 0x09) { - setprg32(0x8000, latch.addr >> 2); - } else { - setprg16(0x8000, latch.addr >> 1); - setprg16(0xC000, latch.addr >> 1); - } - setchr8(latch.addr >> 1); - setmirror((latch.addr & 1) ^ 1); -} - -void Mapper202_Init(CartInfo *info) { - Latch_Init(info, M202Sync, NULL, 0, 0); -} - -/*------------------ Map 204 ---------------------------*/ - -static void M204Sync(void) { - int32 tmp2 = latch.addr & 0x6; - int32 tmp1 = tmp2 + ((tmp2 == 0x6) ? 0 : (latch.addr & 1)); - setprg16(0x8000, tmp1); - setprg16(0xc000, tmp2 + ((tmp2 == 0x6) ? 1 : (latch.addr & 1))); - setchr8(tmp1); - setmirror(((latch.addr >> 4) & 1) ^ 1); -} - -void Mapper204_Init(CartInfo *info) { - Latch_Init(info, M204Sync, NULL, 0, 0); -} - -/*------------------ Map 212 ---------------------------*/ - -static DECLFR(M212Read) { - return X.DB | ((A & 0x10) ? 0 : 0x80); -} - -static void M212Sync(void) { - if (latch.addr & 0x4000) { - setprg32(0x8000, (latch.addr >> 1) & 3); - } else { - setprg16(0x8000, latch.addr & 7); - setprg16(0xC000, latch.addr & 7); - } - setchr8(latch.addr & 7); - setmirror(((latch.addr >> 3) & 1) ^ 1); -} - -static void M212Power() { - LatchPower(); - SetReadHandler(0x6000, 0x7FFF, M212Read); -} - -void Mapper212_Init(CartInfo *info) { - Latch_Init(info, M212Sync, NULL, 0, 0); - info->Power = M212Power; -} - -/*------------------ Map 214 ---------------------------*/ - -static void M214Sync(void) { - setprg16(0x8000, (latch.addr >> 2) & 3); - setprg16(0xC000, (latch.addr >> 2) & 3); - setchr8(latch.addr & 3); -} - -void Mapper214_Init(CartInfo *info) { - Latch_Init(info, M214Sync, NULL, 0, 0); -} - -/*------------------ Map 217 ---------------------------*/ - -static void M217Sync(void) { - setprg32(0x8000, latch.addr >> 2); - setchr8(latch.addr); -} - -void Mapper217_Init(CartInfo *info) { - Latch_Init(info, M217Sync, NULL, 0, 0); - info->Reset = LatchHardReset; -} - -/*------------------ Map 227 ---------------------------*/ - -static void M227Sync(void) { - uint32 S = latch.addr & 1; - uint32 p = ((latch.addr >> 2) & 0x1F) + ((latch.addr & 0x100) >> 3); - uint32 L = (latch.addr >> 9) & 1; - - if ((latch.addr >> 7) & 1) { - if (S) { - setprg32(0x8000, p >> 1); - } else { - setprg16(0x8000, p); - setprg16(0xC000, p); - } - } else { - if (S) { - if (L) { - setprg16(0x8000, p & 0x3E); - setprg16(0xC000, p | 7); - } else { - setprg16(0x8000, p & 0x3E); - setprg16(0xC000, p & 0x38); - } - } else { - if (L) { - setprg16(0x8000, p); - setprg16(0xC000, p | 7); - } else { - setprg16(0x8000, p); - setprg16(0xC000, p & 0x38); - } - } - } - - if (!hasBattery && (latch.addr & 0x80) == 0x80) - /* CHR-RAM write protect hack, needed for some multicarts */ - SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0); - else - SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1); - - setmirror(((latch.addr >> 1) & 1) ^ 1); - setchr8(0); - setprg8r(0x10, 0x6000, 0); -} - -static DECLFR(M227Read) { - if ((latch.addr & 0x400) && dipswitch) { - A |= dipswitch; - } - return CartBROB(A); -} - -static void M227Power() { - dipswitch = 0; - LatchPower(); - SetReadHandler(0x8000, 0xFFFF, M227Read); -} - -static void M227Reset() { - LatchHardReset(); - - dipswitch = (dipswitch + 1) & 0x0F; - M227Sync(); -} - -void Mapper227_Init(CartInfo *info) { - Latch_Init(info, M227Sync, NULL, 1, 0); - info->Power = M227Power; - info->Reset = M227Reset; - hasBattery = info->battery; - AddExState(&dipswitch, 1, 0, "PADS"); -} - -/*------------------ Map 229 ---------------------------*/ - -static void M229Sync(void) { - setchr8(latch.addr); - if (!(latch.addr & 0x1e)) - setprg32(0x8000, 0); - else { - setprg16(0x8000, latch.addr & 0x1F); - setprg16(0xC000, latch.addr & 0x1F); - } - setmirror(((latch.addr >> 5) & 1) ^ 1); -} - -void Mapper229_Init(CartInfo *info) { - Latch_Init(info, M229Sync, NULL, 0, 0); -} - -/*------------------ Map 231 ---------------------------*/ - -static void M231Sync(void) { - setchr8(0); - if (latch.addr & 0x20) - setprg32(0x8000, (latch.addr >> 1) & 0x0F); - else { - setprg16(0x8000, latch.addr & 0x1E); - setprg16(0xC000, latch.addr & 0x1E); - } - setmirror(((latch.addr >> 7) & 1) ^ 1); -} - -void Mapper231_Init(CartInfo *info) { - Latch_Init(info, M231Sync, NULL, 0, 0); -} - -/*------------------ Map 242 ---------------------------*/ - -static uint8 M242TwoChips; -static void M242Sync(void) { - uint32 S = latch.addr & 1; - uint32 p = (latch.addr >> 2) & 0x1F; - uint32 L = (latch.addr >> 9) & 1; - - if (M242TwoChips) { - if (latch.addr & 0x600) { /* First chip */ - p &= ((ROM_size & ~8) - 1); - } else { /* Second chip */ - p &= 0x07; - p += (ROM_size & ~8); - } - } - - if ((latch.addr >> 7) & 1) { - if (S) { - setprg32(0x8000, p >> 1); - } else { - setprg16(0x8000, p); - setprg16(0xC000, p); - } - } else { - if (S) { - if (L) { - setprg16(0x8000, p & 0x3E); - setprg16(0xC000, p | 7); - } else { - setprg16(0x8000, p & 0x3E); - setprg16(0xC000, p & 0x38); - } - } else { - if (L) { - setprg16(0x8000, p); - setprg16(0xC000, p | 7); - } else { - setprg16(0x8000, p); - setprg16(0xC000, p & 0x38); - } - } - } - - if (!hasBattery && (latch.addr & 0x80) == 0x80 && (ROM_size * 16) > 256) - /* CHR-RAM write protect hack, needed for some multicarts */ - SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0); - else - SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1); - - setmirror(((latch.addr >> 1) & 1) ^ 1); - setchr8(0); - setprg8r(0x10, 0x6000, 0); -} - -static DECLFR(M242Read) { - if (latch.addr & 0x100) { - A |= dipswitch; - } - return CartBROB(A); -} - -static void M242Power() { - LatchPower(); - - dipswitch = 0; - SetReadHandler(0x8000, 0xFFFF, M242Read); -} - -static void M242Reset() { - dipswitch = (dipswitch + 1) & 0x1F; - LatchHardReset(); -} - -void Mapper242_Init(CartInfo *info) { - Latch_Init(info, M242Sync, NULL, 1, 0); - info->Power = M242Power; - info->Reset = M242Reset; - M242TwoChips = info->PRGRomSize & 0x20000 && info->PRGRomSize > 0x20000; - hasBattery = info->battery; - AddExState(&dipswitch, 1, 0, "PADS"); -} - -/*------------------ Map 288 ---------------------------*/ -/* NES 2.0 Mapper 288 is used for two GKCX1 21-in-1 multicarts - * - 21-in-1 (GA-003) - * - 64-in-1 (CF-015) - */ -static void M288Sync(void) { - setchr8(latch.addr & 7); - setprg32(0x8000, (latch.addr >> 3) & 3); -} - -static DECLFR(M288Read) { - uint8 ret = CartBR(A); - if (latch.addr & 0x20) - ret |= (dipswitch << 2); - return ret; -} - -static void M288Reset(void) { - dipswitch++; - dipswitch &= 3; - M288Sync(); -} - -void Mapper288_Init(CartInfo *info) { - dipswitch = 0; - Latch_Init(info, M288Sync, M288Read, 0, 0); - info->Reset = M288Reset; - AddExState(&dipswitch, 1, 0, "DIPSW"); -} - -/*------------------ Map 385 ---------------------------*/ - -static void M385Sync(void) { - setprg16(0x8000, latch.addr >> 1); - setprg16(0xc000, latch.addr >> 1); - setmirror((latch.addr & 1) ^ 1); - setchr8(0); -} - -void Mapper385_Init(CartInfo *info) { - Latch_Init(info, M385Sync, NULL, 0, 1); - info->Reset = LatchHardReset; -} - -/*------------------ Map 541 ---------------------------*/ -/* LittleCom 160-in-1 multicart */ -static void M541Sync(void) { - if (latch.addr & 2) { - /* NROM-128 */ - setprg16(0x8000, latch.addr >> 2); - setprg16(0xC000, latch.addr >> 2); - } else { - /* NROM=256 */ - setprg32(0x8000, latch.addr >> 3); - } - setchr8(0); - setmirror(latch.addr & 1); -} - -static void M541Write(uint32 A, uint8 V) { - if (A >= 0xC000) { - latch.addr = A; - M541Sync(); - } -} - -static void M541Power() { - LatchPower(); - SetWriteHandler(0x8000, 0xFFFF, M541Write); -} - -void Mapper541_Init(CartInfo *info) { - Latch_Init(info, M541Sync, NULL, 0, 0); - info->Power = M541Power; - info->Reset = LatchHardReset; -} - -/*------------------ BMC-190in1 ---------------------------*/ -/* NES 2.0 Mapper 300 */ - -static void BMC190in1Sync(void) { - setprg16(0x8000, (latch.addr >> 2) & 7); - setprg16(0xC000, (latch.addr >> 2) & 7); - setchr8((latch.addr >> 2) & 7); - setmirror((latch.addr & 1) ^ 1); -} - -void BMC190in1_Init(CartInfo *info) { - Latch_Init(info, BMC190in1Sync, NULL, 0, 0); -} - -/*-------------- BMC810544-C-A1 ------------------------*/ -/* NES 2.0 Mapper 261 */ - -static void BMC810544CA1Sync(void) { - uint32 bank = latch.addr >> 7; - if (latch.addr & 0x40) - setprg32(0x8000, bank); - else { - setprg16(0x8000, (bank << 1) | ((latch.addr >> 5) & 1)); - setprg16(0xC000, (bank << 1) | ((latch.addr >> 5) & 1)); - } - setchr8(latch.addr & 0x0f); - setmirror(((latch.addr >> 4) & 1) ^ 1); -} - -void BMC810544CA1_Init(CartInfo *info) { - Latch_Init(info, BMC810544CA1Sync, NULL, 0, 0); -} - -/*-------------- BMCNTD-03 ------------------------*/ -/* NES 2.0 Mapper 290 */ - -static void BMCNTD03Sync(void) { - /* 1PPP Pmcc spxx xccc - * 1000 0000 0000 0000 v - * 1001 1100 0000 0100 h - * 1011 1010 1100 0100 - */ - uint32 prg = ((latch.addr >> 10) & 0x1e); - uint32 chr = ((latch.addr & 0x0300) >> 5) | (latch.addr & 7); - if (latch.addr & 0x80) { - setprg16(0x8000, prg | ((latch.addr >> 6) & 1)); - setprg16(0xC000, prg | ((latch.addr >> 6) & 1)); - } else - setprg32(0x8000, prg >> 1); - setchr8(chr); - setmirror(((latch.addr >> 10) & 1) ^ 1); -} - -void BMCNTD03_Init(CartInfo *info) { - Latch_Init(info, BMCNTD03Sync, NULL, 0, 0); - info->Reset = LatchHardReset; -} - -/*-------------- BMCG-146 ------------------------*/ -/* NES 2.0 Mapper 349 */ - -static void BMCG146Sync(void) { - setchr8(0); - if (latch.addr & 0x800) { /* UNROM mode */ - setprg16(0x8000, (latch.addr & 0x1F) | (latch.addr & ((latch.addr & 0x40) >> 6))); - setprg16(0xC000, (latch.addr & 0x18) | 7); - } else { - if (latch.addr & 0x40) { /* 16K mode */ - setprg16(0x8000, latch.addr & 0x1F); - setprg16(0xC000, latch.addr & 0x1F); - } else { - setprg32(0x8000, (latch.addr >> 1) & 0x0F); - } - } - setmirror(((latch.addr & 0x80) >> 7) ^ 1); -} - -void BMCG146_Init(CartInfo *info) { - Latch_Init(info, BMCG146Sync, NULL, 0, 0); -} - -/*-------------- BMC-TJ-03 ------------------------*/ -/* NES 2.0 mapper 341 is used for a simple 4-in-1 multicart */ - -static void BMCTJ03Sync(void) { - uint8 mirr = (latch.addr & ((PRGsize[0] & 0x40000) ? 0x800 : 0x200)) ? MI_H : MI_V; - setprg32(0x8000, latch.addr >> 8); - setchr8(latch.addr >> 8); - setmirror(mirr); -} - -void BMCTJ03_Init(CartInfo *info) { - Latch_Init(info, BMCTJ03Sync, NULL, 0, 0); - info->Reset = LatchHardReset; -} - -/*-------------- 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, latch.addr & 0x0F); - setprg16(0xC000, latch.addr & 0x0F); - setchr8(latch.addr & 0x0F); - setmirror((latch.addr >> 3) & 1); -} - -void BMCSA005A_Init(CartInfo *info) { - Latch_Init(info, BMCSA005ASync, NULL, 0, 0); - info->Reset = LatchHardReset; -} - -/* -------------- Mapper 402 ------------------------ */ - -static void M402Sync(void) { - if (latch.addr & 0x800) { - setprg8(0x6000, ((latch.addr & 0x1F) << 1) | 3); - } - if ((latch.addr & 0x40)) { - setprg16(0x8000, latch.addr & 0x1F); - setprg16(0xC000, latch.addr & 0x1F); - } else { - setprg32(0x8000, (latch.addr & 0x1F) >> 1); - } - if ((latch.addr & 0x400) == 0) { - SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0); - } else { - SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1); - } - setchr8(0); - setmirror(((latch.addr >> 7) & 1) ^ 1); -} - -void Mapper402_Init(CartInfo *info) { - Latch_Init(info, M402Sync, NULL, 0, 0); - info->Reset = LatchHardReset; -} - -/* -------------- Mapper 409 ------------------------ */ -static void M409Sync(void) { - setprg16(0x8000, latch.addr); - setprg16(0xC000, ~0); - setchr8(0); -} - -void Mapper409_Init(CartInfo *info) { - Latch_Init(info, M409Sync, NULL, 0, 0); -} - -/*------------------ Map 435 ---------------------------*/ -static void M435Sync(void) { - int p = ((latch.addr >> 2) & 0x1F) | ((latch.addr >> 3) & 0x20) | ((latch.addr >> 4) & 0x40); - if (latch.addr & 0x200) { - if (latch.addr & 0x001) { - setprg16(0x8000, p); - setprg16(0xC000, p); - } else { - setprg32(0x8000, p >> 1); - } - } else { - setprg16(0x8000, p); - setprg16(0xC000, p | 7); - } - - if (latch.addr & 0x800) - SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0); - else - SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1); - - setmirror(((latch.addr >> 1) & 1) ^ 1); - setchr8(0); -} - -void Mapper435_Init(CartInfo *info) { - Latch_Init(info, M435Sync, NULL, 1, 0); - info->Reset = LatchHardReset; -} diff --git a/src/boards/bandai.c b/src/boards/bandai.c deleted file mode 100644 index 4d8e57011..000000000 --- a/src/boards/bandai.c +++ /dev/null @@ -1,623 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2007 CaH4e3 - * Copyright (C) 2011 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 - * - * Bandai mappers - * - */ - -#include "mapinc.h" - -static uint8 reg[16], is153, x24c02; -static uint8 IRQa; -static int16 IRQCount, IRQLatch; - -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; - -static SFORMAT StateRegs[] = -{ - { reg, 16, "REGS" }, - { &IRQa, 1, "IRQA" }, - { &IRQCount, 2, "IRQC" }, - { &IRQLatch, 2, "IRQL" }, /* need for Famicom Jump II - Saikyou no 7 Nin (J) [!] */ - { 0 } -}; - -/* x24C0x interface */ - -#define X24C0X_STANDBY 0 -#define X24C0X_ADDRESS 1 -#define X24C0X_WORD 2 -#define X24C0X_READ 3 -#define X24C0X_WRITE 4 - -static uint8 x24c0x_data[512]; - -static uint8 x24c01_state; -static uint8 x24c01_addr, x24c01_word, x24c01_latch, x24c01_bitcount; -static uint8 x24c01_sda, x24c01_scl, x24c01_out; - -static uint8 x24c02_state; -static uint8 x24c02_addr, x24c02_word, x24c02_latch, x24c02_bitcount; -static uint8 x24c02_sda, x24c02_scl, x24c02_out; - -static SFORMAT x24c01StateRegs[] = -{ - { &x24c01_addr, 1, "ADDR" }, - { &x24c01_word, 1, "WORD" }, - { &x24c01_latch, 1, "LATC" }, - { &x24c01_bitcount, 1, "BITC" }, - { &x24c01_sda, 1, "SDA" }, - { &x24c01_scl, 1, "SCL" }, - { &x24c01_out, 1, "OUT" }, - { &x24c01_state, 1, "STAT" }, - { 0 } -}; - -static SFORMAT x24c02StateRegs[] = -{ - { &x24c02_addr, 1, "ADDR" }, - { &x24c02_word, 1, "WORD" }, - { &x24c02_latch, 1, "LATC" }, - { &x24c02_bitcount, 1, "BITC" }, - { &x24c02_sda, 1, "SDA" }, - { &x24c02_scl, 1, "SCL" }, - { &x24c02_out, 1, "OUT" }, - { &x24c02_state, 1, "STAT" }, - { 0 } -}; - -static void x24c01_init(void) { - x24c01_addr = x24c01_word = x24c01_latch = x24c01_bitcount = x24c01_sda = x24c01_scl = 0; - x24c01_state = X24C0X_STANDBY; -} - -static void x24c02_init(void) { - x24c02_addr = x24c02_word = x24c02_latch = x24c02_bitcount = x24c02_sda = x24c02_scl = 0; - x24c02_state = X24C0X_STANDBY; -} - -static void x24c01_write(uint8 data) { - uint8 scl = (data >> 5) & 1; - uint8 sda = (data >> 6) & 1; - - if(x24c01_scl && scl) { - if(x24c01_sda && !sda) { /* START */ - x24c01_state = X24C0X_ADDRESS; - x24c01_bitcount = 0; - x24c01_addr = 0; - } else if(!x24c01_sda && sda) { /* STOP */ - x24c01_state = X24C0X_STANDBY; - } - } else if(!x24c01_scl && scl) { /* RISING EDGE */ - switch(x24c01_state) { - case X24C0X_ADDRESS: - if(x24c01_bitcount < 7) { - x24c01_addr <<= 1; - x24c01_addr |= sda; - } else { - x24c01_word = x24c01_addr; - if(sda) /* READ COMMAND */ - x24c01_state = X24C0X_READ; - else /* WRITE COMMAND */ - x24c01_state = X24C0X_WRITE; - } - x24c01_bitcount++; - break; - case X24C0X_READ: - if (x24c01_bitcount == 8) { /* ACK */ - x24c01_out = 0; - x24c01_latch = x24c0x_data[x24c01_word]; - x24c01_bitcount = 0; - } else { /* REAL OUTPUT */ - x24c01_out = x24c01_latch >> 7; - x24c01_latch <<= 1; - x24c01_bitcount++; - if(x24c01_bitcount == 8) { - x24c01_word++; - x24c01_word &= 0xff; - } - } - break; - case X24C0X_WRITE: - if (x24c01_bitcount == 8) { /* ACK */ - x24c01_out = 0; - x24c01_latch = 0; - x24c01_bitcount = 0; - } else { /* REAL INPUT */ - x24c01_latch <<= 1; - x24c01_latch |= sda; - x24c01_bitcount++; - if(x24c01_bitcount == 8) { - x24c0x_data[x24c01_word] = x24c01_latch; - x24c01_word++; - x24c01_word &= 0xff; - } - } - break; - } - } - - x24c01_sda = sda; - x24c01_scl = scl; -} - -static void x24c02_write(uint8 data) { - uint8 scl = (data >> 5) & 1; - uint8 sda = (data >> 6) & 1; - - if (x24c02_scl && scl) { - if (x24c02_sda && !sda) { /* START */ - x24c02_state = X24C0X_ADDRESS; - x24c02_bitcount = 0; - x24c02_addr = 0; - } else if (!x24c02_sda && sda) { /* STOP */ - x24c02_state = X24C0X_STANDBY; - } - } else if (!x24c02_scl && scl) { /* RISING EDGE */ - switch (x24c02_state) { - case X24C0X_ADDRESS: - if (x24c02_bitcount < 7) { - x24c02_addr <<= 1; - x24c02_addr |= sda; - } else { - if (sda) /* READ COMMAND */ - x24c02_state = X24C0X_READ; - else /* WRITE COMMAND */ - x24c02_state = X24C0X_WORD; - } - x24c02_bitcount++; - break; - case X24C0X_WORD: - if (x24c02_bitcount == 8) { /* ACK */ - x24c02_word = 0; - x24c02_out = 0; - } else { /* WORD ADDRESS INPUT */ - x24c02_word <<= 1; - x24c02_word |= sda; - if (x24c02_bitcount == 16) { /* END OF ADDRESS INPUT */ - x24c02_bitcount = 7; - x24c02_state = X24C0X_WRITE; - } - } - x24c02_bitcount++; - break; - case X24C0X_READ: - if (x24c02_bitcount == 8) { /* ACK */ - x24c02_out = 0; - x24c02_latch = x24c0x_data[x24c02_word|0x100]; - x24c02_bitcount = 0; - } else { /* REAL OUTPUT */ - x24c02_out = x24c02_latch >> 7; - x24c02_latch <<= 1; - x24c02_bitcount++; - if (x24c02_bitcount == 8) { - x24c02_word++; - x24c02_word &= 0xff; - } - } - break; - case X24C0X_WRITE: - if (x24c02_bitcount == 8) { /* ACK */ - x24c02_out = 0; - x24c02_latch = 0; - x24c02_bitcount = 0; - } else { /* REAL INPUT */ - x24c02_latch <<= 1; - x24c02_latch |= sda; - x24c02_bitcount++; - if (x24c02_bitcount == 8) { - x24c0x_data[x24c02_word|0x100] = x24c02_latch; - x24c02_word++; - x24c02_word &= 0xff; - } - } - break; - } - } - - x24c02_sda = sda; - x24c02_scl = scl; -} - -static void SyncMirror(void) { - switch (reg[9] & 3) { - case 0: setmirror(MI_V); break; - case 1: setmirror(MI_H); break; - case 2: setmirror(MI_0); break; - case 3: setmirror(MI_1); break; - } -} - -static void Sync(void) { - if (is153) { - int base = (reg[0] & 1) << 4; - setchr8(0); - setprg16(0x8000, (reg[8] & 0x0F) | base); - setprg16(0xC000, 0x0F | base); - } else { - int i; - for (i = 0; i < 8; i++) setchr1(i << 10, reg[i]); - setprg16(0x8000, reg[8]); - setprg16(0xC000, ~0); - } - SyncMirror(); -} - -static DECLFW(BandaiWrite) { - A &= 0x0F; - if (A < 0x0A) { - reg[A & 0x0F] = V; - Sync(); - } else - switch (A) { - case 0x0A: X6502_IRQEnd(FCEU_IQEXT); IRQa = V & 1; IRQCount = IRQLatch; break; - case 0x0B: IRQLatch &= 0xFF00; IRQLatch |= V; break; - case 0x0C: IRQLatch &= 0xFF; IRQLatch |= V << 8; break; - case 0x0D: - if (x24c02) - x24c02_write(V); - else - x24c01_write(V); - break; - } -} - -static DECLFR(BandaiRead) { - if (x24c02) - return (X.DB & 0xEF) | (x24c02_out << 4); - else - return (X.DB & 0xEF) | (x24c01_out << 4); -} - -static void FP_FASTAPASS(1) BandaiIRQHook(int a) { - if (IRQa) { - IRQCount -= a; - if (IRQCount < 0) { - X6502_IRQBegin(FCEU_IQEXT); - IRQa = 0; - IRQCount = -1; - } - } -} - -static void BandaiPower(void) { - IRQa = 0; - if (x24c02) - x24c02_init(); - else - x24c01_init(); - Sync(); - SetReadHandler(0x6000, 0x7FFF, BandaiRead); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0xFFFF, BandaiWrite); -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper16_Init(CartInfo *info) { - x24c02 = 1; - is153 = 0; - info->Power = BandaiPower; - MapIRQHook = BandaiIRQHook; - - info->battery = 1; - info->SaveGame[0] = x24c0x_data + 256; - info->SaveGameLen[0] = 256; - AddExState(x24c0x_data, 256, 0, "DATA"); - - GameStateRestore = StateRestore; - AddExState(&x24c02StateRegs, ~0, 0, 0); - AddExState(&StateRegs, ~0, 0, 0); -} - -void Mapper159_Init(CartInfo *info) { - x24c02 = 0; - is153 = 0; - info->Power = BandaiPower; - MapIRQHook = BandaiIRQHook; - - info->battery = 1; - info->SaveGame[0] = x24c0x_data; - info->SaveGameLen[0] = 128; - AddExState(x24c0x_data, 128, 0, "DATA"); - - GameStateRestore = StateRestore; - AddExState(&x24c01StateRegs, ~0, 0, 0); - AddExState(&StateRegs, ~0, 0, 0); -} - -/* Famicom jump 2: - * 0-7: Lower bit of data selects which 256KB PRG block is in use. - * This seems to be a hack on the developers' part, so I'll make emulation - * of it a hack(I think the current PRG block would depend on whatever the - * lowest bit of the CHR bank switching register that corresponds to the - * last CHR address read). - */ - -static void M153Power(void) { - Sync(); - setprg8r(0x10, 0x6000, 0); - SetReadHandler(0x6000, 0x7FFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, BandaiWrite); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); -} - - -static void M153Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -void Mapper153_Init(CartInfo *info) { - is153 = 1; - info->Power = M153Power; - info->Close = M153Close; - MapIRQHook = BandaiIRQHook; - - WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - - if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; - } - - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} - -/* Datach Barcode Battler */ - -static uint8 BarcodeData[256]; -static int BarcodeReadPos; -static int BarcodeCycleCount; -static uint32 BarcodeOut; - -/* #define INTERL2OF5 */ - -int FCEUI_DatachSet(uint8 *rcode) { - int prefix_parity_type[10][6] = { - { 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 1, 1 }, { 0, 0, 1, 1, 0, 1 }, { 0, 0, 1, 1, 1, 0 }, - { 0, 1, 0, 0, 1, 1 }, { 0, 1, 1, 0, 0, 1 }, { 0, 1, 1, 1, 0, 0 }, { 0, 1, 0, 1, 0, 1 }, - { 0, 1, 0, 1, 1, 0 }, { 0, 1, 1, 0, 1, 0 } - }; - int data_left_odd[10][7] = { - { 0, 0, 0, 1, 1, 0, 1 }, { 0, 0, 1, 1, 0, 0, 1 }, { 0, 0, 1, 0, 0, 1, 1 }, { 0, 1, 1, 1, 1, 0, 1 }, - { 0, 1, 0, 0, 0, 1, 1 }, { 0, 1, 1, 0, 0, 0, 1 }, { 0, 1, 0, 1, 1, 1, 1 }, { 0, 1, 1, 1, 0, 1, 1 }, - { 0, 1, 1, 0, 1, 1, 1 }, { 0, 0, 0, 1, 0, 1, 1 } - }; - int data_left_even[10][7] = { - { 0, 1, 0, 0, 1, 1, 1 }, { 0, 1, 1, 0, 0, 1, 1 }, { 0, 0, 1, 1, 0, 1, 1 }, { 0, 1, 0, 0, 0, 0, 1 }, - { 0, 0, 1, 1, 1, 0, 1 }, { 0, 1, 1, 1, 0, 0, 1 }, { 0, 0, 0, 0, 1, 0, 1 }, { 0, 0, 1, 0, 0, 0, 1 }, - { 0, 0, 0, 1, 0, 0, 1 }, { 0, 0, 1, 0, 1, 1, 1 } - }; - int data_right[10][7] = { - { 1, 1, 1, 0, 0, 1, 0 }, { 1, 1, 0, 0, 1, 1, 0 }, { 1, 1, 0, 1, 1, 0, 0 }, { 1, 0, 0, 0, 0, 1, 0 }, - { 1, 0, 1, 1, 1, 0, 0 }, { 1, 0, 0, 1, 1, 1, 0 }, { 1, 0, 1, 0, 0, 0, 0 }, { 1, 0, 0, 0, 1, 0, 0 }, - { 1, 0, 0, 1, 0, 0, 0 }, { 1, 1, 1, 0, 1, 0, 0 } - }; - uint8 code[13 + 1]; - uint32 tmp_p = 0; - uint32 csum = 0; - int i, j; - int len; - - for (i = len = 0; i < 13; i++) { - if (!rcode[i]) break; - if ((code[i] = rcode[i] - '0') > 9) - return(0); - len++; - } - if (len != 13 && len != 12 && len != 8 && len != 7) return(0); - - #define BS(x) BarcodeData[tmp_p] = x; tmp_p++ - - for (j = 0; j < 32; j++) { /* delay before sending a code */ - BS(0x00); - } - -#ifdef INTERL2OF5 - - BS(1); BS(1); BS(0); BS(0); /* 1 */ - BS(1); BS(1); BS(0); BS(0); /* 1 */ - BS(1); BS(1); BS(0); BS(0); /* 1 */ - BS(1); BS(1); BS(0); BS(0); /* 1 */ - BS(1); BS(1); BS(0); BS(0); /* 1 */ - BS(1); BS(0); BS(0); /* 0 */ - BS(1); BS(0); BS(0); /* 0 */ - BS(1); BS(0); BS(0); /* 0 */ - BS(1); BS(0); BS(0); /* 0 */ - BS(1); BS(0); BS(0); /* 0 */ - BS(1); BS(0); BS(0); /* 0 */ - BS(1); BS(0); BS(0); /* 0 */ - BS(1); BS(0); BS(0); /* 0 */ - BS(1); BS(0); BS(0); /* 0 */ - BS(1); BS(0); BS(0); /* 0 */ - BS(1); BS(0); BS(0); /* 0 */ - BS(1); BS(0); BS(0); /* 0 */ - BS(1); BS(0); BS(0); /* 0 */ - BS(1); BS(0); BS(0); /* 0 */ - BS(1); BS(0); BS(0); /* 0 */ - BS(1); BS(0); BS(0); /* 0 */ - BS(1); BS(0); BS(0); /* 0 */ - BS(1); BS(0); BS(0); /* 0 */ - BS(1); BS(0); BS(0); /* 0 */ - BS(1); BS(0); BS(0); /* 0 */ - BS(1); BS(0); BS(0); /* 0 cs */ - BS(1); BS(1); BS(0); BS(0); /* 1 */ - -#else - /* Left guard bars */ - BS(1); BS(0); BS(1); - - if (len == 13 || len == 12) { - - for (i = 0; i < 6; i++) - if (prefix_parity_type[code[0]][i]) { - for (j = 0; j < 7; j++) { - BS(data_left_even[code[i + 1]][j]); - } - } else - for (j = 0; j < 7; j++) { - BS(data_left_odd[code[i + 1]][j]); - } - - /* Center guard bars */ - BS(0); BS(1); BS(0); BS(1); BS(0); - - for (i = 7; i < 12; i++) - for (j = 0; j < 7; j++) { - BS(data_right[code[i]][j]); - } - /* Calc and write down the control code if not assigned, instead, send code as is - Battle Rush uses modified type of codes with different control code calculation */ - if (len == 12) { - for (i = 0; i < 12; i++) - csum += code[i] * ((i & 1) ? 3 : 1); - csum = (10 - (csum % 10)) % 10; - rcode[12] = csum + 0x30; /* update check code to the input string as well */ - rcode[13] = 0; - code[12] = csum; - } - for (j = 0; j < 7; j++) { - BS(data_right[code[12]][j]); - } - } else if (len == 8 || len == 7) { - for (i = 0; i < 4; i++) { - for (j = 0; j < 7; j++) { - BS(data_left_odd[code[i]][j]); - } - } - - /* Center guard bars */ - BS(0); BS(1); BS(0); BS(1); BS(0); - - for (i = 4; i < 7; i++) - for (j = 0; j < 7; j++) { - BS(data_right[code[i]][j]); - } - csum = 0; - for (i = 0; i < 7; i++) - csum += (i & 1) ? code[i] : (code[i] * 3); - csum = (10 - (csum % 10)) % 10; - rcode[7] = csum + 0x30; /* update check code to the input string as well */ - rcode[8] = 0; - for (j = 0; j < 7; j++) { - BS(data_right[csum][j]); - } - } - - /* Right guard bars */ - BS(1); BS(0); BS(1); -#endif - - for (j = 0; j < 32; j++) { - BS(0x00); - } - - BS(0xFF); - - #undef BS - - BarcodeReadPos = 0; - BarcodeOut = 0x8; - BarcodeCycleCount = 0; - return(1); -} - -static void BarcodeSync(void) { - setchr8(0); - setprg16(0x8000, (reg[8] & 0x0F)); - setprg16(0xC000, 0x0F); - SyncMirror(); -} - -static DECLFW(BarcodeWrite) { - A &= 0x0F; - switch (A) { - case 0x00: reg[0] = (V & 8) << 2; x24c01_write(reg[0xD] | reg[0]); break; /* extra EEPROM x24C01 used in Battle Rush mini-cart */ - case 0x08: - case 0x09: reg[A] = V; BarcodeSync(); break; - case 0x0A: X6502_IRQEnd(FCEU_IQEXT); IRQa = V & 1; IRQCount = IRQLatch; break; - case 0x0B: IRQLatch &= 0xFF00; IRQLatch |= V; break; - case 0x0C: IRQLatch &= 0xFF; IRQLatch |= V << 8; break; - case 0x0D: reg[0xD] = V & (~0x20); x24c01_write(reg[0xD] | reg[0]); x24c02_write(V); break; - } -} - -static void FP_FASTAPASS(1) BarcodeIRQHook(int a) { - BandaiIRQHook(a); - - BarcodeCycleCount += a; - - if (BarcodeCycleCount >= 1000) { - BarcodeCycleCount -= 1000; - if (BarcodeData[BarcodeReadPos] == 0xFF) { - BarcodeOut = 0; - } else { - BarcodeOut = (BarcodeData[BarcodeReadPos] ^ 1) << 3; - BarcodeReadPos++; - } - } -} - -static DECLFR(BarcodeRead) { - return (X.DB & 0xE7) | ((x24c02_out | x24c01_out) << 4) | BarcodeOut; -} - -static void M157Power(void) { - IRQa = 0; - BarcodeData[0] = 0xFF; - BarcodeReadPos = 0; - BarcodeOut = 0; - BarcodeCycleCount = 0; - - x24c01_init(); - x24c02_init(); - BarcodeSync(); - - SetReadHandler(0x6000, 0x7FFF, BarcodeRead); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, BarcodeWrite); -} - -void Mapper157_Init(CartInfo *info) { - x24c02 = 1; - info->Power = M157Power; - MapIRQHook = BarcodeIRQHook; - - GameInfo->cspecial = SIS_DATACH; - info->battery = 1; - info->SaveGame[0] = x24c0x_data; - info->SaveGameLen[0] = 512; - GameStateRestore = StateRestore; - AddExState(x24c0x_data, 512, 0, "DATA"); - AddExState(&x24c01StateRegs, ~0, 0, 0); - AddExState(&x24c02StateRegs, ~0, 0, 0); - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/bmc12in1.c b/src/boards/bmc12in1.c deleted file mode 100644 index ff9a9ff88..000000000 --- a/src/boards/bmc12in1.c +++ /dev/null @@ -1,81 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2009 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 - * - * 7-in-1 Darkwing Duck, Snake, MagicBlock (PCB marked as "12 in 1") - * 12-in-1 1991 New Star Co. Ltd. - * - */ - -#include "mapinc.h" - -static uint8 prgchr[2], ctrl; -static SFORMAT StateRegs[] = -{ - { prgchr, 2, "REGS" }, - { &ctrl, 1, "CTRL" }, - { 0 } -}; - -static void Sync(void) { - uint8 bank = (ctrl & 3) << 3; - setchr4(0x0000, (prgchr[0] >> 3) | (bank << 2)); - setchr4(0x1000, (prgchr[1] >> 3) | (bank << 2)); - if (ctrl & 8) { - setprg16(0x8000, bank | (prgchr[0] & 6) | 0); /* actually, both 0 and 1 registers used, but they will switch each PA12 transition */ - setprg16(0xc000, bank | (prgchr[0] & 6) | 1); /* if bits are different for both registers, so they must be programmed strongly the same! */ - } else { - setprg16(0x8000, bank | (prgchr[0] & 7)); - setprg16(0xc000, bank | 7); - } - setmirror(((ctrl & 4) >> 2) ^ 1); -} - -static DECLFW(BMC12IN1Write) { - switch (A & 0xE000) { - case 0xA000: - prgchr[0] = V; - Sync(); - break; - case 0xC000: - prgchr[1] = V; - Sync(); - break; - case 0xE000: - ctrl = V & 0x0F; - Sync(); - break; - } -} - -static void BMC12IN1Power(void) { - prgchr[0] = prgchr[1] = ctrl = 0; - Sync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, BMC12IN1Write); -} - -static void StateRestore(int version) { - Sync(); -} - -void BMC12IN1_Init(CartInfo *info) { - info->Power = BMC12IN1Power; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/bmc830118C.c b/src/boards/bmc830118C.c deleted file mode 100644 index 5c2992815..000000000 --- a/src/boards/bmc830118C.c +++ /dev/null @@ -1,68 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2008 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 - */ - -/* NES 2.0 Mapper 348 - * M-022 MMC3 based 830118C T-106 4M + 4M */ - -#include "mapinc.h" -#include "mmc3.h" - -static void BMC830118CCW(uint32 A, uint8 V) { - setchr1(A, ((mmc3.expregs[0] << 5) & 0x180) | (V & 0x7F)); -} - -static void BMC830118CPW(uint32 A, uint8 V) { - if ((mmc3.expregs[0] & 0x0C) == 0x0C) { - setprg8(0x8000, ((mmc3.expregs[0] << 2) & 0x30) | ((mmc3.regs[6] & ~2) & 0x0F)); - setprg8(0xA000, ((mmc3.expregs[0] << 2) & 0x30) | ((mmc3.regs[7] & ~2) & 0x0F)); - setprg8(0xC000, ((mmc3.expregs[0] << 2) & 0x30) | ((mmc3.regs[6] | 2) & 0x0F)); - setprg8(0xE000, ((mmc3.expregs[0] << 2) & 0x30) | ((mmc3.regs[7] | 2) & 0x0F)); - } else { - setprg8(A, ((mmc3.expregs[0] << 2) & 0x30) | (V & 0x0F)); - } -} - -static DECLFW(BMC830118CLoWrite) { - if (MMC3CanWriteToWRAM()) { - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } -} - -static void BMC830118CReset(void) { - mmc3.expregs[0] = 0; - MMC3RegReset(); -} - -static void BMC830118CPower(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); - SetWriteHandler(0x6800, 0x68FF, BMC830118CLoWrite); -} - -void BMC830118C_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 128, 0, 0); - mmc3.pwrap = BMC830118CPW; - mmc3.cwrap = BMC830118CCW; - info->Power = BMC830118CPower; - info->Reset = BMC830118CReset; - AddExState(mmc3.expregs, 1, 0, "EXPR"); -} diff --git a/src/boards/bmc830134C.c b/src/boards/bmc830134C.c deleted file mode 100644 index eb6618413..000000000 --- a/src/boards/bmc830134C.c +++ /dev/null @@ -1,70 +0,0 @@ -/* 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, ((mmc3.expregs[0] << 8) & 0x100) | ((mmc3.expregs[0] << 6) & 0x80) | ((mmc3.expregs[0] << 3) & 0x40) | V); -} - -static void BMC830134CPW(uint32 A, uint8 V) { - if ((mmc3.expregs[0] & 0x06) == 0x06) { - setprg8(0x8000, ((mmc3.expregs[0] << 3) & 0x30) | ((mmc3.regs[6] & ~2) & 0x0F)); - setprg8(0xA000, ((mmc3.expregs[0] << 3) & 0x30) | ((mmc3.regs[7] & ~2) & 0x0F)); - setprg8(0xC000, ((mmc3.expregs[0] << 3) & 0x30) | ((mmc3.regs[6] | 2) & 0x0F)); - setprg8(0xE000, ((mmc3.expregs[0] << 3) & 0x30) | ((mmc3.regs[7] | 2) & 0x0F)); - } else { - setprg8(A, (V & 0x0F) | ((mmc3.expregs[0] & 0x06) << 3)); - } -} - -static DECLFW(BMC830134CWrite) { - if (MMC3CanWriteToWRAM()) { - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } -} - -static void BMC830134CReset(void) { - mmc3.expregs[0] = 0; - MMC3RegReset(); -} - -static void BMC830134CPower(void) { - GenMMC3Power(); - SetWriteHandler(0x6800, 0x68FF, BMC830134CWrite); -} - -void BMC830134C_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 256, 0, 0); - mmc3.pwrap = BMC830134CPW; - mmc3.cwrap = BMC830134CCW; - info->Power = BMC830134CPower; - info->Reset = BMC830134CReset; - AddExState(mmc3.expregs, 1, 0, "EXPR"); -} diff --git a/src/boards/bmcgamecard.c b/src/boards/bmcgamecard.c deleted file mode 100644 index 16f02c25f..000000000 --- a/src/boards/bmcgamecard.c +++ /dev/null @@ -1,127 +0,0 @@ -/* FCEUmm - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2019 Libretro Team - * Copyright (C) 2023 - * - * 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 isM350; -static uint8 latche; - -static SFORMAT StateRegs[] = { - { &latche, 1, "REG0" }, - { &isM350, 1, "M350" }, - { 0 } -}; - -static void Sync(void) { - uint8 mirr, mode, chrp; - uint8 bank = latche & 0x1F; - - if (isM350) { - mirr = ((latche >> 7) & 1); - mode = ((latche >> 5) & 3); - chrp = (latche & 0x40) != 0; - if (mode == 3) { - /* 2nd chip only has 128KB */ - bank &= 7; - bank |= 0x20; - } - } else { - mirr = ((latche >> 5) & 1); - mode = ((latche >> 6) & 3); - chrp = (latche & 0x80) != 0; - } - - setprg8(0x6000, 1); - switch (mode) { - case 0: /* NROM-128 */ - setprg16(0x8000, bank); - setprg16(0xC000, bank); - break; - case 1: /* NROM-256 */ - setprg32(0x8000, bank >> 1); - break; - case 2: - case 3: /* UNROM */ - setprg16(0x8000, bank); - setprg16(0xC000, bank | 7); - break; - } - - /* CHR-RAM Protect... kinda */ - SetupCartCHRMapping(0, CHRptr[0], 0x2000, chrp); - setchr8(0); - if (isM350 && (latche & 0x40)) { - /* use default mirroring */ - } else { - setmirror(mirr ^ 1); - } -} - -static DECLFW(GCOuterBankWrite) { - latche = (latche & 7) | (V & ~7); - Sync(); -} - -static DECLFW(GCInnerBankWrite) { - latche = (latche & ~7) | (V & 7); - Sync(); -} - -static void GCPower(void) { - Sync(); - SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xBFFF, GCOuterBankWrite); - SetWriteHandler(0xC000, 0xFFFF, GCInnerBankWrite); -} - -static void GCReset() { - latche = 0; /* always reset to menu */ - Sync(); -} - -static void StateRestore(int version) { - Sync(); -} - -static void GameCard_Init(CartInfo *info, int m350) { - isM350 = m350; - info->Power = GCPower; - info->Reset = GCReset; - GameStateRestore = StateRestore; - AddExState(StateRegs, ~0, 0, NULL); -} - -void BMCCTC12IN1_Init(CartInfo *info) { - GameCard_Init(info, 0); -} - -void BMC891227_Init(CartInfo *info) { - GameCard_Init(info, 1); -} diff --git a/src/boards/bmck3006.c b/src/boards/bmck3006.c deleted file mode 100644 index ebea2e69e..000000000 --- a/src/boards/bmck3006.c +++ /dev/null @@ -1,72 +0,0 @@ -/* 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) | (mmc3.expregs[0] & 0x18) << 4); -} - -static void BMCK3006PW(uint32 A, uint8 V) { - if (mmc3.expregs[0] & 0x20) { /* MMC3 mode */ - setprg8(A, (V & 0x0F) | (mmc3.expregs[0] & 0x18) << 1); - } else { - if ((mmc3.expregs[0] & 0x07) == 0x06) { /* NROM-256 */ - setprg32(0x8000, (mmc3.expregs[0] >> 1) & 0x0F); - } else { /* NROM-128 */ - setprg16(0x8000, mmc3.expregs[0] & 0x1F); - setprg16(0xC000, mmc3.expregs[0] & 0x1F); - } - } -} - -static DECLFW(BMCK3006Write) { - if (MMC3CanWriteToWRAM()) { - mmc3.expregs[0] = A & 0x3F; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } -} - -static void BMCK3006Reset(void) { - mmc3.expregs[0] = 0; - MMC3RegReset(); -} - -static void BMCK3006Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, BMCK3006Write); -} - -void BMCK3006_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 512, 8, 0); - mmc3.pwrap = BMCK3006PW; - mmc3.cwrap = BMCK3006CW; - info->Power = BMCK3006Power; - info->Reset = BMCK3006Reset; - AddExState(mmc3.expregs, 1, 0, "EXPR"); -} diff --git a/src/boards/bmck3033.c b/src/boards/bmck3033.c deleted file mode 100644 index d2965a66c..000000000 --- a/src/boards/bmck3033.c +++ /dev/null @@ -1,87 +0,0 @@ -/* 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 (mmc3.expregs[0] & 0x20) { - uint32 outer = ((mmc3.expregs[0] >> 4) & 4) | ((mmc3.expregs[0] >> 3) & 3); - if (mmc3.expregs[0] & 0x80) { - setchr1(A, (outer << 8) | (V & 0xFF)); - } else { - setchr1(A, (outer << 7) | (V & 0x7F)); - } - } else { - setchr1(A, (V & 0x7F)); - } -} - -static void BMCK3033PW(uint32 A, uint8 V) { - uint32 outer = ((mmc3.expregs[0] >> 4) & 4) | ((mmc3.expregs[0] >> 3) & 3); - if (mmc3.expregs[0] & 0x20) { - if (mmc3.expregs[0] & 0x80) { - setprg8(A, (outer << 5) | (V & 0x1F)); - } else { - setprg8(A, (outer << 4) | (V & 0x0F)); - } - } else { - if (mmc3.expregs[0] & 0x03) { - setprg32(0x8000, (outer << 3) | ((mmc3.expregs[0] >> 1) & 3)); - } else { - setprg16(0x8000, (outer << 3) | (mmc3.expregs[0] & 7)); - setprg16(0xC000, (outer << 3) | (mmc3.expregs[0] & 7)); - } - } -} - -static DECLFW(BMCK3033Write) { - if (MMC3CanWriteToWRAM()) { - mmc3.expregs[0] = A & 0xFF; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } -} - -static void BMCK3033Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, BMCK3033Write); -} - -static void BMCK3033Reset(void) { - mmc3.expregs[0] = 0; - MMC3RegReset(); -} - -void BMCK3033_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 0, 0); - mmc3.pwrap = BMCK3033PW; - mmc3.cwrap = BMCK3033CW; - info->Power = BMCK3033Power; - info->Reset = BMCK3033Reset; - AddExState(mmc3.expregs, 1, 0, "EXPR"); -} diff --git a/src/boards/bonza.c b/src/boards/bonza.c deleted file mode 100644 index f1d13c7ee..000000000 --- a/src/boards/bonza.c +++ /dev/null @@ -1,112 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2002 CaH4e3 - * Copyright (C) 2023 - * - * 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 "latch.h" - -#if 0 -#define CARD_EXTERNAL_INSERED 0x80 - -cmd[0] = response on/off - 0x00 - on - 0x80 - off -cmd[1] = cmd - - -_GET_CHALLENGE: .BYTE 0,$B4, 0, 0,$62 - -_SELECT_FILE_1_0200: .BYTE 0,$A4, 1, 0, 2, 2, 0 -_SELECT_FILE_2_0201: .BYTE 0,$A4, 2, 0, 2, 2, 1 -_SELECT_FILE_2_0203: .BYTE 0,$A4, 2, 0, 2, 2, 3 -_SELECT_FILE_2_0204: .BYTE 0,$A4, 2, 0, 2, 2, 4 -_SELECT_FILE_2_0205: .BYTE 0,$A4, 2, 0, 2, 2, 5 -_SELECT_FILE_2_3F04: .BYTE 0,$A4, 2, 0, 2,$3F, 4 -_SELECT_FILE_2_4F00: .BYTE 0,$A4, 2, 0, 2,$4F, 0 - -_READ_BINARY_5: .BYTE 0,$B0,$85, 0, 2 -_READ_BINARY_6: .BYTE 0,$B0,$86, 0, 4 -_READ_BINARY_6_0: .BYTE 0,$B0,$86, 0,$18 -_READ_BINARY_0: .BYTE 0,$B0, 0, 2, 3 -_READ_BINARY_0_0: .BYTE 0,$B0, 0, 0, 4 -_READ_BINARY_0_1: .BYTE 0,$B0, 0, 0, $C -_READ_BINARY_0_2: .BYTE 0,$B0, 0, 0,$10 - -_UPDATE_BINARY: .BYTE 0,$D6, 0, 0, 4 -_UPDATE_BINARY_0: .BYTE 0,$D6, 0, 0,$10 - -_GET_RESPONSE: .BYTE $80,$C0, 2,$A1, 8 -_GET_RESPONSE_0: .BYTE 0,$C0, 0, 0, 2 -_GET_RESPONSE_1: .BYTE 0,$C0, 0, 0, 6 -_GET_RESPONSE_2: .BYTE 0,$C0, 0, 0, 8 -_GET_RESPONSE_3: .BYTE 0,$C0, 0, 0, $C -_GET_RESPONSE_4: .BYTE 0,$C0, 0, 0,$10 - -byte_8C0B: .BYTE $80,$30, 0, 2, $A, 0, 1 -byte_8C48: .BYTE $80,$32, 0, 1, 4 -byte_8C89: .BYTE $80,$34, 0, 0, 8, 0, 0 -byte_8D01: .BYTE $80,$36, 0, 0, $C -byte_8CA7: .BYTE $80,$38, 0, 2, 4 -byte_8BEC: .BYTE $80,$3A, 0, 3, 0 - -byte_89A0: .BYTE 0,$48, 0, 0, 6 -byte_8808: .BYTE 0,$54, 0, 0,$1C -byte_89BF: .BYTE 0,$58, 0, 0,$1C - -_MANAGE_CHANNEL: .BYTE 0,$70, 0, 0, 8 -byte_8CE5: .BYTE 0,$74, 0, 0,$12 -byte_8C29: .BYTE 0,$76, 0, 0, 8 -byte_8CC6: .BYTE 0,$78, 0, 0,$12 -#endif - -#if 0 /* Silenced since unused */ -static uint8 sim0reset[0x1F] = { - 0x3B, 0xE9, 0x00, 0xFF, 0xC1, 0x10, 0x31, 0xFE, - 0x55, 0xC8, 0x10, 0x20, 0x55, 0x47, 0x4F, 0x53, - 0x56, 0x53, 0x43, 0xAD, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 -}; - -#endif - -static void Sync(void) { - setprg32(0x8000, latch.addr & 1); - setchr8(latch.addr >> 1); -} - -static DECLFW(M216Write5000) { -/* FCEU_printf("WRITE: %04x:%04x (PC=%02x cnt=%02x)\n",A,V,X.PC,sim0bcnt); */ -} - -static DECLFR(M216Read5000) { -/* FCEU_printf("READ: %04x PC=%04x out=%02x byte=%02x cnt=%02x bit=%02x\n",A,X.PC,sim0out,sim0byte,sim0bcnt,sim0bit); */ - return 0; -} - -static void M216Power(void) { - LatchPower(); - SetWriteHandler(0x5000, 0x5000, M216Write5000); - SetReadHandler(0x5000, 0x5000, M216Read5000); -} - -void Mapper216_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); - info->Power = M216Power; -} diff --git a/src/boards/bs-5.c b/src/boards/bs-5.c deleted file mode 100644 index f00f4f92b..000000000 --- a/src/boards/bs-5.c +++ /dev/null @@ -1,84 +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 - */ - -#include "mapinc.h" - -static uint8 reg_prg[4]; -static uint8 reg_chr[4]; -static uint8 dip_switch; - -static SFORMAT StateRegs[] = -{ - { reg_prg, 4, "PREG" }, - { reg_chr, 4, "CREG" }, - { 0 } -}; - -static void Sync(void) { - setprg8(0x8000, reg_prg[0]); - setprg8(0xa000, reg_prg[1]); - setprg8(0xc000, reg_prg[2]); - setprg8(0xe000, reg_prg[3]); - setchr2(0x0000, reg_chr[0]); - setchr2(0x0800, reg_chr[1]); - setchr2(0x1000, reg_chr[2]); - setchr2(0x1800, reg_chr[3]); - setmirror(MI_V); -} - -static DECLFW(MBS5Write) { - int bank_sel = (A & 0xC00) >> 10; - switch (A & 0xF000) { - case 0x8000: - reg_chr[bank_sel] = A & 0x1F; - break; - case 0xA000: - if (A & (1 << (dip_switch + 4))) - reg_prg[bank_sel] = A & 0x0F; - break; - } - Sync(); -} - -static void MBS5Reset(void) { - dip_switch++; - dip_switch &= 3; - reg_prg[0] = reg_prg[1] = reg_prg[2] = reg_prg[3] = ~0; - Sync(); -} - -static void MBS5Power(void) { - dip_switch = 0; - reg_prg[0] = reg_prg[1] = reg_prg[2] = reg_prg[3] = ~0; - Sync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, MBS5Write); -} - -static void StateRestore(int version) { - Sync(); -} - -void BMCBS5_Init(CartInfo *info) { - info->Power = MBS5Power; - info->Reset = MBS5Reset; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/cheapocabra.c b/src/boards/cheapocabra.c deleted file mode 100644 index 6afb45868..000000000 --- a/src/boards/cheapocabra.c +++ /dev/null @@ -1,268 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2002 Xodnizel - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* mapper 111 - Cheapocabra board by Memblers - * http://forums.nesdev.com/viewtopic.php?p=146039 - * - * 512k PRG-ROM in 32k pages (flashable if battery backed is specified) - * 32k CHR-RAM used as: - * 2 x 8k pattern pages - * 2 x 8k nametable pages - * - * Notes: - * - CHR-RAM for nametables maps to $3000-3FFF as well, but FCEUX internally mirrors to 4k? - */ - -#include "mapinc.h" - -static uint8 reg; -static uint8 *CHRRAM = NULL; -static uint32 CHRRAMSIZE; - -static uint8 flash = 0; -static uint8 flash_mode; -static uint8 flash_sequence; -static uint8 flash_id; -static uint8 *FLASHROM = NULL; -static uint32 FLASHROMSIZE; - -static SFORMAT StateRegs[] = { - { ®, 1, "REG" }, - { 0 } -}; - -static SFORMAT FlashRegs[] = { - { &flash_mode, 1, "FMOD" }, - { &flash_sequence, 1, "FSEQ" }, - { &flash_id, 1, "FMID" }, - { 0 } -}; - -static void Sync(void) { - /* bit 7 controls green LED */ - /* bit 6 controls red LED */ - uint32 prg_chip = flash ? 0x10 : 0; - int nt = (reg & 0x20) ? 8192 : 0; /* bit 5 controls 8k nametable page */ - int chr = (reg & 0x10) ? 1 : 0; /* bit 4 selects 8k CHR page */ - int prg = (reg & 0x0F); /* bits 0-3 select 32k PRG page */ - int n = 0; - - nt += (16 * 1024); - for (n = 0; n < 4; ++n) { - setntamem(CHRRAM + nt + (1024 * n), 1, n); - } - setchr8r(0x10, chr); - setprg32r(prg_chip, 0x8000, prg); -} - -static DECLFW(M111Write) { - if ((A >= 0x5000 && A <= 0x5FFF) || (A >= 0x7000 && A <= 0x7FFF)) { - reg = V; - Sync(); - } -} - -static DECLFR(M111FlashID) { - /* Software ID mode is undefined by the datasheet for all but the lowest 2 addressable bytes, - * but some tests of the chip currently being used found it repeats in 512-byte patterns. - * http://forums.nesdev.com/viewtopic.php?p=178728#p178728 - */ - - uint32 aid = A & 0x1FF; - switch (aid) { - case 0: - return 0xBF; - case 1: - return 0xB7; - default: - return 0xFF; - } -} - -void M111FlashIDEnter() { - if (flash_id) - return; - flash_id = 1; - SetReadHandler(0x8000, 0xFFFF, M111FlashID); -} - -void M111FlashIDExit() { - if (!flash_id) - return; - flash_id = 0; - SetReadHandler(0x8000, 0xFFFF, CartBR); -} - -enum { - FLASH_MODE_READY = 0, - FLASH_MODE_COMMAND, - FLASH_MODE_BYTE_WRITE, - FLASH_MODE_ERASE -}; - -static DECLFW(M111Flash) { - uint32 flash_addr = 0; - uint32 command_addr = 0; - - if (A < 0x8000 || A > 0xFFFF) - return; - - flash_addr = ((reg & 0x0F) << 15) | (A & 0x7FFF); - command_addr = flash_addr & 0x7FFF; - - switch (flash_mode) { - default: - case FLASH_MODE_READY: - if (command_addr == 0x5555 && V == 0xAA) { - flash_mode = FLASH_MODE_COMMAND; - flash_sequence = 0; - } else if (V == 0xF0) { - M111FlashIDExit(); - } - break; - case FLASH_MODE_COMMAND: - if (flash_sequence == 0) { - if (command_addr == 0x2AAA && V == 0x55) - flash_sequence = 1; - else - flash_mode = FLASH_MODE_READY; - } else if (flash_sequence == 1) { - if (command_addr == 0x5555) { - flash_sequence = 0; - switch (V) { - default: - flash_mode = FLASH_MODE_READY; - break; - case 0xA0: - flash_mode = FLASH_MODE_BYTE_WRITE; - break; - case 0x80: - flash_mode = FLASH_MODE_ERASE; - break; - case 0x90: - M111FlashIDEnter(); - flash_mode = FLASH_MODE_READY; - break; - case 0xF0: - M111FlashIDExit(); - flash_mode = FLASH_MODE_READY; - break; - } - } else - flash_mode = FLASH_MODE_READY; - } else - flash_mode = FLASH_MODE_READY; /* should be unreachable */ - break; - case FLASH_MODE_BYTE_WRITE: - FLASHROM[flash_addr] &= V; - flash_mode = FLASH_MODE_READY; - break; - case FLASH_MODE_ERASE: - if (flash_sequence == 0) { - if (command_addr == 0x5555 && V == 0xAA) - flash_sequence = 1; - else - flash_mode = FLASH_MODE_READY; - } else if (flash_sequence == 1) { - if (command_addr == 0x2AAA && V == 0x55) - flash_sequence = 2; - else - flash_mode = FLASH_MODE_READY; - } else if (flash_sequence == 2) { - if (command_addr == 0x5555 && V == 0x10) /* erase chip */ - { - memset(FLASHROM, 0xFF, FLASHROMSIZE); - } else if (V == 0x30) /* erase 4k sector */ - { - uint32 sector = flash_addr & 0x7F000; - memset(FLASHROM + sector, 0xFF, 1024 * 4); - } - flash_mode = FLASH_MODE_READY; - } else - flash_mode = FLASH_MODE_READY; /* should be unreachable */ - break; - } -} - -static void M111Power(void) { - reg = 0xFF; - Sync(); - SetReadHandler(0x8000, 0xffff, CartBR); - SetWriteHandler(0x5000, 0x5fff, M111Write); - SetWriteHandler(0x7000, 0x7fff, M111Write); - - if (flash) { - flash_mode = 0; - flash_sequence = 0; - flash_id = 0; - SetWriteHandler(0x8000, 0xFFFF, M111Flash); - } -} - -static void M111Close(void) { - if (CHRRAM) - FCEU_gfree(CHRRAM); - CHRRAM = NULL; - - if (FLASHROM) - FCEU_gfree(FLASHROM); - FLASHROM = NULL; -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper111_Init(CartInfo* info) { - info->Power = M111Power; - info->Close = M111Close; - - CHRRAMSIZE = 1024 * 32; - CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSIZE); - SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); - - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); - AddExState(CHRRAM, CHRRAMSIZE, 0, "CRAM"); - - flash = (info->battery != 0); - if (flash) { - uint32 PRGSIZE = 0; - uint32 w = 0; - uint32 r = 0; - - FLASHROMSIZE = 1024 * 512; - FLASHROM = (uint8*)FCEU_gmalloc(FLASHROMSIZE); - info->SaveGame[0] = FLASHROM; - info->SaveGameLen[0] = FLASHROMSIZE; - AddExState(FLASHROM, FLASHROMSIZE, 0, "FROM"); - AddExState(&FlashRegs, ~0, 0, 0); - - /* copy PRG ROM into FLASHROM, use it instead of PRG ROM */ - PRGSIZE = ROM_size * 16 * 1024; - for (w = 0, r = 0; w < FLASHROMSIZE; ++w) { - FLASHROM[w] = ROM[r]; - ++r; - if (r >= PRGSIZE) - r = 0; - } - SetupCartPRGMapping(0x10, FLASHROM, FLASHROMSIZE, 0); - } -} diff --git a/src/boards/coolboy.c b/src/boards/coolboy.c deleted file mode 100644 index 64e02b70a..000000000 --- a/src/boards/coolboy.c +++ /dev/null @@ -1,177 +0,0 @@ -/* FCEUmm - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2023 - * - * 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" - -static uint8 *CHRRAM = NULL; -static uint32 CHRRAMSize = 0; -static uint8 submapper; - -static void M268CW(uint32 A, uint8 V) { - uint16 base = ((mmc3.expregs[0] << 4) & 0x380) | ((mmc3.expregs[2] << 3) & 0x078); - uint16 mask = (mmc3.expregs[0] & 0x80) ? 0x7F : 0xFF; - uint8 ram = CHRRAM && (mmc3.expregs[4] & 0x01) && ((V & 0xFE) == (mmc3.expregs[4] & 0xFE)); - /* CHR-RAM write protect on submapper 8/9) */ - if ((submapper & ~1) == 8) { - if (mmc3.expregs[0] & 0x10) { - SetupCartCHRMapping(0, CHRptr[0], CHRsize[0], 0); - } else { - SetupCartCHRMapping(0, CHRptr[0], CHRsize[0], 1); - } - } - if (mmc3.expregs[3] & 0x10) { - /* GNROM */ - mask = 0x07; - V = A >> 10; - } - setchr1r(ram ? 0x10 : 0x00, A, (base & ~mask) | (V & mask)); -} - -static void M268PW(uint32 A, uint8 V) { - uint16 base; - uint16 mask = 0x0F /* PRG A13-A16 */ - | ((~mmc3.expregs[0] >> 2) & 0x10) /* PRG A17 */ - | ((~mmc3.expregs[1] >> 2) & 0x20) /* PRG A18 */ - | ((mmc3.expregs[1] >> 0) & 0x40) /* PRG A19 */ - | ((mmc3.expregs[1] << 2) & 0x80) /* PRG A20 */ - ; - switch (submapper & ~1) { - default: /* Original implementation */ - base = (mmc3.expregs[3] & 0x0E) | ((mmc3.expregs[0] << 4) & 0x70) | ((mmc3.expregs[1] << 3) & 0x80) | - ((mmc3.expregs[1] << 6) & 0x300) | ((mmc3.expregs[0] << 6) & 0xC00); - break; - case 2: /* Later revision with different arrangement of register 1 */ - base = (mmc3.expregs[3] & 0x0E) | ((mmc3.expregs[0] << 4) & 0x70) | ((mmc3.expregs[1] << 4) & 0x80) | - ((mmc3.expregs[1] << 6) & 0x100) | ((mmc3.expregs[1] << 8) & 0x200) | ((mmc3.expregs[0] << 6) & 0xC00); - break; - case 4: /* LD622D: PRG A20-21 moved to register 0 */ - base = (mmc3.expregs[3] & 0x0E) | ((mmc3.expregs[0] << 4) & 0x70) | ((mmc3.expregs[0] << 3) & 0x180); - break; - case 6: /* J-852C: CHR A17 selects between two PRG chips */ - base = (mmc3.expregs[3] & 0x0E) | ((mmc3.expregs[0] << 4) & 0x70) | ((mmc3.expregs[1] << 3) & 0x80) | - ((mmc3.expregs[1] << 6) & 0x300) | ((mmc3.expregs[0] << 6) & 0xC00); - base &= ROM_size - 1; - if ((mmc3.expregs[0] & 0x80) ? !!(mmc3.expregs[0] & 0x08) : !!(mmc3.regs[0] & 0x80)) { - base |= ROM_size; - } - break; - } - if (mmc3.expregs[3] & 0x10) { - /* GNROM */ - switch (submapper & ~1) { - default: - mask = (mmc3.expregs[1] & 0x02) ? 0x03 : 0x01; - break; - case 2: - mask = (mmc3.expregs[1] & 0x10) ? 0x01 : 0x03; - break; - } - V = A >> 13; - } - setprg8(A, (base & ~mask) | (V & mask)); -} - -static DECLFR(M268WramRead) { - if (mmc3.wram & 0xA0) { - return CartBR(A); - } - return X.DB; -} - -static DECLFW(M268WramWrite) { - if (MMC3CanWriteToWRAM() || (mmc3.wram & 0x20)) { - CartBW(A, V); - } -} - -static DECLFW(M268Write) { - uint8 index = A & 0x07; - if (~submapper & 0x01) { - M268WramWrite(A, V); - } - if ((~mmc3.expregs[3] & 0x80) || (index == 2)) { - if (index == 2) { - if (mmc3.expregs[2] & 0x80) { - V = (V & 0x0F) | (mmc3.expregs[2] & ~0x0F); - } - V &= ((~mmc3.expregs[2] >> 3) & 0x0E) | 0xF1; - } - mmc3.expregs[index] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } -} - -static void M268Reset(void) { - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[2] = mmc3.expregs[3] = 0x00; - mmc3.expregs[4] = mmc3.expregs[5] = mmc3.expregs[6] = mmc3.expregs[7] = 0x00; - MMC3RegReset(); -} - -static void M268Power(void) { - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[2] = mmc3.expregs[3] = 0x00; - mmc3.expregs[4] = mmc3.expregs[5] = mmc3.expregs[6] = mmc3.expregs[7] = 0x00; - GenMMC3Power(); - SetReadHandler(0x6000, 0x7FFF, M268WramRead); - if (submapper & 1) { - SetWriteHandler(0x5000, 0x5FFF, M268Write); - SetWriteHandler(0x6000, 0x7FFF, M268WramWrite); - } else { - SetWriteHandler(0x6000, 0x7FFF, M268Write); - } -} - -static void M268Close(void) { - GenMMC3Close(); - if (CHRRAM) { - FCEU_gfree(CHRRAM); - } - CHRRAM = NULL; -} - -static void ComminInit(CartInfo *info, int _submapper) { - GenMMC3_Init(info, 512, 256, (info->PRGRamSize + info->PRGRamSaveSize) >> 10, info->battery); - submapper = _submapper; - mmc3.pwrap = M268PW; - mmc3.cwrap = M268CW; - info->Power = M268Power; - info->Reset = M268Reset; - info->Close = M268Close; - CHRRAMSize = info->CHRRamSize + info->CHRRamSaveSize; - if (!UNIFchrrama && CHRRAMSize) { - CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSize); - SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSize, 1); - AddExState(CHRRAM, CHRRAMSize, 0x00, "CRAM"); - } - AddExState(mmc3.expregs, 8, 0x00, "EXPR"); -} - -void COOLBOY_Init(CartInfo *info) { - ComminInit(info, 0); -} - -void MINDKIDS_Init(CartInfo *info) { - ComminInit(info, 1); -} - -void Mapper268_Init(CartInfo *info) { - ComminInit(info, info->submapper); -} diff --git a/src/boards/datalatch.c b/src/boards/datalatch.c deleted file mode 100644 index f77827286..000000000 --- a/src/boards/datalatch.c +++ /dev/null @@ -1,470 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2002 Xodnizel - * Copyright (C) 2023 - * - * 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 "latch.h" -#include "../fds_apu.h" - -static uint8 submapper = 0; - -/*------------------ Map 2 ---------------------------*/ - -static void UNROMSync(void) { - setprg8r(0x10, 0x6000, 0); - setprg16(0x8000, latch.data); - setprg16(0xc000, ~0); - setchr8(0); -} - -void UNROM_Init(CartInfo *info) { - /* By default, do not emulate bus conflicts except when explicitly told by a NES 2.0 header to do so. */ - Latch_Init(info, UNROMSync, NULL, 1, info->iNES2 && info->submapper == 2); -} - -/*------------------ Map 3 ---------------------------*/ - -static void CNROMSync(void) { - setchr8(latch.data); - setprg32(0x8000, 0); - setprg8r(0x10, 0x6000, 0); /* Hayauchy IGO uses 2Kb or RAM */ -} - -void CNROM_Init(CartInfo *info) { - /* By default, do not emulate bus conflicts except when explicitly told by a NES 2.0 header to do so. */ - Latch_Init(info, CNROMSync, NULL, 1, info->iNES2 && info->submapper == 2); -} - -/*------------------ Map 7 ---------------------------*/ - -static void ANROMSync(void) { - setprg32(0x8000, latch.data & 0xF); - setmirror(MI_0 + ((latch.data >> 4) & 1)); - setchr8(0); -} - -void ANROM_Init(CartInfo *info) { - Latch_Init(info, ANROMSync, NULL, 0, info->iNES2 && info->submapper == 2); -} - -/*------------------ Map 8 ---------------------------*/ - -static void M8Sync(void) { - setprg16(0x8000, latch.data >> 3); - setprg16(0xc000, 1); - setchr8(latch.data & 3); -} - -void Mapper8_Init(CartInfo *info) { - Latch_Init(info, M8Sync, NULL, 0, 0); -} - -/*------------------ Map 11 / 144 ---------------------------*/ - -static void M11Sync(void) { - setprg32(0x8000, latch.data & 0xF); - setchr8(latch.data >> 4); -} - -void Mapper11_Init(CartInfo *info) { - Latch_Init(info, M11Sync, NULL, 0, 0); -} - -static DECLFW(M144Write) { - uint8 data = CartBR(A & (A | 1)); - LatchWrite(A, data); -} - -static void M144Power() { - LatchPower(); - SetWriteHandler(0x8000, 0xFFFF, M144Write); -} - -void Mapper144_Init(CartInfo *info) { - Latch_Init(info, M11Sync, NULL, 0, 1); - info->Power = M144Power; -} - -/*------------------ Map 13 ---------------------------*/ - -static void CPROMSync(void) { - setchr4(0x0000, 0); - setchr4(0x1000, latch.data & 3); - setprg32(0x8000, 0); -} - -void CPROM_Init(CartInfo *info) { - Latch_Init(info, CPROMSync, NULL, 0, 1); -} - -/*------------------ 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, (latch.data >> 2) & 7); - setprg16(0xc000, ~0); - setchr8r(0, latch.data & 3); - setprg8r(0x10, 0x6000, 0); -} - -void Mapper29_Init(CartInfo *info) { - Latch_Init(info, M29Sync, NULL, 1, 0); -} - -/*------------------ Map 66 ---------------------------*/ - -static void MHROMSync(void) { - setprg32(0x8000, latch.data >> 4); - setchr8(latch.data & 0xF); -} - -void MHROM_Init(CartInfo *info) { - Latch_Init(info, MHROMSync, NULL, 0, 1); -} - -/*------------------ Map 70 ---------------------------*/ - -static void M70Sync(void) { - setprg16(0x8000, latch.data >> 4); - setprg16(0xc000, ~0); - setchr8(latch.data & 0xf); -} - -void Mapper70_Init(CartInfo *info) { - Latch_Init(info, M70Sync, NULL, 0, 1); -} - -/*------------------ Map 78 ---------------------------*/ -/* Should be two separate emulation functions for this "mapper". Sigh. URGE TO KILL RISING. */ -/* Submapper 1 - Uchuusen - Cosmo Carrier ( one-screen mirroring ) */ -/* Submapper 3 - Holy Diver ( horizontal/vertical mirroring ) */ -static void M78Sync(void) { - setprg16(0x8000, (latch.data & 7)); - setprg16(0xc000, ~0); - setchr8(latch.data >> 4); - if (submapper == 3) { - setmirror((latch.data >> 3) & 1); - } else { - setmirror(MI_0 + ((latch.data >> 3) & 1)); - } -} - -void Mapper78_Init(CartInfo *info) { - Latch_Init(info, M78Sync, NULL, 0, 1); - submapper = info->iNES2 ? info->submapper : 0; -} - -/*------------------ Map 89 ---------------------------*/ - -static void M89Sync(void) { - setprg16(0x8000, (latch.data >> 4) & 7); - setprg16(0xc000, ~0); - setchr8((latch.data & 7) | ((latch.data >> 4) & 8)); - setmirror(MI_0 + ((latch.data >> 3) & 1)); -} - -void Mapper89_Init(CartInfo *info) { - Latch_Init(info, M89Sync, NULL, 0, 1); -} - -/*------------------ Map 93 ---------------------------*/ - -static void SSUNROMSync(void) { - setprg16(0x8000, latch.data >> 4); - setprg16(0xc000, ~0); - setchr8(0); -} - -void SUNSOFT_UNROM_Init(CartInfo *info) { - Latch_Init(info, SSUNROMSync, NULL, 0, 1); -} - -/*------------------ Map 94 ---------------------------*/ - -static void M94Sync(void) { - setprg16(0x8000, latch.data >> 2); - setprg16(0xc000, ~0); - setchr8(0); -} - -void Mapper94_Init(CartInfo *info) { - Latch_Init(info, M94Sync, NULL, 0, 1); -} - -/*------------------ Map 97 ---------------------------*/ - -static void M97Sync(void) { - setchr8(0); - setprg16(0x8000, ~0); - setprg16(0xc000, latch.data); - setmirror((latch.data >> 7) & 1); -} - -void Mapper97_Init(CartInfo *info) { - Latch_Init(info, M97Sync, NULL, 0, 0); -} - -/*------------------ Map 107 ---------------------------*/ - -static void M107Sync(void) { - setprg32(0x8000, latch.data >> 1); - setchr8(latch.data); -} - -void Mapper107_Init(CartInfo *info) { - Latch_Init(info, M107Sync, NULL, 0, 0); -} - -/*------------------ Map 152 ---------------------------*/ - -static void M152Sync(void) { - setprg16(0x8000, (latch.data >> 4) & 7); - setprg16(0xc000, ~0); - setchr8(latch.data & 0xf); - setmirror(MI_0 + ((latch.data >> 7) & 1)); /* Saint Seiya...hmm. */ -} - -void Mapper152_Init(CartInfo *info) { - Latch_Init(info, M152Sync, NULL, 0, 1); -} - -/*------------------ Map 180 ---------------------------*/ - -static void M180Sync(void) { - setprg16(0x8000, 0); - setprg16(0xc000, latch.data); - setchr8(0); -} - -void Mapper180_Init(CartInfo *info) { - Latch_Init(info, M180Sync, NULL, 0, 1); -} - -/*------------------ Map 203 ---------------------------*/ - -static void M203Sync(void) { - setprg16(0x8000, latch.data >> 2); - setprg16(0xC000, latch.data >> 2); - setchr8(latch.data & 3); -} - -void Mapper203_Init(CartInfo *info) { - Latch_Init(info, M203Sync, NULL, 0, 0); -} - -/*------------------ Map 241 ---------------------------*/ -/* Mapper 7 mostly, but with SRAM or maybe prot circuit. - * figure out, which games do need 5xxx area reading. - */ - -static void M241Sync(void) { - setchr8(0); - setprg8r(0x10, 0x6000, 0); - setprg32(0x8000, latch.data); -} - -void Mapper241_Init(CartInfo *info) { - Latch_Init(info, M241Sync, NULL, 1, 0); - info->Reset = LatchHardReset; -} - -/*------------------ Map 271 ---------------------------*/ - -static void M271Sync(void) { - setchr8(latch.data & 0x0F); - setprg32(0x8000, latch.data >> 4); - setmirror((latch.data >> 5) & 1); -} - -void Mapper271_Init(CartInfo *info) { - Latch_Init(info, M271Sync, NULL, 0, 0); -} - -/*------------------ Map 381 ---------------------------*/ -/* 2-in-1 High Standard Game (BC-019), reset-based */ -static uint8 reset = 0; -static void M381Sync(void) { - setprg16(0x8000, ((latch.data & 0x10) >> 4) | ((latch.data & 7) << 1) | (reset << 4)); - setprg16(0xC000, 15 | (reset << 4)); - setchr8(0); -} - -static void M381Reset(void) { - reset ^= 1; - M381Sync(); -} - -void Mapper381_Init(CartInfo *info) { - info->Reset = M381Reset; - Latch_Init(info, M381Sync, NULL, 0, 0); - AddExState(&reset, 1, 0, "RST0"); -} - -/*------------------ Map 538 ---------------------------*/ -/* NES 2.0 Mapper 538 denotes the 60-1064-16L PCB, used for a - * bootleg cartridge conversion named Super Soccer Champion - * of the Konami FDS game Exciting Soccer. - */ - -/* this code emulates rom dump with wrong bank order */ -static uint8 M538Banks[16] = { 0, 1, 2, 1, 3, 1, 4, 1, 5, 5, 1, 1, 6, 6, 7, 7 }; -static void M538Sync_wrong_prg_order(void) { - setprg8(0x6000, (latch.data >> 1) | 8); - setprg8(0x8000, M538Banks[latch.data & 15]); - setprg8(0xA000, 14); - setprg8(0xC000, 7); - setprg8(0xE000, 15); - setchr8(0); - setmirror(1); -} - -static void M538Sync(void) { - setprg8(0x6000, latch.data | 1); - setprg8(0x8000, (latch.data & 1) && (~latch.data & 8) ? 10 : (latch.data & ~1)); - setprg8(0xA000, 13); - setprg8(0xC000, 14); - setprg8(0xE000, 15); - setchr8(0); - setmirror(MI_V); -} - -static DECLFW(M538Write) { - LatchWrite(A, V); -} - -static void M538Power(void) { - FDSSoundPower(); - LatchHardReset(); - SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0xC000, 0xDFFF, M538Write); -} - -void Mapper538_Init(CartInfo *info) { - if (info->CRC32 == 0xA8C6D77D) { - Latch_Init(info, M538Sync_wrong_prg_order, NULL, 0, 0); - } - Latch_Init(info, M538Sync, NULL, 0, 0); - info->Power = M538Power; -} - -/* ------------------ A65AS (m285) --------------------------- */ - -/* actually, there is two cart in one... First have extra mirroring - * mode (one screen) and 32K bankswitching, second one have only - * 16 bankswitching mode and normal mirroring... But there is no any - * correlations between modes and they can be used in one mapper code. - * - * Submapper 0 - 3-in-1 (N068) - * Submapper 0 - 3-in-1 (N080) - * Submapper 1 - 4-in-1 (JY-066) - */ - -static int A65ASsubmapper; -static void BMCA65ASSync(void) { - if (latch.data & 0x40) - setprg32(0x8000, (latch.data >> 1) & 0x0F); - else { - if (A65ASsubmapper == 1) { - setprg16(0x8000, ((latch.data & 0x30) >> 1) | (latch.data & 7)); - setprg16(0xC000, ((latch.data & 0x30) >> 1) | 7); - } else { - setprg16(0x8000, latch.data & 0x0F); - setprg16(0xC000, (latch.data & 0x0F) | 7); - } - } - setchr8(0); - if (latch.data & 0x80) - setmirror(MI_0 + (((latch.data >> 5) & 1))); - else - setmirror(((latch.data >> 3) & 1) ^ 1); -} - -void BMCA65AS_Init(CartInfo *info) { - A65ASsubmapper = info->submapper; - Latch_Init(info, BMCA65ASSync, NULL, 0, 0); -} - -/*------------------ BMC-11160 (m299) ---------------------------*/ -/* Simple BMC discrete mapper by TXC */ - -static void BMC11160Sync(void) { - uint32 bank = (latch.data >> 4) & 7; - setprg32(0x8000, bank); - setchr8((bank << 2) | (latch.data & 3)); - setmirror((latch.data >> 7) & 1); -} - -void BMC11160_Init(CartInfo *info) { - Latch_Init(info, BMC11160Sync, NULL, 0, 0); - info->Reset = LatchHardReset; -} - -/*------------------ 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, latch.data); - setprg16(0xC000, latch.data | 0x07); - setchr8(0); -} - -void BMCK3046_Init(CartInfo *info) { - Latch_Init(info, BMCK3046Sync, NULL, 0, 0); - info->Reset = LatchHardReset; -} - -/*------ Mapper 429: LIKO BBG-235-8-1B/Milowork FCFC1 ----*/ - -static void Mapper429_Sync(void) { - setprg32(0x8000, latch.data >> 2); - setchr8(latch.data); -} - -static void Mapper429_Reset(void) { - latch.data = 4; /* Initial CHR bank 0, initial PRG bank 1 */ - Mapper429_Sync(); -} - -void Mapper429_Init(CartInfo *info) { - Latch_Init(info, Mapper429_Sync, NULL, 0, 0); - info->Reset = Mapper429_Reset; -} - -/*------------------ Mapper 415 ---------------------------*/ - -static void Mapper415_Sync(void) { - setprg8(0x6000, latch.data & 0x0F); - setprg32(0x8000, ~0); - setchr8(0); - setmirror(((latch.data >> 4) & 1) ^ 1); -} - -static void M415Power(void) { - LatchPower(); - SetReadHandler(0x6000, 0x7FFF, CartBR); -} - -void Mapper415_Init(CartInfo *info) { - Latch_Init(info, Mapper415_Sync, NULL, 0, 0); - info->Power = M415Power; -} diff --git a/src/boards/eeprom_93C66.c b/src/boards/eeprom_93C66.c deleted file mode 100644 index c88b86236..000000000 --- a/src/boards/eeprom_93C66.c +++ /dev/null @@ -1,194 +0,0 @@ -#include "eeprom_93C66.h" - -static uint8* eeprom_93C66_storage; -static uint8 eeprom_93C66_opcode; -static uint16 eeprom_93C66_data; -static uint16 eeprom_93C66_address; -static uint8 eeprom_93C66_state; -static uint8 eeprom_93C66_lastCLK; -static uint8 eeprom_93C66_writeEnabled; -static uint8 eeprom_93C66_output; -static uint8 eeprom_savesize; -static uint8 eeprom_wordlength; -static uint8 state_address; -static uint8 state_data; - -#define OPCODE_MISC 0 -#define OPCODE_WRITE 1 -#define OPCODE_READ 2 -#define OPCODE_ERASE 3 -#define OPCODE_WRITEDISABLE 10 -#define OPCODE_WRITEALL 11 -#define OPCODE_ERASEALL 12 -#define OPCODE_WRITEENABLE 13 - -#define STATE_STANDBY 0 -#define STATE_STARTBIT 1 -#define STATE_OPCODE 3 -#define STATE_ADDRESS8 12 -#define STATE_DATA8 20 -#define STATE_ADDRESS16 11 -#define STATE_DATA16 27 -#define STATE_FINISHED 99 - -void eeprom_93C66_init(uint8 *data, uint32 savesize, uint8 wordlength) -{ - eeprom_93C66_storage =data; - eeprom_93C66_address =0; - eeprom_93C66_state =STATE_STANDBY; - eeprom_93C66_lastCLK =0; - eeprom_93C66_writeEnabled =0; - eeprom_savesize =savesize; - eeprom_wordlength =wordlength; - - state_address = (wordlength == 16) ? STATE_ADDRESS16 : STATE_ADDRESS8; - state_data = (wordlength == 16) ? STATE_DATA16 : STATE_DATA8; -} - -uint8 eeprom_93C66_read (void) -{ - return eeprom_93C66_output; -} - -void eeprom_93C66_write (uint8 CS, uint8 CLK, uint8 DAT) -{ - if (!CS && eeprom_93C66_state <= state_address) - eeprom_93C66_state =STATE_STANDBY; - else - if (eeprom_93C66_state ==STATE_STANDBY && CS && CLK) - { - eeprom_93C66_state =STATE_STARTBIT; - eeprom_93C66_opcode =0; - eeprom_93C66_address =0; - eeprom_93C66_output =1; - } - else - if (CLK && !eeprom_93C66_lastCLK) - { - if (eeprom_93C66_state >=STATE_STARTBIT && eeprom_93C66_state =STATE_OPCODE && eeprom_93C66_state =state_address && eeprom_93C66_state >6) + 10; - else - eeprom_93C66_opcode =(eeprom_93C66_address >>7) + 10; - switch (eeprom_93C66_opcode) - { - case OPCODE_WRITEDISABLE: - eeprom_93C66_writeEnabled = 0; - eeprom_93C66_state = STATE_FINISHED; - break; - case OPCODE_WRITEENABLE: - eeprom_93C66_writeEnabled = 1; - eeprom_93C66_state = STATE_FINISHED; - break; - case OPCODE_ERASEALL: - if (eeprom_93C66_writeEnabled) - { - int i; - for (i =0; i > 8; - eeprom_93C66_address++; - } - else - eeprom_93C66_storage[eeprom_93C66_address++] = eeprom_93C66_data; - eeprom_93C66_state = STATE_FINISHED; - } - else - if (eeprom_93C66_opcode ==OPCODE_WRITEALL) - { - if (eeprom_wordlength == 16) - { - eeprom_93C66_storage[eeprom_93C66_address << 1 | 0] = eeprom_93C66_data & 0xFF; - eeprom_93C66_storage[eeprom_93C66_address << 1 | 1] = eeprom_93C66_data >> 8; - eeprom_93C66_address++; - } - else - eeprom_93C66_storage[eeprom_93C66_address++] = eeprom_93C66_data; - eeprom_93C66_state = CS && eeprom_93C66_address > (b)) - -/* Leave the lower b bit(s). */ -#define LOWBITS(c, b) ((c) & ((1 << (b)) - 1)) - -/* Expand x which is s bits to d bits. */ -#define EXPAND_BITS(x, s, d) ((x) << ((d) - (s))) - -/* Expand x which is s bits to d bits and fill expanded bits '1' */ -#define EXPAND_BITS_X(x, s, d) (((x) << ((d) - (s))) | ((1 << ((d) - (s))) - 1)) - -/* Adjust envelope speed which depends on sampling rate. */ -#define rate_adjust(x) (rate == 49716 ? x : (uint32)((double)(x) * clk / 72 / rate + 0.5)) /* added 0.5 to round the value*/ - -#define MOD(o, x) (&(o)->slot[(x) << 1]) -#define CAR(o, x) (&(o)->slot[((x) << 1) | 1]) - -#define BIT(s, b) (((s) >> (b)) & 1) - -/* Input clock */ -static uint32 clk = 844451141; -/* Sampling rate */ -static uint32 rate = 3354932; - -/* WaveTable for each envelope amp */ -static uint16 fullsintable[PG_WIDTH]; -static uint16 halfsintable[PG_WIDTH]; - -static uint16 *waveform[2] = { fullsintable, halfsintable }; - -/* LFO Table */ -static int32 pmtable[PM_PG_WIDTH]; -static int32 amtable[AM_PG_WIDTH]; - -/* Phase delta for LFO */ -static uint32 pm_dphase; -static uint32 am_dphase; - -/* dB to Liner table */ -static int16 DB2LIN_TABLE[(DB_MUTE + DB_MUTE) * 2]; - -/* Liner to Log curve conversion table (for Attack rate). */ -static uint16 AR_ADJUST_TABLE[1 << EG_BITS]; - -/* Definition of envelope mode */ -enum -{ SETTLE, ATTACK, DECAY, SUSHOLD, SUSTINE, RELEASE, FINISH }; - -/* Phase incr table for Attack */ -static uint32 dphaseARTable[16][16]; -/* Phase incr table for Decay and Release */ -static uint32 dphaseDRTable[16][16]; - -/* KSL + TL Table */ -static uint32 tllTable[16][8][1 << TL_BITS][4]; -static int32 rksTable[2][8][2]; - -/* Phase incr table for PG */ -static uint32 dphaseTable[512][8][16]; - -/*************************************************** - - Create tables - -****************************************************/ -INLINE static int32 Min(int32 i, int32 j) { - if (i < j) - return i; - else - return j; -} - -/* Table for AR to LogCurve. */ -static void makeAdjustTable(void) { - int32 i; - - AR_ADJUST_TABLE[0] = (1 << EG_BITS); - for (i = 1; i < 128; i++) - AR_ADJUST_TABLE[i] = (uint16)((double)(1 << EG_BITS) - 1 - (1 << EG_BITS) * log(i) / log(128)); -} - - -/* Table for dB(0 -- (1<= DB_MUTE) DB2LIN_TABLE[i] = 0; - DB2LIN_TABLE[i + DB_MUTE + DB_MUTE] = (int16)(-DB2LIN_TABLE[i]); - } -} - -/* Liner(+0.0 - +1.0) to dB((1<> (20 - DP_BITS)); -} - -static void makeTllTable(void) { -#define dB2(x) ((x) * 2) - - static double kltable[16] = { - dB2(0.000), dB2(9.000), dB2(12.000), dB2(13.875), dB2(15.000), dB2(16.125), dB2(16.875), dB2(17.625), - dB2(18.000), dB2(18.750), dB2(19.125), dB2(19.500), dB2(19.875), dB2(20.250), dB2(20.625), dB2(21.000) - }; - - int32 tmp; - int32 fnum, block, TL, KL; - - for (fnum = 0; fnum < 16; fnum++) - for (block = 0; block < 8; block++) - for (TL = 0; TL < 64; TL++) - for (KL = 0; KL < 4; KL++) { - if (KL == 0) { - tllTable[fnum][block][TL][KL] = TL2EG(TL); - } else { - tmp = (int32)(kltable[fnum] - dB2(3.000) * (7 - block)); - if (tmp <= 0) - tllTable[fnum][block][TL][KL] = TL2EG(TL); - else - tllTable[fnum][block][TL][KL] = (uint32)((tmp >> (3 - KL)) / EG_STEP) + TL2EG(TL); - } - } -} - -/* Rate Table for Attack */ -static void makeDphaseARTable(void) { - int32 AR, Rks, RM, RL; - for (AR = 0; AR < 16; AR++) - for (Rks = 0; Rks < 16; Rks++) { - RM = AR + (Rks >> 2); - RL = Rks & 3; - if (RM > 15) - RM = 15; - switch (AR) { - case 0: - dphaseARTable[AR][Rks] = 0; - break; - case 15: - dphaseARTable[AR][Rks] = 0; /*EG_DP_WIDTH;*/ - break; - default: - dphaseARTable[AR][Rks] = rate_adjust((uint32)(3 * (RL + 4) << (RM + 1))); - break; - } - } -} - -/* Rate Table for Decay and Release */ -static void makeDphaseDRTable(void) { - int32 DR, Rks, RM, RL; - - for (DR = 0; DR < 16; DR++) - for (Rks = 0; Rks < 16; Rks++) { - RM = DR + (Rks >> 2); - RL = Rks & 3; - if (RM > 15) - RM = 15; - switch (DR) { - case 0: - dphaseDRTable[DR][Rks] = 0; - break; - default: - dphaseDRTable[DR][Rks] = rate_adjust((uint32)((RL + 4) << (RM - 1))); - break; - } - } -} - -static void makeRksTable(void) { - int32 fnum8, block, KR; - - for (fnum8 = 0; fnum8 < 2; fnum8++) - for (block = 0; block < 8; block++) - for (KR = 0; KR < 2; KR++) { - if (KR != 0) - rksTable[fnum8][block][KR] = (block << 1) + fnum8; - else - rksTable[fnum8][block][KR] = block >> 1; - } -} - -/************************************************************ - - Calc Parameters - -************************************************************/ - -INLINE static uint32 calc_eg_dphase(OPLL_SLOT * slot) { - switch (slot->eg_mode) { - case ATTACK: - return dphaseARTable[slot->patch.AR][slot->rks]; - - case DECAY: - return dphaseDRTable[slot->patch.DR][slot->rks]; - - case SUSHOLD: - return 0; - - case SUSTINE: - return dphaseDRTable[slot->patch.RR][slot->rks]; - - case RELEASE: - if (slot->sustine) - return dphaseDRTable[5][slot->rks]; - else if (slot->patch.EG) - return dphaseDRTable[slot->patch.RR][slot->rks]; - else - return dphaseDRTable[7][slot->rks]; - - case FINISH: - return 0; - - default: - return 0; - } -} - -/************************************************************* - - OPLL internal interfaces - -*************************************************************/ - -#define UPDATE_PG(S) (S)->dphase = dphaseTable[(S)->fnum][(S)->block][(S)->patch.ML] -#define UPDATE_TLL(S) \ - (((S)->type == 0) ? \ - ((S)->tll = tllTable[((S)->fnum) >> 5][(S)->block][(S)->patch.TL][(S)->patch.KL]) : \ - ((S)->tll = tllTable[((S)->fnum) >> 5][(S)->block][(S)->volume][(S)->patch.KL])) -#define UPDATE_RKS(S) (S)->rks = rksTable[((S)->fnum) >> 8][(S)->block][(S)->patch.KR] -#define UPDATE_WF(S) (S)->sintbl = waveform[(S)->patch.WF] -#define UPDATE_EG(S) (S)->eg_dphase = calc_eg_dphase(S) -#define UPDATE_ALL(S) \ - UPDATE_PG(S); \ - UPDATE_TLL(S); \ - UPDATE_RKS(S); \ - UPDATE_WF(S); \ - UPDATE_EG(S) /* EG should be updated last. */ - - -/* Slot key on */ -INLINE static void slotOn(OPLL_SLOT * slot) { - slot->eg_mode = ATTACK; - slot->eg_phase = 0; - slot->phase = 0; -} - -/* Slot key on without reseting the phase */ -INLINE static void slotOn2(OPLL_SLOT * slot) { - slot->eg_mode = ATTACK; - slot->eg_phase = 0; -} - -/* Slot key off */ -INLINE static void slotOff(OPLL_SLOT * slot) { - if (slot->eg_mode == ATTACK) - slot->eg_phase = EXPAND_BITS(AR_ADJUST_TABLE[HIGHBITS(slot->eg_phase, EG_DP_BITS - EG_BITS)], EG_BITS, EG_DP_BITS); - slot->eg_mode = RELEASE; -} - -/* Channel key on */ -INLINE static void keyOn(OPLL * opll, int32 i) { - if (!opll->slot_on_flag[i * 2]) - slotOn(MOD(opll, i)); - if (!opll->slot_on_flag[i * 2 + 1]) - slotOn(CAR(opll, i)); - opll->key_status[i] = 1; -} - -/* Channel key off */ -INLINE static void keyOff(OPLL * opll, int32 i) { - if (opll->slot_on_flag[i * 2 + 1]) - slotOff(CAR(opll, i)); - opll->key_status[i] = 0; -} - -/* Set sustine parameter */ -INLINE static void setSustine(OPLL * opll, int32 c, int32 sustine) { - CAR(opll, c)->sustine = sustine; - if (MOD(opll, c)->type) - MOD(opll, c)->sustine = sustine; -} - -/* Volume : 6bit ( Volume register << 2 ) */ -INLINE static void setVolume(OPLL * opll, int32 c, int32 volume) { - CAR(opll, c)->volume = volume; -} - -INLINE static void setSlotVolume(OPLL_SLOT * slot, int32 volume) { - slot->volume = volume; -} - -/* Set F-Number ( fnum : 9bit ) */ -INLINE static void setFnumber(OPLL * opll, int32 c, int32 fnum) { - CAR(opll, c)->fnum = fnum; - MOD(opll, c)->fnum = fnum; -} - -/* Set Block data (block : 3bit ) */ -INLINE static void setBlock(OPLL * opll, int32 c, int32 block) { - CAR(opll, c)->block = block; - MOD(opll, c)->block = block; -} - -INLINE static void update_key_status(OPLL * opll) { - int ch; - - for (ch = 0; ch < 6; ch++) - opll->slot_on_flag[ch * 2] = opll->slot_on_flag[ch * 2 + 1] = (opll->HiFreq[ch]) & 0x10; -} - -/*********************************************************** - - Initializing - -***********************************************************/ - -static void OPLL_SLOT_reset(OPLL_SLOT * slot, int type) { - slot->type = type; - slot->sintbl = waveform[0]; - slot->phase = 0; - slot->dphase = 0; - slot->output[0] = 0; - slot->output[1] = 0; - slot->feedback = 0; - slot->eg_mode = SETTLE; - slot->eg_phase = EG_DP_WIDTH; - slot->eg_dphase = 0; - slot->rks = 0; - slot->tll = 0; - slot->sustine = 0; - slot->fnum = 0; - slot->block = 0; - slot->volume = 0; - slot->pgout = 0; - slot->egout = 0; -} - -static void internal_refresh(void) { - makeDphaseTable(); - makeDphaseARTable(); - makeDphaseDRTable(); - pm_dphase = (uint32)rate_adjust(PM_SPEED * PM_DP_WIDTH / (clk / 72)); - am_dphase = (uint32)rate_adjust(AM_SPEED * AM_DP_WIDTH / (clk / 72)); -} - -static void maketables(uint32 c, uint32 r) { - if (c != clk) { - clk = c; - makePmTable(); - makeAmTable(); - makeDB2LinTable(); - makeAdjustTable(); - makeTllTable(); - makeRksTable(); - makeSinTable(); - /* makeDefaultPatch (); */ - } - - if (r != rate) { - rate = r; - internal_refresh(); - } -} - -OPLL *OPLL_new(uint32 _clk, uint32 _rate) { - OPLL *opll; - - maketables(_clk, _rate); - - opll = (OPLL*)calloc(sizeof(OPLL), 1); - if (opll == NULL) - return NULL; - - opll->mask = 0; - - OPLL_reset(opll); - - return opll; -} - - -void OPLL_delete(OPLL * opll) { - free(opll); -} - -/* Reset whole of OPLL except patch datas. */ -void OPLL_reset(OPLL * opll) { - int32 i; - - if (!opll) - return; - - opll->adr = 0; - opll->out = 0; - - opll->pm_phase = 0; - opll->am_phase = 0; - - opll->mask = 0; - - for (i = 0; i < 12; i++) - OPLL_SLOT_reset(&opll->slot[i], i % 2); - - for (i = 0; i < 6; i++) { - opll->key_status[i] = 0; - /* setPatch (opll, i, 0); */ - } - - for (i = 0; i < 0x40; i++) - OPLL_writeReg(opll, i, 0); - - opll->realstep = (uint32)((1 << 31) / rate); - opll->opllstep = (uint32)((1 << 31) / (clk / 72)); - opll->oplltime = 0; -} - -/* Force Refresh (When external program changes some parameters). */ -void OPLL_forceRefresh(OPLL * opll) { - int32 i; - - if (opll == NULL) - return; - - for (i = 0; i < 12; i++) { - UPDATE_PG(&opll->slot[i]); - UPDATE_RKS(&opll->slot[i]); - UPDATE_TLL(&opll->slot[i]); - UPDATE_WF(&opll->slot[i]); - UPDATE_EG(&opll->slot[i]); - } -} - -void OPLL_set_rate(OPLL * opll, uint32 r) { - if (opll->quality) - rate = 49716; - else - rate = r; - internal_refresh(); - rate = r; -} - -void OPLL_set_quality(OPLL * opll, uint32 q) { - opll->quality = q; - OPLL_set_rate(opll, rate); -} - -/********************************************************* - - Generate wave data - -*********************************************************/ -/* Convert Amp(0 to EG_HEIGHT) to Phase(0 to 2PI). */ -#if (SLOT_AMP_BITS - PG_BITS) > 0 -#define wave2_2pi(e) ((e) >> (SLOT_AMP_BITS - PG_BITS)) -#else -#define wave2_2pi(e) ((e) << (PG_BITS - SLOT_AMP_BITS)) -#endif - -/* Convert Amp(0 to EG_HEIGHT) to Phase(0 to 4PI). */ -#if (SLOT_AMP_BITS - PG_BITS - 1) == 0 -#define wave2_4pi(e) (e) -#elif (SLOT_AMP_BITS - PG_BITS - 1) > 0 -#define wave2_4pi(e) ((e) >> (SLOT_AMP_BITS - PG_BITS - 1)) -#else -#define wave2_4pi(e) ((e) << (1 + PG_BITS - SLOT_AMP_BITS)) -#endif - -/* Convert Amp(0 to EG_HEIGHT) to Phase(0 to 8PI). */ -#if (SLOT_AMP_BITS - PG_BITS - 2) == 0 -#define wave2_8pi(e) (e) -#elif (SLOT_AMP_BITS - PG_BITS - 2) > 0 -#define wave2_8pi(e) ((e) >> (SLOT_AMP_BITS - PG_BITS - 2)) -#else -#define wave2_8pi(e) ((e) << (2 + PG_BITS - SLOT_AMP_BITS)) -#endif - - - -/* Update AM, PM unit */ -static void update_ampm(OPLL * opll) { - opll->pm_phase = (opll->pm_phase + pm_dphase) & (PM_DP_WIDTH - 1); - opll->am_phase = (opll->am_phase + am_dphase) & (AM_DP_WIDTH - 1); - opll->lfo_am = amtable[HIGHBITS(opll->am_phase, AM_DP_BITS - AM_PG_BITS)]; - opll->lfo_pm = pmtable[HIGHBITS(opll->pm_phase, PM_DP_BITS - PM_PG_BITS)]; -} - -/* PG */ -INLINE static void calc_phase(OPLL_SLOT * slot, int32 lfo) { - if (slot->patch.PM) - slot->phase += (slot->dphase * lfo) >> PM_AMP_BITS; - else - slot->phase += slot->dphase; - - slot->phase &= (DP_WIDTH - 1); - - slot->pgout = HIGHBITS(slot->phase, DP_BASE_BITS); -} - -/* EG */ -static void calc_envelope(OPLL_SLOT * slot, int32 lfo) { -#define S2E(x) (SL2EG((int32)(x / SL_STEP)) << (EG_DP_BITS - EG_BITS)) - - static uint32 SL[16] = { - S2E(0.0), S2E(3.0), S2E(6.0), S2E(9.0), S2E(12.0), S2E(15.0), S2E(18.0), S2E(21.0), - S2E(24.0), S2E(27.0), S2E(30.0), S2E(33.0), S2E(36.0), S2E(39.0), S2E(42.0), S2E(48.0) - }; - - uint32 egout; - - switch (slot->eg_mode) { - case ATTACK: - egout = AR_ADJUST_TABLE[HIGHBITS(slot->eg_phase, EG_DP_BITS - EG_BITS)]; - slot->eg_phase += slot->eg_dphase; - if ((EG_DP_WIDTH & slot->eg_phase) || (slot->patch.AR == 15)) { - egout = 0; - slot->eg_phase = 0; - slot->eg_mode = DECAY; - UPDATE_EG(slot); - } - break; - - case DECAY: - egout = HIGHBITS(slot->eg_phase, EG_DP_BITS - EG_BITS); - slot->eg_phase += slot->eg_dphase; - if (slot->eg_phase >= SL[slot->patch.SL]) { - if (slot->patch.EG) { - slot->eg_phase = SL[slot->patch.SL]; - slot->eg_mode = SUSHOLD; - UPDATE_EG(slot); - } else { - slot->eg_phase = SL[slot->patch.SL]; - slot->eg_mode = SUSTINE; - UPDATE_EG(slot); - } - } - break; - - case SUSHOLD: - egout = HIGHBITS(slot->eg_phase, EG_DP_BITS - EG_BITS); - if (slot->patch.EG == 0) { - slot->eg_mode = SUSTINE; - UPDATE_EG(slot); - } - break; - - case SUSTINE: - case RELEASE: - egout = HIGHBITS(slot->eg_phase, EG_DP_BITS - EG_BITS); - slot->eg_phase += slot->eg_dphase; - if (egout >= (1 << EG_BITS)) { - slot->eg_mode = FINISH; - egout = (1 << EG_BITS) - 1; - } - break; - - case FINISH: - egout = (1 << EG_BITS) - 1; - break; - - default: - egout = (1 << EG_BITS) - 1; - break; - } - - if (slot->patch.AM) - egout = EG2DB(egout + slot->tll) + lfo; - else - egout = EG2DB(egout + slot->tll); - - if (egout >= DB_MUTE) - egout = DB_MUTE - 1; - - slot->egout = egout; -} - -/* CARRIOR */ -INLINE static int32 calc_slot_car(OPLL_SLOT * slot, int32 fm) { - slot->output[1] = slot->output[0]; - - if (slot->egout >= (DB_MUTE - 1)) { - slot->output[0] = 0; - } else { - slot->output[0] = DB2LIN_TABLE[slot->sintbl[(slot->pgout + wave2_8pi(fm)) & (PG_WIDTH - 1)] + slot->egout]; - } - - return (slot->output[1] + slot->output[0]) >> 1; -} - -/* MODULATOR */ -INLINE static int32 calc_slot_mod(OPLL_SLOT * slot) { - int32 fm; - - slot->output[1] = slot->output[0]; - - if (slot->egout >= (DB_MUTE - 1)) { - slot->output[0] = 0; - } else if (slot->patch.FB != 0) { - fm = wave2_4pi(slot->feedback) >> (7 - slot->patch.FB); - slot->output[0] = DB2LIN_TABLE[slot->sintbl[(slot->pgout + fm) & (PG_WIDTH - 1)] + slot->egout]; - } else { - slot->output[0] = DB2LIN_TABLE[slot->sintbl[slot->pgout] + slot->egout]; - } - - slot->feedback = (slot->output[1] + slot->output[0]) >> 1; - - return slot->feedback; -} - -static INLINE int16 calc(OPLL * opll) { - int32 inst = 0, out = 0; - int32 i; - - update_ampm(opll); - - for (i = 0; i < 12; i++) { - calc_phase(&opll->slot[i], opll->lfo_pm); - calc_envelope(&opll->slot[i], opll->lfo_am); - } - - for (i = 0; i < 6; i++) - if (!(opll->mask & OPLL_MASK_CH(i)) && (CAR(opll, i)->eg_mode != FINISH)) - inst += calc_slot_car(CAR(opll, i), calc_slot_mod(MOD(opll, i))); - - out = inst; - return (int16)out; -} - -void OPLL_fillbuf(OPLL* opll, int32 *buf, int32 len, int shift) { - while (len > 0) { - *buf += (calc(opll) + 32768) << shift; - buf++; - len--; - } -} - -int16 OPLL_calc(OPLL * opll) { - if (!opll->quality) - return calc(opll); - - while (opll->realstep > opll->oplltime) { - opll->oplltime += opll->opllstep; - opll->prev = opll->next; - opll->next = calc(opll); - } - - opll->oplltime -= opll->realstep; - opll->out = (int16)(((double)opll->next * (opll->opllstep - opll->oplltime) - + (double)opll->prev * opll->oplltime) / opll->opllstep); - - return (int16)opll->out; -} - -uint32 OPLL_setMask(OPLL * opll, uint32 mask) { - uint32 ret; - - if (opll) { - ret = opll->mask; - opll->mask = mask; - return ret; - } else - return 0; -} - -uint32 OPLL_toggleMask(OPLL * opll, uint32 mask) { - uint32 ret; - - if (opll) { - ret = opll->mask; - opll->mask ^= mask; - return ret; - } else - return 0; -} - -/**************************************************** - - I/O Ctrl - -*****************************************************/ - -static void setInstrument(OPLL * opll, uint32 i, uint32 inst) { - const uint8 *src; - OPLL_PATCH *modp, *carp; - - opll->patch_number[i] = inst; - - if (inst) - src = default_inst[inst - 1]; - else - src = opll->CustInst; - - modp = &MOD(opll, i)->patch; - carp = &CAR(opll, i)->patch; - - modp->AM = (src[0] >> 7) & 1; - modp->PM = (src[0] >> 6) & 1; - modp->EG = (src[0] >> 5) & 1; - modp->KR = (src[0] >> 4) & 1; - modp->ML = (src[0] & 0xF); - - carp->AM = (src[1] >> 7) & 1; - carp->PM = (src[1] >> 6) & 1; - carp->EG = (src[1] >> 5) & 1; - carp->KR = (src[1] >> 4) & 1; - carp->ML = (src[1] & 0xF); - - modp->KL = (src[2] >> 6) & 3; - modp->TL = (src[2] & 0x3F); - - carp->KL = (src[3] >> 6) & 3; - carp->WF = (src[3] >> 4) & 1; - - modp->WF = (src[3] >> 3) & 1; - - modp->FB = (src[3]) & 7; - - modp->AR = (src[4] >> 4) & 0xF; - modp->DR = (src[4] & 0xF); - - carp->AR = (src[5] >> 4) & 0xF; - carp->DR = (src[5] & 0xF); - - modp->SL = (src[6] >> 4) & 0xF; - modp->RR = (src[6] & 0xF); - - carp->SL = (src[7] >> 4) & 0xF; - carp->RR = (src[7] & 0xF); -} - - -void OPLL_writeReg(OPLL * opll, uint32 reg, uint32 data) { - int32 i, v, ch; - - data = data & 0xff; - reg = reg & 0x3f; - - switch (reg) { - case 0x00: - opll->CustInst[0] = data; - for (i = 0; i < 6; i++) { - if (opll->patch_number[i] == 0) { - setInstrument(opll, i, 0); - UPDATE_PG(MOD(opll, i)); - UPDATE_RKS(MOD(opll, i)); - UPDATE_EG(MOD(opll, i)); - } - } - break; - - case 0x01: - opll->CustInst[1] = data; - for (i = 0; i < 6; i++) { - if (opll->patch_number[i] == 0) { - setInstrument(opll, i, 0); - UPDATE_PG(CAR(opll, i)); - UPDATE_RKS(CAR(opll, i)); - UPDATE_EG(CAR(opll, i)); - } - } - break; - - case 0x02: - opll->CustInst[2] = data; - for (i = 0; i < 6; i++) { - if (opll->patch_number[i] == 0) { - setInstrument(opll, i, 0); - UPDATE_TLL(MOD(opll, i)); - } - } - break; - - case 0x03: - opll->CustInst[3] = data; - for (i = 0; i < 6; i++) { - if (opll->patch_number[i] == 0) { - setInstrument(opll, i, 0); - UPDATE_WF(MOD(opll, i)); - UPDATE_WF(CAR(opll, i)); - } - } - break; - - case 0x04: - opll->CustInst[4] = data; - for (i = 0; i < 6; i++) { - if (opll->patch_number[i] == 0) { - setInstrument(opll, i, 0); - UPDATE_EG(MOD(opll, i)); - } - } - break; - - case 0x05: - opll->CustInst[5] = data; - for (i = 0; i < 6; i++) { - if (opll->patch_number[i] == 0) { - setInstrument(opll, i, 0); - UPDATE_EG(CAR(opll, i)); - } - } - break; - - case 0x06: - opll->CustInst[6] = data; - for (i = 0; i < 6; i++) { - if (opll->patch_number[i] == 0) { - setInstrument(opll, i, 0); - UPDATE_EG(MOD(opll, i)); - } - } - break; - - case 0x07: - opll->CustInst[7] = data; - for (i = 0; i < 6; i++) { - if (opll->patch_number[i] == 0) { - setInstrument(opll, i, 0); - UPDATE_EG(CAR(opll, i)); - } - } - break; - - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - ch = reg - 0x10; - opll->LowFreq[ch] = data; - setFnumber(opll, ch, data + ((opll->HiFreq[ch] & 1) << 8)); - UPDATE_ALL(MOD(opll, ch)); - UPDATE_ALL(CAR(opll, ch)); - break; - - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - ch = reg - 0x20; - opll->HiFreq[ch] = data; - - setFnumber(opll, ch, ((data & 1) << 8) + opll->LowFreq[ch]); - setBlock(opll, ch, (data >> 1) & 7); - setSustine(opll, ch, (data >> 5) & 1); - if (data & 0x10) - keyOn(opll, ch); - else - keyOff(opll, ch); - UPDATE_ALL(MOD(opll, ch)); - UPDATE_ALL(CAR(opll, ch)); - update_key_status(opll); - break; - - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - opll->InstVol[reg - 0x30] = data; - i = (data >> 4) & 15; - v = data & 15; - setInstrument(opll, reg - 0x30, i); - setVolume(opll, reg - 0x30, v << 2); - UPDATE_ALL(MOD(opll, reg - 0x30)); - UPDATE_ALL(CAR(opll, reg - 0x30)); - break; - - default: - break; - } -} - -void OPLL_writeIO(OPLL * opll, uint32 adr, uint32 val) { - if (adr & 1) - OPLL_writeReg(opll, opll->adr, val); - else - opll->adr = val; -} - diff --git a/src/boards/emu2413.h b/src/boards/emu2413.h deleted file mode 100644 index b14833b0b..000000000 --- a/src/boards/emu2413.h +++ /dev/null @@ -1,123 +0,0 @@ -#ifndef _EMU2413_H_ -#define _EMU2413_H_ - -#include -#include -#include -#include "../fceu-types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define PI 3.14159265358979323846 - -enum { OPLL_VRC7_TONE=0 }; - -/* voice data */ -typedef struct { - uint32 TL, FB, EG, ML, AR, DR, SL, RR, KR, KL, AM, PM, WF; -} OPLL_PATCH; - -/* slot */ -typedef struct { - OPLL_PATCH patch; - - int32 type; /* 0 : modulator 1 : carrier */ - - /* OUTPUT */ - int32 feedback; - int32 output[2]; /* Output value of slot */ - - /* for Phase Generator (PG) */ - uint16 *sintbl; /* Wavetable */ - uint32 phase; /* Phase */ - uint32 dphase; /* Phase increment amount */ - uint32 pgout; /* output */ - - /* for Envelope Generator (EG) */ - int32 fnum; /* F-Number */ - int32 block; /* Block */ - int32 volume; /* Current volume */ - int32 sustine; /* Sustine 1 = ON, 0 = OFF */ - uint32 tll; /* Total Level + Key scale level*/ - uint32 rks; /* Key scale offset (Rks) */ - int32 eg_mode; /* Current state */ - uint32 eg_phase; /* Phase */ - uint32 eg_dphase; /* Phase increment amount */ - uint32 egout; /* output */ -} OPLL_SLOT; - -/* Mask */ -#define OPLL_MASK_CH(x) (1 << (x)) - -/* opll */ -typedef struct { - uint32 adr; - int32 out; - - uint32 realstep; - uint32 oplltime; - uint32 opllstep; - int32 prev, next; - - /* Register */ - uint8 LowFreq[6]; - uint8 HiFreq[6]; - uint8 InstVol[6]; - - uint8 CustInst[8]; - - int32 slot_on_flag[6 * 2]; - - /* Pitch Modulator */ - uint32 pm_phase; - int32 lfo_pm; - - /* Amp Modulator */ - int32 am_phase; - int32 lfo_am; - - uint32 quality; - - /* Channel Data */ - int32 patch_number[6]; - int32 key_status[6]; - - /* Slot */ - OPLL_SLOT slot[6 * 2]; - - uint32 mask; -} OPLL; - -/* Create Object */ -OPLL *OPLL_new(uint32 clk, uint32 rate); -void OPLL_delete(OPLL *); - -/* Setup */ -void OPLL_reset(OPLL *); -void OPLL_set_rate(OPLL *opll, uint32 r); -void OPLL_set_quality(OPLL *opll, uint32 q); - -/* Port/Register access */ -void OPLL_writeIO(OPLL *, uint32 reg, uint32 val); -void OPLL_writeReg(OPLL *, uint32 reg, uint32 val); - -/* Synthsize */ -int16 OPLL_calc(OPLL *); - -/* Misc */ -void OPLL_forceRefresh(OPLL *); - -/* Channel Mask */ -uint32 OPLL_setMask(OPLL *, uint32 mask); -uint32 OPLL_toggleMask(OPLL *, uint32 mask); - - -void OPLL_fillbuf(OPLL* opll, int32 *buf, int32 len, int shift); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/boards/flashrom.h b/src/boards/flashrom.h deleted file mode 100644 index 92be5338f..000000000 --- a/src/boards/flashrom.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2010-2023 Fabio Cavallo (aka FHorse) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef FLASHROM_H_ -#define FLASHROM_H_ - -void Flash_Init(uint8 *data, uint32 size, uint8 manufacter_id, uint8 model_id, uint32 sector_size, uint32 adr1, uint32 adr2); -void FlashWrite(uint32 address, uint8 value); -uint8 FlashRead(uint32 address); -void FlashCPUHook(int a); - -#endif /* FLASHROM_H_ */ \ No newline at end of file diff --git a/src/boards/gn26.c b/src/boards/gn26.c deleted file mode 100644 index c39d829f7..000000000 --- a/src/boards/gn26.c +++ /dev/null @@ -1,68 +0,0 @@ -/* 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) { - int chrAND = (mmc3.expregs[0] & 0x02) ? 0x7F : 0xFF; - int chrOR = (mmc3.expregs[0] & 3) << 7; - setchr1(A, chrOR | (V & chrAND)); -} - -static void BMCGN26PW(uint32 A, uint8 V) { - if (mmc3.expregs[0] & 4) { - setprg32(0x8000, (mmc3.expregs[0] << 2) | ((mmc3.regs[6] & 0x0F) >> 2)); - } else { - setprg8(A, (mmc3.expregs[0] << 4) | (V & 0x0F)); - } -} - -static DECLFW(BMCGN26Write) { - if (MMC3CanWriteToWRAM()) { - mmc3.expregs[0] = A & 0xFF; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } -} - -static void BMCGN26Reset(void) { - mmc3.expregs[0] = 0; - MMC3RegReset(); -} - -static void BMCGN26Power(void) { - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, BMCGN26Write); -} - -void BMCGN26_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 256, 0, 0); - mmc3.pwrap = BMCGN26PW; - mmc3.cwrap = BMCGN26CW; - info->Power = BMCGN26Power; - info->Reset = BMCGN26Reset; - AddExState(mmc3.expregs, 1, 0, "EXPR"); -} diff --git a/src/boards/hp10xx_hp20xx.c b/src/boards/hp10xx_hp20xx.c deleted file mode 100644 index 27abbfa2f..000000000 --- a/src/boards/hp10xx_hp20xx.c +++ /dev/null @@ -1,170 +0,0 @@ -/* 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" - -/* 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 (mmc3.expregs[0] & 4) { /* custom banking */ - switch(mmc3.expregs[0] & 3) { - case 0: - case 1: - setchr8(mmc3.expregs[2] & 0x3F); -/* FCEU_printf("\tCHR8 %02X\n",mmc3.expregs[2]&0x3F); */ - break; - case 2: - setchr8((mmc3.expregs[2] & 0x3E) | (unromchr & 1)); -/* FCEU_printf("\tCHR8 %02X\n",(mmc3.expregs[2]&0x3E)|(unromchr&1)); */ - break; - case 3: - setchr8((mmc3.expregs[2] & 0x3C) | (unromchr & 3)); -/* FCEU_printf("\tCHR8 %02X\n",(mmc3.expregs[2]&0x3C)|(unromchr&3)); */ - break; - } - } else { /* mmc3 banking */ - int base, mask; - if(mmc3.expregs[0] & 1) { /* 128K mode */ - base = mmc3.expregs[2] & 0x30; - mask = 0x7F; - } else { /* 256K mode */ - base = mmc3.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(mmc3.expregs[0] & 4) { /* custom banking */ - if((mmc3.expregs[0] & 0xF) == 4) { /* 16K mode */ -/* FCEU_printf("\tPRG16 %02X\n",mmc3.expregs[1]&0x1F); */ - setprg16(0x8000, mmc3.expregs[1] & 0x1F); - setprg16(0xC000, mmc3.expregs[1] & 0x1F); - } else { /* 32K modes */ -/* FCEU_printf("\tPRG32 %02X\n",(mmc3.expregs[1]&0x1F)>>1); */ - setprg32(0x8000, (mmc3.expregs[1] & 0x1F) >> 1); - } - } else { /* mmc3 banking */ - uint8 base, mask; - if(mmc3.expregs[0] & 2) { /* 128K mode */ - base = mmc3.expregs[1] & 0x18; - mask = 0x0F; - } else { /* 256K mode */ - base = mmc3.expregs[1] & 0x10; - mask = 0x1F; - } -/* FCEU_printf("\tPRG8 %02X\n",(V&mask)|(base<<1)); */ - setprg8(A, (V & mask) | (base << 1)); - setprg8r(0x10, 0x6000, mmc3.wram & 3); - } -} - -/* MIRROR wrapper */ -static void BMCHPxxMW(uint8 V) { - if(mmc3.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); */ - mmc3.mirroring = V; - setmirror((mmc3.mirroring & 1) ^ 1); - } -} - -/* PRG handler ($8000-$FFFF) */ -static DECLFW(BMCHPxxHiWrite) { -/* FCEU_printf("HI WRITE %04X:%02X\n",A,V); */ - if(mmc3.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); */ - mmc3.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); */ - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[2] = mmc3.expregs[3] = 0; - MMC3RegReset(); - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); -} - -static void BMCHPxxPower(void) { - GenMMC3Power(); - dipswitch = lock = 0; - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[2] = mmc3.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); - mmc3.cwrap = BMCHPxxCW; - mmc3.pwrap = BMCHPxxPW; - mmc3.mwrap = BMCHPxxMW; - info->Power = BMCHPxxPower; - info->Reset = BMCHPxxReset; - AddExState(mmc3.expregs, 8, 0, "EXPR"); - AddExState(&unromchr, 1, 0, "UCHR"); - AddExState(&dipswitch, 1, 0, "DPSW"); - AddExState(&lock, 1, 0, "LOCK"); -} diff --git a/src/boards/hp898f.c b/src/boards/hp898f.c deleted file mode 100644 index 50d63d0e3..000000000 --- a/src/boards/hp898f.c +++ /dev/null @@ -1,72 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2015 CaH4e3 - * Copyright (C) 2020 dragon2snow,loong2snow from www.nesbbs.com - * 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" - -/* This source code file only applies to Sanchez' original UNIF file with the incorrect bank order. - The correctly-specified mapper, used for all NES 2.0 ROM files, is implemented in 319.c. */ - -static uint8 regs[2]; - -static SFORMAT StateRegs[] = -{ - { regs, 2, "REGS" }, - { 0 } -}; - -static void Sync(void) { - uint8 chr = (regs[0] >> 4) & 7; - uint8 prg = (regs[1] >> 3) & 7; - uint8 dec = (regs[1] >> 4) & 4; - setchr8(chr & (~(((regs[0] & 1) << 2) | (regs[0] & 2)))); - setprg16(0x8000, prg & (~dec)); - setprg16(0xC000, prg | dec); - setmirror(regs[1] >> 7); -} - -static DECLFW(HP898FWrite) { - if ((A & 0x6000) == 0x6000) { - regs[(A & 4) >> 2] = V; - Sync(); - } -} - -static void HP898FPower(void) { - regs[0] = regs[1] = 0; - Sync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0xFFFF, HP898FWrite); -} - -static void HP898FReset(void) { - regs[0] = regs[1] = 0; - Sync(); -} - -static void StateRestore(int version) { - Sync(); -} - -void BMCHP898F_Init(CartInfo *info) { - info->Reset = HP898FReset; - info->Power = HP898FPower; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/jyasic.c b/src/boards/jyasic.c deleted file mode 100644 index ee24af934..000000000 --- a/src/boards/jyasic.c +++ /dev/null @@ -1,720 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * 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 - * 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" - -static void (*WSync)(void); -static uint8 allowExtendedMirroring; - -static uint8 mode[4]; -static uint8* WRAM = NULL; -static uint32 WRAMSIZE; - -static uint8 irqControl; -static uint8 irqEnabled; -static uint8 irqPrescaler; -static uint8 irqCounter; -static uint8 irqXor; -static uint32 lastPPUAddress; - -static uint8 prg[4]; -static uint16 chr[8]; -static uint16 nt[4]; -static uint8 latch[2]; -static uint8 mul[2]; -static uint8 adder; -static uint8 test; -static uint8 dipSwitch; - -static uint8 cpuWriteHandlersSet; -static writefunc cpuWriteHandlers[0x10000]; /* Actual write handlers for CPU write trapping as a method fo IRQ clocking */ - -static SFORMAT JYASIC_stateRegs[] = { - { &irqControl, 1, "IRQM" }, - { &irqPrescaler, 1, "IRQP" }, - { &irqCounter, 1, "IRQC" }, - { &irqXor, 1, "IRQX" }, - { &irqEnabled, 1, "IRQA" }, - { mul, 2, "MUL" }, - { &test, 1, "REGI" }, - { mode , 4, "TKCO" }, - { prg, 4, "PRGB" }, - { latch, 2, "CLTC" }, - { chr, 16, "CHRB" }, - { nt, 8, "NMS0" }, - { &dipSwitch, 1, "TEKR" }, - { &adder, 1, "ADDE" }, - { 0 } -}; - -static uint8 rev(uint8_t val) { - return ((val << 6) & 0x40) | ((val << 4) & 0x20) | ((val << 2) & 0x10) | (val & 0x08) | ((val >> 2) & 0x04) | - ((val >> 4) & 0x02) | ((val >> 6) & 0x01); -} - -static void syncPRG(int AND, int OR) { - uint8_t prgLast = (mode[0] & 0x04) ? prg[3] : 0xFF; - uint8_t prg6000 = 0; - switch (mode[0] & 0x03) { - case 0: - setprg32(0x8000, (prgLast & (AND >> 2)) | (OR >> 2)); - prg6000 = (prg[3] << 2) | 3; - break; - case 1: - setprg16(0x8000, (prg[1] & (AND >> 1)) | (OR >> 1)); - setprg16(0xC000, (prgLast & (AND >> 1)) | (OR >> 1)); - prg6000 = (prg[3] << 1) | 1; - break; - case 2: - setprg8(0x8000, (prg[0] & AND) | OR); - setprg8(0xA000, (prg[1] & AND) | OR); - setprg8(0xC000, (prg[2] & AND) | OR); - setprg8(0xE000, (prgLast & AND) | OR); - prg6000 = prg[3]; - break; - case 3: - setprg8(0x8000, (rev(prg[0]) & AND) | OR); - setprg8(0xA000, (rev(prg[1]) & AND) | OR); - setprg8(0xC000, (rev(prg[2]) & AND) | OR); - setprg8(0xE000, (rev(prgLast) & AND) | OR); - prg6000 = rev(prg[3]); - break; - } - if (mode[0] & 0x80) /* Map ROM */ - setprg8(0x6000, (prg6000 & AND) | OR); - else if (WRAMSIZE) /* Otherwise map WRAM if it exists */ - setprg8r(0x10, 0x6000, 0); -} - -static void syncCHR(int AND, int OR) { - /* MMC4 mode[0] with 4 KiB CHR mode[0] */ - if (mode[3] & 0x80 && (mode[0] & 0x18) == 0x08) { - int chrBank; - for (chrBank = 0; chrBank < 8; chrBank += 4) - setchr4(0x400 * chrBank, (chr[(latch[chrBank / 4] & 2) | chrBank] & (AND >> 2)) | (OR >> 2)); - } else { - int chrBank; - switch (mode[0] & 0x18) { - case 0x00: /* 8 KiB CHR mode[0] */ - setchr8((chr[0] & (AND >> 3)) | (OR >> 3)); - break; - case 0x08: /* 4 KiB CHR mode[0] */ - for (chrBank = 0; chrBank < 8; chrBank += 4) - setchr4(0x400 * chrBank, (chr[chrBank] & (AND >> 2)) | (OR >> 2)); - break; - case 0x10: - for (chrBank = 0; chrBank < 8; chrBank += 2) - setchr2(0x400 * chrBank, (chr[chrBank] & (AND >> 1)) | (OR >> 1)); - break; - case 0x18: - for (chrBank = 0; chrBank < 8; chrBank += 1) - setchr1(0x400 * chrBank, (chr[chrBank] & AND) | OR); - break; - } - } - - PPUCHRRAM = (mode[2] & 0x40) ? 0xFF : 0x00; /* Write-protect or write-enable CHR-RAM */ -} - -static void syncNT(int AND, int OR) { - if (mode[0] & 0x20 || mode[1] & 0x08) { - /* ROM nametables or extended mirroring */ - /* First, set normal CIRAM pages using extended registers ... */ - setmirrorw(nt[0] & 1, nt[1] & 1, nt[2] & 1, nt[3] & 1); - - if (mode[0] & 0x20) { - int ntBank; - for (ntBank = 0; ntBank < 4; ntBank++) { - /* Then replace with ROM nametables if such are generally enabled */ - int vromHere = ((nt[ntBank] & 0x80) ^ (mode[2] & 0x80)) | (mode[0] & 0x40); - /* ROM nametables are used either when globally enabled via D000.6 or per-bank via B00x.7 vs. D002.7 */ - if (vromHere) - setntamem(CHRptr[0] + 0x400 * (((nt[ntBank] & AND) | OR) & CHRmask1[0]), 0, ntBank); - } - } - } else - switch (mode[1] & 0x03) { - /* Regularly mirrored CIRAM */ - case 0: - setmirror(MI_V); - break; - case 1: - setmirror(MI_H); - break; - case 2: - setmirror(MI_0); - break; - case 3: - setmirror(MI_1); - break; - } -} - -static void clockIRQ(void) { - uint8_t mask = irqControl & 0x04 ? 0x07 : 0xFF; - bool clockIrqCounter = false; - uint8 prescaler = irqPrescaler & mask; - - if (irqEnabled) { - switch (irqControl & 0xC0) { - case 0x40: - prescaler++; - if((prescaler & mask) == 0) { - clockIrqCounter = true; - } - break; - case 0x80: - if(--prescaler == 0) { - clockIrqCounter = true; - } - } - - irqPrescaler = (irqPrescaler & ~mask) | (prescaler & mask); - - if (clockIrqCounter) { - switch (irqControl & 0xC0) { - case 0x40: - if ((irqControl & 0x08) == 0) - irqCounter++; - if (irqCounter == 0x00) - X6502_IRQBegin(FCEU_IQEXT); - break; - case 0x80: - if ((irqControl & 0x08) == 0) - irqCounter--; - if (irqCounter == 0xFF) - X6502_IRQBegin(FCEU_IQEXT); - break; - } - } - } -} - -static DECLFW(trapCPUWrite) { - if ((irqControl & 0x03) == 0x03) - clockIRQ(); /* Clock IRQ counter on CPU writes */ - cpuWriteHandlers[A](A, V); -} - -static void FP_FASTAPASS(1) trapPPUAddressChange(uint32 A) { - if (((irqControl & 0x03) == 0x02) && (lastPPUAddress != A)) { - int i; - for (i = 0; i < 2; i++) - clockIRQ(); /* Clock IRQ counter on PPU "reads" */ - } - if ((mode[3] & 0x80) && ((mode[0] & 0x18) == 0x08) && (((A & 0x2FF0) == 0xFD0) || ((A & 0x2FF0) == 0xFE0))) { - /* If MMC4 mode[0] is enabled, and CHR mode[0] is 4 KiB, and tile FD or FE is being fetched ... */ - latch[(A >> 12) & 1] = ((A >> 10) & 4) | ((A >> 4) & 2); /* switch the left or right pattern table's latch to 0 (FD) or 2 (FE), - * being used as an offset for the CHR register index. */ - WSync(); - } - lastPPUAddress = A; -} - -static void ppuScanline(void) { - if ((irqControl & 0x03) == 0x01) { - int i; - for (i = 0; i < 8; i++) - clockIRQ(); /* Clock IRQ counter on A12 rises (eight per scanline). This should be done in - trapPPUAddressChange, but would require more accurate PPU emulation for that. */ - } -} - -static void FP_FASTAPASS(1) cpuCycle(int a) { - if ((irqControl & 0x03) == 0x00) - while (a--) - clockIRQ(); /* Clock IRQ counter on M2 cycles */ -} - -static DECLFR(readALU_DIP) { - if ((A & 0x3FF) == 0 && A != 0x5800) /* 5000, 5400, 5C00: read solder pad setting */ - return dipSwitch | (X.DB & 0x3F); - - if (A & 0x800) - switch (A & 3) { - /* 5800-5FFF: read ALU */ - case 0: - return (mul[0] * mul[1]) & 0xFF; - case 1: - return (mul[0] * mul[1]) >> 8; - case 2: - return adder; - case 3: - return test; - } - /* all others */ - return X.DB; -} - -static DECLFW(writeALU) { - switch (A & 3) { - case 0: - mul[0] = V; - break; - case 1: - mul[1] = V; - break; - case 2: - adder += V; - break; - case 3: - test = V; - adder = 0; - break; - } -} - -static DECLFW(writePRG) { - prg[A & 3] = V; - WSync(); -} - -static DECLFW(writeCHRLow) { - chr[A & 7] = (chr[A & 7] & 0xFF00) | V; - WSync(); -} - -static DECLFW(writeCHRHigh) { - chr[A & 7] = (chr[A & 7] & 0x00FF) | V << 8; - WSync(); -} - -static DECLFW(writeNT) { - if (~A & 4) - nt[A & 3] = (nt[A & 3] & 0xFF00) | V; - else - nt[A & 3] = (nt[A & 3] & 0x00FF) | V << 8; - WSync(); -} - -static DECLFW(writeIRQ) { - switch (A & 7) { - case 0: - irqEnabled = !!(V & 1); - if (!irqEnabled) { - irqPrescaler = 0; - X6502_IRQEnd(FCEU_IQEXT); - } - break; - case 1: - irqControl = V; - break; - case 2: - irqEnabled = 0; - irqPrescaler = 0; - X6502_IRQEnd(FCEU_IQEXT); - break; - case 3: - irqEnabled = 1; - break; - case 4: - irqPrescaler = V ^ irqXor; - break; - case 5: - irqCounter = V ^ irqXor; - break; - case 6: - irqXor = V; - break; - } -} - -static DECLFW(writeMode) { - switch (A & 3) { - case 0: - mode[0] = V; - if (!allowExtendedMirroring) - mode[0] &= ~0x20; - break; - case 1: - mode[1] = V; - if (!allowExtendedMirroring) - mode[1] &= ~0x08; - break; - case 2: - mode[2] = V; - break; - case 3: - mode[3] = V; - break; - } - WSync(); -} - -static void JYASIC_restoreWriteHandlers(void) { - int i; - if (cpuWriteHandlersSet) { - for (i = 0; i < 0x10000; i++) - SetWriteHandler(i, i, cpuWriteHandlers[i]); - cpuWriteHandlersSet = 0; - } -} - -static void JYASIC_power(void) { - unsigned int i; - - SetWriteHandler(0x5000, 0x5FFF, writeALU); - SetWriteHandler(0x6000, 0x7fff, CartBW); - SetWriteHandler(0x8000, 0x87FF, writePRG); /* 8800-8FFF ignored */ - SetWriteHandler(0x9000, 0x97FF, writeCHRLow); /* 9800-9FFF ignored */ - SetWriteHandler(0xA000, 0xA7FF, writeCHRHigh); /* A800-AFFF ignored */ - SetWriteHandler(0xB000, 0xB7FF, writeNT); /* B800-BFFF ignored */ - SetWriteHandler(0xC000, 0xCFFF, writeIRQ); - SetWriteHandler(0xD000, 0xD7FF, writeMode); /* D800-DFFF ignored */ - - JYASIC_restoreWriteHandlers(); - for (i = 0; i < 0x10000; i++) - cpuWriteHandlers[i] = GetWriteHandler(i); - SetWriteHandler(0x0000, 0xFFFF, trapCPUWrite); /* Trap all CPU writes for IRQ clocking purposes */ - cpuWriteHandlersSet = 1; - - SetReadHandler(0x5000, 0x5FFF, readALU_DIP); - SetReadHandler(0x6000, 0xFFFF, CartBR); - - mul[0] = mul[1] = adder = test = dipSwitch = 0; - mode[0] = mode[1] = mode[2] = mode[3] = 0; - irqControl = irqEnabled = irqPrescaler = irqCounter = irqXor = lastPPUAddress = 0; - memset(prg, 0, sizeof(prg)); - memset(chr, 0, sizeof(chr)); - memset(nt, 0, sizeof(nt)); - latch[0] = 0; - latch[1] = 4; - - WSync(); -} - -static void JYASIC_reset(void) { - dipSwitch = (dipSwitch + 0x40) & 0xC0; -} - -static void JYASIC_close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -static void JYASIC_restore(int version) { - WSync(); -} - -void JYASIC_init(CartInfo *info) { - cpuWriteHandlersSet = 0; - info->Reset = JYASIC_reset; - info->Power = JYASIC_power; - info->Close = JYASIC_close; - PPU_hook = trapPPUAddressChange; - MapIRQHook = cpuCycle; - GameHBIRQHook2 = ppuScanline; - AddExState(JYASIC_stateRegs, ~0, 0, 0); - GameStateRestore = JYASIC_restore; - - /* WRAM is present only in iNES mapper 35, or in mappers with numbers above 255 that require NES 2.0, which - * explicitly denotes WRAM size */ - if (info->iNES2) - WRAMSIZE = info->PRGRamSize + info->PRGRamSaveSize; - else - WRAMSIZE = info->mapper == 35 ? 8192 : 0; - - if (WRAMSIZE) { - WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); - } -} - -static void syncSingleCart(void) { - syncPRG(0x3F, (mode[3] << 5) & ~0x3F); - if (mode[3] & 0x20) { - syncCHR(0x1FF, (mode[3] << 6) & 0x600); - syncNT(0x1FF, (mode[3] << 6) & 0x600); - } else { - syncCHR(0x0FF, ((mode[3] << 8) & 0x100) | ((mode[3] << 6) & 0x600)); - syncNT(0x0FF, ((mode[3] << 8) & 0x100) | ((mode[3] << 6) & 0x600)); - } -} -void Mapper35_Init(CartInfo *info) { - /* Basically mapper 90/209/211 with WRAM */ - allowExtendedMirroring = 1; - WSync = syncSingleCart; - JYASIC_init(info); -} -void Mapper90_Init(CartInfo *info) { - /* Single cart, extended mirroring and ROM nametables disabled */ - allowExtendedMirroring = 0; - WSync = syncSingleCart; - JYASIC_init(info); -} - -void Mapper209_Init(CartInfo *info) { - /* Single cart, extended mirroring and ROM nametables enabled */ - allowExtendedMirroring = 1; - WSync = syncSingleCart; - JYASIC_init(info); -} - -void Mapper211_Init(CartInfo *info) { - /* Duplicate of mapper 209 */ - allowExtendedMirroring = 1; - WSync = syncSingleCart; - JYASIC_init(info); -} - -static void sync281(void) { - syncPRG(0x1F, mode[3] << 5); - syncCHR(0xFF, mode[3] << 8); - syncNT(0xFF, mode[3] << 8); -} - -void Mapper281_Init(CartInfo *info) { - /* Multicart */ - allowExtendedMirroring = 1; - WSync = sync281; - JYASIC_init(info); -} - -static void sync282(void) { - syncPRG(0x1F, (mode[3] << 4) & ~0x1F); - if (mode[3] & 0x20) { - syncCHR(0x1FF, (mode[3] << 6) & 0x600); - syncNT(0x1FF, (mode[3] << 6) & 0x600); - } else { - syncCHR(0x0FF, ((mode[3] << 8) & 0x100) | ((mode[3] << 6) & 0x600)); - syncNT(0x0FF, ((mode[3] << 8) & 0x100) | ((mode[3] << 6) & 0x600)); - } -} - -void Mapper282_Init(CartInfo *info) { - /* Multicart */ - allowExtendedMirroring = 1; - WSync = sync282; - JYASIC_init(info); -} - -void sync295(void) { - syncPRG(0x0F, mode[3] << 4); - syncCHR(0x7F, mode[3] << 7); - syncNT(0x7F, mode[3] << 7); -} - -void Mapper295_Init(CartInfo *info) { - /* Multicart */ - allowExtendedMirroring = 1; - WSync = sync295; - JYASIC_init(info); -} - -void sync358(void) { - syncPRG(0x1F, (mode[3] << 4) & ~0x1F); - if (mode[3] & 0x20) { - syncCHR(0x1FF, (mode[3] << 7) & 0x600); - syncNT(0x1FF, (mode[3] << 7) & 0x600); - } else { - syncCHR(0x0FF, ((mode[3] << 8) & 0x100) | ((mode[3] << 7) & 0x600)); - syncNT(0x0FF, ((mode[3] << 8) & 0x100) | ((mode[3] << 7) & 0x600)); - } -} - -void Mapper358_Init(CartInfo *info) { - /* Multicart */ - allowExtendedMirroring = 1; - WSync = sync358; - JYASIC_init(info); -} - -void sync386(void) { - syncPRG(0x1F, ((mode[3] << 4) & 0x20) | ((mode[3] << 3) & 0x40)); - if (mode[3] & 0x20) { - syncCHR(0x1FF, (mode[3] << 7) & 0x600); - syncNT(0x1FF, (mode[3] << 7) & 0x600); - } else { - syncCHR(0x0FF, ((mode[3] << 8) & 0x100) | ((mode[3] << 7) & 0x600)); - syncNT(0x0FF, ((mode[3] << 8) & 0x100) | ((mode[3] << 7) & 0x600)); - } -} - -void Mapper386_Init(CartInfo *info) { - /* Multicart */ - allowExtendedMirroring = 1; - WSync = sync386; - JYASIC_init(info); -} - -void sync387(void) { - syncPRG(0x0F, ((mode[3] << 3) & 0x10) | ((mode[3] << 2) & 0x20)); - if (mode[3] & 0x20) { - syncCHR(0x1FF, (mode[3] << 7) & 0x600); - syncNT(0x1FF, (mode[3] << 7) & 0x600); - } else { - syncCHR(0x0FF, ((mode[3] << 8) & 0x100) | ((mode[3] << 7) & 0x600)); - syncNT(0x0FF, ((mode[3] << 8) & 0x100) | ((mode[3] << 7) & 0x600)); - } -} - -void Mapper387_Init(CartInfo *info) { - /* Multicart */ - allowExtendedMirroring = 1; - WSync = sync387; - JYASIC_init(info); -} - -void sync388(void) { - syncPRG(0x1F, (mode[3] << 3) & 0x60); - - if (mode[3] & 0x20) { - syncCHR(0x1FF, (mode[3] << 8) & 0x200); - syncNT(0x1FF, (mode[3] << 8) & 0x200); - } else { - syncCHR(0x0FF, ((mode[3] << 8) & 0x100) | ((mode[3] << 8) & 0x200)); - syncNT(0x0FF, ((mode[3] << 8) & 0x100) | ((mode[3] << 8) & 0x200)); - } -} - -void Mapper388_Init(CartInfo *info) { - /* Multicart */ - allowExtendedMirroring = 0; - WSync = sync388; - JYASIC_init(info); -} - -void sync397(void) { - syncPRG(0x1F, (mode[3] << 4) & ~0x1F); - syncCHR(0x7F, mode[3] << 7); - syncNT(0x7F, mode[3] << 7); -} - -void Mapper397_Init(CartInfo *info) { - /* Multicart */ - allowExtendedMirroring = 1; - WSync = sync397; - JYASIC_init(info); -} - -void sync421(void) { - if (mode[3] & 0x04) - syncPRG(0x3F, (mode[3] << 4) & ~0x3F); - else - syncPRG(0x1F, (mode[3] << 4) & ~0x1F); - syncCHR(0x1FF, (mode[3] << 8) & 0x300); - syncNT(0x1FF, (mode[3] << 8) & 0x300); -} - -void Mapper421_Init(CartInfo *info) { - /* Multicart */ - allowExtendedMirroring = 1; - WSync = sync421; - JYASIC_init(info); -} - -/* Mapper 394: HSK007 circuit board that can simulate J.Y. ASIC, MMC3, and NROM. */ -static uint8 HSK007Reg[4]; -void sync394(void) /* Called when J.Y. ASIC is active */ -{ - int prgOR = ((HSK007Reg[3] << 1) & 0x010) | ((HSK007Reg[1] << 5) & 0x020); - int chrOR = ((HSK007Reg[3] << 1) & 0x080) | ((HSK007Reg[1] << 8) & 0x100); - syncPRG(0x1F, prgOR); - syncCHR(0xFF, chrOR); - syncNT(0xFF, chrOR); -} -static void Mapper394_PWrap(uint32 A, uint8 V) { - int prgAND = (HSK007Reg[3] & 0x10) ? 0x1F : 0x0F; - int prgOR = ((HSK007Reg[3] << 1) & 0x010) | ((HSK007Reg[1] << 5) & 0x020); - if (HSK007Reg[1] & 0x08) - setprg8(A, (V & prgAND) | (prgOR & ~prgAND)); - else if (A == 0x8000) - setprg32(A, (prgOR | ((HSK007Reg[3] << 1) & 0x0F)) >> 2); -} -static void Mapper394_CWrap(uint32 A, uint8 V) { - int chrAND = (HSK007Reg[3] & 0x80) ? 0xFF : 0x7F; - int chrOR = ((HSK007Reg[3] << 1) & 0x080) | ((HSK007Reg[1] << 8) & 0x100); - setchr1(A, (V & chrAND) | (chrOR & ~chrAND)); -} -static DECLFW(Mapper394_Write) { - uint8 oldMode = HSK007Reg[1]; - A &= 3; - HSK007Reg[A] = V; - if (A == 1) { - if ((~oldMode & 0x10) && (V & 0x10)) - JYASIC_power(); - if ((oldMode & 0x10) && (~V & 0x10)) { - JYASIC_restoreWriteHandlers(); - GenMMC3Power(); - } - } else { - if (HSK007Reg[1] & 0x10) - WSync(); - else { - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } - } -} -static void Mapper394_restore(int version) { - int i; - JYASIC_restoreWriteHandlers(); - if (HSK007Reg[1] & 0x10) { - SetWriteHandler(0x5000, 0x5FFF, writeALU); - SetWriteHandler(0x6000, 0x7fff, CartBW); - SetWriteHandler(0x8000, 0x87FF, writePRG); /* 8800-8FFF ignored */ - SetWriteHandler(0x9000, 0x97FF, writeCHRLow); /* 9800-9FFF ignored */ - SetWriteHandler(0xA000, 0xA7FF, writeCHRHigh); /* A800-AFFF ignored */ - SetWriteHandler(0xB000, 0xB7FF, writeNT); /* B800-BFFF ignored */ - SetWriteHandler(0xC000, 0xCFFF, writeIRQ); - SetWriteHandler(0xD000, 0xD7FF, writeMode); /* D800-DFFF ignored */ - - for (i = 0; i < 0x10000; i++) - cpuWriteHandlers[i] = GetWriteHandler(i); - SetWriteHandler(0x0000, 0xFFFF, trapCPUWrite); /* Trap all CPU writes for IRQ clocking purposes */ - cpuWriteHandlersSet = 1; - - SetReadHandler(0x5000, 0x5FFF, readALU_DIP); - SetReadHandler(0x6000, 0xFFFF, CartBR); - WSync(); - } else { - SetWriteHandler(0x8000, 0xBFFF, MMC3_CMDWrite); - SetWriteHandler(0xC000, 0xFFFF, MMC3_IRQWrite); - SetReadHandler(0x8000, 0xFFFF, CartBR); - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } -} -static void Mapper394_power(void) { - HSK007Reg[0] = 0x00; - HSK007Reg[1] = 0x0F; - HSK007Reg[2] = 0x00; - HSK007Reg[3] = 0x10; - GenMMC3Power(); - SetWriteHandler(0x5000, 0x5FFF, Mapper394_Write); -} - -void Mapper394_Init(CartInfo *info) { - allowExtendedMirroring = 1; - WSync = sync394; - JYASIC_init(info); - GenMMC3_Init(info, 128, 128, 0, 0); - mmc3.pwrap = Mapper394_PWrap; - mmc3.cwrap = Mapper394_CWrap; - info->Reset = Mapper394_power; - info->Power = Mapper394_power; - AddExState(HSK007Reg, 4, 0, "HSK "); - GameStateRestore = Mapper394_restore; -} diff --git a/src/boards/latch.h b/src/boards/latch.h deleted file mode 100644 index b66c7e5b5..000000000 --- a/src/boards/latch.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _FCEU_LATCH_H -#define _FCEU_LATCH_H - -typedef struct { - uint16 addr; - uint8 data; -} LATCH; - -extern LATCH latch; - -void Latch_Init(CartInfo *info, void (*proc)(void), readfunc func, uint8 wram, uint8 busc); -void LatchPower(void); -void LatchClose(void); -void LatchWrite(uint32 A, uint8 V); -void LatchHardReset(); - -#endif /* _FCEU_LATCH_H */ diff --git a/src/boards/mapper000.c b/src/boards/mapper000.c deleted file mode 100644 index e2ed8030e..000000000 --- a/src/boards/mapper000.c +++ /dev/null @@ -1,69 +0,0 @@ -/* FCEUmm - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2002 Xodnizel - * Copyright (C) 2023 - * - * 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" - -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; - -#ifdef DEBUG_MAPPER -static DECLFW(NROMWrite) { - FCEU_printf("bs %04x %02x\n", A, V); - CartBW(A, V); -} -#endif - -static void NROMClose(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -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, 1); - setchr8(0); - - SetReadHandler(0x6000, 0x7FFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetReadHandler(0x8000, 0xFFFF, CartBR); - - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); - -#ifdef DEBUG_MAPPER - SetWriteHandler(0x4020, 0xFFFF, NROMWrite); -#endif -} - -void NROM_Init(CartInfo *info) { - info->Power = NROMPower; - info->Close = NROMClose; - - 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/mapper028.c b/src/boards/mapper028.c deleted file mode 100644 index 19a3c0994..000000000 --- a/src/boards/mapper028.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - * 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 = 0; - uint8 prghi = 0; - - 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/mapper032.c b/src/boards/mapper032.c deleted file mode 100644 index 2f1eb7639..000000000 --- a/src/boards/mapper032.c +++ /dev/null @@ -1,102 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2012 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" - -static uint8 preg[2], creg[8], mirr; - -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; - -static SFORMAT StateRegs[] = -{ - { preg, 4, "PREG" }, - { creg, 8, "CREG" }, - { &mirr, 1, "MIRR" }, - { 0 } -}; - -static void Sync(void) { - uint8 i; - uint16 swap = ((mirr & 2) << 13); - setmirror((mirr & 1) ^ 1); - setprg8r(0x10, 0x6000, 0); - setprg8(0x8000 ^ swap, preg[0]); - setprg8(0xA000, preg[1]); - setprg8(0xC000 ^ swap, ~1); - setprg8(0xE000, ~0); - for (i = 0; i < 8; i++) - setchr1(i << 10, creg[i]); -} - -static DECLFW(M32Write0) { - preg[0] = V; - Sync(); -} - -static DECLFW(M32Write1) { - mirr = V; - Sync(); -} - -static DECLFW(M32Write2) { - preg[1] = V; - Sync(); -} - -static DECLFW(M32Write3) { - creg[A & 7] = V; - Sync(); -} - -static void M32Power(void) { - Sync(); - SetReadHandler(0x6000, 0x7fff, CartBR); - SetWriteHandler(0x6000, 0x7fff, CartBW); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0x8FFF, M32Write0); - SetWriteHandler(0x9000, 0x9FFF, M32Write1); - SetWriteHandler(0xA000, 0xAFFF, M32Write2); - SetWriteHandler(0xB000, 0xBFFF, M32Write3); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); -} - -static void M32Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper32_Init(CartInfo *info) { - info->Power = M32Power; - info->Close = M32Close; - 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/mapper033.c b/src/boards/mapper033.c deleted file mode 100644 index c72531392..000000000 --- a/src/boards/mapper033.c +++ /dev/null @@ -1,154 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2012 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" - -static uint8 is48; -static uint8 regs[8], mirr; -static uint8 IRQa; -static int16 IRQCount, IRQLatch; - -static SFORMAT StateRegs[] = -{ - { regs, 8, "PREG" }, - { &mirr, 1, "MIRR" }, - { &IRQa, 1, "IRQA" }, - { &IRQCount, 2, "IRQC" }, - { &IRQLatch, 2, "IRQL" }, - { 0 } -}; - -static void Sync(void) { - setmirror(mirr); - setprg8(0x8000, regs[0]); - setprg8(0xA000, regs[1]); - setprg8(0xC000, ~1); - setprg8(0xE000, ~0); - setchr2(0x0000, regs[2]); - setchr2(0x0800, regs[3]); - setchr1(0x1000, regs[4]); - setchr1(0x1400, regs[5]); - setchr1(0x1800, regs[6]); - setchr1(0x1C00, regs[7]); -} - -static DECLFW(M33Write) { - A &= 0xF003; - switch (A) { - case 0x8000: - regs[0] = V & 0x3F; - if (!is48) - mirr = ((V >> 6) & 1) ^ 1; - Sync(); - break; - case 0x8001: - regs[1] = V & 0x3F; - Sync(); - break; - case 0x8002: - regs[2] = V; - Sync(); - break; - case 0x8003: - regs[3] = V; - Sync(); - break; - case 0xA000: - regs[4] = V; - Sync(); - break; - case 0xA001: - regs[5] = V; - Sync(); - break; - case 0xA002: - regs[6] = V; - Sync(); - break; - case 0xA003: - regs[7] = V; - Sync(); - break; - } -} - -static DECLFW(M48Write) { - switch (A & 0xF003) { - case 0xC000: - IRQLatch = V; - break; - case 0xC001: - IRQCount = IRQLatch; - break; - case 0xC003: - IRQa = 0; - X6502_IRQEnd(FCEU_IQEXT); - break; - case 0xC002: - IRQa = 1; - break; - case 0xE000: - mirr = ((V >> 6) & 1) ^ 1; - Sync(); - break; - } -} - -static void M33Power(void) { - Sync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, M33Write); -} - -static void M48Power(void) { - Sync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xBFFF, M33Write); - SetWriteHandler(0xC000, 0xFFFF, M48Write); -} - -static void M48IRQ(void) { - if (IRQa) { - IRQCount++; - if (IRQCount == 0x100) { - X6502_IRQBegin(FCEU_IQEXT); - IRQa = 0; - } - } -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper33_Init(CartInfo *info) { - is48 = 0; - info->Power = M33Power; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} - -void Mapper48_Init(CartInfo *info) { - is48 = 1; - info->Power = M48Power; - GameHBIRQHook = M48IRQ; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/mapper034.c b/src/boards/mapper034.c deleted file mode 100644 index 9ca6e6299..000000000 --- a/src/boards/mapper034.c +++ /dev/null @@ -1,99 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2012 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 - * - * Many-in-one hacked mapper crap. - * - * Original BNROM is actually AxROM variations without mirroring control, - * and haven't SRAM on-board, so it must be removed from here - * - * Difficult banking is what NINA board doing, most hacks for 34 mapper are - * NINA hacks, so this is actually 34 mapper - * - */ - -#include "mapinc.h" - -static uint8 regs[3]; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; - -static SFORMAT StateRegs[] = -{ - { regs, 3, "REGS" }, - { 0 } -}; - -static void Sync(void) { - setprg8r(0x10, 0x6000, 0); - setprg32(0x8000, regs[0]); - setchr4(0x0000, regs[1]); - setchr4(0x1000, regs[2]); -} - -static DECLFW(M34Write) { - if (A >= 0x8000) - regs[0] = V; - else - switch (A) { - case 0x7ffd: - regs[0] = V; - break; - case 0x7ffe: - regs[1] = V; - break; - case 0x7fff: - regs[2] = V; - break; - } - Sync(); -} - -static void M34Power(void) { - regs[0] = regs[1] = 0; - regs[2] = 1; - Sync(); - SetReadHandler(0x6000, 0x7ffc, CartBR); - SetWriteHandler(0x6000, 0x7ffc, CartBW); - SetReadHandler(0x8000, 0xffff, CartBR); - SetWriteHandler(0x7ffd, 0xffff, M34Write); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); -} - -static void M34Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper34_Init(CartInfo *info) { - info->Power = M34Power; - info->Close = M34Close; - 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/mapper040.c b/src/boards/mapper040.c deleted file mode 100644 index f6ed1f91a..000000000 --- a/src/boards/mapper040.c +++ /dev/null @@ -1,121 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2012 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 - * - * FDS Conversion - * - */ - -#include "mapinc.h" - -static uint8 reg; -static uint32 IRQCount, IRQa; -static uint8 outer_bank; -static uint8 submapper; - -static SFORMAT StateRegs[] = -{ - { &IRQCount, 4, "IRQC" }, - { &IRQa, 4, "IRQA" }, - { ®, 1, "REG" }, - { &outer_bank, 1, "OUTB" }, - { 0 } -}; - -static void Sync(void) { - if (outer_bank & 8) { - if (outer_bank & 0x10) { - setprg32(0x8000, 2 | (outer_bank >> 6)); - } else { - setprg16(0x8000, 4 | (outer_bank >> 5)); - setprg16(0xC000, 4 | (outer_bank >> 5)); - } - } else { - setprg8(0x6000, 6); - setprg8(0x8000, 4); - setprg8(0xa000, 5); - setprg8(0xc000, reg & 7); - setprg8(0xe000, 7); - } - setchr8((outer_bank >> 1) & 3); - setmirror((outer_bank & 1) ^ 1); -} - -static DECLFW(M40Write) { - switch (A & 0xe000) { - case 0x8000: - IRQa = 0; - IRQCount = 0; - X6502_IRQEnd(FCEU_IQEXT); - break; - case 0xa000: - IRQa = 1; - break; - case 0xc000: - if (submapper == 1) { - outer_bank = A & 0xFF; - Sync(); - - } - break; - case 0xe000: - reg = V; - Sync(); - break; - } -} - -static void M40Power(void) { - reg = 0; - outer_bank = 0; - IRQCount = IRQa = 0; - Sync(); - SetReadHandler(0x6000, 0xffff, CartBR); - SetWriteHandler(0x8000, 0xffff, M40Write); -} - -static void M40Reset(void) { - reg = 0; - outer_bank = 0; - IRQCount = IRQa = 0; - Sync(); - } - -static void FP_FASTAPASS(1) M40IRQHook(int a) { - if (IRQa) { - if (IRQCount < 4096) - IRQCount += a; - else { - IRQa = 0; - X6502_IRQBegin(FCEU_IQEXT); - } - } -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper40_Init(CartInfo *info) { - info->Reset = M40Reset; - info->Power = M40Power; - MapIRQHook = M40IRQHook; - GameStateRestore = StateRestore; - submapper = info->submapper; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/mapper042.c b/src/boards/mapper042.c deleted file mode 100644 index f822363d7..000000000 --- a/src/boards/mapper042.c +++ /dev/null @@ -1,109 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2012 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 - * - * FDS Conversion - * - Ai Senshi Nicol (256K PRG, 128K CHR) - * - Bio Miracle Bokutte Upa (J) (128K PRG, 0K CHR) - */ - -#include "mapinc.h" -#include "../fds_apu.h" - -static uint8 preg, creg, mirr; -static uint32 IRQCount, IRQa; - -static SFORMAT StateRegs[] = -{ - { &preg, 1, "PREG" }, - { &creg, 1, "CREG" }, - { &mirr, 1, "MIRR" }, - { &IRQCount, 4, "IRQC" }, - { &IRQa, 4, "IRQA" }, - { 0 } -}; - -static void Sync(void) { - setprg8(0x6000, preg); - setprg32(0x8000, ~0); - setchr8(creg); - setmirror(mirr); -} - -static DECLFW(M42Write) { - switch (A & 0xE003) { - case 0x8000: - creg = V; - Sync(); - break; - case 0xE000: - preg = V & 0x0F; - Sync(); - break; - case 0xE001: - mirr = ((V >> 3) & 1) ^ 1; - Sync(); - break; - case 0xE002: - IRQa = V & 2; - if (!IRQa) - IRQCount = 0; - X6502_IRQEnd(FCEU_IQEXT); - break; - } -} - -static void M42Power(void) { - FDSSoundPower(); - preg = 0; - mirr = 1; /* Ai Senshi Nicol actually has fixed mirroring, but mapper forcing it's default value now */ - Sync(); - SetReadHandler(0x6000, 0xffff, CartBR); - SetWriteHandler(0x6000, 0xffff, M42Write); -} - -static void FP_FASTAPASS(1) M42IRQHook(int a) { - if (IRQa) { - IRQCount += a; - if (IRQCount >= 32768) - IRQCount -= 32768; - if (IRQCount >= 24576) - X6502_IRQBegin(FCEU_IQEXT); - else - X6502_IRQEnd(FCEU_IQEXT); - } -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper42_Init(CartInfo *info) { - if (info->iNES2 && (info->submapper == 2)) { - AC08_Init(info); - return; - } else if (UNIFchrrama && ((info->PRGRomSize == 163840) || (info->PRGRomSize == 262144))) { - /* Green Beret LH09 FDS Conversion can be 160K or 256K */ - AC08_Init(info); - return; - } - info->Power = M42Power; - MapIRQHook = M42IRQHook; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/mapper046.c b/src/boards/mapper046.c deleted file mode 100644 index 04e031226..000000000 --- a/src/boards/mapper046.c +++ /dev/null @@ -1,69 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2012 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" - -static uint8 reg0, reg1; - -static SFORMAT StateRegs[] = -{ - { ®0, 1, "REG0" }, - { ®1, 1, "REG1" }, - { 0 } -}; - -static void Sync(void) { - setprg32(0x8000, (reg1 & 1) + ((reg0 & 0xF) << 1)); - setchr8(((reg1 >> 4) & 7) + ((reg0 & 0xF0) >> 1)); -} - -static DECLFW(M46Write0) { - reg0 = V; - Sync(); -} - -static DECLFW(M46Write1) { - reg1 = V; - Sync(); -} - -static void M46Power(void) { - reg0 = reg1 = 0; - Sync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, M46Write0); - SetWriteHandler(0x8000, 0xFFFF, M46Write1); -} - -static void M46Reset(void) { - reg0 = reg1 = 0; - Sync(); -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper46_Init(CartInfo *info) { - info->Power = M46Power; - info->Reset = M46Reset; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/mapper062.c b/src/boards/mapper062.c deleted file mode 100644 index 15edc02e0..000000000 --- a/src/boards/mapper062.c +++ /dev/null @@ -1,69 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2012 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" - -static uint8 bank; -static uint16 mode; -static SFORMAT StateRegs[] = -{ - { &bank, 1, "BANK" }, - { &mode, 2, "MODE" }, - { 0 } -}; - -static void Sync(void) { - setchr8(((mode & 0x1F) << 2) | (bank & 0x03)); - if (mode & 0x20) { - setprg16(0x8000, (mode & 0x40) | ((mode >> 8) & 0x3F)); - setprg16(0xc000, (mode & 0x40) | ((mode >> 8) & 0x3F)); - } else - setprg32(0x8000, ((mode & 0x40) | ((mode >> 8) & 0x3F)) >> 1); - setmirror(((mode >> 7) & 1) ^ 1); -} - -static DECLFW(M62Write) { - mode = A & 0x3FFF; - bank = V & 3; - Sync(); -} - -static void M62Power(void) { - bank = mode = 0; - Sync(); - SetWriteHandler(0x8000, 0xFFFF, M62Write); - SetReadHandler(0x8000, 0xFFFF, CartBR); -} - -static void M62Reset(void) { - bank = mode = 0; - Sync(); -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper62_Init(CartInfo *info) { - info->Power = M62Power; - info->Reset = M62Reset; - AddExState(&StateRegs, ~0, 0, 0); - GameStateRestore = StateRestore; -} diff --git a/src/boards/mapper065.c b/src/boards/mapper065.c deleted file mode 100644 index cecbee4e7..000000000 --- a/src/boards/mapper065.c +++ /dev/null @@ -1,147 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2012 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" - -static uint8 preg[3], creg[8], mirr; -static uint8 IRQa; -static int16 IRQCount, IRQLatch; - -static SFORMAT StateRegs[] = -{ - { preg, 3, "PREG" }, - { creg, 8, "CREG" }, - { &mirr, 1, "MIRR" }, - { &IRQa, 1, "IRQA" }, - { &IRQCount, 2, "IRQC" }, - { &IRQLatch, 2, "IRQL" }, - { 0 } -}; - -static void Sync(void) { - setmirror(mirr); - setprg8(0x8000, preg[0]); - setprg8(0xA000, preg[1]); - setprg8(0xC000, preg[2]); - setprg8(0xE000, ~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(M65Write) { - switch (A) { - case 0x8000: - preg[0] = V; - Sync(); - break; - case 0xA000: - preg[1] = V; - Sync(); - break; - case 0xC000: - preg[2] = V; - Sync(); - break; - case 0x9001: - mirr = ((V >> 7) & 1) ^ 1; - Sync(); - break; - case 0x9003: - IRQa = V & 0x80; - X6502_IRQEnd(FCEU_IQEXT); - break; - case 0x9004: IRQCount = IRQLatch; break; - case 0x9005: - IRQLatch &= 0x00FF; - IRQLatch |= V << 8; - break; - case 0x9006: - IRQLatch &= 0xFF00; - IRQLatch |= V; - break; - case 0xB000: - creg[0] = V; - Sync(); - break; - case 0xB001: - creg[1] = V; - Sync(); - break; - case 0xB002: - creg[2] = V; - Sync(); - break; - case 0xB003: - creg[3] = V; - Sync(); - break; - case 0xB004: - creg[4] = V; - Sync(); - break; - case 0xB005: - creg[5] = V; - Sync(); - break; - case 0xB006: - creg[6] = V; - Sync(); - break; - case 0xB007: - creg[7] = V; - Sync(); - break; - } -} - -static void M65Power(void) { - preg[2] = ~1; - Sync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, M65Write); -} - -void FP_FASTAPASS(1) M65IRQ(int a) { - if (IRQa) { - IRQCount -= a; - if (IRQCount <= 0) { - X6502_IRQBegin(FCEU_IQEXT); - IRQa = 0; - } - } -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper65_Init(CartInfo *info) { - info->Power = M65Power; - MapIRQHook = M65IRQ; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/mapper067.c b/src/boards/mapper067.c deleted file mode 100644 index 02e2e7026..000000000 --- a/src/boards/mapper067.c +++ /dev/null @@ -1,121 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2012 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" - -static uint8 preg, creg[4], mirr, suntoggle = 0; -static uint8 IRQa; -static int16 IRQCount, IRQLatch; - -static SFORMAT StateRegs[] = -{ - { &preg, 1, "PREG" }, - { &suntoggle, 1, "STOG" }, - { creg, 4, "CREG" }, - { &mirr, 1, "MIRR" }, - { &IRQa, 1, "IRQA" }, - { &IRQCount, 2, "IRQC" }, - { &IRQLatch, 2, "IRQL" }, - { 0 } -}; - -static void Sync(void) { - setmirror(mirr); - setprg16(0x8000, preg); - setprg16(0xC000, ~0); - setchr2(0x0000, creg[0]); - setchr2(0x0800, creg[1]); - setchr2(0x1000, creg[2]); - setchr2(0x1800, creg[3]); - switch (mirr) { - case 0: setmirror(MI_V); break; - case 1: setmirror(MI_H); break; - case 2: setmirror(MI_0); break; - case 3: setmirror(MI_1); break; - } -} - -static DECLFW(M67Write) { - switch (A & 0xF800) { - case 0x8800: - creg[0] = V; - Sync(); - break; - case 0x9800: - creg[1] = V; - Sync(); - break; - case 0xA800: - creg[2] = V; - Sync(); - break; - case 0xB800: - creg[3] = V; - Sync(); - break; - case 0xC000: - case 0xC800: - IRQCount &= 0xFF << (suntoggle << 3); - IRQCount |= V << ((suntoggle ^ 1) << 3); - suntoggle ^= 1; - break; - case 0xD800: - suntoggle = 0; - IRQa = V & 0x10; - X6502_IRQEnd(FCEU_IQEXT); - break; - case 0xE800: - mirr = V & 3; - Sync(); - break; - case 0xF800: - preg = V; - Sync(); - break; - } -} - -static void M67Power(void) { - suntoggle = 0; - Sync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, M67Write); -} - -void FP_FASTAPASS(1) M67IRQ(int a) { - if (IRQa) { - IRQCount -= a; - if (IRQCount < 0) { - X6502_IRQBegin(FCEU_IQEXT); - IRQa = 0; - } - } -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper67_Init(CartInfo *info) { - info->Power = M67Power; - MapIRQHook = M67IRQ; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/mapper068.c b/src/boards/mapper068.c deleted file mode 100644 index b707eb58c..000000000 --- a/src/boards/mapper068.c +++ /dev/null @@ -1,164 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2006 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" - -static uint8 chr_reg[4]; -static uint8 kogame, prg_reg, nt1, nt2, mirr; - -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE, count; - -static SFORMAT StateRegs[] = -{ - { &nt1, 1, "NT1" }, - { &nt2, 1, "NT2" }, - { &mirr, 1, "MIRR" }, - { &prg_reg, 1, "PRG" }, - { &kogame, 1, "KGME" }, - { &count, 4, "CNT" }, - { chr_reg, 4, "CHR" }, - { 0 } -}; - -static void M68NTfix(void) { - if ((!UNIFchrrama) && (mirr & 0x10)) { - PPUNTARAM = 0; - switch (mirr & 3) { - case 0: - vnapage[0] = vnapage[2] = CHRptr[0] + (((nt1 | 128) & CHRmask1[0]) << 10); - vnapage[1] = vnapage[3] = CHRptr[0] + (((nt2 | 128) & CHRmask1[0]) << 10); - break; - case 1: - vnapage[0] = vnapage[1] = CHRptr[0] + (((nt1 | 128) & CHRmask1[0]) << 10); - vnapage[2] = vnapage[3] = CHRptr[0] + (((nt2 | 128) & CHRmask1[0]) << 10); - break; - case 2: - vnapage[0] = vnapage[1] = vnapage[2] = vnapage[3] = CHRptr[0] + (((nt1 | 128) & CHRmask1[0]) << 10); - break; - case 3: - vnapage[0] = vnapage[1] = vnapage[2] = vnapage[3] = CHRptr[0] + (((nt2 | 128) & CHRmask1[0]) << 10); - break; - } - } else - switch (mirr & 3) { - case 0: setmirror(MI_V); break; - case 1: setmirror(MI_H); break; - case 2: setmirror(MI_0); break; - case 3: setmirror(MI_1); break; - } -} - -static void Sync(void) { - setchr2(0x0000, chr_reg[0]); - setchr2(0x0800, chr_reg[1]); - setchr2(0x1000, chr_reg[2]); - setchr2(0x1800, chr_reg[3]); - setprg8r(0x10, 0x6000, 0); - setprg16r((PRGptr[1]) ? kogame : 0, 0x8000, prg_reg); - setprg16(0xC000, 0x07); -} - -static DECLFR(M68Read) { - if (!(kogame & 8)) { - count++; - if (count == 1784) - setprg16r(0, 0x8000, prg_reg); - } - return CartBR(A); -} - -static DECLFW(M68WriteLo) { - if (!V) { - count = 0; - setprg16r((PRGptr[1]) ? kogame : 0, 0x8000, prg_reg); - } - CartBW(A, V); -} - -static DECLFW(M68WriteCHR) { - chr_reg[(A >> 12) & 3] = V; - Sync(); -} - -static DECLFW(M68WriteNT1) { - nt1 = V; - M68NTfix(); -} - -static DECLFW(M68WriteNT2) { - nt2 = V; - M68NTfix(); -} - -static DECLFW(M68WriteMIR) { - mirr = V; - M68NTfix(); -} - -static DECLFW(M68WriteROM) { - prg_reg = V & 7; - kogame = ((V >> 3) & 1) ^ 1; - Sync(); -} - -static void M68Power(void) { - prg_reg = 0; - kogame = 0; - Sync(); - M68NTfix(); - SetReadHandler(0x6000, 0x7FFF, CartBR); - SetReadHandler(0x8000, 0xBFFF, M68Read); - SetReadHandler(0xC000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xBFFF, M68WriteCHR); - SetWriteHandler(0xC000, 0xCFFF, M68WriteNT1); - SetWriteHandler(0xD000, 0xDFFF, M68WriteNT2); - SetWriteHandler(0xE000, 0xEFFF, M68WriteMIR); - SetWriteHandler(0xF000, 0xFFFF, M68WriteROM); - SetWriteHandler(0x6000, 0x6000, M68WriteLo); - SetWriteHandler(0x6001, 0x7FFF, CartBW); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); -} - -static void M68Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -static void StateRestore(int version) { - Sync(); - M68NTfix(); -} - -void Mapper68_Init(CartInfo *info) { - info->Power = M68Power; - info->Close = M68Close; - 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/mapper069.c b/src/boards/mapper069.c deleted file mode 100644 index 57d574bb0..000000000 --- a/src/boards/mapper069.c +++ /dev/null @@ -1,382 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2012 CaH4e3 - * Copyright (C) 2002 Xodnizel - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "mapinc.h" - -static uint8 cmdreg, preg[4], creg[8], mirr; -static uint8 IRQa; -static int32 IRQCount; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; - -static void(*sfun[3]) (void); - -static SFORMAT StateRegs[] = -{ - { &cmdreg, 1, "CMDR" }, - { preg, 4, "PREG" }, - { creg, 8, "CREG" }, - { &mirr, 1, "MIRR" }, - { &IRQa, 1, "IRQA" }, - { &IRQCount, 4, "IRQC" }, - { 0 } -}; - -static void Sync(void) { - uint8 i; - if ((preg[3] & 0xC0) == 0xC0) - setprg8r(0x10, 0x6000, preg[3] & 0x3F); - else - setprg8(0x6000, preg[3] & 0x3F); - setprg8(0x8000, preg[0]); - setprg8(0xA000, preg[1]); - setprg8(0xC000, preg[2]); - setprg8(0xE000, ~0); - for (i = 0; i < 8; i++) - setchr1(i << 10, creg[i]); - switch (mirr & 3) { - case 0: setmirror(MI_V); break; - case 1: setmirror(MI_H); break; - case 2: setmirror(MI_0); break; - case 3: setmirror(MI_1); break; - } -} - -static DECLFW(M69WRAMWrite) { - if ((preg[3] & 0xC0) == 0xC0) - CartBW(A, V); -} - -static DECLFR(M69WRAMRead) { - if ((preg[3] & 0xC0) == 0x40) - return X.DB; - else - return CartBR(A); -} - -static DECLFW(M69Write0) { - cmdreg = V & 0xF; -} - -static DECLFW(M69Write1) { - switch (cmdreg) { - case 0x0: - creg[0] = V; - Sync(); - break; - case 0x1: - creg[1] = V; - Sync(); - break; - case 0x2: - creg[2] = V; - Sync(); - break; - case 0x3: - creg[3] = V; - Sync(); - break; - case 0x4: - creg[4] = V; - Sync(); - break; - case 0x5: - creg[5] = V; - Sync(); - break; - case 0x6: - creg[6] = V; - Sync(); - break; - case 0x7: - creg[7] = V; - Sync(); - break; - case 0x8: - preg[3] = V; - Sync(); - break; - case 0x9: - preg[0] = V; - Sync(); - break; - case 0xA: - preg[1] = V; - Sync(); - break; - case 0xB: - preg[2] = V; - Sync(); - break; - case 0xC: - mirr = V & 3; - Sync(); - break; - case 0xD: - IRQa = V; - X6502_IRQEnd(FCEU_IQEXT); - break; - case 0xE: - IRQCount &= 0xFF00; - IRQCount |= V; - break; - case 0xF: - IRQCount &= 0x00FF; - IRQCount |= V << 8; - break; - } -} - -/* SUNSOFT-5/FME-7 Sound */ - -static void AYSound(int Count); -static void AYSoundHQ(void); -static void DoAYSQ(int x); -static void DoAYSQHQ(int x); - -static uint8 sndcmd, sreg[14]; -static int32 vcount[3]; -static int32 dcount[3]; -static int32 CAYBC[3]; - -static SFORMAT SStateRegs[] = -{ - { &sndcmd, 1, "SCMD" }, - { sreg, 14, "SREG" }, - { dcount, 12, "DCNT" }, - { vcount, 12, "VCNT" }, - { CAYBC, 12, "BC00" }, - - { 0 } -}; - -static DECLFW(M69SWrite0) { - sndcmd = V % 14; -} - -static DECLFW(M69SWrite1) { - GameExpSound.Fill = AYSound; - GameExpSound.HiFill = AYSoundHQ; - switch (sndcmd) { - case 0: - case 1: - case 8: - if (sfun[0]) - sfun[0](); - break; - case 2: - case 3: - case 9: - if (sfun[1]) - sfun[1](); - break; - case 4: - case 5: - case 10: - if (sfun[2]) - sfun[2](); - break; - case 7: - if (sfun[0]) - sfun[0](); - if (sfun[1]) - sfun[1](); - break; - } - sreg[sndcmd] = V; -} - -static void DoAYSQ(int x) { - int32 freq = ((sreg[x << 1] | ((sreg[(x << 1) + 1] & 15) << 8)) + 1) << (4 + 17); - int32 amp = (sreg[0x8 + x] & 15) << 2; - int32 start, end; - int V; - - amp += amp >> 1; - - start = CAYBC[x]; - end = (SOUNDTS << 16) / soundtsinc; - if (end <= start) - return; - CAYBC[x] = end; - - if (amp && !(sreg[0x7] & (1 << x))) - for (V = start; V < end; V++) { - if (dcount[x]) - Wave[V >> 4] += amp; - vcount[x] -= nesincsize; - while (vcount[x] <= 0) { - dcount[x] ^= 1; - vcount[x] += freq; - } - } -} - -static void DoAYSQHQ(int x) { - uint32 V; - int32 freq = ((sreg[x << 1] | ((sreg[(x << 1) + 1] & 15) << 8)) + 1) << 4; - int32 amp = (sreg[0x8 + x] & 15) << 6; - - amp += amp >> 1; - - if (!(sreg[0x7] & (1 << x))) { - for (V = CAYBC[x]; V < SOUNDTS; V++) { - if (dcount[x]) - WaveHi[V] += amp; - vcount[x]--; - if (vcount[x] <= 0) { - dcount[x] ^= 1; - vcount[x] = freq; - } - } - } - CAYBC[x] = SOUNDTS; -} - -static void DoAYSQ1(void) { - DoAYSQ(0); -} - -static void DoAYSQ2(void) { - DoAYSQ(1); -} - -static void DoAYSQ3(void) { - DoAYSQ(2); -} - -static void DoAYSQ1HQ(void) { - DoAYSQHQ(0); -} - -static void DoAYSQ2HQ(void) { - DoAYSQHQ(1); -} - -static void DoAYSQ3HQ(void) { - DoAYSQHQ(2); -} - -static void AYSound(int Count) { - int x; - DoAYSQ1(); - DoAYSQ2(); - DoAYSQ3(); - for (x = 0; x < 3; x++) - CAYBC[x] = Count; -} - -static void AYSoundHQ(void) { - DoAYSQ1HQ(); - DoAYSQ2HQ(); - DoAYSQ3HQ(); -} - -static void AYHiSync(int32 ts) { - int x; - - for (x = 0; x < 3; x++) - CAYBC[x] = ts; -} - -void Mapper69_ESI(void) { - GameExpSound.RChange = Mapper69_ESI; - GameExpSound.HiSync = AYHiSync; - memset(dcount, 0, sizeof(dcount)); - memset(vcount, 0, sizeof(vcount)); - memset(CAYBC, 0, sizeof(CAYBC)); - if (FSettings.SndRate) { - if (FSettings.soundq >= 1) { - sfun[0] = DoAYSQ1HQ; - sfun[1] = DoAYSQ2HQ; - sfun[2] = DoAYSQ3HQ; - } else { - sfun[0] = DoAYSQ1; - sfun[1] = DoAYSQ2; - sfun[2] = DoAYSQ3; - } - } else - memset(sfun, 0, sizeof(sfun)); -} - -/* SUNSOFT-5/FME-7 Sound */ - -static void M69Power(void) { - cmdreg = sndcmd = 0; - IRQCount = 0xFFFF; - IRQa = 0; - Sync(); - SetReadHandler(0x6000, 0x7FFF, M69WRAMRead); - SetWriteHandler(0x6000, 0x7FFF, M69WRAMWrite); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0x9FFF, M69Write0); - SetWriteHandler(0xA000, 0xBFFF, M69Write1); - SetWriteHandler(0xC000, 0xDFFF, M69SWrite0); - SetWriteHandler(0xE000, 0xFFFF, M69SWrite1); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); -} - -static void M69Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -static void M69IRQHook(int a) { - if (IRQa) { - IRQCount -= a; - if (IRQCount <= 0) { - X6502_IRQBegin(FCEU_IQEXT); - IRQa = 0; - IRQCount = 0xFFFF; - } - } -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper69_Init(CartInfo *info) { - info->Power = M69Power; - info->Close = M69Close; - MapIRQHook = M69IRQHook; - WRAMSIZE = 8192; - WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; - } - GameStateRestore = StateRestore; - Mapper69_ESI(); - AddExState(&StateRegs, ~0, 0, 0); - AddExState(&SStateRegs, ~0, 0, 0); -} - -void NSFAY_Init(void) { - sndcmd = 0; - SetWriteHandler(0xC000, 0xDFFF, M69SWrite0); - SetWriteHandler(0xE000, 0xFFFF, M69SWrite1); - Mapper69_ESI(); - AddExState(&SStateRegs, ~0, 0, 0); -} diff --git a/src/boards/mapper080.c b/src/boards/mapper080.c deleted file mode 100644 index af853f0b8..000000000 --- a/src/boards/mapper080.c +++ /dev/null @@ -1,259 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2012 CaH4e3 - * Copyright (C) 2002 Xodnizel - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "mapinc.h" - -static uint8 preg[3], creg[6], isExMirr; -static uint8 mirr, cmd, wram_enable, wram[256]; -static uint8 mcache[8]; -static uint32 lastppu; - -static SFORMAT StateRegs80[] = -{ - { preg, 3, "PREG" }, - { creg, 6, "CREG" }, - { wram, 256, "WRAM" }, - { &mirr, 1, "MIRR" }, - { &wram_enable, 1, "WRME" }, - { 0 } -}; - -static SFORMAT StateRegs95[] = -{ - { &cmd, 1, "CMDR" }, - { preg, 3, "PREG" }, - { creg, 6, "CREG" }, - { mcache, 8, "MCCH" }, - { &lastppu, 4, "LPPU" }, - { 0 } -}; - -static SFORMAT StateRegs207[] = -{ - { preg, 3, "PREG" }, - { creg, 6, "CREG" }, - { mcache, 8, "MCCH" }, - { &lastppu, 4, "LPPU" }, - { 0 } -}; - -static void Sync(void) { - setprg8(0x8000, preg[0]); - setprg8(0xA000, preg[1]); - setprg8(0xC000, preg[2]); - setprg8(0xE000, ~0); - setchr2(0x0000, (creg[0] >> 1) & 0x3F); - setchr2(0x0800, (creg[1] >> 1) & 0x3F); - setchr1(0x1000, creg[2]); - setchr1(0x1400, creg[3]); - setchr1(0x1800, creg[4]); - setchr1(0x1C00, creg[5]); - if (isExMirr) { - setmirror(MI_0 + mcache[lastppu]); - } else - setmirror(mirr); -} - -static DECLFW(M80RamWrite) { - if (wram_enable == 0xA3) - wram[A & 0xFF] = V; -} - -static DECLFR(M80RamRead) { - if (wram_enable == 0xA3) - return wram[A & 0xFF]; - else - return 0xFF; -} - -static DECLFW(M80Write) { - switch (A) { - case 0x7EF0: - creg[0] = V; - mcache[0] = mcache[1] = V >> 7; - Sync(); - break; - case 0x7EF1: - creg[1] = V; - mcache[2] = mcache[3] = V >> 7; - Sync(); - break; - case 0x7EF2: - creg[2] = V; - mcache[4] = V >> 7; - Sync(); - break; - case 0x7EF3: - creg[3] = V; - mcache[5] = V >> 7; - Sync(); - break; - case 0x7EF4: - creg[4] = V; - mcache[6] = V >> 7; - Sync(); - break; - case 0x7EF5: - creg[5] = V; - mcache[7] = V >> 7; - Sync(); - break; - case 0x7EF6: - mirr = V & 1; - Sync(); - break; - case 0x7EF8: wram_enable = V; break; - case 0x7EFA: - case 0x7EFB: - preg[0] = V; - Sync(); - break; - case 0x7EFC: - case 0x7EFD: - preg[1] = V; - Sync(); - break; - case 0x7EFE: - case 0x7EFF: - preg[2] = V; - Sync(); - break; - } -} - -static DECLFW(M95Write) { - switch (A & 0xF001) { - case 0x8000: cmd = V; break; - case 0x8001: - switch (cmd & 0x07) { - case 0: - creg[0] = V & 0x1F; - mcache[0] = mcache[1] = (V >> 5) & 1; - Sync(); - break; - case 1: - creg[1] = V & 0x1F; - mcache[2] = mcache[3] = (V >> 5) & 1; - Sync(); - break; - case 2: - creg[2] = V & 0x1F; - mcache[4] = (V >> 5) & 1; - Sync(); - break; - case 3: - creg[3] = V & 0x1F; - mcache[5] = (V >> 5) & 1; - Sync(); - break; - case 4: - creg[4] = V & 0x1F; - mcache[6] = (V >> 5) & 1; - Sync(); - break; - case 5: - creg[5] = V & 0x1F; - mcache[7] = (V >> 5) & 1; - Sync(); - break; - case 6: - preg[0] = V; - Sync(); - break; - case 7: - preg[1] = V; - Sync(); - break; - } - Sync(); - } -} - -static void FP_FASTAPASS(1) MExMirrPPU(uint32 A) { - static int8 lastmirr = -1, curmirr; - if (A < 0x2000) { - lastppu = A >> 10; - curmirr = mcache[lastppu]; - if (curmirr != lastmirr) { - setmirror(MI_0 + curmirr); - lastmirr = curmirr; - } - } -} - -static void M80Power(void) { - wram_enable = 0xFF; - Sync(); - SetReadHandler(0x7F00, 0x7FFF, M80RamRead); - SetWriteHandler(0x7F00, 0x7FFF, M80RamWrite); - SetWriteHandler(0x7EF0, 0x7EFF, M80Write); - SetReadHandler(0x8000, 0xFFFF, CartBR); -} - -static void M207Power(void) { - mcache[0] = mcache[1] = mcache[2] = mcache[3] = 0; - mcache[4] = mcache[5] = mcache[6] = mcache[7] = 0; - Sync(); - SetWriteHandler(0x7EF0, 0x7EFF, M80Write); - SetReadHandler(0x8000, 0xFFFF, CartBR); -} - -static void M95Power(void) { - preg[2] = ~1; - mcache[0] = mcache[1] = mcache[2] = mcache[3] = 0; - mcache[4] = mcache[5] = mcache[6] = mcache[7] = 0; - Sync(); - SetWriteHandler(0x8000, 0xFFFF, M95Write); - SetReadHandler(0x8000, 0xFFFF, CartBR); -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper80_Init(CartInfo *info) { - isExMirr = 0; - info->Power = M80Power; - GameStateRestore = StateRestore; - - if (info->battery) { - info->SaveGame[0] = wram; - info->SaveGameLen[0] = 256; - } - - AddExState(&StateRegs80, ~0, 0, 0); -} - -void Mapper95_Init(CartInfo *info) { - isExMirr = 1; - info->Power = M95Power; - PPU_hook = MExMirrPPU; - GameStateRestore = StateRestore; - AddExState(&StateRegs95, ~0, 0, 0); -} - -void Mapper207_Init(CartInfo *info) { - isExMirr = 1; - info->Power = M207Power; - PPU_hook = MExMirrPPU; - GameStateRestore = StateRestore; - AddExState(&StateRegs207, ~0, 0, 0); -} diff --git a/src/boards/mapper088.c b/src/boards/mapper088.c deleted file mode 100644 index 3f13e45fd..000000000 --- a/src/boards/mapper088.c +++ /dev/null @@ -1,91 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2005 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" - -static uint8 reg[8]; -static uint8 mirror, cmd, is154; - -static SFORMAT StateRegs[] = -{ - { &cmd, 1, "CMD" }, - { &mirror, 1, "MIRR" }, - { reg, 8, "REGS" }, - { 0 } -}; - -static void Sync(void) { - setchr2(0x0000, reg[0] >> 1); - setchr2(0x0800, reg[1] >> 1); - setchr1(0x1000, reg[2] | 0x40); - setchr1(0x1400, reg[3] | 0x40); - setchr1(0x1800, reg[4] | 0x40); - setchr1(0x1C00, reg[5] | 0x40); - setprg8(0x8000, reg[6]); - setprg8(0xA000, reg[7]); - setprg8(0xC000, ~1); - setprg8(0xE000, ~0); -} - -static void MSync(void) { - if (is154) - setmirror(MI_0 + (mirror & 1)); -} - -static DECLFW(M88Write) { - switch (A & 0x8001) { - case 0x8000: - cmd = V & 7; - mirror = V >> 6; - MSync(); - break; - case 0x8001: - reg[cmd] = V; - Sync(); - break; - } -} - -static void M88Power(void) { - reg[0] = reg[1] = reg[2] = reg[3] = reg[4] = reg[5] = reg[6] = reg[7] = 0; - Sync(); - MSync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, M88Write); -} - -static void StateRestore(int version) { - Sync(); - MSync(); -} - -void Mapper88_Init(CartInfo *info) { - is154 = 0; - info->Power = M88Power; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} - -void Mapper154_Init(CartInfo *info) { - is154 = 1; - info->Power = M88Power; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/mapper091.c b/src/boards/mapper091.c deleted file mode 100644 index 578d211be..000000000 --- a/src/boards/mapper091.c +++ /dev/null @@ -1,134 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2012 CaH4e3 - * Copyright (C) 2020 - * - * 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 2020-2-15 - * Street Fighter 3, Mortal Kombat II, Dragon Ball Z 2, Mario & Sonic 2 (JY-016) - * 1995 Super HIK 4-in-1 (JY-016), 1995 Super HiK 4-in-1 (JY-017) - * submapper 1 - Super Fighter III - * NOTE: nesdev's notes for IRQ is different that whats implemented here - */ - -#include "mapinc.h" - -static uint8 cregs[4], pregs[2]; -static uint8 IRQCount, IRQa; -static uint8 submapper; -static uint8 outerbank; -static uint8 mirr; - -static SFORMAT StateRegs[] = -{ - { cregs, 4, "CREG" }, - { pregs, 2, "PREG" }, - { &IRQa, 1, "IRQA" }, - { &IRQCount, 1, "IRQC" }, - { &outerbank, 1, "BLOK" }, - { &mirr, 1, "MIRR" }, - { 0 } -}; - -static void Sync(void) { - /* FCEU_printf("P0:%02x P1:%02x outerbank:%02x\n", pregs[0], pregs[1], outerbank);*/ - setprg8(0x8000, pregs[0] | (outerbank & 6) << 3); - setprg8(0xa000, pregs[1] | (outerbank & 6) << 3); - setprg8(0xc000, 0xE | (outerbank & 6) << 3); - setprg8(0xe000, 0xF | (outerbank & 6) << 3); - setchr2(0x0000, cregs[0] | (outerbank & 1) << 8); - setchr2(0x0800, cregs[1] | (outerbank & 1) << 8); - setchr2(0x1000, cregs[2] | (outerbank & 1) << 8); - setchr2(0x1800, cregs[3] | (outerbank & 1) << 8); - - if (submapper == 1) - setmirror(mirr ^ 1); -} - -static DECLFW(M91Write0) { - switch (A & 7) { - case 0: - case 1: - case 2: - case 3: - cregs[A & 3] = V; - Sync(); - break; - case 4: - case 5: - mirr = V & 1; - Sync(); - break; - default: /*FCEU_printf("A:%04x V:%02x\n", A, V);*/ break; - } -} - -static DECLFW(M91Write1) { - switch (A & 3) { - case 0: - case 1: - pregs[A & 1] = V; - Sync(); - break; - case 2: - IRQa = IRQCount = 0; - X6502_IRQEnd(FCEU_IQEXT); - break; - case 3: - IRQa = 1; - X6502_IRQEnd(FCEU_IQEXT); - break; - } -} - -static DECLFW(M91Write2) { - outerbank = A & 7; - Sync(); -} - -static void M91Power(void) { - Sync(); - SetReadHandler(0x8000, 0xffff, CartBR); - SetWriteHandler(0x6000, 0x6fff, M91Write0); - SetWriteHandler(0x7000, 0x7fff, M91Write1); - SetWriteHandler(0x8000, 0x9fff, M91Write2); -} - -static void M91IRQHook(void) { - if (IRQCount < 8 && IRQa) { - IRQCount++; - if (IRQCount >= 8) { - X6502_IRQBegin(FCEU_IQEXT); - } - } -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper91_Init(CartInfo *info) { - submapper = 0; - /* Super Fighter III */ - if (info->submapper == 1) - submapper = info->submapper; - info->Power = M91Power; - GameHBIRQHook = M91IRQHook; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/mapper116.c b/src/boards/mapper116.c deleted file mode 100644 index 61aba14e9..000000000 --- a/src/boards/mapper116.c +++ /dev/null @@ -1,387 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2011 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 - * - * SL12 Protected 3-in-1 mapper hardware (VRC2, MMC3, MMC1) - * the same as 603-5052 board (TODO: add reading registers, merge) - * SL1632 2-in-1 protected board, similar to SL12 (TODO: find difference) - * - * Known PCB: - * - * Garou Densetsu Special (G0904.PCB, Huang-1, GAL dip: W conf.) - * Kart Fighter (008, Huang-1, GAL dip: W conf.) - * Somari (008, C5052-13, GAL dip: P conf., GK2-P/GK2-V maskroms) - * Somari (008, Huang-1, GAL dip: W conf., GK1-P/GK1-V maskroms) - * AV Mei Shao Nv Zhan Shi (aka AV Pretty Girl Fighting) (SL-12 PCB, Hunag-1, GAL dip: unk conf. SL-11A/SL-11B maskroms) - * Samurai Spirits (Full version) (Huang-1, GAL dip: unk conf. GS-2A/GS-4A maskroms) - * Contra Fighter (603-5052 PCB, C5052-3, GAL dip: unk conf. SC603-A/SCB603-B maskroms) - * - */ - -#include "mapinc.h" - -static uint8 vrc2_chr[8] = { 0 }; -static uint8 vrc2_prg[2] = { 0 }; -static uint8 vrc2_mirr = 0; - -static uint8 mmc3_regs[10] = { 0 }; -static uint8 mmc3_ctrl = 0; -static uint8 mmc3_mirr = 0; - -static uint8 mmc1_regs[4] = { 0 }; -static uint8 mmc1_buffer = 0; -static uint8 mmc1_shift = 0; - -static uint8 IRQCount = 0; -static uint8 IRQLatch = 0; -static uint8 IRQa = 0; -static uint8 IRQReload = 0; -static uint8 mode = 0; - -static uint8 submapper = 0; -static uint8 game = 0; - -static SFORMAT StateRegs[] = -{ - { &mode, 1, "MODE" }, - { vrc2_chr, 8, "VRCC" }, - { vrc2_prg, 2, "VRCP" }, - { &vrc2_mirr, 1, "VRCM" }, - { mmc3_regs, 10, "M3RG" }, - { &mmc3_ctrl, 1, "M3CT" }, - { &mmc3_mirr, 1, "M3MR" }, - { &IRQReload, 1, "IRQR" }, - { &IRQCount, 1, "IRQC" }, - { &IRQLatch, 1, "IRQL" }, - { &IRQa, 1, "IRQA" }, - { mmc1_regs, 4, "M1RG" }, - { &mmc1_buffer, 1, "M1BF" }, - { &mmc1_shift, 1, "M1MR" }, - { &submapper, 1, "SUBM" }, - { &game, 1, "GAME" }, - { 0 } -}; - -static void SyncPRG(void) { - uint8 mask = (submapper != 3) ? 0x3F : (game ? 0x0F : 0x1F); - uint8 outer = game ? (game + 1) * 0x10 : 0; - switch (mode & 3) { - case 0: - setprg8(0x8000, (outer & ~mask) | (vrc2_prg[0] & mask)); - setprg8(0xA000, (outer & ~mask) | (vrc2_prg[1] & mask)); - setprg8(0xC000, (outer & ~mask) | (~1 & mask)); - setprg8(0xE000, (outer & ~mask) | (~0 & mask)); - break; - case 1: { - uint32 swap = (mmc3_ctrl >> 5) & 2; - setprg8(0x8000, (outer & ~mask) | (mmc3_regs[6 + swap] & mask)); - setprg8(0xA000, (outer & ~mask) | (mmc3_regs[7] & mask)); - setprg8(0xC000, (outer & ~mask) | (mmc3_regs[6 + (swap ^ 2)] & mask)); - setprg8(0xE000, (outer & ~mask) | (mmc3_regs[9] & mask)); - break; - } - case 2: - case 3: { - uint8 bank = mmc1_regs[3] & mask; - if (mmc1_regs[0] & 8) { - if (submapper == 2) - bank >>= 1; - if (mmc1_regs[0] & 4) { - setprg16(0x8000, bank); - setprg16(0xC000, 0x0F); - } else { - setprg16(0x8000, 0); - setprg16(0xC000, bank); - } - } else - setprg32(0x8000, ((outer & ~mask) >> 1) | (bank >> 1)); - } break; - } -} - -static void SyncCHR(void) { - uint32 mask = game ? 0x7F : 0xFF; - uint32 outer = game ? (game + 1) * 0x80 : 0; - uint32 base = (mode & 4) << 6; - switch (mode & 3) { - case 0: - setchr1(0x0000, ((outer | base) & ~mask) | (vrc2_chr[0] & mask)); - setchr1(0x0400, ((outer | base) & ~mask) | (vrc2_chr[1] & mask)); - setchr1(0x0800, ((outer | base) & ~mask) | (vrc2_chr[2] & mask)); - setchr1(0x0c00, ((outer | base) & ~mask) | (vrc2_chr[3] & mask)); - setchr1(0x1000, ((outer | base) & ~mask) | (vrc2_chr[4] & mask)); - setchr1(0x1400, ((outer | base) & ~mask) | (vrc2_chr[5] & mask)); - setchr1(0x1800, ((outer | base) & ~mask) | (vrc2_chr[6] & mask)); - setchr1(0x1c00, ((outer | base) & ~mask) | (vrc2_chr[7] & mask)); - break; - case 1: { - uint32 swap = (mmc3_ctrl & 0x80) << 5; - setchr1(0x0000 ^ swap, ((outer | base) & ~mask) | ((mmc3_regs[0] & 0xFE) & mask)); - setchr1(0x0400 ^ swap, ((outer | base) & ~mask) | ((mmc3_regs[0] | 1) & mask)); - setchr1(0x0800 ^ swap, ((outer | base) & ~mask) | ((mmc3_regs[1] & 0xFE) & mask)); - setchr1(0x0c00 ^ swap, ((outer | base) & ~mask) | ((mmc3_regs[1] | 1) & mask)); - setchr1(0x1000 ^ swap, ((outer | base) & ~mask) | (mmc3_regs[2] & mask)); - setchr1(0x1400 ^ swap, ((outer | base) & ~mask) | (mmc3_regs[3] & mask)); - setchr1(0x1800 ^ swap, ((outer | base) & ~mask) | (mmc3_regs[4] & mask)); - setchr1(0x1c00 ^ swap, ((outer | base) & ~mask) | (mmc3_regs[5] & mask)); - break; - } - case 2: - case 3: - if (mmc1_regs[0] & 0x10) { - setchr4(0x0000, (outer & ~mask) | (mmc1_regs[1] & mask)); - setchr4(0x1000, (outer & ~mask) | (mmc1_regs[2] & mask)); - } else - setchr8(((outer & ~mask) >> 1) | (mmc1_regs[1] & mask) >> 1); - break; - } -} - -static void SyncMIR(void) { - switch (mode & 3) { - case 0: { - setmirror((vrc2_mirr & 1) ^ 1); - break; - } - case 1: { - setmirror((mmc3_mirr & 1) ^ 1); - break; - } - case 2: - case 3: { - switch (mmc1_regs[0] & 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; - } - break; - } - } -} - -static void Sync(void) { - SyncPRG(); - SyncCHR(); - SyncMIR(); -} - -static DECLFW(UNLSL12ModeWrite) { - /* FCEU_printf("%04X:%02X\n",A,V); */ - if (A & 0x100) { - mode = V; - if (A & 1) { /* hacky hacky, there are two configuration modes on SOMARI HUANG-1 PCBs - * Solder pads with P1/P2 shorted called SOMARI P, - * Solder pads with W1/W2 shorted called SOMARI W - * Both identical 3-in-1 but W wanted MMC1 registers - * to be reset when switch to MMC1 mode P one - doesn't - * There is issue with W version of Somari at starting copyrights - */ - mmc1_regs[0] = 0xc; - mmc1_regs[3] = 0; - mmc1_buffer = 0; - mmc1_shift = 0; - } - Sync(); - } -} - -static DECLFW(UNLSL12Write) { - /* FCEU_printf("%04X:%02X\n",A,V); */ - switch (mode & 3) { - case 0: { - if ((A >= 0xB000) && (A <= 0xE003)) { - int32 ind = ((((A & 2) | (A >> 10)) >> 1) + 2) & 7; - int32 sar = ((A & 1) << 2); - vrc2_chr[ind] = (vrc2_chr[ind] & (0xF0 >> sar)) | ((V & 0x0F) << sar); - SyncCHR(); - } else - switch (A & 0xF000) { - case 0x8000: - vrc2_prg[0] = V; - SyncPRG(); - break; - case 0xA000: - vrc2_prg[1] = V; - SyncPRG(); - break; - case 0x9000: - vrc2_mirr = V; - SyncMIR(); - break; - } - break; - } - case 1: { - switch (A & 0xE001) { - case 0x8000: { - uint8 old_ctrl = mmc3_ctrl; - mmc3_ctrl = V; - if ((old_ctrl & 0x40) != (mmc3_ctrl & 0x40)) - SyncPRG(); - if ((old_ctrl & 0x80) != (mmc3_ctrl & 0x80)) - SyncCHR(); - break; - } - case 0x8001: - mmc3_regs[mmc3_ctrl & 7] = V; - if ((mmc3_ctrl & 7) < 6) - SyncCHR(); - else - SyncPRG(); - break; - case 0xA000: - mmc3_mirr = V; - SyncMIR(); - break; - case 0xC000: - IRQLatch = V; - break; - case 0xC001: - IRQReload = 1; - break; - case 0xE000: - X6502_IRQEnd(FCEU_IQEXT); - IRQa = 0; - break; - case 0xE001: - IRQa = 1; - break; - } - break; - } - case 2: - case 3: { - if (V & 0x80) { - mmc1_regs[0] |= 0xc; - mmc1_buffer = mmc1_shift = 0; - SyncPRG(); - } else { - uint8 n = (A >> 13) - 4; - mmc1_buffer |= (V & 1) << (mmc1_shift++); - if (mmc1_shift == 5) { - mmc1_regs[n] = mmc1_buffer; - mmc1_buffer = mmc1_shift = 0; - switch (n) { - case 0: - SyncMIR(); - break; - case 2: - SyncCHR(); - break; - case 3: - case 1: - SyncPRG(); - break; - } - } - } - break; - } - } -} - -static void UNLSL12HBIRQ(void) { - if ((mode & 3) == 1) { - int32 count = IRQCount; - if (!count || IRQReload) { - IRQCount = IRQLatch; - IRQReload = 0; - } else - IRQCount--; - if (!IRQCount) { - if (IRQa) - X6502_IRQBegin(FCEU_IQEXT); - } - } -} - -static void StateRestore(int version) { - Sync(); -} - -static void UNLSL12Reset(void) { - /* this is suppose to increment during power cycle */ - /* but we dont have a way to do that, so increment on reset instead. */ - if (submapper == 3) { - game = game + 1; - if (game > 4) { - game = 0; - } - } - Sync(); -} - -static void UNLSL12Power(void) { - game = (submapper == 3) ? 4 : 0; - mode = 1; - vrc2_chr[0] = ~0; - vrc2_chr[1] = ~0; - vrc2_chr[2] = ~0; - vrc2_chr[3] = ~0; /* W conf. of Somari wanted CHR3 has to be set to BB bank (or similar), but doesn't do that directly */ - vrc2_chr[4] = 4; - vrc2_chr[5] = 5; - vrc2_chr[6] = 6; - vrc2_chr[7] = 7; - vrc2_prg[0] = 0; - vrc2_prg[1] = 1; - vrc2_mirr = 0; - mmc3_regs[0] = 0; - mmc3_regs[1] = 2; - mmc3_regs[2] = 4; - mmc3_regs[3] = 5; - mmc3_regs[4] = 6; - mmc3_regs[5] = 7; - mmc3_regs[6] = ~3; - mmc3_regs[7] = ~2; - mmc3_regs[8] = ~1; - mmc3_regs[9] = ~0; - mmc3_ctrl = mmc3_mirr = IRQCount = IRQLatch = IRQa = 0; - mmc1_regs[0] = 0xc; - mmc1_regs[1] = 0; - mmc1_regs[2] = 0; - mmc1_regs[3] = 0; - mmc1_buffer = 0; - mmc1_shift = 0; - Sync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x4100, 0x5FFF, UNLSL12ModeWrite); - SetWriteHandler(0x8000, 0xFFFF, UNLSL12Write); -} - -void UNLSL12_Init(CartInfo *info) { - info->Power = UNLSL12Power; - info->Reset = UNLSL12Reset; - GameHBIRQHook = UNLSL12HBIRQ; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); - submapper = info->submapper; - if (submapper == 0) { - /* PRG 128K and CHR 128K is Huang-2 (submapper 2) */ - if (ROM_size == 8 && VROM_size == 16) - submapper = 2; - } -} diff --git a/src/boards/mapper121.c b/src/boards/mapper121.c deleted file mode 100644 index 313af3da7..000000000 --- a/src/boards/mapper121.c +++ /dev/null @@ -1,155 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2007-2008 Mad Dumper, 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 - * - * Panda prince pirate. - * MK4, MK6, A9711/A9713 board - * 6035052 seems to be the same too, but with prot array in reverse - * A9746 seems to be the same too, check - * 187 seems to be the same too, check (A98402 board) - * - */ - -#include "mapinc.h" -#include "mmc3.h" - -static void Sync() { - switch (mmc3.expregs[5] & 0x3F) { - case 0x20: - mmc3.expregs[7] = 1; - mmc3.expregs[0] = mmc3.expregs[6]; - break; - case 0x29: - mmc3.expregs[7] = 1; - mmc3.expregs[0] = mmc3.expregs[6]; - break; - case 0x26: - mmc3.expregs[7] = 0; - mmc3.expregs[0] = mmc3.expregs[6]; - break; - case 0x2B: - mmc3.expregs[7] = 1; - mmc3.expregs[0] = mmc3.expregs[6]; - break; - case 0x2C: - mmc3.expregs[7] = 1; - if (mmc3.expregs[6]) - mmc3.expregs[0] = mmc3.expregs[6]; - break; - case 0x3C: - case 0x3F: - mmc3.expregs[7] = 1; - mmc3.expregs[0] = mmc3.expregs[6]; - break; - case 0x28: - mmc3.expregs[7] = 0; - mmc3.expregs[1] = mmc3.expregs[6]; - break; - case 0x2A: - mmc3.expregs[7] = 0; - mmc3.expregs[2] = mmc3.expregs[6]; - break; - case 0x2F: - break; - default: - mmc3.expregs[5] = 0; - break; - } -} - -static void M121CW(uint32 A, uint8 V) { - if (PRGsize[0] == CHRsize[0]) { /* A9713 multigame extension hack! */ - setchr1(A, V | ((mmc3.expregs[3] & 0x80) << 1)); - } else { - if ((A & 0x1000) == ((mmc3.cmd & 0x80) << 5)) - setchr1(A, V | 0x100); - else - setchr1(A, V); - } -} - -static void M121PW(uint32 A, uint8 V) { - setprg8(A, (V & 0x1F) | ((mmc3.expregs[3] & 0x80) >> 2)); - if (mmc3.expregs[5] & 0x3F) { - setprg8(0xE000, (mmc3.expregs[0]) | ((mmc3.expregs[3] & 0x80) >> 2)); - setprg8(0xC000, (mmc3.expregs[1]) | ((mmc3.expregs[3] & 0x80) >> 2)); - setprg8(0xA000, (mmc3.expregs[2]) | ((mmc3.expregs[3] & 0x80) >> 2)); - } -} - -static DECLFW(M121Write) { - /* FCEU_printf("write: %04x:%04x\n",A&0xE003,V); */ - switch (A & 0xE003) { - case 0x8000: -/* mmc3.expregs[5] = 0; */ -/* FCEU_printf("gen: %02x\n",V); */ - MMC3_CMDWrite(A, V); - FixMMC3PRG(mmc3.cmd); - break; - case 0x8001: - mmc3.expregs[6] = ((V & 1) << 5) | ((V & 2) << 3) | ((V & 4) << 1) | - ((V & 8) >> 1) | ((V & 0x10) >> 3) | ((V & 0x20) >> 5); -/* FCEU_printf("bank: %02x (%02x)\n",V,mmc3.expregs[6]); */ - if (!mmc3.expregs[7]) - Sync(); - MMC3_CMDWrite(A, V); - FixMMC3PRG(mmc3.cmd); - break; - case 0x8003: - mmc3.expregs[5] = V; - /* mmc3.expregs[7] = 0; */ - /* FCEU_printf("prot: %02x\n",mmc3.expregs[5]); */ - Sync(); - MMC3_CMDWrite(0x8000, V); - FixMMC3PRG(mmc3.cmd); - break; - } -} - -static uint8 prot_array[16] = { 0x83, 0x83, 0x42, 0x00 }; -static DECLFW(M121LoWrite) { - mmc3.expregs[4] = prot_array[V & 3]; /* 0x100 bit in address seems to be switch arrays 0, 2, 2, 3 (Contra Fighter) */ - if ((A & 0x5180) == 0x5180) { /* A9713 multigame extension */ - mmc3.expregs[3] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } - /* FCEU_printf("write: %04x:%04x\n",A,V); */ -} - -static DECLFR(M121Read) { - /* FCEU_printf("read: %04x->\n",A,mmc3.expregs[0]); */ - return mmc3.expregs[4]; -} - -static void M121Power(void) { - mmc3.expregs[3] = 0x80; - mmc3.expregs[5] = 0; - GenMMC3Power(); - SetReadHandler(0x5000, 0x5FFF, M121Read); - SetWriteHandler(0x5000, 0x5FFF, M121LoWrite); - SetWriteHandler(0x8000, 0x9FFF, M121Write); -} - -void Mapper121_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 256, 0, 0); - mmc3.pwrap = M121PW; - mmc3.cwrap = M121CW; - info->Power = M121Power; - AddExState(mmc3.expregs, 8, 0, "EXPR"); -} diff --git a/src/boards/mapper126-422-534.c b/src/boards/mapper126-422-534.c deleted file mode 100644 index dda554b0c..000000000 --- a/src/boards/mapper126-422-534.c +++ /dev/null @@ -1,139 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2020 NewRisingSun - * - * 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 422: "Normal" version of the mapper. Represents UNIF boards BS-400R and BS-4040R. - Mapper 126: Power Joy version of the mapper, connecting CHR A18 and A19 in reverse order. - Mapper 534: Waixing version of the mapper, inverting the reload value of the MMC3 scanline counter. -*/ - -#include "mapinc.h" -#include "mmc3.h" - -static uint8 reverseCHR_A18_A19; -static uint8 invertC000; -static uint8 dipSwitch; - -static void wrapPRG(uint32 A, uint8 V) { - int prgAND = (mmc3.expregs[0] & 0x40) ? 0x0F : 0x1F; /* 128 KiB or 256 KiB inner PRG bank selection */ - int prgOR = (((mmc3.expregs[0] << 4) & 0x70) | ((mmc3.expregs[0] << 3) & 0x180)) & ~prgAND; /* outer PRG bank */ - switch (mmc3.expregs[3] & 3) { - case 0: /* MMC3 PRG mode */ - break; - case 1: - case 2: /* NROM-128 mode: MMC3 register 6 applies throughout $8000-$FFFF, MMC3 A13 replaced with CPU A13. */ - V = (mmc3.regs[6] & ~1) | ((A >> 13) & 1); - setprg8(A ^ 0x4000, (V & prgAND) | prgOR); /* wrapPRG is only called with A containing the switchable banks, so we need to - manually switch the normally fixed banks in this mode as well. */ - break; - case 3: /* NROM-256 mode: MMC3 register 6 applies throughout $8000-$FFFF, MMC3 A13-14 replaced with CPU A13-14. */ - V = (mmc3.regs[6] & ~3) | ((A >> 13) & 3); - setprg8(A ^ 0x4000, ((V ^ 2) & prgAND) | prgOR); /* wrapPRG is only called with A containing the switchable banks, so we need to manually - switch the normally fixed banks in this mode as well. */ - break; - } - setprg8(A, (V & prgAND) | prgOR); -} - -static void wrapCHR(uint32 A, uint8 V) { - int chrAND = mmc3.expregs[0] & 0x80 ? 0x7F : 0xFF; /* 128 KiB or 256 KiB innter CHR bank selection */ - int chrOR; /* outer CHR bank */ - if (reverseCHR_A18_A19) /* Mapper 126 swaps CHR A18 and A19 */ - chrOR = ((mmc3.expregs[0] << 4) & 0x080) | ((mmc3.expregs[0] << 3) & 0x100) | ((mmc3.expregs[0] << 5) & 0x200); - else - chrOR = (mmc3.expregs[0] << 4) & 0x380; - - if (mmc3.expregs[3] & 0x10) /* CNROM mode: 8 KiB inner CHR bank comes from outer bank register #2 */ - setchr8((mmc3.expregs[2] & (chrAND >> 3)) | ((chrOR & ~chrAND) >> 3)); - else /* MMC3 CHR mode */ - setchr1(A, (V & chrAND) | (chrOR & ~chrAND)); -} - -static DECLFW(writeWRAM) { - if (~mmc3.expregs[3] & 0x80) { - /* Lock bit clear: Update any outer bank register */ - mmc3.expregs[A & 3] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } else if ((A & 3) == 2) { - /* Lock bit set: Only update the bottom one or two bits of the CNROM bank */ - int latchMask = (mmc3.expregs[2] & 0x10) ? 1 : 3; /* 16 or 32 KiB inner CHR bank selection */ - mmc3.expregs[2] &= ~latchMask; - mmc3.expregs[2] |= V & latchMask; - FixMMC3CHR(mmc3.cmd); - } - CartBW(A, V); -} - -static DECLFR(readDIP) { - uint8 result = CartBR(A); - if (mmc3.expregs[1] & 1) - result = (result & ~3) | (dipSwitch & 3); /* Replace bottom two bits with solder pad or DIP switch setting if so selected */ - return result; -} - -static DECLFW(writeIRQ) { - MMC3_IRQWrite(A, V ^ 0xFF); -} - -static void ResetCommon(void) { - dipSwitch++; /* Soft-resetting cycles through solder pad or DIP switch settings */ - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[2] = mmc3.expregs[3] = 0; - MMC3RegReset(); -} - -static void PowerCommon(void) { - dipSwitch = 0; - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[2] = mmc3.expregs[3] = 0; - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, writeWRAM); - SetReadHandler(0x8000, 0xFFFF, readDIP); - if (invertC000) - SetWriteHandler(0xC000, 0xDFFF, writeIRQ); /* Mapper 534 inverts the MMC3 scanline counter reload value */ -} - -static void InitCommon(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 8, info->battery); - mmc3.cwrap = wrapCHR; - mmc3.pwrap = wrapPRG; - - info->Power = PowerCommon; - info->Reset = ResetCommon; - - AddExState(mmc3.expregs, 4, 0, "EXPR"); - AddExState(&dipSwitch, 1, 0, "DPSW"); -} - -void Mapper126_Init(CartInfo *info) { - reverseCHR_A18_A19 = 1; - invertC000 = 0; - InitCommon(info); -} - -void Mapper422_Init(CartInfo *info) { - reverseCHR_A18_A19 = 0; - invertC000 = 0; - InitCommon(info); -} - -void Mapper534_Init(CartInfo *info) { - reverseCHR_A18_A19 = 0; - invertC000 = 1; - InitCommon(info); -} diff --git a/src/boards/mapper134.c b/src/boards/mapper134.c deleted file mode 100644 index b27a6349e..000000000 --- a/src/boards/mapper134.c +++ /dev/null @@ -1,97 +0,0 @@ -/* FCEUmm - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2020 - * - * 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 - */ - -/* Chipset used on various PCBs named WX-KB4K, T4A54A, BS-5652... */ -/* "Rockman 3" on YH-322 and "King of Fighters 97" on "Super 6-in-1" enable interrupts without initializing the frame IRQ register and therefore freeze on real hardware. - They can run if another game is selected that does initialize the frame IRQ register, then soft-resetting to the menu and selecting the previously-freezing games. */ - -#include "mapinc.h" -#include "mmc3.h" - -static uint8 dip; - -static void Mapper134_PRGWrap(uint32 A, uint8 V) { - int prgAND = (mmc3.expregs[1] & 0x04) ? 0x0F : 0x1F; - int prgOR = ((mmc3.expregs[1] << 4) & 0x30) | ((mmc3.expregs[0] << 2) & 0x40); - if (mmc3.expregs[1] & 0x80) { /* NROM mode */ - if (mmc3.expregs[1] & 0x08) { /* NROM-128 mode */ - setprg8(0x8000, (((mmc3.regs[6] & ~1) | 0) & prgAND) | (prgOR & ~prgAND)); - setprg8(0xA000, (((mmc3.regs[6] & ~1) | 1) & prgAND) | (prgOR & ~prgAND)); - setprg8(0xC000, (((mmc3.regs[6] & ~1) | 0) & prgAND) | (prgOR & ~prgAND)); - setprg8(0xE000, (((mmc3.regs[6] & ~1) | 1) & prgAND) | (prgOR & ~prgAND)); - } else { /* NROM-256 mode */ - setprg8(0x8000, (((mmc3.regs[6] & ~3) | 0) & prgAND) | (prgOR & ~prgAND)); - setprg8(0xA000, (((mmc3.regs[6] & ~3) | 1) & prgAND) | (prgOR & ~prgAND)); - setprg8(0xC000, (((mmc3.regs[6] & ~3) | 2) & prgAND) | (prgOR & ~prgAND)); - setprg8(0xE000, (((mmc3.regs[6] & ~3) | 3) & prgAND) | (prgOR & ~prgAND)); - } - } else - setprg8(A, (V & prgAND) | (prgOR & ~prgAND)); -} - -static void Mapper134_CHRWrap(uint32 A, uint8 V) { - int chrAND = (mmc3.expregs[1] & 0x40) ? 0x7F : 0xFF; - int chrOR = ((mmc3.expregs[1] << 3) & 0x180) | ((mmc3.expregs[0] << 4) & 0x200); - if (mmc3.expregs[0] & 0x08) - V = (mmc3.expregs[2] << 3) | ((A >> 10) & 7); /* In CNROM mode, outer bank register 2 replaces the MMC3's CHR registers, - and CHR A10-A12 are PPU A10-A12. */ - setchr1(A, (V & chrAND) | (chrOR & ~chrAND)); -} - -static DECLFR(Mapper134_Read) { - return (mmc3.expregs[0] & 0x40) ? dip : CartBR(A); -} - -static DECLFW(Mapper134_Write) { - if (~mmc3.expregs[0] & 0x80) { - mmc3.expregs[A & 3] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } else if ((A & 3) == 2) { - mmc3.expregs[A & 3] = (mmc3.expregs[A & 3] & ~3) | (V & 3); - FixMMC3CHR(mmc3.cmd); - } - CartBW(A, V); -} - -static void Mapper134_Reset(void) { - dip++; - dip &= 15; - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[2] = mmc3.expregs[3] = 0; - MMC3RegReset(); -} - -static void Mapper134_Power(void) { - dip = 0; - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[2] = mmc3.expregs[3] = 0; - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, Mapper134_Write); - SetReadHandler(0x8000, 0xFFFF, Mapper134_Read); -} - -void Mapper134_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, info->iNES2 ? (info->PRGRamSize + info->PRGRamSaveSize) / 1024 : 8, info->battery); - mmc3.cwrap = Mapper134_CHRWrap; - mmc3.pwrap = Mapper134_PRGWrap; - info->Power = Mapper134_Power; - info->Reset = Mapper134_Reset; - AddExState(mmc3.expregs, 4, 0, "EXPR"); - AddExState(&dip, 1, 0, "DIPS"); -} diff --git a/src/boards/mapper178.c b/src/boards/mapper178.c deleted file mode 100644 index 18044449d..000000000 --- a/src/boards/mapper178.c +++ /dev/null @@ -1,202 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2013 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 - * - * DSOUNDV1/FL-TR8MA boards (32K WRAM, 8/16M), 178 mapper boards (8K WRAM, 4/8M) - * Various Education Cartridges - * - * mapper 551 - * Compared to INES Mapper 178, mirroring is hard-wired, and the chipset's internal CHR-RAM is not used in favor of CHR-ROM. - * - */ - -#include "mapinc.h" - -static uint8 reg[4]; - -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; - -/* SND Registers */ -static uint8 pcm_enable = 0; -static int16 pcm_latch = 0x3F6, pcm_clock = 0x3F6; -static writefunc pcmwrite; -static int mappernum = 0; - -static SFORMAT StateRegs[] = -{ - { reg, 4, "REGS" }, - { 0 } -}; - -static int16 step_size[49] = { - 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, - 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, - 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, - 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, - 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552 -}; /* 49 items */ - -static int32 step_adj[16] = { -1, -1, -1, -1, 2, 5, 7, 9, -1, -1, -1, -1, 2, 5, 7, 9 }; - -/* decode stuff */ -static int32 jedi_table[16 * 49]; -static int32 acc = 0; /* ADPCM accumulator, initial condition must be 0 */ -static int32 decstep = 0; /* ADPCM decoding step, initial condition must be 0 */ - -static void jedi_table_init() { - int step, nib; - - for (step = 0; step < 49; step++) { - for (nib = 0; nib < 16; nib++) { - int value = (2 * (nib & 0x07) + 1) * step_size[step] / 8; - jedi_table[step * 16 + nib] = ((nib & 0x08) != 0) ? -value : value; - } - } -} - -static uint8 decode(uint8 code) { - acc += jedi_table[decstep + code]; - if ((acc & ~0x7ff) != 0) /* acc is > 2047 */ - acc |= ~0xfff; - else - acc &= 0xfff; - decstep += step_adj[code & 7] * 16; - if (decstep < 0) - decstep = 0; - if (decstep > 48 * 16) - decstep = 48 * 16; - return (acc >> 8) & 0xff; -} - -static void Sync(void) { - uint32 sbank = reg[1] & 0x7; - uint32 bbank = reg[2]; - if (reg[0] & 2) { /* UNROM mode */ - setprg16(0x8000, (bbank << 3) | sbank); - if (reg[0] & 4) - setprg16(0xC000, (bbank << 3) | 6 | (reg[1] & 1)); - else - setprg16(0xC000, (bbank << 3) | 7); - } else { /* NROM mode */ - uint32 bank = (bbank << 3) | sbank; - if (reg[0] & 4) { - setprg16(0x8000, bank); - setprg16(0xC000, bank); - } else - setprg32(0x8000, bank >> 1); - } - - if (mappernum == 551) { - setprg8r(0x10, 0x6000, 0); - setchr8(reg[3]); - setmirror(head.ROM_type & 1); - } else { - setchr8(0); - setprg8r(0x10, 0x6000, reg[3] & 3); - setmirror((reg[0] & 1) ^ 1); - } - - if (mappernum != 551) setmirror((reg[0] & 1) ^ 1); -} - -static DECLFW(M178Write) { - reg[A & 3] = V; - /* FCEU_printf("cmd %04x:%02x\n", A, V); */ - Sync(); -} - -static DECLFW(M178WriteSnd) { - if (A == 0x5800) { - if (V & 0xF0) { - pcm_enable = 1; - /* pcmwrite(0x4011, (V & 0xF) << 3); */ - pcmwrite(0x4011, decode(V & 0xf)); - } else - pcm_enable = 0; - } else - FCEU_printf("misc %04x:%02x\n", A, V); -} - -static DECLFR(M178ReadSnd) { - if (A == 0x5800) - return (X.DB & 0xBF) | ((pcm_enable ^ 1) << 6); - else - return X.DB; -} - -static void M178Power(void) { - reg[0] = reg[1] = reg[2] = reg[3] = 0; - Sync(); - pcmwrite = GetWriteHandler(0x4011); - SetWriteHandler(0x4800, 0x4fff, M178Write); - SetWriteHandler(0x5800, 0x5fff, M178WriteSnd); - SetReadHandler(0x5800, 0x5fff, M178ReadSnd); - SetReadHandler(0x6000, 0x7fff, CartBR); - SetWriteHandler(0x6000, 0x7fff, CartBW); - SetReadHandler(0x8000, 0xffff, CartBR); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); -} - -static void M178Reset(void) { - /* Always reset to menu */ - reg[0] = reg[1] = reg[2] = reg[3] = 0; - Sync(); -} -static void M178SndClk(int a) { - if (pcm_enable) { - pcm_latch -= a; - if (pcm_latch <= 0) { - pcm_latch += pcm_clock; - pcm_enable = 0; - } - } -} - -static void M178Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper178_Init(CartInfo *info) { - info->Power = M178Power; - info->Reset = M178Reset; - info->Close = M178Close; - GameStateRestore = StateRestore; - MapIRQHook = M178SndClk; - - jedi_table_init(); - - WRAMSIZE = 32768; - 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); - - mappernum = info->mapper; -} diff --git a/src/boards/mapper206.c b/src/boards/mapper206.c deleted file mode 100644 index 0f7c3293a..000000000 --- a/src/boards/mapper206.c +++ /dev/null @@ -1,80 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2002 Xodnizel - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "mapinc.h" - -static uint8 cmd; -static uint8 DRegs[8]; - -static SFORMAT StateRegs[] = -{ - { &cmd, 1, "CMD" }, - { DRegs, 8, "DREG" }, - { 0 } -}; - -static void Sync(void) { - int x; - setchr2(0x0000, DRegs[0]); - setchr2(0x0800, DRegs[1]); - for (x = 0; x < 4; x++) - setchr1(0x1000 + (x << 10), DRegs[2 + x]); - setprg8(0x8000, DRegs[6]); - setprg8(0xa000, DRegs[7]); - setprg8(0xc000, ~1); - setprg8(0xe000, ~0); -} - -static void StateRestore(int version) { - Sync(); -} - -static DECLFW(M206Write) { - switch (A & 0x8001) { - case 0x8000: - cmd = V & 0x07; - break; - case 0x8001: - if (cmd <= 0x05) - V &= 0x3F; - else - V &= 0x0F; - if (cmd <= 0x01) - V >>= 1; - DRegs[cmd & 0x07] = V; - Sync(); - break; - } -} - -static void M206Power(void) { - cmd = 0; - DRegs[6] = 0; - DRegs[7] = 1; - Sync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, M206Write); -} - -void Mapper206_Init(CartInfo *info) { - info->Power = M206Power; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/mapper215.c b/src/boards/mapper215.c deleted file mode 100644 index d790e1b40..000000000 --- a/src/boards/mapper215.c +++ /dev/null @@ -1,191 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2011 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 - * - * Submapper 0, UNIF board name UNL-8237: - * Earthworm Jim 2 - * Mortal Kombat 3 (SuperGame, not Extra 60, not to be confused by similarly-named games from other developers) - * Mortal Kombat 3 Extra 60 (both existing ROM images are just extracts of the 2-in-1 multicart containing this game) - * Pocahontas Part 2 - * 2-in-1: Aladdin, EarthWorm Jim 2 (Super 808) - * 2-in-1: The Lion King, Bomber Boy (GD-103) - * 2-in-1: Super Golden Card: EarthWorm Jim 2, Boogerman (king002) - * 2-in-1: Mortal Kombat 3 Extra 60, The Super Shinobi (king005) - * 3-in-1: Boogerman, Adventure Island 3, Double Dragon 3 (Super 308) - * 5-in-1: Golden Card: Aladdin, EarthWorm Jim 2, Garo Densetsu Special, Silkworm, Contra Force (SPC005) - * 6-in-1: Golden Card: EarthWorm Jim 2, Mortal Kombat 3, Double Dragon 3, Contra 3, The Jungle Book, Turtles Tournament Fighters (SPC009) - * - * Submapper 1, UNIF board name UNL-8237A: - * 9-in-1 High Standard Card: The Lion King, EarthWorm Jim 2, Aladdin, Boogerman, Somari, Turtles Tournament Fighters, Mortal Kombat 3, Captain Tsubasa 2, Taito Basketball (king001) - */ - -#include "mapinc.h" -#include "mmc3.h" - -static uint8 submapper; - -static uint8 regperm[8][8] = -{ - { 0, 1, 2, 3, 4, 5, 6, 7 }, - { 0, 2, 6, 1, 7, 3, 4, 5 }, - { 0, 5, 4, 1, 7, 2, 6, 3 }, /* unused */ - { 0, 6, 3, 7, 5, 2, 4, 1 }, - { 0, 2, 5, 3, 6, 1, 7, 4 }, - { 0, 1, 2, 3, 4, 5, 6, 7 }, /* empty */ - { 0, 1, 2, 3, 4, 5, 6, 7 }, /* empty */ - { 0, 1, 2, 3, 4, 5, 6, 7 }, /* empty */ -}; - -static uint8 adrperm[8][8] = -{ - { 0, 1, 2, 3, 4, 5, 6, 7 }, - { 3, 2, 0, 4, 1, 5, 6, 7 }, - { 0, 1, 2, 3, 4, 5, 6, 7 }, /* unused */ - { 5, 0, 1, 2, 3, 7, 6, 4 }, - { 3, 1, 0, 5, 2, 4, 6, 7 }, - { 0, 1, 2, 3, 4, 5, 6, 7 }, /* empty */ - { 0, 1, 2, 3, 4, 5, 6, 7 }, /* empty */ - { 0, 1, 2, 3, 4, 5, 6, 7 }, /* empty */ -}; - -static uint8 protarray[8][8] = { - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 0 Super Hang-On */ - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00 }, /* 1 Monkey King */ - { 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, 0x00, 0x00 }, /* 2 Super Hang-On/Monkey King */ - { 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x05, 0x00 }, /* 3 Super Hang-On/Monkey King */ - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 4 */ - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 5 */ - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 6 */ - { 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x0F, 0x00 } /* 7 (default) Blood of Jurassic */ -}; - -static void UNL8237CW(uint32 A, uint8 V) { - uint16 outer_bank; - - if (submapper == 1) - outer_bank = ((mmc3.expregs[1] & 0xE) << 7); - else - outer_bank = ((mmc3.expregs[1] & 0xC) << 6); - - if (mmc3.expregs[0] & 0x40) - setchr1(A, outer_bank | (V & 0x7F) | ((mmc3.expregs[1] & 0x20) << 2)); - else - setchr1(A, outer_bank | V); -} - -static void UNL8237PW(uint32 A, uint8 V) { - uint8 outer_bank = ((mmc3.expregs[1] & 3) << 5); - - if (submapper == 1) - outer_bank |= ((mmc3.expregs[1] & 8) << 4); - - if (mmc3.expregs[0] & 0x40) { - uint8 sbank = (mmc3.expregs[1] & 0x10); - if (mmc3.expregs[0] & 0x80) { /* NROM */ - uint8 bank = (outer_bank >> 1) | (mmc3.expregs[0] & 0x7) | (sbank >> 1); - if (mmc3.expregs[0] & 0x20) /* NROM-256 */ - setprg32(0x8000, bank >> 1); - else { /* NROM-128 */ - setprg16(0x8000, bank); - setprg16(0xC000, bank); - } - } else - setprg8(A, outer_bank | (V & 0x0F) | sbank); - } else { - if (mmc3.expregs[0] & 0x80) { /* NROM */ - uint8 bank = (outer_bank >> 1) | (mmc3.expregs[0] & 0xF); - if (mmc3.expregs[0] & 0x20) /* NROM-256 */ - setprg32(0x8000, bank >> 1); - else { /* NROM-128 */ - setprg16(0x8000, bank); - setprg16(0xC000, bank); - } - } else - setprg8(A, outer_bank | (V & 0x1F)); - } -} - -static DECLFR(UNL8237ProtRead) { - return (protarray[mmc3.expregs[3]][A & 7] & 0x0F) | 0x50; -} - -static DECLFW(UNL8237Write) { - uint8 dat = V; - uint8 adr = adrperm[mmc3.expregs[2]][((A >> 12) & 6) | (A & 1)]; - uint16 addr = (adr & 1) | ((adr & 6) << 12) | 0x8000; - if (adr < 4) { - if (!adr) - dat = (dat & 0xC0) | (regperm[mmc3.expregs[2]][dat & 7]); - MMC3_CMDWrite(addr, dat); - } else - MMC3_IRQWrite(addr, dat); -} - -static DECLFW(UNL8237ExWrite) { - switch (A & 0xF007) { - case 0x5000: - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - break; - case 0x5001: - mmc3.expregs[1] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - break; - case 0x5002: - mmc3.expregs[3] = V; - break; - case 0x5007: - mmc3.expregs[2] = V; - break; - } -} - -static void UNL8237Power(void) { - mmc3.expregs[0] = mmc3.expregs[2] = 0; - mmc3.expregs[1] = 0x0F; - mmc3.expregs[3] = 7; - GenMMC3Power(); - SetWriteHandler(0x8000, 0xFFFF, UNL8237Write); - SetReadHandler(0x5000, 0x5FFF, UNL8237ProtRead); - SetWriteHandler(0x5000, 0x5FFF, UNL8237ExWrite); -} - -static void UNL8237Reset(void) { - mmc3.expregs[0] = mmc3.expregs[2] = 0; - mmc3.expregs[1] = 0x0F; - mmc3.expregs[3] = 7; - MMC3RegReset(); -} - -void UNL8237_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 0, 0); - mmc3.cwrap = UNL8237CW; - mmc3.pwrap = UNL8237PW; - info->Power = UNL8237Power; - info->Reset = UNL8237Reset; - AddExState(mmc3.expregs, 4, 0, "EXPR"); - if (info->iNES2) - submapper = info->submapper; -} - -void UNL8237A_Init(CartInfo *info) { - UNL8237_Init(info); - submapper = 1; -} diff --git a/src/boards/mapper232.c b/src/boards/mapper232.c deleted file mode 100644 index a157407f0..000000000 --- a/src/boards/mapper232.c +++ /dev/null @@ -1,69 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2012 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" - -static uint8 bank, preg; -static SFORMAT StateRegs[] = -{ - { &bank, 1, "BANK" }, - { &preg, 1, "PREG" }, - { 0 } -}; - -static void Sync(void) { - /* uint32 bbank = (bank & 0x18) >> 1; */ - uint32 bbank = ((bank & 0x10) >> 2) | (bank & 8); /* some dumps have bbanks swapped, if swap commands, - * then all roms can be played, but with some swapped - * games in menu. if not, some dumps are unplayable - * make hard dump for both cart types to check - */ - setprg16(0x8000, bbank | (preg & 3)); - setprg16(0xC000, bbank | 3); - setchr8(0); -} - -static DECLFW(M232WriteBank) { - bank = V; - Sync(); -} - -static DECLFW(M232WritePreg) { - preg = V; - Sync(); -} - -static void M232Power(void) { - bank = preg = 0; - Sync(); - SetWriteHandler(0x8000, 0xBFFF, M232WriteBank); - SetWriteHandler(0xC000, 0xFFFF, M232WritePreg); - SetReadHandler(0x8000, 0xFFFF, CartBR); -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper232_Init(CartInfo *info) { - info->Power = M232Power; - AddExState(&StateRegs, ~0, 0, 0); - GameStateRestore = StateRestore; -} diff --git a/src/boards/mapper252.c b/src/boards/mapper252.c deleted file mode 100644 index a53ddfd84..000000000 --- a/src/boards/mapper252.c +++ /dev/null @@ -1,154 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2009 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" - -static uint8 creg[8], preg[2]; -static int32 IRQa, IRQCount, IRQClock, IRQLatch; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; -static uint8 *CHRRAM = NULL; -static uint32 CHRRAMSIZE; - -static SFORMAT StateRegs[] = -{ - { creg, 8, "CREG" }, - { preg, 2, "PREG" }, - { &IRQa, 4, "IRQA" }, - { &IRQCount, 4, "IRQC" }, - { &IRQLatch, 4, "IRQL" }, - { &IRQClock, 4, "IRQK" }, - { 0 } -}; - -static void Sync(void) { - uint8 i; - setprg8r(0x10, 0x6000, 0); - setprg8(0x8000, preg[0]); - setprg8(0xa000, preg[1]); - setprg8(0xc000, ~1); - setprg8(0xe000, ~0); - for (i = 0; i < 8; i++) - if ((creg[i] == 6) || (creg[i] == 7)) - setchr1r(0x10, i << 10, creg[i] & 1); - else - setchr1(i << 10, creg[i]); -} - -static DECLFW(M252Write) { - if ((A >= 0xB000) && (A <= 0xEFFF)) { - uint8 ind = ((((A & 8) | (A >> 8)) >> 3) + 2) & 7; - uint8 sar = A & 4; - creg[ind] = (creg[ind] & (0xF0 >> sar)) | ((V & 0x0F) << sar); - Sync(); - } else - switch (A & 0xF00C) { - case 0x8000: - case 0x8004: - case 0x8008: - case 0x800C: - preg[0] = V; - Sync(); - break; - case 0xA000: - case 0xA004: - case 0xA008: - case 0xA00C: - preg[1] = V; - Sync(); - break; - case 0xF000: - X6502_IRQEnd(FCEU_IQEXT); - IRQLatch &= 0xF0; - IRQLatch |= V & 0xF; - break; - case 0xF004: - X6502_IRQEnd(FCEU_IQEXT); - IRQLatch &= 0x0F; - IRQLatch |= V << 4; - break; - case 0xF008: - X6502_IRQEnd(FCEU_IQEXT); - IRQClock = 0; - IRQCount = IRQLatch; - IRQa = V & 2; - break; - } -} - -static void M252Power(void) { - Sync(); - SetReadHandler(0x6000, 0x7FFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, M252Write); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); -} - -static void M252IRQ(int a) { -#define LCYCS 341 - if (IRQa) { - IRQClock += a * 3; - if (IRQClock >= LCYCS) { - while (IRQClock >= LCYCS) { - IRQClock -= LCYCS; - IRQCount++; - if (IRQCount & 0x100) { - X6502_IRQBegin(FCEU_IQEXT); - IRQCount = IRQLatch; - } - } - } - } -} - -static void M252Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - if (CHRRAM) - FCEU_gfree(CHRRAM); - WRAM = CHRRAM = NULL; -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper252_Init(CartInfo *info) { - info->Power = M252Power; - info->Close = M252Close; - MapIRQHook = M252IRQ; - - CHRRAMSIZE = 2048; - CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); - SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); - AddExState(CHRRAM, CHRRAMSIZE, 0, "CRAM"); - - WRAMSIZE = 8192; - WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; - } - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/mapper253.c b/src/boards/mapper253.c deleted file mode 100644 index 3deaea592..000000000 --- a/src/boards/mapper253.c +++ /dev/null @@ -1,183 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2009 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" - -static uint8 chrlo[8], chrhi[8], prg[2], mirr, vlock; -static int32 IRQa, IRQCount, IRQLatch, IRQClock; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; -static uint8 *CHRRAM = NULL; -static uint32 CHRRAMSIZE; - -static SFORMAT StateRegs[] = -{ - { chrlo, 8, "CHRL" }, - { chrhi, 8, "CHRH" }, - { prg, 2, "PRGR" }, - { &mirr, 1, "MIRR" }, - { &vlock, 1, "VLCK" }, - { &IRQa, 4, "IRQA" }, - { &IRQCount, 4, "IRQC" }, - { &IRQLatch, 4, "IRQL" }, - { &IRQClock, 4, "IRQK" }, - { 0 } -}; - -static void Sync(void) { - uint8 i; - setprg8r(0x10, 0x6000, 0); - setprg8(0x8000, prg[0]); - setprg8(0xa000, prg[1]); - setprg8(0xc000, ~1); - setprg8(0xe000, ~0); - for (i = 0; i < 8; i++) { - uint32 chr = chrlo[i] | (chrhi[i] << 8); - if (((chrlo[i] == 4) || (chrlo[i] == 5)) && !vlock) - setchr1r(0x10, i << 10, chr & 1); - else - setchr1(i << 10, chr); - } - switch (mirr) { - case 0: - setmirror(MI_V); - break; - case 1: - setmirror(MI_H); - break; - case 2: - setmirror(MI_0); - break; - case 3: - setmirror(MI_1); - break; - } -} - -static DECLFW(M253Write) { - if ((A >= 0xB000) && (A <= 0xE00C)) { - uint8 ind = ((((A & 8) | (A >> 8)) >> 3) + 2) & 7; - uint8 sar = A & 4; - uint8 clo = (chrlo[ind] & (0xF0 >> sar)) | ((V & 0x0F) << sar); - chrlo[ind] = clo; - if (ind == 0) { - if (clo == 0xc8) - vlock = 0; - else if (clo == 0x88) - vlock = 1; - } - if (sar) - chrhi[ind] = V >> 4; - Sync(); - } else { - switch (A) { - case 0x8010: - prg[0] = V; - Sync(); - break; - case 0xA010: - prg[1] = V; - Sync(); - break; - case 0x9400: - mirr = V & 3; - Sync(); - break; - case 0xF000: - X6502_IRQEnd(FCEU_IQEXT); - IRQLatch &= 0xF0; - IRQLatch |= V & 0xF; - break; - case 0xF004: - X6502_IRQEnd(FCEU_IQEXT); - IRQLatch &= 0x0F; - IRQLatch |= V << 4; - break; - case 0xF008: - X6502_IRQEnd(FCEU_IQEXT); - IRQClock = 0; - IRQCount = IRQLatch; - IRQa = V & 2; - break; - } - } -} - -static void M253Power(void) { - vlock = 0; - Sync(); - SetReadHandler(0x6000, 0x7FFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, M253Write); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); -} - -static void M253Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - if (CHRRAM) - FCEU_gfree(CHRRAM); - WRAM = CHRRAM = NULL; -} - -static void M253IRQ(int a) { -#define LCYCS 341 - if (IRQa) { - IRQClock += a * 3; - if (IRQClock >= LCYCS) { - while (IRQClock >= LCYCS) { - IRQClock -= LCYCS; - IRQCount++; - if (IRQCount & 0x100) { - X6502_IRQBegin(FCEU_IQEXT); - IRQCount = IRQLatch; - } - } - } - } -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper253_Init(CartInfo *info) { - info->Power = M253Power; - info->Close = M253Close; - MapIRQHook = M253IRQ; - GameStateRestore = StateRestore; - - CHRRAMSIZE = 2048; - CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); - SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); - AddExState(CHRRAM, CHRRAMSIZE, 0, "CRAM"); - - WRAMSIZE = 8192; - WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; - } - - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/mapper272.c b/src/boards/mapper272.c deleted file mode 100644 index 00b4464b4..000000000 --- a/src/boards/mapper272.c +++ /dev/null @@ -1,230 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2022 - * - * 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 272 is used for a bootleg implementation of - * 悪魔城 Special: ぼくDracula君 (Akumajō Special: Boku Dracula-kun). - * - * as implemented from - * https://forums.nesdev.org/viewtopic.php?f=9&t=15302&start=60#p205862 - * - */ - -#include "mapinc.h" - -static uint8 prg[2]; -static uint8 chr[8]; -static uint8 mirr; -static uint8 pal_mirr; -static uint8 last_pa13; -static uint8 IRQCount; -static uint8 IRQa; - -static SFORMAT StateRegs[] = -{ - { prg, 2, "PRG" }, - { chr, 8, "CHR" }, - { &mirr, 1, "MIRR" }, - { &last_pa13, 1, "PA13" }, - { &IRQCount, 1, "CNTR" }, - { &pal_mirr, 1, "PALM" }, - { &IRQa, 1, "CCLK" }, - { 0 } -}; - -/* shifts bit from position `bit` into position `pos` of expression `exp` */ -#define shi(exp, bit, pos) ((((exp) & (1 << (bit))) >> (bit)) << (pos)) - -static uint32 vrc_addr_mix(uint32 A) { - /* this game wires A0 to VRC_A0 and A1 to VRC_A1 */ - return (A & 0xf000) | shi(A, 0, 0) | shi(A, 1, 1); -} - -static void Sync(void) { - uint8 i; - setprg8(0x8000, prg[0]); - setprg8(0xa000, prg[1]); - setprg16(0xc000, -1); - for (i = 0; i < 8; ++i) - setchr1(0x400 * i, chr[i]); - switch (pal_mirr) { - case 2: - setmirror(MI_0); - break; - case 3: - setmirror(MI_1); - break; - default: - switch (mirr) { - case 0: - setmirror(MI_V); - break; - case 1: - setmirror(MI_H); - break; - } - } -} - -static DECLFW(M272Write) { - /* writes to VRC chip */ - switch (vrc_addr_mix(A)) { - case 0x8000: - case 0x8001: - case 0x8002: - case 0x8003: - prg[0] = V; - break; - case 0x9000: - case 0x9001: - case 0x9002: - case 0x9003: - mirr = V & 1; - break; - case 0xA000: - case 0xA001: - case 0xA002: - case 0xA003: - prg[1] = V; - break; - case 0xb000: - chr[0] = (chr[0] & 0xF0) | (V & 0xF); - break; - case 0xb001: - chr[0] = (chr[0] & 0xF) | ((V & 0xF) << 4); - break; - case 0xb002: - chr[1] = (chr[1] & 0xF0) | (V & 0xF); - break; - case 0xb003: - chr[1] = (chr[1] & 0xF) | ((V & 0xF) << 4); - break; - case 0xc000: - chr[2] = (chr[2] & 0xF0) | (V & 0xF); - break; - case 0xc001: - chr[2] = (chr[2] & 0xF) | ((V & 0xF) << 4); - break; - case 0xc002: - chr[3] = (chr[3] & 0xF0) | (V & 0xF); - break; - case 0xc003: - chr[3] = (chr[3] & 0xF) | ((V & 0xF) << 4); - break; - case 0xd000: - chr[4] = (chr[4] & 0xF0) | (V & 0xF); - break; - case 0xd001: - chr[4] = (chr[4] & 0xF) | ((V & 0xF) << 4); - break; - case 0xd002: - chr[5] = (chr[5] & 0xF0) | (V & 0xF); - break; - case 0xd003: - chr[5] = (chr[5] & 0xF) | ((V & 0xF) << 4); - break; - case 0xe000: - chr[6] = (chr[6] & 0xF0) | (V & 0xF); - break; - case 0xe001: - chr[6] = (chr[6] & 0xF) | ((V & 0xF) << 4); - break; - case 0xe002: - chr[7] = (chr[7] & 0xF0) | (V & 0xF); - break; - case 0xe003: - chr[7] = (chr[7] & 0xF) | ((V & 0xF) << 4); - break; - - default: - break; - } - - /* writes to PAL chip */ - switch (A & 0xC00C) { - case 0x8004: - pal_mirr = V & 3; - break; - case 0x800c: - X6502_IRQBegin(FCEU_IQEXT); - break; - case 0xc004: - X6502_IRQEnd(FCEU_IQEXT); - break; - case 0xc008: - IRQa = 1; - break; - case 0xc00c: - IRQa = 0; - IRQCount = 0; - X6502_IRQEnd(FCEU_IQEXT); - break; - } - - Sync(); -} - -static void M272Power(void) { - prg[0] = prg[1] = 0; - chr[0] = chr[1] = chr[2] = chr[3] = 0; - chr[4] = chr[5] = chr[6] = chr[7] = 0; - mirr = pal_mirr = 0; - last_pa13 = 0; - IRQCount = 0; - IRQa = 0; - Sync(); - SetWriteHandler(0x8000, 0xFFFF, M272Write); - SetReadHandler(0x8000, 0xFFFF, CartBR); -} - -static void M272Hook(uint32 A) { - uint8 pa13 = (A >> 13) & 1; - if ((last_pa13 == 1) && (pa13 == 0)) { - if (IRQa) { - IRQCount++; - if (IRQCount == 84) { - IRQCount = 0; - X6502_IRQBegin(FCEU_IQEXT); - } - } - } - last_pa13 = pa13; -} - -static void M272Reset(void) { - prg[0] = prg[1] = 0; - chr[0] = chr[1] = chr[2] = chr[3] = 0; - chr[4] = chr[5] = chr[6] = chr[7] = 0; - mirr = pal_mirr = 0; - last_pa13 = 0; - IRQCount = 0; - IRQa = 0; - Sync(); -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper272_Init(CartInfo *info) { - info->Power = M272Power; - info->Reset = M272Reset; - PPU_hook = M272Hook; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/mapper351.c b/src/boards/mapper351.c deleted file mode 100644 index d94513ae1..000000000 --- a/src/boards/mapper351.c +++ /dev/null @@ -1,420 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2022 NewRisingSun - * - * 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" - -static uint8 reg[4], dip; -static uint8 MMC1_reg[4], MMC1_shift, MMC1_count; -static uint8 MMC3_reg[8], MMC3_index, MMC3_mirroring, MMC3_wram, MMC3_reload, MMC3_count, MMC3_irq; -static uint8 VRC4_prg[2]; -static uint8 VRC4_mirroring; -static uint8 VRC4_misc; -static uint16 VRC4_chr[8]; -static uint8 VRCIRQ_latch; -static uint8 VRCIRQ_mode; -static uint8 VRCIRQ_count; -static int16 VRCIRQ_cycles; -static uint8 *CHRRAM = NULL; -static uint8 *PRGCHR = NULL; - -static SFORMAT stateRegs[] = { - { reg, 4, "REGS" }, - { &dip, 1, "DIPS" }, - { MMC1_reg, 4, "MMC1" }, - { &MMC1_shift, 1, "M1SH" }, - { &MMC1_count, 1, "M1CN" }, - { MMC3_reg, 8, "MMC3" }, - { &MMC3_index, 1, "M3IX" }, - { &MMC3_mirroring, 1, "M3MI" }, - { &MMC3_wram, 1, "M3WR" }, - { &MMC3_reload, 1, "M3RL" }, - { &MMC3_count, 1, "M3CN" }, - { &MMC3_irq, 1, "M3IQ" }, - { VRC4_prg, 2, "V4PR" }, - { &VRC4_mirroring, 1, "V4MI" }, - { &VRC4_misc, 1, "V4MS" }, - { VRC4_chr, 16, "V4CH" }, - { &VRCIRQ_latch, 1, "VILA" }, - { &VRCIRQ_mode, 1, "VIMO" }, - { &VRCIRQ_count, 1, "VICO" }, - { &VRCIRQ_cycles, 2, "VICY" }, - { 0 } -}; - -static void SyncPRG(void) { - uint8 prgAND = (reg[2] & 0x04) ? 0x0F : 0x1F; - uint8 prgOR = reg[1] >> 1; - uint8 chip = ((reg[2] & 0x01) && CHRRAM) ? 0x10 : 0x00; - if (reg[2] & 0x10) { /* NROM mode */ - if (reg[2] & 0x08) { /* NROM-64 */ - setprg8r(chip, 0x8000, prgOR); - setprg8r(chip, 0xA000, prgOR); - setprg8r(chip, 0xC000, prgOR); - setprg8r(chip, 0xE000, prgOR); - } else { - if (reg[2] & 0x04) { /* NROM-128 */ - setprg16r(chip, 0x8000, prgOR >> 1); - setprg16r(chip, 0xC000, prgOR >> 1); - } else { /* NROM-256 */ - setprg32r(chip, 0x8000, prgOR >> 2); - } - } - } else { - switch (reg[0] & 0x03) { - case 0: - case 1: /* MMC3 mode */ - setprg8r(chip, 0x8000 ^ ((MMC3_index << 8) & 0x4000), (MMC3_reg[6] & prgAND) | (prgOR & ~prgAND)); - setprg8r(chip, 0xA000, (MMC3_reg[7] & prgAND) | (prgOR & ~prgAND)); - setprg8r(chip, 0xC000 ^ ((MMC3_index << 8) & 0x4000), (0xFE & prgAND) | (prgOR & ~prgAND)); - setprg8r(chip, 0xE000, (0xFF & prgAND) | (prgOR & ~prgAND)); - break; - case 2: /* MMC1 mode */ - prgAND >>= 1; - prgOR >>= 1; - if (MMC1_reg[0] & 0x8) { /* 16 KiB mode */ - if (MMC1_reg[0] & 0x04) { /* OR logic */ - setprg16r(chip, 0x8000, (MMC1_reg[3] & prgAND) | (prgOR & ~prgAND)); - setprg16r(chip, 0xC000, (0xFF & prgAND) | (prgOR & ~prgAND)); - } else { /* AND logic */ - setprg16r(chip, 0x8000, (0x00 & prgAND) | (prgOR & ~prgAND)); - setprg16r(chip, 0xC000, (MMC1_reg[3] & prgAND) | (prgOR & ~prgAND)); - } - } else { - setprg32(0x8000, ((MMC1_reg[3] & prgAND) | (prgOR & ~prgAND)) >> 1); - } - break; - case 3: /* VRC4 mode */ - setprg8r(chip, 0x8000 ^ ((VRC4_misc << 13) & 0x4000), (VRC4_prg[0] & prgAND) | (prgOR & ~prgAND)); - setprg8r(chip, 0xA000, (VRC4_prg[1] & prgAND) | (prgOR & ~prgAND)); - setprg8r(chip, 0xC000 ^ ((VRC4_misc << 13) & 0x4000), (0xFE & prgAND) | (prgOR & ~prgAND)); - setprg8r(chip, 0xE000, (0xFF & prgAND) | (prgOR & ~prgAND)); - break; - } - } -} - -static void SyncCHR(void) { - uint16 chrAND = ((reg[2] & 0x10) && (~reg[2] & 0x20)) ? 0x1F : ((reg[2] & 0x20) ? 0x7F : 0xFF); - uint16 chrOR = reg[0] << 1; - if (reg[2] & 0x01) { /* CHR RAM mode */ - setchr8r(0x10, 0); - } else if (reg[2] & 0x40) { /* CNROM mode */ - setchr8(chrOR >> 3); - } else { - switch (reg[0] & 0x03) { - case 0: - case 1: /* MMC3 mode */ - setchr1(0x0000 ^ (MMC3_index << 5 & 0x1000), ((MMC3_reg[0] & 0xFE) & chrAND) | (chrOR & ~chrAND)); - setchr1(0x0400 ^ (MMC3_index << 5 & 0x1000), ((MMC3_reg[0] | 0x01) & chrAND) | (chrOR & ~chrAND)); - setchr1(0x0800 ^ (MMC3_index << 5 & 0x1000), ((MMC3_reg[1] & 0xFE) & chrAND) | (chrOR & ~chrAND)); - setchr1(0x0C00 ^ (MMC3_index << 5 & 0x1000), ((MMC3_reg[1] | 0x01) & chrAND) | (chrOR & ~chrAND)); - setchr1(0x1000 ^ (MMC3_index << 5 & 0x1000), (MMC3_reg[2] & chrAND) | (chrOR & ~chrAND)); - setchr1(0x1400 ^ (MMC3_index << 5 & 0x1000), (MMC3_reg[3] & chrAND) | (chrOR & ~chrAND)); - setchr1(0x1800 ^ (MMC3_index << 5 & 0x1000), (MMC3_reg[4] & chrAND) | (chrOR & ~chrAND)); - setchr1(0x1C00 ^ (MMC3_index << 5 & 0x1000), (MMC3_reg[5] & chrAND) | (chrOR & ~chrAND)); - break; - case 2: /* MMC1 mode */ - chrAND >>= 2; - chrOR >>= 2; - if (MMC1_reg[0] & 0x10) { /* 4 KiB mode */ - setchr4(0x0000, (MMC1_reg[1] & chrAND) | (chrOR & ~chrAND)); - setchr4(0x1000, (MMC1_reg[2] & chrAND) | (chrOR & ~chrAND)); - } else { /* 8 KiB mode */ - setchr8(((MMC1_reg[1] & chrAND) | (chrOR & ~chrAND)) >> 1); - } - break; - case 3: /* VRC4 mode */ - setchr1(0x0000, (VRC4_chr[0] & chrAND) | (chrOR & ~chrAND)); - setchr1(0x0400, (VRC4_chr[1] & chrAND) | (chrOR & ~chrAND)); - setchr1(0x0800, (VRC4_chr[2] & chrAND) | (chrOR & ~chrAND)); - setchr1(0x0C00, (VRC4_chr[3] & chrAND) | (chrOR & ~chrAND)); - setchr1(0x1000, (VRC4_chr[4] & chrAND) | (chrOR & ~chrAND)); - setchr1(0x1400, (VRC4_chr[5] & chrAND) | (chrOR & ~chrAND)); - setchr1(0x1800, (VRC4_chr[6] & chrAND) | (chrOR & ~chrAND)); - setchr1(0x1C00, (VRC4_chr[7] & chrAND) | (chrOR & ~chrAND)); - break; - } - } -} - -static void SyncMirroring(void) { - if (~reg[0] & 0x02) { /* MMC3 mode */ - setmirror((MMC3_mirroring & 0x01) ^ 1); - } else if (reg[0] & 0x01) { /* VRC4 mode */ - switch (VRC4_mirroring & 0x03) { - case 0: setmirror(MI_V); break; - case 1: setmirror(MI_H); break; - case 2: setmirror(MI_0); break; - case 3: setmirror(MI_1); break; - } - } else { /* MMC1 mode */ - switch (MMC1_reg[0] & 0x03) { - case 2: setmirror(MI_V); break; - case 3: setmirror(MI_H); break; - case 0: setmirror(MI_0); break; - case 1: setmirror(MI_1); break; - } - } -} - -static void Sync(void) { - SyncPRG(); - SyncCHR(); - SyncMirroring(); -} - -static DECLFW(writeMMC3) { - switch (A & 0xE001) { - case 0x8000: - MMC3_index = V; - Sync(); - break; - case 0x8001: - MMC3_reg[MMC3_index & 7] = V; - Sync(); - break; - case 0xA000: - MMC3_mirroring = V; - Sync(); - break; - case 0xA001: - MMC3_wram = V; - Sync(); - break; - case 0xC000: - MMC3_reload = V; - break; - case 0xC001: - MMC3_count = 0; - break; - case 0xE000: - MMC3_irq = 0; - X6502_IRQEnd(FCEU_IQEXT); - break; - case 0xE001: - MMC3_irq = 1; - break; - } -} - -static uint64 lreset; -static DECLFW(writeMMC1) { - if ((timestampbase + timestamp) < (lreset + 2)) { - return; - } - if (V & 0x80) { - MMC1_shift = MMC1_count = 0; - MMC1_reg[0] |= 0x0C; - Sync(); - lreset = timestampbase + timestamp; - return; - } - MMC1_shift |= (V & 1) << MMC1_count++; - if (MMC1_count == 5) { - MMC1_reg[(A >> 13) & 3] = MMC1_shift; - MMC1_count = 0; - MMC1_shift = 0; - Sync(); - } -} - -static DECLFW(writeVRC4) { - uint8 index; - A = (A & 0xF000) | (A & 0x800 ? ((A & 8 ? 1 : 0) | (A & 4 ? 2 : 0)) : ((A & 4 ? 1 : 0) | (A & 8 ? 2 : 0))); - switch (A & 0xF000) { - case 0x8000: - case 0xA000: - VRC4_prg[(A >> 13) & 1] = V; - Sync(); - break; - case 0x9000: - if (~A & 2) { - VRC4_mirroring = V; - } else if (~A & 1) { - VRC4_misc = V; - } - Sync(); - break; - case 0xF000: - switch (A & 3) { - case 0: - VRCIRQ_latch = (VRCIRQ_latch & 0xF0) | (V & 0x0F); - break; - case 1: - VRCIRQ_latch = (VRCIRQ_latch & 0x0F) | (V << 4); - break; - case 2: - VRCIRQ_mode = V; - if (VRCIRQ_mode & 0x02) { - VRCIRQ_count = VRCIRQ_latch; - VRCIRQ_cycles = 341; - } - X6502_IRQEnd(FCEU_IQEXT); - break; - case 3: - VRCIRQ_mode = (VRCIRQ_mode & ~0x02) | ((VRCIRQ_mode << 1) & 0x02); - X6502_IRQEnd(FCEU_IQEXT); - break; - } - break; - default: - index = ((A - 0xB000) >> 11) | ((A >> 1) & 1); - if (A & 1) { - VRC4_chr[index] = (VRC4_chr[index] & 0x0F) | (V << 4); - } else { - VRC4_chr[index] = (VRC4_chr[index] & ~0x0F) | (V & 0x0F); - } - Sync(); - break; - } -} - -static void FP_FASTAPASS(1) M351CPUHook(int a) { - if ((reg[0] & 3) == 3) { - while (a--) { /* VRC4 mode */ - if (VRCIRQ_mode & 0x02 && (VRCIRQ_mode & 0x04 || (VRCIRQ_cycles -= 3) <= 0)) { - if (~VRCIRQ_mode & 0x04) { - VRCIRQ_cycles += 341; - } - if (!++VRCIRQ_count) { - VRCIRQ_count = VRCIRQ_latch; - X6502_IRQBegin(FCEU_IQEXT); - } - } - } - } -} - -static void M351HBHook(void) { - if (~reg[0] & 2) { /* MMC3 mode */ - if (MMC3_count == 0) { - MMC3_count = MMC3_reload; - } else { - MMC3_count--; - } - if (!MMC3_count && MMC3_irq) { - X6502_IRQBegin(FCEU_IQEXT); - } - } -} - -static DECLFR(M351ReadDIP) { - return dip; -} - -static DECLFW(M351WriteMirroring) { - /* FDS mirroring */ - MMC3_mirroring = (V >> 3) & 1; - Sync(); -} - -static DECLFW(M351WriteReg) { - reg[A & 3] = V; - Sync(); -} - -static DECLFW(M351Write) { - switch (reg[0] & 3) { - case 0: - case 1: - writeMMC3(A, V); - break; - case 2: - writeMMC1(A, V); - break; - case 3: - writeVRC4(A, V); - break; - } -} - -static void M351Power(void) { - int i; - for (i = 0; i < 4; i++) - reg[i] = 0; - for (i = 0; i < 4; i++) - MMC1_reg[i] = 0; - for (i = 0; i < 8; i++) - MMC3_reg[i] = 0; - for (i = 0; i < 2; i++) - VRC4_prg[i] = 0; - for (i = 0; i < 8; i++) - VRC4_chr[i] = 0; - MMC1_shift = MMC1_count = lreset = 0; - MMC1_reg[0] = 0x0C; - MMC3_index = MMC3_mirroring = MMC3_wram = MMC3_reload = MMC3_count = MMC3_irq = 0; - VRC4_mirroring = VRC4_misc = VRCIRQ_latch = VRCIRQ_mode = VRCIRQ_count = VRCIRQ_cycles = 0; - dip = 0; - Sync(); - - SetReadHandler(0x6000, 0xFFFF, CartBR); - SetReadHandler(0x5000, 0x5FFF, M351ReadDIP); - SetWriteHandler(0x4025, 0x4025, M351WriteMirroring); - SetWriteHandler(0x5000, 0x5FFF, M351WriteReg); - SetWriteHandler(0x8000, 0xFFFF, M351Write); -} - -static void M531Reset(void) { - lreset = 0; - reg[0] = reg[1] = reg[2] = reg[3] = 0; - dip++; - Sync(); -} - -static void M351Close(void) { - if (CHRRAM) { - FCEU_gfree(CHRRAM); - } - if (PRGCHR) { - FCEU_gfree(PRGCHR); - } - CHRRAM = NULL; - PRGCHR = NULL; -} - -static void StateRestore(int version) { - Sync(); - lreset = 0; -} - -void Mapper351_Init(CartInfo *info) { - int CHRRAMSIZE = info->CHRRamSize + info->CHRRamSaveSize; - - info->Reset = M531Reset; - info->Power = M351Power; - info->Close = M351Close; - MapIRQHook = M351CPUHook; - GameHBIRQHook = M351HBHook; - GameStateRestore = StateRestore; - AddExState(stateRegs, ~0, 0, 0); - - if (!UNIFchrrama && CHRRAMSIZE) { - CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); - SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); - AddExState(CHRRAM, CHRRAMSIZE, 0, "CRAM"); - - /* This crazy thing can map CHR-ROM into CPU address space. Allocate a combined PRG+CHR address space and treat - * it a second "chip". */ - PRGCHR = (uint8 *)FCEU_gmalloc(PRGsize[0] + CHRsize[0]); - memcpy(PRGCHR, PRGptr[0], PRGsize[0]); - memcpy(PRGCHR + PRGsize[0], CHRptr[0], CHRsize[0]); - SetupCartPRGMapping(0x10, PRGCHR, PRGsize[0] + CHRsize[0], 0); - } -} diff --git a/src/boards/mapper353.c b/src/boards/mapper353.c deleted file mode 100644 index aa06eb478..000000000 --- a/src/boards/mapper353.c +++ /dev/null @@ -1,134 +0,0 @@ -/* FCEUmm - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2020 - * - * 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 353 is used for the 92 Super Mario Family multicart, - * consisting of an MMC3 clone ASIC together with a PAL. - * The PCB code is 81-03-05-C. - */ - -#include "../fds_apu.h" -#include "mapinc.h" -#include "mmc3.h" - -static uint8 *CHRRAM = NULL; -static uint32 CHRRAMSIZE; -static uint8 PPUCHRBus; -static uint8 MIR[8]; - -static void M353PPU(uint32 A) { - A &= 0x1FFF; - A >>= 10; - PPUCHRBus = A; - if (mmc3.expregs[0] == 0) - setmirror(MI_0 + MIR[A]); -} - -static void M353PW(uint32 A, uint8 V) { - uint8 bank = V; - - if (mmc3.expregs[0] == 2) { - bank &= 0x0F; - bank |= (mmc3.regs[0] & 0x80) ? 0x10 : 0x00; - bank |= (mmc3.expregs[0] << 5); - } else { - if ((mmc3.expregs[0] == 3) && !(mmc3.regs[0] & 0x80)) { - switch (A & 0xF000) { - case 0xC000: - case 0xE000: - bank = mmc3.regs[6 + ((A >> 13) & 1)] | 0x70; - break; - } - } else { - bank &= 0x1F; - bank |= (mmc3.expregs[0] << 5); - } - } - - setprg8(A, bank); -} - -static void M353CW(uint32 A, uint8 V) { - if ((mmc3.expregs[0] == 2) && (mmc3.regs[0] & 0x80)) - setchr8r(0x10, 0); - else - setchr1(A, (V & 0x7F) | ((mmc3.expregs[0]) << 7)); - - MIR[A >> 10] = V >> 7; - if ((mmc3.expregs[0] == 0) && (PPUCHRBus == (A >> 10))) - setmirror(MI_0 + (V >> 7)); -} - -static void M353MW(uint8 V) { - if (mmc3.expregs[0] != 0) { - mmc3.mirroring = V; - setmirror((V & 1) ^ 1); - } -} - -static DECLFW(M353Write) { - if (A & 0x80) { - mmc3.expregs[0] = (A >> 13) & 0x03; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } else { - if (A < 0xC000) { - MMC3_CMDWrite(A, V); - FixMMC3PRG(mmc3.cmd); - } else - MMC3_IRQWrite(A, V); - } -} - -static void M353Power(void) { - FDSSoundPower(); - mmc3.expregs[0] = 0; - GenMMC3Power(); - SetWriteHandler(0x8000, 0xFFFF, M353Write); -} - -static void M353Reset(void) { - mmc3.expregs[0] = 0; - MMC3RegReset(); - FDSSoundReset(); -} - -static void M353Close(void) { - GenMMC3Close(); - if (CHRRAM) - FCEU_gfree(CHRRAM); - CHRRAM = NULL; -} - -void Mapper353_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 128, 8, info->battery); - mmc3.cwrap = M353CW; - mmc3.pwrap = M353PW; - mmc3.mwrap = M353MW; - PPU_hook = M353PPU; - info->Power = M353Power; - info->Close = M353Close; - info->Reset = M353Reset; - AddExState(mmc3.expregs, 1, 0, "EXPR"); - - CHRRAMSIZE = 8192; - CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); - SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); - AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); -} diff --git a/src/boards/mapper359.c b/src/boards/mapper359.c deleted file mode 100644 index a52beb162..000000000 --- a/src/boards/mapper359.c +++ /dev/null @@ -1,212 +0,0 @@ -/* FCEUmm - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2020 - * - * 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 359 - BMC-SB-5013 - * NES 2.0 Mapper 540 - UNL-82112C - */ - -#include "mapinc.h" -#include "../fds_apu.h" - -static uint32 mapperNum; -static uint8 preg[4]; -static uint8 creg[8]; -static uint8 exRegs[4]; -static uint8 IRQReload; -static uint8 IRQa; -static uint8 irqPA12; -static uint8 IRQAutoEnable; -static uint8 IRQLatch; -static uint8 IRQCount; -static int16 IRQCount16; - -static SFORMAT StateRegs[] = { - { preg, 4, "PREG" }, - { creg, 8, "CREG" }, - { exRegs, 4, "EXPR" }, - { &IRQReload, 1, "IRQL" }, - { &IRQa, 1, "IRQa" }, - { &irqPA12, 1, "IRQp" }, - { &IRQAutoEnable, 1, "IRQe" }, - { &IRQLatch, 1, "IRQl" }, - { &IRQCount, 1, "IRQ8" }, - { &IRQCount16, 2, "IRQC" }, - { 0 } -}; - -static void Sync(void) { - uint8 prgMask = 0x3F; - uint8 prgOuterBank = (exRegs[0] & 0x38) << 1; - - switch (exRegs[1] & 3) { - case 0: - prgMask = 0x3F; - break; - case 1: - prgMask = 0x1F; - break; - case 2: - prgMask = 0x2F; - break; - case 3: - prgMask = 0x0F; - break; - } - - setprg8(0x6000, (preg[3] & prgMask) | prgOuterBank); - setprg8(0x8000, (preg[0] & prgMask) | prgOuterBank); - setprg8(0xA000, (preg[1] & prgMask) | prgOuterBank); - setprg8(0xC000, (preg[2] & prgMask) | prgOuterBank); - setprg8(0xE000, ( ~0 & prgMask) | prgOuterBank); - - if (!UNIFchrrama) { - switch (mapperNum) { - case 359: { - uint8 i; - uint8 chrMask = (exRegs[1] & 0x40) ? 0xFF : 0x7F; - uint16 chrOuterBank = (exRegs[3] << 7); - - for (i = 0; i < 8; i++) - setchr1(i << 10, (creg[i] & chrMask) | chrOuterBank); - } break; - case 540: - setchr2(0x0000, creg[0]); - setchr2(0x0800, creg[1]); - setchr2(0x1000, creg[6]); - setchr2(0x1800, creg[7]); - break; - } - } else - setchr8(0); - - if (exRegs[2] & 2) - setmirror(MI_0 + (exRegs[2] & 1)); - else - setmirror((exRegs[2] & 1) ^ 1); -} - -static DECLFW(M359WriteIRQ) { - switch (A & 0xF003) { - case 0xC000: - if (IRQAutoEnable) - IRQa = 0; - IRQCount16 &= 0xFF00; - IRQCount16 |= V; - IRQReload = 1; - X6502_IRQEnd(FCEU_IQEXT); - break; - case 0xC001: - if (IRQAutoEnable) - IRQa = 1; - IRQCount16 &= 0x00FF; - IRQCount16 |= (V << 8); - IRQLatch = V; - X6502_IRQEnd(FCEU_IQEXT); - break; - case 0xC002: - IRQa = (V & 1); - irqPA12 = (V & 2) >> 1; - IRQAutoEnable = (V & 4) >> 2; - X6502_IRQEnd(FCEU_IQEXT); - break; - case 0xC003: - IRQa = (V & 1); - X6502_IRQEnd(FCEU_IQEXT); - break; - } -} - -static DECLFW(M359WritePRG) { - uint8 i = A & 3; - preg[i] = V; - Sync(); -} - -static DECLFW(M359WriteCHR) { - uint8 i = ((A >> 10) & 4) | (A & 3); - creg[i] = V; - Sync(); -} - -static DECLFW(M359WriteEx) { - uint8 i = A & 3; - exRegs[i] = V; - Sync(); -} - -static void M359Power(void) { - FDSSoundPower(); - Sync(); - SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0x8FFF, M359WritePRG); - SetWriteHandler(0x9000, 0x9FFF, M359WriteEx); - SetWriteHandler(0xA000, 0xBFFF, M359WriteCHR); - SetWriteHandler(0xC000, 0xCFFF, M359WriteIRQ); -} - -static void M359Reset(void) { - FDSSoundReset(); - Sync(); -} - -static void FP_FASTAPASS(1) M359CPUHook(int a) { - if (!irqPA12) { - if (IRQa && IRQCount16) { - IRQCount16 -= a; - if (IRQCount16 <= 0) - X6502_IRQBegin(FCEU_IQEXT); - } - } -} - -static void M359IRQHook(void) { - if (irqPA12) { - if (!IRQCount || IRQReload) { - IRQCount = IRQLatch; - IRQReload = 0; - } else - IRQCount--; - if (!IRQCount && IRQa) - X6502_IRQBegin(FCEU_IQEXT); - } -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper359_Init(CartInfo *info) { - mapperNum = 359; - info->Power = M359Power; - info->Reset = M359Reset; - MapIRQHook = M359CPUHook; - GameHBIRQHook = M359IRQHook; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} - -void Mapper540_Init(CartInfo *info) { - mapperNum = 540; - info->Power = M359Power; - MapIRQHook = M359CPUHook; - GameHBIRQHook = M359IRQHook; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/mapper369.c b/src/boards/mapper369.c deleted file mode 100644 index cbef4eaaa..000000000 --- a/src/boards/mapper369.c +++ /dev/null @@ -1,194 +0,0 @@ -/* FCEUmm - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2020 - * - * 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 369 (BMC-N49C-300) - Super Mario Bros. Party multicart */ - -#include "mapinc.h" -#include "mmc3.h" - -static uint8 mode; -static uint8 mmc3_count, mmc3_latch, mmc3_enabled, mmc3_reload; -static uint8 smb2_reg; -static uint8 smb2j_enabled; -static uint16 smb2j_count; - -static SFORMAT StateRegs[] = { - { &mode, 1, "MODE" }, - { &mmc3_reload, 1, "IRQR" }, - { &mmc3_count, 1, "IRQC" }, - { &mmc3_latch, 1, "IRQL" }, - { &mmc3_enabled, 1, "IRQA" }, - { &smb2_reg, 1, "MBRG" }, - { &smb2j_enabled, 1, "MIRQ" }, - { &smb2j_count, 2, "MIQC" }, - { 0 } -}; - -static void SyncPRG(uint32 A, uint8 V) { - switch (mode) { - case 0x00: - case 0x01: /* NROM */ - setprg32(0x8000, mode & 0x01); - break; - case 0x13: /* Mapper 40 */ - setprg8r(0, 0x6000, 0x0E); - setprg8(0x8000, 0x0C); - setprg8(0xa000, 0x0D); - setprg8(0xc000, smb2_reg | 0x08); - setprg8(0xe000, 0x0F); - break; - case 0x37: /* MMC3 128 PRG */ - setprg8r(0x10, 0x6000, 0); - setprg8(A, (V & 0x0F) | 0x10); - break; - case 0xFF: /* MMC3 256 PRG */ - setprg8r(0x10, 0x6000, 0); - setprg8(A, (V & 0x1F) | 0x20); - break; - } -} - -static void SyncCHR(uint32 A, uint8 V) { - switch (mode) { - case 0x00: - case 0x01: /* NROM */ - case 0x13: /* Mapper 40 */ - setchr8(mode & 0x03); - break; - case 0x37: /* MMC3 128 CHR */ - setchr1(A, (V & 0x7F) | 0x80); - break; - case 0xFF: /* MMC3 256 CHR */ - setchr1(A, (V & 0xFF) | 0x100); - break; - } -} - -static DECLFW(M369WriteLo) { - if ((A & 0xC100) == 0x4100) { - mode = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } -} - -static DECLFW(M369Write) { - if (mode == 0x13) { - switch (A & 0xE000) { - case 0x8000: - smb2j_enabled = 0; - smb2j_count = 0; - X6502_IRQEnd(FCEU_IQEXT); - break; - case 0xA000: - smb2j_enabled = 1; - break; - case 0xE000: - smb2_reg = V & 7; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - break; - } - } else { - switch (A & 0xE001) { - case 0x8000: - case 0x8001: - case 0xA000: - case 0xA001: - MMC3_CMDWrite(A, V); - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - break; - case 0xC000: - mmc3_latch = V; - break; - case 0xC001: - mmc3_reload = 1; - break; - case 0xE000: - X6502_IRQEnd(FCEU_IQEXT); - mmc3_enabled = 0; - break; - case 0xE001: - mmc3_enabled = 1; - break; - } - } -} - -static void FP_FASTAPASS(1) SMB2JIRQHook(int a) { - if (mode != 0x13) - return; - - if (smb2j_enabled) { - if (smb2j_count < 4096) - smb2j_count += a; - else { - smb2j_enabled = 0; - X6502_IRQBegin(FCEU_IQEXT); - } - } -} - -static void MMC3IRQHook(void) { - int32 count = mmc3_count; - - if (mode == 0x13) - return; - - if (!count || mmc3_reload) { - mmc3_count = mmc3_latch; - mmc3_reload = 0; - } else - mmc3_count--; - if (count && !mmc3_count && mmc3_enabled) - X6502_IRQBegin(FCEU_IQEXT); -} - -static void M369Reset(void) { - mode = 0; - smb2_reg = 0; - smb2j_enabled = 0; - smb2j_count = 0; - mmc3_count = mmc3_latch = mmc3_enabled = 0; - MMC3RegReset(); -} - -static void M369Power(void) { - mode = 0; - smb2_reg = 0; - smb2j_enabled = 0; - smb2j_count = 0; - mmc3_count = mmc3_latch = mmc3_enabled = 0; - GenMMC3Power(); - SetWriteHandler(0x4100, 0x4FFF, M369WriteLo); - SetWriteHandler(0x8000, 0xFFFF, M369Write); -} - -void Mapper369_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 384, 8, info->battery); - mmc3.pwrap = SyncPRG; - mmc3.cwrap = SyncCHR; - info->Power = M369Power; - info->Reset = M369Reset; - MapIRQHook = SMB2JIRQHook; - GameHBIRQHook = MMC3IRQHook; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/mapper370.c b/src/boards/mapper370.c deleted file mode 100644 index 490fdf3c3..000000000 --- a/src/boards/mapper370.c +++ /dev/null @@ -1,93 +0,0 @@ -/* FCEUmm - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2020 - * - * 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 370 - F600 - * Golden Mario Party II - Around the World (6-in-1 multicart) - */ - -#include "mapinc.h" -#include "mmc3.h" - -static uint8 PPUCHRBus; -static uint8 mirr[8]; - -static void FP_FASTAPASS(1) M370PPU(uint32 A) { - if ((mmc3.expregs[0] & 7) == 1) { - A &= 0x1FFF; - A >>= 10; - PPUCHRBus = A; - setmirror(MI_0 + mirr[A]); - } -} - -static void M370CW(uint32 A, uint8 V) { - uint8 mask = (mmc3.expregs[0] & 4) ? 0xFF : 0x7F; - mirr[A >> 10] = V >> 7; - setchr1(A, (V & mask) | ((mmc3.expregs[0] & 7) << 7)); - if (((mmc3.expregs[0] & 7) == 1) && (PPUCHRBus == (A >> 10))) - setmirror(MI_0 + (V >> 7)); -} - -static void M370PW(uint32 A, uint8 V) { - uint8 mask = mmc3.expregs[0] & 0x20 ? 0x0F : 0x1F; - setprg8(A, (V & mask) | ((mmc3.expregs[0] & 0x38) << 1)); -} - -static void M370MW(uint8 V) { - mmc3.mirroring = V; - if ((mmc3.expregs[0] & 7) != 1) - setmirror((V & 1) ^ 1); -} - -static DECLFR(M370Read) { - return (mmc3.expregs[1] << 7); -} - -static DECLFW(M370Write) { - mmc3.expregs[0] = (A & 0xFF); - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); -} - -static void M370Reset(void) { - mmc3.expregs[0] = 0; - mmc3.expregs[1] ^= 1; - FCEU_printf("solderpad=%02x\n", mmc3.expregs[1]); - MMC3RegReset(); -} - -static void M370Power(void) { - mmc3.expregs[0] = 0; - mmc3.expregs[1] = 1; /* start off with the 6-in-1 menu */ - GenMMC3Power(); - SetReadHandler(0x5000, 0x5FFF, M370Read); - SetWriteHandler(0x5000, 0x5FFF, M370Write); -} - -void Mapper370_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 8, 0); - mmc3.cwrap = M370CW; - mmc3.pwrap = M370PW; - mmc3.mwrap = M370MW; - PPU_hook = M370PPU; - info->Power = M370Power; - info->Reset = M370Reset; - AddExState(mmc3.expregs, 2, 0, "EXPR"); -} diff --git a/src/boards/mapper376.c b/src/boards/mapper376.c deleted file mode 100644 index c531c6938..000000000 --- a/src/boards/mapper376.c +++ /dev/null @@ -1,68 +0,0 @@ -/* 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 - */ - -#include "mapinc.h" -#include "mmc3.h" - -static void Mapper376CW(uint32 A, uint8 V) { - uint32 base = (mmc3.expregs[0] & 0x40 ? 0x080 : 0x000) | (mmc3.expregs[1] & 0x01 ? 0x100 : 0x000); - setchr1(A, base | (V & 0x7F)); -} - -static void Mapper376PW(uint32 A, uint8 V) { - uint32 base = (mmc3.expregs[0] & 0x07) | (mmc3.expregs[0] & 0x40 ? 0x08 : 0x00) | (mmc3.expregs[1] & 0x01 ? 0x10 : 0x00); - if (mmc3.expregs[0] & 0x80) { - if (mmc3.expregs[0] & 0x20) { - if (A == 0x8000) - setprg32(A, base >> 1); - } else { - if (A == 0x8000 || A == 0xC000) - setprg16(A, base); - } - } else { - setprg8(A, ((base << 1) & ~0x0F) | (V & 0x0F)); - } -} - -static DECLFW(Mapper376Write) { - mmc3.expregs[A & 1] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); -} - -static void Mapper376Reset(void) { - mmc3.expregs[0] = 0; - mmc3.expregs[1] = 0; - MMC3RegReset(); -} - -static void Mapper376Power(void) { - GenMMC3Power(); - SetWriteHandler(0x7000, 0x7FFF, Mapper376Write); -} - -void Mapper376_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 256, 0, 0); - mmc3.pwrap = Mapper376PW; - mmc3.cwrap = Mapper376CW; - info->Power = Mapper376Power; - info->Reset = Mapper376Reset; - AddExState(mmc3.expregs, 2, 0, "EXPR"); -} diff --git a/src/boards/mapper383.c b/src/boards/mapper383.c deleted file mode 100644 index d9a48b7fc..000000000 --- a/src/boards/mapper383.c +++ /dev/null @@ -1,103 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * 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 - */ - -/* 晶太 YY840708C PCB - Solely used for the "1995 Soccer 6-in-1 足球小将專輯 (JY-014)" multicart. - MMC3+PAL16L8 combination, resulting in a bizarre mapper that switches banks in part upon *reads*. -*/ - -#include "mapinc.h" -#include "mmc3.h" - -#define A15 mmc3.expregs[0] -#define A16 mmc3.expregs[1] -#define A17A18 mmc3.expregs[2] - -static void M383PRGWrap(uint32 A, uint8 V) { - switch (A17A18) { - case 0x00: - /* "Setting 0 provides a round-about means of dividing the first 128 KiB bank into two 32 KiB and one 64 KiB - * bank." */ - setprg8(A, (V & (A16 ? 0x07 : 0x03)) | (A16 ? 0x00 : A15) | A16 | A17A18); - break; - case 0x30: - /* "Setting 3 provides 128 KiB MMC3 banking with the CPU A14 line fed to the MMC3 clone reversed. - This is used for the game Tecmo Cup: Soccer Game (renamed "Tecmo Cup Soccer"), - originally an MMC1 game with the fixed bank at $8000-$BFFF and the switchable bank at $C000-$FFFF, - a configuration that could not be reproduced with an MMC3 alone." */ - setprg8(A ^ 0x4000, (V & 0x0F) | A17A18); - - /* "It is also used for the menu, - which in part executes from PRG-ROM mapped to the CPU $6000-$7FFF address range on the MMC3 clone's fixed - banks alone, as no MMC3 PRG bank register is written to before JMPing to this address range." */ - if (A == 0xE000) - setprg8(A ^ 0x8000, (V & 0x0B) | A17A18); - break; - default: - /* "Settings 1 and 2 provide normal 128 KiB MMC3 banking." */ - setprg8(A, (V & 0x0F) | A17A18); - break; - } -} - -static void M383CHRWrap(uint32 A, uint8 V) { - setchr1(A, (V & 0x7F) | (A17A18 << 3)); -} - -static DECLFR(M383Read) { - if (A17A18 == 0x00) { /* "PAL PRG A16 is updated with the content of the corresponding MMC3 PRG bank bit by reading from the - respective address range, which in turn will then be applied across the entire ROM address range." */ - A16 = mmc3.regs[0x06 | ((A >> 13) & 0x01)] & 0x08; - FixMMC3PRG(mmc3.cmd); - } - return CartBR(A); -} - -static DECLFW(M383Write) { - if (A & 0x0100) { - A15 = (A >> 11) & 0x04; - A17A18 = A & 0x30; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } - if (A & 0x4000) - MMC3_IRQWrite(A, V); - else - MMC3_CMDWrite(A, V); -} - -static void M383Reset(void) { - mmc3.expregs[0] = 0; - mmc3.expregs[1] = 0; - mmc3.expregs[2] = 0; - MMC3RegReset(); -} - -static void M383Power(void) { - GenMMC3Power(); - SetReadHandler(0x8000, 0xBFFF, M383Read); - SetWriteHandler(0x8000, 0xFFFF, M383Write); -} - -void Mapper383_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 128, 8, 0); - mmc3.pwrap = M383PRGWrap; - mmc3.cwrap = M383CHRWrap; - info->Power = M383Power; - info->Reset = M383Reset; - AddExState(mmc3.expregs, 3, 0, "EXPR"); -} diff --git a/src/boards/mapper391.c b/src/boards/mapper391.c deleted file mode 100644 index ac0a0d1b1..000000000 --- a/src/boards/mapper391.c +++ /dev/null @@ -1,81 +0,0 @@ -/* FCEUmm - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2022 - * - * 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 - */ - -/* BS-110 PCB, previously called NC7000M due to a mix-up. */ - -#include "mapinc.h" -#include "mmc3.h" - -static void Mapper391_PRGWrap(uint32 A, uint8 V) { - uint8 mask = mmc3.expregs[0] & 0x08 ? 0x0F : 0x1F; - uint8 base = mmc3.expregs[0] << 4 & 0x30; - if (mmc3.expregs[0] & 0x20) { /* GNROM-like PRG banking */ - if (mmc3.expregs[0] & 0x04) { /* NROM-256 */ - setprg8(0x8000, (base & ~mask) | ((mmc3.regs[6] & ~3) & mask) | 0); - setprg8(0xA000, (base & ~mask) | ((mmc3.regs[7] & ~3) & mask) | 1); - setprg8(0xC000, (base & ~mask) | ((mmc3.regs[6] & ~3) & mask) | 2); - setprg8(0xE000, (base & ~mask) | ((mmc3.regs[7] & ~3) & mask) | 3); - } else { /* NROM-128 */ - setprg8(0x8000, (base & ~mask) | ((mmc3.regs[6] & ~1) & mask) | 0); - setprg8(0xA000, (base & ~mask) | ((mmc3.regs[7] & ~1) & mask) | 1); - setprg8(0xC000, (base & ~mask) | ((mmc3.regs[6] & ~1) & mask) | 0); - setprg8(0xE000, (base & ~mask) | ((mmc3.regs[7] & ~1) & mask) | 1); - } - } else { - setprg8(A, (base & ~mask) | (V & mask)); - } -} - -static void Mapper391_CHRWrap(uint32 A, uint8 V) { - uint16 mask = (mmc3.expregs[0] & 0x40) ? 0x7F : 0xFF; - uint16 base = ((mmc3.expregs[0] << 3) & 0x80) | ((mmc3.expregs[1] << 8) & 0x100); - setchr1(A, (base & ~mask) | (V & mask)); -} - -static DECLFW(Mapper391_Write) { - if (MMC3CanWriteToWRAM()) { - if (~mmc3.expregs[0] & 0x80) { - mmc3.expregs[0] = V; - mmc3.expregs[1] = ((A >> 8) & 0xFF); - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } - } -} - -static void Mapper391_Reset(void) { - mmc3.expregs[0] = mmc3.expregs[1] = 0; - MMC3RegReset(); -} - -static void Mapper391_Power(void) { - mmc3.expregs[0] = mmc3.expregs[1] = 0; - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, Mapper391_Write); -} - -void Mapper391_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 0, 0); - mmc3.cwrap = Mapper391_CHRWrap; - mmc3.pwrap = Mapper391_PRGWrap; - info->Power = Mapper391_Power; - info->Reset = Mapper391_Reset; - AddExState(mmc3.expregs, 2, 0, "EXPR"); -} diff --git a/src/boards/mapper401.c b/src/boards/mapper401.c deleted file mode 100644 index e91f4225d..000000000 --- a/src/boards/mapper401.c +++ /dev/null @@ -1,96 +0,0 @@ -/* FCEUmm - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2020 - * - * 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 401 (reference from NewRisingSun) - * Super 19-in-1 (VIP19) (crc 0x2F497313) - * - */ - -#include "mapinc.h" -#include "mmc3.h" - -static uint8 dipswitch = 0; - -static void M401CW(uint32 A, uint8 V) { - uint32 mask = (0xFF >> (~mmc3.expregs[2] & 0xF)); - uint32 bank = (mmc3.expregs[0] | ((mmc3.expregs[2] << 4) & 0xF00)); - setchr1(A, (V & mask) | bank); -} - -static void M401PW(uint32 A, uint8 V) { - if ((dipswitch & 1) && (mmc3.expregs[1] & 0x80)) { - /* openbus */ - } else { - uint32 mask = (~mmc3.expregs[3] & 0x1F); - uint32 bank = (mmc3.expregs[1] & 0x1F) | (mmc3.expregs[2] & 0x80) | - ((dipswitch & 2) ? (mmc3.expregs[2] & 0x20) : ((mmc3.expregs[1] >> 1) & 0x20)) | - ((dipswitch & 4) ? (mmc3.expregs[2] & 0x40) : ((mmc3.expregs[1] << 1) & 0x40)); - setprg8(A, (V & mask) | bank); - } -} - -static DECLFR(M401Read) { - if ((dipswitch & 1) && (mmc3.expregs[1] & 0x80)) - return X.DB; - return CartBR(A); -} - -static DECLFW(M401Write) { - /* FCEU_printf("Wr A:%04x V:%02x index:%d\n", A, V, mmc3.expregs[4]); */ - if (!(mmc3.expregs[3] & 0x40)) { - mmc3.expregs[mmc3.expregs[4]] = V; - mmc3.expregs[4] = (mmc3.expregs[4] + 1) & 3; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } - CartBW(A, V); -} - -static void M401Reset(void) { - dipswitch = (dipswitch + 1) & 7; - FCEU_printf("dipswitch = %d\n", dipswitch); - mmc3.expregs[0] = 0x00; - mmc3.expregs[1] = 0x00; - mmc3.expregs[2] = 0x0F; - mmc3.expregs[3] = 0x00; - mmc3.expregs[4] = 0x00; - MMC3RegReset(); -} - -static void M401Power(void) { - dipswitch = 7; - mmc3.expregs[0] = 0x00; - mmc3.expregs[1] = 0x00; - mmc3.expregs[2] = 0x0F; - mmc3.expregs[3] = 0x00; - mmc3.expregs[4] = 0x00; - GenMMC3Power(); - SetReadHandler(0x8000, 0xFFFF, M401Read); - SetWriteHandler(0x6000, 0x7FFF, M401Write); -} - -void Mapper401_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 8, 0); - mmc3.cwrap = M401CW; - mmc3.pwrap = M401PW; - info->Power = M401Power; - info->Reset = M401Reset; - AddExState(mmc3.expregs, 5, 0, "EXPR"); - AddExState(&dipswitch, 1, 0, "DPSW"); -} diff --git a/src/boards/mapper416.c b/src/boards/mapper416.c deleted file mode 100644 index 8a5f6a676..000000000 --- a/src/boards/mapper416.c +++ /dev/null @@ -1,98 +0,0 @@ -/* FCEUmm - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2022 - * - * 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 "latch.h" - -static uint8 smb2j_reg; -static uint8 IRQa; -static uint16 IRQCount; - -static void Sync(void) { - if (latch.data & 8) { - uint8 prg = ((latch.data >> 5) & 1) | ((latch.data >> 6) & 2) | ((latch.data >> 1) & 4); - switch ((latch.data >> 6) & 3) { - case 0: - setprg8(0x8000, prg << 1); - setprg8(0xA000, prg << 1); - setprg8(0xC000, prg << 1); - setprg8(0xE000, prg << 1); - break; - case 1: - setprg16(0x8000, prg); - setprg16(0xC000, prg); - break; - case 2: - case 3: - setprg32(0x8000, prg >> 1); - break; - } - } else { - setprg8(0x8000, 0x0); - setprg8(0xA000, 0x1); - setprg8(0xC000, smb2j_reg); - setprg8(0xE000, 0x3); - } - setprg8(0x6000, 0x7); - setchr8((latch.data >> 1) & 3); - setmirror(((latch.data >> 2) & 1) ^ 1); -} - -static DECLFW(M416Write4) { - switch (A & 0xD160) { - case 0x4120: - IRQa = V & 1; - if (!IRQa) - IRQCount = 0; - X6502_IRQEnd(FCEU_IQEXT); - break; - case 0x4020: - smb2j_reg = ((V & 1) << 2) | ((V & 6) >> 1); - Sync(); - break; - } -} - -static void M416Power(void) { - smb2j_reg = IRQa = IRQCount = 0; - LatchPower(); - SetReadHandler(0x6000, 0x7FFF, CartBR); - SetWriteHandler(0x4020, 0x4FFF, M416Write4); -} - -static void FP_FASTAPASS(1) M416IRQHook(int a) { - if (IRQa) { - if (IRQCount < 4096) - IRQCount += a; - else { - IRQa = 0; - X6502_IRQBegin(FCEU_IQEXT); - } - } -} - -void Mapper416_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); - info->Power = M416Power; - MapIRQHook = M416IRQHook; - AddExState(&smb2j_reg, 1, 0, "SMBJ"); - AddExState(&IRQa, 1, 0, "IRQa"); - AddExState(&IRQCount, 2, 0, "IRQC"); -} diff --git a/src/boards/mapper432.c b/src/boards/mapper432.c deleted file mode 100644 index cc79c35dc..000000000 --- a/src/boards/mapper432.c +++ /dev/null @@ -1,91 +0,0 @@ -/* FCEUmm - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2020 - * - * 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" - -static void M432CW(uint32 A, uint8 V) { - int chrAND = (mmc3.expregs[1] & 0x04) ? 0x7F : 0xFF; - int chrOR = ((mmc3.expregs[1] << 7) & 0x080) | ((mmc3.expregs[1] << 5) & 0x100) | ((mmc3.expregs[1] << 4) & 0x200); - setchr1(A, (V & chrAND) | (chrOR & ~chrAND)); -} - -static void M432PW(uint32 A, uint8 V) { - int prgAND = (mmc3.expregs[1] & 0x02) ? 0x0F : 0x1F; - int prgOR = ((mmc3.expregs[1] << 4) & 0x10) | ((mmc3.expregs[1] << 1) & 0x60); - if (mmc3.expregs[1] & 0x40) { /* NROM */ - if (mmc3.expregs[1] & 0x80) { /* NROM-256 */ - setprg8(0x8000, ((mmc3.regs[6] & ~2) & prgAND) | (prgOR & ~prgAND)); - setprg8(0xA000, ((mmc3.regs[7] & ~2) & prgAND) | (prgOR & ~prgAND)); - setprg8(0xC000, ((mmc3.regs[6] | 2) & prgAND) | (prgOR & ~prgAND)); - setprg8(0xE000, ((mmc3.regs[7] | 2) & prgAND) | (prgOR & ~prgAND)); - } else { /* NROM-128 */ - setprg8(0x8000, (mmc3.regs[6] & prgAND) | (prgOR & ~prgAND)); - setprg8(0xA000, (mmc3.regs[7] & prgAND) | (prgOR & ~prgAND)); - setprg8(0xC000, (mmc3.regs[6] & prgAND) | (prgOR & ~prgAND)); - setprg8(0xE000, (mmc3.regs[7] & prgAND) | (prgOR & ~prgAND)); - } - } else { /* MMC3 */ - setprg8(A, (V & prgAND) | (prgOR & ~prgAND)); - } -} - -static DECLFR(M432Read) { - if (mmc3.expregs[0] & 1 || ((mmc3.expregs[1] & 0x20) && (ROM_size < 64))) - return mmc3.expregs[2]; - return CartBR(A); -} - -static DECLFW(M432Write) { - if (MMC3CanWriteToWRAM()) { - mmc3.expregs[A & 1] = V; - if (~A & 1 && ~V & 1 && ROM_size < 64) - mmc3.expregs[1] &= ~0x20; /* Writing 0 to register 0 clears register 1's DIP bit */ - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } -} - -static void M432Reset(void) { - mmc3.expregs[0] = 0; - mmc3.expregs[1] = 0; - mmc3.expregs[2]++; - MMC3RegReset(); -} - -static void M432Power(void) { - mmc3.expregs[0] = 0; - mmc3.expregs[1] = 0; - mmc3.expregs[2] = 0; - GenMMC3Power(); - SetReadHandler(0x8000, 0xFFFF, M432Read); - SetWriteHandler(0x6000, 0x7FFF, M432Write); -} - -void Mapper432_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 0, 0); - mmc3.cwrap = M432CW; - mmc3.pwrap = M432PW; - info->Power = M432Power; - info->Reset = M432Reset; - AddExState(mmc3.expregs, 3, 0, "EXPR"); -} diff --git a/src/boards/mapper443.c b/src/boards/mapper443.c deleted file mode 100644 index f3f8f24c4..000000000 --- a/src/boards/mapper443.c +++ /dev/null @@ -1,79 +0,0 @@ -/* FCEUmm - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2022 - * - * 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 - */ - -/* NC3000M PCB */ - -#include "mapinc.h" -#include "mmc3.h" - -static uint8 dip; - -static void Mapper443_PRGWrap(uint32 A, uint8 V) { - int prgAND = 0x0F; - int prgOR = ((mmc3.expregs[0] << 4) & 0x20) | (mmc3.expregs[0] & 0x10); - if (mmc3.expregs[0] & 0x04) { - if (~A & 0x4000) { - setprg8(A, ((((~mmc3.expregs[0] & 0x08) ? ~2 : ~0) & V) & prgAND) | (prgOR & ~prgAND)); - setprg8(A | 0x4000, ((~mmc3.expregs[0] & 0x08) ? 2 : 0) | (V & prgAND) | (prgOR & ~prgAND)); - } - } else - setprg8(A, (V & prgAND) | (prgOR & ~prgAND)); -} - -static void Mapper443_CHRWrap(uint32 A, uint8 V) { - int chrAND = 0xFF; - int chrOR = mmc3.expregs[0] << 8; - setchr1(A, (V & chrAND) | (chrOR & ~chrAND)); -} - -static DECLFR(Mapper443_Read) { - return (((mmc3.expregs[0] & 0x0C) == 0x08) ? dip : CartBR(A)); -} - -static DECLFW(Mapper443_Write) { - mmc3.expregs[0] = A & 0xFF; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); -} - -static void Mapper443_Reset(void) { - dip++; - dip &= 15; - mmc3.expregs[0] = 0; - MMC3RegReset(); -} - -static void Mapper443_Power(void) { - dip = 0; - mmc3.expregs[0] = 0; - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, Mapper443_Write); - SetReadHandler(0x8000, 0xFFFF, Mapper443_Read); -} - -void Mapper443_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 0, 0); - mmc3.cwrap = Mapper443_CHRWrap; - mmc3.pwrap = Mapper443_PRGWrap; - info->Power = Mapper443_Power; - info->Reset = Mapper443_Reset; - AddExState(mmc3.expregs, 1, 0, "EXPR"); - AddExState(&dip, 1, 0, "DIPS"); -} diff --git a/src/boards/mapper444.c b/src/boards/mapper444.c deleted file mode 100644 index 901e5b625..000000000 --- a/src/boards/mapper444.c +++ /dev/null @@ -1,83 +0,0 @@ -/* FCEUmm - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2020 - * - * 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 - */ - -/* NC7000M PCB, with incorrect UNIF MAPR BS-110 due to a mix-up. Submapper bits 0 and 1. denote the setting of two - * solder pads that configure CHR banking. */ -/* NC8000M PCB, indicated by submapper bit 2. */ - -#include "mapinc.h" -#include "mmc3.h" - -static uint8 pads; -static uint8 dip; - -static void Mapper444_PRGWrap(uint32 A, uint8 V) { - int prgAND = ((pads & 4) && (mmc3.expregs[0] & 0x02)) ? 0x1F : 0x0F; - int prgOR = mmc3.expregs[0] << 4; - if (mmc3.expregs[0] & 0x04) { - if (~A & 0x4000) { - setprg8(A, ((((~mmc3.expregs[0] & 0x08) ? ~2 : ~0) & V) & prgAND) | (prgOR & ~prgAND)); - setprg8(A | 0x4000, ((~mmc3.expregs[0] & 0x08) ? 2 : 0) | (V & prgAND) | (prgOR & ~prgAND)); - } - } else - setprg8(A, (V & prgAND) | (prgOR & ~prgAND)); -} - -static void Mapper444_CHRWrap(uint32 A, uint8 V) { - int chrAND = (pads & 1) ? 0xFF : 0x7F; - int chrOR = ((mmc3.expregs[0] << 7) & ((pads & 1) ? 0x00 : 0x80)) | ((mmc3.expregs[0] << ((pads & 2) ? 4 : 7)) & 0x100); - setchr1(A, (V & chrAND) | (chrOR & ~chrAND)); -} - -static DECLFR(Mapper444_Read) { - return (mmc3.expregs[0] & 0x0C) == 0x08 ? dip : CartBR(A); -} - -static DECLFW(Mapper444_Write) { - mmc3.expregs[0] = A & 0xFF; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); -} - -static void Mapper444_Reset(void) { - dip++; - dip &= 3; - mmc3.expregs[0] = 0; - MMC3RegReset(); -} - -static void Mapper444_Power(void) { - dip = 0; - mmc3.expregs[0] = 0; - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, Mapper444_Write); - SetReadHandler(0x8000, 0xFFFF, Mapper444_Read); -} - -void Mapper444_Init(CartInfo *info) { - pads = info->submapper; /* UNIF represents submapper 0 */ - GenMMC3_Init(info, 256, 256, 0, 0); - mmc3.cwrap = Mapper444_CHRWrap; - mmc3.pwrap = Mapper444_PRGWrap; - info->Power = Mapper444_Power; - info->Reset = Mapper444_Reset; - AddExState(mmc3.expregs, 1, 0, "EXPR"); - AddExState(&dip, 1, 0, "DIPS"); -} diff --git a/src/boards/mapper450.c b/src/boards/mapper450.c deleted file mode 100644 index 9e5045249..000000000 --- a/src/boards/mapper450.c +++ /dev/null @@ -1,67 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2023 - * - * 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 450 - YY841157C - */ - -#include "mapinc.h" -#include "vrc24.h" - -/* TODO: move this register to VRC2 microwire interface when implemented */ -static uint8 wires; - -static SFORMAT StateRegs[] = { - { &wires, 1, "WIRE" }, - { 0 }, -}; - -static void M450PW(uint32 A, uint8 V) { - setprg8(A, (wires << 4) | (V & 0x0F)); -} - -static void M450CW(uint32 A, uint32 V) { - setchr1(A, (wires << 7) | (V & 0x7F)); -} - -static DECLFW(M450WriteReg) { - wires = V; - FixVRC24PRG(); - FixVRC24CHR(); -} - -static void M450Reset(void) { - wires = 0; - FixVRC24PRG(); - FixVRC24CHR(); -} - -static void M450Power(void) { - wires = 0; - GenVRC24Power(); - SetWriteHandler(0x6000, 0x6FFF, M450WriteReg); -} - -void Mapper450_Init(CartInfo *info) { - GenVRC24_Init(info, VRC2b, 0); - info->Power = M450Power; - vrc24.pwrap = M450PW; - vrc24.cwrap = M450CW; - AddExState(StateRegs, ~0, 0, 0); -} diff --git a/src/boards/mapper467.c b/src/boards/mapper467.c deleted file mode 100644 index bb967adfe..000000000 --- a/src/boards/mapper467.c +++ /dev/null @@ -1,74 +0,0 @@ -/* FCEUmm - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2022 NewRisingSun - * - * 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" - -static void Mapper467_PRGWrap(uint32 A, uint8 V) { - if (mmc3.expregs[0] & 0x20) { - int prgAND = (mmc3.expregs[0] & 0x40) ? 0x0F : 0x03; - int prgOR = ((mmc3.expregs[0] << 1) & 0x3C) | 0x40; - setprg8(A, (V & prgAND) | (prgOR & ~prgAND)); - } else if (~A & 0x2000) - setprg16(A, mmc3.expregs[0] & 0x1F); -} - -static void Mapper467_CHRWrap(uint32 A, uint8 V) { - if (~A & 0x0800) { - A = (A & ~0x400) | ((A << 1) & 0x800); - if (mmc3.expregs[0] & 0x40) - setchr2(A, V | 0x100); - else - setchr2(A, (V & ~3) | ((A >> 11) & 3)); - } -} - -static DECLFW(Mapper467_WriteExtra) { - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - setmirror(mmc3.expregs[0] & 0x80 ? MI_H : MI_V); -} - -static DECLFW(Mapper467_WriteMMC3) { - if (~A & 1) - V &= 0x3F; - MMC3_CMDWrite(A, V); -} - -static void Mapper467_Reset(void) { - mmc3.expregs[0] = 0; - MMC3RegReset(); -} - -static void Mapper467_Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); - SetWriteHandler(0x8000, 0x8FFF, Mapper467_WriteMMC3); - SetWriteHandler(0x9000, 0x9FFF, Mapper467_WriteExtra); -} - -void Mapper467_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 0, 0); - mmc3.cwrap = Mapper467_CHRWrap; - mmc3.pwrap = Mapper467_PRGWrap; - info->Power = Mapper467_Power; - info->Reset = Mapper467_Reset; - AddExState(mmc3.expregs, 1, 0, "EXPR"); -} diff --git a/src/boards/mapper528.c b/src/boards/mapper528.c deleted file mode 100644 index 0d078fc49..000000000 --- a/src/boards/mapper528.c +++ /dev/null @@ -1,127 +0,0 @@ -/* FCEUmm - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2023 - * - * 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 528 - * UNIF BMC-831128C - */ - -#include "mapinc.h" -#include "vrcirq.h" - -static uint8 preg[4], creg[8], mirr; -static uint8 gamesel; -static uint8 *WRAM; -static uint32 WRAMSIZE; - -static SFORMAT StateRegs[] = -{ - { preg, 4, "PREG" }, - { creg, 8, "CREG" }, - { &mirr, 1, "MIRR" }, - { &gamesel, 1, "GSEL" }, - { 0 } -}; - -static void Sync(void) { - uint8 mask = (gamesel << 4) | 0x0F; - if (preg[3] == 1) { - setprg8r(0x10, 0x6000, 0); - } else { - setprg8(0x6000, (preg[3] & mask) + gamesel); - } - setprg8(0x8000, (preg[0] & mask) + (gamesel << 4)); - setprg8(0xA000, (preg[1] & mask) + (gamesel << 4)); - setprg8(0xC000, ( ~1 & mask) + (gamesel << 4)); - setprg8(0xE000, ( ~0 & mask) + (gamesel << 4)); - setchr1(0x0000, creg[0] + (gamesel << 8)); - setchr1(0x0400, creg[1] + (gamesel << 8)); - setchr1(0x0800, creg[2] + (gamesel << 8)); - setchr1(0x0C00, creg[3] + (gamesel << 8)); - setchr1(0x1000, creg[4] + (gamesel << 8)); - setchr1(0x1400, creg[5] + (gamesel << 8)); - setchr1(0x1800, creg[6] + (gamesel << 8)); - setchr1(0x1C00, creg[7] + (gamesel << 8)); - switch (mirr & 3) { - case 0: setmirror(MI_V); break; - case 1: setmirror(MI_H); break; - case 2: setmirror(MI_0); break; - case 3: setmirror(MI_1); break; - } -} - -static DECLFW(M528Write1) { - switch (A & 0x0F) { - case 0x0: creg[0] = V; break; - case 0x1: creg[1] = V; break; - case 0x2: creg[2] = V; break; - case 0x3: creg[3] = V; break; - case 0x4: creg[4] = V; break; - case 0x5: creg[5] = V; break; - case 0x6: creg[6] = V; break; - case 0x7: creg[7] = V; break; - case 0x8: preg[3] = V; break; - case 0x9: preg[0] = V; break; - case 0xA: preg[1] = V; break; - case 0xB: break; - case 0xC: mirr = V & 3; break; - case 0xD: VRCIRQ_Control(V); break; - case 0xE: VRCIRQ_Acknowledge(); break; - case 0xF: VRCIRQ_Latch(V); break; - } - gamesel = (A & 0x4000) >> 14; - Sync(); -} - -static void M528Power(void) { - int i; - gamesel = 0; - preg[0] = 0; - preg[1] = 1; - preg[2] = 0; - preg[3] = 0; - for (i = 0; i < 8; i++) { - creg[i] = i; - } - Sync(); - - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0xA000, 0xAFFF, M528Write1); - SetWriteHandler(0xC000, 0xCFFF, M528Write1); - - SetReadHandler(0x6000, 0x7FFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper528_Init(CartInfo *info) { - info->Power = M528Power; - GameStateRestore = StateRestore; - VRCIRQ_Init(); - AddExState(&StateRegs, ~0, 0, 0); - - WRAMSIZE = 8192; - WRAM = (uint8*) FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); -} diff --git a/src/boards/mapper539.c b/src/boards/mapper539.c deleted file mode 100644 index a2ef5f5a5..000000000 --- a/src/boards/mapper539.c +++ /dev/null @@ -1,106 +0,0 @@ -/* FCEUmm - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2020 - * - * 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 - Kid Icarus (パルテナの鏡) (Parthena) */ - -#include "mapinc.h" -#include "../fds_apu.h" - -static uint8 preg; -static uint8 mirr; -static uint8 WRAM[8192]; - -static SFORMAT StateRegs[] = -{ - { &preg, 1, "PREG" }, - { &mirr, 1, "MIRR" }, - { 0 } -}; - -static uint32 GetWRAMAddress(uint32 A) { - return ((A & 0x1FFF) | - ((A < 0xC000) ? 0x1000 : 0x0000) | - ((A < 0x8000) ? 0x0800 : 0x000)); -} - -static void Sync(void) { - setprg8(0x6000, 13); - setprg8(0x8000, 12); - setprg8(0xA000, preg); - setprg8(0xC000, 14); - setprg8(0xE000, 15); - setchr8(0); - setmirror(((mirr & 8) >> 3) ^ 1); -} - -static DECLFR(M539Read) { - switch (A >> 8) { - case 0x60: case 0x62: case 0x64: case 0x65: case 0x82: case 0xC0: case 0xC1: case 0xC2: - case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: case 0xC8: case 0xC9: case 0xCA: - case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: case 0xD0: case 0xD1: case 0xDF: - return WRAM[GetWRAMAddress(A)]; - default: - return CartBR(A); - } -} - -static DECLFW(M539Write) { - switch (A >> 8) { - case 0x60: case 0x62: case 0x64: case 0x65: case 0x82: case 0xC0: case 0xC1: case 0xC2: - case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: case 0xC8: case 0xC9: case 0xCA: - case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: case 0xD0: case 0xD1: case 0xDF: - WRAM[GetWRAMAddress(A)] = V; - break; - default: - switch (A & 0xF000) { - case 0xA000: - preg = V; - Sync(); - break; - case 0xF000: - if ((A & 0x25) == 0x25) { - mirr = V; - Sync(); - } - break; - } - break; - } -} - -static void M539Power(void) { - FDSSoundPower(); - preg = 0; - mirr = 0; - Sync(); - SetReadHandler(0x6000, 0xFFFF, M539Read); - SetWriteHandler(0x6000, 0xFFFF, M539Write); -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper539_Init(CartInfo *info) { - info->Power = M539Power; - GameStateRestore = StateRestore; - AddExState(WRAM, 8192, 0, "WRAM"); - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/mapper556.c b/src/boards/mapper556.c deleted file mode 100644 index 8781fe987..000000000 --- a/src/boards/mapper556.c +++ /dev/null @@ -1,330 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2023 - * - * 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 556 - * Used for the for the 超强小新2+瑪莉家族 7-in-1 (JY-215) multicart. - */ - -#include "mapinc.h" - -static uint8 reg[5]; -static uint8 mmc3Reg[8]; -static uint8 mmc3Cmd; -static uint8 mmc3Mirr; -static uint8 mmc3Wram; -static uint8 mmc3IRQLatch; -static uint8 mmc3IRQCount; -static uint8 mmc3IRQa; -static uint8 mmc3IRQReload; -static uint8 vrc4Prg[2]; -static uint8 vrc4Mirr; -static uint8 vrc4Misc; -static uint16 vrc4Chr[8]; -static uint8 vrc4IRQLatch; -static uint8 vrc4IRQa; -static uint8 vrc4IRQCount; -static int16 vrc4IRQCycles; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE = 0; - -static SFORMAT StateRegs[] = { - { reg, 5, "REGS" }, - { mmc3Reg, 8, "MMC3" }, - { &mmc3Cmd, 1, "M3IX" }, - { &mmc3Mirr, 1, "M3MI" }, - { &mmc3Wram, 1, "M3WR" }, - { &mmc3IRQLatch, 1, "M3RL" }, - { &mmc3IRQCount, 1, "M3CN" }, - { &mmc3IRQa, 1, "M3IQ" }, - { &mmc3IRQReload, 1, "M3IR" }, - { vrc4Prg, 2, "V4PR" }, - { &vrc4Mirr, 1, "V4MI" }, - { &vrc4Misc, 1, "V4MS" }, - { vrc4Chr, 16, "V4CH" }, - { &vrc4IRQLatch, 1, "VILA" }, - { &vrc4IRQa, 1, "VIMO" }, - { &vrc4IRQCount, 1, "VICO" }, - { &vrc4IRQCycles, 2, "VICY" }, - { 0 }, -}; - -static void Sync(void) { - uint32 prgmask = ~reg[3] & 0x3F; - uint32 prgbase = ((reg[3] & 0x40) << 2) | reg[1]; - uint32 chrmask = 0xFF >> (~reg[2] & 0x0F); - uint32 chrbase = ((reg[3] & 0x40) << 6) | ((reg[2] & 0xF0) << 4) | reg[0]; - uint32 cbase = 0; /* prg/chr bank flip flag */ - - if (~reg[2] & 0x80) { - /* MMC3 */ - cbase = (mmc3Cmd << 8) & 0x4000; - setprg8(0x8000 ^ cbase, (prgbase & ~prgmask) | (mmc3Reg[6] & prgmask)); - setprg8(0xA000, (prgbase & ~prgmask) | (mmc3Reg[7] & prgmask)); - setprg8(0xC000 ^ cbase, (prgbase & ~prgmask) | (0xFE & prgmask)); - setprg8(0xE000, (prgbase & ~prgmask) | (0xFF & prgmask)); - - cbase = (mmc3Cmd << 5) & 0x1000; - setchr1(0x0000 ^ cbase, (chrbase & ~chrmask) | ((mmc3Reg[0] & 0xFE) & chrmask)); - setchr1(0x0400 ^ cbase, (chrbase & ~chrmask) | ((mmc3Reg[0] | 0x01) & chrmask)); - setchr1(0x0800 ^ cbase, (chrbase & ~chrmask) | ((mmc3Reg[1] & 0xFE) & chrmask)); - setchr1(0x0C00 ^ cbase, (chrbase & ~chrmask) | ((mmc3Reg[1] | 0x01) & chrmask)); - setchr1(0x1000 ^ cbase, (chrbase & ~chrmask) | (mmc3Reg[2] & chrmask)); - setchr1(0x1400 ^ cbase, (chrbase & ~chrmask) | (mmc3Reg[3] & chrmask)); - setchr1(0x1800 ^ cbase, (chrbase & ~chrmask) | (mmc3Reg[4] & chrmask)); - setchr1(0x1C00 ^ cbase, (chrbase & ~chrmask) | (mmc3Reg[5] & chrmask)); - - setmirror((mmc3Mirr & 0x01) ^ 1); - } else { - /* VRC4 mode */ - cbase = (vrc4Misc << 13) & 0x4000; - setprg8(0x8000 ^ cbase, (prgbase & ~prgmask) | (vrc4Prg[0] & prgmask)); - setprg8(0xA000, (prgbase & ~prgmask) | (vrc4Prg[1] & prgmask)); - setprg8(0xC000 ^ cbase, (prgbase & ~prgmask) | (0xFE & prgmask)); - setprg8(0xE000, (prgbase & ~prgmask) | (0xFF & prgmask)); - - setchr1(0x0000, (chrbase & ~chrmask) | (vrc4Chr[0] & chrmask)); - setchr1(0x0400, (chrbase & ~chrmask) | (vrc4Chr[1] & chrmask)); - setchr1(0x0800, (chrbase & ~chrmask) | (vrc4Chr[2] & chrmask)); - setchr1(0x0C00, (chrbase & ~chrmask) | (vrc4Chr[3] & chrmask)); - setchr1(0x1000, (chrbase & ~chrmask) | (vrc4Chr[4] & chrmask)); - setchr1(0x1400, (chrbase & ~chrmask) | (vrc4Chr[5] & chrmask)); - setchr1(0x1800, (chrbase & ~chrmask) | (vrc4Chr[6] & chrmask)); - setchr1(0x1C00, (chrbase & ~chrmask) | (vrc4Chr[7] & chrmask)); - - switch (vrc4Mirr & 0x03) { - case 0: setmirror(MI_V); break; - case 1: setmirror(MI_H); break; - case 2: setmirror(MI_0); break; - case 3: setmirror(MI_1); break; - } - } -} - -static DECLFW(writeMMC3) { - switch (A & 0xE001) { - case 0x8000: - mmc3Cmd = V; - Sync(); - break; - case 0x8001: - mmc3Reg[mmc3Cmd & 7] = V; - Sync(); - break; - case 0xA000: - mmc3Mirr = V; - Sync(); - break; - case 0xA001: - mmc3Wram = V; - Sync(); - break; - case 0xC000: - mmc3IRQLatch = V; - break; - case 0xC001: - mmc3IRQReload = 1; - break; - case 0xE000: - mmc3IRQa = 0; - X6502_IRQEnd(FCEU_IQEXT); - break; - case 0xE001: - mmc3IRQa = 1; - break; - } -} - -static DECLFW(writeVRC4) { - uint8 index; - A = (A & 0xF000) | ((A >> 2) & 3) | (A & 3); - switch (A & 0xF000) { - case 0x8000: - case 0xA000: - vrc4Prg[(A >> 13) & 1] = V; - Sync(); - break; - case 0x9000: - if (~A & 2) { - vrc4Mirr = V; - } else if (~A & 1) { - vrc4Misc = V; - } - Sync(); - break; - case 0xF000: - switch (A & 3) { - case 0: - vrc4IRQLatch = (vrc4IRQLatch & 0xF0) | (V & 0x0F); - break; - case 1: - vrc4IRQLatch = (vrc4IRQLatch & 0x0F) | (V << 4); - break; - case 2: - vrc4IRQa = V; - if (vrc4IRQa & 0x02) { - vrc4IRQCount = vrc4IRQLatch; - vrc4IRQCycles = 341; - } - X6502_IRQEnd(FCEU_IQEXT); - break; - case 3: - vrc4IRQa = (vrc4IRQa & ~0x02) | ((vrc4IRQa << 1) & 0x02); - X6502_IRQEnd(FCEU_IQEXT); - break; - } - break; - default: - index = ((A - 0xB000) >> 11) | ((A >> 1) & 1); - if (A & 1) { - vrc4Chr[index] = (vrc4Chr[index] & 0x0F) | (V << 4); - } else { - vrc4Chr[index] = (vrc4Chr[index] & ~0x0F) | (V & 0x0F); - } - Sync(); - break; - } -} - -static DECLFW(M556WriteReg) { - if (~reg[3] & 0x80) { - reg[reg[4] & 3] = V; - reg[4]++; - Sync(); - } -} - -static DECLFW(M556Write) { - if (~reg[2] & 0x80) { - writeMMC3(A, V); - } else { - writeVRC4(A, V); - } -} - -static void FP_FASTAPASS(1) M556CPUHook(int a) { - int count = a; - - if (~reg[2] & 0x80) { - return; - } - - /* VRC4 IRQ mode */ - while (count--) { - if ((vrc4IRQa & 0x02) && ((vrc4IRQa & 0x04) || ((vrc4IRQCycles -= 3) <= 0))) { - if (~vrc4IRQa & 0x04) { - vrc4IRQCycles += 341; - } - if (!++vrc4IRQCount) { - vrc4IRQCount = vrc4IRQLatch; - X6502_IRQBegin(FCEU_IQEXT); - } - } - } -} - -static void M556HBHook(void) { - int count = mmc3IRQCount; - - if (reg[2] & 0x80) { - return; - } - - /* MMC3 IRQ mode */ - if (!count || mmc3IRQReload) { - mmc3IRQCount = mmc3IRQLatch; - } else { - mmc3IRQCount--; - } - if (count && !mmc3IRQCount && mmc3IRQa) { - X6502_IRQBegin(FCEU_IQEXT); - } - mmc3IRQReload = 0; -} - -static void M556Reset(void) { - int i; - for (i = 0; i < 5; i++) { - reg[i] = 0; - } - reg[2] = 0x0F; - Sync(); -} - -static void M556Power(void) { - int i; - for (i = 0; i < 5; i++) { - reg[i] = 0; - } - for (i = 0; i < 8; i++) { - mmc3Reg[i] = 0; - } - for (i = 0; i < 2; i++) { - vrc4Prg[i] = 0; - } - for (i = 0; i < 8; i++) { - vrc4Chr[i] = 0; - } - mmc3Cmd = mmc3Mirr = mmc3Wram = mmc3IRQLatch = mmc3IRQCount = mmc3IRQa = mmc3IRQReload = 0; - vrc4Mirr = vrc4Misc = vrc4IRQLatch = vrc4IRQa = vrc4IRQCount = vrc4IRQCycles = 0; - reg[2] = 0x0F; - Sync(); - - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x5000, 0x5FFF, M556WriteReg); - SetWriteHandler(0x8000, 0xFFFF, M556Write); - - if (WRAM) { - setprg8r(0x10, 0x6000, 0); - SetReadHandler(0x6000, 0x7FFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - } -} - -static void M556Close(void) { - if (WRAM) { - FCEU_gfree(WRAM); - } - WRAM = NULL; -} - -static void StateRestore(int version) { - Sync(); -} - -void Mapper556_Init(CartInfo *info) { - info->Reset = M556Reset; - info->Power = M556Power; - info->Close = M556Close; - MapIRQHook = M556CPUHook; - GameHBIRQHook = M556HBHook; - GameStateRestore = StateRestore; - AddExState(StateRegs, ~0, 0, 0); - - WRAMSIZE = info->PRGRamSize + info->PRGRamSaveSize; - if (WRAMSIZE) { - WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; - } - } -} diff --git a/src/boards/mmc1.c b/src/boards/mmc1.c deleted file mode 100644 index 288995256..000000000 --- a/src/boards/mmc1.c +++ /dev/null @@ -1,724 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 1998 BERO - * Copyright (C) 2002 Xodnizel - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "mapinc.h" - -static void GenMMC1Power(void); -static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int saveram); - -static uint8 DRegs[4]; -static uint8 Buffer, BufferShift; - -static uint32 WRAMSIZE = 0; - - /* size of non-battery-backed portion of WRAM */ - /* serves as starting offset for actual save ram from total wram size */ - /* returns 0 if entire work ram is battery backed ram */ -static uint32 NONSaveRAMSIZE = 0; - -static void (*MMC1CHRHook4)(uint32 A, uint8 V); -static void (*MMC1PRGHook16)(uint32 A, uint8 V); -/* Used to override default wram behavior */ -/* NULL uses default MMC1 wram. Set after GenMMC1Init() is called to override */ -static void (*MMC1WRAMHook8)(void); - -static uint8 *WRAM = NULL; -static uint8 *CHRRAM = NULL; -static int is155; - -static uint32 MMC1GetCHRBank (uint32 bank) { - if (DRegs[0] & 0x10) /* 4 KiB mode */ - return (DRegs[1 + bank]); - else /* 8 KiB mode */ - return ((DRegs[1] & ~1) | bank); -} - -static uint8 MMC1WRAMEnabled(void) { - return !(DRegs[3] & 0x10); -} - -static DECLFW(MBWRAM) { - if (MMC1WRAMEnabled() || is155) - Page[A >> 11][A] = V; /* WRAM is enabled. */ -} - -static DECLFR(MAWRAM) { - if (!MMC1WRAMEnabled() && !is155) - return X.DB; /* WRAM is disabled */ - return(Page[A >> 11][A]); -} - -static void MMC1CHR(void) { - if (MMC1WRAMHook8) /* Use custom wram hook, currently used for M543 */ - MMC1WRAMHook8(); - else { /* Use default MMC1 wram behavior */ - if (WRAMSIZE > 8192) { - if (WRAMSIZE > 16384) - setprg8r(0x10, 0x6000, (DRegs[1] >> 2) & 3); - else - setprg8r(0x10, 0x6000, (DRegs[1] >> 3) & 1); - } - } - if (MMC1CHRHook4) { - if (DRegs[0] & 0x10) { - MMC1CHRHook4(0x0000, DRegs[1]); - MMC1CHRHook4(0x1000, DRegs[2]); - } else { - MMC1CHRHook4(0x0000, (DRegs[1] & 0xFE)); - MMC1CHRHook4(0x1000, DRegs[1] | 1); - } - } else { - if (DRegs[0] & 0x10) { - setchr4(0x0000, DRegs[1]); - setchr4(0x1000, DRegs[2]); - } else - setchr8(DRegs[1] >> 1); - } -} - -static void MMC1PRG(void) { - uint8 offs = DRegs[1] & 0x10; - if (MMC1PRGHook16) { - switch (DRegs[0] & 0xC) { - case 0xC: - MMC1PRGHook16(0x8000, (DRegs[3] + offs)); - MMC1PRGHook16(0xC000, 0xF + offs); - break; - case 0x8: - MMC1PRGHook16(0xC000, (DRegs[3] + offs)); - MMC1PRGHook16(0x8000, offs); - break; - case 0x0: - case 0x4: - MMC1PRGHook16(0x8000, ((DRegs[3] & ~1) + offs)); - MMC1PRGHook16(0xc000, ((DRegs[3] & ~1) + offs + 1)); - break; - } - } else { - switch (DRegs[0] & 0xC) { - case 0xC: - setprg16(0x8000, (DRegs[3] + offs)); - setprg16(0xC000, 0xF + offs); - break; - case 0x8: - setprg16(0xC000, (DRegs[3] + offs)); - setprg16(0x8000, offs); - break; - case 0x0: - case 0x4: - setprg16(0x8000, ((DRegs[3] & ~1) + offs)); - setprg16(0xc000, ((DRegs[3] & ~1) + offs + 1)); - break; - } - } -} - -static void MMC1MIRROR(void) { - switch (DRegs[0] & 3) { - case 2: setmirror(MI_V); break; - case 3: setmirror(MI_H); break; - case 0: setmirror(MI_0); break; - case 1: setmirror(MI_1); break; - } -} - -static uint64 lreset; -static DECLFW(MMC1_write) { - int n = (A >> 13) - 4; - - /* The MMC1 is busy so ignore the write. */ - /* As of version FCE Ultra 0.81, the timestamp is only - increased before each instruction is executed(in other words - precision isn't that great), but this should still work to - deal with 2 writes in a row from a single RMW instruction. - */ - if ((timestampbase + timestamp) < (lreset + 2)) - return; -/* FCEU_printf("Write %04x:%02x\n",A,V); */ - if (V & 0x80) { - DRegs[0] |= 0xC; - BufferShift = Buffer = 0; - MMC1PRG(); - lreset = timestampbase + timestamp; - return; - } - - Buffer |= (V & 1) << (BufferShift++); - - if (BufferShift == 5) { -/* FCEU_printf("REG[%d]=%02x\n",n,Buffer); */ - DRegs[n] = Buffer; - BufferShift = Buffer = 0; - switch (n) { - case 0: MMC1MIRROR(); MMC1CHR(); MMC1PRG(); break; - case 1: MMC1CHR(); MMC1PRG(); break; - case 2: MMC1CHR(); break; - case 3: MMC1PRG(); break; - } - } -} - -static void MMC1_Restore(int version) { - MMC1MIRROR(); - MMC1CHR(); - MMC1PRG(); - lreset = 0; /* timestamp(base) is not stored in save states. */ -} - -static void MMC1CMReset(void) { - int i; - - for (i = 0; i < 4; i++) - DRegs[i] = 0; - Buffer = BufferShift = 0; - DRegs[0] = 0x1F; - - DRegs[1] = 0; - DRegs[2] = 0; /* Should this be something other than 0? */ - DRegs[3] = 0; - - MMC1MIRROR(); - MMC1CHR(); - MMC1PRG(); -} - -static int DetectMMC1WRAMSize(CartInfo *info, int *saveRAM) { - int workRAM = 8; - if (info->iNES2) { - workRAM = (info->PRGRamSize + info->PRGRamSaveSize) / 1024; - *saveRAM = info->PRGRamSaveSize / 1024; - /* we only support sizes between 8K and 32K */ - if (workRAM > 0 && workRAM < 8) - workRAM = 8; - if (workRAM > 32) - workRAM = 32; - if (*saveRAM > 0 && *saveRAM < 8) - *saveRAM = 8; - if (*saveRAM > 32) - *saveRAM = 32; - /* save ram cannot be bigger than workram */ - if (*saveRAM > workRAM) { - *saveRAM = workRAM; - workRAM = 0; - } - } else if (info->battery) { - *saveRAM = 8; - } - if (workRAM > 8) - FCEU_printf(" >8KB external WRAM present. Use NES 2.0 if you hack the ROM image.\n"); - return workRAM; -} - -static uint32 NWCIRQCount; -static uint8 NWCRec; -static uint32 nwcdip = 0x4; - -static void NWCIRQHook(int a) { - if (!(NWCRec & 0x10)) { - NWCIRQCount += a; - if (NWCIRQCount >= nwcdip) { - NWCIRQCount = 0; - X6502_IRQBegin(FCEU_IQEXT); - } - } -} - -static void NWCCHRHook(uint32 A, uint8 V) { - if ((V & 0x10)) { /* && !(NWCRec&0x10)) */ - NWCIRQCount = 0; - X6502_IRQEnd(FCEU_IQEXT); - } - - NWCRec = V; - if (V & 0x08) - MMC1PRG(); - else - setprg32(0x8000, (V >> 1) & 3); -} - -static void NWCPRGHook(uint32 A, uint8 V) { - if (NWCRec & 0x8) - setprg16(A, 8 | (V & 0x7)); - else - setprg32(0x8000, (NWCRec >> 1) & 3); -} - -static void NWCPower(void) { - GenMMC1Power(); - setchr8r(0, 0); - nwcdip = 0x20000000 | ((uint32)GameInfo->cspecial << 25); -} - -static void NWCReset(void) { - nwcdip = 0x20000000 | ((uint32)GameInfo->cspecial << 25); - MMC1CMReset(); -} - -void Mapper105_Init(CartInfo *info) { - GenMMC1Init(info, 256, 256, 8, 0); - MMC1CHRHook4 = NWCCHRHook; - MMC1PRGHook16 = NWCPRGHook; - MapIRQHook = NWCIRQHook; - info->Power = NWCPower; - info->Reset = NWCReset; -} - -static void GenMMC1Power(void) { - lreset = 0; - SetWriteHandler(0x8000, 0xFFFF, MMC1_write); - SetReadHandler(0x8000, 0xFFFF, CartBR); - - if (WRAMSIZE) { - FCEU_CheatAddRAM(8, 0x6000, WRAM); - - /* clear non-battery-backed portion of WRAM */ - if (NONSaveRAMSIZE) - FCEU_MemoryRand(WRAM, NONSaveRAMSIZE); - - SetReadHandler(0x6000, 0x7FFF, MAWRAM); - SetWriteHandler(0x6000, 0x7FFF, MBWRAM); - setprg8r(0x10, 0x6000, 0); - } - - MMC1CMReset(); -} - -static void GenMMC1Close(void) { - if (CHRRAM) - FCEU_gfree(CHRRAM); - if (WRAM) - FCEU_gfree(WRAM); - CHRRAM = WRAM = NULL; -} - -static void GenMMC1Init(CartInfo *info, int prg, int chr, int wram, int saveram) { - is155 = 0; - - info->Close = GenMMC1Close; - MMC1PRGHook16 = MMC1CHRHook4 = 0; - MMC1WRAMHook8 = 0; - WRAMSIZE = wram * 1024; - NONSaveRAMSIZE = (wram - saveram) * 1024; - PRGmask16[0] &= (prg >> 14) - 1; - CHRmask4[0] &= (chr >> 12) - 1; - CHRmask8[0] &= (chr >> 13) - 1; - - if (WRAMSIZE) { - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - if (saveram) { - info->SaveGame[0] = WRAM + NONSaveRAMSIZE; - info->SaveGameLen[0] = saveram * 1024; - } - } - if (!chr) { - CHRRAM = (uint8*)FCEU_gmalloc(8192); - SetupCartCHRMapping(0, CHRRAM, 8192, 1); - AddExState(CHRRAM, 8192, 0, "CHRR"); - } - AddExState(DRegs, 4, 0, "DREG"); - - info->Power = GenMMC1Power; - GameStateRestore = MMC1_Restore; - AddExState(&lreset, 8, 1, "LRST"); - AddExState(&Buffer, 1, 1, "BFFR"); - AddExState(&BufferShift, 1, 1, "BFRS"); -} - -void Mapper1_Init(CartInfo *info) { - int bs = info->battery ? 8 : 0; - int ws = DetectMMC1WRAMSize(info, &bs); - GenMMC1Init(info, 512, 256, ws, bs); -} - -/* Same as mapper 1, without respect for WRAM enable bit. */ -void Mapper155_Init(CartInfo *info) { - GenMMC1Init(info, 512, 256, 8, info->battery ? 8 : 0); - is155 = 1; -} - -void SAROM_Init(CartInfo *info) { - GenMMC1Init(info, 128, 64, 8, info->battery ? 8 : 0); -} - -void SBROM_Init(CartInfo *info) { - GenMMC1Init(info, 128, 64, 0, 0); -} - -void SCROM_Init(CartInfo *info) { - GenMMC1Init(info, 128, 128, 0, 0); -} - -void SEROM_Init(CartInfo *info) { - GenMMC1Init(info, 32, 64, 0, 0); -} - -void SGROM_Init(CartInfo *info) { - GenMMC1Init(info, 256, 0, 0, 0); -} - -void SKROM_Init(CartInfo *info) { - GenMMC1Init(info, 256, 64, 8, info->battery ? 8 : 0); -} - -void SLROM_Init(CartInfo *info) { - GenMMC1Init(info, 256, 128, 0, 0); -} - -void SL1ROM_Init(CartInfo *info) { - GenMMC1Init(info, 128, 128, 0, 0); -} - -/* Begin unknown - may be wrong - perhaps they use different MMC1s from the - similarly functioning boards? -*/ - -void SL2ROM_Init(CartInfo *info) { - GenMMC1Init(info, 256, 256, 0, 0); -} - -void SFROM_Init(CartInfo *info) { - GenMMC1Init(info, 256, 256, 0, 0); -} - -void SHROM_Init(CartInfo *info) { - GenMMC1Init(info, 256, 256, 0, 0); -} - -/* End unknown */ -/* */ -/* */ - -void SNROM_Init(CartInfo *info) { - GenMMC1Init(info, 256, 0, 8, info->battery ? 8 : 0); -} - -void SOROM_Init(CartInfo *info) { - GenMMC1Init(info, 256, 0, 16, info->battery ? 8 : 0); -} - -/* ----------------------- 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"); -} - -/* ---------------------------- Mapper 374 -------------------------------- */ -/* 1995 Super HiK 4-in-1 - 新系列機器戰警组合卡 (JY-022) - * 1996 Super HiK 4-in-1 - 新系列超級飛狼組合卡 (JY-051) - */ -static uint8 game = 0; -static void M374PRG(uint32 A, uint8 V) { - setprg16(A, (V & 0x07) | (game << 3)); -} - -static void M374CHR(uint32 A, uint8 V) { - setchr4(A, (V & 0x1F) | (game << 5)); -} - -static void M374Reset(void) { - game = (game + 1) & 3; - MMC1CMReset(); -} - -void Mapper374_Init(CartInfo *info) { - GenMMC1Init(info, 128, 128, 0, 0); - MMC1CHRHook4 = M374CHR; - MMC1PRGHook16 = M374PRG; - info->Reset = M374Reset; - AddExState(&game, 1, 0, "GAME"); -} - -/* ---------------------------- Mapper 297 -------------------------------- */ -/* NES 2.0 Mapper 297 - 2-in-1 Uzi Lightgun (MGC-002) */ - -static uint8 mode; -static uint8 latch; - -static void M297PRG(uint32 A, uint8 V) { - setprg16(A, (V & 0x07) | ((mode & 1) << 3)); -} - -static void M297CHR(uint32 A, uint8 V) { - setchr4(A, (V & 0x1F) | ((mode & 1) << 5)); -} - -static void Sync(void) { - if (mode & 1) { - /* MMC1 */ - MMC1PRG(); - MMC1CHR(); - MMC1MIRROR(); - } else { - /* Mapper 70 */ - setprg16(0x8000, ((mode & 2) << 1) | ((latch >> 4) & 3)); - setprg16(0xC000, ((mode & 2) << 1) | 3); - setchr8(latch & 0xF); - setmirror(1); - } -} - -static DECLFW(M297Mode) { - if (A & 0x100) { - mode = V; - Sync(); - } -} - -static DECLFW(M297Latch) { - if (mode & 1) { - MMC1_write(A, V); - } else { - latch = V; - Sync(); - } -} - -static void M297Power(void) { - latch = 0; - mode = 0; - Sync(); - GenMMC1Power(); - SetWriteHandler(0x4120, 0x4120, M297Mode); - SetWriteHandler(0x8000, 0xFFFF, M297Latch); -} - -static void M297StateRestore(int version) { - Sync(); -} - -void Mapper297_Init(CartInfo *info) { - GenMMC1Init(info, 256, 256, 0, 0); - info->Power = M297Power; - MMC1CHRHook4 = M297CHR; - MMC1PRGHook16 = M297PRG; - GameStateRestore = M297StateRestore; - AddExState(&latch, 1, 0, "LATC"); - AddExState(&mode, 1, 0, "MODE"); -} - -/* ---------------------------- Mapper 543 -------------------------------- */ - -/* NES 2.0 Mapper 543 - 1996 無敵智カ卡 5-in-1 (CH-501) */ - -static uint8_t outerBank; -static uint8_t bits; -static uint8_t shift; - -static void M543PRG16(uint32 A, uint8 V) { - setprg16(A, (V & 0x0F) | (outerBank << 4)); -} - -static void M543CHR4(uint32 A, uint8 V) { - setchr4(A, (V & 7)); -} - -static void M543WRAM8(void) { - uint32 wramBank; - if (outerBank & 2) - wramBank = 4 | ((outerBank >> 1) & 2) | (outerBank & 1) ; - else - wramBank = ((outerBank << 1) & 2) | ((MMC1GetCHRBank(0) >> 3) & 1); - setprg8r(0x10, 0x6000, wramBank); -} - -static DECLFW(M543Write) { - bits |= ((V >> 3) & 1) << shift++; - if (shift == 4) { - outerBank = bits; - bits = shift = 0; - MMC1PRG(); - MMC1CHR(); - } -} - -static void M543Reset(void) { - bits = 0; - shift = 0; - outerBank = 0; - MMC1CMReset(); -} - -static void M543Power(void) { - bits = 0; - shift = 0; - outerBank = 0; - GenMMC1Power(); - SetWriteHandler(0x5000, 0x5FFF, M543Write); -} - -void Mapper543_Init(CartInfo *info) { - /* M543 has 32K CHR RAM but only uses 8K, so its safe to set this chr to 0 */ - GenMMC1Init(info, 2048, 32, 64, info->battery ? 64 : 0); - info->Power = M543Power; - info->Reset = M543Reset; - MMC1CHRHook4 = M543CHR4; - MMC1PRGHook16 = M543PRG16; - MMC1WRAMHook8 = M543WRAM8; - AddExState(&bits, 1, 0, "BITS"); - AddExState(&shift, 1, 0, "SHFT"); - AddExState(&outerBank, 1, 0, "BANK"); -} - -/* ---------------------------- Mapper 550 -------------------------------- */ - -/* NES 2.0 Mapper 550 - 7-in-1 1993 Chess Series (JY-015) */ - -static uint8_t latch; -static uint8_t outerBank; - -static void M550PRG16(uint32 A, uint8 V) { - if ((outerBank & 6) == 6) - setprg16(A, (V & 7) | (outerBank << 2)); - else - setprg32(0x8000, (latch >> 4) | (outerBank << 1)); -} - -static void M550CHR4(uint32 A, uint8 V) { - if ((outerBank & 6) == 6) - setchr4(A, (V & 7) | ((outerBank << 2) & 0x18)); - else - setchr8((latch & 3) | ((outerBank << 1) & 0x0C)); -} - -static DECLFW(M550Write7) { - if (!(outerBank & 8)) { - outerBank = A & 15; - MMC1PRG(); - MMC1CHR(); - } -} - -static DECLFW(M550Write8) { - latch = V; - if ((outerBank & 6) == 6) - MMC1_write(A, V); - MMC1PRG(); - MMC1CHR(); -} - -static void M550Reset(void) { - latch = 0; - outerBank = 0; - MMC1CMReset(); -} - -static void M550Power(void) { - latch = 0; - outerBank = 0; - GenMMC1Power(); - SetWriteHandler(0x7000, 0x7FFF, M550Write7); - SetWriteHandler(0x8000, 0xFFFF, M550Write8); -} - -void Mapper550_Init(CartInfo *info) { - GenMMC1Init(info, 512, 128, 8, 0); - info->Power = M550Power; - info->Reset = M550Reset; - MMC1CHRHook4 = M550CHR4; - MMC1PRGHook16 = M550PRG16; - AddExState(&latch, 1, 0, "LATC"); - AddExState(&outerBank, 1, 0, "BANK"); -} - -/* ---------------------------- Mapper 404 -------------------------------- */ - -/* NES 2.0 Mapper 404 - JY012005 - * 1998 Super HiK 8-in-1 (JY-021B)*/ - -static uint8_t outerBank; - -static void M404PRG16(uint32 A, uint8 V) { - uint8 mask = outerBank & 0x40 ? 0x07 : 0x0F; - setprg16(A, (V & mask) | ((outerBank << 3) & ~mask)); -} - -static void M404CHR4(uint32 A, uint8 V) { - setchr4(A, (V & 0x1F) | outerBank << 5); -} - -static DECLFW(M404Write) { - if (!(outerBank & 0x80)) { - outerBank = V; - MMC1PRG(); - MMC1CHR(); - } -} - -static void M404Reset(void) { - outerBank = 0; - MMC1CMReset(); -} - -static void M404Power(void) { - outerBank = 0; - GenMMC1Power(); - SetWriteHandler(0x6000, 0x7FFF, M404Write); -} - -void Mapper404_Init(CartInfo *info) { - GenMMC1Init(info, 256, 256, 0, 0); - info->Power = M404Power; - info->Reset = M404Reset; - MMC1CHRHook4 = M404CHR4; - MMC1PRGHook16 = M404PRG16; - AddExState(&outerBank, 1, 0, "BANK"); -} \ No newline at end of file diff --git a/src/boards/mmc2and4.c b/src/boards/mmc2and4.c deleted file mode 100644 index e5c8f40a9..000000000 --- a/src/boards/mmc2and4.c +++ /dev/null @@ -1,152 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2012 CaH4e3 - * Copyright (C) 2002 Xodnizel - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "mapinc.h" - -static uint8 is10, isPC10; -static uint8 creg[4], latch0, latch1, preg, mirr; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; - -static SFORMAT StateRegs[] = -{ - { creg, 4, "CREG" }, - { &preg, 1, "PREG" }, - { &mirr, 1, "MIRR" }, - { &latch0, 1, "LAT0" }, - { &latch1, 1, "LAT1" }, - { 0 } -}; - -static void Sync(void) { - if (is10) { - setprg16(0x8000, preg); - setprg16(0xC000, ~0); - } else { - setprg8(0x8000, preg); - setprg8(0xA000, ~2); - setprg8(0xC000, ~1); - setprg8(0xE000, ~0); - } - if (is10 || isPC10) - setprg8r(0x10, 0x6000, 0); - setchr4(0x0000, creg[latch0]); - setchr4(0x1000, creg[latch1 + 2]); - setmirror(mirr); -} - -DECLFW(MMC2and4Write) { - switch (A & 0xF000) { - case 0xA000: preg = V & 0xF; Sync(); break; - case 0xB000: creg[0] = V & 0x1F; Sync(); break; - case 0xC000: creg[1] = V & 0x1F; Sync(); break; - case 0xD000: creg[2] = V & 0x1F; Sync(); break; - case 0xE000: creg[3] = V & 0x1F; Sync(); break; - case 0xF000: mirr = (V & 1) ^ 1; Sync(); break; - } -} - -static void FP_FASTAPASS(1) MMC2and4PPUHook(uint32 A) { - uint8 l, h = A >> 8; - if (h >= 0x20 || ((h & 0xF) != 0xF)) - return; - l = A & 0xF0; - if (h < 0x10) { - if (l == 0xD0) { - latch0 = 0; - setchr4(0x0000, creg[0]); - } else if (l == 0xE0) { - latch0 = 1; - setchr4(0x0000, creg[1]); - } - } else { - if (l == 0xD0) { - latch1 = 0; - setchr4(0x1000, creg[2]); - } else if (l == 0xE0) { - latch1 = 1; - setchr4(0x1000, creg[3]); - } - } -} - -static void MMC2and4Power(void) { - preg = 0; - latch0 = latch1 = 1; - Sync(); - if (is10 || isPC10) { - SetReadHandler(0x6000, 0x7FFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); - } - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0xA000, 0xFFFF, MMC2and4Write); -} - -static void StateRestore(int version) { - Sync(); -} - -static void MMC2and4Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -void Mapper9_Init(CartInfo *info) { - is10 = 0; - isPC10 = 0; - info->Power = MMC2and4Power; - info->Close = MMC2and4Close; - PPU_hook = MMC2and4PPUHook; - if (info->battery) { /* Mike Tyson's Punch-Out!! (PC10) supports save ram */ - isPC10 = 1; - WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; - } - } - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} - -void Mapper10_Init(CartInfo *info) { - is10 = 1; - isPC10 = 0; - info->Power = MMC2and4Power; - info->Close = MMC2and4Close; - PPU_hook = MMC2and4PPUHook; - WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; - } - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/mmc3.c b/src/boards/mmc3.c deleted file mode 100644 index 8285fef39..000000000 --- a/src/boards/mmc3.c +++ /dev/null @@ -1,1467 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 1998 BERO - * Copyright (C) 2003 Xodnizel - * Mapper 12 code Copyright (C) 2003 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 - */ - -/* Code for emulating iNES mappers 4,12,44,45,47,49,52,74,114,115,116,118, - 119,165,205,245,249,250,254 -*/ - -#include "mapinc.h" -#include "mmc3.h" - -MMC3 mmc3; - -static uint8 *WRAM; -static uint32 WRAMSIZE; -static uint8 *CHRRAM; -static uint32 CHRRAMSIZE; - -static uint8 IRQCount, IRQLatch, IRQa; -static uint8 IRQReload; -static uint8 submapper; - -static SFORMAT MMC3_StateRegs[] = -{ - { mmc3.regs, 8, "REGS" }, - { &mmc3.cmd, 1, "CMD" }, - { &mmc3.mirroring, 1, "A000" }, - { &mmc3.wram, 1, "A001" }, - { &IRQReload, 1, "IRQR" }, - { &IRQCount, 1, "IRQC" }, - { &IRQLatch, 1, "IRQL" }, - { &IRQa, 1, "IRQA" }, - { 0 } -}; - -static int isRevB = 1; - -void GenMMC3Power(void); -void FixMMC3PRG(int V); -void FixMMC3CHR(int V); - -void GenMMC3_Init(CartInfo *info, int prg, int chr, int wram, int battery); - -/* ---------------------------------------------------------------------- - * ------------------------- Generic MM3 Code --------------------------- - * ---------------------------------------------------------------------- - */ - -int MMC3CanWriteToWRAM() { - return ((mmc3.wram & 0x80) && !(mmc3.wram & 0x40)); -} - -void FixMMC3PRG(int V) { - if (V & 0x40) { - mmc3.pwrap(0xC000, mmc3.regs[6]); - mmc3.pwrap(0x8000, ~1); - } else { - mmc3.pwrap(0x8000, mmc3.regs[6]); - mmc3.pwrap(0xC000, ~1); - } - mmc3.pwrap(0xA000, mmc3.regs[7]); - mmc3.pwrap(0xE000, ~0); -} - -void FixMMC3CHR(int V) { - int cbase = (V & 0x80) << 5; - - mmc3.cwrap((cbase ^ 0x000), mmc3.regs[0] & (~1)); - mmc3.cwrap((cbase ^ 0x400), mmc3.regs[0] | 1); - mmc3.cwrap((cbase ^ 0x800), mmc3.regs[1] & (~1)); - mmc3.cwrap((cbase ^ 0xC00), mmc3.regs[1] | 1); - - mmc3.cwrap(cbase ^ 0x1000, mmc3.regs[2]); - mmc3.cwrap(cbase ^ 0x1400, mmc3.regs[3]); - mmc3.cwrap(cbase ^ 0x1800, mmc3.regs[4]); - mmc3.cwrap(cbase ^ 0x1c00, mmc3.regs[5]); - - if (mmc3.mwrap) - mmc3.mwrap(mmc3.mirroring); -} - -void MMC3RegReset(void) { - IRQCount = IRQLatch = IRQa = mmc3.cmd = 0; - - mmc3.regs[0] = 0; - mmc3.regs[1] = 2; - mmc3.regs[2] = 4; - mmc3.regs[3] = 5; - mmc3.regs[4] = 6; - mmc3.regs[5] = 7; - mmc3.regs[6] = 0; - mmc3.regs[7] = 1; - - FixMMC3PRG(0); - FixMMC3CHR(0); -} - -DECLFW(MMC3_CMDWrite) { - /* FCEU_printf("bs %04x %02x\n",A,V); */ - switch (A & 0xE001) { - case 0x8000: - if ((V & 0x40) != (mmc3.cmd & 0x40)) - FixMMC3PRG(V); - if ((V & 0x80) != (mmc3.cmd & 0x80)) - FixMMC3CHR(V); - mmc3.cmd = V; - break; - case 0x8001: { - int cbase = (mmc3.cmd & 0x80) << 5; - mmc3.regs[mmc3.cmd & 0x7] = V; - switch (mmc3.cmd & 0x07) { - case 0: - mmc3.cwrap((cbase ^ 0x000), V & (~1)); - mmc3.cwrap((cbase ^ 0x400), V | 1); - break; - case 1: - mmc3.cwrap((cbase ^ 0x800), V & (~1)); - mmc3.cwrap((cbase ^ 0xC00), V | 1); - break; - case 2: - mmc3.cwrap(cbase ^ 0x1000, V); - break; - case 3: - mmc3.cwrap(cbase ^ 0x1400, V); - break; - case 4: - mmc3.cwrap(cbase ^ 0x1800, V); - break; - case 5: - mmc3.cwrap(cbase ^ 0x1C00, V); - break; - case 6: - if (mmc3.cmd & 0x40) - mmc3.pwrap(0xC000, V); - else - mmc3.pwrap(0x8000, V); - break; - case 7: - mmc3.pwrap(0xA000, V); - break; - } - break; - } - case 0xA000: - if (mmc3.mwrap) - mmc3.mwrap(V); - break; - case 0xA001: - mmc3.wram = V; - break; - } -} - -DECLFW(MMC3_IRQWrite) { - /* FCEU_printf("%04x:%04x\n",A,V); */ - switch (A & 0xE001) { - case 0xC000: - IRQLatch = V; - break; - case 0xC001: - IRQReload = 1; - break; - case 0xE000: - X6502_IRQEnd(FCEU_IQEXT); - IRQa = 0; - break; - case 0xE001: - IRQa = 1; - break; - } -} - -static void ClockMMC3Counter(void) { - int count = IRQCount; - if (!count || IRQReload) { - IRQCount = IRQLatch; - IRQReload = 0; - } else - IRQCount--; - if ((count | isRevB) && !IRQCount) { - if (IRQa) { - X6502_IRQBegin(FCEU_IQEXT); - } - } -} - -static void MMC3_hb(void) { - ClockMMC3Counter(); -} - -static void MMC3_hb_KickMasterHack(void) { - if (scanline == 238) - ClockMMC3Counter(); - ClockMMC3Counter(); -} - -static void MMC3_hb_PALStarWarsHack(void) { - if (scanline == 240) - ClockMMC3Counter(); - ClockMMC3Counter(); -} - -void GenMMC3Restore(int version) { - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); -} - -static void GENCWRAP(uint32 A, uint8 V) { - setchr1(A, V); /* Business Wars NEEDS THIS for 8K CHR-RAM */ -} - -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)); -} - -static void GENMWRAP(uint8 V) { - mmc3.mirroring = V; - setmirror((V & 1) ^ 1); -} - -static void GENNOMWRAP(uint8 V) { - mmc3.mirroring = V; -} - -static DECLFW(MBWRAMMMC6) { - WRAM[A & 0x3ff] = V; -} - -static DECLFR(MAWRAMMMC6) { - return (WRAM[A & 0x3ff]); -} - -void GenMMC3Power(void) { - if (UNIFchrrama) - setchr8(0); - - SetWriteHandler(0x8000, 0xBFFF, MMC3_CMDWrite); - SetWriteHandler(0xC000, 0xFFFF, MMC3_IRQWrite); - SetReadHandler(0x8000, 0xFFFF, CartBR); - - mmc3.wram = mmc3.mirroring = 0; - setmirror(1); - if (mmc3.opts & 1) { - if (WRAMSIZE == 1024) { - FCEU_CheatAddRAM(1, 0x7000, WRAM); - SetReadHandler(0x7000, 0x7FFF, MAWRAMMMC6); - SetWriteHandler(0x7000, 0x7FFF, MBWRAMMMC6); - } else { - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); - SetWriteHandler(0x6000, 0x6000 + ((WRAMSIZE - 1) & 0x1fff), CartBW); - SetReadHandler(0x6000, 0x6000 + ((WRAMSIZE - 1) & 0x1fff), CartBR); - setprg8r(0x10, 0x6000, 0); - } - if (!(mmc3.opts & 2)) - FCEU_MemoryRand(WRAM, WRAMSIZE); - } - MMC3RegReset(); - if (CHRRAM) - FCEU_MemoryRand(CHRRAM, CHRRAMSIZE); -} - -void GenMMC3Close(void) { - if (CHRRAM) - FCEU_gfree(CHRRAM); - if (WRAM) - FCEU_gfree(WRAM); - CHRRAM = WRAM = NULL; -} - -void GenMMC3_Init(CartInfo *info, int prg, int chr, int wram, int battery) { - mmc3.pwrap = GENPWRAP; - mmc3.cwrap = GENCWRAP; - mmc3.mwrap = GENMWRAP; - - WRAMSIZE = wram << 10; - - PRGmask8[0] &= (prg >> 13) - 1; - CHRmask1[0] &= (chr >> 10) - 1; - CHRmask2[0] &= (chr >> 11) - 1; - - if (wram) { - mmc3.opts |= 1; - WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - } - - if (battery) { - mmc3.opts |= 2; - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; - } - - AddExState(MMC3_StateRegs, ~0, 0, 0); - - info->Power = GenMMC3Power; - info->Reset = MMC3RegReset; - info->Close = GenMMC3Close; - - if (info->CRC32 == 0x5104833e) /* Kick Master */ - GameHBIRQHook = MMC3_hb_KickMasterHack; - else if (info->CRC32 == 0x5a6860f1 || info->CRC32 == 0xae280e20) /* Shougi Meikan '92/'93 */ - GameHBIRQHook = MMC3_hb_KickMasterHack; - else if (info->CRC32 == 0xfcd772eb) /* PAL Star Wars, similar problem as Kick Master. */ - GameHBIRQHook = MMC3_hb_PALStarWarsHack; - else - GameHBIRQHook = MMC3_hb; - GameStateRestore = GenMMC3Restore; - submapper = info->submapper; -} - -/* ---------------------------------------------------------------------- - * -------------------------- MMC3 Based Code --------------------------- - * ---------------------------------------------------------------------- - */ - -/* ---------------------------- Mapper 4 -------------------------------- */ - -static int hackm4 = 0; /* For Karnov, maybe others. BLAH. Stupid iNES format.*/ - -static void M4Power(void) { - GenMMC3Power(); - mmc3.mirroring = (hackm4 ^ 1) & 1; - setmirror(hackm4); -} - -void Mapper4_Init(CartInfo *info) { - int ws = 8; - - if ((info->CRC32 == 0x93991433 || info->CRC32 == 0xaf65aa84)) { - FCEU_printf("Low-G-Man can not work normally in the iNES format.\nThis game has been recognized by its CRC32 " - "value, and the appropriate changes will be made so it will run.\nIf you wish to hack this game, " - "you should use the UNIF format for your hack.\n\n"); - ws = 0; - } - if (info->CRC32 == 0x97b6cb19) - isRevB = 0; - - GenMMC3_Init(info, 512, 256, ws, info->battery); - info->Power = M4Power; - hackm4 = info->mirror; -} - -/* ---------------------------- Mapper 12 ------------------------------- */ - -static void M12CW(uint32 A, uint8 V) { - setchr1(A, (mmc3.expregs[(A & 0x1000) >> 12] << 8) + V); -} - -static DECLFW(M12Write) { - mmc3.expregs[0] = V & 0x01; - mmc3.expregs[1] = (V & 0x10) >> 4; -} - -static DECLFR(M12Read) { - return mmc3.expregs[2]; -} - -static void M12Power(void) { - mmc3.expregs[0] = mmc3.expregs[1] = 0; - mmc3.expregs[2] = 1; /* chinese is default */ - GenMMC3Power(); - SetWriteHandler(0x4100, 0x5FFF, M12Write); - SetReadHandler(0x4100, 0x5FFF, M12Read); -} - -static void M12Reset(void) { - mmc3.expregs[0] = mmc3.expregs[1] = 0; - mmc3.expregs[2] ^= 1; - MMC3RegReset(); -} - -void Mapper12_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 8, info->battery); - mmc3.cwrap = M12CW; - isRevB = 0; - - info->Power = M12Power; - info->Reset = M12Reset; - AddExState(mmc3.expregs, 2, 0, "EXPR"); -} - -/* ---------------------------- Mapper 37 ------------------------------- */ - -static void M37PW(uint32 A, uint8 V) { - if (mmc3.expregs[0] != 2) - V &= 0x7; - else - V &= 0xF; - V |= mmc3.expregs[0] << 3; - setprg8(A, V); -} - -static void M37CW(uint32 A, uint8 V) { - uint32 NV = V; - NV &= 0x7F; - NV |= mmc3.expregs[0] << 6; - setchr1(A, NV); -} - -static DECLFW(M37Write) { - mmc3.expregs[0] = (V & 6) >> 1; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); -} - -static void M37Reset(void) { - mmc3.expregs[0] = 0; - MMC3RegReset(); -} - -static void M37Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, M37Write); -} - -void Mapper37_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 8, info->battery); - mmc3.pwrap = M37PW; - mmc3.cwrap = M37CW; - info->Power = M37Power; - info->Reset = M37Reset; - AddExState(mmc3.expregs, 1, 0, "EXPR"); -} - -/* ---------------------------- Mapper 44 ------------------------------- */ - -static void M44PW(uint32 A, uint8 V) { - uint32 NV = V; - if (mmc3.expregs[0] >= 6) - NV &= 0x1F; - else - NV &= 0x0F; - NV |= mmc3.expregs[0] << 4; - setprg8(A, NV); -} - -static void M44CW(uint32 A, uint8 V) { - uint32 NV = V; - if (mmc3.expregs[0] < 6) - NV &= 0x7F; - NV |= mmc3.expregs[0] << 7; - setchr1(A, NV); -} - -static DECLFW(M44Write) { - if (A & 1) { - mmc3.expregs[0] = V & 7; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } else - MMC3_CMDWrite(A, V); -} - -static void M44Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); - SetWriteHandler(0xA000, 0xBFFF, M44Write); -} - -void Mapper44_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 8, info->battery); - mmc3.cwrap = M44CW; - mmc3.pwrap = M44PW; - info->Power = M44Power; - AddExState(mmc3.expregs, 1, 0, "EXPR"); -} - -/* ---------------------------- Mapper 45 ------------------------------- */ - -static void M45CW(uint32 A, uint8 V) { - if (UNIFchrrama) { - /* assume chr-ram, 4-in-1 Yhc-Sxx-xx variants */ - setchr1(A, V); - } else { - uint32 mask = 0xFF >> (~mmc3.expregs[2] & 0xF); - uint32 base = ((mmc3.expregs[2] << 4) & 0xF00) | mmc3.expregs[0]; - setchr1(A, (base & ~mask) | (V & mask)); - } -} - -static DECLFR(M45ReadOB) { - return X.DB; -} - -static void M45PW(uint32 A, uint8 V) { - uint32 mask = ~mmc3.expregs[3] & 0x3F; - uint32 base = ((mmc3.expregs[2] << 2) & 0x300) | mmc3.expregs[1]; - setprg8(A, (base & ~mask) | (V & mask)); - - /* Some multicarts select between five different menus by connecting one of the higher address lines to PRG /CE. - The menu code selects between menus by checking which of the higher address lines disables PRG-ROM when set. */ - if ((PRGsize[0] < 0x200000 && mmc3.expregs[5] == 1 && (mmc3.expregs[1] & 0x80)) || - (PRGsize[0] < 0x200000 && mmc3.expregs[5] == 2 && (mmc3.expregs[2] & 0x40)) || - (PRGsize[0] < 0x100000 && mmc3.expregs[5] == 3 && (mmc3.expregs[1] & 0x40)) || - (PRGsize[0] < 0x100000 && mmc3.expregs[5] == 4 && (mmc3.expregs[2] & 0x20))) { - SetReadHandler(0x8000, 0xFFFF, M45ReadOB); - } else { - SetReadHandler(0x8000, 0xFFFF, CartBR); - } -} - -static DECLFW(M45Write) { - CartBW(A, V); - if (!(mmc3.expregs[3] & 0x40)) { - mmc3.expregs[mmc3.expregs[4]] = V; - mmc3.expregs[4] = (mmc3.expregs[4] + 1) & 3; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } -} - -static DECLFR(M45Read) { - uint32 addr = 1 << (mmc3.expregs[5] + 4); - if (A & (addr | (addr - 1))) - return X.DB | 1; - else - return X.DB; -} - -static void M45Reset(void) { - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[3] = mmc3.expregs[4] = 0; - mmc3.expregs[2] = 0x0F; - mmc3.expregs[5]++; - mmc3.expregs[5] &= 7; - MMC3RegReset(); -} - -static void M45Power(void) { - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[3] = mmc3.expregs[4] = mmc3.expregs[5] = 0; - mmc3.expregs[2] = 0x0F; - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, M45Write); - SetReadHandler(0x5000, 0x5FFF, M45Read); -} - -void Mapper45_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 8, info->battery); - mmc3.cwrap = M45CW; - mmc3.pwrap = M45PW; - info->Reset = M45Reset; - info->Power = M45Power; - AddExState(mmc3.expregs, 5, 0, "EXPR"); -} - -/* ---------------------------- Mapper 47 ------------------------------- */ - -static void M47PW(uint32 A, uint8 V) { - V &= 0xF; - V |= mmc3.expregs[0] << 4; - setprg8(A, V); -} - -static void M47CW(uint32 A, uint8 V) { - uint32 NV = V; - NV &= 0x7F; - NV |= mmc3.expregs[0] << 7; - setchr1(A, NV); -} - -static DECLFW(M47Write) { - mmc3.expregs[0] = V & 1; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); -} - -static void M47Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, M47Write); - /* SetReadHandler(0x6000,0x7FFF,0); */ -} - -void Mapper47_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 8, 0); - mmc3.pwrap = M47PW; - mmc3.cwrap = M47CW; - info->Power = M47Power; - AddExState(mmc3.expregs, 1, 0, "EXPR"); -} - -/* ---------------------------- Mapper 49 ------------------------------- */ -/* -------------------- BMC-STREETFIGTER-GAME4IN1 ----------------------- */ -/* added 6-24-19: - * BMC-STREETFIGTER-GAME4IN1 - Sic. $6000 set to $41 rather than $00 on power-up. - */ - -static void M49PW(uint32 A, uint8 V) { - if (mmc3.expregs[0] & 1) { - setprg8(A, ((mmc3.expregs[0] >> 2) & ~0x0F) | (V & 0x0F)); - } else { - setprg32(0x8000, (mmc3.expregs[0] >> 4) & 3); - } -} - -static void M49CW(uint32 A, uint8 V) { - setchr1(A, ((mmc3.expregs[0] << 1) & 0x180) | (V & 0x7F)); -} - -static DECLFW(M49Write) { - if (MMC3CanWriteToWRAM()) { - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } -} - -static void M49Reset(void) { - mmc3.expregs[0] = mmc3.expregs[1]; - MMC3RegReset(); -} - -static void M49Power(void) { - mmc3.expregs[0] = mmc3.expregs[1]; - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, M49Write); -} - -void Mapper49_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 128, 0, 0); - mmc3.cwrap = M49CW; - mmc3.pwrap = M49PW; - info->Reset = M49Reset; - info->Power = M49Power; - AddExState(mmc3.expregs, 2, 0, "EXPR"); - mmc3.expregs[1] = 0; - if (info->PRGCRC32 == 0x408EA235) - mmc3.expregs[1] = 0x41; /* Street Fighter II Game 4-in-1 */ -} - -/* ---------------------------- Mapper 52 ------------------------------- */ -/* Submapper 13 - CHR-ROM + CHR-RAM */ -static void M52PW(uint32 A, uint8 V) { - uint32 mask = (mmc3.expregs[0] & 8) ? 0x0F : 0x1F; - setprg8(A, ((mmc3.expregs[0] << 4) & 0x70) | (V & mask)); -} - -static void M52CW(uint32 A, uint8 V) { - uint32 mask = (mmc3.expregs[0] & 0x40) ? 0x7F : 0xFF; - uint32 bank = (submapper == 14) ? (((mmc3.expregs[0] << 3) & 0x080) | ((mmc3.expregs[0] << 7) & 0x300)) : - (((mmc3.expregs[0] << 3) & 0x180) | ((mmc3.expregs[0] << 7) & 0x200)); - uint8 ram = CHRRAM && ( - ((submapper == 13) && ((mmc3.expregs[0] & 3) == 0x3)) || - ((submapper == 14) && (mmc3.expregs[0] & 0x20))); - if (ram) { - setchr8r(0x10, 0); - } else { - setchr1(A, bank | (V & mask)); - } -} - -static DECLFW(M52Write) { - if (mmc3.expregs[1]) { - WRAM[A - 0x6000] = V; - return; - } - mmc3.expregs[1] = V & 0x80; - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); -} - -static void M52Reset(void) { - mmc3.expregs[0] = mmc3.expregs[1] = 0; - MMC3RegReset(); -} - -static void M52Power(void) { - M52Reset(); - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, M52Write); -} - -void Mapper52_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 8, info->battery); - mmc3.cwrap = M52CW; - mmc3.pwrap = M52PW; - info->Reset = M52Reset; - info->Power = M52Power; - AddExState(mmc3.expregs, 2, 0, "EXPR"); - if (info->iNES2 && ((info->submapper == 13) || (info->submapper == 14))) { - CHRRAMSIZE = info->CHRRamSize ? info->CHRRamSize : 8192; - CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); - SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); - AddExState(CHRRAM, CHRRAMSIZE, 0, "CRAM"); - } - if (info->CRC32 == 0xCCE8CA2F && submapper != 14) { - /* Well 8-in-1 (AB128) (Unl) (p1), with 1024 PRG and CHR is incompatible with submapper 13. - * This was reassigned to submapper 14 instead. */ - submapper = 14; - } -} - -/* ---------------------------- Mapper 76 ------------------------------- */ - -static void M76CW(uint32 A, uint8 V) { - if (A >= 0x1000) - setchr2((A & 0xC00) << 1, V); -} - -void Mapper76_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 128, 0, 0); - mmc3.cwrap = M76CW; -} - -/* ---------------------------- Mapper 74 ------------------------------- */ - -static void M74CW(uint32 A, uint8 V) { - if ((V == 8) || (V == 9)) /* Di 4 Ci - Ji Qi Ren Dai Zhan (As).nes, Ji Jia Zhan Shi (As).nes */ - setchr1r(0x10, A, V); - else - setchr1r(0, A, V); -} - -void Mapper74_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 8, info->battery); - mmc3.cwrap = M74CW; - CHRRAMSIZE = 2048; - CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); - SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); - AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); -} - -/* ---------------------------- Mapper 114 ------------------------------ */ - -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 (mmc3.expregs[0] & 0x80) { - if (mmc3.expregs[0] & 0x20) - setprg32(0x8000, (mmc3.expregs[0] & 0x0F) >> 1); - else { - setprg16(0x8000, (mmc3.expregs[0] & 0x0F)); - setprg16(0xC000, (mmc3.expregs[0] & 0x0F)); - } - } else - setprg8(A, V); -} - -static void M114CWRAP(uint32 A, uint8 V) { - setchr1(A, (uint32)V | ((mmc3.expregs[1] & 1) << 8)); -} - -static DECLFW(M114Write) { - switch (A & 0xE001) { - case 0x8001: - MMC3_CMDWrite(0xA000, V); - break; - case 0xA000: - MMC3_CMDWrite(0x8000, (V & 0xC0) | (m114_perm[V & 7])); - cmdin = 1; - break; - case 0xC000: - if (!cmdin) - break; - MMC3_CMDWrite(0x8001, V); - cmdin = 0; - break; - case 0xA001: - IRQLatch = V; - break; - case 0xC001: - IRQReload = 1; - break; - case 0xE000: - X6502_IRQEnd(FCEU_IQEXT); - IRQa = 0; - break; - case 0xE001: - IRQa = 1; - break; - } -} - -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) { - if (A & 1) - mmc3.expregs[1] = V; - else - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); - } -} - -static void M114Power(void) { - mmc3.expregs[0] = mmc3.expregs[1] = 0; - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, M114ExWrite); - SetWriteHandler(0x8000, 0xFFFF, M114Write); - if (type_Boogerman) - SetWriteHandler(0x8000, 0xFFFF, BoogermanWrite); -} - -static void M114Reset(void) { - mmc3.expregs[0] = mmc3.expregs[1] = 0; - MMC3RegReset(); -} - -void Mapper114_Init(CartInfo *info) { - isRevB = 0; - /* Use NES 2.0 submapper to identify scrambling pattern, otherwise CRC32 for Boogerman and test rom */ - type_Boogerman = info->iNES2 ? (info->submapper == 1) : (info->CRC32 == 0x80eb1839 || info->CRC32 == 0x071e4ee8); - - GenMMC3_Init(info, 256, 256, 0, 0); - mmc3.pwrap = M114PWRAP; - mmc3.cwrap = M114CWRAP; - info->Power = M114Power; - info->Reset = M114Reset; - AddExState(mmc3.expregs, 1, 0, "EXPR"); - AddExState(&cmdin, 1, 0, "CMDI"); -} - -/* ---------------------------- Mapper 115 KN-658 board ------------------------------ */ - -static void M115PW(uint32 A, uint8 V) { - if (mmc3.expregs[0] & 0x80) { - if (mmc3.expregs[0] & 0x20) - setprg32(0x8000, (mmc3.expregs[0] & 0x0F) >> 1); /* real hardware tests, info 100% now lol */ - else { - setprg16(0x8000, (mmc3.expregs[0] & 0x0F)); - setprg16(0xC000, (mmc3.expregs[0] & 0x0F)); - } - } else - setprg8(A, V); -} - -static void M115CW(uint32 A, uint8 V) { - setchr1(A, (uint32)V | ((mmc3.expregs[1] & 1) << 8)); -} - -static DECLFW(M115Write) { - if (A == 0x5080) - mmc3.expregs[2] = V; /* Extra prot hardware 2-in-1 mode */ - else if (A == 0x6000) - mmc3.expregs[0] = V; - else if (A == 0x6001) - mmc3.expregs[1] = V; - FixMMC3PRG(mmc3.cmd); -} - -static DECLFR(M115Read) { - return mmc3.expregs[2]; -} - -static void M115Power(void) { - GenMMC3Power(); - SetWriteHandler(0x4100, 0x7FFF, M115Write); - SetReadHandler(0x5000, 0x5FFF, M115Read); -} - -void Mapper115_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 512, 0, 0); - mmc3.cwrap = M115CW; - mmc3.pwrap = M115PW; - info->Power = M115Power; - AddExState(mmc3.expregs, 3, 0, "EXPR"); -} - -/* ---------------------------- Mapper 118 ------------------------------ */ - -static uint8 PPUCHRBus; -static uint8 TKSMIR[8]; - -static void FP_FASTAPASS(1) TKSPPU(uint32 A) { - A &= 0x1FFF; - A >>= 10; - PPUCHRBus = A; - setmirror(MI_0 + TKSMIR[A]); -} - -static void TKSWRAP(uint32 A, uint8 V) { - TKSMIR[A >> 10] = V >> 7; - setchr1(A, V & 0x7F); - if (PPUCHRBus == (A >> 10)) - setmirror(MI_0 + (V >> 7)); -} - -/* ---------------------------- Mapper 119 ------------------------------ */ - -static void TQWRAP(uint32 A, uint8 V) { - setchr1r((V & 0x40) >> 2, A, V & 0x3F); -} - -void Mapper119_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 64, 0, 0); - mmc3.cwrap = TQWRAP; - CHRRAMSIZE = 8192; - CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); - SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); - AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); -} - -/* ---------------------------- Mapper 165 ------------------------------ */ - -static void M165CW(uint32 A, uint8 V) { - if (V == 0) - setchr4r(0x10, A, 0); - else - setchr4(A, V >> 2); -} - -static void M165PPUFD(void) { - if (mmc3.expregs[0] == 0xFD) { - M165CW(0x0000, mmc3.regs[0]); - M165CW(0x1000, mmc3.regs[2]); - } -} - -static void M165PPUFE(void) { - if (mmc3.expregs[0] == 0xFE) { - M165CW(0x0000, mmc3.regs[1]); - M165CW(0x1000, mmc3.regs[4]); - } -} - -static void M165CWM(uint32 A, uint8 V) { - if (((mmc3.cmd & 0x7) == 0) || ((mmc3.cmd & 0x7) == 2)) - M165PPUFD(); - if (((mmc3.cmd & 0x7) == 1) || ((mmc3.cmd & 0x7) == 4)) - M165PPUFE(); -} - -static void FP_FASTAPASS(1) M165PPU(uint32 A) { - if ((A & 0x1FF0) == 0x1FD0) { - mmc3.expregs[0] = 0xFD; - M165PPUFD(); - } else if ((A & 0x1FF0) == 0x1FE0) { - mmc3.expregs[0] = 0xFE; - M165PPUFE(); - } -} - -static void M165Power(void) { - mmc3.expregs[0] = 0xFD; - GenMMC3Power(); -} - -void Mapper165_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 128, 8, info->battery); - mmc3.cwrap = M165CWM; - PPU_hook = M165PPU; - info->Power = M165Power; - CHRRAMSIZE = 4096; - CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); - SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); - AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); - AddExState(mmc3.expregs, 4, 0, "EXPR"); -} - -/* ---------------------------- Mapper 191 ------------------------------ */ - -static void M191CW(uint32 A, uint8 V) { - setchr1r((V & 0x80) >> 3, A, V); -} - -void Mapper191_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 8, info->battery); - mmc3.cwrap = M191CW; - CHRRAMSIZE = 2048; - CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); - SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); - AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); -} - -/* ---------------------------- Mapper 192 ------------------------------- */ - -static void M192CW(uint32 A, uint8 V) { - /* Ying Lie Qun Xia Zhuan (Chinese), - * You Ling Xing Dong (China) (Unl) [this will be mistakenly headered as m074 sometimes] - */ - if ((V == 8) || (V == 9) || (V == 0xA) || (V == 0xB)) - setchr1r(0x10, A, V); - else - setchr1r(0, A, V); -} - -void Mapper192_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 8, info->battery); - mmc3.cwrap = M192CW; - CHRRAMSIZE = 4096; - CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); - SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); - AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); -} - -/* ---------------------------- Mapper 194 ------------------------------- */ - -static void M194CW(uint32 A, uint8 V) { - if (V <= 1) /* Dai-2-Ji - Super Robot Taisen (As).nes */ - setchr1r(0x10, A, V); - else - setchr1r(0, A, V); -} - -void Mapper194_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 8, info->battery); - mmc3.cwrap = M194CW; - CHRRAMSIZE = 2048; - CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); - SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); - AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); -} - -/* ---------------------------- Mapper 196 ------------------------------- */ -/* MMC3 board with optional command address line connection, allows to - * make three-four different wirings to IRQ address lines and separately to - * CMD address line, Mali Boss additionally check if wiring are correct for - * game - */ - -static void M196PW(uint32 A, uint8 V) { - if (mmc3.expregs[0]) - setprg32(0x8000, mmc3.expregs[1]); - else - setprg8(A, V); -} - -static DECLFW(Mapper196Write) { - A = (A & 0xF000) | (!!(A & 0xE) ^ (A & 1)); - if (A >= 0xC000) - MMC3_IRQWrite(A, V); - else - MMC3_CMDWrite(A, V); -} - -static DECLFW(Mapper196WriteLo) { - mmc3.expregs[0] = 1; - mmc3.expregs[1] = (V & 0xf) | (V >> 4); - FixMMC3PRG(mmc3.cmd); -} - -static void Mapper196Power(void) { - GenMMC3Power(); - mmc3.expregs[0] = mmc3.expregs[1] = 0; - SetWriteHandler(0x6000, 0x6FFF, Mapper196WriteLo); - SetWriteHandler(0x8000, 0xFFFF, Mapper196Write); -} - -void Mapper196_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 128, 0, 0); - mmc3.pwrap = M196PW; - info->Power = Mapper196Power; -} - -/* ---------------------------- Mali Splash Bomb---------------------------- */ -/* The same board as for 196 mapper games, but with additional data bit swap - * Also, it is impossible to work on the combined 196 mapper source with - * all data bits merged, because it's using one of them as 8000 reg... - */ - -static void UNLMaliSBPW(uint32 A, uint8 V) { - setprg8(A, (V & 3) | ((V & 8) >> 1) | ((V & 4) << 1)); -} - -static void UNLMaliSBCW(uint32 A, uint8 V) { - setchr1(A, (V & 0xDD) | ((V & 0x20) >> 4) | ((V & 2) << 4)); -} - -static DECLFW(UNLMaliSBWrite) { - if (A >= 0xC000) { - A = (A & 0xFFFE) | ((A >> 2) & 1) | ((A >> 3) & 1); - MMC3_IRQWrite(A, V); - } else { - A = (A & 0xFFFE) | ((A >> 3) & 1); - MMC3_CMDWrite(A, V); - } -} - -static void UNLMaliSBPower(void) { - GenMMC3Power(); - SetWriteHandler(0x8000, 0xFFFF, UNLMaliSBWrite); -} - -void UNLMaliSB_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 128, 0, 0); - mmc3.pwrap = UNLMaliSBPW; - mmc3.cwrap = UNLMaliSBCW; - info->Power = UNLMaliSBPower; -} - -/* ---------------------------- Mapper 197 ------------------------------- */ - -static void M197CW(uint32 A, uint8 V) { - if (A == 0x0000) - setchr4(0x0000, V >> 1); - else if (A == 0x1000) - setchr2(0x1000, V); - else if (A == 0x1400) - setchr2(0x1800, V); -} - -void Mapper197_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 512, 8, 0); - mmc3.cwrap = M197CW; -} - -/* ---------------------------- Mapper 198 ------------------------------- */ - -static void M198PW(uint32 A, uint8 V) { - if (V >= 0x50) /* Tenchi o Kurau II - Shokatsu Koumei Den (J) (C).nes */ - setprg8(A, V & 0x4F); - else - setprg8(A, V); -} - -static void M198Power(void) { - GenMMC3Power(); - setprg4r(0x10, 0x5000, 2); - SetWriteHandler(0x5000, 0x5fff, CartBW); - SetReadHandler(0x5000, 0x5fff, CartBR); -} - -void Mapper198_Init(CartInfo *info) { - GenMMC3_Init(info, 1024, 0, 16, info->battery); - mmc3.pwrap = M198PW; - info->Power = M198Power; -} - -/* ---------------------------- Mapper 205 ------------------------------ */ -/* UNIF boardname BMC-JC-016-2 -https://wiki.nesdev.com/w/index.php/INES_Mapper_205 */ - -/* 2023-02 : Update reg write logic and add solder pad */ - -static void M205PW(uint32 A, uint8 V) { - uint8 bank = V & ((mmc3.expregs[0] & 0x02) ? 0x0F : 0x1F); - setprg8(A, mmc3.expregs[0] << 4 | bank); -} - -static void M205CW(uint32 A, uint8 V) { - uint8 bank = V & ((mmc3.expregs[0] & 0x02) ? 0x7F : 0xFF); - setchr1(A, (mmc3.expregs[0] << 7) | bank); -} - -static DECLFW(M205Write) { - mmc3.expregs[0] = V & 3; - if (V & 1) { - mmc3.expregs[0] |= mmc3.expregs[1]; - } - CartBW(A, V); - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); -} - -static void M205Reset(void) { - mmc3.expregs[0] = 0; - mmc3.expregs[1] ^= 2; /* solder pad */ - MMC3RegReset(); -} - -static void M205Power(void) { - mmc3.expregs[0] = mmc3.expregs[1] = 0; - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, M205Write); -} - -void Mapper205_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 128, 8, 0); - mmc3.pwrap = M205PW; - mmc3.cwrap = M205CW; - info->Power = M205Power; - info->Reset = M205Reset; - AddExState(mmc3.expregs, 2, 0, "EXPR"); -} - -/* --------------------------- GN-45 BOARD ------------------------------ */ - -/* Mapper 361 and 366, previously assigned as Mapper 205 */ -/* Mapper 361: - * JY-009 - * JY-018 - * JY-019 - * OK-411 - * Mapper 366 (GN-45): - * K-3131GS - * K-3131SS -*/ -static void GN45PW(uint32 A, uint8 V) { - setprg8(A, (V & 0x0f) | mmc3.expregs[0]); -} - -static void GN45CW(uint32 A, uint8 V) { - setchr1(A, (V & 0x7F) | (mmc3.expregs[0] << 3)); -} - -static void GN45Reset(void) { - mmc3.expregs[0] = mmc3.expregs[2] = 0; - MMC3RegReset(); -} - -static DECLFW(M361Write) { - mmc3.expregs[0] = V & 0xF0; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); -} - -static void M361Power(void) { - GenMMC3Power(); - SetWriteHandler(0x7000, 0x7fff, M361Write); /* OK-411 boards, the same logic, but data latched, 2-in-1 frankenstein */ -} - -void Mapper361_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 512, 0, 0); - mmc3.pwrap = GN45PW; - mmc3.cwrap = GN45CW; - info->Power = M361Power; - info->Reset = GN45Reset; - AddExState(mmc3.expregs, 1, 0, "EXPR"); -} - -static DECLFW(M366Write) { - CartBW(A, V); - if (mmc3.expregs[2] == 0) { - mmc3.expregs[0] = A & 0x70; - mmc3.expregs[2] = A & 0x80; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } -} - -static void M366Power(void) { - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7fff, M366Write); -} - -void Mapper366_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 512, 8, 0); - mmc3.pwrap = GN45PW; - mmc3.cwrap = GN45CW; - info->Power = M366Power; - info->Reset = GN45Reset; - AddExState(mmc3.expregs, 1, 0, "EXPR"); -} - -/* ---------------------------- Mapper 245 ------------------------------ */ - -static void M245CW(uint32 A, uint8 V) { - if (!UNIFchrrama) /* Yong Zhe Dou E Long - Dragon Quest VI (As).nes NEEDS THIS for RAM cart */ - setchr1(A, V & 7); - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); -} - -static void M245PW(uint32 A, uint8 V) { - setprg8(A, (V & 0x3F) | ((mmc3.expregs[0] & 2) << 5)); -} - -static void M245Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); -} - -void Mapper245_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 8, info->battery); - mmc3.cwrap = M245CW; - mmc3.pwrap = M245PW; - info->Power = M245Power; - AddExState(mmc3.expregs, 1, 0, "EXPR"); -} - -/* ---------------------------- Mapper 249 ------------------------------ */ - -static void M249PW(uint32 A, uint8 V) { - if (mmc3.expregs[0] & 0x2) { - if (V < 0x20) - V = (V & 1) | ((V >> 3) & 2) | ((V >> 1) & 4) | ((V << 2) & 8) | ((V << 2) & 0x10); - else { - V -= 0x20; - V = (V & 3) | ((V >> 1) & 4) | ((V >> 4) & 8) | ((V >> 2) & 0x10) | ((V << 3) & 0x20) | ((V << 2) & 0xC0); - } - } - setprg8(A, V); -} - -static void M249CW(uint32 A, uint8 V) { - if (mmc3.expregs[0] & 0x2) - V = (V & 3) | ((V >> 1) & 4) | ((V >> 4) & 8) | ((V >> 2) & 0x10) | ((V << 3) & 0x20) | ((V << 2) & 0xC0); - setchr1(A, V); -} - -static DECLFW(M249Write) { - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); -} - -static void M249Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); - SetWriteHandler(0x5000, 0x5000, M249Write); -} - -void Mapper249_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 8, info->battery); - mmc3.cwrap = M249CW; - mmc3.pwrap = M249PW; - info->Power = M249Power; - AddExState(mmc3.expregs, 1, 0, "EXPR"); -} - -/* ---------------------------- Mapper 250 ------------------------------ */ - -static DECLFW(M250Write) { - MMC3_CMDWrite((A & 0xE000) | ((A & 0x400) >> 10), A & 0xFF); -} - -static DECLFW(M250IRQWrite) { - MMC3_IRQWrite((A & 0xE000) | ((A & 0x400) >> 10), A & 0xFF); -} - -static void M250_Power(void) { - GenMMC3Power(); - SetWriteHandler(0x8000, 0xBFFF, M250Write); - SetWriteHandler(0xC000, 0xFFFF, M250IRQWrite); -} - -void Mapper250_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 8, info->battery); - info->Power = M250_Power; -} - -/* ---------------------------- Mapper 254 ------------------------------ */ - -static DECLFR(MR254WRAM) { - if (mmc3.expregs[0]) - return WRAM[A - 0x6000]; - else - return WRAM[A - 0x6000] ^ mmc3.expregs[1]; -} - -static DECLFW(M254Write) { - switch (A) { - case 0x8000: - mmc3.expregs[0] = 0xff; - break; - case 0xA001: - mmc3.expregs[1] = V; - break; - } - MMC3_CMDWrite(A, V); -} - -static void M254_Power(void) { - GenMMC3Power(); - SetWriteHandler(0x8000, 0xBFFF, M254Write); - SetReadHandler(0x6000, 0x7FFF, MR254WRAM); -} - -void Mapper254_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 128, 8, info->battery); - info->Power = M254_Power; - AddExState(mmc3.expregs, 2, 0, "EXPR"); -} - -/* ---------------------------- UNIF Boards ----------------------------- */ - -void TBROM_Init(CartInfo *info) { - GenMMC3_Init(info, 64, 64, 0, 0); -} - -void TEROM_Init(CartInfo *info) { - GenMMC3_Init(info, 32, 32, 0, 0); -} - -void TFROM_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 64, 0, 0); -} - -void TGROM_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 0, 0, 0); -} - -void TKROM_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 8, info->battery); -} - -void TLROM_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 0, 0); -} - -void TSROM_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 8, 0); -} - -void TLSROM_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 8, 0); - mmc3.cwrap = TKSWRAP; - mmc3.mwrap = GENNOMWRAP; - PPU_hook = TKSPPU; - AddExState(&PPUCHRBus, 1, 0, "PPUC"); -} - -void TKSROM_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 8, info->battery); - mmc3.cwrap = TKSWRAP; - mmc3.mwrap = GENNOMWRAP; - PPU_hook = TKSPPU; - AddExState(&PPUCHRBus, 1, 0, "PPUC"); -} - -void TQROM_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 64, 0, 0); - mmc3.cwrap = TQWRAP; - CHRRAMSIZE = 8192; - CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); - SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); - AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); -} - -void HKROM_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 512, 1, info->battery); -} diff --git a/src/boards/mmc3.h b/src/boards/mmc3.h deleted file mode 100644 index c483ac83a..000000000 --- a/src/boards/mmc3.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef _MMC3_H -#define _MMC3_H - -typedef struct { - uint8 cmd; - uint8 opts; - uint8 mirroring; - uint8 wram; - uint8 regs[8]; - uint8 expregs[8]; /* extra regs, mostly for pirate/multicart carts */ - - void (*pwrap)(uint32 A, uint8 V); - void (*cwrap)(uint32 A, uint8 V); - void (*mwrap)(uint8 V); -} MMC3; - -extern MMC3 mmc3; - -void GenMMC3Power(void); -void GenMMC3Restore(int version); -void MMC3RegReset(void); -void GenMMC3Close(void); -void FixMMC3PRG(int V); -void FixMMC3CHR(int V); -int MMC3CanWriteToWRAM(); -DECLFW(MMC3_CMDWrite); -DECLFW(MMC3_IRQWrite); - -void GenMMC3_Init(CartInfo *info, int prg, int chr, int wram, int battery); - -#endif /* _MMC3_H */ diff --git a/src/boards/n106.c b/src/boards/n106.c deleted file mode 100644 index cca6791f9..000000000 --- a/src/boards/n106.c +++ /dev/null @@ -1,458 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2002 Xodnizel - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "mapinc.h" - -static uint16 IRQCount; -static uint8 IRQa; - -static uint8 WRAM[8192]; -static uint8 IRAM[128]; - -static DECLFR(AWRAM) { - return(WRAM[A - 0x6000]); -} - -static DECLFW(BWRAM) { - WRAM[A - 0x6000] = V; -} - -void Mapper19_ESI(void); - -static uint8 NTAPage[4]; - -static uint8 dopol; -static uint8 gorfus; -static uint8 gorko; - -static void NamcoSound(int Count); -static void NamcoSoundHack(void); -static void DoNamcoSound(int32 *Wave, int Count); -static void DoNamcoSoundHQ(void); -static void SyncHQ(int32 ts); - -static int is210; /* Lesser mapper. */ - -static uint8 PRG[3]; -static uint8 CHR[8]; - -static SFORMAT N106_StateRegs[] = { - { PRG, 3, "PRG" }, - { CHR, 8, "CHR" }, - { NTAPage, 4, "NTA" }, - { &IRQCount, 2, "IRQC" }, - { &IRQa, 1, "IRQA" }, - { &dopol, 1, "GORF" }, - { &gorfus, 1, "DOPO" }, - { &gorko, 1, "GORK" }, - { 0 } -}; - -static void SyncPRG(void) { - setprg8(0x8000, PRG[0]); - setprg8(0xa000, PRG[1]); - setprg8(0xc000, PRG[2]); - setprg8(0xe000, 0x3F); -} - -static void SyncMirror() { - switch(gorko) { - case 0: setmirror(MI_0); break; - case 1: setmirror(MI_V); break; - case 2: setmirror(MI_H); break; - case 3: setmirror(MI_0); break; - } -} - -static void FP_FASTAPASS(1) NamcoIRQHook(int a) { - if (IRQa) { - IRQCount += a; - if (IRQCount >= 0x7FFF) { - X6502_IRQBegin(FCEU_IQEXT); - IRQa = 0; - IRQCount = 0x7FFF; - } - } -} - -static DECLFR(Namco_Read4800) { - uint8 ret = IRAM[dopol & 0x7f]; - /* Maybe I should call NamcoSoundHack() here? */ - #ifdef FCEUDEF_DEBUGGER - if (!fceuindbg) - #endif - if (dopol & 0x80) - dopol = (dopol & 0x80) | ((dopol + 1) & 0x7f); - return ret; -} - -static DECLFR(Namco_Read5000) { - return(IRQCount); -} - -static DECLFR(Namco_Read5800) { - return(IRQCount >> 8); -} - -static void FASTAPASS(2) DoNTARAMROM(int w, uint8 V) { - NTAPage[w] = V; - if (V >= 0xE0) - setntamem(NTARAM + ((V & 1) << 10), 1, w); - else { - V &= CHRmask1[0]; - setntamem(CHRptr[0] + (V << 10), 0, w); - } -} - -static void FixNTAR(void) { - int x; - for (x = 0; x < 4; x++) - DoNTARAMROM(x, NTAPage[x]); -} - -static void FASTAPASS(2) DoCHRRAMROM(int x, uint8 V) { - CHR[x] = V; - if (!is210 && !((gorfus >> ((x >> 2) + 6)) & 1) && (V >= 0xE0)) { - } else - setchr1(x << 10, V); -} - -static void FixCRR(void) { - int x; - for (x = 0; x < 8; x++) - DoCHRRAMROM(x, CHR[x]); -} - -static DECLFW(Mapper19C0D8_write) { - DoNTARAMROM((A - 0xC000) >> 11, V); -} - -static uint32 FreqCache[8]; -static uint32 EnvCache[8]; -static uint32 LengthCache[8]; - -static void FixCache(int a, int V) { - int w = (a >> 3) & 0x7; - switch (a & 0x07) { - case 0x00: FreqCache[w] &= ~0x000000FF; FreqCache[w] |= V; break; - case 0x02: FreqCache[w] &= ~0x0000FF00; FreqCache[w] |= V << 8; break; - case 0x04: - FreqCache[w] &= ~0x00030000; FreqCache[w] |= (V & 3) << 16; - /* something wrong here http://www.romhacking.net/forum/index.php?topic=21907.msg306903#msg306903 */ - /* LengthCache[w] = (8 - ((V >> 2) & 7)) << 2; */ - /* fix be like in https://github.com/SourMesen/Mesen/blob/cda0a0bdcb5525480784f4b8c71de6fc7273b570/Core/Namco163Audio.h#L61 */ - LengthCache[w] = 256 - (V & 0xFC); - break; - case 0x07: EnvCache[w] = (double)(V & 0xF) * 576716; break; - } -} - -static DECLFW(Mapper19_write) { - A &= 0xF800; - if (A >= 0x8000 && A <= 0xb800) - DoCHRRAMROM((A - 0x8000) >> 11, V); - else - switch (A) { - case 0x4800: - if (dopol & 0x40) { - if (FSettings.SndRate) { - NamcoSoundHack(); - GameExpSound.Fill = NamcoSound; - GameExpSound.HiFill = DoNamcoSoundHQ; - GameExpSound.HiSync = SyncHQ; - } - FixCache(dopol, V); - } - IRAM[dopol & 0x7f] = V; - if (dopol & 0x80) - dopol = (dopol & 0x80) | ((dopol + 1) & 0x7f); - break; - case 0xf800: - dopol = V; break; - case 0x5000: - IRQCount &= 0xFF00; IRQCount |= V; X6502_IRQEnd(FCEU_IQEXT); break; - case 0x5800: - IRQCount &= 0x00ff; IRQCount |= (V & 0x7F) << 8; - IRQa = V & 0x80; - X6502_IRQEnd(FCEU_IQEXT); - break; - case 0xE000: - gorko = V & 0xC0; - PRG[0] = V & 0x3F; - SyncPRG(); - if (is210) { - gorko = V >> 6; - SyncMirror(); - } - break; - case 0xE800: - gorfus = V & 0xC0; - FixCRR(); - PRG[1] = V & 0x3F; - SyncPRG(); - break; - case 0xF000: - PRG[2] = V & 0x3F; - SyncPRG(); - break; - } -} - -static int dwave = 0; - -static void NamcoSoundHack(void) { - int32 z, a; - if (FSettings.soundq >= 1) { - DoNamcoSoundHQ(); - return; - } - z = ((SOUNDTS << 16) / soundtsinc) >> 4; - a = z - dwave; - if (a) DoNamcoSound(&Wave[dwave], a); - dwave += a; -} - -static void NamcoSound(int Count) { - int32 z, a; - z = ((SOUNDTS << 16) / soundtsinc) >> 4; - a = z - dwave; - if (a) DoNamcoSound(&Wave[dwave], a); - dwave = 0; -} - -static uint32 PlayIndex[8]; -static int32 vcount[8]; -static int32 CVBC; - -#define TOINDEX (16 + 1) - -static SFORMAT N106_SStateRegs[] = -{ - { PlayIndex, 32, "IDX0" }, - { vcount, 32, "VCT0" }, - { &CVBC, 4, "BC00" }, - { 0 } -}; - -/* 16:15 */ -static void SyncHQ(int32 ts) { - CVBC = ts; -} - - -/* Things to do: - 1 Read freq low - 2 Read freq mid - 3 Read freq high - 4 Read envelope - ...? -*/ - -static INLINE uint32 FetchDuff(uint32 P, uint32 envelope) { - uint32 duff; - duff = IRAM[((IRAM[0x46 + (P << 3)] + (PlayIndex[P] >> TOINDEX)) & 0xFF) >> 1]; - if ((IRAM[0x46 + (P << 3)] + (PlayIndex[P] >> TOINDEX)) & 1) - duff >>= 4; - duff &= 0xF; - duff = (duff * envelope) >> 16; - return(duff); -} - -static void DoNamcoSoundHQ(void) { - int32 P, V; - int32 cyclesuck = (((IRAM[0x7F] >> 4) & 7) + 1) * 15; - - for (P = 7; P >= (7 - ((IRAM[0x7F] >> 4) & 7)); P--) { - if ((IRAM[0x44 + (P << 3)] & 0xE0) && (IRAM[0x47 + (P << 3)] & 0xF)) { - uint32 freq; - int32 vco; - uint32 duff2, lengo, envelope; - - vco = vcount[P]; - freq = FreqCache[P]; - envelope = EnvCache[P]; - lengo = LengthCache[P]; - - duff2 = FetchDuff(P, envelope); - for (V = CVBC << 1; V < (int)SOUNDTS << 1; V++) { - WaveHi[V >> 1] += duff2; - if (!vco) { - PlayIndex[P] += freq; - while ((PlayIndex[P] >> TOINDEX) >= lengo) PlayIndex[P] -= lengo << TOINDEX; - duff2 = FetchDuff(P, envelope); - vco = cyclesuck; - } - vco--; - } - vcount[P] = vco; - } - } - CVBC = SOUNDTS; -} - - -static void DoNamcoSound(int32 *Wave, int Count) { - int P, V; - for (P = 7; P >= 7 - ((IRAM[0x7F] >> 4) & 7); P--) { - if ((IRAM[0x44 + (P << 3)] & 0xE0) && (IRAM[0x47 + (P << 3)] & 0xF)) { - int32 inc; - uint32 freq; - int32 vco; - uint32 duff, duff2, lengo, envelope; - - vco = vcount[P]; - freq = FreqCache[P]; - envelope = EnvCache[P]; - lengo = LengthCache[P]; - - if (!freq) - continue; - - { - int c = ((IRAM[0x7F] >> 4) & 7) + 1; - inc = (long double)(FSettings.SndRate << 15) / ((long double)freq * 21477272 / ((long double)0x400000 * c * 45)); - } - - duff = IRAM[(((IRAM[0x46 + (P << 3)] + PlayIndex[P]) & 0xFF) >> 1)]; - if ((IRAM[0x46 + (P << 3)] + PlayIndex[P]) & 1) - duff >>= 4; - duff &= 0xF; - duff2 = (duff * envelope) >> 19; - for (V = 0; V < Count * 16; V++) { - if (vco >= inc) { - PlayIndex[P]++; - if (PlayIndex[P] >= lengo) - PlayIndex[P] = 0; - vco -= inc; - duff = IRAM[(((IRAM[0x46 + (P << 3)] + PlayIndex[P]) & 0xFF) >> 1)]; - if ((IRAM[0x46 + (P << 3)] + PlayIndex[P]) & 1) - duff >>= 4; - duff &= 0xF; - duff2 = (duff * envelope) >> 19; - } - Wave[V >> 4] += duff2; - vco += 0x8000; - } - vcount[P] = vco; - } - } -} - -static void Mapper19_StateRestore(int version) { - int x; - SyncPRG(); - SyncMirror(); - FixNTAR(); - FixCRR(); - for (x = 0x40; x < 0x80; x++) - FixCache(x, IRAM[x]); -} - -static void M19SC(void) { - if (FSettings.SndRate) - Mapper19_ESI(); -} - -void Mapper19_ESI(void) { - GameExpSound.RChange = M19SC; - memset(vcount, 0, sizeof(vcount)); - memset(PlayIndex, 0, sizeof(PlayIndex)); - CVBC = 0; -} - -void NSFN106_Init(void) { - SetWriteHandler(0xf800, 0xffff, Mapper19_write); - SetWriteHandler(0x4800, 0x4fff, Mapper19_write); - SetReadHandler(0x4800, 0x4fff, Namco_Read4800); - Mapper19_ESI(); -} - -static int battery = 0; - -static void N106_Power(void) { - int x; - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xffff, Mapper19_write); - SetWriteHandler(0x4020, 0x5fff, Mapper19_write); - if (!is210) { - SetWriteHandler(0xc000, 0xdfff, Mapper19C0D8_write); - SetReadHandler(0x4800, 0x4fff, Namco_Read4800); - SetReadHandler(0x5000, 0x57ff, Namco_Read5000); - SetReadHandler(0x5800, 0x5fff, Namco_Read5800); - NTAPage[0] = NTAPage[1] = NTAPage[2] = NTAPage[3] = 0xFF; - FixNTAR(); - } - - SetReadHandler(0x6000, 0x7FFF, AWRAM); - SetWriteHandler(0x6000, 0x7FFF, BWRAM); - FCEU_CheatAddRAM(8, 0x6000, WRAM); - - gorfus = 0xFF; - SyncPRG(); - FixCRR(); - - if (!battery) { - FCEU_MemoryRand(WRAM, sizeof(WRAM)); - FCEU_MemoryRand(IRAM, sizeof(IRAM)); - } - for (x = 0x40; x < 0x80; x++) - FixCache(x, IRAM[x]); -} - -void Mapper19_Init(CartInfo *info) { - is210 = 0; - battery = info->battery; - info->Power = N106_Power; - - MapIRQHook = NamcoIRQHook; - GameStateRestore = Mapper19_StateRestore; - GameExpSound.RChange = M19SC; - - if (FSettings.SndRate) - Mapper19_ESI(); - - FCEU_MemoryRand(WRAM, sizeof(WRAM)); - FCEU_MemoryRand(IRAM, sizeof(IRAM)); - AddExState(WRAM, 8192, 0, "WRAM"); - AddExState(IRAM, 128, 0, "IRAM"); - AddExState(N106_StateRegs, ~0, 0, 0); - AddExState(N106_SStateRegs, ~0, 0, 0); - - if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = 8192; - info->SaveGame[1] = IRAM; - info->SaveGameLen[1] = 128; - } -} - -static void Mapper210_StateRestore(int version) { - SyncPRG(); - FixCRR(); -} - -void Mapper210_Init(CartInfo *info) { - is210 = 1; - GameStateRestore = Mapper210_StateRestore; - info->Power = N106_Power; - FCEU_MemoryRand(WRAM, sizeof(WRAM)); - AddExState(WRAM, 8192, 0, "WRAM"); - AddExState(N106_StateRegs, ~0, 0, 0); -} diff --git a/src/boards/n625092.c b/src/boards/n625092.c deleted file mode 100644 index 8d5617b81..000000000 --- a/src/boards/n625092.c +++ /dev/null @@ -1,95 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2006 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 - * - * 700in1 and 400in1 carts - * 1000-in-1 - */ - -#include "mapinc.h" - -static uint16 cmd, bank; - -static SFORMAT StateRegs[] = -{ - { &cmd, 2, "CMD" }, - { &bank, 2, "BANK" }, - { 0 } -}; - -static void Sync(void) { - setmirror((cmd & 1) ^ 1); - setchr8(0); - if (cmd & 2) { - if (cmd & 0x100) { - setprg16(0x8000, ((cmd & 0x200) >> 3) | ((cmd & 0xfc) >> 2) | bank); - setprg16(0xC000, ((cmd & 0x200) >> 3) | ((cmd & 0xfc) >> 2) | 7); - } else { - setprg16(0x8000, ((cmd & 0x200) >> 3) | ((cmd & 0xfc) >> 2) | (bank & 6)); - setprg16(0xC000, ((cmd & 0x200) >> 3) | ((cmd & 0xfc) >> 2) | ((bank & 6) | 1)); - } - } else { - setprg16(0x8000, ((cmd & 0x200) >> 3) | ((cmd & 0xfc) >> 2) | bank); - setprg16(0xC000, ((cmd & 0x200) >> 3) | ((cmd & 0xfc) >> 2) | bank); - } -} - -static uint16 ass = 0; - -static DECLFW(UNLN625092WriteCommand) { - cmd = A; - if (A == 0x80F8) { - setprg16(0x8000, ass); - setprg16(0xC000, ass); - } else { - Sync(); - } -} - -static DECLFW(UNLN625092WriteBank) { - bank = A & 7; - Sync(); -} - -static void UNLN625092Power(void) { - cmd = 0; - bank = 0; - Sync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xBFFF, UNLN625092WriteCommand); - SetWriteHandler(0xC000, 0xFFFF, UNLN625092WriteBank); -} - -static void UNLN625092Reset(void) { - cmd = 0; - bank = 0; - ass++; - FCEU_printf("%04x\n", ass); - Sync(); -} - -static void StateRestore(int version) { - Sync(); -} - -void UNLN625092_Init(CartInfo *info) { - info->Reset = UNLN625092Reset; - info->Power = UNLN625092Power; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/sachen.c b/src/boards/sachen.c deleted file mode 100644 index 33600dfb7..000000000 --- a/src/boards/sachen.c +++ /dev/null @@ -1,337 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2002 Xodnizel - * Copyright (C) 2020 - * - * 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 - */ - -/* 2020-2-3 - updated mapper 150/243 */ - -#include "mapinc.h" - -static uint8 cmd, dip; -static uint8 latch[8]; -static uint8 mapperNum; - -static void S74LS374MSync(uint8 mirr) { - switch (mirr & 3) { - case 0: setmirror(MI_V); break; - case 1: setmirror(MI_H); break; - case 2: setmirrorw(0, 1, 1, 1); break; - case 3: setmirror(MI_0); break; - } -} - -static int type; -static void S8259Synco(void) { - int x; - setprg32(0x8000, latch[5] & 7); - - if (!UNIFchrrama) { /* No CHR RAM? Then BS'ing is ok. */ - for (x = 0; x < 4; x++) { - int bank; - if (latch[7] & 1) - bank = (latch[0] & 0x7) | ((latch[4] & 7) << 3); - else - bank = (latch[x] & 0x7) | ((latch[4] & 7) << 3); - switch (type) { - case 00: bank = (bank << 1) | (x & 1); setchr2(0x800 * x, bank); break; - case 01: setchr2(0x800 * x, bank); break; - case 02: bank = (bank << 2) | (x & 3); setchr2(0x800 * x, bank); break; - case 03: - bank = latch[x] & 7; - switch (x & 3) { - case 01: bank |= (latch[4] & 1) << 4; break; - case 02: bank |= (latch[4] & 2) << 3; break; - case 03: bank |= ((latch[4] & 4) << 2) | ((latch[6] & 1) << 3); break; - } - setchr1(0x400 * x, bank); - setchr4(0x1000, ~0); - break; - } - } - } - if (!(latch[7] & 1)) - S74LS374MSync(latch[7] >> 1); - else - setmirror(MI_V); -} - -static DECLFW(S8259Write) { - A &= 0x4101; - if (A == 0x4100) - cmd = V; - else { - latch[cmd & 7] = V; - S8259Synco(); - } -} - -static void S8259Reset(void) { - int x; - cmd = 0; - - for (x = 0; x < 8; x++) latch[x] = 0; - setchr8(0); - - S8259Synco(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x4100, 0x7FFF, S8259Write); -} - -static void S8259Restore(int version) { - S8259Synco(); -} - -void S8259A_Init(CartInfo *info) { /* Kevin's Horton 141 mapper */ - info->Power = S8259Reset; - GameStateRestore = S8259Restore; - AddExState(latch, 8, 0, "LATC"); - AddExState(&cmd, 1, 0, "CMD"); - type = 0; -} - -void S8259B_Init(CartInfo *info) { /* Kevin's Horton 138 mapper */ - info->Power = S8259Reset; - GameStateRestore = S8259Restore; - AddExState(latch, 8, 0, "LATC"); - AddExState(&cmd, 1, 0, "CMD"); - type = 1; -} - -void S8259C_Init(CartInfo *info) { /* Kevin's Horton 139 mapper */ - info->Power = S8259Reset; - GameStateRestore = S8259Restore; - AddExState(latch, 8, 0, "LATC"); - AddExState(&cmd, 1, 0, "CMD"); - type = 2; -} - -void S8259D_Init(CartInfo *info) { /* Kevin's Horton 137 mapper */ - info->Power = S8259Reset; - GameStateRestore = S8259Restore; - AddExState(latch, 8, 0, "LATC"); - AddExState(&cmd, 1, 0, "CMD"); - type = 3; -} - -static void (*WSync)(void); - -static DECLFW(SAWrite) { - if (A & 0x100) { - latch[0] = V; - WSync(); - } -} - -static void SAPower(void) { - latch[0] = 0; - WSync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x4100, 0x5FFF, SAWrite); -} - -static void SARestore(int version) { - WSync(); -} - -static DECLFW(SADWrite) { - latch[0] = V; - WSync(); -} - -static void SADPower(void) { - latch[0] = 0; - WSync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, SADWrite); -} - -static void SA0161MSynco(void) { - setprg32(0x8000, (latch[0] >> 3) & 1); - setchr8(latch[0] & 7); -} - -static void SA72007Synco(void) { - setprg32(0x8000, 0); - setchr8(latch[0] >> 7); -} - -static void SA009Synco(void) { - setprg32(0x8000, 0); - setchr8(latch[0] & 1); -} - -static void SA72008Synco(void) { - setprg32(0x8000, (latch[0] >> 2) & 1); - setchr8(latch[0] & 3); -} - -void SA72007_Init(CartInfo *info) { - WSync = SA72007Synco; - GameStateRestore = SARestore; - info->Power = SAPower; - AddExState(&latch[0], 1, 0, "LATC"); -} - -void SA72008_Init(CartInfo *info) { - WSync = SA72008Synco; - GameStateRestore = SARestore; - info->Power = SAPower; - AddExState(&latch[0], 1, 0, "LATC"); -} - -void SA009_Init(CartInfo *info) { - WSync = SA009Synco; - GameStateRestore = SARestore; - info->Power = SAPower; - AddExState(&latch[0], 1, 0, "LATC"); -} - -void SA0036_Init(CartInfo *info) { - WSync = SA72007Synco; - GameStateRestore = SARestore; - info->Power = SADPower; - AddExState(&latch[0], 1, 0, "LATC"); -} - -void SA0037_Init(CartInfo *info) { - WSync = SA0161MSynco; - GameStateRestore = SARestore; - info->Power = SADPower; - AddExState(&latch[0], 1, 0, "LATC"); -} - -/* --------------------------------------------- */ - -static DECLFR(TCA01Read) { - uint8 ret; - if ((A & 0x4100) == 0x4100) - ret = (X.DB & 0xC0) | ((~A) & 0x3F); - else - ret = X.DB; - return ret; -} - -static void TCA01Power(void) { - setprg16(0x8000, 0); - setprg16(0xC000, 1); - setchr8(0); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetReadHandler(0x4100, 0x5FFF, TCA01Read); -} - -void TCA01_Init(CartInfo *info) { - info->Power = TCA01Power; -} - -/* ------------------ Mapper 150 --------------------- */ -/* ------------------ Mapper 243 --------------------- */ - -/* Mapper 150 - SA-015 / SA-630 / Unif UNL-Sachen-74LS374N */ -/* Mapper 243 - SA-020A */ - -static void S74LS374NSynco(void) { - uint32 chrBank; - if (mapperNum == 150) - chrBank = (latch[6] & 3) | ((latch[4] << 2) & 4) | (latch[2] << 3); - else - chrBank = (latch[2] & 1) | ((latch[4] << 1) & 2) | (latch[6] << 2); - - setprg32(0x8000, (latch[2] & 1) | latch[5]); - setchr8(chrBank); - - switch ((latch[7] >> 1) & 3) { - case 0: setmirrorw(0, 1, 1, 1); break; - case 1: setmirror(MI_H); break; - case 2: setmirror(MI_V); break; - case 3: setmirror(MI_0); break; - } -} - -static DECLFR(S74LS374NRead) { - uint8 ret; - if ((A & 0xC101) == 0x4101) { - if (dip & 1) - ret = (latch[cmd] & 3) | (X.DB & 0xFC); - else - ret = (latch[cmd] & 7) | (X.DB & 0xF8); - } else { - ret = X.DB; - } - return ret; -} - -static DECLFW(S74LS374NWrite) { - if (dip & 1) - V |= 4; - switch (A & 0xC101) { - case 0x4100: - cmd = V & 7; - break; - case 0x4101: - latch[cmd] = V & 7; - S74LS374NSynco(); - break; - } -} - -static void S74LS374NRestore(int version) { - S74LS374NSynco(); -} - -static void S74LS374NReset(void) { - dip ^= 1; - latch[0] = latch[1] = latch[2] = latch[3] = 0; - latch[4] = latch[5] = latch[6] = latch[7] = 0; - S74LS374NSynco(); -} - -static void S74LS374NPower(void) { - dip = 0; - latch[0] = latch[1] = latch[2] = latch[3] = 0; - latch[4] = latch[5] = latch[6] = latch[7] = 0; - S74LS374NSynco(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x4100, 0x7FFF, S74LS374NWrite); - if (mapperNum == 150) - SetReadHandler(0x4100, 0x7FFF, S74LS374NRead); -} - -void S74LS374N_Init(CartInfo *info) { - mapperNum = info->mapper; - info->Power = S74LS374NPower; - info->Reset = S74LS374NReset; - GameStateRestore = S74LS374NRestore; - AddExState(latch, 8, 0, "LATC"); - AddExState(&cmd, 1, 0, "CMD"); -} - -static DECLFR(Mapper553Read) { - return 0x3A; -} - -static void Mapper553Power(void) { - setprg16(0xC000, 0); - setchr8(0); - SetReadHandler(0x8000, 0xBFFF, Mapper553Read); - SetReadHandler(0xC000, 0xFFFF, CartBR); -} - -void Mapper553_Init(CartInfo *info) { - info->Power = Mapper553Power; -} diff --git a/src/boards/sheroes.c b/src/boards/sheroes.c deleted file mode 100644 index fbcde4280..000000000 --- a/src/boards/sheroes.c +++ /dev/null @@ -1,80 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2006 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" - -static uint8 *CHRRAM; -static uint8 tekker; - -static void MSHCW(uint32 A, uint8 V) { - if (mmc3.expregs[0] & 0x40) - setchr8r(0x10, 0); - else { - if (A < 0x800) - setchr1(A, V | ((mmc3.expregs[0] & 8) << 5)); - else if (A < 0x1000) - setchr1(A, V | ((mmc3.expregs[0] & 4) << 6)); - else if (A < 0x1800) - setchr1(A, V | ((mmc3.expregs[0] & 1) << 8)); - else - setchr1(A, V | ((mmc3.expregs[0] & 2) << 7)); - } -} - -static DECLFW(MSHWrite) { - mmc3.expregs[0] = V; - FixMMC3CHR(mmc3.cmd); -} - -static DECLFR(MSHRead) { - return(tekker); -} - -static void MSHReset(void) { - MMC3RegReset(); - tekker ^= 0xFF; -} - -static void MSHPower(void) { - tekker = 0x00; - GenMMC3Power(); - SetWriteHandler(0x4100, 0x4100, MSHWrite); - SetReadHandler(0x4100, 0x4100, MSHRead); -} - -static void MSHClose(void) { - GenMMC3Close(); - if (CHRRAM) - FCEU_gfree(CHRRAM); - CHRRAM = NULL; -} - -void UNLSHeroes_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 512, 0, 0); - mmc3.cwrap = MSHCW; - info->Power = MSHPower; - info->Reset = MSHReset; - info->Close = MSHClose; - CHRRAM = (uint8*)FCEU_gmalloc(8192); - SetupCartCHRMapping(0x10, CHRRAM, 8192, 1); - AddExState(mmc3.expregs, 4, 0, "EXPR"); - AddExState(&tekker, 1, 0, "DIPSW"); -} diff --git a/src/boards/sl1632.c b/src/boards/sl1632.c deleted file mode 100644 index e931d46b7..000000000 --- a/src/boards/sl1632.c +++ /dev/null @@ -1,111 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2005 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 - * - * SL1632 2-in-1 protected board, similar to SL12 - * Samurai Spirits Rex (Full) - * - */ - -#include "mapinc.h" -#include "mmc3.h" - -static uint8 chrcmd[8], prg0, prg1, bbrk, mirr, swap; -static SFORMAT StateRegs[] = -{ - { chrcmd, 8, "CHRC" }, - { &prg0, 1, "PRG0" }, - { &prg1, 1, "PRG1" }, - { &bbrk, 1, "BRK" }, - { &mirr, 1, "MIRR" }, - { &swap, 1, "SWAP" }, - { 0 } -}; - -static void Sync(void) { - int i; - setprg8(0x8000, prg0); - setprg8(0xA000, prg1); - setprg8(0xC000, ~1); - setprg8(0xE000, ~0); - for (i = 0; i < 8; i++) - setchr1(i << 10, chrcmd[i]); - setmirror(mirr ^ 1); -} - -static void UNLSL1632CW(uint32 A, uint8 V) { - int cbase = (mmc3.cmd & 0x80) << 5; - int page0 = (bbrk & 0x08) << 5; - int page1 = (bbrk & 0x20) << 3; - int page2 = (bbrk & 0x80) << 1; - setchr1(cbase ^ 0x0000, page0 | (mmc3.regs[0] & (~1))); - setchr1(cbase ^ 0x0400, page0 | mmc3.regs[0] | 1); - setchr1(cbase ^ 0x0800, page0 | (mmc3.regs[1] & (~1))); - setchr1(cbase ^ 0x0C00, page0 | mmc3.regs[1] | 1); - setchr1(cbase ^ 0x1000, page1 | mmc3.regs[2]); - setchr1(cbase ^ 0x1400, page1 | mmc3.regs[3]); - setchr1(cbase ^ 0x1800, page2 | mmc3.regs[4]); - setchr1(cbase ^ 0x1c00, page2 | mmc3.regs[5]); -} - -static DECLFW(UNLSL1632CMDWrite) { - if (A == 0xA131) { - bbrk = V; - } - if (bbrk & 2) { - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - if (A < 0xC000) - MMC3_CMDWrite(A, V); - else - MMC3_IRQWrite(A, V); - } else { - if ((A >= 0xB000) && (A <= 0xE003)) { - int ind = ((((A & 2) | (A >> 10)) >> 1) + 2) & 7; - int sar = ((A & 1) << 2); - chrcmd[ind] = (chrcmd[ind] & (0xF0 >> sar)) | ((V & 0x0F) << sar); - } else - switch (A & 0xF003) { - case 0x8000: prg0 = V; break; - case 0xA000: prg1 = V; break; - case 0x9000: mirr = V & 1; break; - } - Sync(); - } -} - -static void StateRestore(int version) { - if (bbrk & 2) { - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } else - Sync(); -} - -static void UNLSL1632Power(void) { - GenMMC3Power(); - SetWriteHandler(0x4100, 0xFFFF, UNLSL1632CMDWrite); -} - -void UNLSL1632_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 512, 0, 0); - mmc3.cwrap = UNLSL1632CW; - info->Power = UNLSL1632Power; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/super40in1.c b/src/boards/super40in1.c deleted file mode 100644 index 4f841c772..000000000 --- a/src/boards/super40in1.c +++ /dev/null @@ -1,101 +0,0 @@ -/* FCEUmm - NES/Famicom Emulator - * - * Copyright (C) 2019 Libretro Team - * Copyright (C) 2023 - * - * 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 - * NES 2.0 Mapper 332 - * BMC-WS Used for Super 40-in-1 multicart - * https://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_332 */ - -#include "mapinc.h" -#include "latch.h" - -static uint8 preg, creg, dipSwitch; - -static SFORMAT StateRegs[] = -{ - { &preg, 1, "PREG" }, - { &creg, 1, "CREG" }, - { &dipSwitch, 1, "DPSW" }, - { 0 } -}; - -static void Sync(void) { - uint32 prg = (preg & 7) | ((preg >> 3) & 0x08); /* There is a high bit 3 of the PRG register that applies both to PRG and CHR */ - uint32 chr = (creg & 7) | ((preg >> 3) & 0x08); /* There is a high bit 3 of the PRG register that applies both to PRG and CHR */ - uint32 mask = (creg & 0x10)? 0: (creg & 0x20)? 1: 3; /* There is an CNROM mode that takes either two or four inner CHR banks from a CNROM-like latch.data register at $8000-$FFFF. */ - - if (preg & 8) { - setprg16(0x8000, prg); - setprg16(0xc000, prg); - } else - setprg32(0x8000, prg >> 1); - - setchr8((chr & ~mask) | (latch.data & mask)); /* This "inner CHR bank" substitutes the respective bit(s) of the creg register. */ - setmirror(((preg >> 4) & 1) ^ 1); -} - -static DECLFR(BMCWSRead) { - if ((creg >> 6) & (dipSwitch & 3)) - return X.DB; - return CartBR(A); -} - -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) { - preg = 0; - creg = 0; - dipSwitch = 0; - LatchPower(); - SetReadHandler(0x8000, 0xFFFF, BMCWSRead); - SetWriteHandler(0x6000, 0x7FFF, BMCWSWrite); -} - -static void BMCWSReset(void) { - dipSwitch++; /* Soft-resetting cycles through solder pad or DIP switch settings */ - if (dipSwitch == 3) - dipSwitch = 0; /* Only 00b, 01b and 10b settings are valid */ - - /* Always reset to menu */ - preg = 0; - creg = 0; - LatchHardReset(); -} - -void BMCWS_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); - info->Reset = BMCWSReset; - info->Power = MBMCWSPower; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/tengen.c b/src/boards/tengen.c deleted file mode 100644 index 5c7a6b096..000000000 --- a/src/boards/tengen.c +++ /dev/null @@ -1,187 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2002 Xodnizel - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* Mapper 64 - Tengen 800032 Rambo-1 - * Mapper 158 - Tengen 800037 (Alien Syndrome Unl) -*/ - -#include "mapinc.h" - -static uint8 cmd, mirr, regs[11]; -static uint8 rmode, IRQmode, IRQCount, IRQa, IRQLatch; -static uint8 M158PPUCHRBus; -static uint8 M158MIR[8]; -static uint8 mapper; - -static SFORMAT StateRegs[] = { - { regs, 11, "REGS" }, - { &cmd, 1, "CMDR" }, - { &mirr, 1, "MIRR" }, - { &rmode, 1, "RMOD" }, - { &IRQmode, 1, "IRQM" }, - { &IRQCount, 1, "IRQC" }, - { &IRQa, 1, "IRQA" }, - { &IRQLatch, 1, "IRQL" }, - { 0 } -}; - -static void cwrap(uint32 A, uint8 V) { - setchr1(A, V); - if (mapper == 158) { - M158MIR[A >> 10] = (V >> 7) & 1; - if (M158PPUCHRBus == (A >> 10)) { - setmirror(MI_0 + ((V >> 7) & 1)); - } - } -} - -static void Sync(void) { - if (cmd & 0x20) { - cwrap(0x0000, regs[0]); - cwrap(0x0400, regs[8]); - cwrap(0x0800, regs[1]); - cwrap(0x0C00, regs[9]); - } else { - cwrap(0x0000, (regs[0] & 0xFE)); - cwrap(0x0400, (regs[0] & 0xFE) | 1); - cwrap(0x0800, (regs[1] & 0xFE)); - cwrap(0x0C00, (regs[1] & 0xFE) | 1); - } - cwrap(0x1000, regs[2]); - cwrap(0x1400, regs[3]); - cwrap(0x1800, regs[4]); - cwrap(0x1C00, regs[5]); - - setprg8(0x8000, regs[6]); - setprg8(0xA000, regs[7]); - setprg8(0xC000, regs[10]); - setprg8(0xE000, ~0); - - if (mapper != 158) { - setmirror(mirr); - } -} - -static DECLFW(RAMBO1_Write) { - switch (A & 0xF001) { - case 0xA000: - mirr = (V & 1) ^ 1; - Sync(); - break; - case 0x8000: cmd = V; break; - case 0x8001: - if ((cmd & 0xF) < 10) - regs[cmd & 0xF] = V; - else if ((cmd & 0xF) == 0xF) - regs[10] = V; - Sync(); - break; - case 0xC000: - IRQLatch = V; - if (rmode == 1) - IRQCount = IRQLatch; - break; - case 0xC001: - rmode = 1; - IRQCount = IRQLatch; - IRQmode = V & 1; - break; - case 0xE000: - IRQa = 0; - X6502_IRQEnd(FCEU_IQEXT); - if (rmode == 1) - IRQCount = IRQLatch; - break; - case 0xE001: - IRQa = 1; - if (rmode == 1) - IRQCount = IRQLatch; - break; - } -} - -static void RAMBO1Power(void) { - cmd = mirr = 0; - regs[0] = regs[1] = regs[2] = regs[3] = regs[4] = regs[5] = ~0; - regs[6] = regs[7] = regs[8] = regs[9] = regs[10] = ~0; - Sync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, RAMBO1_Write); -} - -static void StateRestore(int version) { - Sync(); -} - -static void FP_FASTAPASS(1) RAMBO1IRQHook(int a) { - static int32 smallcount; - if (IRQmode) { - smallcount += a; - while (smallcount >= 4) { - smallcount -= 4; - IRQCount--; - if (IRQCount == 0xFF) - if (IRQa) X6502_IRQBegin(FCEU_IQEXT); - } - } -} - -static void RAMBO1HBHook(void) { - if ((!IRQmode) && (scanline != 240)) { - rmode = 0; - IRQCount--; - if (IRQCount == 0xFF) { - if (IRQa) { - rmode = 1; - X6502_IRQBegin(FCEU_IQEXT); - } - } - } -} - -static void RAMBO1_Init(CartInfo *info) { - mapper = info->mapper; - info->Power = RAMBO1Power; - GameHBIRQHook = RAMBO1HBHook; - MapIRQHook = RAMBO1IRQHook; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} - -/* Mapper 64 */ - -void Mapper64_Init(CartInfo *info) { - RAMBO1_Init(info); -} - -/* Mapper 158 - Alien Syndrome */ - -static void FP_FASTAPASS(1) M158PPU(uint32 A) { - A &= 0x1FFF; - A >>= 10; - M158PPUCHRBus = A; - setmirror(MI_0 + M158MIR[A]); -} - -void Mapper158_Init(CartInfo *info) { - RAMBO1_Init(info); - PPU_hook = M158PPU; - AddExState(&M158PPUCHRBus, 1, 0, "PPUC"); -} diff --git a/src/boards/txcchip.c b/src/boards/txcchip.c deleted file mode 100644 index a45c89e66..000000000 --- a/src/boards/txcchip.c +++ /dev/null @@ -1,393 +0,0 @@ -/* FCEUmm - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2012 CaH4e3 - * Copyright (C) 2019 Libretro Team - * Copyright (C) 2020 - * - * 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 - * - * 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) - * - * TXC mappers, originally much complex banksitching - * - * 01-22111-000 (05-00002-010) (132, 22211) - MGC-001 Qi Wang - * 01-22110-000 (52S ) - MGC-002 2-in-1 Gun - * 01-22111-100 (02-00002-010) (173 ) - MGC-008 Mahjong Block - * (079 ) - MGC-012 Poke Block - * 01-22110-200 (05-00002-010) (036 ) - MGC-014 Strike Wolf - * 01-22000-400 (05-00002-010) (036 ) - MGC-015 Policeman - * 01-22017-000 (05-PT017-080) (189 ) - MGC-017 Thunder Warrior - * 01-11160-000 (04-02310-000) ( , 11160) - MGC-023 6-in-1 - * 01-22270-000 (05-00002-010) (132, 22211) - MGC-xxx Creatom - * 01-22200-400 (------------) (079 ) - ET.03 F-15 City War - * (172 ) - 1991 Du Ma Racing - * - */ - -/* added 2020-2-16 - * Updated based on latest source - * Mappers 36, 132, 173 - * Mappers 136, 147, 172 - */ - -#include "mapinc.h" - -typedef struct { - uint8 mask; - uint8 isJV001; - uint8 accumulator; - uint8 inverter; - uint8 staging; - uint8 output; - uint8 increase; - uint8 Y; - uint8 invert; -} TXC; - -static TXC txc; - -static void Dummyfunc(void) { } -static void (*WSync)(void) = Dummyfunc; - -static void UNL22211_Init(CartInfo *info); - -static SFORMAT StateRegs[] = -{ - { &txc.accumulator, 1, "ACC0" }, - { &txc.inverter, 1, "INVR" }, - { &txc.staging, 1, "STG0" }, - { &txc.output, 1, "OUT0" }, - { &txc.increase, 1, "INC0" }, - { &txc.Y, 1, "YFLG" }, - { &txc.invert, 1, "INVT" }, - { 0 } -}; - -static uint8 TXC_CMDRead(void) { - uint8 ret = ((txc.accumulator & txc.mask) | ((txc.inverter ^ txc.invert) & ~txc.mask)); - txc.Y = !txc.invert || ((ret & 0x10) != 0); - WSync(); - return ret; -} - -static DECLFW(TXC_CMDWrite) { - if (A & 0x8000) { - if (txc.isJV001) - txc.output = (txc.accumulator & 0x0F) | (txc.inverter & 0xF0); - else - txc.output = (txc.accumulator & 0x0F) | ((txc.inverter << 1) & 0x10); - } else { - switch (A & 0x103) { - case 0x100: - if (txc.increase) - txc.accumulator++; - else - txc.accumulator = ((txc.accumulator & ~txc.mask) | ((txc.staging ^ txc.invert) & txc.mask)); - break; - case 0x101: - txc.invert = (V & 0x01) ? 0xFF : 0x00; - break; - case 0x102: - txc.staging = V & txc.mask; - txc.inverter = V & ~txc.mask; - break; - case 0x103: - txc.increase = ((V & 0x01) != 0); - break; - } - } - txc.Y = !txc.invert || ((V & 0x10) != 0); - WSync(); -} - -static void TXCRegReset(void) { - txc.output = 0; - txc.accumulator = 0; - txc.inverter = 0; - txc.staging = 0; - txc.increase = 0; - txc.Y = 0; - txc.mask = txc.isJV001 ? 0x0F : 0x07; - txc.invert = txc.isJV001 ? 0xFF : 0x00; - - WSync(); -} - -static void GenTXCPower(void) { - TXCRegReset(); -} - -static void StateRestore(int version) { - WSync(); -} - -static void GenTXC_Init(CartInfo *info, void (*proc)(void), uint32 jv001) { - txc.isJV001 = jv001; - WSync = proc; - GameStateRestore = StateRestore; - AddExState(StateRegs, ~0, 0, 0); -} - -static int CheckHash(CartInfo *info) { - int x = 0; - uint64 partialmd5 = 0; - - /* These carts do not work with new mapper implementation. - * This is a hack to use previous mapper implementation for such carts. */ - for (x = 0; x < 8; x++) - partialmd5 |= (uint64)info->MD5[15 - x] << (x * 8); - switch (partialmd5) { - case 0x2dd8f958850f21f4LL: /* Jin Gwok Sei Chuen Saang (Ch) [U][!] */ - FCEU_printf(" WARNING: Using alternate mapper implementation.\n"); - UNL22211_Init(info); - return 1; - } - if (info->CRC32 == 0x2A5F4C5A) { - FCEU_printf(" WARNING: Using alternate mapper implementation.\n"); - return 1; - } - return 0; -} - -/* --------------- Mapper 36 --------------- */ - -static uint8 creg = 0; - -static void M36Sync(void) { - setprg32(0x8000, txc.output & 0x03); - setchr8(creg & 0x0F); -} - -static DECLFW(M36Write) { - if ((A & 0xF200) == 0x4200) creg = V; - TXC_CMDWrite(A, (V >> 4) & 0x03); -} - -static DECLFR(M36Read) { - uint8 ret = X.DB; - if ((A & 0x103) == 0x100) - ret = (X.DB & 0xCF) | ((TXC_CMDRead() << 4) & 0x30); - return ret; -} - -static void M36Power(void) { - creg = 0; - GenTXCPower(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetReadHandler(0x4100, 0x5FFF, M36Read); - SetWriteHandler(0x4100, 0xFFFF, M36Write); -} - -void Mapper36_Init(CartInfo *info) { - GenTXC_Init(info, M36Sync, 0); - info->Power = M36Power; - AddExState(&creg, 1, 0, "CREG"); -} - -/* --------------- Mapper 132 --------------- */ - -static void M132Sync(void) { - setprg32(0x8000, (txc.output >> 2) & 0x01); - setchr8(txc.output & 0x03); -} - -static DECLFW(M132Write) { - TXC_CMDWrite(A, V & 0x0F); -} - -static DECLFR(M132Read) { - uint8 ret = X.DB; - if ((A & 0x103) == 0x100) - ret = ((X.DB & 0xF0) | (TXC_CMDRead() & 0x0F)); - return ret; -} - -static void M132Power(void) { - GenTXCPower(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetReadHandler(0x4100, 0x5FFF, M132Read); - SetWriteHandler(0x4100, 0xFFFF, M132Write); -} - -void Mapper132_Init(CartInfo *info) { - if (CheckHash(info) != 0) return; - GenTXC_Init(info, M132Sync, 0); - info->Power = M132Power; -} - -/* --------------- Mapper 173 --------------- */ - -static void M173Sync(void) { - setprg32(0x8000, 0); - if (CHRsize[0] > 0x2000) - setchr8(((txc.output & 0x01) | (txc.Y ? 0x02 : 0x00) | ((txc.output & 2) << 0x01))); - else - setchr8(0); -} - -void Mapper173_Init(CartInfo *info) { - GenTXC_Init(info, M173Sync, 0); - info->Power = M132Power; -} - -/* ---------------- Joy/Van ----------------- */ - -/* --------------- Mapper 136 --------------- */ - -static void M136Sync(void) { - setprg32(0x8000, (txc.output >> 4) & 0x01); - setchr8(txc.output & 0x07); -} - -static DECLFW(M136Write) { - TXC_CMDWrite(A, V & 0x3F); -} - -static DECLFR(M136Read) { - uint8 ret = X.DB; - if ((A & 0x103) == 0x100) - ret = ((X.DB & 0xC0) | (TXC_CMDRead() & 0x3F)); - return ret; -} - -static void M136Power(void) { - GenTXCPower(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetReadHandler(0x4100, 0x5FFF, M136Read); - SetWriteHandler(0x4100, 0xFFFF, M136Write); -} - -void Mapper136_Init(CartInfo *info) { - GenTXC_Init(info, M136Sync, 1); - info->Power = M136Power; -} - -/* --------------- Mapper 147 --------------- */ - -static void M147Sync(void) { - setprg32(0x8000, ((txc.output >> 4) & 0x02) | (txc.output & 0x01)); - setchr8((txc.output >> 1) & 0x0F); -} - -static DECLFW(M147Write) { - TXC_CMDWrite(A, ((V >> 2) & 0x3F) | ((V << 6) & 0xC0)); -} - -static DECLFR(M147Read) { - uint8 ret = X.DB; - if ((A & 0x103) == 0x100) { - uint8 value = TXC_CMDRead(); - ret = ((value << 2) & 0xFC) | ((value >> 6) & 0x03); - } - return ret; -} - -static void M147Power(void) { - GenTXCPower(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetReadHandler(0x4100, 0x5FFF, M147Read); - SetWriteHandler(0x4100, 0xFFFF, M147Write); -} - -void Mapper147_Init(CartInfo *info) { - GenTXC_Init(info, M147Sync, 1); - info->Power = M147Power; -} - -/* --------------- Mapper 172 --------------- */ - -static void M172Sync(void) { - setprg32(0x8000, 0); - setchr8(txc.output); - setmirror(txc.invert ? 1 : 0); -} - -static uint8 GetValue(uint8 value) { - return (((value << 5) & 0x20) | ((value << 3) & 0x10) | ((value << 1) & 0x08) | - ((value >> 1) & 0x04) | ((value >> 3) & 0x02) | ((value >> 5) & 0x01)); -} - -static DECLFW(M172Write) { - TXC_CMDWrite(A, GetValue(V)); -} - -static DECLFR(M172Read) { - uint8 ret = X.DB; - if ((A & 0x103) == 0x100) - ret = (X.DB & 0xC0) | GetValue(TXC_CMDRead()); - return ret; -} - -static void M172Power(void) { - GenTXCPower(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetReadHandler(0x4100, 0x5FFF, M172Read); - SetWriteHandler(0x4100, 0xFFFF, M172Write); -} - -void Mapper172_Init(CartInfo *info) { - GenTXC_Init(info, M172Sync, 1); - info->Power = M172Power; -} - -/* === LEGACY MAPPER IMPLEMENTATION === */ - -static uint8 reg[4]; - -static SFORMAT UNL22211StateRegs[] = -{ - { reg, 4, "REGS" }, - { 0 } -}; - -static void UNL22211Sync(void) { - setprg32(0x8000, (reg[2] >> 2) & 1); - setchr8(reg[2] & 3); -} - -static DECLFW(UNL22211WriteLo) { - if (A & 0x100) { - reg[A & 3] = V; - UNL22211Sync(); - } -} - -static DECLFR(UNL22211ReadLo) { - return ((reg[1] ^ reg[2]) | 0x40); -} - -static void UNL22211Power(void) { - UNL22211Sync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetReadHandler(0x4100, 0x4100, UNL22211ReadLo); - SetWriteHandler(0x4100, 0x4FFF, UNL22211WriteLo); -} - -static void UNL22211StateRestore(int version) { - UNL22211Sync(); -} - -static void UNL22211_Init(CartInfo *info) { - info->Power = UNL22211Power; - GameStateRestore = UNL22211StateRestore; - AddExState(&UNL22211StateRegs, ~0, 0, 0); -} diff --git a/src/boards/unrom512.c b/src/boards/unrom512.c deleted file mode 100644 index 69612e8e2..000000000 --- a/src/boards/unrom512.c +++ /dev/null @@ -1,210 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2014 CaitSith2, 2022 Cluster - * - * 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 - */ - -/* - * Roms still using NES 1.0 format should be loaded as 8K CHR RAM. - * Roms defined under NES 2.0 should use the VRAM size field, defining 7, 8 or 9, based on how much VRAM should be - * present. UNIF doesn't have this problem, because unique board names can define this information. The UNIF names are - * UNROM-512-8K, UNROM-512-16K and UNROM-512-32K - * - * The battery flag in the NES header enables flash, Mirrror mode 2 Enables MI_0 and MI_1 mode. - * Known games to use this board are: - * Battle Kid 2: Mountain of Torment (512K PRG, 8K CHR RAM, Horizontal Mirroring, Flash disabled) - * Study Hall (128K PRG (in 512K flash chip), 8K CHR RAM, Horizontal Mirroring, Flash enabled) - * Nix: The Paradox Relic (512 PRG, 8K CHR RAM, Vertical Mirroring, Flash enabled) - * Although Xmas 2013 uses a different board, where LEDs can be controlled (with writes to the $8000-BFFF space), - * it otherwise functions identically. - */ - -#include "mapinc.h" -#include "latch.h" - -#define ROM_CHIP 0x00 -#define CFI_CHIP 0x10 -#define FLASH_CHIP 0x11 -#define FLASH_SECTOR_SIZE (4 * 1024) - -static uint8 flash_save, flash_state, flash_id_mode; -static uint8 *flash_data; -static uint16 flash_buffer_a[10]; -static uint8 flash_buffer_v[10]; -static uint8 flash_id[2]; -static uint8 submapper; - -static void UNROM512_Sync() { - int chip; - if (flash_save) { - chip = !flash_id_mode ? FLASH_CHIP : CFI_CHIP; - } else { - chip = ROM_CHIP; - } - setprg16r(chip, 0x8000, latch.data & 0x1F); - setprg16r(chip, 0xc000, ~0); - setchr8((latch.data >> 5) & 3); - switch (submapper) { - case 1: - /* Mega Man II (30th Anniversary Edition) */ - setmirror((latch.data >> 7) & 1); - break; - default: - setmirror(MI_0 + ((latch.data >> 7) & 1)); - break; - } -} - -static void StateRestore(int version) { - UNROM512_Sync(); -} - -static DECLFW(UNROM512FlashWrite) { - int i, offset, sector; - if (flash_state < sizeof(flash_buffer_a) / sizeof(flash_buffer_a[0])) { - flash_buffer_a[flash_state] = (A & 0x3FFF) | ((latch.data & 1) << 14); - flash_buffer_v[flash_state] = V; - flash_state++; - - /* enter flash ID mode */ - if ((flash_state == 2) && (flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) && - (flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) && (flash_buffer_a[1] == 0x5555) && - (flash_buffer_v[1] == 0x90)) { - flash_id_mode = 0; - flash_state = 0; - } - - /* erase sector */ - if ((flash_state == 6) && (flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) && - (flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) && (flash_buffer_a[2] == 0x5555) && - (flash_buffer_v[2] == 0x80) && (flash_buffer_a[3] == 0x5555) && (flash_buffer_v[3] == 0xAA) && - (flash_buffer_a[4] == 0x2AAA) && (flash_buffer_v[4] == 0x55) && (flash_buffer_v[5] == 0x30)) { - offset = &Page[A >> 11][A] - flash_data; - sector = offset / FLASH_SECTOR_SIZE; - for (i = sector * FLASH_SECTOR_SIZE; i < (sector + 1) * FLASH_SECTOR_SIZE; i++) { - flash_data[i % PRGsize[ROM_CHIP]] = 0xFF; - } - FCEU_printf("Flash sector #%d is erased (0x%08x - 0x%08x).\n", sector, offset, offset + FLASH_SECTOR_SIZE); - } - - /* erase chip */ - if ((flash_state == 6) && (flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) && - (flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) && (flash_buffer_a[2] == 0x5555) && - (flash_buffer_v[2] == 0x80) && (flash_buffer_a[3] == 0x5555) && (flash_buffer_v[3] == 0xAA) && - (flash_buffer_a[4] == 0x2AAA) && (flash_buffer_v[4] == 0x55) && (flash_buffer_a[4] == 0x5555) && - (flash_buffer_v[4] == 0x10)) { - memset(flash_data, 0xFF, PRGsize[ROM_CHIP]); - FCEU_printf("Flash chip erased.\n"); - flash_state = 0; - } - - /* write byte */ - if ((flash_state == 4) && (flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) && - (flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) && (flash_buffer_a[2] == 0x5555) && - (flash_buffer_v[2] == 0xA0)) { - offset = &Page[A >> 11][A] - flash_data; - if (CartBR(A) != 0xFF) { - FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased.\n", offset); - } else { - CartBW(A, V); - } - flash_state = 0; - } - } - - /* not a command */ - if (((A & 0xFFF) != 0x0AAA) && ((A & 0xFFF) != 0x0555)) { - flash_state = 0; - } - - /* reset */ - if (V == 0xF0) { - flash_state = 0; - flash_id_mode = 0; - } - - UNROM512_Sync(); -} - -static void UNROM512LatchPower(void) { - LatchPower(); - if (flash_save) { - SetWriteHandler(0x8000, 0xBFFF, UNROM512FlashWrite); - } -} - -static void UNROM512LatchClose(void) { - LatchClose(); - if (flash_data) { - FCEU_gfree(flash_data); - } - flash_data = NULL; -} - -void UNROM512_Init(CartInfo *info) { - Latch_Init(info, UNROM512_Sync, NULL, 0, !info->battery); - - info->Power = UNROM512LatchPower; - info->Close = UNROM512LatchClose; - GameStateRestore = StateRestore; - - submapper = (info->iNES2 && info->submapper) ? info->submapper : ((info->PRGCRC32 == 0x891C14BC) ? 0x01 : 0x00); - - if (!(submapper & 1)) { - switch (info->mirror2bits) { - case 0: /* hard horizontal, internal */ - SetupCartMirroring(MI_H, 1, NULL); - break; - case 1: /* hard vertical, internal */ - SetupCartMirroring(MI_V, 1, NULL); - break; - case 2: /* switchable 1-screen, internal (flags: 4-screen + horizontal) */ - 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->CHRRamSize - 8192)); - break; - } - } - - flash_state = 0; - flash_id_mode = 0; - flash_save = info->battery; - - if (flash_save) { - uint32 i; - /* Allocate memory for flash */ - flash_data = (uint8 *)FCEU_gmalloc(PRGsize[ROM_CHIP]); - /* Copy ROM to flash data */ - for (i = 0; i < PRGsize[ROM_CHIP]; i++) { - flash_data[i] = PRGptr[ROM_CHIP][i % PRGsize[ROM_CHIP]]; - } - SetupCartPRGMapping(FLASH_CHIP, flash_data, PRGsize[ROM_CHIP], 1); - info->SaveGame[0] = flash_data; - info->SaveGameLen[0] = PRGsize[ROM_CHIP]; - - flash_id[0] = 0xBF; - flash_id[1] = 0xB5 + (ROM_size >> 4); - SetupCartPRGMapping(CFI_CHIP, flash_id, sizeof(flash_id), 0); - - AddExState(flash_data, PRGsize[ROM_CHIP], 0, "FLSH"); - AddExState(&flash_state, 1, 0, "FLST"); - AddExState(&flash_id_mode, 1, 0, "FLMD"); - AddExState(flash_buffer_a, sizeof(flash_buffer_a), 0, "FLBA"); - AddExState(flash_buffer_v, sizeof(flash_buffer_v), 0, "FLBV"); - } -} diff --git a/src/boards/vrc24.h b/src/boards/vrc24.h deleted file mode 100644 index 5247e00fc..000000000 --- a/src/boards/vrc24.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _VRC24_H -#define _VRC24_H - -typedef enum { - VRC2a = 1, /* Mapper 22 */ - VRC2b, /* Mapper 23 */ - VRC2c, /* Mapper 25 */ - VRC4a, /* Mapper 21 */ - VRC4b, /* Mapper 25 */ - VRC4c, /* Mapper 21 */ - VRC4d, /* Mapper 25 */ - VRC4e, /* Mapper 23 */ - VRC4f, /* Mapper 23 */ - VRC4_544, - VRC4_559, -} VRC24Type; - -typedef struct { - uint8 prgreg[2]; - uint8 chrreg[8]; - uint8 chrhi[8]; - uint8 cmd; - uint8 mirr; - - void (*pwrap)(uint32 A, uint8 V); - void (*cwrap)(uint32 A, uint32 V); - void (*mwrap)(uint8 V); -} VRC24; - -extern VRC24 vrc24; - -void GenVRC24Power(void); -void GenVRC24Close(void); -void GenVRC24Restore(int version); -void FixVRC24PRG(void); -void FixVRC24CHR(void); -DECLFW(VRC24Write); - -void GenVRC24_Init(CartInfo *info, VRC24Type type, int wram); - -#endif /* _VRC24_H */ diff --git a/src/boards/vrc2and4.c b/src/boards/vrc2and4.c deleted file mode 100644 index 64a98284a..000000000 --- a/src/boards/vrc2and4.c +++ /dev/null @@ -1,389 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2007 CaH4e3 - * Copyright (C) 2023 - * - * 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 - * - * VRC-2/VRC-4 Konami - * VRC-4 Pirate - * - * VRC2 - * Nickname PCB A0 A1 Registers iNES mapper submapper - * VRC2a 351618 A1 A0 $x000, $x002, $x001, $x003 22 0 - * VRC2b many† A0 A1 $x000, $x001, $x002, $x003 23 3 - * VRC2c 351948 A1 A0 $x000, $x002, $x001, $x003 25 3 - * VRC4 - * Nickname PCB A0 A1 Registers iNES mapper submapper - * VRC4a 352398 A1 A2 $x000, $x002, $x004, $x006 21 1 - * VRC4b 351406 A1 A0 $x000, $x002, $x001, $x003 25 1 - * VRC4c 352889 A6 A7 $x000, $x040, $x080, $x0C0 21 2 - * VRC4d 352400 A3 A2 $x000, $x008, $x004, $x00C 25 2 - * VRC4e 352396 A2 A3 $x000, $x004, $x008, $x00C 23 2 - * VRC4f - A0 A1 $x000, $x001, $x002, $x003 23 1 - * - */ - -#include "mapinc.h" -#include "vrc24.h" -#include "vrcirq.h" - -static VRC24Type variant; -static uint8 autoConfig = 0; - -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; - -VRC24 vrc24; - -static SFORMAT StateRegs[] = -{ - { vrc24.prgreg, 2, "PREG" }, - { vrc24.chrreg, 8, "CREG" }, - { vrc24.chrhi, 8, "CHRH" }, - { &vrc24.cmd, 1, "CMDR" }, - { &vrc24.mirr, 1, "MIRR" }, - { &variant, 1, "VRNT" }, - - { 0 } -}; - -static uint32 translateAddr(uint32 A) { - uint8 A0 = 0; - uint8 A1 = 0; - - if (autoConfig) { - switch (variant) { - /* 21 */ - case VRC4a: - case VRC4c: - A0 = (A >> 1) & 0x01; - A1 = (A >> 2) & 0x01; - - A0 |= (A >> 6) & 0x01; - A1 |= (A >> 7) & 0x01; - break; - - /* 23 */ - case VRC2b: - case VRC4f: - case VRC4e: - A0 = (A >> 0) & 0x01; - A1 = (A >> 1) & 0x01; - - A0 |= (A >> 2) & 0x01; - A1 |= (A >> 3) & 0x01; - break; - - /* 25 */ - case VRC2c: - case VRC4b: - case VRC4d: - A0 = (A >> 1) & 0x01; - A1 = (A >> 0) & 0x01; - - A0 |= (A >> 3) & 0x01; - A1 |= (A >> 2) & 0x01; - break; - - default: - break; - } - } else { - switch (variant) { - /* 21 */ - case VRC4a: - A0 = (A >> 1) & 0x01; - A1 = (A >> 2) & 0x01; - break; - - case VRC4c: - A0 = (A >> 6) & 0x01; - A1 = (A >> 7) & 0x01; - break; - - /* 22 */ - case VRC2a: - A0 = (A >> 1) & 0x01; - A1 = (A >> 0) & 0x01; - break; - - /* 23 */ - case VRC2b: - case VRC4f: - A0 = (A >> 0) & 0x01; - A1 = (A >> 1) & 0x01; - break; - - case VRC4e: - A0 |= (A >> 2) & 0x01; - A1 |= (A >> 3) & 0x01; - break; - - /* 25 */ - case VRC2c: - case VRC4b: - A0 = (A >> 1) & 0x01; - A1 = (A >> 0) & 0x01; - break; - - case VRC4d: - A0 |= (A >> 3) & 0x01; - A1 |= (A >> 2) & 0x01; - break; - - case VRC4_544: - case VRC4_559: - A0 |= (A >> 10) & 0x01; - A1 |= (A >> 11) & 0x01; - break; - - default: - break; - } - } - - return (A & 0xF000) | (A1 << 1) | (A0 << 0); -} - -void FixVRC24PRG(void) { - if (vrc24.cmd & 2) { - vrc24.pwrap(0x8000, ~1); - vrc24.pwrap(0xC000, vrc24.prgreg[0]); - } else { - vrc24.pwrap(0x8000, vrc24.prgreg[0]); - vrc24.pwrap(0xC000, ~1); - } - vrc24.pwrap(0xA000, vrc24.prgreg[1]); - vrc24.pwrap(0xE000, ~0); -} - -void FixVRC24CHR(void) { - int i; - - for (i = 0; i < 8; i++) { - vrc24.cwrap(0x0400 * i, (vrc24.chrhi[i] << 4) | vrc24.chrreg[i]); - } - if (vrc24.mwrap) { - vrc24.mwrap(vrc24.mirr); - } -} - -DECLFW(VRC24Write) { - uint8 index; - - A = translateAddr(A) & 0xF003; - - switch (A & 0xF000) { - case 0x8000: - case 0xA000: - vrc24.prgreg[(A >> 13) & 0x01] = V & 0x1F; - FixVRC24PRG(); - break; - - case 0x9000: - switch (A & 0x03) { - case 0: - case 1: - if (V != 0xFF) { - if (vrc24.mwrap) { - vrc24.mwrap(V); - } - } - break; - case 2: - case 3: - vrc24.cmd = V; - FixVRC24PRG(); - break; - } - break; - - case 0xF000: - switch (A & 0x03) { - case 0x00: VRCIRQ_LatchNibble(V, 0); break; - case 0x01: VRCIRQ_LatchNibble(V, 1); break; - case 0x02: VRCIRQ_Control(V); break; - case 0x03: VRCIRQ_Acknowledge(); break; - } - break; - - default: - index = ((A >> 1) & 0x01) | ((A - 0xB000) >> 11); - if (A & 0x01) { - /* m25 can be 512K, rest are 256K or less */ - vrc24.chrhi[index] = V & 0x1F; - } else { - vrc24.chrreg[index] = V & 0xF; - } - vrc24.cwrap(index << 10, ((vrc24.chrhi[index] << 4) | vrc24.chrreg[index])); - break; - } -} - -static void GENPWRAP(uint32 A, uint8 V) { - setprg8(A, V & 0x1F); -} - -static void GENCWRAP(uint32 A, uint32 V) { - setchr1(A, V & 0x1FF); -} - -static void GENMWRAP(uint8 V) { - vrc24.mirr = V; - - switch (V & 0x3) { - case 0: setmirror(MI_V); break; - case 1: setmirror(MI_H); break; - case 2: setmirror(MI_0); break; - case 3: setmirror(MI_1); break; - } -} - -void GenVRC24Power(void) { - vrc24.prgreg[0] = 0; - vrc24.prgreg[1] = 1; - - vrc24.chrreg[0] = 0; - vrc24.chrreg[1] = 1; - vrc24.chrreg[2] = 2; - vrc24.chrreg[3] = 3; - vrc24.chrreg[4] = 4; - vrc24.chrreg[5] = 5; - vrc24.chrreg[6] = 6; - vrc24.chrreg[7] = 7; - - vrc24.chrhi[0] = vrc24.chrhi[1] = vrc24.chrhi[2] = vrc24.chrhi[3] = 0; - vrc24.chrhi[4] = vrc24.chrhi[5] = vrc24.chrhi[6] = vrc24.chrhi[7] = 0; - - vrc24.cmd = vrc24.mirr = 0; - - FixVRC24PRG(); - FixVRC24CHR(); - - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, VRC24Write); - - if (WRAMSIZE) { - setprg8r(0x10, 0x6000, 0); - SetReadHandler(0x6000, 0x7FFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); - } - - if (UNIFchrrama) { - setchr8(0); - } -} - -void GenVRC24Restore(int version) { - FixVRC24PRG(); - FixVRC24CHR(); -} - -void GenVRC24Close(void) { - if (WRAM) { - FCEU_gfree(WRAM); - } - WRAM = NULL; -} - -void GenVRC24_Init(CartInfo *info, VRC24Type type, int wram) { - vrc24.pwrap = GENPWRAP; - vrc24.cwrap = GENCWRAP; - vrc24.mwrap = GENMWRAP; - - WRAMSIZE = wram ? 8192 : 0; - variant = type; - - if (wram) { - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - - if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; - } - } - - AddExState(&StateRegs, ~0, 0, 0); - - info->Power = GenVRC24Power; - info->Close = GenVRC24Close; - GameStateRestore = GenVRC24Restore; - - VRCIRQ_Init(); -} - -/* -------------------- Mapper 21 -------------------- */ - -void Mapper21_Init(CartInfo *info) { - /* Mapper 21 - VRC4a, VRC4c */ - VRC24Type type = VRC4a; - if (info->iNES2 && info->submapper) { - switch (info->submapper) { - case 1: type = VRC4a; break; - case 2: type = VRC4c; break; - } - } - autoConfig = !info->submapper; - GenVRC24_Init(info, type, 1); -} - -/* -------------------- Mapper 22 -------------------- */ - -static void M22CW(uint32 A, uint32 V) { - setchr1(A, V >> 1); -} - -void Mapper22_Init(CartInfo *info) { - /* Mapper 22 - VRC2a */ - GenVRC24_Init(info, VRC2a, 0); - vrc24.cwrap = M22CW; -} - -/* -------------------- Mapper 23 -------------------- */ - -void Mapper23_Init(CartInfo *info) { - /* Mapper 23 - VRC2b, VRC4e, VRC4f */ - VRC24Type type = VRC4f; - if (info->iNES2 && info->submapper) { - switch (info->submapper) { - case 1: type = VRC4f; break; - case 2: type = VRC4e; break; - case 3: type = VRC2b; break; - } - } - autoConfig = !info->submapper; - GenVRC24_Init(info, type, 1); -} - -/* -------------------- Mapper 25 -------------------- */ - -void Mapper25_Init(CartInfo *info) { - /* Mapper 25 - VRC2c, VRC4b, VRC4d */ - VRC24Type type = VRC4b; - if (info->iNES2 && info->submapper) { - switch (info->submapper) { - case 1: type = VRC4b; break; - case 2: type = VRC4d; break; - case 3: type = VRC2c; break; - } - } - autoConfig = !info->submapper; - GenVRC24_Init(info, type, 1); -} diff --git a/src/boards/vrc7.c b/src/boards/vrc7.c deleted file mode 100644 index 8f2d26f9f..000000000 --- a/src/boards/vrc7.c +++ /dev/null @@ -1,200 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2012 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 "emu2413.h" -#include "vrcirq.h" - -static int32 dwave = 0; -static OPLL *VRC7Sound = NULL; -static uint8 vrc7idx, preg[3], creg[8], mirr; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; - -static SFORMAT StateRegs[] = -{ - { &vrc7idx, 1, "VRCI" }, - { preg, 3, "PREG" }, - { creg, 8, "CREG" }, - { &mirr, 1, "MIRR" }, - - { 0 } -}; - -/* VRC7 Sound */ - -void DoVRC7Sound(void) { - int32 z, a; - if (FSettings.soundq >= 1) - return; - z = ((SOUNDTS << 16) / soundtsinc) >> 4; - a = z - dwave; - OPLL_fillbuf(VRC7Sound, &Wave[dwave], a, 1); - dwave += a; -} - -void UpdateOPLNEO(int32 *Wave, int Count) { - OPLL_fillbuf(VRC7Sound, Wave, Count, 4); -} - -void UpdateOPL(int Count) { - int32 z, a; - z = ((SOUNDTS << 16) / soundtsinc) >> 4; - a = z - dwave; - if (VRC7Sound && a) - OPLL_fillbuf(VRC7Sound, &Wave[dwave], a, 1); - dwave = 0; -} - -static void VRC7SC(void) { - if (VRC7Sound) - OPLL_set_rate(VRC7Sound, FSettings.SndRate); -} - -static void VRC7SKill(void) { - if (VRC7Sound) - OPLL_delete(VRC7Sound); - VRC7Sound = NULL; -} - -static void VRC7_ESI(void) { - GameExpSound.RChange = VRC7SC; - GameExpSound.Kill = VRC7SKill; - VRC7Sound = OPLL_new(3579545, FSettings.SndRate ? FSettings.SndRate : 44100); - OPLL_reset(VRC7Sound); - OPLL_reset(VRC7Sound); -} - -/* VRC7 Sound */ - -static void Sync(void) { - uint8 i; - setprg8r(0x10, 0x6000, 0); - setprg8(0x8000, preg[0]); - setprg8(0xA000, preg[1]); - setprg8(0xC000, preg[2]); - setprg8(0xE000, ~0); - for (i = 0; i < 8; i++) - setchr1(i << 10, creg[i]); - switch (mirr & 3) { - case 0: setmirror(MI_V); break; - case 1: setmirror(MI_H); break; - case 2: setmirror(MI_0); break; - case 3: setmirror(MI_1); break; - } -} - -static DECLFW(VRC7SW) { - if (FSettings.SndRate) { - OPLL_writeReg(VRC7Sound, vrc7idx, V); - GameExpSound.Fill = UpdateOPL; - GameExpSound.NeoFill = UpdateOPLNEO; - } -} - -static DECLFW(VRC7Write) { - A |= (A & 8) << 1; /* another two-in-oooone */ - if (A >= 0xA000 && A <= 0xDFFF) { - A &= 0xF010; - creg[((A >> 4) & 1) | ((A - 0xA000) >> 11)] = V; - Sync(); - } else if (A == 0x9030) { - VRC7SW(A, V); - } else switch (A & 0xF010) { - case 0x8000: preg[0] = V; Sync(); break; - case 0x8010: preg[1] = V; Sync(); break; - case 0x9000: preg[2] = V; Sync(); break; - case 0x9010: vrc7idx = V; break; - case 0xE000: mirr = V & 3; Sync(); break; - case 0xE010: VRCIRQ_Latch(V); break; - case 0xF000: VRCIRQ_Control(V); break; - case 0xF010: VRCIRQ_Acknowledge(); break; - } -} - -static void VRC7Power(void) { - Sync(); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, VRC7Write); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); -} - -static void VRC7Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -static void StateRestore(int version) { - Sync(); - -#ifndef GEKKO - OPLL_forceRefresh(VRC7Sound); -#endif -} - -void Mapper85_Init(CartInfo *info) { - info->Power = VRC7Power; - info->Close = VRC7Close; - VRCIRQ_Init(); - WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; - } - GameStateRestore = StateRestore; - VRC7_ESI(); - AddExState(&StateRegs, ~0, 0, 0); - -/* Ignoring these sound state files for Wii since it causes states unable to load */ -#ifndef GEKKO - /* Sound states */ - AddExState(&VRC7Sound->adr, sizeof(VRC7Sound->adr), 0, "ADDR"); - AddExState(&VRC7Sound->out, sizeof(VRC7Sound->out), 0, "OUT0"); - AddExState(&VRC7Sound->realstep, sizeof(VRC7Sound->realstep), 0, "RTIM"); - AddExState(&VRC7Sound->oplltime, sizeof(VRC7Sound->oplltime), 0, "TIME"); - AddExState(&VRC7Sound->opllstep, sizeof(VRC7Sound->opllstep), 0, "STEP"); - AddExState(&VRC7Sound->prev, sizeof(VRC7Sound->prev), 0, "PREV"); - AddExState(&VRC7Sound->next, sizeof(VRC7Sound->next), 0, "NEXT"); - AddExState(&VRC7Sound->LowFreq, sizeof(VRC7Sound->LowFreq), 0, "LFQ0"); - AddExState(&VRC7Sound->HiFreq, sizeof(VRC7Sound->HiFreq), 0, "HFQ0"); - AddExState(&VRC7Sound->InstVol, sizeof(VRC7Sound->InstVol), 0, "VOLI"); - AddExState(&VRC7Sound->CustInst, sizeof(VRC7Sound->CustInst), 0, "CUSI"); - AddExState(&VRC7Sound->slot_on_flag, sizeof(VRC7Sound->slot_on_flag), 0, "FLAG"); - AddExState(&VRC7Sound->pm_phase, sizeof(VRC7Sound->pm_phase), 0, "PMPH"); - AddExState(&VRC7Sound->lfo_pm, sizeof(VRC7Sound->lfo_pm), 0, "PLFO"); - AddExState(&VRC7Sound->am_phase, sizeof(VRC7Sound->am_phase), 0, "AMPH"); - AddExState(&VRC7Sound->lfo_am, sizeof(VRC7Sound->lfo_am), 0, "ALFO"); - AddExState(&VRC7Sound->patch_number, sizeof(VRC7Sound->patch_number), 0, "PNUM"); - AddExState(&VRC7Sound->key_status, sizeof(VRC7Sound->key_status), 0, "KET"); - AddExState(&VRC7Sound->mask, sizeof(VRC7Sound->mask), 0, "MASK"); - AddExState((uint8 *)VRC7Sound->slot, sizeof(VRC7Sound->slot), 0, "SLOT"); -#endif -} - -void NSFVRC7_Init(void) { - SetWriteHandler(0x9010, 0x901F, VRC7Write); - SetWriteHandler(0x9030, 0x903F, VRC7Write); - VRC7_ESI(); -} diff --git a/src/boards/vrc7p.c b/src/boards/vrc7p.c deleted file mode 100644 index f1d28ca1e..000000000 --- a/src/boards/vrc7p.c +++ /dev/null @@ -1,120 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2009 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 - * - * YOKO Mortal Kombat V Pro, VRC7 pirate clone - */ - -#include "mapinc.h" - -static uint8 prg[3], chr[8], mirr; -static uint8 IRQLatch, IRQa, IRQd; -static int32 IRQCount, CycleCount; - -static SFORMAT StateRegs[] = -{ - { prg, 3, "PRG" }, - { chr, 8, "CHR" }, - { &mirr, 1, "MIRR" }, - { &IRQa, 1, "IRQA" }, - { &IRQd, 1, "IRQD" }, - { &IRQLatch, 1, "IRQL" }, - { &IRQCount, 4, "IRQC" }, - { &CycleCount, 4, "CYCC" }, - { 0 } -}; - -static void Sync(void) { - uint8 i; - setprg8(0x8000, prg[0]); - setprg8(0xa000, prg[1]); - setprg8(0xc000, prg[2]); - setprg8(0xe000, ~0); - for (i = 0; i < 8; i++) - setchr1(i << 10, chr[i]); - switch (mirr & 3) { - case 0: setmirror(MI_V); break; - case 1: setmirror(MI_H); break; - case 2: setmirror(MI_0); break; - case 3: setmirror(MI_1); break; - } -} - -static DECLFW(UNLVRC7Write) { - switch (A & 0xF008) { - case 0x8000: prg[0] = V; Sync(); break; - case 0x8008: prg[1] = V; Sync(); break; - case 0x9000: prg[2] = V; Sync(); break; - case 0xa000: chr[0] = V; Sync(); break; - case 0xa008: chr[1] = V; Sync(); break; - case 0xb000: chr[2] = V; Sync(); break; - case 0xb008: chr[3] = V; Sync(); break; - case 0xc000: chr[4] = V; Sync(); break; - case 0xc008: chr[5] = V; Sync(); break; - case 0xd000: chr[6] = V; Sync(); break; - case 0xd008: chr[7] = V; Sync(); break; - case 0xe000: mirr = V; Sync(); break; - case 0xe008: IRQLatch = V; X6502_IRQEnd(FCEU_IQEXT); break; - case 0xf000: - IRQa = V & 2; - IRQd = V & 1; - if (V & 2) - IRQCount = IRQLatch; - CycleCount = 0; - X6502_IRQEnd(FCEU_IQEXT); - break; - case 0xf008: - if (IRQd) - IRQa = 1; - else - IRQa = 0; - X6502_IRQEnd(FCEU_IQEXT); - break; - } -} - -static void UNLVRC7Power(void) { - Sync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, UNLVRC7Write); -} - -static void UNLVRC7IRQHook(int a) { - if (IRQa) { - CycleCount += a * 3; - while (CycleCount >= 341) { - CycleCount -= 341; - IRQCount++; - if (IRQCount == 248) { - IRQCount = IRQLatch; - X6502_IRQBegin(FCEU_IQEXT); - } - } - } -} - -static void StateRestore(int version) { - Sync(); -} - -void UNLVRC7_Init(CartInfo *info) { - info->Power = UNLVRC7Power; - MapIRQHook = UNLVRC7IRQHook; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/vrcirq.c b/src/boards/vrcirq.c deleted file mode 100644 index d12d3d36d..000000000 --- a/src/boards/vrcirq.c +++ /dev/null @@ -1,93 +0,0 @@ -#include "mapinc.h" -#include "vrcirq.h" - -static int16 IRQPrescaler; -static uint8 IRQCount; -static uint8 IRQLatch; -static uint8 IRQd; -static uint8 IRQa; -static uint8 IRQm; - -static SFORMAT StateRegs[] = -{ - { &IRQPrescaler, 2, "PREC" }, - { &IRQCount, 1, "IRQC" }, - { &IRQLatch, 1, "IRQL" }, - { &IRQd, 1, "IRQD" }, - { &IRQa, 1, "IRQA" }, - { &IRQm, 1, "IRQM" }, - - { 0 } -}; - -static void FP_FASTAPASS(1) VRCIRQ_IrqHook(int a) -{ - int count = a; - - if (!IRQa) { - return; - } - - while (count) { - count--; - IRQPrescaler -= 3; - if (IRQm || (IRQPrescaler < 0 && !IRQm)) { - IRQPrescaler += 341; - if (IRQCount == 0xFF) { - X6502_IRQBegin(FCEU_IQEXT); - IRQCount = IRQLatch; - } else { - IRQCount++; - } - } - } -} - -void VRCIRQ_Init(void) -{ - IRQPrescaler = 0; - IRQCount = 0; - IRQLatch = 0; - IRQd = 0; - IRQa = 0; - IRQm = 0; - MapIRQHook = VRCIRQ_IrqHook; - - AddExState(&StateRegs, ~0, 0, 0); -} - -void VRCIRQ_Latch(uint8 V) -{ - IRQLatch = V; -} - -void VRCIRQ_LatchNibble(uint8 V, uint8 highBit) -{ - if (highBit) { - IRQLatch &= 0x0F; - IRQLatch |= V << 4; - } else { - IRQLatch &= 0xF0; - IRQLatch |= V & 0xF; - } -} - -void VRCIRQ_Control(uint8 V) -{ - IRQd = (V & 0x01) == 0x01; - IRQa = (V & 0x02) == 0x02; - IRQm = (V & 0x04) == 0x04; - IRQPrescaler = 341; - - if (IRQa) { - IRQCount = IRQLatch; - } - - X6502_IRQEnd(FCEU_IQEXT); -} - -void VRCIRQ_Acknowledge(void) -{ - IRQa = IRQd; - X6502_IRQEnd(FCEU_IQEXT); -} diff --git a/src/boards/vrcirq.h b/src/boards/vrcirq.h deleted file mode 100644 index 5a9813722..000000000 --- a/src/boards/vrcirq.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _VRCIRQ_H -#define _VRCIRQ_H - -void VRCIRQ_Init(void); -void VRCIRQ_Latch(uint8 V); -void VRCIRQ_LatchNibble(uint8 V, uint8 highBit); -void VRCIRQ_Control(uint8 V); -void VRCIRQ_Acknowledge(void); - -#endif /* _VRCIRQ_H */ \ No newline at end of file diff --git a/src/boards/yoko.c b/src/boards/yoko.c deleted file mode 100644 index d04323bbc..000000000 --- a/src/boards/yoko.c +++ /dev/null @@ -1,248 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2006 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 - * - * YOKO mapper, almost the same as 83, TODO: figure out difference - * Mapper 83 - 30-in-1 mapper, two modes for single game carts, one mode for - * multigame Dragon Ball Z Party - * - * Mortal Kombat 2 YOKO - * N-CXX(M), XX - PRG+CHR, 12 - 128+256, 22 - 256+256, 14 - 128+512 - * - */ - -#include "mapinc.h" - -static uint8 mode, bank, reg[11], low[4], dip, IRQa; -static int32 IRQCount; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; - -static uint8 is2kbank, dbzParty; - -static SFORMAT StateRegs[] = -{ - { &mode, 1, "MODE" }, - { &bank, 1, "BANK" }, - { &IRQCount, 4, "IRQC" }, - { &IRQa, 1, "IRQA" }, - { reg, 11, "REGS" }, - { low, 4, "LOWR" }, - { &is2kbank, 1, "IS2K" }, - { 0 } -}; - -static void UNLYOKOSync(void) { - setmirror((mode & 1) ^ 1); - setchr2(0x0000, reg[3]); - setchr2(0x0800, reg[4]); - setchr2(0x1000, reg[5]); - setchr2(0x1800, reg[6]); - if (mode & 0x10) { - uint32 base = (bank & 8) << 1; - setprg8(0x8000, (reg[0] & 0x0f) | base); - setprg8(0xA000, (reg[1] & 0x0f) | base); - setprg8(0xC000, (reg[2] & 0x0f) | base); - setprg8(0xE000, 0x0f | base); - } else { - if (mode & 8) - setprg32(0x8000, bank >> 1); - else { - setprg16(0x8000, bank); - setprg16(0xC000, ~0); - } - } -} - -static void M83Sync(void) { - switch (mode & 3) { /* check if it is true */ - case 0: setmirror(MI_V); break; - case 1: setmirror(MI_H); break; - case 2: setmirror(MI_0); break; - case 3: setmirror(MI_1); break; - } - if (is2kbank) { - setchr2(0x0000, reg[0]); - setchr2(0x0800, reg[1]); - setchr2(0x1000, reg[6]); - setchr2(0x1800, reg[7]); - } else { - int x; - for (x = 0; x < 8; x++) - setchr1(x << 10, reg[x] | ((bank & 0x30) << 4)); - } - setprg8r(0x10, 0x6000, 0); - switch ((mode >> 3) & 3) { - case 0: - setprg16(0x8000, bank); - setprg16(0xC000, bank | 0x0F); - break; - case 1: - setprg32(0x8000, bank >> 1); - break; - case 2: - case 3: - setprg8(0x8000, ((bank << 1) & ~0x1F) | (reg[8] & 0x1F)); - setprg8(0xA000, ((bank << 1) & ~0x1F) | (reg[9] & 0x1F)); - setprg8(0xC000, ((bank << 1) & ~0x1F) | (reg[10] & 0x1F)); - setprg8(0xE000, ((bank << 1) & ~0x1F) | 0x1F); - break; - } -} - -static DECLFW(UNLYOKOWrite) { - switch (A & 0x8C17) { - case 0x8000: bank = V; UNLYOKOSync(); break; - case 0x8400: mode = V; UNLYOKOSync(); break; - case 0x8800: IRQCount &= 0xFF00; IRQCount |= V; X6502_IRQEnd(FCEU_IQEXT); break; - case 0x8801: IRQa = mode & 0x80; IRQCount &= 0xFF; IRQCount |= V << 8; break; - case 0x8c00: reg[0] = V; UNLYOKOSync(); break; - case 0x8c01: reg[1] = V; UNLYOKOSync(); break; - case 0x8c02: reg[2] = V; UNLYOKOSync(); break; - case 0x8c10: reg[3] = V; UNLYOKOSync(); break; - case 0x8c11: reg[4] = V; UNLYOKOSync(); break; - case 0x8c16: reg[5] = V; UNLYOKOSync(); break; - case 0x8c17: reg[6] = V; UNLYOKOSync(); break; - } -} - -static DECLFW(M83Write) { - switch (A &0x31F) { - case 0x000: bank = V; M83Sync(); break; - case 0x100: mode = V; M83Sync(); break; - case 0x200: IRQCount &= 0xFF00; IRQCount |= V; X6502_IRQEnd(FCEU_IQEXT); break; - case 0x201: IRQa = mode & 0x80; IRQCount &= 0xFF; IRQCount |= V << 8; break; - case 0x300: reg[8] = V; mode &= 0xBF; M83Sync(); break; - case 0x301: reg[9] = V; mode &= 0xBF; M83Sync(); break; - case 0x302: reg[10] = V; mode &= 0xBF; M83Sync(); break; - case 0x310: reg[0] = V; M83Sync(); break; - case 0x311: reg[1] = V; M83Sync(); break; - case 0x312: reg[2] = V; M83Sync(); break; - case 0x313: reg[3] = V; M83Sync(); break; - case 0x314: reg[4] = V; M83Sync(); break; - case 0x315: reg[5] = V; M83Sync(); break; - case 0x316: reg[6] = V; M83Sync(); break; - case 0x317: reg[7] = V; M83Sync(); break; - } -} - -static DECLFR(UNLYOKOReadDip) { - return (X.DB & 0xFC) | dip; -} - -static DECLFR(UNLYOKOReadLow) { - return low[A & 3]; -} - -static DECLFW(UNLYOKOWriteLow) { - low[A & 3] = V; -} - -static void UNLYOKOPower(void) { - mode = bank = 0; - dip = 3; - UNLYOKOSync(); - SetReadHandler(0x5000, 0x53FF, UNLYOKOReadDip); - SetReadHandler(0x5400, 0x5FFF, UNLYOKOReadLow); - SetWriteHandler(0x5400, 0x5FFF, UNLYOKOWriteLow); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, UNLYOKOWrite); -} - -static void M83Power(void) { - mode = bank = 0; - dip = 0; - M83Sync(); - SetReadHandler(0x5000, 0x5000, UNLYOKOReadDip); - SetReadHandler(0x5100, 0x5103, UNLYOKOReadLow); - SetWriteHandler(0x5100, 0x5103, UNLYOKOWriteLow); - SetReadHandler(0x6000, 0x7fff, CartBR); - SetWriteHandler(0x6000, 0x7fff, CartBW); - SetReadHandler(0x8000, 0xffff, CartBR); - SetWriteHandler(0x8000, 0xffff, M83Write); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); -} - -static void UNLYOKOReset(void) { - dip = (dip + 1) & 3; - mode = bank = 0; - UNLYOKOSync(); -} - -static void M83Reset(void) { - dip ^= 1; - mode = bank = 0; - M83Sync(); -} - -static void M83Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -static void FP_FASTAPASS(1) UNLYOKOIRQHook(int a) { - if (IRQa) { - IRQCount -= a; - if (IRQCount < 0) { - X6502_IRQBegin(FCEU_IQEXT); - IRQa = 0; - IRQCount = 0xFFFF; - } - } -} - -static void UNLYOKOStateRestore(int version) { - UNLYOKOSync(); -} - -static void M83StateRestore(int version) { - M83Sync(); -} - -void UNLYOKO_Init(CartInfo *info) { - info->Power = UNLYOKOPower; - info->Reset = UNLYOKOReset; - MapIRQHook = UNLYOKOIRQHook; - GameStateRestore = UNLYOKOStateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} - -void Mapper83_Init(CartInfo *info) { - info->Power = M83Power; - info->Reset = M83Reset; - info->Close = M83Close; - MapIRQHook = UNLYOKOIRQHook; - GameStateRestore = M83StateRestore; - - if (info->iNES2) { - is2kbank = info->submapper == 1; - dbzParty = info->submapper == 2; - } else { - is2kbank = info->CHRRomSize == (512 * 1024); - dbzParty = info->PRGRomSize == (1024 * 1024); - } - if (dbzParty) { - 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/cart.c b/src/cart.c index 9d4a5d69b..084d2978b 100644 --- a/src/cart.c +++ b/src/cart.c @@ -35,15 +35,13 @@ #include "general.h" -/* - This file contains all code for coordinating the mapping in of the - address space external to the NES. - It's also (ab)used by the NSF code. -*/ +/* This file contains all code for coordinating the mapping in of the + address space external to the NES. + It's also (ab)used by the NSF code. + */ uint8 *Page[32], *VPage[8]; uint8 **VPageR = VPage; -uint8 *VPageG[8]; uint8 *MMC5SPRVPage[8]; uint8 *MMC5BGVPage[8]; @@ -70,29 +68,21 @@ uint32 CHRmask2[32]; uint32 CHRmask4[32]; uint32 CHRmask8[32]; -int geniestage = 0; - -int modcon; - -uint8 genieval[3]; -uint8 geniech[3]; - -uint32 genieaddr[3]; - static INLINE void setpageptr(int s, uint32 A, uint8 *p, int ram) { uint32 AB = A >> 11; int x; - if (p) + if (p) { for (x = (s >> 1) - 1; x >= 0; x--) { PRGIsRAM[AB + x] = ram; Page[AB + x] = p - A; } - else + } else { for (x = (s >> 1) - 1; x >= 0; x--) { PRGIsRAM[AB + x] = 0; Page[AB + x] = 0; } + } } static uint8 nothing[8192]; @@ -144,47 +134,49 @@ DECLFW(CartBW) { } DECLFR(CartBROB) { - if (!Page[A >> 11]) - return(X.DB); - else + if (!Page[A >> 11]) { + return(cpu.openbus); + } else { return Page[A >> 11][A]; + } } -void FASTAPASS(3) setprg2r(int r, uint32 A, uint32 V) { +void setprg2r(int r, uint32 A, uint32 V) { V &= PRGmask2[r]; setpageptr(2, A, PRGptr[r] ? (&PRGptr[r][V << 11]) : 0, PRGram[r]); } -void FASTAPASS(2) setprg2(uint32 A, uint32 V) { +void setprg2(uint32 A, uint32 V) { setprg2r(0, A, V); } -void FASTAPASS(3) setprg4r(int r, uint32 A, uint32 V) { +void setprg4r(int r, uint32 A, uint32 V) { V &= PRGmask4[r]; setpageptr(4, A, PRGptr[r] ? (&PRGptr[r][V << 12]) : 0, PRGram[r]); } -void FASTAPASS(2) setprg4(uint32 A, uint32 V) { +void setprg4(uint32 A, uint32 V) { setprg4r(0, A, V); } -void FASTAPASS(3) setprg8r(int r, uint32 A, uint32 V) { +void setprg8r(int r, uint32 A, uint32 V) { if (PRGsize[r] >= 8192) { V &= PRGmask8[r]; setpageptr(8, A, PRGptr[r] ? (&PRGptr[r][V << 13]) : 0, PRGram[r]); } else { uint32 VA = V << 2; int x; - for (x = 0; x < 4; x++) + for (x = 0; x < 4; x++) { setpageptr(2, A + (x << 11), PRGptr[r] ? (&PRGptr[r][((VA + x) & PRGmask2[r]) << 11]) : 0, PRGram[r]); + } } } -void FASTAPASS(2) setprg8(uint32 A, uint32 V) { +void setprg8(uint32 A, uint32 V) { setprg8r(0, A, V); } -void FASTAPASS(3) setprg16r(int r, uint32 A, uint32 V) { +void setprg16r(int r, uint32 A, uint32 V) { if (PRGsize[r] >= 16384) { V &= PRGmask16[r]; setpageptr(16, A, PRGptr[r] ? (&PRGptr[r][V << 14]) : 0, PRGram[r]); @@ -192,16 +184,17 @@ void FASTAPASS(3) setprg16r(int r, uint32 A, uint32 V) { uint32 VA = V << 3; int x; - for (x = 0; x < 8; x++) + for (x = 0; x < 8; x++) { setpageptr(2, A + (x << 11), PRGptr[r] ? (&PRGptr[r][((VA + x) & PRGmask2[r]) << 11]) : 0, PRGram[r]); + } } } -void FASTAPASS(2) setprg16(uint32 A, uint32 V) { +void setprg16(uint32 A, uint32 V) { setprg16r(0, A, V); } -void FASTAPASS(3) setprg32r(int r, uint32 A, uint32 V) { +void setprg32r(int r, uint32 A, uint32 V) { if (PRGsize[r] >= 32768) { V &= PRGmask32[r]; setpageptr(32, A, PRGptr[r] ? (&PRGptr[r][V << 15]) : 0, PRGram[r]); @@ -209,87 +202,102 @@ void FASTAPASS(3) setprg32r(int r, uint32 A, uint32 V) { uint32 VA = V << 4; int x; - for (x = 0; x < 16; x++) + for (x = 0; x < 16; x++) { setpageptr(2, A + (x << 11), PRGptr[r] ? (&PRGptr[r][((VA + x) & PRGmask2[r]) << 11]) : 0, PRGram[r]); + } } } -void FASTAPASS(2) setprg32(uint32 A, uint32 V) { +void setprg32(uint32 A, uint32 V) { setprg32r(0, A, V); } -void FASTAPASS(3) setchr1r(int r, uint32 A, uint32 V) { - if (!CHRptr[r]) return; +void setchr1r(int r, uint32 A, uint32 V) { + if (!CHRptr[r]) { + return; + } FCEUPPU_LineUpdate(); V &= CHRmask1[r]; - if (CHRram[r]) + if (CHRram[r]) { PPUCHRRAM |= (1 << (A >> 10)); - else + } else { PPUCHRRAM &= ~(1 << (A >> 10)); + } VPageR[(A) >> 10] = &CHRptr[r][(V) << 10] - (A); } -void FASTAPASS(3) setchr2r(int r, uint32 A, uint32 V) { - if (!CHRptr[r]) return; +void setchr2r(int r, uint32 A, uint32 V) { + if (!CHRptr[r]) { + return; + } FCEUPPU_LineUpdate(); V &= CHRmask2[r]; VPageR[(A) >> 10] = VPageR[((A) >> 10) + 1] = &CHRptr[r][(V) << 11] - (A); - if (CHRram[r]) + if (CHRram[r]) { PPUCHRRAM |= (3 << (A >> 10)); - else + } else { PPUCHRRAM &= ~(3 << (A >> 10)); + } } -void FASTAPASS(3) setchr4r(int r, uint32 A, uint32 V) { - if (!CHRptr[r]) return; +void setchr4r(int r, uint32 A, uint32 V) { + if (!CHRptr[r]) { + return; + } FCEUPPU_LineUpdate(); V &= CHRmask4[r]; VPageR[(A) >> 10] = VPageR[((A) >> 10) + 1] = - VPageR[((A) >> 10) + 2] = VPageR[((A) >> 10) + 3] = &CHRptr[r][(V) << 12] - (A); - if (CHRram[r]) + VPageR[((A) >> 10) + 2] = VPageR[((A) >> 10) + 3] = &CHRptr[r][(V) << 12] - (A); + if (CHRram[r]) { PPUCHRRAM |= (15 << (A >> 10)); - else + } else { PPUCHRRAM &= ~(15 << (A >> 10)); + } } -void FASTAPASS(2) setchr8r(int r, uint32 V) { +void setchr8r(int r, uint32 V) { int x; - if (!CHRptr[r]) return; + if (!CHRptr[r]) { + return; + } FCEUPPU_LineUpdate(); V &= CHRmask8[r]; - for (x = 7; x >= 0; x--) + for (x = 7; x >= 0; x--) { VPageR[x] = &CHRptr[r][V << 13]; - if (CHRram[r]) - PPUCHRRAM |= (255); - else + } + if (CHRram[r]) { + PPUCHRRAM |= 0xFF; + } else { PPUCHRRAM = 0; + } } -void FASTAPASS(2) setchr1(uint32 A, uint32 V) { +void setchr1(uint32 A, uint32 V) { setchr1r(0, A, V); } -void FASTAPASS(2) setchr2(uint32 A, uint32 V) { +void setchr2(uint32 A, uint32 V) { setchr2r(0, A, V); } -void FASTAPASS(2) setchr4(uint32 A, uint32 V) { +void setchr4(uint32 A, uint32 V) { setchr4r(0, A, V); } -void FASTAPASS(1) setchr8(uint32 V) { +void setchr8(uint32 V) { setchr8r(0, V); } /* This function can be called without calling SetupCartMirroring(). */ -void FASTAPASS(3) setntamem(uint8 * p, int ram, uint32 b) { +void setntamem(uint8 *p, int ram, uint32 b) { FCEUPPU_LineUpdate(); vnapage[b] = p; PPUNTARAM &= ~(1 << b); - if (ram) + if (ram) { PPUNTARAM |= 1 << b; + } } static int mirrorhard = 0; @@ -301,25 +309,30 @@ void setmirrorw(int a, int b, int c, int d) { vnapage[3] = NTARAM + d * 0x400; } -void FASTAPASS(1) setmirror(int t) { +void setmirror(int t) { FCEUPPU_LineUpdate(); - if (!mirrorhard) { - switch (t) { - case MI_H: - vnapage[0] = vnapage[1] = NTARAM; vnapage[2] = vnapage[3] = NTARAM + 0x400; - break; - case MI_V: - vnapage[0] = vnapage[2] = NTARAM; vnapage[1] = vnapage[3] = NTARAM + 0x400; - break; - case MI_0: - vnapage[0] = vnapage[1] = vnapage[2] = vnapage[3] = NTARAM; - break; - case MI_1: - vnapage[0] = vnapage[1] = vnapage[2] = vnapage[3] = NTARAM + 0x400; - break; - } - PPUNTARAM = 0xF; + + if (mirrorhard) { + return; } + + switch (t) { + case MI_H: + vnapage[0] = vnapage[1] = NTARAM; + vnapage[2] = vnapage[3] = NTARAM + 0x400; + break; + case MI_V: + vnapage[0] = vnapage[2] = NTARAM; + vnapage[1] = vnapage[3] = NTARAM + 0x400; + break; + case MI_0: + vnapage[0] = vnapage[1] = vnapage[2] = vnapage[3] = NTARAM; + break; + case MI_1: + vnapage[0] = vnapage[1] = vnapage[2] = vnapage[3] = NTARAM + 0x400; + break; + } + PPUNTARAM = 0xF; } void SetupCartMirroring(int m, int hard, uint8 *extra) { @@ -335,193 +348,3 @@ void SetupCartMirroring(int m, int hard, uint8 *extra) { } mirrorhard = hard; } - -static uint8 *GENIEROM = 0; - -void FixGenieMap(void); - -/* Called when a game(file) is opened successfully. */ -void FCEU_OpenGenie(void) { - RFILE *fp = NULL; - int x; - - if (!GENIEROM) { - char *fn; - - if (!(GENIEROM = (uint8*)FCEU_malloc(4096 + 1024))) return; - - fn = FCEU_MakeFName(FCEUMKF_GGROM, 0, 0); - - if (!string_is_empty(fn) && path_is_valid(fn)) - fp = filestream_open(fn, - RETRO_VFS_FILE_ACCESS_READ, - RETRO_VFS_FILE_ACCESS_HINT_NONE); - - free(fn); - fn = NULL; - - if (!fp) { - FCEU_PrintError("Error opening Game Genie ROM image!\n"); - FCEUD_DispMessage(RETRO_LOG_WARN, 3000, "Game Genie ROM image (gamegenie.nes) missing"); - free(GENIEROM); - GENIEROM = 0; - return; - } - if (filestream_read(fp, GENIEROM, 16) != 16) { - grerr: - FCEU_PrintError("Error reading from Game Genie ROM image!\n"); - FCEUD_DispMessage(RETRO_LOG_WARN, 3000, "Failed to read Game Genie ROM image (gamegenie.nes)"); - free(GENIEROM); - GENIEROM = 0; - filestream_close(fp); - return; - } - if (GENIEROM[0] == 0x4E) { /* iNES ROM image */ - if (filestream_read(fp, GENIEROM, 4096) != 4096) - goto grerr; - if (filestream_seek(fp, 16384 - 4096, RETRO_VFS_SEEK_POSITION_CURRENT)) - goto grerr; - if (filestream_read(fp, GENIEROM + 4096, 256) != 256) - goto grerr; - } else { - if (filestream_read(fp, GENIEROM + 16, 4352 - 16) != (4352 - 16)) - goto grerr; - } - filestream_close(fp); - - /* Workaround for the FCE Ultra CHR page size only being 1KB */ - for (x = 0; x < 4; x++) - memcpy(GENIEROM + 4096 + (x << 8), GENIEROM + 4096, 256); - } - - geniestage = 1; -} - -/* Called when a game is closed. */ -void FCEU_CloseGenie(void) { - /* No good reason to free() the Game Genie ROM image data. */ - geniestage = 0; - FlushGenieRW(); - VPageR = VPage; -} - -void FCEU_KillGenie(void) { - if (GENIEROM) { - free(GENIEROM); - GENIEROM = 0; - } -} - -static DECLFR(GenieRead) { - return GENIEROM[A & 4095]; -} - -static DECLFW(GenieWrite) { - switch (A) { - case 0x800c: - case 0x8008: - case 0x8004: genieval[((A - 4) & 0xF) >> 2] = V; break; - - case 0x800b: - case 0x8007: - case 0x8003: geniech[((A - 3) & 0xF) >> 2] = V; break; - - case 0x800a: - case 0x8006: - case 0x8002: genieaddr[((A - 2) & 0xF) >> 2] &= 0xFF00; genieaddr[((A - 2) & 0xF) >> 2] |= V; break; - - case 0x8009: - case 0x8005: - case 0x8001: genieaddr[((A - 1) & 0xF) >> 2] &= 0xFF; genieaddr[((A - 1) & 0xF) >> 2] |= (V | 0x80) << 8; break; - - case 0x8000: - if (!V) - FixGenieMap(); - else { - modcon = V ^ 0xFF; - if (V == 0x71) - modcon = 0; - } - break; - } -} - -static readfunc GenieBackup[3]; - -static DECLFR(GenieFix1) { - uint8 r = GenieBackup[0](A); - - if ((modcon >> 1) & 1) /* No check */ - return genieval[0]; - else if (r == geniech[0]) - return genieval[0]; - - return r; -} - -static DECLFR(GenieFix2) { - uint8 r = GenieBackup[1](A); - - if ((modcon >> 2) & 1) /* No check */ - return genieval[1]; - else if (r == geniech[1]) - return genieval[1]; - - return r; -} - -static DECLFR(GenieFix3) { - uint8 r = GenieBackup[2](A); - - if ((modcon >> 3) & 1) /* No check */ - return genieval[2]; - else if (r == geniech[2]) - return genieval[2]; - - return r; -} - - -void FixGenieMap(void) { - int x; - - geniestage = 2; - - for (x = 0; x < 8; x++) - VPage[x] = VPageG[x]; - - VPageR = VPage; - FlushGenieRW(); - for (x = 0; x < 3; x++) - if ((modcon >> (4 + x)) & 1) { - readfunc tmp[3] = { GenieFix1, GenieFix2, GenieFix3 }; - GenieBackup[x] = GetReadHandler(genieaddr[x]); - SetReadHandler(genieaddr[x], genieaddr[x], tmp[x]); - } -} - -void FCEU_GeniePower(void) { - uint32 x; - - if (!geniestage) - return; - - geniestage = 1; - for (x = 0; x < 3; x++) { - genieval[x] = 0xFF; - geniech[x] = 0xFF; - genieaddr[x] = 0xFFFF; - } - modcon = 0; - - SetWriteHandler(0x8000, 0xFFFF, GenieWrite); - SetReadHandler(0x8000, 0xFFFF, GenieRead); - - for (x = 0; x < 8; x++) - VPage[x] = GENIEROM + 4096 - 0x400 * x; - - if (AllocGenieRW()) - VPageR = VPageG; - else - geniestage = 2; -} diff --git a/src/cart.h b/src/cart.h index 7b7a97a12..f02c3a068 100644 --- a/src/cart.h +++ b/src/cart.h @@ -1,50 +1,57 @@ #ifndef _FCEU_CART_H #define _FCEU_CART_H +enum DefaultValues { DEFAULT = -1, NOEXTRA = -1 }; + +enum ConsoleSystem { NES_NTSC = 0, NES_PAL = 1, MULTI = 2, DENDY = 3 }; + typedef struct { /* Set by mapper/board code: */ void (*Power)(void); void (*Reset)(void); void (*Close)(void); - uint8 *SaveGame[4]; /* Pointers to memory to save/load. */ - uint32 SaveGameLen[4]; /* How much memory to save/load. */ + + uint8 *SaveGame[4]; /* Pointers to memory to save/load. */ + 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" - * that are not really MMC3 but are - * set to mapper 4. - */ - int mirror2bits; /* a 2bit representation for mirroring. - * For use in nonstandard way like apply one-screen mirroring on - * mapper 30. - */ - int battery; /* Presence of an actual battery. */ - int PRGRomSize; /* prg rom size in bytes */ - int CHRRomSize; /* chr rom size in bytes */ - int PRGRamSize; /* prg ram size in bytes (volatile) */ - int CHRRamSize; /* chr ram size in bytes (volatile) */ - int PRGRamSaveSize; /* prg ram size in bytes (non-volatile or battery backed) */ - int CHRRamSaveSize; /* chr ram size in bytes (non-volatile or battery backed) */ - int region; /* video system timing (ntsc, pal, dendy */ - - int ConsoleType; - int ExtConsoleType; - int InputTypes; - int VS_PPUTypes; - int VS_HWType; + uint8 format; + uint8 iNES2; /* iNES version */ + uint16 mapper; /* mapper used */ + uint8 submapper; + uint8 mirror; /* As set in the header or chunk. + * iNES/UNIF specific. Intended + * to help support games like "Karnov" + * that are not really MMC3 but are + * set to mapper 4. + */ + uint8 mirror2bits; /* a 2bit representation for mirroring. + * For use in nonstandard way like apply one-screen mirroring on + * mapper 30. + */ + uint8 battery; /* Presence of an actual battery. */ + uint8 trainer; /* Presense of trainer data */ + uint8 MiscRoms; /* Presense of misc roms */ + uint8 region; /* video system timing (NTSC, PAL, Dendy */ + uint8 ConsoleType; + uint8 InputTypes; + uint8 VS_PPUTypes; + uint8 VS_HWType; + + uint32 PRGRomSize; /* actual prg rom size in bytes */ + uint32 CHRRomSize; /* actual chr rom size in bytes */ + uint32 PRGRamSize; /* prg ram size in bytes (volatile) */ + uint32 CHRRamSize; /* chr ram size in bytes (volatile) */ + uint32 PRGRamSaveSize; /* prg ram size in bytes (non-volatile or battery backed) */ + uint32 CHRRamSaveSize; /* chr ram size in bytes (non-volatile or battery backed) */ uint8 MD5[16]; uint32 PRGCRC32; uint32 CHRCRC32; - uint32 CRC32; /* Should be set by the iNES/UNIF loading - * code, used by mapper/board code, maybe - * other code in the future. - */ + uint32 CRC32; /* Should be set by the iNES/UNIF loading + * code, used by mapper/board code, maybe + * other code in the future. + */ } CartInfo; extern uint8 *Page[32], *VPage[8], *MMC5SPRVPage[8], *MMC5BGVPage[8]; @@ -75,43 +82,43 @@ extern uint32 CHRmask2[32]; extern uint32 CHRmask4[32]; extern uint32 CHRmask8[32]; -void FASTAPASS(2) setprg2(uint32 A, uint32 V); -void FASTAPASS(2) setprg4(uint32 A, uint32 V); -void FASTAPASS(2) setprg8(uint32 A, uint32 V); -void FASTAPASS(2) setprg16(uint32 A, uint32 V); -void FASTAPASS(2) setprg32(uint32 A, uint32 V); - -void FASTAPASS(3) setprg2r(int r, uint32 A, uint32 V); -void FASTAPASS(3) setprg4r(int r, uint32 A, uint32 V); -void FASTAPASS(3) setprg8r(int r, uint32 A, uint32 V); -void FASTAPASS(3) setprg16r(int r, uint32 A, uint32 V); -void FASTAPASS(3) setprg32r(int r, uint32 A, uint32 V); - -void FASTAPASS(3) setchr1r(int r, uint32 A, uint32 V); -void FASTAPASS(3) setchr2r(int r, uint32 A, uint32 V); -void FASTAPASS(3) setchr4r(int r, uint32 A, uint32 V); -void FASTAPASS(2) setchr8r(int r, uint32 V); - -void FASTAPASS(2) setchr1(uint32 A, uint32 V); -void FASTAPASS(2) setchr2(uint32 A, uint32 V); -void FASTAPASS(2) setchr4(uint32 A, uint32 V); -void FASTAPASS(2) setchr8(uint32 V); - -void FASTAPASS(1) setmirror(int t); -void setmirrorw(int a, int b, int c, int d); -void FASTAPASS(3) setntamem(uint8 *p, int ram, uint32 b); +extern uint8 *WRAM; +extern uint32 WRAMSIZE; -#define MI_H 0 -#define MI_V 1 -#define MI_0 2 -#define MI_1 3 +void setprg2(uint32 A, uint32 V); +void setprg4(uint32 A, uint32 V); +void setprg8(uint32 A, uint32 V); +void setprg16(uint32 A, uint32 V); +void setprg32(uint32 A, uint32 V); -extern int geniestage; +void setprg2r(int r, uint32 A, uint32 V); +void setprg4r(int r, uint32 A, uint32 V); +void setprg8r(int r, uint32 A, uint32 V); +void setprg16r(int r, uint32 A, uint32 V); +void setprg32r(int r, uint32 A, uint32 V); + +void setchr1r(int r, uint32 A, uint32 V); +void setchr2r(int r, uint32 A, uint32 V); +void setchr4r(int r, uint32 A, uint32 V); +void setchr8r(int r, uint32 V); + +void setchr1(uint32 A, uint32 V); +void setchr2(uint32 A, uint32 V); +void setchr4(uint32 A, uint32 V); +void setchr8(uint32 V); + +void setmirror(int t); +void setmirrorw(int a, int b, int c, int d); +void setntamem(uint8 *p, int ram, uint32 b); -void FCEU_GeniePower(void); +enum MirroringType { + MI_H = 0, /* horizontal */ + MI_V = 1, /* vertical */ + MI_0 = 2, /* single-screen 0 */ + MI_1 = 3, /* single-screen 1 */ + MI_4 = 4 /* four-screen */ +}; -void FCEU_OpenGenie(void); -void FCEU_CloseGenie(void); -void FCEU_KillGenie(void); +extern CartInfo iNESCart; #endif diff --git a/src/cheat.c b/src/cheat.c index 043270a21..a97f5b7eb 100644 --- a/src/cheat.c +++ b/src/cheat.c @@ -102,7 +102,7 @@ static DECLFR(SubCheatsRead) { return(0); /* We should never get here. */ } -void RebuildSubCheats(void) { +static void RebuildSubCheats(void) { int x; struct CHEATF *c = cheats; @@ -127,7 +127,7 @@ void RebuildSubCheats(void) { } } -void FCEU_PowerCheats() { +void FCEU_PowerCheats(void) { numsubcheats = 0; /* Quick hack to prevent setting of ancient read addresses. */ RebuildSubCheats(); } diff --git a/src/drawing.c b/src/drawing.c new file mode 100644 index 000000000..a5db853ce --- /dev/null +++ b/src/drawing.c @@ -0,0 +1,201 @@ +#include + +#include "fceu-types.h" +#include "fceu.h" +#include "drawing.h" + +static const uint8 fontdata2[2048] = +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x81,0xa5,0x81,0xbd,0x99,0x81,0x7e,0x7e,0xff,0xdb,0xff,0xc3,0xe7,0xff,0x7e,0x36,0x7f,0x7f,0x7f,0x3e,0x1c,0x08,0x00, + 0x08,0x1c,0x3e,0x7f,0x3e,0x1c,0x08,0x00,0x1c,0x3e,0x1c,0x7f,0x7f,0x3e,0x1c,0x3e,0x08,0x08,0x1c,0x3e,0x7f,0x3e,0x1c,0x3e,0x00,0x00,0x18,0x3c,0x3c,0x18,0x00,0x00, + 0xff,0xff,0xe7,0xc3,0xc3,0xe7,0xff,0xff,0x00,0x3c,0x66,0x42,0x42,0x66,0x3c,0x00,0xff,0xc3,0x99,0xbd,0xbd,0x99,0xc3,0xff,0xf0,0xe0,0xf0,0xbe,0x33,0x33,0x33,0x1e, + 0x3c,0x66,0x66,0x66,0x3c,0x18,0x7e,0x18,0xfc,0xcc,0xfc,0x0c,0x0c,0x0e,0x0f,0x07,0xfe,0xc6,0xfe,0xc6,0xc6,0xe6,0x67,0x03,0x99,0x5a,0x3c,0xe7,0xe7,0x3c,0x5a,0x99, + 0x01,0x07,0x1f,0x7f,0x1f,0x07,0x01,0x00,0x40,0x70,0x7c,0x7f,0x7c,0x70,0x40,0x00,0x18,0x3c,0x7e,0x18,0x18,0x7e,0x3c,0x18,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x00, + 0xfe,0xdb,0xdb,0xde,0xd8,0xd8,0xd8,0x00,0x7c,0xc6,0x1c,0x36,0x36,0x1c,0x33,0x1e,0x00,0x00,0x00,0x00,0x7e,0x7e,0x7e,0x00,0x18,0x3c,0x7e,0x18,0x7e,0x3c,0x18,0xff, + 0x18,0x3c,0x7e,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x7e,0x3c,0x18,0x00,0x00,0x18,0x30,0x7f,0x30,0x18,0x00,0x00,0x00,0x0c,0x06,0x7f,0x06,0x0c,0x00,0x00, + 0x00,0x00,0x03,0x03,0x03,0x7f,0x00,0x00,0x00,0x24,0x66,0xff,0x66,0x24,0x00,0x00,0x00,0x18,0x3c,0x7e,0xff,0xff,0x00,0x00,0x00,0xff,0xff,0x7e,0x3c,0x18,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x1e,0x0c,0x0c,0x00,0x0c,0x00,0x36,0x36,0x36,0x00,0x00,0x00,0x00,0x00,0x36,0x36,0x7f,0x36,0x7f,0x36,0x36,0x00, + 0x0c,0x3e,0x03,0x1e,0x30,0x1f,0x0c,0x00,0x00,0x63,0x33,0x18,0x0c,0x66,0x63,0x00,0x1c,0x36,0x1c,0x6e,0x3b,0x33,0x6e,0x00,0x06,0x06,0x03,0x00,0x00,0x00,0x00,0x00, + 0x18,0x0c,0x06,0x06,0x06,0x0c,0x18,0x00,0x06,0x0c,0x18,0x18,0x18,0x0c,0x06,0x00,0x00,0x66,0x3c,0xff,0x3c,0x66,0x00,0x00,0x00,0x0c,0x0c,0x3f,0x0c,0x0c,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x0c,0x0c,0x06,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x0c,0x00,0x60,0x30,0x18,0x0c,0x06,0x03,0x01,0x00, + 0x3e,0x63,0x73,0x7b,0x6f,0x67,0x3e,0x00,0x0c,0x0e,0x0c,0x0c,0x0c,0x0c,0x3f,0x00,0x1e,0x33,0x30,0x1c,0x06,0x33,0x3f,0x00,0x1e,0x33,0x30,0x1c,0x30,0x33,0x1e,0x00, + 0x38,0x3c,0x36,0x33,0x7f,0x30,0x78,0x00,0x3f,0x03,0x1f,0x30,0x30,0x33,0x1e,0x00,0x1c,0x06,0x03,0x1f,0x33,0x33,0x1e,0x00,0x3f,0x33,0x30,0x18,0x0c,0x0c,0x0c,0x00, + 0x1e,0x33,0x33,0x1e,0x33,0x33,0x1e,0x00,0x1e,0x33,0x33,0x3e,0x30,0x18,0x0e,0x00,0x00,0x0c,0x0c,0x00,0x00,0x0c,0x0c,0x00,0x00,0x0c,0x0c,0x00,0x00,0x0c,0x0c,0x06, + 0x18,0x0c,0x06,0x03,0x06,0x0c,0x18,0x00,0x00,0x00,0x3f,0x00,0x00,0x3f,0x00,0x00,0x06,0x0c,0x18,0x30,0x18,0x0c,0x06,0x00,0x1e,0x33,0x30,0x18,0x0c,0x00,0x0c,0x00, + 0x3e,0x63,0x7b,0x7b,0x7b,0x03,0x1e,0x00,0x0c,0x1e,0x33,0x33,0x3f,0x33,0x33,0x00,0x3f,0x66,0x66,0x3e,0x66,0x66,0x3f,0x00,0x3c,0x66,0x03,0x03,0x03,0x66,0x3c,0x00, + 0x1f,0x36,0x66,0x66,0x66,0x36,0x1f,0x00,0x7f,0x46,0x16,0x1e,0x16,0x46,0x7f,0x00,0x7f,0x46,0x16,0x1e,0x16,0x06,0x0f,0x00,0x3c,0x66,0x03,0x03,0x73,0x66,0x7c,0x00, + 0x33,0x33,0x33,0x3f,0x33,0x33,0x33,0x00,0x1e,0x0c,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x78,0x30,0x30,0x30,0x33,0x33,0x1e,0x00,0x67,0x66,0x36,0x1e,0x36,0x66,0x67,0x00, + 0x0f,0x06,0x06,0x06,0x46,0x66,0x7f,0x00,0x63,0x77,0x7f,0x7f,0x6b,0x63,0x63,0x00,0x63,0x67,0x6f,0x7b,0x73,0x63,0x63,0x00,0x1c,0x36,0x63,0x63,0x63,0x36,0x1c,0x00, + 0x3f,0x66,0x66,0x3e,0x06,0x06,0x0f,0x00,0x1e,0x33,0x33,0x33,0x3b,0x1e,0x38,0x00,0x3f,0x66,0x66,0x3e,0x36,0x66,0x67,0x00,0x1e,0x33,0x07,0x0e,0x38,0x33,0x1e,0x00, + 0x3f,0x2d,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x33,0x33,0x33,0x33,0x33,0x33,0x3f,0x00,0x33,0x33,0x33,0x33,0x33,0x1e,0x0c,0x00,0x63,0x63,0x63,0x6b,0x7f,0x77,0x63,0x00, + 0x63,0x63,0x36,0x1c,0x1c,0x36,0x63,0x00,0x33,0x33,0x33,0x1e,0x0c,0x0c,0x1e,0x00,0x7f,0x63,0x31,0x18,0x4c,0x66,0x7f,0x00,0x1e,0x06,0x06,0x06,0x06,0x06,0x1e,0x00, + 0x03,0x06,0x0c,0x18,0x30,0x60,0x40,0x00,0x1e,0x18,0x18,0x18,0x18,0x18,0x1e,0x00,0x08,0x1c,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff, + 0x0c,0x0c,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1e,0x30,0x3e,0x33,0x6e,0x00,0x07,0x06,0x06,0x3e,0x66,0x66,0x3b,0x00,0x00,0x00,0x1e,0x33,0x03,0x33,0x1e,0x00, + 0x38,0x30,0x30,0x3e,0x33,0x33,0x6e,0x00,0x00,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x1c,0x36,0x06,0x0f,0x06,0x06,0x0f,0x00,0x00,0x00,0x6e,0x33,0x33,0x3e,0x30,0x1f, + 0x07,0x06,0x36,0x6e,0x66,0x66,0x67,0x00,0x0c,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00,0x30,0x00,0x30,0x30,0x30,0x33,0x33,0x1e,0x07,0x06,0x66,0x36,0x1e,0x36,0x67,0x00, + 0x0e,0x0c,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x33,0x7f,0x7f,0x6b,0x63,0x00,0x00,0x00,0x1f,0x33,0x33,0x33,0x33,0x00,0x00,0x00,0x1e,0x33,0x33,0x33,0x1e,0x00, + 0x00,0x00,0x3b,0x66,0x66,0x3e,0x06,0x0f,0x00,0x00,0x6e,0x33,0x33,0x3e,0x30,0x78,0x00,0x00,0x3b,0x6e,0x66,0x06,0x0f,0x00,0x00,0x00,0x3e,0x03,0x1e,0x30,0x1f,0x00, + 0x08,0x0c,0x3e,0x0c,0x0c,0x2c,0x18,0x00,0x00,0x00,0x33,0x33,0x33,0x33,0x6e,0x00,0x00,0x00,0x33,0x33,0x33,0x1e,0x0c,0x00,0x00,0x00,0x63,0x6b,0x7f,0x7f,0x36,0x00, + 0x00,0x00,0x63,0x36,0x1c,0x36,0x63,0x00,0x00,0x00,0x33,0x33,0x33,0x3e,0x30,0x1f,0x00,0x00,0x3f,0x19,0x0c,0x26,0x3f,0x00,0x38,0x0c,0x0c,0x07,0x0c,0x0c,0x38,0x00, + 0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x00,0x07,0x0c,0x0c,0x38,0x0c,0x0c,0x07,0x00,0x6e,0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1c,0x36,0x63,0x63,0x7f,0x00, + 0x1e,0x33,0x03,0x33,0x1e,0x18,0x30,0x1e,0x00,0x33,0x00,0x33,0x33,0x33,0x7e,0x00,0x38,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x7e,0xc3,0x3c,0x60,0x7c,0x66,0xfc,0x00, + 0x33,0x00,0x1e,0x30,0x3e,0x33,0x7e,0x00,0x07,0x00,0x1e,0x30,0x3e,0x33,0x7e,0x00,0x0c,0x0c,0x1e,0x30,0x3e,0x33,0x7e,0x00,0x00,0x00,0x1e,0x03,0x03,0x1e,0x30,0x1c, + 0x7e,0xc3,0x3c,0x66,0x7e,0x06,0x3c,0x00,0x33,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x07,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x33,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00, + 0x3e,0x63,0x1c,0x18,0x18,0x18,0x3c,0x00,0x07,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00,0x63,0x1c,0x36,0x63,0x7f,0x63,0x63,0x00,0x0c,0x0c,0x00,0x1e,0x33,0x3f,0x33,0x00, + 0x38,0x00,0x3f,0x06,0x1e,0x06,0x3f,0x00,0x00,0x00,0xfe,0x30,0xfe,0x33,0xfe,0x00,0x7c,0x36,0x33,0x7f,0x33,0x33,0x73,0x00,0x1e,0x33,0x00,0x1e,0x33,0x33,0x1e,0x00, + 0x00,0x33,0x00,0x1e,0x33,0x33,0x1e,0x00,0x00,0x07,0x00,0x1e,0x33,0x33,0x1e,0x00,0x1e,0x33,0x00,0x33,0x33,0x33,0x7e,0x00,0x00,0x07,0x00,0x33,0x33,0x33,0x7e,0x00, + 0x00,0x33,0x00,0x33,0x33,0x3e,0x30,0x1f,0xc3,0x18,0x3c,0x66,0x66,0x3c,0x18,0x00,0x33,0x00,0x33,0x33,0x33,0x33,0x1e,0x00,0x18,0x18,0x7e,0x03,0x03,0x7e,0x18,0x18, + 0x1c,0x36,0x26,0x0f,0x06,0x67,0x3f,0x00,0x33,0x33,0x1e,0x3f,0x0c,0x3f,0x0c,0x0c,0x1f,0x33,0x33,0x5f,0x63,0xf3,0x63,0xe3,0x70,0xd8,0x18,0x3c,0x18,0x18,0x1b,0x0e, + 0x38,0x00,0x1e,0x30,0x3e,0x33,0x7e,0x00,0x1c,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x38,0x00,0x1e,0x33,0x33,0x1e,0x00,0x00,0x38,0x00,0x33,0x33,0x33,0x7e,0x00, + 0x00,0x1f,0x00,0x1f,0x33,0x33,0x33,0x00,0x3f,0x00,0x33,0x37,0x3f,0x3b,0x33,0x00,0x3c,0x36,0x36,0x7c,0x00,0x7e,0x00,0x00,0x1c,0x36,0x36,0x1c,0x00,0x3e,0x00,0x00, + 0x0c,0x00,0x0c,0x06,0x03,0x33,0x1e,0x00,0x00,0x00,0x00,0x3f,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x3f,0x30,0x30,0x00,0x00,0xc3,0x63,0x33,0x7b,0xcc,0x66,0x33,0xf0, + 0xc3,0x63,0x33,0xdb,0xec,0xf6,0xf3,0xc0,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x00,0x00,0xcc,0x66,0x33,0x66,0xcc,0x00,0x00,0x00,0x33,0x66,0xcc,0x66,0x33,0x00,0x00, + 0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xdb,0xee,0xdb,0x77,0xdb,0xee,0xdb,0x77,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + 0x18,0x18,0x18,0x18,0x1f,0x18,0x18,0x18,0x18,0x18,0x1f,0x18,0x1f,0x18,0x18,0x18,0x6c,0x6c,0x6c,0x6c,0x6f,0x6c,0x6c,0x6c,0x00,0x00,0x00,0x00,0x7f,0x6c,0x6c,0x6c, + 0x00,0x00,0x1f,0x18,0x1f,0x18,0x18,0x18,0x6c,0x6c,0x6f,0x60,0x6f,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x00,0x00,0x7f,0x60,0x6f,0x6c,0x6c,0x6c, + 0x6c,0x6c,0x6f,0x60,0x7f,0x00,0x00,0x00,0x6c,0x6c,0x6c,0x6c,0x7f,0x00,0x00,0x00,0x18,0x18,0x1f,0x18,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x18,0x18,0x18, + 0x18,0x18,0x18,0x18,0xf8,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0x18,0x18, + 0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0xff,0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0xf8,0x18,0x18,0x18,0x6c,0x6c,0x6c,0x6c,0xec,0x6c,0x6c,0x6c, + 0x6c,0x6c,0xec,0x0c,0xfc,0x00,0x00,0x00,0x00,0x00,0xfc,0x0c,0xec,0x6c,0x6c,0x6c,0x6c,0x6c,0xef,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xef,0x6c,0x6c,0x6c, + 0x6c,0x6c,0xec,0x0c,0xec,0x6c,0x6c,0x6c,0x00,0x00,0xff,0x00,0xff,0x00,0x00,0x00,0x6c,0x6c,0xef,0x00,0xef,0x6c,0x6c,0x6c,0x18,0x18,0xff,0x00,0xff,0x00,0x00,0x00, + 0x6c,0x6c,0x6c,0x6c,0xff,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0xff,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0xfc,0x00,0x00,0x00, + 0x18,0x18,0xf8,0x18,0xf8,0x00,0x00,0x00,0x00,0x00,0xf8,0x18,0xf8,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0xfc,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0xff,0x6c,0x6c,0x6c, + 0x18,0x18,0xff,0x18,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x18,0x18,0x18,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, + 0x00,0x00,0x6e,0x3b,0x13,0x3b,0x6e,0x00,0x00,0x1e,0x33,0x1f,0x33,0x1f,0x03,0x03,0x00,0x3f,0x33,0x03,0x03,0x03,0x03,0x00,0x00,0x7f,0x36,0x36,0x36,0x36,0x36,0x00, + 0x3f,0x33,0x06,0x0c,0x06,0x33,0x3f,0x00,0x00,0x00,0x7e,0x1b,0x1b,0x1b,0x0e,0x00,0x00,0x66,0x66,0x66,0x66,0x3e,0x06,0x03,0x00,0x6e,0x3b,0x18,0x18,0x18,0x18,0x00, + 0x3f,0x0c,0x1e,0x33,0x33,0x1e,0x0c,0x3f,0x1c,0x36,0x63,0x7f,0x63,0x36,0x1c,0x00,0x1c,0x36,0x63,0x63,0x36,0x36,0x77,0x00,0x38,0x0c,0x18,0x3e,0x33,0x33,0x1e,0x00, + 0x00,0x00,0x7e,0xdb,0xdb,0x7e,0x00,0x00,0x60,0x30,0x7e,0xdb,0xdb,0x7e,0x06,0x03,0x1c,0x06,0x03,0x1f,0x03,0x06,0x1c,0x00,0x1e,0x33,0x33,0x33,0x33,0x33,0x33,0x00, + 0x00,0x3f,0x00,0x3f,0x00,0x3f,0x00,0x00,0x0c,0x0c,0x3f,0x0c,0x0c,0x00,0x3f,0x00,0x06,0x0c,0x18,0x0c,0x06,0x00,0x3f,0x00,0x18,0x0c,0x06,0x0c,0x18,0x00,0x3f,0x00, + 0x70,0xd8,0xd8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1b,0x1b,0x0e,0x0c,0x0c,0x00,0x3f,0x00,0x0c,0x0c,0x00,0x00,0x6e,0x3b,0x00,0x6e,0x3b,0x00,0x00, + 0x1c,0x36,0x36,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0xf0,0x30,0x30,0x30,0x37,0x36,0x3c,0x38, + 0x1e,0x36,0x36,0x36,0x36,0x00,0x00,0x00,0x0e,0x18,0x0c,0x06,0x1e,0x00,0x00,0x00,0x00,0x00,0x3c,0x3c,0x3c,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; + +static const uint8 sstat[2541] = +{ + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, + 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80, + 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80, + 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83, + 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83, + 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83, + 0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x83, + 0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, + 0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83, + 0x83,0x83,0x83,0x81,0x83,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x83,0x83,0x81,0x80,0x83,0x83, + 0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83, + 0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83, + 0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83, + 0x83,0x81,0x81,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83, + 0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, + 0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81, + 0x83,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83, + 0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, + 0x83,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80, + 0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81, + 0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80, + 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83, + 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x80, + 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83, + 0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x81,0x81,0x83, + 0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x81,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83, + 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83, + 0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83, + 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83, + 0x83,0x83,0x81,0x81,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83, + 0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83, + 0x83,0x81,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83, + 0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83, + 0x81,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83, + 0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, + 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, + 0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80, + 0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81, + 0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80, + 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83, + 0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83, + 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, + 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83, + 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x81,0x81,0x83, + 0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83, + 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83, + 0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83, + 0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83, + 0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83, + 0x83,0x83,0x83,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, + 0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83, + 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83, + 0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83, + 0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83, + 0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81, + 0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83, + 0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, + 0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, + 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80, + 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83, + 0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83, + 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x81, + 0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83, + 0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83, + 0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, + 0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83, + 0x83,0x83,0x83,0x81,0x83,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83, + 0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83, + 0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83, + 0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83, + 0x83,0x83,0x81,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83, + 0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80 +}; + +void DrawTextTrans(uint8 *dest, uint32 width, uint8 *textmsg, uint8 fgcolor) { + uint8 length = strlen((char*)textmsg); + uint8 x; + uint8 y; + uint8 z; + + for (x = 0; x < length; x++) + for (y = 0; y < 8; y++) + for (z = 0; z < 8; z++) + if ((fontdata2[(textmsg[x] << 3) + y] >> z) & 1) dest[y * width + (x << 3) + z] = fgcolor; +} + +void FCEU_DrawNumberRow(uint8 *target, int *nstatus, int cur) { + uint8 *XBaf; + int z, x, y; + + XBaf = target - 4 + (FSettings.LastSLine - 34) * 256; + if (XBaf >= target) + for (z = 1; z < 11; z++) { + if (nstatus[z % 10]) { + for (y = 0; y < 13; y++) + for (x = 0; x < 21; x++) + XBaf[y * 256 + x + z * 21 + z] = sstat[y * 21 + x + (z - 1) * 21 * 12] ^ 0x80; + } else { + for (y = 0; y < 13; y++) + for (x = 0; x < 21; x++) + if (sstat[y * 21 + x + (z - 1) * 21 * 12] != 0x83) + XBaf[y * 256 + x + z * 21 + z] = sstat[y * 21 + x + (z - 1) * 21 * 12] ^ 0x80; + else + XBaf[y * 256 + x + z * 21 + z] = (XBaf[y * 256 + x + z * 21 + z] & 0xF) | 0xC0; + } + if (cur == z % 10) { + for (x = 0; x < 21; x++) + XBaf[x + z * 21 + z * 1] = 4; + for (x = 1; x < 12; x++) { + XBaf[256 * x + z * 21 + z * 1] = + XBaf[256 * x + z * 21 + z * 1 + 20] = 4; + } + for (x = 0; x < 21; x++) + XBaf[12 * 256 + x + z * 21 + z * 1] = 4; + } + } +} diff --git a/src/drawing.h b/src/drawing.h index 110dd4801..592cbf52f 100644 --- a/src/drawing.h +++ b/src/drawing.h @@ -1,201 +1,7 @@ #ifndef _FCEU_DRAWING_H #define _FCEU_DRAWING_H -uint8 fontdata2[2048] = -{ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x81,0xa5,0x81,0xbd,0x99,0x81,0x7e,0x7e,0xff,0xdb,0xff,0xc3,0xe7,0xff,0x7e,0x36,0x7f,0x7f,0x7f,0x3e,0x1c,0x08,0x00, - 0x08,0x1c,0x3e,0x7f,0x3e,0x1c,0x08,0x00,0x1c,0x3e,0x1c,0x7f,0x7f,0x3e,0x1c,0x3e,0x08,0x08,0x1c,0x3e,0x7f,0x3e,0x1c,0x3e,0x00,0x00,0x18,0x3c,0x3c,0x18,0x00,0x00, - 0xff,0xff,0xe7,0xc3,0xc3,0xe7,0xff,0xff,0x00,0x3c,0x66,0x42,0x42,0x66,0x3c,0x00,0xff,0xc3,0x99,0xbd,0xbd,0x99,0xc3,0xff,0xf0,0xe0,0xf0,0xbe,0x33,0x33,0x33,0x1e, - 0x3c,0x66,0x66,0x66,0x3c,0x18,0x7e,0x18,0xfc,0xcc,0xfc,0x0c,0x0c,0x0e,0x0f,0x07,0xfe,0xc6,0xfe,0xc6,0xc6,0xe6,0x67,0x03,0x99,0x5a,0x3c,0xe7,0xe7,0x3c,0x5a,0x99, - 0x01,0x07,0x1f,0x7f,0x1f,0x07,0x01,0x00,0x40,0x70,0x7c,0x7f,0x7c,0x70,0x40,0x00,0x18,0x3c,0x7e,0x18,0x18,0x7e,0x3c,0x18,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x00, - 0xfe,0xdb,0xdb,0xde,0xd8,0xd8,0xd8,0x00,0x7c,0xc6,0x1c,0x36,0x36,0x1c,0x33,0x1e,0x00,0x00,0x00,0x00,0x7e,0x7e,0x7e,0x00,0x18,0x3c,0x7e,0x18,0x7e,0x3c,0x18,0xff, - 0x18,0x3c,0x7e,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x7e,0x3c,0x18,0x00,0x00,0x18,0x30,0x7f,0x30,0x18,0x00,0x00,0x00,0x0c,0x06,0x7f,0x06,0x0c,0x00,0x00, - 0x00,0x00,0x03,0x03,0x03,0x7f,0x00,0x00,0x00,0x24,0x66,0xff,0x66,0x24,0x00,0x00,0x00,0x18,0x3c,0x7e,0xff,0xff,0x00,0x00,0x00,0xff,0xff,0x7e,0x3c,0x18,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x1e,0x1e,0x0c,0x0c,0x00,0x0c,0x00,0x36,0x36,0x36,0x00,0x00,0x00,0x00,0x00,0x36,0x36,0x7f,0x36,0x7f,0x36,0x36,0x00, - 0x0c,0x3e,0x03,0x1e,0x30,0x1f,0x0c,0x00,0x00,0x63,0x33,0x18,0x0c,0x66,0x63,0x00,0x1c,0x36,0x1c,0x6e,0x3b,0x33,0x6e,0x00,0x06,0x06,0x03,0x00,0x00,0x00,0x00,0x00, - 0x18,0x0c,0x06,0x06,0x06,0x0c,0x18,0x00,0x06,0x0c,0x18,0x18,0x18,0x0c,0x06,0x00,0x00,0x66,0x3c,0xff,0x3c,0x66,0x00,0x00,0x00,0x0c,0x0c,0x3f,0x0c,0x0c,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x0c,0x0c,0x06,0x00,0x00,0x00,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x0c,0x00,0x60,0x30,0x18,0x0c,0x06,0x03,0x01,0x00, - 0x3e,0x63,0x73,0x7b,0x6f,0x67,0x3e,0x00,0x0c,0x0e,0x0c,0x0c,0x0c,0x0c,0x3f,0x00,0x1e,0x33,0x30,0x1c,0x06,0x33,0x3f,0x00,0x1e,0x33,0x30,0x1c,0x30,0x33,0x1e,0x00, - 0x38,0x3c,0x36,0x33,0x7f,0x30,0x78,0x00,0x3f,0x03,0x1f,0x30,0x30,0x33,0x1e,0x00,0x1c,0x06,0x03,0x1f,0x33,0x33,0x1e,0x00,0x3f,0x33,0x30,0x18,0x0c,0x0c,0x0c,0x00, - 0x1e,0x33,0x33,0x1e,0x33,0x33,0x1e,0x00,0x1e,0x33,0x33,0x3e,0x30,0x18,0x0e,0x00,0x00,0x0c,0x0c,0x00,0x00,0x0c,0x0c,0x00,0x00,0x0c,0x0c,0x00,0x00,0x0c,0x0c,0x06, - 0x18,0x0c,0x06,0x03,0x06,0x0c,0x18,0x00,0x00,0x00,0x3f,0x00,0x00,0x3f,0x00,0x00,0x06,0x0c,0x18,0x30,0x18,0x0c,0x06,0x00,0x1e,0x33,0x30,0x18,0x0c,0x00,0x0c,0x00, - 0x3e,0x63,0x7b,0x7b,0x7b,0x03,0x1e,0x00,0x0c,0x1e,0x33,0x33,0x3f,0x33,0x33,0x00,0x3f,0x66,0x66,0x3e,0x66,0x66,0x3f,0x00,0x3c,0x66,0x03,0x03,0x03,0x66,0x3c,0x00, - 0x1f,0x36,0x66,0x66,0x66,0x36,0x1f,0x00,0x7f,0x46,0x16,0x1e,0x16,0x46,0x7f,0x00,0x7f,0x46,0x16,0x1e,0x16,0x06,0x0f,0x00,0x3c,0x66,0x03,0x03,0x73,0x66,0x7c,0x00, - 0x33,0x33,0x33,0x3f,0x33,0x33,0x33,0x00,0x1e,0x0c,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x78,0x30,0x30,0x30,0x33,0x33,0x1e,0x00,0x67,0x66,0x36,0x1e,0x36,0x66,0x67,0x00, - 0x0f,0x06,0x06,0x06,0x46,0x66,0x7f,0x00,0x63,0x77,0x7f,0x7f,0x6b,0x63,0x63,0x00,0x63,0x67,0x6f,0x7b,0x73,0x63,0x63,0x00,0x1c,0x36,0x63,0x63,0x63,0x36,0x1c,0x00, - 0x3f,0x66,0x66,0x3e,0x06,0x06,0x0f,0x00,0x1e,0x33,0x33,0x33,0x3b,0x1e,0x38,0x00,0x3f,0x66,0x66,0x3e,0x36,0x66,0x67,0x00,0x1e,0x33,0x07,0x0e,0x38,0x33,0x1e,0x00, - 0x3f,0x2d,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x33,0x33,0x33,0x33,0x33,0x33,0x3f,0x00,0x33,0x33,0x33,0x33,0x33,0x1e,0x0c,0x00,0x63,0x63,0x63,0x6b,0x7f,0x77,0x63,0x00, - 0x63,0x63,0x36,0x1c,0x1c,0x36,0x63,0x00,0x33,0x33,0x33,0x1e,0x0c,0x0c,0x1e,0x00,0x7f,0x63,0x31,0x18,0x4c,0x66,0x7f,0x00,0x1e,0x06,0x06,0x06,0x06,0x06,0x1e,0x00, - 0x03,0x06,0x0c,0x18,0x30,0x60,0x40,0x00,0x1e,0x18,0x18,0x18,0x18,0x18,0x1e,0x00,0x08,0x1c,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff, - 0x0c,0x0c,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1e,0x30,0x3e,0x33,0x6e,0x00,0x07,0x06,0x06,0x3e,0x66,0x66,0x3b,0x00,0x00,0x00,0x1e,0x33,0x03,0x33,0x1e,0x00, - 0x38,0x30,0x30,0x3e,0x33,0x33,0x6e,0x00,0x00,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x1c,0x36,0x06,0x0f,0x06,0x06,0x0f,0x00,0x00,0x00,0x6e,0x33,0x33,0x3e,0x30,0x1f, - 0x07,0x06,0x36,0x6e,0x66,0x66,0x67,0x00,0x0c,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00,0x30,0x00,0x30,0x30,0x30,0x33,0x33,0x1e,0x07,0x06,0x66,0x36,0x1e,0x36,0x67,0x00, - 0x0e,0x0c,0x0c,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x33,0x7f,0x7f,0x6b,0x63,0x00,0x00,0x00,0x1f,0x33,0x33,0x33,0x33,0x00,0x00,0x00,0x1e,0x33,0x33,0x33,0x1e,0x00, - 0x00,0x00,0x3b,0x66,0x66,0x3e,0x06,0x0f,0x00,0x00,0x6e,0x33,0x33,0x3e,0x30,0x78,0x00,0x00,0x3b,0x6e,0x66,0x06,0x0f,0x00,0x00,0x00,0x3e,0x03,0x1e,0x30,0x1f,0x00, - 0x08,0x0c,0x3e,0x0c,0x0c,0x2c,0x18,0x00,0x00,0x00,0x33,0x33,0x33,0x33,0x6e,0x00,0x00,0x00,0x33,0x33,0x33,0x1e,0x0c,0x00,0x00,0x00,0x63,0x6b,0x7f,0x7f,0x36,0x00, - 0x00,0x00,0x63,0x36,0x1c,0x36,0x63,0x00,0x00,0x00,0x33,0x33,0x33,0x3e,0x30,0x1f,0x00,0x00,0x3f,0x19,0x0c,0x26,0x3f,0x00,0x38,0x0c,0x0c,0x07,0x0c,0x0c,0x38,0x00, - 0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x00,0x07,0x0c,0x0c,0x38,0x0c,0x0c,0x07,0x00,0x6e,0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1c,0x36,0x63,0x63,0x7f,0x00, - 0x1e,0x33,0x03,0x33,0x1e,0x18,0x30,0x1e,0x00,0x33,0x00,0x33,0x33,0x33,0x7e,0x00,0x38,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x7e,0xc3,0x3c,0x60,0x7c,0x66,0xfc,0x00, - 0x33,0x00,0x1e,0x30,0x3e,0x33,0x7e,0x00,0x07,0x00,0x1e,0x30,0x3e,0x33,0x7e,0x00,0x0c,0x0c,0x1e,0x30,0x3e,0x33,0x7e,0x00,0x00,0x00,0x1e,0x03,0x03,0x1e,0x30,0x1c, - 0x7e,0xc3,0x3c,0x66,0x7e,0x06,0x3c,0x00,0x33,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x07,0x00,0x1e,0x33,0x3f,0x03,0x1e,0x00,0x33,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00, - 0x3e,0x63,0x1c,0x18,0x18,0x18,0x3c,0x00,0x07,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00,0x63,0x1c,0x36,0x63,0x7f,0x63,0x63,0x00,0x0c,0x0c,0x00,0x1e,0x33,0x3f,0x33,0x00, - 0x38,0x00,0x3f,0x06,0x1e,0x06,0x3f,0x00,0x00,0x00,0xfe,0x30,0xfe,0x33,0xfe,0x00,0x7c,0x36,0x33,0x7f,0x33,0x33,0x73,0x00,0x1e,0x33,0x00,0x1e,0x33,0x33,0x1e,0x00, - 0x00,0x33,0x00,0x1e,0x33,0x33,0x1e,0x00,0x00,0x07,0x00,0x1e,0x33,0x33,0x1e,0x00,0x1e,0x33,0x00,0x33,0x33,0x33,0x7e,0x00,0x00,0x07,0x00,0x33,0x33,0x33,0x7e,0x00, - 0x00,0x33,0x00,0x33,0x33,0x3e,0x30,0x1f,0xc3,0x18,0x3c,0x66,0x66,0x3c,0x18,0x00,0x33,0x00,0x33,0x33,0x33,0x33,0x1e,0x00,0x18,0x18,0x7e,0x03,0x03,0x7e,0x18,0x18, - 0x1c,0x36,0x26,0x0f,0x06,0x67,0x3f,0x00,0x33,0x33,0x1e,0x3f,0x0c,0x3f,0x0c,0x0c,0x1f,0x33,0x33,0x5f,0x63,0xf3,0x63,0xe3,0x70,0xd8,0x18,0x3c,0x18,0x18,0x1b,0x0e, - 0x38,0x00,0x1e,0x30,0x3e,0x33,0x7e,0x00,0x1c,0x00,0x0e,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x38,0x00,0x1e,0x33,0x33,0x1e,0x00,0x00,0x38,0x00,0x33,0x33,0x33,0x7e,0x00, - 0x00,0x1f,0x00,0x1f,0x33,0x33,0x33,0x00,0x3f,0x00,0x33,0x37,0x3f,0x3b,0x33,0x00,0x3c,0x36,0x36,0x7c,0x00,0x7e,0x00,0x00,0x1c,0x36,0x36,0x1c,0x00,0x3e,0x00,0x00, - 0x0c,0x00,0x0c,0x06,0x03,0x33,0x1e,0x00,0x00,0x00,0x00,0x3f,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x3f,0x30,0x30,0x00,0x00,0xc3,0x63,0x33,0x7b,0xcc,0x66,0x33,0xf0, - 0xc3,0x63,0x33,0xdb,0xec,0xf6,0xf3,0xc0,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x00,0x00,0xcc,0x66,0x33,0x66,0xcc,0x00,0x00,0x00,0x33,0x66,0xcc,0x66,0x33,0x00,0x00, - 0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xdb,0xee,0xdb,0x77,0xdb,0xee,0xdb,0x77,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, - 0x18,0x18,0x18,0x18,0x1f,0x18,0x18,0x18,0x18,0x18,0x1f,0x18,0x1f,0x18,0x18,0x18,0x6c,0x6c,0x6c,0x6c,0x6f,0x6c,0x6c,0x6c,0x00,0x00,0x00,0x00,0x7f,0x6c,0x6c,0x6c, - 0x00,0x00,0x1f,0x18,0x1f,0x18,0x18,0x18,0x6c,0x6c,0x6f,0x60,0x6f,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x00,0x00,0x7f,0x60,0x6f,0x6c,0x6c,0x6c, - 0x6c,0x6c,0x6f,0x60,0x7f,0x00,0x00,0x00,0x6c,0x6c,0x6c,0x6c,0x7f,0x00,0x00,0x00,0x18,0x18,0x1f,0x18,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x18,0x18,0x18, - 0x18,0x18,0x18,0x18,0xf8,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0x18,0x18, - 0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0xff,0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0xf8,0x18,0x18,0x18,0x6c,0x6c,0x6c,0x6c,0xec,0x6c,0x6c,0x6c, - 0x6c,0x6c,0xec,0x0c,0xfc,0x00,0x00,0x00,0x00,0x00,0xfc,0x0c,0xec,0x6c,0x6c,0x6c,0x6c,0x6c,0xef,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xef,0x6c,0x6c,0x6c, - 0x6c,0x6c,0xec,0x0c,0xec,0x6c,0x6c,0x6c,0x00,0x00,0xff,0x00,0xff,0x00,0x00,0x00,0x6c,0x6c,0xef,0x00,0xef,0x6c,0x6c,0x6c,0x18,0x18,0xff,0x00,0xff,0x00,0x00,0x00, - 0x6c,0x6c,0x6c,0x6c,0xff,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0xff,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0xfc,0x00,0x00,0x00, - 0x18,0x18,0xf8,0x18,0xf8,0x00,0x00,0x00,0x00,0x00,0xf8,0x18,0xf8,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0xfc,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0xff,0x6c,0x6c,0x6c, - 0x18,0x18,0xff,0x18,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x18,0x18,0x18,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, - 0x00,0x00,0x6e,0x3b,0x13,0x3b,0x6e,0x00,0x00,0x1e,0x33,0x1f,0x33,0x1f,0x03,0x03,0x00,0x3f,0x33,0x03,0x03,0x03,0x03,0x00,0x00,0x7f,0x36,0x36,0x36,0x36,0x36,0x00, - 0x3f,0x33,0x06,0x0c,0x06,0x33,0x3f,0x00,0x00,0x00,0x7e,0x1b,0x1b,0x1b,0x0e,0x00,0x00,0x66,0x66,0x66,0x66,0x3e,0x06,0x03,0x00,0x6e,0x3b,0x18,0x18,0x18,0x18,0x00, - 0x3f,0x0c,0x1e,0x33,0x33,0x1e,0x0c,0x3f,0x1c,0x36,0x63,0x7f,0x63,0x36,0x1c,0x00,0x1c,0x36,0x63,0x63,0x36,0x36,0x77,0x00,0x38,0x0c,0x18,0x3e,0x33,0x33,0x1e,0x00, - 0x00,0x00,0x7e,0xdb,0xdb,0x7e,0x00,0x00,0x60,0x30,0x7e,0xdb,0xdb,0x7e,0x06,0x03,0x1c,0x06,0x03,0x1f,0x03,0x06,0x1c,0x00,0x1e,0x33,0x33,0x33,0x33,0x33,0x33,0x00, - 0x00,0x3f,0x00,0x3f,0x00,0x3f,0x00,0x00,0x0c,0x0c,0x3f,0x0c,0x0c,0x00,0x3f,0x00,0x06,0x0c,0x18,0x0c,0x06,0x00,0x3f,0x00,0x18,0x0c,0x06,0x0c,0x18,0x00,0x3f,0x00, - 0x70,0xd8,0xd8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1b,0x1b,0x0e,0x0c,0x0c,0x00,0x3f,0x00,0x0c,0x0c,0x00,0x00,0x6e,0x3b,0x00,0x6e,0x3b,0x00,0x00, - 0x1c,0x36,0x36,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0xf0,0x30,0x30,0x30,0x37,0x36,0x3c,0x38, - 0x1e,0x36,0x36,0x36,0x36,0x00,0x00,0x00,0x0e,0x18,0x0c,0x06,0x1e,0x00,0x00,0x00,0x00,0x00,0x3c,0x3c,0x3c,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -}; - -void DrawTextTrans(uint8 *dest, uint32 width, uint8 *textmsg, uint8 fgcolor) { - uint8 length = strlen((char*)textmsg); - uint8 x; - uint8 y; - uint8 z; - - for (x = 0; x < length; x++) - for (y = 0; y < 8; y++) - for (z = 0; z < 8; z++) - if ((fontdata2[(textmsg[x] << 3) + y] >> z) & 1) dest[y * width + (x << 3) + z] = fgcolor; -} - -static uint8 sstat[2541] = -{ - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83, - 0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x83, - 0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, - 0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83, - 0x83,0x83,0x83,0x81,0x83,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x83,0x83,0x81,0x80,0x83,0x83, - 0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83, - 0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83, - 0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83, - 0x83,0x81,0x81,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83, - 0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, - 0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81, - 0x83,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83, - 0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, - 0x83,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80, - 0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81, - 0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x80, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83, - 0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x81,0x81,0x83, - 0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x81,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83, - 0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83, - 0x83,0x83,0x81,0x81,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83, - 0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83, - 0x83,0x81,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83, - 0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83, - 0x81,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83, - 0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, - 0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80, - 0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81, - 0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83, - 0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x81,0x81,0x83, - 0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83, - 0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83, - 0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83, - 0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83, - 0x83,0x83,0x83,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, - 0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83, - 0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83, - 0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83, - 0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81, - 0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83, - 0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, - 0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83, - 0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83, - 0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x81, - 0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83, - 0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83, - 0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83, - 0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x81,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83, - 0x83,0x83,0x83,0x81,0x83,0x80,0x80,0x81,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83, - 0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83, - 0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83, - 0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x81,0x80,0x83,0x83,0x81,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83, - 0x83,0x83,0x81,0x81,0x81,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x83,0x83,0x83,0x83,0x83, - 0x83,0x83,0x80,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, - 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80 -}; - -void FCEU_DrawNumberRow(uint8 *XBuf, int *nstatus, int cur) { - uint8 *XBaf; - int z, x, y; - - XBaf = XBuf - 4 + (FSettings.LastSLine - 34) * 256; - if (XBaf >= XBuf) - for (z = 1; z < 11; z++) { - if (nstatus[z % 10]) { - for (y = 0; y < 13; y++) - for (x = 0; x < 21; x++) - XBaf[y * 256 + x + z * 21 + z] = sstat[y * 21 + x + (z - 1) * 21 * 12] ^ 0x80; - } else { - for (y = 0; y < 13; y++) - for (x = 0; x < 21; x++) - if (sstat[y * 21 + x + (z - 1) * 21 * 12] != 0x83) - XBaf[y * 256 + x + z * 21 + z] = sstat[y * 21 + x + (z - 1) * 21 * 12] ^ 0x80; - else - XBaf[y * 256 + x + z * 21 + z] = (XBaf[y * 256 + x + z * 21 + z] & 0xF) | 0xC0; - } - if (cur == z % 10) { - for (x = 0; x < 21; x++) - XBaf[x + z * 21 + z * 1] = 4; - for (x = 1; x < 12; x++) { - XBaf[256 * x + z * 21 + z * 1] = - XBaf[256 * x + z * 21 + z * 1 + 20] = 4; - } - for (x = 0; x < 21; x++) - XBaf[12 * 256 + x + z * 21 + z * 1] = 4; - } - } -} - +void DrawTextTrans(uint8 *dest, uint32 width, uint8 *textmsg, uint8 fgcolor); +void FCEU_DrawNumberRow(uint8 *target, int *nstatus, int cur); #endif diff --git a/src/driver.h b/src/driver.h index 9da57b452..dec37c775 100644 --- a/src/driver.h +++ b/src/driver.h @@ -10,11 +10,14 @@ extern "C" { #include "fceu-types.h" #include "git.h" #include "debug.h" +#include "palette.h" #define FCEUNPCMD_RESET 0x01 #define FCEUNPCMD_POWER 0x02 #define FCEUNPCMD_VSUNICOIN 0x07 +#define FCEUNPCMD_VSUNICOIN2 0x20 +#define FCEUNPCMD_VSUNISERVICE 0x21 #define FCEUNPCMD_VSUNIDIP0 0x08 #define FCEUNPCMD_FDSINSERTx 0x10 #define FCEUNPCMD_FDSINSERT 0x18 @@ -32,10 +35,12 @@ void FCEU_printf(char *format, ...); #define FCEUI_printf FCEU_printf /* Video interface */ -void FCEUD_SetPalette(uint8 index, uint8 r, uint8 g, uint8 b); +void FCEUD_SetPalette(int index, uint8 r, uint8 g, uint8 b); +void FCEUD_SetPaletteFull(int index, uint8 r, uint8 g, uint8 b); /* Displays an error. Can block or not. */ void FCEUD_PrintError(char *s); +void FCEUD_PrintDebug(char *s); void FCEUD_Message(char *s); void FCEUD_DispMessage(enum retro_log_level level, unsigned duration, const char *str); @@ -46,51 +51,16 @@ void FCEUI_PowerNES(void); void FCEUI_SetInput(int port, int type, void *ptr, int attrib); void FCEUI_SetInputFC(int type, void *ptr, int attrib); -void FCEUI_DisableFourScore(int s); - -#define SI_UNSET -1 -#define SI_NONE 0 -#define SI_GAMEPAD 1 -#define SI_ZAPPER 2 -#define SI_POWERPADA 3 -#define SI_POWERPADB 4 -#define SI_ARKANOID 5 -#define SI_MOUSE 6 -#define SI_LCDCOMP_ZAPPER 7 -#define SI_SNES_MOUSE 8 -#define SI_SNES_GAMEPAD 9 -#define SI_VIRTUALBOY 10 - -#define SIFC_UNSET -1 -#define SIFC_NONE 0 -#define SIFC_ARKANOID 1 -#define SIFC_SHADOW 2 -#define SIFC_4PLAYER 3 -#define SIFC_FKB 4 -#define SIFC_SUBORKB 5 -#define SIFC_PEC586KB 6 -#define SIFC_HYPERSHOT 7 -#define SIFC_MAHJONG 8 -#define SIFC_QUIZKING 9 -#define SIFC_FTRAINERA 10 -#define SIFC_FTRAINERB 11 -#define SIFC_OEKAKIDS 12 -#define SIFC_BWORLD 13 -#define SIFC_TOPRIDER 14 - -#define SIS_NONE 0 -#define SIS_DATACH 1 -#define SIS_NWC 2 -#define SIS_VSUNISYSTEM 3 -#define SIS_NSF 4 +void FCEUI_SetInputFourScore(int useFourScore); /* New interface functions */ /* 0 to keep 8-sprites limitation, 1 to remove it */ void FCEUI_DisableSpriteLimitation(int a); -/* -1 = no change, 0 = show, 1 = hide, 2 = internal toggle */ -void FCEUI_SetRenderDisable(int sprites, int bg); +/* 1 = show, 0 = hide */ +void FCEUI_SetRenderPlanes(int sprites, int bg); +void FCEUI_GetRenderPlanes(int *sprites, int *bg); /* frontend_post_load_init_cb() is called immediately * after loading the ROM, allowing any frontend @@ -105,7 +75,7 @@ FCEUGI *FCEUI_LoadGame(const char *name, const uint8_t *databuf, size_t databufs int FCEUI_Initialize(void); /* Emulates a frame. */ -void FCEUI_Emulate(uint8 **, int32 **, int32 *, int); +void FCEUI_Emulate(uint8 **, uint8 **, int32 **, int32 *, int); /* Closes currently loaded game */ void FCEUI_CloseGame(void); @@ -138,19 +108,24 @@ void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall); void FCEUI_SetBaseDirectory(const char *dir); /* Tells FCE Ultra to copy the palette data pointed to by pal and use it. - Data pointed to by pal needs to be 64*3 bytes in length. + Data pointed to by pal needs to be 64*3 or 512x3 bytes in length. */ -void FCEUI_SetPaletteArray(uint8 *pal); +void FCEUI_SetPaletteUser(pal *data, int Entries); /* Sets up sound code to render sound at the specified rate, in samples per second. Only sample rates of 44100, 48000, and 96000 are currently supported. - If "Rate" equals 0, sound is disabled. -*/ + If "Rate" equals 0, sound is disabled. */ void FCEUI_Sound(int Rate); -void FCEUI_SetSoundVolume(uint32 volume); void FCEUI_SetSoundQuality(int quality); +/* Sets up volume on each sound channel. + If "volume" equals 0, then sound for that channel is muted. Max volume is 256. */ +void FCEUI_SetSoundVolume(int channel, int volume); + +/* Gets the current volume of the specific audio channel. */ +int FCEUI_GetSoundVolume(int channel); + int32 FCEUI_GetDesiredFPS(void); int FCEUI_DecodePAR(const char *code, uint16 *a, uint8 *v, int *c, int *type); @@ -193,9 +168,11 @@ void FCEUI_VSUniToggleDIP(int w); uint8 FCEUI_VSUniGetDIPs(void); void FCEUI_VSUniSetDIP(int w, int state); void FCEUI_VSUniCoin(void); +void FCEUI_VSUniCoin2(void); +void FCEUI_VSUniService(void); -int FCEUI_FDSInsert(int oride); -int FCEUI_FDSEject(void); +void FCEUI_FDSInsert(void); +void FCEUI_FDSEject(void); void FCEUI_FDSSelect(void); int FCEUI_DatachSet(uint8 *rcode); diff --git a/src/drivers/libretro/libretro.c b/src/drivers/libretro/libretro.c deleted file mode 100644 index a6a6c3f6c..000000000 --- a/src/drivers/libretro/libretro.c +++ /dev/null @@ -1,3703 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#ifdef _MSC_VER -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "../../fceu.h" -#include "../../fceu-endian.h" -#include "../../input.h" -#include "../../state.h" -#include "../../ppu.h" -#include "../../cart.h" -#include "../../x6502.h" -#include "../../git.h" -#include "../../palette.h" -#include "../../sound.h" -#include "../../file.h" -#include "../../cheat.h" -#include "../../ines.h" -#include "../../unif.h" -#include "../../fds.h" -#include "../../vsuni.h" -#include "../../video.h" - -#ifdef PSP -#include "pspgu.h" -#endif - -#if defined(RENDER_GSKIT_PS2) -#include "libretro-common/include/libretro_gskit_ps2.h" -#endif - -#define MAX_PLAYERS 4 /* max supported players */ -#define MAX_PORTS 2 /* max controller ports, - * port 0 for player 1/3, port 1 for player 2/4 */ - -#define DEVICE_AUTO RETRO_DEVICE_JOYPAD -#define DEVICE_GAMEPAD RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 0) -#define DEVICE_HYPERSHOT RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 1) -#define DEVICE_4PLAYER RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 2) -#define DEVICE_POWERPADA RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 3) -#define DEVICE_POWERPADB RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 4) -#define DEVICE_FTRAINERA RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 5) -#define DEVICE_FTRAINERB RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 6) -#define DEVICE_QUIZKING RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 7) -#define DEVICE_SNESGAMEPAD RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 8) -#define DEVICE_VIRTUALBOY RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 9) - -#define DEVICE_SNESMOUSE RETRO_DEVICE_MOUSE -#define DEVICE_ZAPPER RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_MOUSE, 0) -#define DEVICE_ARKANOID RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_MOUSE, 1) -#define DEVICE_OEKAKIDS RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_MOUSE, 2) -#define DEVICE_SHADOW RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_MOUSE, 3) - -#define NES_WIDTH 256 -#define NES_HEIGHT 240 -#define NES_8_7_PAR ((width * (8.0 / 7.0)) / height) -#define NES_4_3 ((width / (height * (256.0 / 240.0))) * 4.0 / 3.0) -#define NES_PP ((width / (height * (256.0 / 240.0))) * 16.0 / 15.0) - -#define NES_PAL_FPS (838977920.0 / 16777215.0) -#define NES_NTSC_FPS (1008307711.0 / 16777215.0) - -#if defined(_3DS) -void* linearMemAlign(size_t size, size_t alignment); -void linearFree(void* mem); -#endif - -#if defined(RENDER_GSKIT_PS2) -RETRO_HW_RENDER_INTEFACE_GSKIT_PS2 *ps2 = NULL; -#endif - -extern void FCEU_ZapperSetTolerance(int t); - -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; -retro_environment_t environ_cb = NULL; - -#ifdef PSP -static bool crop_overscan; -#endif - -static int overscan_left; -static int overscan_right; -static int overscan_top; -static int overscan_bottom; - -static bool use_raw_palette; -static int aspect_ratio_par; - -/* - * Flags to keep track of whether turbo - * buttons toggled on or off. - * - * There are two values in array - * for Turbo A and Turbo B for - * each player - */ - -#define MAX_BUTTONS 9 -#define TURBO_BUTTONS 2 -unsigned char turbo_button_toggle[MAX_PLAYERS][TURBO_BUTTONS] = { {0} }; - -typedef struct -{ - unsigned retro; - unsigned nes; -} keymap; - -static const keymap turbomap[] = { - { RETRO_DEVICE_ID_JOYPAD_X, JOY_A }, - { RETRO_DEVICE_ID_JOYPAD_Y, JOY_B }, -}; - -typedef struct { - bool enable_4player; /* four-score / 4-player adapter used */ - bool up_down_allowed; /* disabled simultaneous up+down and left+right dpad combinations */ - bool needs_update; - - /* turbo related */ - uint32_t turbo_enabler[MAX_PLAYERS]; - uint32_t turbo_delay; - - uint32_t type[MAX_PLAYERS + 1]; /* 4-players + famicom expansion */ - - /* input data */ - uint32_t JSReturn; /* player input data, 1 byte per player (1-4) */ - uint32_t JoyButtons[2]; - uint32_t MouseData[MAX_PORTS][3]; /* nes mouse data */ - uint32_t FamicomData[3]; /* Famicom expansion port data */ - uint32_t PowerPadData[2]; /* NES Power Pad data */ - uint32_t FTrainerData; /* Expansion: Family Trainer Data */ - uint8_t QuizKingData; /* Expansion: Quiz King Data */ -} NES_INPUT_T; - -static NES_INPUT_T nes_input = { 0 }; -enum RetroZapperInputModes{RetroLightgun, RetroMouse, RetroPointer}; -static enum RetroZapperInputModes zappermode = RetroLightgun; -enum RetroArkanoidInputModes{RetroArkanoidMouse, RetroArkanoidPointer, RetroArkanoidAbsMouse, RetroArkanoidStelladaptor}; -enum RetroArkanoidInputModes arkanoidmode = RetroArkanoidMouse; -static int mouseSensitivity = 100; - -static bool libretro_supports_bitmasks = false; -static bool libretro_supports_option_categories = false; -static unsigned libretro_msg_interface_version = 0; - -/* emulator-specific variables */ - -const size_t PPU_BIT = 1ULL << 31ULL; - -extern uint8 NTARAM[0x800], PALRAM[0x20], SPRAM[0x100], PPU[4]; - -unsigned dendy = 0; - -static unsigned systemRegion = 0; -static unsigned opt_region = 0; -static bool opt_showAdvSoundOptions = true; -static bool opt_showAdvSystemOptions = true; - -#if defined(PSP) || defined(PS2) -static __attribute__((aligned(16))) uint16_t retro_palette[256]; -#else -static uint16_t retro_palette[256]; -#endif -#if defined(RENDER_GSKIT_PS2) -static uint8_t* fceu_video_out; -#else -static uint16_t* fceu_video_out; -#endif - -/* Some timing-related variables. */ -static unsigned sndsamplerate; -static unsigned sndquality; -static unsigned sndvolume; -unsigned swapDuty; - -static int32_t *sound = 0; -static uint32_t Dummy = 0; -static uint32_t current_palette = 0; -static unsigned serialize_size; - -/* extern forward decls.*/ -extern FCEUGI *GameInfo; -extern uint8 *XBuf; -extern CartInfo iNESCart; -extern CartInfo UNIFCart; -extern int show_crosshair; -extern int option_ramstate; - -/* emulator-specific callback functions */ - -const char * GetKeyboard(void) -{ - return ""; -} - -#define BUILD_PIXEL_RGB565(R,G,B) (((int) ((R)&0x1f) << RED_SHIFT) | ((int) ((G)&0x3f) << GREEN_SHIFT) | ((int) ((B)&0x1f) << BLUE_SHIFT)) - -#if defined (PSP) -#define RED_SHIFT 0 -#define GREEN_SHIFT 5 -#define BLUE_SHIFT 11 -#define RED_EXPAND 3 -#define GREEN_EXPAND 2 -#define BLUE_EXPAND 3 -#elif defined (FRONTEND_SUPPORTS_ABGR1555) -#define RED_SHIFT 0 -#define GREEN_SHIFT 5 -#define BLUE_SHIFT 10 -#define RED_EXPAND 3 -#define GREEN_EXPAND 3 -#define BLUE_EXPAND 3 -#define RED_MASK 0x1F -#define GREEN_MASK 0x3E0 -#define BLUE_MASK 0x7C00 -#elif defined (FRONTEND_SUPPORTS_RGB565) -#define RED_SHIFT 11 -#define GREEN_SHIFT 5 -#define BLUE_SHIFT 0 -#define RED_EXPAND 3 -#define GREEN_EXPAND 2 -#define BLUE_EXPAND 3 -#define RED_MASK 0xF800 -#define GREEN_MASK 0x7e0 -#define BLUE_MASK 0x1f -#else -#define RED_SHIFT 10 -#define GREEN_SHIFT 5 -#define BLUE_SHIFT 0 -#define RED_EXPAND 3 -#define GREEN_EXPAND 3 -#define BLUE_EXPAND 3 -#endif - -void FCEUD_SetPalette(uint8_t index, uint8_t r, uint8_t g, uint8_t b) -{ - unsigned char index_to_write = index; -#if defined(RENDER_GSKIT_PS2) - /* Index correction for PS2 GS */ - int modi = index & 63; - if ((modi >= 8 && modi < 16) || (modi >= 40 && modi < 48)) { - index_to_write += 8; - } else if ((modi >= 16 && modi < 24) || (modi >= 48 && modi < 56)) { - index_to_write -= 8; - } -#endif - -#ifdef FRONTEND_SUPPORTS_RGB565 - retro_palette[index_to_write] = BUILD_PIXEL_RGB565(r >> RED_EXPAND, g >> GREEN_EXPAND, b >> BLUE_EXPAND); -#else - retro_palette[index_to_write] = - ((r >> RED_EXPAND) << RED_SHIFT) | ((g >> GREEN_EXPAND) << GREEN_SHIFT) | ((b >> BLUE_EXPAND) << BLUE_SHIFT); -#endif -} - -static struct retro_log_callback log_cb; - -static void default_logger(enum retro_log_level level, const char *fmt, ...) {} - -void FCEUD_PrintError(char *c) -{ - log_cb.log(RETRO_LOG_WARN, "%s", c); -} - -void FCEUD_Message(char *s) -{ - log_cb.log(RETRO_LOG_INFO, "%s", s); -} - -void FCEUD_DispMessage(enum retro_log_level level, unsigned duration, const char *str) -{ - if (!environ_cb) - return; - - if (libretro_msg_interface_version >= 1) - { - struct retro_message_ext msg; - unsigned priority; - - switch (level) - { - case RETRO_LOG_ERROR: - priority = 5; - break; - case RETRO_LOG_WARN: - priority = 4; - break; - case RETRO_LOG_INFO: - priority = 3; - break; - case RETRO_LOG_DEBUG: - default: - priority = 1; - break; - } - - msg.msg = str; - msg.duration = duration; - msg.priority = priority; - msg.level = level; - msg.target = RETRO_MESSAGE_TARGET_OSD; - msg.type = RETRO_MESSAGE_TYPE_NOTIFICATION_ALT; - msg.progress = -1; - - environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE_EXT, &msg); - } - else - { - float fps = (FSettings.PAL || dendy) ? NES_PAL_FPS : NES_NTSC_FPS; - unsigned frames = (unsigned)(((float)duration * fps / 1000.0f) + 0.5f); - struct retro_message msg; - - msg.msg = str; - msg.frames = frames; - - environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, &msg); - } -} - -void FCEUD_SoundToggle (void) -{ - FCEUI_SetSoundVolume(sndvolume); -} - -/*palette for FCEU*/ -#define PAL_INTERNAL (int)(sizeof(palettes) / sizeof(palettes[0])) /* Number of palettes in palettes[] */ -#define PAL_DEFAULT (PAL_INTERNAL + 1) -#define PAL_RAW (PAL_INTERNAL + 2) -#define PAL_CUSTOM (PAL_INTERNAL + 3) -#define PAL_TOTAL PAL_CUSTOM - -static int external_palette_exist = 0; -extern int ipalette; - -/* table for currently loaded palette */ -static uint8_t base_palette[192]; - -struct st_palettes { - char name[32]; - char desc[32]; - unsigned int data[64]; -}; - -struct st_palettes palettes[] = { - { "asqrealc", "AspiringSquire's Real palette", - { 0x6c6c6c, 0x00268e, 0x0000a8, 0x400094, - 0x700070, 0x780040, 0x700000, 0x621600, - 0x442400, 0x343400, 0x005000, 0x004444, - 0x004060, 0x000000, 0x101010, 0x101010, - 0xbababa, 0x205cdc, 0x3838ff, 0x8020f0, - 0xc000c0, 0xd01474, 0xd02020, 0xac4014, - 0x7c5400, 0x586400, 0x008800, 0x007468, - 0x00749c, 0x202020, 0x101010, 0x101010, - 0xffffff, 0x4ca0ff, 0x8888ff, 0xc06cff, - 0xff50ff, 0xff64b8, 0xff7878, 0xff9638, - 0xdbab00, 0xa2ca20, 0x4adc4a, 0x2ccca4, - 0x1cc2ea, 0x585858, 0x101010, 0x101010, - 0xffffff, 0xb0d4ff, 0xc4c4ff, 0xe8b8ff, - 0xffb0ff, 0xffb8e8, 0xffc4c4, 0xffd4a8, - 0xffe890, 0xf0f4a4, 0xc0ffc0, 0xacf4f0, - 0xa0e8ff, 0xc2c2c2, 0x202020, 0x101010 } - }, - { "nintendo-vc", "Virtual Console palette", - { 0x494949, 0x00006a, 0x090063, 0x290059, - 0x42004a, 0x490000, 0x420000, 0x291100, - 0x182700, 0x003010, 0x003000, 0x002910, - 0x012043, 0x000000, 0x000000, 0x000000, - 0x747174, 0x003084, 0x3101ac, 0x4b0194, - 0x64007b, 0x6b0039, 0x6b2101, 0x5a2f00, - 0x424900, 0x185901, 0x105901, 0x015932, - 0x01495a, 0x101010, 0x000000, 0x000000, - 0xadadad, 0x4a71b6, 0x6458d5, 0x8450e6, - 0xa451ad, 0xad4984, 0xb5624a, 0x947132, - 0x7b722a, 0x5a8601, 0x388e31, 0x318e5a, - 0x398e8d, 0x383838, 0x000000, 0x000000, - 0xb6b6b6, 0x8c9db5, 0x8d8eae, 0x9c8ebc, - 0xa687bc, 0xad8d9d, 0xae968c, 0x9c8f7c, - 0x9c9e72, 0x94a67c, 0x84a77b, 0x7c9d84, - 0x73968d, 0xdedede, 0x000000, 0x000000 } - }, - { "rgb", "Nintendo RGB PPU palette", - { 0x6D6D6D, 0x002492, 0x0000DB, 0x6D49DB, - 0x92006D, 0xB6006D, 0xB62400, 0x924900, - 0x6D4900, 0x244900, 0x006D24, 0x009200, - 0x004949, 0x000000, 0x000000, 0x000000, - 0xB6B6B6, 0x006DDB, 0x0049FF, 0x9200FF, - 0xB600FF, 0xFF0092, 0xFF0000, 0xDB6D00, - 0x926D00, 0x249200, 0x009200, 0x00B66D, - 0x009292, 0x242424, 0x000000, 0x000000, - 0xFFFFFF, 0x6DB6FF, 0x9292FF, 0xDB6DFF, - 0xFF00FF, 0xFF6DFF, 0xFF9200, 0xFFB600, - 0xDBDB00, 0x6DDB00, 0x00FF00, 0x49FFDB, - 0x00FFFF, 0x494949, 0x000000, 0x000000, - 0xFFFFFF, 0xB6DBFF, 0xDBB6FF, 0xFFB6FF, - 0xFF92FF, 0xFFB6B6, 0xFFDB92, 0xFFFF49, - 0xFFFF6D, 0xB6FF49, 0x92FF6D, 0x49FFDB, - 0x92DBFF, 0x929292, 0x000000, 0x000000 } - }, - { "sony-cxa2025as-us", "Sony CXA2025AS US palette", - { 0x585858, 0x00238C, 0x00139B, 0x2D0585, - 0x5D0052, 0x7A0017, 0x7A0800, 0x5F1800, - 0x352A00, 0x093900, 0x003F00, 0x003C22, - 0x00325D, 0x000000, 0x000000, 0x000000, - 0xA1A1A1, 0x0053EE, 0x153CFE, 0x6028E4, - 0xA91D98, 0xD41E41, 0xD22C00, 0xAA4400, - 0x6C5E00, 0x2D7300, 0x007D06, 0x007852, - 0x0069A9, 0x000000, 0x000000, 0x000000, - 0xFFFFFF, 0x1FA5FE, 0x5E89FE, 0xB572FE, - 0xFE65F6, 0xFE6790, 0xFE773C, 0xFE9308, - 0xC4B200, 0x79CA10, 0x3AD54A, 0x11D1A4, - 0x06BFFE, 0x424242, 0x000000, 0x000000, - 0xFFFFFF, 0xA0D9FE, 0xBDCCFE, 0xE1C2FE, - 0xFEBCFB, 0xFEBDD0, 0xFEC5A9, 0xFED18E, - 0xE9DE86, 0xC7E992, 0xA8EEB0, 0x95ECD9, - 0x91E4FE, 0xACACAC, 0x000000, 0x000000 } - }, - { "pal", "PAL palette", - { 0x808080, 0x0000BA, 0x3700BF, 0x8400A6, - 0xBB006A, 0xB7001E, 0xB30000, 0x912600, - 0x7B2B00, 0x003E00, 0x00480D, 0x003C22, - 0x002F66, 0x000000, 0x050505, 0x050505, - 0xC8C8C8, 0x0059FF, 0x443CFF, 0xB733CC, - 0xFE33AA, 0xFE375E, 0xFE371A, 0xD54B00, - 0xC46200, 0x3C7B00, 0x1D8415, 0x009566, - 0x0084C4, 0x111111, 0x090909, 0x090909, - 0xFEFEFE, 0x0095FF, 0x6F84FF, 0xD56FFF, - 0xFE77CC, 0xFE6F99, 0xFE7B59, 0xFE915F, - 0xFEA233, 0xA6BF00, 0x51D96A, 0x4DD5AE, - 0x00D9FF, 0x666666, 0x0D0D0D, 0x0D0D0D, - 0xFEFEFE, 0x84BFFF, 0xBBBBFF, 0xD0BBFF, - 0xFEBFEA, 0xFEBFCC, 0xFEC4B7, 0xFECCAE, - 0xFED9A2, 0xCCE199, 0xAEEEB7, 0xAAF8EE, - 0xB3EEFF, 0xDDDDDD, 0x111111, 0x111111 } - }, - { "bmf-final2", "BMF's Final 2 palette", - { 0x525252, 0x000080, 0x08008A, 0x2C007E, - 0x4A004E, 0x500006, 0x440000, 0x260800, - 0x0A2000, 0x002E00, 0x003200, 0x00260A, - 0x001C48, 0x000000, 0x000000, 0x000000, - 0xA4A4A4, 0x0038CE, 0x3416EC, 0x5E04DC, - 0x8C00B0, 0x9A004C, 0x901800, 0x703600, - 0x4C5400, 0x0E6C00, 0x007400, 0x006C2C, - 0x005E84, 0x000000, 0x000000, 0x000000, - 0xFFFFFF, 0x4C9CFF, 0x7C78FF, 0xA664FF, - 0xDA5AFF, 0xF054C0, 0xF06A56, 0xD68610, - 0xBAA400, 0x76C000, 0x46CC1A, 0x2EC866, - 0x34C2BE, 0x3A3A3A, 0x000000, 0x000000, - 0xFFFFFF, 0xB6DAFF, 0xC8CAFF, 0xDAC2FF, - 0xF0BEFF, 0xFCBCEE, 0xFAC2C0, 0xF2CCA2, - 0xE6DA92, 0xCCE68E, 0xB8EEA2, 0xAEEABE, - 0xAEE8E2, 0xB0B0B0, 0x000000, 0x000000 } - }, - { "bmf-final3", "BMF's Final 3 palette", - { 0x686868, 0x001299, 0x1A08AA, 0x51029A, - 0x7E0069, 0x8E001C, 0x7E0301, 0x511800, - 0x1F3700, 0x014E00, 0x005A00, 0x00501C, - 0x004061, 0x000000, 0x000000, 0x000000, - 0xB9B9B9, 0x0C5CD7, 0x5035F0, 0x8919E0, - 0xBB0CB3, 0xCE0C61, 0xC02B0E, 0x954D01, - 0x616F00, 0x1F8B00, 0x01980C, 0x00934B, - 0x00819B, 0x000000, 0x000000, 0x000000, - 0xFFFFFF, 0x63B4FF, 0x9B91FF, 0xD377FF, - 0xEF6AFF, 0xF968C0, 0xF97D6C, 0xED9B2D, - 0xBDBD16, 0x7CDA1C, 0x4BE847, 0x35E591, - 0x3FD9DD, 0x606060, 0x000000, 0x000000, - 0xFFFFFF, 0xACE7FF, 0xD5CDFF, 0xEDBAFF, - 0xF8B0FF, 0xFEB0EC, 0xFDBDB5, 0xF9D28E, - 0xE8EB7C, 0xBBF382, 0x99F7A2, 0x8AF5D0, - 0x92F4F1, 0xBEBEBE, 0x000000, 0x000000 } - }, - { "nescap", "RGBSource's NESCAP palette", - { 0x646365, 0x001580, 0x1D0090, 0x380082, - 0x56005D, 0x5A001A, 0x4F0900, 0x381B00, - 0x1E3100, 0x003D00, 0x004100, 0x003A1B, - 0x002F55, 0x000000, 0x000000, 0x000000, - 0xAFADAF, 0x164BCA, 0x472AE7, 0x6B1BDB, - 0x9617B0, 0x9F185B, 0x963001, 0x7B4800, - 0x5A6600, 0x237800, 0x017F00, 0x00783D, - 0x006C8C, 0x000000, 0x000000, 0x000000, - 0xFFFFFF, 0x60A6FF, 0x8F84FF, 0xB473FF, - 0xE26CFF, 0xF268C3, 0xEF7E61, 0xD89527, - 0xBAB307, 0x81C807, 0x57D43D, 0x47CF7E, - 0x4BC5CD, 0x4C4B4D, 0x000000, 0x000000, - 0xFFFFFF, 0xC2E0FF, 0xD5D2FF, 0xE3CBFF, - 0xF7C8FF, 0xFEC6EE, 0xFECEC6, 0xF6D7AE, - 0xE9E49F, 0xD3ED9D, 0xC0F2B2, 0xB9F1CC, - 0xBAEDED, 0xBAB9BB, 0x000000, 0x000000 } - }, - { "wavebeam", "nakedarthur's Wavebeam palette", - { 0X6B6B6B, 0X001B88, 0X21009A, 0X40008C, - 0X600067, 0X64001E, 0X590800, 0X481600, - 0X283600, 0X004500, 0X004908, 0X00421D, - 0X003659, 0X000000, 0X000000, 0X000000, - 0XB4B4B4, 0X1555D3, 0X4337EF, 0X7425DF, - 0X9C19B9, 0XAC0F64, 0XAA2C00, 0X8A4B00, - 0X666B00, 0X218300, 0X008A00, 0X008144, - 0X007691, 0X000000, 0X000000, 0X000000, - 0XFFFFFF, 0X63B2FF, 0X7C9CFF, 0XC07DFE, - 0XE977FF, 0XF572CD, 0XF4886B, 0XDDA029, - 0XBDBD0A, 0X89D20E, 0X5CDE3E, 0X4BD886, - 0X4DCFD2, 0X525252, 0X000000, 0X000000, - 0XFFFFFF, 0XBCDFFF, 0XD2D2FF, 0XE1C8FF, - 0XEFC7FF, 0XFFC3E1, 0XFFCAC6, 0XF2DAAD, - 0XEBE3A0, 0XD2EDA2, 0XBCF4B4, 0XB5F1CE, - 0XB6ECF1, 0XBFBFBF, 0X000000, 0X000000 } - }, - { "digital-prime-fbx", "FBX's Digital Prime palette", - { 0x616161, 0x000088, 0x1F0D99, 0x371379, - 0x561260, 0x5D0010, 0x520E00, 0x3A2308, - 0x21350C, 0x0D410E, 0x174417, 0x003A1F, - 0x002F57, 0x000000, 0x000000, 0x000000, - 0xAAAAAA, 0x0D4DC4, 0x4B24DE, 0x6912CF, - 0x9014AD, 0x9D1C48, 0x923404, 0x735005, - 0x5D6913, 0x167A11, 0x138008, 0x127649, - 0x1C6691, 0x000000, 0x000000, 0x000000, - 0xFCFCFC, 0x639AFC, 0x8A7EFC, 0xB06AFC, - 0xDD6DF2, 0xE771AB, 0xE38658, 0xCC9E22, - 0xA8B100, 0x72C100, 0x5ACD4E, 0x34C28E, - 0x4FBECE, 0x424242, 0x000000, 0x000000, - 0xFCFCFC, 0xBED4FC, 0xCACAFC, 0xD9C4FC, - 0xECC1FC, 0xFAC3E7, 0xF7CEC3, 0xE2CDA7, - 0xDADB9C, 0xC8E39E, 0xBFE5B8, 0xB2EBC8, - 0xB7E5EB, 0xACACAC, 0x000000, 0x000000 } - }, - { "magnum-fbx", "FBX's Magnum palette", - { 0x696969, 0x00148F, 0x1E029B, 0x3F008A, - 0x600060, 0x660017, 0x570D00, 0x451B00, - 0x243400, 0x004200, 0x004500, 0x003C1F, - 0x00315C, 0x000000, 0x000000, 0x000000, - 0xAFAFAF, 0x0F51DD, 0x442FF3, 0x7220E2, - 0xA319B3, 0xAE1C51, 0xA43400, 0x884D00, - 0x676D00, 0x208000, 0x008B00, 0x007F42, - 0x006C97, 0x010101, 0x000000, 0x000000, - 0xFFFFFF, 0x65AAFF, 0x8C96FF, 0xB983FF, - 0xDD6FFF, 0xEA6FBD, 0xEB8466, 0xDCA21F, - 0xBAB403, 0x7ECB07, 0x54D33E, 0x3CD284, - 0x3EC7CC, 0x4B4B4B, 0x000000, 0x000000, - 0xFFFFFF, 0xBDE2FF, 0xCECFFF, 0xE6C2FF, - 0xF6BCFF, 0xF9C2ED, 0xFACFC6, 0xF8DEAC, - 0xEEE9A1, 0xD0F59F, 0xBBF5AF, 0xB3F5CD, - 0xB9EDF0, 0xB9B9B9, 0x000000, 0x000000 } - }, - { "smooth-v2-fbx", "FBX's Smooth V2 palette", - { 0x6A6A6A, 0x00148F, 0x1E029B, 0x3F008A, - 0x600060, 0x660017, 0x570D00, 0x3C1F00, - 0x1B3300, 0x004200, 0x004500, 0x003C1F, - 0x00315C, 0x000000, 0x000000, 0x000000, - 0xB9B9B9, 0x0F4BD4, 0x412DEB, 0x6C1DD9, - 0x9C17AB, 0xA71A4D, 0x993200, 0x7C4A00, - 0x546400, 0x1A7800, 0x007F00, 0x00763E, - 0x00678F, 0x010101, 0x000000, 0x000000, - 0xFFFFFF, 0x68A6FF, 0x8C9CFF, 0xB586FF, - 0xD975FD, 0xE377B9, 0xE58D68, 0xD49D29, - 0xB3AF0C, 0x7BC211, 0x55CA47, 0x46CB81, - 0x47C1C5, 0x4A4A4A, 0x000000, 0x000000, - 0xFFFFFF, 0xCCEAFF, 0xDDDEFF, 0xECDAFF, - 0xF8D7FE, 0xFCD6F5, 0xFDDBCF, 0xF9E7B5, - 0xF1F0AA, 0xDAFAA9, 0xC9FFBC, 0xC3FBD7, - 0xC4F6F6, 0xBEBEBE, 0x000000, 0x000000 } - }, - { "nes-classic-fbx", "FBX's NES Classic palette", - { 0x616161, 0x000088, 0x1F0D99, 0x371379, - 0x561260, 0x5D0010, 0x520E00, 0x3A2308, - 0x21350C, 0x0D410E, 0x174417, 0x003A1F, - 0x002F57, 0x000000, 0x000000, 0x000000, - 0xAAAAAA, 0x0D4DC4, 0x4B24DE, 0x6912CF, - 0x9014AD, 0x9D1C48, 0x923404, 0x735005, - 0x5D6913, 0x167A11, 0x138008, 0x127649, - 0x1C6691, 0x000000, 0x000000, 0x000000, - 0xFCFCFC, 0x639AFC, 0x8A7EFC, 0xB06AFC, - 0xDD6DF2, 0xE771AB, 0xE38658, 0xCC9E22, - 0xA8B100, 0x72C100, 0x5ACD4E, 0x34C28E, - 0x4FBECE, 0x424242, 0x000000, 0x000000, - 0xFCFCFC, 0xBED4FC, 0xCACAFC, 0xD9C4FC, - 0xECC1FC, 0xFAC3E7, 0xF7CEC3, 0xE2CDA7, - 0xDADB9C, 0xC8E39E, 0xBFE5B8, 0xB2EBC8, - 0xB7E5EB, 0xACACAC, 0x000000, 0x000000 } - } -}; - -/* ======================================== - * Palette switching START - * ======================================== */ - -/* Period in frames between palette switches - * when holding RetroPad L2 + Left/Right */ -#define PALETTE_SWITCH_PERIOD 30 - -static bool libretro_supports_set_variable = false; -static bool palette_switch_enabled = false; -static unsigned palette_switch_counter = 0; -struct retro_core_option_value *palette_opt_values = NULL; -static const char *palette_labels[PAL_TOTAL] = {0}; - -static uint32_t palette_switch_get_current_index(void) -{ - if (current_palette < PAL_INTERNAL) - return current_palette + 1; - - switch (current_palette) - { - case PAL_DEFAULT: - return 0; - case PAL_RAW: - case PAL_CUSTOM: - return current_palette - 1; - default: - break; - } - - /* Cannot happen */ - return 0; -} - -static void palette_switch_init(void) -{ - size_t i; - struct retro_core_option_v2_definition *opt_defs = option_defs; - struct retro_core_option_v2_definition *opt_def = NULL; -#ifndef HAVE_NO_LANGEXTRA - struct retro_core_option_v2_definition *opt_defs_intl = NULL; - struct retro_core_option_v2_definition *opt_def_intl = NULL; - unsigned language = 0; -#endif - - libretro_supports_set_variable = false; - if (environ_cb(RETRO_ENVIRONMENT_SET_VARIABLE, NULL)) - libretro_supports_set_variable = true; - - palette_switch_enabled = libretro_supports_set_variable; - palette_switch_counter = 0; - -#ifndef HAVE_NO_LANGEXTRA - if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) && - (language < RETRO_LANGUAGE_LAST) && - (language != RETRO_LANGUAGE_ENGLISH) && - options_intl[language]) - opt_defs_intl = options_intl[language]->definitions; -#endif - - /* Find option corresponding to palettes key */ - for (opt_def = opt_defs; opt_def->key; opt_def++) - if (!strcmp(opt_def->key, "fceumm_palette")) - break; - - /* Cache option values array for fast access - * when setting palette index */ - palette_opt_values = opt_def->values; - - /* Loop over all palette values and fetch - * palette labels for notification purposes */ - for (i = 0; i < PAL_TOTAL; i++) - { - const char *value = opt_def->values[i].value; - const char *value_label = NULL; - - /* Check if we have a localised palette label */ -#ifndef HAVE_NO_LANGEXTRA - if (opt_defs_intl) - { - /* Find localised option corresponding to key */ - for (opt_def_intl = opt_defs_intl; - opt_def_intl->key; - opt_def_intl++) - { - if (!strcmp(opt_def_intl->key, "fceumm_palette")) - { - size_t j = 0; - - /* Search for current option value */ - for (;;) - { - const char *value_intl = opt_def_intl->values[j].value; - - if (!value_intl) - break; - - if (!strcmp(value, value_intl)) - { - /* We have a match; fetch localised label */ - value_label = opt_def_intl->values[j].label; - break; - } - - j++; - } - - break; - } - } - } -#endif - /* If localised palette label is unset, - * use label from option_defs_us or fallback - * to value itself */ - if (!value_label) - value_label = opt_def->values[i].label; - if (!value_label) - value_label = value; - - palette_labels[i] = value_label; - } -} - -static void palette_switch_deinit(void) -{ - libretro_supports_set_variable = false; - palette_switch_enabled = false; - palette_switch_counter = 0; - palette_opt_values = NULL; -} - -static void palette_switch_set_index(uint32_t palette_index) -{ - struct retro_variable var = {0}; - - if (palette_index >= PAL_TOTAL) - palette_index = PAL_TOTAL - 1; - - /* Notify frontend of option value changes */ - var.key = "fceumm_palette"; - var.value = palette_opt_values[palette_index].value; - environ_cb(RETRO_ENVIRONMENT_SET_VARIABLE, &var); - - /* Display notification message */ - FCEUD_DispMessage(RETRO_LOG_INFO, 2000, palette_labels[palette_index]); -} - -/* ======================================== - * Palette switching END - * ======================================== */ - -/* ======================================== - * Stereo Filter START - * ======================================== */ - -enum stereo_filter_type -{ - STEREO_FILTER_NULL = 0, - STEREO_FILTER_DELAY -}; -static enum stereo_filter_type current_stereo_filter = STEREO_FILTER_NULL; - -#define STEREO_FILTER_DELAY_MS_DEFAULT 15.0f -typedef struct -{ - int32_t *samples; - size_t samples_size; - size_t samples_pos; - size_t delay_count; -} stereo_filter_delay_t; -static stereo_filter_delay_t stereo_filter_delay; -static float stereo_filter_delay_ms = STEREO_FILTER_DELAY_MS_DEFAULT; - -static void stereo_filter_apply_null(int32_t *sound_buffer, size_t size) -{ - size_t i; - /* Each element of sound_buffer is a 16 bit mono sample - * stored in a 32 bit value. We convert this to stereo - * by copying the mono sample to both the high and low - * 16 bit regions of the value and casting sound_buffer - * to int16_t when uploading to the frontend */ - for (i = 0; i < size; i++) - sound_buffer[i] = (sound_buffer[i] << 16) | - (sound_buffer[i] & 0xFFFF); -} - -static void stereo_filter_apply_delay(int32_t *sound_buffer, size_t size) -{ - size_t delay_capacity = stereo_filter_delay.samples_size - - stereo_filter_delay.samples_pos; - size_t i; - - /* Copy current samples into the delay buffer - * (resizing if required) */ - if (delay_capacity < size) - { - int32_t *tmp_buffer = NULL; - size_t tmp_buffer_size; - - tmp_buffer_size = stereo_filter_delay.samples_size + (size - delay_capacity); - tmp_buffer_size = (tmp_buffer_size << 1) - (tmp_buffer_size >> 1); - tmp_buffer = (int32_t *)malloc(tmp_buffer_size * sizeof(int32_t)); - - memcpy(tmp_buffer, stereo_filter_delay.samples, - stereo_filter_delay.samples_pos * sizeof(int32_t)); - - free(stereo_filter_delay.samples); - - stereo_filter_delay.samples = tmp_buffer; - stereo_filter_delay.samples_size = tmp_buffer_size; - } - - for (i = 0; i < size; i++) - stereo_filter_delay.samples[i + - stereo_filter_delay.samples_pos] = sound_buffer[i]; - - stereo_filter_delay.samples_pos += size; - - /* If we have enough samples in the delay - * buffer, mix them into the output */ - if (stereo_filter_delay.samples_pos > - stereo_filter_delay.delay_count) - { - size_t delay_index = 0; - size_t samples_to_mix = stereo_filter_delay.samples_pos - - stereo_filter_delay.delay_count; - samples_to_mix = (samples_to_mix > size) ? - size : samples_to_mix; - - /* Perform 'null' filtering for any samples for - * which a delay buffer entry is unavailable */ - if (size > samples_to_mix) - for (i = 0; i < size - samples_to_mix; i++) - sound_buffer[i] = (sound_buffer[i] << 16) | - (sound_buffer[i] & 0xFFFF); - - /* Each element of sound_buffer is a 16 bit mono sample - * stored in a 32 bit value. We convert this to stereo - * by copying the mono sample to the high (left channel) - * 16 bit region and the delayed sample to the low - * (right channel) region, casting sound_buffer - * to int16_t when uploading to the frontend */ - for (i = size - samples_to_mix; i < size; i++) - sound_buffer[i] = (sound_buffer[i] << 16) | - (stereo_filter_delay.samples[delay_index++] & 0xFFFF); - - /* Remove the mixed samples from the delay buffer */ - memmove(stereo_filter_delay.samples, - stereo_filter_delay.samples + samples_to_mix, - (stereo_filter_delay.samples_pos - samples_to_mix) * - sizeof(int32_t)); - stereo_filter_delay.samples_pos -= samples_to_mix; - } - /* Otherwise apply the regular 'null' filter */ - else - for (i = 0; i < size; i++) - sound_buffer[i] = (sound_buffer[i] << 16) | - (sound_buffer[i] & 0xFFFF); -} - -static void (*stereo_filter_apply)(int32_t *sound_buffer, size_t size) = stereo_filter_apply_null; - -static void stereo_filter_deinit_delay(void) -{ - if (stereo_filter_delay.samples) - free(stereo_filter_delay.samples); - - stereo_filter_delay.samples = NULL; - stereo_filter_delay.samples_size = 0; - stereo_filter_delay.samples_pos = 0; - stereo_filter_delay.delay_count = 0; -} - -static void stereo_filter_init_delay(void) -{ - size_t initial_samples_size; - - /* Convert delay (ms) to number of samples */ - stereo_filter_delay.delay_count = (size_t)( - (stereo_filter_delay_ms / 1000.0f) * - (float)sndsamplerate); - - /* Preallocate delay_count + worst case expected - * samples per frame to minimise reallocation of - * the samples buffer during runtime */ - initial_samples_size = stereo_filter_delay.delay_count + - (size_t)((float)sndsamplerate / NES_PAL_FPS) + 1; - - stereo_filter_delay.samples = (int32_t *)malloc( - initial_samples_size * sizeof(int32_t)); - stereo_filter_delay.samples_size = initial_samples_size; - stereo_filter_delay.samples_pos = 0; - - /* Assign function pointer */ - stereo_filter_apply = stereo_filter_apply_delay; -} - -static void stereo_filter_deinit(void) -{ - /* Clean up */ - stereo_filter_deinit_delay(); - /* Assign default function pointer */ - stereo_filter_apply = stereo_filter_apply_null; -} - -static void stereo_filter_init(void) -{ - stereo_filter_deinit(); - - /* Use a case statement to simplify matters - * if more filter types are added in the - * future... */ - switch (current_stereo_filter) - { - case STEREO_FILTER_DELAY: - stereo_filter_init_delay(); - break; - default: - break; - } -} - -/* ======================================== - * Stereo Filter END - * ======================================== */ - -#ifdef HAVE_NTSC_FILTER -/* ntsc */ -#include "nes_ntsc.h" -#define NTSC_NONE 0 -#define NTSC_COMPOSITE 1 -#define NTSC_SVIDEO 2 -#define NTSC_RGB 3 -#define NTSC_MONOCHROME 4 - -#define NES_NTSC_WIDTH (((NES_NTSC_OUT_WIDTH(256) + 3) >> 2) << 2) - -static unsigned use_ntsc = 0; -static unsigned burst_phase = 0; -static nes_ntsc_t nes_ntsc; -static nes_ntsc_setup_t ntsc_setup; -static uint16_t *ntsc_video_out = NULL; /* for ntsc blit buffer */ - -static void NTSCFilter_Cleanup(void) -{ - if (ntsc_video_out) - free(ntsc_video_out); - ntsc_video_out = NULL; - - use_ntsc = 0; - burst_phase = 0; -} - -static void NTSCFilter_Init(void) -{ - memset(&nes_ntsc, 0, sizeof(nes_ntsc)); - memset(&ntsc_setup, 0, sizeof(ntsc_setup)); - ntsc_video_out = (uint16_t *)malloc(NES_NTSC_WIDTH * NES_HEIGHT * sizeof(uint16_t)); -} - -static void NTSCFilter_Setup(void) -{ - if (ntsc_video_out == NULL) - NTSCFilter_Init(); - - switch (use_ntsc) { - case NTSC_COMPOSITE: - ntsc_setup = nes_ntsc_composite; - break; - case NTSC_SVIDEO: - ntsc_setup = nes_ntsc_svideo; - break; - case NTSC_RGB: - ntsc_setup = nes_ntsc_rgb; - break; - case NTSC_MONOCHROME: - ntsc_setup = nes_ntsc_monochrome; - break; - default: - break; - } - - ntsc_setup.merge_fields = 0; - if ((GameInfo->type != GIT_VSUNI) && (current_palette == PAL_DEFAULT || current_palette == PAL_RAW)) - /* use ntsc default palette instead of internal default palette for that "identity" effect */ - ntsc_setup.base_palette = NULL; - else - /* use internal palette, this includes palette presets, external palette and custom palettes - * for VS. System games */ - ntsc_setup.base_palette = (unsigned char const *)palo; - - nes_ntsc_init(&nes_ntsc, &ntsc_setup); -} -#endif /* HAVE_NTSC_FILTER */ - -static void ResetPalette(void); -static void retro_set_custom_palette(void); - -static void ResetPalette(void) -{ - retro_set_custom_palette(); -#ifdef HAVE_NTSC_FILTER - NTSCFilter_Setup(); -#endif -} - -unsigned retro_api_version(void) -{ - return RETRO_API_VERSION; -} - -void retro_set_video_refresh(retro_video_refresh_t cb) -{ - video_cb = cb; -} - -void retro_set_audio_sample(retro_audio_sample_t cb) -{ } - -void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) -{ - audio_batch_cb = cb; -} - -void retro_set_input_poll(retro_input_poll_t cb) -{ - poll_cb = cb; -} - -void retro_set_input_state(retro_input_state_t cb) -{ - input_cb = cb; -} - -static void addDesc(struct retro_input_descriptor *p, unsigned port, unsigned id, const char *description) -{ - p->port = port; - p->device = RETRO_DEVICE_JOYPAD; - p->index = 0; - p->id = id; - p->description = description; -} - -static void update_input_descriptors(void) -{ - struct retro_input_descriptor desc[128] = { 0 }; - - int i, port; - - for (i = 0, port = 0; port < 5; port++) - { - if (nes_input.type[port] == DEVICE_GAMEPAD || nes_input.type[port] == RETRO_DEVICE_JOYPAD || nes_input.type[port] == DEVICE_SNESGAMEPAD) - { - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" ); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" ); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" ); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" ); - if(nes_input.type[port] == DEVICE_SNESGAMEPAD) { - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_A, "A"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_B, "B"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_X, "X"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_Y, "Y"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_L, "L"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_R, "R"); - } - else - { - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_B, "B" ); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_A, "A" ); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_X, "Turbo A" ); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_Y, "Turbo B" ); - } - - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" ); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_START, "Start" ); - - if (port == 0) - { - addDesc(&desc[i++], 0, RETRO_DEVICE_ID_JOYPAD_L, "(FDS) Disk Side Change" ); - addDesc(&desc[i++], 0, RETRO_DEVICE_ID_JOYPAD_R, "(FDS) Insert/Eject Disk" ); - addDesc(&desc[i++], 0, RETRO_DEVICE_ID_JOYPAD_R2, "(VS) Insert Coin" ); - addDesc(&desc[i++], 0, RETRO_DEVICE_ID_JOYPAD_L3, "(Famicom) Microphone (P2)" ); - - if (palette_switch_enabled) - addDesc(&desc[i++], 0, RETRO_DEVICE_ID_JOYPAD_L2, "Switch Palette (+ Left/Right)" ); - } - } - else if (nes_input.type[port] == DEVICE_FTRAINERA || nes_input.type[port] == DEVICE_FTRAINERB || - nes_input.type[port] == DEVICE_POWERPADA || nes_input.type[port] == DEVICE_POWERPADB) - { - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_B, "B1"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_A, "B2"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_Y, "B3"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_X, "B4"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_L, "B5"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_R, "B6"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_LEFT, "B7"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_RIGHT, "B8"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_UP, "B9"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_DOWN, "B10"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_SELECT, "B11"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_START, "B12"); - } - else if (nes_input.type[port] == DEVICE_QUIZKING) - { - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_B, "B1"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_A, "B2"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_Y, "B3"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_X, "B4"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_L, "B5"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_R, "B6"); - } - else if(nes_input.type[port] == DEVICE_VIRTUALBOY) - { - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_B, "Right D-Pad Down"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_Y, "Right D-Pad Left"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_START, "Start"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_UP, "Left D-Pad Up"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_DOWN, "Left D-Pad Down"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left D-Pad Left"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Left D-Pad Right"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_A, "Right D-Pad Right"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_X, "Right D-Pad Up"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_L, "Left Trigger"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_R, "Right Trigger"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_L2, "B"); - addDesc(&desc[i++], port, RETRO_DEVICE_ID_JOYPAD_R2, "A"); - } - } - - environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc); -} - -static void set_input(unsigned port) -{ - int type; - int attrib; - void *inputDPtr; - - if (port <= 1) - { - type = 0; - attrib = 0; - inputDPtr = 0; - - switch(nes_input.type[port]) - { - case RETRO_DEVICE_NONE: - type = SI_UNSET; - inputDPtr = &Dummy; - FCEU_printf(" Player %u: None Connected\n", port + 1); - break; - case RETRO_DEVICE_JOYPAD: - case DEVICE_GAMEPAD: - type = SI_GAMEPAD; - inputDPtr = &nes_input.JSReturn; - FCEU_printf(" Player %u: Standard Gamepad\n", port + 1); - break; - case DEVICE_ARKANOID: - type = SI_ARKANOID; - inputDPtr = &nes_input.MouseData[port]; - FCEU_printf(" Player %u: Arkanoid\n", port + 1); - break; - case DEVICE_ZAPPER: - type = SI_ZAPPER; - attrib = 1; - inputDPtr = &nes_input.MouseData[port]; - FCEU_printf(" Player %u: Zapper\n", port + 1); - break; - case DEVICE_POWERPADA: - case DEVICE_POWERPADB: - type = SI_POWERPADA ? (SI_POWERPADA) : (SI_POWERPADB); - inputDPtr = &nes_input.PowerPadData[port]; - FCEU_printf(" Player %u: Power Pad %s\n", port + 1, SI_POWERPADA ? "A" : "B"); - break; - case DEVICE_SNESGAMEPAD: - type = SI_SNES_GAMEPAD; - inputDPtr = &nes_input.JoyButtons[port]; - FCEU_printf(" Player %u: SNES Gamepad\n", port + 1); - break; - case DEVICE_SNESMOUSE: - type = SI_SNES_MOUSE; - inputDPtr = &nes_input.MouseData[port]; - FCEU_printf(" Player %u: SNES Mouse\n", port + 1); - break; - case DEVICE_VIRTUALBOY: - type = SI_VIRTUALBOY; - inputDPtr = &nes_input.JoyButtons[port]; - FCEU_printf(" Player %u: Virtual Boy Controller\n", port + 1); - break; - } - - FCEUI_SetInput(port, type, inputDPtr, attrib); - } - else if (port <= 3) - { - /* nes_input.type[port] = device;*/ - if (nes_input.type[port] == DEVICE_GAMEPAD) - FCEU_printf(" Player %u: Standard Gamepad\n", port + 1); - else - FCEU_printf(" Player %u: None Connected\n", port + 1); - } - else - { - /* famicom expansion port */ - type = 0; - attrib = 0; - inputDPtr = 0; - - switch (nes_input.type[4]) - { - case DEVICE_ARKANOID: - type = SIFC_ARKANOID; - inputDPtr = nes_input.FamicomData; - FCEU_printf(" Famicom Expansion: Arkanoid\n"); - break; - case DEVICE_SHADOW: - type = SIFC_SHADOW; - inputDPtr = nes_input.FamicomData; - attrib = 1; - FCEU_printf(" Famicom Expansion: (Bandai) Hyper Shot\n"); - break; - case DEVICE_OEKAKIDS: - type = SIFC_OEKAKIDS; - inputDPtr = nes_input.FamicomData; - attrib = 1; - FCEU_printf(" Famicom Expansion: Oeka Kids Tablet\n"); - break; - case DEVICE_4PLAYER: - type = SIFC_4PLAYER; - inputDPtr = &nes_input.JSReturn; - FCEU_printf(" Famicom Expansion: Famicom 4-Player Adapter\n"); - break; - case DEVICE_HYPERSHOT: - type = SIFC_HYPERSHOT; - inputDPtr = nes_input.FamicomData; - FCEU_printf(" Famicom Expansion: Konami Hyper Shot\n"); - break; - case DEVICE_FTRAINERA: - case DEVICE_FTRAINERB: - type = SIFC_FTRAINERA ? (DEVICE_FTRAINERA) : (DEVICE_FTRAINERB); - inputDPtr = &nes_input.FTrainerData; - FCEU_printf(" Famicom Expansion: Family Trainer %s\n", SIFC_FTRAINERA ? "A" : "B"); - break; - case DEVICE_QUIZKING: - type = SIFC_QUIZKING; - inputDPtr = &nes_input.QuizKingData; - FCEU_printf(" Famicom Expansion: Quiz King\n"); - break; - case RETRO_DEVICE_NONE: - default: - type = SIFC_NONE, - inputDPtr = &Dummy; - FCEU_printf(" Famicom Expansion: None Connected\n"); - break; - } - - FCEUI_SetInputFC(type, inputDPtr, attrib); - } - - if (nes_input.type[4] != DEVICE_4PLAYER && (nes_input.type[2] == DEVICE_GAMEPAD || nes_input.type[3] == DEVICE_GAMEPAD)) - FCEUI_DisableFourScore(0); - else - FCEUI_DisableFourScore(1); - - /* check if famicom 4player adapter is used */ - if (nes_input.type[4] == DEVICE_4PLAYER) - FCEUI_DisableFourScore(1); -} - -void retro_set_controller_port_device(unsigned port, unsigned device) -{ - if (port >= 5) - return; - - if (device == DEVICE_AUTO) - { - if (port <= 1) - { - switch (GameInfo->input[port]) - { - case SI_GAMEPAD: - nes_input.type[port] = DEVICE_GAMEPAD; - break; - case SI_ZAPPER: - nes_input.type[port] = DEVICE_ZAPPER; - break; - case SI_ARKANOID: - nes_input.type[port] = DEVICE_ARKANOID; - break; - case SI_POWERPADA: - nes_input.type[port] = DEVICE_POWERPADA; - break; - case SI_POWERPADB: - nes_input.type[port] = DEVICE_POWERPADB; - break; - case SI_SNES_GAMEPAD: - nes_input.type[port] = DEVICE_SNESGAMEPAD; - break; - case SI_SNES_MOUSE: - nes_input.type[port] = DEVICE_SNESMOUSE; - break; - case SI_VIRTUALBOY: - nes_input.type[port] = DEVICE_VIRTUALBOY; - break; - default: - case SI_UNSET: - case SI_NONE: - case SI_MOUSE: - /* unsupported devices */ - nes_input.type[port] = DEVICE_GAMEPAD; - break; - } - } - else if (port <= 3) - { - nes_input.type[port] = RETRO_DEVICE_NONE; - - if (nes_input.enable_4player || nes_input.type[4] == DEVICE_4PLAYER) - { - nes_input.type[port] = DEVICE_GAMEPAD; - } - } - else - { - /* famicom expansion port */ - switch (GameInfo->inputfc) - { - case SIFC_UNSET: - case SIFC_NONE: - nes_input.type[4] = RETRO_DEVICE_NONE; - break; - case SIFC_ARKANOID: - nes_input.type[4] = DEVICE_ARKANOID; - break; - case SIFC_SHADOW: - nes_input.type[4] = DEVICE_SHADOW; - break; - case SIFC_4PLAYER: - nes_input.type[4] = DEVICE_4PLAYER; - break; - case SIFC_HYPERSHOT: - nes_input.type[4] = DEVICE_HYPERSHOT; - break; - case SIFC_OEKAKIDS: - nes_input.type[4] = DEVICE_OEKAKIDS; - break; - case SIFC_FTRAINERA: - nes_input.type[4] = DEVICE_FTRAINERA; - break; - case SIFC_FTRAINERB: - nes_input.type[4] = DEVICE_FTRAINERB; - break; - case SIFC_QUIZKING: - nes_input.type[4] = DEVICE_QUIZKING; - break; - default: - /* unsupported input device */ - nes_input.type[4] = RETRO_DEVICE_NONE; - break; - } - } - } - else - { - nes_input.type[port] = device; - } - - set_input(port); - - nes_input.needs_update = true; -} - -/* Core options 'update display' callback */ -static bool update_option_visibility(void) -{ - struct retro_variable var = {0}; - bool updated = false; - - /* If frontend supports core option categories, - * then fceumm_show_adv_system_options and - * fceumm_show_adv_sound_options are ignored - * and no options should be hidden */ - if (libretro_supports_option_categories) - return false; - - var.key = "fceumm_show_adv_system_options"; - var.value = NULL; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - bool opt_showAdvSystemOptions_prev = opt_showAdvSystemOptions; - - opt_showAdvSystemOptions = true; - if (strcmp(var.value, "disabled") == 0) - opt_showAdvSystemOptions = false; - - if (opt_showAdvSystemOptions != opt_showAdvSystemOptions_prev) - { - struct retro_core_option_display option_display; - unsigned i; - unsigned size; - char options_list[][25] = { - "fceumm_overclocking", - "fceumm_ramstate", - "fceumm_nospritelimit", - "fceumm_up_down_allowed", - "fceumm_show_crosshair" - }; - - option_display.visible = opt_showAdvSystemOptions; - size = sizeof(options_list) / sizeof(options_list[0]); - for (i = 0; i < size; i++) - { - option_display.key = options_list[i]; - environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, - &option_display); - } - - updated = true; - } - } - - var.key = "fceumm_show_adv_sound_options"; - var.value = NULL; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - bool opt_showAdvSoundOptions_prev = opt_showAdvSoundOptions; - - opt_showAdvSoundOptions = true; - if (strcmp(var.value, "disabled") == 0) - opt_showAdvSoundOptions = false; - - if (opt_showAdvSoundOptions != opt_showAdvSoundOptions_prev) - { - struct retro_core_option_display option_display; - unsigned i; - unsigned size; - char options_list[][25] = { - "fceumm_sndvolume", - "fceumm_sndquality", - "fceumm_sndlowpass", - "fceumm_sndstereodelay", - "fceumm_swapduty", - "fceumm_apu_1", - "fceumm_apu_2", - "fceumm_apu_3", - "fceumm_apu_4", - "fceumm_apu_5" - }; - - option_display.visible = opt_showAdvSoundOptions; - size = sizeof(options_list) / sizeof(options_list[0]); - for (i = 0; i < size; i++) - { - option_display.key = options_list[i]; - environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, - &option_display); - } - - updated = true; - } - } - - return updated; -} - -static void set_variables(void) -{ - struct retro_core_option_display option_display; - unsigned index = 0; - - option_display.visible = false; - - /* Initialize main core option struct */ - memset(&option_defs_us, 0, sizeof(option_defs_us)); - - /* Write common core options to main struct */ - while (option_defs[index].key) { - memcpy(&option_defs_us[index], &option_defs[index], - sizeof(struct retro_core_option_v2_definition)); - index++; - } - - /* Append dipswitch settings to core options if available */ - set_dipswitch_variables(index, option_defs_us); - - libretro_supports_option_categories = false; - libretro_set_core_options(environ_cb, - &libretro_supports_option_categories); - - /* If frontend supports core option categories, - * fceumm_show_adv_system_options and - * fceumm_show_adv_sound_options are unused - * and should be hidden */ - if (libretro_supports_option_categories) - { - option_display.key = "fceumm_show_adv_system_options"; - - environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, - &option_display); - - option_display.key = "fceumm_show_adv_sound_options"; - - environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, - &option_display); - } - /* If frontend does not support core option - * categories, core options may be shown/hidden - * at runtime. In this case, register 'update - * display' callback, so frontend can update - * core options menu without calling retro_run() */ - else - { - struct retro_core_options_update_display_callback update_display_cb; - update_display_cb.callback = update_option_visibility; - - environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK, - &update_display_cb); - } - - /* VS UNISystem games use internal palette regardless - * of user setting, so hide fceumm_palette option */ - if (GameInfo && (GameInfo->type == GIT_VSUNI)) - { - option_display.key = "fceumm_palette"; - - environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, - &option_display); - - /* Additionally disable gamepad palette - * switching */ - palette_switch_enabled = false; - } -} - -/* Game Genie add-on must be enabled before - * loading content, so we cannot parse this - * option inside check_variables() */ -static void check_game_genie_variable(void) -{ - struct retro_variable var = {0}; - int game_genie_enabled = 0; - - var.key = "fceumm_game_genie"; - - /* Game Genie is only enabled for regular - * cartridges (excludes arcade content, - * FDS games, etc.) */ - if ((GameInfo->type == GIT_CART) && - (iNESCart.mapper != 105) && /* Nintendo World Championship cart (Mapper 105)*/ - environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && - var.value && - !strcmp(var.value, "enabled")) - game_genie_enabled = 1; - - FCEUI_SetGameGenie(game_genie_enabled); -} - -/* Callback passed to FCEUI_LoadGame() - * > Required since we must set and check - * core options immediately after ROM - * is loaded, before FCEUI_LoadGame() - * returns */ -static void frontend_post_load_init() -{ - set_variables(); - check_game_genie_variable(); -} - -void retro_set_environment(retro_environment_t cb) -{ - struct retro_vfs_interface_info vfs_iface_info; - - static const struct retro_controller_description pads1[] = { - { "Auto", DEVICE_AUTO }, - { "Gamepad", DEVICE_GAMEPAD }, - { "Arkanoid", DEVICE_ARKANOID }, - { "Zapper", DEVICE_ZAPPER }, - { "Power Pad A", DEVICE_POWERPADA }, - { "Power Pad B", DEVICE_POWERPADB }, - { "SNES Gamepad", DEVICE_SNESGAMEPAD }, - { "SNES Mouse", DEVICE_SNESMOUSE }, - { "Virtual Boy", DEVICE_VIRTUALBOY }, - { 0, 0 }, - }; - - static const struct retro_controller_description pads2[] = { - { "Auto", DEVICE_AUTO }, - { "Gamepad", DEVICE_GAMEPAD }, - { "Arkanoid", DEVICE_ARKANOID }, - { "Zapper", DEVICE_ZAPPER }, - { "Power Pad A", DEVICE_POWERPADA }, - { "Power Pad B", DEVICE_POWERPADB }, - { "SNES Gamepad", DEVICE_SNESGAMEPAD }, - { "SNES Mouse", DEVICE_SNESMOUSE }, - { "Virtual Boy", DEVICE_VIRTUALBOY }, - { 0, 0 }, - }; - - static const struct retro_controller_description pads3[] = { - { "Auto", DEVICE_AUTO }, - { "Gamepad", DEVICE_GAMEPAD }, - { 0, 0 }, - }; - - static const struct retro_controller_description pads4[] = { - { "Auto", DEVICE_AUTO }, - { "Gamepad", DEVICE_GAMEPAD }, - { 0, 0 }, - }; - - static const struct retro_controller_description pads5[] = { - { "Auto", DEVICE_AUTO }, - { "Arkanoid", DEVICE_ARKANOID }, - { "Bandai Hyper Shot", DEVICE_SHADOW }, - { "Konami Hyper Shot", DEVICE_HYPERSHOT }, - { "Oeka Kids Tablet", DEVICE_OEKAKIDS }, - { "4-Player Adapter", DEVICE_4PLAYER }, - { "Family Trainer A", DEVICE_FTRAINERA }, - { "Family Trainer B", DEVICE_FTRAINERB }, - { "Quiz King", DEVICE_QUIZKING }, - { 0, 0 }, - }; - - static const struct retro_controller_info ports[] = { - { pads1, 8 }, - { pads2, 8 }, - { pads3, 2 }, - { pads4, 2 }, - { pads5, 9 }, - { 0, 0 }, - }; - - static const struct retro_system_content_info_override content_overrides[] = { - { - "fds|nes|unf|unif", /* extensions */ - false, /* need_fullpath */ - false /* persistent_data */ - }, - { NULL, false, false } - }; - - environ_cb = cb; - - environ_cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports); - - vfs_iface_info.required_interface_version = 1; - vfs_iface_info.iface = NULL; - if (environ_cb(RETRO_ENVIRONMENT_GET_VFS_INTERFACE, &vfs_iface_info)) - filestream_vfs_init(&vfs_iface_info); - - environ_cb(RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE, - (void*)content_overrides); -} - -void retro_get_system_info(struct retro_system_info *info) -{ - info->need_fullpath = true; - info->valid_extensions = "fds|nes|unf|unif"; -#ifdef GIT_VERSION - info->library_version = "(SVN)" GIT_VERSION; -#else - info->library_version = "(SVN)"; -#endif - info->library_name = "FCEUmm"; - info->block_extract = false; -} - -static float get_aspect_ratio(unsigned width, unsigned height) -{ - if (aspect_ratio_par == 2) - return NES_4_3; - else if (aspect_ratio_par == 3) - return NES_PP; - else - return NES_8_7_PAR; -} - -void retro_get_system_av_info(struct retro_system_av_info *info) -{ - unsigned width = NES_WIDTH - overscan_left - overscan_right; - unsigned height = NES_HEIGHT - overscan_top - overscan_bottom; -#ifdef HAVE_NTSC_FILTER - info->geometry.base_width = (use_ntsc ? NES_NTSC_OUT_WIDTH(width) : width); - info->geometry.max_width = (use_ntsc ? NES_NTSC_WIDTH : NES_WIDTH); -#else - info->geometry.base_width = width; - info->geometry.max_width = NES_WIDTH; -#endif - info->geometry.base_height = height; - info->geometry.max_height = NES_HEIGHT; - info->geometry.aspect_ratio = get_aspect_ratio(width, height); - info->timing.sample_rate = (float)sndsamplerate; - if (FSettings.PAL || dendy) - info->timing.fps = NES_PAL_FPS; - else - info->timing.fps = NES_NTSC_FPS; -} - -static void check_system_specs(void) -{ - /* TODO - when we get it running at fullspeed on PSP, set to 4 */ - unsigned level = 5; - environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level); -} - -void retro_init(void) -{ - bool achievements = true; - log_cb.log=default_logger; - environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log_cb); - - environ_cb(RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS, &achievements); - - if (environ_cb(RETRO_ENVIRONMENT_GET_INPUT_BITMASKS, NULL)) - libretro_supports_bitmasks = true; - - environ_cb(RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION, - &libretro_msg_interface_version); - - palette_switch_init(); -} - -static void retro_set_custom_palette(void) -{ - unsigned i; - - ipalette = 0; - use_raw_palette = false; - - /* VS UNISystem uses internal palette presets regardless of options */ - if (GameInfo->type == GIT_VSUNI) - FCEU_ResetPalette(); - - /* Reset and choose between default internal or external custom palette */ - else if (current_palette == PAL_DEFAULT || current_palette == PAL_CUSTOM) - { - ipalette = external_palette_exist && (current_palette == PAL_CUSTOM); - - /* if ipalette is set to 1, external palette - * is loaded, else it will load default NES palette. - * FCEUI_SetPaletteArray() both resets the palette array to - * internal default palette and then chooses which one to use. */ - FCEUI_SetPaletteArray( NULL ); - } - - /* setup raw palette */ - else if (current_palette == PAL_RAW) - { - pal color; - use_raw_palette = true; - for (i = 0; i < 64; i++) - { - color.r = (((i >> 0) & 0xF) * 255) / 15; - color.g = (((i >> 4) & 0x3) * 255) / 3; - color.b = 0; - FCEUD_SetPalette( i, color.r, color.g, color.b); - } - } - - /* setup palette presets */ - else - { - unsigned *palette_data = palettes[current_palette].data; - for ( i = 0; i < 64; i++ ) - { - unsigned data = palette_data[i]; - base_palette[ i * 3 + 0 ] = ( data >> 16 ) & 0xff; /* red */ - base_palette[ i * 3 + 1 ] = ( data >> 8 ) & 0xff; /* green */ - base_palette[ i * 3 + 2 ] = ( data >> 0 ) & 0xff; /* blue */ - } - FCEUI_SetPaletteArray( base_palette ); - } -} - -/* Set variables for NTSC(1) / PAL(2) / Dendy(3) - * Dendy has PAL framerate and resolution, but ~NTSC timings, - * and has 50 dummy scanlines to force 50 fps. - */ -static void FCEUD_RegionOverride(unsigned region) -{ - unsigned pal = 0; - unsigned d = 0; - - switch (region) - { - case 0: /* auto */ - d = (systemRegion >> 1) & 1; - pal = systemRegion & 1; - break; - case 1: /* ntsc */ - FCEUD_DispMessage(RETRO_LOG_INFO, 2000, "System: NTSC"); - break; - case 2: /* pal */ - pal = 1; - FCEUD_DispMessage(RETRO_LOG_INFO, 2000, "System: PAL"); - break; - case 3: /* dendy */ - d = 1; - FCEUD_DispMessage(RETRO_LOG_INFO, 2000, "System: Dendy"); - break; - } - - dendy = d; - FCEUI_SetVidSystem(pal); - ResetPalette(); -} - -void retro_deinit (void) -{ - FCEUI_CloseGame(); - FCEUI_Sound(0); - FCEUI_Kill(); -#if defined(_3DS) - linearFree(fceu_video_out); -#else - if (fceu_video_out) - free(fceu_video_out); - fceu_video_out = NULL; -#endif -#if defined(RENDER_GSKIT_PS2) - ps2 = NULL; -#endif - libretro_supports_bitmasks = false; - libretro_msg_interface_version = 0; - DPSW_Cleanup(); -#ifdef HAVE_NTSC_FILTER - NTSCFilter_Cleanup(); -#endif - palette_switch_deinit(); - stereo_filter_deinit(); -} - -void retro_reset(void) -{ - ResetNES(); -} - -static void set_apu_channels(int chan) -{ - FSettings.SquareVolume[1] = (chan & 1) ? 256 : 0; - FSettings.SquareVolume[0] = (chan & 2) ? 256 : 0; - FSettings.TriangleVolume = (chan & 3) ? 256 : 0; - FSettings.NoiseVolume = (chan & 4) ? 256 : 0; - FSettings.PCMVolume = (chan & 5) ? 256 : 0; -} - -static void check_variables(bool startup) -{ - struct retro_variable var = {0}; - char key[256]; - int i, enable_apu; - bool stereo_filter_updated = false; - - /* 1 = Performs only geometry update: e.g. overscans */ - /* 2 = Performs video/geometry update when needed and timing changes: e.g. region and filter change */ - int audio_video_updated = 0; - - 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; - } - -#ifdef HAVE_NTSC_FILTER - var.key = "fceumm_ntsc_filter"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - unsigned orig_value = use_ntsc; - if (strcmp(var.value, "disabled") == 0) - use_ntsc = NTSC_NONE; - else if (strcmp(var.value, "composite") == 0) - use_ntsc = NTSC_COMPOSITE; - else if (strcmp(var.value, "svideo") == 0) - use_ntsc = NTSC_SVIDEO; - else if (strcmp(var.value, "rgb") == 0) - use_ntsc = NTSC_RGB; - else if (strcmp(var.value, "monochrome") == 0) - use_ntsc = NTSC_MONOCHROME; - if (use_ntsc != orig_value) - { - ResetPalette(); - audio_video_updated = 2; - } - } -#endif /* HAVE_NTSC_FILTER */ - - var.key = "fceumm_palette"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - unsigned orig_value = current_palette; - - if (!strcmp(var.value, "default")) - current_palette = PAL_DEFAULT; - else if (!strcmp(var.value, "raw")) - current_palette = PAL_RAW; - else if (!strcmp(var.value, "custom")) - current_palette = PAL_CUSTOM; - else if (!strcmp(var.value, "asqrealc")) - current_palette = 0; - else if (!strcmp(var.value, "nintendo-vc")) - current_palette = 1; - else if (!strcmp(var.value, "rgb")) - current_palette = 2; - else if (!strcmp(var.value, "sony-cxa2025as-us")) - current_palette = 3; - else if (!strcmp(var.value, "pal")) - current_palette = 4; - else if (!strcmp(var.value, "bmf-final2")) - current_palette = 5; - else if (!strcmp(var.value, "bmf-final3")) - current_palette = 6; - else if (!strcmp(var.value, "nescap")) - current_palette = 7; - else if (!strcmp(var.value, "wavebeam")) - current_palette = 8; - else if (!strcmp(var.value, "digital-prime-fbx")) - current_palette = 9; - else if (!strcmp(var.value, "magnum-fbx")) - current_palette = 10; - else if (!strcmp(var.value, "smooth-v2-fbx")) - current_palette = 11; - else if (!strcmp(var.value, "nes-classic-fbx")) - current_palette = 12; - - if (current_palette != orig_value) - { - audio_video_updated = 1; - ResetPalette(); - } - } - - var.key = "fceumm_up_down_allowed"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - nes_input.up_down_allowed = (!strcmp(var.value, "enabled")) ? true : false; - else - nes_input.up_down_allowed = false; - - var.key = "fceumm_nospritelimit"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - int no_sprite_limit = (!strcmp(var.value, "enabled")) ? 1 : 0; - FCEUI_DisableSpriteLimitation(no_sprite_limit); - } - - var.key = "fceumm_overclocking"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - bool do_reinit = false; - - if (!strcmp(var.value, "disabled") - && ppu.overclock_enabled != 0) - { - ppu.skip_7bit_overclocking = 1; - ppu.extrascanlines = 0; - ppu.vblankscanlines = 0; - ppu.overclock_enabled = 0; - do_reinit = true; - } - else if (!strcmp(var.value, "2x-Postrender")) - { - ppu.skip_7bit_overclocking = 1; - ppu.extrascanlines = 266; - ppu.vblankscanlines = 0; - ppu.overclock_enabled = 1; - do_reinit = true; - } - else if (!strcmp(var.value, "2x-VBlank")) - { - ppu.skip_7bit_overclocking = 1; - ppu.extrascanlines = 0; - ppu.vblankscanlines = 266; - ppu.overclock_enabled = 1; - do_reinit = true; - } - - ppu.normal_scanlines = dendy ? 290 : 240; - ppu.totalscanlines = ppu.normal_scanlines + (ppu.overclock_enabled ? ppu.extrascanlines : 0); - - if (do_reinit && startup) - { - FCEU_KillVirtualVideo(); - FCEU_InitVirtualVideo(); - } - } - - var.key = "fceumm_zapper_mode"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - if (!strcmp(var.value, "mouse")) zappermode = RetroMouse; - else if (!strcmp(var.value, "touchscreen")) zappermode = RetroPointer; - else zappermode = RetroLightgun; /*default setting*/ - } - - var.key = "fceumm_arkanoid_mode"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - if (!strcmp(var.value, "touchscreen")) - { - arkanoidmode = RetroArkanoidPointer; - } - else if (!strcmp(var.value, "abs_mouse")) - { - arkanoidmode = RetroArkanoidAbsMouse; - } - else if (!strcmp(var.value, "stelladaptor")) - { - arkanoidmode = RetroArkanoidStelladaptor; - } - else - { - arkanoidmode = RetroArkanoidMouse; /*default setting*/ - } - } - - var.key = "fceumm_zapper_tolerance"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - FCEU_ZapperSetTolerance(atoi(var.value)); - } - - var.key = "fceumm_mouse_sensitivity"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - mouseSensitivity = atoi(var.value); - } - - var.key = "fceumm_show_crosshair"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - if (!strcmp(var.value, "enabled")) show_crosshair = 1; - else if (!strcmp(var.value, "disabled")) show_crosshair = 0; - } - -#ifdef PSP - var.key = "fceumm_overscan"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - bool newval = (!strcmp(var.value, "enabled")); - if (newval != crop_overscan) - { - overscan_left = (newval == true ? 8 : 0); - overscan_right = (newval == true ? 8 : 0); - overscan_top = (newval == true ? 8 : 0); - overscan_bottom = (newval == true ? 8 : 0); - - crop_overscan = newval; - audio_video_updated = 1; - } - } -#else - var.key = "fceumm_overscan_left"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - int newval = atoi(var.value); - if (newval != overscan_left) - { - overscan_left = newval; - audio_video_updated = 1; - } - } - - var.key = "fceumm_overscan_right"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - int newval = atoi(var.value); - if (newval != overscan_right) - { - overscan_right = newval; - audio_video_updated = 1; - } - } - - var.key = "fceumm_overscan_top"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - int newval = atoi(var.value); - if (newval != overscan_top) - { - overscan_top = newval; - audio_video_updated = 1; - } - } - - var.key = "fceumm_overscan_bottom"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - int newval = atoi(var.value); - if (newval != overscan_bottom) - { - overscan_bottom = newval; - audio_video_updated = 1; - } - } -#endif - - var.key = "fceumm_aspect"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - int oldval = aspect_ratio_par; - if (!strcmp(var.value, "8:7 PAR")) { - aspect_ratio_par = 1; - } else if (!strcmp(var.value, "4:3")) { - aspect_ratio_par = 2; - } else if (!strcmp(var.value, "PP")) { - aspect_ratio_par = 3; - } - if (aspect_ratio_par != oldval) - audio_video_updated = 1; - } - - var.key = "fceumm_turbo_enable"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - nes_input.turbo_enabler[0] = 0; - nes_input.turbo_enabler[1] = 0; - - if (!strcmp(var.value, "Player 1")) - nes_input.turbo_enabler[0] = 1; - else if (!strcmp(var.value, "Player 2")) - nes_input.turbo_enabler[1] = 1; - else if (!strcmp(var.value, "Both")) - { - nes_input.turbo_enabler[0] = 1; - nes_input.turbo_enabler[1] = 1; - } - } - - var.key = "fceumm_turbo_delay"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - nes_input.turbo_delay = atoi(var.value); - - var.key = "fceumm_region"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - unsigned oldval = opt_region; - if (!strcmp(var.value, "Auto")) - opt_region = 0; - else if (!strcmp(var.value, "NTSC")) - opt_region = 1; - else if (!strcmp(var.value, "PAL")) - opt_region = 2; - else if (!strcmp(var.value, "Dendy")) - opt_region = 3; - if (opt_region != oldval) - { - FCEUD_RegionOverride(opt_region); - audio_video_updated = 2; - } - } - - var.key = "fceumm_sndquality"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - unsigned oldval = sndquality; - if (!strcmp(var.value, "Low")) - sndquality = 0; - else if (!strcmp(var.value, "High")) - sndquality = 1; - else if (!strcmp(var.value, "Very High")) - sndquality = 2; - if (sndquality != oldval) - FCEUI_SetSoundQuality(sndquality); - } - - var.key = "fceumm_sndlowpass"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - int lowpass = (!strcmp(var.value, "enabled")) ? 1 : 0; - FCEUI_SetLowPass(lowpass); - } - - var.key = "fceumm_sndstereodelay"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - enum stereo_filter_type filter_type = STEREO_FILTER_NULL; - float filter_delay_ms = STEREO_FILTER_DELAY_MS_DEFAULT; - - if (strcmp(var.value, "disabled") && - (strlen(var.value) > 1)) - { - filter_type = STEREO_FILTER_DELAY; - filter_delay_ms = (float)atoi(var.value); - - filter_delay_ms = (filter_delay_ms < 1.0f) ? - 1.0f : filter_delay_ms; - filter_delay_ms = (filter_delay_ms > 32.0f) ? - 32.0f : filter_delay_ms; - } - - if ((filter_type != current_stereo_filter) || - ((filter_type == STEREO_FILTER_DELAY) && - (filter_delay_ms != stereo_filter_delay_ms))) - { - current_stereo_filter = filter_type; - stereo_filter_delay_ms = filter_delay_ms; - stereo_filter_updated = true; - } - } - - if ((stereo_filter_updated || - (audio_video_updated == 2)) && !startup) - stereo_filter_init(); - - var.key = "fceumm_sndvolume"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - int val = (int)(atof(var.value) * 25.6); - sndvolume = val; - FCEUD_SoundToggle(); - } - - if (audio_video_updated && !startup) - { - struct retro_system_av_info av_info; - retro_get_system_av_info(&av_info); - if (audio_video_updated == 2) - environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &av_info); - else - environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &av_info); - } - - var.key = "fceumm_swapduty"; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - bool newval = (!strcmp(var.value, "enabled")); - if (newval != swapDuty) - swapDuty = newval; - } - - var.key = key; - - enable_apu = 0xff; - - strcpy(key, "fceumm_apu_x"); - for (i = 0; i < 5; i++) - { - key[strlen("fceumm_apu_")] = '1' + i; - var.value = NULL; - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && !strcmp(var.value, "disabled")) - enable_apu &= ~(1 << i); - } - set_apu_channels(enable_apu); - - update_dipswitch(); - - update_option_visibility(); -} - -static const unsigned powerpad_map[] = { - RETRO_DEVICE_ID_JOYPAD_B, - RETRO_DEVICE_ID_JOYPAD_A, - RETRO_DEVICE_ID_JOYPAD_Y, - RETRO_DEVICE_ID_JOYPAD_X, - RETRO_DEVICE_ID_JOYPAD_L, - RETRO_DEVICE_ID_JOYPAD_R, - RETRO_DEVICE_ID_JOYPAD_LEFT, - RETRO_DEVICE_ID_JOYPAD_RIGHT, - RETRO_DEVICE_ID_JOYPAD_UP, - RETRO_DEVICE_ID_JOYPAD_DOWN, - RETRO_DEVICE_ID_JOYPAD_SELECT, - RETRO_DEVICE_ID_JOYPAD_START -}; - -static const unsigned ftrainer_map[] = { - RETRO_DEVICE_ID_JOYPAD_B, - RETRO_DEVICE_ID_JOYPAD_A, - RETRO_DEVICE_ID_JOYPAD_Y, - RETRO_DEVICE_ID_JOYPAD_X, - RETRO_DEVICE_ID_JOYPAD_L, - RETRO_DEVICE_ID_JOYPAD_R, - RETRO_DEVICE_ID_JOYPAD_LEFT, - RETRO_DEVICE_ID_JOYPAD_RIGHT, - RETRO_DEVICE_ID_JOYPAD_UP, - RETRO_DEVICE_ID_JOYPAD_DOWN, - RETRO_DEVICE_ID_JOYPAD_SELECT, - RETRO_DEVICE_ID_JOYPAD_START -}; - -static const unsigned quizking_map[] = { - RETRO_DEVICE_ID_JOYPAD_B, - RETRO_DEVICE_ID_JOYPAD_A, - RETRO_DEVICE_ID_JOYPAD_Y, - RETRO_DEVICE_ID_JOYPAD_X, - RETRO_DEVICE_ID_JOYPAD_L, - RETRO_DEVICE_ID_JOYPAD_R -}; - -static uint32 update_PowerPad(int w) -{ - int x; - uint32 r = 0; - - for (x = 0; x < 12; x++) - r |= input_cb(w, RETRO_DEVICE_JOYPAD, 0, powerpad_map[x]) ? (1 << x) : 0; - - return r; -} - -static void update_FTrainer(void) -{ - int x; - uint32 r = 0; - - for (x = 0; x < 12; x++) - r |= input_cb(4, RETRO_DEVICE_JOYPAD, 0, ftrainer_map[x]) ? (1 << x) : 0; - - nes_input.FTrainerData = r; -} - -static void update_QuizKing(void) -{ - int x; - uint8 r = 0; - - for (x = 0; x < 6; x++) - r |= input_cb(4, RETRO_DEVICE_JOYPAD, 0, quizking_map[x]) ? (1 << x) : 0; - - nes_input.QuizKingData = r; -} - -static int mzx = 0, mzy = 0; - -void get_mouse_input(unsigned port, unsigned variant, uint32_t *mousedata) -{ - int min_width, min_height, max_width, max_height; - - max_width = 256; - max_height = 240; - mousedata[2] = 0; /* reset click state */ - - if ((variant != DEVICE_ARKANOID && zappermode == RetroMouse) || - (variant == DEVICE_ARKANOID && arkanoidmode == RetroArkanoidMouse)) /* mouse device */ - { - min_width = overscan_left + 1; - min_height = overscan_top + 1; - max_width -= overscan_right; - max_height -= overscan_bottom; - - /* TODO: Add some sort of mouse sensitivity */ - mzx += mouseSensitivity * input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X) / 100; - mzy += mouseSensitivity * input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y) / 100; - - switch(variant) - { - case DEVICE_ARKANOID: - if (mzx < 0) mzx = 0; - else if (mzx > 240) mzx = 240; - - if (mzy < min_height) mzy = min_height; - else if (mzy > max_height) mzy = max_height; - - break; - case DEVICE_ZAPPER: - default: - /* Set crosshair within the limits of current screen resolution */ - if (mzx < min_width) mzx = min_width; - else if (mzx > max_width) mzx = max_width; - - if (mzy < min_height) mzy = min_height; - else if (mzy > max_height) mzy = max_height; - break; - } - - mousedata[0] = mzx; - mousedata[1] = mzy; - - if (input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT)) - mousedata[2] |= 0x1; - if (input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_RIGHT)) - mousedata[2] |= 0x2; - } - else if (variant != DEVICE_ARKANOID && zappermode == RetroPointer) - { - int offset_x = (overscan_left * 0x120) - 1; - int offset_y = (overscan_top * 0x133) + 1; - - 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) - { - mousedata[0] = 0; - mousedata[1] = 0; - } - else - { - mousedata[0] = (_x + (0x7FFF + offset_x)) * max_width / ((0x7FFF + offset_x) * 2); - mousedata[1] = (_y + (0x7FFF + offset_y)) * max_height / ((0x7FFF + offset_y) * 2); - } - - if (input_cb(port, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED)) - mousedata[2] |= 0x1; - } - else if (variant == DEVICE_ARKANOID && (arkanoidmode == RetroArkanoidAbsMouse || arkanoidmode == RetroArkanoidPointer)) - { - int offset_x = (overscan_left * 0x120) - 1; - - 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) - { - int32 raw = (_x + (0x7FFF + offset_x)) * max_width / ((0x7FFF + offset_x) * 2); - if (arkanoidmode == RetroArkanoidAbsMouse) - { - /* remap so full screen movement ends up within the encoder range 0-240 */ - /* game board: 176 wide */ - /* paddle: 32 */ - /* range of movement: 176-32 = 144 */ - /* left edge: 16 */ - /* right edge: 64 */ - - /* increase movement by 10 to allow edges to be reached in case of problems */ - raw = (raw - 128) * 140 / 128 + 128; - if (raw < 0) - raw = 0; - else if (raw > 255) - raw = 255; - - mousedata[0] = raw * 240 / 255; - } - else - { - /* remap so full board movement ends up within the encoder range 0-240 */ - if (mousedata[0] < 16+(32/2)) - mousedata[0] = 0; - else - mousedata[0] -= 16+(32/2); - if (mousedata[0] > 144) - mousedata[0] = 144; - mousedata[0] = raw * 240 / 144; - } - } - - if (input_cb(port, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED)) - mousedata[2] |= 0x1; - } - else if (variant == DEVICE_ARKANOID && arkanoidmode == RetroArkanoidStelladaptor) - { - int x = input_cb(port, RETRO_DEVICE_ANALOG, 0, RETRO_DEVICE_ID_ANALOG_X); - mousedata[0] = (x+32768)*240/65535; - if (input_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A) || input_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B)) - mousedata[2] |= 0x1; - } - else /* lightgun device */ - { - int offset_x = (overscan_left * 0x120) - 1; - int offset_y = (overscan_top * 0x133) + 1; - int offscreen; - int offscreen_shot; - int trigger; - - offscreen = input_cb( port, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN ); - offscreen_shot = input_cb( port, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_RELOAD ); - trigger = input_cb( port, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_TRIGGER ); - - if ( offscreen || offscreen_shot ) - { - mousedata[0] = 0; - mousedata[1] = 0; - } - else - { - int _x = input_cb(port, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X); - int _y = input_cb(port, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y); - - mousedata[0] = (_x + (0x7FFF + offset_x)) * max_width / ((0x7FFF + offset_x) * 2); - mousedata[1] = (_y + (0x7FFF + offset_y)) * max_height / ((0x7FFF + offset_y) * 2); - } - - if ( trigger || offscreen_shot ) - mousedata[2] |= 0x1; - } -} - -static void FCEUD_UpdateInput(void) -{ - unsigned player, port; - bool palette_prev = false; - bool palette_next = false; - - poll_cb(); - - /* Reset input states */ - nes_input.JSReturn = 0; - - /* nes gamepad */ - for (player = 0; player < MAX_PLAYERS; player++) - { - int i = 0; - uint8_t input_buf = 0; - int player_enabled = (nes_input.type[player] == DEVICE_GAMEPAD) || - (nes_input.type[player] == RETRO_DEVICE_JOYPAD); - - if (player_enabled) - { - int16_t ret = 0; - bool dpad_enabled = true; - static int last_pressed_keys = 0; - - if (libretro_supports_bitmasks) - { - ret = input_cb(player, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_MASK); - } - else - { - for (i = 0; i <= RETRO_DEVICE_ID_JOYPAD_R3; i++) - ret |= input_cb(player, RETRO_DEVICE_JOYPAD, 0, i) ? (1 << i) : 0; - } - - /* If palette switching is enabled, check if - * player 1 has the L2 button held down */ - if ((player == 0) && - palette_switch_enabled && - (ret & (1 << RETRO_DEVICE_ID_JOYPAD_L2))) - { - /* D-Pad left/right are used to switch palettes */ - palette_prev = (bool)(ret & (1 << RETRO_DEVICE_ID_JOYPAD_LEFT)); - palette_next = (bool)(ret & (1 << RETRO_DEVICE_ID_JOYPAD_RIGHT)); - - /* Regular D-Pad input is disabled */ - dpad_enabled = false; - } - - 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 (dpad_enabled) - { - 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; - } - - if (player == 0) - { - if (!(last_pressed_keys & (1 << RETRO_DEVICE_ID_JOYPAD_L3)) && (ret & (1 << RETRO_DEVICE_ID_JOYPAD_L3))) - replaceP2StartWithMicrophone = !replaceP2StartWithMicrophone; - last_pressed_keys = ret; - } - - /* Turbo A and Turbo B buttons are - * mapped to Joypad X and Joypad Y - * in RetroArch joypad. - * - * We achieve this by keeping track of - * the number of times it increments - * the toggle counter and fire or not fire - * depending on whether the delay value has - * been reached. - * - * Each turbo button is activated by - * corresponding mapped button - * OR mapped Turbo A+B button. - * This allows Turbo A+B button to use - * the same toggle counters as Turbo A - * and Turbo B buttons use separately. - */ - - if (nes_input.turbo_enabler[player]) - { - /* Handle Turbo A, B & A+B buttons */ - for (i = 0; i < TURBO_BUTTONS; i++) - { - if (input_cb(player, RETRO_DEVICE_JOYPAD, 0, turbomap[i].retro)) - { - if (!turbo_button_toggle[player][i]) - input_buf |= turbomap[i].nes; - turbo_button_toggle[player][i]++; - turbo_button_toggle[player][i] %= nes_input.turbo_delay + 1; - } - else - /* If the button is not pressed, just reset the toggle */ - turbo_button_toggle[player][i] = 0; - } - } - } - - if (!nes_input.up_down_allowed) - { - if ((input_buf & JOY_UP) && (input_buf & JOY_DOWN)) - input_buf &= ~(JOY_UP | JOY_DOWN); - if ((input_buf & JOY_LEFT) && (input_buf & JOY_RIGHT)) - input_buf &= ~(JOY_LEFT | JOY_RIGHT); - } - - nes_input.JSReturn |= (input_buf & 0xff) << (player << 3); - } - - /* other inputs*/ - for (port = 0; port < MAX_PORTS; port++) - { - int device = nes_input.type[port]; - - switch (device) - { - case DEVICE_SNESMOUSE: - { - int dx = input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X); - int dy = input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y); - int mb = ((input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT) ? 1 : 0) - | (input_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_RIGHT) ? 2 : 0)); - - nes_input.MouseData[port][0] = dx; - nes_input.MouseData[port][1] = dy; - nes_input.MouseData[port][2] = mb; - } break; - case DEVICE_ARKANOID: - case DEVICE_ZAPPER: - get_mouse_input(port, nes_input.type[port], nes_input.MouseData[port]); - break; - case DEVICE_POWERPADA: - case DEVICE_POWERPADB: - nes_input.PowerPadData[port] = update_PowerPad(port); - break; - case DEVICE_SNESGAMEPAD: - case DEVICE_VIRTUALBOY: - { - int i; - int ret = 0; - nes_input.JoyButtons[port] = 0; - for (i = 0; i <= RETRO_DEVICE_ID_JOYPAD_R3; i++) - ret |= input_cb(port, RETRO_DEVICE_JOYPAD, 0, i) ? (1 << i) : 0; - - nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_UP)) ? JOY_UP : 0; - nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_DOWN)) ? JOY_DOWN : 0; - nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_LEFT)) ? JOY_LEFT : 0; - nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_RIGHT)) ? JOY_RIGHT : 0; - - if (!nes_input.up_down_allowed) - { - if ((nes_input.JoyButtons[port] & JOY_UP) && (nes_input.JoyButtons[port] & JOY_DOWN)) - nes_input.JoyButtons[port] &= ~(JOY_UP | JOY_DOWN); - if ((nes_input.JoyButtons[port] & JOY_LEFT) && (nes_input.JoyButtons[port] & JOY_RIGHT)) - nes_input.JoyButtons[port] &= ~(JOY_LEFT | JOY_RIGHT); - } - - if (nes_input.type[port] == DEVICE_SNESGAMEPAD) - { - nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_B)) ? (1 << 0) : 0; - nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_Y)) ? (1 << 1) : 0; - nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_A)) ? (1 << 8) : 0; - nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_X)) ? (1 << 9) : 0; - nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_L)) ? (1 << 10) : 0; - nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_R)) ? (1 << 11) : 0; - } - else if (nes_input.type[port] == DEVICE_VIRTUALBOY) - { - #define RIGHT_DPAD_DOWN (1 << 0) - #define RIGHT_DPAD_LEFT (1 << 1) - #define RIGHT_DPAD_RIGHT (1 << 8) - #define RIGHT_DPAD_UP (1 << 9) - - nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_B)) ? (1 << 0) : 0; /* Right D-pad Down */ - nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_Y)) ? (1 << 1) : 0; /* Right D-pad Left */ - nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_A)) ? (1 << 8) : 0; /* Right D-pad Right */ - nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_X)) ? (1 << 9) : 0; /* Right D-pad Up */ - nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_L)) ? (1 << 10) : 0; /* Rear Left Trigger */ - nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_R)) ? (1 << 11) : 0; /* Rear Left Trigger */ - nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_L2)) ? (1 << 12) : 0; /* B */ - nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_R2)) ? (1 << 13) : 0; /* A */ - - if (!nes_input.up_down_allowed) - { - if ((nes_input.JoyButtons[port] & RIGHT_DPAD_DOWN) && (nes_input.JoyButtons[port] & RIGHT_DPAD_UP)) - nes_input.JoyButtons[port] &= ~(RIGHT_DPAD_DOWN | RIGHT_DPAD_UP); - if ((nes_input.JoyButtons[port] & RIGHT_DPAD_LEFT) && (nes_input.JoyButtons[port] & RIGHT_DPAD_RIGHT)) - nes_input.JoyButtons[port] &= ~(RIGHT_DPAD_LEFT | RIGHT_DPAD_RIGHT); - } - - #undef RIGHT_DPAD_DOWN - #undef RIGHT_DPAD_LEFT - #undef RIGHT_DPAD_RIGHT - #undef RIGHT_DPAD_UP - } - - nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_SELECT)) ? JOY_SELECT : 0; - nes_input.JoyButtons[port] |= (ret & (1 << RETRO_DEVICE_ID_JOYPAD_START)) ? JOY_START : 0; - - } break; - default: - break; - } - } - - /* famicom inputs */ - switch (nes_input.type[4]) - { - case DEVICE_ARKANOID: - case DEVICE_OEKAKIDS: - case DEVICE_SHADOW: - get_mouse_input(0, nes_input.type[4], nes_input.FamicomData); - break; - case DEVICE_FTRAINERA: - case DEVICE_FTRAINERB: - update_FTrainer(); - break; - case DEVICE_QUIZKING: - update_QuizKing(); - break; - case DEVICE_HYPERSHOT: - { - static int toggle; - int i; - - nes_input.FamicomData[0] = 0; - toggle ^= 1; - for (i = 0; i < 2; i++) - { - - if (input_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B)) - nes_input.FamicomData[0] |= 0x02 << (i * 2); - else if (input_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y)) - { - if (toggle) - nes_input.FamicomData[0] |= 0x02 << (i * 2); - else - nes_input.FamicomData[0] &= ~(0x02 << (i * 2)); - } - if (input_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A)) - nes_input.FamicomData[0] |= 0x04 << (i * 2); - else if (input_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X)) - { - if (toggle) - nes_input.FamicomData[0] |= 0x04 << (i * 2); - else - nes_input.FamicomData[0] &= ~(0x04 << (i * 2)); - } - } - break; - } - } - - if (input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2)) - FCEU_VSUniCoin(); /* Insert Coin VS System */ - - if (GameInfo->type == GIT_FDS) /* Famicom Disk System */ - { - bool curL = input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L); - bool curR = input_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R); - static bool prevL = false, prevR = false; - - if (curL && !prevL) - FCEU_FDSSelect(); /* Swap FDisk side */ - prevL = curL; - - if (curR && !prevR) - FCEU_FDSInsert(-1); /* Insert or eject the disk */ - prevR = curR; - } - - /* Handle internal palette switching */ - if (palette_prev || palette_next) - { - if (palette_switch_counter == 0) - { - int new_palette_index = palette_switch_get_current_index(); - - if (palette_prev) - { - if (new_palette_index > 0) - new_palette_index--; - else - new_palette_index = PAL_TOTAL - 1; - } - else /* palette_next */ - { - if (new_palette_index < PAL_TOTAL - 1) - new_palette_index++; - else - new_palette_index = 0; - } - - palette_switch_set_index(new_palette_index); - } - - palette_switch_counter++; - if (palette_switch_counter >= PALETTE_SWITCH_PERIOD) - palette_switch_counter = 0; - } - else - palette_switch_counter = 0; -} - -static void retro_run_blit(uint8_t *gfx) -{ - unsigned x, y; -#ifdef PSP - static unsigned int __attribute__((aligned(16))) d_list[32]; - void* texture_vram_p = NULL; -#endif - unsigned incr = 0; - unsigned width = 256; - unsigned height = 240; - unsigned pitch = 512; - -#ifdef PSP - if (crop_overscan) - { - width -= 16; - height -= 16; - } - texture_vram_p = (void*) (0x44200000 - (256 * 256)); /* max VRAM address - frame size */ - - sceKernelDcacheWritebackRange(retro_palette,256 * 2); - sceKernelDcacheWritebackRange(XBuf, 256*240 ); - - sceGuStart(GU_DIRECT, d_list); - - /* sceGuCopyImage doesnt seem to work correctly with GU_PSM_T8 - * so we use GU_PSM_4444 ( 2 Bytes per pixel ) instead - * with half the values for pitch / width / x offset - */ - if (crop_overscan) - sceGuCopyImage(GU_PSM_4444, 4, 4, 120, 224, 128, XBuf, 0, 0, 128, texture_vram_p); - else - sceGuCopyImage(GU_PSM_4444, 0, 0, 128, 240, 128, XBuf, 0, 0, 128, texture_vram_p); - - sceGuTexSync(); - sceGuTexImage(0, 256, 256, 256, texture_vram_p); - sceGuTexMode(GU_PSM_T8, 0, 0, GU_FALSE); - sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGB); - sceGuDisable(GU_BLEND); - sceGuClutMode(GU_PSM_5650, 0, 0xFF, 0); - sceGuClutLoad(32, retro_palette); - - sceGuFinish(); - - video_cb(texture_vram_p, width, height, 256); -#elif defined(RENDER_GSKIT_PS2) - uint32_t *buf = (uint32_t *)RETRO_HW_FRAME_BUFFER_VALID; - - if (!ps2) { - if (!environ_cb(RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE, (void **)&ps2) || !ps2) { - FCEU_printf(" Failed to get HW rendering interface!\n"); - return; - } - - if (ps2->interface_version != RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION) { - FCEU_printf(" HW render interface mismatch, expected %u, got %u!\n", - RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION, ps2->interface_version); - return; - } - - ps2->coreTexture->Width = width; - ps2->coreTexture->Height = height; - 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){ (float)overscan_top, - (float)overscan_left, - (float)overscan_bottom, - (float)overscan_right }; - } - - ps2->coreTexture->Clut = (u32*)retro_palette; - ps2->coreTexture->Mem = (u32*)gfx; - - video_cb(buf, width, height, pitch); -#else -#ifdef HAVE_NTSC_FILTER - if (use_ntsc) - { - uint16_t *in; - uint16_t *out; - int32_t h_offset; - int32_t v_offset; - - burst_phase ^= 1; - if (ntsc_setup.merge_fields) - burst_phase = 0; - - nes_ntsc_blit(&nes_ntsc, (NES_NTSC_IN_T const*)gfx, (NES_NTSC_IN_T *)XDBuf, - NES_WIDTH, burst_phase, NES_WIDTH, NES_HEIGHT, - ntsc_video_out, NES_NTSC_WIDTH * sizeof(uint16)); - - width = NES_NTSC_OUT_WIDTH(NES_WIDTH - overscan_left - overscan_right); - height = NES_HEIGHT - overscan_top - overscan_bottom; - pitch = width * sizeof(uint16_t); - h_offset = overscan_left ? NES_NTSC_OUT_WIDTH(overscan_left) : 0; - v_offset = overscan_top; - in = ntsc_video_out + h_offset + NES_NTSC_WIDTH * v_offset; - out = fceu_video_out; - - for (y = 0; y < height; y++) { - memcpy(out, in, pitch); - in += NES_NTSC_WIDTH; - out += width; - } - - video_cb(fceu_video_out, width, height, pitch); - } - else -#endif /* HAVE_NTSC_FILTER */ - { - incr += (overscan_left + overscan_right); - width -= (overscan_left + overscan_right); - height -= (overscan_top + overscan_bottom); - pitch -= (overscan_left + overscan_right) * sizeof(uint16_t); - gfx += (overscan_top * 256) + overscan_left; - - if (use_raw_palette) - { - uint8_t *deemp = XDBuf + (gfx - XBuf); - for (y = 0; y < height; y++, gfx += incr, deemp += incr) - for (x = 0; x < width; x++, gfx++, deemp++) - fceu_video_out[y * width + x] = retro_palette[*gfx & 0x3F] | (*deemp << 2); - } - else - { - for (y = 0; y < height; y++, gfx += incr) - for (x = 0; x < width; x++, gfx++) - fceu_video_out[y * width + x] = retro_palette[*gfx]; - } - video_cb(fceu_video_out, width, height, pitch); - } -#endif -} - -void retro_run(void) -{ - uint8_t *gfx; - int32_t ssize = 0; - bool updated = false; - - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) - check_variables(false); - - if (nes_input.needs_update) - { - /* since you can only update input descriptors all at once, its better to place this callback here, - * so descriptor labels can be updated in real-time when inputs gets changed */ - nes_input.needs_update = false; - update_input_descriptors(); - } - - FCEUD_UpdateInput(); - FCEUI_Emulate(&gfx, &sound, &ssize, 0); - - retro_run_blit(gfx); - - stereo_filter_apply(sound, ssize); - audio_batch_cb((const int16_t*)sound, ssize); -} - -size_t retro_serialize_size(void) -{ - if (serialize_size == 0) - { - /* Something arbitrarily big.*/ - uint8_t *buffer = (uint8_t*)malloc(1000000); - memstream_set_buffer(buffer, 1000000); - - FCEUSS_Save_Mem(); - serialize_size = memstream_get_last_size(); - free(buffer); - } - - return serialize_size; -} - -bool retro_serialize(void *data, size_t size) -{ - /* Cannot save state while Game Genie - * screen is open */ - if (geniestage == 1) - return false; - - if (size != retro_serialize_size()) - return false; - - memstream_set_buffer((uint8_t*)data, size); - FCEUSS_Save_Mem(); - return true; -} - -bool retro_unserialize(const void * data, size_t size) -{ - /* Cannot load state while Game Genie - * screen is open */ - if (geniestage == 1) - return false; - - if (size != retro_serialize_size()) - return false; - - memstream_set_buffer((uint8_t*)data, size); - FCEUSS_Load_Mem(); - return true; -} - -static int checkGG(char c) -{ - static const char lets[16] = { 'A', 'P', 'Z', 'L', 'G', 'I', 'T', 'Y', 'E', 'O', 'X', 'U', 'K', 'S', 'V', 'N' }; - int x; - - for (x = 0; x < 16; x++) - if (lets[x] == toupper(c)) - return 1; - return 0; -} - -static int GGisvalid(const char *code) -{ - size_t len = strlen(code); - uint32 i; - - if (len != 6 && len != 8) - return 0; - - for (i = 0; i < len; i++) - if (!checkGG(code[i])) - return 0; - return 1; -} - -void retro_cheat_reset(void) -{ - FCEU_ResetCheats(); -} - -void retro_cheat_set(unsigned index, bool enabled, const char *code) -{ - char name[256]; - char temp[256]; - char *codepart; - uint16 a; - uint8 v; - int c; - int type = 1; - - if (code == NULL) - return; - - sprintf(name, "N/A"); - strcpy(temp, code); - codepart = strtok(temp, "+,;._ "); - - while (codepart) - { - if ((strlen(codepart) == 7) && (codepart[4]==':')) - { - /* raw code in xxxx:xx format */ - log_cb.log(RETRO_LOG_DEBUG, "Cheat code added: '%s' (Raw)\n", codepart); - codepart[4] = '\0'; - a = strtoul(codepart, NULL, 16); - v = strtoul(codepart + 5, NULL, 16); - c = -1; - /* Zero-page addressing modes don't go through the normal read/write handlers in FCEU, so - * we must do the old hacky method of RAM cheats. */ - if (a < 0x0100) type = 0; - FCEUI_AddCheat(name, a, v, c, type); - } - else if ((strlen(codepart) == 10) && (codepart[4] == '?') && (codepart[7] == ':')) - { - /* raw code in xxxx?xx:xx */ - log_cb.log(RETRO_LOG_DEBUG, "Cheat code added: '%s' (Raw)\n", codepart); - codepart[4] = '\0'; - codepart[7] = '\0'; - a = strtoul(codepart, NULL, 16); - v = strtoul(codepart + 8, NULL, 16); - c = strtoul(codepart + 5, NULL, 16); - /* Zero-page addressing modes don't go through the normal read/write handlers in FCEU, so - * we must do the old hacky method of RAM cheats. */ - if (a < 0x0100) type = 0; - FCEUI_AddCheat(name, a, v, c, type); - } - else if (GGisvalid(codepart) && FCEUI_DecodeGG(codepart, &a, &v, &c)) - { - FCEUI_AddCheat(name, a, v, c, type); - log_cb.log(RETRO_LOG_DEBUG, "Cheat code added: '%s' (GG)\n", codepart); - } - else if (FCEUI_DecodePAR(codepart, &a, &v, &c, &type)) - { - FCEUI_AddCheat(name, a, v, c, type); - log_cb.log(RETRO_LOG_DEBUG, "Cheat code added: '%s' (PAR)\n", codepart); - } - else - log_cb.log(RETRO_LOG_DEBUG, "Invalid or unknown code: '%s'\n", codepart); - codepart = strtok(NULL,"+,;._ "); - } -} - -typedef struct cartridge_db -{ - char title[256]; - uint32_t crc; -} cartridge_db_t; - -static const struct cartridge_db fourscore_db_list[] = -{ - { - "Bomberman II (USA)", - 0x1ebb5b42 - }, -#if 0 - { - "Championship Bowling (USA)", - 0xeac38105 - }, -#endif - { - "Chris Evert & Ivan Lendl in Top Players' Tennis (USA)", - 0xf99e37eb - }, -#if 0 - { - "Crash 'n' the Boys - Street Challenge (USA)", - 0xc7f0c457 - }, -#endif - { - "Four Players' Tennis (Europe)", - 0x48b8ee58 - }, - { - "Danny Sullivan's Indy Heat (Europe)", - 0x27ca0679, - }, - { - "Gauntlet II (Europe)", - 0x79f688bc - }, - { - "Gauntlet II (USA)", - 0x1b71ccdb - }, - { - "Greg Norman's Golf Power (USA)", - 0x1352f1b9 - }, - { - "Harlem Globetrotters (USA)", - 0x2e6ee98d - }, - { - "Ivan 'Ironman' Stewart's Super Off Road (Europe)", - 0x05104517 - }, - { - "Ivan 'Ironman' Stewart's Super Off Road (USA)", - 0x4b041b6b - }, - { - "Kings of the Beach - Professional Beach Volleyball (USA)", - 0xf54b34bd - }, - { - "Magic Johnson's Fast Break (USA)", - 0xc6c2edb5 - }, - { - "M.U.L.E. (USA)", - 0x0939852f - }, - { - "Micro Mages", - 0x4e6b9078 - }, - { - "Monster Truck Rally (USA)", - 0x2f698c4d - }, - { - "NES Play Action Football (USA)", - 0xb9b4d9e0 - }, - { - "Nightmare on Elm Street, A (USA)", - 0xda2cb59a - }, - { - "Nintendo World Cup (Europe)", - 0x8da6667d - }, - { - "Nintendo World Cup (Europe) (Rev A)", - 0x7c16f819 - }, - { - "Nintendo World Cup (Europe) (Rev B)", - 0x7f08d0d9 - }, - { - "Nintendo World Cup (USA)", - 0xa22657fa - }, - { - "R.C. Pro-Am II (Europe)", - 0x308da987 - }, - { - "R.C. Pro-Am II (USA)", - 0x9edd2159 - }, - { - "Rackets & Rivals (Europe)", - 0x8fa6e92c - }, - { - "Roundball - 2-on-2 Challenge (Europe)", - 0xad0394f0 - }, - { - "Roundball - 2-on-2 Challenge (USA)", - 0x6e4dcfd2 - }, - { - "Spot - The Video Game (Japan)", - 0x0abdd5ca - }, - { - "Spot - The Video Game (USA)", - 0xcfae9dfa - }, - { - "Smash T.V. (Europe)", - 0x0b8f8128 - }, - { - "Smash T.V. (USA)", - 0x6ee94d32 - }, - { - "Super Jeopardy! (USA)", - 0xcf4487a2 - }, - { - "Super Spike V'Ball (Europe)", - 0xc05a63b2 - }, - { - "Super Spike V'Ball (USA)", - 0xe840fd21 - }, - { - "Super Spike V'Ball + Nintendo World Cup (USA)", - 0x407d6ffd - }, - { - "Swords and Serpents (Europe)", - 0xd153caf6 - }, - { - "Swords and Serpents (France)", - 0x46135141 - }, - { - "Swords and Serpents (USA)", - 0x3417ec46 - }, - { - "Battle City (Japan) (4 Players Hack) http://www.romhacking.net/hacks/2142/", - 0x69977c9e - }, - { - "Bomberman 3 (Homebrew) http://tempect.de/senil/games.html", - 0x2da5ece0 - }, - { - "K.Y.F.F. (Homebrew) http://slydogstudios.org/index.php/k-y-f-f/", - 0x90d2e9f0 - }, - { - "Super PakPak (Homebrew) http://wiki.nesdev.com/w/index.php/Super_PakPak", - 0x1394ded0 - }, - { - "Super Mario Bros. + Tetris + Nintendo World Cup (Europe)", - 0x73298c87 - }, - { - "Super Mario Bros. + Tetris + Nintendo World Cup (Europe) (Rev A)", - 0xf46ef39a - } -}; - -static const struct cartridge_db famicom_4p_db_list[] = -{ - { - "Bakutoushi Patton-Kun (Japan) (FDS)", - 0xc39b3bb2 - }, - { - "Bomber Man II (Japan)", - 0x0c401790 - }, - { - "Championship Bowling (Japan)", - 0x9992f445 - }, - { - "Downtown - Nekketsu Koushinkyoku - Soreyuke Daiundoukai (Japan)", - 0x3e470fe0 - }, - { - "Ike Ike! Nekketsu Hockey-bu - Subette Koronde Dairantou (Japan)", - 0x4f032933 - }, - { - "Kunio-kun no Nekketsu Soccer League (Japan)", - 0x4b5177e9 - }, - { - "Moero TwinBee - Cinnamon Hakase o Sukue! (Japan)", - 0x9f03b11f - }, - { - "Moero TwinBee - Cinnamon Hakase wo Sukue! (Japan) (FDS)", - 0x13205221 - }, - { - "Nekketsu Kakutou Densetsu (Japan)", - 0x37e24797 - }, - { - "Nekketsu Koukou Dodgeball-bu (Japan)", - 0x62c67984 - }, - { - "Nekketsu! Street Basket - Ganbare Dunk Heroes (Japan)", - 0x88062d9a - }, - { - "Super Dodge Ball (USA) (3-4p with Game Genie code GEUOLZZA)", - 0x689971f9 - }, - { - "Super Dodge Ball (USA) (patched) http://www.romhacking.net/hacks/71/", - 0x4ff17864 - }, - { - "U.S. Championship V'Ball (Japan)", - 0x213cb3fb - }, - { - "U.S. Championship V'Ball (Japan) (Beta)", - 0xd7077d96 - }, - { - "Wit's (Japan)", - 0xb1b16b8a - } -}; - -bool retro_load_game(const struct retro_game_info *info) -{ - unsigned i, j; - const char *system_dir = NULL; - size_t fourscore_len = sizeof(fourscore_db_list) / sizeof(fourscore_db_list[0]); - size_t famicom_4p_len = sizeof(famicom_4p_db_list) / sizeof(famicom_4p_db_list[0]); - enum retro_pixel_format rgb565; - - size_t desc_base = 64; - struct retro_memory_descriptor descs[64 + 4]; - struct retro_memory_map mmaps; - - struct retro_game_info_ext *info_ext = NULL; - const uint8_t *content_data = NULL; - size_t content_size = 0; - char content_path[2048] = {0}; - - /* Attempt to fetch extended game info */ - if (environ_cb(RETRO_ENVIRONMENT_GET_GAME_INFO_EXT, &info_ext) && info_ext) - { - content_data = (const uint8_t *)info_ext->data; - content_size = info_ext->size; - - if (info_ext->file_in_archive) - { - /* We don't have a 'physical' file in this - * case, but the core still needs a filename - * in order to detect the region of iNES v1.0 - * ROMs. We therefore fake it, using the content - * directory, canonical content name, and content - * file extension */ - snprintf(content_path, sizeof(content_path), "%s%c%s.%s", - info_ext->dir, - PATH_DEFAULT_SLASH_C(), - info_ext->name, - info_ext->ext); - } - else - strlcpy(content_path, info_ext->full_path, - sizeof(content_path)); - } - else - { - if (!info || string_is_empty(info->path)) - return false; - - strlcpy(content_path, info->path, - sizeof(content_path)); - } - -#ifdef FRONTEND_SUPPORTS_RGB565 - rgb565 = RETRO_PIXEL_FORMAT_RGB565; - if(environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &rgb565)) - 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; - dendy = 0; - opt_region = 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(); -#if defined(_3DS) - fceu_video_out = (uint16_t*)linearMemAlign(256 * 240 * sizeof(uint16_t), 128); -#elif !defined(PSP) -#ifdef HAVE_NTSC_FILTER -#define FB_WIDTH NES_NTSC_WIDTH -#define FB_HEIGHT NES_HEIGHT -#else /* !HAVE_NTSC_FILTER */ -#define FB_WIDTH NES_WIDTH -#define FB_HEIGHT NES_HEIGHT -#endif - fceu_video_out = (uint16_t*)malloc(FB_WIDTH * FB_HEIGHT * sizeof(uint16_t)); -#endif - - if (environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &system_dir) && system_dir) - FCEUI_SetBaseDirectory(system_dir); - - memset(base_palette, 0, sizeof(base_palette)); - - FCEUI_Initialize(); - - FCEUI_SetSoundVolume(sndvolume); - FCEUI_Sound(sndsamplerate); - - GameInfo = (FCEUGI*)FCEUI_LoadGame(content_path, content_data, content_size, - frontend_post_load_init); - - if (!GameInfo) - { -#if 0 - /* An error message here is superfluous - the frontend - * will report that content loading has failed */ - FCEUD_DispMessage(RETRO_LOG_ERROR, 3000, "ROM loading failed..."); -#endif - return false; - } - - for (i = 0; i < MAX_PORTS; i++) { - FCEUI_SetInput(i, SI_GAMEPAD, &nes_input.JSReturn, 0); - nes_input.type[i] = DEVICE_GAMEPAD; - } - - update_input_descriptors(); - - external_palette_exist = ipalette; - if (external_palette_exist) - FCEU_printf(" Loading custom palette: %s%cnes.pal\n", - system_dir, PATH_DEFAULT_SLASH_C()); - - /* Save region and dendy mode for region-auto detect */ - systemRegion = (dendy << 1) | (retro_get_region() & 1); - - current_palette = 0; - - ResetPalette(); - FCEUD_SoundToggle(); - check_variables(true); - stereo_filter_init(); - PowerNES(); - - FCEUI_DisableFourScore(1); - - for (i = 0; i < fourscore_len; i++) - { - if (fourscore_db_list[i].crc == iNESCart.CRC32) - { - FCEUI_DisableFourScore(0); - nes_input.enable_4player = true; - break; - } - } - - for (i = 0; i < famicom_4p_len; i++) - { - if (famicom_4p_db_list[i].crc == iNESCart.CRC32) - { - GameInfo->inputfc = SIFC_4PLAYER; - FCEUI_SetInputFC(SIFC_4PLAYER, &nes_input.JSReturn, 0); - nes_input.enable_4player = true; - break; - } - } - - memset(descs, 0, sizeof(descs)); - i = 0; - - for (j = 0; j < desc_base; j++) - { - if (MMapPtrs[j] != NULL) - { - descs[i].ptr = MMapPtrs[j]; - descs[i].start = j * 1024; - descs[i].len = 1024; - descs[i].select = 0; - i++; - } - } - /* This doesn't map in 2004--2007 but those aren't really - * worthwhile to read from on a vblank anyway - */ - descs[i].flags = 0; - descs[i].ptr = PPU; - descs[i].offset = 0; - descs[i].start = 0x2000; - descs[i].select = 0; - descs[i].disconnect = 0; - descs[i].len = 4; - descs[i].addrspace="PPUREG"; - i++; - /* In the future, it would be good to map pattern tables 1 and 2, - * but these must be remapped often - */ - /* descs[i] = (struct retro_memory_descriptor){0, ????, 0, 0x0000 | PPU_BIT, PPU_BIT, PPU_BIT, 0x1000, "PAT0"}; */ - /* i++; */ - /* descs[i] = (struct retro_memory_descriptor){0, ????, 0, 0x1000 | PPU_BIT, PPU_BIT, PPU_BIT, 0x1000, "PAT1"}; */ - /* i++; */ - /* Likewise it would be better to use "vnapage" for this but - * RetroArch API is inconvenient for handles like that, so we'll - * just blithely assume the client will handle mapping and that - * we'll ignore those carts that have extra NTARAM. - */ - descs[i].flags = 0; - descs[i].ptr = NTARAM; - descs[i].offset = 0; - descs[i].start = PPU_BIT | 0x2000; - descs[i].select = PPU_BIT; - descs[i].disconnect = PPU_BIT; - descs[i].len = 0x0800; - descs[i].addrspace="NTARAM"; - i++; - descs[i].flags = 0; - descs[i].ptr = PALRAM; - descs[i].offset = 0; - descs[i].start = PPU_BIT | 0x3000; - descs[i].select = PPU_BIT; - descs[i].disconnect = PPU_BIT; - descs[i].len = 0x020; - descs[i].addrspace="PALRAM"; - i++; - /* OAM doesn't really live anywhere in address space so I'll put it at 0x4000. */ - descs[i].flags = 0; - descs[i].ptr = SPRAM; - descs[i].offset = 0; - descs[i].start = PPU_BIT | 0x4000; - descs[i].select = PPU_BIT; - descs[i].disconnect = PPU_BIT; - descs[i].len = 0x100; - descs[i].addrspace="OAM"; - i++; - mmaps.descriptors = descs; - mmaps.num_descriptors = i; - environ_cb(RETRO_ENVIRONMENT_SET_MEMORY_MAPS, &mmaps); - - /* make sure we run input descriptors */ - nes_input.needs_update = true; - - return true; -} - -bool retro_load_game_special( - unsigned game_type, - const struct retro_game_info *info, size_t num_info -) -{ - return false; -} - -void retro_unload_game(void) -{ - FCEUI_CloseGame(); -#if defined(_3DS) - if (fceu_video_out) - linearFree(fceu_video_out); -#else - if (fceu_video_out) - free(fceu_video_out); - fceu_video_out = NULL; -#endif -#if defined(RENDER_GSKIT_PS2) - ps2 = NULL; -#endif -#ifdef HAVE_NTSC_FILTER - NTSCFilter_Cleanup(); -#endif -} - -unsigned retro_get_region(void) -{ - return FSettings.PAL ? RETRO_REGION_PAL : RETRO_REGION_NTSC; -} - -void *retro_get_memory_data(unsigned type) -{ - uint8_t* data; - - switch(type) - { - case RETRO_MEMORY_SAVE_RAM: - if (iNESCart.battery && iNESCart.SaveGame[0] && iNESCart.SaveGameLen[0]) - return iNESCart.SaveGame[0]; - else if (UNIFCart.battery && UNIFCart.SaveGame[0] && UNIFCart.SaveGameLen[0]) - return UNIFCart.SaveGame[0]; - else if (GameInfo->type == GIT_FDS) - return FDSROM_ptr(); - else - data = NULL; - break; - case RETRO_MEMORY_SYSTEM_RAM: - data = RAM; - break; - default: - data = NULL; - break; - } - - return data; -} - -size_t retro_get_memory_size(unsigned type) -{ - unsigned size; - - switch(type) - { - case RETRO_MEMORY_SAVE_RAM: - if (iNESCart.battery && iNESCart.SaveGame[0] && iNESCart.SaveGameLen[0]) - size = iNESCart.SaveGameLen[0]; - else if (UNIFCart.battery && UNIFCart.SaveGame[0] && UNIFCart.SaveGameLen[0]) - size = UNIFCart.SaveGameLen[0]; - else if (GameInfo->type == GIT_FDS) - size = FDSROM_size(); - else - size = 0; - break; - case RETRO_MEMORY_SYSTEM_RAM: - size = 0x800; - break; - default: - size = 0; - break; - } - - return size; -} diff --git a/src/drivers/libretro/libretro_dipswitch.h b/src/drivers/libretro/libretro_dipswitch.h deleted file mode 100644 index a0ef57950..000000000 --- a/src/drivers/libretro/libretro_dipswitch.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __VSUNI_DIPSWITCH__ -#define __VSUNI_DIPSWITCH__ - -#include - -void set_dipswitch_variables(unsigned current_index, struct retro_core_option_v2_definition *vars); -void update_dipswitch(void); -void DPSW_Cleanup(void); - -extern retro_environment_t environ_cb; - -#endif /* __VSUNI_DIPSWITCH__ */ diff --git a/src/drivers/libretro/zlib.h b/src/drivers/libretro/zlib.h deleted file mode 100644 index 6891d881d..000000000 --- a/src/drivers/libretro/zlib.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef _ZLIB_STUB_H -#define _ZLIB_STUB_H - -#endif diff --git a/src/fceu-endian.c b/src/fceu-endian.c index 32aec45bc..e5fcc15fc 100644 --- a/src/fceu-endian.c +++ b/src/fceu-endian.c @@ -25,58 +25,55 @@ #include "fceu-types.h" #include "fceu-endian.h" -void FlipByteOrder(uint8 *src, uint32 count) -{ - uint8 *start = src; - uint8 *end = src + count - 1; +void FlipByteOrder(uint8 *src, uint32 count) { + uint8 *start = src; + uint8 *end = src + count - 1; - if ((count & 1) || !count) - return; /* This shouldn't happen. */ + if ((count & 1) || !count) { + return; /* This shouldn't happen. */ + } - while (count--) - { - uint8 tmp; + while (count--) { + uint8 tmp; - tmp = *end; - *end = *start; - *start = tmp; - end--; - start++; - } + tmp = *end; + *end = *start; + *start = tmp; + end--; + start++; + } } -int write32le_mem(uint32 b, memstream_t *mem) -{ - uint8 s[4]; - s[0]=b; - s[1]=b>>8; - s[2]=b>>16; - s[3]=b>>24; - return((memstream_write(mem, s, 4)<4)?0:4); +int write32le_mem(uint32 b, memstream_t *mem) { + uint8 s[4]; + s[0] = b; + s[1] = b >> 8; + s[2] = b >> 16; + s[3] = b >> 24; + return ((memstream_write(mem, s, 4) < 4) ? 0 : 4); } -int read32le_mem(uint32 *Bufo, memstream_t *mem) -{ - uint32 buf; - if(memstream_read(mem, &buf, 4)<4) - return 0; +int read32le_mem(uint32 *Bufo, memstream_t *mem) { + uint32 buf; + if (memstream_read(mem, &buf, 4) < 4) { + return 0; + } #ifdef MSB_FIRST - *(uint32*)Bufo=((buf&0xFF)<<24)|((buf&0xFF00)<<8)|((buf&0xFF0000)>>8)|((buf&0xFF000000)>>24); + *(uint32 *)Bufo = + ((buf & 0xFF) << 24) | ((buf & 0xFF00) << 8) | ((buf & 0xFF0000) >> 8) | ((buf & 0xFF000000) >> 24); #else - *(uint32*)Bufo=buf; + *(uint32 *)Bufo = buf; #endif - return 1; + return 1; } -void FCEU_en32lsb(uint8 *buf, uint32 morp) -{ - buf[0] = morp; - buf[1] = morp >> 8; - buf[2] = morp >> 16; - buf[3] = morp >> 24; +void FCEU_en32lsb(uint8 *buf, uint32 morp) { + buf[0] = morp; + buf[1] = morp >> 8; + buf[2] = morp >> 16; + buf[3] = morp >> 24; } -uint32 FCEU_de32lsb(const uint8 *morp) -{ - return(morp[0] | (morp[1] << 8) | (morp[2] << 16) | (morp[3] << 24)); +uint32 FCEU_de32lsb(const uint8 *morp) { + return (morp[0] | (morp[1] << 8) | (morp[2] << 16) | (morp[3] << 24)); } diff --git a/src/fceu-memory.c b/src/fceu-memory.c index 2b99dfbb9..4785bfd47 100644 --- a/src/fceu-memory.c +++ b/src/fceu-memory.c @@ -26,37 +26,46 @@ #include "fceu-memory.h" #include "general.h" -void *FCEU_gmalloc(uint32 size) -{ - void *ret = malloc(size); - if (!ret) - { - FCEU_PrintError("Error allocating memory! Doing a hard exit."); - exit(1); - } - memset(ret, 0, size); - return ret; +#include "memalign.h" + +void *FCEU_amalloc(uint32 size) { + void *ret = memalign_alloc(256, size); + if (!ret) { + FCEU_PrintError("Error allocating memory! Doing a hard exit."); + exit(1); + } + return ret; +} + +void *FCEU_gmalloc(uint32 size) { + void *ret = malloc(size); + if (!ret) { + FCEU_PrintError("Error allocating memory! Doing a hard exit."); + exit(1); + } + FCEU_MemoryRand((uint8 *)ret, size); + return ret; +} + +void *FCEU_malloc(uint32 size) { + void *ret = (void *)malloc(size); + + if (!ret) { + FCEU_PrintError("Error allocating memory!"); + ret = 0; + } + memset(ret, 0, size); + return ret; } -void *FCEU_malloc(uint32 size) -{ - void *ret = (void*)malloc(size); - - if (!ret) - { - FCEU_PrintError("Error allocating memory!"); - ret = 0; - } - memset(ret, 0, size); - return ret; +void FCEU_afree(void *ptr) { + memalign_free(ptr); } -void FCEU_free(void *ptr) -{ +void FCEU_free(void *ptr) { free(ptr); } -void FCEU_gfree(void *ptr) -{ +void FCEU_gfree(void *ptr) { free(ptr); } diff --git a/src/fceu-memory.h b/src/fceu-memory.h index bd61d6b7b..13c7e980d 100644 --- a/src/fceu-memory.h +++ b/src/fceu-memory.h @@ -29,9 +29,23 @@ #define FCEU_dwmemset(d, c, n) { int _x; for (_x = n - 4; _x >= 0; _x -= 4) *(uint32*)& (d)[_x] = c; } +/* returns an aligned buffer */ +void *FCEU_amalloc(uint32 size); + +/* returns a buffer initialized to 0 */ void *FCEU_malloc(uint32 size); + +/* returns a buffer with initialization based on FCEU_MemoryRand() */ +/* Used by mappers for wram, chr ram, etc */ void *FCEU_gmalloc(uint32 size); + +/* free memory allocated by FCEU_amalloc */ +void FCEU_afree(void *ptr); + +/* free memory allocated by FCEU_gmalloc */ void FCEU_gfree(void *ptr); + +/* free memory allocated by FCEU_malloc */ void FCEU_free(void *ptr); #endif diff --git a/src/fceu-types.h b/src/fceu-types.h index 78ab88a0d..54aeed6b6 100644 --- a/src/fceu-types.h +++ b/src/fceu-types.h @@ -23,6 +23,7 @@ #define __FCEU_TYPES_H #include + typedef int8_t int8; typedef int16_t int16; typedef int32_t int32; @@ -34,13 +35,13 @@ typedef uint32_t uint32; #ifdef __GNUC__ typedef unsigned long long uint64; typedef long long int64; - #define GINLINE inline +#define GINLINE inline #elif MSVC | _MSC_VER typedef __int64 int64; typedef unsigned __int64 uint64; - #define GINLINE /* Can't declare a function INLINE - * and global in MSVC. Bummer. - */ +#define GINLINE /* Can't declare a function INLINE \ + * and global in MSVC. Bummer. \ + */ #else typedef unsigned long long uint64; typedef long long int64; @@ -59,25 +60,26 @@ typedef long long int64; #endif #endif -#ifdef __GNUC__ - #ifdef C80x86 - #define FASTAPASS(x) __attribute__((regparm(x))) - #define FP_FASTAPASS FASTAPASS - #else - #define FASTAPASS(x) - #define FP_FASTAPASS(x) - #endif -#elif MSVC - #define FP_FASTAPASS(x) - #define FASTAPASS(x) __fastcall -#else - #define FP_FASTAPASS(x) - #define FASTAPASS(x) +#define FCEU_UNUSED(x) (void)(x) +#define FCEU_MAYBE_UNUSED __attribute__((unused)) + +#if !defined(FALSE) +#define FALSE 0 #endif -#define FCEU_MAYBE_UNUSED(x) (void)(x) +#if !defined(TRUE) +#define TRUE 1 +#endif + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif -typedef void (FP_FASTAPASS(2) *writefunc)(uint32 A, uint8 V); -typedef uint8 (FP_FASTAPASS(1) *readfunc)(uint32 A); +typedef void (*writefunc)(uint32 A, uint8 V); +typedef uint8 (*readfunc)(uint32 A); #endif diff --git a/src/fceu.c b/src/fceu.c index 58e0cf215..fb7d86ef0 100644 --- a/src/fceu.c +++ b/src/fceu.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "fceu.h" #include "fceu-types.h" @@ -45,6 +46,7 @@ #include "file.h" #include "crc32.h" #include "vsuni.h" +#include "gamegenie.h" uint64 timestampbase; @@ -55,311 +57,317 @@ void (*GameStateRestore)(int version); readfunc ARead[0x10000]; writefunc BWrite[0x10000]; -static readfunc *AReadG = NULL; -static writefunc *BWriteG = NULL; -static int RWWrap = 0; - -static DECLFW(BNull) -{ -} - -static DECLFR(ANull) -{ - return(X.DB); -} - -int AllocGenieRW(void) -{ - if (!AReadG) - { - if (!(AReadG = (readfunc*)FCEU_malloc(0x8000 * sizeof(readfunc)))) - return 0; - } - else - memset(AReadG, 0, 0x8000 * sizeof(readfunc)); - - if (!BWriteG) - { - if (!(BWriteG = (writefunc*)FCEU_malloc(0x8000 * sizeof(writefunc)))) - return 0; - } - else - memset(BWriteG, 0, 0x8000 * sizeof(writefunc)); - - RWWrap = 1; - return 1; -} - -void FlushGenieRW(void) -{ - int32 x; - - if (RWWrap) - { - for (x = 0; x < 0x8000; x++) - { - ARead[x + 0x8000] = AReadG[x]; - BWrite[x + 0x8000] = BWriteG[x]; - } - free(AReadG); - free(BWriteG); - AReadG = NULL; - BWriteG = NULL; - } - RWWrap = 0; -} - -readfunc FASTAPASS(1) GetReadHandler(int32 a) -{ - if (a >= 0x8000 && RWWrap) + +static DECLFW(BNull) { } + +static DECLFR(ANull) { + return (cpu.openbus); +} + +readfunc GetReadHandler(int32 a) { + if (a >= 0x8000 && RWWrap) { return AReadG[a - 0x8000]; - else + } else { return ARead[a]; + } } -void FASTAPASS(3) SetReadHandler(int32 start, int32 end, readfunc func) -{ +void SetReadHandler(int32 start, int32 end, readfunc func) { int32 x; - if (!func) + if (!func) { func = ANull; + } - if (RWWrap) - for (x = end; x >= start; x--) - { - if (x >= 0x8000) - AReadG[x - 0x8000] = func; - else - ARead[x] = func; - } - else - for (x = end; x >= start; x--) + if (RWWrap) { + for (x = end; x >= start; x--) { + if (x >= 0x8000) { + AReadG[x - 0x8000] = func; + } else { + ARead[x] = func; + } + } + } else { + for (x = end; x >= start; x--) { ARead[x] = func; + } + } } -writefunc FASTAPASS(1) GetWriteHandler(int32 a) -{ - if (RWWrap && a >= 0x8000) +writefunc GetWriteHandler(int32 a) { + if (RWWrap && a >= 0x8000) { return BWriteG[a - 0x8000]; - else + } else { return BWrite[a]; + } } -void FASTAPASS(3) SetWriteHandler(int32 start, int32 end, writefunc func) -{ +void SetWriteHandler(int32 start, int32 end, writefunc func) { int32 x; - if (!func) + if (!func) { func = BNull; + } - if (RWWrap) - for (x = end; x >= start; x--) - { - if (x >= 0x8000) + if (RWWrap) { + for (x = end; x >= start; x--) { + if (x >= 0x8000) { BWriteG[x - 0x8000] = func; - else + } else { BWrite[x] = func; + } } - else - for (x = end; x >= start; x--) + } else { + for (x = end; x >= start; x--) { BWrite[x] = func; + } + } } -uint8 RAM[0x800]; +uint8 *RAM; + +uint8 isPAL = FALSE; +uint8 isDendy = FALSE; -uint8 PAL = 0; +static int AllocBuffers(void) { + RAM = (uint8 *)FCEU_malloc(RAM_SIZE); + if (!RAM) { + return FALSE; + } + return TRUE; +} -static DECLFW(BRAML) -{ +static void FreeBuffers(void) { + if (RAM) { + FCEU_free(RAM); + } + RAM = NULL; +} + +static DECLFW(BRAML) { RAM[A] = V; } -static DECLFR(ARAML) -{ +static DECLFR(ARAML) { return RAM[A]; } -static DECLFW(BRAMH) -{ - RAM[A & 0x7FF] = V; +static DECLFW(BRAMH) { + RAM[A & RAM_MASK] = V; } -static DECLFR(ARAMH) -{ - return RAM[A & 0x7FF]; +static DECLFR(ARAMH) { + return RAM[A & RAM_MASK]; } -void FCEUI_CloseGame(void) -{ - if (!GameInfo) - return; +void FCEUI_CloseGame(void) { + if (!GameInfo) { + return; + } - if (GameInfo->name) - free(GameInfo->name); - GameInfo->name = 0; - if (GameInfo->type != GIT_NSF) - FCEU_FlushGameCheats(); - GameInterface(GI_CLOSE); - ResetExState(0, 0); - FCEU_CloseGenie(); - free(GameInfo); - GameInfo = 0; + if (GameInfo->name) { + free(GameInfo->name); + } + GameInfo->name = NULL; + if (GameInfo->type != GIT_NSF) { + FCEU_FlushGameCheats(); + } + GameInterface(GI_CLOSE); + ResetExState(0, 0); + FCEU_CloseGenie(); + free(GameInfo); + GameInfo = NULL; } -void ResetGameLoaded(void) -{ - if (GameInfo) - FCEUI_CloseGame(); +void ResetGameLoaded(void) { + int x; + + if (GameInfo) { + FCEUI_CloseGame(); + } GameStateRestore = NULL; - PPU_hook = NULL; - GameHBIRQHook = NULL; + PPU_hook = NULL; + GameHBIRQHook = NULL; + + for (x = 0; x < GAMEEXPSOUND_COUNT; x++) { + if (GameExpSound[x].Kill) { + GameExpSound[x].Kill(); + } + } - if (GameExpSound.Kill) - GameExpSound.Kill(); memset(&GameExpSound, 0, sizeof(GameExpSound)); MapIRQHook = NULL; - MMC5Hack = 0; - PEC586Hack = 0; - PAL &= 1; - pale = 0; + MMC5Hack = FALSE; + PEC586Hack = FALSE; + isPAL &= 1; + palette_nes_selected = PAL_NES_DEFAULT; } -int UNIFLoad(const char *name, FCEUFILE *fp); -int iNESLoad(const char *name, FCEUFILE *fp); -int FDSLoad(const char *name, FCEUFILE *fp); -int NSFLoad(FCEUFILE *fp); - FCEUGI *FCEUI_LoadGame(const char *name, const uint8_t *databuf, size_t databufsize, - frontend_post_load_init_cb_t frontend_post_load_init_cb) -{ - FCEUFILE *fp; + frontend_post_load_init_cb_t frontend_post_load_init_cb) { + FCEUFILE *fp; - ResetGameLoaded(); + ResetGameLoaded(); - GameInfo = malloc(sizeof(FCEUGI)); - memset(GameInfo, 0, sizeof(FCEUGI)); + GameInfo = malloc(sizeof(FCEUGI)); + memset(GameInfo, 0, sizeof(FCEUGI)); - GameInfo->soundchan = 0; - GameInfo->soundrate = 0; - GameInfo->name = 0; - GameInfo->type = GIT_CART; - GameInfo->vidsys = GIV_USER; - GameInfo->input[0] = GameInfo->input[1] = -1; - GameInfo->inputfc = -1; - GameInfo->cspecial = 0; + GameInfo->soundchan = 0; + GameInfo->soundrate = 0; + GameInfo->name = 0; + GameInfo->type = GIT_CART; + GameInfo->vidsys = GIV_USER; + GameInfo->input[0] = -1; + GameInfo->input[1] = -1; + GameInfo->inputfc = -1; + GameInfo->cspecial = 0; - fp = FCEU_fopen(name, databuf, databufsize); + fp = FCEU_fopen(name, databuf, databufsize); - if (!fp) { - FCEU_PrintError("Error opening \"%s\"!", name); + if (!fp) { + FCEU_PrintError("Error opening \"%s\"!", name); - free(GameInfo); - GameInfo = NULL; + free(GameInfo); + GameInfo = NULL; - return NULL; - } + return NULL; + } - if (iNESLoad(name, fp)) - goto endlseq; - if (NSFLoad(fp)) - goto endlseq; - if (UNIFLoad(NULL, fp)) - goto endlseq; - if (FDSLoad(NULL, fp)) - goto endlseq; + if (iNESLoad(name, fp)) { + goto endlseq; + } + if (NSFLoad(fp)) { + goto endlseq; + } + if (UNIFLoad(NULL, fp)) { + goto endlseq; + } + if (FDSLoad(NULL, fp)) { + goto endlseq; + } - FCEU_PrintError("An error occurred while loading the file.\n"); - FCEU_fclose(fp); + FCEU_PrintError("An error occurred while loading the file.\n"); + FCEU_fclose(fp); - if (GameInfo->name) - free(GameInfo->name); - GameInfo->name = NULL; - free(GameInfo); - GameInfo = NULL; + if (GameInfo->name) { + free(GameInfo->name); + } + GameInfo->name = NULL; + free(GameInfo); + GameInfo = NULL; - return NULL; + return NULL; endlseq: - FCEU_fclose(fp); + FCEU_fclose(fp); - if (frontend_post_load_init_cb) - (*frontend_post_load_init_cb)(); + if (frontend_post_load_init_cb) { + (*frontend_post_load_init_cb)(); + } - FCEU_ResetVidSys(); - if (GameInfo->type != GIT_NSF) - if (FSettings.GameGenie) - FCEU_OpenGenie(); + FCEU_ResetVidSys(); + if (GameInfo->type != GIT_NSF) { + if (FSettings.GameGenie) { + FCEU_OpenGenie(); + } + } - PowerNES(); + PowerNES(); - if (GameInfo->type != GIT_NSF) { - FCEU_LoadGamePalette(); - FCEU_LoadGameCheats(); - } + if (GameInfo->type != GIT_NSF) { + FCEU_LoadGamePalette(); + FCEU_LoadGameCheats(); + } - FCEU_ResetPalette(); + FCEU_ResetPalette(); - return(GameInfo); + return (GameInfo); } int FCEUI_Initialize(void) { - if (!FCEU_InitVirtualVideo()) - return 0; + srand(time(0)); + + if (!AllocBuffers()) { + return FALSE; + } + + if (!FCEU_InitVirtualVideo()) { + return FALSE; + } + memset(&FSettings, 0, sizeof(FSettings)); - FSettings.UsrFirstSLine[0] = 8; - FSettings.UsrFirstSLine[1] = 0; - FSettings.UsrLastSLine[0] = 231; - FSettings.UsrLastSLine[1] = 239; - FSettings.SoundVolume = 100; + + FSettings.UsrFirstSLine[0] = 8; + FSettings.UsrFirstSLine[1] = 0; + FSettings.UsrLastSLine[0] = 231; + FSettings.UsrLastSLine[1] = 239; + FSettings.volume[SND_MASTER] = 256; + FSettings.volume[SND_SQUARE1] = 256; + FSettings.volume[SND_SQUARE2] = 256; + FSettings.volume[SND_TRIANGLE] = 256; + FSettings.volume[SND_NOISE] = 256; + FSettings.volume[SND_DMC] = 256; + FSettings.volume[SND_FDS] = 256; + FSettings.volume[SND_MMC5] = 256; + FSettings.volume[SND_N163] = 256; + FSettings.volume[SND_S5B] = 256; + FSettings.volume[SND_VRC6] = 256; + FSettings.volume[SND_VRC7] = 256; + FCEUPPU_Init(); X6502_Init(); - return 1; + + return TRUE; } void FCEUI_Kill(void) { FCEU_KillVirtualVideo(); FCEU_KillGenie(); + FreeBuffers(); } -void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int skip) { +void FCEUI_Emulate(uint8 **pXBuf, uint8 **pXDBuf, int32 **SoundBuf, int32 *SoundBufSize, int skip) { int ssize; FCEU_UpdateInput(); - if (geniestage != 1) FCEU_ApplyPeriodicCheats(); + if (geniestage != 1) { + FCEU_ApplyPeriodicCheats(); + } FCEUPPU_Loop(skip); ssize = FlushEmulateSound(); timestampbase += timestamp; - timestamp = 0; + timestamp = 0; sound_timestamp = 0; - *pXBuf = skip ? 0 : XBuf; - *SoundBuf = WaveFinal; + *pXBuf = skip ? 0 : XBuf; + *pXDBuf = skip ? 0 : XDBuf; + + *SoundBuf = WaveFinal; *SoundBufSize = ssize; } - -void ResetNES(void) -{ - if (!GameInfo) - return; +void ResetNES(void) { + if (!GameInfo) { + return; + } GameInterface(GI_RESETM2); FCEUSND_Reset(); FCEUPPU_Reset(); X6502_Reset(); } -int ram_init_seed = 0; -int option_ramstate = 0; +static int ram_init_seed = 0; -uint64 splitmix64(uint32 input) { +FCEU_MAYBE_UNUSED +static uint64 splitmix64(uint32 input) { uint64 z = (input + 0x9e3779b97f4a7c15); - z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; - z = (z ^ (z >> 27)) * 0x94d049bb133111eb; + z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; + z = (z ^ (z >> 27)) * 0x94d049bb133111eb; return z ^ (z >> 31); } @@ -367,72 +375,69 @@ static INLINE uint64 xoroshiro128plus_rotl(const uint64 x, int k) { return (x << k) | (x >> (64 - k)); } -uint64 xoroshiro128plus_s[2]; -void xoroshiro128plus_seed(uint32 input) -{ -/* http://xoroshiro.di.unimi.it/splitmix64.c */ - uint64 x = input; +static uint64 xoroshiro128plus_s[2]; +static void xoroshiro128plus_seed(uint32 input) { + /* http://xoroshiro.di.unimi.it/splitmix64.c */ + uint64 x, z; - uint64 z = (x += 0x9e3779b97f4a7c15); + x = input; + z = (x += 0x9e3779b97f4a7c15); z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; z = (z ^ (z >> 27)) * 0x94d049bb133111eb; + xoroshiro128plus_s[0] = z ^ (z >> 31); - + z = (x += 0x9e3779b97f4a7c15); z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; z = (z ^ (z >> 27)) * 0x94d049bb133111eb; + xoroshiro128plus_s[1] = z ^ (z >> 31); } /* http://vigna.di.unimi.it/xorshift/xoroshiro128plus.c */ -uint64 xoroshiro128plus_next() { - const uint64 s0 = xoroshiro128plus_s[0]; - uint64 s1 = xoroshiro128plus_s[1]; +static uint64 xoroshiro128plus_next(void) { + const uint64 s0 = xoroshiro128plus_s[0]; + uint64 s1 = xoroshiro128plus_s[1]; const uint64 result = s0 + s1; s1 ^= s0; xoroshiro128plus_s[0] = xoroshiro128plus_rotl(s0, 55) ^ s1 ^ (s1 << 14); /* a, b */ - xoroshiro128plus_s[1] = xoroshiro128plus_rotl(s1, 36); /* c */ + xoroshiro128plus_s[1] = xoroshiro128plus_rotl(s1, 36); /* c */ return result; } -void FCEU_MemoryRand(uint8 *ptr, uint32 size) -{ +void FCEU_MemoryRand(uint8 *ptr, uint32 size) { int x = 0; - while (size) { -#if 0 - *ptr = (x & 4) ? 0xFF : 0x00; /* Huang Di DEBUG MODE enabled by default */ - /* Cybernoid NO MUSIC by default */ - *ptr = (x & 4) ? 0x7F : 0x00; /* Huang Di DEBUG MODE enabled by default */ - /* Minna no Taabou no Nakayoshi Daisakusen DOESN'T BOOT */ - /* Cybernoid NO MUSIC by default */ - *ptr = (x & 1) ? 0x55 : 0xAA; /* F-15 Sity War HISCORE is screwed... */ - /* 1942 SCORE/HISCORE is screwed... */ -#endif - uint8 v = 0; - switch (option_ramstate) - { - case 0: v = 0xff; break; - case 1: v = 0x00; break; - case 2: v = (uint8)(xoroshiro128plus_next()); break; + + if (!ptr || !size) { + return; + } + + switch (FSettings.RamInitState) { + case 0: + for (x = 0; x < size; x++) { + ptr[x] = 0xFF; + } + break; + case 1: + for (x = 0; x < size; x++) { + ptr[x] = 0x00; + } + break; + case 2: + for (x = 0; x < size; x++) { + ptr[x] = (uint8)(xoroshiro128plus_next() & 0xFF); } - *ptr = v; - x++; - size--; - ptr++; + break; } } -void hand(X6502 *X, int type, uint32 A) -{ -} +void PowerNES(void) { + if (!GameInfo) { + return; + } -void PowerNES(void) -{ - if (!GameInfo) - return; - /* reseed random, unless we're in a movie */ ram_init_seed = rand() ^ (uint32)xoroshiro128plus_next(); /* always reseed the PRNG with the current seed, for deterministic results (for that seed) */ @@ -443,7 +448,7 @@ void PowerNES(void) FCEU_GeniePower(); - FCEU_MemoryRand(RAM, 0x800); + FCEU_MemoryRand(RAM, RAM_SIZE); SetReadHandler(0x0000, 0xFFFF, ANull); SetWriteHandler(0x0000, 0xFFFF, BNull); @@ -451,57 +456,72 @@ void PowerNES(void) SetReadHandler(0, 0x7FF, ARAML); SetWriteHandler(0, 0x7FF, BRAML); - SetReadHandler(0x800, 0x1FFF, ARAMH); /* Part of a little */ - SetWriteHandler(0x800, 0x1FFF, BRAMH); /* hack for a small speed boost. */ + SetReadHandler(0x800, 0x1FFF, ARAMH); /* Part of a little */ + SetWriteHandler(0x800, 0x1FFF, BRAMH); /* hack for a small speed boost. */ InitializeInput(); FCEUSND_Power(); FCEUPPU_Power(); /* Have the external game hardware "powered" after the internal NES stuff. - Needed for the NSF code and VS System code. + Needed for the NSF code and VS System code. */ GameInterface(GI_POWER); - if (GameInfo->type == GIT_VSUNI) + if (GameInfo->type == GIT_VSUNI) { FCEU_VSUniPower(); + } timestampbase = 0; X6502_Power(); FCEU_PowerCheats(); } -void FCEU_ResetVidSys(void) -{ +void FCEU_ResetVidSys(void) { int w; - if (GameInfo->vidsys == GIV_NTSC) + if (GameInfo->vidsys == GIV_NTSC) { w = 0; - else if (GameInfo->vidsys == GIV_PAL) - { - w = 1; - dendy = 0; - } - else + } else if (GameInfo->vidsys == GIV_PAL) { + w = 1; + isDendy = FALSE; + } else { w = FSettings.PAL; + } - PAL = w ? 1 : 0; + isPAL = w ? TRUE : FALSE; - if (PAL) - dendy = 0; + if (isPAL) { + isDendy = FALSE; + } - ppu.normal_scanlines = dendy ? 290 : 240; - ppu.totalscanlines = ppu.normal_scanlines; - if (ppu.overclock_enabled) - ppu.totalscanlines += ppu.extrascanlines; + ppu.normal_scanlines = isDendy ? 290 : 240; + ppu.totalscanlines = ppu.normal_scanlines; + if (FSettings.PPUOverclockEnabled && ppu.overclock.postrender_scanlines) { + ppu.totalscanlines += ppu.overclock.postrender_scanlines; + } - FCEUPPU_SetVideoSystem(w || dendy); + FCEUPPU_SetVideoSystem(w || isDendy); SetSoundVariables(); } FCEUS FSettings; -void FCEU_printf(char *format, ...) -{ +void FCEU_DispMessage(enum retro_log_level level, unsigned duration, const char *format, ...) { + static char msg[512] = { 0 }; + va_list ap; + + if (!format || (*format == '\0')) { + return; + } + + va_start(ap, format); + vsprintf(msg, format, ap); + va_end(ap); + + FCEUD_DispMessage(level, duration, msg); +} + +void FCEU_printf(char *format, ...) { char temp[2048]; va_list ap; @@ -513,8 +533,19 @@ void FCEU_printf(char *format, ...) va_end(ap); } -void FCEU_PrintError(char *format, ...) -{ +void FCEU_PrintDebug(char *format, ...) { + char temp[2048]; + + va_list ap; + + va_start(ap, format); + vsprintf(temp, format, ap); + FCEUD_PrintDebug(temp); + + va_end(ap); +} + +void FCEU_PrintError(char *format, ...) { char temp[2048]; va_list ap; @@ -526,53 +557,48 @@ void FCEU_PrintError(char *format, ...) va_end(ap); } -void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall) -{ +void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall) { FSettings.UsrFirstSLine[0] = ntscf; - FSettings.UsrLastSLine[0] = ntscl; + FSettings.UsrLastSLine[0] = ntscl; FSettings.UsrFirstSLine[1] = palf; - FSettings.UsrLastSLine[1] = pall; - if (PAL || dendy) - { + FSettings.UsrLastSLine[1] = pall; + if (isPAL || isDendy) { FSettings.FirstSLine = FSettings.UsrFirstSLine[1]; - FSettings.LastSLine = FSettings.UsrLastSLine[1]; - } - else - { + FSettings.LastSLine = FSettings.UsrLastSLine[1]; + } else { FSettings.FirstSLine = FSettings.UsrFirstSLine[0]; - FSettings.LastSLine = FSettings.UsrLastSLine[0]; + FSettings.LastSLine = FSettings.UsrLastSLine[0]; } } -void FCEUI_SetVidSystem(int a) -{ - FSettings.PAL = a ? 1 : 0; +void FCEUI_SetVidSystem(int a) { + FSettings.PAL = a ? TRUE : FALSE; - if (!GameInfo) - return; + if (!GameInfo) { + return; + } - FCEU_ResetVidSys(); - FCEU_ResetPalette(); + FCEU_ResetVidSys(); + FCEU_ResetPalette(); } -int FCEUI_GetCurrentVidSystem(int *slstart, int *slend) -{ - if (slstart) +int FCEUI_GetCurrentVidSystem(int *slstart, int *slend) { + if (slstart) { *slstart = FSettings.FirstSLine; - if (slend) + } + if (slend) { *slend = FSettings.LastSLine; - return(PAL); + } + return (isPAL); } -void FCEUI_SetGameGenie(int a) -{ - FSettings.GameGenie = a ? 1 : 0; +void FCEUI_SetGameGenie(int a) { + FSettings.GameGenie = a ? TRUE : FALSE; } -int32 FCEUI_GetDesiredFPS(void) -{ - if (PAL || dendy) - return(838977920); /* ~50.007 */ - else - return(1008307711); /* ~60.1 */ +int32 FCEUI_GetDesiredFPS(void) { + if (isPAL || isDendy) { + return (838977920); /* ~50.007 */ + } + return (1008307711); /* ~60.1 */ } diff --git a/src/fceu.h b/src/fceu.h index 7b61f92a4..17930fa47 100644 --- a/src/fceu.h +++ b/src/fceu.h @@ -2,30 +2,27 @@ #define _FCEUH #include "fceu-types.h" +#include "file.h" + +#define RAM_SIZE 0x800 +#define RAM_MASK (RAM_SIZE - 1) + +#define NES_WIDTH 256 +#define NES_HEIGHT 240 extern int fceuindbg; -extern unsigned DMC_7bit; /* Region selection */ -extern unsigned dendy; - -/* Audio mods*/ -extern unsigned swapDuty; /* Swap bits 6 & 7 of $4000/$4004 to mimic bug - * found on some famiclones/Dendy models. - */ void ResetGameLoaded(void); -#define DECLFR(x) uint8 FP_FASTAPASS(1) x(uint32 A) -#define DECLFW(x) void FP_FASTAPASS(2) x(uint32 A, uint8 V) +#define DECLFR(x) uint8 x(uint32 A) +#define DECLFW(x) void x(uint32 A, uint8 V) void FCEU_MemoryRand(uint8 *ptr, uint32 size); -void FASTAPASS(3) SetReadHandler(int32 start, int32 end, readfunc func); -void FASTAPASS(3) SetWriteHandler(int32 start, int32 end, writefunc func); -writefunc FASTAPASS(1) GetWriteHandler(int32 a); -readfunc FASTAPASS(1) GetReadHandler(int32 a); - -int AllocGenieRW(void); -void FlushGenieRW(void); +void SetReadHandler(int32 start, int32 end, readfunc func); +void SetWriteHandler(int32 start, int32 end, writefunc func); +writefunc GetWriteHandler(int32 a); +readfunc GetReadHandler(int32 a); void FCEU_ResetVidSys(void); @@ -33,11 +30,10 @@ void ResetMapping(void); void ResetNES(void); void PowerNES(void); - extern uint64 timestampbase; extern uint32 MMC5HackVROMMask; extern uint8 *MMC5HackExNTARAMPtr; -extern int MMC5Hack, PEC586Hack; +extern uint8 MMC5Hack; extern uint8 *MMC5HackVROMPTR; extern uint8 MMC5HackCHRMode; extern uint8 MMC5HackSPMode; @@ -45,7 +41,13 @@ extern uint8 MMC50x5130; extern uint8 MMC5HackSPScroll; extern uint8 MMC5HackSPPage; -extern uint8 RAM[0x800]; +extern uint8 PEC586Hack; + +extern uint8 QTAIHack; +extern uint8 qtramreg; +extern uint8 QTRAM[0x800]; + +extern uint8 *RAM; extern readfunc ARead[0x10000]; extern writefunc BWrite[0x10000]; @@ -53,24 +55,23 @@ extern writefunc BWrite[0x10000]; extern void (*GameInterface)(int h); extern void (*GameStateRestore)(int version); -#define GI_RESETM2 1 -#define GI_POWER 2 -#define GI_CLOSE 3 +#define GI_RESETM2 1 +#define GI_POWER 2 +#define GI_CLOSE 3 #include "git.h" extern FCEUGI *GameInfo; -extern uint8 PAL; +extern uint8 isPAL; +extern uint8 isDendy; #include "driver.h" typedef struct { int PAL; - int SoundVolume; - int TriangleVolume; - int SquareVolume[2]; - int NoiseVolume; - int PCMVolume; + + int volume[12]; /* master, nes apu and expansion audio */ + int GameGenie; /* Current first and last rendered scanlines. */ @@ -82,15 +83,24 @@ typedef struct { */ int UsrFirstSLine[2]; int UsrLastSLine[2]; - uint32 SndRate; + + int SndRate; int soundq; int lowpass; + + int SwapDutyCycles; + int RamInitState; + int ShowCrosshair; + int ReplaceP2StartWithMicrophone; + int PPUOverclockEnabled; + int SkipDMC7BitOverclock; } FCEUS; extern FCEUS FSettings; -void FCEU_PrintError(char *format, ...); -void FCEU_printf(char *format, ...); +void FCEU_PrintError(char *format, ...); /* warning level messages */ +void FCEU_PrintDebug(char *format, ...); /* debug level messages */ +void FCEU_printf(char *format, ...); /* normal messages */ void SetNESDeemph(uint8 d, int force); void DrawTextTrans(uint8 *dest, uint32 width, uint8 *textmsg, uint8 fgcolor); @@ -99,17 +109,18 @@ void FCEU_PutImage(void); void FCEU_PutImageDummy(void); #endif -extern uint8 Exit; -extern uint8 pale; -extern uint8 vsdip; - -#define JOY_A 0x01 -#define JOY_B 0x02 -#define JOY_SELECT 0x04 -#define JOY_START 0x08 -#define JOY_UP 0x10 -#define JOY_DOWN 0x20 -#define JOY_LEFT 0x40 -#define JOY_RIGHT 0x80 +#define JOY_A 0x01 +#define JOY_B 0x02 +#define JOY_SELECT 0x04 +#define JOY_START 0x08 +#define JOY_UP 0x10 +#define JOY_DOWN 0x20 +#define JOY_LEFT 0x40 +#define JOY_RIGHT 0x80 + +int UNIFLoad(const char *name, FCEUFILE *fp); +int iNESLoad(const char *name, FCEUFILE *fp); +int FDSLoad(const char *name, FCEUFILE *fp); +int NSFLoad(FCEUFILE *fp); #endif diff --git a/src/fcoeffs.h b/src/fcoeffs.h index c5f419931..69d262f86 100644 --- a/src/fcoeffs.h +++ b/src/fcoeffs.h @@ -3,42 +3,32 @@ #define SQ2NCOEFFS 1024 -static int32 sq2coeffs[SQ2NCOEFFS]; - -static int32 SQ2C44100NTSC[SQ2NCOEFFS / 2] = -{ - #include "fir/c44100ntsc.h" +static int32 SQ2C44100NTSC[SQ2NCOEFFS / 2] = { +#include "fir/c44100ntsc.h" }; -static int32 SQ2C48000NTSC[SQ2NCOEFFS / 2] = -{ - #include "fir/c48000ntsc.h" +static int32 SQ2C48000NTSC[SQ2NCOEFFS / 2] = { +#include "fir/c48000ntsc.h" }; -static int32 SQ2C96000NTSC[SQ2NCOEFFS / 2] = -{ - #include "fir/c96000ntsc.h" +static int32 SQ2C96000NTSC[SQ2NCOEFFS / 2] = { +#include "fir/c96000ntsc.h" }; -static int32 SQ2C44100PAL[SQ2NCOEFFS / 2] = -{ - #include "fir/c44100pal.h" +static int32 SQ2C44100PAL[SQ2NCOEFFS / 2] = { +#include "fir/c44100pal.h" }; -static int32 SQ2C48000PAL[SQ2NCOEFFS / 2] = -{ - #include "fir/c48000pal.h" +static int32 SQ2C48000PAL[SQ2NCOEFFS / 2] = { +#include "fir/c48000pal.h" }; -static int32 SQ2C96000PAL[SQ2NCOEFFS / 2] = -{ - #include "fir/c96000pal.h" +static int32 SQ2C96000PAL[SQ2NCOEFFS / 2] = { +#include "fir/c96000pal.h" }; #define NCOEFFS 484 -static int32 coeffs[NCOEFFS]; - /* 96000hz filter could probably be improved. */ /* diff --git a/src/fds.c b/src/fds.c index 5fa668042..adce3d17c 100644 --- a/src/fds.c +++ b/src/fds.c @@ -29,7 +29,7 @@ #include "x6502.h" #include "fceu.h" #include "fds.h" -#include "fds_apu.h" +#include "fdssound.h" #include "sound.h" #include "general.h" #include "state.h" @@ -44,24 +44,20 @@ * when the virtual motor is on(mmm...virtual motor). */ -static DECLFR(FDSRead4030); -static DECLFR(FDSRead4031); -static DECLFR(FDSRead4032); -static DECLFR(FDSRead4033); - +static DECLFR(FDSRead); static DECLFW(FDSWrite); static void FDSInit(void); static void FDSClose(void); -static void FP_FASTAPASS(1) FDSFix(int a); +static void FDSFix(int a); -static uint8 FDSRegs[6]; static int32 IRQLatch, IRQCount; static uint8 IRQa; +static uint8 IRQr; -static uint8 *FDSROM = NULL; -static uint32 FDSROMSize = 0; +static uint8 *FDSDISK = NULL; /* fds disks raw data */ +static uint32 FDSDISKSize = 0; /* fds disks total data size */ static uint8 *FDSRAM = NULL; static uint32 FDSRAMSize; static uint8 *FDSBIOS = NULL; @@ -74,79 +70,104 @@ static uint8 *diskdatao[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; static uint8 *diskdata[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; static uint32 TotalSides; -static uint8 DiskWritten = 0; /* Set to 1 if disk was written to. */ -static uint8 writeskip; -static int32 DiskPtr; static int32 DiskSeekIRQ; static uint8 SelectDisk, InDisk; -enum FDS_DiskBlockIDs { - DSK_INIT = 0, - DSK_VOLUME, - DSK_FILECNT, - DSK_FILEHDR, - DSK_FILEDATA -}; - -static uint8 mapperFDS_control; /* 4025(w) control register */ +enum FDS_DiskBlockIDs { DSK_INIT = 0, DSK_VOLUME, DSK_FILECNT, DSK_FILEHDR, DSK_FILEDATA }; + +static uint8 DiskRegsEnabled; + +/* +FDS Control ($4025) +7 bit 0 +--------- +IS1B MRTD +|||| |||| +|||| |||+- Drive Motor Control +|||| ||| 0: Stop motor +|||| ||| 1: Turn on motor +|||| ||+-- Transfer Reset +|||| || Set 1 to reset transfer timing to the initial state. +|||| |+--- Read / Write mode +|||| | (0: write; 1: read) +|||| +---- Mirroring (0: vertical; 1: horizontal) +|||+------ CRC control (set during CRC calculation of transfer) +||+------- Always set to '1' +|+-------- Read/Write Start +| Turn on motor. Set to 1 when the drive becomes ready for read/write ++--------- Interrupt Transfer + 0: Transfer without using IRQ + 1: Enable IRQ when the drive becomes ready for +*/ + +static uint8 mapperFDS_control; /* 4025(w) control register */ static uint16 mapperFDS_filesize; /* size of file being read/written */ -static uint8 mapperFDS_block; /* block-id of current block */ +static uint8 mapperFDS_blockID; /* block-id of current block */ static uint16 mapperFDS_blockstart; /* start-address of current block */ static uint16 mapperFDS_blocklen; /* length of current block */ static uint16 mapperFDS_diskaddr; /* current address relative to blockstart */ -static uint8 mapperFDS_diskaccess; /* disk needs to be accessed at least once before writing */ - -#define GET_FDS_DISK() (diskdata[InDisk][mapperFDS_blockstart + mapperFDS_diskaddr]) -#define FDS_DISK_INSERTED (InDisk != 255) +static uint8 mapperFDS_diskaccess; /* disk needs to be accessed at least once before writing */ -#define DC_INC 1 #define BYTES_PER_SIDE 65500 +static uint8 FDSDISK_read(void) { + uint32 offset = mapperFDS_blockstart + mapperFDS_diskaddr; + return diskdata[InDisk][offset]; +} + +static void FDSDISK_write(uint8 V) { + uint32 offset = mapperFDS_blockstart + mapperFDS_diskaddr; + uint8 ret = diskdata[InDisk][offset]; + if (V != ret) { + diskdata[InDisk][offset] = V; + } +} + uint8 *FDSROM_ptr(void) { - return (FDSROM); + return (FDSDISK); } uint32 FDSROM_size(void) { - return (FDSROMSize); + return (FDSDISKSize); } -void FDSGI(int h) { +static void FDSGI(int h) { switch (h) { - case GI_CLOSE: FDSClose(); break; - case GI_POWER: FDSInit(); break; + case GI_CLOSE: + FDSClose(); + break; + case GI_POWER: + FDSInit(); + break; } } static void FDSStateRestore(int version) { uint32 x; - setmirror(((FDSRegs[5] & 8) >> 3) ^ 1); + setmirror(((mapperFDS_control & 8) >> 3) ^ 1); - if (version >= 9810) - for (x = 0; x < TotalSides; x++) { - int b; - for (b = 0; b < 65500; b++) - diskdata[x][b] ^= diskdatao[x][b]; + for (x = 0; x < TotalSides; x++) { + int b; + for (b = 0; b < BYTES_PER_SIDE; b++) { + diskdata[x][b] ^= diskdatao[x][b]; } + } } static void FDSInit(void) { - memset(FDSRegs, 0, sizeof(FDSRegs)); - writeskip = DiskPtr = DiskSeekIRQ = 0; + DiskRegsEnabled = 0; + DiskSeekIRQ = 0; setmirror(1); - setprg8(0xE000, 0); /* BIOS */ - setprg32r(1, 0x6000, 0); /* 32KB RAM */ - setchr8(0); /* 8KB CHR RAM */ + setprg8(0xE000, 0); /* BIOS */ + setprg32r(1, 0x6000, 0); /* 32KB RAM */ + setchr8(0); /* 8KB CHR RAM */ MapIRQHook = FDSFix; GameStateRestore = FDSStateRestore; - SetReadHandler(0x4030, 0x4030, FDSRead4030); - SetReadHandler(0x4031, 0x4031, FDSRead4031); - SetReadHandler(0x4032, 0x4032, FDSRead4032); - SetReadHandler(0x4033, 0x4033, FDSRead4033); - + SetReadHandler(0x4030, 0x4033, FDSRead); SetWriteHandler(0x4020, 0x4025, FDSWrite); SetWriteHandler(0x6000, 0xDFFF, CartBW); @@ -154,54 +175,58 @@ static void FDSInit(void) { IRQCount = IRQLatch = IRQa = 0; - FDSSoundReset(); + FDSSound_Reset(); InDisk = 0; SelectDisk = 0; mapperFDS_control = 0; mapperFDS_filesize = 0; - mapperFDS_block = 0; + mapperFDS_blockID = 0; mapperFDS_blockstart = 0; mapperFDS_blocklen = 0; mapperFDS_diskaddr = 0; mapperFDS_diskaccess = 0; } -void FCEU_FDSInsert(int oride) { - if (InDisk == 255) { - FCEU_DispMessage(RETRO_LOG_INFO, 2000, "Disk %d of %d Side %s Inserted", - 1 + (SelectDisk >> 1), (TotalSides + 1) >> 1, (SelectDisk & 1) ? "B" : "A"); - InDisk = SelectDisk; - } else { - FCEU_DispMessage(RETRO_LOG_INFO, 2000, "Disk %d of %d Side %s Ejected", - 1 + (SelectDisk >> 1), (TotalSides + 1) >> 1, (SelectDisk & 1) ? "B" : "A"); - InDisk = 255; - } +static uint8 isDiskInserted(void) { + return (InDisk != 255); } void FCEU_FDSEject(void) { InDisk = 255; } +void FCEU_FDSInsert(int oride) { + if (!isDiskInserted()) { + FCEU_DispMessage(RETRO_LOG_INFO, 2000, "Disk %d of %d Side %s Inserted", 1 + (SelectDisk >> 1), + (TotalSides + 1) >> 1, (SelectDisk & 1) ? "B" : "A"); + InDisk = SelectDisk; + } else { + FCEU_DispMessage(RETRO_LOG_INFO, 2000, "Disk %d of %d Side %s Ejected", 1 + (SelectDisk >> 1), + (TotalSides + 1) >> 1, (SelectDisk & 1) ? "B" : "A"); + FCEU_FDSEject(); + } +} + void FCEU_FDSSelect(void) { - if (InDisk != 255) { + if (isDiskInserted()) { FCEUD_DispMessage(RETRO_LOG_WARN, 2000, "Eject disk before selecting"); return; } SelectDisk = ((SelectDisk + 1) % TotalSides) & 3; - FCEU_DispMessage(RETRO_LOG_INFO, 2000, "Disk %d of %d Side %s Selected", - 1 + (SelectDisk >> 1), (TotalSides + 1) >> 1, (SelectDisk & 1) ? "B" : "A"); + FCEU_DispMessage(RETRO_LOG_INFO, 2000, "Disk %d of %d Side %s Selected", 1 + (SelectDisk >> 1), + (TotalSides + 1) >> 1, (SelectDisk & 1) ? "B" : "A"); } /* 2018/12/15 - update irq timings */ -static void FP_FASTAPASS(1) FDSFix(int a) { - if (IRQa & 2) { +static void FDSFix(int a) { + if (IRQa) { IRQCount -= a; if (IRQCount <= 0) { X6502_IRQBegin(FCEU_IQEXT); IRQCount = IRQLatch; - if (!(IRQa & 1)) { - IRQa &= ~2; + if (!IRQr) { + IRQa = 0; } } } @@ -209,179 +234,178 @@ static void FP_FASTAPASS(1) FDSFix(int a) { if (DiskSeekIRQ > 0) { DiskSeekIRQ -= a; if (DiskSeekIRQ <= 0) { - if (FDSRegs[5] & 0x80) { + if (mapperFDS_control & 0x80) { X6502_IRQBegin(FCEU_IQEXT2); } } } } -static DECLFR(FDSRead4030) { - uint8 ret = 0; - - /* Cheap hack. */ - if (X.IRQlow & FCEU_IQEXT) ret |= 1; - if (X.IRQlow & FCEU_IQEXT2) ret |= 2; +static DECLFR(FDSRead) { + uint8 ret = cpu.openbus; - #ifdef FCEUDEF_DEBUGGER - if (!fceuindbg) - #endif - { - X6502_IRQEnd(FCEU_IQEXT); - X6502_IRQEnd(FCEU_IQEXT2); + if (!DiskRegsEnabled) { + return ret; } - return ret; -} -static DECLFR(FDSRead4031) { - uint8 ret = 0xff; + switch (A) { + case 0x4030: + ret &= ~0xC3; + /* Cheap hack. */ + if (cpu.IRQlow & FCEU_IQEXT) { + ret |= 1; + } + if (cpu.IRQlow & FCEU_IQEXT2) { + ret |= 2; + } +#ifdef FCEUDEF_DEBUGGER + if (!fceuindbg) +#endif + { + X6502_IRQEnd(FCEU_IQEXT); + X6502_IRQEnd(FCEU_IQEXT2); + } + return ret; - if (FDS_DISK_INSERTED && mapperFDS_control & 0x04) { - mapperFDS_diskaccess = 1; - ret = 0; + case 0x4031: + if (isDiskInserted() && (mapperFDS_control & 0x04)) { + uint8 data = 0xFF; - switch (mapperFDS_block) { - case DSK_FILEHDR: + mapperFDS_diskaccess = 1; if (mapperFDS_diskaddr < mapperFDS_blocklen) { - ret = GET_FDS_DISK(); - switch (mapperFDS_diskaddr) { - case 13: - mapperFDS_filesize = ret; - break; - case 14: - mapperFDS_filesize |= ret << 8; + data = FDSDISK_read(); + switch (mapperFDS_blockID) { + case DSK_FILEHDR: + switch (mapperFDS_diskaddr) { + case 13: + mapperFDS_filesize = data; + break; + case 14: + mapperFDS_filesize |= (data << 8); + break; + } break; } mapperFDS_diskaddr++; } - break; - default: - if (mapperFDS_diskaddr < mapperFDS_blocklen) { - ret = GET_FDS_DISK(); - mapperFDS_diskaddr++; - } - break; + DiskSeekIRQ = 150; + X6502_IRQEnd(FCEU_IQEXT2); + return data; } + return 0xFF; - DiskSeekIRQ = 150; - X6502_IRQEnd(FCEU_IQEXT2); - } - - return ret; -} - -static DECLFR(FDSRead4032) { - uint8 ret; + case 0x4032: + ret &= ~0x07; + if (!isDiskInserted()) { + ret |= 5; + } + if (!isDiskInserted() || !(mapperFDS_control & 0x01) || (mapperFDS_control & 0x02)) { + ret |= 2; + } + return ret; - ret = X.DB & ~7; - if (InDisk == 255) - ret |= 5; + case 0x4033: + return 0x80; /* battery */ + } - if (InDisk == 255 || !(FDSRegs[5] & 1) || (FDSRegs[5] & 2)) - ret |= 2; return ret; } -static DECLFR(FDSRead4033) { - return 0x80; /* battery */ -} - static DECLFW(FDSWrite) { + if (!DiskRegsEnabled && (A >= 0x4024)) { + return; + } + switch (A) { case 0x4020: IRQLatch &= 0xFF00; IRQLatch |= V; break; + case 0x4021: IRQLatch &= 0xFF; IRQLatch |= V << 8; break; + case 0x4022: - IRQa = (V & 0x1); /* irq repeat */ - if (FDSRegs[3] & 0x1) { - IRQa |= (V & 0x2); /* irq enabled */ - } - if (IRQa & 2) { + /* irq repeat */ + IRQr = (V & 0x01) == 0x01; + /* irq enabled */ + IRQa = DiskRegsEnabled ? ((V >> 1) & 0x01) : 0x00; + if (IRQa) { IRQCount = IRQLatch; } else { X6502_IRQEnd(FCEU_IQEXT); } break; + case 0x4023: - if (!(V & 1)) { - IRQa &= ~0x02; + DiskRegsEnabled = V & 0x01; + if (!DiskRegsEnabled) { + IRQa = 0; X6502_IRQEnd(FCEU_IQEXT); X6502_IRQEnd(FCEU_IQEXT2); } break; - case 0x4024: - if (FDS_DISK_INSERTED && ~mapperFDS_control & 0x04) { + case 0x4024: + if (isDiskInserted() && (~mapperFDS_control & 0x04)) { if (mapperFDS_diskaccess == 0) { mapperFDS_diskaccess = 1; - break; - } - - switch (mapperFDS_block) { + } else if (mapperFDS_diskaddr < mapperFDS_blocklen) { + FDSDISK_write(V); + switch (mapperFDS_blockID) { case DSK_FILEHDR: - if (mapperFDS_diskaddr < mapperFDS_blocklen) { - GET_FDS_DISK() = V; - switch (mapperFDS_diskaddr) { - case 13: mapperFDS_filesize = V; break; - case 14: - mapperFDS_filesize |= V << 8; - break; - } - mapperFDS_diskaddr++; - } - break; - default: - if (mapperFDS_diskaddr < mapperFDS_blocklen) { - GET_FDS_DISK() = V; - mapperFDS_diskaddr++; + switch (mapperFDS_diskaddr) { + case 13: + mapperFDS_filesize = V; + break; + case 14: + mapperFDS_filesize |= V << 8; + break; } break; + } + mapperFDS_diskaddr++; } - + DiskSeekIRQ = 150; + X6502_IRQEnd(FCEU_IQEXT2); } break; + case 0x4025: X6502_IRQEnd(FCEU_IQEXT2); - if (FDS_DISK_INSERTED) { - if (V & 0x40 && ~mapperFDS_control & 0x40) { + if (isDiskInserted()) { + if ((V & 0x40) && (~mapperFDS_control & 0x40)) { mapperFDS_diskaccess = 0; - DiskSeekIRQ = 150; - /* blockstart - address of block on disk * diskaddr - address relative to blockstart * _block -> _blockID ? */ mapperFDS_blockstart += mapperFDS_diskaddr; mapperFDS_diskaddr = 0; - - mapperFDS_block++; - if (mapperFDS_block > DSK_FILEDATA) - mapperFDS_block = DSK_FILEHDR; - - switch (mapperFDS_block) { - case DSK_VOLUME: - mapperFDS_blocklen = 0x38; - break; - case DSK_FILECNT: - mapperFDS_blocklen = 0x02; - break; - case DSK_FILEHDR: - mapperFDS_blocklen = 0x10; - break; - case DSK_FILEDATA: /* */ - mapperFDS_blocklen = 0x01 + mapperFDS_filesize; - break; + mapperFDS_blockID++; + if (mapperFDS_blockID > DSK_FILEDATA) { + mapperFDS_blockID = DSK_FILEHDR; + } + switch (mapperFDS_blockID) { + case DSK_VOLUME: + mapperFDS_blocklen = 0x38; + break; + case DSK_FILECNT: + mapperFDS_blocklen = 0x02; + break; + case DSK_FILEHDR: + mapperFDS_blocklen = 0x10; + break; + case DSK_FILEDATA: + mapperFDS_blocklen = 0x01 + mapperFDS_filesize; + break; } } - if (V & 0x02) { /* transfer reset */ - mapperFDS_block = DSK_INIT; + mapperFDS_blockID = DSK_INIT; mapperFDS_blockstart = 0; mapperFDS_blocklen = 0; mapperFDS_diskaddr = 0; @@ -395,7 +419,6 @@ static DECLFW(FDSWrite) { setmirror(((V >> 3) & 1) ^ 1); break; } - FDSRegs[A & 7] = V; } struct codes_t { @@ -540,11 +563,10 @@ static const struct codes_t list[] = { { 0xEC, "Epic/Sony Records" }, { 0xEE, "IGS" }, { 0xF0, "A Wave" }, - { 0 } - }; + { 0 }, +}; -static const char *getManufacturer(uint8 code) -{ +static const char *getManufacturer(uint8 code) { int x = 0; char *ret = "unlicensed"; @@ -554,23 +576,27 @@ static const char *getManufacturer(uint8 code) break; } x++; - } + } return ret; } static void FreeFDSMemory(void) { - if (FDSROM) - free(FDSROM); - FDSROM = NULL; - if (FDSBIOS) + if (FDSDISK) { + free(FDSDISK); + } + FDSDISK = NULL; + if (FDSBIOS) { free(FDSBIOS); + } FDSBIOS = NULL; - if (FDSRAM) + if (FDSRAM) { free(FDSRAM); + } FDSRAM = NULL; - if (CHRRAM) + if (CHRRAM) { free(CHRRAM); + } CHRRAM = NULL; } @@ -582,46 +608,56 @@ static int SubLoad(FCEUFILE *fp) { FCEU_fread(header, 16, 1, fp); if (memcmp(header, "FDS\x1a", 4)) { - if (!(memcmp(header + 1, "*NINTENDO-HVC*", 14))) { + if (!(memcmp(header, "\x1*NINTENDO-HVC*", 15))) { long t; t = FCEU_fgetsize(fp); - if (t < 65500) - t = 65500; - TotalSides = t / 65500; + if (t < BYTES_PER_SIDE) { + t = BYTES_PER_SIDE; + } + TotalSides = t / BYTES_PER_SIDE; FCEU_fseek(fp, 0, SEEK_SET); - } else - return(0); - } else + } else { + return (0); + } + } else { TotalSides = header[4]; + } - if (TotalSides > 8) TotalSides = 8; - if (TotalSides < 1) TotalSides = 1; + if (TotalSides > 8) { + TotalSides = 8; + } + if (TotalSides < 1) { + TotalSides = 1; + } - FDSROMSize = TotalSides * BYTES_PER_SIDE; - FDSROM = (uint8*)FCEU_malloc(FDSROMSize); + FDSDISKSize = TotalSides * BYTES_PER_SIDE; + FDSDISK = (uint8 *)FCEU_malloc(FDSDISKSize); - if (!FDSROM) + if (!FDSDISK) { return (0); + } - for (x = 0; x < TotalSides; x++) - diskdata[x] = &FDSROM[x * BYTES_PER_SIDE]; + for (x = 0; x < TotalSides; x++) { + diskdata[x] = &FDSDISK[x * BYTES_PER_SIDE]; + } md5_starts(&md5); for (x = 0; x < TotalSides; x++) { - FCEU_fread(diskdata[x], 1, 65500, fp); - md5_update(&md5, diskdata[x], 65500); + FCEU_fread(diskdata[x], 1, BYTES_PER_SIDE, fp); + md5_update(&md5, diskdata[x], BYTES_PER_SIDE); } md5_finish(&md5, GameInfo->MD5); - return(1); + return (1); } static void PreSave(void) { uint32 x; for (x = 0; x < TotalSides; x++) { int b; - for (b = 0; b < 65500; b++) + for (b = 0; b < BYTES_PER_SIDE; b++) { diskdata[x][b] ^= diskdatao[x][b]; + } } } @@ -629,8 +665,9 @@ static void PostSave(void) { uint32 x; for (x = 0; x < TotalSides; x++) { int b; - for (b = 0; b < 65500; b++) + for (b = 0; b < BYTES_PER_SIDE; b++) { diskdata[x][b] ^= diskdatao[x][b]; + } } } @@ -644,7 +681,7 @@ int FDSLoad(const char *name, FCEUFILE *fp) { FCEU_PrintError("FDS BIOS ROM image missing!\n"); FCEUD_DispMessage(RETRO_LOG_ERROR, 3000, "FDS BIOS image (disksys.rom) missing"); free(fn); - return 0; + return FALSE; } free(fn); @@ -654,17 +691,18 @@ int FDSLoad(const char *name, FCEUFILE *fp) { ResetCartMapping(); FDSBIOSsize = 8192; - FDSBIOS = (uint8*)FCEU_gmalloc(FDSBIOSsize); + FDSBIOS = (uint8 *)FCEU_gmalloc(FDSBIOSsize); SetupCartPRGMapping(0, FDSBIOS, FDSBIOSsize, 0); if (FCEU_fread(FDSBIOS, 1, FDSBIOSsize, zp) != FDSBIOSsize) { - if (FDSBIOS) + if (FDSBIOS) { free(FDSBIOS); + } FDSBIOS = NULL; FCEU_fclose(zp); FCEU_PrintError("Error reading FDS BIOS ROM image.\n"); FCEUD_DispMessage(RETRO_LOG_ERROR, 3000, "Error reading FDS BIOS image (disksys.rom)"); - return 0; + return FALSE; } FCEU_fclose(zp); @@ -672,65 +710,57 @@ int FDSLoad(const char *name, FCEUFILE *fp) { FCEU_fseek(fp, 0, SEEK_SET); if (!SubLoad(fp)) { - if (FDSBIOS) + if (FDSBIOS) { free(FDSBIOS); + } FDSBIOS = NULL; - return(0); + return FALSE; } for (x = 0; x < TotalSides; x++) { - diskdatao[x] = (uint8*)FCEU_malloc(65500); - memcpy(diskdatao[x], diskdata[x], 65500); + diskdatao[x] = (uint8 *)FCEU_malloc(BYTES_PER_SIDE); + memcpy(diskdatao[x], diskdata[x], BYTES_PER_SIDE); } - - DiskWritten = 1; GameInfo->type = GIT_FDS; GameInterface = FDSGI; SelectDisk = 0; - InDisk = 255; + FCEU_FDSEject(); ResetExState(PreSave, PostSave); - FDSSoundStateAdd(); for (x = 0; x < TotalSides; x++) { char temp[5]; sprintf(temp, "DDT%d", x); - AddExState(diskdata[x], 65500, 0, temp); + AddExState(diskdata[x], BYTES_PER_SIDE, 0, temp); } - AddExState(&FDSRegs[0], 1, 0, "REG1"); - AddExState(&FDSRegs[1], 1, 0, "REG2"); - AddExState(&FDSRegs[2], 1, 0, "REG3"); - AddExState(&FDSRegs[3], 1, 0, "REG4"); - AddExState(&FDSRegs[4], 1, 0, "REG5"); - AddExState(&FDSRegs[5], 1, 0, "REG6"); + AddExState(&DiskRegsEnabled, 1, 0, "DREG"); AddExState(&IRQCount, 4 | FCEUSTATE_RLSB, 1, "IRQC"); AddExState(&IRQLatch, 4 | FCEUSTATE_RLSB, 1, "IQL1"); AddExState(&IRQa, 1, 0, "IRQA"); - AddExState(&writeskip, 1, 0, "WSKI"); - AddExState(&DiskPtr, 4 | FCEUSTATE_RLSB, 1, "DPTR"); AddExState(&DiskSeekIRQ, 4 | FCEUSTATE_RLSB, 1, "DSIR"); AddExState(&SelectDisk, 1, 0, "SELD"); AddExState(&InDisk, 1, 0, "INDI"); - AddExState(&DiskWritten, 1, 0, "DSKW"); AddExState(&mapperFDS_control, 1, 0, "CTRG"); AddExState(&mapperFDS_filesize, 2 | FCEUSTATE_RLSB, 1, "FLSZ"); - AddExState(&mapperFDS_block, 1, 0, "BLCK"); + AddExState(&mapperFDS_blockID, 1, 0, "BLCK"); AddExState(&mapperFDS_blockstart, 2 | FCEUSTATE_RLSB, 1, "BLKS"); AddExState(&mapperFDS_blocklen, 2 | FCEUSTATE_RLSB, 1, "BLKL"); AddExState(&mapperFDS_diskaddr, 2 | FCEUSTATE_RLSB, 1, "DADR"); AddExState(&mapperFDS_diskaccess, 1, 0, "DACC"); + FDSSound_AddStateInfo(); + CHRRAMSize = 8192; - CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSize); + CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSize); SetupCartCHRMapping(0, CHRRAM, CHRRAMSize, 1); AddExState(CHRRAM, CHRRAMSize, 0, "CHRR"); FDSRAMSize = 32768; - FDSRAM = (uint8*)FCEU_gmalloc(FDSRAMSize); + FDSRAM = (uint8 *)FCEU_gmalloc(FDSRAMSize); SetupCartPRGMapping(1, FDSRAM, FDSRAMSize, 1); AddExState(FDSRAM, FDSRAMSize, 0, "FDSR"); @@ -743,19 +773,18 @@ int FDSLoad(const char *name, FCEUFILE *fp) { FCEUI_SetVidSystem(0); - return 1; + return TRUE; } void FDSClose(void) { uint32 x; - if (!DiskWritten) return; - - for (x = 0; x < TotalSides; x++) + for (x = 0; x < TotalSides; x++) { if (diskdatao[x]) { free(diskdatao[x]); diskdatao[x] = 0; } + } FreeFDSMemory(); } diff --git a/src/fds_apu.h b/src/fds_apu.h deleted file mode 100644 index 29e6f9bbd..000000000 --- a/src/fds_apu.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef FDS_APU_H -#define FDS_APU_H - -#include "fceu-types.h" - -void FDSSoundReset(void); -void FDSSoundStateAdd(void); - -/* Used for fds conversion-based mappers to allow access to fds apu registers */ -void FDSSoundPower(void); -uint8 FDSSoundRead(uint32 A); /* $4040-$407F, $4090-$4092 */ -void FDSSoundWrite(uint32 A, uint8 V); /* $4040-$407F, $4080-$408A */ - -#endif /* FDS_APU_H */ \ No newline at end of file diff --git a/src/file.c b/src/file.c index 30a38980b..82ebd0743 100644 --- a/src/file.c +++ b/src/file.c @@ -37,88 +37,92 @@ #include "driver.h" #include "general.h" -static MEMWRAP *MakeMemWrap(RFILE *tz) -{ - MEMWRAP *tmp = NULL; - - if (!(tmp = (MEMWRAP*)FCEU_malloc(sizeof(MEMWRAP)))) - goto doret; - tmp->location = 0; - - filestream_seek(tz, 0, RETRO_VFS_SEEK_POSITION_END); - tmp->size = filestream_tell(tz); - filestream_seek(tz, 0, RETRO_VFS_SEEK_POSITION_START); - - if (!(tmp->data_int = (uint8*)FCEU_malloc(tmp->size))) - { - free(tmp); - tmp = NULL; - goto doret; +static MEMWRAP *MakeMemWrap(RFILE *tz) { + MEMWRAP *tmp = NULL; + + if (!(tmp = (MEMWRAP *)FCEU_malloc(sizeof(MEMWRAP)))) { + goto doret; } + tmp->location = 0; + + filestream_seek(tz, 0, RETRO_VFS_SEEK_POSITION_END); + tmp->size = filestream_tell(tz); + filestream_seek(tz, 0, RETRO_VFS_SEEK_POSITION_START); - filestream_read(tz, tmp->data_int, tmp->size); - tmp->data = tmp->data_int; + if (!(tmp->data_int = (uint8 *)FCEU_malloc(tmp->size))) { + free(tmp); + tmp = NULL; + goto doret; + } + + filestream_read(tz, tmp->data_int, tmp->size); + tmp->data = tmp->data_int; doret: - return tmp; + return tmp; } -static MEMWRAP *MakeMemWrapBuffer(const uint8 *buffer, size_t bufsize) -{ - MEMWRAP *tmp = (MEMWRAP*)FCEU_malloc(sizeof(MEMWRAP)); +static MEMWRAP *MakeMemWrapBuffer(const uint8 *buffer, size_t bufsize) { + MEMWRAP *tmp = (MEMWRAP *)FCEU_malloc(sizeof(MEMWRAP)); - if (!tmp) - return NULL; + if (!tmp) { + return NULL; + } - tmp->location = 0; - tmp->size = bufsize; - tmp->data_int = NULL; - tmp->data = buffer; + tmp->location = 0; + tmp->size = bufsize; + tmp->data_int = NULL; + tmp->data = buffer; - return tmp; + return tmp; } -FCEUFILE * FCEU_fopen(const char *path, const uint8 *buffer, size_t bufsize) -{ - FCEUFILE *fceufp = (FCEUFILE*)malloc(sizeof(FCEUFILE)); - - if (buffer) - fceufp->fp = MakeMemWrapBuffer(buffer, bufsize); - else - { - RFILE *t = NULL; +FCEUFILE *FCEU_fopen(const char *path, const uint8 *buffer, size_t bufsize) { + FCEUFILE *fceufp = (FCEUFILE *)malloc(sizeof(FCEUFILE)); + RFILE *t = NULL; - if (!string_is_empty(path) && path_is_valid(path)) - t = filestream_open(path, - RETRO_VFS_FILE_ACCESS_READ, - RETRO_VFS_FILE_ACCESS_HINT_NONE); + if (!fceufp) { + return NULL; + } - if (!t) - { + if (buffer) { + fceufp->fp = MakeMemWrapBuffer(buffer, bufsize); + if (!fceufp->fp) { free(fceufp); return NULL; } + return fceufp; + } + + if (!string_is_empty(path) && path_is_valid(path)) { + t = filestream_open(path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE); + } - fceufp->fp = MakeMemWrap(t); - filestream_close(t); + if (!t) { + free(fceufp); + return NULL; } + + fceufp->fp = MakeMemWrap(t); + filestream_close(t); + return fceufp; } -int FCEU_fclose(FCEUFILE *fp) -{ - if (!fp) - return 0; +int FCEU_fclose(FCEUFILE *fp) { + if (!fp) { + return 0; + } - if (fp->fp) - { - if (fp->fp->data_int) - free(fp->fp->data_int); - fp->fp->data_int = NULL; + if (fp->fp) { + if (fp->fp->data_int) { + free(fp->fp->data_int); + } + fp->fp->data_int = NULL; - free(fp->fp); - } - fp->fp = NULL; + free(fp->fp); + } + fp->fp = NULL; free(fp); fp = NULL; @@ -126,78 +130,64 @@ int FCEU_fclose(FCEUFILE *fp) return 1; } -uint64 FCEU_fread(void *ptr, size_t element_size, size_t nmemb, FCEUFILE *fp) -{ - uint32_t total = nmemb * element_size; +uint64 FCEU_fread(void *ptr, size_t element_size, size_t nmemb, FCEUFILE *fp) { + uint32_t total = nmemb * element_size; - if (fp->fp->location >= fp->fp->size) - return 0; - - if((fp->fp->location + total) > fp->fp->size) - { - int64_t ak = fp->fp->size - fp->fp->location; - - memcpy((uint8_t*)ptr, fp->fp->data + fp->fp->location, ak); - - fp->fp->location = fp->fp->size; - - return (ak / element_size); + if (fp->fp->location >= fp->fp->size) { + return 0; } - memcpy((uint8_t*)ptr, fp->fp->data + fp->fp->location, total); + if ((fp->fp->location + total) > fp->fp->size) { + int64_t ak = fp->fp->size - fp->fp->location; - fp->fp->location += total; + memcpy((uint8_t *)ptr, fp->fp->data + fp->fp->location, ak); + fp->fp->location = fp->fp->size; + return (ak / element_size); + } - return nmemb; + memcpy((uint8_t *)ptr, fp->fp->data + fp->fp->location, total); + fp->fp->location += total; + return nmemb; } -int FCEU_fseek(FCEUFILE *fp, long offset, int whence) -{ - switch (whence) - { - case SEEK_SET: - if (offset >= fp->fp->size) - return -1; - - fp->fp->location = offset; - break; - case SEEK_CUR: - if ((offset + fp->fp->location) > fp->fp->size) - return -1; - - fp->fp->location += offset; - break; - } - - return 0; +int FCEU_fseek(FCEUFILE *fp, long offset, int whence) { + switch (whence) { + case SEEK_SET: + if (offset >= fp->fp->size) { + return -1; + } + fp->fp->location = offset; + break; + case SEEK_CUR: + if ((offset + fp->fp->location) > fp->fp->size) { + return -1; + } + fp->fp->location += offset; + break; + } + return 0; } -int FCEU_read32le(uint32 *Bufo, FCEUFILE *fp) -{ - if ((fp->fp->location + 4) > fp->fp->size) - return 0; - - *Bufo = FCEU_de32lsb(fp->fp->data + fp->fp->location); - - fp->fp->location += 4; - - return 1; +int FCEU_read32le(uint32 *Bufo, FCEUFILE *fp) { + if ((fp->fp->location + 4) > fp->fp->size) { + return 0; + } + *Bufo = FCEU_de32lsb(fp->fp->data + fp->fp->location); + fp->fp->location += 4; + return 1; } -int FCEU_fgetc(FCEUFILE *fp) -{ - if (fp->fp->location < fp->fp->size) - return fp->fp->data[fp->fp->location++]; - - return EOF; +int FCEU_fgetc(FCEUFILE *fp) { + if (fp->fp->location < fp->fp->size) { + return fp->fp->data[fp->fp->location++]; + } + return EOF; } -uint64 FCEU_ftell(FCEUFILE *fp) -{ - return fp->fp->location; +uint64 FCEU_ftell(FCEUFILE *fp) { + return fp->fp->location; } -uint64 FCEU_fgetsize(FCEUFILE *fp) -{ - return fp->fp->size; +uint64 FCEU_fgetsize(FCEUFILE *fp) { + return fp->fp->size; } diff --git a/src/file.h b/src/file.h index 09167dd2f..317337809 100644 --- a/src/file.h +++ b/src/file.h @@ -1,24 +1,26 @@ #ifndef _FCEU_FILE_H #define _FCEU_FILE_H +#include + typedef struct { - uint8 *data_int; - const uint8 *data; - uint32 size; - uint32 location; + uint8 *data_int; + const uint8 *data; + uint32 size; + uint32 location; } MEMWRAP; typedef struct { - MEMWRAP *fp; + MEMWRAP *fp; } FCEUFILE; FCEUFILE *FCEU_fopen(const char *path, const uint8 *buffer, size_t bufsize); -int FCEU_fclose(FCEUFILE*); -uint64 FCEU_fread(void *ptr, size_t size, size_t nmemb, FCEUFILE*); -int FCEU_fseek(FCEUFILE*, long offset, int whence); -uint64 FCEU_ftell(FCEUFILE*); -int FCEU_read32le(uint32 *Bufo, FCEUFILE*); -int FCEU_fgetc(FCEUFILE*); -uint64 FCEU_fgetsize(FCEUFILE*); +int FCEU_fclose(FCEUFILE *); +uint64 FCEU_fread(void *ptr, size_t size, size_t nmemb, FCEUFILE *); +int FCEU_fseek(FCEUFILE *, long offset, int whence); +uint64 FCEU_ftell(FCEUFILE *); +int FCEU_read32le(uint32 *Bufo, FCEUFILE *); +int FCEU_fgetc(FCEUFILE *); +uint64 FCEU_fgetsize(FCEUFILE *); #endif diff --git a/src/filter.c b/src/filter.c index fcc752e8d..4af192ca9 100644 --- a/src/filter.c +++ b/src/filter.c @@ -8,11 +8,14 @@ #include "fcoeffs.h" +static int32 sq2coeffs[SQ2NCOEFFS]; +static int32 coeffs[NCOEFFS]; + static uint32 mrindex; static uint32 mrratio; void SexyFilter2(int32 *in, int32 count) { - #ifdef moo +#ifdef moo static int64 acc = 0; double x, p; int64 c; @@ -21,13 +24,11 @@ void SexyFilter2(int32 *in, int32 count) { p = ((double)2 - cos(x)) - sqrt(pow((double)2 - cos(x), 2) - 1); c = p * 0x100000; - #endif +#endif static int64 acc = 0; while (count--) { - int64 dropcurrent; - dropcurrent = ((*in << 16) - acc) >> 3; - + int64 dropcurrent = ((*in << 16) - acc) >> (FSettings.lowpass & 0x03); acc += dropcurrent; *in = acc >> 16; in++; @@ -46,24 +47,29 @@ void SexyFilter(int32 *in, int32 *out, int32 count) { mul1 = (94 << 16) / FSettings.SndRate; mul2 = (24 << 16) / FSettings.SndRate; - vmul = (FSettings.SoundVolume << 16) * 3 / 4 / 100; + vmul = (FSettings.volume[SND_MASTER] << 16) * 3 / 4 / 100; - if (FSettings.soundq) + if (FSettings.soundq) { vmul /= 4; - else - vmul *= 2; /* TODO: Increase volume in low quality sound rendering code itself */ + } else { + vmul *= 2; /* TODO: Increase volume in low quality sound rendering code itself */ + } while (count) { - int64 ino = (int64) * in * vmul; + int64 ino = (int64)*in * vmul; + int32 t; + sexyfilter_acc1 += ((ino - sexyfilter_acc1) * mul1) >> 16; sexyfilter_acc2 += ((ino - sexyfilter_acc1 - sexyfilter_acc2) * mul2) >> 16; *in = 0; - { - int32 t = (sexyfilter_acc1 - ino + sexyfilter_acc2) >> 16; - if (t > 32767) t = 32767; - if (t < -32768) t = -32768; - *out = t; + t = (sexyfilter_acc1 - ino + sexyfilter_acc2) >> 16; + if (t > 32767) { + t = 32767; } + if (t < -32768) { + t = -32768; + } + *out = t; in++; out++; count--; @@ -72,14 +78,14 @@ void SexyFilter(int32 *in, int32 *out, int32 count) { /* Returns number of samples written to out. */ /* leftover is set to the number of samples that need to be copied - from the end of in to the beginning of in. + from the end of in to the beginning of in. */ /* static uint32 mva=1000; */ /* This filtering code assumes that almost all input values stay below 32767. - Do not adjust the volume in the wlookup tables and the expansion sound - code to be higher, or you *might* overflow the FIR code. + Do not adjust the volume in the wlookup tables and the expansion sound + code to be higher, or you *might* overflow the FIR code. */ int32 NeoFilterSound(int32 *in, int32 *out, uint32 inlen, int32 *leftover) { @@ -94,7 +100,7 @@ int32 NeoFilterSound(int32 *in, int32 *out, uint32 inlen, int32 *leftover) { uint32 c; int32 *S, *D; - for (c = SQ2NCOEFFS, S = &in[(x >> 16) - SQ2NCOEFFS], D = sq2coeffs; c; c--, D++) { + for (c = SQ2NCOEFFS, S = &in [(x >> 16) - SQ2NCOEFFS], D = sq2coeffs; c; c--, D++) { acc += (S[c] * *D) >> 6; acc2 += (S[1 + c] * *D) >> 6; } @@ -110,7 +116,7 @@ int32 NeoFilterSound(int32 *in, int32 *out, uint32 inlen, int32 *leftover) { uint32 c; int32 *S, *D; - for (c = NCOEFFS, S = &in[(x >> 16) - NCOEFFS], D = coeffs; c; c--, D++) { + for (c = NCOEFFS, S = &in [(x >> 16) - NCOEFFS], D = coeffs; c; c--, D++) { acc += (S[c] * *D) >> 6; acc2 += (S[1 + c] * *D) >> 6; } @@ -132,42 +138,49 @@ int32 NeoFilterSound(int32 *in, int32 *out, uint32 inlen, int32 *leftover) { *leftover = NCOEFFS + 1; } - if (GameExpSound.NeoFill) - GameExpSound.NeoFill(outsave, count); + for (x = 0; x < GAMEEXPSOUND_COUNT; x++) { + if (GameExpSound[x].NeoFill) { + GameExpSound[x].NeoFill(outsave, count); + } + } SexyFilter(outsave, outsave, count); - if (FSettings.lowpass) + if (FSettings.lowpass) { SexyFilter2(outsave, count); - return(count); + } + return (count); } void MakeFilters(int32 rate) { - int32 *tabs[6] = { C44100NTSC, C44100PAL, C48000NTSC, C48000PAL, C96000NTSC, - C96000PAL }; - int32 *sq2tabs[6] = { SQ2C44100NTSC, SQ2C44100PAL, SQ2C48000NTSC, SQ2C48000PAL, - SQ2C96000NTSC, SQ2C96000PAL }; + int32 *tabs[6] = { C44100NTSC, C44100PAL, C48000NTSC, C48000PAL, C96000NTSC, C96000PAL }; + int32 *sq2tabs[6] = { SQ2C44100NTSC, SQ2C44100PAL, SQ2C48000NTSC, SQ2C48000PAL, SQ2C96000NTSC, SQ2C96000PAL }; int32 *tmp; int32 x; uint32 nco; - if (FSettings.soundq == 2) + if (FSettings.soundq == 2) { nco = SQ2NCOEFFS; - else + } else { nco = NCOEFFS; + } mrindex = (nco + 1) << 16; - mrratio = (PAL ? (int64)(PAL_CPU * 65536) : (int64)(NTSC_CPU * 65536)) / rate; + mrratio = (isPAL ? (int64)(PAL_CPU * 65536) : (int64)(NTSC_CPU * 65536)) / rate; - if (FSettings.soundq == 2) - tmp = sq2tabs[(PAL ? 1 : 0) | (rate == 48000 ? 2 : 0) | (rate == 96000 ? 4 : 0)]; - else - tmp = tabs[(PAL ? 1 : 0) | (rate == 48000 ? 2 : 0) | (rate == 96000 ? 4 : 0)]; + if (FSettings.soundq == 2) { + tmp = sq2tabs[(isPAL ? 1 : 0) | (rate == 48000 ? 2 : 0) | (rate == 96000 ? 4 : 0)]; + } else { + tmp = tabs[(isPAL ? 1 : 0) | (rate == 48000 ? 2 : 0) | (rate == 96000 ? 4 : 0)]; + } - if (FSettings.soundq == 2) - for (x = 0; x < (SQ2NCOEFFS >> 1); x++) + if (FSettings.soundq == 2) { + for (x = 0; x < (SQ2NCOEFFS >> 1); x++) { sq2coeffs[x] = sq2coeffs[SQ2NCOEFFS - 1 - x] = tmp[x]; - else - for (x = 0; x < (NCOEFFS >> 1); x++) + } + } else { + for (x = 0; x < (NCOEFFS >> 1); x++) { coeffs[x] = coeffs[NCOEFFS - 1 - x] = tmp[x]; + } + } } diff --git a/src/gamegenie.c b/src/gamegenie.c new file mode 100644 index 000000000..f559bbd34 --- /dev/null +++ b/src/gamegenie.c @@ -0,0 +1,298 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "fceu-types.h" +#include "fceu.h" +#include "cart.h" +#include "fceu-memory.h" +#include "general.h" +#include "gamegenie.h" + +int RWWrap = 0; +int geniestage = 0; +readfunc *AReadG = NULL; +writefunc *BWriteG = NULL; + +static uint8 *VPageG[8]; +static int modcon; +static uint8 genieval[3]; +static uint8 geniech[3]; +static uint32 genieaddr[3]; +static uint8 *GENIEROM = 0; +static readfunc GenieBackup[3]; + +extern uint8 **VPageR; + +static void FlushGenieRW(void); + +/* Called when a game(file) is opened successfully. */ +void FCEU_OpenGenie(void) { + RFILE *fp = NULL; + int x; + + if (!GENIEROM) { + char *fn; + + if (!(GENIEROM = (uint8 *)FCEU_malloc(4096 + 1024))) { + return; + } + + fn = FCEU_MakeFName(FCEUMKF_GGROM, 0, 0); + + if (!string_is_empty(fn) && path_is_valid(fn)) { + fp = filestream_open(fn, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE); + } + + free(fn); + fn = NULL; + + if (!fp) { + FCEU_PrintError("Error opening Game Genie ROM image!\n"); + FCEUD_DispMessage(RETRO_LOG_WARN, 3000, "Game Genie ROM image (gamegenie.nes) missing"); + free(GENIEROM); + GENIEROM = 0; + return; + } + if (filestream_read(fp, GENIEROM, 16) != 16) { +grerr: + FCEU_PrintError("Error reading from Game Genie ROM image!\n"); + FCEUD_DispMessage(RETRO_LOG_WARN, 3000, "Failed to read Game Genie ROM image (gamegenie.nes)"); + free(GENIEROM); + GENIEROM = 0; + filestream_close(fp); + return; + } + if (GENIEROM[0] == 0x4E) { /* iNES ROM image */ + if (filestream_read(fp, GENIEROM, 4096) != 4096) { + goto grerr; + } + if (filestream_seek(fp, 16384 - 4096, RETRO_VFS_SEEK_POSITION_CURRENT)) { + goto grerr; + } + if (filestream_read(fp, GENIEROM + 4096, 256) != 256) { + goto grerr; + } + } else { + if (filestream_read(fp, GENIEROM + 16, 4352 - 16) != (4352 - 16)) { + goto grerr; + } + } + filestream_close(fp); + + /* Workaround for the FCE Ultra CHR page size only being 1KB */ + for (x = 0; x < 4; x++) { + memcpy(GENIEROM + 4096 + (x << 8), GENIEROM + 4096, 256); + } + } + + geniestage = 1; +} + +/* Called when a game is closed. */ +void FCEU_CloseGenie(void) { + /* No good reason to free() the Game Genie ROM image data. */ + geniestage = 0; + FlushGenieRW(); + VPageR = VPage; +} + +void FCEU_KillGenie(void) { + if (GENIEROM) { + free(GENIEROM); + GENIEROM = 0; + } +} + +static int AllocGenieRW(void) { + if (!AReadG) { + if (!(AReadG = (readfunc *)FCEU_malloc(0x8000 * sizeof(readfunc)))) { + return 0; + } + } else { + memset(AReadG, 0, 0x8000 * sizeof(readfunc)); + } + + if (!BWriteG) { + if (!(BWriteG = (writefunc *)FCEU_malloc(0x8000 * sizeof(writefunc)))) { + return 0; + } + } else { + memset(BWriteG, 0, 0x8000 * sizeof(writefunc)); + } + + RWWrap = 1; + return 1; +} + +static void FlushGenieRW(void) { + int32 x; + + if (RWWrap) { + for (x = 0; x < 0x8000; x++) { + ARead[x + 0x8000] = AReadG[x]; + BWrite[x + 0x8000] = BWriteG[x]; + } + free(AReadG); + free(BWriteG); + AReadG = NULL; + BWriteG = NULL; + } + RWWrap = 0; +} + +static DECLFR(GenieFix1) { + uint8 r = GenieBackup[0](A); + + if ((modcon >> 1) & 1) { /* No check */ + return genieval[0]; + } + + if (r == geniech[0]) { + return genieval[0]; + } + + return r; +} + +static DECLFR(GenieFix2) { + uint8 r = GenieBackup[1](A); + + if ((modcon >> 2) & 1) { /* No check */ + return genieval[1]; + } + + if (r == geniech[1]) { + return genieval[1]; + } + + return r; +} + +static DECLFR(GenieFix3) { + uint8 r = GenieBackup[2](A); + + if ((modcon >> 3) & 1) { /* No check */ + return genieval[2]; + } + + if (r == geniech[2]) { + return genieval[2]; + } + + return r; +} + +static void FixGenieMap(void) { + int x; + + geniestage = 2; + + for (x = 0; x < 8; x++) { + VPage[x] = VPageG[x]; + } + + VPageR = VPage; + FlushGenieRW(); + for (x = 0; x < 3; x++) { + if ((modcon >> (4 + x)) & 1) { + readfunc tmp[3] = { GenieFix1, GenieFix2, GenieFix3 }; + GenieBackup[x] = GetReadHandler(genieaddr[x]); + SetReadHandler(genieaddr[x], genieaddr[x], tmp[x]); + } + } +} + +static DECLFR(GenieRead) { + return GENIEROM[A & 4095]; +} + +static DECLFW(GenieWrite) { + switch (A) { + case 0x800c: + case 0x8008: + case 0x8004: + genieval[((A - 4) & 0xF) >> 2] = V; + break; + + case 0x800b: + case 0x8007: + case 0x8003: + geniech[((A - 3) & 0xF) >> 2] = V; + break; + + case 0x800a: + case 0x8006: + case 0x8002: + genieaddr[((A - 2) & 0xF) >> 2] &= 0xFF00; + genieaddr[((A - 2) & 0xF) >> 2] |= V; + break; + + case 0x8009: + case 0x8005: + case 0x8001: + genieaddr[((A - 1) & 0xF) >> 2] &= 0xFF; + genieaddr[((A - 1) & 0xF) >> 2] |= (V | 0x80) << 8; + break; + + case 0x8000: + if (!V) { + FixGenieMap(); + } else { + modcon = V ^ 0xFF; + if (V == 0x71) { + modcon = 0; + } + } + break; + } +} + +void FCEU_GeniePower(void) { + uint32 x; + + if (!geniestage) { + return; + } + + geniestage = 1; + for (x = 0; x < 3; x++) { + genieval[x] = 0xFF; + geniech[x] = 0xFF; + genieaddr[x] = 0xFFFF; + } + modcon = 0; + + SetWriteHandler(0x8000, 0xFFFF, GenieWrite); + SetReadHandler(0x8000, 0xFFFF, GenieRead); + + for (x = 0; x < 8; x++) { + VPage[x] = GENIEROM + 4096 - 0x400 * x; + } + + if (AllocGenieRW()) { + VPageR = VPageG; + } else { + geniestage = 2; + } +} diff --git a/src/gamegenie.h b/src/gamegenie.h new file mode 100644 index 000000000..d9fdf541f --- /dev/null +++ b/src/gamegenie.h @@ -0,0 +1,14 @@ +#ifndef _FCEU_GAMEGENIE_H +#define _FCEU_GAMEGENIE_H + +extern int geniestage; +extern readfunc *AReadG; +extern writefunc *BWriteG; +extern int RWWrap; + +void FCEU_OpenGenie(void); +void FCEU_GeniePower(void); +void FCEU_CloseGenie(void); +void FCEU_KillGenie(void); + +#endif /* _FCEU_GAMEGENIE_H */ \ No newline at end of file diff --git a/src/general.c b/src/general.c index bc24fd815..d54125b68 100644 --- a/src/general.c +++ b/src/general.c @@ -42,55 +42,52 @@ #include "md5.h" -static char BaseDirectory[2048] = {0}; +static char BaseDirectory[2048] = { 0 }; -void FCEUI_SetBaseDirectory(const char *dir) -{ +void FCEUI_SetBaseDirectory(const char *dir) { strncpy(BaseDirectory, dir, 2047); BaseDirectory[2047] = 0; } -char *FCEU_MakeFName(int type, int id1, char *cd1) -{ - char tmp[4096 + 512] = {0}; /* +512 for no reason :D */ - char *ret = 0; - - switch (type) - { - case FCEUMKF_GGROM: - fill_pathname_join(tmp, BaseDirectory, - "gamegenie.nes", sizeof(tmp)); - break; - case FCEUMKF_FDSROM: - fill_pathname_join(tmp, BaseDirectory, - "disksys.rom", sizeof(tmp)); - break; - case FCEUMKF_PALETTE: - fill_pathname_join(tmp, BaseDirectory, - "nes.pal", sizeof(tmp)); - break; - default: - break; - } - - FCEU_printf(" FCEU_MakeFName: %s\n", tmp); - - ret = (char*)malloc(strlen(tmp) * sizeof(char) + 1); - strcpy(ret, tmp); - - return(ret); +char *FCEU_MakeFName(int type, int id1, char *cd1) { + char tmp[4096 + 512] = { 0 }; /* +512 for no reason :D */ + char *ret = 0; + + switch (type) { + case FCEUMKF_GGROM: + fill_pathname_join(tmp, BaseDirectory, "gamegenie.nes", sizeof(tmp)); + break; + case FCEUMKF_FDSROM: + fill_pathname_join(tmp, BaseDirectory, "disksys.rom", sizeof(tmp)); + break; + case FCEUMKF_PALETTE: + fill_pathname_join(tmp, BaseDirectory, "nes.pal", sizeof(tmp)); + break; + case FCEUMKF_PALETTE_512: + fill_pathname_join(tmp, BaseDirectory, "nes512.pal", sizeof(tmp)); + break; + default: + break; + } + + FCEU_printf(" FCEU_MakeFName: %s\n", tmp); + + ret = (char *)malloc(strlen(tmp) * sizeof(char) + 1); + strcpy(ret, tmp); + + return (ret); } -uint32 uppow2(uint32 n) -{ - int x; - - for (x = 31; x >= 0; x--) - if (n & (1 << x)) - { - if ((uint32)(1 << x) != n) - return(1 << (x + 1)); - break; - } - return n; +uint32 uppow2(uint32 n) { + int x; + + for (x = 31; x >= 0; x--) { + if (n & (1 << x)) { + if ((uint32)(1 << x) != n) { + return (1 << (x + 1)); + } + break; + } + } + return n; } diff --git a/src/general.h b/src/general.h index f7bbd0c61..405e73f2a 100644 --- a/src/general.h +++ b/src/general.h @@ -9,6 +9,7 @@ enum FILE_TYPES { FCEUMKF_FDSROM = 1, FCEUMKF_PALETTE, + FCEUMKF_PALETTE_512, FCEUMKF_GGROM }; diff --git a/src/git.h b/src/git.h index d14e79218..66eac765b 100644 --- a/src/git.h +++ b/src/git.h @@ -2,30 +2,101 @@ #define __FCEU_GIT /* Mmm...git. Almost as funny as "gimp". */ -#define GIT_CART 0 /* Cart. */ -#define GIT_VSUNI 1 /* VS Unisystem. */ -#define GIT_FDS 2 /* Famicom Disk System. */ -#define GIT_NSF 3 /* NES Sound Format. */ +enum GITYPES { + GIT_CART = 0, /* Cart. */ + GIT_VSUNI = 1, /* VS Unisystem. */ + GIT_FDS = 2, /* Famicom Disk System. */ + GIT_NSF = 3 /* NES Sound Format. */ +}; -#define GIV_NTSC 0 /* NTSC emulation. */ -#define GIV_PAL 1 /* PAL emulation. */ -#define GIV_USER 2 /* What was set by FCEUI_SetVidSys(). */ +enum GIV { + GIV_NTSC = 0, /* NTSC emulation. */ + GIV_PAL = 1, /* PAL emulation. */ + GIV_USER = 2 /* What was set by FCEUI_SetVidSys(). */ +}; + +enum GIPPU { + PPU_USER = 0, + PPU_RP2C04_0001 = 1, + PPU_RP2C04_0002 = 2, + PPU_RP2C04_0003 = 3, + PPU_RP2C04_0004 = 4, + PPU_RC2C03 = 5, /* somewhat similar to RP2C03x */ + PPU_RC2C05_01 = 6, + PPU_RC2C05_02 = 7, + PPU_RC2C05_03 = 8, + PPU_RC2C05_04 = 9, + PPU_RC2C05_05 = 10 +}; + +enum VSTYPES { + VS_TYPE_NORMAL = 0, + VS_TYPE_RBI = 1, /* RBI Baseball protection */ + VS_TYPE_TKO = 2, /* TKO Boxing protection */ + VS_TYPE_XEVIOUS = 3, /* Super Xevious protection */ + VS_TYPE_ICECLIMBER = 4 /* Ice Climber protection (unimplemented) */ +}; + +enum SIS { + SIS_NONE = 0, + SIS_DATACH = 1, + SIS_NWC = 2, + SIS_VSUNISYSTEM = 3, + SIS_NSF = 4 +}; + +enum SINES { + SI_UNSET = -1, + SI_NONE = 0, + SI_GAMEPAD = 1, + SI_ZAPPER = 2, + SI_POWERPADA = 3, + SI_POWERPADB = 4, + SI_ARKANOID = 5, + SI_MOUSE = 6, + SI_LCDCOMP_ZAPPER = 7, + SI_SNES_MOUSE = 8, + SI_SNES_GAMEPAD = 9, + SI_VIRTUALBOY = 10 +}; + +enum SIFC { + SIFC_UNSET = -1, + SIFC_NONE = 0, + SIFC_ARKANOID = 1, + SIFC_SHADOW = 2, + SIFC_4PLAYER = 3, + SIFC_FKB = 4, + SIFC_SUBORKB = 5, + SIFC_PEC586KB = 6, + SIFC_HYPERSHOT = 7, + SIFC_MAHJONG = 8, + SIFC_QUIZKING = 9, + SIFC_FTRAINERA = 10, + SIFC_FTRAINERB = 11, + SIFC_OEKAKIDS = 12, + SIFC_BWORLD = 13, + SIFC_TOPRIDER = 14, + SIFC_FAMINETSYS = 15, + SIFC_HORI4PLAYER = 16, + + SIFC_COUNT = SIFC_HORI4PLAYER +}; typedef struct { - uint8 *name; /* Game name, UTF8 encoding */ - - int type; /* GIT_* */ - int vidsys; /* Current emulated video system; GIV_* */ - int input[2]; /* Desired input for emulated input ports 1 and 2; -1 - for unknown desired input. */ - int inputfc; /* Desired Famicom expansion port device. -1 for unknown - desired input. */ - int cspecial; /* Special cart expansion: DIP switches, barcode - reader, etc. */ + uint8 *name; /* Game name, UTF8 encoding */ + + int type; /* GIT_* */ + int vidsys; /* Current emulated video system; GIV_* */ + int input[2]; /* Desired input for emulated input ports 1 and 2; -1 + for unknown desired input. */ + int inputfc; /* Desired Famicom expansion port device. -1 for unknown + desired input. */ + int cspecial; /* Special cart expansion: DIP switches, barcode + reader, etc. */ 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 */ + int soundrate; /* For Ogg Vorbis expansion sound wacky support. 0 for default. */ + int soundchan; /* Number of sound channels. */ } FCEUGI; #endif diff --git a/src/ines-correct.h b/src/ines-correct.h index fa6083211..c20e79bd1 100644 --- a/src/ines-correct.h +++ b/src/ines-correct.h @@ -1,10 +1,25 @@ #ifndef _FCEU_INES_CORRECT_H #define _FCEU_INES_CORRECT_H - /* ROM images that have the battery-backed bit set in the header that really - don't have battery-backed RAM is not that big of a problem, so I'll - treat this differently by only listing games that should have battery-backed RAM. - */ +#include "fceu-types.h" + +struct CHINF { + uint32 crc32; + int mapper; + int submapper; + int mirror; + int battery; + int prgram; /* ines2 prgram format */ + int chrram; /* ines2 chrram format */ + int region; + int extra; +}; + +/* ROM images that have the battery-backed bit set in the header that really +don't have battery-backed RAM is not that big of a problem, so I'll +treat this differently by only listing games that should have battery-backed RAM. +*/ +static struct CHINF moo[] = { /* CRC32, mapperNum, SubMapper, Mirroring, hasBattery, prgRam, chrRam, region, extra flags */ { 0xb17574f3, 1, DEFAULT, DEFAULT, 1, 0x70, DEFAULT, DEFAULT, NOEXTRA }, /* AD&D Heroes of the Lance */ { 0x5de61639, 1, DEFAULT, DEFAULT, 1, 0x70, 0x07, DEFAULT, NOEXTRA }, /* AD&D Hillsfar */ @@ -21,11 +36,6 @@ { 0xeaf7ed72, 1, DEFAULT, DEFAULT, 1, 0x70, 0x07, DEFAULT, NOEXTRA }, /* Legend of Zelda */ { 0x3fe272fb, 1, DEFAULT, DEFAULT, 1, 0x70, 0x07, DEFAULT, NOEXTRA }, /* Legend of Zelda */ { 0xba322865, 1, DEFAULT, DEFAULT, 1, 0x70, DEFAULT, DEFAULT, NOEXTRA }, /* Zelda 2 */ - { 0x25952141, 4, DEFAULT, DEFAULT, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* AD&D Pool of Radiance */ - { 0x1335cb05, 4, DEFAULT, DEFAULT, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Crystalis */ - { 0x57e220d0, 4, DEFAULT, DEFAULT, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Final Fantasy 3 */ - { 0x889129cb, 4, DEFAULT, DEFAULT, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Startropics */ - { 0xd054ffb0, 4, DEFAULT, DEFAULT, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Startropics 2*/ { 0xb5ff71ab, 19, DEFAULT, DEFAULT, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Battle Fleet */ { 0x0c1792da, 19, DEFAULT, DEFAULT, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Famista '90 */ { 0x47c2020b, 19, DEFAULT, DEFAULT, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Hydlide 3*/ @@ -54,34 +64,34 @@ { 0x330de468, 0, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Obake no Q Tarou - Wanwan Panic (Japan).nes */ { 0xe28f2596, 0, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Pac-Land (J) [b2].nes */ { 0x5112dc21, 0, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Wild Gunman (World) (Rev 1).nes */ - { 0xd8ee7669, 1, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Adventures of Rad Gravity, The (USA).nes */ - { 0x5b837e8d, 1, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Alien Syndrome (Japan).nes */ - { 0x37ba3261, 1, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Back to the Future Part II & III (USA).nes */ - { 0x5b6ca654, 1, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Barbie (USA).nes */ - { 0x61a852ea, 1, DEFAULT, DFAULT8, 1, 0x70, DEFAULT, DEFAULT, NOEXTRA }, /* Battle Stadium - Senbatsu Pro Yakyuu (Japan).nes */ - { 0xf6fa4453, 1, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Bigfoot (U) [b4].nes */ - { 0x391aa1b8, 1, DEFAULT, DFAULT8, 1, 0x70, 0x07, DEFAULT, NOEXTRA }, /* Bloody Warriors - Shan-Go no Gyakushuu (Japan).nes */ - { 0xa5e8d2cd, 1, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* BreakThru (USA).nes */ - { 0x3f56a392, 1, DEFAULT, DFAULT8, 0, DEFAULT, 0x07, DEFAULT, NOEXTRA }, /* Captain ED (Japan).nes */ - { 0x078ced30, 1, DEFAULT, DFAULT8, 1, 0x07, DEFAULT, DEFAULT, NOEXTRA }, /* Choujin - Ultra Baseball (Japan).nes */ - { 0xfe364be5, 1, DEFAULT, DFAULT8, 1, 0x70, 0x07, DEFAULT, NOEXTRA }, /* Deep Dungeon IV - Kuro no Youjutsushi (Japan).nes */ - { 0x57c12280, 1, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Demon Sword (U) [b1].nes */ - { 0xd09b74dc, 1, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Great Tank (Japan).nes */ - { 0xe8baa782, 1, DEFAULT, DFAULT8, 1, 0x70, DEFAULT, DEFAULT, NOEXTRA }, /* Gunhed - Aratanaru Tatakai (Japan).nes */ - { 0x970bd9c2, 1, DEFAULT, DFAULT8, 1, 0x70, 0x07, DEFAULT, NOEXTRA }, /* Hanjuku Eiyuu (J) [b1].nes */ - { 0xcd7a2fd7, 1, DEFAULT, DFAULT8, 1, 0x70, 0x07, DEFAULT, NOEXTRA }, /* Hanjuku Hero (Japan).nes */ - { 0x63469396, 1, DEFAULT, DFAULT8, 1, 0x70, 0x07, DEFAULT, NOEXTRA }, /* Hokuto no Ken 4 - Shichisei Haken Den - Hokuto Shinken no Kanata e (Japan).nes */ - { 0xe94d5181, 1, DEFAULT, DFAULT8, 1, 0x70, 0x07, DEFAULT, NOEXTRA }, /* Future Wars - Mirai Senshi Lios (Japan).nes */ - { 0x7156cb4d, 1, DEFAULT, DFAULT8, 0, 0x70, DEFAULT, DEFAULT, NOEXTRA }, /* Muppet Adventure - Chaos at the Carnival (USA).nes */ - { 0x70f67ab7, 1, DEFAULT, DFAULT8, 1, 0x70, DEFAULT, DEFAULT, NOEXTRA }, /* Musashi no Bouken (Japan).nes */ - { 0x958e4bae, 1, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Orb-3D (USA).nes */ - { 0x291bcd7d, 1, DEFAULT, DFAULT8, 0, DEFAULT, 0x07, DEFAULT, NOEXTRA }, /* Pachio-kun 2 (Japan).nes */ - { 0xa9a4ea4c, 1, DEFAULT, DFAULT8, 1, 0x70, DEFAULT, DEFAULT, NOEXTRA }, /* Satomi Hakkenden (J) [b2].nes */ - { 0xcc3544b0, 1, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Triathron, The (Japan).nes */ - { 0x52ab2d17, 1, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Toukyou Pachi-Slot Adventure (Japan).nes */ + { 0xd8ee7669, 1, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Adventures of Rad Gravity, The (USA).nes */ + { 0x5b837e8d, 1, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Alien Syndrome (Japan).nes */ + { 0x37ba3261, 1, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Back to the Future Part II & III (USA).nes */ + { 0x5b6ca654, 1, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Barbie (USA).nes */ + { 0x61a852ea, 1, DEFAULT, MI_H, 1, 0x70, DEFAULT, DEFAULT, NOEXTRA }, /* Battle Stadium - Senbatsu Pro Yakyuu (Japan).nes */ + { 0xf6fa4453, 1, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Bigfoot (U) [b4].nes */ + { 0x391aa1b8, 1, DEFAULT, MI_H, 1, 0x70, 0x07, DEFAULT, NOEXTRA }, /* Bloody Warriors - Shan-Go no Gyakushuu (Japan).nes */ + { 0xa5e8d2cd, 1, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* BreakThru (USA).nes */ + { 0x3f56a392, 1, DEFAULT, MI_H, 0, DEFAULT, 0x07, DEFAULT, NOEXTRA }, /* Captain ED (Japan).nes */ + { 0x078ced30, 1, DEFAULT, MI_H, 1, 0x07, DEFAULT, DEFAULT, NOEXTRA }, /* Choujin - Ultra Baseball (Japan).nes */ + { 0xfe364be5, 1, DEFAULT, MI_H, 1, 0x70, 0x07, DEFAULT, NOEXTRA }, /* Deep Dungeon IV - Kuro no Youjutsushi (Japan).nes */ + { 0x57c12280, 1, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Demon Sword (U) [b1].nes */ + { 0xd09b74dc, 1, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Great Tank (Japan).nes */ + { 0xe8baa782, 1, DEFAULT, MI_H, 1, 0x70, DEFAULT, DEFAULT, NOEXTRA }, /* Gunhed - Aratanaru Tatakai (Japan).nes */ + { 0x970bd9c2, 1, DEFAULT, MI_H, 1, 0x70, 0x07, DEFAULT, NOEXTRA }, /* Hanjuku Eiyuu (J) [b1].nes */ + { 0xcd7a2fd7, 1, DEFAULT, MI_H, 1, 0x70, 0x07, DEFAULT, NOEXTRA }, /* Hanjuku Hero (Japan).nes */ + { 0x63469396, 1, DEFAULT, MI_H, 1, 0x70, 0x07, DEFAULT, NOEXTRA }, /* Hokuto no Ken 4 - Shichisei Haken Den - Hokuto Shinken no Kanata e (Japan).nes */ + { 0xe94d5181, 1, DEFAULT, MI_H, 1, 0x70, 0x07, DEFAULT, NOEXTRA }, /* Future Wars - Mirai Senshi Lios (Japan).nes */ + { 0x7156cb4d, 1, DEFAULT, MI_H, 0, 0x70, DEFAULT, DEFAULT, NOEXTRA }, /* Muppet Adventure - Chaos at the Carnival (USA).nes */ + { 0x70f67ab7, 1, DEFAULT, MI_H, 1, 0x70, DEFAULT, DEFAULT, NOEXTRA }, /* Musashi no Bouken (Japan).nes */ + { 0x958e4bae, 1, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Orb-3D (USA).nes */ + { 0x291bcd7d, 1, DEFAULT, MI_H, 0, DEFAULT, 0x07, DEFAULT, NOEXTRA }, /* Pachio-kun 2 (Japan).nes */ + { 0xa9a4ea4c, 1, DEFAULT, MI_H, 1, 0x70, DEFAULT, DEFAULT, NOEXTRA }, /* Satomi Hakkenden (J) [b2].nes */ + { 0xcc3544b0, 1, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Triathron, The (Japan).nes */ + { 0x52ab2d17, 1, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Toukyou Pachi-Slot Adventure (Japan).nes */ { 0x934db14a, 1, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* All-Pro Basketball (USA).nes */ { 0xf74dfc91, 1, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Win, Lose or Draw (USA).nes */ - { 0xcfe02ada, 1, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, PAL, NOEXTRA }, /* Darkman (Europe).nes */ + { 0xcfe02ada, 1, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, NES_PAL, NOEXTRA }, /* Darkman (Europe).nes */ { 0x1a71fd06, 1, DEFAULT, MI_H, 0, DEFAULT, 0x07, DEFAULT, NOEXTRA }, /* Kujaku Ou.nes */ /* MMC1 games with more than 8K wram */ @@ -127,7 +137,7 @@ { 0xdbf90772, 3, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Alpha Mission (USA).nes */ { 0xd858033d, 3, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* ASO - Armored Scrum Object (J).nes */ { 0xd858033d, 3, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* ASO - Armored Scrum Object (J).nes */ - { 0x637ba508, 3, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, PAL, NOEXTRA }, /* Adan y Eva (Spain) (Gluk Video) (Unl).nes */ + { 0x637ba508, 3, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, NES_PAL, NOEXTRA }, /* Adan y Eva (Spain) (Gluk Video) (Unl).nes */ { 0x9bde3267, 3, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Adventures of Dino Riki (USA).nes */ { 0xd8eff0df, 3, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Gradius (Japan).nes */ { 0x1d41cc8c, 3, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Gyruss (USA).nes */ @@ -139,24 +149,40 @@ { 0x8dedea07, 3, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Shui Guo Li (Ch) [a1].nes */ { 0x684afccd, 3, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Space Hunter (Japan).nes */ - { 0x97b6cb19, 4, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Aladdin (SuperGame) (Mapper 4) [!].nes */ + { 0x97b6cb19, 4, 4, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Aladdin (SuperGame) (Mapper 4) [!].nes */ { 0xd97c31b0, 206, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Lasalle Ishii no Child's Quest (Japan).nes */ { 0x404b2e8b, 4, DEFAULT, MI_4, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Rad Racer II (USA).nes */ - { 0x15141401, 4, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Asmik-kun Land (Japan).nes */ - { 0x4cccd878, 4, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Kyatto Ninden Teyandee (J) [b1].nes */ - { 0x59280bec, 4, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Jackie Chan (Japan).nes */ - { 0x7474ac92, 4, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Kabuki - Quantum Fighter (USA).nes */ - { 0xf2594374, 4, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Matendouji (Japan).nes */ - { 0x5337f73c, 4, DEFAULT, DFAULT8, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Niji no Silk Road (Japan).nes */ - { 0x9eefb4b4, 4, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Pachi-Slot Adventure 2 - Sorotta-kun no Pachi-Slot Tanteidan (Japan).nes */ - { 0xafe03802, 4, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Pachio-kun 3 (Japan) (Rev A).nes */ + { 0x15141401, 4, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Asmik-kun Land (Japan).nes */ + { 0x4cccd878, 4, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Kyatto Ninden Teyandee (J) [b1].nes */ + { 0x59280bec, 4, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Jackie Chan (Japan).nes */ + { 0x7474ac92, 4, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Kabuki - Quantum Fighter (USA).nes */ + { 0xf2594374, 4, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Matendouji (Japan).nes */ + { 0x5337f73c, 4, DEFAULT, MI_H, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Niji no Silk Road (Japan).nes */ + { 0x9eefb4b4, 4, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Pachi-Slot Adventure 2 - Sorotta-kun no Pachi-Slot Tanteidan (Japan).nes */ + { 0xafe03802, 4, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Pachio-kun 3 (Japan) (Rev A).nes */ { 0x21a653c7, 4, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Super Sky Kid (VS).nes */ + { 0xF011AFD6, 4, 0, DEFAULT, 0, 0x70, 0x07, DEFAULT, NOEXTRA }, /* Rockman 4- Minus Infinity [Infinite Life]. Basically oversize MMC3 that fails to enable WRAM before accessing it. */ { 0xdb7f07be, 4, DEFAULT, DEFAULT, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Toki (USA) (Beta).nes */ { 0x8F6CC85A, 4, DEFAULT, DEFAULT, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* (KT-220B) Totally Rad 4-in-1.nes [overdump] */ { 0xAB9DE91F, 4, DEFAULT, DEFAULT, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* (KT-220B) Totally Rad 4-in-1.nes, Commonly set to mapper 176 */ + { 0x25952141, 4, DEFAULT, DEFAULT, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* AD&D Pool of Radiance */ + { 0x1335cb05, 4, DEFAULT, DEFAULT, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Crystalis */ + { 0x57e220d0, 4, DEFAULT, DEFAULT, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Final Fantasy 3 */ + { 0x889129cb, 4, 1, DEFAULT, 1, 0x40, DEFAULT, DEFAULT, NOEXTRA }, /* Startropics */ + { 0xd054ffb0, 4, 1, DEFAULT, 1, 0x40, DEFAULT, DEFAULT, NOEXTRA }, /* Startropics 2*/ + { 0x33751782, 4, 1, DEFAULT, 1, 0x40, DEFAULT, DEFAULT, NOEXTRA }, /* Zoda's Revenge - StarTropics II (USA, Europe) (Virtual Console).nes */ + { 0xE7B34C02, 4, 1, DEFAULT, 1, 0x40, DEFAULT, DEFAULT, NOEXTRA }, /* StarTropics (NTSC).nes */ + { 0xF6A64735, 4, 1, DEFAULT, 1, 0x40, DEFAULT, DEFAULT, NOEXTRA }, /* StarTropics (PAL).nes */ + { 0xFCEDB11A, 4, 1, DEFAULT, 1, 0x40, DEFAULT, DEFAULT, NOEXTRA }, /* Startropics [music synchronization].nes */ + { 0x998422FC, 4, 1, DEFAULT, 1, 0x40, DEFAULT, DEFAULT, NOEXTRA }, /* Startropics_1.nes */ + + { 0x57D162F1, 4, 0, DEFAULT, 0, 0x07, DEFAULT, DEFAULT, NOEXTRA }, /* Mickey Mouse III */ + { 0x762653B1, 4, 0, DEFAULT, 0, 0x07, DEFAULT, DEFAULT, NOEXTRA }, /* Mickey Mouse III Dream Balloon (T-Eng) */ + + /* CRC32, mapperNum, SubMapper, Mirroring, hasBattery, prgRam, chrRam, region, extra flags */ /* MMC5 */ - { 0x671f23a8, 5, DEFAULT, DEFAULT, 0, 0, 0, PAL, NOEXTRA }, /* Castlevania III - Dracula's Curse (E) */ + { 0x671f23a8, 5, DEFAULT, DEFAULT, 0, 0, 0, NES_PAL, NOEXTRA }, /* Castlevania III - Dracula's Curse (E) */ { 0xcd4e7430, 5, DEFAULT, DEFAULT, 0, 0, 0, DEFAULT, NOEXTRA }, /* Castlevania III - Dracula's Curse (KC) */ { 0xed2465be, 5, DEFAULT, DEFAULT, 0, 0, 0, DEFAULT, NOEXTRA }, /* Castlevania III - Dracula's Curse (U) */ { 0x0afb395e, 5, DEFAULT, DEFAULT, 0, 0, 0, DEFAULT, NOEXTRA }, /* Gun Sight */ @@ -183,8 +209,8 @@ { 0x184c2124, 5, DEFAULT, DEFAULT, 1, 0x90, 0, DEFAULT, NOEXTRA }, /* Sangokushi II (J) (PRG0) */ { 0xee8e6553, 5, DEFAULT, DEFAULT, 1, 0x90, 0, DEFAULT, NOEXTRA }, /* Sangokushi II (J) (PRG1) */ - { 0xf518dd58, 7, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Captain Skyhawk (USA).nes */ - { 0x6c4a9735, 7, DEFAULT, DFAULT8, 1, DEFAULT, DEFAULT, PAL, NOEXTRA }, /* WWF Wrestlemania (Europe).nes */ + { 0xf518dd58, 7, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Captain Skyhawk (USA).nes */ + { 0x6c4a9735, 7, DEFAULT, MI_H, 1, DEFAULT, DEFAULT, NES_PAL, NOEXTRA }, /* WWF Wrestlemania (Europe).nes */ { 0x84382231, 9, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Punch-Out!! (Japan) (Gold Edition).nes */ { 0xbe939fce, 9, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Punch-Out!! (U) [b1].nes */ { 0x7b837fde, 9, DEFAULT, DEFAULT, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Mike Tyson's Punch-Out!! (PC10) [b1].nes */ @@ -192,8 +218,8 @@ { 0xb79f2651, 11, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Chiller (USA) (Unl).nes */ { 0x5e66eaea, 13, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Videomation (USA).nes */ { 0xcd373baa, 14, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 武士魂 (8 characters).nes */ - { 0xbfc7a2e9, 16, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Dragon Ball 3 - Gokuu Den (Japan) (Rev 1).nes */ - { 0x6e68e31a, 16, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Dragon Ball 3 - Gokuu Den (Japan).nes */ + { 0xbfc7a2e9, 16, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Dragon Ball 3 - Gokuu Den (Japan) (Rev 1).nes */ + { 0x6e68e31a, 16, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Dragon Ball 3 - Gokuu Den (Japan).nes */ { 0x33b899c9, 16, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Dragon Ball - Daimaou Fukkatsu (Japan).nes */ { 0xa262a81f, 16, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Rokudenashi Blues (Japan).nes */ { 0x286fcd20, 21, DEFAULT, DEFAULT, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Ganbare Goemon Gaiden 2 - Tenka no Zaihou (Japan).nes */ @@ -207,23 +233,23 @@ { 0x43753886, 27, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Mi Hun Che (Ch)(replaced copyrights)[p1][!].nes */ { 0x5b3de3d1, 27, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* -- */ { 0x511e73f8, 27, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Mi Hun Che (Ch) [p1][b2].nes */ - { 0x5555fca3, 32, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Ai Sensei no Oshiete - Watashi no Hoshi (J) [b1].nes */ - { 0x283ad224, 32, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Ai Sensei no Oshiete - Watashi no Hoshi (Japan).nes */ - { 0x243a8735, 32, DEFAULT, 0x10|4, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Major League (Japan).nes */ - { 0x8a7d0abe, 33, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Akira (Japan).nes */ - { 0x376138d8, 33, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Akira (J) [a1].nes */ - { 0xadf606f6, 33, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Bakushou!! Jinsei Gekijou (Japan).nes */ - { 0xbc7b1d0f, 33, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Bakushou!! Jinsei Gekijou 2 (Japan).nes */ - { 0x7a497ae3, 33, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Don Doko Don (Japan).nes */ - { 0xbaca10a9, 33, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Golfkko Open (Japan).nes */ - { 0xf80bdc50, 33, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Insector X (Japan).nes */ - { 0x2a6559a1, 33, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Operation Wolf (Japan).nes */ - { 0xaeb7fce9, 33, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Power Blazer (Japan).nes */ - { 0xd920f9df, 33, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Takeshi no Sengoku Fuuunji (Japan).nes */ - { 0x3cd4b420, 33, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Takeshi no Sengoku Fuuunji (Japan) (Beta).nes */ + { 0x5555fca3, 32, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Ai Sensei no Oshiete - Watashi no Hoshi (J) [b1].nes */ + { 0x283ad224, 32, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Ai Sensei no Oshiete - Watashi no Hoshi (Japan).nes */ + { 0x243a8735, 32, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Major League (Japan).nes */ + { 0x8a7d0abe, 33, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Akira (Japan).nes */ + { 0x376138d8, 33, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Akira (J) [a1].nes */ + { 0xadf606f6, 33, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Bakushou!! Jinsei Gekijou (Japan).nes */ + { 0xbc7b1d0f, 33, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Bakushou!! Jinsei Gekijou 2 (Japan).nes */ + { 0x7a497ae3, 33, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Don Doko Don (Japan).nes */ + { 0xbaca10a9, 33, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Golfkko Open (Japan).nes */ + { 0xf80bdc50, 33, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Insector X (Japan).nes */ + { 0x2a6559a1, 33, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Operation Wolf (Japan).nes */ + { 0xaeb7fce9, 33, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Power Blazer (Japan).nes */ + { 0xd920f9df, 33, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Takeshi no Sengoku Fuuunji (Japan).nes */ + { 0x3cd4b420, 33, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Takeshi no Sengoku Fuuunji (Japan) (Beta).nes */ { 0x4c7c1af3, 34, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Caesars Palace (U) [b1].nes */ { 0x932ff06e, 34, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Classic Concentration (U) [b1].nes */ - { 0xf46ef39a, 37, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, PAL, NOEXTRA }, /* Super Mario Bros. + Tetris + Nintendo World Cup (Europe) (Rev 1).nes */ + { 0xf46ef39a, 37, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, NES_PAL, NOEXTRA }, /* Super Mario Bros. + Tetris + Nintendo World Cup (Europe) (Rev 1).nes */ { 0x4686c5dd, 41, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Caltron - 6 in 1 (USA) (Unl).nes */ { 0x090c0c17, 42, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Ai Senshi Nicol (FDS Conversion) [p1][!].nes */ { 0x4df84825, 42, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Ai Senshi Nicol (FDS Conversion) [p2][!].nes */ @@ -235,33 +261,33 @@ { 0x50ab1ab2, 42, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* ?? Green Beret (FDS Conversion, LH09) (Unl) [U][!][t1] (160K PRG */ { 0x7ccb12a3, 43, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* ?? SMB2j */ { 0x6c71feae, 45, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Kunio 8-in-1 [p1].nes */ - { 0x40c0ad47, 48, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Flintstones, The - The Rescue of Dino & Hoppy (Japan).nes */ - { 0xaebd6549, 48, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Bakushou!! Jinsei Gekijou 3 (Japan).nes */ - { 0x6cdc0cd9, 48, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Bubble Bobble 2 (Japan).nes */ - { 0x99c395f9, 48, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Captain Saver (Japan).nes */ - { 0xa7b0536c, 48, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Don Doko Don 2 (Japan).nes */ - { 0xb17c828a, 48, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Don Doko Don 2 (J) [a1].nes */ - { 0x40c0ad47, 48, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Flintstones, The - The Rescue of Dino & Hoppy (J).nes */ - { 0x1500e835, 48, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Jetsons, The - Cogswell's Caper (Japan).nes */ - { 0xe2c94bc2, 48, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Super Bros 8 (Unl) [!].nes */ - { 0xa912b064, 51, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, 0x800 }, /* 11-in-1 Ball Games [p1][o1].nes (has CHR ROM when it shouldn't) */ - { 0x2e72a5d9, 59, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 11-in-1 (66-in-1, 86-in-1, 63-in-1).nes */ - { 0x39f514fd, 59, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 18 in 1 (118-in-1, 138-in-1, 198-in-1)VTxxxx.nes */ - { 0xd8b1f465, 59, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 26-in-1 (36-in-1, 46-in-1,56-in-1) VT 335.nes */ - { 0xcf82fae9, 59, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 28 in 1 (38-in-1, 48-in-1, 58-in1)VTxxxx.nes */ - { 0xa7a98698, 59, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 28-in-1 (46-in-1, 63-in-1, 118-in-1)VT-5116.nes */ - { 0x21fd7143, 59, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 41-in-1 (5-in-1,71-in-1) VT345.nes */ - { 0x49ec88d6, 59, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 42-in-1 NT-234 Bad Game Road Fighter.nes */ - { 0x60306f19, 59, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 42-in-1 PCB 3840.nes */ - { 0x450cd86e, 59, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 48-in-1 (62-in-1,73-in-1,88-in-1) VTxxx.nes */ - { 0xd774e041, 59, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 50-in-1 (60-in-1,70-in-1,80-in-1) NT-113.nes */ - { 0x3c4e94f6, 59, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 51-in-1 (61-in-1, 71-in-1, 81-in-1) VT5310.nes */ - { 0x0422ed44, 59, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 7-in-1 (32-in-1,66-in-1,119-in-1) VT15004.nes */ - { 0x7efc0d2c, 59, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 7-in-1 (5000-in-1, 999999999-in-1, 10000000-in-1)NC-07N.nes */ - { 0x6d92dff1, 59, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* TN 95-in-1 (6-in-1) [p1].nes */ + { 0x40c0ad47, 48, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Flintstones, The - The Rescue of Dino & Hoppy (Japan).nes */ + { 0xaebd6549, 48, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Bakushou!! Jinsei Gekijou 3 (Japan).nes */ + { 0x6cdc0cd9, 48, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Bubble Bobble 2 (Japan).nes */ + { 0x99c395f9, 48, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Captain Saver (Japan).nes */ + { 0xa7b0536c, 48, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Don Doko Don 2 (Japan).nes */ + { 0xb17c828a, 48, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Don Doko Don 2 (J) [a1].nes */ + { 0x40c0ad47, 48, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Flintstones, The - The Rescue of Dino & Hoppy (J).nes */ + { 0x1500e835, 48, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Jetsons, The - Cogswell's Caper (Japan).nes */ + { 0xe2c94bc2, 48, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Super Bros 8 (Unl) [!].nes */ + { 0xa912b064, 51, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, 0x800 }, /* 11-in-1 Ball Games [p1][o1].nes (has CHR ROM when it shouldn't) */ + { 0x2e72a5d9, 59, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 11-in-1 (66-in-1, 86-in-1, 63-in-1).nes */ + { 0x39f514fd, 59, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 18 in 1 (118-in-1, 138-in-1, 198-in-1)VTxxxx.nes */ + { 0xd8b1f465, 59, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 26-in-1 (36-in-1, 46-in-1,56-in-1) VT 335.nes */ + { 0xcf82fae9, 59, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 28 in 1 (38-in-1, 48-in-1, 58-in1)VTxxxx.nes */ + { 0xa7a98698, 59, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 28-in-1 (46-in-1, 63-in-1, 118-in-1)VT-5116.nes */ + { 0x21fd7143, 59, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 41-in-1 (5-in-1,71-in-1) VT345.nes */ + { 0x49ec88d6, 59, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 42-in-1 NT-234 Bad Game Road Fighter.nes */ + { 0x60306f19, 59, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 42-in-1 PCB 3840.nes */ + { 0x450cd86e, 59, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 48-in-1 (62-in-1,73-in-1,88-in-1) VTxxx.nes */ + { 0xd774e041, 59, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 50-in-1 (60-in-1,70-in-1,80-in-1) NT-113.nes */ + { 0x3c4e94f6, 59, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 51-in-1 (61-in-1, 71-in-1, 81-in-1) VT5310.nes */ + { 0x0422ed44, 59, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 7-in-1 (32-in-1,66-in-1,119-in-1) VT15004.nes */ + { 0x7efc0d2c, 59, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 7-in-1 (5000-in-1, 999999999-in-1, 10000000-in-1)NC-07N.nes */ + { 0x6d92dff1, 59, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* TN 95-in-1 (6-in-1) [p1].nes */ { 0xF2CCE424, 59, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 78-in-1 (69, 98, 1800-in-1) (VT1512A_20210626) (Unl) [p1].nes */ - { 0x39ab0fc7, 64, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Hard Drivin' (USA) (Proto) (Unl).nes */ - { 0xb19a55dd, 64, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Road Runner (USA) (Unl).nes */ + { 0x39ab0fc7, 64, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Hard Drivin' (USA) (Proto) (Unl).nes */ + { 0xb19a55dd, 64, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Road Runner (USA) (Unl).nes */ { 0xf92be3ec, 64, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Rolling Thunder (USA) (Unl).nes */ { 0xd114f544, 66, DEFAULT, MI_H, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* AV Super Real Pachinko (Japan) (Unl).nes */ { 0xe84274c5, 66, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Mississippi Satsujin Jiken (J) [h2].nes */ @@ -279,21 +305,21 @@ { 0x496ac8f7, 74, DEFAULT, DEFAULT, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Ji Jia Zhan Shi (Ch) [b3].nes */ { 0xae854cef, 74, DEFAULT, DEFAULT, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Jia A Fung Yun (Ch).nes */ { 0xba51ac6f, 78, DEFAULT, MI_4, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Holy Diver (Japan).nes */ - { 0x3d1c3137, 78, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Uchuusen Cosmo Carrier (Japan).nes */ + { 0x3d1c3137, 78, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Uchuusen Cosmo Carrier (Japan).nes */ { 0xa4fbb438, 79, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* F-15 City War (AVE) (REV1.x) [b1].nes */ { 0xd4a76b07, 79, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* F-15 City War (AVE) (REV1.x) [b2].nes */ { 0x8eab381c, 79, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Deathbots (USA) (Rev 1) (Unl).nes */ { 0x1eb4a920, 79, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Double Strike - Aerial Attack Force (USA) (v1.1) (Unl).nes */ { 0x3e1271d5, 79, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Tiles of Fate (USA) (Unl).nes */ { 0xd2699893, 88, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Dragon Spirit - Aratanaru Densetsu (Japan).nes */ - { 0xbb7c5f7a, 89, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Tenka no Goikenban - Mito Koumon (J) [f1].nes */ + { 0xbb7c5f7a, 89, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Tenka no Goikenban - Mito Koumon (J) [f1].nes */ { 0x082778e6, 91, 1, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Super Fighter III.nes */ - { 0x10119e6b, 93, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Fantasy Zone (Japan) (Sunsoft).nes */ + { 0x10119e6b, 93, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Fantasy Zone (Japan) (Sunsoft).nes */ { 0x2b750bf9, 101, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Urusei Yatsura - Lum no Wedding Bell (Japan) (Beta).nes */ { 0x0da5e32e, 101, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Urusei Yatsura - Lum no Wedding Bell (Japan).nes */ { 0x6096f84e, 104, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Pegasus 5-in-1 (Golden Five) (Unl).nes */ { 0x3d3ff543, 113, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Kazama Jun to Asama Yuuko no AV Dragon Mahjong (Japan) (Unl).nes */ - { 0x68379fdb, 113, DEFAULT, MI_V, 1, DEFAULT, DEFAULT, PAL, NOEXTRA }, /* Pipemania (Australia) (HES) (Unl).nes */ + { 0x68379fdb, 113, DEFAULT, MI_V, 1, DEFAULT, DEFAULT, NES_PAL, NOEXTRA }, /* Pipemania (Australia) (HES) (Unl).nes */ { 0x6a03d3f3, 114, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Lion King, The (Unl) (Mapper 114).nes */ { 0x0d98db53, 114, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Pocahontas (Unl).nes */ { 0xf5676f0b, 114, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Super Donkey Kong (Unl) [b1].nes */ @@ -308,7 +334,7 @@ { 0x318e5502, 121, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Sonic 3D Blast 6 (Unl).nes */ { 0xddcfb058, 121, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Street Fighter Zero 2 '97 (Unl) [!].nes */ { 0xd2674b0a, 132, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Qi Wang - Chinese Chess (Asia) (Ja) (Unl).nes */ - { 0x5aefbc94, 133, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, PAL, NOEXTRA }, /* Jovial Race (Asia) (Ja) (PAL) (Unl).nes */ + { 0x5aefbc94, 133, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, NES_PAL, NOEXTRA }, /* Jovial Race (Asia) (Ja) (PAL) (Unl).nes */ { 0xB550B627, 136, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Incantation (Dip Bin) (Joy Van).nes */ { 0xc2df0a00, 140, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Bio Senshi Dan - Increaser Tono Tatakai (J) [hM66][b3].nes */ { 0xe46b1c5d, 140, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Mississippi Satsujin Jiken (Japan).nes */ @@ -320,35 +346,35 @@ { 0xa62b79e1, 146, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Sidewinder (HES) [o1].nes */ { 0xcc868d4e, 149, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Taiwan Mahjong 16 (Sachen) [a1][!].nes */ { 0x29582ca1, 150, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Mei Nu Quan (Honey Peach) (Sachen) [!].nes */ - { 0x40dbf7a2, 150, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, PAL, NOEXTRA }, /* Olympic IQ (Asia) (Ja) (PAL) (Unl).nes */ + { 0x40dbf7a2, 150, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, NES_PAL, NOEXTRA }, /* Olympic IQ (Asia) (Ja) (PAL) (Unl).nes */ { 0x73fb55ac, 150, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Lightgun Game 2 in 1 - Cosmocop + Cyber Monster (Asia) (Ja) (Unl).nes */ { 0xddcbda16, 150, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Lightgun Game 2 in 1 - Tough Cop + Super Tough Cop (Asia) (Ja) (Unl).nes */ - { 0x47918d84, 150, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, PAL, NOEXTRA }, /* Auto-Upturn (Asia) (Ja) (PAL) (Unl).nes */ - { 0x471173e7, 150, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, PAL, NOEXTRA }, /* Chinese Checkers (Asia) (Ja) (PAL) (Unl).nes */ - { 0x2394ae1c, 150, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, PAL, NOEXTRA }, /* Happy Pairs (Asia) (Ja) (PAL) (Unl).nes */ - { 0xcab40a6c, 150, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, PAL, NOEXTRA }, /* Magic Cube (Asia) (Ja) (PAL) (Unl).nes */ + { 0x47918d84, 150, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, NES_PAL, NOEXTRA }, /* Auto-Upturn (Asia) (Ja) (PAL) (Unl).nes */ + { 0x471173e7, 150, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, NES_PAL, NOEXTRA }, /* Chinese Checkers (Asia) (Ja) (PAL) (Unl).nes */ + { 0x2394ae1c, 150, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, NES_PAL, NOEXTRA }, /* Happy Pairs (Asia) (Ja) (PAL) (Unl).nes */ + { 0xcab40a6c, 150, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, NES_PAL, NOEXTRA }, /* Magic Cube (Asia) (Ja) (PAL) (Unl).nes */ { 0xbe17e27b, 150, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Poker III (Asia) (Ja) (Alt 2) (Unl).nes */ { 0x34ddf806, 150, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Strategist (Asia) (Ja) (NTSC) (Unl).nes */ - { 0xc06facfc, 150, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, PAL, NOEXTRA }, /* Strategist (Asia) (Ja) (PAL) (Unl).nes */ + { 0xc06facfc, 150, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, NES_PAL, NOEXTRA }, /* Strategist (Asia) (Ja) (PAL) (Unl).nes */ { 0xa95a915a, 150, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Tasac (Asia) (Ja) (Unl).nes */ - { 0x0f141525, 152, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Arkanoid II (Japan).nes */ - { 0xbda8f8e4, 152, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Gegege no Kitarou 2 - Youkai Gundan no Chousen (Japan).nes */ - { 0xb1a94b82, 152, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Pocket Zaurus - Juu Ouken no Nazo (Japan).nes */ - { 0x026c5fca, 152, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Saint Seiya - Ougon Densetsu (Japan).nes */ - { 0x3f15d20d, 153, DEFAULT, DFAULT8, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Famicom Jump II - Saikyou no 7 Nin (Japan).nes */ - { 0xd1691028, 154, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Devil Man (Japan).nes */ - { 0xcfd4a281, 155, DEFAULT, DFAULT8, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Money Game, The (Japan).nes */ - { 0x2f27cdef, 155, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Tatakae!! Rahmen Man - Sakuretsu Choujin 102 Gei (J) [b1].nes */ - { 0xc1719664, 155, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Tatakae!! Rahmen Man - Sakuretsu Choujin 102 Gei (Japan).nes */ + { 0x0f141525, 152, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Arkanoid II (Japan).nes */ + { 0xbda8f8e4, 152, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Gegege no Kitarou 2 - Youkai Gundan no Chousen (Japan).nes */ + { 0xb1a94b82, 152, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Pocket Zaurus - Juu Ouken no Nazo (Japan).nes */ + { 0x026c5fca, 152, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Saint Seiya - Ougon Densetsu (Japan).nes */ + { 0x3f15d20d, 153, DEFAULT, MI_H, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Famicom Jump II - Saikyou no 7 Nin (Japan).nes */ + { 0xd1691028, 154, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Devil Man (Japan).nes */ + { 0xcfd4a281, 155, DEFAULT, MI_H, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Money Game, The (Japan).nes */ + { 0x2f27cdef, 155, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Tatakae!! Rahmen Man - Sakuretsu Choujin 102 Gei (J) [b1].nes */ + { 0xc1719664, 155, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Tatakae!! Rahmen Man - Sakuretsu Choujin 102 Gei (Japan).nes */ { 0xccc03440, 156, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Buzz & Waldog (USA) (Proto) (Unl).nes */ - { 0x983d8175, 157, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Datach - Battle Rush - Build Up Robot Tournament (Japan).nes */ - { 0x894efdbc, 157, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Datach - Crayon Shin-chan - Ora to Poi Poi (Japan).nes */ - { 0x19e81461, 157, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Datach - Dragon Ball Z - Gekitou Tenkaichi Budoukai (Japan).nes */ - { 0xbe06853f, 157, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Datach - J.League Super Top Players (Japan).nes */ - { 0x0be0a328, 157, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Datach - SD Gundam - Gundam Wars (Japan).nes */ - { 0x5b457641, 157, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Datach - Ultraman Club - Supokon Fight! (Japan).nes */ - { 0xf51a7f46, 157, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Datach - Yu Yu Hakusho - Bakutou Ankoku Bujutsukai (Japan).nes */ - { 0xcbf4366f, 158, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Alien Syndrome (USA) (Unl).nes */ + { 0x983d8175, 157, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Datach - Battle Rush - Build Up Robot Tournament (Japan).nes */ + { 0x894efdbc, 157, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Datach - Crayon Shin-chan - Ora to Poi Poi (Japan).nes */ + { 0x19e81461, 157, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Datach - Dragon Ball Z - Gekitou Tenkaichi Budoukai (Japan).nes */ + { 0xbe06853f, 157, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Datach - J.League Super Top Players (Japan).nes */ + { 0x0be0a328, 157, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Datach - SD Gundam - Gundam Wars (Japan).nes */ + { 0x5b457641, 157, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Datach - Ultraman Club - Supokon Fight! (Japan).nes */ + { 0xf51a7f46, 157, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Datach - Yu Yu Hakusho - Bakutou Ankoku Bujutsukai (Japan).nes */ + { 0xcbf4366f, 158, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Alien Syndrome (USA) (Unl).nes */ { 0xe170404c, 159, DEFAULT, DEFAULT, 1, 0x10, DEFAULT, DEFAULT, NOEXTRA }, /* SD Gundam Gaiden - Knight Gundam Monogatari (Japan).nes */ { 0x276ac722, 159, DEFAULT, DEFAULT, 1, 0x10, DEFAULT, DEFAULT, NOEXTRA }, /* SD Gundam Gaiden - Knight Gundam Monogatari (Japan) (Rev 1).nes */ { 0x0cf42e69, 159, DEFAULT, DEFAULT, 1, 0x10, DEFAULT, DEFAULT, NOEXTRA }, /* Magical Taruruuto-kun - Fantastic World!! (Japan).nes */ @@ -596,7 +622,6 @@ { 0xE3A0B9E5, 176, 0, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* (YH-8027) Super Game 4-in-1 */ { 0x5A0E3E69, 176, 0, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* (YH-8033) Super Game 4-in-1 */ { 0x21D4484A, 176, 0, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* (YH-8042) Super Game 4-in-1 */ - { 0xF011AFD6, 4, 0, DEFAULT, 0, 0x70, 0x07, DEFAULT, NOEXTRA }, /* Rockman 4- Minus Infinity [Infinite Life]. Basically oversize MMC3 that fails to enable WRAM before accessing it. */ { 0x576D9589, 176, 1, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* (BS-0210A PCB) Super Mario 4-in-1.nes */ { 0x01B3EDD2, 176, 1, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* (BS-6002) Super Game 16-in-1.nes */ { 0x291F5318, 176, 1, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* (BS-6008) 210-in-1.nes */ @@ -743,8 +768,8 @@ { 0x1923A8C5, 176, 2, DEFAULT, 1, 0x90, 0x07, DENDY, NOEXTRA }, /* 水滸神獸 [protection removed].nes */ { 0x6B4CAC80, 176, 2, DEFAULT, 1, 0x90, 0x07, DENDY, NOEXTRA }, /* 水滸神獸.nes */ { 0xC9D968AF, 176, 2, DEFAULT, 1, 0x90, 0x07, DENDY, NOEXTRA }, /* 混沌世界.nes */ - { 0x7F3DBF1B, 176, 2, DEFAULT, 1, 0x90, 0x07, PAL, NOEXTRA }, /* 混沌世界 [VirtuaNES PAL].nes */ - { 0xB616885C, 176, 2, DEFAULT, 1, 0x90, 0x07, PAL, NOEXTRA }, /* 混沌世界 [VirtuaNES PAL, SRAM bank switch removed].nes */ + { 0x7F3DBF1B, 176, 2, DEFAULT, 1, 0x90, 0x07, NES_PAL, NOEXTRA }, /* 混沌世界 [VirtuaNES PAL].nes */ + { 0xB616885C, 176, 2, DEFAULT, 1, 0x90, 0x07, NES_PAL, NOEXTRA }, /* 混沌世界 [VirtuaNES NES_PAL, SRAM bank switch removed].nes */ { 0xF031E7CD, 176, 2, DEFAULT, 1, 0x90, 0x07, DENDY, NOEXTRA }, /* 激战弗利萨之孙悟饭.nes */ { 0xD871D3E6, 176, 2, DEFAULT, 1, 0x90, 0x07, DENDY, NOEXTRA }, /* 激战弗利萨之孙悟饭 [bad CHR].nes */ { 0xC35E9AA8, 176, 2, DEFAULT, 1, 0x90, 0x07, DENDY, NOEXTRA }, /* 激战弗利萨之孙悟饭 [Traditional Chinese].nes */ @@ -799,7 +824,7 @@ { 0x558c0dc3, 178, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Super 2-in-1 (Soccer Game & Crazy Dance) (Unl) [!].nes */ { 0xc68363f6, 180, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Crazy Climber (Japan).nes */ { 0x0f05ff0a, 185, 4, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Seicross (Japan) (Rev 1).nes */ - { 0x96ce586e, 189, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Street Fighter II - The World Warrior (Unl) [!].nes */ + { 0x96ce586e, 189, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Street Fighter II - The World Warrior (Unl) [!].nes */ { 0x0e76e4c1, 190, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Magic Kid Googoo (Korea) (Unl).nes */ { 0x555a555e, 191, DEFAULT, DEFAULT, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Sugoro Quest - Dice no Senshitachi (Ch).nes */ { 0x2cc381f6, 191, DEFAULT, DEFAULT, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Sugoro Quest - Dice no Senshitachi (Ch) [o1].nes */ @@ -831,7 +856,7 @@ { 0x96dfc776, 206, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* R.B.I. Baseball 2 (USA) (Unl).nes */ { 0xfd63e7ac, 206, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* R.B.I. Baseball 3 (USA) (Unl).nes */ { 0x2a01f9d1, 206, DEFAULT, MI_V, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Wagyan Land (Japan).nes */ - { 0x7678f1d5, 207, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Fudou Myouou Den (Japan).nes */ + { 0x7678f1d5, 207, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Fudou Myouou Den (Japan).nes */ { 0x07eb2c12, 208, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* FC25-台湾格斗游戏+快打传说.nes */ { 0xdd8ced31, 209, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Power Rangers III (Unl) [!].nes */ { 0x063b1151, 209, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Power Rangers IV (Unl) [!].nes */ @@ -852,7 +877,7 @@ { 0x046d70cc, 217, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* ?? 500-in-1 (Anim Splash, Alt Mapper)[p1][!] */ { 0x12f86a4d, 217, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 500-in-1.nes */ { 0xd09f778d, 217, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* ?? 9999999-in-1 (Static Splash, Alt Mapper)[p1][!] */ - { 0x62ef6c79, 232, DEFAULT, DFAULT8, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Quattro Sports (Camerica) (Aladdin) [b1].nes */ + { 0x62ef6c79, 232, DEFAULT, MI_H, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Quattro Sports (Camerica) (Aladdin) [b1].nes */ { 0x2705eaeb, 234, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Maxi 15 (USA) (Unl).nes */ { 0x80cbcacb, 235, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 100-in-1 (Unl).nes */ { 0x6175b9a0, 235, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 150_in_1_199x-ASp.nes */ @@ -932,7 +957,6 @@ { 0x19c1ed51, 150, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Poker III (Asia) (Ja) (Unl).nes */ { 0x282745c5, 141, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Q Boy (Asia) (Ja) (Unl).nes */ { 0x4b9ecfb2, 21, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Wai Wai World 2 - SOS!! Paseri Jou (Japan) (Virtual Console).nes */ - { 0x33751782, 4, DEFAULT, DEFAULT, 1, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Zoda's Revenge - StarTropics II (USA, Europe) (Virtual Console).nes */ { 0x9bbf3e5d, 15, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* 168-in-1 [p1][!].nes */ /* TXC / Sachen / JoyVan */ @@ -974,5 +998,6 @@ { 0x2076CABF, 352, DEFAULT, DEFAULT, 0, DEFAULT, DEFAULT, DEFAULT, NOEXTRA }, /* Kaiser 4-in-1(Unl,KS106C)[p1] */ { 0x00000000, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, NOEXTRA } +}; #endif diff --git a/src/ines.c b/src/ines.c index 82a25201f..6250b71da 100644 --- a/src/ines.c +++ b/src/ines.c @@ -41,38 +41,124 @@ #include "unif.h" #include "vsuni.h" -extern SFORMAT FCEUVSUNI_STATEINFO[]; +#include "ines-correct.h" -uint8 *trainerpoo = NULL; -uint8 *ROM = NULL; -uint8 *VROM = NULL; -uint8 *MiscROM = NULL; -uint8 *ExtraNTARAM = NULL; -iNES_HEADER head = { 0 }; +struct console_type { + uint8 id; + char *name; +}; -CartInfo iNESCart = { 0 }; +static const struct console_type console_types_str[] = { + { 0x00, "NES/Famicom/Dendy" }, + { 0x01, "Nintendo Vs. System" }, + { 0x02, "Playchoice 10" }, + { 0x03, "Famiclone, but with CPU that supports Decimal Mode" }, + { 0x04, "NES/Famicom with EPSM module or plug-through cartridge" }, + { 0x05, "V.R. Technology VT01 with red/cyan STN palette" }, + { 0x06, "V.R. Technology VT02" }, + { 0x07, "V.R. Technology VT03" }, + { 0x08, "V.R. Technology VT09" }, + { 0x09, "V.R. Technology VT32" }, + { 0x0A, "V.R. Technology VT369" }, + { 0x0B, "UMC UM6578" }, + { 0x0C, "Famicom Network System" }, + { 0x0D, "reserved" }, + { 0x0E, "reserved" }, + { 0x0F, "reserved" }, + { 0 }, +}; + +struct input_type { + uint8 id; + char *name; +}; -uint32 ROM_size = 0; -uint32 VROM_size = 0; -uint32 MiscROM_size = 0; +static const struct input_type input_type_str[] = { + { 0x00, "Unspecified" }, + { 0x01, "Standard controllers" }, + { 0x02, "NES Four Score/Satellite" }, + { 0x03, "Famicom Four Players Adapter" }, + { 0x04, "Vs. System (1P via $4016)" }, + { 0x05, "Vs. System (1P via $4017)" }, + { 0x06, "Reserved" }, + { 0x07, "Vs. Zapper" }, + { 0x08, "Zapper ($4017)" }, + { 0x09, "Two Zappers" }, + { 0x0A, "Bandai Hyper Shot Lightgun" }, + { 0x0B, "Power Pad Side A" }, + { 0x0C, "Power Pad Side B" }, + { 0x0D, "Family Trainer Side A" }, + { 0x0E, "Family Trainer Side B" }, + { 0x0F, "Arkanoid Paddle (NES)" }, + { 0x10, "Arkanoid Paddle (Famicom)" }, + { 0x11, "Two Arkanoid Paddles plus Famicom Data Recorder" }, + { 0x12, "Konami Hyper Shot Controller" }, + { 0x13, "Coconuts Pachinko Controller" }, + { 0x14, "Exciting Boxing Punching Bag" }, + { 0x15, "Jissen Mahjong Controller" }, + { 0x16, "Party Tap" }, + { 0x17, "Oeka Kids Tablet" }, + { 0x18, "Sunsoft Barcode Battler" }, + { 0x19, "Miracle Piano Keyboard" }, + { 0x1A, "Pokkun Moguraa" }, + { 0x1B, "Top Rider" }, + { 0x1C, "Double-Fisted" }, + { 0x1D, "Famicom 3D System" }, + { 0x1E, "Doremikko Keyboard" }, + { 0x1F, "R.O.B. Gyro Set" }, + { 0x20, "Famicom Data Recorder (\"silent\" keyboard)" }, + { 0x21, "ASCII Turbo File" }, + { 0x22, "IGS Storage Battle Box" }, + { 0x23, "Family BASIC Keyboard" }, + { 0x24, "Dongda PEC-586 Keyboard" }, + { 0x25, "Bit Corp. Bit-79 Keyboard" }, + { 0x26, "Subor Keyboard" }, + { 0x27, "Subor Keyboard plus 3x8-bit mouse" }, + { 0x28, "Subor Keyboard plus 24-bit mouse $4016" }, + { 0x29, "SNES Mouse ($4017.d0)" }, + { 0x2A, "Multicart" }, + { 0x2B, "Two SNES controllers" }, + { 0x2C, "RacerMate Bicycle" }, + { 0x2D, "U-Force" }, + { 0x2E, "R.O.B. Stack-Up" }, + { 0x2F, "City Patrolman Lightgun" }, + { 0x30, "Sharp C1 Cassette Interface" }, + { 0x31, "Standard Controller with swapped Left-Right/Up-Down/B-A" }, + { 0x32, "Excalibor Sudoku Pad" }, + { 0x33, "ABL Pinball" }, + { 0x34, "Golden Nugget Casino extra buttons" }, + { 0x35, "Unknown famiclone keyboard used by the \"Golden Key\" educational cartridge" }, + { 0x36, "Subor Keyboard plus 24-bit mouse (via $4017)" }, + { 0x37, "Port test controller" }, + { 0x38, "Bandai Multi Game Player Gamepad" }, + { 0x39, "Venom TV Dance Mat" }, + { 0x3A, "LG TV Remote Control" }, + { 0 } +}; + +extern SFORMAT FCEUVSUNI_STATEINFO[]; + +romData_t ROM = { 0 }; +CartInfo iNESCart = { 0 }; +uint8 *ExtraNTARAM = NULL; static int CHRRAMSize = -1; static int iNES_Init(int num); - static DECLFR(TrainerRead) { - return (trainerpoo[A & 0x1FF]); + return (ROM.trainer.data[A & 0x1FF]); } -static void iNES_ExecPower() { - if (iNESCart.Power) +static void iNES_ExecPower(void) { + if (iNESCart.Power) { iNESCart.Power(); + } - if (trainerpoo) { + if (ROM.trainer.data) { int x; for (x = 0; x < 512; x++) { - X6502_DMW(0x7000 + x, trainerpoo[x]); - if (X6502_DMR(0x7000 + x) != trainerpoo[x]) { + X6502_DMW(0x7000 + x, ROM.trainer.data[x]); + if (X6502_DMR(0x7000 + x) != ROM.trainer.data[x]) { SetReadHandler(0x7000, 0x71FF, TrainerRead); break; } @@ -81,40 +167,43 @@ static void iNES_ExecPower() { } static void Cleanup(void) { - if (ROM) { - free(ROM); - ROM = NULL; + if (ROM.prg.data) { + free(ROM.prg.data); + ROM.prg.data = NULL; } - if (VROM) { - free(VROM); - VROM = NULL; + if (ROM.chr.data) { + free(ROM.chr.data); + ROM.chr.data = NULL; } - if (trainerpoo) { - free(trainerpoo); - trainerpoo = NULL; + if (ROM.trainer.data) { + free(ROM.trainer.data); + ROM.trainer.data = NULL; } if (ExtraNTARAM) { free(ExtraNTARAM); ExtraNTARAM = NULL; } - if (MiscROM) { - free(MiscROM); - MiscROM = NULL; + if (ROM.misc.data) { + free(ROM.misc.data); + ROM.misc.data = NULL; + } + if (WRAM) { + free(WRAM); + WRAM = NULL; + WRAMSIZE = 0; } } static void iNESGI(int h) { switch (h) { case GI_RESETM2: - if (iNESCart.Reset) - iNESCart.Reset(); + if (iNESCart.Reset) iNESCart.Reset(); break; case GI_POWER: iNES_ExecPower(); break; case GI_CLOSE: - if (iNESCart.Close) - iNESCart.Close(); + if (iNESCart.Close) iNESCart.Close(); Cleanup(); break; } @@ -132,7 +221,7 @@ struct INPSEL { int inputfc; }; -static void SetInput(void) { +static void SetInput(CartInfo *info) { static struct INPSEL moo[] = { { 0x19b0a9f1, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, /* 6-in-1 (MGC-023)(Unl)[!] */ { 0x29de87af, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, /* Aerobics Studio */ @@ -208,7 +297,68 @@ static void SetInput(void) { int x = 0; while (moo[x].input1 >= 0 || moo[x].input2 >= 0 || moo[x].inputfc >= 0) { - if (moo[x].crc32 == iNESCart.CRC32) { + if (moo[x].crc32 == info->CRC32) { + GameInfo->input[0] = moo[x].input1; + GameInfo->input[1] = moo[x].input2; + GameInfo->inputfc = moo[x].inputfc; + break; + } + x++; + } +} + +struct INPSEL_NES20 { + uint8 id; + int input1; + int input2; + int inputfc; +}; + +/* +* Function to set input controllers based on NES 2.0 header +*/ + +static void SetInputNes20(uint8 input_id) { + static struct INPSEL_NES20 moo[] = + { + { 0x01, SI_GAMEPAD, SI_GAMEPAD, SIFC_UNSET }, /* Standard NES/Famicom controllers */ + { 0x02, SI_GAMEPAD, SI_GAMEPAD, SIFC_NONE }, /* NES Four Score/Satellite with two additional standard controllers */ + { 0x03, SI_GAMEPAD, SI_GAMEPAD, SIFC_4PLAYER }, /* Famicom Four Players Adapter with two additional standard controllers using the "simple" protocol */ + { 0x04, SI_GAMEPAD, SI_GAMEPAD, SIFC_NONE }, /* Vs. System (1P via $4016) */ + { 0x05, SI_GAMEPAD, SI_GAMEPAD, SIFC_NONE }, /* Vs. System (1P via $4017) */ + { 0x07, SI_ZAPPER, SI_NONE, SIFC_NONE }, /* Vs. Zapper */ + { 0x08, SI_UNSET, SI_ZAPPER, SIFC_NONE }, /* Zapper ($4017) */ + { 0x0A, SI_UNSET, SI_UNSET, SIFC_SHADOW }, /* Bandai Hyper Shot Lightgun */ + { 0x0B, SI_UNSET, SI_POWERPADA, SIFC_UNSET }, /* Power Pad Side A */ + { 0x0C, SI_UNSET, SI_POWERPADB, SIFC_UNSET }, /* Power Pad Side B */ + { 0x0D, SI_UNSET, SI_UNSET, SIFC_FTRAINERA }, /* Family Trainer Side A */ + { 0x0E, SI_UNSET, SI_UNSET, SIFC_FTRAINERB }, /* Family Trainer Side B */ + { 0x0F, SI_UNSET, SI_ARKANOID, SIFC_UNSET }, /* Arkanoid Paddle (NES) */ + { 0x10, SI_UNSET, SI_UNSET, SIFC_ARKANOID }, /* Arkanoid Paddle (Famicom) */ + { 0x12, SI_UNSET, SI_UNSET, SIFC_HYPERSHOT }, /* Konami Hyper Shot Controller */ + { 0x15, SI_UNSET, SI_UNSET, SIFC_MAHJONG }, /* Jissen Mahjong Controller */ + { 0x17, SI_UNSET, SI_UNSET, SIFC_OEKAKIDS }, /* Oeka Kids Tablet */ + { 0x18, SI_UNSET, SI_UNSET, SIFC_BWORLD }, /* Sunsoft Barcode Battler */ + { 0x1B, SI_UNSET, SI_UNSET, SIFC_TOPRIDER }, /* Top Rider (Inflatable Bicycle) */ + { 0x23, SI_UNSET, SI_UNSET, SIFC_FKB }, /* Family BASIC Keyboard plus Famicom Data Recorder */ + { 0x24, SI_UNSET, SI_UNSET, SIFC_PEC586KB }, /* Dongda PEC-586 Keyboard */ + { 0x26, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, /* Subor Keyboard */ + /* { 0x27, SI_UNSET, SI_MOUSE, SIFC_SUBORKB }, */ /* Subor Keyboard plus mouse (3x8-bit protocol) */ + { 0x28, SI_UNSET, SI_MOUSE, SIFC_SUBORKB }, /* Subor Keyboard plus mouse (24-bit protocol) */ + { 0x29, SI_UNSET, SI_SNES_MOUSE, SIFC_UNSET }, /* SNES Mouse */ + { 0x00, SI_UNSET, SI_UNSET, SIFC_UNSET } + }; + + int x = 0; + + /* four score adaptor */ + /*if (device == 0x02) + eoptions |= 32768;*/ + if (input_id == 0x05) + vsuni_system.ioption |= IOPTION_SWAPDIRAB; + + while (moo[x].id) { + if (moo[x].id == input_id) { GameInfo->input[0] = moo[x].input1; GameInfo->input[1] = moo[x].input2; GameInfo->inputfc = moo[x].inputfc; @@ -244,107 +394,93 @@ static void CheckBad(uint64 md5partial) { } } -struct CHINF { - uint32 crc32; - int32 mapper; - int32 submapper; - int32 mirror; - int32 battery; - int32 prgram; /* ines2 prgram format */ - int32 chrram; /* ines2 chrram format */ - int32 region; - int32 extra; +static char *mirroring_str[] = { + "Horizontal", + "Vertical", + "Single-screen 0", + "Single-screen 1", + "\"Four-screen\"" }; -static void CheckHInfo(void) { -#define DEFAULT (-1) -#define NOEXTRA (-1) - - /* used for mirroring special overrides */ -#define MI_4 2 /* forced 4-screen mirroring */ -#define DFAULT8 8 /* anything but hard-wired (4-screen) mirroring, mapper-controlled */ - - /* tv system/region */ -#define PAL 1 -#define MULTI 2 -#define DENDY 3 +const char *tv_region_str[] = { + "NTSC", + "PAL", + "Multi-region", + "Dendy", +}; - static struct CHINF moo[] = { -#include "ines-correct.h" - }; - int32 tofix = 0, x; - uint64 partialmd5 = 0; - int32 current_mapper = 0; - int32 cur_mirr = 0; +static void CheckHInfo(CartInfo *info, uint64 partialmd5) { + int32 tofix = 0; + int x; - for (x = 0; x < 8; x++) - partialmd5 |= (uint64)iNESCart.MD5[15 - x] << (x * 8); CheckBad(partialmd5); x = 0; do { - if (moo[x].crc32 == iNESCart.CRC32) { + if (moo[x].crc32 == info->CRC32) { if (moo[x].mapper >= 0) { - if (moo[x].extra >= 0 && moo[x].extra == 0x800 && VROM_size) { - VROM_size = 0; - free(VROM); - VROM = NULL; + if (moo[x].extra >= 0 && moo[x].extra == 0x800 && ROM.chr.size) { + ROM.chr.size = 0; + free(ROM.chr.data); + ROM.chr.data = NULL; tofix |= 8; } - if (iNESCart.mapper != (moo[x].mapper & 0xFFF)) { + if (info->mapper != (moo[x].mapper & 0xFFF)) { tofix |= 1; - current_mapper = iNESCart.mapper; - iNESCart.mapper = moo[x].mapper & 0xFFF; + info->mapper = moo[x].mapper & 0xFFF; } } if (moo[x].submapper >= 0) { - iNESCart.iNES2 = 1; - if (moo[x].submapper != iNESCart.submapper) { - iNESCart.submapper = moo[x].submapper; + info->iNES2 = 1; + if (moo[x].submapper != info->submapper) { + info->submapper = moo[x].submapper; } } if (moo[x].mirror >= 0) { - cur_mirr = iNESCart.mirror; - if (moo[x].mirror == 8) { - if (iNESCart.mirror == 2) { /* Anything but hard-wired(four screen). */ - tofix |= 2; - iNESCart.mirror = 0; - } - } else if (iNESCart.mirror != moo[x].mirror) { - if (iNESCart.mirror != (moo[x].mirror & ~4)) - if ((moo[x].mirror & ~4) <= 2) /* Don't complain if one-screen mirroring + if (info->mirror != moo[x].mirror) { + /* TODO: Verify this condition */ + if (info->mirror != (moo[x].mirror & ~MI_4)) + if ((moo[x].mirror & ~MI_4) <= 2) /* Don't complain if one-screen mirroring needs to be set(the iNES header can't hold this information). */ tofix |= 2; - iNESCart.mirror = moo[x].mirror; + info->mirror = moo[x].mirror; } } if (moo[x].battery >= 0) { - if (!(head.ROM_type & 2) && (moo[x].battery != 0)) { + if ((info->battery == 0) && (moo[x].battery != 0)) { tofix |= 4; - head.ROM_type |= 2; + info->battery = 1; } } if (moo[x].region >= 0) { - if (iNESCart.region != moo[x].region) { + if (info->region != moo[x].region) { tofix |= 16; - iNESCart.region = moo[x].region; + info->region = moo[x].region; } } if (moo[x].prgram >= 0) { - tofix |= 32; - iNESCart.iNES2 = 1; - iNESCart.PRGRamSize = (moo[x].prgram & 0x0F) ? (64 << ((moo[x].prgram >> 0) & 0xF)) : 0; - iNESCart.PRGRamSaveSize = (moo[x].prgram & 0xF0) ? (64 << ((moo[x].prgram >> 4) & 0xF)) : 0; + uint32 prgram = (moo[x].prgram & 0x0F) ? (64 << ((moo[x].prgram >> 0) & 0xF)) : 0; + uint32 prgsaveram = (moo[x].prgram & 0xF0) ? (64 << ((moo[x].prgram >> 4) & 0xF)) : 0; + if (prgram != info->PRGRamSize || prgsaveram != info->PRGRamSaveSize) { + tofix |= 32; + info->iNES2 = 1; + info->PRGRamSize = (moo[x].prgram & 0x0F) ? (64 << ((moo[x].prgram >> 0) & 0xF)) : 0; + info->PRGRamSaveSize = (moo[x].prgram & 0xF0) ? (64 << ((moo[x].prgram >> 4) & 0xF)) : 0; + } } if (moo[x].chrram >= 0) { - tofix |= 32; - iNESCart.iNES2 = 1; - iNESCart.CHRRamSize = (moo[x].chrram & 0x0F) ? (64 << ((moo[x].chrram >> 0) & 0xF)) : 0; - iNESCart.CHRRamSaveSize = (moo[x].chrram & 0xF0) ? (64 << ((moo[x].chrram >> 4) & 0xF)) : 0; + uint32 chrram = (moo[x].chrram & 0x0F) ? (64 << ((moo[x].chrram >> 0) & 0xF)) : 0; + uint32 chrsaveram = (moo[x].chrram & 0xF0) ? (64 << ((moo[x].chrram >> 4) & 0xF)) : 0; + if (chrram != info->CHRRamSize || chrsaveram != info->CHRRamSaveSize) { + tofix |= 32; + info->iNES2 = 1; + info->CHRRamSize = (moo[x].chrram & 0x0F) ? (64 << ((moo[x].chrram >> 0) & 0xF)) : 0; + info->CHRRamSaveSize = (moo[x].chrram & 0xF0) ? (64 << ((moo[x].chrram >> 4) & 0xF)) : 0; + } } break; @@ -355,59 +491,49 @@ static void CheckHInfo(void) { /* Games that use these iNES mappers tend to have the four-screen bit set when it should not be. */ - if ((iNESCart.mapper == 118 || iNESCart.mapper == 24 || iNESCart.mapper == 26) && (iNESCart.mirror == 2)) { - iNESCart.mirror = 0; + if ((info->mapper == 118 || info->mapper == 24 || info->mapper == 26) && (info->mirror == MI_4)) { + info->mirror = MI_H; tofix |= 2; } /* Four-screen mirroring implicitly set. */ - if (iNESCart.mapper == 99) - iNESCart.mirror = 2; + if (info->mapper == 99) { + if (info->mirror != MI_4) { + tofix |= 2; + info->mirror = MI_4; + } + } if (tofix) { - char gigastr[768]; - strcpy(gigastr, - " The iNES header contains incorrect information. For now, the information will be corrected in RAM. "); - if (tofix & 1) - sprintf(gigastr + strlen(gigastr), "Current mapper # is %d. The mapper number should be set to %d. ", - current_mapper, iNESCart.mapper); + FCEU_printf(" The iNES header contains incorrect information. For now, the information will be corrected in RAM.\n"); + if (tofix & 1) { + FCEU_printf(" [DB] Mapper: %3d\n", info->mapper); + } if (tofix & 2) { - uint8 *mstr[3] = { (uint8_t *)"Horizontal", (uint8_t *)"Vertical", (uint8_t *)"Four-screen" }; - sprintf(gigastr + strlen(gigastr), "Current mirroring is %s. Mirroring should be set to \"%s\". ", - mstr[cur_mirr & 3], mstr[iNESCart.mirror & 3]); + FCEU_printf(" [DB] Mirroring: %s\n", mirroring_str[info->mirror]); + } + if (tofix & 4) { + FCEU_printf(" [DB] Battery: %s\n", info->battery ? "Yes" : "No"); + } + if (tofix & 8) { + FCEU_printf(" [DB] CHR ROM: %d\n", info->CHRRomSize); } - 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. "); if (tofix & 16) { - uint8 *rstr[4] = { (uint8 *)"NTSC", (uint8 *)"PAL", (uint8 *)"Multi", (uint8 *)"Dendy" }; - sprintf(gigastr + strlen(gigastr), "This game should run with \"%s\" timings.", rstr[iNESCart.region]); + FCEU_printf(" [DB] Region: %s\n", tv_region_str[info->region]); } if (tofix & 32) { - unsigned PRGRAM = iNESCart.PRGRamSize + iNESCart.PRGRamSaveSize; - unsigned CHRRAM = iNESCart.CHRRamSize + iNESCart.CHRRamSaveSize; + size_t PRGRAM = info->PRGRamSize + info->PRGRamSaveSize; + size_t CHRRAM = info->CHRRamSize + info->CHRRamSaveSize; if (PRGRAM || CHRRAM) { - if (iNESCart.PRGRamSaveSize == 0) - sprintf(gigastr + strlen(gigastr), "workram: %d KB, ", PRGRAM / 1024); - else if (iNESCart.PRGRamSize == 0) - sprintf(gigastr + strlen(gigastr), "saveram: %d KB, ", PRGRAM / 1024); - else - sprintf(gigastr + strlen(gigastr), "workram: %d KB (%dKB battery-backed), ", PRGRAM / 1024, - iNESCart.PRGRamSaveSize / 1024); - sprintf(gigastr + strlen(gigastr), "chrram: %d KB.", (CHRRAM + iNESCart.CHRRamSaveSize) / 1024); + if (info->PRGRamSaveSize == 0) { + FCEU_printf(" [DB] PRG RAM: %d KB, ", PRGRAM / 1024); + } else { + FCEU_printf(" [DB] PRG RAM: %d KB ( %dKB is battery-backed )\n", PRGRAM / 1024, info->PRGRamSaveSize / 1024); + } + FCEU_printf(" [DB] CHR RAM: %d KB.", CHRRAM / 1024); } } - strcat(gigastr, "\n"); - FCEU_printf("%s\n", gigastr); } - -#undef DEFAULT -#undef NOEXTRA -#undef DFAULT8 -#undef MI_4 -#undef PAL -#undef DENDY } typedef struct { @@ -422,110 +548,110 @@ typedef struct { } BMAPPINGLocal; #define INES_BOARD_BEGIN() static BMAPPINGLocal bmap[] = { -#define INES_BOARD_END() { (uint8_t *)"", 0, NULL } }; +#define INES_BOARD_END(void) { (uint8_t *)"", 0, NULL } }; #define INES_BOARD(a, b, c) { (uint8_t *)a, b, c }, INES_BOARD_BEGIN() - INES_BOARD( "NROM", 0, NROM_Init ) - INES_BOARD( "MMC1", 1, Mapper1_Init ) - INES_BOARD( "UNROM", 2, UNROM_Init ) - INES_BOARD( "CNROM", 3, CNROM_Init ) - INES_BOARD( "MMC3", 4, Mapper4_Init ) - INES_BOARD( "MMC5", 5, Mapper5_Init ) - INES_BOARD( "FFE Rev. A", 6, Mapper6_Init ) - INES_BOARD( "ANROM", 7, ANROM_Init ) - INES_BOARD( "", 8, Mapper8_Init ) /* no games, it's worthless */ - INES_BOARD( "MMC2", 9, Mapper9_Init ) - INES_BOARD( "MMC4", 10, Mapper10_Init ) - INES_BOARD( "Color Dreams", 11, Mapper11_Init ) - INES_BOARD( "REX DBZ 5", 12, Mapper12_Init ) - INES_BOARD( "CPROM", 13, CPROM_Init ) - INES_BOARD( "REX SL-1632", 14, UNLSL1632_Init ) - INES_BOARD( "100-in-1", 15, Mapper15_Init ) - INES_BOARD( "BANDAI 24C02", 16, Mapper16_Init ) - INES_BOARD( "FFE Rev. B", 17, Mapper17_Init ) - INES_BOARD( "JALECO SS880006", 18, Mapper18_Init ) /* JF-NNX (EB89018-30007) boards */ - INES_BOARD( "Namcot 106", 19, Mapper19_Init ) + INES_BOARD( "NROM", 0, Mapper000_Init ) + INES_BOARD( "MMC1", 1, Mapper001_Init ) + INES_BOARD( "UNROM", 2, Mapper002_Init ) + INES_BOARD( "CNROM", 3, Mapper003_Init ) + INES_BOARD( "MMC3", 4, Mapper004_Init ) + INES_BOARD( "MMC5", 5, Mapper005_Init ) + INES_BOARD( "FFE Rev. A", 6, Mapper006_Init ) + INES_BOARD( "ANROM", 7, Mapper007_Init ) + INES_BOARD( "", 8, Mapper008_Init ) /* no games, it's worthless */ + INES_BOARD( "MMC2", 9, Mapper009_Init ) + INES_BOARD( "MMC4", 10, Mapper010_Init ) + INES_BOARD( "Color Dreams", 11, Mapper011_Init ) + INES_BOARD( "REX DBZ 5", 12, Mapper012_Init ) + INES_BOARD( "CPROM", 13, Mapper013_Init ) + INES_BOARD( "REX SL-1632", 14, Mapper014_Init ) + INES_BOARD( "100-in-1", 15, Mapper015_Init ) + INES_BOARD( "BANDAI 24C02", 16, Mapper016_Init ) + INES_BOARD( "FFE Rev. B", 17, Mapper017_Init ) + INES_BOARD( "JALECO SS880006", 18, Mapper018_Init ) /* JF-NNX (EB89018-30007) boards */ + INES_BOARD( "Namco 129/163", 19, Mapper019_Init ) /* INES_BOARD( "", 20, Mapper20_Init ) */ - INES_BOARD( "Konami VRC2/VRC4 A", 21, Mapper21_Init ) - INES_BOARD( "Konami VRC2/VRC4 B", 22, Mapper22_Init ) - INES_BOARD( "Konami VRC2/VRC4 C", 23, Mapper23_Init ) - INES_BOARD( "Konami VRC6 Rev. A", 24, Mapper24_Init ) - INES_BOARD( "Konami VRC2/VRC4 D", 25, Mapper25_Init ) - INES_BOARD( "Konami VRC6 Rev. B", 26, Mapper26_Init ) - INES_BOARD( "CC-21 MI HUN CHE", 27, UNLCC21_Init ) /* Former dupe for VRC2/VRC4 mapper, redefined with crc to mihunche boards */ - INES_BOARD( "Action 53", 28, Mapper28_Init ) - INES_BOARD( "RET-CUFROM", 29, Mapper29_Init ) - INES_BOARD( "UNROM 512", 30, UNROM512_Init ) - INES_BOARD( "infineteNesLives-NSF", 31, Mapper31_Init ) - INES_BOARD( "IREM G-101", 32, Mapper32_Init ) - INES_BOARD( "TC0190FMC/TC0350FMR", 33, Mapper33_Init ) - INES_BOARD( "IREM I-IM/BNROM", 34, Mapper34_Init ) - INES_BOARD( "EL870914C", 35, Mapper35_Init ) - INES_BOARD( "TXC Policeman", 36, Mapper36_Init ) - INES_BOARD( "PAL-ZZ SMB/TETRIS/NWC", 37, Mapper37_Init ) - INES_BOARD( "Bit Corp.", 38, Mapper38_Init ) /* Crime Busters */ + INES_BOARD( "Konami VRC2/VRC4 A", 21, Mapper021_Init ) + INES_BOARD( "Konami VRC2/VRC4 B", 22, Mapper022_Init ) + INES_BOARD( "Konami VRC2/VRC4 C", 23, Mapper023_Init ) + INES_BOARD( "Konami VRC6 Rev. A", 24, Mapper024_Init ) + INES_BOARD( "Konami VRC2/VRC4 D", 25, Mapper025_Init ) + INES_BOARD( "Konami VRC6 Rev. B", 26, Mapper026_Init ) + INES_BOARD( "CC-21 MI HUN CHE", 27, Mapper027_Init ) /* Former dupe for VRC2/VRC4 mapper, redefined with crc to mihunche boards */ + INES_BOARD( "Action 53", 28, Mapper028_Init ) + INES_BOARD( "RET-CUFROM", 29, Mapper029_Init ) + INES_BOARD( "UNROM 512", 30, Mapper030_Init ) + INES_BOARD( "infineteNesLives-NSF", 31, Mapper031_Init ) + INES_BOARD( "IREM G-101", 32, Mapper032_Init ) + INES_BOARD( "Taito TC0190FMC/TC0350FMR", 33, Mapper033_Init ) + INES_BOARD( "BNROM/NINA-001", 34, Mapper034_Init ) + INES_BOARD( "EL870914C", 35, Mapper035_Init ) + INES_BOARD( "TXC Policeman", 36, Mapper036_Init ) + INES_BOARD( "PAL-ZZ SMB/TETRIS/NWC", 37, Mapper037_Init ) + INES_BOARD( "Bit Corp.", 38, Mapper038_Init ) /* Crime Busters */ /* INES_BOARD( "", 39, Mapper39_Init ) */ - INES_BOARD( "SMB2j FDS", 40, Mapper40_Init ) - INES_BOARD( "CALTRON 6-in-1", 41, Mapper41_Init ) - INES_BOARD( "BIO MIRACLE FDS", 42, Mapper42_Init ) - INES_BOARD( "FDS SMB2j LF36", 43, Mapper43_Init ) - INES_BOARD( "MMC3 BMC PIRATE A", 44, Mapper44_Init ) - INES_BOARD( "MMC3 BMC PIRATE B", 45, Mapper45_Init ) - INES_BOARD( "RUMBLESTATION 15-in-1", 46, Mapper46_Init ) - INES_BOARD( "NES-QJ SSVB/NWC", 47, Mapper47_Init ) - INES_BOARD( "TAITO TCxxx", 48, Mapper48_Init ) - INES_BOARD( "MMC3 BMC PIRATE C", 49, Mapper49_Init ) - INES_BOARD( "SMB2j FDS Rev. A", 50, Mapper50_Init ) - INES_BOARD( "11-in-1 BALL SERIES", 51, Mapper51_Init ) /* 1993 year version */ - INES_BOARD( "MMC3 BMC PIRATE D", 52, Mapper52_Init ) - INES_BOARD( "SUPERVISION 16-in-1", 53, Supervision16_Init ) + INES_BOARD( "SMB2j FDS", 40, Mapper040_Init ) + INES_BOARD( "CALTRON 6-in-1", 41, Mapper041_Init ) + INES_BOARD( "BIO MIRACLE FDS", 42, Mapper042_Init ) + INES_BOARD( "FDS SMB2j LF36", 43, Mapper043_Init ) + INES_BOARD( "MMC3 BMC PIRATE A", 44, Mapper044_Init ) + INES_BOARD( "MMC3 BMC PIRATE B", 45, Mapper045_Init ) + INES_BOARD( "RUMBLESTATION 15-in-1", 46, Mapper046_Init ) + INES_BOARD( "NES-QJ SSVB/NWC", 47, Mapper047_Init ) + INES_BOARD( "Taito TC0690/TC190+PAL16R4", 48, Mapper048_Init ) + INES_BOARD( "MMC3 BMC PIRATE C", 49, Mapper049_Init ) + INES_BOARD( "SMB2j FDS Rev. A", 50, Mapper050_Init ) + INES_BOARD( "11-in-1 BALL SERIES", 51, Mapper051_Init ) /* 1993 year version */ + INES_BOARD( "MMC3 BMC PIRATE D", 52, Mapper052_Init ) + INES_BOARD( "SUPERVISION 16-in-1", 53, Mapper053_Init ) /* INES_BOARD( "", 54, Mapper54_Init ) */ - INES_BOARD( "MARIO1-MALEE2", 55, MALEE_Init ) - INES_BOARD( "UNLKS202", 56, UNLKS202_Init ) - INES_BOARD( "SIMBPLE BMC PIRATE A", 57, Mapper57_Init ) - INES_BOARD( "SIMBPLE BMC PIRATE B", 58, Mapper58_Init ) - INES_BOARD( "BMC T3H53/D1038", 59, BMCD1038_Init ) - INES_BOARD( "Reset-based NROM-128 ", 60, Mapper60_Init ) - INES_BOARD( "20-in-1 KAISER Rev. A", 61, Mapper61_Init ) - INES_BOARD( "700-in-1", 62, Mapper62_Init ) - INES_BOARD( "Powerful 250-in-1 (NTDEC TH2291)", 63, Mapper63_Init ) - INES_BOARD( "TENGEN RAMBO1", 64, Mapper64_Init ) - INES_BOARD( "IREM-H3001", 65, Mapper65_Init ) - INES_BOARD( "GNROM / MHROM", 66, MHROM_Init ) - INES_BOARD( "SUNSOFT-FZII", 67, Mapper67_Init ) - INES_BOARD( "Sunsoft Mapper #4", 68, Mapper68_Init ) - INES_BOARD( "SUNSOFT-5/FME-7", 69, Mapper69_Init ) - INES_BOARD( "BA KAMEN DISCRETE", 70, Mapper70_Init ) - INES_BOARD( "CAMERICA BF9093", 71, Mapper71_Init ) - INES_BOARD( "JALECO JF-17", 72, Mapper72_Init ) - INES_BOARD( "KONAMI VRC3", 73, Mapper73_Init ) - INES_BOARD( "TW MMC3+VRAM Rev. A", 74, Mapper74_Init ) - INES_BOARD( "KONAMI VRC1", 75, Mapper75_Init ) - INES_BOARD( "NAMCOT 108 Rev. A", 76, Mapper76_Init ) - INES_BOARD( "IREM LROG017", 77, Mapper77_Init ) - INES_BOARD( "Irem 74HC161/32", 78, Mapper78_Init ) - INES_BOARD( "AVE/C&E/TXC BOARD", 79, Mapper79_Init ) - INES_BOARD( "TAITO X1-005 Rev. A", 80, Mapper80_Init ) - INES_BOARD( "Super Gun (NTDEC N715021)", 81, Mapper81_Init ) - INES_BOARD( "TAITO X1-017", 82, Mapper82_Init ) - INES_BOARD( "YOKO VRC Rev. B", 83, Mapper83_Init ) + INES_BOARD( "MARIO1-MALEE2", 55, Mapper055_Init ) + INES_BOARD( "UNLKS202", 56, Mapper056_Init ) + INES_BOARD( "SIMBPLE BMC PIRATE A", 57, Mapper057_Init ) + INES_BOARD( "SIMBPLE BMC PIRATE B", 58, Mapper058_Init ) + INES_BOARD( "BMC T3H53/D1038", 59, Mapper059_Init ) + INES_BOARD( "Reset-based NROM-128 ", 60, Mapper060_Init ) + INES_BOARD( "20-in-1 KAISER Rev. A", 61, Mapper061_Init ) + INES_BOARD( "700-in-1", 62, Mapper062_Init ) + INES_BOARD( "Powerful 250-in-1 (NTDEC TH2291)", 63, Mapper063_Init ) + INES_BOARD( "TENGEN RAMBO1", 64, Mapper064_Init ) + INES_BOARD( "IREM-H3001", 65, Mapper065_Init ) + INES_BOARD( "GNROM / MHROM", 66, Mapper066_Init ) + INES_BOARD( "SUNSOFT-FZII", 67, Mapper067_Init ) + INES_BOARD( "Sunsoft Mapper #4", 68, Mapper068_Init ) + INES_BOARD( "SUNSOFT-5/FME-7", 69, Mapper069_Init ) + INES_BOARD( "BA KAMEN DISCRETE", 70, Mapper070_Init ) + INES_BOARD( "CAMERICA BF9093", 71, Mapper071_Init ) + INES_BOARD( "JALECO JF-17", 72, Mapper072_Init ) + INES_BOARD( "KONAMI VRC3", 73, Mapper073_Init ) + INES_BOARD( "TW MMC3+VRAM Rev. A", 74, Mapper074_Init ) + INES_BOARD( "KONAMI VRC1", 75, Mapper075_Init ) + INES_BOARD( "NAMCOT 108 Rev. A", 76, Mapper076_Init ) + INES_BOARD( "IREM LROG017", 77, Mapper077_Init ) + INES_BOARD( "Irem 74HC161/32", 78, Mapper078_Init ) + INES_BOARD( "AVE/C&E/TXC BOARD", 79, Mapper079_Init ) + INES_BOARD( "TAITO X1-005 Rev. A", 80, Mapper080_Init ) + INES_BOARD( "Super Gun (NTDEC N715021)", 81, Mapper081_Init ) + INES_BOARD( "TAITO X1-017", 82, Mapper082_Init ) + INES_BOARD( "YOKO VRC Rev. B", 83, Mapper083_Init ) /* INES_BOARD( "", 84, Mapper84_Init ) */ - INES_BOARD( "KONAMI VRC7", 85, Mapper85_Init ) - INES_BOARD( "JALECO JF-13", 86, Mapper86_Init ) - INES_BOARD( "74*139/74 DISCRETE", 87, Mapper87_Init ) - INES_BOARD( "NAMCO 3433", 88, Mapper88_Init ) - INES_BOARD( "SUNSOFT-3", 89, Mapper89_Init ) /* SUNSOFT-2 mapper */ - INES_BOARD( "HUMMER/JY BOARD", 90, Mapper90_Init ) - INES_BOARD( "EARLY HUMMER/JY BOARD", 91, Mapper91_Init ) - INES_BOARD( "JALECO JF-19", 92, Mapper92_Init ) - INES_BOARD( "SUNSOFT-3R", 93, SUNSOFT_UNROM_Init ) /* SUNSOFT-2 mapper with VRAM, different wiring */ - INES_BOARD( "HVC-UN1ROM", 94, Mapper94_Init ) - INES_BOARD( "NAMCOT 108 Rev. B", 95, Mapper95_Init ) - INES_BOARD( "BANDAI OEKAKIDS", 96, Mapper96_Init ) - INES_BOARD( "IREM TAM-S1", 97, Mapper97_Init ) + INES_BOARD( "KONAMI VRC7", 85, Mapper085_Init ) + INES_BOARD( "JALECO JF-13", 86, Mapper086_Init ) + INES_BOARD( "74*139/74 DISCRETE", 87, Mapper087_Init ) + INES_BOARD( "NAMCO 3433", 88, Mapper088_Init ) + INES_BOARD( "SUNSOFT-3", 89, Mapper089_Init ) /* SUNSOFT-2 mapper */ + INES_BOARD( "HUMMER/JY BOARD", 90, Mapper090_Init ) + INES_BOARD( "JY830623C/YY840238C/EJ-006-1", 91, Mapper091_Init ) + INES_BOARD( "JALECO JF-19", 92, Mapper072_Init ) + INES_BOARD( "SUNSOFT-3R", 93, Mapper093_Init ) /* SUNSOFT-2 mapper with VRAM, different wiring */ + INES_BOARD( "HVC-UN1ROM", 94, Mapper094_Init ) + INES_BOARD( "NAMCOT 108 Rev. B", 95, Mapper095_Init ) + INES_BOARD( "BANDAI OEKAKIDS", 96, Mapper096_Init ) + INES_BOARD( "IREM TAM-S1", 97, Mapper097_Init ) /* INES_BOARD( "", 98, Mapper98_Init ) */ - INES_BOARD( "VS Uni/Dual- system", 99, Mapper99_Init ) + INES_BOARD( "Vs. System", 99, Mapper099_Init ) /* INES_BOARD( "", 100, Mapper100_Init ) */ INES_BOARD( "", 101, Mapper101_Init ) /* INES_BOARD( "", 102, Mapper102_Init ) */ @@ -542,16 +668,16 @@ INES_BOARD_BEGIN() INES_BOARD( "HACKER/SACHEN BOARD", 113, Mapper113_Init ) INES_BOARD( "MMC3 SG PROT. A", 114, Mapper114_Init ) INES_BOARD( "MMC3 PIRATE A", 115, Mapper115_Init ) - INES_BOARD( "MMC1/MMC3/VRC PIRATE", 116, UNLSL12_Init ) + INES_BOARD( "MMC1/MMC3/VRC PIRATE", 116, Mapper116_Init ) INES_BOARD( "FUTURE MEDIA BOARD", 117, Mapper117_Init ) - INES_BOARD( "TSKROM", 118, TKSROM_Init ) - INES_BOARD( "NES-TQROM", 119, Mapper119_Init ) + INES_BOARD( "TSKROM", 118, Mapper118_Init ) + INES_BOARD( "TQROM", 119, Mapper119_Init ) INES_BOARD( "FDS TOBIDASE", 120, Mapper120_Init ) INES_BOARD( "MMC3 PIRATE PROT. A", 121, Mapper121_Init ) /* INES_BOARD( "", 122, Mapper122_Init ) */ - INES_BOARD( "MMC3 PIRATE H2288", 123, UNLH2288_Init ) -/* INES_BOARD( "", 124, Mapper124_Init ) */ - INES_BOARD( "FDS LH32", 125, LH32_Init ) + INES_BOARD( "MMC3 PIRATE H2288", 123, Mapper123_Init ) + INES_BOARD( "Super Game Mega Type III", 124, Mapper124_Init ) + INES_BOARD( "FDS LH32", 125, Mapper125_Init ) INES_BOARD( "PowerJoy 84-in-1 PJ-008", 126, Mapper126_Init ) INES_BOARD( "Double Dragon II (Pirate)", 127, Mapper127_Init ) INES_BOARD( "1994 Super HiK 4-in-1", 128, Mapper128_Init ) @@ -559,34 +685,34 @@ INES_BOARD_BEGIN() /* INES_BOARD( "", 130, Mapper130_Init ) */ /* INES_BOARD( "", 131, Mapper131_Init ) */ INES_BOARD( "TXC/UNL-22211", 132, Mapper132_Init ) - INES_BOARD( "SA72008", 133, SA72008_Init ) + INES_BOARD( "SA72008", 133, Mapper133_Init ) INES_BOARD( "MMC3 BMC PIRATE", 134, Mapper134_Init ) -/* INES_BOARD( "", 135, Mapper135_Init ) */ +/* INES_BOARD( "", 135, Mapper135_Init ) */ /* Duplicate of 135 */ INES_BOARD( "Sachen 3011", 136, Mapper136_Init ) - INES_BOARD( "S8259D", 137, S8259D_Init ) - INES_BOARD( "S8259B", 138, S8259B_Init ) - INES_BOARD( "S8259C", 139, S8259C_Init ) + INES_BOARD( "S8259D", 137, Mapper137_Init ) + INES_BOARD( "S8259B", 138, Mapper138_Init ) + INES_BOARD( "S8259C", 139, Mapper139_Init ) INES_BOARD( "JALECO JF-11/14", 140, Mapper140_Init ) - INES_BOARD( "S8259A", 141, S8259A_Init ) - INES_BOARD( "UNLKS7032", 142, UNLKS7032_Init ) - INES_BOARD( "TCA01", 143, TCA01_Init ) + INES_BOARD( "S8259A", 141, Mapper141_Init ) + INES_BOARD( "UNLKS7032", 142, Mapper142_Init ) + INES_BOARD( "TCA01", 143, Mapper143_Init ) INES_BOARD( "AGCI 50282", 144, Mapper144_Init ) - INES_BOARD( "SA72007", 145, SA72007_Init ) + INES_BOARD( "SA72007", 145, Mapper145_Init ) /* INES_BOARD( "", 146, SA0161M_Init ) */ /* moved to mapper 79 */ INES_BOARD( "Sachen 3018 board", 147, Mapper147_Init ) - INES_BOARD( "SA0037", 148, SA0037_Init ) - INES_BOARD( "SA0036", 149, SA0036_Init ) - INES_BOARD( "SA-015/SA-630", 150, S74LS374N_Init ) - INES_BOARD( "", 151, Mapper151_Init ) + INES_BOARD( "SA0037", 148, Mapper148_Init ) + INES_BOARD( "SA0036", 149, Mapper149_Init ) + INES_BOARD( "SA-015/SA-630", 150, Mapper150_Init ) + INES_BOARD( "Vs. Unisystem (Konami)", 151, Mapper151_Init ) /* legacy support. all fixed roms should be using mapper 75 */ INES_BOARD( "", 152, Mapper152_Init ) INES_BOARD( "BANDAI SRAM", 153, Mapper153_Init ) /* Bandai board 16 with SRAM instead of EEPROM */ INES_BOARD( "", 154, Mapper154_Init ) INES_BOARD( "", 155, Mapper155_Init ) INES_BOARD( "", 156, Mapper156_Init ) INES_BOARD( "BANDAI BARCODE", 157, Mapper157_Init ) - INES_BOARD( "TENGEN 800037", 158, Mapper158_Init ) + INES_BOARD( "TENGEN 800037", 158, Mapper064_Init ) INES_BOARD( "BANDAI 24C01", 159, Mapper159_Init ) /* Different type of EEPROM on the bandai board */ - INES_BOARD( "SA009", 160, SA009_Init ) +/* INES_BOARD( "SA009", 160, Mapper160_Init ) */ /* INES_BOARD( "", 161, Mapper161_Init ) */ INES_BOARD( "", 162, Mapper162_Init ) INES_BOARD( "", 163, Mapper163_Init ) @@ -639,15 +765,15 @@ INES_BOARD_BEGIN() INES_BOARD( "", 210, Mapper210_Init ) INES_BOARD( "HUMMER/JY BOARD", 211, Mapper211_Init ) INES_BOARD( "", 212, Mapper212_Init ) - INES_BOARD( "", 213, Mapper58_Init ) /* in mapper 58 */ + INES_BOARD( "", 213, Mapper058_Init ) /* in mapper 58 */ INES_BOARD( "", 214, Mapper214_Init ) - INES_BOARD( "UNL-8237", 215, UNL8237_Init ) + INES_BOARD( "UNL-8237", 215, Mapper215_Init ) INES_BOARD( "Bonza", 216, Mapper216_Init ) INES_BOARD( "", 217, Mapper217_Init ) /* Redefined to a new Discrete BMC mapper */ INES_BOARD( "Magic Floor", 218, Mapper218_Init ) - INES_BOARD( "UNLA9746", 219, UNLA9746_Init ) + INES_BOARD( "A9746", 219, Mapper219_Init ) /* INES_BOARD( "Debug Mapper", 220, Mapper220_Init ) */ - INES_BOARD( "UNLN625092", 221, UNLN625092_Init ) + INES_BOARD( "UNLN625092", 221, Mapper221_Init ) INES_BOARD( "", 222, Mapper222_Init ) /* INES_BOARD( "", 223, Mapper223_Init ) */ INES_BOARD( "KT-008", 224, MINDKIDS_Init ) /* The KT-008 board contains the MINDKIDS chipset */ @@ -657,19 +783,19 @@ INES_BOARD_BEGIN() INES_BOARD( "", 228, Mapper228_Init ) INES_BOARD( "", 229, Mapper229_Init ) INES_BOARD( "BMC Contra+22-in-1", 230, Mapper230_Init ) - INES_BOARD( "", 231, Mapper231_Init ) + INES_BOARD( "20-in-1", 231, Mapper231_Init ) INES_BOARD( "BMC QUATTRO", 232, Mapper232_Init ) INES_BOARD( "BMC 22+20-in-1 RST", 233, Mapper233_Init ) INES_BOARD( "BMC MAXI", 234, Mapper234_Init ) INES_BOARD( "Golden Game", 235, Mapper235_Init ) - INES_BOARD( "Realtec 8031/8155/8099/8106", 236, Mapper236_Init ) + INES_BOARD( "Realtec 8031/8155/8099/8106", 236, Mapper236_Init ) INES_BOARD( "Teletubbies / Y2K", 237, Mapper237_Init ) - INES_BOARD( "UNL6035052", 238, UNL6035052_Init ) + INES_BOARD( "UNL6035052", 238, Mapper238_Init ) /* INES_BOARD( "", 239, Mapper239_Init ) */ INES_BOARD( "", 240, Mapper240_Init ) INES_BOARD( "BxROM+WRAM", 241, Mapper241_Init ) INES_BOARD( "43272", 242, Mapper242_Init ) - INES_BOARD( "SA-020A", 243, S74LS374N_Init ) + INES_BOARD( "SA-020A", 243, Mapper150_Init ) INES_BOARD( "DECATHLON", 244, Mapper244_Init ) INES_BOARD( "", 245, Mapper245_Init ) INES_BOARD( "FONG SHEN BANG", 246, Mapper246_Init ) @@ -679,97 +805,97 @@ INES_BOARD_BEGIN() INES_BOARD( "", 250, Mapper250_Init ) /* INES_BOARD( "", 251, Mapper251_Init ) */ /* No good dumps for this mapper, use UNIF version */ INES_BOARD( "SAN GUO ZHI PIRATE", 252, Mapper252_Init ) - INES_BOARD( "DRAGON BALL PIRATE", 253, Mapper253_Init ) + INES_BOARD( "DRAGON BALL PIRATE", 253, Mapper252_Init ) INES_BOARD( "", 254, Mapper254_Init ) INES_BOARD( "", 255, Mapper255_Init ) /* Duplicate of M225? */ /* NES 2.0 MAPPERS */ - INES_BOARD( "OneBus", 256, UNLOneBus_Init ) - INES_BOARD( "158B", 258, UNL8237_Init ) - INES_BOARD( "F-15", 259, BMCF15_Init ) - INES_BOARD( "HPxx / HP2018-A", 260, BMCHPxx_Init ) - INES_BOARD( "810544-C-A1", 261, BMC810544CA1_Init ) - INES_BOARD( "SHERO", 262, UNLSHeroes_Init ) - INES_BOARD( "KOF97", 263, UNLKOF97_Init ) - INES_BOARD( "YOKO", 264, UNLYOKO_Init ) - INES_BOARD( "T-262", 265, BMCT262_Init ) - INES_BOARD( "CITYFIGHT", 266, UNLCITYFIGHT_Init ) + INES_BOARD( "OneBus", 256, Mapper256_Init ) + INES_BOARD( "158B", 258, Mapper215_Init ) + INES_BOARD( "F-15", 259, Mapper259_Init ) + INES_BOARD( "HPxx / HP2018-A", 260, Mapper260_Init ) + INES_BOARD( "810544-C-A1", 261, Mapper261_Init ) + INES_BOARD( "SHERO", 262, Mapper262_Init ) + INES_BOARD( "KOF97", 263, Mapper263_Init ) + INES_BOARD( "YOKO", 264, Mapper264_Init ) + INES_BOARD( "T-262", 265, Mapper265_Init ) + INES_BOARD( "CITYFIGHT", 266, Mapper266_Init ) INES_BOARD( "8-in-1 JY-119", 267, Mapper267_Init ) INES_BOARD( "COOLBOY/MINDKIDS", 268, Mapper268_Init ) /* Submapper distinguishes between COOLBOY and MINDKIDS */ INES_BOARD( "Games Xplosion 121-in-1", 269, Mapper269_Init ) INES_BOARD( "MGC-026", 271, Mapper271_Init ) - INES_BOARD( "Akumajō Special: Boku Dracula-kun", 272, Mapper272_Init ) - INES_BOARD( "80013-B", 274, BMC80013B_Init ) + INES_BOARD( "Akumajō Special: Boku Dracula-kun", 272, Mapper272_Init ) + INES_BOARD( "80013-B", 274, Mapper274_Init ) INES_BOARD( "", 277, Mapper277_Init ) INES_BOARD( "YY860417C", 281, Mapper281_Init ) INES_BOARD( "860224C", 282, Mapper282_Init ) INES_BOARD( "GS-2004/GS-2013", 283, Mapper283_Init ) - INES_BOARD( "A65AS", 285, BMCA65AS_Init ) - INES_BOARD( "BS-5", 286, BMCBS5_Init ) - INES_BOARD( "411120-C, 811120-C", 287, BMC411120C_Init ) + INES_BOARD( "A65AS", 285, Mapper285_Init ) + INES_BOARD( "BS-5", 286, Mapper286_Init ) + INES_BOARD( "411120-C, 811120-C", 287, Mapper287_Init ) INES_BOARD( "GKCX1", 288, Mapper288_Init ) - INES_BOARD( "60311C", 289, BMC60311C_Init ) - INES_BOARD( "NTD-03", 290, BMCNTD03_Init ) + INES_BOARD( "60311C", 289, Mapper289_Init ) + INES_BOARD( "NTD-03", 290, Mapper290_Init ) INES_BOARD( "Kasheng 2-in-1 ", 291, Mapper291_Init ) - INES_BOARD( "DRAGONFIGHTER", 292, UNLBMW8544_Init ) + INES_BOARD( "BMW8544", 292, Mapper292_Init ) INES_BOARD( "NewStar 12-in-1/7-in-1", 293, Mapper293_Init ) INES_BOARD( "63-1601 ", 294, Mapper294_Init ) INES_BOARD( "YY860216C", 295, Mapper295_Init ) INES_BOARD( "TXC 01-22110-000", 297, Mapper297_Init ) - INES_BOARD( "TF1201", 298, UNLTF1201_Init ) - INES_BOARD( "11160", 299, BMC11160_Init ) - INES_BOARD( "190in1", 300, BMC190in1_Init ) - INES_BOARD( "8157", 301, UNL8157_Init ) - INES_BOARD( "KS7057", 302, UNLKS7057_Init ) - INES_BOARD( "KS7017", 303, UNLKS7017_Init ) - INES_BOARD( "SMB2J", 304, UNLSMB2J_Init ) - INES_BOARD( "KS7031", 305, UNLKS7031_Init ) - INES_BOARD( "KS7016", 306, UNLKS7016_Init ) - INES_BOARD( "KS7037", 307, UNLKS7037_Init ) - INES_BOARD( "TH2131-1", 308, UNLTH21311_Init ) - INES_BOARD( "LH51", 309, LH51_Init ) + INES_BOARD( "TF1201", 298, Mapper298_Init ) + INES_BOARD( "11160", 299, Mapper299_Init ) + INES_BOARD( "190in1", 300, Mapper300_Init ) + INES_BOARD( "8157", 301, Mapper301_Init ) + INES_BOARD( "KS7057", 302, Mapper302_Init ) + INES_BOARD( "KS7017", 303, Mapper303_Init ) + INES_BOARD( "SMB2J", 304, Mapper304_Init ) + INES_BOARD( "KS7031", 305, Mapper305_Init ) + INES_BOARD( "KS7016", 306, Mapper306_Init ) + INES_BOARD( "KS7037", 307, Mapper307_Init ) + INES_BOARD( "TH2131-1", 308, Mapper308_Init ) + INES_BOARD( "LH51", 309, Mapper309_Init ) INES_BOARD( "K-1053", 310, Mapper310_Init ) - INES_BOARD( "KS7013B", 312, UNLKS7013B_Init ) - INES_BOARD( "RESET-TXROM", 313, BMCRESETTXROM_Init ) - INES_BOARD( "64in1NoRepeat", 314, BMC64in1nr_Init ) - INES_BOARD( "830134C", 315, BMC830134C_Init ) + INES_BOARD( "KS7013B", 312, Mapper312_Init ) + INES_BOARD( "RESET-TXROM", 313, Mapper313_Init ) + INES_BOARD( "64in1NoRepeat", 314, Mapper314_Init ) + INES_BOARD( "830134C", 315, Mapper315_Init ) INES_BOARD( "HP898F", 319, Mapper319_Init ) - INES_BOARD( "830425C-4391T", 320, BMC830425C4391T_Init ) - INES_BOARD( "K-3033", 322, BMCK3033_Init ) - INES_BOARD( "FARID_SLROM_8-IN-1", 323, FARIDSLROM8IN1_Init ) - INES_BOARD( "FARID_UNROM_8-IN-1", 324, FARIDUNROM_Init ) - INES_BOARD( "MALISB", 325, UNLMaliSB_Init ) + INES_BOARD( "830425C-4391T", 320, Mapper320_Init ) + INES_BOARD( "K-3033", 322, Mapper322_Init ) + INES_BOARD( "FARID_SLROM_8-IN-1", 323, Mapper323_Init ) + INES_BOARD( "FARID_UNROM_8-IN-1", 324, Mapper324_Init ) + INES_BOARD( "MALISB", 325, Mapper325_Init ) INES_BOARD( "Contra/Gryzor", 326, Mapper326_Init ) - INES_BOARD( "10-24-C-A1", 327, BMC1024CA1_Init ) - INES_BOARD( "RT-01", 328, UNLRT01_Init ) - INES_BOARD( "EDU2000", 329, UNLEDU2000_Init ) + INES_BOARD( "10-24-C-A1", 327, Mapper327_Init ) + INES_BOARD( "RT-01", 328, Mapper328_Init ) + INES_BOARD( "EDU2000", 329, Mapper329_Init ) INES_BOARD( "Sangokushi II: Haō no Tairiku", 330, Mapper330_Init ) - INES_BOARD( "12-IN-1", 331, BMC12IN1_Init ) - INES_BOARD( "WS", 332, BMCWS_Init ) - INES_BOARD( "NEWSTAR-GRM070-8IN1", 333, BMC8IN1_Init ) - INES_BOARD( "5/20-in-1 1993 Copyright", 334, Mapper334_Init ) - INES_BOARD( "CTC-09", 335, BMCCTC09_Init ) - INES_BOARD( "K-3046", 336, BMCK3046_Init ) - INES_BOARD( "CTC-12IN1", 337, BMCCTC12IN1_Init ) - INES_BOARD( "SA005-A", 338, BMCSA005A_Init ) - INES_BOARD( "K-3006", 339, BMCK3006_Init ) - INES_BOARD( "K-3036", 340, BMCK3036_Init ) - INES_BOARD( "TJ-03", 341, BMCTJ03_Init ) + INES_BOARD( "12-IN-1", 331, Mapper331_Init ) + INES_BOARD( "WS", 332, Mapper332_Init ) + INES_BOARD( "NEWSTAR-GRM070-8IN1", 333, Mapper333_Init ) + INES_BOARD( "821202C", 334, Mapper334_Init ) + INES_BOARD( "CTC-09", 335, Mapper335_Init ) + INES_BOARD( "K-3046", 336, Mapper336_Init ) + INES_BOARD( "CTC-12IN1", 337, Mapper337_Init ) + INES_BOARD( "SA005-A", 338, Mapper338_Init ) + INES_BOARD( "K-3006", 339, Mapper339_Init ) + INES_BOARD( "K-3036", 340, Mapper340_Init ) + INES_BOARD( "TJ-03", 341, Mapper341_Init ) INES_BOARD( "COOLGIRL", 342, COOLGIRL_Init ) - INES_BOARD( "RESETNROM-XIN1", 343, BMCRESETNROMXIN1_Init ) - INES_BOARD( "GN-26", 344, BMCGN26_Init ) - INES_BOARD( "L6IN1", 345, BMCL6IN1_Init ) - INES_BOARD( "KS7012", 346, UNLKS7012_Init ) - INES_BOARD( "KS7030", 347, UNLKS7030_Init ) - INES_BOARD( "830118C", 348, BMC830118C_Init ) - INES_BOARD( "G-146", 349, BMCG146_Init ) - INES_BOARD( "891227", 350, BMC891227_Init ) + INES_BOARD( "RESETNROM-XIN1", 343, Mapper343_Init ) + INES_BOARD( "GN-26", 344, Mapper344_Init ) + INES_BOARD( "L6IN1", 345, Mapper345_Init ) + INES_BOARD( "KS7012", 346, Mapper346_Init ) + INES_BOARD( "KS7030", 347, Mapper347_Init ) + INES_BOARD( "830118C", 348, Mapper348_Init ) + INES_BOARD( "G-146", 349, Mapper349_Init ) + INES_BOARD( "891227", 350, Mapper350_Init ) INES_BOARD( "Techline XB", 351, Mapper351_Init ) - INES_BOARD( "KS106C", 352, BMCKS106C_Init ) + INES_BOARD( "KS106C", 352, Mapper352_Init ) INES_BOARD( "Super Mario Family", 353, Mapper353_Init ) INES_BOARD( "FAM250/810139C/810331C/SCHI-24", 354, Mapper354_Init ) - INES_BOARD( "3D-BLOCK", 355, UNL3DBlock_Init ) + INES_BOARD( "3D-BLOCK", 355, Mapper355_Init ) INES_BOARD( "7-in-1 Rockman (JY-208)", 356, Mapper356_Init ) INES_BOARD( "Bit Corp 4-in-1", 357, Mapper357_Init ) INES_BOARD( "YY860606C", 358, Mapper358_Init ) @@ -781,7 +907,7 @@ INES_BOARD_BEGIN() INES_BOARD( "GN-45", 366, Mapper366_Init ) INES_BOARD( "Yung-08", 368, Mapper368_Init ) INES_BOARD( "N49C-300", 369, Mapper369_Init ) - INES_BOARD( "Golden Mario Party II - Around the World 6-in-1", 370, Mapper370_Init ) + INES_BOARD( "Golden Mario Party II - Around the World 6-in-1", 370, Mapper370_Init ) INES_BOARD( "MMC3 PIRATE SFC-12", 372, Mapper372_Init ) INES_BOARD( "95/96 Super HiK 4-in-1", 374, Mapper374_Init ) INES_BOARD( "135-in-1", 375, Mapper375_Init ) @@ -804,6 +930,7 @@ INES_BOARD_BEGIN() INES_BOARD( "YY850437C", 396, Mapper396_Init ) INES_BOARD( "YY850439C", 397, Mapper397_Init ) INES_BOARD( "YY840820C", 398, Mapper398_Init ) + INES_BOARD( "Star Versus", 399, Mapper399_Init ) INES_BOARD( "8-BIT XMAS", 400, Mapper400_Init ) INES_BOARD( "BMC Super 19-in-1 (VIP19)",401, Mapper401_Init ) INES_BOARD( "J-2282", 402, Mapper402_Init ) @@ -814,10 +941,12 @@ INES_BOARD_BEGIN() INES_BOARD( "JY-302", 410, Mapper410_Init ) INES_BOARD( "A88S-1", 411, Mapper411_Init ) INES_BOARD( "Intellivision 10-in-1 PnP 2nd Ed.", 412, Mapper412_Init ) + INES_BOARD( "Super Russian Roulette", 413, Mapper413_Init ) INES_BOARD( "9999999-in-1", 414, Mapper414_Init ) INES_BOARD( "0353", 415, Mapper415_Init ) INES_BOARD( "4-in-1/N-32", 416, Mapper416_Init ) INES_BOARD( "", 417, Mapper417_Init ) + INES_BOARD( "820106-C/821007C/LH42", 418, Mapper418_Init ) INES_BOARD( "A971210", 420, Mapper420_Init ) INES_BOARD( "SC871115C", 421, Mapper421_Init ) INES_BOARD( "BS-400R/BS-4040", 422, Mapper422_Init ) @@ -837,6 +966,7 @@ INES_BOARD_BEGIN() INES_BOARD( "NC-3000M", 443, Mapper443_Init ) INES_BOARD( "NC-7000M/NC-8000M", 444, Mapper444_Init ) INES_BOARD( "DG574B", 445, Mapper445_Init ) + INES_BOARD( "SMD172B_FPGA", 446, Mapper446_Init ) INES_BOARD( "KL-06 multicart", 447, Mapper447_Init ) INES_BOARD( "830768C", 448, Mapper448_Init ) INES_BOARD( "Super Games King", 449, Mapper449_Init ) @@ -844,6 +974,7 @@ INES_BOARD_BEGIN() INES_BOARD( "Haratyler HP/MP", 451, Mapper451_Init ) INES_BOARD( "DS-9-27", 452, Mapper452_Init ) INES_BOARD( "Realtec 8042", 453, Mapper453_Init ) + INES_BOARD( "100-in-1", 454, Mapper454_Init ) INES_BOARD( "N625836", 455, Mapper455_Init ) INES_BOARD( "K6C3001A", 456, Mapper456_Init ) INES_BOARD( "810431C", 457, Mapper457_Init ) @@ -856,34 +987,38 @@ INES_BOARD_BEGIN() INES_BOARD( "ET-120", 465, Mapper465_Init ) INES_BOARD( "Keybyte Computer", 466, Mapper466_Init ) INES_BOARD( "47-2", 467, Mapper467_Init ) + INES_BOARD( "Impact Soft IM1", 471, Mapper471_Init ) INES_BOARD( "Yhc-000", 500, Mapper500_Init ) INES_BOARD( "Yhc-001", 501, Mapper501_Init ) INES_BOARD( "Yhc-002", 502, Mapper502_Init ) INES_BOARD( "", 512, Mapper512_Init ) - INES_BOARD( "SA-9602B", 513, SA9602B_Init ) + INES_BOARD( "SA-9602B", 513, Mapper513_Init ) + INES_BOARD( "Subor Karaoke", 514, Mapper514_Init ) INES_BOARD( "Brilliant Com Cocoma Pack", 516, Mapper516_Init ) - INES_BOARD( "DANCE2000", 518, UNLD2000_Init ) - INES_BOARD( "EH8813A", 519, UNLEH8813A_Init ) + INES_BOARD( "Kkachi-wa Nolae Chingu", 517, Mapper517_Init ) /* Korean Karaoke */ + INES_BOARD( "DANCE2000", 518, Mapper518_Init ) + INES_BOARD( "EH8813A", 519, Mapper519_Init ) INES_BOARD( "Datach DBZ/Yu Yu Hakusho", 520, Mapper520_Init ) - INES_BOARD( "DREAMTECH01", 521, DreamTech01_Init ) - INES_BOARD( "LH10", 522, LH10_Init ) + INES_BOARD( "DREAMTECH01", 521, Mapper521_Init ) + INES_BOARD( "LH10", 522, Mapper522_Init ) INES_BOARD( "Jncota KT-???", 523, Mapper523_Init ) - INES_BOARD( "900218", 524, BTL900218_Init ) - INES_BOARD( "KS7021A", 525, UNLKS7021A_Init ) - INES_BOARD( "BJ-56", 526, UNLBJ56_Init ) - INES_BOARD( "AX-40G", 527, UNLAX40G_Init ) + INES_BOARD( "900218", 524, Mapper524_Init ) + INES_BOARD( "KS7021A", 525, Mapper525_Init ) + INES_BOARD( "BJ-56", 526, Mapper526_Init ) + INES_BOARD( "AX-40G", 527, Mapper527_Init ) INES_BOARD( "831128C", 528, Mapper528_Init ) - INES_BOARD( "YY0807/J-2148/T-230", 529, UNLT230_Init ) - INES_BOARD( "AX5705", 530, UNLAX5705_Init ) + INES_BOARD( "YY0807/J-2148/T-230", 529, Mapper529_Init ) + INES_BOARD( "AX5705", 530, Mapper530_Init ) INES_BOARD( "Sachen 3014", 533, Mapper533_Init ) INES_BOARD( "NJ064", 534, Mapper534_Init ) - INES_BOARD( "LH53", 535, LH53_Init ) + INES_BOARD( "LH53", 535, Mapper535_Init ) INES_BOARD( "60-1064-16L (FDS)", 538, Mapper538_Init ) INES_BOARD( "Kid Ikarus (FDS)", 539, Mapper539_Init ) INES_BOARD( "82112C", 540, Mapper540_Init ) INES_BOARD( "LittleCom 160-in-1", 541, Mapper541_Init ) INES_BOARD( "5-in-1 (CH-501)", 543, Mapper543_Init ) INES_BOARD( "Waixing FS306", 544, Mapper544_Init ) + INES_BOARD( "KONAMI-QTAI", 547, Mapper547_Init ) INES_BOARD( "CTC-15", 548, Mapper548_Init ) INES_BOARD( "KS-701B (Kaiser FDS)", 549, Mapper549_Init ) INES_BOARD( "", 551, Mapper178_Init ) @@ -892,142 +1027,274 @@ INES_BOARD_BEGIN() INES_BOARD( "KS-7010", 554, Mapper554_Init ) INES_BOARD( "JY-215", 556, Mapper556_Init ) INES_BOARD( "JY820845C", 550, Mapper550_Init ) + INES_BOARD( "NES-EVENT2", 555, Mapper555_Init ) + INES_BOARD( "", 557, Mapper557_Init ) INES_BOARD( "YC-03-09", 558, Mapper558_Init ) INES_BOARD( "Subor 0102", 559, Mapper559_Init ) INES_BOARD_END() -static void iNES_read_header_info(void) { - ROM_size = head.ROM_size; - VROM_size = head.VROM_size; - iNESCart.mirror = (head.ROM_type & 8) ? 2 : (head.ROM_type & 1); - iNESCart.mirror2bits = ((head.ROM_type & 8) ? 2 : 0) | (head.ROM_type & 1); - iNESCart.battery = (head.ROM_type & 2) ? 1 : 0; - iNESCart.mapper = (head.ROM_type2 & 0xF0) | ((head.ROM_type & 0xF0) >> 4); - iNESCart.iNES2 = (head.ROM_type2 & 0x0C) == 0x08; - iNESCart.ConsoleType = head.ROM_type2 & 0x03; - - if (iNESCart.iNES2) { - iNESCart.mapper |= (((uint32)head.ROM_type3 << 8) & 0xF00); - iNESCart.submapper = (head.ROM_type3 >> 4) & 0x0F; - ROM_size |= ((head.upper_PRG_CHR_size >> 0) & 0xF) << 8; - VROM_size |= ((head.upper_PRG_CHR_size >> 4) & 0xF) << 8; - iNESCart.region = head.Region & 3; - - if (head.PRGRAM_size & 0x0F) - iNESCart.PRGRamSize = 64 << ((head.PRGRAM_size >> 0) & 0x0F); - if (head.PRGRAM_size & 0xF0) - iNESCart.PRGRamSaveSize = 64 << ((head.PRGRAM_size >> 4) & 0x0F); - if (head.CHRRAM_size & 0x0F) - iNESCart.CHRRamSize = 64 << ((head.CHRRAM_size >> 0) & 0x0F); - if (head.CHRRAM_size & 0xF0) - iNESCart.CHRRamSaveSize = 64 << ((head.CHRRAM_size >> 4) & 0x0F); - } -} +#define NES_HEADER_SIZE 16 +#define NES_TRAINER_SIZE 512 int iNESLoad(const char *name, FCEUFILE *fp) { - const char *tv_region[] = { "NTSC", "PAL", "Multi-region", "Dendy" }; + iNES_HEADER header; + struct md5_context md5; + uint64 partialmd5 = 0; + char *mappername = NULL; uint32 mappertest = 0; - uint64 filesize = FCEU_fgetsize(fp); /* size of file including header */ + + uint64 filesize = FCEU_fgetsize(fp) - NES_HEADER_SIZE; /* size of file excluding header */ uint64 romSize = 0; /* size of PRG + CHR rom */ - /* used for malloc and cart mapping */ - uint32 rom_size_pow2 = 0; - uint32 vrom_size_pow2 = 0; - if (FCEU_fread(&head, 1, 16, fp) != 16) + int x; + + if (FCEU_fread(&header, 1, 16, fp) != 16) return 0; - if (memcmp(&head, "NES\x1a", 4)) { + if (memcmp(&header, "NES\x1a", 4)) { FCEU_PrintError("Not an iNES file!\n"); return 0; } memset(&iNESCart, 0, sizeof(iNESCart)); + memset(&vsuni_system, 0, sizeof(vsuni_system)); + + if (!memcmp((char *)(&header) + 0x7, "DiskDude", 8)) { + memset((char *)(&header) + 0x7, 0, 0x9); + } else if (!memcmp((char *)(&header) + 0x7, "demiforce", 9)) { + memset((char *)(&header) + 0x7, 0, 0x9); + } else if (!memcmp((char *)(&header) + 0xA, "Ni03", 4)) { + memset((char *)(&header) + 0x7, 0, 0x9); + } - if (!memcmp((char *)(&head) + 0x7, "DiskDude", 8)) { - memset((char *)(&head) + 0x7, 0, 0x9); - } else if (!memcmp((char *)(&head) + 0x7, "demiforce", 9)) { - memset((char *)(&head) + 0x7, 0, 0x9); - } else if (!memcmp((char *)(&head) + 0xA, "Ni03", 4)) { - memset((char *)(&head) + 0x7, 0, 0x9); + iNESCart.iNES2 = (header.ROM_type2 & 0x0C) == 0x08; + ROM.prg.size = header.ROM_size; + ROM.chr.size = header.VROM_size; + iNESCart.PRGRomSize = ROM.prg.size * 0x4000; + iNESCart.CHRRomSize = ROM.chr.size * 0x2000; + iNESCart.mapper = (header.ROM_type2 & 0xF0) | (header.ROM_type >> 4); + if (header.ROM_type & 8) { + iNESCart.mirror = MI_4; + } else if (header.ROM_type & 1) { + iNESCart.mirror = MI_V; + } else { + iNESCart.mirror = MI_H; } + /* special mirroring case for mapper 30/218 */ + iNESCart.mirror2bits = ((header.ROM_type & 0x08) ? 2 : 0) | (header.ROM_type & 1); + iNESCart.battery = (header.ROM_type & 0x02) != 0; + iNESCart.trainer = (header.ROM_type & 0x04) != 0; + iNESCart.ConsoleType = header.ROM_type2 & 0x03; + if (iNESCart.iNES2) { + uint8 value; + + iNESCart.mapper |= ((header.ROM_type3 & 0x0F) << 8); + iNESCart.submapper = (header.ROM_type3 >> 4); + + value = (header.upper_PRG_CHR_size >> 0) & 0x0F; + if (value < 0x0F) { + ROM.prg.size |= (value << 8); + iNESCart.PRGRomSize = ROM.prg.size * 0x4000; + } else { + iNESCart.PRGRomSize = pow(2, header.ROM_size >> 2) * ((header.ROM_size & 0x03) * 2 + 1); + ROM.prg.size = (iNESCart.PRGRomSize / 0x4000) + ((iNESCart.PRGRomSize % 0x4000) ? 1 : 0); + } - iNES_read_header_info(); + value = (header.upper_PRG_CHR_size >> 4) & 0x0F; + if (value < 0x0F) { + ROM.chr.size |= (value << 8); + iNESCart.CHRRomSize = ROM.chr.size * 0x2000; + } else { + iNESCart.CHRRomSize = pow(2, header.VROM_size >> 2) * ((header.VROM_size & 0x03) * 2 + 1); + ROM.chr.size = (iNESCart.CHRRomSize / 0x2000) + ((iNESCart.CHRRomSize % 0x2000) ? 1 : 0); + } - if (!ROM_size) - ROM_size = 256; + value = (header.PRGRAM_size >> 0) & 0x0F; + if (value) { + iNESCart.PRGRamSize = 64 << value; + } - filesize -= 16; /* remove header size from total size */ + value = (header.PRGRAM_size >> 4) & 0x0F; + if (value) { + iNESCart.PRGRamSaveSize = 64 << value; + } - /* Trainer */ - if (head.ROM_type & 4) { - trainerpoo = (uint8 *)FCEU_gmalloc(512); - FCEU_fread(trainerpoo, 512, 1, fp); - filesize -= 512; + value = (header.CHRRAM_size >> 0) & 0x0F; + if (value) { + iNESCart.CHRRamSize = 64 << value; + } + + value = (header.CHRRAM_size >> 4) & 0x0F; + if (value) { + iNESCart.CHRRamSaveSize = 64 << value; + } + if ((header.PRGRAM_size & 0xF0) && !(header.ROM_type & 0x02)) { + /* set battery bit in header when upper nibble of PRG RAM is non zero */ + header.ROM_type |= 0x02; + iNESCart.battery = true; + } + if (header.Region == 3) { + iNESCart.region = DENDY; + } else if (header.Region == 1) { + iNESCart.region = NES_PAL; + } else { + /* 0: Nes Ntsc, 1: Nes Pal */ + iNESCart.region = NES_NTSC; + } + if (iNESCart.ConsoleType == 3) { + iNESCart.ConsoleType = header.VS_hardware & 0x0F; + } else if (iNESCart.ConsoleType == 1) { + iNESCart.VS_PPUTypes = header.VS_hardware & 0x0F; + iNESCart.VS_HWType = header.VS_hardware >> 4; + } + iNESCart.MiscRoms = header.MiscRoms & 0x03; + iNESCart.InputTypes = header.ExpDevice; + } else { + iNESCart.region = header.upper_PRG_CHR_size & 1; + iNESCart.submapper = 0; + iNESCart.PRGRamSize = 0; + iNESCart.PRGRamSaveSize = 0; + iNESCart.CHRRamSize = 0; + iNESCart.CHRRamSaveSize = 0; + iNESCart.VS_PPUTypes = 0; + iNESCart.VS_HWType = 0; + iNESCart.MiscRoms = 0; + iNESCart.InputTypes = 0; + if (!ROM.prg.size) { + ROM.prg.size = 256; + iNESCart.PRGRomSize = ROM.prg.size * 0x4000; + } } - iNESCart.PRGRomSize = - ROM_size >= 0xF00 ? (pow(2, head.ROM_size >> 2) * ((head.ROM_size & 3) * 2 + 1)) : (ROM_size * 0x4000); - iNESCart.CHRRomSize = - VROM_size >= 0xF00 ? (pow(2, head.VROM_size >> 2) * ((head.VROM_size & 3) * 2 + 1)) : (VROM_size * 0x2000); + /* Set Vs. System flag if need */ + switch (iNESCart.ConsoleType) { + case 0: /* standard NES/Dendy */ + case 2: /* Playchoice 10 */ + GameInfo->type = GIT_CART; + break; + case 1: + GameInfo->type = GIT_VSUNI; + break; + default: + FCEU_PrintError(" Game type 0x%02x is not supported. Trying as standard NES.\n", iNESCart.ConsoleType); + GameInfo->type = GIT_CART; + break; + } - romSize = iNESCart.PRGRomSize + iNESCart.CHRRomSize; + /* Set Vs. System PPU type if need */ + if (GameInfo->type == GIT_VSUNI) { + switch (iNESCart.VS_PPUTypes) { + case 0x0: vsuni_system.ppu = PPU_RC2C03; break; /* RP2C03B */ + case 0x1: vsuni_system.ppu = PPU_RC2C03; break; /* RP2C03G */ + case 0x2: vsuni_system.ppu = PPU_RP2C04_0001; break; + case 0x3: vsuni_system.ppu = PPU_RP2C04_0002; break; + case 0x4: vsuni_system.ppu = PPU_RP2C04_0003; break; + case 0x5: vsuni_system.ppu = PPU_RP2C04_0004; break; + case 0x6: vsuni_system.ppu = PPU_RC2C03; break; /* RC2C03B */ + case 0x7: vsuni_system.ppu = PPU_RC2C03; break; /* RC2C03C */ + case 0x8: vsuni_system.ppu = PPU_RC2C05_01; break; + case 0x9: vsuni_system.ppu = PPU_RC2C05_02; break; + case 0xA: vsuni_system.ppu = PPU_RC2C05_03; break; + case 0xB: vsuni_system.ppu = PPU_RC2C05_04; break; + case 0xC: vsuni_system.ppu = PPU_RC2C05_05; break; + default: + FCEU_PrintError(" Unknown VS System PPU type: 0x%02x\n.", iNESCart.VS_PPUTypes); + break; + } - if (romSize > filesize) { - FCEU_PrintError(" File length is too short to contain all data reported from header by %llu\n", - romSize - filesize); - } else if (romSize < filesize) - FCEU_PrintError(" File contains %llu bytes of unused data\n", filesize - romSize); + switch (iNESCart.VS_HWType) { + case 0x0: vsuni_system.type = VS_TYPE_NORMAL; break; + case 0x1: vsuni_system.type = VS_TYPE_RBI; break; + case 0x2: vsuni_system.type = VS_TYPE_TKO; break; + case 0x3: vsuni_system.type = VS_TYPE_XEVIOUS; break; + case 0x4: vsuni_system.type = VS_TYPE_ICECLIMBER; break; + } - rom_size_pow2 = uppow2(iNESCart.PRGRomSize); + switch (iNESCart.InputTypes) { + case 0x04: /* 1P connected to $4016 */ + break; + case 0x05: /* 1P connected to $4017 */ + vsuni_system.ioption = IOPTION_SWAPDIRAB; + break; + case 0x07: /* Famicom Zapper */ + vsuni_system.ioption = IOPTION_GUN; + break; + } + + if (vsuni_system.ioption & IOPTION_GUN) { + GameInfo->input[0] = SI_ZAPPER; + GameInfo->input[1] = SI_NONE; + } else { + GameInfo->input[0] = SI_GAMEPAD; + GameInfo->input[1] = SI_GAMEPAD; + } + } + + /* Trainer */ + if (iNESCart.trainer) { + ROM.trainer.size = NES_TRAINER_SIZE; + ROM.trainer.data = (uint8 *)FCEU_gmalloc(ROM.trainer.size); + FCEU_fread(ROM.trainer.data, ROM.trainer.size, 1, fp); + filesize -= ROM.trainer.size; + } + + romSize = iNESCart.PRGRomSize + iNESCart.CHRRomSize; + if (romSize > filesize) { + FCEU_PrintError( " File length is too short to contain all data reported from header by %llu\n", romSize - filesize); + } else if (romSize < filesize) { + if (!iNESCart.MiscRoms) { + /* in some rare cases where CHR page count is malformed and no , just recompute CHR data from remaining length */ + size_t newCHRSize = filesize - iNESCart.PRGRomSize; + FCEU_PrintError(" File contains %llu bytes of unused data.\n", filesize - romSize); + FCEU_PrintError(" CHRROM size is is adjusted for this unused data.\n"); + iNESCart.CHRRomSize = newCHRSize; + } + } - if ((ROM = (uint8 *)FCEU_malloc(rom_size_pow2)) == NULL) { + if (!(ROM.prg.data = (uint8 *)FCEU_malloc(uppow2(iNESCart.PRGRomSize)))) { Cleanup(); return 0; } - - memset(ROM, 0xFF, rom_size_pow2); - FCEU_fread(ROM, 1, iNESCart.PRGRomSize, fp); + memset(ROM.prg.data, 0xFF, uppow2(iNESCart.PRGRomSize)); + FCEU_fread(ROM.prg.data, 1, iNESCart.PRGRomSize, fp); if (iNESCart.CHRRomSize) { - vrom_size_pow2 = uppow2(iNESCart.CHRRomSize); - - if ((VROM = (uint8 *)FCEU_malloc(vrom_size_pow2)) == NULL) { + if (!(ROM.chr.data = (uint8 *)FCEU_malloc(uppow2(iNESCart.CHRRomSize)))) { Cleanup(); return 0; } - - memset(VROM, 0xFF, vrom_size_pow2); - FCEU_fread(VROM, 1, iNESCart.CHRRomSize, fp); + memset(ROM.chr.data, 0xFF, uppow2(iNESCart.CHRRomSize)); + FCEU_fread(ROM.chr.data, 1, iNESCart.CHRRomSize, fp); } - if (head.MiscRoms & 3) { - MiscROM_size = filesize - iNESCart.PRGRomSize - iNESCart.CHRRomSize; - - if ((MiscROM = (uint8 *)FCEU_malloc(MiscROM_size)) == NULL) { + if (iNESCart.MiscRoms) { + ROM.misc.size = filesize - romSize; + if (!(ROM.misc.data = (uint8 *)FCEU_malloc(ROM.misc.size))) { Cleanup(); return 0; } - - memset(MiscROM, 0xFF, MiscROM_size); - FCEU_fread(MiscROM, 1, MiscROM_size, fp); + memset(ROM.misc.data, 0xFF, ROM.misc.size); + FCEU_fread(ROM.misc.data, 1, ROM.misc.size, fp); } - iNESCart.PRGCRC32 = CalcCRC32(0, ROM, iNESCart.PRGRomSize); - iNESCart.CHRCRC32 = CalcCRC32(0, VROM, iNESCart.CHRRomSize); - iNESCart.CRC32 = CalcCRC32(iNESCart.PRGCRC32, VROM, iNESCart.CHRRomSize); + iNESCart.PRGCRC32 = CalcCRC32(0, ROM.prg.data, iNESCart.PRGRomSize); + iNESCart.CHRCRC32 = CalcCRC32(0, ROM.chr.data, iNESCart.CHRRomSize); + iNESCart.CRC32 = CalcCRC32(iNESCart.PRGCRC32, ROM.chr.data, iNESCart.CHRRomSize); md5_starts(&md5); - md5_update(&md5, ROM, iNESCart.PRGRomSize); - if (iNESCart.CHRRomSize) - md5_update(&md5, VROM, iNESCart.CHRRomSize); + md5_update(&md5, ROM.prg.data, iNESCart.PRGRomSize); + if (iNESCart.CHRRomSize) { + md5_update(&md5, ROM.chr.data, iNESCart.CHRRomSize); + } md5_finish(&md5, iNESCart.MD5); - memcpy(&GameInfo->MD5, &iNESCart.MD5, sizeof(iNESCart.MD5)); + for (x = 0; x < 8; x++) { + partialmd5 |= (uint64)iNESCart.MD5[7 - x] << (x * 8); + } mappername = "Not Listed"; - for (mappertest = 0; mappertest < (sizeof bmap / sizeof bmap[0]) - 1; mappertest++) { if (bmap[mappertest].number == iNESCart.mapper) { mappername = (char *)bmap[mappertest].name; @@ -1035,122 +1302,102 @@ int iNESLoad(const char *name, FCEUFILE *fp) { } } - if (iNESCart.iNES2 == 0) { + if (!iNESCart.iNES2) { 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; + iNESCart.region = NES_PAL; } } + if (iNESCart.iNES2) FCEU_printf(" NES 2.0 extended iNES.\n"); FCEU_printf(" PRG-ROM CRC32: 0x%08X\n", iNESCart.PRGCRC32); if (iNESCart.PRGCRC32 != iNESCart.CRC32) { FCEU_printf(" PRG+CHR CRC32: 0x%08X\n", iNESCart.CRC32); } FCEU_printf(" PRG+CHR MD5: 0x%s\n", md5_asciistr(iNESCart.MD5)); - FCEU_printf(" PRG-ROM: %6d KiB\n", iNESCart.PRGRomSize >> 10); - FCEU_printf(" CHR-ROM: %6d KiB\n", iNESCart.CHRRomSize >> 10); - FCEU_printf(" Mapper #: %3d\n", iNESCart.mapper); + FCEU_printf(" PRG ROM: %-4d x 16 KiB = %-5d KiB\n", ROM.prg.size, iNESCart.PRGRomSize >> 10); + FCEU_printf(" CHR ROM: %-4d x 8 KiB = %-5d KiB\n", ROM.chr.size, iNESCart.CHRRomSize >> 10); + FCEU_printf(" Mapper #: %-6d\n", iNESCart.mapper); FCEU_printf(" Mapper name: %s\n", mappername); - FCEU_printf(" Mirroring: %s\n", - iNESCart.mirror == 2 ? "None (Four-screen)" : - iNESCart.mirror ? "Vertical" : "Horizontal"); - FCEU_printf(" Battery: %s\n", (head.ROM_type & 2) ? "Yes" : "No"); - FCEU_printf(" System: %s\n", tv_region[iNESCart.region]); - FCEU_printf(" Trained: %s\n", (head.ROM_type & 4) ? "Yes" : "No"); - + FCEU_printf(" Mirroring: %s\n", mirroring_str[iNESCart.mirror]); + FCEU_printf(" Trainer: %s\n", iNESCart.trainer ? "Yes" : "No"); + FCEU_printf(" Battery: %s\n", iNESCart.battery ? "Yes" : "No"); + FCEU_printf(" System: %s\n", tv_region_str[iNESCart.region]); + FCEU_printf(" Console: %s\n", console_types_str[iNESCart.ConsoleType & 0x0F].name); if (iNESCart.iNES2) { - unsigned PRGRAM = iNESCart.PRGRamSize + iNESCart.PRGRamSaveSize; - unsigned CHRRAM = iNESCart.CHRRamSize + iNESCart.CHRRamSaveSize; - - FCEU_printf(" NES 2.0 extended iNES.\n"); + size_t PRGRAM = iNESCart.PRGRamSize + iNESCart.PRGRamSaveSize; + size_t CHRRAM = iNESCart.CHRRamSize + iNESCart.CHRRamSaveSize; + if (iNESCart.InputTypes) { + FCEU_printf(" Input: %s\n", input_type_str[iNESCart.InputTypes].name); + } FCEU_printf(" Submapper: %2d\n", iNESCart.submapper); if (PRGRAM || CHRRAM) { - if (head.ROM_type & 0x02) { - FCEU_printf(" PRG-RAM: %2d KB ( %2d KB battery-backed)\n", PRGRAM / 1024, iNESCart.PRGRamSaveSize / 1024); - FCEU_printf(" CHR-RAM: %2d KB ( %2d KB battery-backed)\n", CHRRAM / 1024, iNESCart.CHRRamSaveSize / 1024); + if (iNESCart.battery) { + FCEU_printf(" PRG RAM: %-3d KiB ( %2d KiB battery-backed)\n", PRGRAM / 1024, iNESCart.PRGRamSaveSize / 1024); + FCEU_printf(" CHR RAM: %-3d KiB ( %2d KiB battery-backed)\n", CHRRAM / 1024, iNESCart.CHRRamSaveSize / 1024); } else { - FCEU_printf(" PRG-RAM: %2d KB\n", PRGRAM / 1024); - FCEU_printf(" CHR-RAM: %2d KB\n", CHRRAM / 1024); + FCEU_printf(" PRG RAM: %-3d KiB\n", PRGRAM / 1024); + FCEU_printf(" CHR RAM: %-3d KiB\n", CHRRAM / 1024); } } - if (MiscROM_size) { - FCEU_printf(" MISC-ROM: %6d KiB\n", MiscROM_size >> 10); + if (ROM.misc.size) { + FCEU_printf(" MISC-ROM: %-6d KiB\n", ROM.misc.size >> 10); } } + if (iNESCart.VS_HWType >= 5) { + FCEUD_DispMessage(RETRO_LOG_ERROR, 2000, "Vs. Dual System is unsupported.\n"); + FCEU_PrintError( " Vs. Dual System is unsupported.\n"); + } + if (iNESCart.ConsoleType > 0x02) { + FCEU_PrintError(" Unsupported type (%02x, \"%s\").\n", iNESCart.ConsoleType, console_types_str[iNESCart.ConsoleType & 0x0F].name); + } + ResetCartMapping(); ResetExState(0, 0); - SetupCartPRGMapping(0, ROM, rom_size_pow2, 0); + SetupCartPRGMapping(0, ROM.prg.data, uppow2(iNESCart.PRGRomSize), 0); - SetInput(); - - if (iNESCart.iNES2 < 1) - CheckHInfo(); - - { - int x; - uint64 partialmd5 = 0; - int mapper = iNESCart.mapper; - int mirroring = iNESCart.mirror; - - for (x = 0; x < 8; x++) - partialmd5 |= (uint64)iNESCart.MD5[7 - x] << (x * 8); - - FCEU_VSUniCheck(partialmd5, &mapper, &mirroring); - - if ((mapper != iNESCart.mapper) || (mirroring != iNESCart.mirror)) { - FCEU_PrintError("\n"); - FCEU_PrintError(" Incorrect VS-Unisystem header information!\n"); - if (mapper != iNESCart.mapper) - FCEU_PrintError(" Mapper: %d\n", mapper); - if (mirroring != iNESCart.mirror) - FCEU_PrintError(" Mirroring: %s\n", - (mirroring == 2) ? "None (Four-screen)" : - mirroring ? "Vertical" : - "Horizontal"); - iNESCart.mapper = mapper; - iNESCart.mirror = mirroring; - } - } + SetInput(&iNESCart); + if (iNESCart.iNES2) SetInputNes20(iNESCart.InputTypes); + CheckHInfo(&iNESCart, partialmd5); + FCEU_VSUniCheck(partialmd5, &iNESCart.mapper, &iNESCart.mirror); /* Must remain here because above functions might change value of - * VROM_size and free(VROM). + * ROM.chr.size and free(ROM.chr.data). */ - if (VROM_size) - SetupCartCHRMapping(0, VROM, vrom_size_pow2, 0); + if (iNESCart.CHRRomSize) { + SetupCartCHRMapping(0, ROM.chr.data, uppow2(iNESCart.CHRRomSize), 0); + } - if (iNESCart.mirror == 2) { + if (iNESCart.mirror == MI_4) { ExtraNTARAM = (uint8 *)FCEU_gmalloc(2048); - SetupCartMirroring(4, 1, ExtraNTARAM); - } else if (iNESCart.mirror >= 0x10) - SetupCartMirroring(2 + (iNESCart.mirror & 1), 1, 0); - else - SetupCartMirroring(iNESCart.mirror & 1, (iNESCart.mirror & 4) >> 2, 0); - - iNESCart.battery = (head.ROM_type & 2) ? 1 : 0; + SetupCartMirroring(iNESCart.mirror, TRUE, ExtraNTARAM); + } else { + SetupCartMirroring(iNESCart.mirror, (iNESCart.mirror & 2) ? TRUE : FALSE, NULL); + } if (!iNES_Init(iNESCart.mapper)) { - FCEU_printf("\n"); - FCEU_PrintError(" iNES mapper #%d is not supported at all.\n", iNESCart.mapper); + FCEU_PrintError(" iNES mapper #%d is not supported.\n", iNESCart.mapper); Cleanup(); return 0; } - GameInterface = iNESGI; - /* 0: RP2C02 ("NTSC NES") * 1: RP2C07 ("Licensed PAL NES") * 2: Multiple-region * 3: UMC 6527P ("Dendy") */ if (iNESCart.region == 3) - dendy = 1; + isDendy = TRUE; + FCEUI_SetVidSystem((iNESCart.region == 1) ? 1 : 0); + GameInterface = iNESGI; + return 1; } @@ -1165,11 +1412,12 @@ static int iNES_Init(int num) { while (tmp->init) { if (num == tmp->number) { UNIFchrrama = 0; /* need here for compatibility with UNIF mapper code */ - if (!VROM_size) { + if (!ROM.chr.size) { if (iNESCart.iNES2) { CHRRAMSize = iNESCart.CHRRamSize + iNESCart.CHRRamSaveSize; - if (CHRRAMSize == 0) - CHRRAMSize = iNESCart.CHRRamSize = 8 * 8192; + /* in NES 2.0 headered, its possible to have CHR ROM/RAM at zero */ + /* if (CHRRAMSize == 0) + CHRRAMSize = iNESCart.CHRRamSize = 8 * 8192; */ } else { switch (num) { /* FIXME, mapper or game data base with the board parameters and ROM/RAM sizes */ case 13: @@ -1181,15 +1429,12 @@ static int iNES_Init(int num) { case 30: case 45: case 96: - case 513: + case 111: CHRRAMSize = 32 * 1024; break; case 176: CHRRAMSize = 128 * 1024; break; - case 268: - CHRRAMSize = 256 * 1024; - break; default: CHRRAMSize = 8 * 1024; break; @@ -1198,16 +1443,16 @@ static int iNES_Init(int num) { } if (CHRRAMSize > 0) { /* 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) + if ((ROM.chr.data = (uint8 *)malloc(CHRRAMSize)) == NULL) { return 0; - FCEU_MemoryRand(VROM, CHRRAMSize); - UNIFchrrama = VROM; - SetupCartCHRMapping(0, VROM, CHRRAMSize, 1); - AddExState(VROM, CHRRAMSize, 0, "CHRR"); - /* FCEU_printf(" CHR-RAM: %3d KiB\n", CHRRAMSize / 1024); */ + } + FCEU_MemoryRand(ROM.chr.data, CHRRAMSize); + UNIFchrrama = ROM.chr.data; + SetupCartCHRMapping(0, ROM.chr.data, CHRRAMSize, 1); + AddExState(ROM.chr.data, CHRRAMSize, 0, "CHRR"); } } - if (head.ROM_type & 8) { + if (iNESCart.mirror == MI_4) { if (ExtraNTARAM != NULL) { AddExState(ExtraNTARAM, 2048, 0, "EXNR"); } diff --git a/src/ines.h b/src/ines.h index 0c80dbac9..2805c8cdb 100644 --- a/src/ines.h +++ b/src/ines.h @@ -23,116 +23,137 @@ #define _FCEU_INES_H typedef struct { - char ID[4]; /*NES^Z*/ - uint8 ROM_size; - uint8 VROM_size; - uint8 ROM_type; - uint8 ROM_type2; - uint8 ROM_type3; - uint8 upper_PRG_CHR_size; - uint8 PRGRAM_size; - uint8 CHRRAM_size; - uint8 Region; - uint8 VS_hardware; - uint8 MiscRoms; - uint8 ExpDevice; + char ID[4]; /* NES^Z */ + uint8 ROM_size; /* prg page count (16K) */ + uint8 VROM_size; /* chr page count (8K) */ + uint8 ROM_type; /* byte6 */ + uint8 ROM_type2; /* byte7 */ + uint8 ROM_type3; /* byte8 */ + uint8 upper_PRG_CHR_size; /* byte9 */ + uint8 PRGRAM_size; /* byte10 */ + uint8 CHRRAM_size; /* byte11 */ + uint8 Region; /* byte12 */ + uint8 VS_hardware; /* byte13 */ + uint8 MiscRoms; /* byte14 */ + uint8 ExpDevice; /* byte15 */ } iNES_HEADER; -extern uint8 *ROM; -extern uint8 *VROM; -extern uint32 ROM_size; /* prg size in 16K chunks */ -extern uint32 VROM_size; /* chr size in 8K chunks */ -extern iNES_HEADER head; +typedef struct romData_t { + struct prg { + uint8 *data; + uint32 size; /* prg 16k count */ + } prg; + struct chr { + uint8 *data; + uint32 size; /* chr 8k count */ + } chr; + struct trainer { + uint8 *data; + uint32 size; + } trainer; + struct misc { + uint8 *data; + uint32 size; + } misc; +} romData_t; -void NSFVRC6_Init(void); -void NSFMMC5_Init(void); -void NSFAY_Init(void); -void NSFN106_Init(void); -void NSFVRC7_Init(void); +extern romData_t ROM; -void Mapper1_Init(CartInfo *); -void Mapper4_Init(CartInfo *); -void Mapper5_Init(CartInfo *); -void Mapper6_Init(CartInfo *); -void Mapper8_Init(CartInfo *); -void Mapper9_Init(CartInfo *); -void Mapper10_Init(CartInfo *); -void Mapper11_Init(CartInfo *); -void Mapper12_Init(CartInfo *); -void Mapper15_Init(CartInfo *); -void Mapper16_Init(CartInfo *); -void Mapper17_Init(CartInfo *); -void Mapper18_Init(CartInfo *); -void Mapper19_Init(CartInfo *); -void Mapper21_Init(CartInfo *); -void Mapper22_Init(CartInfo *); -void Mapper23_Init(CartInfo *); -void Mapper24_Init(CartInfo *); -void Mapper25_Init(CartInfo *); -void Mapper26_Init(CartInfo *); -void Mapper28_Init(CartInfo *); -void Mapper29_Init(CartInfo *); -void Mapper31_Init(CartInfo *); -void Mapper32_Init(CartInfo *); -void Mapper33_Init(CartInfo *); -void Mapper34_Init(CartInfo *); -void Mapper35_Init(CartInfo *); -void Mapper36_Init(CartInfo *); -void Mapper37_Init(CartInfo *); -void Mapper38_Init(CartInfo *); -void Mapper40_Init(CartInfo *); -void Mapper41_Init(CartInfo *); -void Mapper42_Init(CartInfo *); -void Mapper43_Init(CartInfo *); -void Mapper44_Init(CartInfo *); -void Mapper45_Init(CartInfo *); -void Mapper46_Init(CartInfo *); -void Mapper47_Init(CartInfo *); -void Mapper48_Init(CartInfo *); -void Mapper49_Init(CartInfo *); -void Mapper50_Init(CartInfo *); -void Mapper51_Init(CartInfo *); -void Mapper52_Init(CartInfo *); -void Mapper57_Init(CartInfo *); -void Mapper58_Init(CartInfo *); -void Mapper59_Init(CartInfo *); -void Mapper60_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 *); -void Mapper68_Init(CartInfo *); -void Mapper69_Init(CartInfo *); -void Mapper70_Init(CartInfo *); -void Mapper71_Init(CartInfo *); -void Mapper72_Init(CartInfo *); -void Mapper73_Init(CartInfo *); -void Mapper74_Init(CartInfo *); -void Mapper75_Init(CartInfo *); -void Mapper76_Init(CartInfo *); -void Mapper77_Init(CartInfo *); -void Mapper78_Init(CartInfo *); -void Mapper79_Init(CartInfo *); -void Mapper80_Init(CartInfo *); -void Mapper81_Init(CartInfo *); -void Mapper82_Init(CartInfo *); -void Mapper83_Init(CartInfo *); -void Mapper85_Init(CartInfo *); -void Mapper86_Init(CartInfo *); -void Mapper87_Init(CartInfo *); -void Mapper88_Init(CartInfo *); -void Mapper89_Init(CartInfo *); -void Mapper90_Init(CartInfo *); -void Mapper91_Init(CartInfo *); -void Mapper92_Init(CartInfo *); -void Mapper93_Init(CartInfo *); -void Mapper94_Init(CartInfo *); -void Mapper95_Init(CartInfo *); -void Mapper96_Init(CartInfo *); -void Mapper97_Init(CartInfo *); -void Mapper99_Init(CartInfo *); +void Mapper000_Init(CartInfo *); +void Mapper001_Init(CartInfo *); +void Mapper002_Init(CartInfo *); +void Mapper003_Init(CartInfo *); +void Mapper004_Init(CartInfo *); +void Mapper005_Init(CartInfo *); +void Mapper006_Init(CartInfo *); +void Mapper007_Init(CartInfo *); +void Mapper008_Init(CartInfo *); +void Mapper009_Init(CartInfo *); +void Mapper010_Init(CartInfo *); +void Mapper011_Init(CartInfo *); +void Mapper012_Init(CartInfo *); +void Mapper013_Init(CartInfo *); +void Mapper014_Init(CartInfo *); +void Mapper015_Init(CartInfo *); +void Mapper016_Init(CartInfo *); +void Mapper017_Init(CartInfo *); +void Mapper018_Init(CartInfo *); +void Mapper019_Init(CartInfo *); +void Mapper021_Init(CartInfo *); +void Mapper022_Init(CartInfo *); +void Mapper023_Init(CartInfo *); +void Mapper024_Init(CartInfo *); +void Mapper025_Init(CartInfo *); +void Mapper026_Init(CartInfo *); +void Mapper027_Init(CartInfo *); +void Mapper028_Init(CartInfo *); +void Mapper029_Init(CartInfo *); +void Mapper030_Init(CartInfo *); +void Mapper031_Init(CartInfo *); +void Mapper032_Init(CartInfo *); +void Mapper033_Init(CartInfo *); +void Mapper034_Init(CartInfo *); +void Mapper035_Init(CartInfo *); +void Mapper036_Init(CartInfo *); +void Mapper037_Init(CartInfo *); +void Mapper038_Init(CartInfo *); +void Mapper040_Init(CartInfo *); +void Mapper041_Init(CartInfo *); +void Mapper042_Init(CartInfo *); +void Mapper043_Init(CartInfo *); +void Mapper044_Init(CartInfo *); +void Mapper045_Init(CartInfo *); +void Mapper046_Init(CartInfo *); +void Mapper047_Init(CartInfo *); +void Mapper048_Init(CartInfo *); +void Mapper049_Init(CartInfo *); +void Mapper050_Init(CartInfo *); +void Mapper051_Init(CartInfo *); +void Mapper052_Init(CartInfo *); +void Mapper053_Init(CartInfo *); +void Mapper055_Init(CartInfo *); +void Mapper056_Init(CartInfo *); +void Mapper057_Init(CartInfo *); +void Mapper058_Init(CartInfo *); +void Mapper059_Init(CartInfo *); +void Mapper060_Init(CartInfo *); +void Mapper061_Init(CartInfo *); +void Mapper062_Init(CartInfo *); +void Mapper063_Init(CartInfo *); +void Mapper064_Init(CartInfo *); +void Mapper065_Init(CartInfo *); +void Mapper066_Init(CartInfo *); +void Mapper067_Init(CartInfo *); +void Mapper068_Init(CartInfo *); +void Mapper069_Init(CartInfo *); +void Mapper070_Init(CartInfo *); +void Mapper071_Init(CartInfo *); +void Mapper072_Init(CartInfo *); +void Mapper073_Init(CartInfo *); +void Mapper074_Init(CartInfo *); +void Mapper075_Init(CartInfo *); +void Mapper076_Init(CartInfo *); +void Mapper077_Init(CartInfo *); +void Mapper078_Init(CartInfo *); +void Mapper079_Init(CartInfo *); +void Mapper080_Init(CartInfo *); +void Mapper081_Init(CartInfo *); +void Mapper082_Init(CartInfo *); +void Mapper083_Init(CartInfo *); +void Mapper085_Init(CartInfo *); +void Mapper086_Init(CartInfo *); +void Mapper087_Init(CartInfo *); +void Mapper088_Init(CartInfo *); +void Mapper089_Init(CartInfo *); +void Mapper090_Init(CartInfo *); +void Mapper091_Init(CartInfo *); +/* void Mapper092_Init(CartInfo *); */ +void Mapper093_Init(CartInfo *); +void Mapper094_Init(CartInfo *); +void Mapper095_Init(CartInfo *); +void Mapper096_Init(CartInfo *); +void Mapper097_Init(CartInfo *); +void Mapper099_Init(CartInfo *); void Mapper101_Init(CartInfo *); void Mapper103_Init(CartInfo *); void Mapper104_Init(CartInfo *); @@ -147,19 +168,33 @@ void Mapper114_Init(CartInfo *); void Mapper115_Init(CartInfo *); void Mapper116_Init(CartInfo *); void Mapper117_Init(CartInfo *); +void Mapper118_Init(CartInfo *); void Mapper119_Init(CartInfo *); void Mapper120_Init(CartInfo *); void Mapper121_Init(CartInfo *); +void Mapper123_Init(CartInfo *); +void Mapper124_Init(CartInfo *); void Mapper125_Init(CartInfo *); void Mapper126_Init(CartInfo *); void Mapper127_Init(CartInfo *); void Mapper128_Init(CartInfo *); void Mapper132_Init(CartInfo *); +void Mapper133_Init(CartInfo *); void Mapper134_Init(CartInfo *); void Mapper136_Init(CartInfo *); +void Mapper137_Init(CartInfo *); +void Mapper138_Init(CartInfo *); +void Mapper139_Init(CartInfo *); void Mapper140_Init(CartInfo *); +void Mapper141_Init(CartInfo *); +void Mapper142_Init(CartInfo *); +void Mapper143_Init(CartInfo *); void Mapper144_Init(CartInfo *); +void Mapper145_Init(CartInfo *); void Mapper147_Init(CartInfo *); +void Mapper148_Init(CartInfo *); +void Mapper149_Init(CartInfo *); +void Mapper150_Init(CartInfo *); void Mapper151_Init(CartInfo *); void Mapper152_Init(CartInfo *); void Mapper153_Init(CartInfo *); @@ -167,7 +202,6 @@ void Mapper154_Init(CartInfo *); void Mapper155_Init(CartInfo *); void Mapper156_Init(CartInfo *); void Mapper157_Init(CartInfo *); -void Mapper158_Init(CartInfo *); void Mapper159_Init(CartInfo *); void Mapper162_Init(CartInfo *); void Mapper163_Init(CartInfo *); @@ -186,7 +220,6 @@ void Mapper176_Init(CartInfo *); void Mapper177_Init(CartInfo *); void Mapper178_Init(CartInfo *); void Mapper180_Init(CartInfo *); -/* void Mapper181_Init(CartInfo *); */ void Mapper183_Init(CartInfo *); void Mapper184_Init(CartInfo *); void Mapper185_Init(CartInfo *); @@ -194,6 +227,7 @@ void Mapper186_Init(CartInfo *); void Mapper187_Init(CartInfo *); void Mapper188_Init(CartInfo *); void Mapper189_Init(CartInfo *); +void Mapper190_Init(CartInfo *); void Mapper191_Init(CartInfo *); void Mapper192_Init(CartInfo *); void Mapper193_Init(CartInfo *); @@ -218,10 +252,13 @@ void Mapper211_Init(CartInfo *); void Mapper212_Init(CartInfo *); void Mapper213_Init(CartInfo *); void Mapper214_Init(CartInfo *); +void Mapper215_Init(CartInfo *); void Mapper216_Init(CartInfo *); void Mapper217_Init(CartInfo *); void Mapper218_Init(CartInfo *); +void Mapper219_Init(CartInfo *); void Mapper220_Init(CartInfo *); +void Mapper221_Init(CartInfo *); void Mapper222_Init(CartInfo *); void Mapper224_Init(CartInfo *); void Mapper225_Init(CartInfo *); @@ -237,6 +274,7 @@ void Mapper234_Init(CartInfo *); void Mapper235_Init(CartInfo *); void Mapper236_Init(CartInfo *); void Mapper237_Init(CartInfo *); +void Mapper238_Init(CartInfo *); void Mapper240_Init(CartInfo *); void Mapper241_Init(CartInfo *); void Mapper242_Init(CartInfo *); @@ -249,30 +287,90 @@ void Mapper252_Init(CartInfo *); void Mapper253_Init(CartInfo *); void Mapper254_Init(CartInfo *); void Mapper255_Init(CartInfo *); - +void Mapper256_Init(CartInfo *); +void Mapper257_Init(CartInfo *); +void Mapper259_Init(CartInfo *); +void Mapper260_Init(CartInfo *); +void Mapper261_Init(CartInfo *); +void Mapper262_Init(CartInfo *); +void Mapper263_Init(CartInfo *); +void Mapper264_Init(CartInfo *); +void Mapper265_Init(CartInfo *); +void Mapper266_Init(CartInfo *); void Mapper267_Init(CartInfo *); void Mapper268_Init(CartInfo *); void Mapper269_Init(CartInfo *); void Mapper271_Init(CartInfo *); void Mapper272_Init(CartInfo *); +void Mapper274_Init(CartInfo *); void Mapper277_Init(CartInfo *); void Mapper281_Init(CartInfo *); void Mapper282_Init(CartInfo *); void Mapper283_Init(CartInfo *); +void Mapper285_Init(CartInfo *); +void Mapper286_Init(CartInfo *); +void Mapper287_Init(CartInfo *); void Mapper288_Init(CartInfo *); +void Mapper289_Init(CartInfo *); +void Mapper290_Init(CartInfo *); void Mapper291_Init(CartInfo *); +void Mapper292_Init(CartInfo *); void Mapper293_Init(CartInfo *); void Mapper294_Init(CartInfo *); void Mapper295_Init(CartInfo *); void Mapper297_Init(CartInfo *); +void Mapper298_Init(CartInfo *); +void Mapper299_Init(CartInfo *); +void Mapper300_Init(CartInfo *); +void Mapper301_Init(CartInfo *); +void Mapper302_Init(CartInfo *); +void Mapper303_Init(CartInfo *); +void Mapper304_Init(CartInfo *); +void Mapper305_Init(CartInfo *); +void Mapper306_Init(CartInfo *); +void Mapper307_Init(CartInfo *); +void Mapper308_Init(CartInfo *); +void Mapper309_Init(CartInfo *); void Mapper310_Init(CartInfo *); +void Mapper312_Init(CartInfo *); +void Mapper313_Init(CartInfo *); +void Mapper314_Init(CartInfo *); +void Mapper315_Init(CartInfo *); void Mapper319_Init(CartInfo *); +void Mapper320_Init(CartInfo *); +void Mapper322_Init(CartInfo *); +void Mapper323_Init(CartInfo *); +void Mapper324_Init(CartInfo *); +void Mapper325_Init(CartInfo *); void Mapper326_Init(CartInfo *); +void Mapper327_Init(CartInfo *); +void Mapper328_Init(CartInfo *); +void Mapper329_Init(CartInfo *); void Mapper330_Init(CartInfo *); +void Mapper331_Init(CartInfo *); +void Mapper332_Init(CartInfo *); +void Mapper333_Init(CartInfo *); void Mapper334_Init(CartInfo *); +void Mapper335_Init(CartInfo *); +void Mapper336_Init(CartInfo *); +void Mapper337_Init(CartInfo *); +void Mapper338_Init(CartInfo *); +void Mapper339_Init(CartInfo *); +void Mapper340_Init(CartInfo *); +void Mapper341_Init(CartInfo *); +void Mapper343_Init(CartInfo *); +void Mapper344_Init(CartInfo *); +void Mapper345_Init(CartInfo *); +void Mapper346_Init(CartInfo *); +void Mapper347_Init(CartInfo *); +void Mapper348_Init(CartInfo *); +void Mapper349_Init(CartInfo *); +void Mapper350_Init(CartInfo *); void Mapper351_Init(CartInfo *); +void Mapper352_Init(CartInfo *); void Mapper353_Init(CartInfo *); void Mapper354_Init(CartInfo *); +void Mapper355_Init(CartInfo *); void Mapper356_Init(CartInfo *); void Mapper357_Init(CartInfo *); void Mapper358_Init(CartInfo *); @@ -307,6 +405,7 @@ void Mapper395_Init(CartInfo *); void Mapper396_Init(CartInfo *); void Mapper397_Init(CartInfo *); void Mapper398_Init(CartInfo *); +void Mapper399_Init(CartInfo *); void Mapper400_Init(CartInfo *); void Mapper401_Init(CartInfo *); void Mapper402_Init(CartInfo *); @@ -317,10 +416,12 @@ void Mapper409_Init(CartInfo *); void Mapper410_Init(CartInfo *); void Mapper411_Init(CartInfo *); void Mapper412_Init(CartInfo *); +void Mapper413_Init(CartInfo *); void Mapper414_Init(CartInfo *); void Mapper415_Init(CartInfo *); void Mapper416_Init(CartInfo *); void Mapper417_Init(CartInfo *); +void Mapper418_Init(CartInfo *); void Mapper420_Init(CartInfo *); void Mapper421_Init(CartInfo *); void Mapper422_Init(CartInfo *); @@ -340,13 +441,15 @@ void Mapper441_Init(CartInfo *); void Mapper443_Init(CartInfo *); void Mapper444_Init(CartInfo *); void Mapper445_Init(CartInfo *); -void Mapper448_Init(CartInfo *); +void Mapper446_Init(CartInfo *); void Mapper447_Init(CartInfo *); +void Mapper448_Init(CartInfo *); void Mapper449_Init(CartInfo *); void Mapper450_Init(CartInfo *); void Mapper451_Init(CartInfo *); void Mapper452_Init(CartInfo *); void Mapper453_Init(CartInfo *); +void Mapper454_Init(CartInfo *); void Mapper455_Init(CartInfo *); void Mapper456_Init(CartInfo *); void Mapper457_Init(CartInfo *); @@ -359,30 +462,47 @@ void Mapper464_Init(CartInfo *); void Mapper465_Init(CartInfo *); void Mapper466_Init(CartInfo *); void Mapper467_Init(CartInfo *); +void Mapper471_Init(CartInfo *); void Mapper500_Init(CartInfo *); void Mapper501_Init(CartInfo *); void Mapper502_Init(CartInfo *); - void Mapper512_Init(CartInfo *); +void Mapper513_Init(CartInfo *); +void Mapper514_Init(CartInfo *); void Mapper516_Init(CartInfo *); +void Mapper517_Init(CartInfo *); +void Mapper518_Init(CartInfo *); +void Mapper519_Init(CartInfo *); void Mapper520_Init(CartInfo *); +void Mapper521_Init(CartInfo *); +void Mapper522_Init(CartInfo *); void Mapper523_Init(CartInfo *); +void Mapper524_Init(CartInfo *); +void Mapper525_Init(CartInfo *); +void Mapper526_Init(CartInfo *); +void Mapper527_Init(CartInfo *); void Mapper528_Init(CartInfo *); +void Mapper529_Init(CartInfo *); +void Mapper530_Init(CartInfo *); void Mapper533_Init(CartInfo *); void Mapper534_Init(CartInfo *); +void Mapper535_Init(CartInfo *); void Mapper538_Init(CartInfo *); void Mapper539_Init(CartInfo *); void Mapper540_Init(CartInfo *); void Mapper541_Init(CartInfo *); void Mapper543_Init(CartInfo *); void Mapper544_Init(CartInfo *); +void Mapper547_Init(CartInfo *); void Mapper548_Init(CartInfo *); void Mapper549_Init(CartInfo *); void Mapper550_Init(CartInfo *); void Mapper552_Init(CartInfo *); void Mapper553_Init(CartInfo *); void Mapper554_Init(CartInfo *); +void Mapper555_Init(CartInfo *); void Mapper556_Init(CartInfo *); +void Mapper557_Init(CartInfo *); void Mapper558_Init(CartInfo *); void Mapper559_Init(CartInfo *); diff --git a/src/input.c b/src/input.c index b3b4155c5..54403c2e7 100644 --- a/src/input.c +++ b/src/input.c @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - /* merged pad.c 2017-9-30 */ +/* merged pad.c 2017-9-30 */ #include @@ -29,10 +29,13 @@ #include "fceu.h" #include "state.h" +#include "cart.h" #include "input.h" #include "vsuni.h" #include "fds.h" +#include "input/zapper.h" + extern INPUTC *FCEU_InitZapper(int w); extern INPUTC *FCEU_InitMouse(int w); extern INPUTC *FCEU_InitPowerpadA(int w); @@ -55,473 +58,539 @@ extern INPUTCFC *FCEU_InitFamilyTrainerA(void); extern INPUTCFC *FCEU_InitFamilyTrainerB(void); extern INPUTCFC *FCEU_InitOekaKids(void); extern INPUTCFC *FCEU_InitTopRider(void); +extern INPUTCFC *FCEU_InitFamiNetSys(void); extern INPUTCFC *FCEU_InitBarcodeWorld(void); +typedef struct JOYPORT { + uint8 type; + uint8 attrib; + void *dataptr; + INPUTC *driver; +} JOYPORT; + +typedef struct PORTFC { + uint8 type; + uint8 attrib; + void *dataptr; + INPUTCFC *driver; +} PORTFC; + static uint8 joy_readbit[2]; static uint8 joy[4] = { 0, 0, 0, 0 }; static uint8 LastStrobe; -extern uint8 coinon; - -static int FSDisable = 0; /* Set to 1 if NES-style four-player adapter is disabled. */ -static int JPAttrib[2] = { 0, 0 }; -static int JPType[2] = { 0, 0 }; -static void *InputDataPtr[2]; +static int FourScoreAttached = FALSE; /* Set to 1 if NES-style four-player adapter is disabled. */ -static int JPAttribFC = 0; -static int JPTypeFC = 0; -static void *InputDataPtrFC; +static JOYPORT joyport[2]; +static PORTFC portFC; static INPUTC DummyJPort = { 0, 0, 0, 0, 0, 0 }; -static INPUTC *JPorts[2] = { &DummyJPort, &DummyJPort }; -static INPUTCFC *FCExp = 0; -int replaceP2StartWithMicrophone = 0; - -void (*InputScanlineHook)(uint8 *bg, uint8 *spr, uint32 linets, int final); - -static DECLFR(JPRead) -{ - uint8 ret = 0; - static int microphone = 0; +static DECLFR(JPRead) { + uint8 ret = 0; + static uint8 microphone = 0; - if (JPorts[A & 1]->Read) - ret |= JPorts[A & 1]->Read(A & 1); + if (joyport[A & 0x01].driver->Read) { + ret |= joyport[A & 0x01].driver->Read(A & 0x01); + } /* Test if the port 2 start button is being pressed. * On a famicom, port 2 start shouldn't exist, so this removes it. * Games can't automatically be checked for NES/Famicom status, * so it's an all-encompassing change in the input config menu. */ - if ((replaceP2StartWithMicrophone) && (A & 1) && (joy_readbit[1] == 4)) { + if ((FSettings.ReplaceP2StartWithMicrophone) && (A & 0x01) && (joy_readbit[1] == 0x04)) { /* Nullify Port 2 Start Button */ ret &= 0xFE; } - if (FCExp) - if (FCExp->Read) - ret = FCExp->Read(A & 1, ret); + if (portFC.driver && portFC.driver->Read) { + ret = portFC.driver->Read(A & 0x01, ret); + } /* Not verified against hardware. */ - if (replaceP2StartWithMicrophone) { - if (joy[1] & 8) { + if (FSettings.ReplaceP2StartWithMicrophone) { + if (joy[1] & 0x08) { microphone = !microphone; if (microphone) { - ret |= 4; + ret |= 0x04; } } else { microphone = 0; } } - ret |= X.DB & 0xC0; + ret |= (cpu.openbus & 0xC0); - return(ret); + return (ret); } -static DECLFW(B4016) -{ - if (FCExp) - if (FCExp->Write) - FCExp->Write(V & 7); +static DECLFW(B4016) { + int x; - if (JPorts[0]->Write) - JPorts[0]->Write(V & 1); - if (JPorts[1]->Write) - JPorts[1]->Write(V & 1); + if (portFC.driver && portFC.driver->Write) { + portFC.driver->Write(V & 0x07); + } - if ((LastStrobe & 1) && (!(V & 1))) - { - if (JPorts[0]->Strobe) - JPorts[0]->Strobe(0); - if (JPorts[1]->Strobe) - JPorts[1]->Strobe(1); - if (FCExp) - if (FCExp->Strobe) - FCExp->Strobe(); - } - LastStrobe = V & 0x1; -} + for (x = 0; x < 2; x++) { + if (joyport[x].driver->Write) { + joyport[x].driver->Write(V & 0x01); + } + } -void FCEU_DrawInput(uint8 *buf) -{ - int x; + if ((LastStrobe & 0x01) && (!(V & 0x01))) { + for (x = 0; x < 2; x++) { + if (joyport[x].driver->Strobe) { + joyport[x].driver->Strobe(x); + } + } + if (portFC.driver && portFC.driver->Strobe) { + portFC.driver->Strobe(); + } + } - for (x = 0; x < 2; x++) - if (JPorts[x]->Draw) - JPorts[x]->Draw(x, buf, JPAttrib[x]); - if (FCExp) - if (FCExp->Draw) - FCExp->Draw(buf, JPAttribFC); + LastStrobe = V; } /**********************************************************************/ /* This function is a quick hack to get the NSF player to use emulated gamepad - input. + input. */ uint8 FCEU_GetJoyJoy(void) { - return(joy[0] | joy[1] | joy[2] | joy[3]); + return (joy[0] | joy[1] | joy[2] | joy[3]); } /* 4-player support for famicom expansion */ static uint8 F4ReadBit[2]; - static void StrobeFami4(void) { F4ReadBit[0] = F4ReadBit[1] = 0; } -static uint8 FP_FASTAPASS(2) ReadFami4(int w, uint8 ret) { - ret &= 1; - ret |= ((joy[2 + w] >> (F4ReadBit[w])) & 1) << 1; - if (F4ReadBit[w] >= 8) ret |= 2; - else F4ReadBit[w]++; - return(ret); +static uint8 ReadFami4(int w, uint8 ret) { + ret &= 0x01; + ret |= ((joy[2 + w] >> (F4ReadBit[w])) & 0x01) << 1; + + if (F4ReadBit[w] >= 8) { + ret |= 0x02; + } else { + F4ReadBit[w]++; + } + + return (ret); +} + +/* Hori 4 player driver for expansion port */ +static uint8 Hori4ReadBit[2]; +static void StrobeHori4(void) { + Hori4ReadBit[0] = Hori4ReadBit[1] = 0; +} + +static uint8 ReadHori4(int w, uint8 ret) { + ret &= 0x01; + if (Hori4ReadBit[w] < 8) { + ret |= ((joy[w] >> (Hori4ReadBit[w])) & 0x01) << 1; + } else if (Hori4ReadBit[w] < 16) { + ret |= ((joy[2 + w] >> (Hori4ReadBit[w] - 8)) & 0x01) << 1; + } else if (Hori4ReadBit[w] < 24) { + ret |= (((w ? 0x10 : 0x20) >> (7 - (Hori4ReadBit[w] - 16))) & 0x01) << 1; + } + + if (Hori4ReadBit[w] >= 24) { + ret |= 0x02; + } else { + Hori4ReadBit[w]++; + } + + return (ret); } /* VS. Unisystem inputs */ -static uint8 FP_FASTAPASS(1) ReadGPVS(int w) { +static uint8 ReadGPVS(int w) { uint8 ret = 0; - if (joy_readbit[w] >= 8) + + if (joy_readbit[w] >= 8) { ret = 1; - else { + } else { ret = ((joy[w] >> (joy_readbit[w])) & 1); - #ifdef FCEUDEF_DEBUGGER +#ifdef FCEUDEF_DEBUGGER if (!fceuindbg) - #endif - joy_readbit[w]++; +#endif + joy_readbit[w]++; } return ret; } /* standard gamepad inputs */ -static uint8 FP_FASTAPASS(1) ReadGP(int w) { - uint8 ret; - if (joy_readbit[w] >= 8) - ret = ((joy[2 + w] >> (joy_readbit[w] & 7)) & 1); - else - ret = ((joy[w] >> (joy_readbit[w])) & 1); - if (joy_readbit[w] >= 16) ret = 0; - if (FSDisable) { - if (joy_readbit[w] >= 8) - ret |= 1; +static uint8 ReadGP(int w) { + uint8 ret = 0; + + if (joy_readbit[w] >= 8) { + ret = ((joy[2 + w] >> (joy_readbit[w] & 0x07)) & 0x01); } else { - if (joy_readbit[w] == 19 - w) - ret |= 1; + ret = ((joy[w] >> (joy_readbit[w])) & 0x01); + } + if (joy_readbit[w] >= 16) { + ret = 0; } - #ifdef FCEUDEF_DEBUGGER + if (!FourScoreAttached) { + if (joy_readbit[w] >= 8) { + ret |= 0x01; + } + } else { + if (joy_readbit[w] == 19 - w) { + ret |= 0x01; + } + } +#ifdef FCEUDEF_DEBUGGER if (!fceuindbg) - #endif - joy_readbit[w]++; +#endif + joy_readbit[w]++; return ret; } -static void FP_FASTAPASS(3) UpdateGP(int w, void *data, int arg) { - uint32 *ptr = (uint32*)data; +static void UpdateGP(int w, void *data, int arg) { + uint32 *ptr = (uint32 *)data; if (!w) { - joy[0] = *(uint32*)ptr; - joy[2] = *(uint32*)ptr >> 16; + joy[0] = *(uint32 *)ptr; + joy[2] = *(uint32 *)ptr >> 16; } else { - joy[1] = *(uint32*)ptr >> 8; - joy[3] = *(uint32*)ptr >> 24; + joy[1] = *(uint32 *)ptr >> 8; + joy[3] = *(uint32 *)ptr >> 24; } } -static void FP_FASTAPASS(1) StrobeGP(int w) { +static void StrobeGP(int w) { joy_readbit[w] = 0; } -static INPUTC GPC = { ReadGP, 0, StrobeGP, UpdateGP, 0, 0 }; -static INPUTC GPCVS = { ReadGPVS, 0, StrobeGP, UpdateGP, 0, 0 }; +static INPUTC GPC = { ReadGP, 0, StrobeGP, UpdateGP, 0, 0 }; +static INPUTC GPCVS = { ReadGPVS, 0, StrobeGP, UpdateGP, 0, 0 }; static INPUTCFC FAMI4C = { ReadFami4, 0, StrobeFami4, 0, 0, 0 }; +static INPUTCFC HORI4C = { ReadHori4, 0, StrobeHori4, 0, 0, 0 }; /**********************************************************************/ +void FCEU_DrawInput(uint8 *buf) { + int x; + + for (x = 0; x < 2; x++) { + if (joyport[x].driver->Draw) { + joyport[x].driver->Draw(x, buf, joyport[x].attrib); + } + } + + if (portFC.driver && portFC.driver->Draw) { + portFC.driver->Draw(buf, portFC.attrib); + } +} -void FCEU_UpdateInput(void) -{ - int x; +void FCEU_UpdateInput(void) { + int x; - for (x = 0; x < 2; x++) - { - if (JPorts[x] && JPorts[x]->Update) - JPorts[x]->Update(x, InputDataPtr[x], JPAttrib[x]); - } + for (x = 0; x < 2; x++) { + if (joyport[x].driver && joyport[x].driver->Update) { + joyport[x].driver->Update(x, joyport[x].dataptr, joyport[x].attrib); + } + } - if (FCExp && FCExp->Update) - FCExp->Update(InputDataPtrFC, JPAttribFC); + if (portFC.driver && portFC.driver->Update) { + portFC.driver->Update(portFC.dataptr, portFC.attrib); + } - if (GameInfo && GameInfo->type == GIT_VSUNI) - if (coinon) coinon--; + if (GameInfo && ((GameInfo->type == GIT_VSUNI) || (iNESCart.mapper == 124))) { + for (x = 0; x < 2; x++) { + if (vsuni_system.coinon[x]) { + vsuni_system.coinon[x]--; + } + } + if (vsuni_system.service) { + vsuni_system.service--; + } + } - if (GameInfo->type == GIT_VSUNI) - FCEU_VSUniSwap(&joy[0], &joy[1]); + if (GameInfo->type == GIT_VSUNI) { + FCEU_VSUniSwap(&joy[0], &joy[1]); + } } -static DECLFR(VSUNIRead0) -{ - uint8 ret = 0; +static DECLFR(VSUNIRead0) { + uint8 ret = 0; - if (JPorts[0]->Read) - ret |= (JPorts[0]->Read(0)) & 1; + if (joyport[0].driver->Read) { + ret |= (joyport[0].driver->Read(0)) & 0x01; + } + + ret |= (vsuni_system.vsdip & 0x03) << 3; + + if (vsuni_system.coinon[0]) { + ret |= 0x20; + } + if (vsuni_system.coinon[1]) { + ret |= 0x40; + } + if (vsuni_system.service) { + ret |= 0x04; + } - ret |= (vsdip & 3) << 3; - if (coinon) - ret |= 0x4; - return ret; + return (ret); } -static DECLFR(VSUNIRead1) -{ +static DECLFR(VSUNIRead1) { uint8 ret = 0; - if (JPorts[1] && JPorts[1]->Read) - ret |= (JPorts[1]->Read(1)) & 1; - ret |= vsdip & 0xFC; - return ret; + if (joyport[1].driver && joyport[1].driver->Read) { + ret |= (joyport[1].driver->Read(1)) & 0x01; + } + + ret |= vsuni_system.vsdip & 0xFC; + + return (ret); +} + +void InputScanlineHook(uint8 *bg, uint8 *spr, uint32 linets, int final) { + int x; + + for (x = 0; x < 2; x++) { + if (joyport[x].driver && joyport[x].driver->SLHook) { + joyport[x].driver->SLHook(x, bg, spr, linets, final); + } + } + + if (portFC.driver && portFC.driver->SLHook) { + portFC.driver->SLHook(bg, spr, linets, final); + } +} + +static void SetInputStuff(int x) { + switch (joyport[x].type) { + case SI_NONE: + joyport[x].driver = &DummyJPort; + break; + case SI_GAMEPAD: + if (GameInfo->type == GIT_VSUNI) + joyport[x].driver = &GPCVS; + else + joyport[x].driver = &GPC; + break; + case SI_ARKANOID: + joyport[x].driver = FCEU_InitArkanoid(x); + break; + case SI_MOUSE: + joyport[x].driver = FCEU_InitMouse(x); + break; + case SI_ZAPPER: + joyport[x].driver = FCEU_InitZapper(x); + break; + case SI_POWERPADA: + joyport[x].driver = FCEU_InitPowerpadA(x); + break; + case SI_POWERPADB: + joyport[x].driver = FCEU_InitPowerpadB(x); + break; + case SI_LCDCOMP_ZAPPER: + joyport[x].driver = FCEU_InitLCDCompZapper(x); + break; + case SI_SNES_GAMEPAD: + joyport[x].driver = FCEU_InitSNESGamepad(x); + break; + case SI_SNES_MOUSE: + joyport[x].driver = FCEU_InitSNESMouse(x); + break; + case SI_VIRTUALBOY: + joyport[x].driver = FCEU_InitVirtualBoy(x); + break; + } } -static void SLHLHook(uint8 *bg, uint8 *spr, uint32 linets, int final) -{ - int x; - - for (x = 0; x < 2; x++) - if (JPorts[x] && JPorts[x]->SLHook) - JPorts[x]->SLHook(x, bg, spr, linets, final); - - if (FCExp && FCExp->SLHook) - FCExp->SLHook(bg, spr, linets, final); -} - -static void CheckSLHook(void) -{ - InputScanlineHook = 0; - - if ((JPorts[0] && JPorts[0]->SLHook) || (JPorts[1] && JPorts[1]->SLHook)) - InputScanlineHook = SLHLHook; - - if (FCExp && FCExp->SLHook) - InputScanlineHook = SLHLHook; -} - -static void FASTAPASS(1) SetInputStuff(int x) -{ - switch (JPType[x]) - { - case SI_NONE: - JPorts[x] = &DummyJPort; - break; - case SI_GAMEPAD: - if (GameInfo->type == GIT_VSUNI) - JPorts[x] = &GPCVS; - else - JPorts[x] = &GPC; - break; - case SI_ARKANOID: - JPorts[x] = FCEU_InitArkanoid(x); - break; - case SI_MOUSE: - JPorts[x] = FCEU_InitMouse(x); - break; - case SI_ZAPPER: - JPorts[x] = FCEU_InitZapper(x); - break; - case SI_POWERPADA: - JPorts[x] = FCEU_InitPowerpadA(x); - break; - case SI_POWERPADB: - JPorts[x] = FCEU_InitPowerpadB(x); - break; - case SI_LCDCOMP_ZAPPER: - JPorts[x] = FCEU_InitLCDCompZapper(x); - break; - case SI_SNES_GAMEPAD: - JPorts[x] = FCEU_InitSNESGamepad(x); - break; - case SI_SNES_MOUSE: - JPorts[x] = FCEU_InitSNESMouse(x); - break; - case SI_VIRTUALBOY: - JPorts[x] = FCEU_InitVirtualBoy(x); - break; - } - CheckSLHook(); -} - -static void SetInputStuffFC(void) -{ - switch (JPTypeFC) - { - case SIFC_NONE: - FCExp = 0; - break; - case SIFC_ARKANOID: - FCExp = FCEU_InitArkanoidFC(); - break; - case SIFC_SHADOW: - FCExp = FCEU_InitSpaceShadow(); - break; - case SIFC_OEKAKIDS: - FCExp = FCEU_InitOekaKids(); - break; - case SIFC_4PLAYER: - FCExp = &FAMI4C; - memset(&F4ReadBit, 0, sizeof(F4ReadBit)); - break; - case SIFC_FKB: - FCExp = FCEU_InitFKB(); - break; - case SIFC_SUBORKB: - FCExp = FCEU_InitSuborKB(); - break; - case SIFC_PEC586KB: - FCExp = FCEU_InitPEC586KB(); - break; - case SIFC_HYPERSHOT: - FCExp = FCEU_InitHS(); - break; - case SIFC_MAHJONG: - FCExp = FCEU_InitMahjong(); - break; - case SIFC_QUIZKING: - FCExp = FCEU_InitQuizKing(); - break; - case SIFC_FTRAINERA: - FCExp = FCEU_InitFamilyTrainerA(); - break; - case SIFC_FTRAINERB: - FCExp = FCEU_InitFamilyTrainerB(); - break; - case SIFC_BWORLD: - FCExp = FCEU_InitBarcodeWorld(); - break; - case SIFC_TOPRIDER: - FCExp = FCEU_InitTopRider(); - break; - } - CheckSLHook(); -} - -void InitializeInput(void) -{ - memset(joy_readbit,0,sizeof(joy_readbit)); - memset(joy,0,sizeof(joy)); - LastStrobe = 0; - - if (GameInfo && GameInfo->type == GIT_VSUNI) - { - SetReadHandler(0x4016, 0x4016, VSUNIRead0); - SetReadHandler(0x4017, 0x4017, VSUNIRead1); - } - else - SetReadHandler(0x4016, 0x4017, JPRead); - - SetWriteHandler(0x4016, 0x4016, B4016); - - SetInputStuff(0); - SetInputStuff(1); - SetInputStuffFC(); -} - -void FCEUI_SetInput(int port, int type, void *ptr, int attrib) -{ - JPAttrib[port] = attrib; - JPType[port] = type; - InputDataPtr[port] = ptr; - SetInputStuff(port); -} - -void FCEUI_SetInputFC(int type, void *ptr, int attrib) -{ - JPAttribFC = attrib; - JPTypeFC = type; - InputDataPtrFC = ptr; +static void SetInputStuffFC(void) { + switch (portFC.type) { + case SIFC_NONE: + portFC.driver = 0; + break; + case SIFC_ARKANOID: + portFC.driver = FCEU_InitArkanoidFC(); + break; + case SIFC_SHADOW: + portFC.driver = FCEU_InitSpaceShadow(); + break; + case SIFC_OEKAKIDS: + portFC.driver = FCEU_InitOekaKids(); + break; + case SIFC_4PLAYER: + portFC.driver = &FAMI4C; + memset(&F4ReadBit, 0, sizeof(F4ReadBit)); + break; + case SIFC_FKB: + portFC.driver = FCEU_InitFKB(); + break; + case SIFC_SUBORKB: + portFC.driver = FCEU_InitSuborKB(); + break; + case SIFC_PEC586KB: + portFC.driver = FCEU_InitPEC586KB(); + break; + case SIFC_HYPERSHOT: + portFC.driver = FCEU_InitHS(); + break; + case SIFC_MAHJONG: + portFC.driver = FCEU_InitMahjong(); + break; + case SIFC_QUIZKING: + portFC.driver = FCEU_InitQuizKing(); + break; + case SIFC_FTRAINERA: + portFC.driver = FCEU_InitFamilyTrainerA(); + break; + case SIFC_FTRAINERB: + portFC.driver = FCEU_InitFamilyTrainerB(); + break; + case SIFC_BWORLD: + portFC.driver = FCEU_InitBarcodeWorld(); + break; + case SIFC_TOPRIDER: + portFC.driver = FCEU_InitTopRider(); + break; + case SIFC_FAMINETSYS: + portFC.driver = FCEU_InitFamiNetSys(); + break; + case SIFC_HORI4PLAYER: + portFC.driver = &HORI4C; + memset(&Hori4ReadBit, 0, sizeof(Hori4ReadBit)); + break; + } +} + +void InitializeInput(void) { + memset(joy_readbit, 0, sizeof(joy_readbit)); + memset(joy, 0, sizeof(joy)); + LastStrobe = 0; + + memset(joyport, 0, sizeof(joyport)); + memset(&portFC, 0, sizeof(portFC)); + + joyport[0].driver = &DummyJPort; + joyport[1].driver = &DummyJPort; + + if (GameInfo && GameInfo->type == GIT_VSUNI) { + SetReadHandler(0x4016, 0x4016, VSUNIRead0); + SetReadHandler(0x4017, 0x4017, VSUNIRead1); + } else + SetReadHandler(0x4016, 0x4017, JPRead); + + SetWriteHandler(0x4016, 0x4016, B4016); + + SetInputStuff(0); + SetInputStuff(1); SetInputStuffFC(); } -void FCEUI_DisableFourScore(int s) { - FSDisable = s; +void FCEUI_SetInput(int port, int type, void *ptr, int attrib) { + joyport[port].attrib = attrib; + joyport[port].type = type; + joyport[port].dataptr = ptr; + SetInputStuff(port); +} + +void FCEUI_SetInputFC(int type, void *ptr, int attrib) { + portFC.attrib = attrib; + portFC.type = type; + portFC.dataptr = ptr; + SetInputStuffFC(); +} + +void FCEUI_SetInputFourScore(int useFourScore) { + FourScoreAttached = useFourScore; } SFORMAT FCEUCTRL_STATEINFO[] = { { joy_readbit, 2, "JYRB" }, { joy, 4, "JOYS" }, { &LastStrobe, 1, "LSTS" }, - { 0 } + { &ZD[0].bogo, 1, "ZBG0" }, + { &ZD[1].bogo, 1, "ZBG1" }, + { &ZD[0].zaphit, sizeof(ZD[0].zaphit), "ZHT0" }, + { &ZD[1].zaphit, sizeof(ZD[1].zaphit), "ZHT1" }, + { &ZD[0].zappo, sizeof(ZD[0].zappo), "ZAP0" }, + { &ZD[1].zappo, sizeof(ZD[1].zappo), "ZAP1" }, + { &ZD[0].zap_readbit, sizeof(ZD[0].zap_readbit), "ZRB0" }, + { &ZD[1].zap_readbit, sizeof(ZD[1].zap_readbit), "ZRB1" }, + { 0 }, }; -void FCEU_DoSimpleCommand(int cmd) -{ - switch (cmd) - { - case FCEUNPCMD_FDSINSERT: - FCEU_FDSInsert(-1); - break; - case FCEUNPCMD_FDSSELECT: - FCEU_FDSSelect(); - break; - case FCEUNPCMD_FDSEJECT: - FCEU_FDSEject(); - break; - case FCEUNPCMD_VSUNICOIN: - FCEU_VSUniCoin(); - break; - case FCEUNPCMD_VSUNIDIP0: - case (FCEUNPCMD_VSUNIDIP0 + 1): - case (FCEUNPCMD_VSUNIDIP0 + 2): - case (FCEUNPCMD_VSUNIDIP0 + 3): - case (FCEUNPCMD_VSUNIDIP0 + 4): - case (FCEUNPCMD_VSUNIDIP0 + 5): - case (FCEUNPCMD_VSUNIDIP0 + 6): - case (FCEUNPCMD_VSUNIDIP0 + 7): - FCEU_VSUniToggleDIP(cmd - FCEUNPCMD_VSUNIDIP0); - break; - case FCEUNPCMD_POWER: - PowerNES(); - break; - case FCEUNPCMD_RESET: - ResetNES(); - break; - } -} - -void FCEU_QSimpleCommand(int cmd) -{ - FCEU_DoSimpleCommand(cmd); -} - -void FCEUI_FDSSelect(void) -{ +void FCEU_DoSimpleCommand(int cmd) { + switch (cmd) { + case FCEUNPCMD_FDSINSERT: + FCEU_FDSInsert(-1); + break; + case FCEUNPCMD_FDSSELECT: + FCEU_FDSSelect(); + break; + case FCEUNPCMD_FDSEJECT: + FCEU_FDSEject(); + break; + case FCEUNPCMD_VSUNICOIN: + FCEU_VSUniCoin(0); + break; + case FCEUNPCMD_VSUNICOIN2: + FCEU_VSUniCoin(1); + break; + case FCEUNPCMD_VSUNISERVICE: + FCEU_VSUniService(); + break; + case FCEUNPCMD_VSUNIDIP0: + case (FCEUNPCMD_VSUNIDIP0 + 1): + case (FCEUNPCMD_VSUNIDIP0 + 2): + case (FCEUNPCMD_VSUNIDIP0 + 3): + case (FCEUNPCMD_VSUNIDIP0 + 4): + case (FCEUNPCMD_VSUNIDIP0 + 5): + case (FCEUNPCMD_VSUNIDIP0 + 6): + case (FCEUNPCMD_VSUNIDIP0 + 7): + FCEU_VSUniToggleDIP(cmd - FCEUNPCMD_VSUNIDIP0); + break; + case FCEUNPCMD_POWER: + PowerNES(); + break; + case FCEUNPCMD_RESET: + ResetNES(); + break; + } +} + +static void FCEU_QSimpleCommand(int cmd) { + FCEU_DoSimpleCommand(cmd); +} + +void FCEUI_FDSSelect(void) { FCEU_QSimpleCommand(FCEUNPCMD_FDSSELECT); } -int FCEUI_FDSInsert(int oride) -{ +void FCEUI_FDSInsert(void) { FCEU_QSimpleCommand(FCEUNPCMD_FDSINSERT); - return(1); } -int FCEUI_FDSEject(void) -{ +void FCEUI_FDSEject(void) { FCEU_QSimpleCommand(FCEUNPCMD_FDSEJECT); - return(1); } -void FCEUI_VSUniToggleDIP(int w) -{ +void FCEUI_VSUniToggleDIP(int w) { FCEU_QSimpleCommand(FCEUNPCMD_VSUNIDIP0 + w); } -void FCEUI_VSUniCoin(void) -{ +void FCEUI_VSUniCoin(void) { FCEU_QSimpleCommand(FCEUNPCMD_VSUNICOIN); } -void FCEUI_ResetNES(void) -{ +void FCEUI_VSUniCoin2(void) { + FCEU_QSimpleCommand(FCEUNPCMD_VSUNICOIN2); +} + +void FCEUI_VSUniService(void) { + FCEU_QSimpleCommand(FCEUNPCMD_VSUNISERVICE); +} + +void FCEUI_ResetNES(void) { FCEU_QSimpleCommand(FCEUNPCMD_RESET); } -void FCEUI_PowerNES(void) -{ +void FCEUI_PowerNES(void) { FCEU_QSimpleCommand(FCEUNPCMD_POWER); } - diff --git a/src/input.h b/src/input.h index 4936bdcfb..bf4882fe4 100644 --- a/src/input.h +++ b/src/input.h @@ -2,31 +2,37 @@ #define _FCEU_INPUT_H typedef struct { - uint8 FP_FASTAPASS(1) (*Read)(int w); - void FP_FASTAPASS(1) (*Write)(uint8 v); - void FP_FASTAPASS(1) (*Strobe)(int w); - void FP_FASTAPASS(3) (*Update)(int w, void *data, int arg); - void FP_FASTAPASS(3) (*SLHook)(int w, uint8 *bg, uint8 *spr, uint32 linets, int final); - void FP_FASTAPASS(3) (*Draw)(int w, uint8 *buf, int arg); + uint8 (*Read)(int w); + void (*Write)(uint8 v); + void (*Strobe)(int w); + void (*Update)(int w, void *data, int arg); + void (*SLHook)(int w, uint8 *bg, uint8 *spr, uint32 linets, int final); + void (*Draw)(int w, uint8 *buf, int arg); } INPUTC; typedef struct { - uint8 FP_FASTAPASS(2) (*Read)(int w, uint8 ret); - void FP_FASTAPASS(1) (*Write)(uint8 v); + uint8 (*Read)(int w, uint8 ret); + void (*Write)(uint8 v); void (*Strobe)(void); - void FP_FASTAPASS(2) (*Update)(void *data, int arg); - void FP_FASTAPASS(3) (*SLHook)(uint8 *bg, uint8 *spr, uint32 linets, int final); - void FP_FASTAPASS(2) (*Draw)(uint8 *buf, int arg); + void (*Update)(void *data, int arg); + void (*SLHook)(uint8 *bg, uint8 *spr, uint32 linets, int final); + void (*Draw)(uint8 *buf, int arg); } INPUTCFC; +uint8 FCEU_GetJoyJoy(void); + void FCEU_DrawInput(uint8 *buf); void FCEU_UpdateInput(void); void InitializeInput(void); + extern void (*PStrobe[2])(void); -extern void (*InputScanlineHook)(uint8 *bg, uint8 *spr, uint32 linets, int final); +void InputScanlineHook(uint8 *bg, uint8 *spr, uint32 linets, int final); void FCEU_DoSimpleCommand(int cmd); -extern int replaceP2StartWithMicrophone; +void FCEU_ZapperSetTolerance(int t); +void FCEU_ZapperSetMode(int mode); +void FCEU_ZapperInvertTrigger(int invert); +void FCEU_ZapperInvertSensor(int invert); #endif diff --git a/src/input/arkanoid.c b/src/input/arkanoid.c index 453dfdfd7..92719e5f7 100644 --- a/src/input/arkanoid.c +++ b/src/input/arkanoid.c @@ -34,7 +34,7 @@ static void StrobeARKFC(void) { FCArk.readbit = 0; } -static uint8 FP_FASTAPASS(2) ReadARKFC(int w, uint8 ret) { +static uint8 ReadARKFC(int w, uint8 ret) { ret &= ~2; if (w) { if (FCArk.readbit >= 8) @@ -58,7 +58,7 @@ static uint32 FixX(uint32 x) { return(x); } -static void FP_FASTAPASS(2) UpdateARKFC(void *data, int arg) { +static void UpdateARKFC(void *data, int arg) { uint32 *ptr = (uint32*)data; FCArk.mzx = FixX(ptr[0]); FCArk.mzb = ptr[2] ? 1 : 0; @@ -72,7 +72,7 @@ INPUTCFC *FCEU_InitArkanoidFC(void) { return(&ARKCFC); } -static uint8 FP_FASTAPASS(1) ReadARK(int w) { +static uint8 ReadARK(int w) { uint8 ret = 0; if (NESArk[w].readbit >= 8) ret |= 1 << 4; @@ -87,11 +87,11 @@ static uint8 FP_FASTAPASS(1) ReadARK(int w) { return(ret); } -static void FP_FASTAPASS(1) StrobeARK(int w) { +static void StrobeARK(int w) { NESArk[w].readbit = 0; } -static void FP_FASTAPASS(3) UpdateARK(int w, void *data, int arg) { +static void UpdateARK(int w, void *data, int arg) { uint32 *ptr = (uint32*)data; NESArk[w].mzx = FixX(ptr[0]); NESArk[w].mzb = ptr[2] ? 1 : 0; diff --git a/src/input/bbox.c b/src/input/bbox.c index f8ab27fe4..e34aa44a8 100644 --- a/src/input/bbox.c +++ b/src/input/bbox.c @@ -160,7 +160,7 @@ uint8 serialROMstate(uint8 linestate) return answ; } -static uint8 FP_FASTAPASS(2) BBRead(int w, uint8 ret) +static uint8 BBRead(int w, uint8 ret) { if(w) { @@ -170,7 +170,7 @@ static uint8 FP_FASTAPASS(2) BBRead(int w, uint8 ret) return(ret); } -static void FP_FASTAPASS(1) BBWrite(uint8 V) +static void BBWrite(uint8 V) { OUT0state = V; serialROMstate(OUT0state?OUT0:0); diff --git a/src/input/bworld.c b/src/input/bworld.c index 92a15c014..83668c3ee 100644 --- a/src/input/bworld.c +++ b/src/input/bworld.c @@ -25,7 +25,7 @@ static int seq, ptr, bit, cnt, have; static uint8 bdata[20]; -static uint8 FP_FASTAPASS(2) Read(int w, uint8 ret) { +static uint8 Read(int w, uint8 ret) { if (w && have) { switch (seq) { case 0: seq++; ptr = 0; ret |= 0x4; break; @@ -43,10 +43,10 @@ static uint8 FP_FASTAPASS(2) Read(int w, uint8 ret) { return(ret); } -static void FP_FASTAPASS(1) Write(uint8 V) { +static void Write(uint8 V) { } -static void FP_FASTAPASS(2) Update(void *data, int arg) { +static void Update(void *data, int arg) { if (*(uint8*)data) { *(uint8*)data = 0; seq = ptr = 0; diff --git a/src/input/fkb.c b/src/input/fkb.c index 1f3961955..a8aa4d416 100644 --- a/src/input/fkb.c +++ b/src/input/fkb.c @@ -49,7 +49,7 @@ static uint16 matrix[9][2][4] = { AK(DOWN), AK(SPACE), AK(DELETE), AK(INSERT) } }, }; -static void FP_FASTAPASS(1) FKB_Write(uint8 v) { +static void FKB_Write(uint8 v) { v >>= 1; if (v & 2) { if ((ksmode & 1) && !(v & 1)) @@ -58,7 +58,7 @@ static void FP_FASTAPASS(1) FKB_Write(uint8 v) { ksmode = v; } -static uint8 FP_FASTAPASS(2) FKB_Read(int w, uint8 ret) { +static uint8 FKB_Read(int w, uint8 ret) { if (w) { int x; @@ -76,7 +76,7 @@ static void FKB_Strobe(void) { ksindex = 0; } -static void FP_FASTAPASS(2) FKB_Update(void *data, int arg) { +static void FKB_Update(void *data, int arg) { memcpy(bufit + 1, data, sizeof(bufit) - 1); } diff --git a/src/input/fns.c b/src/input/fns.c new file mode 100644 index 000000000..2504f2a1a --- /dev/null +++ b/src/input/fns.c @@ -0,0 +1,53 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2019 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 + * + * Family Network System controller + * + */ + +#include +#include "share.h" + +static int readbit; +static int32 readdata; + +static uint8 Read(int w, uint8 ret) { + if (!w) { + if (readbit < 24) { + ret |= ((readdata >> readbit) & 1) << 1; + readbit++; + } else + ret |= 2; /* sense! */ + } + return ret; +} + +static void Strobe(void) { + readbit = 0; +} + +static void Update(void *data, int arg) { + readdata = *(uint32 *)data; +} + +static INPUTCFC FamiNetSys = { Read, 0, Strobe, Update, 0, 0 }; + +INPUTCFC *FCEU_InitFamiNetSys(void) { + return (&FamiNetSys); +} diff --git a/src/input/ftrainer.c b/src/input/ftrainer.c index a018e9c48..962ce6fe1 100644 --- a/src/input/ftrainer.c +++ b/src/input/ftrainer.c @@ -25,14 +25,14 @@ static uint32 FTVal, FTValR; static char side; -static uint8 FP_FASTAPASS(2) FT_Read(int w, uint8 ret) { +static uint8 FT_Read(int w, uint8 ret) { if (w) { ret |= FTValR; } return(ret); } -static void FP_FASTAPASS(1) FT_Write(uint8 V) { +static void FT_Write(uint8 V) { FTValR = 0; if (!(V & 0x1)) @@ -48,7 +48,7 @@ static void FP_FASTAPASS(1) FT_Write(uint8 V) { FTValR <<= 1; } -static void FP_FASTAPASS(2) FT_Update(void *data, int arg) { +static void FT_Update(void *data, int arg) { FTVal = *(uint32*)data; } diff --git a/src/input/hypershot.c b/src/input/hypershot.c index d62c62375..f0e2c7081 100644 --- a/src/input/hypershot.c +++ b/src/input/hypershot.c @@ -24,7 +24,7 @@ static uint8 HSVal, HSValR; -static uint8 FP_FASTAPASS(2) HS_Read(int w, uint8 ret) { +static uint8 HS_Read(int w, uint8 ret) { if (w) ret |= HSValR; return(ret); @@ -34,7 +34,7 @@ static void HS_Strobe(void) { HSValR = HSVal << 1; } -static void FP_FASTAPASS(2) HS_Update(void *data, int arg) { +static void HS_Update(void *data, int arg) { HSVal = *(uint8*)data; } diff --git a/src/input/lcdcompzapper.c b/src/input/lcdcompzapper.c index 407b8c41c..d1dbe89ee 100644 --- a/src/input/lcdcompzapper.c +++ b/src/input/lcdcompzapper.c @@ -28,7 +28,7 @@ static void StrobeLCDCompZapper(int w) { lcdCompZapperStrobe[w] = 0; } -void UpdateLCDCompZapper(int w, void *data, int arg) { +static void UpdateLCDCompZapper(int w, void *data, int arg) { /* In the '(*(uint32*)data)' variable, bit 0 holds the trigger value and bit 1 holds the light sense value. * Ultimately this needs to be converted from 0000 00lt to 000t l000 where l is the light bit and t * is the trigger bit. diff --git a/src/input/mahjong.c b/src/input/mahjong.c index 497563a7b..0b19e06b3 100644 --- a/src/input/mahjong.c +++ b/src/input/mahjong.c @@ -23,7 +23,7 @@ static uint32 MReal, MRet; -static uint8 FP_FASTAPASS(2) MJ_Read(int w, uint8 ret) { +static uint8 MJ_Read(int w, uint8 ret) { if (w) { /* ret|=(MRet&1)<<1; */ ret |= ((MRet & 0x80) >> 6) & 2; @@ -36,7 +36,7 @@ static uint8 FP_FASTAPASS(2) MJ_Read(int w, uint8 ret) { return(ret); } -static void FP_FASTAPASS(1) MJ_Write(uint8 v) { +static void MJ_Write(uint8 v) { /* 1: I-D7, J-D6, K-D5, L-D4, M-D3, Big Red-D2 2: A-D7, B-D6, C-D5, D-D4, E-D3, F-D2, G-D1, H-D0 3: Sel-D6, Start-D7, D5, D4, D3, D2, D1 @@ -54,7 +54,7 @@ static void FP_FASTAPASS(1) MJ_Write(uint8 v) { MRet = (MReal >> 8) & 0x3F; } -static void FP_FASTAPASS(2) MJ_Update(void *data, int arg) { +static void MJ_Update(void *data, int arg) { MReal = *(uint32*)data; } diff --git a/src/input/mouse.c b/src/input/mouse.c index 28f2e64c3..99ea0ac6c 100644 --- a/src/input/mouse.c +++ b/src/input/mouse.c @@ -30,7 +30,7 @@ typedef struct { static MOUSE Mouse; -static void FP_FASTAPASS(1) StrobeMOUSE(int w) { +static void StrobeMOUSE(int w) { Mouse.readbit = 0; if ((Mouse.mzxold - Mouse.mzx) > 0) Mouse.data |= 0x0C; @@ -42,7 +42,7 @@ static void FP_FASTAPASS(1) StrobeMOUSE(int w) { Mouse.data |= 0x10; } -static uint8 FP_FASTAPASS(1) ReadMOUSE(int w) { +static uint8 ReadMOUSE(int w) { uint8 ret = 0; if (Mouse.readbit >= 8) ret |= 1; @@ -56,7 +56,7 @@ static uint8 FP_FASTAPASS(1) ReadMOUSE(int w) { return(ret); } -static void FP_FASTAPASS(3) UpdateMOUSE(int w, void *data, int arg) { +static void UpdateMOUSE(int w, void *data, int arg) { uint32 *ptr = (uint32*)data; Mouse.data = 0; Mouse.mzxold = Mouse.mzx; diff --git a/src/input/oekakids.c b/src/input/oekakids.c index a6a5c5745..fdd9a9365 100644 --- a/src/input/oekakids.c +++ b/src/input/oekakids.c @@ -25,14 +25,14 @@ static uint8 OKValR, LastWR; static uint32 OKData; static uint32 OKX, OKY, OKB; -static uint8 FP_FASTAPASS(2) OK_Read(int w, uint8 ret) { +static uint8 OK_Read(int w, uint8 ret) { if (w) { ret |= OKValR; } return(ret); } -static void FP_FASTAPASS(1) OK_Write(uint8 V) { +static void OK_Write(uint8 V) { if (!(V & 0x1)) { int32 vx, vy; @@ -64,13 +64,13 @@ static void FP_FASTAPASS(1) OK_Write(uint8 V) { LastWR = V; } -static void FP_FASTAPASS(2) OK_Update(void *data, int arg) { +static void OK_Update(void *data, int arg) { OKX = ((uint32*)data)[0]; OKY = ((uint32*)data)[1]; OKB = ((uint32*)data)[2]; } -static void FP_FASTAPASS(2) DrawOeka(uint8 * buf, int arg) { +static void DrawOeka(uint8 * buf, int arg) { if (arg && OKY < 44) FCEU_DrawCursor(buf, OKX, OKY); } diff --git a/src/input/pec586kb.c b/src/input/pec586kb.c index 3ab947eb9..e8fcc4a0d 100644 --- a/src/input/pec586kb.c +++ b/src/input/pec586kb.c @@ -47,7 +47,7 @@ static uint16 matrix[13][8] = { AK(INSERT),AK(NUMPAD1),AK(HOME),AK(PRIOR),AK(DELETE),AK(END),AK(NEXT),AK(NUMLOCK) }, }; -static void FP_FASTAPASS(1) PEC586KB_Write(uint8 v) { +static void PEC586KB_Write(uint8 v) { if (!(kstrobe & 2) && (v & 2)) { kspos = 0; } @@ -61,7 +61,7 @@ static void FP_FASTAPASS(1) PEC586KB_Write(uint8 v) { kstrobe = v; } -static uint8 FP_FASTAPASS(2) PEC586KB_Read(int w, uint8 ret) { +static uint8 PEC586KB_Read(int w, uint8 ret) { #ifdef FCEUDEF_DEBUGGER if (!fceuindbg) { #endif @@ -84,7 +84,7 @@ static void PEC586KB_Strobe(void) { */ } -static void FP_FASTAPASS(2) PEC586KB_Update(void *data, int arg) { +static void PEC586KB_Update(void *data, int arg) { memcpy(bufit + 1, data, sizeof(bufit) - 1); } diff --git a/src/input/powerpad.c b/src/input/powerpad.c index 62bed8e8f..1e4285117 100644 --- a/src/input/powerpad.c +++ b/src/input/powerpad.c @@ -27,7 +27,7 @@ static char side; static uint32 pprsb[2]; static uint32 pprdata[2]; -static uint8 FP_FASTAPASS(1) ReadPP(int w) { +static uint8 ReadPP(int w) { uint8 ret = 0; ret |= ((pprdata[w] >> pprsb[w]) & 1) << 3; ret |= ((pprdata[w] >> (pprsb[w] + 8)) & 1) << 4; @@ -43,11 +43,11 @@ static uint8 FP_FASTAPASS(1) ReadPP(int w) { return ret; } -static void FP_FASTAPASS(1) StrobePP(int w) { +static void StrobePP(int w) { pprsb[w] = 0; } -void FP_FASTAPASS(3) UpdatePP(int w, void *data, int arg) { +static void UpdatePP(int w, void *data, int arg) { static const char shifttableA[12] = { 8, 9, 0, 1, 11, 7, 4, 2, 10, 6, 5, 3 }; static const char shifttableB[12] = { 1, 0, 9, 8, 2, 4, 7, 11, 3, 5, 6, 10 }; int x; diff --git a/src/input/quiz.c b/src/input/quiz.c index 77bbb4fe1..930608198 100644 --- a/src/input/quiz.c +++ b/src/input/quiz.c @@ -24,7 +24,7 @@ static uint8 QZVal, QZValR; static uint8 FunkyMode; -static uint8 FP_FASTAPASS(2) QZ_Read(int w, uint8 ret) { +static uint8 QZ_Read(int w, uint8 ret) { if (w) { ret |= (QZValR & 0x7) << 2; QZValR = QZValR >> 3; @@ -42,11 +42,11 @@ static void QZ_Strobe(void) { QZValR = QZVal; } -static void FP_FASTAPASS(1) QZ_Write(uint8 V) { +static void QZ_Write(uint8 V) { FunkyMode = V & 4; } -static void FP_FASTAPASS(2) QZ_Update(void *data, int arg) { +static void QZ_Update(void *data, int arg) { QZVal = *(uint8*)data; } diff --git a/src/input/shadow.c b/src/input/shadow.c index e8b0aa927..4d055153e 100644 --- a/src/input/shadow.c +++ b/src/input/shadow.c @@ -22,18 +22,11 @@ #include #include "share.h" +#include "zapper.h" -typedef struct { - uint32 mzx, mzy, mzb; - int zap_readbit; - int bogo; - int zappo; - uint64 zaphit; -} ZAPPER; +#define ZD ZD[0] -static ZAPPER ZD; - -static void FP_FASTAPASS(3) ZapperFrapper(uint8 * bg, uint8 * spr, uint32 linets, int final) { +static void ZapperFrapper(uint8 * bg, uint8 * spr, uint32 linets, int final) { int xs, xe; int zx, zy; @@ -66,7 +59,7 @@ static void FP_FASTAPASS(3) ZapperFrapper(uint8 * bg, uint8 * spr, uint32 linets sum = palo[a1].r + palo[a1].g + palo[a1].b; if (sum >= 100 * 3) { - ZD.zaphit = ((uint64)linets + (uint64)(xs + 16) * (PAL ? 15 : 16)) / 48 + timestampbase; + ZD.zaphit = ((uint64)linets + (uint64)(xs + 16) * (isPAL ? 15 : 16)) / 48 + timestampbase; goto endo; } } @@ -86,7 +79,7 @@ static INLINE int CheckColor(void) { } -static uint8 FP_FASTAPASS(2) ReadZapper(int w, uint8 ret) { +static uint8 ReadZapper(int w, uint8 ret) { if (w) { ret &= ~0x18; if (ZD.bogo) @@ -104,12 +97,12 @@ static uint8 FP_FASTAPASS(2) ReadZapper(int w, uint8 ret) { return ret; } -static void FP_FASTAPASS(2) DrawZapper(uint8 * buf, int arg) { +static void DrawZapper(uint8 * buf, int arg) { if (arg) FCEU_DrawGunSight(buf, ZD.mzx, ZD.mzy); } -static void FP_FASTAPASS(2) UpdateZapper(void *data, int arg) { +static void UpdateZapper(void *data, int arg) { uint32 *ptr = (uint32*)data; if (ZD.bogo) diff --git a/src/input/suborkb.c b/src/input/suborkb.c index abf02c77e..93bc921de 100644 --- a/src/input/suborkb.c +++ b/src/input/suborkb.c @@ -44,7 +44,7 @@ static uint16 matrix[13][2][4] = { { AK(GRAVE), AK(NUMPAD6), AK(PAUSE), AK(SPACE) }, { AK(F9), AK(NUMPAD3), AK(DECIMAL), AK(NUMPAD0) } }, }; -static void FP_FASTAPASS(1) SuborKB_Write(uint8 v) { +static void SuborKB_Write(uint8 v) { v >>= 1; if (v & 2) { if ((ksmode & 1) && !(v & 1)) @@ -53,7 +53,7 @@ static void FP_FASTAPASS(1) SuborKB_Write(uint8 v) { ksmode = v; } -static uint8 FP_FASTAPASS(2) SuborKB_Read(int w, uint8 ret) { +static uint8 SuborKB_Read(int w, uint8 ret) { if (w) { int x; @@ -71,7 +71,7 @@ static void SuborKB_Strobe(void) { ksindex = 0; } -static void FP_FASTAPASS(2) SuborKB_Update(void *data, int arg) { +static void SuborKB_Update(void *data, int arg) { memcpy(bufit + 1, data, sizeof(bufit) - 1); } diff --git a/src/input/toprider.c b/src/input/toprider.c index e05bbe206..b10af62c5 100644 --- a/src/input/toprider.c +++ b/src/input/toprider.c @@ -24,7 +24,7 @@ static uint32 bs, bss; static uint32 boop; -static uint8 FP_FASTAPASS(2) Read(int w, uint8 ret) { +static uint8 Read(int w, uint8 ret) { if (w) { ret |= (bs & 1) << 3; ret |= (boop & 1) << 4; @@ -34,11 +34,11 @@ static uint8 FP_FASTAPASS(2) Read(int w, uint8 ret) { return(ret); } -static void FP_FASTAPASS(1) Write(uint8 V) { +static void Write(uint8 V) { bs = bss; } -static void FP_FASTAPASS(2) Update(void *data, int arg) { +static void Update(void *data, int arg) { bss = *(uint8*)data; bss |= bss << 8; bss |= bss << 8; diff --git a/src/input/zapper.c b/src/input/zapper.c index b8363773b..f54a2bc8d 100644 --- a/src/input/zapper.c +++ b/src/input/zapper.c @@ -22,28 +22,30 @@ #include #include "share.h" +#include "zapper.h" #define ROUNDED_TARGET #ifdef ROUNDED_TARGET #define MAX_TOLERANCE 20 -static uint32 targetExpansion[MAX_TOLERANCE+1]; +static uint32 targetExpansion[MAX_TOLERANCE + 1]; #endif static int tolerance; -typedef struct { - uint32 mzx, mzy, mzb; - int zap_readbit; - int bogo; - int zappo; - uint64 zaphit; -} ZAPPER; +static uint8 stmode = FALSE; +static uint8 invert_trigger = TRUE; +static uint8 invert_sensor = TRUE; -static ZAPPER ZD[2]; +ZAPPER ZD[2]; -static void FP_FASTAPASS(3) ZapperFrapper(int w, uint8 * bg, uint8 * spr, uint32 linets, int final) { +static void ZapperFrapper(int w, uint8 * bg, uint8 * spr, uint32 linets, int final) { int xs, xe; int zx, zy; + if (stmode) { + ZD[w].zappo = 0; + return; + } + if (!bg) { /* New line, so reset stuff. */ ZD[w].zappo = 0; return; @@ -82,7 +84,7 @@ static void FP_FASTAPASS(3) ZapperFrapper(int w, uint8 * bg, uint8 * spr, uint32 sum = palo[a1].r + palo[a1].g + palo[a1].b; if (sum >= 100 * 3) { - ZD[w].zaphit = ((uint64)linets + (uint64)(xs + 16) * (PAL ? 15 : 16)) / 48 + timestampbase; + ZD[w].zaphit = ((uint64)linets + (uint64)(xs + 16) * (isPAL ? 15 : 16)) / 48 + timestampbase; goto endo; } } @@ -102,7 +104,7 @@ static INLINE int CheckColor(int w) { return(1); } -static uint8 FP_FASTAPASS(1) ReadZapperVS(int w) { +static uint8 ReadZapperVS(int w) { uint8 ret = 0; if (ZD[w].zap_readbit == 4) ret = 1; @@ -112,8 +114,13 @@ static uint8 FP_FASTAPASS(1) ReadZapperVS(int w) { ret |= 0x1; } if (ZD[w].zap_readbit == 6) { - if (!CheckColor(w)) - ret |= 0x1; + if (stmode) { + if (!ZD[w].mzs) + ret |= 0x1; + } else { + if (!CheckColor(w)) + ret |= 0x1; + } } #ifdef FCEUDEF_DEBUGGER if (!fceuindbg) @@ -122,25 +129,33 @@ static uint8 FP_FASTAPASS(1) ReadZapperVS(int w) { return ret; } -static void FP_FASTAPASS(1) StrobeZapperVS(int w) { +static void StrobeZapperVS(int w) { ZD[w].zap_readbit = 0; } -static uint8 FP_FASTAPASS(1) ReadZapper(int w) { +static uint8 ReadZapper(int w) { uint8 ret = 0; if (ZD[w].bogo) ret |= 0x10; - if (CheckColor(w)) - ret |= 0x8; + if (stmode) { + if (ZD[w].mzs) + ret |= 0x8; + } else { + if (CheckColor(w)) + ret |= 0x8; + } return ret; } -static void FASTAPASS(3) DrawZapper(int w, uint8 * buf, int arg) { +static void DrawZapper(int w, uint8 * buf, int arg) { + if (stmode) + return; + if (arg) FCEU_DrawGunSight(buf, ZD[w].mzx, ZD[w].mzy); } -static void FP_FASTAPASS(3) UpdateZapper(int w, void *data, int arg) { +static void UpdateZapper(int w, void *data, int arg) { uint32 *ptr = (uint32*)data; if (ZD[w].bogo) @@ -150,7 +165,16 @@ static void FP_FASTAPASS(3) UpdateZapper(int w, void *data, int arg) { ZD[w].mzx = ptr[0]; ZD[w].mzy = ptr[1]; - ZD[w].mzb = ptr[2]; + + if (invert_trigger) + ZD[w].mzb = ptr[2]; + else + ZD[w].mzb = !ptr[2]; + + if (invert_sensor) + ZD[w].mzs = !ptr[3]; + else + ZD[w].mzs = ptr[3]; } static INPUTC ZAPC = { ReadZapper, 0, 0, UpdateZapper, ZapperFrapper, DrawZapper }; @@ -176,6 +200,18 @@ void FCEU_ZapperSetTolerance(int t) #endif } +void FCEU_ZapperSetMode(int mode) { + stmode = mode ? TRUE : FALSE; +} + +void FCEU_ZapperInvertTrigger(int invert) { + invert_trigger = invert ? TRUE : FALSE; +} + +void FCEU_ZapperInvertSensor(int invert) { + invert_sensor = invert ? TRUE : FALSE; +} + INPUTC *FCEU_InitZapper(int w) { memset(&ZD[w], 0, sizeof(ZAPPER)); if (GameInfo->type == GIT_VSUNI) diff --git a/src/input/zapper.h b/src/input/zapper.h new file mode 100644 index 000000000..fe9ef8cba --- /dev/null +++ b/src/input/zapper.h @@ -0,0 +1,16 @@ +#ifndef _ZAPPER_H_ +#define _ZAPPER_H_ + +#include "../fceu-types.h" + +typedef struct ZAPPER { + uint32 mzx, mzy, mzb, mzs; + int zap_readbit; + uint8 bogo; + int zappo; + uint64 zaphit; +} ZAPPER; + +extern ZAPPER ZD[2]; + +#endif diff --git a/src/mappers.c b/src/mappers.c new file mode 100644 index 000000000..597f70948 --- /dev/null +++ b/src/mappers.c @@ -0,0 +1,6 @@ +#include + +#include "fceu-types.h" + +uint8 *WRAM = NULL; +uint32 WRAMSIZE = 0; diff --git a/src/mappers/hw/bandai.c b/src/mappers/hw/bandai.c new file mode 100644 index 000000000..3b429a620 --- /dev/null +++ b/src/mappers/hw/bandai.c @@ -0,0 +1,235 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2007 CaH4e3 + * Copyright (C) 2011 FCEUX team + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + * INES Mapper 016 + * iNES Mapper 016 is used for some of the Bandai FCG boards, namely, boards with + * the FCG-1 ASIC that supports no EEPROM, and the LZ93D50 ASIC with no or 256 bytes of EEPROM. + * + * INES Mapper 016 submapper table + * Submapper # Meaning Note + * 0 Unspecified Emulate both FCG-1/2 and LZ93D50 chips in their respective CPU address ranges. + * 1 LZ93D50 with 128 byte serial EEPROM (24C01) Deprecated, use INES Mapper 159 instead. + * 2 Datach Joint ROM System Deprecated, use INES Mapper 157 instead. + * 3 8 KiB of WRAM instead of serial EEPROM Deprecated, use INES Mapper 153 instead. + * 4 FCG-1/2 Responds only in the CPU $6000-$7FFF address range; IRQ counter is not latched. + * 5 LZ93D50 with no or 256-byte serial EEPROM (24C02) Responds only in the CPU $8000-$FFFF address range; IRQ counter is latched. + * + */ + +#include "mapinc.h" +#include "eeprom_x24c0x.h" +#include "bandai.h" + +EEPROM_TYPE eeprom_type = EEPROM_NONE; + +static uint8 prg; +static uint8 chr[8]; +static uint8 mirr; +static uint8 IRQa; +static int16 IRQCount, IRQLatch; + +static uint8 isFCG12 = 0; + +static uint8 eeprom[256]; + +void (*BANDAI_pwrap)(uint32 A, uint8 V); +void (*BANDAI_cwrap)(uint32 A, uint8 V); + +static SFORMAT StateRegs[] = +{ + { chr, 8, "CRGS" }, + { &prg, 1, "PREG" }, + { &mirr, 1, "MIRR" }, + { &IRQa, 1, "IRQA" }, + { &IRQCount, 2, "IRQC" }, + { &IRQLatch, 2, "IRQL" }, /* need for Famicom Jump II - Saikyou no 7 Nin (J) [!] */ + { 0 } +}; + +static void GENPWRAP(uint32 A, uint8 V) { + setprg16(A, V & 0x0F); +} + +static void GENCWRAP(uint32 A, uint8 V) { + setchr1(A, V); +} + +void BANDAI_FixPRG(void) { + BANDAI_pwrap(0x8000, prg); + BANDAI_pwrap(0xC000, ~0); +} + +void BANDAI_FixCHR(void) { + BANDAI_cwrap(0x0000, chr[0]); + BANDAI_cwrap(0x0400, chr[1]); + BANDAI_cwrap(0x0800, chr[2]); + BANDAI_cwrap(0x0C00, chr[3]); + BANDAI_cwrap(0x1000, chr[4]); + BANDAI_cwrap(0x1400, chr[5]); + BANDAI_cwrap(0x1800, chr[6]); + BANDAI_cwrap(0x1C00, chr[7]); +} + +void BANDAI_FixMIR(void) { + switch (mirr & 0x03) { + case 0: setmirror(MI_V); break; + case 1: setmirror(MI_H); break; + case 2: setmirror(MI_0); break; + case 3: setmirror(MI_1); break; + } +} + +static DECLFR(BANDAI_Read) { + if (eeprom_type == EEPROM_X24C01) { + return (cpu.openbus & ~0x010) | (x24c01_read() << 4); + } + return (cpu.openbus & ~0x010) | (x24c02_read() << 4); +} + +DECLFW(BANDAI_Write) { + switch (A & 0x0F) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + chr[A & 0x07] = V; + BANDAI_FixCHR(); + break; + case 0x08: + prg = V; + BANDAI_FixPRG(); + break; + case 0x09: + mirr = V; + BANDAI_FixMIR(); + break; + case 0x0A: + IRQa = V & 1; + IRQCount = IRQLatch; + if (IRQa && !IRQLatch) { + X6502_IRQBegin(FCEU_IQEXT); + } else { + X6502_IRQEnd(FCEU_IQEXT); + } + break; + case 0x0B: + IRQLatch &= 0xFF00; + IRQLatch |= V; + break; + case 0x0C: + IRQLatch &= 0x00FF; + IRQLatch |= V << 8; + break; + case 0x0D: + if (eeprom_type == EEPROM_X24C02) { + x24c02_write(V); + } else if (eeprom_type == EEPROM_X24C01) { + x24c01_write(V); + } + break; + } +} + +void BANDAI_IRQHook(int a) { + if (IRQa) { + IRQCount -= a; + if (IRQCount < 0) { + X6502_IRQBegin(FCEU_IQEXT); + } + } +} + +void BANDAI_Reset(void) { + int x; + + prg = 0x00; + for (x = 0; x < 8; x++) { + chr[x] = x; + } + IRQCount = 0; + IRQLatch = 0; + IRQa = FALSE; + + BANDAI_FixPRG(); + BANDAI_FixCHR(); + BANDAI_FixMIR(); +} + +static void StateRestore(int version) { + BANDAI_FixPRG(); + BANDAI_FixCHR(); + BANDAI_FixMIR(); +} + +void BANDAI_Power(void) { + if (UNIFchrrama) { + setchr8(0); + } + + BANDAI_Reset(); + + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, BANDAI_Write); + if (isFCG12) { + /* submapper 4 */ + SetWriteHandler(0x6000, 0x7FFF, BANDAI_Write); + } + + if (eeprom_type != EEPROM_NONE) { + SetReadHandler(0x6000, 0x7FFF, BANDAI_Read); + if (EEPROM_X24C02) { + x24c02_init(eeprom); + } else { + x24c01_init(eeprom); + } + } +} + +void BANDAI_Init(CartInfo *info, EEPROM_TYPE _eeprom_type, int _isFCG) { + BANDAI_pwrap = GENPWRAP; + BANDAI_cwrap = GENCWRAP; + + eeprom_type = _eeprom_type; + isFCG12 = _isFCG; + + info->Power = BANDAI_Power; + MapIRQHook = BANDAI_IRQHook; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + + if (eeprom_type != EEPROM_NONE) { + info->battery = 1; + memset(eeprom, 0, sizeof(eeprom)); + if (eeprom_type == EEPROM_X24C02) { + info->SaveGame[0] = eeprom; + info->SaveGameLen[0] = 256; + AddExState(&x24c02_StateRegs, ~0, 0, 0); + } else if (eeprom_type == EEPROM_X24C01) { + info->SaveGame[0] = eeprom; + info->SaveGameLen[0] = 128; + AddExState(&x24c01_StateRegs, ~0, 0, 0); + } + } +} diff --git a/src/mappers/hw/bandai.h b/src/mappers/hw/bandai.h new file mode 100644 index 000000000..dd497d3ef --- /dev/null +++ b/src/mappers/hw/bandai.h @@ -0,0 +1,39 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _BANDAI_H +#define _BANDAI_H + +DECLFW(BANDAI_Write); + +void BANDAI_Power(void); +void BANDAI_IRQHook(int a); +void BANDAI_Reset(void); + +void BANDAI_Init(CartInfo *info, EEPROM_TYPE _eeprom_type, int _isFCG); + +void BANDAI_FixPRG(void); +void BANDAI_FixCHR(void); +void BANDAI_FixMIR(void); + +extern void (*BANDAI_pwrap)(uint32 A, uint8 V); +extern void (*BANDAI_cwrap)(uint32 A, uint8 V); + +#endif /* _BANDAI_H */ diff --git a/src/mappers/hw/eeprom_93Cx6.c b/src/mappers/hw/eeprom_93Cx6.c new file mode 100644 index 000000000..85f01a5ce --- /dev/null +++ b/src/mappers/hw/eeprom_93Cx6.c @@ -0,0 +1,173 @@ +#include "mapinc.h" +#include "eeprom_93Cx6.h" + +struct EEPROM_93Cx6 { + uint8 *storage; + uint8 opcode; + uint16 data; + uint16 address; + uint8 state; + uint8 lastCLK; + uint8 writeEnabled; + uint8 output; + uint8 capacity; + uint8 wordsize; + uint8 state_address; + uint8 state_data; +} EEPROM_93Cx6; + +#define OPCODE_MISC 0 +#define OPCODE_WRITE 1 +#define OPCODE_READ 2 +#define OPCODE_ERASE 3 +#define OPCODE_WRITEDISABLE 10 +#define OPCODE_WRITEALL 11 +#define OPCODE_ERASEALL 12 +#define OPCODE_WRITEENABLE 13 + +#define STATE_STANDBY 0 +#define STATE_STARTBIT 1 +#define STATE_OPCODE 3 +#define STATE_ADDRESS8 12 +#define STATE_DATA8 20 +#define STATE_ADDRESS16 11 +#define STATE_DATA16 27 +#define STATE_FINISHED 99 + +static struct EEPROM_93Cx6 eeprom_93Cx6 = { 0 }; + +void eeprom_93Cx6_init(uint8 *data, uint32 capacity, uint8 wordsize) { + eeprom_93Cx6.storage = data; + eeprom_93Cx6.address = 0; + eeprom_93Cx6.state = STATE_STANDBY; + eeprom_93Cx6.lastCLK = FALSE; + eeprom_93Cx6.writeEnabled = FALSE; + eeprom_93Cx6.capacity = capacity; + eeprom_93Cx6.wordsize = wordsize; + + eeprom_93Cx6.state_address = (wordsize == 16) ? STATE_ADDRESS16 : STATE_ADDRESS8; + eeprom_93Cx6.state_data = (wordsize == 16) ? STATE_DATA16 : STATE_DATA8; +} + +uint8 eeprom_93Cx6_read(void) { + return eeprom_93Cx6.output; +} + +void eeprom_93Cx6_write(uint8 CS, uint8 CLK, uint8 DAT) { + if (!CS && (eeprom_93Cx6.state <= eeprom_93Cx6.state_address)) { + eeprom_93Cx6.state = STATE_STANDBY; + } else if ((eeprom_93Cx6.state == STATE_STANDBY) && CS && CLK && !eeprom_93Cx6.lastCLK) { + eeprom_93Cx6.state = STATE_STARTBIT; + eeprom_93Cx6.opcode = 0; + eeprom_93Cx6.address = 0; + eeprom_93Cx6.output = TRUE; + } else if (CLK && !eeprom_93Cx6.lastCLK) { + if ((eeprom_93Cx6.state >= STATE_STARTBIT) && (eeprom_93Cx6.state < STATE_OPCODE)) { + eeprom_93Cx6.opcode = (eeprom_93Cx6.opcode << 1) | (DAT ? 1 : 0); + } else if ((eeprom_93Cx6.state >= STATE_OPCODE) && (eeprom_93Cx6.state < eeprom_93Cx6.state_address)) { + eeprom_93Cx6.address = (eeprom_93Cx6.address << 1) | (DAT ? 1 : 0); + } else if ((eeprom_93Cx6.state >= eeprom_93Cx6.state_address) && (eeprom_93Cx6.state < eeprom_93Cx6.state_data)) { + if ((eeprom_93Cx6.opcode == OPCODE_WRITE) || (eeprom_93Cx6.opcode == OPCODE_WRITEALL)) { + eeprom_93Cx6.data = (eeprom_93Cx6.data << 1) | (DAT ? 1 : 0); + } else if (eeprom_93Cx6.opcode == OPCODE_READ) { + if (eeprom_93Cx6.wordsize == 16) { + eeprom_93Cx6.output = (eeprom_93Cx6.data & 0x8000) != 0; + } else { + eeprom_93Cx6.output = (eeprom_93Cx6.data & 0x80) != 0; + } + eeprom_93Cx6.data = eeprom_93Cx6.data << 1; + } + } + + eeprom_93Cx6.state++; + if (eeprom_93Cx6.state == eeprom_93Cx6.state_address) { + switch (eeprom_93Cx6.opcode) { + case OPCODE_MISC: + if (eeprom_93Cx6.wordsize == 16) { + eeprom_93Cx6.opcode = (eeprom_93Cx6.address >> 6) + 10; + } else { + eeprom_93Cx6.opcode = (eeprom_93Cx6.address >> 7) + 10; + } + switch (eeprom_93Cx6.opcode) { + case OPCODE_WRITEDISABLE: + eeprom_93Cx6.writeEnabled = FALSE; + eeprom_93Cx6.state = STATE_FINISHED; + break; + case OPCODE_WRITEENABLE: + eeprom_93Cx6.writeEnabled = TRUE; + eeprom_93Cx6.state = STATE_FINISHED; + break; + case OPCODE_ERASEALL: + if (eeprom_93Cx6.writeEnabled) { + int i; + + for (i = 0; i < eeprom_93Cx6.capacity; i++) { + eeprom_93Cx6.storage[i] = 0xFF; + } + } + eeprom_93Cx6.state = STATE_FINISHED; + break; + case OPCODE_WRITEALL: + eeprom_93Cx6.address = 0; + break; + } + break; + case OPCODE_ERASE: + if (eeprom_93Cx6.writeEnabled) { + if (eeprom_93Cx6.wordsize == 16) { + eeprom_93Cx6.storage[(eeprom_93Cx6.address << 1) | 0] = 0xFF; + eeprom_93Cx6.storage[(eeprom_93Cx6.address << 1) | 1] = 0xFF; + } else { + eeprom_93Cx6.storage[eeprom_93Cx6.address] = 0xFF; + } + } + eeprom_93Cx6.state = STATE_FINISHED; + break; + case OPCODE_READ: + if (eeprom_93Cx6.wordsize == 16) { + eeprom_93Cx6.data = eeprom_93Cx6.storage[(eeprom_93Cx6.address << 1) | 0]; + eeprom_93Cx6.data |= (eeprom_93Cx6.storage[(eeprom_93Cx6.address << 1) | 1] << 8); + eeprom_93Cx6.address++; + } else { + eeprom_93Cx6.data = eeprom_93Cx6.storage[eeprom_93Cx6.address++]; + } + break; + } + } else if (eeprom_93Cx6.state == eeprom_93Cx6.state_data) { + if (eeprom_93Cx6.opcode == OPCODE_WRITE) { + if (eeprom_93Cx6.wordsize == 16) { + eeprom_93Cx6.storage[(eeprom_93Cx6.address << 1) | 0] = eeprom_93Cx6.data & 0xFF; + eeprom_93Cx6.storage[(eeprom_93Cx6.address << 1) | 1] = eeprom_93Cx6.data >> 8; + eeprom_93Cx6.address++; + } else { + eeprom_93Cx6.storage[eeprom_93Cx6.address++] = eeprom_93Cx6.data; + } + eeprom_93Cx6.state = STATE_FINISHED; + } else if (eeprom_93Cx6.opcode == OPCODE_WRITEALL) { + if (eeprom_93Cx6.wordsize == 16) { + eeprom_93Cx6.storage[(eeprom_93Cx6.address << 1) | 0] = eeprom_93Cx6.data & 0xFF; + eeprom_93Cx6.storage[(eeprom_93Cx6.address << 1) | 1] = eeprom_93Cx6.data >> 8; + eeprom_93Cx6.address++; + } else { + eeprom_93Cx6.storage[eeprom_93Cx6.address++] = eeprom_93Cx6.data; + } + eeprom_93Cx6.state = (CS && (eeprom_93Cx6.address < eeprom_93Cx6.capacity)) ? eeprom_93Cx6.state_address : STATE_FINISHED; + } else if (eeprom_93Cx6.opcode == OPCODE_READ) { + if (eeprom_93Cx6.address < eeprom_93Cx6.capacity) { + if (eeprom_93Cx6.wordsize == 16) { + eeprom_93Cx6.data = eeprom_93Cx6.storage[(eeprom_93Cx6.address << 1) | 0]; + eeprom_93Cx6.data |= (eeprom_93Cx6.storage[(eeprom_93Cx6.address << 1) | 1] << 8); + } else { + eeprom_93Cx6.data = eeprom_93Cx6.storage[eeprom_93Cx6.address]; + } + } + eeprom_93Cx6.state = (CS && (++eeprom_93Cx6.address <= eeprom_93Cx6.capacity)) ? eeprom_93Cx6.state_address : STATE_FINISHED; + } + } + if (eeprom_93Cx6.state == STATE_FINISHED) { + eeprom_93Cx6.output = FALSE; + eeprom_93Cx6.state = STATE_STANDBY; + } + } + eeprom_93Cx6.lastCLK = CLK; +} diff --git a/src/mappers/hw/eeprom_93Cx6.h b/src/mappers/hw/eeprom_93Cx6.h new file mode 100644 index 000000000..439f4d025 --- /dev/null +++ b/src/mappers/hw/eeprom_93Cx6.h @@ -0,0 +1,28 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _EEPROM_93Cx6_H +#define _EEPROM_93Cx6_H + +void eeprom_93Cx6_init (uint8 *data, uint32 capacity, uint8 wordsize); +uint8 eeprom_93Cx6_read (void); +void eeprom_93Cx6_write (uint8 CS, uint8 CLK, uint8 DAT); + +#endif diff --git a/src/mappers/hw/eeprom_x24c0x.c b/src/mappers/hw/eeprom_x24c0x.c new file mode 100644 index 000000000..0cdcf38de --- /dev/null +++ b/src/mappers/hw/eeprom_x24c0x.c @@ -0,0 +1,258 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2007 CaH4e3 + * Copyright (C) 2011 FCEUX team + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* x24C0x interface */ + +#include "mapinc.h" +#include "eeprom_x24c0x.h" + +#define X24C0X_STANDBY 0 +#define X24C0X_ADDRESS 1 +#define X24C0X_WORD 2 +#define X24C0X_READ 3 +#define X24C0X_WRITE 4 + +struct X24C01 { + uint8 *data; + uint8 state; + uint8 addr; + uint8 word; + uint8 latch; + uint8 bitcount; + uint8 sda; + uint8 scl; + uint8 out; +} X24C01; + +struct X24C02 { + uint8 *data; + uint8 state; + uint8 addr; + uint8 word; + uint8 latch; + uint8 bitcount; + uint8 sda; + uint8 scl; + uint8 out; +} X24C02; + +static struct X24C01 x24c01 = { 0 }; +static struct X24C02 x24c02 = { 0 }; + +SFORMAT x24c01_StateRegs[] = { + { &x24c01.addr, 1, "ADDR" }, + { &x24c01.word, 1, "WORD" }, + { &x24c01.latch, 1, "LATC" }, + { &x24c01.bitcount, 1, "BITC" }, + { &x24c01.sda, 1, "SDA" }, + { &x24c01.scl, 1, "SCL" }, + { &x24c01.out, 1, "OUT" }, + { &x24c01.state, 1, "STAT" }, + { 0 } +}; + +SFORMAT x24c02_StateRegs[] = { + { &x24c02.addr, 1, "ADDR" }, + { &x24c02.word, 1, "WORD" }, + { &x24c02.latch, 1, "LATC" }, + { &x24c02.bitcount, 1, "BITC" }, + { &x24c02.sda, 1, "SDA" }, + { &x24c02.scl, 1, "SCL" }, + { &x24c02.out, 1, "OUT" }, + { &x24c02.state, 1, "STAT" }, + { 0 }, +}; + +void x24c01_init(uint8 *data) { + x24c01.data = data; + x24c01.addr = 0; + x24c01.word = 0; + x24c01.latch = 0; + x24c01.bitcount = 0; + x24c01.sda = 0; + x24c01.scl = 0; + x24c01.state = X24C0X_STANDBY; +} + +void x24c02_init(uint8 *data) { + x24c02.data = data; + x24c02.addr = 0; + x24c02.word = 0; + x24c02.latch = 0; + x24c02.bitcount = 0; + x24c02.sda = 0; + x24c02.scl = 0; + x24c02.state = X24C0X_STANDBY; +} + +uint8 x24c01_read(void) { + return x24c01.out; +} + +void x24c01_write(uint8 V) { + uint8 scl = (V >> 5) & 1; + uint8 sda = (V >> 6) & 1; + + if (x24c01.scl && scl) { + if (x24c01.sda && !sda) { /* START */ + x24c01.state = X24C0X_ADDRESS; + x24c01.bitcount = 0; + x24c01.addr = 0; + } else if (!x24c01.sda && sda) { /* STOP */ + x24c01.state = X24C0X_STANDBY; + } + } else if (!x24c01.scl && scl) { /* RISING EDGE */ + switch (x24c01.state) { + case X24C0X_ADDRESS: + if (x24c01.bitcount < 7) { + x24c01.addr <<= 1; + x24c01.addr |= sda; + } else { + x24c01.word = x24c01.addr; + if (sda) { /* READ COMMAND */ + x24c01.state = X24C0X_READ; + } else { /* WRITE COMMAND */ + x24c01.state = X24C0X_WRITE; + } + } + x24c01.bitcount++; + break; + case X24C0X_READ: + if (x24c01.bitcount == 8) { /* ACK */ + x24c01.out = 0; + x24c01.latch = x24c01.data[x24c01.word]; + x24c01.bitcount = 0; + } else { /* REAL OUTPUT */ + x24c01.out = x24c01.latch >> 7; + x24c01.latch <<= 1; + x24c01.bitcount++; + if (x24c01.bitcount == 8) { + x24c01.word++; + x24c01.word &= 0xff; + } + } + break; + case X24C0X_WRITE: + if (x24c01.bitcount == 8) { /* ACK */ + x24c01.out = 0; + x24c01.latch = 0; + x24c01.bitcount = 0; + } else { /* REAL INPUT */ + x24c01.latch <<= 1; + x24c01.latch |= sda; + x24c01.bitcount++; + if (x24c01.bitcount == 8) { + x24c01.data[x24c01.word] = x24c01.latch; + x24c01.word++; + x24c01.word &= 0xff; + } + } + break; + } + } + + x24c01.sda = sda; + x24c01.scl = scl; +} + +uint8 x24c02_read(void) { + return x24c02.out; +} + +void x24c02_write(uint8 V) { + uint8 scl = (V >> 5) & 1; + uint8 sda = (V >> 6) & 1; + + if (x24c02.scl && scl) { + if (x24c02.sda && !sda) { /* START */ + x24c02.state = X24C0X_ADDRESS; + x24c02.bitcount = 0; + x24c02.addr = 0; + } else if (!x24c02.sda && sda) { /* STOP */ + x24c02.state = X24C0X_STANDBY; + } + } else if (!x24c02.scl && scl) { /* RISING EDGE */ + switch (x24c02.state) { + case X24C0X_ADDRESS: + if (x24c02.bitcount < 7) { + x24c02.addr <<= 1; + x24c02.addr |= sda; + } else { + if (sda) { /* READ COMMAND */ + x24c02.state = X24C0X_READ; + } else { /* WRITE COMMAND */ + x24c02.state = X24C0X_WORD; + } + } + x24c02.bitcount++; + break; + case X24C0X_WORD: + if (x24c02.bitcount == 8) { /* ACK */ + x24c02.word = 0; + x24c02.out = 0; + } else { /* WORD ADDRESS INPUT */ + x24c02.word <<= 1; + x24c02.word |= sda; + if (x24c02.bitcount == 16) { /* END OF ADDRESS INPUT */ + x24c02.bitcount = 7; + x24c02.state = X24C0X_WRITE; + } + } + x24c02.bitcount++; + break; + case X24C0X_READ: + if (x24c02.bitcount == 8) { /* ACK */ + x24c02.out = 0; + x24c02.latch = x24c02.data[x24c02.word]; + x24c02.bitcount = 0; + } else { /* REAL OUTPUT */ + x24c02.out = x24c02.latch >> 7; + x24c02.latch <<= 1; + x24c02.bitcount++; + if (x24c02.bitcount == 8) { + x24c02.word++; + x24c02.word &= 0xff; + } + } + break; + case X24C0X_WRITE: + if (x24c02.bitcount == 8) { /* ACK */ + x24c02.out = 0; + x24c02.latch = 0; + x24c02.bitcount = 0; + } else { /* REAL INPUT */ + x24c02.latch <<= 1; + x24c02.latch |= sda; + x24c02.bitcount++; + if (x24c02.bitcount == 8) { + x24c02.data[x24c02.word] = x24c02.latch; + x24c02.word++; + x24c02.word &= 0xff; + } + } + break; + } + } + + x24c02.sda = sda; + x24c02.scl = scl; +} diff --git a/src/mappers/hw/eeprom_x24c0x.h b/src/mappers/hw/eeprom_x24c0x.h new file mode 100644 index 000000000..4567e208e --- /dev/null +++ b/src/mappers/hw/eeprom_x24c0x.h @@ -0,0 +1,40 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _EEPROM_X24C0X_H +#define _EEPROM_X24C0X_H + +typedef enum { + EEPROM_NONE = 0, + EEPROM_X24C01, + EEPROM_X24C02 +} EEPROM_TYPE; + +void x24c01_init(uint8 *data); +void x24c01_write(uint8 V); +uint8 x24c01_read(void); +extern SFORMAT x24c01_StateRegs[9]; + +void x24c02_init(uint8 *data); +void x24c02_write(uint8 V); +uint8 x24c02_read(void); +extern SFORMAT x24c02_StateRegs[9]; + +#endif /* _EEPROM_X24C0X_H */ diff --git a/src/boards/flashrom.c b/src/mappers/hw/flashrom.c similarity index 88% rename from src/boards/flashrom.c rename to src/mappers/hw/flashrom.c index 4e03c86c4..b9a00c963 100644 --- a/src/boards/flashrom.c +++ b/src/mappers/hw/flashrom.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -34,13 +34,12 @@ static int32 time_out; static SFORMAT FlashStateRegs[] = { { &flash_state, 1, "STAT" }, { &time_out, 4, "TIME" }, - { 0 } }; -#define PRG_OFFSET(A) &Page[A >> 11][A] - flash_data +#define PRG_OFFSET(A) (&Page[(A) >> 11][(A)] - flash_data) -DECLFR(FlashRead) { +DECLFR(FlashROM_Read) { if (flash_state == 0x90) { /* 0: manufacturer id */ /* 1: model id */ @@ -51,10 +50,9 @@ DECLFR(FlashRead) { return flash_data[PRG_OFFSET(A)]; } -DECLFW(FlashWrite) { +DECLFW(FlashROM_Write) { uint32 chip_address = PRG_OFFSET(A); - uint32 cmd = A & 0x7FFF; - int i; + uint32 cmd = chip_address & 0x7FFF; switch (flash_state) { default: @@ -79,6 +77,7 @@ DECLFW(FlashWrite) { if (V == 0x30) { /* sector erase */ if (chip_address < flash_size) { + uint32 i; chip_address &= ~(flash_sect_size - 1); for (i = 0; i < flash_sect_size; i++) { flash_data[chip_address + i] = 0xFF; @@ -87,8 +86,9 @@ DECLFW(FlashWrite) { time_out = flash_sect_size; } } else if ((cmd == flash_addr1) && (V == 0x10)) { + int i; /* chip erase */ - for (i = 0; i <= flash_size; i++) { + for (i = 0; i <= (int)flash_size; i++) { flash_data[i] = 0xFF; } FCEU_printf("Flash chip erased.\n"); @@ -113,7 +113,7 @@ DECLFW(FlashWrite) { /* FCEU_printf("%04x:%02x cmd:%04x state:%02x addr1:%04x addr2:%04x\n", A, V, cmd, flash_state, flash_addr1, flash_addr2); */ } -void FlashCPUHook(int a) { +void FlashROM_CPUCyle(int a) { if (time_out > 0) { time_out -= a; if (time_out <= 0) { @@ -122,7 +122,7 @@ void FlashCPUHook(int a) { } } -void Flash_Init(uint8 *data, uint32 size, uint8 manufacter_id, uint8 model_id, uint32 sector_size, uint32 adr1, uint32 adr2) { +void FlashROM_Init(uint8 *data, uint32 size, uint8 manufacter_id, uint8 model_id, uint32 sector_size, uint32 adr1, uint32 adr2) { flash_data = data; flash_size = size; flash_id[0] = manufacter_id; diff --git a/src/mappers/hw/flashrom.h b/src/mappers/hw/flashrom.h new file mode 100644 index 000000000..19e6c50cb --- /dev/null +++ b/src/mappers/hw/flashrom.h @@ -0,0 +1,30 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef FLASHROM_H +#define FLASHROM_H + +DECLFW(FlashROM_Write); +DECLFR(FlashROM_Read); + +void FlashROM_Init(uint8 *data, uint32 size, uint8 manufacter_id, uint8 model_id, uint32 sector_size, uint32 adr1, uint32 adr2); +void FlashROM_CPUCyle(int a); + +#endif /* FLASHROM_H */ diff --git a/src/mappers/hw/fme7.c b/src/mappers/hw/fme7.c new file mode 100644 index 000000000..9b7b1a7f7 --- /dev/null +++ b/src/mappers/hw/fme7.c @@ -0,0 +1,236 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2002 Xodnizel + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "fme7.h" +#include "s5bsound.h" + +static uint8 IRQa; +static int32 IRQCount; + +FME7 fme7; + +void (*FME7_pwrap)(uint32 A, uint8 V); +void (*FME7_cwrap)(uint32 A, uint8 V); + +void (*FME7_FixWRAM)(void); +void (*FME7_FixPRG)(void); +void (*FME7_FixCHR)(void); +void (*FME7_FixMIR)(void); + +static SFORMAT StateRegs[] = { + { fme7.prg, 4, "PREG" }, + { fme7.chr, 8, "CREG" }, + { &fme7.cmd, 1, "CMDR" }, + { &fme7.mirr, 1, "MIRR" }, + { &IRQa, 1, "IRQA" }, + { &IRQCount, 4, "IRQC" }, + { 0 } +}; + +static void GENPWRAP(uint32 A, uint8 V) { + setprg8(A, V); +} + +static void GENCWRAP(uint32 A, uint8 V) { + setchr1(A, V); +} + +static void GENFIXWRAM(void) { + if (fme7.prg[0] & 0x40) { + setprg8r(0x10, 0x6000, fme7.prg[0] & 0x3F); + } else { + setprg8(0x6000, fme7.prg[0] & 0x3F); + } +} + +static void GENFIXPRG(void) { + FME7_pwrap(0x8000, fme7.prg[1]); + FME7_pwrap(0xA000, fme7.prg[2]); + FME7_pwrap(0xC000, fme7.prg[3]); + FME7_pwrap(0xE000, ~0); +} + +static void GENFIXCHR(void) { + FME7_cwrap(0x0000, fme7.chr[0]); + FME7_cwrap(0x0400, fme7.chr[1]); + FME7_cwrap(0x0800, fme7.chr[2]); + FME7_cwrap(0x0C00, fme7.chr[3]); + FME7_cwrap(0x1000, fme7.chr[4]); + FME7_cwrap(0x1400, fme7.chr[5]); + FME7_cwrap(0x1800, fme7.chr[6]); + FME7_cwrap(0x1C00, fme7.chr[7]); +} + +static void GENFIXMIR(void) { + switch (fme7.mirr & 0x03) { + case 0: setmirror(MI_V); break; + case 1: setmirror(MI_H); break; + case 2: setmirror(MI_0); break; + case 3: setmirror(MI_1); break; + } +} + +static DECLFW(FME7_WRAMWrite) { + if ((fme7.prg[0] & 0xC0) == 0xC0) { + CartBW(A, V); + } +} + +static DECLFR(FME7_WRAMRead) { + if ((fme7.prg[0] & 0xC0) == 0x40) { + return cpu.openbus; + } + return CartBR(A); + +} + +DECLFW(FME7_WriteIndex) { + fme7.cmd = V; +} + +DECLFW(FME7_WriteReg) { + switch (fme7.cmd & 0x0F) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + fme7.chr[fme7.cmd] = V; + FME7_FixCHR(); + break; + case 0x08: case 0x09: case 0x0A: case 0x0B: + fme7.prg[fme7.cmd & 0x03] = V; + FME7_FixPRG(); + FME7_FixWRAM(); + break; + case 0x0C: + fme7.mirr = V; + FME7_FixMIR(); + break; + case 0x0D: + IRQa = V; + X6502_IRQEnd(FCEU_IQEXT); + break; + case 0x0E: + IRQCount = (IRQCount & 0xFF00) | (V & 0xFF); + break; + case 0x0F: + IRQCount = (IRQCount & 0x00FF) | (V << 8); + break; + } +} + +void FME7_Reset(void) { + fme7.prg[0] = 0; + fme7.prg[1] = 0; + fme7.prg[2] = 1; + fme7.prg[3] = ~1; + fme7.chr[0] = 0; + fme7.chr[1] = 1; + fme7.chr[2] = 2; + fme7.chr[3] = 3; + fme7.chr[4] = 4; + fme7.chr[5] = 5; + fme7.chr[6] = 6; + fme7.chr[7] = 7; + fme7.cmd = 0; + IRQCount = ~0; + IRQa = 0; + + FME7_FixPRG(); + FME7_FixCHR(); + FME7_FixMIR(); + FME7_FixWRAM(); +} + +void FME7_Power(void) { + SetReadHandler(0x8000, 0xFFFF, CartBR); + + SetWriteHandler(0x8000, 0x9FFF, FME7_WriteIndex); + SetWriteHandler(0xA000, 0xBFFF, FME7_WriteReg); + + SetReadHandler(0x6000, 0x7FFF, FME7_WRAMRead); + SetWriteHandler(0x6000, 0x7FFF, FME7_WRAMWrite); + + SetWriteHandler(0xC000, 0xDFFF, S5BSound_Write); + SetWriteHandler(0xE000, 0xFFFF, S5BSound_Write); + + if (WRAM) { + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + } + + FME7_Reset(); +} + +static void FME7_Close(void) { +} + +static void FME7_IRQHook(int a) { + if (IRQa) { + IRQCount -= a; + if (IRQCount <= 0) { + X6502_IRQBegin(FCEU_IQEXT); + IRQa = 0; + IRQCount = 0xFFFF; + } + } +} + +static void StateRestore(int version) { + FME7_FixWRAM(); + FME7_FixPRG(); + FME7_FixCHR(); + FME7_FixMIR(); +} + +void FME7_Init(CartInfo *info, int wram, int battery) { + FME7_FixPRG = GENFIXPRG; + FME7_FixCHR = GENFIXCHR; + FME7_FixMIR = GENFIXMIR; + FME7_FixWRAM = GENFIXWRAM; + + FME7_pwrap = GENPWRAP; + FME7_cwrap = GENCWRAP; + + if (wram) { + WRAMSIZE = 8192; + if (info->iNES2) { + WRAMSIZE = info->PRGRamSize + info->PRGRamSaveSize; + } + } + if (WRAMSIZE) { + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + if (battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + } + + info->Power = FME7_Power; + info->Close = FME7_Close; + MapIRQHook = FME7_IRQHook; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + + S5BSound_ESI(); + S5BSound_AddStateInfo(); +} diff --git a/src/mappers/hw/fme7.h b/src/mappers/hw/fme7.h new file mode 100644 index 000000000..305324eae --- /dev/null +++ b/src/mappers/hw/fme7.h @@ -0,0 +1,47 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _FME7_H +#define _FME7_H +typedef struct __FME7 { + uint8 prg[4]; + uint8 chr[8]; + uint8 cmd; + uint8 mirr; +} FME7; + +extern FME7 fme7; + +DECLFW(FME7_WriteIndex); +DECLFW(FME7_WriteReg); + +void FME7_Init(CartInfo *info, int wram, int battery); +void FME7_Power(void); +void FME7_Reset(void); + +extern void (*FME7_FixPRG)(void); +extern void (*FME7_FixCHR)(void); +extern void (*FME7_FixMIR)(void); +extern void (*FME7_FixWRAM)(void); + +extern void (*FME7_pwrap)(uint32 A, uint8 V); +extern void (*FME7_cwrap)(uint32 A, uint8 V); + +#endif /* _FME7_H */ diff --git a/src/mappers/hw/jv001.c b/src/mappers/hw/jv001.c new file mode 100644 index 000000000..bd58d07be --- /dev/null +++ b/src/mappers/hw/jv001.c @@ -0,0 +1,134 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + * 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) + * + * TXC mappers, originally much complex banksitching + * + * 01-22111-000 (05-00002-010) (132, 22211) - MGC-001 Qi Wang + * 01-22110-000 (52S ) - MGC-002 2-in-1 Gun + * 01-22111-100 (02-00002-010) (173 ) - MGC-008 Mahjong Block + * (079 ) - MGC-012 Poke Block + * 01-22110-200 (05-00002-010) (036 ) - MGC-014 Strike Wolf + * 01-22000-400 (05-00002-010) (036 ) - MGC-015 Policeman + * 01-22017-000 (05-PT017-080) (189 ) - MGC-017 Thunder Warrior + * 01-11160-000 (04-02310-000) ( , 11160) - MGC-023 6-in-1 + * 01-22270-000 (05-00002-010) (132, 22211) - MGC-xxx Creatom + * 01-22200-400 (------------) (079 ) - ET.03 F-15 City War + * (172 ) - 1991 Du Ma Racing + * + */ + +/* added 2020-2-16 + * Updated based on latest source + * Mappers 36, 132, 173 + * Mappers 136, 147, 172 + */ + +#include "mapinc.h" +#include "jv001.h" + +JV001 jv001; + +static void Dummyfunc(void) { } +static void (*WSync)(void) = Dummyfunc; + +static SFORMAT StateRegs[] = +{ + { &jv001.accumulator, 1, "ACC0" }, + { &jv001.inverter, 1, "INVR" }, + { &jv001.staging, 1, "STG0" }, + { &jv001.output, 1, "OUT0" }, + { &jv001.increase, 1, "INC0" }, + { &jv001.X, 1, "XFLG" }, + { &jv001.invert, 1, "INVT" }, + { 0 } +}; + +DECLFR(JV001_Read) { + uint8 ret = cpu.openbus; + if ((A & 0x103) == 0x100) { + ret = ((jv001.accumulator & 0x0F) | ((jv001.inverter ^ jv001.invert) & ~0x0F)); + WSync(); + } + return ret; +} + +DECLFW(JV001_Write) { + if (A & 0x8000) { + jv001.output = (jv001.accumulator & 0x0F) | (jv001.inverter & 0xF0); + } else { + switch (A & 0x103) { + case 0x100: + if (jv001.increase) { + jv001.accumulator++; + } else { + jv001.accumulator = ((jv001.accumulator & ~0x0F) | ((jv001.staging ^ jv001.invert) & 0x0F)); + } + break; + case 0x101: + jv001.invert = (V & 0x01) ? 0xFF : 0x00; + break; + case 0x102: + jv001.staging = V & 0x0F; + jv001.inverter = V & ~0x0F; + break; + case 0x103: + jv001.increase = ((V & 0x01) != 0); + break; + } + } + jv001.X = jv001.invert ? jv001.A : jv001.B; + WSync(); +} + +void JV001_Reset(void) { + WSync(); +} + +void JV001_Power(void) { + jv001.output = 0; + jv001.accumulator = 0; + jv001.inverter = 0; + jv001.staging = 0; + jv001.increase = 0; + jv001.invert = 0xFF; + jv001.X = 0; + jv001.A = 0; + jv001.B = 1; + JV001_Reset(); +} + +static void StateRestore(int version) { + WSync(); +} + +void JV001_Init(CartInfo *info, void (*proc)(void)) { + WSync = proc; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/hw/jv001.h b/src/mappers/hw/jv001.h new file mode 100644 index 000000000..a2c0476bd --- /dev/null +++ b/src/mappers/hw/jv001.h @@ -0,0 +1,46 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _JV001_H +#define _JV001_H + +typedef struct __JV001 { + uint8 accumulator; + uint8 inverter; + uint8 staging; + uint8 output; + uint8 increase; + uint8 invert; + uint8 A; + uint8 B; + uint8 X; +} JV001; + +extern JV001 jv001; + +void JV001_Power(void); +void JV001_Reset(void); + +void JV001_Init(CartInfo *info, void (*proc)(void)); + +DECLFR(JV001_Read); +DECLFW(JV001_Write); + +#endif /* _JV001_H */ diff --git a/src/mappers/hw/jyasic.c b/src/mappers/hw/jyasic.c new file mode 100644 index 000000000..d114706da --- /dev/null +++ b/src/mappers/hw/jyasic.c @@ -0,0 +1,520 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * Copyright (C) 2005 CaH4e3 + * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "jyasic.h" + +JYASIC jyasic = { 0 }; + +static uint8 dipSwitch; +static uint8 allow_extended_mirroring; +static uint32 lastPPUAddress; + +uint8 JYASIC_CPUWriteHandlersSet; +writefunc JYASIC_cpuWrite[0x10000]; /* Actual write handlers for CPU write trapping as a method fo IRQ clocking */ + +void (*JYASIC_pwrap)(uint32 A, uint32 V); +void (*JYASIC_wwrap)(uint32 A, uint32 V); +void (*JYASIC_cwrap)(uint32 A, uint32 V); + +uint32 (*JYASIC_GetPRGBank)(uint32 V); +uint32 (*JYASIC_GetCHRBank)(uint32 V); + +static SFORMAT JYASIC_StateRegs[] = { + { jyasic.mode, 4, "TKCO" }, + { jyasic.prg, 4, "PRGB" }, + { jyasic.mul, 2, "MUL" }, + { jyasic.latch, 2, "CLTC" }, + { jyasic.chr, 16, "CHRB" }, + { jyasic.nt, 8, "NMS0" }, + { &jyasic.adder, 1, "ADDE" }, + { &jyasic.test, 1, "REGI" }, + { &jyasic.irq.control, 1, "IRQM" }, + { &jyasic.irq.prescaler, 1, "IRQP" }, + { &jyasic.irq.counter, 1, "IRQC" }, + { &jyasic.irq.xor, 1, "IRQX" }, + { &jyasic.irq.enable, 1, "IRQA" }, + { 0 } +}; + +static uint8 rev(uint8 val) { + return ( + ((val << 6) & 0x40) | + ((val << 4) & 0x20) | + ((val << 2) & 0x10) | + ((val << 0) & 0x08) | + ((val >> 2) & 0x04) | + ((val >> 4) & 0x02) | + ((val >> 6) & 0x01)); +} + +static uint32 GENPRGBANK(uint32 V) { return 0; } +static uint32 GENCHRBANK(uint32 V) { return 0; } + +static void GENPWRAP(uint32 A, uint32 V) { + uint32 bank = JYASIC_GetPRGBank(V); + setprg8(A, bank); +} + +static void GENCWRAP(uint32 A, uint32 V) { + uint32 bank = JYASIC_GetCHRBank(V); + setchr1(A, bank); +} + +static void GENWWRAP(uint32 A, uint32 V) { + uint32 bank = JYASIC_GetPRGBank(V); + setprg8(A, bank); +} + +void JYASIC_FixPRG(void) { + uint8 prgLast = (jyasic.mode[0] & 0x04) ? jyasic.prg[3] : 0xFF; + uint8 prg6000 = 0; + + switch (jyasic.mode[0] & 0x03) { + case 0: + JYASIC_pwrap(0x8000, (prgLast << 2) | 0); + JYASIC_pwrap(0xA000, (prgLast << 2) | 1); + JYASIC_pwrap(0xC000, (prgLast << 2) | 2); + JYASIC_pwrap(0xE000, (prgLast << 2) | 3); + prg6000 = (jyasic.prg[3] << 2) | 3; + break; + case 1: + JYASIC_pwrap(0x8000, (jyasic.prg[1] << 1) | 0); + JYASIC_pwrap(0xA000, (jyasic.prg[1] << 1) | 1); + JYASIC_pwrap(0xC000, (prgLast << 1) | 0); + JYASIC_pwrap(0xE000, (prgLast << 1) | 1); + prg6000 = (jyasic.prg[3] << 1) | 1; + break; + case 2: + JYASIC_pwrap(0x8000, jyasic.prg[0]); + JYASIC_pwrap(0xA000, jyasic.prg[1]); + JYASIC_pwrap(0xC000, jyasic.prg[2]); + JYASIC_pwrap(0xE000, prgLast); + prg6000 = jyasic.prg[3]; + break; + case 3: + JYASIC_pwrap(0x8000, rev(jyasic.prg[0])); + JYASIC_pwrap(0xA000, rev(jyasic.prg[1])); + JYASIC_pwrap(0xC000, rev(jyasic.prg[2])); + JYASIC_pwrap(0xE000, rev(prgLast)); + prg6000 = rev(jyasic.prg[3]); + break; + } + if (jyasic.mode[0] & 0x80) { /* Map ROM */ + JYASIC_wwrap(0x6000, prg6000); + } else if (WRAMSIZE) { /* Otherwise map WRAM if it exists */ + setprg8r(0x10, 0x6000, 0); + } +} + +void JYASIC_FixCHR(void) { + /* MMC4 jyasic.mode[0] with 4 KiB CHR jyasic.mode[0] */ + if (jyasic.mode[3] & 0x80 && (jyasic.mode[0] & 0x18) == 0x08) { + JYASIC_cwrap(0x0000, (jyasic.chr[(jyasic.latch[0] & 2) | 0] << 2) | 0); + JYASIC_cwrap(0x0400, (jyasic.chr[(jyasic.latch[0] & 2) | 0] << 2) | 1); + JYASIC_cwrap(0x0800, (jyasic.chr[(jyasic.latch[0] & 2) | 0] << 2) | 2); + JYASIC_cwrap(0x0C00, (jyasic.chr[(jyasic.latch[0] & 2) | 0] << 2) | 3); + JYASIC_cwrap(0x1000, (jyasic.chr[(jyasic.latch[1] & 2) | 4] << 2) | 0); + JYASIC_cwrap(0x1400, (jyasic.chr[(jyasic.latch[1] & 2) | 4] << 2) | 1); + JYASIC_cwrap(0x1800, (jyasic.chr[(jyasic.latch[1] & 2) | 4] << 2) | 2); + JYASIC_cwrap(0x1C00, (jyasic.chr[(jyasic.latch[1] & 2) | 4] << 2) | 3); + } else { + switch (jyasic.mode[0] & 0x18) { + case 0x00: /* 8 KiB CHR mode */ + JYASIC_cwrap(0x0000, (jyasic.chr[0] << 3) | 0); + JYASIC_cwrap(0x0400, (jyasic.chr[0] << 3) | 1); + JYASIC_cwrap(0x0800, (jyasic.chr[0] << 3) | 2); + JYASIC_cwrap(0x0C00, (jyasic.chr[0] << 3) | 3); + JYASIC_cwrap(0x1000, (jyasic.chr[0] << 3) | 4); + JYASIC_cwrap(0x1400, (jyasic.chr[0] << 3) | 5); + JYASIC_cwrap(0x1800, (jyasic.chr[0] << 3) | 6); + JYASIC_cwrap(0x1C00, (jyasic.chr[0] << 3) | 7); + break; + case 0x08: /* 4 KiB CHR mode */ + JYASIC_cwrap(0x0000, (jyasic.chr[0] << 2) | 0); + JYASIC_cwrap(0x0400, (jyasic.chr[0] << 2) | 1); + JYASIC_cwrap(0x0800, (jyasic.chr[0] << 2) | 2); + JYASIC_cwrap(0x0C00, (jyasic.chr[0] << 2) | 3); + JYASIC_cwrap(0x1000, (jyasic.chr[4] << 2) | 0); + JYASIC_cwrap(0x1400, (jyasic.chr[4] << 2) | 1); + JYASIC_cwrap(0x1800, (jyasic.chr[4] << 2) | 2); + JYASIC_cwrap(0x1C00, (jyasic.chr[4] << 2) | 3); + break; + case 0x10: /* 2 KiB CHR mode */ + JYASIC_cwrap(0x0000, (jyasic.chr[0] << 1) | 0); + JYASIC_cwrap(0x0400, (jyasic.chr[0] << 1) | 1); + JYASIC_cwrap(0x0800, (jyasic.chr[2] << 1) | 0); + JYASIC_cwrap(0x0C00, (jyasic.chr[2] << 1) | 1); + JYASIC_cwrap(0x1000, (jyasic.chr[4] << 1) | 0); + JYASIC_cwrap(0x1400, (jyasic.chr[4] << 1) | 1); + JYASIC_cwrap(0x1800, (jyasic.chr[6] << 1) | 0); + JYASIC_cwrap(0x1C00, (jyasic.chr[6] << 1) | 1); + break; + case 0x18: /* 1 KiB CHR mode */ + JYASIC_cwrap(0x0000, jyasic.chr[0]); + JYASIC_cwrap(0x0400, jyasic.chr[1]); + JYASIC_cwrap(0x0800, jyasic.chr[2]); + JYASIC_cwrap(0x0C00, jyasic.chr[3]); + JYASIC_cwrap(0x1000, jyasic.chr[4]); + JYASIC_cwrap(0x1400, jyasic.chr[5]); + JYASIC_cwrap(0x1800, jyasic.chr[6]); + JYASIC_cwrap(0x1C00, jyasic.chr[7]); + break; + } + } + + PPUCHRRAM = (jyasic.mode[2] & 0x40) ? 0xFF : 0x00; /* Write-protect or write-enable CHR-RAM */ +} + +void JYASIC_FixMIR(void) { + if (jyasic.mode[0] & 0x20 || jyasic.mode[1] & 0x08) { + /* ROM nametables or extended mirroring */ + /* First, set normal CIRAM pages using extended registers ... */ + setmirrorw(jyasic.nt[0] & 1, jyasic.nt[1] & 1, jyasic.nt[2] & 1, jyasic.nt[3] & 1); + + if (jyasic.mode[0] & 0x20) { + int i; + for (i = 0; i < 4; i++) { + /* Then replace with ROM nametables if such are generally enabled */ + /* ROM nametables are used either when globally enabled via + * D000.6 or per-bank via B00x.7 vs. D002.7 */ + if (((jyasic.nt[i] & 0x80) ^ (jyasic.mode[2] & 0x80)) | (jyasic.mode[0] & 0x40)) { + setntamem(CHRptr[0] + 0x400 * (JYASIC_GetCHRBank(jyasic.nt[i]) & CHRmask1[0]), 0, i); + } + } + } + } else { + switch (jyasic.mode[1] & 0x03) { + /* Regularly mirrored CIRAM */ + case 0: setmirror(MI_V); break; + case 1: setmirror(MI_H); break; + case 2: setmirror(MI_0); break; + case 3: setmirror(MI_1); break; + } + } +} + +static void clockIRQ(void) { + uint8 mask = jyasic.irq.control & 0x04 ? 0x07 : 0xFF; + uint8 prescaler = jyasic.irq.prescaler & mask; + uint8 clockIrqCounter = FALSE; + + if (jyasic.irq.enable) { + switch (jyasic.irq.control & 0xC0) { + case 0x40: + prescaler++; + if ((prescaler & mask) == 0) { + clockIrqCounter = TRUE; + } + break; + case 0x80: + if (--prescaler == 0) { + clockIrqCounter = TRUE; + } + break; + } + + jyasic.irq.prescaler = (jyasic.irq.prescaler & ~mask) | (prescaler & mask); + + if (clockIrqCounter) { + switch (jyasic.irq.control & 0xC0) { + case 0x40: + if ((jyasic.irq.control & 0x08) == 0) { + jyasic.irq.counter++; + } + if (jyasic.irq.counter == 0x00) { + X6502_IRQBegin(FCEU_IQEXT); + } + break; + case 0x80: + if ((jyasic.irq.control & 0x08) == 0) { + jyasic.irq.counter--; + } + if (jyasic.irq.counter == 0xFF) { + X6502_IRQBegin(FCEU_IQEXT); + } + break; + } + } + } +} + +DECLFW(JYASIC_trapCPUWrite) { + if ((jyasic.irq.control & 0x03) == 0x03) { + clockIRQ(); /* Clock IRQ counter on CPU writes */ + } + JYASIC_cpuWrite[A](A, V); +} + +static void trapPPUAddressChange(uint32 A) { + if (((jyasic.irq.control & 0x03) == 0x02) && (lastPPUAddress != A)) { + int i; + for (i = 0; i < 2; i++) { + clockIRQ(); /* Clock IRQ counter on PPU "reads" */ + } + } + if ((jyasic.mode[3] & 0x80) && ((jyasic.mode[0] & 0x18) == 0x08) && (((A & 0x2FF0) == 0xFD0) || ((A & 0x2FF0) == 0xFE0))) { + /* If MMC4 jyasic.mode[0] is enabled, and CHR jyasic.mode[0] is 4 KiB, and tile FD or FE is being fetched ... */ + jyasic.latch[(A >> 12) & 1] = ((A >> 10) & 4) | ((A >> 4) & 2); /* switch the left or right pattern table's latch to 0 (FD) or 2 (FE), + * being used as an offset for the CHR register index. */ + JYASIC_FixCHR(); + } + lastPPUAddress = A; +} + +static void ppuScanline(void) { + if ((jyasic.irq.control & 0x03) == 0x01) { + int i; + for (i = 0; i < 8; i++) { + clockIRQ(); /* Clock IRQ counter on A12 rises (eight per scanline). This should be done in + trapPPUAddressChange, but would require more accurate PPU emulation for that. */ + } + } +} + +static void cpuCycle(int a) { + if ((jyasic.irq.control & 0x03) == 0x00) { + while (a--) { + clockIRQ(); /* Clock IRQ counter on M2 cycles */ + } + } +} + +DECLFR(JYASIC_ReadALU_DIP) { + if ((A & 0x3FF) == 0 && + A != 0x5800) { /* 5000, 5400, 5C00: read solder pad setting */ + return dipSwitch | (cpu.openbus & 0x3F); + } + + if (A & 0x800) { + switch (A & 3) { + /* 5800-5FFF: read ALU */ + case 0: return (jyasic.mul[0] * jyasic.mul[1]) & 0xFF; + case 1: return (jyasic.mul[0] * jyasic.mul[1]) >> 8; + case 2: return jyasic.adder; + case 3: return jyasic.test; + } + } + /* all others */ + return cpu.openbus; +} + +DECLFW(JYASIC_WriteALU) { + switch (A & 3) { + case 0: jyasic.mul[0] = V; break; + case 1: jyasic.mul[1] = V; break; + case 2: jyasic.adder += V; break; + case 3: jyasic.test = V; jyasic.adder = 0; break; + } +} + +DECLFW(JYASIC_WritePRG) { + jyasic.prg[A & 3] = V; + JYASIC_FixPRG(); +} + +DECLFW(JYASIC_WriteCHRLow) { + jyasic.chr[A & 7] = (jyasic.chr[A & 7] & 0xFF00) | V; + JYASIC_FixCHR(); +} + +DECLFW(JYASIC_WriteCHRHigh) { + jyasic.chr[A & 7] = (jyasic.chr[A & 7] & 0x00FF) | V << 8; + JYASIC_FixCHR(); +} + +DECLFW(JYASIC_WriteNT) { + if (~A & 4) { + jyasic.nt[A & 3] = (jyasic.nt[A & 3] & 0xFF00) | V; + } else { + jyasic.nt[A & 3] = (jyasic.nt[A & 3] & 0x00FF) | V << 8; + } + JYASIC_FixMIR(); +} + +DECLFW(JYASIC_WriteIRQ) { + switch (A & 7) { + case 0: + jyasic.irq.enable = !!(V & 1); + if (!jyasic.irq.enable) { + jyasic.irq.prescaler = 0; + X6502_IRQEnd(FCEU_IQEXT); + } + break; + case 1: + jyasic.irq.control = V; + break; + case 2: + jyasic.irq.enable = 0; + jyasic.irq.prescaler = 0; + X6502_IRQEnd(FCEU_IQEXT); + break; + case 3: + jyasic.irq.enable = 1; + break; + case 4: + jyasic.irq.prescaler = V ^ jyasic.irq.xor; + break; + case 5: + jyasic.irq.counter = V ^ jyasic.irq.xor; + break; + case 6: + jyasic.irq.xor = V; + break; + } +} + +DECLFW(JYASIC_WriteMode) { + switch (A & 3) { + case 0: + jyasic.mode[0] = V; + if (!allow_extended_mirroring) { + jyasic.mode[0] &= ~0x20; + } + break; + case 1: + jyasic.mode[1] = V; + if (!allow_extended_mirroring) { + jyasic.mode[1] &= ~0x08; + } + break; + case 2: + jyasic.mode[2] = V; + break; + case 3: + jyasic.mode[3] = V; + break; + } + JYASIC_FixPRG(); + JYASIC_FixCHR(); + JYASIC_FixMIR(); +} + +void JYASIC_restoreWriteHandlers(void) { + int i; + if (JYASIC_CPUWriteHandlersSet) { + for (i = 0; i < 0x10000; i++) { + SetWriteHandler(i, i, JYASIC_cpuWrite[i]); + } + JYASIC_CPUWriteHandlersSet = 0; + } +} + +void JYASIC_RegReset(void) { + memset(jyasic.mode, 0, sizeof(jyasic.mode)); + memset(jyasic.prg, 0, sizeof(jyasic.prg)); + memset(jyasic.chr, 0, sizeof(jyasic.chr)); + memset(jyasic.nt, 0, sizeof(jyasic.nt)); + memset(jyasic.mul, 0, sizeof(jyasic.mul)); + + jyasic.adder = jyasic.test = dipSwitch = 0; + jyasic.irq.control = jyasic.irq.enable = 0; + jyasic.irq.prescaler = jyasic.irq.counter = 0; + jyasic.irq.xor = lastPPUAddress = 0; + + jyasic.latch[0] = 0; + jyasic.latch[1] = 4; + + JYASIC_FixPRG(); + JYASIC_FixCHR(); + JYASIC_FixMIR(); +} + +void JYASIC_Power(void) { + int i; + + SetWriteHandler(0x5000, 0x5FFF, JYASIC_WriteALU); + SetWriteHandler(0x6000, 0x7fff, CartBW); + SetWriteHandler(0x8000, 0x87FF, JYASIC_WritePRG); /* 8800-8FFF ignored */ + SetWriteHandler(0x9000, 0x97FF, JYASIC_WriteCHRLow); /* 9800-9FFF ignored */ + SetWriteHandler(0xA000, 0xA7FF, JYASIC_WriteCHRHigh); /* A800-AFFF ignored */ + SetWriteHandler(0xB000, 0xB7FF, JYASIC_WriteNT); /* B800-BFFF ignored */ + SetWriteHandler(0xC000, 0xCFFF, JYASIC_WriteIRQ); + SetWriteHandler(0xD000, 0xD7FF, JYASIC_WriteMode); /* D800-DFFF ignored */ + + JYASIC_restoreWriteHandlers(); + for (i = 0; i < 0x10000; i++) { + JYASIC_cpuWrite[i] = GetWriteHandler(i); + } + SetWriteHandler(0x0000, 0xFFFF, JYASIC_trapCPUWrite); /* Trap all CPU writes for IRQ clocking purposes */ + JYASIC_CPUWriteHandlersSet = 1; + + SetReadHandler(0x5000, 0x5FFF, JYASIC_ReadALU_DIP); + SetReadHandler(0x6000, 0xFFFF, CartBR); + + JYASIC_RegReset(); +} + +void JYASIC_Reset(void) { + dipSwitch = (dipSwitch + 0x40) & 0xC0; + JYASIC_FixPRG(); + JYASIC_FixCHR(); + JYASIC_FixMIR(); +} + +void JYASIC_Close(void) { +} + +static void StateRestore(int version) { + JYASIC_FixPRG(); + JYASIC_FixCHR(); + JYASIC_FixMIR(); +} + +void JYASIC_Init(CartInfo *info, int extended_mirr) { + JYASIC_pwrap = GENPWRAP; + JYASIC_wwrap = GENWWRAP; + JYASIC_cwrap = GENCWRAP; + + JYASIC_GetPRGBank = GENPRGBANK; + JYASIC_GetCHRBank = GENCHRBANK; + + allow_extended_mirroring = extended_mirr; + + JYASIC_CPUWriteHandlersSet = 0; + info->Reset = JYASIC_Reset; + info->Power = JYASIC_Power; + info->Close = JYASIC_Close; + + PPU_hook = trapPPUAddressChange; + MapIRQHook = cpuCycle; + GameHBIRQHook2 = ppuScanline; + + AddExState(JYASIC_StateRegs, ~0, 0, 0); + GameStateRestore = StateRestore; + + /* WRAM is present only in iNES mapper 35, or in mappers with numbers above 255 that require NES 2.0, which + * explicitly denotes WRAM size */ + if (info->iNES2) { + WRAMSIZE = info->PRGRamSize + info->PRGRamSaveSize; + } else { + WRAMSIZE = info->mapper == 35 ? 8192 : 0; + } + + if (WRAMSIZE) { + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + } +} diff --git a/src/mappers/hw/jyasic.h b/src/mappers/hw/jyasic.h new file mode 100644 index 000000000..8316f1b42 --- /dev/null +++ b/src/mappers/hw/jyasic.h @@ -0,0 +1,75 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _JYASIC_H +#define _JYASIC_H + +typedef struct __JYASIC { + uint8 mode[4]; + uint8 prg[4]; + uint8 mul[2]; + uint8 adder; + uint8 test; + uint8 latch[2]; + uint16 chr[8]; + uint16 nt[4]; + struct irq { + uint8 control; + uint8 enable; + uint8 prescaler; + uint8 counter; + uint8 xor; + } irq; +} JYASIC; + +extern JYASIC jyasic; + +extern uint8 JYASIC_CPUWriteHandlersSet; +extern writefunc JYASIC_cpuWrite[0x10000]; + +DECLFR(JYASIC_ReadALU_DIP); +DECLFW(JYASIC_trapCPUWrite); +DECLFW(JYASIC_WriteALU); +DECLFW(JYASIC_WritePRG); +DECLFW(JYASIC_WriteCHRLow); +DECLFW(JYASIC_WriteCHRHigh); +DECLFW(JYASIC_WriteNT); +DECLFW(JYASIC_WriteIRQ); +DECLFW(JYASIC_WriteMode); + +void JYASIC_restoreWriteHandlers(void); +void JYASIC_RegReset(void); +void JYASIC_Reset(void); +void JYASIC_Close(void); +void JYASIC_Power(void); +void JYASIC_Init(CartInfo * info, int extended_mirr); + +void JYASIC_FixPRG(void); +void JYASIC_FixCHR(void); +void JYASIC_FixMIR(void); + +extern void (*JYASIC_pwrap)(uint32 A, uint32 V); +extern void (*JYASIC_wwrap)(uint32 A, uint32 V); +extern void (*JYASIC_cwrap)(uint32 A, uint32 V); + +extern uint32 (*JYASIC_GetPRGBank)(uint32 V); +extern uint32 (*JYASIC_GetCHRBank)(uint32 V); + +#endif /* _JYASIC_H */ diff --git a/src/mappers/hw/ks202.c b/src/mappers/hw/ks202.c new file mode 100644 index 000000000..d72f161bd --- /dev/null +++ b/src/mappers/hw/ks202.c @@ -0,0 +1,137 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2007 CaH4e3 + * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + * KS202 Asic, used for Mapper 142, and Mapper 56 with extra PAL chip + * + */ + +#include "mapinc.h" +#include "ks202.h" + +static uint8 IRQa = 0; +static int32 IRQCount, IRQLatch; + +static void (*WSync)(void); + +KS202 ks202 = { 0 }; + +static SFORMAT StateRegs[] = +{ + { &ks202.cmd, 1, "CMD" }, + { ks202.reg, 8, "REGS" }, + { &IRQa, 1, "IRQA" }, + { &IRQCount, 4, "IRQC" }, + { 0 } +}; + +DECLFW(KS202_Write) { +/* FCEU_printf("bs %04x %02x\n",A,V); */ + switch (A & 0xF000) { + 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: + ks202.cmd = V & 7; + break; + case 0xF000: + ks202.reg[ks202.cmd] = V; + WSync(); + break; + } +} + +static void KS202IRQHook(int a) { + if (IRQa) { + IRQCount += a; + if (IRQCount >= 0xFFFF) { + IRQa = 0; + IRQCount = IRQLatch; + X6502_IRQBegin(FCEU_IQEXT); + } + } +} + +void KS202_Power(void) { + KS202_Reset(); + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, KS202_Write); + if (WRAMSIZE) { + SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + } +} + +void KS202_Reset(void) { + ks202.reg[0] = ks202.reg[1] = ks202.reg[2] = ks202.reg[3] = 0; + ks202.reg[4] = ks202.reg[5] = ks202.reg[6] = ks202.reg[7] = 0; + ks202.cmd = 0; + IRQa = IRQCount = IRQLatch = 0; + WSync(); +} + +void KS202_Close(void) { +} + +void KS202_Restore(int version) { + WSync(); +} + +void KS202_Init(CartInfo *info, void (*proc)(void), int wram, int battery) { + WSync = proc; + + info->Power = KS202_Power; + info->Close = KS202_Close; + MapIRQHook = KS202IRQHook; + GameStateRestore = KS202_Restore; + + AddExState(StateRegs, ~0, 0, NULL); + + if (wram) { + WRAMSIZE = 8 * 1024; + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + if (battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + } +} diff --git a/src/mappers/hw/ks202.h b/src/mappers/hw/ks202.h new file mode 100644 index 000000000..f06c352d5 --- /dev/null +++ b/src/mappers/hw/ks202.h @@ -0,0 +1,40 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _KS202_H +#define _KS202_H + +typedef struct __KS202 { + uint8 reg[8]; + uint8 cmd; +} KS202; + +extern KS202 ks202; + +DECLFW(KS202_Write); + +void KS202_Power(void); +void KS202_Close(void); +void KS202_Reset(void); +void KS202_Restore(int version); + +void KS202_Init(CartInfo *info, void (*proc)(void), int wram, int battery); + +#endif /* _KS202_H */ diff --git a/src/boards/latch.c b/src/mappers/hw/latch.c similarity index 79% rename from src/boards/latch.c rename to src/mappers/hw/latch.c index 57f672fc8..63cc7454c 100644 --- a/src/boards/latch.c +++ b/src/mappers/hw/latch.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,45 +22,39 @@ #include "latch.h" static uint8 bus_conflict; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; static void (*WSync)(void); static readfunc defread; LATCH latch; -DECLFW(LatchWrite) { +DECLFW(Latch_Write) { /* FCEU_printf("bs %04x %02x\n",A,V); */ - if (bus_conflict) + if (bus_conflict) { V &= CartBR(A); + } latch.addr = A; latch.data = V; WSync(); } -void LatchHardReset() { +void Latch_RegReset(void) { latch.addr = 0; latch.data = 0; WSync(); } -void LatchPower(void) { - LatchHardReset(); - WSync(); +void Latch_Power(void) { + Latch_RegReset(); if (WRAM) { - SetReadHandler(0x6000, 0xFFFF, CartBR); + SetReadHandler(0x6000, 0x7FFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); - } else { - SetReadHandler(0x8000, 0xFFFF, defread); } - SetWriteHandler(0x8000, 0xFFFF, LatchWrite); + SetReadHandler(0x8000, 0xFFFF, defread); + SetWriteHandler(0x8000, 0xFFFF, Latch_Write); } -void LatchClose(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; +void Latch_Close(void) { } static void LatchReset(void) { @@ -79,8 +73,8 @@ void Latch_Init(CartInfo *info, void (*proc)(void), readfunc func, defread = func; else defread = CartBROB; - info->Power = LatchPower; - info->Close = LatchClose; + info->Power = Latch_Power; + info->Close = Latch_Close; info->Reset = LatchReset; GameStateRestore = StateRestore; if (wram) { diff --git a/src/mappers/hw/latch.h b/src/mappers/hw/latch.h new file mode 100644 index 000000000..22b36f6d3 --- /dev/null +++ b/src/mappers/hw/latch.h @@ -0,0 +1,39 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _FCEU_LATCH_H +#define _FCEU_LATCH_H + +typedef struct __LATCH { + uint16 addr; + uint8 data; +} LATCH; + +extern LATCH latch; + +DECLFW(Latch_Write); + +void Latch_Power(void); +void Latch_Close(void); +void Latch_RegReset(void); + +void Latch_Init(CartInfo *info, void (*proc)(void), readfunc func, uint8 wram, uint8 busc); + +#endif /* _FCEU_LATCH_H */ diff --git a/src/mappers/hw/mmc1.c b/src/mappers/hw/mmc1.c new file mode 100644 index 000000000..8a5f75e95 --- /dev/null +++ b/src/mappers/hw/mmc1.c @@ -0,0 +1,279 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 1998 BERO + * Copyright (C) 2002 Xodnizel + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "mmc1.h" + + /* size of non-battery-backed portion of WRAM */ + /* serves as starting offset for actual save ram from total wram size */ + /* returns 0 if entire work ram is battery backed ram */ +static uint32 NONSaveRAMSIZE = 0; + +MMC1Type mmc1_type = MMC1B; + +void (*MMC1_pwrap)(uint32 A, uint8 V); +void (*MMC1_cwrap)(uint32 A, uint8 V); +void (*MMC1_mwrap)(uint8 V); +void (*MMC1_wwrap)(void); + +MMC1 mmc1; + +static void GENWRAMWRAP(void) { + uint8 bank = 0; + + if (!WRAMSIZE) { + return; + } + if (WRAMSIZE > 8192) { + if (WRAMSIZE > 16384) { + bank = (mmc1.reg[1] >> 2) & 3; + } else { + bank = (mmc1.reg[1] >> 3) & 1; + } + } + setprg8r(0x10, 0x6000, bank); +} + +static void GENPWRAP(uint32 A, uint8 V) { + setprg16(A, V & 0x0F); +} + +static void GENCWRAP(uint32 A, uint8 V) { + setchr4(A, V & 0x1F); +} + +static uint8 MMC1WRAMEnabled(void) { + if ((mmc1.reg[3] & 0x10) && (mmc1_type == MMC1B)) { + return FALSE; + } + + return TRUE; +} + +static DECLFW(MBWRAM) { + if (MMC1WRAMEnabled()) { + /* WRAM is enabled. */ + CartBW(A, V); + } +} + +static DECLFR(MAWRAM) { + if (!MMC1WRAMEnabled()) { + /* WRAM is disabled */ + return cpu.openbus; + } + + return CartBR(A); +} + +uint32 MMC1_GetPRGBank(int index) { + uint32 bank; + uint8 prg = mmc1.reg[3]; + + switch (mmc1.reg[0] & 0xC) { + case 0xC: + bank = prg | (index * 0x0F); + break; + case 0x8: + bank = (prg & (index * 0x0F)); + break; + case 0x0: + case 0x4: + default: + bank = (prg & ~1) | index; + break; + } + + if ((mmc1.reg[3] & 0x10) && (mmc1_type == MMC1A)) { + return ((bank & 0x07) | (mmc1.reg[3] & 0x08)); + } + + return (bank & 0x0F); +} + +uint32 MMC1_GetCHRBank(int index) { + if (mmc1.reg[0] & 0x10) { + return (mmc1.reg[1 + index]); + } + + return ((mmc1.reg[1] & ~1) | index); +} + +void MMC1_FixCHR(void) { + if (MMC1_wwrap) { + MMC1_wwrap(); + } + + MMC1_cwrap(0x0000, MMC1_GetCHRBank(0)); + MMC1_cwrap(0x1000, MMC1_GetCHRBank(1)); +} + +void MMC1_FixPRG(void) { + MMC1_pwrap(0x8000, MMC1_GetPRGBank(0)); + MMC1_pwrap(0xC000, MMC1_GetPRGBank(1)); +} + +void MMC1_FixMIR(void) { + switch (mmc1.reg[0] & 3) { + case 2: setmirror(MI_V); break; + case 3: setmirror(MI_H); break; + case 0: setmirror(MI_0); break; + case 1: setmirror(MI_1); break; + } +} + +static uint64 lreset; +DECLFW(MMC1_Write) { + int n = (A >> 13) - 4; + + /* The MMC1 is busy so ignore the write. */ + /* As of version FCE Ultra 0.81, the timestamp is only + increased before each instruction is executed(in other words + precision isn't that great), but this should still work to + deal with 2 writes in a row from a single RMW instruction. + */ + if ((timestampbase + timestamp) < (lreset + 2)) { + return; + } + + /* FCEU_printf("Write %04x:%02x\n",A,V); */ + if (V & 0x80) { + mmc1.reg[0] |= 0xC; + mmc1.shift = mmc1.buffer = 0; + MMC1_FixPRG(); + lreset = timestampbase + timestamp; + return; + } + + mmc1.buffer |= (V & 1) << (mmc1.shift++); + + if (mmc1.shift == 5) { + /* FCEU_printf("REG[%d]=%02x\n",n,mmc1.buffer); */ + mmc1.reg[n] = mmc1.buffer; + mmc1.shift = mmc1.buffer = 0; + switch (n) { + case 0: + MMC1_FixMIR(); + MMC1_FixCHR(); + MMC1_FixPRG(); + break; + case 1: + MMC1_FixCHR(); + MMC1_FixPRG(); + break; + case 2: + MMC1_FixCHR(); + break; + case 3: + MMC1_FixPRG(); + break; + } + } +} + +void MMC1_Restore(int version) { + MMC1_FixMIR(); + MMC1_FixCHR(); + MMC1_FixPRG(); + lreset = 0; /* timestamp(base) is not stored in save states. */ +} + +void MMC1_Reset(void) { + mmc1.reg[0] = 0x0C; + mmc1.reg[1] = 0; + mmc1.reg[2] = 0; + mmc1.reg[3] = 0; + + mmc1.buffer = mmc1.shift = 0; + + MMC1_FixPRG(); + MMC1_FixCHR(); + MMC1_FixMIR(); +} + +void MMC1_Power(void) { + lreset = 0; + SetWriteHandler(0x8000, 0xFFFF, MMC1_Write); + SetReadHandler(0x8000, 0xFFFF, CartBR); + + if (WRAMSIZE) { + FCEU_CheatAddRAM(8, 0x6000, WRAM); + + /* clear non-battery-backed portion of WRAM */ + if (NONSaveRAMSIZE) { + FCEU_MemoryRand(WRAM, NONSaveRAMSIZE); + } + + SetReadHandler(0x6000, 0x7FFF, MAWRAM); + SetWriteHandler(0x6000, 0x7FFF, MBWRAM); + setprg8r(0x10, 0x6000, 0); + } + + MMC1_Reset(); +} + +void MMC1_Close(void) { +} + +void MMC1_Init(CartInfo *info, int wram, int saveram) { + MMC1_pwrap = GENPWRAP; + MMC1_cwrap = GENCWRAP; + MMC1_wwrap = GENWRAMWRAP; + + WRAMSIZE = wram * 1024; + NONSaveRAMSIZE = (wram - saveram) * 1024; + + if (WRAMSIZE) { + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + if (saveram) { + info->SaveGame[0] = WRAM + NONSaveRAMSIZE; + info->SaveGameLen[0] = saveram * 1024; + } + } + + AddExState(mmc1.reg, 4, 0, "DREG"); + + info->Power = MMC1_Power; + info->Close = MMC1_Close; + GameStateRestore = MMC1_Restore; + AddExState(&lreset, 8, 1, "LRST"); + AddExState(&mmc1.buffer, 1, 1, "BFFR"); + AddExState(&mmc1.shift, 1, 1, "BFRS"); +} + +void SAROM_Init(CartInfo *info) { + MMC1_Init(info, 8, info->battery ? 8 : 0); +} + +void SKROM_Init(CartInfo *info) { + MMC1_Init(info, 8, info->battery ? 8 : 0); +} + +void SNROM_Init(CartInfo *info) { + MMC1_Init(info, 8, info->battery ? 8 : 0); +} + +void SOROM_Init(CartInfo *info) { + MMC1_Init(info, 16, info->battery ? 8 : 0); +} diff --git a/src/mappers/hw/mmc1.h b/src/mappers/hw/mmc1.h new file mode 100644 index 000000000..c36d91795 --- /dev/null +++ b/src/mappers/hw/mmc1.h @@ -0,0 +1,59 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _MMC1_H +#define _MMC1_H + +typedef enum { + MMC1A, + MMC1B +} MMC1Type; + +typedef struct __MMC1 { + uint8 reg[4]; + uint8 buffer; + uint8 shift; +} MMC1; + +extern MMC1 mmc1; +extern MMC1Type mmc1_type; + +uint32 MMC1_GetPRGBank(int index); +uint32 MMC1_GetCHRBank(int index); + +DECLFW(MMC1_Write); + +void MMC1_Power(void); +void MMC1_Close(void); +void MMC1_Restore(int version); +void MMC1_Reset(void); + +void MMC1_Init(CartInfo *info, int wram, int saveram); + +void MMC1_FixPRG(void); +void MMC1_FixCHR(void); +void MMC1_FixMIR(void); + +extern void (*MMC1_pwrap)(uint32 A, uint8 V); +extern void (*MMC1_cwrap)(uint32 A, uint8 V); +extern void (*MMC1_mwrap)(uint8 V); +extern void (*MMC1_wwrap)(void); + +#endif /* _MMC1_H */ diff --git a/src/mappers/hw/mmc2.c b/src/mappers/hw/mmc2.c new file mode 100644 index 000000000..36d804d70 --- /dev/null +++ b/src/mappers/hw/mmc2.c @@ -0,0 +1,150 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2002 Xodnizel + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "mmc2.h" + +void (*MMC2_pwrap)(uint32 A, uint8 V); +void (*MMC2_cwrap)(uint32 A, uint8 V); +void (*MMC2_mwrap)(uint8 V); + +MMC2 mmc2; + +static SFORMAT StateRegs[] = +{ + { mmc2.chr, 4, "CREG" }, + { mmc2.latch, 2, "PPUL" }, + { &mmc2.prg, 1, "PREG" }, + { &mmc2.mirr, 1, "MIRR" }, + { 0 } +}; + +static void GENPWRAP(uint32 A, uint8 V) { + setprg8(A, V); +} + +static void GENCWRAP(uint32 A, uint8 V) { + setchr4(A, V); +} + +static void GENMWRAP(uint8 V) { + mmc2.mirr = V; + setmirror((mmc2.mirr & 1) ^ 1); +} + +void MMC2_FixPRG(void) { + MMC2_pwrap(0x8000, mmc2.prg); + MMC2_pwrap(0xA000, ~2); + MMC2_pwrap(0xC000, ~1); + MMC2_pwrap(0xE000, ~0); +} + +void MMC2_FixCHR(void) { + MMC2_cwrap(0x0000, mmc2.chr[mmc2.latch[0] | 0]); + MMC2_cwrap(0x1000, mmc2.chr[mmc2.latch[1] | 2]); + + if (MMC2_mwrap) { + MMC2_mwrap(mmc2.mirr); + } +} + +DECLFW(MMC2_Write) { + switch (A & 0xF000) { + case 0xA000: + mmc2.prg = V; + MMC2_FixPRG(); + break; + case 0xB000: + case 0xC000: + case 0xD000: + case 0xE000: + mmc2.chr[(A - 0xB000) >> 12] = V; + MMC2_FixCHR(); + break; + case 0xF000: + if (MMC2_mwrap) { + MMC2_mwrap(V); + } + break; + } +} + +static void MMC2PPUHook(uint32 A) { + uint8 bank = (A >> 12) & 0x01; + if ((A & 0x2000) || (((A & 0xFF0) != 0xFD0) && ((A & 0xFF0) != 0xFE0))) { + return; + } + mmc2.latch[bank] = (A >> 5) & 0x01; + MMC2_FixCHR(); +} + +void MMC2_Reset(void) { + mmc2.prg = mmc2.mirr = 0; + mmc2.latch[0] = mmc2.latch[1] = 0; + MMC2_FixPRG(); + MMC2_FixCHR(); +} + +void MMC2_Power(void) { + MMC2_Reset(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0xA000, 0xFFFF, MMC2_Write); + if (WRAMSIZE) { + setprg8r(0x10, 0x6000, 0); + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + } +} + +void MMC2_Restore(int version) { + MMC2_FixPRG(); + MMC2_FixCHR(); +} + +void MMC2_Close(void) { +} + +void MMC2_Init(CartInfo *info, int wram, int battery) { + MMC2_pwrap = GENPWRAP; + MMC2_cwrap = GENCWRAP; + MMC2_mwrap = GENMWRAP; + + info->Power = MMC2_Power; + info->Close = MMC2_Close; + PPU_hook = MMC2PPUHook; + + GameStateRestore = MMC2_Restore; + AddExState(StateRegs, ~0, 0, NULL); + + if (wram) { + WRAMSIZE = wram * 1024; + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + if (battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + } +} diff --git a/src/mappers/hw/mmc2.h b/src/mappers/hw/mmc2.h new file mode 100644 index 000000000..b61f4fa24 --- /dev/null +++ b/src/mappers/hw/mmc2.h @@ -0,0 +1,48 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _MMC2_H +#define _MMC2_H + +typedef struct __MMC2 { + uint8 prg; + uint8 chr[4]; + uint8 latch[2]; + uint8 mirr; +} MMC2; + +extern MMC2 mmc2; + +DECLFW(MMC2_Write); + +void MMC2_Power(void); +void MMC2_Close(void); +void MMC2_Reset(void); +void MMC2_Restore(int version); +void MMC2_Init(CartInfo *info, int wram, int battery); + +void MMC2_FixPRG(void); +void MMC2_FixCHR(void); + +extern void (*MMC2_pwrap)(uint32 A, uint8 V); +extern void (*MMC2_cwrap)(uint32 A, uint8 V); +extern void (*MMC2_mwrap)(uint8 V); + +#endif /* _MMC2_H */ diff --git a/src/mappers/hw/mmc3.c b/src/mappers/hw/mmc3.c new file mode 100644 index 000000000..ea124e9d4 --- /dev/null +++ b/src/mappers/hw/mmc3.c @@ -0,0 +1,339 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 1998 BERO + * Copyright (C) 2003 Xodnizel + * Mapper 12 code Copyright (C) 2003 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* Code for emulating iNES mappers 4,12,44,45,47,49,52,74,114,115,116,118, + 119,165,205,245,249,250,254 +*/ + +#include "mapinc.h" +#include "mmc3.h" + +MMC3 mmc3; + +static uint8 IRQCount, IRQLatch, IRQa; +static uint8 IRQReload; + +static SFORMAT MMC3_StateRegs[] = +{ + { mmc3.reg, 8, "REGS" }, + { &mmc3.cmd, 1, "CMD" }, + { &mmc3.mirr, 1, "A000" }, + { &mmc3.wram, 1, "A001" }, + { &IRQReload, 1, "IRQR" }, + { &IRQCount, 1, "IRQC" }, + { &IRQLatch, 1, "IRQL" }, + { &IRQa, 1, "IRQA" }, + { 0 } +}; + +static void GENFIXPRG(void); +static void GENFIXCHR(void); + +static void GENPWRAP(uint32 A, uint8 V); +static void GENCWRAP(uint32 A, uint8 V); + +int isRevB = 1; + +void (*MMC3_FixPRG)(void); +void (*MMC3_FixCHR)(void); +void (*MMC3_FixMIR)(void); + +void (*MMC3_pwrap)(uint32 A, uint8 V); +void (*MMC3_cwrap)(uint32 A, uint8 V); + +void MMC3_Init(CartInfo *info, int wram, int battery); + +static void GENCWRAP(uint32 A, uint8 V) { + setchr1(A, V & 0xFF); +} + +static void GENPWRAP(uint32 A, uint8 V) { + setprg8(A, (V & 0x7F)); +} + +/* ---------------------------------------------------------------------- + * ------------------------- Generic MM3 Code --------------------------- + * ---------------------------------------------------------------------- + */ + +uint8 MMC3_GetPRGBank(int V) { + if ((~V & 0x01) && (mmc3.cmd & 0x40)) { + V ^= 0x02; + } + if (V & 0x02) { + return (0xFE | (V & 0x01)); + } + return mmc3.reg[6 | (V & 0x01)]; +} + +uint8 MMC3_GetCHRBank(int V) { + if (mmc3.cmd & 0x80) { + V ^= 0x04; + } + if (V & 0x04) { + return mmc3.reg[V - 2]; + } + return ((mmc3.reg[V >> 1] & ~0x01) | (V & 0x01)); +} + +int MMC3_WramIsWritable(void) { + return ((mmc3.wram & 0x80) && !(mmc3.wram & 0x40)) ? TRUE : FALSE; +} + +static void GENFIXPRG(void) { + MMC3_pwrap(0x8000, MMC3_GetPRGBank(0)); + MMC3_pwrap(0xA000, MMC3_GetPRGBank(1)); + MMC3_pwrap(0xC000, MMC3_GetPRGBank(2)); + MMC3_pwrap(0xE000, MMC3_GetPRGBank(3)); +} + +static void GENFIXCHR(void) { + MMC3_cwrap(0x0000, MMC3_GetCHRBank(0)); + MMC3_cwrap(0x0400, MMC3_GetCHRBank(1)); + MMC3_cwrap(0x0800, MMC3_GetCHRBank(2)); + MMC3_cwrap(0x0C00, MMC3_GetCHRBank(3)); + + MMC3_cwrap(0x1000, MMC3_GetCHRBank(4)); + MMC3_cwrap(0x1400, MMC3_GetCHRBank(5)); + MMC3_cwrap(0x1800, MMC3_GetCHRBank(6)); + MMC3_cwrap(0x1C00, MMC3_GetCHRBank(7)); +} + +static void GENFIXMIR(void) { + setmirror((mmc3.mirr & 0x01) ^ 0x01); +} + +void MMC3_Reset(void) { + IRQCount = IRQLatch = IRQa = mmc3.cmd = 0; + mmc3.mirr = mmc3.wram = 0; + + mmc3.reg[0] = 0; + mmc3.reg[1] = 2; + mmc3.reg[2] = 4; + mmc3.reg[3] = 5; + mmc3.reg[4] = 6; + mmc3.reg[5] = 7; + mmc3.reg[6] = 0; + mmc3.reg[7] = 1; + + MMC3_FixPRG(); + MMC3_FixCHR(); + MMC3_FixMIR(); +} + +DECLFW(MMC3_CMDWrite) { + uint8 oldcmd = mmc3.cmd; + /* FCEU_printf("bs %04x %02x\n",A,V); */ + switch (A & 0xE001) { + case 0x8000: + mmc3.cmd = V; + if ((oldcmd & 0x40) != (mmc3.cmd & 0x40)) { + MMC3_FixPRG(); + } + if ((oldcmd & 0x80) != (mmc3.cmd & 0x80)) { + MMC3_FixCHR(); + } + break; + case 0x8001: { + int cbase = (mmc3.cmd & 0x80) << 5; + mmc3.reg[mmc3.cmd & 0x7] = V; + switch (mmc3.cmd & 0x07) { + case 0: + MMC3_cwrap((cbase ^ 0x000), V & (~1)); + MMC3_cwrap((cbase ^ 0x400), V | 1); + break; + case 1: + MMC3_cwrap((cbase ^ 0x800), V & (~1)); + MMC3_cwrap((cbase ^ 0xC00), V | 1); + break; + case 2: + MMC3_cwrap(cbase ^ 0x1000, V); + break; + case 3: + MMC3_cwrap(cbase ^ 0x1400, V); + break; + case 4: + MMC3_cwrap(cbase ^ 0x1800, V); + break; + case 5: + MMC3_cwrap(cbase ^ 0x1C00, V); + break; + case 6: + if (mmc3.cmd & 0x40) { + MMC3_pwrap(0xC000, V); + } else { + MMC3_pwrap(0x8000, V); + } + break; + case 7: + MMC3_pwrap(0xA000, V); + break; + } + break; + } + case 0xA000: + mmc3.mirr = V; + MMC3_FixMIR(); + break; + case 0xA001: + mmc3.wram = V; + break; + } +} + +DECLFW(MMC3_IRQWrite) { + /* FCEU_printf("%04x:%04x\n",A,V); */ + switch (A & 0xE001) { + case 0xC000: + IRQLatch = V; + break; + case 0xC001: + IRQCount = 0; + IRQReload = 1; + break; + case 0xE000: + X6502_IRQEnd(FCEU_IQEXT); + IRQa = 0; + break; + case 0xE001: + IRQa = 1; + break; + } +} + +DECLFW(MMC3_Write) { + /* FCEU_printf("bs %04x %02x\n",A,V); */ + switch (A & 0xE000) { + case 0x8000: + case 0xA000: + MMC3_CMDWrite(A, V); + break; + case 0xC000: + case 0xE000: + MMC3_IRQWrite(A, V); + break; + } +} + +void MMC3_IRQHBHook(void) { + int count = IRQCount; + if (!count || IRQReload) { + IRQCount = IRQLatch; + IRQReload = 0; + } else { + IRQCount--; + } + if ((count | isRevB) && !IRQCount && IRQa) { + X6502_IRQBegin(FCEU_IQEXT); + } +} + +static void MMC3_hb(void) { + MMC3_IRQHBHook(); +} + +static void MMC3_hb_KickMasterHack(void) { + if (scanline == 238) { + MMC3_IRQHBHook(); + } + MMC3_IRQHBHook(); +} + +static void MMC3_hb_PALStarWarsHack(void) { + if (scanline == 240) { + MMC3_IRQHBHook(); + } + MMC3_IRQHBHook(); +} + +static void StateRestore(int version) { + MMC3_FixPRG(); + MMC3_FixCHR(); + MMC3_FixMIR(); +} + +void MMC3_Power(void) { + if (UNIFchrrama) { + setchr8(0); + } + + SetWriteHandler(0x8000, 0xBFFF, MMC3_CMDWrite); + SetWriteHandler(0xC000, 0xFFFF, MMC3_IRQWrite); + SetReadHandler(0x8000, 0xFFFF, CartBR); + + setmirror(1); + if (mmc3.opts & 1) { + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + SetWriteHandler(0x6000, 0x6000 + ((WRAMSIZE - 1) & 0x1fff), CartBW); + SetReadHandler(0x6000, 0x6000 + ((WRAMSIZE - 1) & 0x1fff), CartBR); + setprg8r(0x10, 0x6000, 0); + if (!(mmc3.opts & 2)) { + FCEU_MemoryRand(WRAM, WRAMSIZE); + } + } + MMC3_Reset(); +} + +void MMC3_Close(void) { +} + +void MMC3_Init(CartInfo *info, int wram, int battery) { + MMC3_FixPRG = GENFIXPRG; + MMC3_FixCHR = GENFIXCHR; + MMC3_FixMIR = GENFIXMIR; + + MMC3_pwrap = GENPWRAP; + MMC3_cwrap = GENCWRAP; + + WRAMSIZE = wram << 10; + + if (wram) { + mmc3.opts |= 1; + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + } + + if (battery) { + mmc3.opts |= 2; + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + + AddExState(MMC3_StateRegs, ~0, 0, 0); + + info->Power = MMC3_Power; + info->Reset = MMC3_Reset; + info->Close = MMC3_Close; + + if (info->CRC32 == 0x5104833e) { /* Kick Master */ + GameHBIRQHook = MMC3_hb_KickMasterHack; + } else if (info->CRC32 == 0x5a6860f1 || info->CRC32 == 0xae280e20) { /* Shougi Meikan '92/'93 */ + GameHBIRQHook = MMC3_hb_KickMasterHack; + } else if (info->CRC32 == 0xfcd772eb) { /* PAL Star Wars, similar problem as Kick Master. */ + GameHBIRQHook = MMC3_hb_PALStarWarsHack; + } else { + GameHBIRQHook = MMC3_hb; + } + GameStateRestore = StateRestore; +} diff --git a/src/mappers/hw/mmc3.h b/src/mappers/hw/mmc3.h new file mode 100644 index 000000000..a8877bc89 --- /dev/null +++ b/src/mappers/hw/mmc3.h @@ -0,0 +1,56 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _MMC3_H +#define _MMC3_H + +typedef struct __MMC3 { + uint8 cmd; + uint8 opts; + uint8 mirr; + uint8 wram; + uint8 reg[8]; +} MMC3; + +extern MMC3 mmc3; +extern int isRevB; + +uint8 MMC3_GetPRGBank(int V); +uint8 MMC3_GetCHRBank(int V); + +DECLFW(MMC3_CMDWrite); /* $ 0x8000 - 0xBFFF */ +DECLFW(MMC3_IRQWrite); /* $ 0xC000 - 0xFFFF */ +DECLFW(MMC3_Write); /* $ 0x8000 - 0xFFFF */ + +void MMC3_Power(void); +void MMC3_Reset(void); +void MMC3_Close(void); +void MMC3_IRQHBHook(void); +int MMC3_WramIsWritable(void); +void MMC3_Init(CartInfo *info, int wram, int battery); + +extern void (*MMC3_FixPRG)(void); +extern void (*MMC3_FixCHR)(void); +extern void (*MMC3_FixMIR)(void); + +extern void (*MMC3_pwrap)(uint32 A, uint8 V); +extern void (*MMC3_cwrap)(uint32 A, uint8 V); + +#endif /* _MMC3_H */ diff --git a/src/mappers/hw/mmc4.c b/src/mappers/hw/mmc4.c new file mode 100644 index 000000000..d1f3ac262 --- /dev/null +++ b/src/mappers/hw/mmc4.c @@ -0,0 +1,148 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2002 Xodnizel + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "mmc4.h" + +void (*MMC4_pwrap)(uint32 A, uint8 V); +void (*MMC4_cwrap)(uint32 A, uint8 V); +void (*MMC4_mwrap)(uint8 V); + +MMC4 mmc4; + +static SFORMAT StateRegs[] = +{ + { mmc4.chr, 4, "CREG" }, + { mmc4.latch, 2, "PPUL" }, + { &mmc4.prg, 1, "PREG" }, + { &mmc4.mirr, 1, "MIRR" }, + { 0 } +}; + +static void GENPWRAP(uint32 A, uint8 V) { + setprg16(A, V); +} + +static void GENCWRAP(uint32 A, uint8 V) { + setchr4(A, V); +} + +static void GENMWRAP(uint8 V) { + mmc4.mirr = V; + setmirror((mmc4.mirr & 1) ^ 1); +} + +void MMC4_FixPRG(void) { + MMC4_pwrap(0x8000, mmc4.prg); + MMC4_pwrap(0xC000, ~0); +} + +void MMC4_FixCHR(void) { + MMC4_cwrap(0x0000, mmc4.chr[mmc4.latch[0] | 0]); + MMC4_cwrap(0x1000, mmc4.chr[mmc4.latch[1] | 2]); + + if (MMC4_mwrap) { + MMC4_mwrap(mmc4.mirr); + } +} + +DECLFW(MMC4_Write) { + switch (A & 0xF000) { + case 0xA000: + mmc4.prg = V; + MMC4_FixPRG(); + break; + case 0xB000: + case 0xC000: + case 0xD000: + case 0xE000: + mmc4.chr[(A - 0xB000) >> 12] = V; + MMC4_FixCHR(); + break; + case 0xF000: + if (MMC4_mwrap) { + MMC4_mwrap(V); + } + break; + } +} + +static void MMC4PPUHook(uint32 A) { + uint8 bank = (A >> 12) & 0x01; + if ((A & 0x2000) || (((A & 0xFF0) != 0xFD0) && ((A & 0xFF0) != 0xFE0))) { + return; + } + mmc4.latch[bank] = (A >> 5) & 0x01; + MMC4_FixCHR(); +} + +void MMC4_Reset(void) { + mmc4.prg = mmc4.mirr = 0; + mmc4.latch[0] = mmc4.latch[1] = 0; + MMC4_FixPRG(); + MMC4_FixCHR(); +} + +void MMC4_Power(void) { + MMC4_Reset(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0xA000, 0xFFFF, MMC4_Write); + if (WRAMSIZE) { + setprg8r(0x10, 0x6000, 0); + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + } +} + +void MMC4_Restore(int version) { + MMC4_FixPRG(); + MMC4_FixCHR(); +} + +void MMC4_Close(void) { +} + +void MMC4_Init(CartInfo *info, int wram, int battery) { + MMC4_pwrap = GENPWRAP; + MMC4_cwrap = GENCWRAP; + MMC4_mwrap = GENMWRAP; + + info->Power = MMC4_Power; + info->Close = MMC4_Close; + PPU_hook = MMC4PPUHook; + + GameStateRestore = MMC4_Restore; + AddExState(StateRegs, ~0, 0, NULL); + + if (wram) { + WRAMSIZE = wram * 1024; + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + if (battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + } +} diff --git a/src/mappers/hw/mmc4.h b/src/mappers/hw/mmc4.h new file mode 100644 index 000000000..bb81e8159 --- /dev/null +++ b/src/mappers/hw/mmc4.h @@ -0,0 +1,48 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _MMC4_H +#define _MMC4_H + +typedef struct __MMC4 { + uint8 prg; + uint8 chr[4]; + uint8 latch[2]; + uint8 mirr; +} MMC4; + +extern MMC4 mmc4; + +DECLFW(MMC4_Write); + +void MMC4_Power(void); +void MMC4_Close(void); +void MMC4_Reset(void); +void MMC4_Restore(int version); +void MMC4_Init(CartInfo *info, int wram, int battery); + +void MMC4_FixPRG(void); +void MMC4_FixCHR(void); + +extern void (*MMC4_pwrap)(uint32 A, uint8 V); +extern void (*MMC4_cwrap)(uint32 A, uint8 V); +extern void (*MMC4_mwrap)(uint8 V); + +#endif /* _MMC4_H */ diff --git a/src/mappers/hw/mmc6.c b/src/mappers/hw/mmc6.c new file mode 100644 index 000000000..765f2f08a --- /dev/null +++ b/src/mappers/hw/mmc6.c @@ -0,0 +1,285 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "mmc6.h" + +typedef struct __MMC6 { + uint8 cmd; + uint8 opts; + uint8 mirr; + uint8 wram; + uint8 reg[8]; +} MMC6; + +static MMC6 mmc6; + +static uint8 IRQCount, IRQLatch, IRQa; +static uint8 IRQReload; + +static SFORMAT MMC6_StateRegs[] = +{ + { mmc6.reg, 8, "REGS" }, + { &mmc6.cmd, 1, "CMD" }, + { &mmc6.mirr, 1, "A000" }, + { &mmc6.wram, 1, "A001" }, + { &IRQReload, 1, "IRQR" }, + { &IRQCount, 1, "IRQC" }, + { &IRQLatch, 1, "IRQL" }, + { &IRQa, 1, "IRQA" }, + { 0 } +}; + +static void MMC6_FixPRG(void) { + if (!(mmc6.cmd & 0x40)) { + setprg8(0x8000, mmc6.reg[6]); + setprg8(0xA000, mmc6.reg[7]); + setprg8(0xC000, ~1); + setprg8(0xE000, ~0); + } else { + setprg8(0x8000, ~1); + setprg8(0xA000, mmc6.reg[7]); + setprg8(0xC000, mmc6.reg[6]); + setprg8(0xE000, ~0); + } +} + +static void MMC6_FixCHR(void) { + if (!(mmc6.cmd & 0x80)) { + setchr1(0x0000, mmc6.reg[0] & 0xFE); + setchr1(0x0400, mmc6.reg[0] | 0x01); + setchr1(0x0800, mmc6.reg[1] & 0xFE); + setchr1(0x0C00, mmc6.reg[1] | 0x01); + + setchr1(0x1000, mmc6.reg[2]); + setchr1(0x1400, mmc6.reg[3]); + setchr1(0x1800, mmc6.reg[4]); + setchr1(0x1C00, mmc6.reg[5]); + } else { + setchr1(0x0000, mmc6.reg[2]); + setchr1(0x0400, mmc6.reg[3]); + setchr1(0x0800, mmc6.reg[4]); + setchr1(0x0C00, mmc6.reg[5]); + + setchr1(0x1000, mmc6.reg[0] & 0xFE); + setchr1(0x1400, mmc6.reg[0] | 0x01); + setchr1(0x1800, mmc6.reg[1] & 0xFE); + setchr1(0x1C00, mmc6.reg[1] | 0x01); + } +} + +static void MMC6_FixMIR(void) { + setmirror((mmc6.mirr & 0x01) ^ 0x01); +} + +static void MMC6_Reset(void) { + IRQCount = IRQLatch = IRQa = mmc6.cmd = 0; + mmc6.mirr = mmc6.wram = 0; + + mmc6.reg[0] = 0; + mmc6.reg[1] = 2; + mmc6.reg[2] = 4; + mmc6.reg[3] = 5; + mmc6.reg[4] = 6; + mmc6.reg[5] = 7; + mmc6.reg[6] = 0; + mmc6.reg[7] = 1; + + MMC6_FixPRG(); + MMC6_FixCHR(); + MMC6_FixMIR(); +} + + +static DECLFW(MBWRAMMMC6) { + if (!(mmc6.cmd & 0x20)) { + /* wram disabled */ + return; + } + + A &= 0x3FF; + if (!(A & 0x200)) { + /* 1st bank writes are disabled */ + if ((mmc6.wram & 0x30) == 0x30) WRAM[A] = V; + } else { + /* 2nd bank writes are disabled */ + if ((mmc6.wram & 0xC0) == 0xC0) WRAM[A] = V; + } +} + +static DECLFR(MAWRAMMMC6) { + if (!(mmc6.cmd & 0x20)) { + /* wram disabled */ + return cpu.openbus; + } + + A &= 0x3FF; + if (!(A & 0x200)) { + /* 1st bank */ + if (mmc6.wram & 0x20) return WRAM[A]; + if (mmc6.wram & 0x80) return 0x00; + } else { + /* 2nd bank */ + if (mmc6.wram & 0x80) return WRAM[A]; + if (mmc6.wram & 0x20) return 0x00; + } + return cpu.openbus; +} + +static DECLFW(MMC6_CMDWrite) { + uint8 oldcmd = mmc6.cmd; + /* FCEU_printf("bs %04x %02x\n",A,V); */ + switch (A & 0xE001) { + case 0x8000: + mmc6.cmd = V; + if ((oldcmd & 0x40) != (mmc6.cmd & 0x40)) + MMC6_FixPRG(); + if ((oldcmd & 0x80) != (mmc6.cmd & 0x80)) + MMC6_FixCHR(); + break; + case 0x8001: { + int cbase = (mmc6.cmd & 0x80) << 5; + mmc6.reg[mmc6.cmd & 0x7] = V; + switch (mmc6.cmd & 0x07) { + case 0: + setchr1((cbase ^ 0x000), V & (~1)); + setchr1((cbase ^ 0x400), V | 1); + break; + case 1: + setchr1((cbase ^ 0x800), V & (~1)); + setchr1((cbase ^ 0xC00), V | 1); + break; + case 2: + setchr1(cbase ^ 0x1000, V); + break; + case 3: + setchr1(cbase ^ 0x1400, V); + break; + case 4: + setchr1(cbase ^ 0x1800, V); + break; + case 5: + setchr1(cbase ^ 0x1C00, V); + break; + case 6: + if (mmc6.cmd & 0x40) + setprg8(0xC000, V); + else + setprg8(0x8000, V); + break; + case 7: + setprg8(0xA000, V); + break; + } + break; + } + case 0xA000: + mmc6.mirr = V; + MMC6_FixMIR(); + break; + case 0xA001: + mmc6.wram = V; + break; + } +} + +static DECLFW(MMC6_IRQWrite) { + /* FCEU_printf("%04x:%04x\n",A,V); */ + switch (A & 0xE001) { + case 0xC000: + IRQLatch = V; + break; + case 0xC001: + IRQReload = 1; + break; + case 0xE000: + X6502_IRQEnd(FCEU_IQEXT); + IRQa = 0; + break; + case 0xE001: + IRQa = 1; + break; + } +} + +static void MMC6_IRQHBHook(void) { + int count = IRQCount; + + if (!count || IRQReload) { + IRQCount = IRQLatch; + IRQReload = 0; + } else + IRQCount--; + if (!IRQCount && IRQa) { + X6502_IRQBegin(FCEU_IQEXT); + } +} + +static void StateRestore(int version) { + MMC6_FixPRG(); + MMC6_FixCHR(); + MMC6_FixMIR(); +} + +static void MMC6_Power(void) { + if (UNIFchrrama) { + setchr8(0); + } + + SetWriteHandler(0x8000, 0xBFFF, MMC6_CMDWrite); + SetWriteHandler(0xC000, 0xFFFF, MMC6_IRQWrite); + SetReadHandler(0x8000, 0xFFFF, CartBR); + + setmirror(1); + + FCEU_CheatAddRAM(1, 0x7000, WRAM); + SetReadHandler(0x7000, 0x7FFF, MAWRAMMMC6); + SetWriteHandler(0x7000, 0x7FFF, MBWRAMMMC6); + if (!(mmc6.opts & 2)) { + FCEU_MemoryRand(WRAM, WRAMSIZE); + } + + MMC6_Reset(); +} + +static void MMC6_Close(void) { +} + +void MMC6_Init(CartInfo *info) { + WRAMSIZE = 1024; + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + + if (info->battery) { + mmc6.opts |= 2; + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + + AddExState(MMC6_StateRegs, ~0, 0, 0); + + info->Power = MMC6_Power; + info->Reset = MMC6_Reset; + info->Close = MMC6_Close; + + GameHBIRQHook = MMC6_IRQHBHook; + GameStateRestore = StateRestore; +} diff --git a/src/mappers/hw/mmc6.h b/src/mappers/hw/mmc6.h new file mode 100644 index 000000000..adf0cd54f --- /dev/null +++ b/src/mappers/hw/mmc6.h @@ -0,0 +1,26 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _MMC6_H +#define _MMC6_H + +void MMC6_Init(CartInfo *info); + +#endif /* _MMC6_H */ diff --git a/src/mappers/hw/n118.c b/src/mappers/hw/n118.c new file mode 100644 index 000000000..f7a5654eb --- /dev/null +++ b/src/mappers/hw/n118.c @@ -0,0 +1,127 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "n118.h" + +void (*N118_FixPRG)(void); +void (*N118_FixCHR)(void); + +void (*N118_pwrap)(uint32 A, uint8 V); +void (*N118_cwrap)(uint32 A, uint8 V); + +N118 n118; + +static SFORMAT StateRegs[] = { + { n118.reg, 8, "REGS" }, + { &n118.cmd, 1, "CMD0" }, + { 0 } +}; + +static void GENCWRAP(uint32 A, uint8 V) { + setchr1(A, V & 0x3F); +} + +static void GENPWRAP(uint32 A, uint8 V) { + setprg8(A, V & 0x0F); +} + +static void GENFIXCHR(void) { + N118_cwrap(0x0000, n118.reg[0] & (~1)); + N118_cwrap(0x0400, n118.reg[0] | 1); + N118_cwrap(0x0800, n118.reg[1] & (~1)); + N118_cwrap(0x0C00, n118.reg[1] | 1); + N118_cwrap(0x1000, n118.reg[2]); + N118_cwrap(0x1400, n118.reg[3]); + N118_cwrap(0x1800, n118.reg[4]); + N118_cwrap(0x1C00, n118.reg[5]); +} + +static void GENFIXPRG(void) { + N118_pwrap(0x8000, n118.reg[6]); + N118_pwrap(0xA000, n118.reg[7]); + N118_pwrap(0xC000, ~1); + N118_pwrap(0xE000, ~0); +} + +DECLFW(N118_Write) { + if (A & 0x01) { + n118.reg[n118.cmd & 0x07] = V; + } else { + n118.cmd = V; + } + N118_FixPRG(); + N118_FixCHR(); +} + +void N118_Power(void) { + n118.reg[0] = 0; + n118.reg[1] = 2; + n118.reg[2] = 4; + n118.reg[3] = 5; + n118.reg[4] = 6; + n118.reg[5] = 7; + n118.reg[6] = 0; + n118.reg[7] = 1; + n118.cmd = 0; + + N118_FixPRG(); + N118_FixCHR(); + + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0x9FFF, N118_Write); + + if (WRAM) { + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + } +} + +static void StateRestore(int version) { + N118_FixPRG(); + N118_FixCHR(); +} + +void N118_Init(CartInfo *info, int wsize, int battery) { + N118_FixPRG = GENFIXPRG; + N118_FixCHR = GENFIXCHR; + + N118_pwrap = GENPWRAP; + N118_cwrap = GENCWRAP; + + WRAMSIZE = wsize * 1024; + + if (WRAMSIZE) { + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + + if (battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + } + + info->Power = N118_Power; + + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/hw/n118.h b/src/mappers/hw/n118.h new file mode 100644 index 000000000..5f42a68ed --- /dev/null +++ b/src/mappers/hw/n118.h @@ -0,0 +1,44 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _N118_H +#define _N118_H + +typedef struct __N118 { + uint8 reg[8]; + uint8 cmd; +} N118; + +extern N118 n118; + +DECLFW(N118_Write); + +void N118_Close(void); +void N118_Power(void); + +void N118_Init(CartInfo *info, int wsize, int battery); + +extern void (*N118_FixPRG)(void); +extern void (*N118_FixCHR)(void); + +extern void (*N118_pwrap)(uint32 A, uint8 V); +extern void (*N118_cwrap)(uint32 A, uint8 V); + +#endif /* _N118_H */ diff --git a/src/mappers/hw/pic16c5x.c b/src/mappers/hw/pic16c5x.c new file mode 100644 index 000000000..c5a79e6be --- /dev/null +++ b/src/mappers/hw/pic16c5x.c @@ -0,0 +1,1001 @@ +/* license:BSD-3-Clause + copyright-holders:Tony La Porta */ + /**************************************************************************\ + * Microchip PIC16C5x Emulator * + * * + * Copyright Tony La Porta * + * Originally written for the MAME project. * + * * + * * + * Addressing architecture is based on the Harvard addressing scheme. * + * * + * * + * **** Change Log **** * + * TLP (06-Apr-2003) * + * - First Public release. * + * BO (07-Apr-2003) Ver 1.01 * + * - Renamed 'sleep' function to 'sleepic' to avoid C conflicts. * + * TLP (09-Apr-2003) Ver 1.10 * + * - Fixed modification of file register $03 (Status). * + * - Corrected support for 7FFh (12-bit) size ROMs. * + * - The 'call' and 'goto' instructions weren't correctly handling the * + * STATUS page info correctly. * + * - The FSR register was incorrectly oring the data with 0xe0 when read. * + * - Prescaler masking information was set to 3 instead of 7. * + * - Prescaler assign bit was set to 4 instead of 8. * + * - Timer source and edge select flags/masks were wrong. * + * - Corrected the memory bank selection in GET/SET_REGFILE and also the * + * indirect register addressing. * + * BMP (18-May-2003) Ver 1.11 * + * - PIC16C5x_get_reg functions were missing 'returns'. * + * TLP (27-May-2003) Ver 1.12 * + * - Fixed the WatchDog timer count. * + * - The Prescaler rate was incorrectly being zeroed, instead of the * + * actual Prescaler counter in the CLRWDT and SLEEP instructions. * + * - Added masking to the FSR register. Upper unused bits are always 1. * + * TLP (27-Aug-2009) Ver 1.13 * + * - Indirect addressing was not taking into account special purpose * + * memory mapped locations. * + * - 'iorlw' instruction was saving the result to memory instead of * + * the W register. * + * - 'tris' instruction no longer modifies Port-C on PIC models that * + * do not have Port-C implemented. * + * TLP (07-Sep-2009) Ver 1.14 * + * - Edge sense control for the T0 count input was incorrectly reversed * + * LE (05-Feb-2017) Ver 1.15 * + * - Allow writing all bits of the status register except TO and PD. * + * This enables e.g. bcf, bsf or clrf to change the flags when the * + * status register is the destination. * + * - Changed rlf and rrf to update the carry flag in the last step. * + * Fixes the case where the status register is the destination. * + * hap (12-Feb-2017) Ver 1.16 * + * - Added basic support for the old GI PIC1650 and PIC1655. * + * - Made RTCC(aka T0CKI) pin an inputline handler. * + * * + * * + * **** Notes: **** * + * PIC WatchDog Timer has a separate internal clock. For the moment, we're * + * basing the count on a 4MHz input clock, since 4MHz is the typical * + * input frequency (but by no means always). * + * A single scaler is available for the Counter/Timer or WatchDog Timer. * + * When connected to the Counter/Timer, it functions as a Prescaler, * + * hence prescale overflows, tick the Counter/Timer. * + * When connected to the WatchDog Timer, it functions as a Postscaler * + * hence WatchDog Timer overflows, tick the Postscaler. This scenario * + * means that the WatchDog timeout occurs when the Postscaler has * + * reached the scaler rate value, not when the WatchDog reaches zero. * + * CLRWDT should prevent the WatchDog Timer from timing out and generating * + * a device reset, but how is not known. The manual also mentions that * + * the WatchDog Timer can only be disabled during ROM programming, and * + * no other means seem to exist??? * + * * + \**************************************************************************/ + +#include +#include "pic16c5x.h" + +/******************** CPU Internal Registers *******************/ +static uint16 m_PC; +static uint16 m_PREVPC; /* previous program counter */ +static uint8 m_W; +static uint8 m_OPTION; +static uint16 m_CONFIG; +static uint8 m_ALU; +static uint16 m_WDT; +static uint8 m_TRISA; +static uint8 m_TRISB; +static uint8 m_TRISC; +static uint16 m_STACK[2]; +static uint16 m_prescaler; /* Note: this is really an 8-bit register */ +static uint16 m_opcode; +static uint8 m_internalram[128]; +static uint8 *m_rom; + +static int m_icount; +static int m_picmodel; +static int m_delay_timer; +static uint16 m_temp_config; +static int m_rtcc; +static uint8 m_count_pending; /* boolean type */ +static int8 m_old_data; +static uint8 m_picRAMmask; +static uint16 m_picROMmask; +static int m_inst_cycles; +static int m_clock2cycle; + +/*address_space *m_program; +memory_access_cache<1, -1, ENDIANNESS_LITTLE> *m_cache; +address_space *m_data;*/ + +/* i/o handlers */ +static pic16c5x_readfunc m_read; +static pic16c5x_writefunc m_write; + +static void PIC16C5x(int program_width, int data_width, int picmodel, uint8 *rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr) +{ + m_rom = rom; + m_picmodel = picmodel; + m_temp_config = 0; + m_picRAMmask = ((1 << data_width) - 1); + m_picROMmask = ((1 << program_width) - 1); + m_read = _rd; + m_write = _wr; + m_PC = 0; + m_PREVPC = 0; + m_W = 0; + m_OPTION = 0; + m_CONFIG = 0; + m_ALU = 0; + m_WDT = 0; + m_TRISA = 0; + m_TRISB = 0; + m_TRISC = 0; + m_prescaler = 0; + m_icount = 0; + m_delay_timer = 0; + m_rtcc = 0; + m_count_pending = 0; + m_old_data = 0; + m_inst_cycles = 0; + m_clock2cycle = 0; +} + +void pic16c54_init(uint8 *rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr) { PIC16C5x( 9, 5, 0x16C54, rom, _rd, _wr); } +void pic16c55_init(uint8 *rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr) { PIC16C5x( 9, 5, 0x16C55, rom, _rd, _wr); } +void pic16c56_init(uint8 *rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr) { PIC16C5x(10, 5, 0x16C56, rom, _rd, _wr); } +void pic16c57_init(uint8 *rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr) { PIC16C5x(11, 7, 0x16C57, rom, _rd, _wr); } +void pic16c58_init(uint8 *rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr) { PIC16C5x(11, 7, 0x16C58, rom, _rd, _wr); } +void pic1650_init (uint8 *rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr) { PIC16C5x( 9, 5, 0x1650, rom, _rd, _wr); } +void pic1655_init (uint8 *rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr) { PIC16C5x( 9, 5, 0x1655, rom, _rd, _wr); } + +#define M_OPCODE_B0 (m_opcode & 0xFF) +#define M_OPCODE_B1 ((m_opcode >> 8) & 0xFF) +#define M_OPCODE_S0 m_opcode + +#define M_RDRAM(A) m_internalram[A &m_picRAMmask] +#define M_WRTRAM(A,V) m_internalram[A &m_picRAMmask] =(V) +#define M_RDOP(A) m_rom[(A &m_picROMmask) <<1 |0] | m_rom[(A &m_picROMmask) <<1 |1] <<8 +#define ADDR_MASK 0x7ff + +#define TMR0 m_internalram[1] +#define PCL m_internalram[2] +#define STATUS m_internalram[3] +#define FSR m_internalram[4] +#define PORTA m_internalram[5] +#define PORTB m_internalram[6] +#define PORTC m_internalram[7] +#define PORTD m_internalram[8] +#define INDF M_RDRAM(FSR) + +#define ADDR (M_OPCODE_B0 & 0x1f) + + +/******** The following is the Status Flag register definition. *********/ + /* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | */ + /* | PA | TO | PD | Z | DC | C | */ +#define PA_REG 0xe0 /* PA Program Page Preselect - bit 8 is unused here */ +#define TO_FLAG 0x10 /* TO Time Out flag (WatchDog) */ +#define PD_FLAG 0x08 /* PD Power Down flag */ +#define Z_FLAG 0x04 /* Z Zero Flag */ +#define DC_FLAG 0x02 /* DC Digit Carry/Borrow flag (Nibble) */ +#define C_FLAG 0x01 /* C Carry/Borrow Flag (Byte) */ + +#define PA (STATUS & PA_REG) +#define TO (STATUS & TO_FLAG) +#define PD (STATUS & PD_FLAG) +#define ZERO (STATUS & Z_FLAG) +#define DC (STATUS & DC_FLAG) +#define CARRY (STATUS & C_FLAG) + + +/******** The following is the Option Flag register definition. *********/ + /* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | */ + /* | 0 | 0 | TOCS | TOSE | PSA | PS | */ +#define T0CS_FLAG 0x20 /* TOCS Timer 0 clock source select */ +#define T0SE_FLAG 0x10 /* TOSE Timer 0 clock source edge select */ +#define PSA_FLAG 0x08 /* PSA Prescaler Assignment bit */ +#define PS_REG 0x07 /* PS Prescaler Rate select */ + +#define T0CS (m_OPTION & T0CS_FLAG) +#define T0SE (m_OPTION & T0SE_FLAG) +#define PSA (m_OPTION & PSA_FLAG) +#define PS (m_OPTION & PS_REG) + + +/******** The following is the Config Flag register definition. *********/ + /* | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | */ + /* | CP | WDTE | FOSC | */ + /* CP Code Protect (ROM read protect) */ +#define WDTE_FLAG 0x04 /* WDTE WatchDog Timer enable */ +#define FOSC_FLAG 0x03 /* FOSC Oscillator source select */ + +#define WDTE (m_CONFIG & WDTE_FLAG) +#define FOSC (m_CONFIG & FOSC_FLAG) + + +/************************************************************************ + * Shortcuts + ************************************************************************/ + +#define CLR(flagreg, flag) ( flagreg &= (uint8)(~flag) ) +#define SET(flagreg, flag) ( flagreg |= flag ) + + +/* Easy bit position selectors */ +#define POS ((M_OPCODE_B0 >> 5) & 7) +static const unsigned int bit_clr[8] = { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f }; +static const unsigned int bit_set[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; + +static INLINE void CALCULATE_Z_FLAG(void) +{ + if (m_ALU == 0) SET(STATUS, Z_FLAG); + else CLR(STATUS, Z_FLAG); +} + +static INLINE void CALCULATE_ADD_CARRY(void) +{ + if ((uint8)(m_old_data) > (uint8)(m_ALU)) { + SET(STATUS, C_FLAG); + } + else { + CLR(STATUS, C_FLAG); + } +} + +static INLINE void CALCULATE_ADD_DIGITCARRY(void) +{ + if (((uint8)(m_old_data) & 0x0f) > ((uint8)(m_ALU) & 0x0f)) { + SET(STATUS, DC_FLAG); + } + else { + CLR(STATUS, DC_FLAG); + } +} + +static INLINE void CALCULATE_SUB_CARRY(void) +{ + if ((uint8)(m_old_data) < (uint8)(m_ALU)) { + CLR(STATUS, C_FLAG); + } + else { + SET(STATUS, C_FLAG); + } +} + +static INLINE void CALCULATE_SUB_DIGITCARRY(void) +{ + if (((uint8)(m_old_data) & 0x0f) < ((uint8)(m_ALU) & 0x0f)) { + CLR(STATUS, DC_FLAG); + } + else { + SET(STATUS, DC_FLAG); + } +} + + + +static INLINE uint16 POP_STACK(void) +{ + uint16 data = m_STACK[1]; + m_STACK[1] = m_STACK[0]; + return (data & ADDR_MASK); +} +static INLINE void PUSH_STACK(uint16 data) +{ + m_STACK[0] = m_STACK[1]; + m_STACK[1] = (data & ADDR_MASK); +} + + + +static INLINE uint8 GET_REGFILE(uint32_t addr) /* Read from internal memory */ +{ + uint8 data = 0; + + if (addr == 0) { /* Indirect addressing */ + addr = (FSR & m_picRAMmask); + } + + if ((m_picmodel == 0x16C57) || (m_picmodel == 0x16C58)) { + addr |= (FSR & 0x60); /* FSR bits 6-5 are used for banking in direct mode */ + } + + if ((addr & 0x10) == 0) addr &= 0x0f; + + switch(addr) + { + case 0: /* Not an actual register, so return 0 */ + data = 0; + break; + case 4: data = (FSR | (uint8)(~m_picRAMmask)); + break; + case 5: /* read port A */ + if (m_picmodel == 0x1650) { + data = m_read(PIC16C5x_PORTA) & PORTA; + } + else if (m_picmodel == 0x1655) { + data = m_read(PIC16C5x_PORTA) & 0x0f; + } + else { + data = m_read(PIC16C5x_PORTA); + data &= m_TRISA; + data |= ((uint8)(~m_TRISA) & PORTA); + data &= 0x0f; /* 4-bit port (only lower 4 bits used) */ + } + break; + case 6: /* read port B */ + if (m_picmodel == 0x1650) { + data = m_read(PIC16C5x_PORTB) & PORTB; + } + else if (m_picmodel != 0x1655) { /* B is output-only on 1655 */ + data = m_read(PIC16C5x_PORTB); + data &= m_TRISB; + data |= ((uint8)(~m_TRISB) & PORTB); + } + break; + case 7: /* read port C */ + if (m_picmodel == 0x1650 || m_picmodel == 0x1655) { + data = m_read(PIC16C5x_PORTC) & PORTC; + } + else if ((m_picmodel == 0x16C55) || (m_picmodel == 0x16C57)) { + data = m_read(PIC16C5x_PORTC); + data &= m_TRISC; + data |= ((uint8)(~m_TRISC) & PORTC); + } + else { /* PIC16C54, PIC16C56, PIC16C58 */ + data = M_RDRAM(addr); + } + break; + case 8: /* read port D */ + if (m_picmodel == 0x1650) { + data = m_read(PIC16C5x_PORTD) & PORTD; + } + else { + data = M_RDRAM(addr); + } + break; + default: data = M_RDRAM(addr); + break; + } + return data; +} + +static INLINE void STORE_REGFILE(uint32_t addr, uint8 data) /* Write to internal memory */ +{ + if (addr == 0) { /* Indirect addressing */ + addr = (FSR & m_picRAMmask); + } + + if ((m_picmodel == 0x16C57) || (m_picmodel == 0x16C58)) { + addr |= (FSR & 0x60); /* FSR bits 6-5 are used for banking in direct mode */ + } + + if ((addr & 0x10) == 0) addr &= 0x0f; + + switch(addr) + { + case 0: /* Not an actual register, nothing to save */ + break; + case 1: m_delay_timer = 2; /* Timer starts after next two instructions */ + if (PSA == 0) m_prescaler = 0; /* Must clear the Prescaler */ + TMR0 = data; + break; + case 2: PCL = data; + m_PC = ((STATUS & PA_REG) << 4) | data; + break; + case 3: STATUS = (STATUS & (TO_FLAG | PD_FLAG)) | (data & (uint8)(~(TO_FLAG | PD_FLAG))); + break; + case 4: FSR = (data | (uint8)(~m_picRAMmask)); + break; + case 5: /* write port A */ + if (m_picmodel == 0x1650) { + m_write(PIC16C5x_PORTA, data); + } + else if (m_picmodel != 0x1655) { /* A is input-only on 1655 */ + data &= 0x0f; /* 4-bit port (only lower 4 bits used) */ + m_write(PIC16C5x_PORTA, data & (uint8)(~m_TRISA)); + } + PORTA = data; + break; + case 6: /* write port B */ + if (m_picmodel == 0x1650 || m_picmodel == 0x1655) { + m_write(PIC16C5x_PORTB, data); + } + else { + m_write(PIC16C5x_PORTB, data & (uint8)(~m_TRISB)); + } + PORTB = data; + break; + case 7: /* write port C */ + if (m_picmodel == 0x1650 || m_picmodel == 0x1655) { + m_write(PIC16C5x_PORTC, data); + } + else if ((m_picmodel == 0x16C55) || (m_picmodel == 0x16C57)) { + m_write(PIC16C5x_PORTC, data & (uint8)(~m_TRISC)); + } + PORTC = data; /* also writes to RAM */ + break; + case 8: /* write port D */ + if (m_picmodel == 0x1650) { + m_write(PIC16C5x_PORTD, data); + } + PORTD = data; /* also writes to RAM */ + break; + default: M_WRTRAM(addr, data); + break; + } +} + + +static INLINE void STORE_RESULT(uint32_t addr, uint8 data) +{ + if (M_OPCODE_B0 & 0x20) + { + STORE_REGFILE(addr, data); + } + else + { + m_W = data; + } +} + + +/************************************************************************ + * Emulate the Instructions + ************************************************************************/ + +/* This following function is here to fill in the void for */ +/* the opcode call function. This function is never called. */ + + +static INLINE void illegal(void) +{ + /* printf("PIC16C5x: PC=%03x, Illegal opcode = %04x\n", (m_PC-1), M_OPCODE_S0); */ +} + +/* + Note: + According to the manual, if the STATUS register is the destination for an instruction that affects the Z, DC or C bits + then the write to these three bits is disabled. These bits are set or cleared according to the device logic. + To ensure this is correctly emulated, in instructions that write to the file registers, always change the status flags + *after* storing the result of the instruction. + e.g. CALCULATE_*, SET(STATUS,*_FLAG) and CLR(STATUS,*_FLAG) should appear as the last steps of the instruction emulation. +*/ + +static INLINE void addwf(void) +{ + m_old_data = GET_REGFILE(ADDR); + m_ALU = m_old_data + m_W; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); + CALCULATE_ADD_CARRY(); + CALCULATE_ADD_DIGITCARRY(); +} + +static INLINE void andwf(void) +{ + m_ALU = GET_REGFILE(ADDR) & m_W; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +static INLINE void andlw(void) +{ + m_ALU = M_OPCODE_B0 & m_W; + m_W = m_ALU; + CALCULATE_Z_FLAG(); +} + +static INLINE void bcf(void) +{ + m_ALU = GET_REGFILE(ADDR); + m_ALU &= bit_clr[POS]; + STORE_REGFILE(ADDR, m_ALU); +} + +static INLINE void bsf(void) +{ + m_ALU = GET_REGFILE(ADDR); + m_ALU |= bit_set[POS]; + STORE_REGFILE(ADDR, m_ALU); +} + +static INLINE void btfss(void) +{ + if ((GET_REGFILE(ADDR) & bit_set[POS]) == bit_set[POS]) + { + m_PC++; + PCL = m_PC & 0xff; + m_inst_cycles += 1; /* Add NOP cycles */ + } +} + +static INLINE void btfsc(void) +{ + if ((GET_REGFILE(ADDR) & bit_set[POS]) == 0) + { + m_PC++; + PCL = m_PC & 0xff; + m_inst_cycles += 1; /* Add NOP cycles */ + } +} + +static INLINE void call(void) +{ + PUSH_STACK(m_PC); + m_PC = ((STATUS & PA_REG) << 4) | M_OPCODE_B0; + m_PC &= 0x6ff; + PCL = m_PC & 0xff; +} + +static INLINE void clrw(void) +{ + m_W = 0; + SET(STATUS, Z_FLAG); +} + +static INLINE void clrf(void) +{ + STORE_REGFILE(ADDR, 0); + SET(STATUS, Z_FLAG); +} + +static INLINE void clrwdt(void) +{ + m_WDT = 0; + if (PSA) m_prescaler = 0; + SET(STATUS, TO_FLAG); + SET(STATUS, PD_FLAG); +} + +static INLINE void comf(void) +{ + m_ALU = (uint8)(~(GET_REGFILE(ADDR))); + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +static INLINE void decf(void) +{ + m_ALU = GET_REGFILE(ADDR) - 1; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +static INLINE void decfsz(void) +{ + m_ALU = GET_REGFILE(ADDR) - 1; + STORE_RESULT(ADDR, m_ALU); + if (m_ALU == 0) + { + m_PC++; + PCL = m_PC & 0xff; + m_inst_cycles += 1; /* Add NOP cycles */ + } +} + +static INLINE void goto_op(void) +{ + m_PC = ((STATUS & PA_REG) << 4) | (M_OPCODE_S0 & 0x1ff); + m_PC &= ADDR_MASK; + PCL = m_PC & 0xff; +} + +static INLINE void incf(void) +{ + m_ALU = GET_REGFILE(ADDR) + 1; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +static INLINE void incfsz(void) +{ + m_ALU = GET_REGFILE(ADDR) + 1; + STORE_RESULT(ADDR, m_ALU); + if (m_ALU == 0) + { + m_PC++; + PCL = m_PC & 0xff; + m_inst_cycles += 1; /* Add NOP cycles */ + } +} + +static INLINE void iorlw(void) +{ + m_ALU = M_OPCODE_B0 | m_W; + m_W = m_ALU; + CALCULATE_Z_FLAG(); +} + +static INLINE void iorwf(void) +{ + m_ALU = GET_REGFILE(ADDR) | m_W; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +static INLINE void movf(void) +{ + m_ALU = GET_REGFILE(ADDR); + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + +static INLINE void movlw(void) +{ + m_W = M_OPCODE_B0; +} + +static INLINE void movwf(void) +{ + STORE_REGFILE(ADDR, m_W); +} + +static INLINE void nop(void) +{ + /* Do nothing */ +} + +static INLINE void option(void) +{ + m_OPTION = m_W & (T0CS_FLAG | T0SE_FLAG | PSA_FLAG | PS_REG); +} + +static INLINE void retlw(void) +{ + m_W = M_OPCODE_B0; + m_PC = POP_STACK(); + PCL = m_PC & 0xff; +} + +static INLINE void rlf(void) +{ + uint8 bit7; + m_ALU = GET_REGFILE(ADDR); + bit7 = m_ALU & 0x80; + m_ALU <<= 1; + if (STATUS & C_FLAG) m_ALU |= 1; + STORE_RESULT(ADDR, m_ALU); + if (bit7) SET(STATUS, C_FLAG); + else CLR(STATUS, C_FLAG); +} + +static INLINE void rrf(void) +{ + uint8 bit0; + m_ALU = GET_REGFILE(ADDR); + bit0 = m_ALU & 1; + m_ALU >>= 1; + if (STATUS & C_FLAG) m_ALU |= 0x80; + STORE_RESULT(ADDR, m_ALU); + if (bit0) SET(STATUS, C_FLAG); + else CLR(STATUS, C_FLAG); +} + +static INLINE void sleepic(void) +{ + if (WDTE) m_WDT = 0; + if (PSA) m_prescaler = 0; + SET(STATUS, TO_FLAG); + CLR(STATUS, PD_FLAG); +} + +static INLINE void subwf(void) +{ + m_old_data = GET_REGFILE(ADDR); + m_ALU = m_old_data - m_W; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); + CALCULATE_SUB_CARRY(); + CALCULATE_SUB_DIGITCARRY(); +} + +static INLINE void swapf(void) +{ + m_ALU = ((GET_REGFILE(ADDR) << 4) & 0xf0); + m_ALU |= ((GET_REGFILE(ADDR) >> 4) & 0x0f); + STORE_RESULT(ADDR, m_ALU); +} + +static INLINE void tris(void) +{ + switch(M_OPCODE_B0 & 0x7) + { + case 5: if (m_TRISA == m_W) break; + else { m_TRISA = m_W | 0xf0; m_write(PIC16C5x_PORTA, 0x1000 | (PORTA & (uint8)(~m_TRISA) & 0x0f)); break; } + case 6: if (m_TRISB == m_W) break; + else { m_TRISB = m_W; m_write(PIC16C5x_PORTB, 0x1000 | (PORTB & (uint8)(~m_TRISB))); break; } + case 7: if ((m_picmodel == 0x16C55) || (m_picmodel == 0x16C57)) { + if (m_TRISC == m_W) break; + else { m_TRISC = m_W; m_write(PIC16C5x_PORTC, 0x1000 | (PORTC & (uint8)(~m_TRISC))); break; } + } + else { + illegal(); break; + } + default: illegal(); break; + } +} + +static INLINE void xorlw(void) +{ + m_ALU = m_W ^ M_OPCODE_B0; + m_W = m_ALU; + CALCULATE_Z_FLAG(); +} + +static INLINE void xorwf(void) +{ + m_ALU = GET_REGFILE(ADDR) ^ m_W; + STORE_RESULT(ADDR, m_ALU); + CALCULATE_Z_FLAG(); +} + + + + +/*********************************************************************** + * Opcode Table (Cycles, Instruction) + ***********************************************************************/ + +static const uint8 s_opcode_main_cycles[256] = { +/*00*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*08*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*10*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*18*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*20*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*28*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*30*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*38*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*40*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*48*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*50*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*58*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*60*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*68*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*70*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*78*/ 1, 1, 1, 1, 1, 1, 1, 1, + +/*80*/ 2, 2, 2, 2, 2, 2, 2, 2, +/*88*/ 2, 2, 2, 2, 2, 2, 2, 2, +/*90*/ 2, 2, 2, 2, 2, 2, 2, 2, +/*98*/ 2, 2, 2, 2, 2, 2, 2, 2, +/*A0*/ 2, 2, 2, 2, 2, 2, 2, 2, +/*A8*/ 2, 2, 2, 2, 2, 2, 2, 2, +/*B0*/ 2, 2, 2, 2, 2, 2, 2, 2, +/*B8*/ 2, 2, 2, 2, 2, 2, 2, 2, + +/*C0*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*C8*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*D0*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*D8*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*E0*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*E8*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*F0*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*F8*/ 1, 1, 1, 1, 1, 1, 1, 1 +}; + +static const uint8 s_opcode_00x_cycles[16] = { +/*00*/ 1, 1, 1, 1, 1, 1, 1, 1, +/*08*/ 1, 1, 1, 1, 1, 1, 1, 1 +}; + + + +/**************************************************************************** + * Inits CPU emulation + ****************************************************************************/ + +enum +{ + PIC16C5x_PC=1, PIC16C5x_STK0, PIC16C5x_STK1, PIC16C5x_FSR, + PIC16C5x_W, PIC16C5x_ALU, PIC16C5x_STR, PIC16C5x_OPT, + PIC16C5x_TMR0, PIC16C5x_PRTA, PIC16C5x_PRTB, PIC16C5x_PRTC, PIC16C5x_PRTD, + PIC16C5x_WDT, PIC16C5x_TRSA, PIC16C5x_TRSB, PIC16C5x_TRSC, + PIC16C5x_PSCL +}; + +/**************************************************************************** + * Reset registers to their initial values + ****************************************************************************/ + +static INLINE void PIC16C5x_reset_regs(void) +{ + m_PC = m_picROMmask; + m_CONFIG = m_temp_config; + m_TRISA = 0xff; + m_TRISB = 0xff; + m_TRISC = 0xff; + m_OPTION = (T0CS_FLAG | T0SE_FLAG | PSA_FLAG | PS_REG); + PCL = 0xff; + FSR |= (uint8)(~m_picRAMmask); + m_prescaler = 0; + m_delay_timer = 0; + m_inst_cycles = 0; + m_count_pending = FALSE; +} + +void pic16c5x_reset(uint8 hard) +{ + if (hard) { + memset(m_internalram, 0, sizeof(m_internalram)); + PIC16C5x_reset_regs(); + CLR(STATUS, PA_REG); + SET(STATUS, (TO_FLAG | PD_FLAG)); + m_icount = 0; + m_clock2cycle = 0; + } else { + SET(STATUS, (TO_FLAG | PD_FLAG | Z_FLAG | DC_FLAG | C_FLAG)); + PIC16C5x_reset_regs(); + } +} + +void pic16c5x_set_config(uint16 data) +{ + m_temp_config = data; +} + + + +/**************************************************************************** + * WatchDog + ****************************************************************************/ + +static INLINE void PIC16C5x_update_watchdog(int counts) +{ + /* WatchDog is set up to count 18,000 (0x464f hex) ticks to provide */ + /* the timeout period of 0.018ms based on a 4MHz input clock. */ + /* Note: the 4MHz clock should be divided by the PIC16C5x_CLOCK_DIVIDER */ + /* which effectively makes the PIC run at 1MHz internally. */ + + /* If the current instruction is CLRWDT or SLEEP, don't update the WDT */ + + if ((M_OPCODE_S0 != 3) && (M_OPCODE_S0 != 4)) + { + uint16 old_WDT = m_WDT; + + m_WDT -= counts; + + if (m_WDT > 0x464f) { + m_WDT = 0x464f - (0xffff - m_WDT); + } + + if (((old_WDT != 0) && (old_WDT < m_WDT)) || (m_WDT == 0)) + { + if (PSA) { + m_prescaler++; + if (m_prescaler >= (1 << PS)) { /* Prescale values from 1 to 128 */ + m_prescaler = 0; + CLR(STATUS, TO_FLAG); + /* PIC16C5x_soft_reset(); */ + } + } + else { + CLR(STATUS, TO_FLAG); + /* PIC16C5x_soft_reset(); */ + } + } + } +} + + +/**************************************************************************** + * Update Timer + ****************************************************************************/ + +static INLINE void PIC16C5x_update_timer(int counts) +{ + if (PSA == 0) { + m_prescaler += counts; + if (m_prescaler >= (2 << PS)) { /* Prescale values from 2 to 256 */ + TMR0 += (m_prescaler / (2 << PS)); + m_prescaler %= (2 << PS); /* Overflow prescaler */ + } + } + else { + TMR0 += counts; + } +} + +void pic16c5x_set_input(int line, int state) +{ + switch (line) + { + /* RTCC/T0CKI pin */ + case PIC16C5x_RTCC: + if (T0CS && state != m_rtcc) /* Count mode, edge triggered */ + if ((T0SE && !state) || (!T0SE && state)) + m_count_pending = TRUE; + + m_rtcc = state; + break; + + default: + break; + } +} + + +void pic16c5x_run(void) +{ + if ((++m_clock2cycle &3) ==0) m_icount++; + + while (m_icount > 0) { + if (PD == 0) /* Sleep Mode */ + { + m_count_pending = FALSE; + m_inst_cycles = 1; + if (WDTE) { + PIC16C5x_update_watchdog(1); + } + } + else + { + if (m_count_pending) { /* RTCC/T0CKI clocked while in Count mode */ + m_count_pending = FALSE; + PIC16C5x_update_timer(1); + } + + m_PREVPC = m_PC; + + M_OPCODE_S0 = M_RDOP(m_PC); + /* printf("%04X: %03X %03X\n", m_PC, M_OPCODE_S0, M_OPCODE_B0); */ + m_PC++; + PCL++; + + if (m_picmodel == 0x1650 || m_picmodel == 0x1655 || (M_OPCODE_S0 & 0xff0) != 0x000) { /* Do all opcodes except the 00? ones */ + uint8 b1 = (M_OPCODE_S0 >> 4) & 0xff; + m_inst_cycles = s_opcode_main_cycles[b1]; + switch (b1) { + #include "pic16c5x_ops_main.inc" + } + } + else { /* Opcode 0x00? has many opcodes in its minor nibble */ + uint8 b1 = M_OPCODE_B0 & 0x1f; + m_inst_cycles = s_opcode_00x_cycles[b1]; + switch (b1) { + #include "pic16c5x_ops_00x.inc" + } + } + + if (!T0CS) { /* Timer mode */ + if (m_delay_timer) { + m_delay_timer--; + } + else { + PIC16C5x_update_timer(m_inst_cycles); + } + } + if (WDTE) { + PIC16C5x_update_watchdog(m_inst_cycles); + } + } + + m_icount -= m_inst_cycles; + } +} + +void AddExState(void *v, uint32 s, int type, char *desc); + +void pic16c5x_add_statesinfo(void) { + AddExState(&m_PC, sizeof(m_PC), 0, "PC00"); + AddExState(&m_PREVPC, sizeof(m_PREVPC), 0, "PRPC"); + AddExState(&m_W, sizeof(m_W), 0, "W000"); + AddExState(&m_OPTION, sizeof(m_OPTION), 0, "OPT0"); + AddExState(&m_CONFIG, sizeof(m_CONFIG), 0, "CONF"); + AddExState(&m_ALU, sizeof(m_ALU), 0, "ALU"); + AddExState(&m_WDT, sizeof(m_WDT), 0, "WDT"); + AddExState(&m_TRISA, sizeof(m_TRISA), 0, "TRSA"); + AddExState(&m_TRISB, sizeof(m_TRISB), 0, "TRSB"); + AddExState(&m_TRISC, sizeof(m_TRISC), 0, "TRSC"); + AddExState(&m_STACK[0], sizeof(m_STACK[0]), 0, "STC0"); + AddExState(&m_STACK[1], sizeof(m_STACK[1]), 0, "STC1"); + AddExState(&m_prescaler, sizeof(m_prescaler), 0, "PSCL"); + AddExState(&m_opcode, sizeof(m_opcode), 0, "OPS0"); + AddExState(m_internalram, sizeof(m_internalram), 0, "IRAM"); + AddExState(&m_icount, sizeof(m_icount), 0, "ICNT"); + AddExState(&m_delay_timer, sizeof(m_delay_timer), 0, "DTIM"); + AddExState(&m_rtcc, sizeof(m_rtcc), 0, "RTCC"); + AddExState(&m_count_pending, sizeof(m_count_pending), 0, "CNTP"); + AddExState(&m_inst_cycles, sizeof(m_inst_cycles), 0, "ICYC"); + AddExState(&m_clock2cycle, sizeof(m_clock2cycle), 0, "CL2C"); +} \ No newline at end of file diff --git a/src/mappers/hw/pic16c5x.h b/src/mappers/hw/pic16c5x.h new file mode 100644 index 000000000..67c03dc17 --- /dev/null +++ b/src/mappers/hw/pic16c5x.h @@ -0,0 +1,57 @@ +/* license:BSD-3-Clause */ +/* copyright-holders:Tony La Porta */ + /**************************************************************************\ + * Microchip PIC16C5x_ Emulator * + * * + * Copyright Tony La Porta * + * Originally written for the MAME project. * + * * + * * + * Addressing architecture is based on the Harvard addressing scheme. * + * * + \**************************************************************************/ + +#ifndef _PIC16C5x_H +#define _PIC16C5x_H + +#include "../../fceu-types.h" + +typedef uint8 (*pic16c5x_readfunc)(int); +typedef void (*pic16c5x_writefunc)(int, int); + +enum { + PIC16C5x_RTCC = 0 +}; + + +/* in the mid-90s RTCC was renamed to T0CKI */ +#define PIC16C5x_T0CKI PIC16C5x_RTCC + +/* i/o ports */ +enum { + PIC16C5x_PORTA = 0, + PIC16C5x_PORTB, + PIC16C5x_PORTC, + PIC16C5x_PORTD +}; + +/**************************************************************************** + * Function to configure the CONFIG register. This is actually hard-wired + * during ROM programming, so should be called in the driver INIT, with + * the value if known (available in HEX dumps of the ROM). + */ +void pic16c5x_set_input(int line, int state); +void pic16c5x_set_config(uint16 data); +void pic16c5x_reset(uint8 hard); +void pic16c5x_run(void); +void pic16c5x_add_statesinfo(void); + +void pic16c54_init(uint8* rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr); +void pic16c55_init(uint8* rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr); +void pic16c56_init(uint8* rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr); +void pic16c57_init(uint8* rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr); +void pic16c58_init(uint8* rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr); +void pic1650_init(uint8* rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr); +void pic1655_init(uint8* rom, pic16c5x_readfunc _rd, pic16c5x_writefunc _wr); + +#endif /* _PIC16C5x_H */ diff --git a/src/mappers/hw/pic16c5x_ops_00x.inc b/src/mappers/hw/pic16c5x_ops_00x.inc new file mode 100644 index 000000000..67f058efc --- /dev/null +++ b/src/mappers/hw/pic16c5x_ops_00x.inc @@ -0,0 +1,16 @@ +case 0x00: nop(); break; +case 0x01: illegal(); break; +case 0x02: option(); break; +case 0x03: sleepic(); break; +case 0x04: clrwdt(); break; +case 0x05: tris(); break; +case 0x06: tris(); break; +case 0x07: tris(); break; +case 0x08: illegal(); break; +case 0x09: illegal(); break; +case 0x0A: illegal(); break; +case 0x0B: illegal(); break; +case 0x0C: illegal(); break; +case 0x0D: illegal(); break; +case 0x0E: illegal(); break; +case 0x0F: illegal(); break; \ No newline at end of file diff --git a/src/mappers/hw/pic16c5x_ops_main.inc b/src/mappers/hw/pic16c5x_ops_main.inc new file mode 100644 index 000000000..f054d548f --- /dev/null +++ b/src/mappers/hw/pic16c5x_ops_main.inc @@ -0,0 +1,287 @@ +case 0x00: nop(); break; +case 0x01: illegal(); break; +case 0x02: movwf(); break; +case 0x03: movwf(); break; +case 0x04: clrw(); break; +case 0x05: illegal(); break; +case 0x06: clrf(); break; +case 0x07: clrf(); break; +/*08*/ +case 0x08: subwf(); break; +case 0x09: subwf(); break; +case 0x0A: subwf(); break; +case 0x0B: subwf(); break; +case 0x0C: decf(); break; +case 0x0D: decf(); break; +case 0x0E: decf(); break; +case 0x0F: decf(); break; +/*10*/ +case 0x10: iorwf(); break; +case 0x11: iorwf(); break; +case 0x12: iorwf(); break; +case 0x13: iorwf(); break; +case 0x14: andwf(); break; +case 0x15: andwf(); break; +case 0x16: andwf(); break; +case 0x17: andwf(); break; +/*18*/ +case 0x18: xorwf(); break; +case 0x19: xorwf(); break; +case 0x1A: xorwf(); break; +case 0x1B: xorwf(); break; +case 0x1C: addwf(); break; +case 0x1D: addwf(); break; +case 0x1E: addwf(); break; +case 0x1F: addwf(); break; +/*20*/ +case 0x20: movf(); break; +case 0x21: movf(); break; +case 0x22: movf(); break; +case 0x23: movf(); break; +case 0x24: comf(); break; +case 0x25: comf(); break; +case 0x26: comf(); break; +case 0x27: comf(); break; +/*28*/ +case 0x28: incf(); break; +case 0x29: incf(); break; +case 0x2A: incf(); break; +case 0x2B: incf(); break; +case 0x2C: decfsz(); break; +case 0x2D: decfsz(); break; +case 0x2E: decfsz(); break; +case 0x2F: decfsz(); break; +/*30*/ +case 0x30: rrf(); break; +case 0x31: rrf(); break; +case 0x32: rrf(); break; +case 0x33: rrf(); break; +case 0x34: rlf(); break; +case 0x35: rlf(); break; +case 0x36: rlf(); break; +case 0x37: rlf(); break; +/*38*/ +case 0x38: swapf(); break; +case 0x39: swapf(); break; +case 0x3A: swapf(); break; +case 0x3B: swapf(); break; +case 0x3C: incfsz(); break; +case 0x3D: incfsz(); break; +case 0x3E: incfsz(); break; +case 0x3F: incfsz(); break; +/*40*/ +case 0x40: bcf(); break; +case 0x41: bcf(); break; +case 0x42: bcf(); break; +case 0x43: bcf(); break; +case 0x44: bcf(); break; +case 0x45: bcf(); break; +case 0x46: bcf(); break; +case 0x47: bcf(); break; +/*48*/ +case 0x48: bcf(); break; +case 0x49: bcf(); break; +case 0x4A: bcf(); break; +case 0x4B: bcf(); break; +case 0x4C: bcf(); break; +case 0x4D: bcf(); break; +case 0x4E: bcf(); break; +case 0x4F: bcf(); break; +/*50*/ +case 0x50: bsf(); break; +case 0x51: bsf(); break; +case 0x52: bsf(); break; +case 0x53: bsf(); break; +case 0x54: bsf(); break; +case 0x55: bsf(); break; +case 0x56: bsf(); break; +case 0x57: bsf(); break; +/*58*/ +case 0x58: bsf(); break; +case 0x59: bsf(); break; +case 0x5A: bsf(); break; +case 0x5B: bsf(); break; +case 0x5C: bsf(); break; +case 0x5D: bsf(); break; +case 0x5E: bsf(); break; +case 0x5F: bsf(); break; +/*60*/ +case 0x60: btfsc(); break; +case 0x61: btfsc(); break; +case 0x62: btfsc(); break; +case 0x63: btfsc(); break; +case 0x64: btfsc(); break; +case 0x65: btfsc(); break; +case 0x66: btfsc(); break; +case 0x67: btfsc(); break; +/*68*/ +case 0x68: btfsc(); break; +case 0x69: btfsc(); break; +case 0x6A: btfsc(); break; +case 0x6B: btfsc(); break; +case 0x6C: btfsc(); break; +case 0x6D: btfsc(); break; +case 0x6E: btfsc(); break; +case 0x6F: btfsc(); break; +/*70*/ +case 0x70: btfss(); break; +case 0x71: btfss(); break; +case 0x72: btfss(); break; +case 0x73: btfss(); break; +case 0x74: btfss(); break; +case 0x75: btfss(); break; +case 0x76: btfss(); break; +case 0x77: btfss(); break; +/*78*/ +case 0x78: btfss(); break; +case 0x79: btfss(); break; +case 0x7A: btfss(); break; +case 0x7B: btfss(); break; +case 0x7C: btfss(); break; +case 0x7E: btfss(); break; +case 0x7D: btfss(); break; +case 0x7F: btfss(); break; +/*80*/ +case 0x80: retlw(); break; +case 0x81: retlw(); break; +case 0x82: retlw(); break; +case 0x83: retlw(); break; +case 0x84: retlw(); break; +case 0x85: retlw(); break; +case 0x86: retlw(); break; +case 0x87: retlw(); break; +/*88*/ +case 0x88: retlw(); break; +case 0x89: retlw(); break; +case 0x8A: retlw(); break; +case 0x8B: retlw(); break; +case 0x8C: retlw(); break; +case 0x8D: retlw(); break; +case 0x8E: retlw(); break; +case 0x8F: retlw(); break; +/*90*/ +case 0x90: call(); break; +case 0x91: call(); break; +case 0x92: call(); break; +case 0x93: call(); break; +case 0x94: call(); break; +case 0x95: call(); break; +case 0x96: call(); break; +case 0x97: call(); break; +/*98*/ +case 0x98: call(); break; +case 0x99: call(); break; +case 0x9A: call(); break; +case 0x9B: call(); break; +case 0x9C: call(); break; +case 0x9D: call(); break; +case 0x9E: call(); break; +case 0x9F: call(); break; +/*A0*/ +case 0xA0: goto_op(); break; +case 0xA1: goto_op(); break; +case 0xA2: goto_op(); break; +case 0xA3: goto_op(); break; +case 0xA4: goto_op(); break; +case 0xA5: goto_op(); break; +case 0xA6: goto_op(); break; +case 0xA7: goto_op(); break; +/*A8*/ +case 0xA8: goto_op(); break; +case 0xA9: goto_op(); break; +case 0xAA: goto_op(); break; +case 0xAB: goto_op(); break; +case 0xAC: goto_op(); break; +case 0xAD: goto_op(); break; +case 0xAE: goto_op(); break; +case 0xAF: goto_op(); break; +/*B0*/ +case 0xB0: goto_op(); break; +case 0xB1: goto_op(); break; +case 0xB2: goto_op(); break; +case 0xB3: goto_op(); break; +case 0xB4: goto_op(); break; +case 0xB5: goto_op(); break; +case 0xB6: goto_op(); break; +case 0xB7: goto_op(); break; +/*B8*/ +case 0xB8: goto_op(); break; +case 0xB9: goto_op(); break; +case 0xBA: goto_op(); break; +case 0xBB: goto_op(); break; +case 0xBC: goto_op(); break; +case 0xBD: goto_op(); break; +case 0xBE: goto_op(); break; +case 0xBF: goto_op(); break; +/*C0*/ +case 0xC0: movlw(); break; +case 0xC1: movlw(); break; +case 0xC2: movlw(); break; +case 0xC3: movlw(); break; +case 0xC4: movlw(); break; +case 0xC5: movlw(); break; +case 0xC6: movlw(); break; +case 0xC7: movlw(); break; +/*C8*/ +case 0xC8: movlw(); break; +case 0xC9: movlw(); break; +case 0xCA: movlw(); break; +case 0xCB: movlw(); break; +case 0xCC: movlw(); break; +case 0xCD: movlw(); break; +case 0xCE: movlw(); break; +case 0xCF: movlw(); break; +/*D0*/ +case 0xD0: iorlw(); break; +case 0xD1: iorlw(); break; +case 0xD2: iorlw(); break; +case 0xD3: iorlw(); break; +case 0xD4: iorlw(); break; +case 0xD5: iorlw(); break; +case 0xD6: iorlw(); break; +case 0xD7: iorlw(); break; +/*D8*/ +case 0xD8: iorlw(); break; +case 0xD9: iorlw(); break; +case 0xDA: iorlw(); break; +case 0xDB: iorlw(); break; +case 0xDC: iorlw(); break; +case 0xDD: iorlw(); break; +case 0xDE: iorlw(); break; +case 0xDF: iorlw(); break; +/*E0*/ +case 0xE0: andlw(); break; +case 0xE1: andlw(); break; +case 0xE2: andlw(); break; +case 0xE3: andlw(); break; +case 0xE4: andlw(); break; +case 0xE5: andlw(); break; +case 0xE6: andlw(); break; +case 0xE7: andlw(); break; +/*E8*/ +case 0xE8: andlw(); break; +case 0xE9: andlw(); break; +case 0xEA: andlw(); break; +case 0xEB: andlw(); break; +case 0xEC: andlw(); break; +case 0xED: andlw(); break; +case 0xEE: andlw(); break; +case 0xEF: andlw(); break; +/*F0*/ +case 0xF0: xorlw(); break; +case 0xF1: xorlw(); break; +case 0xF2: xorlw(); break; +case 0xF3: xorlw(); break; +case 0xF4: xorlw(); break; +case 0xF5: xorlw(); break; +case 0xF6: xorlw(); break; +case 0xF7: xorlw(); break; +/*F8*/ +case 0xF8: xorlw(); break; +case 0xF9: xorlw(); break; +case 0xFA: xorlw(); break; +case 0xFB: xorlw(); break; +case 0xFC: xorlw(); break; +case 0xFD: xorlw(); break; +case 0xFE: xorlw(); break; +case 0xFF: xorlw(); break; diff --git a/src/mappers/hw/txc.c b/src/mappers/hw/txc.c new file mode 100644 index 000000000..5c7b0e690 --- /dev/null +++ b/src/mappers/hw/txc.c @@ -0,0 +1,138 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + * 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) + * + * TXC mappers, originally much complex banksitching + * + * 01-22111-000 (05-00002-010) (132, 22211) - MGC-001 Qi Wang + * 01-22110-000 (52S ) - MGC-002 2-in-1 Gun + * 01-22111-100 (02-00002-010) (173 ) - MGC-008 Mahjong Block + * (079 ) - MGC-012 Poke Block + * 01-22110-200 (05-00002-010) (036 ) - MGC-014 Strike Wolf + * 01-22000-400 (05-00002-010) (036 ) - MGC-015 Policeman + * 01-22017-000 (05-PT017-080) (189 ) - MGC-017 Thunder Warrior + * 01-11160-000 (04-02310-000) ( , 11160) - MGC-023 6-in-1 + * 01-22270-000 (05-00002-010) (132, 22211) - MGC-xxx Creatom + * 01-22200-400 (------------) (079 ) - ET.03 F-15 City War + * (172 ) - 1991 Du Ma Racing + * + */ + +/* added 2020-2-16 + * Updated based on latest source + * Mappers 36, 132, 173 + * Mappers 136, 147, 172 + */ + +#include "mapinc.h" +#include "txc.h" + +TXC txc; + +static void Dummyfunc(void) { } +static void (*WSync)(void) = Dummyfunc; + +static SFORMAT StateRegs[] = +{ + { &txc.accumulator, 1, "ACC0" }, + { &txc.inverter, 1, "INVR" }, + { &txc.staging, 1, "STG0" }, + { &txc.output, 1, "OUT0" }, + { &txc.increase, 1, "INC0" }, + { &txc.X, 1, "XFLG" }, + { &txc.Y, 1, "YFLG" }, + { &txc.invert, 1, "INVT" }, + { 0 } +}; + +DECLFR(TXC_Read) { + uint8 ret = cpu.openbus; + if ((A & 0x103) == 0x100) { + ret = ((txc.accumulator & 0x07) | ((txc.inverter ^ txc.invert) & ~0x07)); + txc.Y = txc.X || ((ret & 0x10) != 0); + WSync(); + } + return ret; +} + +DECLFW(TXC_Write) { + if (A & 0x8000) { + txc.output = (txc.accumulator & 0x0F) | ((txc.inverter << 1) & 0x10); + } else { + switch (A & 0x103) { + case 0x100: + if (txc.increase) { + txc.accumulator++; + } else { + txc.accumulator = ((txc.accumulator & ~0x07) | ((txc.staging ^ txc.invert) & 0x07)); + } + break; + case 0x101: + txc.invert = (V & 0x01) ? 0xFF : 0x00; + break; + case 0x102: + txc.staging = V & 0x07; + txc.inverter = V & ~0x07; + break; + case 0x103: + txc.increase = ((V & 0x01) != 0); + break; + } + } + txc.X = txc.invert ? txc.A : txc.B; + txc.Y = txc.X || ((V & 0x10) != 0); + WSync(); +} + +static void TXCRegReset(void) { + WSync(); +} + +void TXC_Power(void) { + txc.output = 0; + txc.accumulator = 0; + txc.inverter = 0; + txc.staging = 0; + txc.increase = 0; + txc.invert = 0; + txc.X = 0; + txc.Y = 0; + txc.A = 0; + txc.B = 1; + TXCRegReset(); +} + +static void StateRestore(int version) { + WSync(); +} + +void TXC_Init(CartInfo *info, void (*proc)(void)) { + WSync = proc; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/hw/txc.h b/src/mappers/hw/txc.h new file mode 100644 index 000000000..589ec32ee --- /dev/null +++ b/src/mappers/hw/txc.h @@ -0,0 +1,46 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _TXC_H +#define _TXC_H + +typedef struct __TXC { + uint8 accumulator; + uint8 inverter; + uint8 staging; + uint8 output; + uint8 increase; + uint8 invert; + uint8 A; + uint8 B; + uint8 X; + uint8 Y; +} TXC; + +extern TXC txc; + +DECLFR(TXC_Read); +DECLFW(TXC_Write); + +void TXC_Power(void); + +void TXC_Init(CartInfo *info, void (*proc)(void)); + +#endif /* _TXC_H */ diff --git a/src/mappers/hw/vrc2and4.c b/src/mappers/hw/vrc2and4.c new file mode 100644 index 000000000..ab0836b72 --- /dev/null +++ b/src/mappers/hw/vrc2and4.c @@ -0,0 +1,277 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2007 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + * VRC-2/VRC-4 Konami + * VRC-4 Pirate + * + * VRC2 + * Nickname PCB A0 A1 Registers iNES mapper submapper + * VRC2a 351618 A1 A0 $x000, $x002, $x001, $x003 22 0 + * VRC2b many† A0 A1 $x000, $x001, $x002, $x003 23 3 + * VRC2c 351948 A1 A0 $x000, $x002, $x001, $x003 25 3 + * VRC4 + * Nickname PCB A0 A1 Registers iNES mapper submapper + * VRC4a 352398 A1 A2 $x000, $x002, $x004, $x006 21 1 + * VRC4b 351406 A1 A0 $x000, $x002, $x001, $x003 25 1 + * VRC4c 352889 A6 A7 $x000, $x040, $x080, $x0C0 21 2 + * VRC4d 352400 A3 A2 $x000, $x008, $x004, $x00C 25 2 + * VRC4e 352396 A2 A3 $x000, $x004, $x008, $x00C 23 2 + * VRC4f - A0 A1 $x000, $x001, $x002, $x003 23 1 + * + */ + +#include "mapinc.h" +#include "vrc2and4.h" +#include "vrcirq.h" + +uint8 vrc2and4_VRC4; +uint32 vrc2and4_A0; +uint32 vrc2and4_A1; + +void (*VRC24_FixPRG)(void); +void (*VRC24_FixCHR)(void); +void (*VRC24_FixMIR)(void); + +void (*VRC24_pwrap)(uint32 A, uint8 V); +void (*VRC24_cwrap)(uint32 A, uint32 V); +void (*VRC24_miscWrite)(uint32 A, uint8 V); + +VRC24 vrc24; + +static SFORMAT StateRegs[] = { + { vrc24.prg, 2, "PREG" }, + { vrc24.chr, 16, "CREG" }, + { &vrc24.cmd, 1, "CMDR" }, + { &vrc24.mirr, 1, "MIRR" }, + { &vrc24.latch, 1, "LATC" }, + + { 0 } +}; + +static void GENFIXPRG(void) { + if (vrc24.cmd & 2) { + VRC24_pwrap(0x8000, ~1); + VRC24_pwrap(0xC000, vrc24.prg[0]); + } else { + VRC24_pwrap(0x8000, vrc24.prg[0]); + VRC24_pwrap(0xC000, ~1); + } + VRC24_pwrap(0xA000, vrc24.prg[1]); + VRC24_pwrap(0xE000, ~0); +} + +static void GENFIXCHR(void) { + VRC24_cwrap(0x0000, vrc24.chr[0]); + VRC24_cwrap(0x0400, vrc24.chr[1]); + VRC24_cwrap(0x0800, vrc24.chr[2]); + VRC24_cwrap(0x0C00, vrc24.chr[3]); + VRC24_cwrap(0x1000, vrc24.chr[4]); + VRC24_cwrap(0x1400, vrc24.chr[5]); + VRC24_cwrap(0x1800, vrc24.chr[6]); + VRC24_cwrap(0x1C00, vrc24.chr[7]); +} + +static void GENFIXMIR(void) { + switch (vrc24.mirr & (vrc2and4_VRC4 ? 0x03 : 0x01)) { + case 0: setmirror(MI_V); break; + case 1: setmirror(MI_H); break; + case 2: setmirror(MI_0); break; + case 3: setmirror(MI_1); break; + } +} + +static DECLFR(VRC24WRAMRead) { + A = 0x6000 | (A & (WRAMSIZE - 1)); + return CartBR(A); +} + +static DECLFW(VRC24WRAMWrite) { + A = 0x6000 | (A & (WRAMSIZE - 1)); + CartBW(A, V); +} + +static DECLFR(VRC24LatchRead) { + return (cpu.openbus & ~0x01) | (vrc24.latch & 0x01); +} + +static DECLFW(VRC24LatchWrite) { + vrc24.latch = V; + VRC24_FixPRG(); + VRC24_FixCHR(); +} + +DECLFW(VRC24_Write) { + uint8 index; + + switch (A & 0xF000) { + case 0x8000: + case 0xA000: + vrc24.prg[(A >> 13) & 0x01] = V & 0x1F; + VRC24_FixPRG(); + break; + + case 0x9000: + index = ((A & vrc2and4_A1) ? 0x02 : 0x00) | ((A & vrc2and4_A0) ? 0x01 : 0x00); + switch (index & (vrc2and4_VRC4 ? 0x03 : 0x00)) { + case 0: + case 1: + if (V != 0xFF) { + vrc24.mirr = V; + VRC24_FixMIR(); + } + break; + case 2: + vrc24.cmd = V; + VRC24_FixPRG(); + break; + case 3: + if (VRC24_miscWrite) { + VRC24_miscWrite(A, V); + } + break; + } + break; + + case 0xF000: + index = ((A & vrc2and4_A1) ? 0x02 : 0x00) | ((A & vrc2and4_A0) ? 0x01 : 0x00); + switch (index) { + case 0x00: VRCIRQ_LatchNibble(V, 0); break; + case 0x01: VRCIRQ_LatchNibble(V, 1); break; + case 0x02: VRCIRQ_Control(V); break; + case 0x03: VRCIRQ_Acknowledge(); break; + } + break; + + default: + index = (((A - 0xB000) >> 11) & 0x06) | ((A & vrc2and4_A1) ? 0x01 : 0x00); + if (A & vrc2and4_A0) { + /* m25 can be 512K, rest are 256K or less */ + vrc24.chr[index] = (vrc24.chr[index] & 0x000F) | (V << 4); + } else { + vrc24.chr[index] = (vrc24.chr[index] & 0x0FF0) | (V & 0x0F); + } + VRC24_cwrap(index << 10, vrc24.chr[index]); + break; + } +} + +static void GENPWRAP(uint32 A, uint8 V) { + setprg8(A, V & 0x1F); +} + +static void GENCWRAP(uint32 A, uint32 V) { + setchr1(A, V & 0x1FF); +} + +void VRC24_IRQCPUHook(int a) { + VRCIRQ_CPUHook(a); +} + +void VRC24_Reset(void) { + vrc24.prg[0] = 0; + vrc24.prg[1] = 1; + + vrc24.chr[0] = 0; + vrc24.chr[1] = 1; + vrc24.chr[2] = 2; + vrc24.chr[3] = 3; + vrc24.chr[4] = 4; + vrc24.chr[5] = 5; + vrc24.chr[6] = 6; + vrc24.chr[7] = 7; + + vrc24.cmd = vrc24.mirr = 0; + + VRC24_FixPRG(); + VRC24_FixCHR(); +} + +void VRC24_Power(void) { + VRC24_Reset(); + + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, VRC24_Write); + + if (WRAMSIZE) { + setprg8r(0x10, 0x6000, 0); + SetReadHandler(0x6000, 0x7FFF, VRC24WRAMRead); + SetWriteHandler(0x6000, 0x7FFF, VRC24WRAMWrite); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + } else if (!vrc2and4_VRC4) { + /* microwire interface */ + SetReadHandler(0x6000, 0x6FFF, VRC24LatchRead); + SetWriteHandler(0x6000, 0x6FFF, VRC24LatchWrite); + } + + if (UNIFchrrama) { + setchr8(0); + } +} + +static void StateRestore(int version) { + VRC24_FixPRG(); + VRC24_FixCHR(); + VRC24_FixMIR(); +} + +void VRC24_Close(void) { +} + +void VRC24_Init(CartInfo *info, uint8 vrc4, uint32 A0, uint32 A1, int wram, int irqRepeated) { + VRC24_FixPRG = GENFIXPRG; + VRC24_FixCHR = GENFIXCHR; + VRC24_FixMIR = GENFIXMIR; + + VRC24_pwrap = GENPWRAP; + VRC24_cwrap = GENCWRAP; + VRC24_miscWrite = NULL; + + vrc2and4_A0 = A0; + vrc2and4_A1 = A1; + vrc2and4_VRC4 = vrc4; + + if (wram) { + if (info->iNES2) { + WRAMSIZE = info->PRGRamSize + info->PRGRamSaveSize; + } else { + WRAMSIZE = 8192; + } + if (WRAMSIZE) { + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + } + } + + AddExState(StateRegs, ~0, 0, NULL); + + info->Power = VRC24_Power; + info->Close = VRC24_Close; + GameStateRestore = StateRestore; + + VRCIRQ_Init(irqRepeated); + MapIRQHook = VRCIRQ_CPUHook; + AddExState(&VRCIRQ_StateRegs, ~0, 0, 0); +} diff --git a/src/mappers/hw/vrc2and4.h b/src/mappers/hw/vrc2and4.h new file mode 100644 index 000000000..4067ba0f2 --- /dev/null +++ b/src/mappers/hw/vrc2and4.h @@ -0,0 +1,74 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _VRC24_H +#define _VRC24_H + +typedef enum { + VRC2a = 1, /* Mapper 22 */ + VRC2b, /* Mapper 23 */ + VRC2c, /* Mapper 25 */ + VRC4a, /* Mapper 21 */ + VRC4b, /* Mapper 25 */ + VRC4c, /* Mapper 21 */ + VRC4d, /* Mapper 25 */ + VRC4e, /* Mapper 23 */ + VRC4f, /* Mapper 23 */ + VRC4_544, + VRC4_559 +} VRC24Type; + +enum { + VRC2 = 0, + VRC4 +}; + +typedef struct __VRC24 { + uint8 prg[2]; + uint16 chr[8]; + uint8 cmd; + uint8 mirr; + uint8 latch; /* VRC2 $6000-$6FFF */ +} VRC24; + +extern VRC24 vrc24; + +extern uint8 vrc2and4_VRC4; +extern uint32 vrc2and4_A0; +extern uint32 vrc2and4_A1; + +DECLFW(VRC24_Write); + +void VRC24_IRQCPUHook(int a); +void VRC24_Reset(void); +void VRC24_Power(void); +void VRC24_Close(void); + +void VRC24_Init(CartInfo *info, uint8 vrc4, uint32 A0, uint32 A1, int wram, int irqRepeated); + +extern void (*VRC24_FixPRG)(void); +extern void (*VRC24_FixCHR)(void); +extern void (*VRC24_FixMIR)(void); + +extern void (*VRC24_pwrap)(uint32 A, uint8 V); +extern void (*VRC24_cwrap)(uint32 A, uint32 V); +extern void (*VRC24_miscWrite)(uint32 A, uint8 V); + +#endif /* _VRC24_H */ diff --git a/src/mappers/hw/vrc6.c b/src/mappers/hw/vrc6.c new file mode 100644 index 000000000..c9e699d76 --- /dev/null +++ b/src/mappers/hw/vrc6.c @@ -0,0 +1,206 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2009 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 + * + * VRC-6 + * + */ + +#include "mapinc.h" +#include "vrc6.h" +#include "vrcirq.h" +#include "vrc6sound.h" + +static uint32 vrc6_A0; +static uint32 vrc6_A1; + +VRC6 vrc6; + +void (*VRC6_pwrap)(uint32 A, uint8 V); +void (*VRC6_cwrap)(uint32 A, uint8 V); + +static SFORMAT StateRegs[] = +{ + { vrc6.prg, 2, "PRG" }, + { vrc6.chr, 8, "CHR" }, + { &vrc6.mirr, 1, "MIRR" }, + + { 0 } +}; + +static void GENPWRAP(uint32 A, uint8 V) { + setprg8(A, V & 0x3F); +} + +static void GENCWRAP(uint32 A, uint8 V) { + setchr1(A, V & 0xFF); +} + +void VRC6_FixMIR(void) { + switch (vrc6.mirr & 3) { + case 0: setmirror(MI_V); break; + case 1: setmirror(MI_H); break; + case 2: setmirror(MI_0); break; + case 3: setmirror(MI_1); break; + } +} + +void VRC6_FixPRG(void) { + VRC6_pwrap(0x8000, (vrc6.prg[0] << 1) | 0x00); + VRC6_pwrap(0xa000, (vrc6.prg[0] << 1) | 0x01); + VRC6_pwrap(0xc000, vrc6.prg[1]); + VRC6_pwrap(0xe000, ~0); +} + +void VRC6_FixCHR(void) { + int i; + + for (i = 0; i < 8; i++) { + VRC6_cwrap(i << 10, vrc6.chr[i]); + } +} + +DECLFW(VRC6_Write) { + int index; + + A = (A & 0xF000) | ((A & vrc6_A1) ? 0x02 : 0x00) | ((A & vrc6_A0) ? 0x01 : 0x00); + switch (A & 0xF000) { + case 0x8000: + vrc6.prg[0] = V; + VRC6_pwrap(0x8000, (V << 1) | 0x00); + VRC6_pwrap(0xA000, (V << 1) | 0x01); + break; + case 0x9000: + case 0xA000: + case 0xB000: + if (A >= 0x9000 && A <= 0xB002) { + VRC6Sound_Write(A, V); + } else { + vrc6.mirr = (V >> 2) & 3; + VRC6_FixMIR(); + } + break; + case 0xC000: + vrc6.prg[1] = V; + VRC6_pwrap(0xC000, V); + break; + case 0xD000: + case 0xE000: + index = ((A - 0xD000) >> 10) | (A & 0x03); + vrc6.chr[index] = V; + VRC6_cwrap(index << 10, V); + break; + case 0xF000: + index = A & 0x03; + switch (index) { + case 0x00: VRCIRQ_Latch(V); break; + case 0x01: VRCIRQ_Control(V); break; + case 0x02: VRCIRQ_Acknowledge(); break; + } + } +} + +void VRC6_IRQCPUHook(int a) { + VRCIRQ_CPUHook(a); +} + +void VRC6_Reset(void) { + vrc6.prg[0] = 0; + vrc6.prg[1] = 1; + + vrc6.chr[0] = 0; + vrc6.chr[1] = 1; + vrc6.chr[2] = 2; + vrc6.chr[3] = 3; + vrc6.chr[4] = 4; + vrc6.chr[5] = 5; + vrc6.chr[6] = 6; + vrc6.chr[7] = 7; + + vrc6.mirr = 0; + + VRC6_FixPRG(); + VRC6_FixCHR(); + VRC6_FixMIR(); +} + +void VRC6_Power(void) { + VRC6_Reset(); + + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, VRC6_Write); + + if (WRAMSIZE) { + setprg8r(0x10, 0x6000, 0); + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + } +} + +void VRC6_Close(void) { +} + +void VRC6_Restore(int version) { + VRC6_FixPRG(); + VRC6_FixCHR(); + VRC6_FixMIR(); +} + +void VRC6_Init(CartInfo *info, uint32 A0, uint32 A1, int wram) { + VRC6_pwrap = GENPWRAP; + VRC6_cwrap = GENCWRAP; + + vrc6_A0 = A0; + vrc6_A1 = A1; + + if (wram) { + if (info->iNES2) { + WRAMSIZE = info->PRGRamSize + info->PRGRamSaveSize; + } else if (info->mapper == 26) { + WRAMSIZE = 8192; + } + if (WRAMSIZE) { + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + } + } + AddExState(StateRegs, ~0, 0, NULL); + + info->Power = VRC6_Power; + info->Close = VRC6_Close; + GameStateRestore = VRC6_Restore; + + VRCIRQ_Init(TRUE); + MapIRQHook = VRC6_IRQCPUHook; + AddExState(&VRCIRQ_StateRegs, ~0, 0, 0); + + VRC6Sound_ESI(); + VRC6Sound_AddStateInfo(); +} + +void NSFVRC6_Init(int chip, int A0, int A1) { + VRC6Sound_ESI(); + vrc6_A0 = A0; + vrc6_A1 = A1; +} diff --git a/src/mappers/hw/vrc6.h b/src/mappers/hw/vrc6.h new file mode 100644 index 000000000..068a1e587 --- /dev/null +++ b/src/mappers/hw/vrc6.h @@ -0,0 +1,49 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _VRC6_H +#define _VRC6_H + +typedef struct __VRC6 { + uint8 prg[2]; + uint8 chr[8]; + uint8 mirr; +} VRC6; + +extern VRC6 vrc6; + +DECLFW(VRC6_Write); + +void VRC6_Power(void); +void VRC6_Reset(void); +void VRC6_Close(void); +void VRC6_Restore(int version); +void VRC6_IRQCPUHook(int a); + +void VRC6_Init(CartInfo *info, uint32 A0, uint32 A1, int wram); + +void VRC6_FixPRG(void); +void VRC6_FixCHR(void); +void VRC6_FixMIR(void); + +extern void (*VRC6_pwrap)(uint32 A, uint8 V); +extern void (*VRC6_cwrap)(uint32 A, uint8 V); + +#endif /* _VRC6_H */ diff --git a/src/mappers/hw/vrc7.c b/src/mappers/hw/vrc7.c new file mode 100644 index 000000000..12c4f6cba --- /dev/null +++ b/src/mappers/hw/vrc7.c @@ -0,0 +1,191 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "vrcirq.h" +#include "vrc7sound.h" +#include "vrc7.h" + +static uint32 vrc7_A0; +static uint32 vrc7_A1; + +VRC7 vrc7; + +void (*VRC7_pwrap)(uint32 A, uint8 V); +void (*VRC7_cwrap)(uint32 A, uint8 V); +void (*VRC7_mwrap)(uint8 V); + +static SFORMAT StateRegs[] = +{ + { vrc7.prg, 3, "PREG" }, + { vrc7.chr, 8, "CREG" }, + { &vrc7.mirr, 1, "MIRR" }, + + { 0 } +}; + +static void GENPWRAP(uint32 A, uint8 V) { + setprg8(A, V & 0x3F); +} + +static void GENCWRAP(uint32 A, uint8 V) { + setchr1(A, V & 0xFF); +} + +static void GENMWRAP(uint8 V) { + vrc7.mirr = V; + + switch (vrc7.mirr & 3) { + case 0: setmirror(MI_V); break; + case 1: setmirror(MI_H); break; + case 2: setmirror(MI_0); break; + case 3: setmirror(MI_1); break; + } +} + +void VRC7_FixPRG(void) { + setprg8r(0x10, 0x6000, 0); + VRC7_pwrap(0x8000, vrc7.prg[0]); + VRC7_pwrap(0xa000, vrc7.prg[1]); + VRC7_pwrap(0xc000, vrc7.prg[2]); + VRC7_pwrap(0xe000, ~0); +} + +void VRC7_FixCHR(void) { + int i; + for (i = 0; i < 8; i++) { + VRC7_cwrap(i << 10, vrc7.chr[i]); + } + + if (VRC7_mwrap) { + VRC7_mwrap(vrc7.mirr); + } +} + +DECLFW(VRC7_Write) { + int index; + switch (A & 0xF000) { + case 0x8000: + case 0x9000: + index = ((A >> 11) & 0x02) | ((A & vrc7_A0) ? 0x01 : 0x00); + switch (index) { + case 0x00: + case 0x01: + case 0x02: + vrc7.prg[index] = V; + VRC7_FixPRG(); + break; + default: + VRC7Sound_Write(A, V); + break; + } + break; + + case 0xA000: + case 0xB000: + case 0xC000: + case 0xD000: + index = ((A - 0xA000) >> 11) | ((A & vrc7_A0) ? 0x01 : 0x00); + vrc7.chr[index] = V; + VRC7_FixCHR(); + break; + + case 0xE000: + case 0xF000: + index = ((A >> 11) & 0x02) | ((A & vrc7_A0) ? 0x01 : 0x00); + switch (index) { + case 0x00: if (VRC7_mwrap) VRC7_mwrap(V); break; + case 0x01: VRCIRQ_Latch(V); break; + case 0x02: VRCIRQ_Control(V); break; + case 0x03: VRCIRQ_Acknowledge(); break; + } + break; + } +} + +void VRC7_Power(void) { + vrc7.prg[0] = 0; + vrc7.prg[1] = 1; + vrc7.prg[2] = ~1; + + vrc7.chr[0] = 0; + vrc7.chr[1] = 1; + vrc7.chr[2] = 2; + vrc7.chr[3] = 3; + vrc7.chr[4] = 4; + vrc7.chr[5] = 5; + vrc7.chr[6] = 6; + vrc7.chr[7] = 7; + + vrc7.mirr = 0; + + VRC7_FixPRG(); + VRC7_FixCHR(); + + SetWriteHandler(0x6000, 0x7FFF, CartBW); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, VRC7_Write); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); +} + +void VRC7_Close(void) { +} + +static void StateRestore(int version) { + VRC7_FixPRG(); + VRC7_FixCHR(); +} + +void VRC7_Init(CartInfo *info, uint32 A0, uint32 A1) { + VRC7_pwrap = GENPWRAP; + VRC7_cwrap = GENCWRAP; + VRC7_mwrap = GENMWRAP; + + vrc7_A0 = A0; + vrc7_A1 = A1; + + WRAMSIZE = 8192; + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + AddExState(StateRegs, ~0, 0, NULL); + + info->Power = VRC7_Power; + info->Close = VRC7_Close; + GameStateRestore = StateRestore; + + VRCIRQ_Init(TRUE); + MapIRQHook = VRCIRQ_CPUHook; + AddExState(&VRCIRQ_StateRegs, ~0, 0, 0); + + VRC7Sound_ESI(); + VRC7Sound_AddStateInfo(); +} + +void NSFVRC7_Init(int chip, int A0, int A1) { + VRC7Sound_ESI(); + vrc7_A0 = A0; + vrc7_A1 = A1; +} diff --git a/src/mappers/hw/vrc7.h b/src/mappers/hw/vrc7.h new file mode 100644 index 000000000..98a1fb49c --- /dev/null +++ b/src/mappers/hw/vrc7.h @@ -0,0 +1,46 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _VRC7_H +#define _VRC7_H + +typedef struct __VRC7 { + uint8 prg[4]; + uint8 chr[8]; + uint8 mirr; +} VRC7; + +extern VRC7 vrc7; + +DECLFW(VRC7_Write); + +void VRC7_Power(void); +void VRC7_Close(void); + +void VRC7_Init(CartInfo *info, uint32 A0, uint32 A1); + +void VRC7_FixPRG(void); +void VRC7_FixCHR(void); + +extern void (*VRC7_pwrap)(uint32 A, uint8 V); +extern void (*VRC7_cwrap)(uint32 A, uint8 V); +extern void (*VRC7_mwrap)(uint8 V); + +#endif /* _VRC7_H */ diff --git a/src/mappers/hw/vrcirq.c b/src/mappers/hw/vrcirq.c new file mode 100644 index 000000000..f0396a874 --- /dev/null +++ b/src/mappers/hw/vrcirq.c @@ -0,0 +1,117 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "vrcirq.h" + +static int16 IRQPrescaler; +static uint8 IRQCount, IRQLatch, IRQd, IRQa, IRQm, IRQr; + +static uint8 IRQScanPos; +static uint8 IRQScanLut[3] = { 113, 113, 112 }; + +SFORMAT VRCIRQ_StateRegs[] = { + { &IRQPrescaler, 2, "PREC" }, + { &IRQCount, 1, "IRQC" }, + { &IRQLatch, 1, "IRQL" }, + { &IRQd, 1, "IRQD" }, + { &IRQa, 1, "IRQA" }, + { &IRQm, 1, "IRQM" }, + { &IRQr, 1, "IRQR" }, + { &IRQScanPos, 1, "IPOS" }, + { 0 } +}; + +static void VRCIRQ_Clock(void) { + if (IRQCount == 0xFF) { + X6502_IRQBegin(FCEU_IQEXT); + IRQCount = IRQLatch; + } else { + IRQCount++; + } +} + +void VRCIRQ_CPUHook(int a) { + if (!IRQa) { + return; + } + + while (a--) { + if (IRQm) { /* cycle mode */ + VRCIRQ_Clock(); + } else { + if (IRQPrescaler >= IRQScanLut[IRQScanPos]) { + VRCIRQ_Clock(); + IRQScanPos++; + if (IRQScanPos >= 3) IRQScanPos = 0; + IRQPrescaler = 0; + } else { + IRQPrescaler++; + } + } + } +} + +void VRCIRQ_Latch(uint8 V) { + IRQLatch = V; +} + +void VRCIRQ_LatchNibble(uint8 V, uint8 highBit) { + if (highBit) { + IRQLatch &= 0x0F; + IRQLatch |= V << 4; + } else { + IRQLatch &= 0xF0; + IRQLatch |= V & 0xF; + } +} + +void VRCIRQ_Control(uint8 V) { + IRQd = (V & 0x01) == 0x01; + IRQa = (V & 0x02) == 0x02; + IRQm = (V & 0x04) == 0x04; + + if (IRQa) { + IRQCount = IRQLatch; + IRQPrescaler = 0; + IRQScanPos = 0; + } + + X6502_IRQEnd(FCEU_IQEXT); +} + +void VRCIRQ_Acknowledge(void) { + if (IRQr == TRUE) { + IRQa = IRQd; + } + + X6502_IRQEnd(FCEU_IQEXT); +} + +void VRCIRQ_Init(int irqRepeated) { + IRQPrescaler = 0; + IRQCount = 0; + IRQLatch = 0; + IRQd = 0; + IRQa = 0; + IRQm = 0; + IRQr = irqRepeated ? TRUE : FALSE; + IRQScanPos = 0; +} diff --git a/src/mappers/hw/vrcirq.h b/src/mappers/hw/vrcirq.h new file mode 100644 index 000000000..87f989729 --- /dev/null +++ b/src/mappers/hw/vrcirq.h @@ -0,0 +1,33 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _VRCIRQ_H +#define _VRCIRQ_H + +void VRCIRQ_Init(int irqRepeated); +void VRCIRQ_Latch(uint8 V); +void VRCIRQ_LatchNibble(uint8 V, uint8 highBit); +void VRCIRQ_Control(uint8 V); +void VRCIRQ_Acknowledge(void); +void VRCIRQ_CPUHook(int a); + +extern SFORMAT VRCIRQ_StateRegs[]; + +#endif /* _VRCIRQ_H */ diff --git a/src/boards/mapinc.h b/src/mappers/mapinc.h similarity index 66% rename from src/boards/mapinc.h rename to src/mappers/mapinc.h index ba3964dba..b58913a89 100644 --- a/src/boards/mapinc.h +++ b/src/mappers/mapinc.h @@ -1,3 +1,6 @@ +#ifndef _MAPINC_H +#define _MAPINC_H + #include "../fceu-types.h" #include "../x6502.h" #include "../fceu.h" @@ -9,4 +12,10 @@ #include "../cheat.h" #include "../unif.h" #include "../ines.h" +#include "../nsf.h" #include + +void MMC5_hb(int scanline); +void NSFMMC5_Close(void); + +#endif /* _MAPINC_H */ diff --git a/src/mappers/mapper000.c b/src/mappers/mapper000.c new file mode 100644 index 000000000..644d88d8c --- /dev/null +++ b/src/mappers/mapper000.c @@ -0,0 +1,74 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static void NROMClose(void) { +} + +static void NROMPower(void) { + if (ROM.prg.size == 3) { /* NROM-368 */ + setprg16(0x4000, 0); + setprg16(0x8000, 1); + setprg16(0xC000, 2); + SetReadHandler(0x4800, 0xFFFF, CartBR); + } else { + setprg32(0x8000, 0); + SetReadHandler(0x8000, 0xFFFF, CartBR); + + if (WRAMSIZE) { + setprg8r(0x10, 0x6000, 0); /* Famili BASIC (v3.0) need it (uses only 4KB), FP-BASIC uses 8KB */ + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + } + } + + setchr8(0); +} + +void Mapper000_Init(CartInfo *info) { + info->Power = NROMPower; + info->Close = NROMClose; + + WRAMSIZE = 8192; + + if (info->submapper) { + WRAMSIZE = info->PRGRamSize + info->PRGRamSaveSize; + } + + if (WRAMSIZE) { + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + } + + if (!UNIFchrrama && info->CHRRamSize) { + /* A variant of Wild Ball with both chr-rom and chr-ram indicated in header. */ + /* Chr-rom in this case should be remapped as chr-ram */ + SetupCartCHRMapping(0, CHRptr[0], CHRsize[0], 1); + } +} diff --git a/src/mappers/mapper001.c b/src/mappers/mapper001.c new file mode 100644 index 000000000..398d7c8ce --- /dev/null +++ b/src/mappers/mapper001.c @@ -0,0 +1,67 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "mmc1.h" + +static int DetectMMC1WRAMSize(CartInfo *info, int *saveRAM) { + int workRAM = 8; + + if (info->iNES2) { + workRAM = (info->PRGRamSize + info->PRGRamSaveSize) / 1024; + *saveRAM = info->PRGRamSaveSize / 1024; + /* we only support sizes between 8K and 32K */ + if (workRAM > 0 && workRAM < 8) + workRAM = 8; + if (workRAM > 32) + workRAM = 32; + if (*saveRAM > 0 && *saveRAM < 8) + *saveRAM = 8; + if (*saveRAM > 32) + *saveRAM = 32; + /* save ram cannot be bigger than workram */ + if (*saveRAM > workRAM) { + *saveRAM = workRAM; + workRAM = 0; + } + } else if (info->battery) { + *saveRAM = 8; + } + if (workRAM > 8) { + FCEU_printf(" >8KB external WRAM present. Use NES 2.0 if you hack the ROM image.\n"); + } + return workRAM; +} + +static void M001PW(uint32 A, uint8 V) { + if (iNESCart.submapper == 5) { + setprg32(0x8000, 0); + } else { + setprg16(A, (MMC1_GetCHRBank(0) & 0x10) | (V & 0x0F)); + } +} + +void Mapper001_Init(CartInfo *info) { + int bs = 0; + int ws = DetectMMC1WRAMSize(info, &bs); + MMC1_Init(info, ws, bs); + MMC1_pwrap = M001PW; + mmc1_type = (info->submapper == 3) ? MMC1A : MMC1B; +} diff --git a/src/mappers/mapper002.c b/src/mappers/mapper002.c new file mode 100644 index 000000000..7c329069c --- /dev/null +++ b/src/mappers/mapper002.c @@ -0,0 +1,34 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg8r(0x10, 0x6000, 0); + setprg16(0x8000, latch.data); + setprg16(0xC000, ~0); + setchr8(0); +} + +void Mapper002_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, TRUE, (info->submapper == 2)); +} diff --git a/src/mappers/mapper003.c b/src/mappers/mapper003.c new file mode 100644 index 000000000..9a460a310 --- /dev/null +++ b/src/mappers/mapper003.c @@ -0,0 +1,33 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg8r(0x10, 0x6000, 0); /* Hayauchy IGO uses 2Kb or RAM */ + setprg32(0x8000, 0); + setchr8(latch.data); +} + +void Mapper003_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, TRUE, (info->submapper == 2)); +} diff --git a/src/mappers/mapper004.c b/src/mappers/mapper004.c new file mode 100644 index 000000000..d6673706f --- /dev/null +++ b/src/mappers/mapper004.c @@ -0,0 +1,70 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "mmc6.h" + +static void M004PW(uint32 A, uint8 V) { + setprg8(A, V & 0xFF); +} + +static void M004CW(uint32 A, uint8 V) { + setchr1(A, V & 0xFF); +} + +void Mapper004_Init(CartInfo *info) { + int ws = 8; + + if (info->submapper == 1) { + MMC6_Init(info); + return; + } + + if (info->submapper == 5) { + Mapper249_Init(info); + return; + } + + if (!info->iNES2) { + if ((info->CRC32 == 0x93991433) || (info->CRC32 == 0xaf65aa84)) { + FCEU_printf( + "Low-G-Man can not work normally in the iNES format.\nThis game has been recognized by its CRC32 " + "value, and the appropriate changes will be made so it will run.\nIf you wish to hack this game, " + "you should use the UNIF format for your hack.\n\n"); + ws = 0; + } + } else { + ws = (info->PRGRamSize + info->PRGRamSaveSize) / 1024; + } + + if ((info->submapper == 4) || (info->CRC32 == 0x97b6cb19)) { + isRevB = 0; /* MMC3A */ + } + + if ((info->CRC32 == 0x762653B1) && (ws < 8)) { + /* Mickey Mouse III - Dream Balloon [NikcDC v1.1] */ + ws = 8; + } + + MMC3_Init(info, ws, info->battery); + MMC3_pwrap = M004PW; + MMC3_cwrap = M004CW; +} diff --git a/src/boards/mmc5.c b/src/mappers/mapper005.c similarity index 58% rename from src/boards/mmc5.c rename to src/mappers/mapper005.c index af8ac391d..c4f518db1 100644 --- a/src/boards/mmc5.c +++ b/src/mappers/mapper005.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2002 Xodnizel + * Copyright (C) 2023-2024 negativeExponent * * 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,56 +22,54 @@ /* None of this code should use any of the iNES bank switching wrappers. */ #include "mapinc.h" - -static void (*sfun)(int P); -static void (*psfun)(void); - -void MMC5RunSound(int Count); -void MMC5RunSoundHQ(void); +#include "mmc5sound.h" static INLINE void MMC5SPRVROM_BANK1(uint32 A, uint32 V) { if (CHRptr[0]) { V &= CHRmask1[0]; - MMC5SPRVPage[(A) >> 10] = &CHRptr[0][(V) << 10] - (A); + MMC5SPRVPage[A >> 10] = &CHRptr[0][V << 10] - A; } } static INLINE void MMC5BGVROM_BANK1(uint32 A, uint32 V) { if (CHRptr[0]) { - V &= CHRmask1[0]; MMC5BGVPage[(A) >> 10] = &CHRptr[0][(V) << 10] - (A); + V &= CHRmask1[0]; MMC5BGVPage[A >> 10] = &CHRptr[0][V << 10] - A; } } static INLINE void MMC5SPRVROM_BANK2(uint32 A, uint32 V) { if (CHRptr[0]) { - V &= CHRmask2[0]; MMC5SPRVPage[(A) >> 10] = MMC5SPRVPage[((A) >> 10) + 1] = &CHRptr[0][(V) << 11] - (A); + V &= CHRmask2[0]; MMC5SPRVPage[A >> 10] = MMC5SPRVPage[(A >> 10) + 1] = &CHRptr[0][V << 11] - A; } } + static INLINE void MMC5BGVROM_BANK2(uint32 A, uint32 V) { if (CHRptr[0]) { - V &= CHRmask2[0]; MMC5BGVPage[(A) >> 10] = MMC5BGVPage[((A) >> 10) + 1] = &CHRptr[0][(V) << 11] - (A); + V &= CHRmask2[0]; MMC5BGVPage[A >> 10] = MMC5BGVPage[(A >> 10) + 1] = &CHRptr[0][V << 11] - A; } } static INLINE void MMC5SPRVROM_BANK4(uint32 A, uint32 V) { if (CHRptr[0]) { - V &= CHRmask4[0]; MMC5SPRVPage[(A) >> 10] = MMC5SPRVPage[((A) >> 10) + 1] = MMC5SPRVPage[((A) >> 10) + 2] = MMC5SPRVPage[((A) >> 10) + 3] = &CHRptr[0][(V) << 12] - (A); + V &= CHRmask4[0]; MMC5SPRVPage[A >> 10] = MMC5SPRVPage[(A >> 10) + 1] = MMC5SPRVPage[(A >> 10) + 2] = MMC5SPRVPage[(A >> 10) + 3] = &CHRptr[0][V << 12] - A; } } + static INLINE void MMC5BGVROM_BANK4(uint32 A, uint32 V) { if (CHRptr[0]) { - V &= CHRmask4[0]; MMC5BGVPage[(A) >> 10] = MMC5BGVPage[((A) >> 10) + 1] = MMC5BGVPage[((A) >> 10) + 2] = MMC5BGVPage[((A) >> 10) + 3] = &CHRptr[0][(V) << 12] - (A); + V &= CHRmask4[0]; MMC5BGVPage[A >> 10] = MMC5BGVPage[(A >> 10) + 1] = MMC5BGVPage[(A >> 10) + 2] = MMC5BGVPage[(A >> 10) + 3] = &CHRptr[0][V << 12] - A; } } static INLINE void MMC5SPRVROM_BANK8(uint32 V) { if (CHRptr[0]) { - V &= CHRmask8[0]; MMC5SPRVPage[0] = MMC5SPRVPage[1] = MMC5SPRVPage[2] = MMC5SPRVPage[3] = MMC5SPRVPage[4] = MMC5SPRVPage[5] = MMC5SPRVPage[6] = MMC5SPRVPage[7] = &CHRptr[0][(V) << 13]; + V &= CHRmask8[0]; MMC5SPRVPage[0] = MMC5SPRVPage[1] = MMC5SPRVPage[2] = MMC5SPRVPage[3] = MMC5SPRVPage[4] = MMC5SPRVPage[5] = MMC5SPRVPage[6] = MMC5SPRVPage[7] = &CHRptr[0][V << 13]; } } + static INLINE void MMC5BGVROM_BANK8(uint32 V) { if (CHRptr[0]) { - V &= CHRmask8[0]; MMC5BGVPage[0] = MMC5BGVPage[1] = MMC5BGVPage[2] = MMC5BGVPage[3] = MMC5BGVPage[4] = MMC5BGVPage[5] = MMC5BGVPage[6] = MMC5BGVPage[7] = &CHRptr[0][(V) << 13]; + V &= CHRmask8[0]; MMC5BGVPage[0] = MMC5BGVPage[1] = MMC5BGVPage[2] = MMC5BGVPage[3] = MMC5BGVPage[4] = MMC5BGVPage[5] = MMC5BGVPage[6] = MMC5BGVPage[7] = &CHRptr[0][V << 13]; } } @@ -88,8 +87,6 @@ static uint8 MMC5LineCounter; static uint8 mmc5psize, mmc5vsize; static uint8 mul[2]; -static uint32 WRAMSIZE = 0; -static uint8 *WRAM = NULL; static uint8 *MMC5fill = NULL; static uint8 *ExRAM = NULL; static uint8 MMC5battery = 0; @@ -100,6 +97,30 @@ static uint8 MMC5WRAMIndex[8]; /* configuration, not state */ static uint8 MMC5ROMWrProtect[4]; static uint8 MMC5MemIn[5]; +static SFORMAT MMC5_StateRegs[] = { + { PRGBanks, 4, "PREG" }, + { CHRBanksA, 16, "CHRA" }, + { CHRBanksB, 8, "CHRB" }, + { &WRAMPage, 1, "WRMP" }, + { WRAMMaskEnable, 2, "WRMK" }, + { &mmc5ABMode, 1, "ABMD" }, + { &IRQScanline, 1, "IRQS" }, + { &IRQEnable, 1, "IRQE" }, + { &CHRMode, 1, "CHRM" }, + { &NTAMirroring, 1, "NTAM" }, + { &NTFill, 1, "NTFL" }, + { &ATFill, 1, "ATFL" }, + { &MMC5IRQR, 1, "IRQR" }, + { &MMC5LineCounter, 1, "LCTR" }, + { &mmc5psize, 1, "PSIZ" }, + { &mmc5vsize, 1, "VSIZ" }, + { mul, 2, "MUL0" }, + { MMC5ROMWrProtect, 4, "PROT" }, + { MMC5MemIn, 5, "MEMN" }, + + { 0 } +}; + static void MMC5CHRA(void); static void MMC5CHRB(void); @@ -143,7 +164,7 @@ static void MMC5CHRA(void) { for (x = 0; x < 8; x++) { setchr1(x << 10, CHRBanksA[x]); MMC5SPRVROM_BANK1(x << 10, CHRBanksA[x]); - } + } break; } } @@ -175,19 +196,20 @@ static void MMC5CHRB(void) { for (x = 0; x < 8; x++) { setchr1(x << 10, CHRBanksB[x & 3]); MMC5BGVROM_BANK1(x << 10, CHRBanksB[x & 3]); - } + } break; } } -static void FASTAPASS(2) MMC5WRAM(uint32 A, uint32 V) { +static void MMC5WRAM(uint32 A, uint32 V) { V = MMC5WRAMIndex[V & 7]; if (V != 255) { setprg8r(0x10, A, V); FCEU_CheatAddRAM(8, 0x6000, (WRAM + ((V * 8192) & (WRAMSIZE - 1)))); MMC5MemIn[(A - 0x6000) >> 13] = 1; - } else + } else { MMC5MemIn[(A - 0x6000) >> 13] = 0; + } } static void MMC5PRG(void) { @@ -195,9 +217,10 @@ static void MMC5PRG(void) { switch (mmc5psize & 3) { case 0: MMC5ROMWrProtect[0] = MMC5ROMWrProtect[1] = MMC5ROMWrProtect[2] = MMC5ROMWrProtect[3] = 1; - setprg32(0x8000, ((PRGBanks[1] & 0x7F) >> 2)); - for (x = 0; x < 4; x++) + setprg32(0x8000, ((PRGBanks[3] & 0x7F) >> 2)); + for (x = 0; x < 4; x++) { MMC5MemIn[1 + x] = 1; + } break; case 1: if (PRGBanks[1] & 0x80) { @@ -236,7 +259,7 @@ static void MMC5PRG(void) { setprg8(0xE000, PRGBanks[3] & 0x7F); break; case 3: - for (x = 0; x < 3; x++) + for (x = 0; x < 3; x++) { if (PRGBanks[x] & 0x80) { MMC5ROMWrProtect[x] = 1; setprg8(0x8000 + (x << 13), PRGBanks[x] & 0x7F); @@ -245,6 +268,7 @@ static void MMC5PRG(void) { MMC5ROMWrProtect[x] = 0; MMC5WRAM(0x8000 + (x << 13), PRGBanks[x] & 7); } + } MMC5MemIn[4] = 1; MMC5ROMWrProtect[3] = 1; setprg8(0xE000, PRGBanks[3] & 0x7F); @@ -252,118 +276,143 @@ static void MMC5PRG(void) { } } -static DECLFW(Mapper5_write) { - switch (A) { - case 0x5100: - mmc5psize = V; - MMC5PRG(); - break; - case 0x5101: - mmc5vsize = V; - if (!mmc5ABMode) { - MMC5CHRB(); - MMC5CHRA(); - } else { - MMC5CHRA(); - MMC5CHRB(); - } - break; - case 0x5102: - WRAMMaskEnable[0] = V; - break; - case 0x5103: - WRAMMaskEnable[1] = V; - break; - case 0x5104: - CHRMode = V; - MMC5HackCHRMode = V & 3; - break; - case 0x5105: - { - int x; - for (x = 0; x < 4; x++) { - switch ((V >> (x << 1)) & 3) { - case 0: PPUNTARAM |= 1 << x; vnapage[x] = NTARAM; break; - case 1: PPUNTARAM |= 1 << x; vnapage[x] = NTARAM + 0x400; break; - case 2: PPUNTARAM |= 1 << x; vnapage[x] = ExRAM; break; - case 3: PPUNTARAM &= ~(1 << x); vnapage[x] = MMC5fill; break; - } - } - NTAMirroring = V; - break; +static void MMC5MIRR(void) { + int x; + for (x = 0; x < 4; x++) { + switch ((NTAMirroring >> (x << 1)) & 3) { + case 0: PPUNTARAM |= 1 << x; vnapage[x] = NTARAM; break; + case 1: PPUNTARAM |= 1 << x; vnapage[x] = NTARAM + 0x400; break; + case 2: PPUNTARAM |= 1 << x; vnapage[x] = ExRAM; break; + case 3: PPUNTARAM &= ~(1 << x); vnapage[x] = MMC5fill; break; } - case 0x5106: - if (V != NTFill) - FCEU_dwmemset(MMC5fill, (V | (V << 8) | (V << 16) | (V << 24)), 0x3c0); - NTFill = V; - break; - case 0x5107: - if (V != ATFill) { - unsigned char moop = V | (V << 2) | (V << 4) | (V << 6); - FCEU_dwmemset(MMC5fill + 0x3c0, moop | (moop << 8) | (moop << 16) | (moop << 24), 0x40); - } - ATFill = V; - break; - case 0x5113: - WRAMPage = V; - MMC5WRAM(0x6000, V & 7); - break; - case 0x5114: - case 0x5115: - case 0x5116: - case 0x5117: - PRGBanks[A & 3] = V; - MMC5PRG(); - break; - case 0x5120: - case 0x5121: - case 0x5122: - case 0x5123: - case 0x5124: - case 0x5125: - case 0x5126: - case 0x5127: - mmc5ABMode = 0; - CHRBanksA[A & 7] = V | ((MMC50x5130 & 0x3) << 8); + } +} + +DECLFW(Mapper5_write) { + switch (A) { + case 0x5100: + mmc5psize = V; + MMC5PRG(); + break; + case 0x5101: + mmc5vsize = V; + if (!mmc5ABMode) { + MMC5CHRB(); + MMC5CHRA(); + } else { MMC5CHRA(); - break; - case 0x5128: - case 0x5129: - case 0x512a: - case 0x512b: - mmc5ABMode = 1; - CHRBanksB[A & 3] = V | ((MMC50x5130 & 0x3) << 8); MMC5CHRB(); - break; - case 0x5130: MMC50x5130 = V; break; - case 0x5200: MMC5HackSPMode = V; break; - case 0x5201: MMC5HackSPScroll = (V >> 3) & 0x1F; break; - case 0x5202: MMC5HackSPPage = V & 0x3F; break; - case 0x5203: X6502_IRQEnd(FCEU_IQEXT); IRQScanline = V; break; - case 0x5204: X6502_IRQEnd(FCEU_IQEXT); IRQEnable = V & 0x80; break; - case 0x5205: mul[0] = V; break; - case 0x5206: mul[1] = V; break; } + break; + case 0x5102: + WRAMMaskEnable[0] = V; + break; + case 0x5103: + WRAMMaskEnable[1] = V; + break; + case 0x5104: + CHRMode = V; + MMC5HackCHRMode = V & 3; + break; + case 0x5105: + NTAMirroring = V; + MMC5MIRR(); + break; + case 0x5106: + if (V != NTFill) { + FCEU_dwmemset(MMC5fill, (V | (V << 8) | (V << 16) | (V << 24)), 0x3c0); + } + NTFill = V; + break; + case 0x5107: + if (V != ATFill) { + unsigned char moop = V | (V << 2) | (V << 4) | (V << 6); + FCEU_dwmemset(MMC5fill + 0x3c0, moop | (moop << 8) | (moop << 16) | (moop << 24), 0x40); + } + ATFill = V; + break; + case 0x5113: + WRAMPage = V; + MMC5WRAM(0x6000, V & 7); + break; + case 0x5114: + case 0x5115: + case 0x5116: + case 0x5117: + PRGBanks[A & 3] = V; + MMC5PRG(); + break; + case 0x5120: + case 0x5121: + case 0x5122: + case 0x5123: + case 0x5124: + case 0x5125: + case 0x5126: + case 0x5127: + mmc5ABMode = 0; + CHRBanksA[A & 7] = V | ((MMC50x5130 & 0x3) << 8); + MMC5CHRA(); + break; + case 0x5128: + case 0x5129: + case 0x512a: + case 0x512b: + mmc5ABMode = 1; + CHRBanksB[A & 3] = V | ((MMC50x5130 & 0x3) << 8); + MMC5CHRB(); + break; + case 0x5130: + MMC50x5130 = V; + break; + case 0x5200: + MMC5HackSPMode = V; + break; + case 0x5201: + MMC5HackSPScroll = (V >> 3) & 0x1F; + break; + case 0x5202: + MMC5HackSPPage = V & 0x3F; + break; + case 0x5203: + X6502_IRQEnd(FCEU_IQEXT); + IRQScanline = V; + break; + case 0x5204: + X6502_IRQEnd(FCEU_IQEXT); + IRQEnable = V & 0x80; + break; + case 0x5205: + mul[0] = V; + break; + case 0x5206: + mul[1] = V; + break; + } } static DECLFR(MMC5_ReadROMRAM) { - if (MMC5MemIn[(A - 0x6000) >> 13]) + if (MMC5MemIn[(A - 0x6000) >> 13]) { return Page[A >> 11][A]; - else - return X.DB; + } + return cpu.openbus; } static DECLFW(MMC5_WriteROMRAM) { - if ((A >= 0x8000) && (MMC5ROMWrProtect[(A - 0x8000) >> 13])) - return; - if (MMC5MemIn[(A - 0x6000) >> 13]) - if (((WRAMMaskEnable[0] & 3) | ((WRAMMaskEnable[1] & 3) << 2)) == 6) + if ((A >= 0x8000) && (MMC5ROMWrProtect[(A - 0x8000) >> 13])) { + return; + } + if (MMC5MemIn[(A - 0x6000) >> 13]) { + if (((WRAMMaskEnable[0] & 3) | ((WRAMMaskEnable[1] & 3) << 2)) == 6) { Page[A >> 11][A] = V; + } + } } -static DECLFW(MMC5_ExRAMWr) { - if (MMC5HackCHRMode != 3) +DECLFW(MMC5_ExRAMWr) { + if (MMC5HackCHRMode != 3) { ExRAM[A & 0x3ff] = V; + } } static DECLFR(MMC5_ExRAMRd) { @@ -371,37 +420,29 @@ static DECLFR(MMC5_ExRAMRd) { } static DECLFR(MMC5_read) { + uint8 ret = cpu.openbus; switch (A) { - case 0x5204: { - uint8 x; + case 0x5204: X6502_IRQEnd(FCEU_IQEXT); - x = MMC5IRQR; - #ifdef FCEUDEF_DEBUGGER + ret = MMC5IRQR; +#ifdef FCEUDEF_DEBUGGER if (!fceuindbg) - #endif - MMC5IRQR &= 0x40; - return x; - } +#endif + MMC5IRQR &= 0x40; + return ret; case 0x5205: - return(mul[0] * mul[1]); + return ((uint32)(mul[0] * mul[1]) & 0xFF); case 0x5206: - return((mul[0] * mul[1]) >> 8); + return ((uint32)(mul[0] * mul[1]) >> 8); } - return(X.DB); + return ret; } -void MMC5Synco(void) { - int x; +static void MMC5Synco(void) { + uint8 moop; MMC5PRG(); - for (x = 0; x < 4; x++) { - switch ((NTAMirroring >> (x << 1)) & 3) { - case 0: PPUNTARAM |= 1 << x; vnapage[x] = NTARAM; break; - case 1: PPUNTARAM |= 1 << x; vnapage[x] = NTARAM + 0x400; break; - case 2: PPUNTARAM |= 1 << x; vnapage[x] = ExRAM; break; - case 3: PPUNTARAM &= ~(1 << x); vnapage[x] = MMC5fill; break; - } - } + MMC5MIRR(); MMC5WRAM(0x6000, WRAMPage & 7); if (!mmc5ABMode) { MMC5CHRB(); @@ -413,10 +454,8 @@ void MMC5Synco(void) { /* in case the fill register changed, we need to overwrite the fill buffer */ FCEU_dwmemset(MMC5fill, NTFill | (NTFill << 8) | (NTFill << 16) | (NTFill << 24), 0x3c0); - { - unsigned char moop = ATFill | (ATFill << 2) | (ATFill << 4) | (ATFill << 6); - FCEU_dwmemset(MMC5fill + 0x3c0, moop | (moop << 8) | (moop << 16) | (moop << 24), 0x40); - } + moop = ATFill | (ATFill << 2) | (ATFill << 4) | (ATFill << 6); + FCEU_dwmemset(MMC5fill + 0x3c0, moop | (moop << 8) | (moop << 16) | (moop << 24), 0x40); MMC5HackCHRMode = CHRMode & 3; @@ -428,12 +467,10 @@ void MMC5Synco(void) { void MMC5_hb(int scanline) { /* zero 24-jul-2014 - revised for newer understanding, to fix metal slader glory credits. see r7371 in bizhawk */ - int sl = scanline + 1; int ppuon = (PPU[1] & 0x18); - if (!ppuon || sl >= 241) - { + if (!ppuon || sl >= 241) { /* whenever rendering is off for any reason (vblank or forced disable * the irq counter resets, as well as the inframe flag (easily verifiable from software) */ @@ -444,230 +481,30 @@ void MMC5_hb(int scanline) { return; } - if (!(MMC5IRQR&0x40)) - { + if (!(MMC5IRQR & 0x40)) { MMC5IRQR |= 0x40; MMC5IRQR &= ~0x80; MMC5LineCounter = 0; X6502_IRQEnd(FCEU_IQEXT); - } - else - { + } else { MMC5LineCounter++; - if (MMC5LineCounter == IRQScanline) - { + if (MMC5LineCounter == IRQScanline) { MMC5IRQR |= 0x80; - if (IRQEnable & 0x80) + if (IRQEnable & 0x80) { X6502_IRQBegin(FCEU_IQEXT); - } - } - -} - -void MMC5_StateRestore(int version) { - MMC5Synco(); -} - -typedef struct { - uint16 wl[2]; - uint8 env[2]; - uint8 enable; - uint8 running; - uint8 raw; - uint8 rawcontrol; - int32 dcount[2]; - int32 BC[3]; - int32 vcount[2]; -} MMC5APU; - -static MMC5APU MMC5Sound; - - -static void Do5PCM(void) { - int32 V; - int32 start, end; - - start = MMC5Sound.BC[2]; - end = (SOUNDTS << 16) / soundtsinc; - if (end <= start) return; - MMC5Sound.BC[2] = end; - - if (!(MMC5Sound.rawcontrol & 0x40) && MMC5Sound.raw) - for (V = start; V < end; V++) - Wave[V >> 4] += MMC5Sound.raw << 1; -} - -static void Do5PCMHQ(void) { - uint32 V; - if (!(MMC5Sound.rawcontrol & 0x40) && MMC5Sound.raw) - for (V = MMC5Sound.BC[2]; V < SOUNDTS; V++) - WaveHi[V] += MMC5Sound.raw << 5; - MMC5Sound.BC[2] = SOUNDTS; -} - - -static DECLFW(Mapper5_SW) { - A &= 0x1F; - - GameExpSound.Fill = MMC5RunSound; - GameExpSound.HiFill = MMC5RunSoundHQ; - - switch (A) { - case 0x10: if (psfun) psfun(); MMC5Sound.rawcontrol = V; break; - case 0x11: if (psfun) psfun(); MMC5Sound.raw = V; break; - - case 0x0: - case 0x4: - if (sfun) sfun(A >> 2); - MMC5Sound.env[A >> 2] = V; - break; - case 0x2: - case 0x6: - if (sfun) sfun(A >> 2); - MMC5Sound.wl[A >> 2] &= ~0x00FF; - MMC5Sound.wl[A >> 2] |= V & 0xFF; - break; - case 0x3: - case 0x7: - MMC5Sound.wl[A >> 2] &= ~0x0700; - MMC5Sound.wl[A >> 2] |= (V & 0x07) << 8; - MMC5Sound.running |= 1 << (A >> 2); - break; - case 0x15: - if (sfun) { - sfun(0); - sfun(1); - } - MMC5Sound.running &= V; - MMC5Sound.enable = V; - break; - } -} - -static void Do5SQ(int P) { - static int tal[4] = { 1, 2, 4, 6 }; - int32 V, amp, rthresh, wl; - int32 start, end; - - start = MMC5Sound.BC[P]; - end = (SOUNDTS << 16) / soundtsinc; - if (end <= start) return; - MMC5Sound.BC[P] = end; - - wl = MMC5Sound.wl[P] + 1; - amp = (MMC5Sound.env[P] & 0xF) << 4; - rthresh = tal[(MMC5Sound.env[P] & 0xC0) >> 6]; - - if (wl >= 8 && (MMC5Sound.running & (P + 1))) { - int dc, vc; - - wl <<= 18; - dc = MMC5Sound.dcount[P]; - vc = MMC5Sound.vcount[P]; - - for (V = start; V < end; V++) { - if (dc < rthresh) - Wave[V >> 4] += amp; - vc -= nesincsize; - while (vc <= 0) { - vc += wl; - dc = (dc + 1) & 7; } } - MMC5Sound.dcount[P] = dc; - MMC5Sound.vcount[P] = vc; } } -static void Do5SQHQ(int P) { - static int tal[4] = { 1, 2, 4, 6 }; - uint32 V; - int32 amp, rthresh, wl; - - wl = MMC5Sound.wl[P] + 1; - amp = ((MMC5Sound.env[P] & 0xF) << 8); - rthresh = tal[(MMC5Sound.env[P] & 0xC0) >> 6]; - - if (wl >= 8 && (MMC5Sound.running & (P + 1))) { - int dc, vc; - - wl <<= 1; - - dc = MMC5Sound.dcount[P]; - vc = MMC5Sound.vcount[P]; - for (V = MMC5Sound.BC[P]; V < SOUNDTS; V++) { - if (dc < rthresh) - WaveHi[V] += amp; - vc--; - if (vc <= 0) { /* Less than zero when first started. */ - vc = wl; - dc = (dc + 1) & 7; - } - } - MMC5Sound.dcount[P] = dc; - MMC5Sound.vcount[P] = vc; - } - MMC5Sound.BC[P] = SOUNDTS; -} - -void MMC5RunSoundHQ(void) { - Do5SQHQ(0); - Do5SQHQ(1); - Do5PCMHQ(); -} - -void MMC5HiSync(int32 ts) { - int x; - for (x = 0; x < 3; x++) - MMC5Sound.BC[x] = ts; -} - -void MMC5RunSound(int Count) { - int x; - Do5SQ(0); - Do5SQ(1); - Do5PCM(); - for (x = 0; x < 3; x++) - MMC5Sound.BC[x] = Count; -} - -void Mapper5_ESI(void) { - GameExpSound.RChange = Mapper5_ESI; - if (FSettings.SndRate) { - if (FSettings.soundq >= 1) { - sfun = Do5SQHQ; - psfun = Do5PCMHQ; - } else { - sfun = Do5SQ; - psfun = Do5PCM; - } - } else { - sfun = 0; - psfun = 0; - } - memset(MMC5Sound.BC, 0, sizeof(MMC5Sound.BC)); - memset(MMC5Sound.vcount, 0, sizeof(MMC5Sound.vcount)); - GameExpSound.HiSync = MMC5HiSync; -} - -void NSFMMC5_Init(void) { - memset(&MMC5Sound, 0, sizeof(MMC5Sound)); - mul[0] = mul[1] = 0; - ExRAM = (uint8*)FCEU_gmalloc(1024); - Mapper5_ESI(); - SetWriteHandler(0x5c00, 0x5fef, MMC5_ExRAMWr); - SetReadHandler(0x5c00, 0x5fef, MMC5_ExRAMRd); - MMC5HackCHRMode = 2; - SetWriteHandler(0x5000, 0x5015, Mapper5_SW); - SetWriteHandler(0x5205, 0x5206, Mapper5_write); - SetReadHandler(0x5205, 0x5206, MMC5_read); +static void MMC5_StateRestore(int version) { + MMC5Synco(); } void NSFMMC5_Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; - FCEU_gfree(ExRAM); + if (ExRAM) { + FCEU_gfree(ExRAM); + } ExRAM = NULL; } @@ -679,10 +516,20 @@ static void GenMMC5Power(void) { for (x = 0; x < 4; x++) PRGBanks[x] = ~0; for (x = 0; x < 8; x++) CHRBanksA[x] = ~0; for (x = 0; x < 4; x++) CHRBanksB[x] = ~0; - WRAMMaskEnable[0] = WRAMMaskEnable[1] = ~0; + for (x = 0; x < 2; x++) WRAMMaskEnable[x] = ~0; + for (x = 0; x < 4; x++) MMC5ROMWrProtect[x] = 0; + for (x = 0; x < 5; x++) MMC5MemIn[x] = 0; + for (x = 0; x < 2; x++) mul[x] = 0; - mmc5psize = mmc5vsize = 3; + WRAMPage = 0; CHRMode = 0; + mmc5ABMode = 0; + mmc5psize = mmc5vsize = 3; + + IRQScanline = 0; + IRQEnable = 0; + MMC5IRQR = 0; + MMC5LineCounter = 0; NTAMirroring = NTFill = ATFill = 0xFF; @@ -692,10 +539,10 @@ static void GenMMC5Power(void) { FCEU_dwmemset(MMC5fill + 0x000, nval | (nval<<8) | (nval<<16) | (nval<<24), 0x3C0); FCEU_dwmemset(MMC5fill + 0x3C0, aval | (aval<<8) | (aval<<16) | (aval<<24), 0x040); - if(MMC5battery == 0) { + if (MMC5battery == 0) { FCEU_MemoryRand(WRAM, MMC5WRAMsize * 8 * 1024); - FCEU_MemoryRand(MMC5fill,1024); - FCEU_MemoryRand(ExRAM,1024); + FCEU_MemoryRand(MMC5fill, 1024); + FCEU_MemoryRand(ExRAM, 1024); } MMC5Synco(); @@ -709,7 +556,7 @@ static void GenMMC5Power(void) { SetWriteHandler(0x6000, 0xFFFF, MMC5_WriteROMRAM); SetReadHandler(0x6000, 0xFFFF, MMC5_ReadROMRAM); - SetWriteHandler(0x5000, 0x5015, Mapper5_SW); + SetWriteHandler(0x5000, 0x5015, MMC5Sound_Write); SetWriteHandler(0x5205, 0x5206, Mapper5_write); SetReadHandler(0x5205, 0x5206, MMC5_read); @@ -718,49 +565,15 @@ static void GenMMC5Power(void) { FCEU_CheatAddRAM(1, 0x5c00, ExRAM); } -static SFORMAT MMC5_StateRegs[] = { - { PRGBanks, 4, "PREG" }, - { CHRBanksA, 16, "CHRA" }, - { CHRBanksB, 8, "CHRB" }, - { &WRAMPage, 1, "WRMP" }, - { WRAMMaskEnable, 2, "WRMK" }, - { &mmc5ABMode, 1, "ABMD" }, - { &IRQScanline, 1, "IRQS" }, - { &IRQEnable, 1, "IRQE" }, - { &CHRMode, 1, "CHRM" }, - { &NTAMirroring, 1, "NTAM" }, - { &NTFill, 1, "NTFL" }, - { &ATFill, 1, "ATFL" }, - { &MMC5IRQR, 1, "IRQR" }, - { &MMC5LineCounter, 1, "LCTR" }, - { &mmc5psize, 1, "PSIZ" }, - { &mmc5vsize, 1, "VSIZ" }, - { mul, 2, "MUL0" }, - { MMC5ROMWrProtect, 4, "PROT" }, - { MMC5MemIn, 5, "MEMN" }, - { MMC5Sound.wl, 4, "SDW0" }, - { MMC5Sound.env, 2, "SDEV" }, - { &MMC5Sound.enable, 1, "SDEN" }, - { &MMC5Sound.running, 1, "RUNN" }, - { &MMC5Sound.raw, 1, "RAW0" }, - { &MMC5Sound.rawcontrol, 1, "RAWC" }, - { MMC5Sound.dcount, 8, "DCNT" }, - { MMC5Sound.BC, 12, "SDBC" }, - { MMC5Sound.vcount, 8, "VCNT" }, - - { 0 } -}; - static void GenMMC5_Init(CartInfo *info, int wsize, int battery) { if (wsize) { - WRAM = (uint8*)FCEU_gmalloc(wsize * 1024); - FCEU_MemoryRand(WRAM, wsize * 1024); + WRAM = (uint8 *)FCEU_gmalloc(wsize * 1024); SetupCartPRGMapping(0x10, WRAM, wsize * 1024, 1); AddExState(WRAM, wsize * 1024, 0, "WRAM"); } - MMC5fill = (uint8*)FCEU_gmalloc(1024); - ExRAM = (uint8*)FCEU_gmalloc(1024); + MMC5fill = (uint8 *)FCEU_gmalloc(1024); + ExRAM = (uint8 *)FCEU_gmalloc(1024); FCEU_MemoryRand(MMC5fill, 1024); FCEU_MemoryRand(ExRAM, 1024); @@ -779,23 +592,30 @@ static void GenMMC5_Init(CartInfo *info, int wsize, int battery) { MMC5battery = battery; if (battery) { + uint32 saveramsize; + if (info->iNES2) { + saveramsize = info->PRGRamSaveSize; + } else { + if (wsize <= 16) saveramsize = 8 * 1024; + else if (wsize >= 64) saveramsize = 64 * 1024; + else saveramsize = 32 * 1024; + } info->SaveGame[0] = WRAM; - if (wsize <= 16) - info->SaveGameLen[0] = 8192; - else - info->SaveGameLen[0] = 32768; + info->SaveGameLen[0] = saveramsize; } MMC5HackVROMMask = CHRmask4[0]; MMC5HackExNTARAMPtr = ExRAM; - MMC5Hack = 1; + MMC5Hack = TRUE; MMC5HackVROMPTR = CHRptr[0]; MMC5HackCHRMode = 0; MMC5HackSPMode = MMC5HackSPScroll = MMC5HackSPPage = 0; - Mapper5_ESI(); + + MMC5Sound_ESI(); + MMC5Sound_AddStateInfo(); } -void Mapper5_Init(CartInfo *info) { +void Mapper005_Init(CartInfo *info) { WRAMSIZE = 64; if (info->iNES2) { WRAMSIZE = (info->PRGRamSize + info->PRGRamSaveSize) / 1024; @@ -826,3 +646,12 @@ void ETROM_Init(CartInfo *info) { void EWROM_Init(CartInfo *info) { GenMMC5_Init(info, 32, info->battery); } + +void NSFMMC5_Init(int chip) { + mul[0] = mul[1] = 0; + ExRAM = (uint8*)FCEU_gmalloc(1024); + MMC5Sound_ESI(); + SetReadHandler(0x5c00, 0x5fef, MMC5_ExRAMRd); + MMC5HackCHRMode = 2; + SetReadHandler(0x5205, 0x5206, MMC5_read); +} diff --git a/src/boards/ffe.c b/src/mappers/mapper006.c similarity index 91% rename from src/boards/ffe.c rename to src/mappers/mapper006.c index 5b80e9cb3..fdd52503a 100644 --- a/src/boards/ffe.c +++ b/src/mappers/mapper006.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) 2023-2024 negativeExponent * * 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 @@ -26,8 +27,6 @@ static uint8 preg[4], creg[8], latch, ffemode; static uint8 IRQa, mirr; static int32 IRQCount, IRQLatch; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; static SFORMAT StateRegs[] = { @@ -105,7 +104,7 @@ static void FFEPower(void) { FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } -static void FP_FASTAPASS(1) FFEIRQHook(int a) { +static void FFEIRQHook(int a) { if (IRQa) { IRQCount += a; if (IRQCount >= 0x10000) { @@ -117,16 +116,13 @@ static void FP_FASTAPASS(1) FFEIRQHook(int a) { } static void FFEClose(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; } static void StateRestore(int version) { Sync(); } -void Mapper6_Init(CartInfo *info) { +void Mapper006_Init(CartInfo *info) { ffemode = 0; mirr = ((info->mirror & 1) ^ 1) | 2; @@ -144,10 +140,10 @@ void Mapper6_Init(CartInfo *info) { info->SaveGameLen[0] = WRAMSIZE; } - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } -void Mapper17_Init(CartInfo *info) { +void Mapper017_Init(CartInfo *info) { ffemode = 1; - Mapper6_Init(info); + Mapper006_Init(info); } diff --git a/src/mappers/mapper007.c b/src/mappers/mapper007.c new file mode 100644 index 000000000..3191b0063 --- /dev/null +++ b/src/mappers/mapper007.c @@ -0,0 +1,33 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg32(0x8000, latch.data); + setchr8(0); + setmirror(MI_0 + ((latch.data >> 4) & 0x01)); +} + +void Mapper007_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, (info->submapper == 2)); +} diff --git a/src/mappers/mapper008.c b/src/mappers/mapper008.c new file mode 100644 index 000000000..e517ced7d --- /dev/null +++ b/src/mappers/mapper008.c @@ -0,0 +1,33 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg16(0x8000, latch.data >> 3); + setprg16(0xC000, 1); + setchr8(latch.data & 3); +} + +void Mapper008_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); +} diff --git a/src/mappers/mapper009.c b/src/mappers/mapper009.c new file mode 100644 index 000000000..318e7dd59 --- /dev/null +++ b/src/mappers/mapper009.c @@ -0,0 +1,38 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "mmc2.h" + +static void M009PW(uint32 A, uint8 V) { + setprg8(A, V & 0x0F); +} + +static void M009CW(uint32 A, uint8 V) { + setchr4(A, V & 0x1F); +} + +void Mapper009_Init(CartInfo *info) { + int ws = info->iNES2 ? ((info->PRGRamSize + info->PRGRamSaveSize) / 1024) : (info->battery ? 8 : 0); + MMC2_Init(info, ws, info->battery); + MMC2_pwrap = M009PW; + MMC2_cwrap = M009CW; +} diff --git a/src/mappers/mapper010.c b/src/mappers/mapper010.c new file mode 100644 index 000000000..90babf805 --- /dev/null +++ b/src/mappers/mapper010.c @@ -0,0 +1,38 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "mmc4.h" + +static void M010PW(uint32 A, uint8 V) { + setprg16(A, V & 0x0F); +} + +static void M010CW(uint32 A, uint8 V) { + setchr4(A, V & 0x1F); +} + +void Mapper010_Init(CartInfo *info) { + int ws = info->iNES2 ? ((info->PRGRamSize + info->PRGRamSaveSize) / 1024) : (info->battery ? 8 : 0); + MMC4_Init(info, ws, info->battery); + MMC4_pwrap = M010PW; + MMC4_cwrap = M010CW; +} \ No newline at end of file diff --git a/src/mappers/mapper011.c b/src/mappers/mapper011.c new file mode 100644 index 000000000..a5c42cbcc --- /dev/null +++ b/src/mappers/mapper011.c @@ -0,0 +1,32 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg32(0x8000, latch.data); + setchr8(latch.data >> 4); +} + +void Mapper011_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); +} diff --git a/src/mappers/mapper012.c b/src/mappers/mapper012.c new file mode 100644 index 000000000..badb6035a --- /dev/null +++ b/src/mappers/mapper012.c @@ -0,0 +1,70 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 reg; +static uint8 dipsw; + +static void M012CW(uint32 A, uint8 V) { + uint16 base = reg << ((A & 0x1000) ? 4 : 8); + + setchr1(A, (base & 0x100) | (V & 0xFF)); +} + +static DECLFW(M012Write) { + if (A & 0x100) { + reg = V; + MMC3_FixCHR(); + } +} + +static DECLFR(M012Read) { + if (A & 0x100) { + return dipsw; + } + return CartBR(A); +} + +static void M012Power(void) { + reg = 0; + dipsw = 1; /* chinese is default */ + MMC3_Power(); + SetWriteHandler(0x4100, 0x4FFF, M012Write); + SetReadHandler(0x4100, 0x4FFF, M012Read); +} + +static void M012Reset(void) { + reg = 0; + dipsw ^= 1; + MMC3_Reset(); +} + +void Mapper012_Init(CartInfo *info) { + MMC3_Init(info, 8, info->battery); + MMC3_cwrap = M012CW; + isRevB = 0; + + info->Power = M012Power; + info->Reset = M012Reset; + AddExState(®, 1, 0, "EXPR"); + AddExState(&dipsw, 1, 0, "DPSW"); +} diff --git a/src/boards/mihunche.c b/src/mappers/mapper013.c similarity index 74% rename from src/boards/mihunche.c rename to src/mappers/mapper013.c index bec195311..e60acf483 100644 --- a/src/boards/mihunche.c +++ b/src/mappers/mapper013.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2013 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -16,6 +16,7 @@ * 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" @@ -23,11 +24,10 @@ static void Sync(void) { setprg32(0x8000, 0); - setchr4(0x0000, ((latch.addr << 1) & 2) | (latch.addr & 1)); - setchr4(0x1000, ((latch.addr << 1) & 2) | (latch.addr & 1)); - setmirror(MI_0 + (latch.addr & 1)); + setchr4(0x0000, 0); + setchr4(0x1000, latch.data); } -void UNLCC21_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); +void Mapper013_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, TRUE); } diff --git a/src/mappers/mapper014.c b/src/mappers/mapper014.c new file mode 100644 index 000000000..b842beff0 --- /dev/null +++ b/src/mappers/mapper014.c @@ -0,0 +1,107 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2005 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + * SL1632 2-in-1 protected board, similar to SL12 + * Samurai Spirits Rex (Full) + * + */ + +#include "mapinc.h" +#include "mmc3.h" +#include "vrc2and4.h" + +static uint8 reg; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 }, +}; + +static uint8 GetChrBase(uint16 A) { + if (A & 0x1000) { + if (A & 0x800) { + return ((reg & 0x80) >> 7); + } else { + return ((reg & 0x20) >> 5); + } + } + return ((reg & 0x08) >> 3); +} + +static void M014CW_MMC3(uint32 A, uint8 V) { + uint16 mask = 0xFF; + uint16 base = GetChrBase(A) << 8; + + setchr1(A, (base & ~mask) | (V & mask)); +} + +static void M014CW_VRC2(uint32 A, uint32 V) { + uint16 mask = 0xFF; + uint16 base = GetChrBase(A) << 8; + + setchr1(A, (base & ~mask) | (V & mask)); +} + +static DECLFW(M014Write) { + if (A == 0xA131) { + reg = V; + if (reg & 0x02) { + MMC3_FixCHR(); + } else { + VRC24_FixCHR(); + } + } + if (reg & 0x02) { + MMC3_Write(A, V); + } else { + VRC24_Write(A, V); + } +} + +static void StateRestore(int version) { + if (reg & 0x02) { + MMC3_FixPRG(); + MMC3_FixCHR(); + MMC3_FixMIR(); + } else { + VRC24_FixPRG(); + VRC24_FixCHR(); + VRC24_FixMIR(); + } +} + +static void M014Power(void) { + reg = 0; + VRC24_Power(); + SetWriteHandler(0x8000, 0xFFFF, M014Write); +} + +void Mapper014_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_cwrap = M014CW_MMC3; + + VRC24_Init(info, VRC2, 0x01, 0x02, FALSE, TRUE); + VRC24_cwrap = M014CW_VRC2; + + info->Power = M014Power; + + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/mapper015.c b/src/mappers/mapper015.c similarity index 62% rename from src/boards/mapper015.c rename to src/mappers/mapper015.c index 3e1864904..8f3ef3754 100644 --- a/src/boards/mapper015.c +++ b/src/mappers/mapper015.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2006 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -23,35 +24,33 @@ #include "latch.h" static void Sync(void) { - uint8 bank = latch.data & 0x3F; - uint8 prgA13 = latch.data >> 7; + uint8 prg = latch.data & 0x3F; setprg8r(0x10, 0x6000, 0); switch (latch.addr & 0x03) { case 0: - setprg32(0x8000, bank >> 1); + setprg32(0x8000, prg >> 1); break; case 1: - setprg16(0x8000, bank); - setprg16(0xC000, bank | 7); + setprg16(0x8000, prg); + setprg16(0xC000, prg | 0x07); break; case 2: - setprg8(0x8000, (bank << 1) | prgA13); - setprg8(0xA000, (bank << 1) | prgA13); - setprg8(0xC000, (bank << 1) | prgA13); - setprg8(0xE000, (bank << 1) | prgA13); + setprg8(0x8000, (prg << 1) | (latch.data >> 7)); + setprg8(0xA000, (prg << 1) | (latch.data >> 7)); + setprg8(0xC000, (prg << 1) | (latch.data >> 7)); + setprg8(0xE000, (prg << 1) | (latch.data >> 7)); break; case 3: - setprg16(0x8000, bank); - setprg16(0xC000, bank); + setprg16(0x8000, prg); + setprg16(0xC000, prg); break; } - setchr8(0); - setmirror(((latch.data >> 6) & 1) ^ 1); + setmirror(((latch.data >> 6) & 0x01) ^ 0x01); } -void Mapper15_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 1, 0); - info->Reset = LatchHardReset; +void Mapper015_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, TRUE, FALSE); + info->Reset = Latch_RegReset; } diff --git a/src/mappers/mapper016.c b/src/mappers/mapper016.c new file mode 100644 index 000000000..c4f7bfda9 --- /dev/null +++ b/src/mappers/mapper016.c @@ -0,0 +1,51 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "eeprom_x24c0x.h" +#include "bandai.h" + +static void M016PW(uint32 A, uint8 V) { + setprg16(A, V & 0x0F); +} + +static void M016CW(uint32 A, uint8 V) { + setchr1(A, V); +} + +void Mapper016_Init(CartInfo *info) { + switch (info->submapper) { + case 4: + BANDAI_Init(info, EEPROM_NONE, TRUE); + break; + case 5: + if (info->battery || ((info->PRGRamSaveSize > 0) && (info->PRGRamSaveSize <= 256))) { + BANDAI_Init(info, EEPROM_X24C02, FALSE); break; + } else { + BANDAI_Init(info, EEPROM_NONE, FALSE); break; + } + break; + default: + BANDAI_Init(info, EEPROM_NONE, TRUE); + break; + } + BANDAI_pwrap = M016PW; + BANDAI_cwrap = M016CW; +} diff --git a/src/boards/mapper018.c b/src/mappers/mapper018.c similarity index 51% rename from src/boards/mapper018.c rename to src/mappers/mapper018.c index 6c2f81289..8e85062c7 100644 --- a/src/boards/mapper018.c +++ b/src/mappers/mapper018.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) 2023-2024 negativeExponent * * 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 @@ -20,16 +21,13 @@ #include "mapinc.h" -static uint8 preg[4], creg[8]; +static uint8 prg[4], chr[8]; static uint8 IRQa, mirr; static int32 IRQCount, IRQLatch; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; -static SFORMAT StateRegs[] = -{ - { preg, 4, "PREG" }, - { creg, 8, "CREG" }, +static SFORMAT StateRegs[] = { + { prg, 4, "PREG" }, + { chr, 8, "CREG" }, { &mirr, 1, "MIRR" }, { &IRQa, 1, "IRQA" }, { &IRQCount, 4, "IRQC" }, @@ -38,82 +36,98 @@ static SFORMAT StateRegs[] = }; static void Sync(void) { - int i; - for (i = 0; i < 8; i++) - setchr1(i << 10, creg[i]); setprg8r(0x10, 0x6000, 0); - setprg8(0x8000, preg[0]); - setprg8(0xA000, preg[1]); - setprg8(0xC000, preg[2]); + + setprg8(0x8000, prg[0]); + setprg8(0xA000, prg[1]); + setprg8(0xC000, prg[2]); setprg8(0xE000, ~0); + + setchr1(0x0000, chr[0]); + setchr1(0x0400, chr[1]); + setchr1(0x0800, chr[2]); + setchr1(0x0C00, chr[3]); + setchr1(0x1000, chr[4]); + setchr1(0x1400, chr[5]); + setchr1(0x1800, chr[6]); + setchr1(0x1C00, chr[7]); + if (mirr & 2) setmirror(MI_0); else - setmirror(mirr & 1); + setmirror(mirr & 0x01); } -static DECLFW(M18WriteIRQ) { +static DECLFW(M018WriteIRQ) { switch (A & 0xF003) { - case 0xE000: - IRQLatch &= 0xFFF0; - IRQLatch |= (V & 0x0f) << 0x0; - break; - case 0xE001: - IRQLatch &= 0xFF0F; - IRQLatch |= (V & 0x0f) << 0x4; - break; - case 0xE002: - IRQLatch &= 0xF0FF; - IRQLatch |= (V & 0x0f) << 0x8; - break; - case 0xE003: - IRQLatch &= 0x0FFF; - IRQLatch |= (V & 0x0f) << 0xC; - break; - case 0xF000: - IRQCount = IRQLatch; - break; - case 0xF001: - IRQa = V & 1; - X6502_IRQEnd(FCEU_IQEXT); - break; - case 0xF002: - mirr = V & 3; - Sync(); - break; + case 0xE000: + IRQLatch &= 0xFFF0; + IRQLatch |= (V & 0x0F) << 0x00; + break; + case 0xE001: + IRQLatch &= 0xFF0F; + IRQLatch |= (V & 0x0F) << 0x04; + break; + case 0xE002: + IRQLatch &= 0xF0FF; + IRQLatch |= (V & 0x0F) << 0x08; + break; + case 0xE003: + IRQLatch &= 0x0FFF; + IRQLatch |= (V & 0x0F) << 0x0C; + break; + case 0xF000: + IRQCount = IRQLatch; + break; + case 0xF001: + IRQa = V & 0x01; + X6502_IRQEnd(FCEU_IQEXT); + break; + case 0xF002: + mirr = V & 0x03; + Sync(); + break; } } -static DECLFW(M18WritePrg) { +static DECLFW(M018WritePrg) { uint32 i = ((A >> 1) & 1) | ((A - 0x8000) >> 11); - preg[i] &= (0xF0) >> ((A & 1) << 2); - preg[i] |= (V & 0xF) << ((A & 1) << 2); + + if (A & 0x01) { + prg[i] = (prg[i] & 0x0F) | (V << 4); + } else { + prg[i] = (prg[i] & 0xF0) | (V & 0x0F); + } Sync(); } -static DECLFW(M18WriteChr) { +static DECLFW(M018WriteChr) { uint32 i = ((A >> 1) & 1) | ((A - 0xA000) >> 11); - creg[i] &= (0xF0) >> ((A & 1) << 2); - creg[i] |= (V & 0xF) << ((A & 1) << 2); + + if (A & 0x01) { + chr[i] = (chr[i] & 0x0F) | (V << 4); + } else { + chr[i] = (chr[i] & 0xF0) | (V & 0x0F); + } Sync(); } -static void M18Power(void) { +static void M018Power(void) { IRQa = 0; - preg[0] = 0; - preg[1] = 1; - preg[2] = ~1; - preg[3] = ~0; + prg[0] = 0; + prg[1] = 1; + prg[2] = ~1; + prg[3] = ~0; Sync(); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetWriteHandler(0x8000, 0x9FFF, M18WritePrg); - SetWriteHandler(0xA000, 0xDFFF, M18WriteChr); - SetWriteHandler(0xE000, 0xFFFF, M18WriteIRQ); + SetWriteHandler(0x8000, 0x9FFF, M018WritePrg); + SetWriteHandler(0xA000, 0xDFFF, M018WriteChr); + SetWriteHandler(0xE000, 0xFFFF, M018WriteIRQ); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } -static void FP_FASTAPASS(1) M18IRQHook(int a) { +static void M018IRQHook(int a) { if (IRQa && IRQCount) { IRQCount -= a; if (IRQCount <= 0) { @@ -124,21 +138,19 @@ static void FP_FASTAPASS(1) M18IRQHook(int a) { } } -static void M18Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; +static void M018Close(void) { } static void StateRestore(int version) { Sync(); } -void Mapper18_Init(CartInfo *info) { - info->Power = M18Power; - info->Close = M18Close; - MapIRQHook = M18IRQHook; +void Mapper018_Init(CartInfo *info) { + info->Power = M018Power; + info->Close = M018Close; + MapIRQHook = M018IRQHook; GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); WRAMSIZE = 8192; WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); @@ -148,6 +160,4 @@ void Mapper18_Init(CartInfo *info) { info->SaveGame[0] = WRAM; info->SaveGameLen[0] = WRAMSIZE; } - - AddExState(&StateRegs, ~0, 0, 0); } diff --git a/src/mappers/mapper019.c b/src/mappers/mapper019.c new file mode 100644 index 000000000..b25047855 --- /dev/null +++ b/src/mappers/mapper019.c @@ -0,0 +1,257 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "n163sound.h" + +static uint8 prg[4]; +static uint8 chr[8]; +static uint8 nt[4]; +static uint8 wram_protect; + +static uint16 IRQCount; +static uint8 IRQa; + +static SFORMAT N163_StateRegs[] = { + { prg, 4, "PREG" }, + { chr, 8, "CREG" }, + { nt, 4, "NMTA" }, + { &IRQCount, 2, "IRQC" }, + { &IRQa, 1, "IRQA" }, + { &wram_protect, 1, "WPRT" }, + + { 0 } +}; + +static void SyncPRG(void) { + setprg8(0x8000, prg[0] & 0x3F); + setprg8(0xa000, prg[1] & 0x3F); + setprg8(0xc000, prg[2] & 0x3F); + setprg8(0xe000, prg[3] & 0x3F); +} + +static void DoCHRRAMROM(int x, uint8 V) { + chr[x] = V; + if (((prg[1] >> ((x >> 2) + 6)) & 1) || (V < 0xE0)) { + setchr1(x << 10, V); + } +} + +static void FixCRR(void) { + int x; + for (x = 0; x < 8; x++) { + DoCHRRAMROM(x, chr[x]); + } +} + +static void DoNTARAMROM(int w, uint8 V) { + nt[w] = V; + if (V < 0xE0) { + V &= CHRmask1[0]; + setntamem(CHRptr[0] + (V << 10), 0, w); + } else { + setntamem(NTARAM + ((V & 1) << 10), 1, w); + } +} + +static void FixNTAR(void) { + int x; + for (x = 0; x < 4; x++) { + DoNTARAMROM(x, nt[x]); + } +} + +static void NamcoIRQHook(int a) { + if (IRQa) { + IRQCount += a; + if (IRQCount >= 0x7FFF) { + X6502_IRQBegin(FCEU_IQEXT); + IRQa = 0; + IRQCount = 0x7FFF; + } + } +} + +static DECLFR(AWRAM) { + return WRAM[A - 0x6000]; +} + +static DECLFW(BWRAM) { + if (((A >= 0x6000) && (A <= 0x67FF) && ((wram_protect & 0xF1) == 0x40)) || + ((A >= 0x6800) && (A <= 0x6FFF) && ((wram_protect & 0xF2) == 0x40)) || + ((A >= 0x7000) && (A <= 0x77FF) && ((wram_protect & 0xF4) == 0x40)) || + ((A >= 0x7800) && (A <= 0x7FFF) && ((wram_protect & 0xF8) == 0x40))) { + WRAM[A - 0x6000] = V; + } +} + +static DECLFR(M019Read) { + switch (A & 0xF800) { + case 0x4800: + return N163Sound_Read(A); + case 0x5000: + return IRQCount & 0xFF; + case 0x5800: + return IRQCount >> 8; + } + + return 0; +} + +static DECLFW(M019Write) { + switch (A & 0xF800) { + case 0x4800: + N163Sound_Write(A, V); + break; + case 0x5000: + IRQCount &= 0xFF00; + IRQCount |= V; + X6502_IRQEnd(FCEU_IQEXT); + break; + case 0x5800: + IRQCount &= 0x00ff; + IRQCount |= (V & 0x7F) << 8; + IRQa = V & 0x80; + X6502_IRQEnd(FCEU_IQEXT); + break; + case 0x8000: + case 0x8800: + case 0x9000: + case 0x9800: + case 0xA000: + case 0xA800: + case 0xB000: + case 0xB800: + DoCHRRAMROM((A - 0x8000) >> 11, V); + break; + case 0xC000: + case 0xC800: + case 0xD000: + case 0xD800: + DoNTARAMROM((A - 0xC000) >> 11, V); + break; + case 0xE000: + prg[0] = V; + SyncPRG(); + break; + case 0xE800: + prg[1] = V; + SyncPRG(); + FixCRR(); + break; + case 0xF000: + prg[2] = V; + SyncPRG(); + break; + case 0xF800: + wram_protect = V; + N163Sound_Write(A, V); + break; + } +} + +static void StateRestore(int version) { + SyncPRG(); + FixNTAR(); + FixCRR(); +} + +static int battery = 0; + +static void N163_Power(void) { + prg[0] = ~3; + prg[1] = ~2; + prg[2] = ~1; + prg[3] = ~0; + + chr[0] = 0; + chr[1] = 1; + chr[2] = 2; + chr[3] = 3; + chr[4] = 4; + chr[5] = 5; + chr[6] = 6; + chr[7] = 7; + + nt[0] = 0xE0; + nt[1] = 0xE1; + nt[2] = 0xE0; + nt[3] = 0xE1; + + wram_protect = 0xFF; + + SyncPRG(); + FixCRR(); + FixNTAR(); + + SetReadHandler(0x4800, 0x5FFF, M019Read); + SetWriteHandler(0x4800, 0x5FFF, M019Write); + + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M019Write); + + if (WRAMSIZE) { + SetReadHandler(0x6000, 0x7FFF, AWRAM); + SetWriteHandler(0x6000, 0x7FFF, BWRAM); + FCEU_CheatAddRAM(8, 0x6000, WRAM); + } + + if (!battery) { + FCEU_MemoryRand(WRAM, sizeof(WRAM)); + FCEU_MemoryRand(GetIRAM_ptr(), GetIRAM_size()); + } +} + +void Mapper019_Init(CartInfo *info) { + battery = info->battery; + info->Power = N163_Power; + + MapIRQHook = NamcoIRQHook; + GameStateRestore = StateRestore; + AddExState(N163_StateRegs, ~0, 0, 0); + + if (info->iNES2) { + WRAMSIZE = info->PRGRamSize + info->PRGRamSaveSize; + } else if (info->battery) { + WRAMSIZE = 8192; + } + + if (WRAMSIZE) { + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + } + + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = 8192; + info->SaveGame[1] = GetIRAM_ptr(); + info->SaveGameLen[1] = GetIRAM_size(); + } + + N163Sound_ESI(); + N163Sound_AddStateInfo(); +} + +void NSFN163_Init(int chip) { + SetReadHandler(0x4800, 0x4fff, M019Read); + N163Sound_ESI(); +} diff --git a/src/mappers/mapper021.c b/src/mappers/mapper021.c new file mode 100644 index 000000000..9e423b56b --- /dev/null +++ b/src/mappers/mapper021.c @@ -0,0 +1,31 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "vrc2and4.h" + +void Mapper021_Init(CartInfo *info) { + /* Mapper 21 - VRC4a, VRC4c */ + switch (info->submapper) { + case 1: VRC24_Init(info, VRC4, 0x02, 0x04, 1, 1); break; + case 2: VRC24_Init(info, VRC4, 0x40, 0x80, 1, 1); break; + default: VRC24_Init(info, VRC4, 0x42, 0x84, 1, 1); break; + } +} diff --git a/src/mappers/mapper022.c b/src/mappers/mapper022.c new file mode 100644 index 000000000..641fb6e03 --- /dev/null +++ b/src/mappers/mapper022.c @@ -0,0 +1,32 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "vrc2and4.h" + +static void M22CW(uint32 A, uint32 V) { + setchr1(A, (V & 0xFF) >> 1); +} + +void Mapper022_Init(CartInfo *info) { + /* Mapper 22 - VRC2a */ + VRC24_Init(info, VRC2, 0x02, 0x01, 0, 1); + VRC24_cwrap = M22CW; +} diff --git a/src/mappers/mapper023.c b/src/mappers/mapper023.c new file mode 100644 index 000000000..726a2bfb5 --- /dev/null +++ b/src/mappers/mapper023.c @@ -0,0 +1,32 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "vrc2and4.h" + +void Mapper023_Init(CartInfo *info) { + /* Mapper 23 - VRC2b, VRC4e, VRC4f */ + switch (info->submapper) { + case 1: VRC24_Init(info, VRC4, 0x01, 0x02, 1, 1); break; + case 2: VRC24_Init(info, VRC4, 0x04, 0x08, 1, 1); break; + case 3: VRC24_Init(info, VRC2, 0x01, 0x02, 0, 1); break; + default: VRC24_Init(info, VRC4, 0x05, 0x0A, 1, 1); break; + } +} diff --git a/src/mappers/mapper024.c b/src/mappers/mapper024.c new file mode 100644 index 000000000..91fa598b3 --- /dev/null +++ b/src/mappers/mapper024.c @@ -0,0 +1,44 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "vrc6.h" + +static void M024PW(uint32 A, uint8 V) { + setprg8(A, V & 0x3F); +} + +static void M024CW(uint32 A, uint8 V) { + setchr1(A, V & 0xFF); +} + +void Mapper024_Init(CartInfo *info) { + int wram = 0; + if (info->iNES2 && (info->PRGRamSize || info->PRGRamSaveSize)) { + wram = 1; + } else if (info->battery) { + wram = 1; + } + VRC6_Init(info, 0x01, 0x02, wram); + VRC6_pwrap = M024PW; + VRC6_cwrap = M024CW; +} diff --git a/src/mappers/mapper025.c b/src/mappers/mapper025.c new file mode 100644 index 000000000..5e6a8c617 --- /dev/null +++ b/src/mappers/mapper025.c @@ -0,0 +1,37 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "vrc2and4.h" + +static void M025CW(uint32 A, uint32 V) { + setchr1(A, V & 0xFFF); +} + +void Mapper025_Init(CartInfo *info) { + /* Mapper 25 - VRC2c, VRC4b, VRC4d */ + switch (info->submapper) { + case 1: VRC24_Init(info, VRC4, 0x02, 0x01, 1, 1); break; + case 2: VRC24_Init(info, VRC4, 0x08, 0x04, 1, 1); break; + case 3: VRC24_Init(info, VRC2, 0x02, 0x01, 0, 1); break; + default: VRC24_Init(info, VRC4, 0x0A, 0x05, 1, 1); break; + } + VRC24_cwrap = M025CW; +} diff --git a/src/mappers/mapper026.c b/src/mappers/mapper026.c new file mode 100644 index 000000000..a066db868 --- /dev/null +++ b/src/mappers/mapper026.c @@ -0,0 +1,38 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "vrc6.h" + +static void M026PW(uint32 A, uint8 V) { + setprg8(A, V & 0x3F); +} + +static void M026CW(uint32 A, uint8 V) { + setchr1(A, V & 0xFF); +} + +void Mapper026_Init(CartInfo *info) { + VRC6_Init(info, 0x02, 0x01, 1); + VRC6_pwrap = M026PW; + VRC6_cwrap = M026CW; +} diff --git a/src/mappers/mapper027.c b/src/mappers/mapper027.c new file mode 100644 index 000000000..0813e713f --- /dev/null +++ b/src/mappers/mapper027.c @@ -0,0 +1,34 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2013 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg32(0x8000, 0); + setchr4(0x0000, ((latch.addr << 1) & 0x02) | (latch.addr & 0x01)); + setchr4(0x1000, ((latch.addr << 1) & 0x02) | (latch.addr & 0x01)); + setmirror(MI_0 + (latch.addr & 0x01)); +} + +void Mapper027_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); +} diff --git a/src/mappers/mapper028.c b/src/mappers/mapper028.c new file mode 100644 index 000000000..5b9c54ef9 --- /dev/null +++ b/src/mappers/mapper028.c @@ -0,0 +1,107 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 cmd; +static uint8 reg[4]; + +static SFORMAT StateRegs[] = { + {&cmd, 1, "REG"}, + {reg, 4, "REGS"}, + {0} +}; + +static uint8 bank_size_masks[4] = { 0x01, 0x03, 0x07, 0x0F }; +static uint16 GetPRGBank(int V) { + uint16 cpu_a14 = V & 0x01; + uint16 outer_bank = reg[3] << 1; + uint16 bank_mode = reg[2] >> 2; /* discard mirroring bits */ + uint16 current_bank = reg[1]; + uint16 bank_size_mask = 0; + + if (((bank_mode ^ cpu_a14) & 0x03) == 0x02) { /* in UNROM fixed bank? */ + bank_mode = 0; /* if so, treat as NROM */ + } + if ((bank_mode & 0x02) == 0) { /* in 32K bank mode? */ + current_bank = (current_bank << 1) | cpu_a14; + } + bank_size_mask = bank_size_masks[(bank_mode >> 2) & 3]; + return ((current_bank & bank_size_mask) | (outer_bank & ~bank_size_mask)); +} + +static void Sync(void) { + setprg16(0x8000, GetPRGBank(0)); + setprg16(0xC000, GetPRGBank(1)); + setchr8(reg[0] & 0x03); + switch (reg[2] & 0x03) { + case 0: setmirror(MI_0); break; + case 1: setmirror(MI_1); break; + case 2: setmirror(MI_V); break; + case 3: setmirror(MI_H); break; + } +} + +static DECLFW(WriteCMD) { + cmd = ((V >> 6) & 0x02) | (V & 0x01); +} + +static DECLFW(WriteREG) { + reg[cmd] = V; + if (!(cmd & 0x02) && !(reg[2] & 0x02)) { + reg[2] &= ~0x01; + reg[2] |= (V >> 4) & 0x01; + } + Sync(); +} + +static void M028Power(void) { + reg[0] = ~0; + reg[1] = ~0; + reg[2] = ~0; + reg[3] = ~0; + Sync(); + + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetReadHandler(0x8000, 0xFFFF, CartBR); + + SetWriteHandler(0x5000, 0x5FFF, WriteCMD); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + SetWriteHandler(0x8000, 0xFFFF, WriteREG); +} + +static void M028Reset(void) { + Sync(); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper028_Init(CartInfo *info) { + info->Power = M028Power; + info->Reset = M028Reset; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper029.c b/src/mappers/mapper029.c new file mode 100644 index 000000000..a0b038e70 --- /dev/null +++ b/src/mappers/mapper029.c @@ -0,0 +1,37 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 28, used by homebrew game Glider + * https://wiki.nesdev.com/w/index.php/INES_Mapper_029 */ + +#include "mapinc.h" +#include "latch.h" + +static void Sync(void) { + setprg16(0x8000, latch.data >> 2); + setprg16(0xc000, ~0); + setprg8r(0x10, 0x6000, 0); + setchr8r(0, latch.data & 3); +} + +void Mapper029_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, TRUE, FALSE); +} diff --git a/src/mappers/mapper030.c b/src/mappers/mapper030.c new file mode 100644 index 000000000..a4c2e2939 --- /dev/null +++ b/src/mappers/mapper030.c @@ -0,0 +1,142 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2014 CaitSith2, 2022 Cluster + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* + * Roms still using NES 1.0 format should be loaded as 8K CHR RAM. + * Roms defined under NES 2.0 should use the VRAM size field, defining 7, 8 or 9, based on how much VRAM should be + * present. UNIF doesn't have this problem, because unique board names can define this information. The UNIF names are + * UNROM-512-8K, UNROM-512-16K and UNROM-512-32K + * + * The battery flag in the NES header enables flash, Mirrror mode 2 Enables MI_0 and MI_1 mode. + * Known games to use this board are: + * Battle Kid 2: Mountain of Torment (512K PRG, 8K CHR RAM, Horizontal Mirroring, Flash disabled) + * Study Hall (128K PRG (in 512K flash chip), 8K CHR RAM, Horizontal Mirroring, Flash enabled) + * Nix: The Paradox Relic (512 PRG, 8K CHR RAM, Vertical Mirroring, Flash enabled) + * Although Xmas 2013 uses a different board, where LEDs can be controlled (with writes to the $8000-BFFF space), + * it otherwise functions identically. + */ + +#include "mapinc.h" +#include "latch.h" +#include "flashrom.h" + +#define ROM_CHIP 0x00 +#define FLASH_CHIP 0x10 + +static uint8 flash_save; +static uint8 *flash_data; + +static void M030Sync(void) { + int chip = flash_save ? FLASH_CHIP : ROM_CHIP; + + setprg16r(chip, 0x8000, latch.data & 0x1F); + setprg16r(chip, 0xC000, ~0); + setchr8((latch.data >> 5) & 0x03); + switch (iNESCart.submapper) { + case 1: + /* Mega Man II (30th Anniversary Edition) */ + setmirror((latch.data >> 7) & 0x01); + break; + default: + setmirror(MI_0 + ((latch.data >> 7) & 0x01)); + break; + } +} + +static void M030CPUHook(int a) { + FlashROM_CPUCyle(a); +} + +static DECLFR(M030Read) { + if ((A < 0xC000) && flash_save) { + return FlashROM_Read(A); + } + return CartBR(A); +} + +static DECLFW(M030Write) { + if ((A < 0xC000) && flash_save) { + FlashROM_Write(A, V); + } else { + Latch_Write(A, V); + } +} + +static void M030Power(void) { + Latch_Power(); + SetReadHandler(0x8000, 0xFFFF, M030Read); + SetWriteHandler(0x8000, 0xBFFF, M030Write); +} + +static void M030Close(void) { + Latch_Close(); + if (flash_data) { + FCEU_gfree(flash_data); + } + flash_data = NULL; +} + +void Mapper030_Init(CartInfo *info) { + flash_save = info->battery; + Latch_Init(info, M030Sync, NULL, 0, !flash_save); + + if (!info->submapper && (info->PRGCRC32 == 0x891C14BC)) { + info->submapper = 0x01; + } + + if (!(info->submapper & 1)) { + switch (info->mirror2bits) { + case 0: /* hard horizontal, internal */ + SetupCartMirroring(MI_H, 1, NULL); + break; + case 1: /* hard vertical, internal */ + SetupCartMirroring(MI_V, 1, NULL); + break; + case 2: /* switchable 1-screen, internal (flags: 4-screen + horizontal) */ + SetupCartMirroring(MI_0, 0, NULL); + break; + case 3: /* hard four screen, last 8k of 32k RAM (flags: 4-screen + vertical) */ + SetupCartMirroring(4, 1, ROM.chr.data + (info->CHRRamSize - 8192)); + break; + } + } + + info->Power = M030Power; + info->Close = M030Close; + + if (flash_save) { + uint32 i, ssize; + /* Allocate memory for flash */ + ssize = PRGsize[0]; + flash_data = (uint8 *)FCEU_gmalloc(ssize); + /* Copy ROM to flash data */ + for (i = 0; i < ssize; i++) { + flash_data[i] = PRGptr[ROM_CHIP][i % ssize]; + } + SetupCartPRGMapping(FLASH_CHIP, flash_data, ssize, 1); + AddExState(flash_data, ssize, 0, "FLSH"); + info->SaveGame[0] = flash_data; + info->SaveGameLen[0] = ssize; + + FlashROM_Init(flash_data, ssize, 0xBF, 0xB7, 4096, 0x5555, 0x2AAA); + MapIRQHook = M030CPUHook; + } +} diff --git a/src/boards/mapper031.c b/src/mappers/mapper031.c similarity index 60% rename from src/boards/mapper031.c rename to src/mappers/mapper031.c index 17777ab9b..489dc81f7 100644 --- a/src/boards/mapper031.c +++ b/src/mappers/mapper031.c @@ -1,6 +1,8 @@ /* FCEUmm - NES/Famicom Emulator * - * Copyright (C) 2019 Libretro Team + * Copyright notice for this file: + * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -23,44 +25,50 @@ #include "mapinc.h" -static uint8 preg[8]; +static uint8 prg[8]; -static SFORMAT StateRegs[] = -{ - { preg, 8, "PREG" }, +static SFORMAT StateRegs[] = { + { prg, 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]); + setprg4(0x8000, prg[0]); + setprg4(0x9000, prg[1]); + setprg4(0xA000, prg[2]); + setprg4(0xB000, prg[3]); + setprg4(0xC000, prg[4]); + setprg4(0xD000, prg[5]); + setprg4(0xE000, prg[6]); + setprg4(0xF000, prg[7]); setchr8(0); } -static DECLFW(M31Write) { - preg[A & 7] = V; +static DECLFW(M031Write) { + prg[A & 0x07] = V; Sync(); } -static void M31Power(void) { - preg[7] = ~0; +static void M031Power(void) { + prg[0] = ~7; + prg[1] = ~6; + prg[2] = ~5; + prg[3] = ~4; + prg[4] = ~3; + prg[5] = ~2; + prg[6] = ~1; + prg[7] = ~0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x5000, 0x5FFF, M31Write); + SetWriteHandler(0x5000, 0x5FFF, M031Write); } static void StateRestore(int version) { Sync(); } -void Mapper31_Init(CartInfo *info) { - info->Power = M31Power; +void Mapper031_Init(CartInfo *info) { + info->Power = M031Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper032.c b/src/mappers/mapper032.c new file mode 100644 index 000000000..4abd47eb0 --- /dev/null +++ b/src/mappers/mapper032.c @@ -0,0 +1,132 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 prg[2], chr[8], prgMode, mirr; + +static SFORMAT StateRegs[] = { + { prg, 4, "PREG" }, + { chr, 8, "CREG" }, + { &prgMode, 1, "MODE" }, + { &mirr, 1, "mirr" }, + { 0 } +}; + +static void Sync(void) { + if (prgMode == 0) { + setprg8(0x8000, prg[0]); + setprg8(0xA000, prg[1]); + setprg8(0xC000, ~1); + setprg8(0xE000, ~0); + } else { + setprg8(0x8000, ~1); + setprg8(0xA000, prg[1]); + setprg8(0xC000, prg[0]); + setprg8(0xE000, ~0); + } + + setchr1(0x0000, chr[0]); + setchr1(0x0400, chr[1]); + setchr1(0x0800, chr[2]); + setchr1(0x0C00, chr[3]); + setchr1(0x1000, chr[4]); + setchr1(0x1400, chr[5]); + setchr1(0x1800, chr[6]); + setchr1(0x1C00, chr[7]); + + if (iNESCart.submapper == 1) { + setmirror(MI_1); + } else { + setmirror((mirr & 0x01) ^ 0x01); + } +} + +static DECLFW(M032Write) { + switch (A & 0xF000) { + case 0x8000: + case 0xA000: + prg[(A >> 13) & 0x01] = V; + Sync(); + break; + case 0x9000: + mirr = (V & 0x01) != 0; + prgMode = (V & 0x02) != 0; + if (iNESCart.submapper == 1) { + prgMode = 0; + } + Sync(); + break; + case 0xB000: + chr[A & 0x07] = V; + Sync(); + break; + } +} + +static void M032Power(void) { + prg[0] = 0; + prg[1] = 1; + chr[0] = 0; + chr[1] = 1; + chr[2] = 2; + chr[3] = 3; + chr[4] = 4; + chr[5] = 5; + chr[6] = 6; + chr[7] = 7; + prgMode = 0; + Sync(); + + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M032Write); + + if (WRAM) { + setprg8r(0x10, 0x6000, 0); + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + } +} + +static void M032Close(void) { +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper032_Init(CartInfo *info) { + info->Power = M032Power; + info->Close = M032Close; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + + WRAMSIZE = 8192; + if (info->iNES2) { + WRAMSIZE = info->PRGRamSize + info->PRGRamSaveSize; + } + if (WRAMSIZE) { + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + } +} diff --git a/src/mappers/mapper033.c b/src/mappers/mapper033.c new file mode 100644 index 000000000..a8f57b24e --- /dev/null +++ b/src/mappers/mapper033.c @@ -0,0 +1,86 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* iNES Mapper 33 - Taito TC0190/TC0350 */ + +#include "mapinc.h" + +static uint8 prg[2], chr[6]; + +static SFORMAT StateRegs[] = { + { prg, 2, "PREG" }, + { chr, 6, "CREG" }, + { 0 } +}; + +static void Sync(void) { + setprg8(0x8000, prg[0]); + setprg8(0xA000, prg[1]); + setprg16(0xC000, ~0); + + setchr2(0x0000, chr[0]); + setchr2(0x0800, chr[1]); + setchr1(0x1000, chr[2]); + setchr1(0x1400, chr[3]); + setchr1(0x1800, chr[4]); + setchr1(0x1C00, chr[5]); + + setmirror(((prg[0] >> 6) & 0x01) ^ 0x01); +} + +static DECLFW(M033Write) { + switch (A & 0xE003) { + case 0x8000: + case 0x8001: + prg[A & 0x01] = V; + Sync(); + break; + case 0x8002: + case 0x8003: + chr[A & 0x01] = V; + Sync(); + break; + case 0xA000: + case 0xA001: + case 0xA002: + case 0xA003: + chr[2 + (A & 0x03)] = V; + Sync(); + break; + } +} + +static void M33Power(void) { + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xBFFF, M033Write); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper033_Init(CartInfo *info) { + info->Power = M33Power; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} + diff --git a/src/mappers/mapper034.c b/src/mappers/mapper034.c new file mode 100644 index 000000000..4c6193ece --- /dev/null +++ b/src/mappers/mapper034.c @@ -0,0 +1,149 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + * Many-in-one hacked mapper crap. + * + * Original BNROM is actually AxROM variations without mirroring control, + * and haven't SRAM on-board, so it must be removed from here + * + * Difficult banking is what NINA board doing, most hacks for 34 mapper are + * NINA hacks, so this is actually 34 mapper + * + */ + +#include "mapinc.h" +#include "latch.h" + +#define M034_NINA001 1 +#define M034_BNROM 2 +#define M034_NESTICLE 3 + +static uint8 reg[3]; + +static uint8 type; +static void (*WSync)(void); + +static SFORMAT StateRegs[] = { + { reg, 3, "REGS" }, + { 0 } +}; + +/* submapper 1 - AVE NINA-001 */ + +static void Sync_NINA001(void) { + setprg8r(0x10, 0x6000, 0); + setprg32(0x8000, reg[0]); + setchr4(0x0000, reg[1]); + setchr4(0x1000, reg[2]); +} + +static DECLFW(M034Write_NINA001) { + CartBW(A, V); + if (A >= 0x7FFD) { + reg[A - 0x7FFD] = V; + WSync(); + } +} + +static void M034Power_NINA001(void) { + reg[0] = reg[1] = 0; + reg[2] = 1; + WSync(); + + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, M034Write_NINA001); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); +} + +/* submapper 2 - BNROM */ + +static void Sync_BNROM(void) { + setprg32(0x8000, latch.data); + setchr8(0); +} + +/* nesticle */ + +static void Sync_Nesticle(void) { + setprg8r(0x10, 0x6000, 0); + setprg32(0x8000, reg[0]); + setchr4(0x0000, reg[1]); + setchr4(0x1000, reg[2]); +} + +static DECLFW(M034Write_Nesticle) { + if (A >= 0x8000) { + reg[0] = V; + WSync(); + } else { + CartBW(A, V); + if (A >= 0x7FFD) { + reg[A - 0x7FFD] = V; + WSync(); + } + } +} + +static void M034Power_Nesticle(void) { + reg[0] = reg[1] = 0; + reg[2] = 1; + WSync(); + + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0xFFFF, M034Write_Nesticle); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); +} + +static void M034Close(void) { +} + +static void StateRestore(int version) { + WSync(); +} + +void Mapper034_Init(CartInfo *info) { + if (ROM.trainer.data && (ROM.trainer.size > 0)) { + type = M034_NESTICLE; + WSync = Sync_Nesticle; + info->Power = M034Power_Nesticle; + } else if ((info->submapper == 1) || ((info->submapper != 2) && ROM.chr.size > 0)) { + type = M034_NINA001; + WSync = Sync_NINA001; + info->Power = M034Power_NINA001; + } else if ((info->submapper == 2) || ((info->submapper != 1) && ROM.chr.size == 0)) { + type = M034_BNROM; + Latch_Init(info, Sync_BNROM, NULL, FALSE, TRUE); + info->Reset = Latch_RegReset; + } + + switch (type) { + case M034_NESTICLE: + case M034_NINA001: + info->Close = M034Close; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + + WRAMSIZE = 8192; + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + break; + } +} diff --git a/src/mappers/mapper036.c b/src/mappers/mapper036.c new file mode 100644 index 000000000..1fbeb7bea --- /dev/null +++ b/src/mappers/mapper036.c @@ -0,0 +1,55 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "txc.h" + +static uint8 chr = 0; + +static void M036Sync(void) { + setprg32(0x8000, txc.output & 0x03); + setchr8(chr & 0x0F); +} + +static DECLFW(M036Write) { + if ((A & 0xF200) == 0x4200) { + chr = V; + } + TXC_Write(A, (V >> 4) & 0x03); +} + +static DECLFR(M036Read) { + return (cpu.openbus & ~0x30) | ((TXC_Read(A) << 4) & 0x30); +} + +static void M036Power(void) { + chr = 0; + TXC_Power(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetReadHandler(0x4100, 0x5FFF, M036Read); + SetWriteHandler(0x4100, 0xFFFF, M036Write); +} + +void Mapper036_Init(CartInfo *info) { + TXC_Init(info, M036Sync); + info->Power = M036Power; + AddExState(&chr, 1, 0, "CREG"); +} diff --git a/src/mappers/mapper037.c b/src/mappers/mapper037.c new file mode 100644 index 000000000..f28319905 --- /dev/null +++ b/src/mappers/mapper037.c @@ -0,0 +1,66 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 reg; + +static void M037PW(uint32 A, uint8 V) { + uint16 mask = (reg << 1) | 0x07; + uint16 base = ((reg << 2) & 0x10) | (((reg & 0x03) == 0x03) ? 0x08 : 0); + + setprg8(A, (base & ~mask) | (V & mask)); +} + +static void M037CW(uint32 A, uint8 V) { + uint16 mask = 0x7F; + uint16 base = (reg << 5) & 0x80; + + setchr1(A, (base & ~mask) | (V & mask)); +} + +static DECLFW(M037Write) { + if (MMC3_WramIsWritable()) { + reg = V; + MMC3_FixPRG(); + MMC3_FixCHR(); + } +} + +static void M037Reset(void) { + reg = 0; + MMC3_Reset(); +} + +static void M037Power(void) { + reg = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M037Write); +} + +void Mapper037_Init(CartInfo *info) { + MMC3_Init(info, 8, info->battery); + MMC3_pwrap = M037PW; + MMC3_cwrap = M037CW; + info->Power = M037Power; + info->Reset = M037Reset; + AddExState(®, 1, 0, "EXPR"); +} diff --git a/src/boards/mapper038.c b/src/mappers/mapper038.c similarity index 74% rename from src/boards/mapper038.c rename to src/mappers/mapper038.c index 59921b6da..d036d050c 100644 --- a/src/boards/mapper038.c +++ b/src/mappers/mapper038.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,35 +22,34 @@ static uint8 reg; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { ®, 1, "REG" }, { 0 } }; -static void Sync() { - setprg32(0x8000, reg & 3); - setchr8(reg >> 2); +static void Sync(void) { + setprg32(0x8000, reg & 0x03); + setchr8((reg >> 2) & 0x03); } -static DECLFW(M38Write) { +static DECLFW(M038Write) { reg = V; Sync(); } -static void M38Power(void) { +static void M038Power(void) { reg = 0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x7000, 0x7FFF, M38Write); + SetWriteHandler(0x7000, 0x7FFF, M038Write); } static void StateRestore(int version) { Sync(); } -void Mapper38_Init(CartInfo *info) { - info->Power = M38Power; +void Mapper038_Init(CartInfo *info) { + info->Power = M038Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper040.c b/src/mappers/mapper040.c new file mode 100644 index 000000000..9218ce246 --- /dev/null +++ b/src/mappers/mapper040.c @@ -0,0 +1,113 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + */ + +#include "mapinc.h" + +static uint8 reg[2]; +static uint32 IRQCount, IRQa; + +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, + { &IRQCount, 4, "IRQC" }, + { &IRQa, 4, "IRQA" }, + { 0 } +}; + +static void Sync(void) { + if (reg[1] & 0x08) { + if (reg[1] & 0x10) + setprg32(0x8000, 2 | (reg[1] >> 6)); + else { + setprg16(0x8000, 4 | (reg[1] >> 5)); + setprg16(0xC000, 4 | (reg[1] >> 5)); + } + } else { + setprg8(0x6000, 6); + setprg8(0x8000, 4); + setprg8(0xA000, 5); + setprg8(0xC000, reg[0] & 0x07); + setprg8(0xE000, 7); + } + setchr8((reg[1] >> 1) & 0x03); + setmirror((reg[1] & 0x01) ^ 0x01); +} + +static DECLFW(M040Write) { + switch (A & 0xE000) { + case 0x8000: + IRQa = FALSE; + IRQCount = 0; + X6502_IRQEnd(FCEU_IQEXT); + break; + case 0xA000: + IRQa = TRUE; + break; + case 0xC000: + if (iNESCart.submapper == 1) { + reg[1] = A & 0xFF; + Sync(); + } + break; + case 0xE000: + reg[0] = V; + Sync(); + break; + } +} + +static void M040Power(void) { + reg[0] = reg[1] = 0; + IRQCount = IRQa = 0; + Sync(); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M040Write); +} + +static void M040Reset(void) { + reg[0] = 0; + reg[1] = 0; + IRQCount = IRQa = 0; + Sync(); +} + +static void M040IRQHook(int a) { + if (IRQa) { + IRQCount += a; + if (IRQCount & 0x1000) { + X6502_IRQBegin(FCEU_IQEXT); + } + } +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper040_Init(CartInfo *info) { + info->Reset = M040Reset; + info->Power = M040Power; + MapIRQHook = M040IRQHook; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/mapper041.c b/src/mappers/mapper041.c similarity index 57% rename from src/boards/mapper041.c rename to src/mappers/mapper041.c index d0d908396..12b440ce1 100644 --- a/src/boards/mapper041.c +++ b/src/mappers/mapper041.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) 2023-2024 negativeExponent * * 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 @@ -20,50 +21,52 @@ #include "mapinc.h" -static uint8 mainreg, chrreg, mirror; +static uint8 reg[2]; -static SFORMAT StateRegs[] = -{ - { &mainreg, 1, "MREG" }, - { &chrreg, 1, "CREG" }, - { &mirror, 1, "MIRR" }, +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, { 0 } }; static void Sync(void) { - setprg32(0x8000, mainreg & 7); - setchr8(chrreg); - setmirror(mirror); + setprg32(0x8000, reg[0] & 0x07); + setchr8(((reg[0] >> 1) & 0x0C) | (reg[1] & 0x03)); + setmirror(((reg[0] >> 5) & 0x01) ^ 0x01); } -static DECLFW(M41Write0) { - mainreg = A & 0xFF; - mirror = ((A >> 5) & 1) ^ 1; - chrreg = (chrreg & 3) | ((A >> 1) & 0xC); +static DECLFW(M041Write0) { + reg[0] = A; Sync(); } -static DECLFW(M41Write1) { - if (mainreg & 0x4) { - chrreg = (chrreg & 0xC) | (A & 3); +static DECLFW(M041Write1) { + if (reg[0] & 0x04) { + /* bus conflict */ + reg[1] = (V & CartBR(A)); Sync(); } } -static void M41Power(void) { - mainreg = chrreg = 0; +static void M041Reset(void) { + reg[0] = reg[1] = 0; + Sync(); +} + +static void M041Power(void) { + reg[0] = reg[1] = 0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0x67FF, M41Write0); - SetWriteHandler(0x8000, 0xFFFF, M41Write1); + SetWriteHandler(0x6000, 0x67FF, M041Write0); + SetWriteHandler(0x8000, 0xFFFF, M041Write1); } static void StateRestore(int version) { Sync(); } -void Mapper41_Init(CartInfo *info) { - info->Power = M41Power; +void Mapper041_Init(CartInfo *info) { + info->Power = M041Power; + info->Reset = M041Reset; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper042.c b/src/mappers/mapper042.c new file mode 100644 index 000000000..c4b41d5bc --- /dev/null +++ b/src/mappers/mapper042.c @@ -0,0 +1,201 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * - Submapper 1 - Ai Senshi Nicol (256K PRG, 128K CHR, fixed Mirroring) + * - Submapper 3 - Bio Miracle Bokutte Upa (J) (128K PRG, 0K CHR, IRQ) + * + * - Submapper 2 + * - KS-018/AC-08/LH09 + * - UNIF UNL-AC08 + * - [UNIF] Green Beret (FDS Conversion, LH09) (Unl) [U][!][t1] (160K PRG) + * - Green Beret (FDS Conversion) (Unl) (256K PRG) + */ + +#include "mapinc.h" +#include "fdssound.h" + +static uint8 reg[2]; +static uint8 IRQa; +static uint16 IRQCount; + +static void (*WSync)(void); + +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, + { &IRQa, 1, "IRQA" }, + { &IRQCount, 2, "IRQC" }, + { 0 } +}; + +/* Submapper 1 - Ai Senshi Nicol */ + +static void M042_Sub1_Sync(void) { + setprg8(0x6000, reg[1] & 0x0F); + setprg32(0x8000, ~0); + setchr8(reg[0] & 0x0F); +} + +static DECLFW(M042_Sub1_Write) { + switch (A & 0xE000) { + case 0x8000: + reg[0] = V; + WSync(); + break; + case 0xE000: + reg[1] = V; + WSync(); + break; + } +} + +static void M042_Sub1_Power(void) { + reg[1] = 0; + reg[0] = 0; + FDSSound_Power(); + WSync(); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M042_Sub1_Write); +} + +/* Submapper 2 - Green Beret */ + +static void M042_Sub2_Sync(void) { + setprg8(0x6000, (reg[0] >> 1) & 0x0F); + setprg32(0x8000, (ROM.prg.size & 0x0F) ? 4 : 7); + setchr8(0); + setmirror(((reg[1] >> 3) & 1) ^ 1); +} + +static DECLFW(M042_Sub2_Write) { + switch (A & 0xF001) { + case 0x4001: + case 0x4000: + if ((A & 0xFF) != 0x25) { + break; + } + reg[1] = V; + WSync(); + break; + case 0x8001: + reg[0] = V; + WSync(); + break; + } +} + +static void M042_Sub2_Power(void) { + reg[0] = 0; + reg[1] = 0; + WSync(); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x4020, 0xFFFF, M042_Sub2_Write); +} + +/* Submapper 3 - Mario Baby */ + +static void M042_Sub3_Sync(void) { + setprg8(0x6000, reg[0] & 0x0F); + setprg32(0x8000, ~0); + setchr8(0); + setmirror(((reg[1] >> 3) & 1) ^ 1); +} + +static DECLFW(M042_Sub3_Write) { + switch (A & 0xE003) { + case 0xE000: + reg[0] = V; + WSync(); + break; + case 0xE001: + reg[1] = V; + WSync(); + break; + case 0xE002: + IRQa = (V & 0x02) != 0; + if (!IRQa) { + IRQCount = 0; + X6502_IRQEnd(FCEU_IQEXT); + } + break; + } +} + +static void M042_Sub3_Power(void) { + reg[0] = 0; + reg[1] = 0; + IRQa = IRQCount = 0; + WSync(); + FDSSound_Power(); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0xE000, 0xFFFF, M042_Sub3_Write); +} + +static void M042_Sub3_IRQHook(int a) { + if (IRQa) { + IRQCount += a; + if (IRQCount >= 24576) { + X6502_IRQBegin(FCEU_IQEXT); + } else { + X6502_IRQEnd(FCEU_IQEXT); + } + } +} + +/* Mapper 42 Loader */ +static void StateRestore(int version) { + WSync(); +} + +void Mapper042_Init(CartInfo *info) { + if (info->submapper == 0 || info-> submapper > 3) { + if (!UNIFchrrama) { + /* Ai Senshi Nicole, only cart with CHR-ROM, all others use CHR-RAM */ + info->submapper = 1; + } else { + if ((ROM.prg.size * 16) > 128) { + /* Green Beret LH09 FDS Conversion can be 160K or 256K */ + info->submapper = 2; + } else { + /* Mario Baby has only 128K PRG */ + info->submapper = 3; + } + } + } + + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + + switch (info->submapper) { + case 1: + info->Power = M042_Sub1_Power; + WSync = M042_Sub1_Sync; + break; + case 2: + info->Power = M042_Sub2_Power; + WSync = M042_Sub2_Sync; + break; + default: + info->Power = M042_Sub3_Power; + WSync = M042_Sub3_Sync; + MapIRQHook = M042_Sub3_IRQHook; + break; + } +} diff --git a/src/boards/mapper043.c b/src/mappers/mapper043.c similarity index 61% rename from src/boards/mapper043.c rename to src/mappers/mapper043.c index ebeb77f7d..7840198de 100644 --- a/src/boards/mapper043.c +++ b/src/mappers/mapper043.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2006 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -26,22 +27,23 @@ static uint8 reg, swap; static uint32 IRQCount, IRQa; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { &IRQCount, 4, "IRQC" }, { &IRQa, 4, "IRQA" }, - { ®, 1, "REG" }, + { ®, 1, "REGS" }, { &swap, 1, "SWAP" }, { 0 } }; static void Sync(void) { + int transo[8] = { 4, 3, 4, 4, 4, 7, 5, 6 }; + setprg4(0x5000, 8 << 1); /* Only YS-612 advanced version */ setprg8(0x6000, swap ? 0 : 2); setprg8(0x8000, 1); - setprg8(0xa000, 0); - setprg8(0xc000, reg); - setprg8(0xe000, swap ? 8 : 9); /* hard dump for mr.Mary is 128K, + setprg8(0xA000, 0); + setprg8(0xC000, transo[reg & 0x07]); + setprg8(0xE000, swap ? 8 : 9); /* hard dump for mr.Mary is 128K, * bank 9 is the last 2K ok bank 8 repeated 4 times, then till the end of 128K * instead used bank A, containing some CHR data, ines rom have unused banks removed, * and bank A moved to the bank 9 place for compatibility with other crappy dumps @@ -49,53 +51,47 @@ static void Sync(void) { setchr8(0); } -static DECLFW(M43Write) { - /* int transo[8]={4,3,4,4,4,7,5,6}; */ - int transo[8] = { 4, 3, 5, 3, 6, 3, 7, 3 }; /* According to hardware tests */ - switch (A & 0xf1ff) { - case 0x4022: - reg = transo[V & 7]; - Sync(); - break; - case 0x4120: - swap = V & 1; - Sync(); - break; - case 0x8122: /* hacked version */ - case 0x4122: /* original version */ - IRQa = V & 1; - X6502_IRQEnd(FCEU_IQEXT); - IRQCount = 0; - break; +static DECLFW(M043Write) { + switch (A & 0xF1FF) { + case 0x4022: + reg = V; + Sync(); + break; + case 0x4120: + swap = V & 0x01; + Sync(); + break; + case 0x8122: /* hacked version */ + case 0x4122: /* original version */ + IRQa = V & 0x01; + IRQCount = 0; + X6502_IRQEnd(FCEU_IQEXT); + break; } } -static void M43Power(void) { +static void M043Power(void) { reg = swap = 0; Sync(); - SetReadHandler(0x5000, 0xffff, CartBR); - SetWriteHandler(0x4020, 0xffff, M43Write); + SetReadHandler(0x5000, 0xFFFF, CartBR); + SetWriteHandler(0x4020, 0x8FFF, M043Write); } -static void M43Reset(void) { } - -static void FP_FASTAPASS(1) M43IRQHook(int a) { +static void M043IRQHook(int a) { IRQCount += a; - if (IRQa) - if (IRQCount >= 4096) { - IRQa = 0; - X6502_IRQBegin(FCEU_IQEXT); - } + if (IRQa && (IRQCount >= 4096)) { + IRQa = 0; + X6502_IRQBegin(FCEU_IQEXT); + } } static void StateRestore(int version) { Sync(); } -void Mapper43_Init(CartInfo *info) { - info->Reset = M43Reset; - info->Power = M43Power; - MapIRQHook = M43IRQHook; +void Mapper043_Init(CartInfo *info) { + info->Power = M043Power; + MapIRQHook = M043IRQHook; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper044.c b/src/mappers/mapper044.c new file mode 100644 index 000000000..9e0d2172e --- /dev/null +++ b/src/mappers/mapper044.c @@ -0,0 +1,63 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static void M044PW(uint32 A, uint8 V) { + uint8 base = (mmc3.wram << 4) & 0x70; + uint8 mask = ((mmc3.wram & 0x06) == 0x06) ? 0x1F : 0x0F; + + setprg8(A, (base & ~mask) | (V & mask)); +} + +static void M044CW(uint32 A, uint8 V) { + uint16 base = (mmc3.wram << 7) & 0x380; + uint16 mask = ((mmc3.wram & 0x06) == 0x06) ? 0xFF : 0x7F; + + setchr1(A, (base & ~mask) | (V & mask)); +} + +static DECLFW (M044WriteA000) { + MMC3_CMDWrite(A, V); + switch (A & 0xE001) { + case 0xA001: + MMC3_FixPRG(); + MMC3_FixCHR(); + break; + } +} + +static void M044Reset(void) { + MMC3_Reset(); +} + +static void M044Power(void) { + MMC3_Power(); + SetWriteHandler(0xA000, 0xBFFF, M044WriteA000); +} + +void Mapper044_Init(CartInfo *info) { + MMC3_Init(info, 8, info->battery); + MMC3_cwrap = M044CW; + MMC3_pwrap = M044PW; + info->Power = M044Power; + info->Reset = M044Reset; +} diff --git a/src/mappers/mapper045.c b/src/mappers/mapper045.c new file mode 100644 index 000000000..31056e502 --- /dev/null +++ b/src/mappers/mapper045.c @@ -0,0 +1,108 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 reg[4]; +static uint8 cmd; +static uint8 dipsw; + +static SFORMAT StateRegs[] = { + { reg, 4, "REGS" }, + { &cmd, 1, "CMD0" }, + { &dipsw, 1, "DPSW" }, + { 0 } +}; + +static void M045CW(uint32 A, uint8 V) { + if (UNIFchrrama) { + /* assume chr-ram, 4-in-1 Yhc-Sxx-xx variants */ + setchr8(0); + } else { + uint32 mask = 0xFF >> (~reg[2] & 0x0F); + uint32 base = ((reg[2] << 4) & 0xF00) | reg[0]; + + setchr1(A, (base & ~mask) | (V & mask)); + } +} + +static void M045PW(uint32 A, uint8 V) { + uint32 mask = ~reg[3] & 0x3F; + uint32 base = ((reg[2] << 2) & 0x300) | reg[1]; + + setprg8(A, (base & ~mask) | (V & mask)); +} + +static DECLFR(M045ReadCart) { + /* Some multicarts select between five different menus by connecting one of the higher address lines to PRG /CE. + The menu code selects between menus by checking which of the higher address lines disables PRG-ROM when set. */ + if (((PRGsize[0] < 0x200000) && (dipsw == 1) && (reg[1] & 0x80)) || + ((PRGsize[0] < 0x200000) && (dipsw == 2) && (reg[2] & 0x40)) || + ((PRGsize[0] < 0x100000) && (dipsw == 3) && (reg[1] & 0x40)) || + ((PRGsize[0] < 0x100000) && (dipsw == 4) && (reg[2] & 0x20))) { + return cpu.openbus; + } + return CartBR(A); +} + +static DECLFW(M045WriteReg) { + CartBW(A, V); + if (!(reg[3] & 0x40)) { + reg[cmd] = V; + cmd = (cmd + 1) & 0x03; + MMC3_FixPRG(); + MMC3_FixCHR(); + } +} + +static DECLFR(M045ReadDIP) { + uint32 addr = 1 << (dipsw + 4); + if (A & (addr | (addr - 1))) { + return 0x01; + } + return 0x00; +} + +static void M045Reset(void) { + reg[0] = reg[1] = reg[3] = cmd = 0; + reg[2] = 0x0F; + dipsw++; + dipsw &= 7; + MMC3_Reset(); +} + +static void M045Power(void) { + reg[0] = reg[1] = reg[3] = cmd = dipsw = 0; + reg[2] = 0x0F; + MMC3_Power(); + SetReadHandler(0x8000, 0xFFFF, M045ReadCart); + SetWriteHandler(0x6000, 0x7FFF, M045WriteReg); + SetReadHandler(0x5000, 0x5FFF, M045ReadDIP); +} + +void Mapper045_Init(CartInfo *info) { + MMC3_Init(info, 8, info->battery); + MMC3_cwrap = M045CW; + MMC3_pwrap = M045PW; + info->Reset = M045Reset; + info->Power = M045Power; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/mapper151.c b/src/mappers/mapper046.c similarity index 57% rename from src/boards/mapper151.c rename to src/mappers/mapper046.c index 45b7e2a59..04d15ef6e 100644 --- a/src/boards/mapper151.c +++ b/src/mappers/mapper046.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) 2023-2024 negativeExponent * * 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 @@ -19,41 +20,39 @@ */ #include "mapinc.h" +#include "latch.h" -static uint8 regs[8]; +static uint8 reg; -static SFORMAT StateRegs[] = -{ - { regs, 8, "REGS" }, +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, { 0 } }; static void Sync(void) { - setprg8(0x8000, regs[0]); - setprg8(0xA000, regs[2]); - setprg8(0xC000, regs[4]); - setprg8(0xE000, ~0); - setchr4(0x0000, regs[6]); - setchr4(0x1000, regs[7]); + setprg32(0x8000, ((reg & 0x0F) << 1) | (latch.data & 0x01)); + setchr8(((reg & 0xF0) >> 1) | ((latch.data >> 4) & 0x07)); } -static DECLFW(M151Write) { - regs[(A >> 12) & 7] = V; +static DECLFW(M046WriteReg) { + reg = V; Sync(); } -static void M151Power(void) { - Sync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, M151Write); +static void M046Power(void) { + reg = 0; + Latch_Power(); + SetWriteHandler(0x6000, 0x7FFF, M046WriteReg); } -static void StateRestore(int version) { +static void M046Reset(void) { + reg = 0; Sync(); } -void Mapper151_Init(CartInfo *info) { - info->Power = M151Power; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); +void Mapper046_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, TRUE); + info->Power = M046Power; + info->Reset = M046Reset; + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper047.c b/src/mappers/mapper047.c new file mode 100644 index 000000000..850423ac0 --- /dev/null +++ b/src/mappers/mapper047.c @@ -0,0 +1,64 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 reg; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; + +static void M047PW(uint32 A, uint8 V) { + setprg8(A, (reg << 4) | (V & 0x0F)); +} + +static void M047CW(uint32 A, uint8 V) { + setchr1(A, (reg << 7) | (V & 0x7F)); +} + +static DECLFW(M047Write) { + if (MMC3_WramIsWritable()) { + reg = V; + MMC3_FixPRG(); + MMC3_FixCHR(); + } +} + +static void M047Reset(void) { + MMC3_Reset(); +} + +static void M047Power(void) { + reg = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M047Write); +} + +void Mapper047_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_pwrap = M047PW; + MMC3_cwrap = M047CW; + info->Power = M047Power; + info->Reset = M047Reset; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper048.c b/src/mappers/mapper048.c new file mode 100644 index 000000000..3467c5121 --- /dev/null +++ b/src/mappers/mapper048.c @@ -0,0 +1,120 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* iNES Mapper 48 - Taito TC0690/TC190+PAL16R4 */ + +#include "mapinc.h" + +static uint8 prg[2], chr[6], mirr; +static uint8 IRQa; +static int16 IRQCount, IRQLatch; + +static SFORMAT StateRegs[] = { + { prg, 2, "PREG" }, + { chr, 6, "CREG" }, + { &mirr, 1, "MIRR" }, + { &IRQCount, 2, "IRQC" }, + { &IRQLatch, 2, "IRQL" }, + { &IRQa, 1, "IRQA" }, + { 0 } +}; + +static void Sync(void) { + setprg8(0x8000, prg[0]); + setprg8(0xA000, prg[1]); + setprg16(0xC000, ~0); + + setchr2(0x0000, chr[0]); + setchr2(0x0800, chr[1]); + setchr1(0x1000, chr[2]); + setchr1(0x1400, chr[3]); + setchr1(0x1800, chr[4]); + setchr1(0x1C00, chr[5]); + + setmirror(((mirr >> 6) & 0x01) ^ 0x01); +} + +static DECLFW(M048Write) { + switch (A & 0xE003) { + case 0x8000: + case 0x8001: + prg[A & 0x01] = V; + Sync(); + break; + case 0x8002: + case 0x8003: + chr[A & 0x01] = V; + Sync(); + break; + case 0xA000: + case 0xA001: + case 0xA002: + case 0xA003: + chr[2 + (A & 0x03)] = V; + Sync(); + break; + case 0xC000: + IRQLatch = V; + break; + case 0xC001: + IRQCount = IRQLatch; + break; + case 0xC002: + IRQa = TRUE; + break; + case 0xC003: + IRQa = FALSE; + X6502_IRQEnd(FCEU_IQEXT); + break; + case 0xE000: + mirr = V; + Sync(); + break; + } +} + +static void M048Power(void) { + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M048Write); +} + +static void IRQHook(void) { + if (IRQa) { + IRQCount++; + if (IRQCount == 0x100) { + X6502_IRQBegin(FCEU_IQEXT); + IRQa = 0; + } + } +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper048_Init(CartInfo *info) { + info->Power = M048Power; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + GameHBIRQHook = IRQHook; +} + diff --git a/src/mappers/mapper049.c b/src/mappers/mapper049.c new file mode 100644 index 000000000..0734e20ff --- /dev/null +++ b/src/mappers/mapper049.c @@ -0,0 +1,72 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* iNES Mapper 49 */ +/* BMC-STREETFIGTER-GAME4IN1 - Sic. $6000 set to $41 rather than $00 on power-up. */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 reg; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; + +static void M049PW(uint32 A, uint8 V) { + if (reg & 0x01) { + setprg8(A, ((reg >> 2) & ~0x0F) | (V & 0x0F)); + } else { + setprg32(0x8000, (reg >> 4) & 0x03); + } +} + +static void M049CW(uint32 A, uint8 V) { + setchr1(A, ((reg << 1) & 0x180) | (V & 0x7F)); +} + +static DECLFW(M049Write) { + if (MMC3_WramIsWritable()) { + reg = V; + MMC3_FixPRG(); + MMC3_FixCHR(); + } +} + +static void M049Reset(void) { + reg = ((iNESCart.submapper == 1) || (iNESCart.PRGCRC32 == 0x408EA235)) ? 0x41 : 0x00; /* Street Fighter II Game 4-in-1 */ + MMC3_Reset(); +} + +static void M049Power(void) { + reg = ((iNESCart.submapper == 1) || (iNESCart.PRGCRC32 == 0x408EA235)) ? 0x41 : 0x00; /* Street Fighter II Game 4-in-1 */ + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M049Write); +} + +void Mapper049_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_cwrap = M049CW; + MMC3_pwrap = M049PW; + info->Reset = M049Reset; + info->Power = M049Power; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/mapper050.c b/src/mappers/mapper050.c similarity index 60% rename from src/boards/mapper050.c rename to src/mappers/mapper050.c index a35850b4f..68cbb6aa1 100644 --- a/src/boards/mapper050.c +++ b/src/mappers/mapper050.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) 2023-2024 negativeExponent * * 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 @@ -26,8 +27,7 @@ static uint8 reg; static uint32 IRQCount, IRQa; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { &IRQCount, 4, "IRQC" }, { &IRQa, 4, "IRQA" }, { ®, 1, "REG" }, @@ -35,44 +35,44 @@ static SFORMAT StateRegs[] = }; static void Sync(void) { - setprg8(0x6000, 0xF); - setprg8(0x8000, 0x8); - setprg8(0xa000, 0x9); - setprg8(0xc000, reg); - setprg8(0xe000, 0xB); + uint8 prg = ((reg & 0x01) << 2) | ((reg & 0x02) >> 1) | ((reg & 0x04) >> 1) | (reg & 0x08); + + setprg8(0x6000, 15); + setprg8(0x8000, 8); + setprg8(0xA000, 9); + setprg8(0xC000, prg); + setprg8(0xE000, 11); setchr8(0); } -static DECLFW(M50Write) { +static DECLFW(M050Write) { switch (A & 0xD160) { - case 0x4120: - IRQa = V & 1; - if (!IRQa) - IRQCount = 0; + case 0x4120: + IRQa = V & 0x01; + if (!IRQa) { + IRQCount = 0; X6502_IRQEnd(FCEU_IQEXT); - break; - case 0x4020: - reg = ((V & 1) << 2) | ((V & 2) >> 1) | ((V & 4) >> 1) | (V & 8); - Sync(); - break; + } + break; + case 0x4020: + reg = V; + Sync(); + break; } } -static void M50Power(void) { +static void M050Power(void) { reg = 0; + IRQa = IRQCount = 0; Sync(); - SetReadHandler(0x6000, 0xffff, CartBR); - SetWriteHandler(0x4020, 0x5fff, M50Write); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x4020, 0x4FFF, M050Write); } -static void M50Reset(void) { } - -static void FP_FASTAPASS(1) M50IRQHook(int a) { +static void M050IRQHook(int a) { if (IRQa) { - if (IRQCount < 4096) - IRQCount += a; - else { - IRQa = 0; + IRQCount += a; + if (IRQCount & 0x1000) { X6502_IRQBegin(FCEU_IQEXT); } } @@ -82,10 +82,9 @@ static void StateRestore(int version) { Sync(); } -void Mapper50_Init(CartInfo *info) { - info->Reset = M50Reset; - info->Power = M50Power; - MapIRQHook = M50IRQHook; +void Mapper050_Init(CartInfo *info) { + info->Power = M050Power; + MapIRQHook = M050IRQHook; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper051.c b/src/mappers/mapper051.c similarity index 55% rename from src/boards/mapper051.c rename to src/mappers/mapper051.c index 2c97a3aaf..e991195a7 100644 --- a/src/boards/mapper051.c +++ b/src/mappers/mapper051.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) 2023-2024 negativeExponent * * 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 @@ -20,56 +21,58 @@ #include "mapinc.h" -static uint8 bank, mode, submapper; -static SFORMAT StateRegs[] = -{ - { &bank, 1, "BANK" }, +static uint8 prg, mode; + +static SFORMAT StateRegs[] = { + { &prg, 1, "PREG" }, { &mode, 1, "MODE" }, { 0 } }; static void Sync(void) { - if (submapper == 1) { - setprg8(0x6000, (bank << 1) | 0x23); - if (mode & 2) - setprg32(0x8000, bank >> 1); + if (iNESCart.submapper == 1) { + setprg8(0x6000, (prg << 1) | 0x23); + if (mode & 0x022) + setprg32(0x8000, prg >> 1); else { - setprg16(0x8000, ((bank >> 2) & 0x10) | ((bank >> 1) & 0x08) | (bank & 7)); - setprg16(0xC000, ((bank >> 2) & 0x10) | ((bank >> 1) & 0x08) | 7); + setprg16(0x8000, ((prg >> 2) & 0x10) | ((prg >> 1) & 0x08) | (prg & 0x07)); + setprg16(0xC000, ((prg >> 2) & 0x10) | ((prg >> 1) & 0x08) | 0x07); } - } else if (mode & 2) { - setprg8(0x6000, ((bank << 2) & 0x1C) | 0x23); - setprg32(0x8000, bank); } else { - setprg8(0x6000, ((bank << 2) & 0x10) | 0x2F); - setprg16(0x8000, (bank << 1) | (bank >> 4)); - setprg16(0xC000, (bank << 1) | 7); + if (mode & 0x02) { + setprg8(0x6000, ((prg << 2) & 0x1C) | 0x23); + setprg32(0x8000, prg); + } else { + setprg8(0x6000, ((prg << 2) & 0x10) | 0x2F); + setprg16(0x8000, (prg << 1) | (prg >> 4)); + setprg16(0xC000, (prg << 1) | 0x07); + } } setchr8(0); setmirror(((mode >> 4) & 1) ^ 1); } -static DECLFW(M51WriteMode) { +static DECLFW(M051WriteMode) { mode = V; Sync(); } -static DECLFW(M51WriteBank) { - bank = V; +static DECLFW(M051WriteBank) { + prg = V; Sync(); } -static void M51Power(void) { - bank = 0; +static void M051Power(void) { + prg = 0; mode = 2; Sync(); - SetWriteHandler(0x6000, 0x7FFF, M51WriteMode); - SetWriteHandler(0x8000, 0xFFFF, M51WriteBank); + SetWriteHandler(0x6000, 0x7FFF, M051WriteMode); + SetWriteHandler(0x8000, 0xFFFF, M051WriteBank); SetReadHandler(0x6000, 0xFFFF, CartBR); } -static void M51Reset(void) { - bank = 0; +static void M051Reset(void) { + prg = 0; mode = 2; Sync(); } @@ -78,13 +81,13 @@ static void StateRestore(int version) { Sync(); } -void Mapper51_Init(CartInfo *info) { - info->Power = M51Power; - info->Reset = M51Reset; - AddExState(&StateRegs, ~0, 0, 0); +void Mapper051_Init(CartInfo *info) { + info->Power = M051Power; + info->Reset = M051Reset; + AddExState(StateRegs, ~0, 0, NULL); GameStateRestore = StateRestore; - submapper = info->submapper; - if (!UNIFchrrama && (VROM_size == 1)) { + + if (!UNIFchrrama && (ROM.chr.size == 1)) { /* at least 1 variant has 8K CHR-ROM which should be treated as CHR-RAM */ SetupCartCHRMapping(0, CHRptr[0], CHRsize[0], 1); AddExState(CHRptr[0], CHRsize[0], 0, "CHRR"); diff --git a/src/mappers/mapper052.c b/src/mappers/mapper052.c new file mode 100644 index 000000000..6ae51d455 --- /dev/null +++ b/src/mappers/mapper052.c @@ -0,0 +1,118 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* Submapper 13/14 - CHR-ROM + CHR-RAM */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 reg; + +static uint8 *CHRRAM = NULL; +static uint32 CHRRAMSIZE; + +static void M052PW(uint32 A, uint8 V) { + uint8 mask = (reg & 0x08) ? 0x0F : 0x1F; + uint8 base = (reg << 4) & 0x70; + + setprg8(A, (base & ~mask) | (V & mask)); +} + +static void M052CW(uint32 A, uint8 V) { + uint8 chrram = ((iNESCart.submapper == 13) && ((reg & 0x03) == 0x03)) || + ((iNESCart.submapper == 14) && (reg & 0x20)); + + if (chrram) { + setchr8r(0x10, 0); + } else { + uint16 mask = (reg & 0x40) ? 0x7F : 0xFF; + uint16 base = (((reg << 3) & 0x180) | ((reg << 7) & 0x200)); + + if (iNESCart.CRC32 == 0x68FE207F) { + /* Mario 7-in-1 (YH-705) with wrong bank order */ + base = ((reg & 0x20) << 4) | ((reg & 0x04) << 6) | + (reg & 0x40 ? (reg & 0x10) << 3 : 0x00); + } else if (iNESCart.submapper == 14) { + /* Well 8-in-1 (AB128) (Unl) (p1) */ + base = ((reg << 3) & 0x080) | ((reg << 7) & 0x300); + } + + setchr1(A, (base & ~mask) | (V & mask)); + } +} + +static DECLFW(M052Write) { + if (MMC3_WramIsWritable()) { + if (!(reg & 0x80)) { + reg = V; + MMC3_FixPRG(); + MMC3_FixCHR(); + } else { + CartBW(A, V); + } + } +} + +static void M052Close(void) { + MMC3_Close(); + if (CHRRAM) { + FCEU_free(CHRRAM); + CHRRAM = NULL; + } +} + +static void M052Reset(void) { + reg = 0; + MMC3_Reset(); +} + +static void M052Power(void) { + reg = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M052Write); +} + +void Mapper052_Init(CartInfo *info) { + uint8 ws = info->iNES2 ? (info->PRGRamSize + info->PRGRamSaveSize) / 1024 : 8; + + MMC3_Init(info, ws, info->battery); + MMC3_cwrap = M052CW; + MMC3_pwrap = M052PW; + + info->Reset = M052Reset; + info->Power = M052Power; + info->Close = M052Close; + AddExState(®, 1, 0, "EXPR"); + + if (info->CRC32 == 0xA874E216 && info->submapper != 13) { + info->submapper = 13; /* (YH-430) 97-98 Four-in-One */ + } else if (info->CRC32 == 0xCCE8CA2F && info->submapper != 14) { + /* Well 8-in-1 (AB128) (Unl) (p1), with 1024 PRG and CHR is incompatible with submapper 13. + * This is reassigned to submapper 14 instead. */ + info->submapper = 14; + } + + if ((info->submapper == 13) || (info->submapper == 14)) { + CHRRAMSIZE = info->CHRRamSize ? info->CHRRamSize : 8192; + CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CRAM"); + } +} diff --git a/src/boards/supervision.c b/src/mappers/mapper053.c similarity index 50% rename from src/boards/supervision.c rename to src/mappers/mapper053.c index 43b67f5a3..56b36dbb2 100644 --- a/src/boards/supervision.c +++ b/src/mappers/mapper053.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2002 Xodnizel + * Copyright (C) 2023-2024 negativeExponent * * 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,59 +19,61 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +/* Mapper 053 - BMC-Supervision16in1 */ + #include "mapinc.h" -static uint8 cmd0, cmd1; -static SFORMAT StateRegs[] = -{ - { &cmd0, 1, "L1" }, - { &cmd1, 1, "L2" }, +static uint8 reg[2]; + +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, { 0 } }; static void Sync(void) { - setchr8(0); - setprg8(0x6000, (((cmd0 & 0xF) << 4) | 0xF) + 4); - if (cmd0 & 0x10) { - setprg16(0x8000, (((cmd0 & 0xF) << 3) | (cmd1 & 7)) + 2); - setprg16(0xc000, (((cmd0 & 0xF) << 3) | 7) + 2); - } else + setprg8(0x6000, 0x04 + (((reg[0] & 0x0F) << 4) | 0x0F)); + if (reg[0] & 0x10) { + setprg16(0x8000, 0x02 + (((reg[0] & 0x0F) << 3) | (reg[1] & 0x07))); + setprg16(0xc000, 0x02 + (((reg[0] & 0x0F) << 3) | 0x07)); + } else { setprg32(0x8000, 0); - setmirror(((cmd0 & 0x20) >> 5) ^ 1); + } + setchr8(0); + setmirror(((reg[0] & 0x20) >> 5) ^ 0x01); } -static DECLFW(SuperWriteLo) { - if (!(cmd0 & 0x10)) { - cmd0 = V; +static DECLFW(M053Write6) { + if (!(reg[0] & 0x10)) { + reg[0] = V; Sync(); } } -static DECLFW(SuperWriteHi) { - cmd1 = V; +static DECLFW(M053Write8) { + reg[1] = V; Sync(); } -static void SuperPower(void) { - SetWriteHandler(0x6000, 0x7FFF, SuperWriteLo); - SetWriteHandler(0x8000, 0xFFFF, SuperWriteHi); +static void M053Power(void) { + SetWriteHandler(0x6000, 0x7FFF, M053Write6); + SetWriteHandler(0x8000, 0xFFFF, M053Write8); SetReadHandler(0x6000, 0xFFFF, CartBR); - cmd0 = cmd1 = 0; + reg[0] = reg[1] = 0; Sync(); } -static void SuperReset(void) { - cmd0 = cmd1 = 0; +static void M053Reset(void) { + reg[0] = reg[1] = 0; Sync(); } -static void SuperRestore(int version) { +static void StateRestore(int version) { Sync(); } -void Supervision16_Init(CartInfo *info) { - info->Power = SuperPower; - info->Reset = SuperReset; - GameStateRestore = SuperRestore; - AddExState(&StateRegs, ~0, 0, 0); +void Mapper053_Init(CartInfo *info) { + info->Power = M053Power; + info->Reset = M053Reset; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/malee.c b/src/mappers/mapper055.c similarity index 69% rename from src/boards/malee.c rename to src/mappers/mapper055.c index 6d03417ba..3b5c877f8 100644 --- a/src/boards/malee.c +++ b/src/mappers/mapper055.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2002 Xodnizel + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -17,28 +18,35 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + * Mapper 55 - UNL-MARIO1-M0552 * FDS Conversion * */ #include "mapinc.h" -static uint8 WRAM[2048]; - -static void MALEEPower(void) { - setprg2r(0x10, 0x7000, 0); +static void M055Power(void) { SetReadHandler(0x8000, 0xFFFF, CartBR); SetReadHandler(0x6000, 0x67FF, CartBR); SetReadHandler(0x7000, 0x77FF, CartBR); SetWriteHandler(0x7000, 0x77FF, CartBW); + setprg2(0x6000, 16); + setprg2r(0x10, 0x7000, 0); setprg32(0x8000, 0); setchr8(0); } -void MALEE_Init(CartInfo *info) { - info->Power = MALEEPower; - FCEU_MemoryRand(WRAM, sizeof(WRAM)); - SetupCartPRGMapping(0x10, WRAM, 2048, 1); - AddExState(WRAM, 2048, 0, "WRAM"); +void Mapper055_Init(CartInfo *info) { + info->Power = M055Power; + if (info->iNES2) { + WRAMSIZE = info->PRGRamSize + info->PRGRamSaveSize; + } else if (info->battery) { + WRAMSIZE = 2048; + } + if (WRAMSIZE) { + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + } } diff --git a/src/mappers/mapper056.c b/src/mappers/mapper056.c new file mode 100644 index 000000000..703a9823c --- /dev/null +++ b/src/mappers/mapper056.c @@ -0,0 +1,94 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 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" + #include "ks202.h" + +static uint8 prg[4]; +static uint8 chr[8]; +static uint8 mirr; + +static SFORMAT M056StateRegs[] = { + { prg, 8, "PREG" }, + { chr, 8, "CREG" }, + { &mirr, 1, "MIRR" }, + { 0 } +}; + +static void Sync(void) { + setprg8r(0x10, 0x6000, 0); + + setprg8(0x8000, (prg[0] & 0x10) | (ks202.reg[1] & 0x0F)); + setprg8(0xA000, (prg[1] & 0x10) | (ks202.reg[2] & 0x0F)); + setprg8(0xC000, (prg[2] & 0x10) | (ks202.reg[3] & 0x0F)); + setprg8(0xE000, (prg[3] & 0x10) | ( ~0 & 0x0F)); + + setchr1(0x0000, chr[0]); + setchr1(0x0400, chr[1]); + setchr1(0x0800, chr[2]); + setchr1(0x0C00, chr[3]); + setchr1(0x1000, chr[4]); + setchr1(0x1400, chr[5]); + setchr1(0x1800, chr[6]); + setchr1(0x1C00, chr[7]); + + setmirror(mirr & 1); +} + +static DECLFW(M056Write) { + switch (A & 0xC00) { + case 0x000: prg[A & 0x03] = V; break; + case 0x800: mirr = V; break; + case 0xC00: chr[A & 0x07] = V; break; + } + ks202.reg[ks202.cmd & 0x07] = V; + Sync(); +} + +static void M056Reset(void) { + prg[0] = prg[1] = prg[2] = prg[3] = 0x10; + chr[0] = chr[1] = chr[2] = chr[3] = 0; + chr[4] = chr[5] = chr[6] = chr[7] = 0; + mirr = 0; + Sync(); +} + +static void M056Power(void) { + prg[0] = prg[1] = prg[2] = prg[3] = 0x10; + chr[0] = chr[1] = chr[2] = chr[3] = 0; + chr[4] = chr[5] = chr[6] = chr[7] = 0; + mirr = 0; + KS202_Power(); + SetWriteHandler(0xF000, 0xFFFF, M056Write); +} + +void Mapper056_Init(CartInfo *info) { + KS202_Init(info, Sync, 1, 0); + info->Power = M056Power; + info->Reset = M056Reset; + AddExState(&M056StateRegs, ~0, 0, 0); +} diff --git a/src/boards/mapper057.c b/src/mappers/mapper057.c similarity index 50% rename from src/boards/mapper057.c rename to src/mappers/mapper057.c index 8651a8346..b4af8b52c 100644 --- a/src/boards/mapper057.c +++ b/src/mappers/mapper057.c @@ -1,8 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,60 +22,59 @@ #include "mapinc.h" -static uint8 regs[2]; -static uint8 hrd_flag; +static uint8 reg[2]; +static uint8 dipsw; -static SFORMAT StateRegs[] = -{ - { &hrd_flag, 1, "DPSW" }, - { regs, 2, "REGS" }, +static SFORMAT StateRegs[] = { + { &dipsw, 1, "DPSW" }, + { reg, 2, "REGS" }, { 0 } }; static void Sync(void) { - uint8 prg = (regs[1] >> 5) & 7; - uint8 outer_chr = ((regs[0] >> 3) & 8) | (regs[1] & 7); - if (regs[1] & 0x10) { + uint8 prg = (reg[1] >> 5) & 0x07; + uint8 chr = ((reg[0] >> 3) & 0x08) | (reg[1] & 0x07); + + if (reg[1] & 0x10) { setprg32(0x8000, prg >> 1); } else { setprg16(0x8000, prg); setprg16(0xC000, prg); } - if (regs[0] & 0x80) { - setchr8(outer_chr); + if (reg[0] & 0x80) { + setchr8(chr); } else { - setchr8((outer_chr & ~3) | (regs[0] & 3)); + setchr8((chr & ~0x03) | (reg[0] & 0x03)); } - setmirror(((regs[1] >> 3) & 1) ^ 1); + setmirror(((reg[1] >> 3) & 0x01) ^ 0x01); } -static DECLFR(M57Read) { - return hrd_flag; +static DECLFR(M057Read) { + return dipsw & 0x03; } -static DECLFW(M57Write) { +static DECLFW(M057Write) { if (A & 0x2000) { - regs[(A >> 11) & 1] = (regs[(A >> 11) & 1] & ~0x40) | (V & 0x40); + reg[(A >> 11) & 0x01] = (reg[(A >> 11) & 0x01] & ~0x40) | (V & 0x40); } else { - regs[(A >> 11) & 1] = V; + reg[(A >> 11) & 0x01] = V; } Sync(); } -static void M57Power(void) { - regs[1] = regs[0] = 0; /* Always reset to menu */ - hrd_flag = 1; /* YH-xxx "Olympic" multicarts disable the menu after one selection */ +static void M057Power(void) { + reg[1] = reg[0] = 0; /* Always reset to menu */ + dipsw = 1; /* YH-xxx "Olympic" multicarts disable the menu after one selection */ + SetReadHandler(0x5000, 0x6FFF, M057Read); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, M57Write); - SetReadHandler(0x6000, 0x6000, M57Read); + SetWriteHandler(0x8000, 0xFFFF, M057Write); Sync(); } -static void M57Reset(void) { - regs[1] = regs[0] = 0; /* Always reset to menu */ - hrd_flag++; - hrd_flag &= 3; - FCEU_printf("Select Register = %02x\n", hrd_flag); +static void M057Reset(void) { + reg[1] = reg[0] = 0; /* Always reset to menu */ + dipsw++; + FCEU_printf("Select Register = %02x\n", dipsw); Sync(); } @@ -83,9 +82,9 @@ static void StateRestore(int version) { Sync(); } -void Mapper57_Init(CartInfo *info) { - info->Power = M57Power; - info->Reset = M57Reset; +void Mapper057_Init(CartInfo *info) { + info->Power = M057Power; + info->Reset = M057Reset; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper058.c b/src/mappers/mapper058.c new file mode 100644 index 000000000..5bbf20b66 --- /dev/null +++ b/src/mappers/mapper058.c @@ -0,0 +1,39 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + if (latch.addr & 0x40) { + setprg16(0x8000, latch.addr & 0x07); + setprg16(0xC000, latch.addr & 0x07); + } else { + setprg32(0x8000, (latch.addr >> 1) & 0x03); + } + setchr8((latch.addr >> 3) & 0x07); + setmirror(((latch.addr & 0x80) >> 7) ^ 0x01); +} + +void Mapper058_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Reset = Latch_RegReset; +} diff --git a/src/mappers/mapper059.c b/src/mappers/mapper059.c new file mode 100644 index 000000000..d5e6961f8 --- /dev/null +++ b/src/mappers/mapper059.c @@ -0,0 +1,73 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + */ + +/* iNES Mapper 59 - BMCD1038 */ + +#include "mapinc.h" +#include "latch.h" + +static uint8 dipsw; + +static void Sync(void) { + if (latch.addr & 0x80) { + setprg16(0x8000, (latch.addr & 0x70) >> 4); + setprg16(0xC000, (latch.addr & 0x70) >> 4); + } else { + setprg32(0x8000, (latch.addr & 0x60) >> 5); + } + setchr8(latch.addr & 0x07); + setmirror(((latch.addr & 0x08) >> 3) ^ 0x01); +} + +static DECLFR(M059Read) { + if (latch.addr & 0x100) { + return (cpu.openbus & ~0x03) | (dipsw & 0x03); + } + return CartBR(A); +} + +static DECLFW(M059Write) { + /* Only recognize the latch write if the lock bit has not been set. */ + /* Needed for NT-234 "Road Fighter" */ + if (!(latch.addr & 0x200)) { + Latch_Write(A, V); + } +} + +static void M059Reset(void) { + dipsw++; + /* Always reset to menu */ + latch.addr = 0; + Sync(); +} + +static void M059Power(void) { + Latch_Power(); + /* Trap latch writes to enforce the "Lock" bit */ + SetWriteHandler(0x8000, 0xFFFF, M059Write); +} + +void Mapper059_Init(CartInfo *info) { + Latch_Init(info, Sync, M059Read, FALSE, FALSE); + info->Reset = M059Reset; + info->Power = M059Power; + AddExState(&dipsw, 1, 0, "DIPSW"); +} diff --git a/src/boards/mapper060.c b/src/mappers/mapper060.c similarity index 82% rename from src/boards/mapper060.c rename to src/mappers/mapper060.c index bd5483606..12ea59722 100644 --- a/src/boards/mapper060.c +++ b/src/mappers/mapper060.c @@ -1,7 +1,8 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 + * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -28,25 +29,24 @@ static void Sync(void) { setprg16(0xC000, game); } -static void M60Reset(void) { - game = (game + 1) & 3; +static void M060Reset(void) { + game++; Sync(); } -static void M60Power(void) { +static void M060Power(void) { game = 0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, CartBW); } static void StateRestore(int version) { Sync(); } -void Mapper60_Init(CartInfo *info) { - info->Power = M60Power; - info->Reset = M60Reset; +void Mapper060_Init(CartInfo *info) { + info->Power = M060Power; + info->Reset = M060Reset; GameStateRestore = StateRestore; AddExState(&game, 1, 0, "GAME"); -} \ No newline at end of file +} diff --git a/src/mappers/mapper061.c b/src/mappers/mapper061.c new file mode 100644 index 000000000..e1b2994b0 --- /dev/null +++ b/src/mappers/mapper061.c @@ -0,0 +1,39 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + if (latch.addr & 0x10) { + setprg16(0x8000, ((latch.addr & 0x0F) << 1) | ((latch.addr & 0x20) >> 5)); + setprg16(0xC000, ((latch.addr & 0x0F) << 1) | ((latch.addr & 0x20) >> 5)); + } else { + setprg32(0x8000, latch.addr & 0x0F); + } + setchr8(latch.addr >> 8 & 0x0F); + setmirror(((latch.addr >> 7) & 0x01) ^ 0x01); +} + +void Mapper061_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Reset = Latch_RegReset; +} diff --git a/src/mappers/mapper062.c b/src/mappers/mapper062.c new file mode 100644 index 000000000..5e7e4d305 --- /dev/null +++ b/src/mappers/mapper062.c @@ -0,0 +1,41 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + uint8 prg = (latch.addr & 0x40) | ((latch.addr >> 8) & 0x3F); + + if (latch.addr & 0x20) { + setprg16(0x8000, prg); + setprg16(0xC000, prg); + } else { + setprg32(0x8000, prg >> 1); + } + setchr8(((latch.addr & 0x1F) << 2) | (latch.data & 0x03)); + setmirror(((latch.addr >> 7) & 1) ^ 1); +} + +void Mapper062_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Reset = Latch_RegReset; +} diff --git a/src/mappers/mapper063.c b/src/mappers/mapper063.c new file mode 100644 index 000000000..56c58b290 --- /dev/null +++ b/src/mappers/mapper063.c @@ -0,0 +1,64 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 63 NTDEC-Multicart + * http://wiki.nesdev.com/w/index.php/INES_Mapper_063 + * - Powerful 250-in-1 + * - Hello Kitty 255-in-1 */ + +#include "mapinc.h" +#include "latch.h" + +static uint16 openBus = 0; + +static void Sync(void) { + uint8 prg_mask = (iNESCart.submapper == 0) ? 0xFF : 0x7F; + uint8 prg_bank = (latch.addr >> 2) & prg_mask; + uint8 chr_protect = (latch.addr & ((iNESCart.submapper == 0) ? 0x400 : 0x200)) == 0; + + /* return openbus for unpopulated rom banks */ + openBus = prg_bank >= ROM.prg.size; + + if (latch.addr & 2) { + setprg32(0x8000, prg_bank >> 1); + } else { + setprg16(0x8000, prg_bank); + setprg16(0xC000, prg_bank); + } + + setchr8(0); + setmirror((latch.addr & 1) ^ 1); + + /* chr-ram protect */ + SetupCartCHRMapping(0, CHRptr[0], 0x2000, chr_protect); +} + +static DECLFR(M063Read) { + if (openBus) { + return cpu.openbus; + } + return CartBR(A); +} + +void Mapper063_Init(CartInfo *info) { + Latch_Init(info, Sync, M063Read, FALSE, FALSE); + info->Reset = Latch_RegReset; +} diff --git a/src/mappers/mapper064.c b/src/mappers/mapper064.c new file mode 100644 index 000000000..fd05dc8c9 --- /dev/null +++ b/src/mappers/mapper064.c @@ -0,0 +1,183 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * Copyright (C) 2023-2024 negativeExponent + * + * 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 64 - Tengen 800032 Rambo-1 + * Mapper 158 - Tengen 800037 (Alien Syndrome Unl) +*/ + +#include "mapinc.h" + +static uint8 cmd, mirr, reg[16]; +static uint8 IRQReload, IRQmode, IRQCount, IRQa, IRQLatch; +static uint8 IRQPrescaler; + +static SFORMAT StateRegs[] = { + { reg, 16, "REGS" }, + { &cmd, 1, "CMDR" }, + { &mirr, 1, "MIRR" }, + { &IRQReload, 1, "IRQR" }, + { &IRQmode, 1, "IRQM" }, + { &IRQCount, 1, "IRQC" }, + { &IRQa, 1, "IRQA" }, + { &IRQLatch, 1, "IRQL" }, + { &IRQPrescaler, 1, "IRQP" }, + { 0 } +}; + +static void Sync(void) { + /* + 0000: R0: Select 2 (K=0) or 1 (K=1) KiB CHR bank at PPU $0000 (or $1000) + 0001: R1: Select 2 (K=0) or 1 (K=1) KiB CHR bank at PPU $0800 (or $1800) + 0010: R2: Select 1 KiB CHR bank at PPU $1000-$13FF (or $0000-$03FF) + 0011: R3: Select 1 KiB CHR bank at PPU $1400-$17FF (or $0400-$07FF) + 0100: R4: Select 1 KiB CHR bank at PPU $1800-$1BFF (or $0800-$0BFF) + 0101: R5: Select 1 KiB CHR bank at PPU $1C00-$1FFF (or $0C00-$0FFF) + 0110: R6: Select 8 KiB PRG ROM bank at $8000-$9FFF (or $C000-$DFFF) + 0111: R7: Select 8 KiB PRG ROM bank at $A000-$BFFF + 1000: R8: If K=1, Select 1 KiB CHR bank at PPU $0400 (or $1400) + 1001: R9: If K=1, Select 1 KiB CHR bank at PPU $0C00 (or $1C00) + 1111: RF: Select 8 KiB PRG ROM bank at $C000-$DFFF (or $8000-$9FFF) + */ + setprg8(0x8000, reg[6]); + setprg8(0xA000, reg[7]); + setprg8(0xC000, reg[15]); + setprg8(0xE000, ~0); + + if (cmd & 0x20) { + setchr1(0x0000, reg[0]); + setchr1(0x0400, reg[8]); + setchr1(0x0800, reg[1]); + setchr1(0x0C00, reg[9]); + } else { + setchr1(0x0000, (reg[0] & 0xFE)); + setchr1(0x0400, (reg[0] & 0xFE) | 1); + setchr1(0x0800, (reg[1] & 0xFE)); + setchr1(0x0C00, (reg[1] & 0xFE) | 1); + } + + setchr1(0x1000, reg[2]); + setchr1(0x1400, reg[3]); + setchr1(0x1800, reg[4]); + setchr1(0x1C00, reg[5]); + + if (iNESCart.mapper == 158) { + if (cmd & 0x20) { + setntamem(NTARAM + ((reg[0] >> 7) << 10), 1, 0); + setntamem(NTARAM + ((reg[8] >> 7) << 10), 1, 1); + setntamem(NTARAM + ((reg[1] >> 7) << 10), 1, 2); + setntamem(NTARAM + ((reg[9] >> 7) << 10), 1, 3); + } else { + setntamem(NTARAM + ((reg[0] >> 7) << 10), 1, 0); + setntamem(NTARAM + ((reg[0] >> 7) << 10), 1, 1); + setntamem(NTARAM + ((reg[1] >> 7) << 10), 1, 2); + setntamem(NTARAM + ((reg[1] >> 7) << 10), 1, 3); + } + } else { + setmirror((mirr & 1) ^ 1); + } +} + +static DECLFW(M064Write) { + switch (A & 0xF001) { + case 0xA000: + mirr = V; + Sync(); + break; + case 0x8000: + cmd = V; + break; + case 0x8001: + reg[cmd & 0x0F] = V; + Sync(); + break; + case 0xC000: + IRQLatch = V; + if (IRQReload) { + IRQCount = IRQLatch; + } + break; + case 0xC001: + IRQReload = TRUE; + IRQCount = IRQLatch; + IRQmode = V & 1; + break; + case 0xE000: + IRQa = FALSE; + X6502_IRQEnd(FCEU_IQEXT); + if (IRQReload) { + IRQCount = IRQLatch; + } + break; + case 0xE001: + IRQa = TRUE; + if (IRQReload) { + IRQCount = IRQLatch; + } + break; + } +} + +static void M064Power(void) { + cmd = mirr = 0; + reg[0] = reg[1] = reg[2] = reg[3] = reg[4] = reg[5] = ~0; + reg[6] = reg[7] = reg[8] = reg[9] = reg[10] = ~0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M064Write); +} + +static void StateRestore(int version) { + Sync(); +} + +static void M064CPUHook(int a) { + static int32 smallcount; + if (IRQmode) { + smallcount += a; + while (smallcount >= 4) { + smallcount -= 4; + IRQCount--; + if (IRQCount == 0xFF) + if (IRQa) X6502_IRQBegin(FCEU_IQEXT); + } + } +} + +static void M064HBHook(void) { + if ((!IRQmode) && (scanline != 240)) { + IRQReload = 0; + IRQCount--; + if (IRQCount == 0xFF) { + if (IRQa) { + IRQReload = 1; + X6502_IRQBegin(FCEU_IQEXT); + } + } + } +} + +void Mapper064_Init(CartInfo *info) { + info->Power = M064Power; + GameHBIRQHook = M064HBHook; + MapIRQHook = M064CPUHook; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper065.c b/src/mappers/mapper065.c new file mode 100644 index 000000000..4ebf8f842 --- /dev/null +++ b/src/mappers/mapper065.c @@ -0,0 +1,153 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 prg[2], chr[8], mirr, cmd; +static uint8 IRQa; +static int16 IRQCount, IRQLatch; + +static SFORMAT StateRegs[] = { + { &cmd, 1, "CMD0" }, + { prg, 2, "PREG" }, + { chr, 8, "CREG" }, + { &mirr, 1, "MIRR" }, + { &IRQa, 1, "IRQA" }, + { &IRQCount, 2, "IRQC" }, + { &IRQLatch, 2, "IRQL" }, + { 0 } +}; + +static void Sync(void) { + if (cmd & 0x80) { + setprg8(0x8000, ~1); + setprg8(0xA000, prg[1]); + setprg8(0xC000, prg[0]); + setprg8(0xE000, ~0); + } else { + setprg8(0x8000, prg[0]); + setprg8(0xA000, prg[1]); + setprg8(0xC000, ~1); + setprg8(0xE000, ~0); + } + + setchr1(0x0000, chr[0]); + setchr1(0x0400, chr[1]); + setchr1(0x0800, chr[2]); + setchr1(0x0C00, chr[3]); + setchr1(0x1000, chr[4]); + setchr1(0x1400, chr[5]); + setchr1(0x1800, chr[6]); + setchr1(0x1C00, chr[7]); + + switch (mirr >> 6) { + case 0: + setmirror(MI_V); + break; + case 2: + setmirror(MI_H); + break; + default: + setmirror(MI_0); + break; + } +} + +static DECLFW(M065Write) { + switch (A & 0xF000) { + case 0x8000: + case 0xA000: + prg[(A >> 13) & 0x01] = V; + Sync(); + break; + case 0x9000: + switch (A & 0x07) { + case 0: + cmd = V; + Sync(); + break; + case 1: + mirr = V; + Sync(); + break; + case 3: + IRQa = V & 0x80; + X6502_IRQEnd(FCEU_IQEXT); + break; + case 4: + IRQCount = IRQLatch; + X6502_IRQEnd(FCEU_IQEXT); + break; + case 5: + IRQLatch &= 0x00FF; + IRQLatch |= V << 8; + break; + case 6: + IRQLatch &= 0xFF00; + IRQLatch |= V; + break; + } + break; + case 0xB000: + chr[A & 0x07] = V; + Sync(); + break; + } +} + +static void M065Power(void) { + prg[0] = 0; + prg[1] = 1; + + chr[0] = 0; + chr[1] = 1; + chr[2] = 2; + chr[3] = 3; + chr[4] = 4; + chr[5] = 5; + chr[6] = 6; + chr[7] = 7; + + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xBFFF, M065Write); +} + +static void M065IRQ(int a) { + if (IRQa) { + IRQCount -= a; + if (IRQCount <= 0) { + X6502_IRQBegin(FCEU_IQEXT); + IRQa = 0; + } + } +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper065_Init(CartInfo *info) { + info->Power = M065Power; + MapIRQHook = M065IRQ; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper066.c b/src/mappers/mapper066.c new file mode 100644 index 000000000..c40f30fed --- /dev/null +++ b/src/mappers/mapper066.c @@ -0,0 +1,32 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg32(0x8000, (latch.data >> 4) & 0x07); + setchr8(latch.data & 0x0F); +} + +void Mapper066_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, TRUE); +} diff --git a/src/mappers/mapper067.c b/src/mappers/mapper067.c new file mode 100644 index 000000000..b852dcfcf --- /dev/null +++ b/src/mappers/mapper067.c @@ -0,0 +1,126 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 prg, chr[4], mirr; +static uint8 IRQa, toggle = 0; +static int16 IRQCount, IRQLatch; + +static SFORMAT StateRegs[] = { + { &prg, 1, "PREG" }, + { &toggle, 1, "TOGL" }, + { chr, 4, "CREG" }, + { &mirr, 1, "MIRR" }, + { &IRQa, 1, "IRQA" }, + { &IRQCount, 2, "IRQC" }, + { &IRQLatch, 2, "IRQL" }, + { 0 } +}; + +static void Sync(void) { + setprg16(0x8000, prg); + setprg16(0xC000, ~0); + + setchr2(0x0000, chr[0]); + setchr2(0x0800, chr[1]); + setchr2(0x1000, chr[2]); + setchr2(0x1800, chr[3]); + + switch (mirr & 0x03) { + case 0: + setmirror(MI_V); + break; + case 1: + setmirror(MI_H); + break; + case 2: + setmirror(MI_0); + break; + case 3: + setmirror(MI_1); + break; + } +} + +static DECLFW(M067Write) { + switch (A & 0xF800) { + case 0x8800: + case 0x9800: + case 0xA800: + case 0xB800: + chr[(A >> 12) & 0x03] = V; + Sync(); + break; + case 0xC000: + case 0xC800: + IRQCount &= 0xFF << (toggle << 3); + IRQCount |= V << ((toggle ^ 1) << 3); + toggle ^= 1; + break; + case 0xD800: + toggle = 0; + IRQa = V & 0x10; + X6502_IRQEnd(FCEU_IQEXT); + break; + case 0xE800: + mirr = V; + Sync(); + break; + case 0xF800: + prg = V; + Sync(); + break; + } +} + +static void M067Power(void) { + prg = 0; + chr[0] = 0; + chr[1] = 1; + chr[2] = 2; + chr[3] = 3; + IRQa = IRQCount = IRQLatch = toggle = 0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M067Write); +} + +static void M067IRQ(int a) { + if (IRQa) { + IRQCount -= a; + if (IRQCount < 0) { + X6502_IRQBegin(FCEU_IQEXT); + IRQa = 0; + } + } +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper067_Init(CartInfo *info) { + info->Power = M067Power; + MapIRQHook = M067IRQ; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper068.c b/src/mappers/mapper068.c new file mode 100644 index 000000000..37a8d62e8 --- /dev/null +++ b/src/mappers/mapper068.c @@ -0,0 +1,150 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2006 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +/* FIXME: needs updating, submapper 1 support etc */ + +static uint8 chr[4]; +static uint8 nt[2]; +static uint8 kogame, prg, mirr; +static uint32 count; + +static SFORMAT StateRegs[] = { + { &mirr, 1, "MIRR" }, + { &prg, 1, "PRG" }, + { &kogame, 1, "KGME" }, + { &count, 4, "CNT" }, + { chr, 4, "CHR" }, + { nt, 2, "NTAR" }, + { 0 } +}; + +static void Sync(void) { + setprg8r(0x10, 0x6000, 0); + setprg16r((PRGptr[1]) ? kogame : 0, 0x8000, prg); + setprg16(0xC000, 0x07); + + setchr2(0x0000, chr[0]); + setchr2(0x0800, chr[1]); + setchr2(0x1000, chr[2]); + setchr2(0x1800, chr[3]); + + if ((!UNIFchrrama) && (mirr & 0x10)) { + int i; + PPUNTARAM = 0; + for (i = 0; i < 4; i++) { + switch (mirr & 0x03) { + case 0: vnapage[i] = CHRptr[0] + (((nt[i & 0x01] | 0x80) & CHRmask1[0]) << 10); break; + case 1: vnapage[i] = CHRptr[0] + (((nt[(i >> 0x01) & 0x01] | 0x80) & CHRmask1[0]) << 10); break; + case 2: vnapage[i] = CHRptr[0] + (((nt[0] | 0x80) & CHRmask1[0]) << 10); break; + case 3: vnapage[i] = CHRptr[0] + (((nt[1] | 0x80) & CHRmask1[0]) << 10); break; + } + } + } else { + switch (mirr & 0x03) { + case 0: setmirror(MI_V); break; + case 1: setmirror(MI_H); break; + case 2: setmirror(MI_0); break; + case 3: setmirror(MI_1); break; + } + } +} + +static DECLFR(M68Read) { + if (!(kogame & 0x08)) { + count++; + if (count == 1784) { + setprg16r(0, 0x8000, prg); + } + } + return CartBR(A); +} + +static DECLFW(M68WriteLo) { + if (!V) { + count = 0; + setprg16r((PRGptr[1]) ? kogame : 0, 0x8000, prg); + } + CartBW(A, V); +} + +static DECLFW(M068Write) { + switch (A & 0xF000) { + case 0x8000: + case 0x9000: + case 0xA000: + case 0xB000: + chr[(A >> 12) & 0x03] = V; + Sync(); + break; + case 0xC000: + case 0xD000: + nt[(A >> 12) & 0x01] = V; + Sync(); + break; + case 0xE000: + mirr = V; + Sync(); + break; + case 0xF000: + prg = V & 0x07; + kogame = ((V >> 3) & 0x01) ^ 0x01; + Sync(); + break; + } +} + +static void M68Power(void) { + prg = 0; + kogame = 0; + Sync(); + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetReadHandler(0x8000, 0xBFFF, M68Read); + SetReadHandler(0xC000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M068Write); + SetWriteHandler(0x6000, 0x6000, M68WriteLo); + SetWriteHandler(0x6001, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); +} + +static void M68Close(void) { +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper068_Init(CartInfo *info) { + info->Power = M68Power; + info->Close = M68Close; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + + WRAMSIZE = 8192; + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } +} diff --git a/src/mappers/mapper069.c b/src/mappers/mapper069.c new file mode 100644 index 000000000..cfc896bc6 --- /dev/null +++ b/src/mappers/mapper069.c @@ -0,0 +1,41 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "s5bsound.h" +#include "fme7.h" + +static void M069PW(uint32 A, uint8 V) { + setprg8(A, V & 0x3F); +} + +static void M069CW(uint32 A, uint8 V) { + setchr1(A, V & 0xFF); +} + +void Mapper069_Init(CartInfo *info) { + FME7_Init(info, TRUE, info->battery); + FME7_pwrap = M069PW; + FME7_cwrap = M069CW; +} + +void NSFS5B_Init(int chip) { + S5BSound_ESI(); +} diff --git a/src/mappers/mapper070.c b/src/mappers/mapper070.c new file mode 100644 index 000000000..d42a50ac4 --- /dev/null +++ b/src/mappers/mapper070.c @@ -0,0 +1,33 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg16(0x8000, latch.data >> 4); + setprg16(0xc000, ~0); + setchr8(latch.data & 0x0F); +} + +void Mapper070_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, TRUE); +} diff --git a/src/boards/mapper071.c b/src/mappers/mapper071.c similarity index 62% rename from src/boards/mapper071.c rename to src/mappers/mapper071.c index 96d48e147..1527dd444 100644 --- a/src/boards/mapper071.c +++ b/src/mappers/mapper071.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) 2023-2024 negativeExponent * * 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 @@ -20,46 +21,54 @@ #include "mapinc.h" -static uint8 preg, mirr; +static uint8 prg, mirr; -static SFORMAT StateRegs[] = -{ - { &preg, 1, "PREG" }, +static SFORMAT StateRegs[] = { + { &prg, 1, "PREG" }, { &mirr, 1, "MIRR" }, { 0 } }; static void Sync(void) { - setprg16(0x8000, preg); + setprg16(0x8000, prg); setprg16(0xC000, ~0); setchr8(0); - if (mirr) + /* Fire Hawk or submapper 1, otherwise hard-mirroring */ + if (mirr) { setmirror(mirr); + } } -static DECLFW(M71Write) { - if ((A & 0xF000) == 0x9000) - mirr = MI_0 + ((V >> 4) & 1); /* 2-in-1, some carts are normal hardwire V/H mirror, some uses mapper selectable 0/1 mirror */ - else - preg = V; - Sync(); +static DECLFW(M071Write) { + switch (A & 0xF000) { + case 0x9000: + mirr = MI_0 + ((V >> 4) & 0x01); + Sync(); + break; + case 0xC000: + case 0xD000: + case 0xE000: + case 0xF000: + prg = V; + Sync(); + break; + } } -static void M71Power(void) { - preg = 0; +static void M071Power(void) { + prg = 0; mirr = 0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, M71Write); + SetWriteHandler(0x9000, 0xFFFF, M071Write); } static void StateRestore(int version) { Sync(); } -void Mapper71_Init(CartInfo *info) { - info->Power = M71Power; +void Mapper071_Init(CartInfo *info) { + info->Power = M071Power; GameStateRestore = StateRestore; - - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper072.c b/src/mappers/mapper072.c new file mode 100644 index 000000000..2ba80e790 --- /dev/null +++ b/src/mappers/mapper072.c @@ -0,0 +1,80 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 72: + * Moero!! Pro Tennis have ADPCM codec on-board, PROM isn't dumped, emulation isn't + * possible just now. + * + * Mapper 092 + * Another two-in-one mapper, two Jaleco carts uses similar + * hardware, but with different wiring. + * Original code provided by LULU + * Additionally, PCB contains DSP extra sound chip, used for voice samples (unemulated) + * This mapper is identical to mapper 072 except for the different PRG Setup. + */ + +#include "mapinc.h" + +static uint8 prg, chr, reg; + +static SFORMAT StateRegs[] = { + { &prg, 1, "PREG" }, + { &chr, 1, "CREG" }, + { ®, 1, "REGS" }, + { 0 } +}; + +static void Sync(void) { + if (iNESCart.mapper == 92) { + setprg16(0x8000, 0); + setprg16(0xC000, prg); + setchr8(chr); + } else { + setprg16(0x8000, prg); + setprg16(0xC000, ~0); + setchr8(chr); + } +} + +static DECLFW(M072Write) { + V &= CartBR(A); /* bus conflict */ + + reg = (reg ^ V) & V; + if (reg & 0x80) prg = V; + if (reg & 0x40) chr = V; + + Sync(); +} + +static void M072Power(void) { + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M072Write); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper072_Init(CartInfo *info) { + info->Power = M072Power; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/vrc3.c b/src/mappers/mapper073.c similarity index 50% rename from src/boards/vrc3.c rename to src/mappers/mapper073.c index 6e32d49a6..7649d9f32 100644 --- a/src/boards/vrc3.c +++ b/src/mappers/mapper073.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) 2023-2024 negativeExponent * * 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 @@ -17,118 +18,114 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * VRC-3 + * Konami VRC-3 * */ #include "mapinc.h" -static uint8 preg; +static uint8 prg; static uint8 IRQx; /* autoenable */ static uint8 IRQm; /* mode */ static uint8 IRQa; -static uint16 IRQReload, IRQCount; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint16 IRQLatch, IRQCount; -static SFORMAT StateRegs[] = -{ - { &preg, 1, "PREG" }, +static SFORMAT StateRegs[] = { + { &prg, 1, "PREG" }, { &IRQa, 1, "IRQA" }, { &IRQx, 1, "IRQX" }, { &IRQm, 1, "IRQM" }, - { &IRQReload, 2, "IRQR" }, + { &IRQLatch, 2, "IRQL" }, { &IRQCount, 2, "IRQC" }, { 0 } }; static void Sync(void) { setprg8r(0x10, 0x6000, 0); - setprg16(0x8000, preg); + setprg16(0x8000, prg); setprg16(0xC000, ~0); setchr8(0); } -static DECLFW(M73Write) { +static DECLFW(M073Write) { switch (A & 0xF000) { - case 0x8000: IRQReload &= 0xFFF0; IRQReload |= (V & 0xF) << 0; break; - case 0x9000: IRQReload &= 0xFF0F; IRQReload |= (V & 0xF) << 4; break; - case 0xA000: IRQReload &= 0xF0FF; IRQReload |= (V & 0xF) << 8; break; - case 0xB000: IRQReload &= 0x0FFF; IRQReload |= (V & 0xF) << 12; break; + case 0x8000: + IRQLatch &= 0xFFF0; + IRQLatch |= (V & 0x0F) << 0; + break; + case 0x9000: + IRQLatch &= 0xFF0F; + IRQLatch |= (V & 0x0F) << 4; + break; + case 0xA000: + IRQLatch &= 0xF0FF; + IRQLatch |= (V & 0x0F) << 8; + break; + case 0xB000: + IRQLatch &= 0x0FFF; + IRQLatch |= (V & 0x0F) << 12; + break; case 0xC000: - IRQm = V & 4; - IRQx = V & 1; - IRQa = V & 2; + IRQm = V & 0x04; + IRQx = V & 0x01; + IRQa = V & 0x02; if (IRQa) { - if (IRQm) { - IRQCount &= 0xFFFF; - IRQCount |= (IRQReload & 0xFF); - } else - IRQCount = IRQReload; + IRQCount = IRQLatch; } X6502_IRQEnd(FCEU_IQEXT); break; - case 0xD000: X6502_IRQEnd(FCEU_IQEXT); IRQa = IRQx; break; - case 0xF000: preg = V; Sync(); break; + case 0xD000: + X6502_IRQEnd(FCEU_IQEXT); + IRQa = IRQx; + break; + case 0xF000: + prg = V; + Sync(); + break; } } -static void M73IRQHook(int a) { +static void M073IRQHook(int a) { int32 i; - if (!IRQa) return; - for (i = 0; i < a; i++) { - if (IRQm) { - uint16 temp = IRQCount; - temp &= 0xFF; - IRQCount &= 0xFF00; - if (temp == 0xFF) { - IRQCount = IRQReload; - IRQCount |= (uint16)(IRQReload & 0xFF); + + if (IRQa) { + for (i = 0; i < a; i++) { + uint32 IRQCountMask = IRQm ? 0xFF : 0xFFFF; + if ((IRQCount & IRQCountMask) == IRQCountMask) { + IRQCount = IRQLatch; X6502_IRQBegin(FCEU_IQEXT); } else { - temp++; - IRQCount |= temp; - } - } else { - /* 16 bit mode */ - if (IRQCount == 0xFFFF) { - IRQCount = IRQReload; - X6502_IRQBegin(FCEU_IQEXT); - } else IRQCount++; + } } } } -static void M73Power(void) { - IRQReload = IRQm = IRQx = 0; +static void M073Power(void) { + IRQLatch = IRQm = IRQx = 0; Sync(); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetWriteHandler(0x8000, 0xFFFF, M73Write); + SetWriteHandler(0x8000, 0xFFFF, M073Write); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } -static void M73Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; +static void M073Close(void) { } static void StateRestore(int version) { Sync(); } -void Mapper73_Init(CartInfo *info) { - info->Power = M73Power; - info->Close = M73Close; - MapIRQHook = M73IRQHook; +void Mapper073_Init(CartInfo *info) { + info->Power = M073Power; + info->Close = M073Close; + MapIRQHook = M073IRQHook; + AddExState(StateRegs, ~0, 0, NULL); + GameStateRestore = StateRestore; WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - - AddExState(&StateRegs, ~0, 0, 0); - GameStateRestore = StateRestore; } diff --git a/src/boards/KS7021A.c b/src/mappers/mapper074.c similarity index 53% rename from src/boards/KS7021A.c rename to src/mappers/mapper074.c index 92d049cb6..60b90f544 100644 --- a/src/boards/KS7021A.c +++ b/src/mappers/mapper074.c @@ -1,8 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2007 CaH4e3 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -19,30 +18,35 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* -------------------- 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. - */ - #include "mapinc.h" -#include "vrc24.h" +#include "mmc3.h" -static DECLFW(KS7021AWrite) { - switch (A & 0xB000) { - case 0xB000: - vrc24.chrreg[A & 0x07] = V; - FixVRC24CHR(); - break; +static uint8 *CHRRAM = NULL; +static uint32 CHRRAMSIZE; + +static void M074CW(uint32 A, uint8 V) { + if ((V & ~0x01) == 0x08) { /* Di 4 Ci - Ji Qi Ren Dai Zhan (As).nes, Ji Jia Zhan Shi (As).nes */ + setchr1r(0x10, A, V & 0x01); + } else { + setchr1(A, V); } } -static void KS7021APower(void) { - GenVRC24Power(); - SetWriteHandler(0xB000, 0xBFFF, KS7021AWrite); +static void M074Close(void) { + MMC3_Close(); + if (CHRRAM) { + FCEU_free(CHRRAM); + CHRRAM = NULL; + } } -void UNLKS7021A_Init(CartInfo *info) { - GenVRC24_Init(info, VRC2b, 1); - info->Power = KS7021APower; +void Mapper074_Init(CartInfo *info) { + MMC3_Init(info, 8, info->battery); + info->Close = M074Close; + MMC3_cwrap = M074CW; + + CHRRAMSIZE = 2048; + CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); } diff --git a/src/boards/vrc1.c b/src/mappers/mapper075.c similarity index 54% rename from src/boards/vrc1.c rename to src/mappers/mapper075.c index eec2d9d34..ab4c318f2 100644 --- a/src/boards/vrc1.c +++ b/src/mappers/mapper075.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) 2023-2024 negativeExponent * * 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 @@ -17,39 +18,52 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * VRC-1 + * Konami VRC-1 * */ #include "mapinc.h" -static uint8 preg[3], creg[2], mode; -static SFORMAT StateRegs[] = -{ +static uint8 prg[3], chr[2], mode; + +static SFORMAT StateRegs[] = { { &mode, 1, "MODE" }, - { creg, 2, "CREG" }, - { preg, 3, "PREG" }, + { chr, 2, "CREG" }, + { prg, 3, "PREG" }, { 0 } }; static void Sync(void) { - setprg8(0x8000, preg[0]); - setprg8(0xA000, preg[1]); - setprg8(0xC000, preg[2]); + setprg8(0x8000, prg[0]); + setprg8(0xA000, prg[1]); + setprg8(0xC000, prg[2]); setprg8(0xE000, ~0); - setchr4(0x0000, creg[0] | ((mode & 2) << 3)); - setchr4(0x1000, creg[1] | ((mode & 4) << 2)); - setmirror((mode & 1) ^ 1); + + setchr4(0x0000, (chr[0] & 0x0F) | ((mode & 2) << 3)); + setchr4(0x1000, (chr[1] & 0x0F) | ((mode & 4) << 2)); + + if (iNESCart.mirror != MI_4) { /* VS rom conversion uses 4-screen mirroring */ + setmirror((mode & 1) ^ 1); + } } static DECLFW(M75Write) { switch (A & 0xF000) { - case 0x8000: preg[0] = V; Sync(); break; - case 0x9000: mode = V; Sync(); break; - case 0xA000: preg[1] = V; Sync(); break; - case 0xC000: preg[2] = V; Sync(); break; - case 0xE000: creg[0] = V & 0xF; Sync(); break; - case 0xF000: creg[1] = V & 0xF; Sync(); break; + case 0x8000: + case 0xA000: + case 0xC000: + prg[(A >> 13) & 0x03] = V; + Sync(); + break; + case 0x9000: + mode = V; + Sync(); + break; + case 0xE000: + case 0xF000: + chr[(A >> 12) & 0x01] = V; + Sync(); + break; } } @@ -63,8 +77,20 @@ static void StateRestore(int version) { Sync(); } -void Mapper75_Init(CartInfo *info) { +void Mapper075_Init(CartInfo *info) { info->Power = M75Power; - AddExState(&StateRegs, ~0, 0, 0); GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); } + +extern uint8 *ExtraNTARAM; + +void Mapper151_Init(CartInfo *info) { + Mapper075_Init(info); + info->mirror = MI_4; + if (!ExtraNTARAM) { + ExtraNTARAM = (uint8 *)FCEU_malloc(2048); + } + SetupCartMirroring(MI_4, TRUE, ExtraNTARAM); +} + diff --git a/src/mappers/mapper076.c b/src/mappers/mapper076.c new file mode 100644 index 000000000..85e1b0df8 --- /dev/null +++ b/src/mappers/mapper076.c @@ -0,0 +1,48 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* iNES Mapper 076 + * iNES Mapper 076 represents NAMCOT-3446, a board used onlyfor the game + * Megami Tensei: Digital Devil Story. + * It rewires the Namcot 108 mapper IC to be able to address 128 KiB of CHR, + * in exchange for coarser CHR banking. + * The PCB also has a 7432 which allows the use of a 28-pin CHR-ROM. + * https://www.nesdev.org/wiki/INES_Mapper_076 + */ + +#include "mapinc.h" +#include "n118.h" + +static void M076PW(uint32 A, uint8 V) { + setprg8(A, V & 0x1F); /* support for PRG bank for fan translations */ +} + +static void M076FixCHR(void) { + setchr2(0x0000, n118.reg[2] & 0x3F); + setchr2(0x0800, n118.reg[3] & 0x3F); + setchr2(0x1000, n118.reg[4] & 0x3F); + setchr2(0x1800, n118.reg[5] & 0x3F); +} + +void Mapper076_Init(CartInfo *info) { + N118_Init(info, 0, 0); + N118_pwrap = M076PW; + N118_FixCHR = M076FixCHR; +} diff --git a/src/boards/mapper077.c b/src/mappers/mapper077.c similarity index 84% rename from src/boards/mapper077.c rename to src/mappers/mapper077.c index 29c415ae5..ecd926b21 100644 --- a/src/boards/mapper077.c +++ b/src/mappers/mapper077.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) 2023-2024 negativeExponent * * 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 @@ -31,16 +32,16 @@ static void Sync(void) { setchr4r(0x10, 0x1000, 0); } -static void M77Close(void) { - LatchClose(); +static void M077Close(void) { + Latch_Close(); if (CHRRAM) FCEU_gfree(CHRRAM); CHRRAM = NULL; } -void Mapper77_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 1); - info->Close = M77Close; +void Mapper077_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, TRUE); + info->Close = M077Close; CHRRAMSIZE = 6 * 1024; CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); diff --git a/src/mappers/mapper078.c b/src/mappers/mapper078.c new file mode 100644 index 000000000..55c63393c --- /dev/null +++ b/src/mappers/mapper078.c @@ -0,0 +1,43 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + */ + +/* Map 78 */ +/* Should be two separate emulation functions for this "mapper". Sigh. URGE TO KILL RISING. */ +/* Submapper 1 - Uchuusen - Cosmo Carrier ( one-screen mirroring ) */ +/* Submapper 3 - Holy Diver ( horizontal/vertical mirroring ) */ + +#include "mapinc.h" +#include "latch.h" + +static void Sync(void) { + setprg16(0x8000, latch.data & 0x07); + setprg16(0xc000, ~0); + setchr8(latch.data >> 4); + if (iNESCart.submapper == 3) { + setmirror((latch.data >> 3) & 0x01); + } else { + setmirror(MI_0 + ((latch.data >> 3) & 0x01)); + } +} + +void Mapper078_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, TRUE); +} diff --git a/src/boards/mapper079.c b/src/mappers/mapper079.c similarity index 75% rename from src/boards/mapper079.c rename to src/mappers/mapper079.c index 68bb3b39e..7d1f12595 100644 --- a/src/boards/mapper079.c +++ b/src/mappers/mapper079.c @@ -1,8 +1,9 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2012 CaH4e3 * Copyright (C) 2002 Xodnizel + * Copyright (C) 2023-2024 negativeExponent * * 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,29 +22,27 @@ #include "mapinc.h" -static uint8 creg, preg; -static SFORMAT StateRegs[] = -{ - { &creg, 1, "CREG" }, - { &preg, 1, "PREG" }, +static uint8 reg; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, { 0 } }; static void Sync(void) { - setprg32(0x8000, preg); - setchr8(creg); + setprg32(0x8000, (reg >> 3) & 0x01); + setchr8(reg & 0x07); } static DECLFW(M79Write) { if (A & 0x100) { - preg = (V >> 3) & 1; - creg = V & 7; + reg = V; Sync(); } } -static void M79Power(void) { - preg = 0; +static void M079Power(void) { + reg = 0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x4100, 0x5FFF, M79Write); @@ -53,8 +52,8 @@ static void StateRestore(int version) { Sync(); } -void Mapper79_Init(CartInfo *info) { - info->Power = M79Power; - AddExState(&StateRegs, ~0, 0, 0); +void Mapper079_Init(CartInfo *info) { + info->Power = M079Power; GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper080.c b/src/mappers/mapper080.c new file mode 100644 index 000000000..8928dd6f9 --- /dev/null +++ b/src/mappers/mapper080.c @@ -0,0 +1,125 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2002 Xodnizel + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 prg[3], chr[6], mirr; +static uint8 wram[256]; + +static SFORMAT StateRegs[] = { + { prg, 3, "PREG" }, + { chr, 6, "CREG" }, + { &mirr, 1, "MIRR" }, + { 0 } +}; + +static void Sync(void) { + setprg8(0x8000, prg[0]); + setprg8(0xA000, prg[1]); + setprg8(0xC000, prg[2]); + setprg8(0xE000, ~0); + + setchr2(0x0000, chr[0] >> 1); + setchr2(0x0800, chr[1] >> 1); + setchr1(0x1000, chr[2]); + setchr1(0x1400, chr[3]); + setchr1(0x1800, chr[4]); + setchr1(0x1C00, chr[5]); + + if (iNESCart.mapper == 207) { + setmirrorw(chr[0] >>7, chr[0] >>7, chr[1] >>7, chr[1] >>7); + } else { + setmirror(mirr & 0x01); + } +} + +static DECLFW(M080RamWrite) { + wram[A & 0xFF] = V; +} + +static DECLFR(M080RamRead) { + return wram[A & 0xFF]; +} + +static DECLFW(M080Write) { + switch (A) { + case 0x7EF0: + case 0x7EF1: + case 0x7EF2: + case 0x7EF3: + case 0x7EF4: + case 0x7EF5: + chr[A & 0x07] = V; + Sync(); + break; + case 0x7EF6: + mirr = V; + Sync(); + break; + case 0x7EF8: + break; + case 0x7EFA: + case 0x7EFB: + case 0x7EFC: + case 0x7EFD: + case 0x7EFE: + case 0x7EFF: + prg[(A - 0x7EFA) >> 1] = V; + Sync(); + break; + } +} + +static void M080Power(void) { + Sync(); + SetReadHandler(0x7F00, 0x7FFF, M080RamRead); + SetWriteHandler(0x7F00, 0x7FFF, M080RamWrite); + SetWriteHandler(0x7EF0, 0x7EFF, M080Write); + SetReadHandler(0x8000, 0xFFFF, CartBR); +} + +static void M207Power(void) { + Sync(); + SetWriteHandler(0x7EF0, 0x7EFF, M080Write); + SetReadHandler(0x8000, 0xFFFF, CartBR); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper080_Init(CartInfo *info) { + info->Power = M080Power; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + if (info->battery) { + info->SaveGame[0] = wram; + info->SaveGameLen[0] = 256; + AddExState(wram, sizeof(wram), 0, "WRAM"); + } +} + +void Mapper207_Init(CartInfo *info) { + info->Power = M207Power; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/mapper081.c b/src/mappers/mapper081.c similarity index 85% rename from src/boards/mapper081.c rename to src/mappers/mapper081.c index 1fe4dcb29..405bd1e46 100644 --- a/src/boards/mapper081.c +++ b/src/mappers/mapper081.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -27,6 +27,6 @@ static void Sync(void) { setchr8(latch.data & 3); } -void Mapper81_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); +void Mapper081_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); } diff --git a/src/boards/mapper082.c b/src/mappers/mapper082.c similarity index 53% rename from src/boards/mapper082.c rename to src/mappers/mapper082.c index 78f6c7915..3facc47de 100644 --- a/src/boards/mapper082.c +++ b/src/mappers/mapper082.c @@ -1,8 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2012 CaH4e3 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -26,23 +26,19 @@ #include "mapinc.h" -static uint8 creg[6], preg[3], prot[3], ctrl; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; -static int mappernum; +static uint8 chr[6], prg[3], protect[3], ctrl; -static SFORMAT StateRegs[] = -{ - { preg, 3, "PREGS" }, - { creg, 6, "CREGS" }, - { prot, 3, "PROT" }, +static SFORMAT StateRegs[] = { + { prg, 3, "PREGS" }, + { chr, 6, "CREGS" }, + { protect, 3, "PROT" }, { &ctrl, 1, "CTRL" }, { 0 } }; -static uint32 getPRGBank(uint8 V) { - if (mappernum == 552) { +static uint32 GetPRGBank(uint8 V) { + if (iNESCart.mapper == 552) { return (((V << 5) & 0x20) | ((V << 3) & 0x10) | ((V << 1) & 0x08) | @@ -55,79 +51,84 @@ static uint32 getPRGBank(uint8 V) { static void Sync(void) { uint32 swap = ((ctrl & 2) << 11); - setchr2(0x0000 ^ swap, creg[0] >> 1); - setchr2(0x0800 ^ swap, creg[1] >> 1); - setchr1(0x1000 ^ swap, creg[2]); - setchr1(0x1400 ^ swap, creg[3]); - setchr1(0x1800 ^ swap, creg[4]); - setchr1(0x1c00 ^ swap, creg[5]); + setprg8r(0x10, 0x6000, 0); - setprg8(0x8000, getPRGBank(preg[0])); - setprg8(0xA000, getPRGBank(preg[1])); - setprg8(0xC000, getPRGBank(preg[2])); + + setprg8(0x8000, GetPRGBank(prg[0])); + setprg8(0xA000, GetPRGBank(prg[1])); + setprg8(0xC000, GetPRGBank(prg[2])); setprg8(0xE000, ~0); - setmirror(ctrl & 1); + + setchr2(0x0000 ^ swap, chr[0] >> 1); + setchr2(0x0800 ^ swap, chr[1] >> 1); + setchr1(0x1000 ^ swap, chr[2]); + setchr1(0x1400 ^ swap, chr[3]); + setchr1(0x1800 ^ swap, chr[4]); + setchr1(0x1C00 ^ swap, chr[5]); + + setmirror(ctrl & 0x01); } static DECLFR(ReadWRAM) { - if (((A >= 0x6000) && (A <= 0x67FF) && (prot[0] == 0xCA)) || - ((A >= 0x6800) && (A <= 0x6FFF) && (prot[1] == 0x69)) || - ((A >= 0x7000) && (A <= 0x73FF) && (prot[2] == 0x84))) { - return CartBR(A); + if (((A >= 0x6000) && (A <= 0x67FF) && (protect[0] == 0xCA)) || + ((A >= 0x6800) && (A <= 0x6FFF) && (protect[1] == 0x69)) || + ((A >= 0x7000) && (A <= 0x73FF) && (protect[2] == 0x84))) { + return CartBR(A); } - return X.DB; + return cpu.openbus; } static DECLFW(WriteWRAM) { - if (((A >= 0x6000) && (A <= 0x67FF) && (prot[0] == 0xCA)) || - ((A >= 0x6800) && (A <= 0x6FFF) && (prot[1] == 0x69)) || - ((A >= 0x7000) && (A <= 0x73FF) && (prot[2] == 0x84))) { - CartBW(A, V); + if (((A >= 0x6000) && (A <= 0x67FF) && (protect[0] == 0xCA)) || + ((A >= 0x6800) && (A <= 0x6FFF) && (protect[1] == 0x69)) || + ((A >= 0x7000) && (A <= 0x73FF) && (protect[2] == 0x84))) { + CartBW(A, V); } } -static DECLFW(M82Write) { +static DECLFW(M082Write) { switch (A & 0x0F) { - case 0x0: - case 0x1: - case 0x2: - case 0x3: - case 0x4: - case 0x5: creg[A & 7] = V; break; - case 0x6: ctrl = V & 3; break; - case 0x7: prot[0] = V; break; - case 0x8: prot[1] = V; break; - case 0x9: prot[2] = V; break; - case 0xA: preg[0] = V; break; - case 0xB: preg[1] = V; break; - case 0xC: preg[2] = V; break; + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: chr[A & 7] = V; break; + case 0x06: ctrl = V & 3; break; + case 0x07: protect[0] = V; break; + case 0x08: protect[1] = V; break; + case 0x09: protect[2] = V; break; + case 0x0A: prg[0] = V; break; + case 0x0B: prg[1] = V; break; + case 0x0C: prg[2] = V; break; + default: + /* IRQ emulation ignored since no commercial games uses it */ + return; } Sync(); } -static void M82Power(void) { +static void M082Power(void) { Sync(); SetReadHandler(0x6000, 0xffff, CartBR); SetReadHandler(0x6000, 0x73ff, ReadWRAM); SetWriteHandler(0x6000, 0x73ff, WriteWRAM); - SetWriteHandler(0x7ef0, 0x7eff, M82Write); /* external WRAM might end at $73FF */ + SetWriteHandler(0x7ef0, 0x7eff, M082Write); /* external WRAM might end at $73FF */ FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } -static void M82Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; +static void M082Close(void) { } static void StateRestore(int version) { Sync(); } -void Mapper82_Init(CartInfo *info) { - mappernum = info->mapper; - info->Power = M82Power; - info->Close = M82Close; +void Mapper082_Init(CartInfo *info) { + info->Power = M082Power; + info->Close = M082Close; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); WRAMSIZE = 8192; WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); @@ -137,10 +138,8 @@ void Mapper82_Init(CartInfo *info) { info->SaveGame[0] = WRAM; info->SaveGameLen[0] = WRAMSIZE; } - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); } void Mapper552_Init(CartInfo *info) { - Mapper82_Init(info); + Mapper082_Init(info); } diff --git a/src/mappers/mapper083.c b/src/mappers/mapper083.c new file mode 100644 index 000000000..21336c51d --- /dev/null +++ b/src/mappers/mapper083.c @@ -0,0 +1,268 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2006 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + * YOKO mapper, almost the same as 83, TODO: figure out difference + * Mapper 83 - 30-in-1 mapper, two modes for single game carts, one mode for + * multigame Dragon Ball Z Party + * + * Mortal Kombat 2 YOKO + * N-CXX(M), XX - PRG+CHR, 12 - 128+256, 22 - 256+256, 14 - 128+512 + * + */ + +/* + * iNES Mapper 083 also knows as Yoko + * 256 KiB CHR-ROM => Submapper 0 (1 KiB CHR-ROM banking, no WRAM) + * - Street Fighter II Pro/Street Blaster II Pro + * - Street Fighter IV Pro 10/Street Blaster IV Pro 10 + * - Street Blaster V Turbo 20 + * - Street Fighter X Turbo 40 + * - Fatal Fury 2/餓狼伝説 2 + * - Fatal Fury 2'/餓狼伝説 2' + * 512 KiB CHR-ROM => Submapper 1 (2 KiB CHR-ROM banking, no WRAM) + * - Super Blaster VII Turbo 28 + * - World Heroes 2/快打英雄榜 2 + * - World Heroes 2 Pro//快打英雄榜 2 Pro + * 1024 KiB CHR-ROM => Submapper 2 (1 KiB CHR-ROM banking with outer bank, 32 KiB banked WRAM) + * - Dragon Ball Party + * + * NES 2.0 264 - UNL-Yoko + * - Mortal Kombat II/V Pro + * - Master Fighter VI' +*/ + +#include "mapinc.h" + +static uint8 prg[4], chr[8], low[4]; +static uint8 mode, bank, dip; +static uint8 IRQa; +static int32 IRQCount; + +static uint8 prgMask; +static uint8 chrMode; +static uint16 dipMask; + +static SFORMAT StateRegs[] = +{ + { prg, 4, "PREG" }, + { chr, 8, "CREG" }, + { &mode, 1, "MODE" }, + { &bank, 1, "BANK" }, + { &IRQCount, 4, "IRQC" }, + { &IRQa, 1, "IRQA" }, + { low, 4, "LOWR" }, + { 0 } +}; + +static void M083Sync(void) { + uint8 prgMode = (mode >> 3) & 0x03; + uint8 mirr = mode & 0x03; + + if (WRAMSIZE) { + setprg8r(0x10, 0x6000, (bank >> 6)); + } else if (mode & 0x20) { + setprg8(0x6000, prg[3]); + } + switch (prgMode) { + case 0: + setprg16(0x8000, bank); + setprg16(0xC000, bank | (prgMask >> 1)); + break; + case 1: + setprg32(0x8000, bank >> 1); + break; + case 2: + case 3: + setprg8(0x8000, ((bank << 1) & ~prgMask) | (prg[0] & prgMask)); + setprg8(0xA000, ((bank << 1) & ~prgMask) | (prg[1] & prgMask)); + setprg8(0xC000, ((bank << 1) & ~prgMask) | (prg[2] & prgMask)); + setprg8(0xE000, ((bank << 1) & ~prgMask) | (~0 & prgMask)); + break; + } + switch (chrMode) { + case 0: + setchr1(0x0000, chr[0]); + setchr1(0x0400, chr[1]); + setchr1(0x0800, chr[2]); + setchr1(0x0C00, chr[3]); + setchr1(0x1000, chr[4]); + setchr1(0x1400, chr[5]); + setchr1(0x1800, chr[6]); + setchr1(0x1C00, chr[7]); + break; + case 1: + setchr2(0x0000, chr[0]); + setchr2(0x0800, chr[1]); + setchr2(0x1000, chr[6]); + setchr2(0x1800, chr[7]); + break; + case 2: + setchr1(0x0000, ((bank << 4) & 0x300) | chr[0]); + setchr1(0x0400, ((bank << 4) & 0x300) | chr[1]); + setchr1(0x0800, ((bank << 4) & 0x300) | chr[2]); + setchr1(0x0C00, ((bank << 4) & 0x300) | chr[3]); + setchr1(0x1000, ((bank << 4) & 0x300) | chr[4]); + setchr1(0x1400, ((bank << 4) & 0x300) | chr[5]); + setchr1(0x1800, ((bank << 4) & 0x300) | chr[6]); + setchr1(0x1C00, ((bank << 4) & 0x300) | chr[7]); + break; + } + switch (mirr) { + case 0: setmirror(MI_V); break; + case 1: setmirror(MI_H); break; + case 2: setmirror(MI_0); break; + case 3: setmirror(MI_1); break; + } +} + +static DECLFW(M083Write) { + if (iNESCart.mapper == 264) { + A = ((A >> 2) & 0x3C0) | (A & 0x3F); + } + switch (A & 0x300) { + case 0x000: + bank = V; + break; + case 0x100: + mode = V; + break; + case 0x200: + if (A & 0x01) { + IRQa = mode & 0x80; + IRQCount &= 0xFF; + IRQCount |= V << 8; + } else { + IRQCount &= 0xFF00; + IRQCount |= V; + X6502_IRQEnd(FCEU_IQEXT); + } + break; + case 0x300: + A &= 0x1F; + if (A < 0x10) { + prg[A & 0x03] = V; + } else if (A < 0x18) { + chr[A & 0x07] = V; + } + break; + } + M083Sync(); +} + +static DECLFR(M083ReadLow) { + if (A & dipMask) { + return low[A & 3]; + } + return dip; +} + +static DECLFW(M083WriteLow) { + low[A & 3] = V; +} + +static void M083Power(void) { + mode = 0x10; + bank = 0; + dip = (iNESCart.mapper == 264) ? 0x01 : 0x00; + M083Sync(); + SetReadHandler(0x5000, 0x5FFF, M083ReadLow); + SetWriteHandler(0x5000, 0x5FFF, M083WriteLow); + SetReadHandler(0x6000, 0x7fff, CartBR); + SetReadHandler(0x8000, 0xffff, CartBR); + SetWriteHandler(0x8000, 0xffff, M083Write); + if (WRAMSIZE) { + SetWriteHandler(0x6000, 0x7fff, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + + } +} + +static void M083Reset(void) { + dip++; + if (iNESCart.mapper == 264) { + dip &= 3; + } else { + dip &= 1; + } + mode = bank = 0; + M083Sync(); +} + +static void M083Close(void) { +} + +static void M083IRQHook(int a) { + if (IRQa && (IRQCount > 0)) { + if (mode & 0x40) { + IRQCount -= a; + } else { + IRQCount += a; + } + if (IRQCount <= 0) { + X6502_IRQBegin(FCEU_IQEXT); + IRQa = 0; + } + } +} + +static void M083StateRestore(int version) { + M083Sync(); +} + +void Mapper083_Init(CartInfo *info) { + info->Power = M083Power; + info->Reset = M083Reset; + info->Close = M083Close; + MapIRQHook = M083IRQHook; + GameStateRestore = M083StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + + if (!info->iNES2) { + if (info->CHRRomSize >= (1024 * 1024)) { + info->submapper = 2; + } else if (info->CHRRomSize >= (512 * 1024)) { + info->submapper = 1; + } + } + + chrMode = info->submapper; + prgMask = 0x1F; + dipMask = 0x100; + + WRAMSIZE = (info->submapper == 2) ? 32768 : 0; + if (WRAMSIZE) { + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + } +} + +void Mapper264_Init(CartInfo *info) { + info->Power = M083Power; + info->Reset = M083Reset; + info->Close = M083Close; + MapIRQHook = M083IRQHook; + GameStateRestore = M083StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + + chrMode = 1; + prgMask = 0x0F; + dipMask = 0x400; +} diff --git a/src/mappers/mapper085.c b/src/mappers/mapper085.c new file mode 100644 index 000000000..0523111b9 --- /dev/null +++ b/src/mappers/mapper085.c @@ -0,0 +1,42 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "vrc7.h" + +static void M085PW(uint32 A, uint8 V) { + setprg8(A, V & 0x3F); +} + +static void M085CW(uint32 A, uint8 V) { + setchr1(A, V & 0xFF); +} + +void Mapper085_Init(CartInfo *info) { + switch (info->submapper) { + case 0x01: VRC7_Init(info, 0x08, 0x20); break; + case 0x02: VRC7_Init(info, 0x10, 0x20); break; + default: VRC7_Init(info, 0x18, 0x20); break; + } + VRC7_pwrap = M085PW; + VRC7_cwrap = M085CW; +} diff --git a/src/boards/mapper086.c b/src/mappers/mapper086.c similarity index 72% rename from src/boards/mapper086.c rename to src/mappers/mapper086.c index ef33ea896..ca40f199c 100644 --- a/src/boards/mapper086.c +++ b/src/mappers/mapper086.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -24,35 +24,34 @@ static uint8 reg; -static SFORMAT StateRegs[] = -{ - { ®, 1, "REG" }, +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, { 0 } }; -static void Sync() { - setprg32(0x8000, (reg >> 4) & 3); - setchr8((reg & 3) | ((reg >> 4) & 4)); +static void Sync(void) { + setprg32(0x8000, (reg >> 4) & 0x03); + setchr8(((reg >> 4) & 0x04) | (reg & 0x03)); } -static DECLFW(M86Write) { +static DECLFW(M086Write) { reg = V; Sync(); } -static void M86Power(void) { +static void M086Power(void) { reg = 0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0x6FFF, M86Write); + SetWriteHandler(0x6000, 0x6FFF, M086Write); } static void StateRestore(int version) { Sync(); } -void Mapper86_Init(CartInfo *info) { - info->Power = M86Power; +void Mapper086_Init(CartInfo *info) { + info->Power = M086Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper087.c b/src/mappers/mapper087.c similarity index 73% rename from src/boards/mapper087.c rename to src/mappers/mapper087.c index 625722260..8344b2a3f 100644 --- a/src/boards/mapper087.c +++ b/src/mappers/mapper087.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,35 +22,34 @@ static uint8 reg; -static SFORMAT StateRegs[] = -{ - { ®, 1, "REG" }, +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, { 0 } }; -static void Sync() { +static void Sync(void) { setprg32(0x8000, 0); - setchr8(((reg >> 1) & 1) | ((reg << 1) & 2)); + setchr8(((reg << 1) & 0x02) | ((reg >> 1) & 0x01)); } -static DECLFW(M87Write) { +static DECLFW(M087Write) { reg = V; Sync(); } -static void M87Power(void) { +static void M087Power(void) { reg = 0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, M87Write); + SetWriteHandler(0x6000, 0x7FFF, M087Write); } static void StateRestore(int version) { Sync(); } -void Mapper87_Init(CartInfo *info) { - info->Power = M87Power; +void Mapper087_Init(CartInfo *info) { + info->Power = M087Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper088.c b/src/mappers/mapper088.c new file mode 100644 index 000000000..bf7778bcc --- /dev/null +++ b/src/mappers/mapper088.c @@ -0,0 +1,36 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "n118.h" + +static void M088FixCHR(void) { + setchr2(0x0000, (n118.reg[0] & 0x3F) >> 1); + setchr2(0x0800, (n118.reg[1] & 0x3F) >> 1); + setchr1(0x1000, 0x40 | (n118.reg[2] & 0x3F)); + setchr1(0x1400, 0x40 | (n118.reg[3] & 0x3F)); + setchr1(0x1800, 0x40 | (n118.reg[4] & 0x3F)); + setchr1(0x1C00, 0x40 | (n118.reg[5] & 0x3F)); +} + +void Mapper088_Init(CartInfo *info) { + N118_Init(info, 0, 0); + N118_FixCHR = M088FixCHR; +} diff --git a/src/mappers/mapper089.c b/src/mappers/mapper089.c new file mode 100644 index 000000000..8013a021f --- /dev/null +++ b/src/mappers/mapper089.c @@ -0,0 +1,34 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg16(0x8000, (latch.data >> 4) & 0x07); + setprg16(0xC000, ~0); + setchr8((latch.data & 0x07) | ((latch.data >> 4) & 0x08)); + setmirror(MI_0 + ((latch.data >> 3) & 0x01)); +} + +void Mapper089_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, TRUE); +} diff --git a/src/mappers/mapper091.c b/src/mappers/mapper091.c new file mode 100644 index 000000000..228057b90 --- /dev/null +++ b/src/mappers/mapper091.c @@ -0,0 +1,162 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2020 + * + * 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 2020-2-15 + * Street Fighter 3, Mortal Kombat II, Dragon Ball Z 2, Mario & Sonic 2 (JY-016) + * 1995 Super HIK 4-in-1 (JY-016), 1995 Super HiK 4-in-1 (JY-017) + * submapper 1 - Super Fighter III + * NOTE: nesdev's notes for IRQ is different that whats implemented here + */ + +#include "mapinc.h" + +static uint8 chr[4], prg[2]; +static uint8 outerbank; +static uint8 mirr; + +static uint8 IRQa; +static uint8 IRQPrescaler; +static uint8 IRQCount; +static int16 IRQCount16; + +static SFORMAT StateRegs[] = { + { chr, 4, "CREG" }, + { prg, 2, "PREG" }, + { &IRQa, 1, "IRQA" }, + { &IRQPrescaler, 1, "IRQP" }, + { &IRQCount, 1, "IRQC" }, + { &IRQCount16, 4, "IRQ2" }, + { &outerbank, 1, "OUTB" }, + { &mirr, 1, "MIRR" }, + { 0 } +}; + +static void Sync(void) { + /* FCEU_printf("P0:%02x P1:%02x outerbank:%02x\n", prg[0], prg[1], outerbank);*/ + setprg8(0x8000, ((outerbank << 3) & ~0x0F) | prg[0]); + setprg8(0xa000, ((outerbank << 3) & ~0x0F) | prg[1]); + setprg8(0xc000, ((outerbank << 3) & ~0x0F) | 0x0E); + setprg8(0xe000, ((outerbank << 3) & ~0x0F) | 0x0F); + + setchr2(0x0000, ((outerbank << 8) & 0x100) | chr[0]); + setchr2(0x0800, ((outerbank << 8) & 0x100) | chr[1]); + setchr2(0x1000, ((outerbank << 8) & 0x100) | chr[2]); + setchr2(0x1800, ((outerbank << 8) & 0x100) | chr[3]); + + if (iNESCart.submapper != 0) { + setmirror((mirr & 0x01) ^ 0x01); + } +} + +static DECLFW(M091CHRWrite) { + if (iNESCart.submapper == 1) { + switch (A & 0x07) { + case 0: + case 1: + case 2: + case 3: + chr[A & 0x03] = V; + Sync(); + break; + case 4: + case 5: + mirr = V; + Sync(); + break; + case 6: + IRQCount16 = (IRQCount16 & 0xFF00) | V; + break; + case 7: + IRQCount16 = (IRQCount16 & 0x00FF) | (V << 8); + break; + } + } else { + chr[A & 0x03] = V; + Sync(); + } +} + +static DECLFW(M091IRQWrite) { + switch (A & 0x03) { + case 0: + case 1: + prg[A & 0x01] = V; + Sync(); + break; + case 2: + IRQa = IRQCount = 0; + X6502_IRQEnd(FCEU_IQEXT); + break; + case 3: + IRQa = 1; + IRQPrescaler = 3; + X6502_IRQEnd(FCEU_IQEXT); + break; + } +} + +static DECLFW(M091OuterBankWrite) { + outerbank = A & 0xFF; + Sync(); +} + +static void M091Power(void) { + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x6FFF, M091CHRWrite); + SetWriteHandler(0x7000, 0x7FFF, M091IRQWrite); + SetWriteHandler(0x8000, 0x9FFF, M091OuterBankWrite); +} + +static void M091HBHook(void) { + if ((IRQCount < 8) && IRQa) { + IRQCount++; + if (IRQCount >= 8) { + X6502_IRQBegin(FCEU_IQEXT); + } + } +} + +static void M091IRQHook(int a) { + IRQPrescaler += a; + if (IRQPrescaler >= 4) { + IRQPrescaler -= 4; + IRQCount16 -= 5; + if ((IRQCount16 <= 0) && IRQa) { + X6502_IRQBegin(FCEU_IQEXT); + } + } +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper091_Init(CartInfo *info) { + info->Power = M091Power; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + if (info->submapper == 1) { + MapIRQHook = M091IRQHook; + } else { + GameHBIRQHook = M091HBHook; + } +} diff --git a/src/mappers/mapper093.c b/src/mappers/mapper093.c new file mode 100644 index 000000000..e241352f8 --- /dev/null +++ b/src/mappers/mapper093.c @@ -0,0 +1,33 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg16(0x8000, latch.data >> 4); + setprg16(0xc000, ~0); + setchr8(0); +} + +void Mapper093_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, TRUE); +} diff --git a/src/mappers/mapper094.c b/src/mappers/mapper094.c new file mode 100644 index 000000000..132ce5602 --- /dev/null +++ b/src/mappers/mapper094.c @@ -0,0 +1,33 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg16(0x8000, latch.data >> 2); + setprg16(0xc000, ~0); + setchr8(0); +} + +void Mapper094_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, TRUE); +} diff --git a/src/mappers/mapper095.c b/src/mappers/mapper095.c new file mode 100644 index 000000000..cbbd87a4f --- /dev/null +++ b/src/mappers/mapper095.c @@ -0,0 +1,121 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2005 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 95 represents NAMCOT-3425, a board used only for the game Dragon Buster (J). + +It is to the ordinary Namco 108 family boards (mapper 206) as TKSROM and TLSROM +(mapper 118) is to ordinary MMC3 boards. Instead of having hardwired mirroring +like mapper 206, it has CHR A15 directly controlling CIRAM A10, just as CHR A17 +controls CIRAM A10 on TxSROM. Only horizontal mirroring and 1-screen mirroring +are possible because the Namco 108 lacks the C bit of MMC3. +*/ + +#include "mapinc.h" +#include "n118.h" + +static uint8 mcache[8]; +static uint32 lastppu; + +static SFORMAT StateRegs[] = { + { mcache, 8, "MCCH" }, + { &lastppu, 4, "LPPU" }, + { 0 } +}; + +static void M095FixCHR(void) { + setchr2(0x0000, n118.reg[0] >> 1); + setchr2(0x0800, n118.reg[1] >> 1); + setchr1(0x1000, n118.reg[2]); + setchr1(0x1400, n118.reg[3]); + setchr1(0x1800, n118.reg[4]); + setchr1(0x1C00, n118.reg[5]); + setmirror(MI_0 + mcache[lastppu]); +} + +static DECLFW(M095Write) { + switch (A & 0xE001) { + case 0x8001: + n118.reg[n118.cmd & 0x07] = V & 0x1F; + switch (n118.cmd & 0x07) { + case 0: + mcache[0] = mcache[1] = (V >> 5) & 0x01; + N118_FixCHR(); + break; + case 1: + mcache[2] = mcache[3] = (V >> 5) & 0x01; + N118_FixCHR(); + break; + case 2: + mcache[4] = (V >> 5) & 0x01; + N118_FixCHR(); + break; + case 3: + mcache[5] = (V >> 5) & 0x01; + N118_FixCHR(); + break; + case 4: + mcache[6] = (V >> 5) & 0x01; + N118_FixCHR(); + break; + case 5: + mcache[7] = (V >> 5) & 0x01; + N118_FixCHR(); + break; + case 6: + case 7: + N118_FixPRG(); + break; + } + break; + default: + N118_Write(A, V); + break; + } +} + +static void MExMirrPPU(uint32 A) { + static int8 lastmirr = -1, curmirr; + if (A < 0x2000) { + lastppu = A >> 10; + curmirr = mcache[lastppu]; + if (curmirr != lastmirr) { + setmirror(MI_0 + curmirr); + lastmirr = curmirr; + } + } +} + +static void M095Power(void) { + lastppu = 0; + memset(mcache, 0, sizeof(mcache)); + + N118_Power(); + SetWriteHandler(0x8000, 0x9FFF, M095Write); +} + +void Mapper095_Init(CartInfo *info) { + N118_Init(info, 0, 0); + info->Power = M095Power; + N118_FixCHR = M095FixCHR; + PPU_hook = MExMirrPPU; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/mapper096.c b/src/mappers/mapper096.c similarity index 83% rename from src/boards/mapper096.c rename to src/mappers/mapper096.c index 9c74393b6..059eccec7 100644 --- a/src/boards/mapper096.c +++ b/src/mappers/mapper096.c @@ -1,10 +1,10 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 1998 BERO * Copyright (C) 2002 Xodnizel * Copyright (C) 2012 CaH4e3 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -48,7 +48,7 @@ static void Sync(void) { setchr4(0x1000, (latch.data & 4) | 3); } -static void FP_FASTAPASS(1) M96Hook(uint32 A) { +static void M096PPUHook(uint32 A) { uint16 addr = A & 0x3000; if ((lastAddr != 0x2000) && ((A & 0x3000) == 0x2000)) { ppulatch = (A >> 8) & 3; @@ -57,15 +57,15 @@ static void FP_FASTAPASS(1) M96Hook(uint32 A) { lastAddr = addr; } -static void M96Power(void) { +static void M096Power(void) { ppulatch = 0; lastAddr = 0; - LatchPower(); + Latch_Power(); } -void Mapper96_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 1); - info->Power = M96Power; - PPU_hook = M96Hook; - AddExState(&StateRegs, ~0, 0, 0); +void Mapper096_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, TRUE); + info->Power = M096Power; + PPU_hook = M096PPUHook; + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper097.c b/src/mappers/mapper097.c new file mode 100644 index 000000000..52369e163 --- /dev/null +++ b/src/mappers/mapper097.c @@ -0,0 +1,34 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg16(0x8000, ~0); + setprg16(0xC000, latch.data); + setchr8(0); + setmirror((latch.data >> 7) & 0x01); +} + +void Mapper097_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); +} diff --git a/src/boards/mapper099.c b/src/mappers/mapper099.c similarity index 78% rename from src/boards/mapper099.c rename to src/mappers/mapper099.c index 5a23a414d..20630c2bb 100644 --- a/src/boards/mapper099.c +++ b/src/mappers/mapper099.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) 2023-2024 negativeExponent * * 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,58 +22,52 @@ #include "mapinc.h" static uint8 latch; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; static writefunc old4016; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { &latch, 1, "LATC" }, { 0 } }; static void Sync(void) { - setchr8((latch >> 2) & 1); setprg8r(0x10, 0x6000, 0); setprg32(0x8000, 0); setprg8(0x8000, latch & 4); /* Special for VS Gumshoe */ + setchr8((latch >> 2) & 1); } -static DECLFW(M99Write) { +static DECLFW(M099Write) { latch = V; Sync(); old4016(A, V); } -static void M99Power(void) { +static void M099Power(void) { latch = 0; Sync(); old4016 = GetWriteHandler(0x4016); - SetWriteHandler(0x4016, 0x4016, M99Write); + SetWriteHandler(0x4016, 0x4016, M099Write); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } -static void M99Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; +static void M099Close(void) { } static void StateRestore(int version) { Sync(); } -void Mapper99_Init(CartInfo *info) { - info->Power = M99Power; - info->Close = M99Close; +void Mapper099_Init(CartInfo *info) { + info->Power = M099Power; + info->Close = M099Close; + + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); WRAMSIZE = 8192; WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); } diff --git a/src/boards/mapper101.c b/src/mappers/mapper101.c similarity index 90% rename from src/boards/mapper101.c rename to src/mappers/mapper101.c index 15093a7ef..706499dfe 100644 --- a/src/boards/mapper101.c +++ b/src/mappers/mapper101.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,13 +22,12 @@ static uint8 reg; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { ®, 1, "REG" }, { 0 } }; -static void Sync() { +static void Sync(void) { setprg32(0x8000, 0); setchr8(reg); } @@ -52,5 +51,5 @@ static void StateRestore(int version) { void Mapper101_Init(CartInfo *info) { info->Power = M101Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper103.c b/src/mappers/mapper103.c similarity index 62% rename from src/boards/mapper103.c rename to src/mappers/mapper103.c index 434b3bef1..b7053ae89 100644 --- a/src/boards/mapper103.c +++ b/src/mappers/mapper103.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2007 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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,39 +23,34 @@ */ #include "mapinc.h" -#include "../fds_apu.h" +#include "fdssound.h" -static uint8 reg0, reg1, reg2; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint8 reg[3]; -static SFORMAT StateRegs[] = -{ - { ®0, 1, "REG0" }, - { ®1, 1, "REG1" }, - { ®2, 1, "REG2" }, +static SFORMAT StateRegs[] = { + { reg, 3, "REGS" }, { 0 } }; static void Sync(void) { - setchr8(0); - setprg8(0x8000, 0xc); - setprg8(0xe000, 0xf); - if (reg2 & 0x10) { - setprg8(0x6000, reg0); - setprg8(0xa000, 0xd); - setprg8(0xc000, 0xe); + setprg8(0x8000, 0x0C); + setprg8(0xE000, 0x0F); + if (reg[2] & 0x10) { + setprg8(0x6000, reg[0] & 0x0F); + setprg8(0xA000, 0x0D); + setprg8(0xC000, 0x0E); } else { setprg8r(0x10, 0x6000, 0); - setprg4(0xa000, (0xd << 1)); - setprg2(0xb000, (0xd << 2) + 2); - setprg2r(0x10, 0xb800, 4); - setprg2r(0x10, 0xc000, 5); - setprg2r(0x10, 0xc800, 6); - setprg2r(0x10, 0xd000, 7); - setprg2(0xd800, (0xe << 2) + 3); + setprg4(0xA000, (0x0D << 1)); + setprg2(0xB000, (0x0D << 2) + 2); + setprg2r(0x10, 0xB800, 4); + setprg2r(0x10, 0xC000, 5); + setprg2r(0x10, 0xC800, 6); + setprg2r(0x10, 0xD000, 7); + setprg2(0xD800, (0x0E << 2) + 3); } - setmirror(reg1 ^ 1); + setchr8(0); + setmirror(((reg[1] >> 3) & 0x01) ^ 0x01); } static DECLFW(M103RamWrite0) { @@ -65,39 +61,36 @@ static DECLFW(M103RamWrite1) { WRAM[0x2000 + ((A - 0xB800) & 0x1FFF)] = V; } -static DECLFW(M103Write0) { - reg0 = V & 0xf; +static DECLFW(M103WritePRG) { + reg[0] = V; Sync(); } -static DECLFW(M103Write1) { - reg1 = (V >> 3) & 1; +static DECLFW(M103WriteMirror) { + reg[1] = V; Sync(); } -static DECLFW(M103Write2) { - reg2 = V; +static DECLFW(M103WriteRAMEnable) { + reg[2] = V; Sync(); } static void M103Power(void) { - FDSSoundPower(); - reg0 = reg1 = 0; - reg2 = 0; + FDSSound_Power(); + reg[0] = reg[1] = 0; + reg[2] = 0; Sync(); SetReadHandler(0x6000, 0x7FFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, M103RamWrite0); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0xB800, 0xD7FF, M103RamWrite1); - SetWriteHandler(0x8000, 0x8FFF, M103Write0); - SetWriteHandler(0xE000, 0xEFFF, M103Write1); - SetWriteHandler(0xF000, 0xFFFF, M103Write2); + SetWriteHandler(0x8000, 0x8FFF, M103WritePRG); + SetWriteHandler(0xE000, 0xEFFF, M103WriteMirror); + SetWriteHandler(0xF000, 0xFFFF, M103WriteRAMEnable); } static void M103Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; } static void StateRestore(int version) { @@ -108,11 +101,10 @@ void Mapper103_Init(CartInfo *info) { info->Power = M103Power; info->Close = M103Close; GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); WRAMSIZE = 16384; 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/mapper104.c b/src/mappers/mapper104.c similarity index 56% rename from src/boards/mapper104.c rename to src/mappers/mapper104.c index ad72e110f..a7b0fe1af 100644 --- a/src/boards/mapper104.c +++ b/src/mappers/mapper104.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2012 + * Copyright (C) 2023-2024 negativeExponent * * 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,51 +23,49 @@ #include "mapinc.h" -static uint8 preg[2]; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint8 reg[2]; -static SFORMAT StateRegs[] = -{ - { preg, 2, "PREG" }, +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, { 0 } }; static void Sync(void) { setprg8r(0x10, 0x6000, 0); - setprg16(0x8000, preg[0]); - setprg16(0xC000, preg[1]); + setprg16(0x8000, (reg[1] << 4) | (reg[0] & 0x0F)); + setprg16(0xC000, (reg[1] << 4) | 0x0F); setchr8(0); } -static DECLFW(M104WriteBank) { - if ((V & 8) > 0) { - preg[0] = ((V << 4) & 0x70) | (preg[0] & 0x0F); - preg[1] = ((V << 4) & 0x70) | 0x0F; +static DECLFW(M104Write) { + switch (A & 0xF000) { + case 0x8000: + case 0x9000: + case 0xA000: + case 0xB000: + if (!(reg[1] & 0x08)) { + reg[1] = V; + Sync(); + } + break; + case 0xC000: + case 0xD000: + case 0xE000: + case 0xF000: + reg[0] = V; Sync(); + break; } } -static DECLFW(M104WritePreg) { - preg[0] = (preg[0] & 0x70) | (V & 0x0F); - Sync(); -} - static void M104Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; } static void M104Power(void) { - preg[1] = 0x0F; + reg[0] = reg[1] = 0; Sync(); - SetReadHandler(0x6000, 0x7fff, CartBR); - SetWriteHandler(0x6000, 0x7fff, CartBW); - SetWriteHandler(0x8000, 0x9FFF, M104WriteBank); - SetWriteHandler(0xC000, 0xFFFF, M104WritePreg); SetReadHandler(0x8000, 0xFFFF, CartBR); - setmirror(MI_V); + SetWriteHandler(0x8000, 0xFFFF, M104Write); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } @@ -77,16 +76,6 @@ static void StateRestore(int version) { void Mapper104_Init(CartInfo *info) { info->Power = M104Power; info->Close = M104Close; - AddExState(&StateRegs, ~0, 0, 0); - - WRAMSIZE = 8192; - WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; - } - GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper105.c b/src/mappers/mapper105.c new file mode 100644 index 000000000..edf88470e --- /dev/null +++ b/src/mappers/mapper105.c @@ -0,0 +1,74 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "mmc1.h" + +static uint32 count; +static uint32 count_target = 0x28000000; + +static void M105IRQHook(int a) { + while (a--) { + if (mmc1.reg[1] & 0x10) { + count = 0; + X6502_IRQEnd(FCEU_IQEXT); + } else { + if (++count == count_target) { + X6502_IRQBegin(FCEU_IQEXT); + } + if ((count % 1789773) == 0) { + uint32 seconds = (count_target - count) / 1789773; + FCEU_DispMessage(RETRO_LOG_INFO, 1000, "Time left: %02i:%02i\n", seconds / 60, seconds % 60); + } + } + } +} + +static void M105CW(uint32 A, uint8 V) { + setchr8r(0, 0); +} + +static void M105PW(uint32 A, uint8 V) { + if (mmc1.reg[1] & 0x08) { + setprg16(A, 8 | (V & 0x7)); + } else { + setprg32(0x8000, (mmc1.reg[1] >> 1) & 0x03); + } +} + +static void M105Power(void) { + count_target = 0x20000000 | ((uint32)GameInfo->cspecial << 25); + MMC1_Power(); +} + +static void M105Reset(void) { + count_target = 0x20000000 | ((uint32)GameInfo->cspecial << 25); + MMC1_Reset(); +} + +void Mapper105_Init(CartInfo *info) { + MMC1_Init(info, 8, 0); + MMC1_cwrap = M105CW; + MMC1_pwrap = M105PW; + MapIRQHook = M105IRQHook; + info->Power = M105Power; + info->Reset = M105Reset; + AddExState(&count, 4, 0, "IRQC"); +} diff --git a/src/boards/mapper106.c b/src/mappers/mapper106.c similarity index 59% rename from src/boards/mapper106.c rename to src/mappers/mapper106.c index 5fc5dc293..5fe755c2e 100644 --- a/src/boards/mapper106.c +++ b/src/mappers/mapper106.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2007 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -20,60 +21,68 @@ #include "mapinc.h" -static uint8 reg[16], IRQa; +static uint8 prg[4], chr[8]; +static uint8 mirr, IRQa; static uint32 IRQCount; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { + { prg, 4, "PREGS" }, + { chr, 8, "CREGS" }, { &IRQa, 1, "IRQA" }, { &IRQCount, 4, "IRQC" }, - { reg, 16, "REGS" }, { 0 } }; static void Sync(void) { - setchr1(0x0000, reg[0] & 0xfe); - setchr1(0x0400, reg[1] | 1); - setchr1(0x0800, reg[2] & 0xfe); - setchr1(0x0c00, reg[3] | 1); - setchr1(0x1000, reg[4]); - setchr1(0x1400, reg[5]); - setchr1(0x1800, reg[6]); - setchr1(0x1c00, reg[7]); setprg8r(0x10, 0x6000, 0); - setprg8(0x8000, (reg[0x8] & 0xf) | 0x10); - setprg8(0xA000, (reg[0x9] & 0x1f)); - setprg8(0xC000, (reg[0xa] & 0x1f)); - setprg8(0xE000, (reg[0xb] & 0xf) | 0x10); - setmirror((reg[0xc] & 1) ^ 1); + setprg8(0x8000, (prg[0] & 0x0F) | 0x10); + setprg8(0xA000, (prg[1] & 0x1F)); + setprg8(0xC000, (prg[2] & 0x1F)); + setprg8(0xE000, (prg[3] & 0x0F) | 0x10); + + setchr1(0x0000, chr[0] & ~1); + setchr1(0x0400, chr[1] | 1); + setchr1(0x0800, chr[2] & ~1); + setchr1(0x0c00, chr[3] | 1); + setchr1(0x1000, chr[4]); + setchr1(0x1400, chr[5]); + setchr1(0x1800, chr[6]); + setchr1(0x1C00, chr[7]); + + setmirror((mirr & 0x01) ^ 0x01); } static DECLFW(M106Write) { - A &= 0xF; - switch (A) { - case 0xD: - IRQa = 0; - IRQCount = 0; - X6502_IRQEnd(FCEU_IQEXT); - break; - case 0xE: - IRQCount = (IRQCount & 0xFF00) | V; - break; - case 0xF: - IRQCount = (IRQCount & 0x00FF) | (V << 8); - IRQa = 1; - break; - default: - reg[A] = V; - Sync(); - break; + switch (A & 0x0F) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + chr[A & 0x07] = V; + Sync(); + break; + case 0x08: case 0x09: case 0x0A: case 0x0B: + prg[A & 0x03] = V; + Sync(); + break; + case 0x0C: + mirr = V; + Sync(); + break; + case 0x0D: + IRQa = 0; + IRQCount = 0; + X6502_IRQEnd(FCEU_IQEXT); + break; + case 0x0E: + IRQCount = (IRQCount & 0xFF00) | V; + break; + case 0x0F: + IRQCount = (IRQCount & 0x00FF) | (V << 8); + IRQa = 1; + break; } } static void M106Power(void) { - reg[8] = reg[9] = reg[0xa] = reg[0xb] = -1; Sync(); SetReadHandler(0x6000, 0x7FFF, CartBR); SetReadHandler(0x8000, 0xFFFF, CartBR); @@ -84,12 +93,9 @@ static void M106Power(void) { static void M106Reset(void) { } static void M106Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; } -void FP_FASTAPASS(1) M106CpuHook(int a) { +static void M106CpuHook(int a) { if (IRQa) { IRQCount += a; if (IRQCount > 0x10000) { @@ -109,11 +115,10 @@ void Mapper106_Init(CartInfo *info) { info->Close = M106Close; MapIRQHook = M106CpuHook; GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); 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/mappers/mapper107.c b/src/mappers/mapper107.c new file mode 100644 index 000000000..abfaacc15 --- /dev/null +++ b/src/mappers/mapper107.c @@ -0,0 +1,32 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg32(0x8000, latch.data >> 1); + setchr8(latch.data); +} + +void Mapper107_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); +} diff --git a/src/boards/mapper108.c b/src/mappers/mapper108.c similarity index 71% rename from src/boards/mapper108.c rename to src/mappers/mapper108.c index b32e83cfa..dd395424c 100644 --- a/src/boards/mapper108.c +++ b/src/mappers/mapper108.c @@ -1,8 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2007 CaH4e3 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -31,18 +31,17 @@ */ #include "mapinc.h" +#include "fdssound.h" static uint8 reg; -static uint8 submapper; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { ®, 1, "REGS" }, { 0 } }; static void Sync(void) { - if (submapper == 4) { + if (iNESCart.submapper == 4) { setprg8(0x6000, ~0); } else { setprg8(0x6000, reg); @@ -63,19 +62,13 @@ static DECLFW(M108Write) { static void M108Power(void) { reg = 0; Sync(); - SetReadHandler(0x6000, 0x7FFF, CartBR); - SetReadHandler(0x8000, 0xFFFF, CartBR); - switch (submapper) { - case 1: - SetWriteHandler(0xF000, 0xFFFF, M108Write); - break; - case 2: - SetWriteHandler(0xE000, 0xFFFF, M108Write); - break; - default: - SetWriteHandler(0x8000, 0xFFFF, M108Write); - break; + SetReadHandler(0x6000, 0xFFFF, CartBR); + switch (iNESCart.submapper) { + case 1: SetWriteHandler(0xF000, 0xFFFF, M108Write); break; + case 2: SetWriteHandler(0xE000, 0xFFFF, M108Write); break; + default: SetWriteHandler(0x8000, 0xFFFF, M108Write); break; } + FDSSound_Power(); } static void StateRestore(int version) { @@ -85,21 +78,20 @@ static void StateRestore(int version) { void Mapper108_Init(CartInfo *info) { info->Power = M108Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); - submapper = info->submapper; - if (!info->iNES2 || !submapper) { + if (!info->iNES2 || !info->submapper) { if (UNIFchrrama) { - if (info->mirror == 0) { - submapper = 1; + if (info->mirror == MI_H) { + info->submapper = 1; } else { - submapper = 3; + info->submapper = 3; } } else { if (CHRsize[0] > (16 * 1024)) { - submapper = 2; + info->submapper = 2; } else { - submapper = 4; + info->submapper = 4; } } } diff --git a/src/mappers/mapper111.c b/src/mappers/mapper111.c new file mode 100644 index 000000000..0a332afeb --- /dev/null +++ b/src/mappers/mapper111.c @@ -0,0 +1,176 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * Copyright (C) 2023-2024 negativeExponent + * + * 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 111 - Cheapocabra board by Memblers + * http://forums.nesdev.com/viewtopic.php?p=146039 + * + * 512k PRG-ROM in 32k pages (flashable if battery backed is specified) + * 32k CHR-RAM used as: + * 2 x 8k pattern pages + * 2 x 8k nametable pages + * + * Notes: + * - CHR-RAM for nametables maps to $3000-3FFF as well, but FCEUX internally mirrors to 4k? + */ + +#include "mapinc.h" +#include "flashrom.h" +#include "mmc1.h" + +static uint8 reg; + +static uint8 *FLASHROM = NULL; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; + +static void M111PW_mmc1(uint32 A, uint8 V) { + setprg16(A, V & 0x0F); +} + +static void M111CW_mmc1(uint32 A, uint8 V) { + setchr4(A, V & 0x3F); +} + +static DECLFW(M111Write_mmc1) { + mmc1.reg[(A >> 13) & 0x03] = V; + MMC1_FixPRG(); + MMC1_FixCHR(); + MMC1_FixMIR(); +} + +static void M111Power_mmc1(void) { + MMC1_Power(); + SetWriteHandler(0x8000, 0xFFFF, M111Write_mmc1); +} + +#define VRAM_OFFSET(x) (0x4000 + (0x400 * (x))) + +static void Sync(void) { + /* 7 bit 0 + * ---- ---- + * GRNC PPPP + * |||| |||| + * |||| ++++- Select 32 KB PRG ROM bank for CPU $8000-$FFFF + * |||+------ Select 8 KB CHR RAM bank for PPU $0000-$1FFF + * ||+------- Select 8 KB nametable for PPU $2000-$3EFF + * |+-------- Red LED - 0=On; 1=Off + * +--------- Green LED - 0=On; 1=Off */ + int nt = (reg & 0x20) >> 5; + int chr = (reg & 0x10) >> 4; + int prg = (reg & 0x0F); + + setprg32r(FLASHROM ? 0x10 : 0, 0x8000, prg); + setchr8(chr); + setntamem(CHRptr[0] + VRAM_OFFSET(0) + (nt << 13), 1, 0); + setntamem(CHRptr[0] + VRAM_OFFSET(1) + (nt << 13), 1, 1); + setntamem(CHRptr[0] + VRAM_OFFSET(2) + (nt << 13), 1, 2); + setntamem(CHRptr[0] + VRAM_OFFSET(3) + (nt << 13), 1, 3); +} + +static DECLFR(M111ReadOB) { + reg = cpu.openbus; + Sync(); + return reg; +} + +static DECLFW(M111WriteReg) { + reg = V; + Sync(); +} + +static DECLFR(M111ReadFlash) { + return FlashROM_Read(A); +} + +static DECLFW(M111WriteFlash) { + FlashROM_Write(A, V); +} + +static void M111CPUCycle(int a) { + FlashROM_CPUCyle(a); +} + +static void M111Power(void) { + reg = 0xFF; + Sync(); + + SetReadHandler(0x5000, 0x5FFF, M111ReadOB); + SetReadHandler(0x7000, 0x7FFF, M111ReadOB); + + SetWriteHandler(0x5000, 0x5FFF, M111WriteReg); + SetWriteHandler(0x7000, 0x7FFF, M111WriteReg); + + SetReadHandler(0x8000, 0xFFFF, M111ReadFlash); + SetWriteHandler(0x8000, 0xFFFF, M111WriteFlash); +} + +static void M111Close(void) { + if (FLASHROM) { + FCEU_gfree(FLASHROM); + } + FLASHROM = NULL; +} + +static void StateRestore(int version) { + if (!UNIFchrrama) { + MMC1_FixPRG(); + MMC1_FixCHR(); + MMC1_FixMIR(); + return; + } + + Sync(); +} + +void Mapper111_Init(CartInfo *info) { + if (!UNIFchrrama) { + /* Prior to the introduction of GTROM, Mapper 111 was assigned to a Chinese Fan Translation + * of Ninja Ryukenden (Japanese Ninja Gaiden). This translation uses a non-serialized + * version of MMC1 and supports 256KiB of CHR-ROM, whereas the official MMC1 is limited to + * 128KiB */ + info->Power = M111Power_mmc1; + MMC1_pwrap = M111PW_mmc1; + MMC1_cwrap = M111CW_mmc1; + return; + } + + info->Power = M111Power; + info->Close = M111Close; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + + if (info->battery) { + int fsize = PRGsize[0]; + + FLASHROM = (uint8 *)FCEU_gmalloc(fsize); + info->SaveGame[0] = FLASHROM; + info->SaveGameLen[0] = fsize; + AddExState(FLASHROM, fsize, 0, "FROM"); + memcpy(FLASHROM, PRGptr[0], fsize); + SetupCartPRGMapping(0x10, FLASHROM, fsize, 0); + + FlashROM_Init(FLASHROM, fsize, 0xB7, 0xBF, 4096, 0x5555, 0x2AAA); + MapIRQHook = M111CPUCycle; + } +} diff --git a/src/boards/mapper112.c b/src/mappers/mapper112.c similarity index 68% rename from src/boards/mapper112.c rename to src/mappers/mapper112.c index 0e0763ec3..0cc0e97e2 100644 --- a/src/boards/mapper112.c +++ b/src/mappers/mapper112.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -24,63 +25,71 @@ #include "mapinc.h" static uint8 reg[8]; -static uint8 mirror, cmd, bank; -static uint8 *WRAM = NULL; +static uint8 mirror, cmd, chrBase; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { &cmd, 1, "CMD" }, { &mirror, 1, "MIRR" }, - { &bank, 1, "BANK" }, + { &chrBase, 1, "CHRB" }, { reg, 8, "REGS" }, { 0 } }; static void Sync(void) { - setmirror(mirror ^ 1); + setprg8r(0x10, 0x6000, 0); + setprg8(0x8000, reg[0]); setprg8(0xA000, reg[1]); + setprg16(0xC000, ~0); + setchr2(0x0000, (reg[2] >> 1)); setchr2(0x0800, (reg[3] >> 1)); - setchr1(0x1000, ((bank & 0x10) << 4) | reg[4]); - setchr1(0x1400, ((bank & 0x20) << 3) | reg[5]); - setchr1(0x1800, ((bank & 0x40) << 2) | reg[6]); - setchr1(0x1C00, ((bank & 0x80) << 1) | reg[7]); + setchr1(0x1000, ((chrBase << 4) & 0x100) | reg[4]); + setchr1(0x1400, ((chrBase << 3) & 0x100) | reg[5]); + setchr1(0x1800, ((chrBase << 2) & 0x100) | reg[6]); + setchr1(0x1C00, ((chrBase << 1) & 0x100) | reg[7]); + + setmirror((mirror & 0x01) ^ 0x01); } static DECLFW(M112Write) { - switch (A) { - case 0xe000: - mirror = V & 1; - Sync(); - break; - case 0x8000: - cmd = V & 7; - break; - case 0xa000: - reg[cmd] = V; - Sync(); - break; - case 0xc000: - bank = V; - Sync(); - break; + switch (A & 0xE000) { + case 0x8000: + cmd = V; + break; + case 0xA000: + reg[cmd & 0x07] = V; + Sync(); + break; + case 0xC000: + chrBase = V; + Sync(); + break; + case 0xE000: + mirror = V; + Sync(); + break; } } static void M112Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; } static void M112Power(void) { - bank = 0; - setprg16(0xC000, ~0); - setprg8r(0x10, 0x6000, 0); + reg[0] = 0; + reg[1] = 1; + reg[2] = 0; + reg[3] = 2; + reg[4] = 4; + reg[5] = 5; + reg[6] = 6; + reg[7] = 7; + chrBase = 0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0xFFFF, M112Write); - SetWriteHandler(0x4020, 0x5FFF, M112Write); + SetReadHandler(0x6000, 0x7FFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); FCEU_CheatAddRAM(8, 0x6000, WRAM); @@ -94,8 +103,9 @@ void Mapper112_Init(CartInfo *info) { info->Power = M112Power; info->Close = M112Close; GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + WRAM = (uint8 *)FCEU_gmalloc(8192); SetupCartPRGMapping(0x10, WRAM, 8192, 1); AddExState(WRAM, 8192, 0, "WRAM"); - AddExState(&StateRegs, ~0, 0, 0); } diff --git a/src/boards/mapper113.c b/src/mappers/mapper113.c similarity index 81% rename from src/boards/mapper113.c rename to src/mappers/mapper113.c index 3a4da2129..1ef59d4fa 100644 --- a/src/boards/mapper113.c +++ b/src/mappers/mapper113.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,16 +22,15 @@ static uint8 reg; -static SFORMAT StateRegs[] = -{ - { ®, 1, "REG" }, +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, { 0 } }; -static void Sync() { - setprg32(0x8000, (reg >> 3) & 7); - setchr8(((reg >> 3) & 8) | (reg & 7)); - setmirror(reg >> 7); +static void Sync(void) { + setprg32(0x8000, (reg >> 3) & 0x07); + setchr8(((reg >> 3) & 0x08) | (reg & 0x07)); + setmirror(reg >> 0x07); } static DECLFW(M113Write) { @@ -55,5 +54,5 @@ static void StateRestore(int version) { void Mapper113_Init(CartInfo *info) { info->Power = M113Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper114.c b/src/mappers/mapper114.c new file mode 100644 index 000000000..f60b39857 --- /dev/null +++ b/src/mappers/mapper114.c @@ -0,0 +1,117 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 reg[2]; +static uint8 dipsw; + +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, + { &dipsw, 1, "DPSW" }, + { 0 } +}; + +static uint32 M114_addr[2][8] = { + { 0xA001, 0xA000, 0x8000, 0xC000, 0x8001, 0xC001, 0xE000, 0xE001 }, /* 0: Aladdin, The Lion King */ + { 0xA001, 0x8001, 0x8000, 0xC001, 0xA000, 0xC000, 0xE000, 0xE001 } /* 1: Boogerman */ +}; + +static uint8 M114_index[2][8] = { + { 0, 3, 1, 5, 6, 7, 2, 4 }, /* 0: Aladdin, The Lion King */ + { 0, 2, 5, 3, 6, 1, 7, 4 }, /* 1: Boogerman */ +}; + +static void M114PW(uint32 A, uint8 V) { + if (reg[0] & 0x80) { + uint8 bank = reg[0] & 0x0F; + + if (reg[0] & 0x20) { + setprg32(0x8000, bank >> 1); + } else { + setprg16(0x8000, bank); + setprg16(0xC000, bank); + } + } else { + setprg8(A, V & 0x3F); + } +} + +static void M114CW(uint32 A, uint8 V) { + setchr1(A, ((reg[1] << 8) & 0x100) | (V & 0x0FF)); +} + +static DECLFW(M114WriteReg) { + reg[A & 0x01] = V; + MMC3_FixPRG(); + MMC3_FixCHR(); +} + +static DECLFW(M114Write) { + A = M114_addr[iNESCart.submapper & 0x01][((A >> 12) & 0x06) | (A & 0x01)]; + switch (A & 0xE001) { + case 0x8000: + V = (V & 0xF8) | M114_index[iNESCart.submapper & 0x01][V & 0x07]; + MMC3_CMDWrite(A, V); + break; + default: + MMC3_Write(A, V); + break; + } +} + +static DECLFR(M114ReadDip) { + if ((A & 0x03) == 0x02) { + return (cpu.openbus & ~0x07) | (dipsw & 0x07); + } + return cpu.openbus; +} + +static void M114Power(void) { + reg[0] = reg[1] = 0; + MMC3_Power(); + SetReadHandler(0x6000, 0x7FFF, M114ReadDip); + SetWriteHandler(0x6000, 0x7FFF, M114WriteReg); + SetWriteHandler(0x8000, 0xFFFF, M114Write); +} + +static void M114Reset(void) { + reg[0] = reg[1] = 0; + dipsw++; + MMC3_Reset(); +} + +void Mapper114_Init(CartInfo *info) { + isRevB = 0; + /* Use NES 2.0 submapper to identify scrambling pattern, otherwise CRC32 for Boogerman and test rom */ + if (!info->iNES2) { + if ((info->CRC32 == 0x80eb1839) || (info->CRC32 == 0x071e4ee8)) { + info->submapper = 1; + } + } + + MMC3_Init(info, 0, 0); + MMC3_pwrap = M114PW; + MMC3_cwrap = M114CW; + info->Power = M114Power; + info->Reset = M114Reset; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper115.c b/src/mappers/mapper115.c new file mode 100644 index 000000000..9afb6a940 --- /dev/null +++ b/src/mappers/mapper115.c @@ -0,0 +1,67 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 reg[2]; + +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, + { 0 } +}; + +static void M115PW(uint32 A, uint8 V) { + if (reg[0] & 0x80) { + uint8 bank = reg[0] & 0x0F; + + if (reg[0] & 0x20) { + setprg32(0x8000, bank >> 1); + } else { + setprg16(0x8000, bank); + setprg16(0xC000, bank); + } + } else { + setprg8(A, V & 0x3F); + } +} + +static void M115CW(uint32 A, uint8 V) { + setchr1(A, ((reg[1] << 8) & 0x100) | (V & 0xFF)); +} + +static DECLFW(M115WriteReg) { + reg[A & 0x01] = V; + MMC3_FixPRG(); + MMC3_FixCHR(); +} + +static void M115Power(void) { + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M115WriteReg); +} + +void Mapper115_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_cwrap = M115CW; + MMC3_pwrap = M115PW; + info->Power = M115Power; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper116.c b/src/mappers/mapper116.c new file mode 100644 index 000000000..492182591 --- /dev/null +++ b/src/mappers/mapper116.c @@ -0,0 +1,208 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2011 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + * SL12 Protected 3-in-1 mapper hardware (VRC2, MMC3, MMC1) + * the same as 603-5052 board (TODO: add reading registers, merge) + * SL1632 2-in-1 protected board, similar to SL12 (TODO: find difference) + * + * Known PCB: + * + * Garou Densetsu Special (G0904.PCB, Huang-1, GAL dip: W conf.) + * Kart Fighter (008, Huang-1, GAL dip: W conf.) + * Somari (008, C5052-13, GAL dip: P conf., GK2-P/GK2-V maskroms) + * Somari (008, Huang-1, GAL dip: W conf., GK1-P/GK1-V maskroms) + * AV Mei Shao Nv Zhan Shi (aka AV Pretty Girl Fighting) (SL-12 PCB, Hunag-1, GAL dip: unk conf. SL-11A/SL-11B maskroms) + * Samurai Spirits (Full version) (Huang-1, GAL dip: unk conf. GS-2A/GS-4A maskroms) + * Contra Fighter (603-5052 PCB, C5052-3, GAL dip: unk conf. SC603-A/SCB603-B maskroms) + * + */ + +#include "mapinc.h" +#include "vrc2and4.h" +#include "mmc3.h" +#include "mmc1.h" + +#define MODE_MMC1 mode & 0x02 +#define MODE_MMC3 mode & 0x01 + +static uint8 mode = 0; +static uint8 game = 0; + +static SFORMAT StateRegs[] = { + { &mode, 1, "MODE"}, + { &game, 1, "GAME"}, + { 0 } +}; + +static uint32 GetPRGMask(void) { + if (iNESCart.submapper != 3) { + return 0x3F; + } + return (game ? 0x0F : 0x1F); +} + +static uint32 GetPRGBase(void) { + if (game) { + return (game + 1) * 0x10; + } + return 0; +} + +static uint32 GetCHRMask(void) { + return (game ? 0x7F : 0xFF); +} + +static uint32 GetCHRBase(void) { + return (game ? (game + 1) * 0x80 : 0); +} + +static void M116PW_vrc2(uint32 A, uint8 V) { + setprg8(A, GetPRGBase() | (V & GetPRGMask())); +} + +static void M116CW_vrc2(uint32 A, uint32 V) { + setchr1(A, ((mode << 6) & 0x100) | GetCHRBase() | (V & GetCHRMask())); +} + +static void M116PW_mmc3(uint32 A, uint8 V) { + setprg8(A, GetPRGBase() | (V & GetPRGMask())); +} + +static void M116CW_mmc3(uint32 A, uint8 V) { + setchr1(A, ((mode << 6) & 0x100) | GetCHRBase() | (V & GetCHRMask())); +} + +static void M116PW_mmc1(uint32 A, uint8 V) { + if (iNESCart.submapper == 2) { + setprg16(A, V >> 1); + } else { + setprg16(A, (GetPRGBase() >> 1) | (V & (GetPRGMask() >> 1))); + } +} + +static void M116CW_mmc1(uint32 A, uint8 V) { + setchr4(A, (GetCHRBase() >> 2) | (V & (GetCHRMask() >> 2))); +} + +static void Sync(void) { + if (MODE_MMC1) { + MMC1_FixPRG(); + MMC1_FixCHR(); + MMC1_FixMIR(); + } else if (MODE_MMC3) { + MMC3_FixPRG(); + MMC3_FixCHR(); + MMC3_FixMIR(); + } else { + VRC24_FixPRG(); + VRC24_FixCHR(); + VRC24_FixMIR(); + } +} + +static void applyMode(void) { + if (MODE_MMC1) { + SetWriteHandler(0x8000, 0xFFFF, MMC1_Write); + if (iNESCart.submapper != 1) { + MMC1_Write(0x8000, 0x80); + } + } else if (MODE_MMC3) { + SetWriteHandler(0x8000, 0xFFFF, MMC3_Write); + } else { + SetWriteHandler(0x8000, 0xFFFF, VRC24_Write); + } +} + +static DECLFW(M116ModeWrite) { + if (A & 0x100) { + mode = V; + applyMode(); + Sync(); + } +} + +static void M116HBIRQ(void) { + if ((mode & 0x03) == 0x01) { + MMC3_IRQHBHook(); + } +} + +static void StateRestore(int version) { + Sync(); +} + +static void M116Reset(void) { + if (iNESCart.submapper == 3) { + game = game + 1; + if (game > 4) { + game = 0; + } + } + applyMode(); + Sync(); +} + +static void M116Power(void) { + game = (iNESCart.submapper == 3) ? 4 : 0; + mode = 1; + + MMC3_Power(); + MMC1_Reset(); + VRC24_Power(); + + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x4100, 0x5FFF, M116ModeWrite); + + vrc24.chr[0] = ~0; + vrc24.chr[1] = ~0; + vrc24.chr[2] = ~0; + vrc24.chr[3] = ~0; + + applyMode(); + Sync(); +} + +void Mapper116_Init(CartInfo *info) { + VRC24_Init(info, VRC2, 0x01, 0x02, FALSE, TRUE); + VRC24_pwrap = M116PW_vrc2; + VRC24_cwrap = M116CW_vrc2; + + MMC3_Init(info, FALSE, FALSE); + MMC3_pwrap = M116PW_mmc3; + MMC3_cwrap = M116CW_mmc3; + + MMC1_Init(info, FALSE, FALSE); + MMC1_pwrap = M116PW_mmc1; + MMC1_cwrap = M116CW_mmc1; + mmc1_type = MMC1A; + + info->Power = M116Power; + info->Reset = M116Reset; + + GameHBIRQHook = M116HBIRQ; + + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + + /* PRG 128K and CHR 128K is Huang-2 (iNESCart.submapper 2) */ + if (((ROM.prg.size * 16) == 128) && ((ROM.chr.size * 8) == 128)) { + info->submapper = 2; + } +} diff --git a/src/boards/mapper117.c b/src/mappers/mapper117.c similarity index 56% rename from src/boards/mapper117.c rename to src/mappers/mapper117.c index 1b7addf0a..15ded86d5 100644 --- a/src/boards/mapper117.c +++ b/src/mappers/mapper117.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2002 Xodnizel + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -20,67 +21,81 @@ #include "mapinc.h" -static uint8 prgreg[4], chrreg[8], mirror; +static uint8 prg[4], chr[8], mirr; static uint8 IRQa, IRQCount, IRQLatch; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { + { prg, 4, "PREG" }, + { chr, 8, "CREG" }, + { &mirr, 1, "MREG" }, { &IRQa, 1, "IRQA" }, { &IRQCount, 1, "IRQC" }, { &IRQLatch, 1, "IRQL" }, - { prgreg, 4, "PREG" }, - { chrreg, 8, "CREG" }, - { &mirror, 1, "MREG" }, { 0 } }; static void Sync(void) { - int i; - setprg8(0x8000, prgreg[0]); - setprg8(0xa000, prgreg[1]); - setprg8(0xc000, prgreg[2]); - setprg8(0xe000, prgreg[3]); - for (i = 0; i < 8; i++) - setchr1(i << 10, chrreg[i]); - setmirror(mirror ^ 1); + setprg8(0x8000, prg[0]); + setprg8(0xA000, prg[1]); + setprg8(0xC000, prg[2]); + setprg8(0xE000, ~0); + + setchr1(0x0000, chr[0]); + setchr1(0x0400, chr[1]); + setchr1(0x0800, chr[2]); + setchr1(0x0C00, chr[3]); + setchr1(0x1000, chr[4]); + setchr1(0x1400, chr[5]); + setchr1(0x1800, chr[6]); + setchr1(0x1C00, chr[7]); + + setmirror(mirr ^ 1); } static DECLFW(M117Write) { - if (A < 0x8004) { - prgreg[A & 3] = V; - Sync(); - } else if ((A >= 0xA000) && (A <= 0xA007)) { - chrreg[A & 7] = V; + switch (A & 0xF000) { + case 0x8000: + prg[A & 0x03] = V; Sync(); - } else { - switch (A) { - case 0xc001: - IRQLatch = V; - break; - case 0xc003: - IRQCount = IRQLatch; - IRQa |= 2; - break; - case 0xe000: - IRQa &= ~1; - IRQa |= V & 1; - X6502_IRQEnd(FCEU_IQEXT); - break; - case 0xc002: - X6502_IRQEnd(FCEU_IQEXT); - break; - case 0xd000: - mirror = V & 1; - break; + break; + case 0xA000: + switch (A & 0x0F) { + case 0: case 1: case 2: case 3: + case 4: case 5: case 6: case 7: + chr[A & 0x07] = V; + Sync(); + break; } + break; + case 0xC000: + switch (A & 0x03) { + case 1: + IRQLatch = V; + break; + case 3: + IRQCount = IRQLatch; + IRQa |= 2; + break; + } + X6502_IRQEnd(FCEU_IQEXT); + break; + case 0xD000: + mirr = V & 1; + Sync(); + break; + case 0xE000: + IRQa &= ~1; + IRQa |= V & 1; + X6502_IRQEnd(FCEU_IQEXT); + break; } } static void M117Power(void) { - prgreg[0] = ~3; - prgreg[1] = ~2; - prgreg[2] = ~1; - prgreg[3] = ~0; + prg[0] = ~3; + prg[1] = ~2; + prg[2] = ~1; + prg[3] = ~0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0xFFFF, M117Write); @@ -104,5 +119,5 @@ void Mapper117_Init(CartInfo *info) { info->Power = M117Power; GameHBIRQHook = M117IRQHook; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper118.c b/src/mappers/mapper118.c new file mode 100644 index 000000000..a6be1fa8f --- /dev/null +++ b/src/mappers/mapper118.c @@ -0,0 +1,75 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static void M118MIR(void) { + if (mmc3.cmd & 0x80) { + setntamem(NTARAM + 0x400 * ((mmc3.reg[2] >> 7) & 0x01), 1, 0); + setntamem(NTARAM + 0x400 * ((mmc3.reg[3] >> 7) & 0x01), 1, 1); + setntamem(NTARAM + 0x400 * ((mmc3.reg[4] >> 7) & 0x01), 1, 2); + setntamem(NTARAM + 0x400 * ((mmc3.reg[5] >> 7) & 0x01), 1, 3); + } else { + setntamem(NTARAM + 0x400 * ((mmc3.reg[0] >> 7) & 0x01), 1, 0); + setntamem(NTARAM + 0x400 * ((mmc3.reg[0] >> 7) & 0x01), 1, 1); + setntamem(NTARAM + 0x400 * ((mmc3.reg[1] >> 7) & 0x01), 1, 2); + setntamem(NTARAM + 0x400 * ((mmc3.reg[1] >> 7) & 0x01), 1, 3); + } +} + +static DECLFW(M118Write) { + switch (A & 0xE001) { + case 0x8001: + switch (mmc3.cmd & 0x07) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + mmc3.reg[mmc3.cmd & 0x07] = V; + MMC3_FixCHR(); + MMC3_FixMIR(); + break; + default: + MMC3_CMDWrite(A, V); + break; + } + case 0xA000: + /* MMC3 mirroring not used in favor of nametable mirroring */ + break; + default: + MMC3_CMDWrite(A, V); + break; + } +} + +static void M118Power(void) { + MMC3_Power(); + SetWriteHandler(0x8000, 0xBFFF, M118Write); +} + +void Mapper118_Init(CartInfo *info) { + uint8 ws = info->iNES2 ? (info->PRGRamSize + info->PRGRamSaveSize) / 1024 : 8; + MMC3_Init(info, ws, info->battery); + info->Power = M118Power; + MMC3_FixMIR = M118MIR; +} diff --git a/src/mappers/mapper119.c b/src/mappers/mapper119.c new file mode 100644 index 000000000..d1256bdee --- /dev/null +++ b/src/mappers/mapper119.c @@ -0,0 +1,51 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 *CHRRAM = NULL; +static uint32 CHRRAMSIZE = 0; + +static void M119CW(uint32 A, uint8 V) { + if (V & 0x40) { + setchr1r(0x10, A, V & 0x07); + } else { + setchr1(A, V); + } +} + +static void M119Close(void) { + MMC3_Close(); + if (CHRRAM) { + FCEU_free(CHRRAM); + CHRRAM = NULL; + } +} + +void Mapper119_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + info->Close = M119Close; + MMC3_cwrap = M119CW; + CHRRAMSIZE = 8192; + CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); +} diff --git a/src/boards/mapper120.c b/src/mappers/mapper120.c similarity index 87% rename from src/boards/mapper120.c rename to src/mappers/mapper120.c index bdc8dd50f..f99abd7d4 100644 --- a/src/boards/mapper120.c +++ b/src/mappers/mapper120.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2007 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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,8 +26,7 @@ static uint8 reg; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { ®, 1, "REG" }, { 0 } }; @@ -38,8 +38,8 @@ static void Sync(void) { } static DECLFW(M120Write) { - if (A == 0x41FF) { - reg = V & 7; + if ((A & 0xE100) == 0x4100) { + reg = V & 0x07; Sync(); } } @@ -58,5 +58,5 @@ static void StateRestore(int version) { void Mapper120_Init(CartInfo *info) { info->Power = M120Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper121.c b/src/mappers/mapper121.c new file mode 100644 index 000000000..efd723dbd --- /dev/null +++ b/src/mappers/mapper121.c @@ -0,0 +1,129 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2007-2008 Mad Dumper, CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + * Panda prince pirate. + * MK4, MK6, A9711/A9713 board + * 6035052 seems to be the same too, but with prot array in reverse + * A9746 seems to be the same too, check + * 187 seems to be the same too, check (A98402 board) + * + */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 prg[3]; +static uint8 reg; +static uint8 readIndex; +static uint8 protIndex; +static uint8 protLatch; + +static SFORMAT StateRegs[] = { + { prg, 3, "PREG" }, + { ®, 2, "REGS" }, + { &readIndex, 1, "PRRD" }, + { &protIndex, 1, "PRID" }, + { &protLatch, 1, "PRLT" }, + { 0 } +}; + +static void M121CW(uint32 A, uint8 V) { + if ((ROM.prg.size * 16) > 256) { + setchr1(A, ((reg & 0x80) << 1) | V); + } else { + if ((A & 0x1000) == (uint32)((mmc3.cmd & 0x80) << 5)){ + setchr1(A, 0x100 | V); + } else { + setchr1(A, V); + } + } +} + +static void M121PW(uint32 A, uint8 V) { + uint8 mask = 0x1F; + uint8 base = ((reg & 0x80) >> 2); + + if ((protIndex & 0x20) && (A > 0x8000)) { + mask = 0xFF; + V = prg[((A >> 13) & 0x03) - 1]; + } + + setprg8(A, base | (V & mask)); +} + +static const uint8 prot_array[] = { 0x83, 0x83, 0x42, 0x00, 0x00, 0x02, 0x02, 0x03 }; +static DECLFR(M121ReadLUT) { + return prot_array[readIndex]; +} + +static DECLFW(M121WriteLUT) { + readIndex = ((A >> 6) & 0x04) | (V & 0x03); + if (A & 0x0100) { + reg = V; + MMC3_FixPRG(); + MMC3_FixCHR(); + } +} + +static DECLFW(M121Write) { + switch (A & 0xE001) { + case 0x8001: + switch (A & 0x03) { + case 0x01: + protLatch = ((V & 0x01) << 5) | ((V & 0x02) << 3) | + ((V & 0x04) << 1) | ((V & 0x08) >> 1) | + ((V & 0x10) >> 3) | ((V & 0x20) >> 5); + if ((protIndex == 0x26) || (protIndex == 0x28) || (protIndex == 0x2A)) { + prg[0x15 - (protIndex >> 1)] = protLatch; + } + break; + case 0x03: + protIndex = V & 0x3F; + if ((protIndex & 0x20) && protLatch) { + prg[2] = protLatch; + } + break; + } + mmc3.reg[mmc3.cmd & 0x07] = V; + MMC3_FixPRG(); + MMC3_FixCHR(); + break; + default: + MMC3_CMDWrite(A, V); + break; + } +} + +static void M121Power(void) { + memset(prg, 0, sizeof(prg)); + reg = readIndex = protIndex = protLatch = 0; + MMC3_Power(); + SetReadHandler(0x5000, 0x5FFF, M121ReadLUT); + SetWriteHandler(0x5000, 0x5FFF, M121WriteLUT); + SetWriteHandler(0x8000, 0x9FFF, M121Write); +} + +void Mapper121_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_pwrap = M121PW; + MMC3_cwrap = M121CW; + info->Power = M121Power; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/h2288.c b/src/mappers/mapper123.c similarity index 57% rename from src/boards/h2288.c rename to src/mappers/mapper123.c index 6fd16e0c1..f28461381 100644 --- a/src/boards/h2288.c +++ b/src/mappers/mapper123.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -23,14 +24,15 @@ #include "mapinc.h" #include "mmc3.h" -extern uint8 m114_perm[8]; +static uint8 reg; -static void H2288PW(uint32 A, uint8 V) { - if (mmc3.expregs[0] & 0x40) { - uint8 bank = (mmc3.expregs[0] & 5) | ((mmc3.expregs[0] & 8) >> 2) | ((mmc3.expregs[0] & 0x20) >> 2); - if (mmc3.expregs[0] & 2) +static void M123PW(uint32 A, uint8 V) { + if (reg & 0x40) { + uint8 bank = ((reg & 0x28) >> 2) | (reg & 0x05); + + if (reg & 2) { setprg32(0x8000, bank >> 1); - else { + } else { setprg16(0x8000, bank); setprg16(0xC000, bank); } @@ -39,30 +41,33 @@ static void H2288PW(uint32 A, uint8 V) { } } -static DECLFW(H2288WriteHi) { - if (!(A & 1)) { - V = (V & 0xC0) | (m114_perm[V & 7]); +static DECLFW(M123WriteHi) { + static const uint8 m114_perm[8] = { 0, 3, 1, 5, 6, 7, 2, 4 }; + + if (!(A & 0x01)) { + V = (V & 0xC0) | m114_perm[V & 0x07]; } + MMC3_CMDWrite(A, V); } -static DECLFW(H2288WriteLo) { +static DECLFW(M123WriteLo) { if (A & 0x800) { - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); + reg = V; + MMC3_FixPRG(); } } -static void H2288Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); - SetWriteHandler(0x5000, 0x5FFF, H2288WriteLo); - SetWriteHandler(0x8000, 0x9FFF, H2288WriteHi); +static void M123Power(void) { + reg = 0; + MMC3_Power(); + SetWriteHandler(0x5000, 0x5FFF, M123WriteLo); + SetWriteHandler(0x8000, 0x9FFF, M123WriteHi); } -void UNLH2288_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 0, 0); - mmc3.pwrap = H2288PW; - info->Power = H2288Power; - AddExState(mmc3.expregs, 1, 0, "EXPR"); +void Mapper123_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_pwrap = M123PW; + info->Power = M123Power; + AddExState(®, 1, 0, "EXPR"); } diff --git a/src/mappers/mapper124.c b/src/mappers/mapper124.c new file mode 100644 index 000000000..3a10769b4 --- /dev/null +++ b/src/mappers/mapper124.c @@ -0,0 +1,242 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + */ + +/* iNES mapper 124 is assigned to the Super Game Mega Type III pirate arcade board. */ + +#include "mapinc.h" +#include "mmc1.h" +#include "mmc3.h" +#include "latch.h" + +#define MAPPER_UNROM 0 +#define MAPPER_AMROM 1 +#define MAPPER_MMC1 2 +#define MAPPER_MMC3 3 + +static uint8 reg[2]; +static uint8 mapper; +static uint8 dipsw; + +static uint8 *CHRRAM = NULL; +static uint32 CHRRAMSIZE; + +static uint8 audioEnable; +static uint8 *mRAM; + +static SFORMAT StateRegs[] = { + { reg, 2, "MODE" }, + { &mapper, 1, "MAPR" }, + { 0 } +}; + +static uint32 GetPRGBase(void) { + return ((reg[1] << 4) & 0x1F0); +} + +static uint32 GetCHRBase(void) { + return ((reg[0] << 7) & 0x780); +} + +static void M124PW_mmc1(uint32 A, uint8 V) { + setprg16(A, (GetPRGBase() >> 1) | (V & 0x07)); +} + +static void M124CW_mmc1(uint32 A, uint8 V) { + setchr4(A, (GetCHRBase() >> 2) | (V & 0x1F)); +} + +static void M124PW_mmc3(uint32 A, uint8 V) { + uint16 mask = (reg[1] & 0x20) ? 0x0F : 0x1F; + setprg8(A, GetPRGBase() | (V & mask)); +} + +static void M124CW_mmc3(uint32 A, uint8 V) { + uint16 mask = (reg[0] & 0x40) ? 0x7F : 0xFF; + setchr1(A, GetCHRBase() | (V & mask)); +} + +static void Sync(void) { + switch (mapper) { + case MAPPER_UNROM: + setprg16(0x8000, (GetPRGBase() >> 1) | (latch.data & 0x07)); + setprg16(0xC000, (GetPRGBase() >> 1) | 0x07); + setchr8(0); + setmirror(MI_V); + break; + case MAPPER_AMROM: + setprg32(0x8000, (GetPRGBase() >> 2) | (latch.data & 0x07)); + setchr8(0); + setmirror(MI_0 + ((latch.data >> 4) & 1)); + break; + case MAPPER_MMC1: + setprg16r(0x10, 0x6000, 0); + MMC1_FixPRG(); + MMC1_FixCHR(); + MMC1_FixMIR(); + break; + case MAPPER_MMC3: + setprg16r(0x10, 0x6000, 0); + MMC3_FixPRG(); + MMC3_FixCHR(); + MMC3_FixMIR(); + break; + } + setprg4(0x5000, 0x380 + 0x05); + if (reg[1] & 0x20) { + setprg8(0x6000, (0x380 + 0x06) >> 1); + } + if (!(reg[1] & 0x80)) { + setprg32(0x8000, (0x380 + 0x08) >> 3); + } + if (!(reg[1] & 0x40)) { + setchr8r(0x10, 0); + } +} + +static void applyMode(void) { + mapper = (reg[0] >> 4) & 0x03; +} + +static DECLFR(ReadRAM) { + return mRAM[A]; +} + +static DECLFW(WriteRAM) { + mRAM[A] = V; +} + +#include "vsuni.h" +static DECLFR(M124ReadCoinDIP) { + if ((A & 0x0F) == 0x0F) { + /* TODO: Hack to use VS' coin insert map to use as mappers coin insert trigger */ + return ((vsuni_system.coinon[0] ? 0x80 : 0x00) | (dipsw & 0x7F)); + } + return cpu.openbus; +} + +static DECLFW(M124WriteReg) { + if (A & 0x10) { + audioEnable = V; + } else { + reg[A & 0x01] = V; + applyMode(); + Sync(); + } +} + +static DECLFW(M124Write) { + switch (mapper) { + case MAPPER_UNROM: + case MAPPER_AMROM: + Latch_Write(A, V); + break; + case MAPPER_MMC3: + MMC3_Write(A, V); + break; + case MAPPER_MMC1: + MMC1_Write(A, V); + break; + } +} + +static void M124Close(void) { + if (mRAM) { + FCEU_gfree(mRAM); + mRAM = NULL; + } + if (CHRRAM) { + FCEU_gfree(CHRRAM); + CHRRAM = NULL; + } +} + +static void M124Reset(void) { + dipsw++; + Sync(); +} + +static void M124Power(void) { + FCEU_MemoryRand(mRAM, 4096); + memset(reg, 0, sizeof(reg)); + mapper = 0; + dipsw = 0; + + MMC1_Reset(); + MMC3_Reset(); + Latch_RegReset(); + + SetReadHandler(0x0000, 0x0FFF, ReadRAM); + SetWriteHandler(0x0000, 0x0FFF, WriteRAM); + + SetReadHandler(0x4F00, 0x4FFF, M124ReadCoinDIP); + + SetReadHandler(0x5000, 0xFFFF, CartBR); + SetWriteHandler(0x5000, 0x5FFF, M124WriteReg); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + SetWriteHandler(0x8000, 0xFFFF, M124Write); + + applyMode(); + Sync(); +} + +static void M124HBIRQHook(void) { + if (mapper == MAPPER_MMC3) { + MMC3_IRQHBHook(); + } +} + +static void StateRestore(int version) { + applyMode(); + Sync(); +} + +void Mapper124_Init(CartInfo *info) { + MMC1_Init(info, FALSE, FALSE); + MMC1_pwrap = M124PW_mmc1; + MMC1_cwrap = M124CW_mmc1; + mmc1_type = MMC1A; + + MMC3_Init(info, FALSE, FALSE); + MMC3_pwrap = M124PW_mmc3; + MMC3_cwrap = M124CW_mmc3; + + Latch_Init(info, Sync, NULL, FALSE, TRUE); + + info->Power = M124Power; + info->Reset = M124Reset; + info->Close = M124Close; + GameHBIRQHook = M124HBIRQHook; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + + WRAMSIZE = 8192; + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, TRUE); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + + mRAM = (uint8 *)FCEU_gmalloc(4096); + AddExState(mRAM, 4096, 0, "mRAM"); + + CHRRAMSIZE = 8192; + CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, TRUE); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); +} diff --git a/src/boards/lh32.c b/src/mappers/mapper125.c similarity index 69% rename from src/boards/lh32.c rename to src/mappers/mapper125.c index b0635a98f..e8c0f29d9 100644 --- a/src/boards/lh32.c +++ b/src/mappers/mapper125.c @@ -1,4 +1,4 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2007 CaH4e3 @@ -17,65 +17,60 @@ * 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 - Monty no Doki Doki Daisassō, Monty on the Run, cartridge code LH32 + * NES 2.0 Mapper 125 - UNL-M125 + * FDS Conversion - Monty no Doki Doki Daisassō, Monty on the Run, cartridge code M125 * */ #include "mapinc.h" -#include "../fds_apu.h" +#include "fdssound.h" -static uint8 reg; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint8 prg; -static SFORMAT StateRegs[] = -{ - { ®, 1, "REG" }, +static SFORMAT StateRegs[] = { + { &prg, 1, "PREG" }, { 0 } }; static void Sync(void) { - setprg8(0x6000, reg); + setprg8(0x6000, prg); setprg8(0x8000, ~3); setprg8(0xa000, ~2); - setprg8r(0x10, 0xc000, 0); - setprg8(0xe000, ~0); + setprg8r(0x10, 0xC000, 0); + setprg8(0xE000, ~0); setchr8(0); } -static DECLFW(LH32Write) { - reg = V; +static DECLFW(M125WritePRG) { + prg = V; Sync(); } -static void LH32Power(void) { - FDSSoundPower(); +static void M125Power(void) { + prg = 0; Sync(); + FDSSound_Power(); SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x6000, M125WritePRG); SetWriteHandler(0xC000, 0xDFFF, CartBW); - SetWriteHandler(0x6000, 0x6000, LH32Write); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } -static void LH32Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; +static void M125Close(void) { } static void StateRestore(int version) { Sync(); } -void LH32_Init(CartInfo *info) { - info->Power = LH32Power; - info->Close = LH32Close; +void Mapper125_Init(CartInfo *info) { + info->Power = M125Power; + info->Close = M125Close; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); WRAMSIZE = 8192; WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); } diff --git a/src/mappers/mapper126.c b/src/mappers/mapper126.c new file mode 100644 index 000000000..875c2be70 --- /dev/null +++ b/src/mappers/mapper126.c @@ -0,0 +1,147 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 422: "Normal" version of the mapper. Represents UNIF boards BS-400R and BS-4040R. + * Mapper 126: Power Joy version of the mapper, connecting CHR A18 and A19 in reverse order. + * Mapper 534: Waixing version of the mapper, inverting the reload value of the MMC3 scanline counter. + */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 reg[4]; +static uint8 dipsw; + +static SFORMAT StateRegs[] = { + { reg, 4, "REGS" }, + { &dipsw, 1, "DPSW" }, + { 0 } +}; + +static void M126PW(uint32 A, uint8 V) { + uint16 mask = (reg[0] & 0x40) ? 0x0F : 0x1F; /* 128 KiB or 256 KiB inner PRG bank selection */ + uint16 base = (((reg[0] << 4) & 0x70) | ((reg[0] << 3) & 0x180)) & ~mask; /* outer PRG bank */ + + switch (iNESCart.submapper) { + case 1: /* uses PRG A21 as a chip select between two 1 MiB chips. */ + base |= ((base & 0x100) >> 1); + break; + case 2: /* uses $6001 bit 2 as a chip select between two 1 MiB chips. */ + base |= ((reg[1] & 0x02) << 5); + break; + } + + if (reg[3] & 0x03) { + if ((reg[3] & 0x03) == 0x03) { + setprg32(0x8000, (base | (mmc3.reg[6] & mask)) >> 2); + } else { + setprg16(0x8000, (base | (mmc3.reg[6] & mask)) >> 1); + setprg16(0xC000, (base | (mmc3.reg[6] & mask)) >> 1); + } + } else { + setprg8(A, (base & ~mask) | (V & mask)); + } +} + +static void M126CW(uint32 A, uint8 V) { + uint16 mask = (reg[0] & 0x80) ? 0x7F : 0xFF; /* 128 KiB or 256 KiB innter CHR bank selection */ + uint16 base; /* outer CHR bank */ + + if (iNESCart.mapper == 126) { + /* Mapper 126 swaps CHR A18 and A19 */ + base = ((reg[0] << 4) & 0x080) | ((reg[0] << 3) & 0x100) | ((reg[0] << 5) & 0x200); + } else { + base = (reg[0] << 4) & 0x380; + } + + if (reg[3] & 0x10) { + /* CNROM mode: 8 KiB inner CHR bank comes from outer bank register #2 */ + setchr8((reg[2] & (mask >> 3)) | ((base & ~mask) >> 3)); + } else { + /* MMC3 CHR mode */ + setchr1(A, (base & ~mask) | (V & mask)); + } +} + +static DECLFR(M126ReadDIP) { + if (reg[1] & 0x01) { + /* Replace bottom two bits with solder pad or DIP switch setting if so selected */ + return CartBR((A & ~0x03) | (dipsw & 0x03)); + } + return CartBR(A); +} + +static DECLFW(M126WriteWRAM) { + CartBW(A, V); + if (!(reg[3] & 0x80)) { /* Lock bit clear: Update any outer bank register */ + reg[A & 0x03] = V; + MMC3_FixPRG(); + } else if ((A & 0x03) == 2) { /* Lock bit set: Only update the bottom one or two bits of the CNROM bank */ + uint8 mask = ((reg[2] & 0x10) ? 0x01 : 0x03); + + reg[2] = (reg[2] & ~mask) | (V & mask); + } + MMC3_FixCHR(); +} + +static DECLFW(M534IRQWrite) { + /* Mapper 534 takes the inverted $C000 value for the scanline counter */ + V ^= 0xFF; + MMC3_IRQWrite(A, V); +} + +static void M126Reset(void) { + dipsw++; /* Soft-resetting cycles through solder pad or DIP switch settings */ + reg[0] = reg[1] = reg[2] = reg[3] = 0; + MMC3_Reset(); +} + +static void M126Power(void) { + dipsw = 0; + reg[0] = reg[1] = reg[2] = reg[3] = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M126WriteWRAM); + SetReadHandler(0x8000, 0xFFFF, M126ReadDIP); + if (iNESCart.mapper == 534) { + SetWriteHandler(0xC000, 0xDFFF, M534IRQWrite); + } +} + +void Mapper126_Init(CartInfo *info) { + uint8 ws = 8; + if (info->iNES2) { + ws = info->PRGRamSize + info->PRGRamSaveSize; + } + MMC3_Init(info, ws, info->battery); + MMC3_cwrap = M126CW; + MMC3_pwrap = M126PW; + info->Power = M126Power; + info->Reset = M126Reset; + AddExState(StateRegs, ~0, 0, NULL); +} + +void Mapper422_Init(CartInfo *info) { + Mapper126_Init(info); +} + +void Mapper534_Init(CartInfo *info) { + Mapper126_Init(info); +} diff --git a/src/boards/mapper127.c b/src/mappers/mapper127.c similarity index 65% rename from src/boards/mapper127.c rename to src/mappers/mapper127.c index 832d00a39..a1c15ea7b 100644 --- a/src/boards/mapper127.c +++ b/src/mappers/mapper127.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -20,13 +20,12 @@ #include "mapinc.h" -static uint8 preg[4], creg[8], nt[4], IRQa; -static uint8 IRQCount; +static uint8 prg[4], chr[8], nt[4]; +static uint8 IRQCount, IRQa; -static SFORMAT StateRegs[] = -{ - { preg, 4, "PREG" }, - { creg, 8, "CREG" }, +static SFORMAT StateRegs[] = { + { prg, 4, "PREG" }, + { chr, 8, "CREG" }, { nt, 4, "NTAM" }, { &IRQa, 1, "IRQA" }, { &IRQCount, 1, "IRQC" }, @@ -34,36 +33,34 @@ static SFORMAT StateRegs[] = }; static void Sync(void) { - setprg8(0x8000, preg[0]); - setprg8(0xA000, preg[1]); - setprg8(0xC000, preg[2]); - setprg8(0xE000, preg[3] | 0x0C); + prg[3] |= 0x0C; + setprg8(0x8000, prg[0] & 0x0F); + setprg8(0xA000, prg[1] & 0x0F); + setprg8(0xC000, prg[2] & 0x0F); + setprg8(0xE000, prg[3] & 0x0F); - 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]); + setchr1(0x0000, chr[0] & 0x7F); + setchr1(0x0400, chr[1] & 0x7F); + setchr1(0x0800, chr[2] & 0x7F); + setchr1(0x0C00, chr[3] & 0x7F); + setchr1(0x1000, chr[4] & 0x7F); + setchr1(0x1400, chr[5] & 0x7F); + setchr1(0x1800, chr[6] & 0x7F); + setchr1(0x1C00, chr[7] & 0x7F); - setntamem(NTARAM + ((nt[0] & 1) << 10), 1, 0); - setntamem(NTARAM + ((nt[1] & 1) << 10), 1, 1); - setntamem(NTARAM + ((nt[2] & 1) << 10), 1, 2); - setntamem(NTARAM + ((nt[3] & 1) << 10), 1, 3); + setmirrorw(nt[0] & 0x01, nt[1] & 0x01, nt[2] & 0x01, nt[3] & 0x01); } static DECLFW(M127Write) { switch (A & 0x73) { case 0x00: case 0x01: case 0x02: case 0x03: - preg[A & 3] = V; + prg[A & 3] = V; Sync(); break; case 0x10: case 0x11: case 0x12: case 0x13: case 0x20: case 0x21: case 0x22: case 0x23: - creg[((A >> 3) & 4) | (A & 3)] = V; + chr[((A >> 3) & 4) | (A & 3)] = V; Sync(); break; @@ -85,9 +82,9 @@ static DECLFW(M127Write) { } static void M127Power(void) { - preg[0] = preg[1] = preg[2] = preg[3] = ~0; - creg[0] = creg[1] = creg[2] = creg[3] = 0; - creg[4] = creg[5] = creg[6] = creg[7] = 0; + prg[0] = prg[1] = prg[2] = prg[3] = ~0; + chr[0] = chr[1] = chr[2] = chr[3] = 0; + chr[4] = chr[5] = chr[6] = chr[7] = 0; nt[0] = nt[1] = nt[2] = nt[3] = 0; IRQa = IRQCount = 0; Sync(); @@ -95,7 +92,7 @@ static void M127Power(void) { SetWriteHandler(0x8000, 0xFFFF, M127Write); } -static void FP_FASTAPASS(1) M127IRQHook(int a) { +static void M127IRQHook(int a) { int count = a; while (count--) { if (IRQa) { @@ -115,5 +112,5 @@ void Mapper127_Init(CartInfo *info) { info->Power = M127Power; MapIRQHook = M127IRQHook; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper128.c b/src/mappers/mapper128.c similarity index 63% rename from src/boards/mapper128.c rename to src/mappers/mapper128.c index 930f4021a..9669c5673 100644 --- a/src/boards/mapper128.c +++ b/src/mappers/mapper128.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,36 +21,41 @@ #include "mapinc.h" #include "latch.h" -static uint16 outerbank = 0; +static uint16 reg = 0; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; static void Sync(void) { - setprg16(0x8000, (outerbank >> 2) | (latch.data & 7)); - setprg16(0xC000, (outerbank >> 2) | 7); + setprg16(0x8000, (reg >> 2) | (latch.data & 0x07)); + setprg16(0xC000, (reg >> 2) | 0x07); setchr8(0); - setmirror(((outerbank >> 1) & 1) ^ 1); + setmirror(((reg >> 1) & 0x01) ^ 0x01); } static DECLFW(M128Write) { - if (outerbank < 0xF000) { - outerbank = A; + if (reg < 0xF000) { + reg = A & 0xFFFF; } - LatchWrite(A, V); + Latch_Write(A, V); } -static void M128Reset() { - outerbank = 0; - LatchHardReset(); +static void M128Reset(void) { + reg = 0; + Latch_RegReset(); } -static void M128Power() { - outerbank = 0; - LatchPower(); +static void M128Power(void) { + reg = 0; + Latch_Power(); SetWriteHandler(0x8000, 0xFFFF, M128Write); } void Mapper128_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); + Latch_Init(info, Sync, NULL, FALSE, FALSE); info->Power = M128Power; info->Reset = M128Reset; - AddExState(&outerbank, 2, 0, "BANK"); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper132.c b/src/mappers/mapper132.c new file mode 100644 index 000000000..d1118373d --- /dev/null +++ b/src/mappers/mapper132.c @@ -0,0 +1,98 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "txc.h" + +/**** LEGACY MAPPER IMPLEMENTATION ****/ + +static uint8 reg[4]; + +static SFORMAT UNL22211StateRegs[] = { + { reg, 4, "REGS" }, + { 0 } +}; + +static void UNL22211Sync(void) { + setprg32(0x8000, (reg[2] >> 2) & 1); + setchr8(reg[2] & 3); +} + +static DECLFW(UNL22211WriteLo) { + if (A & 0x100) { + reg[A & 3] = V; + UNL22211Sync(); + } +} + +static DECLFR(UNL22211ReadLo) { + return ((reg[1] ^ reg[2]) | 0x40); +} + +static void UNL22211Power(void) { + UNL22211Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetReadHandler(0x4100, 0x4100, UNL22211ReadLo); + SetWriteHandler(0x4100, 0x4FFF, UNL22211WriteLo); +} + +static void UNL22211StateRestore(int version) { + UNL22211Sync(); +} + +static void UNL22211_Init(CartInfo *info) { + info->Power = UNL22211Power; + GameStateRestore = UNL22211StateRestore; + AddExState(&UNL22211StateRegs, ~0, 0, 0); +} + +/* Mapper 132 */ + +static void M132Sync(void) { + setprg32(0x8000, (txc.output >> 2) & 0x01); + setchr8(txc.output & 0x03); +} + +static DECLFW(M132Write) { + TXC_Write(A, V & 0x0F); +} + +static DECLFR(M132Read) { + return ((cpu.openbus & 0xF0) | (TXC_Read(A) & 0x0F)); +} + +static void M132Power(void) { + TXC_Power(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetReadHandler(0x4100, 0x5FFF, M132Read); + SetWriteHandler(0x4100, 0xFFFF, M132Write); +} + +void Mapper132_Init(CartInfo *info) { + if ((info->CRC32) == 0x2A5F4C5A) { + /* Jin Gwok Sei Chuen Saang (Ch) [U][!] */ + FCEU_printf(" WARNING: Using alternate mapper implementation.\n"); + UNL22211_Init(info); + return; + } + TXC_Init(info, M132Sync); + info->Power = M132Power; +} diff --git a/src/mappers/mapper133.c b/src/mappers/mapper133.c new file mode 100644 index 000000000..a0217d7f3 --- /dev/null +++ b/src/mappers/mapper133.c @@ -0,0 +1,59 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* iNES Mapper 133 - Sachen 3009 */ + +#include "mapinc.h" + +static uint8 reg = 0; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; + +static void Sync(void) { + setprg32(0x8000, (reg >> 2) & 0x01); + setchr8(reg & 0x03); +} + +static DECLFW(M133Write) { + if (A & 0x100) { + reg = V; + Sync(); + } +} + +static void M133Power(void) { + reg = 0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x4100, 0x5FFF, M133Write); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper133_Init(CartInfo *info) { + info->Power = M133Power; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper134.c b/src/mappers/mapper134.c new file mode 100644 index 000000000..9129ade88 --- /dev/null +++ b/src/mappers/mapper134.c @@ -0,0 +1,112 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* Chipset used on various PCBs named WX-KB4K, T4A54A, BS-5652... */ +/* "Rockman 3" on YH-322 and "King of Fighters 97" on "Super 6-in-1" enable interrupts without initializing the frame IRQ register and therefore freeze on real hardware. + They can run if another game is selected that does initialize the frame IRQ register, then soft-resetting to the menu and selecting the previously-freezing games. */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 reg[4]; +static uint8 dipsw; + +static SFORMAT StateRegs[] = { + { reg, 4, "REGS" }, + { &dipsw, 1, "DPSW" }, + { 0 } +}; + +static void M134PW(uint32 A, uint8 V) { + uint16 mask = (reg[1] & 0x04) ? 0x0F : 0x1F; + uint16 base = ((reg[1] << 4) & 0x30) | ((reg[0] << 2) & 0x40); + + if (reg[1] & 0x80) { /* NROM mode */ + if (reg[1] & 0x08) { /* NROM-128 mode */ + setprg8(0x8000, (base & ~mask) | ((mmc3.reg[6] & mask) & ~1) | 0); + setprg8(0xA000, (base & ~mask) | ((mmc3.reg[6] & mask) & ~1) | 1); + setprg8(0xC000, (base & ~mask) | ((mmc3.reg[6] & mask) & ~1) | 0); + setprg8(0xE000, (base & ~mask) | ((mmc3.reg[6] & mask) & ~1) | 1); + } else { /* NROM-256 mode */ + setprg8(0x8000, (base & ~mask) | (((mmc3.reg[6] & ~0x02) & mask) & ~1) | 0); + setprg8(0xA000, (base & ~mask) | (((mmc3.reg[6] & ~0x02) & mask) & ~1) | 1); + setprg8(0xC000, (base & ~mask) | (((mmc3.reg[6] | 0x02) & mask) & ~1) | 0); + setprg8(0xE000, (base & ~mask) | (((mmc3.reg[6] | 0x02) & mask) & ~1) | 1); + } + } else { /* MMC3 */ + setprg8(A, (base & ~mask) | (V & mask)); + } +} + +static void M134CW(uint32 A, uint8 V) { + uint16 mask = (reg[1] & 0x40) ? 0x7F : 0xFF; + uint16 base = ((reg[1] << 3) & 0x180) | ((reg[0] << 4) & 0x200); + + if (reg[0] & 0x08) { /* In CNROM mode, outer bank register 2 replaces the MMC3's CHR registers, and CHR A10-A12 are PPU A10-A12. */ + setchr8(((base & ~mask) >> 3) | (reg[2] & (mask >> 3))); + } else { + setchr1(A, (base & ~mask) | (V & mask)); + } +} + +static DECLFR(M134Read) { + if (reg[0] & 0x40) { + return dipsw; + } + return CartBR(A); +} + +static DECLFW(M134Write) { + if (MMC3_WramIsWritable()) { + CartBW(A, V); + if (!(reg[0] & 0x80)) { + reg[A & 0x03] = V; + MMC3_FixPRG(); + MMC3_FixCHR(); + } else if ((A & 0x03) == 2) { + reg[2] = (reg[2] & ~0x03) | (V & 0x03); + MMC3_FixCHR(); + } + } +} + +static void M134Reset(void) { + dipsw++; + dipsw &= 15; + reg[0] = reg[1] = reg[2] = reg[3] = 0; + MMC3_Reset(); +} + +static void M134Power(void) { + dipsw = 0; + reg[0] = reg[1] = reg[2] = reg[3] = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M134Write); + SetReadHandler(0x8000, 0xFFFF, M134Read); +} + +void Mapper134_Init(CartInfo *info) { + MMC3_Init(info, info->iNES2 ? (info->PRGRamSize + info->PRGRamSaveSize) / 1024 : 8, info->battery); + MMC3_cwrap = M134CW; + MMC3_pwrap = M134PW; + info->Power = M134Power; + info->Reset = M134Reset; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper136.c b/src/mappers/mapper136.c new file mode 100644 index 000000000..b870f9aad --- /dev/null +++ b/src/mappers/mapper136.c @@ -0,0 +1,48 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "jv001.h" + +static void M136Sync(void) { + setprg32(0x8000, (jv001.output >> 4) & 0x01); + setchr8(jv001.output & 0x07); +} + +static DECLFW(M136Write) { + JV001_Write(A, V & 0x3F); +} + +static DECLFR(M136Read) { + return ((cpu.openbus & 0xC0) | (JV001_Read(A) & 0x3F)); +} + +static void M136Power(void) { + JV001_Power(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetReadHandler(0x4100, 0x5FFF, M136Read); + SetWriteHandler(0x4100, 0xFFFF, M136Write); +} + +void Mapper136_Init(CartInfo *info) { + JV001_Init(info, M136Sync); + info->Power = M136Power; +} diff --git a/src/mappers/mapper137.c b/src/mappers/mapper137.c new file mode 100644 index 000000000..a1def8670 --- /dev/null +++ b/src/mappers/mapper137.c @@ -0,0 +1,77 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* iNES Mapper 137 - Sachen 8259D */ + +#include "mapinc.h" + +static uint8 cmd; +static uint8 reg[8]; + +static SFORMAT StateRegs[] = { + { reg, 8, "REGS" }, + { &cmd, 1, "CMD0" }, + { 0 } +}; + +static void Sync(void) { + setprg32(0x8000, reg[5]); + setchr1(0x0000, (reg[0] & 0x07)); + setchr1(0x0400, ((reg[4] << 4) & 0x10) | (reg[(reg[7] & 0x01) ? 0 : 1] & 0x07)); + setchr1(0x0800, ((reg[4] << 3) & 0x10) | (reg[(reg[7] & 0x01) ? 0 : 2] & 0x07)); + setchr1(0x0C00, ((reg[4] << 2) & 0x10) | ((reg[6] << 3) & 0x08) | (reg[(reg[7] & 0x01) ? 0 : 3] & 0x07)); + setchr4(0x1000, ~0); + switch (reg[7] & 0x07) { + default: setmirror(MI_H); break; + case 2: setmirror(MI_V); break; + case 4: setmirrorw(0, 0, 0, 1); break; + case 6: setmirror(MI_0); break; + } +} + +static DECLFW(M137Write) { + if ((A & 0x4000) && (A & 0x100)) { + if (A & 0x01) { + reg[cmd & 0x07] = V; + Sync(); + } else { + cmd = V; + } + } +} + +static void M137Reset(void) { + cmd = 0; + reg[0] = reg[1] = reg[2] = reg[3] = 0; + reg[4] = reg[5] = reg[6] = reg[7] = 0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x4100, 0xFFFF, M137Write); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper137_Init(CartInfo *info) { + info->Power = M137Reset; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper138.c b/src/mappers/mapper138.c new file mode 100644 index 000000000..bf8c45ee5 --- /dev/null +++ b/src/mappers/mapper138.c @@ -0,0 +1,76 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* iNES Mapper 138 - Sachen 8259B */ + +#include "mapinc.h" + +static uint8 cmd; +static uint8 reg[8]; + +static SFORMAT StateRegs[] = { + { reg, 8, "REGS" }, + { &cmd, 1, "CMD0" }, + { 0 } +}; + +static void Sync(void) { + setprg32(0x8000, reg[5]); + setchr2(0x0000, ((reg[4] << 3) | (reg[(reg[7] & 0x01) ? 0 : 0] & 0x07))); + setchr2(0x0800, ((reg[4] << 3) | (reg[(reg[7] & 0x01) ? 0 : 1] & 0x07))); + setchr2(0x1000, ((reg[4] << 3) | (reg[(reg[7] & 0x01) ? 0 : 2] & 0x07))); + setchr2(0x1800, ((reg[4] << 3) | (reg[(reg[7] & 0x01) ? 0 : 3] & 0x07))); + switch (reg[7] & 0x07) { + case 0: setmirrorw(0, 0, 0, 1); break; + case 2: setmirror(MI_H); break; + default: setmirror(MI_V); break; + case 6: setmirror(MI_0); break; + } +} + +static DECLFW(M138Write) { + if ((A & 0x4000) && (A & 0x100)) { + if (A & 0x01) { + reg[cmd & 0x07] = V; + Sync(); + } else { + cmd = V; + } + } +} + +static void M138Reset(void) { + cmd = 0; + reg[0] = reg[1] = reg[2] = reg[3] = 0; + reg[4] = reg[5] = reg[6] = reg[7] = 0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x4100, 0xFFFF, M138Write); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper138_Init(CartInfo *info) { + info->Power = M138Reset; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper139.c b/src/mappers/mapper139.c new file mode 100644 index 000000000..490fc999b --- /dev/null +++ b/src/mappers/mapper139.c @@ -0,0 +1,76 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* iNES Mapper 139 - Sachen 8259C */ + +#include "mapinc.h" + +static uint8 cmd; +static uint8 reg[8]; + +static SFORMAT StateRegs[] = { + { reg, 8, "REGS" }, + { &cmd, 1, "CMD0" }, + { 0 } +}; + +static void Sync(void) { + setprg32(0x8000, reg[5]); + setchr2(0x0000, ((((reg[4] << 3) | (reg[(reg[7] & 0x01) ? 0 : 0] & 0x07)) << 2) | 0)); + setchr2(0x0800, ((((reg[4] << 3) | (reg[(reg[7] & 0x01) ? 0 : 1] & 0x07)) << 2) | 1)); + setchr2(0x1000, ((((reg[4] << 3) | (reg[(reg[7] & 0x01) ? 0 : 2] & 0x07)) << 2) | 2)); + setchr2(0x1800, ((((reg[4] << 3) | (reg[(reg[7] & 0x01) ? 0 : 3] & 0x07)) << 2) | 3)); + switch (reg[7] & 0x07) { + case 0: setmirrorw(0, 0, 0, 1); break; + case 2: setmirror(MI_H); break; + default: setmirror(MI_V); break; + case 6: setmirror(MI_0); break; + } +} + +static DECLFW(M139Write) { + if ((A & 0x4000) && (A & 0x100)) { + if (A & 0x01) { + reg[cmd & 0x07] = V; + Sync(); + } else { + cmd = V; + } + } +} + +static void M139Reset(void) { + cmd = 0; + reg[0] = reg[1] = reg[2] = reg[3] = 0; + reg[4] = reg[5] = reg[6] = reg[7] = 0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x4100, 0xFFFF, M139Write); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper139_Init(CartInfo *info) { + info->Power = M139Reset; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/mapper140.c b/src/mappers/mapper140.c similarity index 88% rename from src/boards/mapper140.c rename to src/mappers/mapper140.c index efe324e59..18c54929e 100644 --- a/src/boards/mapper140.c +++ b/src/mappers/mapper140.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,15 +22,14 @@ static uint8 reg; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { ®, 1, "REG" }, { 0 } }; -static void Sync() { +static void Sync(void) { setprg32(0x8000, reg >> 4); - setchr8(reg & 0xF); + setchr8(reg & 0x0F); } static DECLFW(M140Write) { @@ -52,5 +51,5 @@ static void StateRestore(int version) { void Mapper140_Init(CartInfo *info) { info->Power = M140Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper141.c b/src/mappers/mapper141.c new file mode 100644 index 000000000..ed05a7b98 --- /dev/null +++ b/src/mappers/mapper141.c @@ -0,0 +1,80 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* iNES Mapper 141 - Sachen 8259A */ + +#include "mapinc.h" + +static uint8 cmd; +static uint8 reg[8]; + +static SFORMAT StateRegs[] = { + { reg, 8, "REGS" }, + { &cmd, 1, "CMD0" }, + { 0 } +}; + +static void Sync(void) { + setprg32(0x8000, reg[5]); + if (UNIFchrrama) { + setchr8(0); + } else { + setchr2(0x0000, (((reg[4] << 3) | (reg[(reg[7] & 0x01) ? 0 : 0] & 0x07)) << 1) | 0); + setchr2(0x0800, (((reg[4] << 3) | (reg[(reg[7] & 0x01) ? 0 : 1] & 0x07)) << 1) | 1); + setchr2(0x1000, (((reg[4] << 3) | (reg[(reg[7] & 0x01) ? 0 : 2] & 0x07)) << 1) | 0); + setchr2(0x1800, (((reg[4] << 3) | (reg[(reg[7] & 0x01) ? 0 : 3] & 0x07)) << 1) | 1); + } + switch (reg[7] & 0x07) { + case 0: setmirrorw(0, 0, 0, 1); break; + case 2: setmirror(MI_H); break; + default: setmirror(MI_V); break; + case 6: setmirror(MI_0); break; + } +} + +static DECLFW(M141Write) { + if ((A & 0x4000) && (A & 0x100)) { + if (A & 0x01) { + reg[cmd & 0x07] = V; + Sync(); + } else { + cmd = V; + } + } +} + +static void M141Reset(void) { + cmd = 0; + reg[0] = reg[1] = reg[2] = reg[3] = 0; + reg[4] = reg[5] = reg[6] = reg[7] = 0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x4100, 0xFFFF, M141Write); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper141_Init(CartInfo *info) { + info->Power = M141Reset; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper142.c b/src/mappers/mapper142.c new file mode 100644 index 000000000..55b519d9d --- /dev/null +++ b/src/mappers/mapper142.c @@ -0,0 +1,37 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 142 - UNL KS7032 */ + + #include "mapinc.h" + #include "ks202.h" + + static void Sync(void) { + setprg8(0x6000, ks202.reg[4] & 0x0F); + setprg8(0x8000, ks202.reg[1] & 0x0F); + setprg8(0xA000, ks202.reg[2] & 0x0F); + setprg8(0xC000, ks202.reg[3] & 0x0F); + setprg8(0xE000, ~0 & 0x0F); + setchr8(0); +} + +void Mapper142_Init(CartInfo *info) { + KS202_Init(info, Sync, 0, 0); +} diff --git a/src/mappers/mapper143.c b/src/mappers/mapper143.c new file mode 100644 index 000000000..c4a38a5e8 --- /dev/null +++ b/src/mappers/mapper143.c @@ -0,0 +1,41 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* iNES Mapper 143 - TC-A01 */ + +#include "mapinc.h" + +static DECLFR(M143Read) { + if ((A & 0x100) == 0x100) { + return (cpu.openbus & 0xC0) | ((~A) & 0x3F); + } + return cpu.openbus; +} + +static void M143Power(void) { + setprg32(0x8000, 0); + setchr8(0); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetReadHandler(0x4100, 0x5FFF, M143Read); +} + +void Mapper143_Init(CartInfo *info) { + info->Power = M143Power; +} diff --git a/src/mappers/mapper144.c b/src/mappers/mapper144.c new file mode 100644 index 000000000..982c0bee6 --- /dev/null +++ b/src/mappers/mapper144.c @@ -0,0 +1,44 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg32(0x8000, latch.data); + setchr8(latch.data >> 4); +} + +static DECLFW(M144Write) { + uint8 reg = CartBR(A); + latch.data = reg & ((V & reg) | 0x01); + Sync(); +} + +static void M144Power(void) { + Latch_Power(); + SetWriteHandler(0x8000, 0xFFFF, M144Write); +} + +void Mapper144_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, TRUE); + info->Power = M144Power; +} diff --git a/src/mappers/mapper145.c b/src/mappers/mapper145.c new file mode 100644 index 000000000..ecad0f046 --- /dev/null +++ b/src/mappers/mapper145.c @@ -0,0 +1,54 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* iNES Mapper 145 - Sachen SA-72007 */ + +#include "mapinc.h" + +static uint8 reg = 0; + +static void Sync(void) { + setprg32(0x8000, 0); + setchr8(reg >> 7); +} + +static DECLFW(M145Write) { + if (A & 0x100) { + reg = V; + Sync(); + } +} + +static void M145Power(void) { + reg = 0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x4100, 0x5FFF, M145Write); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper145_Init(CartInfo *info) { + info->Power = M145Power; + GameStateRestore = StateRestore; + AddExState(®, 1, 0, "REG0"); +} diff --git a/src/mappers/mapper147.c b/src/mappers/mapper147.c new file mode 100644 index 000000000..94900d3b1 --- /dev/null +++ b/src/mappers/mapper147.c @@ -0,0 +1,49 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "jv001.h" + +static void M147Sync(void) { + setprg32(0x8000, ((jv001.output >> 4) & 0x02) | (jv001.output & 0x01)); + setchr8((jv001.output >> 1) & 0x0F); +} + +static DECLFW(M147Write) { + JV001_Write(A, ((V >> 2) & 0x3F) | ((V << 6) & 0xC0)); +} + +static DECLFR(M147Read) { + uint8 ret = JV001_Read(A); + return ((ret << 2) | ((ret >> 6) & 0x03)); +} + +static void M147Power(void) { + JV001_Power(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetReadHandler(0x4100, 0x5FFF, M147Read); + SetWriteHandler(0x4100, 0xFFFF, M147Write); +} + +void Mapper147_Init(CartInfo *info) { + JV001_Init(info, M147Sync); + info->Power = M147Power; +} diff --git a/src/mappers/mapper148.c b/src/mappers/mapper148.c new file mode 100644 index 000000000..31bd13291 --- /dev/null +++ b/src/mappers/mapper148.c @@ -0,0 +1,33 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* iNES Mapper 148 - Sachen SA-008-A and Tengen 800008 */ + +#include "mapinc.h" +#include "latch.h" + +static void Sync(void) { + setprg32(0x8000, (latch.data >> 3) & 0x01); + setchr8(latch.data & 0x07); +} + +void Mapper148_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, TRUE); +} diff --git a/src/mappers/mapper149.c b/src/mappers/mapper149.c new file mode 100644 index 000000000..59db1366f --- /dev/null +++ b/src/mappers/mapper149.c @@ -0,0 +1,33 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* iNES Mapper 149 - Sachen SA-0036 */ + +#include "mapinc.h" +#include "latch.h" + +static void Sync(void) { + setprg32(0x8000, 0); + setchr8(latch.data >> 7); +} + +void Mapper149_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, TRUE); +} diff --git a/src/mappers/mapper150.c b/src/mappers/mapper150.c new file mode 100644 index 000000000..6cc6fa67b --- /dev/null +++ b/src/mappers/mapper150.c @@ -0,0 +1,102 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 150 - SA-015 / SA-630 / Unif UNL-Sachen-74LS374N */ +/* Mapper 243 - SA-020A */ + +#include "mapinc.h" + +static uint8 dipsw; +static uint8 cmd; +static uint8 reg[8]; + +static SFORMAT StateRegs[] = { + { reg, 8, "REGS" }, + { &dipsw, 1, "DPSW" }, + { &cmd, 1, "CMD0" }, + { 0 } +}; + +static void Sync(void) { + setprg32(0x8000, (reg[2] & 0x01) | reg[5]); + if (iNESCart.mapper == 243) { + setchr8((reg[2] & 0x01) | ((reg[4] << 1) & 0x02) | (reg[6] << 2)); + } else { + setchr8((reg[6] & 0x03) | ((reg[4] << 2) & 0x04) | (reg[2] << 3)); + } + switch ((reg[7] >> 1) & 0x03) { + case 0: setmirrorw(0, 1, 1, 1); break; + case 1: setmirror(MI_H); break; + case 2: setmirror(MI_V); break; + case 3: setmirror(MI_0); break; + } +} + +static DECLFR(M150Read) { + if ((A & 0x101) == 0x101) { + if (dipsw & 1) + return (reg[cmd] & 0x03) | (cpu.openbus & 0xFC); + else + return (reg[cmd] & 0x07) | (cpu.openbus & 0xF8); + } + return cpu.openbus; +} + +static DECLFW(M150Write) { + if (dipsw & 0x01) + V |= 0x04; + switch (A & 0x101) { + case 0x100: + cmd = V & 0x07; + break; + case 0x101: + reg[cmd] = V & 0x07; + Sync(); + break; + } +} + +static void M150Restore(int version) { + Sync(); +} + +static void M150Reset(void) { + dipsw ^= 0x01; + reg[0] = reg[1] = reg[2] = reg[3] = 0; + reg[4] = reg[5] = reg[6] = reg[7] = 0; + Sync(); +} + +static void M150Power(void) { + dipsw = 0; + reg[0] = reg[1] = reg[2] = reg[3] = 0; + reg[4] = reg[5] = reg[6] = reg[7] = 0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetReadHandler(0x4100, 0x5FFF, M150Read); + SetWriteHandler(0x4100, 0x5FFF, M150Write); +} + +void Mapper150_Init(CartInfo *info) { + info->Power = M150Power; + info->Reset = M150Reset; + GameStateRestore = M150Restore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper152.c b/src/mappers/mapper152.c new file mode 100644 index 000000000..4f251843a --- /dev/null +++ b/src/mappers/mapper152.c @@ -0,0 +1,34 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg16(0x8000, latch.data >> 4); + setprg16(0xc000, ~0); + setchr8(latch.data & 0x0F); + setmirror(MI_0 + ((latch.data >> 7) & 0x01)); /* Saint Seiya...hmm. */ +} + +void Mapper152_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, TRUE); +} diff --git a/src/mappers/mapper153.c b/src/mappers/mapper153.c new file mode 100644 index 000000000..5b2f8e6bb --- /dev/null +++ b/src/mappers/mapper153.c @@ -0,0 +1,91 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "eeprom_x24c0x.h" +#include "bandai.h" + +static uint8 outer; + +/* Famicom jump 2: + * 0-7: Lower bit of data selects which 256KB PRG block is in use. + * This seems to be a hack on the developers' part, so I'll make emulation + * of it a hack(I think the current PRG block would depend on whatever the + * lowest bit of the CHR bank switching register that corresponds to the + * last CHR address read). + */ + +static SFORMAT StateRegs[] = { + { &outer, 1, "OUTB" }, + { 0 } +}; + +static void M153PW(uint32 A, uint8 V) { + setprg16(A, ((outer << 4) & 0x10) | (V & 0x0F)); +} + +static void M153CW(uint32 A, uint8 V) { + setchr8(0); +} + +static DECLFW(M153Write) { + if ((A & 0x0F) <= 0x03) { + outer = V; + BANDAI_FixPRG(); + } + BANDAI_Write(A, V); +} + +static void M153Power(void) { + BANDAI_Power(); + SetWriteHandler(0x8000, 0xFFFF, M153Write); + if (WRAMSIZE) { + setprg8r(0x10, 0x6000, 0); + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + } +} + +static void M153Close(void) { +} + +void Mapper153_Init(CartInfo *info) { + BANDAI_Init(info, EEPROM_NONE, FALSE); + info->Power = M153Power; + info->Close = M153Close; + BANDAI_pwrap = M153PW; + BANDAI_cwrap = M153CW; + AddExState(StateRegs, ~0, 0, NULL); + + WRAMSIZE = 8192; + if (info->iNES2) { + WRAMSIZE = info->PRGRamSize + info->PRGRamSaveSize; + } + if (WRAMSIZE) { + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + } +} diff --git a/src/mappers/mapper154.c b/src/mappers/mapper154.c new file mode 100644 index 000000000..f3f8fc3a5 --- /dev/null +++ b/src/mappers/mapper154.c @@ -0,0 +1,73 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2005 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 154 It is identical to Mapper 88, but with the addition of a single bit allowing for mapper-controlled one-screen regoring: */ + +#include "mapinc.h" +#include "n118.h" + +static uint8 reg; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; + +static void M154Mirroring(void) { + setmirror(MI_0 + ((reg >> 6) & 0x01)); +} + +static void M154FixCHR(void) { + setchr2(0x0000, (n118.reg[0] & 0x3F) >> 1); + setchr2(0x0800, (n118.reg[1] & 0x3F) >> 1); + setchr1(0x1000, 0x40 | (n118.reg[2] & 0x3F)); + setchr1(0x1400, 0x40 | (n118.reg[3] & 0x3F)); + setchr1(0x1800, 0x40 | (n118.reg[4] & 0x3F)); + setchr1(0x1C00, 0x40 | (n118.reg[5] & 0x3F)); +} + +static DECLFW(M154Write) { + if (A < 0xA000) { + N118_Write(A, V); + } + reg = V; /* mirroring latch */ + M154Mirroring(); +} + +static void M154Power(void) { + reg = 0; + N118_Power(); + SetWriteHandler(0x8000, 0xFFFF, M154Write); +} + +static void StateRestore(int version) { + N118_FixPRG(); + N118_FixCHR(); + M154Mirroring(); +} + +void Mapper154_Init(CartInfo *info) { + N118_Init(info, 0, 0); + info->Power = M154Power; + N118_FixCHR = M154FixCHR; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper155.c b/src/mappers/mapper155.c new file mode 100644 index 000000000..735af7130 --- /dev/null +++ b/src/mappers/mapper155.c @@ -0,0 +1,33 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "mmc1.h" + +static void M155PW(uint32 A, uint8 V) { + setprg16(A, (MMC1_GetCHRBank(0) & 0x10) | (V & 0x0F)); +} + +/* Same as mapper 1, without respect for WRAM enable bit. */ +void Mapper155_Init(CartInfo *info) { + MMC1_Init(info, 8, info->battery ? 8 : 0); + MMC1_pwrap = M155PW; + mmc1_type = MMC1A; +} diff --git a/src/boards/mapper156.c b/src/mappers/mapper156.c similarity index 63% rename from src/boards/mapper156.c rename to src/mappers/mapper156.c index 77a1c343f..673ac01d7 100644 --- a/src/boards/mapper156.c +++ b/src/mappers/mapper156.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2009 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -26,83 +27,75 @@ #include "mapinc.h" -static uint8 chrlo[8], chrhi[8], prg, mirr, mirrisused = 0; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint8 prg, mirr; +static uint16 chr[8]; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { + { chr, 16, "CREG" }, { &prg, 1, "PREG" }, - { chrlo, 8, "CRGL" }, - { chrhi, 8, "CRGH" }, { &mirr, 1, "MIRR" }, { 0 } }; static void Sync(void) { - uint32 i; - for (i = 0; i < 8; i++) - setchr1(i << 10, chrlo[i] | (chrhi[i] << 8)); setprg8r(0x10, 0x6000, 0); setprg16(0x8000, prg); setprg16(0xC000, ~0); - if (mirrisused) - setmirror(mirr ^ 1); - else - setmirror(MI_0); + + setchr1(0x0000, chr[0]); + setchr1(0x0400, chr[1]); + setchr1(0x0800, chr[2]); + setchr1(0x0C00, chr[3]); + setchr1(0x1000, chr[4]); + setchr1(0x1400, chr[5]); + setchr1(0x1800, chr[6]); + setchr1(0x1C00, chr[7]); + + switch (mirr) { + case 0: setmirror(MI_V); break; + case 1: setmirror(MI_H); break; + default: setmirror(MI_0); break; + } } static DECLFW(M156Write) { - switch (A) { - case 0xC000: - case 0xC001: - case 0xC002: - case 0xC003: - chrlo[A & 3] = V; - Sync(); - break; - case 0xC004: - case 0xC005: - case 0xC006: - case 0xC007: - chrhi[A & 3] = V; - Sync(); - break; - case 0xC008: - case 0xC009: - case 0xC00A: - case 0xC00B: - chrlo[4 + (A & 3)] = V; - Sync(); - break; - case 0xC00C: - case 0xC00D: - case 0xC00E: - case 0xC00F: - chrhi[4 + (A & 3)] = V; - Sync(); - break; - case 0xC010: - prg = V; - Sync(); - break; - case 0xC014: - mirr = V; - mirrisused = 1; - Sync(); - break; + uint8 index = A & 0x03; + + switch (A & 0xFFFC) { + case 0xC000: + chr[0 | index] &= (chr[0 | index] & 0xFF00) | V; + Sync(); + break; + case 0xC004: + chr[0 | index] = (chr[0 | index] & 0x00FF) | V << 8; + Sync(); + break; + case 0xC008: + chr[4 | index] = (chr[4 | index] & 0xFF00) | V; + Sync(); + break; + case 0xC00C: + chr[4 | index] = (chr[4 | index] & 0x00FF) | V << 8; + Sync(); + break; + case 0xC010: + prg = V; + Sync(); + break; + case 0xC014: + mirr = V; + Sync(); + break; } } static void M156Reset(void) { uint32 i; for (i = 0; i < 8; i++) { - chrlo[i] = 0; - chrhi[i] = 0; + chr[i] = 0; } prg = 0; - mirr = 0; - mirrisused = 0; + mirr = 2; } static void M156Power(void) { @@ -115,9 +108,6 @@ static void M156Power(void) { } static void M156Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; } static void StateRestore(int version) { @@ -128,12 +118,11 @@ void Mapper156_Init(CartInfo *info) { info->Reset = M156Reset; info->Power = M156Power; info->Close = M156Close; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); WRAMSIZE = 8192; WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); } diff --git a/src/mappers/mapper157.c b/src/mappers/mapper157.c new file mode 100644 index 000000000..ac76663a7 --- /dev/null +++ b/src/mappers/mapper157.c @@ -0,0 +1,290 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* FIXME: Bar code input interface not attached yet */ + +#include "mapinc.h" +#include "eeprom_x24c0x.h" +#include "bandai.h" + +/* Datach Barcode Battler */ + +static uint8 BarcodeData[256]; +static int BarcodeReadPos; +static int BarcodeCycleCount; +static uint32 BarcodeOut; + +/* #define INTERL2OF5 */ + +int FCEUI_DatachSet(uint8 *rcode) { + int prefix_parity_type[10][6] = { + { 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 1, 1 }, { 0, 0, 1, 1, 0, 1 }, { 0, 0, 1, 1, 1, 0 }, + { 0, 1, 0, 0, 1, 1 }, { 0, 1, 1, 0, 0, 1 }, { 0, 1, 1, 1, 0, 0 }, { 0, 1, 0, 1, 0, 1 }, + { 0, 1, 0, 1, 1, 0 }, { 0, 1, 1, 0, 1, 0 } + }; + int data_left_odd[10][7] = { + { 0, 0, 0, 1, 1, 0, 1 }, { 0, 0, 1, 1, 0, 0, 1 }, { 0, 0, 1, 0, 0, 1, 1 }, { 0, 1, 1, 1, 1, 0, 1 }, + { 0, 1, 0, 0, 0, 1, 1 }, { 0, 1, 1, 0, 0, 0, 1 }, { 0, 1, 0, 1, 1, 1, 1 }, { 0, 1, 1, 1, 0, 1, 1 }, + { 0, 1, 1, 0, 1, 1, 1 }, { 0, 0, 0, 1, 0, 1, 1 } + }; + int data_left_even[10][7] = { + { 0, 1, 0, 0, 1, 1, 1 }, { 0, 1, 1, 0, 0, 1, 1 }, { 0, 0, 1, 1, 0, 1, 1 }, { 0, 1, 0, 0, 0, 0, 1 }, + { 0, 0, 1, 1, 1, 0, 1 }, { 0, 1, 1, 1, 0, 0, 1 }, { 0, 0, 0, 0, 1, 0, 1 }, { 0, 0, 1, 0, 0, 0, 1 }, + { 0, 0, 0, 1, 0, 0, 1 }, { 0, 0, 1, 0, 1, 1, 1 } + }; + int data_right[10][7] = { + { 1, 1, 1, 0, 0, 1, 0 }, { 1, 1, 0, 0, 1, 1, 0 }, { 1, 1, 0, 1, 1, 0, 0 }, { 1, 0, 0, 0, 0, 1, 0 }, + { 1, 0, 1, 1, 1, 0, 0 }, { 1, 0, 0, 1, 1, 1, 0 }, { 1, 0, 1, 0, 0, 0, 0 }, { 1, 0, 0, 0, 1, 0, 0 }, + { 1, 0, 0, 1, 0, 0, 0 }, { 1, 1, 1, 0, 1, 0, 0 } + }; + uint8 code[13 + 1]; + uint32 tmp_p = 0; + uint32 csum = 0; + int i, j; + int len; + + for (i = len = 0; i < 13; i++) { + if (!rcode[i]) break; + if ((code[i] = rcode[i] - '0') > 9) + return(0); + len++; + } + if (len != 13 && len != 12 && len != 8 && len != 7) return(0); + + #define BS(x) BarcodeData[tmp_p] = x; tmp_p++ + + for (j = 0; j < 32; j++) { /* delay before sending a code */ + BS(0x00); + } + +#ifdef INTERL2OF5 + + BS(1); BS(1); BS(0); BS(0); /* 1 */ + BS(1); BS(1); BS(0); BS(0); /* 1 */ + BS(1); BS(1); BS(0); BS(0); /* 1 */ + BS(1); BS(1); BS(0); BS(0); /* 1 */ + BS(1); BS(1); BS(0); BS(0); /* 1 */ + BS(1); BS(0); BS(0); /* 0 */ + BS(1); BS(0); BS(0); /* 0 */ + BS(1); BS(0); BS(0); /* 0 */ + BS(1); BS(0); BS(0); /* 0 */ + BS(1); BS(0); BS(0); /* 0 */ + BS(1); BS(0); BS(0); /* 0 */ + BS(1); BS(0); BS(0); /* 0 */ + BS(1); BS(0); BS(0); /* 0 */ + BS(1); BS(0); BS(0); /* 0 */ + BS(1); BS(0); BS(0); /* 0 */ + BS(1); BS(0); BS(0); /* 0 */ + BS(1); BS(0); BS(0); /* 0 */ + BS(1); BS(0); BS(0); /* 0 */ + BS(1); BS(0); BS(0); /* 0 */ + BS(1); BS(0); BS(0); /* 0 */ + BS(1); BS(0); BS(0); /* 0 */ + BS(1); BS(0); BS(0); /* 0 */ + BS(1); BS(0); BS(0); /* 0 */ + BS(1); BS(0); BS(0); /* 0 */ + BS(1); BS(0); BS(0); /* 0 */ + BS(1); BS(0); BS(0); /* 0 cs */ + BS(1); BS(1); BS(0); BS(0); /* 1 */ + +#else + /* Left guard bars */ + BS(1); BS(0); BS(1); + + if (len == 13 || len == 12) { + + for (i = 0; i < 6; i++) { + if (prefix_parity_type[code[0]][i]) { + for (j = 0; j < 7; j++) { + BS(data_left_even[code[i + 1]][j]); + } + } else { + for (j = 0; j < 7; j++) { + BS(data_left_odd[code[i + 1]][j]); + } + } + } + + /* Center guard bars */ + BS(0); BS(1); BS(0); BS(1); BS(0); + + for (i = 7; i < 12; i++) { + for (j = 0; j < 7; j++) { + BS(data_right[code[i]][j]); + } + } + /* Calc and write down the control code if not assigned, instead, send code as is + Battle Rush uses modified type of codes with different control code calculation */ + if (len == 12) { + for (i = 0; i < 12; i++) { + csum += code[i] * ((i & 1) ? 3 : 1); + } + csum = (10 - (csum % 10)) % 10; + rcode[12] = csum + 0x30; /* update check code to the input string as well */ + rcode[13] = 0; + code[12] = csum; + } + for (j = 0; j < 7; j++) { + BS(data_right[code[12]][j]); + } + } else if (len == 8 || len == 7) { + for (i = 0; i < 4; i++) { + for (j = 0; j < 7; j++) { + BS(data_left_odd[code[i]][j]); + } + } + + /* Center guard bars */ + BS(0); BS(1); BS(0); BS(1); BS(0); + + for (i = 4; i < 7; i++) { + for (j = 0; j < 7; j++) { + BS(data_right[code[i]][j]); + } + } + csum = 0; + for (i = 0; i < 7; i++) { + csum += (i & 1) ? code[i] : (code[i] * 3); + } + csum = (10 - (csum % 10)) % 10; + rcode[7] = csum + 0x30; /* update check code to the input string as well */ + rcode[8] = 0; + for (j = 0; j < 7; j++) { + BS(data_right[csum][j]); + } + } + + /* Right guard bars */ + BS(1); BS(0); BS(1); +#endif + + for (j = 0; j < 32; j++) { + BS(0x00); + } + + BS(0xFF); + + #undef BS + + BarcodeReadPos = 0; + BarcodeOut = 0x8; + BarcodeCycleCount = 0; + return(1); +} + +static uint8 latch; +static uint8 hasExternalEEPROM = FALSE; +/* first 256K is internal eeprom data, 2nd 256 is for external eeprom if used. + * Combined here for simplicity and frontend save compatibility */ +static uint8 eeprom[512]; + +static void M157PW(uint32 A, uint8 V) { + setprg16(A, V & 0x0F); +} + +static void M157CW(uint32 A, uint8 V) { + setchr8(0); +} + +static DECLFW(M157Write) { + switch (A & 0x0F) { + case 0x00: + if (hasExternalEEPROM) { + latch = (latch & ~0x20) | ((V << 2) & 0x20); + x24c01_write(latch); + } + break; + case 0x0D: + if (hasExternalEEPROM) { + latch = (V & ~0x20) | (latch & 0x20); + x24c01_write(latch); + } + x24c02_write(V); + break; + default: + BANDAI_Write(A, V); + break; + } +} + +static void M157IRQHook(int a) { + BANDAI_IRQHook(a); + + BarcodeCycleCount += a; + if (BarcodeCycleCount >= 1000) { + BarcodeCycleCount -= 1000; + if (BarcodeData[BarcodeReadPos] == 0xFF) { + BarcodeOut = 0; + } else { + BarcodeOut = (BarcodeData[BarcodeReadPos] ^ 1) << 3; + BarcodeReadPos++; + } + } +} + +static DECLFR(M157Read) { + return ((cpu.openbus & 0xE7) | ((x24c02_read() | x24c01_read()) << 4) | BarcodeOut); +} + +static void M157Power(void) { + BANDAI_Reset(); + + BarcodeData[0] = 0xFF; + BarcodeReadPos = 0; + BarcodeOut = 0; + BarcodeCycleCount = 0; + + SetReadHandler(0x6000, 0x7FFF, M157Read); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M157Write); +} + +void Mapper157_Init(CartInfo *info) { + BANDAI_Init(info, EEPROM_NONE, FALSE); + BANDAI_pwrap = M157PW; + BANDAI_cwrap = M157CW; + + info->Power = M157Power; + MapIRQHook = M157IRQHook; + + GameInfo->cspecial = SIS_DATACH; + + /* internal eeprom shared among all games + and always enabled regardless of battery flag */ + info->battery = 1; + x24c02_init(eeprom); + AddExState(&x24c02_StateRegs, ~0, 0, 0); + + if (info->PRGRamSaveSize && info->PRGRamSaveSize <= 128) { + /* additional 128 external eeprom */ + x24c01_init(&eeprom[256]); + AddExState(&x24c01_StateRegs, ~0, 0, 0); + AddExState(&latch, 1, 0, "LATC"); + hasExternalEEPROM = TRUE; + } + + if (hasExternalEEPROM) { + info->SaveGame[0] = eeprom; + info->SaveGameLen[0] = 512; + } else { + info->SaveGame[0] = eeprom; + info->SaveGameLen[0] = 256; + } +} diff --git a/src/mappers/mapper159.c b/src/mappers/mapper159.c new file mode 100644 index 000000000..553272f85 --- /dev/null +++ b/src/mappers/mapper159.c @@ -0,0 +1,37 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "eeprom_x24c0x.h" +#include "bandai.h" + +static void M159PW(uint32 A, uint8 V) { + setprg16(A, V & 0x1F); /* map upto 512K PRG for fan translations etc */ +} + +static void M159CW(uint32 A, uint8 V) { + setchr1(A, V); +} + +void Mapper159_Init(CartInfo *info) { + BANDAI_Init(info, EEPROM_X24C01, FALSE); + BANDAI_pwrap = M159PW; + BANDAI_cwrap = M159CW; +} diff --git a/src/mappers/mapper160.c b/src/mappers/mapper160.c new file mode 100644 index 000000000..cbcb3f993 --- /dev/null +++ b/src/mappers/mapper160.c @@ -0,0 +1,59 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +/* +iNES Mapper 160 appeared to describe variant behavior of iNES Mapper 090, but +Mapper 90 fully encompasses the behavior Mapper 160 was intended to emulate. +*/ + +#if 0 +static uint8 reg = 0; + +static void Sync(void) { + setprg32(0x8000, 0); + setchr8(reg & 1); +} + +static DECLFW(SAWrite) { + if (A & 0x100) { + reg = V; + Sync(); + } +} + +static void M160Power(void) { + reg = 0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x4100, 0x5FFF, SAWrite); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper160_Init(CartInfo *info) { + GameStateRestore = StateRestore; + info->Power = M160Power; + AddExState(®, 1, 0, "LATC"); +} +#endif \ No newline at end of file diff --git a/src/boards/mapper162.c b/src/mappers/mapper162.c similarity index 95% rename from src/boards/mapper162.c rename to src/mappers/mapper162.c index 969a5728f..dab0b3bd1 100644 --- a/src/boards/mapper162.c +++ b/src/mappers/mapper162.c @@ -24,16 +24,15 @@ #include "mapinc.h" -static uint8 *WRAM; -static uint32 WRAMSIZE; static uint8 reg[4]; + static SFORMAT StateRegs[] = { { reg, 4, "REGS" }, { 0 } }; -static void Sync() { +static void Sync(void) { setprg32(0x8000, (reg[2] << 4) | (reg[0] & 0x0C) /* PRG A17-A20 always normal from $5000 and $5200 */ | ((reg[3] & 0x04) ? 0x00 : 0x02) /* PRG A16 is 1 if $5300.2=0 */ @@ -81,9 +80,6 @@ static void M162Reset(void) { } static void M162Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; } static void StateRestore(int version) { @@ -97,7 +93,7 @@ void Mapper162_Init(CartInfo *info) { GameHBIRQHook = M162HBIRQHook; GameStateRestore = StateRestore; - AddExState(StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); WRAMSIZE = info->iNES2 ? (info->PRGRamSize + info->PRGRamSaveSize) : 8192; WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); diff --git a/src/boards/mapper163.c b/src/mappers/mapper163.c similarity index 93% rename from src/boards/mapper163.c rename to src/mappers/mapper163.c index 8467dbad7..0240b7605 100644 --- a/src/boards/mapper163.c +++ b/src/mappers/mapper163.c @@ -24,16 +24,15 @@ #include "mapinc.h" -static uint8 *WRAM; -static uint32 WRAMSIZE; static uint8 reg[4]; + static SFORMAT StateRegs[] = { { reg, 4, "REGS" }, { 0 } }; -static void Sync() { +static void Sync(void) { setprg32(0x8000, (reg[2] << 4) | (reg[0] & 0xF) | ((reg[3] & 0x04) ? 0x00 : 0x03)); setprg8r(0x10, 0x6000, 0); if (~reg[0] & 0x80) @@ -58,7 +57,7 @@ static DECLFW(writeReg) { uint8 index = (A >> 8) & 3; /* Swap bits of registers 0-2 again if the "swap bits" bit is set. Exclude register 2 on when PRG-ROM is 1 MiB. */ - if ((reg[3] & 0x01) && (index <= (ROM_size == 64 ? 1 : 2))) + if ((reg[3] & 0x01) && (index <= (ROM.prg.size == 64 ? 1 : 2))) V = (V & ~3) | ((V >> 1) & 1) | ((V << 1) & 2); if (A & 1) { @@ -85,9 +84,6 @@ static void M163Reset(void) { } static void M163Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; } static void StateRestore(int version) { @@ -101,7 +97,7 @@ void Mapper163_Init(CartInfo *info) { GameHBIRQHook = M163HBIRQHook; GameStateRestore = StateRestore; - AddExState(StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); WRAMSIZE = info->iNES2 ? (info->PRGRamSize + info->PRGRamSaveSize) : 8192; WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); diff --git a/src/boards/mapper164.c b/src/mappers/mapper164.c similarity index 54% rename from src/boards/mapper164.c rename to src/mappers/mapper164.c index bf0ee2d1c..7366c2c68 100644 --- a/src/boards/mapper164.c +++ b/src/mappers/mapper164.c @@ -1,9 +1,10 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2002 Xodnizel * Copyright (C) 2005 CaH4e3 * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -26,58 +27,76 @@ */ #include "mapinc.h" -#include "eeprom_93C66.h" +#include "eeprom_93Cx6.h" -static uint8 *WRAM; -static uint32 WRAMSIZE; -static uint8 reg[8]; +static uint8 reg[4]; static uint8 eeprom_data[512]; -static SFORMAT StateRegs[] = -{ - { reg, 8, "REGS" }, + +static SFORMAT StateRegs[] = { + { reg, 4, "REGS" }, { eeprom_data, 512, "EEPR" }, { 0 } }; -static void Sync() { +static void Sync(void) { uint8 prgLow = (reg[0] & 0x0F) | ((reg[0] >> 1) & 0x10); uint8 prgHigh = reg[1] << 5; - switch (((reg[0] >> 5) & 2) | ((reg[0] >> 4) & 1)) { - case 0: /* UNROM-512 */ - setprg16(0x8000, prgHigh | prgLow); - setprg16(0xC000, prgHigh | 0x1F); - break; - case 1: /* Open Bus on Yancheng cy2000-3 PCB, expansion cartridge on the Dongda PEC-9588 */ - break; - case 2: /* UNROM-448+64. Very strange mode, used for the LOGO program on the Dongda PEC-9588 */ - setprg16(0x8000, prgHigh | prgLow); - setprg16(0xC000, prgHigh | ((prgLow >= 0x1C) ? 0x1C : 0x1E)); - break; - case 3: /* UNROM-128 or BNROM */ - if (prgLow & 0x10) { - setprg16(0x8000, prgHigh | ((prgLow << 1) & 0x10) | (prgLow & 0x0F)); - setprg16(0xC000, prgHigh | ((prgLow << 1) & 0x10) | 0x0F); - } else - setprg32(0x8000, (prgHigh >> 1) | prgLow); - break; + + uint8 mode = ((reg[0] >> 5) & 0x02) | ((reg[0] >> 4) & 0x01); + uint8 mirr = ((reg[0] & 0x10) && !(reg[3] & 0x80)) ? MI_H : MI_V; + + switch (mode) { + case 0: /* UNROM-512 */ + setprg16(0x8000, prgHigh | prgLow); + setprg16(0xC000, prgHigh | 0x1F); + break; + case 1: /* Open Bus on Yancheng cy2000-3 PCB, expansion cartridge on the Dongda PEC-9588 */ + break; + case 2: /* UNROM-448+64. Very strange mode, used for the LOGO program on the Dongda PEC-9588 */ + setprg16(0x8000, prgHigh | prgLow); + setprg16(0xC000, prgHigh | ((prgLow >= 0x1C) ? 0x1C : 0x1E)); + break; + case 3: /* UNROM-128 or BNROM */ + if (prgLow & 0x10) { + setprg16(0x8000, prgHigh | ((prgLow << 1) & 0x10) | (prgLow & 0x0F)); + setprg16(0xC000, prgHigh | ((prgLow << 1) & 0x10) | 0x0F); + } else { + setprg32(0x8000, (prgHigh >> 1) | prgLow); + } + break; } + setprg8r(0x10, 0x6000, 0); setchr8(0); - PEC586Hack = !!(reg[0] & 0x80); - - setmirror(((reg[0] & 0x10) && (~reg[3] & 0x80)) ? MI_H : MI_V); + PEC586Hack = (reg[0] & 0x80) ? TRUE : FALSE; - eeprom_93C66_write((reg[2] & 0x10), (reg[2] & 0x04), (reg[2] & 0x01)); + setmirror(mirr); } static DECLFR(readReg) { - return eeprom_93C66_read() ? 0x00 : 0x04; + return eeprom_93Cx6_read() ? 0x00 : 0x04; } static DECLFW(writeReg) { - reg[(A >> 8) & 7] = V; - Sync(); + switch (A & 0xFF00) { + case 0x5000: + reg[0] = V; + Sync(); + break; + case 0x5100: + reg[1] = V; + Sync(); + break; + case 0x5200: + reg[2] = V; + eeprom_93Cx6_write((reg[2] & 0x10), (reg[2] & 0x04), (reg[2] & 0x01)); + break; + case 0x5300: + reg[3] = V; + Sync(); + break; + } } static void M164Power(void) { @@ -96,9 +115,6 @@ static void M164Reset(void) { } static void M164Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; } static void StateRestore(int version) { @@ -111,14 +127,19 @@ void Mapper164_Init(CartInfo *info) { info->Close = M164Close; GameStateRestore = StateRestore; - AddExState(StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); - WRAMSIZE = info->iNES2 ? (info->PRGRamSize + (info->PRGRamSaveSize & ~0x7FF)) : 8192; - WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + WRAMSIZE = 8192; + if (info->iNES2) { + WRAMSIZE = info->iNES2 ? (info->PRGRamSize + (info->PRGRamSaveSize & ~0x7FF)) : 8192; + } + if (WRAMSIZE) { + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + } - eeprom_93C66_init(eeprom_data, 512, 8); + eeprom_93Cx6_init(eeprom_data, 512, 8); info->battery = 1; info->SaveGame[0] = eeprom_data; info->SaveGameLen[0] = 512; diff --git a/src/mappers/mapper165.c b/src/mappers/mapper165.c new file mode 100644 index 000000000..8be8977b3 --- /dev/null +++ b/src/mappers/mapper165.c @@ -0,0 +1,94 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 reg; + +static uint8 *CHRRAM = NULL; +static uint32 CHRRAMSIZE = 0; + +static void M165CW(uint32 A, uint8 V) { + if (V == 0) { + setchr4r(0x10, A, 0); + } else { + setchr4(A, V >> 2); + } +} + +static void M165PPUFD(void) { + if (reg == 0xFD) { + M165CW(0x0000, mmc3.reg[0]); + M165CW(0x1000, mmc3.reg[2]); + } +} + +static void M165PPUFE(void) { + if (reg == 0xFE) { + M165CW(0x0000, mmc3.reg[1]); + M165CW(0x1000, mmc3.reg[4]); + } +} + +static void M165CWM(uint32 A, uint8 V) { + if (((mmc3.cmd & 0x7) == 0) || ((mmc3.cmd & 0x7) == 2)) { + M165PPUFD(); + } + if (((mmc3.cmd & 0x7) == 1) || ((mmc3.cmd & 0x7) == 4)) { + M165PPUFE(); + } +} + +static void M165PPU(uint32 A) { + if ((A & 0x1FF0) == 0x1FD0) { + reg = 0xFD; + M165PPUFD(); + } else if ((A & 0x1FF0) == 0x1FE0) { + reg = 0xFE; + M165PPUFE(); + } +} + +static void M165Close(void) { + MMC3_Close(); + if (CHRRAM) { + FCEU_free(CHRRAM); + CHRRAM = NULL; + } +} + +static void M165Power(void) { + reg = 0xFD; + MMC3_Power(); +} + +void Mapper165_Init(CartInfo *info) { + MMC3_Init(info, 8, info->battery); + info->Close = M165Close; + MMC3_cwrap = M165CWM; + PPU_hook = M165PPU; + info->Power = M165Power; + CHRRAMSIZE = 4096; + CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); + AddExState(®, 1, 0, "EXPR"); +} \ No newline at end of file diff --git a/src/boards/subor.c b/src/mappers/mapper166.c similarity index 57% rename from src/boards/subor.c rename to src/mappers/mapper166.c index 4f9a9bb60..3ce2b56db 100644 --- a/src/boards/subor.c +++ b/src/mappers/mapper166.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -20,53 +21,49 @@ #include "mapinc.h" -static uint8 is167, regs[4]; +static uint8 reg[4]; -static SFORMAT StateRegs[] = -{ - { regs, 4, "DREG" }, +static SFORMAT StateRegs[] = { + { reg, 4, "REGS" }, { 0 } }; static void Sync(void) { - int base, bank; - base = ((regs[0] ^ regs[1]) & 0x10) << 1; - bank = (regs[2] ^ regs[3]) & 0x1f; + uint16 base = ((reg[0] ^ reg[1]) & 0x10) << 1; + uint16 bank = (reg[2] ^ reg[3]) & 0x1f; - if (regs[1] & 0x08) { + if (reg[1] & 0x08) { bank &= 0xFE; - if (is167) { - setprg16(0x8000, base + bank + 1); - setprg16(0xC000, base + bank + 0); - } else { - setprg16(0x8000, base + bank + 0); - setprg16(0xC000, base + bank + 1); - } + setprg16(0x8000, base + bank + 0); + setprg16(0xC000, base + bank + 1); } else { - if (regs[1] & 0x04) { + if (reg[1] & 0x04) { setprg16(0x8000, 0x1F); setprg16(0xC000, base + bank); } else { setprg16(0x8000, base + bank); - if (is167) - setprg16(0xC000, 0x20); - else - setprg16(0xC000, 0x07); + setprg16(0xC000, 0x07); } } setchr8(0); } static DECLFW(M166Write) { - regs[(A >> 13) & 0x03] = V; + reg[(A >> 13) & 0x03] = V; Sync(); } static void M166Power(void) { - regs[0] = regs[1] = regs[2] = regs[3] = 0; + reg[0] = reg[1] = reg[2] = reg[3] = 0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); SetWriteHandler(0x8000, 0xFFFF, M166Write); + if (WRAMSIZE) { + setprg8r(0x10, 0x6000, 0); + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + } } static void StateRestore(int version) { @@ -74,15 +71,18 @@ static void StateRestore(int version) { } void Mapper166_Init(CartInfo *info) { - is167 = 0; info->Power = M166Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} + AddExState(StateRegs, ~0, 0, NULL); -void Mapper167_Init(CartInfo *info) { - is167 = 1; - info->Power = M166Power; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + WRAMSIZE = 8 * 1024; + if (info->iNES2) { + WRAMSIZE = info->PRGRamSize + info->PRGRamSaveSize; + } + if (WRAMSIZE) { + WRAM = (uint8 *)FCEU_malloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + } } diff --git a/src/mappers/mapper167.c b/src/mappers/mapper167.c new file mode 100644 index 000000000..1cfd7674d --- /dev/null +++ b/src/mappers/mapper167.c @@ -0,0 +1,88 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2005 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 reg[4]; + +static SFORMAT StateRegs[] = { + { reg, 4, "DREG" }, + { 0 } +}; + +static void Sync(void) { + uint16 base = ((reg[0] ^ reg[1]) & 0x10) << 1; + uint16 bank = (reg[2] ^ reg[3]) & 0x1f; + + if (reg[1] & 0x08) { + bank &= 0xFE; + setprg16(0x8000, base + bank + 1); + setprg16(0xC000, base + bank + 0); + } else { + if (reg[1] & 0x04) { + setprg16(0x8000, 0x1F); + setprg16(0xC000, base + bank); + } else { + setprg16(0x8000, base + bank); + setprg16(0xC000, 0x20); + } + } + setchr8(0); +} + +static DECLFW(M167Write) { + reg[(A >> 13) & 0x03] = V; + Sync(); +} + +static void M167Power(void) { + reg[0] = reg[1] = reg[2] = reg[3] = 0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + SetWriteHandler(0x8000, 0xFFFF, M167Write); + if (WRAMSIZE) { + setprg8r(0x10, 0x6000, 0); + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + } +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper167_Init(CartInfo *info) { + info->Power = M167Power; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + + WRAMSIZE = 8 * 1024; + if (info->iNES2) { + WRAMSIZE = info->PRGRamSize + info->PRGRamSaveSize; + } + if (WRAMSIZE) { + WRAM = (uint8 *)FCEU_malloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + } +} diff --git a/src/boards/mapper168.c b/src/mappers/mapper168.c similarity index 98% rename from src/boards/mapper168.c rename to src/mappers/mapper168.c index 924f7ab83..71652ae47 100644 --- a/src/boards/mapper168.c +++ b/src/mappers/mapper168.c @@ -71,7 +71,7 @@ void Mapper168_Init(CartInfo *info) { info->Power = M168Power; info->Close = M168Close; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); CHRRAMSIZE = 8192 * 8; CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); diff --git a/src/boards/mapper170.c b/src/mappers/mapper170.c similarity index 79% rename from src/boards/mapper170.c rename to src/mappers/mapper170.c index 37e8612d8..104d3620f 100644 --- a/src/boards/mapper170.c +++ b/src/mappers/mapper170.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2011 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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,41 +23,30 @@ static uint8 reg; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { ®, 1, "REGS" }, { 0 } }; -static void Sync(void) { - setprg16(0x8000, 0); - setprg16(0xc000, ~0); - setchr8(0); -} - static DECLFW(M170ProtW) { - reg = V << 1 & 0x80; + reg = ((V << 1) & 0x80); } static DECLFR(M170ProtR) { - return reg | (X.DB & 0x7F); + return (reg | (cpu.openbus & 0x7F)); } static void M170Power(void) { - Sync(); - SetWriteHandler(0x6502, 0x6502, M170ProtW); - SetWriteHandler(0x7000, 0x7000, M170ProtW); + setprg32(0x8000, 0); + setchr8(0); SetReadHandler(0x7001, 0x7001, M170ProtR); SetReadHandler(0x7777, 0x7777, M170ProtR); SetReadHandler(0x8000, 0xFFFF, CartBR); -} - -static void StateRestore(int version) { - Sync(); + SetWriteHandler(0x6502, 0x6502, M170ProtW); + SetWriteHandler(0x7000, 0x7000, M170ProtW); } void Mapper170_Init(CartInfo *info) { info->Power = M170Power; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/KS7058.c b/src/mappers/mapper171.c similarity index 85% rename from src/boards/KS7058.c rename to src/mappers/mapper171.c index 294a4de4c..cef5c3698 100644 --- a/src/boards/KS7058.c +++ b/src/mappers/mapper171.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -23,9 +23,9 @@ #include "mapinc.h" static uint8 chr[2]; -static SFORMAT StateRegs[] = -{ - { chr, 2, "CHR" }, + +static SFORMAT StateRegs[] = { + { chr, 2, "CREG" }, { 0 } }; @@ -36,11 +36,12 @@ static void Sync(void) { } static DECLFW(M171Write) { - chr[A & 1] = V; + chr[A & 0x01] = V; Sync(); } static void M171Power(void) { + chr[0] = chr[1] = 0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0xFFFF, M171Write); @@ -53,5 +54,5 @@ static void StateRestore(int version) { void Mapper171_Init(CartInfo *info) { info->Power = M171Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper172.c b/src/mappers/mapper172.c new file mode 100644 index 000000000..f4f18776d --- /dev/null +++ b/src/mappers/mapper172.c @@ -0,0 +1,54 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "jv001.h" + +static void M172Sync(void) { + setprg32(0x8000, 0); + setchr8(jv001.output); + setmirror((jv001.X & 1) ^ 1); +} + +static uint8 GetVal(uint8 V) { + return (((V << 5) & 0x20) | ((V << 3) & 0x10) | ((V << 1) & 0x08) | ((V >> 1) & 0x04) | + ((V >> 3) & 0x02) | ((V >> 5) & 0x01)); +} + +static DECLFW(M172Write) { + JV001_Write(A, GetVal(V)); +} + +static DECLFR(M172Read) { + return (cpu.openbus & 0xC0) | GetVal(JV001_Read(A)); +} + +static void M172Power(void) { + JV001_Power(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetReadHandler(0x4100, 0x5FFF, M172Read); + SetWriteHandler(0x4100, 0xFFFF, M172Write); +} + +void Mapper172_Init(CartInfo *info) { + JV001_Init(info, M172Sync); + info->Power = M172Power; +} diff --git a/src/mappers/mapper173.c b/src/mappers/mapper173.c new file mode 100644 index 000000000..70cd963e6 --- /dev/null +++ b/src/mappers/mapper173.c @@ -0,0 +1,52 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "txc.h" + +static void M173Sync(void) { + setprg32(0x8000, 0); + if (iNESCart.CHRRomSize >= (16 * 1024)) { + setchr8(((txc.output & 0x01) | (txc.Y ? 0x02 : 0x00) | ((txc.output & 2) << 0x01))); + } else { + setchr8(0); + } +} + +static DECLFW(M173Write) { + TXC_Write(A, V & 0x0F); +} + +static DECLFR(M173Read) { + return ((cpu.openbus & 0xF0) | (TXC_Read(A) & 0x0F)); +} + +static void M173Power(void) { + TXC_Power(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetReadHandler(0x4100, 0x5FFF, M173Read); + SetWriteHandler(0x4100, 0xFFFF, M173Write); +} + +void Mapper173_Init(CartInfo *info) { + TXC_Init(info, M173Sync); + info->Power = M173Power; +} diff --git a/src/boards/mapper174.c b/src/mappers/mapper174.c similarity index 71% rename from src/boards/mapper174.c rename to src/mappers/mapper174.c index e4520fe89..114262eff 100644 --- a/src/boards/mapper174.c +++ b/src/mappers/mapper174.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -23,15 +23,15 @@ static void Sync(void) { if (latch.addr & 0x80) { - setprg32(0x8000, (latch.addr >> 5) & 3); + setprg32(0x8000, (latch.addr >> 5) & 0x03); } else { - setprg16(0x8000, (latch.addr >> 4) & 7); - setprg16(0xC000, (latch.addr >> 4) & 7); + setprg16(0x8000, (latch.addr >> 4) & 0x07); + setprg16(0xC000, (latch.addr >> 4) & 0x07); } - setchr8((latch.addr >> 1) & 7); - setmirror((latch.addr & 1) ^ 1); + setchr8((latch.addr >> 1) & 0x07); + setmirror((latch.addr & 0x01) ^ 0x01); } void Mapper174_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); + Latch_Init(info, Sync, NULL, FALSE, FALSE); } diff --git a/src/boards/mapper175.c b/src/mappers/mapper175.c similarity index 65% rename from src/boards/mapper175.c rename to src/mappers/mapper175.c index 91e52a8eb..a0f896e7f 100644 --- a/src/boards/mapper175.c +++ b/src/mappers/mapper175.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2007 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -20,50 +21,49 @@ #include "mapinc.h" -static uint8 reg, delay, mirr; +static uint8 reg[2], mirr; -static SFORMAT StateRegs[] = -{ - { ®, 1, "REG" }, +static SFORMAT StateRegs[] = { + { reg, 2, "REG" }, { &mirr, 1, "MIRR" }, { 0 } }; static void Sync(void) { - setchr8(reg); - if (!delay) { - setprg16(0x8000, reg); - setprg8(0xC000, reg << 1); - } - setprg8(0xE000, (reg << 1) + 1); - setmirror(((mirr & 4) >> 2) ^ 1); -} - -static DECLFW(M175Write1) { - mirr = V; - delay = 1; - Sync(); + setprg16(0x8000, reg[0]); + setprg16(0xC000, reg[0]); + setchr8(reg[0]); + setmirror(((mirr >> 2) & 0x01) ^ 0x01); } -static DECLFW(M175Write2) { - reg = V & 0x0F; - delay = 1; - Sync(); +static DECLFR(M175Read) { + switch (A & 0xF000) { + case 0xF000: + if (reg[0] != reg[1]) { + reg[0] = reg[1]; + Sync(); + } + break; + } + return CartBR(A); } -static DECLFR(M175Read) { - if (A == 0xFFFC) { - delay = 0; +static DECLFW(M175Write) { + switch (A & 0xF000) { + case 0x8000: + mirr = V; Sync(); + break; + case 0xA000: + reg[1] = V; + break; } - return CartBR(A); } static void M175Power(void) { - reg = mirr = delay = 0; + reg[0] = reg[1] = mirr = 0; SetReadHandler(0x8000, 0xFFFF, M175Read); - SetWriteHandler(0x8000, 0x8000, M175Write1); - SetWriteHandler(0xA000, 0xA000, M175Write2); + SetWriteHandler(0x8000, 0xFFFF, M175Write); Sync(); } @@ -74,6 +74,5 @@ static void StateRestore(int version) { void Mapper175_Init(CartInfo *info) { info->Power = M175Power; GameStateRestore = StateRestore; - - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/fk23c.c b/src/mappers/mapper176.c similarity index 74% rename from src/boards/fk23c.c rename to src/mappers/mapper176.c index a40166ee7..9fc19bba8 100644 --- a/src/boards/fk23c.c +++ b/src/mappers/mapper176.c @@ -42,9 +42,7 @@ #include "mapinc.h" -static uint8 *WRAM = NULL; static uint8 *CHRRAM = NULL; -static uint32 WRAMSIZE = 0; static uint32 CHRRAMSIZE = 0; static uint8 fk23_regs[8] = { 0 }; /* JX9003B has eight registers, all others have four */ @@ -59,10 +57,12 @@ static uint8 irq_reload = 0; static uint8 latch = 0; static uint8 dipswitch = 0; static uint8 subType = 0; /* NES 2.0 Submapper, denoting PCB variants */ -static uint8 jncota523 = 0; /* Jncota board with unusual wiring that turns 1 KiB CHR banks into 2 KiB banks, and has hard-wired nametable mirroring. */ static uint8 dipsw_enable = 0; /* Change the address mask on every reset? */ static uint8 after_power = 0; /* Used for detecting whether a DIP switch is used or not (see above) */ +static void (*FK23_cwrap)(uint32 A, uint32 V); +static void (*SyncMIRR)(void); + static SFORMAT StateRegs[] = { { fk23_regs, 8, "EXPR" }, { mmc3_regs, 12, "M3RG" }, @@ -91,50 +91,43 @@ static SFORMAT StateRegs[] = { #define CHR_OUTER_BANK_SIZE !!( fk23_regs[0] & 0x10) /* Switch between 256 and 128 KiB CHR, or 32 and 16 KiB CHR in CNROM mode */ #define CHR_MIXED !!(WRAM_EXTENDED && mmc3_wram &0x04) /* First 8 KiB of CHR address space are RAM, then ROM */ -static void cwrap(uint32 A, uint32 V) { - int bank = 0; - - if (jncota523) { - if (~A & 0x0400) { - setchr2r(bank, A, V); - } - } else { - /* some workaround for chr rom / ram access */ - if (UNIFchrrama) { - /* CHR-RAM only */ - bank = 0; - } else if (CHRRAMSIZE) { - /* Mixed CHR-ROM + CHR-RAM */ - if ((fk23_regs[0] & 0x20) && ((subType == 0) || (subType == 1))) { - bank = 0x10; - } else if (CHR_MIXED && (V < 8)) { - /* first 8K of chr bank is RAM */ - bank = 0x10; - } +static void CHRWRAP(uint32 A, uint32 V) { + uint8 bank = 0; + + /* some workaround for chr rom / ram access */ + if (UNIFchrrama) { + /* CHR-RAM only */ + bank = 0; + } else if (CHRRAMSIZE) { + /* Mixed CHR-ROM + CHR-RAM */ + if ((fk23_regs[0] & 0x20) && ((subType == 0) || (subType == 1))) { + bank = 0x10; + } else if (CHR_MIXED && (V < 8)) { + /* first 8K of chr bank is RAM */ + bank = 0x10; } - setchr1r(bank, A, V); } + setchr1r(bank, A, V); } static void SyncCHR(void) { uint32 outer = fk23_regs[2] | - (subType == 3 ? (fk23_regs[6] << 8) : - 0); /* Outer 8 KiB CHR bank. Subtype 3 has an MSB register providing more bits. */ + (subType == 3 ? (fk23_regs[6] << 8) : 0); /* Outer 8 KiB CHR bank. Subtype 3 has an MSB register providing more bits. */ if (CHR_8K_MODE) { uint32 mask = (CHR_CNROM_MODE ? (CHR_OUTER_BANK_SIZE ? 0x01 : 0x03) : 0x00); /* In Submapper 1, address bits come either from outer bank or from latch. In Submapper 5, they are OR'd. Both * verified on original hardware. */ uint32 bank = ((subType == 5 ? outer : (outer & ~mask)) | (latch & mask)) << 3; - cwrap(0x0000, bank + 0); - cwrap(0x0400, bank + 1); - cwrap(0x0800, bank + 2); - cwrap(0x0C00, bank + 3); + FK23_cwrap(0x0000, bank + 0); + FK23_cwrap(0x0400, bank + 1); + FK23_cwrap(0x0800, bank + 2); + FK23_cwrap(0x0C00, bank + 3); - cwrap(0x1000, bank + 4); - cwrap(0x1400, bank + 5); - cwrap(0x1800, bank + 6); - cwrap(0x1C00, bank + 7); + FK23_cwrap(0x1000, bank + 4); + FK23_cwrap(0x1400, bank + 5); + FK23_cwrap(0x1800, bank + 6); + FK23_cwrap(0x1C00, bank + 7); } else { uint32 cbase = (INVERT_CHR ? 0x1000 : 0); uint32 mask = (CHR_OUTER_BANK_SIZE ? 0x7F : 0xFF); @@ -143,25 +136,25 @@ static void SyncCHR(void) { the outer bank or from the MMC3. */ if (MMC3_EXTENDED) { - cwrap(cbase ^ 0x0000, (mmc3_regs[0] & mask) | outer); - cwrap(cbase ^ 0x0400, (mmc3_regs[10] & mask) | outer); - cwrap(cbase ^ 0x0800, (mmc3_regs[1] & mask) | outer); - cwrap(cbase ^ 0x0c00, (mmc3_regs[11] & mask) | outer); - - cwrap(cbase ^ 0x1000, (mmc3_regs[2] & mask) | outer); - cwrap(cbase ^ 0x1400, (mmc3_regs[3] & mask) | outer); - cwrap(cbase ^ 0x1800, (mmc3_regs[4] & mask) | outer); - cwrap(cbase ^ 0x1c00, (mmc3_regs[5] & mask) | outer); + FK23_cwrap(cbase ^ 0x0000, (mmc3_regs[0] & mask) | outer); + FK23_cwrap(cbase ^ 0x0400, (mmc3_regs[10] & mask) | outer); + FK23_cwrap(cbase ^ 0x0800, (mmc3_regs[1] & mask) | outer); + FK23_cwrap(cbase ^ 0x0c00, (mmc3_regs[11] & mask) | outer); + + FK23_cwrap(cbase ^ 0x1000, (mmc3_regs[2] & mask) | outer); + FK23_cwrap(cbase ^ 0x1400, (mmc3_regs[3] & mask) | outer); + FK23_cwrap(cbase ^ 0x1800, (mmc3_regs[4] & mask) | outer); + FK23_cwrap(cbase ^ 0x1c00, (mmc3_regs[5] & mask) | outer); } else { - cwrap(cbase ^ 0x0000, ((mmc3_regs[0] & 0xFE) & mask) | outer); - cwrap(cbase ^ 0x0400, ((mmc3_regs[0] | 0x01) & mask) | outer); - cwrap(cbase ^ 0x0800, ((mmc3_regs[1] & 0xFE) & mask) | outer); - cwrap(cbase ^ 0x0C00, ((mmc3_regs[1] | 0x01) & mask) | outer); - - cwrap(cbase ^ 0x1000, (mmc3_regs[2] & mask) | outer); - cwrap(cbase ^ 0x1400, (mmc3_regs[3] & mask) | outer); - cwrap(cbase ^ 0x1800, (mmc3_regs[4] & mask) | outer); - cwrap(cbase ^ 0x1c00, (mmc3_regs[5] & mask) | outer); + FK23_cwrap(cbase ^ 0x0000, ((mmc3_regs[0] & 0xFE) & mask) | outer); + FK23_cwrap(cbase ^ 0x0400, ((mmc3_regs[0] | 0x01) & mask) | outer); + FK23_cwrap(cbase ^ 0x0800, ((mmc3_regs[1] & 0xFE) & mask) | outer); + FK23_cwrap(cbase ^ 0x0C00, ((mmc3_regs[1] | 0x01) & mask) | outer); + + FK23_cwrap(cbase ^ 0x1000, (mmc3_regs[2] & mask) | outer); + FK23_cwrap(cbase ^ 0x1400, (mmc3_regs[3] & mask) | outer); + FK23_cwrap(cbase ^ 0x1800, (mmc3_regs[4] & mask) | outer); + FK23_cwrap(cbase ^ 0x1c00, (mmc3_regs[5] & mask) | outer); } } } @@ -170,18 +163,21 @@ static void SyncPRG(void) { uint32 mask = 0x3F >> PRG_MODE; /* For PRG modes 0-2, the mode# decides how many bits of the inner 8 KiB bank are used. This is greatly relevant to map the correct bank that contains the reset vectors. */ uint32 prg_base = fk23_regs[1] & 0x7F; /* The bits for the first 2 MiB are the same between all the variants. */ + uint32 cbase = 0; switch (subType) { case 1: /* FK-xxx */ - if (PRG_MODE == 7 || MMC3_EXTENDED) + if (PRG_MODE == 7 || MMC3_EXTENDED) { mask = 0xFF; /* Mode 7 allows the MMC3 to address 2 MiB rather than the usual 512 KiB. */ + } break; case 2: /* FS005 */ prg_base |= ((fk23_regs[0] << 4) & 0x080) | ((fk23_regs[0] << 1) & 0x100) | ((fk23_regs[2] << 3) & 0x600) | ((fk23_regs[2] << 6) & 0x800); break; case 3: /* JX9003B */ - if (PRG_MODE == 7) + if (PRG_MODE == 7) { mask = 0xFF; /* Mode 7 allows the MMC3 to address 2 MiB rather than the usual 512 KiB. */ + } prg_base |= fk23_regs[5] << 7; break; case 4: /* GameStar Smart Genius Deluxe */ @@ -200,12 +196,9 @@ static void SyncPRG(void) { /* 7: MMC3 with 2 MB addressable. Used byc at least on 2 games: - 最终幻想 2 - 光明篇 (Final Fantasy 2 - Arc of Light) - 梦幻仙境 - (Fantasy Wonderworld) */ - { - uint32 cbase = (INVERT_PRG ? 0x4000 : 0); - + cbase = (INVERT_PRG ? 0x4000 : 0); prg_base = (prg_base << 1) & ~mask; /* from 16 to 8 KiB. Address bits are never OR'd; they either come from the outer bank or from the MMC3. */ - if (MMC3_EXTENDED) { setprg8(0x8000 ^ cbase, (mmc3_regs[6] & mask) | prg_base); setprg8(0xA000, (mmc3_regs[7] & mask) | prg_base); @@ -218,7 +211,6 @@ static void SyncPRG(void) { setprg8(0xE000, (0xFF & mask) | prg_base); } break; - } case 3: /* NROM-128 */ setprg16(0x8000, prg_base); setprg16(0xC000, prg_base); @@ -239,36 +231,26 @@ static void SyncWRAM(void) { if (WRAM_EXTENDED) { setprg8r(0x10, 0x4000, (mmc3_wram + 1) & 0x03); setprg8r(0x10, 0x6000, (mmc3_wram + 0) & 0x03); - } else + } else { setprg8r(0x10, 0x6000, 0); + } } } -static void SyncMIR(void) { - if (jncota523) /* Jncota board has hard-wired mirroring */ - return; - else - switch (mmc3_mirr & (subType == 2 ? 0x03 : 0x01)) { - case 0: - setmirror(MI_V); - break; - case 1: - setmirror(MI_H); - break; - case 2: - setmirror(MI_0); - break; - case 3: - setmirror(MI_1); - break; - } +static void FixMir(void) { + switch (mmc3_mirr & (subType == 2 ? 0x03 : 0x01)) { + case 0: setmirror(MI_V); break; + case 1: setmirror(MI_H); break; + case 2: setmirror(MI_0); break; + case 3: setmirror(MI_1); break; + } } static void Sync(void) { SyncPRG(); SyncCHR(); SyncWRAM(); - SyncMIR(); + SyncMIRR(); } static DECLFW(Write4800) /* Only used by submapper 5 (HST-162) */ @@ -279,8 +261,7 @@ static DECLFW(Write4800) /* Only used by submapper 5 (HST-162) */ } static DECLFW(Write5000) { if (after_power && A > 0x5010 && - A != 0x5FF3) /* Ignore writes from $5000-$500F, in particular to $5008, but not $5FF3 */ - { + A != 0x5FF3) { /* Ignore writes from $5000-$500F, in particular to $5008, but not $5FF3 */ after_power = 0; dipsw_enable = A >= 0x5020; /* The DIP switch change on soft-reset is enabled if the first write after power-on is not to $501x */ @@ -289,70 +270,73 @@ static DECLFW(Write5000) { fk23_regs[A & (subType == 3 ? 7 : 3)] = V; SyncPRG(); SyncCHR(); - } else + } else { /* FK23C Registers disabled, $5000-$5FFF maps to the second 4 KiB of the 8 KiB WRAM bank 2 */ CartBW(A, V); + } } static DECLFW(Write8000) { + uint8 old_ctrl = 0; + uint8 ctrl_mask = 0; + latch = V; - if (CHR_8K_MODE && CHR_CNROM_MODE) + if (CHR_8K_MODE && CHR_CNROM_MODE) { SyncCHR(); /* CNROM latch updated */ - if (PRG_MODE == 5) + } + if (PRG_MODE == 5) { SyncPRG(); /* UNROM latch has been updated */ + } switch (A & 0xE001) { - case 0x8000: { - uint8 old_ctrl; - if (A & 2) + case 0x8000: + if (A & 2) { return; /* Confirmed on real hardware: writes to 8002 and 8003, or 9FFE and 9FFF, are ignored. Needed for Dr. Mario on some of the "bouncing ball" multis. */ + } old_ctrl = mmc3_ctrl; - /* Subtype 2, 8192 or more KiB PRG-ROM, no CHR-ROM: Like Subtype 0, * but MMC3 registers $46 and $47 swapped. */ if (subType == 2) { - if (V == 0x46) + if (V == 0x46) { V = 0x47; - else if (V == 0x47) + } else if (V == 0x47) { V = 0x46; + } } - mmc3_ctrl = V; - - if (INVERT_PRG != (old_ctrl & 0x40)) + if (INVERT_PRG != (old_ctrl & 0x40)) { SyncPRG(); - - if (INVERT_CHR != (old_ctrl & 0x80)) + } + if (INVERT_CHR != (old_ctrl & 0x80)) { SyncCHR(); - + } break; - } - case 0x8001: { - uint8 ctrl_mask; - if (A & 2) + case 0x8001: + if (A & 2) { return; /* Confirmed on real hardware: writes to 8002 and 8003, or 9FFE and 9FFF, are ignored. Needed for Dr. Mario on some of the "bouncing ball" multis. */ + } ctrl_mask = MMC3_EXTENDED ? 0x0F : 0x07; - if ((mmc3_ctrl & ctrl_mask) < 12) { mmc3_regs[mmc3_ctrl & ctrl_mask] = V; - if (((mmc3_ctrl & ctrl_mask) < 6) || ((mmc3_ctrl & ctrl_mask) >= 10)) + if (((mmc3_ctrl & ctrl_mask) < 6) || ((mmc3_ctrl & ctrl_mask) >= 10)) { SyncCHR(); - else + } else { SyncPRG(); + } } break; - } case 0xA000: mmc3_mirr = V; - SyncMIR(); + SyncMIRR(); break; case 0xA001: /* ignore bits when ram config register is disabled */ - if ((V & 0x20) == 0) + if ((V & 0x20) == 0) { V &= 0xC0; + } mmc3_wram = V; Sync(); break; @@ -375,14 +359,14 @@ static DECLFW(Write8000) { } static void M176HBIRQHook(void) { - if (!irq_count || irq_reload) + if (!irq_count || irq_reload) { irq_count = irq_latch; - else + } else { irq_count--; - - if (!irq_count && irq_enabled) + } + if (!irq_count && irq_enabled) { X6502_IRQBegin(FCEU_IQEXT); - + } irq_reload = 0; } @@ -393,9 +377,9 @@ static void M176Reset(void) { FCEU_printf("BMCFK23C dipswitch set to $%04x\n", 0x5000 | 0x10 << dipswitch); } - fk23_regs[1] = fk23_regs[2] = fk23_regs[3] = fk23_regs[4] = fk23_regs[5] = fk23_regs[6] = - fk23_regs[7] = 0; fk23_regs[0] = (subType == 1 || subType == 3) ? 7 : 0; + fk23_regs[1] = fk23_regs[2] = fk23_regs[3] = 0; + fk23_regs[4] = fk23_regs[5] = fk23_regs[6] = fk23_regs[7] = 0; mmc3_regs[0] = 0; mmc3_regs[1] = 2; mmc3_regs[2] = 4; @@ -415,9 +399,9 @@ static void M176Reset(void) { } static void M176Power(void) { - fk23_regs[1] = fk23_regs[2] = fk23_regs[3] = fk23_regs[4] = fk23_regs[5] = fk23_regs[6] = - fk23_regs[7] = 0; fk23_regs[0] = (subType == 1 || subType == 3) ? 7 : 0; + fk23_regs[1] = fk23_regs[2] = fk23_regs[3] = 0; + fk23_regs[4] = fk23_regs[5] = fk23_regs[6] = fk23_regs[7] = 0; mmc3_regs[0] = 0; mmc3_regs[1] = 2; mmc3_regs[2] = 4; @@ -439,8 +423,9 @@ static void M176Power(void) { SetWriteHandler(0x5000, 0x5FFF, Write5000); SetWriteHandler(0x8000, 0xFFFF, Write8000); - if (subType == 5) + if (subType == 5) { SetWriteHandler(0x4800, 0x4FFF, Write4800); + } if (WRAMSIZE) { if (subType == 2) { @@ -453,12 +438,9 @@ static void M176Power(void) { } static void M176Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; - - if (CHRRAM) + if (CHRRAM) { FCEU_gfree(CHRRAM); + } CHRRAM = NULL; } @@ -466,14 +448,18 @@ static void StateRestore(int version) { Sync(); } -void Init(CartInfo *info) { +static void Init(CartInfo *info) { + /* Setup default function wrappers */ + FK23_cwrap = CHRWRAP; + SyncMIRR = FixMir; + /* Initialization for iNES and UNIF. subType and dipsw_enable must have been set. */ info->Power = M176Power; info->Reset = M176Reset; info->Close = M176Close; GameHBIRQHook = M176HBIRQHook; GameStateRestore = StateRestore; - AddExState(StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); if (CHRRAMSIZE) { CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); @@ -488,17 +474,17 @@ void Init(CartInfo *info) { if (info->battery) { info->SaveGame[0] = WRAM; - if (info->iNES2 && info->PRGRamSaveSize) + if (info->iNES2 && info->PRGRamSaveSize) { info->SaveGameLen[0] = info->PRGRamSaveSize; - else + } else { info->SaveGameLen[0] = WRAMSIZE; + } } } } void Mapper176_Init(CartInfo *info) { /* .NES file */ dipsw_enable = 0; - jncota523 = 0; if (info->iNES2) { subType = info->submapper; after_power = subType != 2; /* FS005 never has DIP switches, the others may have one, so use the heuristic. */ @@ -511,17 +497,19 @@ void Mapper176_Init(CartInfo *info) { /* .NES file */ after_power = 0; WRAMSIZE = 32 * 1024; } else { + uint32 prg = iNESCart.PRGRomSize / 1024; + uint32 chr = iNESCart.CHRRomSize / 1024; + /* Always enable WRAM for iNES-headered files */ WRAMSIZE = 8 * 1024; /* Distinguishing subType 1 from subType 0 is important for the correct reset vector location. It is safe to assume subType 1 except for the following-sized ROMs. */ - subType = ((ROM_size == 128 && VROM_size == 256) || /* 2048+2048 */ - (ROM_size == 128 && VROM_size == 128) || /* 2048+1024 */ - (ROM_size == 128 && VROM_size == 64) || /* 2048+512 */ - (ROM_size == 128 && VROM_size == 0) || /* 2048+0 */ - (ROM_size == 64 && VROM_size == 64)) ? /* 1024+512 */ - 0 : 1; + subType = ((prg == 2048 && chr == 2048) || + (prg == 2048 && chr == 1024) || + (prg == 2048 && chr == 512) || + (prg == 2048 && chr == 0) || + (prg == 64 && chr == 512)) ? 0 : 1; /* Detect heuristically whether the address mask should be changed on every soft reset */ after_power = 1; @@ -530,68 +518,77 @@ void Mapper176_Init(CartInfo *info) { /* .NES file */ Init(info); } -void BMCFK23C_Init( - CartInfo *info) /* UNIF FK23C. Also includes mislabelled WAIXING-FS005, recognizable by their PRG-ROM size. */ -{ +/* UNIF FK23C. Also includes mislabelled WAIXING-FS005, recognizable by their PRG-ROM size. */ +void BMCFK23C_Init(CartInfo *info) { if (!UNIFchrrama) { /* Rockman I-VI uses mixed chr rom/ram */ - if ((ROM_size * 16) == 2048 && (VROM_size * 8) == 512) + if ((ROM.prg.size * 16) == 2048 && (ROM.chr.size * 8) == 512) { CHRRAMSIZE = 8 * 1024; + } } WRAMSIZE = 8 * 1024; dipsw_enable = 0; after_power = 1; - jncota523 = 0; - subType = ROM_size * 16 >= 4096 ? 2 : ROM_size == 64 && VROM_size == 128 ? 1 : 0; - if (subType == 2) + subType = ROM.prg.size * 16 >= 4096 ? 2 : ROM.prg.size == 64 && ROM.chr.size == 128 ? 1 : 0; + if (subType == 2) { CHRRAMSIZE = 256 * 1024; + } Init(info); } -void BMCFK23CA_Init( - CartInfo *info) /* UNIF FK23CA. Also includes mislabelled WAIXING-FS005, recognizable by their PRG-ROM size. */ -{ + /* UNIF FK23CA. Also includes mislabelled WAIXING-FS005, recognizable by their PRG-ROM size. */ +void BMCFK23CA_Init(CartInfo *info) { WRAMSIZE = 8 * 1024; dipsw_enable = 0; after_power = 1; - jncota523 = 0; - subType = ROM_size * 16 >= 2048 ? 2 : 1; - if (subType == 2) + subType = ROM.prg.size * 16 >= 2048 ? 2 : 1; + if (subType == 2) { CHRRAMSIZE = 256 * 1024; + } Init(info); } -void Super24_Init(CartInfo *info) /* UNIF BMC-Super24in1SC03 */ -{ +/* UNIF BMC-Super24in1SC03 */ +void Super24_Init(CartInfo *info) { CHRRAMSIZE = 8 * 1024; dipsw_enable = 0; after_power = 0; - jncota523 = 0; subType = 0; Init(info); } -void WAIXINGFS005_Init(CartInfo *info) /* UNIF WAIXING-FS005 */ -{ +/* UNIF WAIXING-FS005 */ +void WAIXINGFS005_Init(CartInfo *info) { CHRRAMSIZE = 8 * 1024; WRAMSIZE = 32 * 1024; dipsw_enable = 0; after_power = 0; - jncota523 = 0; subType = 2; Init(info); } -void Mapper523_Init(CartInfo *info) /* Jncota Fengshengban */ -{ +static void M523CW(uint32 A, uint32 V) { + if (~A & 0x0400) { + setchr2(A, V); + } +} + +static void M523MIR(void) { + /* Jncota board has hard-wired mirroring */ +} + +/* Jncota board with unusual wiring that turns 1 KiB CHR banks into 2 KiB banks, and has hard-wired nametable mirroring. */ +void Mapper523_Init(CartInfo *info) { /* Jncota Fengshengban */ WRAMSIZE = 8 * 1024; dipsw_enable = 0; after_power = 0; - jncota523 = 1; subType = 1; + Init(info); + SyncMIRR = M523MIR; + FK23_cwrap = M523CW; } diff --git a/src/boards/mapper177.c b/src/mappers/mapper177.c similarity index 84% rename from src/boards/mapper177.c rename to src/mappers/mapper177.c index 5db8db09a..936f8ffcc 100644 --- a/src/boards/mapper177.c +++ b/src/mappers/mapper177.c @@ -1,8 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2007 CaH4e3 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,13 +25,13 @@ #include "latch.h" static void Sync(void) { - setchr8(0); setprg8r(0x10, 0x6000, 0); - setprg32(0x8000, latch.data & 0x1f); + setprg32(0x8000, latch.data & 0x1F); + setchr8(0); setmirror(((latch.data & 0x20) >> 5) ^ 1); } void Mapper177_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 1, 0); - info->Reset = LatchHardReset; + Latch_Init(info, Sync, NULL, TRUE, FALSE); + info->Reset = Latch_RegReset; } diff --git a/src/mappers/mapper178.c b/src/mappers/mapper178.c new file mode 100644 index 000000000..ae2050e8d --- /dev/null +++ b/src/mappers/mapper178.c @@ -0,0 +1,107 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2013 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + * DSOUNDV1/FL-TR8MA boards (32K WRAM, 8/16M), 178 mapper boards (8K WRAM, 4/8M) + * Various Education Cartridges + * + * mapper 551 + * Compared to INES Mapper 178, mirroring is hard-wired, and the chipset's internal CHR-RAM is not used in favor of CHR-ROM. + * + */ + +#include "mapinc.h" + +static uint8 reg[4]; + +static SFORMAT StateRegs[] = { + { reg, 4, "REGS" }, + { 0 } +}; + +static void Sync(void) { + uint16 base = (reg[1] & 0x07) | (reg[2] << 3); + + if ((reg[0] & 0x02)) { + setprg16(0x8000, base); + setprg16(0xC000, base | ((reg[0] & 0x04) ? 0x06 : 0x07)); + } else { + if (reg[0] & 0x04) { + setprg16(0x8000, base); + setprg16(0xC000, base); + } else { + setprg32(0x8000, base >> 1); + } + } + + if (iNESCart.mapper == 551) { + setprg8r(0x10, 0x6000, 0); + setchr8(reg[3]); + } else { + setchr8(0); + setprg8r(0x10, 0x6000, reg[3] & 3); + setmirror((reg[0] & 1) ^ 1); + } +} + +static DECLFW(M178Write) { + reg[A & 3] = V; +/* FCEU_printf("cmd %04x:%02x\n", A, V); */ + Sync(); +} + +static void M178Power(void) { + reg[0] = reg[1] = reg[2] = reg[3] = 0; + Sync(); + SetWriteHandler(0x4800, 0x4FFF, M178Write); + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + SetReadHandler(0x8000, 0xFFFF, CartBR); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); +} + +static void M178Reset(void) { + /* Always reset to menu */ + reg[0] = reg[1] = reg[2] = reg[3] = 0; + Sync(); +} + +static void M178Close(void) { +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper178_Init(CartInfo *info) { + info->Power = M178Power; + info->Reset = M178Reset; + info->Close = M178Close; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + + WRAMSIZE = 8192; + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } +} diff --git a/src/mappers/mapper180.c b/src/mappers/mapper180.c new file mode 100644 index 000000000..ea396672e --- /dev/null +++ b/src/mappers/mapper180.c @@ -0,0 +1,33 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg16(0x8000, 0); + setprg16(0xC000, latch.data); + setchr8(0); +} + +void Mapper180_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, TRUE); +} diff --git a/src/boards/mapper183.c b/src/mappers/mapper183.c similarity index 62% rename from src/boards/mapper183.c rename to src/mappers/mapper183.c index 17326666d..0e081cf54 100644 --- a/src/boards/mapper183.c +++ b/src/mappers/mapper183.c @@ -1,8 +1,8 @@ -/* FCEU mm - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -23,57 +23,65 @@ */ #include "mapinc.h" -#include "vrc24.h" +#include "vrc2and4.h" static uint8 prg[4]; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { prg, 4, "PRG" }, { 0 } }; -static void M183PW(void) { - setprg8(0x6000, prg[3]); - setprg8(0x8000, prg[0]); - setprg8(0xA000, prg[1]); - setprg8(0xC000, prg[2]); - setprg8(0xE000, ~0); +static void M183PRG(void) { + setprg8(0x6000, prg[0] & 0x3F); + setprg8(0x8000, prg[1] & 0x3F); + setprg8(0xA000, prg[2] & 0x3F); + setprg8(0xC000, prg[3] & 0x3F); + setprg8(0xE000, (~0) & 0x3F); } static DECLFW(M183Write) { - switch (A & 0xF80C) { + switch (A & 0xF800) { case 0x6800: - prg[3] = A & 0x3F; - FixVRC24PRG(); + prg[0] = A; + VRC24_FixPRG(); break; case 0x8800: - prg[0] = V; - FixVRC24PRG(); - break; - case 0x9800: - VRC24Write(0x9000 | (A & 0xC0), V); + prg[1] = V; + VRC24_FixPRG(); break; case 0xA800: - prg[1] = V; - FixVRC24PRG(); + prg[2] = V; + VRC24_FixPRG(); break; case 0xA000: - prg[2] = V; - FixVRC24PRG(); + prg[3] = V; + VRC24_FixPRG(); + break; + case 0x9800: + VRC24_Write(0x9000, V); break; + case 0x6000: + case 0x7000: + case 0x7800: + case 0x8000: + case 0x9000: + return; + default: + VRC24_Write(A, V); + return; } } static void M183Power(void) { - GenVRC24Power(); + VRC24_Power(); SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0xAFFF, M183Write); + SetWriteHandler(0x6000, 0xFFFF, M183Write); } void Mapper183_Init(CartInfo *info) { - GenVRC24_Init(info, VRC4e, 0); + VRC24_Init(info, VRC4, 0x04, 0x08, 0, 1); info->Power = M183Power; - vrc24.pwrap = M183PW; - AddExState(&StateRegs, ~0, 0, 0); + VRC24_FixPRG = M183PRG; + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper184.c b/src/mappers/mapper184.c similarity index 85% rename from src/boards/mapper184.c rename to src/mappers/mapper184.c index c98ea024d..654123182 100644 --- a/src/boards/mapper184.c +++ b/src/mappers/mapper184.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,16 +22,15 @@ static uint8 reg; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { ®, 1, "REG" }, { 0 } }; -static void Sync() { - setchr4(0x0000, reg); - setchr4(0x1000, reg >> 4); +static void Sync(void) { setprg32(0x8000, 0); + setchr4(0x0000, reg & 0x0F); + setchr4(0x1000, (reg >> 4) & 0x0F); } static DECLFW(M184Write) { @@ -53,5 +52,5 @@ static void StateRestore(int version) { void Mapper184_Init(CartInfo *info) { info->Power = M184Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper185.c b/src/mappers/mapper185.c similarity index 64% rename from src/boards/mapper185.c rename to src/mappers/mapper185.c index 36984622b..e26337c43 100644 --- a/src/boards/mapper185.c +++ b/src/mappers/mapper185.c @@ -1,8 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -24,42 +24,40 @@ #include "latch.h" static uint8 *DummyCHR = NULL; -static uint8 submapper = 0; - -/* on off -1 0x0F, 0xF0 - Bird Week -2 0x33, 0x00 - B-Wings -3 0x11, 0x00 - Mighty Bomb Jack -4 0x22, 0x20 - Sansuu 1 Nen, Sansuu 2 Nen -5 0xFF, 0x00 - Sansuu 3 Nen -6 0x21, 0x13 - Spy vs Spy -7 0x20, 0x21 - Seicross -*/ static void Sync(void) { + /* on off + 1 0x0F, 0xF0 - Bird Week + 2 0x33, 0x00 - B-Wings + 3 0x11, 0x00 - Mighty Bomb Jack + 4 0x22, 0x20 - Sansuu 1 Nen, Sansuu 2 Nen + 5 0xFF, 0x00 - Sansuu 3 Nen + 6 0x21, 0x13 - Spy vs Spy + 7 0x20, 0x21 - Seicross */ + uint8 chrEnable = ( + ((iNESCart.submapper != 4) && ((latch.data & 3) != 0) && (latch.data != 0x13)) || /* 1, 2, 3, 4, 5, 6 */ + ((iNESCart.submapper == 4) && ((latch.data & 1) == 0)) /* 7 */ + ) ? 0 : 0x10; setprg32(0x8000, 0); - if ((submapper != 4 && (latch.data & 3) != 0 && latch.data != 0x13) || /* 1, 2, 3, 4, 5, 6 */ - (submapper == 4 && (latch.data & 1) == 0)) { /* 7 */ - setchr8(0); - } else { - setchr8r(0x10, 0); - } + setchr8r(chrEnable, 0); } static void M185Close(void) { - LatchClose(); - if (DummyCHR) + Latch_Close(); + if (DummyCHR) { FCEU_gfree(DummyCHR); + } DummyCHR = NULL; } void Mapper185_Init(CartInfo *info) { int x; - Latch_Init(info, Sync, NULL, 0, 0); + Latch_Init(info, Sync, NULL, FALSE, FALSE); info->Close = M185Close; - submapper = info->submapper; + DummyCHR = (uint8 *)FCEU_gmalloc(8192); - for (x = 0; x < 8192; x++) - DummyCHR[x] = 0xff; SetupCartCHRMapping(0x10, DummyCHR, 8192, 0); + for (x = 0; x < 8192; x++) { + DummyCHR[x] = 0xff; + } } diff --git a/src/boards/mapper186.c b/src/mappers/mapper186.c similarity index 86% rename from src/boards/mapper186.c rename to src/mappers/mapper186.c index f26bda4f2..2c10a1d0b 100644 --- a/src/boards/mapper186.c +++ b/src/mappers/mapper186.c @@ -23,25 +23,24 @@ #include "mapinc.h" static uint8 SWRAM[3072]; -static uint8 *WRAM = NULL; -static uint8 regs[4]; +static uint8 reg[4]; -static SFORMAT StateRegs[] = -{ - { regs, 4, "DREG" }, +static SFORMAT StateRegs[] = { + { reg, 4, "DREG" }, { SWRAM, 3072, "SWRM" }, { 0 } }; static void Sync(void) { - setprg8r(0x10, 0x6000, regs[0] >> 6); - setprg16(0x8000, regs[1]); + setprg8r(0x10, 0x6000, reg[0] >> 6); + setprg16(0x8000, reg[1]); setprg16(0xc000, 0); + setchr8(0); } static DECLFW(M186Write) { if (A & 0x4203) - regs[A & 3] = V; + reg[A & 3] = V; Sync(); } @@ -67,7 +66,6 @@ static DECLFW(BSWRAM) { } static void M186Power(void) { - setchr8(0); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0xFFFF, CartBW); SetReadHandler(0x4200, 0x43FF, M186Read); @@ -75,14 +73,11 @@ static void M186Power(void) { SetReadHandler(0x4400, 0x4FFF, ASWRAM); SetWriteHandler(0x4400, 0x4FFF, BSWRAM); FCEU_CheatAddRAM(32, 0x6000, WRAM); - regs[0] = regs[1] = regs[2] = regs[3]; + reg[0] = reg[1] = reg[2] = reg[3]; Sync(); } static void M186Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; } static void M186Restore(int version) { @@ -96,5 +91,5 @@ void Mapper186_Init(CartInfo *info) { WRAM = (uint8 *)FCEU_gmalloc(32768); SetupCartPRGMapping(0x10, WRAM, 32768, 1); AddExState(WRAM, 32768, 0, "WRAM"); - AddExState(StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper187.c b/src/mappers/mapper187.c similarity index 72% rename from src/boards/mapper187.c rename to src/mappers/mapper187.c index 2ce37bc41..6d1ccd813 100644 --- a/src/boards/mapper187.c +++ b/src/mappers/mapper187.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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,48 +26,53 @@ #include "mapinc.h" #include "mmc3.h" +static uint8 reg; + static void M187CW(uint32 A, uint8 V) { - if ((A & 0x1000) == ((mmc3.cmd & 0x80) << 5)) + if ((A & 0x1000) == ((mmc3.cmd & 0x80) << 5)) { setchr1(A, V | 0x100); - else + } else { setchr1(A, V); + } } static void M187PW(uint32 A, uint8 V) { - if (mmc3.expregs[0] & 0x80) { - uint8 bank = (mmc3.expregs[0] >> 1) & 0x0F; - if (mmc3.expregs[0] & 0x20) { + if (reg & 0x80) { + uint8 bank = (reg >> 1) & 0x0F; + + if (reg & 0x20) { setprg32(0x8000, bank >> 1); } else { setprg16(0x8000, bank); setprg16(0xC000, bank); } - } else + } else { setprg8(A, V & 0x3F); + } } -static DECLFW(M187WriteLo) { - if (!(A & 1)) { - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); +static DECLFW(M187Write) { + if (!(A & 0x01)) { + reg = V; + MMC3_FixPRG(); } } static DECLFR(M187Read) { - return X.DB | 0x80; + return cpu.openbus | 0x80; } static void M187Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); + reg = 0; + MMC3_Power(); SetReadHandler(0x5000, 0x5FFF, M187Read); - SetWriteHandler(0x5000, 0x5FFF, M187WriteLo); + SetWriteHandler(0x5000, 0x5FFF, M187Write); } void Mapper187_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 0, 0); - mmc3.pwrap = M187PW; - mmc3.cwrap = M187CW; + MMC3_Init(info, 0, 0); + MMC3_pwrap = M187PW; + MMC3_cwrap = M187CW; info->Power = M187Power; - AddExState(mmc3.expregs, 1, 0, "EXPR"); + AddExState(®, 1, 0, "EXPR"); } diff --git a/src/boards/karaoke.c b/src/mappers/mapper188.c similarity index 78% rename from src/boards/karaoke.c rename to src/mappers/mapper188.c index 7f7611168..95d1fbc5f 100644 --- a/src/boards/karaoke.c +++ b/src/mappers/mapper188.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2002 Xodnizel + * Copyright (C) 2023-2024 negativeExponent * * 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,15 +23,13 @@ #include "latch.h" static void Sync(void) { + if (latch.data & 0x10) { + setprg16(0x8000, (latch.data & 0x07)); + } else { + setprg16(0x8000, (0x08 | latch.data)); + } + setprg16(0xC000, 0x07); setchr8(0); - setprg16(0xc000, 0x7); - if (latch.data) { - if (latch.data & 0x10) - setprg16(0x8000, (latch.data & 7)); - else - setprg16(0x8000, (latch.data & 7) | 8); - } else - setprg16(0x8000, 7 + (ROM_size >> 4)); } static DECLFR(ExtDev) { @@ -38,11 +37,11 @@ static DECLFR(ExtDev) { } static void M118Power(void) { - LatchPower(); + Latch_Power(); SetReadHandler(0x6000, 0x7FFF, ExtDev); } void Mapper188_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); + Latch_Init(info, Sync, NULL, FALSE, FALSE); info->Power = M118Power; } diff --git a/src/boards/mapper189.c b/src/mappers/mapper189.c similarity index 66% rename from src/boards/mapper189.c rename to src/mappers/mapper189.c index 6e4f6577d..baf876165 100644 --- a/src/boards/mapper189.c +++ b/src/mappers/mapper189.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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,34 +22,36 @@ #include "mapinc.h" #include "mmc3.h" +static uint8 reg; + static void M189PW(uint32 A, uint8 V) { - setprg32(0x8000, mmc3.expregs[0] | (mmc3.expregs[0] >> 4)); + setprg32(0x8000, reg | (reg >> 4)); } -static DECLFW(M189Write) { +static DECLFW(M189Write4) { if (A & 0x100) { - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); + reg = V; + MMC3_FixPRG(); } } -static DECLFW(M189WRAMWrite) { - if (MMC3CanWriteToWRAM()) { - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); +static DECLFW(M189Write6) { + if (MMC3_WramIsWritable()) { + reg = V; + MMC3_FixPRG(); } } static void M189Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); - SetWriteHandler(0x4120, 0x5FFF, M189Write); - SetWriteHandler(0x6000, 0x7FFF, M189WRAMWrite); + reg = 0; + MMC3_Power(); + SetWriteHandler(0x4120, 0x5FFF, M189Write4); + SetWriteHandler(0x6000, 0x7FFF, M189Write6); } void Mapper189_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 0, 0); - mmc3.pwrap = M189PW; + MMC3_Init(info, 0, 0); + MMC3_pwrap = M189PW; info->Power = M189Power; - AddExState(mmc3.expregs, 1, 0, "EXPR"); + AddExState(®, 1, 0, "EXPR"); } diff --git a/src/boards/mapper190.c b/src/mappers/mapper190.c similarity index 64% rename from src/boards/mapper190.c rename to src/mappers/mapper190.c index 449e6de90..d66e546ae 100644 --- a/src/boards/mapper190.c +++ b/src/mappers/mapper190.c @@ -1,6 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * - * Copyright (C) 2017 FCEUX Team + * Copyright notice for this file: + * Copyright (C) 2017 FCEUX Team + * Copyright (C) 2023-2024 negativeExponent * * 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,58 +23,51 @@ #include "mapinc.h" -static uint8 preg, creg[4]; -static uint8 *WRAM = NULL; +static uint8 prg, chr[4]; -static SFORMAT StateRegs[] = -{ - { &preg, 1, "PREG" }, - { creg, 4, "CREG" }, +static SFORMAT StateRegs[] = { + { &prg, 1, "PREG" }, + { chr, 4, "CREG" }, { 0 } }; static void Sync(void) { setprg8r(0x10, 0x6000, 0); - setprg16(0x8000, preg); + setprg16(0x8000, prg); setprg16(0xC000, 0); - setchr2(0x0000, creg[0]); - setchr2(0x0800, creg[1]); - setchr2(0x1000, creg[2]); - setchr2(0x1800, creg[3]); + setchr2(0x0000, chr[0]); + setchr2(0x0800, chr[1]); + setchr2(0x1000, chr[2]); + setchr2(0x1800, chr[3]); } -static DECLFW(M190Write89) { - preg = V & 7; - Sync(); -} - -static DECLFW(M190WriteCD) { - preg = 8 | (V & 7); - Sync(); +static DECLFW(M190Write) { + switch (A & 0xE000) { + case 0x8000: + case 0xC000: + prg = (A << 11) | (V & 0x07); + Sync(); + break; + case 0xA000: + chr[A & 0x03] = V; + Sync(); + break; + } } -static DECLFW(M190WriteAB) { - creg[A & 3] = V; +static void M190Power(void) { + chr[0] = chr[1] = chr[2] = chr[3] = 0; + prg = 0; + setmirror(MI_V); Sync(); -} -static void M190Power(void) { - creg[0] = creg[1] = creg[2] = creg[3] = 0; - preg = 0; - FCEU_CheatAddRAM(0x2000 >> 10, 0x6000, WRAM); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetWriteHandler(0x8000, 0x9FFF, M190Write89); - SetWriteHandler(0xA000, 0xBFFF, M190WriteAB); - SetWriteHandler(0xC000, 0xDFFF, M190WriteCD); - setmirror(MI_V); - Sync(); + SetWriteHandler(0x8000, 0xFFFF, M190Write); + FCEU_CheatAddRAM(0x2000 >> 10, 0x6000, WRAM); } static void M190Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; } static void StateRestore(int version) { @@ -82,9 +77,10 @@ static void StateRestore(int version) { void Mapper190_Init(CartInfo *info) { info->Power = M190Power; info->Close = M190Close; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + WRAM = (uint8 *)FCEU_gmalloc(0x2000); SetupCartPRGMapping(0x10, WRAM, 0x2000, 1); AddExState(WRAM, 0x2000, 0, "WRAM"); - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); } diff --git a/src/mappers/mapper191.c b/src/mappers/mapper191.c new file mode 100644 index 000000000..7cd35c166 --- /dev/null +++ b/src/mappers/mapper191.c @@ -0,0 +1,52 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 *CHRRAM = NULL; +static uint32 CHRRAMSIZE = 0; + +static void M191CW(uint32 A, uint8 V) { + if (V & 0x80) { + setchr1r(0x10, A, V & 0x01); + } else { + setchr1(A, V); + } +} + +static void M191Close(void) { + MMC3_Close(); + if (CHRRAM) { + FCEU_free(CHRRAM); + CHRRAM = NULL; + } +} + +void Mapper191_Init(CartInfo *info) { + MMC3_Init(info, 8, info->battery); + info->Close = M191Close; + MMC3_cwrap = M191CW; + + CHRRAMSIZE = 2048; + CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); +} \ No newline at end of file diff --git a/src/mappers/mapper192.c b/src/mappers/mapper192.c new file mode 100644 index 000000000..d6edd56d9 --- /dev/null +++ b/src/mappers/mapper192.c @@ -0,0 +1,53 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 *CHRRAM = NULL; +static uint32 CHRRAMSIZE = 0; + +static void M192CW(uint32 A, uint8 V) { + if ((V & ~0x03) == 0x08) { + setchr1r(0x10, A, V & 0x03); + } else { + setchr1(A, V); + } +} + +static void M192Close(void) { + MMC3_Close(); + if (CHRRAM) { + FCEU_free(CHRRAM); + CHRRAM = NULL; + } +} + +void Mapper192_Init(CartInfo *info) { + MMC3_Init(info, 8, info->battery); + info->Close = M192Close; + MMC3_cwrap = M192CW; + + CHRRAMSIZE = 4096; + CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); +} + diff --git a/src/boards/mapper193.c b/src/mappers/mapper193.c similarity index 77% rename from src/boards/mapper193.c rename to src/mappers/mapper193.c index c5c4e8e66..2f279731d 100644 --- a/src/boards/mapper193.c +++ b/src/mappers/mapper193.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2009 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -24,50 +25,44 @@ #include "mapinc.h" static uint8 reg[8]; -static uint8 mirror, cmd, bank; +static uint8 mirror; -static SFORMAT StateRegs[] = -{ - { &cmd, 1, "CMD" }, +static SFORMAT StateRegs[] = { { &mirror, 1, "MIRR" }, - { &bank, 1, "BANK" }, { reg, 8, "REGS" }, { 0 } }; static void Sync(void) { - setmirror(mirror ^ 1); setprg8(0x8000, reg[3]); - setprg8(0xA000, 0xD); - setprg8(0xC000, 0xE); - setprg8(0xE000, 0xF); + setprg8(0xA000, ~2); + setprg8(0xC000, ~1); + setprg8(0xE000, ~0); setchr4(0x0000, reg[0] >> 2); setchr2(0x1000, reg[1] >> 1); setchr2(0x1800, reg[2] >> 1); + setmirror((mirror & 0x01) ^ 0x01); } static DECLFW(M193Write) { - reg[A & 3] = V; + reg[A & 7] = V; Sync(); } static void M193Power(void) { - bank = 0; + memset(reg, 0, sizeof(reg)); Sync(); - SetWriteHandler(0x6000, 0x6003, M193Write); + SetWriteHandler(0x6000, 0x7FFF, M193Write); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0xFFFF, CartBW); } -static void M193Reset(void) { } - static void StateRestore(int version) { Sync(); } void Mapper193_Init(CartInfo *info) { - info->Reset = M193Reset; info->Power = M193Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper194.c b/src/mappers/mapper194.c new file mode 100644 index 000000000..d3d73adc0 --- /dev/null +++ b/src/mappers/mapper194.c @@ -0,0 +1,52 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 *CHRRAM = NULL; +static uint32 CHRRAMSIZE = 0; + +static void M194CW(uint32 A, uint8 V) { + if ((V & ~0x01) == 0x00) { /* Dai-2-Ji - Super Robot Taisen (As).nes */ + setchr1r(0x10, A, V & 0x01); + } else { + setchr1(A, V); + } +} + +static void M194Close(void) { + MMC3_Close(); + if (CHRRAM) { + FCEU_free(CHRRAM); + CHRRAM = NULL; + } +} + +void Mapper194_Init(CartInfo *info) { + MMC3_Init(info, 8, info->battery); + info->Close = M194Close; + MMC3_cwrap = M194CW; + + CHRRAMSIZE = 2048; + CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); +} \ No newline at end of file diff --git a/src/boards/mapper195.c b/src/mappers/mapper195.c similarity index 92% rename from src/boards/mapper195.c rename to src/mappers/mapper195.c index f569bf4bf..07952256c 100644 --- a/src/boards/mapper195.c +++ b/src/mappers/mapper195.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -56,7 +56,7 @@ static DECLFW(M195PPUWrite) { reg = addr >> 11; } - chrBank = mmc3.regs[reg]; + chrBank = mmc3.reg[reg]; if (chrBank & 0x80) { if (chrBank & 0x10) { /* CHR-RAM disable */ @@ -64,10 +64,11 @@ static DECLFW(M195PPUWrite) { chrRamBankSelect = 0xFF; } else { uint8 index = ((chrBank >> 4) & 0x04) | ((chrBank >> 2) & 0x02) | ((chrBank >> 1) & 0x01); + chrRamMask = (chrBank & 0x40) ? 0xFE : 0xFC; chrRamBankSelect = chrRamLut[index]; } - FixMMC3CHR(mmc3.cmd); + MMC3_FixCHR(); } } writePPU(A, V); @@ -76,7 +77,7 @@ static DECLFW(M195PPUWrite) { static void M195Power(void) { chrRamMask = 0xFC; chrRamBankSelect = 0x00; - GenMMC3Power(); + MMC3_Power(); setprg4r(0x10, 0x5000, 2); SetWriteHandler(0x5000, 0x5FFF, CartBW); SetReadHandler(0x5000, 0x5FFF, CartBR); @@ -85,7 +86,8 @@ static void M195Power(void) { SetWriteHandler(0x2007, 0x2007, M195PPUWrite); } -void M195Close(void) { +static void M195Close(void) { + MMC3_Close(); if (CHRRAM) { FCEU_gfree(CHRRAM); } @@ -93,10 +95,10 @@ void M195Close(void) { } void Mapper195_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 16, info->battery); + MMC3_Init(info, 16, info->battery); info->Power = M195Power; info->Close = M195Close; - mmc3.cwrap = M195CW; + MMC3_cwrap = M195CW; CHRRAMSIZE = 4096; CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); diff --git a/src/mappers/mapper196.c b/src/mappers/mapper196.c new file mode 100644 index 000000000..0e509e72b --- /dev/null +++ b/src/mappers/mapper196.c @@ -0,0 +1,68 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +/* MMC3 board with optional command address line connection, allows to + * make three-four different wirings to IRQ address lines and separately to + * CMD address line, Mali Boss additionally check if wiring are correct for + * game + */ + +static uint8 reg[2]; + +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, + { 0 } +}; + +static void M196PW(uint32 A, uint8 V) { + if (reg[0]) { + setprg32(0x8000, reg[1]); + } else { + setprg8(A, V); + } +} + +static DECLFW(M196Write) { + A = (A & 0xF000) | (!!(A & 0x0E) ^ (A & 0x01)); + MMC3_Write(A, V); +} + +static DECLFW(M196WriteNROM) { + reg[0] = 1; + reg[1] = V | (V >> 4); + MMC3_FixPRG(); +} + +static void M196Power(void) { + reg[0] = reg[1] = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M196WriteNROM); + SetWriteHandler(0x8000, 0xFFFF, M196Write); +} + +void Mapper196_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_pwrap = M196PW; + info->Power = M196Power; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper197.c b/src/mappers/mapper197.c new file mode 100644 index 000000000..66b7d1e03 --- /dev/null +++ b/src/mappers/mapper197.c @@ -0,0 +1,121 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 reg; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; + +static void M197PW(uint32 A, uint8 V) { + uint8 mask = (reg & 0x08) ? 0x0F : 0x1F; + + switch (iNESCart.submapper) { + case 3: + setprg8(A, (reg << 4) | (V & mask)); + break; + default: + setprg8(A, V & 0x3F); + break; + } +} + +static void M197CHR(void) { + switch (iNESCart.submapper) { + case 1: + setchr2(0x0000, mmc3.reg[1] & ~0x01); + setchr2(0x0800, mmc3.reg[1] | 0x01); + setchr2(0x1000, mmc3.reg[4]); + setchr2(0x1800, mmc3.reg[5]); + break; + case 2: + setchr2(0x0000, mmc3.reg[0] & ~0x01); + setchr2(0x0800, mmc3.reg[1] | 0x01); + setchr2(0x1000, mmc3.reg[2]); + setchr2(0x1800, mmc3.reg[5]); + break; + case 0: + case 3: + default: + setchr2(0x0000, mmc3.reg[0] & ~0x01); + setchr2(0x0800, mmc3.reg[0] | 0x01); + setchr2(0x1000, mmc3.reg[2]); + setchr2(0x1800, mmc3.reg[3]); + break; + } +} + +static DECLFW(M197WriteReg) { + if (MMC3_WramIsWritable()) { + reg = V; + MMC3_FixPRG(); + } +} + +static DECLFW(M197Write) { + switch (A & 0xE001) { + case 0x8001: + switch (mmc3.cmd & 0x07) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + mmc3.reg[mmc3.cmd & 0x07] = V; + MMC3_FixCHR(); + break; + default: + MMC3_CMDWrite(A, V); + break; + } + break; + default: + MMC3_CMDWrite(A, V); + break; + } +} + +static void M197Reset(void) { + reg = 0; + MMC3_FixCHR(); + MMC3_FixPRG(); + MMC3_FixMIR(); +} + +static void M197Power(void) { + reg = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M197WriteReg); + SetWriteHandler(0x8000, 0x9FFF, M197Write); +} + +void Mapper197_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + info->Power = M197Power; + info->Reset = M197Reset; + MMC3_FixCHR = M197CHR; + MMC3_pwrap = M197PW; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper198.c b/src/mappers/mapper198.c new file mode 100644 index 000000000..73f5d6262 --- /dev/null +++ b/src/mappers/mapper198.c @@ -0,0 +1,42 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static void M198PW(uint32 A, uint8 V) { + if (V >= 0x40) { + V = (0x40 | (V & 0x0F)); + } + setprg8(A, V); +} + +static void M198Power(void) { + MMC3_Power(); + setprg4r(0x10, 0x5000, 2); + SetWriteHandler(0x5000, 0x5fff, CartBW); + SetReadHandler(0x5000, 0x5fff, CartBR); +} + +void Mapper198_Init(CartInfo *info) { + MMC3_Init(info, 16, info->battery); + MMC3_pwrap = M198PW; + info->Power = M198Power; +} diff --git a/src/boards/mapper199.c b/src/mappers/mapper199.c similarity index 88% rename from src/boards/mapper199.c rename to src/mappers/mapper199.c index 36f8b46db..c03a20190 100644 --- a/src/boards/mapper199.c +++ b/src/mappers/mapper199.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -26,15 +26,15 @@ static void M199CW(uint32 A, uint8 V) { } static void M199Power(void) { - GenMMC3Power(); + MMC3_Power(); setprg4r(0x10, 0x5000, 2); SetReadHandler(0x5000, 0x5FFF, CartBR); SetWriteHandler(0x5000, 0x5FFF, CartBW); } void Mapper199_Init(CartInfo *info) { - GenMMC3_Init(info, 1024, 8, 16, info->battery); - mmc3.cwrap = M199CW; + MMC3_Init(info, 16, info->battery); + MMC3_cwrap = M199CW; info->Power = M199Power; - info->Reset = MMC3RegReset; + info->Reset = MMC3_Reset; } diff --git a/src/mappers/mapper200.c b/src/mappers/mapper200.c new file mode 100644 index 000000000..8a015a472 --- /dev/null +++ b/src/mappers/mapper200.c @@ -0,0 +1,38 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg16(0x8000, latch.addr & 0x07); + setprg16(0xC000, latch.addr & 0x07); + setchr8(latch.addr & 0x07); + if (iNESCart.submapper == 1) { + setmirror(((latch.addr >> 2) & 0x01) ^ 0x01); + } else { + setmirror(((latch.addr >> 3) & 0x01) ^ 0x01); + } +} + +void Mapper200_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); +} diff --git a/src/mappers/mapper201.c b/src/mappers/mapper201.c new file mode 100644 index 000000000..7bc6c8b11 --- /dev/null +++ b/src/mappers/mapper201.c @@ -0,0 +1,33 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg32(0x8000, latch.addr); + setchr8(latch.addr); +} + +void Mapper201_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Reset = Latch_RegReset; +} diff --git a/src/boards/mapper438.c b/src/mappers/mapper202.c similarity index 74% rename from src/boards/mapper438.c rename to src/mappers/mapper202.c index e1825c54c..1fbf5d941 100644 --- a/src/boards/mapper438.c +++ b/src/mappers/mapper202.c @@ -1,9 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2012 CaH4e3 - * Copyright (C) 2002 Xodnizel - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 +16,23 @@ * 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 + * */ -/* K-3071 */ - #include "mapinc.h" #include "latch.h" static void Sync(void) { - if (latch.addr & 1) + if ((latch.addr & 0x09) == 0x09) { setprg32(0x8000, latch.addr >> 2); - else { + } else { setprg16(0x8000, latch.addr >> 1); setprg16(0xC000, latch.addr >> 1); } - setchr8(latch.data >> 1); - setmirror((latch.data & 1) ^ 1); + setchr8(latch.addr >> 1); + setmirror((latch.addr & 0x01) ^ 0x01); } -void Mapper438_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); - info->Reset = LatchHardReset; +void Mapper202_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); } diff --git a/src/mappers/mapper203.c b/src/mappers/mapper203.c new file mode 100644 index 000000000..7a0aedac8 --- /dev/null +++ b/src/mappers/mapper203.c @@ -0,0 +1,33 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg16(0x8000, latch.data >> 2); + setprg16(0xC000, latch.data >> 2); + setchr8(latch.data & 0x03); +} + +void Mapper203_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); +} diff --git a/src/mappers/mapper204.c b/src/mappers/mapper204.c new file mode 100644 index 000000000..74d95d53d --- /dev/null +++ b/src/mappers/mapper204.c @@ -0,0 +1,39 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + if (latch.addr & 0x20) { + setprg32(0x8000, latch.addr >> 1); + setchr8(latch.addr & 0x0E); + } else { + setprg16(0x8000, latch.addr); + setprg16(0xC000, latch.addr); + setchr8(latch.addr & 0x0F); + } + setmirror(((latch.addr >> 4) & 0x01) ^ 0x01); +} + +void Mapper204_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); +} diff --git a/src/mappers/mapper205.c b/src/mappers/mapper205.c new file mode 100644 index 000000000..838565a71 --- /dev/null +++ b/src/mappers/mapper205.c @@ -0,0 +1,78 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* iNES Mapper 205 + * UNIF boardname BMC-JC-016-2 + */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 reg; +static uint8 dipsw; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { &dipsw, 1, "DPSW" }, + { 0 } +}; + +static void M205PW(uint32 A, uint8 V) { + uint8 mask = (reg & 0x02) ? 0x0F : 0x1F; + + setprg8(A, (reg << 4) | (V & mask)); +} + +static void M205CW(uint32 A, uint8 V) { + uint8 mask = (reg & 0x02) ? 0x7F : 0xFF; + + setchr1(A, (reg << 7) | (V & mask)); +} + +static DECLFW(M205Write) { + CartBW(A, V); + reg = V & 0x03; + if ((V & 0x01) && dipsw) { + reg |= 0x02; + } + MMC3_FixPRG(); + MMC3_FixCHR(); +} + +static void M205Reset(void) { + reg = 0; + dipsw = (dipsw + 1) & 0x01; /* solder pad */ + MMC3_Reset(); +} + +static void M205Power(void) { + reg = dipsw = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M205Write); +} + +void Mapper205_Init(CartInfo *info) { + MMC3_Init(info, 8, 0); + MMC3_pwrap = M205PW; + MMC3_cwrap = M205CW; + info->Power = M205Power; + info->Reset = M205Reset; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper206.c b/src/mappers/mapper206.c new file mode 100644 index 000000000..9b9180506 --- /dev/null +++ b/src/mappers/mapper206.c @@ -0,0 +1,37 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "n118.h" + +static void M206PW(uint32 A, uint8 V) { + if (iNESCart.submapper == 1) { + /* 3407, 3417 and 3451 PCBs */ + setprg32(0x8000, 0); + } else { + setprg8(A, V & 0x0F); + } +} + +void Mapper206_Init(CartInfo *info) { + N118_Init(info, 0, 0); + N118_pwrap = M206PW; +} diff --git a/src/boards/mapper208.c b/src/mappers/mapper208.c similarity index 63% rename from src/boards/mapper208.c rename to src/mappers/mapper208.c index 58db9cc64..0038ace56 100644 --- a/src/boards/mapper208.c +++ b/src/mappers/mapper208.c @@ -1,8 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 - * Copyright (C) 2022 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -20,14 +20,16 @@ */ /* 2022-2-14 - * - add support for submapper 1, Mortal Kombat (JJ-01) (Ch) [!] + * - add support for iNESCart.submapper 1, Mortal Kombat (JJ-01) (Ch) [!] * - add mirroring */ #include "mapinc.h" #include "mmc3.h" -static uint8 submapper; +static uint8 reg; +static uint8 protIndex; +static uint8 protReg[4]; static const uint8 lut[256] = { 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x49, 0x19, 0x09, 0x59, 0x49, 0x19, 0x09, @@ -48,51 +50,83 @@ static const uint8 lut[256] = { 0x09, 0x19, 0x49, 0x59, 0x09, 0x19, 0x49, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -static void M208PW(uint32 A, uint8 V) { - if (submapper == 1) - setprg32(0x8000, mmc3.regs[6] >> 2); - else - setprg32(0x8000, (mmc3.expregs[5] & 0x1) | ((mmc3.expregs[5] >> 3) & 0x2)); +static void M208PRG(void) { + setprg32(0x8000, (reg & 0x01) | ((reg >> 3) & 0x02)); } -static void M208MW(uint8 V) { - if (submapper == 1) - setmirror((V & 1) ^ 1); - else - setmirror(((mmc3.expregs[5] >> 5) & 1) ^ 1); +static void M208MIR(void) { + setmirror(((reg >> 5) & 0x01) ^ 0x01); +} + +static void M208PRG_Sub1(void) { + setprg32(0x8000, mmc3.reg[6] >> 2); +} + +static void M208MIR_Sub1(void) { + setmirror((mmc3.mirr & 0x01) ^ 0x01); } static DECLFW(M208Write) { - mmc3.expregs[5] = V; - FixMMC3PRG(mmc3.cmd); + reg = V; + MMC3_FixPRG(); + MMC3_FixMIR(); } static DECLFW(M208ProtWrite) { - if (A <= 0x57FF) - mmc3.expregs[4] = V; - else - mmc3.expregs[(A & 0x03)] = V ^ lut[mmc3.expregs[4]]; + if (A & 0x800) { + protReg[(A & 0x03)] = V ^ lut[protIndex]; + } else { + protIndex = V; + } } static DECLFR(M208ProtRead) { - return (mmc3.expregs[(A & 0x3)]); + return (protReg[(A & 0x3)]); +} + +static DECLFW(M208WriteCMD) { + switch (A & 0xE001) { + case 0x8001: + switch (mmc3.cmd & 0x07) { + case 6: + case 7: + mmc3.reg[mmc3.cmd & 0x07] = V; + MMC3_FixPRG(); + break; + default: + MMC3_CMDWrite(A, V); + break; + } + break; + default: + MMC3_CMDWrite(A, V); + break; + } } static void M208Power(void) { - mmc3.expregs[5] = 0x11; - GenMMC3Power(); - SetWriteHandler(0x4800, 0x4fff, M208Write); - SetWriteHandler(0x6800, 0x6fff, M208Write); - SetWriteHandler(0x5000, 0x5fff, M208ProtWrite); - SetReadHandler(0x5800, 0x5fff, M208ProtRead); - SetReadHandler(0x8000, 0xffff, CartBR); + reg = 0x11; + MMC3_Power(); + SetWriteHandler(0x4800, 0x4FFF, M208Write); + SetWriteHandler(0x6800, 0x6FFF, M208Write); + SetWriteHandler(0x5000, 0x5FFF, M208ProtWrite); + SetReadHandler(0x5800, 0x5FFF, M208ProtRead); + SetReadHandler(0x8000, 0xFFFF, CartBR); + + if (iNESCart.submapper == 1) { + SetWriteHandler(0x8000, 0x9FFF, M208WriteCMD); + MMC3_FixPRG = M208PRG_Sub1; + MMC3_FixMIR = M208MIR_Sub1; + MMC3_Reset(); + } } void Mapper208_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 256, 0, 0); - mmc3.pwrap = M208PW; - mmc3.mwrap = M208MW; + MMC3_Init(info, 0, 0); + MMC3_FixPRG = M208PRG; + MMC3_FixMIR = M208MIR; info->Power = M208Power; - AddExState(mmc3.expregs, 6, 0, "EXPR"); - submapper = info->submapper; + AddExState(®, 1, 0, "EXPR"); + AddExState(&protIndex, 1, 0, "PRID"); + AddExState(&protReg, 4, 0, "PRRG"); } diff --git a/src/mappers/mapper209.c b/src/mappers/mapper209.c new file mode 100644 index 000000000..f6faa3634 --- /dev/null +++ b/src/mappers/mapper209.c @@ -0,0 +1,62 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "jyasic.h" + +static uint32 GetPRGBank(uint32 V) { + return (((jyasic.mode[3] << 5) & ~0x3F) | (V & 0x3F)); +} + +static uint32 GetCHRBank(uint32 V) { + if (jyasic.mode[3] & 0x20) { + return (((jyasic.mode[3] << 6) & 0x600) | (V & 0x1FF)); + } else { + return (((jyasic.mode[3] << 6) & 0x600) | ((jyasic.mode[3] << 8) & 0x100) | (V & 0x0FF)); + } +} + +void Mapper035_Init(CartInfo *info) { + /* Basically mapper 90/209/211 with WRAM */ + JYASIC_Init(info, TRUE); + JYASIC_GetPRGBank = GetPRGBank; + JYASIC_GetCHRBank = GetCHRBank; +} + +void Mapper090_Init(CartInfo *info) { + /* Single cart, extended mirroring and ROM nametables disabled */ + JYASIC_Init(info, FALSE); + JYASIC_GetPRGBank = GetPRGBank; + JYASIC_GetCHRBank = GetCHRBank; +} + +void Mapper209_Init(CartInfo *info) { + /* Single cart, extended mirroring and ROM nametables enabled */ + JYASIC_Init(info, TRUE); + JYASIC_GetPRGBank = GetPRGBank; + JYASIC_GetCHRBank = GetCHRBank; +} + +void Mapper211_Init(CartInfo *info) { + /* Duplicate of mapper 209 */ + JYASIC_Init(info, TRUE); + JYASIC_GetPRGBank = GetPRGBank; + JYASIC_GetCHRBank = GetCHRBank; +} diff --git a/src/mappers/mapper210.c b/src/mappers/mapper210.c new file mode 100644 index 000000000..b84579164 --- /dev/null +++ b/src/mappers/mapper210.c @@ -0,0 +1,146 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * Copyright (C) 2023-2024 negativeExponent + * + * 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 210 - simplified version of Mapper 19 + * Namco 175 - submapper 1 - optional wram, hard-wired mirroring + * Namco 340 - submapper 2 - selectable H/V/0 mirroring + */ + +#include "mapinc.h" + +static uint8 prg[4]; +static uint8 chr[8]; +static uint8 wram_enable; + +static SFORMAT StateRegs[] = { + { prg, 3, "PRG" }, + { chr, 8, "CHR" }, + { &wram_enable, 1, "WREN" }, + { 0 } +}; + +static void Sync(void) { + setprg8(0x8000, prg[0] & 0x3F); + setprg8(0xA000, prg[1] & 0x3F); + setprg8(0xC000, prg[2] & 0x3F); + setprg8(0xE000, prg[3] & 0x3F); + + setchr1(0x0000, chr[0]); + setchr1(0x0400, chr[1]); + setchr1(0x0800, chr[2]); + setchr1(0x0C00, chr[3]); + setchr1(0x1000, chr[4]); + setchr1(0x1400, chr[5]); + setchr1(0x1800, chr[6]); + setchr1(0x1C00, chr[7]); + + if (iNESCart.submapper != 1) { + switch((prg[0] >> 6) & 0x03) { + case 0: setmirror(MI_0); break; + case 1: setmirror(MI_V); break; + case 2: setmirror(MI_H); break; + case 3: setmirror(MI_0); break; + } + } +} + +static DECLFR(AWRAM) { + A = ((A - 0x6000) & (WRAMSIZE -1)); + return WRAM[A]; +} + +static DECLFW(BWRAM) { + if (wram_enable) { + A = ((A - 0x6000) & (WRAMSIZE -1)); + WRAM[A] = V; + } +} + +static DECLFW(M210Write) { + switch (A & 0xF800) { + case 0x8000: + case 0x8800: + case 0x9000: + case 0x9800: + case 0xA000: + case 0xA800: + case 0xB000: + case 0xB800: + chr[(A - 0x8000) >> 11] = V; + Sync(); + break; + case 0xC000: + wram_enable = V & 0x01; + break; + case 0xE000: + case 0xE800: + case 0xF000: + prg[(A - 0xE000) >> 11] = V; + Sync(); + break; + } +} + +static void M210Power(void) { + int i; + for (i = 0; i < 4; i++) prg[i] = 0xFC | i; + for (i = 0; i < 4; i++) chr[0 | i] = 0 | i; + for (i = 0; i < 4; i++) chr[4 | i] = 4 | i; + wram_enable = 0; + Sync(); + + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xffff, M210Write); + + if (WRAM) { + SetReadHandler(0x6000, 0x7FFF, AWRAM); + SetWriteHandler(0x6000, 0x7FFF, BWRAM); + FCEU_CheatAddRAM(8, 0x6000, WRAM); + } + + if (WRAM && !iNESCart.battery) { + FCEU_MemoryRand(WRAM, sizeof(WRAM)); + } +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper210_Init(CartInfo *info) { + GameStateRestore = StateRestore; + info->Power = M210Power; + AddExState(StateRegs, ~0, 0, NULL); + + WRAMSIZE = 8192; + if (info->iNES2) { + WRAMSIZE = info->PRGRamSize + info->PRGRamSaveSize; + } + + if (WRAMSIZE) { + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + } +} diff --git a/src/mappers/mapper212.c b/src/mappers/mapper212.c new file mode 100644 index 000000000..4af813474 --- /dev/null +++ b/src/mappers/mapper212.c @@ -0,0 +1,48 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + if (latch.addr & 0x4000) { + setprg32(0x8000, latch.addr >> 1); + } else { + setprg16(0x8000, latch.addr); + setprg16(0xC000, latch.addr); + } + setchr8(latch.addr); + setmirror(((latch.addr >> 3) & 0x01) ^ 0x01); +} + +static DECLFR(M212Read) { + return (cpu.openbus & ~0x80) | ((A & 0x10) ? 0 : 0x80); +} + +static void M212Power(void) { + Latch_Power(); + SetReadHandler(0x6000, 0x7FFF, M212Read); +} + +void Mapper212_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Power = M212Power; +} diff --git a/src/mappers/mapper214.c b/src/mappers/mapper214.c new file mode 100644 index 000000000..818c3d39c --- /dev/null +++ b/src/mappers/mapper214.c @@ -0,0 +1,33 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg16(0x8000, latch.addr >> 2); + setprg16(0xC000, latch.addr >> 2); + setchr8(latch.addr >> 2); +} + +void Mapper214_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); +} diff --git a/src/mappers/mapper215.c b/src/mappers/mapper215.c new file mode 100644 index 000000000..e5eb98eec --- /dev/null +++ b/src/mappers/mapper215.c @@ -0,0 +1,184 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2011 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + * Submapper 0, UNIF board name UNL-8237: + * Earthworm Jim 2 + * Mortal Kombat 3 (SuperGame, not Extra 60, not to be confused by similarly-named games from other developers) + * Mortal Kombat 3 Extra 60 (both existing ROM images are just extracts of the 2-in-1 multicart containing this game) + * Pocahontas Part 2 + * 2-in-1: Aladdin, EarthWorm Jim 2 (Super 808) + * 2-in-1: The Lion King, Bomber Boy (GD-103) + * 2-in-1: Super Golden Card: EarthWorm Jim 2, Boogerman (king002) + * 2-in-1: Mortal Kombat 3 Extra 60, The Super Shinobi (king005) + * 3-in-1: Boogerman, Adventure Island 3, Double Dragon 3 (Super 308) + * 5-in-1: Golden Card: Aladdin, EarthWorm Jim 2, Garo Densetsu Special, Silkworm, Contra Force (SPC005) + * 6-in-1: Golden Card: EarthWorm Jim 2, Mortal Kombat 3, Double Dragon 3, Contra 3, The Jungle Book, Turtles Tournament Fighters (SPC009) + * + * Submapper 1, UNIF board name UNL-8237A: + * 9-in-1 High Standard Card: The Lion King, EarthWorm Jim 2, Aladdin, Boogerman, Somari, Turtles Tournament Fighters, Mortal Kombat 3, Captain Tsubasa 2, Taito Basketball (king001) + */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 reg[4]; + +static const uint8 regperm[8][8] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7 }, + { 0, 2, 6, 1, 7, 3, 4, 5 }, + { 0, 5, 4, 1, 7, 2, 6, 3 }, /* unused */ + { 0, 6, 3, 7, 5, 2, 4, 1 }, + { 0, 2, 5, 3, 6, 1, 7, 4 }, + { 0, 1, 2, 3, 4, 5, 6, 7 }, /* empty */ + { 0, 1, 2, 3, 4, 5, 6, 7 }, /* empty */ + { 0, 1, 2, 3, 4, 5, 6, 7 }, /* empty */ +}; + +static const uint16 adrperm[8][8] = { + { 0x8000, 0x8001, 0xA000, 0xA001, 0xC000, 0xC001, 0xE000, 0xE001 }, + { 0xA001, 0xA000, 0x8000, 0xC000, 0x8001, 0xC001, 0xE000, 0xE001 }, + { 0x8000, 0x8001, 0xA000, 0xA001, 0xC000, 0xC001, 0xE000, 0xE001 }, /* unused */ + { 0xC001, 0x8000, 0x8001, 0xA000, 0xA001, 0xE001, 0xE000, 0xC000 }, + { 0xA001, 0x8001, 0x8000, 0xC000, 0xA000, 0xC001, 0xE000, 0xE001 }, + { 0x8000, 0x8001, 0xA000, 0xA001, 0xC000, 0xC001, 0xE000, 0xE001 }, /* empty */ + { 0x8000, 0x8001, 0xA000, 0xA001, 0xC000, 0xC001, 0xE000, 0xE001 }, /* empty */ + { 0x8000, 0x8001, 0xA000, 0xA001, 0xC000, 0xC001, 0xE000, 0xE001 }, /* empty */ +}; + +static const uint8 protarray[8][8] = { + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 0 Super Hang-On */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00 }, /* 1 Monkey King */ + { 0x00, 0x00, 0x00, 0x00, 0x03, 0x04, 0x00, 0x00 }, /* 2 Super Hang-On/Monkey King */ + { 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x05, 0x00 }, /* 3 Super Hang-On/Monkey King */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 4 */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 5 */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 6 */ + { 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x0F, 0x00 } /* 7 (default) Blood of Jurassic */ +}; + +static void M215CW(uint32 A, uint8 V) { + uint16 mask = (reg[0] & 0x40) ? 0x7F : 0xFF; + uint16 base; + + if (iNESCart.submapper == 1) { + base = (reg[1] << 7) & 0x700; + } else { + base = (reg[1] << 6) & 0x300; + } + + base = (base & ~mask) | (((reg[1] << 2) & 0x80) & ~mask); + setchr1(A, base | (V & mask)); +} + +static void M215PW(uint32 A, uint8 V) { + uint16 mask = (reg[0] & 0x40) ? 0x0F : 0x1F; + uint16 base; + + if (iNESCart.submapper == 1) { + base = ((reg[1] << 5) & 0x60) | ((reg[1] << 4) & 0x80); + } else { + base = (reg[1] << 5) & 0x60; + } + + if (reg[0] & 0x80) { /* NROM */ + uint16 bank = (((reg[1] & 0x10) & ~mask) >> 1) | ((base & ~mask) >> 1) | (reg[0] & (mask >> 1)); + + if (reg[0] & 0x20) { /* NROM-256 */ + setprg32(0x8000, bank >> 1); + } else { /* NROM-128 */ + setprg16(0x8000, bank); + setprg16(0xC000, bank); + } + } else { + setprg8(A, ((reg[1] & 0x10) & ~mask) | (base & ~mask) | (V & mask)); + } +} + +static DECLFR(M215ProtRead) { + return (cpu.openbus & ~0x0F) | (protarray[reg[2]][A & 0x07] & 0x0F); +} + +static DECLFW(M215Write) { + A = adrperm[reg[3]][((A >> 12) & 0x06) | (A & 0x01)]; + switch (A & 0xE001) { + case 0x8000: + MMC3_Write(A, (V & 0xC0) | regperm[reg[3]][V & 0x07]); + break; + default: + MMC3_Write(A, V); + break; + } +} + +static DECLFW(M215Write5) { + switch (A & 0x07) { + case 0: + reg[0] = V; + MMC3_FixPRG(); + MMC3_FixCHR(); + break; + case 1: + reg[1] = V; + MMC3_FixPRG(); + MMC3_FixCHR(); + break; + case 2: + reg[2] = V & 0x07; + break; + case 7: + reg[3] = V & 0x07; + break; + } +} + +static void M215Power(void) { + reg[0] = 0x00; + reg[1] = 0x0F; + reg[3] = 0x04; + reg[2] = 0x07; + MMC3_Power(); + SetReadHandler(0x5000, 0x5FFF, M215ProtRead); + SetWriteHandler(0x5000, 0x5FFF, M215Write5); + SetWriteHandler(0x8000, 0xFFFF, M215Write); +} + +static void M215Reset(void) { + reg[0] = 0x00; + reg[1] = 0x0F; + reg[3] = 0x04; + reg[2] = 0x07; + MMC3_Reset(); +} + +void Mapper215_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_cwrap = M215CW; + MMC3_pwrap = M215PW; + + info->Power = M215Power; + info->Reset = M215Reset; + + AddExState(reg, 4, 0, "EXPR"); + + if ((!info->iNES2) && ((ROM.prg.size * 16) >= 2048)) { /* UNL-8237A */ + info->submapper = 1; + } +} diff --git a/src/mappers/mapper216.c b/src/mappers/mapper216.c new file mode 100644 index 000000000..7e6be09e5 --- /dev/null +++ b/src/mappers/mapper216.c @@ -0,0 +1,32 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg32(0x8000, latch.addr & 0x01); + setchr8(latch.addr >> 1); +} + +void Mapper216_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); +} diff --git a/src/mappers/mapper217.c b/src/mappers/mapper217.c new file mode 100644 index 000000000..f63858520 --- /dev/null +++ b/src/mappers/mapper217.c @@ -0,0 +1,33 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg32(0x8000, latch.addr >> 2); + setchr8(latch.addr); +} + +void Mapper217_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Reset = Latch_RegReset; +} diff --git a/src/boards/mapper218.c b/src/mappers/mapper218.c similarity index 79% rename from src/boards/mapper218.c rename to src/mappers/mapper218.c index be884386c..c6370f8fd 100644 --- a/src/boards/mapper218.c +++ b/src/mappers/mapper218.c @@ -36,8 +36,6 @@ static void M218Power(void) { } void Mapper218_Init(CartInfo *info) { - int i; - info->Power = M218Power; /* similar to mapper 30, this mapper interprets the two bits in headers mirroring in idiosyncratic ways */ @@ -45,10 +43,13 @@ void Mapper218_Init(CartInfo *info) { /* cryptic logic to effect the CHR RAM mappings by mapping 1k blocks to NTARAM according to how the pins are wired this could be done by bit logic, but this is self-documenting */ - - for (i = 0; i < 8; i++) { - VPageR[i] = &NTARAM[mapping[info->mirror2bits][i]]; - } - + VPageR[0] = &NTARAM[mapping[info->mirror2bits][0]]; + VPageR[1] = &NTARAM[mapping[info->mirror2bits][1]]; + VPageR[2] = &NTARAM[mapping[info->mirror2bits][2]]; + VPageR[3] = &NTARAM[mapping[info->mirror2bits][3]]; + VPageR[4] = &NTARAM[mapping[info->mirror2bits][4]]; + VPageR[5] = &NTARAM[mapping[info->mirror2bits][5]]; + VPageR[6] = &NTARAM[mapping[info->mirror2bits][6]]; + VPageR[7] = &NTARAM[mapping[info->mirror2bits][7]]; PPUCHRRAM = 0xFF; } diff --git a/src/mappers/mapper219.c b/src/mappers/mapper219.c new file mode 100644 index 000000000..a6ff023d1 --- /dev/null +++ b/src/mappers/mapper219.c @@ -0,0 +1,113 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2007 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 reg; +static uint8 extMode; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { &extMode, 1, "MODE" }, + { 0 } +}; + +static void M219PW(uint32 A, uint8 V) { + setprg8(A, (reg << 4) | (V & 0x0F)); +} + +static void M219CW(uint32 A, uint8 V) { + setchr1(A, (reg << 7) | (V & 0x7F)); +} + +static DECLFW(M219WriteOuter) { + switch (A & 0x01) { + case 0: + reg = (reg & ~0x01) | ((V >> 3) & 0x01); + break; + case 1: + reg = (reg & ~0x02) | ((V >> 4) & 0x02); + break; + } + MMC3_FixPRG(); + MMC3_FixCHR(); +} + +static DECLFW(M219WriteASIC) { + uint8 oldcmd = mmc3.cmd; + + if (!(A & 0x01)) { /* Register index */ + mmc3.cmd = V; + if ((oldcmd & 0x40) != ((V & 0x40))) { + MMC3_FixPRG(); + } + if ((oldcmd & 0x80) != ((V & 0x80))) { + MMC3_FixPRG(); + } + if (A & 0x02) { + extMode = (V & 0x20) != 0; + } + } else { + if (!extMode) { /* Scrambled mode inactive */ + MMC3_CMDWrite(A, V); + } else { /* Scrambled mode active */ + if ((mmc3.cmd >= 0x08) && (mmc3.cmd <= 0x1F)) { /* Scrambled CHR register */ + uint8 index = (mmc3.cmd - 8) >> 2; + if (mmc3.cmd & 0x01) { /* LSB nibble */ + mmc3.reg[index] &= ~0x0F; + mmc3.reg[index] |= ((V >> 1) & 0x0F); + } else { /* MSB nibble */ + mmc3.reg[index] &= ~0xF0; + mmc3.reg[index] |= ((V << 4) & 0xF0); + } + MMC3_FixCHR(); + } else if ((mmc3.cmd >= 0x25) && (mmc3.cmd <= 0x26)) { /* Scrambled PRG register */ + V = ((V << 1) & 0x08) | ((V >> 1) & 0x04) | ((V >> 3) & 0x02) | ((V >> 5) & 0x01); + mmc3.reg[6 | (mmc3.cmd & 0x01)] = V; + MMC3_FixPRG(); + } + } + } +} + +static void M219Power(void) { + extMode = FALSE; + reg = 3; + MMC3_Power(); + SetWriteHandler(0x5000, 0x5FFF, M219WriteOuter); + SetWriteHandler(0x8000, 0x9FFF, M219WriteASIC); +} + +static void M219Reset(void) { + extMode = FALSE; + reg = ~0; + MMC3_Reset(); +} + +void Mapper219_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_pwrap = M219PW; + MMC3_cwrap = M219CW; + info->Power = M219Power; + info->Reset = M219Reset; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper221.c b/src/mappers/mapper221.c new file mode 100644 index 000000000..9094a93a3 --- /dev/null +++ b/src/mappers/mapper221.c @@ -0,0 +1,75 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2006 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 reg[0] 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 221 - UNL-N625092 + * 700in1 and 400in1 carts + * 1000-in-1 + */ + +#include "mapinc.h" + +static uint16 reg[2]; + +static SFORMAT StateRegs[] = { + { reg, 4, "REGS" }, + { 0 } +}; + +static void Sync(void) { + uint16 prg = ((reg[0] >> 3) & 0x40) | ((reg[0] >> 2) & 0x38) | (reg[1] & 0x07); + + if (!(reg[0] & 0x02)) { + setprg16(0x8000, prg); + setprg16(0xC000, prg); + } else { + if (reg[0] & 0x100) { + setprg16(0x8000, prg); + setprg16(0xC000, prg | 0x07); + } else { + setprg16(0x8000, prg & ~1); + setprg16(0xC000, prg | 1); + } + } + SetupCartCHRMapping(0, CHRptr[0], CHRsize[0], !(reg[1] & 0x08)); + setchr8(0); + setmirror((reg[0] & 0x01) ^ 0x01); +} + +static DECLFW(M221Write) { + reg[(A >> 14) & 0x01] = A; + Sync(); +} + +static void M221Power(void) { + reg[0] = reg[1] = 0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M221Write); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper221_Init(CartInfo *info) { + info->Power = M221Power; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/mapper222.c b/src/mappers/mapper222.c similarity index 83% rename from src/boards/mapper222.c rename to src/mappers/mapper222.c index f204877ba..353ffd983 100644 --- a/src/boards/mapper222.c +++ b/src/mappers/mapper222.c @@ -1,8 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -24,13 +24,12 @@ */ #include "mapinc.h" -#include "vrc24.h" +#include "vrc2and4.h" static uint8 IRQCount; static uint8 IRQa; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { &IRQCount, 1, "IRQC" }, { &IRQa, 1, "IRQA" }, { 0 } @@ -46,9 +45,9 @@ static void M222IRQ(void) { } static DECLFW(M222WriteCHR) { - if (~A & 0x01) { - VRC24Write(A, V); - VRC24Write(A | 0x01, V >> 4); + if (!(A & 0x01)) { + VRC24_Write(A, V); + VRC24_Write(A | 0x01, V >> 4); } } @@ -63,16 +62,15 @@ static DECLFW(M222WriteIRQ) { } static void M222Power(void) { - GenVRC24Power(); + VRC24_Power(); SetWriteHandler(0xB000, 0xEFFF, M222WriteCHR); SetWriteHandler(0xF000, 0xFFFF, M222WriteIRQ); - } void Mapper222_Init(CartInfo *info) { - GenVRC24_Init(info, VRC2b, 0); + VRC24_Init(info, VRC2, 0x01, 0x02, 0, 1); info->Power = M222Power; MapIRQHook = NULL; GameHBIRQHook = M222IRQ; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper225.c b/src/mappers/mapper225.c similarity index 74% rename from src/boards/mapper225.c rename to src/mappers/mapper225.c index cfb854dca..8f93aff82 100644 --- a/src/boards/mapper225.c +++ b/src/mappers/mapper225.c @@ -1,9 +1,10 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2011 CaH4e3 - * Copyright (C) 2019 Libretro Team + * Copyright (C) 2019 Libretro Team * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -33,20 +34,25 @@ static uint8 extraRAM[4]; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { extraRAM, 4, "PROT" }, { 0 } }; static void Sync(void) { + uint8 base = (latch.addr >> 8) & 0x40; + uint8 prg = (latch.addr >> 6) & 0x3F; + uint8 chr = latch.addr & 0x3F; + uint8 mirr = ((latch.addr >> 13) & 1) ^ 1; + if (latch.addr & 0x1000) { - setprg16(0x8000, ((latch.addr >> 8) & 0x40) | ((latch.addr >> 6) & 0x3F)); - setprg16(0xC000, ((latch.addr >> 8) & 0x40) | ((latch.addr >> 6) & 0x3F)); - } else - setprg32(0x8000, ((latch.addr >> 9) & 0x20) | ((latch.addr >> 7) & 0x1F)); - setchr8(((latch.addr >> 8) & 0x40) | (latch.addr & 0x3F)); - setmirror(((latch.addr >> 13) & 1) ^ 1); + setprg16(0x8000, base | prg); + setprg16(0xC000, base | prg); + } else { + setprg32(0x8000, (base | prg) >> 1); + } + setchr8(base | chr); + setmirror(mirr); } static DECLFW(M225LoWrite) { @@ -60,17 +66,17 @@ static DECLFR(M225LoRead) { if (A & 0x800) { return extraRAM[A & 3]; } - return X.DB; + return cpu.openbus; } static void M225Power(void) { - LatchPower(); + Latch_Power(); SetReadHandler(0x5000, 0x5fff, M225LoRead); SetWriteHandler(0x5000, 0x5fff, M225LoWrite); } void Mapper225_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); + Latch_Init(info, Sync, NULL, FALSE, FALSE); info->Power = M225Power; AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/bmc42in1r.c b/src/mappers/mapper226.c similarity index 68% rename from src/boards/bmc42in1r.c rename to src/mappers/mapper226.c index 8675bbb57..c23b289ef 100644 --- a/src/boards/bmc42in1r.c +++ b/src/mappers/mapper226.c @@ -1,9 +1,10 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 * Copyright (C) 2009 qeed * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -27,41 +28,41 @@ #include "mapinc.h" -static uint8 reorder_banks = 0; -static uint8 latche[2], reset; -static uint8 banks[4] = { 0, 0, 1, 2 }; -static SFORMAT StateRegs[] = -{ - { &reset, 1, "RST" }, - { latche, 2, "LATC" }, +static uint8 reg[2], dipsw; +static SFORMAT StateRegs[] = { + { &dipsw, 1, "RST" }, + { reg, 2, "LATC" }, { 0 } }; static void Sync(void) { - uint8 bank = 0; - uint8 base = ((latche[0] & 0x80) >> 7) | ((latche[1] & 1) << 1); + uint8 base = (reg[0] >> 7) | ((reg[1] & 0x01) << 1); + uint8 prg = reg[0] & 0x1F; - if (reorder_banks) /* for 1536 KB prg roms */ - base = banks[base]; - bank = (base << 5) | (latche[0] & 0x1f); + /* 1536KiB PRG roms have different bank order */ + if (((ROM.prg.size * 16) == 1536) && base > 0) { + base--; + } - if (!(latche[0] & 0x20)) - setprg32(0x8000, bank >> 1); - else { - setprg16(0x8000, bank); - setprg16(0xC000, bank); + if (reg[0] & 0x20) { + setprg16(0x8000, (base << 5) | prg); + setprg16(0xC000, (base << 5) | prg); + } else { + setprg32(0x8000, ((base << 5) | prg) >> 1); } - setmirror((latche[0] >> 6) & 1); + + SetupCartCHRMapping(0, CHRptr[0], CHRsize[0], !(reg[1] & 0x02)); setchr8(0); + setmirror((reg[0] >> 6) & 0x01); } static DECLFW(M226Write) { - latche[A & 1] = V; + reg[A & 0x01] = V; Sync(); } static void M226Power(void) { - latche[0] = latche[1] = 0; + reg[0] = reg[1] = 0; Sync(); SetWriteHandler(0x8000, 0xFFFF, M226Write); SetReadHandler(0x8000, 0xFFFF, CartBR); @@ -72,15 +73,13 @@ static void StateRestore(int version) { } static void M226Reset(void) { - latche[0] = latche[1] = 0; + reg[0] = reg[1] = 0; Sync(); } void Mapper226_Init(CartInfo *info) { - /* 1536KiB PRG roms have different bank order */ - reorder_banks = ((info->PRGRomSize / 1024) == 1536) ? 1 : 0; info->Power = M226Power; info->Reset = M226Reset; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); GameStateRestore = StateRestore; } diff --git a/src/mappers/mapper227.c b/src/mappers/mapper227.c new file mode 100644 index 000000000..66ac20593 --- /dev/null +++ b/src/mappers/mapper227.c @@ -0,0 +1,69 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static uint8 dipsw; + +static void Sync(void) { + uint32 prg = ((latch.addr >> 3) & 0x20) | ((latch.addr >> 2) & 0x1F); + uint32 cpuA14 = latch.addr & 0x01; + uint32 nrom = (latch.addr >> 7) & 0x01; + uint32 unrom = (latch.addr >> 9) & 0x01; + + setprg8r(0x10, 0x6000, 0); + setprg16(0x8000, prg & ~cpuA14); + setprg16(0xC000, ((prg | cpuA14) & ~(0x07 * !nrom * !unrom)) | (0x07 * !nrom * unrom)); + + setchr8(0); + setmirror(((latch.addr >> 1) & 0x01) ^ 0x01); + if (!iNESCart.battery && (latch.addr & 0x80) == 0x80) { + /* CHR-RAM write protect hack, needed for some multicarts */ + SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0); + } else { + SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1); + } +} + +static DECLFR(M227Read) { + if ((latch.addr & 0x400) && dipsw) { + A |= dipsw; + } + return CartBROB(A); +} + +static void M227Power(void) { + dipsw = 0; + Latch_Power(); +} + +static void M227Reset(void) { + dipsw = (dipsw + 1) & 0x1F; + Latch_RegReset(); +} + +void Mapper227_Init(CartInfo *info) { + Latch_Init(info, Sync, M227Read, TRUE, FALSE); + info->Power = M227Power; + info->Reset = M227Reset; + AddExState(&dipsw, 1, 0, "PADS"); +} diff --git a/src/boards/mapper228.c b/src/mappers/mapper228.c similarity index 56% rename from src/boards/mapper228.c rename to src/mappers/mapper228.c index cb088ef98..acc4e2769 100644 --- a/src/boards/mapper228.c +++ b/src/mappers/mapper228.c @@ -1,8 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2012 CaH4e3 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -33,18 +33,40 @@ #include "latch.h" static void Sync(void) { - uint32 prgl, prgh, page = (latch.addr >> 7) & 0x3F; - if ((page & 0x30) == 0x30) - page -= 0x10; - prgl = prgh = (page << 1) + (((latch.addr >> 6) & 1) & ((latch.addr >> 5) & 1)); - prgh += ((latch.addr >> 5) & 1) ^ 1; - - setmirror(((latch.addr >> 13) & 1) ^ 1); - setprg16(0x8000, prgl); - setprg16(0xc000, prgh); - setchr8(((latch.data & 0x3) | ((latch.addr & 0xF) << 2))); + if (latch.addr & 0x20) { + setprg16(0x8000, (latch.addr >> 6) & 0x7F); + setprg16(0xC000, (latch.addr >> 6) & 0x7F); + } else { + setprg32(0x8000, (latch.addr >> 7) & 0x3F); + } + setchr8(((latch.addr << 2) & 0x3C) | (latch.data & 0x3)); + setmirror(((latch.addr >> 13) & 0x01) ^ 0x01); } void Mapper228_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); + Latch_Init(info, Sync, NULL, FALSE, FALSE); + + if (iNESCart.PRGRomSize == 0x180000) { + int i; + size_t ssize = 0x200000; + uint8 *tmp = (uint8 *)FCEU_malloc(ssize); + + for (i = 0; i < (int)iNESCart.PRGRomSize; i++) { + tmp[i] = ROM.prg.data[i]; + } + for (i = 0x000000; i < 0x080000; i++) { + tmp[0x180000 + i] = tmp[0x100000 + i]; + tmp[0x100000 + i] = (i >> 8) & 0xFF; + } + + iNESCart.PRGRomSize = ssize; + if (ROM.prg.data) FCEU_free(ROM.prg.data); + ROM.prg.data = (uint8 *)FCEU_malloc(ssize); + for (i = 0; i < (int)iNESCart.PRGRomSize; i++) { + ROM.prg.data[i] = tmp[i]; + } + FCEU_free(tmp); + + SetupCartPRGMapping(0, ROM.prg.data, iNESCart.PRGRomSize, 0); + } } diff --git a/src/mappers/mapper229.c b/src/mappers/mapper229.c new file mode 100644 index 000000000..2fc519e76 --- /dev/null +++ b/src/mappers/mapper229.c @@ -0,0 +1,38 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + if (latch.addr & 0x1E) { + setprg16(0x8000, latch.addr & 0x1F); + setprg16(0xC000, latch.addr & 0x1F); + } else { + setprg32(0x8000, 0); + } + setchr8(latch.addr & 0x1F); + setmirror(((latch.addr >> 5) & 0x01) ^ 0x01); +} + +void Mapper229_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); +} diff --git a/src/boards/mapper230.c b/src/mappers/mapper230.c similarity index 67% rename from src/boards/mapper230.c rename to src/mappers/mapper230.c index 4f8ea68c7..8c505b03f 100644 --- a/src/boards/mapper230.c +++ b/src/mappers/mapper230.c @@ -1,9 +1,9 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 * Copyright (C) 2009 qeed - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -26,43 +26,43 @@ #include "mapinc.h" #include "latch.h" -static uint8 reset; -static SFORMAT StateRegs[] = -{ - { &reset, 1, "RST" }, +static uint8 mode; + +static SFORMAT StateRegs[] = { + { &mode, 1, "MODE" }, { 0 } }; static void Sync(void) { - if (reset) { /* Contra mode */ - setprg16(0x8000, latch.data & 7); - setprg16(0xC000, 7); + if (mode) { /* Contra mode */ + setprg16(0x8000, latch.data & 0x07); + setprg16(0xC000, 0x07); setmirror(MI_V); } else { /* multicart mode */ - uint32 bank = (latch.data & 0x1F) + 8; if (latch.data & 0x20) { - setprg16(0x8000, bank); - setprg16(0xC000, bank); - } else - setprg32(0x8000, bank >> 1); - setmirror((latch.data >> 6) & 1); + setprg16(0x8000, 8 + (latch.data & 0x1F)); + setprg16(0xC000, 8 + (latch.data & 0x1F)); + } else { + setprg32(0x8000, (8 + (latch.data & 0x1F)) >> 1); + } + setmirror((latch.data >> 6) & 0x01); } setchr8(0); } static void M230Reset(void) { - reset ^= 1; - LatchHardReset(); + mode ^= 1; + Latch_RegReset(); } static void M230Power(void) { - reset = 0; - LatchPower(); + mode = 0; + Latch_Power(); } void Mapper230_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); + Latch_Init(info, Sync, NULL, FALSE, FALSE); info->Power = M230Power; info->Reset = M230Reset; - AddExState(StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper231.c b/src/mappers/mapper231.c new file mode 100644 index 000000000..dca7c117c --- /dev/null +++ b/src/mappers/mapper231.c @@ -0,0 +1,43 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + if (latch.addr & 0x20) { + setprg32(0x8000, (latch.addr >> 1) & 0x0F); + } else { + setprg16(0x8000, latch.addr & 0x1E); + setprg16(0xC000, latch.addr & 0x1E); + } + setchr8(0); + switch ((latch.addr >> 6) & 0x03) { + case 0: setmirror(MI_0); break; + case 1: setmirror(MI_V); break; + case 2: setmirror(MI_H); break; + case 3: setmirrorw(0, 1, 1, 1); break; + } +} + +void Mapper231_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); +} diff --git a/src/boards/mapper072.c b/src/mappers/mapper232.c similarity index 61% rename from src/boards/mapper072.c rename to src/mappers/mapper232.c index bd187f8af..e004e819b 100644 --- a/src/boards/mapper072.c +++ b/src/mappers/mapper232.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) 2023-2024 negativeExponent * * 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 @@ -16,49 +17,46 @@ * 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 - * - * Moero!! Pro Tennis have ADPCM codec on-board, PROM isn't dumped, emulation isn't - * possible just now. */ #include "mapinc.h" -static uint8 preg, creg; +static uint8 reg[2]; -static SFORMAT StateRegs[] = -{ - { &preg, 1, "PREG" }, - { &creg, 1, "CREG" }, +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, { 0 } }; static void Sync(void) { - setprg16(0x8000, preg); - setprg16(0xC000, ~0); - setchr8(creg); + uint8 base = (reg[0] >> 1) & 0x0C; + + if (iNESCart.submapper == 1) { + base = ((base << 1) & 0x08) | ((base >> 1) & 0x04); + } + setprg16(0x8000, base | (reg[1] & 0x03)); + setprg16(0xC000, base | 0x03); + setchr8(0); } -static DECLFW(M72Write) { - if (V & 0x80) - preg = V & 0xF; - if (V & 0x40) - creg = V & 0xF; +static DECLFW(M232Write) { + reg[(A >> 14) & 0x01] = V; Sync(); } -static void M72Power(void) { +static void M232Power(void) { + reg[0] = reg[1] = 0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0xFFFF, M72Write); + SetWriteHandler(0x8000, 0xFFFF, M232Write); } static void StateRestore(int version) { Sync(); } -void Mapper72_Init(CartInfo *info) { - info->Power = M72Power; +void Mapper232_Init(CartInfo *info) { + info->Power = M232Power; GameStateRestore = StateRestore; - - AddExState(&StateRegs, ~0, 0, 0); + AddExState(&StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper233.c b/src/mappers/mapper233.c similarity index 73% rename from src/boards/mapper233.c rename to src/mappers/mapper233.c index dc2a1a573..5d271382b 100644 --- a/src/boards/mapper233.c +++ b/src/mappers/mapper233.c @@ -1,10 +1,10 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 * Copyright (C) 2009 qeed * Copyright (C) 2019 Libretro Team - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -31,43 +31,32 @@ static uint8 reset; -static SFORMAT StateRegs[] = -{ - { &reset, 1, "RST" }, +static SFORMAT StateRegs[] = { + { &reset, 1, "RST0" }, { 0 } }; static void Sync(void) { - uint8 bank = (latch.data & 0x1f) | (reset << 5); + uint8 bank = (latch.data & 0x1F) | (reset << 5); - if (!(latch.data & 0x20)) - setprg32(0x8000, bank >> 1); - else { + if (latch.data & 0x20) { setprg16(0x8000, bank); setprg16(0xC000, bank); + } else { + setprg32(0x8000, bank >> 1); } - - switch ((latch.data >> 6) & 3) { - case 0: - setmirror(MI_0); - break; - case 1: - setmirror(MI_V); - break; - case 2: - setmirror(MI_H); - break; - case 3: - setmirror(MI_1); - break; - } - setchr8(0); + switch ((latch.data >> 6) & 0x03) { + case 0: setmirror(MI_0); break; + case 1: setmirror(MI_V); break; + case 2: setmirror(MI_H); break; + case 3: setmirror(MI_1); break; + } } static void M233Power(void) { reset = 0; - LatchPower(); + Latch_Power(); } static void M233Reset(void) { @@ -76,8 +65,8 @@ static void M233Reset(void) { } void Mapper233_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); + Latch_Init(info, Sync, NULL, FALSE, FALSE); info->Power = M233Power; info->Reset = M233Reset; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper234.c b/src/mappers/mapper234.c similarity index 56% rename from src/boards/mapper234.c rename to src/mappers/mapper234.c index 2037c53b4..3cbf5e46c 100644 --- a/src/boards/mapper234.c +++ b/src/mappers/mapper234.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) 2023-2024 negativeExponent * * 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 @@ -20,51 +21,66 @@ #include "mapinc.h" -static uint8 bank, preg; -static SFORMAT StateRegs[] = -{ - { &bank, 1, "BANK" }, - { &preg, 1, "PREG" }, +static uint8 reg[3]; + +static SFORMAT StateRegs[] = { + { reg, 3, "REGS" }, { 0 } }; static void Sync(void) { - if (bank & 0x40) { - setprg32(0x8000, (bank & 0xE) | (preg & 1)); - setchr8(((bank & 0xE) << 2) | ((preg >> 4) & 7)); + if (reg[0] & 0x40) { + setprg32(0x8000, (reg[0] & 0x0E) | (reg[1] & 0x01)); + setchr8(((reg[0] & 0x0E) << 2) | ((reg[1] >> 4) & 0x07)); } else { - setprg32(0x8000, bank & 0xF); - setchr8(((bank & 0xF) << 2) | ((preg >> 4) & 3)); + setprg32(0x8000, reg[0] & 0x0F); + setchr8(((reg[0] & 0x0F) << 2) | ((reg[1] >> 4) & 0x03)); } - setmirror((bank >> 7) ^ 1); + setmirror((reg[0] >> 7) ^ 0x01); } -DECLFR(M234ReadBank) { - uint8 r = CartBR(A); - if (!bank) { - bank = r; +static DECLFR(M234Read) { + uint8 ret = CartBR(A); + + switch (A & 0xFFF8) { + case 0xFF80: + case 0xFF88: + case 0xFF90: + case 0xFF98: + if (!reg[0]) { + reg[0] = ret; + Sync(); + } + break; + case 0xFFC0: + case 0xFFC8: + case 0xFFD0: + case 0xFFD8: + if (!reg[0]) { + reg[2] = ret; + Sync(); + } + break; + case 0xFFE8: + case 0xFFF0: + reg[1] = ret; Sync(); + break; } - return r; -} -DECLFR(M234ReadPreg) { - uint8 r = CartBR(A); - preg = r; - Sync(); - return r; + return ret; } static void M234Reset(void) { - bank = preg = 0; + reg[0] = reg[1] = reg[2] = 0; Sync(); } static void M234Power(void) { - M234Reset(); + reg[0] = reg[1] = reg[2] = 0; + Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetReadHandler(0xFF80, 0xFF9F, M234ReadBank); - SetReadHandler(0xFFE8, 0xFFF7, M234ReadPreg); + SetReadHandler(0xFF80, 0xFFFF, M234Read); } static void StateRestore(int version) { @@ -74,6 +90,6 @@ static void StateRestore(int version) { void Mapper234_Init(CartInfo *info) { info->Power = M234Power; info->Reset = M234Reset; - AddExState(&StateRegs, ~0, 0, 0); GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper235.c b/src/mappers/mapper235.c similarity index 58% rename from src/boards/mapper235.c rename to src/mappers/mapper235.c index e3d3dd764..f90c61b26 100644 --- a/src/boards/mapper235.c +++ b/src/mappers/mapper235.c @@ -1,8 +1,9 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent * * 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,57 +23,55 @@ #include "mapinc.h" #include "latch.h" -static uint8 unrom, openbus; +static uint8 mode; -static SFORMAT StateRegs[] = -{ - { &openbus, 1, "OPNB" }, - { &unrom, 1, "UROM" }, +static SFORMAT StateRegs[] = { + { &mode, 1, "UROM" }, { 0 } }; static void Sync(void) { - if (unrom) { /* Contra mode */ - setprg16(0x8000, (ROM_size & 0xC0) | (latch.data & 7)); - setprg16(0xC000, (ROM_size & 0xC0) | 7); + if (mode) { /* Contra mode */ + setprg16(0x8000, (ROM.prg.size & 0xC0) | (latch.data & 0x07)); + setprg16(0xC000, (ROM.prg.size & 0xC0) | 0x07); setchr8(0); setmirror(MI_V); } else { - uint8 bank = ((latch.addr & 0x300) >> 3) | (latch.addr & 0x1F); - if (latch.addr & 0x400) { - setmirror(MI_0); - } else { - setmirror(((latch.addr >> 13) & 1) ^ 1); - } - if (bank >= (ROM_size >> 1)) { - openbus = 1; - } else if (latch.addr & 0x800) { - setprg16(0x8000, (bank << 1) | ((latch.addr >> 12) & 1)); - setprg16(0xC000, (bank << 1) | ((latch.addr >> 12) & 1)); + uint8 bank = ((latch.addr >> 3) & 0x60) | (latch.addr & 0x1F); + + if (latch.addr & 0x800) { + setprg16(0x8000, (bank << 1) | ((latch.addr >> 12) & 0x01)); + setprg16(0xC000, (bank << 1) | ((latch.addr >> 12) & 0x01)); } else { setprg32(0x8000, bank); } setchr8(0); + if (latch.addr & 0x400) { + setmirror(MI_0); + } else { + setmirror(((latch.addr >> 13) & 0x01) ^ 0x01); + } } } static DECLFR(M235Read) { - if (openbus) { - openbus = 0; - return X.DB; + uint8 bank = ((latch.addr >> 3) & 0x60) | (latch.addr & 0x1F); + + if (!mode && (bank >= (PRGsize[0] / 32768))) { + return cpu.openbus; } return CartBR(A); } static void M235Reset(void) { - if ((ROM_size * 16384) & 0x20000) { - unrom = (unrom + 1) & 1; + if ((ROM.prg.size * 16384) & 0x20000) { + mode = (mode + 1) & 1; } - LatchHardReset(); + Latch_RegReset(); } void Mapper235_Init(CartInfo *info) { - Latch_Init(info, Sync, M235Read, 0, 0); + Latch_Init(info, Sync, M235Read, FALSE, FALSE); info->Reset = M235Reset; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper236.c b/src/mappers/mapper236.c similarity index 68% rename from src/boards/mapper236.c rename to src/mappers/mapper236.c index 9fa9aa21c..5f41201cb 100644 --- a/src/boards/mapper236.c +++ b/src/mappers/mapper236.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) 2023-2024 negativeExponent * * 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,56 +22,59 @@ #include "mapinc.h" static uint8 reg[2]; -static uint8 dip; -static SFORMAT StateRegs[] = -{ - { reg, 2, "REG " }, - { &dip, 1, "DIP " }, +static uint8 dipsw; + +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, + { &dipsw, 1, "DPSW " }, { 0 } }; static void Sync(void) { - int prg; - int chr; + uint8 prg; + uint8 chr; + if (UNIFchrrama) { - prg = (reg[1] & 7) | (reg[0] << 3); + prg = (reg[1] & 0x07) | (reg[0] << 3); chr = 0; } else { prg = reg[1] & 0x0F; chr = reg[0] & 0x0F; } switch (reg[1] >> 4 & 3) { - case 0: - case 1: - setprg16(0x8000, prg); - setprg16(0xC000, prg | 7); - break; - case 2: - setprg32(0x8000, prg >> 1); - break; - case 3: - setprg16(0x8000, prg); - setprg16(0xC000, prg); - break; + case 0: + case 1: + setprg16(0x8000, prg); + setprg16(0xC000, prg | 0x07); + break; + case 2: + setprg32(0x8000, prg >> 1); + break; + case 3: + setprg16(0x8000, prg); + setprg16(0xC000, prg); + break; } setchr8(chr); - setmirror(((reg[0] >> 5) & 1) ^ 1); + setmirror(((reg[0] >> 5) & 0x01) ^ 0x01); } static DECLFR(M236Read) { - if (((reg[1] >> 4) & 3) == 1) - return CartBR((A & ~0xF) | (dip & 0xF)); - else - return CartBR(A); + uint8 ret = CartBR(A); + + if (((reg[1] >> 4) & 0x03) == 1) { + return ((ret & ~0x0F) | (dipsw & 0x0F)); + } + return CartBR(A); } static DECLFW(M236WriteReg) { - reg[(A >> 14) & 1] = A & 0xFF; + reg[(A >> 14) & 0x01] = A & 0xFF; Sync(); } static void M236Power(void) { - dip = 0; + dipsw = 0; reg[0] = 0; reg[1] = 0; Sync(); @@ -79,7 +83,7 @@ static void M236Power(void) { } static void M236Reset(void) { - ++dip; + ++dipsw; /* Soft-reset returns to menu */ reg[0] = 0; reg[1] = 0; @@ -93,6 +97,6 @@ static void StateRestore(int version) { void Mapper236_Init(CartInfo *info) { info->Power = M236Power; info->Reset = M236Reset; - AddExState(&StateRegs, ~0, 0, 0); GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper237.c b/src/mappers/mapper237.c similarity index 64% rename from src/boards/mapper237.c rename to src/mappers/mapper237.c index 2dd3f194c..259f0c33a 100644 --- a/src/boards/mapper237.c +++ b/src/mappers/mapper237.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -29,67 +30,59 @@ #include "mapinc.h" #include "latch.h" -static uint8 dipswitch; +static uint8 dipsw; -static SFORMAT StateRegs[] = -{ - { &dipswitch, 1, "DPSW" }, +static SFORMAT StateRegs[] = { + { &dipsw, 1, "DPSW" }, { 0 } }; static void Sync(void) { uint8 bank = (latch.data & 0x07); uint8 base = ((latch.addr << 3) & 0x20) | (latch.data & 0x18); - uint8 mode = (latch.data & 0xC0) >> 6; + uint8 A14 = (latch.data >> 6) & 0x01; + setprg16(0x8000, base | (bank & ~A14)); + if (latch.data & 0x80) { + setprg16(0xC000, base | (bank | A14)); + } else { + setprg16(0xC000, base | 0x07); + } setchr8(0); - setprg16(0x8000, base | (bank & ~(mode & 1))); - setprg16(0xC000, base | ((mode & 0x02) ? (bank | (mode & 0x01)) : 0x07)); - setmirror(((latch.data & 0x20) >> 5) ^ 1); + setmirror(((latch.data & 0x20) >> 5) ^ 0x01); } static DECLFW(M237Write) { if (latch.addr & 0x02) { - latch.data &= ~0x07; - latch.data |= (V & 0x07); - Sync(); + latch.data = (latch.data & 0xF8) | (V & 0x07); } else { - LatchWrite(A, V); + latch.addr = A; + latch.data = V; } + Sync(); } static DECLFR(M237Read) { if (latch.addr & 0x01) { - return dipswitch; + return dipsw; } return CartBR(A); } -static void M237Reset() { - dipswitch++; - dipswitch &= 3; - LatchHardReset(); +static void M237Reset(void) { + dipsw++; + dipsw &= 3; + Latch_RegReset(); } static void M237Power(void) { - LatchPower(); + Latch_Power(); SetWriteHandler(0x8000, 0xFFFF, M237Write); } void Mapper237_Init(CartInfo *info) { -#if 0 - /* The menu system used by this cart seems to be configurable as 4 different types: - * 0: 42-in-1 - * 1: 5,000-in-1 - * 2: 420-in-1 - * 3: 10,000,000-in-1 (lol) - */ - dipswitch = 0; - if ((info->CRC32) == 0x272709b9) /* Teletubbies Y2K (420-in-1) */ - dipswitch = 2; -#endif - Latch_Init(info, Sync, M237Read, 0, 0); + Latch_Init(info, Sync, M237Read, FALSE, FALSE); info->Power = M237Power; info->Reset = M237Reset; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper238.c b/src/mappers/mapper238.c similarity index 68% rename from src/boards/mapper238.c rename to src/mappers/mapper238.c index aa5830cbc..b8499a31d 100644 --- a/src/boards/mapper238.c +++ b/src/mappers/mapper238.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -17,6 +18,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + * iNES Mapper 238 * SL12 Protected 3-in-1 mapper hardware (VRC2, MMC3, MMC1) * the same as 603-5052 board (TODO: add reading registers, merge) * @@ -26,24 +28,27 @@ #include "mapinc.h" #include "mmc3.h" +static uint8 reg; + static const uint8 lut[4] = { 0x00, 0x02, 0x02, 0x03 }; -static DECLFW(UNL6035052ProtWrite) { - mmc3.expregs[0] = lut[V & 3]; +static DECLFW(M238ProtWrite) { + reg = lut[V & 0x03]; } -static DECLFR(UNL6035052ProtRead) { - return mmc3.expregs[0]; +static DECLFR(M238ProtRead) { + return reg; } -static void UNL6035052Power(void) { - GenMMC3Power(); - SetWriteHandler(0x4020, 0x7FFF, UNL6035052ProtWrite); - SetReadHandler(0x4020, 0x7FFF, UNL6035052ProtRead); +static void M238Power(void) { + reg = 0; + MMC3_Power(); + SetWriteHandler(0x4020, 0x7FFF, M238ProtWrite); + SetReadHandler(0x4020, 0x7FFF, M238ProtRead); } -void UNL6035052_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 256, 0, 0); - info->Power = UNL6035052Power; - AddExState(mmc3.expregs, 6, 0, "EXPR"); +void Mapper238_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + info->Power = M238Power; + AddExState(®, 1, 0, "EXPR"); } diff --git a/src/boards/mapper240.c b/src/mappers/mapper240.c similarity index 73% rename from src/boards/mapper240.c rename to src/mappers/mapper240.c index 1c5338982..2cf33c15e 100644 --- a/src/boards/mapper240.c +++ b/src/mappers/mapper240.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -20,20 +20,17 @@ #include "mapinc.h" -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; static uint8 reg; -static SFORMAT StateRegs[] = -{ - { ®, 1, "REG" }, +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, { 0 } }; -static void Sync() { - setprg8r(0x10, 0x6000, 0); +static void Sync(void) { setprg32(0x8000, reg >> 4); - setchr8(reg & 0xF); + setchr8(reg & 0x0F); + setprg8r(0x10, 0x6000, 0); } static DECLFW(M240Write) { @@ -45,7 +42,7 @@ static void M240Power(void) { reg = 0; Sync(); SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x4020, 0x5FFF, M240Write); + SetWriteHandler(0x4020, 0x4FFF, M240Write); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } @@ -56,16 +53,19 @@ static void StateRestore(int version) { void Mapper240_Init(CartInfo *info) { info->Power = M240Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); WRAMSIZE = 8192; - if (info->iNES2) + if (info->iNES2) { WRAMSIZE = info->PRGRamSize + info->PRGRamSaveSize; - 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"); + if (WRAMSIZE) { + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + } } diff --git a/src/mappers/mapper241.c b/src/mappers/mapper241.c new file mode 100644 index 000000000..7db733685 --- /dev/null +++ b/src/mappers/mapper241.c @@ -0,0 +1,37 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + */ + +/* Map 241 */ +/* Mapper 7 mostly, but with SRAM or maybe prot circuit. */ + +#include "mapinc.h" +#include "latch.h" + +static void Sync(void) { + setprg8r(0x10, 0x6000, 0); + setprg32(0x8000, latch.data); + setchr8(0); +} + +void Mapper241_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, TRUE, FALSE); + info->Reset = Latch_RegReset; +} diff --git a/src/mappers/mapper242.c b/src/mappers/mapper242.c new file mode 100644 index 000000000..d8c79c5d8 --- /dev/null +++ b/src/mappers/mapper242.c @@ -0,0 +1,79 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static uint8 dipsw; + +static void Sync(void) { + uint32 prg = (latch.addr >> 2) & 0x1F; + uint32 cpuA14 = latch.addr & 0x01; + uint32 nrom = (latch.addr >> 7) & 0x01; + uint32 unrom = (latch.addr >> 9) & 0x01; + uint32 M242TwoChips = (iNESCart.PRGRomSize & 0x20000) && (iNESCart.PRGRomSize > 0x20000); + + if (M242TwoChips) { + if (latch.addr & 0x600) { /* First chip */ + prg &= ((ROM.prg.size & ~0x08) - 1); + } else { /* Second chip */ + prg &= 0x07; + prg += (ROM.prg.size & ~0x08); + } + } + + setprg8r(0x10, 0x6000, 0); + setprg16(0x8000, prg & ~cpuA14); + setprg16(0xC000, ((prg | cpuA14) & ~(0x07 * !nrom * !unrom)) | (0x07 * !nrom * unrom)); + + setchr8(0); + setmirror(((latch.addr >> 1) & 1) ^ 1); + if (!iNESCart.battery && (latch.addr & 0x80) == 0x80 && (ROM.prg.size * 16) > 256) { + /* CHR-RAM write protect hack, needed for some multicarts */ + SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0); + } else { + SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1); + } +} + +static DECLFR(M242Read) { + if (latch.addr & 0x100) { + A |= dipsw; + } + return CartBROB(A); +} + +static void M242Power(void) { + dipsw = 0; + Latch_Power(); +} + +static void M242Reset(void) { + dipsw = (dipsw + 1) & 0x1F; + Latch_RegReset(); +} + +void Mapper242_Init(CartInfo *info) { + Latch_Init(info, Sync, M242Read, TRUE, FALSE); + info->Power = M242Power; + info->Reset = M242Reset; + AddExState(&dipsw, 1, 0, "PADS"); +} diff --git a/src/boards/mapper244.c b/src/mappers/mapper244.c similarity index 58% rename from src/boards/mapper244.c rename to src/mappers/mapper244.c index f5d696e14..059af9713 100644 --- a/src/boards/mapper244.c +++ b/src/mappers/mapper244.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) 2023-2024 negativeExponent * * 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 @@ -20,47 +21,46 @@ #include "mapinc.h" -static uint8 preg, creg; -static SFORMAT StateRegs[] = -{ - { &preg, 1, "PREG" }, - { &creg, 1, "CREG" }, - { 0 } -}; - -static uint8 prg_perm[4][4] = { - { 0, 1, 2, 3, }, - { 3, 2, 1, 0, }, - { 0, 2, 1, 3, }, - { 3, 1, 2, 0, }, -}; +static uint8 reg[2]; -static uint8 chr_perm[8][8] = { - { 0, 1, 2, 3, 4, 5, 6, 7, }, - { 0, 2, 1, 3, 4, 6, 5, 7, }, - { 0, 1, 4, 5, 2, 3, 6, 7, }, - { 0, 4, 1, 5, 2, 6, 3, 7, }, - { 0, 4, 2, 6, 1, 5, 3, 7, }, - { 0, 2, 4, 6, 1, 3, 5, 7, }, - { 7, 6, 5, 4, 3, 2, 1, 0, }, - { 7, 6, 5, 4, 3, 2, 1, 0, }, +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, + { 0 } }; static void Sync(void) { - setprg32(0x8000, preg); - setchr8(creg); + setprg32(0x8000, reg[0]); + setchr8(reg[1]); } static DECLFW(M244Write) { - if (V & 8) - creg = chr_perm[(V >> 4) & 7][V & 7]; - else - preg = prg_perm[(V >> 4) & 3][V & 3]; - Sync(); + if (V & 8) { + static const uint8 chr_perm[8][8] = { + { 0, 1, 2, 3, 4, 5, 6, 7, }, + { 0, 2, 1, 3, 4, 6, 5, 7, }, + { 0, 1, 4, 5, 2, 3, 6, 7, }, + { 0, 4, 1, 5, 2, 6, 3, 7, }, + { 0, 4, 2, 6, 1, 5, 3, 7, }, + { 0, 2, 4, 6, 1, 3, 5, 7, }, + { 7, 6, 5, 4, 3, 2, 1, 0, }, + { 7, 6, 5, 4, 3, 2, 1, 0, }, + }; + reg[1] = chr_perm[(V >> 4) & 0x07][V & 0x07]; + Sync(); + } else { + static const uint8 prg_perm[4][4] = { + { 0, 1, 2, 3, }, + { 3, 2, 1, 0, }, + { 0, 2, 1, 3, }, + { 3, 1, 2, 0, }, + }; + reg[0] = prg_perm[(V >> 4) & 0x03][V & 0x03]; + Sync(); + } } static void M244Power(void) { - preg = creg = 0; + reg[0] = reg[1] = 0; Sync(); SetWriteHandler(0x8000, 0xFFFF, M244Write); SetReadHandler(0x8000, 0xFFFF, CartBR); @@ -72,6 +72,6 @@ static void StateRestore(int version) { void Mapper244_Init(CartInfo *info) { info->Power = M244Power; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); GameStateRestore = StateRestore; } diff --git a/src/mappers/mapper245.c b/src/mappers/mapper245.c new file mode 100644 index 000000000..884c91b4c --- /dev/null +++ b/src/mappers/mapper245.c @@ -0,0 +1,61 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 reg; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; + +static void M245PW(uint32 A, uint8 V) { + setprg8(A, ((mmc3.reg[0] & 0x02) << 5) | (V & 0x3F)); +} + +static void M245CW(uint32 A, uint8 V) { + setchr8(0); +} + +static DECLFW(M245Write) { + if (A & 0x01) { + mmc3.reg[mmc3.cmd & 0x07] = V; + } else { + mmc3.cmd = V; + } + MMC3_FixPRG(); + MMC3_FixCHR(); +} + +static void M245Power(void) { + reg = 0; + MMC3_Power(); + SetWriteHandler(0x8000, 0x9FFF, M245Write); +} + +void Mapper245_Init(CartInfo *info) { + MMC3_Init(info, 8, info->battery); + info->Power = M245Power; + MMC3_pwrap = M245PW; + MMC3_cwrap = M245CW; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/mapper246.c b/src/mappers/mapper246.c similarity index 65% rename from src/boards/mapper246.c rename to src/mappers/mapper246.c index 84bf851fc..ecc161fdc 100644 --- a/src/boards/mapper246.c +++ b/src/mappers/mapper246.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) 2023-2024 negativeExponent * * 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 @@ -20,47 +21,61 @@ #include "mapinc.h" -static uint8 regs[8]; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; +static uint8 prg[4]; +static uint8 chr[4]; -static SFORMAT StateRegs[] = -{ - { regs, 8, "REGS" }, +static SFORMAT StateRegs[] = { + { prg, 4, "PREG" }, + { chr, 4, "CREG" }, { 0 } }; static void Sync(void) { setprg2r(0x10, 0x6800, 0); - setprg8(0x8000, regs[0]); - setprg8(0xA000, regs[1]); - setprg8(0xC000, regs[2]); - setprg8(0xE000, regs[3]); - setchr2(0x0000, regs[4]); - setchr2(0x0800, regs[5]); - setchr2(0x1000, regs[6]); - setchr2(0x1800, regs[7]); + setprg8(0x8000, prg[0]); + setprg8(0xA000, prg[1]); + setprg8(0xC000, prg[2]); + setprg8(0xE000, prg[3]); + setchr2(0x0000, chr[0]); + setchr2(0x0800, chr[1]); + setchr2(0x1000, chr[2]); + setchr2(0x1800, chr[3]); +} + +static DECLFR(M246Read) { + if ((A & 0xFFE4) == 0xFFE4) { + size_t prgOffset = ((prg[3] | 0x10) << 13) | 0x1000 | (A & 0xFFF); + return PRGptr[0][prgOffset & 0x7FFFF]; + } + return CartBR(A); } static DECLFW(M246Write) { - regs[A & 7] = V; - Sync(); + if (A & 0x04) { + chr[A & 0x03] = V; + Sync(); + } else { + prg[A & 0x03] = V; + Sync(); + } } static void M246Power(void) { - regs[0] = regs[1] = regs[2] = regs[3] = ~0; + prg[0] = 0; + prg[1] = 1; + prg[2] = ~1; + prg[3] = ~0; Sync(); - SetWriteHandler(0x6000, 0x67FF, M246Write); + SetReadHandler(0x6800, 0x6FFF, CartBR); + SetReadHandler(0x8000, 0xFFFF, M246Read); + SetWriteHandler(0x6000, 0x67FF, M246Write); SetWriteHandler(0x6800, 0x6FFF, CartBW); - SetReadHandler(0x8000, 0xFFFF, CartBR); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void M246Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; } static void StateRestore(int version) { @@ -71,16 +86,14 @@ void Mapper246_Init(CartInfo *info) { info->Power = M246Power; info->Close = M246Close; GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); WRAMSIZE = 2048; WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - if (info->battery) { info->SaveGame[0] = WRAM; info->SaveGameLen[0] = WRAMSIZE; } - - AddExState(&StateRegs, ~0, 0, 0); } diff --git a/src/mappers/mapper249.c b/src/mappers/mapper249.c new file mode 100644 index 000000000..4863f12cf --- /dev/null +++ b/src/mappers/mapper249.c @@ -0,0 +1,89 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 reg; + +static uint32 scrambleBankOrder(uint32 V, const uint8 *source, const uint8 *target, uint32 length) { + uint32 bank = 0; + uint32 bit = 0; + + for (bit = 0; bit < 8; bit++) { + if (V & (0x01 << bit)) { + uint32 index = 0; + + for (index = 0; index < length; index++) { + if (source[index] == bit) { + break; + } + } + bank |= (0x01 << (index == length ? bit : target[index])); + } + } + return bank; +} + +static void M249PW(uint32 A, uint8 V) { + static const uint8 prg_pattern[4][4] = { + { 3, 4, 2, 1 }, + { 4, 3, 1, 2 }, + { 1, 2, 3, 4 }, + { 2, 1, 4, 3 }, + }; + uint32 bank = scrambleBankOrder(V, prg_pattern[reg & 0x03], prg_pattern[(iNESCart.mapper == 249) ? 0 : 2], 4); + setprg8(A, bank); +} + +static void M249CW(uint32 A, uint8 V) { + static const uint8 chr_pattern[8][6] = { + { 5, 2, 6, 7, 4, 3 }, + { 4, 5, 3, 2, 7, 6 }, + { 2, 3, 4, 5, 6, 7 }, + { 6, 4, 2, 3, 7, 5 }, + { 5, 3, 7, 6, 2, 4 }, + { 4, 2, 5, 6, 7, 3 }, + { 3, 6, 4, 5, 2, 7 }, + { 2, 5, 6, 7, 3, 4 }, + }; + uint32 bank = scrambleBankOrder(V, chr_pattern[reg & 0x07], chr_pattern[(iNESCart.mapper == 249) ? 0 : 2], 6); + setchr1(A, bank); +} + +static DECLFW(M249Write) { + reg = V; + MMC3_FixPRG(); + MMC3_FixCHR(); +} + +static void M249Power(void) { + reg = 0; + MMC3_Power(); + SetWriteHandler(0x5000, 0x5FFF, M249Write); +} + +void Mapper249_Init(CartInfo *info) { + MMC3_Init(info, 8, info->battery); + MMC3_cwrap = M249CW; + MMC3_pwrap = M249PW; + info->Power = M249Power; + AddExState(®, 1, 0, "EXPR"); +} diff --git a/src/mappers/mapper250.c b/src/mappers/mapper250.c new file mode 100644 index 000000000..0d1afd1d1 --- /dev/null +++ b/src/mappers/mapper250.c @@ -0,0 +1,36 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static DECLFW(M250Write) { + MMC3_Write(((A & 0xE000) | ((A & 0x400) >> 10)), (A & 0xFF)); +} + +static void M250Power(void) { + MMC3_Power(); + SetWriteHandler(0x8000, 0xFFFF, M250Write); +} + +void Mapper250_Init(CartInfo *info) { + MMC3_Init(info, 8, info->battery); + info->Power = M250Power; +} diff --git a/src/mappers/mapper252.c b/src/mappers/mapper252.c new file mode 100644 index 000000000..d27dc336c --- /dev/null +++ b/src/mappers/mapper252.c @@ -0,0 +1,100 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2009 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "vrc2and4.h" + +static uint8 *CHRRAM = NULL; +static uint32 CHRRAMSIZE; + +static uint8 maskCHRCompare; +static uint8 maskCHRBank; + +static writefunc writePPU; +extern uint32 RefreshAddr; + +static void M252PW(uint32 A, uint8 V) { + setprg8(A, V & 0x1F); +} + +static void M252CW(uint32 A, uint32 V) { + if ((V & maskCHRBank) == maskCHRCompare) { + setchr1r(0x10, A, V & 0x01); + } else { + setchr1(A, V); + } +} + +static DECLFW(M252PPU_B2007) { + if (RefreshAddr < 0x2000) { + switch (vrc24.chr[RefreshAddr >> 10]) { + case 0x88: + maskCHRBank = 0xFC; + maskCHRCompare = 0x4C; + break; + case 0xC2: + maskCHRBank = 0xFE; + maskCHRCompare = 0x7C; + break; + case 0xC8: + maskCHRBank = 0xFE; + maskCHRCompare = 0x04; + break; + } + } + writePPU(A, V); +} + +static void M252Close(void) { + VRC24_Close(); + if (CHRRAM) { + FCEU_free(CHRRAM); + CHRRAM = NULL; + } +} + +static void M252Power(void) { + if (iNESCart.mapper == 252) { + maskCHRBank = 0xFE; + maskCHRCompare = 0x06; + } else { + maskCHRBank = 0xFE; + maskCHRCompare = 0x04; + } + VRC24_Power(); + + writePPU = GetWriteHandler(0x2007); + SetWriteHandler(0x2007, 0x2007, M252PPU_B2007); +} + +void Mapper252_Init(CartInfo *info) { + VRC24_Init(info, VRC4, 0x04, 0x08, TRUE, TRUE); + VRC24_pwrap = M252PW; + VRC24_cwrap = M252CW; + + info->Power = M252Power; + info->Close = M252Close; + + CHRRAMSIZE = 2048; + CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CRAM"); +} diff --git a/src/mappers/mapper254.c b/src/mappers/mapper254.c new file mode 100644 index 000000000..867171dc0 --- /dev/null +++ b/src/mappers/mapper254.c @@ -0,0 +1,58 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 reg; + +static DECLFR(M254ReadWRAM) { + if (reg == TRUE) { + return cpu.openbus ^ (reg * 0x80); + } + return CartBR(A); +} + +static DECLFW(M254WriteWRAM) { + if (V & 0x01) { + reg = FALSE; + } + CartBW(A, V); +} + +static void M254Reset(void) { + reg = TRUE; + MMC3_FixCHR(); + MMC3_FixPRG(); +} + +static void M254Power(void) { + reg = 0x80; + MMC3_Power(); + SetReadHandler(0x6000, 0x7FFF, M254ReadWRAM); + SetWriteHandler(0x6000, 0x7FFF, M254WriteWRAM); +} + +void Mapper254_Init(CartInfo *info) { + MMC3_Init(info, 8, info->battery); + info->Power = M254Power; + info->Reset = M254Reset; + AddExState(®, 1, 0, "EXPR"); +} diff --git a/src/boards/onebus.c b/src/mappers/mapper256.c similarity index 92% rename from src/boards/onebus.c rename to src/mappers/mapper256.c index 0e3374036..8c13f068a 100644 --- a/src/boards/onebus.c +++ b/src/mappers/mapper256.c @@ -64,8 +64,6 @@ static SFORMAT StateRegs[] = { 0 } }; -static uint8 *WRAM; - static void PSync(void) { uint8 bankmode = cpu410x[0xb] & 7; uint8 mask = (bankmode == 0x7) ? (0xff) : (0x3f >> bankmode); @@ -111,11 +109,11 @@ static void CSync(void) { setchr1(0x0000 ^ cswap, block | (bank0 & mask)); setchr1(0x0400 ^ cswap, block | (bank1 & mask)); setchr1(0x0800 ^ cswap, block | (bank2 & mask)); - setchr1(0x0c00 ^ cswap, block | (bank3 & mask)); + setchr1(0x0C00 ^ cswap, block | (bank3 & mask)); setchr1(0x1000 ^ cswap, block | (bank4 & mask)); setchr1(0x1400 ^ cswap, block | (bank5 & mask)); setchr1(0x1800 ^ cswap, block | (bank6 & mask)); - setchr1(0x1c00 ^ cswap, block | (bank7 & mask)); + setchr1(0x1C00 ^ cswap, block | (bank7 & mask)); setmirror((mirror ^ 1) & 1); } @@ -143,7 +141,7 @@ static const uint8 cpuMangle[16][4] = { { 0, 1, 2, 3 }, /* Submapper E: Karaoto (CPU opcode encryption only) */ { 0, 1, 2, 3 } /* Submapper F: Jungletac (CPU opcode encryption only) */ }; -static DECLFW(UNLOneBusWriteCPU410X) { +static DECLFW(M256WriteCPU410X) { /* FCEU_printf("CPU %04x:%04x\n",A,V); */ A &= 0xF; switch (A) { @@ -186,7 +184,7 @@ static const uint8 ppuMangle[16][6] = { { 0, 1, 2, 3, 4, 5 }, /* Submapper E: Karaoto (CPU opcode encryption only) */ { 0, 1, 2, 3, 4, 5 } /* Submapper F: Jungletac (CPU opcode encryption only) */ }; -static DECLFW(UNLOneBusWritePPU201X) { +static DECLFW(M256WritePPU201X) { /* FCEU_printf("PPU %04x:%04x\n",A,V); */ A &= 0x0F; if (A >= 2 && A <= 7) @@ -213,7 +211,7 @@ static const uint8 mmc3Mangle[16][8] = { { 0, 1, 2, 3, 4, 5, 6, 7 }, /* Submapper E: Karaoto (CPU opcode encryption only) */ { 0, 1, 2, 3, 4, 5, 6, 7 } /* Submapper F: Jungletac (CPU opcode encryption only) */ }; -static DECLFW(UNLOneBusWriteMMC3) { +static DECLFW(M256WriteMMC3) { /* FCEU_printf("MMC %04x:%04x\n",A,V); */ switch (A & 0xe001) { case 0x8000: @@ -278,7 +276,7 @@ static DECLFW(UNLOneBusWriteMMC3) { } } -static void UNLOneBusIRQHook(void) { +static void M256IRQHook(void) { uint32 count = IRQCount; if (!count || IRQReload) { IRQCount = IRQLatch; @@ -291,7 +289,7 @@ static void UNLOneBusIRQHook(void) { } } -static DECLFW(UNLOneBusWriteAPU40XX) { +static DECLFW(M256WriteAPU40XX) { /* if(((A & 0x3f)!=0x16) && ((apu40xx[0x30] & 0x10) || ((A & 0x3f)>0x17)))FCEU_printf("APU %04x:%04x\n",A,V); */ apu40xx[A & 0x3f] = V; switch (A & 0x3f) { @@ -321,7 +319,7 @@ static DECLFW(UNLOneBusWriteAPU40XX) { defapuwrite[A & 0x3f](A, V); } -static DECLFR(UNLOneBusReadAPU40XX) { +static DECLFR(M256ReadAPU40XX) { uint8 result = defapuread[A & 0x3f](A); /* FCEU_printf("read %04x, %02x\n",A,result); */ switch (A & 0x3f) { @@ -334,7 +332,7 @@ static DECLFR(UNLOneBusReadAPU40XX) { return result; } -static void UNLOneBusCpuHook(int a) { +static void M256CpuHook(int a) { if (pcm_enable) { pcm_latch -= a; if (pcm_latch <= 0) { @@ -355,7 +353,7 @@ static void UNLOneBusCpuHook(int a) { } } -static void UNLOneBusPower(void) { +static void M256Power(void) { uint32 i; IRQReload = IRQCount = IRQa = 0; @@ -369,21 +367,21 @@ static void UNLOneBusPower(void) { defapuread[i] = GetReadHandler(0x4000 | i); defapuwrite[i] = GetWriteHandler(0x4000 | i); } - SetReadHandler(0x4000, 0x403f, UNLOneBusReadAPU40XX); - SetWriteHandler(0x4000, 0x403f, UNLOneBusWriteAPU40XX); + SetReadHandler(0x4000, 0x403f, M256ReadAPU40XX); + SetWriteHandler(0x4000, 0x403f, M256WriteAPU40XX); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetWriteHandler(0x2010, 0x201f, UNLOneBusWritePPU201X); - SetWriteHandler(0x4100, 0x410f, UNLOneBusWriteCPU410X); - SetWriteHandler(0x8000, 0xffff, UNLOneBusWriteMMC3); + SetWriteHandler(0x2010, 0x201f, M256WritePPU201X); + SetWriteHandler(0x4100, 0x410f, M256WriteCPU410X); + SetWriteHandler(0x8000, 0xffff, M256WriteMMC3); FCEU_CheatAddRAM(8, 0x6000, WRAM); setprg8r(0x10, 0x6000, 0); Sync(); } -static void UNLOneBusReset(void) { +static void M256Reset(void) { IRQReload = IRQCount = IRQa = 0; memset(cpu410x, 0x00, sizeof(cpu410x)); @@ -397,26 +395,23 @@ static void StateRestore(int version) { Sync(); } -void UNLOneBus_Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; +static void M256Close(void) { } -void UNLOneBus_Init(CartInfo *info) { - info->Power = UNLOneBusPower; - info->Reset = UNLOneBusReset; - info->Close = UNLOneBus_Close; +void Mapper256_Init(CartInfo *info) { + info->Power = M256Power; + info->Reset = M256Reset; + info->Close = M256Close; if (info->iNES2) submapper = info->submapper; else submapper = (((*(uint32 *)&(info->MD5)) == 0x305fcdc3) || ((*(uint32 *)&(info->MD5)) == 0x6abfce8e)) ? 2 : 0; /* PowerJoy Supermax Carts */ - GameHBIRQHook = UNLOneBusIRQHook; - MapIRQHook = UNLOneBusCpuHook; + GameHBIRQHook = M256IRQHook; + MapIRQHook = M256CpuHook; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); WRAM = (uint8 *)FCEU_gmalloc(8192); SetupCartPRGMapping(0x10, WRAM, 8192, 1); diff --git a/src/boards/pec-586.c b/src/mappers/mapper257.c similarity index 83% rename from src/boards/pec-586.c rename to src/mappers/mapper257.c index 536905dca..cb2e1a566 100644 --- a/src/boards/pec-586.c +++ b/src/mappers/mapper257.c @@ -22,8 +22,6 @@ static uint8 reg[8]; static uint32 lastnt = 0; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; static SFORMAT StateRegs[] = { @@ -68,26 +66,26 @@ static void Sync(void) { } } -static DECLFW(UNLPEC586Write) { +static DECLFW(M257Write) { reg[(A & 0x700) >> 8] = V; - PEC586Hack = (reg[0] & 0x80) >> 7; + PEC586Hack = (reg[0] & 0x80) ? TRUE : FALSE; /* FCEU_printf("bs %04x %02x\n", A, V); */ Sync(); } -static DECLFR(UNLPEC586Read) { +static DECLFR(M257Read) { /* FCEU_printf("read %04x\n", A); */ - return (X.DB & 0xD8) | br_tbl[reg[4] >> 4]; + return (cpu.openbus & 0xD8) | br_tbl[reg[4] >> 4]; } -static DECLFR(UNLPEC586ReadHi) { +static DECLFR(M257ReadHi) { if((reg[0] & 0x10) || ((reg[0] & 0x40) && (A < 0xA000))) return CartBR(A); else return PRGptr[0][((0x0107 | ((A >> 7) & 0x0F8)) << 10) | (A & 0x3FF)]; } -static void UNLPEC586Power(void) { +static void M257Power(void) { if(PRGsize[0] == 512 * 1024) reg[0] = 0x00; else @@ -96,27 +94,24 @@ static void UNLPEC586Power(void) { SetReadHandler(0x6000, 0x7FFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); if(PRGsize[0] == 512 * 1024) - SetReadHandler(0x8000, 0xFFFF, UNLPEC586ReadHi); + SetReadHandler(0x8000, 0xFFFF, M257ReadHi); else SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x5000, 0x5fff, UNLPEC586Write); - SetReadHandler(0x5000, 0x5fff, UNLPEC586Read); + SetWriteHandler(0x5000, 0x5fff, M257Write); + SetReadHandler(0x5000, 0x5fff, M257Read); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } -static void UNLPEC586Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; +static void M257Close(void) { } static void StateRestore(int version) { Sync(); } -void UNLPEC586Init(CartInfo *info) { - info->Power = UNLPEC586Power; - info->Close = UNLPEC586Close; +void Mapper257_Init(CartInfo *info) { + info->Power = M257Power; + info->Close = M257Close; GameStateRestore = StateRestore; WRAMSIZE = 8192; @@ -124,5 +119,5 @@ void UNLPEC586Init(CartInfo *info) { SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/f-15.c b/src/mappers/mapper259.c similarity index 66% rename from src/boards/f-15.c rename to src/mappers/mapper259.c index 84c612fd3..243e1a995 100644 --- a/src/boards/f-15.c +++ b/src/mappers/mapper259.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2015 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -17,6 +18,7 @@ * 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 259 - BMC-F-15 * BMC F-15 PCB (256+266 MMC3 based, with 16/32Kb banking discrete logic) * 150-in-1 Unchaied Melody FIGHT version with system test (START+SELECT) * @@ -33,29 +35,36 @@ #include "mapinc.h" #include "mmc3.h" -static void BMCF15PW(uint32 A, uint8 V) { - uint32 bank = mmc3.expregs[0] & 0xF; - uint32 mode = (mmc3.expregs[0] & 8) >> 3; - uint32 mask = ~(mode); - setprg16(0x8000, (bank & mask)); - setprg16(0xC000, (bank & mask) | mode); +static uint8 reg; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; + +static void M259PW(uint32 A, uint8 V) { + uint8 mode = (reg & 0x08) >> 3; + + setprg16(0x8000, ((reg & 0x0F) & ~mode)); + setprg16(0xC000, ((reg & 0x0F) | mode)); } -static DECLFW(BMCF15Write) { - if (MMC3CanWriteToWRAM()) { - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); +static DECLFW(M259Write) { + if (MMC3_WramIsWritable()) { + reg = V; + MMC3_FixPRG(); } } -static void BMCF15Power(void) { - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, BMCF15Write); +static void M259Power(void) { + reg = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M259Write); } -void BMCF15_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 0, 0); - mmc3.pwrap = BMCF15PW; - info->Power = BMCF15Power; - AddExState(mmc3.expregs, 1, 0, "EXPR"); +void Mapper259_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_pwrap = M259PW; + info->Power = M259Power; + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper260.c b/src/mappers/mapper260.c new file mode 100644 index 000000000..507df619f --- /dev/null +++ b/src/mappers/mapper260.c @@ -0,0 +1,119 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2017 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +/* 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 reg[4]; +static uint8 dipsw; + +static SFORMAT StateRegs[] = { + { reg, 4, "REGS" }, + { &dipsw, 1, "DPSW" }, + { 0 } +}; + +static void M260CW(uint32 A, uint8 V) { + uint16 base = reg[2] & 0x7F; + + switch (reg[0] & 0x07) { + case 0: setchr1(A, ((base << 3) & ~0xFF) | (V & 0xFF)); break; + case 1: setchr1(A, ((base << 3) & ~0x7F) | (V & 0x7F)); break; + case 2: setchr1(A, ((base << 3) & ~0xFF) | (V & 0xFF)); break; + case 3: setchr1(A, ((base << 3) & ~0x7F) | (V & 0x7F)); break; + case 4: setchr8(base); break; + case 5: setchr8(base); break; + case 6: setchr8((base & ~0x01) | (reg[3] & 0x01)); break; + case 7: setchr8((base & ~0x03) | (reg[3] & 0x03)); break; + } +} + +static void M260PW(uint32 A, uint8 V) { + uint8 base = reg[1] & 0x3F; + + switch (reg[0] & 0x07) { + case 0: setprg8(A, ((base << 1) & ~0x1F) | (V & 0x1F)); break; + case 1: setprg8(A, ((base << 1) & ~0x1F) | (V & 0x1F)); break; + case 2: setprg8(A, ((base << 1) & ~0x0F) | (V & 0x0F)); break; + case 3: setprg8(A, ((base << 1) & ~0x0F) | (V & 0x0F)); break; + case 4: + setprg16(0x8000, base); + setprg16(0xC000, base); + break; + case 5: setprg32(0x8000, base >> 1); break; + case 6: setprg32(0x8000, base >> 1); break; + case 7: setprg32(0x8000, base >> 1); break; + } +} + +static DECLFR(M260Read) { + return ((cpu.openbus & ~0x03) | (dipsw & 0x03)); +} + +static DECLFW(M260WriteReg) { + if (!(reg[0] & 0x80)) { + reg[A & 0x03] = V; + MMC3_FixPRG(); + MMC3_FixCHR(); + } +} + +static DECLFW(M260WriteLatch) { + if((reg[0] & 0xE6) == 0x06 ) { + reg[3] = V; + MMC3_FixCHR(); + } else { + MMC3_Write(A, V); + } +} + +static void M260Reset(void) { + dipsw++; + reg[0] = reg[1] = reg[2] = reg[3] = 0; + MMC3_Reset(); + MMC3_FixPRG(); + MMC3_FixCHR(); +} + +static void M260Power(void) { + dipsw = 0; + reg[0] = reg[1] = reg[2] = reg[3] = 0; + MMC3_Power(); + SetReadHandler(0x5000, 0x5FFF, M260Read); + SetWriteHandler(0x5000, 0x5FFF, M260WriteReg); + SetWriteHandler(0x8000, 0xFFFF, M260WriteLatch); +} + +void Mapper260_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_cwrap = M260CW; + MMC3_pwrap = M260PW; + info->Power = M260Power; + info->Reset = M260Reset; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper261.c b/src/mappers/mapper261.c new file mode 100644 index 000000000..589741dc8 --- /dev/null +++ b/src/mappers/mapper261.c @@ -0,0 +1,40 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 261 - BMC810544-C-A1 */ + +#include "mapinc.h" +#include "latch.h" + +static void Sync(void) { + if (latch.addr & 0x40) + setprg32(0x8000, latch.addr >> 7); + else { + setprg16(0x8000, ((latch.addr >> 6) & 0x0E) | ((latch.addr >> 5) & 0x01)); + setprg16(0xC000, ((latch.addr >> 6) & 0x0E) | ((latch.addr >> 5) & 0x01)); + } + setchr8(latch.addr & 0x0F); + setmirror(((latch.addr >> 4) & 0x01) ^ 0x01); +} + +void Mapper261_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); +} diff --git a/src/mappers/mapper262.c b/src/mappers/mapper262.c new file mode 100644 index 000000000..a4d346a21 --- /dev/null +++ b/src/mappers/mapper262.c @@ -0,0 +1,94 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2006 CaH4e3 + * Copyright (C) 2023 + * + * 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 262 - UNL-SHERO */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 reg; +static uint8 dipsw; + +static uint8 *CHRRAM; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { &dipsw, 1, "DPSW" }, + { 0 } +}; + +static void M262CW(uint32 A, uint8 V) { + if (reg & 0x40) { + setchr8r(0x10, 0); + } else { + uint8 lsh[] = { 3, 2, 0, 1 }; + uint8 bank = (A >> 11) & 0x03; + + setchr1(A, (((reg >> lsh[bank]) << 8) & 0x100) | (V & 0xFF)); + } +} + +static DECLFW(M262Write) { + if (A & 0x100) { + reg = V; + MMC3_FixCHR(); + } +} + +static DECLFR(M262Read) { + if (A & 0x100) { + return(dipsw); + } + return cpu.openbus; +} + +static void M262Reset(void) { + MMC3_Reset(); + dipsw ^= 0xFF; +} + +static void M262Power(void) { + dipsw = 0x00; + MMC3_Power(); + SetWriteHandler(0x4100, 0x4FFF, M262Write); + SetReadHandler(0x4100, 0x4FFF, M262Read); +} + +static void M262Close(void) { + MMC3_Close(); + if (CHRRAM) { + FCEU_gfree(CHRRAM); + } + CHRRAM = NULL; +} + +void Mapper262_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_cwrap = M262CW; + info->Power = M262Power; + info->Reset = M262Reset; + info->Close = M262Close; + AddExState(StateRegs, ~0, 0, NULL); + + CHRRAM = (uint8*)FCEU_gmalloc(8192); + SetupCartCHRMapping(0x10, CHRRAM, 8192, 1); + AddExState(CHRRAM, 8192, 0, "CHRR"); +} diff --git a/src/boards/kof97.c b/src/mappers/mapper263.c similarity index 61% rename from src/boards/kof97.c rename to src/mappers/mapper263.c index 565311d5c..053033b95 100644 --- a/src/boards/kof97.c +++ b/src/mappers/mapper263.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -24,28 +25,23 @@ #include "mmc3.h" static uint32 unscrambleAddr(uint32 A) { - return ((A & 0xE000) | ((A >> 12) & 1)); + return ((A & 0xE000) | ((A >> 12) & 0x01)); } static uint8 unscrambleData(uint8 V) { - return ((V & 0xD8) | ((V & 0x20) >> 4) | ((V & 4) << 3) | ((V & 2) >> 1) | ((V & 1) << 2)); + return ((V & 0xD8) | ((V & 0x20) >> 4) | ((V & 0x04) << 3) | ((V & 0x02) >> 1) | ((V & 0x01) << 2)); } -static DECLFW(UNLKOF97CMDWrite) { - MMC3_CMDWrite(unscrambleAddr(A), unscrambleData(V)); +static DECLFW(M263Write) { + MMC3_Write(unscrambleAddr(A), unscrambleData(V)); } -static DECLFW(UNLKOF97IRQWrite) { - MMC3_IRQWrite(unscrambleAddr(A), unscrambleData(V)); +static void M263Power(void) { + MMC3_Power(); + SetWriteHandler(0x8000, 0xFFFF, M263Write); } -static void UNLKOF97Power(void) { - GenMMC3Power(); - SetWriteHandler(0x8000, 0xA000, UNLKOF97CMDWrite); - SetWriteHandler(0xC000, 0xF000, UNLKOF97IRQWrite); -} - -void UNLKOF97_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 256, 0, 0); - info->Power = UNLKOF97Power; +void Mapper263_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + info->Power = M263Power; } diff --git a/src/boards/t-262.c b/src/mappers/mapper265.c similarity index 52% rename from src/boards/t-262.c rename to src/mappers/mapper265.c index 5dd65dfe8..c8188af0c 100644 --- a/src/boards/t-262.c +++ b/src/mappers/mapper265.c @@ -1,8 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2006 CaH4e3 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -19,38 +19,47 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +/* NES 2.0 Mapper 265 - BMC-T-262 */ + #include "mapinc.h" #include "latch.h" static void Sync(void) { - uint32 bank = ((latch.addr >> 3) & 0xE0) | ((latch.addr >> 2) & 0x18) | (latch.data & 7); + uint8 bank = ((latch.addr >> 3) & 0x60) | ((latch.addr >> 2) & 0x18) | (latch.data & 0x07); + if (latch.addr & 0x80) { - setprg16(0x8000, bank & ~1); - setprg16(0xC000, bank | 1); + if (!bank) { + /* NOTE: Unofficial support but Tetris II in 11-in-1 variant + works as if its NROM-256 */ + setprg32(0x8000, bank >> 1); + } else { + setprg16(0x8000, bank); + setprg16(0xC000, bank); + } } else { setprg16(0x8000, bank); - setprg16(0xC000, bank | 7); + setprg16(0xC000, bank | 0x07); } setchr8(0); - setmirror(((latch.addr >> 1) & 1) ^ 1); + setmirror(((latch.addr >> 1) & 0x01) ^ 0x01); } -static DECLFW(BMCT262Write) { - if (latch.addr & 0x2000) { - latch.data = V; - Sync(); - } else { - LatchWrite(A, V); +static DECLFW(M265Write) { + if (!(latch.addr & 0x2000)) { + latch.addr = A; } + latch.data = V; + Sync(); } -static void BMCT262Power(void) { - LatchPower(); - SetWriteHandler(0x8000, 0xFFFF, BMCT262Write); +static void M265Power(void) { + Latch_Power(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M265Write); } -void BMCT262_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); - info->Power = BMCT262Power; - info->Reset = LatchHardReset; +void Mapper265_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Power = M265Power; + info->Reset = Latch_RegReset; } diff --git a/src/boards/cityfighter.c b/src/mappers/mapper266.c similarity index 50% rename from src/boards/cityfighter.c rename to src/mappers/mapper266.c index a09a44c78..31dc33569 100644 --- a/src/boards/cityfighter.c +++ b/src/mappers/mapper266.c @@ -1,8 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2007 CaH4e3 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,49 +22,46 @@ */ #include "mapinc.h" -#include "vrc24.h" +#include "vrc2and4.h" -static uint8 prg_reg; -static writefunc pcmwrite; +static uint8 reg; +static writefunc pcm; -static SFORMAT StateRegs[] = -{ - { &prg_reg, 1, "PREG" }, +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, { 0 } }; -static void UNLCITYFIGHTPW(uint32 A, uint8 V) { - setprg32(0x8000, prg_reg >> 2); +static void M266PW(uint32 A, uint8 V) { + setprg32(0x8000, reg >> 2); } -static DECLFW(UNLCITYFIGHTWrite) { +static DECLFW(M266Write) { /* FCEU_printf("%04x %02x",A,V); */ - switch (A & 0xF00C) { - case 0x900C: - if (A & 0x800) { - pcmwrite(0x4011, (V & 0xf) << 3); - } else { - prg_reg = V & 0xC; - FixVRC24PRG(); - } - break; - default: - A = (A & ~0x6000) | ((A << 1) & 0x4000) | ((A >> 1) & 0x2000); - VRC24Write(A, V); - break; + A = (A & 0x9FFF) | ((A << 1) & 0x4000) | ((A >> 1) & 0x2000); + VRC24_Write(A, V); +} + +static DECLFW(M266WriteMisc) { + if (A & 0x800) { + pcm(0x4011, (V & 0x0F) << 3); + } else { + reg = V & 0x0C; + VRC24_FixPRG(); } } -static void UNLCITYFIGHTPower(void) { - prg_reg = 0; - GenVRC24Power(); - pcmwrite = GetWriteHandler(0x4011); - SetWriteHandler(0x8000, 0xFFFF, UNLCITYFIGHTWrite); +static void M266Power(void) { + reg = 0; + VRC24_Power(); + pcm = GetWriteHandler(0x4011); + SetWriteHandler(0x8000, 0xFFFF, M266Write); } -void UNLCITYFIGHT_Init(CartInfo *info) { - GenVRC24_Init(info, VRC4e, 0); - info->Power = UNLCITYFIGHTPower; - vrc24.pwrap = UNLCITYFIGHTPW; - AddExState(&StateRegs, ~0, 0, 0); +void Mapper266_Init(CartInfo *info) { + VRC24_Init(info, VRC4, 0x04, 0x08, FALSE, TRUE); + info->Power = M266Power; + VRC24_pwrap = M266PW; + VRC24_miscWrite = M266WriteMisc; + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper267.c b/src/mappers/mapper267.c similarity index 68% rename from src/boards/mapper267.c rename to src/mappers/mapper267.c index 5abebe108..5b6a4e61d 100644 --- a/src/boards/mapper267.c +++ b/src/mappers/mapper267.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -23,40 +24,46 @@ #include "mapinc.h" #include "mmc3.h" -#define OUTER_BANK (((mmc3.expregs[0] & 0x20) >> 2) | (mmc3.expregs[0] & 0x06)) +static uint8 reg; static void M267CW(uint32 A, uint8 V) { - setchr1(A, (V & 0x7F) | (OUTER_BANK << 6)); + uint16 base = ((reg & 0x20) >> 2) | (reg & 0x06); + + setchr1(A, (base << 6) | (V & 0x7F)); } static void M267PW(uint32 A, uint8 V) { - setprg8(A, (V & 0x1F) | (OUTER_BANK << 4)); + uint16 base = ((reg & 0x20) >> 2) | (reg & 0x06); + + setprg8(A, (base << 4) | (V & 0x1F)); } static DECLFW(M267Write) { - if (!(mmc3.expregs[0] & 0x80)) { - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + if (MMC3_WramIsWritable()) { + if (!(reg & 0x80)) { + reg = V; + MMC3_FixPRG(); + MMC3_FixCHR(); + } } } static void M267Reset(void) { - mmc3.expregs[0] = 0; - MMC3RegReset(); + reg = 0; + MMC3_Reset(); } static void M267Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, M267Write); + reg = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x6FFF, M267Write); } void Mapper267_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 128, 0, 0); - mmc3.cwrap = M267CW; - mmc3.pwrap = M267PW; + MMC3_Init(info, 0, 0); + MMC3_cwrap = M267CW; + MMC3_pwrap = M267PW; info->Reset = M267Reset; info->Power = M267Power; - AddExState(mmc3.expregs, 1, 0, "EXPR"); + AddExState(®, 1, 0, "EXPR"); } diff --git a/src/mappers/mapper268.c b/src/mappers/mapper268.c new file mode 100644 index 000000000..4faf30326 --- /dev/null +++ b/src/mappers/mapper268.c @@ -0,0 +1,182 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 reg[8]; + +static uint8 *CHRRAM = NULL; +static uint32 CHRRAMSize = 0; + +static void M268CW(uint32 A, uint8 V) { + uint16 base = ((reg[0] << 4) & 0x380) | ((reg[2] << 3) & 0x078); + uint16 mask = (reg[0] & 0x80) ? 0x7F : 0xFF; + uint8 ram = CHRRAM && (reg[4] & 0x01) && ((V & 0xFE) == (reg[4] & 0xFE)); + + /* CHR-RAM write protect on submapper 8/9) */ + if ((iNESCart.submapper & ~1) == 8) { + if (reg[0] & 0x10) { + SetupCartCHRMapping(0, CHRptr[0], CHRsize[0], 0); + } else { + SetupCartCHRMapping(0, CHRptr[0], CHRsize[0], 1); + } + } + if (reg[3] & 0x10) { + /* GNROM */ + mask = 0x07; + V = A >> 10; + } + setchr1r(ram ? 0x10 : 0x00, A, (base & ~mask) | (V & mask)); +} + +static void M268PW(uint32 A, uint8 V) { + uint16 base; + uint16 mask = 0x0F /* PRG A13-A16 */ + | ((~reg[0] >> 2) & 0x10) /* PRG A17 */ + | ((~reg[1] >> 2) & 0x20) /* PRG A18 */ + | ((reg[1] >> 0) & 0x40) /* PRG A19 */ + | ((reg[1] << 2) & 0x80) /* PRG A20 */ + ; + + switch (iNESCart.submapper & ~1) { + default: /* Original implementation */ + base = (reg[3] & 0x0E) | ((reg[0] << 4) & 0x70) | ((reg[1] << 3) & 0x80) | + ((reg[1] << 6) & 0x300) | ((reg[0] << 6) & 0xC00); + break; + case 2: /* Later revision with different arrangement of register 1 */ + base = (reg[3] & 0x0E) | ((reg[0] << 4) & 0x70) | ((reg[1] << 4) & 0x80) | + ((reg[1] << 6) & 0x100) | ((reg[1] << 8) & 0x200) | ((reg[0] << 6) & 0xC00); + break; + case 4: /* LD622D: PRG A20-21 moved to register 0 */ + base = (reg[3] & 0x0E) | ((reg[0] << 4) & 0x70) | ((reg[0] << 3) & 0x180); + break; + case 6: /* J-852C: CHR A17 selects between two PRG chips */ + base = (reg[3] & 0x0E) | ((reg[0] << 4) & 0x70) | ((reg[1] << 3) & 0x80) | + ((reg[1] << 6) & 0x300) | ((reg[0] << 6) & 0xC00); + base &= ROM.prg.size - 1; + if ((reg[0] & 0x80) ? !!(reg[0] & 0x08) : !!(mmc3.reg[0] & 0x80)) { + base |= ROM.prg.size; + } + break; + } + if (reg[3] & 0x10) { + /* GNROM */ + switch (iNESCart.submapper & ~1) { + default: + mask = (reg[1] & 0x02) ? 0x03 : 0x01; + break; + case 2: + mask = (reg[1] & 0x10) ? 0x01 : 0x03; + break; + } + V = A >> 13; + } + setprg8(A, (base & ~mask) | (V & mask)); +} + +static DECLFR(M268WramRead) { + if (MMC3_WramIsWritable() || (mmc3.wram & 0x20)) { + return CartBR(A); + } + return cpu.openbus; +} + +static DECLFW(M268WramWrite) { + if (MMC3_WramIsWritable() || (mmc3.wram & 0x20)) { + CartBW(A, V); + } +} + +static DECLFW(M268Write) { + uint8 index = A & 0x07; + + if (!(iNESCart.submapper & 0x01)) { + M268WramWrite(A, V); + } + if (!(reg[3] & 0x80) || (index == 2)) { + if (index == 2) { + if (reg[2] & 0x80) { + V = (V & 0x0F) | (reg[2] & ~0x0F); + } + V &= ((~reg[2] >> 3) & 0x0E) | 0xF1; + } + reg[index] = V; + MMC3_FixPRG(); + MMC3_FixCHR(); + } +} + +static void M268Reset(void) { + reg[0] = reg[1] = reg[2] = reg[3] = 0x00; + reg[4] = reg[5] = reg[6] = reg[7] = 0x00; + MMC3_Reset(); +} + +static void M268Power(void) { + reg[0] = reg[1] = reg[2] = reg[3] = 0x00; + reg[4] = reg[5] = reg[6] = reg[7] = 0x00; + MMC3_Power(); + SetReadHandler(0x6000, 0x7FFF, M268WramRead); + if (iNESCart.submapper & 1) { + SetWriteHandler(0x5000, 0x5FFF, M268Write); + } else { + SetWriteHandler(0x6000, 0x7FFF, M268Write); + } +} + +static void M268Close(void) { + MMC3_Close(); + if (CHRRAM) { + FCEU_gfree(CHRRAM); + } + CHRRAM = NULL; +} + +static void Common_Init(CartInfo *info, int _submapper) { + MMC3_Init(info, (info->PRGRamSize + info->PRGRamSaveSize) >> 10, info->battery); + if (info->submapper != _submapper) { + info->submapper = _submapper; + } + MMC3_pwrap = M268PW; + MMC3_cwrap = M268CW; + info->Power = M268Power; + info->Reset = M268Reset; + info->Close = M268Close; + CHRRAMSize = info->CHRRamSize + info->CHRRamSaveSize; + if (!UNIFchrrama && CHRRAMSize) { + CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSize); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSize, 1); + AddExState(CHRRAM, CHRRAMSize, 0x00, "CRAM"); + } + AddExState(reg, 8, 0, "EXPR"); +} + +void COOLBOY_Init(CartInfo *info) { + Common_Init(info, 0); +} + +void MINDKIDS_Init(CartInfo *info) { /* M224 */ + Common_Init(info, 1); +} + +void Mapper268_Init(CartInfo *info) { + Common_Init(info, info->submapper); +} diff --git a/src/boards/mapper269.c b/src/mappers/mapper269.c similarity index 64% rename from src/boards/mapper269.c rename to src/mappers/mapper269.c index 5446f91a6..982f0c8b5 100644 --- a/src/boards/mapper269.c +++ b/src/mappers/mapper269.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -27,38 +27,42 @@ #include "mapinc.h" #include "mmc3.h" +static uint8 reg[4]; +static uint8 cmd; + static void M269CW(uint32 A, uint8 V) { - uint32 mask = 0xFF >> (~mmc3.expregs[2] & 0xF); - uint32 base = ((mmc3.expregs[2] << 4) & 0xF00) | mmc3.expregs[0]; + uint32 mask = 0xFF >> (~reg[2] & 0xF); + uint32 base = ((reg[2] << 4) & 0xF00) | reg[0]; + setchr1(A, (base & ~mask) | (V & mask)); } static void M269PW(uint32 A, uint8 V) { - uint32 mask = ~mmc3.expregs[3] & 0x3F; - uint32 base = ((mmc3.expregs[2] << 2) & 0x300) | mmc3.expregs[1]; + uint32 mask = ~reg[3] & 0x3F; + uint32 base = ((reg[2] << 2) & 0x300) | reg[1]; + setprg8(A, (base & ~mask) | (V & mask)); } static DECLFW(M269Write5) { - CartBW(A, V); - if (!(mmc3.expregs[3] & 0x80)) { - mmc3.expregs[mmc3.expregs[4]] = V; - mmc3.expregs[4] = (mmc3.expregs[4] + 1) & 3; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + if (!(reg[3] & 0x80)) { + reg[cmd] = V; + cmd = (cmd + 1) & 3; + MMC3_FixPRG(); + MMC3_FixCHR(); } } static void M269Reset(void) { - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[3] = mmc3.expregs[4] = 0; - mmc3.expregs[2] = 0x0F; - MMC3RegReset(); + reg[0] = reg[1] = reg[3] = cmd = 0; + reg[2] = 0x0F; + MMC3_Reset(); } static void M269Power(void) { - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[3] = mmc3.expregs[4] = 0; - mmc3.expregs[2] = 0x0F; - GenMMC3Power(); + reg[0] = reg[1] = reg[3] = cmd = 0; + reg[2] = 0x0F; + MMC3_Power(); SetWriteHandler(0x5000, 0x5FFF, M269Write5); } @@ -68,23 +72,24 @@ static uint8 unscrambleCHR(uint8 data) { } void Mapper269_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 0, 8, 0); - mmc3.cwrap = M269CW; - mmc3.pwrap = M269PW; + MMC3_Init(info, 8, 0); + MMC3_cwrap = M269CW; + MMC3_pwrap = M269PW; info->Power = M269Power; info->Reset = M269Reset; - AddExState(mmc3.expregs, 5, 0, "EXPR"); + AddExState(reg, 4, 0, "EXPR"); + AddExState(&cmd, 1, 0, "CMD0"); if (UNIFchrrama) { uint32 i; - if (VROM) { - FCEU_free(VROM); + if (ROM.chr.data) { + FCEU_free(ROM.chr.data); } - VROM = (uint8*)FCEU_malloc(PRGsize[0]); + ROM.chr.data = (uint8*)FCEU_malloc(PRGsize[0]); /* unscramble CHR data from PRG */ for (i = 0; i < PRGsize[0]; i++) { - VROM[i] = unscrambleCHR(ROM[i]); + ROM.chr.data[i] = unscrambleCHR(ROM.prg.data[i]); } - SetupCartCHRMapping(0, VROM, PRGsize[0], 0); + SetupCartCHRMapping(0, ROM.chr.data, PRGsize[0], 0); } } diff --git a/src/mappers/mapper271.c b/src/mappers/mapper271.c new file mode 100644 index 000000000..2b3448409 --- /dev/null +++ b/src/mappers/mapper271.c @@ -0,0 +1,33 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg32(0x8000, latch.data >> 4); + setchr8(latch.data & 0x0F); + setmirror((latch.data >> 5) & 0x01); +} + +void Mapper271_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); +} diff --git a/src/mappers/mapper272.c b/src/mappers/mapper272.c new file mode 100644 index 000000000..fd0732dee --- /dev/null +++ b/src/mappers/mapper272.c @@ -0,0 +1,162 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2022 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 272 is used for a bootleg implementation of + * 悪魔城 Special: ぼくDracula君 (Akumajō Special: Boku Dracula-kun). + * + * as implemented from + * https://forums.nesdev.org/viewtopic.php?f=9&t=15302&start=60#p205862 + * + */ + +#include "mapinc.h" + +static uint8 prg[2]; +static uint8 chr[8]; +static uint8 mirr; +static uint8 pal_mirr; +static uint8 IRQCount; +static uint8 IRQa; + +static uint16 lastAddr; + +static SFORMAT StateRegs[] = { + { prg, 2, "PREG" }, + { chr, 8, "CREG" }, + { &mirr, 1, "MIRR" }, + { &pal_mirr, 1, "PALM" }, + { &IRQCount, 1, "CNTR" }, + { &IRQa, 1, "CCLK" }, + { &lastAddr, 1, "LADR" }, + { 0 } +}; + +static void Sync(void) { + setprg8(0x8000, prg[0]); + setprg8(0xA000, prg[1]); + setprg16(0xC000, ~0); + + setchr1(0x0000, chr[0]); + setchr1(0x0400, chr[1]); + setchr1(0x0800, chr[2]); + setchr1(0x0C00, chr[3]); + setchr1(0x1000, chr[4]); + setchr1(0x1400, chr[5]); + setchr1(0x1800, chr[6]); + setchr1(0x1C00, chr[7]); + + if (pal_mirr & 0x02) { + setmirror(MI_0 + (pal_mirr & 0x01)); + } else { + setmirror((mirr & 0x01) ^ 0x01); + } +} + +static DECLFW(M272Write) { + /* writes to VRC chip */ + switch (A & 0xF000) { + case 0x8000: + prg[0] = V; + break; + case 0x9000: + mirr = V; + break; + case 0xA000: + prg[1] = V; + break; + case 0xB000: + case 0xC000: + case 0xD000: + case 0xE000: { + int bank = (((A - 0xB000) >> 11) & 0x06) | ((A >> 1) & 0x01); + if (A & 0x01) { + chr[bank] = (chr[bank] & ~0xF0) | (V << 4); + } else { + chr[bank] = (chr[bank] & ~0x0F) | (V & 0x0F); + } + break; + } + } + + /* writes to PAL chip */ + switch (A & 0xC00C) { + case 0x8004: + pal_mirr = V; + break; + case 0x800c: + X6502_IRQBegin(FCEU_IQEXT); + break; + case 0xc004: + X6502_IRQEnd(FCEU_IQEXT); + break; + case 0xc008: + IRQa = 1; + break; + case 0xc00c: + IRQa = 0; + IRQCount = 0; + X6502_IRQEnd(FCEU_IQEXT); + break; + } + + Sync(); +} + +static void M272Reset(void) { + prg[0] = prg[1] = 0; + chr[0] = chr[1] = chr[2] = chr[3] = 0; + chr[4] = chr[5] = chr[6] = chr[7] = 0; + mirr = pal_mirr = 0; + lastAddr = 0; + IRQCount = 0; + IRQa = 0; + Sync(); +} + +static void M272Power(void) { + M272Reset(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M272Write); +} + +static void M272Hook(uint32 A) { + if ((lastAddr & 0x2000) && !(A & 0x2000)) { + if (IRQa) { + IRQCount++; + if (IRQCount == 84) { + IRQCount = 0; + X6502_IRQBegin(FCEU_IQEXT); + } + } + } + lastAddr = A; +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper272_Init(CartInfo *info) { + info->Power = M272Power; + info->Reset = M272Reset; + PPU_hook = M272Hook; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/bmc80013b.c b/src/mappers/mapper274.c similarity index 55% rename from src/boards/bmc80013b.c rename to src/mappers/mapper274.c index f10e875e2..a321f6feb 100644 --- a/src/boards/bmc80013b.c +++ b/src/mappers/mapper274.c @@ -1,6 +1,8 @@ /* FCEUmm - NES/Famicom Emulator * - * Copyright (C) 2019 Libretro Team + * Copyright notice for this file: + * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent * * 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,59 +27,58 @@ #include "mapinc.h" -static uint8 regs[2], extra_chip; +static uint8 reg[2], extraChip; -static SFORMAT StateRegs[] = -{ - { regs, 2, "REGS" }, - { &extra_chip, 1, "XTRA" }, +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, + { &extraChip, 1, "CHIP" }, { 0 } }; static void Sync(void) { - if (extra_chip) { - setprg16(0x8000, 0x80 | (regs[0] & ((ROM_size - 1) & 0x0F))); + if (extraChip) { + setprg16(0x8000, 0x80 | (reg[0] & ((ROM.prg.size - 1) & 0x0F))); } else { - setprg16(0x8000, (regs[1] & 0x70) | (regs[0] & 0x0F)); + setprg16(0x8000, (reg[1] & 0x70) | (reg[0] & 0x0F)); } - setprg16(0xC000, regs[1] & 0x7F); + setprg16(0xC000, reg[1] & 0x7F); setchr8(0); - setmirror(((regs[0] >> 4) & 1) ^ 1); + setmirror(((reg[0] >> 4) & 0x01) ^ 0x01); } -static DECLFW(BMC80013BWrite8) { - regs[0] = V; +static DECLFW(M274Write8) { + reg[0] = V; Sync(); } -static DECLFW(BMC80013BWriteA) { - regs[1] = V; - extra_chip = (A & 0x4000) == 0; +static DECLFW(M274WriteA) { + reg[1] = V; + extraChip = (A & 0x4000) == 0; Sync(); } -static void BMC80013BPower(void) { - regs[0] = regs[1] = 0; - extra_chip = 1; +static void M274Power(void) { + reg[0] = reg[1] = 0; + extraChip = 1; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0x9FFF, BMC80013BWrite8); - SetWriteHandler(0xA000, 0xFFFF, BMC80013BWriteA); + SetWriteHandler(0x8000, 0x9FFF, M274Write8); + SetWriteHandler(0xA000, 0xFFFF, M274WriteA); } -static void BMC80013BReset(void) { - regs[0] = regs[1] = 0; - extra_chip = 1; +static void M274Reset(void) { + reg[0] = reg[1] = 0; + extraChip = 1; Sync(); } -static void BMC80013BRestore(int version) { +static void M274Restore(int version) { Sync(); } -void BMC80013B_Init(CartInfo *info) { - info->Power = BMC80013BPower; - info->Reset = BMC80013BReset; - GameStateRestore = BMC80013BRestore; - AddExState(&StateRegs, ~0, 0, 0); +void Mapper274_Init(CartInfo *info) { + info->Power = M274Power; + info->Reset = M274Reset; + GameStateRestore = M274Restore; + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper277.c b/src/mappers/mapper277.c similarity index 63% rename from src/boards/mapper277.c rename to src/mappers/mapper277.c index 449d4d8fc..a76640c9a 100644 --- a/src/boards/mapper277.c +++ b/src/mappers/mapper277.c @@ -1,8 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2006 CaH4e3 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -23,42 +23,45 @@ #include "latch.h" static void Sync(void) { - if (!(latch.data & 1) && (latch.data & 8)) { - setprg16(0x8000, latch.data & ~1); - setprg16(0xC000, latch.data | 1); - } else { - if (latch.data & 8) { - setprg16(0x8000, latch.data); - setprg16(0xC000, latch.data); - } else { - setprg16(0x8000, latch.data); - setprg16(0xC000, latch.data | 7); - } - } + uint8 prg = latch.data & 0x0F; + + if (latch.data & 0x08) { + if (latch.data & 0x01) { + setprg16(0x8000, prg); + setprg16(0xC000, prg); + } else { + setprg32(0x8000, prg >> 1); + } + } else { + setprg16(0x8000, prg); + setprg16(0xC000, prg | 0x07); + } setchr8(0); - setmirror(((latch.data >> 4) & 1) ^ 1); + setmirror(((latch.data >> 4) & 0x01) ^ 0x01); } static DECLFW(M277Write) { if (!(latch.data & 0x20)) { - LatchWrite(A, V); + Latch_Write(A, V); } } static void M277Power(void) { - LatchPower(); - latch.data = 8; - Sync(); + latch.addr = 0; + latch.data = 8; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBROB); SetWriteHandler(0x8000, 0xFFFF, M277Write); } -static void M277Reset() { - latch.data = 0x08; - Sync(); +static void M277Reset(void) { + latch.addr = 0; + latch.data = 8; + Sync(); } void Mapper277_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); + Latch_Init(info, Sync, NULL, FALSE, FALSE); info->Power = M277Power; info->Reset = M277Reset; } diff --git a/src/mappers/mapper281.c b/src/mappers/mapper281.c new file mode 100644 index 000000000..ac59ebda1 --- /dev/null +++ b/src/mappers/mapper281.c @@ -0,0 +1,37 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "jyasic.h" + +static uint32 GetPRGBank(uint32 V) { + return ((jyasic.mode[3] << 5) | (V & 0x1F)); +} + +static uint32 GetCHRBank(uint32 V) { + return ((jyasic.mode[3] << 8) | (V & 0xFF)); +} + +void Mapper281_Init(CartInfo *info) { + /* Multicart */ + JYASIC_Init(info, TRUE); + JYASIC_GetPRGBank = GetPRGBank; + JYASIC_GetCHRBank = GetCHRBank; +} diff --git a/src/mappers/mapper282.c b/src/mappers/mapper282.c new file mode 100644 index 000000000..11e02019e --- /dev/null +++ b/src/mappers/mapper282.c @@ -0,0 +1,41 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "jyasic.h" + +static uint32 GetPRGBank(uint32 V) { + return (((jyasic.mode[3] << 4) & ~0x1F) | (V & 0x1F)); +} + +static uint32 GetCHRBank(uint32 V) { + if (jyasic.mode[3] & 0x20) { + return (((jyasic.mode[3] << 6) & 0x600) | (V & 0x1FF)); + } else { + return (((jyasic.mode[3] << 6) & 0x600) | ((jyasic.mode[3] << 8) & 0x100) | (V & 0xFF)); + } +} + +void Mapper282_Init(CartInfo *info) { + /* Multicart */ + JYASIC_Init(info, TRUE); + JYASIC_GetPRGBank = GetPRGBank; + JYASIC_GetCHRBank = GetCHRBank; +} diff --git a/src/boards/mapper283.c b/src/mappers/mapper283.c similarity index 83% rename from src/boards/mapper283.c rename to src/mappers/mapper283.c index a6c092257..dab7874ed 100644 --- a/src/boards/mapper283.c +++ b/src/mappers/mapper283.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2007 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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,11 +22,11 @@ #include "latch.h" static void Sync(void) { - setprg8(0x6000, ((ROM_size * 16384) & 0x6000) ? 32 : 31); + setprg8(0x6000, ((ROM.prg.size * 16384) & 0x6000) ? 32 : 31); setprg32(0x8000, latch.data); setchr8(0); } void Mapper283_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 1, 0); + Latch_Init(info, Sync, NULL, TRUE, FALSE); } diff --git a/src/mappers/mapper285.c b/src/mappers/mapper285.c new file mode 100644 index 000000000..8cb88fe63 --- /dev/null +++ b/src/mappers/mapper285.c @@ -0,0 +1,58 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 285 - A65AS */ +/* actually, there is two cart in one... First have extra mirroring + * mode (one screen) and 32K bankswitching, second one have only + * 16 bankswitching mode and normal mirroring... But there is no any + * correlations between modes and they can be used in one mapper code. + * + * Submapper 0 - 3-in-1 (N068) + * Submapper 0 - 3-in-1 (N080) + * Submapper 1 - 4-in-1 (JY-066) + */ + +#include "mapinc.h" +#include "latch.h" + +static void Sync(void) { + if (latch.data & 0x40) { + setprg32(0x8000, (latch.data >> 1) & 0x0F); + } else { + if (iNESCart.submapper == 1) { + setprg16(0x8000, ((latch.data & 0x30) >> 1) | (latch.data & 0x07)); + setprg16(0xC000, ((latch.data & 0x30) >> 1) | 0x07); + } else { + setprg16(0x8000, latch.data & 0x0F); + setprg16(0xC000, (latch.data & 0x0F) | 0x07); + } + } + setchr8(0); + if (latch.data & 0x80) { + setmirror(MI_0 + (((latch.data >> 5) & 0x01))); + } else { + setmirror(((latch.data >> 3) & 0x01) ^ 0x01); + } +} + +void Mapper285_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); +} diff --git a/src/mappers/mapper286.c b/src/mappers/mapper286.c new file mode 100644 index 000000000..e5bd861d2 --- /dev/null +++ b/src/mappers/mapper286.c @@ -0,0 +1,98 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2007 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 prg[4]; +static uint8 chr[4]; +static uint8 mirr; +static uint8 dipsw; + +static SFORMAT StateRegs[] = { + { prg, 4, "PREG" }, + { chr, 4, "CREG" }, + { &mirr, 1, "MIRR" }, + { &dipsw, 1, "DPSW" }, + { 0 } +}; + +static void Sync(void) { + setprg8(0x8000, prg[0]); + setprg8(0xa000, prg[1]); + setprg8(0xc000, prg[2]); + setprg8(0xe000, prg[3]); + + setchr2(0x0000, chr[0]); + setchr2(0x0800, chr[1]); + setchr2(0x1000, chr[2]); + setchr2(0x1800, chr[3]); + + setmirror((mirr & 0x01) ^ 0x01); +} + +static DECLFW(M286Write) { + switch (A & 0xF000) { + case 0x8000: + case 0x9000: + chr[(A & 0xC00) >> 10] = A & 0x1F; + Sync(); + break; + case 0xA000: + case 0xB000: + if (A & (1 << (dipsw + 4))) { + prg[(A & 0xC00) >> 10] = A & 0x0F; + Sync(); + } + break; + case 0xC000: + mirr = V; + Sync(); + break; + } +} + +static void M286Reset(void) { + dipsw++; + dipsw &= 3; + prg[0] = prg[1] = prg[2] = prg[3] = ~0; + mirr = 0; + Sync(); +} + +static void M286Power(void) { + dipsw = 0; + prg[0] = prg[1] = prg[2] = prg[3] = ~0; + mirr = 0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M286Write); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper286_Init(CartInfo *info) { + info->Power = M286Power; + info->Reset = M286Reset; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/bmc411120C.c b/src/mappers/mapper287.c similarity index 50% rename from src/boards/bmc411120C.c rename to src/mappers/mapper287.c index 336a30144..23830793b 100644 --- a/src/boards/bmc411120C.c +++ b/src/mappers/mapper287.c @@ -1,8 +1,9 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2008 CaH4e3 * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -36,58 +37,62 @@ #include "mapinc.h" #include "mmc3.h" -static uint8 reset_flag = 0; +static uint8 reg; +static uint8 dipsw; -static void BMC411120CCW(uint32 A, uint8 V) { - setchr1(A, (V & 0x7F) | ((mmc3.expregs[0] & 7) << 7)); +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { &dipsw, 1, "DPSW" }, + { 0 } +}; + +static void M287CW(uint32 A, uint8 V) { + uint16 base = reg & 0x07; + + setchr1(A, (base << 7) | (V & 0x7F)); } -static void BMC411120CPW(uint32 A, uint8 V) { - if (mmc3.expregs[0] & (8 | (reset_flag && ((ROM_size * 16) <= 512) ? 4 : 0))) { +static void M287PW(uint32 A, uint8 V) { + uint16 mode = reg & ((dipsw && ((ROM.prg.size * 16) <= 512)) ? 0x0C : 0x08); + uint16 base = reg & 0x07; + + if (mode) { /* 32K Mode */ - if (A == 0x8000) { - /* bit 0-1 of register should be used as outer bank regardless of banking modes */ - setprg32(A, ((mmc3.expregs[0] >> 4) & 3) | ((mmc3.expregs[0] & 7) << 2)); - /* FCEU_printf("32K mode: bank:%02x\n", ((mmc3.expregs[0] >> 4) & 3) | ((mmc3.expregs[0] & 7) << 2)); */ - } + setprg32(0x8000, (base << 2) | ((reg >> 4) & 0x03)); + /* FCEU_printf("32K mode: bank:%02x\n", ((reg >> 4) & 3) | ((reg & 7) << 2)); */ } else { /* MMC3 Mode */ - setprg8(A, (V & 0x0F) | ((mmc3.expregs[0] & 7) << 4)); - /* FCEU_printf("MMC3: %04x:%02x\n", A, (V & 0x0F) | ((mmc3.expregs[0] & 7) << 4)); */ + setprg8(A, (base << 4) | (V & 0x0F)); + /* FCEU_printf("MMC3: %04x:%02x\n", A, (V & 0x0F) | ((reg & 7) << 4)); */ } } -static DECLFW(BMC411120CLoWrite) { +static DECLFW(M287WriteReg) { /* printf("Wr: A:%04x V:%02x\n", A, V); */ - if (MMC3CanWriteToWRAM()) { - mmc3.expregs[0] = A; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + if (MMC3_WramIsWritable()) { + reg = A; + MMC3_FixPRG(); + MMC3_FixCHR(); } } -static void BMC411120CReset(void) { - mmc3.expregs[0] = 0; - reset_flag ^= 4; - MMC3RegReset(); -} - -static void BMC411120CPower(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, BMC411120CLoWrite); +static void M287Reset(void) { + reg = 0; + dipsw ^= 4; + MMC3_Reset(); } -void BMC411120C_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 512, 0, 0); - mmc3.pwrap = BMC411120CPW; - mmc3.cwrap = BMC411120CCW; - info->Power = BMC411120CPower; - info->Reset = BMC411120CReset; - AddExState(mmc3.expregs, 1, 0, "EXPR"); +static void M287Power(void) { + reg = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M287WriteReg); } -void BMCK3088_Init(CartInfo *info) { - BMC411120C_Init(info); +void Mapper287_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_pwrap = M287PW; + MMC3_cwrap = M287CW; + info->Power = M287Power; + info->Reset = M287Reset; + AddExState(StateRegs, ~0, 0, NULL); } - diff --git a/src/mappers/mapper288.c b/src/mappers/mapper288.c new file mode 100644 index 000000000..b32ab63f0 --- /dev/null +++ b/src/mappers/mapper288.c @@ -0,0 +1,55 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 288 is used for two GKCX1 21-in-1 multicarts + * - 21-in-1 (GA-003) + * - 64-in-1 (CF-015) + */ + +#include "mapinc.h" +#include "latch.h" + +static uint8 dipsw; + +static void Sync(void) { + setprg32(0x8000, latch.addr >> 3); + setchr8(latch.addr); + setmirror(((latch.addr >> 5) & 0x01) ^ 0x01); +} + +static DECLFR(M288Read) { + uint8 ret = CartBR(A); + if (latch.addr & 0x20) { + return CartBR(A | (dipsw & 0x0F)); + } + return ret; +} + +static void M288Reset(void) { + dipsw++; + Sync(); +} + +void Mapper288_Init(CartInfo *info) { + Latch_Init(info, Sync, M288Read, FALSE, FALSE); + info->Reset = M288Reset; + AddExState(&dipsw, 1, 0, "DIPSW"); +} diff --git a/src/boards/bmc60311c.c b/src/mappers/mapper289.c similarity index 51% rename from src/boards/bmc60311c.c rename to src/mappers/mapper289.c index 6f54241df..9f52e7bed 100644 --- a/src/boards/bmc60311c.c +++ b/src/mappers/mapper289.c @@ -26,66 +26,56 @@ #include "latch.h" static uint8 reg[2]; -static uint8 solderpad; +static uint8 dipsw; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { reg, 2, "REGS" }, - { &solderpad, 1, "PADS" }, + { &dipsw, 1, "DPSW" }, { 0 } }; static void Sync(void) { uint32 bank = reg[1] & 0x7F; - switch (reg[0] & 3) { - case 0: /* NROM-128 */ - setprg16(0x8000, bank); - setprg16(0xC000, bank); - break; - case 1: /* NROM-256 */ - setprg32(0x8000, bank >> 1); - break; - case 2: /* UNROM */ - setprg16(0x8000, bank | (latch.data & 7)); - setprg16(0xC000, bank | 7); - break; - case 3: /* A14-A16=1 regardless of CPU A14 */ - setprg16(0x8000, bank | 7); - setprg16(0xC000, bank | 7); - break; + + if (reg[0] & 0x02) { + setprg16(0x8000, (bank & ~0x07) | ((reg[0] & 0x01) ? 0x07 : (latch.data & 0x07))); + setprg16(0xC000, bank | 0x07); + } else { + setprg16(0x8000, bank & ~(reg[0] & 0x01)); + setprg16(0xC000, bank | (reg[0] & 0x01)); } /* CHR-RAM write-protect */ - SetupCartCHRMapping(0, CHRptr[0], 0x2000, ((reg[0] >> 2) & 1) ^ 1); + SetupCartCHRMapping(0, CHRptr[0], 0x2000, ((reg[0] >> 2) & 0x01) ^ 0x01); setchr8(0); - setmirror(((reg[0] >> 3) & 1) ^ 1); + setmirror(((reg[0] >> 3) & 0x01) ^ 0x01); } -static DECLFR(ReadPad) { - return (X.DB & ~3) | (solderpad & 3); +static DECLFR(M289Read) { + return (cpu.openbus & ~0x03) | (dipsw & 0x03); } -static DECLFW(WriteReg) { - reg[A & 1] = V; +static DECLFW(M289Write) { + reg[A & 0x01] = V; Sync(); } -static void BMC60311CPower(void) { +static void M289Power(void) { + dipsw = 0; reg[0] = reg[1] = 0; - solderpad = 0; - LatchPower(); - SetReadHandler(0x6000, 0x7FFF, ReadPad); - SetWriteHandler(0x6000, 0x7FFF, WriteReg); + Latch_Power(); + SetReadHandler(0x6000, 0x7FFF, M289Read); + SetWriteHandler(0x6000, 0x7FFF, M289Write); } -static void BMC60311CReset(void) { +static void M289Reset(void) { + dipsw++; reg[0] = reg[1] = 0; - solderpad++; - LatchHardReset(); + Latch_RegReset(); } -void BMC60311C_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); - info->Power = BMC60311CPower; - info->Reset = BMC60311CReset; - AddExState(&StateRegs, ~0, 0, 0); +void Mapper289_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Power = M289Power; + info->Reset = M289Reset; + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper290.c b/src/mappers/mapper290.c new file mode 100644 index 000000000..b51d63ba8 --- /dev/null +++ b/src/mappers/mapper290.c @@ -0,0 +1,44 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 290 - BMC-NTD-03 */ + +#include "mapinc.h" +#include "latch.h" + +static void Sync(void) { + uint32 prg = ((latch.addr >> 10) & 0x1E) | ((latch.addr >> 6) & 0x01); + uint32 chr = ((latch.addr >> 5) & 0x18) | (latch.addr & 0x07); + + if (latch.addr & 0x80) { + setprg16(0x8000, prg); + setprg16(0xC000, prg); + } else { + setprg32(0x8000, prg >> 1); + } + setchr8(chr); + setmirror(((latch.addr >> 10) & 0x01) ^ 0x01); +} + +void Mapper290_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Reset = Latch_RegReset; +} diff --git a/src/boards/mapper291.c b/src/mappers/mapper291.c similarity index 70% rename from src/boards/mapper291.c rename to src/mappers/mapper291.c index 9c6eb402a..151455ad3 100644 --- a/src/boards/mapper291.c +++ b/src/mappers/mapper291.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2022 + * Copyright (C) 2023-2024 negativeExponent * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -21,40 +21,48 @@ #include "mapinc.h" #include "mmc3.h" +static uint8 reg; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; + static void M291CW(uint32 A, uint8 V) { - setchr1(A, V | ((mmc3.expregs[0] << 2) & 0x100)); + setchr1(A, ((reg << 2) & 0x100) | (V & 0xFF)); } static void M291PW(uint32 A, uint8 V) { - if (mmc3.expregs[0] & 0x20) - setprg32(0x8000, ((mmc3.expregs[0] >> 1) & 3) | ((mmc3.expregs[0] >> 4) & 4)); - else - setprg8(A, (V & 0x0F) | ((mmc3.expregs[0] >> 2) & 0x10)); + if (reg & 0x20) { + setprg32(0x8000, ((reg >> 4) & 0x04) | ((reg >> 1) & 0x03)); + } else { + setprg8(A, ((reg >> 2) & 0x10) | (V & 0x0F)); + } } static DECLFW(M291Write) { /* The Outer Bank Register responds even when the MMC3 clone's WRAM bit is clear. */ - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + reg = V; + MMC3_FixPRG(); + MMC3_FixCHR(); } static void M291Reset(void) { - mmc3.expregs[0] = 0; - MMC3RegReset(); + reg = 0; + MMC3_Reset(); } static void M291Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); + reg = 0; + MMC3_Power(); SetWriteHandler(0x6000, 0x7FFF, M291Write); } void Mapper291_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 512, 0, 0); - mmc3.cwrap = M291CW; - mmc3.pwrap = M291PW; + MMC3_Init(info, 0, 0); + MMC3_cwrap = M291CW; + MMC3_pwrap = M291PW; info->Power = M291Power; info->Reset = M291Reset; - AddExState(mmc3.expregs, 1, 0, "EXPR"); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper292.c b/src/mappers/mapper292.c new file mode 100644 index 000000000..b28a77637 --- /dev/null +++ b/src/mappers/mapper292.c @@ -0,0 +1,80 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2015 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 292 - PCB BMW8544 + * UNIF UNL-DRAGONFIGHTER + * "Dragon Fighter" protected MMC3 based custom mapper board + * mostly hacky implementation, I can't verify if this mapper can read a RAM of the + * console or watches the bus writes somehow. + * + * TODO: needs updating + * + */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 reg[3]; + +static SFORMAT StateRegs[] = { + { reg, 3, "REGS" }, + { 0 } +}; + +static void M292PW(uint32 A, uint8 V) { + setprg8(A, V); + setprg8(0x8000, reg[0] & 0x1F); +} + +static void M292CW(uint32 A, uint8 V) { + setchr2(0x0000, (mmc3.reg[0] >> 1) ^ reg[1]); + setchr2(0x0800, (mmc3.reg[1] >> 1) ^ ((reg[2] & 0x40) << 1)); + setchr4(0x1000, reg[2] & 0x3F); +} + +static DECLFW(M292ProtWrite) { + reg[0] = V; + MMC3_FixPRG(); +} + +static DECLFR(M292ProtRead) { + if ((reg[0] & 0xE0) == 0xC0) { + reg[1] = ARead[0x6A](0x6A); + } else { + reg[2] = ARead[0xFF](0xFF); + } + MMC3_FixCHR(); + return cpu.openbus; +} + +static void M292Power(void) { + reg[0] = reg[1] = reg[2] = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M292ProtWrite); + SetReadHandler(0x6000, 0x7FFF, M292ProtRead); +} + +void Mapper292_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_pwrap = M292PW; + MMC3_cwrap = M292CW; + info->Power = M292Power; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/mapper293.c b/src/mappers/mapper293.c similarity index 52% rename from src/boards/mapper293.c rename to src/mappers/mapper293.c index b3ca82606..1e5244fbb 100644 --- a/src/boards/mapper293.c +++ b/src/mappers/mapper293.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent * * 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,61 +23,56 @@ #include "mapinc.h" -static uint8 regs[2]; -static SFORMAT StateRegs[] = -{ - { regs, 2, "REGS" }, +static uint8 reg[2]; + +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, { 0 } }; static void Sync(void) { - uint8 mode = ((regs[0] >> 2) & 2) | ((regs[1] >> 6) & 1); - uint8 bank = ((regs[1] << 5) & 0x20) | ((regs[1] >> 1) & 0x18); - uint8 block = (regs[0] & 7); + uint8 mode = ((reg[0] >> 2) & 0x02) | ((reg[1] >> 6) & 0x01); + uint8 base = ((reg[1] << 5) & 0x20) | ((reg[1] >> 1) & 0x18); + uint8 bank = (reg[0] & 0x07); + switch (mode) { - case 0: /* UNROM */ - setprg16(0x8000, bank | block); - setprg16(0xC000, bank | 7); - break; - case 1: - setprg16(0x8000, bank | (block & 0xFE)); - setprg16(0xC000, bank | 7); - break; - case 2: /* NROM-128 */ - setprg16(0x8000, bank | block); - setprg16(0xC000, bank | block); - break; - case 3: /* NROM-256 */ - setprg32(0x8000, (bank | block) >> 1); - break; + case 0: /* UNROM */ + setprg16(0x8000, base | bank); + setprg16(0xC000, base | 0x07); + break; + case 1: + setprg16(0x8000, base | (bank & 0xFE)); + setprg16(0xC000, base | 0x07); + break; + case 2: /* NROM-128 */ + setprg16(0x8000, base | bank); + setprg16(0xC000, base | bank); + break; + case 3: /* NROM-256 */ + setprg16(0x8000, (base | bank) & 0xFE); + setprg16(0xC000, (base | bank) | 1); + break; } setchr8(0); - setmirror(((regs[1] >> 7) & 1) ^ 1); -} - -static DECLFW(M293Write1) { - regs[0] = V; - regs[1] = V; - Sync(); + setmirror(((reg[1] >> 7) & 0x01) ^ 0x01); } -static DECLFW(M293Write2) { - regs[1] = V; - Sync(); -} - -static DECLFW(M293Write3) { - regs[0] = V; - Sync(); +static DECLFW(M293Write) { + if (!(A & 0x2000)) { + /* First Banking Register ($8000-$9FFF, $C000-$DFFF) */ + reg[0] = V; + } + if (!(A & 0x4000)) { + /* Second Banking Register ($8000-$BFFF) */ + reg[1] = V; + } } static void M293Power(void) { - regs[0] = regs[1] = 0; + reg[0] = reg[1] = 0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0x9FFF, M293Write1); - SetWriteHandler(0xA000, 0xBFFF, M293Write2); - SetWriteHandler(0xC000, 0xDFFF, M293Write3); + SetWriteHandler(0x8000, 0xDFFF, M293Write); } static void StateRestore(int version) { @@ -87,5 +83,5 @@ static void StateRestore(int version) { void Mapper293_Init(CartInfo *info) { info->Power = M293Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper294.c b/src/mappers/mapper294.c similarity index 80% rename from src/boards/mapper294.c rename to src/mappers/mapper294.c index 79564acf3..16478c291 100644 --- a/src/boards/mapper294.c +++ b/src/mappers/mapper294.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2022 NewRisingSun + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -24,6 +25,11 @@ static uint8 reg; +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; + static void Sync(void) { setprg16(0x8000, (reg << 3) | (latch.data & 0x07)); setprg16(0xC000, (reg << 3) | 0x07); @@ -40,17 +46,18 @@ static DECLFW(M294Write) { static void M294Reset(void) { reg = 0; - LatchHardReset(); + Latch_RegReset(); } static void M294Power(void) { - LatchPower(); - SetWriteHandler(0x4020, 0x4FFF, M294Write); + reg = 0; + Latch_Power(); + SetWriteHandler(0x4100, 0x5FFF, M294Write); } void Mapper294_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); + Latch_Init(info, Sync, NULL, FALSE, FALSE); info->Power = M294Power; info->Reset = M294Reset; - AddExState(®, 1, 0, "REGS"); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper295.c b/src/mappers/mapper295.c new file mode 100644 index 000000000..0b4881de9 --- /dev/null +++ b/src/mappers/mapper295.c @@ -0,0 +1,44 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "jyasic.h" +#include "fdssound.h" + +static uint32 GetPRGBank(uint32 V) { + return ((jyasic.mode[3] << 4) | (V & 0x0F)); +} + +static uint32 GetCHRBank(uint32 V) { + return ((jyasic.mode[3] << 7) | (V & 0x7F)); +} + +static void M295Power(void) { + JYASIC_Power(); + FDSSound_Power(); +} + +void Mapper295_Init(CartInfo *info) { + /* Multicart */ + JYASIC_Init(info, TRUE); + JYASIC_GetPRGBank = GetPRGBank; + JYASIC_GetCHRBank = GetCHRBank; + info->Power = M295Power; +} diff --git a/src/mappers/mapper297.c b/src/mappers/mapper297.c new file mode 100644 index 000000000..52246faea --- /dev/null +++ b/src/mappers/mapper297.c @@ -0,0 +1,94 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 297 - 2-in-1 Uzi Lightgun (MGC-002) */ + +#include "mapinc.h" +#include "mmc1.h" + +static uint8 mode; +static uint8 latch; + +static SFORMAT StateRegs[] = { + { &mode, 1, "MODE" }, + { &latch, 1, "LATC" }, + { 0 } +}; + +static void M297PRG(uint32 A, uint8 V) { + setprg16(A, 0x08 | (V & 0x07)); +} + +static void M297CHR(uint32 A, uint8 V) { + setchr4(A, 0x20 | (V & 0x1F)); +} + +static void Sync(void) { + if (mode & 0x01) { + /* MMC1 */ + MMC1_FixPRG(); + MMC1_FixCHR(); + MMC1_FixMIR(); + } else { + /* Mapper 70 */ + setprg16(0x8000, ((mode & 0x02) << 1) | ((latch >> 4) & 0x03)); + setprg16(0xC000, ((mode & 0x02) << 1) | 0x03); + setchr8(latch & 0x0F); + setmirror(MI_V); + } +} + +static DECLFW(M297Mode) { + if (A & 0x100) { + mode = V; + Sync(); + } +} + +static DECLFW(M297Latch) { + if (mode & 0x01) { + MMC1_Write(A, V); + } else { + latch = V; + Sync(); + } +} + +static void M297Power(void) { + latch = 0; + mode = 0; + Sync(); + MMC1_Power(); + SetWriteHandler(0x4100, 0x5FFF, M297Mode); + SetWriteHandler(0x8000, 0xFFFF, M297Latch); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper297_Init(CartInfo *info) { + MMC1_Init(info, 0, 0); + info->Power = M297Power; + MMC1_cwrap = M297CHR; + MMC1_pwrap = M297PRG; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/tf-1201.c b/src/mappers/mapper298.c similarity index 62% rename from src/boards/tf-1201.c rename to src/mappers/mapper298.c index e33726900..28662b7ec 100644 --- a/src/boards/tf-1201.c +++ b/src/mappers/mapper298.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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,23 +23,8 @@ */ #include "mapinc.h" -#include "vrc24.h" +#include "vrc2and4.h" -static DECLFW(UNLTF1201IRQWrite) { - /* NOTE: acknowledge IRQ but do not move A control bit to E control bit. - * So, just make E bit the same with A bit coz im lazy to modify IRQ code for now. */ - if ((A & 0x03) == 0x01) { - V |= ((V >> 1) & 0x01); - } - VRC24Write(A, V); -} - -static void UNLTF1201Power(void) { - GenVRC24Power(); - SetWriteHandler(0xF000, 0xFFFF, UNLTF1201IRQWrite); -} - -void UNLTF1201_Init(CartInfo *info) { - GenVRC24_Init(info, VRC4b, 0); - info->Power = UNLTF1201Power; +void Mapper298_Init(CartInfo *info) { + VRC24_Init(info, VRC4, 0x02, 0x01, FALSE, FALSE); } diff --git a/src/mappers/mapper299.c b/src/mappers/mapper299.c new file mode 100644 index 000000000..6c0853f96 --- /dev/null +++ b/src/mappers/mapper299.c @@ -0,0 +1,37 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + */ + +/* BMC-11160 (m299) */ +/* Simple BMC discrete mapper by TXC */ + +#include "mapinc.h" +#include "latch.h" + +static void Sync(void) { + setprg32(0x8000, (latch.data >> 4) & 0x07); + setchr8(((latch.data >> 2) & 0x1C) | (latch.data & 0x03)); + setmirror((latch.data >> 7) & 0x01); +} + +void Mapper299_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Reset = Latch_RegReset; +} diff --git a/src/mappers/mapper300.c b/src/mappers/mapper300.c new file mode 100644 index 000000000..02d3cb584 --- /dev/null +++ b/src/mappers/mapper300.c @@ -0,0 +1,36 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 300 - BMC-190in1 */ + +#include "mapinc.h" +#include "latch.h" + +static void Sync(void) { + setprg16(0x8000, latch.addr >> 2); + setprg16(0xC000, latch.addr >> 2); + setchr8(latch.addr >> 2); + setmirror((latch.addr & 0x01) ^ 0x01); +} + +void Mapper300_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); +} diff --git a/src/boards/mapper301.c b/src/mappers/mapper301.c similarity index 56% rename from src/boards/mapper301.c rename to src/mappers/mapper301.c index 1baa3f947..f16f57edf 100644 --- a/src/boards/mapper301.c +++ b/src/mappers/mapper301.c @@ -1,8 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,55 +25,44 @@ #include "mapinc.h" #include "latch.h" -static uint8 reset; -static SFORMAT StateRegs[] = -{ - { &reset, 1, "PADS" }, +static uint8 dipsw; + +static SFORMAT StateRegs[] = { + { &dipsw, 1, "DPSW" }, { 0 } }; static void Sync(void) { - uint32 bank = (latch.addr >> 2) & 0x1F; - switch (((latch.addr >> 8) & 2) | ((latch.addr >> 7) & 1)) { - case 0: - setprg16(0x8000, bank); - setprg16(0xC000, 0); - break; - case 1: - setprg16(0x8000, bank); - setprg16(0xC000, bank); - break; - case 2: - case 3: - setprg16(0x8000, bank); - setprg16(0xC000, bank | 7); - break; - } + uint8 prg = (latch.addr >> 2) & 0x1F; + uint8 nrom = (latch.addr & 0x80) != 0; + uint8 unrom = (latch.addr & 0x200) != 0; + setprg16(0x8000, prg); + setprg16(0xC000, (prg & ~(0x07 * nrom)) | (0x07 * unrom)); setchr8(0); setmirror(((latch.addr & 2) >> 1) ^ 1); } -static DECLFR(UNL8157Read) { +static DECLFR(M301Read) { if ((latch.addr & 0x100) && (PRGsize[0] <= (512 * 1024))) { - A = (A & 0xFFFE) + reset; + A = (A & 0xFFFE) + (dipsw & 0x01); } return CartBR(A); } -static void UNL8157Power(void) { - reset = 0; - LatchPower(); +static void M301Power(void) { + dipsw = 0; + Latch_Power(); } -static void UNL8157Reset(void) { - reset = !reset; - LatchHardReset(); +static void M301Reset(void) { + dipsw++; + Latch_RegReset(); } -void UNL8157_Init(CartInfo *info) { - Latch_Init(info, Sync, UNL8157Read, 0, 0); - info->Power = UNL8157Power; - info->Reset = UNL8157Reset; - AddExState(&StateRegs, ~0, 0, 0); +void Mapper301_Init(CartInfo *info) { + Latch_Init(info, Sync, M301Read, FALSE, FALSE); + info->Power = M301Power; + info->Reset = M301Reset; + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper302.c b/src/mappers/mapper302.c new file mode 100644 index 000000000..eea35fc95 --- /dev/null +++ b/src/mappers/mapper302.c @@ -0,0 +1,54 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2011 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 302 - UNL-KS7057 + * FDS Conversion + */ + +#include "mapinc.h" +#include "vrc2and4.h" + +static void M302PW(uint32 A, uint8 V) { + setprg8( 0x8000, 0x00); + setprg8( 0xA000, 0x0D); + setprg16(0xC000, 0x07); +} + +static void M302CW(uint32 A, uint32 V) { + setchr8(0); +} + +static DECLFR(M302Read) { + uint8 bank = (((A - 0x6000) >> 11) & 0x06) | ((A >> 11) & 0x01); + + return PRGptr[0][(vrc24.chr[bank ^ 4] << 11) | (A & 0x07FF)]; +} + +static void M302Power(void) { + VRC24_Power(); + SetReadHandler(0x6000, 0x9FFF, M302Read); +} + +void Mapper302_Init(CartInfo *info) { + VRC24_Init(info, VRC2, 0x01, 0x02, FALSE, TRUE); + info->Power = M302Power; + VRC24_pwrap = M302PW; + VRC24_cwrap = M302CW;; +} diff --git a/src/boards/KS7017.c b/src/mappers/mapper303.c similarity index 68% rename from src/boards/KS7017.c rename to src/mappers/mapper303.c index 1e4a83019..775ce5786 100644 --- a/src/boards/KS7017.c +++ b/src/mappers/mapper303.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2007 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -17,65 +18,70 @@ * 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 303 - Kaiser 7017 + * UNIF UNL-KS7017 * FDS Conversion - Almana No Kiseki * */ #include "mapinc.h" -#include "../fds_apu.h" +#include "fdssound.h" -static uint8 latche, reg, mirr; +static uint8 latch; +static uint8 prg, mirr; static int32 IRQa, IRQCount, IRQLatch; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { &mirr, 1, "MIRR" }, - { ®, 1, "REGS" }, + { &prg, 1, "REGS" }, + { &latch, 1, "LATC" }, { &IRQa, 4, "IRQA" }, { &IRQCount, 4, "IRQC" }, { &IRQLatch, 4, "IRQL" }, - { &latche, 1, "LATC" }, { 0 } }; static void Sync(void) { - setprg16(0x8000, reg); + setprg16(0x8000, prg); setprg16(0xC000, 2); + setchr8(0); + setprg8r(0x10, 0x6000, 0); setmirror(mirr); } -static DECLFW(UNLKS7017Write) { -/* FCEU_printf("bs %04x %02x\n",A,V); */ +static DECLFW(M303Write) { + /* FCEU_printf("bs %04x %02x\n",A,V); */ if ((A & 0xFF00) == 0x4A00) { - latche = ((A >> 2) & 3) | ((A >> 4) & 4); + latch = ((A >> 2) & 0x03) | ((A >> 4) & 0x04); } else if ((A & 0xFF00) == 0x5100) { - reg = latche; + prg = latch; Sync(); } else { - if (A == 0x4020) { + if (A == 0x4020) { X6502_IRQEnd(FCEU_IQEXT); IRQCount &= 0xFF00; IRQCount |= V; } else if (A == 0x4021) { X6502_IRQEnd(FCEU_IQEXT); - IRQCount &= 0xFF; + IRQCount &= 0x00FF; IRQCount |= V << 8; IRQa = 1; } else if (A == 0x4025) { - mirr = ((V & 8) >> 3) ^ 1; + mirr = ((V & 8) >> 3) ^ 0x01; + } else { + FDSSound_Write(A, V); } - FDSSoundWrite(A, V); } } static DECLFR(FDSRead4030) { + uint8 ret = (cpu.IRQlow & FCEU_IQEXT) ? 1 : 0; + X6502_IRQEnd(FCEU_IQEXT); - return X.IRQlow & FCEU_IQEXT ? 1 : 0; + return ret; } -static void FP_FASTAPASS(1) UNL7017IRQ(int a) { +static void UNL7017IRQ(int a) { if (IRQa) { IRQCount -= a; if (IRQCount <= 0) { @@ -85,39 +91,34 @@ static void FP_FASTAPASS(1) UNL7017IRQ(int a) { } } -static void UNLKS7017Power(void) { - FDSSoundPower(); +static void M303Power(void) { + latch = prg = mirr = IRQa = IRQCount = IRQLatch = 0; + FDSSound_Power(); Sync(); - setchr8(0); - setprg8r(0x10, 0x6000, 0); SetReadHandler(0x6000, 0x7FFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); SetReadHandler(0x8000, 0xFFFF, CartBR); SetReadHandler(0x4030, 0x4030, FDSRead4030); - SetWriteHandler(0x4020, 0x5FFF, UNLKS7017Write); + SetWriteHandler(0x4020, 0x5FFF, M303Write); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } -static void UNLKS7017Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; +static void M303Close(void) { } static void StateRestore(int version) { Sync(); } -void UNLKS7017_Init(CartInfo *info) { - info->Power = UNLKS7017Power; - info->Close = UNLKS7017Close; +void Mapper303_Init(CartInfo *info) { + info->Power = M303Power; + info->Close = M303Close; MapIRQHook = UNL7017IRQ; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); WRAMSIZE = 8192; WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); } diff --git a/src/boards/mapper304.c b/src/mappers/mapper304.c similarity index 74% rename from src/boards/mapper304.c rename to src/mappers/mapper304.c index 51eaa08c2..1c2147ccc 100644 --- a/src/boards/mapper304.c +++ b/src/mappers/mapper304.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2007 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -24,7 +25,8 @@ * Both Voleyball and Zanac by Whirlind Manu shares the same PCB, but with * some differences: Voleyball has 8K CHR ROM and 8K ROM at 6000K, Zanac * have 8K CHR RAM and banked 16K ROM mapper at 6000 as two 8K banks. -* + * + * NES 2.0 Mapper 304 - UNL-SMB2J * Super Mario Bros 2j (Alt Small) uses additionally IRQ timer to drive framerate * * PCB for this mapper is "09-034A" @@ -49,35 +51,36 @@ static void Sync(void) { setchr8(0); } -static DECLFW(UNLSMB2JWrite1) { - prg = V & 1; +static DECLFW(M304Write1) { + prg = V & 0x01; Sync(); } -static DECLFW(UNLSMB2JWrite2) { - IRQa = V & 1; +static DECLFW(M304Write2) { + IRQa = V & 0x01; IRQCount = 0; X6502_IRQEnd(FCEU_IQEXT); } -static DECLFR(UNLSMB2JRead) { +static DECLFR(M304Read) { return 0xFF; } -static void UNLSMB2JPower(void) { +static void M304Power(void) { prg = 0; + IRQCount = IRQa = 0; Sync(); SetReadHandler(0x6000, 0xFFFF, CartBR); - SetReadHandler(0x4042, 0x4055, UNLSMB2JRead); - SetWriteHandler(0x4068, 0x4068, UNLSMB2JWrite2); - SetWriteHandler(0x4027, 0x4027, UNLSMB2JWrite1); + SetReadHandler(0x4020, 0x4FFF, M304Read); + SetWriteHandler(0x4068, 0x4068, M304Write2); + SetWriteHandler(0x4027, 0x4027, M304Write1); } -static void FP_FASTAPASS(1) UNLSMB2JIRQHook(int a) { +static void M304IRQHook(int a) { if (IRQa) { - if (IRQCount < 5750) /* completely by guess */ + if (IRQCount < 5750) { IRQCount += a; - else { + } else { IRQa = 0; X6502_IRQBegin(FCEU_IQEXT); } @@ -88,9 +91,9 @@ static void StateRestore(int version) { Sync(); } -void UNLSMB2J_Init(CartInfo *info) { - info->Power = UNLSMB2JPower; - MapIRQHook = UNLSMB2JIRQHook; +void Mapper304_Init(CartInfo *info) { + info->Power = M304Power; + MapIRQHook = M304IRQHook; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/KS7031.c b/src/mappers/mapper305.c similarity index 76% rename from src/boards/KS7031.c rename to src/mappers/mapper305.c index 4f961f4ef..e25040386 100644 --- a/src/boards/KS7031.c +++ b/src/mappers/mapper305.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) 2023-2024 negativeExponent * * 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 @@ -17,17 +18,18 @@ * 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 305 + * UNIF UNL-KS7031 * FDS Conversion - dracula ii - noroi no fuuin [u][!] * */ #include "mapinc.h" -#include "fds_apu.h" +#include "fdssound.h" static uint8 reg[4]; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { reg, 4, "REGS" }, { 0 } }; @@ -59,24 +61,26 @@ static void Sync(void) { setchr8(0); } -static DECLFW(UNLKS7031Write) { - reg[(A >> 11) & 3] = V; +static DECLFW(M305Write) { + reg[(A >> 11) & 0x03] = V; Sync(); } -static void UNLKS7031Power(void) { - FDSSoundPower(); +static void M305Power(void) { + memset(reg, 0, sizeof(reg)); + FDSSound_Power(); Sync(); + setmirror(MI_V); SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xffff, UNLKS7031Write); + SetWriteHandler(0x8000, 0xFFFF, M305Write); } static void StateRestore(int version) { Sync(); } -void UNLKS7031_Init(CartInfo *info) { - info->Power = UNLKS7031Power; +void Mapper305_Init(CartInfo *info) { + info->Power = M305Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/KS7016.c b/src/mappers/mapper306.c similarity index 56% rename from src/boards/KS7016.c rename to src/mappers/mapper306.c index a62145578..b140bb633 100644 --- a/src/boards/KS7016.c +++ b/src/mappers/mapper306.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2016 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -17,6 +18,8 @@ * 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 306 - Kaiser 7016 + * UNIF UNL-KS7016 * FDS Conversion (Exciting Basket), weird banking addressing, seems because * of used addressing scheme, made to disable the lower system banks from 6000 * but the kaiser mapper chip and PCB are the same as usual @@ -25,63 +28,48 @@ */ #include "mapinc.h" -#include "../fds_apu.h" +#include "fdssound.h" -static uint8 preg; +static uint8 reg; -static SFORMAT StateRegs[] = -{ - { &preg, 1, "PREG" }, +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, { 0 } }; static void Sync(void) { - setprg8(0x6000, preg); - setprg8(0x8000, 0xC); - setprg8(0xA000, 0xD); - setprg8(0xC000, 0xE); - setprg8(0xE000, 0xF); + setprg8( 0x6000, reg); + setprg32(0x8000, 3); setchr8(0); } -static DECLFW(UNLKS7016Write) { - uint16 mask = (A & 0x30); - switch(A & 0xD943) { - case 0xD943: { - if(mask == 0x30) { - preg = 8 | 3; /* or A, or no bus (all FF) */ +static DECLFW(M306Write) { + if ((A & 0xD903) == 0xD903) { + if (A & 0x40) { + reg = (A >> 2) & 0x0F; } else { - preg = (A >> 2) & 0xF; /* can be anything but C-F */ + reg = 0x08 | ((A >> 2) & 0x03); } Sync(); - break; - } - case 0xD903: { /* this case isn't usedby the game, but addressing does this as a side effect */ - if(mask == 0x30) { - preg = 8 | ((A >> 2) & 3); /* also masked C-F from output */ - } else { - preg = 8 | 3; - } - Sync(); - break; - } } } -static void UNLKS7016Power(void) { - FDSSoundPower(); - preg = 8; +static void M306Power(void) { + FDSSound_Power(); + + reg = 0; Sync(); - SetReadHandler(0x6000, 0xffff, CartBR); - SetWriteHandler(0x8000, 0xffff, UNLKS7016Write); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0xD000, 0xDFFF, M306Write); + SetWriteHandler(0xF000, 0xFFFF, M306Write); } static void StateRestore(int version) { Sync(); } -void UNLKS7016_Init(CartInfo *info) { - info->Power = UNLKS7016Power; +void Mapper306_Init(CartInfo *info) { + info->Power = M306Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper307.c b/src/mappers/mapper307.c new file mode 100644 index 000000000..3b82baa53 --- /dev/null +++ b/src/mappers/mapper307.c @@ -0,0 +1,55 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 - Metroid - Jin Ji Zhi Ling (Kaiser)(KS7037)[U][!] + * NES 2.0 Mapper 307 - UNL-KS7037 + * + */ + +#include "mapinc.h" +#include "n118.h" +#include "fdssound.h" + +static void M307FixPRG(void) { + setprg4r(0x10, 0x6000, 0); + setprg4(0x7000, 15); + setprg8(0x8000, n118.reg[6]); + setprg4(0xA000, ~3); + setprg4r(0x10, 0xB000, 0x01); + setprg8(0xC000, n118.reg[7]); + setprg8(0xE000, ~0); +} + +static void M307FixCHR(void) { + setchr8(0); + setmirrorw(n118.reg[2] & 0x01, n118.reg[4] & 0x01, n118.reg[3] & 0x01, n118.reg[5] & 0x01); +} + +static void M307Power(void) { + FDSSound_Power(); + N118_Power(); + SetWriteHandler(0xB000, 0xBFFF, CartBW); +} + +void Mapper307_Init(CartInfo *info) { + N118_Init(info, 8, info->battery); + info->Power = M307Power; + N118_FixPRG = M307FixPRG; + N118_FixCHR = M307FixCHR; +} diff --git a/src/boards/th21311.c b/src/mappers/mapper308.c similarity index 71% rename from src/boards/th21311.c rename to src/mappers/mapper308.c index 90b52b87a..3e6d1af8e 100644 --- a/src/boards/th21311.c +++ b/src/mappers/mapper308.c @@ -2,7 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2007 CaH4e3 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* -------------------- UNL-TH2131-1 -------------------- */ +/* NES 2.0 Mapper 308 - 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. @@ -27,10 +27,10 @@ */ #include "mapinc.h" -#include "vrc24.h" +#include "vrc2and4.h" -static uint16 IRQCount; static uint8 IRQLatch, IRQa; +static uint16 IRQCount; static SFORMAT IRQStateRegs[] = { { &IRQCount, 2, "IRQC" }, @@ -40,7 +40,7 @@ static SFORMAT IRQStateRegs[] = { { 0 } }; -static DECLFW(TH2131Write) { +static DECLFW(M308Write) { switch (A & 0xF003) { case 0xF000: X6502_IRQEnd(FCEU_IQEXT); IRQa = 0; IRQCount = 0; break; case 0xF001: IRQa = 1; break; @@ -48,30 +48,29 @@ static DECLFW(TH2131Write) { } } -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 M308IRQHook(int a) { + if (IRQa) { + while (a--) { + IRQCount++; + if ((IRQCount & 0x0FFF) == 2048) { + IRQLatch--; + } + if (!IRQLatch && (IRQCount & 0x0FFF) < 2048) { + X6502_IRQBegin(FCEU_IQEXT); + } + } } } -static void TH2131Power(void) { +static void M308Power(void) { IRQa = IRQCount = IRQLatch = 0; - GenVRC24Power(); - SetWriteHandler(0xF000, 0xFFFF, TH2131Write); + VRC24_Power(); + SetWriteHandler(0xF000, 0xFFFF, M308Write); } -void UNLTH21311_Init(CartInfo *info) { - GenVRC24_Init(info, VRC2b, 1); - info->Power = TH2131Power; - MapIRQHook = TH2131IRQHook; +void Mapper308_Init(CartInfo *info) { + VRC24_Init(info, VRC2, 0x01, 0x02, 0, 1); + info->Power = M308Power; + MapIRQHook = M308IRQHook; AddExState(IRQStateRegs, ~0, 0, NULL); } diff --git a/src/boards/lh51.c b/src/mappers/mapper309.c similarity index 72% rename from src/boards/lh51.c rename to src/mappers/mapper309.c index 4a559bb92..8c1b3cb0a 100644 --- a/src/boards/lh51.c +++ b/src/mappers/mapper309.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -20,70 +21,63 @@ /* FDS Conversion * NES 2.0 Mapper 309 is used for Whirlwind Manu's ROM cartridge conversion - * of game 愛戦士ニコル (Ai Senshi Nicol, cartridge code LH51). + * of game 愛戦士ニコル (Ai Senshi Nicol, cartridge code M309). * Its UNIF board name is UNL-LH51. * https://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_309 */ #include "mapinc.h" -#include "../fds_apu.h" +#include "fdssound.h" static uint8 reg, mirr; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; -static SFORMAT StateRegs[] = -{ +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); + setprg8(0x8000, reg); + setprg8(0xA000, ~2); + setprg8(0xC000, ~1); + setprg8(0xE000, ~0); + setchr8(0); + setmirror(((mirr >> 3) & 0x01) ^ 0x01); } -static DECLFW(LH51Write) { +static DECLFW(M309Write) { switch (A & 0xF000) { case 0x8000: reg = V; Sync(); break; case 0xF000: mirr = V; Sync(); break; } } -static void LH51Power(void) { - FDSSoundPower(); +static void M309Power(void) { + FDSSound_Power(); Sync(); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetWriteHandler(0x8000, 0xFFFF, LH51Write); + SetWriteHandler(0x8000, 0xFFFF, M309Write); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } -static void LH51Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; +static void M309Close(void) { } static void StateRestore(int version) { Sync(); } -void LH51_Init(CartInfo *info) { - info->Power = LH51Power; - info->Close = LH51Close; +void Mapper309_Init(CartInfo *info) { + info->Power = M309Power; + info->Close = M309Close; GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); 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/mapper310.c b/src/mappers/mapper310.c similarity index 100% rename from src/boards/mapper310.c rename to src/mappers/mapper310.c diff --git a/src/boards/KS7013.c b/src/mappers/mapper312.c similarity index 64% rename from src/boards/KS7013.c rename to src/mappers/mapper312.c index e7fd1bf82..5fb9e16bd 100644 --- a/src/boards/KS7013.c +++ b/src/mappers/mapper312.c @@ -1,8 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2011 CaH4e3 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,6 +18,8 @@ * 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 312 - Kaiser 7013B + * UNIF UNL-KS7013B * Just another pirate cart with pirate mapper, instead of original MMC1 * Kaiser Highway Star * @@ -26,34 +28,33 @@ #include "mapinc.h" #include "latch.h" -static uint8 prg; +static uint8 reg; -static SFORMAT StateRegs[] = -{ - { &prg, 1, "REGS" }, +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, { 0 } }; static void Sync(void) { - setprg16(0x8000, prg); + setprg16(0x8000, reg); setprg16(0xc000, ~0); - setmirror((latch.data & 1) ^ 1); + setmirror((latch.data & 0x01) ^ 0x01); setchr8(0); } -static DECLFW(UNLKS7013BLoWrite) { - prg = V; +static DECLFW(M312LoWrite) { + reg = V; Sync(); } -static void UNLKS7013BPower(void) { - prg = 0; - LatchPower(); - SetWriteHandler(0x6000, 0x7FFF, UNLKS7013BLoWrite); +static void M312Power(void) { + reg = 0; + Latch_Power(); + SetWriteHandler(0x6000, 0x7FFF, M312LoWrite); } -void UNLKS7013B_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); - info->Power = UNLKS7013BPower; - AddExState(&StateRegs, ~0, 0, 0); +void Mapper312_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Power = M312Power; + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/resettxrom.c b/src/mappers/mapper313.c similarity index 51% rename from src/boards/resettxrom.c rename to src/mappers/mapper313.c index de947fece..d53eb20e7 100644 --- a/src/boards/resettxrom.c +++ b/src/mappers/mapper313.c @@ -2,7 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2019 Libretro Team - * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -28,58 +28,51 @@ #include "mapinc.h" #include "mmc3.h" -static uint8 submapper; +static uint8 reg; static void M313CW(uint32 A, uint8 V) { - /*FCEU_printf("CHR: A:%04x V:%02x 0:%02x\n", A, V, mmc3.expregs[0]);*/ - uint32_t bank; - switch (submapper) { - default: bank = (mmc3.expregs[0] << 7) | (V & 0x7F); break; - case 1: bank = (mmc3.expregs[0] << 7) | (V & 0x7F); break; - case 2: bank = (mmc3.expregs[0] << 8) | (V & 0xFF); break; - case 3: bank = (mmc3.expregs[0] << 8) | (V & 0xFF); break; - case 4: bank = (mmc3.expregs[0] << 7) | (V & 0x7F); break; + switch (iNESCart.submapper) { + default: setchr1(A, (reg << 7) | (V & 0x7F)); break; + case 1: setchr1(A, (reg << 7) | (V & 0x7F)); break; + case 2: setchr1(A, (reg << 8) | (V & 0xFF)); break; + case 3: setchr1(A, (reg << 8) | (V & 0xFF)); break; + case 4: setchr1(A, (reg << 7) | (V & 0x7F)); break; } - setchr1(A, bank); } static void M313PW(uint32 A, uint8 V) { - /*FCEU_printf("PRG: A:%04x V:%02x 0:%02x\n", A, V, mmc3.expregs[0]);*/ - uint32_t bank; - switch (submapper) { - default: bank = (mmc3.expregs[0] << 4) | (V & 0x0F); break; - case 1: bank = (mmc3.expregs[0] << 5) | (V & 0x1F); break; - case 2: bank = (mmc3.expregs[0] << 4) | (V & 0x0F); break; - case 3: bank = (mmc3.expregs[0] << 5) | (V & 0x1F); break; + switch (iNESCart.submapper) { + default: setprg8(A, (reg << 4) | (V & 0x0F)); break; + case 1: setprg8(A, (reg << 5) | (V & 0x1F)); break; + case 2: setprg8(A, (reg << 4) | (V & 0x0F)); break; + case 3: setprg8(A, (reg << 5) | (V & 0x1F)); break; case 4: - if (mmc3.expregs[0] == 0) - bank = (mmc3.expregs[0] << 5) | (V & 0x1F); - else - bank = (mmc3.expregs[0] << 4) | (V & 0x0F); + if (reg == 0) { + setprg8(A, (reg << 5) | (V & 0x1F)); + } else { + setprg8(A, (reg << 4) | (V & 0x0F)); + } break; } - setprg8(A, bank); } static void M313Reset(void) { - mmc3.expregs[0]++; - mmc3.expregs[0] &= 0x03; - MMC3RegReset(); + reg++; + reg &= 0x03; + MMC3_Reset(); } static void M313Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); + reg = 0; + MMC3_Power(); } /* NES 2.0 313, UNIF BMC-RESET-TXROM */ -void BMCRESETTXROM_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 8, 0); - mmc3.cwrap = M313CW; - mmc3.pwrap = M313PW; - submapper = info->submapper; +void Mapper313_Init(CartInfo *info) { + MMC3_Init(info, 8, 0); + MMC3_cwrap = M313CW; + MMC3_pwrap = M313PW; info->Power = M313Power; info->Reset = M313Reset; - AddExState(&mmc3.expregs[0], 1, 0, "EXPR"); - AddExState(&submapper, 1, 0, "SUBM"); + AddExState(®, 1, 0, "EXPR"); } diff --git a/src/boards/bmc64in1nr.c b/src/mappers/mapper314.c similarity index 56% rename from src/boards/bmc64in1nr.c rename to src/mappers/mapper314.c index 5ab484c19..ce2dd47b7 100644 --- a/src/boards/bmc64in1nr.c +++ b/src/mappers/mapper314.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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,60 +26,56 @@ static uint8 regs[4]; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { regs, 4, "REGS" }, { 0 } }; static void Sync(void) { + uint8 prg = regs[1] & 0x3F; + if (regs[0] & 0x80) { /* NROM mode */ - if (regs[1] & 0x80) - setprg32(0x8000, regs[1] & 0x3F); - else { - int bank = ((regs[1] & 0x3F) << 1) | ((regs[1] >> 6) & 1); - setprg16(0x8000, bank); - setprg16(0xC000, bank); + if (regs[1] & 0x80) { + setprg32(0x8000, prg); + } else { + setprg16(0x8000, (prg << 1) | ((regs[1] >> 6) & 0x01)); + setprg16(0xC000, (prg << 1) | ((regs[1] >> 6) & 0x01)); } } else { /* UNROM mode */ - setprg16(0x8000, (regs[1] << 1) | (latch.data & 7)); - setprg16(0xC000, (regs[1] << 1) | 7); + setprg16(0x8000, (prg << 1) | (latch.data & 0x07)); + setprg16(0xC000, (prg << 1) | 0x07); } - if (regs[0] & 0x20) - setmirror(MI_H); - else - setmirror(MI_V); - setchr8((regs[2] << 2) | ((regs[0] >> 1) & 3)); + setchr8((regs[2] << 2) | ((regs[0] >> 1) & 0x03)); + setmirror(((regs[0] >> 5) & 0x01) ^ 0x01); + } -static DECLFW(BMC64in1nrWriteLo) { - A &= 3; - if (A == 3) - A = 1; /* K-42001's "Aladdin III" */ - regs[A & 3] = V; +static DECLFW(M314Write) { + A &= 0x03; + if (A == 0x03) A = 0x01; /* K-42001's "Aladdin III" */ + regs[A] = V; Sync(); } -static void BMC64in1nrPower(void) { +static void M314Reset(void) { + /* Reset returns to menu */ regs[0] = 0x80; regs[1] = 0x43; regs[2] = regs[3] = 0; - LatchPower(); - SetWriteHandler(0x5000, 0x5FFF, BMC64in1nrWriteLo); + Sync(); } -static void BMC64in1nrReset(void) { - /* Reset returns to menu */ +static void M314Power(void) { regs[0] = 0x80; regs[1] = 0x43; regs[2] = regs[3] = 0; - Sync(); - + Latch_Power(); + SetWriteHandler(0x5000, 0x5FFF, M314Write); } -void BMC64in1nr_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); - info->Power = BMC64in1nrPower; - info->Reset = BMC64in1nrReset; - AddExState(&StateRegs, ~0, 0, 0); +void Mapper314_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, TRUE); + info->Power = M314Power; + info->Reset = M314Reset; + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper315.c b/src/mappers/mapper315.c new file mode 100644 index 000000000..feb9fe235 --- /dev/null +++ b/src/mappers/mapper315.c @@ -0,0 +1,81 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent + * + * 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 uint8 reg; + +static void M315CCW(uint32 A, uint8 V) { + uint16 mask = 0xFF; + uint16 base = reg << 8; + + V = ((reg << 6) & 0x80) | ((reg << 3) & 0x40) | (V & 0xFF); + setchr1(A, (base & ~mask) | (V & mask)); +} + +static void M315CPW(uint32 A, uint8 V) { + uint16 mask = 0x0F; + uint16 base = reg << 3; + + if ((reg & 0x06) == 0x06) { /* GNROM-like */ + setprg8(0x8000, (base & ~mask) | ((mmc3.reg[6] & ~0x02) & mask)); + setprg8(0xA000, (base & ~mask) | ((mmc3.reg[7] & ~0x02) & mask)); + setprg8(0xC000, (base & ~mask) | ((mmc3.reg[6] | 0x02) & mask)); + setprg8(0xE000, (base & ~mask) | ((mmc3.reg[7] | 0x02) & mask)); + } else { + setprg8(A, (base & ~mask) | (V & mask)); + } +} + +static DECLFW(M315CWrite) { + if (MMC3_WramIsWritable()) { + reg = V; + MMC3_FixPRG(); + MMC3_FixCHR(); + } +} + +static void M315CReset(void) { + reg = 0; + MMC3_Reset(); +} + +static void M315CPower(void) { + reg = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M315CWrite); +} + +void Mapper315_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_pwrap = M315CPW; + MMC3_cwrap = M315CCW; + info->Power = M315CPower; + info->Reset = M315CReset; + AddExState(®, 1, 0, "EXPR"); +} diff --git a/src/boards/mapper319.c b/src/mappers/mapper319.c similarity index 50% rename from src/boards/mapper319.c rename to src/mappers/mapper319.c index b30af14f6..2b44cb632 100644 --- a/src/boards/mapper319.c +++ b/src/mappers/mapper319.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -23,51 +24,69 @@ #include "latch.h" static uint8 reg[2]; -static uint8 pad; +static uint8 dipsw; static SFORMAT StateRegs[] = { { reg, 2, "REG" }, - { &pad, 1, "PAD" }, + { &dipsw, 1, "DPSW" }, { 0 } }; static void M319Sync(void) { - if (reg[1] & 0x40) - setprg32(0x8000, (reg[1] >> 3) & 3); - else { - setprg16(0x8000, ((reg[1] >> 2) & 6) | ((reg[1] >> 5) & 1)); - setprg16(0xC000, ((reg[1] >> 2) & 6) | ((reg[1] >> 5) & 1)); + uint16 bank, mask; + + if (iNESCart.CRC32 == 0xE5B9AB1F || iNESCart.PRGCRC32 == 0xC25FD362) { + /* The publicly-available UNIF (UNL-HP898F) ROM file of Prima Soft 9999999-in-1 has + * the order of the 16 KiB PRG-ROM banks slightly mixed up, so that the + * PRG A14 mode bit operates on A16 instead of A14. To obtain the + * correct bank order, use UNIF 16 KiB PRG banks 0, 4, 1, 5, 2, 6, 3, 7. + */ + bank = (reg[1] >> 3) & 7; + mask = (reg[1] >> 4) & 4; + + setprg16(0x8000, bank & ~mask); + setprg16(0xC000, bank | mask); + } else { + bank = ((reg[1] >> 2) & 0x06) | ((reg[1] >> 5) & 0x01); + mask = (reg[1] >> 6) & 0x01; + + setprg16(0x8000, (bank & ~mask)); + setprg16(0xC000, (bank | mask)); } - setchr8(((reg[0] >> 4) & ~((reg[0] << 2) & 4)) | ((latch.data << 2) & ((reg[0] << 2) & 4))); + + bank = reg[0] >> 4; + mask = (reg[0] << 2) & 0x04; + + setchr8((bank & ~mask) | ((latch.data << 2) & mask)); setmirror(reg[1] >> 7); } -static DECLFR(M319ReadPad) { - return pad; +static DECLFR(M319ReadDIP) { + return dipsw; } -static DECLFW(M319WriteReg) { - reg[A >> 2 & 1] = V; +static DECLFW(M319Write) { + reg[(A >> 2) & 0x01] = V; M319Sync(); } static void M319Reset(void) { reg[0] = reg[1] = 0; - pad ^= 0x40; + dipsw ^= 0x40; M319Sync(); } static void M319Power(void) { - reg[0] = reg[1] = pad = 0; - LatchPower(); - SetReadHandler(0x5000, 0x5FFF, M319ReadPad); - SetWriteHandler(0x6000, 0x7FFF, M319WriteReg); + reg[0] = reg[1] = dipsw = 0; + Latch_Power(); + SetReadHandler(0x5000, 0x5FFF, M319ReadDIP); + SetWriteHandler(0x6000, 0x7FFF, M319Write); } void Mapper319_Init(CartInfo *info) { Latch_Init(info, M319Sync, NULL, 0, 0); info->Power = M319Power; info->Reset = M319Reset; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/bmc830425C4391t.c b/src/mappers/mapper320.c similarity index 72% rename from src/boards/bmc830425C4391t.c rename to src/mappers/mapper320.c index 0d8d9a391..0fe0bb324 100644 --- a/src/boards/bmc830425C4391t.c +++ b/src/mappers/mapper320.c @@ -29,33 +29,30 @@ #include "latch.h" static void Sync(void) { - if (latch.addr & 0x10) { /* UNROM */ - setprg16(0x8000, ((latch.addr << 3) & ~7) | (latch.data & 7)); - setprg16(0xC000, ((latch.addr << 3) & ~7) | 7); - } else { /* UOROM */ - setprg16(0x8000, ((latch.addr << 3) & ~7) | (latch.data & 0x0F)); - setprg16(0xC000, ((latch.addr << 3) & ~7) | 0x0F); - } + uint16 mask = (latch.addr & 0x10) ? 0x07 : 0x0F; + uint16 base = latch.addr << 3; + + setprg16(0x8000, base | (latch.data & mask)); + setprg16(0xC000, base | (latch.data & mask) | ((~latch.addr >> 1) & 0x08) | 0x07); setchr8(0); setmirror(MI_V); } static DECLFW(M320Write) { if ((A & 0xFFE0) == 0xF0E0) { - LatchWrite(A, V); - } else { - latch.data = V; - Sync(); + latch.addr = A; } + latch.data = V; + Sync(); } -static void M320Power() { - LatchPower(); +static void M320Power(void) { + Latch_Power(); SetWriteHandler(0x8000, 0xFFFF, M320Write); } -void BMC830425C4391T_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); +void Mapper320_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); info->Power = M320Power; - info->Reset = LatchHardReset; + info->Reset = Latch_RegReset; } diff --git a/src/mappers/mapper322.c b/src/mappers/mapper322.c new file mode 100644 index 000000000..d34e95194 --- /dev/null +++ b/src/mappers/mapper322.c @@ -0,0 +1,97 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent + * + * 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 uint8 reg; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; + +static void M322CW(uint32 A, uint8 V) { + if (reg & 0x20) { + uint16 base = ((reg >> 4) & 0x04) | ((reg >> 3) & 0x03); + + if (reg & 0x80) { + setchr1(A, (base << 8) | (V & 0xFF)); + } else { + setchr1(A, (base << 7) | (V & 0x7F)); + } + } else { + setchr1(A, (V & 0x7F)); + } +} + +static void M322PW(uint32 A, uint8 V) { + uint16 base = ((reg >> 4) & 0x04) | ((reg >> 3) & 0x03); + + if (reg & 0x20) { + if (reg & 0x80) { + setprg8(A, (base << 5) | (V & 0x1F)); + } else { + setprg8(A, (base << 4) | (V & 0x0F)); + } + } else { + if (reg & 0x03) { + setprg32(0x8000, (base << 3) | ((reg >> 1) & 0x03)); + } else { + setprg16(0x8000, (base << 3) | (reg & 0x07)); + setprg16(0xC000, (base << 3) | (reg & 0x07)); + } + } +} + +static DECLFW(M322Write) { + if (MMC3_WramIsWritable()) { + reg = A & 0xFF; + MMC3_FixPRG(); + MMC3_FixCHR(); + } +} + +static void M322Power(void) { + reg = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M322Write); +} + +static void M322Reset(void) { + reg = 0; + MMC3_Reset(); +} + +void Mapper322_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_pwrap = M322PW; + MMC3_cwrap = M322CW; + info->Power = M322Power; + info->Reset = M322Reset; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper323.c b/src/mappers/mapper323.c new file mode 100644 index 000000000..3675e07c0 --- /dev/null +++ b/src/mappers/mapper323.c @@ -0,0 +1,74 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 323 - UNIF FARID_SLROM_8-IN-1 */ + +#include "mapinc.h" +#include "mmc1.h" + +static uint8 reg; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; + +static void M323PW(uint32 A, uint8 V) { + uint8 mask = 0x07; + uint8 base = reg >> 1; + + setprg16(A, (base & ~mask) | (V & mask)); +} + +static void M323CW(uint32 A, uint8 V) { + uint16 mask = 0x1F; + uint16 base = reg << 1; + + setchr4(A, (base & ~mask) | (V & mask)); +} + +static DECLFW(M323Write) { + if (!(mmc1.reg[3] & 0x10) && !(reg & 0x08)) { + reg = V; + MMC1_FixCHR(); + MMC1_FixPRG(); + MMC1_FixMIR(); + } +} + +static void M323Power(void) { + reg = 0; + MMC1_Power(); + SetWriteHandler(0x6000, 0x7FFF, M323Write); +} + +static void M323Reset(void) { + reg = 0; + MMC1_Reset(); +} + +void Mapper323_Init(CartInfo *info) { + MMC1_Init(info, 0, 0); + MMC1_cwrap = M323CW; + MMC1_pwrap = M323PW; + info->Power = M323Power; + info->Reset = M323Reset; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/faridunrom.c b/src/mappers/mapper324.c similarity index 76% rename from src/boards/faridunrom.c rename to src/mappers/mapper324.c index 29d1c42a2..9b694a509 100644 --- a/src/boards/faridunrom.c +++ b/src/mappers/mapper324.c @@ -2,7 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2019 Libretro Team - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -33,22 +33,22 @@ static void Sync(void) { setprg16(0xC000, ((latch.data & 0x70) >> 1) | 0x07 ); } -static DECLFW(FARIDUNROMWrite) { +static DECLFW(M324Write) { if ((V & 0x80) && !(latch.data & 0x80) && !(latch.data & 0x08)) { - LatchWrite(A, V); + Latch_Write(A, V); } else { - latch.data = (latch.data & ~7) | (V & 7); + latch.data = (latch.data & ~0x07) | (V & 0x07); Sync(); } } -static void FARIDUNROMPower(void) { - LatchPower(); - SetWriteHandler(0x8000, 0xFFFF, FARIDUNROMWrite); +static void M324Power(void) { + Latch_Power(); + SetWriteHandler(0x8000, 0xFFFF, M324Write); } -void FARIDUNROM_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 1); - info->Power = FARIDUNROMPower; - info->Reset = LatchHardReset; +void Mapper324_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, TRUE); + info->Power = M324Power; + info->Reset = Latch_RegReset; } diff --git a/src/mappers/mapper325.c b/src/mappers/mapper325.c new file mode 100644 index 000000000..561043dcb --- /dev/null +++ b/src/mappers/mapper325.c @@ -0,0 +1,51 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 325 + * UNIF UNL-MALISB + */ + +#include "mapinc.h" +#include "mmc3.h" + +static void M325PW(uint32 A, uint8 V) { + setprg8(A, ((V << 1) & 0x08) | ((V >> 1) & 0x04) | (V & 0x03)); +} + +static void M325CW(uint32 A, uint8 V) { + setchr1(A, (V & 0xDD) | ((V << 4) & 0x20) | ((V >> 4) & 0x02)); +} + +static DECLFW(M325Write) { + A = (A & 0xFFFE) | ((A >> 3) & 1); + MMC3_Write(A, V); +} + +static void M325Power(void) { + MMC3_Power(); + SetWriteHandler(0x8000, 0xFFFF, M325Write); +} + +void Mapper325_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_pwrap = M325PW; + MMC3_cwrap = M325CW; + info->Power = M325Power; +} diff --git a/src/boards/mapper326.c b/src/mappers/mapper326.c similarity index 55% rename from src/boards/mapper326.c rename to src/mappers/mapper326.c index 7ea3d556f..eec1b010d 100644 --- a/src/boards/mapper326.c +++ b/src/mappers/mapper326.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2022 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -24,84 +25,65 @@ #include "mapinc.h" -static uint8 PRG[3], CHR[8], NTAPage[4]; +static uint8 prg[4], chr[8], nt[4]; -static SFORMAT StateRegs[] = -{ - { PRG, 3, "PRG" }, - { CHR, 8, "CHR" }, - { NTAPage, 4, "NT" }, +static SFORMAT StateRegs[] = { + { prg, 4, "PREG" }, + { chr, 8, "CREG" }, + { nt, 4, "NTAR" }, { 0 } }; -static void SyncPRG(void) { - setprg8(0x8000, PRG[0]); - setprg8(0xA000, PRG[1]); - setprg8(0xC000, PRG[2]); - setprg8(0xE000, ~0); -} - -static void DoCHR(int x, uint8 V) { - CHR[x] = V; - setchr1(x << 10, V); -} +static void Sync(void) { + int i; -static void FixCHR(void) { - int x; - for (x = 0; x < 8; x++) - DoCHR(x, CHR[x]); -} - -static void FASTAPASS(2) DoNTARAM(int w, uint8 V) { - NTAPage[w] = V; - setntamem(NTARAM + ((V & 1) << 10), 1, w); -} - -static void FixNTAR(void) { - int x; - for (x = 0; x < 4; x++) - DoNTARAM(x, NTAPage[x]); + for (i = 0; i < 4; i++) setprg8(0x8000 + (i << 13), prg[i]); + for (i = 0; i < 8; i++) setchr1(i << 10, chr[i]); + for (i = 0; i < 3; i++) setntamem(NTARAM + 0x400 * (nt[i] & 0x01), 1, i); } static DECLFW(M326Write) { switch (A & 0xE010) { - case 0x8000: - PRG[0] = V; - SyncPRG(); - break; - case 0xA000: - PRG[1] = V; - SyncPRG(); - break; - case 0xC000: - PRG[2] = V; - SyncPRG(); - break; + case 0x8000: prg[0] = V; break; + case 0xA000: prg[1] = V; break; + case 0xC000: prg[2] = V; break; + default: break; + } + + switch (A & 0x1F) { + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + chr[A & 0x07] = V; + break; + case 0x18: case 0x19: case 0x1A: case 0x1B: + nt[A & 0x03] = V; + break; + default: + break; } - A &= 0x801F; - if ((A >= 0x8010) && (A <= 0x8017)) - DoCHR(A - 0x8010, V); - else if ((A >= 0x8018) && (A <= 0x801B)) - DoNTARAM(A - 0x8018, V); + Sync(); } static void M326Power(void) { - SyncPRG(); - FixCHR(); - FixNTAR(); + int i; + + for (i = 0; i < 4; i++) prg[i] = 0xFC | i; + for (i = 0; i < 8; i++) chr[i] = i; + for (i = 0; i < 4; i++) nt[i] = (i >> 1) & 0x01; + + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0xFFFF, M326Write); } static void StateRestore(int version) { - SyncPRG(); - FixCHR(); - FixNTAR(); + Sync(); } void Mapper326_Init(CartInfo *info) { info->Power = M326Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/et-100.c b/src/mappers/mapper327.c similarity index 61% rename from src/boards/et-100.c rename to src/mappers/mapper327.c index 2ed757cc9..2f3b9bdce 100644 --- a/src/boards/et-100.c +++ b/src/mappers/mapper327.c @@ -1,10 +1,12 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2015 Cluster * http://clusterrr.com * clusterrr@clusterrr.com * + * Copyright (C) 2023-2024 negativeExponent + * * 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 @@ -43,64 +45,71 @@ #include "mapinc.h" #include "mmc3.h" +static uint8 reg; + static uint8 *CHRRAM = NULL; static uint32 CHRRAMSize; -static void BMC1024CA1PW(uint32 A, uint8 V) { - if (mmc3.expregs[0] & 8) - setprg8(A, (V & 0x1F) | ((mmc3.expregs[0] & 7) << 4)); - else - setprg8(A, (V & 0x0F) | ((mmc3.expregs[0] & 7) << 4)); +static void M327PW(uint32 A, uint8 V) { + uint8 base = (reg << 4) & 0x70; + uint8 mask = (reg & 0x08) ? 0x1F : 0x0F; + + setprg8(A, (base & ~mask) | (V & mask)); } -static void BMC1024CA1CW(uint32 A, uint8 V) { - if ((mmc3.expregs[0] >> 4) & 1) - setchr1r(0x10, A, V); - else if (mmc3.expregs[0] & 0x20) - setchr1(A, V | ((mmc3.expregs[0] & 7) << 7)); - else - setchr1(A, (V & 0x7F) | ((mmc3.expregs[0] & 7) << 7)); +static void M327CW(uint32 A, uint8 V) { + if (reg & 0x10) { + setchr8r(0x10, 0); + } else { + uint16 base = (reg << 7) & 0x380; + uint16 mask = (reg & 0x20) ? 0xFF : 0x7F; + + setchr1(A, base | (V & mask)); + } } -static DECLFW(BMC1024CA1Write) { - if (MMC3CanWriteToWRAM()) { +static DECLFW(M327Write) { + if (MMC3_WramIsWritable()) { CartBW(A, V); - if ((mmc3.expregs[0] & 7) == 0) { - mmc3.expregs[0] = A & 0x3F; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + if ((reg & 7) == 0) { + reg = A & 0x3F; + MMC3_FixPRG(); + MMC3_FixCHR(); } } } -static void BMC1024CA1Reset(void) { - mmc3.expregs[0] = 0; - MMC3RegReset(); +static void M327Reset(void) { + reg = 0; + MMC3_Reset(); } -static void BMC1024CA1Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, BMC1024CA1Write); +static void M327Power(void) { + reg = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M327Write); } -static void BMC1024CA1Close(void) { - GenMMC3Close(); - if (CHRRAM) +static void M327Close(void) { + MMC3_Close(); + if (CHRRAM) { FCEU_gfree(CHRRAM); + } CHRRAM = NULL; } -void BMC1024CA1_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 8, 0); +void Mapper327_Init(CartInfo *info) { + MMC3_Init(info, 8, 0); + MMC3_pwrap = M327PW; + MMC3_cwrap = M327CW; + + info->Power = M327Power; + info->Reset = M327Reset; + info->Close = M327Close; + AddExState(®, 1, 0, "EXPR"); + CHRRAMSize = 8192; CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSize); SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSize, 1); AddExState(CHRRAM, CHRRAMSize, 0, "CHRR"); - mmc3.pwrap = BMC1024CA1PW; - mmc3.cwrap = BMC1024CA1CW; - info->Power = BMC1024CA1Power; - info->Reset = BMC1024CA1Reset; - info->Close = BMC1024CA1Close; - AddExState(mmc3.expregs, 1, 0, "EXPR"); } diff --git a/src/boards/rt-01.c b/src/mappers/mapper328.c similarity index 78% rename from src/boards/rt-01.c rename to src/mappers/mapper328.c index 866bb9200..286ef204b 100644 --- a/src/boards/rt-01.c +++ b/src/mappers/mapper328.c @@ -24,33 +24,28 @@ * */ +/* NES 2.0 Mapper 328 - UNL-RT-01 */ + #include #include "mapinc.h" -static DECLFR(UNLRT01Read) { -#if 0 - u16 i, prot_areas[2][2] = { - { 0x8E80, 0x8EFF }, - { 0xFE80, 0xFEFF }, - }; -#endif - if(((A >= 0xCE80) && (A < 0xCF00)) || - ((A >= 0xFE80) && (A < 0xFF00))) { +static DECLFR(M328Read) { + if (((A >= 0xCE80) && (A < 0xCF00)) || ((A >= 0xFE80) && (A < 0xFF00))) { return 0xF2 | (rand() & 0x0D); - } else - return CartBR(A); + } + return CartBR(A); } -static void UNLRT01Power(void) { +static void M328Power(void) { setprg16(0x8000, 0); setprg16(0xC000, 0); setchr2(0x0000,0); setchr2(0x0800,0); setchr2(0x1000,0); setchr2(0x1800,0); - SetReadHandler(0x8000, 0xFFFF, UNLRT01Read); + SetReadHandler(0x8000, 0xFFFF, M328Read); } -void UNLRT01_Init(CartInfo *info) { - info->Power = UNLRT01Power; +void Mapper328_Init(CartInfo *info) { + info->Power = M328Power; } diff --git a/src/boards/edu2000.c b/src/mappers/mapper329.c similarity index 79% rename from src/boards/edu2000.c rename to src/mappers/mapper329.c index 50cc1a8ee..fda93319a 100644 --- a/src/boards/edu2000.c +++ b/src/mappers/mapper329.c @@ -1,8 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2006 CaH4e3 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -20,20 +20,18 @@ * */ -/* NES 2.0 Mapper 329 - * UNL-EDU2000 - */ +/* NES 2.0 Mapper 329 - UNL-EDU2000 */ #include "mapinc.h" #include "latch.h" static void Sync(void) { - setchr8(0); setprg8r(0x10, 0x6000, latch.data >> 6); setprg32(0x8000, latch.data & 0x1F); - setmirror(((latch.data >> 5) & 1) ^ 1); + setchr8(0); + setmirror(((latch.data >> 5) & 0x01) ^ 0x01); } -void UNLEDU2000_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); +void Mapper329_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); } diff --git a/src/boards/mapper330.c b/src/mappers/mapper330.c similarity index 55% rename from src/boards/mapper330.c rename to src/mappers/mapper330.c index 642166761..bf44bcd33 100644 --- a/src/boards/mapper330.c +++ b/src/mappers/mapper330.c @@ -1,4 +1,4 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2022 @@ -23,63 +23,33 @@ */ #include "mapinc.h" +#include "n163sound.h" -static uint8 *WRAM; - -static uint8 PRG[3], CHR[8], NTAPage[4]; static uint8 IRQa; static uint16 IRQCount; -static SFORMAT StateRegs[] = -{ - { PRG, 3, "PRG" }, - { CHR, 8, "CHR" }, - { NTAPage, 4, "NT" }, - { &IRQa, 1, "IRQA" }, - { &IRQCount, 2, "IRQC" }, +static uint8 prg[4], chr[8], nt[4]; + +static SFORMAT StateRegs[] = { + { prg, 4, "PREG" }, + { chr, 8, "CREG" }, + { nt, 4, "NTAR" }, { 0 } }; -static void SyncPRG(void) { - setprg8(0x8000, PRG[0]); - setprg8(0xA000, PRG[1]); - setprg8(0xC000, PRG[2]); - setprg8(0xE000, ~0); -} - -static void DoCHR(int x, uint8 V) { - CHR[x] = V; - setchr1(x << 10, V); -} - -static void FixCHR(void) { - int x; - for (x = 0; x < 8; x++) - DoCHR(x, CHR[x]); -} +static void Sync(void) { + int i; -static void FASTAPASS(2) DoNTARAM(int w, uint8 V) { - NTAPage[w] = V; - setntamem(NTARAM + ((V & 1) << 10), 1, w); -} + setprg8r(0x10, 0x6000, 0); + setprg8(0xE000, ~0); -static void FixNTAR(void) { - int x; - for (x = 0; x < 4; x++) - DoNTARAM(x, NTAPage[x]); + for (i = 0; i < 3; i++) setprg8(0x8000 + (i << 13), prg[i]); + for (i = 0; i < 8; i++) setchr1(i << 10, chr[i]); + for (i = 0; i < 3; i++) setntamem(NTARAM + 0x400 * (nt[i] & 0x01), 1, i); } -static DECLFW(M330Write) { - if (!(A & 0x400)) { - if (A >= 0x8000 && A <= 0xB800) - DoCHR((A - 0x8000) >> 11, V); - else if (A >= 0xC000 && A <= 0xD800) - DoNTARAM((A - 0xC000) >> 11, V); - else if (A >= 0xE000 && A <= 0xF000) { - PRG[(A - 0xE000) >> 11] = V; - SyncPRG(); - } - } else if ((A < 0xC000) && !(A & 0x4000)) { +static DECLFW(M330WriteCHR) { + if ((A & 0x400) && !(A & 0x4000)) { if (A & 0x2000) { IRQCount &= 0x00FF; IRQCount |= (V & 0x7F) << 8; @@ -89,27 +59,54 @@ static DECLFW(M330Write) { IRQCount &= 0xFF00; IRQCount |= V; } + } else { + int index = (A >> 11) & 0x07; + chr[index] = V; + Sync(); + } +} + +static DECLFW(M330WriteNT) { + if (!(A & 0x400)) { + int index = (A >> 11) & 0x03; + nt[index] = V; + Sync(); + } +} + +static DECLFW(M330WritePRG) { + if ((A >= 0xF000) && (A & 0x800)) { + N163Sound_Write(A, V); + } else if (!(A & 0x400)) { + int index = (A >> 11) & 0x03; + prg[index] = V; + Sync(); } } static void M330Power(void) { int i; - for (i = 0; i < 3; i++) - PRG[i] = i; - for (i = 0; i < 8; i++) - CHR[i] = i; - for (i = 0; i < 4; i++) - NTAPage[i] = ~0; - IRQa = 0; - IRQCount = 0; - SyncPRG(); - FixCHR(); - FixNTAR(); + + for (i = 0; i < 4; i++) prg[i] = i; + for (i = 0; i < 8; i++) chr[i] = i; + for (i = 0; i < 4; i++) nt[i] = (i >> 1) & 0x01; + + IRQa = IRQCount = 0; + + Sync(); + + SetReadHandler(0x4800, 0x4FFF, N163Sound_Read); + SetWriteHandler(0x4800, 0x4FFF, N163Sound_Write); + SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, M330Write); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + + SetWriteHandler(0x8000, 0xBFFF, M330WriteCHR); + SetWriteHandler(0xC000, 0xDFFF, M330WriteNT); + SetWriteHandler(0xE000, 0xFFFF, M330WritePRG); } -static void FP_FASTAPASS(1) M330IRQHook(int a) { +static void M330IRQHook(int a) { if (IRQa) { IRQCount += a; if (IRQCount > 0x7FFF) { @@ -121,17 +118,18 @@ static void FP_FASTAPASS(1) M330IRQHook(int a) { } static void StateRestore(int version) { - SyncPRG(); - FixCHR(); - FixNTAR(); + Sync(); } void Mapper330_Init(CartInfo *info) { info->Power = M330Power; MapIRQHook = M330IRQHook; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); + WRAM = (uint8 *)FCEU_gmalloc(8192); SetupCartPRGMapping(0x10, WRAM, 8192, 1); AddExState(WRAM, 8192, 0, "WRAM"); + + N163Sound_ESI(); } diff --git a/src/mappers/mapper331.c b/src/mappers/mapper331.c new file mode 100644 index 000000000..a8deb637f --- /dev/null +++ b/src/mappers/mapper331.c @@ -0,0 +1,84 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2009 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + * 7-in-1 Darkwing Duck, Snake, MagicBlock (PCB marked as "12 in 1") + * 12-in-1 1991 New Star Co. Ltd. + * + */ + +#include "mapinc.h" + +static uint8 reg[3]; +static uint8 PPUCHRBus; + +static SFORMAT StateRegs[] = { + { reg, 3, "REGS" }, + { 0 } +}; + +static void Sync(void) { + uint8 base = (reg[2] & 0x03) << 3; + + if (reg[2] & 8) { + setprg16(0x8000, base | ((reg[PPUCHRBus] & 0x06) & ~0x01)); /* actually, both 0 and 1 registers used, but they will switch each PA12 transition */ + setprg16(0xc000, base | ((reg[PPUCHRBus] & 0x06) | 0x01)); /* if bits are different for both registers, so they must be programmed strongly the same! */ + } else { + setprg16(0x8000, base | (reg[PPUCHRBus] & 0x07)); + setprg16(0xc000, base | 0x07); + } + setchr4(0x0000, (base << 2) | (reg[0] >> 3)); + setchr4(0x1000, (base << 2) | (reg[1] >> 3)); + setmirror(((reg[2] & 4) >> 2) ^ 1); +} + +static DECLFW(M331Write) { + switch (A & 0xE000) { + case 0xA000: reg[0] = V; Sync(); break; + case 0xC000: reg[1] = V; Sync(); break; + case 0xE000: reg[2] = V; Sync(); break; + } +} + +static void M331Power(void) { + reg[0] = reg[1] = reg[2] = 0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M331Write); +} + +static void StateRestore(int version) { + Sync(); +} + +static void M331PPUHook(uint32 A) { + uint8 bank = (A & 0x1000) >> 12; + + if ((PPUCHRBus != bank) && ((A & 0x3000) != 0x2000)) { + PPUCHRBus = bank; + Sync(); + } +} + +void Mapper331_Init(CartInfo *info) { + info->Power = M331Power; + PPU_hook = M331PPUHook; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper332.c b/src/mappers/mapper332.c new file mode 100644 index 000000000..b09f4ae32 --- /dev/null +++ b/src/mappers/mapper332.c @@ -0,0 +1,89 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023 + * + * 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 + * NES 2.0 Mapper 332 + * BMC-WS Used for Super 40-in-1 multicart + * https://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_332 */ + +#include "mapinc.h" +#include "latch.h" + +static uint8 reg[2], dipsw; + +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, + { &dipsw, 1, "DPSW" }, + { 0 } +}; + +static void Sync(void) { + uint32 prg = ((reg[0] >> 3) & 0x08) | (reg[0] & 0x07); + uint32 chr = ((reg[0] >> 3) & 0x08) | (reg[1] & 0x07); + uint32 mask = (reg[1] & 0x10) ? 0 : (reg[1] & 0x20) ? 1 : 3; + + if (reg[0] & 0x08) { + setprg16(0x8000, prg); + setprg16(0xc000, prg); + } else { + setprg32(0x8000, prg >> 1); + } + setchr8((chr & ~mask) | (latch.data & mask)); + setmirror(((reg[0] >> 4) & 0x01) ^ 0x01); +} + +static DECLFR(M332Read) { + if ((reg[1] >> 6) & (dipsw & 0x03)) { + return cpu.openbus; + } + return CartBR(A); +} + +static DECLFW(M332Write) { + if (!(reg[0] & 0x20)) { + reg[A & 0x01] = V; + Sync(); + } +} + +static void M332Reset(void) { + dipsw++; /* Soft-resetting cycles through solder pad or DIP switch settings */ + if (dipsw == 3) { + dipsw = 0; /* Only 00b, 01b and 10b settings are valid */ + } + /* Always reset to menu */ + reg[0] = reg[1] = 0; + Latch_RegReset(); +} + +static void M332Power(void) { + dipsw = 0; + reg[0] = reg[1] = 0; + Latch_Power(); + SetReadHandler(0x8000, 0xFFFF, M332Read); + SetWriteHandler(0x6000, 0x7FFF, M332Write); +} + +void Mapper332_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Reset = M332Reset; + info->Power = M332Power; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/bmc8in1.c b/src/mappers/mapper333.c similarity index 58% rename from src/boards/bmc8in1.c rename to src/mappers/mapper333.c index 1eef14529..a489c6753 100644 --- a/src/boards/bmc8in1.c +++ b/src/mappers/mapper333.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2016 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -27,41 +28,45 @@ #include "mapinc.h" #include "mmc3.h" -static void BMC8IN1CW(uint32 A, uint8 V) { - setchr1(A, ((mmc3.expregs[0] & 0xC) << 5) | (V & 0x7F)); +static uint8 reg; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; + +static void M333CW(uint32 A, uint8 V) { + setchr1(A, ((reg & 0x0C) << 5) | (V & 0x7F)); } -static void BMC8IN1PW(uint32 A, uint8 V) { - if (mmc3.expregs[0] & 0x10) { /* MMC3 mode */ - setprg8(A, ((mmc3.expregs[0] & 0xC) << 2) | (V & 0xF)); +static void M333PW(uint32 A, uint8 V) { + if (reg & 0x10) { /* MMC3 mode */ + setprg8(A, ((reg & 0x0C) << 2) | (V & 0x0F)); } else { - setprg32(0x8000, mmc3.expregs[0] & 0xF); + setprg32(0x8000, reg & 0x0F); } } -static DECLFW(BMC8IN1Write) { +static DECLFW(M333Write) { if (A & 0x1000) { - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + reg = V; + MMC3_FixPRG(); + MMC3_FixCHR(); } else { - if (A < 0xC000) - MMC3_CMDWrite(A, V); - else - MMC3_IRQWrite(A, V); + MMC3_Write(A, V); } } -static void BMC8IN1Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); - SetWriteHandler(0x8000, 0xFFFF, BMC8IN1Write); +static void M333Power(void) { + reg = 0; + MMC3_Power(); + SetWriteHandler(0x8000, 0xFFFF, M333Write); } -void BMC8IN1_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 128, 0, 0); - mmc3.cwrap = BMC8IN1CW; - mmc3.pwrap = BMC8IN1PW; - info->Power = BMC8IN1Power; - AddExState(mmc3.expregs, 1, 0, "EXPR"); +void Mapper333_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_cwrap = M333CW; + MMC3_pwrap = M333PW; + info->Power = M333Power; + AddExState(&StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper334.c b/src/mappers/mapper334.c similarity index 69% rename from src/boards/mapper334.c rename to src/mappers/mapper334.c index a9afec3df..c2162af42 100644 --- a/src/boards/mapper334.c +++ b/src/mappers/mapper334.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -23,45 +23,51 @@ #include "mapinc.h" #include "mmc3.h" -static uint8 dipswitch; +static uint8 reg; +static uint8 dipsw; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { &dipsw, 1, "DPSW" }, + { 0 } +}; static void M334PW(uint32 A, uint8 V) { - setprg32(0x8000, mmc3.expregs[0] >> 1); + setprg32(0x8000, reg >> 1); } static DECLFW(M334Write) { - if (MMC3CanWriteToWRAM()) { - if (!(A & 1)) { - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); - } + if (!(A & 0x01) && MMC3_WramIsWritable()) { + reg = V; + MMC3_FixPRG(); } } static DECLFR(M334Read) { - if (A & 2) - return ((X.DB & 0xFE) | (dipswitch & 1)); - return X.DB; + if (A & 0x02) { + return ((cpu.openbus & 0xFE) | (dipsw & 0x01)); + } + return cpu.openbus; } static void M334Reset(void) { - dipswitch++; - mmc3.expregs[0] = 0; - MMC3RegReset(); + dipsw++; + reg = 0; + MMC3_Reset(); } static void M334Power(void) { - dipswitch = 0; - mmc3.expregs[0] = 0; - GenMMC3Power(); + dipsw = 0; + reg = 0; + MMC3_Power(); SetReadHandler(0x6000, 0x7FFF, M334Read); SetWriteHandler(0x6000, 0x7FFF, M334Write); } void Mapper334_Init(CartInfo *info) { - GenMMC3_Init(info, 32, 32, 0, 0); - mmc3.pwrap = M334PW; + MMC3_Init(info, 0, 0); + MMC3_pwrap = M334PW; info->Power = M334Power; info->Reset = M334Reset; - AddExState(mmc3.expregs, 1, 0, "EXPR"); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/bmcctc09.c b/src/mappers/mapper335.c similarity index 57% rename from src/boards/bmcctc09.c rename to src/mappers/mapper335.c index 8651ad9bf..57a615976 100644 --- a/src/boards/bmcctc09.c +++ b/src/mappers/mapper335.c @@ -1,6 +1,8 @@ /* FCEUmm - NES/Famicom Emulator * - * Copyright (C) 2019 Libretro Team + * Copyright notice for this file: + * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -24,51 +26,52 @@ #include "mapinc.h" -#define PRG 0 -#define CHR 1 +static uint8 reg[2]; -static uint8 regs[2]; - -static SFORMAT StateRegs[] = -{ - { regs, 2, "REGS" }, +static SFORMAT StateRegs[] = { + { reg, 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(); + if (reg[1] & 0x10) { + setprg16(0x8000, ((reg[1] & 0x07) << 1) | ((reg[1] >> 3) & 0x01)); + setprg16(0xC000, ((reg[1] & 0x07) << 1) | ((reg[1] >> 3) & 0x01)); + } else { + setprg32(0x8000, reg[1] & 0x07); + } + setchr8(reg[0] & 0x0F); + setmirror(((reg[1] >> 5) & 0x01) ^ 0x01); } -static DECLFW(WriteCHR) { - regs[CHR] = V; - Sync(); +static DECLFW(M335Write) { + switch (A & 0xE000) { + case 0x8000: + case 0xA000: + reg[0] = V; + Sync(); + break; + case 0xC000: + case 0xE000: + reg[1] = V; + Sync(); + break; + } } -static void BMCCTC09Power(void) { +static void M335Power(void) { + reg[0] = reg[1] = 0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xBFFF, WriteCHR); - SetWriteHandler(0xC000, 0xFFFF, WritePRG); + SetWriteHandler(0x8000, 0xFFFF, M335Write); } static void StateRestore(int version) { Sync(); } -void BMCCTC09_Init(CartInfo *info) { - info->Power = BMCCTC09Power; +void Mapper335_Init(CartInfo *info) { + info->Power = M335Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper336.c b/src/mappers/mapper336.c new file mode 100644 index 000000000..b3681b731 --- /dev/null +++ b/src/mappers/mapper336.c @@ -0,0 +1,50 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + */ + +/* 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 */ + +#include "mapinc.h" +#include "latch.h" + +static void Sync(void) { + setprg16(0x8000, latch.data); + setprg16(0xC000, latch.data | 0x07); + setchr8(0); +} + +static DECLFW(M336Write) { + latch.addr = A; + latch.data = V | CartBR(A); + Sync(); +} + +static void M336Power(void) { + Latch_Power(); + SetWriteHandler(0x8000, 0xFFFF, M336Write); +} + +void Mapper336_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Power = M336Power; + info->Reset = Latch_RegReset; +} diff --git a/src/mappers/mapper337.c b/src/mappers/mapper337.c new file mode 100644 index 000000000..83ae9f1bd --- /dev/null +++ b/src/mappers/mapper337.c @@ -0,0 +1,79 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#include "mapinc.h" + +static uint8 reg; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; + +static void Sync(void) { + uint8 bank = reg & 0x1F; + + setprg8(0x6000, 1); + if (reg & 0x80) { /* UNROM */ + setprg16(0x8000, bank); + setprg16(0xC000, bank | 0x07); + } else { + if (reg & 0x40) { /* NROM-256 */ + setprg32(0x8000, bank >> 1); + } else { /* NROM-128 */ + setprg16(0x8000, bank); + setprg16(0xC000, bank); + } + } + setchr8(0); + setmirror(((reg >> 5) & 0x01) ^ 0x01); +} + +static DECLFW(M337Write) { + if (A < 0xC000) { + reg = (reg & 0x07) | (V & ~0x07); + } else { + reg = (reg & ~0x07) | (V & 0x07); + } + Sync(); +} + +static void StateRestore(int version) { + Sync(); +} + +static void M337Power(void) { + reg = 0; + Sync(); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M337Write); +} + +void Mapper337_Init(CartInfo *info) { + info->Power = M337Power; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper338.c b/src/mappers/mapper338.c new file mode 100644 index 000000000..69c0c3f56 --- /dev/null +++ b/src/mappers/mapper338.c @@ -0,0 +1,39 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + */ + +/* 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 */ + +#include "mapinc.h" +#include "latch.h" + +static void Sync(void) { + setprg16(0x8000, latch.addr); + setprg16(0xC000, latch.addr); + setchr8(latch.addr); + setmirror((latch.addr >> 3) & 0x01); +} + +void Mapper338_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Reset = Latch_RegReset; +} diff --git a/src/mappers/mapper339.c b/src/mappers/mapper339.c new file mode 100644 index 000000000..0f1dd0ee8 --- /dev/null +++ b/src/mappers/mapper339.c @@ -0,0 +1,77 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent + * + * 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 uint8 reg; + +static void M339CW(uint32 A, uint8 V) { + setchr1(A, ((reg << 4) & ~0x7F) | (V & 0x7F)); +} + +static void M339PW(uint32 A, uint8 V) { + uint16 base = reg & 0x1F; + + if (reg & 0x20) { /* MMC3 mode */ + setprg8(A, ((base << 1) & ~0x0F) | (V & 0x0F)); + } else { + if ((reg & 0x07) == 0x06) { /* NROM-256 */ + setprg32(0x8000, base >> 1); + } else { /* NROM-128 */ + setprg16(0x8000, base); + setprg16(0xC000, base); + } + } +} + +static DECLFW(M339Write) { + if (MMC3_WramIsWritable()) { + reg = A & 0x3F; + MMC3_FixPRG(); + MMC3_FixCHR(); + } +} + +static void M339Reset(void) { + reg = 0; + MMC3_Reset(); +} + +static void M339Power(void) { + reg = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M339Write); +} + +void Mapper339_Init(CartInfo *info) { + MMC3_Init(info, 8, 0); + MMC3_pwrap = M339PW; + MMC3_cwrap = M339CW; + info->Power = M339Power; + info->Reset = M339Reset; + AddExState(®, 1, 0, "EXPR"); +} diff --git a/src/boards/bmck3036.c b/src/mappers/mapper340.c similarity index 64% rename from src/boards/bmck3036.c rename to src/mappers/mapper340.c index 555464ee8..5b0c026ab 100644 --- a/src/boards/bmck3036.c +++ b/src/mappers/mapper340.c @@ -19,28 +19,32 @@ * */ +/* NES 2.0 Mapper 340 + * UNIF BMC-K-3036 */ + #include "mapinc.h" #include "latch.h" static void Sync(void) { + uint16 prg = ((latch.addr >> 2) & 0x20) | (latch.addr & 0x1F); + if (latch.addr & 0x20) { /* NROM-128 */ - SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0); - if (latch.addr & 1) { - setprg16(0x8000, ((latch.addr >> 2) & 0x20) | (latch.addr & 0x1F)); - setprg16(0xC000, ((latch.addr >> 2) & 0x20) | (latch.addr & 0x1F)); - } else { - setprg32(0x8000, ((latch.addr >> 3) & 0x10) | ((latch.addr >> 1) & 0xF)); + if (latch.addr & 0x01) { + setprg16(0x8000, prg); + setprg16(0xC000, prg); + } else { /* NROM-256 */ + setprg32(0x8000, prg >> 1); } } else { /* UNROM */ - SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1); - setprg16(0x8000, ((latch.addr >> 2) & 0x20) | latch.addr | (latch.data & 7)); - setprg16(0xC000, ((latch.addr >> 2) & 0x20) | latch.addr | 7); + setprg16(0x8000, prg); + setprg16(0xC000, prg | 0x07); } + SetupCartCHRMapping(0, CHRptr[0], 0x2000, (~latch.addr & 0x20)); setchr8(0); setmirror(((latch.addr & 0x40) || ((latch.addr & 0x20) && (latch.addr & 0x04))) ? MI_H : MI_V); } -void BMCK3036_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); - info->Reset = LatchHardReset; +void Mapper340_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Reset = Latch_RegReset; } diff --git a/src/mappers/mapper341.c b/src/mappers/mapper341.c new file mode 100644 index 000000000..4596abb58 --- /dev/null +++ b/src/mappers/mapper341.c @@ -0,0 +1,39 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + */ + +/* BMC-TJ-03 */ +/* NES 2.0 mapper 341 is used for a simple 4-in-1 multicart */ + +#include "mapinc.h" +#include "latch.h" + +static void Sync(void) { + uint8 mirr = (latch.addr & ((PRGsize[0] & 0x40000) ? 0x800 : 0x200)) ? MI_H : MI_V; + + setprg32(0x8000, latch.addr >> 8); + setchr8(latch.addr >> 8); + setmirror(mirr); +} + +void Mapper341_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Reset = Latch_RegReset; +} diff --git a/src/boards/coolgirl.c b/src/mappers/mapper342.c similarity index 99% rename from src/boards/coolgirl.c rename to src/mappers/mapper342.c index 0ae603ff1..a85e161b3 100644 --- a/src/boards/coolgirl.c +++ b/src/mappers/mapper342.c @@ -106,8 +106,6 @@ #define CFI_CHIP 0x13 static uint32 CHR_SIZE = 0; -static uint32 WRAM_SIZE = 0; -static uint8 *WRAM = NULL; static uint8 *SAVE_FLASH = NULL; static uint8* CFI = NULL; @@ -1810,7 +1808,7 @@ static DECLFR(MAFRAM) { return CartBR(A); /* PRG */ } - return X.DB; /* Open bus */ + return cpu.openbus; /* Open bus */ } static void COOLGIRL_ScanlineCounter(void) { @@ -2085,13 +2083,11 @@ static void COOLGIRL_Power(void) { } static void COOLGIRL_Close(void) { - if (WRAM) - FCEU_gfree(WRAM); if (SAVE_FLASH) FCEU_gfree(SAVE_FLASH); if (CFI) FCEU_gfree(CFI); - WRAM = SAVE_FLASH = CFI = NULL; + SAVE_FLASH = CFI = NULL; } static void COOLGIRL_Restore(int version) { @@ -2102,7 +2098,7 @@ static void COOLGIRL_Restore(int version) { #define ExState(var, varname) AddExState(&var, sizeof(var), 0, varname) void COOLGIRL_Init(CartInfo *info) { - size_t i; + int i; info->Power = COOLGIRL_Power; info->Reset = COOLGIRL_Reset; @@ -2114,15 +2110,15 @@ void COOLGIRL_Init(CartInfo *info) { CHR_SIZE = info->CHRRamSize; - WRAM_SIZE = (info->PRGRamSize + info->PRGRamSaveSize) ? (info->PRGRamSize + info->PRGRamSaveSize) : (32 * 1024); - if (WRAM_SIZE > 0) { - WRAM = (uint8 *)FCEU_gmalloc(WRAM_SIZE); - memset(WRAM, 0, WRAM_SIZE); - SetupCartPRGMapping(WRAM_CHIP, WRAM, WRAM_SIZE, 1); - AddExState(WRAM, WRAM_SIZE, 0, "SRAM"); + WRAMSIZE = (info->PRGRamSize + info->PRGRamSaveSize) ? (info->PRGRamSize + info->PRGRamSaveSize) : (32 * 1024); + if (WRAMSIZE > 0) { + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + memset(WRAM, 0, WRAMSIZE); + SetupCartPRGMapping(WRAM_CHIP, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); if (info->battery) { info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAM_SIZE; + info->SaveGameLen[0] = WRAMSIZE; } } @@ -2134,7 +2130,7 @@ void COOLGIRL_Init(CartInfo *info) { } CFI = (uint8 *)FCEU_gmalloc(sizeof(cfi_data) * 2); - for (i = 0; i < sizeof(cfi_data); i++) { + for (i = 0; i < (int)sizeof(cfi_data); i++) { CFI[i * 2] = CFI[i * 2 + 1] = cfi_data[i]; } SetupCartPRGMapping(CFI_CHIP, CFI, sizeof(cfi_data) * 2, 0); diff --git a/src/boards/mapper343.c b/src/mappers/mapper343.c similarity index 79% rename from src/boards/mapper343.c rename to src/mappers/mapper343.c index 30ced177e..54f56fc9d 100644 --- a/src/boards/mapper343.c +++ b/src/mappers/mapper343.c @@ -2,7 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2019 Libretro Team - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -28,30 +28,27 @@ #include "mapinc.h" #include "latch.h" -static uint8 submapper; - static void Sync(void) { - if (submapper == 1) { + if (iNESCart.submapper == 1) { setprg32(0x8000, latch.data); } else { setprg16(0x8000, latch.data); setprg16(0xC000, latch.data); } setchr8(latch.data); - setmirror(latch.data >> 7 & 1); + setmirror((latch.data >> 7) & 0x01); } static DECLFW(M343Write) { - LatchWrite(A, ~V); + Latch_Write(A, V ^ 0xFF); } -static void BMCRESETNROMXIN1Power(void) { - LatchPower(); +static void M343Power(void) { + Latch_Power(); SetWriteHandler(0x8000, 0xFFFF, M343Write); } -void BMCRESETNROMXIN1_Init(CartInfo *info) { - submapper = info->submapper; - Latch_Init(info, Sync, NULL, 0, 0); - info->Power = BMCRESETNROMXIN1Power; +void Mapper343_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Power = M343Power; } diff --git a/src/mappers/mapper344.c b/src/mappers/mapper344.c new file mode 100644 index 000000000..ca459fd42 --- /dev/null +++ b/src/mappers/mapper344.c @@ -0,0 +1,78 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 uint8 reg; + +static uint8 prg_bank_order[2][4] = { + { 0, 1, 2, 3 }, /* normal bank order */ + { 0, 3, 1, 2 } /* wrong bank order, added for compatibility */ +}; + +static void M344CW(uint32 A, uint8 V) { + uint16 mask = (reg & 0x02) ? 0x7F : 0xFF; + uint16 base = (reg & 0x03) << 7; + + setchr1(A, base | (V & mask)); +} + +static void M344PW(uint32 A, uint8 V) { + uint8 base = prg_bank_order[(iNESCart.PRGCRC32 == 0xAB2ACA46)][reg & 0x03]; + + if (reg & 0x04) { + setprg32(0x8000, (base << 2) | ((mmc3.reg[6] & 0x0F) >> 2)); + } else { + setprg8(A, (base << 4) | (V & 0x0F)); + } +} + +static DECLFW(M344Write) { + if (MMC3_WramIsWritable()) { + reg = A & 0xFF; + MMC3_FixPRG(); + MMC3_FixCHR(); + } +} + +static void M344Reset(void) { + reg = 0; + MMC3_Reset(); +} + +static void M344Power(void) { + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M344Write); +} + +void Mapper344_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_pwrap = M344PW; + MMC3_cwrap = M344CW; + info->Power = M344Power; + info->Reset = M344Reset; + AddExState(®, 1, 0, "EXPR"); +} diff --git a/src/boards/bmcl6in1.c b/src/mappers/mapper345.c similarity index 50% rename from src/boards/bmcl6in1.c rename to src/mappers/mapper345.c index 4b899feae..503b7310b 100644 --- a/src/boards/bmcl6in1.c +++ b/src/mappers/mapper345.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -27,45 +27,50 @@ #include "mapinc.h" #include "mmc3.h" -static void BMCL6IN1PW(uint32 A, uint8 V) { - if (mmc3.expregs[0] & 0x0C) - setprg8(A, (V & 0x0F) | (mmc3.expregs[0] & 0xC0) >> 2); - else - setprg32(0x8000, ((mmc3.expregs[0] & 0xC0) >> 4) | (mmc3.expregs[0] & 0x03)); +static uint8 reg; + +static void M345PW(uint32 A, uint8 V) { + uint8 base = reg >> 6; + + if (reg & 0x0C) { + setprg8(A, (base << 4) | (V & 0x0F)); + } else { + setprg32(0x8000, (base << 2) | (reg & 0x03)); + } } -static void BMCL6IN1MW(uint8 V) { - if (mmc3.expregs[0] & 0x20) - setmirror(MI_0 + ((mmc3.expregs[0] & 0x10) >> 1)); - else { - mmc3.mirroring = V; - setmirror((V & 1) ^ 1); +static void M345MIR(void) { + if (reg & 0x20) { + setmirror(MI_0 + ((reg & 0x10) >> 1)); + } else { + setmirror((mmc3.mirr & 0x01) ^ 0x01); } } -static DECLFW(BMCL6IN1Write) { - if (MMC3CanWriteToWRAM()) { - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); +static DECLFW(M345Write) { + if (MMC3_WramIsWritable()) { + reg = V; + MMC3_FixPRG(); + MMC3_FixCHR(); + MMC3_FixMIR(); } } -static void BMCL6IN1Reset(void) { - mmc3.expregs[0] = 0; - MMC3RegReset(); +static void M345Reset(void) { + reg = 0; + MMC3_Reset(); } -static void BMCL6IN1Power(void) { - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, BMCL6IN1Write); +static void M345Power(void) { + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M345Write); } -void BMCL6IN1_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 8, 0, 0); - mmc3.pwrap = BMCL6IN1PW; - mmc3.mwrap = BMCL6IN1MW; - info->Power = BMCL6IN1Power; - info->Reset = BMCL6IN1Reset; - AddExState(mmc3.expregs, 1, 0, "EXPR"); +void Mapper345_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_pwrap = M345PW; + MMC3_FixMIR = M345MIR; + info->Power = M345Power; + info->Reset = M345Reset; + AddExState(®, 1, 0, "EXPR"); } diff --git a/src/boards/KS7012.c b/src/mappers/mapper346.c similarity index 73% rename from src/boards/KS7012.c rename to src/mappers/mapper346.c index c4dbcb7f8..22bbfcf8d 100644 --- a/src/boards/KS7012.c +++ b/src/mappers/mapper346.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2007 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -17,6 +18,8 @@ * 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 346 - Kaiser 7012 + * UNL-KS7012 * FDS Conversion * */ @@ -24,22 +27,19 @@ #include "mapinc.h" static uint8 reg; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { ®, 1, "REGS" }, { 0 } }; static void Sync(void) { setprg8r(0x10, 0x6000, 0); - setprg32(0x8000, reg & 1); + setprg32(0x8000, reg); setchr8(0); } -static DECLFW(UNLKS7012Write) { +static DECLFW(M346Write) { /* FCEU_printf("bs %04x %02x\n",A,V); */ switch (A) { case 0xE0A0: reg = 0; Sync(); break; @@ -47,18 +47,18 @@ static DECLFW(UNLKS7012Write) { } } -static void UNLKS7012Power(void) { - reg = ~0; +static void M346Power(void) { + reg = 1; Sync(); SetReadHandler(0x6000, 0x7FFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, UNLKS7012Write); + SetWriteHandler(0xE000, 0xEFFF, M346Write); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } -static void UNLKS7012Reset(void) { - reg = ~0; +static void M346Reset(void) { + reg = 1; Sync(); } @@ -66,22 +66,19 @@ static void StateRestore(int version) { Sync(); } -static void UNLKS7012Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; +static void M346Close(void) { } -void UNLKS7012_Init(CartInfo *info) { - info->Power = UNLKS7012Power; - info->Reset = UNLKS7012Reset; - info->Close = UNLKS7012Close; +void Mapper346_Init(CartInfo *info) { + info->Power = M346Power; + info->Reset = M346Reset; + info->Close = M346Close; + + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); WRAMSIZE = 8192; WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); } diff --git a/src/mappers/mapper347.c b/src/mappers/mapper347.c new file mode 100644 index 000000000..c01768c29 --- /dev/null +++ b/src/mappers/mapper347.c @@ -0,0 +1,193 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2007 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 347 - Kaiser 7030 + * UNIF UNL-KS7030 + * FDS Conversion - Yume Koujou: Doki Doki Panic + * + * Logical bank layot 32 K BANK 0, 64K BANK 1, 32K ~0 hardwired, 8K is missing + * need redump from MASKROM! + * probably need refix mapper after hard dump + * + */ + +/* 2020-3-6 - update mirroring + * PRG-ROM Bank Select #1/Mirroring Select ($8000-$8FFF, write) + * A~FEDC BA98 7654 3210 + * ------------------- + * 1000 .... .... MBBB + * |+++- Select 4 KiB PRG-ROM bank at CPU $7000-$7FFF + * +---- Select nametable mirroring type + * 0: Vertical + * 1: Horizontal + */ + +#include "mapinc.h" +#include "fdssound.h" + +static uint8 reg[2]; +static void (*WSync)(void); + +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, + { 0 } +}; + +/* Legacy bank order */ + +/* 6000 - 6BFF - RAM + * 6C00 - 6FFF - BANK 1K REG1 + * 7000 - 7FFF - BANK 4K REG0 + * 8000 - B7FF - PRG + * B800 - BFFF - RAM + * C000 - CBFF - BANK 3K + * CC00 - D7FF - RAM + * D800 - FFFF - PRG + */ + +static void M347Sync2(void) { + setchr8(0); + setprg32(0x8000, ~0); + setprg4(0xb800, reg[0] & 0x07); + setprg4(0xc800, reg[1] + 8); + setmirror(((reg[0] >> 3) & 0x01) ^ 0x01); +} + +static DECLFR(M347Read2) { + if ((A >= 0x6000) && (A <= 0x6BFF)) { + return WRAM[A - 0x6000]; + } else if ((A >= 0x6C00) && (A <= 0x6FFF)) { + return CartBR(0xC800 + (A - 0x6C00)); + } else if ((A >= 0x7000) && (A <= 0x7FFF)) { + return CartBR(0xB800 + (A - 0x7000)); + } else if ((A >= 0xB800) && (A <= 0xBFFF)) { + return WRAM[0x0C00 + (A - 0xB800)]; + } else if ((A >= 0xC000) && (A <= 0xCBFF)) { + return CartBR(0xCC00 + (A - 0xC000)); + } else if ((A >= 0xCC00) && (A <= 0xD7FF)) { + return WRAM[0x1400 + (A - 0xCC00)]; + } else if ((A >= 0x8000) && (A <= 0xB7FF)) { + return CartBR(A); + } else if ((A >= 0xD800) && (A <= 0xFFFF)) { + return CartBR(A); + } + return cpu.openbus; +} + +static DECLFW(M347Write2) { + if ((A >= 0x6000) && (A <= 0x6BFF)) { + WRAM[A - 0x6000] = V; + } else if ((A >= 0x6C00) && (A <= 0x6FFF)) { + CartBW(0xC800 + (A - 0x6C00), V); + } else if ((A >= 0x7000) && (A <= 0x7FFF)) { + CartBW(0xB800 + (A - 0x7000), V); + } else if ((A >= 0xB800) && (A <= 0xBFFF)) { + WRAM[0x0C00 + (A - 0xB800)] = V; + } else if ((A >= 0xC000) && (A <= 0xCBFF)) { + CartBW(0xCC00 + (A - 0xC000), V); + } else if ((A >= 0xCC00) && (A <= 0xD7FF)) { + WRAM[0x1400 + (A - 0xCC00)] = V; + } else if ((A >= 0x8000) && (A <= 0x8FFF)) { + reg[0] = A & 0x0F; + WSync(); + } else if ((A >= 0x9000) && (A <= 0x9FFF)) { + reg[1] = A & 0x0F; + WSync(); + } +} +/* end of legacy bank order handling */ + +static void Sync(void) { + setchr8(0); + setprg32(0x8000, ~0); + if (reg[0] & 8) + setmirror(MI_H); + else + setmirror(MI_V); +} + +static DECLFR(M347Read) { + if (A >= 0x6000 && A <= 0x6BFF) { + return WRAM[A - 0x6000 + 0x00000]; + } else if (A >= 0x6C00 && A <= 0x6FFF) { + return PRGptr[0][A - 0x6000 + 0x01000 * reg[1] + 0x00000]; + } else if (A >= 0x7000 && A <= 0x7FFF) { + return PRGptr[0][A - 0x7000 + 0x01000 * (reg[0] & 0x07) + 0x10000]; + } else if (A >= 0xB800 && A <= 0xBFFF) { + return WRAM[A - 0xB800 + 0x00C00]; + } else if (A >= 0xC000 && A <= 0xCBFF) { + return PRGptr[0][A - 0xC000 + 0x01000 * reg[1] + 0x00000]; + } else if (A >= 0xCC00 && A <= 0xD7FF) { + return WRAM[A - 0xCC00 + 0x01400]; + } else if (A >= 0x8000) { + return PRGptr[0][A - 0x8000 + 0x18000]; + } + return cpu.openbus; +} + +static DECLFW(M347Write) { + if (A >= 0x6000 && A <= 0x6BFF) { + WRAM[A - 0x6000 + 0x0000] = V; + } else if (A >= 0xB800 && A <= 0xBFFF) { + WRAM[A - 0xB800 + 0x0C00] = V; + } else if (A >= 0xCC00 && A <= 0xD7FF) { + WRAM[A - 0xCC00 + 0x1400] = V; + } else if (A >= 0x8000 && A <= 0x8FFF) { + reg[0] = A & 15; + WSync(); + } else if (A >= 0x9000 && A <= 0x9FFF) { + reg[1] = A & 15; + WSync(); + } +} + +static void M347Power(void) { + FDSSound_Power(); + reg[0] = reg[1] = ~0; + + if (iNESCart.PRGCRC32 == 0xFA4DAC91) { + SetReadHandler(0x6000, 0xFFFF, M347Read2); + SetWriteHandler(0x6000, 0xFFFF, M347Write2); + WSync = M347Sync2; + } else { + SetReadHandler(0x6000, 0xFFFF, M347Read); + SetWriteHandler(0x6000, 0xFFFF, M347Write); + WSync = Sync; + } + WSync(); +} + +static void M347Close(void) { +} + +static void StateRestore(int version) { + WSync(); +} + +void Mapper347_Init(CartInfo *info) { + info->Power = M347Power; + info->Close = M347Close; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + + WRAMSIZE = 8192; + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); +} diff --git a/src/mappers/mapper348.c b/src/mappers/mapper348.c new file mode 100644 index 000000000..3b191f74c --- /dev/null +++ b/src/mappers/mapper348.c @@ -0,0 +1,77 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2008 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 348 + * M-022 MMC3 based 830118C T-106 4M + 4M */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 reg; + +static void M348CW(uint32 A, uint8 V) { + uint16 mask = 0x7F; + uint16 base = (reg << 5) & 0x180; + + setchr1(A, base | (V & mask)); +} + +static void M348PW(uint32 A, uint8 V) { + uint8 mask = 0x0F; + uint8 base = (reg << 2) & 0x30; + + if ((reg & 0x0C) == 0x0C) { + setprg8(0x8000, base | ((mmc3.reg[6] & ~0x02) & mask)); + setprg8(0xA000, base | ((mmc3.reg[7] & ~0x02) & mask)); + setprg8(0xC000, base | ((mmc3.reg[6] | 0x02) & mask)); + setprg8(0xE000, base | ((mmc3.reg[7] | 0x02) & mask)); + } else { + setprg8(A, base | (V & mask)); + } +} + +static DECLFW(M348Write) { + if (MMC3_WramIsWritable()) { + reg = V; + MMC3_FixPRG(); + MMC3_FixCHR(); + } +} + +static void M348Reset(void) { + reg = 0; + MMC3_Reset(); +} + +static void M348Power(void) { + reg = 0; + MMC3_Power(); + SetWriteHandler(0x6800, 0x68FF, M348Write); +} + +void Mapper348_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_pwrap = M348PW; + MMC3_cwrap = M348CW; + info->Power = M348Power; + info->Reset = M348Reset; + AddExState(®, 1, 0, "EXPR"); +} diff --git a/src/mappers/mapper349.c b/src/mappers/mapper349.c new file mode 100644 index 000000000..b3d07e6c1 --- /dev/null +++ b/src/mappers/mapper349.c @@ -0,0 +1,45 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 349 - BMC-G-146 */ + +#include "mapinc.h" +#include "latch.h" + +static void Sync(void) { + if (latch.addr & 0x800) { /* UNROM mode */ + setprg16(0x8000, (latch.addr & 0x1F) | (latch.addr & ((latch.addr & 0x40) >> 6))); + setprg16(0xC000, (latch.addr & 0x1F) | 0x07); + } else { + if (latch.addr & 0x40) { /* 16K mode */ + setprg16(0x8000, latch.addr & 0x1F); + setprg16(0xC000, latch.addr & 0x1F); + } else { /* 32K mode */ + setprg32(0x8000, (latch.addr >> 1) & 0x0F); + } + } + setchr8(0); + setmirror(((latch.addr & 0x80) >> 7) ^ 0x01); +} + +void Mapper349_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, TRUE); +} diff --git a/src/mappers/mapper350.c b/src/mappers/mapper350.c new file mode 100644 index 000000000..f349d0755 --- /dev/null +++ b/src/mappers/mapper350.c @@ -0,0 +1,88 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent + * + * 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 350 - BMC-891227 + * Super 15-in-1 Game Card + * https://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_350 + */ + +#include "mapinc.h" +#include "latch.h" + +static uint8 reg[2]; + +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, + { 0 } +}; + +static void Sync(void) { + uint8 bank = (reg[0] & 0x18) | (reg[1] & 0x07); + + setprg8(0x6000, 1); + if (reg[0] & 0x40) { /* UNROM */ + if (reg[0] & 0x20) { + /* 2nd chip only has 128K PRG */ + bank &= 0x07; + } + setprg16(0x8000, (reg[0] & 0x20) | bank); + setprg16(0xC000, (reg[0] & 0x20) | bank | 0x07); + } else { + if (reg[0] & 0x20) { /* NROM-256 */ + setprg32(0x8000, bank >> 1); + } else { + setprg16(0x8000, bank); + setprg16(0xC000, bank); + } + } + /* CHR-RAM Protect... kinda */ + SetupCartCHRMapping(0, CHRptr[0], 0x2000, (reg[0] & 0x40) != 0); + setchr8(0); + setmirror(((reg[0] >> 7) & 0x01) ^ 0x01); +} + +static DECLFW(M350Write) { + reg[(A >> 14) & 0x01] = V; + Sync(); +} + +static void M350Reset(void) { + reg[0] = reg[1] = 0; + Sync(); +} + +static void M350Power(void) { + reg[0] = reg[1] = 0; + Sync(); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M350Write); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper350_Init(CartInfo *info) { + info->Power = M350Power; + info->Reset = M350Reset; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper351.c b/src/mappers/mapper351.c new file mode 100644 index 000000000..2ec4700e7 --- /dev/null +++ b/src/mappers/mapper351.c @@ -0,0 +1,284 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "mmc1.h" +#include "mmc3.h" +#include "vrc2and4.h" + +static uint8 reg[4], dipsw; + +static uint8 *CHRRAM = NULL; +static uint8 *PRGCHR = NULL; + +static SFORMAT stateRegs[] = { + { reg, 4, "REGS" }, + { &dipsw, 1, "DIPS" }, + { 0 }, +}; + +static uint32 GetPRGChip(void) { + return (((reg[2] & 0x01) && CHRRAM) ? 0x10 : 0x00); +} + +static uint32 GetPRGMask(void) { + return ((reg[2] & 0x04) ? 0x0F : 0x1F); +} + +static uint32 GetPRGBase(void) { + return (reg[1] >> 1); +} + +static uint32 GetCHRMask(void) { + if ((reg[2] & 0x10) && !(reg[2] & 0x20)) { + return 0x1F; + } + return ((reg[2] & 0x20) ? 0x7F : 0xFF); +} + +static uint32 GetCHRBase(void) { + return (reg[0] << 1); +} + +static void M351PW_MMC1(uint32 A, uint8 V) { + uint8 mask = GetPRGMask() >> 1; + uint8 bank = GetPRGBase() >> 1; + + setprg16r(GetPRGChip(), A, (bank & ~mask) | (V & mask)); +} + +static void M351CW_MMC1(uint32 A, uint8 V) { + uint16 mask = GetCHRMask() >> 2; + uint16 bank = GetCHRBase() >> 2; + + setchr4(A, (bank & ~mask) | (V & mask)); +} + +static void M351PW_MMC3(uint32 A, uint8 V) { + uint8 mask = GetPRGMask(); + uint8 bank = GetPRGBase(); + + setprg8r(GetPRGChip(), A, (bank & ~mask) | (V & mask)); +} + +static void M351CW_MMC3(uint32 A, uint8 V) { + uint16 mask = GetCHRMask(); + uint16 bank = GetCHRBase(); + + setchr1(A, (bank & ~mask) | (V & mask)); +} + +static void M351PW_VRC24(uint32 A, uint8 V) { + uint8 mask = GetPRGMask(); + uint8 bank = GetPRGBase(); + + setprg8r(GetPRGChip(), A, (bank & ~mask) | (V & mask)); +} + +static void M351CW_VRC24(uint32 A, uint32 V) { + uint16 mask = GetCHRMask(); + uint16 bank = GetCHRBase(); + + setchr1(A, (bank & ~mask) | (V & mask)); +} + +static void SyncPRG(void) { + if (reg[2] & 0x10) { /* NROM mode */ + uint32 bank = GetPRGBase(); + uint32 chip = GetPRGChip(); + + if (reg[2] & 0x08) { /* NROM-64 */ + setprg8r(chip, 0x8000, bank); + setprg8r(chip, 0xA000, bank); + setprg8r(chip, 0xC000, bank); + setprg8r(chip, 0xE000, bank); + } else { + if (reg[2] & 0x04) { /* NROM-128 */ + setprg16r(chip, 0x8000, bank >> 1); + setprg16r(chip, 0xC000, bank >> 1); + } else { /* NROM-256 */ + setprg32r(chip, 0x8000, bank >> 2); + } + } + } else { + switch (reg[0] & 0x03) { + default: + case 1: MMC3_FixPRG(); break; + case 2: MMC1_FixPRG(); break; + case 3: VRC24_FixPRG(); break; + } + } +} + +static void SyncCHR(void) { + if (reg[2] & 0x01) { /* CHR RAM mode */ + setchr8r(0x10, 0); + } else if (reg[2] & 0x40) { /* CNROM mode */ + setchr8(GetCHRBase() >> 3); + } else { + switch (reg[0] & 0x03) { + default: + case 1: MMC3_FixCHR(); break; + case 2: MMC1_FixCHR(); break; + case 3: VRC24_FixCHR(); break; + } + } +} + +static void SyncMIR(void) { + switch (reg[0] & 0x03) { + default: + case 1: MMC3_FixMIR(); break; + case 2: MMC1_FixMIR(); break; + case 3: VRC24_FixMIR(); break; + } +} + +static void Sync(void) { + SyncPRG(); + SyncCHR(); + SyncMIR(); +} + +static void M351CPUHook(int a) { + if ((reg[0] & 0x03) == 0x03) { + VRC24_IRQCPUHook(a); + } +} + +static void M351HBHook(void) { + if (!(reg[0] & 0x02)) { /* MMC3 mode */ + MMC3_IRQHBHook(); + } +} + +static DECLFR(M351ReadDIP) { + return dipsw; +} + +static DECLFW(M351WriteMirr) { + /* FDS mirroring */ + mmc3.mirr = (V >> 3) & 0x01; + SyncMIR(); +} + +static DECLFW(M351WriteReg) { + reg[A & 0x03] = V; + Sync(); +} + +static DECLFW(M351Write) { + switch (reg[0] & 0x03) { + default: + case 1: + MMC3_Write(A, V); + Sync(); + break; + case 2: + MMC1_Write(A, V); + break; + case 3: + if (A & 0x800) { + A = (A & 0xFFF3) | ((A << 1) & 0x08) | ((A >> 1) & 0x04); + } + VRC24_Write(A, V); + break; + } +} + +static void M351Power(void) { + reg[0] = reg[1] = reg[2] = reg[3] = 0; + dipsw = 0; + + VRC24_Reset(); + MMC1_Reset(); + MMC3_Reset(); + + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetReadHandler(0x5000, 0x5FFF, M351ReadDIP); + SetWriteHandler(0x4025, 0x4025, M351WriteMirr); + SetWriteHandler(0x5000, 0x5FFF, M351WriteReg); + SetWriteHandler(0x8000, 0xFFFF, M351Write); +} + +static void M531Reset(void) { + reg[0] = reg[1] = reg[2] = reg[3] = 0; + dipsw++; + + VRC24_Reset(); + MMC1_Reset(); + MMC3_Reset(); + + FCEU_printf(" Mapper Reset! dpsw:%d\n", dipsw); +} + +static void M351Close(void) { + if (CHRRAM) { + FCEU_gfree(CHRRAM); + } + if (PRGCHR) { + FCEU_gfree(PRGCHR); + } + CHRRAM = NULL; + PRGCHR = NULL; +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper351_Init(CartInfo *info) { + int CHRRAMSIZE = info->CHRRamSize + info->CHRRamSaveSize; + + VRC24_Init(info, VRC2, 0x04, 0x08, FALSE, TRUE); + VRC24_pwrap = M351PW_VRC24; + VRC24_cwrap = M351CW_VRC24; + + MMC1_Init(info, FALSE, FALSE); + MMC1_pwrap = M351PW_MMC1; + MMC1_cwrap = M351CW_MMC1; + + MMC3_Init(info, FALSE, FALSE); + MMC3_pwrap = M351PW_MMC3; + MMC3_cwrap = M351CW_MMC3; + + info->Reset = M531Reset; + info->Power = M351Power; + info->Close = M351Close; + + MapIRQHook = M351CPUHook; + GameHBIRQHook = M351HBHook; + + GameStateRestore = StateRestore; + AddExState(stateRegs, ~0, 0, 0); + + if (!UNIFchrrama && CHRRAMSIZE) { + CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CRAM"); + + /* This crazy thing can map CHR-ROM into CPU address space. Allocate a combined PRG+CHR address space and treat + * it a second "chip". */ + PRGCHR = (uint8 *)FCEU_gmalloc(PRGsize[0] + CHRsize[0]); + memcpy(PRGCHR, PRGptr[0], PRGsize[0]); + memcpy(PRGCHR + PRGsize[0], CHRptr[0], CHRsize[0]); + SetupCartPRGMapping(0x10, PRGCHR, PRGsize[0] + CHRsize[0], 0); + } +} diff --git a/src/boards/mapper352.c b/src/mappers/mapper352.c similarity index 76% rename from src/boards/mapper352.c rename to src/mappers/mapper352.c index 1ec8e0ae8..5282a6449 100644 --- a/src/boards/mapper352.c +++ b/src/mappers/mapper352.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,15 +21,14 @@ /* * NES 2.0 Mapper 352 * BMC-KS106C - * - Kaiser 4-in-1(Unl,KS106C)[p1] - B-Wings, Kung Fu, 1942, SMB1 + * - Kaiser 4-in-1(Unl,M352)[p1] - B-Wings, Kung Fu, 1942, SMB1 */ #include "mapinc.h" static uint8 gameblock; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { &gameblock, 1, "GAME" }, { 0 } }; @@ -37,16 +36,16 @@ static SFORMAT StateRegs[] = static void Sync(void) { setprg32(0x8000, gameblock); setchr8(gameblock); - setmirror(gameblock & 1); + setmirror(gameblock & 0x01); } -static void KS106CPower(void) { +static void M352Power(void) { gameblock = 0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); } -static void KS106CReset(void) { +static void M352Reset(void) { gameblock++; Sync(); } @@ -55,9 +54,9 @@ static void StateRestore(int version) { Sync(); } -void BMCKS106C_Init(CartInfo *info) { - info->Power = KS106CPower; - info->Reset = KS106CReset; +void Mapper352_Init(CartInfo *info) { + info->Power = M352Power; + info->Reset = M352Reset; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper353.c b/src/mappers/mapper353.c new file mode 100644 index 000000000..30e641186 --- /dev/null +++ b/src/mappers/mapper353.c @@ -0,0 +1,169 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 353 is used for the 92 Super Mario Family multicart, + * consisting of an MMC3 clone ASIC together with a PAL. + * The PCB code is 81-03-05-C. + */ + +#include "mapinc.h" +#include "mmc3.h" +#include "fdssound.h" + +static uint8 reg; + +static uint8 *CHRRAM = NULL; +static uint32 CHRRAMSIZE; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; + +static void M353PW(uint32 A, uint8 V) { + uint16 base = reg << 5; + uint16 mask = 0x1F; + + if (reg == 2) { + base |= (mmc3.reg[0] & 0x80) ? 0x10 : 0x00; + mask >>= 1; + } else if ((reg == 3) && !(mmc3.reg[0] & 0x80) && (A >= 0xC000)) { + base = 0x70; + mask = 0x0F; + V = mmc3.reg[6 + ((A >> 13) & 0x01)]; + } + + setprg8(A, (base & ~mask) | (V & mask)); +} + +static void M353CW(uint32 A, uint8 V) { + uint16 mask = 0x7F; + uint16 base = reg << 7; + + if ((reg == 2) && (mmc3.reg[0] & 0x80)) { + setchr8r(0x10, 0); + } else { + setchr1(A, (base & ~mask) | (V & mask)); + } +} + +static void M353MIR(void) { + if (reg == 0) { + if (mmc3.cmd & 0x80) { + setntamem(NTARAM + 0x400 * ((mmc3.reg[2] >> 7) & 0x01), 1, 0); + setntamem(NTARAM + 0x400 * ((mmc3.reg[3] >> 7) & 0x01), 1, 1); + setntamem(NTARAM + 0x400 * ((mmc3.reg[4] >> 7) & 0x01), 1, 2); + setntamem(NTARAM + 0x400 * ((mmc3.reg[5] >> 7) & 0x01), 1, 3); + } else { + setntamem(NTARAM + 0x400 * ((mmc3.reg[0] >> 7) & 0x01), 1, 0); + setntamem(NTARAM + 0x400 * ((mmc3.reg[0] >> 7) & 0x01), 1, 1); + setntamem(NTARAM + 0x400 * ((mmc3.reg[1] >> 7) & 0x01), 1, 2); + setntamem(NTARAM + 0x400 * ((mmc3.reg[1] >> 7) & 0x01), 1, 3); + } + } else { + setmirror((mmc3.mirr & 0x01) ^ 0x01); + } +} + +static DECLFW(M353Write) { + if (A & 0x80) { + reg = (A >> 13) & 0x03; + MMC3_FixPRG(); + MMC3_FixCHR(); + MMC3_FixMIR(); + } else { + uint8 oldcmd = mmc3.cmd; + + switch (A & 0xE001) { + case 0x8000: + mmc3.cmd = V; + if ((oldcmd & 0x40) != (mmc3.cmd & 0x40)) { + MMC3_FixPRG(); + } + if ((oldcmd & 0x80) != (mmc3.cmd & 80)) { + MMC3_FixCHR(); + MMC3_FixMIR(); + } + break; + case 0x8001: + mmc3.reg[mmc3.cmd & 0x07] = V; + switch (mmc3.cmd & 0x07) { + case 0: + MMC3_FixPRG(); + MMC3_FixCHR(); + MMC3_FixMIR(); + break; + case 1: + case 2: + case 3: + case 4: + case 5: + MMC3_FixCHR(); + MMC3_FixMIR(); + break; + case 6: + case 7: + MMC3_FixPRG(); + break; + } + break; + default: + MMC3_Write(A, V); + break; + } + } +} + +static void M353Power(void) { + FDSSound_Power(); + reg = 0; + MMC3_Power(); + SetWriteHandler(0x8000, 0xFFFF, M353Write); +} + +static void M353Reset(void) { + reg = 0; + MMC3_Reset(); + FDSSound_Reset(); +} + +static void M353Close(void) { + MMC3_Close(); + if (CHRRAM) { + FCEU_gfree(CHRRAM); + } + CHRRAM = NULL; +} + +void Mapper353_Init(CartInfo *info) { + MMC3_Init(info, 8, info->battery); + MMC3_cwrap = M353CW; + MMC3_pwrap = M353PW; + MMC3_FixMIR = M353MIR; + info->Power = M353Power; + info->Close = M353Close; + info->Reset = M353Reset; + AddExState(StateRegs, ~0, 0, NULL); + + CHRRAMSIZE = 8192; + CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); +} diff --git a/src/boards/mapper354.c b/src/mappers/mapper354.c similarity index 54% rename from src/boards/mapper354.c rename to src/mappers/mapper354.c index e7ee734ea..0e6147db6 100644 --- a/src/boards/mapper354.c +++ b/src/mappers/mapper354.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -19,70 +19,69 @@ */ /* NES 2.0 Mapper 354 denotes three different PCBs: - * - FAM250 for the 1992 巨作 250-in-1 劃面選關 鑽石巨王 multicart (submapper 0), - * - 810139C for the 1992 劃面選關 400-in-1 創新版 as well as an undumped 650-in-1 multicart (also submapper 0), - * - 810331C/SCHI-24 for the 1992 劃面選關 1050-in-1 multicart (submapper 1). + * - FAM250 for the 1992 巨作 250-in-1 劃面選關 鑽石巨王 multicart (iNESCart.submapper 0), + * - 810139C for the 1992 劃面選關 400-in-1 創新版 as well as an undumped 650-in-1 multicart (also iNESCart.submapper 0), + * - 810331C/SCHI-24 for the 1992 劃面選關 1050-in-1 multicart (iNESCart.submapper 1). */ #include "mapinc.h" #include "latch.h" -static uint8 submapper; - static void Sync(void) { - uint32 bank = ((latch.addr >> 5) & 0x80) | ((latch.addr << 2) & 0x40) | (latch.data & 0x3F); + uint16 prg = ((latch.addr >> 5) & 0x80) | ((latch.addr << 2) & 0x40) | (latch.data & 0x3F); - switch (latch.addr & 7) { + switch (latch.addr & 0x07) { case 0: case 4: - setprg32(0x8000, bank >> 1); - break; + setprg32(0x8000, prg >> 1); + break; case 1: - setprg16(0x8000, bank); - setprg16(0xC000, bank | 7); + setprg16(0x8000, prg); + setprg16(0xC000, prg | 0x07); break; case 2: case 6: - setprg8(0x8000, (bank << 1) | (latch.data >> 7)); - setprg8(0xA000, (bank << 1) | (latch.data >> 7)); - setprg8(0xC000, (bank << 1) | (latch.data >> 7)); - setprg8(0xE000, (bank << 1) | (latch.data >> 7)); + setprg8(0x8000, (prg << 1) | (latch.data >> 7)); + setprg8(0xA000, (prg << 1) | (latch.data >> 7)); + setprg8(0xC000, (prg << 1) | (latch.data >> 7)); + setprg8(0xE000, (prg << 1) | (latch.data >> 7)); break; case 3: case 7: - setprg16(0x8000, bank); - setprg16(0xC000, bank); + setprg16(0x8000, prg); + setprg16(0xC000, prg); break; case 5: - setprg8(0x6000, (bank << 1) | (latch.data >> 7)); - setprg32(0x8000, (bank >> 1) | 3); + setprg8(0x6000, (prg << 1) | (latch.data >> 7)); + setprg32(0x8000, (prg >> 1) | 0x03); break; } - - /* CHR-RAM write protect */ - SetupCartCHRMapping(0, CHRptr[0], CHRsize[0], ((latch.addr >> 3) & 1) ^ 1); - + /* CHR-RAM write protect */ + SetupCartCHRMapping(0, CHRptr[0], CHRsize[0], ((latch.addr >> 3) & 0x01) ^ 0x01); setchr8(0); - setmirror(((latch.data >> 6) & 1) ^ 1); + setmirror(((latch.data >> 6) & 0x01) ^ 0x01); } -static DECLFW(M354_WriteLatch) { - uint32 adr = (submapper == 1) ? 0xE000 : 0xF000; - if (A >= adr) { - LatchWrite(A, V); +static DECLFW(M354Write) { + uint32 addr = 0xE000 | (iNESCart.submapper == 0) ? 0x1000 : 0; + + if (A < addr) { + return; } + + latch.addr = A; + latch.data = V; + Sync(); } static void M354_Power(void) { - LatchPower(); + Latch_Power(); SetReadHandler(0x6000, 0x7FFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, M354_WriteLatch); - Sync(); + SetWriteHandler(0x8000, 0xFFFF, M354Write); } void Mapper354_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); - submapper = info->submapper; + Latch_Init(info, Sync, NULL, FALSE, FALSE); info->Power = M354_Power; - info->Reset = LatchHardReset; + info->Reset = Latch_RegReset; } \ No newline at end of file diff --git a/src/mappers/mapper355.c b/src/mappers/mapper355.c new file mode 100644 index 000000000..a25410eda --- /dev/null +++ b/src/mappers/mapper355.c @@ -0,0 +1,135 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* NOTE: This only emulates the UNIF variant of 3D-Blocks */ + +#include "mapinc.h" + +#include "mapper355.h" +#include "hw/pic16c5x.h" + +static uint32 address; +static uint8 *eprom = NULL; + +static uint8_t pci16c5x_read(int port) { + if (port == 0) { + return (1 | + (address & 0x0040 ? 0x02 : 0) | /* A6 -> RA1 */ + (address & 0x0020 ? 0x04 : 0) | /* A5 -> RA2 */ + (address & 0x0010 ? 0x08 : 0)); /* A4 -> RA3 */ + } else if (port == 1) { + return ( + (address & 0x1000 ? 0x01 : 0) | /* A12 -> RB0 */ + (address & 0x0080 ? 0x02 : 0) | /* A7 -> RB1 */ + (address & 0x0400 ? 0x04 : 0) | /* A10 -> RB2 */ + (address & 0x0800 ? 0x08 : 0) | /* A11 -> RB3 */ + (address & 0x0200 ? 0x10 : 0) | /* A9 -> RB4 */ + (address & 0x0100 ? 0x20 : 0) | /* A8 -> RB5 */ + (address & 0x2000 ? 0x40 : 0) | /* A13 -> RB6 */ + (address & 0x4000 ? 0x80 : 0)); /* A14 -> RB7 */ + } + return (0xFF); +} + +static void pci16c5x_write(int port, int val) { + if (port == 0) { + if (val & 0x1001) { + X6502_IRQEnd(FCEU_IQEXT); + } else { + X6502_IRQBegin(FCEU_IQEXT); + } + } +} + +static void M355CPUIRQHook(int a) { + while (a--) { + pic16c5x_run(); + } +} + +static readfunc cpuRead[0x10000]; +static writefunc cpuWrite[0x10000]; + +static DECLFR(M555Read) { + address = A; + if (A >= 0x8000) { + return CartBR(A); + } + return cpuRead[A](A); +} + +static DECLFW(M555Write) { + address = A; + if (cpuWrite[A]) { + cpuWrite[A](A, V); + } +} + +static void M555Power(void) { + int x; + + address = 0; + + pic16c5x_reset(1); + + setprg32(0x8000, 0); + setchr8(0); + + for (x = 0; x < 0x10000; x++) { + cpuRead[x] = GetReadHandler(x); + cpuWrite[x] = GetWriteHandler(x); + } + + SetReadHandler(0, 0xFFFF, M555Read); + SetWriteHandler(0, 0xFFFF, M555Write); +} + +static void M555Reset(void) { + address = 0; + pic16c5x_reset(0); +} + +static void M555Close(void) { + eprom = NULL; +} + +void Mapper355_Init(CartInfo *info) { + if (ROM.misc.data && (ROM.misc.size == 1024)) { + eprom = ROM.misc.data; + } else { + if (info->CRC32 == 0x86DBA660) { /* 3D Block (Hwang Shinwei) [!].nes */ + eprom = &eprom_3d_block[0]; + } else if ((info->CRC32 == 0x3C43939D) || /* Block Force.nes */ + (info->CRC32 == 0xB655C53A)) { /* Block Force (Hwang Shinwei).nes */ + eprom = &eprom_block_force[0]; + } + } + + if (eprom) { + pic16c54_init(eprom, pci16c5x_read, pci16c5x_write); + pic16c5x_add_statesinfo(); + } + + info->Power = M555Power; + info->Reset = M555Reset; + info->Close = M555Close; + MapIRQHook = M355CPUIRQHook; + AddExState(&address, sizeof(address), 0, "ADDR"); +} diff --git a/src/mappers/mapper355.h b/src/mappers/mapper355.h new file mode 100644 index 000000000..2b4c1d063 --- /dev/null +++ b/src/mappers/mapper355.h @@ -0,0 +1,140 @@ +#ifndef _MAPPER_355_H +#define _MAPPER_355_H + +/* microcontroller ROM */ + +static uint8 eprom_3d_block[] = { + 0xFE, 0x0C, 0x05, 0x00, 0x00, 0x0C, 0x25, 0x00, 0x00, 0x00, 0xFF, 0x0C, 0x05, 0x00, 0x00, 0x08, + 0x28, 0x00, 0xE8, 0x02, 0x09, 0x0A, 0x00, 0x08, 0x28, 0x00, 0xE8, 0x02, 0x0D, 0x0A, 0xE9, 0x02, + 0x0D, 0x0A, 0x00, 0x08, 0xE2, 0x0C, 0x86, 0x01, 0x43, 0x06, 0x12, 0x0A, 0x00, 0x08, 0xE2, 0x01, + 0x00, 0x08, 0x01, 0x08, 0x01, 0x08, 0x01, 0x08, 0x00, 0x08, 0xFF, 0x08, 0xFF, 0x08, 0xFF, 0x08, + 0xE2, 0x01, 0xFF, 0x08, 0xFF, 0x08, 0x00, 0x08, 0x01, 0x08, 0x01, 0x08, 0x01, 0x08, 0x00, 0x08, + 0xFF, 0x08, 0xFF, 0x0C, 0x05, 0x00, 0xFF, 0x0C, 0x06, 0x00, 0xE2, 0x0C, 0x86, 0x01, 0x43, 0x07, + 0x2D, 0x0A, 0xE2, 0x0C, 0x86, 0x01, 0x43, 0x07, 0x2D, 0x0A, 0xE2, 0x0C, 0x86, 0x01, 0x43, 0x07, + 0x2D, 0x0A, 0x0E, 0x0C, 0x45, 0x01, 0x2A, 0x00, 0x43, 0x07, 0x44, 0x0A, 0x05, 0x0C, 0x29, 0x00, + 0x03, 0x0C, 0x0C, 0x09, 0x00, 0x09, 0x2D, 0x0A, 0x02, 0x0C, 0x8A, 0x01, 0x43, 0x07, 0x55, 0x0A, + 0x02, 0x0C, 0x29, 0x00, 0x05, 0x0C, 0x0C, 0x09, 0x00, 0x09, 0x0B, 0x0C, 0x29, 0x00, 0x90, 0x0C, + 0x08, 0x09, 0x00, 0x09, 0xE9, 0x02, 0x4F, 0x0A, 0x2D, 0x0A, 0x0E, 0x0C, 0x8A, 0x01, 0x43, 0x07, + 0x5C, 0x0A, 0xA0, 0x0C, 0x2B, 0x00, 0x2D, 0x0A, 0x04, 0x0C, 0x8A, 0x01, 0x43, 0x07, 0x98, 0x0A, + 0x02, 0x0C, 0x8B, 0x01, 0x43, 0x06, 0x2D, 0x0A, 0xEB, 0x00, 0xEB, 0x00, 0x03, 0x0C, 0x29, 0x00, + 0x2C, 0x0C, 0x0C, 0x09, 0x00, 0x09, 0x30, 0x0C, 0x2C, 0x00, 0x00, 0x0C, 0x2D, 0x00, 0x0B, 0x02, + 0x28, 0x00, 0xE2, 0x0C, 0x86, 0x01, 0x43, 0x07, 0x79, 0x0A, 0xE2, 0x0C, 0x86, 0x01, 0x43, 0x06, + 0x2D, 0x0A, 0xE8, 0x02, 0x71, 0x0A, 0x00, 0x09, 0x3B, 0x0C, 0x28, 0x00, 0xE2, 0x0C, 0x86, 0x01, + 0x43, 0x07, 0x86, 0x0A, 0xE2, 0x0C, 0x86, 0x01, 0x43, 0x06, 0x2D, 0x0A, 0xE8, 0x02, 0x7E, 0x0A, + 0x00, 0x09, 0x0B, 0x02, 0xEC, 0x01, 0x03, 0x07, 0x8E, 0x0A, 0xAD, 0x02, 0x3B, 0x0C, 0xEC, 0x01, + 0x03, 0x07, 0x93, 0x0A, 0xAD, 0x02, 0x02, 0x0C, 0x8D, 0x00, 0x03, 0x07, 0x6F, 0x0A, 0x2D, 0x0A, + 0x08, 0x0C, 0x8A, 0x01, 0x43, 0x07, 0xA1, 0x0A, 0x08, 0x0C, 0x2E, 0x00, 0xF0, 0x0C, 0x24, 0x00, + 0x5A, 0x0B, 0x0A, 0x0C, 0x8A, 0x01, 0x43, 0x07, 0xA7, 0x0A, 0x03, 0x04, 0xAC, 0x0A, 0x0C, 0x0C, + 0x8A, 0x01, 0x43, 0x07, 0x5D, 0x0B, 0x03, 0x05, 0x60, 0x03, 0xEE, 0x00, 0x43, 0x07, 0x5A, 0x0B, + 0x08, 0x0C, 0x2E, 0x00, 0xA4, 0x02, 0xF4, 0x0C, 0x84, 0x01, 0x43, 0x07, 0x5A, 0x0B, 0x1F, 0x0C, + 0x53, 0x01, 0x37, 0x00, 0x33, 0x03, 0x33, 0x03, 0x33, 0x03, 0x33, 0x03, 0x33, 0x03, 0x07, 0x0C, + 0x53, 0x01, 0x3A, 0x00, 0x0F, 0x0C, 0x52, 0x01, 0x39, 0x00, 0x28, 0x00, 0x32, 0x03, 0x32, 0x03, + 0x32, 0x03, 0x32, 0x03, 0x0F, 0x0C, 0x52, 0x01, 0x38, 0x00, 0x07, 0x0C, 0x51, 0x01, 0x35, 0x00, + 0x31, 0x03, 0x31, 0x03, 0x31, 0x03, 0x07, 0x0C, 0x51, 0x01, 0x34, 0x00, 0x31, 0x03, 0x31, 0x03, + 0x31, 0x03, 0x03, 0x0C, 0x51, 0x01, 0x33, 0x00, 0x07, 0x0C, 0x50, 0x01, 0x32, 0x00, 0x30, 0x03, + 0x30, 0x03, 0x30, 0x03, 0x07, 0x0C, 0x50, 0x01, 0x31, 0x00, 0x30, 0x03, 0x30, 0x03, 0x30, 0x03, + 0x03, 0x0C, 0x50, 0x01, 0x30, 0x00, 0x07, 0x0C, 0x79, 0x01, 0x28, 0x03, 0x04, 0x0C, 0x48, 0x01, + 0x33, 0x01, 0x08, 0x0C, 0x57, 0x01, 0x43, 0x06, 0xF6, 0x0A, 0xB8, 0x02, 0x10, 0x0C, 0x57, 0x01, + 0x43, 0x06, 0x06, 0x0B, 0x07, 0x0C, 0x77, 0x01, 0x17, 0x02, 0x17, 0x09, 0xF9, 0x01, 0xF9, 0x06, + 0xB9, 0x00, 0x17, 0x02, 0x20, 0x09, 0xFA, 0x01, 0xFA, 0x06, 0xBA, 0x00, 0x7B, 0x00, 0x02, 0x0C, + 0xB1, 0x00, 0x71, 0x02, 0xB1, 0x02, 0xF1, 0x06, 0x13, 0x0B, 0x19, 0x02, 0x91, 0x00, 0x03, 0x07, + 0x13, 0x0B, 0x11, 0x02, 0x39, 0x00, 0x02, 0x0C, 0xB2, 0x00, 0x72, 0x02, 0xB2, 0x02, 0xF2, 0x06, + 0x1F, 0x0B, 0x1A, 0x02, 0x92, 0x00, 0x03, 0x07, 0x1F, 0x0B, 0x12, 0x02, 0x3A, 0x00, 0x02, 0x0C, + 0xB0, 0x00, 0x70, 0x02, 0xB0, 0x02, 0xF0, 0x06, 0x2B, 0x0B, 0x18, 0x02, 0x90, 0x00, 0x03, 0x07, + 0x2B, 0x0B, 0x10, 0x02, 0x38, 0x00, 0x02, 0x0C, 0xB4, 0x00, 0x05, 0x0C, 0xB4, 0x00, 0x74, 0x02, + 0xB4, 0x02, 0xF4, 0x06, 0x39, 0x0B, 0x19, 0x02, 0x94, 0x00, 0x03, 0x06, 0x39, 0x0B, 0x14, 0x02, + 0x39, 0x00, 0x02, 0x0C, 0xB5, 0x00, 0x05, 0x0C, 0xB5, 0x00, 0x75, 0x02, 0xB5, 0x02, 0xF5, 0x06, + 0x47, 0x0B, 0x1A, 0x02, 0x95, 0x00, 0x03, 0x06, 0x47, 0x0B, 0x15, 0x02, 0x3A, 0x00, 0x02, 0x0C, + 0xB3, 0x00, 0x0A, 0x0C, 0xB3, 0x00, 0x73, 0x02, 0xB3, 0x02, 0xF3, 0x06, 0x58, 0x0B, 0x18, 0x02, + 0x93, 0x00, 0x43, 0x06, 0x57, 0x0B, 0x03, 0x06, 0x58, 0x0B, 0x13, 0x02, 0x38, 0x00, 0xBB, 0x02, + 0xF8, 0x0C, 0x24, 0x00, 0x12, 0x09, 0x00, 0x09, 0x2D, 0x0A, 0x12, 0x09, 0x00, 0x02, 0x43, 0x06, + 0x67, 0x0B, 0x03, 0x0C, 0x08, 0x09, 0x00, 0x09, 0xE0, 0x00, 0x43, 0x07, 0x61, 0x0B, 0xA4, 0x02, + 0x2D, 0x0A, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0x29, 0x0A +}; + +static uint8 eprom_block_force[] = { + 0xFE, 0x0C, 0x05, 0x00, 0x05, 0x05, 0xFF, 0x0C, 0x06, 0x00, 0x02, 0x0C, 0x3A, 0x00, 0x00, 0x0C, + 0x3B, 0x00, 0x05, 0x0C, 0x3C, 0x00, 0x06, 0x0C, 0x3D, 0x00, 0x00, 0x0C, 0x3E, 0x00, 0x00, 0x0C, + 0x3F, 0x00, 0xDD, 0x0C, 0x86, 0x01, 0x43, 0x07, 0x11, 0x0A, 0xDD, 0x0C, 0x86, 0x01, 0x43, 0x06, + 0x15, 0x0A, 0xDF, 0x0C, 0x86, 0x01, 0x43, 0x07, 0x11, 0x0A, 0x0F, 0x0C, 0x45, 0x01, 0xE2, 0x01, + 0x30, 0x0A, 0x30, 0x0A, 0x38, 0x0A, 0x38, 0x0A, 0x34, 0x0A, 0x34, 0x0A, 0x48, 0x0A, 0x48, 0x0A, + 0x32, 0x0A, 0x32, 0x0A, 0x44, 0x0A, 0x44, 0x0A, 0x36, 0x0A, 0x36, 0x0A, 0x4B, 0x0A, 0x4B, 0x0A, + 0x64, 0x00, 0x11, 0x0A, 0xA4, 0x02, 0x11, 0x0A, 0x60, 0x00, 0x11, 0x0A, 0xA0, 0x02, 0x11, 0x0A, + 0x10, 0x02, 0x32, 0x00, 0x11, 0x02, 0x33, 0x00, 0xF2, 0x02, 0x3C, 0x0A, 0xF3, 0x02, 0x3C, 0x0A, + 0x05, 0x04, 0x05, 0x04, 0x05, 0x05, 0x11, 0x0A, 0x08, 0x02, 0xE2, 0x01, 0x50, 0x0A, 0x88, 0x0A, + 0x00, 0x02, 0x27, 0x00, 0x11, 0x0A, 0xE7, 0x02, 0x11, 0x0A, 0x05, 0x04, 0x05, 0x05, 0x11, 0x0A, + 0x19, 0x02, 0x9F, 0x00, 0x43, 0x06, 0x57, 0x0A, 0x03, 0x07, 0x7B, 0x0A, 0x11, 0x0A, 0x18, 0x02, + 0x9E, 0x00, 0x43, 0x06, 0x5E, 0x0A, 0x03, 0x07, 0x7B, 0x0A, 0x11, 0x0A, 0x17, 0x02, 0x9D, 0x00, + 0x43, 0x06, 0x65, 0x0A, 0x03, 0x07, 0x7B, 0x0A, 0x11, 0x0A, 0x16, 0x02, 0x9C, 0x00, 0x43, 0x06, + 0x6C, 0x0A, 0x03, 0x07, 0x7B, 0x0A, 0x11, 0x0A, 0x15, 0x02, 0x9B, 0x00, 0x43, 0x06, 0x73, 0x0A, + 0x03, 0x07, 0x7B, 0x0A, 0x11, 0x0A, 0x14, 0x02, 0x9A, 0x00, 0x43, 0x06, 0x7A, 0x0A, 0x03, 0x07, + 0x7B, 0x0A, 0x11, 0x0A, 0x11, 0x0A, 0x14, 0x02, 0x3A, 0x00, 0x15, 0x02, 0x3B, 0x00, 0x16, 0x02, + 0x3C, 0x00, 0x17, 0x02, 0x3D, 0x00, 0x18, 0x02, 0x3E, 0x00, 0x19, 0x02, 0x3F, 0x00, 0x11, 0x0A, + 0x8B, 0x09, 0x29, 0x00, 0x11, 0x0A, 0x09, 0x02, 0xE2, 0x01, 0x00, 0x08, 0x19, 0x08, 0x33, 0x08, + 0x4C, 0x08, 0x66, 0x08, 0x80, 0x08, 0x99, 0x08, 0xB3, 0x08, 0xCC, 0x08, 0xE6, 0x08, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x0F, 0x00, 0x0A +}; + +#endif /* _MAPPER_355_H */ \ No newline at end of file diff --git a/src/boards/mapper356.c b/src/mappers/mapper356.c similarity index 63% rename from src/boards/mapper356.c rename to src/mappers/mapper356.c index ec56917a5..9dcca7e93 100644 --- a/src/boards/mapper356.c +++ b/src/mappers/mapper356.c @@ -1,8 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -26,15 +25,25 @@ #include "mapinc.h" #include "mmc3.h" -static uint8 *CHRRAM = NULL; +static uint8 reg[4]; +static uint8 cmd; + +static uint8 *CHRRAM = NULL; static uint32 CHRRAMSIZE = 0; extern uint8 *ExtraNTARAM; +static SFORMAT StateRegs[] = { + { reg, 4, "REGS" }, + { &cmd, 1, "CMD0" }, + { 0 } +}; + static void M356CW(uint32 A, uint8 V) { - if (mmc3.expregs[2] & 0x20) { - uint32 mask = 0xFF >> (~mmc3.expregs[2] & 0xF); - uint32 base = ((mmc3.expregs[2] << 4) & 0xF00) | mmc3.expregs[0]; + if (reg[2] & 0x20) { + uint16 mask = 0xFF >> (~reg[2] & 0xF); + uint16 base = ((reg[2] << 4) & 0xF00) | reg[0]; + setchr1(A, (base & ~mask) | (V & mask)); } else { setchr8r(0x10, 0); @@ -42,58 +51,60 @@ static void M356CW(uint32 A, uint8 V) { } static void M356PW(uint32 A, uint8 V) { - uint32 mask = ~mmc3.expregs[3] & 0x3F; - uint32 base = ((mmc3.expregs[2] << 2) & 0x300) | mmc3.expregs[1]; + uint16 mask = ~reg[3] & 0x3F; + uint16 base = ((reg[2] << 2) & 0x300) | reg[1]; + setprg8(A, (base & ~mask) | (V & mask)); } -static void M356MW(uint8 V) { - if (mmc3.expregs[2] & 0x40) { - SetupCartMirroring(4, 1, ExtraNTARAM); +static void M356MIR(void) { + if (reg[2] & 0x40) { + SetupCartMirroring(4, 0, ExtraNTARAM); } else { - mmc3.mirroring = V; - SetupCartMirroring((V & 1) ^ 1, 0, 0); + setmirror((mmc3.mirr & 0x01) ^ 0x01); } } static DECLFW(M356Write) { - if (!(mmc3.expregs[3] & 0x40)) { - mmc3.expregs[mmc3.expregs[4]] = V; - mmc3.expregs[4] = (mmc3.expregs[4] + 1) & 3; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + if (!(reg[3] & 0x40)) { + reg[cmd] = V; + cmd = (cmd + 1) & 3; + MMC3_FixPRG(); + MMC3_FixCHR(); + MMC3_FixMIR(); } } static void M356Close(void) { - GenMMC3Close(); - if (CHRRAM) + MMC3_Close(); + if (CHRRAM) { FCEU_free(CHRRAM); + } CHRRAM = NULL; } static void M356Reset(void) { - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[3] = mmc3.expregs[4] = 0; - mmc3.expregs[2] = 0x0F; - MMC3RegReset(); + reg[0] = reg[1] = reg[3] = cmd = 0; + reg[2] = 0x0F; + MMC3_Reset(); } static void M356Power(void) { - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[3] = mmc3.expregs[4] = 0; - mmc3.expregs[2] = 0x0F; - GenMMC3Power(); + reg[0] = reg[1] = reg[3] = cmd = 0; + reg[2] = 0x0F; + MMC3_Power(); SetWriteHandler(0x6000, 0x7FFF, M356Write); } void Mapper356_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 0, 0); - mmc3.cwrap = M356CW; - mmc3.pwrap = M356PW; - mmc3.mwrap = M356MW; + MMC3_Init(info, 0, 0); + MMC3_cwrap = M356CW; + MMC3_pwrap = M356PW; + MMC3_FixMIR = M356MIR; info->Reset = M356Reset; info->Power = M356Power; info->Close = M356Close; - AddExState(mmc3.expregs, 5, 0, "EXPR"); + AddExState(StateRegs, ~0, 0, NULL); CHRRAMSIZE = 8192; CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); diff --git a/src/boards/mapper357.c b/src/mappers/mapper357.c similarity index 58% rename from src/boards/mapper357.c rename to src/mappers/mapper357.c index 31292191e..fe1948ed7 100644 --- a/src/boards/mapper357.c +++ b/src/mappers/mapper357.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -27,92 +28,85 @@ #include "mapinc.h" -static uint8 preg[4]; -static uint8 dipswitch; +static uint8 reg[4]; +static uint8 dipsw; static uint8 IRQa; static uint16 IRQCount; -static const uint8 banks[8] = { 4, 3, 5, 3, 6, 3, 7, 3 }; -static const uint8 outer_bank[4] = { 0x00, 0x08, 0x10, 0x18 }; - -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { + { reg, 4, "REG" }, + { &dipsw, 1, "DPSW" }, { &IRQCount, 2, "IRQC" }, { &IRQa, 1, "IRQA" }, - { &dipswitch, 1, "DPSW" }, - { &preg, 4, "REG" }, { 0 } }; static void Sync(void) { - if (dipswitch == 0) { + if (dipsw == 0) { + static const uint8 banks[2][8] = { + { 4, 3, 5, 3, 6, 3, 7, 3 }, + { 1, 1, 5, 1, 4, 1, 5, 1 } + }; /* SMB2J Mode */ - setprg4(0x5000, 16); - setprg8(0x6000, preg[1] ? 0 : 2); - setprg8(0x8000, 1); - setprg8(0xa000, 0); - setprg8(0xc000, banks[preg[0]]); - setprg8(0xe000, preg[1] ? 8 : 10); + setprg8(0x6000, reg[1] ? 0 : 2); + setprg8(0x8000, reg[1] ? 0 : 1); + setprg8(0xA000, 0); + setprg8(0xC000, banks[reg[1]][reg[0]]); + setprg8(0xE000, reg[1] ? 8 : 10); } else { /* UNROM Mode */ - setprg16(0x8000, outer_bank[dipswitch] | preg[2]); - setprg16(0xc000, outer_bank[dipswitch] | 7); + setprg16(0x8000, (dipsw << 3) | reg[2]); + setprg16(0xc000, (dipsw << 3) | 0x07); } - setchr8(0); - setmirror(dipswitch == 3 ? MI_H : MI_V); } -static DECLFW(M357WriteLo) { - switch (A & 0x71ff) { - case 0x4022: - preg[0] = V & 7; - Sync(); - break; - case 0x4120: - preg[1] = V & 1; - Sync(); - break; +static DECLFW(M357Write) { + if (A & 0x8000) { + reg[2] = V & 0x07; + Sync(); } -} - -static DECLFW(M357WriteIRQ) { - IRQa = V & 1; - if (!IRQa) { + if ((A & 0x71FF) == 0x4022) { + reg[0] = V & 0x07; + Sync(); + } + if ((A & 0x71FF) == 0x4120) { + reg[1] = V & 0x01; + Sync(); + } + if ((A & 0xF1FF) == 0x4122) { + IRQa = V & 0x01; IRQCount = 0; X6502_IRQEnd(FCEU_IQEXT); } } -static DECLFW(M357WriteUNROM) { - preg[2] = V & 7; - Sync(); -} - static void M357Power(void) { - preg[0] = 0; - preg[1] = 0; + reg[0] = 0; + reg[1] = 0; + reg[2] = 0; IRQa = IRQCount = 0; + setchr8(0); + setmirror(MI_V); Sync(); - SetReadHandler(0x5000, 0xffff, CartBR); - SetWriteHandler(0x4022, 0x4022, M357WriteLo); - SetWriteHandler(0x4120, 0x4120, M357WriteLo); - SetWriteHandler(0x4122, 0x4122, M357WriteIRQ); - SetWriteHandler(0x8000, 0xffff, M357WriteUNROM); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x4020, 0xFFFF, M357Write); } static void M357Reset(void) { + reg[0] = 0; + reg[1] = 0; + reg[2] = 0; IRQa = IRQCount = 0; - dipswitch++; - dipswitch &= 3; + dipsw++; + dipsw &= 3; + setmirror((dipsw == 3) ? MI_H : MI_V); Sync(); } -static void FP_FASTAPASS(1) M357IRQHook(int a) { +static void M357IRQHook(int a) { if (IRQa) { - if (IRQCount < 4096) - IRQCount += a; - else { - IRQa = 0; + IRQCount += a; + if (IRQCount & 0x1000) { X6502_IRQBegin(FCEU_IQEXT); } } @@ -127,5 +121,5 @@ void Mapper357_Init(CartInfo *info) { info->Power = M357Power; MapIRQHook = M357IRQHook; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper358.c b/src/mappers/mapper358.c new file mode 100644 index 000000000..4249ebbbe --- /dev/null +++ b/src/mappers/mapper358.c @@ -0,0 +1,41 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "jyasic.h" + +static uint32 GetPRGBank(uint32 V) { + return (((jyasic.mode[3] << 4) & ~0x1F) | (V & 0x1F)); +} + +static uint32 GetCHRBank(uint32 V) { + if (jyasic.mode[3] & 0x20) { + return (((jyasic.mode[3] << 7) & 0x600) | (V & 0x1FF)); + } else { + return (((jyasic.mode[3] << 7) & 0x600) | ((jyasic.mode[3] << 8) & 0x100) | (V & 0x0FF)); + } +} + +void Mapper358_Init(CartInfo *info) { + /* Multicart */ + JYASIC_Init(info, TRUE); + JYASIC_GetPRGBank = GetPRGBank; + JYASIC_GetCHRBank = GetCHRBank; +} diff --git a/src/mappers/mapper359.c b/src/mappers/mapper359.c new file mode 100644 index 000000000..531443d27 --- /dev/null +++ b/src/mappers/mapper359.c @@ -0,0 +1,225 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 359 - BMC-SB-5013 + * NES 2.0 Mapper 540 - UNL-82112C + */ + +#include "mapinc.h" +#include "fdssound.h" + +static uint8 prg[4]; +static uint8 chr[8]; +static uint8 reg[4]; + +static uint8 IRQReload; +static uint8 IRQa; +static uint8 irqPA12; +static uint8 IRQAutoEnable; +static uint8 IRQLatch; +static uint8 IRQCount; +static int16 IRQCount16; + +static SFORMAT StateRegs[] = { + { prg, 4, "PREG" }, + { chr, 8, "CREG" }, + { reg, 4, "EXPR" }, + { &IRQReload, 1, "IRQL" }, + { &IRQa, 1, "IRQa" }, + { &irqPA12, 1, "IRQp" }, + { &IRQAutoEnable, 1, "IRQe" }, + { &IRQLatch, 1, "IRQl" }, + { &IRQCount, 1, "IRQ8" }, + { &IRQCount16, 2, "IRQC" }, + { 0 } +}; + +static void Sync(void) { + uint16 prgMask = 0x3F; + uint16 prgBase = (reg[0] & 0x38) << 1; + + switch (reg[1] & 0x03) { + case 0: prgMask = 0x3F; break; + case 1: prgMask = 0x1F; break; + case 2: prgMask = 0x2F; break; + case 3: prgMask = 0x0F; break; + } + + setprg8(0x6000, prgBase | (prg[3] & prgMask)); + setprg8(0x8000, prgBase | (prg[0] & prgMask)); + setprg8(0xA000, prgBase | (prg[1] & prgMask)); + setprg8(0xC000, prgBase | (prg[2] & prgMask)); + setprg8(0xE000, prgBase | ( ~0 & prgMask)); + + if (UNIFchrrama) { + setchr8(0); + } else { + if (iNESCart.mapper == 540) { + setchr2(0x0000, chr[0]); + setchr2(0x0800, chr[1]); + setchr2(0x1000, chr[6]); + setchr2(0x1800, chr[7]); + } else { + uint16 chrMask = (reg[1] & 0x40) ? 0xFF : 0x7F; + uint16 chrBase = (reg[3] << 7); + + setchr1(0x0000, chrBase | (chr[0] & chrMask)); + setchr1(0x0400, chrBase | (chr[1] & chrMask)); + setchr1(0x0800, chrBase | (chr[2] & chrMask)); + setchr1(0x0C00, chrBase | (chr[3] & chrMask)); + setchr1(0x1000, chrBase | (chr[4] & chrMask)); + setchr1(0x1400, chrBase | (chr[5] & chrMask)); + setchr1(0x1800, chrBase | (chr[6] & chrMask)); + setchr1(0x1C00, chrBase | (chr[7] & chrMask)); + } + } + + switch (reg[2] & 0x03) { + case 0: setmirror(MI_V); break; + case 1: setmirror(MI_H); break; + case 2: setmirror(MI_0); break; + case 3: setmirror(MI_1); break; + } +} + +static DECLFW(M359Write) { + switch (A & 0xF000) { + case 0x8000: + prg[A & 0x03] = V; + Sync(); + break; + case 0x9000: + reg[A & 0x03] = V; + Sync(); + break; + case 0xA000: + case 0xB000: + chr[((A >> 10) & 0x04) | (A & 0x03)] = V; + Sync(); + break; + case 0xC000: + switch (A & 0x03) { + case 0: + if (IRQAutoEnable) { + IRQa = FALSE; + } + IRQCount16 &= 0xFF00; + IRQCount16 |= V; + X6502_IRQEnd(FCEU_IQEXT); + break; + case 1: + if (IRQAutoEnable) { + IRQa = TRUE; + } + IRQCount16 &= 0x00FF; + IRQCount16 |= (V << 8); + IRQReload = TRUE; + IRQLatch = V; + X6502_IRQEnd(FCEU_IQEXT); + break; + case 2: + IRQa = (V & 0x01); + irqPA12 = (V & 0x02) >> 1; + IRQAutoEnable = (V & 0x04) >> 2; + X6502_IRQEnd(FCEU_IQEXT); + break; + case 3: + IRQa = (V & 0x01); + X6502_IRQEnd(FCEU_IQEXT); + break; + } + } +} + +static void M359Power(void) { + prg[0] = ~3; + prg[1] = ~2; + prg[2] = ~1; + prg[3] = ~0; + chr[0] = 0; + chr[1] = 1; + chr[2] = 2; + chr[3] = 3; + chr[4] = 4; + chr[5] = 5; + chr[6] = 6; + chr[7] = 7; + reg[0] = 0; + reg[1] = 0x40; + reg[2] = 0; + reg[3] = 0; + IRQReload = IRQa = irqPA12 = IRQAutoEnable = 0; + IRQLatch = IRQCount = IRQCount16 = 0; + Sync(); + FDSSound_Power(); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xCFFF, M359Write); +} + +static void M359Reset(void) { + FDSSound_Reset(); + Sync(); +} + +static void M359CPUHook(int a) { + if (!irqPA12) { + if (IRQa && IRQCount16) { + IRQCount16 -= a; + if (IRQCount16 <= 0) + X6502_IRQBegin(FCEU_IQEXT); + } + } +} + +static void M359IRQHook(void) { + if (irqPA12) { + if (!IRQCount || IRQReload) { + IRQCount = IRQLatch; + } else { + IRQCount--; + } + if (!IRQCount && IRQa) { + X6502_IRQBegin(FCEU_IQEXT); + } + IRQReload = FALSE; + } +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper359_Init(CartInfo *info) { + info->Power = M359Power; + info->Reset = M359Reset; + MapIRQHook = M359CPUHook; + GameHBIRQHook = M359IRQHook; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} + +void Mapper540_Init(CartInfo *info) { + info->Power = M359Power; + MapIRQHook = M359CPUHook; + GameHBIRQHook = M359IRQHook; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/mapper360.c b/src/mappers/mapper360.c similarity index 75% rename from src/boards/mapper360.c rename to src/mappers/mapper360.c index eb61154d0..59b9453e2 100644 --- a/src/boards/mapper360.c +++ b/src/mappers/mapper360.c @@ -1,7 +1,8 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 + * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -22,37 +23,36 @@ #include "mapinc.h" -static uint8 dipswitch; +static uint8 dipsw; -static SFORMAT StateRegs[] = -{ - { &dipswitch, 1, "DPSW" }, +static SFORMAT StateRegs[] = { + { &dipsw, 1, "DPSW" }, { 0 } }; static void Sync(void) { /* dip 0 and 1 is the same game SMB) */ - if (dipswitch < 2) - setprg32(0x8000, dipswitch >> 1); - else { - setprg16(0x8000, dipswitch); - setprg16(0xC000, dipswitch); + if (dipsw < 2) { + setprg32(0x8000, dipsw >> 1); + } else { + setprg16(0x8000, dipsw); + setprg16(0xC000, dipsw); } - setchr8(dipswitch); - setmirror(((dipswitch & 0x10) >> 4) ^ 1); + setchr8(dipsw); + setmirror(((dipsw & 0x10) >> 4) ^ 1); } static void M360Power(void) { - dipswitch = 0; + dipsw = 0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0XFFFF, CartBW); } static void M360Reset(void) { - dipswitch = (dipswitch + 1) & 31; + dipsw = (dipsw + 1) & 31; Sync(); - FCEU_printf("dipswitch = %d\n", dipswitch); + FCEU_printf("dipsw = %d\n", dipsw); } static void StateRestore(int version) { @@ -63,5 +63,5 @@ void Mapper360_Init(CartInfo *info) { info->Reset = M360Reset; info->Power = M360Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper361.c b/src/mappers/mapper361.c new file mode 100644 index 000000000..346484b21 --- /dev/null +++ b/src/mappers/mapper361.c @@ -0,0 +1,70 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 361 (YY841101C): + * JY-009 + * JY-018 + * JY-019 + * OK-411 +*/ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 reg; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; + +static void M361PW(uint32 A, uint8 V) { + setprg8(A, (reg & 0xF0) | (V & 0x0F)); +} + +static void M361CW(uint32 A, uint8 V) { + setchr1(A, ((reg & 0xF0) << 3) | (V & 0x7F)); +} + +static void M361Reset(void) { + reg = 0; + MMC3_Reset(); +} + +static DECLFW(M361Write) { + reg = V; + MMC3_FixPRG(); + MMC3_FixCHR(); +} + +static void M361Power(void) { + reg = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M361Write); +} + +void Mapper361_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_pwrap = M361PW; + MMC3_cwrap = M361CW; + info->Power = M361Power; + info->Reset = M361Reset; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/mapper362.c b/src/mappers/mapper362.c similarity index 67% rename from src/boards/mapper362.c rename to src/mappers/mapper362.c index 3aeded9ba..6335757ef 100644 --- a/src/boards/mapper362.c +++ b/src/mappers/mapper362.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -23,7 +23,7 @@ */ #include "mapinc.h" -#include "vrc24.h" +#include "vrc2and4.h" static uint8 game; static uint8 PPUCHRBus; @@ -35,40 +35,33 @@ static SFORMAT StateRegs[] = { }; static void M362PW(uint32 A, uint8 V) { - uint8 prgBase = (game == 0) ? ((vrc24.chrhi[PPUCHRBus] << 1) & 0x30) : 0x40; + uint16 prgBase = (game == 0) ? ((vrc24.chr[PPUCHRBus] & 0x180) >> 3) : 0x40; + setprg8(A, prgBase | (V & 0x0F)); } static void M362CW(uint32 A, uint32 V) { - uint32 chrBase = (game == 0) ? ((vrc24.chrhi[PPUCHRBus] << 4) & 0x180) : 0x200; - uint32 chrMask = (game == 0) ? 0x7F : 0x1FF; + uint16 chrBase = (game == 0) ? (vrc24.chr[PPUCHRBus] & 0x180) : 0x200; + uint16 chrMask = (game == 0) ? 0x7F : 0x1FF; + setchr1(A, chrBase | (V & chrMask)); } static DECLFW(M362CHRWrite) { - VRC24Write(A, V); + VRC24_Write(A, V); if (A & 0x01) { /* NOTE: Because the lst higher 2 CHR-ROM bits are repurposed as PRG/CHR outer bank, an extra PRG sync after a CHR write. */ - FixVRC24PRG(); - } -} - -static DECLFW(M362IRQWrite) { - /* NOTE: acknowledge IRQ but do not move A control bit to E control bit. - * So, just make E bit the same with A bit coz im lazy to modify IRQ code for now. */ - if ((A & 0x03) == 0x02) { - V |= ((V >> 1) & 0x01); + VRC24_FixPRG(); } - VRC24Write(A, V); } -static void FP_FASTAPASS(1) M362PPUHook(uint32 A) { +static void M362PPUHook(uint32 A) { uint8 bank = (A & 0x1FFF) >> 10; if ((game == 0) && (PPUCHRBus != bank) && ((A & 0x3000) != 0x2000)) { PPUCHRBus = bank; - FixVRC24CHR(); - FixVRC24PRG(); + VRC24_FixCHR(); + VRC24_FixPRG(); } } @@ -78,23 +71,22 @@ static void M362Reset(void) { } else { game = (game + 1) & 0x01; } - FixVRC24CHR(); - FixVRC24PRG(); + VRC24_FixCHR(); + VRC24_FixPRG(); } static void M362Power(void) { PPUCHRBus = game = 0; - GenVRC24Power(); + VRC24_Power(); SetWriteHandler(0xB000, 0xEFFF, M362CHRWrite); - SetWriteHandler(0xF000, 0xFFFF, M362IRQWrite); } void Mapper362_Init(CartInfo *info) { - GenVRC24_Init(info, VRC4f, 0); + VRC24_Init(info, VRC4, 0x01, 0x02, 0, 0); info->Reset = M362Reset; info->Power = M362Power; PPU_hook = M362PPUHook; - vrc24.pwrap = M362PW; - vrc24.cwrap = M362CW; - AddExState(StateRegs, ~0, 0, 0); + VRC24_pwrap = M362PW; + VRC24_cwrap = M362CW; + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper364.c b/src/mappers/mapper364.c similarity index 64% rename from src/boards/mapper364.c rename to src/mappers/mapper364.c index 3f419c4f5..a3251b6f2 100644 --- a/src/boards/mapper364.c +++ b/src/mappers/mapper364.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2022 + * Copyright (C) 2023-2024 negativeExponent * * 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,32 +22,41 @@ #include "mapinc.h" #include "mmc3.h" +static uint8 reg; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; + static void M364CW(uint32 A, uint8 V) { - V &= (mmc3.expregs[0] & 0x20) ? 0x7F : 0xFF; - setchr1(A, V | ((mmc3.expregs[0] << 4) & 0x100)); + uint8 mask = (reg & 0x20) ? 0x7F : 0xFF; + + setchr1(A, ((reg << 4) & 0x100) | (V & mask)); } static void M364PW(uint32 A, uint8 V) { - V &= (mmc3.expregs[0] & 0x20) ? 0x0F : 0x1F; - setprg8(A, V | ((mmc3.expregs[0] >> 1) & 0x20)); + uint8 mask = (reg & 0x20) ? 0x0F : 0x1F; + + setprg8(A, ((reg >> 1) & 0x20) | (V & mask)); } static DECLFW(M364Write) { - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + reg = V; + MMC3_FixPRG(); + MMC3_FixCHR(); } static void M364Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); - SetWriteHandler(0x7000, 0x7FFF, M364Write); + reg = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M364Write); } void Mapper364_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 512, 8, 0); - mmc3.pwrap = M364PW; - mmc3.cwrap = M364CW; + MMC3_Init(info, 8, 0); + MMC3_pwrap = M364PW; + MMC3_cwrap = M364CW; info->Power = M364Power; - AddExState(mmc3.expregs, 1, 0, "EXPR"); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper366.c b/src/mappers/mapper366.c new file mode 100644 index 000000000..aa57adeb8 --- /dev/null +++ b/src/mappers/mapper366.c @@ -0,0 +1,67 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 366 (GN-45): + * K-3131GS + * K-3131SS +*/ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 reg; + +static void M366PW(uint32 A, uint8 V) { + setprg8(A, reg | (V & 0x0F)); +} + +static void M366CW(uint32 A, uint8 V) { + setchr1(A, (reg << 3) | (V & 0x7F)); +} + +static void M366Reset(void) { + reg = 0; + MMC3_Reset(); +} + +static DECLFW(M366Write) { + CartBW(A, V); + if (!(reg & 0x80)) { + reg = A & 0xF0; + MMC3_FixPRG(); + MMC3_FixCHR(); + } +} + +static void M366Power(void) { + reg = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M366Write); +} + +void Mapper366_Init(CartInfo *info) { + MMC3_Init(info, 8, 0); + MMC3_pwrap = M366PW; + MMC3_cwrap = M366CW; + info->Power = M366Power; + info->Reset = M366Reset; + AddExState(®, 1, 0, "EXPR"); +} diff --git a/src/boards/mapper368.c b/src/mappers/mapper368.c similarity index 60% rename from src/boards/mapper368.c rename to src/mappers/mapper368.c index 518bf3f44..9c7177e9d 100644 --- a/src/boards/mapper368.c +++ b/src/mappers/mapper368.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2022 + * Copyright (C) 2023-2024 negativeExponent * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -21,79 +22,89 @@ /* NES 2.0 Mapper 357 is used for a 4-in-1 multicart (cartridge ID 4602) from Bit Corp. * The first game is Bit Corp's hack of the YUNG-08 conversion of Super Mario Brothers 2 (J) named Mr. Mary 2, * the other three games are UNROM games. - * - * Implementation is modified so reset actually sets the correct dipswitch (or outer banks) for each of the 4 games */ + #include "mapinc.h" -static uint8 preg; -static uint8 latch; +static uint8 reg[2]; static uint8 IRQa; static uint16 IRQCount; -static const uint8 banks[8] = { 4, 3, 5, 3, 6, 3, 7, 3 }; - -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, { &IRQCount, 2, "IRQC" }, { &IRQa, 1, "IRQA" }, - { &latch, 1, "LATC" }, - { &preg, 1, "REG" }, { 0 } }; static void Sync(void) { - setprg8(0x6000, 2); - setprg8(0x8000, 1); - setprg8(0xa000, 0); - setprg8(0xc000, banks[preg]); - setprg8(0xe000, 8); - setchr8(0); -} + /* + The actual bank number is: + Value Bank# + ------------ + 0 4 + 1 3 + 2 5 + 3 3 + 4 6 + 5 3 + 6 7 + 7 3 */ + uint8 prg = (reg[0] & 0x01) ? 0x03 : (0x04 | ((reg[0] >> 1) & 0x03)); -static DECLFW(M368WritePRG) { - preg = V & 7; - Sync(); + setprg8(0x6000, 0x02); + setprg8(0x8000, 0x01); + setprg8(0xA000, 0x00); + setprg8(0xC000, prg); + setprg8(0xE000, 0x08); + setchr8(0); } -static DECLFW(M368WriteIRQ) { - latch = V & 0x53; - IRQa = V & 1; - if (!IRQa) { - IRQCount = 0; - X6502_IRQEnd(FCEU_IQEXT); +static DECLFR(M368Read) { + if ((A & 0xF1FF) == 0x4122) { + return (0x8A | (reg[1] & 0x35)); } + return CartBR(A); } -static DECLFR(M368Read) { - return (latch | 0xBA); +static DECLFW(M368Write) { + switch (A & 0xF1FF) { + case 0x4022: + reg[0] = V; + Sync(); + break; + case 0x4122: + reg[1] = V; + IRQa = V & 0x01; + if (!IRQa) { + IRQCount = 0; + X6502_IRQEnd(FCEU_IQEXT); + } + break; + } } static void M368Power(void) { - preg = 0; - latch = 0; + reg[0] = reg[1] = 0; IRQa = IRQCount = 0; Sync(); - SetReadHandler(0x4122, 0x4122, M368Read); - SetReadHandler(0x6000, 0x7FFF, CartBR); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x4022, 0x4022, M368WritePRG); - SetWriteHandler(0x4120, 0x4120, M368WritePRG); - SetWriteHandler(0x4122, 0x4122, M368WriteIRQ); + SetReadHandler(0x4020, 0x4FFF, M368Read); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x4020, 0x4FFF, M368Write); } static void M368Reset(void) { + reg[0] = reg[1] = 0; IRQa = IRQCount = 0; Sync(); } -static void FP_FASTAPASS(1) M368IRQHook(int a) { +static void M368IRQHook(int a) { if (IRQa) { - if (IRQCount < 4096) - IRQCount += a; - else { - IRQa = 0; + IRQCount += a; + if (IRQCount >= 4096) { + IRQCount -= 4096; X6502_IRQBegin(FCEU_IQEXT); } } @@ -108,5 +119,5 @@ void Mapper368_Init(CartInfo *info) { info->Power = M368Power; MapIRQHook = M368IRQHook; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper369.c b/src/mappers/mapper369.c new file mode 100644 index 000000000..6bd26eca8 --- /dev/null +++ b/src/mappers/mapper369.c @@ -0,0 +1,165 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 369 (BMC-N49C-300) - Super Mario Bros. Party multicart */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 reg; +static uint8 smb2j; +static uint8 IRQa; +static uint16 IRQCount; + +static SFORMAT StateRegs[] = { + { ®, 1, "MODE" }, + { &smb2j, 1, "SMB2" }, + { &IRQa, 1, "MIQA" }, + { &IRQCount, 2, "MIQC" }, + { 0 } +}; + +static void M369PW(uint32 A, uint8 V) { + uint8 mask = (reg == 0xFF) ? 0x1F : 0x0F; + uint8 base = (reg == 0xFF) ? 0x20 : 0x10; + + setprg8(A, (base & ~mask) | (V & mask)); +} + +static void M369CW(uint32 A, uint8 V) { + uint16 mask = (reg == 0xFF) ? 0xFF : 0x7F; + uint16 base = (reg == 0xFF) ? 0x100 : 0x80; + + setchr1(A, (base & ~mask) | (V & mask)); +} + +static void M369Sync(void) { + switch (reg) { + case 0x00: + case 0x01: /* NROM */ + setprg32(0x8000, reg); + setchr8(reg & 0x03); + break; + case 0x13: /* SMB2J */ + setprg8r(0, 0x6000, 0x0E); + setprg8(0x8000, 0x0C); + setprg8(0xA000, 0x0D); + setprg8(0xC000, 0x08 | (smb2j & 0x03)); + setprg8(0xE000, 0x0F); + setchr8(reg & 0x03); + break; + case 0x37: /* MMC3: 128 KiB CHR */ + case 0xFF: /* MMC3: 256 KiB CHR */ + setprg8r(0x10, 0x6000, 0); + MMC3_FixPRG(); + MMC3_FixCHR(); + } +} + +static DECLFW(M369WriteLo) { + if (A & 0x100) { + reg = V; + M369Sync(); + } +} + +static DECLFW(M369Write) { + switch (A & 0xE000) { + case 0x8000: + if (reg == 0x13) { + IRQa = 0; + X6502_IRQEnd(FCEU_IQEXT); + } + if (A & 0x01) { + mmc3.reg[mmc3.cmd & 0x07] = V; + M369Sync(); + } else { + mmc3.cmd = V; + M369Sync(); + } + break; + case 0xA000: + if (reg == 0x13) { + IRQa = (V & 0x02) != 0; + } + MMC3_CMDWrite(A, V); + break; + case 0xC000: + MMC3_IRQWrite(A, V); + break; + case 0xE000: + if (reg == 0x13) { + smb2j = V; + M369Sync(); + } + MMC3_IRQWrite(A, V); + break; + } +} + +static void SMB2JIRQHook(int a) { + if (reg == 0x13) { + if (IRQa) { + IRQCount += a; + if (IRQCount >= 4096) { + IRQCount -= 4096; + X6502_IRQBegin(FCEU_IQEXT); + } + } + } +} + +static void MMC3IRQHook(void) { + if (reg != 0x13) { + MMC3_IRQHBHook(); + } +} + +static void M369Reset(void) { + reg = smb2j = 0; + IRQa = IRQCount = 0; + MMC3_Reset(); + M369Sync(); +} + +static void StateRestore(int version) { + M369Sync(); +} + +static void M369Power(void) { + reg = smb2j = 0; + IRQa = IRQCount = 0; + MMC3_Power(); + SetWriteHandler(0x4100, 0x4FFF, M369WriteLo); + SetWriteHandler(0x8000, 0xFFFF, M369Write); + M369Sync(); +} + +void Mapper369_Init(CartInfo *info) { + MMC3_Init(info, 8, 0); + MMC3_pwrap = M369PW; + MMC3_cwrap = M369CW; + info->Power = M369Power; + info->Reset = M369Reset; + MapIRQHook = SMB2JIRQHook; + GameHBIRQHook = MMC3IRQHook; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper370.c b/src/mappers/mapper370.c new file mode 100644 index 000000000..5fc282d7a --- /dev/null +++ b/src/mappers/mapper370.c @@ -0,0 +1,136 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 370 - F600 + * Golden Mario Party II - Around the World (6-in-1 multicart) + */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 reg; +static uint8 dipsw; + +static void M370CW(uint32 A, uint8 V) { + uint16 mask = (reg & 0x04) ? 0xFF : 0x7F; + uint16 base = reg << 7; + + setchr1(A, (base & ~mask) | (V & mask)); +} + +static void M370PW(uint32 A, uint8 V) { + uint16 mask = reg & 0x20 ? 0x0F : 0x1F; + uint16 base = reg << 1; + + setprg8(A, (base & ~mask) | (V & mask)); +} + +static void M370MIR(void) { + if ((reg & 0x07) == 1) { + if (mmc3.cmd & 0x80) { + setntamem(NTARAM + 0x400 * ((mmc3.reg[2] >> 7) & 0x01), 1, 0); + setntamem(NTARAM + 0x400 * ((mmc3.reg[3] >> 7) & 0x01), 1, 1); + setntamem(NTARAM + 0x400 * ((mmc3.reg[4] >> 7) & 0x01), 1, 2); + setntamem(NTARAM + 0x400 * ((mmc3.reg[5] >> 7) & 0x01), 1, 3); + } else { + setntamem(NTARAM + 0x400 * ((mmc3.reg[0] >> 7) & 0x01), 1, 0); + setntamem(NTARAM + 0x400 * ((mmc3.reg[0] >> 7) & 0x01), 1, 1); + setntamem(NTARAM + 0x400 * ((mmc3.reg[1] >> 7) & 0x01), 1, 2); + setntamem(NTARAM + 0x400 * ((mmc3.reg[1] >> 7) & 0x01), 1, 3); + } + } else { + setmirror((mmc3.mirr & 0x01) ^ 0x01); + } +} + +static DECLFR(M370Read) { + return (((dipsw << 7) & 0x80) | (cpu.openbus & 0x7F)); +} + +static DECLFW(M370Write) { + reg = (A & 0xFF); + MMC3_FixPRG(); + MMC3_FixCHR(); + MMC3_FixMIR(); +} + +static DECLFW(M370WriteCMD) { + uint8 oldcmd = mmc3.cmd; + + switch (A & 0xE001) { + case 0x8000: + mmc3.cmd = V; + if ((oldcmd & 0x40) != (mmc3.cmd & 0x40)) { + MMC3_FixPRG(); + } + if ((oldcmd & 0x80) != (mmc3.cmd & 0x80)) { + MMC3_FixCHR(); + MMC3_FixMIR(); + } + break; + case 0x8001: + switch (mmc3.cmd & 0x07) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + mmc3.reg[mmc3.cmd & 0x07] = V; + MMC3_FixCHR(); + MMC3_FixMIR(); + break; + default: + MMC3_CMDWrite(A, V); + break; + } + break; + default: + MMC3_CMDWrite(A, V); + break; + } +} + +static void M370Reset(void) { + reg = 0; + dipsw ^= 1; + FCEU_printf("solderpad=%02x\n", dipsw); + MMC3_Reset(); +} + +static void M370Power(void) { + reg = 0; + dipsw = 1; /* start off with the 6-in-1 menu */ + MMC3_Power(); + SetReadHandler(0x5000, 0x5FFF, M370Read); + SetWriteHandler(0x5000, 0x5FFF, M370Write); + SetWriteHandler(0x8000, 0x9FFF, M370WriteCMD); +} + +void Mapper370_Init(CartInfo *info) { + MMC3_Init(info, 8, 0); + MMC3_FixMIR = M370MIR; + MMC3_cwrap = M370CW; + MMC3_pwrap = M370PW; + info->Power = M370Power; + info->Reset = M370Reset; + AddExState(®, 1, 0, "EXPR"); + AddExState(&dipsw, 1, 0, "DPSW"); +} diff --git a/src/boards/mapper372.c b/src/mappers/mapper372.c similarity index 68% rename from src/boards/mapper372.c rename to src/mappers/mapper372.c index 1b741bc65..2febf9ce5 100644 --- a/src/boards/mapper372.c +++ b/src/mappers/mapper372.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -26,64 +26,77 @@ #include "mapinc.h" #include "mmc3.h" +static uint8 reg[4]; +static uint8 cmd; + static uint32 CHRRAMSIZE; static uint8 *CHRRAM; +static SFORMAT StateRegs[] = { + { reg, 4, "REGS" }, + { &cmd, 1, "CMD0" }, + { 0 } +}; + static void M372CW(uint32 A, uint8 V) { - if (mmc3.expregs[2] & 0x20) { + if (reg[2] & 0x20) { setchr8r(0x10, 0); } else { - uint32 mask = 0xFF >> (~mmc3.expregs[2] & 0xF); - uint32 base = ((mmc3.expregs[2] << 4) & 0xF00) | mmc3.expregs[0]; + uint32 mask = 0xFF >> (~reg[2] & 0x0F); + uint32 base = ((reg[2] << 4) & 0xF00) | reg[0]; + setchr1(A, (base & ~mask) | (V & mask)); } } static void M372PW(uint32 A, uint8 V) { - uint32 mask = ~mmc3.expregs[3] & 0x3F; - uint32 base = ((mmc3.expregs[2] << 2) & 0x300) | mmc3.expregs[1]; + uint32 mask = ~reg[3] & 0x3F; + uint32 base = ((reg[2] << 2) & 0x300) | reg[1]; + setprg8(A, (base & ~mask) | (V & mask)); } static DECLFW(M372Write) { - if (!(mmc3.expregs[3] & 0x40)) { - mmc3.expregs[mmc3.expregs[4]] = V; - mmc3.expregs[4] = (mmc3.expregs[4] + 1) & 3; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + if (!(reg[3] & 0x40)) { + reg[cmd] = V; + cmd = (cmd + 1) & 0x03; + MMC3_FixPRG(); + MMC3_FixCHR(); } } static void M372Reset(void) { - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[3] = mmc3.expregs[4] = 0; - mmc3.expregs[2] = 0x0F; - MMC3RegReset(); + reg[0] = reg[1] = reg[3] = cmd = 0; + reg[2] = 0x0F; + MMC3_Reset(); } static void M372Power(void) { - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[3] = mmc3.expregs[4] = 0; - mmc3.expregs[2] = 0x0F; - GenMMC3Power(); + reg[0] = reg[1] = reg[3] = cmd = 0; + reg[2] = 0x0F; + MMC3_Power(); SetWriteHandler(0x6000, 0x7FFF, M372Write); } static void M372Close(void) { - GenMMC3Close(); - if (CHRRAM) + MMC3_Close(); + if (CHRRAM) { FCEU_gfree(CHRRAM); + } CHRRAM = NULL; } void Mapper372_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 0, 0); - mmc3.cwrap = M372CW; - mmc3.pwrap = M372PW; + MMC3_Init(info, 0, 0); + MMC3_cwrap = M372CW; + MMC3_pwrap = M372PW; info->Reset = M372Reset; info->Power = M372Power; info->Close = M372Close; + AddExState(StateRegs, ~0, 0, NULL); + CHRRAMSIZE = 8192; CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); - AddExState(mmc3.expregs, 5, 0, "EXPR"); } diff --git a/src/mappers/mapper374.c b/src/mappers/mapper374.c new file mode 100644 index 000000000..a6ccad292 --- /dev/null +++ b/src/mappers/mapper374.c @@ -0,0 +1,55 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 374 + * 1995 Super HiK 4-in-1 - 新系列機器戰警组合卡 (JY-022) + * 1996 Super HiK 4-in-1 - 新系列超級飛狼組合卡 (JY-051) + */ + +#include "mapinc.h" +#include "mmc1.h" + +static uint8 game = 0; + +static SFORMAT StateRegs[] = { + { &game, 1, "GAME" }, + { 0 } +}; + +static void M374PRG(uint32 A, uint8 V) { + setprg16(A, (game << 3) | (V & 0x07)); +} + +static void M374CHR(uint32 A, uint8 V) { + setchr4(A, (game << 5) | (V & 0x1F)); +} + +static void M374Reset(void) { + game = (game + 1) & 0x03; + MMC1_Reset(); +} + +void Mapper374_Init(CartInfo *info) { + MMC1_Init(info, 0, 0); + MMC1_cwrap = M374CHR; + MMC1_pwrap = M374PRG; + info->Reset = M374Reset; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/mapper375.c b/src/mappers/mapper375.c similarity index 61% rename from src/boards/mapper375.c rename to src/mappers/mapper375.c index 0a6e81f2c..727b6e0b5 100644 --- a/src/boards/mapper375.c +++ b/src/mappers/mapper375.c @@ -1,7 +1,8 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2022 + * Copyright (C) 2022 + * Copyright (C) 2023-2024 negativeExponent * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -22,50 +23,24 @@ #include "latch.h" static void Sync(void) { - uint32 S = latch.addr & 1; - uint32 p = ((latch.addr >> 2) & 0x1F) + ((latch.addr & 0x100) >> 3) + ((latch.addr & 0x400) >> 4); - uint32 L = (latch.addr >> 9) & 1; - uint32 p_8000 = p; + uint32 prg = ((latch.addr >> 4) & 0x40) | ((latch.addr >> 3) & 0x20) | ((latch.addr >> 2) & 0x1F); + uint32 cpuA14 = latch.addr & 0x01; + uint32 nrom = (latch.addr >> 7) & 0x01; + uint32 unrom = (latch.addr >> 9) & 0x01; + uint32 unrom_like = (latch.addr >> 11) & 0x01; - if ((latch.addr >> 11) & 1) - p_8000 = (p & 0x7E) | (latch.data & 7); - - if ((latch.addr >> 7) & 1) { - if (S) { - setprg32(0x8000, p >> 1); - } else { - setprg16(0x8000, p_8000); - setprg16(0xC000, p); - } - } else { - if (S) { - if (L) { - setprg16(0x8000, p_8000 & 0x7E); - setprg16(0xC000, p | 7); - } else { - setprg16(0x8000, p_8000 & 0x7E); - setprg16(0xC000, p & 0x78); - } - } else { - if (L) { - setprg16(0x8000, p_8000); - setprg16(0xC000, p | 7); - } else { - setprg16(0x8000, p_8000); - setprg16(0xC000, p & 0x78); - } - } - } + setprg8r(0x10, 0x6000, 0); + setprg16(0x8000, ((prg & ~cpuA14) & ~(0x07 * unrom_like)) | (unrom_like * latch.data)); + setprg16(0xC000, ((prg | cpuA14) & ~(0x07 * !nrom * !unrom)) | (0x07 * !nrom * unrom)); - if ((latch.addr & 0x80) == 0x80) + setchr8(0); + setmirror(((latch.addr >> 1) & 1) ^ 1); + if ((latch.addr & 0x80) == 0x80) { /* CHR-RAM write protect hack, needed for some multicarts */ SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0); - else + } else { SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1); - - setmirror(((latch.addr >> 1) & 1) ^ 1); - setchr8(0); - setprg8r(0x10, 0x6000, 0); + } } static DECLFW(M375Write) { @@ -79,12 +54,12 @@ static DECLFW(M375Write) { } static void M375Power(void) { - LatchPower(); + Latch_Power(); SetWriteHandler(0x8000, 0xFFFF, M375Write); } void Mapper375_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 1, 0); + Latch_Init(info, Sync, NULL, TRUE, FALSE); info->Power = M375Power; - info->Reset = LatchHardReset; + info->Reset = Latch_RegReset; } diff --git a/src/mappers/mapper376.c b/src/mappers/mapper376.c new file mode 100644 index 000000000..7c6611c84 --- /dev/null +++ b/src/mappers/mapper376.c @@ -0,0 +1,71 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 reg[2]; + +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, + { 0 } +}; + +static void M376CW(uint32 A, uint8 V) { + uint16 base = ((reg[1] << 8) & 0x100) | ((reg[0] << 1) & 0x80); + + setchr1(A, base | (V & 0x7F)); +} + +static void M376PW(uint32 A, uint8 V) { + uint16 base = ((reg[1] << 4) & 0x10) | ((reg[0] >> 3) & 0x08) | (reg[0] & 0x07); + + if (reg[0] & 0x80) { + if (reg[0] & 0x20) { + setprg32(0x8000, base >> 1); + } else { + setprg16(0x8000, base); + setprg16(0xC000, base); + } + } else { + setprg8(A, ((base << 1) & ~0x0F) | (V & 0x0F)); + } +} + +static DECLFW(M376Write) { + reg[A & 0x01] = V; + MMC3_FixPRG(); + MMC3_FixCHR(); +} + +static void M376Power(void) { + reg[0] = 0; + reg[1] = 0; + MMC3_Power(); + SetWriteHandler(0x7000, 0x7FFF, M376Write); +} + +void Mapper376_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_pwrap = M376PW; + MMC3_cwrap = M376CW; + info->Power = M376Power; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/mapper377.c b/src/mappers/mapper377.c similarity index 72% rename from src/boards/mapper377.c rename to src/mappers/mapper377.c index e49baff76..81305c071 100644 --- a/src/boards/mapper377.c +++ b/src/mappers/mapper377.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2022 + * Copyright (C) 2023 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -26,40 +26,49 @@ #include "mapinc.h" #include "mmc3.h" -#define OUTER_BANK (((mmc3.expregs[0] & 0x20) >> 2) | (mmc3.expregs[0] & 0x06)) +static uint8 reg; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; static void M377CW(uint32 A, uint8 V) { - setchr1(A, (V & 0x7F) | (OUTER_BANK << 6)); + uint16 base = ((reg & 0x20) >> 2) | (reg & 0x06); + + setchr1(A, (base << 6) | (V & 0x7F)); } static void M377PW(uint32 A, uint8 V) { - setprg8(A, (V & 0x0F) | (OUTER_BANK << 3)); + uint16 base = ((reg & 0x20) >> 2) | (reg & 0x06); + + setprg8(A, (base << 3) | (V & 0x0F)); } static DECLFW(M377Write) { - if (!(mmc3.expregs[0] & 0x80)) { - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + if (!(reg & 0x80)) { + reg = V; + MMC3_FixPRG(); + MMC3_FixCHR(); } } static void M377Reset(void) { - mmc3.expregs[0] = 0; - MMC3RegReset(); + reg = 0; + MMC3_Reset(); } static void M377Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); + reg = 0; + MMC3_Power(); SetWriteHandler(0x6000, 0x7FFF, M377Write); } void Mapper377_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 128, 0, 0); - mmc3.cwrap = M377CW; - mmc3.pwrap = M377PW; + MMC3_Init(info, 0, 0); + MMC3_cwrap = M377CW; + MMC3_pwrap = M377PW; info->Reset = M377Reset; info->Power = M377Power; - AddExState(mmc3.expregs, 1, 0, "EXPR"); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper380.c b/src/mappers/mapper380.c similarity index 64% rename from src/boards/mapper380.c rename to src/mappers/mapper380.c index e3e363309..9b663b38e 100644 --- a/src/boards/mapper380.c +++ b/src/mappers/mapper380.c @@ -24,47 +24,41 @@ #include "mapinc.h" #include "latch.h" -static uint8 dipswitch; -static uint8 isKN35A; +static uint8 dipsw; static SFORMAT StateRegs[] = { - { &dipswitch, 1, "DPSW" }, - + { &dipsw, 1, "DPSW" }, { 0 } }; static void Sync(void) { - if (latch.addr & 0x200) { - if (latch.addr & 1) { /* NROM 128 */ - setprg16(0x8000, latch.addr >> 2); - setprg16(0xC000, latch.addr >> 2); - } else /* NROM-256 */ - setprg32(0x8000, latch.addr >> 3); - } else { /* UxROM */ - setprg16(0x8000, latch.addr >> 2); - setprg16(0xC000, (latch.addr >> 2) | 7 | (isKN35A && latch.addr & 0x100 ? 8 : 0)); - } + uint32 prg = (latch.addr >> 2) & 0x1F; + uint32 cpuA14 = (latch.addr & 0x01) != 0x01; + uint32 ourom = (latch.addr >> 8) & 0x01; + uint32 nrom = (latch.addr >> 9) & 0x01; + + setprg16(0x8000, prg & ~(cpuA14 * nrom)); + setprg16(0xC000, (prg | (cpuA14 * nrom)) | (0x07 * !nrom) | (0x08 * (iNESCart.submapper == 1) * !nrom * ourom)); - SetupCartCHRMapping(0, CHRptr[0], 0x2000, !(latch.addr & 0x80)); setchr8(0); - setmirror(((latch.addr >> 1) & 1) ^ 1); + setmirror(((latch.addr >> 1) & 0x01) ^ 0x01); + SetupCartCHRMapping(0, CHRptr[0], 0x2000, !(latch.addr & 0x80)); } static DECLFR(M380Read) { - if (latch.addr & 0x100 && !isKN35A) { - A |= dipswitch; + if ((iNESCart.submapper == 0) && (latch.addr & 0x100)) { + A |= dipsw; } return CartBR(A); } static void M380Reset(void) { - dipswitch = (dipswitch + 1) & 0xF; - LatchHardReset(); + dipsw = (dipsw + 1) & 0xF; + Latch_RegReset(); } void Mapper380_Init(CartInfo *info) { - Latch_Init(info, Sync, M380Read, 0, 0); - isKN35A = info->iNES2 && info->submapper == 1; + Latch_Init(info, Sync, M380Read, FALSE, FALSE); info->Reset = M380Reset; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper381.c b/src/mappers/mapper381.c new file mode 100644 index 000000000..00bbf6b9a --- /dev/null +++ b/src/mappers/mapper381.c @@ -0,0 +1,44 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + */ + +/* Map 381 - 2-in-1 High Standard Game (BC-019), reset-based */ + +#include "mapinc.h" +#include "latch.h" + +static uint8 reset = 0; + +static void Sync(void) { + setprg16(0x8000, (reset << 4) | ((latch.data & 0x07) << 1) | ((latch.data >> 4) & 0x0F)); + setprg16(0xC000, (reset << 4) | 0x0F); + setchr8(0); +} + +static void M381Reset(void) { + reset++; + Sync(); +} + +void Mapper381_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Reset = M381Reset; + AddExState(&reset, 1, 0, "RST0"); +} diff --git a/src/boards/mapper382.c b/src/mappers/mapper382.c similarity index 71% rename from src/boards/mapper382.c rename to src/mappers/mapper382.c index 1e6cd6a22..8715ccf8c 100644 --- a/src/boards/mapper382.c +++ b/src/mappers/mapper382.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -26,41 +26,40 @@ #include "mapinc.h" #include "latch.h" -static uint8 outerbank; +static uint8 base; static SFORMAT StateRegs[] = { - { &outerbank, 1, "BANK"}, - + { &base, 1, "BASE"}, { 0 } }; static void Sync(void) { - if (!(outerbank & 0x20)) { - outerbank = latch.addr & 0x3F; + if (!(base & 0x20)) { + base = latch.addr & 0x3F; } - switch ((outerbank >> 3) & 1) { - case 1: - /* bnrom */ - setprg32(0x8000, (outerbank<< 2) | (latch.data & 3)); - break; - default: - /* unrom */ - setprg16(0x8000, (outerbank << 3) | (latch.data & 7)); - setprg16(0xC000, (outerbank << 3) | 7); - break; + switch (base & 0x08) { + case 1: + /* bnrom */ + setprg32(0x8000, (base << 2) | (latch.data & 0x03)); + break; + default: + /* unrom */ + setprg16(0x8000, (base << 3) | (latch.data & 0x07)); + setprg16(0xC000, (base << 3) | 0x07); + break; } setchr8(0); - setmirror(((outerbank >> 4) & 1) ^ 1); + setmirror(((base >> 4) & 0x01) ^ 0x01); /* FCEU_printf("inB[0]:%02x outB[1]:%02x mode:%02x mirr:%02x lock:%02x\n", latch.data, latch.addr, mode, mirr, lock); */ } -static void M382Reset() { - outerbank = 0; - LatchHardReset(); +static void M382Reset(void) { + base = 0; + Latch_RegReset(); } void Mapper382_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 1); + Latch_Init(info, Sync, NULL, FALSE, TRUE); info->Reset = M382Reset; AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper383.c b/src/mappers/mapper383.c new file mode 100644 index 000000000..f4c485939 --- /dev/null +++ b/src/mappers/mapper383.c @@ -0,0 +1,121 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023 + * + * 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. + */ + +/* 晶太 YY840708C PCB + Solely used for the "1995 Soccer 6-in-1 足球小将專輯 (JY-014)" multicart. + MMC3+PAL16L8 combination, resulting in a bizarre mapper that switches banks in part upon *reads*. +*/ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 pal_A15, pal_A16, pal_A1718; + +static SFORMAT StateRegs[] = { + { &pal_A15, 1, "A15_"}, + { &pal_A16, 1, "A16_"}, + { &pal_A1718, 1, "A178"}, + { 0 } +}; + +static void M383PW(uint32 A, uint8 V) { + uint16 base; + uint16 mask; + + switch (pal_A1718) { + case 0x00: + /* "Setting 0 provides a round-about means of dividing the first 128 KiB bank into two 32 KiB and one 64 KiB bank." */ + base = pal_A1718 | pal_A16 | (pal_A16 ? 0x00 : pal_A15); + mask = pal_A16 ? 0x07 : 0x03; + break; + case 0x30: + /* "Setting 3 provides 128 KiB MMC3 banking with the CPU A14 line fed to the MMC3 clone reversed. + This is used for the game Tecmo Cup: Soccer Game (renamed "Tecmo Cup Soccer"), + originally an MMC1 game with the fixed bank at $8000-$BFFF and the switchable bank at $C000-$FFFF, + a configuration that could not be reproduced with an MMC3 alone." */ + base = pal_A1718; + mask = 0x0F; + A ^= 0x4000; + + /* "It is also used for the menu, + which in part executes from PRG-ROM mapped to the CPU $6000-$7FFF address range on the MMC3 clone's fixed + banks alone, as no MMC3 PRG bank register is written to before JMPing to this address range." */ + if (A == 0xA000) { + setprg8(0x6000, base | (V & 0x0B)); + } + break; + default: + /* "Settings 1 and 2 provide normal 128 KiB MMC3 banking." */ + base = pal_A1718; + mask = 0x0F; + break; + } + + setprg8(A, base | (V & mask)); +} + +static void M383CW(uint32 A, uint8 V) { + setchr1(A, (pal_A1718 << 3) | (V & 0x7F)); +} + +static DECLFR(M383Read) { + if (pal_A1718 == 0x00) { /* "PAL PRG pal_A16 is updated with the content of the corresponding MMC3 PRG bank bit by reading from the + respective address range, which in turn will then be applied across the entire ROM address range." */ + pal_A16 = mmc3.reg[0x06 | ((A >> 13) & 0x01)] & 0x08; + MMC3_FixPRG(); + } + return CartBR(A); +} + +static DECLFW(M383Write) { + if (A & 0x0100) { + pal_A15 = (A >> 11) & 0x04; + pal_A1718 = A & 0x30; + MMC3_FixPRG(); + MMC3_FixCHR(); + } + MMC3_Write(A, V); +} + +static void M383Reset(void) { + pal_A15 = 0; + pal_A16 = 0; + pal_A1718 = 0; + MMC3_Reset(); +} + +static void M383Power(void) { + pal_A15 = 0; + pal_A16 = 0; + pal_A1718 = 0; + MMC3_Power(); + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetReadHandler(0x8000, 0xBFFF, M383Read); + SetWriteHandler(0x8000, 0xFFFF, M383Write); +} + +void Mapper383_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_pwrap = M383PW; + MMC3_cwrap = M383CW; + info->Power = M383Power; + info->Reset = M383Reset; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper385.c b/src/mappers/mapper385.c new file mode 100644 index 000000000..75265b8e9 --- /dev/null +++ b/src/mappers/mapper385.c @@ -0,0 +1,34 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg16(0x8000, latch.addr >> 1); + setprg16(0xc000, latch.addr >> 1); + setmirror((latch.addr & 0x01) ^ 0x01); + setchr8(0); +} + +void Mapper385_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, TRUE); +} diff --git a/src/mappers/mapper386.c b/src/mappers/mapper386.c new file mode 100644 index 000000000..ab79ee997 --- /dev/null +++ b/src/mappers/mapper386.c @@ -0,0 +1,41 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "jyasic.h" + +static uint32 GetPRGBank(uint32 V) { + return (((jyasic.mode[3] << 3) & 0x40) | ((jyasic.mode[3] << 4) & 0x20) | (V & 0x1F)); +} + +static uint32 GetCHRBank(uint32 V) { + if (jyasic.mode[3] & 0x20) { + return (((jyasic.mode[3] << 7) & 0x600) | (V & 0x1FF)); + } else { + return (((jyasic.mode[3] << 7) & 0x600) | ((jyasic.mode[3] << 8) & 0x100) | (V & 0x0FF)); + } +} + +void Mapper386_Init(CartInfo *info) { + /* Multicart */ + JYASIC_Init(info, TRUE); + JYASIC_GetPRGBank = GetPRGBank; + JYASIC_GetCHRBank = GetCHRBank; +} diff --git a/src/mappers/mapper387.c b/src/mappers/mapper387.c new file mode 100644 index 000000000..c90dede4d --- /dev/null +++ b/src/mappers/mapper387.c @@ -0,0 +1,41 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "jyasic.h" + +static uint32 GetPRGBank(uint32 V) { + return (((jyasic.mode[3] << 2) & 0x20) | ((jyasic.mode[3] << 3) & 0x10) | (V & 0x0F)); +} + +static uint32 GetCHRBank(uint32 V) { + if (jyasic.mode[3] & 0x20) { + return (((jyasic.mode[3] << 7) & 0x600) | (V & 0x1FF)); + } else { + return (((jyasic.mode[3] << 7) & 0x600) | ((jyasic.mode[3] << 8) & 0x100) | (V & 0x0FF)); + } +} + +void Mapper387_Init(CartInfo *info) { + /* Multicart */ + JYASIC_Init(info, TRUE); + JYASIC_GetPRGBank = GetPRGBank; + JYASIC_GetCHRBank = GetCHRBank; +} diff --git a/src/mappers/mapper388.c b/src/mappers/mapper388.c new file mode 100644 index 000000000..62c83e0c0 --- /dev/null +++ b/src/mappers/mapper388.c @@ -0,0 +1,41 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "jyasic.h" + +static uint32 GetPRGBank(uint32 V) { + return (((jyasic.mode[3] << 3) & 0x60) | (V & 0x1F)); +} + +static uint32 GetCHRBank(uint32 V) { + if (jyasic.mode[3] & 0x20) { + return (((jyasic.mode[3] << 8) & 0x200) | (V & 0x1FF)); + } else { + return (((jyasic.mode[3] << 8) & 0x200) | ((jyasic.mode[3] << 8) & 0x100) | (V & 0x0FF)); + } +} + +void Mapper388_Init(CartInfo *info) { + /* Multicart */ + JYASIC_Init(info, FALSE); + JYASIC_GetPRGBank = GetPRGBank; + JYASIC_GetCHRBank = GetCHRBank; +} diff --git a/src/boards/mapper389.c b/src/mappers/mapper389.c similarity index 87% rename from src/boards/mapper389.c rename to src/mappers/mapper389.c index bc695ca15..4ef1ae603 100644 --- a/src/boards/mapper389.c +++ b/src/mappers/mapper389.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -44,18 +45,18 @@ static void Sync(void) { static DECLFW(M389Write) { switch (A & 0xF000) { - case 0x8000: - regs[0] = (A & 0xFF); - Sync(); - break; - case 0x9000: - regs[1] = (A & 0xFF); - Sync(); - break; - default: - regs[2] = (A & 0xFF); - Sync(); - break; + case 0x8000: + regs[0] = (A & 0xFF); + Sync(); + break; + case 0x9000: + regs[1] = (A & 0xFF); + Sync(); + break; + default: + regs[2] = (A & 0x0F); + Sync(); + break; } } @@ -79,5 +80,5 @@ void Mapper389_Init(CartInfo *info) { info->Power = M389Power; info->Reset = M389Reset; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper390.c b/src/mappers/mapper390.c similarity index 57% rename from src/boards/mapper390.c rename to src/mappers/mapper390.c index bf0bedf30..2d146bbe1 100644 --- a/src/boards/mapper390.c +++ b/src/mappers/mapper390.c @@ -1,7 +1,8 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 + * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -19,64 +20,61 @@ */ /* NES 2.0 Mapper 390 - Realtec 8031 */ +/* NOTE: Duplicate of Mapper 236 (CHR-ROM variant */ #include "mapinc.h" -static uint8 regs[2]; -static uint8 dipswitch; +static uint8 reg[2]; +static uint8 dipsw; -static SFORMAT StateRegs[] = -{ - { ®s, 2, "REG" }, - { &dipswitch, 1, "DPSW" }, +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, + { &dipsw, 1, "DPSW" }, { 0 } }; static void Sync(void) { - switch ((regs[1] >> 4) & 3) { - case 0: - case 1: - /* UNROM */ - setprg16(0x8000, regs[1]); - setprg16(0xC000, regs[1] | 7); - break; - case 2: - /* Maybe unused, NROM-256? */ - setprg32(0x8000, regs[1] >> 1); - break; - case 3: - /* NROM-128 */ - setprg16(0x8000, regs[1]); - setprg16(0xC000, regs[1]); - break; + switch (reg[1] & 0x30) { + case 0x00: + case 0x10: /* UNROM */ + setprg16(0x8000, reg[1]); + setprg16(0xC000, reg[1] | 0x07); + break; + case 0x20: /* Maybe unused, NROM-256? */ + setprg32(0x8000, reg[1] >> 1); + break; + case 0x30: /* NROM-128 */ + setprg16(0x8000, reg[1]); + setprg16(0xC000, reg[1]); + break; } - setchr8(regs[0]); - setmirror(((regs[0] & 0x20) >> 5) ^ 1); + setchr8(reg[0]); + setmirror(((reg[0] & 0x20) >> 5) ^ 1); } static DECLFR(M390Read) { uint8 ret = CartBR(A); - if ((regs[1] & 0x30) == 0x10) - ret |= dipswitch; + if ((reg[1] & 0x30) == 0x10) + ret |= dipsw; return ret; } static DECLFW(M390Write) { - regs[(A >> 14) & 1] = A & 0x3F; + reg[(A >> 14) & 0x01] = A & 0x3F; Sync(); } static void M390Power(void) { - regs[0] = 0; - regs[1] = 0; - dipswitch = 11; /* hard-coded 150-in-1 menu */ + reg[0] = 0; + reg[1] = 0; + dipsw = 11; /* hard-coded 150-in-1 menu */ Sync(); - SetReadHandler(0x8000, 0xffff, M390Read); - SetWriteHandler(0x8000, 0xffff, M390Write); + SetReadHandler(0x8000, 0xFFFF, M390Read); + SetWriteHandler(0x8000, 0xFFFF, M390Write); } static void M390Reset(void) { - dipswitch = 11; /* hard-coded 150-in-1 menu */ + dipsw = 11; /* hard-coded 150-in-1 menu */ Sync(); } @@ -88,5 +86,5 @@ void Mapper390_Init(CartInfo *info) { info->Reset = M390Reset; info->Power = M390Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper391.c b/src/mappers/mapper391.c new file mode 100644 index 000000000..24efcc8cb --- /dev/null +++ b/src/mappers/mapper391.c @@ -0,0 +1,90 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* BS-110 PCB, previously called NC7000M due to a mix-up. */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 reg[2]; + +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, + { 0 } +}; + +static void M391PW(uint32 A, uint8 V) { + uint8 mask = (reg[0] & 0x08) ? 0x0F : 0x1F; + uint8 base = (reg[0] << 4) & 0x30; + + if (reg[0] & 0x20) { + if (reg[0] & 0x04) { /* NROM-256 */ + setprg8(0x8000, (base & ~mask) | ((mmc3.reg[6] & mask) & ~0x03) | 0); + setprg8(0xA000, (base & ~mask) | ((mmc3.reg[7] & mask) & ~0x03) | 1); + setprg8(0xC000, (base & ~mask) | ((mmc3.reg[6] & mask) & ~0x03) | 2); + setprg8(0xE000, (base & ~mask) | ((mmc3.reg[7] & mask) & ~0x03) | 3); + } else { /* NROM-128 */ + setprg8(0x8000, (base & ~mask) | ((mmc3.reg[6] & mask) & ~0x01) | 0); + setprg8(0xA000, (base & ~mask) | ((mmc3.reg[7] & mask) & ~0x01) | 1); + setprg8(0xC000, (base & ~mask) | ((mmc3.reg[6] & mask) & ~0x01) | 0); + setprg8(0xE000, (base & ~mask) | ((mmc3.reg[7] & mask) & ~0x01) | 1); + } + } else { + setprg8(A, (base & ~mask) | (V & mask)); + } +} + +static void M391CW(uint32 A, uint8 V) { + uint16 mask = (reg[0] & 0x40) ? 0x7F : 0xFF; + uint16 base = ((reg[0] << 3) & 0x80) | ((reg[1] << 8) & 0x100); + + setchr1(A, (base & ~mask) | (V & mask)); +} + +static DECLFW(M391Write) { + if (MMC3_WramIsWritable()) { + if (!(reg[0] & 0x80)) { + reg[0] = V; + reg[1] = ((A >> 8) & 0xFF); + MMC3_FixPRG(); + MMC3_FixCHR(); + } + } +} + +static void M391Reset(void) { + reg[0] = reg[1] = 0; + MMC3_Reset(); +} + +static void M391Power(void) { + reg[0] = reg[1] = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M391Write); +} + +void Mapper391_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_cwrap = M391CW; + MMC3_pwrap = M391PW; + info->Power = M391Power; + info->Reset = M391Reset; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/mapper393.c b/src/mappers/mapper393.c similarity index 52% rename from src/boards/mapper393.c rename to src/mappers/mapper393.c index 6df8e3a51..4c3f8cc88 100644 --- a/src/boards/mapper393.c +++ b/src/mappers/mapper393.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2022 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -16,93 +16,98 @@ * 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" +static uint8 reg[2]; + static uint8 *CHRRAM; static uint32 CHRRAMSIZE; +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, + { 0 } +}; + static void M393CW(uint32 A, uint8 V) { - if (mmc3.expregs[0] & 8) + if (reg[0] & 0x08) { setchr8r(0x10, 0); - else - setchr1(A, (V & 0xFF) | (mmc3.expregs[0] << 8)); + } else { + setchr1(A, (reg[0] << 8) | (V & 0xFF)); + } } static void M393PW(uint32 A, uint8 V) { - switch ((mmc3.expregs[0] >> 4) & 3) { - case 0: - case 1: - setprg8(A, (V & 0x0F) | (mmc3.expregs[0] << 4)); - break; - case 2: - setprg32(0x8000, ((mmc3.regs[6] >> 2) & 3) | (mmc3.expregs[0] << 2)); - break; - case 3: - setprg16(0x8000, (mmc3.expregs[0] << 3) | (mmc3.expregs[1] & 7)); - setprg16(0xC000, (mmc3.expregs[0] << 3) | 7); - break; + if (reg[0] & 0x20) { + if (reg[0] & 0x10) { + setprg16(0x8000, (reg[0] << 3) | (reg[1] & 0x07)); + setprg16(0xC000, (reg[0] << 3) | 0x07); + } else { + setprg32(0x8000, (reg[0] << 2) | ((mmc3.reg[6] >> 2) & 0x03)); + } + } else { + setprg8(A, (reg[0] << 4) | (V & 0x0F)); } } -static DECLFW(M393Write8) { - switch (A & 0xE000) { - case 0x8000: - case 0xA000: - MMC3_CMDWrite(A, V); - break; - case 0xC000: - case 0xE000: - MMC3_IRQWrite(A, V); - break; +static DECLFW(M393Write) { + reg[1] = V; + switch (A & 0xE001) { + case 0x8001: + mmc3.reg[mmc3.cmd & 0x07] = V; + if ((mmc3.cmd & 0x07) < 6) { + MMC3_FixCHR(); + } + MMC3_FixPRG(); + break; + default: + MMC3_Write(A, V); + MMC3_FixPRG(); + break; } - - mmc3.expregs[1] = V; - FixMMC3CHR(mmc3.cmd); - FixMMC3PRG(mmc3.cmd); } -static DECLFW(M393Write6) { - if (MMC3CanWriteToWRAM()) { - mmc3.expregs[0] = A & 0xFF; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); +static DECLFW(M393WriteReg) { + if (MMC3_WramIsWritable()) { + reg[0] = A & 0xFF; + MMC3_FixPRG(); + MMC3_FixCHR(); } } static void M393Power(void) { - mmc3.expregs[0] = mmc3.expregs[1] = 0; - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, M393Write6); - SetWriteHandler(0x8000, 0xFFFF, M393Write8); + reg[0] = reg[1] = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M393WriteReg); + SetWriteHandler(0x8000, 0xFFFF, M393Write); } static void M393Reset(void) { - mmc3.expregs[0] = mmc3.expregs[1] = 0; - MMC3RegReset(); + reg[0] = reg[1] = 0; + MMC3_Reset(); } static void M393lose(void) { - GenMMC3Close(); - if (CHRRAM) + MMC3_Close(); + if (CHRRAM) { FCEU_free(CHRRAM); + } CHRRAM = NULL; } void Mapper393_Init(CartInfo *info) { - GenMMC3_Init(info, 1024, 512, 8, 0); - mmc3.pwrap = M393PW; - mmc3.cwrap = M393CW; + MMC3_Init(info, 8, 0); + MMC3_pwrap = M393PW; + MMC3_cwrap = M393CW; info->Power = M393Power; info->Reset = M393Reset; info->Close = M393lose; + AddExState(StateRegs, ~0, 0, NULL); + CHRRAMSIZE = 8192; CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); - AddExState(mmc3.expregs, 2, 0, "EXPR"); } diff --git a/src/mappers/mapper394.c b/src/mappers/mapper394.c new file mode 100644 index 000000000..e52c04eea --- /dev/null +++ b/src/mappers/mapper394.c @@ -0,0 +1,140 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 394: HSK007 circuit board that can simulate J.Y. ASIC, MMC3, and NROM. */ + +#include "mapinc.h" +#include "jyasic.h" +#include "mmc3.h" + +static uint8 reg[4]; + +static uint32 M394_PRGBank_JY(uint32 V) { + uint8 base = ((reg[1] << 5) & 0x020) | ((reg[3] << 1) & 0x010); + + return (base | (V & 0x1F)); +} + +static uint32 M394_CHRBank_JY(uint32 V) { + uint32 base = ((reg[1] << 8) & 0x100) | ((reg[3] << 1) & 0x080); + + return (base | (V & 0x0FF)); +} + +static void M394PW_MMC3(uint32 A, uint8 V) { + uint8 mask = (reg[3] & 0x10) ? 0x1F : 0x0F; + uint8 base = ((reg[1] << 5) & 0x020) | ((reg[3] << 1) & 0x010); + + if (reg[1] & 0x08) { + setprg8(A, base | (V & mask)); + } else { + setprg32(0x8000, (base | ((reg[3] << 1) & 0x0F)) >> 2); + } +} + +static void M394CW_MMC3(uint32 A, uint8 V) { + uint16 mask = (reg[3] & 0x80) ? 0xFF : 0x7F; + uint16 base = ((reg[3] << 1) & 0x080) | ((reg[1] << 8) & 0x100); + + setchr1(A, (base & ~mask) | (V & mask)); +} + +static DECLFW(M394WriteReg) { + uint8 oldMode = reg[1]; + + A &= 3; + reg[A] = V; + if (A == 1) { + if (!(oldMode & 0x10) && (V & 0x10)) { + JYASIC_Power(); + } else if ((oldMode & 0x10) && !(V & 0x10)) { + JYASIC_restoreWriteHandlers(); + MMC3_Power(); + } + } else { + if (reg[1] & 0x10) { + JYASIC_FixPRG(); + JYASIC_FixCHR(); + JYASIC_FixMIR(); + } else { + MMC3_FixPRG(); + MMC3_FixCHR(); + MMC3_FixMIR(); + } + } +} + +static void M394StateRestore(int version) { + int i; + + JYASIC_restoreWriteHandlers(); + if (reg[1] & 0x10) { + SetWriteHandler(0x5000, 0x5FFF, JYASIC_WriteALU); + SetWriteHandler(0x6000, 0x7fff, CartBW); + SetWriteHandler(0x8000, 0x87FF, JYASIC_WritePRG); /* 8800-8FFF ignored */ + SetWriteHandler(0x9000, 0x97FF, JYASIC_WriteCHRLow); /* 9800-9FFF ignored */ + SetWriteHandler(0xA000, 0xA7FF, JYASIC_WriteCHRHigh); /* A800-AFFF ignored */ + SetWriteHandler(0xB000, 0xB7FF, JYASIC_WriteNT); /* B800-BFFF ignored */ + SetWriteHandler(0xC000, 0xCFFF, JYASIC_WriteIRQ); + SetWriteHandler(0xD000, 0xD7FF, JYASIC_WriteMode); /* D800-DFFF ignored */ + for (i = 0; i < 0x10000; i++) { + JYASIC_cpuWrite[i] = GetWriteHandler(i); + } + SetWriteHandler(0x0000, 0xFFFF, JYASIC_trapCPUWrite); /* Trap all CPU writes for IRQ clocking purposes */ + JYASIC_CPUWriteHandlersSet = 1; + SetReadHandler(0x5000, 0x5FFF, JYASIC_ReadALU_DIP); + SetReadHandler(0x6000, 0xFFFF, CartBR); + JYASIC_FixPRG(); + JYASIC_FixCHR(); + JYASIC_FixMIR(); + } else { + SetWriteHandler(0x8000, 0xBFFF, MMC3_CMDWrite); + SetWriteHandler(0xC000, 0xFFFF, MMC3_IRQWrite); + SetReadHandler(0x8000, 0xFFFF, CartBR); + MMC3_FixPRG(); + MMC3_FixCHR(); + } +} + +static void M394Power(void) { + reg[0] = 0x00; + reg[1] = 0x0F; /* start in MMC3 mode */ + reg[2] = 0x00; + reg[3] = 0x10; + MMC3_Power(); + SetWriteHandler(0x5000, 0x5FFF, M394WriteReg); +} + +void Mapper394_Init(CartInfo *info) { + /* Multicart */ + JYASIC_Init(info, TRUE); + JYASIC_GetPRGBank = M394_PRGBank_JY; + JYASIC_GetCHRBank = M394_CHRBank_JY; + + MMC3_Init(info, 0, 0); + MMC3_pwrap = M394PW_MMC3; + MMC3_cwrap = M394CW_MMC3; + + info->Reset = M394Power; + info->Power = M394Power; + + AddExState(reg, 4, 0, "HSK"); + GameStateRestore = M394StateRestore; +} diff --git a/src/boards/mapper395.c b/src/mappers/mapper395.c similarity index 64% rename from src/boards/mapper395.c rename to src/mappers/mapper395.c index f7577079f..061dfc1c2 100644 --- a/src/boards/mapper395.c +++ b/src/mappers/mapper395.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -28,40 +28,51 @@ #include "mapinc.h" #include "mmc3.h" +static uint8 reg[2]; + +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, + { 0 } +}; + static void M395CW(uint32 A, uint8 V) { - uint8 mask = mmc3.expregs[1] & 0x40 ? 0x7F : 0xFF; - setchr1(A, (V & mask) | ((mmc3.expregs[1] & 0x10) << 3) | ((mmc3.expregs[0] & 0x30) << 4) | ((mmc3.expregs[1] & 0x20) << 5)); + uint16 mask = (reg[1] & 0x40) ? 0x7F : 0xFF; + uint16 base = ((reg[0] << 4) & 0x300) | ((reg[1] << 5) & 0x400) | ((reg[1] << 3) & 0x80); + + setchr1(A, base | (V & mask)); } static void M395PW(uint32 A, uint8 V) { - uint8 mask = mmc3.expregs[1] & 8 ? 0x0F : 0x1F; - setprg8(A, (V & mask) | ((mmc3.expregs[0] & 0x30) << 1) | ((mmc3.expregs[0] & 8) << 4) | ((mmc3.expregs[1] & 1) << 4)); + uint16 mask = (reg[1] & 0x08) ? 0x0F : 0x1F; + uint16 base = ((reg[0] << 4) & 0x80) | ((reg[0] << 1) & 0x60) | ((reg[1] << 4) & 0x10); + + setprg8(A, base | (V & mask)); } static DECLFW(M395Write) { - if (!(mmc3.expregs[1] & 0x80)) { - mmc3.expregs[(A >> 4) & 1] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + if (!(reg[1] & 0x80)) { + reg[(A >> 4) & 0x01] = V; + MMC3_FixPRG(); + MMC3_FixCHR(); } } static void M395Reset(void) { - mmc3.expregs[0] = mmc3.expregs[1] = 0; - MMC3RegReset(); + reg[0] = reg[1] = 0; + MMC3_Reset(); } static void M395Power(void) { - mmc3.expregs[0] = mmc3.expregs[1] = 0; - GenMMC3Power(); + reg[0] = reg[1] = 0; + MMC3_Power(); SetWriteHandler(0x6000, 0x7FFF, M395Write); } void Mapper395_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 0, 0); - mmc3.cwrap = M395CW; - mmc3.pwrap = M395PW; + MMC3_Init(info, 0, 0); + MMC3_cwrap = M395CW; + MMC3_pwrap = M395PW; info->Power = M395Power; info->Reset = M395Reset; - AddExState(mmc3.expregs, 2, 0, "EXPR"); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper396.c b/src/mappers/mapper396.c similarity index 80% rename from src/boards/mapper396.c rename to src/mappers/mapper396.c index 2a388110c..0d6e063a6 100644 --- a/src/boards/mapper396.c +++ b/src/mappers/mapper396.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -27,31 +27,30 @@ #include "mapinc.h" #include "latch.h" -static uint8 outerbank; +static uint8 reg; static SFORMAT StateRegs[] = { - { &outerbank, 1, "BANK" }, - + { ®, 1, "REGS" }, { 0 } }; static void Sync(void) { if ((latch.addr & 0x6000) == 0x2000) { - outerbank = latch.data; + reg = latch.data; } - setprg16(0x8000, (outerbank << 3) | (latch.data & 7)); - setprg16(0xC000, (outerbank << 3) | 7); + setprg16(0x8000, (reg << 3) | (latch.data & 0x07)); + setprg16(0xC000, (reg << 3) | 0x07); setchr8(0); - setmirror((outerbank & 0x60) ? 0 : 1); + setmirror((reg & 0x60) ? MI_H : MI_V); } static void M396Reset(void) { - outerbank = 0; - LatchHardReset(); + reg = 0; + Latch_RegReset(); } void Mapper396_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); + Latch_Init(info, Sync, NULL, FALSE, FALSE); info->Reset = M396Reset; AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper397.c b/src/mappers/mapper397.c new file mode 100644 index 000000000..60dd580a9 --- /dev/null +++ b/src/mappers/mapper397.c @@ -0,0 +1,44 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "jyasic.h" +#include "fdssound.h" + +static uint32 GetPRGBank(uint32 V) { + return (((jyasic.mode[3] << 4) & ~0x1F) | (V & 0x1F)); +} + +static uint32 GetCHRBank(uint32 V) { + return ((jyasic.mode[3] << 7) | (V & 0x07F)); +} + +static void M397Power(void) { + JYASIC_Power(); + FDSSound_Power(); +} + +void Mapper397_Init(CartInfo *info) { + /* Multicart */ + JYASIC_Init(info, TRUE); + JYASIC_GetPRGBank = GetPRGBank; + JYASIC_GetCHRBank = GetCHRBank; + info->Power = M397Power; +} diff --git a/src/boards/mapper398.c b/src/mappers/mapper398.c similarity index 70% rename from src/boards/mapper398.c rename to src/mappers/mapper398.c index 2d8d22712..6fbb2689a 100644 --- a/src/boards/mapper398.c +++ b/src/mappers/mapper398.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -23,70 +23,70 @@ */ #include "mapinc.h" -#include "vrc24.h" +#include "vrc2and4.h" -static uint8 latch; +static uint8 reg; static uint8 PPUCHRBus; static SFORMAT StateRegs[] = { - { &latch, 1, "LATC" }, + { ®, 1, "REGS" }, { &PPUCHRBus, 1, "PPUC" }, { 0 }, }; static void M398PW(uint32 A, uint8 V) { - if (latch & 0x80) { + if (reg & 0x80) { /* GNROM-like */ - setprg32(0x8000, ((latch >> 5) & 0x06) | ((vrc24.chrreg[PPUCHRBus] >> 2) & 0x01)); + setprg32(0x8000, ((reg >> 5) & 0x06) | ((vrc24.chr[PPUCHRBus] >> 2) & 0x01)); } else { setprg8(A, V & 0x0F); } } static void M398CW(uint32 A, uint32 V) { - if (latch & 0x80) { + if (reg & 0x80) { /* GNROM-like */ - setchr8(0x40 | ((latch >> 3) & 0x08) | (vrc24.chrreg[PPUCHRBus] & 0x07)); + setchr8(0x40 | ((reg >> 3) & 0x08) | (vrc24.chr[PPUCHRBus] & 0x07)); } else { setchr1(A, V & 0x1FF); } } static DECLFW(M398WriteLatch) { - latch = A & 0xFF; - FixVRC24PRG(); - FixVRC24CHR(); - VRC24Write(A, V); + reg = A & 0xFF; + VRC24_FixPRG(); + VRC24_FixCHR(); + VRC24_Write(A, V); } -static void FP_FASTAPASS(1) M398PPUHook(uint32 A) { +static void M398PPUHook(uint32 A) { uint8 bank = (A & 0x1FFF) >> 10; if ((PPUCHRBus != bank) && ((A & 0x3000) != 0x2000)) { PPUCHRBus = bank; - FixVRC24PRG(); - FixVRC24CHR(); + VRC24_FixPRG(); + VRC24_FixCHR(); } } static void M398Reset(void) { - latch = 0xC0; - FixVRC24PRG(); - FixVRC24CHR(); + reg = 0xC0; + VRC24_FixPRG(); + VRC24_FixCHR(); } static void M398Power(void) { PPUCHRBus = 0; - latch = 0xC0; - GenVRC24Power(); + reg = 0xC0; + VRC24_Power(); SetWriteHandler(0x8000, 0xFFFF, M398WriteLatch); } void Mapper398_Init(CartInfo *info) { - GenVRC24_Init(info, VRC4f, 0); + VRC24_Init(info, VRC4, 0x01, 0x02, 0, 1); info->Reset = M398Reset; info->Power = M398Power; PPU_hook = M398PPUHook; - vrc24.pwrap = M398PW; - vrc24.cwrap = M398CW; - AddExState(StateRegs, ~0, 0, 0); + VRC24_pwrap = M398PW; + VRC24_cwrap = M398CW; + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper399.c b/src/mappers/mapper399.c new file mode 100644 index 000000000..84ad92a23 --- /dev/null +++ b/src/mappers/mapper399.c @@ -0,0 +1,86 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 prg[2]; +static uint8 chr[2]; + +static SFORMAT StateRegs[] = { + { prg, 2, "PREG" }, + { chr, 2, "CREG" }, + { 0 } +}; + +static void M399PRG(void) { + if (iNESCart.submapper == 1) { + setprg8(0x6000, 0xFE); + setprg8(0x8000, prg[0] << 1 | 0); + setprg8(0xA000, prg[0] << 1 | 1); + setprg8(0xC000, prg[1]); + setprg8(0xE000, 0xFF); + } else { + setprg8(0x8000, 0x00); + setprg8(0xA000, prg[0]); + setprg8(0xC000, prg[1]); + setprg8(0xE000, 0xFF); + } +} + +static void M399CHR(void) { + setchr4(0x0000, chr[0]); + setchr4(0x1000, chr[1]); +} + +static DECLFW(M399WriteReg) { + if (A & 0x01) { + prg[V >> 7] = V; + MMC3_FixPRG(); + } else { + chr[V >> 7] = V; + MMC3_FixCHR(); + } +} + +static DECLFW(M399Write1) { + MMC3_Write(0x2000 + A, V); +} + +static void M399Power(void) { + prg[0] = chr[0] = 0; + prg[1] = chr[1] = 1; + MMC3_Power(); + if (iNESCart.submapper == 1) { + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x8000, 0xDFFF, M399Write1); + SetWriteHandler(0xE000, 0xFFFF, M399WriteReg); + } else { + SetWriteHandler(0x8000, 0x9FFF, M399WriteReg); + } +} + +void Mapper399_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_FixPRG = M399PRG; + MMC3_FixCHR = M399CHR; + info->Power = M399Power; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/mapper400.c b/src/mappers/mapper400.c similarity index 74% rename from src/boards/mapper400.c rename to src/mappers/mapper400.c index 5bddd702f..5d091aa4b 100644 --- a/src/boards/mapper400.c +++ b/src/mappers/mapper400.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -28,28 +28,22 @@ static uint8 reg; static uint8 led; static SFORMAT StateRegs[] = { - { ®, 1, "REG0" }, - + { ®, 1, "REGS" }, { 0 } }; static void Sync(void) { - uint8 outer = reg & ~7; - setprg16(0x8000, outer | (latch.data & 7)); - setprg16(0xC000, outer | 7); + setprg16(0x8000, (reg & ~0x07) | (latch.data & 0x07)); + setprg16(0xC000, (reg & ~0x07) | 0x07); setchr8(0); - if (outer == 0x80) { - /* use default mirroring */ - } else { - setmirror(((outer >> 5) & 1) ^ 1); + if (reg != 0x80) { + setmirror(((reg >> 5) & 0x01) ^ 0x01); } } static DECLFW(M400WriteReg) { - if (A & 0x800) { - reg = V; - Sync(); - } + reg = V; + Sync(); } static DECLFW(M400WriteLED) { @@ -58,18 +52,18 @@ static DECLFW(M400WriteLED) { static void M400Reset(void) { reg = 0x80; - LatchHardReset(); + Latch_RegReset(); } -static void M400Power() { +static void M400Power(void) { reg = 0x80; - LatchPower(); - SetWriteHandler(0x7000, 0x7FFF, M400WriteReg); + Latch_Power(); + SetWriteHandler(0x7800, 0x7FFF, M400WriteReg); SetWriteHandler(0x8000, 0xBFFF, M400WriteLED); } void Mapper400_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 1); + Latch_Init(info, Sync, NULL, FALSE, TRUE); info->Power = M400Power; info->Reset = M400Reset; AddExState(StateRegs, ~0, 0, NULL); diff --git a/src/mappers/mapper401.c b/src/mappers/mapper401.c new file mode 100644 index 000000000..f1930e689 --- /dev/null +++ b/src/mappers/mapper401.c @@ -0,0 +1,97 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 401 (reference from NewRisingSun) + * Super 19-in-1 (VIP19) (crc 0x2F497313) + * + */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 reg[4]; +static uint8 cmd; +static uint8 dipsw = 0; + +static void M401CW(uint32 A, uint8 V) { + uint32 mask = (0xFF >> (~reg[2] & 0xF)); + uint32 bank = (reg[0] | ((reg[2] << 4) & 0xF00)); + + setchr1(A, bank | (V & mask)); +} + +static void M401PW(uint32 A, uint8 V) { + uint32 mask = (~reg[3] & 0x1F); + uint32 bank = (reg[1] & 0x1F) | (reg[2] & 0x80) | + ((dipsw & 2) ? (reg[2] & 0x20) : ((reg[1] >> 1) & 0x20)) | + ((dipsw & 4) ? (reg[2] & 0x40) : ((reg[1] << 1) & 0x40)); + setprg8(A, bank | (V & mask)); +} + +static DECLFR(M401Read) { + if ((dipsw & 0x01) && (reg[1] & 0x80)) { + return cpu.openbus; + } + return CartBR(A); +} + +static DECLFW(M401Write) { + /* FCEU_printf("Wr A:%04x V:%02x index:%d\n", A, V, cmd); */ + if (!(reg[3] & 0x40)) { + reg[cmd] = V; + cmd = (cmd + 1) & 0x03; + MMC3_FixPRG(); + MMC3_FixCHR(); + } + CartBW(A, V); +} + +static void M401Reset(void) { + dipsw = (dipsw + 1) & 7; + FCEU_printf("dipsw = %d\n", dipsw); + reg[0] = 0x00; + reg[1] = 0x00; + reg[2] = 0x0F; + reg[3] = 0x00; + cmd = 0x00; + MMC3_Reset(); +} + +static void M401Power(void) { + dipsw = 7; + reg[0] = 0x00; + reg[1] = 0x00; + reg[2] = 0x0F; + reg[3] = 0x00; + cmd = 0x00; + MMC3_Power(); + SetReadHandler(0x8000, 0xFFFF, M401Read); + SetWriteHandler(0x6000, 0x7FFF, M401Write); +} + +void Mapper401_Init(CartInfo *info) { + MMC3_Init(info, 8, 0); + MMC3_cwrap = M401CW; + MMC3_pwrap = M401PW; + info->Power = M401Power; + info->Reset = M401Reset; + AddExState(reg, 4, 0, "EXPR"); + AddExState(&cmd, 1, 0, "CMD0"); + AddExState(&dipsw, 1, 0, "DPSW"); +} diff --git a/src/mappers/mapper402.c b/src/mappers/mapper402.c new file mode 100644 index 000000000..d645670ac --- /dev/null +++ b/src/mappers/mapper402.c @@ -0,0 +1,47 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + if (latch.addr & 0x800) { + setprg8(0x6000, ((latch.addr & 0x1F) << 1) | 3); + } + if ((latch.addr & 0x40)) { + setprg16(0x8000, latch.addr & 0x1F); + setprg16(0xC000, latch.addr & 0x1F); + } else { + setprg32(0x8000, (latch.addr & 0x1F) >> 1); + } + if ((latch.addr & 0x400) == 0) { + SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0); + } else { + SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1); + } + setchr8(0); + setmirror(((latch.addr >> 7) & 0x01) ^ 0x01); +} + +void Mapper402_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Reset = Latch_RegReset; +} diff --git a/src/boards/mapper403.c b/src/mappers/mapper403.c similarity index 77% rename from src/boards/mapper403.c rename to src/mappers/mapper403.c index eaa5e81bb..5afff3ba7 100644 --- a/src/boards/mapper403.c +++ b/src/mappers/mapper403.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2022 + * Copyright (C) 2023-2024 negativeExponent * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -29,29 +30,31 @@ static uint8 reg[3]; -static void Sync(void) { - uint8 prg = reg[0]; - uint8 chr = reg[1]; - uint8 mode = reg[2]; +static SFORMAT StateRegs[] = { + { reg, 3, "REGS" }, + { 0 } +}; - /* NROM-128 */ - if (mode & 1) { - setprg16(0x8000, prg >> 1); - setprg16(0xC000, prg >> 1); - /* NROM-256 */ - } else - setprg32(0x8000, prg >> 2); - setchr8(chr); - setmirror(((mode >> 4) & 1) ^ 1); +static void Sync(void) { + if (reg[2] & 0x01) { /* NROM-128 */ + setprg16(0x8000, reg[0] >> 1); + setprg16(0xC000, reg[0] >> 1); + } else { /* NROM-256 */ + setprg32(0x8000, reg[0] >> 2); + } + setchr8(reg[1]); + setmirror(((reg[2] >> 4) & 0x01) ^ 0x01); } static DECLFW(M403Write4) { - reg[A & 3] = V; - Sync(); + if (A & 0x100) { + reg[A & 0x03] = V; + Sync(); + } } static DECLFW(M403Write8) { - if (reg[2] & 4) { + if (reg[2] & 0x04) { reg[1] = V; Sync(); } @@ -67,7 +70,7 @@ static void M403Power(void) { Sync(); SetReadHandler(0x6000, 0x7FFF, CartBR); /* For TetrisA (Tetris Family 19-in-1 NO 1683) */ SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x4100, 0x4103, M403Write4); + SetWriteHandler(0x4100, 0x5FFF, M403Write4); SetWriteHandler(0x8000, 0xFFFF, M403Write8); } @@ -79,5 +82,5 @@ void Mapper403_Init(CartInfo *info) { info->Reset = M403Reset; info->Power = M403Power; GameStateRestore = StateRestore; - AddExState(®, 3, 0, "REGS"); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper404.c b/src/mappers/mapper404.c new file mode 100644 index 000000000..46b80c4ec --- /dev/null +++ b/src/mappers/mapper404.c @@ -0,0 +1,65 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 404 - JY012005 + * 1998 Super HiK 8-in-1 (JY-021B) + */ + +#include "mapinc.h" +#include "mmc1.h" + +static uint8 reg; + +static void M404PW(uint32 A, uint8 V) { + uint8 mask = (reg & 0x40) ? 0x07 : 0x0F; + setprg16(A, ((reg << 3) & ~mask) | (V & mask)); +} + +static void M404CW(uint32 A, uint8 V) { + setchr4(A, (reg << 5) | (V & 0x1F)); +} + +static DECLFW(M404Write) { + if (!(reg & 0x80)) { + reg = V; + MMC1_FixPRG(); + MMC1_FixCHR(); + } +} + +static void M404Reset(void) { + reg = 0; + MMC1_Reset(); +} + +static void M404Power(void) { + reg = 0; + MMC1_Power(); + SetWriteHandler(0x6000, 0x7FFF, M404Write); +} + +void Mapper404_Init(CartInfo *info) { + MMC1_Init(info, 0, 0); + info->Power = M404Power; + info->Reset = M404Reset; + MMC1_cwrap = M404CW; + MMC1_pwrap = M404PW; + AddExState(®, 1, 0, "BANK"); +} diff --git a/src/boards/mapper406.c b/src/mappers/mapper406.c similarity index 51% rename from src/boards/mapper406.c rename to src/mappers/mapper406.c index 459b53bcb..27ed64796 100644 --- a/src/boards/mapper406.c +++ b/src/mappers/mapper406.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,69 +25,63 @@ #include "mmc3.h" #include "flashrom.h" -static uint8 *FLASHROM = NULL; +static uint8 *FLASHROM_data = NULL; static uint32 FLASHROM_size = 0; -static uint8 submapper; - static void M406PW(uint32 A, uint8 V) { - setprg8r(0x10, A, V & 0x3F); + setprg8r(0x10, A, V & 0x3F); } -static DECLFR(M406FlashRead) { - return FlashRead(A); +static DECLFR(M406Read) { + return FlashROM_Read(A); } -static DECLFW(M406FlashWrite) { - FlashWrite(A, V); - if (submapper == 0) { - A = (A & 0xFFFC) | ((A << 1) & 2) | ((A >> 1) & 1); +static DECLFW(M406Write) { + FlashROM_Write(A, V); + if (iNESCart.submapper == 0) { + A = (A & 0xFFFC) | ((A << 1) & 2) | ((A >> 1) & 1); } else if ((A <= 0x9000) || (A >= 0xE000)) { - A = A ^ 0x6000; + A = A ^ 0x6000; } - if (A >= 0xC000) { - MMC3_IRQWrite(A, V); - } else { - MMC3_CMDWrite(A, V); - } + MMC3_Write(A, V); } static void M406Power(void) { - GenMMC3Power(); - SetReadHandler(0x8000, 0xFFFF, M406FlashRead); - SetWriteHandler(0x8000, 0xFFFF, M406FlashWrite); + MMC3_Power(); + SetReadHandler(0x8000, 0xFFFF, M406Read); + SetWriteHandler(0x8000, 0xFFFF, M406Write); } -static void M406Close() { - GenMMC3Close(); - if (FLASHROM) - FCEU_free(FLASHROM); - FLASHROM = NULL; +static void M406Close(void) { + MMC3_Close(); + if (FLASHROM_data) { + FCEU_free(FLASHROM_data); + } + FLASHROM_data = NULL; } void Mapper406_Init(CartInfo *info) { - uint32 w, r; - GenMMC3_Init(info, 512, 256, 0, 0); + uint32 w, r, id; + + MMC3_Init(info, 0, 0); info->Power = M406Power; info->Close = M406Close; - mmc3.pwrap = M406PW; - submapper = info->submapper; - MapIRQHook = FlashCPUHook; + MMC3_pwrap = M406PW; + MapIRQHook = FlashROM_CPUCyle; + info->battery = 1; FLASHROM_size = PRGsize[0]; - FLASHROM = (uint8 *)FCEU_gmalloc(FLASHROM_size); - info->SaveGame[0] = FLASHROM; + FLASHROM_data = (uint8 *)FCEU_gmalloc(FLASHROM_size); + info->SaveGame[0] = FLASHROM_data; info->SaveGameLen[0] = FLASHROM_size; - AddExState(FLASHROM, FLASHROM_size, 0, "FROM"); - /* copy PRG ROM into FLASHROM, use it instead of PRG ROM */ + AddExState(FLASHROM_data, FLASHROM_size, 0, "FROM"); + /* copy PRG ROM into FLASHROM_data, use it instead of PRG ROM */ for (w = 0, r = 0; w < FLASHROM_size; w++) { - FLASHROM[w] = PRGptr[0][r]; + FLASHROM_data[w] = PRGptr[0][r]; ++r; } - SetupCartPRGMapping(0x10, FLASHROM, FLASHROM_size, 0); - if (submapper == 0) { - Flash_Init(FLASHROM, FLASHROM_size, 0xC2, 0xA4, 65536, 0x5555, 0x02AAA); - } else { - Flash_Init(FLASHROM, FLASHROM_size, 0x01, 0xA4, 65536, 0x5555, 0x02AAA); - } + SetupCartPRGMapping(0x10, FLASHROM_data, FLASHROM_size, 0); + + id = (info->submapper == 0) ? 0xC2 : 0x01; + FlashROM_Init(FLASHROM_data, FLASHROM_size, id, 0xA4, 65536, 0x5555, 0x02AAA); } diff --git a/src/mappers/mapper409.c b/src/mappers/mapper409.c new file mode 100644 index 000000000..9729dfa54 --- /dev/null +++ b/src/mappers/mapper409.c @@ -0,0 +1,33 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg16(0x8000, latch.addr); + setprg16(0xC000, ~0); + setchr8(0); +} + +void Mapper409_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); +} diff --git a/src/boards/mapper410.c b/src/mappers/mapper410.c similarity index 68% rename from src/boards/mapper410.c rename to src/mappers/mapper410.c index 20456885c..42c82da85 100644 --- a/src/boards/mapper410.c +++ b/src/mappers/mapper410.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2022 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -27,60 +28,73 @@ #include "mapinc.h" #include "mmc3.h" +static uint8 reg[4]; +static uint8 cmd; + static uint8 *CHRRAM; -static void M410CW(uint32 A, uint8 V) { - if (!(mmc3.expregs[2] & 0x40)) { - uint32 mask = 0xFF >> (~mmc3.expregs[2] & 0xF); - uint32 base = ((mmc3.expregs[2] << 4) & 0xF00) | mmc3.expregs[0]; - setchr1(A, (base & ~mask) | (V & mask)); - } else - setchr8r(0x10, 0); -} +static SFORMAT StateRegs[] = { + { reg, 4, "REGS" }, + { &cmd, 1, "CMD0" }, + { 0 } +}; static void M410PW(uint32 A, uint8 V) { - uint32 mask = ~mmc3.expregs[3] & 0x3F; - uint32 base = ((mmc3.expregs[2] << 2) & 0x300) | mmc3.expregs[1]; + uint32 mask = ~reg[3] & 0x3F; + uint32 base = ((reg[2] << 2) & 0x300) | reg[1]; + setprg8(A, (base & ~mask) | (V & mask)); } +static void M410CW(uint32 A, uint8 V) { + if (!(reg[2] & 0x40)) { + uint32 mask = 0xFF >> (~reg[2] & 0x0F); + uint32 base = ((reg[2] << 4) & 0xF00) | reg[0]; + + setchr1(A, (base & ~mask) | (V & mask)); + } else { + setchr8r(0x10, 0); + } +} + static DECLFW(M410Write) { - if (!(mmc3.expregs[3] & 0x40)) { - mmc3.expregs[mmc3.expregs[4]] = V; - mmc3.expregs[4] = (mmc3.expregs[4] + 1) & 3; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + if (!(reg[3] & 0x40)) { + reg[cmd] = V; + cmd = (cmd + 1) & 0x03; + MMC3_FixPRG(); + MMC3_FixCHR(); } } static void M410Close(void) { - GenMMC3Close(); - if (CHRRAM) + MMC3_Close(); + if (CHRRAM) { FCEU_free(CHRRAM); + } CHRRAM = NULL; } static void M410Reset(void) { - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[3] = mmc3.expregs[4] = 0; - mmc3.expregs[2] = 0x0F; - MMC3RegReset(); + reg[0] = reg[1] = reg[3] = cmd = 0; + reg[2] = 0x0F; + MMC3_Reset(); } static void M410Power(void) { - GenMMC3Power(); - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[3] = mmc3.expregs[4] = 0; - mmc3.expregs[2] = 0x0F; + MMC3_Power(); + reg[0] = reg[1] = reg[3] = cmd = 0; + reg[2] = 0x0F; SetWriteHandler(0x6000, 0x7FFF, M410Write); } void Mapper410_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 0, 0); - mmc3.cwrap = M410CW; - mmc3.pwrap = M410PW; + MMC3_Init(info, 0, 0); + MMC3_cwrap = M410CW; + MMC3_pwrap = M410PW; info->Reset = M410Reset; info->Power = M410Power; info->Close = M410Close; - AddExState(mmc3.expregs, 5, 0, "EXPR"); + AddExState(StateRegs, ~0, 0, NULL); CHRRAM = (uint8 *)FCEU_gmalloc(8192); SetupCartCHRMapping(0x10, CHRRAM, 8192, 1); diff --git a/src/boards/mapper411.c b/src/mappers/mapper411.c similarity index 54% rename from src/boards/mapper411.c rename to src/mappers/mapper411.c index 139361dc3..d6159452e 100644 --- a/src/boards/mapper411.c +++ b/src/mappers/mapper411.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -31,52 +32,58 @@ #include "mapinc.h" #include "mmc3.h" +static uint8 reg[2]; + static void M411CW(uint32 A, uint8 V) { - uint32 mask = (mmc3.expregs[1] & 2) ? 0xFF : 0x7F; - setchr1(A, (V & mask) | ((mmc3.expregs[1] << 5) & 0x80) | ((mmc3.expregs[0] << 4) & 0x100)); + uint16 mask = (reg[1] & 0x02) ? 0xFF : 0x7F; + uint16 base = ((reg[0] << 4) & 0x100) | ((reg[1] << 5) & 0x80); + + setchr1(A, (base & ~mask) | (V & mask)); } static void M411PW(uint32 A, uint8 V) { - /* NROM Mode */ - if ((mmc3.expregs[0] & 0x40) && !(mmc3.expregs[0] & 0x20)) { /* $5xx0 bit 5 check required for JY-212 */ - uint32 bank = (mmc3.expregs[0] & 1) | ((mmc3.expregs[0] >> 2) & 2) | (mmc3.expregs[0] & 4) | (mmc3.expregs[1] & 8) | - ((mmc3.expregs[1] >> 2) & 0x10); + uint16 mask = (reg[1] & 0x02) ? 0x1F : 0x0F; + uint16 base = ((reg[1] >> 2) & 0x10) | (reg[1] & 0x08) | (reg[0] & 0x04) | ((reg[0] >> 2) & 0x02) | (reg[0] & 0x01); - /* NROM-256 */ - if (mmc3.expregs[0] & 0x02) { - setprg32(0x8000, bank >> 1); - - /* NROM-128 */ - } else { - setprg16(0x8000, bank); - setprg16(0xC000, bank); + /* NROM Mode */ + if ((reg[0] & 0x40) && !(reg[0] & 0x20)) { /* $5xx0 bit 5 check required for JY-212 */ + if (reg[0] & 0x02) { /* NROM-256 */ + setprg32(0x8000, base >> 1); + } else { /* NROM-128 */ + setprg16(0x8000, base); + setprg16(0xC000, base); } + } else { /* MMC3 */ + setprg8(A, ((base << 1) & ~mask) | (V & mask)); } +} - /* MMC3 Mode */ - else { - uint32 mask = (mmc3.expregs[1] & 2) ? 0x1F : 0x0F; - setprg8(A, (V & mask) | ((mmc3.expregs[1] << 1) & 0x10) | ((mmc3.expregs[1] >> 1) & 0x20)); +static DECLFW(M411Write) { + if (A & 0x800) { + reg[A & 0x01] = V; + MMC3_FixPRG(); + MMC3_FixCHR(); } } -static DECLFW(M411Write5000) { - mmc3.expregs[A & 1] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); +static void M411Reset(void) { + reg[0] = 0x80; + reg[1] = 0x82; + MMC3_Reset(); } static void M411Power(void) { - mmc3.expregs[0] = 0x80; - mmc3.expregs[1] = 0x82; - GenMMC3Power(); - SetWriteHandler(0x5000, 0x5FFF, M411Write5000); + reg[0] = 0x80; + reg[1] = 0x82; + MMC3_Power(); + SetWriteHandler(0x5000, 0x5FFF, M411Write); } void Mapper411_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 0, 0); - mmc3.pwrap = M411PW; - mmc3.cwrap = M411CW; + MMC3_Init(info, 0, 0); + MMC3_pwrap = M411PW; + MMC3_cwrap = M411CW; info->Power = M411Power; - AddExState(mmc3.expregs, 2, 0, "EXPR"); + info->Reset = M411Reset; + AddExState(reg, 2, 0, "EXPR"); } diff --git a/src/boards/mapper412.c b/src/mappers/mapper412.c similarity index 63% rename from src/boards/mapper412.c rename to src/mappers/mapper412.c index 2aeb17cd3..39f90790b 100644 --- a/src/boards/mapper412.c +++ b/src/mappers/mapper412.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2022 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -27,54 +28,66 @@ #include "mapinc.h" #include "mmc3.h" +static uint8 reg[4]; + static void M412CW(uint32 A, uint8 V) { - if (mmc3.expregs[2] & 2) { - setchr8(mmc3.expregs[0] >> 2); + uint16 mask = (reg[1] & 0x20) ? 0x7F : 0xFF; + uint16 base = ((reg[1] << 5) & 0x100) | (reg[1] & 0x80); + uint16 bank = reg[0] >> 2; + + if (reg[2] & 0x02) { + setchr8(bank); } else { - setchr1(A, (mmc3.expregs[1] & 0x80) | (V & 0x7F)); + setchr1(A, (base & ~mask) | (V & mask)); } } static void M412PW(uint32 A, uint8 V) { - if (mmc3.expregs[2] & 2) { - uint8 bank = mmc3.expregs[2] >> 3; - if (mmc3.expregs[2] & 4) { + uint16 mask = 0x3F & ~(((reg[1] << 1) & 0x20) | ((reg[1] << 3) & 0x10)); + uint16 base = ((reg[1] << 3) & 0x20) | ((reg[1] >> 2) & 0x10); + uint16 bank = reg[2] >> 3; + + if (reg[2] & 0x02) { + if (reg[2] & 0x04) { setprg32(0x8000, bank >> 1); } else { setprg16(0x8000, bank); setprg16(0xC000, bank); } } else { - uint32 mask = 0x3F & ~((mmc3.expregs[1] << 3) & 0x38); - uint32 base = (mmc3.expregs[1] >> 2) & 0x3E; - setprg8(A, base | (V & mask)); + setprg8(A, (base & ~mask) | (V & mask)); } } static DECLFW(M412Write) { - if (MMC3CanWriteToWRAM()) { - mmc3.expregs[A & 3] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + if (MMC3_WramIsWritable()) { + CartBW(A, V); + if (!(reg[1] & 0x01)) { + reg[A & 0x03] = V; + MMC3_FixPRG(); + MMC3_FixCHR(); + } } } static void M412Reset(void) { - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[2] = mmc3.expregs[3] = 0; - MMC3RegReset(); + reg[0] = reg[1] = reg[2] = reg[3] = 0; + MMC3_Reset(); + mmc3.wram = 0x80; } static void M412Power(void) { - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[2] = mmc3.expregs[3] = 0; - GenMMC3Power(); + reg[0] = reg[1] = reg[2] = reg[3] = 0; + MMC3_Power(); + mmc3.wram = 0x80; SetWriteHandler(0x6000, 0x7FFF, M412Write); } void Mapper412_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 0, 0); - mmc3.cwrap = M412CW; - mmc3.pwrap = M412PW; + MMC3_Init(info, 0, 0); + MMC3_cwrap = M412CW; + MMC3_pwrap = M412PW; info->Reset = M412Reset; info->Power = M412Power; - AddExState(mmc3.expregs, 4, 0, "EXPR"); + AddExState(reg, 4, 0, "EXPR"); } diff --git a/src/mappers/mapper413.c b/src/mappers/mapper413.c new file mode 100644 index 000000000..003f97504 --- /dev/null +++ b/src/mappers/mapper413.c @@ -0,0 +1,147 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * Copyright (C) 2024 negativeExponent + * + * 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" + +static uint8 reg[4]; +static uint8 IRQCount; +static uint8 IRQReload; +static uint8 IRQa; +static uint8 serialControl; +static uint32 serialAddress; + +static SFORMAT StateRegs[] = { + { reg, 4, "REGS" }, + { &IRQCount, 1, "IRQC" }, + { &IRQReload, 1, "IRQR" }, + { &IRQa, 1, "IRQA" }, + { &serialAddress, 4, "ADDR" }, + { &serialControl, 1, "CTRL" }, + { 0 } +}; + +static void Sync(void) { + setprg4(0x5000, 0x01); + setprg8(0x6000, reg[0]); + + setprg8(0x8000, reg[1]); + setprg8(0xA000, reg[2]); + setprg4(0xD000, 0x07); + setprg8(0xE000, 0x04); + + setchr4(0x0000, reg[3]); + setchr4(0x1000, ~0x02); +} + +static uint64 lreset; +static uint32 laddr; +static DECLFR(M413ReadPCM) { + uint8 ret = cpu.openbus; + if ((A == laddr) && ((timestampbase + timestamp) < (lreset + 4))) { + return ret; + } + if (serialControl & 0x02) { + ret = ROM.misc.data[serialAddress++ & (ROM.misc.size - 1)]; + } else { + ret = ROM.misc.data[serialAddress & (ROM.misc.size - 1)]; + } + laddr = A; + lreset = timestampbase + timestamp; + return ret; +} + +static DECLFW(M413Write) { + switch (A & 0xF000) { + case 0x8000: + IRQReload = V; + break; + case 0x9000: + IRQCount = 0; + break; + case 0xA000: + case 0xB000: + IRQa = (A & 0x1000) != 0; + if (!IRQa) { + X6502_IRQEnd(FCEU_IQEXT); + } + break; + case 0xC000: + serialAddress = (serialAddress << 1) | (V >> 7); + break; + case 0xD000: + serialControl = V; + break; + case 0xE000: + case 0xF000: + reg[V >> 6] = V & 0x3F; + Sync(); + break; + } +} + +static void M413Power(void) { + serialAddress = 0; + serialControl = 0; + + IRQCount = 0; + IRQReload = 0; + IRQa = 0; + + reg[0] = 0; + reg[1] = 0; + reg[2] = 0; + reg[3] = 0; + + laddr = 0; + lreset = 0; + + Sync(); + + SetReadHandler(0x4800, 0x4FFF, M413ReadPCM); + SetReadHandler(0xC000, 0xCFFF, M413ReadPCM); + SetReadHandler(0x5000, 0x7FFF, CartBR); + SetReadHandler(0x8000, 0xBFFF, CartBR); + SetReadHandler(0xD000, 0xFFFF, CartBR); + + SetWriteHandler(0x8000, 0xFFFF, M413Write); +} + +static void M413IRQHook(void) { + if (IRQCount == 0) { + IRQCount = IRQReload; + } else { + IRQCount--; + } + if ((IRQCount == 0) && IRQa) { + X6502_IRQBegin(FCEU_IQEXT); + } +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper413_Init(CartInfo *info) { + info->Power = M413Power; + GameHBIRQHook = M413IRQHook; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/mapper414.c b/src/mappers/mapper414.c similarity index 79% rename from src/boards/mapper414.c rename to src/mappers/mapper414.c index 7984e123b..5205a3f9a 100644 --- a/src/boards/mapper414.c +++ b/src/mappers/mapper414.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2022 + * Copyright (C) 2023-2024 negativeExponent * * 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,10 +22,10 @@ #include "mapinc.h" #include "latch.h" -static uint8 dipswitch; +static uint8 dipsw; static SFORMAT StateRegs[] = { - { &dipswitch, 1, "DPSW" }, + { &dipsw, 1, "DPSW" }, { 0 } }; @@ -36,24 +37,24 @@ static void Sync(void) { setprg16(0xC000, latch.addr >> 1); } setchr8(latch.data); - setmirror((latch.addr & 1) ^ 1); + setmirror((latch.addr & 0x01) ^ 0x01); } static DECLFR(M414Read) { - if ((A >= 0xC000) && !(latch.addr & 0x100 ) && (latch.addr & (dipswitch << 4))) { - return X.DB; + if ((A >= 0xC000) && !(latch.addr & 0x100) && (latch.addr & (dipsw << 4))) { + return cpu.openbus; } return CartBR(A); } -static void M414Reset() { - dipswitch++; - dipswitch &= 0x0F; +static void M414Reset(void) { + dipsw++; + dipsw &= 0x0F; Sync(); } void Mapper414_Init(CartInfo *info) { - Latch_Init(info, Sync, M414Read, 0, 1); + Latch_Init(info, Sync, M414Read, FALSE, TRUE); info->Reset = M414Reset; AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper415.c b/src/mappers/mapper415.c new file mode 100644 index 000000000..c6a4fde57 --- /dev/null +++ b/src/mappers/mapper415.c @@ -0,0 +1,40 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + setprg8(0x6000, latch.data); + setprg32(0x8000, ~0); + setchr8(0); + setmirror(((latch.data >> 4) & 0x01) ^ 0x01); +} + +static void M415Power(void) { + Latch_Power(); + SetReadHandler(0x6000, 0x7FFF, CartBR); +} + +void Mapper415_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Power = M415Power; +} diff --git a/src/mappers/mapper416.c b/src/mappers/mapper416.c new file mode 100644 index 000000000..ed9ccde82 --- /dev/null +++ b/src/mappers/mapper416.c @@ -0,0 +1,110 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2022 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static uint8 smb2j_reg; +static uint8 IRQa; +static uint16 IRQCount; + +static SFORMAT StateRegs[] = { + { &smb2j_reg, 1, "SMB2" }, + { &IRQa, 1, "IRQA" }, + { &IRQCount, 2, "IRQC" }, + { 0 } +}; + +static void Sync(void) { + uint8 prg = ((latch.data >> 1) & 0x04) | ((latch.data >> 6) & 0x02) | ((latch.data >> 5) & 0x01); + + if (latch.addr >= 0xA000) { + /* latch should not respond to $A000-$FFFF */ + return; + } + + setprg8(0x6000, 0x07); + if (latch.data & 0x08) { + switch (latch.data & 0xC0) { + case 0x00: + setprg8(0x8000, prg << 1); + setprg8(0xA000, prg << 1); + setprg8(0xC000, prg << 1); + setprg8(0xE000, prg << 1); + break; + case 0x40: + setprg16(0x8000, prg); + setprg16(0xC000, prg); + break; + case 0x80: + case 0xC0: + setprg32(0x8000, prg >> 1); + break; + } + } else { + setprg8(0x8000, 0x00); + setprg8(0xA000, 0x01); + setprg8(0xC000, smb2j_reg); + setprg8(0xE000, 0x03); + } + setchr8((latch.data >> 1) & 0x03); + setmirror(((latch.data >> 2) & 0x01) ^ 0x01); +} + +static DECLFW(M416WriteReg) { + if ((A & 0x20) && !(A & 0x40)) { + if (A & 0x100) { + IRQa = V & 0x01; + if (!IRQa) { + IRQCount = 0; + X6502_IRQEnd(FCEU_IQEXT); + } + } else { + smb2j_reg = (V & ~0x07) | ((V << 2) & 0x04) | ((V >> 1) & 0x03); + Sync(); + } + } +} + +static void M416Power(void) { + smb2j_reg = IRQa = IRQCount = 0; + Latch_Power(); + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x4020, 0x5FFF, M416WriteReg); +} + +static void M416IRQHook(int a) { + if (IRQa & 0x01) { + IRQCount += a; + if (IRQCount & 0x1000) { + X6502_IRQBegin(FCEU_IQEXT); + } else { + X6502_IRQEnd(FCEU_IQEXT); + } + } +} + +void Mapper416_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Power = M416Power; + MapIRQHook = M416IRQHook; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/mapper417.c b/src/mappers/mapper417.c similarity index 56% rename from src/boards/mapper417.c rename to src/mappers/mapper417.c index c875f9a61..97ecdd956 100644 --- a/src/boards/mapper417.c +++ b/src/mappers/mapper417.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2022 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -20,15 +21,15 @@ #include "mapinc.h" -static uint8 preg[4]; -static uint8 creg[8]; +static uint8 prg[4]; +static uint8 chr[8]; static uint8 nt[4]; static uint8 IRQa; static uint16 IRQCount; static SFORMAT StateRegs[] = { - { preg, 4, "PREG" }, - { creg, 8, "CREG" }, + { prg, 4, "PREG" }, + { chr, 8, "CREG" }, { nt, 4, "NREG" }, { &IRQa, 1, "IRQA" }, { &IRQCount, 2, "IRQC" }, @@ -36,56 +37,70 @@ static SFORMAT StateRegs[] = { }; static void Sync(void) { - int i; - setprg8(0x8000, preg[0]); - setprg8(0xA000, preg[1]); - setprg8(0xC000, preg[2]); + setprg8(0x8000, prg[0]); + setprg8(0xA000, prg[1]); + setprg8(0xC000, prg[2]); setprg8(0xE000, ~0); - for (i = 0; i < 8; i++) - setchr1(i << 10, creg[i]); - setmirrorw(nt[0] & 1, nt[1] & 1, nt[2] & 1, nt[3] & 1); + + setchr1(0x0000, chr[0]); + setchr1(0x0400, chr[1]); + setchr1(0x0800, chr[2]); + setchr1(0x0C00, chr[3]); + setchr1(0x1000, chr[4]); + setchr1(0x1400, chr[5]); + setchr1(0x1800, chr[6]); + setchr1(0x1C00, chr[7]); + + setmirrorw(nt[0] & 0x01, nt[1] & 0x01, nt[2] & 0x01, nt[3] & 0x01); } static DECLFW(M417Write) { - switch ((A >> 4) & 7) { - case 0: - preg[A & 3] = V; - Sync(); - break; - case 1: - creg[0 | (A & 3)] = V; - Sync(); - break; - case 2: - creg[4 | (A & 3)] = V; - Sync(); - break; - break; - case 3: - IRQCount = 0; - IRQa = 1; - break; - case 4: - IRQa = 0; - X6502_IRQEnd(FCEU_IQEXT); - break; - case 5: - nt[A & 3] = V; - Sync(); - break; + switch ((A >> 4) & 0x07) { + case 0: + prg[A & 0x03] = V; + Sync(); + break; + case 1: + chr[0 | (A & 0x03)] = V; + if (iNESCart.submapper == 1) nt[A & 0x03] = V >> 7; + Sync(); + break; + case 2: + chr[4 | (A & 0x03)] = V; + Sync(); + break; + break; + case 3: + IRQCount = 0; + IRQa = TRUE; + break; + case 4: + IRQa = FALSE; + X6502_IRQEnd(FCEU_IQEXT); + break; + case 5: + if (iNESCart.submapper == 0) nt[A & 0x03] = V & 0x01; + Sync(); + break; } } static void M417Power(void) { + memset(prg, 0, sizeof(prg)); + memset(chr, 0, sizeof(chr)); + memset(nt, 0, sizeof(nt)); Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0xFFFF, M417Write); } static void M417IRQHook(int a) { + uint16 mask = (iNESCart.submapper == 1) ? 0x1000 : 0x400; + IRQCount += a; - if (IRQa && IRQCount > 1024) + if (IRQa && (IRQCount & mask)) { X6502_IRQBegin(FCEU_IQEXT); + } } static void StateRestore(int version) { @@ -96,5 +111,5 @@ void Mapper417_Init(CartInfo *info) { info->Power = M417Power; MapIRQHook = M417IRQHook; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper418.c b/src/mappers/mapper418.c new file mode 100644 index 000000000..cb757380f --- /dev/null +++ b/src/mappers/mapper418.c @@ -0,0 +1,39 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 418 denotes the 820106-C/821007C circuit boards for the LH42 bootleg cartridge versions of Highway Star. */ + +#include "mapinc.h" +#include "n118.h" + +static void M418FixCHR(void) { + setchr2(0x0000, (n118.reg[0] & 0x3F) >> 1); + setchr2(0x0800, (n118.reg[1] & 0x3F) >> 1); + setchr1(0x1000, n118.reg[2] & 0x3F); + setchr1(0x1400, n118.reg[3] & 0x3F); + setchr1(0x1800, n118.reg[4] & 0x3F); + setchr1(0x1C00, n118.reg[5] & 0x3F); + setmirror((n118.reg[5] & 0x01) ^ 0x01); +} + +void Mapper418_Init(CartInfo *info) { + N118_Init(info, 0, 0); + N118_FixCHR = M418FixCHR; +} diff --git a/src/boards/mapper420.c b/src/mappers/mapper420.c similarity index 59% rename from src/boards/mapper420.c rename to src/mappers/mapper420.c index ac9c19866..4a200f7d5 100644 --- a/src/boards/mapper420.c +++ b/src/mappers/mapper420.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 +21,50 @@ #include "mapinc.h" #include "mmc3.h" +static uint8 reg[4]; + static void M420CW(uint32 A, uint8 V) { - uint8 mask = (mmc3.expregs[1] & 0x80) ? 0x7F : 0xFF; - setchr1(A, ((mmc3.expregs[1] << 1) & 0x100) | ((mmc3.expregs[1] << 5) & 0x80) | (V & mask)); + uint16 mask = (reg[1] & 0x80) ? 0x7F : 0xFF; + uint16 base = ((reg[1] << 1) & 0x100) | ((reg[1] << 5) & 0x80); + + setchr1(A, base | (V & mask)); } static void M420PW(uint32 A, uint8 V) { - if (mmc3.expregs[0] & 0x80) { - setprg32(0x8000, ((mmc3.expregs[2] >> 2) & 8) | ((mmc3.expregs[0] >> 1) & 7)); + if (reg[0] & 0x80) { + setprg32(0x8000, ((reg[2] >> 2) & 0x08) | ((reg[0] >> 1) & 0x07)); } else { - uint8 mask = (mmc3.expregs[0] & 0x20) ? 0x0F : ((mmc3.expregs[3] & 0x20) ? 0x1F : 0x3F); - setprg8(A, ((mmc3.expregs[3] << 3) & 0x20) | (V & mask)); + uint8 mask = (reg[0] & 0x20) ? 0x0F : ((reg[3] & 0x20) ? 0x1F : 0x3F); + uint8 base = (reg[3] << 3) & 0x20; + + setprg8(A, base | (V & mask)); } } static DECLFW(M420Write) { /* writes possible regardless of MMC3 wram state */ - mmc3.expregs[A & 3] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + CartBW(A, V); + reg[A & 0x03] = V; + MMC3_FixPRG(); + MMC3_FixCHR(); } static void M420Reset(void) { - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[2] = mmc3.expregs[3] = 0; - MMC3RegReset(); + reg[0] = reg[1] = reg[2] = reg[3] = 0; + MMC3_Reset(); } static void M420Power(void) { - mmc3.expregs[0] = mmc3.expregs[1] = mmc3.expregs[2] = mmc3.expregs[3] = 0; - GenMMC3Power(); + reg[0] = reg[1] = reg[2] = reg[3] = 0; + MMC3_Power(); SetWriteHandler(0x6000, 0x7FFF, M420Write); } void Mapper420_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 0, 0); - mmc3.cwrap = M420CW; - mmc3.pwrap = M420PW; + MMC3_Init(info, 0, 0); + MMC3_cwrap = M420CW; + MMC3_pwrap = M420PW; info->Reset = M420Reset; info->Power = M420Power; - AddExState(mmc3.expregs, 4, 0, "EXPR"); + AddExState(reg, 4, 0, "EXPR"); } diff --git a/src/mappers/mapper421.c b/src/mappers/mapper421.c new file mode 100644 index 000000000..46a6ff3a0 --- /dev/null +++ b/src/mappers/mapper421.c @@ -0,0 +1,41 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "jyasic.h" + +static uint32 GetPRGBank(uint32 V) { + if (jyasic.mode[3] & 0x04) { + return (((jyasic.mode[3] << 4) & ~0x3F) | (V & 0x3F)); + } else { + return (((jyasic.mode[3] << 4) & ~0x1F) | (V & 0x1F)); + } +} + +static uint32 GetCHRBank(uint32 V) { + return (((jyasic.mode[3] << 8) & 0x300) | (V & 0x01FF)); +} + +void Mapper421_Init(CartInfo *info) { + /* Multicart */ + JYASIC_Init(info, TRUE); + JYASIC_GetPRGBank = GetPRGBank; + JYASIC_GetCHRBank = GetCHRBank; +} diff --git a/src/boards/mapper428.c b/src/mappers/mapper428.c similarity index 53% rename from src/boards/mapper428.c rename to src/mappers/mapper428.c index d14d4b4f9..b27eaa130 100644 --- a/src/boards/mapper428.c +++ b/src/mappers/mapper428.c @@ -1,8 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * - * Copyright (C) 2008 -2020 dragon2snow,loong2snow from www.nesbbs.com + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -17,73 +16,69 @@ * 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 "latch.h" -static uint8 regs[4]; -static uint8 hrd_flag; +static uint8 reg[4]; +static uint8 dipsw; -static SFORMAT StateRegs[] = -{ - { &hrd_flag, 1, "FLAG" }, - { regs, 4, "REGS" }, +static SFORMAT StateRegs[] = { + { &dipsw, 1, "DPSW" }, + { reg, 4, "REGS" }, { 0 } }; static void Sync(void) { - int mask = regs[2] >> 6; /* There is an CNROM mode that takes either two or four inner CHR banks from a CNROM-like + int mask = reg[2] >> 6; /* There is an CNROM mode that takes either two or four inner CHR banks from a CNROM-like latch register at $8000-$FFFF. */ - if (regs[1] & 0x10) { - setprg32(0x8000, (regs[1] & 0xC0) >> 6); + if (reg[1] & 0x10) { + setprg32(0x8000, reg[1] >> 6); } else { - setprg16(0x8000, (regs[1] & 0xE0) >> 5); - setprg16(0xC000, (regs[1] & 0xE0) >> 5); + setprg16(0x8000, reg[1] >> 5); + setprg16(0xC000, reg[1] >> 5); } - setchr8(((regs[1] & 0x07) & ~mask) | (latch.data & mask)); + setchr8(((reg[1] & 0x07) & ~mask) | (latch.data & mask)); - setmirror((regs[1] & 0x8) ? 0 : 1); + setmirror(((reg[1] >> 3) & 0x01) ^ 0x01); } -static DECLFW(WriteLo) { - regs[A & 0x03] = V; +static DECLFW(M428Write) { + reg[A & 0x03] = V; Sync(); } -static DECLFR(ReadLo) { - return hrd_flag; +static DECLFR(M428Read) { + return (cpu.openbus & ~0x03) | (dipsw & 0x03); } static void M428Power(void) { - hrd_flag = 0; /* Solder pad, selecting different menus */ - - regs[1] = 0; - regs[2] = 0; - - LatchPower(); - SetWriteHandler(0x6000, 0x7FFF, WriteLo); - SetReadHandler(0x6000, 0x7FFF, ReadLo); + dipsw = 0; + reg[0] = 0; + reg[1] = 0; + reg[2] = 0; + reg[3] = 0; + Latch_Power(); + SetWriteHandler(0x6000, 0x7FFF, M428Write); + SetReadHandler(0x6000, 0x7FFF, M428Read); SetReadHandler(0x8000, 0xFFFF, CartBR); } static void M428Reset(void) { - hrd_flag++; - hrd_flag &= 3; - - regs[1] = 0; - regs[2] = 0; - + dipsw++; + reg[0] = 0; + reg[1] = 0; + reg[2] = 0; + reg[3] = 0; Sync(); } void Mapper428_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); + Latch_Init(info, Sync, NULL, FALSE, FALSE); info->Power = M428Power; info->Reset = M428Reset; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper429.c b/src/mappers/mapper429.c new file mode 100644 index 000000000..29b8474d8 --- /dev/null +++ b/src/mappers/mapper429.c @@ -0,0 +1,40 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 429: LIKO BBG-235-8-1B/Milowork FCFC1 */ + +#include "mapinc.h" +#include "latch.h" + +static void Sync(void) { + setprg32(0x8000, latch.data >> 2); + setchr8(latch.data); +} + +static void Mapper429_Reset(void) { + latch.data = 4; /* Initial CHR bank 0, initial PRG bank 1 */ + Sync(); +} + +void Mapper429_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Reset = Mapper429_Reset; +} diff --git a/src/boards/mapper430.c b/src/mappers/mapper430.c similarity index 57% rename from src/boards/mapper430.c rename to src/mappers/mapper430.c index 1d1511700..2e5eeafbf 100644 --- a/src/boards/mapper430.c +++ b/src/mappers/mapper430.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,46 +21,57 @@ #include "mapinc.h" #include "mmc3.h" -static void M430CW(uint32 A, uint8 V) { - uint8 mask = (mmc3.expregs[0] & 4) ? 0x7F : 0xFF; - setchr1(A, ((mmc3.expregs[0] << 6) & ~mask) | (V & mask)); -} +static uint8 reg; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; static void M430PW(uint32 A, uint8 V) { - if (mmc3.expregs[0] & 8) { - setprg8(0x8000, ((mmc3.expregs[0] << 4) & 0x30) | ((mmc3.regs[6] & ~2) & 0x0F)); - setprg8(0xA000, ((mmc3.expregs[0] << 4) & 0x30) | ((mmc3.regs[7] & ~2) & 0x0F)); - setprg8(0xC000, ((mmc3.expregs[0] << 4) & 0x30) | ((mmc3.regs[6] | 2) & 0x0F)); - setprg8(0xE000, ((mmc3.expregs[0] << 4) & 0x30) | ((mmc3.regs[7] | 2) & 0x0F)); + uint8 mask = 0x0F; + uint8 base = (reg << 4) & 0x30; + + if (reg & 0x08) { + setprg8(0x8000, (base | ((mmc3.reg[6] & ~0x02) & mask))); + setprg8(0xA000, (base | ((mmc3.reg[7] & ~0x02) & mask))); + setprg8(0xC000, (base | ((mmc3.reg[6] | 0x02) & mask))); + setprg8(0xE000, (base | ((mmc3.reg[7] | 0x02) & mask))); } else { - setprg8(A, ((mmc3.expregs[0] << 4) & 0x30) | (V & 0x0F)); + setprg8(A, (base | (V & mask))); } } +static void M430CW(uint32 A, uint8 V) { + uint8 mask = (reg & 0x04) ? 0x7F : 0xFF; + + setchr1(A, ((reg << 6) & ~mask) | (V & mask)); +} + static DECLFW(M430Write) { - if (MMC3CanWriteToWRAM()) { - mmc3.expregs[0] = A & 0xFF; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + if (MMC3_WramIsWritable()) { + reg = A & 0xFF; + MMC3_FixPRG(); + MMC3_FixCHR(); } } static void M430Reset(void) { - mmc3.expregs[0] = 0; - MMC3RegReset(); + reg = 0; + MMC3_Reset(); } static void M430Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); + reg = 0; + MMC3_Power(); SetWriteHandler(0x6000, 0x7FFF, M430Write); } void Mapper430_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 256, 0, 0); - mmc3.cwrap = M430CW; - mmc3.pwrap = M430PW; + MMC3_Init(info, 0, 0); + MMC3_cwrap = M430CW; + MMC3_pwrap = M430PW; info->Reset = M430Reset; info->Power = M430Power; - AddExState(mmc3.expregs, 1, 0, "EXPR"); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper431.c b/src/mappers/mapper431.c similarity index 73% rename from src/boards/mapper431.c rename to src/mappers/mapper431.c index 3bfbbb6ae..85e5f3bdc 100644 --- a/src/boards/mapper431.c +++ b/src/mappers/mapper431.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2022 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -20,34 +21,32 @@ #include "mapinc.h" -static uint8 inner_bank; -static uint8 outer_bank; +static uint8 reg[2]; -static SFORMAT StateRegs[] = -{ - { &outer_bank, 1, "OUTB" }, - { &inner_bank, 1, "INNB" }, +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, { 0 } }; static void Sync(void) { - setprg16(0x8000, ((outer_bank >> 2) & ~7) | (inner_bank & 7)); - setprg16(0xC000, ((outer_bank >> 2) & ~7) | 7); + setprg16(0x8000, ((reg[0] >> 2) & ~0x07) | (reg[1] & 0x07)); + setprg16(0xC000, ((reg[0] >> 2) & ~0x07) | 0x07); setchr8(0); - setmirror((outer_bank & 1) ^ 1); + setmirror((reg[0] & 0x01) ^ 0x01); } static DECLFW(M431Write) { - if (A < 0xC000) - outer_bank = V; - else - inner_bank = V; + reg[(A >> 14) & 0x01] = V; + Sync(); +} + +static void M431Reset(void) { + reg[1] = reg[0] = 0; Sync(); } static void M431Power(void) { - inner_bank = 0; - outer_bank = 0; + reg[1] = reg[0] = 0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0xFFFF, M431Write); @@ -59,6 +58,7 @@ static void StateRestore(int version) { void Mapper431_Init(CartInfo *info) { info->Power = M431Power; + info->Reset = M431Reset; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper432.c b/src/mappers/mapper432.c new file mode 100644 index 000000000..c22573ebe --- /dev/null +++ b/src/mappers/mapper432.c @@ -0,0 +1,98 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 reg[2]; +static uint8 dipsw; + +static void M432CW(uint32 A, uint8 V) { + uint16 mask = (reg[1] & 0x04) ? 0x7F : 0xFF; + uint16 base = ((reg[1] << 7) & 0x080) | ((reg[1] << 5) & 0x100) | ((reg[1] << 4) & 0x200); + + setchr1(A, (base & ~mask) | (V & mask)); +} + +static void M432PW(uint32 A, uint8 V) { + uint16 mask = (reg[1] & 0x02) ? 0x0F : 0x1F; + uint16 base = ((reg[1] << 4) & 0x10) | ((reg[1] << 1) & 0x60); + + if (reg[1] & 0x40) { /* NROM */ + if (reg[1] & 0x80) { /* NROM-256 */ + setprg8(0x8000, (base & ~mask) | ((mmc3.reg[6] & ~0x02) & mask)); + setprg8(0xA000, (base & ~mask) | ((mmc3.reg[7] & ~0x02) & mask)); + setprg8(0xC000, (base & ~mask) | ((mmc3.reg[6] | 0x02) & mask)); + setprg8(0xE000, (base & ~mask) | ((mmc3.reg[7] | 0x02) & mask)); + } else { /* NROM-128 */ + setprg8(0x8000, (base & ~mask) | (mmc3.reg[6] & mask)); + setprg8(0xA000, (base & ~mask) | (mmc3.reg[7] & mask)); + setprg8(0xC000, (base & ~mask) | (mmc3.reg[6] & mask)); + setprg8(0xE000, (base & ~mask) | (mmc3.reg[7] & mask)); + } + } else { /* MMC3 */ + setprg8(A, (base & ~mask) | (V & mask)); + } +} + +static DECLFR(M432Read) { + if ((reg[0] & 0x01) || ((reg[1] & 0x20) && ((ROM.prg.size * 16) < 1024))) { + return dipsw; + } + return CartBR(A); +} + +static DECLFW(M432Write) { + if (MMC3_WramIsWritable()) { + reg[A & 0x01] = V; + if (!(A & 0x01) && !(V & 0x01) && ((ROM.prg.size * 16) < 1024)) { + reg[1] &= ~0x20; /* Writing 0 to register 0 clears register 1's DIP bit */ + } + MMC3_FixPRG(); + MMC3_FixCHR(); + } +} + +static void M432Reset(void) { + reg[0] = 0; + reg[1] = 0; + dipsw++; + MMC3_Reset(); +} + +static void M432Power(void) { + reg[0] = 0; + reg[1] = 0; + dipsw = 0; + MMC3_Power(); + SetReadHandler(0x8000, 0xFFFF, M432Read); + SetWriteHandler(0x6000, 0x7FFF, M432Write); +} + +void Mapper432_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_cwrap = M432CW; + MMC3_pwrap = M432PW; + info->Power = M432Power; + info->Reset = M432Reset; + AddExState(reg, 2, 0, "EXPR"); + AddExState(&dipsw, 1, 0, "CMD0"); +} diff --git a/src/boards/mapper433.c b/src/mappers/mapper433.c similarity index 75% rename from src/boards/mapper433.c rename to src/mappers/mapper433.c index 512ed9a36..e7e4ae67a 100644 --- a/src/boards/mapper433.c +++ b/src/mappers/mapper433.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -26,17 +26,19 @@ #include "latch.h" static void Sync(void) { - if (!(latch.data & 0x20)) - setprg32(0x8000, (latch.data & 0x1f) >> 1); - else { - setprg16(0x8000, (latch.data & 0x1f)); - setprg16(0xC000, (latch.data & 0x1f)); + uint8 prg = latch.data & 0x1F; + + if (latch.data & 0x20) { + setprg16(0x8000, prg); + setprg16(0xC000, prg); + } else { + setprg32(0x8000, prg >> 1); } - setmirror(((latch.data >> 6) & 1) ^ 1); + setmirror(((latch.data >> 6) & 0x01) ^ 0x01); setchr8(0); } void Mapper433_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); - info->Reset = LatchHardReset; + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Reset = Latch_RegReset; } diff --git a/src/boards/mapper434.c b/src/mappers/mapper434.c similarity index 74% rename from src/boards/mapper434.c rename to src/mappers/mapper434.c index 5874ecaa6..f2e1210ba 100644 --- a/src/boards/mapper434.c +++ b/src/mappers/mapper434.c @@ -1,9 +1,9 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2012 CaH4e3 * Copyright (C) 2002 Xodnizel - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -20,39 +20,39 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* S-009. UNROM plus outer bank register at $6000-$7FFF. */ +/* S-009. UNROM plus outerbank register at $6000-$7FFF. */ #include "mapinc.h" #include "latch.h" -static uint8 outer; +static uint8 reg; static void Sync(void) { - setprg16(0x8000, (outer << 3) | (latch.data & 7)); - setprg16(0xC000, (outer << 3) | 7); + setprg16(0x8000, (reg << 3) | (latch.data & 0x07)); + setprg16(0xC000, (reg << 3) | 0x07); setchr8(0); - setmirror((outer >> 5) & 1); + setmirror((reg >> 5) & 0x01); } static DECLFW(M434WriteOuterBank) { - outer = V; + reg = V; Sync(); } static void M434Reset(void) { - outer = 0; + reg = 0; Sync(); } static void M434Power(void) { - outer = 0; - LatchPower(); + reg = 0; + Latch_Power(); SetWriteHandler(0x6000, 0x7FFF, M434WriteOuterBank); } void Mapper434_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 1); + Latch_Init(info, Sync, NULL, FALSE, TRUE); info->Reset = M434Reset; info->Power = M434Power; - AddExState(&outer, 2, 0, "OUTB"); + AddExState(®, 1, 0, "REGS"); } diff --git a/src/mappers/mapper435.c b/src/mappers/mapper435.c new file mode 100644 index 000000000..779920a5f --- /dev/null +++ b/src/mappers/mapper435.c @@ -0,0 +1,53 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static void Sync(void) { + uint16 prg = ((latch.addr >> 4) & 0x40) | ((latch.addr >> 3) & 0x20) | ((latch.addr >> 2) & 0x1F); + + if (latch.addr & 0x200) { + if (latch.addr & 0x001) { + setprg16(0x8000, prg); + setprg16(0xC000, prg); + } else { + setprg32(0x8000, prg >> 1); + } + } else { + setprg16(0x8000, prg); + setprg16(0xC000, prg | 0x07); + } + + if (latch.addr & 0x800) { + SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0); + } else { + SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1); + } + + setmirror(((latch.addr >> 1) & 0x01) ^ 0x01); + setchr8(0); +} + +void Mapper435_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, TRUE, FALSE); + info->Reset = Latch_RegReset; +} diff --git a/src/boards/mapper436.c b/src/mappers/mapper436.c similarity index 52% rename from src/boards/mapper436.c rename to src/mappers/mapper436.c index be703e73d..6233ad5c9 100644 --- a/src/boards/mapper436.c +++ b/src/mappers/mapper436.c @@ -1,8 +1,9 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2008 CaH4e3 * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -24,39 +25,42 @@ #include "mapinc.h" #include "mmc3.h" -static void Mapper436_PWrap(uint32 A, uint8 V) { - if (mmc3.expregs[0] & 0x01) - setprg8(A, (V & 0x0F) | ((mmc3.expregs[0] >> 2) & 0x30)); - else if (A == 0x8000) - setprg32(A, (mmc3.expregs[0] >> 4)); +static uint8 reg; + +static void M436PW(uint32 A, uint8 V) { + if (reg & 0x01) { + setprg8(A, ((reg >> 2) & 0x30) | (V & 0x0F)); + } else { + setprg32(0x8000, (reg >> 4)); + } } -static void Mapper436_CWrap(uint32 A, uint8 V) { - setchr1(A, (V & 0x7F) | ((mmc3.expregs[0] << 1) & ~0x7F)); +static void M436CW(uint32 A, uint8 V) { + setchr1(A, ((reg << 1) & ~0x7F) | (V & 0x7F)); } -static DECLFW(Mapper436_Write) { - mmc3.expregs[0] = A & 0xFF; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); +static DECLFW(M436Write) { + reg = A & 0xFF; + MMC3_FixPRG(); + MMC3_FixCHR(); } -static void Mapper436_Reset(void) { - mmc3.expregs[0] = 0; - MMC3RegReset(); +static void M436Reset(void) { + reg = 0; + MMC3_Reset(); } -static void Mapper436_Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, Mapper436_Write); +static void M436Power(void) { + reg = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M436Write); } void Mapper436_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 128, 8, 0); - mmc3.pwrap = Mapper436_PWrap; - mmc3.cwrap = Mapper436_CWrap; - info->Power = Mapper436_Power; - info->Reset = Mapper436_Reset; - AddExState(mmc3.expregs, 1, 0, "EXPR"); + MMC3_Init(info, 8, 0); + MMC3_pwrap = M436PW; + MMC3_cwrap = M436CW; + info->Power = M436Power; + info->Reset = M436Reset; + AddExState(®, 1, 0, "EXPR"); } diff --git a/src/boards/mapper437.c b/src/mappers/mapper437.c similarity index 68% rename from src/boards/mapper437.c rename to src/mappers/mapper437.c index e3abedd5f..70c2cc1da 100644 --- a/src/boards/mapper437.c +++ b/src/mappers/mapper437.c @@ -1,9 +1,9 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2012 CaH4e3 * Copyright (C) 2002 Xodnizel - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -20,39 +20,39 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* NTDEC TH2348 circuit board. UNROM plus outer bank register at $5FFx. */ +/* NTDEC TH2348 circuit board. UNROM plus reg bank register at $5FFx. */ #include "mapinc.h" #include "latch.h" -static uint8 outer; +static uint8 reg; static void Sync(void) { - setprg16(0x8000, (outer << 3) | (latch.data & 7)); - setprg16(0xC000, (outer << 3) | 7); + setprg16(0x8000, (reg << 3) | (latch.data & 0x07)); + setprg16(0xC000, (reg << 3) | 0x07); setchr8(0); - setmirror(((outer >> 3) & 1) ^ 1); + setmirror(((reg >> 3) & 0x01) ^ 0x01); } -static DECLFW(M437_WriteOuterBank) { - outer = A; +static DECLFW(M437Write) { + reg = A & 0x0F; Sync(); } static void M437_Reset(void) { - outer = 0; + reg = 0; Sync(); } static void M437_Power(void) { - outer = 0; - LatchPower(); - SetWriteHandler(0x5000, 0x5FFF, M437_WriteOuterBank); + reg = 0; + Latch_Power(); + SetWriteHandler(0x5000, 0x5FFF, M437Write); } void Mapper437_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 1); + Latch_Init(info, Sync, NULL, FALSE, TRUE); info->Reset = M437_Reset; info->Power = M437_Power; - AddExState(&outer, 1, 0, "OUTB"); + AddExState(®, 1, 0, "OUTB"); } diff --git a/src/mappers/mapper438.c b/src/mappers/mapper438.c new file mode 100644 index 000000000..a8be1301c --- /dev/null +++ b/src/mappers/mapper438.c @@ -0,0 +1,46 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2012 CaH4e3 + * Copyright (C) 2002 Xodnizel + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* K-3071 */ + +#include "mapinc.h" +#include "latch.h" + +static void Sync(void) { + uint16 prg = latch.addr >> 1; + uint16 chr = latch.data >> 1; + uint16 mirr = (latch.data & 0x01) ^ 0x01; + + if (latch.addr & 1) + setprg32(0x8000, prg >> 1); + else { + setprg16(0x8000, prg); + setprg16(0xC000, prg); + } + setchr8(chr); + setmirror(mirr); +} + +void Mapper438_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Reset = Latch_RegReset; +} diff --git a/src/boards/mapper439.c b/src/mappers/mapper439.c similarity index 66% rename from src/boards/mapper439.c rename to src/mappers/mapper439.c index f1547df8d..eb3885762 100644 --- a/src/boards/mapper439.c +++ b/src/mappers/mapper439.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -28,40 +28,38 @@ static uint8 reg[2]; static void Sync(void) { - setprg16(0x8000, ((reg[0] >> 1) & ~7) | (latch.data & 7)); - setprg16(0xC000, ((reg[0] >> 1) & ~7) | 7); + uint8 mask = ((~reg[1] >> 1) & 0x38) | 0x07; + uint8 base = reg[0] >> 1; + setprg16(0x8000, (base & ~mask) | (latch.data & mask)); + setprg16(0xC000, (base & ~mask) | (0x3F & mask)); setchr8(0); - setmirror(((latch.data >> 7) & 1) ^ 1); + setmirror(((latch.data >> 7) & 0x01) ^ 0x01); } static DECLFW(M439WriteReg) { - reg[A & 1] = V; + reg[A & 0x01] = V; Sync(); } static DECLFW(M439WriteLatch) { - if (!(reg[0] & 0x80)) { - latch.data = (latch.data & ~7) | (V & 7); - } else { - latch.data = V; - } - Sync(); + uint8 mask = (reg[1] & 0x80) | ((reg[1] >> 1) & 0x38); + Latch_Write(A, (V & ~mask) | (latch.data & mask)); } -static void M439Reset() { - reg[0] = reg[1] = ~0; - LatchHardReset(); +static void M439Reset(void) { + reg[0] = reg[1] = 0; + Latch_RegReset(); } -static void M439Power() { - reg[0] = reg[1] = ~0; - LatchPower(); +static void M439Power(void) { + reg[0] = reg[1] = 0; + Latch_Power(); SetWriteHandler(0x6000, 0x7FFF, M439WriteReg); SetWriteHandler(0x8000, 0xFFFF, M439WriteLatch); } void Mapper439_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 1); + Latch_Init(info, Sync, NULL, FALSE, FALSE); info->Power = M439Power; info->Reset = M439Reset; AddExState(reg, 2, 0, "REGS"); diff --git a/src/boards/mapper441.c b/src/mappers/mapper441.c similarity index 54% rename from src/boards/mapper441.c rename to src/mappers/mapper441.c index eb6f2a751..a6a948390 100644 --- a/src/boards/mapper441.c +++ b/src/mappers/mapper441.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -23,50 +23,55 @@ #include "mapinc.h" #include "mmc3.h" +static uint8 reg; + static void M441PW(uint32 A, uint8 V) { - uint8 prgAND = (mmc3.expregs[0] & 0x08) ? 0x0F : 0x1F; - uint8 prgOR = (mmc3.expregs[0] << 4) & 0x30; - if (mmc3.expregs[0] & 0x04) { - setprg8(0x8000, (prgOR & ~prgAND) | ((mmc3.regs[6] & ~0x02) & prgAND)); - setprg8(0xA000, (prgOR & ~prgAND) | ((mmc3.regs[7] & ~0x02) & prgAND)); - setprg8(0xC000, (prgOR & ~prgAND) | ((mmc3.regs[6] | 0x02) & prgAND)); - setprg8(0xE000, (prgOR & ~prgAND) | ((mmc3.regs[7] | 0x02) & prgAND)); - } else - setprg8(A, (prgOR & ~prgAND) | (V & prgAND)); + uint8 mask = (reg & 0x08) ? 0x0F : 0x1F; + uint8 base = (reg << 4) & 0x30; + + if (reg & 0x04) { + setprg8(0x8000, (base & ~mask) | ((mmc3.reg[6] & ~0x02) & mask)); + setprg8(0xA000, (base & ~mask) | ((mmc3.reg[7] & ~0x02) & mask)); + setprg8(0xC000, (base & ~mask) | ((mmc3.reg[6] | 0x02) & mask)); + setprg8(0xE000, (base & ~mask) | ((mmc3.reg[7] | 0x02) & mask)); + } else { + setprg8(A, (base & ~mask) | (V & mask)); + } } static void M441CW(uint32 A, uint8 V) { - uint16 chrAND = (mmc3.expregs[0] & 0x40) ? 0x7F : 0xFF; - uint16 chrOR = (mmc3.expregs[0] << 3) & 0x180; - setchr1(A, (chrOR & ~chrAND) | (V & chrAND)); + uint16 mask = (reg & 0x40) ? 0x7F : 0xFF; + uint16 base = (reg << 3) & 0x180; + + setchr1(A, (base & ~mask) | (V & mask)); } static DECLFW(M441Write) { - if (MMC3CanWriteToWRAM()) { - if (~mmc3.expregs[0] & 0x80) { - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + if (MMC3_WramIsWritable()) { + if (!(reg & 0x80)) { + reg = V; + MMC3_FixPRG(); + MMC3_FixCHR(); } } } static void M441Reset(void) { - mmc3.expregs[0] = 0; - MMC3RegReset(); + reg = 0; + MMC3_Reset(); } static void M441Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); + reg = 0; + MMC3_Power(); SetWriteHandler(0x6000, 0x7FFF, M441Write); } void Mapper441_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 0, 0); - mmc3.cwrap = M441CW; - mmc3.pwrap = M441PW; + MMC3_Init(info, 0, 0); + MMC3_cwrap = M441CW; + MMC3_pwrap = M441PW; info->Power = M441Power; info->Reset = M441Reset; - AddExState(mmc3.expregs, 1, 0, "EXPR"); + AddExState(®, 1, 0, "EXPR"); } diff --git a/src/mappers/mapper443.c b/src/mappers/mapper443.c new file mode 100644 index 000000000..7c5cdbad2 --- /dev/null +++ b/src/mappers/mapper443.c @@ -0,0 +1,84 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2022 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* NC3000M PCB */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 reg; +static uint8 dipsw; + +static void M443PW(uint32 A, uint8 V) { + uint8 mask = 0x0F; + uint8 base = ((reg << 4) & 0x20) | (reg & 0x10); + + if (reg & 0x04) { /* NROM */ + uint16 bank = (base & ~mask) | (mmc3.reg[6] & mask); + if (reg & 0x08) { /* NROM-128 */ + setprg16(0x8000, bank >> 1); + setprg16(0xC000, bank >> 1); + } else { /* NROM-256 */ + setprg32(0x8000, bank >> 2); + } + } else { /* MMC3 */ + setprg8(A, (base & ~mask) | (V & mask)); + } +} + +static void M443CW(uint32 A, uint8 V) { + setchr1(A, ((reg << 8) & ~0xFF) | (V & 0xFF)); +} + +static DECLFR(M443Read) { + return (((reg & 0x0C) == 0x08) ? dipsw : CartBR(A)); +} + +static DECLFW(M443Write) { + reg = A & 0xFF; + MMC3_FixPRG(); + MMC3_FixCHR(); +} + +static void M443Reset(void) { + dipsw++; + dipsw &= 15; + reg = 0; + MMC3_Reset(); +} + +static void M443Power(void) { + dipsw = 0; + reg = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M443Write); + SetReadHandler(0x8000, 0xFFFF, M443Read); +} + +void Mapper443_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_cwrap = M443CW; + MMC3_pwrap = M443PW; + info->Power = M443Power; + info->Reset = M443Reset; + AddExState(®, 1, 0, "EXPR"); + AddExState(&dipsw, 1, 0, "DIPS"); +} diff --git a/src/mappers/mapper444.c b/src/mappers/mapper444.c new file mode 100644 index 000000000..69abc8d44 --- /dev/null +++ b/src/mappers/mapper444.c @@ -0,0 +1,92 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* NC7000M PCB, with incorrect UNIF MAPR BS-110 due to a mix-up. Submapper bits 0 and 1. denote the setting of two + * solder info->submapper that configure CHR banking. */ +/* NC8000M PCB, indicated by submapper bit 2. */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 reg; +static uint8 dipsw; + +static void M444PW(uint32 A, uint8 V) { + uint16 mask = ((iNESCart.submapper & 0x04) && (reg & 0x02)) ? 0x1F : 0x0F; + uint16 base = reg << 4; + + if (reg & 0x04) { /* NROM */ + uint16 bank = (base & ~mask) | (mmc3.reg[6] & mask); + if (reg & 0x08) { /* NROM-128 */ + setprg16(0x8000, bank >> 1); + setprg16(0xC000, bank >> 1); + } else { /* NROM-256 */ + setprg32(0x8000, bank >> 2); + } + } else { /* MMC3 */ + setprg8(A, (base & ~mask) | (V & mask)); + } +} + +static void M444CW(uint32 A, uint8 V) { + uint16 mask = (iNESCart.submapper & 0x01) ? 0xFF : 0x7F; + uint16 base = ((reg << 7) & ((iNESCart.submapper & 0x01) ? 0x00 : 0x80)) | ((reg << ((iNESCart.submapper & 0x02) ? 4 : 7)) & 0x100); + + setchr1(A, (base & ~mask) | (V & mask)); +} + +static DECLFR(M444Read) { + if ((reg & 0x0C) == 0x08) { + return dipsw; + } + return CartBR(A); +} + +static DECLFW(M444Write) { + reg = A & 0xFF; + MMC3_FixPRG(); + MMC3_FixCHR(); +} + +static void M444Reset(void) { + dipsw++; + dipsw &= 3; + reg = 0; + MMC3_Reset(); +} + +static void M444Power(void) { + dipsw = 0; + reg = 0; + MMC3_Power(); + SetWriteHandler(0x6000, 0x7FFF, M444Write); + SetReadHandler(0x8000, 0xFFFF, M444Read); +} + +void Mapper444_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_cwrap = M444CW; + MMC3_pwrap = M444PW; + info->Power = M444Power; + info->Reset = M444Reset; + AddExState(®, 1, 0, "EXPR"); + AddExState(&dipsw, 1, 0, "DIPS"); +} diff --git a/src/boards/mapper445.c b/src/mappers/mapper445.c similarity index 60% rename from src/boards/mapper445.c rename to src/mappers/mapper445.c index 8b3108815..3849c80c3 100644 --- a/src/boards/mapper445.c +++ b/src/mappers/mapper445.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,46 +25,52 @@ #include "mapinc.h" #include "mmc3.h" +static uint8 reg[4]; + static void M445PW(uint32 A, uint8 V) { - uint8 mask = (mmc3.expregs[2] & 0x01) ? 0x0F : 0x1F; - setprg8(A, (mmc3.expregs[0] & ~mask) | (V & mask)); + uint8 mask = (reg[2] & 0x01) ? 0x0F : 0x1F; + uint8 base = reg[0]; + + setprg8(A, (base & ~mask) | (V & mask)); } static void M445CW(uint32 A, uint8 V) { - uint8 mask = (mmc3.expregs[2] & 0x08) ? 0x7F : 0xFF; - setchr1(A, ((mmc3.expregs[1] << 3) & ~mask) | (V & mask)); + uint16 mask = (reg[2] & 0x08) ? 0x7F : 0xFF; + uint16 base = reg[1] << 3; + + setchr1(A, (base & ~mask) | (V & mask)); } static DECLFW(M445Write) { - if (!(mmc3.expregs[3] & 0x20)) { - mmc3.expregs[A & 0x03] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + if (!(reg[3] & 0x20)) { + reg[A & 0x03] = V; + MMC3_FixPRG(); + MMC3_FixCHR(); } } static void M445Reset(void) { - mmc3.expregs[0] = 0x00; - mmc3.expregs[1] = 0x00; - mmc3.expregs[2] = 0x00; - mmc3.expregs[3] = 0x00; - MMC3RegReset(); + reg[0] = 0x00; + reg[1] = 0x00; + reg[2] = 0x00; + reg[3] = 0x00; + MMC3_Reset(); } static void M445Power(void) { - mmc3.expregs[0] = 0x00; - mmc3.expregs[1] = 0x00; - mmc3.expregs[2] = 0x00; - mmc3.expregs[3] = 0x00; - GenMMC3Power(); + reg[0] = 0x00; + reg[1] = 0x00; + reg[2] = 0x00; + reg[3] = 0x00; + MMC3_Power(); SetWriteHandler(0x5000, 0x5FFF, M445Write); } void Mapper445_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 512, info->PRGRamSize + info->PRGRamSaveSize, info->battery); - mmc3.pwrap = M445PW; - mmc3.cwrap = M445CW; + MMC3_Init(info, info->PRGRamSize + info->PRGRamSaveSize, info->battery); + MMC3_pwrap = M445PW; + MMC3_cwrap = M445CW; info->Power = M445Power; info->Reset = M445Reset; - AddExState(mmc3.expregs, 4, 0, "EXPR"); + AddExState(reg, 4, 0, "EXPR"); } diff --git a/src/mappers/mapper446.c b/src/mappers/mapper446.c new file mode 100644 index 000000000..03fd66d71 --- /dev/null +++ b/src/mappers/mapper446.c @@ -0,0 +1,466 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" +#include "mmc1.h" +#include "mmc3.h" +#include "vrc2and4.h" +#include "vrc6.h" +#include "flashrom.h" + +#define MAPPER_UNROM 0x00 +#define MAPPER_MMC3 0x01 +#define MAPPER_NROM 0x02 +#define MAPPER_CNROM 0x03 +#define MAPPER_ANROM 0x04 +#define MAPPER_SLROM 0x05 +#define MAPPER_SNROM 0x06 +#define MAPPER_SUROM 0x07 +#define MAPPER_GNROM 0x08 +#define MAPPER_PNROM 0x09 +#define MAPPER_HKROM 0x0A +#define MAPPER_BANDAI152 0x0B +#define MAPPER_TLSROM 0x0E +#define MAPPER_189 0x0F +#define MAPPER_VRC6 0x10 +#define MAPPER_VRC2_22 0x12 +#define MAPPER_VRC4_25 0x15 +#define MAPPER_VRC4_23 0x18 +#define MAPPER_VRC1 0x1A + +#define WRAM_CHIP 0x10 +#define FLASH_CHIP 0x11 + +static uint8 *flash = NULL; +static uint8_t reg[8], latch189, mapper; + +static SFORMAT StateRegs[] = { + { reg, 8, "REGS" }, + { &mapper, 1, "MAPR" }, + { &latch189, 1, "L189" }, + { 0 } +}; + +static uint32 GetPRGBase(void) { + return ((reg[2] << 8) | reg[1]); +} + +static uint32 GetPRGMask(void) { + return (~reg[3]); +} + +static uint32 GetCHRBase(void) { + return reg[6]; +} + +static void M446PW_mmc1(uint32 A, uint8 V) { + setprg16r(FLASH_CHIP, A, (GetPRGBase() >> 1) | (V & (GetPRGMask() >> 1))); +} +static void M446CW_mmc1(uint32 A, uint8 V) { + setchr4(A, (GetCHRBase() >> 2) | (V & 0x1F)); +} + +static void M446PW_mmc3(uint32 A, uint8 V) { + switch (mapper) { + case MAPPER_MMC3: + case MAPPER_TLSROM: + setprg8r(FLASH_CHIP, A, GetPRGBase() | (V & GetPRGMask())); + break; + case MAPPER_189: + setprg32r(FLASH_CHIP, 0x8000, (GetPRGBase() >> 2) | (latch189 & 0x03)); + break; + } +} +static void M446CW_mmc3(uint32 A, uint8 V) { + switch (mapper) { + case MAPPER_TLSROM: + setchr1(A, GetCHRBase() | (V & 0x7F)); + break; + case MAPPER_MMC3: + case MAPPER_189: + setchr1(A, GetCHRBase() | (V & 0xFF)); + break; + } +} + +static void M446PW_vrc24(uint32 A, uint8 V) { + switch (mapper) { + case MAPPER_VRC2_22: + case MAPPER_VRC4_23: + case MAPPER_VRC4_25: + setprg8r(FLASH_CHIP, A, GetPRGBase() | (V & GetPRGMask())); + break; + } +} +static void M446CW_vrc24(uint32 A, uint32 V) { + int i; + switch (mapper) { + case MAPPER_VRC2_22: + for (i = 0; i < 8; i++) setchr1(i << 10, vrc24.chr[i] >> 1); + break; + case MAPPER_VRC4_23: + case MAPPER_VRC4_25: + setchr1(A, V & 0xFF); + break; + } +} + +static void M446PW_vrc6(uint32 A, uint8 V) { + setprg8r(FLASH_CHIP, A, GetPRGBase() | (V & GetPRGMask())); +} +static void M446CW_vrc6(uint32 A, uint8 V) { + setchr1(A, V & 0xFF); +} + +static void Sync(void) { + if (reg[0] & 0x80) { + switch (mapper) { + case MAPPER_NROM: + setprg8r(FLASH_CHIP, 0x8000, GetPRGBase() | (0x00 & GetPRGMask())); + setprg8r(FLASH_CHIP, 0xA000, GetPRGBase() | (0x01 & GetPRGMask())); + setprg8r(FLASH_CHIP, 0xC000, GetPRGBase() | (0x02 & GetPRGMask())); + setprg8r(FLASH_CHIP, 0xE000, GetPRGBase() | (0x03 & GetPRGMask())); + setchr8(GetCHRBase()); + setmirror(reg[4] & 0x01); + break; + case MAPPER_CNROM: + setprg8r(FLASH_CHIP, 0x8000, GetPRGBase() | (0x00 & GetPRGMask())); + setprg8r(FLASH_CHIP, 0xA000, GetPRGBase() | (0x01 & GetPRGMask())); + setprg8r(FLASH_CHIP, 0xC000, GetPRGBase() | (0x02 & GetPRGMask())); + setprg8r(FLASH_CHIP, 0xE000, GetPRGBase() | (0x03 & GetPRGMask())); + setchr8(latch.data & 3); + setmirror(reg[4] & 0x01); + break; + case MAPPER_UNROM: + setprg16r(FLASH_CHIP, 0x8000, (GetPRGBase() >> 1) | (latch.data & (GetPRGMask() >> 1))); + setprg16r(FLASH_CHIP, 0xC000, (GetPRGBase() >> 1) | ((GetPRGMask() >> 1) & 0x1F)); + setchr8(GetCHRBase()); + setmirror(reg[4] & 0x01); + break; + case MAPPER_BANDAI152: + setprg16r(FLASH_CHIP, 0x8000, (GetPRGBase() >> 1) | ((latch.data >> 4) & (GetPRGMask() >> 1))); + setprg16r(FLASH_CHIP, 0xC000, (GetPRGBase() >> 1) | (0xFF & (GetPRGMask() >> 1))); + setchr8(latch.data & 0xF); + setmirror(MI_0 + ((latch.data & 0x80) >> 7)); + break; + case MAPPER_ANROM: + setprg32r(FLASH_CHIP, 0x8000, (GetPRGBase() >> 2) | (latch.data & (GetPRGMask() >> 2))); + setchr8(GetCHRBase()); + setmirror(MI_0 + ((latch.data & 0x10) >> 4)); + break; + case MAPPER_GNROM: + setprg32r(FLASH_CHIP, 0x8000, (GetPRGBase() >> 2) | ((latch.data >> 4) & (GetPRGMask() >> 2))); + setchr8(latch.data & 0x03); + setmirror(reg[4] & 0x01); + break; + + case MAPPER_SLROM: + case MAPPER_SNROM: + setprg8r(WRAM_CHIP, 0x6000, 0); + MMC1_FixPRG(); + MMC1_FixCHR(); + MMC1_FixMIR(); + break; + + case MAPPER_MMC3: + setprg8r(WRAM_CHIP, 0x6000, 0); + MMC3_FixPRG(); + MMC3_FixCHR(); + MMC3_FixMIR(); + break; + case MAPPER_TLSROM: + setprg8r(WRAM_CHIP, 0x6000, 0); + MMC3_FixPRG(); + MMC3_FixCHR(); + if (mmc3.cmd & 0x80) { + setntamem(NTARAM + 0x400 * ((mmc3.reg[2] >> 7) & 0x01), 1, 0); + setntamem(NTARAM + 0x400 * ((mmc3.reg[3] >> 7) & 0x01), 1, 1); + setntamem(NTARAM + 0x400 * ((mmc3.reg[4] >> 7) & 0x01), 1, 2); + setntamem(NTARAM + 0x400 * ((mmc3.reg[5] >> 7) & 0x01), 1, 3); + } else { + setntamem(NTARAM + 0x400 * ((mmc3.reg[0] >> 7) & 0x01), 1, 0); + setntamem(NTARAM + 0x400 * ((mmc3.reg[0] >> 7) & 0x01), 1, 1); + setntamem(NTARAM + 0x400 * ((mmc3.reg[1] >> 7) & 0x01), 1, 2); + setntamem(NTARAM + 0x400 * ((mmc3.reg[1] >> 7) & 0x01), 1, 3); + } + break; + case MAPPER_189: + setprg8r(WRAM_CHIP, 0x6000, 0); + MMC3_FixPRG(); + MMC3_FixCHR(); + MMC3_FixMIR(); + break; + + case MAPPER_VRC2_22: + setprg8r(WRAM_CHIP, 0x6000, 0); + VRC24_FixPRG(); + VRC24_FixCHR(); + VRC24_FixMIR(); + break; + case MAPPER_VRC4_23: + case MAPPER_VRC4_25: + setprg8r(WRAM_CHIP, 0x6000, 0); + VRC24_FixPRG(); + VRC24_FixCHR(); + VRC24_FixMIR(); + break; + + case MAPPER_VRC6: + setprg8r(WRAM_CHIP, 0x6000, 0); + VRC6_FixPRG(); + VRC6_FixCHR(); + break; + } + } else { + setprg8r(FLASH_CHIP, 0x8000, GetPRGBase()); + setprg8r(FLASH_CHIP, 0xA000, 0x3D); + setprg8r(FLASH_CHIP, 0xC000, 0x3E); + setprg8r(FLASH_CHIP, 0xE000, 0x3F); + setchr8(GetCHRBase()); + setmirror(reg[4] & 0x01); + } + + /* CHR-RAM Protect */ + SetupCartCHRMapping(0, CHRptr[0], CHRsize[0], (reg[5] & 0x04) ? 0 : 1); +} + +static void applyMode(void) { + if (reg[0] & 0x80) { + switch (mapper) { + case MAPPER_ANROM: + case MAPPER_CNROM: + case MAPPER_UNROM: + case MAPPER_GNROM: + case MAPPER_BANDAI152: + Latch_RegReset(); + break; + case MAPPER_SLROM: + case MAPPER_SNROM: + MMC1_Reset(); + break; + case MAPPER_189: + case MAPPER_MMC3: + case MAPPER_TLSROM: + MMC3_Reset(); + break; + case MAPPER_VRC2_22: + vrc2and4_VRC4 = FALSE; + vrc2and4_A0 = 0x02; + vrc2and4_A1 = 0x01; + VRC24_Reset(); + break; + case MAPPER_VRC4_23: + vrc2and4_VRC4 = TRUE; + vrc2and4_A0 = 0x05; + vrc2and4_A1 = 0x0A; + VRC24_Reset(); + break; + case MAPPER_VRC4_25: + vrc2and4_VRC4 = TRUE; + vrc2and4_A0 = 0x0A; + vrc2and4_A1 = 0x05; + VRC24_Reset(); + break; + case MAPPER_VRC6: + VRC6_Reset(); + break; + } + } +} + +static DECLFR(M446Read) { + return FlashROM_Read(A); +} + +static DECLFW(M446WriteLatch) { + if (mapper == MAPPER_189) { + latch189 = A & 0xFF; + Sync(); + } else { + CartBW(A, V); + } +} + +static DECLFW(M446WriteReg) { + A &= 0x07; + if (!A && !iNESCart.submapper && ((V & 0x1F) == 0x01)) { + V = (V & ~0x1F) | MAPPER_SNROM; + } + reg[A] = V; + if (reg[0] & 0x80) { + mapper = reg[0] & 0x1F; + applyMode(); + } + Sync(); +} + +static DECLFW(M446Write) { + if (reg[0] & 0x80) { + switch (mapper) { + case MAPPER_ANROM: + case MAPPER_CNROM: + case MAPPER_UNROM: + case MAPPER_GNROM: + case MAPPER_BANDAI152: + Latch_Write(A, V); + break; + case MAPPER_SLROM: + case MAPPER_SNROM: + MMC1_Write(A, V); + break; + case MAPPER_189: + case MAPPER_MMC3: + case MAPPER_TLSROM: + MMC3_Write(A, V); + break; + case MAPPER_VRC2_22: + VRC24_Write(A, V); + break; + case MAPPER_VRC4_23: + VRC24_Write(A, V); + break; + case MAPPER_VRC4_25: + VRC24_Write(A, V); + break; + case MAPPER_VRC6: + VRC6_Write(A, V); + break; + } + } else { + FlashROM_Write(A, V); + } +} + +static void M446HBIRQHook(void) { + if (reg[0] & 0x80) { + switch (mapper) { + case MAPPER_MMC3: + case MAPPER_TLSROM: + case MAPPER_189: + MMC3_IRQHBHook(); + break; + } + } +} + +static void M446CPUIRQHook(int a) { + FlashROM_CPUCyle(a); + if (reg[0] & 0x80) { + switch (mapper) { + case MAPPER_VRC2_22: + case MAPPER_VRC4_23: + case MAPPER_VRC4_25: + VRC24_IRQCPUHook(a); + break; + case MAPPER_VRC6: + VRC6_IRQCPUHook(a); + break; + } + } +} + +static void M446Close(void) { + if (WRAM) { + FCEU_free(WRAM); + WRAM = NULL; + } + if (flash) { + FCEU_free(flash); + flash = NULL; + } +} + +static void M446Reset(void) { + mapper = 0; + memset(reg, 0, sizeof(reg)); + applyMode(); + Sync(); +} + +static void M446Power(void) { + mapper = 0; + memset(reg, 0, sizeof(reg)); + + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetReadHandler(0x8000, 0xFFFF, M446Read); + + SetWriteHandler(0x5000, 0x5FFF, M446WriteReg); + SetWriteHandler(0x6000, 0x6FFF, M446WriteLatch); + SetWriteHandler(0x7000, 0x7FFF, CartBW); + SetWriteHandler(0x8000, 0xFFFF, M446Write); + + applyMode(); + Sync(); +} + +static void StateRestore(int version) { + applyMode(); + Sync(); +} + +void Mapper446_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + + MMC1_Init(info, FALSE, FALSE); + MMC1_pwrap = M446PW_mmc1; + MMC1_cwrap = M446CW_mmc1; + + MMC3_Init(info, FALSE, FALSE); + MMC3_pwrap = M446PW_mmc3; + MMC3_cwrap = M446CW_mmc3; + + VRC24_Init(info, true, 0x01, 0x02, FALSE, TRUE); + VRC24_pwrap = M446PW_vrc24; + VRC24_cwrap = M446CW_vrc24; + + VRC6_Init(info, 0x01, 0x02, FALSE); + VRC6_pwrap = M446PW_vrc6; + VRC6_cwrap = M446CW_vrc6; + + info->Power = M446Power; + info->Reset = M446Reset; + info->Close = M446Close; + + MapIRQHook = M446CPUIRQHook; + GameHBIRQHook = M446HBIRQHook; + + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + + WRAMSIZE = info->PRGRamSize + info->PRGRamSaveSize; + if (WRAMSIZE) { + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(WRAM_CHIP, WRAM, WRAMSIZE, TRUE); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + } + + /* Allocate memory for flash */ + flash = (uint8 *)FCEU_gmalloc(PRGsize[0]); + SetupCartPRGMapping(FLASH_CHIP, flash, PRGsize[0], 0); + AddExState(flash, PRGsize[0], 0, "FLSH"); + memcpy(flash, PRGptr[0], PRGsize[0]); + FlashROM_Init(flash, PRGsize[0], 0x01, 0x7E, 131072, 0xAAA, 0x555); +} diff --git a/src/boards/mapper447.c b/src/mappers/mapper447.c similarity index 57% rename from src/boards/mapper447.c rename to src/mappers/mapper447.c index ad5be3fb9..3f264ed72 100644 --- a/src/boards/mapper447.c +++ b/src/mappers/mapper447.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -23,65 +23,72 @@ */ #include "mapinc.h" -#include "vrc24.h" +#include "vrc2and4.h" static uint8 reg; +static uint8 dipsw; static SFORMAT StateRegs[] = { - { ®, 1, "OUTB" }, + { ®, 1, "REGS" }, + { &dipsw, 1, "DPSW" }, { 0 }, }; static void M447PW(uint32 A, uint8 V) { - if (reg & 0x04) { - if (reg & 2) { - /* NROM-128 */ - setprg8(0x8000, (reg << 4) | (vrc24.prgreg[0] & 0x0F)); - setprg8(0xA000, (reg << 4) | (vrc24.prgreg[1] & 0x0F)); - setprg8(0xC000, (reg << 4) | (vrc24.prgreg[0] & 0x0F)); - setprg8(0xE000, (reg << 4) | (vrc24.prgreg[1] & 0x0F)); - } else { - /* NROM-256 */ - setprg8(0x8000, (reg << 4) | ((vrc24.prgreg[0] & ~0x02) & 0x0F)); - setprg8(0xA000, (reg << 4) | ((vrc24.prgreg[1] & ~0x02) & 0x0F)); - setprg8(0xC000, (reg << 4) | ((vrc24.prgreg[0] | 0x02) & 0x0F)); - setprg8(0xE000, (reg << 4) | ((vrc24.prgreg[1] | 0x02) & 0x0F)); - } - } else { - setprg8(A, (reg << 4) | (V & 0x0F)); - } + uint16 mask = 0x0F; + uint16 base = reg << 4; + + if (reg & 0x04) { + uint8 A14 = (reg & 0x02) ^ 0x02; + setprg8(0x8000, (base & ~mask) | ((vrc24.prg[0] & ~A14) & mask)); + setprg8(0xA000, (base & ~mask) | ((vrc24.prg[1] & ~A14) & mask)); + setprg8(0xC000, (base & ~mask) | ((vrc24.prg[0] | A14) & mask)); + setprg8(0xE000, (base & ~mask) | ((vrc24.prg[1] | A14) & mask)); + } else { + setprg8(A, (base & ~mask) | (V & mask)); + } } static void M447CW(uint32 A, uint32 V) { setchr1(A, (reg << 7) | (V & 0x7F)); } +static DECLFR(M447Read) { + if ((A & 0x8000) && (reg & 0x08)) { + return CartBR((A & ~0x03) | (dipsw & 0x03)); + } + return CartBR(A); +} + static DECLFW(M447WriteReg) { CartBW(A, V); if ((vrc24.cmd & 0x01) && !(reg & 0x01)) { reg = A & 0xFF; - FixVRC24PRG(); - FixVRC24CHR(); + VRC24_FixPRG(); + VRC24_FixCHR(); } } static void M447Reset(void) { reg = 0; - FixVRC24PRG(); - FixVRC24CHR(); + dipsw++; + VRC24_FixPRG(); + VRC24_FixCHR(); } static void M447Power(void) { reg = 0; - GenVRC24Power(); + dipsw = 0; + VRC24_Power(); + SetReadHandler(0x8000, 0xFFFF, M447Read); SetWriteHandler(0x6000, 0x7FFF, M447WriteReg); } void Mapper447_Init(CartInfo *info) { - GenVRC24_Init(info, VRC4e, 1); + VRC24_Init(info, VRC4, 0x04, 0x08, 1, 1); info->Reset = M447Reset; info->Power = M447Power; - vrc24.pwrap = M447PW; - vrc24.cwrap = M447CW; - AddExState(StateRegs, ~0, 0, 0); + VRC24_pwrap = M447PW; + VRC24_cwrap = M447CW; + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper448.c b/src/mappers/mapper448.c similarity index 78% rename from src/boards/mapper448.c rename to src/mappers/mapper448.c index 6daf59dda..452351337 100644 --- a/src/boards/mapper448.c +++ b/src/mappers/mapper448.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -24,7 +24,7 @@ #include "mapinc.h" #include "latch.h" -#include "vrc24.h" +#include "vrc2and4.h" static uint8 reg; @@ -34,16 +34,15 @@ static SFORMAT StateRegs[] = { }; static void Sync(void) { - setchr8(0); if (reg & 0x08) { /* AOROM */ setprg32(0x8000, ((reg << 2) & ~0x07) | (latch.data & 0x07)); setmirror(MI_0 + ((latch.data >> 4) & 0x01)); } else { if (reg & 0x04) { /* UOROM */ - setprg16(0x8000, ((reg << 3) & ~0x0F) | (vrc24.prgreg[0] & 0x0F)); + setprg16(0x8000, ((reg << 3) & ~0x0F) | (vrc24.prg[0] & 0x0F)); setprg16(0xC000, ((reg << 3) & ~0x0F) | 0x0F); } else { /* UNROM */ - setprg16(0x8000, (reg << 3) | (vrc24.prgreg[0] & 0x07)); + setprg16(0x8000, (reg << 3) | (vrc24.prg[0] & 0x07)); setprg16(0xC000, (reg << 3) | 0x07); } switch (vrc24.mirr & 0x03) { @@ -53,18 +52,19 @@ static void Sync(void) { case 3: setmirror(MI_1); break; } } + setchr8(0); } static DECLFW(M448WriteReg) { - if (vrc24.cmd & 1) { + if (vrc24.cmd & 0x01) { reg = A & 0xFF; Sync(); } } -static DECLFW(M448Write) { - LatchWrite(A, V); - VRC24Write(A, V); +static DECLFW(M448WriteASIC) { + Latch_Write(A, V); + VRC24_Write(A, V); Sync(); } @@ -75,13 +75,13 @@ static void M448Reset(void) { static void M448Power(void) { reg = 0; - LatchPower(); - GenVRC24Power(); + Latch_Power(); + VRC24_Power(); Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, M448WriteReg); - SetWriteHandler(0x8000, 0xFFFF, M448Write); + SetWriteHandler(0x8000, 0xFFFF, M448WriteASIC); } static void StateRestore(int version) { @@ -89,10 +89,10 @@ static void StateRestore(int version) { } void Mapper448_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); - GenVRC24_Init(info, VRC4e, 0); + Latch_Init(info, Sync, NULL, FALSE, FALSE); + VRC24_Init(info, VRC4, 0x04, 0x08, 0, 1); info->Reset = M448Reset; info->Power = M448Power; GameStateRestore = StateRestore; - AddExState(StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper449.c b/src/mappers/mapper449.c similarity index 64% rename from src/boards/mapper449.c rename to src/mappers/mapper449.c index 22e276ada..43943dd34 100644 --- a/src/boards/mapper449.c +++ b/src/mappers/mapper449.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,44 +21,39 @@ #include "mapinc.h" #include "latch.h" -static uint8 dipswitch; +static uint8 dipsw; static SFORMAT StateRegs[] = { - { &dipswitch, 1, "DIPS" }, + { &dipsw, 1, "DPSW" }, { 0 } }; static void Sync(void) { - uint8 prgbank = ((latch.addr >> 2) & 0x1F) | ((latch.addr >> 3) & 0x20); - if (~latch.addr & 0x080) { - setprg16(0x8000, prgbank); - setprg16(0xC000, prgbank | 7); - } else { - if (latch.addr & 0x001) { - setprg32(0x8000, prgbank >> 1); - } else { - setprg16(0x8000, prgbank); - setprg16(0xC000, prgbank); - } - } + uint32 prg = ((latch.addr >> 3) & 0x20) | ((latch.addr >> 2) & 0x1F); + uint32 cpuA14 = latch.addr & 0x01; + uint32 nrom = (latch.addr >> 7) & 0x01; + + setprg16(0x8000, prg & ~(cpuA14 * nrom)); + setprg16(0xC000, prg | (cpuA14 * nrom) | (0x07 * !nrom)); + setchr8(latch.data); - setmirror((((latch.addr >> 1) & 1) ^ 1)); + setmirror((((latch.addr >> 1) & 0x01) ^ 0x01)); } static DECLFR(M449Read) { if (latch.addr & 0x200) { - return CartBR(A | dipswitch); + A |= dipsw; } return CartBR(A); } static void M449Reset(void) { - dipswitch = (dipswitch + 1) & 0xF; - LatchHardReset(); + dipsw = (dipsw + 1) & 0xF; + Latch_RegReset(); } void Mapper449_Init(CartInfo *info) { - Latch_Init(info, Sync, M449Read, 0, 0); + Latch_Init(info, Sync, M449Read, FALSE, FALSE); info->Reset = M449Reset; - AddExState(StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper450.c b/src/mappers/mapper450.c new file mode 100644 index 000000000..d02983a03 --- /dev/null +++ b/src/mappers/mapper450.c @@ -0,0 +1,39 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 450 - YY841157C + */ + +#include "mapinc.h" +#include "vrc2and4.h" + +static void M450PW(uint32 A, uint8 V) { + setprg8(A, (vrc24.latch << 4) | (V & 0x0F)); +} + +static void M450CW(uint32 A, uint32 V) { + setchr1(A, (vrc24.latch << 7) | (V & 0x7F)); +} + +void Mapper450_Init(CartInfo *info) { + VRC24_Init(info, VRC2, 0x01, 0x02, 0, 1); + VRC24_pwrap = M450PW; + VRC24_cwrap = M450CW; +} diff --git a/src/boards/mapper451.c b/src/mappers/mapper451.c similarity index 55% rename from src/boards/mapper451.c rename to src/mappers/mapper451.c index 05d617fd2..e1d471641 100644 --- a/src/boards/mapper451.c +++ b/src/mappers/mapper451.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,87 +25,87 @@ #include "mmc3.h" #include "flashrom.h" +static uint8 reg; + static uint8 *FLASHROM = NULL; static uint32 FLASHROM_size = 0; -static void M451PW(uint32 A, uint8 V) { - switch (A & 0xE000) { - case 0x8000: V = 0; break; - case 0xE000: V = 0x30; break; - default: V &= 0x3F; break; - } - setprg8r(0x10, A, V); +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; + +static void M451FixPRG(void) { + setprg8r(0x10, 0x8000, 0); + setprg8r(0x10, 0xA000, 0x10 | ((reg << 2) & 0x08) | (reg & 0x01)); + setprg8r(0x10, 0xC000, 0x20 | ((reg << 2) & 0x08) | (reg & 0x01)); + setprg8r(0x10, 0xE000, 0x30); +} + +static void M451FixCHR(void) { + setchr8(reg & 0x01); } -static DECLFR(M451FlashRead) { - return FlashRead(A); +static DECLFR(M451Read) { + return FlashROM_Read(A); } -static DECLFW(M451FlashWrite) { - FlashWrite(A, V); +static DECLFW(M451Write) { + FlashROM_Write(A, V); switch (A & 0xE000) { case 0xA000: - MMC3_CMDWrite(0xA000, A & 1); + MMC3_CMDWrite(0xA000, A & 0x01); break; case 0xC000: A &= 0xFF; MMC3_IRQWrite(0xC000, A - 1); MMC3_IRQWrite(0xC001, 0); - MMC3_IRQWrite(0xE000 + (A == 0xFF ? 0 : 1), 0); + MMC3_IRQWrite(0xE000 + ((A == 0xFF) ? 0x00 : 0x01), 0x00); break; case 0xE000: - A = ((A << 2) & 8) | (A & 1); - MMC3_CMDWrite(0x8000, 0x40); - MMC3_CMDWrite(0x8001, (A << 3) | 0); - MMC3_CMDWrite(0x8000, 0x41); - MMC3_CMDWrite(0x8001, (A << 3) | 2); - MMC3_CMDWrite(0x8000, 0x42); - MMC3_CMDWrite(0x8001, (A << 3) | 4); - MMC3_CMDWrite(0x8000, 0x43); - MMC3_CMDWrite(0x8001, (A << 3) | 5); - MMC3_CMDWrite(0x8000, 0x44); - MMC3_CMDWrite(0x8001, (A << 3) | 6); - MMC3_CMDWrite(0x8000, 0x45); - MMC3_CMDWrite(0x8001, (A << 3) | 7); - MMC3_CMDWrite(0x8000, 0x46); - MMC3_CMDWrite(0x8001, 0x20 | A); - MMC3_CMDWrite(0x8000, 0x47); - MMC3_CMDWrite(0x8001, 0x10 | A); + reg = A & 0x03; + MMC3_FixPRG(); + MMC3_FixCHR(); break; } } static void M451Power(void) { - GenMMC3Power(); - SetReadHandler(0x8000, 0xFFFF, M451FlashRead); - SetWriteHandler(0x8000, 0xFFFF, M451FlashWrite); + MMC3_Power(); + SetReadHandler(0x8000, 0xFFFF, M451Read); + SetWriteHandler(0x8000, 0xFFFF, M451Write); } -static void M451Close() { - GenMMC3Close(); - if (FLASHROM) +static void M451Close(void) { + MMC3_Close(); + if (FLASHROM) { FCEU_free(FLASHROM); + } FLASHROM = NULL; } void Mapper451_Init(CartInfo *info) { uint32 w, r; - GenMMC3_Init(info, 512, 256, 0, 0); + + MMC3_Init(info, 0, 0); info->Power = M451Power; info->Close = M451Close; - mmc3.pwrap = M451PW; - MapIRQHook = FlashCPUHook; + MMC3_FixPRG = M451FixPRG; + MMC3_FixCHR = M451FixCHR; + MapIRQHook = FlashROM_CPUCyle; + AddExState(StateRegs, ~0, 0, NULL); + info->battery = 1; FLASHROM_size = PRGsize[0]; FLASHROM = (uint8 *)FCEU_gmalloc(FLASHROM_size); info->SaveGame[0] = FLASHROM; info->SaveGameLen[0] = FLASHROM_size; - AddExState(FLASHROM, FLASHROM_size, 0, "FROM"); + AddExState(FLASHROM, FLASHROM_size, 0, "FLAS"); /* copy PRG ROM into FLASHROM, use it instead of PRG ROM */ for (w = 0, r = 0; w < FLASHROM_size; w++) { FLASHROM[w] = PRGptr[0][r]; ++r; } SetupCartPRGMapping(0x10, FLASHROM, FLASHROM_size, 0); - Flash_Init(FLASHROM, FLASHROM_size, 0x37, 0x86, 65536, 0x0555, 0x02AA); + FlashROM_Init(FLASHROM, FLASHROM_size, 0x37, 0x86, 65536, 0x0555, 0x02AA); } diff --git a/src/boards/mapper452.c b/src/mappers/mapper452.c similarity index 58% rename from src/boards/mapper452.c rename to src/mappers/mapper452.c index fc29152fa..b42fd992a 100644 --- a/src/boards/mapper452.c +++ b/src/mappers/mapper452.c @@ -1,9 +1,9 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2012 CaH4e3 * Copyright (C) 2002 Xodnizel - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -26,38 +26,55 @@ #include "latch.h" static void Sync(void) { - uint8 wramBank = ((latch.data >> 3) & 6) | 8; uint16 prgbank = latch.addr >> 1; - if (latch.data & 2) { + uint16 prgram_addr = 0x8000 | ((latch.data << 9) & 0x6000); + + if (latch.data & 0x02) { setprg8(0x8000, prgbank); setprg8(0xA000, prgbank); setprg8(0xC000, prgbank); setprg8(0xE000, prgbank); - setprg8r(0x10, (wramBank ^ 4) << 12, 0); - } else if (latch.data & 8) { - setprg8(0x8000, (prgbank & ~1) | 0); - setprg8(0xA000, (prgbank & ~1) | 1); - setprg8(0xC000, (prgbank & ~1) | 2); - setprg8(0xE000, 3 | (prgbank & ~1) - | (latch.data & 4) - | ((latch.data & 0x04) - && (latch.data & 0x40) ? 8 : 0)); + } else if (latch.data & 0x08) { + setprg8(0x8000, (prgbank & ~0x01) | 0); + setprg8(0xA000, (prgbank & ~0x01) | 1); + setprg8(0xC000, (prgbank & ~0x01) | 2); + setprg8(0xE000, (prgbank & ~0x01) | 3 + | (latch.data & 0x04) + | ((latch.data & 0x04) && (latch.data & 0x40) ? 0x08 : 0x00)); } else { setprg16(0x8000, latch.addr >> 2); setprg16(0xC000, 0); } - setprg8r(0x10, (wramBank << 12), 0); + setchr8(0); - setmirror((latch.data & 1) ^ 1); + setmirror((latch.data & 0x01) ^ 0x01); + + setprg8r(0x10, prgram_addr, 0); + if (latch.data & 0x02) { + setprg8r(0x10, prgram_addr ^ 0x4000, 0); + } +} + +static DECLFW(M452Write) { + switch (A & 0xE000) { + case 0x8000: + case 0xA000: + case 0xC000: + Latch_Write(A, V); + break; + case 0xE000: + CartBW(A, V); + break; + } } static void M452Power(void) { - LatchPower(); - SetWriteHandler(0xE000, 0xFFFF, CartBW); + Latch_Power(); + SetWriteHandler(0x8000, 0xFFFF, M452Write); } void Mapper452_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 1, 0); - info->Reset = LatchHardReset; - info->Power = M452Power; + Latch_Init(info, Sync, NULL, TRUE, FALSE); + info->Reset = Latch_RegReset; + info->Power = M452Power; } diff --git a/src/boards/mapper453.c b/src/mappers/mapper453.c similarity index 66% rename from src/boards/mapper453.c rename to src/mappers/mapper453.c index c0263ae92..11eb0aea5 100644 --- a/src/boards/mapper453.c +++ b/src/mappers/mapper453.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -27,17 +27,18 @@ #include "latch.h" static void Sync(void) { - setchr8(0); if (latch.data & 0x40) { - setprg32(0x8000, ((latch.data >> 3) & 0x18) | (latch.data & 7)); + setprg32(0x8000, ((latch.data >> 3) & 0x18) | (latch.data & 0x07)); + setmirror(MI_0 + (((latch.data >> 4) & 0x01) ^ 0x01)); } else { - setprg16(0x8000, ((latch.data >> 2) & 0x38) | (latch.data & 7)); - setprg16(0xC000, (latch.data >> 2 & 0x38) | 7); + setprg16(0x8000, ((latch.data >> 2) & 0x38) | (latch.data & 0x07)); + setprg16(0xC000, (latch.data >> 2 & 0x38) | 0x07); + setmirror(((latch.data >> 4) & 0x01) ^ 0x01); } - setmirror(((latch.data >> 5) & 2) + (((latch.data >> 4) & 1) ^ 1)); + setchr8(0); } -static DECLFW(M453WriteLatch) { +static DECLFW(M453Write) { if (latch.data & 0xE0) { latch.data = (latch.data & 0xE0) | (V & ~0xE0); } else { @@ -46,13 +47,13 @@ static DECLFW(M453WriteLatch) { Sync(); } -static void M453Power() { - LatchPower(); - SetWriteHandler(0x8000, 0xFFFF, M453WriteLatch); +static void M453Power(void) { + Latch_Power(); + SetWriteHandler(0x8000, 0xFFFF, M453Write); } void Mapper453_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); + Latch_Init(info, Sync, NULL, FALSE, FALSE); info->Power = M453Power; - info->Reset = LatchHardReset; + info->Reset = Latch_RegReset; } diff --git a/src/mappers/mapper454.c b/src/mappers/mapper454.c new file mode 100644 index 000000000..644cbbd87 --- /dev/null +++ b/src/mappers/mapper454.c @@ -0,0 +1,63 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + */ + +/* NOTE: Only loading Contra after a reset? RAM init also affects powerup */ + +#include "mapinc.h" +#include "latch.h" + +static void Sync(void) { + uint8 prg = ((latch.addr >> 3) & 0x20) | ((latch.addr >> 2) & 0x1F); + uint8 cpuA14 = latch.addr & 0x01; + uint8 nrom = (latch.addr >> 7) & 0x01; + uint8 unrom = (latch.addr >> 9) & 0x01; + + setprg16(0x8000, ((prg & ~cpuA14) & ~(0x07 * unrom)) | (latch.data * unrom)); + setprg16(0xC000, ((prg | cpuA14) & ~(0x07 * !nrom * !unrom)) | (0x07 * !nrom * unrom)); + setchr8(0); + setmirror(((latch.addr >> 1) & 0x01) ^ 0x01); + if (nrom) { + /* CHR-RAM write protect hack, needed for some multicarts */ + SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0); + } else { + SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1); + } +} + +static DECLFW(M454Write) { + if (latch.addr & 0x100) { + latch.data = V & 0x07; + } else { + latch.data = V; + latch.addr = A; + } + Sync(); +} + +static void M454Power(void) { + Latch_Power(); + SetWriteHandler(0x8000, 0xFFFF, M454Write); +} + +void Mapper454_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, 0, 0); + info->Power = M454Power; +} diff --git a/src/boards/mapper455.c b/src/mappers/mapper455.c similarity index 56% rename from src/boards/mapper455.c rename to src/mappers/mapper455.c index d57583b9a..535baa8df 100644 --- a/src/boards/mapper455.c +++ b/src/mappers/mapper455.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2022 + * Copyright (C) 2023-2024 negativeExponent * * 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,54 +22,58 @@ #include "mapinc.h" #include "mmc3.h" +static uint8 reg[2]; + static void M455PW(uint32 A, uint8 V) { - uint8 prgAND = (mmc3.expregs[1] & 0x01) ? 0x1F : 0x0F; - uint8 prgOR = ((mmc3.expregs[0] >> 2) & 0x07) | ((mmc3.expregs[1] << 1) & 0x08) | ((mmc3.expregs[0] >> 2) & 0x10); - if (mmc3.expregs[0] & 0x01) { - if (mmc3.expregs[0] & 0x02) { - setprg32(0x8000, prgOR >> 1); + uint16 mask = (reg[1] & 0x01) ? 0x1F : 0x0F; + uint16 base = ((reg[0] >> 2) & 0x10) | ((reg[1] << 1) & 0x08) | ((reg[0] >> 2) & 0x07); + + if (reg[0] & 0x01) { + if (reg[0] & 0x02) { + setprg32(0x8000, base >> 1); } else { - setprg16(0x8000, prgOR); - setprg16(0xC000, prgOR); + setprg16(0x8000, base); + setprg16(0xC000, base); } } else { - setprg8(A, (V & prgAND) | ((prgOR << 1) & ~prgAND)); + setprg8(A, ((base << 1) & ~mask) | (V & mask)); } } static void M455CW(uint32 A, uint8 V) { - uint8 chrAND = (mmc3.expregs[1] & 0x02) ? 0xFF : 0x7F; - uint8 chrOR = ((mmc3.expregs[0] >> 2) & 0x07) | ((mmc3.expregs[1] << 1) & 0x08) | ((mmc3.expregs[0] >> 2) & 0x10); - setchr1(A, (V & chrAND) | ((chrOR << 4) & ~chrAND)); + uint16 mask = (reg[1] & 0x02) ? 0xFF : 0x7F; + uint16 base = ((reg[0] >> 2) & 0x10) | ((reg[1] << 1) & 0x08) | ((reg[0] >> 2) & 0x07); + + setchr1(A, ((base << 4) & ~mask) | (V & mask)); } static DECLFW(M455Write) { if (A & 0x100) { - mmc3.expregs[0] = V; - mmc3.expregs[1] = A & 0xFF; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + reg[0] = V; + reg[1] = A & 0xFF; + MMC3_FixPRG(); + MMC3_FixCHR(); } } static void M455Reset(void) { - mmc3.expregs[0] = 1; - mmc3.expregs[1] = 0; - MMC3RegReset(); + reg[0] = 1; + reg[1] = 0; + MMC3_Reset(); } static void M455Power(void) { - mmc3.expregs[0] = 1; - mmc3.expregs[1] = 0; - GenMMC3Power(); + reg[0] = 1; + reg[1] = 0; + MMC3_Power(); SetWriteHandler(0x4100, 0x5FFF, M455Write); } void Mapper455_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 0, 0); - mmc3.cwrap = M455CW; - mmc3.pwrap = M455PW; + MMC3_Init(info, 0, 0); + MMC3_cwrap = M455CW; + MMC3_pwrap = M455PW; info->Power = M455Power; info->Reset = M455Reset; - AddExState(mmc3.expregs, 2, 0, "EXPR"); + AddExState(reg, 2, 0, "EXPR"); } diff --git a/src/boards/mapper456.c b/src/mappers/mapper456.c similarity index 56% rename from src/boards/mapper456.c rename to src/mappers/mapper456.c index 108877ea2..60177ed83 100644 --- a/src/boards/mapper456.c +++ b/src/mappers/mapper456.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2022 + * Copyright (C) 2023-2024 negativeExponent * * 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,38 +22,40 @@ #include "mapinc.h" #include "mmc3.h" -static void Mapper456_PRGWrap(uint32 A, uint8 V) { - setprg8(A, (V & 0x0F) | (mmc3.expregs[0] << 4)); +static uint8 reg; + +static void M456PW(uint32 A, uint8 V) { + setprg8(A, (reg << 4) | (V & 0x0F)); } -static void Mapper456_CHRWrap(uint32 A, uint8 V) { - setchr1(A, (V & 0x7F) | (mmc3.expregs[0] << 7)); +static void M456CW(uint32 A, uint8 V) { + setchr1(A, (reg << 7) | (V & 0x7F)); } -static DECLFW(Mapper456_Write) { +static DECLFW(M456Write) { if (A & 0x100) { - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + reg = V; + MMC3_FixPRG(); + MMC3_FixCHR(); } } -static void Mapper456_Reset(void) { - mmc3.expregs[0] = 0; - MMC3RegReset(); +static void M456Reset(void) { + reg = 0; + MMC3_Reset(); } -static void Mapper456_Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); - SetWriteHandler(0x4020, 0x5FFF, Mapper456_Write); +static void M456Power(void) { + reg = 0; + MMC3_Power(); + SetWriteHandler(0x4100, 0x5FFF, M456Write); } void Mapper456_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 128, 8, 0); - mmc3.cwrap = Mapper456_CHRWrap; - mmc3.pwrap = Mapper456_PRGWrap; - info->Power = Mapper456_Power; - info->Reset = Mapper456_Reset; - AddExState(mmc3.expregs, 1, 0, "EXPR"); + MMC3_Init(info, 8, 0); + MMC3_cwrap = M456CW; + MMC3_pwrap = M456PW; + info->Power = M456Power; + info->Reset = M456Reset; + AddExState(®, 1, 0, "EXPR"); } diff --git a/src/boards/mapper457.c b/src/mappers/mapper457.c similarity index 67% rename from src/boards/mapper457.c rename to src/mappers/mapper457.c index 74835c86f..c324b6f64 100644 --- a/src/boards/mapper457.c +++ b/src/mappers/mapper457.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,40 +21,47 @@ #include "mapinc.h" #include "mmc3.h" +static uint8 reg; + static void M457CW(uint32 A, uint8 V) { - uint32 mask = (mmc3.expregs[0] & 8) ? 0xFF : 0x7F; - setchr1(A, ((mmc3.expregs[0] << 7) & ~mask) | (V & mask)); + uint32 mask = (reg & 0x08) ? 0xFF : 0x7F; + uint32 base = reg << 7; + + setchr1(A, (base & ~mask) | (V & mask)); } static void M457PW(uint32 A, uint8 V) { - uint32 mask = (mmc3.expregs[0] & 8) ? 0x1F : 0x0F; - setprg8(A, (((mmc3.expregs[0] & 7) << 4) & ~mask) | (V & mask)); + uint32 mask = (reg & 0x08) ? 0x1F : 0x0F; + uint32 base = reg << 4; + + setprg8(A, (base & ~mask) | (V & mask)); } static DECLFW(M457Write) { - if (MMC3CanWriteToWRAM()) { - mmc3.expregs[0] = V; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + if (MMC3_WramIsWritable()) { + CartBW(A, V); + reg = V; + MMC3_FixPRG(); + MMC3_FixCHR(); } } static void M457Reset(void) { - mmc3.expregs[0] = 0; - MMC3RegReset(); + reg = 0; + MMC3_Reset(); } static void M457Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); + reg = 0; + MMC3_Power(); SetWriteHandler(0x6000, 0x7FFF, M457Write); } void Mapper457_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 256, 0, 0); - mmc3.cwrap = M457CW; - mmc3.pwrap = M457PW; + MMC3_Init(info, 0, 0); + MMC3_cwrap = M457CW; + MMC3_pwrap = M457PW; info->Reset = M457Reset; info->Power = M457Power; - AddExState(mmc3.expregs, 1, 0, "EXPR"); + AddExState(®, 1, 0, "EXPR"); } diff --git a/src/boards/mapper458.c b/src/mappers/mapper458.c similarity index 64% rename from src/boards/mapper458.c rename to src/mappers/mapper458.c index 69ce14200..296d57866 100644 --- a/src/boards/mapper458.c +++ b/src/mappers/mapper458.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,53 +21,62 @@ #include "mapinc.h" #include "mmc3.h" +static uint8 reg; +static uint8 dipsw; + static void M458CW(uint32 A, uint8 V) { - setchr1(A, ((mmc3.expregs[0] << 4) & ~0x7F) | (V & 0x7F)); + uint16 mask = 0x7F; + uint16 base = reg << 4; + + setchr1(A, (base & ~mask) | (V & mask)); } static void M458PW(uint32 A, uint8 V) { - if (mmc3.expregs[0] & 0x10) { - setprg32(0x8000, mmc3.expregs[0] >> 1); + uint8 prg = reg & 0x0F; + + if (reg & 0x10) { + setprg32(0x8000, prg >> 1); } else { - setprg16(0x8000, mmc3.expregs[0]); - setprg16(0xC000, mmc3.expregs[0]); + setprg16(0x8000, prg); + setprg16(0xC000, prg); } } static DECLFR(M458Read) { - if ((mmc3.expregs[0] & 0x20) && (mmc3.expregs[1] & 3)) { - return CartBR((A & ~3) | (mmc3.expregs[1] & 3)); + if ((reg & 0x20) && (dipsw & 0x03)) { + return CartBR((A & ~0x1F) | (dipsw & 0x1F)); } return CartBR(A); } static DECLFW(M458Write) { - if (MMC3CanWriteToWRAM()) { - mmc3.expregs[0] = A & 0xFF; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + if (MMC3_WramIsWritable()) { + reg = A & 0xFF; + MMC3_FixPRG(); + MMC3_FixCHR(); } } static void M458Reset(void) { - mmc3.expregs[0] = 0; - mmc3.expregs[1]++; - MMC3RegReset(); + reg = 0; + dipsw++; + MMC3_Reset(); } static void M458Power(void) { - mmc3.expregs[0] = 0; - mmc3.expregs[1] = 0; - GenMMC3Power(); + reg = 0; + dipsw = 0; + MMC3_Power(); SetReadHandler(0x8000, 0xFFFF, M458Read); SetWriteHandler(0x6000, 0x7FFF, M458Write); } void Mapper458_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 0, 0); - mmc3.cwrap = M458CW; - mmc3.pwrap = M458PW; + MMC3_Init(info, 0, 0); + MMC3_cwrap = M458CW; + MMC3_pwrap = M458PW; info->Reset = M458Reset; info->Power = M458Power; - AddExState(mmc3.expregs, 2, 0, "EXPR"); + AddExState(®, 1, 0, "EXPR"); + AddExState(&dipsw, 1, 0, "CMD0"); } diff --git a/src/boards/mapper459.c b/src/mappers/mapper459.c similarity index 68% rename from src/boards/mapper459.c rename to src/mappers/mapper459.c index 58ba29713..52ad00122 100644 --- a/src/boards/mapper459.c +++ b/src/mappers/mapper459.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,20 +22,21 @@ #include "latch.h" static void Sync(void) { - uint8 prg = latch.addr >> 5; - uint8 chr = (latch.addr & 0x03) | ((latch.addr >> 2) & 0x04) | ((latch.addr >> 4) & 0x08); - chr &= (latch.addr & 8 ? 0x0F : 0x08); - if (latch.addr & 4) { - setprg32(0x8000, prg); + uint8 prg = latch.addr >> 4; + uint8 chr = (latch.addr & 0x03) | ((latch.addr >> 2) & 0x04) | ((latch.addr >> 4) & 0x08); + uint8 mirr = ((latch.addr >> 8) & 0x01) ^ 0x01; + + if (latch.addr & 0x04) { + setprg32(0x8000, prg >> 1); } else { - setprg16(0x8000, prg << 1); - setprg16(0xC000, (prg << 1) | 7); + setprg16(0x8000, prg ); + setprg16(0xC000, prg | 0x07); } setchr8(chr); - setmirror(((latch.addr >> 8) & 1) ^ 1); + setmirror(mirr); } void Mapper459_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); - info->Reset = LatchHardReset; + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Reset = Latch_RegReset; } diff --git a/src/boards/mapper460.c b/src/mappers/mapper460.c similarity index 54% rename from src/boards/mapper460.c rename to src/mappers/mapper460.c index d366d33e6..7a4efcb25 100644 --- a/src/boards/mapper460.c +++ b/src/mappers/mapper460.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,34 +22,43 @@ #include "mmc3.h" static uint8 *CHRRAM = NULL; +static uint8 reg; +static uint8 dipsw; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { &dipsw, 1, "DPSW" }, + { 0 } +}; static void M460PW(uint32 A, uint8 V) { uint32 mask = 0x0F; - uint32 base = mmc3.expregs[0] << 4; - if (mmc3.expregs[0] & 0x20 && ((mmc3.expregs[0] != 0x20) || (~mmc3.expregs[1] & 1))) { + uint32 base = reg << 4; + + if (reg & 0x20) { /* Menu selection by selectively connecting CPU D7 to reg or not */ - if (mmc3.expregs[0] & 0x10) { - setprg8(0x8000, (base & ~mask) | ((mmc3.regs[6] & ~2) & mask)); - setprg8(0xA000, (base & ~mask) | ((mmc3.regs[7] & ~2) & mask)); - setprg8(0xC000, (base & ~mask) | ((mmc3.regs[6] | 2) & mask)); - setprg8(0xE000, (base & ~mask) | ((mmc3.regs[7] | 2) & mask)); + if (reg & 0x10) { + setprg8(0x8000, (base & ~mask) | ((mmc3.reg[6] & ~0x02) & mask)); + setprg8(0xA000, (base & ~mask) | ((mmc3.reg[7] & ~0x02) & mask)); + setprg8(0xC000, (base & ~mask) | ((mmc3.reg[6] | 0x02) & mask)); + setprg8(0xE000, (base & ~mask) | ((mmc3.reg[7] | 0x02) & mask)); } else { - setprg8(0x8000, (base & ~mask) | (mmc3.regs[6] & mask)); - setprg8(0xA000, (base & ~mask) | (mmc3.regs[7] & mask)); - setprg8(0xC000, (base & ~mask) | (mmc3.regs[6] & mask)); - setprg8(0xE000, (base & ~mask) | (mmc3.regs[7] & mask)); + setprg8(0x8000, (base & ~mask) | (mmc3.reg[6] & mask)); + setprg8(0xA000, (base & ~mask) | (mmc3.reg[7] & mask)); + setprg8(0xC000, (base & ~mask) | (mmc3.reg[6] & mask)); + setprg8(0xE000, (base & ~mask) | (mmc3.reg[7] & mask)); } } else { - setprg8(A, (V & mask) | (base & ~mask)); + setprg8(A, (base & ~mask) | (V & mask)); } } static void M460CW(uint32 A, uint8 V) { - if (mmc3.expregs[0] & 0x04) { - setchr2(0x0000, mmc3.regs[0] & 0xFE); - setchr2(0x0800, mmc3.regs[0] | 0x01); - setchr2(0x1000, mmc3.regs[2]); - setchr2(0x1800, mmc3.regs[5]); + if (reg & 0x04) { + setchr2(0x0000, mmc3.reg[0] & 0xFE); + setchr2(0x0800, mmc3.reg[1] | 0x01); + setchr2(0x1000, mmc3.reg[2]); + setchr2(0x1800, mmc3.reg[5]); } else { setchr8r(0x10, 0); } @@ -57,35 +66,36 @@ static void M460CW(uint32 A, uint8 V) { static DECLFR(M460Read) { /* Menu selection by selectively connecting reg's D7 to PRG /CE or not */ - if ((mmc3.expregs[0] & 0x80) && (mmc3.expregs[1] & 1)) { - return X.DB; + if ((reg & 0x80) && (dipsw & 0x01)) { + return cpu.openbus; } return CartBR(A); } -static DECLFW(M460WriteLow) { - if (MMC3CanWriteToWRAM()) { - mmc3.expregs[0] = A & 0xFF; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); +static DECLFW(M460Write) { + if (MMC3_WramIsWritable()) { + reg = A & 0xFF; + MMC3_FixPRG(); + MMC3_FixCHR(); } } static void M460Reset(void) { - mmc3.expregs[0] = 0; - mmc3.expregs[1]++; - MMC3RegReset(); + reg = 0; + dipsw++; + MMC3_Reset(); } static void M460Power(void) { - mmc3.expregs[0] = 0; - mmc3.expregs[1] = 0; - GenMMC3Power(); + reg = 0; + dipsw = 0; + MMC3_Power(); SetReadHandler(0x8000, 0xFFFF, M460Read); - SetWriteHandler(0x6000, 0x7FFF, M460WriteLow); + SetWriteHandler(0x6000, 0x7FFF, M460Write); } static void M460close(void) { + MMC3_Close(); if (CHRRAM) { FCEU_gfree(CHRRAM); } @@ -93,13 +103,13 @@ static void M460close(void) { } void Mapper460_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 512, 0, 0); - mmc3.cwrap = M460CW; - mmc3.pwrap = M460PW; + MMC3_Init(info, 0, 0); + MMC3_cwrap = M460CW; + MMC3_pwrap = M460PW; info->Power = M460Power; info->Reset = M460Reset; info->Close = M460close; - AddExState(mmc3.expregs, 2, 0, "EXPR"); + AddExState(StateRegs, ~0, 0, NULL); CHRRAM = (uint8 *)FCEU_gmalloc(8192); SetupCartCHRMapping(0x10, CHRRAM, 8192, 1); diff --git a/src/boards/mapper461.c b/src/mappers/mapper461.c similarity index 84% rename from src/boards/mapper461.c rename to src/mappers/mapper461.c index c24d244d7..01fad0118 100644 --- a/src/boards/mapper461.c +++ b/src/mappers/mapper461.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,8 +22,9 @@ #include "latch.h" static void Sync(void) { - uint8 prg = (latch.addr << 1) | ((latch.addr >> 5) & 1); + uint8 prg = (latch.addr << 1) | ((latch.addr >> 5) & 0x01); uint8 chr = latch.addr >> 8; + if (!(latch.addr & 0x10)) { setprg32(0x8000, prg >> 1); } else { @@ -31,9 +32,9 @@ static void Sync(void) { setprg16(0xC000, prg); } setchr8(chr); - setmirror(((latch.addr >> 7) & 1) ^ 1); + setmirror(((latch.addr >> 7) & 0x01) ^ 0x01); } void Mapper461_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); + Latch_Init(info, Sync, NULL, FALSE, FALSE); } diff --git a/src/boards/mapper463.c b/src/mappers/mapper463.c similarity index 75% rename from src/boards/mapper463.c rename to src/mappers/mapper463.c index 5c8519e3a..813afe95f 100644 --- a/src/boards/mapper463.c +++ b/src/mappers/mapper463.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -20,41 +20,45 @@ #include "mapinc.h" -static uint8 regs[4] = { 0 }; -static uint8 dipswitch = 0; +static uint8 regs[4]; +static uint8 dipsw; static SFORMAT StateRegs[] = { { regs, 4, "EXPR" }, - { &dipswitch, 1, "DPSW" }, + { &dipsw, 1, "DPSW" }, { 0 } }; static void Sync(void) { - if (regs[0] & 4) { - setprg16(0x8000, regs[1]); - setprg16(0xC000, regs[1]); + uint8 prg = regs[1]; + uint8 chr = regs[2]; + uint8 mirr = (regs[0] & 0x01) ^ 0x01; + + if (regs[0] & 0x04) { + setprg16(0x8000, prg); + setprg16(0xC000, prg); } else { - setprg32(0x8000, regs[1] >> 1); + setprg32(0x8000, prg >> 1); } - setchr8(regs[2]); - setmirror((regs[0] & 1) ^ 1); + setchr8(chr); + setmirror(mirr); } static DECLFW(M463Write5000) { - if (A & (0x10 << dipswitch)) { - regs[A & 3] = V; + if (A & (0x10 << dipsw)) { + regs[A & 0x03] = V; Sync(); } } static void M463Reset(void) { - dipswitch = (dipswitch + 1) & 7; + dipsw = (dipsw + 1) & 0x07; regs[0] = regs[1] = regs[2] = regs[3] = 0; Sync(); } static void M463Power(void) { - dipswitch = 0; + dipsw = 0; regs[0] = regs[1] = regs[2] = regs[3] = 0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); @@ -69,5 +73,5 @@ void Mapper463_Init(CartInfo *info) { info->Power = M463Power; info->Reset = M463Reset; GameStateRestore = StateRestore; - AddExState(StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper464.c b/src/mappers/mapper464.c similarity index 80% rename from src/boards/mapper464.c rename to src/mappers/mapper464.c index ed52d7b42..327f94254 100644 --- a/src/boards/mapper464.c +++ b/src/mappers/mapper464.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,8 +22,10 @@ #include "latch.h" static void Sync(void) { - uint8 prg = latch.addr >> 7; - uint8 chr = latch.addr & 0x1F; + uint8 prg = latch.addr >> 7; + uint8 chr = latch.addr & 0x1F; + uint8 mirr = ((latch.addr >> 5) & 0x01) ^ 0x01; + if (latch.addr & 0x40) { setprg32(0x8000, prg >> 1); } else { @@ -31,10 +33,10 @@ static void Sync(void) { setprg16(0xC000, prg); } setchr8(chr); - setmirror(((latch.addr >> 5) & 1) ^ 1); + setmirror(mirr); } void Mapper464_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); - info->Reset = LatchHardReset; + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Reset = Latch_RegReset; } diff --git a/src/boards/mapper465.c b/src/mappers/mapper465.c similarity index 82% rename from src/boards/mapper465.c rename to src/mappers/mapper465.c index 020b4fbc4..272c43e3a 100644 --- a/src/boards/mapper465.c +++ b/src/mappers/mapper465.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -23,12 +23,13 @@ static void Sync(void) { uint8 prg = ((latch.addr >> 2) & 0x1F) | ((latch.addr >> 5) & 0x20); + if (latch.addr & 0x200) { /* unrom */ - setprg16(0x8000, (prg & ~7) | (latch.data & 7)); - setprg16(0xC000, prg | 7); + setprg16(0x8000, (prg & ~0x07) | (latch.data & 0x07)); + setprg16(0xC000, prg | 0x07); } else { - if (latch.addr & 1) { + if (latch.addr & 0x01) { setprg32(0x8000, prg >> 1); } else { setprg16(0x8000, prg); @@ -36,7 +37,7 @@ static void Sync(void) { } } setchr8(0); - setmirror(((latch.addr >> 1) & 1) ^ 1); + setmirror(((latch.addr >> 1) & 0x01) ^ 0x01); } static DECLFW(M465WriteLatch) { @@ -50,12 +51,12 @@ static DECLFW(M465WriteLatch) { } static void M465Power(void) { - LatchPower(); + Latch_Power(); SetWriteHandler(0x8000, 0xFFFF, M465WriteLatch); } void Mapper465_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); + Latch_Init(info, Sync, NULL, FALSE, FALSE); info->Power = M465Power; - info->Reset = LatchHardReset; + info->Reset = Latch_RegReset; } \ No newline at end of file diff --git a/src/boards/mapper466.c b/src/mappers/mapper466.c similarity index 87% rename from src/boards/mapper466.c rename to src/mappers/mapper466.c index 507f77dc3..4fe82f45f 100644 --- a/src/boards/mapper466.c +++ b/src/mappers/mapper466.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,8 +21,6 @@ #include "mapinc.h" static uint8 regs[4]; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; static SFORMAT StateRegs[] = { { regs, 4, "EXPR" }, @@ -30,11 +28,12 @@ static SFORMAT StateRegs[] = { }; static uint32 getPRGBank(void) { - return ((regs[1] << 5) | ((regs[0] << 1) & 0x1E) | ((regs[0] >> 5) & 1)); + return ((regs[1] << 5) | ((regs[0] << 1) & 0x1E) | ((regs[0] >> 5) & 0x01)); } static void Sync(void) { uint32 prg = getPRGBank(); + if (regs[0] & 0x40) { if (regs[0] & 0x10) { setprg16(0x8000, prg); @@ -43,24 +42,24 @@ static void Sync(void) { setprg32(0x8000, prg >> 1); } } else { - setprg16(0x8000, (prg & ~7) | (regs[2] & 7)); - setprg16(0xC000, (prg & ~7) | 7); + setprg16(0x8000, (prg & ~0x07) | (regs[2] & 0x07)); + setprg16(0xC000, (prg & ~0x07) | 0x07); } setprg8r(0x10, 0x6000, 0); setchr8(0); - setmirror(((regs[0] >> 7) & 1) ^ 1); + setmirror(((regs[0] >> 7) & 0x01) ^ 0x01); } static DECLFR(M466ReadLatch) { /* Return open bus when selecting unpopulated PRG chip */ if ((getPRGBank() & 0x20) && (PRGsize[0] < (1024 * 1024))) { - return X.DB; + return cpu.openbus; } return CartBR(A); } static DECLFW(M466Write5000) { - regs[(A >> 11) & 1] = A & 0xFF; + regs[(A >> 11) & 0x01] = A & 0xFF; Sync(); } @@ -76,21 +75,19 @@ static void M466Reset(void) { static void M466Close(void) { - if (WRAM) { - FCEU_gfree(WRAM); - } - WRAM = NULL; } static void M466Power(void) { regs[0] = regs[1] = 0; Sync(); - SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + SetReadHandler(0x8000, 0xFFFF, M466ReadLatch); SetWriteHandler(0x5000, 0x5FFF, M466Write5000); SetWriteHandler(0x8000, 0xFFFF, M466WriteLatch); + + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } static void StateRestore(int version) { @@ -107,5 +104,5 @@ void Mapper466_Init(CartInfo *info) { WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - AddExState(StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper467.c b/src/mappers/mapper467.c new file mode 100644 index 000000000..428c366d1 --- /dev/null +++ b/src/mappers/mapper467.c @@ -0,0 +1,102 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 reg; + +static void M467PW(uint32 A, uint8 V) { + if (reg & 0x20) { + uint8 mask = (reg & 0x40) ? 0x0F : 0x03; + uint8 base = reg << 1; + + setprg8(A, (base & ~mask) | (V & mask)); + } else { + setprg16(0x8000, reg & 0x1F); + setprg16(0xC000, reg & 0x1F); + } +} + +static void M467CHR(void) { + uint16 base = (reg << 2) & 0x100; + + if (reg & 0x40) { + setchr2(0x0000, base | (mmc3.reg[0] & ~0x01)); + setchr2(0x0800, base | (mmc3.reg[0] | 0x01)); + setchr2(0x1000, base | mmc3.reg[2]); + setchr2(0x1800, base | mmc3.reg[3]); + } else { + setchr2(0x0000, base | (mmc3.reg[0] & ~0x03) | 0); + setchr2(0x0800, base | (mmc3.reg[0] & ~0x03) | 1); + setchr2(0x1000, base | (mmc3.reg[2] & ~0x03) | 2); + setchr2(0x1800, base | (mmc3.reg[3] & ~0x03) | 3); + } +} + +static void M467MIR(void) { + setmirror(((reg >> 7) & 0x01) ^ 0x01); +} + +static DECLFW(M467Write) { + switch (A & 0xF000) { + case 0x9000: + reg = V; + MMC3_FixPRG(); + MMC3_FixCHR(); + MMC3_FixMIR(); + break; + default: + switch (A & 0xE001) { + case 0x8000: + mmc3.cmd = V & 0x3F; + break; + case 0x8001: + mmc3.reg[mmc3.cmd & 0x07] = V; + if (mmc3.cmd < 6) MMC3_FixCHR(); + else MMC3_FixPRG(); + break; + case 0xA000: + break; + } + } +} + + +static void M467Reset(void) { + reg = 0; + MMC3_Reset(); +} + +static void M467Power(void) { + reg = 0; + MMC3_Power(); + SetWriteHandler(0x8000, 0xBFFF, M467Write); +} + +void Mapper467_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_FixCHR = M467CHR; + MMC3_FixMIR = M467MIR; + MMC3_pwrap = M467PW; + info->Power = M467Power; + info->Reset = M467Reset; + AddExState(®, 1, 0, "EXPR"); +} diff --git a/src/mappers/mapper471.c b/src/mappers/mapper471.c new file mode 100644 index 000000000..14ec8262d --- /dev/null +++ b/src/mappers/mapper471.c @@ -0,0 +1,52 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 471 denotes the Impact Soft IM1 circuit board, used for Haratyler (without HG or MP) and Haraforce. + * It is basically INES Mapper 201 with the addition of a scanline IRQ.*/ + +#include "mapinc.h" +#include "latch.h" + +static void Sync(void) { + setprg32(0x8000, latch.addr); + setchr8(latch.addr); +} + +static DECLFW(M471Write) { + X6502_IRQEnd(FCEU_IQEXT); + Latch_Write(A, V); +} + +static void M471HBHook(void) { + X6502_IRQBegin(FCEU_IQEXT); +} + +static void M471Power(void) { + Latch_Power(); + SetWriteHandler(0x8000, 0xFFFF, M471Write); +} + +void Mapper471_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Power = M471Power; + info->Reset = Latch_RegReset; + GameHBIRQHook = M471HBHook; +} diff --git a/src/boards/mapper500.c b/src/mappers/mapper500.c similarity index 78% rename from src/boards/mapper500.c rename to src/mappers/mapper500.c index 9b1c04527..da176c706 100644 --- a/src/boards/mapper500.c +++ b/src/mappers/mapper500.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -31,28 +31,28 @@ static SFORMAT StateRegs[] = { static void Sync(void) { setprg4(0x7000, 0); - setprg16(0x8000, (reg[0] << 3) | (latch.data & 7)); - setprg16(0xC000, (reg[0] << 3) | 7); + setprg16(0x8000, (reg[0] << 3) | (latch.data & 0x07)); + setprg16(0xC000, (reg[0] << 3) | 0x07); setchr8(0); - setmirror(reg[1] & 1); + setmirror(reg[1] & 0x01); } static DECLFW(M500WriteReg) { - if (~reg[1] & 0x80) { - reg[A & 1] = V; + if (!(reg[1] & 0x80)) { + reg[A & 0x01] = V; Sync(); } } -static void M500Power() { +static void M500Power(void) { reg[0] = reg[1] = 0; - LatchPower(); + Latch_Power(); SetReadHandler(0x7000, 0x7FFF, CartBR); SetWriteHandler(0x6000, 0x6FFF, M500WriteReg); } void Mapper500_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); + Latch_Init(info, Sync, NULL, FALSE, FALSE); info->Power = M500Power; AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper501.c b/src/mappers/mapper501.c similarity index 79% rename from src/boards/mapper501.c rename to src/mappers/mapper501.c index faad8ab4d..b0bad58c4 100644 --- a/src/boards/mapper501.c +++ b/src/mappers/mapper501.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -31,27 +31,27 @@ static SFORMAT StateRegs[] = { static void Sync(void) { setprg4(0x7000, 0); - setprg32(0x8000, (reg[0] << 2) + (latch.data & 7)); + setprg32(0x8000, (reg[0] << 2) + (latch.data & 0x07)); setchr8(0); - setmirror(MI_0 + (reg[1] & 1)); + setmirror(MI_0 + ((latch.data >> 4) & 0x01)); } static DECLFW(M501WriteReg) { - if (~reg[1] & 0x80) { - reg[A & 1] = V; + if (!(reg[1] & 0x80)) { + reg[A & 0x01] = V; Sync(); } } -static void M501Power() { +static void M501Power(void) { reg[0] = reg[1] = 0; - LatchPower(); + Latch_Power(); SetReadHandler(0x7000, 0x7FFF, CartBR); SetWriteHandler(0x6000, 0x6FFF, M501WriteReg); } void Mapper501_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); + Latch_Init(info, Sync, NULL, FALSE, FALSE); info->Power = M501Power; AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper502.c b/src/mappers/mapper502.c similarity index 77% rename from src/boards/mapper502.c rename to src/mappers/mapper502.c index cd13f7fa4..1df5fa74e 100644 --- a/src/boards/mapper502.c +++ b/src/mappers/mapper502.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -30,38 +30,39 @@ static SFORMAT StateRegs[] = { }; static void Sync(void) { - uint8 mask = (8 << (reg[1] >> 4 & 3)) - 1; + uint8 mask = (8 << ((reg[1] >> 4) & 0x03)) - 1; + setprg4(0x7000, 0); - if (reg[1] & 6) + if (reg[1] & 0x06) { setprg32(0x8000, (reg[0] << 2) + (latch.data & (mask >> 1))); - else { + } else { setprg16(0x8000, (reg[0] << 3) + (latch.data & mask)); setprg16(0xC000, (reg[0] << 3) + mask); } setchr8(0); - if (reg[1] & 2) { - setmirror(MI_0 + ((latch.data >> 4) & 1)); + if (reg[1] & 0x02) { + setmirror(MI_0 + ((latch.data >> 4) & 0x01)); } else { - setmirror(reg[1] & 1); + setmirror(reg[1] & 0x01); } } static DECLFW(M502WriteReg) { - if (~reg[1] & 0x80) { - reg[A & 1] = V; + if (!(reg[1] & 0x80)) { + reg[A & 0x01] = V; Sync(); } } -static void M502Power() { +static void M502Power(void) { reg[0] = reg[1] = 0; - LatchPower(); + Latch_Power(); SetReadHandler(0x7000, 0x7FFF, CartBR); SetWriteHandler(0x6000, 0x6FFF, M502WriteReg); } void Mapper502_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 0); + Latch_Init(info, Sync, NULL, FALSE, FALSE); info->Power = M502Power; AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper512.c b/src/mappers/mapper512.c similarity index 78% rename from src/boards/mapper512.c rename to src/mappers/mapper512.c index 655fbea8c..3b1d4d952 100644 --- a/src/boards/mapper512.c +++ b/src/mappers/mapper512.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -29,25 +29,27 @@ #include "mapinc.h" #include "mmc3.h" +static uint8 reg; + static uint8 *CHRRAM = NULL; static uint32 CHRRAMSIZE = 8192; extern uint8 *ExtraNTARAM; -static void M512MW(uint8 V) { - if (mmc3.expregs[0] == 1) { - SetupCartMirroring(4, 1, ExtraNTARAM); +static void M512MIR(void) { + if (reg == 1) { + SetupCartMirroring(4, 0, ExtraNTARAM); } else { - mmc3.mirroring = V; - SetupCartMirroring((V & 1) ^ 1, 0, 0); + setmirror((mmc3.mirr & 0x01) ^ 0x01); } } static void M512CW(uint32 A, uint8 V) { - if (mmc3.expregs[0] & 2) + if (reg & 0x02) { setchr1r(0x10, A, (V & 0x03)); - else - setchr1(A, V); + } else { + setchr1(A, V & 0xFF); + } } static void M512PW(uint32 A, uint8 V) { @@ -56,32 +58,34 @@ static void M512PW(uint32 A, uint8 V) { static DECLFW(M512Write) { if (A & 0x100) { - mmc3.expregs[0] = V & 3; - FixMMC3CHR(mmc3.cmd); + reg = V & 0x03; + MMC3_FixCHR(); + MMC3_FixMIR(); } } static void M512Close(void) { - GenMMC3Close(); - if (CHRRAM) + MMC3_Close(); + if (CHRRAM) { FCEU_gfree(CHRRAM); + } CHRRAM = NULL; } static void M512Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); + reg = 0; + MMC3_Power(); SetWriteHandler(0x4100, 0x4FFF, M512Write); } void Mapper512_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 8, info->battery); - mmc3.cwrap = M512CW; - mmc3.pwrap = M512PW; - mmc3.mwrap = M512MW; + MMC3_Init(info, 8, info->battery); + MMC3_cwrap = M512CW; + MMC3_pwrap = M512PW; + MMC3_FixMIR = M512MIR; info->Power = M512Power; info->Close = M512Close; - AddExState(mmc3.expregs, 1, 0, "EXPR"); + AddExState(®, 1, 0, "EXPR"); CHRRAMSIZE = 8192; CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSIZE); diff --git a/src/boards/SA-9602B.c b/src/mappers/mapper513.c similarity index 50% rename from src/boards/SA-9602B.c rename to src/mappers/mapper513.c index cae5dd1e2..deff8b3a0 100644 --- a/src/boards/SA-9602B.c +++ b/src/mappers/mapper513.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) 2023-2024 negativeExponent * * 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,44 +19,68 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +/* NES 2.0 Mapper 513 - Sachen UNL-SA-9602B */ + #include "mapinc.h" #include "mmc3.h" -static void SA9602BPW(uint32 A, uint8 V) { - setprg8(A, (mmc3.expregs[1] & 0xC0) | (V & 0x3F)); - if (mmc3.cmd & 0x40) - setprg8(0x8000, 62); - else - setprg8(0xc000, 62); - setprg8(0xe000, 63); +static uint8 reg; + +static void M513CW(uint32 A, uint8 V) { + setchr1(A, V & 0x3F); +} + +static void M513PW(uint32 A, uint8 V) { + if (!(A & 0x4000)) { + setprg8(A, (reg & 0xC0) | (V & 0x3F)); + } else { + setprg8(A, (V & 0x3F)); + } } -static DECLFW(SA9602BWrite) { - switch (A & 0xe001) { - case 0x8000: mmc3.expregs[0] = V; break; +static DECLFW(M513Write) { + switch (A & 0xE001) { + case 0x8000: + mmc3.cmd = V; + MMC3_FixPRG(); + MMC3_FixCHR(); + break; case 0x8001: - if ((mmc3.expregs[0] & 7) < 6) { - mmc3.expregs[1] = V; - FixMMC3PRG(mmc3.cmd); + mmc3.reg[mmc3.cmd & 0x07] = V; + switch (mmc3.cmd & 0x07) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + reg = V; + MMC3_FixPRG(); + MMC3_FixCHR(); + break; + default: + MMC3_FixPRG(); + break; } + default: break; } - MMC3_CMDWrite(A, V); } -static void SA9602BPower(void) { - mmc3.expregs[0] = mmc3.expregs[1] = 0; - GenMMC3Power(); +static void M513Power(void) { + reg = 0; + MMC3_Power(); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xBFFF, SA9602BWrite); + SetWriteHandler(0x8000, 0x9FFF, M513Write); } -void SA9602B_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 0, 0, 0); - mmc3.pwrap = SA9602BPW; +void Mapper513_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_pwrap = M513PW; + MMC3_cwrap = M513CW; mmc3.opts |= 2; info->SaveGame[0] = UNIFchrrama; info->SaveGameLen[0] = 32 * 1024; - info->Power = SA9602BPower; - AddExState(mmc3.expregs, 2, 0, "EXPR"); + info->Power = M513Power; + AddExState(®, 1, 0, "EXPR"); } diff --git a/src/mappers/mapper514.c b/src/mappers/mapper514.c new file mode 100644 index 000000000..956cf66fe --- /dev/null +++ b/src/mappers/mapper514.c @@ -0,0 +1,95 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static uint8 mode; +static uint32 lastnt; + +static SFORMAT StateRegs[] = { + { &mode, 1, "MODE" }, + { &lastnt, 4, "LSNT" }, + { 0 } +}; + +static void Sync(void) { + setprg8r(0x10, 0x6000, 0); + setprg32(0x8000, mode & 0x3F); + setchr4(0x0000, lastnt); + setchr4(0x1000, 1); + setmirror(((mode >> 6) & 0x01) ^ 0x01); +} + +static DECLFW(M514Write8) { + if ((A & 0xFFF) == 0) { + mode = V; + Sync(); + } +} + +static void M514PPUHook(uint32 A) { + if ((A & 0x3000) == 0x2000) { + uint32 mask = (mode & 0x40) ? 0x02 : 0x01; + uint32 bank = A >> 10; + if ((mode & 0x80) && (bank & mask)) { + setchr4(0, 1); + lastnt = 1; + } else { + lastnt = 0; + setchr4(0, 0); + } + } +} + +static void M514Reset(void) { + lastnt = 0; + mode = 0; + Sync(); +} + +static void M514Power(void) { + lastnt = 0; + mode = 0; + Sync(); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0x8FFF, M514Write8); +} + +static void M514Close(void) { +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper514_Init(CartInfo *info) { + info->Power = M514Power; + info->Reset = M514Reset; + info->Close = M514Close; + PPU_hook = M514PPUHook; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + + WRAMSIZE = 8192; + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, TRUE); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); +} diff --git a/src/boards/mapper516.c b/src/mappers/mapper516.c similarity index 64% rename from src/boards/mapper516.c rename to src/mappers/mapper516.c index 2aaa77af5..172b608f3 100644 --- a/src/boards/mapper516.c +++ b/src/mappers/mapper516.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -23,40 +24,38 @@ #include "mapinc.h" #include "mmc3.h" +static uint8 reg; + static void M516CW(uint32 A, uint8 V) { - /* FCEU_printf("CHR: A:%04x V:%02x R0:%02x\n", A, V, mmc3.expregs[0]); */ - setchr1(A, (V & 0x7F) | ((mmc3.expregs[0] << 5) & 0x180)); +/* FCEU_printf("CHR: A:%04x V:%02x R0:%02x\n", A, V, reg); */ + setchr1(A, ((reg << 5) & 0x180) | (V & 0x7F)); } static void M516PW(uint32 A, uint8 V) { - /* FCEU_printf("PRG: A:%04x V:%02x R0:%02x\n", A, V, mmc3.expregs[0]); */ - setprg8(A, (V & 0x0F) | ((mmc3.expregs[0] << 4) & 0x30)); +/* FCEU_printf("PRG: A:%04x V:%02x R0:%02x\n", A, V, reg); */ + setprg8(A, ((reg << 4) & 0x30) | (V & 0x0F)); } static DECLFW(M516Write) { - /* FCEU_printf("Wr: A:%04x V:%02x R0:%02x\n", A, V, mmc3.expregs[0]); */ +/* FCEU_printf("Wr: A:%04x V:%02x R0:%02x\n", A, V, reg); */ if (A & 0x10) { - mmc3.expregs[0] = A & 0xF; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); - } - if (A < 0xC000) { - MMC3_CMDWrite(A, V); - } else { - MMC3_IRQWrite(A, V); + reg = A & 0x0F; + MMC3_FixPRG(); + MMC3_FixCHR(); } + MMC3_Write(A, V); } static void M516Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); + reg = 0; + MMC3_Power(); SetWriteHandler(0x8000, 0xFFFF, M516Write); } void Mapper516_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 128, 0, 0); - mmc3.cwrap = M516CW; - mmc3.pwrap = M516PW; + MMC3_Init(info, 0, 0); + MMC3_cwrap = M516CW; + MMC3_pwrap = M516PW; info->Power = M516Power; - AddExState(mmc3.expregs, 4, 0, "EXPR"); + AddExState(®, 1, 0, "EXPR"); } diff --git a/src/mappers/mapper517.c b/src/mappers/mapper517.c new file mode 100644 index 000000000..c89756310 --- /dev/null +++ b/src/mappers/mapper517.c @@ -0,0 +1,101 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "latch.h" + +static int32 adc_data; +static int32 adc_high; +static int32 adc_low; +static uint8 adc_state; + +static SFORMAT StateRegs[] = { + { &adc_data, sizeof(adc_data), "DATA" }, + { &adc_high, sizeof(adc_high), "DTHI" }, + { &adc_low, sizeof(adc_low), "DTLO" }, + { &adc_state, sizeof(adc_state), "STAT" }, + { 0 }, +}; + +static void Sync(void) { + setprg16(0x8000, latch.data); + setprg16(0xC000, ~0); + setchr8(0); +} + +static DECLFR(M517Read) { + uint8 result = 0; + if (A == 0x6000) { + switch (adc_state) { + case 0: + adc_state = 1; + result = 0; + break; + case 1: + adc_state = 2; + result = 1; + break; + case 2: + if (adc_low > 0) { + adc_low--; + result = 1; + } else { + adc_state = 0; + result = 0; + } + break; + } + } else { + result = adc_high-- > 0 ? 0 : 1; + } + return result; +} + +static DECLFW(M517Write) { + /* TODO: implement mic input from frontend */ + /* adc_data = MIC * 63.0; */ + adc_data = 0.0 * 63.0; + adc_high = adc_data >> 2; + adc_low = 0x40 - adc_high - ((adc_data & 0x03) << 2); + adc_state = 0; + Latch_Write(A,V); +} + +static void M517Reset(void) { + adc_data = 0; + adc_state = 0; + Sync(); +} + +static void M517Power(void) { + adc_data = 0; + adc_state = 0; + Latch_Power(); + SetReadHandler(0x6000, 0x6FFF, M517Read); + SetWriteHandler(0x8000, 0x8FFF, M517Write); +} + +void Mapper517_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Power = M517Power; + info->Reset = M517Reset; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/dance2000.c b/src/mappers/mapper518.c similarity index 77% rename from src/boards/dance2000.c rename to src/mappers/mapper518.c index a8a90f6f2..314c8ba6a 100644 --- a/src/boards/dance2000.c +++ b/src/mappers/mapper518.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2007 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -24,8 +25,6 @@ #include "mapinc.h" static uint8 prg, mode; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; static uint32 lastnt = 0; static SFORMAT StateRegs[] = @@ -41,39 +40,39 @@ static void Sync(void) { setprg8r(0x10, 0x6000, 0); setchr4(0x0000, lastnt); setchr4(0x1000, 1); - if (mode & 4) + if (mode & 4) { setprg32(0x8000, prg & 7); - else { + } else { setprg16(0x8000, prg & 0x0f); setprg16(0xC000, 0); } } -static DECLFW(UNLD2000Write) { +static DECLFW(M518Write) { switch (A) { case 0x5000: prg = V; Sync(); break; case 0x5200: mode = V; if (mode & 4) Sync(); break; } } -static DECLFR(UNLD2000Read) { +static DECLFR(M518Read) { if (prg & 0x40) - return X.DB; + return cpu.openbus; else return CartBR(A); } -static void UNLD2000Power(void) { +static void M518Power(void) { prg = mode = 0; Sync(); SetReadHandler(0x6000, 0x7FFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetReadHandler(0x8000, 0xFFFF, UNLD2000Read); - SetWriteHandler(0x5000, 0x5FFF, UNLD2000Write); + SetReadHandler(0x8000, 0xFFFF, M518Read); + SetWriteHandler(0x5000, 0x5FFF, M518Write); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } -static void FP_FASTAPASS(1) UNL2000Hook(uint32 A) { +static void M518PPUHook(uint32 A) { if (mode & 2) { if ((A & 0x3000) == 0x2000) { uint32 curnt = A & 0x800; @@ -88,20 +87,17 @@ static void FP_FASTAPASS(1) UNL2000Hook(uint32 A) { } } -static void UNLD2000Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; +static void M518Close(void) { } static void StateRestore(int version) { Sync(); } -void UNLD2000_Init(CartInfo *info) { - info->Power = UNLD2000Power; - info->Close = UNLD2000Close; - PPU_hook = UNL2000Hook; +void Mapper518_Init(CartInfo *info) { + info->Power = M518Power; + info->Close = M518Close; + PPU_hook = M518PPUHook; GameStateRestore = StateRestore; WRAMSIZE = 8192; @@ -109,5 +105,5 @@ void UNLD2000_Init(CartInfo *info) { SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/eh8813a.c b/src/mappers/mapper519.c similarity index 52% rename from src/boards/eh8813a.c rename to src/mappers/mapper519.c index 2b8516276..e756ada64 100644 --- a/src/boards/eh8813a.c +++ b/src/mappers/mapper519.c @@ -1,8 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2015 CaH4e3 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -19,17 +19,17 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* NES 2.0 Mapper 519 +/* NES 2.0 Mapper 519 * UNIF board name UNL-EH8813A */ #include "mapinc.h" #include "latch.h" -static uint8 lock, hw_mode, chr; +static uint8 lock, dipsw, chr, ram[4]; static SFORMAT StateRegs[] = { - { &hw_mode, 1, "HWMO" }, + { &dipsw, 1, "DPSW" }, { &lock, 1, "LOCK" }, { &chr, 1, "CREG" }, { 0 } @@ -37,45 +37,50 @@ static SFORMAT StateRegs[] = { static void Sync(void) { if (lock == 0) { - uint8 prg = (latch.addr & 0x3F); - if (latch.addr & 0x80) { - setprg16(0x8000, prg); - setprg16(0xC000, prg); + setprg16(0x8000, latch.addr); + setprg16(0xC000, latch.addr); } else { - setprg32(0x8000, prg >> 1); + setprg32(0x8000, latch.addr >> 1); } - - setmirror(((latch.data >> 7) & 1) ^ 1); - - lock = (latch.addr & 0x100) >> 8; + setmirror(((latch.data >> 7) & 0x01) ^ 0x01); + lock = (latch.addr & 0x100) == 0x100; chr = latch.data & 0x7C; } + setchr8(chr | (latch.data & 0x03)); +} - setchr8(chr | latch.data); +static DECLFR(M519ReadRAM) { + return ram[A & 0x03]; } -static DECLFR(EH8813ARead) { - if (latch.addr & 0x40) - A = (A & 0xFFF0) + hw_mode; +static DECLFW(M519WriteRAM) { + ram[A & 0x03] = V & 0x0F; +} + +static DECLFR(M519Read) { + if (latch.addr & 0x40) { + return CartBR((A & 0xFFF0) | (dipsw & 0x0F)); + } return CartBR(A); } -static void EH8813APower(void) { - hw_mode = lock = 0; - LatchPower(); +static void M519Power(void) { + dipsw = lock = 0; + Latch_Power(); + SetReadHandler(0x5800, 0x5FFF, M519ReadRAM); + SetWriteHandler(0x5800, 0x5FFF, M519WriteRAM); } -static void EH8813AReset(void) { +static void M519Reset(void) { lock = 0; - hw_mode = (hw_mode + 1) & 0xF; - FCEU_printf("Hardware Switch is %01X\n", hw_mode); - LatchHardReset(); + dipsw++; + Latch_RegReset(); } -void UNLEH8813A_Init(CartInfo *info) { - Latch_Init(info, Sync, EH8813ARead, 0, 0); - info->Reset = EH8813AReset; - info->Power = EH8813APower; - AddExState(&StateRegs, ~0, 0, 0); +void Mapper519_Init(CartInfo *info) { + Latch_Init(info, Sync, M519Read, FALSE, FALSE); + info->Reset = M519Reset; + info->Power = M519Power; + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/mapper520.c b/src/mappers/mapper520.c similarity index 74% rename from src/boards/mapper520.c rename to src/mappers/mapper520.c index 8c71b19ea..e9f6d9700 100644 --- a/src/boards/mapper520.c +++ b/src/mappers/mapper520.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -23,7 +23,7 @@ */ #include "mapinc.h" -#include "vrc24.h" +#include "vrc2and4.h" static uint8 PPUCHRBus; @@ -33,21 +33,25 @@ static SFORMAT StateRegs[] = { }; static void M520PW(uint32 A, uint8 V) { - setprg8(A, ((vrc24.chrreg[PPUCHRBus] << 2) & 0x20) | (V & 0x1F)); + setprg8(A, ((vrc24.chr[PPUCHRBus] << 2) & 0x20) | (V & 0x1F)); } -static void FP_FASTAPASS(1) M520PPUHook(uint32 A) { +static void M520CW(uint32 A, uint32 V) { + setchr1(A, V & 0x07); +} + +static void M520PPUHook(uint32 A) { uint8 bank = (A & 0x1FFF) >> 10; if ((PPUCHRBus != bank) && ((A & 0x3000) != 0x2000)) { PPUCHRBus = bank; - FixVRC24PRG(); - FixVRC24CHR(); + VRC24_FixPRG(); } } void Mapper520_Init(CartInfo *info) { - GenVRC24_Init(info, VRC4e, 0); + VRC24_Init(info, VRC4, 0x04, 0x08, 0, 1); PPU_hook = M520PPUHook; - vrc24.pwrap = M520PW; - AddExState(StateRegs, ~0, 0, 0); + VRC24_pwrap = M520PW; + VRC24_cwrap = M520CW; + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/dream.c b/src/mappers/mapper521.c similarity index 73% rename from src/boards/dream.c rename to src/mappers/mapper521.c index bdc43947f..3212daf59 100644 --- a/src/boards/dream.c +++ b/src/mappers/mapper521.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -20,32 +21,32 @@ #include "mapinc.h" -static uint8 latche; +static uint8 prg; static void Sync(void) { - setprg16(0x8000, latche); - setprg16(0xC000, 8); + setprg16(0x8000, prg); + setprg16(0xC000, 0x08); + setchr8(0); } -static DECLFW(DREAMWrite) { - latche = V & 7; +static DECLFW(M521Write) { + prg = V; Sync(); } -static void DREAMPower(void) { - latche = 0; +static void M521Power(void) { + prg = 0; Sync(); - setchr8(0); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x5020, 0x5020, DREAMWrite); + SetWriteHandler(0x5020, 0x5020, M521Write); } static void Restore(int version) { Sync(); } -void DreamTech01_Init(CartInfo *info) { +void Mapper521_Init(CartInfo *info) { GameStateRestore = Restore; - info->Power = DREAMPower; - AddExState(&latche, 1, 0, "LATC"); + info->Power = M521Power; + AddExState(&prg, 1, 0, "LATC"); } diff --git a/src/mappers/mapper522.c b/src/mappers/mapper522.c new file mode 100644 index 000000000..c7302892e --- /dev/null +++ b/src/mappers/mapper522.c @@ -0,0 +1,83 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2011 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 522 - UNL-LH10 + * + */ + +#include "mapinc.h" +#include "fdssound.h" + +static uint8 reg[8], cmd; + +static SFORMAT StateRegs[] = +{ + { &cmd, 1, "CMD" }, + { reg, 8, "REGS" }, + { 0 } +}; + +static void Sync(void) { + setprg8(0x6000, ~1); + setprg8(0x8000, reg[6]); + setprg8(0xA000, reg[7]); + setprg8r(0x10, 0xC000, 0); + setprg8(0xE000, ~0); + setchr8(0); + setmirror(0); +} + +static DECLFW(M522Write) { + if (A & 0x0001) { + reg[cmd & 0x07] = V; + Sync(); + } else { + cmd = V; + } +} + +static void M522Power(void) { + FDSSound_Power(); + reg[0] = reg[1] = reg[2] = reg[3] = reg[4] = reg[5] = reg[6] = reg[7] = 0; + Sync(); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0x9FFF, M522Write); + SetWriteHandler(0xC000, 0xDFFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); +} + +static void M522Close(void) { +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper522_Init(CartInfo *info) { + info->Power = M522Power; + info->Close = M522Close; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + + WRAMSIZE = 8192; + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); +} diff --git a/src/boards/btl900218.c b/src/mappers/mapper524.c similarity index 72% rename from src/boards/btl900218.c rename to src/mappers/mapper524.c index a5fba5cb2..02c3b2a97 100644 --- a/src/boards/btl900218.c +++ b/src/mappers/mapper524.c @@ -2,7 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2007 CaH4e3 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -19,29 +19,30 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* -------------------- BTL-900218 -------------------- */ +/* NES 2.0 Mapper 524 - 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. */ #include "mapinc.h" -#include "vrc24.h" +#include "vrc2and4.h" static uint16 IRQCount; -static uint8 IRQLatch, IRQa; +static uint8 IRQa; static SFORMAT IRQStateRegs[] = { { &IRQCount, 2, "IRQC" }, - { &IRQLatch, 1, "IRQL" }, { &IRQa, 1, "IRQA" }, { 0 } }; -static DECLFW(BTL900218Write) { +static DECLFW(M524Write) { switch (A & 0xF00C) { - case 0xF008: IRQa = 1; break; + case 0xF008: + IRQa = 1; + break; case 0xF00C: IRQa = 0; IRQCount = 0; @@ -50,7 +51,7 @@ static DECLFW(BTL900218Write) { } } -void FP_FASTAPASS(1) BTL900218IRQHook(int a) { +static void M524IRQHook(int a) { if (!IRQa) return; @@ -59,15 +60,15 @@ void FP_FASTAPASS(1) BTL900218IRQHook(int a) { X6502_IRQBegin(FCEU_IQEXT); } -static void BTL900218Power(void) { - IRQa = IRQCount = IRQLatch = 0; - GenVRC24Power(); - SetWriteHandler(0xF000, 0xFFFF, BTL900218Write); +static void M524Power(void) { + IRQa = IRQCount = 0; + VRC24_Power(); + SetWriteHandler(0xF000, 0xFFFF, M524Write); } -void BTL900218_Init(CartInfo *info) { - GenVRC24_Init(info, VRC2b, 1); - info->Power = BTL900218Power; - MapIRQHook = BTL900218IRQHook; +void Mapper524_Init(CartInfo *info) { + VRC24_Init(info, VRC2, 0x01, 0x02, 0, 1); + info->Power = M524Power; + MapIRQHook = M524IRQHook; AddExState(IRQStateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper525.c b/src/mappers/mapper525.c new file mode 100644 index 000000000..15c45c103 --- /dev/null +++ b/src/mappers/mapper525.c @@ -0,0 +1,87 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 Mapper 525 - UNL-M525 + * 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. + */ + +#include "mapinc.h" + +static uint8 prg; +static uint8 chr[8]; +static uint8 mirr; + +static SFORMAT StateRegs[] = { + { chr, 8, "CHRR" }, + { &prg, 1, "PRGR" }, + { &mirr, 1, "MIRR" }, + { 0 } +}; + +static void Sync(void) { + setprg16(0x8000, prg >> 1); + setprg16(0xC000, ~0); + + setchr1(0x0000, chr[0]); + setchr1(0x0400, chr[1]); + setchr1(0x0800, chr[2]); + setchr1(0x0C00, chr[3]); + setchr1(0x1000, chr[4]); + setchr1(0x1400, chr[5]); + setchr1(0x1800, chr[6]); + setchr1(0x1C00, chr[7]); + + setmirror((mirr & 0x01) ^ 0x01); +} + +static DECLFW(M525WritePRG) { + prg = V; + Sync(); +} + +static DECLFW(M525WriteMIR) { + prg = V; + Sync(); +} + +static DECLFW(M525WriteCHR) { + chr[A & 0x07] = V; + Sync(); +} + +static void M525Power(void) { + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0x8FFF, M525WritePRG); + SetWriteHandler(0x9000, 0x9FFF, M525WriteMIR); + SetWriteHandler(0xB000, 0xBFFF, M525WriteCHR); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper525_Init(CartInfo *info) { + info->Power = M525Power; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/bj56.c b/src/mappers/mapper526.c similarity index 57% rename from src/boards/bj56.c rename to src/mappers/mapper526.c index a0ba32f8b..a15e8b0de 100644 --- a/src/boards/bj56.c +++ b/src/mappers/mapper526.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -26,75 +27,78 @@ #include "mapinc.h" -static uint8 preg[4], creg[8]; +static uint8 prg[4], chr[8]; static uint32 IRQCount; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; -static SFORMAT StateRegs[] = -{ - { preg, 4, "PREG" }, - { creg, 8, "CREG" }, +static SFORMAT StateRegs[] = { + { prg, 4, "PREG" }, + { chr, 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]); + + setprg8(0x8000, prg[0]); + setprg8(0xA000, prg[1]); + setprg8(0xC000, prg[2]); + setprg8(0xE000, prg[3]); + + setchr1(0x0000, chr[0]); + setchr1(0x0400, chr[1]); + setchr1(0x0800, chr[2]); + setchr1(0x0C00, chr[3]); + setchr1(0x1000, chr[4]); + setchr1(0x1400, chr[5]); + setchr1(0x1800, chr[6]); + setchr1(0x1C00, chr[7]); + setmirror(MI_V); } -static DECLFW(UNLBJ56Write) { +static DECLFW(M526Write) { /* FCEU_printf("Wr: A:%04x V:%02x\n", A, V); */ - A &= 0xF00F; - if (A <= 0x8007) { - creg[A & 0x07] = V; + switch (A & 0x0F) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + chr[A & 0x07] = V; Sync(); - } else if (A <= 0x800B) { - preg[A & 0x03] = V; + break; + case 0x08: case 0x09: case 0x0A: case 0x0B: + prg[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; - } + break; + 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) { +static void M526IRQHook(int a) { IRQCount += a; - if (IRQCount & 4096) + if (IRQCount & 0x1000) { X6502_IRQBegin(FCEU_IQEXT); + } } -static void UNLBJ56Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; +static void M526Close(void) { } -static void UNLBJ56Power(void) { - preg[0] = ~3; - preg[1] = ~2; - preg[2] = ~1; - preg[3] = ~0; +static void M526Power(void) { + prg[0] = ~3; + prg[1] = ~2; + prg[2] = ~1; + prg[3] = ~0; Sync(); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetWriteHandler(0x8000, 0x800F, UNLBJ56Write); + SetWriteHandler(0x8000, 0x800F, M526Write); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } @@ -102,10 +106,10 @@ static void StateRestore(int version) { Sync(); } -void UNLBJ56_Init(CartInfo *info) { - info->Power = UNLBJ56Power; - info->Close = UNLBJ56Close; - MapIRQHook = UNLBJ56IRQHook; +void Mapper526_Init(CartInfo *info) { + info->Power = M526Power; + info->Close = M526Close; + MapIRQHook = M526IRQHook; GameStateRestore = StateRestore; WRAMSIZE = 8192; WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); @@ -115,5 +119,5 @@ void UNLBJ56_Init(CartInfo *info) { info->SaveGameLen[0] = WRAMSIZE; } AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/ax40g.c b/src/mappers/mapper527.c similarity index 78% rename from src/boards/ax40g.c rename to src/mappers/mapper527.c index 1ab85ddea..1a6a00dac 100644 --- a/src/boards/ax40g.c +++ b/src/mappers/mapper527.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -26,14 +27,14 @@ */ #include "mapinc.h" -#include "vrc24.h" +#include "vrc2and4.h" -static void UNLAX40GCW(uint32 A, uint32 V) { +static void M527CW(uint32 A, uint32 V) { setchr1(A, V); - setmirrorw((vrc24.chrhi[0] >> 3) & 1, (vrc24.chrhi[0] >> 3) & 1, (vrc24.chrhi[1] >> 3) & 1, (vrc24.chrhi[1] >> 3) & 1); + setmirrorw((vrc24.chr[0] >> 7) & 1, (vrc24.chr[0] >> 7) & 1, (vrc24.chr[1] >> 7) & 1, (vrc24.chr[1] >> 7) & 1); } -void UNLAX40G_Init(CartInfo *info) { - GenVRC24_Init(info, VRC2b, 0); - vrc24.cwrap = UNLAX40GCW; +void Mapper527_Init(CartInfo *info) { + VRC24_Init(info, VRC2, 0x01, 0x02, 0, 1); + VRC24_cwrap = M527CW; } diff --git a/src/mappers/mapper528.c b/src/mappers/mapper528.c new file mode 100644 index 000000000..cfc5e9d4a --- /dev/null +++ b/src/mappers/mapper528.c @@ -0,0 +1,98 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 528 + * UNIF BMC-831128C + */ + +#include "mapinc.h" +#include "fme7.h" +#include "vrcirq.h" + +static uint8 reg; + +static SFORMAT StateRegs[] = { + { ®, 1, "REGS" }, + { 0 } +}; + +static void M528CW(uint32 A, uint8 V) { + uint16 mask = 0xFF; + uint16 base = reg << 4; + + setchr1(A, (base | (V & mask))); +} + +static void M528PW(uint32 A, uint8 V) { + uint16 base = reg; + uint16 mask = base | 0x0F; + + setprg8(A, base + (V & mask)); +} + +static void M528SyncWRAM(void) { + uint16 base = reg; + uint16 mask = base | 0x0F; + + if (fme7.prg[0] == 1) { + setprg8r(0x10, 0x6000, 0); + } else { + setprg8(0x6000, (base + (fme7.prg[0] & mask))); + } +} + +static DECLFW(M528Write) { + switch (A & 0x0F) { + case 0x0B: break; + case 0x0D: VRCIRQ_Control(V); break; + case 0x0E: VRCIRQ_Acknowledge(); break; + case 0x0F: VRCIRQ_Latch(V); break; + default: + FME7_WriteIndex(0x8000, A & 0x0F); + FME7_WriteReg(0xA000, V); + break; + } + reg = (A & 0x4000) >> 10; + FME7_FixPRG(); + FME7_FixCHR(); + FME7_FixWRAM(); +} + +static void M528Power(void) { + reg = 0; + FME7_Power(); + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + SetWriteHandler(0xA000, 0xAFFF, M528Write); + SetWriteHandler(0xC000, 0xCFFF, M528Write); +} + +void Mapper528_Init(CartInfo *info) { + FME7_Init(info, TRUE, info->battery); + FME7_FixWRAM = M528SyncWRAM; + FME7_pwrap = M528PW; + FME7_cwrap = M528CW; + info->Power = M528Power; + AddExState(StateRegs, ~0, 0, NULL); + + VRCIRQ_Init(TRUE); + MapIRQHook = VRCIRQ_CPUHook; + AddExState(&VRCIRQ_StateRegs, ~0, 0, 0); +} diff --git a/src/boards/t230.c b/src/mappers/mapper529.c similarity index 61% rename from src/boards/t230.c rename to src/mappers/mapper529.c index 975ec5230..061739c4e 100644 --- a/src/boards/t230.c +++ b/src/mappers/mapper529.c @@ -2,7 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2007 CaH4e3 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -24,53 +24,47 @@ */ #include "mapinc.h" -#include "vrc24.h" -#include "eeprom_93C66.h" +#include "vrc2and4.h" +#include "eeprom_93Cx6.h" static uint8 haveEEPROM; static uint8 eeprom_data[256]; -static void UNLT230PRGSync(uint32 A, uint8 V) { - switch (A) { - case 0x8000: - setprg16(0x8000, vrc24.prgreg[1]); - break; - case 0xC000: - setprg16(0xC000, ~0); - break; - } +static void M529PW(uint32 A, uint8 V) { + setprg16(0x8000, vrc24.prg[1]); + setprg16(0xC000, ~0); } -static DECLFR(UNLT230EEPROMRead) { +static DECLFR(M529EEPROMRead) { if (haveEEPROM) { - return eeprom_93C66_read() ? 0x01 : 0x00; + return eeprom_93Cx6_read() ? 0x01 : 0x00; } return 0x01; } -static DECLFW(UNLT230Write) { +static DECLFW(M529Write) { if (A & 0x800) { if (haveEEPROM) { - eeprom_93C66_write(!!(A & 0x04), !!(A & 0x02), !!(A & 0x01)); + eeprom_93Cx6_write(!!(A & 0x04), !!(A & 0x02), !!(A & 0x01)); } } else { - VRC24Write(A, V); + VRC24_Write(A, V); } } -static void UNLT230Power(void) { - GenVRC24Power(); - SetReadHandler(0x5000, 0x5FFF, UNLT230EEPROMRead); - SetWriteHandler(0x8000, 0xFFFF, UNLT230Write); +static void M529Power(void) { + VRC24_Power(); + SetReadHandler(0x5000, 0x5FFF, M529EEPROMRead); + SetWriteHandler(0x8000, 0xFFFF, M529Write); } -void UNLT230_Init(CartInfo *info) { +void Mapper529_Init(CartInfo *info) { haveEEPROM = (info->PRGRamSaveSize & 0x100) != 0; - GenVRC24_Init(info, VRC4e, !haveEEPROM); - info->Power = UNLT230Power; - vrc24.pwrap = UNLT230PRGSync; + VRC24_Init(info, VRC4, 0x04, 0x08, !haveEEPROM, 1); + info->Power = M529Power; + VRC24_pwrap = M529PW; if (haveEEPROM) { - eeprom_93C66_init(eeprom_data, 256, 16); + eeprom_93Cx6_init(eeprom_data, 256, 16); info->battery = 1; info->SaveGame[0] = eeprom_data; info->SaveGameLen[0] = 256; diff --git a/src/boards/ax5705.c b/src/mappers/mapper530.c similarity index 62% rename from src/boards/ax5705.c rename to src/mappers/mapper530.c index b6704369e..e5e8e3688 100644 --- a/src/boards/ax5705.c +++ b/src/mappers/mapper530.c @@ -1,8 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2007 CaH4e3 - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -23,29 +23,33 @@ */ #include "mapinc.h" -#include "vrc24.h" - -static void PRGWrap(uint32 A, uint8 V) { - setprg8(A, ((V & 0x02) << 2) | ((V & 0x08) >> 2) | (V & ~0x0A)); -} - -static void CHRWrap(uint32 A, uint32 V) { - setchr1(A, ((V & 0x40) >> 1) | ((V & 0x20) << 1) | (V & ~0x60)); -} +#include "vrc2and4.h" static DECLFW(UNLAX5705Write) { - A |= (A & 0x08) << 9; - VRC24Write(A, V); + A |= (A & 0x0008) ? 0x1000 : 0x0000; + switch (A & 0xF000) { + case 0x8000: + case 0xA000: + V = ((V & 0x02) << 2) | ((V & 0x08) >> 2) | (V & 0x05); + break; + case 0xB000: + case 0xC000: + case 0xD000: + case 0xE000: + if (A & 0x0001) { + V = ((V & 0x04) >> 1) | ((V & 0x02) << 1) | (V & 0x09); + } + break; + } + VRC24_Write(A, V); } -static void UNLAX5705Power(void) { - GenVRC24Power(); +static void M530Power(void) { + VRC24_Power(); SetWriteHandler(0x8000, 0xFFFF, UNLAX5705Write); } -void UNLAX5705_Init(CartInfo *info) { - GenVRC24_Init(info, VRC4f, 0); - info->Power = UNLAX5705Power; - vrc24.pwrap = PRGWrap; - vrc24.cwrap = CHRWrap; +void Mapper530_Init(CartInfo *info) { + VRC24_Init(info, VRC4, 0x01, 0x02, 0, 1); + info->Power = M530Power; } diff --git a/src/boards/mapper533.c b/src/mappers/mapper533.c similarity index 84% rename from src/boards/mapper533.c rename to src/mappers/mapper533.c index 500421ff4..14e478fc6 100644 --- a/src/boards/mapper533.c +++ b/src/mappers/mapper533.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 + * Copyright (C) 2023 * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -30,16 +30,19 @@ static void Sync(void) { setprg32(0x8000, 0); - setchr8((latch.data >> 4) & 1); + setchr8((latch.data >> 4) & 0x01); } static DECLFR(M533Read) { - if ((A & 0xF000) == 0xE000) { - return ((PRGptr[0][0x6000 | A] & 0xF0) | (latch.data >> 4)); + switch (A & 0xF000) { + case 0xE000: + return ((PRGptr[0][0x6000 | (A & 0xFFFF)] & 0xF0) | (latch.data >> 4)); + default: + break; } return CartBROB(A); } void Mapper533_Init(CartInfo *info) { - Latch_Init(info, Sync, M533Read, 0, 1); + Latch_Init(info, Sync, M533Read, FALSE, TRUE); } diff --git a/src/boards/lh53.c b/src/mappers/mapper535.c similarity index 61% rename from src/boards/lh53.c rename to src/mappers/mapper535.c index 1ee159232..3d31f637e 100644 --- a/src/boards/lh53.c +++ b/src/mappers/mapper535.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2007 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -17,17 +18,16 @@ * 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 535 - UNL-M535 * FDS Conversion - Nazo no Murasamejō * */ #include "mapinc.h" -#include "../fds_apu.h" +#include "fdssound.h" static uint8 reg, IRQa; static int32 IRQCount; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; static SFORMAT StateRegs[] = { @@ -40,71 +40,60 @@ static SFORMAT StateRegs[] = static void Sync(void) { setchr8(0); setprg8(0x6000, reg); - setprg8(0x8000, 0xc); - setprg4(0xa000, (0xd << 1)); - setprg2(0xb000, (0xd << 2) + 2); - setprg2r(0x10, 0xb800, 4); - setprg2r(0x10, 0xc000, 5); - setprg2r(0x10, 0xc800, 6); - setprg2r(0x10, 0xd000, 7); - setprg2(0xd800, (0xe << 2) + 3); - setprg8(0xe000, 0xf); + setprg32(0x8000, 0x03); + setprg8r(0x10, 0xB800, 0); } -static DECLFW(LH53RamWrite) { +static DECLFW(M535RamWrite) { WRAM[(A - 0xB800) & 0x1FFF] = V; } -static DECLFW(LH53Write) { +static DECLFW(M535Write) { reg = V; Sync(); } -static DECLFW(LH53IRQaWrite) { - IRQa = V & 2; +static DECLFW(M535IRQaWrite) { + IRQa = V & 0x02; IRQCount = 0; - if (!IRQa) - X6502_IRQEnd(FCEU_IQEXT); + X6502_IRQEnd(FCEU_IQEXT); } -static void FP_FASTAPASS(1) LH53IRQ(int a) { +static void M535IRQHook(int a) { if (IRQa) { IRQCount += a; - if (IRQCount > 7560) + if (IRQCount > 7560) { X6502_IRQBegin(FCEU_IQEXT); + } } } -static void LH53Power(void) { - FDSSoundPower(); +static void M535Power(void) { + FDSSound_Power(); Sync(); SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0xB800, 0xD7FF, LH53RamWrite); - SetWriteHandler(0xE000, 0xEFFF, LH53IRQaWrite); - SetWriteHandler(0xF000, 0xFFFF, LH53Write); + SetWriteHandler(0xB800, 0xD7FF, M535RamWrite); + SetWriteHandler(0xE000, 0xEFFF, M535IRQaWrite); + SetWriteHandler(0xF000, 0xFFFF, M535Write); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); } -static void LH53Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; +static void M535Close(void) { } static void StateRestore(int version) { Sync(); } -void LH53_Init(CartInfo *info) { - info->Power = LH53Power; - info->Close = LH53Close; - MapIRQHook = LH53IRQ; +void Mapper535_Init(CartInfo *info) { + info->Power = M535Power; + info->Close = M535Close; + MapIRQHook = M535IRQHook; GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); 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/mappers/mapper538.c b/src/mappers/mapper538.c new file mode 100644 index 000000000..de337cf2f --- /dev/null +++ b/src/mappers/mapper538.c @@ -0,0 +1,80 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 538 denotes the 60-1064-16L PCB, used for a + * bootleg cartridge conversion named Super Soccer Champion + * of the Konami FDS game Exciting Soccer. + */ + +#include "mapinc.h" +#include "latch.h" +#include "fdssound.h" + +/* this code emulates rom dump with wrong bank order */ +static uint8 M538Banks[16] = { + 0, 1, 2, 1, 3, 1, 4, 1, + 5, 5, 1, 1, 6, 6, 7, 7 +}; + +static void Sync_alt(void) { + setprg8(0x6000, (latch.data >> 1) | 8); + setprg8(0x8000, M538Banks[latch.data & 0x0F]); + setprg8(0xA000, 14); + setprg8(0xC000, 7); + setprg8(0xE000, 15); + setchr8(0); + setmirror(1); +} + +static void Sync(void) { + setprg8(0x6000, latch.data | 1); + setprg8(0x8000, (latch.data & 1) && (~latch.data & 8) ? 10 : (latch.data & ~1)); + setprg8(0xA000, 13); + setprg8(0xC000, 14); + setprg8(0xE000, 15); + setchr8(0); + setmirror(MI_V); +} + +static DECLFW(M538Write) { + switch (A & 0xF000) { + case 0xC000: + case 0xD000: + latch.data = V; + Sync(); + break; + } +} + +static void M538Power(void) { + FDSSound_Power(); + Latch_RegReset(); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M538Write); +} + +void Mapper538_Init(CartInfo *info) { + if (info->CRC32 == 0xA8C6D77D) { + Latch_Init(info, Sync_alt, NULL, 0, 0); + } + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Power = M538Power; +} diff --git a/src/mappers/mapper539.c b/src/mappers/mapper539.c new file mode 100644 index 000000000..5a31b3372 --- /dev/null +++ b/src/mappers/mapper539.c @@ -0,0 +1,115 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 - Kid Icarus (パルテナの鏡) (Parthena) */ + +#include "mapinc.h" +#include "fdssound.h" + +static uint8 prg; +static uint8 mirr; + +static SFORMAT StateRegs[] = { + { &prg, 1, "PREG" }, + { &mirr, 1, "MIRR" }, + { 0 } +}; + +static void Sync(void) { + setprg8(0x6000, 0x0D); + setprg8(0x8000, 0x0C); + setprg8(0xA000, prg & 0x0F); + setprg8(0xC000, 0x0E); + setprg8(0xE000, 0x0F); + setchr8(0); + setmirror(((mirr & 8) >> 3) ^ 1); +} + +static DECLFR(M539ReadWRAM) { + A = (((A) & 0x1FFF) | (((A) < 0xC000) ? 0x1000 : 0x0000) | (((A) < 0x8000) ? 0x800 : 0x000)); + return WRAM[A]; +} + +static DECLFW(M539WriteWRAM) { + A = (((A) & 0x1FFF) | (((A) < 0xC000) ? 0x1000 : 0x0000) | (((A) < 0x8000) ? 0x800 : 0x000)); + WRAM[A] = V; +} + +static DECLFW(M539WritePRG) { + prg = V; + Sync(); +} + +static DECLFW(M539WriteMirroring) { + if ((A & 0x25) == 0x25) { + mirr = V; + Sync(); + } +} + +static void M539Power(void) { + FDSSound_Power(); + prg = 0; + mirr = 0; + Sync(); + + SetReadHandler(0x6000, 0xFFFF, CartBR); + + SetWriteHandler(0xA000, 0xAFFF, M539WritePRG); + SetWriteHandler(0xF000, 0xFFFF, M539WriteMirroring); + + /* Certain ranges in the CPU address space are overlaid with portions of 8 KiB of PRG-RAM as follows: + * CPU $6000-$60FF + * CPU $6200-$62FF + * CPU $6400-$65FF + * CPU $8200-$82FF + * CPU $C000-$D1FF + * CPU $DF00-$DFFF + */ + + SetReadHandler(0x6000, 0x60FF, M539ReadWRAM); + SetReadHandler(0x6200, 0x62FF, M539ReadWRAM); + SetReadHandler(0x6400, 0x65FF, M539ReadWRAM); + SetReadHandler(0x8200, 0x82FF, M539ReadWRAM); + SetReadHandler(0xC000, 0xD1FF, M539ReadWRAM); + SetReadHandler(0xDF00, 0xDFFF, M539ReadWRAM); + + SetWriteHandler(0x6000, 0x60FF, M539WriteWRAM); + SetWriteHandler(0x6200, 0x62FF, M539WriteWRAM); + SetWriteHandler(0x6400, 0x65FF, M539WriteWRAM); + SetWriteHandler(0x8200, 0x82FF, M539WriteWRAM); + SetWriteHandler(0xC000, 0xD1FF, M539WriteWRAM); + SetWriteHandler(0xDF00, 0xDFFF, M539WriteWRAM); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper539_Init(CartInfo *info) { + info->Power = M539Power; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + + WRAMSIZE = 8192; + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, TRUE); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); +} diff --git a/src/mappers/mapper541.c b/src/mappers/mapper541.c new file mode 100644 index 000000000..c6a22273b --- /dev/null +++ b/src/mappers/mapper541.c @@ -0,0 +1,54 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + * + */ + +/* LittleCom 160-in-1 multicart */ + +#include "mapinc.h" +#include "latch.h" + +static void Sync(void) { + if (latch.addr & 2) { /* NROM-128 */ + setprg16(0x8000, latch.addr >> 2); + setprg16(0xC000, latch.addr >> 2); + } else { /* NROM=256 */ + setprg32(0x8000, latch.addr >> 3); + } + setchr8(0); + setmirror(latch.addr & 0x01); +} + +static void M541Write(uint32 A, uint8 V) { + if (A >= 0xC000) { + latch.addr = A; + Sync(); + } +} + +static void M541Power(void) { + Latch_Power(); + SetWriteHandler(0x8000, 0xFFFF, M541Write); +} + +void Mapper541_Init(CartInfo *info) { + Latch_Init(info, Sync, NULL, FALSE, FALSE); + info->Power = M541Power; + info->Reset = Latch_RegReset; +} diff --git a/src/mappers/mapper543.c b/src/mappers/mapper543.c new file mode 100644 index 000000000..1120e095f --- /dev/null +++ b/src/mappers/mapper543.c @@ -0,0 +1,90 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 543 - 1996 無敵智カ卡 5-in-1 (CH-501) */ +/* NOTE: needs RAM to be initialized to all 0x00 */ + +#include "mapinc.h" +#include "mmc1.h" + +static uint8 reg; +static uint8 bits; +static uint8 shift; + +static SFORMAT StateRegs[] = { + { &bits, 1, "BITS" }, + { &shift, 1, "SHFT" }, + { ®, 1, "REG0" }, + { 0 } +}; + +static void M543PW(uint32 A, uint8 V) { + setprg16(A, (reg << 4) | (V & 0x0F)); +} + +static void M543CW(uint32 A, uint8 V) { + setchr4(A, (V & 0x07)); +} + +static void M543WW(void) { + uint32 wramBank; + + if (reg & 0x02) { + wramBank = 0x04 | ((reg >> 1) & 0x02) | (reg & 0x01) ; + } else { + wramBank = ((reg << 1) & 0x02) | ((MMC1_GetCHRBank(0) >> 3) & 0x01); + } + setprg8r(0x10, 0x6000, wramBank); +} + +static DECLFW(M543Write) { + bits |= ((V >> 3) & 0x01) << shift++; + if (shift == 4) { + reg = bits; + bits = shift = 0; + MMC1_FixPRG(); + MMC1_FixCHR(); + } +} + +static void M543Reset(void) { + bits = 0; + shift = 0; + reg = 0; + MMC1_Reset(); +} + +static void M543Power(void) { + bits = 0; + shift = 0; + reg = 0; + MMC1_Power(); + SetWriteHandler(0x5000, 0x5FFF, M543Write); +} + +void Mapper543_Init(CartInfo *info) { + MMC1_Init(info, 64, info->battery ? 64 : 0); + info->Power = M543Power; + info->Reset = M543Reset; + MMC1_cwrap = M543CW; + MMC1_pwrap = M543PW; + MMC1_wwrap = M543WW; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/boards/mapper544.c b/src/mappers/mapper544.c similarity index 79% rename from src/boards/mapper544.c rename to src/mappers/mapper544.c index f80f6b8de..b9e1c7cf3 100644 --- a/src/boards/mapper544.c +++ b/src/mappers/mapper544.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -20,7 +20,7 @@ /* NES 2.0 Mapper 544 - Waixing FS306 */ #include "mapinc.h" -#include "vrc24.h" +#include "vrc2and4.h" static uint8 nt[4]; static uint8 cpuC; @@ -35,8 +35,10 @@ static writefunc writePPU; extern uint32 RefreshAddr; static SFORMAT StateRegs[] = { - { &cpuC, 1, "CPUC" }, { nt, 4, "NTBL" }, + { &cpuC, 1, "CPUC" }, + { &chrRamMask, 1, "CHRM" }, + { &chrRamCompare, 1, "CHRB" }, { 0 }, }; @@ -57,17 +59,13 @@ static void M544CW(uint32 A, uint32 V) { } static DECLFW(M544WriteExtra) { - if ((A & 0xC00) == 0xC00) { - if (A & 0x04) { - nt[A & 0x03] = V & 0x01; - setmirrorw(nt[0], nt[1], nt[2], nt[3]); - } else { - cpuC = V; - FixVRC24PRG(); - } - } else { - VRC24Write(A, V); - } + if (A & 0x04) { + nt[A & 0x03] = V & 0x01; + setmirrorw(nt[0], nt[1], nt[2], nt[3]); + } else { + cpuC = V; + VRC24_FixPRG(); + } } static const uint8 compareMasks[8] = { @@ -77,7 +75,7 @@ static const uint8 compareMasks[8] = { static DECLFW(M544PPUWrite) { if (RefreshAddr < 0x2000) { uint8 reg = RefreshAddr >> 10; - uint8 chrBank = (vrc24.chrhi[reg] << 4) | vrc24.chrreg[reg]; + uint8 chrBank = vrc24.chr[reg]; if (chrBank & 0x80) { if (chrBank & 0x10) { chrRamMask = 0x00; @@ -86,7 +84,7 @@ static DECLFW(M544PPUWrite) { chrRamMask = (chrBank & 0x40) ? 0xFE : 0xFC; chrRamCompare = compareMasks[((chrBank >> 1) & 0x01) | ((chrBank >> 2) & 0x02) | ((chrBank >> 4) & 0x04)]; } - FixVRC24CHR(); + VRC24_FixCHR(); } } writePPU(A, V); @@ -100,13 +98,12 @@ static void M544Power(void) { nt[2] = 1; nt[3] = 1; cpuC = ~1; - GenVRC24Power(); + VRC24_Power(); writePPU = GetWriteHandler(0x2007); SetWriteHandler(0x2007, 0x2007, M544PPUWrite); - SetWriteHandler(0x9000, 0x9FFF, M544WriteExtra); } -void M544Close(void) { +static void M544Close(void) { if (CHRRAM) { FCEU_gfree(CHRRAM); } @@ -114,17 +111,16 @@ void M544Close(void) { } void Mapper544_Init(CartInfo *info) { - GenVRC24_Init(info, VRC4_544, 1); + VRC24_Init(info, VRC4, 0x400, 0x800, 1, 1); info->Power = M544Power; info->Close = M544Close; - vrc24.pwrap = M544PW; - vrc24.cwrap = M544CW; + VRC24_pwrap = M544PW; + VRC24_cwrap = M544CW; + VRC24_miscWrite = M544WriteExtra; + AddExState(StateRegs, ~0, 0, NULL); CHRRAMSIZE = 2048; CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); - - AddExState(&chrRamMask, 1, 0, "CHRM"); - AddExState(&chrRamCompare, 1, 0, "CHRB"); } diff --git a/src/mappers/mapper547.c b/src/mappers/mapper547.c new file mode 100644 index 000000000..6aab08099 --- /dev/null +++ b/src/mappers/mapper547.c @@ -0,0 +1,226 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2005-2019 CaH4e3 (FCEUX) + * Copyright (C) 2024 negativeExponent + * + * 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 + * + * VRC-V (CAI Shogakko no Sansu) + * + */ + +#include "mapinc.h" + +static uint32 CHRSIZE; +static uint8 *CHRRAM = NULL; + +static uint8 reg[16]; +static uint8 IRQa; +static uint8 IRQr; +static uint32 IRQLatch; +static uint32 IRQCount; + +static SFORMAT StateRegs[] = { + { QTRAM, 0x800, "QTAR" }, + { reg, 6, "REGS" }, + { &IRQCount, 4, "IRQC" }, + { &IRQLatch, 4, "IRQL" }, + { &IRQa, 1, "IRQA" }, + { &IRQr, 1, "IRQR" }, + { &qtramreg, 1, "QTRG" }, + { 0 } +}; + +static void SyncWRAM(void) { +/* +D~7654 3210 + --------- + .... C..B + | +- PRG A12 + +---- Chip select + 0: External cartridge's 8 KiB (battery-backed) + 1: Internal 8 KiB (not battery-backed) */ + setprg4r(0x10, 0x6000, ((reg[0] & 0x08) >> 2) | (reg[0] & 0x01)); + setprg4r(0x10, 0x7000, ((reg[1] & 0x08) >> 2) | (reg[1] & 0x01)); +} + +static void SyncPRG(void) { +/* +D~7654 3210 + --------- + .CBB BBBB + |++-++++- PRG A13-A18 + +-------- Chip select + 0: Internal PRG-ROM (128 KiB) + 1: External PRG-ROM (512 KiB) */ + setprg8(0x8000, (reg[2] & 0x40) ? (0x10 + (reg[2] & 0x3F)) : (reg[2] & 0x0F)); + setprg8(0xA000, (reg[3] & 0x40) ? (0x10 + (reg[3] & 0x3F)) : (reg[3] & 0x0F)); + setprg8(0xC000, (reg[4] & 0x40) ? (0x10 + (reg[4] & 0x3F)) : (reg[4] & 0x0F)); + setprg8(0xE000, 0x10 + 0x3F); +} + +static void SyncCHR(void) { + setchr4r(0x10, 0x0000, reg[5] & 0x01); + setchr4r(0x10, 0x1000, 0x01); +} + +static void SyncMir(void) { + setmirror(((reg[10] >> 1) & 1) ^ 1); +} + +static void Sync(void) { + SyncPRG(); + SyncWRAM(); + SyncCHR(); + SyncMir(); +} + +static DECLFW(M547Write) { + int index = (A & 0x0F00) >> 8; + + reg[index] = V; + switch (A) { + case 0xD000: + case 0xD100: + SyncWRAM(); + break; + case 0xD200: + case 0xD300: + case 0xD400: + SyncPRG(); + break; + case 0xD500: + SyncCHR(); + break; + case 0xD600: + IRQLatch &= 0xFF00; + IRQLatch |= V; + break; + case 0xD700: + IRQLatch &= 0x00FF; + IRQLatch |= V << 8; + break; + case 0xD800: + IRQa = IRQr; + X6502_IRQEnd(FCEU_IQEXT); + break; + case 0xD900: + IRQr = V & 0x01; + IRQa = V & 0x02; + if (IRQa) { + IRQCount = IRQLatch; + } + X6502_IRQEnd(FCEU_IQEXT); + break; + case 0xDA00: + SyncMir(); + /* register shadow to share it with ppu */ + qtramreg = reg[10] & 0x03; + break; + } +} + +static const uint8 pageTable[0x24] = { + /* JIS X 0208 rows $20-$4F. $20 is not a valid row number. */ + 0x0, 0x0, 0x2, 0x2, 0x1, 0x1, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, + /* JIS X 0208 rows $50-$7F. $7F is not a valid row number. */ + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0xD, 0xD +}; + +static DECLFR(M547Read) { + uint8 row = reg[13] - 0x20; + uint8 col = reg[12] - 0x20; + + if ((row < 0x60) && (col < 0x60)) { + /* "row" and "col" are the first and second 7-bit JIS X 0208 code byte, respectively, each minus the $21 offset. */ + uint16 code = (col % 32) + /* First, go through 32 columns of a column-third. */ + (row % 16) * 32 + /* Then, through 16 rows of a row-third. */ + (col / 32) * 32 * 16 + /* Then, through three column-thirds. */ + (row / 16) * 32 * 16 * 3; /* Finally, through three row-thirds. */ + uint16 glyph = (code & 0xFF) | (pageTable[code >> 8] << 8); + uint32 tile = glyph * 4; /* four tiles per glyph */ + + if (A == 0xDC00) { + /* tile number */ + return ((tile & 0xFF) | (reg[11] & 0x03)); + } else { + /* bank byte */ + return (0x40 | ((reg[11] & 0x04) << 5) | (tile >> 8)); + } + } + return 0; +} + +static void M547CPUIRQHook(int a) { + if (IRQa) { + IRQCount += a; + if (IRQCount & 0x10000) { + X6502_IRQBegin(FCEU_IQEXT); + IRQCount = IRQLatch; + } + } +} + +static void M547Power(void) { + Sync(); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + SetWriteHandler(0xD000, 0xDFFF, M547Write); + SetReadHandler(0xDC00, 0xDC00, M547Read); + SetReadHandler(0xDD00, 0xDD00, M547Read); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); +} + +static void M547Close(void) { + if (CHRRAM) + FCEU_gfree(CHRRAM); + CHRRAM = NULL; + QTAIHack = FALSE; +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper547_Init(CartInfo *info) { + QTAIHack = TRUE; + + info->Power = M547Power; + info->Close = M547Close; + MapIRQHook = M547CPUIRQHook; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, 0); + + if (iNESCart.iNES2) { + WRAMSIZE = info->PRGRamSize + info->PRGRamSaveSize; + CHRSIZE = info->CHRRamSize + info->CHRRamSaveSize; + } + + if (!CHRSIZE) CHRSIZE = 8192; + if (!WRAMSIZE) WRAMSIZE = 8192 + 8192; /* 8K external + 8K internal RAM */ + + CHRRAM = (uint8 *)FCEU_gmalloc(CHRSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRSIZE, 1); + AddExState(CHRRAM, CHRSIZE, 0, "CRAM"); + + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + + info->battery = TRUE; + iNESCart.SaveGame[0] = WRAM; + iNESCart.SaveGameLen[0] = 8192; /* only bank 0, the external cartridge RAM is battery-backed */ +} diff --git a/src/boards/mapper548.c b/src/mappers/mapper548.c similarity index 86% rename from src/boards/mapper548.c rename to src/mappers/mapper548.c index 2a2d8b023..6b9edb8fc 100644 --- a/src/boards/mapper548.c +++ b/src/mappers/mapper548.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,15 +22,12 @@ */ #include "mapinc.h" -#include "fds_apu.h" +#include "fdssound.h" static uint8 reg, latch, IRQa; static int32 IRQCount; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { ®, 1, "REG" }, { &latch, 1, "LATC" }, { &IRQa, 1, "IRQA" }, @@ -42,12 +39,12 @@ static void Sync(void) { setchr8(0); setprg8r(0x10, 0x6000, 0); setprg16(0x8000, reg); - setprg16(0xC000, 3); + setprg16(0xC000, 0x03); } static DECLFW(M548Write4800) { - latch = ((A >> 3) & 4) | ((A >> 2) & 3); - IRQa = (A & 4) != 4; + latch = ((A >> 3) & 0x04) | ((A >> 2) & 0x03); + IRQa = (A & 0x04) != 0x04; if (!IRQa) { IRQCount = 0; X6502_IRQEnd(FCEU_IQEXT); @@ -60,7 +57,7 @@ static DECLFW(M548Write5000) { } -static void FP_FASTAPASS(1) M548IRQ(int a) { +static void M548IRQ(int a) { int count = a; if (IRQa) { while (count > 0) { @@ -80,7 +77,7 @@ static void M548Power(void) { reg = latch ^ 0x05; IRQa = 0; IRQCount = 0; - FDSSoundPower(); + FDSSound_Power(); Sync(); SetReadHandler(0x6000, 0xFFFF, CartBR); SetWriteHandler(0x4800, 0x4FFF, M548Write4800); @@ -90,9 +87,6 @@ static void M548Power(void) { } static void M548Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; } static void StateRestore(int version) { @@ -104,11 +98,10 @@ void Mapper548_Init(CartInfo *info) { info->Close = M548Close; MapIRQHook = M548IRQ; GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); 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/mapper549.c b/src/mappers/mapper549.c similarity index 75% rename from src/boards/mapper549.c rename to src/mappers/mapper549.c index 6475406af..c041b41ce 100644 --- a/src/boards/mapper549.c +++ b/src/mappers/mapper549.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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,27 +25,27 @@ #include "mapinc.h" #include "latch.h" -#include "fds_apu.h" +#include "fdssound.h" static void Sync(void) { - setprg8(0x6000, ((latch.addr >> 3) & 4) | (latch.addr >> 2)); - setprg32(0x8000, 2); + setprg8(0x6000, ((latch.addr >> 3) & 0x04) | (latch.addr >> 2)); + setprg32(0x8000, 0x02); setchr8(0); } -static void M549Power() { - LatchPower(); - FDSSoundPower(); +static void M549Power(void) { + Latch_Power(); + FDSSound_Power(); SetReadHandler(0x6000, 0x7FFF, CartBR); } -static void M549Reset() { - FDSSoundReset(); +static void M549Reset(void) { + FDSSound_Reset(); Sync(); } void Mapper549_Init(CartInfo *info) { - Latch_Init(info, Sync, NULL, 0, 1); + Latch_Init(info, Sync, NULL, FALSE, TRUE); info->Power = M549Power; info->Reset = M549Reset; } diff --git a/src/mappers/mapper550.c b/src/mappers/mapper550.c new file mode 100644 index 000000000..0396a0b88 --- /dev/null +++ b/src/mappers/mapper550.c @@ -0,0 +1,89 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 550 - 7-in-1 1993 Chess Series (JY-015) */ + +#include "mapinc.h" +#include "mmc1.h" + +static uint8 latch; +static uint8 reg; + +static SFORMAT StateRegs[] = { + { &latch, 1, "LATC" }, + { ®, 1, "REGS" }, + { 0 } +}; + +static void M550PW(uint32 A, uint8 V) { + if ((reg & 0x06) == 0x06) { + setprg16(A, (reg << 2) | (V & 0x07)); + } else { + setprg32(0x8000, (reg << 1) | ((latch >> 4) & 0x01)); + } +} + +static void M550CW(uint32 A, uint8 V) { + if ((reg & 0x06) == 0x06) { + setchr4(A, ((reg << 2) & 0x18) | (V & 0x07)); + } else { + setchr8(((reg << 1) & 0x0C) | (latch & 0x03)); + } +} + +static DECLFW(M550Write7) { + if (!(reg & 0x08)) { + reg = A & 0x0F; + MMC1_FixPRG(); + MMC1_FixCHR(); + } +} + +static DECLFW(M550Write8) { + latch = V; + if ((reg & 0x06) == 0x06) { + MMC1_Write(A, V); + } + MMC1_FixPRG(); + MMC1_FixCHR(); +} + +static void M550Reset(void) { + latch = 0; + reg = 0; + MMC1_Reset(); +} + +static void M550Power(void) { + latch = 0; + reg = 0; + MMC1_Power(); + SetWriteHandler(0x7000, 0x7FFF, M550Write7); + SetWriteHandler(0x8000, 0xFFFF, M550Write8); +} + +void Mapper550_Init(CartInfo *info) { + MMC1_Init(info, 8, 0); + info->Power = M550Power; + info->Reset = M550Reset; + MMC1_cwrap = M550CW; + MMC1_pwrap = M550PW; + AddExState(StateRegs, ~0, 0, NULL); +} diff --git a/src/mappers/mapper553.c b/src/mappers/mapper553.c new file mode 100644 index 000000000..695524eb2 --- /dev/null +++ b/src/mappers/mapper553.c @@ -0,0 +1,38 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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" + +static DECLFR(M553Read) { + if (A < 0xC000) { + return 0x3A; + } + return CartBR(A); +} + +static void M553Power(void) { + setprg16(0xC000, 0); + setchr8(0); + SetReadHandler(0x8000, 0xFFFF, M553Read); +} + +void Mapper553_Init(CartInfo *info) { + info->Power = M553Power; +} diff --git a/src/boards/mapper554.c b/src/mappers/mapper554.c similarity index 69% rename from src/boards/mapper554.c rename to src/mappers/mapper554.c index fa4ed8b0d..adf338d9a 100644 --- a/src/boards/mapper554.c +++ b/src/mappers/mapper554.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -35,31 +35,43 @@ static SFORMAT StateRegs[] = static void Sync(void) { setprg8(0x6000, reg); - setprg8(0x8000, 10); - setprg8(0xA000, 11); - setprg8(0xC000, 6); - setprg8(0xE000, 7); + setprg8(0x8000, 0x0A); + setprg8(0xA000, 0x0B); + setprg8(0xC000, 0x06); + setprg8(0xE000, 0x07); setchr8(reg); } -static DECLFR(M554Read) { - int A1 = A & ~1; - if ((A >= 0xCAB6) && (A <= 0xCAD7)) { - reg = (A >> 2) & 0x0F; - Sync(); - } else if ((A1 == 0xEBE2) || (A1 == 0xEE32)) { - reg = (A >> 2) & 0x0F; - Sync(); - } else if (A1 == 0xFFFC) { - reg = (A >> 2) & 0x0F; - Sync(); +static DECLFR(M544Read) { + uint16 adr = A & 0xFFFE; + + switch (A & 0xF000) { + case 0xC000: + if ((adr >= 0xCAB6) && (adr <= 0xCAD7)) { + reg = (adr >> 2) & 0x0F; + Sync(); + } + break; + case 0xE000: + if ((adr == 0xEBE2) || (adr == 0xEE32)) { + reg = (A >> 2) & 0x0F; + Sync(); + } + break; + case 0xF000: + if (adr == 0xFFFC) { + reg = (A >> 2) & 0x0F; + Sync(); + } + break; } + return CartBR(A); } static void M554Power(void) { Sync(); - SetReadHandler(0x6000, 0xFFFF, M554Read); + SetReadHandler(0x6000, 0xFFFF, M544Read); } static void StateRestore(int version) { @@ -69,5 +81,5 @@ static void StateRestore(int version) { void Mapper554_Init(CartInfo *info) { info->Power = M554Power; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/mapper555.c b/src/mappers/mapper555.c new file mode 100644 index 000000000..2bb350922 --- /dev/null +++ b/src/mappers/mapper555.c @@ -0,0 +1,136 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2020 + * Copyright (C) 2023-2024 negativeExponent + * + * 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 516 - Brilliant Com Cocoma Pack */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 reg[2]; +static uint8 count_expired; +static uint32 count; +static uint32 count_target = 0x20000000; + +static uint8 *CHRRAM = NULL; +static uint32 CHRRAMSIZE; + +static SFORMAT StateRegs[] = { + { reg, 2, "REGS" }, + { &count, 2, "CNTR" }, + { &count_expired, 2, "CNTE" }, + { 0 } +}; + +static void M555CW(uint32 A, uint8 V) { + uint16 base = (reg[0] << 5) & 0x80; + + if ((reg[0] & 0x06) == 0x02) { + if (V & 0x40) { + setchr1r(0x10, A, base | (V & 0x07)); + } else { + setchr1(A, base | (V & 0xFF)); + } + } else { + setchr1(A, base | (V & 0x7F)); + } +} + +static void M555PW(uint32 A, uint8 V) { + uint16 mask = ((reg[0] << 3) & 0x18) | 0x07; + uint16 base = ((reg[0] << 3) & 0x20); + + setprg8(A, base | (V & mask)); +} + +static DECLFR(M555Read5) { + if (A & 0x800) { + return (0x5C | (count_expired ? 0x80 : 0)); + } + return WRAM[0x2000 | (A & 0xFFF)]; +} + +static DECLFW(M555Write5) { + if (A & 0x800) { + reg[(A >> 10) & 0x01] = V; + MMC3_FixPRG(); + MMC3_FixCHR(); + } else { + WRAM[0x2000 | (A & 0xFFF)] = V; + } +} + +static void M555Reset(void) { + count_target = 0x20000000 | ((uint32)GameInfo->cspecial << 25); + count = 0; + memset(reg, 0, sizeof(reg)); + MMC3_Reset(); +} + +static void M555Power(void) { + count_target = 0x20000000 | ((uint32)GameInfo->cspecial << 25); + count = 0; + memset(reg, 0, sizeof(reg)); + MMC3_Power(); + + SetReadHandler(0x5000, 0x5FFF, M555Read5); + SetWriteHandler(0x5000, 0x5FFF, M555Write5); + + setprg8r(0x10, 0x6000, 0); + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); +} + +static void M555CPUIRQHook(int a) { + while (a--) { + if (!(reg[0] & 0x08)) { + count = 0; + count_expired = false; + } else { + if (++count == count_target) { + count_expired = TRUE; + } + if ((count % 1789773) == 0) { + uint32 seconds = (count_target - count) / 1789773; + FCEU_DispMessage(RETRO_LOG_INFO, 1000, "Time left: %02i:%02i\n", seconds / 60, seconds % 60); + } + } + } +} + +void Mapper555_Init(CartInfo *info) { + MMC3_Init(info, 0, 0); + MMC3_cwrap = M555CW; + MMC3_pwrap = M555PW; + info->Power = M555Power; + info->Reset = M555Reset; + MapIRQHook = M555CPUIRQHook; + AddExState(StateRegs, ~0, 0, NULL); + + WRAMSIZE = 16 * 1024; + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, TRUE); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + + CHRRAMSIZE = 8 * 1024; + CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, TRUE); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); +} diff --git a/src/mappers/mapper556.c b/src/mappers/mapper556.c new file mode 100644 index 000000000..63ca88b23 --- /dev/null +++ b/src/mappers/mapper556.c @@ -0,0 +1,180 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 556 + * Used for the for the 超强小新2+瑪莉家族 7-in-1 (JY-215) multicart. + */ + +#include "mapinc.h" +#include "mmc3.h" +#include "vrc2and4.h" + +static uint8 cmd; +static uint8 reg[4]; + +static SFORMAT StateRegs[] = { + { reg, 5, "REGS" }, + { &cmd, 1, "CMD0" }, + { 0 }, +}; + +static uint32 M556PRGMask(void) { + return (~reg[3] & 0x3F); +} + +static uint32 M556PRGBase(void) { + return (((reg[3] & 0x40) << 2) | reg[1]); +} + +static uint32 M556CHRMask(void) { + return (0xFF >> (~reg[2] & 0x0F)); +} + +static uint32 M556CHRBase(void) { + return (((reg[3] & 0x40) << 6) | ((reg[2] & 0xF0) << 4) | reg[0]); +} + +static void M556PW_MMC3(uint32 A, uint8 V) { + uint32 mask = M556PRGMask(); + uint32 base = M556PRGBase(); + + setprg8(A, (base & ~mask) | (V & mask)); +} + +static void M556CW_MMC3(uint32 A, uint8 V) { + uint32 mask = M556CHRMask(); + uint32 base = M556CHRBase(); + + setchr1(A, (base & ~mask) | (V & mask)); +} + +static void M556PW_VRC4(uint32 A, uint8 V) { + uint32 mask = M556PRGMask(); + uint32 base = M556PRGBase(); + + setprg8(A, (base & ~mask) | (V & mask)); +} + +static void M556CW_VRC4(uint32 A, uint32 V) { + uint32 mask = M556CHRMask(); + uint32 base = M556CHRBase(); + + setchr1(A, (base & ~mask) | (V & mask)); +} + +static void M556Sync(void) { + if (reg[2] & 0x80) { + VRC24_FixPRG(); + VRC24_FixCHR(); + VRC24_FixMIR(); + } else { + MMC3_FixPRG(); + MMC3_FixCHR(); + MMC3_FixMIR(); + } +} + +static DECLFW(M556WriteREG) { + if (!(reg[3] & 0x80)) { + reg[cmd] = V; + cmd = (cmd + 1) & 0x03; + M556Sync(); + } +} + +static DECLFW(M556WriteASIC) { + if (reg[2] & 0x80) { + VRC24_Write(A, V); + } else { + MMC3_Write(A, V); + } +} + +static void M556CPUIRQHook(int a) { + if (reg[2] & 0x80) { + VRC24_IRQCPUHook(a); + } +} + +static void M556HBIRQHook(void) { + if (!(reg[2] & 0x80)) { + MMC3_IRQHBHook(); + } +} + +static void M556Reset(void) { + memset(reg, 0, sizeof(reg)); + reg[2] = 0x0F; + M556Sync(); +} + +static void M556Power(void) { + memset(reg, 0, sizeof(reg)); + reg[2] = 0x0F; + + MMC3_Reset(); + VRC24_Reset(); + + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x5000, 0x5FFF, M556WriteREG); + SetWriteHandler(0x8000, 0xFFFF, M556WriteASIC); + + if (WRAM) { + setprg8r(0x10, 0x6000, 0); + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + } +} + +static void M556Close(void) { +} + +static void StateRestore(int version) { + M556Sync(); +} + +void Mapper556_Init(CartInfo *info) { + VRC24_Init(info, VRC4, 0x05, 0x0A, 0, TRUE); + VRC24_pwrap = M556PW_VRC4; + VRC24_cwrap = M556CW_VRC4; + + MMC3_Init(info, 0, 0); + MMC3_pwrap = M556PW_MMC3; + MMC3_cwrap = M556CW_MMC3; + + info->Reset = M556Reset; + info->Power = M556Power; + info->Close = M556Close; + MapIRQHook = M556CPUIRQHook; + GameHBIRQHook = M556HBIRQHook; + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, NULL); + + WRAMSIZE = info->PRGRamSize + info->PRGRamSaveSize; + if (WRAMSIZE) { + WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } + } +} diff --git a/src/mappers/mapper557.c b/src/mappers/mapper557.c new file mode 100644 index 000000000..679c41f42 --- /dev/null +++ b/src/mappers/mapper557.c @@ -0,0 +1,43 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 557 is used for Kaiser's cartridge conversion of the Famicom Disk System game Moero TwinBee: Cinnamon-hakase o Sukue!. */ + +#include "mapinc.h" +#include "n118.h" + +static void M557FixPRG(void) { + setprg8r(0x10, 0x6000, 0); + setprg8(0x8000, n118.reg[6] & 0x0F); + setprg8(0xA000, n118.reg[7] & 0x0F); + setprg8(0xC000, ~1); + setprg8(0xE000, ~0); +} + +static void M557FixCHR(void) { + setchr8(0); + setmirror(((n118.reg[5] >> 5) & 0x01) ^ 0x01); +} + +void Mapper557_Init(CartInfo *info) { + N118_Init(info, 8, 0); + N118_FixPRG = M557FixPRG; + N118_FixCHR = M557FixCHR; +} diff --git a/src/boards/mapper558.c b/src/mappers/mapper558.c similarity index 74% rename from src/boards/mapper558.c rename to src/mappers/mapper558.c index 23a8a3682..cc2d3ac3a 100644 --- a/src/boards/mapper558.c +++ b/src/mappers/mapper558.c @@ -1,9 +1,10 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2002 Xodnizel * Copyright (C) 2005 CaH4e3 * Copyright (C) 2019 Libretro Team + * Copyright (C) 2023-2024 negativeExponent * * 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,27 +23,26 @@ /* Yancheng YC-03-09/Waixing FS??? PCB */ -#include "eeprom_93C66.h" #include "mapinc.h" -static uint8 *WRAM; -static uint32 WRAMSIZE; +#include "eeprom_93Cx6.h" + static uint8 reg[4]; + static uint8 haveEEPROM; static uint8 eeprom_data[512]; + static SFORMAT StateRegs[] = { { reg, 4, "REGS" }, { 0 } }; -static void Sync() { +static void Sync(void) { setprg32(0x8000, (reg[1] << 4) | (reg[0] & 0xF) | ((reg[3] & 0x04) ? 0x00 : 0x03)); setprg8r(0x10, 0x6000, 0); - if (~reg[0] & 0x80) + if (!(reg[0] & 0x80)) { setchr8(0); - - if (haveEEPROM) - eeprom_93C66_write((reg[2] & 0x04), (reg[2] & 0x02), (reg[2] & 0x01)); + } } static void M558HBIRQHook(void) { @@ -51,29 +51,48 @@ static void M558HBIRQHook(void) { PA13 rises. This does not seem possible with the current PPU emulation however. */ setchr4(0x0000, (scanline >= 127) ? 1 : 0); setchr4(0x1000, (scanline >= 127) ? 1 : 0); - } else + } else { setchr8(0); + } } static DECLFR(readReg) { - if (haveEEPROM) - return eeprom_93C66_read() ? 0x04 : 0x00; - else - return reg[2] & 0x04; + if (haveEEPROM) { + return eeprom_93Cx6_read() ? 0x04 : 0x00; + } + return reg[2] & 0x04; } static DECLFW(writeReg) { - uint8 index = A >> 8 & 3; - - /* D0 and D1 are connected to the ASIC in reverse order, so swap once */ - V = (V & ~3) | (V >> 1 & 1) | (V << 1 & 2); - - /* Swap bits of registers 0-2 again if the "swap bits" bit is set. Exclude register 2 on when PRG-ROM is 1 MiB. */ - if ((reg[3] & 0x02) && index <= (ROM_size == 64 ? 1 : 2)) - V = (V & ~3) | (V >> 1 & 1) | (V << 1 & 2); - - reg[index] = V; - Sync(); + switch (A & 0xFF00) { + case 0x5000: + if (!(reg[3] & 0x02)) { + V = (V & ~0x03) | ((V >> 1) & 0x01) | ((V << 1) & 0x02); + } + reg[0] = V; + Sync(); + break; + case 0x5100: + if (!(reg[3] & 0x02)) { + V = (V & ~0x03) | ((V >> 1) & 0x01) | ((V << 1) & 0x02); + } + reg[1] = V; + Sync(); + break; + case 0x5200: + if (((ROM.prg.size * 16) != 1024) && !(reg[3] & 0x02)) { + V = (V & ~0x03) | ((V >> 1) & 0x01) | ((V << 1) & 0x02); + } + reg[2] = V; + if (haveEEPROM) { + eeprom_93Cx6_write((reg[2] & 0x04), (reg[2] & 0x02), (reg[2] & 0x01)); + } + break; + case 0x5300: + reg[3] = V; + Sync(); + break; + } } static void M558Power(void) { @@ -91,9 +110,6 @@ static void M558Reset(void) { } static void M558Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; } static void StateRestore(int version) { @@ -107,16 +123,17 @@ void Mapper558_Init(CartInfo *info) { GameHBIRQHook = M558HBIRQHook; GameStateRestore = StateRestore; - AddExState(StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); WRAMSIZE = info->PRGRamSize + (info->PRGRamSaveSize & ~0x7FF); WRAM = (uint8 *)FCEU_gmalloc(WRAMSIZE); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + haveEEPROM = !!(info->PRGRamSaveSize & 0x200); if (haveEEPROM) { - eeprom_93C66_init(eeprom_data, 512, 8); + eeprom_93Cx6_init(eeprom_data, 512, 8); info->battery = 1; info->SaveGame[0] = eeprom_data; info->SaveGameLen[0] = 512; diff --git a/src/boards/mapper559.c b/src/mappers/mapper559.c similarity index 68% rename from src/boards/mapper559.c rename to src/mappers/mapper559.c index dc7e3db10..047244d60 100644 --- a/src/boards/mapper559.c +++ b/src/mappers/mapper559.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2023 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -23,7 +23,7 @@ */ #include "mapinc.h" -#include "vrc24.h" +#include "vrc2and4.h" static uint8 nt[4]; static uint8 cpuC; @@ -46,26 +46,26 @@ static void M559CW(uint32 A, uint32 V) { setchr1(A, V & 0x1FF); } -static DECLFW(M559WriteExtra) { - if ((A & 0xC00) == 0xC00) { - if (A & 0x04) { - nt[A & 0x03] = V & 0x01; - setmirrorw(nt[0], nt[1], nt[2], nt[3]); - } else { - cpuC = V; - FixVRC24PRG(); - } - } else { - VRC24Write(A, V); - } +static void M559MIRR(void) { + setmirrorw(nt[0], nt[1], nt[2], nt[3]); +} + +static DECLFW(M559WriteMisc) { + if (A & 0x04) { + nt[A & 0x03] = V & 0x01; + VRC24_FixMIR(); + } else { + cpuC = V; + VRC24_FixPRG(); + } } -static DECLFW(M559WriteCHR_IRQ) { +static DECLFW(M559WriteNibble) { /* nibblize address */ if (A & 0x400) { V >>= 4; } - VRC24Write(A, V); + VRC24_Write(A, V); } static void M559Power(void) { @@ -74,17 +74,18 @@ static void M559Power(void) { nt[2] = 1; nt[3] = 1; cpuC = ~1; - GenVRC24Power(); + VRC24_Power(); setprg8(0xC000, cpuC); setmirrorw(nt[0], nt[1], nt[2], nt[3]); - SetWriteHandler(0x9000, 0x9FFF, M559WriteExtra); - SetWriteHandler(0xB000, 0xFFFF, M559WriteCHR_IRQ); + SetWriteHandler(0xB000, 0xFFFF, M559WriteNibble); } void Mapper559_Init(CartInfo *info) { - GenVRC24_Init(info, VRC4_559, 1); + VRC24_Init(info, VRC4, 0x400, 0x800, 1, 1); info->Power = M559Power; - vrc24.pwrap = M559PW; - vrc24.cwrap = M559CW; - AddExState(StateRegs, ~0, 0, 0); + VRC24_FixMIR = M559MIRR; + VRC24_pwrap = M559PW; + VRC24_cwrap = M559CW; + VRC24_miscWrite = M559WriteMisc; + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/mappers/sound/emu2149.c b/src/mappers/sound/emu2149.c new file mode 100644 index 000000000..0594b7050 --- /dev/null +++ b/src/mappers/sound/emu2149.c @@ -0,0 +1,431 @@ +/** + * emu2149 v1.41 + * https://github.com/digital-sound-antiques/emu2149 + * Copyright (C) 2001-2022 Mitsutaka Okazaki + * + * This source refers to the following documents. The author would like to thank all the authors who have + * contributed to the writing of them. + * - psg.vhd -- 2000 written by Kazuhiro Tsujikawa. + * - s_fme7.c -- 1999,2000 written by Mamiya (NEZplug). + * - ay8910.c -- 1998-2001 Author unknown (MAME). + * - MSX-Datapack -- 1991 ASCII Corp. + * - AY-3-8910 data sheet + */ +#include +#include +#include "emu2149.h" + +#ifndef INLINE +#if defined(_MSC_VER) +#define INLINE __inline +#elif defined(__GNUC__) +#define INLINE __inline__ +#else +#define INLINE INLINE +#endif +#endif + +static uint32_t voltbl[2][32] = { + /* YM2149 - 32 steps */ + {0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, 0x09, + 0x0B, 0x0D, 0x0F, 0x12, + 0x16, 0x1A, 0x1F, 0x25, 0x2D, 0x35, 0x3F, 0x4C, 0x5A, 0x6A, 0x7F, 0x97, + 0xB4, 0xD6, 0xFF, 0xFF}, + /* AY-3-8910 - 16 steps */ + {0x00, 0x00, 0x03, 0x03, 0x04, 0x04, 0x06, 0x06, 0x09, 0x09, 0x0D, 0x0D, + 0x12, 0x12, 0x1D, 0x1D, + 0x22, 0x22, 0x37, 0x37, 0x4D, 0x4D, 0x62, 0x62, 0x82, 0x82, 0xA6, 0xA6, + 0xD0, 0xD0, 0xFF, 0xFF} +}; + +static const uint8_t regmsk[16] = { + 0xff, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0x1f, 0x3f, + 0x1f, 0x1f, 0x1f, 0xff, 0xff, 0x0f, 0xff, 0xff +}; + +#define GETA_BITS 24 + +static void +internal_refresh (PSG * psg) +{ + uint32_t f_master = psg->clk; + + if (psg->clk_div) + f_master /= 2; + + if (psg->quality) + { + psg->base_incr = 1 << GETA_BITS; + psg->realstep = f_master; + psg->psgstep = psg->rate * 8; + psg->psgtime = 0; + psg->freq_limit = (uint32_t)(f_master / 16 / (psg->rate / 2)); + } + else + { + psg->base_incr = (uint32_t)((double)f_master * (1 << GETA_BITS) / 8 / psg->rate); + psg->freq_limit = 0; + } +} + +void +PSG_setClock(PSG *psg, uint32_t clock) +{ + if (psg->clk != clock) { + psg->clk = clock; + internal_refresh(psg); + } +} + +void +PSG_setClockDivider(PSG *psg, uint8_t enable) +{ + if (psg->clk_div != enable) { + psg->clk_div = enable; + internal_refresh (psg); + } +} + +void +PSG_setRate (PSG * psg, uint32_t rate) +{ + uint32_t r = rate ? rate : 44100; + if (psg->rate != r) { + psg->rate = r; + internal_refresh(psg); + } +} + +void +PSG_setQuality (PSG * psg, uint8_t q) +{ + if (psg->quality != q) { + psg->quality = q; + internal_refresh(psg); + } +} + +PSG * +PSG_new (uint32_t clock, uint32_t rate) +{ + PSG *psg; + + psg = (PSG *) calloc (1, sizeof (PSG)); + if (psg == NULL) + return NULL; + + PSG_setVolumeMode(psg, 0); + psg->clk = clock; + psg->clk_div = 0; + psg->rate = rate ? rate : 44100; + psg->quality = 0; + internal_refresh(psg); + PSG_setMask(psg, 0x00); + return psg; +} + +void +PSG_setVolumeMode (PSG * psg, int type) +{ + switch (type) + { + case 1: + psg->voltbl = voltbl[0]; /* YM2149 */ + break; + case 2: + psg->voltbl = voltbl[1]; /* AY-3-8910 */ + break; + default: + psg->voltbl = voltbl[0]; /* fallback: YM2149 */ + break; + } +} + +uint32_t +PSG_setMask (PSG *psg, uint32_t mask) +{ + uint32_t ret = 0; + if(psg) + { + ret = psg->mask; + psg->mask = mask; + } + return ret; +} + +uint32_t +PSG_toggleMask (PSG *psg, uint32_t mask) +{ + uint32_t ret = 0; + if(psg) + { + ret = psg->mask; + psg->mask ^= mask; + } + return ret; +} + +void +PSG_reset (PSG * psg) +{ + int i; + + psg->base_count = 0; + + for (i = 0; i < 3; i++) + { + psg->count[i] = 0; + psg->freq[i] = 0; + psg->edge[i] = 0; + psg->volume[i] = 0; + psg->ch_out[i] = 0; + } + + psg->mask = 0; + + for (i = 0; i < 16; i++) + psg->reg[i] = 0; + psg->adr = 0; + + psg->noise_seed = 0xffff; + psg->noise_scaler = 0; + psg->noise_count = 0; + psg->noise_freq = 0; + + psg->env_ptr = 0; + psg->env_freq = 0; + psg->env_count = 0; + psg->env_pause = 1; + + psg->out = 0; + +} + +void +PSG_delete (PSG * psg) +{ + free (psg); +} + +uint8_t +PSG_readIO (PSG * psg) +{ + return (uint8_t) (psg->reg[psg->adr]); +} + +uint8_t +PSG_readReg (PSG * psg, uint32_t reg) +{ + return (uint8_t) (psg->reg[reg & 0x1f]); +} + +void +PSG_writeIO (PSG * psg, uint32_t adr, uint32_t val) +{ + if (adr & 1) + PSG_writeReg (psg, psg->adr, val); + else + psg->adr = val & 0x1f; +} + +static INLINE void +update_output (PSG * psg) +{ + + int i, noise; + uint8_t incr; + + psg->base_count += psg->base_incr; + incr = (psg->base_count >> GETA_BITS); + psg->base_count &= (1 << GETA_BITS) - 1; + + /* Envelope */ + psg->env_count += incr; + + if (psg->env_count >= psg->env_freq) + { + if (!psg->env_pause) + { + if(psg->env_face) + psg->env_ptr = (psg->env_ptr + 1) & 0x3f ; + else + psg->env_ptr = (psg->env_ptr + 0x3f) & 0x3f; + } + + if (psg->env_ptr & 0x20) /* if carry or borrow */ + { + if (psg->env_continue) + { + if (psg->env_alternate^psg->env_hold) psg->env_face ^= 1; + if (psg->env_hold) psg->env_pause = 1; + psg->env_ptr = psg->env_face ? 0 : 0x1f; + } + else + { + psg->env_pause = 1; + psg->env_ptr = 0; + } + } + + if (psg->env_freq >= incr) + psg->env_count -= psg->env_freq; + else + psg->env_count = 0; + } + + /* Noise */ + psg->noise_count += incr; + if (psg->noise_count >= psg->noise_freq) + { + psg->noise_scaler ^= 1; + if (psg->noise_scaler) + { + if (psg->noise_seed & 1) + psg->noise_seed ^= 0x24000; + psg->noise_seed >>= 1; + } + + if (psg->noise_freq >= incr) + psg->noise_count -= psg->noise_freq; + else + psg->noise_count = 0; + } + noise = psg->noise_seed & 1; + + /* Tone */ + for (i = 0; i < 3; i++) + { + psg->count[i] += incr; + if (psg->count[i] >= psg->freq[i]) + { + psg->edge[i] = !psg->edge[i]; + + if (psg->freq[i] >= incr) + psg->count[i] -= psg->freq[i]; + else + psg->count[i] = 0; + } + + if (0 < psg->freq_limit && psg->freq[i] <= psg->freq_limit) + { + /* Mute the channel if the pitch is higher than the Nyquist frequency at the current sample rate, + * to prevent aliased or broken tones from being generated. Of course, this logic doesn't exist + * on the actual chip, but practically all tones higher than the Nyquist frequency are usually + * removed by a low-pass circuit somewhere, so we here halt the output. */ + continue; + } + + if (psg->mask & PSG_MASK_CH(i)) + { + psg->ch_out[i] = 0; + continue; + } + + if ((psg->tmask[i]||psg->edge[i]) && (psg->nmask[i]||noise)) + { + if (!(psg->volume[i] & 32)) + psg->ch_out[i] = (psg->voltbl[psg->volume[i] & 31] << 4); + else + psg->ch_out[i] = (psg->voltbl[psg->env_ptr] << 4); + } + else + { + psg->ch_out[i] = 0; + } + } +} + +static INLINE int16_t +mix_output(PSG *psg) +{ + return (int16_t)(psg->ch_out[0] + psg->ch_out[1] + psg->ch_out[2]); +} + +int16_t +PSG_calc (PSG * psg) +{ + if (!psg->quality) + { + update_output(psg); + psg->out = mix_output(psg); + } + else + { + /* Simple rate converter (See README for detail). */ + while (psg->realstep > psg->psgtime) + { + psg->psgtime += psg->psgstep; + update_output(psg); + psg->out += mix_output(psg); + psg->out >>= 1; + } + psg->psgtime -= psg->realstep; + } + return psg->out; +} + +void +PSG_writeReg (PSG * psg, uint32_t reg, uint32_t val) +{ + int c; + + if (reg > 15) return; + + val &= regmsk[reg]; + + psg->reg[reg] = (uint8_t) val; + + switch (reg) + { + case 0: + case 2: + case 4: + case 1: + case 3: + case 5: + c = reg >> 1; + psg->freq[c] = ((psg->reg[c * 2 + 1] & 15) << 8) + psg->reg[c * 2]; + break; + + case 6: + psg->noise_freq = val & 31; + break; + + case 7: + psg->tmask[0] = (val & 1); + psg->tmask[1] = (val & 2); + psg->tmask[2] = (val & 4); + psg->nmask[0] = (val & 8); + psg->nmask[1] = (val & 16); + psg->nmask[2] = (val & 32); + break; + + case 8: + case 9: + case 10: + psg->volume[reg - 8] = val << 1; + break; + + case 11: + case 12: + psg->env_freq = (psg->reg[12] << 8) + psg->reg[11]; + break; + + case 13: + psg->env_continue = (val >> 3) & 1; + psg->env_attack = (val >> 2) & 1; + psg->env_alternate = (val >> 1) & 1; + psg->env_hold = val & 1; + psg->env_face = psg->env_attack; + psg->env_pause = 0; + psg->env_ptr = psg->env_face ? 0 : 0x1f; + break; + + case 14: + case 15: + default: + break; + } + + return; +} \ No newline at end of file diff --git a/src/mappers/sound/emu2149.h b/src/mappers/sound/emu2149.h new file mode 100644 index 000000000..96daeeb92 --- /dev/null +++ b/src/mappers/sound/emu2149.h @@ -0,0 +1,94 @@ +/* emu2149.h */ +#ifndef _EMU2149_H_ +#define _EMU2149_H_ + +#include + +#define PSG_MASK_CH(x) (1<<(x)) + +#ifdef __cplusplus +extern "C" +{ +#endif + + typedef struct __PSG + { + + /* Volume Table */ + uint32_t *voltbl; + + uint8_t reg[0x20]; + int32_t out; + + uint32_t clk, rate, base_incr; + uint8_t quality; + uint8_t clk_div; + + uint16_t count[3]; + uint8_t volume[3]; + uint16_t freq[3]; + uint8_t edge[3]; + uint8_t tmask[3]; + uint8_t nmask[3]; + uint32_t mask; + + uint32_t base_count; + + uint8_t env_ptr; + uint8_t env_face; + + uint8_t env_continue; + uint8_t env_attack; + uint8_t env_alternate; + uint8_t env_hold; + uint8_t env_pause; + + uint16_t env_freq; + uint32_t env_count; + + uint32_t noise_seed; + uint8_t noise_scaler; + uint8_t noise_count; + uint8_t noise_freq; + + /* rate converter */ + uint32_t realstep; + uint32_t psgtime; + uint32_t psgstep; + + uint32_t freq_limit; + + /* I/O Ctrl */ + uint8_t adr; + + /* output of channels */ + int16_t ch_out[3]; + + } PSG; + + void PSG_setQuality (PSG * psg, uint8_t q); + void PSG_setClock(PSG *psg, uint32_t clk); + void PSG_setClockDivider(PSG *psg, uint8_t enable); + void PSG_setRate (PSG * psg, uint32_t rate); + PSG *PSG_new (uint32_t clk, uint32_t rate); + void PSG_reset (PSG *); + void PSG_delete (PSG *); + void PSG_writeReg (PSG *, uint32_t reg, uint32_t val); + void PSG_writeIO (PSG * psg, uint32_t adr, uint32_t val); + uint8_t PSG_readReg (PSG * psg, uint32_t reg); + uint8_t PSG_readIO (PSG * psg); + int16_t PSG_calc (PSG *); + void PSG_setVolumeMode (PSG * psg, int type); + uint32_t PSG_setMask (PSG *, uint32_t mask); + uint32_t PSG_toggleMask (PSG *, uint32_t mask); + +#ifdef __cplusplus +} +#endif + +/* deprecated interfaces */ +#define PSG_set_quality PSG_setQuality +#define PSG_set_rate PSG_setRate +#define PSG_set_clock PSG_setClock + +#endif diff --git a/src/mappers/sound/emu2413.c b/src/mappers/sound/emu2413.c new file mode 100644 index 000000000..447e27d5d --- /dev/null +++ b/src/mappers/sound/emu2413.c @@ -0,0 +1,1507 @@ +/** + * emu2413 v1.5.9 + * https://github.com/digital-sound-antiques/emu2413 + * Copyright (C) 2020 Mitsutaka Okazaki + * + * This source refers to the following documents. The author would like to thank all the authors who have + * contributed to the writing of them. + * - [YM2413 notes](http://www.smspower.org/Development/YM2413) by andete + * - ymf262.c by Jarek Burczynski + * - [VRC7 presets](https://siliconpr0n.org/archive/doku.php?id=vendor:yamaha:opl2#opll_vrc7_patch_format) by Nuke.YKT + * - YMF281B presets by Chabin + */ +#include "emu2413.h" +#include +#include +#include +#include + +#ifndef INLINE +#if defined(_MSC_VER) +#define INLINE __inline +#elif defined(__GNUC__) +#define INLINE __inline__ +#else +#define INLINE inline +#endif +#endif + +#define _PI_ 3.14159265358979323846264338327950288 + +#define OPLL_TONE_NUM 3 +/* clang-format off */ +static uint8_t default_inst[OPLL_TONE_NUM][(16 + 3) * 8] = {{ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0: User */ +0x71,0x61,0x1e,0x17,0xd0,0x78,0x00,0x17, /* 1: Violin */ +0x13,0x41,0x1a,0x0d,0xd8,0xf7,0x23,0x13, /* 2: Guitar */ +0x13,0x01,0x99,0x00,0xf2,0xc4,0x21,0x23, /* 3: Piano */ +0x11,0x61,0x0e,0x07,0x8d,0x64,0x70,0x27, /* 4: Flute */ +0x32,0x21,0x1e,0x06,0xe1,0x76,0x01,0x28, /* 5: Clarinet */ +0x31,0x22,0x16,0x05,0xe0,0x71,0x00,0x18, /* 6: Oboe */ +0x21,0x61,0x1d,0x07,0x82,0x81,0x11,0x07, /* 7: Trumpet */ +0x33,0x21,0x2d,0x13,0xb0,0x70,0x00,0x07, /* 8: Organ */ +0x61,0x61,0x1b,0x06,0x64,0x65,0x10,0x17, /* 9: Horn */ +0x41,0x61,0x0b,0x18,0x85,0xf0,0x81,0x07, /* A: Synthesizer */ +0x33,0x01,0x83,0x11,0xea,0xef,0x10,0x04, /* B: Harpsichord */ +0x17,0xc1,0x24,0x07,0xf8,0xf8,0x22,0x12, /* C: Vibraphone */ +0x61,0x50,0x0c,0x05,0xd2,0xf5,0x40,0x42, /* D: Synthsizer Bass */ +0x01,0x01,0x55,0x03,0xe9,0x90,0x03,0x02, /* E: Acoustic Bass */ +0x41,0x41,0x89,0x03,0xf1,0xe4,0xc0,0x13, /* F: Electric Guitar */ +0x01,0x01,0x18,0x0f,0xdf,0xf8,0x6a,0x6d, /* R: Bass Drum (from VRC7) */ +0x01,0x01,0x00,0x00,0xc8,0xd8,0xa7,0x68, /* R: High-Hat(M) / Snare Drum(C) (from VRC7) */ +0x05,0x01,0x00,0x00,0xf8,0xaa,0x59,0x55, /* R: Tom-tom(M) / Top Cymbal(C) (from VRC7) */ +},{ +/* VRC7 presets from Nuke.YKT */ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +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, +0x01,0x01,0x18,0x0f,0xdf,0xf8,0x6a,0x6d, +0x01,0x01,0x00,0x00,0xc8,0xd8,0xa7,0x68, +0x05,0x01,0x00,0x00,0xf8,0xaa,0x59,0x55, +},{ +/* YMF281B presets */ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0: User */ +0x62,0x21,0x1a,0x07,0xf0,0x6f,0x00,0x16, /* 1: Electric Strings (form Chabin's patch) */ +0x40,0x10,0x45,0x00,0xf6,0x83,0x73,0x63, /* 2: Bow Wow (based on plgDavid's patch, KSL fixed) */ +0x13,0x01,0x99,0x00,0xf2,0xc3,0x21,0x23, /* 3: Electric Guitar (similar to YM2413 but different DR(C)) */ +0x01,0x61,0x0b,0x0f,0xf9,0x64,0x70,0x17, /* 4: Organ (based on Chabin, TL/DR fixed) */ +0x32,0x21,0x1e,0x06,0xe1,0x76,0x01,0x28, /* 5: Clarinet (identical to YM2413) */ +0x60,0x01,0x82,0x0e,0xf9,0x61,0x20,0x27, /* 6: Saxophone (based on plgDavid, PM/EG fixed) */ +0x21,0x61,0x1c,0x07,0x84,0x81,0x11,0x07, /* 7: Trumpet (similar to YM2413 but different TL/DR(M)) */ +0x37,0x32,0xc9,0x01,0x66,0x64,0x40,0x28, /* 8: Street Organ (from Chabin) */ +0x01,0x21,0x07,0x03,0xa5,0x71,0x51,0x07, /* 9: Synth Brass (based on Chabin, TL fixed) */ +0x06,0x01,0x5e,0x07,0xf3,0xf3,0xf6,0x13, /* A: Electric Piano (based on Chabin, DR/RR/KR fixed) */ +0x00,0x00,0x18,0x06,0xf5,0xf3,0x20,0x23, /* B: Bass (based on Chabin, EG fixed) */ +0x17,0xc1,0x24,0x07,0xf8,0xf8,0x22,0x12, /* C: Vibraphone (identical to YM2413) */ +0x35,0x64,0x00,0x00,0xff,0xf3,0x77,0xf5, /* D: Chimes (from plgDavid) */ +0x11,0x31,0x00,0x07,0xdd,0xf3,0xff,0xfb, /* E: Tom Tom II (from plgDavid) */ +0x3a,0x21,0x00,0x07,0x80,0x84,0x0f,0xf5, /* F: Noise (based on plgDavid, AR fixed) */ +0x01,0x01,0x18,0x0f,0xdf,0xf8,0x6a,0x6d, /* R: Bass Drum (identical to YM2413) */ +0x01,0x01,0x00,0x00,0xc8,0xd8,0xa7,0x68, /* R: High-Hat(M) / Snare Drum(C) (identical to YM2413) */ +0x05,0x01,0x00,0x00,0xf8,0xaa,0x59,0x55, /* R: Tom-tom(M) / Top Cymbal(C) (identical to YM2413) */ +}}; +/* clang-format on */ + +/* phase increment counter */ +#define DP_BITS 19 +#define DP_WIDTH (1 << DP_BITS) +#define DP_BASE_BITS (DP_BITS - PG_BITS) + +/* dynamic range of envelope output */ +#define EG_STEP 0.375 +#define EG_BITS 7 +#define EG_MUTE ((1 << EG_BITS) - 1) +#define EG_MAX (EG_MUTE - 4) + +/* dynamic range of total level */ +#define TL_STEP 0.75 +#define TL_BITS 6 + +/* dynamic range of sustine level */ +#define SL_STEP 3.0 +#define SL_BITS 4 + +/* damper speed before key-on. key-scale affects. */ +#define DAMPER_RATE 12 + +#define TL2EG(d) ((d) << 1) + +/* sine table */ +#define PG_BITS 10 /* 2^10 = 1024 length sine table */ +#define PG_WIDTH (1 << PG_BITS) + +/* clang-format off */ +/* exp_table[x] = round((exp2((double)x / 256.0) - 1) * 1024) */ +static uint16_t exp_table[256] = { +0, 3, 6, 8, 11, 14, 17, 20, 22, 25, 28, 31, 34, 37, 40, 42, +45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, +93, 96, 99, 102, 105, 108, 111, 114, 117, 120, 123, 126, 130, 133, 136, 139, +142, 145, 148, 152, 155, 158, 161, 164, 168, 171, 174, 177, 181, 184, 187, 190, +194, 197, 200, 204, 207, 210, 214, 217, 220, 224, 227, 231, 234, 237, 241, 244, +248, 251, 255, 258, 262, 265, 268, 272, 276, 279, 283, 286, 290, 293, 297, 300, +304, 308, 311, 315, 318, 322, 326, 329, 333, 337, 340, 344, 348, 352, 355, 359, +363, 367, 370, 374, 378, 382, 385, 389, 393, 397, 401, 405, 409, 412, 416, 420, +424, 428, 432, 436, 440, 444, 448, 452, 456, 460, 464, 468, 472, 476, 480, 484, +488, 492, 496, 501, 505, 509, 513, 517, 521, 526, 530, 534, 538, 542, 547, 551, +555, 560, 564, 568, 572, 577, 581, 585, 590, 594, 599, 603, 607, 612, 616, 621, +625, 630, 634, 639, 643, 648, 652, 657, 661, 666, 670, 675, 680, 684, 689, 693, +698, 703, 708, 712, 717, 722, 726, 731, 736, 741, 745, 750, 755, 760, 765, 770, +774, 779, 784, 789, 794, 799, 804, 809, 814, 819, 824, 829, 834, 839, 844, 849, +854, 859, 864, 869, 874, 880, 885, 890, 895, 900, 906, 911, 916, 921, 927, 932, +937, 942, 948, 953, 959, 964, 969, 975, 980, 986, 991, 996, 1002, 1007, 1013, 1018 +}; +/* fullsin_table[x] = round(-log2(sin((x + 0.5) * PI / (PG_WIDTH / 4) / 2)) * 256) */ +static uint16_t fullsin_table[PG_WIDTH] = { +2137, 1731, 1543, 1419, 1326, 1252, 1190, 1137, 1091, 1050, 1013, 979, 949, 920, 894, 869, +846, 825, 804, 785, 767, 749, 732, 717, 701, 687, 672, 659, 646, 633, 621, 609, +598, 587, 576, 566, 556, 546, 536, 527, 518, 509, 501, 492, 484, 476, 468, 461, +453, 446, 439, 432, 425, 418, 411, 405, 399, 392, 386, 380, 375, 369, 363, 358, +352, 347, 341, 336, 331, 326, 321, 316, 311, 307, 302, 297, 293, 289, 284, 280, +276, 271, 267, 263, 259, 255, 251, 248, 244, 240, 236, 233, 229, 226, 222, 219, +215, 212, 209, 205, 202, 199, 196, 193, 190, 187, 184, 181, 178, 175, 172, 169, +167, 164, 161, 159, 156, 153, 151, 148, 146, 143, 141, 138, 136, 134, 131, 129, +127, 125, 122, 120, 118, 116, 114, 112, 110, 108, 106, 104, 102, 100, 98, 96, +94, 92, 91, 89, 87, 85, 83, 82, 80, 78, 77, 75, 74, 72, 70, 69, +67, 66, 64, 63, 62, 60, 59, 57, 56, 55, 53, 52, 51, 49, 48, 47, +46, 45, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, +29, 28, 27, 26, 25, 24, 23, 23, 22, 21, 20, 20, 19, 18, 17, 17, +16, 15, 15, 14, 13, 13, 12, 12, 11, 10, 10, 9, 9, 8, 8, 7, +7, 7, 6, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, +2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, +}; +/* clang-format on */ + +static uint16_t halfsin_table[PG_WIDTH]; +static uint16_t *wave_table_map[2] = {fullsin_table, halfsin_table}; + +/* pitch modulator */ +/* offset to fnum, rough approximation of 14 cents depth. */ +static int8_t pm_table[8][8] = { + {0, 0, 0, 0, 0, 0, 0, 0}, /* fnum = 000xxxxxx */ + {0, 0, 1, 0, 0, 0, -1, 0}, /* fnum = 001xxxxxx */ + {0, 1, 2, 1, 0, -1, -2, -1}, /* fnum = 010xxxxxx */ + {0, 1, 3, 1, 0, -1, -3, -1}, /* fnum = 011xxxxxx */ + {0, 2, 4, 2, 0, -2, -4, -2}, /* fnum = 100xxxxxx */ + {0, 2, 5, 2, 0, -2, -5, -2}, /* fnum = 101xxxxxx */ + {0, 3, 6, 3, 0, -3, -6, -3}, /* fnum = 110xxxxxx */ + {0, 3, 7, 3, 0, -3, -7, -3}, /* fnum = 111xxxxxx */ +}; + +/* amplitude lfo table */ +/* The following envelop pattern is verified on real YM2413. */ +/* each element repeates 64 cycles */ +static uint8_t am_table[210] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* */ + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, /* */ + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, /* */ + 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, /* */ + 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, /* */ + 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, /* */ + 12, 12, 12, 12, 12, 12, 12, 12, /* */ + 13, 13, 13, /* */ + 12, 12, 12, 12, 12, 12, 12, 12, /* */ + 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, /* */ + 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, /* */ + 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, /* */ + 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, /* */ + 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, /* */ + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 +}; + +/* envelope decay increment step table */ +/* based on andete's research */ +static uint8_t eg_step_tables[4][8] = { + {0, 1, 0, 1, 0, 1, 0, 1}, + {0, 1, 0, 1, 1, 1, 0, 1}, + {0, 1, 1, 1, 0, 1, 1, 1}, + {0, 1, 1, 1, 1, 1, 1, 1}, +}; + +enum __OPLL_EG_STATE { ATTACK, DECAY, SUSTAIN, RELEASE, DAMP, UNKNOWN }; + +static uint32_t ml_table[16] = {1, 1 * 2, 2 * 2, 3 * 2, 4 * 2, 5 * 2, 6 * 2, 7 * 2, + 8 * 2, 9 * 2, 10 * 2, 10 * 2, 12 * 2, 12 * 2, 15 * 2, 15 * 2}; + +#define dB2(x) ((x)*2) +static double kl_table[16] = {dB2(0.000), dB2(9.000), dB2(12.000), dB2(13.875), dB2(15.000), dB2(16.125), + dB2(16.875), dB2(17.625), dB2(18.000), dB2(18.750), dB2(19.125), dB2(19.500), + dB2(19.875), dB2(20.250), dB2(20.625), dB2(21.000)}; + +static uint32_t tll_table[8 * 16][1 << TL_BITS][4]; +static int32_t rks_table[8 * 2][2]; + +static OPLL_PATCH null_patch = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static OPLL_PATCH default_patch[OPLL_TONE_NUM][(16 + 3) * 2]; + +/* don't forget min/max is defined as a macro in stdlib.h of Visual C. */ +#ifndef min +static INLINE int min(int i, int j) { return (i < j) ? i : j; } +#endif +#ifndef max +static INLINE int max(int i, int j) { return (i > j) ? i : j; } +#endif + +/*************************************************** + + Internal Sample Rate Converter + +****************************************************/ +/* Note: to disable internal rate converter, set clock/72 to output sampling rate. */ + +/* + * LW is truncate length of sinc(x) calculation. + * Lower LW is faster, higher LW results better quality. + * LW must be a non-zero positive even number, no upper limit. + * LW=16 or greater is recommended when upsampling. + * LW=8 is practically okay for downsampling. + */ +#define LW 16 + +/* resolution of sinc(x) table. sinc(x) where 0.0<=x<1.0 corresponds to sinc_table[0...SINC_RESO-1] */ +#define SINC_RESO 256 +#define SINC_AMP_BITS 12 + +/* double hamming(double x) { return 0.54 - 0.46 * cos(2 * PI * x); } */ +static double blackman(double x) { return 0.42 - 0.5 * cos(2 * _PI_ * x) + 0.08 * cos(4 * _PI_ * x); } +static double sinc(double x) { return (x == 0.0 ? 1.0 : sin(_PI_ * x) / (_PI_ * x)); } +static double windowed_sinc(double x) { return blackman(0.5 + 0.5 * x / (LW / 2)) * sinc(x); } + +/* f_inp: input frequency. f_out: output frequencey, ch: number of channels */ +OPLL_RateConv *OPLL_RateConv_new(double f_inp, double f_out, int ch) { + OPLL_RateConv *conv = malloc(sizeof(OPLL_RateConv)); + int i; + + conv->ch = ch; + conv->f_ratio = f_inp / f_out; + conv->buf = malloc(sizeof(void *) * ch); + for (i = 0; i < ch; i++) { + conv->buf[i] = malloc(sizeof(conv->buf[0][0]) * LW); + } + + /* create sinc_table for positive 0 <= x < LW/2 */ + conv->sinc_table = malloc(sizeof(conv->sinc_table[0]) * SINC_RESO * LW / 2); + for (i = 0; i < SINC_RESO * LW / 2; i++) { + const double x = (double)i / SINC_RESO; + if (f_out < f_inp) { + /* for downsampling */ + conv->sinc_table[i] = (int16_t)((1 << SINC_AMP_BITS) * windowed_sinc(x / conv->f_ratio) / conv->f_ratio); + } else { + /* for upsampling */ + conv->sinc_table[i] = (int16_t)((1 << SINC_AMP_BITS) * windowed_sinc(x)); + } + } + + return conv; +} + +static INLINE int16_t lookup_sinc_table(int16_t *table, double x) { + int16_t index = (int16_t)(x * SINC_RESO); + if (index < 0) + index = -index; + return table[min(SINC_RESO * LW / 2 - 1, index)]; +} + +void OPLL_RateConv_reset(OPLL_RateConv *conv) { + int i; + conv->timer = 0; + for (i = 0; i < conv->ch; i++) { + memset(conv->buf[i], 0, sizeof(conv->buf[i][0]) * LW); + } +} + +/* put original data to this converter at f_inp. */ +void OPLL_RateConv_putData(OPLL_RateConv *conv, int ch, int16_t data) { + int16_t *buf = conv->buf[ch]; + int i; + for (i = 0; i < LW - 1; i++) { + buf[i] = buf[i + 1]; + } + buf[LW - 1] = data; +} + +/* get resampled data from this converter at f_out. */ +/* this function must be called f_out / f_inp times per one putData call. */ +int16_t OPLL_RateConv_getData(OPLL_RateConv *conv, int ch) { + int16_t *buf = conv->buf[ch]; + int32_t sum = 0; + int k; + double dn; + conv->timer += conv->f_ratio; + dn = conv->timer - floor(conv->timer); + conv->timer = dn; + + for (k = 0; k < LW; k++) { + double x = ((double)k - (LW / 2 - 1)) - dn; + sum += buf[k] * lookup_sinc_table(conv->sinc_table, x); + } + return sum >> SINC_AMP_BITS; +} + +void OPLL_RateConv_delete(OPLL_RateConv *conv) { + int i; + for (i = 0; i < conv->ch; i++) { + free(conv->buf[i]); + } + free(conv->buf); + free(conv->sinc_table); + free(conv); +} + +/*************************************************** + + Create tables + +****************************************************/ + +static void makeSinTable(void) { + int x; + + for (x = 0; x < PG_WIDTH / 4; x++) { + fullsin_table[PG_WIDTH / 4 + x] = fullsin_table[PG_WIDTH / 4 - x - 1]; + } + + for (x = 0; x < PG_WIDTH / 2; x++) { + fullsin_table[PG_WIDTH / 2 + x] = 0x8000 | fullsin_table[x]; + } + + for (x = 0; x < PG_WIDTH / 2; x++) + halfsin_table[x] = fullsin_table[x]; + + for (x = PG_WIDTH / 2; x < PG_WIDTH; x++) + halfsin_table[x] = 0xfff; +} + +static void makeTllTable(void) { + + int32_t tmp; + int32_t fnum, block, TL, KL; + + for (fnum = 0; fnum < 16; fnum++) { + for (block = 0; block < 8; block++) { + for (TL = 0; TL < 64; TL++) { + for (KL = 0; KL < 4; KL++) { + if (KL == 0) { + tll_table[(block << 4) | fnum][TL][KL] = TL2EG(TL); + } else { + tmp = (int32_t)(kl_table[fnum] - dB2(3.000) * (7 - block)); + if (tmp <= 0) + tll_table[(block << 4) | fnum][TL][KL] = TL2EG(TL); + else + tll_table[(block << 4) | fnum][TL][KL] = (uint32_t)((tmp >> (3 - KL)) / EG_STEP) + TL2EG(TL); + } + } + } + } + } +} + +static void makeRksTable(void) { + int fnum8, block; + for (fnum8 = 0; fnum8 < 2; fnum8++) + for (block = 0; block < 8; block++) { + rks_table[(block << 1) | fnum8][1] = (block << 1) + fnum8; + rks_table[(block << 1) | fnum8][0] = block >> 1; + } +} + +static void makeDefaultPatch(void) { + int i, j; + for (i = 0; i < OPLL_TONE_NUM; i++) + for (j = 0; j < 19; j++) + OPLL_getDefaultPatch(i, j, &default_patch[i][j * 2]); +} + +static uint8_t table_initialized = 0; + +static void initializeTables(void) { + makeTllTable(); + makeRksTable(); + makeSinTable(); + makeDefaultPatch(); + table_initialized = 1; +} + +/********************************************************* + + Synthesizing + +*********************************************************/ +#define SLOT_BD1 12 +#define SLOT_BD2 13 +#define SLOT_HH 14 +#define SLOT_SD 15 +#define SLOT_TOM 16 +#define SLOT_CYM 17 + +/* utility macros */ +#define MOD(o, x) (&(o)->slot[(x) << 1]) +#define CAR(o, x) (&(o)->slot[((x) << 1) | 1]) +#define BIT(s, b) (((s) >> (b)) & 1) + +#if OPLL_DEBUG +static void _debug_print_patch(OPLL_SLOT *slot) { + OPLL_PATCH *p = slot->patch; + printf("[slot#%d am:%d pm:%d eg:%d kr:%d ml:%d kl:%d tl:%d ws:%d fb:%d A:%d D:%d S:%d R:%d]\n", slot->number, // + p->AM, p->PM, p->EG, p->KR, p->ML, // + p->KL, p->TL, p->WS, p->FB, // + p->AR, p->DR, p->SL, p->RR); +} + +static char *_debug_eg_state_name(OPLL_SLOT *slot) { + switch (slot->eg_state) { + case ATTACK: + return "attack"; + case DECAY: + return "decay"; + case SUSTAIN: + return "sustain"; + case RELEASE: + return "release"; + case DAMP: + return "damp"; + default: + return "unknown"; + } +} + +static INLINE void _debug_print_slot_info(OPLL_SLOT *slot) { + char *name = _debug_eg_state_name(slot); + printf("[slot#%d state:%s fnum:%03x rate:%d-%d]\n", slot->number, name, slot->blk_fnum, slot->eg_rate_h, + slot->eg_rate_l); + _debug_print_patch(slot); + fflush(stdout); +} +#endif + +static INLINE int get_parameter_rate(OPLL_SLOT *slot) { + + if ((slot->type & 1) == 0 && slot->key_flag == 0) { + return 0; + } + + switch (slot->eg_state) { + case ATTACK: + return slot->patch->AR; + case DECAY: + return slot->patch->DR; + case SUSTAIN: + return slot->patch->EG ? 0 : slot->patch->RR; + case RELEASE: + if (slot->sus_flag) { + return 5; + } else if (slot->patch->EG) { + return slot->patch->RR; + } else { + return 7; + } + case DAMP: + return DAMPER_RATE; + default: + return 0; + } +} + +enum SLOT_UPDATE_FLAG { + UPDATE_WS = 1, + UPDATE_TLL = 2, + UPDATE_RKS = 4, + UPDATE_EG = 8, + UPDATE_ALL = 255 +}; + +static INLINE void request_update(OPLL_SLOT *slot, int flag) { slot->update_requests |= flag; } + +static void commit_slot_update(OPLL_SLOT *slot) { + +#if OPLL_DEBUG + if (slot->last_eg_state != slot->eg_state) { + _debug_print_slot_info(slot); + slot->last_eg_state = slot->eg_state; + } +#endif + + if (slot->update_requests & UPDATE_WS) { + slot->wave_table = wave_table_map[slot->patch->WS]; + } + + if (slot->update_requests & UPDATE_TLL) { + if ((slot->type & 1) == 0) { + slot->tll = tll_table[slot->blk_fnum >> 5][slot->patch->TL][slot->patch->KL]; + } else { + slot->tll = tll_table[slot->blk_fnum >> 5][slot->volume][slot->patch->KL]; + } + } + + if (slot->update_requests & UPDATE_RKS) { + slot->rks = rks_table[slot->blk_fnum >> 8][slot->patch->KR]; + } + + if (slot->update_requests & (UPDATE_RKS | UPDATE_EG)) { + int p_rate = get_parameter_rate(slot); + + if (p_rate == 0) { + slot->eg_shift = 0; + slot->eg_rate_h = 0; + slot->eg_rate_l = 0; + return; + } + + slot->eg_rate_h = min(15, p_rate + (slot->rks >> 2)); + slot->eg_rate_l = slot->rks & 3; + if (slot->eg_state == ATTACK) { + slot->eg_shift = (0 < slot->eg_rate_h && slot->eg_rate_h < 12) ? (13 - slot->eg_rate_h) : 0; + } else { + slot->eg_shift = (slot->eg_rate_h < 13) ? (13 - slot->eg_rate_h) : 0; + } + } + + slot->update_requests = 0; +} + +static void reset_slot(OPLL_SLOT *slot, int number) { + slot->number = number; + slot->type = number % 2; + slot->pg_keep = 0; + slot->wave_table = wave_table_map[0]; + slot->pg_phase = 0; + slot->output[0] = 0; + slot->output[1] = 0; + slot->eg_state = RELEASE; + slot->eg_shift = 0; + slot->rks = 0; + slot->tll = 0; + slot->key_flag = 0; + slot->sus_flag = 0; + slot->blk_fnum = 0; + slot->blk = 0; + slot->fnum = 0; + slot->volume = 0; + slot->pg_out = 0; + slot->eg_out = EG_MUTE; + slot->patch = &null_patch; +} + +static INLINE void slotOn(OPLL *opll, int i) { + OPLL_SLOT *slot = &opll->slot[i]; + slot->key_flag = 1; + slot->eg_state = DAMP; + request_update(slot, UPDATE_EG); +} + +static INLINE void slotOff(OPLL *opll, int i) { + OPLL_SLOT *slot = &opll->slot[i]; + slot->key_flag = 0; + if (slot->type & 1) { + slot->eg_state = RELEASE; + request_update(slot, UPDATE_EG); + } +} + +static INLINE void update_key_status(OPLL *opll) { + const uint8_t r14 = opll->reg[0x0e]; + const uint8_t rhythm_mode = BIT(r14, 5); + uint32_t new_slot_key_status = 0; + uint32_t updated_status; + int ch; + + for (ch = 0; ch < 9; ch++) + if (opll->reg[0x20 + ch] & 0x10) + new_slot_key_status |= 3 << (ch * 2); + + if (rhythm_mode) { + if (r14 & 0x10) + new_slot_key_status |= 3 << SLOT_BD1; + + if (r14 & 0x01) + new_slot_key_status |= 1 << SLOT_HH; + + if (r14 & 0x08) + new_slot_key_status |= 1 << SLOT_SD; + + if (r14 & 0x04) + new_slot_key_status |= 1 << SLOT_TOM; + + if (r14 & 0x02) + new_slot_key_status |= 1 << SLOT_CYM; + } + + updated_status = opll->slot_key_status ^ new_slot_key_status; + + if (updated_status) { + int i; + for (i = 0; i < 18; i++) + if (BIT(updated_status, i)) { + if (BIT(new_slot_key_status, i)) { + slotOn(opll, i); + } else { + slotOff(opll, i); + } + } + } + + opll->slot_key_status = new_slot_key_status; +} + +static INLINE void set_patch(OPLL *opll, int32_t ch, int32_t num) { + opll->patch_number[ch] = num; + MOD(opll, ch)->patch = &opll->patch[num * 2 + 0]; + CAR(opll, ch)->patch = &opll->patch[num * 2 + 1]; + request_update(MOD(opll, ch), UPDATE_ALL); + request_update(CAR(opll, ch), UPDATE_ALL); +} + +static INLINE void set_sus_flag(OPLL *opll, int ch, int flag) { + CAR(opll, ch)->sus_flag = flag; + request_update(CAR(opll, ch), UPDATE_EG); + if (MOD(opll, ch)->type & 1) { + MOD(opll, ch)->sus_flag = flag; + request_update(MOD(opll, ch), UPDATE_EG); + } +} + +/* set volume ( volume : 6bit, register value << 2 ) */ +static INLINE void set_volume(OPLL *opll, int ch, int volume) { + CAR(opll, ch)->volume = volume; + request_update(CAR(opll, ch), UPDATE_TLL); +} + +static INLINE void set_slot_volume(OPLL_SLOT *slot, int volume) { + slot->volume = volume; + request_update(slot, UPDATE_TLL); +} + +/* set f-Nnmber ( fnum : 9bit ) */ +static INLINE void set_fnumber(OPLL *opll, int ch, int fnum) { + OPLL_SLOT *car = CAR(opll, ch); + OPLL_SLOT *mod = MOD(opll, ch); + car->fnum = fnum; + car->blk_fnum = (car->blk_fnum & 0xe00) | (fnum & 0x1ff); + mod->fnum = fnum; + mod->blk_fnum = (mod->blk_fnum & 0xe00) | (fnum & 0x1ff); + request_update(car, UPDATE_EG | UPDATE_RKS | UPDATE_TLL); + request_update(mod, UPDATE_EG | UPDATE_RKS | UPDATE_TLL); +} + +/* set block data (blk : 3bit ) */ +static INLINE void set_block(OPLL *opll, int ch, int blk) { + OPLL_SLOT *car = CAR(opll, ch); + OPLL_SLOT *mod = MOD(opll, ch); + car->blk = blk; + car->blk_fnum = ((blk & 7) << 9) | (car->blk_fnum & 0x1ff); + mod->blk = blk; + mod->blk_fnum = ((blk & 7) << 9) | (mod->blk_fnum & 0x1ff); + request_update(car, UPDATE_EG | UPDATE_RKS | UPDATE_TLL); + request_update(mod, UPDATE_EG | UPDATE_RKS | UPDATE_TLL); +} + +static INLINE void update_rhythm_mode(OPLL *opll) { + const uint8_t new_rhythm_mode = (opll->reg[0x0e] >> 5) & 1; + + if (opll->rhythm_mode != new_rhythm_mode) { + + if (new_rhythm_mode) { + opll->slot[SLOT_HH].type = 3; + opll->slot[SLOT_HH].pg_keep = 1; + opll->slot[SLOT_SD].type = 3; + opll->slot[SLOT_TOM].type = 3; + opll->slot[SLOT_CYM].type = 3; + opll->slot[SLOT_CYM].pg_keep = 1; + set_patch(opll, 6, 16); + set_patch(opll, 7, 17); + set_patch(opll, 8, 18); + set_slot_volume(&opll->slot[SLOT_HH], ((opll->reg[0x37] >> 4) & 15) << 2); + set_slot_volume(&opll->slot[SLOT_TOM], ((opll->reg[0x38] >> 4) & 15) << 2); + } else { + opll->slot[SLOT_HH].type = 0; + opll->slot[SLOT_HH].pg_keep = 0; + opll->slot[SLOT_SD].type = 1; + opll->slot[SLOT_TOM].type = 0; + opll->slot[SLOT_CYM].type = 1; + opll->slot[SLOT_CYM].pg_keep = 0; + set_patch(opll, 6, opll->reg[0x36] >> 4); + set_patch(opll, 7, opll->reg[0x37] >> 4); + set_patch(opll, 8, opll->reg[0x38] >> 4); + } + } + + opll->rhythm_mode = new_rhythm_mode; +} + +static void update_ampm(OPLL *opll) { + if (opll->test_flag & 2) { + opll->pm_phase = 0; + opll->am_phase = 0; + } else { + opll->pm_phase += (opll->test_flag & 8) ? 1024 : 1; + opll->am_phase += (opll->test_flag & 8) ? 64 : 1; + } + opll->lfo_am = am_table[(opll->am_phase >> 6) % sizeof(am_table)]; +} + +static void update_noise(OPLL *opll, int cycle) { + int i; + for (i = 0; i < cycle; i++) { + if (opll->noise & 1) { + opll->noise ^= 0x800200; + } + opll->noise >>= 1; + } +} + +static void update_short_noise(OPLL *opll) { + const uint32_t pg_hh = opll->slot[SLOT_HH].pg_out; + const uint32_t pg_cym = opll->slot[SLOT_CYM].pg_out; + + const uint8_t h_bit2 = BIT(pg_hh, PG_BITS - 8); + const uint8_t h_bit7 = BIT(pg_hh, PG_BITS - 3); + const uint8_t h_bit3 = BIT(pg_hh, PG_BITS - 7); + + const uint8_t c_bit3 = BIT(pg_cym, PG_BITS - 7); + const uint8_t c_bit5 = BIT(pg_cym, PG_BITS - 5); + + opll->short_noise = (h_bit2 ^ h_bit7) | (h_bit3 ^ c_bit5) | (c_bit3 ^ c_bit5); +} + +static INLINE void calc_phase(OPLL_SLOT *slot, int32_t pm_phase, uint8_t reset) { + const int8_t pm = slot->patch->PM ? pm_table[(slot->fnum >> 6) & 7][(pm_phase >> 10) & 7] : 0; + if (reset) { + slot->pg_phase = 0; + } + slot->pg_phase += (((slot->fnum & 0x1ff) * 2 + pm) * ml_table[slot->patch->ML]) << slot->blk >> 2; + slot->pg_phase &= (DP_WIDTH - 1); + slot->pg_out = slot->pg_phase >> DP_BASE_BITS; +} + +static INLINE uint8_t lookup_attack_step(OPLL_SLOT *slot, uint32_t counter) { + int index; + + switch (slot->eg_rate_h) { + case 12: + index = (counter & 0xc) >> 1; + return 4 - eg_step_tables[slot->eg_rate_l][index]; + case 13: + index = (counter & 0xc) >> 1; + return 3 - eg_step_tables[slot->eg_rate_l][index]; + case 14: + index = (counter & 0xc) >> 1; + return 2 - eg_step_tables[slot->eg_rate_l][index]; + case 0: + case 15: + return 0; + default: + index = counter >> slot->eg_shift; + return eg_step_tables[slot->eg_rate_l][index & 7] ? 4 : 0; + } +} + +static INLINE uint8_t lookup_decay_step(OPLL_SLOT *slot, uint32_t counter) { + int index; + + switch (slot->eg_rate_h) { + case 0: + return 0; + case 13: + index = ((counter & 0xc) >> 1) | (counter & 1); + return eg_step_tables[slot->eg_rate_l][index]; + case 14: + index = ((counter & 0xc) >> 1); + return eg_step_tables[slot->eg_rate_l][index] + 1; + case 15: + return 2; + default: + index = counter >> slot->eg_shift; + return eg_step_tables[slot->eg_rate_l][index & 7]; + } +} + +static INLINE void start_envelope(OPLL_SLOT *slot) { + if (min(15, slot->patch->AR + (slot->rks >> 2)) == 15) { + slot->eg_state = DECAY; + slot->eg_out = 0; + } else { + slot->eg_state = ATTACK; + } + request_update(slot, UPDATE_EG); +} + +static INLINE void calc_envelope(OPLL_SLOT *slot, OPLL_SLOT *buddy, uint16_t eg_counter, uint8_t test) { + + uint32_t mask = (1 << slot->eg_shift) - 1; + uint8_t s; + + if (slot->eg_state == ATTACK) { + if (0 < slot->eg_out && 0 < slot->eg_rate_h && (eg_counter & mask & ~3) == 0) { + s = lookup_attack_step(slot, eg_counter); + if (0 < s) { + slot->eg_out = max(0, ((int)slot->eg_out - (slot->eg_out >> s) - 1)); + } + } + } else { + if (slot->eg_rate_h > 0 && (eg_counter & mask) == 0) { + slot->eg_out = min(EG_MUTE, slot->eg_out + lookup_decay_step(slot, eg_counter)); + } + } + + switch (slot->eg_state) { + case DAMP: + /* DAMP to ATTACK transition is occured when the envelope reaches EG_MAX (max attenuation but it's not mute). + Do not forget to check (eg_counter & mask) == 0 to synchronize it with the progress of the envelope. */ + if (slot->eg_out >= EG_MAX && (eg_counter & mask) == 0) { + start_envelope(slot); + if (slot->type & 1) { + if (!slot->pg_keep) { + slot->pg_phase = 0; + } + if (buddy && !buddy->pg_keep) { + buddy->pg_phase = 0; + } + } + } + break; + + case ATTACK: + if (slot->eg_out == 0) { + slot->eg_state = DECAY; + request_update(slot, UPDATE_EG); + } + break; + + case DECAY: + /* DECAY to SUSTAIN transition must be checked at every cycle regardless of the conditions of the envelope rate and + counter. i.e. the transition is not synchronized with the progress of the envelope. */ + if ((slot->eg_out >> 3) == slot->patch->SL) { + slot->eg_state = SUSTAIN; + request_update(slot, UPDATE_EG); + } + break; + + case SUSTAIN: + case RELEASE: + default: + break; + } + + if (test) { + slot->eg_out = 0; + } +} + +static void update_slots(OPLL *opll) { + int i; + opll->eg_counter++; + + for (i = 0; i < 18; i++) { + OPLL_SLOT *slot = &opll->slot[i]; + OPLL_SLOT *buddy = NULL; + if (slot->type == 0) { + buddy = &opll->slot[i + 1]; + } + if (slot->type == 1) { + buddy = &opll->slot[i - 1]; + } + if (slot->update_requests) { + commit_slot_update(slot); + } + calc_envelope(slot, buddy, opll->eg_counter, opll->test_flag & 1); + calc_phase(slot, opll->pm_phase, opll->test_flag & 4); + } +} + +/* output: -4095...4095 */ +static INLINE int16_t lookup_exp_table(uint16_t i) { + /* from andete's expression */ + int16_t t = (exp_table[(i & 0xff) ^ 0xff] + 1024); + int16_t res = t >> ((i & 0x7f00) >> 8); + return ((i & 0x8000) ? ~res : res) << 1; +} + +static INLINE int16_t to_linear(uint16_t h, OPLL_SLOT *slot, int16_t am) { + uint16_t att; + if (slot->eg_out > EG_MAX) + return 0; + + att = min(EG_MUTE, (slot->eg_out + slot->tll + am)) << 4; + return lookup_exp_table(h + att); +} + +static INLINE int16_t calc_slot_car(OPLL *opll, int ch, int16_t fm) { + OPLL_SLOT *slot = CAR(opll, ch); + + uint8_t am = slot->patch->AM ? opll->lfo_am : 0; + + slot->output[1] = slot->output[0]; + slot->output[0] = to_linear(slot->wave_table[(slot->pg_out + 2 * (fm >> 1)) & (PG_WIDTH - 1)], slot, am); + + return slot->output[0]; +} + +static INLINE int16_t calc_slot_mod(OPLL *opll, int ch) { + OPLL_SLOT *slot = MOD(opll, ch); + + int16_t fm = slot->patch->FB > 0 ? (slot->output[1] + slot->output[0]) >> (9 - slot->patch->FB) : 0; + uint8_t am = slot->patch->AM ? opll->lfo_am : 0; + + slot->output[1] = slot->output[0]; + slot->output[0] = to_linear(slot->wave_table[(slot->pg_out + fm) & (PG_WIDTH - 1)], slot, am); + + return slot->output[0]; +} + +static INLINE int16_t calc_slot_tom(OPLL *opll) { + OPLL_SLOT *slot = MOD(opll, 8); + + return to_linear(slot->wave_table[slot->pg_out], slot, 0); +} + +/* Specify phase offset directly based on 10-bit (1024-length) sine table */ +#define _PD(phase) ((PG_BITS < 10) ? (phase >> (10 - PG_BITS)) : (phase << (PG_BITS - 10))) + +static INLINE int16_t calc_slot_snare(OPLL *opll) { + OPLL_SLOT *slot = CAR(opll, 7); + + uint32_t phase; + + if (BIT(slot->pg_out, PG_BITS - 2)) + phase = (opll->noise & 1) ? _PD(0x300) : _PD(0x200); + else + phase = (opll->noise & 1) ? _PD(0x0) : _PD(0x100); + + return to_linear(slot->wave_table[phase], slot, 0); +} + +static INLINE int16_t calc_slot_cym(OPLL *opll) { + OPLL_SLOT *slot = CAR(opll, 8); + + uint32_t phase = opll->short_noise ? _PD(0x300) : _PD(0x100); + + return to_linear(slot->wave_table[phase], slot, 0); +} + +static INLINE int16_t calc_slot_hat(OPLL *opll) { + OPLL_SLOT *slot = MOD(opll, 7); + + uint32_t phase; + + if (opll->short_noise) + phase = (opll->noise & 1) ? _PD(0x2d0) : _PD(0x234); + else + phase = (opll->noise & 1) ? _PD(0x34) : _PD(0xd0); + + return to_linear(slot->wave_table[phase], slot, 0); +} + +#define _MO(x) (-(x) >> 1) +#define _RO(x) (x) + +static void update_output(OPLL *opll) { + int16_t *out; + int i; + + update_ampm(opll); + update_short_noise(opll); + update_slots(opll); + + out = opll->ch_out; + + /* CH1-6 */ + for (i = 0; i < 6; i++) { + if (!(opll->mask & OPLL_MASK_CH(i))) { + out[i] = _MO(calc_slot_car(opll, i, calc_slot_mod(opll, i))); + } + } + + /* CH7 */ + if (!opll->rhythm_mode) { + if (!(opll->mask & OPLL_MASK_CH(6))) { + out[6] = _MO(calc_slot_car(opll, 6, calc_slot_mod(opll, 6))); + } + } else { + if (!(opll->mask & OPLL_MASK_BD)) { + out[9] = _RO(calc_slot_car(opll, 6, calc_slot_mod(opll, 6))); + } + } + update_noise(opll, 14); + + /* CH8 */ + if (!opll->rhythm_mode) { + if (!(opll->mask & OPLL_MASK_CH(7))) { + out[7] = _MO(calc_slot_car(opll, 7, calc_slot_mod(opll, 7))); + } + } else { + if (!(opll->mask & OPLL_MASK_HH)) { + out[10] = _RO(calc_slot_hat(opll)); + } + if (!(opll->mask & OPLL_MASK_SD)) { + out[11] = _RO(calc_slot_snare(opll)); + } + } + update_noise(opll, 2); + + /* CH9 */ + if (!opll->rhythm_mode) { + if (!(opll->mask & OPLL_MASK_CH(8))) { + out[8] = _MO(calc_slot_car(opll, 8, calc_slot_mod(opll, 8))); + } + } else { + if (!(opll->mask & OPLL_MASK_TOM)) { + out[12] = _RO(calc_slot_tom(opll)); + } + if (!(opll->mask & OPLL_MASK_CYM)) { + out[13] = _RO(calc_slot_cym(opll)); + } + } + update_noise(opll, 2); +} + +INLINE static void mix_output(OPLL *opll) { + int16_t out = 0; + int i; + for (i = 0; i < 14; i++) { + out += opll->ch_out[i]; + } + if (opll->conv) { + OPLL_RateConv_putData(opll->conv, 0, out); + } else { + opll->mix_out[0] = out; + } +} + +INLINE static void mix_output_stereo(OPLL *opll) { + int16_t *out = opll->mix_out; + int i; + out[0] = out[1] = 0; + for (i = 0; i < 14; i++) { + if (opll->pan[i] & 2) + out[0] += (int16_t)(opll->ch_out[i] * opll->pan_fine[i][0]); + if (opll->pan[i] & 1) + out[1] += (int16_t)(opll->ch_out[i] * opll->pan_fine[i][1]); + } + if (opll->conv) { + OPLL_RateConv_putData(opll->conv, 0, out[0]); + OPLL_RateConv_putData(opll->conv, 1, out[1]); + } +} + +/*********************************************************** + + External Interfaces + +***********************************************************/ + +OPLL *OPLL_new(uint32_t clk, uint32_t rate) { + OPLL *opll; + int i; + + if (!table_initialized) { + initializeTables(); + } + + opll = (OPLL *)calloc(sizeof(OPLL), 1); + if (opll == NULL) + return NULL; + + for (i = 0; i < 19 * 2; i++) + memcpy(&opll->patch[i], &null_patch, sizeof(OPLL_PATCH)); + + opll->clk = clk; + opll->rate = rate; + opll->mask = 0; + opll->conv = NULL; + opll->mix_out[0] = 0; + opll->mix_out[1] = 0; + + OPLL_reset(opll); + OPLL_setChipType(opll, 0); + OPLL_resetPatch(opll, 0); + return opll; +} + +void OPLL_delete(OPLL *opll) { + if (opll->conv) { + OPLL_RateConv_delete(opll->conv); + opll->conv = NULL; + } + free(opll); +} + +static void reset_rate_conversion_params(OPLL *opll) { + const double f_out = opll->rate; + const double f_inp = opll->clk / 72.0; + + opll->out_time = 0; + opll->out_step = f_inp; + opll->inp_step = f_out; + + if (opll->conv) { + OPLL_RateConv_delete(opll->conv); + opll->conv = NULL; + } + + if (floor(f_inp) != f_out && floor(f_inp + 0.5) != f_out) { + opll->conv = OPLL_RateConv_new(f_inp, f_out, 2); + } + + if (opll->conv) { + OPLL_RateConv_reset(opll->conv); + } +} + +void OPLL_reset(OPLL *opll) { + int i; + + if (!opll) + return; + + opll->adr = 0; + + opll->pm_phase = 0; + opll->am_phase = 0; + + opll->noise = 0x1; + opll->mask = 0; + + opll->rhythm_mode = 0; + opll->slot_key_status = 0; + opll->eg_counter = 0; + + reset_rate_conversion_params(opll); + + for (i = 0; i < 18; i++) + reset_slot(&opll->slot[i], i); + + for (i = 0; i < 9; i++) { + set_patch(opll, i, 0); + } + + for (i = 0; i < 0x40; i++) + OPLL_writeReg(opll, i, 0); + + for (i = 0; i < 15; i++) { + opll->pan[i] = 3; + opll->pan_fine[i][1] = opll->pan_fine[i][0] = 1.0f; + } + + for (i = 0; i < 14; i++) { + opll->ch_out[i] = 0; + } +} + +void OPLL_forceRefresh(OPLL *opll) { + int i; + + if (opll == NULL) + return; + + for (i = 0; i < 9; i++) { + set_patch(opll, i, opll->patch_number[i]); + } + + for (i = 0; i < 18; i++) { + request_update(&opll->slot[i], UPDATE_ALL); + } +} + +void OPLL_setRate(OPLL *opll, uint32_t rate) { + opll->rate = rate; + reset_rate_conversion_params(opll); +} + +void OPLL_setQuality(OPLL *opll, uint8_t q) {} + +void OPLL_setChipType(OPLL *opll, uint8_t type) { opll->chip_type = type; } + +void OPLL_writeReg(OPLL *opll, uint32_t reg, uint8_t data) { + int ch, i; + + if (reg >= 0x40) + return; + + /* mirror registers */ + if ((0x19 <= reg && reg <= 0x1f) || (0x29 <= reg && reg <= 0x2f) || (0x39 <= reg && reg <= 0x3f)) { + reg -= 9; + } + + opll->reg[reg] = (uint8_t)data; + + switch (reg) { + case 0x00: + opll->patch[0].AM = (data >> 7) & 1; + opll->patch[0].PM = (data >> 6) & 1; + opll->patch[0].EG = (data >> 5) & 1; + opll->patch[0].KR = (data >> 4) & 1; + opll->patch[0].ML = (data)&15; + for (i = 0; i < 9; i++) { + if (opll->patch_number[i] == 0) { + request_update(MOD(opll, i), UPDATE_RKS | UPDATE_EG); + } + } + break; + + case 0x01: + opll->patch[1].AM = (data >> 7) & 1; + opll->patch[1].PM = (data >> 6) & 1; + opll->patch[1].EG = (data >> 5) & 1; + opll->patch[1].KR = (data >> 4) & 1; + opll->patch[1].ML = (data)&15; + for (i = 0; i < 9; i++) { + if (opll->patch_number[i] == 0) { + request_update(CAR(opll, i), UPDATE_RKS | UPDATE_EG); + } + } + break; + + case 0x02: + opll->patch[0].KL = (data >> 6) & 3; + opll->patch[0].TL = (data)&63; + for (i = 0; i < 9; i++) { + if (opll->patch_number[i] == 0) { + request_update(MOD(opll, i), UPDATE_TLL); + } + } + break; + + case 0x03: + opll->patch[1].KL = (data >> 6) & 3; + opll->patch[1].WS = (data >> 4) & 1; + opll->patch[0].WS = (data >> 3) & 1; + opll->patch[0].FB = (data)&7; + for (i = 0; i < 9; i++) { + if (opll->patch_number[i] == 0) { + request_update(MOD(opll, i), UPDATE_WS); + request_update(CAR(opll, i), UPDATE_WS | UPDATE_TLL); + } + } + break; + + case 0x04: + opll->patch[0].AR = (data >> 4) & 15; + opll->patch[0].DR = (data)&15; + for (i = 0; i < 9; i++) { + if (opll->patch_number[i] == 0) { + request_update(MOD(opll, i), UPDATE_EG); + } + } + break; + + case 0x05: + opll->patch[1].AR = (data >> 4) & 15; + opll->patch[1].DR = (data)&15; + for (i = 0; i < 9; i++) { + if (opll->patch_number[i] == 0) { + request_update(CAR(opll, i), UPDATE_EG); + } + } + break; + + case 0x06: + opll->patch[0].SL = (data >> 4) & 15; + opll->patch[0].RR = (data)&15; + for (i = 0; i < 9; i++) { + if (opll->patch_number[i] == 0) { + request_update(MOD(opll, i), UPDATE_EG); + } + } + break; + + case 0x07: + opll->patch[1].SL = (data >> 4) & 15; + opll->patch[1].RR = (data)&15; + for (i = 0; i < 9; i++) { + if (opll->patch_number[i] == 0) { + request_update(CAR(opll, i), UPDATE_EG); + } + } + break; + + case 0x0e: + if (opll->chip_type == 1) + break; + update_rhythm_mode(opll); + update_key_status(opll); + break; + + case 0x0f: + opll->test_flag = data; + break; + + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + ch = reg - 0x10; + set_fnumber(opll, ch, data + ((opll->reg[0x20 + ch] & 1) << 8)); + break; + + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + ch = reg - 0x20; + set_fnumber(opll, ch, ((data & 1) << 8) + opll->reg[0x10 + ch]); + set_block(opll, ch, (data >> 1) & 7); + set_sus_flag(opll, ch, (data >> 5) & 1); + update_key_status(opll); + break; + + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + if ((opll->reg[0x0e] & 32) && (reg >= 0x36)) { + switch (reg) { + case 0x37: + set_slot_volume(MOD(opll, 7), ((data >> 4) & 15) << 2); + break; + case 0x38: + set_slot_volume(MOD(opll, 8), ((data >> 4) & 15) << 2); + break; + default: + break; + } + } else { + set_patch(opll, reg - 0x30, (data >> 4) & 15); + } + set_volume(opll, reg - 0x30, (data & 15) << 2); + break; + + default: + break; + } +} + +void OPLL_writeIO(OPLL *opll, uint32_t adr, uint8_t val) { + if (adr & 1) + OPLL_writeReg(opll, opll->adr, val); + else + opll->adr = val; +} + +void OPLL_setPan(OPLL *opll, uint32_t ch, uint8_t pan) { opll->pan[ch & 15] = pan; } + +void OPLL_setPanFine(OPLL *opll, uint32_t ch, float pan[2]) { + opll->pan_fine[ch & 15][0] = pan[0]; + opll->pan_fine[ch & 15][1] = pan[1]; +} + +void OPLL_dumpToPatch(const uint8_t *dump, OPLL_PATCH *patch) { + patch[0].AM = (dump[0] >> 7) & 1; + patch[1].AM = (dump[1] >> 7) & 1; + patch[0].PM = (dump[0] >> 6) & 1; + patch[1].PM = (dump[1] >> 6) & 1; + patch[0].EG = (dump[0] >> 5) & 1; + patch[1].EG = (dump[1] >> 5) & 1; + patch[0].KR = (dump[0] >> 4) & 1; + patch[1].KR = (dump[1] >> 4) & 1; + patch[0].ML = (dump[0]) & 15; + patch[1].ML = (dump[1]) & 15; + patch[0].KL = (dump[2] >> 6) & 3; + patch[1].KL = (dump[3] >> 6) & 3; + patch[0].TL = (dump[2]) & 63; + patch[1].TL = 0; + patch[0].FB = (dump[3]) & 7; + patch[1].FB = 0; + patch[0].WS = (dump[3] >> 3) & 1; + patch[1].WS = (dump[3] >> 4) & 1; + patch[0].AR = (dump[4] >> 4) & 15; + patch[1].AR = (dump[5] >> 4) & 15; + patch[0].DR = (dump[4]) & 15; + patch[1].DR = (dump[5]) & 15; + patch[0].SL = (dump[6] >> 4) & 15; + patch[1].SL = (dump[7] >> 4) & 15; + patch[0].RR = (dump[6]) & 15; + patch[1].RR = (dump[7]) & 15; +} + +void OPLL_getDefaultPatch(int32_t type, int32_t num, OPLL_PATCH *patch) { + OPLL_dumpToPatch(default_inst[type] + num * 8, patch); +} + +void OPLL_setPatch(OPLL *opll, const uint8_t *dump) { + OPLL_PATCH patch[2]; + int i; + for (i = 0; i < 19; i++) { + OPLL_dumpToPatch(dump + i * 8, patch); + memcpy(&opll->patch[i * 2 + 0], &patch[0], sizeof(OPLL_PATCH)); + memcpy(&opll->patch[i * 2 + 1], &patch[1], sizeof(OPLL_PATCH)); + } +} + +void OPLL_patchToDump(const OPLL_PATCH *patch, uint8_t *dump) { + dump[0] = (uint8_t)((patch[0].AM << 7) + (patch[0].PM << 6) + (patch[0].EG << 5) + (patch[0].KR << 4) + patch[0].ML); + dump[1] = (uint8_t)((patch[1].AM << 7) + (patch[1].PM << 6) + (patch[1].EG << 5) + (patch[1].KR << 4) + patch[1].ML); + dump[2] = (uint8_t)((patch[0].KL << 6) + patch[0].TL); + dump[3] = (uint8_t)((patch[1].KL << 6) + (patch[1].WS << 4) + (patch[0].WS << 3) + patch[0].FB); + dump[4] = (uint8_t)((patch[0].AR << 4) + patch[0].DR); + dump[5] = (uint8_t)((patch[1].AR << 4) + patch[1].DR); + dump[6] = (uint8_t)((patch[0].SL << 4) + patch[0].RR); + dump[7] = (uint8_t)((patch[1].SL << 4) + patch[1].RR); +} + +void OPLL_copyPatch(OPLL *opll, int32_t num, OPLL_PATCH *patch) { + memcpy(&opll->patch[num], patch, sizeof(OPLL_PATCH)); +} + +void OPLL_resetPatch(OPLL *opll, uint8_t type) { + int i; + for (i = 0; i < 19 * 2; i++) + OPLL_copyPatch(opll, i, &default_patch[type % OPLL_TONE_NUM][i]); +} + +int16_t OPLL_calc(OPLL *opll) { + while (opll->out_step > opll->out_time) { + opll->out_time += opll->inp_step; + update_output(opll); + mix_output(opll); + } + opll->out_time -= opll->out_step; + if (opll->conv) { + opll->mix_out[0] = OPLL_RateConv_getData(opll->conv, 0); + } + return opll->mix_out[0]; +} + +void OPLL_calcStereo(OPLL *opll, int32_t out[2]) { + while (opll->out_step > opll->out_time) { + opll->out_time += opll->inp_step; + update_output(opll); + mix_output_stereo(opll); + } + opll->out_time -= opll->out_step; + if (opll->conv) { + out[0] = OPLL_RateConv_getData(opll->conv, 0); + out[1] = OPLL_RateConv_getData(opll->conv, 1); + } else { + out[0] = opll->mix_out[0]; + out[1] = opll->mix_out[1]; + } +} + +uint32_t OPLL_setMask(OPLL *opll, uint32_t mask) { + uint32_t ret; + + if (opll) { + ret = opll->mask; + opll->mask = mask; + return ret; + } else + return 0; +} + +uint32_t OPLL_toggleMask(OPLL *opll, uint32_t mask) { + uint32_t ret; + + if (opll) { + ret = opll->mask; + opll->mask ^= mask; + return ret; + } else + return 0; +} diff --git a/src/mappers/sound/emu2413.h b/src/mappers/sound/emu2413.h new file mode 100644 index 000000000..dbc0af1d9 --- /dev/null +++ b/src/mappers/sound/emu2413.h @@ -0,0 +1,237 @@ +#ifndef _EMU2413_H_ +#define _EMU2413_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define OPLL_DEBUG 0 + +enum OPLL_TONE_ENUM { OPLL_2413_TONE = 0, OPLL_VRC7_TONE = 1, OPLL_281B_TONE = 2 }; + +/* voice data */ +typedef struct __OPLL_PATCH { + uint32_t TL, FB, EG, ML, AR, DR, SL, RR, KR, KL, AM, PM, WS; +} OPLL_PATCH; + +/* slot */ +typedef struct __OPLL_SLOT { + uint8_t number; + + /* type flags: + * 000000SM + * |+-- M: 0:modulator 1:carrier + * +--- S: 0:normal 1:single slot mode (sd, tom, hh or cym) + */ + uint8_t type; + + OPLL_PATCH *patch; /* voice parameter */ + + /* slot output */ + int32_t output[2]; /* output value, latest and previous. */ + + /* phase generator (pg) */ + uint16_t *wave_table; /* wave table */ + uint32_t pg_phase; /* pg phase */ + uint32_t pg_out; /* pg output, as index of wave table */ + uint8_t pg_keep; /* if 1, pg_phase is preserved when key-on */ + uint16_t blk_fnum; /* (block << 9) | f-number */ + uint16_t fnum; /* f-number (9 bits) */ + uint8_t blk; /* block (3 bits) */ + + /* envelope generator (eg) */ + uint8_t eg_state; /* current state */ + int32_t volume; /* current volume */ + uint8_t key_flag; /* key-on flag 1:on 0:off */ + uint8_t sus_flag; /* key-sus option 1:on 0:off */ + uint16_t tll; /* total level + key scale level*/ + uint8_t rks; /* key scale offset (rks) for eg speed */ + uint8_t eg_rate_h; /* eg speed rate high 4bits */ + uint8_t eg_rate_l; /* eg speed rate low 2bits */ + uint32_t eg_shift; /* shift for eg global counter, controls envelope speed */ + uint32_t eg_out; /* eg output */ + + uint32_t update_requests; /* flags to debounce update */ + +#if OPLL_DEBUG + uint8_t last_eg_state; +#endif +} OPLL_SLOT; + +/* mask */ +#define OPLL_MASK_CH(x) (1 << (x)) +#define OPLL_MASK_HH (1 << (9)) +#define OPLL_MASK_CYM (1 << (10)) +#define OPLL_MASK_TOM (1 << (11)) +#define OPLL_MASK_SD (1 << (12)) +#define OPLL_MASK_BD (1 << (13)) +#define OPLL_MASK_RHYTHM (OPLL_MASK_HH | OPLL_MASK_CYM | OPLL_MASK_TOM | OPLL_MASK_SD | OPLL_MASK_BD) + +/* rate conveter */ +typedef struct __OPLL_RateConv { + int ch; + double timer; + double f_ratio; + int16_t *sinc_table; + int16_t **buf; +} OPLL_RateConv; + +OPLL_RateConv *OPLL_RateConv_new(double f_inp, double f_out, int ch); +void OPLL_RateConv_reset(OPLL_RateConv *conv); +void OPLL_RateConv_putData(OPLL_RateConv *conv, int ch, int16_t data); +int16_t OPLL_RateConv_getData(OPLL_RateConv *conv, int ch); +void OPLL_RateConv_delete(OPLL_RateConv *conv); + +typedef struct __OPLL { + uint32_t clk; + uint32_t rate; + + uint8_t chip_type; + + uint32_t adr; + + double inp_step; + double out_step; + double out_time; + + uint8_t reg[0x40]; + uint8_t test_flag; + uint32_t slot_key_status; + uint8_t rhythm_mode; + + uint32_t eg_counter; + + uint32_t pm_phase; + int32_t am_phase; + + uint8_t lfo_am; + + uint32_t noise; + uint8_t short_noise; + + int32_t patch_number[9]; + OPLL_SLOT slot[18]; + OPLL_PATCH patch[19 * 2]; + + uint8_t pan[16]; + float pan_fine[16][2]; + + uint32_t mask; + + /* channel output */ + /* 0..8:tone 9:bd 10:hh 11:sd 12:tom 13:cym */ + int16_t ch_out[14]; + + int16_t mix_out[2]; + + OPLL_RateConv *conv; +} OPLL; + +OPLL *OPLL_new(uint32_t clk, uint32_t rate); +void OPLL_delete(OPLL *); + +void OPLL_reset(OPLL *); +void OPLL_resetPatch(OPLL *, uint8_t); + +/** + * Set output wave sampling rate. + * @param rate sampling rate. If clock / 72 (typically 49716 or 49715 at 3.58MHz) is set, the internal rate converter is + * disabled. + */ +void OPLL_setRate(OPLL *opll, uint32_t rate); + +/** + * Set internal calcuration quality. Currently no effects, just for compatibility. + * >= v1.0.0 always synthesizes internal output at clock/72 Hz. + */ +void OPLL_setQuality(OPLL *opll, uint8_t q); + +/** + * Set pan pot (extra function - not YM2413 chip feature) + * @param ch 0..8:tone 9:bd 10:hh 11:sd 12:tom 13:cym 14,15:reserved + * @param pan 0:mute 1:right 2:left 3:center + * ``` + * pan: 76543210 + * |+- bit 1: enable Left output + * +-- bit 0: enable Right output + * ``` + */ +void OPLL_setPan(OPLL *opll, uint32_t ch, uint8_t pan); + +/** + * Set fine-grained panning + * @param ch 0..8:tone 9:bd 10:hh 11:sd 12:tom 13:cym 14,15:reserved + * @param pan output strength of left/right channel. + * pan[0]: left, pan[1]: right. pan[0]=pan[1]=1.0f for center. + */ +void OPLL_setPanFine(OPLL *opll, uint32_t ch, float pan[2]); + +/** + * Set chip type. If vrc7 is selected, r#14 is ignored. + * This method not change the current ROM patch set. + * To change ROM patch set, use OPLL_resetPatch. + * @param type 0:YM2413 1:VRC7 + */ +void OPLL_setChipType(OPLL *opll, uint8_t type); + +void OPLL_writeIO(OPLL *opll, uint32_t reg, uint8_t val); +void OPLL_writeReg(OPLL *opll, uint32_t reg, uint8_t val); + +/** + * Calculate one sample + */ +int16_t OPLL_calc(OPLL *opll); + +/** + * Calulate stereo sample + */ +void OPLL_calcStereo(OPLL *opll, int32_t out[2]); + +void OPLL_setPatch(OPLL *, const uint8_t *dump); +void OPLL_copyPatch(OPLL *, int32_t, OPLL_PATCH *); + +/** + * Force to refresh. + * External program should call this function after updating patch parameters. + */ +void OPLL_forceRefresh(OPLL *); + +void OPLL_dumpToPatch(const uint8_t *dump, OPLL_PATCH *patch); +void OPLL_patchToDump(const OPLL_PATCH *patch, uint8_t *dump); +void OPLL_getDefaultPatch(int32_t type, int32_t num, OPLL_PATCH *); + +/** + * Set channel mask + * @param mask mask flag: OPLL_MASK_* can be used. + * - bit 0..8: mask for ch 1 to 9 (OPLL_MASK_CH(i)) + * - bit 9: mask for Hi-Hat (OPLL_MASK_HH) + * - bit 10: mask for Top-Cym (OPLL_MASK_CYM) + * - bit 11: mask for Tom (OPLL_MASK_TOM) + * - bit 12: mask for Snare Drum (OPLL_MASK_SD) + * - bit 13: mask for Bass Drum (OPLL_MASK_BD) + */ +uint32_t OPLL_setMask(OPLL *, uint32_t mask); + +/** + * Toggler channel mask flag + */ +uint32_t OPLL_toggleMask(OPLL *, uint32_t mask); + +/* for compatibility */ +#define OPLL_set_rate OPLL_setRate +#define OPLL_set_quality OPLL_setQuality +#define OPLL_set_pan OPLL_setPan +#define OPLL_set_pan_fine OPLL_setPanFine +#define OPLL_calc_stereo OPLL_calcStereo +#define OPLL_reset_patch OPLL_resetPatch +#define OPLL_dump2patch OPLL_dumpToPatch +#define OPLL_patch2dump OPLL_patchToDump +#define OPLL_setChipMode OPLL_setChipType + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/fds_apu.c b/src/mappers/sound/fdssound.c similarity index 78% rename from src/fds_apu.c rename to src/mappers/sound/fdssound.c index f57d480a2..e7c05f9c2 100644 --- a/src/fds_apu.c +++ b/src/mappers/sound/fdssound.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2002 Xodnizel + * Copyright (C) 2023-2024 negativeExponent * * 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,17 +18,15 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* Begin FDS sound */ -#include -#include "fceu-types.h" -#include "x6502.h" -#include "fceu.h" -#include "sound.h" -#include "state.h" +#include "mapinc.h" +#include "fdssound.h" -#define FDSClock (1789772.7272727272727272 / 2) +static void RenderSound(void); +static void RenderSoundHQ(void); + +#define FDSClock (NTSC_CLOCK_SPEED / 2) -typedef struct { +typedef struct __FDSSOUND { int64 cycles; /* Cycles per PCM sample */ int64 count; /* Cycle counter */ int64 envcount; /* Envelope cycle counter */ @@ -48,18 +46,19 @@ typedef struct { } FDSSOUND; static FDSSOUND fdso; +static int32 FBC = 0; -#define SPSG fdso.SPSG -#define b19shiftreg60 fdso.b19shiftreg60 -#define b24adder66 fdso.b24adder66 -#define b24latch68 fdso.b24latch68 -#define b17latch76 fdso.b17latch76 +#define SPSG fdso.SPSG +#define b19shiftreg60 fdso.b19shiftreg60 +#define b24adder66 fdso.b24adder66 +#define b24latch68 fdso.b24latch68 +#define b17latch76 fdso.b17latch76 #define b8shiftreg88 fdso.b8shiftreg88 -#define clockcount fdso.clockcount -#define amplitude fdso.amplitude -#define speedo fdso.speedo +#define clockcount fdso.clockcount +#define amplitude fdso.amplitude +#define speedo fdso.speedo -void FDSSoundStateAdd(void) { +void FDSSound_AddStateInfo(void) { AddExState(fdso.cwave, 64, 0, "WAVE"); AddExState(fdso.mwave, 32, 0, "MWAV"); AddExState(amplitude, 2, 0, "AMPL"); @@ -76,15 +75,12 @@ void FDSSoundStateAdd(void) { static DECLFR(FDSSRead) { switch (A & 0xF) { - case 0x0: return(amplitude[0] | (X.DB & 0xC0)); - case 0x2: return(amplitude[1] | (X.DB & 0xC0)); + case 0x0: return(0x40 | amplitude[0]); + case 0x2: return(0x40 | amplitude[1]); } - return(X.DB); + return(cpu.openbus); } -static void RenderSound(void); -static void RenderSoundHQ(void); - static DECLFW(FDSSWrite) { if (FSettings.SndRate) { if (FSettings.soundq >= 1) @@ -121,8 +117,7 @@ static DECLFW(FDSSWrite) { * $4087 - Same as $4086($4087 is the upper 4 bits) */ - -static void DoEnv() { +static void DoEnv(void) { int x; for (x = 0; x < 2; x++) @@ -146,7 +141,7 @@ static void DoEnv() { } static DECLFR(FDSWaveRead) { - return(fdso.cwave[A & 0x3f] | (X.DB & 0xC0)); + return(0x40 | fdso.cwave[A & 0x3f]); } static DECLFW(FDSWaveWrite) { @@ -154,11 +149,8 @@ static DECLFW(FDSWaveWrite) { fdso.cwave[A & 0x3f] = V & 0x3F; } -static int ta; static INLINE void ClockRise(void) { if (!clockcount) { - ta++; - b19shiftreg60 = (SPSG[0x2] | ((SPSG[0x3] & 0xF) << 8)); b17latch76 = (SPSG[0x6] | ((SPSG[0x07] & 0xF) << 8)) + b17latch76; @@ -212,12 +204,10 @@ static INLINE int32 FDSDoSound(void) { { int k = amplitude[0]; if (k > 0x20) k = 0x20; - return (fdso.cwave[b24latch68 >> 19] * k) * 4 / ((SPSG[0x9] & 0x3) + 2); + return GetOutput(SND_FDS, (fdso.cwave[b24latch68 >> 19] * k) * 4 / ((SPSG[0x9] & 0x3) + 2)); } } -static int32 FBC = 0; - static void RenderSound(void) { int32 end, start; int32 x; @@ -253,12 +243,12 @@ static void HQSync(int32 ts) { FBC = ts; } -void FDSSound(int c) { +static void FDSSound(int c) { RenderSound(); FBC = c; } -static void FDS_ESI(void) { +static void FDSSound_SC(void) { if (FSettings.SndRate) { if (FSettings.soundq >= 1) { fdso.cycles = (int64)1 << 39; @@ -267,33 +257,46 @@ static void FDS_ESI(void) { fdso.cycles /= FSettings.SndRate * 16; } } +} + +void FDSSound_Reset(void) { + memset(&fdso, 0, sizeof(fdso)); + GameExpSound[SND_FDS - 6].HiSync = HQSync; + GameExpSound[SND_FDS - 6].HiFill = RenderSoundHQ; + GameExpSound[SND_FDS - 6].Fill = FDSSound; + GameExpSound[SND_FDS - 6].RChange = FDSSound_SC; + + FDSSound_SC(); + SetReadHandler(0x4040, 0x407f, FDSWaveRead); SetWriteHandler(0x4040, 0x407f, FDSWaveWrite); SetWriteHandler(0x4080, 0x408A, FDSSWrite); SetReadHandler(0x4090, 0x4092, FDSSRead); } -void FDSSoundReset(void) { +void NSFFDS_Init(int chip) { memset(&fdso, 0, sizeof(fdso)); - FDS_ESI(); - GameExpSound.HiSync = HQSync; - GameExpSound.HiFill = RenderSoundHQ; - GameExpSound.Fill = FDSSound; - GameExpSound.RChange = FDS_ESI; + GameExpSound[SND_FDS - 6].HiSync = HQSync; + GameExpSound[SND_FDS - 6].HiFill = RenderSoundHQ; + GameExpSound[SND_FDS - 6].Fill = FDSSound; + GameExpSound[SND_FDS - 6].RChange = FDSSound_SC; + + FDSSound_SC(); + SetReadHandler(0x4040, 0x407f, FDSWaveRead); + SetReadHandler(0x4090, 0x4092, FDSSRead); } -uint8 FDSSoundRead(uint32 A) { +DECLFR(FDSSound_Read) { if (A >= 0x4040 && A < 0x4080) return FDSWaveRead(A); if (A >= 0x4090 && A < 0x4093) return FDSSRead(A); - return X.DB; + return cpu.openbus; } -void FDSSoundWrite(uint32 A, uint8 V) { +DECLFW(FDSSound_Write) { if (A >= 0x4040 && A < 0x4080) FDSWaveWrite(A, V); else if (A >= 0x4080 && A < 0x408B) FDSSWrite(A, V); } -void FDSSoundPower(void) { - FDSSoundReset(); - FDSSoundStateAdd(); +void FDSSound_Power(void) { + FDSSound_Reset(); } diff --git a/src/mappers/sound/fdssound.h b/src/mappers/sound/fdssound.h new file mode 100644 index 000000000..bd45e934d --- /dev/null +++ b/src/mappers/sound/fdssound.h @@ -0,0 +1,32 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _FDS_APU_H +#define _FDS_APU_H + +void FDSSound_Reset(void); +DECLFR(FDSSound_Read); /* $4040-$407F, $4090-$4092 */ +DECLFW(FDSSound_Write); /* $4040-$407F, $4080-$408A */ +void FDSSound_AddStateInfo(void); + +/* For mappers utilizing FDS expansion audio */ +void FDSSound_Power(void); + +#endif /* _FDS_APU_H */ diff --git a/src/mappers/sound/mmc5sound.c b/src/mappers/sound/mmc5sound.c new file mode 100644 index 000000000..627cdae99 --- /dev/null +++ b/src/mappers/sound/mmc5sound.c @@ -0,0 +1,258 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "mmc5sound.h" + +typedef struct __MMC5SOUND { + uint16 wl[2]; + uint8 env[2]; + uint8 enable; + uint8 running; + uint8 raw; + uint8 rawcontrol; + int32 dcount[2]; + int32 BC[3]; + int32 vcount[2]; +} MMC5SOUND; + +static MMC5SOUND MMC5Sound; + +static void (*sfun)(int P); +static void (*psfun)(void); + +static void Do5PCM(void) { + int32 V; + int32 start, end; + + start = MMC5Sound.BC[2]; + end = (SOUNDTS << 16) / soundtsinc; + + if (end <= start) { + return; + } + + MMC5Sound.BC[2] = end; + + if (!(MMC5Sound.rawcontrol & 0x40) && MMC5Sound.raw) { + int32 amp = GetOutput(SND_MMC5, MMC5Sound.raw) << 1; + + for (V = start; V < end; V++) { + Wave[V >> 4] += amp; + } + } +} + +static void Do5PCMHQ(void) { + uint32 V; + + if (!(MMC5Sound.rawcontrol & 0x40) && MMC5Sound.raw) { + int32 amp = GetOutput(SND_MMC5, MMC5Sound.raw) << 5; + + for (V = MMC5Sound.BC[2]; V < SOUNDTS; V++) { + WaveHi[V] += amp; + } + } + MMC5Sound.BC[2] = SOUNDTS; +} + +static void Do5SQ(int P) { + static int tal[4] = { 1, 2, 4, 6 }; + int32 V, amp, rthresh, wl; + int32 start, end; + + start = MMC5Sound.BC[P]; + end = (SOUNDTS << 16) / soundtsinc; + + if (end <= start) { + return; + } + + MMC5Sound.BC[P] = end; + + wl = MMC5Sound.wl[P] + 1; + amp = (MMC5Sound.env[P] & 0xF) << 4; + amp = GetOutput(SND_MMC5, amp); + rthresh = tal[(MMC5Sound.env[P] & 0xC0) >> 6]; + + if (wl >= 8 && (MMC5Sound.running & (P + 1))) { + int dc, vc; + + wl <<= 18; + dc = MMC5Sound.dcount[P]; + vc = MMC5Sound.vcount[P]; + + for (V = start; V < end; V++) { + if (dc < rthresh) { + Wave[V >> 4] += amp; + } + vc -= nesincsize; + while (vc <= 0) { + vc += wl; + dc = (dc + 1) & 7; + } + } + MMC5Sound.dcount[P] = dc; + MMC5Sound.vcount[P] = vc; + } +} + +static void Do5SQHQ(int P) { + static int tal[4] = { 1, 2, 4, 6 }; + uint32 V; + int32 amp, rthresh, wl; + + wl = MMC5Sound.wl[P] + 1; + amp = ((MMC5Sound.env[P] & 0xF) << 8); + amp = GetOutput(SND_MMC5, amp); + rthresh = tal[(MMC5Sound.env[P] & 0xC0) >> 6]; + + if (wl >= 8 && (MMC5Sound.running & (P + 1))) { + int dc, vc; + + wl <<= 1; + + dc = MMC5Sound.dcount[P]; + vc = MMC5Sound.vcount[P]; + + for (V = MMC5Sound.BC[P]; V < SOUNDTS; V++) { + if (dc < rthresh) { + WaveHi[V] += amp; + } + vc--; + if (vc <= 0) { /* Less than zero when first started. */ + vc = wl; + dc = (dc + 1) & 7; + } + } + MMC5Sound.dcount[P] = dc; + MMC5Sound.vcount[P] = vc; + } + MMC5Sound.BC[P] = SOUNDTS; +} + +static void MMC5RunSoundHQ(void) { + Do5SQHQ(0); + Do5SQHQ(1); + Do5PCMHQ(); +} + +static void MMC5HiSync(int32 ts) { + MMC5Sound.BC[0] = ts; + MMC5Sound.BC[1] = ts; + MMC5Sound.BC[2] = ts; +} + +static void MMC5RunSound(int Count) { + Do5SQ(0); + Do5SQ(1); + Do5PCM(); + MMC5Sound.BC[0] = Count; + MMC5Sound.BC[1] = Count; + MMC5Sound.BC[2] = Count; +} + +DECLFW(MMC5Sound_Write) { + A &= 0x1F; + + GameExpSound[SND_MMC5 - 6].Fill = MMC5RunSound; + GameExpSound[SND_MMC5 - 6].HiFill = MMC5RunSoundHQ; + + switch (A) { + case 0x10: + if (psfun) { + psfun(); + } + MMC5Sound.rawcontrol = V; + break; + case 0x11: + if (psfun) { + psfun(); + } + MMC5Sound.raw = V; + break; + + case 0x0: + case 0x4: + if (sfun) { + sfun(A >> 2); + } + MMC5Sound.env[A >> 2] = V; + break; + case 0x2: + case 0x6: + if (sfun) { + sfun(A >> 2); + } + MMC5Sound.wl[A >> 2] &= ~0x00FF; + MMC5Sound.wl[A >> 2] |= V & 0xFF; + break; + case 0x3: + case 0x7: + MMC5Sound.wl[A >> 2] &= ~0x0700; + MMC5Sound.wl[A >> 2] |= (V & 0x07) << 8; + MMC5Sound.running |= 1 << (A >> 2); + break; + case 0x15: + if (sfun) { + sfun(0); + sfun(1); + } + MMC5Sound.running &= V; + MMC5Sound.enable = V; + break; + } +} + +static void MMC5SC(void) { + memset(MMC5Sound.BC, 0, sizeof(MMC5Sound.BC)); + memset(MMC5Sound.vcount, 0, sizeof(MMC5Sound.vcount)); + GameExpSound[SND_MMC5 - 6].HiSync = MMC5HiSync; + + if (FSettings.SndRate) { + if (FSettings.soundq >= 1) { + sfun = Do5SQHQ; + psfun = Do5PCMHQ; + } else { + sfun = Do5SQ; + psfun = Do5PCM; + } + } else { + sfun = 0; + psfun = 0; + } +} + +void MMC5Sound_ESI(void) { + GameExpSound[SND_MMC5 - 6].RChange = MMC5SC; + MMC5SC(); +} + +void MMC5Sound_AddStateInfo(void) { + AddExState(MMC5Sound.wl, 4, 0, "SDW0"); + AddExState(MMC5Sound.env, 2, 0, "SDEV"); + AddExState(&MMC5Sound.enable, 1, 0, "SDEN"); + AddExState(&MMC5Sound.running, 1, 0, "RUNN"); + AddExState(&MMC5Sound.raw, 1, 0, "RAW0"); + AddExState(&MMC5Sound.rawcontrol, 1, 0, "RAWC"); + AddExState(MMC5Sound.dcount, 8, 0, "DCNT"); + AddExState(MMC5Sound.BC, 12, 0, "SDBC"); + AddExState(MMC5Sound.vcount, 8, 0, "VCNT"); +} \ No newline at end of file diff --git a/src/mappers/sound/mmc5sound.h b/src/mappers/sound/mmc5sound.h new file mode 100644 index 000000000..d0ec715b6 --- /dev/null +++ b/src/mappers/sound/mmc5sound.h @@ -0,0 +1,28 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _MMC5_AUDIO_H +#define _MMC5_AUDIO_H + +void MMC5Sound_ESI(void); +DECLFW(MMC5Sound_Write); +void MMC5Sound_AddStateInfo(void); + +#endif /* _MMC5_AUDIO_H */ diff --git a/src/mappers/sound/n163sound.c b/src/mappers/sound/n163sound.c new file mode 100644 index 000000000..de3f93790 --- /dev/null +++ b/src/mappers/sound/n163sound.c @@ -0,0 +1,275 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* Things to do: + 1 Read freq low + 2 Read freq mid + 3 Read freq high + 4 Read envelope + ...? +*/ + +#include "mapinc.h" +#include "n163sound.h" + +static uint8 IRAM[128]; + +static uint8 currIndex; + +static uint32 FreqCache[8]; +static uint32 EnvCache[8]; +static uint32 LengthCache[8]; + +static void DoN163Sound(int32 *Wave, int Count); +static void DoN163SoundHQ(void); + +static void FixCache(int a, int V) { + int w = (a >> 3) & 0x7; + switch (a & 0x07) { + case 0x00: + FreqCache[w] &= ~0x000000FF; + FreqCache[w] |= V; + break; + case 0x02: + FreqCache[w] &= ~0x0000FF00; + FreqCache[w] |= V << 8; + break; + case 0x04: + FreqCache[w] &= ~0x00030000; + FreqCache[w] |= (V & 3) << 16; + LengthCache[w] = 256 - (V & 0xFC); + break; + case 0x07: + EnvCache[w] = (double)(V & 0xF) * 576716; + break; + } +} + +static int dwave = 0; + +static void N163SoundHack(void) { + int32 z, a; + if (FSettings.soundq >= 1) { + DoN163SoundHQ(); + return; + } + z = ((SOUNDTS << 16) / soundtsinc) >> 4; + a = z - dwave; + if (a) + DoN163Sound(&Wave[dwave], a); + dwave += a; +} + +static void N163Sound(int Count) { + int32 z, a; + z = ((SOUNDTS << 16) / soundtsinc) >> 4; + a = z - dwave; + if (a) + DoN163Sound(&Wave[dwave], a); + dwave = 0; +} + +static uint32 PlayIndex[8]; +static int32 vcount[8]; +static int32 CVBC; + +#define TOINDEX (16 + 1) + +/* 16:15 */ +static void SyncHQ(int32 ts) { + CVBC = ts; +} + +static INLINE uint32 FetchDuffHQ(uint32 P, uint32 envelope) { + uint32 duff; + uint8 sample = (IRAM[0x46 + (P << 3)] + (PlayIndex[P] >> TOINDEX)) & 0xFF; + if (sample & 0x01) { + duff = IRAM[sample >> 1] >> 4; + } else { + duff = IRAM[sample >> 1] & 0x0F; + } + duff = (duff * envelope) >> 16; + return (uint32)GetOutput(SND_N163, duff); +} + +static void DoN163SoundHQ(void) { + int32 P, V; + int32 cyclesuck = (((IRAM[0x7F] >> 4) & 7) + 1) * 15; + + for (P = 7; P >= (7 - ((IRAM[0x7F] >> 4) & 7)); P--) { + if ((IRAM[0x44 + (P << 3)] & 0xE0) && (IRAM[0x47 + (P << 3)] & 0xF)) { + uint32 freq; + int32 vco; + uint32 duff2, lengo, envelope; + + vco = vcount[P]; + freq = FreqCache[P]; + envelope = EnvCache[P]; + lengo = LengthCache[P]; + + duff2 = FetchDuffHQ(P, envelope); + for (V = CVBC << 1; V < (int)SOUNDTS << 1; V++) { + WaveHi[V >> 1] += duff2; + if (!vco) { + PlayIndex[P] += freq; + while ((PlayIndex[P] >> TOINDEX) >= lengo) + PlayIndex[P] -= lengo << TOINDEX; + duff2 = FetchDuffHQ(P, envelope); + vco = cyclesuck; + } + vco--; + } + vcount[P] = vco; + } + } + CVBC = SOUNDTS; +} + +static INLINE uint32 FetchDuff(uint32 P, uint32 envelope) { + uint32 duff; + uint8 sample = (IRAM[0x46 + (P << 3)] + PlayIndex[P]) & 0xFF; + if (sample & 0x01) { + duff = IRAM[sample >> 1] >> 4; + } else { + duff = IRAM[sample >> 1] & 0x0F; + } + duff = (duff * envelope) >> 19; + return (uint32)GetOutput(SND_N163, duff); +} + +static void DoN163Sound(int32 *Wave, int Count) { + int P, V; + + for (P = 7; P >= 7 - ((IRAM[0x7F] >> 4) & 7); P--) { + if ((IRAM[0x44 + (P << 3)] & 0xE0) && (IRAM[0x47 + (P << 3)] & 0xF)) { + int32 inc; + uint32 freq; + int32 vco; + uint32 duff2, lengo, envelope; + + vco = vcount[P]; + freq = FreqCache[P]; + envelope = EnvCache[P]; + lengo = LengthCache[P]; + + if (!freq) + continue; + + { + int c = ((IRAM[0x7F] >> 4) & 7) + 1; + inc = (long double)(FSettings.SndRate << 15) / + ((long double)freq * 21477272 / ((long double)0x400000 * c * 45)); + } + + duff2 = FetchDuff(P, envelope); + for (V = 0; V < Count * 16; V++) { + if (vco >= inc) { + PlayIndex[P]++; + if (PlayIndex[P] >= lengo) + PlayIndex[P] = 0; + vco -= inc; + duff2 = FetchDuff(P, envelope); + } + Wave[V >> 4] += duff2; + vco += 0x8000; + } + vcount[P] = vco; + } + } +} + +DECLFR(N163Sound_Read) { + uint8 ret = IRAM[currIndex & 0x7f]; +/* Maybe I should call N163SoundHack() here? */ +#ifdef FCEUDEF_DEBUGGER + if (!fceuindbg) +#endif + if (currIndex & 0x80) { + currIndex = (currIndex & 0x80) | ((currIndex + 1) & 0x7f); + } + return ret; +} + +DECLFW(N163Sound_Write) { + switch (A & 0xF800) { + case 0x4800: + if (currIndex & 0x40) { + if (FSettings.SndRate) { + N163SoundHack(); + GameExpSound[SND_N163 - 6].Fill = N163Sound; + GameExpSound[SND_N163 - 6].HiFill = DoN163SoundHQ; + GameExpSound[SND_N163 - 6].HiSync = SyncHQ; + } + FixCache(currIndex, V); + } + IRAM[currIndex & 0x7f] = V; + if (currIndex & 0x80) { + currIndex = (currIndex & 0x80) | ((currIndex + 1) & 0x7f); + } + break; + case 0xF800: + currIndex = V; + break; + } +} + +uint8 *GetIRAM_ptr(void) { + return IRAM; +} + +uint32 GetIRAM_size(void) { + return sizeof(IRAM); +} + +static void N163Sound_FixCache(void) { + int x; + for (x = 0x40; x < 0x80; x++) { + FixCache(x, IRAM[x]); + } +} + +static void N163SC(void) { + if (FSettings.SndRate) { + memset(vcount, 0, sizeof(vcount)); + memset(PlayIndex, 0, sizeof(PlayIndex)); + CVBC = 0; + currIndex = 0; + N163Sound_FixCache(); + } +} + +void N163Sound_ESI(void) { + GameExpSound[SND_N163 - 6].RChange = N163SC; + N163SC(); + + if (iNESCart.battery) { + memset(IRAM, 0, sizeof(IRAM)); + } else { + FCEU_MemoryRand(IRAM, sizeof(IRAM)); + } +} + +void N163Sound_AddStateInfo(void) { + AddExState(IRAM, 0x80, 0, "IRAM"); + AddExState(PlayIndex, 32, 0, "IDX0"); + AddExState(vcount, 32, 0, "VCT0"); + AddExState(&CVBC, 4, 0, "BC00"); + AddExState(&currIndex, 1, 0, "INDX"); +} diff --git a/src/mappers/sound/n163sound.h b/src/mappers/sound/n163sound.h new file mode 100644 index 000000000..3d1cbe02f --- /dev/null +++ b/src/mappers/sound/n163sound.h @@ -0,0 +1,32 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _N163_SOUND_H +#define _N163_SOUND_H + +void N163Sound_ESI(void); +DECLFR(N163Sound_Read); +DECLFW(N163Sound_Write); +void N163Sound_AddStateInfo(void); + +uint8 *GetIRAM_ptr(void); /* pointer to internal RAM */ +uint32 GetIRAM_size(void); + +#endif /* _N163_SOUND_H */ diff --git a/src/mappers/sound/s5bsound.c b/src/mappers/sound/s5bsound.c new file mode 100644 index 000000000..43210beab --- /dev/null +++ b/src/mappers/sound/s5bsound.c @@ -0,0 +1,324 @@ + +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +/* SUNSOFT-5B Sound */ + +#include "mapinc.h" +#include "s5bsound.h" + +#if 0 /* remove comment to use old S5B emulation */ +#define USE_OLD_SB5 +#endif + +#ifndef USE_OLD_SB5 +#define USE_EMU2149 +#endif + +#ifdef USE_EMU2149 +#include "emu2149.h" + +static int32 dwave = 0; +static PSG *psg_chip = NULL; + +static void PSG_fillbuf(PSG *ssg, int32 *buf, int32 len, int shift) { + while (len > 0) { + *buf += (GetOutput(SND_S5B, PSG_calc(psg_chip) << shift)); + buf++; + len--; + } +} + +static void UpdatePSGNEO(int32 *Wave, int Count) { + PSG_fillbuf(psg_chip, Wave, Count, 4); +} + +static void UpdatePSG(int Count) { + int32 z, a; + z = ((SOUNDTS << 16) / soundtsinc) >> 4; + a = z - dwave; + if (a) { + PSG_fillbuf(psg_chip, &Wave[dwave], a, 1); + } + dwave = 0; +} + +DECLFW(S5BSound_Write) { + if (!psg_chip) { + return; + } + + switch (A & 0xE000) { + case 0xC000: + PSG_writeIO(psg_chip, 0, V); + break; + case 0xE000: + GameExpSound[SND_S5B - 6].Fill = UpdatePSG; + GameExpSound[SND_S5B - 6].NeoFill = UpdatePSGNEO; + PSG_writeIO(psg_chip, 1, V); + break; + } +} + +static void S5BSound_SC(void) { + if (psg_chip) { + PSG_setRate(psg_chip, FSettings.SndRate ? FSettings.SndRate : 44100); + PSG_setVolumeMode(psg_chip, 1); + PSG_reset(psg_chip); + } +} + +static void S5BSound_KILL(void) { + if (psg_chip) { + PSG_delete(psg_chip); + psg_chip = NULL; + } +} + +void S5BSound_ESI(void) { + if (!(psg_chip = PSG_new(3579545 / 4, FSettings.SndRate ? FSettings.SndRate : 44100))) { + return; + } + + GameExpSound[SND_S5B - 6].RChange = S5BSound_SC; + GameExpSound[SND_S5B - 6].Kill = S5BSound_KILL; + + S5BSound_SC(); +} + +void S5BSound_AddStateInfo(void) { + if (!psg_chip) { + return; + } + + /* Sound states */ + AddExState(psg_chip->reg, sizeof(psg_chip->reg), 0, "REG"); + + AddExState(psg_chip->count, sizeof(psg_chip->count), 0, "PCNT"); + AddExState(psg_chip->volume, sizeof(psg_chip->volume), 0, "PVOL"); + AddExState(psg_chip->edge, sizeof(psg_chip->edge), 0, "EDGE"); + AddExState(psg_chip->freq, sizeof(psg_chip->freq), 0, "FREQ"); + AddExState(psg_chip->tmask, sizeof(psg_chip->tmask), 0, "TMSK"); + AddExState(psg_chip->nmask, sizeof(psg_chip->nmask), 0, "NMSK"); + + AddExState(&psg_chip->env_ptr, sizeof(psg_chip->env_ptr), 0, "PTR"); + AddExState(&psg_chip->env_face, sizeof(psg_chip->env_face), 0, "FACE"); + + AddExState(&psg_chip->env_continue, sizeof(psg_chip->env_continue), 0, "CONT"); + AddExState(&psg_chip->env_attack, sizeof(psg_chip->env_attack), 0, "ATTK"); + AddExState(&psg_chip->env_alternate, sizeof(psg_chip->env_alternate), 0, "ALT"); + AddExState(&psg_chip->env_hold, sizeof(psg_chip->env_hold), 0, "HOLD"); + AddExState(&psg_chip->env_pause, sizeof(psg_chip->env_pause), 0, "PAUS"); + + AddExState(&psg_chip->env_freq, sizeof(psg_chip->env_freq), 0, "EFRQ"); + AddExState(&psg_chip->env_count, sizeof(psg_chip->env_count), 0, "ECNT"); + + AddExState(&psg_chip->noise_seed, sizeof(psg_chip->noise_seed), 0, "NSED"); + AddExState(&psg_chip->noise_scaler, sizeof(psg_chip->noise_scaler), 0, "NSCL"); + AddExState(&psg_chip->noise_count, sizeof(psg_chip->noise_count), 0, "NCNT"); + AddExState(&psg_chip->noise_freq, sizeof(psg_chip->noise_freq), 0, "NFRQ"); +} + +#else /* !USE_EMU2149 */ +static void (*sfun[3])(void); +static uint8 sndcmd, sreg[14]; + +static int32 vcount[3]; +static int32 dcount[3]; +static int32 CAYBC[3]; + +static void AYSound(int Count); +static void AYSoundHQ(void); +static void AYHiSync(int ts); +static void DoAYSQ(int x); +static void DoAYSQHQ(int x); + +static void DoAYSQ(int x) { + int32 freq = ((sreg[x << 1] | ((sreg[(x << 1) + 1] & 15) << 8)) + 1) << (4 + 17); + int32 amp = (sreg[0x8 + x] & 15) << 2; + int32 start, end; + int V; + + amp += amp >> 1; + amp = GetOutput(SND_S5B, amp); + + start = CAYBC[x]; + end = (SOUNDTS << 16) / soundtsinc; + if (end <= start) + return; + CAYBC[x] = end; + + if (amp && !(sreg[0x7] & (1 << x))) { + for (V = start; V < end; V++) { + if (dcount[x]) + Wave[V >> 4] += amp; + vcount[x] -= nesincsize; + while (vcount[x] <= 0) { + dcount[x] ^= 1; + vcount[x] += freq; + } + } + } +} + +static void DoAYSQHQ(int x) { + uint32 V; + int32 freq = ((sreg[x << 1] | ((sreg[(x << 1) + 1] & 15) << 8)) + 1) << 4; + int32 amp = (sreg[0x8 + x] & 15) << 6; + + amp += amp >> 1; + amp = GetOutput(SND_S5B, amp); + + if (!(sreg[0x7] & (1 << x))) { + for (V = CAYBC[x]; V < SOUNDTS; V++) { + if (dcount[x]) + WaveHi[V] += amp; + vcount[x]--; + if (vcount[x] <= 0) { + dcount[x] ^= 1; + vcount[x] = freq; + } + } + } + CAYBC[x] = SOUNDTS; +} + +static void DoAYSQ1(void) { + DoAYSQ(0); +} + +static void DoAYSQ2(void) { + DoAYSQ(1); +} + +static void DoAYSQ3(void) { + DoAYSQ(2); +} + +static void DoAYSQ1HQ(void) { + DoAYSQHQ(0); +} + +static void DoAYSQ2HQ(void) { + DoAYSQHQ(1); +} + +static void DoAYSQ3HQ(void) { + DoAYSQHQ(2); +} + +static void AYSound(int Count) { + DoAYSQ1(); + DoAYSQ2(); + DoAYSQ3(); + CAYBC[0] = Count; + CAYBC[1] = Count; + CAYBC[2] = Count; +} + +static void AYSoundHQ(void) { + DoAYSQ1HQ(); + DoAYSQ2HQ(); + DoAYSQ3HQ(); +} + +static void AYHiSync(int32 ts) { + CAYBC[0] = ts; + CAYBC[1] = ts; + CAYBC[2] = ts; +} + +DECLFW(S5BSound_Write) { + switch (A & 0xE000) { + case 0xC000: + sndcmd = V & 0x0F; + break; + case 0xE000: + GameExpSound[SND_S5B - 6].Fill = AYSound; + GameExpSound[SND_S5B - 6].HiFill = AYSoundHQ; + GameExpSound[SND_S5B - 6].HiSync = AYHiSync; + switch (sndcmd) { + case 0: + case 1: + case 8: + if (sfun[0]) { + sfun[0](); + } + break; + case 2: + case 3: + case 9: + if (sfun[1]) { + sfun[1](); + } + break; + case 4: + case 5: + case 10: + if (sfun[2]) { + sfun[2](); + } + break; + case 7: + if (sfun[0]) { + sfun[0](); + } + if (sfun[1]) { + sfun[1](); + } + break; + } + sreg[sndcmd] = V; + break; + } +} + +static void S5BSound_SC(void) { + memset(dcount, 0, sizeof(dcount)); + memset(vcount, 0, sizeof(vcount)); + memset(CAYBC, 0, sizeof(CAYBC)); + if (FSettings.SndRate) { + if (FSettings.soundq >= 1) { + sfun[0] = DoAYSQ1HQ; + sfun[1] = DoAYSQ2HQ; + sfun[2] = DoAYSQ3HQ; + } else { + sfun[0] = DoAYSQ1; + sfun[1] = DoAYSQ2; + sfun[2] = DoAYSQ3; + } + } else { + memset(sfun, 0, sizeof(sfun)); + } +} + +void S5BSound_ESI(void) { + GameExpSound[SND_S5B - 6].RChange = S5BSound_SC; + S5BSound_SC(); +} + +void S5BSound_AddStateInfo(void) { + AddExState(&sndcmd, 1, 0, "SCMD"); + AddExState(sreg, 14, 0, "SREG"); + AddExState(dcount, 12, 0, "DCNT"); + AddExState(vcount, 12, 0, "VCNT"); + AddExState(CAYBC, 12, 0, "BC00"); +} +#endif \ No newline at end of file diff --git a/src/mappers/sound/s5bsound.h b/src/mappers/sound/s5bsound.h new file mode 100644 index 000000000..f6e785568 --- /dev/null +++ b/src/mappers/sound/s5bsound.h @@ -0,0 +1,28 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _FME7_SOUND_H +#define _FME7_SOUND_H + +void S5BSound_ESI(void); +DECLFW(S5BSound_Write); +void S5BSound_AddStateInfo(void); + +#endif /* _FME7_SOUND_H */ diff --git a/src/boards/vrc6.c b/src/mappers/sound/vrc6sound.c similarity index 56% rename from src/boards/vrc6.c rename to src/mappers/sound/vrc6sound.c index d2d3bf014..5500389b4 100644 --- a/src/boards/vrc6.c +++ b/src/mappers/sound/vrc6sound.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2009 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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 @@ -17,26 +18,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * VRC-6 + * VRC-6 Sound * */ #include "mapinc.h" -#include "vrcirq.h" - -static uint8 is26; -static uint8 prg[2], chr[8], mirr; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; - -static SFORMAT StateRegs[] = -{ - { prg, 2, "PRG" }, - { chr, 8, "CHR" }, - { &mirr, 1, "MIRR" }, - - { 0 } -}; +#include "vrc6sound.h" static void(*sfun[3]) (void); @@ -47,98 +34,6 @@ static int32 vcount[3]; static int32 dcount[3]; static int32 phaseacc; -static SFORMAT SStateRegs[] = -{ - { vpsg1, 8, "PSG1" }, - { vpsg2, 4, "PSG2" }, - { cvbc, 12, "CVBC" }, - { dcount, 12, "DCNT" }, - { vcount, 12, "VCNT" }, - { &phaseacc, 4, "ACCU" }, - - { 0 } -}; - -static void Sync(void) { - uint8 i; - if (is26) - setprg8r(0x10, 0x6000, 0); - setprg16(0x8000, prg[0]); - setprg8(0xc000, prg[1]); - setprg8(0xe000, ~0); - for (i = 0; i < 8; i++) - setchr1(i << 10, chr[i]); - switch (mirr & 3) { - case 0: setmirror(MI_V); break; - case 1: setmirror(MI_H); break; - case 2: setmirror(MI_0); break; - case 3: setmirror(MI_1); break; - } -} - -static DECLFW(VRC6SW) { - A &= 0xF003; - if (A >= 0x9000 && A <= 0x9002) { - vpsg1[A & 3] = V; - if (sfun[0]) sfun[0](); - } else if (A >= 0xA000 && A <= 0xA002) { - vpsg1[4 | (A & 3)] = V; - if (sfun[1]) sfun[1](); - } else if (A >= 0xB000 && A <= 0xB002) { - vpsg2[A & 3] = V; - if (sfun[2]) sfun[2](); - } -} - -static DECLFW(VRC6Write) { - if (is26) - A = (A & 0xFFFC) | ((A >> 1) & 1) | ((A << 1) & 2); - if (A >= 0x9000 && A <= 0xB002) { - VRC6SW(A, V); - return; - } - switch (A & 0xF003) { - case 0x8000: prg[0] = V; Sync(); break; - case 0xB003: mirr = (V >> 2) & 3; Sync(); break; - case 0xC000: prg[1] = V; Sync(); break; - case 0xD000: chr[0] = V; Sync(); break; - case 0xD001: chr[1] = V; Sync(); break; - case 0xD002: chr[2] = V; Sync(); break; - case 0xD003: chr[3] = V; Sync(); break; - case 0xE000: chr[4] = V; Sync(); break; - case 0xE001: chr[5] = V; Sync(); break; - case 0xE002: chr[6] = V; Sync(); break; - case 0xE003: chr[7] = V; Sync(); break; - case 0xF000: VRCIRQ_Latch(V); break; - case 0xF001: VRCIRQ_Control(V); break; - case 0xF002: VRCIRQ_Acknowledge(); break; - } -} - -static void VRC6Power(void) { - Sync(); - SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetWriteHandler(0x8000, 0xFFFF, VRC6Write); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); -} - -static void VRC6Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -static void StateRestore(int version) { - Sync(); -} - -/* VRC6 Sound */ - -static void DoSQV1(void); -static void DoSQV2(void); -static void DoSawV(void); - static INLINE void DoSQV(int x) { int32 V; int32 amp = (((vpsg1[x << 2] & 15) << 8) * 6 / 8) >> 4; @@ -150,6 +45,7 @@ static INLINE void DoSQV(int x) { cvbc[x] = end; if (vpsg1[(x << 2) | 0x2] & 0x80) { + amp = GetOutput(SND_VRC6, amp); if (vpsg1[x << 2] & 0x80) { for (V = start; V < end; V++) Wave[V >> 4] += amp; @@ -214,6 +110,7 @@ static void DoSawV(void) { if (vcount[2] <= 0) goto rea; duff = (((phaseacc >> 3) & 0x1f) << 4) * 6 / 8; + duff = GetOutput(SND_VRC6, duff); } Wave[V >> 4] += duff; } @@ -225,6 +122,7 @@ static INLINE void DoSQVHQ(int x) { int32 amp = ((vpsg1[x << 2] & 15) << 8) * 6 / 8; if (vpsg1[(x << 2) | 0x2] & 0x80) { + amp = GetOutput(SND_VRC6, amp); if (vpsg1[x << 2] & 0x80) { for (V = cvbc[x]; V < (int)SOUNDTS; V++) WaveHi[V] += amp; @@ -259,10 +157,13 @@ static void DoSQV2HQ(void) { static void DoSawVHQ(void) { int32 V; + int32 duff; if (vpsg2[2] & 0x80) { for (V = cvbc[2]; V < (int)SOUNDTS; V++) { - WaveHi[V] += (((phaseacc >> 3) & 0x1f) << 8) * 6 / 8; + duff = (((phaseacc >> 3) & 0x1f) << 8) * 6 / 8; + duff = GetOutput(SND_VRC6, duff); + WaveHi[V] += duff; vcount[2]--; if (vcount[2] <= 0) { vcount[2] = (vpsg2[1] + ((vpsg2[2] & 15) << 8) + 1) << 1; @@ -278,7 +179,7 @@ static void DoSawVHQ(void) { cvbc[2] = SOUNDTS; } -void VRC6Sound(int Count) { +static void VRC6Sound(int Count) { int x; DoSQV1(); @@ -288,22 +189,52 @@ void VRC6Sound(int Count) { cvbc[x] = Count; } -void VRC6SoundHQ(void) { +static void VRC6SoundHQ(void) { DoSQV1HQ(); DoSQV2HQ(); DoSawVHQ(); } -void VRC6SyncHQ(int32 ts) { +static void VRC6SyncHQ(int32 ts) { int x; for (x = 0; x < 3; x++) cvbc[x] = ts; } -static void VRC6_ESI(void) { - GameExpSound.RChange = VRC6_ESI; - GameExpSound.Fill = VRC6Sound; - GameExpSound.HiFill = VRC6SoundHQ; - GameExpSound.HiSync = VRC6SyncHQ; +DECLFW(VRC6Sound_Write) { + switch (A) { + case 0x9000: + case 0x9001: + case 0x9002: + vpsg1[A & 3] = V; + if (sfun[0]) { + sfun[0](); + } + break; + + case 0xA000: + case 0xA001: + case 0xA002: + vpsg1[4 | (A & 3)] = V; + if (sfun[1]) { + sfun[1](); + } + break; + + case 0xB000: + case 0xB001: + case 0xB002: + vpsg2[A & 3] = V; + if (sfun[2]) { + sfun[2](); + } + break; + } +} + +static void VRC6Sound_SC(void) { + GameExpSound[SND_VRC6 - 6].Fill = VRC6Sound; + GameExpSound[SND_VRC6 - 6].HiFill = VRC6SoundHQ; + GameExpSound[SND_VRC6 - 6].HiSync = VRC6SyncHQ; phaseacc = 0; memset(cvbc, 0, sizeof(cvbc)); @@ -323,40 +254,16 @@ static void VRC6_ESI(void) { memset(sfun, 0, sizeof(sfun)); } -/* VRC6 Sound */ - -void Mapper24_Init(CartInfo *info) { - is26 = 0; - info->Power = VRC6Power; - VRCIRQ_Init(); - VRC6_ESI(); - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); - AddExState(&SStateRegs, ~0, 0, 0); +void VRC6Sound_ESI(void) { + GameExpSound[SND_VRC6 - 6].RChange = VRC6Sound_SC; + VRC6Sound_SC(); } -void Mapper26_Init(CartInfo *info) { - is26 = 1; - info->Power = VRC6Power; - info->Close = VRC6Close; - VRCIRQ_Init(); - VRC6_ESI(); - GameStateRestore = StateRestore; - - WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; - } - AddExState(&StateRegs, ~0, 0, 0); - AddExState(&SStateRegs, ~0, 0, 0); -} - -void NSFVRC6_Init(void) { - VRC6_ESI(); - SetWriteHandler(0x8000, 0xbfff, VRC6SW); - AddExState(&SStateRegs, ~0, 0, 0); -} +void VRC6Sound_AddStateInfo(void) { + AddExState(vpsg1, 8, 0, "PSG1"); + AddExState(vpsg2, 4, 0, "PSG2"); + AddExState(cvbc, 12, 0, "CVBC"); + AddExState(dcount, 12, 0, "DCNT"); + AddExState(vcount, 12, 0, "VCNT"); + AddExState(&phaseacc, 4, 0, "ACCU"); +} \ No newline at end of file diff --git a/src/mappers/sound/vrc6sound.h b/src/mappers/sound/vrc6sound.h new file mode 100644 index 000000000..31b7eb7f2 --- /dev/null +++ b/src/mappers/sound/vrc6sound.h @@ -0,0 +1,28 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _VRC6_SOUND_H +#define _VRC6_SOUND_H + +void VRC6Sound_ESI(void); +DECLFW(VRC6Sound_Write); +void VRC6Sound_AddStateInfo(void); + +#endif /* _VRC6_SOUND_H */ diff --git a/src/mappers/sound/vrc7sound.c b/src/mappers/sound/vrc7sound.c new file mode 100644 index 000000000..481949546 --- /dev/null +++ b/src/mappers/sound/vrc7sound.c @@ -0,0 +1,149 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 "emu2413.h" +#include "vrc7sound.h" + +static int32 dwave = 0; + +static OPLL *opll = NULL; + +static void OPLL_fillbuf(OPLL *opll, int32 *buf, int32 len, int shift) { + while (len > 0) { + *buf += GetOutput(SND_VRC7, (OPLL_calc(opll) << shift)); + buf++; + len--; + } +} + +static void UpdateOPLNEO(int32 *Wave, int Count) { + OPLL_fillbuf(opll, Wave, Count, 4); +} + +static void UpdateOPL(int Count) { + int32 z, a; + z = ((SOUNDTS << 16) / soundtsinc) >> 4; + a = z - dwave; + if (a) { + OPLL_fillbuf(opll, &Wave[dwave], a, 1); + } + dwave = 0; +} + +DECLFW(VRC7Sound_Write) { + if (!opll) { + return; + } + + switch (A & 0xF030) { + case 0x9010: + OPLL_writeIO(opll, 0, V); + break; + case 0x9030: + GameExpSound[SND_VRC7 - 6].Fill = UpdateOPL; + GameExpSound[SND_VRC7 - 6].NeoFill = UpdateOPLNEO; + OPLL_writeIO(opll, 1, V); + break; + } +} + +static void VRC7SC(void) { + if (opll) { + OPLL_setRate(opll, FSettings.SndRate ? FSettings.SndRate : 44100); + OPLL_setChipType(opll, 1); + OPLL_reset(opll); + } +} + +static void VRC7SKill(void) { + if (opll) { + OPLL_delete(opll); + opll = NULL; + } +} + +void VRC7Sound_ESI(void) { + if (!(opll = OPLL_new(3579545, FSettings.SndRate ? FSettings.SndRate : 44100))) { + return; + } + + GameExpSound[SND_VRC7 - 6].RChange = VRC7SC; + GameExpSound[SND_VRC7 - 6].Kill = VRC7SKill; + + VRC7SC(); +} + +void VRC7Sound_AddStateInfo(void) { + if (!opll) { + return; + } + /* Sound states */ + AddExState(&opll->clk, sizeof(opll->clk), 0, "CLK7"); + AddExState(&opll->rate, sizeof(opll->rate), 0, "RATE"); + + AddExState(&opll->chip_type, sizeof(opll->chip_type), 0, "CHIP"); + + AddExState(&opll->adr, sizeof(opll->adr), 0, "ADR7"); + + AddExState(&opll->inp_step, sizeof(opll->inp_step), 0, "ISTP"); + AddExState(&opll->out_step, sizeof(opll->out_step), 0, "OSTP"); + AddExState(&opll->out_time, sizeof(opll->out_time), 0, "OTME"); + + AddExState(opll->reg, sizeof(opll->reg), 0, "REG7"); + AddExState(&opll->test_flag, sizeof(opll->test_flag), 0, "TFLG"); + AddExState(&opll->slot_key_status, sizeof(opll->slot_key_status), 0, "SKST"); + AddExState(&opll->rhythm_mode, sizeof(opll->rhythm_mode), 0, "RMOD"); + + AddExState(&opll->eg_counter, sizeof(opll->eg_counter), 0, "ECTR"); + + AddExState(&opll->pm_phase, sizeof(opll->pm_phase), 0, "PMPH"); + AddExState(&opll->am_phase, sizeof(opll->am_phase), 0, "AMPH"); + + AddExState(&opll->lfo_am, sizeof(opll->lfo_am), 0, "LFO7"); + + AddExState(&opll->noise, sizeof(opll->noise), 0, "NOIS"); + AddExState(&opll->short_noise, sizeof(opll->short_noise), 0, "SNOS"); + + AddExState(opll->patch_number, sizeof(opll->patch_number), 0, "PTNM"); + + /* VRC7 only uses 12 slots */ + AddExState(&opll->slot[0], sizeof(opll->slot[0]), 0, "SL00"); + AddExState(&opll->slot[1], sizeof(opll->slot[1]), 0, "SL01"); + AddExState(&opll->slot[2], sizeof(opll->slot[2]), 0, "SL02"); + AddExState(&opll->slot[3], sizeof(opll->slot[3]), 0, "SL03"); + AddExState(&opll->slot[4], sizeof(opll->slot[4]), 0, "SL04"); + AddExState(&opll->slot[5], sizeof(opll->slot[5]), 0, "SL05"); + AddExState(&opll->slot[6], sizeof(opll->slot[6]), 0, "SL06"); + AddExState(&opll->slot[7], sizeof(opll->slot[7]), 0, "SL07"); + AddExState(&opll->slot[8], sizeof(opll->slot[8]), 0, "SL08"); + AddExState(&opll->slot[9], sizeof(opll->slot[9]), 0, "SL09"); + AddExState(&opll->slot[10], sizeof(opll->slot[10]), 0, "SL10"); + AddExState(&opll->slot[11], sizeof(opll->slot[11]), 0, "SL11"); + + AddExState(&opll->mask, sizeof(opll->mask), 0, "MASK"); + + AddExState(opll->ch_out, sizeof(opll->ch_out), 0, "CHOU"); + AddExState(opll->mix_out, sizeof(opll->mix_out), 0, "MIXO"); + + /* custom patches */ + AddExState(&opll->patch[0], sizeof(opll->patch[0]), 0, "PAT0"); + AddExState(&opll->patch[1], sizeof(opll->patch[1]), 0, "PAT1"); +} diff --git a/src/mappers/sound/vrc7sound.h b/src/mappers/sound/vrc7sound.h new file mode 100644 index 000000000..a28e396a2 --- /dev/null +++ b/src/mappers/sound/vrc7sound.h @@ -0,0 +1,28 @@ +/* FCEUmm - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2023-2024 negativeExponent + * + * 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 + */ + +#ifndef _VRC7_SOUND_H +#define _VRC7_SOUND_H + +void VRC7Sound_ESI(void); +DECLFW(VRC7Sound_Write); +void VRC7Sound_AddStateInfo(void); + +#endif /* _VRC7_SOUND_H */ diff --git a/src/boards/mapper355.c b/src/mappers/unif3Dblock.c similarity index 77% rename from src/boards/mapper355.c rename to src/mappers/unif3Dblock.c index 75d560efd..99d1aacbb 100644 --- a/src/boards/mapper355.c +++ b/src/mappers/unif3Dblock.c @@ -1,7 +1,8 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2007 CaH4e3 + * Copyright (C) 2023-2024 negativeExponent * * 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,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +/* NOTE: This only emulates the UNIF variant of 3D-Blocks */ + #include "mapinc.h" static uint8 reg[4], IRQa; @@ -25,8 +28,7 @@ static int16 IRQCount, IRQPause; static int16 Count = 0x0000; -static SFORMAT StateRegs[] = -{ +static SFORMAT StateRegs[] = { { reg, 4, "REGS" }, { &IRQa, 1, "IRQA" }, { &IRQCount, 2, "IRQC" }, @@ -43,26 +45,26 @@ static void Sync(void) { static DECLFW(UNL3DBlockWrite) { switch (A) { - /* 4800 32 */ - /* 4900 37 */ - /* 4a00 01 */ - /* 4e00 18 */ - case 0x4800: - reg[0] = V; - break; - case 0x4900: - reg[1] = V; - break; - case 0x4a00: - reg[2] = V; - break; - case 0x4e00: - reg[3] = V; - IRQCount = Count; - IRQPause = Pause; - IRQa = 1; - X6502_IRQEnd(FCEU_IQEXT); - break; + /* 4800 32 */ + /* 4900 37 */ + /* 4a00 01 */ + /* 4e00 18 */ + case 0x4800: + reg[0] = V; + break; + case 0x4900: + reg[1] = V; + break; + case 0x4a00: + reg[2] = V; + break; + case 0x4e00: + reg[3] = V; + IRQCount = Count; + IRQPause = Pause; + IRQa = 1; + X6502_IRQEnd(FCEU_IQEXT); + break; } } @@ -77,7 +79,7 @@ static void UNL3DBlockReset(void) { FCEU_printf("Count=%04x\n", Count); } -static void FP_FASTAPASS(1) UNL3DBlockIRQHook(int a) { +static void UNL3DBlockIRQHook(int a) { if (IRQa) { if (IRQCount > 0) { IRQCount -= a; @@ -103,5 +105,5 @@ void UNL3DBlock_Init(CartInfo *info) { info->Reset = UNL3DBlockReset; MapIRQHook = UNL3DBlockIRQHook; GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/et-4320.c b/src/mappers/unifEt4320.c similarity index 54% rename from src/boards/et-4320.c rename to src/mappers/unifEt4320.c index e6c96ce75..5473240c4 100644 --- a/src/boards/et-4320.c +++ b/src/mappers/unifEt4320.c @@ -4,6 +4,7 @@ * Copyright (C) 2016 Cluster * http://clusterrr.com * clusterrr@clusterrr.com +* Copyright (C) 2023 * * 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 @@ -38,83 +39,122 @@ Example Game: 7 in 1 multicart (Amarello, TMNT2, Contra, Ninja Cat, Ninja Crusaders, Rainbow Islands 2) */ +/* NOTE: + * Appears similar to Mapper 327 but with mirroring similar to Mapper 118? + * Cannot find a cart to confirm this though +*/ + #include "mapinc.h" #include "mmc3.h" -static uint8 *CHRRAM; +static uint8 *CHRRAM = NULL; static uint32 CHRRAMSize; -static uint8 PPUCHRBus; -static uint8 TKSMIR[8]; +static uint8 reg; static void BMC810131C_PW(uint32 A, uint8 V) { - if ((mmc3.expregs[0] >> 3) & 1) - setprg8(A, (V & 0x1F) | ((mmc3.expregs[0] & 7) << 4)); - else - setprg8(A, (V & 0x0F) | ((mmc3.expregs[0] & 7) << 4)); + uint16 mask = (reg & 0x08) ? 0x1F : 0x0F; + uint16 base = (reg << 4) & 0x70; + + setprg8(A, (base | (V & mask))); } static void BMC810131C_CW(uint32 A, uint8 V) { - if ((mmc3.expregs[0] >> 4) & 1) + uint16 base = (reg << 7) & 0x380; + + if (reg & 0x10) { setchr1r(0x10, A, V); - else if (((mmc3.expregs[0] >> 5) & 1) && ((mmc3.expregs[0] >> 3) & 1)) - setchr1(A, V | ((mmc3.expregs[0] & 7) << 7)); - else - setchr1(A, (V & 0x7F) | ((mmc3.expregs[0] & 7) << 7)); - - TKSMIR[A >> 10] = V >> 7; - if (((mmc3.expregs[0] >> 3) & 1) && (PPUCHRBus == (A >> 10))) - setmirror(MI_0 + (V >> 7)); + } else if ((reg & 0x20) && (reg & 0x08)) { + setchr1(A, (base | (V & 0xFF))); + } else { + setchr1(A, (base | (V & 0x7F))); + } } -static DECLFW(BMC810131C_Write) { - if (((mmc3.wram & 0xC0) == 0x80) && !(mmc3.expregs[0] & 7)) - { - mmc3.expregs[0] = A & 0x3F; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); +static void BMC810131C_SyncMIRR(void) { + if (reg & 0x08) { + if (mmc3.cmd & 0x80) { + setntamem(NTARAM + 0x400 * ((mmc3.reg[2] >> 7) & 0x01), 1, 0); + setntamem(NTARAM + 0x400 * ((mmc3.reg[3] >> 7) & 0x01), 1, 1); + setntamem(NTARAM + 0x400 * ((mmc3.reg[4] >> 7) & 0x01), 1, 2); + setntamem(NTARAM + 0x400 * ((mmc3.reg[5] >> 7) & 0x01), 1, 3); + } else { + setntamem(NTARAM + 0x400 * ((mmc3.reg[0] >> 7) & 0x01), 1, 0); + setntamem(NTARAM + 0x400 * ((mmc3.reg[0] >> 7) & 0x01), 1, 1); + setntamem(NTARAM + 0x400 * ((mmc3.reg[1] >> 7) & 0x01), 1, 2); + setntamem(NTARAM + 0x400 * ((mmc3.reg[1] >> 7) & 0x01), 1, 3); + } + } else { + setmirror((mmc3.mirr & 0x01) ^ 0x01); } - else { +} + +static DECLFW(BMC810131C_Write) { + if (((mmc3.wram & 0xC0) == 0x80) && !(reg & 0x07)) { + reg = A & 0x3F; + MMC3_FixPRG(); + MMC3_FixCHR(); + } else { CartBW(A, V); } } +static DECLFW(BMC810131C_WriteCMD) { + switch (A & 0xE001) { + case 0x8001: + switch (mmc3.cmd & 0x07) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + mmc3.reg[mmc3.cmd & 0x07] = V; + MMC3_FixCHR(); + MMC3_FixMIR(); + break; + default: + MMC3_CMDWrite(A, V); + break; + } + break; + default: + MMC3_CMDWrite(A, V); + break; + } +} + static void BMC810131C_Reset(void) { - mmc3.expregs[0] = 0; - MMC3RegReset(); + reg = 0; + MMC3_Reset(); } static void BMC810131C_Power(void) { - mmc3.expregs[0] = 0; - GenMMC3Power(); + reg = 0; + MMC3_Power(); SetWriteHandler(0x6000, 0x7FFF, BMC810131C_Write); + SetWriteHandler(0x8000, 0x9FFF, BMC810131C_WriteCMD); } static void BMC810131C_Close(void) { - GenMMC3Close(); - if (CHRRAM) + MMC3_Close(); + if (CHRRAM) { FCEU_gfree(CHRRAM); + } CHRRAM = NULL; } -static void TKSPPU(uint32 A) { - A &= 0x1FFF; - A >>= 10; - PPUCHRBus = A; - if ((mmc3.expregs[0] >> 3) & 1) - setmirror(MI_0 + TKSMIR[A]); -} - void BMC810131C_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 8, 0); + MMC3_Init(info, 8, 0); + MMC3_FixMIR = BMC810131C_SyncMIRR; + MMC3_pwrap = BMC810131C_PW; + MMC3_cwrap = BMC810131C_CW; + info->Power = BMC810131C_Power; + info->Reset = BMC810131C_Reset; + info->Close = BMC810131C_Close; + AddExState(®, 1, 0, "EXPR"); + CHRRAMSize = 8192; CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSize); SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSize, 1); AddExState(CHRRAM, CHRRAMSize, 0, "CHRR"); - mmc3.pwrap = BMC810131C_PW; - mmc3.cwrap = BMC810131C_CW; - PPU_hook = TKSPPU; - info->Power = BMC810131C_Power; - info->Reset = BMC810131C_Reset; - info->Close = BMC810131C_Close; - AddExState(mmc3.expregs, 1, 0, "EXPR"); } diff --git a/src/boards/famicombox.c b/src/mappers/unifFamicombox.c similarity index 95% rename from src/boards/famicombox.c rename to src/mappers/unifFamicombox.c index 92e93f104..e4f78fe23 100644 --- a/src/boards/famicombox.c +++ b/src/mappers/unifFamicombox.c @@ -21,8 +21,6 @@ #include "mapinc.h" static uint8 regs[8]; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; static SFORMAT StateRegs[] = { @@ -92,9 +90,6 @@ static void SSSNROMReset(void) { } static void SSSNROMClose(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; } static void SSSNROMIRQHook(void) { @@ -116,5 +111,5 @@ void SSSNROM_Init(CartInfo *info) { WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); } diff --git a/src/boards/KG256.c b/src/mappers/unifKG256.c similarity index 98% rename from src/boards/KG256.c rename to src/mappers/unifKG256.c index a2ac18023..70bd2e713 100644 --- a/src/boards/KG256.c +++ b/src/mappers/unifKG256.c @@ -103,7 +103,7 @@ void KG256_Init(CartInfo *info) { info->Power = KG256Power; info->Reset = KG256Reset; - AddExState(&StateRegs, ~0, 0, 0); + AddExState(StateRegs, ~0, 0, NULL); GameStateRestore = StateRestore; } diff --git a/src/boards/t-227-1.c b/src/mappers/unifT2271.c similarity index 73% rename from src/boards/t-227-1.c rename to src/mappers/unifT2271.c index 3ef10297c..7783ab541 100644 --- a/src/boards/t-227-1.c +++ b/src/mappers/unifT2271.c @@ -24,34 +24,35 @@ #include "mmc3.h" static uint8 reset_flag = 0x07; +static uint8 reg; static void BMCT2271CW(uint32 A, uint8 V) { uint32 va = V; - if (mmc3.expregs[0] & 0x20) { + if (reg & 0x20) { va |= 0x200; - va |= (mmc3.expregs[0] & 0x10) << 4; + va |= (reg & 0x10) << 4; } else { va &= 0x7F; - va |= (mmc3.expregs[0] & 0x18) << 4; + va |= (reg & 0x18) << 4; } setchr1(A, va); } static void BMCT2271PW(uint32 A, uint8 V) { uint32 va = V & 0x3F; - if (mmc3.expregs[0] & 0x20) { + if (reg & 0x20) { va &= 0x1F; va |= 0x40; - va |= (mmc3.expregs[0] & 0x10) << 1; + va |= (reg & 0x10) << 1; } else { va &= 0x0F; - va |= (mmc3.expregs[0] & 0x18) << 1; + va |= (reg & 0x18) << 1; } - switch (mmc3.expregs[0] & 3) { + switch (reg & 3) { case 0x00: setprg8(A, va); break; case 0x02: { - va = (va & 0xFD) | ((mmc3.expregs[0] & 4) >> 1); + va = (va & 0xFD) | ((reg & 4) >> 1); if (A < 0xC000) { setprg16(0x8000, va >> 1); setprg16(0xC000, va >> 1); @@ -64,37 +65,37 @@ static void BMCT2271PW(uint32 A, uint8 V) { } static DECLFW(BMCT2271LoWrite) { - if (!(mmc3.expregs[0] & 0x80)) - mmc3.expregs[0] = A & 0xFF; - FixMMC3PRG(mmc3.cmd); - FixMMC3CHR(mmc3.cmd); + if (!(reg & 0x80)) + reg = A & 0xFF; + MMC3_FixPRG(); + MMC3_FixCHR(); } static DECLFR(BMCT2271HiRead) { uint32 av = A; - if (mmc3.expregs[0] & 0x40) av = (av & 0xFFF0) | reset_flag; + if (reg & 0x40) av = (av & 0xFFF0) | reset_flag; return CartBR(av); } static void BMCT2271Reset(void) { - mmc3.expregs[0] = 0x00; + reg = 0x00; reset_flag++; reset_flag &= 0x0F; - MMC3RegReset(); + MMC3_Reset(); } static void BMCT2271Power(void) { - mmc3.expregs[0] = 0x00; - GenMMC3Power(); + reg = 0x00; + MMC3_Power(); SetWriteHandler(0x6000, 0x7FFF, BMCT2271LoWrite); SetReadHandler(0x8000, 0xFFFF, BMCT2271HiRead); } void BMCT2271_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 128, 8, 0); - mmc3.pwrap = BMCT2271PW; - mmc3.cwrap = BMCT2271CW; + MMC3_Init(info, 8, 0); + MMC3_pwrap = BMCT2271PW; + MMC3_cwrap = BMCT2271CW; info->Power = BMCT2271Power; info->Reset = BMCT2271Reset; - AddExState(mmc3.expregs, 1, 0, "EXPR"); + AddExState(®, 1, 0, "EXPR"); } diff --git a/src/boards/transformer.c b/src/mappers/unifTransformer.c similarity index 94% rename from src/boards/transformer.c rename to src/mappers/unifTransformer.c index cef95142b..257149fd9 100644 --- a/src/boards/transformer.c +++ b/src/mappers/unifTransformer.c @@ -33,15 +33,12 @@ #include "mapinc.h" -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; - char *GetKeyboard(void); static char *TransformerKeys, oldkeys[256]; static int TransformerCycleCount, TransformerChar = 0; -static void FP_FASTAPASS(1) TransformerIRQHook(int a) { +static void TransformerIRQHook(int a) { TransformerCycleCount += a; if (TransformerCycleCount >= 1000) { uint32 i; @@ -89,9 +86,6 @@ static void TransformerPower(void) { } static void TransformerClose(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; } void Transformer_Init(CartInfo *info) { diff --git a/src/md5.c b/src/md5.c index f674bbc10..a977e9d95 100644 --- a/src/md5.c +++ b/src/md5.c @@ -40,7 +40,7 @@ void md5_starts(struct md5_context *ctx) { ctx->state[3] = 0x10325476; } -void md5_process(struct md5_context *ctx, uint8 data[64]) { +static void md5_process(struct md5_context *ctx, uint8 data[64]) { uint32 A, B, C, D, X[16]; GET_UINT32(X[0], data, 0); diff --git a/src/nsf.c b/src/nsf.c index 9046c19bf..79fe83bbf 100644 --- a/src/nsf.c +++ b/src/nsf.c @@ -23,26 +23,39 @@ #include #include +#include + #include "fceu-types.h" #include "x6502.h" #include "fceu.h" #include "video.h" #include "sound.h" #include "nsf.h" +#include "nsfe.h" #include "general.h" #include "fceu-memory.h" #include "file.h" #include "fds.h" -#include "fds_apu.h" +#include "fdssound.h" #include "cart.h" #include "input.h" +#include "state.h" + +#include "mappers/hw/vrc6.h" +#include "mappers/hw/vrc7.h" + +#include "mappers/sound/vrc6sound.h" +#include "mappers/sound/vrc7sound.h" +#include "mappers/sound/fdssound.h" +#include "mappers/sound/mmc5sound.h" +#include "mappers/sound/n163sound.h" +#include "mappers/sound/s5bsound.h" #ifndef M_PI #define M_PI 3.14159265358979323846 #endif -static uint8 SongReload; -static int CurrentSong; +#define FIXED_EXWRAM_SIZE (32768 + 8192) static DECLFW(NSF_write); static DECLFR(NSF_read); @@ -79,99 +92,206 @@ static DECLFR(NSFROMRead) { return (NSFROM - 0x3800)[A]; } +static int lastJoy; static int doreset = 0; static int NSFNMIFlags; -static uint8 *NSFDATA = 0; -static int NSFMaxBank; -static int NSFSize; static uint8 BSon; -static uint16 PlayAddr; -static uint16 InitAddr; -static uint16 LoadAddr; +static int special = 0; +static uint8 *ExWRAM = 0; -static NSF_HEADER NSFHeader; +static uint8 SongReload; + +NSFINFO *NSFInfo; +uint8 FCEU_GetJoyJoy(void); void NSFMMC5_Close(void); -static uint8 *ExWRAM = 0; -void NSFGI(int h) { +void NSFVRC6_Init(int, int, int); +void NSFVRC7_Init(int, int, int); +void NSFFDS_Init(int); +void NSFMMC5_Init(int); +void NSFN163_Init(int); +void NSFS5B_Init(int); + +DECLFW(Mapper5_write); +DECLFW(MMC5_ExRAMWr); + +static DECLFW(NSF_write); + +static SFORMAT StateRegs[] = { + { &lastJoy, 1, "JOY" }, + { &SongReload, 1, "SREL" }, + { &doreset, 1, "DORE" }, + { &NSFNMIFlags, 1, "NMIF" }, + { 0 } +}; + +static void FreeNSF(void) { + if (NSFInfo->NSFDATA) { + free(NSFInfo->NSFDATA); + } + if (NSFInfo->SoundChip & NSFSOUND_VRC6) { + /* NSFVRC6_Init(); */ + } + if (NSFInfo->SoundChip & NSFSOUND_VRC7) { + /* NSFVRC7_Init(); */ + } + if (NSFInfo->SoundChip & NSFSOUND_FDS) { + /* FDSSound_Reset(); */ + } + if (NSFInfo->SoundChip & NSFSOUND_MMC5) { + NSFMMC5_Close(); + } + if (NSFInfo->SoundChip & NSFSOUND_N163) { + /* NSFN163_Init(); */ + } + if (NSFInfo->SoundChip & NSFSOUND_S5B) { + /* NSFS5B_Init(); */ + } + + if (NSFInfo) { + free(NSFInfo); + NSFInfo = 0; + } + + if (ExWRAM) { + free(ExWRAM); + ExWRAM = 0; + } +} + +static void NSFGI(int h) { switch (h) { case GI_CLOSE: - if (NSFDATA) { - free(NSFDATA); NSFDATA = 0; - } - if (ExWRAM) { - free(ExWRAM); ExWRAM = 0; - } - if (NSFHeader.SoundChip & 1) { -/* NSFVRC6_Init(); */ - } else if (NSFHeader.SoundChip & 2) { -/* NSFVRC7_Init(); */ - } else if (NSFHeader.SoundChip & 4) { -/* FDSSoundReset(); */ - } else if (NSFHeader.SoundChip & 8) { - NSFMMC5_Close(); - } else if (NSFHeader.SoundChip & 0x10) { -/* NSFN106_Init(); */ - } else if (NSFHeader.SoundChip & 0x20) { -/* NSFAY_Init(); */ - } + FreeNSF(); break; case GI_RESETM2: - case GI_POWER: NSF_init(); break; + case GI_POWER: + NSF_init(); + break; } } /* First 32KB is reserved for sound chip emulation in the iNES mapper code. */ static INLINE void BANKSET(uint32 A, uint32 bank) { - bank &= NSFMaxBank; - if (NSFHeader.SoundChip & 4) - memcpy(ExWRAM + (A - 0x6000), NSFDATA + (bank << 12), 4096); - else + bank &= NSFInfo->NSFMaxBank; + if (NSFInfo->SoundChip & NSFSOUND_FDS) { + memcpy(ExWRAM + (A - 0x6000), NSFInfo->NSFDATA + (bank << 12), 4096); + } else { setprg4(A, bank); + } } -int NSFLoad(FCEUFILE *fp) { - int x; +static int LoadNSF(FCEUFILE *fp) { + size_t tmp_size = FCEU_fgetsize(fp) - 0x80; + NSF_HEADER NSFHeader; - FCEU_fseek(fp, 0, SEEK_SET); FCEU_fread(&NSFHeader, 1, 0x80, fp); - if (memcmp(NSFHeader.ID, "NESM\x1a", 5)) - return 0; - NSFHeader.SongName[31] = NSFHeader.Artist[31] = NSFHeader.Copyright[31] = 0; - LoadAddr = NSFHeader.LoadAddressLow; - LoadAddr |= NSFHeader.LoadAddressHigh << 8; + /* NULL-terminate strings just in case. */ + NSFHeader.GameName[31] = NSFHeader.Artist[31] = NSFHeader.Copyright[31] = 0; - if (LoadAddr < 0x6000) { - FCEUD_PrintError("Invalid load address."); - return(0); - } - InitAddr = NSFHeader.InitAddressLow; - InitAddr |= NSFHeader.InitAddressHigh << 8; + sprintf((char *)NSFInfo->SongName, "%s", (const char *)NSFHeader.GameName); + sprintf((char *)NSFInfo->Artist, "%s", (const char *)NSFHeader.Artist); + sprintf((char *)NSFInfo->Copyright, "%s", (const char *)NSFHeader.Copyright); - PlayAddr = NSFHeader.PlayAddressLow; - PlayAddr |= NSFHeader.PlayAddressHigh << 8; + NSFInfo->LoadAddr = NSFHeader.LoadAddressLow | (NSFHeader.LoadAddressHigh << 8); + NSFInfo->InitAddr = NSFHeader.InitAddressLow | (NSFHeader.InitAddressHigh << 8); + NSFInfo->PlayAddr = NSFHeader.PlayAddressLow | (NSFHeader.PlayAddressHigh << 8); - NSFSize = FCEU_fgetsize(fp) - 0x80; + if (tmp_size > 16 * 1024 * 1024) { + FCEU_PrintError("NSF is too large.\n"); + return FALSE; + } + + NSFInfo->NSFSize = tmp_size; - NSFMaxBank = ((NSFSize + (LoadAddr & 0xfff) + 4095) / 4096); - NSFMaxBank = uppow2(NSFMaxBank); + NSFInfo->NSFMaxBank = ((NSFInfo->NSFSize + (NSFInfo->LoadAddr & 0xfff) + 4095) / 4096); + NSFInfo->NSFMaxBank = PRGsize[0] = uppow2(NSFInfo->NSFMaxBank); - if (!(NSFDATA = (uint8*)FCEU_malloc(NSFMaxBank * 4096))) - return 0; + if (!(NSFInfo->NSFDATA = (uint8 *)FCEU_malloc(NSFInfo->NSFMaxBank * 4096))) { + return FALSE; + } FCEU_fseek(fp, 0x80, SEEK_SET); - memset(NSFDATA, 0x00, NSFMaxBank * 4096); - FCEU_fread(NSFDATA + (LoadAddr & 0xfff), 1, NSFSize, fp); + memset(NSFInfo->NSFDATA, 0x00, NSFInfo->NSFMaxBank * 4096); + FCEU_fread(NSFInfo->NSFDATA + (NSFInfo->LoadAddr & 0xfff), 1, NSFInfo->NSFSize, fp); + + NSFInfo->NSFMaxBank--; + + NSFInfo->VideoSystem = NSFHeader.VideoSystem; + NSFInfo->SoundChip = NSFHeader.SoundChip; + NSFInfo->TotalSongs = NSFHeader.TotalSongs; + + if (NSFHeader.StartingSong == 0) { + NSFHeader.StartingSong = 1; + } + + NSFInfo->StartingSong = NSFHeader.StartingSong - 1; + memcpy(NSFInfo->BankSwitch, NSFHeader.BankSwitch, 8); + + return TRUE; +} + +int NSFLoad(FCEUFILE *fp) { + char magic[5]; + int x; + + NSFInfo = FCEU_malloc(sizeof(*NSFInfo)); + + FCEU_fseek(fp, 0, SEEK_SET); + FCEU_fread(&magic, 1, 5, fp); + + if (!memcmp(magic, "NESM\x1a", 5)) { + FCEU_fseek(fp, 0, SEEK_SET); + if (!LoadNSF(fp)) { + FreeNSF(); + return FALSE; + } + } else if (!memcmp(magic, "NSFE", 4)) { + FCEU_fseek(fp, 0, SEEK_SET); + if (!LoadNSFE(fp)) { + FreeNSF(); + return FALSE; + } + } - NSFMaxBank--; + if (NSFInfo->LoadAddr < 0x6000) { + FCEU_PrintError("Invalid load address!"); + FreeNSF(); + return FALSE; + } + + if (NSFInfo->TotalSongs < 1) { + FCEU_PrintError("Total number of songs is less than 1\n"); + FreeNSF(); + return FALSE; + } BSon = 0; - for (x = 0; x < 8; x++) - BSon |= NSFHeader.BankSwitch[x]; + for (x = 0; x < 8; x++) { + BSon |= NSFInfo->BankSwitch[x]; + } + + if (BSon == 0) { + uint8 BankCounter = 0x00; + + if (((NSFInfo->LoadAddr >> 8) & 0x70) >= 0x70) { + BSon = 0xFF; /* Ice Climber, and other F000 base address tunes need this */ + } else { + for (x = ((NSFInfo->LoadAddr >> 8) & 0x70) / 0x10; x < 8; x++) { + NSFInfo->BankSwitch[x] = BankCounter; + BankCounter += 0x01; + } + BSon = 0; + } + } + + for (x = 0; x < 8; x++) { + BSon |= NSFInfo->BankSwitch[x]; + } GameInfo->type = GIT_NSF; GameInfo->input[0] = GameInfo->input[1] = SI_GAMEPAD; @@ -179,138 +299,291 @@ int NSFLoad(FCEUFILE *fp) { for (x = 0;; x++) { if (NSFROM[x] == 0x20) { - NSFROM[x + 1] = InitAddr & 0xFF; - NSFROM[x + 2] = InitAddr >> 8; - NSFROM[x + 8] = PlayAddr & 0xFF; - NSFROM[x + 9] = PlayAddr >> 8; + NSFROM[x + 1] = NSFInfo->InitAddr & 0xFF; + NSFROM[x + 2] = NSFInfo->InitAddr >> 8; + NSFROM[x + 8] = NSFInfo->PlayAddr & 0xFF; + NSFROM[x + 9] = NSFInfo->PlayAddr >> 8; break; } } - if (NSFHeader.VideoSystem == 0) + if (NSFInfo->VideoSystem == 0) { GameInfo->vidsys = GIV_NTSC; - else if (NSFHeader.VideoSystem == 1) + } else if (NSFInfo->VideoSystem == 1) { GameInfo->vidsys = GIV_PAL; + } GameInterface = NSFGI; - FCEU_printf("NSF Loaded. File information:\n\n"); - FCEU_printf(" Name: %s\n Artist: %s\n Copyright: %s\n\n", NSFHeader.SongName, NSFHeader.Artist, NSFHeader.Copyright); - if (NSFHeader.SoundChip) { - static char *tab[6] = { "Konami VRCVI", "Konami VRCVII", "Nintendo FDS", "Nintendo MMC5", "Namco 106", "Sunsoft FME-07" }; - - for (x = 0; x < 6; x++) - if (NSFHeader.SoundChip & (1 << x)) { + FCEU_printf("\n"); + FCEU_printf("NSF Loaded.\n"); + FCEU_printf("File information:\n"); + FCEU_printf(" Name: %s\n", NSFInfo->SongName); + FCEU_printf(" Artist: %s\n", NSFInfo->Artist); + FCEU_printf(" Copyright: %s\n", NSFInfo->Copyright); + if (NSFInfo->Dumper[0]) { + FCEU_printf(" Dumper: %s\n", NSFInfo->Dumper); + } + FCEU_printf("\n"); + if (NSFInfo->SoundChip) { + static char *tab[6] = { + "Konami VRC6", + "Konami VRC7", + "Nintendo FDS", + "Nintendo MMC5", + "Namco 163", + "Sunsoft 5B", + }; + + for (x = 0; x < 6; x++) { + if (NSFInfo->SoundChip & (1 << x)) { FCEU_printf(" Expansion hardware: %s\n", tab[x]); - NSFHeader.SoundChip = 1 << x; /* Prevent confusing weirdness if more than one bit is set. */ + #if 0 + NSFInfo->SoundChip = 1 << x; /* Prevent confusing weirdness if more than one bit is set. */ break; + #endif } + } } - if (BSon) + if (BSon) { FCEU_printf(" Bank-switched.\n"); - FCEU_printf(" Load address: $%04x\n Init address: $%04x\n Play address: $%04x\n", LoadAddr, InitAddr, PlayAddr); - FCEU_printf(" %s\n", (NSFHeader.VideoSystem & 1) ? "PAL" : "NTSC"); - FCEU_printf(" Starting song: %d / %d\n\n", NSFHeader.StartingSong, NSFHeader.TotalSongs); - - if (NSFHeader.SoundChip & 4) - ExWRAM = FCEU_gmalloc(32768 + 8192); - else - ExWRAM = FCEU_gmalloc(8192); - return 1; + } + FCEU_printf(" Load address: $%04x\n", NSFInfo->LoadAddr); + FCEU_printf(" Init address: $%04x\n", NSFInfo->InitAddr); + FCEU_printf(" Play address: $%04x\n", NSFInfo->PlayAddr); + FCEU_printf(" %s\n", (NSFInfo->VideoSystem & 1) ? "PAL" : "NTSC"); + FCEU_printf(" Starting song: %d / %d\n\n", NSFInfo->StartingSong + 1, NSFInfo->TotalSongs); + + /*ExWRAMSIZE = 8192; + if (NSFInfo->SoundChip & NSFSOUND_FDS) + ExWRAMSIZE = 32768 + 8192;*/ + /* ExWRAM default size is 8192. FDS format adds additional 32K for RAM. + * For simplicity for savestates and runahead, lets just use the maximum size here. */ + ExWRAM = (uint8 *)FCEU_gmalloc(FIXED_EXWRAM_SIZE); + + FCEUI_SetVidSystem(NSFInfo->VideoSystem != 0); + lastJoy = 0; + + /* TODO: hard-clip strings for now because of DrawNSF limtis */ + NSFInfo->SongName[31] = 0; + NSFInfo->Artist[31] = 0; + NSFInfo->Copyright[31] = 0; + NSFInfo->Dumper[31] = 0; + for (x = 0; x < (sizeof(NSFInfo->SongNames) / sizeof(NSFInfo->SongNames[0])); x++) { + NSFInfo->SongNames[x][31] = 0; + } + + return TRUE; } static DECLFR(NSFVectorRead) { if (((NSFNMIFlags & 1) && SongReload) || (NSFNMIFlags & 2) || doreset) { - if (A == 0xFFFA) return(0x00); - else if (A == 0xFFFB) return(0x38); - else if (A == 0xFFFC) return(0x20); - else if (A == 0xFFFD) { - doreset = 0; return(0x38); + if (A == 0xFFFA) { + return (0x00); + } else if (A == 0xFFFB) { + return (0x38); + } else if (A == 0xFFFC) { + return (0x20); + } else if (A == 0xFFFD) { + doreset = 0; + return (0x38); } - return(X.DB); - } else - return(CartBR(A)); + return (cpu.openbus); + } else { + return (CartBR(A)); + } } -void NSFVRC6_Init(void); -void NSFVRC7_Init(void); -void NSFMMC5_Init(void); -void NSFN106_Init(void); -void NSFAY_Init(void); - void NSF_init(void) { - doreset = 1; + size_t x; + int expsound = 0; + doreset = 1; + ResetExState(0, 0); ResetCartMapping(); - if (NSFHeader.SoundChip & 4) { - SetupCartPRGMapping(0, ExWRAM, 32768 + 8192, 1); + + /* intercept cpu writes */ + SetWriteHandler(0x2000, 0x3FFF, NSF_write); + SetWriteHandler(0x4020, 0xFFFF, NSF_write); + + if (NSFInfo->SoundChip & NSFSOUND_FDS) { + SetupCartPRGMapping(0, ExWRAM, FIXED_EXWRAM_SIZE, 1); setprg32(0x6000, 0); setprg8(0xE000, 4); - memset(ExWRAM, 0x00, 32768 + 8192); - SetWriteHandler(0x6000, 0xDFFF, CartBW); + memset(ExWRAM, 0x00, FIXED_EXWRAM_SIZE); + /* SetWriteHandler(0, 0x6000, 0xDFFF, CartBW); */ SetReadHandler(0x6000, 0xFFFF, CartBR); } else { memset(ExWRAM, 0x00, 8192); SetReadHandler(0x6000, 0x7FFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - SetupCartPRGMapping(0, NSFDATA, ((NSFMaxBank + 1) * 4096), 0); + /*SetWriteHandler(0, 0x6000, 0x7FFF, CartBW);*/ + SetupCartPRGMapping(0, NSFInfo->NSFDATA, ((NSFInfo->NSFMaxBank + 1) * 4096), 0); SetupCartPRGMapping(1, ExWRAM, 8192, 1); setprg8r(1, 0x6000, 0); SetReadHandler(0x8000, 0xFFFF, CartBR); } if (BSon) { - int32 x; for (x = 0; x < 8; x++) { - if (NSFHeader.SoundChip & 4 && x >= 6) - BANKSET(0x6000 + (x - 6) * 4096, NSFHeader.BankSwitch[x]); - BANKSET(0x8000 + x * 4096, NSFHeader.BankSwitch[x]); + if (NSFInfo->SoundChip & NSFSOUND_FDS && x >= 6) { + BANKSET(0x6000 + (x - 6) * 4096, NSFInfo->BankSwitch[x]); + } + BANKSET(0x8000 + x * 4096, NSFInfo->BankSwitch[x]); } } else { - int32 x; - for (x = (LoadAddr & 0xF000); x < 0x10000; x += 0x1000) - BANKSET(x, ((x - (LoadAddr & 0x7000)) >> 12)); + for (x = (NSFInfo->LoadAddr & 0xF000); x < 0x10000; x += 0x1000) { + BANKSET(x, ((x - (NSFInfo->LoadAddr & 0xF000)) >> 12)); + } } SetReadHandler(0xFFFA, 0xFFFD, NSFVectorRead); - SetWriteHandler(0x2000, 0x3fff, 0); + SetWriteHandler(0x2000, 0x3fef, 0); SetReadHandler(0x2000, 0x37ff, 0); SetReadHandler(0x3836, 0x3FFF, 0); SetReadHandler(0x3800, 0x3835, NSFROMRead); - SetWriteHandler(0x5ff6, 0x5fff, NSF_write); + /*SetWriteHandler(0, 0x5ff6, 0x5fff, NSF_write);*/ - SetWriteHandler(0x3ff0, 0x3fff, NSF_write); + /*SetWriteHandler(0, 0x3ff0, 0x3fff, NSF_write);*/ SetReadHandler(0x3ff0, 0x3fff, NSF_read); + if (NSFInfo->SoundChip & NSFSOUND_VRC6) { + NSFVRC6_Init(expsound++, 0x01, 0x02); + } + if (NSFInfo->SoundChip & NSFSOUND_VRC7) { + NSFVRC7_Init(expsound++, 0x10, 0x20); + } + if (NSFInfo->SoundChip & NSFSOUND_FDS) { + NSFFDS_Init(expsound++); + } + if (NSFInfo->SoundChip & NSFSOUND_MMC5) { + NSFMMC5_Init(expsound++); + } + if (NSFInfo->SoundChip & NSFSOUND_N163) { + NSFN163_Init(expsound++); + } + if (NSFInfo->SoundChip & NSFSOUND_S5B) { + NSFS5B_Init(expsound++); + } - if (NSFHeader.SoundChip & 1) { - NSFVRC6_Init(); - } else if (NSFHeader.SoundChip & 2) { - NSFVRC7_Init(); - } else if (NSFHeader.SoundChip & 4) { - FDSSoundReset(); - } else if (NSFHeader.SoundChip & 8) { - NSFMMC5_Init(); - } else if (NSFHeader.SoundChip & 0x10) { - NSFN106_Init(); - } else if (NSFHeader.SoundChip & 0x20) { - NSFAY_Init(); - } - CurrentSong = NSFHeader.StartingSong; + NSFInfo->CurrentSong = NSFInfo->StartingSong; SongReload = 0xFF; NSFNMIFlags = 0; + + AddExState(StateRegs, ~0, 0, NULL); + AddExState(ExWRAM, FIXED_EXWRAM_SIZE, 0, "ERAM"); + AddExState(&NSFInfo->CurrentSong, 4 | FCEUSTATE_RLSB, 0, "CURS"); + + if (NSFInfo->SoundChip & NSFSOUND_VRC6) { + VRC6Sound_AddStateInfo(); + } + if (NSFInfo->SoundChip & NSFSOUND_VRC7) { + VRC7Sound_AddStateInfo(); + } + if (NSFInfo->SoundChip & NSFSOUND_FDS) { + FDSSound_AddStateInfo(); + } + if (NSFInfo->SoundChip & NSFSOUND_MMC5) { + MMC5Sound_AddStateInfo(); + } + if (NSFInfo->SoundChip & NSFSOUND_N163) { + N163Sound_AddStateInfo(); + } + if (NSFInfo->SoundChip & NSFSOUND_S5B) { + S5BSound_AddStateInfo(); + } } static DECLFW(NSF_write) { + if (NSFInfo->SoundChip & NSFSOUND_VRC6) { + switch (A) { + case 0x9000: + case 0x9001: + case 0x9002: + case 0xA000: + case 0xA001: + case 0xA002: + case 0xB000: + case 0xB001: + case 0xB002: + VRC6_Write(A, V); + break; + } + } + + if (NSFInfo->SoundChip & NSFSOUND_VRC7) { + switch (A) { + case 0x9010: + case 0x9030: + VRC7_Write(A, V); + break; + } + } + + if (NSFInfo->SoundChip & NSFSOUND_FDS) { + if ((A >= 0x6000) && (A <= 0xDFFF)){ + /* FIXME: Conflicts in multi chip modes */ + /*CartBW(A, V);*/ + } else if ((A >= 0x4040) && (A <= 0x408A)) { + FDSSound_Write(A, V); + } + } + + if (NSFInfo->SoundChip & NSFSOUND_MMC5) { + if ((A >= 0x5000) && (A <= 0x5015)) { + MMC5Sound_Write(A, V); + } else if ((A >= 0x5205) && (A <= 0x5206)) { + Mapper5_write(A, V); + } else if ((A >= 0x5c00) && (A <= 0x5FF5)) { + MMC5_ExRAMWr(A, V); + } + } + + if (NSFInfo->SoundChip & NSFSOUND_N163) { + switch (A & 0xF800) { + case 0xF800: + N163Sound_Write(A, V); + break; + case 0x4800: + N163Sound_Write(A, V); + break; + } + } + + if (NSFInfo->SoundChip & NSFSOUND_S5B) { + switch (A & 0xE000) { + case 0xC000: + case 0xE000: + N163Sound_Write(A, V); + break; + } + } + + switch (A & 0xF000) { + case 0x6000: + case 0x7000: + /* always mapped to ExWRAM */ + CartBW(A, V); + break; + } + switch (A) { - case 0x3FF3: NSFNMIFlags |= 1; break; - case 0x3FF4: NSFNMIFlags &= ~2; break; - case 0x3FF5: NSFNMIFlags |= 2; break; + case 0x3FF3: + NSFNMIFlags |= 1; + break; + case 0x3FF4: + NSFNMIFlags &= ~2; + break; + case 0x3FF5: + NSFNMIFlags |= 2; + break; case 0x5FF6: - case 0x5FF7: if (!(NSFHeader.SoundChip & 4)) return; + case 0x5FF7: + if (!(NSFInfo->SoundChip & NSFSOUND_FDS)) { + return; + } /* fallthrough */ case 0x5FF8: case 0x5FF9: @@ -319,7 +592,10 @@ static DECLFW(NSF_write) { case 0x5FFC: case 0x5FFD: case 0x5FFE: - case 0x5FFF: if (!BSon) return; + case 0x5FFF: + if (!BSon) { + return; + } A &= 0xF; BANKSET((A * 4096), V); break; @@ -330,26 +606,30 @@ static DECLFR(NSF_read) { int x; switch (A) { - case 0x3ff0: x = SongReload; - #ifdef FCEUDEF_DEBUGGER + case 0x3ff0: + x = SongReload; +#ifdef FCEUDEF_DEBUGGER if (!fceuindbg) - #endif - SongReload = 0; +#endif + SongReload = 0; return x; case 0x3ff1: - #ifdef FCEUDEF_DEBUGGER +#ifdef FCEUDEF_DEBUGGER if (!fceuindbg) - #endif +#endif { - memset(RAM, 0x00, 0x800); + for (x = 0; x < 0x800; x++) { + BWrite[x](x, 0); + } BWrite[0x4015](0x4015, 0x0); - for (x = 0; x < 0x14; x++) + for (x = 0; x < 0x14; x++) { BWrite[0x4000 + x](0x4000 + x, 0); + } BWrite[0x4015](0x4015, 0xF); - if (NSFHeader.SoundChip & 4) { - BWrite[0x4017](0x4017, 0xC0); /* FDS BIOS writes $C0 */ + if (NSFInfo->SoundChip & NSFSOUND_FDS) { + BWrite[0x4017](0x4017, 0xC0); /* FDS BIOS writes $C0 */ BWrite[0x4089](0x4089, 0x80); BWrite[0x408A](0x408A, 0xE8); } else { @@ -360,143 +640,147 @@ static DECLFR(NSF_read) { } if (BSon) { - for (x = 0; x < 8; x++) - BANKSET(0x8000 + x * 4096, NSFHeader.BankSwitch[x]); + for (x = 0; x < 8; x++) { + BANKSET(0x8000 + x * 4096, NSFInfo->BankSwitch[x]); + } } - return(CurrentSong - 1); + return (NSFInfo->CurrentSong); } - case 0x3FF3: return PAL; + case 0x3FF3: + return isPAL; } - return 0; + return FALSE; } -uint8 FCEU_GetJoyJoy(void); - -static int special = 0; - -void DrawNSF(uint8 *XBuf) { +void DrawNSF(uint8 *target) { char snbuf[16]; + int32 *Bufpl; + int32 mul = 0; + int len = GetSoundBuffer(&Bufpl); int x; + uint8 bgFill = 0x3F; + uint8 textColor = 0x20; + uint8 waveFormColor = 0x1C; - if (vismode == 0) return; - - memset(XBuf, 0, 256 * 240); - - - { - int32 *Bufpl; - int32 mul = 0; + if (vismode == 0) { + return; + } - int l; - l = GetSoundBuffer(&Bufpl); + memset(target, bgFill, 256 * 240); + memset(XDBuf, 0, 256 * 240); - if (special == 0) { - if (FSettings.SoundVolume) - mul = 8192 * 240 / (16384 * FSettings.SoundVolume / 50); - for (x = 0; x < 256; x++) { - uint32 y; - y = 142 + ((Bufpl[(x * l) >> 8] * mul) >> 14); - if (y < 240) - XBuf[x + y * 256] = 3; - } - } else if (special == 1) { - if (FSettings.SoundVolume) - mul = 8192 * 240 / (8192 * FSettings.SoundVolume / 50); - for (x = 0; x < 256; x++) { - double r; - uint32 xp, yp; - - r = (Bufpl[(x * l) >> 8] * mul) >> 14; - xp = 128 + r*cos(x*M_PI*2 / 256); - yp = 120 + r*sin(x*M_PI*2 / 256); - xp &= 255; - yp %= 240; - XBuf[xp + yp * 256] = 3; + if (special == 0) { + if (FSettings.volume[SND_MASTER]) { + mul = 8192 * 240 / (16384 * FSettings.volume[SND_MASTER] / 50); + } + for (x = 0; x < 256; x++) { + uint32 y = 142 + ((((int32)(int16)Bufpl[(x * len) >> 8]) * mul) >> 14); + if (y < 240) { + target[x + y * 256] = waveFormColor; } - } else if (special == 2) { - static double theta = 0; - if (FSettings.SoundVolume) - mul = 8192 * 240 / (16384 * FSettings.SoundVolume / 50); - for (x = 0; x < 128; x++) { - double xc, yc; - double r, t; - uint32 m, n; - - xc = (double)128 - x; - yc = 0 - ((double)(((Bufpl[(x * l) >> 8]) * mul) >> 14)); - t = M_PI + atan(yc / xc); - r = sqrt(xc * xc + yc * yc); - - t += theta; - m = 128 + r*cos(t); - n = 120 + r*sin(t); - - if (m < 256 && n < 240) - XBuf[m + n * 256] = 3; + } + } else if (special == 1) { + if (FSettings.volume[SND_MASTER]) { + mul = 8192 * 240 / (8192 * FSettings.volume[SND_MASTER] / 50); + } + for (x = 0; x < 256; x++) { + double r = (((int32)(int16)Bufpl[(x * len) >> 8]) * mul) >> 14; + uint32 xp = 128 + r * cos(x * M_PI * 2 / 256); + uint32 yp = 120 + r * sin(x * M_PI * 2 / 256); + + xp &= 255; + yp %= 240; + target[xp + yp * 256] = waveFormColor; + } + } else if (special == 2) { + static double theta = 0; + + if (FSettings.volume[SND_MASTER]) { + mul = 8192 * 240 / (16384 * FSettings.volume[SND_MASTER] / 50); + } + for (x = 0; x < 128; x++) { + double xc = (double)128 - x; + double yc = 0.0 - ((double)((((int32)(int16)Bufpl[(x * len) >> 8]) * mul) >> 14)); + double t = (M_PI + atan(yc / xc)) + theta; + double r = sqrt(xc * xc + yc * yc); + uint32 m = 128 + r * cos(t); + uint32 n = 120 + r * sin(t); + + if (m < 256 && n < 240) { + target[m + n * 256] = waveFormColor; } - for (x = 128; x < 256; x++) { - double xc, yc; - double r, t; - uint32 m, n; - - xc = (double)x - 128; - yc = (double)((Bufpl[(x * l) >> 8] * mul) >> 14); - t = atan(yc / xc); - r = sqrt(xc * xc + yc * yc); - - t += theta; - m = 128 + r*cos(t); - n = 120 + r*sin(t); - - if (m < 256 && n < 240) - XBuf[m + n * 256] = 3; + } + for (x = 128; x < 256; x++) { + double xc = (double)x - 128; + double yc = (double)((((int32)(int16)Bufpl[(x * len) >> 8]) * mul) >> 14); + double t = (atan(yc / xc)) + theta; + double r = sqrt(xc * xc + yc * yc); + uint32 m = 128 + r * cos(t); + uint32 n = 120 + r * sin(t); + + if (m < 256 && n < 240) { + target[m + n * 256] = waveFormColor; } - theta += (double)M_PI / 256; } + theta += (double)M_PI / 256; } - DrawTextTrans(XBuf + 10 * 256 + 4 + (((31 - strlen((char*)NSFHeader.SongName)) << 2)), 256, NSFHeader.SongName, 6); - DrawTextTrans(XBuf + 26 * 256 + 4 + (((31 - strlen((char*)NSFHeader.Artist)) << 2)), 256, NSFHeader.Artist, 6); - DrawTextTrans(XBuf + 42 * 256 + 4 + (((31 - strlen((char*)NSFHeader.Copyright)) << 2)), 256, NSFHeader.Copyright, 6); - - DrawTextTrans(XBuf + 70 * 256 + 4 + (((31 - strlen("Song:")) << 2)), 256, (uint8*)"Song:", 6); - sprintf(snbuf, "<%d/%d>", CurrentSong, NSFHeader.TotalSongs); - DrawTextTrans(XBuf + 82 * 256 + 4 + (((31 - strlen(snbuf)) << 2)), 256, (uint8*)snbuf, 6); + DrawTextTrans(target + 10 * 256 + 4 + (((31 - strlen((char *)NSFInfo->SongName)) << 2)), 256, (uint8*)NSFInfo->SongName, textColor); + DrawTextTrans(target + 26 * 256 + 4 + (((31 - strlen((char *)NSFInfo->Artist)) << 2)), 256, (uint8*)NSFInfo->Artist, textColor); + DrawTextTrans( target + 42 * 256 + 4 + (((31 - strlen((char *)NSFInfo->Copyright)) << 2)), 256, (uint8*)NSFInfo->Copyright, textColor); - { - static uint8 last = 0; - uint8 tmp; - tmp = FCEU_GetJoyJoy(); - if ((tmp & JOY_RIGHT) && !(last & JOY_RIGHT)) { - if (CurrentSong < NSFHeader.TotalSongs) { - CurrentSong++; - SongReload = 0xFF; - } - } else if ((tmp & JOY_LEFT) && !(last & JOY_LEFT)) { - if (CurrentSong > 1) { - CurrentSong--; - SongReload = 0xFF; - } - } else if ((tmp & JOY_UP) && !(last & JOY_UP)) { - CurrentSong += 10; - if (CurrentSong > NSFHeader.TotalSongs) CurrentSong = NSFHeader.TotalSongs; - SongReload = 0xFF; - } else if ((tmp & JOY_DOWN) && !(last & JOY_DOWN)) { - CurrentSong -= 10; - if (CurrentSong < 1) CurrentSong = 1; - SongReload = 0xFF; - } else if ((tmp & JOY_START) && !(last & JOY_START)) - SongReload = 0xFF; - else if ((tmp & JOY_A) && !(last & JOY_A)) { - special = (special + 1) % 3; - } - last = tmp; + if (NSFInfo->SongNames[0][0]) { + DrawTextTrans(target + 70 * 256 + 4 + (((31 - strlen((char *)NSFInfo->SongNames[NSFInfo->CurrentSong])) << 2)), 256, (uint8 *)NSFInfo->SongNames[NSFInfo->CurrentSong], textColor); + } else { + DrawTextTrans(target + 70 * 256 + 4 + (((31 - strlen("Song:")) << 2)), 256, (uint8 *)"Song:", textColor); } + sprintf(snbuf, "<%d/%d>", NSFInfo->CurrentSong + 1, NSFInfo->TotalSongs); + DrawTextTrans(target + 82 * 256 + 4 + (((31 - strlen(snbuf)) << 2)), 256, (uint8 *)snbuf, textColor); } void DoNSFFrame(void) { - if (((NSFNMIFlags & 1) && SongReload) || (NSFNMIFlags & 2)) + uint8 tmp = FCEU_GetJoyJoy(); + + if (((NSFNMIFlags & 1) && SongReload) || (NSFNMIFlags & 2)) { TriggerNMI(); + } + + if ((tmp & JOY_RIGHT) && !(lastJoy & JOY_RIGHT)) { + if (NSFInfo->CurrentSong < NSFInfo->TotalSongs - 1) { + NSFInfo->CurrentSong++; + } else { + NSFInfo->CurrentSong = NSFInfo->StartingSong; + } + SongReload = 0xFF; + } else if ((tmp & JOY_LEFT) && !(lastJoy & JOY_LEFT)) { + if (NSFInfo->CurrentSong > 0) { + NSFInfo->CurrentSong--; + } else { + NSFInfo->CurrentSong = NSFInfo->TotalSongs - 1; + } + SongReload = 0xFF; + } else if ((tmp & JOY_UP) && !(lastJoy & JOY_UP)) { + uint32 ns = NSFInfo->CurrentSong + (uint32)MIN(NSFInfo->TotalSongs - 1 - NSFInfo->CurrentSong, (uint32)10); + if (NSFInfo->CurrentSong != ns) { + NSFInfo->CurrentSong = ns; + SongReload = 0xFF; + } + } else if ((tmp & JOY_DOWN) && !(lastJoy & JOY_DOWN)) { + unsigned ns = NSFInfo->CurrentSong - (uint32)MIN(NSFInfo->CurrentSong, (uint32)10); + + if (NSFInfo->CurrentSong != ns) { + NSFInfo->CurrentSong = ns; + SongReload = 0xFF; + } + } else if ((tmp & JOY_SELECT) && !(lastJoy & JOY_SELECT)) { + NSFInfo->CurrentSong = NSFInfo->StartingSong; + SongReload = 0xFF; + } else if ((tmp & JOY_START) && !(lastJoy & JOY_START)) { + SongReload = 0xFF; + } else if ((tmp & JOY_A) && !(lastJoy & JOY_A)) { + special = (special + 1) % 3; + } + lastJoy = tmp; } void FCEUI_NSFSetVis(int mode) { @@ -504,18 +788,21 @@ void FCEUI_NSFSetVis(int mode) { } int FCEUI_NSFChange(int amount) { - CurrentSong += amount; - if (CurrentSong < 1) CurrentSong = 1; - else if (CurrentSong > NSFHeader.TotalSongs) CurrentSong = NSFHeader.TotalSongs; + NSFInfo->CurrentSong += amount; + if (NSFInfo->CurrentSong < 1) { + NSFInfo->CurrentSong = 1; + } else if (NSFInfo->CurrentSong > NSFInfo->TotalSongs) { + NSFInfo->CurrentSong = NSFInfo->TotalSongs; + } SongReload = 0xFF; - return(CurrentSong); + return (NSFInfo->CurrentSong); } /* Returns total songs */ int FCEUI_NSFGetInfo(uint8 *name, uint8 *artist, uint8 *copyright, int maxlen) { - strncpy((char*)name, (const char*)NSFHeader.SongName, (size_t)maxlen); - strncpy((char*)artist, (const char*)NSFHeader.Artist, (size_t)maxlen); - strncpy((char*)copyright, (const char*)NSFHeader.Copyright, (size_t)maxlen); - return(NSFHeader.TotalSongs); + strncpy((char *)name, (const char *)NSFInfo->SongName, (size_t)maxlen); + strncpy((char *)artist, (const char *)NSFInfo->Artist, (size_t)maxlen); + strncpy((char *)copyright, (const char *)NSFInfo->Copyright, (size_t)maxlen); + return (NSFInfo->TotalSongs); } diff --git a/src/nsf.h b/src/nsf.h index 2fe0bc4d0..66f60f6e9 100644 --- a/src/nsf.h +++ b/src/nsf.h @@ -21,7 +21,14 @@ #ifndef _FCEU_NSF_H #define _FCEU_NSF_H -typedef struct { +#define NSFSOUND_VRC6 0x01 +#define NSFSOUND_VRC7 0x02 +#define NSFSOUND_FDS 0x04 +#define NSFSOUND_MMC5 0x08 +#define NSFSOUND_N163 0x10 +#define NSFSOUND_S5B 0x20 + +typedef struct NSF_HEADER { char ID[5]; /* NESM^Z */ uint8 Version; uint8 TotalSongs; @@ -32,7 +39,7 @@ typedef struct { uint8 InitAddressHigh; uint8 PlayAddressLow; uint8 PlayAddressHigh; - uint8 SongName[32]; + uint8 GameName[32]; uint8 Artist[32]; uint8 Copyright[32]; uint8 NTSCspeed[2]; /* Unused */ @@ -43,10 +50,35 @@ typedef struct { uint8 Expansion[4]; uint8 reserve[8]; } NSF_HEADER; + +typedef struct NSFINFO { + char SongName[256]; + char Artist[256]; + char Copyright[256]; + char Dumper[256]; + char SongNames[100][256]; + + uint8 TotalSongs; + uint8 StartingSong; + uint8 CurrentSong; + uint8 VideoSystem; + + uint16 PlayAddr, InitAddr, LoadAddr; + uint8 BankSwitch[8]; + uint8 SoundChip; + + uint8 *NSFDATA; + size_t NSFMaxBank; + size_t NSFSize; +} NSFINFO; + +extern NSFINFO *NSFInfo; + void NSF_init(void); -void DrawNSF(uint8 *XBuf); -void NSFDealloc(void); -void NSFDodo(void); +void DrawNSF(uint8 *target); void DoNSFFrame(void); +/* NSF Expansion Chip Set Write Handler for mappers */ +void NFSSetWriteHandler(int chip, int32 start, int32 end, writefunc func); + #endif diff --git a/src/nsfe.c b/src/nsfe.c new file mode 100644 index 000000000..54d38514c --- /dev/null +++ b/src/nsfe.c @@ -0,0 +1,233 @@ +/* FCEUmm - Multi-system Emulator + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#include "fceu.h" +#include "x6502.h" +#include "sound.h" +#include "cart.h" +#include "nsf.h" +#include "nsfe.h" +#include "fceu-endian.h" +#include "file.h" +#include "general.h" + +typedef struct { + uint8 LoadAddressLow; + uint8 LoadAddressHigh; + uint8 InitAddressLow; + uint8 InitAddressHigh; + uint8 PlayAddressLow; + uint8 PlayAddressHigh; + uint8 VideoSystem; + uint8 SoundChip; + uint8 TotalSongs; + uint8 StartingSong; +} NSFE_INFO; +typedef struct { + uint32 size; + char id[4]; +} NFSE_CHUNK; + +typedef struct { + char *name; + uint8 (*init)(FCEUFILE *fp, uint8 *nend); +} BFMAPPING; + +static NFSE_CHUNK nfse_chunk; + +static void GetString(FCEUFILE *fp, uint32 *chunk_size, uint8 *str) { + unsigned count = 0; + + while (*chunk_size) { + uint8 c = FCEU_fgetc(fp); + + (*chunk_size)--; + + if (!c) { + break; + } + + if (c < 0x20) { + c = 0x20; + } + + *str++ = c; + count++; + } +} + +static uint8 nsfe_INFO(FCEUFILE *fp, uint8 *nend) { + NSFE_INFO nsfe_info; + + if (NSFInfo->TotalSongs) { + FCEU_PrintError("NSFE chunk \"%.4s\" is duplicate.\n", (char *)nfse_chunk.id); + return FALSE; + } + + if (nfse_chunk.size < 8) { + FCEU_PrintError("NSFE chunk \"%.4s\" size(%u) is invalid.\n", (char *)nfse_chunk.id, nfse_chunk.size); + return FALSE; + } + + FCEU_fread(&nsfe_info, 1, 10, fp); + + NSFInfo->TotalSongs = 1; + NSFInfo->StartingSong = 0; + + NSFInfo->LoadAddr = nsfe_info.LoadAddressLow | nsfe_info.LoadAddressHigh << 8; + NSFInfo->InitAddr = nsfe_info.InitAddressLow | nsfe_info.InitAddressHigh << 8; + NSFInfo->PlayAddr = nsfe_info.PlayAddressLow | nsfe_info.PlayAddressHigh << 8; + NSFInfo->VideoSystem = nsfe_info.VideoSystem; + NSFInfo->SoundChip = nsfe_info.SoundChip; + + nfse_chunk.size -= 8; + + if (nfse_chunk.size) { + NSFInfo->TotalSongs = nsfe_info.TotalSongs; + if (!NSFInfo->TotalSongs) { + NSFInfo->TotalSongs = 255; + } + nfse_chunk.size--; + } + + if (nfse_chunk.size) { + NSFInfo->StartingSong = nsfe_info.StartingSong; + nfse_chunk.size--; + } + + return TRUE; +} + +static uint8 nsfe_DATA(FCEUFILE *fp, uint8 *nend) { + if (!NSFInfo->TotalSongs) { + FCEU_PrintError("NSFE chunk \"%.4s\" is out of order.\n", (char *)nfse_chunk.id); + return FALSE; + } + + if (NSFInfo->NSFDATA) { + FCEU_PrintError("NSFE chunk \"%.4s\" is duplicate.\n", (char *)nfse_chunk.id); + return FALSE; + } + + NSFInfo->NSFSize = nfse_chunk.size; + NSFInfo->NSFMaxBank = uppow2((NSFInfo->NSFSize + (NSFInfo->LoadAddr & 0xfff) + 0xfff) / 0x1000) - 1; + + NSFInfo->NSFDATA = (uint8 *)FCEU_malloc((NSFInfo->NSFMaxBank + 1) * 4096); + memset(NSFInfo->NSFDATA, 0, (NSFInfo->NSFMaxBank + 1) * 4096); + FCEU_fread(NSFInfo->NSFDATA + (NSFInfo->LoadAddr & 0xfff), 1, NSFInfo->NSFSize, fp); + nfse_chunk.size -= NSFInfo->NSFSize; + + return TRUE; +} + +static uint8 nsfe_BANK(FCEUFILE *fp, uint8 *nend) { + uint64 tr = (uint64)MIN((uint64)nfse_chunk.size, (uint64)8); + + FCEU_fread(NSFInfo->BankSwitch, 1, tr, fp); + nfse_chunk.size -= 8; + + return TRUE; +} + +static uint8 nsfe_NEND(FCEUFILE *fp, uint8 *nend) { + if (nfse_chunk.size != 0) { + FCEU_PrintError("NSFE chunk \"%.4s\" size(%u) is invalid.\n", (char *)nfse_chunk.id, nfse_chunk.size); + } else if (!NSFInfo->NSFDATA) { + FCEU_PrintError("NEND reached without preceding DATA chunk.\n"); + return FALSE; + } + + *nend = TRUE; + return (*nend); +} + +static uint8 nsfe_tlbl(FCEUFILE *fp, uint8 *nend) { + unsigned ws; + + if (!NSFInfo->TotalSongs) { + FCEU_PrintError("NSFE chunk \"%.4s\" is out of order.\n", (char *)nfse_chunk.id); + } + + for (ws = 0; ws < NSFInfo->TotalSongs && nfse_chunk.size > 0; ws++) { + GetString(fp, &nfse_chunk.size, (uint8 *)NSFInfo->SongNames[ws]); + } + + return TRUE; +} + +static uint8 nsfe_auth(FCEUFILE *fp, uint8 *nend) { + unsigned count; + + for (count = 0; count < 4 && nfse_chunk.size > 0; count++) { + switch (count) { + case 0: + GetString(fp, &nfse_chunk.size, (uint8 *)&NSFInfo->SongName); + break; + case 1: + GetString(fp, &nfse_chunk.size, (uint8 *)&NSFInfo->Artist); + break; + case 2: + GetString(fp, &nfse_chunk.size, (uint8 *)&NSFInfo->Copyright); + break; + case 3: + GetString(fp, &nfse_chunk.size, (uint8 *)&NSFInfo->Dumper); + break; + } + } + return TRUE; +} + +static BFMAPPING bfunc[] = { + { "INFO", nsfe_INFO }, + { "DATA", nsfe_DATA }, + { "BANK", nsfe_BANK }, + { "tlbl", nsfe_tlbl }, + { "auth", nsfe_auth }, + { "NEND", nsfe_NEND }, + { NULL, NULL } +}; + +int LoadNSFE(FCEUFILE *fp) { + int x = 0; + uint8 nend = 0; + + FCEU_fseek(fp, 4, SEEK_CUR); + while (nend == 0) { + x = 0; + FCEU_fread(&nfse_chunk, 1, 8, fp); + while (bfunc[x].name) { + if (!memcmp(nfse_chunk.id, bfunc[x].name, 4)) { + if (!bfunc[x].init(fp, &nend)) { + return FALSE; + } + break; + } + x++; + } + if (nfse_chunk.size) { + if (FCEU_fseek(fp, nfse_chunk.size, SEEK_CUR) != 0) { + return FALSE; + } + nfse_chunk.size = 0; + } + } + return TRUE; +} \ No newline at end of file diff --git a/src/nsfe.h b/src/nsfe.h new file mode 100644 index 000000000..739d9f420 --- /dev/null +++ b/src/nsfe.h @@ -0,0 +1,6 @@ +#ifndef __FCEU_NES_NSFE_H +#define __FCEU_NES_NSFE_H + +int LoadNSFE(FCEUFILE *fp); + +#endif /* __FCEU_NES_NSFE_H */ diff --git a/src/palette.c b/src/palette.c index 96fde8b37..b79bf9c28 100644 --- a/src/palette.c +++ b/src/palette.c @@ -34,15 +34,18 @@ #include "palettes/palettes.h" /* These are dynamically filled/generated palettes: */ -pal palettei[64]; /* Custom palette for an individual game. */ -pal palettec[64]; /* Custom "global" palette. */ +pal palette_game[PALETTE_ARRAY_SIZE] = { 0 }; /* Custom palette for an individual game. */ +pal palette_user[PALETTE_ARRAY_SIZE] = { 0 }; /* Custom "global" palette. */ + +int palette_user_available = FALSE; +int palette_game_available = FALSE; +int palette_nes_selected = PAL_NES_DEFAULT; static void ChoosePalette(void); static void WritePalette(void); -uint8 pale = 0; -pal *palo; -static pal *palpoint[8] = +pal *palo = NULL; +static pal *palette_nes_default[8] = { palette, rp2c04_0001, @@ -52,18 +55,150 @@ static pal *palpoint[8] = rp2c03, }; -void FCEUI_SetPaletteArray(uint8 *pal) { - if (!pal) - palpoint[0] = palette; - else { - int x; - palpoint[0] = palettec; - for (x = 0; x < 64; x++) { - palpoint[0][x].r = *((uint8*)pal + x + x + x); - palpoint[0][x].g = *((uint8*)pal + x + x + x + 1); - palpoint[0][x].b = *((uint8*)pal + x + x + x + 2); +static float bisqwit_gammafix(float f, float gamma) { + return f < 0.f ? 0.f : pow(f, 2.2f / gamma); +} +static int bisqwit_clamp(int v) { + return v < 0 ? 0 : v > 255 ? 255 : v; +} + +/* Calculate the luma and chroma by emulating the relevant circuits: */ +static int bisqwit_wave(int p, int color) { + return (color + p + 8) % 12 < 6; +} + +#define BCLAMP(x) ((x) < 0 ? 0 : ((x) > 255 ? 255 : (x))) + +static void ApplyDeemphasisBisqwit(int entry, uint8 *r, uint8 *g, uint8 *b) { + int myr = 0, myg = 0, myb = 0; + + /* The input value is a NES color index (with de-emphasis bits). + * We need RGB values. Convert the index into RGB. + * For most part, this process is described at: + * http://wiki.nesdev.com/w/index.php/NTSC_video + */ + + /* Decode the color index */ + int color = (entry & 0x0F), level = color < 0xE ? (entry >> 4) & 3 : 1; + + /* Voltage levels, relative to synch voltage */ + static const float black = .518f, white = 1.962f, attenuation = .746f, + levels[8] = { .350f, .518f, .962f, 1.550f, /* Signal low */ + 1.094f, 1.506f, 1.962f, 1.962f }; /* Signal high */ + + float lo_and_hi[2]; /* = { levels[level + 4 * (color == 0x0)], levels[level + 4 * (color < 0xD)] }; */ + + int p, pass; + + if (entry < 64) + return; + + lo_and_hi[0] = levels[level + 4 * (color == 0x0)]; + lo_and_hi[1] = levels[level + 4 * (color < 0xD)]; + + /* fceux alteration: two passes + * 1st pass calculates bisqwit's base color + * 2nd pass calculates it with deemph + * finally, we'll do something dumb: find a 'scale factor' between them and apply it to the input palette. (later, + * we could pregenerate the scale factors) whatever, it gets the job done. + */ + for (pass = 0; pass < 2; pass++) { + float y = 0.f, i = 0.f, q = 0.f, gamma = 1.8f; + int rt, gt, bt; + + for (p = 0; p < 12; ++p) /* 12 clock cycles per pixel. */ + { + /* NES NTSC modulator (square wave between two voltage levels): */ + float spot = lo_and_hi[bisqwit_wave(p, color)]; + float v; + + /* De-emphasis bits attenuate a part of the signal: */ + if (pass == 1) { + if (((entry & 0x40) && bisqwit_wave(p, 12)) || ((entry & 0x80) && bisqwit_wave(p, 4)) || + ((entry & 0x100) && bisqwit_wave(p, 8))) + spot *= attenuation; + } + + /* Normalize: */ + v = (spot - black) / (white - black) / 12.f; + + /* Ideal TV NTSC demodulator: */ + y += v; + i += v * cos(3.141592653 * p / 6); + q += v * sin(3.141592653 * p / 6); /* Or cos(... p-3 ... ) + * Note: Integrating cos() and sin() for p-0.5 .. p+0.5 range gives + * the exactly same result, scaled by a factor of 2*cos(pi/12). + */ + } + + /* Convert YIQ into RGB according to FCC-sanctioned conversion matrix. */ + + rt = bisqwit_clamp(255 * bisqwit_gammafix(y + 0.946882f * i + 0.623557f * q, gamma)); + gt = bisqwit_clamp(255 * bisqwit_gammafix(y + -0.274788f * i + -0.635691f * q, gamma)); + bt = bisqwit_clamp(255 * bisqwit_gammafix(y + -1.108545f * i + 1.709007f * q, gamma)); + + if (pass == 0) + myr = rt, myg = gt, myb = bt; + else { + float rscale = (float)rt / myr; + float gscale = (float)gt / myg; + float bscale = (float)bt / myb; + + if (myr != 0) *r = (uint8)(BCLAMP(*r * rscale)); + if (myg != 0) *g = (uint8)(BCLAMP(*g * gscale)); + if (myb != 0) *b = (uint8)(BCLAMP(*b * bscale)); + } + } +} + +#if 0 +static void ApplyDeemphasisClassic(int entry, uint8 *r, uint8 *g, uint8 *b) { + static const float rtmul[] = { 1.239f, 0.794f, 1.019f, 0.905f, 1.023f, 0.741f, 0.75f }; + static const float gtmul[] = { 0.915f, 1.086f, 0.98f, 1.026f, 0.908f, 0.987f, 0.75f }; + static const float btmul[] = { 0.743f, 0.882f, 0.653f, 1.277f, 0.979f, 0.101f, 0.75f }; + + int nr, ng, nb, d; + int deemph_bits = entry >> 6; + + if (deemph_bits == 0) return; + + d = deemph_bits - 1; + nr = *r; + ng = *g; + nb = *b; + nr = (int)(nr * rtmul[d]); + ng = (int)(ng * gtmul[d]); + nb = (int)(nb * btmul[d]); + if (nr > 0xFF) nr = 0xFF; + if (ng > 0xFF) ng = 0xFF; + if (nb > 0xFF) nb = 0xFF; + *r = (uint8)nr; + *g = (uint8)ng; + *b = (uint8)nb; +} +#endif + +static void ApplyDeemphasisComplete(pal *pal512) { + int i, p, idx; + + /* for each deemph level beyond 0 */ + for (i = 0, idx = 0; i < 8; i++) { + /* for each palette entry */ + for (p = 0; p < 64; p++, idx++) { + pal512[idx] = pal512[p]; + ApplyDeemphasisBisqwit(idx, &pal512[idx].r, &pal512[idx].g, &pal512[idx].b); } } +} + +void FCEUI_SetPaletteUser(pal *data, int nEntries) { + if (!data || !nEntries) + palette_user_available = FALSE; + else { + memcpy(palette_user, data, nEntries * 3); + if (nEntries != PALETTE_ARRAY_SIZE) ApplyDeemphasisComplete(palette_user); + palette_user_available = TRUE; + } FCEU_ResetPalette(); } @@ -124,14 +259,12 @@ void SetNESDeemph(uint8 d, int force) { lastd = d; } -int ipalette = 0; - void FCEU_LoadGamePalette(void) { - uint8 ptmp[192]; + uint8 ptmp[64 * 8 * 3] = {0}; RFILE *fp = NULL; char *fn = NULL; - ipalette = 0; + palette_game_available = 0; fn = FCEU_MakeFName(FCEUMKF_PALETTE, 0, 0); @@ -141,15 +274,14 @@ void FCEU_LoadGamePalette(void) { RETRO_VFS_FILE_ACCESS_HINT_NONE); if (fp) { - int x; - filestream_read(fp, ptmp, 192); + int64 readed = filestream_read(fp, ptmp, 64 * 8 * 3); + int nEntries = readed / 3; filestream_close(fp); - for (x = 0; x < 64; x++) { - palettei[x].r = ptmp[x + x + x]; - palettei[x].g = ptmp[x + x + x + 1]; - palettei[x].b = ptmp[x + x + x + 2]; - } - ipalette = 1; + + memcpy(palette_game, ptmp, readed); + if (nEntries != PALETTE_ARRAY_SIZE) ApplyDeemphasisComplete(palette_game); + + palette_game_available = 1; } free(fn); } @@ -162,23 +294,30 @@ void FCEU_ResetPalette(void) { } static void ChoosePalette(void) { - if (GameInfo->type == GIT_NSF) - palo = 0; - else if (ipalette) - palo = palettei; - else - palo = palpoint[pale]; + if (GameInfo->type == GIT_NSF) { + palo = palette_nes_default[0]; + } else if (palette_user_available) { + palo = palette_user; + } else if (palette_game_available) { + palo = palette_game; + } else { + palo = palette_nes_default[palette_nes_selected]; + ApplyDeemphasisComplete(palo); + } } -void WritePalette(void) { +static void WritePalette(void) { int x; + int unvaried = sizeof(unvpalette) / sizeof(unvpalette[0]); - for (x = 0; x < 7; x++) + for (x = 0; x < unvaried; x++) FCEUD_SetPalette(x, unvpalette[x].r, unvpalette[x].g, unvpalette[x].b); - if (GameInfo->type == GIT_NSF) { - } else { - for (x = 0; x < 64; x++) - FCEUD_SetPalette(128 + x, palo[x].r, palo[x].g, palo[x].b); - SetNESDeemph(lastd, 1); + for (x = unvaried; x < 256; x++) + FCEUD_SetPalette(x, 205, 205, 205); + for (x = 0; x < 64; x++) + FCEUD_SetPalette(128 + x, palo[x].r, palo[x].g, palo[x].b); + SetNESDeemph(lastd, 1); + for (x = 0; x < PALETTE_ARRAY_SIZE; x++) { + FCEUD_SetPaletteFull(x, palo[x].r, palo[x].g, palo[x].b); } } diff --git a/src/palette.h b/src/palette.h index a1bf2e8da..da46292ea 100644 --- a/src/palette.h +++ b/src/palette.h @@ -1,15 +1,25 @@ #ifndef _FCEU_PALETTE_H #define _FCEU_PALETTE_H + typedef struct { uint8 r, g, b; } pal; extern pal *palo; -extern int ipalette; -void FCEU_ResetPalette(void); +extern int palette_nes_selected; +void FCEU_ResetPalette(void); void FCEU_ResetPalette(void); void FCEU_LoadGamePalette(void); +#define PALETTE_ARRAY_SIZE 512 /* rgb palette size */ + +#define PAL_NES_DEFAULT 0 +#define PAL_RP2C04_0001 1 +#define PAL_RP2C04_0002 2 +#define PAL_RP2C04_0003 3 +#define PAL_RP2C04_0004 4 +#define PAL_RP2C03 5 + #endif diff --git a/src/palettes/palettes.h b/src/palettes/palettes.h index 6bf38be1b..cebc00b9c 100644 --- a/src/palettes/palettes.h +++ b/src/palettes/palettes.h @@ -1,97 +1,114 @@ -pal rp2c04_0001[64] = { - #include "rp2c04-0001.h" +#define EMPTY_PALETTE_1 { 0, 0, 0}, +#define EMPTY_PALETTE_4 EMPTY_PALETTE_1 EMPTY_PALETTE_1 EMPTY_PALETTE_1 EMPTY_PALETTE_1 +#define EMPTY_PALETTE_16 EMPTY_PALETTE_4 EMPTY_PALETTE_4 EMPTY_PALETTE_4 EMPTY_PALETTE_4 +#define EMPTY_PALETTE_64 EMPTY_PALETTE_16 EMPTY_PALETTE_16 EMPTY_PALETTE_16 EMPTY_PALETTE_16 +#define EMPTY_PALETTE_DEEMPH_X_7 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 + +pal rp2c04_0001[PALETTE_ARRAY_SIZE] = { + #include "rp2c04-0001.h" + EMPTY_PALETTE_DEEMPH_X_7 }; -pal rp2c04_0002[64] = { - #include "rp2c04-0002.h" +pal rp2c04_0002[PALETTE_ARRAY_SIZE] = { + #include "rp2c04-0002.h" + EMPTY_PALETTE_DEEMPH_X_7 }; -pal rp2c04_0003[64] = { - #include "rp2c04-0003.h" +pal rp2c04_0003[PALETTE_ARRAY_SIZE] = { + #include "rp2c04-0003.h" + EMPTY_PALETTE_DEEMPH_X_7 }; -pal rp2c04_0004[64] = { - #include "rp2c04-0004.h" + +pal rp2c04_0004[PALETTE_ARRAY_SIZE] = { + #include "rp2c04-0004.h" + EMPTY_PALETTE_DEEMPH_X_7 }; -pal rp2c03[64] = { - #include "rp2c03.h" +pal rp2c03[PALETTE_ARRAY_SIZE] = { + #include "rp2c03.h" + EMPTY_PALETTE_DEEMPH_X_7 }; pal unvpalette[7] = { - { 0x00 << 2, 0x00 << 2, 0x00 << 2 }, /* Black */ - { 0x3F << 2, 0x3F << 2, 0x34 << 2 }, /* White */ - { 0x00 << 2, 0x00 << 2, 0x00 << 2 }, /* Black */ - { 0x1d << 2, 0x1d << 2, 0x24 << 2 }, /* Greyish */ - { 190, 0, 0 }, /* Redish */ - { 51, 255, 51 }, /* Bright green */ - { 49, 14, 200 }, + { 0x00, 0x00, 0x00 }, /* 0 = Black */ + { 0xFF, 0xFF, 0xD3 }, /* 1 = White */ + { 0x00, 0x00, 0x00 }, /* 2 = Black */ + { 0x75, 0x75, 0x92 }, /* 3 = Greyish */ + { 0xBE, 0x00, 0x00 }, /* 4 = Reddish */ + { 0x33, 0xFF, 0x33 }, /* 5 = Bright green */ + { 0x31, 0x0E, 0xC8 } /* 6 = Ultramarine Blue */ }; +#define P64(x) (((x) << 2) | ((x >> 4) & 3)) /* Default palette */ -pal palette[64] = { - { 0x1D << 2, 0x1D << 2, 0x1D << 2 }, /* Value 0 */ - { 0x09 << 2, 0x06 << 2, 0x23 << 2 }, /* Value 1 */ - { 0x00 << 2, 0x00 << 2, 0x2A << 2 }, /* Value 2 */ - { 0x11 << 2, 0x00 << 2, 0x27 << 2 }, /* Value 3 */ - { 0x23 << 2, 0x00 << 2, 0x1D << 2 }, /* Value 4 */ - { 0x2A << 2, 0x00 << 2, 0x04 << 2 }, /* Value 5 */ - { 0x29 << 2, 0x00 << 2, 0x00 << 2 }, /* Value 6 */ - { 0x1F << 2, 0x02 << 2, 0x00 << 2 }, /* Value 7 */ - { 0x10 << 2, 0x0B << 2, 0x00 << 2 }, /* Value 8 */ - { 0x00 << 2, 0x11 << 2, 0x00 << 2 }, /* Value 9 */ - { 0x00 << 2, 0x14 << 2, 0x00 << 2 }, /* Value 10 */ - { 0x00 << 2, 0x0F << 2, 0x05 << 2 }, /* Value 11 */ - { 0x06 << 2, 0x0F << 2, 0x17 << 2 }, /* Value 12 */ - { 0x00 << 2, 0x00 << 2, 0x00 << 2 }, /* Value 13 */ - { 0x00 << 2, 0x00 << 2, 0x00 << 2 }, /* Value 14 */ - { 0x00 << 2, 0x00 << 2, 0x00 << 2 }, /* Value 15 */ - { 0x2F << 2, 0x2F << 2, 0x2F << 2 }, /* Value 16 */ - { 0x00 << 2, 0x1C << 2, 0x3B << 2 }, /* Value 17 */ - { 0x08 << 2, 0x0E << 2, 0x3B << 2 }, /* Value 18 */ - { 0x20 << 2, 0x00 << 2, 0x3C << 2 }, /* Value 19 */ - { 0x2F << 2, 0x00 << 2, 0x2F << 2 }, /* Value 20 */ - { 0x39 << 2, 0x00 << 2, 0x16 << 2 }, /* Value 21 */ - { 0x36 << 2, 0x0A << 2, 0x00 << 2 }, /* Value 22 */ - { 0x32 << 2, 0x13 << 2, 0x03 << 2 }, /* Value 23 */ - { 0x22 << 2, 0x1C << 2, 0x00 << 2 }, /* Value 24 */ - { 0x00 << 2, 0x25 << 2, 0x00 << 2 }, /* Value 25 */ - { 0x00 << 2, 0x2A << 2, 0x00 << 2 }, /* Value 26 */ - { 0x00 << 2, 0x24 << 2, 0x0E << 2 }, /* Value 27 */ - { 0x00 << 2, 0x20 << 2, 0x22 << 2 }, /* Value 28 */ - { 0x00 << 2, 0x00 << 2, 0x00 << 2 }, /* Value 29 */ - { 0x00 << 2, 0x00 << 2, 0x00 << 2 }, /* Value 30 */ - { 0x00 << 2, 0x00 << 2, 0x00 << 2 }, /* Value 31 */ - { 0x3F << 2, 0x3F << 2, 0x3F << 2 }, /* Value 32 */ - { 0x0F << 2, 0x2F << 2, 0x3F << 2 }, /* Value 33 */ - { 0x17 << 2, 0x25 << 2, 0x3F << 2 }, /* Value 34 */ - { 0x10 << 2, 0x22 << 2, 0x3F << 2 }, /* Value 35 */ - { 0x3D << 2, 0x1E << 2, 0x3F << 2 }, /* Value 36 */ - { 0x3F << 2, 0x1D << 2, 0x2D << 2 }, /* Value 37 */ - { 0x3F << 2, 0x1D << 2, 0x18 << 2 }, /* Value 38 */ - { 0x3F << 2, 0x26 << 2, 0x0E << 2 }, /* Value 39 */ - { 0x3C << 2, 0x2F << 2, 0x0F << 2 }, /* Value 40 */ - { 0x20 << 2, 0x34 << 2, 0x04 << 2 }, /* Value 41 */ - { 0x13 << 2, 0x37 << 2, 0x12 << 2 }, /* Value 42 */ - { 0x16 << 2, 0x3E << 2, 0x26 << 2 }, /* Value 43 */ - { 0x00 << 2, 0x3A << 2, 0x36 << 2 }, /* Value 44 */ - { 0x1E << 2, 0x1E << 2, 0x1E << 2 }, /* Value 45 */ - { 0x00 << 2, 0x00 << 2, 0x00 << 2 }, /* Value 46 */ - { 0x00 << 2, 0x00 << 2, 0x00 << 2 }, /* Value 47 */ - { 0x3F << 2, 0x3F << 2, 0x3F << 2 }, /* Value 48 */ - { 0x2A << 2, 0x39 << 2, 0x3F << 2 }, /* Value 49 */ - { 0x31 << 2, 0x35 << 2, 0x3F << 2 }, /* Value 50 */ - { 0x35 << 2, 0x32 << 2, 0x3F << 2 }, /* Value 51 */ - { 0x3F << 2, 0x31 << 2, 0x3F << 2 }, /* Value 52 */ - { 0x3F << 2, 0x31 << 2, 0x36 << 2 }, /* Value 53 */ - { 0x3F << 2, 0x2F << 2, 0x2C << 2 }, /* Value 54 */ - { 0x3F << 2, 0x36 << 2, 0x2A << 2 }, /* Value 55 */ - { 0x3F << 2, 0x39 << 2, 0x28 << 2 }, /* Value 56 */ - { 0x38 << 2, 0x3F << 2, 0x28 << 2 }, /* Value 57 */ - { 0x2A << 2, 0x3C << 2, 0x2F << 2 }, /* Value 58 */ - { 0x2C << 2, 0x3F << 2, 0x33 << 2 }, /* Value 59 */ - { 0x27 << 2, 0x3F << 2, 0x3C << 2 }, /* Value 60 */ - { 0x31 << 2, 0x31 << 2, 0x31 << 2 }, /* Value 61 */ - { 0x00 << 2, 0x00 << 2, 0x00 << 2 }, /* Value 62 */ - { 0x00 << 2, 0x00 << 2, 0x00 << 2 }, /* Value 63 */ +pal palette[PALETTE_ARRAY_SIZE] = { + { P64(0x1D), P64(0x1D), P64(0x1D) }, /* Value 0 */ + { P64(0x09), P64(0x06), P64(0x23) }, /* Value 1 */ + { P64(0x00), P64(0x00), P64(0x2A) }, /* Value 2 */ + { P64(0x11), P64(0x00), P64(0x27) }, /* Value 3 */ + { P64(0x23), P64(0x00), P64(0x1D) }, /* Value 4 */ + { P64(0x2A), P64(0x00), P64(0x04) }, /* Value 5 */ + { P64(0x29), P64(0x00), P64(0x00) }, /* Value 6 */ + { P64(0x1F), P64(0x02), P64(0x00) }, /* Value 7 */ + { P64(0x10), P64(0x0B), P64(0x00) }, /* Value 8 */ + { P64(0x00), P64(0x11), P64(0x00) }, /* Value 9 */ + { P64(0x00), P64(0x14), P64(0x00) }, /* Value 10 */ + { P64(0x00), P64(0x0F), P64(0x05) }, /* Value 11 */ + { P64(0x06), P64(0x0F), P64(0x17) }, /* Value 12 */ + { P64(0x00), P64(0x00), P64(0x00) }, /* Value 13 */ + { P64(0x00), P64(0x00), P64(0x00) }, /* Value 14 */ + { P64(0x00), P64(0x00), P64(0x00) }, /* Value 15 */ + { P64(0x2F), P64(0x2F), P64(0x2F) }, /* Value 16 */ + { P64(0x00), P64(0x1C), P64(0x3B) }, /* Value 17 */ + { P64(0x08), P64(0x0E), P64(0x3B) }, /* Value 18 */ + { P64(0x20), P64(0x00), P64(0x3C) }, /* Value 19 */ + { P64(0x2F), P64(0x00), P64(0x2F) }, /* Value 20 */ + { P64(0x39), P64(0x00), P64(0x16) }, /* Value 21 */ + { P64(0x36), P64(0x0A), P64(0x00) }, /* Value 22 */ + { P64(0x32), P64(0x13), P64(0x03) }, /* Value 23 */ + { P64(0x22), P64(0x1C), P64(0x00) }, /* Value 24 */ + { P64(0x00), P64(0x25), P64(0x00) }, /* Value 25 */ + { P64(0x00), P64(0x2A), P64(0x00) }, /* Value 26 */ + { P64(0x00), P64(0x24), P64(0x0E) }, /* Value 27 */ + { P64(0x00), P64(0x20), P64(0x22) }, /* Value 28 */ + { P64(0x00), P64(0x00), P64(0x00) }, /* Value 29 */ + { P64(0x00), P64(0x00), P64(0x00) }, /* Value 30 */ + { P64(0x00), P64(0x00), P64(0x00) }, /* Value 31 */ + { P64(0x3F), P64(0x3F), P64(0x3F) }, /* Value 32 */ + { P64(0x0F), P64(0x2F), P64(0x3F) }, /* Value 33 */ + { P64(0x17), P64(0x25), P64(0x3F) }, /* Value 34 */ + { P64(0x33), P64(0x22), P64(0x3F) }, /* Value 35 */ + { P64(0x3D), P64(0x1E), P64(0x3F) }, /* Value 36 */ + { P64(0x3F), P64(0x1D), P64(0x2D) }, /* Value 37 */ + { P64(0x3F), P64(0x1D), P64(0x18) }, /* Value 38 */ + { P64(0x3F), P64(0x26), P64(0x0E) }, /* Value 39 */ + { P64(0x3C), P64(0x2F), P64(0x0F) }, /* Value 40 */ + { P64(0x20), P64(0x34), P64(0x04) }, /* Value 41 */ + { P64(0x13), P64(0x37), P64(0x12) }, /* Value 42 */ + { P64(0x16), P64(0x3E), P64(0x26) }, /* Value 43 */ + { P64(0x00), P64(0x3A), P64(0x36) }, /* Value 44 */ + { P64(0x1E), P64(0x1E), P64(0x1E) }, /* Value 45 */ + { P64(0x00), P64(0x00), P64(0x00) }, /* Value 46 */ + { P64(0x00), P64(0x00), P64(0x00) }, /* Value 47 */ + { P64(0x3F), P64(0x3F), P64(0x3F) }, /* Value 48 */ + { P64(0x2A), P64(0x39), P64(0x3F) }, /* Value 49 */ + { P64(0x31), P64(0x35), P64(0x3F) }, /* Value 50 */ + { P64(0x35), P64(0x32), P64(0x3F) }, /* Value 51 */ + { P64(0x3F), P64(0x31), P64(0x3F) }, /* Value 52 */ + { P64(0x3F), P64(0x31), P64(0x36) }, /* Value 53 */ + { P64(0x3F), P64(0x2F), P64(0x2C) }, /* Value 54 */ + { P64(0x3F), P64(0x36), P64(0x2A) }, /* Value 55 */ + { P64(0x3F), P64(0x39), P64(0x28) }, /* Value 56 */ + { P64(0x38), P64(0x3F), P64(0x28) }, /* Value 57 */ + { P64(0x2A), P64(0x3C), P64(0x2F) }, /* Value 58 */ + { P64(0x2C), P64(0x3F), P64(0x33) }, /* Value 59 */ + { P64(0x27), P64(0x3F), P64(0x3C) }, /* Value 60 */ + { P64(0x31), P64(0x31), P64(0x31) }, /* Value 61 */ + { P64(0x00), P64(0x00), P64(0x00) }, /* Value 62 */ + { P64(0x00), P64(0x00), P64(0x00) }, /* Value 63 */ + + #undef P64 + + EMPTY_PALETTE_DEEMPH_X_7 }; diff --git a/src/ppu.c b/src/ppu.c index aa8f62f08..320d48519 100644 --- a/src/ppu.c +++ b/src/ppu.c @@ -33,10 +33,12 @@ #include "fceu-memory.h" #include "cart.h" +#include "ines.h" #include "palette.h" #include "state.h" #include "video.h" #include "input.h" +#include "gamegenie.h" #define VBlankON (PPU[0] & 0x80) /* Generate VBlank NMI */ #define Sprite16 (PPU[0] & 0x20) /* Sprites 8x16/8x8 */ @@ -44,18 +46,20 @@ #define SpAdrHI (PPU[0] & 0x08) /* Sprite pattern adr $0000/$1000 */ #define INC32 (PPU[0] & 0x04) /* auto increment 1/32 */ -#define SpriteON (PPU[1] & 0x10) /* Show Sprite */ -#define ScreenON (PPU[1] & 0x08) /* Show screen */ #define GRAYSCALE (PPU[1] & 0x01) /* Grayscale (AND palette entries with 0x30) */ +#define BGLeft8ON (PPU[1] & 0x02) /* show background in leftmost 8 pixels of screen. 0: hides */ +#define SpriteLeft8ON (PPU[1] & 0x04) /* show sprites in leftmost 8 pixels of screen. 0: hides */ +#define ScreenON (PPU[1] & 0x08) /* Show screen */ +#define SpriteON (PPU[1] & 0x10) /* Show Sprite */ #define PPU_status (PPU[2]) +#define Sprite0Hit (PPU_status & 0x40) -#define READPALNOGS(ofs) (PALRAM[(ofs)]) #define READPAL(ofs) (PALRAM[(ofs)] & (GRAYSCALE ? 0x30 : 0xFF)) #define READUPAL(ofs) (UPALRAM[(ofs)] & (GRAYSCALE ? 0x30 : 0xFF)) static void FetchSpriteData(void); -static void FASTAPASS(1) RefreshLine(int lastpixel); +static void RefreshLine(int lastpixel); static void RefreshSprites(void); static void CopySprites(uint8 *target); @@ -94,7 +98,7 @@ static uint8 ppudead = 1; static uint8 kook = 0; int fceuindbg = 0; -int MMC5Hack = 0, PEC586Hack = 0; +uint8 MMC5Hack = FALSE; uint32 MMC5HackVROMMask = 0; uint8 *MMC5HackExNTARAMPtr = 0; uint8 *MMC5HackVROMPTR = 0; @@ -104,6 +108,12 @@ uint8 MMC50x5130 = 0; uint8 MMC5HackSPScroll = 0; uint8 MMC5HackSPPage = 0; +uint8 PEC586Hack = 0; + +uint8 QTAIHack = FALSE; +uint8 qtramreg = 0; +uint8 QTRAM[0x800]; + uint8 VRAMBuffer = 0, PPUGenLatch = 0; uint8 *vnapage[4]; uint8 PPUNTARAM = 0; @@ -114,7 +124,7 @@ static uint8 deemp = 0; static int deempcnt[8]; void (*GameHBIRQHook)(void), (*GameHBIRQHook2)(void); -void FP_FASTAPASS(1) (*PPU_hook)(uint32 A); +void (*PPU_hook)(uint32 A); uint8 vtoggle = 0; uint8 XOffset = 0; @@ -138,7 +148,7 @@ uint8 UPALRAM[0x03];/* for 0x4/0x8/0xC addresses in palette, the ones in #define MMC5SPRVRAMADR(V) &MMC5SPRVPage[(V) >> 10][(V)] #define VRAMADR(V) &VPage[(V) >> 10][(V)] -uint8 * MMC5BGVRAMADR(uint32 V) { +static uint8 * MMC5BGVRAMADR(uint32 V) { if (!Sprite16) { extern uint8 mmc5ABMode; /* A=0, B=1 */ if (mmc5ABMode == 0) @@ -324,8 +334,12 @@ static DECLFW(B2007) { if (PPUCHRRAM & (1 << (tmp >> 10))) VPage[tmp >> 10][tmp] = V; } else if (tmp < 0x3F00) { - if (PPUNTARAM & (1 << ((tmp & 0xF00) >> 10))) - vnapage[((tmp & 0xF00) >> 10)][tmp & 0x3FF] = V; + if (QTAIHack && (qtramreg & 1)) { + QTRAM[((((tmp & 0xF00) >> 10) >> ((qtramreg >> 1)) & 1) << 10) | (tmp & 0x3FF)] = V; + } else { + if (PPUNTARAM & (1 << ((tmp & 0xF00) >> 10))) + vnapage[((tmp & 0xF00) >> 10)][tmp & 0x3FF] = V; + } } else { if (!(tmp & 3)) { if (!(tmp & 0xC)) @@ -351,9 +365,7 @@ static DECLFW(B4014) { X6502_DMW(0x2004, X6502_DMR(t + x)); } -#define PAL(c) ((c) + cc) - -#define GETLASTPIXEL (PAL ? ((timestamp * 48 - linestartts) / 15) : ((timestamp * 48 - linestartts) >> 4)) +#define GETLASTPIXEL (isPAL ? ((timestamp * 48 - linestartts) / 15) : ((timestamp * 48 - linestartts) >> 4)) static uint8 *Pline, *Plinef; static int firsttile; @@ -362,12 +374,11 @@ static int tofix = 0; static void ResetRL(uint8 *target) { memset(target, 0xFF, 256); - if (InputScanlineHook) - InputScanlineHook(0, 0, 0, 0); + InputScanlineHook(0, 0, 0, 0); Plinef = target; Pline = target; firsttile = 0; - linestartts = timestamp * 48 + X.count; + linestartts = timestamp * 48 + cpu.count; tofix = 0; FCEUPPU_LineUpdate(); tofix = 1; @@ -385,17 +396,17 @@ void FCEUPPU_LineUpdate(void) { } } -static int rendis = 0; +static int show_sprites = 1; +static int show_background = 1; -void FCEUI_SetRenderDisable(int sprites, int bg) { - if (sprites >= 0) { - if (sprites == 2) rendis ^= 1; - else rendis = (rendis & ~1) | sprites ? 1 : 0; - } - if (bg >= 0) { - if (bg == 2) rendis ^= 2; - else rendis = (rendis & ~2) | bg ? 2 : 0; - } +void FCEUI_SetRenderPlanes(int sprites, int bg) { + show_sprites = sprites; + show_background = bg; +} + +void FCEUI_GetRenderPlanes(int *sprites, int *bg) { + *sprites = show_sprites; + *bg = show_background; } static void CheckSpriteHit(int p); @@ -432,7 +443,7 @@ static void CheckSpriteHit(int p) { static int spork = 0; /* lasttile is really "second to last tile." */ -static void FASTAPASS(1) RefreshLine(int lastpixel) { +static void RefreshLine(int lastpixel) { static uint32 pshift[2]; static uint32 atlatch; uint32 smorkus = RefreshAddr; @@ -441,7 +452,7 @@ static void FASTAPASS(1) RefreshLine(int lastpixel) { uint32 vofs; int X1; - register uint8 *P = Pline; + uint8 *P = Pline; int lasttile = lastpixel >> 3; int numtiles; static int norecurse = 0; /* Yeah, recursion would be bad. @@ -452,7 +463,7 @@ static void FASTAPASS(1) RefreshLine(int lastpixel) { */ if (norecurse) return; - if (sphitx != 0x100 && !(PPU_status & 0x40)) { + if (sphitx != 0x100 && !Sprite0Hit) { if ((sphitx < (lastpixel - 16)) && !(sphitx < ((lasttile - 2) * 8))) lasttile++; } @@ -473,7 +484,7 @@ static void FASTAPASS(1) RefreshLine(int lastpixel) { if (!ScreenON && !SpriteON) { uint32 tem; - tem = READPALNOGS(0) | (READPALNOGS(0) << 8) | (READPALNOGS(0) << 16) | (READPALNOGS(0) << 24); + tem = READPAL(0) | (READPAL(0) << 8) | (READPAL(0) << 16) | (READPAL(0) << 24); tem |= 0x40404040; FCEU_dwmemset(Pline, tem, numtiles * 8); P += numtiles * 8; @@ -487,7 +498,7 @@ static void FASTAPASS(1) RefreshLine(int lastpixel) { tofix = 0; } - if (InputScanlineHook && (lastpixel - 16) >= 0) { + if ((lastpixel - 16) >= 0) { InputScanlineHook(Plinef, spork ? sprlinebuf : 0, linestartts, lasttile * 8 - 16); } return; @@ -562,6 +573,12 @@ static void FASTAPASS(1) RefreshLine(int lastpixel) { #include "pputile.h" } #undef PPU_BGFETCH + } else if (QTAIHack) { + #define PPU_VRC5FETCH + for (X1 = firsttile; X1 < lasttile; X1++) { + #include "pputile.h" + } + #undef PPU_VRC5FETCH } else { for (X1 = firsttile; X1 < lasttile; X1++) { #include "pputile.h" @@ -579,9 +596,9 @@ static void FASTAPASS(1) RefreshLine(int lastpixel) { PALRAM[0xC] &= 63; RefreshAddr = smorkus; - if (firsttile <= 2 && 2 < lasttile && !(PPU[1] & 2)) { + if (firsttile <= 2 && 2 < lasttile && !BGLeft8ON) { uint32 tem; - tem = READPALNOGS(0) | (READPALNOGS(0) << 8) | (READPALNOGS(0) << 16) | (READPALNOGS(0) << 24); + tem = READPAL(0) | (READPAL(0) << 8) | (READPAL(0) << 16) | (READPAL(0) << 24); tem |= 0x40404040; *(uint32*)Plinef = *(uint32*)(Plinef + 4) = tem; } @@ -589,7 +606,7 @@ static void FASTAPASS(1) RefreshLine(int lastpixel) { if (!ScreenON) { uint32 tem; int tstart, tcount; - tem = READPALNOGS(0) | (READPALNOGS(0) << 8) | (READPALNOGS(0) << 16) | (READPALNOGS(0) << 24); + tem = READPAL(0) | (READPAL(0) << 8) | (READPAL(0) << 16) | (READPAL(0) << 24); tem |= 0x40404040; tcount = lasttile - firsttile; @@ -610,7 +627,7 @@ static void FASTAPASS(1) RefreshLine(int lastpixel) { /* This only works right because of a hack earlier in this function. */ CheckSpriteHit(lastpixel); - if (InputScanlineHook && (lastpixel - 16) >= 0) { + if ((lastpixel - 16) >= 0) { InputScanlineHook(Plinef, spork ? sprlinebuf : 0, linestartts, lasttile * 8 - 16); } Pline = P; @@ -662,14 +679,14 @@ static void DoLine(void) target = XBuf + ((scanline < 240 ? scanline : 240) << 8); dtarget = XDBuf + ((scanline < 240 ? scanline : 240) << 8); - if (MMC5Hack && (ScreenON || SpriteON)) MMC5_hb(scanline); + if (MMC5Hack /* && (ScreenON || SpriteON) */) MMC5_hb(scanline); X6502_Run(256); EndRL(); - if (rendis & 2) {/* User asked to not display background data. */ + if (!show_background) {/* User asked to not display background data. */ uint32 tem; - tem = READPALNOGS(0) | (READPALNOGS(0) << 8) | (READPALNOGS(0) << 16) | (READPALNOGS(0) << 24); + tem = READPAL(0) | (READPAL(0) << 8) | (READPAL(0) << 16) | (READPAL(0) << 24); tem |= 0x40404040; FCEU_dwmemset(target, tem, 256); } @@ -890,19 +907,19 @@ static void RefreshSprites(void) { spr = (SPRB*)SPRBUF + numsprites; for (n = numsprites; n >= 0; n--, spr--) { - register uint32 pixdata; - register uint8 J, atr; + uint32 pixdata; + uint8 J, atr; int x = spr->x; uint8 *C; - uint8 *VB; + int VB; pixdata = ppulut1[spr->ca[0]] | ppulut2[spr->ca[1]]; J = spr->ca[0] | spr->ca[1]; atr = spr->atr; if (J) { - if (n == 0 && SpriteBlurp && !(PPU_status & 0x40)) { + if (n == 0 && SpriteBlurp && !Sprite0Hit) { sphitx = x; sphitdata = J; if (atr & H_FLIP) @@ -917,75 +934,75 @@ static void RefreshSprites(void) { } C = sprlinebuf + x; - VB = (PALRAM + 0x10) + ((atr & 3) << 2); + VB = 0x10 + ((atr & 3) << 2); if (atr & SP_BACK) { if (atr & H_FLIP) { - if (J & 0x80) C[7] = VB[pixdata & 3] | 0x40; + if (J & 0x80) C[7] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x40) C[6] = VB[pixdata & 3] | 0x40; + if (J & 0x40) C[6] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x20) C[5] = VB[pixdata & 3] | 0x40; + if (J & 0x20) C[5] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x10) C[4] = VB[pixdata & 3] | 0x40; + if (J & 0x10) C[4] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x08) C[3] = VB[pixdata & 3] | 0x40; + if (J & 0x08) C[3] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x04) C[2] = VB[pixdata & 3] | 0x40; + if (J & 0x04) C[2] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x02) C[1] = VB[pixdata & 3] | 0x40; + if (J & 0x02) C[1] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x01) C[0] = VB[pixdata] | 0x40; + if (J & 0x01) C[0] = READPAL(VB | pixdata) | 0x40; } else { - if (J & 0x80) C[0] = VB[pixdata & 3] | 0x40; + if (J & 0x80) C[0] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x40) C[1] = VB[pixdata & 3] | 0x40; + if (J & 0x40) C[1] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x20) C[2] = VB[pixdata & 3] | 0x40; + if (J & 0x20) C[2] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x10) C[3] = VB[pixdata & 3] | 0x40; + if (J & 0x10) C[3] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x08) C[4] = VB[pixdata & 3] | 0x40; + if (J & 0x08) C[4] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x04) C[5] = VB[pixdata & 3] | 0x40; + if (J & 0x04) C[5] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x02) C[6] = VB[pixdata & 3] | 0x40; + if (J & 0x02) C[6] = READPAL(VB | (pixdata & 3)) | 0x40; pixdata >>= 4; - if (J & 0x01) C[7] = VB[pixdata] | 0x40; + if (J & 0x01) C[7] = READPAL(VB | pixdata) | 0x40; } } else { if (atr & H_FLIP) { - if (J & 0x80) C[7] = VB[pixdata & 3]; + if (J & 0x80) C[7] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x40) C[6] = VB[pixdata & 3]; + if (J & 0x40) C[6] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x20) C[5] = VB[pixdata & 3]; + if (J & 0x20) C[5] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x10) C[4] = VB[pixdata & 3]; + if (J & 0x10) C[4] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x08) C[3] = VB[pixdata & 3]; + if (J & 0x08) C[3] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x04) C[2] = VB[pixdata & 3]; + if (J & 0x04) C[2] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x02) C[1] = VB[pixdata & 3]; + if (J & 0x02) C[1] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x01) C[0] = VB[pixdata]; + if (J & 0x01) C[0] = READPAL(VB | pixdata); } else { - if (J & 0x80) C[0] = VB[pixdata & 3]; + if (J & 0x80) C[0] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x40) C[1] = VB[pixdata & 3]; + if (J & 0x40) C[1] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x20) C[2] = VB[pixdata & 3]; + if (J & 0x20) C[2] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x10) C[3] = VB[pixdata & 3]; + if (J & 0x10) C[3] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x08) C[4] = VB[pixdata & 3]; + if (J & 0x08) C[4] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x04) C[5] = VB[pixdata & 3]; + if (J & 0x04) C[5] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x02) C[6] = VB[pixdata & 3]; + if (J & 0x02) C[6] = READPAL(VB | (pixdata & 3)); pixdata >>= 4; - if (J & 0x01) C[7] = VB[pixdata]; + if (J & 0x01) C[7] = READPAL(VB | pixdata); } } } @@ -995,13 +1012,15 @@ static void RefreshSprites(void) { } static void CopySprites(uint8 *target) { - uint8 n = ((PPU[1] & 4) ^ 4) << 1; + uint8 n = SpriteLeft8ON ? 0 : 8; uint8 *P = target; if (!spork) return; spork = 0; - if (rendis & 1) return; /* User asked to not display sprites. */ + if (!show_sprites) return; /* User asked to not display sprites. */ + + if(!SpriteON) return; do { @@ -1057,7 +1076,7 @@ static void CopySprites(uint8 *target) { void FCEUPPU_SetVideoSystem(int w) { if (w) { - scanlines_per_frame = dendy ? 262 : 312; + scanlines_per_frame = isDendy ? 262 : 312; FSettings.FirstSLine = FSettings.UsrFirstSLine[1]; FSettings.LastSLine = FSettings.UsrLastSLine[1]; } else { @@ -1084,11 +1103,21 @@ void FCEUPPU_Reset(void) { void FCEUPPU_Power(void) { int x; - memset(NTARAM, 0x00, 0x800); - memset(PALRAM, 0x00, 0x20); - memset(UPALRAM, 0x00, 0x03); - memset(SPRAM, 0x00, 0x100); + /* initialize PPU memory regions according to settings */ + FCEU_MemoryRand(NTARAM, 0x800); + FCEU_MemoryRand(PALRAM, 0x20); + FCEU_MemoryRand(SPRAM, 0x100); + + /* palettes can only store values up to $3F, and PALRAM X4/X8/XC are mirrors of X0 for rendering purposes (UPALRAM is used for $2007 readback)*/ + for (x = 0; x < 0x20; ++x) PALRAM[x] &= 0x3F; + UPALRAM[0] = PALRAM[0x04]; + UPALRAM[1] = PALRAM[0x08]; + UPALRAM[2] = PALRAM[0x0C]; + PALRAM[0x0C] = PALRAM[0x08] = PALRAM[0x04] = PALRAM[0x00]; + PALRAM[0x1C] = PALRAM[0x18] = PALRAM[0x14] = PALRAM[0x10]; + FCEUPPU_Reset(); + for (x = 0x2000; x < 0x4000; x += 8) { ARead[x] = A200x; BWrite[x] = B2000; @@ -1137,11 +1166,11 @@ int FCEUPPU_Loop(int skip) { TriggerNMI(); } X6502_Run((scanlines_per_frame - 242) * (256 + 85) - 12); - if (ppu.overclock_enabled && ppu.vblankscanlines) { - if (!DMC_7bit || !ppu.skip_7bit_overclocking) { - ppu.overclocked = 1; - X6502_Run(ppu.vblankscanlines * (256 + 85) - 12); - ppu.overclocked = 0; + if (FSettings.PPUOverclockEnabled && ppu.overclock.vblank_scanlines) { + if (!ppu.overclock.DMC_7bit_in_use || !FSettings.SkipDMC7BitOverclock) { + ppu.overclock.overclocked_state = 1; + X6502_Run(ppu.overclock.vblank_scanlines * (256 + 85) - 12); + ppu.overclock.overclocked_state = 0; } } PPU_status &= 0x1f; @@ -1153,10 +1182,11 @@ int FCEUPPU_Loop(int skip) { if (ScreenON || SpriteON) { if (GameHBIRQHook && ((PPU[0] & 0x38) != 0x18)) GameHBIRQHook(); - if (PPU_hook) + if (PPU_hook) { for (x = 0; x < 42; x++) { PPU_hook(0x2000); PPU_hook(0); } + } if (GameHBIRQHook2) GameHBIRQHook2(); } @@ -1205,25 +1235,25 @@ int FCEUPPU_Loop(int skip) { deemp = PPU[1] >> 5; /* manual samples can't play correctly with overclocking */ - if (DMC_7bit && ppu.skip_7bit_overclocking) + if (ppu.overclock.DMC_7bit_in_use && FSettings.SkipDMC7BitOverclock) ppu.totalscanlines = ppu.normal_scanlines; else - ppu.totalscanlines = ppu.normal_scanlines + (ppu.overclock_enabled ? ppu.extrascanlines : 0); + ppu.totalscanlines = ppu.normal_scanlines + (FSettings.PPUOverclockEnabled ? ppu.overclock.postrender_scanlines : 0); for (scanline = 0; scanline < ppu.totalscanlines; ) { /* scanline is incremented in DoLine. Evil. :/ */ deempcnt[deemp]++; DoLine(); if (scanline < ppu.normal_scanlines || scanline == ppu.totalscanlines) - ppu.overclocked = 0; + ppu.overclock.overclocked_state = 0; else { - if (DMC_7bit && ppu.skip_7bit_overclocking) /* 7bit sample started after 240th line */ + if (ppu.overclock.DMC_7bit_in_use && FSettings.SkipDMC7BitOverclock) /* 7bit sample started after 240th line */ break; - ppu.overclocked = 1; + ppu.overclock.overclocked_state = 1; } } - DMC_7bit = 0; - if (MMC5Hack && (ScreenON || SpriteON)) MMC5_hb(scanline); + ppu.overclock.DMC_7bit_in_use = 0; + if (MMC5Hack /*&& (ScreenON || SpriteON)*/) MMC5_hb(scanline); for (x = 1, max = 0, maxref = 0; x < 7; x++) { if (deempcnt[x] > max) { max = deempcnt[x]; diff --git a/src/ppu.h b/src/ppu.h index ca6ba0b1e..bff4e2498 100644 --- a/src/ppu.h +++ b/src/ppu.h @@ -5,13 +5,14 @@ typedef struct { /* overclock the console by adding dummy scanlines to PPU loop * disables DMC DMA and WaveHi filling for these dummies * doesn't work with new PPU */ - int overclock_enabled; - int overclocked; - int skip_7bit_overclocking; - int totalscanlines; - int normal_scanlines; - int extrascanlines; - int vblankscanlines; + struct { + uint8 overclocked_state; /* ppu in overclock state? stops sound from running in overclocked state */ + uint8 DMC_7bit_in_use; /* DMC in use */ + uint16 vblank_scanlines; + uint16 postrender_scanlines; + } overclock; + uint16 totalscanlines; + uint16 normal_scanlines; } PPU_T; extern PPU_T ppu; @@ -25,7 +26,7 @@ void FCEUPPU_LineUpdate(void); void FCEUPPU_SetVideoSystem(int w); extern void (*GameHBIRQHook)(void), (*GameHBIRQHook2)(void); -extern void FP_FASTAPASS(1) (*PPU_hook)(uint32 A); +extern void (*PPU_hook)(uint32 A); /* For cart.c and banksw.h, mostly */ extern uint8 NTARAM[0x800], *vnapage[4]; diff --git a/src/pputile.h b/src/pputile.h index dbf7e5447..a40293314 100644 --- a/src/pputile.h +++ b/src/pputile.h @@ -1,10 +1,12 @@ uint8 *C; uint8 cc; uint32 vadr; +#ifdef PPU_VRC5FETCH +uint8 tmpd; +#endif #ifndef PPUT_MMC5SP - uint8 zz; - FCEU_MAYBE_UNUSED(zz); + FCEU_MAYBE_UNUSED uint8 zz; #else uint8 xs, ys; xs = X1; @@ -43,7 +45,11 @@ if (X1 >= 2) { #else zz = RefreshAddr & 0x1F; C = vnapage[(RefreshAddr >> 10) & 3]; - vadr = (C[RefreshAddr & 0x3ff] << 4) + vofs; /* Fetch name table byte. */ +#ifdef PPU_VRC5FETCH + tmpd = QTRAM[((((RefreshAddr >> 10) & 3) >> ((qtramreg >> 1)) & 1) << 10) | (RefreshAddr & 0x3FF)]; + vofs = ((tmpd & 0x3F) << 12) | ((RefreshAddr >> 12) & 7); /* recalculate VROM offset */ +#endif + vadr = (C[RefreshAddr & 0x3ff] << 4) + vofs; /* Fetch name table byte. */ #endif #ifdef PPUT_HOOK @@ -75,12 +81,25 @@ pshift[1] <<= 8; #ifdef PPUT_MMC5CHR1 C = MMC5HackVROMPTR; C += (((MMC5HackExNTARAMPtr[RefreshAddr & 0x3ff]) & 0x3f & MMC5HackVROMMask) << 12) + (vadr & 0xfff); - C += (MMC50x5130 & 0x3) << 18; + C += (MMC50x5130 & 0x3) << 18; /* 11-jun-2009 for kuja_killer */ #elif defined(PPUT_MMC5) C = MMC5BGVRAMADR(vadr); + #else + + #ifdef PPU_VRC5FETCH + if (tmpd & 0x40) { + if ((ROM.chr.size * 8) == 128) { + vadr = ((vadr & 0x07) << 1) | ((vadr & 0x10) >> 4) | ((vadr & 0x3FFE0) >> 1); + } + C = &ROM.chr.data[vadr]; + } else { + C = VRAMADR(vadr); + } #else C = VRAMADR(vadr); #endif + + #endif #endif #ifdef PPUT_HOOK @@ -96,8 +115,16 @@ pshift[1] <<= 8; pshift[1] |= C[0]; } #else + #ifdef PPU_VRC5FETCH + pshift[0] |= C[0]; + if (tmpd & 0x40) + pshift[1] |= (tmpd & 0x80) ? 0xFF : 0x00; + else + pshift[1] |= C[8]; + #else pshift[0] |= C[0]; pshift[1] |= C[8]; + #endif #endif if ((RefreshAddr & 0x1f) == 0x1f) diff --git a/src/sound.c b/src/sound.c index 419fcca5d..b192335a1 100644 --- a/src/sound.c +++ b/src/sound.c @@ -29,6 +29,10 @@ #include "sound.h" #include "filter.h" #include "state.h" +#include "ppu.h" + +#define SQ_SHIFT 24 +#define TRINPCM_SHIFT 16 static uint32 wlookup1[32]; static uint32 wlookup2[203]; @@ -37,7 +41,16 @@ int32 Wave[2048 + 512]; int32 WaveHi[40000]; int32 WaveFinal[2048 + 512]; -EXPSOUND GameExpSound = { 0, 0, 0, 0, 0, 0 }; +/* FIXME: Very ugly hack and only relevant in multichip NSF playback */ +/* Indexing is based on sound channel enum */ +EXPSOUND GameExpSound[GAMEEXPSOUND_COUNT] = { + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, +}; static uint8 TriCount = 0; static uint8 TriMode = 0; @@ -52,15 +65,6 @@ static uint8 RawDALatch = 0; /* $4011 0xxxxxxx */ uint8 EnabledChannels = 0; /* Byte written to $4015 */ -typedef struct { - uint8 Speed; - uint8 Mode; /* Fixed volume(1), and loop(2) */ - uint8 DecCountTo1; - uint8 decvolume; - int reloaddec; -} ENVUNIT; - -unsigned DMC_7bit = 0; /* used to skip overclocking */ static ENVUNIT EnvUnits[3]; static const int RectDuties[4] = { 1, 2, 4, 6 }; @@ -70,6 +74,8 @@ static uint8 sweepon[2]; static int32 curfreq[2]; static uint8 SweepCount[2]; static uint8 sweepReload[2]; +static uint8 sweepShift[2]; +static uint8 sweepPeriod[2]; static uint16 nreg = 0; @@ -82,7 +88,6 @@ uint32 soundtsoffs = 0; /* Variables exclusively for low-quality sound. */ int32 nesincsize = 0; uint32 soundtsinc = 0; -uint32 soundtsi = 0; static int32 sqacc[2]; static uint32 lq_tcout; static int32 lq_triacc; @@ -154,32 +159,35 @@ static void (*DoSQ2)(void) = Dummyfunc; static uint32 ChannelBC[5]; static void LoadDMCPeriod(uint8 V) { - if (PAL) + if (isPAL) { DMCPeriod = PALDMCTable[V]; - else + } else { DMCPeriod = NTSCDMCTable[V]; + } } -static void PrepDPCM() { +static void PrepDPCM(void) { DMCAddress = 0x4000 + (DMCAddressLatch << 6); DMCSize = (DMCSizeLatch << 4) + 1; } /* Instantaneous? Maybe the new freq value is being calculated all of the time... */ -static int FASTAPASS(2) CheckFreq(uint32 cf, uint8 sr) { +static int CheckFreq(uint32 cf, uint8 sr) { uint32 mod; if (!(sr & 0x8)) { mod = cf >> (sr & 7); - if ((mod + cf) & 0x800) - return(0); + if ((mod + cf) & 0x800) { + return 0; + } } - return(1); + return 1; } static void SQReload(int x, uint8 V) { - if (EnabledChannels & (1 << x)) + if (EnabledChannels & (1 << x)) { lengthcount[x] = lengthtable[(V >> 3) & 0x1f]; + } curfreq[x] = (curfreq[x] & 0xff) | ((V & 7) << 8); RectDutyCount[x] = 7; @@ -188,84 +196,95 @@ static void SQReload(int x, uint8 V) { static DECLFW(Write_PSG) { A &= 0x1F; + switch (A) { case 0x0: DoSQ1(); EnvUnits[0].Mode = (V & 0x30) >> 4; EnvUnits[0].Speed = (V & 0xF); - if (swapDuty) + if (FSettings.SwapDutyCycles) { V = (V & 0x3F) | ((V & 0x80) >> 1) | ((V & 0x40) << 1); + } break; + case 0x1: DoSQ1(); sweepReload[0] = 1; - sweepon[0] = (V & 0x80); + sweepShift[0] = V & 0x07; + sweepPeriod[0] = ((V >> 4) & 0x7) + 1; + sweepon[0] = (V & 0x80) && sweepShift[0]; break; + case 0x2: DoSQ1(); curfreq[0] &= 0xFF00; curfreq[0] |= V; break; + case 0x3: DoSQ1(); SQReload(0, V); break; + case 0x4: DoSQ2(); EnvUnits[1].Mode = (V & 0x30) >> 4; EnvUnits[1].Speed = (V & 0xF); - if (swapDuty) + if (FSettings.SwapDutyCycles) { V = (V & 0x3F) | ((V & 0x80) >> 1) | ((V & 0x40) << 1); + } break; + case 0x5: DoSQ2(); sweepReload[1] = 1; - sweepon[1] = (V & 0x80); + sweepShift[1] = V & 0x07; + sweepPeriod[1] = ((V >> 4) & 0x7) + 1; + sweepon[1] = (V & 0x80) && sweepShift[1]; break; + case 0x6: DoSQ2(); curfreq[1] &= 0xFF00; curfreq[1] |= V; break; + case 0x7: DoSQ2(); SQReload(1, V); break; + case 0xa: DoTriangle(); break; + case 0xb: DoTriangle(); - if (EnabledChannels & 0x4) + if (EnabledChannels & 0x4) { lengthcount[2] = lengthtable[(V >> 3) & 0x1f]; + } TriMode = 1; /* Load mode */ break; + case 0xC: DoNoise(); EnvUnits[2].Mode = (V & 0x30) >> 4; EnvUnits[2].Speed = (V & 0xF); break; + case 0xE: DoNoise(); break; + case 0xF: DoNoise(); - if (EnabledChannels & 0x8) + if (EnabledChannels & 0x8) { lengthcount[3] = lengthtable[(V >> 3) & 0x1f]; - EnvUnits[2].reloaddec = 1; - break; - case 0x10: - DoPCM(); - LoadDMCPeriod(V & 0xF); - - if (SIRQStat & 0x80) { - if (!(V & 0x80)) { - X6502_IRQEnd(FCEU_IQDPCM); - SIRQStat &= ~0x80; - } else X6502_IRQBegin(FCEU_IQDPCM); } + EnvUnits[2].reloaddec = 1; break; } + PSG[A] = V; } @@ -273,31 +292,38 @@ static DECLFW(Write_DMCRegs) { A &= 0xF; switch (A) { - case 0x00: DoPCM(); + case 0x00: + DoPCM(); LoadDMCPeriod(V & 0xF); if (SIRQStat & 0x80) { - if (!(V & 0x80)) { + if ((V & 0xC0) != 0x80) { X6502_IRQEnd(FCEU_IQDPCM); SIRQStat &= ~0x80; - } else X6502_IRQBegin(FCEU_IQDPCM); + } } DMCFormat = V; break; + case 0x01: DoPCM(); RawDALatch = V & 0x7F; - if (RawDALatch) - DMC_7bit = 1; + if ((GameInfo->type != GIT_NSF) && FSettings.PPUOverclockEnabled && FSettings.SkipDMC7BitOverclock && V) { + ppu.overclock.DMC_7bit_in_use = 1; + } break; + case 0x02: DMCAddressLatch = V; - if (V) - DMC_7bit = 0; + if ((GameInfo->type != GIT_NSF) && FSettings.PPUOverclockEnabled && FSettings.SkipDMC7BitOverclock && V) { + ppu.overclock.DMC_7bit_in_use = 0; + } break; + case 0x03: DMCSizeLatch = V; - if (V) - DMC_7bit = 0; + if ((GameInfo->type != GIT_NSF) && FSettings.PPUOverclockEnabled && FSettings.SkipDMC7BitOverclock && V) { + ppu.overclock.DMC_7bit_in_use = 0; + } break; } } @@ -311,15 +337,20 @@ static DECLFW(StatusWrite) { DoNoise(); DoPCM(); - for (x = 0; x < 4; x++) - if (!(V & (1 << x))) lengthcount[x] = 0; /* Force length counters to 0. */ + for (x = 0; x < 4; x++) { + if (!(V & (1 << x))) { + lengthcount[x] = 0; /* Force length counters to 0. */ + } + } if (V & 0x10) { - if (!DMCSize) + if (!DMCSize) { PrepDPCM(); + } } else { DMCSize = 0; } + SIRQStat &= ~0x80; X6502_IRQEnd(FCEU_IQDPCM); EnabledChannels = V & 0x1F; @@ -330,13 +361,16 @@ static DECLFR(StatusRead) { uint8 ret; ret = SIRQStat; + for (x = 0; x < 4; x++) { + ret |= lengthcount[x] ? (1 << x) : 0; + } + if (DMCSize) { + ret |= 0x10; + } - for (x = 0; x < 4; x++) ret |= lengthcount[x] ? (1 << x) : 0; - if (DMCSize) ret |= 0x10; - - #ifdef FCEUDEF_DEBUGGER +#ifdef FCEUDEF_DEBUGGER if (!fceuindbg) - #endif +#endif { SIRQStat &= ~0x40; X6502_IRQEnd(FCEU_IQFCOUNT); @@ -344,7 +378,7 @@ static DECLFR(StatusRead) { return ret; } -static void FASTAPASS(1) FrameSoundStuff(int V) { +static void FrameSoundStuff(int V) { int P; DoSQ1(); @@ -352,41 +386,48 @@ static void FASTAPASS(1) FrameSoundStuff(int V) { DoNoise(); DoTriangle(); - if (!(V & 1)) { /* Envelope decay, linear counter, length counter, freq sweep */ - if (!(PSG[8] & 0x80)) - if (lengthcount[2] > 0) + if (V & 1) { /* Envelope decay, linear counter, length counter, freq sweep */ + if (!(PSG[8] & 0x80)) { + if (lengthcount[2] > 0) { lengthcount[2]--; + } + } - if (!(PSG[0xC] & 0x20)) /* Make sure loop flag is not set. */ - if (lengthcount[3] > 0) + if (!(PSG[0xC] & 0x20)) { /* Make sure loop flag is not set. */ + if (lengthcount[3] > 0) { lengthcount[3]--; + } + } for (P = 0; P < 2; P++) { - if (!(PSG[P << 2] & 0x20)) /* Make sure loop flag is not set. */ - if (lengthcount[P] > 0) + if (!(PSG[P << 2] & 0x20)) { /* Make sure loop flag is not set. */ + if (lengthcount[P] > 0) { lengthcount[P]--; + } + } /* Frequency Sweep Code Here */ /* xxxx 0000 */ /* xxxx = hz. 120/(x+1)*/ /* http://wiki.nesdev.com/w/index.php/APU_Sweep */ - if (SweepCount[P] > 0) SweepCount[P]--; - if (SweepCount[P] <= 0) { - uint32 sweepShift = (PSG[(P << 2) + 0x1] & 7); - if (sweepon[P] && sweepShift && curfreq[P] >= 8) { - int32 mod = (curfreq[P] >> sweepShift); + if (SweepCount[P]) { + SweepCount[P]--; + } + if (!SweepCount[P]) { + SweepCount[P] = sweepPeriod[P]; + if (sweepon[P] && (curfreq[P] >= 8)) { + int32 offset = (curfreq[P] >> sweepShift[P]); + if (PSG[(P << 2) + 0x1] & 0x8) { - curfreq[P] -= (mod + (P ^ 1)); - } else if ((mod + curfreq[P]) < 0x800) { - curfreq[P] += mod; + curfreq[P] -= (offset + (P ^ 1)); + } else if ((offset + curfreq[P]) < 0x800) { + curfreq[P] += offset; } } - - SweepCount[P] = (((PSG[(P << 2) + 0x1] >> 4) & 7) + 1); } if (sweepReload[P]) { - SweepCount[P] = (((PSG[(P << 2) + 0x1] >> 4) & 7) + 1); + SweepCount[P] = sweepPeriod[P]; sweepReload[P] = 0; } } @@ -394,13 +435,15 @@ static void FASTAPASS(1) FrameSoundStuff(int V) { /* Now do envelope decay + linear counter. */ - if (TriMode)/* In load mode? */ + if (TriMode) { /* In load mode? */ TriCount = PSG[0x8] & 0x7F; - else if (TriCount) + } else if (TriCount) { TriCount--; + } - if (!(PSG[0x8] & 0x80)) + if (!(PSG[0x8] & 0x80)) { TriMode = 0; + } for (P = 0; P < 3; P++) { if (EnvUnits[P].reloaddec) { @@ -410,8 +453,10 @@ static void FASTAPASS(1) FrameSoundStuff(int V) { continue; } - if (EnvUnits[P].DecCountTo1 > 0) EnvUnits[P].DecCountTo1--; - if (EnvUnits[P].DecCountTo1 == 0) { + if (EnvUnits[P].DecCountTo1) { + EnvUnits[P].DecCountTo1--; + } + if (!EnvUnits[P].DecCountTo1) { EnvUnits[P].DecCountTo1 = EnvUnits[P].Speed + 1; if (EnvUnits[P].decvolume || (EnvUnits[P].Mode & 0x2)) { EnvUnits[P].decvolume--; @@ -421,7 +466,7 @@ static void FASTAPASS(1) FrameSoundStuff(int V) { } } -void FrameSoundUpdate(void) { +static void FrameSoundUpdate(void) { /* Linear counter: Bit 0-6 of $4008 * Length counter: Bit 4-7 of $4003, $4007, $400b, $400f */ @@ -431,17 +476,29 @@ void FrameSoundUpdate(void) { fhcnt += fhinc; } - FrameSoundStuff(fcnt); fcnt = (fcnt + 1) & 3; + FrameSoundStuff(fcnt); - /* has to be moved here to fix Dragon Warrior 4 - * after irq inhibit fix for $4017 */ if (!fcnt && !(IRQFrameMode & 0x3)) { SIRQStat |= 0x40; X6502_IRQBegin(FCEU_IQFCOUNT); } } +static DECLFW(Write_IRQFM) { + V = (V & 0xC0) >> 6; + fcnt = 0; + if (V & 2) { + FrameSoundUpdate(); + } + fhcnt = fhinc; + if (V & 1) { + X6502_IRQEnd(FCEU_IQFCOUNT); + SIRQStat &= ~0x40; + } + IRQFrameMode = V; +} + static INLINE void tester(void) { if (DMCBitCount == 0) { if (!DMCHaveDMA) @@ -464,9 +521,9 @@ static INLINE void DMCDMA(void) { DMCAddress = (DMCAddress + 1) & 0x7fff; DMCSize--; if (!DMCSize) { - if (DMCFormat & 0x40) + if (DMCFormat & 0x40) { PrepDPCM(); - else { + } else { if (DMCFormat & 0x80) { SIRQStat |= 0x80; X6502_IRQBegin(FCEU_IQDPCM); @@ -476,13 +533,7 @@ static INLINE void DMCDMA(void) { } } -void FASTAPASS(1) FCEU_SoundCPUHook(int cycles) { - fhcnt -= cycles * 48; - if (fhcnt <= 0) { - FrameSoundUpdate(); - fhcnt += fhinc; - } - +void FCEU_SoundCPUHook(int cycles) { DMCDMA(); DMCacc -= cycles; @@ -490,15 +541,19 @@ void FASTAPASS(1) FCEU_SoundCPUHook(int cycles) { if (DMCHaveSample) { uint8 bah = RawDALatch; int t = ((DMCShift & 1) << 2) - 2; + /* Unbelievably ugly hack */ if (FSettings.SndRate) { - soundtsoffs += DMCacc; + const uint32 fudge = MIN((uint32)(-DMCacc), (uint32)(soundtsoffs + timestamp)); + + soundtsoffs -= fudge; DoPCM(); - soundtsoffs -= DMCacc; + soundtsoffs += fudge; } RawDALatch += t; - if (RawDALatch & 0x80) + if (RawDALatch & 0x80) { RawDALatch = bah; + } } DMCacc += DMCPeriod; @@ -506,14 +561,22 @@ void FASTAPASS(1) FCEU_SoundCPUHook(int cycles) { DMCShift >>= 1; tester(); } + + /* This needs to come after the DMC code because of the "soundtsoffs" +=/-= hack */ + fhcnt -= cycles * 48; + if (fhcnt <= 0) { + FrameSoundUpdate(); + fhcnt += fhinc; + } } -void RDoPCM(void) { +static void RDoPCM(void) { uint32 V; - for (V = ChannelBC[4]; V < SOUNDTS; V++) + for (V = ChannelBC[4]; V < SOUNDTS; V++) { /* TODO: get rid of floating calculations to binary. set log volume scaling. */ - WaveHi[V] += (((RawDALatch << 16) / 256) * FSettings.PCMVolume ) & (~0xFFFF); + WaveHi[V] += GetOutput(SND_DMC, RawDALatch << TRINPCM_SHIFT) & (~0xFFFF); + } ChannelBC[4] = SOUNDTS; } @@ -528,57 +591,58 @@ static INLINE void RDoSQ(int x) { int32 cf; int32 rc; + if (EnvUnits[x].Mode & 0x1) { + amp = EnvUnits[x].Speed; + } else { + amp = EnvUnits[x].decvolume; + } + + amp = GetOutput(SND_SQUARE1 + x, amp); + amp <<= SQ_SHIFT; + + rthresh = RectDuties[(PSG[(x << 2)] & 0xC0) >> 6]; + + D = &WaveHi[ChannelBC[x]]; V = SOUNDTS - ChannelBC[x]; + + currdc = RectDutyCount[x]; cf = (curfreq[x] + 1) * 2; rc = wlcount[x]; /* added 2018/12/08 */ /* when pulse channel is silenced, resets length counters but not * duty cycle, instead of resetting both */ - if ((curfreq[x] < 8 || curfreq[x] > 0x7ff) || - !CheckFreq(curfreq[x], PSG[(x << 2) | 0x1]) || - !lengthcount[x]) { + /* revised 2023-06-28 */ + if ((curfreq[x] < 8) || !CheckFreq(curfreq[x], PSG[(x << 2) | 0x1]) || !lengthcount[x]) { rc -= V; if (rc <= 0) { rc = cf - (-rc % cf); } - } else { - int dutyCycle; - - if (EnvUnits[x].Mode & 0x1) - amp = EnvUnits[x].Speed; - else - amp = EnvUnits[x].decvolume; + V = 0; + } - /* Modify Square wave volume based on channel volume modifiers - * Note: the formulat x = x * y /100 does not yield exact results, - * but is "close enough" and avoids the need for using double values - * or implicit cohersion which are slower (we need speed here) */ - /* TODO: Optimize this. */ - if (FSettings.SquareVolume[x] != 256) - amp = (amp * FSettings.SquareVolume[x]) / 256; + if (rthresh == 6) { /* Reversed below */ + currdc = (currdc - 2) & 0x7; + } - amp <<= 24; - dutyCycle = (PSG[(x << 2)] & 0xC0) >> 6; - rthresh = RectDuties[dutyCycle]; - currdc = RectDutyCount[x]; - D = &WaveHi[ChannelBC[x]]; - - while (V > 0) { - if (currdc < rthresh) - *D += amp; - rc--; - if (!rc) { - rc = cf; - currdc = (currdc + 1) & 7; - } - V--; - D++; + while (V > 0) { + if (currdc < rthresh) { + *D += amp; } + rc--; + if (!rc) { + rc = cf; + currdc = (currdc + 1) & 7; + } + V--; + D++; + } - RectDutyCount[x] = currdc; + if (rthresh == 6) { /* Reverse above */ + currdc = (currdc + 2) & 0x7; } + RectDutyCount[x] = currdc; wlcount[x] = rc; ChannelBC[x] = SOUNDTS; } @@ -605,7 +669,9 @@ static void RDoSQLQ(void) { start = ChannelBC[0]; end = (SOUNDTS << 16) / soundtsinc; - if (end <= start) return; + if (end <= start) { + return; + } ChannelBC[0] = end; for (x = 0; x < 2; x++) { @@ -613,37 +679,37 @@ static void RDoSQLQ(void) { int dutyCycle; inie[x] = nesincsize; - if (curfreq[x] < 8 || curfreq[x] > 0x7ff) + if (curfreq[x] < 8 || curfreq[x] > 0x7ff) { inie[x] = 0; - if (!CheckFreq(curfreq[x], PSG[(x << 2) | 0x1])) + } + if (!CheckFreq(curfreq[x], PSG[(x << 2) | 0x1])) { inie[x] = 0; - if (!lengthcount[x]) + } + if (!lengthcount[x]) { inie[x] = 0; + } - if (EnvUnits[x].Mode & 0x1) + if (EnvUnits[x].Mode & 0x1) { amp[x] = EnvUnits[x].Speed; - else + } else { amp[x] = EnvUnits[x].decvolume; + } - /* Modify Square wave volume based on channel volume modifiers - * Note: the formulat x = x * y /100 does not yield exact results, - * but is "close enough" and avoids the need for using double vales - * or implicit cohersion which are slower (we need speed here) - * fixed - setting up maximum volume for square2 caused complete mute square2 channel. - * TODO: Optimize this. */ - if (FSettings.SquareVolume[x] != 256) - amp[x] = (amp[x] * FSettings.SquareVolume[x]) / 256; + amp[x] = GetOutput(SND_SQUARE1 + x, amp[x]); - if (!inie[x]) amp[x] = 0; /* Correct? Buzzing in MM2, others otherwise... */ + if (!inie[x]) { + amp[x] = 0; /* Correct? Buzzing in MM2, others otherwise... */ + } dutyCycle = (PSG[(x << 2)] & 0xC0) >> 6; rthresh[x] = RectDuties[dutyCycle]; for (y = 0; y < 8; y++) { - if (y < rthresh[x]) + if (y < rthresh[x]) { ttable[x][y] = amp[x]; - else + } else { ttable[x][y] = 0; + } } freq[x] = (curfreq[x] + 1) << 1; freq[x] <<= 17; @@ -652,20 +718,12 @@ static void RDoSQLQ(void) { totalout = wlookup1[ ttable[0][RectDutyCount[0]] + ttable[1][RectDutyCount[1]] ]; if (!inie[0] && !inie[1]) { - for (V = start; V < end; V++) + for (V = start; V < end; V++) { Wave[V >> 4] += totalout; + } } else { for (V = start; V < end; V++) { - /* int tmpamp=0; - if(RectDutyCount[0]> 4] += totalout; /* tmpamp; */ + Wave[V >> 4] += totalout; sqacc[0] -= inie[0]; sqacc[1] -= inie[1]; @@ -674,7 +732,9 @@ static void RDoSQLQ(void) { rea: sqacc[0] += freq[0]; RectDutyCount[0] = (RectDutyCount[0] + 1) & 7; - if (sqacc[0] <= 0) goto rea; + if (sqacc[0] <= 0) { + goto rea; + } totalout = wlookup1[ ttable[0][RectDutyCount[0]] + ttable[1][RectDutyCount[1]] ]; } @@ -682,43 +742,46 @@ static void RDoSQLQ(void) { rea2: sqacc[1] += freq[1]; RectDutyCount[1] = (RectDutyCount[1] + 1) & 7; - if (sqacc[1] <= 0) goto rea2; + if (sqacc[1] <= 0) { + goto rea2; + } totalout = wlookup1[ ttable[0][RectDutyCount[0]] + ttable[1][RectDutyCount[1]] ]; } } } } +static INLINE int32 GetTriSample(void) { + int32 sample = (tristep & 0xF); + if (!(tristep & 0x10)) { + sample ^= 0xF; + } + sample = (sample * 3) << TRINPCM_SHIFT; + return GetOutput(SND_TRIANGLE, sample); +} + static void RDoTriangle(void) { uint32 V; int32 tcout; - tcout = (tristep & 0xF); - if (!(tristep & 0x10)) tcout ^= 0xF; - tcout = (tcout * 3) << 16; /* (tcout<<1); */ + tcout = GetTriSample(); if (!lengthcount[2] || !TriCount) { /* Counter is halted, but we still need to output. */ int32 *start = &WaveHi[ChannelBC[2]]; int32 count = SOUNDTS - ChannelBC[2]; + while (count--) { - *start += (tcout / 256 * FSettings.TriangleVolume) & (~0xFFFF); /* TODO OPTIMIZE ME */ + *start += tcout & (~0xFFFF); start++; } - - /* cout = (tcout / 256 * FSettings.TriangleVolume) & (~0xFFFF); - for(V = ChannelBC[2]; V < SOUNDTS; V++) - WaveHi[V] += cout; */ - } else { for (V = ChannelBC[2]; V < SOUNDTS; V++) { - WaveHi[V] += (tcout / 256 * FSettings.TriangleVolume) & (~0xFFFF); /* TODO OPTIMIZE ME! */ + WaveHi[V] += tcout & (~0xFFFF); wlcount[2]--; if (!wlcount[2]) { wlcount[2] = (PSG[0xa] | ((PSG[0xb] & 7) << 8)) + 1; tristep++; - tcout = (tristep & 0xF); - if (!(tristep & 0x10)) tcout ^= 0xF; - tcout = (tcout * 3) << 16; + tcout = GetTriSample(); } } } @@ -733,50 +796,59 @@ static void RDoTriangleNoisePCMLQ(void) { int32 inie[2]; uint32 amptab[2]; uint32 noiseout; + uint32 pcmout; int nshift; int32 totalout; + int32 wl; start = ChannelBC[2]; end = (SOUNDTS << 16) / soundtsinc; - if (end <= start) return; - ChannelBC[2] = end; - inie[0] = inie[1] = nesincsize; + if (end <= start) { + return; + } + ChannelBC[2] = end; + inie[0] = inie[1] = nesincsize; freq[0] = (((PSG[0xa] | ((PSG[0xb] & 7) << 8)) + 1)); - if (!lengthcount[2] || !TriCount || freq[0] <= 4) + if (!lengthcount[2] || !TriCount || (freq[0] <= 4)) { inie[0] = 0; + } freq[0] <<= 17; - if (EnvUnits[2].Mode & 0x1) + if (EnvUnits[2].Mode & 0x1) { amptab[0] = EnvUnits[2].Speed; - else + } else { amptab[0] = EnvUnits[2].decvolume; + } - /* Modify Triangle wave volume based on channel volume modifiers - * Note: the formulat x = x * y /100 does not yield exact results, - * but is "close enough" and avoids the need for using double vales - * or implicit cohersion which are slower (we need speed here) - * TODO: Optimize this. */ - if (FSettings.TriangleVolume != 256) - amptab[0] = (amptab[0] * FSettings.TriangleVolume) / 256; + pcmout = GetOutput(SND_DMC, RawDALatch); + amptab[0] = GetOutput(SND_NOISE, amptab[0]); amptab[1] = 0; amptab[0] <<= 1; - if (!lengthcount[3]) + if (!lengthcount[3]) { amptab[0] = inie[1] = 0; /* Quick hack speedup, set inie[1] to 0 */ + } noiseout = amptab[(nreg >> 0xe) & 1]; - if (PSG[0xE] & 0x80) + if (PSG[0xE] & 0x80) { nshift = 8; - else + } else { nshift = 13; + } - totalout = wlookup2[lq_tcout + noiseout + RawDALatch]; + totalout = wlookup2[lq_tcout + noiseout + pcmout]; + + if (isPAL) { + wl = PALNoiseFreqTable[PSG[0xE] & 0xF] << (16 + 1); + } else { + wl = NTSCNoiseFreqTable[PSG[0xE] & 0xF] << (16 + 1); + } if (inie[0] && inie[1]) { for (V = start; V < end; V++) { @@ -789,29 +861,30 @@ static void RDoTriangleNoisePCMLQ(void) { rea: lq_triacc += freq[0]; /* t; */ tristep = (tristep + 1) & 0x1F; - if (lq_triacc <= 0) goto rea; + if (lq_triacc <= 0) { + goto rea; + } lq_tcout = (tristep & 0xF); - if (!(tristep & 0x10)) lq_tcout ^= 0xF; + if (!(tristep & 0x10)) { + lq_tcout ^= 0xF; + } lq_tcout = lq_tcout * 3; - totalout = wlookup2[lq_tcout + noiseout + RawDALatch]; + lq_tcout = GetOutput(SND_TRIANGLE, lq_tcout); + totalout = wlookup2[lq_tcout + noiseout + pcmout]; } if (lq_noiseacc <= 0) { rea2: - /* used to added <<(16+2) when the noise table - * values were half. - */ - if (PAL) - lq_noiseacc += PALNoiseFreqTable[PSG[0xE] & 0xF] << (16 + 1); - else - lq_noiseacc += NTSCNoiseFreqTable[PSG[0xE] & 0xF] << (16 + 1); + lq_noiseacc += wl; nreg = (nreg << 1) + (((nreg >> nshift) ^ (nreg >> 14)) & 1); nreg &= 0x7fff; noiseout = amptab[(nreg >> 0xe) & 1]; - if (lq_noiseacc <= 0) goto rea2; - totalout = wlookup2[lq_tcout + noiseout + RawDALatch]; - } /* noiseacc<=0 */ - } /* for(V=... */ + if (lq_noiseacc <= 0) { + goto rea2; + } + totalout = wlookup2[lq_tcout + noiseout + pcmout]; + } + } } else if (inie[0]) { for (V = start; V < end; V++) { Wave[V >> 4] += totalout; @@ -822,11 +895,16 @@ static void RDoTriangleNoisePCMLQ(void) { area: lq_triacc += freq[0]; /* t; */ tristep = (tristep + 1) & 0x1F; - if (lq_triacc <= 0) goto area; + if (lq_triacc <= 0) { + goto area; + } lq_tcout = (tristep & 0xF); - if (!(tristep & 0x10)) lq_tcout ^= 0xF; + if (!(tristep & 0x10)) { + lq_tcout ^= 0xF; + } lq_tcout = lq_tcout * 3; - totalout = wlookup2[lq_tcout + noiseout + RawDALatch]; + lq_tcout = GetOutput(SND_TRIANGLE, lq_tcout); + totalout = wlookup2[lq_tcout + noiseout + pcmout]; } } } else if (inie[1]) { @@ -835,23 +913,20 @@ static void RDoTriangleNoisePCMLQ(void) { lq_noiseacc -= inie[1]; if (lq_noiseacc <= 0) { area2: - /* used to be added <<(16+2) when the noise table - * values were half. - */ - if (PAL) - lq_noiseacc += PALNoiseFreqTable[PSG[0xE] & 0xF] << (16 + 1); - else - lq_noiseacc += NTSCNoiseFreqTable[PSG[0xE] & 0xF] << (16 + 1); + lq_noiseacc += wl; nreg = (nreg << 1) + (((nreg >> nshift) ^ (nreg >> 14)) & 1); nreg &= 0x7fff; noiseout = amptab[(nreg >> 0xe) & 1]; - if (lq_noiseacc <= 0) goto area2; - totalout = wlookup2[lq_tcout + noiseout + RawDALatch]; - } /* noiseacc<=0 */ + if (lq_noiseacc <= 0) { + goto area2; + } + totalout = wlookup2[lq_tcout + noiseout + pcmout]; + } } } else { - for (V = start; V < end; V++) + for (V = start; V < end; V++) { Wave[V >> 4] += totalout; + } } } @@ -859,21 +934,18 @@ static void RDoNoise(void) { uint32 V; int32 outo; uint32 amptab[2]; + int32 wl; + int nshift; - if (EnvUnits[2].Mode & 0x1) + if (EnvUnits[2].Mode & 0x1) { amptab[0] = EnvUnits[2].Speed; - else + } else { amptab[0] = EnvUnits[2].decvolume; + } - /* Modify Noise wave volume based on channel volume modifiers - * Note: the formulat x = x * y /100 does not yield exact results, - * but is "close enough" and avoids the need for using double vales - * or implicit cohersion which are slower (we need speed here) - * TODO: Optimize this. */ - if (FSettings.NoiseVolume != 256) - amptab[0] = (amptab[0] * FSettings.NoiseVolume) / 256; + amptab[0] = GetOutput(SND_NOISE, amptab[0]); - amptab[0] <<= 16; + amptab[0] <<= TRINPCM_SHIFT; amptab[1] = 0; amptab[0] <<= 1; @@ -884,57 +956,35 @@ static void RDoNoise(void) { outo = amptab[0] = 0; } - if (PSG[0xE] & 0x80) {/* "short" noise */ - for (V = ChannelBC[3]; V < SOUNDTS; V++) { - WaveHi[V] += outo; - wlcount[3]--; - if (!wlcount[3]) { - uint8 feedback; - if (PAL) - wlcount[3] = PALNoiseFreqTable[PSG[0xE] & 0xF]; - else - wlcount[3] = NTSCNoiseFreqTable[PSG[0xE] & 0xF]; - feedback = ((nreg >> 8) & 1) ^ ((nreg >> 14) & 1); - nreg = (nreg << 1) + feedback; - nreg &= 0x7fff; - outo = amptab[(nreg >> 0xe) & 1]; - } - } + if (isPAL) { + wl = PALNoiseFreqTable[PSG[0xE] & 0xF]; } else { - for (V = ChannelBC[3]; V < SOUNDTS; V++) { - WaveHi[V] += outo; - wlcount[3]--; - if (!wlcount[3]) { - uint8 feedback; - if (PAL) - wlcount[3] = PALNoiseFreqTable[PSG[0xE] & 0xF]; - else - wlcount[3] = NTSCNoiseFreqTable[PSG[0xE] & 0xF]; - feedback = ((nreg >> 13) & 1) ^ ((nreg >> 14) & 1); - nreg = (nreg << 1) + feedback; - nreg &= 0x7fff; - outo = amptab[(nreg >> 0xe) & 1]; - } - } + wl = NTSCNoiseFreqTable[PSG[0xE] & 0xF]; } - ChannelBC[3] = SOUNDTS; -} -DECLFW(Write_IRQFM) { - V = (V & 0xC0) >> 6; - fcnt = 0; - if (V & 2) - FrameSoundUpdate(); - /* fcnt = 1; */ - fhcnt = fhinc; - if (V & 1) { - X6502_IRQEnd(FCEU_IQFCOUNT); - SIRQStat &= ~0x40; + if (PSG[0xE] & 0x80) { + nshift = 8; + } else { + nshift = 13; } - IRQFrameMode = V; + + for (V = ChannelBC[3]; V < SOUNDTS; V++) { + WaveHi[V] += outo; + wlcount[3]--; + if (!wlcount[3]) { + uint8 feedback; + + wlcount[3] = wl; + feedback = ((nreg >> nshift) & 1) ^ ((nreg >> 14) & 1); + nreg = (nreg << 1) + feedback; + nreg &= 0x7fff; + outo = amptab[(nreg >> 0xe) & 1]; + } + } + ChannelBC[3] = SOUNDTS; } -void SetNESSoundMap(void) { +static void SetNESSoundMap(void) { SetWriteHandler(0x4000, 0x400F, Write_PSG); SetWriteHandler(0x4010, 0x4013, Write_DMCRegs); SetWriteHandler(0x4017, 0x4017, Write_IRQFM); @@ -948,7 +998,9 @@ int FlushEmulateSound(void) { int x; int32 end, left; - if (!sound_timestamp) return(0); + if (!sound_timestamp) { + return(0); + } if (!FSettings.SndRate) { left = 0; @@ -965,11 +1017,17 @@ int FlushEmulateSound(void) { if (FSettings.soundq >= 1) { int32 *tmpo = &WaveHi[soundtsoffs]; - if (GameExpSound.HiFill) GameExpSound.HiFill(); + for (x = 0; x < GAMEEXPSOUND_COUNT; x++) { + if (GameExpSound[x].HiFill) { + GameExpSound[x].HiFill(); + } + } for (x = sound_timestamp; x; x--) { uint32 b = *tmpo; - *tmpo = (b & 65535) + wlookup2[(b >> 16) & 255] + wlookup1[b >> 24]; + int32 sample = wlookup2[(b >> TRINPCM_SHIFT) & 0xFF] + wlookup1[b >> SQ_SHIFT]; + + *tmpo = (b & 0xFFFF) + sample; tmpo++; } @@ -978,21 +1036,31 @@ int FlushEmulateSound(void) { memmove(WaveHi, WaveHi + SOUNDTS - left, left * sizeof(uint32)); memset(WaveHi + left, 0, sizeof(WaveHi) - left * sizeof(uint32)); - if (GameExpSound.HiSync) GameExpSound.HiSync(left); - for (x = 0; x < 5; x++) + for (x = 0; x < GAMEEXPSOUND_COUNT; x++) { + if (GameExpSound[x].HiSync) { + GameExpSound[x].HiSync(left); + } + } + for (x = 0; x < 5; x++) { ChannelBC[x] = left; + } } else { end = (SOUNDTS << 16) / soundtsinc; - if (GameExpSound.Fill) - GameExpSound.Fill(end & 0xF); + for (x = 0; x < GAMEEXPSOUND_COUNT; x++) { + if (GameExpSound[x].Fill) { + GameExpSound[x].Fill(end & 0xF); + } + } SexyFilter(Wave, WaveFinal, end >> 4); - if (FSettings.lowpass) + if (FSettings.lowpass) { SexyFilter2(WaveFinal, end >> 4); + } - if (end & 0xF) + if (end & 0xF) { Wave[0] = Wave[(end >> 4)]; + } Wave[end >> 4] = 0; } nosoundo: @@ -1000,8 +1068,9 @@ int FlushEmulateSound(void) { if (FSettings.soundq >= 1) { soundtsoffs = left; } else { - for (x = 0; x < 5; x++) + for (x = 0; x < 5; x++) { ChannelBC[x] = end & 0xF; + } soundtsoffs = (soundtsinc * (end & 0xF)) >> 16; end >>= 4; } @@ -1028,16 +1097,18 @@ void FCEUSND_Reset(void) { for (x = 0; x < 2; x++) { wlcount[x] = 2048; - if (nesincsize) /* lq mode */ - sqacc[x] = ((uint32)2048 << 17) / nesincsize; - else - sqacc[x] = 1; sweepon[x] = 0; curfreq[x] = 0; + if (nesincsize) { /* lq mode */ + sqacc[x] = ((uint32)2048 << 17) / nesincsize; + } else { + sqacc[x] = 1; + } } - wlcount[2] = 1; /* 2048; */ + + wlcount[2] = 1; /* 2048; */ wlcount[3] = 2048; - DMCHaveDMA = DMCHaveSample = 0; + SIRQStat = 0x00; RawDALatch = 0x00; @@ -1045,8 +1116,9 @@ void FCEUSND_Reset(void) { TriMode = 0; tristep = 0; EnabledChannels = 0; - for (x = 0; x < 4; x++) + for (x = 0; x < 4; x++) { lengthcount[x] = 0; + } DMCAddressLatch = 0; DMCSizeLatch = 0; @@ -1054,8 +1126,13 @@ void FCEUSND_Reset(void) { DMCAddress = 0; DMCSize = 0; DMCShift = 0; - DMCacc=1; - DMCBitCount=0; + + DMCacc = 1; + DMCBitCount = 0; + + DMCHaveDMA = 0; + DMCDMABuf = 0; + DMCHaveSample = 0; } void FCEUSND_Power(void) { @@ -1069,10 +1146,13 @@ void FCEUSND_Power(void) { memset(WaveHi, 0, sizeof(WaveHi)); memset(&EnvUnits, 0, sizeof(EnvUnits)); - for (x = 0; x < 5; x++) + for (x = 0; x < 5; x++) { ChannelBC[x] = 0; + } + soundtsoffs = 0; IRQFrameMode = 0x0; /* Only initialized by power-on reset, not by soft reset */ + LoadDMCPeriod(DMCFormat & 0xF); } @@ -1080,19 +1160,23 @@ void FCEUSND_Power(void) { void SetSoundVariables(void) { int x; - fhinc = PAL ? 16626 : 14915; /* *2 CPU clock rate */ + fhinc = isPAL ? 16626 : 14915; /* *2 CPU clock rate */ fhinc *= 24; if (FSettings.SndRate) { wlookup1[0] = 0; for (x = 1; x < 32; x++) { wlookup1[x] = (double)16 * 16 * 16 * 4 * 95.52 / ((double)8128 / (double)x + 100); - if (!FSettings.soundq) wlookup1[x] >>= 4; + if (!FSettings.soundq) { + wlookup1[x] >>= 4; + } } wlookup2[0] = 0; for (x = 1; x < 203; x++) { wlookup2[x] = (double)16 * 16 * 16 * 4 * 163.67 / ((double)24329 / (double)x + 100); - if (!FSettings.soundq) wlookup2[x] >>= 4; + if (!FSettings.soundq) { + wlookup2[x] >>= 4; + } } if (FSettings.soundq >= 1) { DoNoise = RDoNoise; @@ -1115,16 +1199,19 @@ void SetSoundVariables(void) { MakeFilters(FSettings.SndRate); - if (GameExpSound.RChange) - GameExpSound.RChange(); + for (x = 0; x < GAMEEXPSOUND_COUNT; x++) { + if (GameExpSound[x].RChange) { + GameExpSound[x].RChange(); + } + } - nesincsize = (int64)(((int64)1 << 17) * (double)(PAL ? PAL_CPU : NTSC_CPU) / (FSettings.SndRate * 16)); + nesincsize = (int64)(((int64)1 << 17) * (double)(isPAL ? PAL_CPU : NTSC_CPU) / (FSettings.SndRate * 16)); memset(sqacc, 0, sizeof(sqacc)); memset(ChannelBC, 0, sizeof(ChannelBC)); LoadDMCPeriod(DMCFormat & 0xF); /* For changing from PAL to NTSC */ - soundtsinc = (uint32)((uint64)(PAL ? (long double)PAL_CPU * 65536 : (long double)NTSC_CPU * 65536) / (FSettings.SndRate * 16)); + soundtsinc = (uint32)((uint64)(isPAL ? (long double)PAL_CPU * 65536 : (long double)NTSC_CPU * 65536) / (FSettings.SndRate * 16)); } void FCEUI_Sound(int Rate) { @@ -1141,10 +1228,30 @@ void FCEUI_SetSoundQuality(int quality) { SetSoundVariables(); } -void FCEUI_SetSoundVolume(uint32 volume) { - FSettings.SoundVolume = volume; +void FCEUI_SetSoundVolume(int channel, int volume) { + if (volume > 256) { + volume = 256; + } + FSettings.volume[channel] = volume; } +int FCEUI_GetSoundVolume(int channel) { + if ((channel >= SND_MASTER) && (channel < SND_LAST)) { + return FSettings.volume[channel]; + } + return 0; +} + +int32 GetOutput(int channel, int32 in) { + if ((channel > SND_MASTER) && (channel < SND_LAST)) { + int mod = FCEUI_GetSoundVolume(channel); + + if (in == 0) return 0; /* do nothing */ + if (mod == 256) return in; /* no change */ + return (int32)((in * mod) >> 8); /* return modified volume levels */ + } + return in; +} SFORMAT FCEUSND_STATEINFO[] = { { &fhcnt, 4 | FCEUSTATE_RLSB, "FHCN" }, @@ -1180,6 +1287,9 @@ SFORMAT FCEUSND_STATEINFO[] = { { &curfreq[0], 4 | FCEUSTATE_RLSB, "CRF1" }, { &curfreq[1], 4 | FCEUSTATE_RLSB, "CRF2" }, { SweepCount, 2, "SWCT" }, + { sweepReload, 2, "SWRL" }, + { sweepPeriod, 2, "SWPD" }, + { sweepShift, 2, "SWSH" }, { &SIRQStat, 1, "SIRQ" }, @@ -1222,15 +1332,8 @@ SFORMAT FCEUSND_STATEINFO[] = { { &sexyfilter_acc2, sizeof(sexyfilter_acc2) | FCEUSTATE_RLSB, "FAC2" }, { &lq_tcout, sizeof(lq_tcout) | FCEUSTATE_RLSB, "TCOU"}, -/* 2018-12-14 - Wii and possibly other big-endian platforms are having - * 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 */ -/* 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 { 0 } }; @@ -1240,59 +1343,53 @@ void FCEUSND_SaveState(void) { void FCEUSND_LoadState(int version) { int i; + LoadDMCPeriod(DMCFormat & 0xF); RawDALatch &= 0x7F; DMCAddress &= 0x7FFF; /* minimal validation */ - for (i = 0; i < 5; i++) - { + for (i = 0; i < 5; i++) { uint32 BC_max = 15; - if (FSettings.soundq == 2) - { + if (FSettings.soundq == 2) { BC_max = 1025; - } - else if (FSettings.soundq == 1) - { + } else if (FSettings.soundq == 1) { BC_max = 485; } - if (/* ChannelBC[i] < 0 || */ ChannelBC[i] > BC_max) - { + if (/* ChannelBC[i] < 0 || */ ChannelBC[i] > BC_max) { ChannelBC[i] = 0; } } - for (i = 0; i < 4; i++) - { - if (wlcount[i] < 0 || wlcount[i] > 2048) - { - wlcount[i] = 2048; - } + if (DMCacc <= 0) { + DMCacc = 1; } - for (i = 0; i < 2; i++) - { - if (RectDutyCount[i] < 0 || RectDutyCount[i] > 7) - { - RectDutyCount[i] = 7; + for (i = 0; i < 4; i++) { + wlcount[i] = MAX((int32)(1), (int32)MIN((int32)(0xFFFF), (int32)(wlcount[i]))); + } + for (i = 0; i < 2; i++) { + RectDutyCount[i] &= 0x7; + curfreq[i] &= 0xFFFF; + sweepShift[i] &= 0x7; + if (!sweepShift[i]) { + sweepon[i] = 0; } } /* Comparison is always false because access to array >= 0. */ /* if (sound_timestamp < 0) { - sound_timestamp = 0; + sound_timestamp = 0; } if (soundtsoffs < 0) { - soundtsoffs = 0; + soundtsoffs = 0; } */ - if (soundtsoffs + sound_timestamp >= soundtsinc) - { + if (soundtsoffs + sound_timestamp >= soundtsinc) { soundtsoffs = 0; sound_timestamp = 0; } - if (tristep > 32) - { + if (tristep > 32) { tristep &= 0x1F; } } diff --git a/src/sound.h b/src/sound.h index c4413ccc6..42b2f8055 100644 --- a/src/sound.h +++ b/src/sound.h @@ -21,6 +21,36 @@ #ifndef _FCEU_SOUND_H #define _FCEU_SOUND_H +enum AUDIO_CHANNEL { + /* NES APU */ + SND_MASTER = 0, + SND_SQUARE1 = 1, + SND_SQUARE2 = 2, + SND_TRIANGLE = 3, + SND_NOISE = 4, + SND_DMC = 5, + + /* EXPANSION AUDIO */ + /* index beyond this line also affects GameExpSound struct index */ + + SND_VRC6 = 6, + SND_VRC7 = 7, + SND_FDS = 8, + SND_N163 = 9, + SND_S5B = 10, + SND_MMC5 = 11, + + SND_LAST = 12 +}; + +typedef struct { + uint8 Speed; + uint8 Mode; + uint8 DecCountTo1; + uint8 decvolume; + int reloaddec; +} ENVUNIT; + typedef struct { void (*Fill)(int Count); /* Low quality ext sound. */ @@ -38,7 +68,8 @@ typedef struct { void (*Kill)(void); } EXPSOUND; -extern EXPSOUND GameExpSound; +#define GAMEEXPSOUND_COUNT 6 +extern EXPSOUND GameExpSound[GAMEEXPSOUND_COUNT]; extern int32 nesincsize; @@ -54,14 +85,18 @@ extern uint32 soundtsinc; extern uint32 soundtsoffs; #define SOUNDTS (sound_timestamp + soundtsoffs) -void SetNESSoundMap(void); -void FrameSoundUpdate(void); - void FCEUSND_Power(void); void FCEUSND_Reset(void); void FCEUSND_SaveState(void); void FCEUSND_LoadState(int version); -void FASTAPASS(1) FCEU_SoundCPUHook(int); +void FCEU_SoundCPUHook(int); + +/* Modify channel wave volume based on volume modifiers + * Note: the formulat x = x * y /256 does not yield exact results, + * but is "close enough" and avoids the need for using double values + * or implicit cohersion which are slower (we need speed here) */ +/* TODO: Optimize this. */ +int32 GetOutput(int channel, int32 in); #endif diff --git a/src/state.c b/src/state.c index 881cd44b3..3dd1fe50e 100644 --- a/src/state.c +++ b/src/state.c @@ -38,40 +38,40 @@ #include "fceu-memory.h" #include "ppu.h" #include "video.h" +#include "gamegenie.h" + +#define SFMDATA_SIZE 128 +#define RLSB FCEUSTATE_RLSB static void (*SPreSave)(void); static void (*SPostSave)(void); -/* static int SaveStateStatus[10]; */ - -static SFORMAT SFMDATA[64]; +static SFORMAT SFMDATA[SFMDATA_SIZE]; static int SFEXINDEX; -#define RLSB FCEUSTATE_RLSB /* 0x80000000 */ - extern SFORMAT FCEUPPU_STATEINFO[]; extern SFORMAT FCEUSND_STATEINFO[]; extern SFORMAT FCEUCTRL_STATEINFO[]; SFORMAT SFCPU[] = { - { &X.PC, 2 | RLSB, "PC\0" }, - { &X.A, 1, "A\0\0" }, - { &X.X, 1, "X\0\0" }, - { &X.Y, 1, "Y\0\0" }, - { &X.S, 1, "S\0\0" }, - { &X.P, 1, "P\0\0" }, - { &X.DB, 1, "DB"}, - { RAM, 0x800, "RAM" }, + { &cpu.PC, 2 | RLSB, "PC\0" }, + { &cpu.A, 1, "A\0\0" }, + { &cpu.X, 1, "X\0\0" }, + { &cpu.Y, 1, "Y\0\0" }, + { &cpu.S, 1, "S\0\0" }, + { &cpu.P, 1, "P\0\0" }, + { &cpu.openbus, 1, "DB\0"}, + { &RAM, RAM_SIZE | FCEUSTATE_INDIRECT, "RAM" }, { 0 } }; SFORMAT SFCPUC[] = { - { &X.jammed, 1, "JAMM" }, - { &X.IRQlow, 4 | RLSB, "IQLB" }, - { &X.tcount, 4 | RLSB, "ICoa" }, - { &X.count, 4 | RLSB, "ICou" }, + { &cpu.jammed, 1, "JAMM" }, + { &cpu.IRQlow, 4 | RLSB, "IQLB" }, + { &cpu.tcount, 4 | RLSB, "ICoa" }, + { &cpu.count, 4 | RLSB, "ICou" }, { ×tampbase, sizeof(timestampbase) | RLSB, "TSBS" }, - { &X.mooPI, 1, "MooP"}, + { &cpu.mooPI, 1, "MooP"}, { 0 } }; @@ -93,23 +93,27 @@ static int SubWrite(memstream_t *mem, SFORMAT *sf) } acc += 8; /* Description + size */ - acc += sf->s & (~RLSB); + acc += sf->s & (~FCEUSTATE_FLAGS); if(mem) /* Are we writing or calculating the size of this block? */ { memstream_write(mem, sf->desc, 4); - write32le_mem(sf->s & (~RLSB), mem); + write32le_mem(sf->s & (~FCEUSTATE_FLAGS), mem); #ifdef MSB_FIRST if(sf->s & RLSB) - FlipByteOrder((uint8 *)sf->v, sf->s & (~RLSB)); + FlipByteOrder((uint8 *)sf->v, sf->s & (~FCEUSTATE_FLAGS)); #endif - memstream_write(mem, (char *)sf->v, sf->s & (~RLSB)); + if (sf->s & FCEUSTATE_INDIRECT) { + memstream_write(mem, *(char **)sf->v, sf->s & (~FCEUSTATE_FLAGS)); + } else { + memstream_write(mem, (char *)sf->v, sf->s & (~FCEUSTATE_FLAGS)); + } /* Now restore the original byte order. */ #ifdef MSB_FIRST if(sf->s & RLSB) - FlipByteOrder((uint8 *)sf->v, sf->s & (~RLSB)); + FlipByteOrder((uint8 *)sf->v, sf->s & (~FCEUSTATE_FLAGS)); #endif } sf++; @@ -146,7 +150,7 @@ static SFORMAT *CheckS(SFORMAT *sf, uint32 tsize, char *desc) } if (!strncmp(desc, sf->desc, 4)) { - if (tsize != (sf->s & (~RLSB))) + if (tsize != (sf->s & (~FCEUSTATE_FLAGS))) return(0); return(sf); } @@ -172,11 +176,15 @@ static int ReadStateChunk(memstream_t *mem, SFORMAT *sf, int size) if((tmp = CheckS(sf, tsize, toa))) { - memstream_read(mem, (char *)tmp->v, tmp->s & (~RLSB)); + if (tmp->s & FCEUSTATE_INDIRECT) { + memstream_read(mem, *(char **)tmp->v, tmp->s & (~FCEUSTATE_FLAGS)); + } else { + memstream_read(mem, (char *)tmp->v, tmp->s & (~FCEUSTATE_FLAGS)); + } #ifdef MSB_FIRST if(tmp->s & RLSB) - FlipByteOrder((uint8 *)tmp->v, tmp->s & (~RLSB)); + FlipByteOrder((uint8 *)tmp->v, tmp->s & (~FCEUSTATE_FLAGS)); #endif } else @@ -210,7 +218,7 @@ static int ReadStateChunks(memstream_t *st, int32 totalsize) if (!ReadStateChunk(st, SFCPUC, size)) ret = 0; /* else - X.mooPI = X.P; */ /* Quick and dirty hack. */ + cpu.mooPI = cpu.P; */ /* Quick and dirty hack. */ break; case 3: if (!ReadStateChunk(st, FCEUPPU_STATEINFO, size)) @@ -238,37 +246,32 @@ static int ReadStateChunks(memstream_t *st, int32 totalsize) return ret; } -extern int geniestage; - void FCEUSS_Save_Mem(void) { memstream_t *mem = memstream_open(1); - - uint32 totalsize; uint8 header[16] = {0}; + size_t totalsize = 0; header[0] = 'F'; header[1] = 'C'; header[2] = 'S'; - header[3] = 0xFF; + header[3] = 'M'; FCEU_en32lsb(header + 8, FCEU_VERSION_NUMERIC); memstream_write(mem, header, 16); FCEUPPU_SaveState(); + FCEUSND_SaveState(); + totalsize = WriteStateChunk(mem, 1, SFCPU); totalsize += WriteStateChunk(mem, 2, SFCPUC); totalsize += WriteStateChunk(mem, 3, FCEUPPU_STATEINFO); totalsize += WriteStateChunk(mem, 4, FCEUCTRL_STATEINFO); totalsize += WriteStateChunk(mem, 5, FCEUSND_STATEINFO); - if (SPreSave) - SPreSave(); - + if (SPreSave) SPreSave(); totalsize += WriteStateChunk(mem, 0x10, SFMDATA); - - if (SPreSave) - SPostSave(); + if (SPostSave) SPostSave(); memstream_seek(mem, 4, SEEK_SET); write32le_mem(totalsize, mem); @@ -279,29 +282,21 @@ void FCEUSS_Save_Mem(void) void FCEUSS_Load_Mem(void) { memstream_t *mem = memstream_open(0); - - uint8 header[16]; - int stateversion; - int totalsize; - int x; + uint8 header[16] = {0}; + size_t totalsize = 0; + int stateversion = 0; + int x = 0; memstream_read(mem, header, 16); - if (memcmp(header, "FCS", 3) != 0) + if (memcmp(header, "FCSM", 4) != 0) return; - if (header[3] == 0xFF) - stateversion = FCEU_de32lsb(header + 8); - else - stateversion = header[3] * 100; - totalsize = FCEU_de32lsb(header + 4); + stateversion = FCEU_de32lsb(header + 8); x = ReadStateChunks(mem, totalsize); - if (stateversion < 9500) - X.IRQlow = 0; - if (GameStateRestore) GameStateRestore(stateversion); @@ -333,12 +328,16 @@ void AddExState(void *v, uint32 s, int type, char *desc) SFMDATA[SFEXINDEX].s = s; if (type) SFMDATA[SFEXINDEX].s |= RLSB; - if (SFEXINDEX < 63) + if (SFEXINDEX < (SFMDATA_SIZE - 1)) { SFEXINDEX++; + } else { + static int warn_once = 1; + if (warn_once) { + FCEU_printf("\n"); + FCEU_PrintError(" Error in AddExState: SFEINDEX overflow. SFMDATA_SIZE too small.\n"); + FCEU_printf("\n"); + warn_once = 0; + } + } SFMDATA[SFEXINDEX].v = 0; /* End marker. */ } - -void FCEU_DrawSaveStates(uint8 *XBuf) -{ -} - diff --git a/src/state.h b/src/state.h index c5a1eb348..6ddff0d9f 100644 --- a/src/state.h +++ b/src/state.h @@ -23,6 +23,13 @@ #include "fceu-memory.h" +/* last known fceu-mm version */ +#define FCEU_VERSION_MAJOR 0 +#define FCEU_VERSION_MINOR 98 +#define FCEU_VERSION_PATCH 13 + +#define FCEU_VERSION_NUMERIC ((FCEU_VERSION_MAJOR * 10000) + (FCEU_VERSION_MINOR * 100) + (FCEU_VERSION_PATCH)) + void FCEUSS_Load_Mem(void); void FCEUSS_Save_Mem(void); @@ -35,8 +42,13 @@ typedef struct { void ResetExState(void (*PreSave)(void), void (*PostSave)(void)); void AddExState(void *v, uint32 s, int type, char *desc); -#define FCEUSTATE_RLSB 0x80000000 +/* indicates that the value is a multibyte integer that needs to be put in the correct byte order */ +#define FCEUSTATE_RLSB 0x80000000 + +/* void*v is actually a void** which will be indirected before reading */ +#define FCEUSTATE_INDIRECT 0x40000000 -void FCEU_DrawSaveStates(uint8 *XBuf); +/* all FCEUSTATE flags together so that we can mask them out and get the size */ +#define FCEUSTATE_FLAGS (FCEUSTATE_RLSB | FCEUSTATE_INDIRECT) #endif diff --git a/src/unif.c b/src/unif.c index d00de2ee7..7351e070f 100644 --- a/src/unif.c +++ b/src/unif.c @@ -50,7 +50,8 @@ typedef struct { typedef struct { char *name; - int ines_mapper; + int mapper; + int submapper; void (*init)(CartInfo *); int flags; } BMAPPING; @@ -60,8 +61,6 @@ typedef struct { int (*init)(FCEUFILE *fp); } BFMAPPING; -CartInfo UNIFCart; - static int vramo; static int mirrortodo; static int submapper; @@ -111,11 +110,14 @@ static void FreeUNIF(void) { free(malloced[x]); malloced[x] = 0; } } - if (ROM) { - free(ROM); ROM = 0; + if (ROM.prg.data) { + free(ROM.prg.data); ROM.prg.data = 0; } - if (VROM) { - free(VROM); VROM = 0; + if (ROM.chr.data) { + free(ROM.chr.data); ROM.chr.data = 0; + } + if (WRAM) { + free(WRAM); WRAM = NULL; WRAMSIZE = 0; } } @@ -130,16 +132,16 @@ static void ResetUNIF(void) { vramo = 0; boardname = 0; mirrortodo = 0; - submapper = 0; + submapper = DEFAULT; cspecial = 0; - memset(&UNIFCart, 0, sizeof(UNIFCart)); + memset(&iNESCart, 0, sizeof(iNESCart)); UNIFchrrama = 0; prg_chip_count = 0; chr_chip_count = 0; UNIF_PRGROMSize = 0; UNIF_CHRROMSize = 0; - ROM_size = 0; - VROM_size = 0; + ROM.prg.size = 0; + ROM.chr.size = 0; } static void Cleanup(void) { @@ -151,8 +153,7 @@ static uint8 exntar[2048]; static void MooMirroring(void) { if (mirrortodo < 0x4) - /* 06-22-19 Allow override when using vertical/horizontal mirroring. */ - SetupCartMirroring(mirrortodo, (mirrortodo >> 1) & 1, 0); + SetupCartMirroring(mirrortodo, FALSE, NULL); else if (mirrortodo == 0x4) { FCEU_MemoryRand(exntar, sizeof(exntar)); SetupCartMirroring(4, 1, exntar); @@ -169,7 +170,14 @@ static int DoMirroring(FCEUFILE *fp) { return(0); mirrortodo = t; { - static char *stuffo[6] = { "Horizontal", "Vertical", "$2000", "$2400", "\"Four-screen\"", "Controlled by Mapper Hardware" }; + static char *stuffo[6] = { + "Horizontal", + "Vertical", + "$2000", + "$2400", + "\"Four-screen\"", + "Controlled by Mapper Hardware", + }; if (t < 6) FCEU_printf(" Name/Attribute Table Mirroring: %s\n", stuffo[t]); } @@ -284,8 +292,8 @@ static int TVCI(FCEUFILE *fp) { static int EnableBattery(FCEUFILE *fp) { int ret = FCEU_fgetc(fp); - UNIFCart.battery = (ret > 0) ? 1 : 0; - if (UNIFCart.battery) + iNESCart.battery = (ret > 0) ? 1 : 0; + if (iNESCart.battery) FCEU_printf(" Battery-backed.\n"); return(1); } @@ -369,11 +377,11 @@ struct _unif_db { }; static struct _unif_db unif_db[] = { - { 0x03ed6963ca50e1d8ULL, "A65AS", 1, -1, -1 }, - { 0x616851e56946893bULL, "RESETNROM-XIN1", 1, -1, -1 }, /* Sheng Tian 2-in-1(Unl,ResetBase)[p1].unf */ - { 0x4cd729b5ae23a3cfULL, "RESETNROM-XIN1", 1, -1, -1 }, /* Sheng Tian 2-in-1(Unl,ResetBase)[p2].unf */ + { 0x03ed6963ca50e1d8ULL, "A65AS", 1, DEFAULT, DEFAULT }, + { 0x616851e56946893bULL, "RESETNROM-XIN1", 1, DEFAULT, DEFAULT }, /* Sheng Tian 2-in-1(Unl,ResetBase)[p1].unf */ + { 0x4cd729b5ae23a3cfULL, "RESETNROM-XIN1", 1, DEFAULT, DEFAULT }, /* Sheng Tian 2-in-1(Unl,ResetBase)[p2].unf */ - { 0, NULL, -1, -1, -1 } /* end of the line */ + { 0ULL, NULL, DEFAULT, DEFAULT, DEFAULT } /* end of the line */ }; static void CheckHashInfo(void) { @@ -381,7 +389,7 @@ static void CheckHashInfo(void) { uint64 partialMD5 = 0; for (x = 0; x < 8; x++) - partialMD5 |= (uint64)UNIFCart.MD5[15 - x] << (x * 8); + partialMD5 |= (uint64)iNESCart.MD5[15 - x] << (x * 8); x = 0; do { @@ -416,226 +424,232 @@ static void CheckHashInfo(void) { } -#define NO_INES -1 -#define BMCFLAG_FORCE4 0x01 -#define BMCFLAG_16KCHRR 0x02 -#define BMCFLAG_32KCHRR 0x04 -#define BMCFLAG_128KCHRR 0x08 -#define BMCFLAG_256KCHRR 0x10 +#define NO_INES (-1) + +#define BMCFLAG_FORCE4 0x0001 +#define BMCFLAG_16KCHRR 0x0002 +#define BMCFLAG_32KCHRR 0x0004 +#define BMCFLAG_128KCHRR 0x0008 +#define BMCFLAG_256KCHRR 0x0010 + +#define BMCFLAG_8KWRAM 0x0020 +#define BMCFLAG_16KWRAM 0x0040 +#define BMCFLAG_32KWRAM 0x0080 static BMAPPING bmap[] = { - { "11160", 299, BMC11160_Init, 0 }, - { "12-IN-1", 331, BMC12IN1_Init, 0 }, - { "13in1JY110", 295, Mapper295_Init, 0 }, - { "190in1", 300, BMC190in1_Init, 0 }, - { "22211", 132, Mapper132_Init, 0 }, - { "3D-BLOCK", 355, UNL3DBlock_Init, 0 }, - { "411120-C", 287, BMC411120C_Init, 0 }, - { "42in1ResetSwitch", 233, Mapper233_Init, 0 }, - { "43272", 242, Mapper242_Init, 0 }, - { "603-5052", 238, UNL6035052_Init, 0 }, - { "64in1NoRepeat", 314, BMC64in1nr_Init, 0 }, - { "70in1", 236, Mapper236_Init, 0 }, - { "70in1B", 236, Mapper236_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 }, - { "AB-G1L", 428, Mapper428_Init, 0 }, - { "WELL-NO-DG450", 428, Mapper428_Init, 0 }, - { "TF2740", 428, Mapper428_Init, 0 }, - { "AC08", 42, AC08_Init, 0 }, - { "ANROM", 7, ANROM_Init, 0 }, - { "AX5705", 530, UNLAX5705_Init, 0 }, - { "BB", 108, Mapper108_Init, 0 }, - { "BS-110", 444, Mapper444_Init, 0 }, /* Due to a mix-up, UNIF MAPR BMC-BS-110 is actually the NC7000M PCB and refers to NES 2.0 Mapper 444 instead. */ - { "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 }, - { "T3H53", 59, BMCD1038_Init, 0 }, - { "DANCE", 256, UNLOneBus_Init, 0 }, - { "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, Mapper162_Init, 0 }, - { "G-146", 349, BMCG146_Init, 0 }, - { "GK-192", 58, Mapper58_Init, 0 }, - { "GS-2004", 283, Mapper283_Init, 0 }, - { "GS-2013", 283, Mapper283_Init, 0 }, - { "Ghostbusters63in1", 226, Mapper226_Init, 0 }, - { "G631", 226, Mapper226_Init, 0 }, /* duplicate, probably wrong name */ - { "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", 108, Mapper108_Init, 0 }, - { "LH10", 522, LH10_Init, 0 }, - { "LH32", 125, LH32_Init, 0 }, - { "LH53", 535, LH53_Init, 0 }, - { "MALISB", 325, UNLMaliSB_Init, 0 }, - { "MARIO1-MALEE2", 55, 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, Mapper201_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, Mapper136_Init, 0 }, - { "SA-0036", 149, SA0036_Init, 0 }, - { "SA-0037", 148, SA0037_Init, 0 }, - { "SA-009", 160, SA009_Init, 0 }, - { "SA-016-1M", 79, Mapper79_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, Mapper35_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", 150, S74LS374N_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 }, - { "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, Mapper147_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 }, - { "MINDKIDS", 268, MINDKIDS_Init, BMCFLAG_256KCHRR }, - { "158B", 258, UNL8237_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, WAIXINGFS005_Init, 0 }, - { "80013-B", 274, BMC80013B_Init, 0 }, - { "TH2131-1", 308, UNLTH21311_Init, 0 }, - { "LH51", 309, LH51_Init, 0 }, - { "RESETNROM-XIN1", 343, BMCRESETNROMXIN1_Init, 0 }, /* split roms */ - { "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 }, - { "KS7021A", 525, UNLKS7021A_Init, 0 }, - { "KS106C", 352, BMCKS106C_Init, 0 }, - { "900218", 524, BTL900218_Init, 0 }, - { "JC-016-2", 205, Mapper205_Init, 0 }, - { "AX-40G", 527, UNLAX40G_Init, 0 }, - { "STREETFIGTER-GAME4IN1", 49, Mapper49_Init, 0 }, /* mapper 49? submapper 1*/ - { "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 }, - { "KG256", NO_INES, KG256_Init, 0 }, - { "T4A54A", 134, Mapper134_Init, 0 }, - { "WX-KB4K", 134, Mapper134_Init, 0 }, - { "SB-5013", 359, Mapper359_Init, 0 }, - { "82112C", 540, Mapper540_Init, 0 }, - { "N49C-300", 369, Mapper369_Init, 0 }, - { "830752C", 396, Mapper396_Init, 0 }, - - { "BS-400R", 422, Mapper422_Init, 0 }, - { "BS-4040R", 422, Mapper422_Init, 0 }, - { "22026", 271, Mapper271_Init, 0 }, - { "DS-07", 439, Mapper439_Init, 0 }, - { "K86B", 439, Mapper439_Init, 0 }, - { "S-2009", 434, Mapper434_Init, 0 }, - { "COOLGIRL", 342, COOLGIRL_Init, BMCFLAG_256KCHRR }, - { "DG574B", 445, Mapper445_Init, 0 }, - { "831128C", 528, Mapper528_Init, 0 }, - { "K-3010", 438, Mapper438_Init, 0 }, - { "K-3071", 438, Mapper438_Init, 0 }, - - { NULL, NO_INES, NULL, 0 } + { "NROM", 0, 0, Mapper000_Init, 0 }, + { "NROM-128", 0, 0, Mapper000_Init, 0 }, + { "NROM-256", 0, 0, Mapper000_Init, 0 }, + { "RROM", 0, 0, Mapper000_Init, 0 }, + { "RROM-128", 0, 0, Mapper000_Init, 0 }, + { "SBROM", 1, 0, Mapper001_Init, 0 }, + { "SCROM", 1, 0, Mapper001_Init, 0 }, + { "SEROM", 1, 0, Mapper001_Init, 0 }, + { "SGROM", 1, 0, Mapper001_Init, 0 }, + { "SL1ROM", 1, 0, Mapper001_Init, 0 }, + { "SLROM", 1, 0, Mapper001_Init, 0 }, + { "SAROM", 1, 0, SAROM_Init, 0 }, + { "SKROM", 1, 0, SKROM_Init, 0 }, + { "SNROM", 1, 0, SNROM_Init, 0 }, + { "SOROM", 1, 0, SOROM_Init, 0 }, + { "UNROM", 2, 0, Mapper002_Init, 0 }, + { "UOROM", 2, 0, Mapper002_Init, 0 }, + { "CNROM", 3, 0, Mapper003_Init, 0 }, + { "HKROM", 4, 0, Mapper004_Init, 0 }, /* 1K WRAM, mapper 004.1 */ + { "TBROM", 4, 0, Mapper004_Init, 0 }, + { "TEROM", 4, 0, Mapper004_Init, 0 }, + { "TFROM", 4, 0, Mapper004_Init, 0 }, + { "TGROM", 4, 0, Mapper004_Init, 0 }, + { "TKROM", 4, 0, Mapper004_Init, 0 }, + { "TLROM", 4, 0, Mapper004_Init, 0 }, + { "TSROM", 4, 0, Mapper004_Init, 0 }, + { "TVROM", 4, 0, Mapper004_Init, BMCFLAG_FORCE4 }, + { "TR1ROM", 4, 0, Mapper004_Init, BMCFLAG_FORCE4 }, + { "EKROM", 5, 0, EKROM_Init, 0 }, + { "ELROM", 5, 0, ELROM_Init, 0 }, + { "ETROM", 5, 0, ETROM_Init, 0 }, + { "EWROM", 5, 0, EWROM_Init, 0 }, + { "ANROM", 7, 0, Mapper007_Init, 0 }, + { "CPROM", 13, 0, Mapper013_Init, BMCFLAG_16KCHRR }, + { "SL1632", 14, 0, Mapper014_Init, 0 }, + { "CC-21", 27, 0, Mapper027_Init, 0 }, + { "RET-CUFROM", 29, 0, Mapper029_Init, BMCFLAG_32KCHRR }, + { "UNROM-512-8", 30, 0, Mapper030_Init, 0 }, + { "UNROM-512-16", 30, 0, Mapper030_Init, BMCFLAG_16KCHRR }, + { "UNROM-512-32", 30, 0, Mapper030_Init, BMCFLAG_32KCHRR }, + { "SC-127", 35, 0, Mapper035_Init, 0 }, + { "AC08", 42, 0, Mapper042_Init, 0 }, + { "SuperHIK8in1", 45, 0, Mapper045_Init, 0 }, + { "STREETFIGTER-GAME4IN1", 49, 0, Mapper049_Init, 0 }, /* mapper 49? submapper 1*/ + { "Supervision16in1", 53, 0, Mapper053_Init, 0 }, + { "MARIO1-MALEE2", 55, 0, Mapper055_Init, 0 }, + { "GK-192", 58, 0, Mapper058_Init, 0 }, + { "D1038", 59, 0, Mapper059_Init, 0 }, + { "T3H53", 59, 0, Mapper059_Init, 0 }, + { "MHROM", 66, 0, Mapper066_Init, 0 }, + { "NTBROM", 68, 0, Mapper068_Init, 0 }, + { "SA-016-1M", 79, 0, Mapper079_Init, 0 }, + { "VRC7", 85, 0, Mapper085_Init, 0 }, + { "TEK90", 90, 0, Mapper090_Init, 0 }, + { "SUNSOFT_UNROM", 93, 0, Mapper093_Init, 0 }, /* fix me, real pcb name, real pcb type */ + { "BB", 108, 0, Mapper108_Init, 0 }, + { "LE05", 108, 0, Mapper108_Init, 0 }, + { "SL12", 116, 0, Mapper116_Init, 0 }, + { "TKSROM", 118, 0, Mapper118_Init, 0 }, + { "TLSROM", 118, 0, Mapper118_Init, 0 }, + { "TQROM", 119, 0, Mapper119_Init, 0 }, + { "H2288", 123, 0, Mapper123_Init, 0 }, + { "LH32", 125, 0, Mapper125_Init, 0 }, + { "22211", 132, 0, Mapper132_Init, 0 }, + { "SA-72008", 133, 0, Mapper133_Init, 0 }, + { "T4A54A", 134, 0, Mapper134_Init, 0 }, + { "WX-KB4K", 134, 0, Mapper134_Init, 0 }, + { "SA-002", 136, 0, Mapper136_Init, 0 }, + { "Sachen-8259D", 137, 0, Mapper137_Init, 0 }, + { "Sachen-8259B", 138, 0, Mapper138_Init, 0 }, + { "Sachen-8259C", 139, 0, Mapper139_Init, 0 }, + { "Sachen-8259A", 141, 0, Mapper141_Init, 0 }, + { "KS7032", 142, 0, Mapper142_Init, 0 }, + { "SA-NROM", 143, 0, Mapper143_Init, 0 }, + { "SA-72007", 145, 0, Mapper145_Init, 0 }, + { "TC-U01-1.5M", 147, 0, Mapper147_Init, 0 }, + { "SA-0037", 148, 0, Mapper148_Init, 0 }, + { "SA-0036", 149, 0, Mapper149_Init, 0 }, + { "Sachen-74LS374N", 150, 0, Mapper150_Init, 0 }, + { "Sachen-74LS374NA", 150, 0, Mapper150_Init, 0 }, /* seems to be custom mapper */ +/* { "SA-009", 160, 0, Mapper160_Init, 0 }, */ + { "FS304", 162, 0, Mapper162_Init, 0 }, + { "FK23C", 176, 0, BMCFK23C_Init, BMCFLAG_256KCHRR }, + { "FK23CA", 176, 0, BMCFK23CA_Init, BMCFLAG_256KCHRR }, + { "Super24in1SC03", 176, 0, Super24_Init, 0 }, + { "WAIXING-FS005", 176, 0, WAIXINGFS005_Init, 0 }, + { "NovelDiamond9999999in1", 201, 0, Mapper201_Init, 0 }, + { "JC-016-2", 205, 0, Mapper205_Init, 0 }, + { "8237", 215, 0, Mapper215_Init, 0 }, + { "8237A", 215, 0, Mapper215_Init, 0 }, /* m215 sub 1*/ + { "N625092", 221, 0, Mapper221_Init, 0 }, + { "Ghostbusters63in1", 226, 0, Mapper226_Init, 0 }, + { "G631", 226, 0, Mapper226_Init, 0 }, /* duplicate, probably wrong name */ + { "WAIXING-FW01", 227, 0, Mapper227_Init, 0 }, + { "42in1ResetSwitch", 233, 0, Mapper233_Init, 0 }, + { "70in1", 236, 0, Mapper236_Init, 0 }, + { "70in1B", 236, 0, Mapper236_Init, 0 }, + { "603-5052", 238, 0, Mapper238_Init, 0 }, + { "43272", 242, 0, Mapper242_Init, 0 }, + { "DANCE", 256, 0, Mapper256_Init, 0 }, + { "OneBus", 256, 0, Mapper256_Init, 0 }, + { "PEC-586", 257, 0, Mapper257_Init, 0 }, + { "158B", 258, 0, Mapper215_Init, 0 }, + { "F-15", 259, 0, Mapper259_Init, 0 }, + { "HPxx", 260, 0, Mapper260_Init, 0 }, + { "HP2018-A", 260, 0, Mapper260_Init, 0 }, + { "810544-C-A1", 261, 0, Mapper261_Init, 0 }, + { "SHERO", 262, 0, Mapper262_Init, BMCFLAG_FORCE4 }, + { "KOF97", 263, 0, Mapper263_Init, 0 }, + { "YOKO", 264, 0, Mapper264_Init, 0 }, + { "T-262", 265, 0, Mapper265_Init, 0 }, + { "CITYFIGHT", 266, 0, Mapper266_Init, 0 }, + { "COOLBOY", 268, 0, COOLBOY_Init, BMCFLAG_256KCHRR }, + { "MINDKIDS", 268, 0, MINDKIDS_Init, BMCFLAG_256KCHRR }, + { "22026", 271, 0, Mapper271_Init, 0 }, + { "80013-B", 274, 0, Mapper274_Init, 0 }, + { "GS-2004", 283, 0, Mapper283_Init, 0 }, + { "GS-2013", 283, 0, Mapper283_Init, 0 }, + { "A65AS", 285, 0, Mapper285_Init, 0 }, + { "BS-5", 286, 0, Mapper286_Init, 0 }, + { "411120-C", 287, 0, Mapper287_Init, 0 }, + { "K-3088", 287, 0, Mapper287_Init, 0 }, + { "60311C", 289, 0, Mapper289_Init, 0 }, + { "NTD-03", 290, 0, Mapper290_Init, 0 }, + { "DRAGONFIGHTER", 292, 0, Mapper292_Init, 0 }, + { "13in1JY110", 295, 0, Mapper295_Init, 0 }, + { "TF1201", 298, 0, Mapper298_Init, 0 }, + { "11160", 299, 0, Mapper299_Init, 0 }, + { "190in1", 300, 0, Mapper300_Init, 0 }, + { "8157", 301, 0, Mapper301_Init, 0 }, + { "KS7057", 302, 0, Mapper302_Init, 0 }, + { "KS7017", 303, 0, Mapper303_Init, 0 }, + { "SMB2J", 304, 0, Mapper304_Init, 0 }, + { "KS7031", 305, 0, Mapper305_Init, 0 }, + { "KS7016", 306, 0, Mapper306_Init, 0 }, + { "KS7037", 307, 0, Mapper307_Init, 0 }, + { "TH2131-1", 308, 0, Mapper308_Init, 0 }, + { "LH51", 309, 0, Mapper309_Init, 0 }, + { "KS7013B", 312, 0, Mapper312_Init, 0 }, + { "RESET-TXROM", 313, 0, Mapper313_Init, 0 }, + { "64in1NoRepeat", 314, 0, Mapper314_Init, 0 }, + { "830134C", 315, 0, Mapper315_Init, 0 }, + { "HP898F", 319, 0, Mapper319_Init, 0 }, /* UNIF implementation of mapper 319 */ + { "830425C-4391T", 320, 0, Mapper320_Init, 0 }, + { "K-3033", 322, 0, Mapper322_Init, 0 }, + { "FARID_SLROM_8-IN-1", 323, 0, Mapper323_Init, 0 }, + { "FARID_UNROM_8-IN-1", 324, 0, Mapper324_Init, 0 }, + { "MALISB", 325, 0, Mapper325_Init, 0 }, + { "10-24-C-A1", 327, 0, Mapper327_Init, 0 }, + { "RT-01", 328, 0, Mapper328_Init, 0 }, + { "EDU2000", 329, 0, Mapper329_Init, 0 }, + { "12-IN-1", 331, 0, Mapper331_Init, 0 }, + { "WS", 332, 0, Mapper332_Init, 0 }, + { "8-IN-1", 333, 0, Mapper333_Init, 0 }, + { "NEWSTAR-GRM070-8IN1", 333, 0, Mapper333_Init, 0 }, + { "CTC-09", 335, 0, Mapper335_Init, 0 }, + { "K-3046", 336, 0, Mapper336_Init, 0 }, + { "CTC-12IN1", 337, 0, Mapper337_Init, 0 }, + { "SA005-A", 338, 0, Mapper338_Init, 0 }, + { "K-3006", 339, 0, Mapper339_Init, 0 }, + { "K-3036", 340, 0, Mapper340_Init, 0 }, + { "TJ-03", 341, 0, Mapper341_Init, 0 }, + { "COOLGIRL", 342, 0, COOLGIRL_Init, BMCFLAG_256KCHRR }, + { "RESETNROM-XIN1", 343, 0, Mapper343_Init, 0 }, + { "GN-26", 344, 0, Mapper344_Init, 0 }, + { "L6IN1", 345, 0, Mapper345_Init, 0 }, + { "KS7012", 346, 0, Mapper346_Init, 0 }, + { "KS7030", 347, 0, Mapper347_Init, 0 }, + { "830118C", 348, 0, Mapper348_Init, 0 }, + { "G-146", 349, 0, Mapper349_Init, 0 }, + { "891227", 350, 0, Mapper350_Init, 0 }, + { "KS106C", 352, 0, Mapper352_Init, 0 }, + { "3D-BLOCK", 355, 0, UNL3DBlock_Init, 0 }, + { "SB-5013", 359, 0, Mapper359_Init, 0 }, + { "N49C-300", 369, 0, Mapper369_Init, 0 }, + { "830752C", 396, 0, Mapper396_Init, 0 }, + { "GOLDEN-16IN1-SPC001", 396, 0, Mapper396_Init, 0 }, + { "BS-400R", 422, 0, Mapper422_Init, 0 }, + { "BS-4040R", 422, 0, Mapper422_Init, 0 }, + { "AB-G1L", 428, 0, Mapper428_Init, 0 }, + { "WELL-NO-DG450", 428, 0, Mapper428_Init, 0 }, + { "TF2740", 428, 0, Mapper428_Init, 0 }, + { "S-2009", 434, 0, Mapper434_Init, 0 }, + { "K-3010", 438, 0, Mapper438_Init, 0 }, + { "K-3071", 438, 0, Mapper438_Init, 0 }, + { "DS-07", 439, 0, Mapper439_Init, 0 }, + { "K86B", 439, 0, Mapper439_Init, 0 }, + { "BS-110", 444, 0, Mapper444_Init, 0 }, /* Due to a mix-up, UNIF MAPR BMC-BS-110 is actually the NC7000M PCB and refers to NES 2.0 Mapper 444 instead. */ + { "DG574B", 445, 0, Mapper445_Init, 0 }, + { "SA-9602B", 513, 0, Mapper513_Init, BMCFLAG_32KCHRR }, + { "DANCE2000", 518, 0, Mapper518_Init, 0 }, + { "EH8813A", 519, 0, Mapper519_Init, 0 }, + { "DREAMTECH01", 521, 0, Mapper521_Init, 0 }, + { "LH10", 522, 0, Mapper522_Init, 0 }, + { "900218", 524, 0, Mapper524_Init, 0 }, + { "KS7021A", 525, 0, Mapper525_Init, 0 }, + { "BJ-56", 526, 0, Mapper526_Init, 0 }, + { "AX-40G", 527, 0, Mapper527_Init, 0 }, + { "831128C", 528, 0, Mapper528_Init, 0 }, + { "T-230", 529, 0, Mapper529_Init, 0 }, + { "AX5705", 530, 0, Mapper530_Init, 0 }, + { "LH53", 535, 0, Mapper535_Init, 0 }, + { "82112C", 540, 0, Mapper540_Init, 0 }, + { "KONAMI-QTAI", 547, 0, Mapper547_Init, 0 }, + + { "SSS-NROM-256", NO_INES, 0, SSSNROM_Init, 0 }, /* famicombox - cant find similar cart */ + { "T-227-1", NO_INES, 0, BMCT2271_Init, 0 }, /* cant find similar cart */ + { "Transformer", NO_INES, 0, Transformer_Init, 0 }, + { "81-01-31-C", NO_INES, 0, BMC810131C_Init, 0 }, /* might be mapper 327 with m118-like mirroring */ + { "KG256", NO_INES, 0, KG256_Init, 0 }, /* cant find similar cart */ + { "CHINA_ER_SAN2", NO_INES, 0, Mapper019_Init, 0 }, /* Needs more than just what mapper 19 can handle */ + + { NULL, NO_INES, 0, NULL, 0 } }; static BFMAPPING bfunc[] = { @@ -651,7 +665,7 @@ static BFMAPPING bfunc[] = { { NULL, NULL } }; -int LoadUNIFChunks(FCEUFILE *fp) { +static int LoadUNIFChunks(FCEUFILE *fp) { int x; int t; for (;; ) { @@ -689,7 +703,7 @@ static int InitializeBoard(void) { /* ignore case during board name comparing */ if (string_is_equal_noncase((const char*)sboardname, (const char*)bmap[x].name)) { - if (VROM_size == 0) { + if (ROM.chr.size == 0) { if (bmap[x].flags & BMCFLAG_16KCHRR) CHRRAMSize = 16; else if (bmap[x].flags & BMCFLAG_32KCHRR) @@ -700,7 +714,7 @@ static int InitializeBoard(void) { CHRRAMSize = 256; else CHRRAMSize = 8; - CHRRAMSize <<= 10; + CHRRAMSize <<= 10; if ((UNIFchrrama = (uint8*)FCEU_malloc(CHRRAMSize))) { SetupCartCHRMapping(0, UNIFchrrama, CHRRAMSize, 1); AddExState(UNIFchrrama, CHRRAMSize, 0, "CHRR"); @@ -711,11 +725,14 @@ static int InitializeBoard(void) { mirrortodo = 4; MooMirroring(); - UNIFCart.mapper = bmap[x].ines_mapper; - UNIFCart.submapper = submapper; + if (bmap[x].mapper >= 0) { + iNESCart.mapper = bmap[x].mapper; + } + + iNESCart.submapper = submapper; GameInfo->cspecial = cspecial; - bmap[x].init(&UNIFCart); + bmap[x].init(&iNESCart); return(1); } x++; @@ -728,17 +745,16 @@ static int InitializeBoard(void) { static void UNIFGI(int h) { switch (h) { case GI_RESETM2: - if (UNIFCart.Reset) - UNIFCart.Reset(); + if (iNESCart.Reset) + iNESCart.Reset(); break; case GI_POWER: - if (UNIFCart.Power) - UNIFCart.Power(); + if (iNESCart.Power) + iNESCart.Power(); if (UNIFchrrama) memset(UNIFchrrama, 0, 8192); break; case GI_CLOSE: - if (UNIFCart.Close) - UNIFCart.Close(); + if (iNESCart.Close) iNESCart.Close(); FreeUNIF(); break; } @@ -771,11 +787,11 @@ int UNIFLoad(const char *name, FCEUFILE *fp) { return 0; } - ROM_size = (UNIF_PRGROMSize / 0x1000) + ((UNIF_PRGROMSize % 0x1000) ? 1 : 0); - ROM_size = (ROM_size >> 2) + ((ROM_size & 3) ? 1: 0); + ROM.prg.size = (UNIF_PRGROMSize / 0x1000) + ((UNIF_PRGROMSize % 0x1000) ? 1 : 0); + ROM.prg.size = (ROM.prg.size >> 2) + ((ROM.prg.size & 3) ? 1: 0); if (UNIF_CHRROMSize) { - VROM_size = (UNIF_CHRROMSize / 0x400) + ((UNIF_CHRROMSize % 0x400) ? 1 : 0); - VROM_size = (VROM_size >> 3) + ((VROM_size & 7) ? 1: 0); + ROM.chr.size = (UNIF_CHRROMSize / 0x400) + ((UNIF_CHRROMSize % 0x400) ? 1 : 0); + ROM.chr.size = (ROM.chr.size >> 3) + ((ROM.chr.size & 7) ? 1: 0); } UNIF_PRGROMSize = FixRomSize(UNIF_PRGROMSize, 2048); @@ -784,12 +800,12 @@ int UNIFLoad(const char *name, FCEUFILE *fp) { /* Note: Use rounded size for memory allocations and board mapping */ - if (!(ROM = (uint8*)malloc(UNIF_PRGROMSize))) { + if (!(ROM.prg.data = (uint8*)malloc(UNIF_PRGROMSize))) { Cleanup(); return 0; } if (UNIF_CHRROMSize) { - if (!(VROM = (uint8*)malloc(UNIF_CHRROMSize))) { + if (!(ROM.chr.data = (uint8*)malloc(UNIF_CHRROMSize))) { Cleanup(); return 0; } @@ -801,14 +817,14 @@ int UNIFLoad(const char *name, FCEUFILE *fp) { int p = prg_idx[x]; int c = 16 + chr_idx[x]; if (malloced[p]) { - memcpy(ROM + prg_size_bytes, malloced[p], mallocedsizes[p]); + memcpy(ROM.prg.data + prg_size_bytes, malloced[p], mallocedsizes[p]); prg_size_bytes += mallocedsizes[p]; free(malloced[p]); malloced[p] = 0; } if (malloced[c]) { - memcpy(VROM + chr_size_bytes, malloced[c], mallocedsizes[c]); + memcpy(ROM.chr.data + chr_size_bytes, malloced[c], mallocedsizes[c]); chr_size_bytes += mallocedsizes[c]; free(malloced[c]); malloced[c] = 0; @@ -817,41 +833,41 @@ int UNIFLoad(const char *name, FCEUFILE *fp) { /* Note: Use raw size in bytes for checksums */ - UNIFCart.PRGRomSize = prg_size_bytes; - UNIFCart.CHRRomSize = chr_size_bytes; + iNESCart.PRGRomSize = prg_size_bytes; + iNESCart.CHRRomSize = chr_size_bytes; - UNIFCart.PRGCRC32 = CalcCRC32(0, ROM, prg_size_bytes); - UNIFCart.CHRCRC32 = CalcCRC32(0, VROM, chr_size_bytes); - UNIFCart.CRC32 = CalcCRC32(UNIFCart.PRGCRC32, VROM, chr_size_bytes); + iNESCart.PRGCRC32 = CalcCRC32(0, ROM.prg.data, prg_size_bytes); + iNESCart.CHRCRC32 = CalcCRC32(0, ROM.chr.data, chr_size_bytes); + iNESCart.CRC32 = CalcCRC32(iNESCart.PRGCRC32, ROM.chr.data, chr_size_bytes); md5_starts(&md5); - md5_update(&md5, ROM, prg_size_bytes); + md5_update(&md5, ROM.prg.data, prg_size_bytes); if (chr_size_bytes) - md5_update(&md5, VROM, chr_size_bytes); - md5_finish(&md5, UNIFCart.MD5); - memcpy(GameInfo->MD5, UNIFCart.MD5, sizeof(UNIFCart.MD5)); + md5_update(&md5, ROM.chr.data, chr_size_bytes); + md5_finish(&md5, iNESCart.MD5); + memcpy(GameInfo->MD5, iNESCart.MD5, sizeof(iNESCart.MD5)); CheckHashInfo(); /* Note: Use rounded size for board mappings */ - SetupCartPRGMapping(0, ROM, UNIF_PRGROMSize, 0); + SetupCartPRGMapping(0, ROM.prg.data, UNIF_PRGROMSize, 0); if (UNIF_CHRROMSize) - SetupCartCHRMapping(0, VROM, UNIF_CHRROMSize, 0); + SetupCartCHRMapping(0, ROM.chr.data, UNIF_CHRROMSize, 0); - FCEU_printf(" PRG-ROM CRC32: 0x%08X\n", UNIFCart.PRGCRC32); - FCEU_printf(" PRG+CHR CRC32: 0x%08X\n", UNIFCart.CRC32); - FCEU_printf(" PRG+CHR MD5 : 0x%s\n", md5_asciistr(UNIFCart.MD5)); + FCEU_printf(" PRG-ROM CRC32: 0x%08X\n", iNESCart.PRGCRC32); + FCEU_printf(" PRG+CHR CRC32: 0x%08X\n", iNESCart.CRC32); + FCEU_printf(" PRG+CHR MD5 : 0x%s\n", md5_asciistr(iNESCart.MD5)); if (!InitializeBoard()) { Cleanup(); return 0; } - FCEU_printf(" [UNIF] PRG ROM: %u KiB\n", UNIFCart.PRGRomSize / 1024); - FCEU_printf(" [UNIF] CHR ROM: %u KiB\n", UNIFCart.CHRRomSize / 1024); - FCEU_printf(" [UNIF] iNES Mapper: %d\n", UNIFCart.mapper); - FCEU_printf(" [UNIF] SubMapper: %d\n", UNIFCart.submapper); + FCEU_printf(" [UNIF] PRG ROM: %u KiB\n", iNESCart.PRGRomSize / 1024); + FCEU_printf(" [UNIF] CHR ROM: %u KiB\n", iNESCart.CHRRomSize / 1024); + FCEU_printf(" [UNIF] iNES Mapper: %d\n", iNESCart.mapper); + FCEU_printf(" [UNIF] SubMapper: %d\n", iNESCart.submapper); GameInterface = UNIFGI; diff --git a/src/unif.h b/src/unif.h index ffba7bc03..4797c798a 100644 --- a/src/unif.h +++ b/src/unif.h @@ -21,167 +21,31 @@ #ifndef _FCEU_UNIF_H #define _FCEU_UNIF_H -void AC08_Init(CartInfo *info); -void ANROM_Init(CartInfo *info); -void BMC11160_Init(CartInfo *info); -void BMC12IN1_Init(CartInfo *info); -void BMC190in1_Init(CartInfo *info); -void BMC411120C_Init(CartInfo *info); -void BMC64in1nr_Init(CartInfo *info); -void BMC810544CA1_Init(CartInfo *info); -void BMC830118C_Init(CartInfo *info); -void BMCA65AS_Init(CartInfo *info); -void BMCBS5_Init(CartInfo *info); -void BMCD1038_Init(CartInfo *info); -void BMCFK23CA_Init(CartInfo *info); -void BMCFK23C_Init(CartInfo *info); -void BMCG146_Init(CartInfo *info); -void BMCGhostbusters63in1_Init(CartInfo *info); -void BMCNTD03_Init(CartInfo *info); -void BMCT2271_Init(CartInfo *info); -void BMCT262_Init(CartInfo *info); -void BMC1024CA1_Init(CartInfo *info); -void CNROM_Init(CartInfo *info); -void CPROM_Init(CartInfo *info); -void DreamTech01_Init(CartInfo *info); -void EKROM_Init(CartInfo *info); -void ELROM_Init(CartInfo *info); -void ETROM_Init(CartInfo *info); -void EWROM_Init(CartInfo *info); -void GNROM_Init(CartInfo *info); -void HKROM_Init(CartInfo *info); -void LH10_Init(CartInfo *info); -void LH32_Init(CartInfo *info); -void LH53_Init(CartInfo *info); -void MALEE_Init(CartInfo *info); -void MHROM_Init(CartInfo *info); -void Mapper190_Init(CartInfo *info); -void NROM_Init(CartInfo *info); -void S74LS374NA_Init(CartInfo *info); -void S74LS374N_Init(CartInfo *info); -void S8259A_Init(CartInfo *info); -void S8259B_Init(CartInfo *info); -void S8259C_Init(CartInfo *info); -void S8259D_Init(CartInfo *info); -void SA0036_Init(CartInfo *info); -void SA0037_Init(CartInfo *info); -void SA009_Init(CartInfo *info); -void SA0161M_Init(CartInfo *info); -void SA72007_Init(CartInfo *info); -void SA72008_Init(CartInfo *info); -void SA9602B_Init(CartInfo *info); -void SAROM_Init(CartInfo *info); -void SBROM_Init(CartInfo *info); -void SCROM_Init(CartInfo *info); -void SEROM_Init(CartInfo *info); -void SGROM_Init(CartInfo *info); -void SKROM_Init(CartInfo *info); -void SL1ROM_Init(CartInfo *info); -void SLROM_Init(CartInfo *info); -void SNROM_Init(CartInfo *info); -void SOROM_Init(CartInfo *info); -void SSSNROM_Init(CartInfo *info); -void SUNSOFT_UNROM_Init(CartInfo *info); /* "Shanghi" original version mapper */ -void Super24_Init(CartInfo *info); -void Supervision16_Init(CartInfo *info); -void TBROM_Init(CartInfo *info); -void TCA01_Init(CartInfo *info); -void TEROM_Init(CartInfo *info); -void TFROM_Init(CartInfo *info); -void TGROM_Init(CartInfo *info); -void TKROM_Init(CartInfo *info); -void TKSROM_Init(CartInfo *info); -void TLROM_Init(CartInfo *info); -void TLSROM_Init(CartInfo *info); -void TQROM_Init(CartInfo *info); -void TQROM_Init(CartInfo *info); -void TSROM_Init(CartInfo *info); -void Transformer_Init(CartInfo *info); -void UNL3DBlock_Init(CartInfo *info); -void UNL43272_Init(CartInfo *info); -void UNL6035052_Init(CartInfo *info); -void UNL8157_Init(CartInfo *info); -void UNL8237A_Init(CartInfo *info); -void UNL8237_Init(CartInfo *info); -void UNLA9746_Init(CartInfo *info); -void UNLAX5705_Init(CartInfo *info); -void UNLCC21_Init(CartInfo *info); -void UNLCITYFIGHT_Init(CartInfo *info); -void UNLD2000_Init(CartInfo *info); -void UNLEDU2000_Init(CartInfo *info); -void UNLH2288_Init(CartInfo *info); -void UNLKOF97_Init(CartInfo *info); -void UNLKS7012_Init(CartInfo *info); -void UNLKS7013B_Init(CartInfo *info); -void UNLKS7016_Init(CartInfo *info); -void UNLKS7017_Init(CartInfo *info); -void UNLKS7030_Init(CartInfo *info); -void UNLKS7031_Init(CartInfo *info); -void UNLKS7032_Init(CartInfo *info); -void UNLKS7037_Init(CartInfo *info); -void UNLKS7057_Init(CartInfo *info); -void UNLN625092_Init(CartInfo *info); -void UNLMaliSB_Init(CartInfo *info); -void UNLOneBus_Init(CartInfo *info); -void UNLPEC586Init(CartInfo *info); -void UNLSHeroes_Init(CartInfo *info); -void UNLSL12_Init(CartInfo *info); -void UNLSL1632_Init(CartInfo *info); -void UNLSMB2J_Init(CartInfo *info); -void UNLT230_Init(CartInfo *info); -void UNLTF1201_Init(CartInfo *info); -void UNLVRC7_Init(CartInfo *info); -void UNLYOKO_Init(CartInfo *info); -void UNROM_Init(CartInfo *info); -void UNROM512_Init(CartInfo *info); -void COOLBOY_Init(CartInfo *info); -void UNLBMW8544_Init(CartInfo *info); -void UNLEH8813A_Init(CartInfo *info); -void BMCHP898F_Init(CartInfo *info); -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 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 */ -void COOLGIRL_Init(CartInfo *info); /* m342 */ - -void KG256_Init(CartInfo *info); -void WAIXINGFS005_Init(CartInfo *info); - -void Mapper422_Init(CartInfo *info); -void Mapper444_Init(CartInfo *info); +void BMCFK23CA_Init(CartInfo *); +void BMCFK23C_Init(CartInfo *); +void BMCT2271_Init(CartInfo *); +void EKROM_Init(CartInfo *); +void ELROM_Init(CartInfo *); +void ETROM_Init(CartInfo *); +void EWROM_Init(CartInfo *); +void GNROM_Init(CartInfo *); +void S74LS374NA_Init(CartInfo *); +void SA0161M_Init(CartInfo *); +void SAROM_Init(CartInfo *); +void SKROM_Init(CartInfo *); +void SNROM_Init(CartInfo *); +void SOROM_Init(CartInfo *); +void SSSNROM_Init(CartInfo *); +void Super24_Init(CartInfo *); +void Transformer_Init(CartInfo *); +void UNL3DBlock_Init(CartInfo *); +void UNL43272_Init(CartInfo *); +void COOLBOY_Init(CartInfo *); +void MINDKIDS_Init(CartInfo *); /* m268 */ +void BMC810131C_Init(CartInfo *); +void COOLGIRL_Init(CartInfo *); /* m342 */ +void KG256_Init(CartInfo *); +void WAIXINGFS005_Init(CartInfo *); extern uint8 *UNIFchrrama; /* Meh. So I can stop CHR RAM * bank switcherooing with certain boards... diff --git a/src/video.c b/src/video.c index cdd492012..9a59bb1de 100644 --- a/src/video.c +++ b/src/video.c @@ -38,31 +38,32 @@ uint8 *XBuf = NULL; uint8 *XDBuf = NULL; -int show_crosshair = 0; void FCEU_KillVirtualVideo(void) { if (XBuf) - free(XBuf); - XBuf = 0; + FCEU_afree(XBuf); + XBuf = NULL; if (XDBuf) - free(XDBuf); - XDBuf = 0; + FCEU_afree(XDBuf); + XDBuf = NULL; } int FCEU_InitVirtualVideo(void) { + if (XBuf) return 1; + /* 256 bytes per scanline, * 240 scanline maximum, +8 for alignment, */ if (!XBuf) - XBuf = (uint8*)(FCEU_malloc(256 * (256 + ppu.extrascanlines + 8))); + XBuf = (uint8*)FCEU_amalloc(256 * 256); if (!XDBuf) - XDBuf = (uint8*)(FCEU_malloc(256 * (256 + ppu.extrascanlines + 8))); + XDBuf = (uint8*)FCEU_amalloc(256 * 256); if (!XBuf || !XDBuf) return 0; - memset(XBuf, 128, 256 * (256 + ppu.extrascanlines + 8)); - memset(XDBuf, 128, 256 * (256 + ppu.extrascanlines + 8)); + memset(XBuf, 0, 256 * 256); + memset(XDBuf, 0, 256 * 256); return 1; } @@ -77,25 +78,12 @@ void FCEU_PutImage(void) if (GameInfo->type == GIT_VSUNI) FCEU_VSUniDraw(XBuf); } - if (show_crosshair) + if (FSettings.ShowCrosshair) FCEU_DrawInput(XBuf); } +#ifdef FRAMESKIP void FCEU_PutImageDummy(void) { } - -void FCEU_DispMessage(enum retro_log_level level, unsigned duration, const char *format, ...) -{ - static char msg[512] = {0}; - va_list ap; - - if (!format || (*format == '\0')) - return; - - va_start(ap, format); - vsprintf(msg, format, ap); - va_end(ap); - - FCEUD_DispMessage(level, duration, msg); -} +#endif \ No newline at end of file diff --git a/src/video.h b/src/video.h index 34873d6e1..db8b2ac3e 100644 --- a/src/video.h +++ b/src/video.h @@ -1,11 +1,11 @@ #ifndef _FCEU_VIDEO_H #define _FCEU_VIDEO_H -int FCEU_InitVirtualVideo(void); -void FCEU_KillVirtualVideo(void); extern uint8 *XBuf; extern uint8 *XDBuf; -extern int show_crosshair; -void FCEU_DrawNumberRow(uint8 *XBuf, int *nstatus, int cur); + +int FCEU_InitVirtualVideo(void); +void FCEU_KillVirtualVideo(void); +void FCEU_DrawNumberRow(uint8 *target, int *nstatus, int cur); #endif diff --git a/src/vsuni.c b/src/vsuni.c index 899ba7d70..c1767feca 100644 --- a/src/vsuni.c +++ b/src/vsuni.c @@ -24,12 +24,10 @@ #include "x6502.h" #include "fceu.h" #include "input.h" +#include "palette.h" #include "vsuni.h" #include "state.h" - -#define IOPTION_GUN 0x01 -#define IOPTION_SWAPDIRAB 0x02 -#define IOPTION_PREDIP 0x10 +#include "cart.h" typedef struct { char *name; @@ -40,136 +38,161 @@ typedef struct { int ppu; int ioption; int predip; + int type; } VSUNIENTRY; -VSUNIENTRY *curvs; +VSUNISYSTEM vsuni_system; static uint8 DIPS = 0; -uint8 vsdip = 0; void FCEUI_VSUniToggleDIPView(void) { DIPS = !DIPS; } void FCEU_VSUniToggleDIP(int w) { - vsdip ^= 1 << w; + vsuni_system.vsdip ^= 1 << w; } void FCEUI_VSUniSetDIP(int w, int state) { - if (((vsdip >> w) & 1) != state) + if (((vsuni_system.vsdip >> w) & 1) != state) FCEUI_VSUniToggleDIP(w); } uint8 FCEUI_VSUniGetDIPs(void) { - return(vsdip); + return(vsuni_system.vsdip); } static uint8 secdata[2][32] = { - { 0xff, 0xbf, 0xb7, 0x97, 0x97, 0x17, 0x57, 0x4f, + { + /* TKO Boxing */ + 0xff, 0xbf, 0xb7, 0x97, 0x97, 0x17, 0x57, 0x4f, 0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90, 0x94, 0x14, 0x56, 0x4e, 0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90, - 0xd4, 0x5c, 0x3e, 0x26, 0x87, 0x83, 0x13, 0x00 }, - { 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, + 0xd4, 0x5c, 0x3e, 0x26, 0x87, 0x83, 0x13, 0x00 + }, + { + /* RBI Baseball */ + 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + } }; -static uint8 *secptr; - static uint8 VSindex; static DECLFR(VSSecRead) { - switch (A) { - case 0x5e00: VSindex = 0; return X.DB; - case 0x5e01: return(secptr[(VSindex++) & 0x1F]); + if ((vsuni_system.type == VS_TYPE_TKO) || (vsuni_system.type == VS_TYPE_RBI)) { + if (A == 0x5e00) { + VSindex = 0; + } else if (A == 0x5e01) { + if (vsuni_system.type == VS_TYPE_TKO) { + return (secdata[0][(VSindex++) & 0x1F]); + } else if (vsuni_system.type == VS_TYPE_RBI) { + return (secdata[1][(VSindex++) & 0x1F]); + } + } + } else if (vsuni_system.type == VS_TYPE_XEVIOUS) { + if (A == 0x54FF) { + return (0x5); + } else if (A == 0x5678) { + return (VSindex ? 0 : 1); + } else if (A == 0x578F) { + return (VSindex ? 0xd1 : 0x89); + } else if (A == 0x5567) { + VSindex ^= 1; + return (VSindex ? 0x37 : 0x3E); + } } - return(0x00); + return cpu.openbus; } -uint8 coinon = 0; -void FCEU_VSUniCoin(void) { - coinon = 6; +void FCEU_VSUniCoin(int slot) { + vsuni_system.coinon[slot] = 6; } -static int curppu; -static int64 curmd5; - -#define RP2C04_0001 1 -#define RP2C04_0002 2 -#define RP2C04_0003 3 -#define RP2C04_0004 4 -#define RCP2C03B 5 -#define RC2C05_01 6 -#define RC2C05_02 7 -#define RC2C05_03 8 -#define RC2C05_04 9 +void FCEU_VSUniService(void) { + vsuni_system.service = 6; +} static readfunc OldReadPPU; static writefunc OldWritePPU[2]; -static DECLFR(A2002_Gumshoe) { - return((OldReadPPU(A) & ~0x3F) | 0x1C); +static DECLFR(rc2c05_A2002) { + return((OldReadPPU(A) & ~0x3F) | vsuni_system.rc2c05_A2002); } -static DECLFR(A2002_Topgun) { - return((OldReadPPU(A) & ~0x3F) | 0x1B); +static DECLFW(rc2c05_B2000_2001) { + A = (A ^ 1); + OldWritePPU[A & 1](A, V); } -static DECLFR(A2002_MBJ) { /* Mighty Bomb Jack */ - return((OldReadPPU(A) & ~0x3F) | 0x3D); -} +void FCEU_VSUniSwap(uint8 *j0, uint8 *j1) { + uint8 t0 = *j0; + uint8 t1 = *j1; -static DECLFW(B2000_2001_2C05) { - OldWritePPU[(A & 1) ^ 1](A ^ 1, V); -} -static uint8 xevselect = 0; -static DECLFR(XevRead) { - if (A == 0x54FF) { - return(0x5); - } else if (A == 0x5678) { - return(xevselect ? 0 : 1); - } else if (A == 0x578F) { - return(xevselect ? 0xd1 : 0x89); - } else if (A == 0x5567) { - xevselect ^= 1; - return(xevselect ? 0x37 : 0x3E); + if (vsuni_system.ioption & IOPTION_SWAPDIRAB) { + /* Swap controllers 1 and 2 expect Select/start buttons */ + *j0 = (t0 & 0x0C) | (t1 & 0xF3); + *j1 = (t1 & 0x0C) | (t0 & 0xF3); } - return(X.DB); -} -void FCEU_VSUniSwap(uint8 *j0, uint8 *j1) { - if (curvs->ioption & IOPTION_SWAPDIRAB) { - uint16 t = *j0; - *j0 = (*j0 & 0xC) | (*j1 & 0xF3); - *j1 = (*j1 & 0xC) | (t & 0xF3); - } + t0 = *j0; + t1 = *j1; + + /* swap select and start */ + *j0 = (t0 & 0xF3) | ((t0 & JOY_START) >> 1) | ((t0 & JOY_SELECT) << 1); + *j1 = (t1 & 0xF3) | ((t1 & JOY_START) >> 1) | ((t1 & JOY_SELECT) << 1); } void FCEU_VSUniPower(void) { - coinon = 0; + vsuni_system.coinon[0] = 0; + vsuni_system.coinon[1] = 0; + vsuni_system.service = 0; + VSindex = 0; - if (secptr) - SetReadHandler(0x5e00, 0x5e01, VSSecRead); + switch (vsuni_system.ppu) { + case PPU_RP2C04_0001: + case PPU_RP2C04_0002: + case PPU_RP2C04_0003: + case PPU_RP2C04_0004: + palette_nes_selected = vsuni_system.ppu; + break; + case PPU_RC2C05_01: + vsuni_system.rc2c05_enable = TRUE; + vsuni_system.rc2c05_A2002 = 0x1B; + break; + case PPU_RC2C05_02: + vsuni_system.rc2c05_enable = TRUE; + vsuni_system.rc2c05_A2002 = 0x3D; + break; + case PPU_RC2C05_03: + vsuni_system.rc2c05_enable = TRUE; + vsuni_system.rc2c05_A2002 = 0x1C; + break; + case PPU_RC2C05_04: + vsuni_system.rc2c05_enable = TRUE; + vsuni_system.rc2c05_A2002 = 0x1B; + break; + case PPU_RC2C05_05: + vsuni_system.rc2c05_enable = TRUE; + vsuni_system.rc2c05_A2002 = 0x00; + break; + default: + vsuni_system.rc2c05_enable = FALSE; + vsuni_system.rc2c05_A2002 = 0x00; + break; + } - if (curppu == RC2C05_04) { + SetReadHandler(0x5000, 0x5FFF, VSSecRead); + if (vsuni_system.rc2c05_enable) { OldReadPPU = GetReadHandler(0x2002); - SetReadHandler(0x2002, 0x2002, A2002_Topgun); - } else if (curppu == RC2C05_03) { - OldReadPPU = GetReadHandler(0x2002); - SetReadHandler(0x2002, 0x2002, A2002_Gumshoe); - } else if (curppu == RC2C05_02) { - OldReadPPU = GetReadHandler(0x2002); - SetReadHandler(0x2002, 0x2002, A2002_MBJ); - } - if (curppu == RC2C05_04 || curppu == RC2C05_01 || curppu == RC2C05_03 || curppu == RC2C05_02) { + SetReadHandler(0x2002, 0x2002, rc2c05_A2002); + OldWritePPU[0] = GetWriteHandler(0x2000); OldWritePPU[1] = GetWriteHandler(0x2001); - SetWriteHandler(0x2000, 0x2001, B2000_2001_2C05); - } - if (curmd5 == 0x2d396247cf58f9faLL) { /* Super Xevious */ - SetReadHandler(0x5400, 0x57FF, XevRead); + SetWriteHandler(0x2000, 0x2001, rc2c05_B2000_2001); } } @@ -218,7 +241,7 @@ RP2C04-0004: - Ice Climber Dual (Japan) - Super Mario Bros. -RCP2C03B: +PPU_RC2C03: - Battle City - Duck Hunt - Mahjang @@ -245,115 +268,149 @@ RC2C05-04: VSUNIENTRY VSUniGames[] = { - { "Baseball", VS_BASEBALL, 0x691d4200ea42be45LL, 99, 2, RP2C04_0001, 0, 0 }, - { "Battle City", VS_BATTLECITY, 0x8540949d74c4d0ebLL, 99, 2, RP2C04_0001, 0, 0 }, - { "Battle City(Bootleg)", VS_BATTLECITY, 0x8093cbe7137ac031LL, 99, 2, RP2C04_0001, 0, 0 }, - { "Clu Clu Land", VS_CLUCLULAND, 0x1b8123218f62b1eeLL, 99, 2, RP2C04_0004, IOPTION_SWAPDIRAB, 0 }, - { "Dr Mario", VS_DRMARIO, 0xe1af09c477dc0081LL, 1, 0, RP2C04_0003, IOPTION_SWAPDIRAB, 0 }, - { "Duck Hunt", VS_DUCKHUNT, 0x47735d1e5f1205bbLL, 99, 2, RCP2C03B, IOPTION_GUN, 0 }, - { "Excitebike", VS_EXITEBIKE, 0x3dcd1401bcafde77LL, 99, 2, RP2C04_0003, 0, 0 }, - { "Excitebike (J)", VS_EXITEBIKE, 0x7ea51c9d007375f0LL, 99, 2, RP2C04_0004, 0, 0 }, - { "Freedom Force", VS_FREEDOMFORCE, 0xed96436bd1b5e688LL, 4, 0, RP2C04_0001, IOPTION_GUN, 0 }, /* 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, 0 }, - { "Gradius", VS_GRADIUS, 0x50687ae63bdad976LL, 151, 1, RP2C04_0001, IOPTION_SWAPDIRAB, 0 }, - { "Gumshoe", VS_GUMSHOE, 0x87161f8ee37758d3LL, 99, 2, RC2C05_03, IOPTION_GUN, 0 }, - { "Gumshoe", VS_GUMSHOE, 0xb8500780bf69ce29LL, 99, 2, RC2C05_03, IOPTION_GUN, 0 }, - { "Gumshoe", VS_GUMSHOE, 0xa6bf132ba11d0a8cLL, 99, 2, RC2C05_03, IOPTION_GUN, 0 }, /* Gumshoe (VS).nes added: 2017-9-5*/ - { "Hogan's Alley", VS_HOGANSALLEY, 0xd78b7f0bb621fb45LL, 99, 2, RP2C04_0001, IOPTION_GUN, 0 }, - { "Ice Climber", VS_ICECLIMBER, 0xd21e999513435e2aLL, 99, 2, RP2C04_0004, IOPTION_SWAPDIRAB, 0 }, - { "Ladies Golf", VS_LADIESGOLF, 0x781b24be57ef6785LL, 99, 2, RP2C04_0002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1 }, - { "Mach Rider", VS_MACHRIDER, 0x015672618af06441LL, 99, 2, RP2C04_0002, 0, 0 }, - { "Mach Rider (J)", VS_MACHRIDER, 0xa625afb399811a8aLL, 99, 2, RP2C04_0001, 0, 0 }, - { "Mighty Bomb Jack", VS_MIGHTYBOMBJACK, 0xe6a89f4873fac37bLL, 0, 2, RC2C05_02, 0, 0 }, - { "Ninja Jajamaru Kun", VS_JAJAMARU, 0xb26a2c31474099c0LL, 99, 2, RC2C05_01, IOPTION_SWAPDIRAB, 0 }, - { "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, 0 }, - { "RBI Baseball", VS_RBIBASEBALL, 0x6a02d345812938afLL, 4, 1, RP2C04_0001, IOPTION_SWAPDIRAB, 0 }, - { "Soccer", VS_SOCCER, 0xd4e7a9058780eda3LL, 99, 2, RP2C04_0003, IOPTION_SWAPDIRAB, 0 }, - { "Star Luster", VS_STARLUSTER, 0x8360e134b316d94cLL, 99, 2, RCP2C03B, 0, 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, 0 }, - { "Tetris", VS_TETRIS, 0x531a5e8eea4ce157LL, 99, 2, RCP2C03B, IOPTION_PREDIP, 0x20 }, - { "Top Gun", VS_TOPGUN, 0xf1dea36e6a7b531dLL, 2, 0, RC2C05_04, 0, 0 }, - { "VS Castlevania", VS_CASTLEVANIA, 0x92fd6909c81305b9LL, 2, 1, RP2C04_0002, 0, 0 }, - { "VS Slalom", VS_SLALOM, 0x4889b5a50a623215LL, 0, 1, RP2C04_0002, 0, 0 }, - { "VS Super Mario Bros", VS_SMB, 0x39d8cfa788e20b6cLL, 99, 2, RP2C04_0004, 0, 0 }, - { "VS Super Mario Bros [a1]", VS_SMB, 0xfc182e5aefbce14dLL, 99, 2, RP2C04_0004, 0, 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 }, + { "Baseball", VS_BASEBALL, 0x691d4200ea42be45LL, 99, MI_4, PPU_RP2C04_0001, 0, 0, VS_TYPE_NORMAL }, + { "Battle City", VS_BATTLECITY, 0x8540949d74c4d0ebLL, 99, MI_4, PPU_RP2C04_0001, 0, 0, VS_TYPE_NORMAL }, + { "Battle City(Bootleg)", VS_BATTLECITY, 0x8093cbe7137ac031LL, 99, MI_4, PPU_RP2C04_0001, 0, 0, VS_TYPE_NORMAL }, + + { "Clu Clu Land", VS_CLUCLULAND, 0x1b8123218f62b1eeLL, 99, MI_4, PPU_RP2C04_0004, IOPTION_SWAPDIRAB, 0, VS_TYPE_NORMAL }, + { "Dr Mario", VS_DRMARIO, 0xe1af09c477dc0081LL, 1, MI_4, PPU_RP2C04_0003, IOPTION_SWAPDIRAB, 0, VS_TYPE_NORMAL }, + { "Duck Hunt", VS_DUCKHUNT, 0x47735d1e5f1205bbLL, 99, MI_4, PPU_RC2C03, IOPTION_GUN, 0, VS_TYPE_NORMAL }, + { "Excitebike", VS_EXITEBIKE, 0x3dcd1401bcafde77LL, 99, MI_4, PPU_RP2C04_0003, 0, 0, VS_TYPE_NORMAL }, + { "Excitebike (J)", VS_EXITEBIKE, 0x7ea51c9d007375f0LL, 99, MI_4, PPU_RP2C04_0004, 0, 0, VS_TYPE_NORMAL }, + { "Excitebike (J)", VS_EXITEBIKE, 0x7bcccfdd8011ba99LL, 99, MI_4, PPU_RP2C04_0003, 0, 0, VS_TYPE_NORMAL }, /* Excite Bike (EB4-3 E). nes added 2023-8-5 */ + { "Freedom Force", VS_FREEDOMFORCE, 0xed96436bd1b5e688LL, 206, MI_4, PPU_RP2C04_0001, IOPTION_GUN, 0, VS_TYPE_NORMAL }, /* Wrong color in game select screen? */ + { "Stroke and Match Golf", VS_STROKEANDMATCHGOLF, 0x612325606e82bc66LL, 99, MI_4, PPU_RP2C04_0002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x01, VS_TYPE_NORMAL }, + + { "Goonies", VS_GOONIES, 0xb4032d694e1d2733LL, 75, MI_4, PPU_RP2C04_0003, 0, 0, VS_TYPE_NORMAL }, + { "Gradius", VS_GRADIUS, 0x50687ae63bdad976LL, 75, MI_4, PPU_RP2C04_0001, IOPTION_SWAPDIRAB, 0, VS_TYPE_NORMAL }, + { "Gumshoe", VS_GUMSHOE, 0x87161f8ee37758d3LL, 99, MI_4, PPU_RC2C05_03, IOPTION_GUN, 0, VS_TYPE_NORMAL }, + { "Gumshoe", VS_GUMSHOE, 0xb8500780bf69ce29LL, 99, MI_4, PPU_RC2C05_03, IOPTION_GUN, 0, VS_TYPE_NORMAL }, + { "Gumshoe", VS_GUMSHOE, 0xa6bf132ba11d0a8cLL, 99, MI_4, PPU_RC2C05_03, IOPTION_GUN, 0, VS_TYPE_NORMAL }, /* Gumshoe (VS).nes added: 2017-9-5 */ + { "Gumshoe", VS_GUMSHOE, 0x53658a1f6d2df78eLL, 99, MI_4, PPU_RC2C05_03, IOPTION_GUN, 0, VS_TYPE_NORMAL }, /* Gumshoe (VS).nes added: 2023-8-5 */ + { "Gumshoe", VS_GUMSHOE, 0x15f31725e5cbafd4LL, 99, MI_4, PPU_RC2C05_03, IOPTION_GUN, 0, VS_TYPE_NORMAL }, /* Gumshoe (VS).nes added: 2023-8-5 */ + { "Hogan's Alley", VS_HOGANSALLEY, 0xd78b7f0bb621fb45LL, 99, MI_4, PPU_RP2C04_0001, IOPTION_GUN, 0, VS_TYPE_NORMAL }, + { "Hogan's Alley", VS_HOGANSALLEY, 0x7566994e3d5ca6a7LL, 99, MI_4, PPU_RP2C04_0001, IOPTION_GUN, 0, VS_TYPE_NORMAL }, /* Hogans Alley.nes added: 2023-8-5 */ + { "Ice Climber", VS_ICECLIMBER, 0xd21e999513435e2aLL, 99, MI_4, PPU_RP2C04_0004, IOPTION_SWAPDIRAB, 0, VS_TYPE_NORMAL }, + { "Ladies Golf", VS_LADIESGOLF, 0x781b24be57ef6785LL, 99, MI_4, PPU_RP2C04_0002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1, VS_TYPE_NORMAL }, + + { "Mach Rider", VS_MACHRIDER, 0x015672618af06441LL, 99, MI_4, PPU_RP2C04_0002, 0, 0, VS_TYPE_NORMAL }, + { "Mach Rider (J)", VS_MACHRIDER, 0xa625afb399811a8aLL, 99, MI_4, PPU_RP2C04_0001, 0, 0, VS_TYPE_NORMAL }, + { "Mighty Bomb Jack", VS_MIGHTYBOMBJACK, 0xe6a89f4873fac37bLL, 99, MI_4, PPU_RC2C05_02, 0, 0, VS_TYPE_NORMAL }, /* 2023-8-5 switched to mapper 99 instead of mapper 0 */ + { "Ninja Jajamaru Kun", VS_JAJAMARU, 0xb26a2c31474099c0LL, 99, MI_4, PPU_RC2C05_01, IOPTION_SWAPDIRAB, 0, VS_TYPE_NORMAL }, + { "Pinball", VS_PINBALL, 0xc5f49d3de7f2e9b8LL, 99, MI_4, PPU_RP2C04_0001, IOPTION_PREDIP, 0x01, VS_TYPE_NORMAL }, + { "Pinball (J)", VS_PINBALL, 0x66ab1a3828cc901cLL, 99, MI_4, PPU_RC2C03, IOPTION_PREDIP, 0x1, VS_TYPE_NORMAL }, + { "Platoon", VS_PLATOON, 0x160f237351c19f1fLL, 67, MI_4, PPU_RP2C04_0001, 0, 0, VS_TYPE_NORMAL }, + { "RBI Baseball", VS_RBIBASEBALL, 0x6a02d345812938afLL, 206, MI_4, PPU_RP2C04_0001, IOPTION_SWAPDIRAB, 0, VS_TYPE_RBI }, + { "Soccer", VS_SOCCER, 0xd4e7a9058780eda3LL, 99, MI_4, PPU_RP2C04_0003, IOPTION_SWAPDIRAB, 0, VS_TYPE_NORMAL }, + { "Star Luster", VS_STARLUSTER, 0x8360e134b316d94cLL, 99, MI_4, PPU_RC2C03, 0, 0, VS_TYPE_NORMAL }, + { "Stroke and Match Golf (J)", VS_STROKEANDMATCHGOLF, 0x869bb83e02509747LL, 99, MI_4, PPU_RC2C03, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1, VS_TYPE_NORMAL }, + { "Super Sky Kid", VS_SUPERSKYKID, 0x78d04c1dd4ec0101LL, 206, MI_4, PPU_RC2C03, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x20, VS_TYPE_NORMAL }, + { "Super Xevious", VS_SUPERXEVIOUS, 0x2d396247cf58f9faLL, 206, MI_4, PPU_RP2C04_0001, 0, 0, VS_TYPE_XEVIOUS }, + + { "Tetris", VS_TETRIS, 0x531a5e8eea4ce157LL, 99, MI_4, PPU_RC2C03, IOPTION_PREDIP, 0x20, VS_TYPE_NORMAL }, + { "Tetris", VS_TETRIS, 0x2afaee01608e55cbLL, 99, MI_4, PPU_RC2C03, IOPTION_PREDIP, 0x20, VS_TYPE_NORMAL }, + { "Top Gun", VS_TOPGUN, 0xf1dea36e6a7b531dLL, 2, MI_4, PPU_RC2C05_04, 0, 0, VS_TYPE_NORMAL }, + { "VS Castlevania", VS_CASTLEVANIA, 0x92fd6909c81305b9LL, 2, MI_4, PPU_RP2C04_0002, 0, 0, VS_TYPE_NORMAL }, + { "VS Slalom", VS_SLALOM, 0x4889b5a50a623215LL, 0, MI_4, PPU_RP2C04_0002, 0, 0, VS_TYPE_NORMAL }, + { "VS Super Mario Bros", VS_SMB, 0x39d8cfa788e20b6cLL, 99, MI_4, PPU_RP2C04_0004, 0, 0, VS_TYPE_NORMAL }, + { "VS Super Mario Bros [a1]", VS_SMB, 0xfc182e5aefbce14dLL, 99, MI_4, PPU_RP2C04_0004, 0, 0, VS_TYPE_NORMAL }, + { "VS TKO Boxing", VS_TKOBOXING, 0x6e1ee06171d8ce3aLL, 206, MI_4, PPU_RP2C04_0003, IOPTION_PREDIP, 0x00, VS_TYPE_TKO }, + { "VS TKO Boxing [a1]", VS_TKOBOXING, 0xa1c694ce147bc1edLL, 206, MI_4, PPU_RP2C04_0003, IOPTION_PREDIP, 0x00, VS_TYPE_TKO }, { 0 } }; -void FCEU_VSUniCheck(uint64 md5partial, int *MapperNo, int *Mirroring) { +void FCEU_VSUniCheck(uint64 md5partial, uint16 *MapperNo, uint8 *Mirroring) { VSUNIENTRY *vs = VSUniGames; while (vs->name) { if (md5partial == vs->md5partial) { - if (vs->ppu < RCP2C03B) pale = vs->ppu; - else pale = 5; - *MapperNo = vs->mapper; - *Mirroring = vs->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); + static char *mirroring_str[] = { + "Horizontal", + "Vertical", + "$2000", + "$2400", + "\"Four-screen\"", + }; + int tofix = 0; + + GameInfo->type = GIT_VSUNI; + GameInfo->cspecial = SIS_VSUNISYSTEM; + GameInfo->inputfc = SIFC_NONE; + + if (*MapperNo != vs->mapper) { + tofix |= 1; + *MapperNo = vs->mapper; + } + + if (*Mirroring != vs->mirroring) { + tofix |= 2; + *Mirroring = vs->mirroring; + } - secptr = 0; + vsuni_system.gameid = vs->gameid; + vsuni_system.ppu = vs->ppu; + vsuni_system.type = vs->type; + vsuni_system.vsdip = 0; - if (vs->gameid == VS_TKOBOXING) - secptr = secdata[0]; - if (vs->gameid == VS_RBIBASEBALL) - secptr = secdata[1]; + if (!vsuni_system.ioption) { + vsuni_system.ioption = vs->ioption; + } - vsdip = 0x0; if (vs->ioption & IOPTION_PREDIP) { - vsdip = vs->predip; + vsuni_system.vsdip = vs->predip; } + if (vs->ioption & IOPTION_GUN) { GameInfo->input[0] = SI_ZAPPER; GameInfo->input[1] = SI_NONE; } else { - GameInfo->input[0] = GameInfo->input[1] = SI_GAMEPAD; + GameInfo->input[0] = SI_GAMEPAD; + GameInfo->input[1] = SI_GAMEPAD; + } + + FCEU_printf("\n"); + FCEU_printf(" System: VS-UniSystem\n"); + FCEU_printf(" Name: %s\n", vs->name); + FCEU_printf("\n"); + + if (tofix) { + FCEU_PrintError(" Incorrect VS-Unisystem header information!\n"); + if (tofix & 1) + FCEU_PrintError(" Mapper: %d\n", vs->mapper); + if (tofix & 2) + FCEU_PrintError(" Mirroring: %s\n", mirroring_str[vs->mirroring]); } - curvs = vs; + return; } vs++; } } -void FCEU_VSUniDraw(uint8 *XBuf) { +void FCEU_VSUniDraw(uint8 *target) { uint32 *dest; int y, x; if (!DIPS) return; - dest = (uint32*)(XBuf + 256 * 12 + 164); + dest = (uint32*)(target + 256 * 12 + 164); for (y = 24; y; y--, dest += (256 - 72) >> 2) { for (x = 72 >> 2; x; x--, dest++) *dest = 0; } - dest = (uint32*)(XBuf + 256 * (12 + 4) + 164 + 6); + dest = (uint32*)(target + 256 * (12 + 4) + 164 + 6); for (y = 16; y; y--, dest += (256 >> 2) - 16) for (x = 8; x; x--) { *dest = 0x01010101; dest += 2; } - dest = (uint32*)(XBuf + 256 * (12 + 4) + 164 + 6); + dest = (uint32*)(target + 256 * (12 + 4) + 164 + 6); for (x = 0; x < 8; x++, dest += 2) { uint32 *da = dest + (256 >> 2); - if (!((vsdip >> x) & 1)) + if (!((vsuni_system.vsdip >> x) & 1)) da += (256 >> 2) * 10; for (y = 4; y; y--, da += 256 >> 2) *da = 0; @@ -362,8 +419,6 @@ void FCEU_VSUniDraw(uint8 *XBuf) { SFORMAT FCEUVSUNI_STATEINFO[] = { - { &vsdip, 1, "vsdp" }, - { &coinon, 1, "vscn" }, { &VSindex, 1, "vsin" }, { 0 } }; diff --git a/src/vsuni.h b/src/vsuni.h index e84141c64..9f0ef47b1 100644 --- a/src/vsuni.h +++ b/src/vsuni.h @@ -1,15 +1,7 @@ #ifndef _FCEU_VSUNI_H #define _FCEU_VSUNI_H -void FCEU_VSUniPower(void); -void FCEU_VSUniCheck(uint64 md5partial, int *, int *); -void FCEU_VSUniDraw(uint8 *XBuf); - -void FCEU_VSUniToggleDIP(int); /* For movies and netplay */ -void FCEU_VSUniCoin(void); -void FCEU_VSUniSwap(uint8 *j0, uint8 *j1); - -enum { +enum VSGAMEID { VS_BASEBALL = 1, VS_BATTLECITY, VS_CASTLEVANIA, @@ -39,7 +31,41 @@ enum { VS_SUPERXEVIOUS, VS_TETRIS, VS_TKOBOXING, - VS_TOPGUN + VS_TOPGUN, + + VS_GAMEID_COUNT = VS_TOPGUN +}; + +enum IOPTION { + IOPTION_GUN = 0x01, + IOPTION_SWAPDIRAB = 0x02, + IOPTION_PREDIP = 0x10 }; +typedef struct VSUNISYSTEM { + int gameid; /* Currently used for VS game id for per-game dipswitch */ + int ppu; + int type; + int ioption; + + int coinon[2]; + int service; + + int vsdip; + + int rc2c05_enable; + int rc2c05_A2002; +} VSUNISYSTEM; + +extern VSUNISYSTEM vsuni_system; + +void FCEU_VSUniPower(void); +void FCEU_VSUniCheck(uint64 md5partial, uint16 *, uint8 *); +void FCEU_VSUniDraw(uint8 *target); + +void FCEU_VSUniToggleDIP(int); /* For movies and netplay */ +void FCEU_VSUniCoin(int slot); +void FCEU_VSUniService(void); +void FCEU_VSUniSwap(uint8 *j0, uint8 *j1); + #endif diff --git a/src/x6502.c b/src/x6502.c index 8e550124b..2b6d247a9 100644 --- a/src/x6502.c +++ b/src/x6502.c @@ -26,7 +26,7 @@ #include "sound.h" #include "ppu.h" -X6502 X; +X6502 cpu; #ifdef FCEUDEF_DEBUGGER void (*X6502_Run)(int32 cycles); @@ -34,175 +34,167 @@ void (*X6502_Run)(int32 cycles); uint32 timestamp; uint32 sound_timestamp; -void FP_FASTAPASS(1) (*MapIRQHook)(int a); - -#define _PC X.PC -#define _A X.A -#define _X X.X -#define _Y X.Y -#define _S X.S -#define _P X.P -#define _PI X.mooPI -#define _DB X.DB -#define _count X.count -#define _tcount X.tcount -#define _IRQlow X.IRQlow -#define _jammed X.jammed +void (*MapIRQHook)(int a); #define ADDCYC(x) { \ int __x = x; \ - _tcount += __x; \ - _count -= __x * 48; \ + cpu.tcount += __x; \ + cpu.count -= __x * 48; \ timestamp += __x; \ - if (!ppu.overclocked) sound_timestamp += __x; \ + if (!ppu.overclock.overclocked_state) sound_timestamp += __x; \ } -static INLINE uint8 RdMemNorm(uint32 A) { - return(_DB = ARead[A](A)); +static INLINE uint8 RdMem(uint32 A) { + cpu.openbus = ARead[A](A); + return (cpu.openbus); } -static INLINE void WrMemNorm(uint32 A, uint8 V) { +static INLINE void WrMem(uint32 A, uint8 V) { BWrite[A](A, V); + /*cpu.openbus = V;*/ } #ifdef FCEUDEF_DEBUGGER X6502 XSave; /* This is getting ugly. */ static INLINE uint8 RdMemHook(uint32 A) { - if (X.ReadHook) - return(_DB = X.ReadHook(&X, A)); + if (cpu.ReadHook) + return(cpu.openbus = cpu.ReadHook(&X, A)); else - return(_DB = ARead[A](A)); + return(cpu.openbus = ARead[A](A)); } static INLINE void WrMemHook(uint32 A, uint8 V) { - if (X.WriteHook) - X.WriteHook(&X, A, V); + if (cpu.WriteHook) + cpu.WriteHook(&X, A, V); else BWrite[A](A, V); + cpu.openbus = V; } #endif -static INLINE uint8 RdRAMFast(uint32 A) { - return(_DB = RAM[A]); +static INLINE uint8 RdRAM(uint32 A) { + cpu.openbus = RAM[A]; + return (cpu.openbus); } -static INLINE void WrRAMFast(uint32 A, uint8 V) { +static INLINE void WrRAM(uint32 A, uint8 V) { RAM[A] = V; + /*cpu.openbus = V;*/ } -uint8 FASTAPASS(1) X6502_DMR(uint32 A) { +uint8 X6502_DMR(uint32 A) { ADDCYC(1); - return(X.DB = ARead[A](A)); + return(cpu.openbus = ARead[A](A)); } -void FASTAPASS(2) X6502_DMW(uint32 A, uint8 V) { +void X6502_DMW(uint32 A, uint8 V) { ADDCYC(1); BWrite[A](A, V); } #define PUSH(V) { \ uint8 VTMP = V; \ - WrRAM(0x100 + _S, VTMP); \ - _S--; \ + WrRAM(0x100 + cpu.S, VTMP); \ + cpu.S--; \ } -#define POP() RdRAM(0x100 + (++_S)) +#define POP() RdRAM(0x100 + (++cpu.S)) static uint8 ZNTable[256]; /* Some of these operations will only make sense if you know what the flag constants are. */ -#define X_ZN(zort) _P &= ~(Z_FLAG | N_FLAG); _P |= ZNTable[zort] -#define X_ZNT(zort) _P |= ZNTable[zort] +#define X_ZN(zort) cpu.P &= ~(Z_FLAG | N_FLAG); cpu.P |= ZNTable[zort] +#define X_ZNT(zort) cpu.P |= ZNTable[zort] #define JR(cond) { \ if (cond) \ { \ uint32 tmp; \ int32 disp; \ - disp = (int8)RdMem(_PC); \ - _PC++; \ + disp = (int8)RdMem(cpu.PC); \ + cpu.PC++; \ ADDCYC(1); \ - tmp = _PC; \ - _PC += disp; \ - if ((tmp ^ _PC) & 0x100) \ + tmp = cpu.PC; \ + cpu.PC += disp; \ + if ((tmp ^ cpu.PC) & 0x100) \ ADDCYC(1); \ - } else _PC++; \ + } else cpu.PC++; \ } -#define LDA _A = x; X_ZN(_A) -#define LDX _X = x; X_ZN(_X) -#define LDY _Y = x; X_ZN(_Y) +#define LDA cpu.A = x; X_ZN(cpu.A) +#define LDX cpu.X = x; X_ZN(cpu.X) +#define LDY cpu.Y = x; X_ZN(cpu.Y) /* All of the freaky arithmetic operations. */ -#define AND _A &= x; X_ZN(_A) -#define BIT _P &= ~(Z_FLAG | V_FLAG | N_FLAG); _P |= ZNTable[x & _A] & Z_FLAG; _P |= x & (V_FLAG | N_FLAG) -#define EOR _A ^= x; X_ZN(_A) -#define ORA _A |= x; X_ZN(_A) +#define AND cpu.A &= x; X_ZN(cpu.A) +#define BIT cpu.P &= ~(Z_FLAG | V_FLAG | N_FLAG); cpu.P |= ZNTable[x & cpu.A] & Z_FLAG; cpu.P |= x & (V_FLAG | N_FLAG) +#define EOR cpu.A ^= x; X_ZN(cpu.A) +#define ORA cpu.A |= x; X_ZN(cpu.A) -#define ADC { \ - uint32 l = _A + x + (_P & 1); \ - _P &= ~(Z_FLAG | C_FLAG | N_FLAG | V_FLAG); \ - _P |= ((((_A ^ x) & 0x80) ^ 0x80) & ((_A ^ l) & 0x80)) >> 1; \ - _P |= (l >> 8) & C_FLAG; \ - _A = l; \ - X_ZNT(_A); \ +#define ADC { \ + uint32 l = cpu.A + x + (cpu.P & 1); \ + cpu.P &= ~(Z_FLAG | C_FLAG | N_FLAG | V_FLAG); \ + cpu.P |= ((((cpu.A ^ x) & 0x80) ^ 0x80) & ((cpu.A ^ l) & 0x80)) >> 1; \ + cpu.P |= (l >> 8) & C_FLAG; \ + cpu.A = l; \ + X_ZNT(cpu.A); \ } -#define SBC { \ - uint32 l = _A - x - ((_P & 1) ^ 1); \ - _P &= ~(Z_FLAG | C_FLAG | N_FLAG | V_FLAG); \ - _P |= ((_A ^ l) & (_A ^ x) & 0x80) >> 1; \ - _P |= ((l >> 8) & C_FLAG) ^ C_FLAG; \ - _A = l; \ - X_ZNT(_A); \ +#define SBC { \ + uint32 l = cpu.A - x - ((cpu.P & 1) ^ 1); \ + cpu.P &= ~(Z_FLAG | C_FLAG | N_FLAG | V_FLAG); \ + cpu.P |= ((cpu.A ^ l) & (cpu.A ^ x) & 0x80) >> 1; \ + cpu.P |= ((l >> 8) & C_FLAG) ^ C_FLAG; \ + cpu.A = l; \ + X_ZNT(cpu.A); \ } -#define CMPL(a1, a2) { \ - uint32 t = a1 - a2; \ - X_ZN(t & 0xFF); \ - _P &= ~C_FLAG; \ - _P |= ((t >> 8) & C_FLAG) ^ C_FLAG; \ +#define CMPL(a1, a2) { \ + uint32 t = a1 - a2; \ + X_ZN(t & 0xFF); \ + cpu.P &= ~C_FLAG; \ + cpu.P |= ((t >> 8) & C_FLAG) ^ C_FLAG; \ } /* Special undocumented operation. Very similar to CMP. */ -#define AXS { \ - uint32 t = (_A & _X) - x; \ - X_ZN(t & 0xFF); \ - _P &= ~C_FLAG; \ - _P |= ((t >> 8) & C_FLAG) ^ C_FLAG; \ - _X = t; \ +#define AXS { \ + uint32 t = (cpu.A & cpu.X) - x; \ + X_ZN(t & 0xFF); \ + cpu.P &= ~C_FLAG; \ + cpu.P |= ((t >> 8) & C_FLAG) ^ C_FLAG; \ + cpu.X = t; \ } -#define CMP CMPL(_A, x) -#define CPX CMPL(_X, x) -#define CPY CMPL(_Y, x) +#define CMP CMPL(cpu.A, x) +#define CPX CMPL(cpu.X, x) +#define CPY CMPL(cpu.Y, x) /* The following operations modify the byte being worked on. */ #define DEC x--; X_ZN(x) #define INC x++; X_ZN(x) -#define ASL _P &= ~C_FLAG; _P |= x >> 7; x <<= 1; X_ZN(x) -#define LSR _P &= ~(C_FLAG | N_FLAG | Z_FLAG); _P |= x & 1; x >>= 1; X_ZNT(x) +#define ASL cpu.P &= ~C_FLAG; cpu.P |= x >> 7; x <<= 1; X_ZN(x) +#define LSR cpu.P &= ~(C_FLAG | N_FLAG | Z_FLAG); cpu.P |= x & 1; x >>= 1; X_ZNT(x) /* For undocumented instructions, maybe for other things later... */ -#define LSRA _P &= ~(C_FLAG | N_FLAG | Z_FLAG); _P |= _A & 1; _A >>= 1; X_ZNT(_A) +#define LSRA cpu.P &= ~(C_FLAG | N_FLAG | Z_FLAG); cpu.P |= cpu.A & 1; cpu.A >>= 1; X_ZNT(cpu.A) #define ROL { \ uint8 l = x >> 7; \ x <<= 1; \ - x |= _P & C_FLAG; \ - _P &= ~(Z_FLAG | N_FLAG | C_FLAG); \ - _P |= l; \ + x |= cpu.P & C_FLAG; \ + cpu.P &= ~(Z_FLAG | N_FLAG | C_FLAG); \ + cpu.P |= l; \ X_ZNT(x); \ } #define ROR { \ uint8 l = x & 1; \ x >>= 1; \ - x |= (_P & C_FLAG) << 7; \ - _P &= ~(Z_FLAG | N_FLAG | C_FLAG); \ - _P |= l; \ + x |= (cpu.P & C_FLAG) << 7; \ + cpu.P &= ~(Z_FLAG | N_FLAG | C_FLAG); \ + cpu.P |= l; \ X_ZNT(x); \ } @@ -212,10 +204,10 @@ static uint8 ZNTable[256]; /* Absolute */ #define GetAB(target) { \ - target = RdMem(_PC); \ - _PC++; \ - target |= RdMem(_PC) << 8; \ - _PC++; \ + target = RdMem(cpu.PC); \ + cpu.PC++; \ + target |= RdMem(cpu.PC) << 8; \ + cpu.PC++; \ } /* Absolute Indexed(for reads) */ @@ -243,22 +235,22 @@ static uint8 ZNTable[256]; /* Zero Page */ #define GetZP(target) { \ - target = RdMem(_PC); \ - _PC++; \ + target = RdMem(cpu.PC); \ + cpu.PC++; \ } /* Zero Page Indexed */ #define GetZPI(target, i) { \ - target = i + RdMem(_PC); \ - _PC++; \ + target = i + RdMem(cpu.PC); \ + cpu.PC++; \ } /* Indexed Indirect */ #define GetIX(target) { \ uint8 tmp; \ - tmp = RdMem(_PC); \ - _PC++; \ - tmp += _X; \ + tmp = RdMem(cpu.PC); \ + cpu.PC++; \ + tmp += cpu.X; \ target = RdRAM(tmp); \ tmp++; \ target |= RdRAM(tmp) << 8; \ @@ -268,13 +260,13 @@ static uint8 ZNTable[256]; #define GetIYRD(target) { \ uint32 rt; \ uint8 tmp; \ - tmp = RdMem(_PC); \ - _PC++; \ + tmp = RdMem(cpu.PC); \ + cpu.PC++; \ rt = RdRAM(tmp); \ tmp++; \ rt |= RdRAM(tmp) << 8; \ target = rt; \ - target += _Y; \ + target += cpu.Y; \ if ((target ^ rt) & 0x100) { \ target &= 0xFFFF; \ RdMem(target ^ 0x100); \ @@ -286,13 +278,13 @@ static uint8 ZNTable[256]; #define GetIYWR(target) { \ uint32 rt; \ uint8 tmp; \ - tmp = RdMem(_PC); \ - _PC++; \ + tmp = RdMem(cpu.PC); \ + cpu.PC++; \ rt = RdRAM(tmp); \ tmp++; \ rt |= RdRAM(tmp) << 8; \ target = rt; \ - target += _Y; \ + target += cpu.Y; \ target &= 0xFFFF; \ RdMem((target & 0x00FF) | (rt & 0xFF00)); \ } @@ -302,34 +294,34 @@ and operation macros. Note that operation macros will always operate(redundant redundant) on the variable "x". */ -#define RMW_A(op) { uint8 x = _A; op; _A = x; break; } /* Meh... */ +#define RMW_A(op) { uint8 x = cpu.A; op; cpu.A = x; break; } /* Meh... */ #define RMW_AB(op) { uint32 A; uint8 x; GetAB(A); x = RdMem(A); WrMem(A, x); op; WrMem(A, x); break; } #define RMW_ABI(reg, op) { uint32 A; uint8 x; GetABIWR(A, reg); x = RdMem(A); WrMem(A, x); op; WrMem(A, x); break; } -#define RMW_ABX(op) RMW_ABI(_X, op) -#define RMW_ABY(op) RMW_ABI(_Y, op) +#define RMW_ABX(op) RMW_ABI(cpu.X, op) +#define RMW_ABY(op) RMW_ABI(cpu.Y, op) #define RMW_IX(op) { uint32 A; uint8 x; GetIX(A); x = RdMem(A); WrMem(A, x); op; WrMem(A, x); break; } #define RMW_IY(op) { uint32 A; uint8 x; GetIYWR(A); x = RdMem(A); WrMem(A, x); op; WrMem(A, x); break; } #define RMW_ZP(op) { uint8 A; uint8 x; GetZP(A); x = RdRAM(A); op; WrRAM(A, x); break; } -#define RMW_ZPX(op) { uint8 A; uint8 x; GetZPI(A, _X); x = RdRAM(A); op; WrRAM(A, x); break; } +#define RMW_ZPX(op) { uint8 A; uint8 x; GetZPI(A, cpu.X); x = RdRAM(A); op; WrRAM(A, x); break; } -#define LD_IM(op) { uint8 x; x = RdMem(_PC); _PC++; op; break; } +#define LD_IM(op) { uint8 x; x = RdMem(cpu.PC); cpu.PC++; op; break; } #define LD_ZP(op) { uint8 A; uint8 x; GetZP(A); x = RdRAM(A); op; break; } -#define LD_ZPX(op) { uint8 A; uint8 x; GetZPI(A, _X); x = RdRAM(A); op; break; } -#define LD_ZPY(op) { uint8 A; uint8 x; GetZPI(A, _Y); x = RdRAM(A); op; break; } -#define LD_AB(op) { uint32 A; uint8 x; FCEU_MAYBE_UNUSED(x); GetAB(A); x = RdMem(A); op; break; } -#define LD_ABI(reg, op) { uint32 A; uint8 x; FCEU_MAYBE_UNUSED(x); GetABIRD(A, reg); x = RdMem(A); op; break; } -#define LD_ABX(op) LD_ABI(_X, op) -#define LD_ABY(op) LD_ABI(_Y, op) +#define LD_ZPX(op) { uint8 A; uint8 x; GetZPI(A, cpu.X); x = RdRAM(A); op; break; } +#define LD_ZPY(op) { uint8 A; uint8 x; GetZPI(A, cpu.Y); x = RdRAM(A); op; break; } +#define LD_AB(op) { uint32 A; uint8 x; FCEU_UNUSED(x); GetAB(A); x = RdMem(A); op; break; } +#define LD_ABI(reg, op) { uint32 A; uint8 x; FCEU_UNUSED(x); GetABIRD(A, reg); x = RdMem(A); op; break; } +#define LD_ABX(op) LD_ABI(cpu.X, op) +#define LD_ABY(op) LD_ABI(cpu.Y, op) #define LD_IX(op) { uint32 A; uint8 x; GetIX(A); x = RdMem(A); op; break; } #define LD_IY(op) { uint32 A; uint8 x; GetIYRD(A); x = RdMem(A); op; break; } #define ST_ZP(r) { uint8 A; GetZP(A); WrRAM(A, r); break; } -#define ST_ZPX(r) { uint8 A; GetZPI(A, _X); WrRAM(A, r); break; } -#define ST_ZPY(r) { uint8 A; GetZPI(A, _Y); WrRAM(A, r); break; } +#define ST_ZPX(r) { uint8 A; GetZPI(A, cpu.X); WrRAM(A, r); break; } +#define ST_ZPY(r) { uint8 A; GetZPI(A, cpu.Y); WrRAM(A, r); break; } #define ST_AB(r) { uint32 A; GetAB(A); WrMem(A, r); break; } #define ST_ABI(reg, r) { uint32 A; GetABIWR(A, reg); WrMem(A, r); break; } -#define ST_ABX(r) ST_ABI(_X, r) -#define ST_ABY(r) ST_ABI(_Y, r) +#define ST_ABX(r) ST_ABI(cpu.X, r) +#define ST_ABY(r) ST_ABI(cpu.Y, r) #define ST_IX(r) { uint32 A; GetIX(A); WrMem(A, r); break; } #define ST_IY(r) { uint32 A; GetIYWR(A); WrMem(A, r); break; } @@ -353,30 +345,30 @@ static uint8 CycTable[256] = /*0xF0*/ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, }; -void FASTAPASS(1) X6502_IRQBegin(int w) { - _IRQlow |= w; +void X6502_IRQBegin(int w) { + cpu.IRQlow |= w; } -void FASTAPASS(1) X6502_IRQEnd(int w) { - _IRQlow &= ~w; +void X6502_IRQEnd(int w) { + cpu.IRQlow &= ~w; } void TriggerNMI(void) { - _IRQlow |= FCEU_IQNMI; + cpu.IRQlow |= FCEU_IQNMI; } void TriggerNMI2(void) { - _IRQlow |= FCEU_IQNMI2; + cpu.IRQlow |= FCEU_IQNMI2; } #ifdef FCEUDEF_DEBUGGER /* Called from debugger. */ void FCEUI_NMI(void) { - _IRQlow |= FCEU_IQNMI; + cpu.IRQlow |= FCEU_IQNMI; } void FCEUI_IRQ(void) { - _IRQlow |= FCEU_IQTEMP; + cpu.IRQlow |= FCEU_IQTEMP; } void FCEUI_GetIVectors(uint16 *reset, uint16 *irq, uint16 *nmi) { @@ -394,13 +386,13 @@ static int debugmode; #endif void X6502_Reset(void) { - _IRQlow = FCEU_IQRESET; + cpu.IRQlow = FCEU_IQRESET; } void X6502_Init(void) { int x; - memset((void*)&X, 0, sizeof(X)); + memset((void*)&cpu, 0, sizeof(cpu)); for (x = 0; x < 256; x++) { if (!x) ZNTable[x] = Z_FLAG; @@ -415,227 +407,87 @@ void X6502_Init(void) { } void X6502_Power(void) { - _count = _tcount = _IRQlow = _PC = _A = _X = _Y = _P = _PI = _DB = _jammed = 0; - _S = 0xFD; + cpu.count = cpu.tcount = cpu.IRQlow = cpu.PC = cpu.A = cpu.X = cpu.Y = cpu.P = cpu.mooPI = cpu.openbus = cpu.jammed = 0; + cpu.S = 0xFD; timestamp = sound_timestamp = 0; X6502_Reset(); } -#ifdef FCEUDEF_DEBUGGER -static void X6502_RunDebug(int32 cycles) { - #define RdRAM RdMemHook - #define WrRAM WrMemHook - #define RdMem RdMemHook - #define WrMem WrMemHook - - if (PAL) +void X6502_Run(int32 cycles) { + if (isPAL) cycles *= 15; /* 15*4=60 */ else cycles *= 16; /* 16*4=64 */ - _count += cycles; + cpu.count += cycles; - while (_count > 0) { + while (cpu.count > 0) { int32 temp; uint8 b1; - if (_IRQlow) { - if (_IRQlow & FCEU_IQRESET) { - _PC = RdMem(0xFFFC); - _PC |= RdMem(0xFFFD) << 8; - _jammed = 0; - _PI = _P = I_FLAG; - _IRQlow &= ~FCEU_IQRESET; - } else if (_IRQlow & FCEU_IQNMI2) { - _IRQlow &= ~FCEU_IQNMI2; - _IRQlow |= FCEU_IQNMI; - } else if (_IRQlow & FCEU_IQNMI) { - if (!_jammed) { + if (cpu.IRQlow) { + if (cpu.IRQlow & FCEU_IQRESET) { + cpu.PC = RdMem(0xFFFC); + cpu.PC |= RdMem(0xFFFD) << 8; + cpu.jammed = 0; + cpu.mooPI = cpu.P = I_FLAG; + cpu.IRQlow &= ~FCEU_IQRESET; + } else if (cpu.IRQlow & FCEU_IQNMI2) { + cpu.IRQlow &= ~FCEU_IQNMI2; + cpu.IRQlow |= FCEU_IQNMI; + } else if (cpu.IRQlow & FCEU_IQNMI) { + if (!cpu.jammed) { ADDCYC(7); - PUSH(_PC >> 8); - PUSH(_PC); - PUSH((_P & ~B_FLAG) | (U_FLAG)); - _P |= I_FLAG; - _PC = RdMem(0xFFFA); - _PC |= RdMem(0xFFFB) << 8; - _IRQlow &= ~FCEU_IQNMI; + PUSH(cpu.PC >> 8); + PUSH(cpu.PC); + PUSH((cpu.P & ~B_FLAG) | (U_FLAG)); + cpu.P |= I_FLAG; + cpu.PC = RdMem(0xFFFA); + cpu.PC |= RdMem(0xFFFB) << 8; + cpu.IRQlow &= ~FCEU_IQNMI; } } else { - if (!(_PI & I_FLAG) && !_jammed) { + if (!(cpu.mooPI & I_FLAG) && !cpu.jammed) { ADDCYC(7); - PUSH(_PC >> 8); - PUSH(_PC); - PUSH((_P & ~B_FLAG) | (U_FLAG)); - _P |= I_FLAG; - _PC = RdMem(0xFFFE); - _PC |= RdMem(0xFFFF) << 8; + PUSH(cpu.PC >> 8); + PUSH(cpu.PC); + PUSH((cpu.P & ~B_FLAG) | (U_FLAG)); + cpu.P |= I_FLAG; + cpu.PC = RdMem(0xFFFE); + cpu.PC |= RdMem(0xFFFF) << 8; } } - _IRQlow &= ~(FCEU_IQTEMP); - if (_count <= 0) { - _PI = _P; + cpu.IRQlow &= ~(FCEU_IQTEMP); + if (cpu.count <= 0) { + cpu.mooPI = cpu.P; return; } /* Should increase accuracy without a * major speed hit. */ } - if (X.CPUHook) X.CPUHook(&X); - /* Ok, now the real fun starts. - * Do the pre-exec voodoo. - */ - if (X.ReadHook || X.WriteHook) { - uint32 tsave = timestamp; - XSave = X; - - fceuindbg = 1; - X.preexec = 1; - b1 = RdMem(_PC); - _PC++; - switch (b1) { - #include "ops.inc" - } - - timestamp = tsave; - - /* In case an NMI/IRQ/RESET was triggered by the debugger. - * Should we also copy over the other hook variables? - */ - XSave.IRQlow = X.IRQlow; - XSave.ReadHook = X.ReadHook; - XSave.WriteHook = X.WriteHook; - XSave.CPUHook = X.CPUHook; - X = XSave; - fceuindbg = 0; - } + cpu.mooPI = cpu.P; + b1 = RdMem(cpu.PC); - _PI = _P; - b1 = RdMem(_PC); ADDCYC(CycTable[b1]); - temp = _tcount; - _tcount = 0; + temp = cpu.tcount; + cpu.tcount = 0; if (MapIRQHook) MapIRQHook(temp); - - if (!ppu.overclocked) - FCEU_SoundCPUHook(temp); - - _PC++; + if (!ppu.overclock.overclocked_state) FCEU_SoundCPUHook(temp); + cpu.PC++; switch (b1) { - #include "ops.inc" + #include "x6502ops.inc" } } - #undef RdRAM - #undef WrRAM - #undef RdMem - #undef WrMem -} - -static void X6502_RunNormal(int32 cycles) -#else -void X6502_Run(int32 cycles) -#endif -{ - #define RdRAM RdRAMFast - #define WrRAM WrRAMFast - #define RdMem RdMemNorm - #define WrMem WrMemNorm - - #if (defined(C80x86) && defined(__GNUC__)) - /* Gives a nice little speed boost. */ - register uint16 pbackus asm ("edi"); - #else - uint16 pbackus; - #endif - - pbackus = _PC; - - #undef _PC - #define _PC pbackus - - if (PAL) - cycles *= 15; /* 15*4=60 */ - else - cycles *= 16; /* 16*4=64 */ - - _count += cycles; - - while (_count > 0) { - int32 temp; - uint8 b1; - - if (_IRQlow) { - if (_IRQlow & FCEU_IQRESET) { - _PC = RdMem(0xFFFC); - _PC |= RdMem(0xFFFD) << 8; - _jammed = 0; - _PI = _P = I_FLAG; - _IRQlow &= ~FCEU_IQRESET; - } else if (_IRQlow & FCEU_IQNMI2) { - _IRQlow &= ~FCEU_IQNMI2; - _IRQlow |= FCEU_IQNMI; - } else if (_IRQlow & FCEU_IQNMI) { - if (!_jammed) { - ADDCYC(7); - PUSH(_PC >> 8); - PUSH(_PC); - PUSH((_P & ~B_FLAG) | (U_FLAG)); - _P |= I_FLAG; - _PC = RdMem(0xFFFA); - _PC |= RdMem(0xFFFB) << 8; - _IRQlow &= ~FCEU_IQNMI; - } - } else { - if (!(_PI & I_FLAG) && !_jammed) { - ADDCYC(7); - PUSH(_PC >> 8); - PUSH(_PC); - PUSH((_P & ~B_FLAG) | (U_FLAG)); - _P |= I_FLAG; - _PC = RdMem(0xFFFE); - _PC |= RdMem(0xFFFF) << 8; - } - } - _IRQlow &= ~(FCEU_IQTEMP); - if (_count <= 0) { - _PI = _P; - X.PC = pbackus; - return; - } /* Should increase accuracy without a - * major speed hit. - */ - } - - _PI = _P; - b1 = RdMem(_PC); - - ADDCYC(CycTable[b1]); - - temp = _tcount; - _tcount = 0; - if (MapIRQHook) MapIRQHook(temp); - if (!ppu.overclocked) - FCEU_SoundCPUHook(temp); - X.PC = pbackus; - _PC++; - switch (b1) { - #include "ops.inc" - } - } - - #undef _PC - #define _PC X.PC - _PC = pbackus; - #undef RdRAM - #undef WrRAM } #ifdef FCEUDEF_DEBUGGER void X6502_Debug(void (*CPUHook)(X6502 *), uint8 (*ReadHook)(X6502 *, uint32), void (*WriteHook)(X6502 *, uint32, uint8)) { debugmode = (ReadHook || WriteHook || CPUHook) ? 1 : 0; - X.ReadHook = ReadHook; - X.WriteHook = WriteHook; - X.CPUHook = CPUHook; + cpu.ReadHook = ReadHook; + cpu.WriteHook = WriteHook; + cpu.CPUHook = CPUHook; if (!debugmode) X6502_Run = X6502_RunNormal; diff --git a/src/x6502.h b/src/x6502.h index f4805440f..13501477e 100644 --- a/src/x6502.h +++ b/src/x6502.h @@ -28,14 +28,13 @@ void X6502_Debug(void (*CPUHook)(X6502 *), uint8 (*ReadHook)(X6502 *, uint32), void (*WriteHook)(X6502 *, uint32, uint8)); -extern void (*X6502_Run)(int32 cycles); -#else -void X6502_Run(int32 cycles); #endif +void X6502_Run(int32 cycles); + extern uint32 timestamp; extern uint32 sound_timestamp; -extern X6502 X; +extern X6502 cpu; #define N_FLAG 0x80 #define V_FLAG 0x40 @@ -46,20 +45,29 @@ extern X6502 X; #define Z_FLAG 0x02 #define C_FLAG 0x01 -extern void FP_FASTAPASS(1) (*MapIRQHook)(int a); +extern void (*MapIRQHook)(int a); + +/* 21.47~ MHz ÷ 12 = 1.789773 MHz */ +#define NTSC_CLOCK_SPEED 1789772.7272727272727272 + +/* 26.60~ MHz ÷ 16 = 1.662607 MHz */ +#define PAL_CLOCK_SPEED 1662607.125 + +/* 26.60~ MHz ÷ 15 = 1.773448 MHz */ +#define DENDY_CLOCK_SPEED 1773447.467 -#define NTSC_CPU (dendy ? 1773447.467 : 1789772.7272727272727272) -#define PAL_CPU 1662607.125 +#define NTSC_CPU (isDendy ? DENDY_CLOCK_SPEED : NTSC_CLOCK_SPEED) +#define PAL_CPU PAL_CLOCK_SPEED -#define FCEU_IQEXT 0x001 -#define FCEU_IQEXT2 0x002 +#define FCEU_IQEXT 0x001 +#define FCEU_IQEXT2 0x002 /* ... */ -#define FCEU_IQRESET 0x020 -#define FCEU_IQNMI2 0x040 /* Delayed NMI, gets converted to *_IQNMI */ -#define FCEU_IQNMI 0x080 -#define FCEU_IQDPCM 0x100 -#define FCEU_IQFCOUNT 0x200 -#define FCEU_IQTEMP 0x800 +#define FCEU_IQRESET 0x020 +#define FCEU_IQNMI2 0x040 /* Delayed NMI, gets converted to *_IQNMI */ +#define FCEU_IQNMI 0x080 +#define FCEU_IQDPCM 0x100 +#define FCEU_IQFCOUNT 0x200 +#define FCEU_IQTEMP 0x800 void X6502_Init(void); void X6502_Reset(void); @@ -68,10 +76,10 @@ void X6502_Power(void); void TriggerNMI(void); void TriggerNMI2(void); -uint8 FASTAPASS(1) X6502_DMR(uint32 A); -void FASTAPASS(2) X6502_DMW(uint32 A, uint8 V); +uint8 X6502_DMR(uint32 A); +void X6502_DMW(uint32 A, uint8 V); -void FASTAPASS(1) X6502_IRQBegin(int w); -void FASTAPASS(1) X6502_IRQEnd(int w); +void X6502_IRQBegin(int w); +void X6502_IRQEnd(int w); #endif diff --git a/src/ops.inc b/src/x6502ops.inc similarity index 67% rename from src/ops.inc rename to src/x6502ops.inc index 2864bab7e..23558159d 100644 --- a/src/ops.inc +++ b/src/x6502ops.inc @@ -19,140 +19,140 @@ */ case 0x00: /* BRK */ - _PC++; - PUSH(_PC>>8); - PUSH(_PC); - PUSH(_P|U_FLAG|B_FLAG); - _P|=I_FLAG; - _PI|=I_FLAG; - _PC=RdMem(0xFFFE); - _PC|=RdMem(0xFFFF)<<8; + cpu.PC++; + PUSH(cpu.PC>>8); + PUSH(cpu.PC); + PUSH(cpu.P|U_FLAG|B_FLAG); + cpu.P|=I_FLAG; + cpu.mooPI|=I_FLAG; + cpu.PC=RdMem(0xFFFE); + cpu.PC|=RdMem(0xFFFF)<<8; break; case 0x40: /* RTI */ - _P=POP(); - /* _PI=_P; This is probably incorrect, so it's commented out. */ - _PI = _P; - _PC=POP(); - _PC|=POP()<<8; + cpu.P=POP(); + /* cpu.mooPI=cpu.P; NOTE: This is probably incorrect, so it's commented out. */ + cpu.mooPI = cpu.P; + cpu.PC=POP(); + cpu.PC|=POP()<<8; break; case 0x60: /* RTS */ - _PC=POP(); - _PC|=POP()<<8; - _PC++; + cpu.PC=POP(); + cpu.PC|=POP()<<8; + cpu.PC++; break; case 0x48: /* PHA */ - PUSH(_A); + PUSH(cpu.A); break; case 0x08: /* PHP */ - PUSH(_P|U_FLAG|B_FLAG); + PUSH(cpu.P|U_FLAG|B_FLAG); break; case 0x68: /* PLA */ - _A=POP(); - X_ZN(_A); + cpu.A=POP(); + X_ZN(cpu.A); break; case 0x28: /* PLP */ - _P=POP(); + cpu.P=POP(); break; case 0x4C: - { - uint16 ptmp=_PC; + { + uint16 ptmp=cpu.PC; uint32 npc; npc=RdMem(ptmp); ptmp++; npc|=RdMem(ptmp)<<8; - _PC=npc; - } - break; /* JMP ABSOLUTE */ + cpu.PC=npc; + } + break; /* JMP ABSOLUTE */ case 0x6C: { uint32 tmp; GetAB(tmp); - _PC=RdMem(tmp); - _PC|=RdMem( ((tmp+1)&0x00FF) | (tmp&0xFF00))<<8; + cpu.PC=RdMem(tmp); + cpu.PC|=RdMem( ((tmp+1)&0x00FF) | (tmp&0xFF00))<<8; } break; case 0x20: /* JSR */ { uint8 npc; - npc=RdMem(_PC); - _PC++; - PUSH(_PC>>8); - PUSH(_PC); - _PC=RdMem(_PC)<<8; - _PC|=npc; + npc=RdMem(cpu.PC); + cpu.PC++; + PUSH(cpu.PC>>8); + PUSH(cpu.PC); + cpu.PC=RdMem(cpu.PC)<<8; + cpu.PC|=npc; } break; case 0xAA: /* TAX */ - _X=_A; - X_ZN(_A); + cpu.X=cpu.A; + X_ZN(cpu.A); break; case 0x8A: /* TXA */ - _A=_X; - X_ZN(_A); + cpu.A=cpu.X; + X_ZN(cpu.A); break; case 0xA8: /* TAY */ - _Y=_A; - X_ZN(_A); + cpu.Y=cpu.A; + X_ZN(cpu.A); break; case 0x98: /* TYA */ - _A=_Y; - X_ZN(_A); + cpu.A=cpu.Y; + X_ZN(cpu.A); break; case 0xBA: /* TSX */ - _X=_S; - X_ZN(_X); + cpu.X=cpu.S; + X_ZN(cpu.X); break; case 0x9A: /* TXS */ - _S=_X; + cpu.S=cpu.X; break; case 0xCA: /* DEX */ - _X--; - X_ZN(_X); + cpu.X--; + X_ZN(cpu.X); break; case 0x88: /* DEY */ - _Y--; - X_ZN(_Y); + cpu.Y--; + X_ZN(cpu.Y); break; case 0xE8: /* INX */ - _X++; - X_ZN(_X); + cpu.X++; + X_ZN(cpu.X); break; case 0xC8: /* INY */ - _Y++; - X_ZN(_Y); + cpu.Y++; + X_ZN(cpu.Y); break; case 0x18: /* CLC */ - _P&=~C_FLAG; + cpu.P&=~C_FLAG; break; case 0xD8: /* CLD */ - _P&=~D_FLAG; + cpu.P&=~D_FLAG; break; case 0x58: /* CLI */ - _P&=~I_FLAG; + cpu.P&=~I_FLAG; break; case 0xB8: /* CLV */ - _P&=~V_FLAG; + cpu.P&=~V_FLAG; break; case 0x38: /* SEC */ - _P|=C_FLAG; + cpu.P|=C_FLAG; break; case 0xF8: /* SED */ - _P|=D_FLAG; + cpu.P|=D_FLAG; break; case 0x78: /* SEI */ - _P|=I_FLAG; + cpu.P|=I_FLAG; break; case 0xEA: /* NOP */ @@ -279,67 +279,69 @@ case 0xF9: LD_ABY(SBC); case 0xE1: LD_IX(SBC); case 0xF1: LD_IY(SBC); -case 0x85: ST_ZP(_A); -case 0x95: ST_ZPX(_A); -case 0x8D: ST_AB(_A); -case 0x9D: ST_ABX(_A); -case 0x99: ST_ABY(_A); -case 0x81: ST_IX(_A); -case 0x91: ST_IY(_A); +case 0x85: ST_ZP(cpu.A); +case 0x95: ST_ZPX(cpu.A); +case 0x8D: ST_AB(cpu.A); +case 0x9D: ST_ABX(cpu.A); +case 0x99: ST_ABY(cpu.A); +case 0x81: ST_IX(cpu.A); +case 0x91: ST_IY(cpu.A); -case 0x86: ST_ZP(_X); -case 0x96: ST_ZPY(_X); -case 0x8E: ST_AB(_X); +case 0x86: ST_ZP(cpu.X); +case 0x96: ST_ZPY(cpu.X); +case 0x8E: ST_AB(cpu.X); -case 0x84: ST_ZP(_Y); -case 0x94: ST_ZPX(_Y); -case 0x8C: ST_AB(_Y); +case 0x84: ST_ZP(cpu.Y); +case 0x94: ST_ZPX(cpu.Y); +case 0x8C: ST_AB(cpu.Y); /* BCC */ -case 0x90: JR(!(_P&C_FLAG)); break; +case 0x90: JR(!(cpu.P&C_FLAG)); break; /* BCS */ -case 0xB0: JR(_P&C_FLAG); break; +case 0xB0: JR(cpu.P&C_FLAG); break; /* BEQ */ -case 0xF0: JR(_P&Z_FLAG); break; +case 0xF0: JR(cpu.P&Z_FLAG); break; /* BNE */ -case 0xD0: JR(!(_P&Z_FLAG)); break; +case 0xD0: JR(!(cpu.P&Z_FLAG)); break; /* BMI */ -case 0x30: JR(_P&N_FLAG); break; +case 0x30: JR(cpu.P&N_FLAG); break; /* BPL */ -case 0x10: JR(!(_P&N_FLAG)); break; +case 0x10: JR(!(cpu.P&N_FLAG)); break; /* BVC */ -case 0x50: JR(!(_P&V_FLAG)); break; +case 0x50: JR(!(cpu.P&V_FLAG)); break; /* BVS */ -case 0x70: JR(_P&V_FLAG); break; +case 0x70: JR(cpu.P&V_FLAG); break; /* AAC */ case 0x2B: -case 0x0B: LD_IM(AND;_P&=~C_FLAG;_P|=_A>>7); +case 0x0B: LD_IM(AND;cpu.P&=~C_FLAG;cpu.P|=cpu.A>>7); /* AAX */ -case 0x87: ST_ZP(_A&_X); -case 0x97: ST_ZPY(_A&_X); -case 0x8F: ST_AB(_A&_X); -case 0x83: ST_IX(_A&_X); +case 0x87: ST_ZP(cpu.A&cpu.X); +case 0x97: ST_ZPY(cpu.A&cpu.X); +case 0x8F: ST_AB(cpu.A&cpu.X); +case 0x83: ST_IX(cpu.A&cpu.X); /* ARR - ARGH, MATEY! */ -case 0x6B: { - uint8 arrtmp; - LD_IM(AND;_P&=~V_FLAG;_P|=(_A^(_A>>1))&0x40;arrtmp=_A>>7;_A>>=1;_A|=(_P&C_FLAG)<<7;_P&=~C_FLAG;_P|=arrtmp;X_ZN(_A)); +case 0x6B: + { + uint8 arrtmp; + LD_IM(AND;cpu.P&=~V_FLAG;cpu.P|=(cpu.A^(cpu.A>>1))&0x40;arrtmp=cpu.A>>7;cpu.A>>=1;cpu.A|=(cpu.P&C_FLAG)<<7;cpu.P&=~C_FLAG;cpu.P|=arrtmp;X_ZN(cpu.A)); } + /* ASR */ case 0x4B: LD_IM(AND;LSRA); /* ATX(OAL) Is this(OR with $EE) correct? Blargg did some test and found the constant to be OR with is $FF for NES */ -case 0xAB: LD_IM(_A|=0xFF;AND;_X=_A); +case 0xAB: LD_IM(cpu.A|=0xFF;AND;cpu.X=cpu.A); /* AXS */ case 0xCB: LD_IM(AXS); @@ -364,21 +366,21 @@ case 0xF3: RMW_IY(INC;SBC); /* DOP */ -case 0x04: _PC++;break; -case 0x14: _PC++;break; -case 0x34: _PC++;break; -case 0x44: _PC++;break; -case 0x54: _PC++;break; -case 0x64: _PC++;break; -case 0x74: _PC++;break; - -case 0x80: _PC++;break; -case 0x82: _PC++;break; -case 0x89: _PC++;break; -case 0xC2: _PC++;break; -case 0xD4: _PC++;break; -case 0xE2: _PC++;break; -case 0xF4: _PC++;break; +case 0x04: cpu.PC++;break; +case 0x14: cpu.PC++;break; +case 0x34: cpu.PC++;break; +case 0x44: cpu.PC++;break; +case 0x54: cpu.PC++;break; +case 0x64: cpu.PC++;break; +case 0x74: cpu.PC++;break; + +case 0x80: cpu.PC++;break; +case 0x82: cpu.PC++;break; +case 0x89: cpu.PC++;break; +case 0xC2: cpu.PC++;break; +case 0xD4: cpu.PC++;break; +case 0xE2: cpu.PC++;break; +case 0xF4: cpu.PC++;break; /* KIL */ @@ -393,13 +395,10 @@ case 0x72: case 0x92: case 0xB2: case 0xD2: -case 0xF2:ADDCYC(0xFF); - _jammed=1; - _PC--; - break; +case 0xF2: ADDCYC(0xFF); cpu.jammed=1; cpu.PC--; break; /* LAR */ -case 0xBB: RMW_ABY(_S&=x;_A=_X=_S;X_ZN(_X)); +case 0xBB: RMW_ABY(cpu.S&=x;cpu.A=cpu.X=cpu.S;X_ZN(cpu.X)); /* LAX */ case 0xA7: LD_ZP(LDA;LDX); @@ -454,31 +453,31 @@ case 0x43: RMW_IX(LSR;EOR); case 0x53: RMW_IY(LSR;EOR); /* AXA - SHA */ -case 0x93: ST_IY(_A&_X&(((A-_Y)>>8)+1)); -case 0x9F: ST_ABY(_A&_X&(((A-_Y)>>8)+1)); +case 0x93: ST_IY(cpu.A&cpu.X&(((A-cpu.Y)>>8)+1)); +case 0x9F: ST_ABY(cpu.A&cpu.X&(((A-cpu.Y)>>8)+1)); /* SYA */ case 0x9C: /* Can't reuse existing ST_ABI macro here, due to addressing weirdness. */ -{ - uint32 A; - GetABIWR(A, _X); - A = ((_Y & ((A >> 8) + 1)) << 8) | (A & 0xff); - WrMem(A, A >> 8); - break; -} + { + uint32 A; + GetABIWR(A, cpu.X); + A = ((cpu.Y & ((A >> 8) + 1)) << 8) | (A & 0xff); + WrMem(A, A >> 8); + break; + } /* SXA */ case 0x9E: /* Can't reuse existing ST_ABI macro here, due to addressing weirdness. */ -{ - uint32 A; - GetABIWR(A, _Y); - A = ((_X & ((A >> 8) + 1)) << 8) | (A & 0xff); - WrMem(A, A >> 8); - break; -} + { + uint32 A; + GetABIWR(A, cpu.Y); + A = ((cpu.X & ((A >> 8) + 1)) << 8) | (A & 0xff); + WrMem(A, A >> 8); + break; + } /* XAS */ -case 0x9B: _S=_A&_X;ST_ABY(_S& (((A-_Y)>>8)+1) ); +case 0x9B: cpu.S=cpu.A&cpu.X;ST_ABY(cpu.S& (((A-cpu.Y)>>8)+1) ); /* TOP */ case 0x0C: LD_AB(;); @@ -490,5 +489,5 @@ case 0xDC: case 0xFC: LD_ABX(;); /* XAA - BIG QUESTION MARK HERE */ -case 0x8B: _A|=0xEE; _A&=_X; LD_IM(AND); +case 0x8B: cpu.A|=0xEE; cpu.A&=cpu.X; LD_IM(AND); /* endif */ diff --git a/src/x6502struct.h b/src/x6502struct.h index fec30032f..6a9da6ab0 100644 --- a/src/x6502struct.h +++ b/src/x6502struct.h @@ -12,7 +12,7 @@ typedef struct __X6502 { int32 count; uint32 IRQlow; /* Simulated IRQ pin held low(or is it high?). And other junk hooked on for speed reasons.*/ - uint8 DB; /* Data bus "cache" for reads from certain areas */ + uint8 openbus; /* Data bus "cache" for reads from certain areas */ int preexec; /* Pre-exec'ing for debug breakpoints. */