From 99eb406b1a101864eecd627c0a43943cbb3c417e Mon Sep 17 00:00:00 2001 From: mjbudd77 Date: Sat, 1 Oct 2022 16:29:02 -0400 Subject: [PATCH 01/26] Added appveyor github release functionality. Master auto builds are now uploaded to a rolling interim-build pre-release. Release tag builds will upload official release builds from appveyor automatically. --- appveyor.yml | 36 ++++++-- pipelines/build.pl | 170 +++++++++++++++++++++++++++++++++++++ pipelines/debpkg.pl | 5 +- pipelines/linux_build.sh | 18 +++- pipelines/macOS_build.sh | 30 +++++-- pipelines/qwin64_build.bat | 20 +++-- pipelines/win32_build.bat | 17 +++- pipelines/win64_build.bat | 17 +++- scripts/fceuVersion.pl | 74 ++++++++++++++++ src/CMakeLists.txt | 5 ++ src/version.h | 4 +- vc/vc14_fceux.vcxproj | 4 +- 12 files changed, 369 insertions(+), 31 deletions(-) create mode 100755 pipelines/build.pl create mode 100755 scripts/fceuVersion.pl diff --git a/appveyor.yml b/appveyor.yml index 918b5583..d9c96f10 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,7 +27,7 @@ for: - job_name: Windows 32 build_script: - - cmd: pipelines/win32_build.bat + - cmd: perl pipelines/build.pl win32 - matrix: @@ -35,7 +35,7 @@ for: - job_name: Windows 64 build_script: - - cmd: pipelines/win64_build.bat + - cmd: perl pipelines/build.pl win64 - matrix: @@ -43,7 +43,7 @@ for: - job_name: Win64 Qt build_script: - - cmd: pipelines/qwin64_build.bat + - cmd: perl pipelines/build.pl win64-QtSDL - matrix: @@ -51,7 +51,7 @@ for: - job_name: Ubuntu build_script: - - sh: ./pipelines/linux_build.sh + - sh: perl pipelines/build.pl linux - matrix: @@ -59,5 +59,31 @@ for: - job_name: MacOS build_script: - - sh: ./pipelines/macOS_build.sh + - sh: perl pipelines/build.pl macOS +deploy: + + - provider: GitHub + tag: interim-build + release: interim-build + description: 'Interim Builds - Latest auto builds off master branch - commit: $(APPVEYOR_REPO_COMMIT)\nDate: $(APPVEYOR_REPO_COMMIT_TIMESTAMP)' + auth_token: + secure: 5kNj/zZ1RD5gCBq0Q4my9dBgSTYL7JVvcjv93T9i6FjYA6SAds3/Dmlz8wrRMN8E + artifact: $(WIN32_ARTIFACT), $(WIN64_ARTIFACT), $(WIN64_QTSDL_ARTIFACT), $(MACOS_ARTIFACT), $(LINUX_ARTIFACT) + draft: false + prerelease: true + force_update: true + on: + branch: master # release from master branch only + APPVEYOR_REPO_TAG: false # never deploy on tag push + + - provider: GitHub + description: 'Release Builds - commit: $(APPVEYOR_REPO_COMMIT)' + auth_token: + secure: 5kNj/zZ1RD5gCBq0Q4my9dBgSTYL7JVvcjv93T9i6FjYA6SAds3/Dmlz8wrRMN8E + artifact: $(WIN32_ARTIFACT), $(WIN64_ARTIFACT), $(WIN64_QTSDL_ARTIFACT), $(MACOS_ARTIFACT) + draft: false + prerelease: false + force_update: false + on: + APPVEYOR_REPO_TAG: true # deploy on tag push only diff --git a/pipelines/build.pl b/pipelines/build.pl new file mode 100755 index 00000000..7c469136 --- /dev/null +++ b/pipelines/build.pl @@ -0,0 +1,170 @@ +#!/usr/bin/perl + +use strict; +use File::Basename; +#use File::Spec; + +# +# Global Variables +# +my $platform = ""; +my $fceuVersionMajor = 1; +my $fceuVersionMinor = 0; +my $fceuVersionPatch = 0; + +foreach my $arg (@ARGV) +{ + #print $arg, "\n"; + + if ($platform eq "") + { + $platform = $arg; + } +} + +my $dirname = dirname(__FILE__); +my $projRoot = "$dirname/.."; +my $ReleaseBuild=0; +my $ReleaseVersion=""; + +#print "PATH: $ENV{PATH}\n"; +#print "Dir $dirname\n"; +# +($fceuVersionMajor, $fceuVersionMinor, $fceuVersionPatch) = getVersion(); + +($ReleaseBuild, $ReleaseVersion) = isReleaseBuild(); + +if ($ReleaseBuild) +{ + $ENV{FCEU_RELEASE_VERSION} = $ReleaseVersion; +} + +if ($platform eq "win32") +{ + build_win32(); +} +elsif ($platform eq "win64") +{ + build_win64(); +} +elsif ($platform eq "win64-QtSDL") +{ + build_win64_QtSDL(); +} +elsif ($platform eq "linux") +{ + build_ubuntu_linux(); +} +elsif ($platform eq "macOS") +{ + build_macOS(); +} +#-------------------------------------------------------------------------------------------- +# Build win32 version +#-------------------------------------------------------------------------------------------- +sub build_win32 +{ + chdir("$projRoot"); + + my $ret = system("cmd.exe /c pipelines\\\\win32_build.bat"); + + if ($ret != 0){ die "Build Errors Detected\n";} +} +#-------------------------------------------------------------------------------------------- +# Build win64 version +#-------------------------------------------------------------------------------------------- +sub build_win64 +{ + chdir("$projRoot"); + + my $ret = system("cmd.exe /c pipelines\\\\win64_build.bat"); + + if ($ret != 0){ die "Build Errors Detected\n";} +} +#-------------------------------------------------------------------------------------------- +# Build win64-Qt/SDL version +#-------------------------------------------------------------------------------------------- +sub build_win64_QtSDL +{ + chdir("$projRoot"); + + my $ret = system("cmd.exe /c pipelines\\\\qwin64_build.bat"); + + if ($ret != 0){ die "Build Errors Detected\n";} +} +#-------------------------------------------------------------------------------------------- +# Build Ubuntu Linux version +#-------------------------------------------------------------------------------------------- +sub build_ubuntu_linux +{ + chdir("$projRoot"); + + my $ret = system("./pipelines/linux_build.sh"); + + if ($ret != 0){ die "Build Errors Detected\n";} +} +#-------------------------------------------------------------------------------------------- +# Build MacOSX version +#-------------------------------------------------------------------------------------------- +sub build_macOS +{ + chdir("$projRoot"); + + my $ret = system("./pipelines/macOS_build.sh"); + + if ($ret != 0){ die "Build Errors Detected\n";} +} +#-------------------------------------------------------------------------------------------- +# Search src/version.h and retrieve version numbers +#-------------------------------------------------------------------------------------------- +sub getVersion +{ + my $versionHeader = "$projRoot/src/version.h"; + my $line; + my $major = 1; + my $minor = 0; + my $patch = 0; + open INFILE, "$versionHeader" or die "Error: Could not open file: $versionHeader\n"; + while ($line = ) + { + #print $line; + if ($line =~ m/\s*#define\s+FCEU_VERSION_MAJOR\s+(\d+)/) + { + $major = $1; + } + elsif ($line =~ m/\s*#define\s+FCEU_VERSION_MINOR\s+(\d+)/) + { + $minor = $1; + } + elsif ($line =~ m/\s*#define\s+FCEU_VERSION_PATCH\s+(\d+)/) + { + $patch = $1; + } + } + close(INFILE); + + return ( $major, $minor, $patch ); +} +#-------------------------------------------------------------------------------------------- +# Returns whether this is a release build and returns the version if detected +#-------------------------------------------------------------------------------------------- +sub isReleaseBuild +{ + my $isRelease = 0; + my $tagVersion = ""; + + if (defined($ENV{APPVEYOR_REPO_TAG_NAME})) + { + if ($ENV{APPVEYOR_REPO_TAG_NAME} =~ m/fceux-(\d+\.\d+\.\d+)/) + { + $tagVersion = $1; + $isRelease = 1; + } + elsif ($ENV{APPVEYOR_REPO_TAG_NAME} =~ m/(\d+\.\d+\.\d+)/) + { + $tagVersion = $1; + $isRelease = 1; + } + } + return ($isRelease, $tagVersion); +} diff --git a/pipelines/debpkg.pl b/pipelines/debpkg.pl index 758e5d02..0dd554af 100755 --- a/pipelines/debpkg.pl +++ b/pipelines/debpkg.pl @@ -1,8 +1,11 @@ #!/usr/bin/perl use strict; +use File::Basename; -my $VERSION="2.6.4"; +my $dirname = dirname(__FILE__); + +my $VERSION=`perl $dirname/../scripts/fceuVersion.pl`; my $INSTALL_PREFIX="/tmp/fceux"; my $CTL_FILENAME="$INSTALL_PREFIX/DEBIAN/control"; my $ARCH="amd64"; diff --git a/pipelines/linux_build.sh b/pipelines/linux_build.sh index 77922b5e..cc6cf21c 100755 --- a/pipelines/linux_build.sh +++ b/pipelines/linux_build.sh @@ -4,6 +4,7 @@ id pwd uname -a cat /etc/os-release +env SCRIPT_DIR=$( cd $(dirname $BASH_SOURCE[0]); pwd ); @@ -20,6 +21,10 @@ echo "APPVEYOR_SSH_KEY=$APPVEYOR_SSH_KEY"; echo "APPVEYOR_SSH_BLOCK=$APPVEYOR_SSH_BLOCK"; echo '****************************************' +if [ ! -z $FCEU_RELEASE_VERSION ]; then + APPVEYOR_CMAKE_FLAGS=" -DPUBLIC_RELEASE=1 "; +fi + echo '****************************************' echo '****************************************' echo '*** Installing Package Dependencies ***' @@ -119,6 +124,7 @@ cmake \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/usr \ -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ + $APPVEYOR_CMAKE_FLAGS \ .. make -j `nproc` make install DESTDIR=$INSTALL_PREFIX @@ -191,5 +197,13 @@ echo 'Testing Install of Package' echo '**************************************************************' sudo dpkg -i /tmp/fceux-*.deb -echo 'Pushing Debian Package to Build Artifacts' -appveyor PushArtifact /tmp/fceux-*.deb +if [ ! -z $APPVEYOR ]; then + echo 'Pushing Debian Package to Build Artifacts' + if [ -z $FCEU_RELEASE_VERSION ]; then + cp /tmp/fceux-*.deb /tmp/fceux-ubuntu-x64.deb + appveyor PushArtifact /tmp/fceux-ubuntu-x64.deb + appveyor SetVariable -Name LINUX_ARTIFACT -Value fceux-ubuntu-x64.deb + else + appveyor PushArtifact /tmp/fceux-*.deb + fi +fi diff --git a/pipelines/macOS_build.sh b/pipelines/macOS_build.sh index e4ef91fa..7b61754a 100755 --- a/pipelines/macOS_build.sh +++ b/pipelines/macOS_build.sh @@ -5,15 +5,19 @@ id pwd uname -a sw_vers +env + +SCRIPT_DIR=$( cd $(dirname $BASH_SOURCE[0]); pwd ); QT_MAJOR=5; QT_PKGNAME=qt$QT_MAJOR; -FCEUX_VERSION_MAJOR=2 -FCEUX_VERSION_MINOR=6 -FCEUX_VERSION_PATCH=4 +FCEUX_VERSION_MAJOR=`perl $SCRIPT_DIR/../scripts/fceuVersion.pl -major`; +FCEUX_VERSION_MINOR=`perl $SCRIPT_DIR/../scripts/fceuVersion.pl -minor`; +FCEUX_VERSION_PATCH=`perl $SCRIPT_DIR/../scripts/fceuVersion.pl -patch`; +FCEUX_VERSION="$FCEUX_VERSION_MAJOR.$FCEUX_VERSION_MINOR.$FCEUX_VERSION_PATCH"; SDL2_VERSION=2.0.20 -SCRIPT_DIR=$( cd $(dirname $BASH_SOURCE[0]); pwd ); +echo "Building Version: $FCEUX_VERSION"; NPROC=`getconf _NPROCESSORS_ONLN`; echo "Number of Processors: $NPROC"; @@ -34,6 +38,10 @@ echo "APPVEYOR_SSH_KEY=$APPVEYOR_SSH_KEY"; echo "APPVEYOR_SSH_BLOCK=$APPVEYOR_SSH_BLOCK"; echo '****************************************' +if [ ! -z $FCEU_RELEASE_VERSION ]; then + APPVEYOR_CMAKE_FLAGS=" -DPUBLIC_RELEASE=1 "; +fi + echo '****************************************' echo 'Install Dependency sdl2' echo '****************************************' @@ -121,13 +129,23 @@ cmake \ -DCPACK_PACKAGE_VERSION_MINOR=$FCEUX_VERSION_MINOR \ -DCPACK_PACKAGE_VERSION_PATCH=$FCEUX_VERSION_PATCH \ -DQT6=$USE_QT6 \ + $APPVEYOR_CMAKE_FLAGS \ .. || exit 1 make -j $NPROC || exit 1 #sudo make install || exit 1 # make install is already run by cpack sudo cpack -G DragNDrop || exit 1 -echo 'Pushing DMG Package to Build Artifacts' -appveyor PushArtifact fceux-*.dmg +if [ ! -z $APPVEYOR ]; then + echo 'Pushing DMG Package to Build Artifacts' + if [ -z $FCEU_RELEASE_VERSION ]; then + cp fceux-*.dmg fceux-Darwin.dmg + appveyor PushArtifact fceux-Darwin.dmg + appveyor SetVariable -Name MACOS_ARTIFACT -Value fceux-Darwin.dmg + else + appveyor PushArtifact fceux-*.dmg + appveyor SetVariable -Name MACOS_ARTIFACT -Value `ls fceux-*.dmg` + fi +fi # Debug via ssh if necessary if [ ! -z $APPVEYOR_SSH_BLOCK ]; then diff --git a/pipelines/qwin64_build.bat b/pipelines/qwin64_build.bat index 165a512c..443a4610 100644 --- a/pipelines/qwin64_build.bat +++ b/pipelines/qwin64_build.bat @@ -8,6 +8,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary cd /d %CWD% +set where cmake where nmake where msbuild @@ -36,10 +37,12 @@ del ffmpeg-5.0-full_build-shared.zip set SDL_INSTALL_PREFIX=%CD% set FFMPEG_INSTALL_PREFIX=%CD% +set PUBLIC_RELEASE=0 +IF DEFINED FCEU_RELEASE_VERSION (set PUBLIC_RELEASE=1) REM cmake -h REM cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DSDL_INSTALL_PREFIX=%SDL_INSTALL_PREFIX% .. -cmake -DQT6=0 -DSDL_INSTALL_PREFIX=%SDL_INSTALL_PREFIX% -DUSE_LIBAV=1 -DFFMPEG_INSTALL_PREFIX=%FFMPEG_INSTALL_PREFIX% -G"Visual Studio 16" -T"v142" .. +cmake -DQT6=0 -DPUBLIC_RELEASE=%PUBLIC_RELEASE% -DSDL_INSTALL_PREFIX=%SDL_INSTALL_PREFIX% -DUSE_LIBAV=1 -DFFMPEG_INSTALL_PREFIX=%FFMPEG_INSTALL_PREFIX% -G"Visual Studio 16" -T"v142" .. REM nmake msbuild /m fceux.sln /p:Configuration=Release @@ -51,23 +54,30 @@ copy %FFMPEG_INSTALL_PREFIX%\ffmpeg\bin\*.dll bin\. windeployqt --no-compiler-runtime bin\qfceux.exe +set ZIP_FILENAME=fceux-win64-QtSDL.zip +IF DEFINED FCEU_RELEASE_VERSION set ZIP_FILENAME=fceux-%FCEU_RELEASE_VERSION%-win64-QtSDL.zip + +set DEPLOY_GROUP=master +IF DEFINED APPVEYOR_REPO_TAG_NAME set DEPLOY_GROUP=%APPVEYOR_REPO_TAG_NAME% + dir bin REM Create Zip Archive -%PROJECT_ROOT%\vc\zip -X -9 -r %PROJECT_ROOT%\vc\qfceux64.zip bin +%PROJECT_ROOT%\vc\zip -X -9 -r %PROJECT_ROOT%\vc\%ZIP_FILENAME% bin @if ERRORLEVEL 1 goto end cd %PROJECT_ROOT%\output -%PROJECT_ROOT%\vc\zip -X -9 -u -r %PROJECT_ROOT%\vc\qfceux64.zip palettes luaScripts tools +%PROJECT_ROOT%\vc\zip -X -9 -u -r %PROJECT_ROOT%\vc\%ZIP_FILENAME% palettes luaScripts tools @if ERRORLEVEL 1 goto end mkdir doc copy *.chm doc\. -%PROJECT_ROOT%\vc\zip -X -9 -u -r %PROJECT_ROOT%\vc\qfceux64.zip doc +%PROJECT_ROOT%\vc\zip -X -9 -u -r %PROJECT_ROOT%\vc\%ZIP_FILENAME% doc @if ERRORLEVEL 1 goto end cd %PROJECT_ROOT% -appveyor PushArtifact %PROJECT_ROOT%\vc\qfceux64.zip +IF DEFINED APPVEYOR appveyor SetVariable -Name WIN64_QTSDL_ARTIFACT -Value %ZIP_FILENAME% +IF DEFINED APPVEYOR appveyor PushArtifact %PROJECT_ROOT%\vc\%ZIP_FILENAME% :end diff --git a/pipelines/win32_build.bat b/pipelines/win32_build.bat index 61ea22a9..bddae1f0 100644 --- a/pipelines/win32_build.bat +++ b/pipelines/win32_build.bat @@ -1,18 +1,27 @@ set PROJECT_ROOT=%~dp0.. +set BUILD_CONFIG=Release -msbuild %PROJECT_ROOT%\vc\vc14_fceux.vcxproj /p:Configuration=Release /p:Platform="Win32" +set ZIP_FILENAME=fceux-win32.zip +if defined FCEU_RELEASE_VERSION set ZIP_FILENAME=fceux-%FCEU_RELEASE_VERSION%-win32.zip +if defined FCEU_RELEASE_VERSION set BUILD_CONFIG=PublicRelease + +set DEPLOY_GROUP=master +IF DEFINED APPVEYOR_REPO_TAG_NAME set DEPLOY_GROUP=%APPVEYOR_REPO_TAG_NAME% + +msbuild %PROJECT_ROOT%\vc\vc14_fceux.vcxproj /p:Configuration=%BUILD_CONFIG% /p:Platform="Win32" @if ERRORLEVEL 1 goto end cd %PROJECT_ROOT%\vc REM Create Zip Archive cd %PROJECT_ROOT%\output -..\vc\zip -X -9 -r ..\vc\fceux.zip fceux.exe fceux.chm taseditor.chm lua5.1.dll lua51.dll 7z.dll auxlib.lua palettes luaScripts tools +..\vc\zip -X -9 -r ..\vc\%ZIP_FILENAME% fceux.exe fceux.chm taseditor.chm lua5.1.dll lua51.dll 7z.dll auxlib.lua palettes luaScripts tools @if ERRORLEVEL 1 goto end cd %PROJECT_ROOT% -appveyor PushArtifact %PROJECT_ROOT%\vc\fceux.zip +IF DEFINED APPVEYOR appveyor SetVariable -Name WIN32_ARTIFACT -Value %ZIP_FILENAME% +IF DEFINED APPVEYOR appveyor PushArtifact %PROJECT_ROOT%\vc\%ZIP_FILENAME% -:end \ No newline at end of file +:end diff --git a/pipelines/win64_build.bat b/pipelines/win64_build.bat index 3d127b8d..9a53f144 100644 --- a/pipelines/win64_build.bat +++ b/pipelines/win64_build.bat @@ -1,7 +1,15 @@ set PROJECT_ROOT=%~dp0.. +set BUILD_CONFIG=Release -msbuild %PROJECT_ROOT%\vc\vc14_fceux.vcxproj /p:Configuration=Release /p:Platform="x64" +set ZIP_FILENAME=fceux-win64.zip +if defined FCEU_RELEASE_VERSION set ZIP_FILENAME=fceux-%FCEU_RELEASE_VERSION%-win64.zip +if defined FCEU_RELEASE_VERSION set BUILD_CONFIG=PublicRelease + +set DEPLOY_GROUP=master +IF DEFINED APPVEYOR_REPO_TAG_NAME set DEPLOY_GROUP=%APPVEYOR_REPO_TAG_NAME% + +msbuild %PROJECT_ROOT%\vc\vc14_fceux.vcxproj /p:Configuration=%BUILD_CONFIG% /p:Platform="x64" @if ERRORLEVEL 1 goto end cd %PROJECT_ROOT%\vc @@ -9,13 +17,14 @@ cd %PROJECT_ROOT%\vc REM Create Zip Archive cd %PROJECT_ROOT%\output -..\vc\zip -X -9 -j ..\vc\fceux64.zip ..\vc\x64\Release\fceux64.exe ..\src\drivers\win\lua\x64\lua5.1.dll ..\src\drivers\win\lua\x64\lua51.dll ..\src\auxlib.lua ..\src\drivers\win\7z_64.dll +..\vc\zip -X -9 -j ..\vc\%ZIP_FILENAME% ..\vc\x64\%BUILD_CONFIG%\fceux64.exe ..\src\drivers\win\lua\x64\lua5.1.dll ..\src\drivers\win\lua\x64\lua51.dll ..\src\auxlib.lua ..\src\drivers\win\7z_64.dll @if ERRORLEVEL 1 goto end -..\vc\zip -X -9 -u -r ..\vc\fceux64.zip fceux.chm taseditor.chm palettes luaScripts tools +..\vc\zip -X -9 -u -r ..\vc\%ZIP_FILENAME% fceux.chm taseditor.chm palettes luaScripts tools @if ERRORLEVEL 1 goto end cd %PROJECT_ROOT% -appveyor PushArtifact %PROJECT_ROOT%\vc\fceux64.zip +IF DEFINED APPVEYOR appveyor SetVariable -Name WIN64_ARTIFACT -Value %ZIP_FILENAME% +IF DEFINED APPVEYOR appveyor PushArtifact %PROJECT_ROOT%\vc\%ZIP_FILENAME% :end diff --git a/scripts/fceuVersion.pl b/scripts/fceuVersion.pl new file mode 100755 index 00000000..67beaca0 --- /dev/null +++ b/scripts/fceuVersion.pl @@ -0,0 +1,74 @@ +#!/usr/bin/perl + +use strict; +use File::Basename; +#use File::Spec; + +my $format = 0; + +foreach my $arg (@ARGV) +{ + #print $arg, "\n"; + + if ($arg eq "-major") + { + $format = 1; + } + elsif ($arg eq "-minor") + { + $format = 2; + } + elsif ($arg eq "-patch") + { + $format = 3; + } +} + +#my $file = File::Spec->rel2abs( __FILE__ ); +my $dirname = dirname(__FILE__); +my $projRoot = "$dirname/.."; +my $versionHeader = "$projRoot/src/version.h"; +my $major = 1; +my $minor = 0; +my $patch = 0; + +#print "File: $file\n"; +#print "Dir $dirname\n"; + +my $line; + +open INFILE, "$versionHeader" or die "Error: Could not open file: $versionHeader\n"; +while ($line = ) +{ + #print $line; + if ($line =~ m/\s*#define\s+FCEU_VERSION_MAJOR\s+(\d+)/) + { + $major = $1; + } + elsif ($line =~ m/\s*#define\s+FCEU_VERSION_MINOR\s+(\d+)/) + { + $minor = $1; + } + elsif ($line =~ m/\s*#define\s+FCEU_VERSION_PATCH\s+(\d+)/) + { + $patch = $1; + } +} +close(INFILE); + +if ($format == 1) +{ + print "$major"; +} +elsif ($format == 2) +{ + print "$minor"; +} +elsif ($format == 3) +{ + print "$patch"; +} +else +{ + print "$major.$minor.$patch"; +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8ef081d4..c4dc2b02 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,10 @@ set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) +if (${PUBLIC_RELEASE}) + add_definitions( -DPUBLIC_RELEASE=1 ) +endif() + if ( ${QT6} ) message( STATUS "GUI Frontend: Qt6") set( Qt Qt6 ) @@ -28,6 +32,7 @@ else() include_directories( ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Help_INCLUDE_DIRS} ) endif() + if(WIN32) find_package(OpenGL REQUIRED) #find_package(Qt5 COMPONENTS Widgets OpenGL REQUIRED) diff --git a/src/version.h b/src/version.h index dc2c1be9..01c9daae 100644 --- a/src/version.h +++ b/src/version.h @@ -62,14 +62,14 @@ #define FCEU_VERSION_MAJOR 2 #define FCEU_VERSION_MINOR 6 -#define FCEU_VERSION_PATCH 4 +#define FCEU_VERSION_PATCH 5 #define FCEU_VERSION_NUMERIC ( (FCEU_VERSION_MAJOR*10000) + (FCEU_VERSION_MINOR*100) + (FCEU_VERSION_PATCH) ) #define FCEU_VERSION_MAJOR_DECODE(x) ( (x / 10000) ) #define FCEU_VERSION_MINOR_DECODE(x) ( (x / 100) % 100 ) #define FCEU_VERSION_PATCH_DECODE(x) (x % 100) -#define FCEU_VERSION_STRING "2.6.4" FCEU_SUBVERSION_STRING FCEU_FEATURE_STRING FCEU_COMPILER +#define FCEU_VERSION_STRING "2.6.5" FCEU_SUBVERSION_STRING FCEU_FEATURE_STRING FCEU_COMPILER #define FCEU_NAME_AND_VERSION FCEU_NAME " " FCEU_VERSION_STRING #endif diff --git a/vc/vc14_fceux.vcxproj b/vc/vc14_fceux.vcxproj index 4611ee98..10bdf280 100644 --- a/vc/vc14_fceux.vcxproj +++ b/vc/vc14_fceux.vcxproj @@ -353,7 +353,7 @@ xcopy /y /d "$(ProjectDir)\..\src\drivers\win\7z_64.dll" "$(OutDir)" Speed true .;../src/drivers/win/zlib;../src/drivers/win/directx/x64;../src;../src/drivers/win/lua/include;userconfig;defaultconfig;%(AdditionalIncludeDirectories) - WIN32;WIN64;MSVC;_CRT_SECURE_NO_DEPRECATE;_WIN32_WINDOWS=0x0410;WINVER=0x0410;NETWORK;LSB_FIRST;FCEUDEF_DEBUGGER;_USE_SHARED_MEMORY_;NOMINMAX;HAS_vsnprintf;_S9XLUA_H;NDEBUG;MSVC;_CRT_SECURE_NO_DEPRECATE;_WIN32_WINDOWS=0x0410;WINVER=0x0410;NETWORK;LSB_FIRST;%(PreprocessorDefinitions) + PUBLIC_RELEASE;WIN32;WIN64;MSVC;_CRT_SECURE_NO_DEPRECATE;_WIN32_WINDOWS=0x0410;WINVER=0x0410;NETWORK;LSB_FIRST;FCEUDEF_DEBUGGER;_USE_SHARED_MEMORY_;NOMINMAX;HAS_vsnprintf;_S9XLUA_H;NDEBUG;MSVC;_CRT_SECURE_NO_DEPRECATE;_WIN32_WINDOWS=0x0410;WINVER=0x0410;NETWORK;LSB_FIRST;%(PreprocessorDefinitions) MultiThreaded @@ -1528,4 +1528,4 @@ xcopy /y /d "$(ProjectDir)\..\src\drivers\win\7z_64.dll" "$(OutDir)" - \ No newline at end of file + From 7b007332c49bd62492a9a306373dc5715545873f Mon Sep 17 00:00:00 2001 From: mjbudd77 Date: Sat, 1 Oct 2022 17:03:20 -0400 Subject: [PATCH 02/26] Updated access token. --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index d9c96f10..300fad98 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -68,7 +68,7 @@ deploy: release: interim-build description: 'Interim Builds - Latest auto builds off master branch - commit: $(APPVEYOR_REPO_COMMIT)\nDate: $(APPVEYOR_REPO_COMMIT_TIMESTAMP)' auth_token: - secure: 5kNj/zZ1RD5gCBq0Q4my9dBgSTYL7JVvcjv93T9i6FjYA6SAds3/Dmlz8wrRMN8E + secure: pYXqhuxNn7vivsJ6cnWCHlORrTtaWO7fyGOvGFUNKtM2apSY44gjbAhGIlD+OdtF artifact: $(WIN32_ARTIFACT), $(WIN64_ARTIFACT), $(WIN64_QTSDL_ARTIFACT), $(MACOS_ARTIFACT), $(LINUX_ARTIFACT) draft: false prerelease: true @@ -80,7 +80,7 @@ deploy: - provider: GitHub description: 'Release Builds - commit: $(APPVEYOR_REPO_COMMIT)' auth_token: - secure: 5kNj/zZ1RD5gCBq0Q4my9dBgSTYL7JVvcjv93T9i6FjYA6SAds3/Dmlz8wrRMN8E + secure: pYXqhuxNn7vivsJ6cnWCHlORrTtaWO7fyGOvGFUNKtM2apSY44gjbAhGIlD+OdtF artifact: $(WIN32_ARTIFACT), $(WIN64_ARTIFACT), $(WIN64_QTSDL_ARTIFACT), $(MACOS_ARTIFACT) draft: false prerelease: false From edae2d4f572f9dfc38c78f126ea0750bab80d2c0 Mon Sep 17 00:00:00 2001 From: mjbudd77 Date: Sat, 1 Oct 2022 17:33:17 -0400 Subject: [PATCH 03/26] Updated download links for interim auto builds for new interim-build pre-release setup (uploaded from appveyor using github release deployment) --- readme.md | 10 +++++----- web/download.html | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/readme.md b/readme.md index 19bd9ba4..f8d0c4a8 100644 --- a/readme.md +++ b/readme.md @@ -5,11 +5,11 @@ An open source NES Emulator for Windows and Unix that features solid emulation a ## Builds and Releases Interim builds: -* Win32: [fceux.zip](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux.zip?branch=master&job=Windows%2032) -* Win64: [fceux64.zip](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux64.zip?branch=master&job=Windows%2064) -* Win64 Qt/SDL: [qfceux64.zip](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/qfceux64.zip?branch=master&job=Win64%20Qt) -* Ubuntu: [fceux-2.6.4-amd64.deb](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux-2.6.4-amd64.deb?branch=master&job=Ubuntu) -* MacOSX: [fceux-2.6.4-Darwin.dmg](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux-2.6.4-Darwin.dmg?branch=master&job=MacOS) +* Win32: [fceux-win32.zip](https://github.com/TASEmulators/fceux/releases/download/interim-build/fceux-win32.zip) +* Win64: [fceux-win64.zip](https://github.com/TASEmulators/fceux/releases/download/interim-build/fceux-win64.zip) +* Win64 Qt/SDL: [fceux-win64-QtSDL.zip](https://github.com/TASEmulators/fceux/releases/download/interim-build/fceux-win64-QtSDL.zip) +* Ubuntu: [fceux-ubuntu-x64.deb](https://github.com/TASEmulators/fceux/releases/download/interim-build/fceux-ubuntu-x64.deb) +* MacOSX: [fceux-Darwin.dmg](https://github.com/TASEmulators/fceux/releases/download/interim-build/fceux-Darwin.dmg) * Status: [Appveyor](https://ci.appveyor.com/project/zeromus/fceux/) But you might like mesen more: https://github.com/SourMesen/Mesen diff --git a/web/download.html b/web/download.html index 6491e2e6..da18903f 100644 --- a/web/download.html +++ b/web/download.html @@ -81,11 +81,11 @@

