Merge pull request #1 from libretro/master

bring up to date
This commit is contained in:
arpruss
2022-12-31 21:17:53 -06:00
committed by GitHub
267 changed files with 45803 additions and 8221 deletions

33
.github/workflows/compilation.yml vendored Normal file
View File

@@ -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

33
.github/workflows/crowdin_prep.yml vendored Normal file
View File

@@ -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"

46
.github/workflows/crowdin_translate.yml vendored Normal file
View File

@@ -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 }}

302
.gitlab-ci.yml Normal file
View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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.

4
intl/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
__pycache__
crowdin-cli.jar
*.h
*.json

70
intl/activate.py Executable file
View File

@@ -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>", CORE_NAME)
prep_txt = prep_txt.replace("<PATH/TO>/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>", CORE_NAME)
translate_txt = translate_txt.replace('<PATH/TO>/libretro_core_options_intl.h',
core_intl_file)
with open(TRANSLATE_WF, 'w') as wf_file:
wf_file.write(translate_txt)

95
intl/core_option_regex.py Normal file
View File

@@ -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']')

620
intl/core_option_translation.py Executable file
View File

@@ -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 { '_<lang>': { '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 '<core_name>.h' files in 'intl/_<lang>/' 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 { '_<lang>': { 'macro': 'string', ... }, ... }.
:return: Dictionary of the form { '_<lang>': 'path/to/file (./intl/_<lang>/<core_name>.h)', ... }.
"""
files = {}
for localisation in keyword_string_dict:
path = os.path.join(intl_dir_path, core_name) # intl/<core_name>/
files[localisation] = os.path.join(path, localisation + '.h') # intl/<core_name>/_<lang>.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 { '_<lang>': 'path/to/file (./intl/_<lang>/<core_name>.h)', ... }.
:return: Dictionary of the form { '_<lang>': 'path/to/file (./intl/_<lang>/<core_name>.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/<core_name> 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/<core_name> 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/<core_name>/_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 <libretro.h>\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/<core_name>/_*
if files[file]['is_file'] \
and file.startswith('_') \
and file.endswith('.h') \
and not file.startswith('_us'):
translation_path = files[file]['path'] # <core_name>_<lang>.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: # <core name>.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!')

13
intl/crowdin.yaml Normal file
View File

@@ -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",
},
]

30
intl/crowdin_prep.py Executable file
View File

@@ -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!')

93
intl/crowdin_source_upload.py Executable file
View File

@@ -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

39
intl/crowdin_translate.py Executable file
View File

@@ -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!')

View File

@@ -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

16
intl/download_workflow.py Executable file
View File

@@ -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])

125
intl/initial_sync.py Executable file
View File

@@ -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

30
intl/remove_initial_cycle.py Executable file
View File

@@ -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)

15
intl/upload_workflow.py Executable file
View File

@@ -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])

476
intl/v1_to_v2_converter.py Executable file
View File

@@ -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.')

View File

@@ -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

View File

@@ -1,8 +0,0 @@
#ifndef INTTYPES_H
#define INTTYPES_H
#define PRId64 "ld"
#define PRIu64 "lu"
#define PRIuPTR "lu"
#endif //INTTYPES_H

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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));
}
}

136
src/boards/126-422-534.c Normal file
View File

@@ -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);
}

View File

@@ -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");
}

96
src/boards/134.c Normal file
View File

@@ -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");
}

View File

@@ -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();
}

View File

@@ -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");
}

119
src/boards/162.c Normal file
View File

@@ -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;
}
}

124
src/boards/163.c Normal file
View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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;

97
src/boards/195.c Normal file
View File

@@ -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");
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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

87
src/boards/233.c Normal file
View File

@@ -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;
}

View File

@@ -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" },
{ &reg, 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;
}

111
src/boards/236.c Normal file
View File

@@ -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;
}

View File

@@ -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");
}

157
src/boards/268.c Normal file
View File

@@ -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);
}

View File

@@ -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;

179
src/boards/272.c Normal file
View File

@@ -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);
}

View File

@@ -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);
}

59
src/boards/291.c Normal file
View File

@@ -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");
}

91
src/boards/293.c Normal file
View File

@@ -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);
}

61
src/boards/294.c Normal file
View File

@@ -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");
}

88
src/boards/310.c Normal file
View File

@@ -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" },
{&regAddr, 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);
}

86
src/boards/319.c Normal file
View File

@@ -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);
}

98
src/boards/326.c Normal file
View File

@@ -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);
}

137
src/boards/330.c Normal file
View File

@@ -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");
}

65
src/boards/334.c Normal file
View File

@@ -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");
}

338
src/boards/351.c Normal file
View File

@@ -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) <<MMC1_count++;
if (MMC1_count ==5) {
MMC1_reg[A >>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);
}
}

View File

@@ -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

92
src/boards/354.c Normal file
View File

@@ -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);
}

View File

@@ -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

View File

@@ -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 }

View File

@@ -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

View File

@@ -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

View File

@@ -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");
}

112
src/boards/368.c Normal file
View File

@@ -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);
}

View File

@@ -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

96
src/boards/370.c Normal file
View File

@@ -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");
}

View File

@@ -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.
*/

121
src/boards/375.c Normal file
View File

@@ -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");
}

65
src/boards/376.c Normal file
View File

@@ -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");
}

64
src/boards/377.c Normal file
View File

@@ -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");
}

View File

@@ -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;

View File

@@ -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

108
src/boards/383.c Normal file
View File

@@ -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");
}

View File

@@ -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

View File

@@ -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

71
src/boards/391.c Normal file
View File

@@ -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");
}

111
src/boards/393.c Normal file
View File

@@ -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");
}

67
src/boards/395.c Normal file
View File

@@ -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");
}

73
src/boards/396.c Normal file
View File

@@ -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");
}

View File

@@ -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" },
{ &reg, 1, "REG" },
{ &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;

96
src/boards/401.c Normal file
View File

@@ -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");
}

82
src/boards/403.c Normal file
View File

@@ -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(&reg, 3, 0, "REGS");
}

89
src/boards/410.c Normal file
View File

@@ -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");
}

85
src/boards/411.c Normal file
View File

@@ -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");
}

64
src/boards/414.c Normal file
View File

@@ -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);
}

111
src/boards/416.c Normal file
View File

@@ -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(&reg, 1, 0, "REGS");
AddExState(&smb2j_reg, 1, 0, "SMBJ");
AddExState(&IRQa, 1, 0, "IRQa");
AddExState(&IRQCount, 2, 0, "IRQC");
}

80
src/boards/417.c Normal file
View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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[] =
{
{ &reg, 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);
}

75
src/boards/432.c Normal file
View File

@@ -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");
}

72
src/boards/433.c Normal file
View File

@@ -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;
}

67
src/boards/434.c Normal file
View File

@@ -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");
}

63
src/boards/436.c Normal file
View File

@@ -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");
}

67
src/boards/437.c Normal file
View File

@@ -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");
}

67
src/boards/438.c Normal file
View File

@@ -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");
}

68
src/boards/441.c Normal file
View File

@@ -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");
}

79
src/boards/443.c Normal file
View File

@@ -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");
}

82
src/boards/444.c Normal file
View File

@@ -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");
}

95
src/boards/449.c Normal file
View File

@@ -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);
}

Some files were not shown because too many files have changed in this diff Show More