diff --git a/.github/workflows/compilation.yml b/.github/workflows/compilation.yml new file mode 100644 index 0000000..02f4cef --- /dev/null +++ b/.github/workflows/compilation.yml @@ -0,0 +1,33 @@ +name: CI + +on: + push: + pull_request: + repository_dispatch: + types: [run_build] + +jobs: + build-ps2: + runs-on: ubuntu-latest + container: ps2dev/ps2dev:latest + steps: + - uses: actions/checkout@v2 + + - name: Install dependencies + run: | + apk add build-base git bash + + - name: Compile project + run: | + make -f Makefile.libretro platform=ps2 clean all + + - name: Get short SHA + id: slug + run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)" + + - name: Upload artifacts + if: ${{ success() }} + uses: actions/upload-artifact@v2 + with: + name: fceumm_libretro_ps2-${{ steps.slug.outputs.sha8 }} + path: fceumm_libretro_ps2.a diff --git a/.github/workflows/crowdin_prep.yml b/.github/workflows/crowdin_prep.yml new file mode 100644 index 0000000..165f24b --- /dev/null +++ b/.github/workflows/crowdin_prep.yml @@ -0,0 +1,33 @@ +# Prepare source texts & upload them to Crowdin + +name: Crowdin Source Texts Upload + +# on change to the English texts +on: + push: + branches: + - master + paths: + - 'src/drivers/libretro/libretro_core_options.h' + +jobs: + upload_source_file: + runs-on: ubuntu-latest + steps: + - name: Setup Java JDK + uses: actions/setup-java@v1 + with: + java-version: 1.8 + + - name: Setup Python + uses: actions/setup-python@v2 + + - name: Checkout + uses: actions/checkout@v2 + + - name: Upload Source + shell: bash + 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" diff --git a/.github/workflows/crowdin_translate.yml b/.github/workflows/crowdin_translate.yml new file mode 100644 index 0000000..cb8972e --- /dev/null +++ b/.github/workflows/crowdin_translate.yml @@ -0,0 +1,46 @@ +# Download translations form Crowdin & Recreate libretro_core_options_intl.h + +name: Crowdin Translation Integration + +on: + schedule: + # please choose a random time & weekday to avoid all repos synching at the same time + - cron: '20 1 * * 5' # Fridays at 1:20 AM, UTC + +jobs: + create_intl_file: + runs-on: ubuntu-latest + steps: + - name: Setup Java JDK + uses: actions/setup-java@v1 + with: + java-version: 1.8 + + - name: Setup Python + uses: actions/setup-python@v2 + + - name: Checkout + uses: actions/checkout@v2 + with: + persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token. + fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository. + + - name: Create intl file + shell: bash + 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" + + - 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 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 }} diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..33aef29 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,302 @@ +# DESCRIPTION: GitLab CI/CD for libRetro (NOT FOR GitLab-proper) + +############################################################################## +################################# BOILERPLATE ################################ +############################################################################## + +# Core definitions +.core-defs: + variables: + JNI_PATH: . + CORENAME: fceumm + MAKEFILE: Makefile.libretro + +# Inclusion templates, required for the build to work +include: + ################################## DESKTOPS ################################ + # Windows 64-bit + - project: 'libretro-infrastructure/ci-templates' + file: '/windows-x64-mingw.yml' + + # Windows 32-bit + - project: 'libretro-infrastructure/ci-templates' + file: '/windows-i686-mingw.yml' + + # Windows msvc10 64-bit + - project: 'libretro-infrastructure/ci-templates' + file: '/windows-x64-msvc10-msys2.yml' + + # Windows msvc10 32-bit + - project: 'libretro-infrastructure/ci-templates' + file: '/windows-i686-msvc10-msys2.yml' + + # Windows msvc05 32-bit + - project: 'libretro-infrastructure/ci-templates' + file: '/windows-i686-msvc05-msys2.yml' + + # Linux 64-bit + - project: 'libretro-infrastructure/ci-templates' + file: '/linux-x64.yml' + + # Linux 32-bit + - project: 'libretro-infrastructure/ci-templates' + file: '/linux-i686.yml' + + # MacOS 64-bit + - project: 'libretro-infrastructure/ci-templates' + file: '/osx-x64.yml' + + # MacOS ARM 64-bit + - project: 'libretro-infrastructure/ci-templates' + file: '/osx-arm64.yml' + + ################################## CELLULAR ################################ + # Android + - project: 'libretro-infrastructure/ci-templates' + file: '/android-jni.yml' + + # iOS + - project: 'libretro-infrastructure/ci-templates' + file: '/ios-arm64.yml' + + # iOS (armv7) + - project: 'libretro-infrastructure/ci-templates' + file: '/ios9.yml' + + ################################## CONSOLES ################################ + # PlayStation Portable + - project: 'libretro-infrastructure/ci-templates' + file: '/psp-static.yml' + + # PlayStation Vita + - project: 'libretro-infrastructure/ci-templates' + file: '/vita-static.yml' + + # PlayStation2 + - project: 'libretro-infrastructure/ci-templates' + file: '/ps2-static.yml' + + # Nintendo 3DS + - project: 'libretro-infrastructure/ci-templates' + file: '/ctr-static.yml' + + # Nintendo GameCube + - project: 'libretro-infrastructure/ci-templates' + file: '/ngc-static.yml' + + # Nintendo Wii + - project: 'libretro-infrastructure/ci-templates' + file: '/wii-static.yml' + + # Nintendo WiiU + - project: 'libretro-infrastructure/ci-templates' + file: '/wiiu-static.yml' + + # Nintendo Switch + - project: 'libretro-infrastructure/ci-templates' + file: '/libnx-static.yml' + + # OpenDingux + - project: 'libretro-infrastructure/ci-templates' + file: '/dingux-mips32.yml' + + # OpenDingux (ARM) + - project: 'libretro-infrastructure/ci-templates' + file: '/dingux-arm32.yml' + + # tvOS (AppleTV) + - project: 'libretro-infrastructure/ci-templates' + file: '/tvos-arm64.yml' + + #################################### MISC ################################## + # Emscripten + - project: 'libretro-infrastructure/ci-templates' + file: '/emscripten-static.yml' + +# Stages for building +stages: + - build-prepare + - build-shared + - build-static + +############################################################################## +#################################### STAGES ################################## +############################################################################## +# +################################### DESKTOPS ################################# +# Windows 64-bit +libretro-build-windows-x64: + extends: + - .libretro-windows-x64-mingw-make-default + - .core-defs + +# Windows 32-bit +libretro-build-windows-i686: + extends: + - .libretro-windows-i686-mingw-make-default + - .core-defs + +# Windows msvc10 64-bit +libretro-build-windows-msvc10-x64: + extends: + - .libretro-windows-x64-msvc10-msys2-make-default + - .core-defs + +# Windows msvc10 32-bit +libretro-build-windows-msvc10-i686: + extends: + - .libretro-windows-i686-msvc10-msys2-make-default + - .core-defs + +# Windows msvc05 32-bit +libretro-build-windows-msvc05-i686: + extends: + - .libretro-windows-i686-msvc05-msys2-make-default + - .core-defs + +# Linux 64-bit +libretro-build-linux-x64: + extends: + - .libretro-linux-x64-make-default + - .core-defs + +# Linux 32-bit +libretro-build-linux-i686: + extends: + - .libretro-linux-i686-make-default + - .core-defs + +# MacOS 64-bit +libretro-build-osx-x64: + extends: + - .libretro-osx-x64-make-10-7 + - .core-defs + +# MacOS ARM 64-bit +libretro-build-osx-arm64: + extends: + - .libretro-osx-arm64-make-default + - .core-defs + +################################### CELLULAR ################################# +# Android ARMv7a +android-armeabi-v7a: + extends: + - .libretro-android-jni-armeabi-v7a + - .core-defs + +# Android ARMv8a +android-arm64-v8a: + extends: + - .libretro-android-jni-arm64-v8a + - .core-defs + +# Android 64-bit x86 +android-x86_64: + extends: + - .libretro-android-jni-x86_64 + - .core-defs + +# Android 32-bit x86 +android-x86: + extends: + - .libretro-android-jni-x86 + - .core-defs + +# iOS +libretro-build-ios-arm64: + extends: + - .libretro-ios-arm64-make-default + - .core-defs + +# iOS (armv7) [iOS 9 and up] +libretro-build-ios9: + extends: + - .libretro-ios9-make-default + - .core-defs + +# tvOS +libretro-build-tvos-arm64: + extends: + - .libretro-tvos-arm64-make-default + - .core-defs + +################################### CONSOLES ################################# +# PlayStation Portable +libretro-build-psp: + extends: + - .libretro-psp-static-retroarch-master + - .core-defs + +# PlayStation Vita +libretro-build-vita: + extends: + - .libretro-vita-static-retroarch-master + - .core-defs + +# PlayStation2 +libretro-build-ps2: + extends: + - .libretro-ps2-static-retroarch-master + - .core-defs + +# Nintendo 3DS +libretro-build-ctr: + extends: + - .libretro-ctr-static-retroarch-master + - .core-defs + +# Nintendo GameCube +libretro-build-ngc: + extends: + - .libretro-ngc-static-retroarch-master + - .core-defs + +# Nintendo Wii +libretro-build-wii: + extends: + - .libretro-wii-static-retroarch-master + - .core-defs + +# Nintendo WiiU +libretro-build-wiiu: + extends: + - .libretro-wiiu-static-retroarch-master + - .core-defs + +# Nintendo Switch +libretro-build-libnx-aarch64: + extends: + - .libretro-libnx-static-retroarch-master + - .core-defs + +# OpenDingux +libretro-build-dingux-mips32: + extends: + - .libretro-dingux-mips32-make-default + - .core-defs + +# OpenDingux Beta +libretro-build-dingux-odbeta-mips32: + extends: + - .libretro-dingux-odbeta-mips32-make-default + - .core-defs + +# RetroFW +libretro-build-retrofw-mips32: + extends: + - .libretro-retrofw-mips32-make-default + - .core-defs + +# Miyoo +libretro-build-miyoo-arm32: + extends: + - .libretro-miyoo-arm32-make-default + - .core-defs + +#################################### MISC ################################## +# Emscripten +libretro-build-emscripten: + extends: + - .libretro-emscripten-static-retroarch-master + - .core-defs diff --git a/Makefile.common b/Makefile.common index fe710f6..d0ca21d 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1,69 +1,76 @@ -ifeq ($(LIBRETRO_COMM_DIR),) LIBRETRO_COMM_DIR := $(CORE_DIR)/drivers/libretro/libretro-common -endif -INCFLAGS := -I$(CORE_DIR)/drivers/libretro -I$(LIBRETRO_COMM_DIR)/include -I$(CORE_DIR) -I$(CORE_DIR)/input -I$(CORE_DIR)/boards -COREDEFINES = -D__LIBRETRO__ -DSOUND_QUALITY=0 -DPATH_MAX=1024 -DFCEU_VERSION_NUMERIC=9813 -DFRONTEND_SUPPORTS_RGB565 -ifeq ($(PSS_STYLE),2) -COREDEFINES += -DPSS_STYLE=2 -else -COREDEFINES += -DPSS_STYLE=1 +INCFLAGS := \ + -I$(CORE_DIR)/drivers/libretro \ + -I$(LIBRETRO_COMM_DIR)/include \ + -I$(CORE_DIR) \ + -I$(CORE_DIR)/input \ + -I$(CORE_DIR)/boards + +ifneq (,$(findstring msvc2003,$(platform))) + INCFLAGS += -I$(LIBRETRO_COMM_DIR)/include/compat/msvc endif -ifeq ($(TUP_CWD),) -FCEU_SRC_DIRS := $(CORE_DIR)/boards $(CORE_DIR)/input $(CORE_DIR)/mappers -SOURCES_C := $(foreach dir,$(FCEU_SRC_DIRS),$(wildcard $(dir)/*.c)) -else -SOURCES_C = $(CORE_DIR)/boards/*.c $(CORE_DIR)/input/*.c -endif +COREDEFINES = \ + -D__LIBRETRO__ \ + -DPATH_MAX=1024 \ + -DFCEU_VERSION_NUMERIC=9813 \ + -DFRONTEND_SUPPORTS_RGB565 + +FCEU_SRC_DIRS := \ + $(CORE_DIR)/boards \ + $(CORE_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 -endif - -ifeq ($(HAVE_GRIFFIN),1) -SOURCES_C += $(CORE_DIR)/drivers/libretro/griffin.c -else -SOURCES_C += \ - $(CORE_DIR)/drivers/libretro/libretro.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)/misc.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 - -ifeq ($(STATIC_LINKING),1) -else -SOURCES_C += $(CORE_DIR)/drivers/libretro/libretro-common/streams/memory_stream.c \ - $(CORE_DIR)/drivers/libretro/libretro-common/compat/compat_snprintf.c \ - $(CORE_DIR)/drivers/libretro/libretro-common/string/stdstring.c \ - $(CORE_DIR)/drivers/libretro/libretro-common/encodings/encoding_utf.c \ - $(CORE_DIR)/drivers/libretro/libretro-common/compat/compat_strl.c -endif - -ifeq ($(DEBUG),1) -SOURCES_C += $(CORE_DIR)/debug.c -endif + COREDEFINES += \ + -DHAVE_NTSC_FILTER \ + -I$(CORE_DIR)/ntsc + SOURCES_C += $(CORE_DIR)/ntsc/nes_ntsc.c endif SOURCES_C += \ - $(CORE_DIR)/ines.c \ - $(CORE_DIR)/unif.c $(CORE_DIR)/x6502.c \ - $(CORE_DIR)/drivers/libretro/libretro_dipswitch.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 + +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)/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 +endif diff --git a/Makefile.libretro b/Makefile.libretro index 42f51bc..14b8cbe 100644 --- a/Makefile.libretro +++ b/Makefile.libretro @@ -1,7 +1,5 @@ DEBUG=0 -PSS_STYLE=1 EXTERNAL_ZLIB=0 -HAVE_GRIFFIN=1 STATIC_LINKING=0 ENDIANNESS_DEFINES= SIGNED_CHAR=0 @@ -25,10 +23,6 @@ ifeq ($(platform),) platform = win else ifneq ($(findstring Darwin,$(shell uname -s)),) platform = osx - arch = intel - ifeq ($(shell uname -p),powerpc) - arch = ppc - endif else ifneq ($(findstring win,$(shell uname -s)),) platform = win endif @@ -41,10 +35,15 @@ ifeq ($(shell uname -a),) system_platform = win else ifneq ($(findstring Darwin,$(shell uname -a)),) system_platform = osx - arch = intel - ifeq ($(shell uname -p),powerpc) - arch = ppc +ifeq ($(shell uname -p),powerpc) + arch = ppc +else + ifeq ($(shell uname -p),arm) + arch = arm64 + else + arch = intel endif +endif else ifneq ($(findstring MINGW,$(shell uname -a)),) system_platform = win endif @@ -84,11 +83,19 @@ else ifeq ($(platform), osx) fpic := -fPIC SHARED := -dynamiclib ifeq ($(arch),ppc) - ENDIANNESS_DEFINES += -DMSB_FIRST + ENDIANNESS_DEFINES += -DMSB_FIRST -DHAVE_NO_LANGEXTRA endif + ifeq ($(CROSS_COMPILE),1) + TARGET_RULE = -target $(LIBRETRO_APPLE_PLATFORM) -isysroot $(LIBRETRO_APPLE_ISYSROOT) + CFLAGS += $(TARGET_RULE) + LDFLAGS += $(TARGET_RULE) + endif + OSXVER = `sw_vers -productVersion | cut -d. -f 2` OSX_LT_MAVERICKS = `(( $(OSXVER) <= 9)) && echo "YES"` - fpic += -mmacosx-version-min=10.1 + ifeq ($(OSX_LT_MAVERICKS),YES) + fpic += -mmacosx-version-min=10.1 + endif ifndef ($(NOUNIVERSAL)) CFLAGS += $(ARCHFLAGS) LDFLAGS += $(ARCHFLAGS) @@ -147,42 +154,19 @@ else ifeq ($(platform), qnx) AR = qcc -Vgcc_ntoarmv7le PLATFORM_DEFINES := -D__BLACKBERRY_QNX__ -marm -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp -# PS3 -else ifeq ($(platform), ps3) - TARGET := $(TARGET_NAME)_libretro_$(platform).a - CC = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-gcc.exe - AR = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-ar.exe - PLATFORM_DEFINES := -D__CELLOS_LV2 - ENDIANNESS_DEFINES += -DMSB_FIRST - STATIC_LINKING=1 - EXTERNAL_ZLIB=1 - -# sncps3 -else ifeq ($(platform), sncps3) - TARGET := $(TARGET_NAME)_libretro_ps3.a - CC = $(CELL_SDK)/host-win32/sn/bin/ps3ppusnc.exe - AR = $(CELL_SDK)/host-win32/sn/bin/ps3snarl.exe - PLATFORM_DEFINES := -D__CELLOS_LV2 - ENDIANNESS_DEFINES += -DMSB_FIRST - STATIC_LINKING=1 - EXTERNAL_ZLIB=1 - # PS2 else ifeq ($(platform), ps2) TARGET := $(TARGET_NAME)_libretro_$(platform).a - CC = ee-gcc$(EXE_EXT) - AR = ee-ar$(EXE_EXT) - FCEU_DEFINES := -DPATH_MAX=1024 -DINLINE=inline -DPSS_STYLE=1 -DFCEU_VERSION_NUMERIC=9813 -DHAVE_ASPRINTF + 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 ENDIANNESS_DEFINES := -DLSB_FIRST -DLOCAL_LE=1 - PLATFORM_DEFINES := -DPS2 -G0 -DFRONTEND_SUPPORTS_ABGR1555 -DRENDER_GSKIT_PS2 - PLATFORM_DEFINES += -Dmemcpy=mips_memcpy -Dmemset=mips_memset - PLATFORM_DEFINES += -I$(PS2SDK)/ee/include -I$(PS2SDK)/common/include -Ips2/ -I$(PS2DEV)/gsKit/include + 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 STATIC_LINKING=1 EXTERNAL_ZLIB=1 - RETROARCH_OBJECTS += ps2/SMS_Utils.o HAVE_NTSC = 0 - # PSP else ifeq ($(platform), psp1) TARGET := $(TARGET_NAME)_libretro_$(platform).a @@ -244,16 +228,47 @@ else ifeq ($(platform), rpi2) CFLAGS += -DARM CFLAGS += -marm -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -funsafe-math-optimizations CFLAGS += -fomit-frame-pointer -fstrict-aliasing -ffast-math + +# Raspberry Pi 3 +else ifeq ($(platform), rpi3) + TARGET := $(TARGET_NAME)_libretro.so + fpic := -fPIC + SHARED := -shared -Wl,--version-script=src/drivers/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 + +# Raspberry Pi 3 (64 bit) +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 + CFLAGS += -mcpu=cortex-a53 -mtune=cortex-a53 -funsafe-math-optimizations + CFLAGS += -fomit-frame-pointer -fstrict-aliasing -ffast-math + +# Raspberry Pi 4 (64-bit) +else ifneq (,$(findstring rpi4,$(platform))) + TARGET := $(TARGET_NAME)_libretro.so + fpic := -fPIC + SHARED := -shared -Wl,--version-script=src/drivers/libretro/link.T -Wl,-no-undefined + CFLAGS += -mcpu=cortex-a72 -mtune=cortex-a72 -funsafe-math-optimizations + CFLAGS += -fomit-frame-pointer -fstrict-aliasing -ffast-math # Lightweight PS3 Homebrew SDK -else ifeq ($(platform), psl1ght) - TARGET := $(TARGET_NAME)_libretro_$(platform).a - CC = $(PS3DEV)/ppu/bin/ppu-gcc$(EXE_EXT) - AR = $(PS3DEV)/ppu/bin/ppu-ar$(EXE_EXT) - PLATFORM_DEFINES := -D__CELLOS_LV2 - ENDIANNESS_DEFINES += -DMSB_FIRST - STATIC_LINKING=1 - EXTERNAL_ZLIB=1 +else ifneq (,$(filter $(platform), ps3 psl1ght)) + ENDIANNESS_DEFINES = -DMSB_FIRST + EXTERNAL_ZLIB = 1 + STATIC_LINKING = 1 + PLATFORM_DEFINES += -D__PS3__ + + ifeq ($(platform), psl1ght) + PLATFORM_DEFINES += -D__PSL1GHT__ + endif + + TARGET := $(TARGET_NAME)_libretro_$(platform).a + CC = $(PS3DEV)/ppu/bin/ppu-$(COMMONLV)gcc$(EXE_EXT) + CXX = $(PS3DEV)/ppu/bin/ppu-$(COMMONLV)g++$(EXE_EXT) + AR = $(PS3DEV)/ppu/bin/ppu-$(COMMONLV)ar$(EXE_EXT) # Xbox 360 else ifeq ($(platform), xenon) @@ -380,8 +395,8 @@ else ifeq ($(platform), classic_armv8_a35) ARCH = arm BUILTIN_GPU = neon USE_DYNAREC = 1 - CFLAGS += -march=armv8-a - LDFLAGS += -static-libgcc -static-libstdc++ + LDFLAGS += -lrt + LDFLAGS += -marm -mcpu=cortex-a35 -mfpu=neon-fp-armv8 -mfloat-abi=hard -Ofast -flto -fuse-linker-plugin ####################################### # ARM @@ -424,6 +439,28 @@ else ifeq ($(platform), gcw0) PLATFORM_DEFINES += -ffast-math -march=mips32 -mtune=mips32r2 -mhard-float -fomit-frame-pointer EXTERNAL_ZLIB = 1 +# RETROFW +else ifeq ($(platform), retrofw) + TARGET := $(TARGET_NAME)_libretro.so + CC = /opt/retrofw-toolchain/usr/bin/mipsel-linux-gcc + 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 + PLATFORM_DEFINES += -ffast-math -march=mips32 -mtune=mips32 -mhard-float -fomit-frame-pointer + EXTERNAL_ZLIB = 1 + +# Miyoo +else ifeq ($(platform), miyoo) + TARGET := $(TARGET_NAME)_libretro.so + CC = /opt/miyoo/usr/bin/arm-linux-gcc + 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 + PLATFORM_DEFINES += -fomit-frame-pointer -ffast-math -mcpu=arm926ej-s + EXTERNAL_ZLIB = 1 + # Windows MSVC 2017 all architectures else ifneq (,$(findstring windows_msvc2017,$(platform))) CC = cl.exe @@ -511,7 +548,6 @@ else ifneq (,$(findstring windows_msvc2017,$(platform))) export INCLUDE := $(INCLUDE);$(WindowsSDKSharedIncludeDir);$(WindowsSDKUCRTIncludeDir);$(WindowsSDKUMIncludeDir) export LIB := $(LIB);$(WindowsSDKUCRTLibDir);$(WindowsSDKUMLibDir) TARGET := $(TARGET_NAME)_libretro.dll - PSS_STYLE :=2 LDFLAGS += -DLL # Windows MSVC 2010 x64 @@ -521,20 +557,20 @@ else ifeq ($(platform), windows_msvc2010_x64) PATH := $(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../../VC/bin/amd64"):$(PATH) PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../IDE") -INCLUDE := $(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../../VC/include") LIB := $(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../../VC/lib/amd64") -BIN := $(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../../VC/bin") +INCLUDE := $(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../../VC/include") -WindowsSdkDir := $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')lib/x64 -WindowsSdkDir ?= $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')lib/x64 -WindowsSdkDirInc := $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')Include -WindowsSdkDirInc ?= $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')Include +WindowsSdkDir := $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*') +WindowsSdkDir ?= $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*') -INCFLAGS_PLATFORM = -I"$(WindowsSdkDirInc)" -export INCLUDE := $(INCLUDE) -export LIB := $(LIB);$(WindowsSdkDir) +WindowsSDKIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include") +WindowsSDKGlIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\gl") +WindowsSDKLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib\x64") + +INCFLAGS_PLATFORM = -I"$(WindowsSDKIncludeDir)" +export INCLUDE := $(INCLUDE);$(WindowsSDKIncludeDir);$(WindowsSDKGlIncludeDir) +export LIB := $(LIB);$(WindowsSDKLibDir) TARGET := $(TARGET_NAME)_libretro.dll -PSS_STYLE :=2 LDFLAGS += -DLL # Windows MSVC 2010 x86 @@ -544,20 +580,20 @@ else ifeq ($(platform), windows_msvc2010_x86) PATH := $(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../../VC/bin"):$(PATH) PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../IDE") -INCLUDE := $(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../../VC/include") LIB := $(shell IFS=$$'\n'; cygpath -w "$(VS100COMNTOOLS)../../VC/lib") -BIN := $(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../../VC/bin") +INCLUDE := $(shell IFS=$$'\n'; cygpath "$(VS100COMNTOOLS)../../VC/include") -WindowsSdkDir := $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')lib -WindowsSdkDir ?= $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')lib -WindowsSdkDirInc := $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')Include -WindowsSdkDirInc ?= $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*')Include +WindowsSdkDir := $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*') +WindowsSdkDir ?= $(shell reg query "HKLM\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A" -v "InstallationFolder" | grep -o '[A-Z]:\\.*') -INCFLAGS_PLATFORM = -I"$(WindowsSdkDirInc)" -export INCLUDE := $(INCLUDE) -export LIB := $(LIB);$(WindowsSdkDir) +WindowsSDKIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include") +WindowsSDKGlIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\gl") +WindowsSDKLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib") + +INCFLAGS_PLATFORM = -I"$(WindowsSDKIncludeDir)" +export INCLUDE := $(INCLUDE);$(WindowsSDKIncludeDir);$(WindowsSDKGlIncludeDir) +export LIB := $(LIB);$(WindowsSDKLibDir) TARGET := $(TARGET_NAME)_libretro.dll -PSS_STYLE :=2 LDFLAGS += -DLL # Windows MSVC 2003 Xbox 1 @@ -571,7 +607,6 @@ export INCLUDE := $(XDK)\xbox\include export LIB := $(XDK)\xbox\lib PATH := $(call unixcygpath,$(XDK)/xbox/bin/vc71):$(PATH) -PSS_STYLE :=2 CFLAGS += -D_XBOX -D_XBOX1 CXXFLAGS += -D_XBOX -D_XBOX1 STATIC_LINKING=1 @@ -587,7 +622,6 @@ export INCLUDE := $(XEDK)/include/xbox export LIB := $(XEDK)/lib/xbox PATH := $(call unixcygpath,$(XEDK)/bin/win32):$(PATH) -PSS_STYLE :=2 CFLAGS += -D_XBOX -D_XBOX360 CXXFLAGS += -D_XBOX -D_XBOX360 ENDIANNESS_DEFINES += -DMSB_FIRST @@ -609,7 +643,6 @@ WindowsSdkDir := $(INETSDK) export INCLUDE := $(INCLUDE);$(INETSDK)/Include export LIB := $(LIB);$(WindowsSdkDir);$(INETSDK)/Lib TARGET := $(TARGET_NAME)_libretro.dll -PSS_STYLE :=2 LDFLAGS += -DLL CFLAGS += -D_CRT_SECURE_NO_DEPRECATE @@ -624,12 +657,18 @@ INCLUDE := $(shell IFS=$$'\n'; cygpath "$(VS80COMNTOOLS)../../VC/include") LIB := $(shell IFS=$$'\n'; cygpath -w "$(VS80COMNTOOLS)../../VC/lib") BIN := $(shell IFS=$$'\n'; cygpath "$(VS80COMNTOOLS)../../VC/bin") -WindowsSdkDir := $(INETSDK) +WindowsSdkDir := $(shell reg query "HKLM\SOFTWARE\Microsoft\MicrosoftSDK\InstalledSDKs\8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3" -v "Install Dir" | grep -o '[A-Z]:\\.*') -export INCLUDE := $(INCLUDE);$(INETSDK)/Include -export LIB := $(LIB);$(WindowsSdkDir);$(INETSDK)/Lib +WindowsSDKIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include") +WindowsSDKAtlIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\atl") +WindowsSDKCrtIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\crt") +WindowsSDKGlIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\gl") +WindowsSDKMfcIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\mfc") +WindowsSDKLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib") + +export INCLUDE := $(INCLUDE);$(WindowsSDKIncludeDir);$(WindowsSDKAtlIncludeDir);$(WindowsSDKCrtIncludeDir);$(WindowsSDKGlIncludeDir);$(WindowsSDKMfcIncludeDir);libretro-common/include/compat/msvc +export LIB := $(LIB);$(WindowsSDKLibDir) TARGET := $(TARGET_NAME)_libretro.dll -PSS_STYLE :=2 LDFLAGS += -DLL CFLAGS += -D_CRT_SECURE_NO_DEPRECATE @@ -649,7 +688,6 @@ WindowsSdkDir := $(INETSDK) export INCLUDE := $(INCLUDE);$(INETSDK)/Include export LIB := $(LIB);$(WindowsSdkDir);$(INETSDK)/Lib TARGET := $(TARGET_NAME)_libretro.dll -PSS_STYLE :=2 LDFLAGS += -DLL CFLAGS += -D_CRT_SECURE_NO_DEPRECATE @@ -658,41 +696,27 @@ else TARGET := $(TARGET_NAME)_libretro.dll CC ?= gcc SHARED := -shared -static-libgcc -static-libstdc++ -s -Wl,--version-script=src/drivers/libretro/link.T - PSS_STYLE :=2 endif ifeq ($(DEBUG), 1) ifneq (,$(findstring msvc,$(platform))) - ifeq ($(STATIC_LINKING),1) - CFLAGS += -MTd - CXXFLAGS += -MTd - else - CFLAGS += -MDd - CXXFLAGS += -MDd - endif - - CFLAGS += -Od -Zi -DDEBUG -D_DEBUG - CXXFLAGS += -Od -Zi -DDEBUG -D_DEBUG + CFLAGS += -MTd + CXXFLAGS += -MTd + CFLAGS += -Od -Zi -D_DEBUG + CXXFLAGS += -Od -Zi -D_DEBUG else - CFLAGS += -O0 -g -DDEBUG - CXXFLAGS += -O0 -g -DDEBUG + CFLAGS += -O0 -g + CXXFLAGS += -O0 -g endif + CFLAGS += -DDEBUG + CXXFLAGS += -DDEBUG else ifneq (,$(findstring msvc,$(platform))) - ifeq ($(STATIC_LINKING),1) - CFLAGS += -MT - CXXFLAGS += -MT - else - CFLAGS += -MD - CXXFLAGS += -MD - endif - - CFLAGS += -O2 -DNDEBUG - CXXFLAGS += -O2 -DNDEBUG - else - CFLAGS += -O2 -DNDEBUG - CXXFLAGS += -O2 -DNDEBUG + CFLAGS += -MT + CXXFLAGS += -MT endif + CFLAGS += -O2 -DNDEBUG + CXXFLAGS += -O2 -DNDEBUG endif ifneq ($(SANITIZER),) @@ -726,8 +750,6 @@ ifneq (,$(findstring msvc,$(platform))) COREDEFINES += -DINLINE=_inline endif -CFLAGS += -DWANT_GRIFFIN -Werror=implicit-function-declaration - OBJECTS := $(SOURCES_C:.c=.o) OBJECTS += $(RETROARCH_OBJECTS) @@ -796,11 +818,6 @@ endif %.o: %.c $(CC) -c $(OBJOUT)$@ $< $(CFLAGS) $(INCFLAGS) -ifeq ($(platform), ps2) -%.o: %.s - ee-as -G0 $< -o $@ -endif - clean-objs: rm -f $(OBJECTS) diff --git a/README.md b/README.md index 3c1d4d7..a7f8997 100644 --- a/README.md +++ b/README.md @@ -4,3 +4,5 @@ # FCE Ultra mappers modified 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. +# Sequential targets Light Guns support added +Support for Sequential targets Light Guns has been added. "Gun Aux A" serves as light sensor logic input. \ No newline at end of file diff --git a/intl/.gitignore b/intl/.gitignore new file mode 100644 index 0000000..458f3d3 --- /dev/null +++ b/intl/.gitignore @@ -0,0 +1,4 @@ +__pycache__ +crowdin-cli.jar +*.h +*.json diff --git a/intl/activate.py b/intl/activate.py new file mode 100755 index 0000000..0ef70c2 --- /dev/null +++ b/intl/activate.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 + +import os +import glob +import random as r + +# -------------------- MAIN -------------------- # + +if __name__ == '__main__': + DIR_PATH = os.path.dirname(os.path.realpath(__file__)) + if os.path.basename(DIR_PATH) != "intl": + raise RuntimeError("Script is not in intl folder!") + + BASE_PATH = os.path.dirname(DIR_PATH) + WORKFLOW_PATH = os.path.join(BASE_PATH, ".github", "workflows") + PREP_WF = os.path.join(WORKFLOW_PATH, "crowdin_prep.yml") + TRANSLATE_WF = os.path.join(WORKFLOW_PATH, "crowdin_translate.yml") + CORE_NAME = os.path.basename(BASE_PATH) + CORE_OP_FILE = os.path.join(BASE_PATH, "**", "libretro_core_options.h") + + core_options_hits = glob.glob(CORE_OP_FILE, recursive=True) + + if len(core_options_hits) == 0: + raise RuntimeError("libretro_core_options.h not found!") + elif len(core_options_hits) > 1: + print("More than one libretro_core_options.h file found:\n\n") + for i, file in enumerate(core_options_hits): + print(f"{i} {file}\n") + + while True: + user_choice = input("Please choose one ('q' will exit): ") + if user_choice == 'q': + exit(0) + elif user_choice.isdigit(): + core_op_file = core_options_hits[int(user_choice)] + break + else: + print("Please make a valid choice!\n\n") + else: + core_op_file = core_options_hits[0] + + core_intl_file = os.path.join(os.path.dirname(core_op_file.replace(BASE_PATH, ''))[1:], + 'libretro_core_options_intl.h') + core_op_file = os.path.join(os.path.dirname(core_op_file.replace(BASE_PATH, ''))[1:], + 'libretro_core_options.h') + minutes = r.randrange(0, 59, 5) + hour = r.randrange(0, 23) + + with open(PREP_WF, 'r') as wf_file: + prep_txt = wf_file.read() + + prep_txt = prep_txt.replace("", CORE_NAME) + prep_txt = prep_txt.replace("/libretro_core_options.h", + core_op_file) + with open(PREP_WF, 'w') as wf_file: + wf_file.write(prep_txt) + + + with open(TRANSLATE_WF, 'r') as wf_file: + translate_txt = wf_file.read() + + translate_txt = translate_txt.replace('<0-59>', f"{minutes}") + translate_txt = translate_txt.replace('<0-23>', f"{hour}") + translate_txt = translate_txt.replace('# Fridays at , UTC', + f"# Fridays at {hour%12}:{minutes} {'AM' if hour < 12 else 'PM'}, UTC") + translate_txt = translate_txt.replace("", CORE_NAME) + translate_txt = translate_txt.replace('/libretro_core_options_intl.h', + core_intl_file) + with open(TRANSLATE_WF, 'w') as wf_file: + wf_file.write(translate_txt) diff --git a/intl/core_option_regex.py b/intl/core_option_regex.py new file mode 100644 index 0000000..34a3f20 --- /dev/null +++ b/intl/core_option_regex.py @@ -0,0 +1,95 @@ +import re + +# 0: full struct; 1: up to & including first []; 2: content between first {} +p_struct = re.compile(r'(struct\s*[a-zA-Z0-9_\s]+\[])\s*' + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+)\s*)*' + r'=\s*' # = + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+)\s*)*' + r'{((?:.|[\r\n])*?)\{\s*NULL,\s*NULL,\s*NULL\s*(?:.|[\r\n])*?},?(?:.|[\r\n])*?};') # captures full struct, it's beginning and it's content +# 0: type name[]; 1: type; 2: name +p_type_name = re.compile(r'(retro_core_option_[a-zA-Z0-9_]+)\s*' + r'(option_cats([a-z_]{0,8})|option_defs([a-z_]{0,8}))\s*\[]') +# 0: full option; 1: key; 2: description; 3: additional info; 4: key/value pairs +p_option = re.compile(r'{\s*' # opening braces + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r'(\".*?\"|' # key start; group 1 + r'[a-zA-Z0-9_]+\s*\((?:.|[\r\n])*?\)|' + r'[a-zA-Z0-9_]+\s*\[(?:.|[\r\n])*?]|' + r'[a-zA-Z0-9_]+\s*\".*?\")\s*' # key end + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r',\s*' # comma + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r'(\".*?\")\s*' # description; group 2 + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r',\s*' # comma + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r'((?:' # group 3 + r'(?:NULL|\"(?:.|[\r\n])*?\")\s*' # description in category, info, info in category, category + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r',?\s*' # comma + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r')+)' + r'(?:' # defs only start + r'{\s*' # opening braces + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r'((?:' # key/value pairs start; group 4 + r'{\s*' # opening braces + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r'(?:NULL|\".*?\")\s*' # option key + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r',\s*' # comma + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r'(?:NULL|\".*?\")\s*' # option value + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r'}\s*' # closing braces + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r',?\s*' # comma + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r')*)' # key/value pairs end + r'}\s*' # closing braces + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r',?\s*' # comma + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r'(?:' # defaults start + r'(?:NULL|\".*?\")\s*' # default value + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r',?\s*' # comma + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r')*' # defaults end + r')?' # defs only end + r'},') # closing braces +# analyse option group 3 +p_info = re.compile(r'(NULL|\"(?:.|[\r\n])*?\")\s*' # description in category, info, info in category, category + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r',') +p_info_cat = re.compile(r'(NULL|\"(?:.|[\r\n])*?\")') +# analyse option group 4 +p_key_value = re.compile(r'{\s*' # opening braces + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r'(NULL|\".*?\")\s*' # option key; 1 + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r',\s*' # comma + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r'(NULL|\".*?\")\s*' # option value; 2 + r'(?:(?:\/\*(?:.|[\r\n])*?\*\/|\/\/.*[\r\n]+|#.*[\r\n]+)\s*)*' + r'}') + +p_masked = re.compile(r'([A-Z_][A-Z0-9_]+)\s*(\"(?:"\s*"|\\\s*|.)*\")') + +p_intl = re.compile(r'(struct retro_core_option_definition \*option_defs_intl\[RETRO_LANGUAGE_LAST]) = {' + r'((?:.|[\r\n])*?)};') +p_set = re.compile(r'static INLINE void libretro_set_core_options\(retro_environment_t environ_cb\)' + r'(?:.|[\r\n])*?};?\s*#ifdef __cplusplus\s*}\s*#endif') + +p_yaml = re.compile(r'"project_id": "[0-9]+".*\s*' + r'"api_token": "([a-zA-Z0-9]+)".*\s*' + r'"base_path": "\./intl".*\s*' + r'"base_url": "https://api\.crowdin\.com".*\s*' + r'"preserve_hierarchy": true.*\s*' + r'"files": \[\s*' + r'\{\s*' + r'"source": "/_us/\*\.json",.*\s*' + r'"translation": "/_%two_letters_code%/%original_file_name%",.*\s*' + r'"skip_untranslated_strings": true.*\s*' + r'},\s*' + r']') diff --git a/intl/core_option_translation.py b/intl/core_option_translation.py new file mode 100755 index 0000000..54a4cf9 --- /dev/null +++ b/intl/core_option_translation.py @@ -0,0 +1,620 @@ +#!/usr/bin/env python3 + +"""Core options text extractor + +The purpose of this script is to set up & provide functions for automatic generation of 'libretro_core_options_intl.h' +from 'libretro_core_options.h' using translations from Crowdin. + +Both v1 and v2 structs are supported. It is, however, recommended to convert v1 files to v2 using the included +'v1_to_v2_converter.py'. + +Usage: +python3 path/to/core_option_translation.py "path/to/where/libretro_core_options.h & libretro_core_options_intl.h/are" "core_name" + +This script will: +1.) create key words for & extract the texts from libretro_core_options.h & save them into intl/_us/core_options.h +2.) do the same for any present translations in libretro_core_options_intl.h, saving those in their respective folder +""" +import core_option_regex as cor +import re +import os +import sys +import json +import urllib.request as req +import shutil + +# LANG_CODE_TO_R_LANG = {'_ar': 'RETRO_LANGUAGE_ARABIC', +# '_ast': 'RETRO_LANGUAGE_ASTURIAN', +# '_chs': 'RETRO_LANGUAGE_CHINESE_SIMPLIFIED', +# '_cht': 'RETRO_LANGUAGE_CHINESE_TRADITIONAL', +# '_cs': 'RETRO_LANGUAGE_CZECH', +# '_cy': 'RETRO_LANGUAGE_WELSH', +# '_da': 'RETRO_LANGUAGE_DANISH', +# '_de': 'RETRO_LANGUAGE_GERMAN', +# '_el': 'RETRO_LANGUAGE_GREEK', +# '_eo': 'RETRO_LANGUAGE_ESPERANTO', +# '_es': 'RETRO_LANGUAGE_SPANISH', +# '_fa': 'RETRO_LANGUAGE_PERSIAN', +# '_fi': 'RETRO_LANGUAGE_FINNISH', +# '_fr': 'RETRO_LANGUAGE_FRENCH', +# '_gl': 'RETRO_LANGUAGE_GALICIAN', +# '_he': 'RETRO_LANGUAGE_HEBREW', +# '_hu': 'RETRO_LANGUAGE_HUNGARIAN', +# '_id': 'RETRO_LANGUAGE_INDONESIAN', +# '_it': 'RETRO_LANGUAGE_ITALIAN', +# '_ja': 'RETRO_LANGUAGE_JAPANESE', +# '_ko': 'RETRO_LANGUAGE_KOREAN', +# '_nl': 'RETRO_LANGUAGE_DUTCH', +# '_oc': 'RETRO_LANGUAGE_OCCITAN', +# '_pl': 'RETRO_LANGUAGE_POLISH', +# '_pt_br': 'RETRO_LANGUAGE_PORTUGUESE_BRAZIL', +# '_pt_pt': 'RETRO_LANGUAGE_PORTUGUESE_PORTUGAL', +# '_ru': 'RETRO_LANGUAGE_RUSSIAN', +# '_sk': 'RETRO_LANGUAGE_SLOVAK', +# '_sv': 'RETRO_LANGUAGE_SWEDISH', +# '_tr': 'RETRO_LANGUAGE_TURKISH', +# '_uk': 'RETRO_LANGUAGE_UKRAINIAN', +# '_us': 'RETRO_LANGUAGE_ENGLISH', +# '_vn': 'RETRO_LANGUAGE_VIETNAMESE'} + +# these are handled by RetroArch directly - no need to include them in core translations +ON_OFFS = {'"enabled"', '"disabled"', '"true"', '"false"', '"on"', '"off"'} + + +def remove_special_chars(text: str, char_set=0, allow_non_ascii=False) -> str: + """Removes special characters from a text. + + :param text: String to be cleaned. + :param char_set: 0 -> remove all ASCII special chars except for '_' & 'space' (default) + 1 -> remove invalid chars from file names + :param allow_non_ascii: False -> all non-ascii characters will be removed (default) + True -> non-ascii characters will be passed through + :return: Clean text. + """ + command_chars = [chr(unicode) for unicode in tuple(range(0, 32)) + (127,)] + special_chars = ([chr(unicode) for unicode in tuple(range(33, 48)) + tuple(range(58, 65)) + tuple(range(91, 95)) + + (96,) + tuple(range(123, 127))], + ('\\', '/', ':', '*', '?', '"', '<', '>', '|', '#', '%', + '&', '{', '}', '$', '!', '¸', "'", '@', '+', '=')) + res = text if allow_non_ascii \ + else text.encode('ascii', errors='ignore').decode('unicode-escape') + + for cm in command_chars: + res = res.replace(cm, '_') + for sp in special_chars[char_set]: + res = res.replace(sp, '_') + while res.startswith('_'): + res = res[1:] + while res.endswith('_'): + res = res[:-1] + return res + + +def clean_file_name(file_name: str) -> str: + """Removes characters which might make file_name inappropriate for files on some OS. + + :param file_name: File name to be cleaned. + :return: The clean file name. + """ + file_name = remove_special_chars(file_name, 1) + file_name = re.sub(r'__+', '_', file_name.replace(' ', '_')) + return file_name + + +def get_struct_type_name(decl: str) -> tuple: + """ Returns relevant parts of the struct declaration: + type, name of the struct and the language appendix, if present. + :param decl: The struct declaration matched by cor.p_type_name. + :return: Tuple, e.g.: ('retro_core_option_definition', 'option_defs_us', '_us') + """ + struct_match = cor.p_type_name.search(decl) + if struct_match: + if struct_match.group(3): + struct_type_name = struct_match.group(1, 2, 3) + return struct_type_name + elif struct_match.group(4): + struct_type_name = struct_match.group(1, 2, 4) + return struct_type_name + else: + struct_type_name = struct_match.group(1, 2) + return struct_type_name + else: + raise ValueError(f'No or incomplete struct declaration: {decl}!\n' + 'Please make sure all structs are complete, including the type and name declaration.') + + +def is_viable_non_dupe(text: str, comparison) -> bool: + """text must be longer than 2 ('""'), not 'NULL' and not in comparison. + + :param text: String to be tested. + :param comparison: Dictionary or set to search for text in. + :return: bool + """ + return 2 < len(text) and text != 'NULL' and text not in comparison + + +def is_viable_value(text: str) -> bool: + """text must be longer than 2 ('""'), not 'NULL' and text.lower() not in + {'"enabled"', '"disabled"', '"true"', '"false"', '"on"', '"off"'}. + + :param text: String to be tested. + :return: bool + """ + return 2 < len(text) and text != 'NULL' and text.lower() not in ON_OFFS + + +def create_non_dupe(base_name: str, opt_num: int, comparison) -> str: + """Makes sure base_name is not in comparison, and if it is it's renamed. + + :param base_name: Name to check/make unique. + :param opt_num: Number of the option base_name belongs to, used in making it unique. + :param comparison: Dictionary or set to search for base_name in. + :return: Unique name. + """ + h = base_name + if h in comparison: + n = 0 + h = h + '_O' + str(opt_num) + h_end = len(h) + while h in comparison: + h = h[:h_end] + '_' + str(n) + n += 1 + return h + + +def get_texts(text: str) -> dict: + """Extracts the strings, which are to be translated/are the translations, + from text and creates macro names for them. + + :param text: The string to be parsed. + :return: Dictionary of the form { '_': { 'macro': 'string', ... }, ... }. + """ + # all structs: group(0) full struct, group(1) beginning, group(2) content + structs = cor.p_struct.finditer(text) + hash_n_string = {} + just_string = {} + for struct in structs: + struct_declaration = struct.group(1) + struct_type_name = get_struct_type_name(struct_declaration) + if 3 > len(struct_type_name): + lang = '_us' + else: + lang = struct_type_name[2] + if lang not in just_string: + hash_n_string[lang] = {} + just_string[lang] = set() + + is_v2 = False + pre_name = '' + p = cor.p_info + if 'retro_core_option_v2_definition' == struct_type_name[0]: + is_v2 = True + elif 'retro_core_option_v2_category' == struct_type_name[0]: + pre_name = 'CATEGORY_' + p = cor.p_info_cat + + struct_content = struct.group(2) + # 0: full option; 1: key; 2: description; 3: additional info; 4: key/value pairs + struct_options = cor.p_option.finditer(struct_content) + for opt, option in enumerate(struct_options): + # group 1: key + if option.group(1): + opt_name = pre_name + option.group(1) + # no special chars allowed in key + opt_name = remove_special_chars(opt_name).upper().replace(' ', '_') + else: + raise ValueError(f'No option name (key) found in struct {struct_type_name[1]} option {opt}!') + + # group 2: description0 + if option.group(2): + desc0 = option.group(2) + if is_viable_non_dupe(desc0, just_string[lang]): + just_string[lang].add(desc0) + m_h = create_non_dupe(re.sub(r'__+', '_', f'{opt_name}_LABEL'), opt, hash_n_string[lang]) + hash_n_string[lang][m_h] = desc0 + else: + raise ValueError(f'No label found in struct {struct_type_name[1]} option {option.group(1)}!') + + # group 3: desc1, info0, info1, category + if option.group(3): + infos = option.group(3) + option_info = p.finditer(infos) + if is_v2: + desc1 = next(option_info).group(1) + if is_viable_non_dupe(desc1, just_string[lang]): + just_string[lang].add(desc1) + m_h = create_non_dupe(re.sub(r'__+', '_', f'{opt_name}_LABEL_CAT'), opt, hash_n_string[lang]) + hash_n_string[lang][m_h] = desc1 + last = None + m_h = None + for j, info in enumerate(option_info): + last = info.group(1) + if is_viable_non_dupe(last, just_string[lang]): + just_string[lang].add(last) + m_h = create_non_dupe(re.sub(r'__+', '_', f'{opt_name}_INFO_{j}'), opt, + hash_n_string[lang]) + hash_n_string[lang][m_h] = last + if last in just_string[lang]: # category key should not be translated + hash_n_string[lang].pop(m_h) + just_string[lang].remove(last) + else: + for j, info in enumerate(option_info): + gr1 = info.group(1) + if is_viable_non_dupe(gr1, just_string[lang]): + just_string[lang].add(gr1) + m_h = create_non_dupe(re.sub(r'__+', '_', f'{opt_name}_INFO_{j}'), opt, + hash_n_string[lang]) + hash_n_string[lang][m_h] = gr1 + else: + raise ValueError(f'Too few arguments in struct {struct_type_name[1]} option {option.group(1)}!') + + # group 4: + if option.group(4): + for j, kv_set in enumerate(cor.p_key_value.finditer(option.group(4))): + set_key, set_value = kv_set.group(1, 2) + if not is_viable_value(set_value): + if not is_viable_value(set_key): + continue + set_value = set_key + # re.fullmatch(r'(?:[+-][0-9]+)+', value[1:-1]) + if set_value not in just_string[lang] and not re.sub(r'[+-]', '', set_value[1:-1]).isdigit(): + clean_key = set_key[1:-1] + clean_key = remove_special_chars(clean_key).upper().replace(' ', '_') + m_h = create_non_dupe(re.sub(r'__+', '_', f"OPTION_VAL_{clean_key}"), opt, hash_n_string[lang]) + hash_n_string[lang][m_h] = set_value + just_string[lang].add(set_value) + return hash_n_string + + +def create_msg_hash(intl_dir_path: str, core_name: str, keyword_string_dict: dict) -> dict: + """Creates '.h' files in 'intl/_/' containing the macro name & string combinations. + + :param intl_dir_path: Path to the intl directory. + :param core_name: Name of the core, used for the files' paths. + :param keyword_string_dict: Dictionary of the form { '_': { 'macro': 'string', ... }, ... }. + :return: Dictionary of the form { '_': 'path/to/file (./intl/_/.h)', ... }. + """ + files = {} + for localisation in keyword_string_dict: + path = os.path.join(intl_dir_path, core_name) # intl// + files[localisation] = os.path.join(path, localisation + '.h') # intl//_.h + if not os.path.exists(path): + os.makedirs(path) + with open(files[localisation], 'w', encoding='utf-8') as crowdin_file: + out_text = '' + for keyword in keyword_string_dict[localisation]: + out_text = f'{out_text}{keyword} {keyword_string_dict[localisation][keyword]}\n' + crowdin_file.write(out_text) + return files + + +def h2json(file_paths: dict) -> dict: + """Converts .h files pointed to by file_paths into .jsons. + + :param file_paths: Dictionary of the form { '_': 'path/to/file (./intl/_/.h)', ... }. + :return: Dictionary of the form { '_': 'path/to/file (./intl/_/.json)', ... }. + """ + jsons = {} + for file_lang in file_paths: + if not os.path.isfile(file_paths[file_lang]): + continue + + jsons[file_lang] = file_paths[file_lang][:-2] + '.json' + + p = cor.p_masked + + with open(file_paths[file_lang], 'r+', encoding='utf-8') as h_file: + text = h_file.read() + result = p.finditer(text) + messages = {} + for msg in result: + key, val = msg.group(1, 2) + if key not in messages: + if key and val: + # unescape & remove "\n" + messages[key] = re.sub(r'"\s*(?:(?:/\*(?:.|[\r\n])*?\*/|//.*[\r\n]+)\s*)*"', + '\\\n', val[1:-1].replace('\\\"', '"')) + else: + print(f"DUPLICATE KEY in {file_paths[file_lang]}: {key}") + with open(jsons[file_lang], 'w', encoding='utf-8') as json_file: + json.dump(messages, json_file, indent=2) + + return jsons + + +def json2h(intl_dir_path: str, file_list) -> None: + """Converts .json file in json_file_path into an .h ready to be included in C code. + + :param intl_dir_path: Path to the intl/ directory. + :param file_list: Iterator of os.DirEntry objects. Contains localisation files to convert. + :return: None + """ + + p = cor.p_masked + + def update(s_messages, s_template, s_source_messages, file_name): + translation = '' + template_messages = p.finditer(s_template) + for tp_msg in template_messages: + old_key = tp_msg.group(1) + if old_key in s_messages and s_messages[old_key] != s_source_messages[old_key]: + tl_msg_val = s_messages[old_key] + tl_msg_val = tl_msg_val.replace('"', '\\\"').replace('\n', '') # escape + translation = ''.join((translation, '#define ', old_key, file_name.upper(), f' "{tl_msg_val}"\n')) + + else: # Remove English duplicates and non-translatable strings + translation = ''.join((translation, '#define ', old_key, file_name.upper(), ' NULL\n')) + return translation + + us_h = os.path.join(intl_dir_path, '_us.h') + us_json = os.path.join(intl_dir_path, '_us.json') + + with open(us_h, 'r', encoding='utf-8') as template_file: + template = template_file.read() + with open(us_json, 'r+', encoding='utf-8') as source_json_file: + source_messages = json.load(source_json_file) + + for file in file_list: + if file.name.lower().startswith('_us') \ + or file.name.lower().endswith('.h') \ + or file.is_dir(): + continue + + with open(file.path, 'r+', encoding='utf-8') as json_file: + messages = json.load(json_file) + new_translation = update(messages, template, source_messages, os.path.splitext(file.name)[0]) + with open(os.path.splitext(file.path)[0] + '.h', 'w', encoding='utf-8') as h_file: + h_file.seek(0) + h_file.write(new_translation) + h_file.truncate() + return + + +def get_crowdin_client(dir_path: str) -> str: + """Makes sure the Crowdin CLI client is present. If it isn't, it is fetched & extracted. + + :return: The path to 'crowdin-cli.jar'. + """ + jar_name = 'crowdin-cli.jar' + jar_path = os.path.join(dir_path, jar_name) + + if not os.path.isfile(jar_path): + print('Downloading crowdin-cli.jar') + crowdin_cli_file = os.path.join(dir_path, 'crowdin-cli.zip') + crowdin_cli_url = 'https://downloads.crowdin.com/cli/v3/crowdin-cli.zip' + req.urlretrieve(crowdin_cli_url, crowdin_cli_file) + import zipfile + with zipfile.ZipFile(crowdin_cli_file, 'r') as zip_ref: + jar_dir = zip_ref.namelist()[0] + for file in zip_ref.namelist(): + if file.endswith(jar_name): + jar_file = file + break + zip_ref.extract(jar_file) + os.rename(jar_file, jar_path) + os.remove(crowdin_cli_file) + shutil.rmtree(jar_dir) + return jar_path + + +def create_intl_file(localisation_file_path: str, intl_dir_path: str, text: str, file_path: str) -> None: + """Creates 'libretro_core_options_intl.h' from Crowdin translations. + + :param localisation_file_path: Path to 'libretro_core_options_intl.h' + :param intl_dir_path: Path to the intl/ directory. + :param text: Content of the 'libretro_core_options.h' being translated. + :param file_path: Path to the '_us.h' file, containing the original English texts. + :return: None + """ + msg_dict = {} + lang_up = '' + + def replace_pair(pair_match): + """Replaces a key-value-pair of an option with the macros corresponding to the language. + + :param pair_match: The re match object representing the key-value-pair block. + :return: Replacement string. + """ + offset = pair_match.start(0) + if pair_match.group(1): # key + if pair_match.group(2) in msg_dict: # value + val = msg_dict[pair_match.group(2)] + lang_up + elif pair_match.group(1) in msg_dict: # use key if value not viable (e.g. NULL) + val = msg_dict[pair_match.group(1)] + lang_up + else: + return pair_match.group(0) + else: + return pair_match.group(0) + res = pair_match.group(0)[:pair_match.start(2) - offset] + val \ + + pair_match.group(0)[pair_match.end(2) - offset:] + return res + + def replace_info(info_match): + """Replaces the 'additional strings' of an option with the macros corresponding to the language. + + :param info_match: The re match object representing the 'additional strings' block. + :return: Replacement string. + """ + offset = info_match.start(0) + if info_match.group(1) in msg_dict: + res = info_match.group(0)[:info_match.start(1) - offset] + \ + msg_dict[info_match.group(1)] + lang_up + \ + info_match.group(0)[info_match.end(1) - offset:] + return res + else: + return info_match.group(0) + + def replace_option(option_match): + """Replaces strings within an option + '{ "opt_key", "label", "additional strings", ..., { {"key", "value"}, ... }, ... }' + within a struct with the macros corresponding to the language: + '{ "opt_key", MACRO_LABEL, MACRO_STRINGS, ..., { {"key", MACRO_VALUE}, ... }, ... }' + + :param option_match: The re match object representing the option. + :return: Replacement string. + """ + # label + offset = option_match.start(0) + if option_match.group(2): + res = option_match.group(0)[:option_match.start(2) - offset] + msg_dict[option_match.group(2)] + lang_up + else: + return option_match.group(0) + # additional block + if option_match.group(3): + res = res + option_match.group(0)[option_match.end(2) - offset:option_match.start(3) - offset] + new_info = p.sub(replace_info, option_match.group(3)) + res = res + new_info + else: + return res + option_match.group(0)[option_match.end(2) - offset:] + # key-value-pairs + if option_match.group(4): + res = res + option_match.group(0)[option_match.end(3) - offset:option_match.start(4) - offset] + new_pairs = cor.p_key_value.sub(replace_pair, option_match.group(4)) + res = res + new_pairs + option_match.group(0)[option_match.end(4) - offset:] + else: + res = res + option_match.group(0)[option_match.end(3) - offset:] + + return res + + # ------------------------------------------------------------------------------------ + + with open(file_path, 'r+', encoding='utf-8') as template: # intl//_us.h + masked_msgs = cor.p_masked.finditer(template.read()) + + for msg in masked_msgs: + msg_dict[msg.group(2)] = msg.group(1) + + # top of the file - in case there is no file to copy it from + out_txt = "#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__\n" \ + "#define LIBRETRO_CORE_OPTIONS_INTL_H__\n\n" \ + "#if defined(_MSC_VER) && (_MSC_VER >= 1500 && _MSC_VER < 1900)\n" \ + "/* https://support.microsoft.com/en-us/kb/980263 */\n" \ + '#pragma execution_character_set("utf-8")\n' \ + "#pragma warning(disable:4566)\n" \ + "#endif\n\n" \ + "#include \n\n" \ + '#ifdef __cplusplus\n' \ + 'extern "C" {\n' \ + '#endif\n' + + if os.path.isfile(localisation_file_path): + # copy top of the file for re-use + with open(localisation_file_path, 'r', encoding='utf-8') as intl: # libretro_core_options_intl.h + in_text = intl.read() + intl_start = re.search(re.escape('/*\n' + ' ********************************\n' + ' * Core Option Definitions\n' + ' ********************************\n' + '*/\n'), in_text) + if intl_start: + out_txt = in_text[:intl_start.end(0)] + else: + intl_start = re.search(re.escape('#ifdef __cplusplus\n' + 'extern "C" {\n' + '#endif\n'), in_text) + if intl_start: + out_txt = in_text[:intl_start.end(0)] + + # only write to file, if there is anything worthwhile to write! + overwrite = False + + # iterate through localisation files + files = {} + for file in os.scandir(intl_dir_path): + files[file.name] = {'is_file': file.is_file(), 'path': file.path} + for file in sorted(files): # intl//_* + if files[file]['is_file'] \ + and file.startswith('_') \ + and file.endswith('.h') \ + and not file.startswith('_us'): + translation_path = files[file]['path'] # _.h + # all structs: group(0) full struct, group(1) beginning, group(2) content + struct_groups = cor.p_struct.finditer(text) + lang_low = os.path.splitext(file)[0].lower() + lang_up = lang_low.upper() + out_txt = out_txt + f'/* RETRO_LANGUAGE{lang_up} */\n\n' # /* RETRO_LANGUAGE_NM */ + + # copy adjusted translations (makros) + with open(translation_path, 'r+', encoding='utf-8') as f_in: # .h + out_txt = out_txt + f_in.read() + '\n' + # replace English texts with makros + for construct in struct_groups: + declaration = construct.group(1) + struct_type_name = get_struct_type_name(declaration) + if 3 > len(struct_type_name): # no language specifier + new_decl = re.sub(re.escape(struct_type_name[1]), struct_type_name[1] + lang_low, declaration) + else: + new_decl = re.sub(re.escape(struct_type_name[2]), lang_low, declaration) + if '_us' != struct_type_name[2]: + continue + + p = cor.p_info + if 'retro_core_option_v2_category' == struct_type_name[0]: + p = cor.p_info_cat + offset_construct = construct.start(0) + start = construct.end(1) - offset_construct + end = construct.start(2) - offset_construct + out_txt = out_txt + new_decl + construct.group(0)[start:end] + + content = construct.group(2) + new_content = cor.p_option.sub(replace_option, content) + + start = construct.end(2) - offset_construct + out_txt = out_txt + new_content + construct.group(0)[start:] + '\n' + + # for v2 + if 'retro_core_option_v2_definition' == struct_type_name[0]: + out_txt = out_txt + f'struct retro_core_options_v2 options{lang_low}' \ + ' = {\n' \ + f' option_cats{lang_low},\n' \ + f' option_defs{lang_low}\n' \ + '};\n\n' + # if it got this far, we've got something to write + overwrite = True + + # only write to file, if there is anything worthwhile to write! + if overwrite: + with open(localisation_file_path, 'w', encoding='utf-8') as intl: + intl.write(out_txt + '\n#ifdef __cplusplus\n' + '}\n#endif\n' + '\n#endif') + return + + +# -------------------- MAIN -------------------- # + +if __name__ == '__main__': + try: + if os.path.isfile(sys.argv[1]): + _temp = os.path.dirname(sys.argv[1]) + else: + _temp = sys.argv[1] + while _temp.endswith('/') or _temp.endswith('\\'): + _temp = _temp[:-1] + TARGET_DIR_PATH = _temp + except IndexError: + TARGET_DIR_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + print("No path provided, assuming parent directory:\n" + TARGET_DIR_PATH) + + CORE_NAME = clean_file_name(sys.argv[2]) + + DIR_PATH = os.path.dirname(os.path.realpath(__file__)) + H_FILE_PATH = os.path.join(TARGET_DIR_PATH, 'libretro_core_options.h') + INTL_FILE_PATH = os.path.join(TARGET_DIR_PATH, 'libretro_core_options_intl.h') + + print('Getting texts from libretro_core_options.h') + with open(H_FILE_PATH, 'r+', encoding='utf-8') as _h_file: + _main_text = _h_file.read() + _hash_n_str = get_texts(_main_text) + _files = create_msg_hash(DIR_PATH, CORE_NAME, _hash_n_str) + _source_jsons = h2json(_files) + + print('Getting texts from libretro_core_options_intl.h') + if os.path.isfile(INTL_FILE_PATH): + with open(INTL_FILE_PATH, 'r+', encoding='utf-8') as _intl_file: + _intl_text = _intl_file.read() + _hash_n_str_intl = get_texts(_intl_text) + _intl_files = create_msg_hash(DIR_PATH, CORE_NAME, _hash_n_str_intl) + _intl_jsons = h2json(_intl_files) + + print('\nAll done!') diff --git a/intl/crowdin.yaml b/intl/crowdin.yaml new file mode 100644 index 0000000..c81de77 --- /dev/null +++ b/intl/crowdin.yaml @@ -0,0 +1,13 @@ +"project_id": "380544" +"api_token": "_secret_" +"base_url": "https://api.crowdin.com" +"preserve_hierarchy": true + +"files": + [ + { + "source": "/intl/_core_name_/_us.json", + "dest": "/_core_name_/_core_name_.json", + "translation": "/intl/_core_name_/_%two_letters_code%.json", + }, + ] diff --git a/intl/crowdin_prep.py b/intl/crowdin_prep.py new file mode 100755 index 0000000..bfc9aa9 --- /dev/null +++ b/intl/crowdin_prep.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 + +import core_option_translation as t + +if __name__ == '__main__': + try: + if t.os.path.isfile(t.sys.argv[1]): + _temp = t.os.path.dirname(t.sys.argv[1]) + else: + _temp = t.sys.argv[1] + while _temp.endswith('/') or _temp.endswith('\\'): + _temp = _temp[:-1] + TARGET_DIR_PATH = _temp + except IndexError: + TARGET_DIR_PATH = t.os.path.dirname(t.os.path.dirname(t.os.path.realpath(__file__))) + print("No path provided, assuming parent directory:\n" + TARGET_DIR_PATH) + + CORE_NAME = t.clean_file_name(t.sys.argv[2]) + DIR_PATH = t.os.path.dirname(t.os.path.realpath(__file__)) + H_FILE_PATH = t.os.path.join(TARGET_DIR_PATH, 'libretro_core_options.h') + + print('Getting texts from libretro_core_options.h') + with open(H_FILE_PATH, 'r+', encoding='utf-8') as _h_file: + _main_text = _h_file.read() + _hash_n_str = t.get_texts(_main_text) + _files = t.create_msg_hash(DIR_PATH, CORE_NAME, _hash_n_str) + + _source_jsons = t.h2json(_files) + + print('\nAll done!') diff --git a/intl/crowdin_source_upload.py b/intl/crowdin_source_upload.py new file mode 100755 index 0000000..52fb770 --- /dev/null +++ b/intl/crowdin_source_upload.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 + +import re +import os +import shutil +import subprocess +import sys +import urllib.request +import zipfile +import core_option_translation as t + +# -------------------- MAIN -------------------- # + +if __name__ == '__main__': + # Check Crowdin API Token and core name + try: + API_KEY = sys.argv[1] + CORE_NAME = t.clean_file_name(sys.argv[2]) + except IndexError as e: + print('Please provide Crowdin API Token and core name!') + raise e + + DIR_PATH = t.os.path.dirname(t.os.path.realpath(__file__)) + YAML_PATH = t.os.path.join(DIR_PATH, 'crowdin.yaml') + + # Apply Crowdin API Key + with open(YAML_PATH, 'r') as crowdin_config_file: + crowdin_config = crowdin_config_file.read() + crowdin_config = re.sub(r'"api_token": "_secret_"', + f'"api_token": "{API_KEY}"', + crowdin_config, 1) + crowdin_config = re.sub(r'/_core_name_', + f'/{CORE_NAME}' + , crowdin_config) + with open(YAML_PATH, 'w') as crowdin_config_file: + crowdin_config_file.write(crowdin_config) + + try: + # Download Crowdin CLI + jar_name = 'crowdin-cli.jar' + jar_path = t.os.path.join(DIR_PATH, jar_name) + crowdin_cli_file = 'crowdin-cli.zip' + crowdin_cli_url = 'https://downloads.crowdin.com/cli/v3/' + crowdin_cli_file + crowdin_cli_path = t.os.path.join(DIR_PATH, crowdin_cli_file) + + if not os.path.isfile(t.os.path.join(DIR_PATH, jar_name)): + print('download crowdin-cli.jar') + urllib.request.urlretrieve(crowdin_cli_url, crowdin_cli_path) + with zipfile.ZipFile(crowdin_cli_path, 'r') as zip_ref: + jar_dir = t.os.path.join(DIR_PATH, zip_ref.namelist()[0]) + for file in zip_ref.namelist(): + if file.endswith(jar_name): + jar_file = file + break + zip_ref.extract(jar_file, path=DIR_PATH) + os.rename(t.os.path.join(DIR_PATH, jar_file), jar_path) + os.remove(crowdin_cli_path) + shutil.rmtree(jar_dir) + + print('upload source *.json') + subprocess.run(['java', '-jar', jar_path, 'upload', 'sources', '--config', YAML_PATH]) + + # Reset Crowdin API Key + with open(YAML_PATH, 'r') as crowdin_config_file: + crowdin_config = crowdin_config_file.read() + crowdin_config = re.sub(r'"api_token": ".*?"', + '"api_token": "_secret_"', + crowdin_config, 1) + + # TODO this is NOT safe! + crowdin_config = re.sub(re.escape(f'/{CORE_NAME}'), + '/_core_name_', + crowdin_config) + + with open(YAML_PATH, 'w') as crowdin_config_file: + crowdin_config_file.write(crowdin_config) + + except Exception as e: + # Try really hard to reset Crowdin API Key + with open(YAML_PATH, 'r') as crowdin_config_file: + crowdin_config = crowdin_config_file.read() + crowdin_config = re.sub(r'"api_token": ".*?"', + '"api_token": "_secret_"', + crowdin_config, 1) + + # TODO this is NOT safe! + crowdin_config = re.sub(re.escape(f'/{CORE_NAME}'), + '/_core_name_', + crowdin_config) + + with open(YAML_PATH, 'w') as crowdin_config_file: + crowdin_config_file.write(crowdin_config) + raise e diff --git a/intl/crowdin_translate.py b/intl/crowdin_translate.py new file mode 100755 index 0000000..8a66602 --- /dev/null +++ b/intl/crowdin_translate.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 + +import core_option_translation as t + +if __name__ == '__main__': + try: + if t.os.path.isfile(t.sys.argv[1]): + _temp = t.os.path.dirname(t.sys.argv[1]) + else: + _temp = t.sys.argv[1] + while _temp.endswith('/') or _temp.endswith('\\'): + _temp = _temp[:-1] + TARGET_DIR_PATH = _temp + except IndexError: + TARGET_DIR_PATH = t.os.path.dirname(t.os.path.dirname(t.os.path.realpath(__file__))) + print("No path provided, assuming parent directory:\n" + TARGET_DIR_PATH) + + CORE_NAME = t.clean_file_name(t.sys.argv[2]) + DIR_PATH = t.os.path.dirname(t.os.path.realpath(__file__)) + LOCALISATIONS_PATH = t.os.path.join(DIR_PATH, CORE_NAME) + US_FILE_PATH = t.os.path.join(LOCALISATIONS_PATH, '_us.h') + H_FILE_PATH = t.os.path.join(TARGET_DIR_PATH, 'libretro_core_options.h') + INTL_FILE_PATH = t.os.path.join(TARGET_DIR_PATH, 'libretro_core_options_intl.h') + + print('Getting texts from libretro_core_options.h') + with open(H_FILE_PATH, 'r+', encoding='utf-8') as _h_file: + _main_text = _h_file.read() + _hash_n_str = t.get_texts(_main_text) + _files = t.create_msg_hash(DIR_PATH, CORE_NAME, _hash_n_str) + _source_jsons = t.h2json(_files) + + print('Converting translations *.json to *.h:') + localisation_files = t.os.scandir(LOCALISATIONS_PATH) + t.json2h(LOCALISATIONS_PATH, localisation_files) + + print('Constructing libretro_core_options_intl.h') + t.create_intl_file(INTL_FILE_PATH, LOCALISATIONS_PATH, _main_text, _files["_us"]) + + print('\nAll done!') diff --git a/intl/crowdin_translation_download.py b/intl/crowdin_translation_download.py new file mode 100755 index 0000000..d3e7027 --- /dev/null +++ b/intl/crowdin_translation_download.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 + +import re +import os +import shutil +import subprocess +import sys +import urllib.request +import zipfile +import core_option_translation as t + +# -------------------- MAIN -------------------- # + +if __name__ == '__main__': + # Check Crowdin API Token and core name + try: + API_KEY = sys.argv[1] + CORE_NAME = t.clean_file_name(sys.argv[2]) + except IndexError as e: + print('Please provide Crowdin API Token and core name!') + raise e + + DIR_PATH = t.os.path.dirname(t.os.path.realpath(__file__)) + YAML_PATH = t.os.path.join(DIR_PATH, 'crowdin.yaml') + + # Apply Crowdin API Key + with open(YAML_PATH, 'r') as crowdin_config_file: + crowdin_config = crowdin_config_file.read() + crowdin_config = re.sub(r'"api_token": "_secret_"', + f'"api_token": "{API_KEY}"', + crowdin_config, 1) + crowdin_config = re.sub(r'/_core_name_', + f'/{CORE_NAME}' + , crowdin_config) + with open(YAML_PATH, 'w') as crowdin_config_file: + crowdin_config_file.write(crowdin_config) + + try: + # Download Crowdin CLI + jar_name = 'crowdin-cli.jar' + jar_path = t.os.path.join(DIR_PATH, jar_name) + crowdin_cli_file = 'crowdin-cli.zip' + crowdin_cli_url = 'https://downloads.crowdin.com/cli/v3/' + crowdin_cli_file + crowdin_cli_path = t.os.path.join(DIR_PATH, crowdin_cli_file) + + if not os.path.isfile(t.os.path.join(DIR_PATH, jar_name)): + print('download crowdin-cli.jar') + urllib.request.urlretrieve(crowdin_cli_url, crowdin_cli_path) + with zipfile.ZipFile(crowdin_cli_path, 'r') as zip_ref: + jar_dir = t.os.path.join(DIR_PATH, zip_ref.namelist()[0]) + for file in zip_ref.namelist(): + if file.endswith(jar_name): + jar_file = file + break + zip_ref.extract(jar_file, path=DIR_PATH) + os.rename(t.os.path.join(DIR_PATH, jar_file), jar_path) + os.remove(crowdin_cli_path) + shutil.rmtree(jar_dir) + + print('download translation *.json') + subprocess.run(['java', '-jar', jar_path, 'download', '--config', YAML_PATH]) + + # Reset Crowdin API Key + with open(YAML_PATH, 'r') as crowdin_config_file: + crowdin_config = crowdin_config_file.read() + crowdin_config = re.sub(r'"api_token": ".*?"', + '"api_token": "_secret_"', + crowdin_config, 1) + + # TODO this is NOT safe! + crowdin_config = re.sub(re.escape(f'/{CORE_NAME}'), + '/_core_name_', + crowdin_config) + + with open(YAML_PATH, 'w') as crowdin_config_file: + crowdin_config_file.write(crowdin_config) + + except Exception as e: + # Try really hard to reset Crowdin API Key + with open(YAML_PATH, 'r') as crowdin_config_file: + crowdin_config = crowdin_config_file.read() + crowdin_config = re.sub(r'"api_token": ".*?"', + '"api_token": "_secret_"', + crowdin_config, 1) + + # TODO this is NOT safe! + crowdin_config = re.sub(re.escape(f'/{CORE_NAME}'), + '/_core_name_', + crowdin_config) + + with open(YAML_PATH, 'w') as crowdin_config_file: + crowdin_config_file.write(crowdin_config) + raise e diff --git a/intl/download_workflow.py b/intl/download_workflow.py new file mode 100755 index 0000000..5ce74dd --- /dev/null +++ b/intl/download_workflow.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 + +import sys +import subprocess + +try: + api_key = sys.argv[1] + core_name = sys.argv[2] + dir_path = sys.argv[3] +except IndexError as e: + print('Please provide path to libretro_core_options.h, Crowdin API Token and core name!') + raise e + +subprocess.run(['python3', 'intl/crowdin_prep.py', dir_path, core_name]) +subprocess.run(['python3', 'intl/crowdin_translation_download.py', api_key, core_name]) +subprocess.run(['python3', 'intl/crowdin_translate.py', dir_path, core_name]) diff --git a/intl/initial_sync.py b/intl/initial_sync.py new file mode 100755 index 0000000..1df39ef --- /dev/null +++ b/intl/initial_sync.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python3 + +import re +import os +import shutil +import subprocess +import sys +import time +import urllib.request +import zipfile +import core_option_translation as t + +# -------------------- MAIN -------------------- # + +if __name__ == '__main__': + # Check Crowdin API Token and core name + try: + API_KEY = sys.argv[1] + CORE_NAME = t.clean_file_name(sys.argv[2]) + except IndexError as e: + print('Please provide Crowdin API Token and core name!') + raise e + + DIR_PATH = os.path.dirname(os.path.realpath(__file__)) + YAML_PATH = os.path.join(DIR_PATH, 'crowdin.yaml') + + # Apply Crowdin API Key + with open(YAML_PATH, 'r') as crowdin_config_file: + crowdin_config = crowdin_config_file.read() + crowdin_config = re.sub(r'"api_token": "_secret_"', + f'"api_token": "{API_KEY}"', + crowdin_config, 1) + crowdin_config = re.sub(r'/_core_name_', + f'/{CORE_NAME}' + , crowdin_config) + with open(YAML_PATH, 'w') as crowdin_config_file: + crowdin_config_file.write(crowdin_config) + + try: + # Download Crowdin CLI + jar_name = 'crowdin-cli.jar' + jar_path = os.path.join(DIR_PATH, jar_name) + crowdin_cli_file = 'crowdin-cli.zip' + crowdin_cli_url = 'https://downloads.crowdin.com/cli/v3/' + crowdin_cli_file + crowdin_cli_path = os.path.join(DIR_PATH, crowdin_cli_file) + + if not os.path.isfile(os.path.join(DIR_PATH, jar_name)): + print('download crowdin-cli.jar') + urllib.request.urlretrieve(crowdin_cli_url, crowdin_cli_path) + with zipfile.ZipFile(crowdin_cli_path, 'r') as zip_ref: + jar_dir = os.path.join(DIR_PATH, zip_ref.namelist()[0]) + for file in zip_ref.namelist(): + if file.endswith(jar_name): + jar_file = file + break + zip_ref.extract(jar_file, path=DIR_PATH) + os.rename(os.path.join(DIR_PATH, jar_file), jar_path) + os.remove(crowdin_cli_path) + shutil.rmtree(jar_dir) + + print('upload source & translations *.json') + subprocess.run(['java', '-jar', jar_path, 'upload', 'sources', '--config', YAML_PATH]) + subprocess.run(['java', '-jar', jar_path, 'upload', 'translations', '--config', YAML_PATH]) + + print('wait for crowdin server to process data') + time.sleep(10) + + print('download translation *.json') + subprocess.run(['java', '-jar', jar_path, 'download', '--config', YAML_PATH]) + + # Reset Crowdin API Key + with open(YAML_PATH, 'r') as crowdin_config_file: + crowdin_config = crowdin_config_file.read() + crowdin_config = re.sub(r'"api_token": ".*?"', '"api_token": "_secret_"', crowdin_config, 1) + + # TODO this is NOT safe! + crowdin_config = re.sub(re.escape(f'/{CORE_NAME}'), + '/_core_name_', + crowdin_config) + + with open(YAML_PATH, 'w') as crowdin_config_file: + crowdin_config_file.write(crowdin_config) + + with open('intl/upload_workflow.py', 'r') as workflow: + workflow_config = workflow.read() + workflow_config = workflow_config.replace( + "subprocess.run(['python3', 'intl/core_option_translation.py', dir_path, core_name])", + "subprocess.run(['python3', 'intl/crowdin_prep.py', dir_path, core_name])" + ) + workflow_config = workflow_config.replace( + "subprocess.run(['python3', 'intl/initial_sync.py', api_key, core_name])", + "subprocess.run(['python3', 'intl/crowdin_source_upload.py', api_key, core_name])" + ) + with open('intl/upload_workflow.py', 'w') as workflow: + workflow.write(workflow_config) + + with open('intl/download_workflow.py', 'r') as workflow: + workflow_config = workflow.read() + workflow_config = workflow_config.replace( + "subprocess.run(['python3', 'intl/core_option_translation.py', dir_path, core_name])", + "subprocess.run(['python3', 'intl/crowdin_prep.py', dir_path, core_name])" + ) + workflow_config = workflow_config.replace( + "subprocess.run(['python3', 'intl/initial_sync.py', api_key, core_name])", + "subprocess.run(['python3', 'intl/crowdin_translation_download.py', api_key, core_name])" + ) + with open('intl/download_workflow.py', 'w') as workflow: + workflow.write(workflow_config) + + except Exception as e: + # Try really hard to reset Crowdin API Key + with open(YAML_PATH, 'r') as crowdin_config_file: + crowdin_config = crowdin_config_file.read() + crowdin_config = re.sub(r'"api_token": ".*?"', + '"api_token": "_secret_"', + crowdin_config, 1) + + # TODO this is NOT safe! + crowdin_config = re.sub(re.escape(f'/{CORE_NAME}'), + '/_core_name_', + crowdin_config) + + with open(YAML_PATH, 'w') as crowdin_config_file: + crowdin_config_file.write(crowdin_config) + raise e diff --git a/intl/remove_initial_cycle.py b/intl/remove_initial_cycle.py new file mode 100755 index 0000000..9d90a50 --- /dev/null +++ b/intl/remove_initial_cycle.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 + +with open('intl/upload_workflow.py', 'r') as workflow: + workflow_config = workflow.read() + +workflow_config = workflow_config.replace( + "subprocess.run(['python3', 'intl/core_option_translation.py', dir_path, core_name])", + "subprocess.run(['python3', 'intl/crowdin_prep.py', dir_path, core_name])" +) +workflow_config = workflow_config.replace( + "subprocess.run(['python3', 'intl/initial_sync.py', api_key, core_name])", + "subprocess.run(['python3', 'intl/crowdin_source_upload.py', api_key, core_name])" +) +with open('intl/upload_workflow.py', 'w') as workflow: + workflow.write(workflow_config) + + +with open('intl/download_workflow.py', 'r') as workflow: + workflow_config = workflow.read() + +workflow_config = workflow_config.replace( + "subprocess.run(['python3', 'intl/core_option_translation.py', dir_path, core_name])", + "subprocess.run(['python3', 'intl/crowdin_prep.py', dir_path, core_name])" +) +workflow_config = workflow_config.replace( + "subprocess.run(['python3', 'intl/initial_sync.py', api_key, core_name])", + "subprocess.run(['python3', 'intl/crowdin_translation_download.py', api_key, core_name])" +) +with open('intl/download_workflow.py', 'w') as workflow: + workflow.write(workflow_config) diff --git a/intl/upload_workflow.py b/intl/upload_workflow.py new file mode 100755 index 0000000..6bfff92 --- /dev/null +++ b/intl/upload_workflow.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 + +import sys +import subprocess + +try: + api_key = sys.argv[1] + core_name = sys.argv[2] + dir_path = sys.argv[3] +except IndexError as e: + print('Please provide path to libretro_core_options.h, Crowdin API Token and core name!') + raise e + +subprocess.run(['python3', 'intl/crowdin_prep.py', dir_path, core_name]) +subprocess.run(['python3', 'intl/crowdin_source_upload.py', api_key, core_name]) diff --git a/intl/v1_to_v2_converter.py b/intl/v1_to_v2_converter.py new file mode 100755 index 0000000..453183d --- /dev/null +++ b/intl/v1_to_v2_converter.py @@ -0,0 +1,476 @@ +#!/usr/bin/env python3 + +"""Core options v1 to v2 converter + +Just run this script as follows, to convert 'libretro_core_options.h' & 'Libretro_coreoptions_intl.h' to v2: +python3 "/path/to/v1_to_v2_converter.py" "/path/to/where/libretro_core_options.h & Libretro_coreoptions_intl.h/are" + +The original files will be preserved as *.v1 +""" +import core_option_regex as cor +import os +import sys +import glob + + +def create_v2_code_file(struct_text, file_name): + def replace_option(option_match): + _offset = option_match.start(0) + + if option_match.group(3): + res = option_match.group(0)[:option_match.end(2) - _offset] + ',\n NULL' + \ + option_match.group(0)[option_match.end(2) - _offset:option_match.end(3) - _offset] + \ + 'NULL,\n NULL,\n ' + option_match.group(0)[option_match.end(3) - _offset:] + else: + return option_match.group(0) + + return res + + comment_v1 = '/*\n' \ + ' ********************************\n' \ + ' * VERSION: 1.3\n' \ + ' ********************************\n' \ + ' *\n' \ + ' * - 1.3: Move translations to libretro_core_options_intl.h\n' \ + ' * - libretro_core_options_intl.h includes BOM and utf-8\n' \ + ' * fix for MSVC 2010-2013\n' \ + ' * - Added HAVE_NO_LANGEXTRA flag to disable translations\n' \ + ' * on platforms/compilers without BOM support\n' \ + ' * - 1.2: Use core options v1 interface when\n' \ + ' * RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1\n' \ + ' * (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)\n' \ + ' * - 1.1: Support generation of core options v0 retro_core_option_value\n' \ + ' * arrays containing options with a single value\n' \ + ' * - 1.0: First commit\n' \ + '*/\n' + + comment_v2 = '/*\n' \ + ' ********************************\n' \ + ' * VERSION: 2.0\n' \ + ' ********************************\n' \ + ' *\n' \ + ' * - 2.0: Add support for core options v2 interface\n' \ + ' * - 1.3: Move translations to libretro_core_options_intl.h\n' \ + ' * - libretro_core_options_intl.h includes BOM and utf-8\n' \ + ' * fix for MSVC 2010-2013\n' \ + ' * - Added HAVE_NO_LANGEXTRA flag to disable translations\n' \ + ' * on platforms/compilers without BOM support\n' \ + ' * - 1.2: Use core options v1 interface when\n' \ + ' * RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1\n' \ + ' * (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)\n' \ + ' * - 1.1: Support generation of core options v0 retro_core_option_value\n' \ + ' * arrays containing options with a single value\n' \ + ' * - 1.0: First commit\n' \ + '*/\n' + + p_intl = cor.p_intl + p_set = cor.p_set + new_set = 'static INLINE void libretro_set_core_options(retro_environment_t environ_cb,\n' \ + ' bool *categories_supported)\n' \ + '{\n' \ + ' unsigned version = 0;\n' \ + '#ifndef HAVE_NO_LANGEXTRA\n' \ + ' unsigned language = 0;\n' \ + '#endif\n' \ + '\n' \ + ' if (!environ_cb || !categories_supported)\n' \ + ' return;\n' \ + '\n' \ + ' *categories_supported = false;\n' \ + '\n' \ + ' if (!environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version))\n' \ + ' version = 0;\n' \ + '\n' \ + ' if (version >= 2)\n' \ + ' {\n' \ + '#ifndef HAVE_NO_LANGEXTRA\n' \ + ' struct retro_core_options_v2_intl core_options_intl;\n' \ + '\n' \ + ' core_options_intl.us = &options_us;\n' \ + ' core_options_intl.local = NULL;\n' \ + '\n' \ + ' if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&\n' \ + ' (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))\n' \ + ' core_options_intl.local = options_intl[language];\n' \ + '\n' \ + ' *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,\n' \ + ' &core_options_intl);\n' \ + '#else\n' \ + ' *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,\n' \ + ' &options_us);\n' \ + '#endif\n' \ + ' }\n' \ + ' else\n' \ + ' {\n' \ + ' size_t i, j;\n' \ + ' size_t option_index = 0;\n' \ + ' size_t num_options = 0;\n' \ + ' struct retro_core_option_definition\n' \ + ' *option_v1_defs_us = NULL;\n' \ + '#ifndef HAVE_NO_LANGEXTRA\n' \ + ' size_t num_options_intl = 0;\n' \ + ' struct retro_core_option_v2_definition\n' \ + ' *option_defs_intl = NULL;\n' \ + ' struct retro_core_option_definition\n' \ + ' *option_v1_defs_intl = NULL;\n' \ + ' struct retro_core_options_intl\n' \ + ' core_options_v1_intl;\n' \ + '#endif\n' \ + ' struct retro_variable *variables = NULL;\n' \ + ' char **values_buf = NULL;\n' \ + '\n' \ + ' /* Determine total number of options */\n' \ + ' while (true)\n' \ + ' {\n' \ + ' if (option_defs_us[num_options].key)\n' \ + ' num_options++;\n' \ + ' else\n' \ + ' break;\n' \ + ' }\n' \ + '\n' \ + ' if (version >= 1)\n' \ + ' {\n' \ + ' /* Allocate US array */\n' \ + ' option_v1_defs_us = (struct retro_core_option_definition *)\n' \ + ' calloc(num_options + 1, sizeof(struct retro_core_option_definition));\n' \ + '\n' \ + ' /* Copy parameters from option_defs_us array */\n' \ + ' for (i = 0; i < num_options; i++)\n' \ + ' {\n' \ + ' struct retro_core_option_v2_definition *option_def_us = &option_defs_us[i];\n' \ + ' struct retro_core_option_value *option_values = option_def_us->values;\n' \ + ' struct retro_core_option_definition *option_v1_def_us = &option_v1_defs_us[i];\n' \ + ' struct retro_core_option_value *option_v1_values = option_v1_def_us->values;\n' \ + '\n' \ + ' option_v1_def_us->key = option_def_us->key;\n' \ + ' option_v1_def_us->desc = option_def_us->desc;\n' \ + ' option_v1_def_us->info = option_def_us->info;\n' \ + ' option_v1_def_us->default_value = option_def_us->default_value;\n' \ + '\n' \ + ' /* Values must be copied individually... */\n' \ + ' while (option_values->value)\n' \ + ' {\n' \ + ' option_v1_values->value = option_values->value;\n' \ + ' option_v1_values->label = option_values->label;\n' \ + '\n' \ + ' option_values++;\n' \ + ' option_v1_values++;\n' \ + ' }\n' \ + ' }\n' \ + '\n' \ + '#ifndef HAVE_NO_LANGEXTRA\n' \ + ' if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&\n' \ + ' (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH) &&\n' \ + ' options_intl[language])\n' \ + ' option_defs_intl = options_intl[language]->definitions;\n' \ + '\n' \ + ' if (option_defs_intl)\n' \ + ' {\n' \ + ' /* Determine number of intl options */\n' \ + ' while (true)\n' \ + ' {\n' \ + ' if (option_defs_intl[num_options_intl].key)\n' \ + ' num_options_intl++;\n' \ + ' else\n' \ + ' break;\n' \ + ' }\n' \ + '\n' \ + ' /* Allocate intl array */\n' \ + ' option_v1_defs_intl = (struct retro_core_option_definition *)\n' \ + ' calloc(num_options_intl + 1, sizeof(struct retro_core_option_definition));\n' \ + '\n' \ + ' /* Copy parameters from option_defs_intl array */\n' \ + ' for (i = 0; i < num_options_intl; i++)\n' \ + ' {\n' \ + ' struct retro_core_option_v2_definition *option_def_intl = &option_defs_intl[i];\n' \ + ' struct retro_core_option_value *option_values = option_def_intl->values;\n' \ + ' struct retro_core_option_definition *option_v1_def_intl = &option_v1_defs_intl[i];\n' \ + ' struct retro_core_option_value *option_v1_values = option_v1_def_intl->values;\n' \ + '\n' \ + ' option_v1_def_intl->key = option_def_intl->key;\n' \ + ' option_v1_def_intl->desc = option_def_intl->desc;\n' \ + ' option_v1_def_intl->info = option_def_intl->info;\n' \ + ' option_v1_def_intl->default_value = option_def_intl->default_value;\n' \ + '\n' \ + ' /* Values must be copied individually... */\n' \ + ' while (option_values->value)\n' \ + ' {\n' \ + ' option_v1_values->value = option_values->value;\n' \ + ' option_v1_values->label = option_values->label;\n' \ + '\n' \ + ' option_values++;\n' \ + ' option_v1_values++;\n' \ + ' }\n' \ + ' }\n' \ + ' }\n' \ + '\n' \ + ' core_options_v1_intl.us = option_v1_defs_us;\n' \ + ' core_options_v1_intl.local = option_v1_defs_intl;\n' \ + '\n' \ + ' environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_v1_intl);\n' \ + '#else\n' \ + ' environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, option_v1_defs_us);\n' \ + '#endif\n' \ + ' }\n' \ + ' else\n' \ + ' {\n' \ + ' /* Allocate arrays */\n' \ + ' variables = (struct retro_variable *)calloc(num_options + 1,\n' \ + ' sizeof(struct retro_variable));\n' \ + ' values_buf = (char **)calloc(num_options, sizeof(char *));\n' \ + '\n' \ + ' if (!variables || !values_buf)\n' \ + ' goto error;\n' \ + '\n' \ + ' /* Copy parameters from option_defs_us array */\n' \ + ' for (i = 0; i < num_options; i++)\n' \ + ' {\n' \ + ' const char *key = option_defs_us[i].key;\n' \ + ' const char *desc = option_defs_us[i].desc;\n' \ + ' const char *default_value = option_defs_us[i].default_value;\n' \ + ' struct retro_core_option_value *values = option_defs_us[i].values;\n' \ + ' size_t buf_len = 3;\n' \ + ' size_t default_index = 0;\n' \ + '\n' \ + ' values_buf[i] = NULL;\n' \ + '\n' \ + ' if (desc)\n' \ + ' {\n' \ + ' size_t num_values = 0;\n' \ + '\n' \ + ' /* Determine number of values */\n' \ + ' while (true)\n' \ + ' {\n' \ + ' if (values[num_values].value)\n' \ + ' {\n' \ + ' /* Check if this is the default value */\n' \ + ' if (default_value)\n' \ + ' if (strcmp(values[num_values].value, default_value) == 0)\n' \ + ' default_index = num_values;\n' \ + '\n' \ + ' buf_len += strlen(values[num_values].value);\n' \ + ' num_values++;\n' \ + ' }\n' \ + ' else\n' \ + ' break;\n' \ + ' }\n' \ + '\n' \ + ' /* Build values string */\n' \ + ' if (num_values > 0)\n' \ + ' {\n' \ + ' buf_len += num_values - 1;\n' \ + ' buf_len += strlen(desc);\n' \ + '\n' \ + ' values_buf[i] = (char *)calloc(buf_len, sizeof(char));\n' \ + ' if (!values_buf[i])\n' \ + ' goto error;\n' \ + '\n' \ + ' strcpy(values_buf[i], desc);\n' \ + ' strcat(values_buf[i], "; ");\n' \ + '\n' \ + ' /* Default value goes first */\n' \ + ' strcat(values_buf[i], values[default_index].value);\n' \ + '\n' \ + ' /* Add remaining values */\n' \ + ' for (j = 0; j < num_values; j++)\n' \ + ' {\n' \ + ' if (j != default_index)\n' \ + ' {\n' \ + ' strcat(values_buf[i], "|");\n' \ + ' strcat(values_buf[i], values[j].value);\n' \ + ' }\n' \ + ' }\n' \ + ' }\n' \ + ' }\n' \ + '\n' \ + ' variables[option_index].key = key;\n' \ + ' variables[option_index].value = values_buf[i];\n' \ + ' option_index++;\n' \ + ' }\n' \ + '\n' \ + ' /* Set variables */\n' \ + ' environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);\n' \ + ' }\n' \ + '\n' \ + 'error:\n' \ + ' /* Clean up */\n' \ + '\n' \ + ' if (option_v1_defs_us)\n' \ + ' {\n' \ + ' free(option_v1_defs_us);\n' \ + ' option_v1_defs_us = NULL;\n' \ + ' }\n' \ + '\n' \ + '#ifndef HAVE_NO_LANGEXTRA\n' \ + ' if (option_v1_defs_intl)\n' \ + ' {\n' \ + ' free(option_v1_defs_intl);\n' \ + ' option_v1_defs_intl = NULL;\n' \ + ' }\n' \ + '#endif\n' \ + '\n' \ + ' if (values_buf)\n' \ + ' {\n' \ + ' for (i = 0; i < num_options; i++)\n' \ + ' {\n' \ + ' if (values_buf[i])\n' \ + ' {\n' \ + ' free(values_buf[i]);\n' \ + ' values_buf[i] = NULL;\n' \ + ' }\n' \ + ' }\n' \ + '\n' \ + ' free(values_buf);\n' \ + ' values_buf = NULL;\n' \ + ' }\n' \ + '\n' \ + ' if (variables)\n' \ + ' {\n' \ + ' free(variables);\n' \ + ' variables = NULL;\n' \ + ' }\n' \ + ' }\n' \ + '}\n' \ + '\n' \ + '#ifdef __cplusplus\n' \ + '}\n' \ + '#endif' + + struct_groups = cor.p_struct.finditer(struct_text) + out_text = struct_text + + for construct in struct_groups: + repl_text = '' + declaration = construct.group(1) + struct_match = cor.p_type_name.search(declaration) + if struct_match: + if struct_match.group(3): + struct_type_name_lang = struct_match.group(1, 2, 3) + declaration_end = declaration[struct_match.end(1):] + elif struct_match.group(4): + struct_type_name_lang = struct_match.group(1, 2, 4) + declaration_end = declaration[struct_match.end(1):] + else: + struct_type_name_lang = sum((struct_match.group(1, 2), ('_us',)), ()) + declaration_end = f'{declaration[struct_match.end(1):struct_match.end(2)]}_us' \ + f'{declaration[struct_match.end(2):]}' + else: + return -1 + + if 'retro_core_option_definition' == struct_type_name_lang[0]: + import shutil + shutil.copy(file_name, file_name + '.v1') + new_declaration = f'\nstruct retro_core_option_v2_category option_cats{struct_type_name_lang[2]}[] = ' \ + '{\n { NULL, NULL, NULL },\n' \ + '};\n\n' \ + + declaration[:struct_match.start(1)] + \ + 'retro_core_option_v2_definition' \ + + declaration_end + offset = construct.start(0) + repl_text = repl_text + cor.re.sub(cor.re.escape(declaration), new_declaration, + construct.group(0)[:construct.start(2) - offset]) + content = construct.group(2) + new_content = cor.p_option.sub(replace_option, content) + + repl_text = repl_text + new_content + cor.re.sub(r'{\s*NULL,\s*NULL,\s*NULL,\s*{\{0}},\s*NULL\s*},\s*};', + '{ NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },\n};' + '\n\nstruct retro_core_options_v2 options' + + struct_type_name_lang[2] + ' = {\n' + f' option_cats{struct_type_name_lang[2]},\n' + f' option_defs{struct_type_name_lang[2]}\n' + '};', + construct.group(0)[construct.end(2) - offset:]) + out_text = cor.re.sub(cor.re.escape(construct.group(0)), repl_text, out_text) + else: + return -2 + with open(file_name, 'w', encoding='utf-8') as code_file: + out_text = cor.re.sub(cor.re.escape(comment_v1), comment_v2, out_text) + intl = p_intl.search(out_text) + if intl: + new_intl = out_text[:intl.start(1)] \ + + 'struct retro_core_options_v2 *options_intl[RETRO_LANGUAGE_LAST]' \ + + out_text[intl.end(1):intl.start(2)] \ + + '\n &options_us, /* RETRO_LANGUAGE_ENGLISH */\n' \ + ' &options_ja, /* RETRO_LANGUAGE_JAPANESE */\n' \ + ' &options_fr, /* RETRO_LANGUAGE_FRENCH */\n' \ + ' &options_es, /* RETRO_LANGUAGE_SPANISH */\n' \ + ' &options_de, /* RETRO_LANGUAGE_GERMAN */\n' \ + ' &options_it, /* RETRO_LANGUAGE_ITALIAN */\n' \ + ' &options_nl, /* RETRO_LANGUAGE_DUTCH */\n' \ + ' &options_pt_br, /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */\n' \ + ' &options_pt_pt, /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */\n' \ + ' &options_ru, /* RETRO_LANGUAGE_RUSSIAN */\n' \ + ' &options_ko, /* RETRO_LANGUAGE_KOREAN */\n' \ + ' &options_cht, /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */\n' \ + ' &options_chs, /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */\n' \ + ' &options_eo, /* RETRO_LANGUAGE_ESPERANTO */\n' \ + ' &options_pl, /* RETRO_LANGUAGE_POLISH */\n' \ + ' &options_vn, /* RETRO_LANGUAGE_VIETNAMESE */\n' \ + ' &options_ar, /* RETRO_LANGUAGE_ARABIC */\n' \ + ' &options_el, /* RETRO_LANGUAGE_GREEK */\n' \ + ' &options_tr, /* RETRO_LANGUAGE_TURKISH */\n' \ + ' &options_sv, /* RETRO_LANGUAGE_SLOVAK */\n' \ + ' &options_fa, /* RETRO_LANGUAGE_PERSIAN */\n' \ + ' &options_he, /* RETRO_LANGUAGE_HEBREW */\n' \ + ' &options_ast, /* RETRO_LANGUAGE_ASTURIAN */\n' \ + ' &options_fi, /* RETRO_LANGUAGE_FINNISH */\n' \ + + out_text[intl.end(2):] + out_text = p_set.sub(new_set, new_intl) + else: + out_text = p_set.sub(new_set, out_text) + code_file.write(out_text) + + return 1 + + +# -------------------- MAIN -------------------- # + +if __name__ == '__main__': + DIR_PATH = os.path.dirname(os.path.realpath(__file__)) + if os.path.basename(DIR_PATH) != "intl": + raise RuntimeError("Script is not in intl folder!") + + BASE_PATH = os.path.dirname(DIR_PATH) + CORE_OP_FILE = os.path.join(BASE_PATH, "**", "libretro_core_options.h") + + core_options_hits = glob.glob(CORE_OP_FILE, recursive=True) + + if len(core_options_hits) == 0: + raise RuntimeError("libretro_core_options.h not found!") + elif len(core_options_hits) > 1: + print("More than one libretro_core_options.h file found:\n\n") + for i, file in enumerate(core_options_hits): + print(f"{i} {file}\n") + + while True: + user_choice = input("Please choose one ('q' will exit): ") + if user_choice == 'q': + exit(0) + elif user_choice.isdigit(): + core_op_file = core_options_hits[int(user_choice)] + break + else: + print("Please make a valid choice!\n\n") + else: + core_op_file = core_options_hits[0] + + H_FILE_PATH = core_op_file + INTL_FILE_PATH = core_op_file.replace("libretro_core_options.h", 'libretro_core_options_intl.h') + + for file in (H_FILE_PATH, INTL_FILE_PATH): + if os.path.isfile(file): + with open(file, 'r+', encoding='utf-8') as h_file: + text = h_file.read() + try: + test = create_v2_code_file(text, file) + except Exception as e: + print(e) + test = -1 + if -1 > test: + print('Your file looks like it already is v2? (' + file + ')') + continue + if 0 > test: + print('An error occured! Please make sure to use the complete v1 struct! (' + file + ')') + continue + else: + print(file + ' not found.') diff --git a/ps2/SMS_Utils.s b/ps2/SMS_Utils.s deleted file mode 100644 index e437356..0000000 --- a/ps2/SMS_Utils.s +++ /dev/null @@ -1,202 +0,0 @@ -/* -# ___ _ _ ___ -# | | | | | -# ___| | | ___| PS2DEV Open Source Project. -#---------------------------------------------------------- -# MUL64 is pulled from some binary library (I don't remember which one). -# mips_memcpy routine is pulled from 'sde' library from MIPS. -# -*/ -.set noat -.set noreorder -.set nomacro - -.globl MUL64 -.globl mips_memcpy -.globl mips_memset - -.text - -MUL64: - pmultuw $v0, $a0, $a1 - dsra32 $a2, $a0, 0 - dsra32 $v1, $a1, 0 - mult $v1, $a0, $v1 - mult1 $a2, $a2, $a1 - addu $v1, $v1, $a2 - dsll32 $v1, $v1, 0 - jr $ra - daddu $v0, $v0, $v1 - -mips_memcpy: - addu $v0, $a0, $zero - beqz $a2, 1f - sltiu $t2, $a2, 12 - bnez $t2, 2f - xor $v1, $a1, $a0 - andi $v1, $v1, 7 - negu $a3, $a0 - beqz $v1, 3f - andi $a3, $a3, 7 - beqz $a3, 4f - subu $a2, $a2, $a3 - ldr $v1, 0($a1) - ldl $v1, 7($a1) - addu $a1, $a1, $a3 - sdr $v1, 0($a0) - addu $a0, $a0, $a3 -4: - andi $v1, $a2, 31 - subu $a3, $a2, $v1 - beqz $a3, 5f - addu $a2, $v1, $zero - addu $a3, $a3, $a1 -6: - ldr $v1, 0($a1) - ldl $v1, 7($a1) - ldr $t0, 8($a1) - ldl $t0, 15($a1) - ldr $t1, 16($a1) - ldl $t1, 23($a1) - ldr $t2, 24($a1) - ldl $t2, 31($a1) - sd $v1, 0($a0) - sd $t0, 8($a0) - sd $t1, 16($a0) - addiu $a1, $a1, 32 - addiu $a0, $a0, 32 - bne $a1, $a3, 6b - sd $t2, -8($a0) -5: - andi $v1, $a2, 7 - subu $a3, $a2, $v1 - beqz $a3, 2f - addu $a2, $v1, $zero - addu $a3, $a3, $a1 -7: - ldr $v1, 0($a1) - ldl $v1, 7($a1) - addiu $a1, $a1, 8 - addiu $a0, $a0, 8 - nop - bne $a1, $a3, 7b - sd $v1, -8($a0) - beq $zero, $zero, 2f - nop -3: - beqz $a3, 8f - subu $a2, $a2, $a3 - ldr $v1, 0($a1) - addu $a1, $a1, $a3 - sdr $v1, 0($a0) - addu $a0, $a0, $a3 -8: - andi $v1, $a2, 31 - subu $a3, $a2, $v1 - beqz $a3, 9f - addu $a2, $v1, $zero - addu $a3, $a3, $a1 -10: - ld $v1, 0($a1) - ld $t0, 8($a1) - ld $t1, 16($a1) - ld $t2, 24($a1) - sd $v1, 0($a0) - sd $t0, 8($a0) - sd $t1, 16($a0) - addiu $a1, $a1, 32 - addiu $a0, $a0, 32 - bne $a1, $a3, 10b - sd $t2, -8($a0) -9: - andi $v1, $a2, 7 - subu $a3, $a2, $v1 - beqz $a3, 2f - addu $a2, $v1, $zero - addu $a3, $a3, $a1 -11: - ld $v1, 0($a1) - addiu $a1, $a1, 8 - addiu $a0, $a0, 8 - nop - nop - bne $a1, $a3, 11b - sd $v1, -8($a0) -2: - beqz $a2, 1f - addu $a3, $a2, $a1 -12: - lbu $v1, 0($a1) - addiu $a1, $a1, 1 - addiu $a0, $a0, 1 - nop - nop - bne $a1, $a3, 12b - sb $v1, -1($a0) -1: - jr $ra - nop - -mips_memset: - beqz $a2, 1f - sltiu $at, $a2, 16 - bnez $at, 2f - andi $a1, $a1, 0xFF - dsll $at, $a1, 0x8 - or $a1, $a1, $at - dsll $at, $a1, 0x10 - or $a1, $a1, $at - dsll32 $at, $a1, 0x0 - or $a1, $a1, $at - andi $v1, $a0, 0x7 - beqz $v1, 3f - li $a3, 8 - subu $a3, $a3, $v1 - subu $a2, $a2, $a3 - sdr $a1, 0($a0) - addu $a0, $a0, $a3 -3: - andi $v1, $a2, 0x1f - subu $a3, $a2, $v1 - beqz $a3, 4f - move $a2, $v1 - addu $a3, $a3, $a0 -5: - sd $a1, 0($a0) - sd $a1, 8($a0) - sd $a1, 16($a0) - addiu $a0, $a0, 32 - sd $a1, -8($a0) - bne $a0, $a3, 5b -4: - andi $v1, $a2, 0x7 - subu $a3, $a2, $v1 - beqz $a3, 2f - move $a2, $v1 - addu $a3, $a3, $a0 -6: - addiu $a0, $a0, 8 - beq $a0, $a3, 2f - sd $a1, -8($a0) - addiu $a0, $a0, 8 - beq $a0, $a3, 2f - sd $a1, -8($a0) - addiu $a0, $a0, 8 - bne $a0, $a3, 6b - sd $a1, -8($a0) -2: - beqz $a2, 1f - addu $a3, $a2, $a0 -7: - addiu $a0, $a0, 1 - beq $a0, $a3, 1f - sb $a1, -1($a0) - addiu $a0, $a0, 1 - beq $a0, $a3, 1f - sb $a1, -1($a0) - addiu $a0, $a0, 1 - bne $a0, $a3, 7b - sb $a1, -1($a0) -1: - jr $ra - nop diff --git a/ps2/inttypes.h b/ps2/inttypes.h deleted file mode 100644 index 3049fbd..0000000 --- a/ps2/inttypes.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef INTTYPES_H -#define INTTYPES_H - -#define PRId64 "ld" -#define PRIu64 "lu" -#define PRIuPTR "lu" - -#endif //INTTYPES_H diff --git a/ps2/stdint.h b/ps2/stdint.h deleted file mode 100644 index ae9a75b..0000000 --- a/ps2/stdint.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef STDINT_H -#define STDINT_H - -typedef unsigned long uintptr_t; -typedef signed long intptr_t; - -typedef signed char int8_t; -typedef signed short int16_t; -typedef signed int int32_t; -typedef signed long int64_t; -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -typedef unsigned long uint64_t; - -typedef unsigned long uint_least32_t; -typedef unsigned short uint_least16_t; - -#define STDIN_FILENO 0 /* standard input file descriptor */ -#define STDOUT_FILENO 1 /* standard output file descriptor */ -#define STDERR_FILENO 2 /* standard error file descriptor */ - -#define INT8_C(val) val##c -#define INT16_C(val) val##h -#define INT32_C(val) val##i -#define INT64_C(val) val##l - -#define UINT8_C(val) val##uc -#define UINT16_C(val) val##uh -#define UINT32_C(val) val##ui -#define UINT64_C(val) val##ul - -#endif //STDINT_H diff --git a/src/boards/116.c b/src/boards/116.c index 88f5f00..316f0a1 100644 --- a/src/boards/116.c +++ b/src/boards/116.c @@ -35,29 +35,45 @@ #include "mapinc.h" -static uint8 mode; -static uint8 vrc2_chr[8], vrc2_prg[2], vrc2_mirr; -static uint8 mmc3_regs[10], mmc3_ctrl, mmc3_mirr; -static uint8 IRQCount, IRQLatch, IRQa; -static uint8 IRQReload; -static uint8 mmc1_regs[4], mmc1_buffer, mmc1_shift; +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 uint32 isHuang2 = 0; + +extern uint32 ROM_size; +extern uint32 VROM_size; 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" }, + { &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" }, + { &mmc1_shift, 1, "M1MR" }, { 0 } }; @@ -83,6 +99,8 @@ static void SyncPRG(void) { { uint8 bank = mmc1_regs[3] & 0xF; if (mmc1_regs[0] & 8) { + if (isHuang2) + bank >>= 1; if (mmc1_regs[0] & 4) { setprg16(0x8000, bank); setprg16(0xC000, 0x0F); @@ -92,9 +110,9 @@ static void SyncPRG(void) { } } else setprg32(0x8000, bank >> 1); + } break; } - } } static void SyncCHR(void) { @@ -250,10 +268,10 @@ static DECLFW(UNLSL12Write) { mmc1_regs[n] = mmc1_buffer; mmc1_buffer = mmc1_shift = 0; switch (n) { - case 0: SyncMIR(); - case 2: SyncCHR(); + case 0: SyncMIR(); break; + case 2: SyncCHR(); break; case 3: - case 1: SyncPRG(); + case 1: SyncPRG(); break; } } } @@ -322,4 +340,7 @@ void UNLSL12_Init(CartInfo *info) { GameHBIRQHook = UNLSL12HBIRQ; GameStateRestore = StateRestore; AddExState(&StateRegs, ~0, 0, 0); + /* PRG 128K and CHR 128K is Huang-2 */ + if (ROM_size == 8 && VROM_size == 16) + isHuang2 = 1; } diff --git a/src/boards/121.c b/src/boards/121.c index be70aaf..b09a614 100644 --- a/src/boards/121.c +++ b/src/boards/121.c @@ -56,15 +56,11 @@ static void M121CW(uint32 A, uint8 V) { } static void M121PW(uint32 A, uint8 V) { + setprg8(A, (V & 0x1F) | ((EXPREGS[3] & 0x80) >> 2)); if (EXPREGS[5] & 0x3F) { -/* FCEU_printf("prot banks: %02x %02x %02x %02x\n",V,EXPREGS[2],EXPREGS[1],EXPREGS[0]); */ - setprg8(A, (V & 0x1F) | ((EXPREGS[3] & 0x80) >> 2)); setprg8(0xE000, (EXPREGS[0]) | ((EXPREGS[3] & 0x80) >> 2)); setprg8(0xC000, (EXPREGS[1]) | ((EXPREGS[3] & 0x80) >> 2)); setprg8(0xA000, (EXPREGS[2]) | ((EXPREGS[3] & 0x80) >> 2)); - } else { -/* FCEU_printf("gen banks: %04x %02x\n",A,V); */ - setprg8(A, (V & 0x1F) | ((EXPREGS[3] & 0x80) >> 2)); } } diff --git a/src/boards/126-422-534.c b/src/boards/126-422-534.c new file mode 100644 index 0000000..1b81963 --- /dev/null +++ b/src/boards/126-422-534.c @@ -0,0 +1,136 @@ +/* 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 = EXPREGS[0] &0x40? 0x0F: 0x1F; /* 128 KiB or 256 KiB inner PRG bank selection */ + int prgOR =(EXPREGS[0] <<4 &0x70 | EXPREGS[0] <<3 &0x180) &~prgAND; /* outer PRG bank */ + switch(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 =DRegBuf[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 =DRegBuf[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 = 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 =(EXPREGS[0] <<4 &0x080 | EXPREGS[0] <<3 &0x100 | EXPREGS[0] <<5 &0x200) &~chrAND; + else + chrOR =EXPREGS[0] <<4 &0x380 &~chrAND; + + if (EXPREGS[3] &0x10) /* CNROM mode: 8 KiB inner CHR bank comes from outer bank register #2 */ + setchr8(EXPREGS[2] &(chrAND >>3) | chrOR >>3); + else /* MMC3 CHR mode */ + setchr1(A, (V & chrAND) | chrOR); +} + +static DECLFW(writeWRAM) { + if (~EXPREGS[3] &0x80) { + /* Lock bit clear: Update any outer bank register */ + 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 =EXPREGS[2] &0x10? 1: 3; /* 16 or 32 KiB inner CHR bank selection */ + EXPREGS[2] &=~latchMask; + EXPREGS[2] |= V &latchMask; + FixMMC3CHR(MMC3_cmd); + } + CartBW(A, V); +} + +static DECLFR(readDIP) { + uint8 result =CartBR(A); + if (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 reset(void) { + dipSwitch++; /* Soft-resetting cycles through solder pad or DIP switch settings */ + EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; + MMC3RegReset(); +} + +static void power(void) { + dipSwitch =0; + EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = 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 init(CartInfo *info) { + GenMMC3_Init(info, 512, 256, 8, info->battery); + cwrap = wrapCHR; + pwrap = wrapPRG; + + info->Power = power; + info->Reset = reset; + + AddExState(EXPREGS, 4, 0, "EXPR"); + AddExState(&dipSwitch, 1, 0, "DPSW"); +} + +void Mapper126_Init(CartInfo *info) { + reverseCHR_A18_A19 = 1; + invertC000 = 0; + init(info); +} + +void Mapper422_Init(CartInfo *info) { + reverseCHR_A18_A19 = 0; + invertC000 = 0; + init(info); +} + +void Mapper534_Init(CartInfo *info) { + reverseCHR_A18_A19 = 0; + invertC000 = 1; + init(info); +} diff --git a/src/boards/126.c b/src/boards/126.c deleted file mode 100644 index 0a93910..0000000 --- a/src/boards/126.c +++ /dev/null @@ -1,105 +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 - */ - -/* Mapper 126, PowerJoy 84-in-1 Multicart (PJ-008*/ -/* reference from nestopia since not available in nesdev */ - -#include "mapinc.h" -#include "mmc3.h" - -static uint16 GetExChrExBank() { - uint16 bank = (uint16)EXPREGS[0]; - return ((~bank << 0 & 0x080 & ((uint16)EXPREGS[2])) | (bank << 4 & 0x080 & bank) | - (bank << 3 & 0x100) | (bank << 5 & 0x200)); -} - -static void UpdateChrBank(void) { - uint16 bank = (uint16)EXPREGS[2] & 0x0F; - bank |= GetExChrExBank() >> 3; - setchr8(bank); -} - -static void M126CW(uint32 A, uint8 V) { - if (!(EXPREGS[3] & 0x10)) { - uint16 bank = (uint16)V & (((uint16)EXPREGS[0] & 0x80) - 1); - bank |= GetExChrExBank(); - setchr1(A, bank); - } -} - -static void M126PW(uint32 A, uint8 V) { - uint16 bank = (uint16)V; - uint16 preg = (uint16)EXPREGS[0]; - bank &= ((~preg >> 2) & 0x10) | 0x0F; - bank |= ((preg & (0x06 | (preg & 0x40) >> 6)) << 4) | ((preg & 0x10) << 3); - if (!(EXPREGS[3] & 0x03)) - setprg8(A, bank); - else if ((A - 0x8000) == ((MMC3_cmd << 8) & 0x4000)) { /* TODO: Clean this */ - if ((EXPREGS[3] & 0x3) == 0x3) - setprg32(0x8000, (bank >> 2)); - else { - setprg16(0x8000, (bank >> 1)); - setprg16(0xc000, (bank >> 1)); - } - } -} - -static DECLFW(M126Write) { - A &= 0x03; - if(A == 0x01 || A == 0x02 || ((A == 0x00 || A == 0x03) && !(EXPREGS[3] & 0x80))) { - if (EXPREGS[A] != V) { - EXPREGS[A] = V; - if (EXPREGS[3] & 0x10) - UpdateChrBank(); - else - FixMMC3CHR(MMC3_cmd); - FixMMC3PRG(MMC3_cmd); - } - } -} - -void M126StateRestore(int v) { - FixMMC3CHR(MMC3_cmd); - FixMMC3PRG(MMC3_cmd); - - if (EXPREGS[3] & 0x10) - UpdateChrBank(); -} - -static void M126Reset(void) { - EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; - MMC3RegReset(); -} - -static void M126Power(void) { - EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, M126Write); -} - -void Mapper126_Init(CartInfo *info) { - GenMMC3_Init(info, 2048, 1023, 0, 0); - cwrap = M126CW; - pwrap = M126PW; - info->Power = M126Power; - info->Reset = M126Reset; - GameStateRestore = M126StateRestore; - AddExState(EXPREGS, 4, 0, "EXPR"); -} diff --git a/src/boards/134.c b/src/boards/134.c new file mode 100644 index 0000000..3f2f99f --- /dev/null +++ b/src/boards/134.c @@ -0,0 +1,96 @@ +/* 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 =EXPREGS[1] &0x04? 0x0F: 0x1F; + int prgOR =EXPREGS[1] <<4 &0x30 | EXPREGS[0] <<2 &0x40; + if (EXPREGS[1] &0x80) { /* NROM mode */ + if (EXPREGS[1] &0x08) { /* NROM-128 mode */ + setprg8(0x8000, (DRegBuf[6] &~1 |0) &prgAND | prgOR &~prgAND); + setprg8(0xA000, (DRegBuf[6] &~1 |1) &prgAND | prgOR &~prgAND); + setprg8(0xC000, (DRegBuf[6] &~1 |0) &prgAND | prgOR &~prgAND); + setprg8(0xE000, (DRegBuf[6] &~1 |1) &prgAND | prgOR &~prgAND); + } else { /* NROM-256 mode */ + setprg8(0x8000, (DRegBuf[6] &~3 |0) &prgAND | prgOR &~prgAND); + setprg8(0xA000, (DRegBuf[6] &~3 |1) &prgAND | prgOR &~prgAND); + setprg8(0xC000, (DRegBuf[6] &~3 |2) &prgAND | prgOR &~prgAND); + setprg8(0xE000, (DRegBuf[6] &~3 |3) &prgAND | prgOR &~prgAND); + } + } else + setprg8(A, V &prgAND | prgOR &~prgAND); +} + +static void Mapper134_CHRWrap(uint32 A, uint8 V) { + int chrAND =EXPREGS[1] &0x40? 0x7F: 0xFF; + int chrOR =EXPREGS[1] <<3 &0x180 | EXPREGS[0] <<4 &0x200; + if (EXPREGS[0] &0x08) V =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 EXPREGS[0] &0x40? dip: CartBR(A); +} + +static DECLFW(Mapper134_Write) { + if (~EXPREGS[0] &0x80) { + EXPREGS[A &3] =V; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + } else + if ((A &3) ==2) { + EXPREGS[A &3] =EXPREGS[A &3] &~3 | V &3; + FixMMC3CHR(MMC3_cmd); + } + CartBW(A, V); +} + +static void Mapper134_Reset(void) { + dip++; + dip &= 15; + EXPREGS[0] =EXPREGS[1] =EXPREGS[2] =EXPREGS[3] =0; + MMC3RegReset(); +} + +static void Mapper134_Power(void) { + dip =0; + EXPREGS[0] =EXPREGS[1] =EXPREGS[2] =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); + cwrap = Mapper134_CHRWrap; + pwrap = Mapper134_PRGWrap; + info->Power = Mapper134_Power; + info->Reset = Mapper134_Reset; + AddExState(EXPREGS, 4, 0, "EXPR"); + AddExState(&dip, 1, 0, "DIPS"); +} diff --git a/src/boards/15.c b/src/boards/15.c index e5ff110..f9c99a7 100644 --- a/src/boards/15.c +++ b/src/boards/15.c @@ -63,11 +63,19 @@ static void Sync(void) { setprg8(0xC000, preg[2]); setprg8(0xE000, preg[3]); setmirror(((latched >> 6) & 1) ^ 1); + setchr8(0); } static DECLFW(M15Write) { latchea = A; latched = V; + /* cah4e3 02.10.19 once again, there may be either two similar mapper 15 exist. the one for 110in1 or 168in1 carts with complex multi game features. + and another implified version for subor/waixing chinese originals and hacks with no different modes, working only in mode 0 and which does not + expect there is any CHR write protection. protecting CHR writes only for mode 3 fixes the problem, all roms may be run on the same source again. */ + if((latchea & 3) == 3) + SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0); + else + SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1); Sync(); } diff --git a/src/boards/158B.c b/src/boards/158B.c deleted file mode 100644 index 8bd0f5d..0000000 --- a/src/boards/158B.c +++ /dev/null @@ -1,71 +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 - * - * "Blood Of Jurassic" protected MMC3 based board (GD-98 Cart ID, 158B PCB ID) - * - */ - -#include "mapinc.h" -#include "mmc3.h" - -static uint8 lut[8] = { 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x0F, 0x00 }; - -static void UNL158BPW(uint32 A, uint8 V) { - if (EXPREGS[0] & 0x80) { - uint32 bank = EXPREGS[0] & 7; - if(EXPREGS[0] & 0x20) { /* 32Kb mode */ - setprg32(0x8000, bank >> 1); - } else { /* 16Kb mode */ - setprg16(0x8000, bank); - setprg16(0xC000, bank); - } - } else { - setprg8(A, V & 0xF); - } -} - -static DECLFW(UNL158BProtWrite) { - EXPREGS[A & 7] = V; - switch(A & 7) { - case 0: - FixMMC3PRG(MMC3_cmd); - break; - case 7: - FCEU_printf("UNK PROT WRITE\n"); - break; - } - -} - -static DECLFR(UNL158BProtRead) { - return X.DB | lut[A & 7]; -} - -static void UNL158BPower(void) { - GenMMC3Power(); - SetWriteHandler(0x5000, 0x5FFF, UNL158BProtWrite); - SetReadHandler(0x5000, 0x5FFF, UNL158BProtRead); -} - -void UNL158B_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 128, 0, 0); - pwrap = UNL158BPW; - info->Power = UNL158BPower; - AddExState(EXPREGS, 8, 0, "EXPR"); -} diff --git a/src/boards/162.c b/src/boards/162.c new file mode 100644 index 0000000..676b44f --- /dev/null +++ b/src/boards/162.c @@ -0,0 +1,119 @@ +/* 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 + */ + +/* Waixing FS304 PCB */ + +#include "mapinc.h" + +static uint8 *WRAM; +static uint32 WRAMSIZE; +static uint8 reg[4]; +static SFORMAT StateRegs[] = +{ + { reg, 4, "REGS" }, + { 0 } +}; + +static void sync() +{ + 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 */ + | ( reg[3] &0x04 ?(reg[0] &0x02): 0x00) /* PRG A16 is $5000.1 if %5300.2=1 */ + | ( reg[3] &0x01? 0x00 : reg[1] >>1 &0x01) /* PRG A15 is $5100.1 if $5300.0=0 */ + | (~reg[3] &0x04 && reg[3] &0x01? 0x01 : 0x00) /* PRG A15 is 1 if $5300.2=0 and $5300.0=1 */ + | ( reg[3] &0x04 && reg[3] &0x01?(reg[0] &0x01): 0x00) /* PRG A15 is $5000.0 if $5300.2=1 and $5300.0=1 */ + ); + setprg8r(0x10, 0x6000, 0); + if (~reg[0] &0x80) + setchr8(0); +} + +static void hblank(void) { + if (reg[0] &0x80 && scanline <239) + { /* Actual hardware cannot look at the current scanline number, but instead latches PA09 on 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 + setchr8(0); +} + +static DECLFR(readReg) +{ + return 0x00; +} + +static DECLFW(writeReg) +{ + reg[A >>8 &3] = V; + sync(); +} + +static void power(void) +{ + memset(reg, 0, sizeof(reg)); + sync(); + SetReadHandler (0x5000, 0x57FF, readReg); + SetWriteHandler(0x5000, 0x57FF, writeReg); + SetReadHandler (0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); +} + +static void reset(void) +{ + memset(reg, 0, sizeof(reg)); + sync(); +} + +static void close(void) +{ + if (WRAM) + FCEU_gfree(WRAM); + WRAM = NULL; +} + +static void StateRestore(int version) +{ + sync(); +} + +void Mapper162_Init (CartInfo *info) +{ + info->Power = power; + info->Reset = reset; + info->Close = close; + GameHBIRQHook = hblank; + + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, 0); + + WRAMSIZE = info->iNES2? (info->PRGRamSize + info->PRGRamSaveSize): 8192; + WRAM = (uint8*) FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } +} diff --git a/src/boards/163.c b/src/boards/163.c new file mode 100644 index 0000000..9709255 --- /dev/null +++ b/src/boards/163.c @@ -0,0 +1,124 @@ +/* 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 + */ + +/* Nanjing FC-001 PCB */ + +#include "mapinc.h" + +static uint8 *WRAM; +static uint32 WRAMSIZE; +static uint8 reg[4]; +static SFORMAT StateRegs[] = +{ + { reg, 4, "REGS" }, + { 0 } +}; + +static void sync() +{ + setprg32(0x8000, reg[2] <<4 | reg[0] &0xF | (reg[3] &0x04? 0x00: 0x03)); + setprg8r(0x10, 0x6000, 0); + if (~reg[0] &0x80) + setchr8(0); +} + +static void hblank(void) { + if (reg[0] &0x80 && scanline <239) + { /* Actual hardware cannot look at the current scanline number, but instead latches PA09 on 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 + setchr8(0); +} + +static DECLFR(readReg) +{ + return ~reg[1] &0x04; +} + +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)) + V = V &~3 | V >>1 &1 | V <<1 &2; + + if (A &1) + { + if (reg[1] &0x01 && ~V &0x01) reg[1] ^=0x04; /* If A0=1, flip feedback bit on falling edges of D0 */ + } /* If A0=0, write to register */ + else + reg[index] = V; + sync(); +} + +static void power(void) +{ + memset(reg, 0, sizeof(reg)); + sync(); + SetReadHandler (0x5000, 0x57FF, readReg); + SetWriteHandler(0x5000, 0x57FF, writeReg); + SetReadHandler (0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); +} + +static void reset(void) +{ + memset(reg, 0, sizeof(reg)); + sync(); +} + +static void close(void) +{ + if (WRAM) + FCEU_gfree(WRAM); + WRAM = NULL; +} + +static void StateRestore(int version) +{ + sync(); +} + +void Mapper163_Init (CartInfo *info) +{ + info->Power = power; + info->Reset = reset; + info->Close = close; + GameHBIRQHook = hblank; + + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, 0); + + WRAMSIZE = info->iNES2? (info->PRGRamSize + info->PRGRamSaveSize): 8192; + WRAM = (uint8*) FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + + if (info->battery) { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = WRAMSIZE; + } +} diff --git a/src/boards/164.c b/src/boards/164.c index 7516945..8557317 100644 --- a/src/boards/164.c +++ b/src/boards/164.c @@ -1,7 +1,9 @@ /* FCE Ultra - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2002 Xodnizel 2006 CaH4e3 + * 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 @@ -16,217 +18,120 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * It seems that 162/163/164 mappers are the same mapper with just different - * mapper modes enabled or disabled in software or hardware, need more nanjing - * carts */ +/* Dongda PEC-9588 educational computer. Provides the same 1bpp all-points-addressable graphics mode. + Its chipset was later used for the Yancheng cy2000-3 PCB, used on most of the games that display "Union Bond" at the start. + Some of them also use the 1bpp mode for a few screens! +*/ + #include "mapinc.h" +#include "eeprom_93C66.h" -static uint8 laststrobe, trigger; -static uint8 reg[8]; -static uint8 *WRAM = NULL; +static uint8 *WRAM; static uint32 WRAMSIZE; - -static writefunc pcmwrite; - -static void (*WSync)(void); - +static uint8 reg[8]; +static uint8 eeprom_data[512]; static SFORMAT StateRegs[] = { - { &laststrobe, 1, "STB" }, - { &trigger, 1, "TRG" }, - { reg, 8, "REGS" }, - { 0 } + { reg, 8, "REGS" }, + { eeprom_data, 512, "EEPR" }, + { 0 } }; -static void Sync(void) { - setprg8r(0x10, 0x6000, 0); - setprg32(0x8000, (reg[0] << 4) | (reg[1] & 0xF)); - setchr8(0); +static void sync() +{ + 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; + } + setprg8r(0x10, 0x6000, 0); + + setchr8(0); + PEC586Hack = !!(reg[0] &0x80); + + setmirror(reg[0] &0x10 && ~reg[3] &0x80? MI_H: MI_V); + + eeprom_93C66_write(reg[2] &0x10, reg[2] &0x04, reg[2] &0x01); } -static void StateRestore(int version) { - WSync(); +static DECLFR(readReg) +{ + return eeprom_93C66_read()? 0x00: 0x04; } -static DECLFR(ReadLow) { - switch (A & 0x7700) { - case 0x5100: return reg[2] | reg[0] | reg[1] | (reg[3] ^ 0xff); break; - case 0x5500: - if (trigger) - return reg[2] | reg[1]; /* Lei Dian Huang Bi Ka Qiu Chuan Shuo (NJ046) may broke other games */ - else - return 0; - } - return 4; +static DECLFW(writeReg) +{ + reg[A >>8 &7] = V; + sync(); } -static void M163HB(void) { - if (reg[1] & 0x80) { - if (scanline == 239) { - setchr4(0x0000, 0); - setchr4(0x1000, 0); - } else if (scanline == 127) { - setchr4(0x0000, 1); - setchr4(0x1000, 1); - } -#if 0 - if(scanline>=127) /* Hu Lu Jin Gang (NJ039) (Ch) [!] don't like it */ - { - setchr4(0x0000,1); - setchr4(0x1000,1); - } - else - { - setchr4(0x0000,0); - setchr4(0x1000,0); - } -#endif - } +static void power(void) +{ + memset(reg, 0, sizeof(reg)); + eeprom_93C66_init(); + sync(); + SetReadHandler (0x5400, 0x57FF, readReg); + SetWriteHandler(0x5000, 0x57FF, writeReg); + SetReadHandler (0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); } -static DECLFW(Write) { - switch (A & 0x7300) { - case 0x5100: reg[0] = V; WSync(); break; - case 0x5000: reg[1] = V; WSync(); break; - case 0x5300: reg[2] = V; break; - case 0x5200: reg[3] = V; WSync(); break; - } +static void reset(void) +{ + memset(reg, 0, sizeof(reg)); + sync(); } -static void Power(void) { - memset(reg, 0, 8); - reg[1] = 0xFF; - SetWriteHandler(0x5000, 0x5FFF, Write); - SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); - WSync(); +static void close(void) +{ + if (WRAM) + FCEU_gfree(WRAM); + WRAM = NULL; } -static void Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; +static void StateRestore(int version) +{ + sync(); } -void Mapper164_Init(CartInfo *info) { - info->Power = Power; - info->Close = Close; - WSync = Sync; +void Mapper164_Init (CartInfo *info) +{ + info->Power = power; + info->Reset = reset; + info->Close = close; - WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, 0); - if (info->battery) { - info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = WRAMSIZE; - } + WRAMSIZE = info->iNES2? (info->PRGRamSize + (info->PRGRamSaveSize &~0x7FF)): 8192; + WRAM = (uint8*) FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} - -static DECLFW(Write2) { - if (A == 0x5101) { - if (laststrobe && !V) { - trigger ^= 1; - } - laststrobe = V; - } else if (A == 0x5100 && V == 6) /* damn those protected games */ - setprg32(0x8000, 3); - else - switch (A & 0x7300) { - case 0x5200: reg[0] = V; WSync(); break; - case 0x5000: reg[1] = V; WSync(); if (!(reg[1] & 0x80) && (scanline < 128)) setchr8(0); /* setchr8(0); */ break; - case 0x5300: reg[2] = V; break; - case 0x5100: reg[3] = V; WSync(); break; - } -} - -static void Power2(void) { - memset(reg, 0, 8); - laststrobe = 1; - pcmwrite = GetWriteHandler(0x4011); - SetReadHandler(0x5000, 0x5FFF, ReadLow); - SetWriteHandler(0x5000, 0x5FFF, Write2); - SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); - WSync(); -} - -void Mapper163_Init(CartInfo *info) { - info->Power = Power2; - info->Close = Close; - WSync = Sync; - GameHBIRQHook = M163HB; - - 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); -} - -static void Sync3(void) { - setchr8(0); - setprg8r(0x10, 0x6000, 0); - switch (reg[3] & 7) { - case 0: - case 2: setprg32(0x8000, (reg[0] & 0xc) | (reg[1] & 2) | ((reg[2] & 0xf) << 4)); break; - case 1: - case 3: setprg32(0x8000, (reg[0] & 0xc) | (reg[2] & 0xf) << 4); break; - case 4: - case 6: setprg32(0x8000, (reg[0] & 0xe) | ((reg[1] >> 1) & 1) | ((reg[2] & 0xf) << 4)); break; - case 5: - case 7: setprg32(0x8000, (reg[0] & 0xf) | ((reg[2] & 0xf) << 4)); break; - } -} - -static DECLFW(Write3) { -/* FCEU_printf("bs %04x %02x\n",A,V); */ - reg[(A >> 8) & 3] = V; - WSync(); -} - -static void Power3(void) { - reg[0] = 3; - reg[1] = 0; - reg[2] = 0; - reg[3] = 7; - SetWriteHandler(0x5000, 0x5FFF, Write3); - SetReadHandler(0x6000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, CartBW); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); - WSync(); -} - -void UNLFS304_Init(CartInfo *info) { - info->Power = Power3; - info->Close = Close; - WSync = Sync3; - - 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); + eeprom_93C66_storage = eeprom_data; + info->battery = 1; + info->SaveGame[0] = eeprom_data; + info->SaveGameLen[0] = 512; } diff --git a/src/boards/178.c b/src/boards/178.c index 8f2a8d9..ca60dfe 100644 --- a/src/boards/178.c +++ b/src/boards/178.c @@ -136,6 +136,11 @@ static void M178Power(void) { 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; @@ -158,6 +163,7 @@ static void StateRestore(int version) { void Mapper178_Init(CartInfo *info) { info->Power = M178Power; + info->Reset = M178Reset; info->Close = M178Close; GameStateRestore = StateRestore; MapIRQHook = M178SndClk; diff --git a/src/boards/195.c b/src/boards/195.c new file mode 100644 index 0000000..f956a1a --- /dev/null +++ b/src/boards/195.c @@ -0,0 +1,97 @@ +/* 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 "mmc3.h" + +writefunc writePPU; +static uint8 *CHRRAM; +static uint32 CHRRAMSIZE; +static uint8 mask; +static uint8 compare; +extern uint32 RefreshAddr; + +static void Mapper195_CHRWrap(uint32 A, uint8 V) { + if ((V &mask) ==compare) + setchr1r(0x10, A, V); + else + setchr1r(0, A, V); +} + +static const uint8 compares[8] = { 0x28, 0x00, 0x4C, 0x64, 0x46, 0x7C, 0x04, 0xFF }; +static DECLFW(Mapper195_InterceptPPUWrite) { + if (RefreshAddr <0x2000) { + int addr =RefreshAddr; + int reg, bank; + + if (MMC3_cmd &0x80) addr ^=0x1000; + if (addr <0x1000) + reg =addr >>11; + else + reg =(addr >>10) -2; + + bank =DRegBuf[reg]; + if (bank &0x80) { + if (bank &0x10) { + mask =0x00; + compare =0xFF; + } else { + int index =(bank &0x02? 1: 0) | (bank &0x08? 2: 0) | (bank &0x40? 4: 0); + mask =bank &0x40? 0xFE: 0xFC; + compare =compares[index]; + } + FixMMC3CHR(MMC3_cmd); + } + } + writePPU(A, V); +} + +static void Mapper195_Power(void) { + mask =0xFC; + compare =0x00; + GenMMC3Power(); + setprg4r(0x10, 0x5000, 2); + SetWriteHandler(0x5000, 0x5FFF, CartBW); + SetReadHandler(0x5000, 0x5FFF, CartBR); + + if (GetWriteHandler(0x2007) !=Mapper195_InterceptPPUWrite) { + writePPU =GetWriteHandler(0x2007); + SetWriteHandler(0x2007, 0x2007, Mapper195_InterceptPPUWrite); + } +} + +void Mapper195_Close(void) { + if (CHRRAM) + FCEU_gfree(CHRRAM); + CHRRAM = NULL; +} + +void Mapper195_Init(CartInfo *info) { + GenMMC3_Init(info, 512, 256, 16, info->battery); + cwrap = Mapper195_CHRWrap; + info->Power = Mapper195_Power; + info->Reset = MMC3RegReset; + info->Close = Mapper195_Close; + CHRRAMSIZE =4096; + CHRRAM =(uint8*)FCEU_gmalloc(CHRRAMSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); + AddExState(&mask, 1, 0, "EXP0"); + AddExState(&compare, 1, 0, "EXP1"); +} diff --git a/src/boards/199.c b/src/boards/199.c index c6cd39f..16beb17 100644 --- a/src/boards/199.c +++ b/src/boards/199.c @@ -1,7 +1,7 @@ -/* FCE Ultra - NES/Famicom Emulator +/* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2006 CaH4e3 + * 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 @@ -16,83 +16,24 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Dragon Ball Z 2 - Gekishin Freeza! (C) - * Dragon Ball Z Gaiden - Saiya Jin Zetsumetsu Keikaku (C) - * San Guo Zhi 2 (C) - * */ - #include "mapinc.h" #include "mmc3.h" -static uint8 *CHRRAM = NULL; -static uint32 CHRRAMSIZE; - -static void M199PW(uint32 A, uint8 V) { - setprg8(A, V); - setprg8(0xC000, EXPREGS[0]); - setprg8(0xE000, EXPREGS[1]); +static void Mapper199_CHRWrap(uint32 A, uint8 V) { + setchr8(0); /* Unbanked CHR RAM */ } -static void M199CW(uint32 A, uint8 V) { - setchr1r((V < 8) ? 0x10 : 0x00, A, V); - setchr1r((DRegBuf[0] < 8) ? 0x10 : 0x00, 0x0000, DRegBuf[0]); - setchr1r((EXPREGS[2] < 8) ? 0x10 : 0x00, 0x0400, EXPREGS[2]); - setchr1r((DRegBuf[1] < 8) ? 0x10 : 0x00, 0x0800, DRegBuf[1]); - setchr1r((EXPREGS[3] < 8) ? 0x10 : 0x00, 0x0c00, EXPREGS[3]); -} - -static void M199MW(uint8 V) { -/* FCEU_printf("%02x\n",V); */ - switch (V & 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(M199Write) { - if ((A == 0x8001) && (MMC3_cmd & 8)) { - EXPREGS[MMC3_cmd & 3] = V; - FixMMC3PRG(MMC3_cmd); - FixMMC3CHR(MMC3_cmd); - } else - if (A < 0xC000) - MMC3_CMDWrite(A, V); - else - MMC3_IRQWrite(A, V); -} - -static void M199Power(void) { - EXPREGS[0] = ~1; - EXPREGS[1] = ~0; - EXPREGS[2] = 1; - EXPREGS[3] = 3; +static void Mapper199_Power(void) { GenMMC3Power(); - SetWriteHandler(0x8000, 0xFFFF, M199Write); -} - -static void M199Close(void) { - GenMMC3Close(); - if (CHRRAM) - FCEU_gfree(CHRRAM); - CHRRAM = NULL; + setprg4r(0x10, 0x5000, 2); + SetWriteHandler(0x5000, 0x5FFF, CartBW); + SetReadHandler(0x5000, 0x5FFF, CartBR); } void Mapper199_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 8, info->battery); - cwrap = M199CW; - pwrap = M199PW; - mwrap = M199MW; - info->Power = M199Power; - info->Close = M199Close; - - CHRRAMSIZE = 8192; - CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSIZE); - SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); - AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); - - AddExState(EXPREGS, 4, 0, "EXPR"); + GenMMC3_Init(info, 1024, 0, 16, info->battery); + cwrap = Mapper199_CHRWrap; + info->Power = Mapper199_Power; + info->Reset = MMC3RegReset; } diff --git a/src/boards/208.c b/src/boards/208.c index 95230a2..af03010 100644 --- a/src/boards/208.c +++ b/src/boards/208.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 + * 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 @@ -17,10 +18,17 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + + /* 2022-2-14 + * - add support for submapper 1, Mortal Kombat (JJ-01) (Ch) [!] + * - add mirroring + */ #include "mapinc.h" #include "mmc3.h" +static uint8 submapper; + static const uint8 lut[256] = { 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x49, 0x19, 0x09, 0x59, 0x49, 0x19, 0x09, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x51, 0x41, 0x11, 0x01, 0x51, 0x41, 0x11, 0x01, @@ -41,11 +49,21 @@ static const uint8 lut[256] = { }; static void M208PW(uint32 A, uint8 V) { - setprg32(0x8000, EXPREGS[5]); + if (submapper == 1) + setprg32(0x8000, DRegBuf[6] >> 2); + else + setprg32(0x8000, (EXPREGS[5] & 0x1) | ((EXPREGS[5] >> 3) & 0x2)); +} + +static void M208MW(uint8 V) { + if (submapper == 1) + setmirror((V & 1) ^ 1); + else + setmirror(((EXPREGS[5] >> 5) & 1) ^ 1); } static DECLFW(M208Write) { - EXPREGS[5] = (V & 0x1) | ((V >> 3) & 0x2); + EXPREGS[5] = V; FixMMC3PRG(MMC3_cmd); } @@ -61,7 +79,7 @@ static DECLFR(M208ProtRead) { } static void M208Power(void) { - EXPREGS[5] = 3; + EXPREGS[5] = 0x11; GenMMC3Power(); SetWriteHandler(0x4800, 0x4fff, M208Write); SetWriteHandler(0x6800, 0x6fff, M208Write); @@ -73,6 +91,8 @@ static void M208Power(void) { void Mapper208_Init(CartInfo *info) { GenMMC3_Init(info, 128, 256, 0, 0); pwrap = M208PW; + mwrap = M208MW; info->Power = M208Power; AddExState(EXPREGS, 6, 0, "EXPR"); + submapper = info->submapper; } diff --git a/src/boards/218.c b/src/boards/218.c index 84892d3..97ed530 100644 --- a/src/boards/218.c +++ b/src/boards/218.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 negativeExponent + * 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 @@ -19,7 +19,6 @@ */ #include "mapinc.h" -#include "../ines.h" static void M218Power(void) { setchr8(0); diff --git a/src/boards/225.c b/src/boards/225.c index 846f965..a00b9fd 100644 --- a/src/boards/225.c +++ b/src/boards/225.c @@ -3,7 +3,7 @@ * Copyright notice for this file: * Copyright (C) 2011 CaH4e3 * Copyright (C) 2019 Libretro Team - * Copyright (C) 2020 negativeExponent + * 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 diff --git a/src/boards/233.c b/src/boards/233.c new file mode 100644 index 0000000..e441772 --- /dev/null +++ b/src/boards/233.c @@ -0,0 +1,87 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2005 CaH4e3 + * Copyright (C) 2009 qeed + * Copyright (C) 2019 Libretro Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/* Updated 2019-07-12 + * Mapper 233 - UNIF 42in1ResetSwitch - reset-based switching + */ + +#include "mapinc.h" + +static uint8 latche; +static uint8 reset; + +static SFORMAT StateRegs[] = +{ + { &reset, 1, "RST" }, + { &latche, 1, "LATC" }, + { 0 } +}; + +static void Sync(void) { + uint8 bank = (latche & 0x1f) | (reset << 5); + + if (!(latche & 0x20)) + setprg32(0x8000, bank >> 1); + else { + setprg16(0x8000, bank); + setprg16(0xC000, bank); + } + + switch ((latche >> 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); +} + +static DECLFW(M233Write) { + latche = V; + Sync(); +} + +static void M233Power(void) { + latche = reset = 0; + Sync(); + SetWriteHandler(0x8000, 0xFFFF, M233Write); + SetReadHandler(0x8000, 0xFFFF, CartBR); +} + +static void StateRestore(int version) { + Sync(); +} + +static void M233Reset(void) { + latche = 0; + reset ^= 1; + Sync(); +} + +void Mapper233_Init(CartInfo *info) { + info->Power = M233Power; + info->Reset = M233Reset; + AddExState(&StateRegs, ~0, 0, 0); + GameStateRestore = StateRestore; +} diff --git a/src/boards/235.c b/src/boards/235.c index e065a88..c26d451 100644 --- a/src/boards/235.c +++ b/src/boards/235.c @@ -2,7 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2005 CaH4e3 - * Copyright (C) 2020 negativeExponent + * 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 @@ -20,28 +20,26 @@ */ #include "mapinc.h" -#include "../ines.h" - -static uint8 *CHRRAM; -static uint32 CHRRAMSIZE; static uint16 cmdreg; -static uint8 unrom, reg, type, openbus; +static uint8 unrom, reg, openbus; + +static uint32 PRGROMSize; static SFORMAT StateRegs[] = { { &cmdreg, 2 | FCEUSTATE_RLSB, "CREG" }, { &unrom, 1, "UNRM" }, { ®, 1, "UNRG" }, - { &type, 1, "TYPE" }, { &openbus, 1, "OPNB" }, { 0 } }; static void Sync(void) { - if (type && unrom) { - setprg16(0x8000, 0x80 | reg & 7); - setprg16(0xC000, 0x80 | 7); + if (unrom) { + uint8 PRGPageSize = PRGROMSize / 16384; + setprg16(0x8000, (PRGPageSize & 0xC0) | (reg & 7)); + setprg16(0xC000, (PRGPageSize & 0xC0) | 7); setchr8(0); setmirror(MI_V); } else { @@ -50,7 +48,7 @@ static void Sync(void) { setmirror(MI_0); else setmirror(((cmdreg >> 13) & 1) ^ 1); - if (bank >= PRGsize[0] / 32768) + if (bank >= PRGROMSize / 32768) openbus = 1; else if (cmdreg & 0x800) { setprg16(0x8000, (bank << 1) | ((cmdreg >> 12) & 1)); @@ -75,15 +73,11 @@ static DECLFW(M235Write) { Sync(); } -static void M235Close(void) { - if (CHRRAM) - FCEU_free(CHRRAM); - CHRRAM = NULL; -} - static void M235Reset(void) { cmdreg = 0; - unrom = (unrom + type) & 1; + reg = 0; + if (PRGROMSize & 0x20000) + unrom = (unrom + 1) & 1; Sync(); } @@ -91,6 +85,7 @@ static void M235Power(void) { SetWriteHandler(0x8000, 0xFFFF, M235Write); SetReadHandler(0x8000, 0xFFFF, M235Read); cmdreg = 0; + reg = 0; Sync(); } @@ -101,22 +96,7 @@ static void M235Restore(int version) { void Mapper235_Init(CartInfo *info) { info->Reset = M235Reset; info->Power = M235Power; - info->Close = M235Close; GameStateRestore = M235Restore; AddExState(&StateRegs, ~0, 0, 0); - - /* some nes 2.0 header do can have no chr-ram. - * one such cart is 210-in-1 and Contra 4-in-1 (212-in-1,212 Hong Kong,Reset Based)(Unl).nes (0x745A6791) - */ - if (CHRsize[0] == 0) { - CHRRAMSIZE = 8192; - CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSIZE); - SetupCartCHRMapping(0, CHRRAM, CHRRAMSIZE, 1); - AddExState(CHRRAM, CHRRAMSIZE, 0, "CRAM"); - } - - type = 0; - /* carts with unrom game, reset-based */ - if ((info->CRC32) == 0x745A6791) /* 210-in-1 and Contra 4-in-1 (212-in-1,212 Hong Kong,Reset Based)(Unl).nes */ - type = 1; + PRGROMSize = info->PRGRomSize; } diff --git a/src/boards/236.c b/src/boards/236.c new file mode 100644 index 0000000..463e988 --- /dev/null +++ b/src/boards/236.c @@ -0,0 +1,111 @@ +/* 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 reg[2]; +static uint8 dip; +static uint8 chrramvariant; +static SFORMAT StateRegs[] = +{ + { reg, 2, "REG " }, + { &dip, 1, "DIP " }, + { 0 } +}; + +static void Sync(void) +{ + int prg; + int chr; + if (chrramvariant) + { + prg = reg[1] &7 | 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; + } + setchr8(chr); + setmirror((reg[0] >>5 &1) ^1); +} + +static DECLFR(M236Read) +{ + if ((reg[1] >>4 &3) ==1) + return CartBR(A &~0xF | dip &0xF); + else + return CartBR(A); +} + +static DECLFW(M236WriteReg) +{ + reg[A >>14 &1] =A &0xFF; + Sync(); +} + +static void M236Power(void) +{ + dip = 0; + reg[0] = 0; + reg[1] = 0; + Sync(); + SetWriteHandler(0x8000, 0xFFFF, M236WriteReg); + SetReadHandler(0x8000, 0xFFFF, M236Read); +} + +static void M236Reset(void) +{ + ++dip; + /* Soft-reset returns to menu */ + reg[0] = 0; + reg[1] = 0; + Sync(); +} + +static void StateRestore(int version) +{ + Sync(); +} + +void Mapper236_Init(CartInfo *info) +{ + info->Power = M236Power; + info->Reset = M236Reset; + AddExState(&StateRegs, ~0, 0, 0); + GameStateRestore = StateRestore; + chrramvariant = info->CHRRomSize == 0; +} diff --git a/src/boards/267.c b/src/boards/267.c index 1b53e89..1f34529 100644 --- a/src/boards/267.c +++ b/src/boards/267.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 negativeExponent + * 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 @@ -34,9 +34,11 @@ static void M267PW(uint32 A, uint8 V) { } static DECLFW(M267Write) { - EXPREGS[0] = V; - FixMMC3PRG(MMC3_cmd); - FixMMC3CHR(MMC3_cmd); + if (!(EXPREGS[0] & 0x80)) { + EXPREGS[0] = V; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + } } static void M267Reset(void) { @@ -47,14 +49,14 @@ static void M267Reset(void) { static void M267Power(void) { EXPREGS[0] = 0; GenMMC3Power(); - SetWriteHandler(0x6000, 0x6FFF, M267Write); + SetWriteHandler(0x6000, 0x7FFF, M267Write); } void Mapper267_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 128, 0, 0); + GenMMC3_Init(info, 256, 128, 0, 0); cwrap = M267CW; pwrap = M267PW; info->Reset = M267Reset; info->Power = M267Power; - AddExState(EXPREGS, 4, 0, "EXPR"); + AddExState(EXPREGS, 1, 0, "EXPR"); } diff --git a/src/boards/268.c b/src/boards/268.c new file mode 100644 index 0000000..328fd90 --- /dev/null +++ b/src/boards/268.c @@ -0,0 +1,157 @@ +/* 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 "mmc3.h" + +static uint8 *CHRRAM =NULL; +static uint8 submapper; + +static void Mapper268_PRGWrap(uint32 A, uint8 V) { + int prgMaskMMC3, prgMaskGNROM, prgOffset; + + prgMaskMMC3 =(EXPREGS[3] &0x10? 0x00: 0x0F) /* PRG A13-A16 */ + |(EXPREGS[0] &0x40? 0x00: 0x10) /* PRG A17 */ + |(EXPREGS[1] &0x80? 0x00: 0x20) /* PRG A18 */ + |(EXPREGS[1] &0x40? 0x40: 0x00) /* PRG A19 */ + |(EXPREGS[1] &0x20? 0x80: 0x00) /* PRG A20 */ + ; + switch(submapper &~1) { + default: /* Original implementation */ + prgMaskGNROM =EXPREGS[3] &0x10? (EXPREGS[1] &0x02? 0x03: 0x01): 0x00; + prgOffset =EXPREGS[3] &0x00E + |EXPREGS[0] <<4 &0x070 + |EXPREGS[1] <<3 &0x080 + |EXPREGS[1] <<6 &0x300 + |EXPREGS[0] <<6 &0xC00; + break; + case 2: /* Later revision with different arrangement of register 1 */ + prgMaskGNROM =EXPREGS[3] &0x10? (EXPREGS[1] &0x10? 0x01: 0x03): 0x00; + prgOffset =EXPREGS[3] &0x00E + |EXPREGS[0] <<4 &0x070 + |EXPREGS[1] <<4 &0x080 + |EXPREGS[1] <<6 &0x100 + |EXPREGS[1] <<8 &0x200 + |EXPREGS[0] <<6 &0xC00; + break; + case 4: /* LD622D: PRG A20-21 moved to register 0 */ + prgMaskGNROM =EXPREGS[3] &0x10? (EXPREGS[1] &0x02? 0x03: 0x01): 0x00; + prgOffset =EXPREGS[3] &0x00E + |EXPREGS[0] <<4 &0x070 + |EXPREGS[0] <<3 &0x180; + break; + case 6: /* J-852C: CHR A17 selects between two PRG chips */ + prgMaskGNROM =EXPREGS[3] &0x10? (EXPREGS[1] &0x02? 0x03: 0x01): 0x00; + prgOffset =EXPREGS[3] &0x00E + |EXPREGS[0] <<4 &0x070 + |EXPREGS[1] <<3 &0x080 + |EXPREGS[1] <<6 &0x300 + |EXPREGS[0] <<6 &0xC00; + prgOffset &=ROM_size -1; + if (EXPREGS[0] &0x80? !!(EXPREGS[0] &0x08): !!(DRegBuf[0] &0x80)) prgOffset |=ROM_size; + break; + } + prgOffset &=~(prgMaskMMC3 | prgMaskGNROM); + setprg8(A, V &prgMaskMMC3 | prgOffset | A >>13 &prgMaskGNROM); + + /* CHR-RAM write protect on submapper 8/9) */ + SetupCartCHRMapping(0, CHRptr[0], CHRsize[0], (submapper &~1) ==8 && EXPREGS[0] &0x10? 0: 1); +} + +static void Mapper268_CHRWrap(uint32 A, uint8 V) { + int chrMaskMMC3, chrMaskGNROM, chrOffset; + + chrMaskMMC3 =EXPREGS[3] &0x10? 0x00: EXPREGS[0] &0x80? 0x7F: 0xFF; + chrMaskGNROM =EXPREGS[3] &0x10? 0x07: 0x00; + chrOffset =EXPREGS[0] <<4 &0x380 | EXPREGS[2] <<3 &0x078; + chrOffset &=~(chrMaskMMC3 | chrMaskGNROM); + + setchr1r(CHRRAM && EXPREGS[4] &0x01 && (V &0xFE) ==(EXPREGS[4] &0xFE)? 0x10: 0x00, A, V &chrMaskMMC3 | chrOffset | A >>10 &chrMaskGNROM); +} + +static DECLFR(Mapper268_ReadWRAM) { + return A001B &0xA0? CartBR(A): X.DB; +} + +static DECLFW(Mapper268_WriteWRAM) { + if (A001B &0x80 && ~A001B &0x40 || A001B &0x20) CartBW(A, V); +} + +static DECLFW(Mapper268_WriteReg) { + int index =A &7; + if (~submapper &1) Mapper268_WriteWRAM(A, V); + if (~EXPREGS[3] &0x80 || index ==2) { + if (index ==2) { + if (EXPREGS[2] &0x80) V =V &0x0F | EXPREGS[2] &~0x0F; + V &=~EXPREGS[2] >>3 &0xE |0xF1; + } + EXPREGS[index] =V; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + } +} + +static void Mapper268_Reset(void) { + EXPREGS[0] =EXPREGS[1] =EXPREGS[2] =EXPREGS[3] =EXPREGS[4] =EXPREGS[5] =0; + MMC3RegReset(); +} + +static void Mapper268_Power(void) { + EXPREGS[0] =EXPREGS[1] =EXPREGS[2] =EXPREGS[3] =EXPREGS[4] =EXPREGS[5] =0; + GenMMC3Power(); + SetReadHandler(0x6000, 0x7FFF, Mapper268_ReadWRAM); + if (submapper &1) { + SetWriteHandler(0x5000, 0x5FFF, Mapper268_WriteReg); + SetWriteHandler(0x6000, 0x7FFF, Mapper268_WriteWRAM); + } else + SetWriteHandler(0x6000, 0x7FFF, Mapper268_WriteReg); +} + +static void Mapper268_close(void) { + if (CHRRAM) FCEU_gfree(CHRRAM); + CHRRAM =NULL; + GenMMC3Close(); +} + +void Mapper268_Init(CartInfo *info) { + submapper = info->submapper; + GenMMC3_Init(info, 512, 256, (info->PRGRamSize +info->PRGRamSaveSize) >>10, info->battery); + cwrap = Mapper268_CHRWrap; + pwrap = Mapper268_PRGWrap; + info->Power = Mapper268_Power; + info->Reset = Mapper268_Reset; + info->Close = Mapper268_close; + AddExState(EXPREGS, 8, 0, "EXPR"); + + if (info->CHRRomSize && info->CHRRamSize + info->CHRRamSaveSize) { + CHRRAM =(uint8 *)FCEU_gmalloc(info->CHRRamSize + info->CHRRamSaveSize); + SetupCartCHRMapping(0x10, CHRRAM, info->CHRRamSize + info->CHRRamSaveSize, 1); + AddExState(CHRRAM, info->CHRRamSize + info->CHRRamSaveSize, 0, "CRAM"); + } +} + +void COOLBOY_Init(CartInfo *info) { + info->submapper =0; + Mapper268_Init(info); +} + +void MINDKIDS_Init(CartInfo *info) { + info->submapper =1; + Mapper268_Init(info); +} diff --git a/src/boards/269.c b/src/boards/269.c index 0acef24..9985888 100644 --- a/src/boards/269.c +++ b/src/boards/269.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 negativeExponent + * 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 @@ -80,7 +80,7 @@ static uint8 unscrambleCHR(uint8 data) { } void Mapper269_Init(CartInfo *info) { - int i; + uint32 i; GenMMC3_Init(info, 512, 0, 8, 0); cwrap = M269CW; pwrap = M269PW; diff --git a/src/boards/272.c b/src/boards/272.c new file mode 100644 index 0000000..3e91c1e --- /dev/null +++ b/src/boards/272.c @@ -0,0 +1,179 @@ +/* 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/gs-2013.c b/src/boards/283.c similarity index 81% rename from src/boards/gs-2013.c rename to src/boards/283.c index e7cda5f..7d9eaef 100644 --- a/src/boards/gs-2013.c +++ b/src/boards/283.c @@ -29,25 +29,25 @@ static SFORMAT StateRegs[] = }; static void Sync(void) { - setprg8(0x6000, 31); + setprg8(0x6000, (ROM_size == 17) ? 32 : 31); /* FIXME: Verify these */ setprg32(0x8000, reg); setchr8(0); } -static DECLFW(BMCGS2013Write) { +static DECLFW(M283Write) { reg = V; Sync(); } -static void BMCGS2013Power(void) { +static void M283Power(void) { reg = 0; Sync(); SetReadHandler(0x6000, 0x7FFF, CartBR); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, BMCGS2013Write); + SetWriteHandler(0x8000, 0xFFFF, M283Write); } -static void BMCGS2013Reset(void) { +static void M283Reset(void) { reg = 0; } @@ -55,9 +55,9 @@ static void StateRestore(int version) { Sync(); } -void BMCGS2013_Init(CartInfo *info) { - info->Reset = BMCGS2013Reset; - info->Power = BMCGS2013Power; +void Mapper283_Init(CartInfo *info) { + info->Reset = M283Reset; + info->Power = M283Power; GameStateRestore = StateRestore; AddExState(&StateRegs, ~0, 0, 0); } diff --git a/src/boards/291.c b/src/boards/291.c new file mode 100644 index 0000000..aacce1a --- /dev/null +++ b/src/boards/291.c @@ -0,0 +1,59 @@ +/* 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 "mmc3.h" + +static void M291CW(uint32 A, uint8 V) { + setchr1(A, V | ((EXPREGS[0] << 2) & 0x100)); +} + +static void M291PW(uint32 A, uint8 V) { + if (EXPREGS[0] & 0x20) + setprg32(0x8000, ((EXPREGS[0] >> 1) & 3) | ((EXPREGS[0] >> 4) & 4)); + else + setprg8(A, (V & 0x0F) | ((EXPREGS[0] >> 2) & 0x10)); +} + +static DECLFW(M291Write) { + EXPREGS[0] = V; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static void M291Reset(void) { + EXPREGS[0] = 0; + MMC3RegReset(); +} + +static void M291Power(void) { + EXPREGS[0] = 0; + GenMMC3Power(); + SetWriteHandler(0x6000, 0x7FFF, M291Write); +} + +void Mapper291_Init(CartInfo *info) { + GenMMC3_Init(info, 256, 512, 0, 0); + cwrap = M291CW; + pwrap = M291PW; + info->Power = M291Power; + info->Reset = M291Reset; + AddExState(EXPREGS, 1, 0, "EXPR"); +} diff --git a/src/boards/293.c b/src/boards/293.c new file mode 100644 index 0000000..86348b0 --- /dev/null +++ b/src/boards/293.c @@ -0,0 +1,91 @@ +/* FCE Ultra - 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 + * + * NewStar 12-in-1 and 76-in-1 + */ + +#include "mapinc.h" + +static uint8 regs[2]; +static SFORMAT StateRegs[] = +{ + { regs, 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); + 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; + } + setchr8(0); + setmirror(((regs[1] >> 7) & 1) ^ 1); +} + +static DECLFW(M293Write1) { + regs[0] = V; + regs[1] = V; + Sync(); +} + +static DECLFW(M293Write2) { + regs[1] = V; + Sync(); +} + +static DECLFW(M293Write3) { + regs[0] = V; + Sync(); +} + +static void M293Power(void) { + regs[0] = regs[1] = 0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0x9FFF, M293Write1); + SetWriteHandler(0xA000, 0xBFFF, M293Write2); + SetWriteHandler(0xC000, 0xDFFF, M293Write3); +} + +static void StateRestore(int version) { + Sync(); +} + +/* BMC 12-in-1/76-in-1 (NewStar) (Unl) */ +void Mapper293_Init(CartInfo *info) { + info->Power = M293Power; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/294.c b/src/boards/294.c new file mode 100644 index 0000000..db4956c --- /dev/null +++ b/src/boards/294.c @@ -0,0 +1,61 @@ +/* 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 latch; + +static void Mapper294_sync (void) { + setprg16(0x8000, latch); + setprg16(0xC000, latch |7); + setchr8(0); + setmirror(latch &0x80? MI_H: MI_V); +} + +static DECLFW(Mapper294_writeInnerBank) { + latch =latch &~7 | V&7; + Mapper294_sync(); +} + +static DECLFW(Mapper294_writeOuterBank) { + if (A &0x100) { + latch =latch &7 | V <<3; + Mapper294_sync(); + } +} + +static void Mapper294_reset(void) { + latch =0; + Mapper294_sync(); +} + +static void Mapper294_power(void) { + Mapper294_reset(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, Mapper294_writeInnerBank); + SetWriteHandler(0x4020, 0x7FFF, Mapper294_writeOuterBank); +} + +void Mapper294_Init(CartInfo *info) { + info->Power = Mapper294_power; + info->Reset = Mapper294_reset; + AddExState(&latch, 1, 0, "LATC"); +} diff --git a/src/boards/310.c b/src/boards/310.c new file mode 100644 index 0000000..929af1b --- /dev/null +++ b/src/boards/310.c @@ -0,0 +1,88 @@ +/* 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 regData[2]; +static uint8 regAddr; + +static SFORMAT K1053_state[] = +{ + { regData, 2, "REGD" }, + {®Addr, 1, "REGA" }, + { 0 } +}; + +static void K1053_sync (void) { + int prg =regData[0] &0x3F | regAddr <<4 &~0x3F; + int chrWritable; + switch(regAddr &3) { + case 0: setprg32(0x8000, prg >>1); + chrWritable =0; + break; + case 1: setprg16(0x8000, prg); + setprg16(0xC000, prg |7); + chrWritable =1; + break; + case 2: prg =prg <<1 | regData[0] >>7; + setprg8(0x8000, prg); + setprg8(0xA000, prg); + setprg8(0xC000, prg); + setprg8(0xE000, prg); + chrWritable =1; + break; + case 3: setprg16(0x8000, prg); + setprg16(0xC000, prg); + chrWritable =0; + break; + } + SetupCartCHRMapping(0, CHRptr[0], 0x8000, chrWritable); + setchr8(regData[1]); + setmirror(regData[0] &0x40? MI_H: MI_V); +} + +static void K1053_restore(int version) { + K1053_sync(); +} + +static DECLFW(K1053_write) { + regData[A >>14 &1] =V; + if (A &0x4000) regAddr=A &0xFF; + K1053_sync(); +} + +static void K1053_reset(void) { + regData[0] =regData[1] =regAddr =0; + K1053_sync(); +} + +static void K1053_power(void) { + K1053_reset(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, K1053_write); +} + +void Mapper310_Init(CartInfo *info) { + info->Power = K1053_power; + info->Reset = K1053_reset; + GameStateRestore = K1053_restore; + AddExState(&K1053_state, ~0, 0, 0); +} diff --git a/src/boards/319.c b/src/boards/319.c new file mode 100644 index 0000000..d7288b6 --- /dev/null +++ b/src/boards/319.c @@ -0,0 +1,86 @@ +/* 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[2]; +static uint8 latch; +static uint8 pad; + +static SFORMAT StateRegs[] = +{ + { reg, 2, "REG" }, + { &latch, 1, "LATC" }, + { &pad, 1, "PAD" }, + { 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); + } + setchr8(reg[0] >>4 &~(reg[0] <<2 &4) | latch <<2 &(reg[0] <<2 &4)); + setmirror(reg[1] >>7); +} + +static void StateRestore(int version) { + M319Sync(); +} + +static DECLFR(M319ReadPad) { + return pad; +} + +static DECLFW(M319WriteReg) { + reg[A >>2 &1] =V; + M319Sync(); +} + +static DECLFW(M319WriteLatch) { + latch =V; + M319Sync(); +} + +static void M319Reset(void) { + reg[0] =reg[1] =latch =0; + pad ^=0x40; + M319Sync(); +} + +static void M319Power(void) { + reg[0] =reg[1] =latch =pad =0; + M319Sync(); + SetReadHandler(0x5000, 0x5FFF, M319ReadPad); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, M319WriteReg); + SetWriteHandler(0x8000, 0xFFFF, M319WriteLatch); +} + +void Mapper319_Init(CartInfo *info) { + info->Power = M319Power; + info->Reset = M319Reset; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/326.c b/src/boards/326.c new file mode 100644 index 0000000..a29fced --- /dev/null +++ b/src/boards/326.c @@ -0,0 +1,98 @@ +/* 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 326 is used for a bootleg version of Contra/Gryzor. + * as implemented from + * http://forums.nesdev.org/viewtopic.php?f=9&t=17352&p=218722#p218722 + */ + +#include "mapinc.h" + +static uint8 PRG[3], CHR[8], NTAPage[4]; + +static SFORMAT StateRegs[] = +{ + { PRG, 3, "PRG" }, + { CHR, 8, "CHR" }, + { NTAPage, 4, "NT" }, + { 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 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]); +} + +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; + } + + A &= 0x801F; + if ((A >= 0x8010) && (A <= 0x8017)) + DoCHR(A - 0x8010, V); + else if ((A >= 0x8018) && (A <= 0x801B)) + DoNTARAM(A - 0x8018, V); +} + +static void M326Power(void) { + SyncPRG(); + FixCHR(); + FixNTAR(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M326Write); +} + +static void StateRestore(int version) { + SyncPRG(); + FixCHR(); + FixNTAR(); +} + +void Mapper326_Init(CartInfo *info) { + info->Power = M326Power; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/330.c b/src/boards/330.c new file mode 100644 index 0000000..e2453a3 --- /dev/null +++ b/src/boards/330.c @@ -0,0 +1,137 @@ +/* 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 330 is used for a bootleg version of Contra/Gryzor. + * as implemented from + * http://forums.nesdev.org/viewtopic.php?f=9&t=17352&p=218722#p218722 + */ + +#include "mapinc.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" }, + { 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 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]); +} + +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)) { + if (A & 0x2000) { + IRQCount &= 0x00FF; + IRQCount |= (V & 0x7F) << 8; + IRQa = V & 0x80; + X6502_IRQEnd(FCEU_IQEXT); + } else { + IRQCount &= 0xFF00; + IRQCount |= V; + } + } +} + +static void M330Power(void) { + int i; + for (i = 0; i < 4; 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(); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M330Write); +} + +static void FP_FASTAPASS(1) M330IRQHook(int a) { + if (IRQa) { + IRQCount += a; + if (IRQCount > 0x7FFF) { + X6502_IRQBegin(FCEU_IQEXT); + IRQa = 0; + IRQCount = 0; + } + } +} + +static void StateRestore(int version) { + SyncPRG(); + FixCHR(); + FixNTAR(); +} + +void Mapper330_Init(CartInfo *info) { + info->Power = M330Power; + MapIRQHook = M330IRQHook; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); + WRAM = (uint8 *)FCEU_gmalloc(8192); + SetupCartPRGMapping(0x10, WRAM, 8192, 1); + AddExState(WRAM, 8192, 0, "WRAM"); +} diff --git a/src/boards/334.c b/src/boards/334.c new file mode 100644 index 0000000..a4dfc27 --- /dev/null +++ b/src/boards/334.c @@ -0,0 +1,65 @@ +/* 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 uint8 dipswitch; + +static void M334PW(uint32 A, uint8 V) { + setprg32(0x8000, EXPREGS[0] >> 1); +} + +static DECLFW(M334Write) { + if (!(A & 1)) { + EXPREGS[0] = V; + FixMMC3PRG(MMC3_cmd); + } +} + +static DECLFR(M334Read) { + if (A & 2) + return ((X.DB & 0xFE) | (dipswitch & 1)); + return X.DB; +} + +static void M334Reset(void) { + dipswitch++; + EXPREGS[0] = 0; + MMC3RegReset(); +} + +static void M334Power(void) { + dipswitch = 0; + EXPREGS[0] = 0; + GenMMC3Power(); + SetReadHandler(0x6000, 0x7FFF, M334Read); + SetWriteHandler(0x6000, 0x7FFF, M334Write); +} + +void Mapper334_Init(CartInfo *info) { + GenMMC3_Init(info, 32, 32, 0, 0); + pwrap = M334PW; + info->Power = M334Power; + info->Reset = M334Reset; + AddExState(EXPREGS, 1, 0, "EXPR"); +} diff --git a/src/boards/351.c b/src/boards/351.c new file mode 100644 index 0000000..e8db51c --- /dev/null +++ b/src/boards/351.c @@ -0,0 +1,338 @@ +/* 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, MMC1_filter; +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 signed short int 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" }, + { &MMC1_filter, 1, "M1FI" }, + { MMC3_reg, 1, "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 sync () { + int chrAND; + int chrOR; + int prgAND =reg[2] &0x04? 0x0F: 0x1F; + int prgOR =reg[1] >>1; + int 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 + if (~reg[0] &0x02) { /* 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); + } else + if (reg[0] &0x01) { /* 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); + } else { /* 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); + } + + chrAND =reg[2] &0x10 && ~reg[2] &0x20? 0x1F: reg[2] &0x20? 0x7F: 0xFF; + 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 + if (~reg[0] &0x02) { /* 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); + } else + if (reg[0] &0x01) { /* 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); + } else { /* 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); + } + + if (~reg[0] &0x02) /* MMC3 mode */ + setmirror(MMC3_mirroring &1 ^1); + else + if ( reg[0] &0x01) /* VRC4 mode */ + setmirror(VRC4_mirroring &3 ^(VRC4_mirroring &2? 0: 1)); + else /* MMC1 mode */ + setmirror(MMC1_reg[0] &3 ^3); +} + +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 DECLFW(writeMMC1) { + if (V &0x80) { + MMC1_shift =MMC1_count =0; + MMC1_reg[0] |=0x0C; + sync(); + } else + if (!MMC1_filter) { + MMC1_shift |=(V &1) <>13 &3] =MMC1_shift; + MMC1_count =0; + MMC1_shift =0; + sync(); + } + } + MMC1_filter =2; +} + +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) cpuCycle(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); + } + } + } + if (MMC1_filter) MMC1_filter--; +} + +static void horizontalBlanking(void) { + if (~reg[0] &2) { /* MMC3 mode */ + MMC3_count =!MMC3_count? MMC3_reload: --MMC3_count; + if (!MMC3_count && MMC3_irq) X6502_IRQBegin(FCEU_IQEXT); + } +} + +static void applyMode() { + switch (reg[0] &3) { + case 0: + case 1: SetWriteHandler(0x8000, 0xFFFF, writeMMC3); break; + case 2: SetWriteHandler(0x8000, 0xFFFF, writeMMC1); break; + case 3: SetWriteHandler(0x8000, 0xFFFF, writeVRC4); break; + } +} + +static void Mapper351_restore (int version) { + applyMode(); + sync(); +} + +static DECLFR(readDIP) { + return dip; +} + +static DECLFW(writeReg) { + uint8 previousMode =reg[0] &3; + reg[A &3] =V; + if ((reg[0] &3) !=previousMode) applyMode(); + sync(); +} + +static DECLFW(writeFDSMirroring) { + MMC3_mirroring =V >>3 &1; + sync(); +} + +static void Mapper351_power(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 =MMC1_filter =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; + + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetReadHandler(0x5000, 0x5FFF, readDIP); + SetWriteHandler(0x5000, 0x5FFF, writeReg); + SetWriteHandler(0x4025, 0x4025, writeFDSMirroring); + applyMode(); + sync(); +} + +static void Mapper351_reset (void) { + int i; + for (i =0; i <4; i++) reg[i] =0; + dip++; + applyMode(); + sync(); +} + +static void Mapper351_close(void) { + if (CHRRAM) FCEU_gfree(CHRRAM); + if (PRGCHR) FCEU_gfree(PRGCHR); + CHRRAM =NULL; + PRGCHR =NULL; +} + +void Mapper351_Init (CartInfo *info) { + int CHRRAMSIZE =info->CHRRamSize + info->CHRRamSaveSize; + + info->Reset = Mapper351_reset; + info->Power = Mapper351_power; + info->Close = Mapper351_close; + MapIRQHook = cpuCycle; + GameHBIRQHook = horizontalBlanking; + GameStateRestore = Mapper351_restore; + AddExState(stateRegs, ~0, 0, 0); + + if (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/353.c b/src/boards/353.c index 765aa08..36126f5 100644 --- a/src/boards/353.c +++ b/src/boards/353.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 negativeExponent + * 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 diff --git a/src/boards/354.c b/src/boards/354.c new file mode 100644 index 0000000..0b4d731 --- /dev/null +++ b/src/boards/354.c @@ -0,0 +1,92 @@ +/* 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" + +static uint16 latchAddr; +static uint8 latchData; +static uint8 submapper; + +static SFORMAT StateRegs[] = +{ + { &latchAddr, 2, "ADDR" }, + { &latchData, 1, "DATA" }, + { 0 } +}; + +static void Mapper354_Sync(void) +{ + int prg =latchData &0x3F | latchAddr <<2 &0x40 | latchAddr >>5 &0x80; + switch(latchAddr &7) + { + case 0: case 4: + setprg32(0x8000, prg >>1); + break; + case 1: + setprg16(0x8000, prg); + setprg16(0xC000, prg |7); + break; + case 2: case 6: + setprg8(0x8000, prg <<1 | latchData >>7); + setprg8(0xA000, prg <<1 | latchData >>7); + setprg8(0xC000, prg <<1 | latchData >>7); + setprg8(0xE000, prg <<1 | latchData >>7); + break; + case 3: case 7: + setprg16(0x8000, prg); + setprg16(0xC000, prg); + break; + case 5: + setprg8(0x6000, prg <<1 | latchData >>7); + setprg32(0x8000, prg >>1 |3); + break; + } + setchr8(0); + setmirror(latchData &0x40? MI_H: MI_V); +} + +static DECLFW(Mapper354_WriteLatch) +{ + latchData =V; + latchAddr =A &0xFFFF; + Mapper354_Sync(); +} + +static void Mapper354_Reset(void) +{ + latchAddr =latchData =0; + Mapper354_Sync(); +} + +static void Mapper354_Power(void) +{ + latchAddr =latchData =0; + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(submapper ==1? 0xE000: 0xF000, 0xFFFF, Mapper354_WriteLatch); + Mapper354_Sync(); +} + +void Mapper354_Init(CartInfo *info) +{ + submapper = info->submapper; + info->Power =Mapper354_Power; + info->Reset =Mapper354_Reset; + AddExState(StateRegs, ~0, 0, 0); +} diff --git a/src/boards/356.c b/src/boards/356.c index 3ea1f5f..666b7aa 100644 --- a/src/boards/356.c +++ b/src/boards/356.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 negativeExponent + * 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 diff --git a/src/boards/357.c b/src/boards/357.c index 2c28e9e..48088fc 100644 --- a/src/boards/357.c +++ b/src/boards/357.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 negativeExponent + * 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 @@ -29,15 +29,16 @@ static uint8 preg[4]; static uint8 dipswitch; -static uint32 IRQCount, IRQa; +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[] = { - { &IRQCount, 4 | FCEUSTATE_RLSB, "IRQC" }, - { &IRQa, 4 | FCEUSTATE_RLSB, "IRQA" }, + { &IRQCount, 2 | FCEUSTATE_RLSB, "IRQC" }, + { &IRQa, 1 | FCEUSTATE_RLSB, "IRQA" }, { &dipswitch, 1, "DPSW" }, { &preg, 4, "REG" }, { 0 } diff --git a/src/boards/359.c b/src/boards/359.c index 123e344..db65987 100644 --- a/src/boards/359.c +++ b/src/boards/359.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 negativeExponent + * 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 diff --git a/src/boards/360.c b/src/boards/360.c index 210e93b..eb61154 100644 --- a/src/boards/360.c +++ b/src/boards/360.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 negativeExponent + * 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 diff --git a/src/boards/224.c b/src/boards/364.c similarity index 58% rename from src/boards/224.c rename to src/boards/364.c index 7c885b7..b5f4a5d 100644 --- a/src/boards/224.c +++ b/src/boards/364.c @@ -1,7 +1,7 @@ -/* FCEUmm - NES/Famicom Emulator +/* FCE Ultra - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2019 Libretro Team + * 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 @@ -16,35 +16,38 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * */ -/* 2019-05-29 - Mapper 224, KT-008 - * iNES Mapper 224 is used for the 晶科泰 (Jncota) KT-008 PCB. - * It's an MMC3 clone that supports 1024 KiB of PRG-ROM through an additional - * outer bank register at $5000. - * http://wiki.nesdev.com/w/index.php/INES_Mapper_224 */ - #include "mapinc.h" #include "mmc3.h" -static void M224PW(uint32 A, uint8 V) { - setprg8(A, (V & 0x3f) | ((EXPREGS[0] << 4) & 0x40)); +static void M364CW(uint32 A, uint8 V) { + V &= (EXPREGS[0] & 0x20) ? 0x7F : 0xFF; + setchr1(A, V | ((EXPREGS[0] << 4) & 0x100)); } -static DECLFW(Mapper224Write) { +static void M364PW(uint32 A, uint8 V) { + V &= (EXPREGS[0] & 0x20) ? 0x0F : 0x1F; + setprg8(A, V | ((EXPREGS[0] >> 1) & 0x20)); +} + +static DECLFW(M364Write) { EXPREGS[0] = V; FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); } -static void M224Power(void) { +static void M364Power(void) { EXPREGS[0] = 0; GenMMC3Power(); - SetWriteHandler(0x5000, 0x5000, Mapper224Write); + SetWriteHandler(0x7000, 0x7FFF, M364Write); } -void Mapper224_Init(CartInfo *info) { - GenMMC3_Init(info, 1024, 0, 8, 0); - pwrap = M224PW; - info->Power = M224Power; +void Mapper364_Init(CartInfo *info) { + GenMMC3_Init(info, 512, 512, 8, 0); + pwrap = M364PW; + cwrap = M364CW; + info->Power = M364Power; AddExState(EXPREGS, 1, 0, "EXPR"); } diff --git a/src/boards/368.c b/src/boards/368.c new file mode 100644 index 0000000..a8abf3e --- /dev/null +++ b/src/boards/368.c @@ -0,0 +1,112 @@ +/* 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. + */ + +/* 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 IRQa; +static uint16 IRQCount; + +static const uint8 banks[8] = { 4, 3, 5, 3, 6, 3, 7, 3 }; + +static SFORMAT StateRegs[] = +{ + { &IRQCount, 2 | FCEUSTATE_RLSB, "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); +} + +static DECLFW(M368WritePRG) { + preg = V & 7; + Sync(); +} + +static DECLFW(M368WriteIRQ) { + latch = V & 0x53; + IRQa = V & 1; + if (!IRQa) { + IRQCount = 0; + X6502_IRQEnd(FCEU_IQEXT); + } +} + +static DECLFR(M368Read) { + return (latch | 0xBA); +} + +static void M368Power(void) { + preg = 0; + latch = 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); +} + +static void M368Reset(void) { + IRQa = IRQCount = 0; + Sync(); +} + +static void FP_FASTAPASS(1) M368IRQHook(int a) { + if (IRQa) { + if (IRQCount < 4096) + IRQCount += a; + else { + IRQa = 0; + X6502_IRQBegin(FCEU_IQEXT); + } + } +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper368_Init(CartInfo *info) { + info->Reset = M368Reset; + info->Power = M368Power; + MapIRQHook = M368IRQHook; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/369.c b/src/boards/369.c index a11a439..fea0379 100644 --- a/src/boards/369.c +++ b/src/boards/369.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 negativeExponent + * 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 diff --git a/src/boards/370.c b/src/boards/370.c new file mode 100644 index 0000000..297031b --- /dev/null +++ b/src/boards/370.c @@ -0,0 +1,96 @@ +/* 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 ((EXPREGS[0] & 7) == 1) { + A &= 0x1FFF; + A >>= 10; + PPUCHRBus = A; + setmirror(MI_0 + mirr[A]); + } +} + +static void M370CW(uint32 A, uint8 V) { + uint8 mask = (EXPREGS[0] & 4) ? 0x7F : 0xFF; + /* FIXME: Mario VII, mask is reversed? */ + if ((EXPREGS[0] & 7) == 6 && V & 0x80) + mask = 0xFF; + mirr[A >> 10] = V >> 7; + setchr1(A, (V & mask) | ((EXPREGS[0] & 7) << 7)); + if (((EXPREGS[0] & 7) == 1) && (PPUCHRBus == (A >> 10))) + setmirror(MI_0 + (V >> 7)); +} + +static void M370PW(uint32 A, uint8 V) { + uint8 mask = EXPREGS[0] & 0x20 ? 0x0F : 0x1F; + setprg8(A, (V & mask) | ((EXPREGS[0] & 0x38) << 1)); +} + +static void M370MW(uint8 V) { + A000B = V; + if ((EXPREGS[0] & 7) != 1) + setmirror((V & 1) ^ 1); +} + +static DECLFR(M370Read) {; + return (EXPREGS[1] << 7); +} + +static DECLFW(M370Write) { + EXPREGS[0] = (A & 0xFF); + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static void M370Reset(void) { + EXPREGS[0] = 0; + EXPREGS[1] ^= 1; + FCEU_printf("solderpad=%02x\n", EXPREGS[1]); + MMC3RegReset(); +} + +static void M370Power(void) { + EXPREGS[0] = 0; + 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); + cwrap = M370CW; + pwrap = M370PW; + mwrap = M370MW; + PPU_hook = M370PPU; + info->Power = M370Power; + info->Reset = M370Reset; + AddExState(EXPREGS, 2, 0, "EXPR"); +} diff --git a/src/boards/372.c b/src/boards/372.c index 9da9ee3..3f878b2 100644 --- a/src/boards/372.c +++ b/src/boards/372.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 negativeExponent + * 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 @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -/* added 2020-1-28 - negativeExponent */ +/* added 2020-1-28 - */ /* NES 2.0 Mapper 372 is used for a revision of the Rockman I-VI multicart (PCB ID SFC-12). * It is INES Mapper 045 but with one bit of outer bank register #2 working as a CHR-ROM/RAM switch. */ diff --git a/src/boards/375.c b/src/boards/375.c new file mode 100644 index 0000000..5004fb2 --- /dev/null +++ b/src/boards/375.c @@ -0,0 +1,121 @@ +/* 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" + +static uint8 *WRAM = NULL; +static uint32 WRAMSIZE; + +static uint16 addrlatch; +static uint8 datalatch; + +static void Sync(void) { + uint32 S = addrlatch & 1; + uint32 p = ((addrlatch >> 2) & 0x1F) + ((addrlatch & 0x100) >> 3) + ((addrlatch & 0x400) >> 4); + uint32 L = (addrlatch >> 9) & 1; + uint32 p_8000 = p; + + if ((addrlatch >> 11) & 1) + p_8000 = (p & 0x7E) | (datalatch & 7); + + if ((addrlatch >> 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); + } + } + } + + if ((addrlatch & 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(((addrlatch >> 1) & 1) ^ 1); + setchr8(0); + setprg8r(0x10, 0x6000, 0); +} + +static DECLFW(M375Write) { + if (addrlatch & 0x800) + datalatch = V; + else { + addrlatch = A; + datalatch = V; + } + Sync(); +} + +static void M375Reset(void) { + addrlatch = 0; + datalatch = 0; + Sync(); +} + +static void M375Power(void) { + addrlatch = 0; + datalatch = 0; + Sync(); + setchr8(0); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M375Write); + if (WRAMSIZE) { + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); + } +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper375_Init(CartInfo *info) { + info->Power = M375Power; + info->Reset = M375Reset; + GameStateRestore = StateRestore; + AddExState(&addrlatch, 2, 0, "ADDR"); + AddExState(&datalatch, 1, 0, "DATA"); + + WRAMSIZE = 8192; + WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); +} diff --git a/src/boards/376.c b/src/boards/376.c new file mode 100644 index 0000000..b9a1171 --- /dev/null +++ b/src/boards/376.c @@ -0,0 +1,65 @@ +/* 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 = (EXPREGS[0] &0x40? 0x080: 0x000) | (EXPREGS[1] &0x01? 0x100: 0x000); + setchr1(A, base | (V & 0x7F)); +} + +static void Mapper376PW(uint32 A, uint8 V) { + uint32 base = (EXPREGS[0] &0x07) | (EXPREGS[0] &0x40? 0x08: 0x00) | (EXPREGS[1] &0x01? 0x10: 0x00); + if (EXPREGS[0] & 0x80) { + if (EXPREGS[0] &0x20) { + if (A ==0x8000) setprg32(A, base >>1); + } else { + if (A ==0x8000 || A ==0xC000) setprg16(A, base); + } + } else + setprg8(A, (base << 1) | (V & 0x0F)); +} + +static DECLFW(Mapper376Write) { + EXPREGS[A & 1] = V; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static void Mapper376Reset(void) { + EXPREGS[0] = 0; + EXPREGS[1] = 0; + MMC3RegReset(); +} + +static void Mapper376Power(void) { + GenMMC3Power(); + SetWriteHandler(0x6000, 0x7FFF, Mapper376Write); +} + +void Mapper376_Init(CartInfo *info) { + GenMMC3_Init(info, 128, 256, 1, 0); + pwrap = Mapper376PW; + cwrap = Mapper376CW; + info->Power = Mapper376Power; + info->Reset = Mapper376Reset; + AddExState(EXPREGS, 2, 0, "EXPR"); +} diff --git a/src/boards/377.c b/src/boards/377.c new file mode 100644 index 0000000..9b0cdd9 --- /dev/null +++ b/src/boards/377.c @@ -0,0 +1,64 @@ +/* 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. + */ + +/* NES 2.0 Mapper 377 - NES 2.0 Mapper 377 is used for the + * 1998 Super Game 8-in-1 (JY-111) pirate multicart. It works similarly to Mapper 267 except it has an outer 256KiB PRG-ROM bank. + */ + +#include "mapinc.h" +#include "mmc3.h" + +#define OUTER_BANK (((EXPREGS[0] & 0x20) >> 2) | (EXPREGS[0] & 0x06)) + +static void M377CW(uint32 A, uint8 V) { + setchr1(A, (V & 0x7F) | (OUTER_BANK << 6)); +} + +static void M377PW(uint32 A, uint8 V) { + setprg8(A, (V & 0x0F) | (OUTER_BANK << 3)); +} + +static DECLFW(M377Write) { + if (!(EXPREGS[0] & 0x80)) { + EXPREGS[0] = V; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + } +} + +static void M377Reset(void) { + EXPREGS[0] = 0; + MMC3RegReset(); +} + +static void M377Power(void) { + EXPREGS[0] = 0; + GenMMC3Power(); + SetWriteHandler(0x6000, 0x7FFF, M377Write); +} + +void Mapper377_Init(CartInfo *info) { + GenMMC3_Init(info, 128, 128, 0, 0); + cwrap = M377CW; + pwrap = M377PW; + info->Reset = M377Reset; + info->Power = M377Power; + AddExState(EXPREGS, 1, 0, "EXPR"); +} diff --git a/src/boards/380.c b/src/boards/380.c index a6bf1be..912e266 100644 --- a/src/boards/380.c +++ b/src/boards/380.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 negativeExponent + * 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 @@ -25,6 +25,7 @@ static uint16 latche; static uint8 dipswitch; +static uint8 isKN35A; static SFORMAT StateRegs[] = { { &latche, 2 | FCEUSTATE_RLSB, "LATC" }, @@ -47,14 +48,14 @@ static void Sync(void) else /* UxROM */ { setprg16(0x8000, latche >> 2); - setprg16(0xC000, (latche >> 2) | 7); + setprg16(0xC000, (latche >> 2) | 7 | (isKN35A && latche &0x100? 8: 0)); } setmirror(((latche >> 1) & 1) ^ 1); } static DECLFR(M380Read) { - if (latche & 0x100) + if (latche & 0x100 && !isKN35A) return dipswitch; return CartBR(A); } @@ -89,6 +90,7 @@ static void StateRestore(int version) void Mapper380_Init(CartInfo *info) { + isKN35A = info->iNES2 && info->submapper == 1; info->Power = M380Power; info->Reset = M380Reset; GameStateRestore = StateRestore; diff --git a/src/boards/382.c b/src/boards/382.c index 87e36bc..0372f92 100644 --- a/src/boards/382.c +++ b/src/boards/382.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 negativeExponent + * 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 diff --git a/src/boards/383.c b/src/boards/383.c new file mode 100644 index 0000000..ade8b07 --- /dev/null +++ b/src/boards/383.c @@ -0,0 +1,108 @@ +/* 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 EXPREGS[0] +#define A16 EXPREGS[1] +#define A17A18 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 =DRegBuf[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) { + EXPREGS[0] = 0; + EXPREGS[1] = 0; + 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); + pwrap = M383PRGWrap; + cwrap = M383CHRWrap; + info->Power = M383Power; + info->Reset = M383Reset; + AddExState(EXPREGS, 3, 0, "EXPR"); +} diff --git a/src/boards/389.c b/src/boards/389.c index b90beae..b1dbfd0 100644 --- a/src/boards/389.c +++ b/src/boards/389.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 negativeExponent + * 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 diff --git a/src/boards/390.c b/src/boards/390.c index 0e1e4ba..9d2a953 100644 --- a/src/boards/390.c +++ b/src/boards/390.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 negativeExponent + * 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 diff --git a/src/boards/391.c b/src/boards/391.c new file mode 100644 index 0000000..da66b3e --- /dev/null +++ b/src/boards/391.c @@ -0,0 +1,71 @@ +/* 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) { + int prgAND =EXPREGS[0] &0x08? 0x0F: 0x1F; + int prgOR =EXPREGS[0] <<4 &0x30; + if (EXPREGS[0] &0x20) { + if (~A &0x4000) { + setprg8(A, (EXPREGS[0] &0x04? ~2: ~0) &V &prgAND | prgOR &~prgAND); + setprg8(A |0x4000, (EXPREGS[0] &0x04? 2: 0) |V &prgAND | prgOR &~prgAND); + } + } else + setprg8(A, V &prgAND | prgOR &~prgAND); +} + +static void Mapper391_CHRWrap(uint32 A, uint8 V) { + int chrAND =EXPREGS[0] &0x40? 0x7F: 0xFF; + int chrOR =EXPREGS[0] <<3 &0x80 | EXPREGS[1] <<8 &0x100; + setchr1(A, V &chrAND | chrOR &~chrAND); +} + +static DECLFW(Mapper391_Write) { + if (~EXPREGS[0] &0x80) { + EXPREGS[0] =V; + EXPREGS[1] =A >>8 &0xFF; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + } +} + +static void Mapper391_Reset(void) { + EXPREGS[0] =EXPREGS[1] =0; + MMC3RegReset(); +} + +static void Mapper391_Power(void) { + EXPREGS[0] =EXPREGS[1] =0; + GenMMC3Power(); + SetWriteHandler(0x6000, 0x7FFF, Mapper391_Write); +} + +void Mapper391_Init(CartInfo *info) { + GenMMC3_Init(info, 256, 256, 0, 0); + cwrap = Mapper391_CHRWrap; + pwrap = Mapper391_PRGWrap; + info->Power = Mapper391_Power; + info->Reset = Mapper391_Reset; + AddExState(EXPREGS, 2, 0, "EXPR"); +} diff --git a/src/boards/393.c b/src/boards/393.c new file mode 100644 index 0000000..5315cce --- /dev/null +++ b/src/boards/393.c @@ -0,0 +1,111 @@ +/* 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 + * + * + */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 *CHRRAM; +static uint32 CHRRAMSIZE; + +static int getPRGBank(int bank) { + if ((~bank & 1) && (MMC3_cmd & 0x40)) bank ^= 2; + return (bank & 2) ? 0xFE | (bank & 1) : DRegBuf[6 | (bank & 1)]; +} + +static void M393CW(uint32 A, uint8 V) { + if (EXPREGS[0] & 8) + setchr8r(0x10, 0); + else + setchr1(A, V & 0xFF | EXPREGS[0] << 8); +} + +static void M393PW(uint32 A, uint8 V) { + switch ((EXPREGS[0] >> 4) & 3) { + case 0: + case 1: + setprg8(A, (V & 0x0F) | (EXPREGS[0] << 4)); + break; + case 2: + setprg32(0x8000, ((getPRGBank(0) >> 2) & 3) | (EXPREGS[0] << 2)); + break; + case 3: + setprg16(0x8000, (EXPREGS[0] << 3) | (EXPREGS[1] &7)); + setprg16(0xC000, (EXPREGS[0] << 3) | 7); + break; + } +} + +static DECLFW(M393Write8) { + switch (A & 0xE000) { + case 0x8000: + case 0xA000: + MMC3_CMDWrite(A, V); + break; + case 0xC000: + case 0xE000: + MMC3_IRQWrite(A, V); + break; + } + + EXPREGS[1] = V; + FixMMC3CHR(MMC3_cmd); + FixMMC3PRG(MMC3_cmd); +} + +static DECLFW(M393Write6) { + EXPREGS[0] = A & 0xFF; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static void M393Power(void) { + EXPREGS[0] = EXPREGS[1] = 0; + GenMMC3Power(); + SetWriteHandler(0x6000, 0x7FFF, M393Write6); + SetWriteHandler(0x8000, 0xFFFF, M393Write8); +} + +static void M393Reset(void) { + EXPREGS[0] = EXPREGS[1] = 0; + MMC3RegReset(); +} + +static void M393lose(void) { + GenMMC3Close(); + if (CHRRAM) + FCEU_free(CHRRAM); + CHRRAM = NULL; +} + +void Mapper393_Init(CartInfo *info) { + GenMMC3_Init(info, 1024, 512, 8, 0); + pwrap = M393PW; + cwrap = M393CW; + info->Power = M393Power; + info->Reset = M393Reset; + info->Close = M393lose; + CHRRAMSIZE = 8192; + CHRRAM = (uint8 *)FCEU_gmalloc(CHRRAMSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); + AddExState(EXPREGS, 2, 0, "EXPR"); +} diff --git a/src/boards/395.c b/src/boards/395.c new file mode 100644 index 0000000..949b099 --- /dev/null +++ b/src/boards/395.c @@ -0,0 +1,67 @@ +/* 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 395 - Realtec 8210 + * Super Card 12-in-1 (SPC002) + * Super Card 13-in-1 (SPC003) + * Super Card 14-in-1 (King006) + * Super Card 14-in-1 (King007) + */ + +#include "mapinc.h" +#include "mmc3.h" + +static void M395CW(uint32 A, uint8 V) { + uint8 mask = EXPREGS[1] & 0x40 ? 0x7F : 0xFF; + setchr1(A, (V & mask) | ((EXPREGS[1] & 0x10) << 3) | ((EXPREGS[0] & 0x30) << 4) | ((EXPREGS[1] & 0x20) << 5)); +} + +static void M395PW(uint32 A, uint8 V) { + uint8 mask = EXPREGS[1] & 8 ? 0x0F : 0x1F; + setprg8(A, (V & mask) | ((EXPREGS[0] & 0x30) << 1) | ((EXPREGS[0] & 8) << 4) | ((EXPREGS[1] & 1) << 4)); +} + +static DECLFW(M395Write) { + if (!(EXPREGS[1] & 0x80)) { + EXPREGS[(A >> 4) & 1] = V; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + } +} + +static void M395Reset(void) { + EXPREGS[0] = EXPREGS[1] = 0; + MMC3RegReset(); +} + +static void M395Power(void) { + EXPREGS[0] = EXPREGS[1] = 0; + GenMMC3Power(); + SetWriteHandler(0x6000, 0x7FFF, M395Write); +} + +void Mapper395_Init(CartInfo *info) { + GenMMC3_Init(info, 256, 256, 0, 0); + cwrap = M395CW; + pwrap = M395PW; + info->Power = M395Power; + info->Reset = M395Reset; + AddExState(EXPREGS, 2, 0, "EXPR"); +} diff --git a/src/boards/396.c b/src/boards/396.c new file mode 100644 index 0000000..a31aee1 --- /dev/null +++ b/src/boards/396.c @@ -0,0 +1,73 @@ +/* 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 + * + * NES 2.0 Mapper 396 - BMC-830752C + * 1995 Super 8-in-1 (JY-050 rev0) + * Super 8-in-1 Gold Card Series (JY-085) + * Super 8-in-1 Gold Card Series (JY-086) + * 2-in-1 (GN-51) + */ + +#include "mapinc.h" + +static uint8 reg[2]; + +static void Sync (void) { + setprg16(0x8000, reg[1] << 3 | reg[0] & 7); + setprg16(0xC000, reg[1] << 3 | 7); + setchr8(0); + setmirror(reg[1] & 0x60 ? 0 : 1); +} + +static DECLFW(M396WriteInnerBank) { + reg[0] = V; + Sync(); +} + +static DECLFW(M396WriteOuterBank) { + reg[1] = V; + Sync(); +} + +static void M396Reset(void) { + reg[0] = 0x00; + reg[1] = 0x00; + Sync(); +} + +static void StateRestore(int version) { + Sync(); +} + +static void M396Power(void) { + reg[0] = 0x00; + reg[1] = 0x00; + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0x9FFF, M396WriteInnerBank); + SetWriteHandler(0xA000, 0xBFFF, M396WriteOuterBank); + SetWriteHandler(0xC000, 0xFFFF, M396WriteInnerBank); +} + +void Mapper396_Init(CartInfo *info) { + info->Power = M396Power; + info->Reset = M396Reset; + GameStateRestore = StateRestore; + AddExState(reg, 2, 0, "REGS"); +} diff --git a/src/boards/40.c b/src/boards/40.c index 80d1ad0..e64c16d 100644 --- a/src/boards/40.c +++ b/src/boards/40.c @@ -2,6 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2012 CaH4e3 + * 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 @@ -23,7 +24,8 @@ #include "mapinc.h" -static uint8 reg; +static uint8 submapper; +static uint8 reg, outer; static uint32 IRQCount, IRQa; static SFORMAT StateRegs[] = @@ -31,34 +33,51 @@ static SFORMAT StateRegs[] = { &IRQCount, 4, "IRQC" }, { &IRQa, 4, "IRQA" }, { ®, 1, "REG" }, + { ®, 1, "OUTE" }, { 0 } }; static void Sync(void) { - setprg8(0x6000, ~1); - setprg8(0x8000, ~3); - setprg8(0xa000, ~2); - setprg8(0xc000, reg); - setprg8(0xe000, ~0); - setchr8(0); + if (outer &0x08) { + if (outer &0x10) + setprg32(0x8000, 2 | outer >>6); + else { + setprg16(0x8000, 4 | outer >>5); + setprg16(0xC000, 4 | outer >>5); + } + } else { + setprg8(0x6000, 6); + setprg8(0x8000, 4); + setprg8(0xa000, 5); + setprg8(0xc000, reg &7); + setprg8(0xe000, 7); + } + setchr8(outer >>1); + setmirror(outer &1? MI_H: MI_V); } 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 =A &0xFF; Sync(); } break; case 0xe000: reg = V & 7; Sync(); break; } } static void M40Power(void) { reg = 0; + outer = 0; + IRQa = 0; + X6502_IRQEnd(FCEU_IQEXT); Sync(); SetReadHandler(0x6000, 0xffff, CartBR); SetWriteHandler(0x8000, 0xffff, M40Write); } static void M40Reset(void) { + outer = 0; + Sync(); } static void FP_FASTAPASS(1) M40IRQHook(int a) { @@ -77,6 +96,7 @@ static void StateRestore(int version) { } void Mapper40_Init(CartInfo *info) { + submapper =info->submapper; info->Reset = M40Reset; info->Power = M40Power; MapIRQHook = M40IRQHook; diff --git a/src/boards/401.c b/src/boards/401.c new file mode 100644 index 0000000..940aa4f --- /dev/null +++ b/src/boards/401.c @@ -0,0 +1,96 @@ +/* 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 >> (~EXPREGS[2] & 0xF)); + uint32 bank = (EXPREGS[0] | ((EXPREGS[2] << 4) & 0xF00)); + setchr1(A, (V & mask) | bank); +} + +static void M401PW(uint32 A, uint8 V) { + if ((dipswitch & 1) && (EXPREGS[1] & 0x80)) { + /* openbus */ + } else { + uint32 mask = (~EXPREGS[3] & 0x1F); + uint32 bank = (EXPREGS[1] & 0x1F) | (EXPREGS[2] & 0x80) | + ((dipswitch & 2) ? (EXPREGS[2] & 0x20) : ((EXPREGS[1] >> 1) & 0x20)) | + ((dipswitch & 4) ? (EXPREGS[2] & 0x40) : ((EXPREGS[1] << 1) & 0x40)); + setprg8(A, (V & mask) | bank); + } +} + +static DECLFR(M401Read) { + if ((dipswitch & 1) && (EXPREGS[1] & 0x80)) + return X.DB; + return CartBR(A); +} + +static DECLFW(M401Write) { + /* FCEU_printf("Wr A:%04x V:%02x index:%d\n", A, V, EXPREGS[4]); */ + if (!(EXPREGS[3] & 0x40)) { + EXPREGS[EXPREGS[4]] = V; + EXPREGS[4] = (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); + EXPREGS[0] = 0x00; + EXPREGS[1] = 0x00; + EXPREGS[2] = 0x0F; + EXPREGS[3] = 0x00; + EXPREGS[4] = 0x00; + MMC3RegReset(); +} + +static void M401Power(void) { + dipswitch = 7; + EXPREGS[0] = 0x00; + EXPREGS[1] = 0x00; + EXPREGS[2] = 0x0F; + EXPREGS[3] = 0x00; + EXPREGS[4] = 0x00; + GenMMC3Power(); + SetReadHandler(0x8000, 0xFFFF, M401Read); + SetWriteHandler(0x6000, 0x7FFF, M401Write); +} + +void Mapper401_Init(CartInfo *info) { + GenMMC3_Init(info, 256, 256, 8, 0); + cwrap = M401CW; + pwrap = M401PW; + info->Power = M401Power; + info->Reset = M401Reset; + AddExState(EXPREGS, 5, 0, "EXPR"); + AddExState(&dipswitch, 1, 0, "DPSW"); +} diff --git a/src/boards/403.c b/src/boards/403.c new file mode 100644 index 0000000..11dfa5c --- /dev/null +++ b/src/boards/403.c @@ -0,0 +1,82 @@ +/* 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. + */ + +/* NES 2.0 Mapper 403 denotes the 89433 circuit board with up to 1 MiB PRG-ROM and 32 KiB of CHR-RAM, bankable with 8 KiB granularity. + * + * Tetris Family - 玩家 19-in-1 智瑟實典 (NO-1683) + * Sachen Superpack (versions A-C) + */ + +#include "mapinc.h" + +static uint8 reg[3]; + +static void Sync(void) { + uint8 prg = reg[0]; + uint8 chr = reg[1]; + uint8 mode = reg[2]; + + /* 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 DECLFW(M403Write4) { + reg[A & 3] = V; + Sync(); +} + +static DECLFW(M403Write8) { + if (reg[2] & 4) { + reg[1] = V; + Sync(); + } +} + +static void M403Reset(void) { + reg[0] = reg[1] = reg[2] = 0; + Sync(); +} + +static void M403Power(void) { + reg[0] = reg[1] = reg[2] = 0; + Sync(); + SetReadHandler(0x6000, 0x7FFF, CartBR); /* For TetrisA (Tetris Family 19-in-1 NO 1683) */ + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x4100, 0x4103, M403Write4); + SetWriteHandler(0x8000, 0xFFFF, M403Write8); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper403_Init(CartInfo *info) { + info->Reset = M403Reset; + info->Power = M403Power; + GameStateRestore = StateRestore; + AddExState(®, 3, 0, "REGS"); +} diff --git a/src/boards/410.c b/src/boards/410.c new file mode 100644 index 0000000..1484e59 --- /dev/null +++ b/src/boards/410.c @@ -0,0 +1,89 @@ +/* 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 + */ + +/* NES 2.0 Mapper 410 is a variant of mapper 45 where the + * ASIC's PRG A21/CHR A20 output (set by bit 6 of the third write to $6000) + * selects between regularly-banked CHR-ROM (=0) and 8 KiB of unbanked CHR-RAM (=1). + * It is used solely for the Super 8-in-1 - 98格鬥天王+熱血 (JY-302) multicart. + */ + +#include "mapinc.h" +#include "mmc3.h" + +static uint8 *CHRRAM; + +static void M410CW(uint32 A, uint8 V) { + if (!(EXPREGS[2] & 0x40)) { + uint32 NV = V; + NV &= (1 << ((EXPREGS[2] & 7) + 1)) - 1; + NV |= EXPREGS[0] | ((EXPREGS[2] & 0xF0) << 4); + setchr1(A, NV); + } else + setchr8r(0x10, 0); +} + +static void M410PW(uint32 A, uint8 V) { + uint32 MV = V & ((EXPREGS[3] & 0x3F) ^ 0x3F); + MV |= EXPREGS[1]; + MV |= ((EXPREGS[2] & 0x40) << 2); + setprg8(A, MV); +/* FCEU_printf("1:%02x 2:%02x 3:%02x A=%04x V=%03x\n",EXPREGS[1],EXPREGS[2],EXPREGS[3],A,MV); */ +} + +static DECLFW(M410Write) { + EXPREGS[EXPREGS[4]] = V; + EXPREGS[4] = (EXPREGS[4] + 1) & 3; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static void M410Close(void) { + GenMMC3Close(); + if (CHRRAM) + FCEU_free(CHRRAM); + CHRRAM = NULL; +} + +static void M410Reset(void) { + EXPREGS[0] = EXPREGS[1] = EXPREGS[3] = EXPREGS[4] = 0; + EXPREGS[2] = 0x0F; + MMC3RegReset(); +} + +static void M410Power(void) { + GenMMC3Power(); + EXPREGS[0] = EXPREGS[1] = EXPREGS[3] = EXPREGS[4] = 0; + EXPREGS[2] = 0x0F; + SetWriteHandler(0x6000, 0x7FFF, M410Write); +} + +void Mapper410_Init(CartInfo *info) { + GenMMC3_Init(info, 512, 256, 8, info->battery); + cwrap = M410CW; + pwrap = M410PW; + info->Reset = M410Reset; + info->Power = M410Power; + info->Close = M410Close; + AddExState(EXPREGS, 5, 0, "EXPR"); + + CHRRAM = (uint8*)FCEU_gmalloc(8192); + SetupCartCHRMapping(0x10, CHRRAM, 8192, 1); + AddExState(CHRRAM, 8192, 0, "CRAM"); +} \ No newline at end of file diff --git a/src/boards/411.c b/src/boards/411.c new file mode 100644 index 0000000..db87fb0 --- /dev/null +++ b/src/boards/411.c @@ -0,0 +1,85 @@ +/* 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 411 - A88S-1 + * 1997 Super 7-in-1 (JY-201) + * 1997 Super 6-in-1 (JY-202) + * 1997 Super 7-in-1 (JY-203) + * 1997 龍珠武鬥會 7-in-1 (JY-204) + * 1997 Super 7-in-1 (JY-205) + * 1997 Super 7-in-1 (JY-206) + */ + +#include "mapinc.h" +#include "mmc3.h" + +static void M411CW(uint32 A, uint8 V) { + uint32 mask = (EXPREGS[1] & 2) ? 0xFF : 0x7F; + V &= mask; + setchr1(A, V | ((EXPREGS[1] << 5) & 0x80) | ((EXPREGS[0] << 4) & 0x100)); +} + +static void M411PW(uint32 A, uint8 V) { + /* NROM Mode */ + if (EXPREGS[0] & 0x40) + { + uint32 bank = (EXPREGS[0] & 1) | ((EXPREGS[0] >> 2) & 2) | (EXPREGS[0] & 4) | (EXPREGS[1] & 8) | ((EXPREGS[1] >> 2) & 0x10); + + /* NROM-256 */ + if (EXPREGS[0] & 0x02) { + setprg32(0x8000, bank >> 1); + + /* NROM-128 */ + } else { + setprg16(0x8000, bank); + setprg16(0xC000, bank); + } + } + + /* MMC3 Mode */ + else + { + uint32 mask = (EXPREGS[1] & 2) ? 0x1F : 0x0F; + V &= mask; + setprg8(A, V | ((EXPREGS[1] << 1) & 0x10) | ((EXPREGS[1] >> 1) & 0x20)); + } +} + +static DECLFW(M411Write5000) { + EXPREGS[A & 1] = V; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static void M411Power(void) { + EXPREGS[0] = 0x80; + EXPREGS[1] = 0x82; + GenMMC3Power(); + SetWriteHandler(0x5000, 0x5FFF, M411Write5000); +} + +void Mapper411_Init(CartInfo *info) { + GenMMC3_Init(info, 256, 256, 0, 0); + pwrap = M411PW; + cwrap = M411CW; + info->Power = M411Power; + AddExState(EXPREGS, 2, 0, "EXPR"); +} diff --git a/src/boards/414.c b/src/boards/414.c new file mode 100644 index 0000000..f8c4380 --- /dev/null +++ b/src/boards/414.c @@ -0,0 +1,64 @@ +/* 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" + +static uint8 latch_data; +static uint32 latch_addr; + +static SFORMAT StateRegs[] = +{ + { &latch_addr, 4, "ADDR" }, + { &latch_data, 1, "DATA" }, + { 0 } +}; + +static void Sync(void) { + if (latch_addr & 0x2000) { /* NROM-256 */ + setprg32(0x8000, latch_addr >> 2); + } else { /* NROM-128 */ + setprg16(0x8000, latch_addr >> 1); + setprg16(0xC000, latch_addr >> 1); + } + setchr8(latch_data); + setmirror((latch_addr & 1) ^ 1); +} + +static DECLFW(M414Write) { + latch_addr = A; + latch_data = V & CartBR(A); + Sync(); +} + +static void M414Power(void) { + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M414Write); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper414_Init(CartInfo *info) { + info->Power = M414Power; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/416.c b/src/boards/416.c new file mode 100644 index 0000000..8c04152 --- /dev/null +++ b/src/boards/416.c @@ -0,0 +1,111 @@ +/* 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" + +static uint8 reg; +static uint8 smb2j_reg; +static uint8 IRQa; +static uint16 IRQCount; + +static void Sync(void) { + if (reg & 8) { + uint8 prg = ((reg >> 5) & 1) | ((reg >> 6) & 2) | ((reg >> 1) & 4); + switch ((reg >> 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((reg >> 1) & 3); + setmirror(((reg >> 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 DECLFW(M416Write8) { + reg = V; + Sync(); +} + +static void M416Power(void) { + reg = smb2j_reg = IRQa = IRQCount = 0; + Sync(); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x4020, 0x5FFF, M416Write4); + SetWriteHandler(0x8000, 0x8000, M416Write8); +} + +static void FP_FASTAPASS(1) M416IRQHook(int a) { + if (IRQa) { + if (IRQCount < 4096) + IRQCount += a; + else { + IRQa = 0; + X6502_IRQBegin(FCEU_IQEXT); + } + } +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper416_Init(CartInfo *info) { + info->Power = M416Power; + MapIRQHook = M416IRQHook; + GameStateRestore = StateRestore; + AddExState(®, 1, 0, "REGS"); + AddExState(&smb2j_reg, 1, 0, "SMBJ"); + AddExState(&IRQa, 1, 0, "IRQa"); + AddExState(&IRQCount, 2, 0, "IRQC"); +} diff --git a/src/boards/417.c b/src/boards/417.c new file mode 100644 index 0000000..3af3afc --- /dev/null +++ b/src/boards/417.c @@ -0,0 +1,80 @@ +/* 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" + +static uint8 preg[4]; +static uint8 creg[8]; +static uint8 nt[4]; +static uint8 IRQa; +static uint16 IRQCount; + +static SFORMAT StateRegs[] = { + { preg, 4, "PREG" }, + { creg, 8, "CREG" }, + { nt, 4, "NREG" }, + { &IRQa, 1, "IRQA" }, + { &IRQCount, 2, "IRQC" }, + { 0 } +}; + +static void Sync(void) { + int i; + 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]); + setmirrorw(nt[0] & 1, nt[1] & 1, nt[2] & 1, nt[3] & 1); +} + +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; + } +} + +static void M417Power(void) { + Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, M417Write); +} + +static void M417IRQHook(int a) { + IRQCount += a; + if (IRQa && IRQCount > 1024) + X6502_IRQBegin(FCEU_IQEXT); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper417_Init(CartInfo *info) { + info->Power = M417Power; + MapIRQHook = M417IRQHook; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/AbG1l.c b/src/boards/428.c similarity index 54% rename from src/boards/AbG1l.c rename to src/boards/428.c index 7305336..06f18f7 100644 --- a/src/boards/AbG1l.c +++ b/src/boards/428.c @@ -25,7 +25,6 @@ static uint8 regs[4]; static uint8 hrd_flag; -static void(*Sync)(void); static SFORMAT StateRegs[] = { @@ -34,7 +33,8 @@ static SFORMAT StateRegs[] = { 0 } }; -static void SyncAbG1l(void) { +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 latch register at $8000-$FFFF. */ if (regs[1] & 0x10) setprg32(0x8000,(regs[1] & 0xC0) >> 6); @@ -44,37 +44,36 @@ static void SyncAbG1l(void) { setprg16(0xC000, (regs[1] & 0xE0) >> 5); } - setchr8(regs[1]); + setchr8(((regs[1] & 0x07) & ~mask) | regs[0] & mask); + setmirror((regs[1] & 0x8) ? 0 : 1); - } -static DECLFW(AbG1lWriteHi) { +static DECLFW(WriteHi) { regs[0] = V; - setchr8(((regs[2] & 0xC0) >> 7) << 2 | (regs[0] & 0x03)); Sync(); } -static DECLFW(AbG1lWriteLo) { +static DECLFW(WriteLo) { regs[A & 0x03] = V; Sync(); } -static DECLFR(AbG1lReadLo) { +static DECLFR(ReadLo) { return hrd_flag; } -static void AbG1lPower(void) { - hrd_flag = 0; +static void Power(void) { + hrd_flag = 0; /* Solder pad, selecting different menus */ regs[0] = 0; regs[1] = 0; regs[2] = 0; Sync(); - SetWriteHandler(0x8000, 0xFFFF, AbG1lWriteHi); - SetWriteHandler(0x6001, 0x6002, AbG1lWriteLo); - SetReadHandler(0x6000, 0x7FFF, AbG1lReadLo); + SetWriteHandler(0x8000, 0xFFFF, WriteHi); + SetWriteHandler(0x6001, 0x6002, WriteLo); + SetReadHandler(0x6000, 0x7FFF, ReadLo); SetReadHandler(0x8000, 0xFFFF, CartBR); } @@ -82,7 +81,7 @@ static void StateRestore(int version) { Sync(); } -static void AbG1lReset(void) { +static void Reset(void) { hrd_flag++; hrd_flag &= 3; @@ -93,64 +92,14 @@ static void AbG1lReset(void) { Sync(); } -void AbG1l_Init(CartInfo *info) { - - Sync = SyncAbG1l; - +void Mapper428_Init(CartInfo *info) { hrd_flag = 0; Sync(); - info->Power = AbG1lPower; - info->Reset = AbG1lReset; + info->Power = Power; + info->Reset = Reset; AddExState(&StateRegs, ~0, 0, 0); GameStateRestore = StateRestore; } - -static void SyncWellNoDG450(void) { - - if (regs[1] & 0x10) - setprg32(0x8000, (regs[1]) >> 6); - else - { - setprg16(0x8000, (regs[1]) >> 5); - setprg16(0xC000, (regs[1]) >> 5); - } - - setchr8(regs[1] & 0x0F); - setmirror((regs[1] & 0x8) ? 0 : 1); -} - -static void WellNoDG450Power(void) { - hrd_flag = 0; - - regs[0] = 0; - regs[1] = 0; - regs[2] = 0; - - Sync(); - - SetWriteHandler(0x6001, 0x6002, AbG1lWriteLo); - SetReadHandler(0x6000, 0x7FFF, AbG1lReadLo); - SetReadHandler(0x8000, 0xFFFF, CartBR); -} - -static void WellNoDG450Reset(void) { - hrd_flag++; - hrd_flag &= 3; - - regs[0] = 0; - regs[1] = 0; - regs[2] = 0; - - Sync(); -} - -void WellNoDG450_Init(CartInfo *info) { - Sync = SyncWellNoDG450; - info->Power = WellNoDG450Power; - info->Reset = WellNoDG450Reset; - AddExState(&StateRegs, ~0, 0, 0); - GameStateRestore = StateRestore; -} diff --git a/src/boards/gs-2004.c b/src/boards/431.c similarity index 64% rename from src/boards/gs-2004.c rename to src/boards/431.c index fd964e5..afc9ef9 100644 --- a/src/boards/gs-2004.c +++ b/src/boards/431.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) 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 @@ -20,44 +20,43 @@ #include "mapinc.h" -static uint8 reg, mirr; +static uint8 inner_bank; +static uint8 outer_bank; + static SFORMAT StateRegs[] = { - { ®, 1, "REGS" }, - { &mirr, 1, "MIRR" }, + { &outer_bank, 1, "OUTB" }, + { &inner_bank, 1, "INNB" }, { 0 } }; static void Sync(void) { - setprg8(0x6000, 32); - setprg32(0x8000, reg); + setprg16(0x8000, ((outer_bank >> 2) & ~7) | (inner_bank & 7)); + setprg16(0xC000, ((outer_bank >> 2) & ~7) | 7); setchr8(0); + setmirror((outer_bank & 1) ^ 1); } -static DECLFW(BMCGS2004Write) { - reg = V; +static DECLFW(M431Write) { + if (A < 0xC000) outer_bank = V; + else inner_bank = V; Sync(); } -static void BMCGS2004Power(void) { - reg = 0x07; +static void M431Power(void) { + inner_bank = 0; + outer_bank = 0; Sync(); - SetReadHandler(0x6000, 0x7FFF, CartBR); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, BMCGS2004Write); -} - -static void BMCGS2004Reset(void) { - reg = 0x07; + SetWriteHandler(0x8000, 0xFFFF, M431Write); } static void StateRestore(int version) { Sync(); } -void BMCGS2004_Init(CartInfo *info) { - info->Reset = BMCGS2004Reset; - info->Power = BMCGS2004Power; +void Mapper431_Init(CartInfo *info) { + info->Power = M431Power; GameStateRestore = StateRestore; AddExState(&StateRegs, ~0, 0, 0); } diff --git a/src/boards/432.c b/src/boards/432.c new file mode 100644 index 0000000..eba55d0 --- /dev/null +++ b/src/boards/432.c @@ -0,0 +1,75 @@ +/* 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 = (EXPREGS[1] & 0x04) ? 0x7F : 0xFF; + int chrOR = (EXPREGS[1] << 7) & 0x080 | (EXPREGS[1] << 5) & 0x100 | (EXPREGS[1] << 4) & 0x200; + setchr1(A, (V & chrAND) | (chrOR & ~chrAND)); +} + +static void M432PW(uint32 A, uint8 V) { + int prgAND = (EXPREGS[1] & 0x02) ? 0x0F : 0x1F; + int prgOR = ((EXPREGS[1] << 4) & 0x10) | (EXPREGS[1] << 1) & 0x60; + if ((A < 0xC000) || (~EXPREGS[1] & 0x40)) setprg8(A, (V & prgAND) | (prgOR & ~prgAND) & (EXPREGS[1] & 0x80?~2:~0)); + if ((A < 0xC000) && (EXPREGS[1] & 0x40)) setprg8(A | 0x4000, (V & prgAND) | (prgOR & ~prgAND) | (EXPREGS[1] & 0x80? 2: 0)); +} + +static DECLFR(M432Read) { + if (EXPREGS[0] & 1 || EXPREGS[1] & 0x20 && ROM_size <64) + return EXPREGS[2]; + return CartBR(A); +} + +static DECLFW(M432Write) { + EXPREGS[A & 1] = V; + if (~A &1 && ~V &1 && ROM_size <64) EXPREGS[1] &=~0x20; /* Writing 0 to register 0 clears register 1's DIP bit */ + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static void M432Reset(void) { + EXPREGS[0] = 0; + EXPREGS[1] = 0; + EXPREGS[2]++; + MMC3RegReset(); +} + +static void M432Power(void) { + EXPREGS[0] = 0; + EXPREGS[1] = 0; + EXPREGS[2] = 0; + GenMMC3Power(); + SetReadHandler(0x8000, 0xFFFF, M432Read); + SetWriteHandler(0x6000, 0x7FFF, M432Write); +} + +void Mapper432_Init(CartInfo *info) { + GenMMC3_Init(info, 256, 256, 0, 0); + cwrap = M432CW; + pwrap = M432PW; + info->Power = M432Power; + info->Reset = M432Reset; + AddExState(EXPREGS, 3, 0, "EXPR"); +} diff --git a/src/boards/433.c b/src/boards/433.c new file mode 100644 index 0000000..07dba88 --- /dev/null +++ b/src/boards/433.c @@ -0,0 +1,72 @@ +/* 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 433 denotes the NC-20MB PCB, used for the 20-in-1 (CA-006) multicart. It is almost identical to INES Mapper 433, except that mirroring is selected just by single bit 6 (1=Horizontal). + */ + +#include "mapinc.h" + +static uint8 latche; + +static SFORMAT StateRegs[] = +{ + { &latche, 1, "LATC" }, + { 0 } +}; + +static void Sync(void) { + if (!(latche & 0x20)) + setprg32(0x8000, (latche & 0x1f) >> 1); + else { + setprg16(0x8000, (latche & 0x1f)); + setprg16(0xC000, (latche & 0x1f)); + } + setmirror(((latche >> 6) & 1) ^ 1); + setchr8(0); +} + +static DECLFW(M433Write) { + latche = V; + Sync(); +} + +static void M433Power(void) { + latche = 0; + Sync(); + SetWriteHandler(0x8000, 0xFFFF, M433Write); + SetReadHandler(0x8000, 0xFFFF, CartBR); +} + +static void StateRestore(int version) { + Sync(); +} + +static void M433Reset(void) { + latche = 0; + Sync(); +} + +void Mapper433_Init(CartInfo *info) { + info->Power = M433Power; + info->Reset = M433Reset; + AddExState(&StateRegs, ~0, 0, 0); + GameStateRestore = StateRestore; +} diff --git a/src/boards/434.c b/src/boards/434.c new file mode 100644 index 0000000..cbe0b45 --- /dev/null +++ b/src/boards/434.c @@ -0,0 +1,67 @@ +/* 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 + */ + +/* S-009. UNROM plus outer bank register at $6000-$7FFF. */ + +#include "mapinc.h" + +static uint16 latch; + +static void Mapper434_Sync(void) { + setprg16(0x8000, latch); + setprg16(0xC000, latch |7); + setchr8(0); + setmirror(latch >>8 &1); +} + +static DECLFW(Mapper434_WriteOuterBank) { + latch =latch &7 | V <<3; + Mapper434_Sync(); +} + +static DECLFW(Mapper434_WriteInnerBank) { + latch =latch &~7 | V &CartBR(A) &7; + Mapper434_Sync(); +} + +static void Mapper434_Reset(void) { + latch =0; + Mapper434_Sync(); +} + +static void Mapper434_Power(void) { + latch =0; + Mapper434_Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, Mapper434_WriteOuterBank); + SetWriteHandler(0x8000, 0xFFFF, Mapper434_WriteInnerBank); +} + +static void StateRestore(int version) { + Mapper434_Sync(); +} + +void Mapper434_Init(CartInfo *info) { + info->Reset = Mapper434_Reset; + info->Power = Mapper434_Power; + GameStateRestore = StateRestore; + AddExState(&latch, 2, 0, "LATC"); +} diff --git a/src/boards/436.c b/src/boards/436.c new file mode 100644 index 0000000..b7be076 --- /dev/null +++ b/src/boards/436.c @@ -0,0 +1,63 @@ +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2008 CaH4e3 + * Copyright (C) 2019 Libretro Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 436: 820401/T-217 */ + +#include "mapinc.h" +#include "mmc3.h" + +static void Mapper436_PWrap(uint32 A, uint8 V) { + if (EXPREGS[0] &0x01) + setprg8(A, V &0x0F | EXPREGS[0] >>2 &0x30); + else + if (A == 0x8000) + setprg32(A, (EXPREGS[0] >>4)); +} + +static void Mapper436_CWrap(uint32 A, uint8 V) { + setchr1(A, V &0x7F | EXPREGS[0] <<1 &~0x7F); +} + +static DECLFW(Mapper436_Write) { + EXPREGS[0] = A &0xFF; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static void Mapper436_Reset(void) { + EXPREGS[0] = 0; + MMC3RegReset(); +} + +static void Mapper436_Power(void) { + EXPREGS[0] = 0; + GenMMC3Power(); + SetWriteHandler(0x6000, 0x7FFF, Mapper436_Write); +} + +void Mapper436_Init(CartInfo *info) { + GenMMC3_Init(info, 128, 128, 8, 0); + pwrap = Mapper436_PWrap; + cwrap = Mapper436_CWrap; + info->Power = Mapper436_Power; + info->Reset = Mapper436_Reset; + AddExState(EXPREGS, 1, 0, "EXPR"); +} diff --git a/src/boards/437.c b/src/boards/437.c new file mode 100644 index 0000000..acb4371 --- /dev/null +++ b/src/boards/437.c @@ -0,0 +1,67 @@ +/* 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 + */ + +/* NTDEC TH2348 circuit board. UNROM plus outer bank register at $5FFx. */ + +#include "mapinc.h" + +static uint8 latch; + +static void Mapper437_Sync(void) { + setprg16(0x8000, latch); + setprg16(0xC000, latch |7); + setchr8(0); + setmirror(latch >>6 &1 ^1); +} + +static DECLFW(Mapper437_WriteOuterBank) { + latch =latch &7 | A <<3; + Mapper437_Sync(); +} + +static DECLFW(Mapper437_WriteInnerBank) { + latch =latch &~7 | V &CartBR(A) &7; + Mapper437_Sync(); +} + +static void Mapper437_Reset(void) { + latch =0; + Mapper437_Sync(); +} + +static void Mapper437_Power(void) { + latch =0; + Mapper437_Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x5000, 0x5FFF, Mapper437_WriteOuterBank); + SetWriteHandler(0x8000, 0xFFFF, Mapper437_WriteInnerBank); +} + +static void StateRestore(int version) { + Mapper437_Sync(); +} + +void Mapper437_Init(CartInfo *info) { + info->Reset = Mapper437_Reset; + info->Power = Mapper437_Power; + GameStateRestore = StateRestore; + AddExState(&latch, 1, 0, "LATC"); +} diff --git a/src/boards/438.c b/src/boards/438.c new file mode 100644 index 0000000..b534fb6 --- /dev/null +++ b/src/boards/438.c @@ -0,0 +1,67 @@ +/* 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 + */ + +/* K-3071 */ + +#include "mapinc.h" + +static uint8 latch[2]; + +static void Mapper438_Sync(void) { + if (latch[0] &1) + setprg32(0x8000, latch[0] >>2); + else { + setprg16(0x8000, latch[0] >>1); + setprg16(0xC000, latch[0] >>1); + } + setchr8(latch[1] >>1); + setmirror(latch[1] &1 ^1); + +} + +static DECLFW(Mapper438_WriteLatch) { + latch[0] =A &0xFF; + latch[1] =V; + Mapper438_Sync(); +} + +static void Mapper438_Reset(void) { + latch[0] =latch[1] =0; + Mapper438_Sync(); +} + +static void Mapper438_Power(void) { + latch[0] =latch[1] =0; + Mapper438_Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, Mapper438_WriteLatch); +} + +static void StateRestore(int version) { + Mapper438_Sync(); +} + +void Mapper438_Init(CartInfo *info) { + info->Reset = Mapper438_Reset; + info->Power = Mapper438_Power; + GameStateRestore = StateRestore; + AddExState(&latch, 2, 0, "LATC"); +} diff --git a/src/boards/441.c b/src/boards/441.c new file mode 100644 index 0000000..a2ef809 --- /dev/null +++ b/src/boards/441.c @@ -0,0 +1,68 @@ +/* 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 + */ + +/* 850335C PCB */ + +#include "mapinc.h" +#include "mmc3.h" + +static void Mapper441_PRGWrap(uint32 A, uint8 V) { + int prgAND =EXPREGS[0] &0x08? 0x0F: 0x1F; + int prgOR =EXPREGS[0] <<4 &0x30; + if (EXPREGS[0] &0x04) { + if (~A &0x4000) { + setprg8(A, ~2 &V &prgAND | prgOR &~prgAND); + setprg8(A |0x4000, 2 |V &prgAND | prgOR &~prgAND); + } + } else + setprg8(A, V &prgAND | prgOR &~prgAND); +} + +static void Mapper441_CHRWrap(uint32 A, uint8 V) { + int chrAND =EXPREGS[0] &0x40? 0x7F: 0xFF; + int chrOR =EXPREGS[0] <<3 &0x180; + setchr1(A, V &chrAND | chrOR &~chrAND); +} + +static DECLFW(Mapper441_Write) { + if (~EXPREGS[0] &0x80) EXPREGS[0] =V; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static void Mapper441_Reset(void) { + EXPREGS[0] =0; + MMC3RegReset(); +} + +static void Mapper441_Power(void) { + EXPREGS[0] =0; + GenMMC3Power(); + SetWriteHandler(0x6000, 0x7FFF, Mapper441_Write); +} + +void Mapper441_Init(CartInfo *info) { + GenMMC3_Init(info, 256, 256, 0, 0); + cwrap = Mapper441_CHRWrap; + pwrap = Mapper441_PRGWrap; + info->Power = Mapper441_Power; + info->Reset = Mapper441_Reset; + AddExState(EXPREGS, 1, 0, "EXPR"); +} diff --git a/src/boards/443.c b/src/boards/443.c new file mode 100644 index 0000000..034f615 --- /dev/null +++ b/src/boards/443.c @@ -0,0 +1,79 @@ +/* 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 =EXPREGS[0] <<4 &0x20 | EXPREGS[0] &0x10; + if (EXPREGS[0] &0x04) { + if (~A &0x4000) { + setprg8(A, (~EXPREGS[0] &0x08? ~2: ~0) &V &prgAND | prgOR &~prgAND); + setprg8(A |0x4000, (~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 =EXPREGS[0] <<8; + setchr1(A, V &chrAND | chrOR &~chrAND); +} + +static DECLFR(Mapper443_Read) { + return (EXPREGS[0] &0x0C) ==0x08? dip: CartBR(A); +} + +static DECLFW(Mapper443_Write) { + EXPREGS[0] =A &0xFF; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static void Mapper443_Reset(void) { + dip++; + dip &= 15; + EXPREGS[0] =0; + MMC3RegReset(); +} + +static void Mapper443_Power(void) { + dip =0; + 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); + cwrap = Mapper443_CHRWrap; + pwrap = Mapper443_PRGWrap; + info->Power = Mapper443_Power; + info->Reset = Mapper443_Reset; + AddExState(EXPREGS, 1, 0, "EXPR"); + AddExState(&dip, 1, 0, "DIPS"); +} diff --git a/src/boards/444.c b/src/boards/444.c new file mode 100644 index 0000000..3872f56 --- /dev/null +++ b/src/boards/444.c @@ -0,0 +1,82 @@ +/* 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 && EXPREGS[0] &0x02? 0x1F: 0x0F; + int prgOR =EXPREGS[0] <<4; + if (EXPREGS[0] &0x04) { + if (~A &0x4000) { + setprg8(A, (~EXPREGS[0] &0x08? ~2: ~0) &V &prgAND | prgOR &~prgAND); + setprg8(A |0x4000, (~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 =EXPREGS[0] <<7 &(pads &1? 0x00: 0x80) | EXPREGS[0] <<(pads &2? 4: 7) &0x100; + setchr1(A, V &chrAND | chrOR &~chrAND); +} + +static DECLFR(Mapper444_Read) { + return (EXPREGS[0] &0x0C) ==0x08? dip: CartBR(A); +} + +static DECLFW(Mapper444_Write) { + EXPREGS[0] =A &0xFF; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static void Mapper444_Reset(void) { + dip++; + dip &= 3; + EXPREGS[0] =0; + MMC3RegReset(); +} + +static void Mapper444_Power(void) { + dip =0; + 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); + cwrap = Mapper444_CHRWrap; + pwrap = Mapper444_PRGWrap; + info->Power = Mapper444_Power; + info->Reset = Mapper444_Reset; + AddExState(EXPREGS, 1, 0, "EXPR"); + AddExState(&dip, 1, 0, "DIPS"); +} diff --git a/src/boards/449.c b/src/boards/449.c new file mode 100644 index 0000000..f07ebb4 --- /dev/null +++ b/src/boards/449.c @@ -0,0 +1,95 @@ +/* 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" + +static uint16 latchAddr; +static uint8 latchData; +static uint8 dipswitch; + +static SFORMAT StateRegs[] = +{ + { &latchAddr, 2, "ADDR" }, + { &latchData, 1, "DATA" }, + { &latchData, 1, "DIPS" }, + { 0 } +}; + +static void Mapper449_Sync(void) +{ + int prg =latchAddr >>2 &0x1F | latchAddr >>3 &0x20; + if (~latchAddr &0x080) + { + setprg16(0x8000, prg); + setprg16(0xC000, prg |7); + } + else + { + if (latchAddr &0x001) + { + setprg32(0x8000, prg >>1); + } + else + { + setprg16(0x8000, prg); + setprg16(0xC000, prg); + } + } + setchr8(latchData); + setmirror(latchAddr &0x002? MI_H: MI_V); +} + +static DECLFR(Mapper449_Read) +{ + if (latchAddr &0x200) + return CartBR(A | dipswitch); + else + return CartBR(A); +} + +static DECLFW(Mapper449_WriteLatch) +{ + latchData =V; + latchAddr =A &0xFFFF; + Mapper449_Sync(); +} + +static void Mapper449_Reset(void) +{ + dipswitch =(dipswitch +1) &0xF; + latchAddr =latchData =0; + Mapper449_Sync(); +} + +static void Mapper449_Power(void) +{ + dipswitch =latchAddr =latchData =0; + Mapper449_Sync(); + SetWriteHandler(0x8000, 0xFFFF, Mapper449_WriteLatch); + SetReadHandler(0x6000, 0x7FFF, CartBR); + SetReadHandler(0x8000, 0xFFFF, Mapper449_Read); +} + +void Mapper449_Init(CartInfo *info) +{ + info->Power = Mapper449_Power; + info->Reset = Mapper449_Reset; + AddExState(StateRegs, ~0, 0, 0); +} \ No newline at end of file diff --git a/src/boards/452.c b/src/boards/452.c new file mode 100644 index 0000000..bd83f51 --- /dev/null +++ b/src/boards/452.c @@ -0,0 +1,136 @@ +/* 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 + */ + +/* DS-9-27. Absolutely insane PCB that overlays 8 KiB of WRAM into a selectable position between $8000 and $E000. */ + +#include "mapinc.h" + +static uint8 *WRAM; +static uint32 WRAMSIZE; +static uint16 latch[2]; +static uint8 submapper; + +static void SetWRAM(uint16 A) { + setprg8r(0x10, A, 0); + SetWriteHandler(A, A |0x1FFF, CartBW); +} + +static DECLFW(Mapper452_WriteLatch); +static void Mapper452_Sync(void) { + SetWriteHandler(0x8000, 0xFFFF, Mapper452_WriteLatch); + if (submapper ==1) { + switch(latch[0] &0xF000) { + case 0xA000: + setprg16(0x8000, latch[0] >>1); + setprg8 (0xC000, 0); + SetWRAM(latch[0] <<4 &0x6000 |0x8000); + break; + case 0xC000: + setprg16(0x8000, latch[0] >>1 |0); + setprg16(0xC000, latch[0] >>1 |1); + SetWRAM(latch[0] <<4 &0x6000 |0x8000); + break; + case 0xD000: + setprg8(0x8000, latch[0]); + setprg8(0xA000, latch[0]); + setprg8(0xC000, latch[0]); + setprg8(0xE000, latch[0]); + SetWRAM(latch[0] <<4 &0x2000 |0x8000); + SetWRAM(latch[0] <<4 &0x2000 |0xC000); + break; + case 0xE000: + setprg16(0x8000, latch[0] >>1); + setprg16(0xC000, latch[0] &0x100? (latch[0] >>1 |7): 0); + SetWRAM(latch[0] <<4 &0x6000 |0x8000); + break; + default: + setprg16(0x8000, latch[0] >>1); + setprg16(0xC000, 0); + break; + } + setchr8(0); + setmirror(latch[0] &0x800? MI_H: MI_V); + } else { + uint8 wramBank = latch[1] >>3 &6 |8; + if (latch[1] &2) { + setprg8(0x8000, latch[0] >>1); + setprg8(0xA000, latch[0] >>1); + setprg8(0xC000, latch[0] >>1); + setprg8(0xE000, latch[0] >>1); + SetWRAM((wramBank ^4) <<12); + } else + if (latch[1] &8) { + setprg8(0x8000, latch[0] >>1 &~1 |0); + setprg8(0xA000, latch[0] >>1 &~1 |1); + setprg8(0xC000, latch[0] >>1 &~1 |2); + setprg8(0xE000, latch[0] >>1 &~1 |3 | latch[1] &4 | (latch[1] &0x04 && latch[1] &0x40? 8: 0)); + } else { + setprg16(0x8000, latch[0] >>2); + setprg16(0xC000, 0); + } + SetWRAM(wramBank <<12); + setchr8(0); + setmirror(latch [1] &1 ^1); + } +} + +static DECLFW(Mapper452_WriteLatch) { + CartBW(A, V); + latch[0] =A &0xFFFF; + latch[1] =V; + Mapper452_Sync(); +} + +static void Mapper452_Reset(void) { + latch[0] =latch[1] =0; + Mapper452_Sync(); +} + +static void Mapper452_Power(void) { + latch[0] =latch[1] =0; + SetReadHandler(0x6000, 0xFFFF, CartBR); + Mapper452_Sync(); + FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); +} + +static void Mapper452_Close(void) { + if (WRAM) + FCEU_gfree(WRAM); + WRAM = NULL; +} + +static void StateRestore(int version) { + Mapper452_Sync(); +} + +void Mapper452_Init(CartInfo *info) { + submapper =info->submapper; + info->Reset = Mapper452_Reset; + info->Power = Mapper452_Power; + info->Close = Mapper452_Close; + GameStateRestore = StateRestore; + + WRAMSIZE =8192; + WRAM =(uint8*) FCEU_gmalloc(WRAMSIZE); + SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); + AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + AddExState(&latch, 4, 0, "LATC"); +} diff --git a/src/boards/455.c b/src/boards/455.c new file mode 100644 index 0000000..55c8bdf --- /dev/null +++ b/src/boards/455.c @@ -0,0 +1,77 @@ +/* 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 + */ + +/* N625836 PCB */ + +#include "mapinc.h" +#include "mmc3.h" + +static void Mapper455_PRGWrap(uint32 A, uint8 V) { + int prgAND =EXPREGS[1] &0x01? 0x1F: 0x0F; + int prgOR =EXPREGS[0] >>2 &0x07 | EXPREGS[1] <<1 &0x08 | EXPREGS[0] >>2 &0x10; + if (EXPREGS[0] &0x01) { + if (EXPREGS[0] &0x02) { + setprg32(0x8000, prgOR >>1); + } else { + setprg16(0x8000, prgOR); + setprg16(0xC000, prgOR); + } + } else { + prgOR <<=1; + setprg8(A, V &prgAND | prgOR &~prgAND); + } +} + +static void Mapper455_CHRWrap(uint32 A, uint8 V) { + int chrAND =EXPREGS[1] &0x02? 0xFF: 0x7F; + int chrOR =(EXPREGS[0] >>2 &0x07 | EXPREGS[1] <<1 &0x08 | EXPREGS[0] >>2 &0x10) <<4; + setchr1(A, V &chrAND | chrOR &~chrAND); +} + +static DECLFW(Mapper455_Write) { + if (A &0x100) { + EXPREGS[0] =V; + EXPREGS[1] =A &0xFF; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + } +} + +static void Mapper455_Reset(void) { + EXPREGS[0] =1; + EXPREGS[1] =0; + MMC3RegReset(); +} + +static void Mapper455_Power(void) { + EXPREGS[0] =1; + EXPREGS[1] =0; + GenMMC3Power(); + SetWriteHandler(0x4100, 0x5FFF, Mapper455_Write); +} + +void Mapper455_Init(CartInfo *info) { + GenMMC3_Init(info, 256, 256, 0, 0); + cwrap = Mapper455_CHRWrap; + pwrap = Mapper455_PRGWrap; + info->Power = Mapper455_Power; + info->Reset = Mapper455_Reset; + AddExState(EXPREGS, 2, 0, "EXPR"); +} diff --git a/src/boards/456.c b/src/boards/456.c new file mode 100644 index 0000000..33bf824 --- /dev/null +++ b/src/boards/456.c @@ -0,0 +1,58 @@ +/* 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 "mmc3.h" + +static void Mapper456_PRGWrap(uint32 A, uint8 V) { + setprg8(A, V &0x0F | EXPREGS[0] <<4); +} + +static void Mapper456_CHRWrap(uint32 A, uint8 V) { + setchr1(A, V &0x7F | EXPREGS[0] <<7); +} + +static DECLFW(Mapper456_Write) { + if (A &0x100) { + EXPREGS[0] =V; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + } +} + +static void Mapper456_Reset(void) { + EXPREGS[0] =0; + MMC3RegReset(); +} + +static void Mapper456_Power(void) { + EXPREGS[0] =0; + GenMMC3Power(); + SetWriteHandler(0x4020, 0x5FFF, Mapper456_Write); +} + +void Mapper456_Init(CartInfo *info) { + GenMMC3_Init(info, 128, 128, 8, 0); + cwrap = Mapper456_CHRWrap; + pwrap = Mapper456_PRGWrap; + info->Power = Mapper456_Power; + info->Reset = Mapper456_Reset; + AddExState(EXPREGS, 1, 0, "EXPR"); +} diff --git a/src/boards/460.c b/src/boards/460.c new file mode 100644 index 0000000..0422a5c --- /dev/null +++ b/src/boards/460.c @@ -0,0 +1,94 @@ +/* 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 "mmc3.h" + +static uint8 *CHRRAM =NULL; + +static DECLFR(Mapper460_ReadOB) +{ + return X.DB; +} + +static void Mapper460_PRGWrap(uint32 A, uint8 V) { + int prgAND =0x0F; + int prgOR =EXPREGS[0] <<4; + if (EXPREGS[0] &0x20 && (EXPREGS[0] !=0x20 || ~EXPREGS[1] &1)) { /* Menu selection by selectively connecting CPU D7 to reg or not */ + if (~A &0x4000) { + setprg8(A, (EXPREGS[0] &0x10? ~2: ~0) &V &prgAND | prgOR &~prgAND); + setprg8(A |0x4000, (EXPREGS[0] &0x10? 2: 0) |V &prgAND | prgOR &~prgAND); + } + } else + setprg8(A, V &prgAND | prgOR &~prgAND); + + /* Menu selection by selectively connecting reg's D7 to PRG /CE or not */ + if (EXPREGS[0] &0x80 && EXPREGS[1] &1) + SetReadHandler(0x8000, 0xFFFF, Mapper460_ReadOB); + else + SetReadHandler(0x8000, 0xFFFF, CartBR); +} + +static void Mapper460_CHRWrap(uint32 A, uint8 V) { + if (EXPREGS[0] &0x04) { + setchr2(0x0000, DRegBuf[0] &0xFE); + setchr2(0x0800, DRegBuf[0] |0x01); + setchr2(0x1000, DRegBuf[2]); + setchr2(0x1800, DRegBuf[5]); + } else + setchr8r(0x10, 0); +} + +static DECLFW(Mapper460_WriteExtra) { + if (A001B &0x80 && ~A001B &0x40) EXPREGS[0] =A &0xFF; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static void Mapper460_Reset(void) { + EXPREGS[0] =0; + EXPREGS[1]++; + MMC3RegReset(); +} + +static void Mapper460_Power(void) { + EXPREGS[0] =0; + EXPREGS[1] =0; + GenMMC3Power(); + SetWriteHandler(0x6000, 0x7FFF, Mapper460_WriteExtra); +} + +static void Mapper460_close(void) { + if (CHRRAM) FCEU_gfree(CHRRAM); + CHRRAM =NULL; +} + +void Mapper460_Init(CartInfo *info) { + GenMMC3_Init(info, 128, 512, 0, 0); + cwrap = Mapper460_CHRWrap; + pwrap = Mapper460_PRGWrap; + info->Power = Mapper460_Power; + info->Reset = Mapper460_Reset; + info->Close = Mapper460_close; + AddExState(EXPREGS, 2, 0, "EXPR"); + + CHRRAM =(uint8 *)FCEU_gmalloc(8192); + SetupCartCHRMapping(0x10, CHRRAM, 8192, 1); + AddExState(CHRRAM, 8192, 0, "CRAM"); +} diff --git a/src/boards/463.c b/src/boards/463.c new file mode 100644 index 0000000..3c70244 --- /dev/null +++ b/src/boards/463.c @@ -0,0 +1,77 @@ +/* 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" + +static uint8 regs[4] = { 0 }; +static uint8 dipswitch = 0; + +static SFORMAT StateRegs[] = { + { regs, 4, "EXPR" }, + { &dipswitch, 1, "DPSW" }, + { 0 } +}; + +static void Mapper463_Sync(void) +{ + if (regs[0] &4) + { + setprg16(0x8000, regs[1]); + setprg16(0xC000, regs[1]); + } + else + { + setprg32(0x8000, regs[1] >>1); + } + setchr8(regs[2]); + setmirror(regs[0] &1? MI_H: MI_V); +} + +static DECLFW(Mapper463_Write5000) +{ + if (A &(0x10 << dipswitch)) + { + regs[A &3] =V; + Mapper463_Sync(); + } +} + +static void Mapper463_Reset(void) +{ + dipswitch =(dipswitch +1) &7; + regs[0] =regs[1] =regs[2] =regs[3] =0; + Mapper463_Sync(); +} + +static void Mapper463_Power(void) +{ + dipswitch =0; + regs[0] =regs[1] =regs[2] =regs[3] =0; + Mapper463_Sync(); + SetWriteHandler(0x5000, 0x5FFF, Mapper463_Write5000); + SetReadHandler(0x6000, 0xFFFF, CartBR); +} + +void Mapper463_Init(CartInfo *info) +{ + info->Power = Mapper463_Power; + info->Reset = Mapper463_Reset; + AddExState(StateRegs, ~0, 0, 0); +} \ No newline at end of file diff --git a/src/boards/465.c b/src/boards/465.c new file mode 100644 index 0000000..e847a9b --- /dev/null +++ b/src/boards/465.c @@ -0,0 +1,89 @@ +/* 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" + +static uint16 latchAddr; +static uint8 latchData; + +static SFORMAT StateRegs[] = +{ + { &latchAddr, 2, "ADDR" }, + { &latchData, 1, "DATA" }, + { 0 } +}; + +static void Mapper465_Sync(void) +{ + int prg =latchAddr >>2 &0x1F | latchAddr >>5 &0x20; + if (latchAddr &0x200) + { + setprg16(0x8000, prg &~7 | latchData &7); + setprg16(0xC000, prg | 7); + } + else + { + if (latchAddr &0x001) + { + setprg32(0x8000, prg >>1); + } + else + { + setprg16(0x8000, prg); + setprg16(0xC000, prg); + } + } + setchr8(0); + setmirror(latchAddr &0x002? MI_H: MI_V); +} + +static DECLFW(Mapper465_WriteLatch) +{ + if (latchAddr &0x200) + { + latchData =V; + } + else + { + latchAddr =A &0xFFFF; + } + Mapper465_Sync(); +} + +static void Mapper465_Reset(void) +{ + latchAddr =latchData =0; + Mapper465_Sync(); +} + +static void Mapper465_Power(void) +{ + latchAddr =latchData =0; + Mapper465_Sync(); + SetWriteHandler(0x8000, 0xFFFF, Mapper465_WriteLatch); + SetReadHandler(0x6000, 0xFFFF, CartBR); +} + +void Mapper465_Init(CartInfo *info) +{ + info->Power = Mapper465_Power; + info->Reset = Mapper465_Reset; + AddExState(StateRegs, ~0, 0, 0); +} \ No newline at end of file diff --git a/src/boards/466.c b/src/boards/466.c new file mode 100644 index 0000000..a8ad361 --- /dev/null +++ b/src/boards/466.c @@ -0,0 +1,100 @@ +/* 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" + +static uint8 regs[3]; + +static SFORMAT StateRegs[] = +{ + { regs, 3, "EXPR" }, + { 0 } +}; + +static DECLFR(Mapper466_ReadOB) +{ + return X.DB; +} + +static void Mapper466_Sync(void) +{ + int prg =regs[1] <<5 | regs[0] <<1 &0x1E | regs[0] >>5 &1; + + /* Return open bus when selecting unpopulated PRG chip */ + if (prg &0x20 && PRGsize[0] <1024*1024) + SetReadHandler(0x8000, 0xFFFF, Mapper466_ReadOB); + else + SetReadHandler(0x8000, 0xFFFF, CartBR); + + if (regs[0] &0x40) + { + if (regs[0] &0x10) + { + setprg16(0x8000, prg); + setprg16(0xC000, prg); + } + else + { + setprg32(0x8000, prg >>1); + } + } + else + { + setprg16(0x8000, prg &~7 | regs[2] &7); + setprg16(0xC000, prg &~7 | 7); + } + setprg8r(0x10, 0x6000, 0); + setchr8(0); + setmirror(regs[0] &0x80? MI_H: MI_V); +} + +static DECLFW(Mapper466_Write5000) +{ + regs[A >>11 &1] =A &0xFF; + Mapper466_Sync(); +} + +static DECLFW(Mapper466_WriteLatch) +{ + regs[2] =V; + Mapper466_Sync(); +} + +static void Mapper466_Reset(void) +{ + regs[0] =regs[1] =0; + Mapper466_Sync(); +} + +static void Mapper466_Power(void) +{ + regs[0] =regs[1] =0; + Mapper466_Sync(); + SetWriteHandler(0x5000, 0x5FFF, Mapper466_Write5000); + SetWriteHandler(0x8000, 0xFFFF, Mapper466_WriteLatch); + SetReadHandler(0x6000, 0xFFFF, CartBR); +} + +void Mapper466_Init(CartInfo *info) +{ + info->Power = Mapper466_Power; + info->Reset = Mapper466_Reset; + AddExState(StateRegs, ~0, 0, 0); +} \ No newline at end of file diff --git a/src/boards/467.c b/src/boards/467.c new file mode 100644 index 0000000..268a1a6 --- /dev/null +++ b/src/boards/467.c @@ -0,0 +1,74 @@ +/* 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 (EXPREGS[0] &0x20) { + int prgAND =EXPREGS[0] &0x40? 0x0F: 0x03; + int prgOR =EXPREGS[0] <<1 &0x3C | 0x40; + setprg8(A, V &prgAND | prgOR &~prgAND); + } else + if (~A &0x2000) + setprg16(A, EXPREGS[0] &0x1F); +} + +static void Mapper467_CHRWrap(uint32 A, uint8 V) { + if (~A &0x0800) { + A =A &~0x400 | A <<1 &0x800; + if (EXPREGS[0] &0x40) + setchr2(A, V |0x100); + else + setchr2(A, V &~3 | A >>11 &3); + } +} + +static DECLFW(Mapper467_WriteExtra) { + EXPREGS[0] =V; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + setmirror(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) { + EXPREGS[0] =0; + MMC3RegReset(); +} + +static void Mapper467_Power(void) { + 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); + cwrap = Mapper467_CHRWrap; + pwrap = Mapper467_PRGWrap; + info->Power = Mapper467_Power; + info->Reset = Mapper467_Reset; + AddExState(EXPREGS, 1, 0, "EXPR"); +} diff --git a/src/boards/516.c b/src/boards/516.c index d42b2ed..c9e5a86 100644 --- a/src/boards/516.c +++ b/src/boards/516.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 negativeExponent + * 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 diff --git a/src/boards/533.c b/src/boards/533.c index 821f861..3465576 100644 --- a/src/boards/533.c +++ b/src/boards/533.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 negativeExponent + * 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 diff --git a/src/boards/534.c b/src/boards/534.c deleted file mode 100644 index 8c8bb9d..0000000 --- a/src/boards/534.c +++ /dev/null @@ -1,89 +0,0 @@ -/* FCEUmm - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2020 negativeExponent - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public 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 534 - 2-in-1 数独/五子棋 (Sudoku/Gomoku, NJ064) */ - -#include "mapinc.h" -#include "mmc3.h" - -static uint32 GetPRGBank(uint32 bank) -{ - if (~bank & 1 && (MMC3_cmd & 0x40)) bank ^= 2; - return (bank & 2) ? (0xFE | (bank & 1)) : DRegBuf[6 | (bank & 1)]; -} - -void SyncPRG_GNROM(int A14, int AND, int OR) { - setprg8(0x8000, ((GetPRGBank(0) & ~A14) & AND) | OR); - setprg8(0xA000, ((GetPRGBank(1) & ~A14) & AND) | OR); - setprg8(0xC000, ((GetPRGBank(0) | A14) & AND) | OR); - setprg8(0xE000, ((GetPRGBank(1) | A14) & AND) | OR); -} - -static void M534PW(uint32 A, uint8 V) { - if (EXPREGS[0] & 0x40) - SyncPRG_GNROM(EXPREGS[3] & 0x02, 0x0F, ((EXPREGS[0] & 3) << 4)); - else - setprg8(A, (V & 0x1F) | ((EXPREGS[0] & 0x2) << 4)); -} - -static void M534CW(uint32 A, uint8 V) { - setchr1(A, (V & 0xFF) | ((EXPREGS[2] & 0x0F) << 3) | ((EXPREGS[0] & 0x18) << 4)); -} - -static DECLFW(M534IRQWrite) { - MMC3_IRQWrite(0xC000 | (A & 1), V ^ 0xFF); -} - -static DECLFW(M534WriteLo) { - if ((A & 0x800) && (!(EXPREGS[3] & 0x80) || (A & 3) == 2)) { - EXPREGS[A & 3] = V; - FixMMC3CHR(MMC3_cmd); - FixMMC3PRG(MMC3_cmd); - } -} - -static void M534Power(void) { - EXPREGS[0] = 0x00; - EXPREGS[1] = 0x00; - EXPREGS[2] = 0x00; - EXPREGS[3] = 0x00; - GenMMC3Power(); - SetWriteHandler(0x6000, 0x6FFF, M534WriteLo); - SetWriteHandler(0xC000, 0xDFFF, M534IRQWrite); -} - -static void M534Reset(void) { - EXPREGS[0] = 0x00; - EXPREGS[1] = 0x00; - EXPREGS[2] = 0x00; - EXPREGS[3] = 0x00; - EXPREGS[4] = (EXPREGS[4] + 1) & 7; - FCEU_printf("dipswitch = %d\n", EXPREGS[4]); - MMC3RegReset(); -} - -void Mapper534_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 512, 0, 0); - pwrap = M534PW; - cwrap = M534CW; - info->Power = M534Power; - info->Reset = M534Reset; - AddExState(EXPREGS, 5, 0, "EXPR"); -} diff --git a/src/boards/539.c b/src/boards/539.c index 38053c8..cfcc6b6 100644 --- a/src/boards/539.c +++ b/src/boards/539.c @@ -1,7 +1,7 @@ /* FCEUmm - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2020 negativeExponent + * 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 diff --git a/src/boards/554.c b/src/boards/554.c new file mode 100644 index 0000000..8084a76 --- /dev/null +++ b/src/boards/554.c @@ -0,0 +1,78 @@ +/* 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 554 - Kaiser KS-7010 + * used for one of several cartridge conversions of the FDS version of + * 悪魔城 Dracula, the Japanese version of Castlevania + */ + +#include "mapinc.h" + +static uint8 reg; + +static SFORMAT StateRegs[] = +{ + { ®, 1, "REG" }, + { 0 } +}; + +static void Sync(void) { + setprg8(0x6000, reg); + setprg8(0x8000, 10); + setprg8(0xA000, 11); + setprg8(0xC000, 6); + setprg8(0xE000, 7); + 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(); + } + return CartBR(A); +} + +static void M554Power(void) { + Sync(); + SetReadHandler(0x6000, 0xFFFF, M554Read); +} + +static void StateRestore(int version) { + Sync(); +} + +void Mapper554_Init(CartInfo *info) { + info->Power = M554Power; + GameStateRestore = StateRestore; + AddExState(&StateRegs, ~0, 0, 0); +} diff --git a/src/boards/558.c b/src/boards/558.c new file mode 100644 index 0000000..9be3ed1 --- /dev/null +++ b/src/boards/558.c @@ -0,0 +1,142 @@ +/* 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 + */ + +/* Yancheng YC-03-09/Waixing FS??? PCB */ + +#include "mapinc.h" +#include "eeprom_93C66.h" + +static uint8 *WRAM; +static uint32 WRAMSIZE; +static uint8 reg[4]; +static uint8 haveEEPROM; +static uint8 eeprom_data[512]; +static SFORMAT StateRegs[] = +{ + { reg, 4, "REGS" }, + { 0 } +}; + +static void sync() +{ + setprg32(0x8000, reg[1] <<4 | reg[0] &0xF | (reg[3] &0x04? 0x00: 0x03)); + setprg8r(0x10, 0x6000, 0); + if (~reg[0] &0x80) + setchr8(0); + + if (haveEEPROM) + eeprom_93C66_write(reg[2] &0x04, reg[2] &0x02, reg[2] &0x01); +} + +static void hblank(void) { + if (reg[0] &0x80 && scanline <239) + { /* Actual hardware cannot look at the current scanline number, but instead latches PA09 on 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 + setchr8(0); +} + +static DECLFR(readReg) +{ + if (haveEEPROM) + return eeprom_93C66_read()? 0x04: 0x00; + else + 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(); +} + +static void power(void) +{ + memset(reg, 0, sizeof(reg)); + if (haveEEPROM) + eeprom_93C66_init(); + sync(); + SetReadHandler (0x5000, 0x57FF, readReg); + SetWriteHandler(0x5000, 0x57FF, writeReg); + SetReadHandler (0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); +} + +static void reset(void) +{ + memset(reg, 0, sizeof(reg)); + sync(); +} + +static void close(void) +{ + if (WRAM) + FCEU_gfree(WRAM); + WRAM = NULL; +} + +static void StateRestore(int version) +{ + sync(); +} + +void Mapper558_Init (CartInfo *info) +{ + info->Power = power; + info->Reset = reset; + info->Close = close; + GameHBIRQHook = hblank; + + GameStateRestore = StateRestore; + AddExState(StateRegs, ~0, 0, 0); + + 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_storage = eeprom_data; + info->battery = 1; + info->SaveGame[0] = eeprom_data; + info->SaveGameLen[0] = 512; + } + else + if (info->battery) + { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = (info->PRGRamSaveSize &~0x7FF); + } +} diff --git a/src/boards/57.c b/src/boards/57.c index 278b196..036c485 100644 --- a/src/boards/57.c +++ b/src/boards/57.c @@ -54,8 +54,8 @@ static DECLFW(M57Write) { } static void M57Power(void) { - regs[1] = regs[0] = 0; - hrd_flag = 0; + regs[1] = regs[0] = 0; /* Always reset to menu */ + hrd_flag = 1; /* YH-xxx "Olympic" multicarts disable the menu after one selection */ SetReadHandler(0x8000, 0xFFFF, CartBR); SetWriteHandler(0x8000, 0xFFFF, M57Write); SetReadHandler(0x6000, 0x6000, M57Read); @@ -63,9 +63,11 @@ static void M57Power(void) { } 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); + Sync(); } static void StateRestore(int version) { diff --git a/src/boards/60.c b/src/boards/60.c new file mode 100644 index 0000000..29ace51 --- /dev/null +++ b/src/boards/60.c @@ -0,0 +1,56 @@ +/* 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" + +static uint8 game = 0; + +static void Sync(void) +{ + setchr8(game); + setprg16(0x8000, game); + setprg16(0xC000, game); +} + +static void M60Reset(void) +{ + game = (game + 1) & 3; + Sync(); +} + +static void M60Power(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; + GameStateRestore = StateRestore; + AddExState(&game, 1, 0, "GAME"); +} \ No newline at end of file diff --git a/src/boards/71.c b/src/boards/71.c index 12ce402..343bdf0 100644 --- a/src/boards/71.c +++ b/src/boards/71.c @@ -46,6 +46,7 @@ static DECLFW(M71Write) { } static void M71Power(void) { + preg = 0; mirr = 0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); diff --git a/src/boards/8237.c b/src/boards/8237.c index 93b4513..c72d969 100644 --- a/src/boards/8237.c +++ b/src/boards/8237.c @@ -17,15 +17,27 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * Super Game (Sugar Softec) protected mapper - * Pocahontas 2 (Unl) [U][!], etc. - * TODO: 9in1 LION KING HANGS! + * 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 cmdin; +static uint8 submapper; static uint8 regperm[8][8] = { @@ -51,81 +63,67 @@ static uint8 adrperm[8][8] = { 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) { - if (EXPREGS[0] & 0x40) - setchr1(A, ((EXPREGS[1] & 0xc) << 6) | (V & 0x7F) | ((EXPREGS[1] & 0x20) << 2)); + uint16 outer_bank; + + if (submapper == 1) + outer_bank = ((EXPREGS[1] & 0xE) << 7); else - setchr1(A, ((EXPREGS[1] & 0xc) << 6) | V); + outer_bank = ((EXPREGS[1] & 0xC) << 6); + + if (EXPREGS[0] & 0x40) + setchr1(A, outer_bank | (V & 0x7F) | ((EXPREGS[1] & 0x20) << 2)); + else + setchr1(A, outer_bank | V); } static void UNL8237PW(uint32 A, uint8 V) { + uint8 outer_bank = ((EXPREGS[1] & 3) << 5); + + if (submapper == 1) + outer_bank |= ((EXPREGS[1] & 8) << 4); + if (EXPREGS[0] & 0x40) { uint8 sbank = (EXPREGS[1] & 0x10); - if (EXPREGS[0] & 0x80) { - uint8 bank = ((EXPREGS[1] & 3) << 4) | (EXPREGS[0] & 0x7) | (sbank >> 1); - if (EXPREGS[0] & 0x20) + if (EXPREGS[0] & 0x80) { /* NROM */ + uint8 bank = (outer_bank >> 1) | (EXPREGS[0] & 0x7) | (sbank >> 1); + if (EXPREGS[0] & 0x20) /* NROM-256 */ setprg32(0x8000, bank >> 1); - else { + else { /* NROM-128 */ setprg16(0x8000, bank); setprg16(0xC000, bank); } } else - setprg8(A, ((EXPREGS[1] & 3) << 5) | (V & 0x0F) | sbank); + setprg8(A, outer_bank | (V & 0x0F) | sbank); } else { - if (EXPREGS[0] & 0x80) { - uint8 bank = ((EXPREGS[1] & 3) << 4) | (EXPREGS[0] & 0xF); - if (EXPREGS[0] & 0x20) + if (EXPREGS[0] & 0x80) { /* NROM */ + uint8 bank = (outer_bank >> 1) | (EXPREGS[0] & 0xF); + if (EXPREGS[0] & 0x20) /* NROM-256 */ setprg32(0x8000, bank >> 1); - else { + else { /* NROM-128 */ setprg16(0x8000, bank); setprg16(0xC000, bank); } } else - setprg8(A, ((EXPREGS[1] & 3) << 5) | (V & 0x1F)); + setprg8(A, outer_bank | (V & 0x1F)); } } -static void UNL8237ACW(uint32 A, uint8 V) { - if (EXPREGS[0] & 0x40) - setchr1(A, ((EXPREGS[1] & 0xE) << 7) | (V & 0x7F) | ((EXPREGS[1] & 0x20) << 2)); - else - setchr1(A, ((EXPREGS[1] & 0xE) << 7) | V); +static DECLFR(UNL8237ProtRead) { + return protarray[EXPREGS[3]][A &7] &0x0F | 0x50; } -static void UNL8237APW(uint32 A, uint8 V) { - if (EXPREGS[0] & 0x40) { - uint8 sbank = (EXPREGS[1] & 0x10); - if (EXPREGS[0] & 0x80) { - uint8 bank = ((EXPREGS[1] & 3) << 4) | ((EXPREGS[1] & 8) << 3) | (EXPREGS[0] & 0x7) | (sbank >> 1); - if (EXPREGS[0] & 0x20) { -/* FCEU_printf("8000:%02X\n",bank>>1); */ - setprg32(0x8000, bank >> 1); - } else { -/* FCEU_printf("8000-C000:%02X\n",bank); */ - setprg16(0x8000, bank); - setprg16(0xC000, bank); - } - } else { -/* FCEU_printf("%04x:%02X\n",A,((EXPREGS[1]&3)<<5)|((EXPREGS[1]&8)<<4)|(V&0x0F)|sbank); */ - setprg8(A, ((EXPREGS[1] & 3) << 5) | ((EXPREGS[1] & 8) << 4) | (V & 0x0F) | sbank); - } - } else { - if (EXPREGS[0] & 0x80) { - uint8 bank = ((EXPREGS[1] & 3) << 4) | ((EXPREGS[1] & 8) << 3) | (EXPREGS[0] & 0xF); - if (EXPREGS[0] & 0x20) { -/* FCEU_printf("8000:%02X\n",(bank>>1)&0x07); */ - setprg32(0x8000, bank >> 1); - } else { -/* FCEU_printf("8000-C000:%02X\n",bank&0x0F); */ - setprg16(0x8000, bank); - setprg16(0xC000, bank); - } - } else { -/* FCEU_printf("%04X:%02X\n",A,(((EXPREGS[1]&3)<<5)|((EXPREGS[1]&8)<<4)|(V&0x1F))&0x1F); */ - setprg8(A, ((EXPREGS[1] & 3) << 5) | ((EXPREGS[1] & 8) << 4) | (V & 0x1F)); - } - } -} static DECLFW(UNL8237Write) { uint8 dat = V; uint8 adr = adrperm[EXPREGS[2]][((A >> 12) & 6) | (A & 1)]; @@ -139,19 +137,29 @@ static DECLFW(UNL8237Write) { } static DECLFW(UNL8237ExWrite) { - switch (A) { - case 0x5000: EXPREGS[0] = V; FixMMC3PRG(MMC3_cmd); break; + switch (A & 0xF007) { + case 0x5000: EXPREGS[0] = V; FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); break; case 0x5001: EXPREGS[1] = V; FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); break; + case 0x5002: EXPREGS[3] = V; break; case 0x5007: EXPREGS[2] = V; break; } } static void UNL8237Power(void) { EXPREGS[0] = EXPREGS[2] = 0; - EXPREGS[1] = 3; + EXPREGS[1] = 0x0F; + EXPREGS[3] = 7; GenMMC3Power(); SetWriteHandler(0x8000, 0xFFFF, UNL8237Write); - SetWriteHandler(0x5000, 0x7FFF, UNL8237ExWrite); + SetReadHandler (0x5000, 0x5FFF, UNL8237ProtRead); + SetWriteHandler(0x5000, 0x5FFF, UNL8237ExWrite); +} + +static void UNL8237Reset(void) { + EXPREGS[0] = EXPREGS[2] = 0; + EXPREGS[1] = 0x0F; + EXPREGS[3] = 7; + MMC3RegReset(); } void UNL8237_Init(CartInfo *info) { @@ -159,15 +167,13 @@ void UNL8237_Init(CartInfo *info) { cwrap = UNL8237CW; pwrap = UNL8237PW; info->Power = UNL8237Power; - AddExState(EXPREGS, 3, 0, "EXPR"); - AddExState(&cmdin, 1, 0, "CMDI"); + info->Reset = UNL8237Reset; + AddExState(EXPREGS, 4, 0, "EXPR"); + if (info->iNES2) + submapper = info->submapper; } void UNL8237A_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 0, 0); - cwrap = UNL8237ACW; - pwrap = UNL8237APW; - info->Power = UNL8237Power; - AddExState(EXPREGS, 3, 0, "EXPR"); - AddExState(&cmdin, 1, 0, "CMDI"); + UNL8237_Init(info); + submapper = 1; } diff --git a/src/boards/90.c b/src/boards/90.c deleted file mode 100644 index ff2b0b4..0000000 --- a/src/boards/90.c +++ /dev/null @@ -1,505 +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" -/* #define DEBUG90 */ - -/* Mapper 090 is simpliest mapper hardware and have not extended nametable control and latched chr banks in 4k mode - * Mapper 209 much compicated hardware with decribed above features disabled by default and switchable by command - * Mapper 211 the same mapper 209 but with forced nametable control - * Mapper 281 PRG ($8000-$8FFF) and CHR ($9000-$AFFF) bank select register bits that select 256 KiB banks are masked off. - */ - -static int is209; -static int is211; -static int is281; - -static uint8 IRQMode; /* from $c001 */ -static uint8 IRQPre; /* from $c004 */ -static uint8 IRQPreSize; /* from $c007 */ -static uint8 IRQCount; /* from $c005 */ -static uint8 IRQXOR; /* Loaded from $C006 */ -static uint8 IRQa; /* $c002, $c003, and $c000 */ - -static uint8 mul[2]; -static uint8 regie; - -static uint8 tkcom[4]; -static uint8 prgb[4]; -static uint8 chrlow[8]; -static uint8 chrhigh[8]; - -static uint8 chr[2]; - -static uint16 names[4]; -static uint8 tekker; - -static SFORMAT Tek_StateRegs[] = { - { &IRQMode, 1, "IRQM" }, - { &IRQPre, 1, "IRQP" }, - { &IRQPreSize, 1, "IRQR" }, - { &IRQCount, 1, "IRQC" }, - { &IRQXOR, 1, "IRQX" }, - { &IRQa, 1, "IRQA" }, - { mul, 2, "MUL" }, - { ®ie, 1, "REGI" }, - { tkcom, 4, "TKCO" }, - { prgb, 4, "PRGB" }, - { chr, 2, "CLTC" }, - { chrlow, 4, "CHRL" }, - { chrhigh, 8, "CHRH" }, - { &names[0], 2 | FCEUSTATE_RLSB, "NMS0" }, - { &names[1], 2 | FCEUSTATE_RLSB, "NMS1" }, - { &names[2], 2 | FCEUSTATE_RLSB, "NMS2" }, - { &names[3], 2 | FCEUSTATE_RLSB, "NMS3" }, - { &tekker, 1, "TEKR" }, - { 0 } -}; - -static void mira(void) { - if (((tkcom[0] & 0x20) && is209) || is211 || ((tkcom[1] & 0x08) && is281)) { - int x; - if (tkcom[0] & 0x40) { /* Name tables are ROM-only */ - for (x = 0; x < 4; x++) - setntamem(CHRptr[0] + (((names[x]) & CHRmask1[0]) << 10), 0, x); - } else { /* Name tables can be RAM or ROM. */ - for (x = 0; x < 4; x++) { - if ((tkcom[1] & 0x80) == (names[x] & 0x80)) /* RAM selected. */ - setntamem(NTARAM + ((names[x] & 0x1) << 10), 1, x); - else - setntamem(CHRptr[0] + (((names[x]) & CHRmask1[0]) << 10), 0, x); - } - } - } else { - switch (tkcom[1] & 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 uint8 invertprg(uint8 bank, uint8 reverse) { - if (reverse) - return ((bank & 0x01) << 6 | (bank & 0x02) << 4 | (bank & 0x04) << 2 | - (bank & 0x10) >> 2 | (bank & 0x20) >> 4 | (bank & 0x40) >> 6); - else - return bank; -} - -static void tekprom(void) { - uint8 prgshift = 0, prgmask = 0x3F, outb_sel = 0x06, last_bank = 0x3F; - uint8 prgmode = tkcom[0] & 0x03; - uint8 invert = (tkcom[0] & 0x03) == 0x03 ? 1 : 0; - uint32 bankmode = 0; - - switch (tkcom[0] & 0x03) { - case 0x00: prgshift = 3; prgmask = 0x0F; break; - case 0x01: prgshift = 4; prgmask = 0x1F; break; - default: prgshift = 5; prgmask = 0x3F; break; - } - - if (is281) { - prgmask >>= 1; - outb_sel = 0x01; - } - - bankmode = ((tkcom[3] & outb_sel) << prgshift); - last_bank = (tkcom[0] & 0x04) ? prgb[3] : prgmask; - switch (prgmode) { - case 0x00: - if (tkcom[0] & 0x80) - setprg8(0x6000, (((prgb[3] << 2) + 3) & 0x3F) | bankmode); - setprg32(0x8000, (last_bank & prgmask) | bankmode); - break; - case 0x01: - if (tkcom[0] & 0x80) - setprg8(0x6000, (((prgb[3] << 1) + 1) & 0x3F) | bankmode); - setprg16(0x8000, (prgb[1] & prgmask) | bankmode); - setprg16(0xC000, (last_bank & prgmask) | bankmode); - break; - case 0x02: - case 0x03: - if (tkcom[0] & 0x80) - setprg8(0x6000, (invertprg(prgb[3], invert) & 0x3F) | bankmode); - setprg8(0x8000, (invertprg(prgb[0], invert) & prgmask) | bankmode); - setprg8(0xa000, (invertprg(prgb[1], invert) & prgmask) | bankmode); - setprg8(0xc000, (invertprg(prgb[2], invert) & prgmask) | bankmode); - setprg8(0xe000, (invertprg(last_bank, invert) & prgmask) | bankmode); - break; - } -} - -static void tekvrom(void) { - int x, bank = 0, mask = 0xFFFF; - if (!(tkcom[3] & 0x20) || is281) { - if (is281) - bank = tkcom[3] & 1; - else - bank = (tkcom[3] & 1) | ((tkcom[3] & 0x18) >> 2); - switch (tkcom[0] & 0x18) { - case 0x00: bank <<= 5; mask = 0x1F; break; - case 0x08: bank <<= 6; mask = 0x3F; break; - case 0x10: bank <<= 7; mask = 0x7F; break; - case 0x18: bank <<= 8; mask = 0xFF; break; - } - } - switch (tkcom[0] & 0x18) { - case 0x00: /* 8KB */ - setchr8(((chrlow[0] | (chrhigh[0] << 8)) & mask) | bank); - break; - case 0x08: /* 4KB */ -#if 0 - for(x=0;x<8;x+=4) - setchr4(x<<10,((chrlow[x]|(chrhigh[x]<<8))&mask)|bank); -#endif - setchr4(0x0000, ((chrlow[chr[0]] | (chrhigh[chr[0]] << 8)) & mask) | bank); - setchr4(0x1000, ((chrlow[chr[1]] | (chrhigh[chr[1]] << 8)) & mask) | bank); - break; - case 0x10: /* 2KB */ - for (x = 0; x < 8; x += 2) - setchr2(x << 10, ((chrlow[x] | (chrhigh[x] << 8)) & mask) | bank); - break; - case 0x18: /* 1KB */ - for (x = 0; x < 8; x++) - setchr1(x << 10, ((chrlow[x] | (chrhigh[x] << 8)) & mask) | bank); - break; - } -} - -static DECLFW(M90TekWrite) { - switch (A & 0x5C03) { - case 0x5800: mul[0] = V; break; - case 0x5801: mul[1] = V; break; - case 0x5803: regie = V; break; - } -} - -static DECLFR(M90TekRead) { - switch (A & 0x5C03) { - case 0x5800: return(mul[0] * mul[1]); - case 0x5801: return((mul[0] * mul[1]) >> 8); - case 0x5803: return(regie); - default: return tekker; - } - return(0xff); -} - -static DECLFW(M90PRGWrite) { -/* FCEU_printf("bs %04x %02x\n",A,V); */ - prgb[A & 3] = V; - tekprom(); -} - -static DECLFW(M90CHRlowWrite) { -/* FCEU_printf("bs %04x %02x\n",A,V); */ - chrlow[A & 7] = V; - tekvrom(); -} - -static DECLFW(M90CHRhiWrite) { -/* FCEU_printf("bs %04x %02x\n",A,V); */ - chrhigh[A & 7] = V; - tekvrom(); -} - -static DECLFW(M90NTWrite) { -/* FCEU_printf("bs %04x %02x\n",A,V); */ - if (A & 4) { - names[A & 3] &= 0x00FF; - names[A & 3] |= V << 8; - } else { - names[A & 3] &= 0xFF00; - names[A & 3] |= V; - } - mira(); -} - -static DECLFW(M90IRQWrite) { -/* FCEU_printf("bs %04x %02x\n",A,V); */ - switch (A & 7) { - case 00: -/* FCEU_printf("%s IRQ (C000)\n",V&1?"Enable":"Disable"); */ - IRQa = V & 1; - if (!(V & 1)) - X6502_IRQEnd(FCEU_IQEXT); - break; - case 02: -/* FCEU_printf("Disable IRQ (C002) scanline=%d\n", scanline); */ - IRQa = 0; X6502_IRQEnd(FCEU_IQEXT); - break; - case 03: -/* FCEU_printf("Enable IRQ (C003) scanline=%d\n", scanline); */ - IRQa = 1; - break; - case 01: - IRQMode = V; -#if 0 - FCEU_printf("IRQ Count method: "); - switch (IRQMode&3) - { - case 00: FCEU_printf("M2 cycles\n");break; - case 01: FCEU_printf("PPU A12 toggles\n");break; - case 02: FCEU_printf("PPU reads\n");break; - case 03: FCEU_printf("Writes to CPU space\n");break; - } - FCEU_printf("Counter prescaler size: %s\n",(IRQMode&4)?"3 bits":"8 bits"); - FCEU_printf("Counter prescaler size adjust: %s\n",(IRQMode&8)?"Used C007":"Normal Operation"); - if((IRQMode>>6)==2) FCEU_printf("Counter Down\n"); - else if((IRQMode>>6)==1) FCEU_printf("Counter Up\n"); - else FCEU_printf("Counter Stopped\n"); -#endif - break; - case 04: -/* FCEU_printf("Pre Counter Loaded and Xored wiht C006: %d\n",V^IRQXOR); */ - IRQPre = V ^ IRQXOR; - break; - case 05: -/* FCEU_printf("Main Counter Loaded and Xored wiht C006: %d\n",V^IRQXOR); */ - IRQCount = V ^ IRQXOR; - break; - case 06: -/* FCEU_printf("Xor Value: %d\n",V); */ - IRQXOR = V; - break; - case 07: -#if 0 - if(!(IRQMode&8)) FCEU_printf("C001 is clear, no effect applied\n"); - else if(V==0xFF) FCEU_printf("Prescaler is changed for 12bits\n"); - else FCEU_printf("Counter Stopped\n"); -#endif - IRQPreSize = V; - break; - } -} - -static DECLFW(M90ModeWrite) { -/* FCEU_printf("bs %04x %02x\n",A,V); */ - tkcom[A & 3] = V; - tekprom(); - tekvrom(); - mira(); - -#ifdef DEBUG90 - switch (A & 3) { - case 00: - FCEU_printf("Main Control Register:\n"); - FCEU_printf(" PGR Banking mode: %d\n", V & 7); - FCEU_printf(" CHR Banking mode: %d\n", (V >> 3) & 3); - FCEU_printf(" 6000-7FFF addresses mapping: %s\n", (V & 0x80) ? "Yes" : "No"); - FCEU_printf(" Nametable control: %s\n", (V & 0x20) ? "Enabled" : "Disabled"); - if (V & 0x20) - FCEU_printf(" Nametable can be: %s\n", (V & 0x40) ? "ROM Only" : "RAM or ROM"); - break; - case 01: - FCEU_printf("Mirroring mode: "); - switch (V & 3) { - case 0: FCEU_printf("Vertical\n"); break; - case 1: FCEU_printf("Horizontal\n"); break; - case 2: FCEU_printf("Nametable 0 only\n"); break; - case 3: FCEU_printf("Nametable 1 only\n"); break; - } - FCEU_printf("Mirroring flag: %s\n", (V & 0x80) ? "On" : "Off"); - break; - case 02: - if ((((tkcom[0]) >> 5) & 3) == 1) - FCEU_printf("Nametable ROM/RAM select mode: %d\n", V >> 7); - break; - case 03: - FCEU_printf("CHR Banking mode: %s\n", (V & 0x20) ? "Entire CHR ROM" : "256Kb Switching mode"); - if (!(V & 0x20)) FCEU_printf("256K CHR bank number: %02x\n", (V & 1) | ((V & 0x18) >> 2)); - FCEU_printf("512K PRG bank number: %d\n", (V & 6) >> 1); - FCEU_printf("CHR Bank mirroring: %s\n", (V & 0x80) ? "Swapped" : "Normal operate"); - } -#endif -} - -static DECLFW(M90DummyWrite) { -/* FCEU_printf("bs %04x %02x\n",A,V); */ -} - -static void CCL(void) { - if ((IRQMode >> 6) == 1) { /* Count Up */ - IRQCount++; - if ((IRQCount == 0) && IRQa) { - X6502_IRQBegin(FCEU_IQEXT); - } - } else if ((IRQMode >> 6) == 2) { /* Count down */ - IRQCount--; - if ((IRQCount == 0xFF) && IRQa) { - X6502_IRQBegin(FCEU_IQEXT); - } - } -} - -static void ClockCounter(void) { - uint8 premask; - - if (IRQMode & 0x4) - premask = 0x7; - else - premask = 0xFF; - if ((IRQMode >> 6) == 1) { /* Count up */ - IRQPre++; - if ((IRQPre & premask) == 0) CCL(); - } else if ((IRQMode >> 6) == 2) { /* Count down */ - IRQPre--; - if ((IRQPre & premask) == premask) CCL(); - } -} - -void FP_FASTAPASS(1) CPUWrap(int a) { - int x; - if ((IRQMode & 3) == 0) for (x = 0; x < a; x++) ClockCounter(); -} - -static void SLWrap(void) { - int x; - if ((IRQMode & 3) == 1) for (x = 0; x < 8; x++) ClockCounter(); -} - -static uint32 lastread; -static void FP_FASTAPASS(1) M90PPU(uint32 A) { - if ((IRQMode & 3) == 2) { - if (lastread != A) { - ClockCounter(); - ClockCounter(); - } - lastread = A; - } - - if (is209) { - uint8 l, h; - h = A >> 8; - if (h < 0x20 && ((h & 0x0F) == 0xF)) { - l = A & 0xF0; - if (l == 0xD0) { - chr[(h & 0x10) >> 4] = ((h & 0x10) >> 2); - tekvrom(); - } else if (l == 0xE0) { - chr[(h & 0x10) >> 4] = ((h & 0x10) >> 2) | 2; - tekvrom(); - } - } - } else { - chr[0] = 0; - chr[1] = 4; - } -} - -static void togglie(void) { - tekker += 0x40; - tekker &= 0xC0; - FCEU_printf("tekker=%02x\n", tekker); - memset(tkcom, 0x00, sizeof(tkcom)); - memset(prgb, 0xff, sizeof(prgb)); - tekprom(); - tekvrom(); -} - -static void M90Restore(int version) { - tekprom(); - tekvrom(); - mira(); -} - -static void M90Power(void) { - SetWriteHandler(0x5000, 0x5fff, M90TekWrite); - SetWriteHandler(0x8000, 0x8ff0, M90PRGWrite); - SetWriteHandler(0x9000, 0x9fff, M90CHRlowWrite); - SetWriteHandler(0xA000, 0xAfff, M90CHRhiWrite); - SetWriteHandler(0xB000, 0xBfff, M90NTWrite); - SetWriteHandler(0xC000, 0xCfff, M90IRQWrite); - SetWriteHandler(0xD000, 0xD5ff, M90ModeWrite); - SetWriteHandler(0xE000, 0xFfff, M90DummyWrite); - - SetReadHandler(0x5000, 0x5fff, M90TekRead); - SetReadHandler(0x6000, 0xffff, CartBR); - - mul[0] = mul[1] = regie = 0xFF; - - memset(tkcom, 0x00, sizeof(tkcom)); - memset(prgb, 0xff, sizeof(prgb)); - memset(chrlow, 0xff, sizeof(chrlow)); - memset(chrhigh, 0xff, sizeof(chrhigh)); - memset(names, 0x00, sizeof(names)); - - if (is211) - tekker = 0xC0; - else - tekker = 0x00; - - tekprom(); - tekvrom(); -} - -void Mapper90_Init(CartInfo *info) { - is211 = 0; - is209 = 0; - is281 = 0; - info->Reset = togglie; - info->Power = M90Power; - PPU_hook = M90PPU; - MapIRQHook = CPUWrap; - GameHBIRQHook2 = SLWrap; - GameStateRestore = M90Restore; - AddExState(Tek_StateRegs, ~0, 0, 0); -} - -void Mapper209_Init(CartInfo *info) { - is211 = 0; - is209 = 1; - is281 = 0; - info->Reset = togglie; - info->Power = M90Power; - PPU_hook = M90PPU; - MapIRQHook = CPUWrap; - GameHBIRQHook2 = SLWrap; - GameStateRestore = M90Restore; - AddExState(Tek_StateRegs, ~0, 0, 0); -} - -void Mapper211_Init(CartInfo *info) { - is211 = 1; - is281 = 0; - info->Reset = togglie; - info->Power = M90Power; - PPU_hook = M90PPU; - MapIRQHook = CPUWrap; - GameHBIRQHook2 = SLWrap; - GameStateRestore = M90Restore; - AddExState(Tek_StateRegs, ~0, 0, 0); -} - -void Mapper281_Init(CartInfo *info) { - is211 = 0; - is209 = 0; - is281 = 1; - info->Reset = togglie; - info->Power = M90Power; - PPU_hook = M90PPU; - MapIRQHook = CPUWrap; - GameHBIRQHook2 = SLWrap; - GameStateRestore = M90Restore; - AddExState(Tek_StateRegs, ~0, 0, 0); -} diff --git a/src/boards/91.c b/src/boards/91.c index 33652aa..4e9ccfe 100644 --- a/src/boards/91.c +++ b/src/boards/91.c @@ -2,7 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2012 CaH4e3 - * Copyright (C) 2020 negativeExponent + * 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 diff --git a/src/boards/BS110.c b/src/boards/BS110.c deleted file mode 100644 index 1f5736f..0000000 --- a/src/boards/BS110.c +++ /dev/null @@ -1,199 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator -* -* Copyright notice for this file: -* Copyright (C) 2008 -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" -#include "mmc3.h" - -static uint8 *WRAM; -static uint32 WRAMSIZE; - -static uint8 mmc3_reg[8]; -static uint8 exRegs[8]; -static uint8 pointer; -static uint8 readDIP; -static uint16 prgAND; -static uint16 chrAND; -static uint16 prgOR; -static uint16 chrOR; -static uint8 nrom; -static uint8 nrom128; -static uint8 dipswitch; - - -static SFORMAT BS110_StateRegs[] = -{ - { exRegs, 8, "REGS" }, - { mmc3_reg, 8, "MREG" }, - { &pointer, 1, "PNT0" }, - { &readDIP, 1, "RDIP" }, - { &prgAND, 2 | FCEUSTATE_RLSB, "PAND" }, - { &chrAND, 2 | FCEUSTATE_RLSB, "CAND" }, - { &prgOR, 2 | FCEUSTATE_RLSB, "PROR" }, - { &chrOR, 2 | FCEUSTATE_RLSB, "CHOR" }, - { &nrom, 1, "NROM" }, - { &nrom128, 1, "N128" }, - { &dipswitch, 1, "DIP0" }, - { 0 } -}; - -int BS110GetPRGBank(int bank) -{ - if ((~bank & 1) && (pointer & 0x40)) bank ^= 2; - return (bank & 2) ? 0xFE | (bank & 1) : mmc3_reg[6 | (bank & 1)]; -} - -void BS110SyncPRG_GNROM(int A14, int AND, int OR) { - setprg8(0x8000, ((BS110GetPRGBank(0) &~A14) &AND) | OR); - setprg8(0xA000, ((BS110GetPRGBank(1) &~A14) &AND) | OR); - setprg8(0xC000, ((BS110GetPRGBank(0) | A14) &AND) | OR); - setprg8(0xE000, ((BS110GetPRGBank(1) | A14) &AND) | OR); -} - -static void BS110CW(uint32 A, uint8 V) { - - uint8 block = ((exRegs[1]) & 0x03); - uint8 mask = 0x7F; - setchr1(A, (block << 7) | (V & mask)); - -} - -static void BS110PW(uint32 A, uint8 V) { - if ((exRegs[1] >> 2) & 0x01) - { - uint8 mask = 0x0F; - uint8 block = (exRegs[1] & 3) << 4; - if ((exRegs[1] >> 3) & 0x01) - { - setprg8(0x8000, ((BS110GetPRGBank(0)) & mask) | block); - setprg8(0xA000, ((BS110GetPRGBank(1)) & mask) | block); - setprg8(0xC000, ((BS110GetPRGBank(0)) & mask) | block); - setprg8(0xE000, ((BS110GetPRGBank(1)) & mask) | block); - } - else - { - - setprg8(0x8000, ((BS110GetPRGBank(0)) & mask) | block); - setprg8(0xA000, ((BS110GetPRGBank(1)) & mask) | block); - setprg8(0xC000, ((BS110GetPRGBank(0) | 2) & mask) | block); - setprg8(0xE000, ((BS110GetPRGBank(1) | 2) & mask) | block); - } - } - else - { - uint8 mask = 0x0F; - uint8 block = (exRegs[1] & 3) << 4; - setprg8(A, block | (V & mask)); - } -} - - -static DECLFW(BS110WriteHi) { - - A = A & 0xE001; - - if (A < 0xC000) - { - if (A == 0x8000) - pointer = MMC3_cmd ^ V; - if (A == 0x8001) - mmc3_reg[MMC3_cmd & 0x07] = V; - - MMC3_CMDWrite(A, V); - FixMMC3PRG(MMC3_cmd); - FixMMC3CHR(MMC3_cmd); - } - else - { - MMC3_IRQWrite(A, V); - } -} - -static DECLFW(BS110WriteLo) { - - exRegs[1] = A; - exRegs[0] = V; - FixMMC3PRG(MMC3_cmd); - FixMMC3CHR(MMC3_cmd); - -} -static DECLFR(BS110ReadHi) -{ - if ((A == 0xCB00) && ((exRegs[1] & 0x0F) == 0x08)) - return dipswitch; - else - return CartBR(A); - -} - -static void BS110Power(void) -{ - int i = 0; - dipswitch = 0; - mmc3_reg[0] = 0x00; mmc3_reg[1] = 0x02; - mmc3_reg[2] = 0x04; mmc3_reg[3] = 0x05; mmc3_reg[4] = 0x06; mmc3_reg[5] = 0x07; - mmc3_reg[6] = 0x00; mmc3_reg[7] = 0x01; - - for (i = 0;i<4;i++) - exRegs[i] = 0; - - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, BS110WriteLo); - SetWriteHandler(0x8000, 0xFFFF, BS110WriteHi); - SetReadHandler(0x8000, 0xFFFF, BS110ReadHi); -} - -static void BS110Reset(void) -{ - int i = 0; - - dipswitch++; - mmc3_reg[0] = 0x00; mmc3_reg[1] = 0x02; - mmc3_reg[2] = 0x04; mmc3_reg[3] = 0x05; mmc3_reg[4] = 0x06; mmc3_reg[5] = 0x07; - mmc3_reg[6] = 0x00; mmc3_reg[7] = 0x01; - - for (i = 0;i<4;i++) - exRegs[i] = 0; - - MMC3RegReset(); -} -static void BS110Close(void) { - GenMMC3Close(); - if (WRAM) - FCEU_free(WRAM); - WRAM = NULL; -} - -void BS110_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 512, 0, 0); - pwrap = BS110PW; - cwrap = BS110CW; - info->Power = BS110Power; - info->Reset = BS110Reset; - info->Close = BS110Close; - - WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - - AddExState(EXPREGS, 3, 0, "EXPR"); - AddExState(BS110_StateRegs, ~0, 0, 0); -} diff --git a/src/boards/Bs5652.c b/src/boards/Bs5652.c deleted file mode 100644 index a9f8ad3..0000000 --- a/src/boards/Bs5652.c +++ /dev/null @@ -1,253 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2008 -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" -#include "mmc3.h" -#include "crc32.h" - -static uint8 *WRAM; -static uint32 WRAMSIZE; - -static uint8 mmc3_reg[8]; -static uint8 exRegs[8]; -static uint8 pointer; -static uint8 locked; -static uint8 readDIP; -static uint16 prgAND; -static uint16 chrAND; -static uint16 prgOR; -static uint16 chrOR; -static uint8 nrom; -static uint8 nrom128; -static uint8 dipswitch; - -static SFORMAT BS5652_StateRegs[] = -{ - { exRegs, 8, "REGS" }, - { mmc3_reg, 8, "MREG" }, - { &pointer, 1, "PNT0" }, - { &readDIP, 1, "RDIP" }, - { &prgAND, 2 | FCEUSTATE_RLSB, "PAND" }, - { &chrAND, 2 | FCEUSTATE_RLSB, "CAND" }, - { &prgOR, 2 | FCEUSTATE_RLSB, "PROR" }, - { &chrOR, 2 | FCEUSTATE_RLSB, "CHOR" }, - { &nrom, 1, "NROM" }, - { &nrom128, 1, "N128" }, - { &dipswitch, 1, "DIP0" }, - { 0 } -}; - -void Bs5652AnalyzeReg() -{ - locked = exRegs[0] & 0x80; - readDIP = exRegs[0] & 0x40; - prgAND = exRegs[1] & 0x04 ? 0x0F : 0x1F; - chrAND = exRegs[1] & 0x40 ? 0x7F : 0xFF; - prgOR = (exRegs[1] & 0x03) << 4; - chrOR = (exRegs[1] & 0x30) << 3 ; - nrom = exRegs[0] & 0x08; - nrom128 = exRegs[1] & 0x08; -} - -int Bs5652GetPRGBank(int bank) -{ - if ((~bank & 1) && (pointer & 0x40)) bank ^= 2; - return (bank & 2) ? 0xFE | (bank & 1) : mmc3_reg[6 | (bank & 1)]; -} - -void Bs5652SyncPRG_GNROM(int A14, int AND, int OR) { - setprg8(0x8000, ((Bs5652GetPRGBank(0) &~A14) &AND) | OR); - setprg8(0xA000, ((Bs5652GetPRGBank(1) &~A14) &AND) | OR); - setprg8(0xC000, ((Bs5652GetPRGBank(0) | A14) &AND) | OR); - setprg8(0xE000, ((Bs5652GetPRGBank(1) | A14) &AND) | OR); -} - -static void Bs5652CW(uint32 A, uint8 V) { - - if (exRegs[0] & 0x08) - setchr8((exRegs[2] & 0x0F) | (exRegs[4] & 0x03) | (((exRegs[1] >> 4) & 7) << 4)); - else - setchr1(A, (V & chrAND) | chrOR ); -} - -static void Bs5652PW(uint32 A, uint8 V) { - if (nrom) - { - if (exRegs[3] & 0x8) /* 20190504 up2 */ - { - if ((exRegs[1] >> 3) & 0x01) - { - uint8 _bank = ((exRegs[2] >> 1) & 0x07) | ((exRegs[1] & 3) << 3); - setprg16(0x8000, _bank); - setprg16(0xC000, _bank); - - } - else - { - setprg32(0x8000,((exRegs[2] >> 2) & 0x03) | ((exRegs[1] & 3) << 2)); - } - } - else - { - Bs5652SyncPRG_GNROM(nrom128 ? 0 : 2, prgAND, prgOR); - } - - } - else - { - if (((exRegs[1] >> 7) & 0x01)) - { - setprg32(0x8000,((Bs5652GetPRGBank(0) >> 2) & 0x03) | ((exRegs[1] & 3) << 2)); - } - else - setprg8(A, prgOR | (V & prgAND)); - } -} - - -static DECLFW(Bs5652WriteHi) { - - A = A & 0xE001; - - if (A < 0xC000) - { - if(A==0x8000) - pointer = MMC3_cmd ^ V; - if(A==0x8001) - mmc3_reg[MMC3_cmd & 0x07] = V; - - MMC3_CMDWrite(A, V); - FixMMC3PRG(MMC3_cmd); - FixMMC3CHR(MMC3_cmd); - } - else - { - MMC3_IRQWrite(A, V); - } -} - -static DECLFW(Bs5652WriteLo) { - - if (!locked) { - exRegs[A & 3] = V; - Bs5652AnalyzeReg(); - FixMMC3PRG(MMC3_cmd); - FixMMC3CHR(MMC3_cmd); - } - else - { - if ((exRegs[0] & 0x08)) - { - exRegs[4] = V; - FixMMC3PRG(MMC3_cmd); - FixMMC3CHR(MMC3_cmd); - } - else - { - WRAM[A - 0x6000] = V; - } - } -} -static DECLFR(Bs5652ReadHi) -{ - if (readDIP) - return dipswitch; - return CartBR(A); -} - -static void Bs5652Power(void) -{ - int i=0; - - dipswitch = 0; - mmc3_reg[0] = 0x00; mmc3_reg[1] = 0x02; - mmc3_reg[2] = 0x04; mmc3_reg[3] = 0x05; mmc3_reg[4] = 0x06; mmc3_reg[5] = 0x07; - mmc3_reg[6] = 0x00; mmc3_reg[7] = 0x01; - - for(i=0;i<4;i++) - exRegs[i]=0; - - Bs5652AnalyzeReg(); - - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, Bs5652WriteLo); - SetWriteHandler(0x8000, 0xFFFF, Bs5652WriteHi); - SetReadHandler(0x8000, 0xFFFF, Bs5652ReadHi); -} - -static void Bs5652Reset(void) -{ - int i=0; - - dipswitch++; - mmc3_reg[0] = 0x00; mmc3_reg[1] = 0x02; - mmc3_reg[2] = 0x04; mmc3_reg[3] = 0x05; mmc3_reg[4] = 0x06; mmc3_reg[5] = 0x07; - mmc3_reg[6] = 0x00; mmc3_reg[7] = 0x01; - - for(i=0;i<4;i++) - exRegs[i]=0; - - Bs5652AnalyzeReg(); - - MMC3RegReset(); -} - -static void Bs5652Close(void) -{ - GenMMC3Close(); - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -void Bs5652_Init(CartInfo *info) -{ - uint32 unif_crc; - - GenMMC3_Init(info, 512, 512, 0, 0); - pwrap = Bs5652PW; - cwrap = Bs5652CW; - info->Power = Bs5652Power; - info->Reset = Bs5652Reset; - info->Close = Bs5652Close; - - WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - - unif_crc = CalcCRC32(0, PRGptr[0], PRGsize[0]); - - if (unif_crc == 0xb97641b5) /* Fix my own error, unif CHR 0 error */ - { - if ((CHRsize[0] == 0x2000) && (CHRsize[1] > 0x2000)) - { - CHRsize[0] = CHRsize[1]; - CHRptr[0] = (uint8*)FCEU_gmalloc(CHRsize[1]); - memcpy(CHRptr[0], CHRptr[1], CHRsize[1]); - SetupCartCHRMapping(0, CHRptr[0], CHRsize[0], 0); - } - } - - AddExState(EXPREGS, 3, 0, "EXPR"); - AddExState(BS5652_StateRegs, ~0, 0, 0); -} diff --git a/src/boards/KS7030.c b/src/boards/KS7030.c index c6de258..a35b184 100644 --- a/src/boards/KS7030.c +++ b/src/boards/KS7030.c @@ -25,8 +25,8 @@ * */ -/* 2020-3-6 - update mirroring (negativeExponent) -/* PRG-ROM Bank Select #1/Mirroring Select ($8000-$8FFF, write) +/* 2020-3-6 - update mirroring + * PRG-ROM Bank Select #1/Mirroring Select ($8000-$8FFF, write) * A~FEDC BA98 7654 3210 * ------------------- * 1000 .... .... MBBB diff --git a/src/boards/KS7032.c b/src/boards/KS7032.c index 8e123e5..a435b3c 100644 --- a/src/boards/KS7032.c +++ b/src/boards/KS7032.c @@ -139,6 +139,12 @@ static void UNLKS7032Power(void) { } } +static void UNLKS7032Close(void) { + if (WRAM) + FCEU_gfree(WRAM); + WRAM = NULL; +} + static void StateRestore(int version) { Sync(); } @@ -146,6 +152,7 @@ static void StateRestore(int version) { void UNLKS7032_Init(CartInfo *info) { KS7032 = 1; info->Power = UNLKS7032Power; + info->Close = UNLKS7032Close; MapIRQHook = UNLSMB2JIRQHook; GameStateRestore = StateRestore; AddExState(&StateRegsKS7032, ~0, 0, 0); @@ -154,6 +161,7 @@ void UNLKS7032_Init(CartInfo *info) { void UNLKS202_Init(CartInfo *info) { KS7032 = 0; info->Power = UNLKS7032Power; + info->Close = UNLKS7032Close; MapIRQHook = UNLSMB2JIRQHook; GameStateRestore = StateRestore; AddExState(&StateRegsKS7032, ~0, 0, 0); diff --git a/src/boards/KS7057.c b/src/boards/KS7057.c index 3762138..be32d24 100644 --- a/src/boards/KS7057.c +++ b/src/boards/KS7057.c @@ -85,8 +85,13 @@ 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/NC7000M.c b/src/boards/NC7000M.c deleted file mode 100644 index 0f8b1ce..0000000 --- a/src/boards/NC7000M.c +++ /dev/null @@ -1,186 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2008 -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" -#include "mmc3.h" - - -static uint8 *WRAM; -static uint32 WRAMSIZE; - -static uint8 mmc3_reg[8]; -static uint8 exRegs[8]; -static uint8 pointer; -static uint8 locked; -static uint8 readDIP; -static uint16 prgAND; -static uint16 chrAND; -static uint16 prgOR; -static uint16 chrOR; -static uint8 nrom; -static uint8 nrom256; -static uint16 reg; - - -static SFORMAT NC7000M_StateRegs[] = -{ - { exRegs, 8, "REGS" }, - { mmc3_reg, 8, "MREG" }, - { &pointer, 1, "PNT0" }, - { &readDIP, 1, "RDIP" }, - { &prgAND, 2 | FCEUSTATE_RLSB, "PAND" }, - { &chrAND, 2 | FCEUSTATE_RLSB, "CAND" }, - { &prgOR, 2 | FCEUSTATE_RLSB, "PROR" }, - { &chrOR, 2 | FCEUSTATE_RLSB, "CHOR" }, - { &nrom, 1, "NROM" }, - { &nrom256, 1, "N256" }, - { ®, 2 | FCEUSTATE_RLSB, "REG0" }, - { 0 } -}; - -void NC7000MAnalyzeReg() -{ - locked = (reg & 0x80); - prgAND = (reg & 0x08 ? 0x0F : 0x1F); - chrAND = (reg & 0x40 ? 0x7F : 0xFF); - prgOR = (reg << 4 & 0x30); - chrOR = ((reg << 3) & 0x080) | (reg & 0x100); - nrom = (reg & 0x20); - nrom256 = (reg & 0x04); -} - -int NC7000MGetPRGBank(int bank) -{ - if ((~bank & 1) && (pointer & 0x40)) bank ^= 2; - return (bank & 2) ? 0xFE | (bank & 1) : mmc3_reg[6 | (bank & 1)]; -} - -void NC7000MSyncPRG_GNROM(int A14, int AND, int OR) { - setprg8(0x8000, ((NC7000MGetPRGBank(0) &~A14) &AND) | OR); - setprg8(0xA000, ((NC7000MGetPRGBank(1) &~A14) &AND) | OR); - setprg8(0xC000, ((NC7000MGetPRGBank(0) | A14) &AND) | OR); - setprg8(0xE000, ((NC7000MGetPRGBank(1) | A14) &AND) | OR); -} - -static void NC7000MCW(uint32 A, uint8 V) { - - setchr1(A, (V & chrAND) | (chrOR &~chrAND)); -} - -static void NC7000MPW(uint32 A, uint8 V) { - - if (nrom) - { - NC7000MSyncPRG_GNROM(nrom256 ? 2 : 0, prgAND, prgOR &~prgAND); - } - else - { - setprg8(A, (prgOR &~prgAND) | (V & prgAND)); - } -} - - -static DECLFW(NC7000MWriteHi) { - - A = A & 0xE001; - - if (A < 0xC000) - { - if(A==0x8000) - pointer = MMC3_cmd ^ V; - if(A==0x8001) - mmc3_reg[MMC3_cmd & 0x07] = V; - - MMC3_CMDWrite(A, V); - FixMMC3PRG(MMC3_cmd); - FixMMC3CHR(MMC3_cmd); - } - else - { - MMC3_IRQWrite(A, V); - } -} - -static DECLFW(NC7000MWriteLo) { - - if (!(reg & 0x80)) { - reg = V | (A & 0x100); - NC7000MAnalyzeReg(); - FixMMC3PRG(MMC3_cmd); - FixMMC3CHR(MMC3_cmd); - } - else - { - WRAM[A - 0x6000] = V; - } -} - -static void NC7000MPower(void) { - mmc3_reg[0] = 0x00; mmc3_reg[1] = 0x02; - mmc3_reg[2] = 0x04; mmc3_reg[3] = 0x05; mmc3_reg[4] = 0x06; mmc3_reg[5] = 0x07; - mmc3_reg[6] = 0x00; mmc3_reg[7] = 0x01; - - reg = 0x0000; - - NC7000MAnalyzeReg(); - - GenMMC3Power(); - SetWriteHandler(0x6000, 0x7FFF, NC7000MWriteLo); - SetWriteHandler(0x8000, 0xFFFF, NC7000MWriteHi); -} - -static void NC7000MReset(void) { - - mmc3_reg[0] = 0x00; mmc3_reg[1] = 0x02; - mmc3_reg[2] = 0x04; mmc3_reg[3] = 0x05; mmc3_reg[4] = 0x06; mmc3_reg[5] = 0x07; - mmc3_reg[6] = 0x00; mmc3_reg[7] = 0x01; - - reg = 0x0000; - - NC7000MAnalyzeReg(); - - MMC3RegReset(); -} -static void NC7000MClose(void) { - GenMMC3Close(); - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -void NC7000M_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 512, 0, 0); - pwrap = NC7000MPW; - cwrap = NC7000MCW; - info->Power = NC7000MPower; - info->Reset = NC7000MReset; - info->Close = NC7000MClose; - - WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); - - AddExState(EXPREGS, 3, 0, "EXPR"); - AddExState(NC7000M_StateRegs, ~0, 0, 0); -} diff --git a/src/boards/__serial.c b/src/boards/__serial.c index b13c608..db56841 100644 --- a/src/boards/__serial.c +++ b/src/boards/__serial.c @@ -1,3 +1,4 @@ +#include #include "__serial.h" #if defined(_WIN32) && !defined(_XBOX) && !defined(__LIBRETRO__) diff --git a/src/boards/__serial.h b/src/boards/__serial.h index c9f9af5..56d35c3 100644 --- a/src/boards/__serial.h +++ b/src/boards/__serial.h @@ -1,8 +1,6 @@ #ifndef __SERIAL_H #define __SERIAL_H -#include - typedef int BOOL; #ifndef TRUE diff --git a/src/boards/a9746.c b/src/boards/a9746.c index 97e2755..d2b1a05 100644 --- a/src/boards/a9746.c +++ b/src/boards/a9746.c @@ -21,55 +21,85 @@ #include "mapinc.h" #include "mmc3.h" -static DECLFW(UNLA9746Write) { -/* FCEU_printf("write raw %04x:%02x\n",A,V); */ - switch (A & 0xE003) { - case 0x8000: EXPREGS[1] = V; EXPREGS[0] = 0; break; - case 0x8002: EXPREGS[0] = V; EXPREGS[1] = 0; break; - case 0x8001: - { - uint8 bits_rev = ((V & 0x20) >> 5) | ((V & 0x10) >> 3) | ((V & 0x08) >> 1) | ((V & 0x04) << 1); - switch (EXPREGS[0]) { - case 0x26: setprg8(0x8000, bits_rev); break; - case 0x25: setprg8(0xA000, bits_rev); break; - case 0x24: setprg8(0xC000, bits_rev); break; - case 0x23: setprg8(0xE000, bits_rev); break; +static void UNLA9746PWrap(uint32 A, uint8 V) { + setprg8(A, EXPREGS[1] <<4 | V &0x0F); +} + +static void UNLA9746CWrap(uint32 A, uint8 V) { + setchr1(A, EXPREGS[1] <<7 | V &0x7F); +} + +static DECLFW(UNLA9746WriteOuter) { + switch(A &1) { + case 0: EXPREGS[1] =EXPREGS[1] &~1 | V >>3 &1; break; + case 1: EXPREGS[1] =EXPREGS[1] &~2 | V >>4 &2; break; + } + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); +} + +static DECLFW(UNLA9746WriteASIC) { + int index; + + if (A &1) + { /* Register data */ + if (~EXPREGS[0] &0x20) + { /* Scrambled mode inactive */ + MMC3_CMDWrite(A, V); } - switch (EXPREGS[1]) { - case 0x0a: - case 0x08: EXPREGS[2] = (V << 4); break; - case 0x09: setchr1(0x0000, EXPREGS[2] | (V >> 1)); break; - case 0x0b: setchr1(0x0400, EXPREGS[2] | (V >> 1) | 1); break; - case 0x0c: - case 0x0e: EXPREGS[2] = (V << 4); break; - case 0x0d: setchr1(0x0800, EXPREGS[2] | (V >> 1)); break; - case 0x0f: setchr1(0x0c00, EXPREGS[2] | (V >> 1) | 1); break; - case 0x10: - case 0x12: EXPREGS[2] = (V << 4); break; - case 0x11: setchr1(0x1000, EXPREGS[2] | (V >> 1)); break; - case 0x14: - case 0x16: EXPREGS[2] = (V << 4); break; - case 0x15: setchr1(0x1400, EXPREGS[2] | (V >> 1)); break; - case 0x18: - case 0x1a: EXPREGS[2] = (V << 4); break; - case 0x19: setchr1(0x1800, EXPREGS[2] | (V >> 1)); break; - case 0x1c: - case 0x1e: EXPREGS[2] = (V << 4); break; - case 0x1d: setchr1(0x1c00, EXPREGS[2] | (V >> 1)); break; + 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 */ + DRegBuf[index] &=~0x0F; + DRegBuf[index] |=V >>1 &0x0F; + } + else + { /* MSB nibble */ + DRegBuf[index] &=~0xF0; + DRegBuf[index] |=V <<4 &0xF0; + } + FixMMC3CHR(MMC3_cmd); + } + else + if (MMC3_cmd >=0x25 && MMC3_cmd <=0x26) + { /* Scrambled PRG register */ + DRegBuf[6 | MMC3_cmd &1] =V >>5 &1 | V >>3 &2 | V >>1 &4 | V <<1 &8; + FixMMC3PRG(MMC3_cmd); + } } } - break; + else + { /* Register index */ + MMC3_CMDWrite(A, V); + if (A &2) EXPREGS[0] =V; } } static void UNLA9746Power(void) { GenMMC3Power(); - SetWriteHandler(0x8000, 0xbfff, UNLA9746Write); + SetWriteHandler(0x5000, 0x5FFF, UNLA9746WriteOuter); + SetWriteHandler(0x8000, 0xBFFF, UNLA9746WriteASIC); + EXPREGS[0] = 0; + EXPREGS[1] = 3; + MMC3RegReset(); +} + +static void UNLA9746Reset(void) { + EXPREGS[0] = 0; + EXPREGS[1] = 3; + MMC3RegReset(); } void UNLA9746_Init(CartInfo *info) { - GenMMC3_Init(info, 128, 256, 0, 0); + GenMMC3_Init(info, 128, 128, 0, 0); + pwrap = UNLA9746PWrap; + cwrap = UNLA9746CWrap; info->Power = UNLA9746Power; - AddExState(EXPREGS, 6, 0, "EXPR"); + info->Reset = UNLA9746Reset; + AddExState(EXPREGS, 2, 0, "EXPR"); } diff --git a/src/boards/addrlatch.c b/src/boards/addrlatch.c index b2e193a..a989010 100644 --- a/src/boards/addrlatch.c +++ b/src/boards/addrlatch.c @@ -28,6 +28,7 @@ static readfunc defread; static uint8 *WRAM = NULL; static uint32 WRAMSIZE; static uint32 hasBattery; +static uint32 submapper = 0; static DECLFW(LatchWrite) { latche = A; @@ -108,49 +109,38 @@ static DECLFR(BMCD1038Read) { 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 (~latche & 0x200) + LatchWrite(A, V); +} + static void BMCD1038Reset(void) { dipswitch++; dipswitch &= 3; + + /* Always reset to menu */ + latche = 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, 0x0000, 0x8000, 0xFFFF, 0); info->Reset = BMCD1038Reset; - AddExState(&dipswitch, 1, 0, "DIPSW"); -} - -/*------------------ UNL43272 ---------------------------*/ -/* mapper much complex, including 16K bankswitching */ -static void UNL43272Sync(void) { - if ((latche & 0x81) == 0x81) { - setprg32(0x8000, (latche & 0x38) >> 3); - } else - FCEU_printf("unrecognized command %04!\n", latche); - setchr8(0); - setmirror(0); -} - -static DECLFR(UNL43272Read) { - if (latche & 0x400) - return CartBR(A & 0xFE); - else - return CartBR(A); -} - -static void UNL43272Reset(void) { - latche = 0; - UNL43272Sync(); -} - -void UNL43272_Init(CartInfo *info) { - Latch_Init(info, UNL43272Sync, UNL43272Read, 0x0081, 0x8000, 0xFFFF, 0); - info->Reset = UNL43272Reset; + info->Power = BMCD1038Power; AddExState(&dipswitch, 1, 0, "DIPSW"); } /*------------------ Map 058 ---------------------------*/ -static void BMCGK192Sync(void) { +static void M58Sync(void) { if (latche & 0x40) { setprg16(0x8000, latche & 7); setprg16(0xC000, latche & 7); @@ -160,13 +150,14 @@ static void BMCGK192Sync(void) { setmirror(((latche & 0x80) >> 7) ^ 1); } -void BMCGK192_Init(CartInfo *info) { - Latch_Init(info, BMCGK192Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0); +void Mapper58_Init(CartInfo *info) { + Latch_Init(info, M58Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0); } /*------------------ Map 059 ---------------------------*/ /* One more forgotten mapper */ -static void M59Sync(void) { +/* Formerly, an incorrect implementation of BMC-T3H53 */ +/*static void M59Sync(void) { setprg32(0x8000, (latche >> 4) & 7); setchr8(latche & 0x7); setmirror((latche >> 3) & 1); @@ -181,7 +172,7 @@ static DECLFR(M59Read) { void Mapper59_Init(CartInfo *info) { Latch_Init(info, M59Sync, M59Read, 0x0000, 0x8000, 0xFFFF, 0); -} +}*/ /*------------------ Map 061 ---------------------------*/ static void M61Sync(void) { @@ -275,9 +266,8 @@ void Mapper200_Init(CartInfo *info) { /*------------------ Map 201 ---------------------------*/ /* 2020-3-6 - Support for 21-in-1 (CF-043) (2006-V) (Unl) [p1].nes which has mixed mirroring - * found at the time labeled as submapper 15 (negativeExponent) + * found at the time labeled as submapper 15 * 0x05658DED 128K PRG, 32K CHR */ -static uint32 submapper = 0; static void M201Sync(void) { if (latche & 8 || submapper == 15) { setprg32(0x8000, latche & 3); @@ -291,8 +281,7 @@ static void M201Sync(void) { } void Mapper201_Init(CartInfo *info) { - submapper = 0; - if (info->submapper > 0) submapper = info->submapper; + submapper = info->submapper; Latch_Init(info, M201Sync, NULL, 0xFFFF, 0x8000, 0xFFFF, 0); } @@ -354,20 +343,7 @@ void Mapper212_Init(CartInfo *info) { /*------------------ Map 213 ---------------------------*/ -static void M213Sync(void) { - if(latche & 0x40) { - setprg16(0x8000, (latche & 7)); - setprg16(0xC000, (latche & 7)); - } else { - setprg32(0x8000, (latche >> 1) & 3); - } - setchr8((latche >> 3) & 7); - setmirror(((latche & 1)^((latche >> 6) & 1)) ^ 1); -} - -void Mapper213_Init(CartInfo *info) { - Latch_Init(info, M213Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0); -} +/* SEE MAPPER 58 */ /*------------------ Map 214 ---------------------------*/ @@ -421,7 +397,7 @@ static void M227Sync(void) { setprg16(0xC000, p | 7); } else { setprg16(0x8000, p); - setprg16(0xC000, p & 0x38); + setprg16(0xC000, submapper ==2? 0: p & 0x38); } } } @@ -438,6 +414,7 @@ static void M227Sync(void) { } void Mapper227_Init(CartInfo *info) { + submapper =info->submapper; Latch_Init(info, M227Sync, NULL, 0x0000, 0x8000, 0xFFFF, 1); } @@ -476,15 +453,64 @@ void Mapper231_Init(CartInfo *info) { } /*------------------ Map 242 ---------------------------*/ - +static uint8 M242TwoChips; static void M242Sync(void) { + uint32 S = latche & 1; + uint32 p = (latche >> 2) & 0x1F; + uint32 L = (latche >> 9) & 1; + + if (M242TwoChips) { + if (latche &0x600) + { /* First chip */ + p &= 0x1F; + } + else + { /* Second chip */ + p &= 0x07; + p += 0x20; + } + } + + if ((latche >> 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 && (latche & 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(((latche >> 1) & 1) ^ 1); setchr8(0); setprg8r(0x10, 0x6000, 0); - setprg32(0x8000, (latche >> 3) & 0xf); - setmirror(((latche >> 1) & 1) ^ 1); } void Mapper242_Init(CartInfo *info) { + M242TwoChips = info->PRGRomSize &0x20000 && info->PRGRomSize >0x20000; Latch_Init(info, M242Sync, NULL, 0x0000, 0x8000, 0xFFFF, 1); } @@ -518,6 +544,21 @@ void Mapper288_Init(CartInfo *info) { AddExState(&dipswitch, 1, 0, "DIPSW"); } +/*------------------ Map 385 ---------------------------*/ + +static void M385Sync(void) { + int32 mirror = latche & 1; + int32 bank = (latche >> 1) & 0x7; + setprg16(0x8000, bank); + setprg16(0xc000, bank); + setmirror(mirror ^ 1); + setchr8(0); +} + +void Mapper385_Init(CartInfo *info) { + Latch_Init(info, M385Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0); +} + /*------------------ Map 541 ---------------------------*/ /* LittleCom 160-in-1 multicart */ static void M541Sync(void) { @@ -617,13 +658,12 @@ void BMCG146_Init(CartInfo *info) { /* NES 2.0 mapper 341 is used for a simple 4-in-1 multicart */ static void BMCTJ03Sync(void) { - uint8 mirr = ((latche >> 1) & 1) ^ 1; - uint8 bank = (latche >> 8) & 7; + uint8 mirr = latche &(PRGsize[0] &0x40000? 0x800: 0x200)? MI_H: MI_V; + uint8 bank = latche >> 8; setprg32(0x8000, bank); setchr8(bank); - if (bank == 3) mirr ^= 1; /* Twin Bee has incorrect mirroring */ setmirror(mirr); } @@ -678,3 +718,96 @@ void J2282_Init(CartInfo *info) { Latch_Init(info, J2282Sync, NULL, 0x0000, 0x8000, 0xFFFF, 0); } + +/* -------------- Mapper 409 ------------------------ */ +static void M409Sync(void) { + setprg16(0x8000, latche); + setprg16(0xC000, ~0); + setchr8(0); +} + +void Mapper409_Init(CartInfo *info) { + Latch_Init(info, M409Sync, NULL, 0x0000, 0xC000, 0xCFFF, 0); +} + +/*------------------ Map 435 ---------------------------*/ +static void M435Sync(void) { + int p =latche >>2 &0x1F | latche >>3 &0x20 | latche >>4 &0x40; + if (latche &0x200) { + if (latche &0x001) { + setprg16(0x8000, p); + setprg16(0xC000, p); + } else { + setprg32(0x8000, p >> 1); + } + } else { + setprg16(0x8000, p); + setprg16(0xC000, p | 7); + } + + if (latche &0x800) + SetupCartCHRMapping(0, CHRptr[0], 0x2000, 0); + else + SetupCartCHRMapping(0, CHRptr[0], 0x2000, 1); + + setmirror(latche &0x002? MI_H: MI_V); + setchr8(0); +} + +void Mapper435_Init(CartInfo *info) { + Latch_Init(info, M435Sync, NULL, 0x0000, 0x8000, 0xFFFF, 1); +} + +/*------------------ Map 459 ---------------------------*/ +static void M459Sync(void) { + int p =latche >>5; + int c =latche &0x03 | latche >>2 &0x04 | latche >>4 &0x08; + if (latche &0x04) { + setprg32(0x8000, p); + } else { + setprg16(0x8000, p <<1); + setprg16(0xC000, p <<1 |7); + } + setchr8(c &(latche &0x08? 0x0F: 0x08)); + setmirror(latche &0x100? MI_H: MI_V); +} + +void Mapper459_Init(CartInfo *info) { + Latch_Init(info, M459Sync, NULL, 0x0000, 0x8000, 0xFFFF, 1); +} + +/*------------------ Map 461 ---------------------------*/ +static void M461Sync(void) { + int p =latche <<1 | latche >>5 &1; + int c =latche >>8; + if (latche &0x10) { + setprg16(0x8000, p); + setprg16(0xC000, p); + } else { + setprg32(0x8000, p >>1); + } + setchr8(c); + setmirror(latche &0x80? MI_H: MI_V); +} + +void Mapper461_Init(CartInfo *info) { + Latch_Init(info, M461Sync, NULL, 0x0000, 0x8000, 0xFFFF, 1); +} + +/*------------------ Map 464 ---------------------------*/ +static void M464Sync(void) { + int p =latche >>7; + int c =latche &0x1F; + if (latche &0x40) { + setprg32(0x8000, p >> 1); + } else { + setprg16(0x8000, p); + setprg16(0xC000, p); + } + setchr8(c); + setmirror(latche &0x20? MI_H: MI_V); +} + +void Mapper464_Init(CartInfo *info) { + Latch_Init(info, M464Sync, NULL, 0x0000, 0x8000, 0xFFFF, 1); +} \ No newline at end of file diff --git a/src/boards/bandai.c b/src/boards/bandai.c index 375d2b0..99d04a0 100644 --- a/src/boards/bandai.c +++ b/src/boards/bandai.c @@ -65,116 +65,202 @@ static SFORMAT StateRegs[] = #define X24C0X_READ 3 #define X24C0X_WRITE 4 -static uint8 x24c0x_data[256], x24c0x_state; -static uint8 x24c0x_addr, x24c0x_word, x24c0x_latch, x24c0x_bitcount; -static uint8 x24c0x_sda, x24c0x_scl, x24c0x_out, x24c0x_oe; +static uint8 x24c0x_data[512]; -static SFORMAT x24c0xStateRegs[] = +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[] = { - { &x24c0x_addr, 1, "ADDR" }, - { &x24c0x_word, 1, "WORD" }, - { &x24c0x_latch, 1, "LATC" }, - { &x24c0x_bitcount, 1, "BITC" }, - { &x24c0x_sda, 1, "SDA" }, - { &x24c0x_scl, 1, "SCL" }, - { &x24c0x_out, 1, "OUT" }, - { &x24c0x_oe, 1, "OE" }, - { &x24c0x_state, 1, "STAT" }, + { &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 void x24c0x_init() { - x24c0x_addr = x24c0x_word = x24c0x_latch = x24c0x_bitcount = x24c0x_sda = x24c0x_scl = x24c0x_oe = 0; - x24c0x_state = X24C0X_STANDBY; +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 x24c0x_write(uint8 data) { - uint8 sda = (data >> 6) & 1; - uint8 scl = (data >> 5) & 1; - x24c0x_oe = (data >> 7); +static void x24c02_init(void) { + x24c02_addr = x24c02_word = x24c02_latch = x24c02_bitcount = x24c02_sda = x24c02_scl = 0; + x24c02_state = X24C0X_STANDBY; +} - if(x24c0x_scl && scl) { - if(x24c0x_sda && !sda) { /* START */ - x24c0x_state = X24C0X_ADDRESS; - x24c0x_bitcount = 0; - x24c0x_addr = 0; - } else if(!x24c0x_sda && sda) { /* STOP */ - x24c0x_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(!x24c0x_scl && scl) { /* RISING EDGE */ - switch(x24c0x_state) { + } else if(!x24c01_scl && scl) { /* RISING EDGE */ + switch(x24c01_state) { case X24C0X_ADDRESS: - if(x24c0x_bitcount < 7) { - x24c0x_addr <<= 1; - x24c0x_addr |= sda; + if(x24c01_bitcount < 7) { + x24c01_addr <<= 1; + x24c01_addr |= sda; } else { - if(!x24c02) /* X24C01 mode */ - x24c0x_word = x24c0x_addr; - if(sda) { /* READ COMMAND */ - x24c0x_state = X24C0X_READ; - } else { /* WRITE COMMAND */ - if(x24c02) /* X24C02 mode */ - x24c0x_state = X24C0X_WORD; - else - x24c0x_state = X24C0X_WRITE; - } + x24c01_word = x24c01_addr; + if(sda) /* READ COMMAND */ + x24c01_state = X24C0X_READ; + else /* WRITE COMMAND */ + x24c01_state = X24C0X_WRITE; } - x24c0x_bitcount++; - break; - case X24C0X_WORD: - if(x24c0x_bitcount == 8) { /* ACK */ - x24c0x_word = 0; - x24c0x_out = 0; - } else { /* WORD ADDRESS INPUT */ - x24c0x_word <<= 1; - x24c0x_word |= sda; - if(x24c0x_bitcount == 16) { /* END OF ADDRESS INPUT */ - x24c0x_bitcount = 7; - x24c0x_state = X24C0X_WRITE; - } - } - x24c0x_bitcount++; + x24c01_bitcount++; break; case X24C0X_READ: - if (x24c0x_bitcount == 8) { /* ACK */ - x24c0x_out = 0; - x24c0x_latch = x24c0x_data[x24c0x_word]; - x24c0x_bitcount = 0; - } else { /* REAL OUTPUT */ - x24c0x_out = x24c0x_latch >> 7; - x24c0x_latch <<= 1; - x24c0x_bitcount++; - if(x24c0x_bitcount == 8) { - x24c0x_word++; - x24c0x_word &= 0xff; + 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 (x24c0x_bitcount == 8) { /* ACK */ - x24c0x_out = 0; - x24c0x_latch = 0; - x24c0x_bitcount = 0; - } else { /* REAL INPUT */ - x24c0x_latch <<= 1; - x24c0x_latch |= sda; - x24c0x_bitcount++; - if(x24c0x_bitcount == 8) { - x24c0x_data[x24c0x_word] = x24c0x_latch; - x24c0x_word++; - x24c0x_word &= 0xff; + 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; } } - x24c0x_sda = sda; - x24c0x_scl = scl; + x24c01_sda = sda; + x24c01_scl = scl; } -static uint8 x24c0x_read() { - return x24c0x_out << 4; +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) { @@ -189,12 +275,7 @@ static void Sync(void) { setprg16(0x8000, reg[8]); setprg16(0xC000, ~0); } - 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; - } + SyncMirror(); } static DECLFW(BandaiWrite) { @@ -207,12 +288,20 @@ static DECLFW(BandaiWrite) { 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: x24c0x_write(V); break; + case 0x0D: + if (x24c02) + x24c02_write(V); + else + x24c01_write(V); + break; } } static DECLFR(BandaiRead) { - return (X.DB & 0xEF) | x24c0x_read(); + 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) { @@ -228,7 +317,10 @@ static void FP_FASTAPASS(1) BandaiIRQHook(int a) { static void BandaiPower(void) { IRQa = 0; - x24c0x_init(); + if (x24c02) + x24c02_init(); + else + x24c01_init(); Sync(); SetReadHandler(0x6000, 0x7FFF, BandaiRead); SetReadHandler(0x8000, 0xFFFF, CartBR); @@ -246,12 +338,12 @@ void Mapper16_Init(CartInfo *info) { MapIRQHook = BandaiIRQHook; info->battery = 1; - info->SaveGame[0] = x24c0x_data; + info->SaveGame[0] = x24c0x_data + 256; info->SaveGameLen[0] = 256; AddExState(x24c0x_data, 256, 0, "DATA"); GameStateRestore = StateRestore; - AddExState(&x24c0xStateRegs, ~0, 0, 0); + AddExState(&x24c02StateRegs, ~0, 0, 0); AddExState(&StateRegs, ~0, 0, 0); } @@ -267,7 +359,7 @@ void Mapper159_Init(CartInfo *info) { AddExState(x24c0x_data, 128, 0, "DATA"); GameStateRestore = StateRestore; - AddExState(&x24c0xStateRegs, ~0, 0, 0); + AddExState(&x24c01StateRegs, ~0, 0, 0); AddExState(&StateRegs, ~0, 0, 0); } @@ -323,7 +415,9 @@ static int BarcodeReadPos; static int BarcodeCycleCount; static uint32 BarcodeOut; -int FCEUI_DatachSet(const uint8 *rcode) { +/* #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 }, @@ -346,6 +440,7 @@ int FCEUI_DatachSet(const uint8 *rcode) { }; uint8 code[13 + 1]; uint32 tmp_p = 0; + uint32 csum = 0; int i, j; int len; @@ -359,15 +454,45 @@ int FCEUI_DatachSet(const uint8 *rcode) { #define BS(x) BarcodeData[tmp_p] = x; tmp_p++ - for (j = 0; j < 32; j++) { + 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) { - uint32 csum; for (i = 0; i < 6; i++) if (prefix_parity_type[code[0]][i]) { @@ -386,24 +511,25 @@ int FCEUI_DatachSet(const uint8 *rcode) { for (j = 0; j < 7; j++) { BS(data_right[code[i]][j]); } - csum = 0; - for (i = 0; i < 12; i++) csum += code[i] * ((i & 1) ? 3 : 1); - csum = (10 - (csum % 10)) % 10; + /* 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[csum][j]); + BS(data_right[code[12]][j]); } } else if (len == 8 || len == 7) { - uint32 csum = 0; - - for (i = 0; i < 7; i++) csum += (i & 1) ? code[i] : (code[i] * 3); - - csum = (10 - (csum % 10)) % 10; - - for (i = 0; i < 4; i++) + 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); @@ -412,7 +538,12 @@ int FCEUI_DatachSet(const uint8 *rcode) { 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]); } @@ -420,6 +551,7 @@ int FCEUI_DatachSet(const uint8 *rcode) { /* Right guard bars */ BS(1); BS(0); BS(1); +#endif for (j = 0; j < 32; j++) { BS(0x00); @@ -435,6 +567,26 @@ int FCEUI_DatachSet(const uint8 *rcode) { 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); @@ -452,7 +604,7 @@ static void FP_FASTAPASS(1) BarcodeIRQHook(int a) { } static DECLFR(BarcodeRead) { - return BarcodeOut; + return (X.DB & 0xE7) | ((x24c02_out | x24c01_out) << 4) | BarcodeOut; } static void M157Power(void) { @@ -462,20 +614,27 @@ static void M157Power(void) { BarcodeOut = 0; BarcodeCycleCount = 0; - Sync(); + x24c01_init(); + x24c02_init(); + BarcodeSync(); - SetWriteHandler(0x6000, 0xFFFF, BandaiWrite); SetReadHandler(0x6000, 0x7FFF, BarcodeRead); SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x8000, 0xFFFF, BarcodeWrite); } void Mapper157_Init(CartInfo *info) { - is153 = 1; + 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/bmc13in1jy110.c b/src/boards/bmc13in1jy110.c deleted file mode 100644 index c7bd349..0000000 --- a/src/boards/bmc13in1jy110.c +++ /dev/null @@ -1,97 +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 - * - * BMC 42-in-1 "reset switch" type - */ - -#include "mapinc.h" - -static uint8 bank_mode; -static uint8 bank_value; -static uint8 prgb[4]; -static SFORMAT StateRegs[] = -{ - { &bank_mode, 1, "BNM" }, - { &bank_value, 1, "BMV" }, - { prgb, 4, "PRGB" }, - { 0 } -}; - -static void Sync(void) { -/* FCEU_printf("%02x: %02x %02x\n", bank_mode, bank_value, prgb[0]); */ - switch (bank_mode & 7) { - case 0: - setprg32(0x8000, bank_value & 7); break; - case 1: - setprg16(0x8000, ((8 + (bank_value & 7)) >> 1) + prgb[1]); - setprg16(0xC000, (bank_value & 7) >> 1); - case 4: - setprg32(0x8000, 8 + (bank_value & 7)); break; - case 5: - setprg16(0x8000, ((8 + (bank_value & 7)) >> 1) + prgb[1]); - setprg16(0xC000, ((8 + (bank_value & 7)) >> 1) + prgb[3]); - case 2: - setprg8(0x8000, prgb[0] >> 2); - setprg8(0xa000, prgb[1]); - setprg8(0xc000, prgb[2]); - setprg8(0xe000, ~0); - break; - case 3: - setprg8(0x8000, prgb[0]); - setprg8(0xa000, prgb[1]); - setprg8(0xc000, prgb[2]); - setprg8(0xe000, prgb[3]); - break; - } -} - -static DECLFW(BMC13in1JY110Write) { -/* FCEU_printf("%04x:%04x\n",A,V); */ - switch (A) { - case 0x8000: - case 0x8001: - case 0x8002: - case 0x8003: prgb[A & 3] = V; break; - case 0xD000: bank_mode = V; break; - case 0xD001: setmirror(V & 3); - case 0xD002: break; - case 0xD003: bank_value = V; break; - } - Sync(); -} - -static void BMC13in1JY110Power(void) { - prgb[0] = prgb[1] = prgb[2] = prgb[3] = 0; - bank_mode = 0; - bank_value = 0; - setprg32(0x8000, 0); - setchr8(0); - SetWriteHandler(0x8000, 0xFFFF, BMC13in1JY110Write); - SetReadHandler(0x8000, 0xFFFF, CartBR); -} - -static void StateRestore(int version) { - Sync(); -} - -void BMC13in1JY110_Init(CartInfo *info) { - info->Power = BMC13in1JY110Power; - AddExState(&StateRegs, ~0, 0, 0); - GameStateRestore = StateRestore; -} diff --git a/src/boards/bmc42in1r.c b/src/boards/bmc42in1r.c index 3ac92b8..8675bbb 100644 --- a/src/boards/bmc42in1r.c +++ b/src/boards/bmc42in1r.c @@ -18,21 +18,16 @@ * You should have received a copy of the GNU General Public 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 42-in-1 "reset switch" + "select switch" - * */ /* Updated 2019-07-12 - * Mapper 266 - Updated and combine UNIF Ghostbusters63in1 board (1.5 MB carts), different bank order + * Mapper 226 - Updated and combine UNIF Ghostbusters63in1 board (1.5 MB carts), different bank order * - some 1MB carts can switch game lists using Select - * Mapper 233 - UNIF 42in1ResetSwitch - reset-based switching */ #include "mapinc.h" static uint8 reorder_banks = 0; -static uint8 isresetbased = 0; static uint8 latche[2], reset; static uint8 banks[4] = { 0, 0, 1, 2 }; static SFORMAT StateRegs[] = @@ -46,13 +41,9 @@ static void Sync(void) { uint8 bank = 0; uint8 base = ((latche[0] & 0x80) >> 7) | ((latche[1] & 1) << 1); - if (isresetbased) - bank = (latche[0] & 0x1f) | (reset << 5) | ((latche[1] & 1) << 6); - else { - if (reorder_banks) /* for 1536 KB prg roms */ - base = banks[base]; - bank = (base << 5) | (latche[0] & 0x1f); - } + if (reorder_banks) /* for 1536 KB prg roms */ + base = banks[base]; + bank = (base << 5) | (latche[0] & 0x1f); if (!(latche[0] & 0x20)) setprg32(0x8000, bank >> 1); @@ -70,7 +61,7 @@ static DECLFW(M226Write) { } static void M226Power(void) { - latche[0] = latche[1] = reset = 0; + latche[0] = latche[1] = 0; Sync(); SetWriteHandler(0x8000, 0xFFFF, M226Write); SetReadHandler(0x8000, 0xFFFF, CartBR); @@ -81,12 +72,11 @@ static void StateRestore(int version) { } static void M226Reset(void) { - latche[0] = latche[1] = reset = 0; + latche[0] = latche[1] = 0; Sync(); } void Mapper226_Init(CartInfo *info) { - isresetbased = 0; /* 1536KiB PRG roms have different bank order */ reorder_banks = ((info->PRGRomSize / 1024) == 1536) ? 1 : 0; info->Power = M226Power; @@ -94,18 +84,3 @@ void Mapper226_Init(CartInfo *info) { AddExState(&StateRegs, ~0, 0, 0); GameStateRestore = StateRestore; } - -static void M233Reset(void) { - latche[0] = latche[1] = 0; - reset ^= 1; - Sync(); -} - -void Mapper233_Init(CartInfo *info) { - reorder_banks = 0; - isresetbased = 1; - info->Power = M226Power; - info->Reset = M233Reset; - AddExState(&StateRegs, ~0, 0, 0); - GameStateRestore = StateRestore; -} diff --git a/src/boards/bmc60311c.c b/src/boards/bmc60311c.c index 9ea71fa..02c3b23 100644 --- a/src/boards/bmc60311c.c +++ b/src/boards/bmc60311c.c @@ -24,79 +24,51 @@ #include "mapinc.h" -static uint8 inner_bank, outer_bank, mode; +static uint8 latch, reg[2]; static SFORMAT StateRegs[] = { - { &inner_bank, 1, "INB0" }, - { &outer_bank, 1, "OUTB" }, - { &mode, 1, "MODE" }, + { &latch, 1, "LATC" }, + { reg, 2, "REGS" }, { 0 } }; static void Sync(void) { - uint8 bbank = (mode & 4) ? 0 : (inner_bank & 7); - uint8 bank = outer_bank | bbank; - uint8 preg[2]; - - /* 0: NROM-128: Same inner/outer 16 KiB bank at CPU $8000-$BFFF - * and $C000-$FFFF - * 1: NROM-256: 32 kiB bank at CPU $8000-$FFFF (Selected inner/outer bank SHR 1) - * 2: UNROM: Inner/outer bank at CPU $8000-BFFF, - * fixed inner bank 7 within outer bank at $C000-$FFFF - * 3: Unknown - * - * The combined inner/outer bank is simply the inner bank, selected by the - * latch at $8000-$FFFF (or 0 if the latch is disabled) ORed with the - * outer bank selected by $6001, without any bit shifting. - */ - - preg[0] = bank; - preg[1] = 0; - - switch (mode & 3) { - case 0x00: - case 0x01: - preg[1] = bank | ((mode & 1) ? 1 : 0); - break; - case 0x02: - preg[1] = outer_bank | 7; - case 0x03: - break; + if (reg[0] &2) { /* UNROM */ + setprg16(0x8000, latch &7 | reg[1] &~7); + setprg16(0xC000, 7 | reg[1] &~7); + } else + if (reg[0] &1) /* NROM-256 */ + setprg32(0x8000, reg[1] >>1); + else { /* NROM-128 */ + setprg16(0x8000, reg[1]); + setprg16(0xC000, reg[1]); } - + SetupCartCHRMapping(0, CHRptr[0], 0x2000, !(reg[0] &4)); /* CHR-RAM write-protect */ setchr8(0); - setprg16(0x8000, preg[0]); - setprg16(0xC000, preg[1]); - setmirror(((mode & 8) >> 3) ^ 1); + setmirror(!(reg[0] &8)); } -static DECLFW(Write0) { - mode = V; +static DECLFW(WriteReg) { + reg[A &1] =V; Sync(); } -static DECLFW(Write1) { - outer_bank = V; - Sync(); -} - -static DECLFW(Write8) { - inner_bank = V; +static DECLFW(WriteLatch) { + latch = V; Sync(); } static void BMC60311CPower(void) { - inner_bank = outer_bank = mode = 0; + latch =reg[0] =reg[1] =0; Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0x6000, Write0); - SetWriteHandler(0x6001, 0x6001, Write1); - SetWriteHandler(0x8000, 0xFFFF, Write8); + SetWriteHandler(0x6000, 0x6001, WriteReg); + SetWriteHandler(0x8000, 0xFFFF, WriteLatch); } static void BMC60311CReset(void) { - inner_bank = outer_bank = mode = 0; + latch =reg[0] =reg[1] =0; Sync(); } diff --git a/src/boards/bmc64in1nr.c b/src/boards/bmc64in1nr.c index 88c46cf..8a6cdb5 100644 --- a/src/boards/bmc64in1nr.c +++ b/src/boards/bmc64in1nr.c @@ -31,17 +31,17 @@ static SFORMAT StateRegs[] = }; static void Sync(void) { - if (regs[0] & 0x80) { + if (regs[0] & 0x80) { /* NROM mode */ if (regs[1] & 0x80) - setprg32(0x8000, regs[1] & 0x1F); + setprg32(0x8000, regs[1] & 0x3F); else { - int bank = ((regs[1] & 0x1f) << 1) | ((regs[1] >> 6) & 1); + int bank = ((regs[1] & 0x3F) << 1) | ((regs[1] >> 6) & 1); setprg16(0x8000, bank); setprg16(0xC000, bank); } - } else { - int bank = ((regs[1] & 0x1f) << 1) | ((regs[1] >> 6) & 1); - setprg16(0xC000, bank); + } else { /* UNROM mode */ + setprg16(0x8000, regs[1] <<1 | regs[3] &7); + setprg16(0xC000, regs[1] <<1 | 7); } if (regs[0] & 0x20) setmirror(MI_H); @@ -51,6 +51,8 @@ static void Sync(void) { } static DECLFW(BMC64in1nrWriteLo) { + A &=3; + if (A ==3) A =1; /* K-42001's "Aladdin III" */ regs[A & 3] = V; Sync(); } @@ -65,17 +67,26 @@ static void BMC64in1nrPower(void) { regs[1] = 0x43; regs[2] = regs[3] = 0; Sync(); - SetWriteHandler(0x5000, 0x5003, BMC64in1nrWriteLo); + SetWriteHandler(0x5000, 0x5FFF, BMC64in1nrWriteLo); SetWriteHandler(0x8000, 0xFFFF, BMC64in1nrWriteHi); SetReadHandler(0x8000, 0xFFFF, CartBR); } +static void BMC64in1nrReset(void) { + /* Reset returns to menu */ + regs[0] = 0x80; + regs[1] = 0x43; + regs[2] = regs[3] = 0; + Sync(); +} + static void StateRestore(int version) { Sync(); } void BMC64in1nr_Init(CartInfo *info) { info->Power = BMC64in1nrPower; + info->Reset = BMC64in1nrReset; AddExState(&StateRegs, ~0, 0, 0); GameStateRestore = StateRestore; } diff --git a/src/boards/bmc70in1.c b/src/boards/bmc70in1.c deleted file mode 100644 index 97fb34f..0000000 --- a/src/boards/bmc70in1.c +++ /dev/null @@ -1,123 +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 is_large_banks, hw_switch; -static uint8 large_bank; -static uint8 prg_bank; -static uint8 chr_bank; -static uint8 bank_mode; -static uint8 mirroring; -static SFORMAT StateRegs[] = -{ - { &large_bank, 1, "LB" }, - { &hw_switch, 1, "DPSW" }, - { &prg_bank, 1, "PRG" }, - { &chr_bank, 1, "CHR" }, - { &bank_mode, 1, "BM" }, - { &mirroring, 1, "MIRR" }, - { 0 } -}; - -static void Sync(void) { - switch (bank_mode) { - case 0x00: - case 0x10: - setprg16(0x8000, large_bank | prg_bank); - setprg16(0xC000, large_bank | 7); - break; - case 0x20: - setprg32(0x8000, (large_bank | prg_bank) >> 1); - break; - case 0x30: - setprg16(0x8000, large_bank | prg_bank); - setprg16(0xC000, large_bank | prg_bank); - break; - } - setmirror(mirroring); - if (!is_large_banks) - setchr8(chr_bank); -} - -static DECLFR(BMC70in1Read) { - if (bank_mode == 0x10) -/* if(is_large_banks) */ - return CartBR((A & 0xFFF0) | hw_switch); -#if 0 - else - return CartBR((A&0xFFF0)|hw_switch); -#endif - else - return CartBR(A); -} - -static DECLFW(BMC70in1Write) { - if (A & 0x4000) { - bank_mode = A & 0x30; - prg_bank = A & 7; - } else { - mirroring = ((A & 0x20) >> 5) ^ 1; - if (is_large_banks) - large_bank = (A & 3) << 3; - else - chr_bank = A & 7; - } - Sync(); -} - -static void BMC70in1Reset(void) { - bank_mode = 0; - large_bank = 0; - Sync(); - hw_switch++; - hw_switch &= 0xf; -} - -static void BMC70in1Power(void) { - setchr8(0); - bank_mode = 0; - large_bank = 0; - Sync(); - SetReadHandler(0x8000, 0xFFFF, BMC70in1Read); - SetWriteHandler(0x8000, 0xffff, BMC70in1Write); -} - -static void StateRestore(int version) { - Sync(); -} - -void BMC70in1_Init(CartInfo *info) { - is_large_banks = 0; - hw_switch = 0xd; - info->Power = BMC70in1Power; - info->Reset = BMC70in1Reset; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} - -void BMC70in1B_Init(CartInfo *info) { - is_large_banks = 1; - hw_switch = 0x6; - info->Power = BMC70in1Power; - info->Reset = BMC70in1Reset; - GameStateRestore = StateRestore; - AddExState(&StateRegs, ~0, 0, 0); -} diff --git a/src/boards/bmc80013b.c b/src/boards/bmc80013b.c index a58c77d..6bd8460 100644 --- a/src/boards/bmc80013b.c +++ b/src/boards/bmc80013b.c @@ -24,7 +24,6 @@ /* 2020-03-22 - Update support for Cave Story II, FIXME: Arabian does not work for some reasons... */ #include "mapinc.h" -#include "../ines.h" static uint8 regs[2], mode; diff --git a/src/boards/bmck3036.c b/src/boards/bmck3036.c index bd72ca3..73e03eb 100644 --- a/src/boards/bmck3036.c +++ b/src/boards/bmck3036.c @@ -18,41 +18,31 @@ * */ -/* NES 2.0 mapper 340 is used for a 35-in-1 multicart. - * Its UNIF board name is BMC-K-3036. - * http://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_340 - * TODO: Some games are not working... - */ - #include "mapinc.h" -static uint8 regs[2], mirr, mode; +static uint8 regs[2]; static SFORMAT StateRegs[] = { { regs, 2, "REGS" }, - { &mode, 1, "MODE" }, - { &mirr, 1, "MIRR" }, { 0 } }; static void Sync(void) { - if (mode) { /* NROM-128 */ - setprg16(0x8000, regs[0]); - setprg16(0xC000, regs[0]); - } else { /* UNROM */ - setprg16(0x8000, regs[0] | regs[1]); - setprg16(0xC000, regs[0] | 0x07); + if (regs[0] &0x20) { /* NROM-128 */ + setprg16(0x8000, regs[0] >>2 &0x20 | regs[0] &0x1F); + setprg16(0xC000, regs[0] >>2 &0x20 | regs[0] &0x1F); + } else { /* UNROM */ + setprg16(0x8000, regs[0] >>2 &0x20 | regs[0] | regs[1] &7); + setprg16(0xC000, regs[0] >>2 &0x20 | regs[0] | 7); } setchr8(0); - setmirror(mirr); + setmirror((regs[0] &0x40 || regs[0] &0x20 && regs[0] &0x04)? MI_H: MI_V); } static DECLFW(M340Write) { - regs[0] = A & 0x1F; - regs[1] = V & 0x07; - mode = A & 0x20; - mirr = ((A & 0x25) == 0x25) ? 0 : 1; + regs[0] = A & 0xFF; + regs[1] = V; Sync(); } @@ -63,7 +53,7 @@ static void BMCK3036Power(void) { } static void BMCK3036Reset(void) { - regs[0] = regs[1] = mode = mirr = 0; + regs[0] = regs[1] = 0; Sync(); } diff --git a/src/boards/cheapocabra.c b/src/boards/cheapocabra.c index 7730941..4535986 100644 --- a/src/boards/cheapocabra.c +++ b/src/boards/cheapocabra.c @@ -31,7 +31,6 @@ */ #include "mapinc.h" -#include "../ines.h" static uint8 reg; static uint8 *CHRRAM = NULL; diff --git a/src/boards/coolboy.c b/src/boards/coolboy.c deleted file mode 100644 index 5482550..0000000 --- a/src/boards/coolboy.c +++ /dev/null @@ -1,176 +0,0 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2015 CaH4e3, 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 - * - * CoolBoy 400-in-1 FK23C-mimic mapper 16Mb/32Mb PROM + 128K/256K CHR RAM, optional SRAM, optional NTRAM - * only MMC3 mode - * - * 6000 (xx76x210) | 0xC0 - * 6001 (xxx354x) - * 6002 = 0 - * 6003 = 0 - * - * hardware tested logic, don't try to understand lol - */ - -#include "mapinc.h" -#include "mmc3.h" - -static void COOLBOYCW(uint32 A, uint8 V) { - uint32 mask = 0xFF ^ (EXPREGS[0] & 0x80); - if (EXPREGS[3] & 0x10) { - if (EXPREGS[3] & 0x40) { /* Weird mode */ - int cbase = (MMC3_cmd & 0x80) << 5; - switch (cbase ^ A) { /* Don't even try to understand */ - case 0x0400: - case 0x0C00: V &= 0x7F; break; - } - } - /* Highest bit goes from MMC3 registers when EXPREGS[3]&0x80==0 or from EXPREGS[0]&0x08 otherwise */ - setchr1(A, - (V & 0x80 & mask) | ((((EXPREGS[0] & 0x08) << 4) & ~mask)) /* 7th bit */ - | ((EXPREGS[2] & 0x0F) << 3) /* 6-3 bits */ - | ((A >> 10) & 7) /* 2-0 bits */ - ); - } else { - if (EXPREGS[3] & 0x40) { /* Weird mode, again */ - int cbase = (MMC3_cmd & 0x80) << 5; - switch (cbase ^ A) { /* Don't even try to understand */ - case 0x0000: V = DRegBuf[0]; break; - case 0x0800: V = DRegBuf[1]; break; - case 0x0400: - case 0x0C00: V = 0; break; - } - } - /* Simple MMC3 mode - * Highest bit goes from MMC3 registers when EXPREGS[3]&0x80==0 or from EXPREGS[0]&0x08 otherwise - */ - setchr1(A, (V & mask) | (((EXPREGS[0] & 0x08) << 4) & ~mask)); - } -} - -static void COOLBOYPW(uint32 A, uint8 V) { - uint32 mask = ((0x3F | (EXPREGS[1] & 0x40) | ((EXPREGS[1] & 0x20) << 2)) ^ ((EXPREGS[0] & 0x40) >> 2)) ^ ((EXPREGS[1] & 0x80) >> 2); - uint32 base = ((EXPREGS[0] & 0x07) >> 0) | ((EXPREGS[1] & 0x10) >> 1) | ((EXPREGS[1] & 0x0C) << 2) | ((EXPREGS[0] & 0x30) << 2); - - /* Very weird mode - * Last banks are first in this mode, ignored when MMC3_cmd&0x40 - */ - if ((EXPREGS[3] & 0x40) && (V >= 0xFE) && !((MMC3_cmd & 0x40) != 0)) { - switch (A & 0xE000) { - case 0xA000: - if ((MMC3_cmd & 0x40)) V = 0; - break; - case 0xC000: - if (!(MMC3_cmd & 0x40)) V = 0; - break; - case 0xE000: - V = 0; - break; - } - } - - /* Regular MMC3 mode, internal ROM size can be up to 2048kb! */ - if (!(EXPREGS[3] & 0x10)) - setprg8(A, (((base << 4) & ~mask)) | (V & mask)); - else { /* NROM mode */ - uint8 emask; - mask &= 0xF0; - if ((((EXPREGS[1] & 2) != 0))) /* 32kb mode */ - emask = (EXPREGS[3] & 0x0C) | ((A & 0x4000) >> 13); - else /* 16kb mode */ - emask = EXPREGS[3] & 0x0E; - setprg8(A, ((base << 4) & ~mask) /* 7-4 bits are from base (see below) */ - | (V & mask) /* ... or from MM3 internal regs, depends on mask */ - | emask /* 3-1 (or 3-2 when (EXPREGS[3]&0x0C is set) from EXPREGS[3] */ - | ((A & 0x2000) >> 13)); /* 0th just as is */ - } -} - -static DECLFW(COOLBOYWrite) { - if(A001B & 0x80) - CartBW(A,V); - - /* Deny any further writes when 7th bit is 1 AND 4th is 0 */ - if ((EXPREGS[3] & 0x90) != 0x80) { - EXPREGS[A & 3] = V; - FixMMC3PRG(MMC3_cmd); - FixMMC3CHR(MMC3_cmd); - } -} - -static void COOLBOYReset(void) { - MMC3RegReset(); - EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; -#if 0 - EXPREGS[0] = 0; - EXPREGS[1] = 0x60; - EXPREGS[2] = 0; - EXPREGS[3] = 0; -#endif - FixMMC3PRG(MMC3_cmd); - FixMMC3CHR(MMC3_cmd); -} - -static void COOLBOYPower(void) { - GenMMC3Power(); - EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; -#if 0 - EXPREGS[0] = 0; - EXPREGS[1] = 0x60; - EXPREGS[2] = 0; - EXPREGS[3] = 0; -#endif - FixMMC3PRG(MMC3_cmd); - FixMMC3CHR(MMC3_cmd); - SetWriteHandler(0x5000, 0x5fff, CartBW); /* some games access random unmapped areas and crashes because of KT-008 PCB hack in MMC3 source lol */ - SetWriteHandler(0x6000, 0x7fff, COOLBOYWrite); -} - -void COOLBOY_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 8, 0); - pwrap = COOLBOYPW; - cwrap = COOLBOYCW; - info->Power = COOLBOYPower; - info->Reset = COOLBOYReset; - AddExState(EXPREGS, 4, 0, "EXPR"); -} - -/*------------------ MINDKIDS ---------------------------*/ -/* A COOLBOY variant that works identically but puts the outer bank registers - * in the $5xxx range instead of the $6xxx range. - * The UNIF board name is MINDKIDS (submapper 1). - * http://wiki.nesdev.com/w/index.php/NES_2.0_Mapper_268 - */ - -static void MINDKIDSPower(void) { - GenMMC3Power(); - EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; - FixMMC3PRG(MMC3_cmd); - FixMMC3CHR(MMC3_cmd); - SetWriteHandler(0x5000, 0x5fff, COOLBOYWrite); -} - -void MINDKIDS_Init(CartInfo *info) { - GenMMC3_Init(info, 2048, 256, 8, info->battery); - pwrap = COOLBOYPW; - cwrap = COOLBOYCW; - info->Power = MINDKIDSPower; - info->Reset = COOLBOYReset; - AddExState(EXPREGS, 4, 0, "EXPR"); -} diff --git a/src/boards/copyfami_emu.c b/src/boards/copyfami_emu.c deleted file mode 100644 index 96a22c3..0000000 --- a/src/boards/copyfami_emu.c +++ /dev/null @@ -1,355 +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 - */ - -#ifdef COPYFAMI - -#include "__serial.h" -#include "mapinc.h" -#include "mmc3.h" - -/* #define DEBUG_SERIAL */ - -/* *** COPY FAMICOM EMULATION *** */ - -/* - * - * - * $0000-$1FFF - * $2000-$200F PPU - * $2010-$3FFB - * $3FFC-$3FFF - * $4000-$7FFF APU / - * $8000-$FFF9 CART/ROM - * $FFFA-$FFFB CART/ NMI - * $FFFE-$FFFF CART/ IRQ - * - * - * - * CTRL R/W $3FFC ---aenic ($00 at reset) - * - * c - - * 0 - - * 1 - - * i - IRQ - * 0 - - * 1 - - * n - NMI - * 0 - - * 1 - - * e - NMI - * 0 - - * 1 - - * a - AROM - * 0 - - * 1 - - * - * BANK R/W $3FFD ---mbbbb - * - * b - - * m - ROM - * - * USBDATA R/W $3FFE dddddddd - * - * d - / - * - * STATUS R $3FFF vmnicptr - * - * r - USB - * 0 - - * 1 - - * t - USB - * 0 - - * 1 - - * p - USB - * 0 - - * 1 - - * c - - * 0 - - * 1 - - * i - IRQ - * 0 - - * 1 - - * n - NMI - * 0 - - * 1 - - * m - 10 VRAM () - * v - VRAM - * 0 - - * 1 - - * - * AROM - * - * VRAM - * 8000-FFFF - */ - -#define CTRL 0x00 -#define CCART 0x01 -#define CVIRQ 0x02 -#define CVNMI 0x04 -#define CDNMI 0x08 -#define CAROM 0x10 -#define BANK 0x01 -#define BMIRR 0x10 -#define USB 0x02 -#define STATUS 0x03 -#define SRX 0x01 -#define STX 0x02 -#define SPEN 0x04 -#define SCART 0x08 -#define SIRQ 0x10 -#define SNMI 0x20 -#define SA10 0x40 -#define SVRAM 0x80 - -#ifdef DEBUG_SERIAL -static uint8 debug_serial_data[] = { - 0xDE, 0xAD, 0xBE, 0xEF, 0x00, - 0xDE, 0xAD, 0xBE, 0xEF, 0x01, - - 0x02, - - 0x14, 0x50, 0xB0, - - 0x02, - - 0x14, 0x50, 0xB0, - - 0x02, -}; -static uint32 debug_serial_data_size = sizeof(debug_serial_data); -static uint32 debug_serial_data_pos; -#endif - -static uint8 *CHRRAM = NULL; -static uint32 CHRRAMSIZE; - -static uint8 regs[4]; - -static readfunc def_read_ram, def_read_rom; -static writefunc def_write_ram; - -static SFORMAT StateRegs[] = -{ - { regs, 4, "CREGS" }, - { 0 } -}; - -static void Sync() { - FixMMC3PRG(MMC3_cmd); - FixMMC3CHR(MMC3_cmd); -} - -static void MCopyFamiMMC3PW(uint32 A, uint8 V) { - if (regs[CTRL] & CCART) - setprg8(A, V); - else - setprg32r(1, 0x8000, (regs[BANK] & 0x0F) ^ 0x08); -} - -static void MCopyFamiMMC3CW(uint32 A, uint8 V) { - if ((regs[STATUS] & SCART) && (regs[CTRL] & CAROM)) - setchr8r(0x10, 0); - else - setchr1r(0, A, V); -} - -static void MCopyFamiMMC3MW(uint8 V) { - if (regs[CTRL] & CAROM) { - setmirror(MI_0 + ((regs[BANK] >> 4) & 1)); - } else { - A000B = V; - setmirror((V & 1) ^ 1); - } -} - -static uint32 direction = 0xffffffff; -static uint32 bytes_count = 0; - -static DECLFW(MCopyFamiWriteReg) { - if (((A & 3) == USB) && !fceuindbg) { - if (direction != 0) { - direction = 0; - bytes_count = 0; - FCEU_printf(" >"); - } -#ifndef DEBUG_SERIAL - while (!SerialSendChar(V)) { - } - ; -#endif - bytes_count++; -/* FCEU_printf(" %02X",V); */ - } else { - regs[A & 3] = V; - Sync(); - } -} - -static DECLFR(MCopyFamiReadReg) { -#ifdef DEBUG_SERIAL - if (debug_serial_data_pos == debug_serial_data_size) - regs[STATUS] |= SRX; - else - regs[STATUS] &= ~SRX; -#endif - if (!fceuindbg) { -#ifndef DEBUG_SERIAL - if ((A & 3) == STATUS) { - int data; - if ((data = SerialGetChar()) == EOF) - regs[STATUS] |= SRX; - else - regs[STATUS] &= ~SRX; - regs[USB] = data & 0xff; - } else -#endif - if ((A & 3) == USB) { -#ifdef DEBUG_SERIAL - regs[USB] = debug_serial_data[debug_serial_data_pos++]; -#endif - if (direction != 1) { - if (direction != 0xffffffff) FCEU_printf(" bytes sent: %08x", bytes_count); - direction = 1; - bytes_count = 0; - FCEU_printf("\n<"); - } - FCEU_printf(" %02X", regs[USB]); - } - } - return regs[A & 3]; -} - -static DECLFW(MCopyFamiMMC3Write) { - if (regs[CTRL] & CAROM) { - regs[BANK] = V & 0x1F; - Sync(); - } else { - if (A >= 0xC000) - MMC3_IRQWrite(A, V); - else - MMC3_CMDWrite(A, V); - } -} - -static DECLFW(MCopyFamiMMC3WriteNMI) { - if (regs[CTRL] & CVNMI) - def_write_ram(0x3FFC + (A & 1), V); - else - MCopyFamiMMC3Write(A, V); -} - -static DECLFW(MCopyFamiMMC3WriteIRQ) { - if (regs[CTRL] & CVIRQ) - def_write_ram(0x3FFE + (A & 1), V); - else - MCopyFamiMMC3Write(A, V); -} - -static DECLFR(MCopyFamiReadNMI) { - if (regs[CTRL] & CVNMI) - return def_read_ram(0x3FFC + (A & 1)); - else - return def_read_rom(A); -} - -static DECLFR(MCopyFamiReadIRQ) { - if (regs[CTRL] & CVIRQ) - return def_read_ram(0x3FFE + (A & 1)); - else - return def_read_rom(A); -} - -static void MCopyFamiMMC3Power(void) { - regs[CTRL] = regs[USB] = 0; - regs[STATUS] = SIRQ | SNMI | SVRAM; - regs[BANK] = 0x08; -#ifdef DEBUG_SERIAL - debug_serial_data_pos = 0; -#endif - GenMMC3Power(); - Sync(); - - def_write_ram = GetWriteHandler(0x3FFC); - SetWriteHandler(0x3FFC, 0x3FFF, MCopyFamiWriteReg); - def_read_ram = GetReadHandler(0x3FFC); - SetReadHandler(0x3FFC, 0x3FFF, MCopyFamiReadReg); - - SetWriteHandler(0x8000, 0xFFF9, MCopyFamiMMC3Write); - SetWriteHandler(0xFFFA, 0xFFFB, MCopyFamiMMC3WriteNMI); - SetWriteHandler(0xFFFE, 0xFFFF, MCopyFamiMMC3WriteIRQ); - - def_read_rom = GetReadHandler(0xFFFA); - SetReadHandler(0xFFFA, 0xFFFB, MCopyFamiReadNMI); - SetReadHandler(0xFFFE, 0xFFFF, MCopyFamiReadIRQ); -} - -static void MCopyFamiMMC3Reset(void) { - regs[CTRL] = regs[USB] = 0; - regs[STATUS] = SIRQ | SNMI | SVRAM; - regs[BANK] = 0x08; -#ifdef DEBUG_SERIAL - debug_serial_data_pos = 0; -#endif - MMC3RegReset(); - Sync(); -} - -static void MCopyFamiClose(void) { - if (CHRRAM) - FCEU_gfree(CHRRAM); - CHRRAM = NULL; - SerialClose(); -} - -static void StateRestore(int version) { - Sync(); -} - -void MapperCopyFamiMMC3_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 512, 8, 0); - - cwrap = MCopyFamiMMC3CW; - pwrap = MCopyFamiMMC3PW; - mwrap = MCopyFamiMMC3MW; - - info->Reset = MCopyFamiMMC3Reset; - info->Power = MCopyFamiMMC3Power; - info->Close = MCopyFamiClose; - GameStateRestore = StateRestore; - - CHRRAMSIZE = 8192; - CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSIZE); - SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); - AddExState(CHRRAM, CHRRAMSIZE, 0, "CRAM"); - -#ifndef DEBUG_SERIAL - FCEU_printf("WAITING FOR PORT...\n"); - - while (!SerialOpen(20, 921600)) { - } - - FCEU_printf("PORT READY.\n"); -#endif - - AddExState(&StateRegs, ~0, 0, 0); -} - -#endif diff --git a/src/boards/copyfami_hwi.c b/src/boards/copyfami_hwi.c deleted file mode 100644 index 72a05af..0000000 --- a/src/boards/copyfami_hwi.c +++ /dev/null @@ -1,590 +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 - */ - -#ifdef COPYFAMI - -/* *** COPY FAMICOM HARDWARE INTERFACE *** */ - -#define MESSAGE_LOG -#define NO_CACHE -#define NO_RAM - -#include "__serial.h" -#include "mapinc.h" - -#define FNV_32_PRIME ((uint32)0x01000193) - -#define CHR_CACHE_SIZE (1024 * 4) -#define WRAM_CACHE_SIZE (1024 / 2) -#define PRG_CACHE_SIZE (1024 / 4) -#define CMD_CACHE_SIZE (1024 * 128) - -#define CMD_MAX_SIZE (5) -#define CMD_MAX_RETEST (16) -#define CMD_MAX_VERIFY (16) - -static uint8 *WRAM = NULL; - -uint8 InitVector[] = { 0xDE, 0xAD, 0xBE, 0xEF };/* args none, return DE AD BE EF */ -uint8 ResetCmd[] = { 0x00 }; /* args none, return none */ -uint8 StateCmd[] = { 0x01 }; /* args none, return 7 bytes status */ -uint8 StatusCmd[] = { 0x02 }; /* args none, return 32 bytes status */ -uint8 LoadPlugCmd[] = { 0x03, 0x00, 0x00 }; /* args 2b size, Nb data return none */ -uint8 RunPlugCmd[] = { 0x04 }; /* args none, return none */ -uint8 RunGameCmd[] = { 0x05 }; /* args none, return none */ -uint8 NROMSave[] = { 0x06 }; /* args none, return 16b + 32kb + 8kb */ - -uint8 PRGWBCmd[] = { 0x08, 0x00, 0x00, 0x00 }; /* args 2b addr, 1b data return none */ -uint8 PRGRBCmd[] = { 0x09, 0x00, 0x00 }; /* args 2b addr return 1b data */ -uint8 CHRWBCmd[] = { 0x0A, 0x00, 0x00, 0x00 }; /* args 2b addr, 1b data return none */ -uint8 CHRRBCmd[] = { 0x0B, 0x00, 0x00 }; /* args 2b addr, return 1b data */ - -uint8 PRGSUMCmd[] = { 0x10, 0x00, 0x00 }; /* args 1b addr, 1b size return (256 * N)b */ -uint8 PRG32KSUMCmd[] = { 0x10, 0x80, 0x80 }; /* args 1b addr, 1b size return 32kb */ -uint8 PRG16KSUMCmd[] = { 0x10, 0x00, 0x40 }; /* args 1b addr, 1b size return 16kb */ -uint8 PRG8KSUMCmd[] = { 0x10, 0x00, 0x20 }; /* args 1b addr, 1b size return 8kb */ -uint8 PRG4KSUMCmd[] = { 0x10, 0x00, 0x10 }; /* args 1b addr, 1b size return 4kb */ - -uint8 CHRSUMCmd[] = { 0x11, 0x00, 0x00 }; /* args 1b addr, 1b size return (256 * N)b */ -uint8 CHR8KSUMCmd[] = { 0x11, 0x00, 0x20 }; /* args 1b addr, 1b size return 8kb */ -uint8 CHR4KSUMCmd[] = { 0x11, 0x00, 0x10 }; /* args 1b addr, 1b size return 4kb */ -uint8 CHR2KSUMCmd[] = { 0x11, 0x00, 0x08 }; /* args 1b addr, 1b size return 2kb */ -uint8 CHR1KSUMCmd[] = { 0x11, 0x00, 0x04 }; /* args 1b addr, 1b size return 1kb */ - -uint8 PRGGetCmd[] = { 0x12, 0x00, 0x00 }; /* args 1b addr, 1b size return (256 * N)b */ -uint8 PRG32KGetCmd[] = { 0x12, 0x80, 0x80 }; /* args 1b addr, 1b size return 32kb */ -uint8 PRG16KGetCmd[] = { 0x12, 0x00, 0x40 }; /* args 1b addr, 1b size return 16kb */ -uint8 PRG8KGetCmd[] = { 0x12, 0x00, 0x20 }; /* args 1b addr, 1b size return 8kb */ -uint8 PRG4KGetCmd[] = { 0x12, 0x00, 0x10 }; /* args 1b addr, 1b size return 4kb */ - -uint8 CHRGetCmd[] = { 0x13, 0x00, 0x00 }; /* args 1b addr, 1b size return (256 * N)b */ -uint8 CHR8KGetCmd[] = { 0x13, 0x00, 0x20 }; /* args 1b addr, 1b size return 8kb */ -uint8 CHR4KGetCmd[] = { 0x13, 0x00, 0x10 }; /* args 1b addr, 1b size return 4kb */ -uint8 CHR2KGetCmd[] = { 0x13, 0x00, 0x08 }; /* args 1b addr, 1b size return 2kb */ -uint8 CHR1KGetCmd[] = { 0x13, 0x00, 0x04 }; /* args 1b addr, 1b size return 1kb */ - -uint8 CPUTestCmd[] = { 0x14, 0x00, 0x00 }; /* args 1b addr, 1b size return (2b + 1b) * N + 3b */ - -typedef struct { - int32 mirror; - int32 chrsum[8]; - int32 prgsum[4]; -} SYNC_STATE; - -static SYNC_STATE state_cur, state_new, state_def; - -typedef struct { - uint8 *buf; - int32 count; -} DATA_BANKS; - -static DATA_BANKS chr_data; -static int32 chr_bank[0x10000]; -static DATA_BANKS prg_data; -static int32 prg_bank[0x10000]; - -typedef struct { - SYNC_STATE states[CMD_CACHE_SIZE]; - int32 seqs[CMD_CACHE_SIZE][CMD_MAX_SIZE]; - int32 count; -} SYNC_CMDS; - -typedef struct { - int32 seq[CMD_MAX_SIZE]; - int32 size; - int32 found; - uint32 hash; - uint16 hashf; -} SYNC_CMD; - -static SYNC_CMD cmd; -static SYNC_CMDS cmds; - -typedef struct { - int32 index; - int32 size; - int32 retest; - int32 verify; -} CMD_CACHE; - -static CMD_CACHE cmd_cache[0x10000]; - -static SFORMAT StateRegs[] = -{ - { state_cur.chrsum, sizeof(state_cur.chrsum), "CHRREG" }, - { state_cur.prgsum, sizeof(state_cur.prgsum), "ROMREG" }, - { &state_cur.mirror, sizeof(state_cur.mirror), "MIRREG" }, - { 0 } -}; - -#define MI_U 4 - -static char *mirror_names[5] = { "Horizontal", "Vertical", "Mirror 0", "Mirror 1", "Unknown mirror" }; -static int32 mirror_modes[16] = { - MI_0, MI_U, MI_U, MI_H, MI_U, MI_V, MI_U, MI_U, - MI_U, MI_U, MI_U, MI_U, MI_U, MI_U, MI_U, MI_1 -}; - -#define CHRDEF(slot) (chr_bank[state_def.chrsum[slot]]) -#define PRGDEF(slot) (prg_bank[state_def.prgsum[slot]]) -#define CHRCUR(slot) (chr_bank[state_cur.chrsum[slot]]) -#define PRGCUR(slot) (prg_bank[state_cur.prgsum[slot]]) -#define CHRNEW(slot) (chr_bank[state_new.chrsum[slot]]) -#define PRGNEW(slot) (prg_bank[state_new.prgsum[slot]]) - -static void GetStatus(SYNC_STATE *state) { - uint8 resp0; - uint16 resp1, i; - SEND(StatusCmd); - GET(resp0, 1); - state->mirror = resp0; - GET(resp0, 1); - for (i = 0; i < 8; i++) { - GET(resp1, 2); - state->chrsum[i] = resp1; - } - for (i = 0; i < 4; i++) { - GET(resp1, 2); - state->prgsum[i] = resp1; - } -} - -static int32 FetchNewCHRBank(int32 slot) { - FILE *ofile; - char name[256]; - int32 bank = chr_data.count++; - CHR1KGetCmd[1] = slot << 2; - SENDGET(CHR1KGetCmd, chr_data.buf[bank * 1024], 1024); - sprintf(name, "%04x.chr", bank); - ofile = fopen(name, "wb"); - fwrite((void*)&chr_data.buf[bank * 1024], 1, 1024, ofile); - fclose(ofile); - return bank; -} - -static int32 FetchNewPRGBank(int32 slot) { - FILE *ofile; - char name[256]; - int32 bank = prg_data.count++; - PRG8KGetCmd[1] = 0x80 + (slot << 5); - SENDGET(PRG8KGetCmd, prg_data.buf[bank * 8192], 8192); - sprintf(name, "%04x.prg", bank); - ofile = fopen(name, "wb"); - fwrite((void*)&prg_data.buf[bank * 8192], 1, 8192, ofile); - fclose(ofile); - return bank; -} - -static int CheckStatus(void) { - int32 i, ischanged = 0; - GetStatus(&state_new); - if (state_cur.mirror != state_new.mirror) { - state_cur.mirror = state_new.mirror; -#ifdef MESSAGE_LOG - FCEU_printf(">> mirror changed to %s (%02X)\n", mirror_names[mirror_modes[state_cur.mirror]], state_cur.mirror); -#endif - ischanged = 1; - } else { - state_new.mirror = -1; - } - for (i = 0; i < 8; i++) { - if (state_cur.chrsum[i] != state_new.chrsum[i]) { - state_cur.chrsum[i] = state_new.chrsum[i]; - if (CHRCUR(i) == -1) { - CHRCUR(i) = FetchNewCHRBank(i); -#ifdef MESSAGE_LOG - FCEU_printf(">> chr[%d] bank %d loaded\n", i, CHRCUR(i)); -#endif - } -#ifdef MESSAGE_LOG - else - FCEU_printf(">> chr[%d] bank %d switched\n", i, CHRCUR(i)); -#endif - ischanged = 1; - } else { - state_new.chrsum[i] = -1; - } - } - for (i = 0; i < 4; i++) { - if (state_cur.prgsum[i] != state_new.prgsum[i]) { - state_cur.prgsum[i] = state_new.prgsum[i]; - if (PRGCUR(i) == -1) { - PRGCUR(i) = FetchNewPRGBank(i); -#ifdef MESSAGE_LOG - FCEU_printf(">> prg[%d] bank %d loaded\n", i, PRGCUR(i)); -#endif - } -#ifdef MESSAGE_LOG - else - FCEU_printf(">> prg[%d] bank %d switched\n", i, PRGCUR(i)); -#endif - ischanged = 1; - } else { - state_new.prgsum[i] = -1; - } - } - return ischanged; -} - -#ifndef NO_CACHE -static void ApplyStatus() { - int32 i; - if ((cmds.states[cmd.found].mirror != -1) && (cmds.states[cmd.found].mirror != state_cur.mirror)) { - state_cur.mirror = cmds.states[cmd.found].mirror; - setmirror(mirror_modes[state_cur.mirror]); -#ifdef MESSAGE_LOG - FCEU_printf(">> mirror changed to %s (%02X)\n", mirror_names[mirror_modes[state_cur.mirror]], state_cur.mirror); -#endif - } - for (i = 0; i < 8; i++) { - int32 sum = cmds.states[cmd.found].chrsum[i]; - if (sum != -1) { - if (sum != state_cur.chrsum[i]) { - state_cur.chrsum[i] = sum; - setchr1r(1, i * 1024, CHRCUR(i)); -#ifdef MESSAGE_LOG - FCEU_printf(">> chr[%d] bank %d switched\n", i, chr_bank[sum]); -#endif - } else -#ifdef MESSAGE_LOG - FCEU_printf(">> chr[%d] bank %d switched the same\n", i, chr_bank[sum]); - } -#endif - } - for (i = 0; i < 4; i++) { - int32 sum = cmds.states[cmd.found].prgsum[i]; - if (sum != -1) { - if (sum != state_cur.prgsum[i]) { - state_cur.prgsum[i] = sum; - setprg8r(2, 0x8000 + (i * 8192), PRGCUR(i)); -#ifdef MESSAGE_LOG - FCEU_printf(">> prg[%d] bank %d switched\n", i, prg_bank[sum]); -#endif - } else -#ifdef MESSAGE_LOG - FCEU_printf(">> prg[%d] bank %d switched the same\n", i, prg_bank[sum]); - } -#endif - } - } - - static void LogCmd() { - int32 i; - FCEU_printf(">> new cmd size %d [", cmd_cache[cmd.hashf].size); - for (i = 0; i < cmd_cache[cmd.hashf].size; i++) - FCEU_printf(" %06X", cmds.seqs[cmd.found][i]); - FCEU_printf(" ], switched to ("); - if (cmds.states[cmd.found].mirror != -1) - FCEU_printf(" mirror=%s", mirror_names[mirror_modes[cmds.states[cmd.found].mirror]]); - for (i = 0; i < 8; i++) - if (cmds.states[cmd.found].chrsum[i] != -1) - FCEU_printf(" chr%d=%02X", i, chr_bank[cmds.states[cmd.found].chrsum[i]]); - for (i = 0; i < 4; i++) - if (cmds.states[cmd.found].prgsum[i] != -1) - FCEU_printf(" prg%d=%02X", i, prg_bank[cmds.states[cmd.found].prgsum[i]]); - FCEU_printf(" )\n"); - } -#endif -static void Sync() { - setchr1r(1, 0x0000, CHRCUR(0)); - setchr1r(1, 0x0400, CHRCUR(1)); - setchr1r(1, 0x0800, CHRCUR(2)); - setchr1r(1, 0x0C00, CHRCUR(3)); - setchr1r(1, 0x1000, CHRCUR(4)); - setchr1r(1, 0x1400, CHRCUR(5)); - setchr1r(1, 0x1800, CHRCUR(6)); - setchr1r(1, 0x1C00, CHRCUR(7)); -#ifndef NO_RAM - setprg8r(1, 0x6000, 0); -#endif - setprg8r(2, 0x8000, PRGCUR(0)); - setprg8r(2, 0xA000, PRGCUR(1)); - setprg8r(2, 0xC000, PRGCUR(2)); - setprg8r(2, 0xE000, PRGCUR(3)); - setmirror(mirror_modes[state_cur.mirror]); -} -#ifndef NO_CACHE -static void UpdateCmd(uint32 val) { - int32 index; - if (cmd.size < CMD_MAX_SIZE) { - index = cmd.size++; - } else { - /* , , , - * - */ - cmd.hash = 0; - for (index = 0; index < (CMD_MAX_SIZE - 1); index++) { - cmd.seq[index] = cmd.seq[index + 1]; - cmd.hash *= FNV_32_PRIME; - cmd.hash ^= cmd.seq[index]; - } - } - cmd.seq[index] = val; - cmd.hash *= FNV_32_PRIME; - cmd.hash ^= val; - cmd.hashf = (cmd.hash >> 16) ^ (cmd.hash & 0xffff); - cmd.found = cmd_cache[cmd.hashf].index; -} -#endif - -static DECLFW(MCopyFamiWrite) { -#ifndef NO_CACHE - int32 i; -#endif - -#ifdef MESSAGE_LOG - FCEU_printf("> WRITE %04X:%02X\n", A, V); -#endif - - PRGWBCmd[1] = A & 0xFF; - PRGWBCmd[2] = A >> 8; - PRGWBCmd[3] = V & 0xFF; - SEND(PRGWBCmd); -#ifdef NO_CACHE - CheckStatus(); - Sync(); -#else - UpdateCmd((A << 8) | V); - /* */ - if (cmd.found == -1) { - /* , , - * - */ - cmd_cache[cmd.hashf].index = cmd.found = cmds.count++; - cmd_cache[cmd.hashf].retest = 0; - cmd_cache[cmd.hashf].verify = 0; - for (i = 0; i < cmd.size; i++) - cmds.seqs[cmd.found][i] = cmd.seq[i]; - cmd_cache[cmd.hashf].size = cmd.size; - if (CheckStatus()) { - cmds.states[cmd.found] = state_new; - LogCmd(); - cmd.size = 0; - cmd.hash = 0; - Sync(); - } else { - /* */ - cmd_cache[cmd.hashf].index = -2; - } - } else if (cmd.found == -2) { - /* , */ - if (cmd_cache[cmd.hashf].retest < CMD_MAX_RETEST) { - /* */ - if (CheckStatus()) { - /* , */ - cmd_cache[cmd.hashf].index = cmd.found = cmds.count++; - cmd_cache[cmd.hashf].retest = 0; - cmd_cache[cmd.hashf].verify = 0; - for (i = 0; i < cmd.size; i++) - cmds.seqs[cmd.found][i] = cmd.seq[i]; - cmd_cache[cmd.hashf].size = cmd.size; - cmds.states[cmd.found] = state_new; - LogCmd(); - cmd.size = 0; - cmd.hash = 0; - Sync(); - } else { - /* , */ - cmd_cache[cmd.hashf].retest++; - } - } - } else { - /* , */ -#if 0 - if(cmd_cache[cmd.hashf].verify < CMD_MAX_VERIFY) { - if(CheckStatus()) { - int32 changed = 0; - if(cmds.states[cmd.found].mirror != state_new.mirror) - changed = 1; - for(i=0; i<8; i++) - if(cmds.states[cmd.found].chrsum[i] != state_new.chrsum[i]) - changed = 1; - for(i=0; i<4; i++) - if(cmds.states[cmd.found].prgsum[i] != state_new.prgsum[i]) - changed = 1; - if(changed) { - cmd_cache[cmd.hashf].index = -1; - cmd_cache[cmd.hashf].retest = 0; - cmd_cache[cmd.hashf].verify = 0; - Sync(); - } - } else - cmd_cache[cmd.hashf].verify++; - } else -#endif - { - /* */ - ApplyStatus(); - cmd.size = 0; - cmd.hash = 0; - } - } -#endif -} - -static DECLFR(MCopyFamiRead) { - uint8 result; - PRGRBCmd[1] = A & 0xFF; - PRGRBCmd[2] = A >> 8; - SENDGET(PRGRBCmd, result, 1); -#ifdef MESSAGE_LOG - FCEU_printf("> READ %04X:%02X\n", A, result); -#endif - return result; -} - -static void MCopyFamiReset(void) { - state_cur = state_def; - Sync(); -} - -static void MCopyFamiPower(void) { -/* uint32 resp, presp; */ - - FCEU_printf("NOW POWERING... "); - - Sync(); - - SetWriteHandler(0x4018, 0x7fff, MCopyFamiWrite); - SetReadHandler(0x4018, 0x7fff, MCopyFamiRead); -#ifndef NO_RAM - SetWriteHandler(0x6000, 0x7fff, CartBW); - SetReadHandler(0x6000, 0x7fff, CartBR); -#endif - -#if 0 - FCEU_printf("READING MEMORY MAP...\n"); - CPUTestCmd[1] = 0x50; - CPUTestCmd[2] = 0x30; - SEND(CPUTestCmd); - resp = 0; - presp = 0xffffffff; - while (presp != 0x00ff0000) { - GET(resp, 3); - if(presp != 0xffffffff) { - switch(presp & 0x00FF0000) { - case 0x00000000: /* BUS */ - FCEU_printf(" %04X-%04X OPEN BUS\n",presp & 0x7fff, (resp - 1) & 0x7fff); - break; - case 0x00010000: /* RAM */ - FCEU_printf(" %04X-%04X RAM\n",presp & 0x7fff, (resp - 1) & 0x7fff); - SetWriteHandler(presp & 0x7fff, (resp - 1) & 0x7fff, CartBW); - SetReadHandler(presp & 0x7fff, (resp - 1) & 0x7fff, CartBR); - break; - } - } - presp = resp; - } -#endif - SetWriteHandler(0x8000, 0xffff, MCopyFamiWrite); - SetReadHandler(0x8000, 0xffff, CartBR); - - FCEU_printf("DONE!\nNOW COLLECTING DATA...\n"); -} - -static void MCopyFamiClose(void) { - if (chr_data.buf) - FCEU_gfree(chr_data.buf); - chr_data.buf = NULL; - if (prg_data.buf) - FCEU_gfree(prg_data.buf); - prg_data.buf = NULL; - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; - - SerialClose(); -} - -static void StateRestore(int version) { - Sync(); -} - -void MapperCopyFami_Init(CartInfo *info) { - uint32 resp = 0, i, size; - - memset(chr_bank, -1, sizeof(chr_bank)); - memset(prg_bank, -1, sizeof(chr_bank)); - memset(cmd_cache, -1, sizeof(cmd_cache)); - memset(&cmds, 0, sizeof(cmds)); - memset(&cmd, 0, sizeof(cmd)); - - info->Reset = MCopyFamiReset; - info->Power = MCopyFamiPower; - info->Close = MCopyFamiClose; - GameStateRestore = StateRestore; - - size = 1024 * CHR_CACHE_SIZE; /* 1 */ - chr_data.buf = (uint8*)FCEU_gmalloc(size); - SetupCartCHRMapping(1, chr_data.buf, size, 1); /* , */ - AddExState(chr_data.buf, size, 0, "CCHR"); - - size = 8192; /* 8 */ - WRAM = (uint8*)FCEU_gmalloc(size); - SetupCartPRGMapping(1, WRAM, size, 1); - AddExState(WRAM, size, 0, "CPRM"); - - size = 8192 * PRG_CACHE_SIZE; /* 8 */ - prg_data.buf = (uint8*)FCEU_gmalloc(size); - SetupCartPRGMapping(2, prg_data.buf, size, 0); - AddExState(prg_data.buf, size, 0, "CPPR"); - - - FCEU_printf("WAITING FOR SERIAL PORT... "); - while (!SerialOpen(19, 921600)) { - Sleep(500); - } - FCEU_printf("READY!\n"); - - FCEU_printf("WAITING FOR DEVICE... "); - - while (resp != *(uint32*)&InitVector[0]) { - SEND(ResetCmd); - SENDGET(InitVector, resp, 4); - Sleep(500); - } - - FCEU_printf("READY!\n"); - FCEU_printf("READING STATUS...\n"); - GetStatus(&state_cur); - FCEU_printf("MIRRORING IS %s (%02X)\n", mirror_names[mirror_modes[state_cur.mirror]], state_cur.mirror); - FCEU_printf("READING CHR...\n INITIAL STATE:"); - - for (i = 0; i < 8; i++) { - if (CHRCUR(i) == -1) - CHRCUR(i) = FetchNewCHRBank(i); - FCEU_printf(" CHR%d=%02X", i, CHRCUR(i)); - } - FCEU_printf("\n"); - - FCEU_printf("READING PRG...\n INITIAL STATE:"); - for (i = 0; i < 4; i++) { - if (PRGCUR(i) == -1) - PRGCUR(i) = FetchNewPRGBank(i); - FCEU_printf(" PRG%d=%02X", i, PRGCUR(i)); - } - FCEU_printf("\nDONE!\n"); - - state_def = state_cur; - - AddExState(&StateRegs, ~0, 0, 0); -} - -#endif diff --git a/src/boards/datalatch.c b/src/boards/datalatch.c index 9f85609..d51dd3f 100644 --- a/src/boards/datalatch.c +++ b/src/boards/datalatch.c @@ -19,7 +19,6 @@ */ #include "mapinc.h" -#include "../ines.h" #include "../fds_apu.h" static uint8 latche, latcheinit, bus_conflict; @@ -126,15 +125,6 @@ void NROM_Init(CartInfo *info) { /*------------------ Map 2 ---------------------------*/ static void UNROMSync(void) { -#if 0 - static uint32 mirror_in_use = 0; - if (PRGsize[0] <= 128 * 1024) { - setprg16(0x8000, latche & 0x7); - if ((latche & 0xF8) == 0x08) mirror_in_use = 1; - if (mirror_in_use) - setmirror(((latche >> 3) & 1) ^ 1); /* Higway Star Hacked mapper to be redefined to another mapper */ - } else -#endif setprg8r(0x10, 0x6000, 0); setprg16(0x8000, latche); setprg16(0xc000, ~0); @@ -142,7 +132,8 @@ static void UNROMSync(void) { } void UNROM_Init(CartInfo *info) { - Latch_Init(info, UNROMSync, 0, 0x8000, 0xFFFF, 1, 0); + /* By default, do not emulate bus conflicts except when explicitly told by a NES 2.0 header to do so. */ + Latch_Init(info, UNROMSync, 0, 0x8000, 0xFFFF, 1, info->iNES2 && info->submapper == 2); } /*------------------ Map 3 ---------------------------*/ @@ -154,11 +145,8 @@ static void CNROMSync(void) { } void CNROM_Init(CartInfo *info) { - uint8 CNROM_busc = 1; /* by default, CNROM is set to emulate bus conflicts to all games. */ - if (info->submapper && info->submapper == 1) /* no bus conflict */ - CNROM_busc = 0; - FCEU_printf(" Bus Conflict: %s\n", CNROM_busc ? "Yes" : "No"); - Latch_Init(info, CNROMSync, 0, 0x8000, 0xFFFF, 1, CNROM_busc); + /* By default, do not emulate bus conflicts except when explicitly told by a NES 2.0 header to do so. */ + Latch_Init(info, CNROMSync, 0, 0x8000, 0xFFFF, 1, info->iNES2 && info->submapper == 2); } /*------------------ Map 7 ---------------------------*/ @@ -472,6 +460,18 @@ void Mapper241_Init(CartInfo *info) { Latch_Init(info, M241Sync, 0, 0x8000, 0xFFFF, 1, 0); } +/*------------------ Map 271 ---------------------------*/ + +static void M271Sync(void) { + setchr8(latche & 0x0F); + setprg32(0x8000, latche >> 4); + setmirror((latche >> 5) & 1); +} + +void Mapper271_Init(CartInfo *info) { + Latch_Init(info, M271Sync, 0, 0x8000, 0xFFFF, 0, 0); +} + /*------------------ Map 381 ---------------------------*/ /* 2-in-1 High Standard Game (BC-019), reset-based */ static uint8 reset = 0; @@ -524,33 +524,34 @@ void Mapper538_Init(CartInfo *info) { * 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 (latche & 0x40) setprg32(0x8000, (latche >> 1) & 0x0F); else { if (A65ASsubmapper == 1) { - setprg16(0x8000, ((latche & 0x38) >> 0) | (latche & 7)); - setprg16(0xC000, ((latche & 0x38) >> 0) | 7); - } else { setprg16(0x8000, ((latche & 0x30) >> 1) | (latche & 7)); setprg16(0xC000, ((latche & 0x30) >> 1) | 7); + } else { + setprg16(0x8000, latche & 0x0F); + setprg16(0xC000, latche & 0x0F | 7); } } setchr8(0); if (latche & 0x80) setmirror(MI_0 + (((latche >> 5) & 1))); - else { - if (A65ASsubmapper == 1) /* added as workaround since games for this cart uses vertical mirroring */ - setmirror(MI_V); - else - setmirror(((latche >> 3) & 1) ^ 1); - } + else + setmirror(((latche >> 3) & 1) ^ 1); } void BMCA65AS_Init(CartInfo *info) { - A65ASsubmapper = info->submapper; /* not a real submapper */ + A65ASsubmapper = info->submapper; Latch_Init(info, BMCA65ASSync, 0, 0x8000, 0xFFFF, 0, 0); } @@ -581,3 +582,39 @@ static void BMCK3046Sync(void) { void BMCK3046_Init(CartInfo *info) { Latch_Init(info, BMCK3046Sync, 0, 0x8000, 0xFFFF, 0, 0); } + +/* Mapper 429: LIKO BBG-235-8-1B/Milowork FCFC1 */ + +static void Mapper429_Sync(void) { + setprg32(0x8000, latche >>2); + setchr8(latche); +} + +static void Mapper429_Reset(void) { + latche = 4; /* Initial CHR bank 0, initial PRG bank 1 */ + Mapper429_Sync(); +} + +void Mapper429_Init(CartInfo *info) { + info->Reset = Mapper429_Reset; + Latch_Init(info, Mapper429_Sync, 0, 0x8000, 0xFFFF, 0, 0); +} + +/*------------------ Mapper 415 ---------------------------*/ + +static void Mapper415_Sync(void) { + setprg8(0x6000, latche & 0x0F); + setprg32(0x8000, ~0); + setchr8(0); + setmirror(((latche >> 4) & 1) ^ 1); +} + +static void M415Power(void) { + LatchPower(); + SetReadHandler(0x6000, 0x7FFF, CartBR); +} + +void Mapper415_Init(CartInfo *info) { + Latch_Init(info, Mapper415_Sync, 0, 0x8000, 0xFFFF, 0, 0); + info->Power = M415Power; +} diff --git a/src/boards/eeprom_93C66.c b/src/boards/eeprom_93C66.c new file mode 100644 index 0000000..9f793ec --- /dev/null +++ b/src/boards/eeprom_93C66.c @@ -0,0 +1,140 @@ +#include "eeprom_93C66.h" + +uint8* eeprom_93C66_storage; +uint8 eeprom_93C66_opcode; +uint8 eeprom_93C66_data; +uint16 eeprom_93C66_address; +uint8 eeprom_93C66_state; +uint8 eeprom_93C66_lastCLK; +uint8 eeprom_93C66_writeEnabled; +uint8 eeprom_93C66_output; + +#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_ADDRESS 12 +#define STATE_DATA 20 +#define STATE_FINISHED 99 + +void eeprom_93C66_init () +{ + eeprom_93C66_address =0; + eeprom_93C66_state =STATE_STANDBY; + eeprom_93C66_lastCLK =0; + eeprom_93C66_writeEnabled =0; +} + +uint8 eeprom_93C66_read () +{ + 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 >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 <512; i++) + eeprom_93C66_storage[i] = 0xFF; + } + eeprom_93C66_state = STATE_FINISHED; + break; + case OPCODE_WRITEALL: + eeprom_93C66_address = 0; + break; + } + break; + case OPCODE_ERASE: + if (eeprom_93C66_writeEnabled) eeprom_93C66_storage[eeprom_93C66_address] = 0xFF; + eeprom_93C66_state = STATE_FINISHED; + break; + case OPCODE_READ: + eeprom_93C66_data = eeprom_93C66_storage[eeprom_93C66_address++]; + break; + } + } + else + if (eeprom_93C66_state ==STATE_DATA) + { + if (eeprom_93C66_opcode ==OPCODE_WRITE) + { + eeprom_93C66_storage[eeprom_93C66_address++] = eeprom_93C66_data; + eeprom_93C66_state = STATE_FINISHED; + } + else + if (eeprom_93C66_opcode ==OPCODE_WRITEALL) + { + eeprom_93C66_storage[eeprom_93C66_address++] = eeprom_93C66_data; + eeprom_93C66_state = CS && eeprom_93C66_address <512? STATE_ADDRESS: STATE_FINISHED; + } + else + if (eeprom_93C66_opcode ==OPCODE_READ) + { + if (eeprom_93C66_address <512) eeprom_93C66_data = eeprom_93C66_storage[eeprom_93C66_address]; + eeprom_93C66_state = CS && ++eeprom_93C66_address <=512? STATE_ADDRESS: STATE_FINISHED; + } + } + if (eeprom_93C66_state == STATE_FINISHED) + { + eeprom_93C66_output = 0; + eeprom_93C66_state = STATE_STANDBY; + } + } + eeprom_93C66_lastCLK = CLK; +} diff --git a/src/boards/eeprom_93C66.h b/src/boards/eeprom_93C66.h new file mode 100644 index 0000000..458f02e --- /dev/null +++ b/src/boards/eeprom_93C66.h @@ -0,0 +1,10 @@ +#ifndef _EEPROM_93C66_H +#define _EEPROM_93C66_H +#include "mapinc.h" + +extern uint8* eeprom_93C66_storage; + +void eeprom_93C66_init (); +uint8 eeprom_93C66_read (); +void eeprom_93C66_write (uint8 CS, uint8 CLK, uint8 DAT); +#endif diff --git a/src/boards/emu2413.h b/src/boards/emu2413.h index a0c173c..b14833b 100644 --- a/src/boards/emu2413.h +++ b/src/boards/emu2413.h @@ -1,7 +1,6 @@ #ifndef _EMU2413_H_ #define _EMU2413_H_ -#include #include #include #include diff --git a/src/boards/fk23c.c b/src/boards/fk23c.c index acb781a..ac22b6d 100644 --- a/src/boards/fk23c.c +++ b/src/boards/fk23c.c @@ -2,7 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2006 CaH4e3 - * Copyright (C) 2020 negativeExponent + * 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 @@ -19,31 +19,35 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* BMC-FK23C (no WRAM, no DIP switch) - * BMC-FK23CA (no WRAM, with DIP switch) - * BMC-Super24in1SC03 (functional duplicate of BMC-FK23C) - * WAIXING-FS005 (alternative name: Bensheng BS-001) (32 KiB battery-backed WRAM, 8 KiB of CHR-RAM, no DIP switch) - * WAIXING-FS006 (optional 8 KiB battery-backed WRAM, optional 8 KiB of CHR-RAM, no DIP switch) +/* Mappers: + 176 - Standard + 523 - Jncota KT-xxx, re-release of 封神榜꞉ 伏魔三太子: 1 KiB->2 KiB, 2 KiB->4 KiB CHR, hard-wired nametable mirroring) - * Three incompatible subtypes exist that do not correspond to these UNIF board names. No submappers have been proposed, as the subtypes can be easily discerned heuristically by looking at ROM sizes: - - * Subtype 0, ROM size other than specified below: boot with Extended MMC3 mode disabled (boots in first 512 KiB of PRG-ROM regardless of ROM size) - * Subtype 1, 1024 KiB PRG-ROM, 1024 KiB CHR-ROM: boot with Extended MMC3 mode enabled (boots in last 512 KiB of the first 2 MiB of PRG-ROM) - * Subtype 2, 8192 or more KiB PRG-ROM, no CHR-ROM: Like Subtype 0, but MMC3 registers $46 and $47 swapped. - */ - -/* 2020-3-14 - Refactoring based on latest sources */ -/* TODO: Add database for ines 1.0 headers */ + Submappers: + 0 - Standard + 1 - FK-xxx + 2 - 外星 FS005/FS006 + 3 - JX9003B + 4 - GameStar Smart Genius Deluxe + 5 - HST-162 + + Verified on real hardware: + "Legend of Kage" sets CNROM latch 1 and switches between CHR bank 0 and 1 using 5FF2, causing the wrong bank (1 instead of 0) during gameplay. + + Heuristic for detecting whether the DIP switch should be changed on every soft reset: + The first write to the $5xxx range is to $501x => ROM always addresses $501x; changing the DIP switch on reset would break the emulation after reset, so don't do it. + The first write to the $5xxx range is to $5020 or higher => ROM either uses a DIP switch or writes to $5FFx for safety; changing the DIP switch on reset is possible. + Exclude the $5FF3 address as well as $5000-$500F from this heuristic. +*/ #include "mapinc.h" -#include "../ines.h" static uint8 *WRAM = NULL; static uint8 *CHRRAM = NULL; static uint32 WRAMSIZE = 0; static uint32 CHRRAMSIZE = 0; -static uint8 fk23_regs[4] = { 0 }; +static uint8 fk23_regs[8] = { 0 }; /* JX9003B has eight registers, all others have four */ static uint8 mmc3_regs[12] = { 0 }; static uint8 mmc3_ctrl = 0; static uint8 mmc3_mirr = 0; @@ -52,15 +56,20 @@ static uint8 irq_count = 0; static uint8 irq_latch = 0; static uint8 irq_enabled = 0; static uint8 irq_reload = 0; -static uint8 cnrom_chr = 0; +static uint8 latch = 0; static uint8 dipswitch = 0; -static uint8 subType = 0; -static uint8 is_bmcfk23ca = 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) */ + +extern uint32 ROM_size; +extern uint32 VROM_size; static SFORMAT StateRegs[] = { - { fk23_regs, 4, "EXPR" }, + { fk23_regs, 8, "EXPR" }, { mmc3_regs, 12, "M3RG" }, - { &cnrom_chr, 1, "CCHR" }, + { &latch, 1, "LATC" }, { &dipswitch, 1, "DPSW" }, { &mmc3_ctrl, 1, "M3CT" }, { &mmc3_mirr, 1, "M3MR" }, @@ -73,41 +82,50 @@ static SFORMAT StateRegs[] = { { 0 } }; -#define INVERT_PRG (mmc3_ctrl & 0x40) -#define INVERT_CHR (mmc3_ctrl & 0x80) -#define WRAM_ENABLED (mmc3_wram & 0x80) -#define WRAM_EXTENDED (mmc3_wram & 0x20) -#define FK23_ENABLED (mmc3_wram & 0x40) -#define MMC3_EXTENDED (fk23_regs[3] & 0x02) -#define CHR_CNROM_MODE (fk23_regs[0] & 0x40) -#define CHR_OUTER_BANK_SIZE (fk23_regs[0] & 0x10) +#define INVERT_PRG !!(mmc3_ctrl & 0x40) +#define INVERT_CHR !!(mmc3_ctrl & 0x80) +#define WRAM_ENABLED !!(mmc3_wram & 0x80) +#define WRAM_EXTENDED (!!(mmc3_wram & 0x20) && subType == 2) /* Extended A001 register. Only available on FS005 PCB. */ +#define FK23_ENABLED (!!(mmc3_wram & 0x40) || !WRAM_EXTENDED) /* Enable or disable registers in the $5xxx range. Only available on FS005 PCB. */ +#define PRG_MODE ( fk23_regs[0] & 0x07) +#define MMC3_EXTENDED !!( fk23_regs[3] & 0x02) /* Extended MMC3 mode, adding extra registers for switching the normally-fixed PRG banks C and E and for eight independent 1 KiB CHR banks. Only available on FK- and FS005 PCBs. */ +#define CHR_8K_MODE !!( fk23_regs[0] & 0x40) /* MMC3 CHR registers are ignored, apply outer bank only, and CNROM latch if it exists */ +#define CHR_CNROM_MODE (~fk23_regs[0] & 0x20 && (subType == 1 || subType == 5)) /* Only subtypes 1 and 5 have a CNROM latch, which can be disabled */ +#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(uint16 A, uint16 V) +static void cwrap(uint32 A, uint32 V) { int bank = 0; - /* some workaround for chr rom / ram access */ - if (!VROM_size) - bank = 0; - else if (CHRRAMSIZE && fk23_regs[0] & 0x20) - bank = 0x10; - - if (WRAM_EXTENDED) { - if ((mmc3_wram & 0x04) && V < 8) bank = 0x10; /* first 8K of chr bank is ram */ - else bank = 0; + if (jncota523) + { + if (~A &0x0400) setchr2r(bank, A, V); + } + else + { + /* some workaround for chr rom / ram access */ + if (!VROM_size) + bank = 0; + else if (CHRRAMSIZE && fk23_regs[0] & 0x20) + bank = 0x10; + + if (CHR_MIXED && V < 8) bank = 0x10; /* first 8K of chr bank is RAM */ + + setchr1r(bank, A, V); } - - setchr1r(bank, A, V); } static void SyncCHR(void) { - if (CHR_CNROM_MODE) + 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. */ + if (CHR_8K_MODE) { - uint8 mask = (fk23_regs[3] & 0x46) ? (CHR_OUTER_BANK_SIZE ? 0x01 : 0x03) : 0; - uint16 bank = (fk23_regs[2] | (cnrom_chr & mask)) << 3; + 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); + cwrap(0x0000, bank + 0); cwrap(0x0400, bank + 1); cwrap(0x0800, bank + 2); cwrap(0x0C00, bank + 3); @@ -119,81 +137,98 @@ static void SyncCHR(void) } else { + uint32 cbase = (INVERT_CHR? 0x1000: 0); + uint32 mask = (CHR_OUTER_BANK_SIZE? 0x7F: 0xFF); + outer = (outer << 3) & ~mask; /* From 8 KiB to 1 KiB banks. Address bits are never OR'd; they either come from the outer bank or from the MMC3. */ + if (MMC3_EXTENDED) { - uint16 cbase = INVERT_CHR ? 0x1000 : 0; - uint16 outer = fk23_regs[2] << 3; + 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 ^ 0x0000, mmc3_regs[0] | outer); - cwrap(cbase ^ 0x0400, mmc3_regs[10] | outer); - cwrap(cbase ^ 0x0800, mmc3_regs[1] | outer); - cwrap(cbase ^ 0x0c00, mmc3_regs[11] | outer); - - cwrap(cbase ^ 0x1000, mmc3_regs[2] | outer); - cwrap(cbase ^ 0x1400, mmc3_regs[3] | outer); - cwrap(cbase ^ 0x1800, mmc3_regs[4] | outer); - cwrap(cbase ^ 0x1c00, mmc3_regs[5] | 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); } else { - uint16 cbase = INVERT_CHR ? 0x1000 : 0; - uint8 mask = CHR_OUTER_BANK_SIZE ? 0x7F : 0xFF; - uint16 outer = (fk23_regs[2] << 3) & ~mask; + 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 ^ 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); + 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); } } } static void SyncPRG(void) { - uint8 prg_mode = fk23_regs[0] & 7; - uint16 prg_base = (fk23_regs[1] & 0x07F) | ((fk23_regs[0] << 4) & 0x080) | - ((fk23_regs[0] << 1) & 0x100) | ((fk23_regs[2] << 3) & 0x600) | - ((fk23_regs[2] << 6) & 0x800); - - switch (prg_mode) + 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. */ + switch (subType) { - case 4: - setprg32(0x8000, prg_base >> 1); - break; - case 3: - setprg16(0x8000, prg_base); - setprg16(0xC000, prg_base); - break; - case 0: - case 1: - case 2: - if (MMC3_EXTENDED) - { - uint16 cbase = INVERT_PRG ? 0x4000 : 0; - uint16 outer = prg_base << 1; + case 1: /* FK-xxx */ + if (PRG_MODE == 0) mask = 0xFF; /* Mode 0 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 == 0) mask = 0xFF; /* Mode 0 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 */ + prg_base |= fk23_regs[2] & 0x80; + break; + case 5: /* HST-162 */ + prg_base = prg_base &0x1F | fk23_regs[5] <<5; + break; + } - setprg8(0x8000 ^ cbase, mmc3_regs[6] | outer); - setprg8(0xA000, mmc3_regs[7] | outer); - setprg8(0xC000 ^ cbase, mmc3_regs[8] | outer); - setprg8(0xE000, mmc3_regs[9] | outer); - } - else + switch (PRG_MODE) + { + case 0: /* MMC3 with 512 KiB or 2 MiB addressable */ + case 1: /* MMC3 with 256 KiB addressable */ + case 2: /* MMC3 with 128 KiB addressable */ { - uint16 cbase = INVERT_PRG ? 0x4000 : 0; - uint8 mask = 0x3F >> prg_mode; - uint16 outer = (prg_base << 1) & ~mask; - - setprg8(0x8000 ^ cbase, (mmc3_regs[6] & mask) | outer); - setprg8(0xA000, (mmc3_regs[7] & mask) | outer); - setprg8(0xC000 ^ cbase, (0xFE & mask) | outer); - setprg8(0xE000, (0xFF & mask) | outer); + uint32 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); + setprg8(0xC000 ^ cbase, mmc3_regs[8] & mask | prg_base); + setprg8(0xE000, mmc3_regs[9] & mask | prg_base); + } + else + { + setprg8(0x8000 ^ cbase, (mmc3_regs[6] & mask) | prg_base); + setprg8(0xA000, (mmc3_regs[7] & mask) | prg_base); + setprg8(0xC000 ^ cbase, (0xFE & mask) | prg_base); + setprg8(0xE000, (0xFF & mask) | prg_base); + } + break; } - break; + case 3: /* NROM-128 */ + setprg16(0x8000, prg_base); + setprg16(0xC000, prg_base); + break; + case 4: /* NROM-256 */ + setprg32(0x8000, (prg_base >> 1)); + break; + case 5: /* UNROM */ + setprg16(0x8000, latch & 0x07 | prg_base &~0x07); + setprg16(0xC000, 0x07 | prg_base ); + break; } } @@ -204,7 +239,6 @@ static void SyncWRAM(void) { if (WRAM_EXTENDED) { - /* FIXME:this does not look normal, but it works, $5000-$5fff */ setprg8r(0x10, 0x4000, (mmc3_wram & 0x03) + 1); setprg8r(0x10, 0x6000, mmc3_wram & 0x03); } @@ -215,12 +249,15 @@ static void SyncWRAM(void) static void SyncMIR(void) { - switch (mmc3_mirr & (WRAM_EXTENDED ? 0x03 : 0x01)) + 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; + case 0: setmirror(MI_V); break; + case 1: setmirror(MI_H); break; + case 2: setmirror(MI_0); break; + case 3: setmirror(MI_1); break; } } @@ -232,138 +269,106 @@ static void Sync(void) SyncMIR(); } -static DECLFW(WriteLo) +static DECLFW(Write4800) /* Only used by submapper 5 (HST-162) */ { - if (((WRAM_EXTENDED == 0) || FK23_ENABLED) && (A & (0x10 << dipswitch))) + fk23_regs[5] = V; /* Register 4800 is a separate register, but we use one of the ASIC registers that is otherwise unused in submapper 5 */ + SyncPRG(); +} +static DECLFW(Write5000) +{ + if (after_power && A > 0x5010 && 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 */ + } + if (FK23_ENABLED && (A & (0x10 << dipswitch))) { - switch (A & 3) - { - case 0: - if (fk23_regs[0] != V) - { - fk23_regs[0] = V; - SyncPRG(); - SyncCHR(); - } - break; - case 1: - if (fk23_regs[1] != V) - { - fk23_regs[1] = V; - SyncPRG(); - } - break; - case 2: - cnrom_chr = 0; - if (fk23_regs[2] != V) - { - fk23_regs[2] = V; - SyncPRG(); - SyncCHR(); - } - break; - case 3: - if (fk23_regs[3] != V) - { - fk23_regs[3] = V; - SyncPRG(); - SyncCHR(); - } - break; - } + fk23_regs[A & (subType == 3? 7: 3)] = V; + SyncPRG(); + SyncCHR(); } else /* FK23C Registers disabled, $5000-$5FFF maps to the second 4 KiB of the 8 KiB WRAM bank 2 */ CartBW(A, V); } -static DECLFW(WriteHi) +static DECLFW(Write8000) { - switch (A & 0xE000) - { - case 0x8000: - case 0x9000: - case 0xC000: - case 0xD000: - case 0xE000: - case 0xF000: - if (CHR_CNROM_MODE) - { - cnrom_chr = V & 0x03; - - if ((fk23_regs[0] & 0x07) == 0x03) - cnrom_chr = 0; - - SyncCHR(); - } - break; - } - + latch = V; + if (CHR_8K_MODE && CHR_CNROM_MODE) SyncCHR(); /* CNROM latch updated */ + if (PRG_MODE == 5) SyncPRG(); /* UNROM latch has been updated */ + switch (A & 0xE001) { - case 0x8000: - { - uint8 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) + case 0x8000: { - if (V == 0x46) - V = 0x47; - else if (V == 0x47) - V = 0x46; - } - - mmc3_ctrl = V; - - if (INVERT_PRG != (old_ctrl & 0x40)) - SyncPRG(); - - if (INVERT_CHR != (old_ctrl & 0x80)) - SyncCHR(); - - break; - } - case 0x8001: - { - uint8 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)) - SyncCHR(); - else + uint8 old_ctrl; + 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) + V = 0x47; + else if (V == 0x47) + V = 0x46; + } + + mmc3_ctrl = V; + + if (INVERT_PRG != (old_ctrl & 0x40)) SyncPRG(); + + if (INVERT_CHR != (old_ctrl & 0x80)) + SyncCHR(); + + break; } - break; - } - case 0xA000: - mmc3_mirr = V; - SyncMIR(); - break; - case 0xA001: - /* ignore bits when ram config register is disabled */ - if ((V & 0x20) == 0) - V &= 0xC0; - mmc3_wram = V; - Sync(); - break; - case 0xC000: - irq_latch = V; - break; - case 0xC001: - irq_reload = 1; - break; - case 0xE000: - X6502_IRQEnd(FCEU_IQEXT); - irq_enabled = 0; - break; - case 0xE001: - irq_enabled = 1; - break; + case 0x8001: + { + uint8 ctrl_mask; + 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)) + SyncCHR(); + else + SyncPRG(); + } + break; + } + case 0xA000: + mmc3_mirr = V; + SyncMIR(); + break; + case 0xA001: + /* ignore bits when ram config register is disabled */ + if ((V & 0x20) == 0) + V &= 0xC0; + mmc3_wram = V; + Sync(); + break; + case 0xC000: + irq_latch = V; + break; + case 0xC001: + irq_reload = 1; + break; + case 0xE000: + X6502_IRQEnd(FCEU_IQEXT); + irq_enabled = 0; + break; + case 0xE001: + irq_enabled = 1; + break; + default: + break; } } @@ -383,12 +388,12 @@ static void IRQHook(void) static void Reset(void) { /* this little hack makes sure that we try all the dip switch settings eventually, if we reset enough */ - /*if (is_bmcfk23ca) { + if (dipsw_enable) { dipswitch = (dipswitch + 1) & 7; - printf("BMCFK23C dipswitch set to $%04x\n",0x5000|0x10 << dipswitch); - }*/ + FCEU_printf("BMCFK23C dipswitch set to $%04x\n",0x5000|0x10 << dipswitch); + } - fk23_regs[0] = fk23_regs[1] = fk23_regs[2] = fk23_regs[3] = 0; + fk23_regs[0] = fk23_regs[1] = fk23_regs[2] = fk23_regs[3] = 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; @@ -404,15 +409,12 @@ static void Reset(void) mmc3_wram = 0x80; mmc3_ctrl = mmc3_mirr = irq_count = irq_latch = irq_enabled = 0; - if (subType == 1) - fk23_regs[1] = 0x20; - Sync(); } static void Power(void) { - fk23_regs[0] = fk23_regs[1] = fk23_regs[2] = fk23_regs[3] = 0; + fk23_regs[0] = fk23_regs[1] = fk23_regs[2] = fk23_regs[3] = 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; @@ -428,14 +430,14 @@ static void Power(void) mmc3_wram = 0x80; mmc3_ctrl = mmc3_mirr = irq_count = irq_latch = irq_enabled = 0; - if (subType == 1) - fk23_regs[1] = 0x20; - Sync(); SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x5000, 0x5fff, WriteLo); - SetWriteHandler(0x8000, 0xFFFF, WriteHi); + SetWriteHandler(0x5000, 0x5FFF, Write5000); + SetWriteHandler(0x8000, 0xFFFF, Write8000); + + if (subType == 5) + SetWriteHandler(0x4800, 0x4FFF, Write4800); if (WRAMSIZE) { @@ -461,10 +463,9 @@ static void StateRestore(int version) Sync(); } -void GenBMCFK23C_Init(CartInfo *info) +void Init(CartInfo *info) { - is_bmcfk23ca = 0; - + /* Initialization for iNES and UNIF. subType and dipsw_enable must have been set. */ info->Power = Power; info->Reset = Reset; info->Close = Close; @@ -488,73 +489,116 @@ void GenBMCFK23C_Init(CartInfo *info) if (info->battery) { info->SaveGame[0] = WRAM; - info->SaveGameLen[0] = info->PRGRamSaveSize ? info->PRGRamSaveSize : WRAMSIZE; + if (info->iNES2 && info->PRGRamSaveSize) + info->SaveGameLen[0] = info->PRGRamSaveSize; + else + info->SaveGameLen[0] = WRAMSIZE; } } - subType = 0; - if (((ROM_size * 16) == 1024) && ((VROM_size * 8) == 1024)) - subType = 1; - else if (UNIFchrrama && ((ROM_size << 4) >= 8192)) - subType = 2; } -/* generic entry point for mapper 176 / bmcfk23c carts */ -void BMCFK23C_Init(CartInfo *info) { - /* prepare ROM params before loading... */ +void Mapper176_Init(CartInfo *info) { /* .NES file */ + dipsw_enable = 0; + jncota523 = 0; if (info->iNES2) { - if (!UNIFchrrama) - CHRRAMSIZE = info->CHRRamSize + info->CHRRamSaveSize; + subType = info->submapper; + after_power = subType != 2; /* FS005 never has DIP switches, the others may have one, so use the heuristic. */ + CHRRAMSIZE = info->CHRRamSize + info->CHRRamSaveSize; WRAMSIZE = info->PRGRamSize + info->PRGRamSaveSize; } else { - if (!UNIFchrrama) - { - /* Rockman I - VI uses mixed chr rom/ram */ - if ((ROM_size * 16) == 2048 && (VROM_size * 8) == 512) - CHRRAMSIZE = 8 * 1024; - } - - /* Only waixing boards has battery backed wram, so only declare - * size when battery is set */ + /* Waixing boards have 32K battery backed wram */ if (info->battery) + { + subType = 2; + after_power = 0; WRAMSIZE = 32 * 1024; + } + else + { + /* 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; + + /* Detect heuristically whether the address mask should be changed on every soft reset */ + after_power = 1; + } } - - GenBMCFK23C_Init(info); + Init(info); } -/* UNIF Boards, declares so we can for chr mixed mode size and wram if any */ - -void BMCFK23CA_Init(CartInfo *info) +void BMCFK23C_Init(CartInfo *info) /* UNIF FK23C. Also includes mislabelled WAIXING-FS005, recognizable by their PRG-ROM size. */ { - /* can use mixed chr rom/ram */ if (!UNIFchrrama) - CHRRAMSIZE = 8 * 1024; + { + /* Rockman I-VI uses mixed chr rom/ram */ + if ((ROM_size * 16) == 2048 && (VROM_size * 8) == 512) + CHRRAMSIZE = 8 * 1024; + } + WRAMSIZE = 8 * 1024; - GenBMCFK23C_Init(info); - is_bmcfk23ca = 1; + 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) + CHRRAMSIZE = 256 * 1024; + + Init(info); } -/* BMC-Super24in1SC03 */ -void Super24_Init(CartInfo *info) { - /* can use mixed chr rom/ram */ - if (!UNIFchrrama) - CHRRAMSIZE = 8 * 1024; - - GenBMCFK23C_Init(info); -} - -void WAIXINGFS005_Init(CartInfo *info) +void BMCFK23CA_Init(CartInfo *info) /* UNIF FK23CA. Also includes mislabelled WAIXING-FS005, recognizable by their PRG-ROM size. */ { - /* can have 8 or 32 KB battery-backed prg ram - * plus 8 KB chr for these boards */ - if (!UNIFchrrama) - CHRRAMSIZE = 8 * 1024; + WRAMSIZE = 8 * 1024; + dipsw_enable = 0; + after_power = 1; + jncota523 = 0; + subType =ROM_size *16 >=2048? 2: 1; + if (subType == 2) + CHRRAMSIZE = 256 * 1024; + + Init(info); +} + +void Super24_Init(CartInfo *info) /* UNIF BMC-Super24in1SC03 */ +{ + CHRRAMSIZE = 8 * 1024; + dipsw_enable = 0; + after_power = 0; + jncota523 = 0; + subType = 0; + Init(info); +} + +void WAIXINGFS005_Init(CartInfo *info) /* UNIF WAIXING-FS005 */ +{ + CHRRAMSIZE = 8 * 1024; WRAMSIZE = 32 * 1024; - - GenBMCFK23C_Init(info); + dipsw_enable = 0; + after_power = 0; + jncota523 = 0; + subType = 2; + Init(info); +} + +void Mapper523_Init(CartInfo *info) /* Jncota Fengshengban */ +{ + WRAMSIZE = 8 * 1024; + dipsw_enable = 0; + after_power = 0; + jncota523 = 1; + subType = 1; + Init(info); } diff --git a/src/boards/gn26.c b/src/boards/gn26.c index 0af480b..ecaf5f9 100644 --- a/src/boards/gn26.c +++ b/src/boards/gn26.c @@ -27,26 +27,25 @@ #include "mmc3.h" static void BMCGN26CW(uint32 A, uint8 V) { - uint32 base = (EXPREGS[0] & 0x03) << 7; - setchr1(A, base | (V & 0xFF)); + int chrAND = EXPREGS[0]&0x04? 0xFF: 0x7F; + int chrOR = EXPREGS[0] <<7; + setchr1(A, V &chrAND | chrOR &~chrAND); } static void BMCGN26PW(uint32 A, uint8 V) { - /* Re-ordered -> 0:SF4 1:Contra Force 2:Revolution Hero */ - uint32 table[] = { 0, 0, 1, 2 }; - uint32 base = table[(EXPREGS[0] & 0x03)]; - if (EXPREGS[0] & 4) { if (A == 0x8000) - setprg32(0x8000, (base << 2) | (V >> 2)); + setprg32(0x8000, (EXPREGS[0] << 2) | (V >> 2)); } else - setprg8(A, (base << 4) | (V & 0x0F)); + setprg8(A, (EXPREGS[0] << 4) | (V & 0x0F)); } static DECLFW(BMCGN26Write) { - EXPREGS[0] = A & 0x0F; - FixMMC3PRG(MMC3_cmd); - FixMMC3CHR(MMC3_cmd); + if (A001B &0x80 && ~A001B &0x40) { + EXPREGS[0] = A; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + } } static void BMCGN26Reset(void) { @@ -56,7 +55,7 @@ static void BMCGN26Reset(void) { static void BMCGN26Power(void) { GenMMC3Power(); - SetWriteHandler(0x6800, 0x68FF, BMCGN26Write); + SetWriteHandler(0x6000, 0x7FFF, BMCGN26Write); } void BMCGN26_Init(CartInfo *info) { diff --git a/src/boards/hp10xx_hp20xx.c b/src/boards/hp10xx_hp20xx.c index c18c9d1..496c1e0 100644 --- a/src/boards/hp10xx_hp20xx.c +++ b/src/boards/hp10xx_hp20xx.c @@ -20,7 +20,6 @@ #include "mapinc.h" #include "mmc3.h" -#include "../ines.h" /* added on 2019-5-23 - NES 2.0 Mapper 260 * HP10xx/HP20xx - a simplified version of FK23C mapper with pretty strict and better diff --git a/src/boards/hp898f.c b/src/boards/hp898f.c index a3ace3f..5ce27df 100644 --- a/src/boards/hp898f.c +++ b/src/boards/hp898f.c @@ -20,45 +20,25 @@ #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 uint8 _submapper = 0; static SFORMAT StateRegs[] = { { regs, 2, "REGS" }, - { &_submapper ,1, "SUBM"}, { 0 } }; -/* submapper 1 The code for the original fceux - * submapper 0 new HP898F code by dragon2snow,loong2snow from www.nesbbs.com - */ -static void Sync(void) { - - if (_submapper == 1) - { - 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); - } - else - { - if (regs[1] & 0x40) - setprg32(0x8000, regs[1] >> 1); - else { - setprg16(0x8000, regs[1]); - setprg16(0xC000, regs[1]); - } - setchr8((regs[0] >> 4) &~(((regs[0] & 1) ? 4 : 0) | (regs[0] & 2))); - if (regs[1] & 0x80) - setmirror(1); - else - setmirror(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) { @@ -68,27 +48,11 @@ static DECLFW(HP898FWrite) { } } -static DECLFW(HP898FWriteEx) { - switch (A & 4) { - case 0: regs[0] = V; break; /* CHR */ - case 4: regs[1] = (V & 0xC0) | ((V >> 2) & 6) | ((V & 0x20) ? 1 : 0); break; /* PRG */ - } - Sync(); -} static void HP898FPower(void) { regs[0] = regs[1] = 0; Sync(); - if (_submapper == 1) - { - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0xFFFF, HP898FWrite); - } - else - { - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0x7FFF, HP898FWriteEx); - SetWriteHandler(0xE000, 0xFFFF, HP898FWriteEx); - } + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0xFFFF, HP898FWrite); } static void HP898FReset(void) { @@ -101,7 +65,6 @@ static void StateRestore(int version) { } void BMCHP898F_Init(CartInfo *info) { - _submapper = info->submapper; info->Reset = HP898FReset; info->Power = HP898FPower; GameStateRestore = StateRestore; diff --git a/src/boards/jyasic.c b/src/boards/jyasic.c new file mode 100644 index 0000000..89fd170 --- /dev/null +++ b/src/boards/jyasic.c @@ -0,0 +1,795 @@ +/* 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" + +void (*sync)(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, 8*2, "CHRB" }, + { &nt[0], 2 | FCEUSTATE_RLSB, "NMS0" }, + { &nt[1], 2 | FCEUSTATE_RLSB, "NMS1" }, + { &nt[2], 2 | FCEUSTATE_RLSB, "NMS2" }, + { &nt[3], 2 | FCEUSTATE_RLSB, "NMS3" }, + { &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; + if (irqEnabled) + switch (irqControl &0xC0) + { + case 0x40: + irqPrescaler =(irqPrescaler &~mask) | (++irqPrescaler &mask); + if ((irqPrescaler &mask) ==0x00 && (irqControl &0x08? irqCounter: ++irqCounter) ==0x00) + X6502_IRQBegin(FCEU_IQEXT); + break; + case 0x80: + irqPrescaler =(irqPrescaler &~mask) | (--irqPrescaler &mask); + if ((irqPrescaler &mask) ==mask && (irqControl &0x08? irqCounter: --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. */ + sync(); + } + 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; + sync(); +} + +static DECLFW(writeCHRLow) +{ + chr[A &7] =chr[A &7] &0xFF00 | V; + sync(); +} + +static DECLFW(writeCHRHigh) +{ + chr[A &7] =chr[A &7] &0x00FF | V <<8; + sync(); +} + +static DECLFW(writeNT) +{ + if (~A &4) + nt[A &3] =nt[A &3] &0xFF00 | V; + else + nt[A &3] =nt[A &3] &0x00FF | V <<8; + sync(); +} + +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; + } + sync(); +} + +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; + + sync(); +} + +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) +{ + sync(); +} + +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; + sync =syncSingleCart; + JYASIC_init(info); +} +void Mapper90_Init(CartInfo *info) +{ + /* Single cart, extended mirroring and ROM nametables disabled */ + allowExtendedMirroring =0; + sync =syncSingleCart; + JYASIC_init(info); +} + +void Mapper209_Init(CartInfo *info) +{ + /* Single cart, extended mirroring and ROM nametables enabled */ + allowExtendedMirroring =1; + sync =syncSingleCart; + JYASIC_init(info); +} + +void Mapper211_Init(CartInfo *info) +{ + /* Duplicate of mapper 209 */ + allowExtendedMirroring =1; + sync =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; + sync =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; + sync =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; + sync =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; + sync =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; + sync =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; + sync =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; + sync =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; + sync =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; + sync =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) + sync(); + 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); + sync(); + } + 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; + sync =sync394; + JYASIC_init(info); + GenMMC3_Init(info, 128, 128, 0, 0); + pwrap =Mapper394_PWrap; + cwrap =Mapper394_CWrap; + info->Reset = Mapper394_power; + info->Power = Mapper394_power; + AddExState(HSK007Reg, 4, 0, "HSK "); + GameStateRestore = Mapper394_restore; +} diff --git a/src/boards/le05.c b/src/boards/le05.c index 59eab1a..cd2000e 100644 --- a/src/boards/le05.c +++ b/src/boards/le05.c @@ -56,7 +56,12 @@ static void LE05Power(void) { SetWriteHandler(0x8000, 0xFFFF, LE05Write); } +static void StateRestore(int version) { + Sync(); +} + void LE05_Init(CartInfo *info) { info->Power = LE05Power; + GameStateRestore = StateRestore; AddExState(&StateRegs, ~0, 0, 0); } diff --git a/src/boards/mapinc.h b/src/boards/mapinc.h index 8376a0c..ba3964d 100644 --- a/src/boards/mapinc.h +++ b/src/boards/mapinc.h @@ -8,4 +8,5 @@ #include "../cart.h" #include "../cheat.h" #include "../unif.h" +#include "../ines.h" #include diff --git a/src/boards/mmc1.c b/src/boards/mmc1.c index e30ba53..1338759 100644 --- a/src/boards/mmc1.c +++ b/src/boards/mmc1.c @@ -549,11 +549,16 @@ static void M297Power(void) { 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"); } @@ -681,3 +686,47 @@ void Mapper550_Init(CartInfo *info) { 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/mmc3.c b/src/boards/mmc3.c index 1618bea..864e498 100644 --- a/src/boards/mmc3.c +++ b/src/boards/mmc3.c @@ -28,21 +28,17 @@ #include "mmc3.h" uint8 MMC3_cmd; -uint8 kt_extra; -uint8 *WRAM; -uint32 WRAMSIZE; -uint8 *CHRRAM; -uint32 CHRRAMSIZE; +static uint8 *WRAM; +static uint32 WRAMSIZE; +static uint8 *CHRRAM; +static uint32 CHRRAMSIZE; uint8 DRegBuf[8]; uint8 EXPREGS[8]; /* For bootleg games, mostly. */ uint8 A000B, A001B; uint8 mmc3opts = 0; -#undef IRQCount -#undef IRQLatch -#undef IRQa -uint8 IRQCount, IRQLatch, IRQa; -uint8 IRQReload; +static uint8 IRQCount, IRQLatch, IRQa; +static uint8 IRQReload; static SFORMAT MMC3_StateRegs[] = { @@ -184,17 +180,6 @@ DECLFW(MMC3_IRQWrite) { } } -/* KT-008 boards hack 2-in-1, TODO assign to new ines mapper, most dump of KT-boards on the net are mapper 4, so need database or goodnes fix support */ -DECLFW(KT008HackWrite) { -/* FCEU_printf("%04x:%04x\n",A,V); */ - switch (A & 3) { - case 0: kt_extra = V; FixMMC3PRG(MMC3_cmd); break; - case 1: break; /* unk */ - case 2: break; /* unk */ - case 3: break; /* unk */ - } -} - static void ClockMMC3Counter(void) { int count = IRQCount; if (!count || IRQReload) { @@ -236,9 +221,7 @@ static void GENPWRAP(uint32 A, uint8 V) { /* [NJ102] Mo Dao Jie (C) has 1024Mb MMC3 BOARD, maybe something other will be broken * also HengGe BBC-2x boards enables this mode as default board mode at boot up */ - setprg8(A, (V & 0x7F)/* | ((kt_extra & 4) << 4)*/); - /* KT-008 boards hack 2-in-1, TODO assign to new ines mapper, most dump of KT-boards on the net are mapper 4, so need database or goodnes fix support */ - /* KT-008 boards should be assigned to mapper 224 */ + setprg8(A, (V & 0x7F)); } static void GENMWRAP(uint8 V) { @@ -265,9 +248,6 @@ void GenMMC3Power(void) { SetWriteHandler(0xC000, 0xFFFF, MMC3_IRQWrite); SetReadHandler(0x8000, 0xFFFF, CartBR); - /* KT-008 boards hack 2-in-1, TODO assign to new ines mapper, most dump of KT-boards on the net are mapper 4, so need database or goodnes fix support */ - /* SetWriteHandler(0x5000,0x5FFF, KT008HackWrite); */ /* KT-008 boards should be assigned to mapper 224 */ - A001B = A000B = 0; setmirror(1); if (mmc3opts & 1) { @@ -321,9 +301,6 @@ void GenMMC3_Init(CartInfo *info, int prg, int chr, int wram, int battery) { info->SaveGameLen[0] = WRAMSIZE; } - /* KT-008 boards hack 2-in-1, TODO assign to new ines mapper, most dump of KT-boards on the net are mapper 4, so need database or goodnes fix support */ - /* KT-008 boards should be assigned to mapper 224 */ - AddExState(&kt_extra, 1, 0, "KTEX"); AddExState(MMC3_StateRegs, ~0, 0, 0); info->Power = GenMMC3Power; @@ -497,27 +474,33 @@ void Mapper44_Init(CartInfo *info) { /* ---------------------------- Mapper 45 ------------------------------- */ static void M45CW(uint32 A, uint8 V) { - if (!UNIFchrrama) { - uint32 NV = V; - if (EXPREGS[2] & 8) - NV &= (1 << ((EXPREGS[2] & 7) + 1)) - 1; - else - if (EXPREGS[2]) - NV &= 0; /* hack ;( don't know exactly how it should be */ - NV |= EXPREGS[0] | ((EXPREGS[2] & 0xF0) << 4); - setchr1(A, NV); - } else - /* setchr8(0); */ /* i don't know what cart need this, but a new one need other lol */ + if (CHRsize[0] ==8192) setchr1(A, V); + else { + int chrAND =0xFF >>(~EXPREGS[2] &0xF); + int chrOR =EXPREGS[0] | EXPREGS[2] <<4 &0xF00; + setchr1(A, V &chrAND | chrOR &~chrAND); + } +} + +static DECLFR(M45ReadOB) { + return X.DB; } static void M45PW(uint32 A, uint8 V) { - uint32 MV = V & ((EXPREGS[3] & 0x3F) ^ 0x3F); - MV |= EXPREGS[1]; - if(UNIFchrrama) - MV |= ((EXPREGS[2] & 0x40) << 2); - setprg8(A, MV); -/* FCEU_printf("1:%02x 2:%02x 3:%02x A=%04x V=%03x\n",EXPREGS[1],EXPREGS[2],EXPREGS[3],A,MV); */ + int prgAND =~EXPREGS[3] &0x3F; + int prgOR =EXPREGS[1] | EXPREGS[2] <<2 &0x300; + setprg8(A, V &prgAND | prgOR &~prgAND); + + /* 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 && EXPREGS[5] ==1 && EXPREGS[1] &0x80 || + PRGsize[0] <0x200000 && EXPREGS[5] ==2 && EXPREGS[2] &0x40 || + PRGsize[0] <0x100000 && EXPREGS[5] ==3 && EXPREGS[1] &0x40 || + PRGsize[0] <0x100000 && EXPREGS[5] ==4 && EXPREGS[2] &0x20) + SetReadHandler(0x8000, 0xFFFF, M45ReadOB); + else + SetReadHandler(0x8000, 0xFFFF, CartBR); } static DECLFW(M45Write) { @@ -614,7 +597,7 @@ static void M49PW(uint32 A, uint8 V) { V |= (EXPREGS[0] & 0xC0) >> 2; setprg8(A, V); } else - setprg32(0x8000, (EXPREGS[0] >> 4) & 3); + setprg32(0x8000, (EXPREGS[0] >> 4) & 15); } static void M49CW(uint32 A, uint8 V) { @@ -676,7 +659,10 @@ static void M52CW(uint32 A, uint8 V) { uint32 mask = 0xFF ^ ((EXPREGS[0] & 0x40) << 1); /* uint32 bank = (((EXPREGS[0]>>3)&4)|((EXPREGS[0]>>1)&2)|((EXPREGS[0]>>6)&(EXPREGS[0]>>4)&1))<<7; */ uint32 bank = (((EXPREGS[0] >> 4) & 2) | (EXPREGS[0] & 4) | ((EXPREGS[0] >> 6) & (EXPREGS[0] >> 4) & 1)) << 7; /* actually 256K CHR banks index bits is inverted! */ - setchr1(A, bank | (V & mask)); + if (CHRRAM && (EXPREGS[0] &3) ==3) + setchr1r(0x10, A, bank | (V & mask)); + else + setchr1(A, bank | (V & mask)); } static DECLFW(M52Write) { @@ -708,6 +694,12 @@ void Mapper52_Init(CartInfo *info) { info->Reset = M52Reset; info->Power = M52Power; AddExState(EXPREGS, 2, 0, "EXPR"); + if (info->iNES2 && info->submapper ==13) { + CHRRAMSIZE = 8192; + CHRRAM = (uint8*)FCEU_gmalloc(CHRRAMSIZE); + SetupCartCHRMapping(0x10, CHRRAM, CHRRAMSIZE, 1); + AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); + } } /* ---------------------------- Mapper 76 ------------------------------- */ @@ -812,10 +804,8 @@ static void M114Reset(void) { void Mapper114_Init(CartInfo *info) { isRevB = 0; - type_Boogerman = 0; - if (info->CRC32 == 0x80eb1839 || /* Boogerman (Sugar Softec) (Unl) [!] - submapper 1 */ - info->CRC32 == 0x071e4ee8) /* 114 test-rom https://forums.nesdev.com/viewtopic.php?f=3&t=17391 */ - type_Boogerman = 1; + /* 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); pwrap = M114PWRAP; @@ -906,49 +896,6 @@ void Mapper119_Init(CartInfo *info) { AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); } -/* ---------------------------- Mapper 134 ------------------------------ */ -/* ---------------------------- UNL-T4A54A ------------------------------ */ - -/* UNL-T4A54A, functionally the same as mapper 134. - * Writes @ $6801. Menu @ prg $20000, chr $00000 */ - -static void M134PW(uint32 A, uint8 V) { - uint8 mask = (EXPREGS[0] & 0x04) ? 0x0F : 0x1F; - setprg8(A, (V & mask) | ((EXPREGS[0] & 3) << 4)); -} - -static void M134CW(uint32 A, uint8 V) { - uint8 mask = (EXPREGS[0] & 0x04) ? 0x7F : 0xFF; - setchr1(A, (V & mask) | ((EXPREGS[0] & 0x30) << 3)); -} - -static DECLFW(M134Write) { - EXPREGS[0] = V; - FixMMC3CHR(MMC3_cmd); - FixMMC3PRG(MMC3_cmd); -} - -static void M134Power(void) { - EXPREGS[0] = 0x01; - GenMMC3Power(); - SetWriteHandler(0x6001, 0x6001, M134Write); - SetWriteHandler(0x6801, 0x6801, M134Write); -} - -static void M134Reset(void) { - EXPREGS[0] = 0x01; - MMC3RegReset(); -} - -void Mapper134_Init(CartInfo *info) { - GenMMC3_Init(info, 256, 256, 0, 0); - pwrap = M134PW; - cwrap = M134CW; - info->Power = M134Power; - info->Reset = M134Reset; - AddExState(EXPREGS, 4, 0, "EXPR"); -} - /* ---------------------------- Mapper 165 ------------------------------ */ static void M165CW(uint32 A, uint8 V) { @@ -1060,31 +1007,6 @@ void Mapper194_Init(CartInfo *info) { AddExState(CHRRAM, CHRRAMSIZE, 0, "CHRR"); } -/* ---------------------------- Mapper 195 ------------------------------- */ -static void M195CW(uint32 A, uint8 V) { - if (V <= 3) /* Crystalis (c).nes, Captain Tsubasa Vol 2 - Super Striker (C) */ - setchr1r(0x10, A, V); - else - setchr1r(0, A, V); -} - -static void M195Power(void) { - GenMMC3Power(); - setprg4r(0x10, 0x5000, 2); - SetWriteHandler(0x5000, 0x5fff, CartBW); - SetReadHandler(0x5000, 0x5fff, CartBR); -} - -void Mapper195_Init(CartInfo *info) { - GenMMC3_Init(info, 512, 256, 16, info->battery); - cwrap = M195CW; - info->Power = M195Power; - CHRRAMSIZE = 4096; - 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 @@ -1100,13 +1022,11 @@ static void M196PW(uint32 A, uint8 V) { } static DECLFW(Mapper196Write) { - if (A >= 0xC000) { - A = (A & 0xFFFE) | ((A >> 2) & 1) | ((A >> 3) & 1); + A =A &0xF000 | (!!(A &0xE) ^(A &1)); + if (A >= 0xC000) MMC3_IRQWrite(A, V); - } else { - A = (A & 0xFFFE) | ((A >> 2) & 1) | ((A >> 3) & 1) | ((A >> 1) & 1); + else MMC3_CMDWrite(A, V); - } } static DECLFW(Mapper196WriteLo) { @@ -1182,6 +1102,13 @@ void Mapper197_Init(CartInfo *info) { /* ---------------------------- Mapper 198 ------------------------------- */ +static void M198Power(void) { + GenMMC3Power(); + setprg4r(0x10, 0x5000, 2); + SetWriteHandler(0x5000, 0x5fff, CartBW); + SetReadHandler(0x5000, 0x5fff, CartBR); +} + static void M198PW(uint32 A, uint8 V) { if (V >= 0x50) /* Tenchi o Kurau II - Shokatsu Koumei Den (J) (C).nes */ setprg8(A, V & 0x4F); @@ -1192,7 +1119,7 @@ static void M198PW(uint32 A, uint8 V) { void Mapper198_Init(CartInfo *info) { GenMMC3_Init(info, 1024, 0, 16, info->battery); pwrap = M198PW; - info->Power = M195Power; + info->Power = M198Power; } /* ---------------------------- Mapper 205 ------------------------------ */ diff --git a/src/boards/mmc3.h b/src/boards/mmc3.h index 2479f9d..b29a53e 100644 --- a/src/boards/mmc3.h +++ b/src/boards/mmc3.h @@ -8,12 +8,6 @@ extern uint8 A001B; extern uint8 EXPREGS[8]; extern uint8 DRegBuf[8]; -#undef IRQCount -#undef IRQLatch -#undef IRQa -extern uint8 IRQCount, IRQLatch, IRQa; -extern uint8 IRQReload; - extern void (*pwrap)(uint32 A, uint8 V); extern void (*cwrap)(uint32 A, uint8 V); extern void (*mwrap)(uint8 V); diff --git a/src/boards/n106.c b/src/boards/n106.c index b1d6618..1f26048 100644 --- a/src/boards/n106.c +++ b/src/boards/n106.c @@ -53,34 +53,15 @@ static int is210; /* Lesser mapper. */ static uint8 PRG[3]; static uint8 CHR[8]; -/* TODO: Clean this up. State variables are expanded for - * big-endian compatibility when saving and loading states */ static SFORMAT N106_StateRegs[] = { - { &PRG[0], 1, "PRG1" }, - { &PRG[1], 1, "PRG2" }, - { &PRG[2], 1, "PRG3" }, - - { &CHR[0], 1, "CHR1" }, - { &CHR[1], 1, "CHR2" }, - { &CHR[2], 1, "CHR3" }, - { &CHR[3], 1, "CHR4" }, - { &CHR[4], 1, "CHR5" }, - { &CHR[5], 1, "CHR6" }, - { &CHR[6], 1, "CHR7" }, - { &CHR[7], 1, "CHR8" }, - - { &NTAPage[0], 1, "NTA1" }, - { &NTAPage[1], 1, "NTA2" }, - { &NTAPage[2], 1, "NTA3" }, - { &NTAPage[3], 1, "NTA4" }, - + { PRG, 3, "PRG" }, + { CHR, 8, "CHR" }, + { NTAPage, 4, "NTA" }, { &IRQCount, 2 | FCEUSTATE_RLSB, "IRQC" }, { &IRQa, 1, "IRQA" }, - { &dopol, 1, "GORF" }, { &gorfus, 1, "DOPO" }, { &gorko, 1, "GORK" }, - { 0 } }; @@ -91,6 +72,15 @@ static void SyncPRG(void) { 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; @@ -140,8 +130,6 @@ static void FixNTAR(void) { static void FASTAPASS(2) DoCHRRAMROM(int x, uint8 V) { CHR[x] = V; if (!is210 && !((gorfus >> ((x >> 2) + 6)) & 1) && (V >= 0xE0)) { -/* printf("BLAHAHA: %d, %02x\n",x,V); */ -/* setchr1r(0x10,x<<10,V&7); */ } else setchr1(x << 10, V); } @@ -167,7 +155,10 @@ static void FixCache(int a, int V) { case 0x02: FreqCache[w] &= ~0x0000FF00; FreqCache[w] |= V << 8; break; case 0x04: FreqCache[w] &= ~0x00030000; FreqCache[w] |= (V & 3) << 16; - LengthCache[w] = (8 - ((V >> 2) & 7)) << 2; + /* 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; } @@ -206,6 +197,10 @@ static DECLFW(Mapper19_write) { gorko = V & 0xC0; PRG[0] = V & 0x3F; SyncPRG(); + if (is210) { + gorko = V >> 6; + SyncMirror(); + } break; case 0xE800: gorfus = V & 0xC0; @@ -341,9 +336,8 @@ static void DoNamcoSound(int32 *Wave, int Count) { envelope = EnvCache[P]; lengo = LengthCache[P]; - if (!freq) { /*printf("Ack");*/ + if (!freq) continue; - } { int c = ((IRAM[0x7F] >> 4) & 7) + 1; @@ -378,6 +372,7 @@ static void DoNamcoSound(int32 *Wave, int Count) { static void Mapper19_StateRestore(int version) { int x; SyncPRG(); + SyncMirror(); FixNTAR(); FixCRR(); for (x = 0x40; x < 0x80; x++) diff --git a/src/boards/n625092.c b/src/boards/n625092.c index 1f134c0..800d986 100644 --- a/src/boards/n625092.c +++ b/src/boards/n625092.c @@ -18,18 +18,17 @@ * 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" }, + { &cmd, 2 | FCEUSTATE_RLSB, "CMD" }, + { &bank, 2 | FCEUSTATE_RLSB, "BANK" }, { 0 } }; @@ -38,15 +37,15 @@ static void Sync(void) { setchr8(0); if (cmd & 2) { if (cmd & 0x100) { - setprg16(0x8000, ((cmd & 0xfc) >> 2) | bank); - setprg16(0xC000, ((cmd & 0xfc) >> 2) | 7); + setprg16(0x8000, ((cmd & 0x200) >> 3) | ((cmd & 0xfc) >> 2) | bank); + setprg16(0xC000, ((cmd & 0x200) >> 3) | ((cmd & 0xfc) >> 2) | 7); } else { - setprg16(0x8000, ((cmd & 0xfc) >> 2) | (bank & 6)); - setprg16(0xC000, ((cmd & 0xfc) >> 2) | ((bank & 6) | 1)); + 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 & 0xfc) >> 2) | bank); - setprg16(0xC000, ((cmd & 0xfc) >> 2) | bank); + setprg16(0x8000, ((cmd & 0x200) >> 3) | ((cmd & 0xfc) >> 2) | bank); + setprg16(0xC000, ((cmd & 0x200) >> 3) | ((cmd & 0xfc) >> 2) | bank); } } @@ -81,6 +80,7 @@ static void UNLN625092Reset(void) { bank = 0; ass++; FCEU_printf("%04x\n", ass); + Sync(); } static void StateRestore(int version) { diff --git a/src/boards/onebus.c b/src/boards/onebus.c index d970456..4175ca1 100644 --- a/src/boards/onebus.c +++ b/src/boards/onebus.c @@ -27,6 +27,8 @@ #include "mapinc.h" +static uint8 submapper; + /* General Purpose Registers */ static uint8 cpu410x[16], ppu201x[16], apu40xx[64]; @@ -35,9 +37,6 @@ static uint8 IRQCount, IRQa, IRQReload; #define IRQLatch cpu410x[0x1] /* accc cccc, a = 0, AD12 switching, a = 1, HSYNC switching */ /* MMC3 Registers */ -static uint8 inv_hack = 0; /* some OneBus Systems have swapped PRG reg commans in MMC3 inplementation, - * trying to autodetect unusual behavior, due not to add a new mapper. - */ #define mmc3cmd cpu410x[0x5] /* pcv- ----, p - program swap, c - video swap, v - internal VRAM enable */ #define mirror cpu410x[0x6] /* ---- ---m, m = 0 - H, m = 1 - V */ @@ -65,6 +64,8 @@ static SFORMAT StateRegs[] = { 0 } }; +static uint8 *WRAM; + static void PSync(void) { uint8 bankmode = cpu410x[0xb] & 7; uint8 mask = (bankmode == 0x7) ? (0xff) : (0x3f >> bankmode); @@ -77,8 +78,8 @@ static void PSync(void) { uint8 bank2 = (cpu410x[0xb] & 0x40)?(cpu410x[0x9]):(~1); uint8 bank3 = ~0; #endif - uint8 bank0 = cpu410x[0x7 ^ inv_hack]; - uint8 bank1 = cpu410x[0x8 ^ inv_hack]; + uint8 bank0 = cpu410x[0x7]; + uint8 bank1 = cpu410x[0x8]; uint8 bank2 = (cpu410x[0xb] & 0x40) ? (cpu410x[0x9]) : (~1); uint8 bank3 = ~0; @@ -124,29 +125,91 @@ static void Sync(void) { CSync(); } +static const uint8 cpuMangle[16][4] = { + { 0, 1, 2, 3 }, /* Submapper 0: Normal */ + { 0, 1, 2, 3 }, /* Submapper 1: Waixing VT03 */ + { 1, 0, 2, 3 }, /* Submapper 2: Trump Grand */ + { 0, 1, 2, 3 }, /* Submapper 3: Zechess */ + { 0, 1, 2, 3 }, /* Submapper 4: Qishenglong */ + { 0, 1, 2, 3 }, /* Submapper 5: Waixing VT02 */ + { 0, 1, 2, 3 }, /* Submapper 6: unused so far */ + { 0, 1, 2, 3 }, /* Submapper 7: unused so far */ + { 0, 1, 2, 3 }, /* Submapper 8: unused so far */ + { 0, 1, 2, 3 }, /* Submapper 9: unused so far */ + { 0, 1, 2, 3 }, /* Submapper A: unused so far */ + { 0, 1, 2, 3 }, /* Submapper B: unused so far */ + { 0, 1, 2, 3 }, /* Submapper C: unused so far */ + { 0, 1, 2, 3 }, /* Submapper D: Cube Tech (CPU opcode encryption only) */ + { 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) { /* FCEU_printf("CPU %04x:%04x\n",A,V); */ - switch (A & 0xf) { + A &=0xF; + switch (A) { case 0x1: IRQLatch = V & 0xfe; break; /* */ case 0x2: IRQReload = 1; break; case 0x3: X6502_IRQEnd(FCEU_IQEXT); IRQa = 0; break; case 0x4: IRQa = 1; break; default: - cpu410x[A & 0xf] = V; + if (A >=0x7 && A <=0xA) A =0x7 +cpuMangle[submapper][A -0x7]; + cpu410x[A] = V; Sync(); } } +static const uint8 ppuMangle[16][6] = { + { 0, 1, 2, 3, 4, 5 }, /* Submapper 0: Normal */ + { 1, 0, 5, 4, 3, 2 }, /* Submapper 1: Waixing VT03 */ + { 0, 1, 2, 3, 4, 5 }, /* Submapper 2: Trump Grand */ + { 5, 4, 3, 2, 0, 1 }, /* Submapper 3: Zechess */ + { 2, 5, 0, 4, 3, 1 }, /* Submapper 4: Qishenglong */ + { 1, 0, 5, 4, 3, 2 }, /* Submapper 5: Waixing VT02 */ + { 0, 1, 2, 3, 4, 5 }, /* Submapper 6: unused so far */ + { 0, 1, 2, 3, 4, 5 }, /* Submapper 7: unused so far */ + { 0, 1, 2, 3, 4, 5 }, /* Submapper 8: unused so far */ + { 0, 1, 2, 3, 4, 5 }, /* Submapper 9: unused so far */ + { 0, 1, 2, 3, 4, 5 }, /* Submapper A: unused so far */ + { 0, 1, 2, 3, 4, 5 }, /* Submapper B: unused so far */ + { 0, 1, 2, 3, 4, 5 }, /* Submapper C: unused so far */ + { 0, 1, 2, 3, 4, 5 }, /* Submapper D: Cube Tech (CPU opcode encryption only) */ + { 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) { /* FCEU_printf("PPU %04x:%04x\n",A,V); */ - ppu201x[A & 0x0f] = V; + A &=0x0F; + if (A >=2 && A <=7) A =2 +ppuMangle[submapper][A -2]; + ppu201x[A] = V; Sync(); } +static const uint8 mmc3Mangle[16][8] = { + { 0, 1, 2, 3, 4, 5, 6, 7 }, /* Submapper 0: Normal */ + { 5, 4, 3, 2, 1, 0, 6, 7 }, /* Submapper 1: Waixing VT03 */ + { 0, 1, 2, 3, 4, 5, 7, 6 }, /* Submapper 2: Trump Grand */ + { 0, 1, 2, 3, 4, 5, 6, 7 }, /* Submapper 3: Zechess */ + { 0, 1, 2, 3, 4, 5, 6, 7 }, /* Submapper 4: Qishenglong */ + { 0, 1, 2, 3, 4, 5, 6, 7 }, /* Submapper 5: Waixing VT02 */ + { 0, 1, 2, 3, 4, 5, 6, 7 }, /* Submapper 6: unused so far */ + { 0, 1, 2, 3, 4, 5, 6, 7 }, /* Submapper 7: unused so far */ + { 0, 1, 2, 3, 4, 5, 6, 7 }, /* Submapper 8: unused so far */ + { 0, 1, 2, 3, 4, 5, 6, 7 }, /* Submapper 9: unused so far */ + { 0, 1, 2, 3, 4, 5, 6, 7 }, /* Submapper A: unused so far */ + { 0, 1, 2, 3, 4, 5, 6, 7 }, /* Submapper B: unused so far */ + { 0, 1, 2, 3, 4, 5, 6, 7 }, /* Submapper C: unused so far */ + { 0, 1, 2, 3, 4, 5, 6, 7 }, /* Submapper D: Cube Tech (CPU opcode encryption only) */ + { 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) { /* FCEU_printf("MMC %04x:%04x\n",A,V); */ switch (A & 0xe001) { - case 0x8000: mmc3cmd = (mmc3cmd & 0x38) | (V & 0xc7); Sync(); break; + case 0x8000: + V =V &0xF8 | mmc3Mangle[submapper][V &0x07]; + mmc3cmd = (mmc3cmd & 0x38) | (V & 0xc7); + Sync(); + break; case 0x8001: { switch (mmc3cmd & 7) { @@ -263,11 +326,14 @@ static void UNLOneBusPower(void) { SetReadHandler(0x4000, 0x403f, UNLOneBusReadAPU40XX); SetWriteHandler(0x4000, 0x403f, UNLOneBusWriteAPU40XX); - SetReadHandler(0x8000, 0xFFFF, CartBR); + SetReadHandler(0x6000, 0xFFFF, CartBR); + SetWriteHandler(0x6000, 0x7FFF, CartBW); SetWriteHandler(0x2010, 0x201f, UNLOneBusWritePPU201X); SetWriteHandler(0x4100, 0x410f, UNLOneBusWriteCPU410X); SetWriteHandler(0x8000, 0xffff, UNLOneBusWriteMMC3); + FCEU_CheatAddRAM(8, 0x6000, WRAM); + setprg8r(0x10, 0x6000, 0); Sync(); } @@ -285,16 +351,28 @@ static void StateRestore(int version) { Sync(); } +void UNLOneBus_Close(void) { + if (WRAM) + FCEU_gfree(WRAM); + WRAM = NULL; +} + void UNLOneBus_Init(CartInfo *info) { info->Power = UNLOneBusPower; info->Reset = UNLOneBusReset; + info->Close = UNLOneBus_Close; - if (((*(uint32*)&(info->MD5)) == 0x305fcdc3) || /* PowerJoy Supermax Carts */ - ((*(uint32*)&(info->MD5)) == 0x6abfce8e)) - inv_hack = 0xf; + 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; GameStateRestore = StateRestore; AddExState(&StateRegs, ~0, 0, 0); + + WRAM = (uint8*)FCEU_gmalloc(8192); + SetupCartPRGMapping(0x10, WRAM, 8192, 1); } + diff --git a/src/boards/resettxrom.c b/src/boards/resettxrom.c index 1047283..6d5537d 100644 --- a/src/boards/resettxrom.c +++ b/src/boards/resettxrom.c @@ -2,7 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2019 Libretro Team - * Copyright (C) 2020 negativeExponent + * 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 diff --git a/src/boards/sachen.c b/src/boards/sachen.c index 06750a4..cc97bc9 100644 --- a/src/boards/sachen.c +++ b/src/boards/sachen.c @@ -2,7 +2,7 @@ * * Copyright notice for this file: * Copyright (C) 2002 Xodnizel - * Copyright (C) 2020 negativeExponent + * 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 @@ -327,3 +327,18 @@ void S74LS374N_Init(CartInfo *info) { 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/sc-127.c b/src/boards/sc-127.c deleted file mode 100644 index 127fcb8..0000000 --- a/src/boards/sc-127.c +++ /dev/null @@ -1,123 +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 - * - * Wario Land II (Kirby hack) - */ - -#include "mapinc.h" - -static uint8 reg[8], chr[8]; -static uint8 *WRAM = NULL; -static uint32 WRAMSIZE; -static uint16 IRQCount, IRQa; - -static SFORMAT StateRegs[] = -{ - { reg, 8, "REGS" }, - { chr, 8, "CHRS" }, - { &IRQCount, 2, "IRQc" }, - { &IRQa, 2, "IRQa" }, - { 0 } -}; - -static void Sync(void) { - int i; - setprg8r(0x10, 0x6000, 0); - setprg8(0x8000, reg[0]); - setprg8(0xA000, reg[1]); - setprg8(0xC000, reg[2]); - setprg8(0xE000, ~0); - for (i = 0; i < 8; i++) - setchr1(i << 10, chr[i]); - setmirror(reg[3] ^ 1); -} - -static DECLFW(UNLSC127Write) { - switch (A) { - case 0x8000: reg[0] = V; break; - case 0x8001: reg[1] = V; break; - case 0x8002: reg[2] = V; break; - case 0x9000: chr[0] = V; break; - case 0x9001: chr[1] = V; break; - case 0x9002: chr[2] = V; break; - case 0x9003: chr[3] = V; break; - case 0x9004: chr[4] = V; break; - case 0x9005: chr[5] = V; break; - case 0x9006: chr[6] = V; break; - case 0x9007: chr[7] = V; break; - case 0xC002: IRQa = 0; X6502_IRQEnd(FCEU_IQEXT); break; - case 0xC005: IRQCount = V; break; - case 0xC003: IRQa = 1; break; - case 0xD001: reg[3] = V; break; - } - Sync(); -} - -static DECLFR(UNLSC127ProtRead) { - return 0x20; -} - -static void UNLSC127Power(void) { - IRQCount = IRQa = 0; - Sync(); - SetReadHandler(0x5800, 0x5800, UNLSC127ProtRead); - SetReadHandler(0x6000, 0x7fff, CartBR); - SetWriteHandler(0x6000, 0x7fff, CartBW); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x8000, 0xFFFF, UNLSC127Write); - FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); -} - -static void UNLSC127IRQ(void) { - if (IRQa) { - if(IRQCount > 0) - IRQCount--; - if (!IRQCount) { - X6502_IRQBegin(FCEU_IQEXT); - IRQa = 0; - } - } -} - -static void UNLSC127Reset(void) { - IRQCount = IRQa = 0; -} - -static void UNLSC127Close(void) { - if (WRAM) - FCEU_gfree(WRAM); - WRAM = NULL; -} - -static void StateRestore(int version) { - Sync(); -} - -void UNLSC127_Init(CartInfo *info) { - info->Reset = UNLSC127Reset; - info->Power = UNLSC127Power; - info->Close = UNLSC127Close; - GameHBIRQHook = UNLSC127IRQ; - 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/super40in1.c b/src/boards/super40in1.c index ef5a5e1..7d954be 100644 --- a/src/boards/super40in1.c +++ b/src/boards/super40in1.c @@ -23,43 +23,73 @@ #include "mapinc.h" -static uint8 preg, creg; +static uint8 preg, creg, latch, dipSwitch; static SFORMAT StateRegs[] = { { &preg, 1, "PREG" }, { &creg, 1, "CREG" }, + { &latch, 1, "LATC" }, + { &dipSwitch, 1, "DPSW" }, { 0 } }; static void Sync(void) { + int prg = (preg & 7) | ((preg >> 3) & 0x08); /* There is a high bit 3 of the PRG register that applies both to PRG and CHR */ + int chr = (creg & 7) | ((preg >> 3) & 0x08); /* There is a high bit 3 of the PRG register that applies both to PRG and CHR */ + int 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 register at $8000-$FFFF. */ + if (preg & 8) { - setprg16(0x8000, preg & 7); - setprg16(0xc000, preg & 7); + setprg16(0x8000, prg); + setprg16(0xc000, prg); } else - setprg32(0x8000, (preg & 6) >> 1); - setchr8(creg); + setprg32(0x8000, prg >> 1); + + setchr8((chr &~mask) | (latch &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; + case 0: preg = V; Sync(); break; + case 1: creg = V; Sync(); break; } } -static void MBMCWSPower(void) { +static DECLFW(LatchWrite) { + latch =V; Sync(); - SetReadHandler(0x8000, 0xFFFF, CartBR); - SetWriteHandler(0x6000, 0x6001, BMCWSWrite); +} + +static void MBMCWSPower(void) { + dipSwitch =0; + Sync(); + SetReadHandler(0x8000, 0xFFFF, BMCWSRead); + SetWriteHandler(0x6000, 0x7FFF, BMCWSWrite); + SetWriteHandler(0x8000, 0xFFFF, LatchWrite); } 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; + latch =0; + Sync(); } static void StateRestore(int version) { diff --git a/src/boards/tf-1201.c b/src/boards/tf-1201.c index 6470e0f..4d3aba6 100644 --- a/src/boards/tf-1201.c +++ b/src/boards/tf-1201.c @@ -72,16 +72,21 @@ static DECLFW(UNLTF1201Write) { int sar = ((A & 2) << 1); chr[ind] = (chr[ind] & (0xF0 >> sar)) | ((V & 0x0F) << sar); SyncChr(); - } else switch (A & 0xF003) { - case 0x8000: prg0 = V; SyncPrg(); break; - case 0xA000: prg1 = V; SyncPrg(); break; - case 0x9000: mirr = V & 1; SyncChr(); break; - case 0x9001: swap = V & 3; SyncPrg(); break; - case 0xF000: IRQCount = ((IRQCount & 0xF0) | (V & 0xF)); break; - case 0xF002: IRQCount = ((IRQCount & 0x0F) | ((V & 0xF) << 4)); break; - case 0xF001: - case 0xF003: IRQa = V & 2; X6502_IRQEnd(FCEU_IQEXT); if (scanline < 240) IRQCount -= 8; break; + } + else + { + switch (A & 0xF003) + { + case 0x8000: prg0 = V; SyncPrg(); break; + case 0xA000: prg1 = V; SyncPrg(); break; + case 0x9000: mirr = V & 1; SyncChr(); break; + case 0x9001: swap = V & 3; SyncPrg(); break; + case 0xF000: IRQCount = ((IRQCount & 0xF0) | (V & 0xF)); break; + case 0xF002: IRQCount = ((IRQCount & 0x0F) | ((V & 0xF) << 4)); break; + case 0xF001: + case 0xF003: IRQa = V & 2; X6502_IRQEnd(FCEU_IQEXT); if (scanline < 240) IRQCount -= 8; break; } + } } static void UNLTF1201IRQCounter(void) { diff --git a/src/boards/txcchip.c b/src/boards/txcchip.c index a361cc8..69fbb56 100644 --- a/src/boards/txcchip.c +++ b/src/boards/txcchip.c @@ -3,7 +3,7 @@ * Copyright notice for this file: * Copyright (C) 2012 CaH4e3 * Copyright (C) 2019 Libretro Team - * Copyright (C) 2020 negativeExponent + * 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 @@ -65,7 +65,7 @@ typedef struct { static TXC txc; -static void Dummyfunc(void) { }; +static void Dummyfunc(void) { } static void (*WSync)(void) = Dummyfunc; static SFORMAT StateRegs[] = diff --git a/src/boards/unrom512.c b/src/boards/unrom512.c index 3a1961f..ca3f63b 100644 --- a/src/boards/unrom512.c +++ b/src/boards/unrom512.c @@ -35,7 +35,6 @@ */ #include "mapinc.h" -#include "../ines.h" /* Workaround for libretro api compatibility */ #define ROM_size_max 32 diff --git a/src/boards/yoko.c b/src/boards/yoko.c index e91974a..fa43b47 100644 --- a/src/boards/yoko.c +++ b/src/boards/yoko.c @@ -33,7 +33,7 @@ static int32 IRQCount; static uint8 *WRAM = NULL; static uint32 WRAMSIZE; -static uint8 is2kbank, isnot2kbank; +static uint8 is2kbank, dbzParty, isYoko; static SFORMAT StateRegs[] = { @@ -44,7 +44,6 @@ static SFORMAT StateRegs[] = { reg, 11, "REGS" }, { low, 4, "LOWR" }, { &is2kbank, 1, "IS2K" }, - { &isnot2kbank, 1, "NT2K" }, { 0 } }; @@ -77,7 +76,7 @@ static void M83Sync(void) { case 2: setmirror(MI_0); break; case 3: setmirror(MI_1); break; } - if (is2kbank && !isnot2kbank) { + if (is2kbank) { setchr2(0x0000, reg[0]); setchr2(0x0800, reg[1]); setchr2(0x1000, reg[6]); @@ -88,14 +87,21 @@ static void M83Sync(void) { setchr1(x << 10, reg[x] | ((bank & 0x30) << 4)); } setprg8r(0x10, 0x6000, 0); - if (mode & 0x40) { - setprg16(0x8000, (bank & 0x3F)); /* DBZ Party [p1] */ - setprg16(0xC000, (bank & 0x30) | 0xF); - } else { - setprg8(0x8000, reg[8]); - setprg8(0xA000, reg[9]); - setprg8(0xC000, reg[10]); - setprg8(0xE000, ~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; } } @@ -116,25 +122,22 @@ static DECLFW(UNLYOKOWrite) { } static DECLFW(M83Write) { - switch (A) { - case 0x8000: is2kbank = 1; - case 0xB000: /* Dragon Ball Z Party [p1] BMC */ - case 0xB0FF: /* Dragon Ball Z Party [p1] BMC */ - case 0xB1FF: bank = V; mode |= 0x40; M83Sync(); break; /* Dragon Ball Z Party [p1] BMC */ - case 0x8100: mode = V | (mode & 0x40); M83Sync(); break; - case 0x8200: IRQCount &= 0xFF00; IRQCount |= V; X6502_IRQEnd(FCEU_IQEXT); break; - case 0x8201: IRQa = mode & 0x80; IRQCount &= 0xFF; IRQCount |= V << 8; break; - case 0x8300: reg[8] = V; mode &= 0xBF; M83Sync(); break; - case 0x8301: reg[9] = V; mode &= 0xBF; M83Sync(); break; - case 0x8302: reg[10] = V; mode &= 0xBF; M83Sync(); break; - case 0x8310: reg[0] = V; M83Sync(); break; - case 0x8311: reg[1] = V; M83Sync(); break; - case 0x8312: reg[2] = V; isnot2kbank = 1; M83Sync(); break; - case 0x8313: reg[3] = V; isnot2kbank = 1; M83Sync(); break; - case 0x8314: reg[4] = V; isnot2kbank = 1; M83Sync(); break; - case 0x8315: reg[5] = V; isnot2kbank = 1; M83Sync(); break; - case 0x8316: reg[6] = V; M83Sync(); break; - case 0x8317: reg[7] = V; M83Sync(); break; + 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; } } @@ -162,8 +165,6 @@ static void UNLYOKOPower(void) { } static void M83Power(void) { - is2kbank = 0; - isnot2kbank = 0; mode = bank = 0; dip = 0; M83Sync(); @@ -171,7 +172,7 @@ static void M83Power(void) { SetReadHandler(0x5100, 0x5103, UNLYOKOReadLow); SetWriteHandler(0x5100, 0x5103, UNLYOKOWriteLow); SetReadHandler(0x6000, 0x7fff, CartBR); - SetWriteHandler(0x6000, 0x7fff, CartBW);/* Pirate Dragon Ball Z Party [p1] used if for saves instead of seraial EEPROM */ + SetWriteHandler(0x6000, 0x7fff, CartBW); SetReadHandler(0x8000, 0xffff, CartBR); SetWriteHandler(0x8000, 0xffff, M83Write); FCEU_CheatAddRAM(WRAMSIZE >> 10, 0x6000, WRAM); @@ -185,6 +186,7 @@ static void UNLYOKOReset(void) { static void M83Reset(void) { dip ^= 1; + mode = bank = 0; M83Sync(); } @@ -228,10 +230,19 @@ void Mapper83_Init(CartInfo *info) { MapIRQHook = UNLYOKOIRQHook; GameStateRestore = M83StateRestore; - WRAMSIZE = 8192; - WRAM = (uint8*)FCEU_gmalloc(WRAMSIZE); - SetupCartPRGMapping(0x10, WRAM, WRAMSIZE, 1); - AddExState(WRAM, WRAMSIZE, 0, "WRAM"); + 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 911cb0c..9d4a5d6 100644 --- a/src/cart.c +++ b/src/cart.c @@ -20,7 +20,10 @@ #include #include -#include + +#include +#include +#include #include "fceu-types.h" #include "fceu.h" @@ -136,7 +139,6 @@ DECLFR(CartBR) { } DECLFW(CartBW) { - /* printf("Ok: %04x:%02x, %d\n",A,V,PRGIsRAM[A>>11]); */ if (PRGIsRAM[A >> 11] && Page[A >> 11]) Page[A >> 11][A] = V; } @@ -340,7 +342,7 @@ void FixGenieMap(void); /* Called when a game(file) is opened successfully. */ void FCEU_OpenGenie(void) { - FILE *fp; + RFILE *fp = NULL; int x; if (!GENIEROM) { @@ -349,33 +351,43 @@ void FCEU_OpenGenie(void) { if (!(GENIEROM = (uint8*)FCEU_malloc(4096 + 1024))) return; fn = FCEU_MakeFName(FCEUMKF_GGROM, 0, 0); - fp = FCEUD_UTF8fopen(fn, "rb"); + + 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!"); + 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 (fread(GENIEROM, 1, 16, fp) != 16) { + if (filestream_read(fp, GENIEROM, 16) != 16) { grerr: - FCEU_PrintError("Error reading from Game Genie ROM image!"); + 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; - fclose(fp); + filestream_close(fp); return; } if (GENIEROM[0] == 0x4E) { /* iNES ROM image */ - if (fread(GENIEROM, 1, 4096, fp) != 4096) + if (filestream_read(fp, GENIEROM, 4096) != 4096) goto grerr; - if (fseek(fp, 16384 - 4096, SEEK_CUR)) + if (filestream_seek(fp, 16384 - 4096, RETRO_VFS_SEEK_POSITION_CURRENT)) goto grerr; - if (fread(GENIEROM + 4096, 1, 256, fp) != 256) + if (filestream_read(fp, GENIEROM + 4096, 256) != 256) goto grerr; } else { - if (fread(GENIEROM + 16, 1, 4352 - 16, fp) != (4352 - 16)) + if (filestream_read(fp, GENIEROM + 16, 4352 - 16) != (4352 - 16)) goto grerr; } - fclose(fp); + filestream_close(fp); /* Workaround for the FCE Ultra CHR page size only being 1KB */ for (x = 0; x < 4; x++) @@ -480,7 +492,6 @@ void FixGenieMap(void) { VPageR = VPage; FlushGenieRW(); - /* printf("Rightyo\n"); */ for (x = 0; x < 3; x++) if ((modcon >> (4 + x)) & 1) { readfunc tmp[3] = { GenieFix1, GenieFix2, GenieFix3 }; diff --git a/src/cheat.c b/src/cheat.c index f92e8d4..e8243c0 100644 --- a/src/cheat.c +++ b/src/cheat.c @@ -18,9 +18,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include #include -#include #include #include "fceu-types.h" @@ -114,7 +114,6 @@ void RebuildSubCheats(void) { if (c->type == 1 && c->status) { if (GetReadHandler(c->addr) == SubCheatsRead) { /* Prevent a catastrophe by this check. */ - /* FCEU_DispMessage("oops"); */ } else { SubCheats[numsubcheats].PrevRead = GetReadHandler(c->addr); SubCheats[numsubcheats].addr = c->addr; @@ -162,13 +161,13 @@ static int AddCheatEntry(char *name, uint32 addr, uint8 val, int compare, int st return(1); } -void FCEU_LoadGameCheats(FILE *override) +void FCEU_LoadGameCheats(void) { numsubcheats = savecheats = 0; RebuildSubCheats(); } -void FCEU_FlushGameCheats(FILE *override, int nosave) { +void FCEU_FlushGameCheats(void) { if (CheatComp) { free(CheatComp); @@ -203,8 +202,8 @@ void FCEU_ResetCheats(void) int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type) { char *t; - - if (!(t = (char*)malloc(strlen(name) + 1))) { + if (!(t = (char*)malloc(strlen(name) + 1))) + { CheatMemErr(); return(0); } @@ -319,16 +318,11 @@ static int GGtobin(char c) { /* Returns 1 on success, 0 on failure. Sets *a,*v,*c. */ int FCEUI_DecodeGG(const char *str, uint16 *a, uint8 *v, int *c) { - uint16 A; - uint8 V, C; uint8 t; - int s; - - A = 0x8000; - V = 0; - C = 0; - - s = strlen(str); + uint16 A = 0x8000; + uint8 V = 0; + uint8 C = 0; + int s = strlen(str); if (s != 6 && s != 8) return(0); t = GGtobin(*str++); @@ -388,13 +382,21 @@ int FCEUI_DecodePAR(const char *str, uint16 *a, uint8 *v, int *c, int *type) { *c = -1; - if (1) { + /* 2020-08-31 + * Why is the top code set as default on non-debug runtime when + * bottom code is what works for PAR? + */ + /* if (1) { *a = (boo[3] << 8) | (boo[2] + 0x7F); *v = 0; } else { *v = boo[3]; *a = boo[2] | (boo[1] << 8); - } + } */ + + *v = boo[3]; + *a = boo[2] | (boo[1] << 8); + /* 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. */ @@ -562,7 +564,7 @@ void FCEUI_CheatSearchBegin(void) { } -static int INLINE CAbs(int x) { +static INLINE int CAbs(int x) { if (x < 0) return(0 - x); return x; diff --git a/src/cheat.h b/src/cheat.h index 9081c96..3052f54 100644 --- a/src/cheat.h +++ b/src/cheat.h @@ -6,8 +6,8 @@ extern uint8 *MMapPtrs[64]; void FCEU_CheatResetRAM(void); void FCEU_CheatAddRAM(int s, uint32 A, uint8 *p); -void FCEU_LoadGameCheats(FILE *override); -void FCEU_FlushGameCheats(FILE *override, int nosave); +void FCEU_LoadGameCheats(void); +void FCEU_FlushGameCheats(void); void FCEU_ApplyPeriodicCheats(void); void FCEU_PowerCheats(void); diff --git a/src/crc32.c b/src/crc32.c index 2daa51d..fc70611 100644 --- a/src/crc32.c +++ b/src/crc32.c @@ -103,8 +103,3 @@ uint32 CalcCRC32(uint32 crc, uint8 *buf, uint32 len) { return(crc32(crc, buf, len)); } - -uint32 FCEUI_CRC32(uint32 crc, uint8 *buf, uint32 len) -{ - return(CalcCRC32(crc, buf, len)); -} diff --git a/src/debug.c b/src/debug.c index 53449d6..1786a89 100644 --- a/src/debug.c +++ b/src/debug.c @@ -18,42 +18,47 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include #include #include +#include + #include "fceu-types.h" #include "x6502.h" #include "fceu.h" #include "debug.h" #include "cart.h" - void FCEUI_DumpVid(const char *fname, uint32 start, uint32 end) { - FILE *fp = FCEUD_UTF8fopen(fname, "wb"); + RFILE *fp = filestream_open(fname, + RETRO_VFS_FILE_ACCESS_WRITE, + RETRO_VFS_FILE_ACCESS_HINT_NONE); fceuindbg = 1; start &= 0x3FFF; end &= 0x3FFF; for (; start <= end; start++) - fputc(VPage[start >> 10][start], fp); - fclose(fp); + filestream_putc(fp, VPage[start >> 10][start]); + filestream_close(fp); fceuindbg = 0; } void FCEUI_DumpMem(const char *fname, uint32 start, uint32 end) { - FILE *fp = FCEUD_UTF8fopen(fname, "wb"); + RFILE *fp = filestream_open(fname, + RETRO_VFS_FILE_ACCESS_WRITE, + RETRO_VFS_FILE_ACCESS_HINT_NONE); fceuindbg = 1; for (; start <= end; start++) - fputc(ARead[start](start), fp); - fclose(fp); + filestream_putc(fp, ARead[start](start)); + filestream_close(fp); fceuindbg = 0; } void FCEUI_LoadMem(const char *fname, uint32 start, int hl) { int t; - - FILE *fp = FCEUD_UTF8fopen(fname, "rb"); - while ((t = fgetc(fp)) >= 0) { + RFILE *fp = filestream_open(fname, + RETRO_VFS_FILE_ACCESS_READ, + RETRO_VFS_FILE_ACCESS_HINT_NONE); + while ((t = filestream_getc(fp)) >= 0) { if (start > 0xFFFF) break; if (hl) { extern uint8 *Page[32]; @@ -63,7 +68,7 @@ void FCEUI_LoadMem(const char *fname, uint32 start, int hl) { BWrite[start](start, t); start++; } - fclose(fp); + filestream_close(fp); } #ifdef FCEUDEF_DEBUGGER diff --git a/src/drawing.h b/src/drawing.h index 6a8a4f4..110dd48 100644 --- a/src/drawing.h +++ b/src/drawing.h @@ -1,32 +1,6 @@ #ifndef _FCEU_DRAWING_H #define _FCEU_DRAWING_H -void DrawTextLineBG(uint8 *dest) { - int x, y; - static int otable[7] = { 81, 49, 30, 17, 8, 3, 0 }; - for (y = 0; y < 14; y++) { - int offs; - - if (y >= 7) offs = otable[13 - y]; - else offs = otable[y]; - - for (x = offs; x < (256 - offs); x++) - dest[y * 256 + x] = (dest[y * 256 + x] & 0x0f) | 0xC0; - } -} - -static void DrawMessage(void) { - if (howlong) { - uint8 *t; - howlong--; - t = XBuf + (FSettings.LastSLine - 16) * 256; - if (t >= XBuf) { - DrawTextLineBG(t); - DrawTextTrans(t + 256 * 3 + (128 - strlen(errmsg) * 4), 256, (uint8*)errmsg, 4); - } - } -} - 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, diff --git a/src/driver.h b/src/driver.h index b3f029b..910f5f9 100644 --- a/src/driver.h +++ b/src/driver.h @@ -1,7 +1,7 @@ #ifndef _FCEU_DRIVER_H #define _FCEU_DRIVER_H -#include +#include #ifdef __cplusplus extern "C" { @@ -27,64 +27,23 @@ extern "C" { #define FCEUNPCMD_LOADCHEATS 0x82 #define FCEUNPCMD_TEXT 0x90 -FILE *FCEUD_UTF8fopen(const char *fn, const char *mode); - /* This makes me feel dirty for some reason. */ 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_GetPalette(uint8 i, uint8 *r, uint8 *g, uint8 *b); /* Displays an error. Can block or not. */ void FCEUD_PrintError(char *s); void FCEUD_Message(char *s); -void FCEUD_DispMessage(char *m); -#ifdef NETWORK -/* Network interface */ - -/* Call only when a game is loaded. */ -int FCEUI_NetplayStart(int nlocal, int divisor); - -/* Call when network play needs to stop. */ -void FCEUI_NetplayStop(void); - -/* Note: YOU MUST NOT CALL ANY FCEUI_* FUNCTIONS WHILE IN FCEUD_SendData() or - FCEUD_RecvData(). -*/ - -/* Return 0 on failure, 1 on success. */ -int FCEUD_SendData(void *data, uint32 len); -int FCEUD_RecvData(void *data, uint32 len); - -/* Display text received over the network. */ -void FCEUD_NetplayText(uint8 *text); - -/* Encode and send text over the network. */ -void FCEUI_NetplayText(uint8 *text); - -/* Called when a fatal error occurred and network play can't continue. This function - should call FCEUI_NetplayStop() after it has deinitialized the network on the driver - side. -*/ -void FCEUD_NetworkClose(void); -#endif - -int FCEUI_BeginWaveRecord(char *fn); -int FCEUI_EndWaveRecord(void); +void FCEUD_DispMessage(enum retro_log_level level, unsigned duration, const char *str); +void FCEU_DispMessage(enum retro_log_level level, unsigned duration, const char *format, ...); void FCEUI_ResetNES(void); void FCEUI_PowerNES(void); -void FCEUI_NTSCSELHUE(void); -void FCEUI_NTSCSELTINT(void); -void FCEUI_NTSCDEC(void); -void FCEUI_NTSCINC(void); -void FCEUI_GetNTSCTH(int *tint, int *hue); -void FCEUI_SetNTSCTH(int n, int tint, int hue); - 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); @@ -123,26 +82,20 @@ void FCEUI_DisableFourScore(int s); /* New interface functions */ -/* 0 to order screen snapshots numerically(0.png), 1 to order them file base-numerically(smb3-0.png). */ -void FCEUI_SetSnapName(int a); - /* 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); -#ifdef __LIBRETRO__ -FCEUGI *FCEUI_LoadGame(const char *name, uint8_t *buf, size_t bufsize); -#else -/* name=path and file to load. returns 0 on failure, 1 on success */ -FCEUGI *FCEUI_LoadGame(const char *name); -#endif - -#ifdef COPYFAMI -/* Fake UNIF board to start new CFHI instance */ -FCEUGI *FCEUI_CopyFamiStart(); -#endif +/* frontend_post_load_init_cb() is called immediately + * after loading the ROM, allowing any frontend + * initialisation that is dependent on ROM type to + * be performed before the regular internal post-load + * initialisation */ +typedef void (*frontend_post_load_init_cb_t)(void); +FCEUGI *FCEUI_LoadGame(const char *name, const uint8_t *databuf, size_t databufsize, + frontend_post_load_init_cb_t frontend_post_load_init_cb); /* allocates memory. 0 on failure, 1 on success. */ int FCEUI_Initialize(void); @@ -176,14 +129,9 @@ void FCEUI_FrameSkip(int x); /* First and last scanlines to render, for ntsc and pal emulation. */ void FCEUI_SetRenderedLines(int ntscf, int ntscl, int palf, int pall); -/* Sets the base directory(save states, snapshots, etc. are saved in directories - below this directory. */ -void FCEUI_SetBaseDirectory(char *dir); - -#ifdef __LIBRETRO__ -void FCEUI_SetSaveDirectory(char *sav_dir); -#endif - +/* Sets the base directory (bios and palette files are saved + in this directory. */ +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. @@ -199,20 +147,7 @@ void FCEUI_Sound(int Rate); void FCEUI_SetSoundVolume(uint32 volume); void FCEUI_SetSoundQuality(int quality); -void FCEUI_SelectState(int); - -/* "fname" overrides the default save state filename code if non-NULL. */ -void FCEUI_SaveState(char *fname); -void FCEUI_LoadState(char *fname); - -void FCEUI_SelectMovie(int); -void FCEUI_SaveMovie(char *fname); -void FCEUI_LoadMovie(char *fname); - int32 FCEUI_GetDesiredFPS(void); -void FCEUI_SaveSnapshot(void); -void FCEU_DispMessage(char *format, ...); -#define FCEUI_DispMessage FCEU_DispMessage int FCEUI_DecodePAR(const char *code, uint16 *a, uint8 *v, int *c, int *type); int FCEUI_DecodeGG(const char *str, uint16 *a, uint8 *v, int *c); @@ -233,17 +168,7 @@ int FCEUI_SetCheat(uint32 which, const char *name, int32 a, int32 v, int compare void FCEUI_CheatSearchShowExcluded(void); void FCEUI_CheatSearchSetCurrentAsOriginal(void); -#define FCEUIOD_STATE 0 -#define FCEUIOD_SNAPS 1 -#define FCEUIOD_NV 2 -#define FCEUIOD_CHEATS 3 -#define FCEUIOD_MISC 4 -#define FCEUIOD_MOVIE 5 - -#define FCEUIOD__COUNT 6 - -void FCEUI_SetDirOverride(int which, char *n); - +#ifdef FCEUDEF_DEBUGGER void FCEUI_MemDump(uint16 a, int32 len, void (*callb)(uint16 a, uint8 v)); uint8 FCEUI_MemSafePeek(uint16 A); void FCEUI_MemPoke(uint16 a, uint8 v, int hl); @@ -251,10 +176,8 @@ void FCEUI_NMI(void); void FCEUI_IRQ(void); uint16 FCEUI_Disassemble(void *XA, uint16 a, char *stringo); void FCEUI_GetIVectors(uint16 *reset, uint16 *irq, uint16 *nmi); +#endif -uint32 FCEUI_CRC32(uint32 crc, uint8 *buf, uint32 len); - -/* void FCEUI_ToggleTileView(void); */ void FCEUI_SetLowPass(int q); void FCEUI_NSFSetVis(int mode); @@ -271,7 +194,7 @@ int FCEUI_FDSInsert(int oride); int FCEUI_FDSEject(void); void FCEUI_FDSSelect(void); -int FCEUI_DatachSet(const uint8 *rcode); +int FCEUI_DatachSet(uint8 *rcode); #ifdef __cplusplus } diff --git a/src/drivers/libretro/griffin.c b/src/drivers/libretro/griffin.c deleted file mode 100644 index 3158363..0000000 --- a/src/drivers/libretro/griffin.c +++ /dev/null @@ -1,42 +0,0 @@ -#ifdef WANT_GRIFFIN - -#include "drivers/libretro/libretro.c" - -#ifndef STATIC_LINKING -#include "drivers/libretro/libretro-common/streams/memory_stream.c" -#include "drivers/libretro/libretro-common/string/stdstring.c" -#include "drivers/libretro/libretro-common/encodings/encoding_utf.c" -#include "drivers/libretro/libretro-common/compat/compat_strl.c" -#endif - -#include "cart.c" -#include "cheat.c" -#include "crc32.c" - -#ifdef DEBUG -#include "debug.c" -#endif -#include "fceu-endian.c" -#include "fceu-memory.c" -#include "misc.c" -#include "fceu.c" -#include "fds.c" -#include "fds_apu.c" -#include "file.c" -#include "filter.c" -#include "general.c" -#include "input.c" -#include "md5.c" -#include "nsf.c" -#include "palette.c" -#include "ppu.c" -#include "sound.c" -#include "state.c" -#include "video.c" -#include "vsuni.c" - -/* #include "x6502.c" */ -/* #include "ines.c" */ -/* #include "unif.c" */ - -#endif diff --git a/src/drivers/libretro/libretro-common/compat/compat_posix_string.c b/src/drivers/libretro/libretro-common/compat/compat_posix_string.c new file mode 100644 index 0000000..6a2f07e --- /dev/null +++ b/src/drivers/libretro/libretro-common/compat/compat_posix_string.c @@ -0,0 +1,104 @@ +/* Copyright (C) 2010-2020 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (compat_posix_string.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 + +#ifdef _WIN32 + +#undef strcasecmp +#undef strdup +#undef isblank +#undef strtok_r +#include +#include +#include +#include + +#include + +int retro_strcasecmp__(const char *a, const char *b) +{ + while (*a && *b) + { + int a_ = tolower(*a); + int b_ = tolower(*b); + + if (a_ != b_) + return a_ - b_; + + a++; + b++; + } + + return tolower(*a) - tolower(*b); +} + +char *retro_strdup__(const char *orig) +{ + size_t len = strlen(orig) + 1; + char *ret = (char*)malloc(len); + if (!ret) + return NULL; + + strlcpy(ret, orig, len); + return ret; +} + +int retro_isblank__(int c) +{ + return (c == ' ') || (c == '\t'); +} + +char *retro_strtok_r__(char *str, const char *delim, char **saveptr) +{ + char *first = NULL; + if (!saveptr || !delim) + return NULL; + + if (str) + *saveptr = str; + + do + { + char *ptr = NULL; + first = *saveptr; + while (*first && strchr(delim, *first)) + *first++ = '\0'; + + if (*first == '\0') + return NULL; + + ptr = first + 1; + + while (*ptr && !strchr(delim, *ptr)) + ptr++; + + *saveptr = ptr + (*ptr ? 1 : 0); + *ptr = '\0'; + } while (strlen(first) == 0); + + return first; +} + +#endif diff --git a/src/drivers/libretro/libretro-common/compat/compat_snprintf.c b/src/drivers/libretro/libretro-common/compat/compat_snprintf.c index b69ad04..d7320cc 100644 --- a/src/drivers/libretro/libretro-common/compat/compat_snprintf.c +++ b/src/drivers/libretro/libretro-common/compat/compat_snprintf.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2018 The RetroArch team +/* Copyright (C) 2010-2020 The RetroArch team * * --------------------------------------------------------------------------------------- * The following license statement only applies to this file (compat_snprintf.c). @@ -33,12 +33,12 @@ #if _MSC_VER < 1300 #define _vscprintf c89_vscprintf_retro__ -static int c89_vscprintf_retro__(const char *format, va_list pargs) +static int c89_vscprintf_retro__(const char *fmt, va_list pargs) { int retval; va_list argcopy; va_copy(argcopy, pargs); - retval = vsnprintf(NULL, 0, format, argcopy); + retval = vsnprintf(NULL, 0, fmt, argcopy); va_end(argcopy); return retval; } @@ -46,38 +46,36 @@ static int c89_vscprintf_retro__(const char *format, va_list pargs) /* http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 */ -int c99_vsnprintf_retro__(char *outBuf, size_t size, const char *format, va_list ap) +int c99_vsnprintf_retro__(char *s, size_t len, const char *fmt, va_list ap) { int count = -1; - if (size != 0) + if (len != 0) { #if (_MSC_VER <= 1310) - count = _vsnprintf(outBuf, size - 1, format, ap); + count = _vsnprintf(s, len - 1, fmt, ap); #else - count = _vsnprintf_s(outBuf, size, size - 1, format, ap); + count = _vsnprintf_s(s, len, len - 1, fmt, ap); #endif } if (count == -1) - count = _vscprintf(format, ap); + count = _vscprintf(fmt, ap); - if (count == size) - { - /* there was no room for a NULL, so truncate the last character */ - outBuf[size - 1] = '\0'; - } + /* there was no room for a NULL, so truncate the last character */ + if (count == len && len) + s[len - 1] = '\0'; return count; } -int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...) +int c99_snprintf_retro__(char *s, size_t len, const char *fmt, ...) { int count; va_list ap; - va_start(ap, format); - count = c99_vsnprintf_retro__(outBuf, size, format, ap); + va_start(ap, fmt); + count = c99_vsnprintf_retro__(s, len, fmt, ap); va_end(ap); return count; diff --git a/src/drivers/libretro/libretro-common/compat/compat_strcasestr.c b/src/drivers/libretro/libretro-common/compat/compat_strcasestr.c new file mode 100644 index 0000000..4129dab --- /dev/null +++ b/src/drivers/libretro/libretro-common/compat/compat_strcasestr.c @@ -0,0 +1,58 @@ +/* Copyright (C) 2010-2020 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (compat_strcasestr.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 + +/* Pretty much strncasecmp. */ +static int casencmp(const char *a, const char *b, size_t n) +{ + size_t i; + + for (i = 0; i < n; i++) + { + int a_lower = tolower(a[i]); + int b_lower = tolower(b[i]); + if (a_lower != b_lower) + return a_lower - b_lower; + } + + return 0; +} + +char *strcasestr_retro__(const char *haystack, const char *needle) +{ + size_t i, search_off; + size_t hay_len = strlen(haystack); + size_t needle_len = strlen(needle); + + if (needle_len > hay_len) + return NULL; + + search_off = hay_len - needle_len; + for (i = 0; i <= search_off; i++) + if (!casencmp(haystack + i, needle, needle_len)) + return (char*)haystack + i; + + return NULL; +} diff --git a/src/drivers/libretro/libretro-common/compat/compat_strl.c b/src/drivers/libretro/libretro-common/compat/compat_strl.c index 94cb39b..3172310 100644 --- a/src/drivers/libretro/libretro-common/compat/compat_strl.c +++ b/src/drivers/libretro/libretro-common/compat/compat_strl.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2018 The RetroArch team +/* Copyright (C) 2010-2020 The RetroArch team * * --------------------------------------------------------------------------------------- * The following license statement only applies to this file (compat_strl.c). diff --git a/src/drivers/libretro/libretro-common/include/encodings/win32.h b/src/drivers/libretro/libretro-common/compat/fopen_utf8.c similarity index 56% rename from src/drivers/libretro/libretro-common/include/encodings/win32.h rename to src/drivers/libretro/libretro-common/compat/fopen_utf8.c index d4221bd..85abb59 100644 --- a/src/drivers/libretro/libretro-common/include/encodings/win32.h +++ b/src/drivers/libretro/libretro-common/compat/fopen_utf8.c @@ -1,7 +1,7 @@ -/* Copyright (C) 2010-2018 The RetroArch team +/* Copyright (C) 2010-2020 The RetroArch team * * --------------------------------------------------------------------------------------- - * The following license statement only applies to this file (utf.h). + * The following license statement only applies to this file (fopen_utf8.c). * --------------------------------------------------------------------------------------- * * Permission is hereby granted, free of charge, @@ -20,44 +20,44 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef _LIBRETRO_ENCODINGS_WIN32_H -#define _LIBRETRO_ENCODINGS_WIN32_H +#include +#include +#include +#include -#ifndef _XBOX -#ifdef _WIN32 -/*#define UNICODE -#include -#include */ - -#ifdef __cplusplus -extern "C" { +#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX) +#ifndef LEGACY_WIN32 +#define LEGACY_WIN32 +#endif #endif -#include +#ifdef _WIN32 +#undef fopen -#ifdef __cplusplus +void *fopen_utf8(const char * filename, const char * mode) +{ +#if defined(LEGACY_WIN32) + FILE *ret = NULL; + char * filename_local = utf8_to_local_string_alloc(filename); + + if (!filename_local) + return NULL; + ret = fopen(filename_local, mode); + if (filename_local) + free(filename_local); + return ret; +#else + wchar_t * filename_w = utf8_to_utf16_string_alloc(filename); + wchar_t * mode_w = utf8_to_utf16_string_alloc(mode); + FILE* ret = NULL; + + if (filename_w && mode_w) + ret = _wfopen(filename_w, mode_w); + if (filename_w) + free(filename_w); + if (mode_w) + free(mode_w); + return ret; +#endif } #endif - -#endif -#endif - -#ifdef UNICODE -#define CHAR_TO_WCHAR_ALLOC(s, ws) \ - size_t ws##_size = (NULL != s && s[0] ? strlen(s) : 0) + 1; \ - wchar_t *ws = (wchar_t*)calloc(ws##_size, 2); \ - if (NULL != s && s[0]) \ - MultiByteToWideChar(CP_UTF8, 0, s, -1, ws, ws##_size / sizeof(wchar_t)); - -#define WCHAR_TO_CHAR_ALLOC(ws, s) \ - size_t s##_size = ((NULL != ws && ws[0] ? wcslen((const wchar_t*)ws) : 0) / 2) + 1; \ - char *s = (char*)calloc(s##_size, 1); \ - if (NULL != ws && ws[0]) \ - utf16_to_char_string((const uint16_t*)ws, s, s##_size); - -#else -#define CHAR_TO_WCHAR_ALLOC(s, ws) char *ws = (NULL != s && s[0] ? strdup(s) : NULL); -#define WCHAR_TO_CHAR_ALLOC(ws, s) char *s = (NULL != ws && ws[0] ? strdup(ws) : NULL); -#endif - -#endif diff --git a/src/drivers/libretro/libretro-common/encodings/encoding_utf.c b/src/drivers/libretro/libretro-common/encodings/encoding_utf.c index b6ad2f9..2760824 100644 --- a/src/drivers/libretro/libretro-common/encodings/encoding_utf.c +++ b/src/drivers/libretro/libretro-common/encodings/encoding_utf.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2018 The RetroArch team +/* Copyright (C) 2010-2020 The RetroArch team * * --------------------------------------------------------------------------------------- * The following license statement only applies to this file (encoding_utf.c). @@ -37,6 +37,8 @@ #include #endif +#define UTF8_WALKBYTE(string) (*((*(string))++)) + static unsigned leading_ones(uint8_t c) { unsigned ones = 0; @@ -89,13 +91,14 @@ size_t utf8_conv_utf32(uint32_t *out, size_t out_chars, bool utf16_conv_utf8(uint8_t *out, size_t *out_chars, const uint16_t *in, size_t in_size) { - static uint8_t kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - size_t out_pos = 0; - size_t in_pos = 0; + size_t out_pos = 0; + size_t in_pos = 0; + static const + uint8_t utf8_limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; for (;;) { - unsigned numAdds; + unsigned num_adds; uint32_t value; if (in_pos == in_size) @@ -124,21 +127,21 @@ bool utf16_conv_utf8(uint8_t *out, size_t *out_chars, value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000; } - for (numAdds = 1; numAdds < 5; numAdds++) - if (value < (((uint32_t)1) << (numAdds * 5 + 6))) + for (num_adds = 1; num_adds < 5; num_adds++) + if (value < (((uint32_t)1) << (num_adds * 5 + 6))) break; if (out) - out[out_pos] = (char)(kUtf8Limits[numAdds - 1] - + (value >> (6 * numAdds))); + out[out_pos] = (char)(utf8_limits[num_adds - 1] + + (value >> (6 * num_adds))); out_pos++; do { - numAdds--; + num_adds--; if (out) out[out_pos] = (char)(0x80 - + ((value >> (6 * numAdds)) & 0x3F)); + + ((value >> (6 * num_adds)) & 0x3F)); out_pos++; - }while (numAdds != 0); + }while (num_adds != 0); } *out_chars = out_pos; @@ -166,13 +169,15 @@ size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars) while (*sb && chars-- > 0) { sb++; - while ((*sb & 0xC0) == 0x80) sb++; + while ((*sb & 0xC0) == 0x80) + sb++; } if ((size_t)(sb - sb_org) > d_len-1 /* NUL */) { sb = sb_org + d_len-1; - while ((*sb & 0xC0) == 0x80) sb--; + while ((*sb & 0xC0) == 0x80) + sb--; } memcpy(d, sb_org, sb-sb_org); @@ -184,14 +189,18 @@ size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars) const char *utf8skip(const char *str, size_t chars) { const uint8_t *strb = (const uint8_t*)str; + if (!chars) return str; + do { strb++; - while ((*strb & 0xC0)==0x80) strb++; + while ((*strb & 0xC0)==0x80) + strb++; chars--; - } while(chars); + }while (chars); + return (const char*)strb; } @@ -211,24 +220,22 @@ size_t utf8len(const char *string) return ret; } -#define utf8_walkbyte(string) (*((*(string))++)) - /* Does not validate the input, returns garbage if it's not UTF-8. */ uint32_t utf8_walk(const char **string) { - uint8_t first = utf8_walkbyte(string); + uint8_t first = UTF8_WALKBYTE(string); uint32_t ret = 0; if (first < 128) return first; - ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F); + ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F); if (first >= 0xE0) { - ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F); + ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F); if (first >= 0xF0) { - ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F); + ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F); return ret | (first & 7) << 18; } return ret | (first & 15) << 12; @@ -277,9 +284,7 @@ bool utf16_to_char_string(const uint16_t *in, char *s, size_t len) static char *mb_to_mb_string_alloc(const char *str, enum CodePage cp_in, enum CodePage cp_out) { - char *path_buf = NULL; wchar_t *path_buf_wide = NULL; - int path_buf_len = 0; int path_buf_wide_len = MultiByteToWideChar(cp_in, 0, str, -1, NULL, 0); /* Windows 95 will return 0 from these functions with @@ -292,54 +297,51 @@ static char *mb_to_mb_string_alloc(const char *str, * MultiByteToWideChar also supports CP_UTF7 and CP_UTF8. */ - if (path_buf_wide_len) - { - path_buf_wide = (wchar_t*) - calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t)); - - if (path_buf_wide) - { - MultiByteToWideChar(cp_in, 0, - str, -1, path_buf_wide, path_buf_wide_len); - - if (*path_buf_wide) - { - path_buf_len = WideCharToMultiByte(cp_out, 0, - path_buf_wide, -1, NULL, 0, NULL, NULL); - - if (path_buf_len) - { - path_buf = (char*) - calloc(path_buf_len + sizeof(char), sizeof(char)); - - if (path_buf) - { - WideCharToMultiByte(cp_out, 0, - path_buf_wide, -1, path_buf, - path_buf_len, NULL, NULL); - - free(path_buf_wide); - - if (*path_buf) - return path_buf; - - free(path_buf); - return NULL; - } - } - else - { - free(path_buf_wide); - return strdup(str); - } - } - } - } - else + if (!path_buf_wide_len) return strdup(str); + path_buf_wide = (wchar_t*) + calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t)); + if (path_buf_wide) + { + MultiByteToWideChar(cp_in, 0, + str, -1, path_buf_wide, path_buf_wide_len); + + if (*path_buf_wide) + { + int path_buf_len = WideCharToMultiByte(cp_out, 0, + path_buf_wide, -1, NULL, 0, NULL, NULL); + + if (path_buf_len) + { + char *path_buf = (char*) + calloc(path_buf_len + sizeof(char), sizeof(char)); + + if (path_buf) + { + WideCharToMultiByte(cp_out, 0, + path_buf_wide, -1, path_buf, + path_buf_len, NULL, NULL); + + free(path_buf_wide); + + if (*path_buf) + return path_buf; + + free(path_buf); + return NULL; + } + } + else + { + free(path_buf_wide); + return strdup(str); + } + } + free(path_buf_wide); + } return NULL; } @@ -379,13 +381,13 @@ char* local_to_utf8_string_alloc(const char *str) wchar_t* utf8_to_utf16_string_alloc(const char *str) { #ifdef _WIN32 - int len = 0; - int out_len = 0; + int len = 0; + int out_len = 0; #else - size_t len = 0; + size_t len = 0; size_t out_len = 0; #endif - wchar_t *buf = NULL; + wchar_t *buf = NULL; if (!str || !*str) return NULL; diff --git a/src/drivers/libretro/libretro-common/file/file_path.c b/src/drivers/libretro/libretro-common/file/file_path.c new file mode 100644 index 0000000..fc11270 --- /dev/null +++ b/src/drivers/libretro/libretro-common/file/file_path.c @@ -0,0 +1,1381 @@ +/* Copyright (C) 2010-2020 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (file_path.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 +#include +#include + +#include + +#include +#include +#include +#include +#include