If you would like to test the current in-development version of FCEUX, interim builds are available here:

Source Code

From 1ad9a3d857eb4fa39bebe665009c8fff1b6c8223 Mon Sep 17 00:00:00 2001 From: harry Date: Sat, 8 Oct 2022 09:56:49 -0400 Subject: [PATCH 04/26] For Qt GUI, added logic to prevent controller buttons that are bound to the keyboard from being active when family keyboard is enabled. Controller buttons that are mapped to physical gamepad or joystick are unaffected. For issue #572. --- src/drivers/Qt/input.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/drivers/Qt/input.cpp b/src/drivers/Qt/input.cpp index 9bddbc7c..ff4c4f34 100644 --- a/src/drivers/Qt/input.cpp +++ b/src/drivers/Qt/input.cpp @@ -65,7 +65,7 @@ static int cspec = 0; static int buttonConfigInProgress = 0; extern int gametype; -static int DTestButton(ButtConfig *bc); +static int DTestButton(ButtConfig *bc, bool isFKB = false); //std::list gpKeySeqList; @@ -1416,12 +1416,18 @@ void ButtonConfigEnd() * Tests to see if a specified button is currently pressed. */ static int -DTestButton(ButtConfig *bc) +DTestButton(ButtConfig *bc, bool isFKB) { - if (bc->ButtType == BUTTC_KEYBOARD) { - if (g_keyState[SDL_GetScancodeFromKey(bc->ButtonNum)]) + bool ignoreKB = false; + bool fkbActv = g_fkbEnabled && (CurInputType[2] == SIFC_FKB); + + if (fkbActv) + { + ignoreKB = !isFKB; + } + if (!ignoreKB && g_keyState[SDL_GetScancodeFromKey(bc->ButtonNum)]) { bc->state = 1; return 1; @@ -1753,6 +1759,10 @@ void FCEUD_SetInput(bool fourscore, bool microphone, ESI port0, ESI port1, CurInputType[1] = port1; CurInputType[2] = fcexp; } + if (CurInputType[2] != SIFC_FKB) + { + g_fkbEnabled = false; + } replaceP2StartWithMicrophone = microphone; @@ -1880,7 +1890,7 @@ static void UpdateFKB(void) vkeyDown = getFamilyKeyboardVirtualKey(50); - leftShiftDown = DTestButton(&fkbmap[50]) || vkeyDown; + leftShiftDown = DTestButton(&fkbmap[50], true) || vkeyDown; for (x = 0; x < FAMILYKEYBOARD_NUM_BUTTONS; x++) { @@ -1896,7 +1906,7 @@ static void UpdateFKB(void) vkeyDown = getFamilyKeyboardVirtualKey(x); - if (DTestButton(&fkbmap[x]) || vkeyDown) + if (DTestButton(&fkbmap[x], true) || vkeyDown) { fkbkeys[x] = 1; From 06467ce73aecf1e96c54dbf6e59a00fd617f2eb4 Mon Sep 17 00:00:00 2001 From: harry Date: Sun, 9 Oct 2022 20:11:54 -0400 Subject: [PATCH 05/26] Fix for Qt GUI OpenGL blending parameters. --- src/drivers/Qt/ConsoleViewerGL.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drivers/Qt/ConsoleViewerGL.cpp b/src/drivers/Qt/ConsoleViewerGL.cpp index f836dd88..c877cefe 100644 --- a/src/drivers/Qt/ConsoleViewerGL.cpp +++ b/src/drivers/Qt/ConsoleViewerGL.cpp @@ -671,7 +671,7 @@ void ConsoleViewGL_t::paintGL(void) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE); + glBlendFunc(GL_ONE, GL_ZERO); //glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); if ( textureType == GL_TEXTURE_RECTANGLE ) From 900305b58738f66902fd1c743b5017f607f442e3 Mon Sep 17 00:00:00 2001 From: harry Date: Sun, 9 Oct 2022 21:09:52 -0400 Subject: [PATCH 06/26] For Qt GUI, added option to use palette background color as video background color. This option can be accessed from via main menu -> option submenu. --- src/drivers/Qt/ConsoleWindow.cpp | 40 ++++++++++++++++++++++++++++---- src/drivers/Qt/ConsoleWindow.h | 3 +++ src/drivers/Qt/config.cpp | 1 + src/drivers/Qt/fceuWrapper.cpp | 1 + src/drivers/Qt/fceuWrapper.h | 1 + src/drivers/Qt/sdl-video.cpp | 15 ++++++++++++ 6 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index fd5119c4..58cd2eb4 100644 --- a/src/drivers/Qt/ConsoleWindow.cpp +++ b/src/drivers/Qt/ConsoleWindow.cpp @@ -894,7 +894,6 @@ void consoleWin_t::createMainMenu(void) QActionGroup *group; int useNativeMenuBar; int customAutofireOnFrames, customAutofireOffFrames; - ColorMenuItem *bgColorItem; //QShortcut *shortcut; menubar = new consoleMenuBar(this); @@ -1254,15 +1253,32 @@ void consoleWin_t::createMainMenu(void) optMenu->addAction(act); + optMenu->addSeparator(); + // Options -> Video BG Color fceuLoadConfigColor( "SDL.VideoBgColor", &videoBgColor ); - bgColorItem = new ColorMenuItem( tr("BG Side Panel Color"), "SDL.VideoBgColor", this ); - bgColorItem->connectColor( &videoBgColor ); + bgColorMenuItem = new ColorMenuItem( tr("BG Side Panel Color"), "SDL.VideoBgColor", this ); + bgColorMenuItem->connectColor( &videoBgColor ); - optMenu->addAction(bgColorItem); + optMenu->addAction(bgColorMenuItem); - connect( bgColorItem, SIGNAL(colorChanged(QColor&)), this, SLOT(videoBgColorChanged(QColor&)) ); + connect( bgColorMenuItem, SIGNAL(colorChanged(QColor&)), this, SLOT(videoBgColorChanged(QColor&)) ); + + // Options -> Use BG Palette for Video BG Color + g_config->getOption( "SDL.UseBgPaletteForVideo", &usePaletteForVideoBg ); + + act = new QAction(tr("Use BG Palette for Video BG Color"), this); + //act->setShortcut( QKeySequence(tr("Alt+/"))); + act->setCheckable(true); + act->setChecked( usePaletteForVideoBg ); + act->setStatusTip(tr("Use BG Palette for Video BG Color")); + //act->setIcon( style()->standardIcon( QStyle::SP_TitleBarMaxButton ) ); + connect(act, SIGNAL(triggered(bool)), this, SLOT(toggleUseBgPaletteForVideo(bool)) ); + + optMenu->addAction(act); + + bgColorMenuItem->setEnabled( !usePaletteForVideoBg ); //----------------------------------------------------------------------- // Emulation @@ -2152,6 +2168,20 @@ void consoleWin_t::toggleMenuAutoHide(bool checked) g_config->save(); } //--------------------------------------------------------------------------- +void consoleWin_t::toggleUseBgPaletteForVideo(bool checked) +{ + usePaletteForVideoBg = checked; + + g_config->setOption( "SDL.UseBgPaletteForVideo", usePaletteForVideoBg ); + g_config->save(); + + if ( !usePaletteForVideoBg ) + { + fceuLoadConfigColor( "SDL.VideoBgColor", &videoBgColor ); + } + bgColorMenuItem->setEnabled( !usePaletteForVideoBg ); +} +//--------------------------------------------------------------------------- void consoleWin_t::closeApp(void) { nes_shm->runEmulator = 0; diff --git a/src/drivers/Qt/ConsoleWindow.h b/src/drivers/Qt/ConsoleWindow.h index d4451965..20460591 100644 --- a/src/drivers/Qt/ConsoleWindow.h +++ b/src/drivers/Qt/ConsoleWindow.h @@ -27,6 +27,7 @@ #include #endif +#include "Qt/ColorMenu.h" #include "Qt/ConsoleViewerGL.h" #include "Qt/ConsoleViewerSDL.h" #include "Qt/GamePadConf.h" @@ -259,6 +260,7 @@ class consoleWin_t : public QMainWindow QTimer *gameTimer; QColor videoBgColor; + ColorMenuItem *bgColorMenuItem; std::string errorMsg; bool errorMsgValid; @@ -453,6 +455,7 @@ class consoleWin_t : public QMainWindow void winActiveChanged(void); void emuFrameFinish(void); void toggleMenuAutoHide(bool); + void toggleUseBgPaletteForVideo(bool); void videoBgColorChanged( QColor &c ); void loadRomRequestCB( QString s ); diff --git a/src/drivers/Qt/config.cpp b/src/drivers/Qt/config.cpp index fff49ff4..3f5490cf 100644 --- a/src/drivers/Qt/config.cpp +++ b/src/drivers/Qt/config.cpp @@ -535,6 +535,7 @@ InitConfig() config->addOption('f', "fullscreen", "SDL.Fullscreen", 0); config->addOption("videoDriver", "SDL.VideoDriver", 0); config->addOption("SDL.VideoBgColor", "#000000"); + config->addOption("SDL.UseBgPaletteForVideo", false); config->addOption("SDL.VideoVsync", 1); // set x/y res to 0 for automatic fullscreen resolution detection (no change) diff --git a/src/drivers/Qt/fceuWrapper.cpp b/src/drivers/Qt/fceuWrapper.cpp index 12790b69..888d5b2e 100644 --- a/src/drivers/Qt/fceuWrapper.cpp +++ b/src/drivers/Qt/fceuWrapper.cpp @@ -89,6 +89,7 @@ bool pauseAfterPlayback = false; bool suggestReadOnlyReplay = true; bool showStatusIconOpt = true; bool drawInputAidsEnable = true; +bool usePaletteForVideoBg = false; unsigned int gui_draw_area_width = 256; unsigned int gui_draw_area_height = 256; diff --git a/src/drivers/Qt/fceuWrapper.h b/src/drivers/Qt/fceuWrapper.h index 65534ae0..350480a3 100644 --- a/src/drivers/Qt/fceuWrapper.h +++ b/src/drivers/Qt/fceuWrapper.h @@ -18,6 +18,7 @@ extern bool suggestReadOnlyReplay; extern bool emulatorCycleToggle; extern bool showStatusIconOpt; extern bool drawInputAidsEnable; +extern bool usePaletteForVideoBg; extern unsigned int gui_draw_area_width; extern unsigned int gui_draw_area_height; extern unsigned int emulatorCycleCount; diff --git a/src/drivers/Qt/sdl-video.cpp b/src/drivers/Qt/sdl-video.cpp index b3c46434..73bbd8bc 100644 --- a/src/drivers/Qt/sdl-video.cpp +++ b/src/drivers/Qt/sdl-video.cpp @@ -37,6 +37,7 @@ #include "Qt/sdl-video.h" #include "Qt/AviRecord.h" #include "Qt/fceuWrapper.h" +#include "Qt/ConsoleWindow.h" #ifdef CREATE_AVI #include "../videolog/nesvideos-piece.h" @@ -74,6 +75,7 @@ extern bool MaxSpeed; extern int input_display; extern int frame_display; extern int rerecord_display; +extern uint8 PALRAM[0x20]; /** * Attempts to destroy the graphical video display. Returns 0 on @@ -498,6 +500,19 @@ BlitScreen(uint8 *XBuf) { int i = nes_shm->pixBufIdx; + if (usePaletteForVideoBg) + { + unsigned char r, g, b; + FCEUD_GetPalette(0x80 | PALRAM[0], &r, &g, &b); + + if (consoleWindow) + { + QColor *bgColor = consoleWindow->getVideoBgColorPtr(); + + *bgColor = QColor::fromRgb(r,g,b); + } + } + doBlitScreen(XBuf, (uint8_t*)nes_shm->pixbuf[i]); nes_shm->pixBufIdx = (i+1) % NES_VIDEO_BUFLEN; From 83c529efb68161b431b9e3aa2bf6ad2764b30cb8 Mon Sep 17 00:00:00 2001 From: harry Date: Mon, 10 Oct 2022 09:54:52 -0400 Subject: [PATCH 07/26] Package lua DLLs and auxlib.lua into Qt win64 zip for IUP functionality. --- pipelines/qwin64_build.bat | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pipelines/qwin64_build.bat b/pipelines/qwin64_build.bat index 443a4610..606d5daa 100644 --- a/pipelines/qwin64_build.bat +++ b/pipelines/qwin64_build.bat @@ -49,6 +49,9 @@ msbuild /m fceux.sln /p:Configuration=Release @if ERRORLEVEL 1 goto end copy src\Release\fceux.exe bin\qfceux.exe +copy %PROJECT_ROOT%\src\auxlib.lua bin\. +copy %PROJECT_ROOT%\src\drivers\win\lua\x64\lua51.dll bin\. +copy %PROJECT_ROOT%\src\drivers\win\lua\x64\lua5.1.dll bin\. copy %SDL_INSTALL_PREFIX%\SDL2\lib\x64\SDL2.dll bin\. copy %FFMPEG_INSTALL_PREFIX%\ffmpeg\bin\*.dll bin\. From 06c3473c29913edb81d076c6343a93bbe29d94da Mon Sep 17 00:00:00 2001 From: harry Date: Mon, 10 Oct 2022 22:04:48 -0400 Subject: [PATCH 08/26] Undo packaging of LUA DLLs for Qt Win64 GUI. Static lib seems to be more stable. --- pipelines/qwin64_build.bat | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pipelines/qwin64_build.bat b/pipelines/qwin64_build.bat index 606d5daa..a27701c7 100644 --- a/pipelines/qwin64_build.bat +++ b/pipelines/qwin64_build.bat @@ -50,8 +50,8 @@ msbuild /m fceux.sln /p:Configuration=Release copy src\Release\fceux.exe bin\qfceux.exe copy %PROJECT_ROOT%\src\auxlib.lua bin\. -copy %PROJECT_ROOT%\src\drivers\win\lua\x64\lua51.dll bin\. -copy %PROJECT_ROOT%\src\drivers\win\lua\x64\lua5.1.dll bin\. +REM copy %PROJECT_ROOT%\src\drivers\win\lua\x64\lua51.dll bin\. +REM copy %PROJECT_ROOT%\src\drivers\win\lua\x64\lua5.1.dll bin\. copy %SDL_INSTALL_PREFIX%\SDL2\lib\x64\SDL2.dll bin\. copy %FFMPEG_INSTALL_PREFIX%\ffmpeg\bin\*.dll bin\. From 35c5fa36c1deef6dbd6b092e3ac12a29bd5a0b04 Mon Sep 17 00:00:00 2001 From: harry Date: Wed, 12 Oct 2022 20:51:11 -0400 Subject: [PATCH 09/26] Upgraded Qt/SDL win64 build dependencies to use SDL-2.24.1 and ffmpeg-5.1.2 --- pipelines/qwin64_build.bat | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/pipelines/qwin64_build.bat b/pipelines/qwin64_build.bat index a27701c7..9e829a71 100644 --- a/pipelines/qwin64_build.bat +++ b/pipelines/qwin64_build.bat @@ -22,18 +22,21 @@ mkdir build cd build mkdir bin -curl -s -LO http://www.libsdl.org/release/SDL2-devel-2.0.20-VC.zip -curl -s -LO https://github.com/GyanD/codexffmpeg/releases/download/5.0/ffmpeg-5.0-full_build-shared.zip +set SDL_VERSION=2.24.1 +set FFMPEG_VERSION=5.1.2 + +curl -s -LO https://github.com/libsdl-org/SDL/releases/download/release-%SDL_VERSION%/SDL2-devel-%SDL_VERSION%-VC.zip +curl -s -LO https://github.com/GyanD/codexffmpeg/releases/download/%FFMPEG_VERSION%/ffmpeg-%FFMPEG_VERSION%-full_build-shared.zip REM rmdir /q /s SDL2 -powershell -command "Expand-Archive" SDL2-devel-2.0.20-VC.zip . -powershell -command "Expand-Archive" ffmpeg-5.0-full_build-shared.zip +powershell -command "Expand-Archive" SDL2-devel-%SDL_VERSION%-VC.zip . +powershell -command "Expand-Archive" ffmpeg-%FFMPEG_VERSION%-full_build-shared.zip -rename SDL2-2.0.20 SDL2 -move ffmpeg-5.0-full_build-shared\ffmpeg-5.0-full_build-shared ffmpeg -rmdir ffmpeg-5.0-full_build-shared -del ffmpeg-5.0-full_build-shared.zip +rename SDL2-%SDL_VERSION% SDL2 +move ffmpeg-%FFMPEG_VERSION%-full_build-shared\ffmpeg-%FFMPEG_VERSION%-full_build-shared ffmpeg +rmdir ffmpeg-%FFMPEG_VERSION%-full_build-shared +del ffmpeg-%FFMPEG_VERSION%-full_build-shared.zip set SDL_INSTALL_PREFIX=%CD% set FFMPEG_INSTALL_PREFIX=%CD% From d075c2b46aa4b43bcf216ed8e01c63ba83e95ec8 Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Mon, 5 Dec 2022 13:54:50 +0400 Subject: [PATCH 10/26] COOLBOY fixes and self-writable feature --- src/boards/coolboy.cpp | 261 +++++++++++++++++++++++++++++++++++------ 1 file changed, 228 insertions(+), 33 deletions(-) diff --git a/src/boards/coolboy.cpp b/src/boards/coolboy.cpp index e220ae80..6b5e7b64 100644 --- a/src/boards/coolboy.cpp +++ b/src/boards/coolboy.cpp @@ -21,7 +21,7 @@ * * COOLBOY cartridges use registers at address $6xxx * MINDKIDS cartridges use a solder pad labelled "5/6K" to select between $5000 and $6000 - * + * * $xxx0 * 7 bit 0 * ---- ---- @@ -76,6 +76,44 @@ #include "mapinc.h" #include "mmc3.h" +const int ROM_CHIP = 0x00; +const int WRAM_CHIP = 0x10; +const int CFI_CHIP = 0x11; +const int FLASH_CHIP = 0x12; + +const int FLASH_SECTOR_SIZE = 128 * 1024; + +extern uint8* WRAM; +static uint8* CFI = NULL; +static uint8* Flash = NULL; + +static uint8 flash_save = 0; +static uint8 flash_state = 0; +static uint16 flash_buffer_a[10]; +static uint8 flash_buffer_v[10]; +static uint8 cfi_mode = 0; + +// Macronix 256-mbit memory CFI data +const uint8 cfi_data[] = +{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x51, 0x52, 0x59, 0x02, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x27, 0x36, 0x00, 0x00, 0x03, + 0x06, 0x09, 0x13, 0x03, 0x05, 0x03, 0x02, 0x19, + 0x02, 0x00, 0x06, 0x00, 0x01, 0xFF, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, + 0x50, 0x52, 0x49, 0x31, 0x33, 0x14, 0x02, 0x01, + 0x00, 0x08, 0x00, 0x00, 0x02, 0x95, 0xA5, 0x05, + 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + static void COOLBOYCW(uint32 A, uint8 V) { uint32 mask = 0xFF ^ (EXPREGS[0] & 0x80); if (EXPREGS[3] & 0x10) { @@ -92,7 +130,8 @@ static void COOLBOYCW(uint32 A, uint8 V) { | ((EXPREGS[2] & 0x0F) << 3) // 6-3 bits | ((A >> 10) & 7) // 2-0 bits ); - } else { + } + else { if (EXPREGS[3] & 0x40) { // Weird mode, again int cbase = (MMC3_cmd & 0x80) << 5; switch (cbase ^ A) { // Don't even try do understand @@ -112,6 +151,13 @@ static void COOLBOYPW(uint32 A, uint8 V) { uint32 mask = ((0x3F | (EXPREGS[1] & 0x40) | ((EXPREGS[1] & 0x20) << 2)) ^ ((EXPREGS[0] & 0x40) >> 2)) ^ ((EXPREGS[1] & 0x80) >> 2); uint32 base = ((EXPREGS[0] & 0x07) >> 0) | ((EXPREGS[1] & 0x10) >> 1) | ((EXPREGS[1] & 0x0C) << 2) | ((EXPREGS[0] & 0x30) << 2); + if (cfi_mode) + { + setprg32r(CFI_CHIP, 0x8000, 0); + } + + int chip = !flash_save ? ROM_CHIP : FLASH_CHIP; + // Very weird mode // Last banks are first in this mode, ignored when MMC3_cmd&0x40 if ((EXPREGS[3] & 0x40) && (V >= 0xFE) && !((MMC3_cmd & 0x40) != 0)) { @@ -123,26 +169,28 @@ static void COOLBOYPW(uint32 A, uint8 V) { } } - // Regular MMC3 mode, internal ROM size can be up to 2048kb! - if (!(EXPREGS[3] & 0x10)) - setprg8(A, (((base << 4) & ~mask)) | (V & mask)); - else { // NROM mode + if (!(EXPREGS[3] & 0x10)) { + // Regular MMC3 mode but can be extended to 2MByte + setprg8r(chip, A, (((base << 4) & ~mask)) | (V & mask)); + } + else { + // NROM mode mask &= 0xF0; uint8 emask; if ((((EXPREGS[1] & 2) != 0))) // 32kb mode emask = (EXPREGS[3] & 0x0C) | ((A & 0x4000) >> 13); else // 16kb mode emask = EXPREGS[3] & 0x0E; - setprg8(A, ((base << 4) & ~mask) // 7-4 bits are from base (see below) - | (V & mask) // ... or from MM3 internal regs, depends on mask - | emask // 3-1 (or 3-2 when (EXPREGS[3]&0x0C is set) from EXPREGS[3] - | ((A & 0x2000) >> 13)); // 0th just as is + setprg8r(chip, A, ((base << 4) & ~mask) // 7-4 bits are from base (see below) + | (V & mask) // ... or from MM3 internal regs, depends on mask + | emask // 3-1 (or 3-2 when (EXPREGS[3]&0x0C is set) from EXPREGS[3] + | ((A & 0x2000) >> 13)); // 0th just as is } } static DECLFW(COOLBOYWrite) { - if(A001B & 0x80) - CartBW(A,V); + if (A001B & 0x80) + CartBW(A, V); // Deny any further writes when 7th bit is 1 AND 4th is 0 if ((EXPREGS[3] & 0x90) != 0x80) { @@ -152,9 +200,107 @@ static DECLFW(COOLBOYWrite) { } } -static void COOLBOYReset(void) { +static DECLFW(MINDKIDSWrite) { + if (A >= 0x6000) { + if (A001B & 0x80) + CartBW(A, V); + return; + } + + // Deny any further writes when 7th bit is 1 AND 4th is 0 + if ((EXPREGS[3] & 0x90) != 0x80) { + EXPREGS[A & 3] = V; + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); + } +} + +static DECLFR(COOLBOYFlashRead) { + return CartBR(A); +} + +static DECLFW(COOLBOYFlashWrite) { + if (A < 0xC000) + MMC3_CMDWrite(A, V); + else + MMC3_IRQWrite(A, V); + + if (flash_save) { + if (flash_state < sizeof(flash_buffer_a) / sizeof(flash_buffer_a[0])) { + flash_buffer_a[flash_state] = A & 0xFFF; + flash_buffer_v[flash_state] = V; + flash_state++; + + // enter CFI mode + if ((flash_state == 1) && + (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0x98)) { + cfi_mode = 1; + flash_state = 0; + FixMMC3PRG(MMC3_cmd); + } + + // erase sector + if ((flash_state == 6) && + (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) && + (flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) && + (flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0x80) && + (flash_buffer_a[3] == 0x0AAA) && (flash_buffer_v[3] == 0xAA) && + (flash_buffer_a[4] == 0x0555) && (flash_buffer_v[4] == 0x55) && + (flash_buffer_v[5] == 0x30)) { + int offset = &Page[A >> 11][A] - Flash; + int sector = offset / FLASH_SECTOR_SIZE; + for (uint32 i = sector * FLASH_SECTOR_SIZE; i < (sector + 1) * FLASH_SECTOR_SIZE; i++) + Flash[i % PRGsize[ROM_CHIP]] = 0xFF; + FCEU_printf("Flash sector #%d is erased (0x%08x - 0x%08x)\n", sector, offset, offset + FLASH_SECTOR_SIZE); + } + + // erase chip, lol + if ((flash_state == 6) && + (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) && + (flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) && + (flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0x80) && + (flash_buffer_a[3] == 0x0AAA) && (flash_buffer_v[3] == 0xAA) && + (flash_buffer_a[4] == 0x0555) && (flash_buffer_v[4] == 0x55) && + (flash_buffer_v[5] == 0x10)) { + memset(Flash, 0xFF, PRGsize[ROM_CHIP]); + FCEU_printf("Flash chip erased.\n"); + } + + // write byte + if ((flash_state == 4) && + (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) && + (flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) && + (flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0xA0)) { + int offset = &Page[A >> 11][A] - Flash; + if (CartBR(A) != 0xFF) { + FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased\n", offset); + } + else { + CartBW(A, V); + } + flash_state = 0; + } + + // not a command + if (((A & 0xFFF) != 0x0AAA) && ((A & 0xFFF) != 0x0555)) { + flash_state = 0; + } + + // reset + if (V == 0xF0) { + flash_state = 0; + cfi_mode = 0; + FixMMC3PRG(MMC3_cmd); + } + } + } +} + +static void CommonReset(void) { MMC3RegReset(); EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; + flash_state = 0; + cfi_mode = 0; FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); } @@ -166,6 +312,8 @@ static void COOLBOYPower(void) { FixMMC3CHR(MMC3_cmd); SetWriteHandler(0x5000, 0x5fff, CartBW); // some games access random unmapped areas and crashes because of KT-008 PCB hack in MMC3 source lol SetWriteHandler(0x6000, 0x6fff, COOLBOYWrite); + SetWriteHandler(0x8000, 0xFFFF, COOLBOYFlashWrite); + SetReadHandler(0x8000, 0xFFFF, COOLBOYFlashRead); } static void MINDKIDSPower(void) { @@ -173,41 +321,88 @@ static void MINDKIDSPower(void) { EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); - SetWriteHandler(0x5000, 0x5fff, COOLBOYWrite); + SetWriteHandler(0x5000, 0x7fff, MINDKIDSWrite); + SetWriteHandler(0x8000, 0xFFFF, COOLBOYFlashWrite); + SetReadHandler(0x8000, 0xFFFF, COOLBOYFlashRead); +} + +static void CommonClose(void) { + if (WRAM) + FCEU_gfree(WRAM); + if (Flash) + FCEU_gfree(Flash); + if (CFI) + FCEU_gfree(CFI); + WRAM = Flash = CFI = NULL; +} + +void CommonInit(CartInfo* info, int submapper) +{ + GenMMC3_Init(info, 2048, info->vram_size / 1024, !info->ines2 ? 8 : (info->wram_size + info->battery_wram_size) / 1024, info->battery); + pwrap = COOLBOYPW; + cwrap = COOLBOYCW; + + switch (submapper) + { + case 1: + info->Power = MINDKIDSPower; + default: + info->Power = COOLBOYPower; + break; + } + info->Reset = CommonReset; + info->Close = CommonClose; + + flash_save = info->battery; + + if (flash_save) { + CFI = (uint8*)FCEU_gmalloc(sizeof(cfi_data) * 2); + for (int i = 0; i < sizeof(cfi_data); i++) { + CFI[i * 2] = CFI[i * 2 + 1] = cfi_data[i]; + } + SetupCartPRGMapping(CFI_CHIP, CFI, sizeof(cfi_data) * 2, 0); + + Flash = (uint8*)FCEU_gmalloc(PRGsize[ROM_CHIP]); + for (int i = 0; i < PRGsize[ROM_CHIP]; i++) { + Flash[i] = PRGptr[ROM_CHIP][i % PRGsize[ROM_CHIP]]; + } + SetupCartPRGMapping(FLASH_CHIP, Flash, PRGsize[ROM_CHIP], 1); + info->SaveGame[1] = Flash; + info->SaveGameLen[1] = PRGsize[ROM_CHIP]; + } + + AddExState(EXPREGS, 4, 0, "EXPR"); + if (flash_save) + { + AddExState(&flash_state, sizeof(flash_state), 0, "FLST"); + AddExState(flash_buffer_a, sizeof(flash_buffer_a), 0, "FLBA"); + AddExState(flash_buffer_v, sizeof(flash_buffer_v), 0, "FLBV"); + AddExState(&cfi_mode, sizeof(cfi_mode), 0, "CFIM"); + AddExState(Flash, PRGsize[ROM_CHIP], 0, "FLAS"); + } } // Registers at $6xxx -void COOLBOY_Init(CartInfo *info) { - GenMMC3_Init(info, 2048, 256, 8, 1); - pwrap = COOLBOYPW; - cwrap = COOLBOYCW; - info->Power = COOLBOYPower; - info->Reset = COOLBOYReset; - AddExState(EXPREGS, 4, 0, "EXPR"); +void COOLBOY_Init(CartInfo* info) { + CommonInit(info, 0); } // Registers at $5xxx -void MINDKIDS_Init(CartInfo *info) { - GenMMC3_Init(info, 2048, 256, 8, 1); - pwrap = COOLBOYPW; - cwrap = COOLBOYCW; - info->Power = MINDKIDSPower; - info->Reset = COOLBOYReset; - AddExState(EXPREGS, 4, 0, "EXPR"); +void MINDKIDS_Init(CartInfo* info) { + CommonInit(info, 1); } // For NES 2.0 loader -void SMD132_SMD133_Init(CartInfo *info) { +void SMD132_SMD133_Init(CartInfo* info) { + switch (info->submapper) { case 0: - COOLBOY_Init(info); - break; case 1: - MINDKIDS_Init(info); + CommonInit(info, info->submapper); break; default: - FCEU_PrintError("Unknown submapper: #%d.", info->submapper); + FCEU_PrintError("Submapper #%d is not supported", info->submapper); break; } } From 328e351255a96cadcaf61fedbd98f02b6cb32078 Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Mon, 5 Dec 2022 14:09:21 +0400 Subject: [PATCH 11/26] Typo fix --- src/drivers/win/taseditor/history.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drivers/win/taseditor/history.h b/src/drivers/win/taseditor/history.h index 59d83c5c..af4c14a6 100644 --- a/src/drivers/win/taseditor/history.h +++ b/src/drivers/win/taseditor/history.h @@ -108,7 +108,7 @@ public: int registerChanges(int mod_type, int start = 0, int end =-1, int size = 0, const char* comment = NULL, int consecutivenessTag = 0, RowsSelection* frameset = NULL); int registerAdjustLag(int start, int size); void registerMarkersChange(int modificationType, int start = 0, int end =-1, const char* comment = 0); - void registerBookmarkSet(int slot, BOOKMARK& backupÑopy, int oldCurrentBranch); + void registerBookmarkSet(int slot, BOOKMARK& backupcopy, int oldCurrentBranch); int registerBranching(int slot, bool markersWereChanged); void registerRecording(int frameOfChange, uint32 joypadDifferenceBits); int registerImport(MovieData& md, char* filename); From 90aecc0543833696cf850767bac2ea04db51e584 Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Mon, 5 Dec 2022 14:56:10 +0400 Subject: [PATCH 12/26] COOLGIRL mapper (mapper 342) --- src/boards/coolboy.cpp | 22 +- src/boards/coolgirl.cpp | 2281 +++++++++++++++++++++++++++++++++++++++ src/config.cpp | 2 +- src/ines.cpp | 1 + src/state.cpp | 2 +- src/unif.cpp | 1 + src/unif.h | 1 + 7 files changed, 2298 insertions(+), 12 deletions(-) create mode 100644 src/boards/coolgirl.cpp diff --git a/src/boards/coolboy.cpp b/src/boards/coolboy.cpp index 6b5e7b64..b7a5e8e2 100644 --- a/src/boards/coolboy.cpp +++ b/src/boards/coolboy.cpp @@ -281,17 +281,19 @@ static DECLFW(COOLBOYFlashWrite) { flash_state = 0; } - // not a command - if (((A & 0xFFF) != 0x0AAA) && ((A & 0xFFF) != 0x0555)) { - flash_state = 0; - } - // reset - if (V == 0xF0) { - flash_state = 0; - cfi_mode = 0; - FixMMC3PRG(MMC3_cmd); - } + } + + // not a command + if (((A & 0xFFF) != 0x0AAA) && ((A & 0xFFF) != 0x0555)) { + flash_state = 0; + } + + // reset + if (V == 0xF0) { + flash_state = 0; + cfi_mode = 0; + FixMMC3PRG(MMC3_cmd); } } } diff --git a/src/boards/coolgirl.cpp b/src/boards/coolgirl.cpp new file mode 100644 index 00000000..86441198 --- /dev/null +++ b/src/boards/coolgirl.cpp @@ -0,0 +1,2281 @@ +/* FCE Ultra - NES/Famicom Emulator +* +* Copyright notice for this file: +* Copyright (C) 2022 Cluster +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Very complicated homebrew multicart mapper with. +* The code is so obscured and weird because it's ported from Verilog CPLD source code: +* https://github.com/ClusterM/coolgirl-famicom-multicart/blob/master/CoolGirl_mappers.vh +* +*/ + +#include "mapinc.h" + +const uint32 SAVE_FLASH_SIZE = 1024 * 1024 * 8; +const int FLASH_SECTOR_SIZE = 128 * 1024; +const int ROM_CHIP = 0x00; +const int WRAM_CHIP = 0x10; +const int FLASH_CHIP = 0x11; +const int CHR_RAM_CHIP = 0x12; +const int CFI_CHIP = 0x13; + +static uint32 WRAM_SIZE = 0; +static uint8 *WRAM = NULL; +static uint32 CHR_RAM_SIZE = 0; +static uint8 *CHR_RAM; +static uint8 *SAVE_FLASH = NULL; +static uint8* CFI; + +static uint8 sram_enabled = 0; +static uint8 sram_page = 0; // [1:0] +static uint8 can_write_chr = 0; +static uint8 map_rom_on_6000 = 0; +static uint8 flags = 0; // [2:0] +static uint8 mapper = 0; // [5:0] +static uint8 can_write_flash = 0; +static uint8 mirroring = 0; // [1:0] +static uint8 four_screen = 0; +static uint8 lockout = 0; + +static uint32 prg_base = 0; // [26:14] +static uint32 prg_mask = 0b11111000 << 14; // 11111000, 128KB // [20:14] +static uint8 prg_mode = 0; // [2:0] +static uint8 prg_bank_6000 = 0; // [7:0] +static uint8 prg_bank_a = 0; // [7:0] +static uint8 prg_bank_b = 1; // [7:0] +static uint8 prg_bank_c = ~1; // [7:0] +static uint8 prg_bank_d = ~0; // [7:0] + +static uint32 chr_mask = 0; // [18:13] +static uint8 chr_mode = 0; // [2:0] +static uint16 chr_bank_a = 0; // [8:0] +static uint16 chr_bank_b = 1; // [8:0] +static uint16 chr_bank_c = 2; // [8:0] +static uint16 chr_bank_d = 3; // [8:0] +static uint16 chr_bank_e = 4; // [8:0] +static uint16 chr_bank_f = 5; // [8:0] +static uint16 chr_bank_g = 6; // [8:0] +static uint16 chr_bank_h = 7; // [8:0] + +static uint8 TKSMIR[8]; + +static uint32 prg_bank_6000_mapped = 0; +static uint32 prg_bank_a_mapped = 0; +static uint32 prg_bank_b_mapped = 0; +static uint32 prg_bank_c_mapped = 0; +static uint32 prg_bank_d_mapped = 0; + +// for MMC2/MMC4 +static uint8 ppu_latch0 = 0; +static uint8 ppu_latch1 = 0; +// for MMC1 +static uint64 lreset = 0; +static uint8 mmc1_load_register = 0; // [5:0] +// for MMC3 +static uint8 mmc3_internal = 0; // [2:0] +// for mapper #69 +static uint8 mapper69_internal = 0; // [3:0] +// for mapper #112 +static uint8 mapper112_internal = 0; // [2:0] +// for mapper #163 +static uint8 mapper_163_latch = 0; +static uint8 mapper163_r0 = 0; // [7:0] +static uint8 mapper163_r1 = 0; // [7:0] +static uint8 mapper163_r2 = 0; // [7:0] +static uint8 mapper163_r3 = 0; // [7:0] +static uint8 mapper163_r4 = 0; // [7:0] +static uint8 mapper163_r5 = 0; // [7:0] + +// For mapper #90 +static uint8 mul1 = 0; +static uint8 mul2 = 0; + +// for MMC3 scanline-based interrupts, counts A12 rises after long A12 falls +static uint8 mmc3_irq_enabled = 0; // register to enable/disable counter +static uint8 mmc3_irq_latch = 0; // [7:0], stores counter reload latch value +static uint8 mmc3_irq_counter = 0; // [7:0], counter itself (downcounting) +static uint8 mmc3_irq_reload = 0; // flag to reload counter from latch +// for MMC5 scanline-based interrupts, counts dummy PPU reads +static uint8 mmc5_irq_enabled = 0; // register to enable/disable counter +static uint8 mmc5_irq_line = 0; // [7:0], scanline on which IRQ will be triggered +static uint8 mmc5_irq_out = 0; // stores 1 when IRQ is triggered +// for mapper #18 +static uint16 mapper18_irq_value = 0; // [15:0], counter itself (downcounting) +static uint8 mapper18_irq_control = 0; // [3:0], IRQ settings +static uint16 mapper18_irq_latch = 0; // [15:0], stores counter reload latch value +// for mapper #65 +static uint8 mapper65_irq_enabled = 0; // register to enable/disable IRQ +static uint16 mapper65_irq_value = 0; // [15:0], counter itself (downcounting) +static uint16 mapper65_irq_latch = 0; // [15:0], stores counter reload latch value +// reg mapper65_irq_out = 0; +// for Sunsoft FME-7 +static uint8 mapper69_irq_enabled = 0; // register to enable/disable IRQ +static uint8 mapper69_counter_enabled = 0; // register to enable/disable counter +static uint16 mapper69_irq_value = 0; // counter itself (downcounting) +// for VRC4 CPU-based interrupts +static uint8 vrc4_irq_value = 0; // [7:0], counter itself (upcounting) +static uint8 vrc4_irq_control = 0; // [2:0]� IRQ settings +static uint8 vrc4_irq_latch = 0; // [7:0], stores counter reload latch value +static uint8 vrc4_irq_prescaler = 0; // [6:0], prescaler counter for VRC4 +static uint8 vrc4_irq_prescaler_counter = 0; // prescaler cicles counter for VRC4 +// for VRC3 CPU-based interrupts +static uint16 vrc3_irq_value = 0; // [15:0], counter itself (upcounting) +static uint8 vrc3_irq_control = 0; // [3:0], IRQ settings +static uint16 vrc3_irq_latch = 0; // [15:0], stores counter reload latch value +// for mapper #42 (only Baby Mario) +static uint8 mapper42_irq_enabled = 0; // register to enable/disable counter +static uint16 mapper42_irq_value = 0; // [14:0], counter itself (upcounting) +// for mapper #83 +static uint8 mapper83_irq_enabled_latch = 0; +static uint8 mapper83_irq_enabled = 0; +static uint16 mapper83_irq_counter = 0; +// for mapper #90 +static uint8 mapper90_xor = 0; +// for mapper #67 +static uint8 mapper67_irq_enabled = 0; +static uint8 mapper67_irq_latch = 0; +static uint16 mapper67_irq_counter = 0; + +static uint8 flash_state = 0; +static uint16 flash_buffer_a[10]; +static uint8 flash_buffer_v[10]; +static uint8 cfi_mode = 0; + +// Micron 4-gbit memory CFI data +const uint8 cfi_data[] = +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x51, 0x52, 0x59, 0x02, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x27, 0x36, 0x00, 0x00, 0x06, + 0x06, 0x09, 0x13, 0x03, 0x05, 0x03, 0x02, 0x1E, + 0x02, 0x00, 0x06, 0x00, 0x01, 0xFF, 0x03, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, + 0x50, 0x52, 0x49, 0x31, 0x33, 0x14, 0x02, 0x01, + 0x00, 0x08, 0x00, 0x00, 0x02, 0xB5, 0xC5, 0x05, + 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + +#define SET_BITS(target, target_bits, source, source_bits) target = set_bits(target, target_bits, get_bits(source, source_bits)) + +static inline uint8 string_to_bits(char* bitsstr, int* bits) +{ + uint8 bit1, bit2, count = 0; + for (int i = 0; i < 32; i++) + bits[i] = -1; + while (*bitsstr) + { + bit1 = 0; + bit2 = 0; + if (isdigit(*bitsstr)) + { + while (isdigit(*bitsstr)) + { + bit1 *= 10; + bit1 += *bitsstr - '0'; + bitsstr++; + } + if (*bitsstr == ':') + { + bitsstr++; + while (isdigit(*bitsstr)) + { + bit2 *= 10; + bit2 += *bitsstr - '0'; + bitsstr++; + } + if (bit2 < bit1) + for (int i = bit1; i >= bit2; i--) + { + bits[count] = i; + count++; + } + else + for (int i = bit1; i <= bit2; i++) + { + bits[count] = i; + count++; + } + } + else { + bits[count] = bit1; + count++; + } + } + else { + bitsstr++; + } + } + return count; +} + +static inline uint32 get_bits(uint32 V, char* bitsstr) +{ + uint32 result = 0; + int bits[32]; + string_to_bits(bitsstr, bits); + for (int i = 0; bits[i] >= 0; i++) + { + result <<= 1; + result |= (V >> bits[i]) & 1; + } + return result; +} + +static inline uint32 set_bits(uint32 V, char* bitsstr, uint32 new_bits) +{ + int bits[32]; + uint8 count = string_to_bits(bitsstr, bits); + for (int i = 0; i < count; i++) + { + if ((new_bits >> (count - i - 1)) & 1) + V |= 1 << bits[i]; + else + V &= ~(1 << bits[i]); + } + return V; +} + +static void COOLGIRL_Sync_PRG(void) { + prg_bank_6000_mapped = (prg_base >> 13) | (prg_bank_6000 & ((~(prg_mask >> 13) & 0xFE) | 1)); + prg_bank_a_mapped = (prg_base >> 13) | (prg_bank_a & ((~(prg_mask >> 13) & 0xFE) | 1)); + prg_bank_b_mapped = (prg_base >> 13) | (prg_bank_b & ((~(prg_mask >> 13) & 0xFE) | 1)); + prg_bank_c_mapped = (prg_base >> 13) | (prg_bank_c & ((~(prg_mask >> 13) & 0xFE) | 1)); + prg_bank_d_mapped = (prg_base >> 13) | (prg_bank_d & ((~(prg_mask >> 13) & 0xFE) | 1)); + uint8 REG_A_CHIP = (SAVE_FLASH != NULL && prg_bank_a_mapped >= 0x20000 - SAVE_FLASH_SIZE / 1024 / 8) ? FLASH_CHIP : ROM_CHIP; + uint8 REG_B_CHIP = (SAVE_FLASH != NULL && prg_bank_b_mapped >= 0x20000 - SAVE_FLASH_SIZE / 1024 / 8) ? FLASH_CHIP : ROM_CHIP; + uint8 REG_C_CHIP = (SAVE_FLASH != NULL && prg_bank_c_mapped >= 0x20000 - SAVE_FLASH_SIZE / 1024 / 8) ? FLASH_CHIP : ROM_CHIP; + uint8 REG_D_CHIP = (SAVE_FLASH != NULL && prg_bank_d_mapped >= 0x20000 - SAVE_FLASH_SIZE / 1024 / 8) ? FLASH_CHIP : ROM_CHIP; + + if (!cfi_mode || !SAVE_FLASH) + { + switch (prg_mode & 7) + { + default: + case 0: + setprg16r(REG_A_CHIP, 0x8000, prg_bank_a_mapped >> 1); + setprg16r(REG_C_CHIP, 0xC000, prg_bank_c_mapped >> 1); + break; + case 1: + setprg16r(REG_C_CHIP, 0x8000, prg_bank_c_mapped >> 1); + setprg16r(REG_A_CHIP, 0xC000, prg_bank_a_mapped >> 1); + break; + case 4: + setprg8r(REG_A_CHIP, 0x8000, prg_bank_a_mapped); + setprg8r(REG_B_CHIP, 0xA000, prg_bank_b_mapped); + setprg8r(REG_C_CHIP, 0xC000, prg_bank_c_mapped); + setprg8r(REG_D_CHIP, 0xE000, prg_bank_d_mapped); + break; + case 5: + setprg8r(REG_C_CHIP, 0x8000, prg_bank_c_mapped); + setprg8r(REG_B_CHIP, 0xA000, prg_bank_b_mapped); + setprg8r(REG_A_CHIP, 0xC000, prg_bank_a_mapped); + setprg8r(REG_D_CHIP, 0xE000, prg_bank_d_mapped); + break; + case 6: + setprg32r(REG_A_CHIP, 0x8000, prg_bank_b_mapped >> 2); + break; + case 7: + setprg32r(REG_A_CHIP, 0x8000, prg_bank_a_mapped >> 2); + break; + } + } + else { + setprg32r(CFI_CHIP, 0x8000, 0); + } + + if (!map_rom_on_6000 && WRAM) + setprg8r(WRAM_CHIP, 0x6000, sram_page); // Select SRAM page + else if (map_rom_on_6000) + setprg8(0x6000, prg_bank_6000_mapped); // Map ROM on $6000-$7FFF +} + +static void COOLGIRL_Sync_CHR(void) { + // calculate CHR shift + // wire shift_chr = ENABLE_MAPPER_021_022_023_025 && ENABLE_MAPPER_022 && (mapper == 6'b011000) && flags[1]; + int chr_shift = ((mapper == 0b011000) && (flags & 0b010)) ? 1 : 0; + + // enable or disable writes to CHR RAM, setup CHR mask + SetupCartCHRMapping(CHR_RAM_CHIP, CHR_RAM, ((((~(chr_mask >> 13) & 0x3F) + 1) * 0x2000 - 1) & (CHR_RAM_SIZE - 1)) + 1, can_write_chr); + + switch (chr_mode & 7) + { + default: + case 0: + setchr8r(0x12, chr_bank_a >> 3 >> chr_shift); + break; + case 1: + setchr4r(0x12, 0x0000, mapper_163_latch >> chr_shift); + setchr4r(0x12, 0x1000, mapper_163_latch >> chr_shift); + break; + case 2: + setchr2r(0x12, 0x0000, chr_bank_a >> 1 >> chr_shift); + TKSMIR[0] = TKSMIR[1] = chr_bank_a; + setchr2r(0x12, 0x0800, chr_bank_c >> 1 >> chr_shift); + TKSMIR[2] = TKSMIR[3] = chr_bank_c; + setchr1r(0x12, 0x1000, chr_bank_e >> chr_shift); + TKSMIR[4] = chr_bank_e; + setchr1r(0x12, 0x1400, chr_bank_f >> chr_shift); + TKSMIR[5] = chr_bank_f; + setchr1r(0x12, 0x1800, chr_bank_g >> chr_shift); + TKSMIR[6] = chr_bank_g; + setchr1r(0x12, 0x1C00, chr_bank_h >> chr_shift); + TKSMIR[7] = chr_bank_h; + break; + case 3: + setchr1r(0x12, 0x0000, chr_bank_e >> chr_shift); + TKSMIR[0] = chr_bank_e; + setchr1r(0x12, 0x0400, chr_bank_f >> chr_shift); + TKSMIR[1] = chr_bank_f; + setchr1r(0x12, 0x0800, chr_bank_g >> chr_shift); + TKSMIR[2] = chr_bank_g; + setchr1r(0x12, 0x0C00, chr_bank_h >> chr_shift); + TKSMIR[3] = chr_bank_h; + setchr2r(0x12, 0x1000, chr_bank_a >> 1 >> chr_shift); + TKSMIR[4] = TKSMIR[5] = chr_bank_a; + setchr2r(0x12, 0x1800, chr_bank_c >> 1 >> chr_shift); + TKSMIR[6] = TKSMIR[7] = chr_bank_c; + break; + case 4: + setchr4r(0x12, 0x0000, chr_bank_a >> 2 >> chr_shift); + setchr4r(0x12, 0x1000, chr_bank_e >> 2 >> chr_shift); + break; + case 5: + if (!ppu_latch0) + setchr4r(0x12, 0x0000, chr_bank_a >> 2 >> chr_shift); + else + setchr4r(0x12, 0x0000, chr_bank_b >> 2 >> chr_shift); + if (!ppu_latch1) + setchr4r(0x12, 0x1000, chr_bank_e >> 2 >> chr_shift); + else + setchr4r(0x12, 0x1000, chr_bank_f >> 2 >> chr_shift); + break; + case 6: + setchr2r(0x12, 0x0000, chr_bank_a >> 1 >> chr_shift); + setchr2r(0x12, 0x0800, chr_bank_c >> 1 >> chr_shift); + setchr2r(0x12, 0x1000, chr_bank_e >> 1 >> chr_shift); + setchr2r(0x12, 0x1800, chr_bank_g >> 1 >> chr_shift); + break; + case 7: + setchr1r(0x12, 0x0000, chr_bank_a >> chr_shift); + setchr1r(0x12, 0x0400, chr_bank_b >> chr_shift); + setchr1r(0x12, 0x0800, chr_bank_c >> chr_shift); + setchr1r(0x12, 0x0C00, chr_bank_d >> chr_shift); + setchr1r(0x12, 0x1000, chr_bank_e >> chr_shift); + setchr1r(0x12, 0x1400, chr_bank_f >> chr_shift); + setchr1r(0x12, 0x1800, chr_bank_g >> chr_shift); + setchr1r(0x12, 0x1C00, chr_bank_h >> chr_shift); + break; + } +} + +static void COOLGIRL_Sync_Mirroring(void) { + if (!four_screen) + { + if (!((mapper == 0b010100) && (flags & 1))) // Mapper #189? + setmirror((mirroring < 2) ? (mirroring ^ 1) : mirroring); + } + else { // four screen mode + vnapage[0] = CHR_RAM + 0x3F000; + vnapage[1] = CHR_RAM + 0x3F400; + vnapage[2] = CHR_RAM + 0x3F800; + vnapage[3] = CHR_RAM + 0x3FC00; + } +} + +static void COOLGIRL_Sync(void) { + COOLGIRL_Sync_PRG(); + COOLGIRL_Sync_CHR(); + COOLGIRL_Sync_Mirroring(); +} + +static DECLFW(COOLGIRL_Flash_Write) { + if (flash_state < sizeof(flash_buffer_a) / sizeof(flash_buffer_a[0])) + { + flash_buffer_a[flash_state] = A & 0xFFF; + flash_buffer_v[flash_state] = V; + flash_state++; + + // enter CFI mode + if ((flash_state == 1) && + (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0x98)) + { + cfi_mode = 1; + COOLGIRL_Sync_PRG(); + flash_state = 0; + return; + } + + // sector erase + if ((flash_state == 6) && + (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) && + (flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) && + (flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0x80) && + (flash_buffer_a[3] == 0x0AAA) && (flash_buffer_v[3] == 0xAA) && + (flash_buffer_a[4] == 0x0555) && (flash_buffer_v[4] == 0x55) && + (flash_buffer_v[5] == 0x30)) + { + int sector = prg_bank_a_mapped * 0x2000 / FLASH_SECTOR_SIZE; + uint32 sector_address = sector * FLASH_SECTOR_SIZE; + for (uint32 i = sector_address; i < sector_address + FLASH_SECTOR_SIZE; i++) + SAVE_FLASH[i % SAVE_FLASH_SIZE] = 0xFF; + FCEU_printf("Flash sector #%d is erased: 0x%08x - 0x%08x\n", sector, sector_address, sector_address + FLASH_SECTOR_SIZE - 1); + flash_state = 0; + } + + // write byte + if ((flash_state == 4) && + (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) && + (flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) && + (flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0xA0)) + { + int sector = prg_bank_a_mapped * 0x2000 / FLASH_SECTOR_SIZE; + uint32 sector_address = sector * FLASH_SECTOR_SIZE; + uint32 flash_addr = prg_bank_a_mapped * 0x2000 + (A % 0x8000); + if (SAVE_FLASH[flash_addr % SAVE_FLASH_SIZE] != 0xFF) { + FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased\n", flash_addr); + } + else { + SAVE_FLASH[flash_addr % SAVE_FLASH_SIZE] = V; + if (A % 0x2000 == 0) + FCEU_printf("Flash sector #%d is written: 0x%08x\n", sector, flash_addr); + } + flash_state = 0; + } + } + + // not a command + if (((A & 0xFFF) != 0x0AAA) && ((A & 0xFFF) != 0x0555)) { + flash_state = 0; + } + + // reset + if (V == 0xF0) { + flash_state = 0; + cfi_mode = 0; + } +} + +static DECLFW(COOLGIRL_WRITE) { + if (sram_enabled && A >= 0x6000 && A < 0x8000 && !map_rom_on_6000) + CartBW(A, V); // SRAM is enabled and writable + if (SAVE_FLASH && can_write_flash && A >= 0x8000) // writing flash + COOLGIRL_Flash_Write(A, V); + + // block two writes in a row + if ((timestampbase + timestamp) < (lreset + 2)) return; + lreset = timestampbase + timestamp; + + if (A >= 0x5000 && A < 0x6000 && !lockout) + { + //FCEU_printf("Write: %02x => %04x\n", V, A); + switch (A & 7) + { + case 0: + // {prg_base[26:22]} = cpu_data_in[4:0]; + // use bits 29-27 to simulate flash memory + SET_BITS(prg_base, "29:22", V, "7:0"); + break; + case 1: + // prg_base[21:14] = cpu_data_in[7:0]; + SET_BITS(prg_base, "21:14", V, "7:0"); + break; + case 2: + // {chr_mask[18], prg_mask[20:14]} = cpu_data_in[7:0]; + SET_BITS(chr_mask, "18", V, "7"); + SET_BITS(prg_mask, "20:14", V, "6:0"); + //FCEU_printf("REG_prg_mask: %02x\n", REG_prg_mask); + break; + case 3: + // {prg_mode[2:0], chr_bank_a[7:3]} = cpu_data_in[7:0]; + SET_BITS(prg_mode, "2:0", V, "7:5"); + SET_BITS(chr_bank_a, "7:3", V, "4:0"); + break; + case 4: + // {chr_mode[2:0], chr_mask[17:13]} = cpu_data_in[7:0]; + SET_BITS(chr_mode, "2:0", V, "7:5"); + SET_BITS(chr_mask, "17:13", V, "4:0"); + break; + case 5: + // {chr_bank_a[8], prg_bank_a[5:1], sram_page[1:0]} = cpu_data_in[7:0]; + SET_BITS(chr_bank_a, "8", V, "7"); + SET_BITS(prg_bank_a, "5:1", V, "6:2"); + SET_BITS(sram_page, "1:0", V, "1:0"); + break; + case 6: + // {flags[2:0], mapper[4:0]} = cpu_data_in[7:0]; + SET_BITS(flags, "2:0", V, "7:5"); + SET_BITS(mapper, "4:0", V, "4:0"); + break; + case 7: + // {lockout, mapper[5], four_screen, mirroring[1:0], prg_write_enabled, chr_write_enabled, sram_enabled} = cpu_data_in[7:0]; + SET_BITS(lockout, "0", V, "7"); + SET_BITS(mapper, "5", V, "6"); + SET_BITS(four_screen, "0", V, "5"); + SET_BITS(mirroring, "1:0", V, "4:3"); + SET_BITS(can_write_flash, "0", V, "2"); + SET_BITS(can_write_chr, "0", V, "1"); + SET_BITS(sram_enabled, "0", V, "0"); + if (mapper == 0b010001) prg_bank_b = ~2; // if (USE_MAPPER_009_010 && mapper == 6'b010001) prg_bank_b = 8'b11111101; + if (mapper == 0b010111) map_rom_on_6000 = 1; // if (ENABLE_MAPPER_042 && (mapper == 6'b010111)) map_rom_on_6000 <= 1; + if (mapper == 0b001110) prg_bank_b = 1; // if (USE_MAPPER_065 && mapper == 6'b001110) prg_bank_b = 1; + break; + } + } + + if (A < 0x8000) // $0000-$7FFF + { + // Mapper #163 + if (mapper == 0b000110) + { + if (A == 0x5101) // if (cpu_addr_in[14:0] == 15'h5101) + { + if (mapper163_r4 && !V) // if ((mapper163_r4 != 0) && (cpu_data_in == 0)) + mapper163_r5 ^= 1; // mapper163_r5[0] = ~mapper163_r5[0]; + mapper163_r4 = V; + } + else if (A == 0x5100 && V == 6) // if ((cpu_addr_in[14:0] == 15'h5100) && (cpu_data_in == 6)) + { + SET_BITS(prg_mode, "0", 0, "0"); // prg_mode[0] = 0; + prg_bank_b = 0b1100; // prb_bank_b = 4'b1100; + } + else { + if (get_bits(A, "14:12") == 0b101) // if (cpu_addr_in[14:12] == 3'b101) begin + { + switch (get_bits(A, "9:8")) // case (cpu_addr_in[9:8]) + { + case 2: + SET_BITS(prg_mode, "0", 1, "0"); // prg_mode[0] = 1; + SET_BITS(prg_bank_a, "7:6", V, "1:0"); // prg_bank_a[7:6] = cpu_data_in[1:0]; + mapper163_r0 = V; + break; + case 0: + SET_BITS(prg_mode, "0", 1, "0"); // prg_mode[0] = 1; + SET_BITS(prg_bank_a, "5:2", V, "3:0"); // prg_bank_a[5:2] = cpu_data_in[3:0]; + SET_BITS(chr_mode, "0", V, "7"); // chr_mode[0] = cpu_data_in[7]; + mapper163_r1 = V; + break; + case 3: + mapper163_r2 = V; // mapper163_r2 = cpu_data_in; + break; + case 1: + mapper163_r3 = V; // mapper163_r3 = cpu_data_in; + break; + } + } + } + } + + // Mapper #87 + if (mapper == 0b001100) + { + if (get_bits(A, "14:13") == 0b11) // if (cpu_addr_in[14:13] == 2'b11) // $6000-$7FFF + { + // chr_bank_a[4:3] = {cpu_data_in[0], cpu_data_in[1]}; + SET_BITS(chr_bank_a, "4:3", V, "0,1"); + } + } + + // Mapper #90 - JY + /* + if (mapper == 0b001101) + { + switch (A) + { + case 0x5800: mul1 = V; break; + case 0x5801: mul2 = V; break; + } + } + */ + + // MMC5 (not really) + if (mapper == 0b001111) + { + // case (cpu_addr_in[14:0]) + switch (get_bits(A, "14:0")) + { + case 0x5105: + if (V == 0xFF) + { + four_screen = 1; + } + else { + four_screen = 0; + // case ({cpu_data_in[4], cpu_data_in[2]}) + switch (get_bits(V, "4,2")) + { + case 0b00: // 2'b00: mirroring = 2'b10; + mirroring = 0b10; break; + case 0b01: // 2'b01: mirroring = 2'b00; + mirroring = 0b00; break; + case 0b10: // 2'b10: mirroring = 2'b01; + mirroring = 0b01; break; + case 0b11: // 2'b11: mirroring = 2'b11; + mirroring = 0b11; break; + } + } + break; + case 0x5115: + // prg_bank_a[4:0] = { cpu_data_in[4:1], 1'b0}; + SET_BITS(prg_bank_a, "4:1", V, "4:1"); + SET_BITS(prg_bank_a, "0", 0, "0"); + // prg_bank_b[4:0] = { cpu_data_in[4:1], 1'b1}; + SET_BITS(prg_bank_b, "4:1", V, "4:1"); + SET_BITS(prg_bank_b, "0", 1, "0"); + break; + case 0x5116: + // prg_bank_c[4:0] = cpu_data_in[4:0]; + SET_BITS(prg_bank_c, "4:0", V, "4:0"); + break; + case 0x5117: + // prg_bank_d[4:0] = cpu_data_in[4:0]; + SET_BITS(prg_bank_d, "4:0", V, "4:0"); + break; + case 0x5120: + // chr_bank_a[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_a, "7:0", V, "7:0"); + break; + case 0x5121: + // chr_bank_b[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_b, "7:0", V, "7:0"); + break; + case 0x5122: + // chr_bank_c[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_c, "7:0", V, "7:0"); + break; + case 0x5123: + // chr_bank_d[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_d, "7:0", V, "7:0"); + break; + case 0x5128: + // chr_bank_e[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_e, "7:0", V, "7:0"); + break; + case 0x5129: + // chr_bank_f[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_f, "7:0", V, "7:0"); + break; + case 0x512A: + // chr_bank_g[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_g, "7:0", V, "7:0"); + break; + case 0x512B: + // chr_bank_h[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_h, "7:0", V, "7:0"); + break; + case 0x5203: + // mmc5_irq_ack = 1; + X6502_IRQEnd(FCEU_IQEXT); + mmc5_irq_out = 0; + // mmc5_irq_line[7:0] = cpu_data_in[7:0]; + SET_BITS(mmc5_irq_line, "7:0", V, "7:0"); + break; + case 0x5204: + // mmc5_irq_ack = 1; + X6502_IRQEnd(FCEU_IQEXT); + mmc5_irq_out = 0; + // mmc5_irq_enabled = cpu_data_in[7]; + mmc5_irq_enabled = get_bits(V, "7"); + break; + } + } + + // Mapper #189 + if ((mapper == 0b010100) && (flags & 2)) + { + if (A >= 0x4120) // if (cpu_addr_in[14:0] >= 15'h4120) // $4120-$7FFF + { + // prg_bank_a[5:2] = cpu_data_in[3:0] | cpu_data_in[7:4]; + prg_bank_a = set_bits(prg_bank_a, "5:2", + get_bits(V, "7:4") | get_bits(V, "3:0")); + } + } + + // Mappers #79 and #146 - NINA-03/06 and Sachen 3015: (flag0 = 1) + if (mapper == 0b011011) + { + // if ({cpu_addr_in[14:13], cpu_addr_in[8]} == 3'b101) + if (get_bits(A, "14:13,8") == 0b101) + { + //chr_bank_a[5:3] = cpu_data_in[2:0]; + SET_BITS(chr_bank_a, "5:3", V, "2:0"); + //prg_bank_a[2] = cpu_data_in[3]; + SET_BITS(prg_bank_a, "2", V, "3"); + } + } + + // Mapper #133 + if (mapper == 0b011100) + { + // if ({cpu_addr_in[14:13], cpu_addr_in[8]} == 3'b101) + if (get_bits(A, "14:13,8") == 0b101) + { + //chr_bank_a[4:3] = cpu_data_in[1:0]; + SET_BITS(chr_bank_a, "4:3", V, "1:0"); + //prg_bank_a[2] = cpu_data_in[2]; + SET_BITS(prg_bank_a, "2", V, "2"); + } + } + + // Mapper #184 + if (mapper == 0b011111) + { + if (get_bits(A, "14:13") == 0b11) // if (cpu_addr_in[14:13] == 2'b11) + { + // chr_bank_a[4:2] = cpu_data_in[2:0]; + SET_BITS(chr_bank_a, "4:2", V, "2:0"); + // chr_bank_e[4:2] = {1'b1, cpu_data_in[5:4]}; + SET_BITS(chr_bank_e, "3:2", V, "5:4"); + SET_BITS(chr_bank_e, "4", 1, "0"); + } + } + + // Mapper #38 + if (mapper == 0b100000) + { + // if (cpu_addr_in[14:12] == 3'b111) + if (get_bits(A, "14:12") == 0b111) + { + // prg_bank_a[3:2] = cpu_data_in[1:0]; + SET_BITS(prg_bank_a, "3:2", V, "1:0"); + // chr_bank_a[4:3] = cpu_data_in[3:2]; + SET_BITS(chr_bank_a, "4:3", V, "3:2"); + } + } + } + else // $8000-$FFFF + { + // Mapper #2 - UxROM + // flag0 - mapper #71 - for Fire Hawk only. + // other mapper-#71 games are UxROM + if (mapper == 0b000001) + { + // if (!ENABLE_MAPPER_071 | ~flags[0] | (cpu_addr_in[14:12] != 3'b001)) + if (!(flags & 1) || (get_bits(A, "14:12") != 0b001)) + { + // prg_bank_a[UxROM_BITSIZE+1:1] = cpu_data_in[UxROM_BITSIZE:0]; + // UxROM_BITSIZE = 4 + SET_BITS(prg_bank_a, "5:1", V, "4:0"); + // if (ENABLE_MAPPER_030 && flags[1]) + if (flags & 2) + { + // One screen mirroring select, CHR RAM bank, PRG ROM bank + // mirroring[1:0] = { 1'b1, cpu_data_in[7]}; + SET_BITS(mirroring, "1", 1, "0"); + SET_BITS(mirroring, "0", V, "7"); + // chr_bank_a[1:0] = cpu_data_in[6:5]; + SET_BITS(chr_bank_a, "1:0", V, "6:5"); + } + } + else { + // CodeMasters, blah. Mirroring control used only by Fire Hawk + // mirroring[1:0] = {1'b1, cpu_data_in[4]}; + SET_BITS(mirroring, "1", 1, "0"); + SET_BITS(mirroring, "0", V, "4"); + } + } + + // Mapper #3 - CNROM + if (mapper == 0b000010) + { + // chr_bank_a[7:3] = cpu_data_in[4:0]; + SET_BITS(chr_bank_a, "7:3", V, "4:0"); + } + + // Mapper #78 - Holy Diver + if (mapper == 0b000011) + { + // prg_bank_a[3:1] = cpu_data_in[2:0]; + SET_BITS(prg_bank_a, "3:1", V, "2:0"); + // chr_bank_a[6:3] = cpu_data_in[7:4]; + SET_BITS(chr_bank_a, "6:3", V, "7:4"); + // mirroring = { 1'b0, ~cpu_data_in[3]}; + mirroring = get_bits(V, "3") ^ 1; + } + + // Mapper #97 - Irem's TAM-S1 + if (mapper == 0b000100) + { + // prg_bank_a[5:1] = cpu_data_in[4:0]; + SET_BITS(chr_bank_a, "5:1", V, "4:0"); + // mirroring = { 1'b0, ~cpu_data_in[7]}; + mirroring = get_bits(V, "7") ^ 1; + } + + // Mapper #93 - Sunsoft-2 + if (mapper == 0b000101) + { + // prg_bank_a[3:1] = { cpu_data_in[6:4] }; + SET_BITS(prg_bank_a, "3:1", V, "6:4"); + // chr_write_enabled = cpu_data_in[0]; + can_write_chr = V & 1; + } + + // Mapper #18 + if (mapper == 0b000111) + { + // case ({cpu_addr_in[14:12], cpu_addr_in[1:0]}) + switch (get_bits(A, "14:12,1:0")) + { + case 0b00000: // 5'b00000: prg_bank_a[3:0] = cpu_data_in[3:0]; // $8000 + SET_BITS(prg_bank_a, "3:0", V, "3:0"); break; + case 0b00001: // 5'b00001: prg_bank_a[7:4] = cpu_data_in[3:0]; // $8001 + SET_BITS(prg_bank_a, "7:4", V, "3:0"); break; + case 0b00010: // 5'b00010: prg_bank_b[3:0] = cpu_data_in[3:0]; // $8002 + SET_BITS(prg_bank_b, "3:0", V, "3:0"); break; + case 0b00011: // 5'b00011: prg_bank_b[7:4] = cpu_data_in[3:0]; // $8003 + SET_BITS(prg_bank_b, "7:4", V, "3:0"); break; + case 0b00100: // 5'b00100: prg_bank_c[3:0] = cpu_data_in[3:0]; // $9000 + SET_BITS(prg_bank_c, "3:0", V, "3:0"); break; + case 0b00101: // 5'b00101: prg_bank_c[7:4] = cpu_data_in[3:0]; // $9001 + SET_BITS(prg_bank_c, "7:4", V, "3:0"); break; + case 0b00110: + break; + case 0b00111: + break; + case 0b01000: // 5'b01000: chr_bank_a[3:0] = cpu_data_in[3:0]; // $A000 + SET_BITS(chr_bank_a, "3:0", V, "3:0"); break; + case 0b01001: // 5'b01001: chr_bank_a[7:4] = cpu_data_in[3:0]; // $A001 + SET_BITS(chr_bank_a, "7:4", V, "3:0"); break; + case 0b01010: // 5'b01010: chr_bank_b[3:0] = cpu_data_in[3:0]; // $A002 + SET_BITS(chr_bank_b, "3:0", V, "3:0"); break; + case 0b01011: // 5'b01011: chr_bank_b[7:4] = cpu_data_in[3:0]; // $A003 + SET_BITS(chr_bank_b, "7:4", V, "3:0"); break; + case 0b01100: // 5'b01100: chr_bank_c[3:0] = cpu_data_in[3:0]; // $B000 + SET_BITS(chr_bank_c, "3:0", V, "3:0"); break; + case 0b01101: // 5'b01101: chr_bank_c[7:4] = cpu_data_in[3:0]; // $B001 + SET_BITS(chr_bank_c, "7:4", V, "3:0"); break; + case 0b01110: // 5'b01110: chr_bank_d[3:0] = cpu_data_in[3:0]; // $B002 + SET_BITS(chr_bank_d, "3:0", V, "3:0"); break; + case 0b01111: // 5'b01111: chr_bank_d[7:4] = cpu_data_in[3:0]; // $B003 + SET_BITS(chr_bank_d, "7:4", V, "3:0"); break; + case 0b10000: // 5'b10000: chr_bank_e[3:0] = cpu_data_in[3:0]; // $C000 + SET_BITS(chr_bank_e, "3:0", V, "3:0"); break; + case 0b10001: // 5'b10001: chr_bank_e[7:4] = cpu_data_in[3:0]; // $C001 + SET_BITS(chr_bank_e, "7:4", V, "3:0"); break; + case 0b10010: // 5'b10010: chr_bank_f[3:0] = cpu_data_in[3:0]; // $C002 + SET_BITS(chr_bank_f, "3:0", V, "3:0"); break; + case 0b10011: // 5'b10011: chr_bank_f[7:4] = cpu_data_in[3:0]; // $C003 + SET_BITS(chr_bank_f, "7:4", V, "3:0"); break; + case 0b10100: // 5'b10100: chr_bank_g[3:0] = cpu_data_in[3:0]; // $D000 + SET_BITS(chr_bank_g, "3:0", V, "3:0"); break; + case 0b10101: // 5'b10101: chr_bank_g[7:4] = cpu_data_in[3:0]; // $D001 + SET_BITS(chr_bank_g, "7:4", V, "3:0"); break; + case 0b10110: // 5'b10110: chr_bank_h[3:0] = cpu_data_in[3:0]; // $D002 + SET_BITS(chr_bank_h, "3:0", V, "3:0"); break; + case 0b10111: // 5'b10111: chr_bank_h[7:4] = cpu_data_in[3:0]; // $D003 + SET_BITS(chr_bank_h, "7:4", V, "3:0"); break; + case 0b11000: // 5'b11000: mapper18_irq_latch[3:0] = cpu_data_in[3:0]; // $E000 + SET_BITS(mapper18_irq_latch, "3:0", V, "3:0"); break; + case 0b11001: // 5'b11001: mapper18_irq_latch[7:4] = cpu_data_in[3:0]; // $E001 + SET_BITS(mapper18_irq_latch, "7:4", V, "3:0"); break; + case 0b11010: // 5'b11010: mapper18_irq_latch[11:8] = cpu_data_in[3:0]; // $E002 + SET_BITS(mapper18_irq_latch, "11:8", V, "3:0"); break; + case 0b11011: // 5'b11011: mapper18_irq_latch[15:12] = cpu_data_in[3:0]; // $E003 + SET_BITS(mapper18_irq_latch, "15:12", V, "3:0"); break; + case 0b11100: // 5'b11100: begin // $F000 + // mapper18_irq_out = 0; // ack + X6502_IRQEnd(FCEU_IQEXT); + // mapper18_irq_value[15:0] = mapper18_irq_latch[15:0]; + mapper18_irq_value = mapper18_irq_latch; break; // irq_cpu_out = 0; + case 0b11101: // 5'b11101: begin // $F001 + X6502_IRQEnd(FCEU_IQEXT); // irq_cpu_control[3:0] = cpu_data_in[3:0]; + SET_BITS(mapper18_irq_control, "3:0", V, "3:0"); break; + case 0b11110: // 5'b11110 + switch (get_bits(V, "1:0")) // case (cpu_data_in[1:0]) + { + case 0b00: mirroring = 0b01; break; //2'b00: mirroring = 2'b01; // Horz + case 0b01: mirroring = 0b00; break; //2'b01: mirroring = 2'b00; // Vert + case 0b10: mirroring = 0b10; break; //2'b10: mirroring = 2'b10; // 1SsA + case 0b11: mirroring = 0b11; break; //2'b11: mirroring = 2'b11; // 1SsB + } + case 0b11111: + break; // sound + } + } + + // Mapper #7 - AxROM, mapper #241 - BNROM + if (mapper == 0b001000) + { + // AxROM_BxROM_BITSIZE = 3 + //prg_bank_a[AxROM_BxROM_BITSIZE + 2:2] = cpu_data_in[AxROM_BxROM_BITSIZE:0]; + SET_BITS(prg_bank_a, "5:2", V, "3:0"); + //if (!ENABLE_MAPPER_034_241_BxROM || !flags[0]) // BxROM? + // mirroring = { 1'b1, cpu_data_in[4]}; + if (!(flags & 1)) + mirroring = (1 << 1) | get_bits(V, "4"); + } + + // Mapper #228 - Cheetahmen II + if (mapper == 0b001001) + { + // prg_bank_a[5:2] = cpu_addr_in[10:7]; + SET_BITS(prg_bank_a, "5:2", A, "10:7"); + // chr_bank_a[7:3] = { cpu_addr_in[2:0], cpu_data_in[1:0] }; // only 256k, sorry + SET_BITS(chr_bank_a, "7:5", A, "2:0"); + SET_BITS(chr_bank_a, "4:3", V, "1:0"); + // mirroring = { 1'b0, cpu_addr_in[13]}; + mirroring = get_bits(A, "13"); + } + + // Mapper #11 - ColorDreams + if (mapper == 0b001010) + { + // prg_bank_a[3:2] = cpu_data_in[1:0]; + SET_BITS(prg_bank_a, "3:2", V, "1:0"); + // chr_bank_a[6:3] = cpu_data_in[7:4]; + SET_BITS(chr_bank_a, "6:3", V, "7:4"); + } + + // Mapper #66 - GxROM + if (mapper == 0b001011) + { + // prg_bank_a[3:2] = cpu_data_in[5:4]; + SET_BITS(prg_bank_a, "3:2", V, "5:4"); + // chr_bank_a[4:3] = cpu_data_in[1:0]; + SET_BITS(chr_bank_a, "4:3", V, "1:0"); + } + + // Mapper #90 - JY + if (mapper == 0b001101) + { + // if (cpu_addr_in[14:12] == 3'b000) // $800x + if (get_bits(A, "14:12") == 0b000) + { + // case (cpu_addr_in[1:0]) + switch (get_bits(A, "1:0")) + { + // 2'b00: prg_bank_a[5:0] = cpu_data_in[5:0]; + case 0b00: SET_BITS(prg_bank_a, "5:0", V, "5:0"); break; + // 2'b01: prg_bank_b[5:0] = cpu_data_in[5:0]; + case 0b01: SET_BITS(prg_bank_b, "5:0", V, "5:0"); break; + // 2'b10: prg_bank_c[5:0] = cpu_data_in[5:0]; + case 0b10: SET_BITS(prg_bank_c, "5:0", V, "5:0"); break; + // 2'b11: prg_bank_d[5:0] = cpu_data_in[5:0]; + case 0b11: SET_BITS(prg_bank_d, "5:0", V, "5:0"); break; + } + } + + // if (cpu_addr_in[14:12] == 3'b001) // $900x + if (get_bits(A, "14:12") == 0b001) + { + // case (cpu_addr_in[2:0]) + switch (get_bits(A, "2:0")) + { + case 0b000: // 3'b000: chr_bank_a[7:0] = cpu_data_in[7:0]; // $9000 + SET_BITS(chr_bank_a, "7:0", V, "7:0"); break; + case 0b001: // 3'b001: chr_bank_b[7:0] = cpu_data_in[7:0]; // $9001 + SET_BITS(chr_bank_b, "7:0", V, "7:0"); break; + case 0b010: // 3'b010: chr_bank_c[7:0] = cpu_data_in[7:0]; // $9002 + SET_BITS(chr_bank_c, "7:0", V, "7:0"); break; + case 0b011: // 3'b011: chr_bank_d[7:0] = cpu_data_in[7:0]; // $9003 + SET_BITS(chr_bank_d, "7:0", V, "7:0"); break; + case 0b100: // 3'b100: chr_bank_e[7:0] = cpu_data_in[7:0]; // $9004 + SET_BITS(chr_bank_e, "7:0", V, "7:0"); break; + case 0b101: // 3'b101: chr_bank_f[7:0] = cpu_data_in[7:0]; // $9005 + SET_BITS(chr_bank_f, "7:0", V, "7:0"); break; + case 0b110: // 3'b110: chr_bank_g[7:0] = cpu_data_in[7:0]; // $9006 + SET_BITS(chr_bank_g, "7:0", V, "7:0"); break; + case 0b111: // 3'b111: chr_bank_h[7:0] = cpu_data_in[7:0]; // $9007 + SET_BITS(chr_bank_h, "7:0", V, "7:0"); break; + } + } + + // if ({cpu_addr_in[14:12], cpu_addr_in[1:0]} == 5'b10101) // $D001 + if (get_bits(A, "14:12,1:0") == 0b10101) + { + // mirroring = cpu_data_in[1:0]; + SET_BITS(mirroring, "1:0", V, "1:0"); + } + + // use MMC3's IRQs + // if (cpu_addr_in[14:12] == 3'b100) // $C00x + if (get_bits(A, "14:12") == 0b100) + { + // case (cpu_addr_in[2:0]) + switch (get_bits(A, "2:0")) + { + case 0b000: + // 3'b000: mmc3_irq_enabled = cpu_data_in[0]; + if (V & 1) + { + mmc3_irq_enabled = 1; + } + else { + X6502_IRQEnd(FCEU_IQEXT); + mmc3_irq_enabled = 0; + } + break; + case 0b001: + break; // who cares about this shit? + case 0b010: + // 3'b010: mmc3_irq_enabled = 0; + mmc3_irq_enabled = 0; + X6502_IRQEnd(FCEU_IQEXT); + break; + case 0b011: + // 3'b011: mmc3_irq_enabled = 1; + mmc3_irq_enabled = 1; + break; + case 0b100: + break; // prescaler? who cares? + case 0b101: + // mmc3_irq_latch = cpu_data_in ^ mapper90_xor; + mmc3_irq_latch = V ^ mapper90_xor; + mmc3_irq_reload = 1; + break; + case 0b110: + // mapper90_xor = cpu_data_in; + mapper90_xor = V; + break; + case 0b111: + break; // meh + } + } + } + + // Mapper #65 - Irem's H3001 + if (mapper == 0b001110) + { + // case ({cpu_addr_in[14:12], cpu_addr_in[2:0]}) + switch (get_bits(A, "14:12,2:0")) + { + case 0b000000: + // 6'b000000: prg_bank_a[5:0] = cpu_data_in[5:0]; // $8000 + SET_BITS(prg_bank_a, "5:0", V, "5:0"); + break; + case 0b001001: + // 6'b001001: mirroring = {1'b0, cpu_data_in[7]}; // $9001, mirroring + mirroring = get_bits(V, "7"); + break; + case 0b001011: + // mapper65_irq_out = 0; // ack + X6502_IRQEnd(FCEU_IQEXT); // irq_cpu_out = 0; + // mapper65_irq_enabled = cpu_data_in[7]; // $9003, enable IRQ + mapper65_irq_enabled = get_bits(V, "7"); + break; + case 0b001100: + X6502_IRQEnd(FCEU_IQEXT); // mapper65_irq_out = 0; // ack + mapper65_irq_value = mapper65_irq_latch; // $9004, IRQ reload + break; + case 0b001101: // mapper65_irq_latch[15:8] = cpu_data_in; // $9005, IRQ high value + SET_BITS(mapper65_irq_latch, "15:8", V, "7:0"); break; + case 0b001110: // mapper65_irq_latch[7:0] = cpu_data_in; // $9006, IRQ low value + SET_BITS(mapper65_irq_latch, "7:0", V, "7:0"); break; + case 0b010000: // prg_bank_b[5:0] = cpu_data_in[5:0]; // $A000 + prg_bank_b = (prg_bank_b & 0b11000000) | (V & 0b00111111); break; + case 0b011000: // chr_bank_a[7:0] = cpu_data_in; // $B000 + SET_BITS(chr_bank_a, "7:0", V, "7:0"); break; + case 0b011001: // chr_bank_b[7:0] = cpu_data_in[7:0]; // $B001 + SET_BITS(chr_bank_b, "7:0", V, "7:0"); break; + case 0b011010: // chr_bank_c[7:0] = cpu_data_in[7:0]; // $B002 + SET_BITS(chr_bank_c, "7:0", V, "7:0"); break; + case 0b011011: // chr_bank_d[7:0] = cpu_data_in[7:0]; // $B003 + SET_BITS(chr_bank_d, "7:0", V, "7:0"); break; + case 0b011100: // chr_bank_e[7:0] = cpu_data_in[7:0]; // $B004 + SET_BITS(chr_bank_e, "7:0", V, "7:0"); break; + case 0b011101: // chr_bank_f[7:0] = cpu_data_in[7:0]; // $B005 + SET_BITS(chr_bank_f, "7:0", V, "7:0"); break; + case 0b011110: // chr_bank_g[7:0] = cpu_data_in[7:0]; // $B006 + SET_BITS(chr_bank_g, "7:0", V, "7:0"); break; + case 0b011111: // chr_bank_h[7:0] = cpu_data_in[7:0]; // $B007 + SET_BITS(chr_bank_h, "7:0", V, "7:0"); break; + case 0b100000: // 6'b100000: prg_bank_c[5:0] = cpu_data_in[5:0]; // $C000 + SET_BITS(prg_bank_c, "5:0", V, "5:0"); break; + } + } + + // Mapper #1 - MMC1 + /* + r0 - load register + flag0 - 16KB of SRAM (SOROM) + */ + if (mapper == 0b010000) + { + if (V & 0x80) // reset + { + mmc1_load_register = set_bits(mmc1_load_register, "5:0", 0b100000); // mmc1_load_register[5:0] = 6'b100000; + prg_mode = 0; // 0x4000 (A) + fixed last (C) + prg_bank_c = set_bits(prg_bank_c, "4:0", 0b11110); // prg_bank_c[4:0] = 5'b11110; + } + else { + // mmc1_load_register[5:0] = { cpu_data_in[0], mmc1_load_register[5:1] }; + SET_BITS(mmc1_load_register, "4:0", mmc1_load_register, "5:1"); + SET_BITS(mmc1_load_register, "5", V, "0"); + // if (mmc1_load_register[0] == 1) + if (mmc1_load_register & 1) + { + switch ((A >> 13) & 3) + { + case 0b00: // 2'b00: begin // $8000-$9FFF + if (get_bits(mmc1_load_register, "4:3") == 0b11) // if (mmc1_load_register[4:3] == 2'b11) + { + prg_mode = 0; // prg_mode = 3'b000; // 0x4000 (A) + fixed last (C) + prg_bank_c = set_bits(prg_bank_c, "4:1", 0b1111); // prg_bank_c[4:1] = 4'b1111; + } + //else if (mmc1_load_register[4:3] == 2'b10) + else if (get_bits(mmc1_load_register, "4:3") == 0b10) + { + prg_mode = 0b001; // prg_mode = 3'b001; // fixed first (C) + 0x4000 (A) + prg_bank_c = set_bits(prg_bank_c, "4:1", 0b0000); // prg_bank_c[4:0] = 4'b0000; + } + else + prg_mode = 0b111; // prg_mode = 3'b111; // 0x8000 (A) + if (get_bits(mmc1_load_register, "5")) + chr_mode = 0b100; + else + chr_mode = 0b000; + mirroring = set_bits(mirroring, "1:0", get_bits(mmc1_load_register, "2:1") ^ 0b10); + break; + case 0b01: // 2'b01 + SET_BITS(chr_bank_a, "6:2", mmc1_load_register, "5:1"); // chr_bank_a[6:2] = mmc1_load_register[5:1]; + if (flags & 1) // (flags[0]) - 16KB of SRAM + { + // PRG RAM page #2 is battery backed + sram_page = 2 | get_bits(mmc1_load_register, "4") ^ 1; // sram_page <= {1'b1, ~mmc1_load_register[4]}; + } + SET_BITS(prg_bank_a, "5", mmc1_load_register, "5"); // prg_bank_a[5] = mmc1_load_register[5]; // for SUROM, 512k PRG support + SET_BITS(prg_bank_c, "5", mmc1_load_register, "5"); // prg_bank_c[5] = mmc1_load_register[5]; // for SUROM, 512k PRG support + break; + case 0b10: // 2'b10: chr_bank_e[6:2] = mmc1_load_register[5:1]; // $C000-$DFFF + SET_BITS(chr_bank_e, "6:2", mmc1_load_register, "5:1"); + break; + case 0b11: // 2'b11 + // prg_bank_a[4:1] = r0[4:1]; + SET_BITS(prg_bank_a, "4:1", mmc1_load_register, "4:1"); + // sram_enabled = ~mmc1_load_register[5]; + sram_enabled = get_bits(mmc1_load_register, "5") ^ 1; + break; + } + mmc1_load_register = 0b100000; // mmc1_load_register[5:0] = 6'b100000; + } + } + } + + // Mapper #9 and #10 - MMC2 and MMC4 + // flag0 - 0=MMC2, 1=MMC4 + if (mapper == 0b010001) + { + switch ((A >> 12) & 7) + { + case 2: // $A000-$AFFF + if (!(flags & 1)) // MMC2 + prg_bank_a = (prg_bank_a & 0xF0) | (V & 0x0F); // prg_bank_a[3:0] = cpu_data_in[3:0]; + else // MMC4 + prg_bank_a = (prg_bank_a & 0xE1) | ((V & 0x0F) << 1); // prg_bank_a[4:0] = { cpu_data_in[3:0], 1'b0}; + break; + case 3: // $B000-$BFFF + chr_bank_a = (chr_bank_a & 0x83) | ((V & 0x1F) << 2); // chr_bank_a[6:2] = cpu_data_in[4:0]; + break; + case 4: // $C000-$CFFF + chr_bank_b = (chr_bank_b & 0x83) | ((V & 0x1F) << 2); // chr_bank_b[6:2] = cpu_data_in[4:0]; + break; + case 5: // $D000-$DFFF + chr_bank_e = (chr_bank_e & 0x83) | ((V & 0x1F) << 2); // chr_bank_b[6:2] = cpu_data_in[4:0]; + break; + case 6: // $E000-$EFFF + chr_bank_f = (chr_bank_f & 0x83) | ((V & 0x1F) << 2); // chr_bank_b[6:2] = cpu_data_in[4:0]; + break; + case 7: // $F000-$FFFF + mirroring = V & 1; + break; + } + } + + // Mapper #152 + if (mapper == 0b010010) + { + chr_bank_a = (chr_bank_a & 0x87) | ((V & 0x0F) << 3); // chr_bank_a[6:3] = cpu_data_in[3:0]; + prg_bank_a = (prg_bank_a & 0xF1) | ((V & 0x70) >> 3); // prg_bank_a[3:1] = cpu_data_in[6:4]; + mirroring = 2 | (V >> 7); // mirroring = {1'b1, cpu_data_in[7]}; + } + + // Mapper #73 - VRC3 + if (mapper == 0b010011) + { + switch (get_bits(A, "14:12")) // case (cpu_addr_in[14:12]) + { + case 0b000: // 3'b000: vrc3_irq_latch[3:0] = cpu_data_in[3:0]; // $8000-$8FFF + SET_BITS(vrc3_irq_latch, "3:0", V, "3:0"); + break; + case 0b001: // 3'b001: vrc3_irq_latch[7:4] = cpu_data_in[3:0]; // $9000-$9FFF + SET_BITS(vrc3_irq_latch, "7:4", V, "3:0"); + break; + case 0b010: // 3'b010: vrc3_irq_latch[11:8] = cpu_data_in[3:0]; // $A000-$AFFF + SET_BITS(vrc3_irq_latch, "11:8", V, "3:0"); + break; + case 0b011: // 3'b011: vrc3_irq_latch[15:12] = cpu_data_in[3:0]; // $B000-$BFFF + SET_BITS(vrc3_irq_latch, "15:12", V, "3:0"); + break; + case 0b100: // // $C000-$CFFF + X6502_IRQEnd(FCEU_IQEXT); // vrc3_irq_out = 0; // ack + SET_BITS(vrc3_irq_control, "2:0", V, "2:0"); // vrc3_irq_control[2:0] = cpu_data_in[2:0]; // mode, enabled, enabled after ack + if (vrc3_irq_control & 2) // if (vrc3_irq_control[1]) // if E is set + vrc3_irq_value = vrc3_irq_latch; // vrc3_irq_value[15:0] = vrc3_irq_latch[15:0]; // reload with latch + break; + case 0b101: // // $D000-$DFFF + X6502_IRQEnd(FCEU_IQEXT); // vrc3_irq_out = 0; // ack + SET_BITS(vrc3_irq_control, "1", vrc3_irq_control, "0"); // vrc3_irq_control[1] = vrc3_irq_control[0]; + break; + case 0b110: // $E000-$EFFF + break; + case 0b111: // 3'b111: prg_bank_a[3:1] = cpu_data_in[2:0]; // $F000-$FFFF + SET_BITS(prg_bank_a, "3:1", V, "2:0"); + break; + } + } + + // Mapper #4 - MMC3/MMC6 + /* + flag0 - TxSROM + flag1 - mapper #189 + */ + if (mapper == 0b010100) + { + // case ({cpu_addr_in[14:13], cpu_addr_in[0]}) + switch (get_bits(A, "14:13,0")) + { + case 0b000: // $8000-$9FFE, even + SET_BITS(mmc3_internal, "2:0", V, "2:0"); // mmc3_internal[2:0] = cpu_data_in[2:0]; + if (!(flags & 2) && !(flags & 4)) // if ((!USE_MAPPER_189 | ~flags[1]) & (!USE_MAPPER_206 | ~flags[2])) + { + if (get_bits(V, "6")) // if (cpu_data_in[6]) + prg_mode = 0b101; + else + prg_mode = 0b100; + } + if (!(flags & 4)) // if (!USE_MAPPER_206 | ~flags[2]) // disabled for mapper #206 + { + if (V & 0x80) // if (cpu_data_in[7]) + chr_mode = 0b011; + else + chr_mode = 0b010; + } + break; + case 0b001: // $8001-$9FFF, odd + switch (get_bits(mmc3_internal, "2:0")) + { + case 0b000: // 3'b000: chr_bank_a[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_a, "7:0", V, "7:0"); break; + case 0b001: // 3'b001: chr_bank_c[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_c, "7:0", V, "7:0"); break; + case 0b010: // 3'b010: chr_bank_e[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_e, "7:0", V, "7:0"); break; + case 0b011: // 3'b011: chr_bank_f[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_f, "7:0", V, "7:0"); break; + case 0b100: // 3'b100: chr_bank_g[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_g, "7:0", V, "7:0"); break; + case 0b101: // 3'b101: chr_bank_h[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_h, "7:0", V, "7:0"); break; + case 0b110: // 3'b110: if (!ENABLE_MAPPER_189 | ~flags[1]) prg_bank_a[(MMC3_BITSIZE-1):0] = cpu_data_in[(MMC3_BITSIZE-1):0]; + if (!(flags & 2)) + SET_BITS(prg_bank_a, "7:0", V, "7:0"); + break; + case 0b111: // 3'b111: if (!ENABLE_MAPPER_189 | ~flags[1]) prg_bank_b[(MMC3_BITSIZE-1):0] = cpu_data_in[(MMC3_BITSIZE-1):0]; + if (!(flags & 2)) + SET_BITS(prg_bank_b, "7:0", V, "7:0"); + break; + } + break; + case 0b010: // $A000-$BFFE, even (mirroring) + // if (!ENABLE_MAPPER_206 | ~flags[2]) // disabled for mapper #206 + if (!(flags & 4)) + mirroring = V & 1; // mirroring = {1'b0, cpu_data_in[0]}; + break; + case 0b011: // RAM protect... no + break; + case 0b100: // 3'b100: mmc3_irq_latch = cpu_data_in; // $C000-$DFFE, even (IRQ latch) + mmc3_irq_latch = V; break; + case 0b101: // 3'b101: mmc3_irq_reload = 1; // $C001-$DFFF, odd + mmc3_irq_reload = 1; break; + case 0b110: // 3'b110: mmc3_irq_enabled = 0; // $E000-$FFFE, even + X6502_IRQEnd(FCEU_IQEXT); + mmc3_irq_enabled = 0; + break; + case 0b111: // $E001-$FFFF, odd + if (!(flags & 4)) // if (!USE_MAPPER_206 | ~flags[2]) // disabled for mapper #206 + mmc3_irq_enabled = 1; // mmc3_irq_enabled = 1; + break; + } + } + + // Mapper #112 + /* + r0[2:0] - internal register + */ + if (mapper == 0b010101) + { + switch (get_bits(A, "14:13")) + { + case 0b00: // $8000-$9FFF + SET_BITS(mapper112_internal, "2:0", V, "2:0"); // mapper112_internal[2:0] = cpu_data_in[2:0]; + break; + case 0b01: // $A000-BFFF + switch (get_bits(mapper112_internal, "2:0")) + { + case 0b000: // 3'b000: prg_bank_a[5:0] = cpu_data_in[5:0]; + SET_BITS(prg_bank_a, "5:0", V, "5:0"); break; + case 0b001: // 3'b001: prg_bank_b[5:0] = cpu_data_in[5:0]; + SET_BITS(prg_bank_b, "5:0", V, "5:0"); break; + case 0b010: // 3'b010: chr_bank_a[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_a, "7:0", V, "7:0"); break; + case 0b011: // 3'b011: chr_bank_c[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_c, "7:0", V, "7:0"); break; + case 0b100: // 3'b100: chr_bank_e[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_e, "7:0", V, "7:0"); break; + case 0b101: // 3'b101: chr_bank_f[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_f, "7:0", V, "7:0"); break; + case 0b110: // 3'b110: chr_bank_g[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_g, "7:0", V, "7:0"); break; + case 0b111: // 3'b111: chr_bank_h[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_h, "7:0", V, "7:0"); break; + } + break; + case 0b10: // $C000-$DFFF + break; + case 0b11: // 2'b11: mirroring = {1'b0, cpu_data_in[0]}; // $E000-$FFFF + mirroring = V & 1; break; + } + } + + // Mappers #33 + #48 - Taito + // flag0=0 - #33, flag0=1 - #48 + if (mapper == 0b010110) + { + // case ({cpu_addr_in[14:13], cpu_addr_in[1:0]}) + switch (get_bits(A, "14:13,1:0")) + { + case 0b0000: + SET_BITS(prg_bank_a, "5:0", V, "5:0"); // prg_bank_a[5:0] = cpu_data_in[5:0]; // $8000, PRG Reg 0 (8k @ $8000) + if (!(flags & 1)) // if (~flags[0]) // 33 + mirroring = get_bits(V, "6"); // mirroring = {1'b0, cpu_data_in[6]}; + break; + case 0b0001: // 4'b0001: prg_bank_b[5:0] = cpu_data_in[5:0]; // $8001, PRG Reg 1 (8k @ $A000) + SET_BITS(prg_bank_b, "5:0", V, "5:0"); break; + case 0b0010: // 4'b0010: chr_bank_a[7:1] = cpu_data_in[6:0]; // $8002, CHR Reg 0 (2k @ $0000) + SET_BITS(chr_bank_a, "7:1", V, "6:0"); break; + case 0b0011: // 4'b0011: chr_bank_c[7:1] = cpu_data_in[6:0]; // $8003, CHR Reg 1 (2k @ $0800) + SET_BITS(chr_bank_c, "7:1", V, "6:0"); break; + case 0b0100: // 4'b0100: chr_bank_e[7:0] = cpu_data_in[7:0]; // $A000, CHR Reg 2 (1k @ $1000) + SET_BITS(chr_bank_e, "7:0", V, "7:0"); break; + case 0b0101: // 4'b0101: chr_bank_f[7:0] = cpu_data_in[7:0]; // $A001, CHR Reg 2 (1k @ $1400) + SET_BITS(chr_bank_f, "7:0", V, "7:0"); break; + case 0b0110: // 4'b0110: chr_bank_g[7:0] = cpu_data_in[7:0]; // $A002, CHR Reg 2 (1k @ $1800) + SET_BITS(chr_bank_g, "7:0", V, "7:0"); break; + case 0b0111: // 4'b0111: chr_bank_h[7:0] = cpu_data_in[7:0]; // $A003, CHR Reg 2 (1k @ $1C00) + SET_BITS(chr_bank_h, "7:0", V, "7:0"); break; + case 0b1100: // 4'b1100: if (flags[0]) mirroring = {1'b0, cpu_data_in[6]}; // $E000, mirroring, for mapper #48 + if (flags & 1) // 48 + mirroring = get_bits(V, "6"); // mirroring = cpu_data_in[6]; + case 0b1000: // 4'b1000: irq_scanline_latch = ~cpu_data_in; // $C000, IRQ latch + mmc3_irq_latch = set_bits(mmc3_irq_latch, "7:0", get_bits(V, "7:0") ^ 0b11111111); + break; + case 0b1001: // 4'b1001: mmc3_irq_reload = 1; // $C001, IRQ reload + mmc3_irq_reload = 1; break; + case 0b1010: // 4'b1010: mmc3_irq_enabled = 1; // $C002, IRQ enable + mmc3_irq_enabled = 1; break; + case 0b1011: // 4'b1011: mmc3_irq_enabled = 0; // $C003, IRQ disable & ack + mmc3_irq_enabled = 0; + X6502_IRQEnd(FCEU_IQEXT); // irq_cpu_out = 0; // ack + break; + } + } + + // Mapper #42 + if (mapper == 0b010111) + { + // case ({cpu_addr_in[14], cpu_addr_in[1:0]}) + switch (get_bits(A, "14,1:0")) + { + case 0: // 3'b000: chr_bank_a[7:3] = cpu_data_in[4:0]; // $8000, CHR Reg (8k @ $8000) + SET_BITS(chr_bank_a, "7:3", V, "4:0"); + break; + case 4: // 3'b100: prg_bank_6000[3:0] = cpu_data_in[3:0]; // $E000, PRG Reg (8k @ $6000) + SET_BITS(prg_bank_6000, "3:0", V, "3:0"); + break; + case 5: // 3'b101: mirroring = {1'b0, cpu_data_in[3]}; // Mirroring + mirroring = get_bits(V, "3"); + break; + case 6: // 3'b110: ... // IRQ + mapper42_irq_enabled = get_bits(V, "1"); // mapper42_irq_enabled = cpu_data_in[1]; + if (!mapper42_irq_enabled) // if (!mapper42_irq_enabled) + { + X6502_IRQEnd(FCEU_IQEXT); // irq_cpu_out = 0; + mapper42_irq_value = 0; // mapper42_irq_value = 0; + } + break; + } + } + + // Mapper #23 - VRC2/4 + /* + flag0 - switches A0 and A1 lines. 0=A0,A1 like VRC2b (mapper #23), 1=A1,A0 like VRC2a(#22), VRC2c(#25) + flag1 - divides CHR bank select by two (mapper #22, VRC2a) + */ + if (mapper == 0b011000) + { + uint8 vrc_2b_hi = + (flags & 5) == 0 ? // (!flags[0] && !flags[2]) ? + (get_bits(A, "7") | get_bits(A, "2")) // | cpu_addr_in[7] | cpu_addr_in[2]) // mapper #21 + : (flags & 5) == 1 ? //: (flags[0] && !flags[2]) ? + get_bits(A, "0") // (cpu_addr_in[0]) // mapper #22 + : (flags & 5) == 4 ? // : (!flags[0] && flags[2]) ? + (get_bits(A, "5") | get_bits(A, "3") | get_bits(A, "1")) // (cpu_addr_in[5] | cpu_addr_in[3] | cpu_addr_in[1]) // mapper #23 + : (get_bits(A, "2") | get_bits(A, "0")); // : (cpu_addr_in[2] | cpu_addr_in[0]); // mapper #25 + uint8 vrc_2b_low = + (flags & 5) == 0 ? // (!flags[0] && !flags[2]) ? + (get_bits(A, "6") | get_bits(A, "1")) // (cpu_addr_in[6] | cpu_addr_in[1]) // mapper #21 + : (flags & 5) == 1 ? // : (flags[0] && !flags[2]) ? + get_bits(A, "1") // (cpu_addr_in[1]) // mapper #22 + : (flags & 5) == 4 ?// : (!flags[0] && flags[2]) ? + (get_bits(A, "4") | get_bits(A, "2") | get_bits(A, "0")) // (cpu_addr_in[4] | cpu_addr_in[2] | cpu_addr_in[0]) // mapper #23 + : (get_bits(A, "3") | get_bits(A, "1")); // : (cpu_addr_in[3] | cpu_addr_in[1]); // mapper #25 + + // case ({ cpu_addr_in[14:12], vrc_2b_hi, vrc_2b_low }) + switch ((get_bits(A, "14:12") << 2) | (vrc_2b_hi << 1) | vrc_2b_low) + { + case 0b00000: // $8000-$8003, PRG0 + case 0b00001: + case 0b00010: + case 0b00011: + SET_BITS(prg_bank_a, "4:0", V, "4:0"); // prg_bank_a[4:0] = cpu_data_in[4:0]; + break; + case 0b00100: // $9000-$9001, mirroring + case 0b00101: + // VRC2 - using games are usually well - behaved and only write 0 or 1 to this register, + // but Wai Wai World in one instance writes $FF instead + if (V != 0b11111111) // if (cpu_data_in != 8'b11111111) mirroring = cpu_data_in[1:0]; // $9000-$9001, mirroring + SET_BITS(mirroring, "1:0", V, "1:0"); + break; + case 0b00110: // $9002-$9004, PRG swap + case 0b00111: + SET_BITS(prg_mode, "0", V, "1"); // prg_mode[0] = cpu_data_in[1]; + break; + case 0b01000: // $A000-$A003, PRG1 + case 0b01001: + case 0b01010: + case 0b01011: + SET_BITS(prg_bank_b, "4:0", V, "4:0"); // prg_bank_b[4:0] = cpu_data_in[4:0]; + break; + case 0b01100: // 5'b01100: chr_bank_a[3:0] = cpu_data_in[3:0]; // $B000, CHR0 low + SET_BITS(chr_bank_a, "3:0", V, "3:0"); break; + case 0b01101: // 5'b01101: chr_bank_a[7:4] = cpu_data_in[3:0]; // $B001, CHR0 hi + SET_BITS(chr_bank_a, "7:4", V, "3:0"); break; + case 0b01110: // 5'b01110: chr_bank_b[3:0] = cpu_data_in[3:0]; // $B002, CHR1 low + SET_BITS(chr_bank_b, "3:0", V, "3:0"); break; + case 0b01111: // 5'b01111: chr_bank_b[7:4] = cpu_data_in[3:0]; // $B003, CHR1 hi + SET_BITS(chr_bank_b, "7:4", V, "3:0"); break; + case 0b10000: // 5'b10000: chr_bank_c[3:0] = cpu_data_in[3:0]; // $C000, CHR2 low + SET_BITS(chr_bank_c, "3:0", V, "3:0"); break; + case 0b10001: // 5'b10001: chr_bank_c[7:4] = cpu_data_in[3:0]; // $C001, CHR2 hi + SET_BITS(chr_bank_c, "7:4", V, "3:0"); break; + case 0b10010: // 5'b10010: chr_bank_d[3:0] = cpu_data_in[3:0]; // $C002, CHR3 low + SET_BITS(chr_bank_d, "3:0", V, "3:0"); break; + case 0b10011: // 5'b10011: chr_bank_d[7:4] = cpu_data_in[3:0]; // $C003, CHR3 hi + SET_BITS(chr_bank_d, "7:4", V, "3:0"); break; + case 0b10100: // 5'b10100: chr_bank_e[3:0] = cpu_data_in[3:0]; // $D000, CHR4 low + SET_BITS(chr_bank_e, "3:0", V, "3:0"); break; + case 0b10101: // 5'b10101: chr_bank_e[7:4] = cpu_data_in[3:0]; // $D001, CHR4 hi + SET_BITS(chr_bank_e, "7:4", V, "3:0"); break; + case 0b10110: // 5'b10110: chr_bank_f[3:0] = cpu_data_in[3:0]; // $D002, CHR5 low + SET_BITS(chr_bank_f, "3:0", V, "3:0"); break; + case 0b10111: // 5'b10111: chr_bank_f[7:4] = cpu_data_in[3:0]; // $D003, CHR5 hi + SET_BITS(chr_bank_f, "7:4", V, "3:0"); break; + case 0b11000: // 5'b11000: chr_bank_g[3:0] = cpu_data_in[3:0]; // $E000, CHR6 low + SET_BITS(chr_bank_g, "3:0", V, "3:0"); break; + case 0b11001: // 5'b11001: chr_bank_g[7:4] = cpu_data_in[3:0]; // $E001, CHR6 hi + SET_BITS(chr_bank_g, "7:4", V, "3:0"); break; + case 0b11010: // 5'b11010: chr_bank_h[3:0] = cpu_data_in[3:0]; // $E002, CHR7 low + SET_BITS(chr_bank_h, "3:0", V, "3:0"); break; + case 0b11011: // 5'b11011: chr_bank_h[7:4] = cpu_data_in[3:0]; // $E003, CHR7 hi + SET_BITS(chr_bank_h, "7:4", V, "3:0"); break; + } + + // if (cpu_addr_in[14:12] == 3'b111) + if (get_bits(A, "14:12") == 0b111) + { + // case (vrc_2b_hi, vrc_2b_low}) + switch ((vrc_2b_hi << 1) | vrc_2b_low) + { + case 0b00: // 2'b00: vrc4_irq_latch[3:0] = cpu_data_in[3:0]; // IRQ latch low + SET_BITS(vrc4_irq_latch, "3:0", V, "3:0"); break; + case 0b01: // 2'b01: vrc4_irq_latch[7:4] = cpu_data_in[3:0]; // IRQ latch hi + SET_BITS(vrc4_irq_latch, "7:4", V, "3:0"); break; + case 0b10: // 2'b10 // IRQ control + X6502_IRQEnd(FCEU_IQEXT); // vrc4_irq_out = 0; // ack + SET_BITS(vrc4_irq_control, "2:0", V, "2:0"); // vrc4_irq_control[2:0] = cpu_data_in[2:0]; // mode, enabled, enabled after ack + if (vrc4_irq_control & 2) // if (vrc4_irq_control[1]) begin // if E is set + { + vrc4_irq_prescaler_counter = 0; // vrc4_irq_prescaler_counter[1:0] = 2'b00; // reset prescaler + vrc4_irq_prescaler = 0; // vrc4_irq_prescaler[6:0] = 7'b0000000; + SET_BITS(vrc4_irq_value, "7:0", vrc4_irq_latch, "7:0"); // vrc4_irq_value[7:0] = vrc4_irq_latch[7:0]; // reload with latch + } + break; + case 0b11: // 2'b11 // IRQ ack + X6502_IRQEnd(FCEU_IQEXT); // vrc4_irq_out = 0; + SET_BITS(vrc4_irq_control, "1", vrc4_irq_control, "0"); // vrc4_irq_control[1] = vrc4_irq_control[0]; + break; + } + } + } + + // Mapper #69 - Sunsoft FME-7 + if (mapper == 0b011001) + { + // if (cpu_addr_in[14:13] == 2'b00) mapper69_internal[3:0] = cpu_data_in[3:0]; + if (get_bits(A, "14:13") == 0b00) SET_BITS(mapper69_internal, "3:0", V, "3:0"); + // if (cpu_addr_in[14:13] == 2'b01) + if (get_bits(A, "14:13") == 0b01) + { + switch (get_bits(mapper69_internal, "3:0")) // case (mapper69_internal[3:0]) + { + case 0b0000: // 4'b0000: chr_bank_a[7:0] = cpu_data_in[7:0]; // CHR0 + SET_BITS(chr_bank_a, "7:0", V, "7:0"); break; + case 0b0001: // 4'b0001: chr_bank_b[7:0] = cpu_data_in[7:0]; // CHR1 + SET_BITS(chr_bank_b, "7:0", V, "7:0"); break; + case 0b0010: // 4'b0010: chr_bank_c[7:0] = cpu_data_in[7:0]; // CHR2 + SET_BITS(chr_bank_c, "7:0", V, "7:0"); break; + case 0b0011: // 4'b0011: chr_bank_d[7:0] = cpu_data_in[7:0]; // CHR3 + SET_BITS(chr_bank_d, "7:0", V, "7:0"); break; + case 0b0100: // 4'b0100: chr_bank_e[7:0] = cpu_data_in[7:0]; // CHR4 + SET_BITS(chr_bank_e, "7:0", V, "7:0"); break; + case 0b0101: // 4'b0101: chr_bank_f[7:0] = cpu_data_in[7:0]; // CHR5 + SET_BITS(chr_bank_f, "7:0", V, "7:0"); break; + case 0b0110: // 4'b0110: chr_bank_g[7:0] = cpu_data_in[7:0]; // CHR6 + SET_BITS(chr_bank_g, "7:0", V, "7:0"); break; + case 0b0111: // 4'b0111: chr_bank_h[7:0] = cpu_data_in[7:0]; // CHR7 + SET_BITS(chr_bank_h, "7:0", V, "7:0"); break; + case 0b1000: // 4'b1000: {sram_enabled, map_rom_on_6000, prg_bank_6000} = {cpu_data_in[7], ~cpu_data_in[6], cpu_data_in[5:0]}; // PRG0 + sram_enabled = (V >> 7) & 1; + map_rom_on_6000 = ((V >> 6) & 1) ^ 1; + prg_bank_6000 = V & 0x3F; + break; + case 0b1001: // 4'b1001: prg_bank_a[5:0] = cpu_data_in[5:0]; // PRG1 + SET_BITS(prg_bank_a, "5:0", V, "5:0"); break; + case 0b1010: // 4'b1010: prg_bank_b[5:0] = cpu_data_in[5:0]; // PRG2 + SET_BITS(prg_bank_b, "5:0", V, "5:0"); break; + case 0b1011: // 4'b1011: prg_bank_c[5:0] = cpu_data_in[5:0]; // PRG3 + SET_BITS(prg_bank_c, "5:0", V, "5:0"); break; + case 0b1100: // 4'b1100: mirroring[1:0] = cpu_data_in[1:0]; // mirroring + SET_BITS(mirroring, "1:0", V, "1:0"); break; + case 0b1101: // 4'b1101 + X6502_IRQEnd(FCEU_IQEXT); // fme7_irq_out = 0; // ack + mapper69_counter_enabled = get_bits(V, "7"); // fme7_counter_enabled = cpu_data_in[7]; + mapper69_irq_enabled = get_bits(V, "0"); // fme7_irq_enabled = cpu_data_in[0]; + break; + case 0b1110: // 4'b1110: fme7_irq_value[7:0] = cpu_data_in[7:0]; // IRQ low + SET_BITS(mapper69_irq_value, "7:0", V, "7:0"); break; + case 0b1111: // fme7_irq_value[15:8] = cpu_data_in[7:0]; // IRQ high + SET_BITS(mapper69_irq_value, "15:8", V, "7:0"); break; + } + } + } + + // Mapper #32 - Irem's G-101 + if (mapper == 0b011010) + { + switch (get_bits(A, "14:12")) + { + case 0b000: // 2'b00: prg_bank_a[5:0] = cpu_data_in[5:0]; // $8000-$8FFF, PRG0 + SET_BITS(prg_bank_a, "5:0", V, "5:0"); + break; + case 0b001: // 2'b01: {prg_mode[0], mirroring} = {cpu_data_in[1], 1'b0, cpu_data_in[0]}; // $9000-$9FFF, PRG mode, mirroring + SET_BITS(prg_mode, "0", V, "1"); + mirroring = V & 1; + break; + case 0b010: // 2'b10: prg_bank_b[5:0] = cpu_data_in[5:0]; // $A000-$AFFF, PRG1 + SET_BITS(prg_bank_b, "5:0", V, "5:0"); + break; + case 0b011: // $B000-$BFFF, CHR regs + switch (get_bits(A, "2:0")) + { + case 0b000: // 3'b000: chr_bank_a[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_a, "7:0", V, "7:0"); break; + case 0b001: // 3'b001: chr_bank_b[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_b, "7:0", V, "7:0"); break; + case 0b010: // 3'b010: chr_bank_c[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_c, "7:0", V, "7:0"); break; + case 0b011: // 3'b011: chr_bank_d[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_d, "7:0", V, "7:0"); break; + case 0b100: // 3'b100: chr_bank_e[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_e, "7:0", V, "7:0"); break; + case 0b101: // 3'b101: chr_bank_f[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_f, "7:0", V, "7:0"); break; + case 0b110: // 3'b110: chr_bank_g[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_g, "7:0", V, "7:0"); break; + case 0b111: // 3'b111: chr_bank_h[7:0] = cpu_data_in[7:0]; + SET_BITS(chr_bank_h, "7:0", V, "7:0"); break; + } + break; + } + } + + // Mapper #36 is assigned to TXC's PCB 01-22000-400 + if (mapper == 0b011101) + { + if (get_bits(A, "14:1") != 0b11111111111111) // (cpu_addr_in[14:1] != 14'b11111111111111) + { + // prg_bank_a[5:2] = cpu_data_in[7:4]; + SET_BITS(prg_bank_a, "5:2", V, "7:4"); + // chr_bank_a[6:3] = cpu_data_in[3:0]; + SET_BITS(chr_bank_a, "6:3", V, "3:0"); + } + } + + // Mapper #70 + if (mapper == 0b011110) + { + // prg_bank_a[4:1] = cpu_data_in[7:4]; + SET_BITS(prg_bank_a, "4:1", V, "7:4"); + // chr_bank_a[6:3] = cpu_data_in[3:0]; + SET_BITS(chr_bank_a, "6:3", V, "3:0"); + } + + // Mapper #75 - VRC1 + if (mapper == 0b100010) + { + // case (cpu_addr_in[14:12]) + switch (get_bits(A, "14:12")) + { + case 0b000: // 3'b000: prg_bank_a[3:0] = cpu_data_in[3:0]; // $8000-$8FFF + SET_BITS(prg_bank_a, "3:0", V, "3:0"); break; + case 0b001: + mirroring = V & 1; // mirroring = {1'b0, cpu_data_in[0]}; + SET_BITS(chr_bank_a, "6", V, "1"); // chr_bank_a[6] = cpu_data_in[1]; + SET_BITS(chr_bank_e, "6", V, "2"); // chr_bank_e[6] = cpu_data_in[2]; + break; + case 0b010: // 3'b010: prg_bank_b[3:0] = cpu_data_in[3:0]; // $A000-$AFFF + SET_BITS(prg_bank_b, "3:0", V, "3:0"); break; + case 0b100: // 3'b100: prg_bank_c[3:0] = cpu_data_in[3:0]; // $C000-$CFFF + SET_BITS(prg_bank_c, "3:0", V, "3:0"); break; + case 0b110: // 3'b110: �hr_bank_a[5:2] = cpu_data_in[3:0]; // $E000-$EFFF + SET_BITS(chr_bank_a, "5:2", V, "3:0"); break; + case 0b111: // 3'b111: chr_bank_e[5:2] = cpu_data_in[3:0]; // $F000-$FFFF + SET_BITS(chr_bank_e, "5:2", V, "3:0"); break; + } + } + + // Mapper #83 - Cony/Yoko + if (mapper == 0b100011) + { + // case (cpu_addr_in[9:8]) + switch (get_bits(A, "9:8")) + { + case 0b01: // $81xx + mirroring = get_bits(V, "1:0"); // mirroring <= cpu_data_in[1:0]; + mapper83_irq_enabled_latch = get_bits(V, "7"); // mapper83_irq_enabled_latch <= cpu_data_in[7]; + break; + case 0b10: // 82xx + if (!get_bits(A, "0")) // if (!cpu_addr_in[0]) + { + X6502_IRQEnd(FCEU_IQEXT); // mapper83_irq_out <= 0; + SET_BITS(mapper83_irq_counter, "7:0", V, "7:0"); // mapper83_irq_counter[7:0] <= cpu_data_in[7:0]; + } + else { + mapper83_irq_enabled = mapper83_irq_enabled_latch; //mapper83_irq_enabled <= mapper83_irq_enabled_latch; + SET_BITS(mapper83_irq_counter, "15:8", V, "7:0"); // mapper83_irq_counter[15:8] <= cpu_data_in[7:0]; + } + break; + case 0b11: + if (!get_bits(A, "4")) // if (!cpu_addr_in[4]) + { + switch (get_bits(A, "1:0")) // case (cpu_addr_in[1:0]) + { + case 0b00: SET_BITS(prg_bank_a, "7:0", V, "7:0"); break; // 2'b00: prg_bank_a[7:0] <= cpu_data_in[7:0]; + case 0b01: SET_BITS(prg_bank_b, "7:0", V, "7:0"); break; // 2'b01: prg_bank_b[7:0] <= cpu_data_in[7:0]; + case 0b10: SET_BITS(prg_bank_b, "7:0", V, "7:0"); break; // 2'b10: prg_bank_c[7:0] <= cpu_data_in[7:0]; + //case 0b11: SET_BITS(prg_bank_6000, "7:0", V, "7:0"); break; //2'b11: prg_bank_6000[7:0] <= cpu_data_in[7:0]; + } + } + else { + switch (get_bits(A, "2:0")) // case (cpu_addr_in[2:0]) + { + case 0b000: SET_BITS(chr_bank_a, "7:0", V, "7:0"); break; // 3'b000: chr_bank_a[7:0] <= cpu_data_in[7:0]; + case 0b001: SET_BITS(chr_bank_b, "7:0", V, "7:0"); break; // 3'b001: chr_bank_b[7:0] <= cpu_data_in[7:0]; + case 0b010: SET_BITS(chr_bank_c, "7:0", V, "7:0"); break; // 3'b010: chr_bank_c[7:0] <= cpu_data_in[7:0]; + case 0b011: SET_BITS(chr_bank_d, "7:0", V, "7:0"); break; // 3'b011: chr_bank_d[7:0] <= cpu_data_in[7:0]; + case 0b100: SET_BITS(chr_bank_e, "7:0", V, "7:0"); break; // 3'b100: chr_bank_e[7:0] <= cpu_data_in[7:0]; + case 0b101: SET_BITS(chr_bank_f, "7:0", V, "7:0"); break; // 3'b101: chr_bank_f[7:0] <= cpu_data_in[7:0]; + case 0b110: SET_BITS(chr_bank_g, "7:0", V, "7:0"); break; // 3'b110: chr_bank_g[7:0] <= cpu_data_in[7:0]; + case 0b111: SET_BITS(chr_bank_h, "7:0", V, "7:0"); break; // 3'b111: chr_bank_h[7:0] <= cpu_data_in[7:0]; + } + } + break; + } + } + + // Mapper #67 - Sunsoft-3 + if (mapper == 0b100100) + { + if (get_bits(A, "11")) // if (cpu_addr_in[11]) + { + switch (get_bits(A, "14:12")) // case (cpu_addr_in[14:12]) + { + case 0b000: // 3'b000: chr_bank_a[6:1] <= cpu_data_in[5:0]; // $8800 + SET_BITS(chr_bank_a, "6:1", V, "5:0"); break; + case 0b001: // 3'b001: chr_bank_c[6:1] <= cpu_data_in[5:0]; // $9800 + SET_BITS(chr_bank_c, "6:1", V, "5:0"); break; + case 0b010: // 3'b010: chr_bank_e[6:1] <= cpu_data_in[5:0]; // $A800 + SET_BITS(chr_bank_e, "6:1", V, "5:0"); break; + case 0b011: // 3'b011: chr_bank_g[6:1] <= cpu_data_in[5:0]; // $B800 + SET_BITS(chr_bank_g, "6:1", V, "5:0"); break; + case 0b100: // 3'b100: begin // $C800, IRQ load + mapper67_irq_latch = ~mapper67_irq_latch; + if (mapper67_irq_latch) + SET_BITS(mapper67_irq_counter, "15:8", V, "7:0"); // mapper67_irq_counter[15:8] <= cpu_data_in[7:0]; + else + SET_BITS(mapper67_irq_counter, "7:0", V, "7:0"); // mapper67_irq_counter[7:0] <= cpu_data_in[7:0]; + break; + case 0b101: // 3'b101: begin // $D800, IRQ enable + mapper67_irq_latch = 0; // mapper67_irq_latch <= 0; + SET_BITS(mapper67_irq_enabled, "0", V, "4"); // mapper67_irq_enabled <= cpu_data_in[4]; + break; + case 0b110: // 3'b110: mirroring[1:0] <= cpu_data_in[1:0]; // $E800 + SET_BITS(mirroring, "1:0", V, "1:0"); + break; + case 0b111: // 3'b111: prg_bank_a[4:1] <= cpu_data_in[3:0]; // $F800 + SET_BITS(prg_bank_a, "4:1", V, "3:0"); + break; + } + } + else { + // Interrupt Acknowledge ($8000) + X6502_IRQEnd(FCEU_IQEXT); // mapper67_irq_out <= 0; + } + } + + // Mapper #89 - Sunsoft-2 chip on the Sunsoft-3 board + if (mapper == 0b100101) + { + // prg_bank_a[3:1] <= cpu_data_in[6:4]; + SET_BITS(prg_bank_a, "3:1", V, "6:4"); + // chr_bank_a[6:3] <= {cpu_data_in[7], cpu_data_in[2:0]}; + SET_BITS(chr_bank_a, "6:3", V, "7,2:0"); + // mirroring[1:0] <= {1'b1, cpu_data_in[3]}; + SET_BITS(mirroring, "1", 1, "0"); + SET_BITS(mirroring, "0", V, "3"); + } + } + + COOLGIRL_Sync(); +} + +static DECLFR(MAFRAM) { + if ((mapper == 0b000000) && (A >= 0x5000) && (A < 0x6000)) + return 0; + + // Mapper #163 + // (USE_MAPPER_163 && (mapper == 5'b00110) && m2 && romsel && cpu_rw_in && ((cpu_addr_in[14:8] & 7'h77) == 7'h51)) ? + if ((mapper == 0b000110) && ((A & 0x7700) == 0x5100)) + return mapper163_r2 | mapper163_r0 | mapper163_r1 | ~mapper163_r3; // {1'b1, r2 | r0 | r1 | ~r3} + // (USE_MAPPER_163 && (mapper == 5'b00110) && m2 && romsel && cpu_rw_in && ((cpu_addr_in[14:8] & 7'h77) == 7'h55)) ? + if ((mapper == 0b000110) && ((A & 0x7700) == 0x5500)) + return (mapper163_r5 & 1) ? mapper163_r2 : mapper163_r1; // {1'b1, r5[0] ? r2 : r1} + + // MMC5 + if ((mapper == 0b001111) && (A == 0x5204)) + { + int ppuon = (PPU[1] & 0x18); + uint8 r = (!ppuon || scanline + 1 >= 241) ? 0 : 1; + uint8 p = mmc5_irq_out; + X6502_IRQEnd(FCEU_IQEXT); + mmc5_irq_out = 0; + return (p << 7) | (r << 6); + } + + // Mapper #36 is assigned to TXC's PCB 01-22000-400 + if ((mapper == 0b011101) && ((A & 0xE100) == 0x4100)) // (USE_MAPPER_036 && mapper == 5'b11101 && {cpu_addr_in[14:13], cpu_addr_in[8]} == 3'b101) ? + { + return (prg_bank_a & 0x0C) << 2; // {1'b1, 2'b00, prg_bank_a[3:2], 4'b00} + } + + // Mapper #83 - Cony/Yoko + if ((mapper == 0b100011) && ((A & 0x7000) == 0x5000)) return flags & 3; + + // Mapper #90 - JY + if ((mapper == 0b001101) && (A == 0x5800)) return (mul1 * mul2) & 0xFF; + if ((mapper == 0b001101) && (A == 0x5801)) return ((mul1 * mul2) >> 8) & 0xFF; + + if (sram_enabled && !map_rom_on_6000 && (A >= 0x6000) && (A < 0x8000)) + return CartBR(A); // SRAM + if (map_rom_on_6000 && (A >= 0x6000) && (A < 0x8000)) + return CartBR(A); // PRG + + return X.DB; // Open bus +} + +static void COOLGIRL_ScanlineCounter(void) { + // for MMC3 and MMC3-based + if (mmc3_irq_reload || !mmc3_irq_counter) + { + mmc3_irq_counter = mmc3_irq_latch; + mmc3_irq_reload = 0; + } + else + mmc3_irq_counter--; + if (!mmc3_irq_counter && mmc3_irq_enabled) + X6502_IRQBegin(FCEU_IQEXT); + + // for MMC5 + if (mmc5_irq_line == scanline + 1) + { + if (mmc5_irq_enabled) + { + X6502_IRQBegin(FCEU_IQEXT); + mmc5_irq_out = 1; + } + } + + // for mapper #163 + if (scanline == 239) + { + mapper_163_latch = 0; + COOLGIRL_Sync_CHR(); + } + else if (scanline == 127) + { + mapper_163_latch = 1; + COOLGIRL_Sync_CHR(); + } +} + +static void COOLGIRL_CpuCounter(int a) { + while (a--) + { + // Mapper #23 - VRC4 + if (vrc4_irq_control & 2) // if (ENABLE_MAPPER_021_022_023_025 & ENABLE_VRC4_INTERRUPTS & (vrc4_irq_control[1])) + { + // Cycle mode without prescaler is not used by any games? It's missed in fceux source code. + if (vrc4_irq_control & 4) // if (vrc4_irq_control[2]) // cycle mode + { + FCEU_PrintError("Cycle IRQ mode is not supported, please report to Cluster"); + vrc4_irq_value++; // {carry, vrc4_irq_value[7:0]} = vrc4_irq_value[7:0] + 1'b1; // just count IRQ value + if (vrc4_irq_value == 0) // if (carry) + { + X6502_IRQBegin(FCEU_IQEXT); // vrc4_irq_out = 1; + vrc4_irq_value = vrc4_irq_latch; // vrc4_irq_value[7:0] = vrc4_irq_latch[7:0]; + } + } + else { + vrc4_irq_prescaler++; // vrc4_irq_prescaler = vrc4_irq_prescaler + 1'b1; // count prescaler + // if ((vrc4_irq_prescaler_counter[1] == 0 && vrc4_irq_prescaler == 114) + // || (vrc4_irq_prescaler_counter[1] == 1 && vrc4_irq_prescaler == 113)) // 114, 114, 113 + if ((!(vrc4_irq_prescaler_counter & 2) && vrc4_irq_prescaler == 114) || ((vrc4_irq_prescaler_counter & 2) && vrc4_irq_prescaler == 113)) + { + vrc4_irq_prescaler = 0; // vrc4_irq_prescaler = 0; + vrc4_irq_prescaler_counter++; // vrc4_irq_prescaler_counter = vrc4_irq_prescaler_counter + 1'b1; + if (vrc4_irq_prescaler_counter == 0b11) vrc4_irq_prescaler_counter = 0; // if (vrc4_irq_prescaler_counter == 2'b11) vrc4_irq_prescaler_counter = 2'b00; + vrc4_irq_value++; // {carry, vrc4_irq_value[7:0]} = vrc4_irq_value[7:0] + 1'b1; + if (vrc4_irq_value == 0) // f (carry) + { + X6502_IRQBegin(FCEU_IQEXT); + vrc4_irq_value = vrc4_irq_latch; // irq_cpu_value[7:0] = vrc4_irq_latch[7:0]; + } + } + } + } + + // Mapper #73 - VRC3 + if (vrc3_irq_control & 2) + { + if (vrc3_irq_control & 4) // if (vrc3_irq_control[2]) + { // 8-bit mode + //vrc3_irq_value = set_bits(vrc3_irq_value, "7:0", get_bits(vrc3_irq_value, "7:0") + 1); // vrc3_irq_value[7:0] = vrc3_irq_value[7:0] + 1'b1; + vrc3_irq_value = (vrc3_irq_value & 0xFF00) | ((vrc3_irq_value + 1) & 0xFF); + //if (get_bits(vrc3_irq_value, "7:0") == 0) // if (vrc3_irq_value[7:0] == 0) + if ((vrc3_irq_value & 0xFF) == 0) + { + X6502_IRQBegin(FCEU_IQEXT); // vrc3_irq_out = 1; + //SET_BITS(vrc3_irq_value, "7:0", vrc3_irq_latch, "7:0"); // vrc3_irq_value[7:0] = vrc3_irq_latch[7:0]; + vrc3_irq_value = (vrc3_irq_value & 0xFF00) | (vrc3_irq_latch & 0xFF); + } + } + else { // 16-bit + //vrc3_irq_value = set_bits(vrc3_irq_value, "15:0", get_bits(vrc3_irq_value, "15:0") + 1); // vrc3_irq_value[15:0] = vrc3_irq_value[15:0] + 1'b1; + vrc3_irq_value += 1; + if (vrc3_irq_value == 0) // if (vrc3_irq_value[15:0] == 0) + { + X6502_IRQBegin(FCEU_IQEXT); // vrc3_irq_out = 1; + //SET_BITS(vrc3_irq_value, "15:0", vrc3_irq_latch, "15:0"); // vrc3_irq_value[15:0] = vrc3_irq_latch[15:0]; + vrc3_irq_value = vrc3_irq_latch; + } + } + } + + // Mapper #69 - Sunsoft FME-7 + // if (ENABLE_MAPPER_069 & fme7_counter_enabled) + if (mapper69_counter_enabled) + { + // {carry, fme7_irq_value[15:0]} = {0'b0, fme7_irq_value[15:0]} - 1'b1; + mapper69_irq_value--; + // if (fme7_irq_enabled && carry) fme7_irq_out = 1; + if (mapper69_irq_value == 0xFFFF) X6502_IRQBegin(FCEU_IQEXT); + } + + // Mapper #18 + if (mapper18_irq_control & 1) // if (mapper18_irq_control[0]) + { + uint8 carry; + //carry = get_bits(mapper18_irq_value, "3:0") - 1; + carry = (mapper18_irq_value & 0x0F) - 1; + //SET_BITS(mapper18_irq_value, "3:0", carry, "3:0"); + mapper18_irq_value = (mapper18_irq_value & 0xFFF0) | (carry & 0x0F); + carry = (carry >> 4) & 1; + // if (mapper18_irq_control[3] == 1'b0) + if (!(mapper18_irq_control & 0b1000)) + { + //carry = get_bits(mapper18_irq_value, "7:4") - carry; + carry = ((mapper18_irq_value >> 4) & 0x0F) - carry; + //SET_BITS(mapper18_irq_value, "7:4", carry, "3:0"); + mapper18_irq_value = (mapper18_irq_value & 0xFF0F) | ((carry & 0x0F) << 4); + carry = (carry >> 4) & 1; + } + // if (mapper18_irq_control[3:2] == 2'b00) + if (!(mapper18_irq_control & 0b1100)) + { + //carry = get_bits(mapper18_irq_value, "11:8") - carry; + carry = ((mapper18_irq_value >> 8) & 0x0F) - carry; + //SET_BITS(mapper18_irq_value, "11:8", carry, "3:0"); + mapper18_irq_value = (mapper18_irq_value & 0xF0FF) | ((carry & 0x0F) << 8); + carry = (carry >> 4) & 1; + } + // if (mapper18_irq_control[3:1] == 3'b000) + if (!(mapper18_irq_control & 0b1110)) + { + //carry = get_bits(mapper18_irq_value, "15:12") - carry; + carry = ((mapper18_irq_value >> 12) & 0x0F) - carry; + //SET_BITS(mapper18_irq_value, "15:12", carry, "3:0"); + mapper18_irq_value = (mapper18_irq_value & 0x0FFF) | ((carry & 0x0F) << 12); + carry = (carry >> 4) & 1; + } + if (carry) + X6502_IRQBegin(FCEU_IQEXT); + } + + // Mapper #65 - Irem's H3001 + // if (mapper65_irq_enabled) + if (mapper65_irq_enabled) + { + if (mapper65_irq_value != 0) // if (mapper65_irq_value[15:0] != 0) + { + mapper65_irq_value--; // mapper65_irq_value[15:0] = mapper65_irq_value[15:0] - 1; + if (!mapper65_irq_value) + X6502_IRQBegin(FCEU_IQEXT); // if (mapper65_irq_value[15:0] == 0) irq_cpu_out = 1; + } + } + + // Mapper #42 + if (mapper42_irq_enabled) + { + //mapper42_irq_value = set_bits(mapper42_irq_value, "14:0", get_bits(mapper42_irq_value, "14:0") + 1); + //if (get_bits(mapper42_irq_value, "14:13") == 0b11) + mapper42_irq_value++; + if (mapper42_irq_value >> 15) mapper42_irq_value = 0; + if (((mapper42_irq_value >> 13) & 0b11) == 0b11) + X6502_IRQBegin(FCEU_IQEXT); + else + X6502_IRQEnd(FCEU_IQEXT); + } + + // Mapper #83 - Cony/Yoko + if (mapper83_irq_enabled) + { + if (mapper83_irq_counter == 0) // if (mapper83_irq_counter == 0) + X6502_IRQBegin(FCEU_IQEXT); // mapper83_irq_out <= 1; + mapper83_irq_counter--; // mapper83_irq_counter = mapper83_irq_counter - 1'b1; + } + + // Mapper #67 - Sunsoft-3 + if (mapper67_irq_enabled) + { + mapper67_irq_counter--; // mapper67_irq_counter = mapper67_irq_counter - 1'b1; + if (mapper67_irq_counter == 0xFFFF) // if (mapper67_irq_counter == 16'hFFFF) + { + X6502_IRQBegin(FCEU_IQEXT); // mapper67_irq_out <= 1; // fire IRQ + mapper67_irq_enabled = 0; // mapper67_irq_enabled <= 0; // disable IRQ + } + } + } +} + +static void COOLGIRL_PPUHook(uint32 A) { + // For TxROM + if ((mapper == 0b010100) && (flags & 1)) + { + setmirror(MI_0 + (TKSMIR[(A & 0x1FFF) >> 10] >> 7)); + } + + // Mapper #9 and #10 - MMC2 and MMC4 + if (mapper == 0b010001) + { + if ((A >> 4) == 0xFD) // if (ppu_addr_in[13:3] == 11'b00111111011) ppu_latch0 = 0; + { + ppu_latch0 = 0; + COOLGIRL_Sync_CHR(); + } + if ((A >> 4) == 0xFE) // if (ppu_addr_in[13:3] == 11'b00111111101) ppu_latch0 = 1; + { + ppu_latch0 = 1; + COOLGIRL_Sync_CHR(); + } + if ((A >> 4) == 0x1FD) // if (ppu_addr_in[13:3] == 11'b01111111011) ppu_latch1 = 0; + { + ppu_latch1 = 0; + COOLGIRL_Sync_CHR(); + } + if ((A >> 4) == 0x1FE) // if (ppu_addr_in[13:3] == 11'b01111111101) ppu_latch1 = 1; + { + ppu_latch1 = 1; + COOLGIRL_Sync_CHR(); + } + } +} + +static void COOLGIRL_Reset(void) { + sram_enabled = 0; + sram_page = 0; + can_write_chr = 0; + map_rom_on_6000 = 0; + flags = 0; + mapper = 0; + can_write_flash = 0; + mirroring = 0; + four_screen = 0; + lockout = 0; + prg_base = 0; + prg_mask = 0b11111000 << 14; + prg_mode = 0; + prg_bank_6000 = 0; + prg_bank_a = 0; + prg_bank_b = 1; + prg_bank_c = ~1; + prg_bank_d = ~0; + chr_mask = 0; + chr_mode = 0; + chr_bank_a = 0; + chr_bank_b = 1; + chr_bank_c = 2; + chr_bank_d = 3; + chr_bank_e = 4; + chr_bank_f = 5; + chr_bank_g = 6; + chr_bank_h = 7; + ppu_latch0 = 0; + ppu_latch1 = 0; + lreset = 0; + mmc1_load_register = 0; + mmc3_internal = 0; + mapper69_internal = 0; + mapper112_internal = 0; + mapper_163_latch = 0; + mapper163_r0 = 0; + mapper163_r1 = 0; + mapper163_r2 = 0; + mapper163_r3 = 0; + mapper163_r4 = 0; + mapper163_r5 = 0; + mul1 = 0; + mul2 = 0; + mmc3_irq_enabled = 0; + mmc3_irq_latch = 0; + mmc3_irq_counter = 0; + mmc3_irq_reload = 0; + mmc5_irq_enabled = 0; + mmc5_irq_line = 0; + mmc5_irq_out = 0; + mapper18_irq_value = 0; + mapper18_irq_control = 0; + mapper18_irq_latch = 0; + mapper65_irq_enabled = 0; + mapper65_irq_value = 0; + mapper65_irq_latch = 0; + mapper69_irq_enabled = 0; + mapper69_counter_enabled = 0; + mapper69_irq_value = 0; + vrc4_irq_value = 0; + vrc4_irq_control = 0; + vrc4_irq_latch = 0; + vrc4_irq_prescaler = 0; + vrc4_irq_prescaler_counter = 0; + vrc3_irq_value = 0; + vrc3_irq_control = 0; + vrc3_irq_latch = 0; + mapper42_irq_enabled = 0; + mapper42_irq_value = 0; + mapper90_xor = 0; + flash_state = 0; + cfi_mode = 0; + COOLGIRL_Sync(); +} + +static void COOLGIRL_Power(void) { + FCEU_CheatAddRAM(32, 0x6000, WRAM); + SetReadHandler(0x4020, 0x7FFF, MAFRAM); + SetReadHandler(0x8000, 0xFFFF, CartBR); + SetWriteHandler(0x4020, 0xFFFF, COOLGIRL_WRITE); + GameHBIRQHook = COOLGIRL_ScanlineCounter; + MapIRQHook = COOLGIRL_CpuCounter; + PPU_hook = COOLGIRL_PPUHook; + COOLGIRL_Reset(); +} + +static void COOLGIRL_Close(void) { + if (CHR_RAM) + FCEU_gfree(CHR_RAM); + if (WRAM) + FCEU_gfree(WRAM); + if (SAVE_FLASH) + FCEU_gfree(SAVE_FLASH); + if (CFI) + FCEU_gfree(CFI); + CHR_RAM = WRAM = SAVE_FLASH = CFI = NULL; +} + +static void COOLGIRL_Restore(int version) { + COOLGIRL_Sync(); + lreset = 0; +} + +#define ExState(var, varname) AddExState(&var, sizeof(var), 0, varname) + +void COOLGIRL_Init(CartInfo *info) { + CHR_RAM_SIZE = info->ines2 ? (info->vram_size + info->battery_vram_size) : (512 * 1024); + CHR_RAM = (uint8*)FCEU_gmalloc(CHR_RAM_SIZE); + memset(CHR_RAM, 0, CHR_RAM_SIZE); + SetupCartCHRMapping(CHR_RAM_CHIP, CHR_RAM, CHR_RAM_SIZE, 0); + AddExState(CHR_RAM, sizeof(CHR_RAM_SIZE), 0, "CHR_"); + + WRAM_SIZE = info->ines2 ? (info->wram_size + info->battery_wram_size) : (32 * 1024); + if (WRAM_SIZE > 0) { + WRAM = (uint8*)FCEU_gmalloc(WRAM_SIZE); + memset(WRAM, 0, WRAM_SIZE); + SetupCartPRGMapping(WRAM_CHIP, WRAM, WRAM_SIZE, 1); + AddExState(WRAM, 32 * 1024, 0, "SRAM"); + if (info->battery) + { + info->SaveGame[0] = WRAM; + info->SaveGameLen[0] = 32 * 1024; + } + } + + if (info->battery) + { + SAVE_FLASH = (uint8*)FCEU_gmalloc(SAVE_FLASH_SIZE); + SetupCartPRGMapping(FLASH_CHIP, SAVE_FLASH, SAVE_FLASH_SIZE, 1); + AddExState(SAVE_FLASH, SAVE_FLASH_SIZE, 0, "SAVF"); + info->SaveGame[1] = SAVE_FLASH; + info->SaveGameLen[1] = SAVE_FLASH_SIZE; + } + + CFI = (uint8*)FCEU_gmalloc(sizeof(cfi_data) * 2); + for (int i = 0; i < sizeof(cfi_data); i++) + { + CFI[i * 2] = CFI[i * 2 + 1] = cfi_data[i]; + } + SetupCartPRGMapping(CFI_CHIP, CFI, sizeof(cfi_data) * 2, 0); + + ExState(sram_enabled, "SREN"); + ExState(sram_page, "SRPG"); + ExState(can_write_chr, "SRWR"); + ExState(map_rom_on_6000, "MR6K"); + ExState(flags, "FLGS"); + ExState(mapper, "MPPR"); + ExState(can_write_flash, "FLWR"); + ExState(mirroring, "MIRR"); + ExState(four_screen, "4SCR"); + ExState(lockout, "LOCK"); + ExState(prg_base, "PBAS"); + ExState(prg_mask, "PMSK"); + ExState(prg_mode, "PMOD"); + ExState(prg_bank_6000, "P6BN"); + ExState(prg_bank_a, "PABN"); + ExState(prg_bank_b, "PBBN"); + ExState(prg_bank_c, "PCBN"); + ExState(prg_bank_d, "PDBN"); + ExState(chr_mask, "CMSK"); + ExState(chr_mode, "CMOD"); + ExState(chr_bank_a, "CABN"); + ExState(chr_bank_b, "CBBN"); + ExState(chr_bank_c, "CCBN"); + ExState(chr_bank_d, "CDBN"); + ExState(chr_bank_e, "CEBN"); + ExState(chr_bank_f, "CFBN"); + ExState(chr_bank_g, "CGBN"); + ExState(chr_bank_h, "CHBN"); + ExState(ppu_latch0, "PPU0"); + ExState(ppu_latch1, "PPU1"); + ExState(lreset, "LRST"); + ExState(mmc1_load_register, "M01R"); + ExState(mmc3_internal, "M01I"); + ExState(mapper69_internal, "M69I"); + ExState(mapper112_internal, "112I"); + ExState(mapper_163_latch, "163L"); + ExState(mapper163_r0, "1630"); + ExState(mapper163_r1, "1631"); + ExState(mapper163_r2, "1632"); + ExState(mapper163_r3, "1633"); + ExState(mapper163_r4, "1634"); + ExState(mapper163_r5, "1635"); + ExState(mul1, "MUL1"); + ExState(mul2, "MUL2"); + ExState(mmc3_irq_enabled, "M4IE"); + ExState(mmc3_irq_latch, "M4IL"); + ExState(mmc3_irq_counter, "M4IC"); + ExState(mmc3_irq_reload, "M4IR"); + ExState(mmc5_irq_enabled, "M5IE"); + ExState(mmc5_irq_line, "M5IL"); + ExState(mmc5_irq_out, "M5IO"); + ExState(mapper18_irq_value, "18IV"); + ExState(mapper18_irq_control, "18IC"); + ExState(mapper18_irq_latch, "18IL"); + ExState(mapper65_irq_enabled, "65IE"); + ExState(mapper65_irq_value, "65IV"); + ExState(mapper65_irq_latch, "65IL"); + ExState(mapper69_irq_enabled, "69IE"); + ExState(mapper69_counter_enabled, "69CE"); + ExState(mapper69_irq_value, "69IV"); + ExState(vrc4_irq_value, "V4IV"); + ExState(vrc4_irq_control, "V4IC"); + ExState(vrc4_irq_latch, "V4IL"); + ExState(vrc4_irq_prescaler, "V4PP"); + ExState(vrc4_irq_prescaler_counter, "V4PC"); + ExState(vrc3_irq_value, "V3IV"); + ExState(vrc3_irq_control, "V3IC"); + ExState(vrc3_irq_latch, "V3IL"); + ExState(mapper42_irq_enabled, "42IE"); + ExState(mapper42_irq_value, "42IV"); + ExState(mapper83_irq_enabled_latch, "M83L"); + ExState(mapper83_irq_enabled, "M83I"); + ExState(mapper83_irq_counter, "M83C"); + ExState(mapper90_xor, "90XR"); + ExState(mapper67_irq_enabled, "67IE"); + ExState(mapper67_irq_latch, "67IL"); + ExState(mapper67_irq_counter, "67IC"); + ExState(flash_state, "FLST"); + ExState(flash_buffer_a, "FLBA"); + ExState(flash_buffer_v, "FLBV"); + ExState(cfi_mode, "CFIM"); + + info->Power = COOLGIRL_Power; + info->Reset = COOLGIRL_Reset; + info->Close = COOLGIRL_Close; + GameStateRestore = COOLGIRL_Restore; +} diff --git a/src/config.cpp b/src/config.cpp index 66157634..387c2d20 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -26,7 +26,7 @@ const char *FCEUI_GetAboutString(void) "zeromus, feos\n" "\n" "Current Contributors:\n" - "CaH4e3, rainwarrior, owomomo, punkrockguy318\n" + "CaH4e3, rainwarrior, owomomo, punkrockguy318, Cluster\n" "\n" "Past Contributors:\n" "xhainingx, gocha, AnS, mjbudd77\n" diff --git a/src/ines.cpp b/src/ines.cpp index 92fa0bdf..a75192ba 100644 --- a/src/ines.cpp +++ b/src/ines.cpp @@ -730,6 +730,7 @@ BMAPPINGLocal bmap[] = { {"HP10xx/H20xx Boards", 260, BMCHPxx_Init}, {"810544-CA-1", 261, BMC810544CA1_Init}, {"SMD132/SMD133", 268, SMD132_SMD133_Init}, + {"COOLGIRL", 342, COOLGIRL_Init }, {"Impact Soft MMC3 Flash Board", 406, Mapper406_Init }, diff --git a/src/state.cpp b/src/state.cpp index 78279c4b..3a8fac80 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -88,7 +88,7 @@ EMUFILE_MEMORY memory_savestate; // temporary buffer for compressed data of a savestate std::vector compressed_buf; -#define SFMDATA_SIZE (64) +#define SFMDATA_SIZE (128) static SFORMAT SFMDATA[SFMDATA_SIZE]; static int SFEXINDEX; diff --git a/src/unif.cpp b/src/unif.cpp index 617b41cb..9cc59e20 100644 --- a/src/unif.cpp +++ b/src/unif.cpp @@ -475,6 +475,7 @@ static BMAPPING bmap[] = { { "FNS", FNS_Init, BMCFLAG_16KCHRR }, { "BS-400R", BS400R_Init, 0 }, { "BS-4040R", BS4040R_Init, 0 }, + { "COOLGIRL", COOLGIRL_Init, 0 }, { 0, 0, 0 } }; diff --git a/src/unif.h b/src/unif.h index b6759bdf..8856df71 100644 --- a/src/unif.h +++ b/src/unif.h @@ -163,6 +163,7 @@ void FNS_Init(CartInfo *info); void BS400R_Init(CartInfo *info); void BS4040R_Init(CartInfo *info); void SMD132_SMD133_Init(CartInfo *info); +void COOLGIRL_Init(CartInfo* info); extern uint8 *UNIFchrrama; // Meh. So I can stop CHR RAM // bank switcherooing with certain boards... From 856a19352f42c4fbfa2c33d3253339d0a00b33c9 Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Mon, 5 Dec 2022 17:50:11 +0400 Subject: [PATCH 13/26] Forgot to update CMakeLists.txt --- src/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c4dc2b02..7a6a3566 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -396,6 +396,7 @@ set(SRC_CORE ${CMAKE_CURRENT_SOURCE_DIR}/boards/cheapocabra.cpp ${CMAKE_CURRENT_SOURCE_DIR}/boards/cityfighter.cpp ${CMAKE_CURRENT_SOURCE_DIR}/boards/coolboy.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/boards/coolgirl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/boards/dance2000.cpp ${CMAKE_CURRENT_SOURCE_DIR}/boards/datalatch.cpp ${CMAKE_CURRENT_SOURCE_DIR}/boards/dream.cpp From 7a64e06b8830e7c02389d2dda14f747734433d72 Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Mon, 5 Dec 2022 21:55:38 +0400 Subject: [PATCH 14/26] Mapper 268, submappers 1,2,3 --- src/boards/coolboy.cpp | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/boards/coolboy.cpp b/src/boards/coolboy.cpp index b7a5e8e2..93b25025 100644 --- a/src/boards/coolboy.cpp +++ b/src/boards/coolboy.cpp @@ -93,6 +93,8 @@ static uint16 flash_buffer_a[10]; static uint8 flash_buffer_v[10]; static uint8 cfi_mode = 0; +static uint8 flag23 = 0; + // Macronix 256-mbit memory CFI data const uint8 cfi_data[] = { @@ -188,6 +190,10 @@ static void COOLBOYPW(uint32 A, uint8 V) { } } +static void Submapper23Flip() { + EXPREGS[1] = (EXPREGS[1] & 0b11100000) | ((EXPREGS[1] & 0b11100) >> 1) | (((EXPREGS[1] & 0b10) ^ 0b10) << 3); +} + static DECLFW(COOLBOYWrite) { if (A001B & 0x80) CartBW(A, V); @@ -195,6 +201,7 @@ static DECLFW(COOLBOYWrite) { // Deny any further writes when 7th bit is 1 AND 4th is 0 if ((EXPREGS[3] & 0x90) != 0x80) { EXPREGS[A & 3] = V; + if (flag23) Submapper23Flip(); FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); } @@ -210,6 +217,7 @@ static DECLFW(MINDKIDSWrite) { // Deny any further writes when 7th bit is 1 AND 4th is 0 if ((EXPREGS[3] & 0x90) != 0x80) { EXPREGS[A & 3] = V; + if (flag23) Submapper23Flip(); FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); } @@ -346,11 +354,22 @@ void CommonInit(CartInfo* info, int submapper) switch (submapper) { - case 1: - info->Power = MINDKIDSPower; - default: + case 0: info->Power = COOLBOYPower; break; + case 1: + info->Power = MINDKIDSPower; + break; + case 2: + info->Power = COOLBOYPower; + flag23 = 1; + break; + case 3: + info->Power = MINDKIDSPower; + flag23 = 1; + break; + default: + FCEU_PrintError("Submapper #%d is not supported", submapper); } info->Reset = CommonReset; info->Close = CommonClose; @@ -396,15 +415,5 @@ void MINDKIDS_Init(CartInfo* info) { // For NES 2.0 loader void SMD132_SMD133_Init(CartInfo* info) { - - switch (info->submapper) - { - case 0: - case 1: - CommonInit(info, info->submapper); - break; - default: - FCEU_PrintError("Submapper #%d is not supported", info->submapper); - break; - } + CommonInit(info, info->submapper); } From d6d5b44a350dfe683a4aa695fab2404bf2430cb9 Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Mon, 5 Dec 2022 21:56:50 +0400 Subject: [PATCH 15/26] Mapper 268, submappers 2,3 fix --- src/boards/coolboy.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/boards/coolboy.cpp b/src/boards/coolboy.cpp index 93b25025..6430d9a5 100644 --- a/src/boards/coolboy.cpp +++ b/src/boards/coolboy.cpp @@ -201,7 +201,7 @@ static DECLFW(COOLBOYWrite) { // Deny any further writes when 7th bit is 1 AND 4th is 0 if ((EXPREGS[3] & 0x90) != 0x80) { EXPREGS[A & 3] = V; - if (flag23) Submapper23Flip(); + if (flag23 && (A & 3) == 1) Submapper23Flip(); FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); } @@ -217,7 +217,7 @@ static DECLFW(MINDKIDSWrite) { // Deny any further writes when 7th bit is 1 AND 4th is 0 if ((EXPREGS[3] & 0x90) != 0x80) { EXPREGS[A & 3] = V; - if (flag23) Submapper23Flip(); + if (flag23 && (A & 3) == 1) Submapper23Flip(); FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); } From 92c0417783d5bcdeab1fa6ecf037e17fb7f0515f Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Mon, 5 Dec 2022 23:15:09 +0400 Subject: [PATCH 16/26] Mapper 268 refactoring --- src/boards/coolboy.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/boards/coolboy.cpp b/src/boards/coolboy.cpp index 6430d9a5..08ce3bee 100644 --- a/src/boards/coolboy.cpp +++ b/src/boards/coolboy.cpp @@ -126,7 +126,7 @@ static void COOLBOYCW(uint32 A, uint8 V) { case 0x0C00: V &= 0x7F; break; } } - // Highest bit goes from MMC3 registers when EXPREGS[3]&0x80==0 or from EXPREGS[0]&0x08 otherwise + // Highest bit goes from MMC3 registers when EXPREGS[0]&0x80==0 or from EXPREGS[0]&0x08 otherwise setchr1(A, (V & 0x80 & mask) | ((((EXPREGS[0] & 0x08) << 4) & ~mask)) // 7th bit | ((EXPREGS[2] & 0x0F) << 3) // 6-3 bits @@ -144,14 +144,18 @@ static void COOLBOYCW(uint32 A, uint8 V) { } } // Simple MMC3 mode - // Highest bit goes from MMC3 registers when EXPREGS[3]&0x80==0 or from EXPREGS[0]&0x08 otherwise + // Highest bit goes from MMC3 registers when EXPREGS[0]&0x80==0 or from EXPREGS[0]&0x08 otherwise setchr1(A, (V & mask) | (((EXPREGS[0] & 0x08) << 4) & ~mask)); } } static void COOLBOYPW(uint32 A, uint8 V) { - uint32 mask = ((0x3F | (EXPREGS[1] & 0x40) | ((EXPREGS[1] & 0x20) << 2)) ^ ((EXPREGS[0] & 0x40) >> 2)) ^ ((EXPREGS[1] & 0x80) >> 2); - uint32 base = ((EXPREGS[0] & 0x07) >> 0) | ((EXPREGS[1] & 0x10) >> 1) | ((EXPREGS[1] & 0x0C) << 2) | ((EXPREGS[0] & 0x30) << 2); + uint8 CREGS[] = {EXPREGS[0], EXPREGS[1], EXPREGS[2], EXPREGS[3]}; + if (flag23) + CREGS[1] = (CREGS[1] & 0b11100000) | ((CREGS[1] & 0b11100) >> 1) | (((CREGS[1] & 0b10) ^ 0b10) << 3); + + uint32 mask = ((0x3F | (CREGS[1] & 0x40) | ((CREGS[1] & 0x20) << 2)) ^ ((CREGS[0] & 0x40) >> 2)) ^ ((CREGS[1] & 0x80) >> 2); + uint32 base = ((CREGS[0] & 0x07) >> 0) | ((CREGS[1] & 0x10) >> 1) | ((CREGS[1] & 0x0C) << 2) | ((CREGS[0] & 0x30) << 2); if (cfi_mode) { @@ -162,7 +166,7 @@ static void COOLBOYPW(uint32 A, uint8 V) { // Very weird mode // Last banks are first in this mode, ignored when MMC3_cmd&0x40 - if ((EXPREGS[3] & 0x40) && (V >= 0xFE) && !((MMC3_cmd & 0x40) != 0)) { + if ((CREGS[3] & 0x40) && (V >= 0xFE) && !((MMC3_cmd & 0x40) != 0)) { switch (A & 0xE000) { case 0xC000: case 0xE000: @@ -171,7 +175,7 @@ static void COOLBOYPW(uint32 A, uint8 V) { } } - if (!(EXPREGS[3] & 0x10)) { + if (!(CREGS[3] & 0x10)) { // Regular MMC3 mode but can be extended to 2MByte setprg8r(chip, A, (((base << 4) & ~mask)) | (V & mask)); } @@ -179,10 +183,10 @@ static void COOLBOYPW(uint32 A, uint8 V) { // NROM mode mask &= 0xF0; uint8 emask; - if ((((EXPREGS[1] & 2) != 0))) // 32kb mode - emask = (EXPREGS[3] & 0x0C) | ((A & 0x4000) >> 13); + if ((((CREGS[1] & 2) != 0))) // 32kb mode + emask = (CREGS[3] & 0x0C) | ((A & 0x4000) >> 13); else // 16kb mode - emask = EXPREGS[3] & 0x0E; + emask = CREGS[3] & 0x0E; setprg8r(chip, A, ((base << 4) & ~mask) // 7-4 bits are from base (see below) | (V & mask) // ... or from MM3 internal regs, depends on mask | emask // 3-1 (or 3-2 when (EXPREGS[3]&0x0C is set) from EXPREGS[3] @@ -190,10 +194,6 @@ static void COOLBOYPW(uint32 A, uint8 V) { } } -static void Submapper23Flip() { - EXPREGS[1] = (EXPREGS[1] & 0b11100000) | ((EXPREGS[1] & 0b11100) >> 1) | (((EXPREGS[1] & 0b10) ^ 0b10) << 3); -} - static DECLFW(COOLBOYWrite) { if (A001B & 0x80) CartBW(A, V); @@ -201,7 +201,6 @@ static DECLFW(COOLBOYWrite) { // Deny any further writes when 7th bit is 1 AND 4th is 0 if ((EXPREGS[3] & 0x90) != 0x80) { EXPREGS[A & 3] = V; - if (flag23 && (A & 3) == 1) Submapper23Flip(); FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); } @@ -217,7 +216,6 @@ static DECLFW(MINDKIDSWrite) { // Deny any further writes when 7th bit is 1 AND 4th is 0 if ((EXPREGS[3] & 0x90) != 0x80) { EXPREGS[A & 3] = V; - if (flag23 && (A & 3) == 1) Submapper23Flip(); FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); } @@ -356,9 +354,11 @@ void CommonInit(CartInfo* info, int submapper) { case 0: info->Power = COOLBOYPower; + flag23 = 0; break; case 1: info->Power = MINDKIDSPower; + flag23 = 0; break; case 2: info->Power = COOLBOYPower; From a70bc4c72c7e6a1d798223017f324f3c1ebf2a7a Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Mon, 5 Dec 2022 23:22:45 +0400 Subject: [PATCH 17/26] Mapper 268, submappers 4,5 --- src/boards/coolboy.cpp | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/boards/coolboy.cpp b/src/boards/coolboy.cpp index 08ce3bee..9a524cca 100644 --- a/src/boards/coolboy.cpp +++ b/src/boards/coolboy.cpp @@ -94,6 +94,7 @@ static uint8 flash_buffer_v[10]; static uint8 cfi_mode = 0; static uint8 flag23 = 0; +static uint8 flag45 = 0; // Macronix 256-mbit memory CFI data const uint8 cfi_data[] = @@ -151,15 +152,20 @@ static void COOLBOYCW(uint32 A, uint8 V) { static void COOLBOYPW(uint32 A, uint8 V) { uint8 CREGS[] = {EXPREGS[0], EXPREGS[1], EXPREGS[2], EXPREGS[3]}; - if (flag23) + if (flag23) { CREGS[1] = (CREGS[1] & 0b11100000) | ((CREGS[1] & 0b11100) >> 1) | (((CREGS[1] & 0b10) ^ 0b10) << 3); + } + if (flag45) { + CREGS[1] = (CREGS[1] & 0b11101011) | ((CREGS[0] & 0b00100000) >> 3) | (CREGS[0] & 0b00010000); + CREGS[0] &= 0b11001111; + } uint32 mask = ((0x3F | (CREGS[1] & 0x40) | ((CREGS[1] & 0x20) << 2)) ^ ((CREGS[0] & 0x40) >> 2)) ^ ((CREGS[1] & 0x80) >> 2); uint32 base = ((CREGS[0] & 0x07) >> 0) | ((CREGS[1] & 0x10) >> 1) | ((CREGS[1] & 0x0C) << 2) | ((CREGS[0] & 0x30) << 2); - if (cfi_mode) - { + if (flash_save && cfi_mode) { setprg32r(CFI_CHIP, 0x8000, 0); + return; } int chip = !flash_save ? ROM_CHIP : FLASH_CHIP; @@ -355,18 +361,32 @@ void CommonInit(CartInfo* info, int submapper) case 0: info->Power = COOLBOYPower; flag23 = 0; + flag45 = 0; break; case 1: info->Power = MINDKIDSPower; flag23 = 0; + flag45 = 0; break; case 2: info->Power = COOLBOYPower; flag23 = 1; + flag45 = 0; break; case 3: info->Power = MINDKIDSPower; flag23 = 1; + flag45 = 0; + break; + case 4: + info->Power = COOLBOYPower; + flag23 = 0; + flag45 = 1; + break; + case 5: + info->Power = MINDKIDSPower; + flag23 = 0; + flag45 = 1; break; default: FCEU_PrintError("Submapper #%d is not supported", submapper); From b6bf83db7fb931101aa31ffbfe80ea3191704b91 Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Tue, 6 Dec 2022 17:59:26 +0400 Subject: [PATCH 18/26] Mapper 268, submappers 8,9 --- src/boards/coolboy.cpp | 139 +++++++++++++++++++++++++++-------------- 1 file changed, 91 insertions(+), 48 deletions(-) diff --git a/src/boards/coolboy.cpp b/src/boards/coolboy.cpp index 9a524cca..0b112341 100644 --- a/src/boards/coolboy.cpp +++ b/src/boards/coolboy.cpp @@ -55,15 +55,16 @@ * $xxx3 * 7 bit 0 * ---- ---- - * NPxP QQRx - * || | ||| - * || | +++--- PRG offset for GNROM mode (PRG A16, A15, A14) - * || +------- 1: GNROM mode; 0: MMC3 mode - * || | (1: PRG A16...13 from QQ, L, R, CPU A14, A13 + CHR A16...10 from MMMM, PPU A12...10; - * || | 0: PRG A16...13 from MMC3 + CHR A16...A10 from MMC3 ) + * NPZP QQRx + * |||| ||| + * |||| +++--- PRG offset for GNROM mode (PRG A16, A15, A14) + * |||+------- 1: GNROM mode; 0: MMC3 mode + * |||| (1: PRG A16...13 from QQ, L, R, CPU A14, A13 + CHR A16...10 from MMMM, PPU A12...10; + * |||| 0: PRG A16...13 from MMC3 + CHR A16...A10 from MMC3 ) + * ||+-------- 1: Also enable PRG RAM in $5000-$5FFF * |+-+------- Banking mode * |+--------- "Weird MMC3 mode" - * +---------- Lockout (prevent further writes to these four registers, only works in MMC3 mode) + * +---------- Lockout (prevent further writes to all registers but the one at $xxx2, only works in MMC3 mode) * * Also some new cartridges from MINDKIDS have /WE and /OE pins connected to mapper, * which allows you to rewrite flash memory without soldering. @@ -95,6 +96,7 @@ static uint8 cfi_mode = 0; static uint8 flag23 = 0; static uint8 flag45 = 0; +static uint8 flag89 = 0; // Macronix 256-mbit memory CFI data const uint8 cfi_data[] = @@ -118,9 +120,9 @@ const uint8 cfi_data[] = }; static void COOLBOYCW(uint32 A, uint8 V) { - uint32 mask = 0xFF ^ (EXPREGS[0] & 0x80); - if (EXPREGS[3] & 0x10) { - if (EXPREGS[3] & 0x40) { // Weird mode + uint32 mask = 0xFF ^ (EXPREGS[0] & 0b10000000); + if (EXPREGS[3] & 0b00010000) { + if (EXPREGS[3] & 0b01000000) { // Weird mode int cbase = (MMC3_cmd & 0x80) << 5; switch (cbase ^ A) { // Don't even try do understand case 0x0400: @@ -129,13 +131,13 @@ static void COOLBOYCW(uint32 A, uint8 V) { } // Highest bit goes from MMC3 registers when EXPREGS[0]&0x80==0 or from EXPREGS[0]&0x08 otherwise setchr1(A, - (V & 0x80 & mask) | ((((EXPREGS[0] & 0x08) << 4) & ~mask)) // 7th bit + (V & 0x80 & mask) | ((((EXPREGS[0] & 0b00001000) << 4) & ~mask)) // 7th bit | ((EXPREGS[2] & 0x0F) << 3) // 6-3 bits | ((A >> 10) & 7) // 2-0 bits ); } else { - if (EXPREGS[3] & 0x40) { // Weird mode, again + if (EXPREGS[3] & 0b01000000) { // Weird mode, again int cbase = (MMC3_cmd & 0x80) << 5; switch (cbase ^ A) { // Don't even try do understand case 0x0000: V = DRegBuf[0]; break; @@ -152,16 +154,72 @@ static void COOLBOYCW(uint32 A, uint8 V) { static void COOLBOYPW(uint32 A, uint8 V) { uint8 CREGS[] = {EXPREGS[0], EXPREGS[1], EXPREGS[2], EXPREGS[3]}; + // Submappers has scrambled bits if (flag23) { - CREGS[1] = (CREGS[1] & 0b11100000) | ((CREGS[1] & 0b11100) >> 1) | (((CREGS[1] & 0b10) ^ 0b10) << 3); + /* + $xxx1 + 7 bit 0 + ---- ---- + GHIL JKKx + |||| ||| + |||| +++--- PRG offset (in order: PRG A20, A22, A21) + |||+------- GNROM mode bank PRG size (0: 32 KiB bank, PRG A14=CPU A14; 1: 16 KiB bank, PRG A14=offset A14) + ||+-------- PRG mask (PRG A20 from 0: offset; 1: MMC3) + |+--------- PRG mask (PRG A19 from 0: offset; 1: MMC3) + +---------- PRG mask (PRG A18 from 0: MMC3; 1: offset) + */ + CREGS[1] = (CREGS[1] & 0b11100000) + | ((CREGS[1] & 0b00001110) << 1) // PRG A20, A22, A21 + | (((CREGS[1] & 0b00010000) ^ 0b00010000) >> 3); // GNROM mode bank PRG size } if (flag45) { - CREGS[1] = (CREGS[1] & 0b11101011) | ((CREGS[0] & 0b00100000) >> 3) | (CREGS[0] & 0b00010000); - CREGS[0] &= 0b11001111; + /* + $xxx0 + 7 bit 0 + ---- ---- + ABCC DEEE + |||| |||| + |||| |+++-- PRG offset (PRG A19, A18, A17) + |||| +----- Alternate CHR A17 + ||++------- PRG offset (PRG A21, A20) + |+--------- PRG mask (PRG A17 from 0: MMC3; 1: offset) + +---------- CHR mask (CHR A17 from 0: MMC3; 1: alternate) + $xxx1 + 7 bit 0 + ---- ---- + GHIx xxLx + ||| | + ||| +--- GNROM mode bank PRG size (1: 32 KiB bank, PRG A14=CPU A14; 0: 16 KiB bank, PRG A14=offset A14) + ||+-------- PRG mask (PRG A20 from 0: offset; 1: MMC3) + |+--------- PRG mask (PRG A19 from 0: offset; 1: MMC3) + +---------- PRG mask (PRG A18 from 0: MMC3; 1: offset) + */ + CREGS[1] = (CREGS[1] & 0b11101011) + | ((CREGS[0] & 0b00100000) >> 3) // PRG A21 + | (CREGS[0] & 0b00010000); // PRG A20 + } + if (flag89) { + /* + $xxx1 + 7 bit 0 + ---- ---- + GHIL JKKx + |||| ||| + |||| +++--- PRG offset (in order: A20, A21, A22) + |||+------- GNROM mode bank PRG size (0: 32 KiB bank, PRG A14=CPU A14; 1: 16 KiB bank, PRG A14=offset A14) + ||+-------- PRG mask (PRG A20 from 0: offset; 1: MMC3) + |+--------- PRG mask (PRG A19 from 0: offset; 1: MMC3) + +---------- PRG mask (PRG A18 from 0: MMC3; 1: offset) + */ + CREGS[1] = (CREGS[1] & 0b11100101) + | ((CREGS[1] & 0b00001000) << 1) // PRG A20 + | ((CREGS[1] & 0b00000010) << 2) // PRG A22 + | ((((CREGS[1] ^ 0b00010000) & 0b00010000) >> 3)); // GNROM mode bank PRG size } - uint32 mask = ((0x3F | (CREGS[1] & 0x40) | ((CREGS[1] & 0x20) << 2)) ^ ((CREGS[0] & 0x40) >> 2)) ^ ((CREGS[1] & 0x80) >> 2); - uint32 base = ((CREGS[0] & 0x07) >> 0) | ((CREGS[1] & 0x10) >> 1) | ((CREGS[1] & 0x0C) << 2) | ((CREGS[0] & 0x30) << 2); + uint32 mask = ((0b00111111 | (CREGS[1] & 0b01000000) | ((CREGS[1] & 0b00100000) << 2)) ^ ((CREGS[0] & 0b01000000) >> 2)) ^ ((CREGS[1] & 0b10000000) >> 2); + uint32 base = ((CREGS[0] & 0b00000111) >> 0) | ((CREGS[1] & 0b00010000) >> 1) | ((CREGS[1] & 0b00001100) << 2) | ((CREGS[0] & 0b00110000) << 2); + FCEU_printf("mask=%04x base=%04x r0=%02x r1=%02x r2=%02x r3=%02x\n", mask, base, CREGS[0], CREGS[1], CREGS[2], CREGS[3]); if (flash_save && cfi_mode) { setprg32r(CFI_CHIP, 0x8000, 0); @@ -172,7 +230,7 @@ static void COOLBOYPW(uint32 A, uint8 V) { // Very weird mode // Last banks are first in this mode, ignored when MMC3_cmd&0x40 - if ((CREGS[3] & 0x40) && (V >= 0xFE) && !((MMC3_cmd & 0x40) != 0)) { + if ((CREGS[3] & 0b01000000) && (V >= 0xFE) && !((MMC3_cmd & 0x40) != 0)) { switch (A & 0xE000) { case 0xC000: case 0xE000: @@ -189,11 +247,11 @@ static void COOLBOYPW(uint32 A, uint8 V) { // NROM mode mask &= 0xF0; uint8 emask; - if ((((CREGS[1] & 2) != 0))) // 32kb mode - emask = (CREGS[3] & 0x0C) | ((A & 0x4000) >> 13); + if (CREGS[1] & 0b00000010) // 32kb mode + emask = (CREGS[3] & 0b00001100) | ((A & 0x4000) >> 13); else // 16kb mode - emask = CREGS[3] & 0x0E; - setprg8r(chip, A, ((base << 4) & ~mask) // 7-4 bits are from base (see below) + emask = CREGS[3] & 0b00001110; + setprg8r(chip, A, ((base << 4) & ~mask) // 7-4 bits are from base | (V & mask) // ... or from MM3 internal regs, depends on mask | emask // 3-1 (or 3-2 when (EXPREGS[3]&0x0C is set) from EXPREGS[3] | ((A & 0x2000) >> 13)); // 0th just as is @@ -207,9 +265,9 @@ static DECLFW(COOLBOYWrite) { // Deny any further writes when 7th bit is 1 AND 4th is 0 if ((EXPREGS[3] & 0x90) != 0x80) { EXPREGS[A & 3] = V; - FixMMC3PRG(MMC3_cmd); - FixMMC3CHR(MMC3_cmd); } + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); } static DECLFW(MINDKIDSWrite) { @@ -222,9 +280,9 @@ static DECLFW(MINDKIDSWrite) { // Deny any further writes when 7th bit is 1 AND 4th is 0 if ((EXPREGS[3] & 0x90) != 0x80) { EXPREGS[A & 3] = V; - FixMMC3PRG(MMC3_cmd); - FixMMC3CHR(MMC3_cmd); } + FixMMC3PRG(MMC3_cmd); + FixMMC3CHR(MMC3_cmd); } static DECLFR(COOLBOYFlashRead) { @@ -359,38 +417,23 @@ void CommonInit(CartInfo* info, int submapper) switch (submapper) { case 0: + case 2: + case 4: + case 8: info->Power = COOLBOYPower; - flag23 = 0; - flag45 = 0; break; case 1: - info->Power = MINDKIDSPower; - flag23 = 0; - flag45 = 0; - break; - case 2: - info->Power = COOLBOYPower; - flag23 = 1; - flag45 = 0; - break; case 3: - info->Power = MINDKIDSPower; - flag23 = 1; - flag45 = 0; - break; - case 4: - info->Power = COOLBOYPower; - flag23 = 0; - flag45 = 1; - break; case 5: + case 9: info->Power = MINDKIDSPower; - flag23 = 0; - flag45 = 1; break; default: FCEU_PrintError("Submapper #%d is not supported", submapper); } + flag23 = (submapper == 2) || (submapper == 3); + flag45 = (submapper == 4) || (submapper == 5); + flag89 = (submapper == 8) || (submapper == 9); info->Reset = CommonReset; info->Close = CommonClose; From 853b2718b7b45a0b46975128d26b370ac00dfe3c Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Tue, 6 Dec 2022 22:51:41 +0400 Subject: [PATCH 19/26] Removed debug messages --- src/boards/coolboy.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/boards/coolboy.cpp b/src/boards/coolboy.cpp index 0b112341..b232c61b 100644 --- a/src/boards/coolboy.cpp +++ b/src/boards/coolboy.cpp @@ -219,7 +219,6 @@ static void COOLBOYPW(uint32 A, uint8 V) { uint32 mask = ((0b00111111 | (CREGS[1] & 0b01000000) | ((CREGS[1] & 0b00100000) << 2)) ^ ((CREGS[0] & 0b01000000) >> 2)) ^ ((CREGS[1] & 0b10000000) >> 2); uint32 base = ((CREGS[0] & 0b00000111) >> 0) | ((CREGS[1] & 0b00010000) >> 1) | ((CREGS[1] & 0b00001100) << 2) | ((CREGS[0] & 0b00110000) << 2); - FCEU_printf("mask=%04x base=%04x r0=%02x r1=%02x r2=%02x r3=%02x\n", mask, base, CREGS[0], CREGS[1], CREGS[2], CREGS[3]); if (flash_save && cfi_mode) { setprg32r(CFI_CHIP, 0x8000, 0); From 689d763f67fbd27fc5865fad8dc5ae6ea7aba26d Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Wed, 7 Dec 2022 09:42:05 +0400 Subject: [PATCH 20/26] Windows build fix --- vc/vc14_fceux.vcxproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vc/vc14_fceux.vcxproj b/vc/vc14_fceux.vcxproj index 10bdf280..47b60a73 100644 --- a/vc/vc14_fceux.vcxproj +++ b/vc/vc14_fceux.vcxproj @@ -473,6 +473,7 @@ xcopy /y /d "$(ProjectDir)\..\src\drivers\win\7z_64.dll" "$(OutDir)" + @@ -1528,4 +1529,4 @@ xcopy /y /d "$(ProjectDir)\..\src\drivers\win\7z_64.dll" "$(OutDir)" - + \ No newline at end of file From 0fb86b97406ae93aa9e09e2f7797c1c736c02e79 Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Wed, 7 Dec 2022 20:04:27 +0400 Subject: [PATCH 21/26] Fixed broken UNROM-512 emulation + some refactoring --- src/boards/coolboy.cpp | 127 ++++++++-------- src/boards/coolgirl.cpp | 10 +- src/boards/unrom512.cpp | 324 ++++++++++++++++------------------------ 3 files changed, 198 insertions(+), 263 deletions(-) diff --git a/src/boards/coolboy.cpp b/src/boards/coolboy.cpp index b232c61b..878f3419 100644 --- a/src/boards/coolboy.cpp +++ b/src/boards/coolboy.cpp @@ -294,77 +294,76 @@ static DECLFW(COOLBOYFlashWrite) { else MMC3_IRQWrite(A, V); - if (flash_save) { - if (flash_state < sizeof(flash_buffer_a) / sizeof(flash_buffer_a[0])) { - flash_buffer_a[flash_state] = A & 0xFFF; - flash_buffer_v[flash_state] = V; - flash_state++; + if (!flash_save) return; + if (flash_state < sizeof(flash_buffer_a) / sizeof(flash_buffer_a[0])) { + flash_buffer_a[flash_state] = A & 0xFFF; + flash_buffer_v[flash_state] = V; + flash_state++; - // enter CFI mode - if ((flash_state == 1) && - (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0x98)) { - cfi_mode = 1; - flash_state = 0; - FixMMC3PRG(MMC3_cmd); - } - - // erase sector - if ((flash_state == 6) && - (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) && - (flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) && - (flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0x80) && - (flash_buffer_a[3] == 0x0AAA) && (flash_buffer_v[3] == 0xAA) && - (flash_buffer_a[4] == 0x0555) && (flash_buffer_v[4] == 0x55) && - (flash_buffer_v[5] == 0x30)) { - int offset = &Page[A >> 11][A] - Flash; - int sector = offset / FLASH_SECTOR_SIZE; - for (uint32 i = sector * FLASH_SECTOR_SIZE; i < (sector + 1) * FLASH_SECTOR_SIZE; i++) - Flash[i % PRGsize[ROM_CHIP]] = 0xFF; - FCEU_printf("Flash sector #%d is erased (0x%08x - 0x%08x)\n", sector, offset, offset + FLASH_SECTOR_SIZE); - } - - // erase chip, lol - if ((flash_state == 6) && - (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) && - (flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) && - (flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0x80) && - (flash_buffer_a[3] == 0x0AAA) && (flash_buffer_v[3] == 0xAA) && - (flash_buffer_a[4] == 0x0555) && (flash_buffer_v[4] == 0x55) && - (flash_buffer_v[5] == 0x10)) { - memset(Flash, 0xFF, PRGsize[ROM_CHIP]); - FCEU_printf("Flash chip erased.\n"); - } - - // write byte - if ((flash_state == 4) && - (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) && - (flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) && - (flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0xA0)) { - int offset = &Page[A >> 11][A] - Flash; - if (CartBR(A) != 0xFF) { - FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased\n", offset); - } - else { - CartBW(A, V); - } - flash_state = 0; - } - - - } - - // not a command - if (((A & 0xFFF) != 0x0AAA) && ((A & 0xFFF) != 0x0555)) { + // enter CFI mode + if ((flash_state == 1) && + (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0x98)) { + cfi_mode = 1; flash_state = 0; } - // reset - if (V == 0xF0) { + // erase sector + if ((flash_state == 6) && + (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) && + (flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) && + (flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0x80) && + (flash_buffer_a[3] == 0x0AAA) && (flash_buffer_v[3] == 0xAA) && + (flash_buffer_a[4] == 0x0555) && (flash_buffer_v[4] == 0x55) && + (flash_buffer_v[5] == 0x30)) { + int offset = &Page[A >> 11][A] - Flash; + int sector = offset / FLASH_SECTOR_SIZE; + for (uint32 i = sector * FLASH_SECTOR_SIZE; i < (sector + 1) * FLASH_SECTOR_SIZE; i++) + Flash[i % PRGsize[ROM_CHIP]] = 0xFF; + FCEU_printf("Flash sector #%d is erased (0x%08x - 0x%08x).\n", sector, offset, offset + FLASH_SECTOR_SIZE); + flash_state = 0; + } + + // erase chip, lol + if ((flash_state == 6) && + (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) && + (flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) && + (flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0x80) && + (flash_buffer_a[3] == 0x0AAA) && (flash_buffer_v[3] == 0xAA) && + (flash_buffer_a[4] == 0x0555) && (flash_buffer_v[4] == 0x55) && + (flash_buffer_v[5] == 0x10)) { + memset(Flash, 0xFF, PRGsize[ROM_CHIP]); + FCEU_printf("Flash chip erased.\n"); + flash_state = 0; + } + + // write byte + if ((flash_state == 4) && + (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) && + (flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) && + (flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0xA0)) { + int offset = &Page[A >> 11][A] - Flash; + if (CartBR(A) != 0xFF) { + FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased.\n", offset); + } + else { + CartBW(A, V); + } flash_state = 0; - cfi_mode = 0; - FixMMC3PRG(MMC3_cmd); } } + + // not a command + if (((A & 0xFFF) != 0x0AAA) && ((A & 0xFFF) != 0x0555)) { + flash_state = 0; + } + + // reset + if (V == 0xF0) { + flash_state = 0; + cfi_mode = 0; + } + + FixMMC3PRG(MMC3_cmd); } static void CommonReset(void) { diff --git a/src/boards/coolgirl.cpp b/src/boards/coolgirl.cpp index 86441198..3d2fa7cd 100644 --- a/src/boards/coolgirl.cpp +++ b/src/boards/coolgirl.cpp @@ -419,9 +419,7 @@ static DECLFW(COOLGIRL_Flash_Write) { (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0x98)) { cfi_mode = 1; - COOLGIRL_Sync_PRG(); flash_state = 0; - return; } // sector erase @@ -437,7 +435,7 @@ static DECLFW(COOLGIRL_Flash_Write) { uint32 sector_address = sector * FLASH_SECTOR_SIZE; for (uint32 i = sector_address; i < sector_address + FLASH_SECTOR_SIZE; i++) SAVE_FLASH[i % SAVE_FLASH_SIZE] = 0xFF; - FCEU_printf("Flash sector #%d is erased: 0x%08x - 0x%08x\n", sector, sector_address, sector_address + FLASH_SECTOR_SIZE - 1); + FCEU_printf("Flash sector #%d is erased: 0x%08x - 0x%08x.\n", sector, sector_address, sector_address + FLASH_SECTOR_SIZE - 1); flash_state = 0; } @@ -451,12 +449,10 @@ static DECLFW(COOLGIRL_Flash_Write) { uint32 sector_address = sector * FLASH_SECTOR_SIZE; uint32 flash_addr = prg_bank_a_mapped * 0x2000 + (A % 0x8000); if (SAVE_FLASH[flash_addr % SAVE_FLASH_SIZE] != 0xFF) { - FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased\n", flash_addr); + FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased.\n", flash_addr); } else { SAVE_FLASH[flash_addr % SAVE_FLASH_SIZE] = V; - if (A % 0x2000 == 0) - FCEU_printf("Flash sector #%d is written: 0x%08x\n", sector, flash_addr); } flash_state = 0; } @@ -472,6 +468,8 @@ static DECLFW(COOLGIRL_Flash_Write) { flash_state = 0; cfi_mode = 0; } + + COOLGIRL_Sync_PRG(); } static DECLFW(COOLGIRL_WRITE) { diff --git a/src/boards/unrom512.cpp b/src/boards/unrom512.cpp index 973749ea..f0f41fe4 100644 --- a/src/boards/unrom512.cpp +++ b/src/boards/unrom512.cpp @@ -1,7 +1,7 @@ /* FCE Ultra - NES/Famicom Emulator * * Copyright notice for this file: - * Copyright (C) 2014 CaitSith2 + * Copyright (C) 2014 CaitSith2, 2022 Cluster * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,7 +19,7 @@ */ /* - * Roms still using NES 1.0 format should be loaded as 32K CHR RAM. + * Roms still using NES 1.0 format should be loaded as 8K CHR RAM. * Roms defined under NES 2.0 should use the VRAM size field, defining 7, 8 or 9, based on how much VRAM should be present. * UNIF doesn't have this problem, because unique board names can define this information. * The UNIF names are UNROM-512-8K, UNROM-512-16K and UNROM-512-32K @@ -28,6 +28,7 @@ * Known games to use this board are: * Battle Kid 2: Mountain of Torment (512K PRG, 8K CHR RAM, Horizontal Mirroring, Flash disabled) * Study Hall (128K PRG (in 512K flash chip), 8K CHR RAM, Horizontal Mirroring, Flash enabled) + * Nix: The Paradox Relic (512 PRG, 8K CHR RAM, Vertical Mirroring, Flash enabled) * Although Xmas 2013 uses a different board, where LEDs can be controlled (with writes to the $8000-BFFF space), * it otherwise functions identically. */ @@ -35,211 +36,147 @@ #include "mapinc.h" #include "../ines.h" -static uint8 latche, latcheinit, bus_conflict, chrram_mask, software_id=false; +const int ROM_CHIP = 0x00; +const int CFI_CHIP = 0x10; +const int FLASH_CHIP = 0x11; + +const int FLASH_SECTOR_SIZE = 4 * 1024; + +static uint8 flash_save, flash_state, flash_id_mode, latche, bus_conflict; static uint16 latcha; -static uint8 *flashdata; -static uint32 *flash_write_count; -static uint8 *FlashPage[32]; -//static uint32 *FlashWriteCountPage[32]; -//static uint8 flashloaded = false; +static uint8 *flash_data; +static uint16 flash_buffer_a[10]; +static uint8 flash_buffer_v[10]; +static uint8 flash_id[2]; -static uint8 flash_save=0, flash_state=0, flash_mode=0, flash_bank; -static void (*WLSync)(void); -static void (*WHSync)(void); - -static INLINE void setfpageptr(int s, uint32 A, uint8 *p) { - uint32 AB = A >> 11; - int x; - - if (p) - for (x = (s >> 1) - 1; x >= 0; x--) { - FlashPage[AB + x] = p - A; - } +static void UNROM512_Sync() { + int chip; + if (flash_save) + chip = !flash_id_mode ? FLASH_CHIP : CFI_CHIP; else - for (x = (s >> 1) - 1; x >= 0; x--) { - FlashPage[AB + x] = 0; - } -} - -void setfprg16(uint32 A, uint32 V) { - if (PRGsize[0] >= 16384) { - V &= PRGmask16[0]; - setfpageptr(16, A, flashdata ? (&flashdata[V << 14]) : 0); - } else { - uint32 VA = V << 3; - int x; - - for (x = 0; x < 8; x++) - setfpageptr(2, A + (x << 11), flashdata ? (&flashdata[((VA + x) & PRGmask2[0]) << 11]) : 0); - } -} - -void inc_flash_write_count(uint8 bank, uint32 A) -{ - flash_write_count[(bank*4) + ((A&0x3000)>>12)]++; - if(!flash_write_count[(bank*4) + ((A&0x3000)>>12)]) - flash_write_count[(bank*4) + ((A&0x3000)>>12)]++; -} - -uint32 GetFlashWriteCount(uint8 bank, uint32 A) -{ - return flash_write_count[(bank*4) + ((A&0x3000)>>12)]; + chip = ROM_CHIP; + setprg16r(chip, 0x8000, latche & 0b11111); + setprg16r(chip, 0xc000, ~0); + setchr8((latche >> 5) & 0b11); + setmirror(MI_0 + ((latche >> 7) & 1)); } static void StateRestore(int version) { - WHSync(); + UNROM512_Sync(); } -static DECLFW(UNROM512LLatchWrite) +static DECLFW(UNROM512FlashWrite) { - latche = V; - latcha = A; - WLSync(); + if (flash_state < sizeof(flash_buffer_a) / sizeof(flash_buffer_a[0])) { + flash_buffer_a[flash_state] = (A & 0x3FFF) | ((latche & 1) << 14); + flash_buffer_v[flash_state] = V; + flash_state++; + + // enter flash ID mode + if ((flash_state == 2) && + (flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) && + (flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) && + (flash_buffer_a[1] == 0x5555) && (flash_buffer_v[1] == 0x90)) { + flash_id_mode = 0; + flash_state = 0; + } + + // erase sector + if ((flash_state == 6) && + (flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) && + (flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) && + (flash_buffer_a[2] == 0x5555) && (flash_buffer_v[2] == 0x80) && + (flash_buffer_a[3] == 0x5555) && (flash_buffer_v[3] == 0xAA) && + (flash_buffer_a[4] == 0x2AAA) && (flash_buffer_v[4] == 0x55) && + (flash_buffer_v[5] == 0x30)) { + int offset = &Page[A >> 11][A] - flash_data; + int sector = offset / FLASH_SECTOR_SIZE; + for (uint32 i = sector * FLASH_SECTOR_SIZE; i < (sector + 1) * FLASH_SECTOR_SIZE; i++) + flash_data[i % PRGsize[ROM_CHIP]] = 0xFF; + FCEU_printf("Flash sector #%d is erased (0x%08x - 0x%08x).\n", sector, offset, offset + FLASH_SECTOR_SIZE); + } + + // erase chip + if ((flash_state == 6) && + (flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) && + (flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) && + (flash_buffer_a[2] == 0x5555) && (flash_buffer_v[2] == 0x80) && + (flash_buffer_a[3] == 0x5555) && (flash_buffer_v[3] == 0xAA) && + (flash_buffer_a[4] == 0x2AAA) && (flash_buffer_v[4] == 0x55) && + (flash_buffer_a[4] == 0x5555) && (flash_buffer_v[4] == 0x10)) { + memset(flash_data, 0xFF, PRGsize[ROM_CHIP]); + FCEU_printf("Flash chip erased.\n"); + flash_state = 0; + } + + // write byte + if ((flash_state == 4) && + (flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) && + (flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) && + (flash_buffer_a[2] == 0x5555) && (flash_buffer_v[2] == 0xA0)) { + int offset = &Page[A >> 11][A] - flash_data; + if (CartBR(A) != 0xFF) { + FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased.\n", offset); + } + else { + CartBW(A, V); + } + flash_state = 0; + } + } + + // not a command + if (((A & 0xFFF) != 0x0AAA) && ((A & 0xFFF) != 0x0555)) { + flash_state = 0; + } + + // reset + if (V == 0xF0) { + flash_state = 0; + flash_id_mode = 0; + } + + UNROM512_Sync(); } static DECLFW(UNROM512HLatchWrite) { if (bus_conflict) - latche = (V == CartBR(A)) ? V : 0; + latche = V & CartBR(A); else latche = V; latcha = A; - WHSync(); -} - -static DECLFR(UNROM512LatchRead) -{ - uint8 flash_id[3]={0xB5,0xB6,0xB7}; - if(software_id) - { - if(A&1) - return flash_id[ROM_size>>4]; - else - return 0xBF; - } - if(flash_save) - { - if(A < 0xC000) - { - if(GetFlashWriteCount(flash_bank,A)) - return FlashPage[A >> 11][A]; - } - else - { - if(GetFlashWriteCount(ROM_size-1,A)) - return FlashPage[A >> 11][A]; - } - } - return Page[A >> 11][A]; + UNROM512_Sync(); } static void UNROM512LatchPower(void) { - latche = latcheinit; - WHSync(); - SetReadHandler(0x8000, 0xFFFF, UNROM512LatchRead); + latche = 0; + UNROM512_Sync(); + SetReadHandler(0x8000, 0xFFFF, CartBR); if(!flash_save) SetWriteHandler(0x8000, 0xFFFF, UNROM512HLatchWrite); else { - SetWriteHandler(0x8000,0xBFFF,UNROM512LLatchWrite); + SetWriteHandler(0x8000,0xBFFF,UNROM512FlashWrite); SetWriteHandler(0xC000,0xFFFF,UNROM512HLatchWrite); } } static void UNROM512LatchClose(void) { - if(flash_write_count) - FCEU_gfree(flash_write_count); - if(flashdata) - FCEU_gfree(flashdata); - flash_write_count = NULL; - flashdata = NULL; -} - - -static void UNROM512LSync() { - int erase_a[5]={0x9555,0xAAAA,0x9555,0x9555,0xAAAA}; - int erase_d[5]={0xAA,0x55,0x80,0xAA,0x55}; - int erase_b[5]={1,0,1,1,0}; - - if(flash_mode==0) - { - if((latcha == erase_a[flash_state]) && (latche == erase_d[flash_state]) && (flash_bank == erase_b[flash_state])) - { - flash_state++; - if(flash_state == 5) - { - flash_mode=1; - } - } - else if ((flash_state==2)&&(latcha==0x9555)&&(latche==0xA0)&&(flash_bank==1)) - { - flash_state++; - flash_mode=2; - } - else if ((flash_state==2)&&(latcha==0x9555)&&(latche==0x90)&&(flash_bank==1)) - { - flash_state=0; - software_id=true; - } - else - { - if(latche==0xF0) - software_id=false; - flash_state=0; - } - } - else if(flash_mode==1) //Chip Erase or Sector Erase - { - if(latche==0x30) - { - inc_flash_write_count(flash_bank,latcha); - memset(&FlashPage[(latcha & 0xF000) >> 11][latcha & 0xF000],0xFF,0x1000); - } - else if (latche==0x10) - { - for(uint32 i=0;i<(ROM_size*4);i++) - inc_flash_write_count(i>>2,i<<12); - memset(flashdata,0xFF,ROM_size*0x4000); //Erasing the rom chip as instructed. Crash rate calulated to be 99.9% :) - } - flash_state=0; - flash_mode=0; - } - else if(flash_mode==2) //Byte Program - { - if(!GetFlashWriteCount(flash_bank,latcha)) - { - inc_flash_write_count(flash_bank,latcha); - memcpy(&FlashPage[(latcha & 0xF000) >> 11][latcha & 0xF000],&Page[(latcha & 0xF000)>>11][latcha & 0xF000],0x1000); - } - FlashPage[latcha>>11][latcha]&=latche; - flash_state=0; - flash_mode=0; - } -} - -static void UNROM512HSync() -{ - flash_bank=latche&(ROM_size-1); - - setprg16(0x8000, flash_bank); - setprg16(0xc000, ~0); - setfprg16(0x8000, flash_bank); - setfprg16(0xC000, ~0); - setchr8r(0, (latche & chrram_mask) >> 5); - setmirror(MI_0+(latche>>7)); + if(flash_data) + FCEU_gfree(flash_data); + flash_data = NULL; } void UNROM512_Init(CartInfo *info) { - flash_state=0; - flash_bank=0; - flash_save=info->battery; + info->Power = UNROM512LatchPower; + info->Close = UNROM512LatchClose; + GameStateRestore = StateRestore; - if(info->vram_size == 8192) - chrram_mask = 0; - else if (info->vram_size == 16384) - chrram_mask = 0x20; - else - chrram_mask = 0x60; + flash_state = 0; + flash_id_mode = 0; + flash_save = info->battery; + bus_conflict = !info->battery; // Is it required by any game? int mirror = (head.ROM_type & 1) | ((head.ROM_type & 8) >> 2); switch (mirror) @@ -258,28 +195,29 @@ void UNROM512_Init(CartInfo *info) { break; } - bus_conflict = !info->battery; - latcheinit = 0; - WLSync = UNROM512LSync; - WHSync = UNROM512HSync; - info->Power = UNROM512LatchPower; - info->Close = UNROM512LatchClose; - GameStateRestore = StateRestore; if(flash_save) { - flashdata = (uint8*)FCEU_gmalloc(ROM_size*0x4000); - flash_write_count = (uint32*)FCEU_gmalloc(ROM_size*4*sizeof(uint32)); - info->SaveGame[0] = (uint8*)flash_write_count; - info->SaveGame[1] = flashdata; - info->SaveGameLen[0] = ROM_size*4*sizeof(uint32); - info->SaveGameLen[1] = ROM_size*0x4000; - AddExState(flash_write_count,ROM_size*4*sizeof(uint32),0,"FLASH_WRITE_COUNT"); - AddExState(flashdata,ROM_size*0x4000,0,"FLASH_DATA"); - AddExState(&flash_state,1,0,"FLASH_STATE"); - AddExState(&flash_mode,1,0,"FLASH_MODE"); - AddExState(&flash_bank,1,0,"FLASH_BANK"); - AddExState(&latcha,2,0,"LATA"); + // Allocate memory for flash + flash_data = (uint8*)FCEU_gmalloc(PRGsize[ROM_CHIP]); + // Copy ROM to flash data + for (int i = 0; i < PRGsize[ROM_CHIP]; i++) { + flash_data[i] = PRGptr[ROM_CHIP][i % PRGsize[ROM_CHIP]]; + } + SetupCartPRGMapping(FLASH_CHIP, flash_data, PRGsize[ROM_CHIP], 1); + info->SaveGame[0] = flash_data; + info->SaveGameLen[0] = PRGsize[ROM_CHIP]; + + flash_id[0] = 0xBF; + flash_id[1] = 0xB5 + (ROM_size >> 4); + SetupCartPRGMapping(CFI_CHIP, flash_id, sizeof(flash_id), 0); + + AddExState(flash_data, PRGsize[ROM_CHIP], 0, "FLSH"); + AddExState(&flash_state, 1, 0, "FLST"); + AddExState(&flash_id_mode, 1, 0, "FLMD"); + AddExState(flash_buffer_a, sizeof(flash_buffer_a), 0, "FLBA"); + AddExState(flash_buffer_v, sizeof(flash_buffer_v), 0, "FLBV"); } + AddExState(&latcha, 2, 0, "LATA"); AddExState(&latche, 1, 0, "LATC"); AddExState(&bus_conflict, 1, 0, "BUSC"); } From 773eaa868ca84f71f80c47126ff4c61ee6a784cd Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Mon, 12 Dec 2022 17:48:56 +0400 Subject: [PATCH 22/26] Mapper 268, submappers 8,9 merged into 2,3 and fixed (https://www.nesdev.org/wiki/Talk:NES_2.0_Mapper_268) + refactoring --- src/boards/coolboy.cpp | 104 ++++++++++++++-------------------------- src/boards/coolgirl.cpp | 2 +- src/ines.cpp | 2 +- src/unif.h | 2 +- 4 files changed, 39 insertions(+), 71 deletions(-) diff --git a/src/boards/coolboy.cpp b/src/boards/coolboy.cpp index 878f3419..80000474 100644 --- a/src/boards/coolboy.cpp +++ b/src/boards/coolboy.cpp @@ -82,7 +82,7 @@ const int WRAM_CHIP = 0x10; const int CFI_CHIP = 0x11; const int FLASH_CHIP = 0x12; -const int FLASH_SECTOR_SIZE = 128 * 1024; +const uint32 FLASH_SECTOR_SIZE = 128 * 1024; extern uint8* WRAM; static uint8* CFI = NULL; @@ -94,9 +94,9 @@ static uint16 flash_buffer_a[10]; static uint8 flash_buffer_v[10]; static uint8 cfi_mode = 0; +static uint16 regs_base = 0; static uint8 flag23 = 0; static uint8 flag45 = 0; -static uint8 flag89 = 0; // Macronix 256-mbit memory CFI data const uint8 cfi_data[] = @@ -119,7 +119,7 @@ const uint8 cfi_data[] = 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; -static void COOLBOYCW(uint32 A, uint8 V) { +static void AA6023CW(uint32 A, uint8 V) { uint32 mask = 0xFF ^ (EXPREGS[0] & 0b10000000); if (EXPREGS[3] & 0b00010000) { if (EXPREGS[3] & 0b01000000) { // Weird mode @@ -152,7 +152,7 @@ static void COOLBOYCW(uint32 A, uint8 V) { } } -static void COOLBOYPW(uint32 A, uint8 V) { +static void AA6023PW(uint32 A, uint8 V) { uint8 CREGS[] = {EXPREGS[0], EXPREGS[1], EXPREGS[2], EXPREGS[3]}; // Submappers has scrambled bits if (flag23) { @@ -162,15 +162,16 @@ static void COOLBOYPW(uint32 A, uint8 V) { ---- ---- GHIL JKKx |||| ||| - |||| +++--- PRG offset (in order: PRG A20, A22, A21) + |||| +++--- PRG offset (in order: PRG A20, A21, A22) |||+------- GNROM mode bank PRG size (0: 32 KiB bank, PRG A14=CPU A14; 1: 16 KiB bank, PRG A14=offset A14) ||+-------- PRG mask (PRG A20 from 0: offset; 1: MMC3) |+--------- PRG mask (PRG A19 from 0: offset; 1: MMC3) +---------- PRG mask (PRG A18 from 0: MMC3; 1: offset) */ - CREGS[1] = (CREGS[1] & 0b11100000) - | ((CREGS[1] & 0b00001110) << 1) // PRG A20, A22, A21 - | (((CREGS[1] & 0b00010000) ^ 0b00010000) >> 3); // GNROM mode bank PRG size + CREGS[1] = (CREGS[1] & 0b11100101) + | ((CREGS[1] & 0b00001000) << 1) // PRG A20 + | ((CREGS[1] & 0b00000010) << 2) // PRG A22 + | ((((CREGS[1] ^ 0b00010000) & 0b00010000) >> 3)); // GNROM mode bank PRG size } if (flag45) { /* @@ -194,27 +195,10 @@ static void COOLBOYPW(uint32 A, uint8 V) { |+--------- PRG mask (PRG A19 from 0: offset; 1: MMC3) +---------- PRG mask (PRG A18 from 0: MMC3; 1: offset) */ - CREGS[1] = (CREGS[1] & 0b11101011) + CREGS[1] = (CREGS[1] & 0b11100011) | ((CREGS[0] & 0b00100000) >> 3) // PRG A21 | (CREGS[0] & 0b00010000); // PRG A20 - } - if (flag89) { - /* - $xxx1 - 7 bit 0 - ---- ---- - GHIL JKKx - |||| ||| - |||| +++--- PRG offset (in order: A20, A21, A22) - |||+------- GNROM mode bank PRG size (0: 32 KiB bank, PRG A14=CPU A14; 1: 16 KiB bank, PRG A14=offset A14) - ||+-------- PRG mask (PRG A20 from 0: offset; 1: MMC3) - |+--------- PRG mask (PRG A19 from 0: offset; 1: MMC3) - +---------- PRG mask (PRG A18 from 0: MMC3; 1: offset) - */ - CREGS[1] = (CREGS[1] & 0b11100101) - | ((CREGS[1] & 0b00001000) << 1) // PRG A20 - | ((CREGS[1] & 0b00000010) << 2) // PRG A22 - | ((((CREGS[1] ^ 0b00010000) & 0b00010000) >> 3)); // GNROM mode bank PRG size + CREGS[0] &= 0b11001111; } uint32 mask = ((0b00111111 | (CREGS[1] & 0b01000000) | ((CREGS[1] & 0b00100000) << 2)) ^ ((CREGS[0] & 0b01000000) >> 2)) ^ ((CREGS[1] & 0b10000000) >> 2); @@ -257,23 +241,14 @@ static void COOLBOYPW(uint32 A, uint8 V) { } } -static DECLFW(COOLBOYWrite) { +static DECLFW(AA6023WramWrite) { if (A001B & 0x80) CartBW(A, V); - - // Deny any further writes when 7th bit is 1 AND 4th is 0 - if ((EXPREGS[3] & 0x90) != 0x80) { - EXPREGS[A & 3] = V; - } - FixMMC3PRG(MMC3_cmd); - FixMMC3CHR(MMC3_cmd); } -static DECLFW(MINDKIDSWrite) { +static DECLFW(AA6023Write) { if (A >= 0x6000) { - if (A001B & 0x80) - CartBW(A, V); - return; + AA6023WramWrite(A, V); } // Deny any further writes when 7th bit is 1 AND 4th is 0 @@ -284,11 +259,7 @@ static DECLFW(MINDKIDSWrite) { FixMMC3CHR(MMC3_cmd); } -static DECLFR(COOLBOYFlashRead) { - return CartBR(A); -} - -static DECLFW(COOLBOYFlashWrite) { +static DECLFW(AA6023FlashWrite) { if (A < 0xC000) MMC3_CMDWrite(A, V); else @@ -366,7 +337,7 @@ static DECLFW(COOLBOYFlashWrite) { FixMMC3PRG(MMC3_cmd); } -static void CommonReset(void) { +static void AA6023Reset(void) { MMC3RegReset(); EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; flash_state = 0; @@ -375,28 +346,25 @@ static void CommonReset(void) { FixMMC3CHR(MMC3_cmd); } -static void COOLBOYPower(void) { +static void AA6023Power(void) { GenMMC3Power(); EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); - SetWriteHandler(0x5000, 0x5fff, CartBW); // some games access random unmapped areas and crashes because of KT-008 PCB hack in MMC3 source lol - SetWriteHandler(0x6000, 0x6fff, COOLBOYWrite); - SetWriteHandler(0x8000, 0xFFFF, COOLBOYFlashWrite); - SetReadHandler(0x8000, 0xFFFF, COOLBOYFlashRead); + if (regs_base != 0x5000) + SetWriteHandler(0x5000, 0x5fff, CartBW); // some games access random unmapped areas and crashes because of KT-008 PCB hack in MMC3 source lol + SetWriteHandler(0x6000, 0x7fff, AA6023WramWrite); + SetWriteHandler(regs_base, regs_base + 0x0fff, AA6023Write); + SetWriteHandler(0x8000, 0xFFFF, AA6023FlashWrite); + SetReadHandler(0x8000, 0xFFFF, CartBR); } -static void MINDKIDSPower(void) { - GenMMC3Power(); - EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; +static void AA6023Restore(void) { FixMMC3PRG(MMC3_cmd); FixMMC3CHR(MMC3_cmd); - SetWriteHandler(0x5000, 0x7fff, MINDKIDSWrite); - SetWriteHandler(0x8000, 0xFFFF, COOLBOYFlashWrite); - SetReadHandler(0x8000, 0xFFFF, COOLBOYFlashRead); } -static void CommonClose(void) { +static void AA6023Close(void) { if (WRAM) FCEU_gfree(WRAM); if (Flash) @@ -409,31 +377,31 @@ static void CommonClose(void) { void CommonInit(CartInfo* info, int submapper) { GenMMC3_Init(info, 2048, info->vram_size / 1024, !info->ines2 ? 8 : (info->wram_size + info->battery_wram_size) / 1024, info->battery); - pwrap = COOLBOYPW; - cwrap = COOLBOYCW; + pwrap = AA6023PW; + cwrap = AA6023CW; switch (submapper) { - case 0: case 2: + regs_base = 0x7000; + break; + case 0: case 4: - case 8: - info->Power = COOLBOYPower; + regs_base = 0x6000; break; case 1: case 3: case 5: - case 9: - info->Power = MINDKIDSPower; + regs_base = 0x5000; break; default: FCEU_PrintError("Submapper #%d is not supported", submapper); } flag23 = (submapper == 2) || (submapper == 3); flag45 = (submapper == 4) || (submapper == 5); - flag89 = (submapper == 8) || (submapper == 9); - info->Reset = CommonReset; - info->Close = CommonClose; + info->Power = AA6023Power; + info->Reset = AA6023Reset; + info->Close = AA6023Close; flash_save = info->battery; @@ -475,6 +443,6 @@ void MINDKIDS_Init(CartInfo* info) { } // For NES 2.0 loader -void SMD132_SMD133_Init(CartInfo* info) { +void AA6023_Init(CartInfo* info) { CommonInit(info, info->submapper); } diff --git a/src/boards/coolgirl.cpp b/src/boards/coolgirl.cpp index 3d2fa7cd..f998be1c 100644 --- a/src/boards/coolgirl.cpp +++ b/src/boards/coolgirl.cpp @@ -26,7 +26,7 @@ #include "mapinc.h" const uint32 SAVE_FLASH_SIZE = 1024 * 1024 * 8; -const int FLASH_SECTOR_SIZE = 128 * 1024; +const uint32 FLASH_SECTOR_SIZE = 128 * 1024; const int ROM_CHIP = 0x00; const int WRAM_CHIP = 0x10; const int FLASH_CHIP = 0x11; diff --git a/src/ines.cpp b/src/ines.cpp index a75192ba..c150c3e1 100644 --- a/src/ines.cpp +++ b/src/ines.cpp @@ -729,7 +729,7 @@ BMAPPINGLocal bmap[] = { {"F-15 MMC3 Based", 259, BMCF15_Init}, {"HP10xx/H20xx Boards", 260, BMCHPxx_Init}, {"810544-CA-1", 261, BMC810544CA1_Init}, - {"SMD132/SMD133", 268, SMD132_SMD133_Init}, + {"AA6023/AA6023B", 268, AA6023_Init}, {"COOLGIRL", 342, COOLGIRL_Init }, {"Impact Soft MMC3 Flash Board", 406, Mapper406_Init }, diff --git a/src/unif.h b/src/unif.h index 8856df71..92fc5a36 100644 --- a/src/unif.h +++ b/src/unif.h @@ -162,7 +162,7 @@ void MINDKIDS_Init(CartInfo *info); void FNS_Init(CartInfo *info); void BS400R_Init(CartInfo *info); void BS4040R_Init(CartInfo *info); -void SMD132_SMD133_Init(CartInfo *info); +void AA6023_Init(CartInfo *info); void COOLGIRL_Init(CartInfo* info); extern uint8 *UNIFchrrama; // Meh. So I can stop CHR RAM From 47c2ce5a38ed3476e6285118942565769eedddda Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Mon, 12 Dec 2022 23:13:42 +0400 Subject: [PATCH 23/26] Mapper 268, support for ROMs with 1 MiB CHR-ROM --- src/boards/coolboy.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/boards/coolboy.cpp b/src/boards/coolboy.cpp index 80000474..6cf3a5e4 100644 --- a/src/boards/coolboy.cpp +++ b/src/boards/coolboy.cpp @@ -29,7 +29,7 @@ * |||| |||| * |||| |+++-- PRG offset (PRG A19, A18, A17) * |||| +----- Alternate CHR A17 - * ||++------- PRG offset (PRG A24, A23) + * ||++------- PRG offset (PRG A24, A23), CHR offset (CHR A19, A18) * |+--------- PRG mask (PRG A17 from 0: MMC3; 1: offset) * +---------- CHR mask (CHR A17 from 0: MMC3; 1: alternate) * @@ -134,6 +134,7 @@ static void AA6023CW(uint32 A, uint8 V) { (V & 0x80 & mask) | ((((EXPREGS[0] & 0b00001000) << 4) & ~mask)) // 7th bit | ((EXPREGS[2] & 0x0F) << 3) // 6-3 bits | ((A >> 10) & 7) // 2-0 bits + | ((EXPREGS[0] & 0b00110000) << 4) // There are some ROMs with 1 MiB CHR-ROM ); } else { @@ -148,7 +149,10 @@ static void AA6023CW(uint32 A, uint8 V) { } // Simple MMC3 mode // Highest bit goes from MMC3 registers when EXPREGS[0]&0x80==0 or from EXPREGS[0]&0x08 otherwise - setchr1(A, (V & mask) | (((EXPREGS[0] & 0x08) << 4) & ~mask)); + setchr1(A, + (V & mask) + | (((EXPREGS[0] & 0x08) << 4) & ~mask) + | ((EXPREGS[0] & 0b00110000) << 4)); // There are some ROMs with 1 MiB CHR-ROM } } @@ -223,7 +227,7 @@ static void AA6023PW(uint32 A, uint8 V) { } if (!(CREGS[3] & 0x10)) { - // Regular MMC3 mode but can be extended to 2MByte + // Regular MMC3 mode but can be extended to 2MiB setprg8r(chip, A, (((base << 4) & ~mask)) | (V & mask)); } else { From 9ae27c7deda04db25b1fb8bae8ca3537ad781bfb Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Mon, 12 Dec 2022 23:38:56 +0400 Subject: [PATCH 24/26] Mapper 268, submappers 6 and 7 --- src/boards/coolboy.cpp | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/boards/coolboy.cpp b/src/boards/coolboy.cpp index 6cf3a5e4..c2df0eea 100644 --- a/src/boards/coolboy.cpp +++ b/src/boards/coolboy.cpp @@ -76,6 +76,7 @@ #include "mapinc.h" #include "mmc3.h" +#include "../ines.h" const int ROM_CHIP = 0x00; const int WRAM_CHIP = 0x10; @@ -97,6 +98,7 @@ static uint8 cfi_mode = 0; static uint16 regs_base = 0; static uint8 flag23 = 0; static uint8 flag45 = 0; +static uint8 flag67 = 0; // Macronix 256-mbit memory CFI data const uint8 cfi_data[] = @@ -214,6 +216,11 @@ static void AA6023PW(uint32 A, uint8 V) { } int chip = !flash_save ? ROM_CHIP : FLASH_CHIP; + // There are ROMs with multiple PRG ROM chips + int chip_offset = 0; + if (flag67 && EXPREGS[0] & 0b00001000) { + chip_offset += ROM_size; + } // Very weird mode // Last banks are first in this mode, ignored when MMC3_cmd&0x40 @@ -228,7 +235,7 @@ static void AA6023PW(uint32 A, uint8 V) { if (!(CREGS[3] & 0x10)) { // Regular MMC3 mode but can be extended to 2MiB - setprg8r(chip, A, (((base << 4) & ~mask)) | (V & mask)); + setprg8r(chip, A, ((((base << 4) & ~mask)) | (V & mask)) + chip_offset); } else { // NROM mode @@ -238,10 +245,12 @@ static void AA6023PW(uint32 A, uint8 V) { emask = (CREGS[3] & 0b00001100) | ((A & 0x4000) >> 13); else // 16kb mode emask = CREGS[3] & 0b00001110; - setprg8r(chip, A, ((base << 4) & ~mask) // 7-4 bits are from base - | (V & mask) // ... or from MM3 internal regs, depends on mask - | emask // 3-1 (or 3-2 when (EXPREGS[3]&0x0C is set) from EXPREGS[3] - | ((A & 0x2000) >> 13)); // 0th just as is + setprg8r(chip, A, ( + ((base << 4) & ~mask) // 7-4 bits are from base + | (V & mask) // ... or from MM3 internal regs, depends on mask + | emask // 3-1 (or 3-2 when (EXPREGS[3]&0x0C is set) from EXPREGS[3] + | ((A & 0x2000) >> 13) // 0th just as is + ) + chip_offset); // For multi-chip ROMs } } @@ -391,11 +400,13 @@ void CommonInit(CartInfo* info, int submapper) break; case 0: case 4: + case 6: regs_base = 0x6000; break; case 1: case 3: case 5: + case 7: regs_base = 0x5000; break; default: @@ -403,6 +414,7 @@ void CommonInit(CartInfo* info, int submapper) } flag23 = (submapper == 2) || (submapper == 3); flag45 = (submapper == 4) || (submapper == 5); + flag67 = (submapper == 6) || (submapper == 7); info->Power = AA6023Power; info->Reset = AA6023Reset; info->Close = AA6023Close; @@ -415,7 +427,6 @@ void CommonInit(CartInfo* info, int submapper) CFI[i * 2] = CFI[i * 2 + 1] = cfi_data[i]; } SetupCartPRGMapping(CFI_CHIP, CFI, sizeof(cfi_data) * 2, 0); - Flash = (uint8*)FCEU_gmalloc(PRGsize[ROM_CHIP]); for (int i = 0; i < PRGsize[ROM_CHIP]; i++) { Flash[i] = PRGptr[ROM_CHIP][i % PRGsize[ROM_CHIP]]; From f53c2470fcbeb4b3d53f9df0edcee1e0f16fa4c0 Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Fri, 16 Dec 2022 20:10:21 +0400 Subject: [PATCH 25/26] Submappers 268.8 and 268.9 --- src/boards/coolboy.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/boards/coolboy.cpp b/src/boards/coolboy.cpp index c2df0eea..7fde3c2a 100644 --- a/src/boards/coolboy.cpp +++ b/src/boards/coolboy.cpp @@ -99,6 +99,7 @@ static uint16 regs_base = 0; static uint8 flag23 = 0; static uint8 flag45 = 0; static uint8 flag67 = 0; +static uint8 flag89 = 0; // Macronix 256-mbit memory CFI data const uint8 cfi_data[] = @@ -122,6 +123,25 @@ const uint8 cfi_data[] = }; static void AA6023CW(uint32 A, uint8 V) { + if (flag89) { + /* + $xxx0 + 7 bit 0 + ---- ---- + AB.C DEEE + || | |||| + || | |+++-- PRG offset (PRG A19, A18, A17) + || | +----- Alternate CHR A17 + || +------- 1=Write-protect CHR-RAM + |+--------- PRG mask (PRG A17 from 0: MMC3; 1: offset) + +---------- CHR mask (CHR A17 from 0: MMC3; 1: alternate) + */ + if (EXPREGS[0] & 0b00010000) + SetupCartCHRMapping(0, VROM, CHRsize[0], 0); // write-protect CHR-RAM + else + SetupCartCHRMapping(0, VROM, CHRsize[0], 1); // allow CHR writes + } + uint32 mask = 0xFF ^ (EXPREGS[0] & 0b10000000); if (EXPREGS[3] & 0b00010000) { if (EXPREGS[3] & 0b01000000) { // Weird mode @@ -401,12 +421,14 @@ void CommonInit(CartInfo* info, int submapper) case 0: case 4: case 6: + case 8: regs_base = 0x6000; break; case 1: case 3: case 5: case 7: + case 9: regs_base = 0x5000; break; default: @@ -415,6 +437,7 @@ void CommonInit(CartInfo* info, int submapper) flag23 = (submapper == 2) || (submapper == 3); flag45 = (submapper == 4) || (submapper == 5); flag67 = (submapper == 6) || (submapper == 7); + flag89 = (submapper == 8) || (submapper == 9); info->Power = AA6023Power; info->Reset = AA6023Reset; info->Close = AA6023Close; From f3675320d8eb147c2e2d4f2726ba5a62852ff108 Mon Sep 17 00:00:00 2001 From: Alexey 'Cluster' Avdyukhin Date: Mon, 19 Dec 2022 14:55:53 +0400 Subject: [PATCH 26/26] Fixed IPS loader to prevent double archive browser --- src/drivers/win/window.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/drivers/win/window.cpp b/src/drivers/win/window.cpp index 82c845b5..3aae132b 100644 --- a/src/drivers/win/window.cpp +++ b/src/drivers/win/window.cpp @@ -1078,12 +1078,12 @@ void CloseGame() bool ALoad(const char *nameo, char* innerFilename, bool silent) { - FCEUFILE* patchTrial = FCEU_fopen(nameo,nullptr,"rb",nullptr,-1); + FILE* patchTrial = fopen(nameo, "rb"); if(patchTrial) { char sig[10] = {0}; - FCEU_fread(sig,1,5,patchTrial); - FCEU_fclose(patchTrial); + fread(sig,1,5,patchTrial); + fclose(patchTrial); if(!strcmp(sig,"PATCH")) { //assuming it's a patch: