Codebase list fceux / 61e6ecb
New upstream version 2.6.5+dfsg1 Joe Nahmias 1 year, 2 months ago
149 changed file(s) with 8131 addition(s) and 2862 deletion(s). Raw diff Collapse all Expand all
2626 /vc/fceux.zip
2727 /vc/fceux64.zip
2828
29 # macOS junk
30 .DS_Store
31
2932 # linux build output
3033 bin
3134 src/fceux
44
55 [NOTE: This only applies to Qt/SDL builds]
66
7 http://www.fceux.com
7 https://fceux.com
88
99 Last Modified: March 24, 2022
1010
1616 #appveyor_build_worker_image: Ubuntu1804
1717
1818 - job_name: MacOS
19 appveyor_build_worker_image: macOS
19 appveyor_build_worker_image: macos-bigsur
2020
2121 for:
2222
2626 - job_name: Windows 32
2727
2828 build_script:
29 - cmd: pipelines/win32_build.bat
29 - cmd: perl pipelines/build.pl win32
3030
3131 -
3232 matrix:
3434 - job_name: Windows 64
3535
3636 build_script:
37 - cmd: pipelines/win64_build.bat
37 - cmd: perl pipelines/build.pl win64
3838
3939 -
4040 matrix:
4242 - job_name: Win64 Qt
4343
4444 build_script:
45 - cmd: pipelines/qwin64_build.bat
45 - cmd: perl pipelines/build.pl win64-QtSDL
4646
4747 -
4848 matrix:
5050 - job_name: Ubuntu
5151
5252 build_script:
53 - sh: ./pipelines/linux_build.sh
53 - sh: perl pipelines/build.pl linux
5454
5555 -
5656 matrix:
5858 - job_name: MacOS
5959
6060 build_script:
61 - sh: ./pipelines/macOS_build.sh
61 - sh: perl pipelines/build.pl macOS
6262
63 deploy:
64
65 - provider: GitHub
66 tag: interim-build
67 release: interim-build
68 description: 'Interim Builds - Latest auto builds off master branch - commit: $(APPVEYOR_REPO_COMMIT)\nDate: $(APPVEYOR_REPO_COMMIT_TIMESTAMP)'
69 auth_token:
70 secure: pYXqhuxNn7vivsJ6cnWCHlORrTtaWO7fyGOvGFUNKtM2apSY44gjbAhGIlD+OdtF
71 artifact: $(WIN32_ARTIFACT), $(WIN64_ARTIFACT), $(WIN64_QTSDL_ARTIFACT), $(MACOS_ARTIFACT), $(LINUX_ARTIFACT)
72 draft: false
73 prerelease: true
74 force_update: true
75 on:
76 branch: master # release from master branch only
77 APPVEYOR_REPO_TAG: false # never deploy on tag push
78
79 - provider: GitHub
80 description: 'Release Builds - commit: $(APPVEYOR_REPO_COMMIT)'
81 auth_token:
82 secure: pYXqhuxNn7vivsJ6cnWCHlORrTtaWO7fyGOvGFUNKtM2apSY44gjbAhGIlD+OdtF
83 artifact: $(WIN32_ARTIFACT), $(WIN64_ARTIFACT), $(WIN64_QTSDL_ARTIFACT), $(MACOS_ARTIFACT)
84 draft: false
85 prerelease: false
86 force_update: false
87 on:
88 APPVEYOR_REPO_TAG: true # deploy on tag push only
0 #!/usr/bin/perl
1
2 use strict;
3 use File::Basename;
4 #use File::Spec;
5
6 #
7 # Global Variables
8 #
9 my $platform = "";
10 my $fceuVersionMajor = 1;
11 my $fceuVersionMinor = 0;
12 my $fceuVersionPatch = 0;
13
14 foreach my $arg (@ARGV)
15 {
16 #print $arg, "\n";
17
18 if ($platform eq "")
19 {
20 $platform = $arg;
21 }
22 }
23
24 my $dirname = dirname(__FILE__);
25 my $projRoot = "$dirname/..";
26 my $ReleaseBuild=0;
27 my $ReleaseVersion="";
28
29 #print "PATH: $ENV{PATH}\n";
30 #print "Dir $dirname\n";
31 #
32 ($fceuVersionMajor, $fceuVersionMinor, $fceuVersionPatch) = getVersion();
33
34 ($ReleaseBuild, $ReleaseVersion) = isReleaseBuild();
35
36 if ($ReleaseBuild)
37 {
38 $ENV{FCEU_RELEASE_VERSION} = $ReleaseVersion;
39 }
40
41 if ($platform eq "win32")
42 {
43 build_win32();
44 }
45 elsif ($platform eq "win64")
46 {
47 build_win64();
48 }
49 elsif ($platform eq "win64-QtSDL")
50 {
51 build_win64_QtSDL();
52 }
53 elsif ($platform eq "linux")
54 {
55 build_ubuntu_linux();
56 }
57 elsif ($platform eq "macOS")
58 {
59 build_macOS();
60 }
61 #--------------------------------------------------------------------------------------------
62 # Build win32 version
63 #--------------------------------------------------------------------------------------------
64 sub build_win32
65 {
66 chdir("$projRoot");
67
68 my $ret = system("cmd.exe /c pipelines\\\\win32_build.bat");
69
70 if ($ret != 0){ die "Build Errors Detected\n";}
71 }
72 #--------------------------------------------------------------------------------------------
73 # Build win64 version
74 #--------------------------------------------------------------------------------------------
75 sub build_win64
76 {
77 chdir("$projRoot");
78
79 my $ret = system("cmd.exe /c pipelines\\\\win64_build.bat");
80
81 if ($ret != 0){ die "Build Errors Detected\n";}
82 }
83 #--------------------------------------------------------------------------------------------
84 # Build win64-Qt/SDL version
85 #--------------------------------------------------------------------------------------------
86 sub build_win64_QtSDL
87 {
88 chdir("$projRoot");
89
90 my $ret = system("cmd.exe /c pipelines\\\\qwin64_build.bat");
91
92 if ($ret != 0){ die "Build Errors Detected\n";}
93 }
94 #--------------------------------------------------------------------------------------------
95 # Build Ubuntu Linux version
96 #--------------------------------------------------------------------------------------------
97 sub build_ubuntu_linux
98 {
99 chdir("$projRoot");
100
101 my $ret = system("./pipelines/linux_build.sh");
102
103 if ($ret != 0){ die "Build Errors Detected\n";}
104 }
105 #--------------------------------------------------------------------------------------------
106 # Build MacOSX version
107 #--------------------------------------------------------------------------------------------
108 sub build_macOS
109 {
110 chdir("$projRoot");
111
112 my $ret = system("./pipelines/macOS_build.sh");
113
114 if ($ret != 0){ die "Build Errors Detected\n";}
115 }
116 #--------------------------------------------------------------------------------------------
117 # Search src/version.h and retrieve version numbers
118 #--------------------------------------------------------------------------------------------
119 sub getVersion
120 {
121 my $versionHeader = "$projRoot/src/version.h";
122 my $line;
123 my $major = 1;
124 my $minor = 0;
125 my $patch = 0;
126 open INFILE, "$versionHeader" or die "Error: Could not open file: $versionHeader\n";
127 while ($line = <INFILE>)
128 {
129 #print $line;
130 if ($line =~ m/\s*#define\s+FCEU_VERSION_MAJOR\s+(\d+)/)
131 {
132 $major = $1;
133 }
134 elsif ($line =~ m/\s*#define\s+FCEU_VERSION_MINOR\s+(\d+)/)
135 {
136 $minor = $1;
137 }
138 elsif ($line =~ m/\s*#define\s+FCEU_VERSION_PATCH\s+(\d+)/)
139 {
140 $patch = $1;
141 }
142 }
143 close(INFILE);
144
145 return ( $major, $minor, $patch );
146 }
147 #--------------------------------------------------------------------------------------------
148 # Returns whether this is a release build and returns the version if detected
149 #--------------------------------------------------------------------------------------------
150 sub isReleaseBuild
151 {
152 my $isRelease = 0;
153 my $tagVersion = "";
154
155 if (defined($ENV{APPVEYOR_REPO_TAG_NAME}))
156 {
157 if ($ENV{APPVEYOR_REPO_TAG_NAME} =~ m/fceux-(\d+\.\d+\.\d+)/)
158 {
159 $tagVersion = $1;
160 $isRelease = 1;
161 }
162 elsif ($ENV{APPVEYOR_REPO_TAG_NAME} =~ m/(\d+\.\d+\.\d+)/)
163 {
164 $tagVersion = $1;
165 $isRelease = 1;
166 }
167 }
168 return ($isRelease, $tagVersion);
169 }
00 #!/usr/bin/perl
11
22 use strict;
3 use File::Basename;
34
4 my $VERSION="2.6.4";
5 my $dirname = dirname(__FILE__);
6
7 my $VERSION=`perl $dirname/../scripts/fceuVersion.pl`;
58 my $INSTALL_PREFIX="/tmp/fceux";
69 my $CTL_FILENAME="$INSTALL_PREFIX/DEBIAN/control";
710 my $ARCH="amd64";
33 pwd
44 uname -a
55 cat /etc/os-release
6 env
67
78 SCRIPT_DIR=$( cd $(dirname $BASH_SOURCE[0]); pwd );
89
1819 echo "APPVEYOR_SSH_KEY=$APPVEYOR_SSH_KEY";
1920 echo "APPVEYOR_SSH_BLOCK=$APPVEYOR_SSH_BLOCK";
2021 echo '****************************************'
22
23 if [ ! -z $FCEU_RELEASE_VERSION ]; then
24 APPVEYOR_CMAKE_FLAGS=" -DPUBLIC_RELEASE=1 ";
25 fi
2126
2227 echo '****************************************'
2328 echo '****************************************'
97102 sudo apt-get --assume-yes install libavformat-dev
98103 sudo apt-get --assume-yes install libavutil-dev
99104 sudo apt-get --assume-yes install libswscale-dev
100 sudo apt-get --assume-yes install libavresample-dev
105 sudo apt-get --assume-yes install libswresample-dev
101106
102107 # Install cppcheck
103108 echo '****************************************'
118123 -DCMAKE_BUILD_TYPE=Release \
119124 -DCMAKE_INSTALL_PREFIX=/usr \
120125 -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \
126 $APPVEYOR_CMAKE_FLAGS \
121127 ..
122128 make -j `nproc`
123129 make install DESTDIR=$INSTALL_PREFIX
190196 echo '**************************************************************'
191197 sudo dpkg -i /tmp/fceux-*.deb
192198
193 echo 'Pushing Debian Package to Build Artifacts'
194 appveyor PushArtifact /tmp/fceux-*.deb
199 if [ ! -z $APPVEYOR ]; then
200 echo 'Pushing Debian Package to Build Artifacts'
201 if [ -z $FCEU_RELEASE_VERSION ]; then
202 cp /tmp/fceux-*.deb /tmp/fceux-ubuntu-x64.deb
203 appveyor PushArtifact /tmp/fceux-ubuntu-x64.deb
204 appveyor SetVariable -Name LINUX_ARTIFACT -Value fceux-ubuntu-x64.deb
205 else
206 appveyor PushArtifact /tmp/fceux-*.deb
207 fi
208 fi
44 pwd
55 uname -a
66 sw_vers
7 env
8
9 SCRIPT_DIR=$( cd $(dirname $BASH_SOURCE[0]); pwd );
710
811 QT_MAJOR=5;
912 QT_PKGNAME=qt$QT_MAJOR;
10 FCEUX_VERSION_MAJOR=2
11 FCEUX_VERSION_MINOR=6
12 FCEUX_VERSION_PATCH=4
13 FCEUX_VERSION_MAJOR=`perl $SCRIPT_DIR/../scripts/fceuVersion.pl -major`;
14 FCEUX_VERSION_MINOR=`perl $SCRIPT_DIR/../scripts/fceuVersion.pl -minor`;
15 FCEUX_VERSION_PATCH=`perl $SCRIPT_DIR/../scripts/fceuVersion.pl -patch`;
16 FCEUX_VERSION="$FCEUX_VERSION_MAJOR.$FCEUX_VERSION_MINOR.$FCEUX_VERSION_PATCH";
1317 SDL2_VERSION=2.0.20
1418
15 SCRIPT_DIR=$( cd $(dirname $BASH_SOURCE[0]); pwd );
19 echo "Building Version: $FCEUX_VERSION";
1620
1721 NPROC=`getconf _NPROCESSORS_ONLN`;
1822 echo "Number of Processors: $NPROC";
3236 echo "APPVEYOR_SSH_KEY=$APPVEYOR_SSH_KEY";
3337 echo "APPVEYOR_SSH_BLOCK=$APPVEYOR_SSH_BLOCK";
3438 echo '****************************************'
39
40 if [ ! -z $FCEU_RELEASE_VERSION ]; then
41 APPVEYOR_CMAKE_FLAGS=" -DPUBLIC_RELEASE=1 ";
42 fi
3543
3644 echo '****************************************'
3745 echo 'Install Dependency sdl2'
120128 -DCPACK_PACKAGE_VERSION_MINOR=$FCEUX_VERSION_MINOR \
121129 -DCPACK_PACKAGE_VERSION_PATCH=$FCEUX_VERSION_PATCH \
122130 -DQT6=$USE_QT6 \
131 $APPVEYOR_CMAKE_FLAGS \
123132 .. || exit 1
124133 make -j $NPROC || exit 1
125134 #sudo make install || exit 1 # make install is already run by cpack
126135 sudo cpack -G DragNDrop || exit 1
127136
128 echo 'Pushing DMG Package to Build Artifacts'
129 appveyor PushArtifact fceux-*.dmg
137 if [ ! -z $APPVEYOR ]; then
138 echo 'Pushing DMG Package to Build Artifacts'
139 if [ -z $FCEU_RELEASE_VERSION ]; then
140 cp fceux-*.dmg fceux-Darwin.dmg
141 appveyor PushArtifact fceux-Darwin.dmg
142 appveyor SetVariable -Name MACOS_ARTIFACT -Value fceux-Darwin.dmg
143 else
144 appveyor PushArtifact fceux-*.dmg
145 appveyor SetVariable -Name MACOS_ARTIFACT -Value `ls fceux-*.dmg`
146 fi
147 fi
130148
131149 # Debug via ssh if necessary
132150 if [ ! -z $APPVEYOR_SSH_BLOCK ]; then
77
88 cd /d %CWD%
99
10 set
1011 where cmake
1112 where nmake
1213 where msbuild
2021 cd build
2122 mkdir bin
2223
23 curl -s -LO http://www.libsdl.org/release/SDL2-devel-2.0.20-VC.zip
24 curl -s -LO https://github.com/GyanD/codexffmpeg/releases/download/5.0/ffmpeg-5.0-full_build-shared.zip
24 set SDL_VERSION=2.24.1
25 set FFMPEG_VERSION=5.1.2
26
27 curl -s -LO https://github.com/libsdl-org/SDL/releases/download/release-%SDL_VERSION%/SDL2-devel-%SDL_VERSION%-VC.zip
28 curl -s -LO https://github.com/GyanD/codexffmpeg/releases/download/%FFMPEG_VERSION%/ffmpeg-%FFMPEG_VERSION%-full_build-shared.zip
2529
2630 REM rmdir /q /s SDL2
2731
28 powershell -command "Expand-Archive" SDL2-devel-2.0.20-VC.zip .
29 powershell -command "Expand-Archive" ffmpeg-5.0-full_build-shared.zip
32 powershell -command "Expand-Archive" SDL2-devel-%SDL_VERSION%-VC.zip .
33 powershell -command "Expand-Archive" ffmpeg-%FFMPEG_VERSION%-full_build-shared.zip
3034
31 rename SDL2-2.0.20 SDL2
32 move ffmpeg-5.0-full_build-shared\ffmpeg-5.0-full_build-shared ffmpeg
33 rmdir ffmpeg-5.0-full_build-shared
34 del ffmpeg-5.0-full_build-shared.zip
35 rename SDL2-%SDL_VERSION% SDL2
36 move ffmpeg-%FFMPEG_VERSION%-full_build-shared\ffmpeg-%FFMPEG_VERSION%-full_build-shared ffmpeg
37 rmdir ffmpeg-%FFMPEG_VERSION%-full_build-shared
38 del ffmpeg-%FFMPEG_VERSION%-full_build-shared.zip
3539
3640 set SDL_INSTALL_PREFIX=%CD%
3741 set FFMPEG_INSTALL_PREFIX=%CD%
42 set PUBLIC_RELEASE=0
43 IF DEFINED FCEU_RELEASE_VERSION (set PUBLIC_RELEASE=1)
3844
3945 REM cmake -h
4046 REM cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DSDL_INSTALL_PREFIX=%SDL_INSTALL_PREFIX% ..
41 cmake -DQT6=0 -DSDL_INSTALL_PREFIX=%SDL_INSTALL_PREFIX% -DUSE_LIBAV=1 -DFFMPEG_INSTALL_PREFIX=%FFMPEG_INSTALL_PREFIX% -G"Visual Studio 16" -T"v142" ..
47 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" ..
4248
4349 REM nmake
4450 msbuild /m fceux.sln /p:Configuration=Release
45 @if ERRORLEVEL 1 goto end
51 if %ERRORLEVEL% NEQ 0 EXIT /B 1
4652
4753 copy src\Release\fceux.exe bin\qfceux.exe
54 copy %PROJECT_ROOT%\src\auxlib.lua bin\.
55 REM copy %PROJECT_ROOT%\src\drivers\win\lua\x64\lua51.dll bin\.
56 REM copy %PROJECT_ROOT%\src\drivers\win\lua\x64\lua5.1.dll bin\.
4857 copy %SDL_INSTALL_PREFIX%\SDL2\lib\x64\SDL2.dll bin\.
4958 copy %FFMPEG_INSTALL_PREFIX%\ffmpeg\bin\*.dll bin\.
5059
5160 windeployqt --no-compiler-runtime bin\qfceux.exe
5261
62 set ZIP_FILENAME=fceux-win64-QtSDL.zip
63 IF DEFINED FCEU_RELEASE_VERSION set ZIP_FILENAME=fceux-%FCEU_RELEASE_VERSION%-win64-QtSDL.zip
64
65 set DEPLOY_GROUP=master
66 IF DEFINED APPVEYOR_REPO_TAG_NAME set DEPLOY_GROUP=%APPVEYOR_REPO_TAG_NAME%
67
5368 dir bin
5469
5570 REM Create Zip Archive
56 %PROJECT_ROOT%\vc\zip -X -9 -r %PROJECT_ROOT%\vc\qfceux64.zip bin
57 @if ERRORLEVEL 1 goto end
71 %PROJECT_ROOT%\vc\zip -X -9 -r %PROJECT_ROOT%\vc\%ZIP_FILENAME% bin
72 if %ERRORLEVEL% NEQ 0 EXIT /B 1
5873
5974 cd %PROJECT_ROOT%\output
60 %PROJECT_ROOT%\vc\zip -X -9 -u -r %PROJECT_ROOT%\vc\qfceux64.zip palettes luaScripts tools
61 @if ERRORLEVEL 1 goto end
75 %PROJECT_ROOT%\vc\zip -X -9 -u -r %PROJECT_ROOT%\vc\%ZIP_FILENAME% palettes luaScripts tools
76 if %ERRORLEVEL% NEQ 0 EXIT /B 1
6277
6378 mkdir doc
6479 copy *.chm doc\.
65 %PROJECT_ROOT%\vc\zip -X -9 -u -r %PROJECT_ROOT%\vc\qfceux64.zip doc
66 @if ERRORLEVEL 1 goto end
80 %PROJECT_ROOT%\vc\zip -X -9 -u -r %PROJECT_ROOT%\vc\%ZIP_FILENAME% doc
81 if %ERRORLEVEL% NEQ 0 EXIT /B 1
6782
6883 cd %PROJECT_ROOT%
6984
70 appveyor PushArtifact %PROJECT_ROOT%\vc\qfceux64.zip
85 IF DEFINED APPVEYOR appveyor SetVariable -Name WIN64_QTSDL_ARTIFACT -Value %ZIP_FILENAME%
86 IF DEFINED APPVEYOR appveyor PushArtifact %PROJECT_ROOT%\vc\%ZIP_FILENAME%
7187
7288 :end
00
11 set PROJECT_ROOT=%~dp0..
2 set BUILD_CONFIG=Release
23
3 msbuild %PROJECT_ROOT%\vc\vc14_fceux.vcxproj /p:Configuration=Release /p:Platform="Win32"
4 @if ERRORLEVEL 1 goto end
4 set ZIP_FILENAME=fceux-win32.zip
5 if defined FCEU_RELEASE_VERSION set ZIP_FILENAME=fceux-%FCEU_RELEASE_VERSION%-win32.zip
6 if defined FCEU_RELEASE_VERSION set BUILD_CONFIG=PublicRelease
7
8 set DEPLOY_GROUP=master
9 IF DEFINED APPVEYOR_REPO_TAG_NAME set DEPLOY_GROUP=%APPVEYOR_REPO_TAG_NAME%
10
11 msbuild %PROJECT_ROOT%\vc\vc14_fceux.vcxproj /p:Configuration=%BUILD_CONFIG% /p:Platform="Win32"
12 if %ERRORLEVEL% NEQ 0 EXIT /B 1
513
614 cd %PROJECT_ROOT%\vc
715
816 REM Create Zip Archive
917 cd %PROJECT_ROOT%\output
10 ..\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
11 @if ERRORLEVEL 1 goto end
18 ..\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
19 if %ERRORLEVEL% NEQ 0 EXIT /B 1
1220
1321 cd %PROJECT_ROOT%
1422
15 appveyor PushArtifact %PROJECT_ROOT%\vc\fceux.zip
23 IF DEFINED APPVEYOR appveyor SetVariable -Name WIN32_ARTIFACT -Value %ZIP_FILENAME%
24 IF DEFINED APPVEYOR appveyor PushArtifact %PROJECT_ROOT%\vc\%ZIP_FILENAME%
1625
17 :end
26 :end
00
11 set PROJECT_ROOT=%~dp0..
2 set BUILD_CONFIG=Release
23
3 msbuild %PROJECT_ROOT%\vc\vc14_fceux.vcxproj /p:Configuration=Release /p:Platform="x64"
4 @if ERRORLEVEL 1 goto end
4 set ZIP_FILENAME=fceux-win64.zip
5 if defined FCEU_RELEASE_VERSION set ZIP_FILENAME=fceux-%FCEU_RELEASE_VERSION%-win64.zip
6 if defined FCEU_RELEASE_VERSION set BUILD_CONFIG=PublicRelease
7
8 set DEPLOY_GROUP=master
9 IF DEFINED APPVEYOR_REPO_TAG_NAME set DEPLOY_GROUP=%APPVEYOR_REPO_TAG_NAME%
10
11 msbuild %PROJECT_ROOT%\vc\vc14_fceux.vcxproj /p:Configuration=%BUILD_CONFIG% /p:Platform="x64"
12 if %ERRORLEVEL% NEQ 0 EXIT /B 1
513
614 cd %PROJECT_ROOT%\vc
715
816 REM Create Zip Archive
917
1018 cd %PROJECT_ROOT%\output
11 ..\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
12 @if ERRORLEVEL 1 goto end
13 ..\vc\zip -X -9 -u -r ..\vc\fceux64.zip fceux.chm taseditor.chm palettes luaScripts tools
14 @if ERRORLEVEL 1 goto end
19 ..\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
20 if %ERRORLEVEL% NEQ 0 EXIT /B 1
21 ..\vc\zip -X -9 -u -r ..\vc\%ZIP_FILENAME% fceux.chm taseditor.chm palettes luaScripts tools
22 if %ERRORLEVEL% NEQ 0 EXIT /B 1
1523
1624 cd %PROJECT_ROOT%
1725
18 appveyor PushArtifact %PROJECT_ROOT%\vc\fceux64.zip
26 IF DEFINED APPVEYOR appveyor SetVariable -Name WIN64_ARTIFACT -Value %ZIP_FILENAME%
27 IF DEFINED APPVEYOR appveyor PushArtifact %PROJECT_ROOT%\vc\%ZIP_FILENAME%
1928
2029 :end
44 ## Builds and Releases
55
66 Interim builds:
7 * Win32: [fceux.zip](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux.zip?branch=master&job=Windows%2032)
8 * Win64: [fceux64.zip](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/fceux64.zip?branch=master&job=Windows%2064)
9 * Win64 Qt/SDL: [qfceux64.zip](https://ci.appveyor.com/api/projects/zeromus/fceux/artifacts/qfceux64.zip?branch=master&job=Win64%20Qt)
10 * 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)
11 * 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)
7 * Win32: [fceux-win32.zip](https://github.com/TASEmulators/fceux/releases/download/interim-build/fceux-win32.zip)
8 * Win64: [fceux-win64.zip](https://github.com/TASEmulators/fceux/releases/download/interim-build/fceux-win64.zip)
9 * Win64 Qt/SDL: [fceux-win64-QtSDL.zip](https://github.com/TASEmulators/fceux/releases/download/interim-build/fceux-win64-QtSDL.zip)
10 * Ubuntu: [fceux-ubuntu-x64.deb](https://github.com/TASEmulators/fceux/releases/download/interim-build/fceux-ubuntu-x64.deb)
11 * MacOSX: [fceux-Darwin.dmg](https://github.com/TASEmulators/fceux/releases/download/interim-build/fceux-Darwin.dmg)
1212 * Status: [Appveyor](https://ci.appveyor.com/project/zeromus/fceux/)
1313
1414 But you might like mesen more: https://github.com/SourMesen/Mesen
0 #!/usr/bin/perl
1
2 use strict;
3 use File::Basename;
4 #use File::Spec;
5
6 my $format = 0;
7
8 foreach my $arg (@ARGV)
9 {
10 #print $arg, "\n";
11
12 if ($arg eq "-major")
13 {
14 $format = 1;
15 }
16 elsif ($arg eq "-minor")
17 {
18 $format = 2;
19 }
20 elsif ($arg eq "-patch")
21 {
22 $format = 3;
23 }
24 }
25
26 #my $file = File::Spec->rel2abs( __FILE__ );
27 my $dirname = dirname(__FILE__);
28 my $projRoot = "$dirname/..";
29 my $versionHeader = "$projRoot/src/version.h";
30 my $major = 1;
31 my $minor = 0;
32 my $patch = 0;
33
34 #print "File: $file\n";
35 #print "Dir $dirname\n";
36
37 my $line;
38
39 open INFILE, "$versionHeader" or die "Error: Could not open file: $versionHeader\n";
40 while ($line = <INFILE>)
41 {
42 #print $line;
43 if ($line =~ m/\s*#define\s+FCEU_VERSION_MAJOR\s+(\d+)/)
44 {
45 $major = $1;
46 }
47 elsif ($line =~ m/\s*#define\s+FCEU_VERSION_MINOR\s+(\d+)/)
48 {
49 $minor = $1;
50 }
51 elsif ($line =~ m/\s*#define\s+FCEU_VERSION_PATCH\s+(\d+)/)
52 {
53 $patch = $1;
54 }
55 }
56 close(INFILE);
57
58 if ($format == 1)
59 {
60 print "$major";
61 }
62 elsif ($format == 2)
63 {
64 print "$minor";
65 }
66 elsif ($format == 3)
67 {
68 print "$patch";
69 }
70 else
71 {
72 print "$major.$minor.$patch";
73 }
33 set(CMAKE_AUTOMOC ON)
44 set(CMAKE_AUTORCC ON)
55 set(CMAKE_AUTOUIC ON)
6
7 if (${PUBLIC_RELEASE})
8 add_definitions( -DPUBLIC_RELEASE=1 )
9 endif()
610
711 if ( ${QT6} )
812 message( STATUS "GUI Frontend: Qt6")
2731 include_directories( ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Help_INCLUDE_DIRS} )
2832 endif()
2933
34
3035 if(WIN32)
3136 find_package(OpenGL REQUIRED)
3237 #find_package(Qt5 COMPONENTS Widgets OpenGL REQUIRED)
3540 add_definitions( -DMSVC -D_CRT_SECURE_NO_WARNINGS )
3641 add_definitions( -D__SDL__ -D__QT_DRIVER__ -DQT_DEPRECATED_WARNINGS )
3742 add_definitions( -DFCEUDEF_DEBUGGER )
43 add_definitions( /wd4267 /wd4244 )
44 #add_definitions( /wd4018 ) # Integer comparison sign mismatch warnings
3845 include_directories( ${SDL_INSTALL_PREFIX}/SDL2/include )
3946 include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib )
4047 set( OPENGL_LDFLAGS OpenGL::GL )
7077 find_package(OpenGL REQUIRED)
7178 find_package(ZLIB REQUIRED)
7279
73 add_definitions( -Wall -Wno-write-strings -Wno-sign-compare -Wno-parentheses -Wno-unused-local-typedefs -fPIC )
80 add_definitions( -Wall -Wno-write-strings -Wno-parentheses -Wno-unused-local-typedefs -fPIC )
81 #add_definitions( -Wno-sign-compare ) # Integer comparison sign mismatch warnings
7482 add_definitions( -DFCEUDEF_DEBUGGER )
7583
7684 #if ( ${QT6} )
8391 # include_directories( ${Qt5Widgets_INCLUDE_DIRS} )
8492 #endif()
8593 add_definitions( -D__QT_DRIVER__ -DQT_DEPRECATED_WARNINGS )
94
95 if ( ${ASAN_ENABLE} )
96 add_definitions( -fsanitize=address -fsanitize=bounds-strict )
97 add_definitions( -fsanitize=undefined -fno-sanitize=vptr )
98 set( ASAN_LDFLAGS -lasan -lubsan)
99 message( STATUS "Address Sanitizer Enabled" )
100 else()
101 message( STATUS "Address Sanitizer Disabled" )
102 endif()
86103
87104 # Check for libminizip
88105 pkg_check_modules( MINIZIP REQUIRED minizip)
260277 ${CMAKE_CURRENT_SOURCE_DIR}/conddebug.cpp
261278 ${CMAKE_CURRENT_SOURCE_DIR}/config.cpp
262279 ${CMAKE_CURRENT_SOURCE_DIR}/debug.cpp
280 ${CMAKE_CURRENT_SOURCE_DIR}/debugsymboltable.cpp
263281 ${CMAKE_CURRENT_SOURCE_DIR}/drawing.cpp
264282 ${CMAKE_CURRENT_SOURCE_DIR}/fceu.cpp
265283 ${CMAKE_CURRENT_SOURCE_DIR}/fds.cpp
331349 ${CMAKE_CURRENT_SOURCE_DIR}/boards/32.cpp
332350 ${CMAKE_CURRENT_SOURCE_DIR}/boards/33.cpp
333351 ${CMAKE_CURRENT_SOURCE_DIR}/boards/34.cpp
352 ${CMAKE_CURRENT_SOURCE_DIR}/boards/354.cpp
334353 ${CMAKE_CURRENT_SOURCE_DIR}/boards/36.cpp
335354 ${CMAKE_CURRENT_SOURCE_DIR}/boards/3d-block.cpp
336355 ${CMAKE_CURRENT_SOURCE_DIR}/boards/40.cpp
381400 ${CMAKE_CURRENT_SOURCE_DIR}/boards/cheapocabra.cpp
382401 ${CMAKE_CURRENT_SOURCE_DIR}/boards/cityfighter.cpp
383402 ${CMAKE_CURRENT_SOURCE_DIR}/boards/coolboy.cpp
403 ${CMAKE_CURRENT_SOURCE_DIR}/boards/coolgirl.cpp
384404 ${CMAKE_CURRENT_SOURCE_DIR}/boards/dance2000.cpp
385405 ${CMAKE_CURRENT_SOURCE_DIR}/boards/datalatch.cpp
386406 ${CMAKE_CURRENT_SOURCE_DIR}/boards/dream.cpp
452472 ${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc7.cpp
453473 ${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc7p.cpp
454474 ${CMAKE_CURRENT_SOURCE_DIR}/boards/yoko.cpp
475 ${CMAKE_CURRENT_SOURCE_DIR}/boards/inx007t.cpp
455476 ${CMAKE_CURRENT_SOURCE_DIR}/input/arkanoid.cpp
456477 ${CMAKE_CURRENT_SOURCE_DIR}/input/bworld.cpp
457478 ${CMAKE_CURRENT_SOURCE_DIR}/input/cursor.cpp
480501 ${CMAKE_CURRENT_SOURCE_DIR}/utils/guid.cpp
481502 ${CMAKE_CURRENT_SOURCE_DIR}/utils/md5.cpp
482503 ${CMAKE_CURRENT_SOURCE_DIR}/utils/memory.cpp
504 ${CMAKE_CURRENT_SOURCE_DIR}/utils/mutex.cpp
483505 )
484506
485507
486508 set(SRC_DRIVERS_COMMON
487509 ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/args.cpp
488510 ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/cheat.cpp
489 ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/config.cpp
490511 ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/configSys.cpp
491512 ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/hq2x.cpp
492513 ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/hq3x.cpp
577598 # the FCEUX_BUILD_TIMESTAMP preprocessor definition.
578599 # Note: with CMake >= 3.8.0, this will respect SOURCE_DATE_EPOCH. For more info,
579600 # see <https://reproducible-builds.org/docs/source-date-epoch/>.
580 string(TIMESTAMP BUILD_TS "%H:%M:%S %b %d %Y")
601 string(TIMESTAMP BUILD_TS "%H:%M:%S %b %d %Y" UTC)
581602 add_definitions( -DFCEUX_BUILD_TIMESTAMP=\"${BUILD_TS}\" )
582603
583604 if (WIN32)
612633 ${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp)
613634 endif()
614635
615 target_link_libraries( ${APP_NAME}
636 target_link_libraries( ${APP_NAME} ${ASAN_LDFLAGS}
616637 ${${Qt}Widgets_LIBRARIES}
617638 ${${Qt}Help_LIBRARIES}
618639 ${${Qt}OpenGL_LIBRARIES}
4747 if (PRGsize[0] == CHRsize[0]) { // A9713 multigame extension hack!
4848 setchr1(A, V | ((EXPREGS[3] & 0x80) << 1));
4949 } else {
50 if ((A & 0x1000) == ((MMC3_cmd & 0x80) << 5))
50 if ((A & 0x1000) == static_cast<uint32>((MMC3_cmd & 0x80) << 5))
5151 setchr1(A, V | 0x100);
5252 else
5353 setchr1(A, V);
2121 #include "mmc3.h"
2222
2323 static void M187CW(uint32 A, uint8 V) {
24 if ((A & 0x1000) == ((MMC3_cmd & 0x80) << 5))
24 if ((A & 0x1000) == static_cast<uint32>((MMC3_cmd & 0x80) << 5))
2525 setchr1(A, V | 0x100);
2626 else
2727 setchr1(A, V);
00 /* FCE Ultra - NES/Famicom Emulator
1 *
2 * Copyright notice for this file:
3 * Copyright (C) 2011 CaH4e3
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
1 *
2 * Copyright notice for this file:
3 * Copyright (C) 2011 CaH4e3
4 * Copyright (C) 2019 Libretro Team
5 * Copyright (C) 2020
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 *
21 * PCB-018 board, discrete multigame cart 110-in-1
22 *
23 * Mapper 225
24 * Mapper 255
25 *
26 */
27
28 /* 2020-2-20 - merge mapper 255, re-implement extra RAM */
1929
2030 #include "mapinc.h"
2131
22 static uint8 prot[4], prg, mode, chr, mirr;
32 static uint8 extraRAM[4], prg, mode, chr, mirr;
2333
2434 static SFORMAT StateRegs[] =
2535 {
26 { prot, 4, "PROT" },
36 { extraRAM, 4, "PROT" },
2737 { &prg, 1, "PRG" },
2838 { &chr, 1, "CHR" },
2939 { &mode, 1, "MODE" },
3545 if (mode) {
3646 setprg16(0x8000, prg);
3747 setprg16(0xC000, prg);
38 } else
48 }
49 else
3950 setprg32(0x8000, prg >> 1);
4051 setchr8(chr);
4152 setmirror(mirr ^ 1);
4253 }
4354
4455 static DECLFW(M225Write) {
45 uint32 bank = (A >> 14) & 1;
56 uint8 bank = (A >> 14) & 1;
4657 mirr = (A >> 13) & 1;
4758 mode = (A >> 12) & 1;
4859 chr = (A & 0x3f) | (bank << 6);
5162 }
5263
5364 static DECLFW(M225LoWrite) {
54 if (A & 0x800) {
55 prot[A & 0x03] = V;
56 }
65 /* e.g. 115-in-1 [p1][!] CRC32 0xb39d30b4 */
66 if (A & 0x800) extraRAM[A & 3] = V & 0x0F;
5767 }
5868
5969 static DECLFR(M225LoRead) {
60 if (A & 0x800) {
61 return prot[A & 3] & 0x0F;
62 }
70 if (A & 0x800) return extraRAM[A & 3];
6371 return X.DB;
6472 }
6573
6674 static void M225Power(void) {
6775 prg = 0;
68 chr = 0;
6976 mode = 0;
70 mirr = 0;
7177 Sync();
72 SetReadHandler(0x5000, 0x5FFF, M225LoRead);
73 SetWriteHandler(0x5000, 0x5FFF, M225LoWrite);
78 SetReadHandler(0x5000, 0x5fff, M225LoRead);
79 SetWriteHandler(0x5000, 0x5fff, M225LoWrite);
7480 SetReadHandler(0x8000, 0xFFFF, CartBR);
7581 SetWriteHandler(0x8000, 0xFFFF, M225Write);
7682 }
7783
7884 static void M225Reset(void) {
7985 prg = 0;
80 chr = 0;
8186 mode = 0;
82 mirr = 0;
8387 Sync();
8488 }
8589
9397 GameStateRestore = StateRestore;
9498 AddExState(&StateRegs, ~0, 0, 0);
9599 }
100
101 void Mapper255_Init(CartInfo *info) {
102 Mapper225_Init(info);
103 }
1818 */
1919
2020 #include "mapinc.h"
21 #include "ines.h"
2122
22 static uint16 cmdreg;
23 static uint16 cmdreg = 0;
24 static uint8 openbus = 0;
25
26 // For carts with extra 128K prg rom (Contra)
27 static uint8 unrom = 0;
28 static uint8 unromData = 0;
29
30 static uint32 PRGROMSize = 0;
31
2332 static SFORMAT StateRegs[] =
2433 {
2534 { &cmdreg, 2, "CREG" },
35 { &openbus, 1, "OB" },
36 { &unrom, 1, "UROM" },
37 { &unromData, 1, "UDTA" },
2638 { 0 }
2739 };
2840
2941 static void Sync(void) {
30 if (cmdreg & 0x400)
31 setmirror(MI_0);
32 else
33 setmirror(((cmdreg >> 13) & 1) ^ 1);
34 if (cmdreg & 0x800) {
35 setprg16(0x8000, ((cmdreg & 0x300) >> 3) | ((cmdreg & 0x1F) << 1) | ((cmdreg >> 12) & 1));
36 setprg16(0xC000, ((cmdreg & 0x300) >> 3) | ((cmdreg & 0x1F) << 1) | ((cmdreg >> 12) & 1));
37 } else
38 setprg32(0x8000, ((cmdreg & 0x300) >> 4) | (cmdreg & 0x1F));
42 if (unrom) {
43 int PRGPageCount = PRGROMSize / (16 * 1024);
44 setprg16(0x8000, PRGPageCount & 0xC0 | (unromData & 7));
45 setprg16(0xC000, PRGPageCount & 0xC0 | 7);
46 setmirror(MI_V);
47 } else {
48 uint8 bank = ((cmdreg & 0x300) >> 3) | (cmdreg & 0x1F);
49 if (bank >= (PRGROMSize / (32 * 1024))) {
50 openbus = 1;
51 } else {
52 if (cmdreg & 0x400)
53 setmirror(MI_0);
54 else
55 setmirror(((cmdreg >> 13) & 1) ^ 1);
56 if (cmdreg & 0x800) {
57 setprg16(0x8000, (bank << 1) | ((cmdreg >> 12) & 1));
58 setprg16(0xC000, (bank << 1) | ((cmdreg >> 12) & 1));
59 } else
60 setprg32(0x8000, bank);
61 }
62 }
63 }
64
65 static DECLFR(M235Read) {
66 if (openbus) {
67 openbus = 0;
68 return X.DB;
69 }
70 return CartBR(A);
3971 }
4072
4173 static DECLFW(M235Write) {
4274 cmdreg = A;
75 unromData = V;
76 Sync();
77 }
78
79 static void M235Reset(void) {
80 cmdreg = 0;
81 unromData = 0;
82 if (PRGROMSize & 0x20000)
83 unrom = (unrom + 1) & 1;
4384 Sync();
4485 }
4586
4687 static void M235Power(void) {
4788 setchr8(0);
4889 SetWriteHandler(0x8000, 0xFFFF, M235Write);
49 SetReadHandler(0x8000, 0xFFFF, CartBR);
90 SetReadHandler(0x8000, 0xFFFF, M235Read);
5091 cmdreg = 0;
92 unromData = 0;
93 unrom = 0;
5194 Sync();
5295 }
5396
5699 }
57100
58101 void Mapper235_Init(CartInfo *info) {
102 info->Reset = M235Reset;
59103 info->Power = M235Power;
60104 GameStateRestore = M235Restore;
61105 AddExState(&StateRegs, ~0, 0, 0);
106
107 // needs raw, non-pow2 PRGROM size for comparison
108 PRGROMSize = head.ROM_size * 16384;
62109 }
0 /* FCEUmm - NES/Famicom Emulator
1 *
2 * Copyright notice for this file:
3 * Copyright (C) 2022
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include "mapinc.h"
21
22 static uint16 latchAddr;
23 static uint8 latchData;
24 static uint8 submapper;
25
26 static SFORMAT StateRegs[] =
27 {
28 { &latchAddr, 2, "ADDR" },
29 { &latchData, 1, "DATA" },
30 { 0 }
31 };
32
33 static void Mapper354_Sync(void)
34 {
35 int prg = latchData & 0x3F | latchAddr << 2 & 0x40 | latchAddr >> 5 & 0x80;
36 switch (latchAddr & 7)
37 {
38 case 0: case 4:
39 setprg32(0x8000, prg >> 1);
40 break;
41 case 1:
42 setprg16(0x8000, prg);
43 setprg16(0xC000, prg | 7);
44 break;
45 case 2: case 6:
46 setprg8(0x8000, prg << 1 | latchData >> 7);
47 setprg8(0xA000, prg << 1 | latchData >> 7);
48 setprg8(0xC000, prg << 1 | latchData >> 7);
49 setprg8(0xE000, prg << 1 | latchData >> 7);
50 break;
51 case 3: case 7:
52 setprg16(0x8000, prg);
53 setprg16(0xC000, prg);
54 break;
55 case 5:
56 setprg8(0x6000, prg << 1 | latchData >> 7);
57 setprg32(0x8000, prg >> 1 | 3);
58 break;
59 }
60 setchr8(0);
61 setmirror(latchData & 0x40 ? MI_H : MI_V);
62 }
63
64 static DECLFW(Mapper354_WriteLatch)
65 {
66 latchData = V;
67 latchAddr = A & 0xFFFF;
68 Mapper354_Sync();
69 }
70
71 static void Mapper354_Reset(void)
72 {
73 latchAddr = latchData = 0;
74 Mapper354_Sync();
75 }
76
77 static void Mapper354_Power(void)
78 {
79 latchAddr = latchData = 0;
80 SetReadHandler(0x6000, 0xFFFF, CartBR);
81 SetWriteHandler(submapper == 1 ? 0xE000 : 0xF000, 0xFFFF, Mapper354_WriteLatch);
82 Mapper354_Sync();
83 }
84
85 static void StateRestore(int version) {
86 Mapper354_Sync();
87 }
88
89 void Mapper354_Init(CartInfo *info)
90 {
91 submapper = info->submapper;
92 info->Power = Mapper354_Power;
93 info->Reset = Mapper354_Reset;
94 GameStateRestore = StateRestore;
95 AddExState(StateRegs, ~0, 0, 0);
96 }
121121 if ((latche & 0x81) == 0x81) {
122122 setprg32(0x8000, (latche & 0x38) >> 3);
123123 } else
124 FCEU_printf("unrecognized command %04!\n", latche);
124 FCEU_printf("unrecognized command %04x!\n", latche);
125125 setchr8(0);
126126 setmirror(0);
127127 }
2020 *
2121 * COOLBOY cartridges use registers at address $6xxx
2222 * MINDKIDS cartridges use a solder pad labelled "5/6K" to select between $5000 and $6000
23 *
23 *
2424 * $xxx0
2525 * 7 bit 0
2626 * ---- ----
2828 * |||| ||||
2929 * |||| |+++-- PRG offset (PRG A19, A18, A17)
3030 * |||| +----- Alternate CHR A17
31 * ||++------- PRG offset (PRG A24, A23)
31 * ||++------- PRG offset (PRG A24, A23), CHR offset (CHR A19, A18)
3232 * |+--------- PRG mask (PRG A17 from 0: MMC3; 1: offset)
3333 * +---------- CHR mask (CHR A17 from 0: MMC3; 1: alternate)
3434 *
3535 * $xxx1
36 *
3736 * 7 bit 0
3837 * ---- ----
3938 * GHIJ KKLx
5453 * $xxx3
5554 * 7 bit 0
5655 * ---- ----
57 * NPxP QQRx
58 * || | |||
59 * || | +++--- PRG offset for GNROM mode (PRG A16, A15, A14)
60 * || +------- 1: GNROM mode; 0: MMC3 mode
61 * || | (1: PRG A16...13 from QQ, L, R, CPU A14, A13 + CHR A16...10 from MMMM, PPU A12...10;
62 * || | 0: PRG A16...13 from MMC3 + CHR A16...A10 from MMC3 )
56 * NPZP QQRx
57 * |||| |||
58 * |||| +++--- PRG offset for GNROM mode (PRG A16, A15, A14)
59 * |||+------- 1: GNROM mode; 0: MMC3 mode
60 * |||| (1: PRG A16...13 from QQ, L, R, CPU A14, A13 + CHR A16...10 from MMMM, PPU A12...10;
61 * |||| 0: PRG A16...13 from MMC3 + CHR A16...A10 from MMC3 )
62 * ||+-------- 1: Also enable PRG RAM in $5000-$5FFF
6363 * |+-+------- Banking mode
6464 * |+--------- "Weird MMC3 mode"
65 * +---------- Lockout (prevent further writes to these four registers, only works in MMC3 mode)
65 * +---------- Lockout (prevent further writes to all registers but the one at $xxx2, only works in MMC3 mode)
6666 *
6767 * Also some new cartridges from MINDKIDS have /WE and /OE pins connected to mapper,
6868 * which allows you to rewrite flash memory without soldering.
7474
7575 #include "mapinc.h"
7676 #include "mmc3.h"
77
78 static void COOLBOYCW(uint32 A, uint8 V) {
79 uint32 mask = 0xFF ^ (EXPREGS[0] & 0x80);
80 if (EXPREGS[3] & 0x10) {
81 if (EXPREGS[3] & 0x40) { // Weird mode
77 #include "../ines.h"
78
79 const int ROM_CHIP = 0x00;
80 const int CFI_CHIP = 0x11;
81 const int FLASH_CHIP = 0x12;
82
83 const uint32 FLASH_SECTOR_SIZE = 128 * 1024;
84
85 extern uint8* WRAM;
86 static uint8* CFI = NULL;
87 static uint8* Flash = NULL;
88
89 static uint8 flash_save = 0;
90 static uint8 flash_state = 0;
91 static uint16 flash_buffer_a[10];
92 static uint8 flash_buffer_v[10];
93 static uint8 cfi_mode = 0;
94
95 static uint16 regs_base = 0;
96 static uint8 flag23 = 0;
97 static uint8 flag45 = 0;
98 static uint8 flag67 = 0;
99 static uint8 flag89 = 0;
100
101 // Macronix 256-mbit memory CFI data
102 const uint8 cfi_data[] =
103 {
104 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
105 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
106 0x51, 0x52, 0x59, 0x02, 0x00, 0x40, 0x00, 0x00,
107 0x00, 0x00, 0x00, 0x27, 0x36, 0x00, 0x00, 0x03,
108 0x06, 0x09, 0x13, 0x03, 0x05, 0x03, 0x02, 0x19,
109 0x02, 0x00, 0x06, 0x00, 0x01, 0xFF, 0x00, 0x00,
110 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
111 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
112 0x50, 0x52, 0x49, 0x31, 0x33, 0x14, 0x02, 0x01,
113 0x00, 0x08, 0x00, 0x00, 0x02, 0x95, 0xA5, 0x05,
114 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
115 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
116 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
117 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
118 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
119 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
120 };
121
122 static void AA6023CW(uint32 A, uint8 V) {
123 if (flag89) {
124 /*
125 $xxx0
126 7 bit 0
127 ---- ----
128 AB.C DEEE
129 || | ||||
130 || | |+++-- PRG offset (PRG A19, A18, A17)
131 || | +----- Alternate CHR A17
132 || +------- 1=Write-protect CHR-RAM
133 |+--------- PRG mask (PRG A17 from 0: MMC3; 1: offset)
134 +---------- CHR mask (CHR A17 from 0: MMC3; 1: alternate)
135 */
136 if (EXPREGS[0] & 0b00010000)
137 SetupCartCHRMapping(0, VROM, CHRsize[0], 0); // write-protect CHR-RAM
138 else
139 SetupCartCHRMapping(0, VROM, CHRsize[0], 1); // allow CHR writes
140 }
141
142 uint32 mask = 0xFF ^ (EXPREGS[0] & 0b10000000);
143 if (EXPREGS[3] & 0b00010000) {
144 if (EXPREGS[3] & 0b01000000) { // Weird mode
82145 int cbase = (MMC3_cmd & 0x80) << 5;
83146 switch (cbase ^ A) { // Don't even try do understand
84147 case 0x0400:
85148 case 0x0C00: V &= 0x7F; break;
86149 }
87150 }
88 // Highest bit goes from MMC3 registers when EXPREGS[3]&0x80==0 or from EXPREGS[0]&0x08 otherwise
151 // Highest bit goes from MMC3 registers when EXPREGS[0]&0x80==0 or from EXPREGS[0]&0x08 otherwise
89152 setchr1(A,
90 (V & 0x80 & mask) | ((((EXPREGS[0] & 0x08) << 4) & ~mask)) // 7th bit
153 (V & 0x80 & mask) | ((((EXPREGS[0] & 0b00001000) << 4) & ~mask)) // 7th bit
91154 | ((EXPREGS[2] & 0x0F) << 3) // 6-3 bits
92155 | ((A >> 10) & 7) // 2-0 bits
156 | ((EXPREGS[0] & 0b00110000) << 4) // There are some ROMs with 1 MiB CHR-ROM
93157 );
94 } else {
95 if (EXPREGS[3] & 0x40) { // Weird mode, again
158 }
159 else {
160 if (EXPREGS[3] & 0b01000000) { // Weird mode, again
96161 int cbase = (MMC3_cmd & 0x80) << 5;
97162 switch (cbase ^ A) { // Don't even try do understand
98163 case 0x0000: V = DRegBuf[0]; break;
102167 }
103168 }
104169 // Simple MMC3 mode
105 // Highest bit goes from MMC3 registers when EXPREGS[3]&0x80==0 or from EXPREGS[0]&0x08 otherwise
106 setchr1(A, (V & mask) | (((EXPREGS[0] & 0x08) << 4) & ~mask));
107 }
108 }
109
110 static void COOLBOYPW(uint32 A, uint8 V) {
111 uint32 mask = ((0x3F | (EXPREGS[1] & 0x40) | ((EXPREGS[1] & 0x20) << 2)) ^ ((EXPREGS[0] & 0x40) >> 2)) ^ ((EXPREGS[1] & 0x80) >> 2);
112 uint32 base = ((EXPREGS[0] & 0x07) >> 0) | ((EXPREGS[1] & 0x10) >> 1) | ((EXPREGS[1] & 0x0C) << 2) | ((EXPREGS[0] & 0x30) << 2);
170 // Highest bit goes from MMC3 registers when EXPREGS[0]&0x80==0 or from EXPREGS[0]&0x08 otherwise
171 setchr1(A,
172 (V & mask)
173 | (((EXPREGS[0] & 0x08) << 4) & ~mask)
174 | ((EXPREGS[0] & 0b00110000) << 4)); // There are some ROMs with 1 MiB CHR-ROM
175 }
176 }
177
178 static void AA6023PW(uint32 A, uint8 V) {
179 uint8 CREGS[] = {EXPREGS[0], EXPREGS[1], EXPREGS[2], EXPREGS[3]};
180 // Submappers has scrambled bits
181 if (flag23) {
182 /*
183 $xxx1
184 7 bit 0
185 ---- ----
186 GHIL JKKx
187 |||| |||
188 |||| +++--- PRG offset (in order: PRG A20, A21, A22)
189 |||+------- GNROM mode bank PRG size (0: 32 KiB bank, PRG A14=CPU A14; 1: 16 KiB bank, PRG A14=offset A14)
190 ||+-------- PRG mask (PRG A20 from 0: offset; 1: MMC3)
191 |+--------- PRG mask (PRG A19 from 0: offset; 1: MMC3)
192 +---------- PRG mask (PRG A18 from 0: MMC3; 1: offset)
193 */
194 CREGS[1] = (CREGS[1] & 0b11100101)
195 | ((CREGS[1] & 0b00001000) << 1) // PRG A20
196 | ((CREGS[1] & 0b00000010) << 2) // PRG A22
197 | ((((CREGS[1] ^ 0b00010000) & 0b00010000) >> 3)); // GNROM mode bank PRG size
198 }
199 if (flag45) {
200 /*
201 $xxx0
202 7 bit 0
203 ---- ----
204 ABCC DEEE
205 |||| ||||
206 |||| |+++-- PRG offset (PRG A19, A18, A17)
207 |||| +----- Alternate CHR A17
208 ||++------- PRG offset (PRG A21, A20)
209 |+--------- PRG mask (PRG A17 from 0: MMC3; 1: offset)
210 +---------- CHR mask (CHR A17 from 0: MMC3; 1: alternate)
211 $xxx1
212 7 bit 0
213 ---- ----
214 GHIx xxLx
215 ||| |
216 ||| +--- GNROM mode bank PRG size (1: 32 KiB bank, PRG A14=CPU A14; 0: 16 KiB bank, PRG A14=offset A14)
217 ||+-------- PRG mask (PRG A20 from 0: offset; 1: MMC3)
218 |+--------- PRG mask (PRG A19 from 0: offset; 1: MMC3)
219 +---------- PRG mask (PRG A18 from 0: MMC3; 1: offset)
220 */
221 CREGS[1] = (CREGS[1] & 0b11100011)
222 | ((CREGS[0] & 0b00100000) >> 3) // PRG A21
223 | (CREGS[0] & 0b00010000); // PRG A20
224 CREGS[0] &= 0b11001111;
225 }
226
227 uint32 mask = ((0b00111111 | (CREGS[1] & 0b01000000) | ((CREGS[1] & 0b00100000) << 2)) ^ ((CREGS[0] & 0b01000000) >> 2)) ^ ((CREGS[1] & 0b10000000) >> 2);
228 uint32 base = ((CREGS[0] & 0b00000111) >> 0) | ((CREGS[1] & 0b00010000) >> 1) | ((CREGS[1] & 0b00001100) << 2) | ((CREGS[0] & 0b00110000) << 2);
229
230 if (flash_save && cfi_mode) {
231 setprg32r(CFI_CHIP, 0x8000, 0);
232 return;
233 }
234
235 int chip = !flash_save ? ROM_CHIP : FLASH_CHIP;
236 // There are ROMs with multiple PRG ROM chips
237 int chip_offset = 0;
238 if (flag67 && EXPREGS[0] & 0b00001000) {
239 chip_offset += ROM_size;
240 }
113241
114242 // Very weird mode
115243 // Last banks are first in this mode, ignored when MMC3_cmd&0x40
116 if ((EXPREGS[3] & 0x40) && (V >= 0xFE) && !((MMC3_cmd & 0x40) != 0)) {
244 if ((CREGS[3] & 0b01000000) && (V >= 0xFE) && !((MMC3_cmd & 0x40) != 0)) {
117245 switch (A & 0xE000) {
118246 case 0xC000:
119247 case 0xE000:
122250 }
123251 }
124252
125 // Regular MMC3 mode, internal ROM size can be up to 2048kb!
126 if (!(EXPREGS[3] & 0x10))
127 setprg8(A, (((base << 4) & ~mask)) | (V & mask));
128 else { // NROM mode
253 if (!(CREGS[3] & 0x10)) {
254 // Regular MMC3 mode but can be extended to 2MiB
255 setprg8r(chip, A, ((((base << 4) & ~mask)) | (V & mask)) + chip_offset);
256 }
257 else {
258 // NROM mode
129259 mask &= 0xF0;
130260 uint8 emask;
131 if ((((EXPREGS[1] & 2) != 0))) // 32kb mode
132 emask = (EXPREGS[3] & 0x0C) | ((A & 0x4000) >> 13);
261 if (CREGS[1] & 0b00000010) // 32kb mode
262 emask = (CREGS[3] & 0b00001100) | ((A & 0x4000) >> 13);
133263 else // 16kb mode
134 emask = EXPREGS[3] & 0x0E;
135 setprg8(A, ((base << 4) & ~mask) // 7-4 bits are from base (see below)
136 | (V & mask) // ... or from MM3 internal regs, depends on mask
137 | emask // 3-1 (or 3-2 when (EXPREGS[3]&0x0C is set) from EXPREGS[3]
138 | ((A & 0x2000) >> 13)); // 0th just as is
139 }
140 }
141
142 static DECLFW(COOLBOYWrite) {
143 if(A001B & 0x80)
144 CartBW(A,V);
264 emask = CREGS[3] & 0b00001110;
265 setprg8r(chip, A, (
266 ((base << 4) & ~mask) // 7-4 bits are from base
267 | (V & mask) // ... or from MM3 internal regs, depends on mask
268 | emask // 3-1 (or 3-2 when (EXPREGS[3]&0x0C is set) from EXPREGS[3]
269 | ((A & 0x2000) >> 13) // 0th just as is
270 ) + chip_offset); // For multi-chip ROMs
271 }
272 }
273
274 static DECLFW(AA6023WramWrite) {
275 if (A001B & 0x80)
276 CartBW(A, V);
277 }
278
279 static DECLFW(AA6023Write) {
280 if (A >= 0x6000) {
281 AA6023WramWrite(A, V);
282 }
145283
146284 // Deny any further writes when 7th bit is 1 AND 4th is 0
147285 if ((EXPREGS[3] & 0x90) != 0x80) {
148286 EXPREGS[A & 3] = V;
149 FixMMC3PRG(MMC3_cmd);
150 FixMMC3CHR(MMC3_cmd);
151 }
152 }
153
154 static void COOLBOYReset(void) {
287 }
288 FixMMC3PRG(MMC3_cmd);
289 FixMMC3CHR(MMC3_cmd);
290 }
291
292 static DECLFW(AA6023FlashWrite) {
293 if (A < 0xC000)
294 MMC3_CMDWrite(A, V);
295 else
296 MMC3_IRQWrite(A, V);
297
298 if (!flash_save) return;
299 if (flash_state < sizeof(flash_buffer_a) / sizeof(flash_buffer_a[0])) {
300 flash_buffer_a[flash_state] = A & 0xFFF;
301 flash_buffer_v[flash_state] = V;
302 flash_state++;
303
304 // enter CFI mode
305 if ((flash_state == 1) &&
306 (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0x98)) {
307 cfi_mode = 1;
308 flash_state = 0;
309 }
310
311 // erase sector
312 if ((flash_state == 6) &&
313 (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) &&
314 (flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) &&
315 (flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0x80) &&
316 (flash_buffer_a[3] == 0x0AAA) && (flash_buffer_v[3] == 0xAA) &&
317 (flash_buffer_a[4] == 0x0555) && (flash_buffer_v[4] == 0x55) &&
318 (flash_buffer_v[5] == 0x30)) {
319 int offset = &Page[A >> 11][A] - Flash;
320 int sector = offset / FLASH_SECTOR_SIZE;
321 for (uint32 i = sector * FLASH_SECTOR_SIZE; i < (sector + 1) * FLASH_SECTOR_SIZE; i++)
322 Flash[i % PRGsize[ROM_CHIP]] = 0xFF;
323 FCEU_printf("Flash sector #%d is erased (0x%08x - 0x%08x).\n", sector, offset, offset + FLASH_SECTOR_SIZE);
324 flash_state = 0;
325 }
326
327 // erase chip, lol
328 if ((flash_state == 6) &&
329 (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) &&
330 (flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) &&
331 (flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0x80) &&
332 (flash_buffer_a[3] == 0x0AAA) && (flash_buffer_v[3] == 0xAA) &&
333 (flash_buffer_a[4] == 0x0555) && (flash_buffer_v[4] == 0x55) &&
334 (flash_buffer_v[5] == 0x10)) {
335 memset(Flash, 0xFF, PRGsize[ROM_CHIP]);
336 FCEU_printf("Flash chip erased.\n");
337 flash_state = 0;
338 }
339
340 // write byte
341 if ((flash_state == 4) &&
342 (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) &&
343 (flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) &&
344 (flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0xA0)) {
345 int offset = &Page[A >> 11][A] - Flash;
346 if (CartBR(A) != 0xFF) {
347 FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased.\n", offset);
348 }
349 else {
350 CartBW(A, V);
351 }
352 flash_state = 0;
353 }
354 }
355
356 // not a command
357 if (((A & 0xFFF) != 0x0AAA) && ((A & 0xFFF) != 0x0555)) {
358 flash_state = 0;
359 }
360
361 // reset
362 if (V == 0xF0) {
363 flash_state = 0;
364 cfi_mode = 0;
365 }
366
367 FixMMC3PRG(MMC3_cmd);
368 }
369
370 static void AA6023Reset(void) {
155371 MMC3RegReset();
156372 EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
373 flash_state = 0;
374 cfi_mode = 0;
157375 FixMMC3PRG(MMC3_cmd);
158376 FixMMC3CHR(MMC3_cmd);
159377 }
160378
161 static void COOLBOYPower(void) {
379 static void AA6023Power(void) {
162380 GenMMC3Power();
163381 EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
164382 FixMMC3PRG(MMC3_cmd);
165383 FixMMC3CHR(MMC3_cmd);
166 SetWriteHandler(0x5000, 0x5fff, CartBW); // some games access random unmapped areas and crashes because of KT-008 PCB hack in MMC3 source lol
167 SetWriteHandler(0x6000, 0x6fff, COOLBOYWrite);
168 }
169
170 static void MINDKIDSPower(void) {
171 GenMMC3Power();
172 EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0;
384 if (regs_base != 0x5000)
385 SetWriteHandler(0x5000, 0x5fff, CartBW); // some games access random unmapped areas and crashes because of KT-008 PCB hack in MMC3 source lol
386 SetWriteHandler(0x6000, 0x7fff, AA6023WramWrite);
387 SetWriteHandler(regs_base, regs_base + 0x0fff, AA6023Write);
388 SetWriteHandler(0x8000, 0xFFFF, AA6023FlashWrite);
389 SetReadHandler(0x8000, 0xFFFF, CartBR);
390 }
391
392 static void AA6023Restore(int version) {
173393 FixMMC3PRG(MMC3_cmd);
174394 FixMMC3CHR(MMC3_cmd);
175 SetWriteHandler(0x5000, 0x5fff, COOLBOYWrite);
176 }
177
178 // Registers at $6xxx
179 void COOLBOY_Init(CartInfo *info) {
180 GenMMC3_Init(info, 2048, 256, 8, 1);
181 pwrap = COOLBOYPW;
182 cwrap = COOLBOYCW;
183 info->Power = COOLBOYPower;
184 info->Reset = COOLBOYReset;
185 AddExState(EXPREGS, 4, 0, "EXPR");
186 }
187
188 // Registers at $5xxx
189 void MINDKIDS_Init(CartInfo *info) {
190 GenMMC3_Init(info, 2048, 256, 8, 1);
191 pwrap = COOLBOYPW;
192 cwrap = COOLBOYCW;
193 info->Power = MINDKIDSPower;
194 info->Reset = COOLBOYReset;
195 AddExState(EXPREGS, 4, 0, "EXPR");
196 }
197
198 // For NES 2.0 loader
199 void SMD132_SMD133_Init(CartInfo *info) {
200 switch (info->submapper)
395 }
396
397 static void AA6023Close(void) {
398 if (WRAM)
399 FCEU_gfree(WRAM);
400 if (Flash)
401 FCEU_gfree(Flash);
402 if (CFI)
403 FCEU_gfree(CFI);
404 WRAM = Flash = CFI = NULL;
405 }
406
407 void CommonInit(CartInfo* info, int submapper)
408 {
409 GenMMC3_Init(info, 2048, info->vram_size / 1024, !info->ines2 ? 8 : (info->wram_size + info->battery_wram_size) / 1024, info->battery);
410 pwrap = AA6023PW;
411 cwrap = AA6023CW;
412
413 switch (submapper)
201414 {
415 case 2:
416 regs_base = 0x7000;
417 break;
202418 case 0:
203 COOLBOY_Init(info);
419 case 4:
420 case 6:
421 case 8:
422 regs_base = 0x6000;
204423 break;
205424 case 1:
206 MINDKIDS_Init(info);
425 case 3:
426 case 5:
427 case 7:
428 case 9:
429 regs_base = 0x5000;
207430 break;
208431 default:
209 FCEU_PrintError("Unknown submapper: #%d.", info->submapper);
210 break;
211 }
212 }
432 FCEU_PrintError("Submapper #%d is not supported", submapper);
433 }
434 flag23 = (submapper == 2) || (submapper == 3);
435 flag45 = (submapper == 4) || (submapper == 5);
436 flag67 = (submapper == 6) || (submapper == 7);
437 flag89 = (submapper == 8) || (submapper == 9);
438 info->Power = AA6023Power;
439 info->Reset = AA6023Reset;
440 info->Close = AA6023Close;
441 GameStateRestore = AA6023Restore;
442
443 flash_save = info->battery;
444
445 if (flash_save) {
446 CFI = (uint8*)FCEU_gmalloc(sizeof(cfi_data) * 2);
447 for (size_t i = 0; i < sizeof(cfi_data); i++) {
448 CFI[i * 2] = CFI[i * 2 + 1] = cfi_data[i];
449 }
450 SetupCartPRGMapping(CFI_CHIP, CFI, sizeof(cfi_data) * 2, 0);
451 Flash = (uint8*)FCEU_gmalloc(PRGsize[ROM_CHIP]);
452 for (unsigned int i = 0; i < PRGsize[ROM_CHIP]; i++) {
453 Flash[i] = PRGptr[ROM_CHIP][i % PRGsize[ROM_CHIP]];
454 }
455 SetupCartPRGMapping(FLASH_CHIP, Flash, PRGsize[ROM_CHIP], 1);
456 info->SaveGame[1] = Flash;
457 info->SaveGameLen[1] = PRGsize[ROM_CHIP];
458 }
459
460 AddExState(EXPREGS, 4, 0, "EXPR");
461 if (flash_save)
462 {
463 AddExState(&flash_state, sizeof(flash_state), 0, "FLST");
464 AddExState(flash_buffer_a, sizeof(flash_buffer_a), 0, "FLBA");
465 AddExState(flash_buffer_v, sizeof(flash_buffer_v), 0, "FLBV");
466 AddExState(&cfi_mode, sizeof(cfi_mode), 0, "CFIM");
467 AddExState(Flash, PRGsize[ROM_CHIP], 0, "FLAS");
468 }
469 }
470
471 // Registers at $6xxx
472 void COOLBOY_Init(CartInfo* info) {
473 CommonInit(info, 0);
474 }
475
476 // Registers at $5xxx
477 void MINDKIDS_Init(CartInfo* info) {
478 CommonInit(info, 1);
479 }
480
481 // For NES 2.0 loader
482 void AA6023_Init(CartInfo* info) {
483 CommonInit(info, info->submapper);
484 }
0 /* FCE Ultra - NES/Famicom Emulator
1 *
2 * Copyright notice for this file:
3 * Copyright (C) 2022 Cluster
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * Very complicated homebrew multicart mapper with.
20 * The code is so obscured and weird because it's ported from Verilog CPLD source code:
21 * https://github.com/ClusterM/coolgirl-famicom-multicart/blob/master/CoolGirl_mappers.vh
22 *
23 * Range: $5000-$5FFF
24 *
25 * Mask: $5007
26 *
27 * All registers are $00 on power-on and reset.
28 *
29 * $5xx0
30 * 7 bit 0
31 * ---- ----
32 * PPPP PPPP
33 * |||| ||||
34 * ++++-++++-- PRG base offset (A29-A22)
35 *
36 * $5xx1
37 * 7 bit 0
38 * ---- ----
39 * PPPP PPPP
40 * |||| ||||
41 * ++++-++++-- PRG base offset (A21-A14)
42 *
43 * $5xx2
44 * 7 bit 0
45 * ---- ----
46 * AMMM MMMM
47 * |||| ||||
48 * |+++-++++-- PRG mask (A20-A14, inverted+anded with PRG address)
49 * +---------- CHR mask (A18, inverted+anded with CHR address)
50 *
51 * $5xx3
52 * 7 bit 0
53 * ---- ----
54 * BBBC CCCC
55 * |||| ||||
56 * |||+-++++-- CHR bank A (bits 7-3)
57 * +++-------- PRG banking mode (see below)
58 *
59 * $5xx4
60 * 7 bit 0
61 * ---- ----
62 * DDDE EEEE
63 * |||| ||||
64 * |||+-++++-- CHR mask (A17-A13, inverted+anded with CHR address)
65 * +++-------- CHR banking mode (see below)
66 *
67 * $5xx5
68 * 7 bit 0
69 * ---- ----
70 * CDDE EEWW
71 * |||| ||||
72 * |||| ||++-- 8KiB WRAM page at $6000-$7FFF
73 * |+++-++---- PRG bank A (bits 5-1)
74 * +---------- CHR bank A (bit 8)
75 *
76 * $5xx6
77 * 7 bit 0
78 * ---- ----
79 * FFFM MMMM
80 * |||| ||||
81 * |||+ ++++-- Mapper code (bits 4-0, see below)
82 * +++-------- Flags 2-0, functionality depends on selected mapper
83 *
84 * $5xx7
85 * 7 bit 0
86 * ---- ----
87 * LMTR RSNO
88 * |||| |||+-- Enable WRAM (read and write) at $6000-$7FFF
89 * |||| ||+--- Allow writes to CHR RAM
90 * |||| |+---- Allow writes to flash chip
91 * |||+-+----- Mirroring (00=vertical, 01=horizontal, 10=1Sa, 11=1Sb)
92 * ||+-------- Enable four-screen mode
93 * |+-- ------ Mapper code (bit 5, see below)
94 * +---------- Lockout bit (prevent further writes to all registers)
95 *
96 */
97
98 #include "mapinc.h"
99
100 const uint32 SAVE_FLASH_SIZE = 1024 * 1024 * 8;
101 const uint32 FLASH_SECTOR_SIZE = 128 * 1024;
102 const int ROM_CHIP = 0x00;
103 const int WRAM_CHIP = 0x10;
104 const int FLASH_CHIP = 0x11;
105 const int CHR_RAM_CHIP = 0x12;
106 const int CFI_CHIP = 0x13;
107
108 static uint32 WRAM_SIZE = 0;
109 static uint8 *WRAM = NULL;
110 static uint32 CHR_RAM_SIZE = 0;
111 static uint8 *CHR_RAM;
112 static uint8 *SAVE_FLASH = NULL;
113 static uint8* CFI;
114
115 static uint8 sram_enabled = 0;
116 static uint8 sram_page = 0; // [1:0]
117 static uint8 can_write_chr = 0;
118 static uint8 map_rom_on_6000 = 0;
119 static uint8 flags = 0; // [2:0]
120 static uint8 mapper = 0; // [5:0]
121 static uint8 can_write_flash = 0;
122 static uint8 mirroring = 0; // [1:0]
123 static uint8 four_screen = 0;
124 static uint8 lockout = 0;
125
126 static uint32 prg_base = 0; // [26:14]
127 static uint32 prg_mask = 0b11111000 << 14; // 11111000, 128KB // [20:14]
128 static uint8 prg_mode = 0; // [2:0]
129 static uint8 prg_bank_6000 = 0; // [7:0]
130 static uint8 prg_bank_a = 0; // [7:0]
131 static uint8 prg_bank_b = 1; // [7:0]
132 static uint8 prg_bank_c = ~1; // [7:0]
133 static uint8 prg_bank_d = ~0; // [7:0]
134
135 static uint32 chr_mask = 0; // [18:13]
136 static uint8 chr_mode = 0; // [2:0]
137 static uint16 chr_bank_a = 0; // [8:0]
138 static uint16 chr_bank_b = 1; // [8:0]
139 static uint16 chr_bank_c = 2; // [8:0]
140 static uint16 chr_bank_d = 3; // [8:0]
141 static uint16 chr_bank_e = 4; // [8:0]
142 static uint16 chr_bank_f = 5; // [8:0]
143 static uint16 chr_bank_g = 6; // [8:0]
144 static uint16 chr_bank_h = 7; // [8:0]
145
146 static uint8 TKSMIR[8];
147
148 static uint32 prg_bank_6000_mapped = 0;
149 static uint32 prg_bank_a_mapped = 0;
150 static uint32 prg_bank_b_mapped = 0;
151 static uint32 prg_bank_c_mapped = 0;
152 static uint32 prg_bank_d_mapped = 0;
153
154 // for MMC2/MMC4
155 static uint8 ppu_latch0 = 0;
156 static uint8 ppu_latch1 = 0;
157 // for MMC1
158 static uint64 lreset = 0;
159 static uint8 mmc1_load_register = 0; // [5:0]
160 // for MMC3
161 static uint8 mmc3_internal = 0; // [2:0]
162 // for mapper #69
163 static uint8 mapper69_internal = 0; // [3:0]
164 // for mapper #112
165 static uint8 mapper112_internal = 0; // [2:0]
166 // for mapper #163
167 static uint8 mapper_163_latch = 0;
168 static uint8 mapper163_r0 = 0; // [7:0]
169 static uint8 mapper163_r1 = 0; // [7:0]
170 static uint8 mapper163_r2 = 0; // [7:0]
171 static uint8 mapper163_r3 = 0; // [7:0]
172 static uint8 mapper163_r4 = 0; // [7:0]
173 static uint8 mapper163_r5 = 0; // [7:0]
174
175 // For mapper #90
176 static uint8 mul1 = 0;
177 static uint8 mul2 = 0;
178
179 // for MMC3 scanline-based interrupts, counts A12 rises after long A12 falls
180 static uint8 mmc3_irq_enabled = 0; // register to enable/disable counter
181 static uint8 mmc3_irq_latch = 0; // [7:0], stores counter reload latch value
182 static uint8 mmc3_irq_counter = 0; // [7:0], counter itself (downcounting)
183 static uint8 mmc3_irq_reload = 0; // flag to reload counter from latch
184 // for MMC5 scanline-based interrupts, counts dummy PPU reads
185 static uint8 mmc5_irq_enabled = 0; // register to enable/disable counter
186 static uint8 mmc5_irq_line = 0; // [7:0], scanline on which IRQ will be triggered
187 static uint8 mmc5_irq_out = 0; // stores 1 when IRQ is triggered
188 // for mapper #18
189 static uint16 mapper18_irq_value = 0; // [15:0], counter itself (downcounting)
190 static uint8 mapper18_irq_control = 0; // [3:0], IRQ settings
191 static uint16 mapper18_irq_latch = 0; // [15:0], stores counter reload latch value
192 // for mapper #65
193 static uint8 mapper65_irq_enabled = 0; // register to enable/disable IRQ
194 static uint16 mapper65_irq_value = 0; // [15:0], counter itself (downcounting)
195 static uint16 mapper65_irq_latch = 0; // [15:0], stores counter reload latch value
196 // reg mapper65_irq_out = 0;
197 // for Sunsoft FME-7
198 static uint8 mapper69_irq_enabled = 0; // register to enable/disable IRQ
199 static uint8 mapper69_counter_enabled = 0; // register to enable/disable counter
200 static uint16 mapper69_irq_value = 0; // counter itself (downcounting)
201 // for VRC4 CPU-based interrupts
202 static uint8 vrc4_irq_value = 0; // [7:0], counter itself (upcounting)
203 static uint8 vrc4_irq_control = 0; // [2:0]� IRQ settings
204 static uint8 vrc4_irq_latch = 0; // [7:0], stores counter reload latch value
205 static uint8 vrc4_irq_prescaler = 0; // [6:0], prescaler counter for VRC4
206 static uint8 vrc4_irq_prescaler_counter = 0; // prescaler cicles counter for VRC4
207 // for VRC3 CPU-based interrupts
208 static uint16 vrc3_irq_value = 0; // [15:0], counter itself (upcounting)
209 static uint8 vrc3_irq_control = 0; // [3:0], IRQ settings
210 static uint16 vrc3_irq_latch = 0; // [15:0], stores counter reload latch value
211 // for mapper #42 (only Baby Mario)
212 static uint8 mapper42_irq_enabled = 0; // register to enable/disable counter
213 static uint16 mapper42_irq_value = 0; // [14:0], counter itself (upcounting)
214 // for mapper #83
215 static uint8 mapper83_irq_enabled_latch = 0;
216 static uint8 mapper83_irq_enabled = 0;
217 static uint16 mapper83_irq_counter = 0;
218 // for mapper #90
219 static uint8 mapper90_xor = 0;
220 // for mapper #67
221 static uint8 mapper67_irq_enabled = 0;
222 static uint8 mapper67_irq_latch = 0;
223 static uint16 mapper67_irq_counter = 0;
224
225 static uint8 flash_state = 0;
226 static uint16 flash_buffer_a[10];
227 static uint8 flash_buffer_v[10];
228 static uint8 cfi_mode = 0;
229
230 // Micron 4-gbit memory CFI data
231 const uint8 cfi_data[] =
232 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
233 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
234 0x51, 0x52, 0x59, 0x02, 0x00, 0x40, 0x00, 0x00,
235 0x00, 0x00, 0x00, 0x27, 0x36, 0x00, 0x00, 0x06,
236 0x06, 0x09, 0x13, 0x03, 0x05, 0x03, 0x02, 0x1E,
237 0x02, 0x00, 0x06, 0x00, 0x01, 0xFF, 0x03, 0x00,
238 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
239 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
240 0x50, 0x52, 0x49, 0x31, 0x33, 0x14, 0x02, 0x01,
241 0x00, 0x08, 0x00, 0x00, 0x02, 0xB5, 0xC5, 0x05,
242 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
243 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
244 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
245 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
246 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
247 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
248
249 #define SET_BITS(target, target_bits, source, source_bits) target = set_bits(target, target_bits, get_bits(source, source_bits))
250
251 static inline uint8 string_to_bits(char* bitsstr, int* bits)
252 {
253 uint8 bit1, bit2, count = 0;
254 for (int i = 0; i < 32; i++)
255 bits[i] = -1;
256 while (*bitsstr)
257 {
258 bit1 = 0;
259 bit2 = 0;
260 if (isdigit(*bitsstr))
261 {
262 while (isdigit(*bitsstr))
263 {
264 bit1 *= 10;
265 bit1 += *bitsstr - '0';
266 bitsstr++;
267 }
268 if (*bitsstr == ':')
269 {
270 bitsstr++;
271 while (isdigit(*bitsstr))
272 {
273 bit2 *= 10;
274 bit2 += *bitsstr - '0';
275 bitsstr++;
276 }
277 if (bit2 < bit1)
278 for (int i = bit1; i >= bit2; i--)
279 {
280 bits[count] = i;
281 count++;
282 }
283 else
284 for (int i = bit1; i <= bit2; i++)
285 {
286 bits[count] = i;
287 count++;
288 }
289 }
290 else {
291 bits[count] = bit1;
292 count++;
293 }
294 }
295 else {
296 bitsstr++;
297 }
298 }
299 return count;
300 }
301
302 static inline uint32 get_bits(uint32 V, char* bitsstr)
303 {
304 uint32 result = 0;
305 int bits[32];
306 string_to_bits(bitsstr, bits);
307 for (int i = 0; bits[i] >= 0; i++)
308 {
309 result <<= 1;
310 result |= (V >> bits[i]) & 1;
311 }
312 return result;
313 }
314
315 static inline uint32 set_bits(uint32 V, char* bitsstr, uint32 new_bits)
316 {
317 int bits[32];
318 uint8 count = string_to_bits(bitsstr, bits);
319 for (int i = 0; i < count; i++)
320 {
321 if ((new_bits >> (count - i - 1)) & 1)
322 V |= 1 << bits[i];
323 else
324 V &= ~(1 << bits[i]);
325 }
326 return V;
327 }
328
329 static void COOLGIRL_Sync_PRG(void) {
330 prg_bank_6000_mapped = (prg_base >> 13) | (prg_bank_6000 & ((~(prg_mask >> 13) & 0xFE) | 1));
331 prg_bank_a_mapped = (prg_base >> 13) | (prg_bank_a & ((~(prg_mask >> 13) & 0xFE) | 1));
332 prg_bank_b_mapped = (prg_base >> 13) | (prg_bank_b & ((~(prg_mask >> 13) & 0xFE) | 1));
333 prg_bank_c_mapped = (prg_base >> 13) | (prg_bank_c & ((~(prg_mask >> 13) & 0xFE) | 1));
334 prg_bank_d_mapped = (prg_base >> 13) | (prg_bank_d & ((~(prg_mask >> 13) & 0xFE) | 1));
335 uint8 REG_A_CHIP = (SAVE_FLASH != NULL && prg_bank_a_mapped >= 0x20000 - SAVE_FLASH_SIZE / 1024 / 8) ? FLASH_CHIP : ROM_CHIP;
336 uint8 REG_B_CHIP = (SAVE_FLASH != NULL && prg_bank_b_mapped >= 0x20000 - SAVE_FLASH_SIZE / 1024 / 8) ? FLASH_CHIP : ROM_CHIP;
337 uint8 REG_C_CHIP = (SAVE_FLASH != NULL && prg_bank_c_mapped >= 0x20000 - SAVE_FLASH_SIZE / 1024 / 8) ? FLASH_CHIP : ROM_CHIP;
338 uint8 REG_D_CHIP = (SAVE_FLASH != NULL && prg_bank_d_mapped >= 0x20000 - SAVE_FLASH_SIZE / 1024 / 8) ? FLASH_CHIP : ROM_CHIP;
339
340 if (!cfi_mode || !SAVE_FLASH)
341 {
342 switch (prg_mode & 7)
343 {
344 default:
345 case 0:
346 setprg16r(REG_A_CHIP, 0x8000, prg_bank_a_mapped >> 1);
347 setprg16r(REG_C_CHIP, 0xC000, prg_bank_c_mapped >> 1);
348 break;
349 case 1:
350 setprg16r(REG_C_CHIP, 0x8000, prg_bank_c_mapped >> 1);
351 setprg16r(REG_A_CHIP, 0xC000, prg_bank_a_mapped >> 1);
352 break;
353 case 4:
354 setprg8r(REG_A_CHIP, 0x8000, prg_bank_a_mapped);
355 setprg8r(REG_B_CHIP, 0xA000, prg_bank_b_mapped);
356 setprg8r(REG_C_CHIP, 0xC000, prg_bank_c_mapped);
357 setprg8r(REG_D_CHIP, 0xE000, prg_bank_d_mapped);
358 break;
359 case 5:
360 setprg8r(REG_C_CHIP, 0x8000, prg_bank_c_mapped);
361 setprg8r(REG_B_CHIP, 0xA000, prg_bank_b_mapped);
362 setprg8r(REG_A_CHIP, 0xC000, prg_bank_a_mapped);
363 setprg8r(REG_D_CHIP, 0xE000, prg_bank_d_mapped);
364 break;
365 case 6:
366 setprg32r(REG_A_CHIP, 0x8000, prg_bank_b_mapped >> 2);
367 break;
368 case 7:
369 setprg32r(REG_A_CHIP, 0x8000, prg_bank_a_mapped >> 2);
370 break;
371 }
372 }
373 else {
374 setprg32r(CFI_CHIP, 0x8000, 0);
375 }
376
377 if (!map_rom_on_6000 && WRAM)
378 setprg8r(WRAM_CHIP, 0x6000, sram_page); // Select SRAM page
379 else if (map_rom_on_6000)
380 setprg8(0x6000, prg_bank_6000_mapped); // Map ROM on $6000-$7FFF
381 }
382
383 static void COOLGIRL_Sync_CHR(void) {
384 // calculate CHR shift
385 // wire shift_chr_right = ENABLE_MAPPER_021_022_023_025 && ENABLE_MAPPER_022 && (mapper == 6'b011000) && flags[1];
386 int chr_shift_right = ((mapper == 0b011000) && (flags & 0b010)) ? 1 : 0;
387 int chr_shift_left = 0;
388
389 // enable or disable writes to CHR RAM, setup CHR mask
390 SetupCartCHRMapping(CHR_RAM_CHIP, CHR_RAM, ((((~(chr_mask >> 13) & 0x3F) + 1) * 0x2000 - 1) & (CHR_RAM_SIZE - 1)) + 1, can_write_chr);
391
392 switch (chr_mode & 7)
393 {
394 default:
395 case 0:
396 setchr8r(0x12, chr_bank_a >> 3 >> chr_shift_right << chr_shift_left);
397 break;
398 case 1:
399 setchr4r(0x12, 0x0000, mapper_163_latch >> chr_shift_right << chr_shift_left);
400 setchr4r(0x12, 0x1000, mapper_163_latch >> chr_shift_right << chr_shift_left);
401 break;
402 case 2:
403 setchr2r(0x12, 0x0000, chr_bank_a >> 1 >> chr_shift_right << chr_shift_left);
404 TKSMIR[0] = TKSMIR[1] = chr_bank_a;
405 setchr2r(0x12, 0x0800, chr_bank_c >> 1 >> chr_shift_right << chr_shift_left);
406 TKSMIR[2] = TKSMIR[3] = chr_bank_c;
407 setchr1r(0x12, 0x1000, chr_bank_e >> chr_shift_right << chr_shift_left);
408 TKSMIR[4] = chr_bank_e;
409 setchr1r(0x12, 0x1400, chr_bank_f >> chr_shift_right << chr_shift_left);
410 TKSMIR[5] = chr_bank_f;
411 setchr1r(0x12, 0x1800, chr_bank_g >> chr_shift_right << chr_shift_left);
412 TKSMIR[6] = chr_bank_g;
413 setchr1r(0x12, 0x1C00, chr_bank_h >> chr_shift_right << chr_shift_left);
414 TKSMIR[7] = chr_bank_h;
415 break;
416 case 3:
417 setchr1r(0x12, 0x0000, chr_bank_e >> chr_shift_right << chr_shift_left);
418 TKSMIR[0] = chr_bank_e;
419 setchr1r(0x12, 0x0400, chr_bank_f >> chr_shift_right << chr_shift_left);
420 TKSMIR[1] = chr_bank_f;
421 setchr1r(0x12, 0x0800, chr_bank_g >> chr_shift_right << chr_shift_left);
422 TKSMIR[2] = chr_bank_g;
423 setchr1r(0x12, 0x0C00, chr_bank_h >> chr_shift_right << chr_shift_left);
424 TKSMIR[3] = chr_bank_h;
425 setchr2r(0x12, 0x1000, chr_bank_a >> 1 >> chr_shift_right << chr_shift_left);
426 TKSMIR[4] = TKSMIR[5] = chr_bank_a;
427 setchr2r(0x12, 0x1800, chr_bank_c >> 1 >> chr_shift_right << chr_shift_left);
428 TKSMIR[6] = TKSMIR[7] = chr_bank_c;
429 break;
430 case 4:
431 setchr4r(0x12, 0x0000, chr_bank_a >> 2 >> chr_shift_right << chr_shift_left);
432 setchr4r(0x12, 0x1000, chr_bank_e >> 2 >> chr_shift_right << chr_shift_left);
433 break;
434 case 5:
435 if (!ppu_latch0)
436 setchr4r(0x12, 0x0000, chr_bank_a >> 2 >> chr_shift_right << chr_shift_left);
437 else
438 setchr4r(0x12, 0x0000, chr_bank_b >> 2 >> chr_shift_right << chr_shift_left);
439 if (!ppu_latch1)
440 setchr4r(0x12, 0x1000, chr_bank_e >> 2 >> chr_shift_right << chr_shift_left);
441 else
442 setchr4r(0x12, 0x1000, chr_bank_f >> 2 >> chr_shift_right << chr_shift_left);
443 break;
444 case 6:
445 setchr2r(0x12, 0x0000, chr_bank_a >> 1 >> chr_shift_right << chr_shift_left);
446 setchr2r(0x12, 0x0800, chr_bank_c >> 1 >> chr_shift_right << chr_shift_left);
447 setchr2r(0x12, 0x1000, chr_bank_e >> 1 >> chr_shift_right << chr_shift_left);
448 setchr2r(0x12, 0x1800, chr_bank_g >> 1 >> chr_shift_right << chr_shift_left);
449 break;
450 case 7:
451 setchr1r(0x12, 0x0000, chr_bank_a >> chr_shift_right << chr_shift_left);
452 setchr1r(0x12, 0x0400, chr_bank_b >> chr_shift_right << chr_shift_left);
453 setchr1r(0x12, 0x0800, chr_bank_c >> chr_shift_right << chr_shift_left);
454 setchr1r(0x12, 0x0C00, chr_bank_d >> chr_shift_right << chr_shift_left);
455 setchr1r(0x12, 0x1000, chr_bank_e >> chr_shift_right << chr_shift_left);
456 setchr1r(0x12, 0x1400, chr_bank_f >> chr_shift_right << chr_shift_left);
457 setchr1r(0x12, 0x1800, chr_bank_g >> chr_shift_right << chr_shift_left);
458 setchr1r(0x12, 0x1C00, chr_bank_h >> chr_shift_right << chr_shift_left);
459 break;
460 }
461 }
462
463 static void COOLGIRL_Sync_Mirroring(void) {
464 if (!four_screen)
465 {
466 if (!((mapper == 0b010100) && (flags & 1))) // Mapper #189?
467 setmirror((mirroring < 2) ? (mirroring ^ 1) : mirroring);
468 }
469 else { // four screen mode
470 vnapage[0] = CHR_RAM + 0x3F000;
471 vnapage[1] = CHR_RAM + 0x3F400;
472 vnapage[2] = CHR_RAM + 0x3F800;
473 vnapage[3] = CHR_RAM + 0x3FC00;
474 }
475 }
476
477 static void COOLGIRL_Sync(void) {
478 COOLGIRL_Sync_PRG();
479 COOLGIRL_Sync_CHR();
480 COOLGIRL_Sync_Mirroring();
481 }
482
483 static DECLFW(COOLGIRL_Flash_Write) {
484 if (flash_state < sizeof(flash_buffer_a) / sizeof(flash_buffer_a[0]))
485 {
486 flash_buffer_a[flash_state] = A & 0xFFF;
487 flash_buffer_v[flash_state] = V;
488 flash_state++;
489
490 // enter CFI mode
491 if ((flash_state == 1) &&
492 (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0x98))
493 {
494 cfi_mode = 1;
495 flash_state = 0;
496 }
497
498 // sector erase
499 if ((flash_state == 6) &&
500 (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) &&
501 (flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) &&
502 (flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0x80) &&
503 (flash_buffer_a[3] == 0x0AAA) && (flash_buffer_v[3] == 0xAA) &&
504 (flash_buffer_a[4] == 0x0555) && (flash_buffer_v[4] == 0x55) &&
505 (flash_buffer_v[5] == 0x30))
506 {
507 int sector = prg_bank_a_mapped * 0x2000 / FLASH_SECTOR_SIZE;
508 uint32 sector_address = sector * FLASH_SECTOR_SIZE;
509 for (uint32 i = sector_address; i < sector_address + FLASH_SECTOR_SIZE; i++)
510 SAVE_FLASH[i % SAVE_FLASH_SIZE] = 0xFF;
511 FCEU_printf("Flash sector #%d is erased: 0x%08x - 0x%08x.\n", sector, sector_address, sector_address + FLASH_SECTOR_SIZE - 1);
512 flash_state = 0;
513 }
514
515 // write byte
516 if ((flash_state == 4) &&
517 (flash_buffer_a[0] == 0x0AAA) && (flash_buffer_v[0] == 0xAA) &&
518 (flash_buffer_a[1] == 0x0555) && (flash_buffer_v[1] == 0x55) &&
519 (flash_buffer_a[2] == 0x0AAA) && (flash_buffer_v[2] == 0xA0))
520 {
521 //int sector = prg_bank_a_mapped * 0x2000 / FLASH_SECTOR_SIZE;
522 uint32 flash_addr = prg_bank_a_mapped * 0x2000 + (A % 0x8000);
523 if (SAVE_FLASH[flash_addr % SAVE_FLASH_SIZE] != 0xFF) {
524 FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased.\n", flash_addr);
525 }
526 else {
527 SAVE_FLASH[flash_addr % SAVE_FLASH_SIZE] = V;
528 }
529 flash_state = 0;
530 }
531 }
532
533 // not a command
534 if (((A & 0xFFF) != 0x0AAA) && ((A & 0xFFF) != 0x0555)) {
535 flash_state = 0;
536 }
537
538 // reset
539 if (V == 0xF0) {
540 flash_state = 0;
541 cfi_mode = 0;
542 }
543
544 COOLGIRL_Sync_PRG();
545 }
546
547 static DECLFW(COOLGIRL_WRITE) {
548 if (sram_enabled && A >= 0x6000 && A < 0x8000 && !map_rom_on_6000)
549 CartBW(A, V); // SRAM is enabled and writable
550 if (SAVE_FLASH && can_write_flash && A >= 0x8000) // writing flash
551 COOLGIRL_Flash_Write(A, V);
552
553 // block two writes in a row
554 if ((timestampbase + timestamp) < (lreset + 2)) return;
555 lreset = timestampbase + timestamp;
556
557 if (A >= 0x5000 && A < 0x6000 && !lockout)
558 {
559 //FCEU_printf("Write: %02x => %04x\n", V, A);
560 switch (A & 7)
561 {
562 case 0:
563 // {prg_base[26:22]} = cpu_data_in[4:0];
564 // use bits 29-27 to simulate flash memory
565 SET_BITS(prg_base, "29:22", V, "7:0");
566 break;
567 case 1:
568 // prg_base[21:14] = cpu_data_in[7:0];
569 SET_BITS(prg_base, "21:14", V, "7:0");
570 break;
571 case 2:
572 // {chr_mask[18], prg_mask[20:14]} = cpu_data_in[7:0];
573 SET_BITS(chr_mask, "18", V, "7");
574 SET_BITS(prg_mask, "20:14", V, "6:0");
575 //FCEU_printf("REG_prg_mask: %02x\n", REG_prg_mask);
576 break;
577 case 3:
578 // {prg_mode[2:0], chr_bank_a[7:3]} = cpu_data_in[7:0];
579 SET_BITS(prg_mode, "2:0", V, "7:5");
580 SET_BITS(chr_bank_a, "7:3", V, "4:0");
581 break;
582 case 4:
583 // {chr_mode[2:0], chr_mask[17:13]} = cpu_data_in[7:0];
584 SET_BITS(chr_mode, "2:0", V, "7:5");
585 SET_BITS(chr_mask, "17:13", V, "4:0");
586 break;
587 case 5:
588 // {chr_bank_a[8], prg_bank_a[5:1], sram_page[1:0]} = cpu_data_in[7:0];
589 SET_BITS(chr_bank_a, "8", V, "7");
590 SET_BITS(prg_bank_a, "5:1", V, "6:2");
591 SET_BITS(sram_page, "1:0", V, "1:0");
592 break;
593 case 6:
594 // {flags[2:0], mapper[4:0]} = cpu_data_in[7:0];
595 SET_BITS(flags, "2:0", V, "7:5");
596 SET_BITS(mapper, "4:0", V, "4:0");
597 break;
598 case 7:
599 // {lockout, mapper[5], four_screen, mirroring[1:0], prg_write_enabled, chr_write_enabled, sram_enabled} = cpu_data_in[7:0];
600 SET_BITS(lockout, "0", V, "7");
601 SET_BITS(mapper, "5", V, "6");
602 SET_BITS(four_screen, "0", V, "5");
603 SET_BITS(mirroring, "1:0", V, "4:3");
604 SET_BITS(can_write_flash, "0", V, "2");
605 SET_BITS(can_write_chr, "0", V, "1");
606 SET_BITS(sram_enabled, "0", V, "0");
607 if (mapper == 0b010001) prg_bank_b = ~2; // if (USE_MAPPER_009_010 && mapper == 6'b010001) prg_bank_b = 8'b11111101;
608 if (mapper == 0b010111) map_rom_on_6000 = 1; // if (ENABLE_MAPPER_042 && (mapper == 6'b010111)) map_rom_on_6000 <= 1;
609 if (mapper == 0b001110) prg_bank_b = 1; // if (USE_MAPPER_065 && mapper == 6'b001110) prg_bank_b = 1;
610 break;
611 }
612 }
613
614 if (A < 0x8000) // $0000-$7FFF
615 {
616 // Mapper #163
617 if (mapper == 0b000110)
618 {
619 if (A == 0x5101) // if (cpu_addr_in[14:0] == 15'h5101)
620 {
621 if (mapper163_r4 && !V) // if ((mapper163_r4 != 0) && (cpu_data_in == 0))
622 mapper163_r5 ^= 1; // mapper163_r5[0] = ~mapper163_r5[0];
623 mapper163_r4 = V;
624 }
625 else if (A == 0x5100 && V == 6) // if ((cpu_addr_in[14:0] == 15'h5100) && (cpu_data_in == 6))
626 {
627 SET_BITS(prg_mode, "0", 0, "0"); // prg_mode[0] = 0;
628 prg_bank_b = 0b1100; // prb_bank_b = 4'b1100;
629 }
630 else {
631 if (get_bits(A, "14:12") == 0b101) // if (cpu_addr_in[14:12] == 3'b101) begin
632 {
633 switch (get_bits(A, "9:8")) // case (cpu_addr_in[9:8])
634 {
635 case 2:
636 SET_BITS(prg_mode, "0", 1, "0"); // prg_mode[0] = 1;
637 SET_BITS(prg_bank_a, "7:6", V, "1:0"); // prg_bank_a[7:6] = cpu_data_in[1:0];
638 mapper163_r0 = V;
639 break;
640 case 0:
641 SET_BITS(prg_mode, "0", 1, "0"); // prg_mode[0] = 1;
642 SET_BITS(prg_bank_a, "5:2", V, "3:0"); // prg_bank_a[5:2] = cpu_data_in[3:0];
643 SET_BITS(chr_mode, "0", V, "7"); // chr_mode[0] = cpu_data_in[7];
644 mapper163_r1 = V;
645 break;
646 case 3:
647 mapper163_r2 = V; // mapper163_r2 = cpu_data_in;
648 break;
649 case 1:
650 mapper163_r3 = V; // mapper163_r3 = cpu_data_in;
651 break;
652 }
653 }
654 }
655 }
656
657 // Mapper #87
658 if (mapper == 0b001100)
659 {
660 if (get_bits(A, "14:13") == 0b11) // if (cpu_addr_in[14:13] == 2'b11) // $6000-$7FFF
661 {
662 // chr_bank_a[4:3] = {cpu_data_in[0], cpu_data_in[1]};
663 SET_BITS(chr_bank_a, "4:3", V, "0,1");
664 }
665 }
666
667 // Mapper #90 - JY
668 /*
669 if (mapper == 0b001101)
670 {
671 switch (A)
672 {
673 case 0x5800: mul1 = V; break;
674 case 0x5801: mul2 = V; break;
675 }
676 }
677 */
678
679 // MMC5 (not really)
680 if (mapper == 0b001111)
681 {
682 // case (cpu_addr_in[14:0])
683 switch (get_bits(A, "14:0"))
684 {
685 case 0x5105:
686 if (V == 0xFF)
687 {
688 four_screen = 1;
689 }
690 else {
691 four_screen = 0;
692 // case ({cpu_data_in[4], cpu_data_in[2]})
693 switch (get_bits(V, "4,2"))
694 {
695 case 0b00: // 2'b00: mirroring = 2'b10;
696 mirroring = 0b10; break;
697 case 0b01: // 2'b01: mirroring = 2'b00;
698 mirroring = 0b00; break;
699 case 0b10: // 2'b10: mirroring = 2'b01;
700 mirroring = 0b01; break;
701 case 0b11: // 2'b11: mirroring = 2'b11;
702 mirroring = 0b11; break;
703 }
704 }
705 break;
706 case 0x5115:
707 // prg_bank_a[4:0] = { cpu_data_in[4:1], 1'b0};
708 SET_BITS(prg_bank_a, "4:1", V, "4:1");
709 SET_BITS(prg_bank_a, "0", 0, "0");
710 // prg_bank_b[4:0] = { cpu_data_in[4:1], 1'b1};
711 SET_BITS(prg_bank_b, "4:1", V, "4:1");
712 SET_BITS(prg_bank_b, "0", 1, "0");
713 break;
714 case 0x5116:
715 // prg_bank_c[4:0] = cpu_data_in[4:0];
716 SET_BITS(prg_bank_c, "4:0", V, "4:0");
717 break;
718 case 0x5117:
719 // prg_bank_d[4:0] = cpu_data_in[4:0];
720 SET_BITS(prg_bank_d, "4:0", V, "4:0");
721 break;
722 case 0x5120:
723 // chr_bank_a[7:0] = cpu_data_in[7:0];
724 SET_BITS(chr_bank_a, "7:0", V, "7:0");
725 break;
726 case 0x5121:
727 // chr_bank_b[7:0] = cpu_data_in[7:0];
728 SET_BITS(chr_bank_b, "7:0", V, "7:0");
729 break;
730 case 0x5122:
731 // chr_bank_c[7:0] = cpu_data_in[7:0];
732 SET_BITS(chr_bank_c, "7:0", V, "7:0");
733 break;
734 case 0x5123:
735 // chr_bank_d[7:0] = cpu_data_in[7:0];
736 SET_BITS(chr_bank_d, "7:0", V, "7:0");
737 break;
738 case 0x5128:
739 // chr_bank_e[7:0] = cpu_data_in[7:0];
740 SET_BITS(chr_bank_e, "7:0", V, "7:0");
741 break;
742 case 0x5129:
743 // chr_bank_f[7:0] = cpu_data_in[7:0];
744 SET_BITS(chr_bank_f, "7:0", V, "7:0");
745 break;
746 case 0x512A:
747 // chr_bank_g[7:0] = cpu_data_in[7:0];
748 SET_BITS(chr_bank_g, "7:0", V, "7:0");
749 break;
750 case 0x512B:
751 // chr_bank_h[7:0] = cpu_data_in[7:0];
752 SET_BITS(chr_bank_h, "7:0", V, "7:0");
753 break;
754 case 0x5203:
755 // mmc5_irq_ack = 1;
756 X6502_IRQEnd(FCEU_IQEXT);
757 mmc5_irq_out = 0;
758 // mmc5_irq_line[7:0] = cpu_data_in[7:0];
759 SET_BITS(mmc5_irq_line, "7:0", V, "7:0");
760 break;
761 case 0x5204:
762 // mmc5_irq_ack = 1;
763 X6502_IRQEnd(FCEU_IQEXT);
764 mmc5_irq_out = 0;
765 // mmc5_irq_enabled = cpu_data_in[7];
766 mmc5_irq_enabled = get_bits(V, "7");
767 break;
768 }
769 }
770
771 // Mapper #189
772 if ((mapper == 0b010100) && (flags & 2))
773 {
774 if (A >= 0x4120) // if (cpu_addr_in[14:0] >= 15'h4120) // $4120-$7FFF
775 {
776 // prg_bank_a[5:2] = cpu_data_in[3:0] | cpu_data_in[7:4];
777 prg_bank_a = set_bits(prg_bank_a, "5:2",
778 get_bits(V, "7:4") | get_bits(V, "3:0"));
779 }
780 }
781
782 // Mappers #79 and #146 - NINA-03/06 and Sachen 3015: (flag0 = 1)
783 if (mapper == 0b011011)
784 {
785 // if ({cpu_addr_in[14:13], cpu_addr_in[8]} == 3'b101)
786 if (get_bits(A, "14:13,8") == 0b101)
787 {
788 //chr_bank_a[5:3] = cpu_data_in[2:0];
789 SET_BITS(chr_bank_a, "5:3", V, "2:0");
790 //prg_bank_a[2] = cpu_data_in[3];
791 SET_BITS(prg_bank_a, "2", V, "3");
792 }
793 }
794
795 // Mapper #133
796 if (mapper == 0b011100)
797 {
798 // if ({cpu_addr_in[14:13], cpu_addr_in[8]} == 3'b101)
799 if (get_bits(A, "14:13,8") == 0b101)
800 {
801 //chr_bank_a[4:3] = cpu_data_in[1:0];
802 SET_BITS(chr_bank_a, "4:3", V, "1:0");
803 //prg_bank_a[2] = cpu_data_in[2];
804 SET_BITS(prg_bank_a, "2", V, "2");
805 }
806 }
807
808 // Mapper #184
809 if (mapper == 0b011111)
810 {
811 if (get_bits(A, "14:13") == 0b11) // if (cpu_addr_in[14:13] == 2'b11)
812 {
813 // chr_bank_a[4:2] = cpu_data_in[2:0];
814 SET_BITS(chr_bank_a, "4:2", V, "2:0");
815 // chr_bank_e[4:2] = {1'b1, cpu_data_in[5:4]};
816 SET_BITS(chr_bank_e, "3:2", V, "5:4");
817 SET_BITS(chr_bank_e, "4", 1, "0");
818 }
819 }
820
821 // Mapper #38
822 if (mapper == 0b100000)
823 {
824 // if (cpu_addr_in[14:12] == 3'b111)
825 if (get_bits(A, "14:12") == 0b111)
826 {
827 // prg_bank_a[3:2] = cpu_data_in[1:0];
828 SET_BITS(prg_bank_a, "3:2", V, "1:0");
829 // chr_bank_a[4:3] = cpu_data_in[3:2];
830 SET_BITS(chr_bank_a, "4:3", V, "3:2");
831 }
832 }
833 }
834 else // $8000-$FFFF
835 {
836 // Mapper #2 - UxROM
837 // flag0 - mapper #71 - for Fire Hawk only.
838 // other mapper-#71 games are UxROM
839 if (mapper == 0b000001)
840 {
841 // if (!ENABLE_MAPPER_071 | ~flags[0] | (cpu_addr_in[14:12] != 3'b001))
842 if (!(flags & 1) || (get_bits(A, "14:12") != 0b001))
843 {
844 // prg_bank_a[UxROM_BITSIZE+1:1] = cpu_data_in[UxROM_BITSIZE:0];
845 // UxROM_BITSIZE = 4
846 SET_BITS(prg_bank_a, "5:1", V, "4:0");
847 // if (ENABLE_MAPPER_030 && flags[1])
848 if (flags & 2)
849 {
850 // One screen mirroring select, CHR RAM bank, PRG ROM bank
851 // mirroring[1:0] = { 1'b1, cpu_data_in[7]};
852 SET_BITS(mirroring, "1", 1, "0");
853 SET_BITS(mirroring, "0", V, "7");
854 // chr_bank_a[1:0] = cpu_data_in[6:5];
855 SET_BITS(chr_bank_a, "1:0", V, "6:5");
856 }
857 }
858 else {
859 // CodeMasters, blah. Mirroring control used only by Fire Hawk
860 // mirroring[1:0] = {1'b1, cpu_data_in[4]};
861 SET_BITS(mirroring, "1", 1, "0");
862 SET_BITS(mirroring, "0", V, "4");
863 }
864 }
865
866 // Mapper #3 - CNROM
867 if (mapper == 0b000010)
868 {
869 // chr_bank_a[7:3] = cpu_data_in[4:0];
870 SET_BITS(chr_bank_a, "7:3", V, "4:0");
871 }
872
873 // Mapper #78 - Holy Diver
874 if (mapper == 0b000011)
875 {
876 // prg_bank_a[3:1] = cpu_data_in[2:0];
877 SET_BITS(prg_bank_a, "3:1", V, "2:0");
878 // chr_bank_a[6:3] = cpu_data_in[7:4];
879 SET_BITS(chr_bank_a, "6:3", V, "7:4");
880 // mirroring = { 1'b0, ~cpu_data_in[3]};
881 mirroring = get_bits(V, "3") ^ 1;
882 }
883
884 // Mapper #97 - Irem's TAM-S1
885 if (mapper == 0b000100)
886 {
887 // prg_bank_a[5:1] = cpu_data_in[4:0];
888 SET_BITS(chr_bank_a, "5:1", V, "4:0");
889 // mirroring = { 1'b0, ~cpu_data_in[7]};
890 mirroring = get_bits(V, "7") ^ 1;
891 }
892
893 // Mapper #93 - Sunsoft-2
894 if (mapper == 0b000101)
895 {
896 // prg_bank_a[3:1] = { cpu_data_in[6:4] };
897 SET_BITS(prg_bank_a, "3:1", V, "6:4");
898 // chr_write_enabled = cpu_data_in[0];
899 can_write_chr = V & 1;
900 }
901
902 // Mapper #18
903 if (mapper == 0b000111)
904 {
905 // case ({cpu_addr_in[14:12], cpu_addr_in[1:0]})
906 switch (get_bits(A, "14:12,1:0"))
907 {
908 case 0b00000: // 5'b00000: prg_bank_a[3:0] = cpu_data_in[3:0]; // $8000
909 SET_BITS(prg_bank_a, "3:0", V, "3:0"); break;
910 case 0b00001: // 5'b00001: prg_bank_a[7:4] = cpu_data_in[3:0]; // $8001
911 SET_BITS(prg_bank_a, "7:4", V, "3:0"); break;
912 case 0b00010: // 5'b00010: prg_bank_b[3:0] = cpu_data_in[3:0]; // $8002
913 SET_BITS(prg_bank_b, "3:0", V, "3:0"); break;
914 case 0b00011: // 5'b00011: prg_bank_b[7:4] = cpu_data_in[3:0]; // $8003
915 SET_BITS(prg_bank_b, "7:4", V, "3:0"); break;
916 case 0b00100: // 5'b00100: prg_bank_c[3:0] = cpu_data_in[3:0]; // $9000
917 SET_BITS(prg_bank_c, "3:0", V, "3:0"); break;
918 case 0b00101: // 5'b00101: prg_bank_c[7:4] = cpu_data_in[3:0]; // $9001
919 SET_BITS(prg_bank_c, "7:4", V, "3:0"); break;
920 case 0b00110:
921 break;
922 case 0b00111:
923 break;
924 case 0b01000: // 5'b01000: chr_bank_a[3:0] = cpu_data_in[3:0]; // $A000
925 SET_BITS(chr_bank_a, "3:0", V, "3:0"); break;
926 case 0b01001: // 5'b01001: chr_bank_a[7:4] = cpu_data_in[3:0]; // $A001
927 SET_BITS(chr_bank_a, "7:4", V, "3:0"); break;
928 case 0b01010: // 5'b01010: chr_bank_b[3:0] = cpu_data_in[3:0]; // $A002
929 SET_BITS(chr_bank_b, "3:0", V, "3:0"); break;
930 case 0b01011: // 5'b01011: chr_bank_b[7:4] = cpu_data_in[3:0]; // $A003
931 SET_BITS(chr_bank_b, "7:4", V, "3:0"); break;
932 case 0b01100: // 5'b01100: chr_bank_c[3:0] = cpu_data_in[3:0]; // $B000
933 SET_BITS(chr_bank_c, "3:0", V, "3:0"); break;
934 case 0b01101: // 5'b01101: chr_bank_c[7:4] = cpu_data_in[3:0]; // $B001
935 SET_BITS(chr_bank_c, "7:4", V, "3:0"); break;
936 case 0b01110: // 5'b01110: chr_bank_d[3:0] = cpu_data_in[3:0]; // $B002
937 SET_BITS(chr_bank_d, "3:0", V, "3:0"); break;
938 case 0b01111: // 5'b01111: chr_bank_d[7:4] = cpu_data_in[3:0]; // $B003
939 SET_BITS(chr_bank_d, "7:4", V, "3:0"); break;
940 case 0b10000: // 5'b10000: chr_bank_e[3:0] = cpu_data_in[3:0]; // $C000
941 SET_BITS(chr_bank_e, "3:0", V, "3:0"); break;
942 case 0b10001: // 5'b10001: chr_bank_e[7:4] = cpu_data_in[3:0]; // $C001
943 SET_BITS(chr_bank_e, "7:4", V, "3:0"); break;
944 case 0b10010: // 5'b10010: chr_bank_f[3:0] = cpu_data_in[3:0]; // $C002
945 SET_BITS(chr_bank_f, "3:0", V, "3:0"); break;
946 case 0b10011: // 5'b10011: chr_bank_f[7:4] = cpu_data_in[3:0]; // $C003
947 SET_BITS(chr_bank_f, "7:4", V, "3:0"); break;
948 case 0b10100: // 5'b10100: chr_bank_g[3:0] = cpu_data_in[3:0]; // $D000
949 SET_BITS(chr_bank_g, "3:0", V, "3:0"); break;
950 case 0b10101: // 5'b10101: chr_bank_g[7:4] = cpu_data_in[3:0]; // $D001
951 SET_BITS(chr_bank_g, "7:4", V, "3:0"); break;
952 case 0b10110: // 5'b10110: chr_bank_h[3:0] = cpu_data_in[3:0]; // $D002
953 SET_BITS(chr_bank_h, "3:0", V, "3:0"); break;
954 case 0b10111: // 5'b10111: chr_bank_h[7:4] = cpu_data_in[3:0]; // $D003
955 SET_BITS(chr_bank_h, "7:4", V, "3:0"); break;
956 case 0b11000: // 5'b11000: mapper18_irq_latch[3:0] = cpu_data_in[3:0]; // $E000
957 SET_BITS(mapper18_irq_latch, "3:0", V, "3:0"); break;
958 case 0b11001: // 5'b11001: mapper18_irq_latch[7:4] = cpu_data_in[3:0]; // $E001
959 SET_BITS(mapper18_irq_latch, "7:4", V, "3:0"); break;
960 case 0b11010: // 5'b11010: mapper18_irq_latch[11:8] = cpu_data_in[3:0]; // $E002
961 SET_BITS(mapper18_irq_latch, "11:8", V, "3:0"); break;
962 case 0b11011: // 5'b11011: mapper18_irq_latch[15:12] = cpu_data_in[3:0]; // $E003
963 SET_BITS(mapper18_irq_latch, "15:12", V, "3:0"); break;
964 case 0b11100: // 5'b11100: begin // $F000
965 // mapper18_irq_out = 0; // ack
966 X6502_IRQEnd(FCEU_IQEXT);
967 // mapper18_irq_value[15:0] = mapper18_irq_latch[15:0];
968 mapper18_irq_value = mapper18_irq_latch; break; // irq_cpu_out = 0;
969 case 0b11101: // 5'b11101: begin // $F001
970 X6502_IRQEnd(FCEU_IQEXT); // irq_cpu_control[3:0] = cpu_data_in[3:0];
971 SET_BITS(mapper18_irq_control, "3:0", V, "3:0"); break;
972 case 0b11110: // 5'b11110
973 switch (get_bits(V, "1:0")) // case (cpu_data_in[1:0])
974 {
975 case 0b00: mirroring = 0b01; break; //2'b00: mirroring = 2'b01; // Horz
976 case 0b01: mirroring = 0b00; break; //2'b01: mirroring = 2'b00; // Vert
977 case 0b10: mirroring = 0b10; break; //2'b10: mirroring = 2'b10; // 1SsA
978 case 0b11: mirroring = 0b11; break; //2'b11: mirroring = 2'b11; // 1SsB
979 }
980 case 0b11111:
981 break; // sound
982 }
983 }
984
985 // Mapper #7 - AxROM, mapper #241 - BNROM
986 if (mapper == 0b001000)
987 {
988 // AxROM_BxROM_BITSIZE = 3
989 //prg_bank_a[AxROM_BxROM_BITSIZE + 2:2] = cpu_data_in[AxROM_BxROM_BITSIZE:0];
990 SET_BITS(prg_bank_a, "5:2", V, "3:0");
991 //if (!ENABLE_MAPPER_034_241_BxROM || !flags[0]) // BxROM?
992 // mirroring = { 1'b1, cpu_data_in[4]};
993 if (!(flags & 1))
994 mirroring = (1 << 1) | get_bits(V, "4");
995 }
996
997 // Mapper #228 - Cheetahmen II
998 if (mapper == 0b001001)
999 {
1000 // prg_bank_a[5:2] = cpu_addr_in[10:7];
1001 SET_BITS(prg_bank_a, "5:2", A, "10:7");
1002 // chr_bank_a[7:3] = { cpu_addr_in[2:0], cpu_data_in[1:0] }; // only 256k, sorry
1003 SET_BITS(chr_bank_a, "7:5", A, "2:0");
1004 SET_BITS(chr_bank_a, "4:3", V, "1:0");
1005 // mirroring = { 1'b0, cpu_addr_in[13]};
1006 mirroring = get_bits(A, "13");
1007 }
1008
1009 // Mapper #11 - ColorDreams
1010 if (mapper == 0b001010)
1011 {
1012 // prg_bank_a[3:2] = cpu_data_in[1:0];
1013 SET_BITS(prg_bank_a, "3:2", V, "1:0");
1014 // chr_bank_a[6:3] = cpu_data_in[7:4];
1015 SET_BITS(chr_bank_a, "6:3", V, "7:4");
1016 }
1017
1018 // Mapper #66 - GxROM
1019 if (mapper == 0b001011)
1020 {
1021 // prg_bank_a[3:2] = cpu_data_in[5:4];
1022 SET_BITS(prg_bank_a, "3:2", V, "5:4");
1023 // chr_bank_a[4:3] = cpu_data_in[1:0];
1024 SET_BITS(chr_bank_a, "4:3", V, "1:0");
1025 }
1026
1027 // Mapper #90 - JY
1028 if (mapper == 0b001101)
1029 {
1030 // if (cpu_addr_in[14:12] == 3'b000) // $800x
1031 if (get_bits(A, "14:12") == 0b000)
1032 {
1033 // case (cpu_addr_in[1:0])
1034 switch (get_bits(A, "1:0"))
1035 {
1036 // 2'b00: prg_bank_a[5:0] = cpu_data_in[5:0];
1037 case 0b00: SET_BITS(prg_bank_a, "5:0", V, "5:0"); break;
1038 // 2'b01: prg_bank_b[5:0] = cpu_data_in[5:0];
1039 case 0b01: SET_BITS(prg_bank_b, "5:0", V, "5:0"); break;
1040 // 2'b10: prg_bank_c[5:0] = cpu_data_in[5:0];
1041 case 0b10: SET_BITS(prg_bank_c, "5:0", V, "5:0"); break;
1042 // 2'b11: prg_bank_d[5:0] = cpu_data_in[5:0];
1043 case 0b11: SET_BITS(prg_bank_d, "5:0", V, "5:0"); break;
1044 }
1045 }
1046
1047 // if (cpu_addr_in[14:12] == 3'b001) // $900x
1048 if (get_bits(A, "14:12") == 0b001)
1049 {
1050 // case (cpu_addr_in[2:0])
1051 switch (get_bits(A, "2:0"))
1052 {
1053 case 0b000: // 3'b000: chr_bank_a[7:0] = cpu_data_in[7:0]; // $9000
1054 SET_BITS(chr_bank_a, "7:0", V, "7:0"); break;
1055 case 0b001: // 3'b001: chr_bank_b[7:0] = cpu_data_in[7:0]; // $9001
1056 SET_BITS(chr_bank_b, "7:0", V, "7:0"); break;
1057 case 0b010: // 3'b010: chr_bank_c[7:0] = cpu_data_in[7:0]; // $9002
1058 SET_BITS(chr_bank_c, "7:0", V, "7:0"); break;
1059 case 0b011: // 3'b011: chr_bank_d[7:0] = cpu_data_in[7:0]; // $9003
1060 SET_BITS(chr_bank_d, "7:0", V, "7:0"); break;
1061 case 0b100: // 3'b100: chr_bank_e[7:0] = cpu_data_in[7:0]; // $9004
1062 SET_BITS(chr_bank_e, "7:0", V, "7:0"); break;
1063 case 0b101: // 3'b101: chr_bank_f[7:0] = cpu_data_in[7:0]; // $9005
1064 SET_BITS(chr_bank_f, "7:0", V, "7:0"); break;
1065 case 0b110: // 3'b110: chr_bank_g[7:0] = cpu_data_in[7:0]; // $9006
1066 SET_BITS(chr_bank_g, "7:0", V, "7:0"); break;
1067 case 0b111: // 3'b111: chr_bank_h[7:0] = cpu_data_in[7:0]; // $9007
1068 SET_BITS(chr_bank_h, "7:0", V, "7:0"); break;
1069 }
1070 }
1071
1072 // if ({cpu_addr_in[14:12], cpu_addr_in[1:0]} == 5'b10101) // $D001
1073 if (get_bits(A, "14:12,1:0") == 0b10101)
1074 {
1075 // mirroring = cpu_data_in[1:0];
1076 SET_BITS(mirroring, "1:0", V, "1:0");
1077 }
1078
1079 // use MMC3's IRQs
1080 // if (cpu_addr_in[14:12] == 3'b100) // $C00x
1081 if (get_bits(A, "14:12") == 0b100)
1082 {
1083 // case (cpu_addr_in[2:0])
1084 switch (get_bits(A, "2:0"))
1085 {
1086 case 0b000:
1087 // 3'b000: mmc3_irq_enabled = cpu_data_in[0];
1088 if (V & 1)
1089 {
1090 mmc3_irq_enabled = 1;
1091 }
1092 else {
1093 X6502_IRQEnd(FCEU_IQEXT);
1094 mmc3_irq_enabled = 0;
1095 }
1096 break;
1097 case 0b001:
1098 break; // who cares about this shit?
1099 case 0b010:
1100 // 3'b010: mmc3_irq_enabled = 0;
1101 mmc3_irq_enabled = 0;
1102 X6502_IRQEnd(FCEU_IQEXT);
1103 break;
1104 case 0b011:
1105 // 3'b011: mmc3_irq_enabled = 1;
1106 mmc3_irq_enabled = 1;
1107 break;
1108 case 0b100:
1109 break; // prescaler? who cares?
1110 case 0b101:
1111 // mmc3_irq_latch = cpu_data_in ^ mapper90_xor;
1112 mmc3_irq_latch = V ^ mapper90_xor;
1113 mmc3_irq_reload = 1;
1114 break;
1115 case 0b110:
1116 // mapper90_xor = cpu_data_in;
1117 mapper90_xor = V;
1118 break;
1119 case 0b111:
1120 break; // meh
1121 }
1122 }
1123 }
1124
1125 // Mapper #65 - Irem's H3001
1126 if (mapper == 0b001110)
1127 {
1128 // case ({cpu_addr_in[14:12], cpu_addr_in[2:0]})
1129 switch (get_bits(A, "14:12,2:0"))
1130 {
1131 case 0b000000:
1132 // 6'b000000: prg_bank_a[5:0] = cpu_data_in[5:0]; // $8000
1133 SET_BITS(prg_bank_a, "5:0", V, "5:0");
1134 break;
1135 case 0b001001:
1136 // 6'b001001: mirroring = {1'b0, cpu_data_in[7]}; // $9001, mirroring
1137 mirroring = get_bits(V, "7");
1138 break;
1139 case 0b001011:
1140 // mapper65_irq_out = 0; // ack
1141 X6502_IRQEnd(FCEU_IQEXT); // irq_cpu_out = 0;
1142 // mapper65_irq_enabled = cpu_data_in[7]; // $9003, enable IRQ
1143 mapper65_irq_enabled = get_bits(V, "7");
1144 break;
1145 case 0b001100:
1146 X6502_IRQEnd(FCEU_IQEXT); // mapper65_irq_out = 0; // ack
1147 mapper65_irq_value = mapper65_irq_latch; // $9004, IRQ reload
1148 break;
1149 case 0b001101: // mapper65_irq_latch[15:8] = cpu_data_in; // $9005, IRQ high value
1150 SET_BITS(mapper65_irq_latch, "15:8", V, "7:0"); break;
1151 case 0b001110: // mapper65_irq_latch[7:0] = cpu_data_in; // $9006, IRQ low value
1152 SET_BITS(mapper65_irq_latch, "7:0", V, "7:0"); break;
1153 case 0b010000: // prg_bank_b[5:0] = cpu_data_in[5:0]; // $A000
1154 prg_bank_b = (prg_bank_b & 0b11000000) | (V & 0b00111111); break;
1155 case 0b011000: // chr_bank_a[7:0] = cpu_data_in; // $B000
1156 SET_BITS(chr_bank_a, "7:0", V, "7:0"); break;
1157 case 0b011001: // chr_bank_b[7:0] = cpu_data_in[7:0]; // $B001
1158 SET_BITS(chr_bank_b, "7:0", V, "7:0"); break;
1159 case 0b011010: // chr_bank_c[7:0] = cpu_data_in[7:0]; // $B002
1160 SET_BITS(chr_bank_c, "7:0", V, "7:0"); break;
1161 case 0b011011: // chr_bank_d[7:0] = cpu_data_in[7:0]; // $B003
1162 SET_BITS(chr_bank_d, "7:0", V, "7:0"); break;
1163 case 0b011100: // chr_bank_e[7:0] = cpu_data_in[7:0]; // $B004
1164 SET_BITS(chr_bank_e, "7:0", V, "7:0"); break;
1165 case 0b011101: // chr_bank_f[7:0] = cpu_data_in[7:0]; // $B005
1166 SET_BITS(chr_bank_f, "7:0", V, "7:0"); break;
1167 case 0b011110: // chr_bank_g[7:0] = cpu_data_in[7:0]; // $B006
1168 SET_BITS(chr_bank_g, "7:0", V, "7:0"); break;
1169 case 0b011111: // chr_bank_h[7:0] = cpu_data_in[7:0]; // $B007
1170 SET_BITS(chr_bank_h, "7:0", V, "7:0"); break;
1171 case 0b100000: // 6'b100000: prg_bank_c[5:0] = cpu_data_in[5:0]; // $C000
1172 SET_BITS(prg_bank_c, "5:0", V, "5:0"); break;
1173 }
1174 }
1175
1176 // Mapper #1 - MMC1
1177 /*
1178 r0 - load register
1179 flag0 - 16KB of SRAM (SOROM)
1180 */
1181 if (mapper == 0b010000)
1182 {
1183 if (V & 0x80) // reset
1184 {
1185 mmc1_load_register = set_bits(mmc1_load_register, "5:0", 0b100000); // mmc1_load_register[5:0] = 6'b100000;
1186 prg_mode = 0; // 0x4000 (A) + fixed last (C)
1187 prg_bank_c = set_bits(prg_bank_c, "4:0", 0b11110); // prg_bank_c[4:0] = 5'b11110;
1188 }
1189 else {
1190 // mmc1_load_register[5:0] = { cpu_data_in[0], mmc1_load_register[5:1] };
1191 SET_BITS(mmc1_load_register, "4:0", mmc1_load_register, "5:1");
1192 SET_BITS(mmc1_load_register, "5", V, "0");
1193 // if (mmc1_load_register[0] == 1)
1194 if (mmc1_load_register & 1)
1195 {
1196 switch ((A >> 13) & 3)
1197 {
1198 case 0b00: // 2'b00: begin // $8000-$9FFF
1199 if (get_bits(mmc1_load_register, "4:3") == 0b11) // if (mmc1_load_register[4:3] == 2'b11)
1200 {
1201 prg_mode = 0; // prg_mode = 3'b000; // 0x4000 (A) + fixed last (C)
1202 prg_bank_c = set_bits(prg_bank_c, "4:1", 0b1111); // prg_bank_c[4:1] = 4'b1111;
1203 }
1204 //else if (mmc1_load_register[4:3] == 2'b10)
1205 else if (get_bits(mmc1_load_register, "4:3") == 0b10)
1206 {
1207 prg_mode = 0b001; // prg_mode = 3'b001; // fixed first (C) + 0x4000 (A)
1208 prg_bank_c = set_bits(prg_bank_c, "4:1", 0b0000); // prg_bank_c[4:0] = 4'b0000;
1209 }
1210 else
1211 prg_mode = 0b111; // prg_mode = 3'b111; // 0x8000 (A)
1212 if (get_bits(mmc1_load_register, "5"))
1213 chr_mode = 0b100;
1214 else
1215 chr_mode = 0b000;
1216 mirroring = set_bits(mirroring, "1:0", get_bits(mmc1_load_register, "2:1") ^ 0b10);
1217 break;
1218 case 0b01: // 2'b01
1219 SET_BITS(chr_bank_a, "6:2", mmc1_load_register, "5:1"); // chr_bank_a[6:2] = mmc1_load_register[5:1];
1220 if (flags & 1) // (flags[0]) - 16KB of SRAM
1221 {
1222 // PRG RAM page #2 is battery backed
1223 sram_page = 2 | get_bits(mmc1_load_register, "4") ^ 1; // sram_page <= {1'b1, ~mmc1_load_register[4]};
1224 }
1225 SET_BITS(prg_bank_a, "5", mmc1_load_register, "5"); // prg_bank_a[5] = mmc1_load_register[5]; // for SUROM, 512k PRG support
1226 SET_BITS(prg_bank_c, "5", mmc1_load_register, "5"); // prg_bank_c[5] = mmc1_load_register[5]; // for SUROM, 512k PRG support
1227 break;
1228 case 0b10: // 2'b10: chr_bank_e[6:2] = mmc1_load_register[5:1]; // $C000-$DFFF
1229 SET_BITS(chr_bank_e, "6:2", mmc1_load_register, "5:1");
1230 break;
1231 case 0b11: // 2'b11
1232 // prg_bank_a[4:1] = r0[4:1];
1233 SET_BITS(prg_bank_a, "4:1", mmc1_load_register, "4:1");
1234 // sram_enabled = ~mmc1_load_register[5];
1235 sram_enabled = get_bits(mmc1_load_register, "5") ^ 1;
1236 break;
1237 }
1238 mmc1_load_register = 0b100000; // mmc1_load_register[5:0] = 6'b100000;
1239 }
1240 }
1241 }
1242
1243 // Mapper #9 and #10 - MMC2 and MMC4
1244 // flag0 - 0=MMC2, 1=MMC4
1245 if (mapper == 0b010001)
1246 {
1247 switch ((A >> 12) & 7)
1248 {
1249 case 2: // $A000-$AFFF
1250 if (!(flags & 1)) {
1251 // MMC2
1252 SET_BITS(prg_bank_a, "3:0", V, "3:0");
1253 }
1254 else {
1255 // MMC4
1256 SET_BITS(prg_bank_a, "4:1", V, "3:0"); // prg_bank_a[4:0] = { cpu_data_in[3:0], 1'b0};
1257 prg_bank_a &= ~1;
1258 }
1259 break;
1260 case 3: // $B000-$BFFF
1261 SET_BITS(chr_bank_a, "6:2", V, "4:0"); // chr_bank_a[6:2] = cpu_data_in[4:0];
1262 break;
1263 case 4: // $C000-$CFFF
1264 SET_BITS(chr_bank_b, "6:2", V, "4:0"); // chr_bank_b[6:2] = cpu_data_in[4:0];
1265 break;
1266 case 5: // $D000-$DFFF
1267 SET_BITS(chr_bank_e, "6:2", V, "4:0"); // chr_bank_e[6:2] = cpu_data_in[4:0];
1268 break;
1269 case 6: // $E000-$EFFF
1270 SET_BITS(chr_bank_f, "6:2", V, "4:0"); // chr_bank_f[6:2] = cpu_data_in[4:0];
1271 break;
1272 case 7: // $F000-$FFFF
1273 mirroring = V & 1;
1274 break;
1275 }
1276 }
1277
1278 // Mapper #152
1279 if (mapper == 0b010010)
1280 {
1281 SET_BITS(chr_bank_a, "6:3", V, "3:0"); // chr_bank_a[6:3] = cpu_data_in[3:0];
1282 SET_BITS(prg_bank_a, "3:1", V, "6:4"); // prg_bank_a[3:1] = cpu_data_in[6:4];
1283 if (flags & 1)
1284 mirroring = 2 | get_bits(V, "7"); // mirroring = {1'b1, cpu_data_in[7]}; // Mapper #152
1285 else
1286 SET_BITS(prg_bank_a, "4", V, "7"); //prg_bank_a[4] <= cpu_data_in[7]; // Mapper #70
1287 }
1288
1289 // Mapper #73 - VRC3
1290 if (mapper == 0b010011)
1291 {
1292 switch (get_bits(A, "14:12")) // case (cpu_addr_in[14:12])
1293 {
1294 case 0b000: // 3'b000: vrc3_irq_latch[3:0] = cpu_data_in[3:0]; // $8000-$8FFF
1295 SET_BITS(vrc3_irq_latch, "3:0", V, "3:0");
1296 break;
1297 case 0b001: // 3'b001: vrc3_irq_latch[7:4] = cpu_data_in[3:0]; // $9000-$9FFF
1298 SET_BITS(vrc3_irq_latch, "7:4", V, "3:0");
1299 break;
1300 case 0b010: // 3'b010: vrc3_irq_latch[11:8] = cpu_data_in[3:0]; // $A000-$AFFF
1301 SET_BITS(vrc3_irq_latch, "11:8", V, "3:0");
1302 break;
1303 case 0b011: // 3'b011: vrc3_irq_latch[15:12] = cpu_data_in[3:0]; // $B000-$BFFF
1304 SET_BITS(vrc3_irq_latch, "15:12", V, "3:0");
1305 break;
1306 case 0b100: // // $C000-$CFFF
1307 X6502_IRQEnd(FCEU_IQEXT); // vrc3_irq_out = 0; // ack
1308 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
1309 if (vrc3_irq_control & 2) // if (vrc3_irq_control[1]) // if E is set
1310 vrc3_irq_value = vrc3_irq_latch; // vrc3_irq_value[15:0] = vrc3_irq_latch[15:0]; // reload with latch
1311 break;
1312 case 0b101: // // $D000-$DFFF
1313 X6502_IRQEnd(FCEU_IQEXT); // vrc3_irq_out = 0; // ack
1314 SET_BITS(vrc3_irq_control, "1", vrc3_irq_control, "0"); // vrc3_irq_control[1] = vrc3_irq_control[0];
1315 break;
1316 case 0b110: // $E000-$EFFF
1317 break;
1318 case 0b111: // 3'b111: prg_bank_a[3:1] = cpu_data_in[2:0]; // $F000-$FFFF
1319 SET_BITS(prg_bank_a, "3:1", V, "2:0");
1320 break;
1321 }
1322 }
1323
1324 // Mapper #4 - MMC3/MMC6
1325 /*
1326 flag0 - TxSROM
1327 flag1 - mapper #189
1328 */
1329 if (mapper == 0b010100)
1330 {
1331 // case ({cpu_addr_in[14:13], cpu_addr_in[0]})
1332 switch (get_bits(A, "14:13,0"))
1333 {
1334 case 0b000: // $8000-$9FFE, even
1335 SET_BITS(mmc3_internal, "2:0", V, "2:0"); // mmc3_internal[2:0] = cpu_data_in[2:0];
1336 if (!(flags & 2) && !(flags & 4)) // if ((!USE_MAPPER_189 | ~flags[1]) & (!USE_MAPPER_206 | ~flags[2]))
1337 {
1338 if (get_bits(V, "6")) // if (cpu_data_in[6])
1339 prg_mode = 0b101;
1340 else
1341 prg_mode = 0b100;
1342 }
1343 if (!(flags & 4)) // if (!USE_MAPPER_206 | ~flags[2]) // disabled for mapper #206
1344 {
1345 if (V & 0x80) // if (cpu_data_in[7])
1346 chr_mode = 0b011;
1347 else
1348 chr_mode = 0b010;
1349 }
1350 break;
1351 case 0b001: // $8001-$9FFF, odd
1352 switch (get_bits(mmc3_internal, "2:0"))
1353 {
1354 case 0b000: // 3'b000: chr_bank_a[7:0] = cpu_data_in[7:0];
1355 SET_BITS(chr_bank_a, "7:0", V, "7:0"); break;
1356 case 0b001: // 3'b001: chr_bank_c[7:0] = cpu_data_in[7:0];
1357 SET_BITS(chr_bank_c, "7:0", V, "7:0"); break;
1358 case 0b010: // 3'b010: chr_bank_e[7:0] = cpu_data_in[7:0];
1359 SET_BITS(chr_bank_e, "7:0", V, "7:0"); break;
1360 case 0b011: // 3'b011: chr_bank_f[7:0] = cpu_data_in[7:0];
1361 SET_BITS(chr_bank_f, "7:0", V, "7:0"); break;
1362 case 0b100: // 3'b100: chr_bank_g[7:0] = cpu_data_in[7:0];
1363 SET_BITS(chr_bank_g, "7:0", V, "7:0"); break;
1364 case 0b101: // 3'b101: chr_bank_h[7:0] = cpu_data_in[7:0];
1365 SET_BITS(chr_bank_h, "7:0", V, "7:0"); break;
1366 case 0b110: // 3'b110: if (!ENABLE_MAPPER_189 | ~flags[1]) prg_bank_a[(MMC3_BITSIZE-1):0] = cpu_data_in[(MMC3_BITSIZE-1):0];
1367 if (!(flags & 2))
1368 SET_BITS(prg_bank_a, "7:0", V, "7:0");
1369 break;
1370 case 0b111: // 3'b111: if (!ENABLE_MAPPER_189 | ~flags[1]) prg_bank_b[(MMC3_BITSIZE-1):0] = cpu_data_in[(MMC3_BITSIZE-1):0];
1371 if (!(flags & 2))
1372 SET_BITS(prg_bank_b, "7:0", V, "7:0");
1373 break;
1374 }
1375 break;
1376 case 0b010: // $A000-$BFFE, even (mirroring)
1377 // if (!ENABLE_MAPPER_206 | ~flags[2]) // disabled for mapper #206
1378 if (!(flags & 4))
1379 mirroring = V & 1; // mirroring = {1'b0, cpu_data_in[0]};
1380 break;
1381 case 0b011: // RAM protect... no
1382 break;
1383 case 0b100: // 3'b100: mmc3_irq_latch = cpu_data_in; // $C000-$DFFE, even (IRQ latch)
1384 mmc3_irq_latch = V; break;
1385 case 0b101: // 3'b101: mmc3_irq_reload = 1; // $C001-$DFFF, odd
1386 mmc3_irq_reload = 1; break;
1387 case 0b110: // 3'b110: mmc3_irq_enabled = 0; // $E000-$FFFE, even
1388 X6502_IRQEnd(FCEU_IQEXT);
1389 mmc3_irq_enabled = 0;
1390 break;
1391 case 0b111: // $E001-$FFFF, odd
1392 if (!(flags & 4)) // if (!USE_MAPPER_206 | ~flags[2]) // disabled for mapper #206
1393 mmc3_irq_enabled = 1; // mmc3_irq_enabled = 1;
1394 break;
1395 }
1396 }
1397
1398 // Mapper #112
1399 /*
1400 r0[2:0] - internal register
1401 */
1402 if (mapper == 0b010101)
1403 {
1404 switch (get_bits(A, "14:13"))
1405 {
1406 case 0b00: // $8000-$9FFF
1407 SET_BITS(mapper112_internal, "2:0", V, "2:0"); // mapper112_internal[2:0] = cpu_data_in[2:0];
1408 break;
1409 case 0b01: // $A000-BFFF
1410 switch (get_bits(mapper112_internal, "2:0"))
1411 {
1412 case 0b000: // 3'b000: prg_bank_a[5:0] = cpu_data_in[5:0];
1413 SET_BITS(prg_bank_a, "5:0", V, "5:0"); break;
1414 case 0b001: // 3'b001: prg_bank_b[5:0] = cpu_data_in[5:0];
1415 SET_BITS(prg_bank_b, "5:0", V, "5:0"); break;
1416 case 0b010: // 3'b010: chr_bank_a[7:0] = cpu_data_in[7:0];
1417 SET_BITS(chr_bank_a, "7:0", V, "7:0"); break;
1418 case 0b011: // 3'b011: chr_bank_c[7:0] = cpu_data_in[7:0];
1419 SET_BITS(chr_bank_c, "7:0", V, "7:0"); break;
1420 case 0b100: // 3'b100: chr_bank_e[7:0] = cpu_data_in[7:0];
1421 SET_BITS(chr_bank_e, "7:0", V, "7:0"); break;
1422 case 0b101: // 3'b101: chr_bank_f[7:0] = cpu_data_in[7:0];
1423 SET_BITS(chr_bank_f, "7:0", V, "7:0"); break;
1424 case 0b110: // 3'b110: chr_bank_g[7:0] = cpu_data_in[7:0];
1425 SET_BITS(chr_bank_g, "7:0", V, "7:0"); break;
1426 case 0b111: // 3'b111: chr_bank_h[7:0] = cpu_data_in[7:0];
1427 SET_BITS(chr_bank_h, "7:0", V, "7:0"); break;
1428 }
1429 break;
1430 case 0b10: // $C000-$DFFF
1431 break;
1432 case 0b11: // 2'b11: mirroring = {1'b0, cpu_data_in[0]}; // $E000-$FFFF
1433 mirroring = V & 1; break;
1434 }
1435 }
1436
1437 // Mappers #33 + #48 - Taito
1438 // flag0=0 - #33, flag0=1 - #48
1439 if (mapper == 0b010110)
1440 {
1441 // case ({cpu_addr_in[14:13], cpu_addr_in[1:0]})
1442 switch (get_bits(A, "14:13,1:0"))
1443 {
1444 case 0b0000:
1445 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)
1446 if (!(flags & 1)) // if (~flags[0]) // 33
1447 mirroring = get_bits(V, "6"); // mirroring = {1'b0, cpu_data_in[6]};
1448 break;
1449 case 0b0001: // 4'b0001: prg_bank_b[5:0] = cpu_data_in[5:0]; // $8001, PRG Reg 1 (8k @ $A000)
1450 SET_BITS(prg_bank_b, "5:0", V, "5:0"); break;
1451 case 0b0010: // 4'b0010: chr_bank_a[7:1] = cpu_data_in[6:0]; // $8002, CHR Reg 0 (2k @ $0000)
1452 SET_BITS(chr_bank_a, "7:1", V, "6:0"); break;
1453 case 0b0011: // 4'b0011: chr_bank_c[7:1] = cpu_data_in[6:0]; // $8003, CHR Reg 1 (2k @ $0800)
1454 SET_BITS(chr_bank_c, "7:1", V, "6:0"); break;
1455 case 0b0100: // 4'b0100: chr_bank_e[7:0] = cpu_data_in[7:0]; // $A000, CHR Reg 2 (1k @ $1000)
1456 SET_BITS(chr_bank_e, "7:0", V, "7:0"); break;
1457 case 0b0101: // 4'b0101: chr_bank_f[7:0] = cpu_data_in[7:0]; // $A001, CHR Reg 2 (1k @ $1400)
1458 SET_BITS(chr_bank_f, "7:0", V, "7:0"); break;
1459 case 0b0110: // 4'b0110: chr_bank_g[7:0] = cpu_data_in[7:0]; // $A002, CHR Reg 2 (1k @ $1800)
1460 SET_BITS(chr_bank_g, "7:0", V, "7:0"); break;
1461 case 0b0111: // 4'b0111: chr_bank_h[7:0] = cpu_data_in[7:0]; // $A003, CHR Reg 2 (1k @ $1C00)
1462 SET_BITS(chr_bank_h, "7:0", V, "7:0"); break;
1463 case 0b1100: // 4'b1100: if (flags[0]) mirroring = {1'b0, cpu_data_in[6]}; // $E000, mirroring, for mapper #48
1464 if (flags & 1) // 48
1465 mirroring = get_bits(V, "6"); // mirroring = cpu_data_in[6];
1466 case 0b1000: // 4'b1000: irq_scanline_latch = ~cpu_data_in; // $C000, IRQ latch
1467 mmc3_irq_latch = set_bits(mmc3_irq_latch, "7:0", get_bits(V, "7:0") ^ 0b11111111);
1468 break;
1469 case 0b1001: // 4'b1001: mmc3_irq_reload = 1; // $C001, IRQ reload
1470 mmc3_irq_reload = 1; break;
1471 case 0b1010: // 4'b1010: mmc3_irq_enabled = 1; // $C002, IRQ enable
1472 mmc3_irq_enabled = 1; break;
1473 case 0b1011: // 4'b1011: mmc3_irq_enabled = 0; // $C003, IRQ disable & ack
1474 mmc3_irq_enabled = 0;
1475 X6502_IRQEnd(FCEU_IQEXT); // irq_cpu_out = 0; // ack
1476 break;
1477 }
1478 }
1479
1480 // Mapper #42
1481 if (mapper == 0b010111)
1482 {
1483 // case ({cpu_addr_in[14], cpu_addr_in[1:0]})
1484 switch (get_bits(A, "14,1:0"))
1485 {
1486 case 0: // 3'b000: chr_bank_a[7:3] = cpu_data_in[4:0]; // $8000, CHR Reg (8k @ $8000)
1487 SET_BITS(chr_bank_a, "7:3", V, "4:0");
1488 break;
1489 case 4: // 3'b100: prg_bank_6000[3:0] = cpu_data_in[3:0]; // $E000, PRG Reg (8k @ $6000)
1490 SET_BITS(prg_bank_6000, "3:0", V, "3:0");
1491 break;
1492 case 5: // 3'b101: mirroring = {1'b0, cpu_data_in[3]}; // Mirroring
1493 mirroring = get_bits(V, "3");
1494 break;
1495 case 6: // 3'b110: ... // IRQ
1496 mapper42_irq_enabled = get_bits(V, "1"); // mapper42_irq_enabled = cpu_data_in[1];
1497 if (!mapper42_irq_enabled) // if (!mapper42_irq_enabled)
1498 {
1499 X6502_IRQEnd(FCEU_IQEXT); // irq_cpu_out = 0;
1500 mapper42_irq_value = 0; // mapper42_irq_value = 0;
1501 }
1502 break;
1503 }
1504 }
1505
1506 // Mapper #23 - VRC2/4
1507 /*
1508 flag0 - switches A0 and A1 lines. 0=A0,A1 like VRC2b (mapper #23), 1=A1,A0 like VRC2a(#22), VRC2c(#25)
1509 flag1 - divides CHR bank select by two (mapper #22, VRC2a)
1510 */
1511 if (mapper == 0b011000)
1512 {
1513 uint8 vrc_2b_hi =
1514 (flags & 5) == 0 ? // (!flags[0] && !flags[2]) ?
1515 (get_bits(A, "7") | get_bits(A, "2")) // | cpu_addr_in[7] | cpu_addr_in[2]) // mapper #21
1516 : (flags & 5) == 1 ? //: (flags[0] && !flags[2]) ?
1517 get_bits(A, "0") // (cpu_addr_in[0]) // mapper #22
1518 : (flags & 5) == 4 ? // : (!flags[0] && flags[2]) ?
1519 (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
1520 : (get_bits(A, "2") | get_bits(A, "0")); // : (cpu_addr_in[2] | cpu_addr_in[0]); // mapper #25
1521 uint8 vrc_2b_low =
1522 (flags & 5) == 0 ? // (!flags[0] && !flags[2]) ?
1523 (get_bits(A, "6") | get_bits(A, "1")) // (cpu_addr_in[6] | cpu_addr_in[1]) // mapper #21
1524 : (flags & 5) == 1 ? // : (flags[0] && !flags[2]) ?
1525 get_bits(A, "1") // (cpu_addr_in[1]) // mapper #22
1526 : (flags & 5) == 4 ?// : (!flags[0] && flags[2]) ?
1527 (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
1528 : (get_bits(A, "3") | get_bits(A, "1")); // : (cpu_addr_in[3] | cpu_addr_in[1]); // mapper #25
1529
1530 // case ({ cpu_addr_in[14:12], vrc_2b_hi, vrc_2b_low })
1531 switch ((get_bits(A, "14:12") << 2) | (vrc_2b_hi << 1) | vrc_2b_low)
1532 {
1533 case 0b00000: // $8000-$8003, PRG0
1534 case 0b00001:
1535 case 0b00010:
1536 case 0b00011:
1537 SET_BITS(prg_bank_a, "4:0", V, "4:0"); // prg_bank_a[4:0] = cpu_data_in[4:0];
1538 break;
1539 case 0b00100: // $9000-$9001, mirroring
1540 case 0b00101:
1541 // VRC2 - using games are usually well - behaved and only write 0 or 1 to this register,
1542 // but Wai Wai World in one instance writes $FF instead
1543 if (V != 0b11111111) // if (cpu_data_in != 8'b11111111) mirroring = cpu_data_in[1:0]; // $9000-$9001, mirroring
1544 SET_BITS(mirroring, "1:0", V, "1:0");
1545 break;
1546 case 0b00110: // $9002-$9004, PRG swap
1547 case 0b00111:
1548 SET_BITS(prg_mode, "0", V, "1"); // prg_mode[0] = cpu_data_in[1];
1549 break;
1550 case 0b01000: // $A000-$A003, PRG1
1551 case 0b01001:
1552 case 0b01010:
1553 case 0b01011:
1554 SET_BITS(prg_bank_b, "4:0", V, "4:0"); // prg_bank_b[4:0] = cpu_data_in[4:0];
1555 break;
1556 case 0b01100: // 5'b01100: chr_bank_a[3:0] = cpu_data_in[3:0]; // $B000, CHR0 low
1557 SET_BITS(chr_bank_a, "3:0", V, "3:0"); break;
1558 case 0b01101: // 5'b01101: chr_bank_a[7:4] = cpu_data_in[3:0]; // $B001, CHR0 hi
1559 SET_BITS(chr_bank_a, "7:4", V, "3:0"); break;
1560 case 0b01110: // 5'b01110: chr_bank_b[3:0] = cpu_data_in[3:0]; // $B002, CHR1 low
1561 SET_BITS(chr_bank_b, "3:0", V, "3:0"); break;
1562 case 0b01111: // 5'b01111: chr_bank_b[7:4] = cpu_data_in[3:0]; // $B003, CHR1 hi
1563 SET_BITS(chr_bank_b, "7:4", V, "3:0"); break;
1564 case 0b10000: // 5'b10000: chr_bank_c[3:0] = cpu_data_in[3:0]; // $C000, CHR2 low
1565 SET_BITS(chr_bank_c, "3:0", V, "3:0"); break;
1566 case 0b10001: // 5'b10001: chr_bank_c[7:4] = cpu_data_in[3:0]; // $C001, CHR2 hi
1567 SET_BITS(chr_bank_c, "7:4", V, "3:0"); break;
1568 case 0b10010: // 5'b10010: chr_bank_d[3:0] = cpu_data_in[3:0]; // $C002, CHR3 low
1569 SET_BITS(chr_bank_d, "3:0", V, "3:0"); break;
1570 case 0b10011: // 5'b10011: chr_bank_d[7:4] = cpu_data_in[3:0]; // $C003, CHR3 hi
1571 SET_BITS(chr_bank_d, "7:4", V, "3:0"); break;
1572 case 0b10100: // 5'b10100: chr_bank_e[3:0] = cpu_data_in[3:0]; // $D000, CHR4 low
1573 SET_BITS(chr_bank_e, "3:0", V, "3:0"); break;
1574 case 0b10101: // 5'b10101: chr_bank_e[7:4] = cpu_data_in[3:0]; // $D001, CHR4 hi
1575 SET_BITS(chr_bank_e, "7:4", V, "3:0"); break;
1576 case 0b10110: // 5'b10110: chr_bank_f[3:0] = cpu_data_in[3:0]; // $D002, CHR5 low
1577 SET_BITS(chr_bank_f, "3:0", V, "3:0"); break;
1578 case 0b10111: // 5'b10111: chr_bank_f[7:4] = cpu_data_in[3:0]; // $D003, CHR5 hi
1579 SET_BITS(chr_bank_f, "7:4", V, "3:0"); break;
1580 case 0b11000: // 5'b11000: chr_bank_g[3:0] = cpu_data_in[3:0]; // $E000, CHR6 low
1581 SET_BITS(chr_bank_g, "3:0", V, "3:0"); break;
1582 case 0b11001: // 5'b11001: chr_bank_g[7:4] = cpu_data_in[3:0]; // $E001, CHR6 hi
1583 SET_BITS(chr_bank_g, "7:4", V, "3:0"); break;
1584 case 0b11010: // 5'b11010: chr_bank_h[3:0] = cpu_data_in[3:0]; // $E002, CHR7 low
1585 SET_BITS(chr_bank_h, "3:0", V, "3:0"); break;
1586 case 0b11011: // 5'b11011: chr_bank_h[7:4] = cpu_data_in[3:0]; // $E003, CHR7 hi
1587 SET_BITS(chr_bank_h, "7:4", V, "3:0"); break;
1588 }
1589
1590 // if (cpu_addr_in[14:12] == 3'b111)
1591 if (get_bits(A, "14:12") == 0b111)
1592 {
1593 // case (vrc_2b_hi, vrc_2b_low})
1594 switch ((vrc_2b_hi << 1) | vrc_2b_low)
1595 {
1596 case 0b00: // 2'b00: vrc4_irq_latch[3:0] = cpu_data_in[3:0]; // IRQ latch low
1597 SET_BITS(vrc4_irq_latch, "3:0", V, "3:0"); break;
1598 case 0b01: // 2'b01: vrc4_irq_latch[7:4] = cpu_data_in[3:0]; // IRQ latch hi
1599 SET_BITS(vrc4_irq_latch, "7:4", V, "3:0"); break;
1600 case 0b10: // 2'b10 // IRQ control
1601 X6502_IRQEnd(FCEU_IQEXT); // vrc4_irq_out = 0; // ack
1602 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
1603 if (vrc4_irq_control & 2) // if (vrc4_irq_control[1]) begin // if E is set
1604 {
1605 vrc4_irq_prescaler_counter = 0; // vrc4_irq_prescaler_counter[1:0] = 2'b00; // reset prescaler
1606 vrc4_irq_prescaler = 0; // vrc4_irq_prescaler[6:0] = 7'b0000000;
1607 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
1608 }
1609 break;
1610 case 0b11: // 2'b11 // IRQ ack
1611 X6502_IRQEnd(FCEU_IQEXT); // vrc4_irq_out = 0;
1612 SET_BITS(vrc4_irq_control, "1", vrc4_irq_control, "0"); // vrc4_irq_control[1] = vrc4_irq_control[0];
1613 break;
1614 }
1615 }
1616 }
1617
1618 // Mapper #69 - Sunsoft FME-7
1619 if (mapper == 0b011001)
1620 {
1621 // if (cpu_addr_in[14:13] == 2'b00) mapper69_internal[3:0] = cpu_data_in[3:0];
1622 if (get_bits(A, "14:13") == 0b00) SET_BITS(mapper69_internal, "3:0", V, "3:0");
1623 // if (cpu_addr_in[14:13] == 2'b01)
1624 if (get_bits(A, "14:13") == 0b01)
1625 {
1626 switch (get_bits(mapper69_internal, "3:0")) // case (mapper69_internal[3:0])
1627 {
1628 case 0b0000: // 4'b0000: chr_bank_a[7:0] = cpu_data_in[7:0]; // CHR0
1629 SET_BITS(chr_bank_a, "7:0", V, "7:0"); break;
1630 case 0b0001: // 4'b0001: chr_bank_b[7:0] = cpu_data_in[7:0]; // CHR1
1631 SET_BITS(chr_bank_b, "7:0", V, "7:0"); break;
1632 case 0b0010: // 4'b0010: chr_bank_c[7:0] = cpu_data_in[7:0]; // CHR2
1633 SET_BITS(chr_bank_c, "7:0", V, "7:0"); break;
1634 case 0b0011: // 4'b0011: chr_bank_d[7:0] = cpu_data_in[7:0]; // CHR3
1635 SET_BITS(chr_bank_d, "7:0", V, "7:0"); break;
1636 case 0b0100: // 4'b0100: chr_bank_e[7:0] = cpu_data_in[7:0]; // CHR4
1637 SET_BITS(chr_bank_e, "7:0", V, "7:0"); break;
1638 case 0b0101: // 4'b0101: chr_bank_f[7:0] = cpu_data_in[7:0]; // CHR5
1639 SET_BITS(chr_bank_f, "7:0", V, "7:0"); break;
1640 case 0b0110: // 4'b0110: chr_bank_g[7:0] = cpu_data_in[7:0]; // CHR6
1641 SET_BITS(chr_bank_g, "7:0", V, "7:0"); break;
1642 case 0b0111: // 4'b0111: chr_bank_h[7:0] = cpu_data_in[7:0]; // CHR7
1643 SET_BITS(chr_bank_h, "7:0", V, "7:0"); break;
1644 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
1645 sram_enabled = (V >> 7) & 1;
1646 map_rom_on_6000 = ((V >> 6) & 1) ^ 1;
1647 prg_bank_6000 = V & 0x3F;
1648 break;
1649 case 0b1001: // 4'b1001: prg_bank_a[5:0] = cpu_data_in[5:0]; // PRG1
1650 SET_BITS(prg_bank_a, "5:0", V, "5:0"); break;
1651 case 0b1010: // 4'b1010: prg_bank_b[5:0] = cpu_data_in[5:0]; // PRG2
1652 SET_BITS(prg_bank_b, "5:0", V, "5:0"); break;
1653 case 0b1011: // 4'b1011: prg_bank_c[5:0] = cpu_data_in[5:0]; // PRG3
1654 SET_BITS(prg_bank_c, "5:0", V, "5:0"); break;
1655 case 0b1100: // 4'b1100: mirroring[1:0] = cpu_data_in[1:0]; // mirroring
1656 SET_BITS(mirroring, "1:0", V, "1:0"); break;
1657 case 0b1101: // 4'b1101
1658 X6502_IRQEnd(FCEU_IQEXT); // fme7_irq_out = 0; // ack
1659 mapper69_counter_enabled = get_bits(V, "7"); // fme7_counter_enabled = cpu_data_in[7];
1660 mapper69_irq_enabled = get_bits(V, "0"); // fme7_irq_enabled = cpu_data_in[0];
1661 break;
1662 case 0b1110: // 4'b1110: fme7_irq_value[7:0] = cpu_data_in[7:0]; // IRQ low
1663 SET_BITS(mapper69_irq_value, "7:0", V, "7:0"); break;
1664 case 0b1111: // fme7_irq_value[15:8] = cpu_data_in[7:0]; // IRQ high
1665 SET_BITS(mapper69_irq_value, "15:8", V, "7:0"); break;
1666 }
1667 }
1668 }
1669
1670 // Mapper #32 - Irem's G-101
1671 if (mapper == 0b011010)
1672 {
1673 switch (get_bits(A, "14:12"))
1674 {
1675 case 0b000: // 2'b00: prg_bank_a[5:0] = cpu_data_in[5:0]; // $8000-$8FFF, PRG0
1676 SET_BITS(prg_bank_a, "5:0", V, "5:0");
1677 break;
1678 case 0b001: // 2'b01: {prg_mode[0], mirroring} = {cpu_data_in[1], 1'b0, cpu_data_in[0]}; // $9000-$9FFF, PRG mode, mirroring
1679 SET_BITS(prg_mode, "0", V, "1");
1680 mirroring = V & 1;
1681 break;
1682 case 0b010: // 2'b10: prg_bank_b[5:0] = cpu_data_in[5:0]; // $A000-$AFFF, PRG1
1683 SET_BITS(prg_bank_b, "5:0", V, "5:0");
1684 break;
1685 case 0b011: // $B000-$BFFF, CHR regs
1686 switch (get_bits(A, "2:0"))
1687 {
1688 case 0b000: // 3'b000: chr_bank_a[7:0] = cpu_data_in[7:0];
1689 SET_BITS(chr_bank_a, "7:0", V, "7:0"); break;
1690 case 0b001: // 3'b001: chr_bank_b[7:0] = cpu_data_in[7:0];
1691 SET_BITS(chr_bank_b, "7:0", V, "7:0"); break;
1692 case 0b010: // 3'b010: chr_bank_c[7:0] = cpu_data_in[7:0];
1693 SET_BITS(chr_bank_c, "7:0", V, "7:0"); break;
1694 case 0b011: // 3'b011: chr_bank_d[7:0] = cpu_data_in[7:0];
1695 SET_BITS(chr_bank_d, "7:0", V, "7:0"); break;
1696 case 0b100: // 3'b100: chr_bank_e[7:0] = cpu_data_in[7:0];
1697 SET_BITS(chr_bank_e, "7:0", V, "7:0"); break;
1698 case 0b101: // 3'b101: chr_bank_f[7:0] = cpu_data_in[7:0];
1699 SET_BITS(chr_bank_f, "7:0", V, "7:0"); break;
1700 case 0b110: // 3'b110: chr_bank_g[7:0] = cpu_data_in[7:0];
1701 SET_BITS(chr_bank_g, "7:0", V, "7:0"); break;
1702 case 0b111: // 3'b111: chr_bank_h[7:0] = cpu_data_in[7:0];
1703 SET_BITS(chr_bank_h, "7:0", V, "7:0"); break;
1704 }
1705 break;
1706 }
1707 }
1708
1709 // Mapper #36 is assigned to TXC's PCB 01-22000-400
1710 if (mapper == 0b011101)
1711 {
1712 if (get_bits(A, "14:1") != 0b11111111111111) // (cpu_addr_in[14:1] != 14'b11111111111111)
1713 {
1714 // prg_bank_a[5:2] = cpu_data_in[7:4];
1715 SET_BITS(prg_bank_a, "5:2", V, "7:4");
1716 // chr_bank_a[6:3] = cpu_data_in[3:0];
1717 SET_BITS(chr_bank_a, "6:3", V, "3:0");
1718 }
1719 }
1720
1721 // Mapper #70
1722 if (mapper == 0b011110)
1723 {
1724 // prg_bank_a[4:1] = cpu_data_in[7:4];
1725 SET_BITS(prg_bank_a, "4:1", V, "7:4");
1726 // chr_bank_a[6:3] = cpu_data_in[3:0];
1727 SET_BITS(chr_bank_a, "6:3", V, "3:0");
1728 }
1729
1730 // Mapper #75 - VRC1
1731 if (mapper == 0b100010)
1732 {
1733 // case (cpu_addr_in[14:12])
1734 switch (get_bits(A, "14:12"))
1735 {
1736 case 0b000: // 3'b000: prg_bank_a[3:0] = cpu_data_in[3:0]; // $8000-$8FFF
1737 SET_BITS(prg_bank_a, "3:0", V, "3:0"); break;
1738 case 0b001:
1739 mirroring = V & 1; // mirroring = {1'b0, cpu_data_in[0]};
1740 SET_BITS(chr_bank_a, "6", V, "1"); // chr_bank_a[6] = cpu_data_in[1];
1741 SET_BITS(chr_bank_e, "6", V, "2"); // chr_bank_e[6] = cpu_data_in[2];
1742 break;
1743 case 0b010: // 3'b010: prg_bank_b[3:0] = cpu_data_in[3:0]; // $A000-$AFFF
1744 SET_BITS(prg_bank_b, "3:0", V, "3:0"); break;
1745 case 0b100: // 3'b100: prg_bank_c[3:0] = cpu_data_in[3:0]; // $C000-$CFFF
1746 SET_BITS(prg_bank_c, "3:0", V, "3:0"); break;
1747 case 0b110: // 3'b110: �hr_bank_a[5:2] = cpu_data_in[3:0]; // $E000-$EFFF
1748 SET_BITS(chr_bank_a, "5:2", V, "3:0"); break;
1749 case 0b111: // 3'b111: chr_bank_e[5:2] = cpu_data_in[3:0]; // $F000-$FFFF
1750 SET_BITS(chr_bank_e, "5:2", V, "3:0"); break;
1751 }
1752 }
1753
1754 // Mapper #83 - Cony/Yoko
1755 if (mapper == 0b100011)
1756 {
1757 // case (cpu_addr_in[9:8])
1758 switch (get_bits(A, "9:8"))
1759 {
1760 case 0b00: // $80xx
1761 SET_BITS(prg_bank_a, "4:1", V, "3:0");
1762 break;
1763 case 0b01: // $81xx
1764 mirroring = get_bits(V, "1:0"); // mirroring <= cpu_data_in[1:0];
1765 SET_BITS(prg_mode, "2", V, "4"); // prg_mode[2] <= cpu_data_in[4];
1766 map_rom_on_6000 = get_bits(V, "5"); // map_rom_on_6000 <= cpu_data_in[5];
1767 mapper83_irq_enabled_latch = get_bits(V, "7"); // mapper83_irq_enabled_latch <= cpu_data_in[7];
1768 break;
1769 case 0b10: // 82xx
1770 if (!get_bits(A, "0")) // if (!cpu_addr_in[0])
1771 {
1772 X6502_IRQEnd(FCEU_IQEXT); // mapper83_irq_out <= 0;
1773 SET_BITS(mapper83_irq_counter, "7:0", V, "7:0"); // mapper83_irq_counter[7:0] <= cpu_data_in[7:0];
1774 }
1775 else {
1776 mapper83_irq_enabled = mapper83_irq_enabled_latch; //mapper83_irq_enabled <= mapper83_irq_enabled_latch;
1777 SET_BITS(mapper83_irq_counter, "15:8", V, "7:0"); // mapper83_irq_counter[15:8] <= cpu_data_in[7:0];
1778 }
1779 break;
1780 case 0b11:
1781 if (!get_bits(A, "4")) // if (!cpu_addr_in[4])
1782 {
1783 switch (get_bits(A, "1:0")) // case (cpu_addr_in[1:0])
1784 {
1785 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];
1786 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];
1787 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];
1788 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];
1789 }
1790 }
1791 else {
1792 if (!(flags & 0b100))
1793 {
1794 switch (get_bits(A, "2:0")) // case (cpu_addr_in[2:0])
1795 {
1796 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];
1797 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];
1798 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];
1799 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];
1800 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];
1801 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];
1802 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];
1803 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];
1804 }
1805 }
1806 else {
1807 switch (get_bits(A, "2:0")) // case (cpu_addr_in[2:0])
1808 {
1809 case 0b000:
1810 SET_BITS(chr_bank_a, "8:1", V, "7:0"); break; // 3'b000: chr_bank_a[8:1] <= cpu_data_in[7:0];
1811 case 0b001:
1812 SET_BITS(chr_bank_c, "8:1", V, "7:0"); break; // 3'b001: chr_bank_c[8:1] <= cpu_data_in[7:0];
1813 case 0b110:
1814 SET_BITS(chr_bank_e, "8:1", V, "7:0"); break; // 3'b110: chr_bank_e[8:1] <= cpu_data_in[7:0];
1815 case 0b111:
1816 SET_BITS(chr_bank_g, "8:1", V, "7:0"); break; // 3'b111: chr_bank_g[8:1] <= cpu_data_in[7:0];
1817 }
1818 }
1819 }
1820 break;
1821 }
1822 }
1823
1824 // Mapper #67 - Sunsoft-3
1825 if (mapper == 0b100100)
1826 {
1827 if (get_bits(A, "11")) // if (cpu_addr_in[11])
1828 {
1829 switch (get_bits(A, "14:12")) // case (cpu_addr_in[14:12])
1830 {
1831 case 0b000: // 3'b000: chr_bank_a[6:1] <= cpu_data_in[5:0]; // $8800
1832 SET_BITS(chr_bank_a, "6:1", V, "5:0"); break;
1833 case 0b001: // 3'b001: chr_bank_c[6:1] <= cpu_data_in[5:0]; // $9800
1834 SET_BITS(chr_bank_c, "6:1", V, "5:0"); break;
1835 case 0b010: // 3'b010: chr_bank_e[6:1] <= cpu_data_in[5:0]; // $A800
1836 SET_BITS(chr_bank_e, "6:1", V, "5:0"); break;
1837 case 0b011: // 3'b011: chr_bank_g[6:1] <= cpu_data_in[5:0]; // $B800
1838 SET_BITS(chr_bank_g, "6:1", V, "5:0"); break;
1839 case 0b100: // 3'b100: begin // $C800, IRQ load
1840 mapper67_irq_latch = ~mapper67_irq_latch;
1841 if (mapper67_irq_latch)
1842 SET_BITS(mapper67_irq_counter, "15:8", V, "7:0"); // mapper67_irq_counter[15:8] <= cpu_data_in[7:0];
1843 else
1844 SET_BITS(mapper67_irq_counter, "7:0", V, "7:0"); // mapper67_irq_counter[7:0] <= cpu_data_in[7:0];
1845 break;
1846 case 0b101: // 3'b101: begin // $D800, IRQ enable
1847 mapper67_irq_latch = 0; // mapper67_irq_latch <= 0;
1848 SET_BITS(mapper67_irq_enabled, "0", V, "4"); // mapper67_irq_enabled <= cpu_data_in[4];
1849 break;
1850 case 0b110: // 3'b110: mirroring[1:0] <= cpu_data_in[1:0]; // $E800
1851 SET_BITS(mirroring, "1:0", V, "1:0");
1852 break;
1853 case 0b111: // 3'b111: prg_bank_a[4:1] <= cpu_data_in[3:0]; // $F800
1854 SET_BITS(prg_bank_a, "4:1", V, "3:0");
1855 break;
1856 }
1857 }
1858 else {
1859 // Interrupt Acknowledge ($8000)
1860 X6502_IRQEnd(FCEU_IQEXT); // mapper67_irq_out <= 0;
1861 }
1862 }
1863
1864 // Mapper #89 - Sunsoft-2 chip on the Sunsoft-3 board
1865 if (mapper == 0b100101)
1866 {
1867 // prg_bank_a[3:1] <= cpu_data_in[6:4];
1868 SET_BITS(prg_bank_a, "3:1", V, "6:4");
1869 // chr_bank_a[6:3] <= {cpu_data_in[7], cpu_data_in[2:0]};
1870 SET_BITS(chr_bank_a, "6:3", V, "7,2:0");
1871 // mirroring[1:0] <= {1'b1, cpu_data_in[3]};
1872 SET_BITS(mirroring, "1", 1, "0");
1873 SET_BITS(mirroring, "0", V, "3");
1874 }
1875 }
1876
1877 COOLGIRL_Sync();
1878 }
1879
1880 static DECLFR(MAFRAM) {
1881 if ((mapper == 0b000000) && (A >= 0x5000) && (A < 0x6000))
1882 return 0;
1883
1884 // Mapper #163
1885 // (USE_MAPPER_163 && (mapper == 5'b00110) && m2 && romsel && cpu_rw_in && ((cpu_addr_in[14:8] & 7'h77) == 7'h51)) ?
1886 if ((mapper == 0b000110) && ((A & 0x7700) == 0x5100))
1887 return mapper163_r2 | mapper163_r0 | mapper163_r1 | ~mapper163_r3; // {1'b1, r2 | r0 | r1 | ~r3}
1888 // (USE_MAPPER_163 && (mapper == 5'b00110) && m2 && romsel && cpu_rw_in && ((cpu_addr_in[14:8] & 7'h77) == 7'h55)) ?
1889 if ((mapper == 0b000110) && ((A & 0x7700) == 0x5500))
1890 return (mapper163_r5 & 1) ? mapper163_r2 : mapper163_r1; // {1'b1, r5[0] ? r2 : r1}
1891
1892 // MMC5
1893 if ((mapper == 0b001111) && (A == 0x5204))
1894 {
1895 int ppuon = (PPU[1] & 0x18);
1896 uint8 r = (!ppuon || scanline + 1 >= 241) ? 0 : 1;
1897 uint8 p = mmc5_irq_out;
1898 X6502_IRQEnd(FCEU_IQEXT);
1899 mmc5_irq_out = 0;
1900 return (p << 7) | (r << 6);
1901 }
1902
1903 // Mapper #36 is assigned to TXC's PCB 01-22000-400
1904 if ((mapper == 0b011101) && ((A & 0xE100) == 0x4100)) // (USE_MAPPER_036 && mapper == 5'b11101 && {cpu_addr_in[14:13], cpu_addr_in[8]} == 3'b101) ?
1905 {
1906 return (prg_bank_a & 0x0C) << 2; // {1'b1, 2'b00, prg_bank_a[3:2], 4'b00}
1907 }
1908
1909 // Mapper #83 - Cony/Yoko
1910 if ((mapper == 0b100011) && ((A & 0x7000) == 0x5000)) return flags & 3;
1911
1912 // Mapper #90 - JY
1913 if ((mapper == 0b001101) && (A == 0x5800)) return (mul1 * mul2) & 0xFF;
1914 if ((mapper == 0b001101) && (A == 0x5801)) return ((mul1 * mul2) >> 8) & 0xFF;
1915
1916 if (sram_enabled && !map_rom_on_6000 && (A >= 0x6000) && (A < 0x8000))
1917 return CartBR(A); // SRAM
1918 if (map_rom_on_6000 && (A >= 0x6000) && (A < 0x8000))
1919 return CartBR(A); // PRG
1920
1921 return X.DB; // Open bus
1922 }
1923
1924 static void COOLGIRL_ScanlineCounter(void) {
1925 // for MMC3 and MMC3-based
1926 if (mmc3_irq_reload || !mmc3_irq_counter)
1927 {
1928 mmc3_irq_counter = mmc3_irq_latch;
1929 mmc3_irq_reload = 0;
1930 }
1931 else
1932 mmc3_irq_counter--;
1933 if (!mmc3_irq_counter && mmc3_irq_enabled)
1934 X6502_IRQBegin(FCEU_IQEXT);
1935
1936 // for MMC5
1937 if (mmc5_irq_line == scanline + 1)
1938 {
1939 if (mmc5_irq_enabled)
1940 {
1941 X6502_IRQBegin(FCEU_IQEXT);
1942 mmc5_irq_out = 1;
1943 }
1944 }
1945
1946 // for mapper #163
1947 if (scanline == 239)
1948 {
1949 mapper_163_latch = 0;
1950 COOLGIRL_Sync_CHR();
1951 }
1952 else if (scanline == 127)
1953 {
1954 mapper_163_latch = 1;
1955 COOLGIRL_Sync_CHR();
1956 }
1957 }
1958
1959 static void COOLGIRL_CpuCounter(int a) {
1960 while (a--)
1961 {
1962 // Mapper #23 - VRC4
1963 if (vrc4_irq_control & 2) // if (ENABLE_MAPPER_021_022_023_025 & ENABLE_VRC4_INTERRUPTS & (vrc4_irq_control[1]))
1964 {
1965 // Cycle mode without prescaler is not used by any games? It's missed in fceux source code.
1966 if (vrc4_irq_control & 4) // if (vrc4_irq_control[2]) // cycle mode
1967 {
1968 FCEU_PrintError("Cycle IRQ mode is not supported, please report to Cluster");
1969 vrc4_irq_value++; // {carry, vrc4_irq_value[7:0]} = vrc4_irq_value[7:0] + 1'b1; // just count IRQ value
1970 if (vrc4_irq_value == 0) // if (carry)
1971 {
1972 X6502_IRQBegin(FCEU_IQEXT); // vrc4_irq_out = 1;
1973 vrc4_irq_value = vrc4_irq_latch; // vrc4_irq_value[7:0] = vrc4_irq_latch[7:0];
1974 }
1975 }
1976 else {
1977 vrc4_irq_prescaler++; // vrc4_irq_prescaler = vrc4_irq_prescaler + 1'b1; // count prescaler
1978 // if ((vrc4_irq_prescaler_counter[1] == 0 && vrc4_irq_prescaler == 114)
1979 // || (vrc4_irq_prescaler_counter[1] == 1 && vrc4_irq_prescaler == 113)) // 114, 114, 113
1980 if ((!(vrc4_irq_prescaler_counter & 2) && vrc4_irq_prescaler == 114) || ((vrc4_irq_prescaler_counter & 2) && vrc4_irq_prescaler == 113))
1981 {
1982 vrc4_irq_prescaler = 0; // vrc4_irq_prescaler = 0;
1983 vrc4_irq_prescaler_counter++; // vrc4_irq_prescaler_counter = vrc4_irq_prescaler_counter + 1'b1;
1984 if (vrc4_irq_prescaler_counter == 0b11) vrc4_irq_prescaler_counter = 0; // if (vrc4_irq_prescaler_counter == 2'b11) vrc4_irq_prescaler_counter = 2'b00;
1985 vrc4_irq_value++; // {carry, vrc4_irq_value[7:0]} = vrc4_irq_value[7:0] + 1'b1;
1986 if (vrc4_irq_value == 0) // f (carry)
1987 {
1988 X6502_IRQBegin(FCEU_IQEXT);
1989 vrc4_irq_value = vrc4_irq_latch; // irq_cpu_value[7:0] = vrc4_irq_latch[7:0];
1990 }
1991 }
1992 }
1993 }
1994
1995 // Mapper #73 - VRC3
1996 if (vrc3_irq_control & 2)
1997 {
1998 if (vrc3_irq_control & 4) // if (vrc3_irq_control[2])
1999 { // 8-bit mode
2000 //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;
2001 vrc3_irq_value = (vrc3_irq_value & 0xFF00) | ((vrc3_irq_value + 1) & 0xFF);
2002 //if (get_bits(vrc3_irq_value, "7:0") == 0) // if (vrc3_irq_value[7:0] == 0)
2003 if ((vrc3_irq_value & 0xFF) == 0)
2004 {
2005 X6502_IRQBegin(FCEU_IQEXT); // vrc3_irq_out = 1;
2006 //SET_BITS(vrc3_irq_value, "7:0", vrc3_irq_latch, "7:0"); // vrc3_irq_value[7:0] = vrc3_irq_latch[7:0];
2007 vrc3_irq_value = (vrc3_irq_value & 0xFF00) | (vrc3_irq_latch & 0xFF);
2008 }
2009 }
2010 else { // 16-bit
2011 //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;
2012 vrc3_irq_value += 1;
2013 if (vrc3_irq_value == 0) // if (vrc3_irq_value[15:0] == 0)
2014 {
2015 X6502_IRQBegin(FCEU_IQEXT); // vrc3_irq_out = 1;
2016 //SET_BITS(vrc3_irq_value, "15:0", vrc3_irq_latch, "15:0"); // vrc3_irq_value[15:0] = vrc3_irq_latch[15:0];
2017 vrc3_irq_value = vrc3_irq_latch;
2018 }
2019 }
2020 }
2021
2022 // Mapper #69 - Sunsoft FME-7
2023 // if (ENABLE_MAPPER_069 & fme7_counter_enabled)
2024 if (mapper69_counter_enabled)
2025 {
2026 // {carry, fme7_irq_value[15:0]} = {0'b0, fme7_irq_value[15:0]} - 1'b1;
2027 mapper69_irq_value--;
2028 // if (fme7_irq_enabled && carry) fme7_irq_out = 1;
2029 if (mapper69_irq_value == 0xFFFF) X6502_IRQBegin(FCEU_IQEXT);
2030 }
2031
2032 // Mapper #18
2033 if (mapper18_irq_control & 1) // if (mapper18_irq_control[0])
2034 {
2035 uint8 carry;
2036 //carry = get_bits(mapper18_irq_value, "3:0") - 1;
2037 carry = (mapper18_irq_value & 0x0F) - 1;
2038 //SET_BITS(mapper18_irq_value, "3:0", carry, "3:0");
2039 mapper18_irq_value = (mapper18_irq_value & 0xFFF0) | (carry & 0x0F);
2040 carry = (carry >> 4) & 1;
2041 // if (mapper18_irq_control[3] == 1'b0)
2042 if (!(mapper18_irq_control & 0b1000))
2043 {
2044 //carry = get_bits(mapper18_irq_value, "7:4") - carry;
2045 carry = ((mapper18_irq_value >> 4) & 0x0F) - carry;
2046 //SET_BITS(mapper18_irq_value, "7:4", carry, "3:0");
2047 mapper18_irq_value = (mapper18_irq_value & 0xFF0F) | ((carry & 0x0F) << 4);
2048 carry = (carry >> 4) & 1;
2049 }
2050 // if (mapper18_irq_control[3:2] == 2'b00)
2051 if (!(mapper18_irq_control & 0b1100))
2052 {
2053 //carry = get_bits(mapper18_irq_value, "11:8") - carry;
2054 carry = ((mapper18_irq_value >> 8) & 0x0F) - carry;
2055 //SET_BITS(mapper18_irq_value, "11:8", carry, "3:0");
2056 mapper18_irq_value = (mapper18_irq_value & 0xF0FF) | ((carry & 0x0F) << 8);
2057 carry = (carry >> 4) & 1;
2058 }
2059 // if (mapper18_irq_control[3:1] == 3'b000)
2060 if (!(mapper18_irq_control & 0b1110))
2061 {
2062 //carry = get_bits(mapper18_irq_value, "15:12") - carry;
2063 carry = ((mapper18_irq_value >> 12) & 0x0F) - carry;
2064 //SET_BITS(mapper18_irq_value, "15:12", carry, "3:0");
2065 mapper18_irq_value = (mapper18_irq_value & 0x0FFF) | ((carry & 0x0F) << 12);
2066 carry = (carry >> 4) & 1;
2067 }
2068 if (carry)
2069 X6502_IRQBegin(FCEU_IQEXT);
2070 }
2071
2072 // Mapper #65 - Irem's H3001
2073 // if (mapper65_irq_enabled)
2074 if (mapper65_irq_enabled)
2075 {
2076 if (mapper65_irq_value != 0) // if (mapper65_irq_value[15:0] != 0)
2077 {
2078 mapper65_irq_value--; // mapper65_irq_value[15:0] = mapper65_irq_value[15:0] - 1;
2079 if (!mapper65_irq_value)
2080 X6502_IRQBegin(FCEU_IQEXT); // if (mapper65_irq_value[15:0] == 0) irq_cpu_out = 1;
2081 }
2082 }
2083
2084 // Mapper #42
2085 if (mapper42_irq_enabled)
2086 {
2087 //mapper42_irq_value = set_bits(mapper42_irq_value, "14:0", get_bits(mapper42_irq_value, "14:0") + 1);
2088 //if (get_bits(mapper42_irq_value, "14:13") == 0b11)
2089 mapper42_irq_value++;
2090 if (mapper42_irq_value >> 15) mapper42_irq_value = 0;
2091 if (((mapper42_irq_value >> 13) & 0b11) == 0b11)
2092 X6502_IRQBegin(FCEU_IQEXT);
2093 else
2094 X6502_IRQEnd(FCEU_IQEXT);
2095 }
2096
2097 // Mapper #83 - Cony/Yoko
2098 if (mapper83_irq_enabled)
2099 {
2100 if (mapper83_irq_counter == 0) // if (mapper83_irq_counter == 0)
2101 X6502_IRQBegin(FCEU_IQEXT); // mapper83_irq_out <= 1;
2102 mapper83_irq_counter--; // mapper83_irq_counter = mapper83_irq_counter - 1'b1;
2103 }
2104
2105 // Mapper #67 - Sunsoft-3
2106 if (mapper67_irq_enabled)
2107 {
2108 mapper67_irq_counter--; // mapper67_irq_counter = mapper67_irq_counter - 1'b1;
2109 if (mapper67_irq_counter == 0xFFFF) // if (mapper67_irq_counter == 16'hFFFF)
2110 {
2111 X6502_IRQBegin(FCEU_IQEXT); // mapper67_irq_out <= 1; // fire IRQ
2112 mapper67_irq_enabled = 0; // mapper67_irq_enabled <= 0; // disable IRQ
2113 }
2114 }
2115 }
2116 }
2117
2118 static void COOLGIRL_PPUHook(uint32 A) {
2119 // For TxROM
2120 if ((mapper == 0b010100) && (flags & 1))
2121 {
2122 setmirror(MI_0 + (TKSMIR[(A & 0x1FFF) >> 10] >> 7));
2123 }
2124
2125 // Mapper #9 and #10 - MMC2 and MMC4
2126 if (mapper == 0b010001)
2127 {
2128 if ((A >> 4) == 0xFD) // if (ppu_addr_in[13:3] == 11'b00111111011) ppu_latch0 = 0;
2129 {
2130 ppu_latch0 = 0;
2131 COOLGIRL_Sync_CHR();
2132 }
2133 if ((A >> 4) == 0xFE) // if (ppu_addr_in[13:3] == 11'b00111111101) ppu_latch0 = 1;
2134 {
2135 ppu_latch0 = 1;
2136 COOLGIRL_Sync_CHR();
2137 }
2138 if ((A >> 4) == 0x1FD) // if (ppu_addr_in[13:3] == 11'b01111111011) ppu_latch1 = 0;
2139 {
2140 ppu_latch1 = 0;
2141 COOLGIRL_Sync_CHR();
2142 }
2143 if ((A >> 4) == 0x1FE) // if (ppu_addr_in[13:3] == 11'b01111111101) ppu_latch1 = 1;
2144 {
2145 ppu_latch1 = 1;
2146 COOLGIRL_Sync_CHR();
2147 }
2148 }
2149 }
2150
2151 static void COOLGIRL_Reset(void) {
2152 sram_enabled = 0;
2153 sram_page = 0;
2154 can_write_chr = 0;
2155 map_rom_on_6000 = 0;
2156 flags = 0;
2157 mapper = 0;
2158 can_write_flash = 0;
2159 mirroring = 0;
2160 four_screen = 0;
2161 lockout = 0;
2162 prg_base = 0;
2163 prg_mask = 0b11111000 << 14;
2164 prg_mode = 0;
2165 prg_bank_6000 = 0;
2166 prg_bank_a = 0;
2167 prg_bank_b = 1;
2168 prg_bank_c = ~1;
2169 prg_bank_d = ~0;
2170 chr_mask = 0;
2171 chr_mode = 0;
2172 chr_bank_a = 0;
2173 chr_bank_b = 1;
2174 chr_bank_c = 2;
2175 chr_bank_d = 3;
2176 chr_bank_e = 4;
2177 chr_bank_f = 5;
2178 chr_bank_g = 6;
2179 chr_bank_h = 7;
2180 ppu_latch0 = 0;
2181 ppu_latch1 = 0;
2182 lreset = 0;
2183 mmc1_load_register = 0;
2184 mmc3_internal = 0;
2185 mapper69_internal = 0;
2186 mapper112_internal = 0;
2187 mapper_163_latch = 0;
2188 mapper163_r0 = 0;
2189 mapper163_r1 = 0;
2190 mapper163_r2 = 0;
2191 mapper163_r3 = 0;
2192 mapper163_r4 = 0;
2193 mapper163_r5 = 0;
2194 mul1 = 0;
2195 mul2 = 0;
2196 mmc3_irq_enabled = 0;
2197 mmc3_irq_latch = 0;
2198 mmc3_irq_counter = 0;
2199 mmc3_irq_reload = 0;
2200 mmc5_irq_enabled = 0;
2201 mmc5_irq_line = 0;
2202 mmc5_irq_out = 0;
2203 mapper18_irq_value = 0;
2204 mapper18_irq_control = 0;
2205 mapper18_irq_latch = 0;
2206 mapper65_irq_enabled = 0;
2207 mapper65_irq_value = 0;
2208 mapper65_irq_latch = 0;
2209 mapper69_irq_enabled = 0;
2210 mapper69_counter_enabled = 0;
2211 mapper69_irq_value = 0;
2212 vrc4_irq_value = 0;
2213 vrc4_irq_control = 0;
2214 vrc4_irq_latch = 0;
2215 vrc4_irq_prescaler = 0;
2216 vrc4_irq_prescaler_counter = 0;
2217 vrc3_irq_value = 0;
2218 vrc3_irq_control = 0;
2219 vrc3_irq_latch = 0;
2220 mapper42_irq_enabled = 0;
2221 mapper42_irq_value = 0;
2222 mapper90_xor = 0;
2223 flash_state = 0;
2224 cfi_mode = 0;
2225 COOLGIRL_Sync();
2226 }
2227
2228 static void COOLGIRL_Power(void) {
2229 FCEU_CheatAddRAM(32, 0x6000, WRAM);
2230 SetReadHandler(0x4020, 0x7FFF, MAFRAM);
2231 SetReadHandler(0x8000, 0xFFFF, CartBR);
2232 SetWriteHandler(0x4020, 0xFFFF, COOLGIRL_WRITE);
2233 GameHBIRQHook = COOLGIRL_ScanlineCounter;
2234 MapIRQHook = COOLGIRL_CpuCounter;
2235 PPU_hook = COOLGIRL_PPUHook;
2236 COOLGIRL_Reset();
2237 }
2238
2239 static void COOLGIRL_Close(void) {
2240 if (CHR_RAM)
2241 FCEU_gfree(CHR_RAM);
2242 if (WRAM)
2243 FCEU_gfree(WRAM);
2244 if (SAVE_FLASH)
2245 FCEU_gfree(SAVE_FLASH);
2246 if (CFI)
2247 FCEU_gfree(CFI);
2248 CHR_RAM = WRAM = SAVE_FLASH = CFI = NULL;
2249 }
2250
2251 static void COOLGIRL_Restore(int version) {
2252 COOLGIRL_Sync();
2253 lreset = 0;
2254 }
2255
2256 #define ExState(var, varname) AddExState(&var, sizeof(var), 0, varname)
2257
2258 void COOLGIRL_Init(CartInfo *info) {
2259 CHR_RAM_SIZE = info->ines2 ? (info->vram_size + info->battery_vram_size) : (512 * 1024);
2260 CHR_RAM = (uint8*)FCEU_gmalloc(CHR_RAM_SIZE);
2261 memset(CHR_RAM, 0, CHR_RAM_SIZE);
2262 SetupCartCHRMapping(CHR_RAM_CHIP, CHR_RAM, CHR_RAM_SIZE, 0);
2263 AddExState(CHR_RAM, sizeof(CHR_RAM_SIZE), 0, "CHR_");
2264
2265 WRAM_SIZE = info->ines2 ? (info->wram_size + info->battery_wram_size) : (32 * 1024);
2266 if (WRAM_SIZE > 0) {
2267 WRAM = (uint8*)FCEU_gmalloc(WRAM_SIZE);
2268 memset(WRAM, 0, WRAM_SIZE);
2269 SetupCartPRGMapping(WRAM_CHIP, WRAM, WRAM_SIZE, 1);
2270 AddExState(WRAM, 32 * 1024, 0, "SRAM");
2271 if (info->battery)
2272 {
2273 info->SaveGame[0] = WRAM;
2274 info->SaveGameLen[0] = 32 * 1024;
2275 }
2276 }
2277
2278 if (info->battery)
2279 {
2280 SAVE_FLASH = (uint8*)FCEU_gmalloc(SAVE_FLASH_SIZE);
2281 SetupCartPRGMapping(FLASH_CHIP, SAVE_FLASH, SAVE_FLASH_SIZE, 1);
2282 AddExState(SAVE_FLASH, SAVE_FLASH_SIZE, 0, "SAVF");
2283 info->SaveGame[1] = SAVE_FLASH;
2284 info->SaveGameLen[1] = SAVE_FLASH_SIZE;
2285 }
2286
2287 CFI = (uint8*)FCEU_gmalloc(sizeof(cfi_data) * 2);
2288 for (size_t i = 0; i < sizeof(cfi_data); i++)
2289 {
2290 CFI[i * 2] = CFI[i * 2 + 1] = cfi_data[i];
2291 }
2292 SetupCartPRGMapping(CFI_CHIP, CFI, sizeof(cfi_data) * 2, 0);
2293
2294 ExState(sram_enabled, "SREN");
2295 ExState(sram_page, "SRPG");
2296 ExState(can_write_chr, "SRWR");
2297 ExState(map_rom_on_6000, "MR6K");
2298 ExState(flags, "FLGS");
2299 ExState(mapper, "MPPR");
2300 ExState(can_write_flash, "FLWR");
2301 ExState(mirroring, "MIRR");
2302 ExState(four_screen, "4SCR");
2303 ExState(lockout, "LOCK");
2304 ExState(prg_base, "PBAS");
2305 ExState(prg_mask, "PMSK");
2306 ExState(prg_mode, "PMOD");
2307 ExState(prg_bank_6000, "P6BN");
2308 ExState(prg_bank_a, "PABN");
2309 ExState(prg_bank_b, "PBBN");
2310 ExState(prg_bank_c, "PCBN");
2311 ExState(prg_bank_d, "PDBN");
2312 ExState(chr_mask, "CMSK");
2313 ExState(chr_mode, "CMOD");
2314 ExState(chr_bank_a, "CABN");
2315 ExState(chr_bank_b, "CBBN");
2316 ExState(chr_bank_c, "CCBN");
2317 ExState(chr_bank_d, "CDBN");
2318 ExState(chr_bank_e, "CEBN");
2319 ExState(chr_bank_f, "CFBN");
2320 ExState(chr_bank_g, "CGBN");
2321 ExState(chr_bank_h, "CHBN");
2322 ExState(ppu_latch0, "PPU0");
2323 ExState(ppu_latch1, "PPU1");
2324 ExState(lreset, "LRST");
2325 ExState(mmc1_load_register, "M01R");
2326 ExState(mmc3_internal, "M01I");
2327 ExState(mapper69_internal, "M69I");
2328 ExState(mapper112_internal, "112I");
2329 ExState(mapper_163_latch, "163L");
2330 ExState(mapper163_r0, "1630");
2331 ExState(mapper163_r1, "1631");
2332 ExState(mapper163_r2, "1632");
2333 ExState(mapper163_r3, "1633");
2334 ExState(mapper163_r4, "1634");
2335 ExState(mapper163_r5, "1635");
2336 ExState(mul1, "MUL1");
2337 ExState(mul2, "MUL2");
2338 ExState(mmc3_irq_enabled, "M4IE");
2339 ExState(mmc3_irq_latch, "M4IL");
2340 ExState(mmc3_irq_counter, "M4IC");
2341 ExState(mmc3_irq_reload, "M4IR");
2342 ExState(mmc5_irq_enabled, "M5IE");
2343 ExState(mmc5_irq_line, "M5IL");
2344 ExState(mmc5_irq_out, "M5IO");
2345 ExState(mapper18_irq_value, "18IV");
2346 ExState(mapper18_irq_control, "18IC");
2347 ExState(mapper18_irq_latch, "18IL");
2348 ExState(mapper65_irq_enabled, "65IE");
2349 ExState(mapper65_irq_value, "65IV");
2350 ExState(mapper65_irq_latch, "65IL");
2351 ExState(mapper69_irq_enabled, "69IE");
2352 ExState(mapper69_counter_enabled, "69CE");
2353 ExState(mapper69_irq_value, "69IV");
2354 ExState(vrc4_irq_value, "V4IV");
2355 ExState(vrc4_irq_control, "V4IC");
2356 ExState(vrc4_irq_latch, "V4IL");
2357 ExState(vrc4_irq_prescaler, "V4PP");
2358 ExState(vrc4_irq_prescaler_counter, "V4PC");
2359 ExState(vrc3_irq_value, "V3IV");
2360 ExState(vrc3_irq_control, "V3IC");
2361 ExState(vrc3_irq_latch, "V3IL");
2362 ExState(mapper42_irq_enabled, "42IE");
2363 ExState(mapper42_irq_value, "42IV");
2364 ExState(mapper83_irq_enabled_latch, "M83L");
2365 ExState(mapper83_irq_enabled, "M83I");
2366 ExState(mapper83_irq_counter, "M83C");
2367 ExState(mapper90_xor, "90XR");
2368 ExState(mapper67_irq_enabled, "67IE");
2369 ExState(mapper67_irq_latch, "67IL");
2370 ExState(mapper67_irq_counter, "67IC");
2371 ExState(flash_state, "FLST");
2372 ExState(flash_buffer_a, "FLBA");
2373 ExState(flash_buffer_v, "FLBV");
2374 ExState(cfi_mode, "CFIM");
2375
2376 info->Power = COOLGIRL_Power;
2377 info->Reset = COOLGIRL_Reset;
2378 info->Close = COOLGIRL_Close;
2379 GameStateRestore = COOLGIRL_Restore;
2380 }
473473 Latch_Init(info, M203Sync, 0, 0x8000, 0xFFFF, 0, 0);
474474 }
475475
476 //------------------ Map 218 ---------------------------
477
478 static void Mapper218_Power()
479 {
480 //doesn't really matter
481 SetReadHandler(0x6000, 0xFFFF, &CartBROB);
482 }
483
484 void Mapper218_Init(CartInfo *info)
485 {
486 info->Power = &Mapper218_Power;
487
488 //fixed PRG mapping
489 setprg32(0x8000, 0);
490
491 //this mapper is supposed to interpret the iNES header bits specially
492 static const uint8 mirrorings[] = {MI_V,MI_H,MI_0,MI_1};
493 SetupCartMirroring(mirrorings[info->mirrorAs2Bits],1,nullptr);
494
495 //cryptic logic to effect the CHR RAM mappings by mapping 1k blocks to NTARAM according to how the pins are wired
496 //this could be done by bit logic, but this is self-documenting
497 static const uint8 mapping[] = {
498 0,1,0,1,0,1,0,1, //mirrorAs2Bits==0
499 0,0,1,1,0,0,1,1, //mirrorAs2Bits==1
500 0,0,0,0,1,1,1,1, //mirrorAs2Bits==2
501 0,0,0,0,0,0,0,0 //mirrorAs2Bits==3
502 };
503 for(int i=0;i<8;i++)
504 VPageR[i] = &NTARAM[mapping[info->mirrorAs2Bits*8+i]];
505
506 PPUCHRRAM = 0xFF;
507 }
508
476509 //------------------ Map 240 ---------------------------
477510
478511 static void M240Sync(void) {
3333 static int kanji_pos, kanji_page, r40C0;
3434 static int IRQa, IRQCount;
3535
36 FCEU_MAYBE_UNUSED
3637 static DECLFW(MBWRAM) {
3738 if (!(DRegs[3] & 0x10))
3839 Page[A >> 11][A] = V;
3940 }
4041
42 FCEU_MAYBE_UNUSED
4143 static DECLFR(MAWRAM) {
4244 if (DRegs[3] & 0x10)
4345 return X.DB;
0 /* FCE Ultra - NES/Famicom Emulator
1 *
2 * Copyright notice for this file:
3 * Copyright (C) 2022 Cluster
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * NES 2.0 Mapper 470 denotes the INX_007T_V01 multicart circuit board,
20 * used for the Retro-Bit re-release of Battletoads and Double Dragon.
21 * It is basically AOROM with an additional outer bank register at $5000-$5FFF
22 * whose data selects the 256 KiB outer bank.
23 *
24 * $5000-$5FFF
25 * 7 bit 0
26 * ---- ----
27 * xxxx xxOO
28 * ||
29 * ++- Select outer 256 KB PRG ROM bank for CPU $8000-$FFFF
30 *
31 * $8000-$FFFF
32 * 7 bit 0
33 * ---- ----
34 * xxxM xPPP
35 * | |||
36 * | +++- Select inner 32 KB PRG ROM bank for CPU $8000-$FFFF
37 * +------ Select 1 KB VRAM page for all 4 nametables
38 *
39 */
40
41 #include "mapinc.h"
42
43 static uint8 latch_out, latch_in;
44
45 static void INX_007T_Sync() {
46 setprg32(0x8000, (latch_in & 0b111) | (latch_out << 3));
47 setmirror(MI_0 + ((latch_in >> 4) & 1));
48 setchr8(0);
49 }
50
51 static void StateRestore(int version) {
52 INX_007T_Sync();
53 }
54
55 static DECLFW(INX_007T_WriteLow)
56 {
57 latch_out = V;
58 INX_007T_Sync();
59 }
60
61 static DECLFW(INX_007T_WriteHi)
62 {
63 latch_in = V;
64 INX_007T_Sync();
65 }
66
67 static void INX_007T_Power(void) {
68 latch_in = latch_out = 0;
69 INX_007T_Sync();
70 SetReadHandler(0x8000, 0xFFFF, CartBR);
71 SetWriteHandler(0x5000,0x5FFF, INX_007T_WriteLow);
72 SetWriteHandler(0x8000, 0xFFFF, INX_007T_WriteHi);
73 }
74
75 static void INX_007T_Reset(void) {
76 latch_in = latch_out = 0;
77 INX_007T_Sync();
78 }
79
80 void INX_007T_Init(CartInfo *info) {
81 info->Power = INX_007T_Power;
82 info->Reset = INX_007T_Reset;
83 GameStateRestore = StateRestore;
84 SetupCartMirroring(MI_0, 0, NULL);
85 AddExState(&latch_out, 1, 0, "LATO");
86 AddExState(&latch_in, 1, 0, "LATI");
87 }
13751375 MMC3_IRQWrite((A & 0xFFFE) | ((A & 2) >> 1), V);
13761376 }
13771377
1378 FCEU_MAYBE_UNUSED
13781379 static DECLFW(M406Write) {
13791380 }
13801381
306306
307307 #define MMC5_NOCARTS (sizeof(MMC5CartList) / sizeof(MMC5CartList[0]))
308308 int DetectMMC5WRAMSize(uint32 crc32) {
309 int x;
310 for (x = 0; x < MMC5_NOCARTS; x++) {
309 for (size_t x = 0; x < MMC5_NOCARTS; x++) {
311310 if (crc32 == MMC5CartList[x].crc32) {
312311 if(MMC5CartList[x].size > 1)
313312 FCEU_printf(" >8KB external WRAM present. Use UNIF if you hack the ROM image.\n");
00 /* FCE Ultra - NES/Famicom Emulator
11 *
22 * Copyright notice for this file:
3 * Copyright (C) 2014 CaitSith2
3 * Copyright (C) 2014 CaitSith2, 2022 Cluster
44 *
55 * This program is free software; you can redistribute it and/or modify
66 * it under the terms of the GNU General Public License as published by
1818 */
1919
2020 /*
21 * Roms still using NES 1.0 format should be loaded as 32K CHR RAM.
21 * Roms still using NES 1.0 format should be loaded as 8K CHR RAM.
2222 * 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.
2323 * UNIF doesn't have this problem, because unique board names can define this information.
2424 * The UNIF names are UNROM-512-8K, UNROM-512-16K and UNROM-512-32K
2727 * Known games to use this board are:
2828 * Battle Kid 2: Mountain of Torment (512K PRG, 8K CHR RAM, Horizontal Mirroring, Flash disabled)
2929 * Study Hall (128K PRG (in 512K flash chip), 8K CHR RAM, Horizontal Mirroring, Flash enabled)
30 * Nix: The Paradox Relic (512 PRG, 8K CHR RAM, Vertical Mirroring, Flash enabled)
3031 * Although Xmas 2013 uses a different board, where LEDs can be controlled (with writes to the $8000-BFFF space),
3132 * it otherwise functions identically.
3233 */
3435 #include "mapinc.h"
3536 #include "../ines.h"
3637
37 static uint8 latche, latcheinit, bus_conflict, chrram_mask, software_id=false;
38 const int ROM_CHIP = 0x00;
39 const int CFI_CHIP = 0x10;
40 const int FLASH_CHIP = 0x11;
41
42 const int FLASH_SECTOR_SIZE = 4 * 1024;
43
44 static uint8 flash_save, flash_state, flash_id_mode, latche, bus_conflict;
3845 static uint16 latcha;
39 static uint8 *flashdata;
40 static uint32 *flash_write_count;
41 static uint8 *FlashPage[32];
42 //static uint32 *FlashWriteCountPage[32];
43 //static uint8 flashloaded = false;
44
45 static uint8 flash_save=0, flash_state=0, flash_mode=0, flash_bank;
46 static void (*WLSync)(void);
47 static void (*WHSync)(void);
48
49 static INLINE void setfpageptr(int s, uint32 A, uint8 *p) {
50 uint32 AB = A >> 11;
51 int x;
52
53 if (p)
54 for (x = (s >> 1) - 1; x >= 0; x--) {
55 FlashPage[AB + x] = p - A;
56 }
46 static uint8 *flash_data;
47 static uint16 flash_buffer_a[10];
48 static uint8 flash_buffer_v[10];
49 static uint8 flash_id[2];
50
51 static void UNROM512_Sync() {
52 int chip;
53 if (flash_save)
54 chip = !flash_id_mode ? FLASH_CHIP : CFI_CHIP;
5755 else
58 for (x = (s >> 1) - 1; x >= 0; x--) {
59 FlashPage[AB + x] = 0;
60 }
61 }
62
63 void setfprg16(uint32 A, uint32 V) {
64 if (PRGsize[0] >= 16384) {
65 V &= PRGmask16[0];
66 setfpageptr(16, A, flashdata ? (&flashdata[V << 14]) : 0);
67 } else {
68 uint32 VA = V << 3;
69 int x;
70
71 for (x = 0; x < 8; x++)
72 setfpageptr(2, A + (x << 11), flashdata ? (&flashdata[((VA + x) & PRGmask2[0]) << 11]) : 0);
73 }
74 }
75
76 void inc_flash_write_count(uint8 bank, uint32 A)
56 chip = ROM_CHIP;
57 setprg16r(chip, 0x8000, latche & 0b11111);
58 setprg16r(chip, 0xc000, ~0);
59 setchr8((latche >> 5) & 0b11);
60 setmirror(MI_0 + ((latche >> 7) & 1));
61 }
62
63 static void StateRestore(int version) {
64 UNROM512_Sync();
65 }
66
67 static DECLFW(UNROM512FlashWrite)
7768 {
78 flash_write_count[(bank*4) + ((A&0x3000)>>12)]++;
79 if(!flash_write_count[(bank*4) + ((A&0x3000)>>12)])
80 flash_write_count[(bank*4) + ((A&0x3000)>>12)]++;
81 }
82
83 uint32 GetFlashWriteCount(uint8 bank, uint32 A)
84 {
85 return flash_write_count[(bank*4) + ((A&0x3000)>>12)];
86 }
87
88 static void StateRestore(int version) {
89 WHSync();
90 }
91
92 static DECLFW(UNROM512LLatchWrite)
93 {
94 latche = V;
95 latcha = A;
96 WLSync();
69 if (flash_state < sizeof(flash_buffer_a) / sizeof(flash_buffer_a[0])) {
70 flash_buffer_a[flash_state] = (A & 0x3FFF) | ((latche & 1) << 14);
71 flash_buffer_v[flash_state] = V;
72 flash_state++;
73
74 // enter flash ID mode
75 if ((flash_state == 2) &&
76 (flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) &&
77 (flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) &&
78 (flash_buffer_a[1] == 0x5555) && (flash_buffer_v[1] == 0x90)) {
79 flash_id_mode = 0;
80 flash_state = 0;
81 }
82
83 // erase sector
84 if ((flash_state == 6) &&
85 (flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) &&
86 (flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) &&
87 (flash_buffer_a[2] == 0x5555) && (flash_buffer_v[2] == 0x80) &&
88 (flash_buffer_a[3] == 0x5555) && (flash_buffer_v[3] == 0xAA) &&
89 (flash_buffer_a[4] == 0x2AAA) && (flash_buffer_v[4] == 0x55) &&
90 (flash_buffer_v[5] == 0x30)) {
91 int offset = &Page[A >> 11][A] - flash_data;
92 int sector = offset / FLASH_SECTOR_SIZE;
93 for (int i = sector * FLASH_SECTOR_SIZE; i < (sector + 1) * FLASH_SECTOR_SIZE; i++)
94 flash_data[i % PRGsize[ROM_CHIP]] = 0xFF;
95 FCEU_printf("Flash sector #%d is erased (0x%08x - 0x%08x).\n", sector, offset, offset + FLASH_SECTOR_SIZE);
96 }
97
98 // erase chip
99 if ((flash_state == 6) &&
100 (flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) &&
101 (flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) &&
102 (flash_buffer_a[2] == 0x5555) && (flash_buffer_v[2] == 0x80) &&
103 (flash_buffer_a[3] == 0x5555) && (flash_buffer_v[3] == 0xAA) &&
104 (flash_buffer_a[4] == 0x2AAA) && (flash_buffer_v[4] == 0x55) &&
105 (flash_buffer_a[4] == 0x5555) && (flash_buffer_v[4] == 0x10)) {
106 memset(flash_data, 0xFF, PRGsize[ROM_CHIP]);
107 FCEU_printf("Flash chip erased.\n");
108 flash_state = 0;
109 }
110
111 // write byte
112 if ((flash_state == 4) &&
113 (flash_buffer_a[0] == 0x5555) && (flash_buffer_v[0] == 0xAA) &&
114 (flash_buffer_a[1] == 0x2AAA) && (flash_buffer_v[1] == 0x55) &&
115 (flash_buffer_a[2] == 0x5555) && (flash_buffer_v[2] == 0xA0)) {
116 int offset = &Page[A >> 11][A] - flash_data;
117 if (CartBR(A) != 0xFF) {
118 FCEU_PrintError("Error: can't write to 0x%08x, flash sector is not erased.\n", offset);
119 }
120 else {
121 CartBW(A, V);
122 }
123 flash_state = 0;
124 }
125 }
126
127 // not a command
128 if (((A & 0xFFF) != 0x0AAA) && ((A & 0xFFF) != 0x0555)) {
129 flash_state = 0;
130 }
131
132 // reset
133 if (V == 0xF0) {
134 flash_state = 0;
135 flash_id_mode = 0;
136 }
137
138 UNROM512_Sync();
97139 }
98140
99141 static DECLFW(UNROM512HLatchWrite)
100142 {
101143 if (bus_conflict)
102 latche = (V == CartBR(A)) ? V : 0;
144 latche = V & CartBR(A);
103145 else
104146 latche = V;
105147 latcha = A;
106 WHSync();
107 }
108
109 static DECLFR(UNROM512LatchRead)
110 {
111 uint8 flash_id[3]={0xB5,0xB6,0xB7};
112 if(software_id)
113 {
114 if(A&1)
115 return flash_id[ROM_size>>4];
116 else
117 return 0xBF;
118 }
119 if(flash_save)
120 {
121 if(A < 0xC000)
122 {
123 if(GetFlashWriteCount(flash_bank,A))
124 return FlashPage[A >> 11][A];
125 }
126 else
127 {
128 if(GetFlashWriteCount(ROM_size-1,A))
129 return FlashPage[A >> 11][A];
130 }
131 }
132 return Page[A >> 11][A];
148 UNROM512_Sync();
133149 }
134150
135151 static void UNROM512LatchPower(void) {
136 latche = latcheinit;
137 WHSync();
138 SetReadHandler(0x8000, 0xFFFF, UNROM512LatchRead);
152 latche = 0;
153 UNROM512_Sync();
154 SetReadHandler(0x8000, 0xFFFF, CartBR);
139155 if(!flash_save)
140156 SetWriteHandler(0x8000, 0xFFFF, UNROM512HLatchWrite);
141157 else
142158 {
143 SetWriteHandler(0x8000,0xBFFF,UNROM512LLatchWrite);
159 SetWriteHandler(0x8000,0xBFFF,UNROM512FlashWrite);
144160 SetWriteHandler(0xC000,0xFFFF,UNROM512HLatchWrite);
145161 }
146162 }
147163
148164 static void UNROM512LatchClose(void) {
149 if(flash_write_count)
150 FCEU_gfree(flash_write_count);
151 if(flashdata)
152 FCEU_gfree(flashdata);
153 flash_write_count = NULL;
154 flashdata = NULL;
155 }
156
157
158 static void UNROM512LSync() {
159 int erase_a[5]={0x9555,0xAAAA,0x9555,0x9555,0xAAAA};
160 int erase_d[5]={0xAA,0x55,0x80,0xAA,0x55};
161 int erase_b[5]={1,0,1,1,0};
162
163 if(flash_mode==0)
164 {
165 if((latcha == erase_a[flash_state]) && (latche == erase_d[flash_state]) && (flash_bank == erase_b[flash_state]))
166 {
167 flash_state++;
168 if(flash_state == 5)
169 {
170 flash_mode=1;
171 }
172 }
173 else if ((flash_state==2)&&(latcha==0x9555)&&(latche==0xA0)&&(flash_bank==1))
174 {
175 flash_state++;
176 flash_mode=2;
177 }
178 else if ((flash_state==2)&&(latcha==0x9555)&&(latche==0x90)&&(flash_bank==1))
179 {
180 flash_state=0;
181 software_id=true;
182 }
183 else
184 {
185 if(latche==0xF0)
186 software_id=false;
187 flash_state=0;
188 }
189 }
190 else if(flash_mode==1) //Chip Erase or Sector Erase
191 {
192 if(latche==0x30)
193 {
194 inc_flash_write_count(flash_bank,latcha);
195 memset(&FlashPage[(latcha & 0xF000) >> 11][latcha & 0xF000],0xFF,0x1000);
196 }
197 else if (latche==0x10)
198 {
199 for(uint32 i=0;i<(ROM_size*4);i++)
200 inc_flash_write_count(i>>2,i<<12);
201 memset(flashdata,0xFF,ROM_size*0x4000); //Erasing the rom chip as instructed. Crash rate calulated to be 99.9% :)
202 }
203 flash_state=0;
204 flash_mode=0;
205 }
206 else if(flash_mode==2) //Byte Program
207 {
208 if(!GetFlashWriteCount(flash_bank,latcha))
209 {
210 inc_flash_write_count(flash_bank,latcha);
211 memcpy(&FlashPage[(latcha & 0xF000) >> 11][latcha & 0xF000],&Page[(latcha & 0xF000)>>11][latcha & 0xF000],0x1000);
212 }
213 FlashPage[latcha>>11][latcha]&=latche;
214 flash_state=0;
215 flash_mode=0;
216 }
217 }
218
219 static void UNROM512HSync()
220 {
221 flash_bank=latche&(ROM_size-1);
222
223 setprg16(0x8000, flash_bank);
224 setprg16(0xc000, ~0);
225 setfprg16(0x8000, flash_bank);
226 setfprg16(0xC000, ~0);
227 setchr8r(0, (latche & chrram_mask) >> 5);
228 setmirror(MI_0+(latche>>7));
165 if(flash_data)
166 FCEU_gfree(flash_data);
167 flash_data = NULL;
229168 }
230169
231170 void UNROM512_Init(CartInfo *info) {
232 flash_state=0;
233 flash_bank=0;
234 flash_save=info->battery;
235
236 if(info->vram_size == 8192)
237 chrram_mask = 0;
238 else if (info->vram_size == 16384)
239 chrram_mask = 0x20;
240 else
241 chrram_mask = 0x60;
171 info->Power = UNROM512LatchPower;
172 info->Close = UNROM512LatchClose;
173 GameStateRestore = StateRestore;
174
175 flash_state = 0;
176 flash_id_mode = 0;
177 flash_save = info->battery;
178 bus_conflict = !info->battery; // Is it required by any game?
242179
243180 int mirror = (head.ROM_type & 1) | ((head.ROM_type & 8) >> 2);
244181 switch (mirror)
257194 break;
258195 }
259196
260 bus_conflict = !info->battery;
261 latcheinit = 0;
262 WLSync = UNROM512LSync;
263 WHSync = UNROM512HSync;
264 info->Power = UNROM512LatchPower;
265 info->Close = UNROM512LatchClose;
266 GameStateRestore = StateRestore;
267197 if(flash_save)
268198 {
269 flashdata = (uint8*)FCEU_gmalloc(ROM_size*0x4000);
270 flash_write_count = (uint32*)FCEU_gmalloc(ROM_size*4*sizeof(uint32));
271 info->SaveGame[0] = (uint8*)flash_write_count;
272 info->SaveGame[1] = flashdata;
273 info->SaveGameLen[0] = ROM_size*4*sizeof(uint32);
274 info->SaveGameLen[1] = ROM_size*0x4000;
275 AddExState(flash_write_count,ROM_size*4*sizeof(uint32),0,"FLASH_WRITE_COUNT");
276 AddExState(flashdata,ROM_size*0x4000,0,"FLASH_DATA");
277 AddExState(&flash_state,1,0,"FLASH_STATE");
278 AddExState(&flash_mode,1,0,"FLASH_MODE");
279 AddExState(&flash_bank,1,0,"FLASH_BANK");
280 AddExState(&latcha,2,0,"LATA");
281 }
199 // Allocate memory for flash
200 flash_data = (uint8*)FCEU_gmalloc(PRGsize[ROM_CHIP]);
201 // Copy ROM to flash data
202 for (unsigned int i = 0; i < PRGsize[ROM_CHIP]; i++) {
203 flash_data[i] = PRGptr[ROM_CHIP][i % PRGsize[ROM_CHIP]];
204 }
205 SetupCartPRGMapping(FLASH_CHIP, flash_data, PRGsize[ROM_CHIP], 1);
206 info->SaveGame[0] = flash_data;
207 info->SaveGameLen[0] = PRGsize[ROM_CHIP];
208
209 flash_id[0] = 0xBF;
210 flash_id[1] = 0xB5 + (ROM_size >> 4);
211 SetupCartPRGMapping(CFI_CHIP, flash_id, sizeof(flash_id), 0);
212
213 AddExState(flash_data, PRGsize[ROM_CHIP], 0, "FLSH");
214 AddExState(&flash_state, 1, 0, "FLST");
215 AddExState(&flash_id_mode, 1, 0, "FLMD");
216 AddExState(flash_buffer_a, sizeof(flash_buffer_a), 0, "FLBA");
217 AddExState(flash_buffer_v, sizeof(flash_buffer_v), 0, "FLBV");
218 }
219 AddExState(&latcha, 2, 0, "LATA");
282220 AddExState(&latche, 1, 0, "LATC");
283221 AddExState(&bus_conflict, 1, 0, "BUSC");
284222 }
2222 static bool isPirate;
2323 static uint8 is22, reg1mask, reg2mask;
2424 static uint16 IRQCount;
25 static uint8 IRQLatch, IRQa;
25 static uint8 IRQLatch, IRQa, IRQMode;
2626 static uint8 prgreg[2], chrreg[8];
2727 static uint16 chrhi[8];
2828 static uint8 regcmd, irqcmd, mirr, big_bank;
4444 { &IRQCount, 2, "IRQC" },
4545 { &IRQLatch, 1, "IRQL" },
4646 { &IRQa, 1, "IRQA" },
47 { &IRQMode, 1, "IRQM" },
4748 { 0 }
4849 };
4950
114115 case 0x9003: regcmd = V; Sync(); break;
115116 case 0xF000: X6502_IRQEnd(FCEU_IQEXT); IRQLatch &= 0xF0; IRQLatch |= V & 0xF; break;
116117 case 0xF001: X6502_IRQEnd(FCEU_IQEXT); IRQLatch &= 0x0F; IRQLatch |= V << 4; break;
117 case 0xF002: X6502_IRQEnd(FCEU_IQEXT); acount = 0; IRQCount = IRQLatch; IRQa = V & 2; irqcmd = V & 1; break;
118 case 0xF002: X6502_IRQEnd(FCEU_IQEXT); acount = 0; IRQCount = IRQLatch; IRQMode = V & 4; IRQa = V & 2; irqcmd = V & 1; break;
118119 case 0xF003: X6502_IRQEnd(FCEU_IQEXT); IRQa = irqcmd; break;
119120 }
120121 }
135136 void VRC24IRQHook(int a) {
136137 #define LCYCS 341
137138 if (IRQa) {
138 acount += a * 3;
139 if (acount >= LCYCS) {
140 while (acount >= LCYCS) {
141 acount -= LCYCS;
139 if (IRQMode) {
140 acount += a;
141 while (acount > 0) {
142 acount--;
142143 IRQCount++;
143144 if (IRQCount & 0x100) {
144145 X6502_IRQBegin(FCEU_IQEXT);
145146 IRQCount = IRQLatch;
146147 }
147148 }
149 } else {
150 acount += a * 3;
151 if (acount >= LCYCS) {
152 while (acount >= LCYCS) {
153 acount -= LCYCS;
154 IRQCount++;
155 if (IRQCount & 0x100) {
156 X6502_IRQBegin(FCEU_IQEXT);
157 IRQCount = IRQLatch;
158 }
159 }
160 }
148161 }
149162 }
150163 }
2424
2525 static uint8 is26;
2626 static uint8 prg[2], chr[8], mirr;
27 static uint8 IRQLatch, IRQa, IRQd;
27 static uint8 IRQLatch, IRQa, IRQd, IRQMode;
2828 static int32 IRQCount, CycleCount;
2929 static uint8 *WRAM = NULL;
3030 static uint32 WRAMSIZE;
3939 { &IRQLatch, 1, "IRQL" },
4040 { &IRQCount, 4, "IRQC" },
4141 { &CycleCount, 4, "CYCC" },
42 { &IRQMode, 1, "IRQM" },
4243 { 0 }
4344 };
4445
108109 case 0xE003: chr[7] = V; Sync(); break;
109110 case 0xF000: IRQLatch = V; X6502_IRQEnd(FCEU_IQEXT); break;
110111 case 0xF001:
112 IRQMode = V & 4;
111113 IRQa = V & 2;
112114 IRQd = V & 1;
113115 if (V & 2)
131133
132134 static void VRC6IRQHook(int a) {
133135 if (IRQa) {
134 CycleCount += a * 3;
135 while(CycleCount >= 341) {
136 CycleCount -= 341;
137 IRQCount++;
138 if (IRQCount == 0x100) {
139 IRQCount = IRQLatch;
140 X6502_IRQBegin(FCEU_IQEXT);
136 if (IRQMode) {
137 CycleCount += a;
138 while (CycleCount > 0) {
139 CycleCount--;
140 IRQCount++;
141 if (IRQCount & 0x100) {
142 X6502_IRQBegin(FCEU_IQEXT);
143 IRQCount = IRQLatch;
144 }
145 }
146 } else {
147 CycleCount += a * 3;
148 while(CycleCount >= 341) {
149 CycleCount -= 341;
150 IRQCount++;
151 if (IRQCount == 0x100) {
152 IRQCount = IRQLatch;
153 X6502_IRQBegin(FCEU_IQEXT);
154 }
141155 }
142156 }
143157 }
2020 #include "mapinc.h"
2121
2222 static uint8 vrc7idx, preg[3], creg[8], mirr;
23 static uint8 IRQLatch, IRQa, IRQd;
23 static uint8 IRQLatch, IRQa, IRQd, IRQMode;
2424 static int32 IRQCount, CycleCount;
2525 static uint8 *WRAM = NULL;
2626 static uint32 WRAMSIZE;
4343 { &IRQCount, 4, "IRQC" },
4444 { &CycleCount, 4, "CYCC" },
4545 { (void**)VRC7Sound_saveptr, sizeof(*VRC7Sound) | FCEUSTATE_INDIRECT, "VRC7" },
46 { &IRQMode, 1, "IRQM" },
4647 {0}
4748 };
4849
133134 case 0xE000: mirr = V & 3; Sync(); break;
134135 case 0xE010: IRQLatch = V; X6502_IRQEnd(FCEU_IQEXT); break;
135136 case 0xF000:
137 IRQMode = V & 4;
136138 IRQa = V & 2;
137139 IRQd = V & 1;
138140 if (V & 2)
164166
165167 static void VRC7IRQHook(int a) {
166168 if (IRQa) {
167 CycleCount += a * 3;
168 while(CycleCount >= 341) {
169 CycleCount -= 341;
170 IRQCount++;
171 if (IRQCount == 0x100) {
172 IRQCount = IRQLatch;
173 X6502_IRQBegin(FCEU_IQEXT);
169 if (IRQMode) {
170 CycleCount += a;
171 while (CycleCount > 0) {
172 CycleCount--;
173 IRQCount++;
174 if (IRQCount & 0x100) {
175 X6502_IRQBegin(FCEU_IQEXT);
176 IRQCount = IRQLatch;
177 }
178 }
179 } else {
180 CycleCount += a * 3;
181 while(CycleCount >= 341) {
182 CycleCount -= 341;
183 IRQCount++;
184 if (IRQCount == 0x100) {
185 IRQCount = IRQLatch;
186 X6502_IRQBegin(FCEU_IQEXT);
187 }
174188 }
175189 }
176190 }
561561
562562 std::string soot = FCEU_MakeFName(FCEUMKF_SAV, 0, "sav");
563563 sp = FCEUD_UTF8fopen(soot, "rb");
564 if (sp != NULL) {
564 if (sp != NULL)
565 {
565566 for (int x = 0; x < 4; x++)
567 {
566568 if (LocalHWInfo->SaveGame[x])
567 fread(LocalHWInfo->SaveGame[x], 1, LocalHWInfo->SaveGameLen[x], sp);
569 {
570 if ( fread(LocalHWInfo->SaveGame[x], 1, LocalHWInfo->SaveGameLen[x], sp) != static_cast<size_t>(LocalHWInfo->SaveGameLen[x]) )
571 {
572 FCEU_printf("Warning save game data read came up short!\n");
573 }
574 }
575 }
568576 }
569577 }
570578 }
1414 // to help support games like "Karnov"
1515 // that are not really MMC3 but are
1616 // set to mapper 4.
17 int mirrorAs2Bits;
1718 int battery; // Presence of an actual battery.
1819 int ines2;
1920 int submapper; // Submappers as defined by NES 2.0
5858 }
5959
6060
61 CHEATF_SUBFAST SubCheats[256] = { 0 };
61 CHEATF_SUBFAST SubCheats[256];
6262 uint32 numsubcheats = 0;
6363 int globalCheatDisabled = 0;
6464 int disableAutoLSCheats = 0;
151151 return count;
152152 }
153153
154 static int AddCheatEntry(const char *name, uint32 addr, uint8 val, int compare, int status, int type);
154 static void AddCheatEntry(const char *name, uint32 addr, uint8 val, int compare, int status, int type);
155155 static void CheatMemErr(void)
156156 {
157157 FCEUD_PrintError("Error allocating memory for cheat data.");
158158 }
159159
160 static int AddCheatEntry(const char *name, uint32 addr, uint8 val, int compare, int status, int type)
161 {
162 struct CHEATF *temp;
163 if(!(temp = (struct CHEATF *)FCEU_dmalloc(sizeof(struct CHEATF))))
164 {
165 CheatMemErr();
166 return(0);
167 }
168
169 temp->name = strcpy((char*) FCEU_dmalloc(strlen(name) + 1), name);
160 static void AddCheatEntry(const char *name, uint32 addr, uint8 val, int compare, int status, int type)
161 {
162 CHEATF *temp = new CHEATF();
163
164 temp->name = name;
170165 temp->addr = addr;
171166 temp->val = val;
172167 temp->status = status;
173168 temp->compare = compare;
174169 temp->type = type;
175 temp->next = 0;
170 temp->next = nullptr;
176171
177172 if(cheats)
178173 {
181176 }
182177 else
183178 cheats = cheatsl = temp;
184
185 return (1);
186179 }
187180
188181 /* The "override_existing" parameter is used only in cheat dialog import.
305298 fputc(':', fp);
306299
307300 if (next->compare >= 0)
308 fprintf(fp, "%04x:%02x:%02x:%s\n", next->addr, next->val, next->compare, next->name);
301 fprintf(fp, "%04x:%02x:%02x:%s\n", next->addr, next->val, next->compare, next->name.c_str());
309302 else
310 fprintf(fp, "%04x:%02x:%s\n", next->addr, next->val, next->name);
311
312 if (release) free(next->name);
303 fprintf(fp, "%04x:%02x:%s\n", next->addr, next->val, next->name.c_str());
304
313305 struct CHEATF *t = next;
314306 next = next->next;
315 if (release) free(t);
307 if (release) delete t;
316308 }
317309 }
318310
332324 {
333325 struct CHEATF *last=next;
334326 next=next->next;
335 free(last->name);
336 free(last);
327 delete last;
337328 if(!next) break;
338329 }
339330 cheats=cheatsl=0;
378369
379370 int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type)
380371 {
381
382 if(!AddCheatEntry(name, addr, val, compare, 1, type))
383 return 0;
372 AddCheatEntry(name, addr, val, compare, 1, type);
384373 savecheats = 1;
385374 RebuildSubCheats();
386375
414403 else
415404 cheats=cheatsl=0; // No (more) cheats.
416405 }
417 free(cur->name); // Now that all references to this cheat are removed,
418 free(cur); // free the memory.
406 delete cur; // free the memory.
419407 break;
420408 } // *END REMOVE THIS CHEAT*
421409
450438 }
451439
452440
453 void FCEUI_ListCheats(int (*callb)(char *name, uint32 a, uint8 v, int compare, int s, int type, void *data), void *data)
441 void FCEUI_ListCheats(int (*callb)(const char *name, uint32 a, uint8 v, int compare, int s, int type, void *data), void *data)
454442 {
455443 struct CHEATF *next=cheats;
456444
457445 while(next)
458446 {
459 if(!callb(next->name,next->addr,next->val,next->compare,next->status,next->type,data)) break;
447 if(!callb(next->name.c_str(),next->addr,next->val,next->compare,next->status,next->type,data)) break;
460448 next=next->next;
461449 }
462450 }
463451
464 int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *compare, int *s, int *type)
452 int FCEUI_GetCheat(uint32 which, std::string *name, uint32 *a, uint8 *v, int *compare, int *s, int *type)
465453 {
466454 struct CHEATF *next=cheats;
467455 uint32 x=0;
599587 /* name can be NULL if the name isn't going to be changed. */
600588 /* same goes for a, v, and s(except the values of each one must be <0) */
601589
602 int FCEUI_SetCheat(uint32 which, const char *name, int32 a, int32 v, int c, int s, int type)
590 int FCEUI_SetCheat(uint32 which, const std::string *name, int32 a, int32 v, int c, int s, int type)
603591 {
604592 struct CHEATF *next = cheats;
605593 uint32 x = 0;
609597 if(x == which)
610598 {
611599 if(name)
612 {
613 char *t;
614 if((t = (char *)realloc(next->name, strlen(name) + 1)))
615 strcpy(next->name = t, name);
616 else
617 return 0;
618 }
600 next->name = *name;
619601 if(a >= 0)
620602 next->addr = a;
621603 if(v >= 0)
661643
662644 int FCEUI_GlobalToggleCheat(int global_enabled)
663645 {
664 int _numsubcheats = numsubcheats;
646 unsigned int _numsubcheats = numsubcheats;
665647 globalCheatDisabled = !global_enabled;
666648 RebuildSubCheats();
667649 return _numsubcheats != numsubcheats;
910892 while (cur)
911893 {
912894 next = cur->next;
913 if ( cur->name )
914 {
915 free(cur->name);
916 }
917 free(cur);
895 delete cur;
918896 cur = next;
919897 }
920898 cheats = cheatsl = 0;
3232 int FCEU_DisableAllCheats(void);
3333 int FCEU_DeleteAllCheats(void);
3434
35 typedef struct {
35 struct CHEATF_SUBFAST
36 {
3637 uint16 addr;
3738 uint8 val;
3839 int compare;
3940 readfunc PrevRead;
40 } CHEATF_SUBFAST;
41
42 CHEATF_SUBFAST(void)
43 {
44 addr = 0; val = 0; compare = 0; PrevRead = nullptr;
45 }
46 };
4147
4248 struct CHEATF {
4349 struct CHEATF *next;
44 char *name;
50 std::string name;
4551 uint16 addr;
4652 uint8 val;
4753 int compare; /* -1 for no compare. */
1010 #include <cstdio>
1111 #include <cstdlib>
1212
13 static char *aboutString = 0;
13 static std::string aboutString;
1414
1515 #ifndef FCEUX_BUILD_TIMESTAMP
1616 #define FCEUX_BUILD_TIMESTAMP __TIME__ " " __DATE__
1717 #endif
18
19 //#pragma message( "Compiling using C++ Std: " __FCEU_STRINGIZE(__cplusplus) )
1820
1921 // returns a string suitable for use in an aboutbox
2022 const char *FCEUI_GetAboutString(void)
2527 "zeromus, feos\n"
2628 "\n"
2729 "Current Contributors:\n"
28 "CaH4e3, rainwarrior, owomomo, punkrockguy318\n"
30 "CaH4e3, rainwarrior, owomomo, punkrockguy318, Cluster\n"
2931 "\n"
3032 "Past Contributors:\n"
3133 "xhainingx, gocha, AnS, mjbudd77\n"
5456 "\n"
5557 FCEUX_BUILD_TIMESTAMP "\n";
5658
57 if (aboutString) return aboutString;
59 if (aboutString.size() > 0) return aboutString.c_str();
5860
5961 const char *compilerString = FCEUD_GetCompilerString();
6062
61 //allocate the string and concatenate the template with the compiler string
62 if (!(aboutString = (char*)FCEU_dmalloc(strlen(aboutTemplate) + strlen(compilerString) + 1)))
63 return NULL;
63 char cppVersion[128];
6464
65 sprintf(aboutString,"%s%s",aboutTemplate,compilerString);
66 return aboutString;
65 snprintf( cppVersion, sizeof(cppVersion), "\nCompiled using C++ Language Standard: %li\n", __cplusplus);
66
67 aboutString.assign( aboutTemplate );
68 aboutString.append( compilerString );
69 aboutString.append( cppVersion );
70
71 return aboutString.c_str();
6772 }
55 #include "cart.h"
66 #include "ines.h"
77 #include "debug.h"
8 #include "debugsymboltable.h"
89 #include "driver.h"
910 #include "ppu.h"
1011
4041 }
4142 else // BT_C
4243 {
44 auto sym = debugSymbolTable.getSymbolAtAnyBank(offsetBuffer);
45
46 if (sym)
47 {
48 return sym->offset() & 0xFFFF;
49 }
50
4351 int type = GIT_CART;
4452
4553 if (GameInfo)
641649
642650 ///fires a breakpoint
643651 static void breakpoint(uint8 *opcode, uint16 A, int size) {
644 int i, j, romAddrPC;
652 int i, romAddrPC;
653 unsigned int j;
645654 uint8 brk_type;
646655 uint8 stackop=0;
647656 uint8 stackopstartaddr=0,stackopendaddr=0;
782791 {
783792 if (watchpoint[i].flags & BT_R)
784793 {
785 if ( (watchpoint[i].flags & WP_X) && (watchpoint[i].address == romAddrPC) )
794 if ( (watchpoint[i].flags & WP_X) && (watchpoint[i].address == static_cast<unsigned int>(romAddrPC)) )
786795 {
787796 BREAKHIT(i);
788797 }
813822 // TXS and TSX only deal with the pointer.
814823 if (watchpoint[i].flags & stackop)
815824 {
816 for (j = (stackopstartaddr|0x0100); j <= (stackopendaddr|0x0100); j++)
825 for (j = (stackopstartaddr|0x0100); j <= (static_cast<unsigned int>(stackopendaddr)|0x0100); j++)
817826 {
818827 if (watchpoint[i].endaddress)
819828 {
839848 // Pushes to stack
840849 if (watchpoint[i].flags & WP_W)
841850 {
842 for (j = (X.S|0x0100); j < (StackAddrBackup|0x0100); j++)
851 for (j = (X.S|0x0100); j < (static_cast<unsigned int>(StackAddrBackup)|0x0100); j++)
843852 {
844853 if (watchpoint[i].endaddress)
845854 {
857866 // Pulls from stack
858867 if (watchpoint[i].flags & WP_R)
859868 {
860 for (j = (StackAddrBackup|0x0100); j < (X.S|0x0100); j++)
869 for (j = (StackAddrBackup|0x0100); j < (static_cast<unsigned int>(X.S)|0x0100); j++)
861870 {
862871 if (watchpoint[i].endaddress)
863872 {
0 /// \file
1 /// \brief Implements debug symbol table (from .nl files)
2
3 #include "debugsymboltable.h"
4
5 #include "types.h"
6 #include "debug.h"
7 #include "fceu.h"
8 #include "cart.h"
9
10 #ifdef __QT_DRIVER__
11 #include "Qt/ConsoleUtilities.h"
12 #else
13 extern char LoadedRomFName[4096];
14 static inline const char* getRomFile() { return LoadedRomFName; }
15 #endif
16
17 extern FCEUGI *GameInfo;
18
19 debugSymbolTable_t debugSymbolTable;
20
21 static char dbgSymTblErrMsg[256] = {0};
22 static bool dbgSymAllowDuplicateNames = true;
23 //--------------------------------------------------------------
24 // debugSymbol_t
25 //--------------------------------------------------------------
26 int debugSymbol_t::updateName( const char *name, int arrayIndex )
27 {
28 std::string newName;
29
30 newName.assign( name );
31
32 while ( newName.size() > 0 )
33 {
34 if ( isspace( newName.back() ) )
35 {
36 newName.pop_back();
37 }
38 else
39 {
40 break;
41 }
42 }
43
44 if (arrayIndex >= 0)
45 {
46 char stmp[32];
47
48 sprintf( stmp, "[%i]", arrayIndex );
49
50 newName.append(stmp);
51 }
52
53 if (page)
54 {
55 debugSymbol_t *dupSym = debugSymbolTable.getSymbol( page->pageNum(), newName );
56
57 if (!dbgSymAllowDuplicateNames && dupSym != nullptr && dupSym != this)
58 {
59 snprintf( dbgSymTblErrMsg, sizeof(dbgSymTblErrMsg), "Error: debug symbol '%s' already exists in %s page.\n", newName.c_str(), page->pageName() );
60 return -1;
61 }
62 }
63 _name = newName;
64
65 debugSymbolTable.updateSymbol(this);
66
67 return 0;
68 }
69 //--------------------------------------------------------------
70 void debugSymbol_t::trimTrailingSpaces(void)
71 {
72 while ( _name.size() > 0 )
73 {
74 if ( isspace( _name.back() ) )
75 {
76 _name.pop_back();
77 }
78 else
79 {
80 break;
81 }
82 }
83 while ( _comment.size() > 0 )
84 {
85 if ( isspace( _comment.back() ) )
86 {
87 _comment.pop_back();
88 }
89 else
90 {
91 break;
92 }
93 }
94 }
95 //--------------------------------------------------------------
96 // debugSymbolPage_t
97 //--------------------------------------------------------------
98 debugSymbolPage_t::debugSymbolPage_t(int page)
99 {
100 _pageNum = page;
101
102 _pageName[0] = 0;
103
104 if (page == -2)
105 {
106 strcpy( _pageName, "REG");
107 }
108 else if (page == -1)
109 {
110 strcpy( _pageName, "RAM");
111 }
112 else
113 {
114 snprintf( _pageName, sizeof(_pageName), "%X", page);
115 _pageName[sizeof(_pageName)-1] = 0;
116 }
117 }
118 //--------------------------------------------------------------
119 debugSymbolPage_t::~debugSymbolPage_t(void)
120 {
121 for (auto it=symMap.begin(); it!=symMap.end(); it++)
122 {
123 delete it->second;
124 }
125 }
126 //--------------------------------------------------------------
127 int debugSymbolPage_t::addSymbol( debugSymbol_t*sym )
128 {
129 // Check if symbol already is loaded by that name or offset
130 if ( symMap.count( sym->offset() ) )
131 {
132 snprintf( dbgSymTblErrMsg, sizeof(dbgSymTblErrMsg), "Error: symbol offset 0x%04X already has an entry on %s page\n", sym->offset(), _pageName );
133 return -1;
134 }
135 if ( !dbgSymAllowDuplicateNames && (sym->name().size() > 0) && symNameMap.count( sym->name() ) )
136 {
137 snprintf( dbgSymTblErrMsg, sizeof(dbgSymTblErrMsg), "Error: symbol name '%s' already exists on %s page\n", sym->name().c_str(), _pageName );
138 return -1;
139 }
140
141 symMap[ sym->offset() ] = sym;
142
143 sym->page = this;
144
145 // Comment only lines don't need to have a name.
146 if (sym->name().size() > 0)
147 {
148 symNameMap[ sym->name() ] = sym;
149 }
150
151 return 0;
152 }
153 //--------------------------------------------------------------
154 debugSymbol_t *debugSymbolPage_t::getSymbolAtOffset( int ofs )
155 {
156 auto it = symMap.find( ofs );
157 return it != symMap.end() ? it->second : nullptr;
158 }
159 //--------------------------------------------------------------
160 debugSymbol_t *debugSymbolPage_t::getSymbol( const std::string &name )
161 {
162 auto it = symNameMap.find( name );
163 return it != symNameMap.end() ? it->second : nullptr;
164 }
165 //--------------------------------------------------------------
166 int debugSymbolPage_t::deleteSymbolAtOffset( int ofs )
167 {
168 auto it = symMap.find( ofs );
169
170 if ( it != symMap.end() )
171 {
172 auto sym = it->second;
173
174 if ( sym->name().size() > 0 )
175 {
176 auto itName = symNameMap.find( sym->name() );
177
178 if ( (itName != symNameMap.end()) && (itName->second == sym) )
179 {
180 symNameMap.erase(itName);
181 }
182 }
183 symMap.erase(it);
184 delete sym;
185
186 return 0;
187 }
188 return -1;
189 }
190 //--------------------------------------------------------------
191 int debugSymbolPage_t::updateSymbol(debugSymbol_t *sym)
192 {
193 auto itName = symNameMap.begin();
194
195 while (itName != symNameMap.end())
196 {
197 if (itName->second == sym)
198 {
199 if (sym->name().size() == 0 || sym->name().compare( itName->first ) )
200 {
201 //printf("Changing Name: %s %s\n", itName->first.c_str(), sym->name().c_str() );
202 itName = symNameMap.erase(itName);
203 }
204 break;
205 }
206 else
207 {
208 itName++;
209 }
210 }
211 if (sym->name().size() > 0)
212 {
213 symNameMap[ sym->name() ] = sym;
214 }
215
216 // Sanity Check
217 auto it = symMap.find( sym->offset() );
218
219 if ( it == symMap.end() )
220 { // This shouldn't happen
221 return -1;
222 }
223 return 0;
224 }
225 //--------------------------------------------------------------
226 int debugSymbolPage_t::save(void)
227 {
228 FILE *fp;
229 debugSymbol_t *sym;
230 std::map <int, debugSymbol_t*>::iterator it;
231 const char *romFile;
232 std::string filename;
233 char stmp[512];
234 int i,j;
235
236 if ( symMap.size() == 0 )
237 {
238 //printf("Skipping Empty Debug Page Save\n");
239 return 0;
240 }
241 if ( _pageNum == -2 )
242 {
243 //printf("Skipping Register Debug Page Save\n");
244 return 0;
245 }
246
247 romFile = getRomFile();
248
249 if ( romFile == nullptr )
250 {
251 return -1;
252 }
253 i=0;
254 while ( romFile[i] != 0 )
255 {
256
257 if ( romFile[i] == '|' )
258 {
259 filename.push_back('.');
260 }
261 else
262 {
263 filename.push_back(romFile[i]);
264 }
265 i++;
266 }
267
268 if ( _pageNum < 0 )
269 {
270 filename.append(".ram.nl" );
271 }
272 else
273 {
274 char suffix[32];
275
276 sprintf( suffix, ".%X.nl", _pageNum );
277
278 filename.append( suffix );
279 }
280
281 fp = ::fopen( filename.c_str(), "w" );
282
283 if ( fp == nullptr )
284 {
285 FCEU_printf("Error: Could not open file '%s' for writing\n", filename.c_str() );
286 return -1;
287 }
288
289 for (it=symMap.begin(); it!=symMap.end(); it++)
290 {
291 const char *c;
292
293 sym = it->second;
294
295 i=0; j=0; c = sym->_comment.c_str();
296
297 while ( c[i] != 0 )
298 {
299 if ( c[i] == '\n' )
300 {
301 i++; break;
302 }
303 else
304 {
305 stmp[j] = c[i]; j++; i++;
306 }
307 }
308 stmp[j] = 0;
309
310 fprintf( fp, "$%04X#%s#%s\n", sym->offset(), sym->name().c_str(), stmp );
311
312 j=0;
313 while ( c[i] != 0 )
314 {
315 if ( c[i] == '\n' )
316 {
317 i++; stmp[j] = 0;
318
319 if ( j > 0 )
320 {
321 fprintf( fp, "\\%s\n", stmp );
322 }
323 j=0;
324 }
325 else
326 {
327 stmp[j] = c[i]; j++; i++;
328 }
329 }
330 }
331
332 fclose(fp);
333
334 return 0;
335 }
336 //--------------------------------------------------------------
337 void debugSymbolPage_t::print(void)
338 {
339 FILE *fp;
340 debugSymbol_t *sym;
341 std::map <int, debugSymbol_t*>::iterator it;
342
343 fp = stdout;
344
345 fprintf( fp, "Page: %X \n", _pageNum );
346
347 for (it=symMap.begin(); it!=symMap.end(); it++)
348 {
349 sym = it->second;
350
351 fprintf( fp, " Sym: $%04X '%s' \n", sym->ofs, sym->name().c_str() );
352 }
353 }
354 //--------------------------------------------------------------
355 // debugSymbolTable_t
356 //--------------------------------------------------------------
357 debugSymbolTable_t::debugSymbolTable_t(void)
358 {
359 cs = new FCEU::mutex();
360
361 dbgSymTblErrMsg[0] = 0;
362 }
363 //--------------------------------------------------------------
364 debugSymbolTable_t::~debugSymbolTable_t(void)
365 {
366 this->clear();
367
368 if (cs)
369 {
370 delete cs;
371 }
372 }
373 //--------------------------------------------------------------
374 void debugSymbolTable_t::clear(void)
375 {
376 FCEU::autoScopedLock alock(cs);
377
378 std::map <int, debugSymbolPage_t*>::iterator it;
379
380 for (it=pageMap.begin(); it!=pageMap.end(); it++)
381 {
382 delete it->second;
383 }
384 pageMap.clear();
385 }
386 //--------------------------------------------------------------
387 static int generateNLFilenameForBank(int bank, std::string &NLfilename)
388 {
389 int i;
390 const char *romFile;
391
392 romFile = getRomFile();
393
394 if ( romFile == nullptr )
395 {
396 return -1;
397 }
398 i=0;
399 while ( romFile[i] != 0 )
400 {
401
402 if ( romFile[i] == '|' )
403 {
404 NLfilename.push_back('.');
405 }
406 else
407 {
408 NLfilename.push_back(romFile[i]);
409 }
410 i++;
411 }
412
413 if (bank < 0)
414 {
415 // The NL file for the RAM addresses has the name nesrom.nes.ram.nl
416 NLfilename.append(".ram.nl");
417 }
418 else
419 {
420 char stmp[64];
421 #ifdef DW3_NL_0F_1F_HACK
422 if(bank == 0x0F)
423 bank = 0x1F;
424 #endif
425 sprintf( stmp, ".%X.nl", bank);
426 NLfilename.append( stmp );
427 }
428 return 0;
429 }
430 //--------------------------------------------------------------
431 int generateNLFilenameForAddress(int address, std::string &NLfilename)
432 {
433 int bank;
434
435 if (address < 0x8000)
436 {
437 bank = -1;
438 }
439 else
440 {
441 bank = getBank(address);
442 #ifdef DW3_NL_0F_1F_HACK
443 if(bank == 0x0F)
444 bank = 0x1F;
445 #endif
446 }
447 return generateNLFilenameForBank( bank, NLfilename );
448 }
449 //--------------------------------------------------------------
450 int debugSymbolTable_t::loadFileNL( int bank )
451 {
452 FILE *fp;
453 int i, j, ofs, lineNum = 0, literal = 0, array = 0;
454 std::string fileName;
455 char stmp[512], line[512];
456 debugSymbolPage_t *page = nullptr;
457 debugSymbol_t *sym = nullptr;
458 FCEU::autoScopedLock alock(cs);
459
460 //printf("Looking to Load Debug Bank: $%X \n", bank );
461
462 if ( generateNLFilenameForBank( bank, fileName ) )
463 {
464 return -1;
465 }
466 //printf("Loading NL File: %s\n", fileName.c_str() );
467
468 fp = ::fopen( fileName.c_str(), "r" );
469
470 if ( fp == nullptr )
471 {
472 return -1;
473 }
474 page = new debugSymbolPage_t(bank);
475
476 pageMap[ page->pageNum() ] = page;
477
478 while ( fgets( line, sizeof(line), fp ) != 0 )
479 {
480 i=0; lineNum++;
481 //printf("%4i:%s", lineNum, line );
482
483 if ( line[i] == '\\' )
484 {
485 // Line is a comment continuation line.
486 i++;
487
488 j=0;
489 stmp[j] = '\n'; j++;
490
491 while ( line[i] != 0 )
492 {
493 stmp[j] = line[i]; j++; i++;
494 }
495 stmp[j] = 0;
496
497 j--;
498 while ( j >= 0 )
499 {
500 if ( isspace( stmp[j] ) )
501 {
502 stmp[j] = 0;
503 }
504 else
505 {
506 break;
507 }
508 j--;
509 }
510 if ( sym != nullptr )
511 {
512 sym->_comment.append( stmp );
513 }
514 }
515 else if ( line[i] == '$' )
516 {
517 // Line is a new debug offset
518 array = 0;
519
520 j=0; i++;
521 if ( !isxdigit( line[i] ) )
522 {
523 FCEU_printf("Error: Invalid Offset on Line %i of File %s\n", lineNum, fileName.c_str() );
524 }
525 while ( isxdigit( line[i] ) )
526 {
527 stmp[j] = line[i]; i++; j++;
528 }
529 stmp[j] = 0;
530
531 ofs = strtol( stmp, nullptr, 16 );
532
533 if ( line[i] == '/' )
534 {
535 j=0; i++;
536 while ( isxdigit( line[i] ) )
537 {
538 stmp[j] = line[i]; i++; j++;
539 }
540 stmp[j] = 0;
541
542 array = strtol( stmp, nullptr, 16 );
543 }
544
545 if ( line[i] != '#' )
546 {
547 FCEU_printf("Error: Missing field delimiter following offset $%X on Line %i of File %s\n", ofs, lineNum, fileName.c_str() );
548 continue;
549 }
550 i++;
551
552 while ( isspace(line[i]) ) i++;
553
554 j = 0;
555 while ( line[i] != 0 )
556 {
557 if ( line[i] == '\\' )
558 {
559 if ( literal )
560 {
561 switch ( line[i] )
562 {
563 case 'r':
564 stmp[j] = '\r';
565 break;
566 case 'n':
567 stmp[j] = '\n';
568 break;
569 case 't':
570 stmp[j] = '\t';
571 break;
572 default:
573 stmp[j] = line[i];
574 break;
575 }
576 j++; i++;
577 literal = 0;
578 }
579 else
580 {
581 i++;
582 literal = !literal;
583 }
584 }
585 else if ( line[i] == '#' )
586 {
587 break;
588 }
589 else
590 {
591 stmp[j] = line[i]; j++; i++;
592 }
593 }
594 stmp[j] = 0;
595
596 j--;
597 while ( j >= 0 )
598 {
599 if ( isspace( stmp[j] ) )
600 {
601 stmp[j] = 0;
602 }
603 else
604 {
605 break;
606 }
607 j--;
608 }
609
610 if ( line[i] != '#' )
611 {
612 FCEU_printf("Error: Missing field delimiter following name '%s' on Line %i of File %s\n", stmp, lineNum, fileName.c_str() );
613 continue;
614 }
615 i++;
616
617 sym = new debugSymbol_t( ofs, stmp );
618
619 if ( sym == nullptr )
620 {
621 FCEU_printf("Error: Failed to allocate memory for offset $%04X Name '%s' on Line %i of File %s\n", ofs, stmp, lineNum, fileName.c_str() );
622 continue;
623 }
624 sym->ofs = ofs;
625 sym->_name.assign( stmp );
626
627 while ( isspace( line[i] ) ) i++;
628
629 j=0;
630 while ( line[i] != 0 )
631 {
632 stmp[j] = line[i]; j++; i++;
633 }
634 stmp[j] = 0;
635
636 j--;
637 while ( j >= 0 )
638 {
639 if ( isspace( stmp[j] ) )
640 {
641 stmp[j] = 0;
642 }
643 else
644 {
645 break;
646 }
647 j--;
648 }
649
650 sym->_comment.assign( stmp );
651
652 if ( array > 0 )
653 {
654 debugSymbol_t *arraySym = nullptr;
655
656 for (j=0; j<array; j++)
657 {
658 arraySym = new debugSymbol_t();
659
660 if ( arraySym )
661 {
662 arraySym->ofs = sym->ofs + j;
663
664 sprintf( stmp, "[%i]", j );
665 arraySym->_name.assign( sym->name() );
666 arraySym->_name.append( stmp );
667 arraySym->_comment.assign( sym->comment() );
668
669 if ( page->addSymbol( arraySym ) )
670 {
671 FCEU_printf("Error: Failed to add symbol for offset $%04X Name '%s' on Line %i of File %s\n", ofs, arraySym->name().c_str(), lineNum, fileName.c_str() );
672 FCEU_printf("%s\n", errorMessage() );
673 delete arraySym; arraySym = nullptr; // Failed to add symbol
674 }
675 }
676 }
677 delete sym; sym = nullptr; // Delete temporary symbol
678 }
679 else
680 {
681 if ( page->addSymbol( sym ) )
682 {
683 FCEU_printf("Error: Failed to add symbol for offset $%04X Name '%s' on Line %i of File %s\n", ofs, sym->name().c_str(), lineNum, fileName.c_str() );
684 FCEU_printf("%s\n", errorMessage() );
685 delete sym; sym = nullptr; // Failed to add symbol
686 }
687 }
688 }
689 }
690
691 ::fclose(fp);
692
693 return 0;
694 }
695 //--------------------------------------------------------------
696 int debugSymbolTable_t::loadRegisterMap(void)
697 {
698 FCEU::autoScopedLock alock(cs);
699 debugSymbolPage_t *page;
700
701 page = new debugSymbolPage_t(-2);
702
703 page->addSymbol( new debugSymbol_t( 0x2000, "PPU_CTRL" ) );
704 page->addSymbol( new debugSymbol_t( 0x2001, "PPU_MASK" ) );
705 page->addSymbol( new debugSymbol_t( 0x2002, "PPU_STATUS" ) );
706 page->addSymbol( new debugSymbol_t( 0x2003, "PPU_OAM_ADDR" ) );
707 page->addSymbol( new debugSymbol_t( 0x2004, "PPU_OAM_DATA" ) );
708 page->addSymbol( new debugSymbol_t( 0x2005, "PPU_SCROLL" ) );
709 page->addSymbol( new debugSymbol_t( 0x2006, "PPU_ADDRESS" ) );
710 page->addSymbol( new debugSymbol_t( 0x2007, "PPU_DATA" ) );
711 page->addSymbol( new debugSymbol_t( 0x4000, "SQ1_VOL" ) );
712 page->addSymbol( new debugSymbol_t( 0x4001, "SQ1_SWEEP" ) );
713 page->addSymbol( new debugSymbol_t( 0x4002, "SQ1_LO" ) );
714 page->addSymbol( new debugSymbol_t( 0x4003, "SQ1_HI" ) );
715 page->addSymbol( new debugSymbol_t( 0x4004, "SQ2_VOL" ) );
716 page->addSymbol( new debugSymbol_t( 0x4005, "SQ2_SWEEP" ) );
717 page->addSymbol( new debugSymbol_t( 0x4006, "SQ2_LO" ) );
718 page->addSymbol( new debugSymbol_t( 0x4007, "SQ2_HI" ) );
719 page->addSymbol( new debugSymbol_t( 0x4008, "TRI_LINEAR" ) );
720 // page->addSymbol( new debugSymbol_t( 0x4009, "UNUSED" ) );
721 page->addSymbol( new debugSymbol_t( 0x400A, "TRI_LO" ) );
722 page->addSymbol( new debugSymbol_t( 0x400B, "TRI_HI" ) );
723 page->addSymbol( new debugSymbol_t( 0x400C, "NOISE_VOL" ) );
724 // page->addSymbol( new debugSymbol_t( 0x400D, "UNUSED" ) );
725 page->addSymbol( new debugSymbol_t( 0x400E, "NOISE_LO" ) );
726 page->addSymbol( new debugSymbol_t( 0x400F, "NOISE_HI" ) );
727 page->addSymbol( new debugSymbol_t( 0x4010, "DMC_FREQ" ) );
728 page->addSymbol( new debugSymbol_t( 0x4011, "DMC_RAW" ) );
729 page->addSymbol( new debugSymbol_t( 0x4012, "DMC_START" ) );
730 page->addSymbol( new debugSymbol_t( 0x4013, "DMC_LEN" ) );
731 page->addSymbol( new debugSymbol_t( 0x4014, "OAM_DMA" ) );
732 page->addSymbol( new debugSymbol_t( 0x4015, "APU_STATUS" ) );
733 page->addSymbol( new debugSymbol_t( 0x4016, "JOY1" ) );
734 page->addSymbol( new debugSymbol_t( 0x4017, "JOY2_FRAME" ) );
735
736 pageMap[ page->pageNum() ] = page;
737
738 return 0;
739 }
740 //--------------------------------------------------------------
741 int debugSymbolTable_t::loadGameSymbols(void)
742 {
743 int nPages, pageSize, romSize = 0x10000;
744
745 this->save();
746 this->clear();
747
748 if ( GameInfo != nullptr )
749 {
750 romSize = 16 + CHRsize[0] + PRGsize[0];
751 }
752
753 loadFileNL( -1 );
754
755 loadRegisterMap();
756
757 pageSize = (1<<debuggerPageSize);
758
759 //nPages = 1<<(15-debuggerPageSize);
760 nPages = romSize / pageSize;
761
762 //printf("RomSize: %i NumPages: %i \n", romSize, nPages );
763
764 for(int i=0;i<nPages;i++)
765 {
766 //printf("Loading Page Offset: $%06X\n", pageSize*i );
767
768 loadFileNL( i );
769 }
770
771 //print();
772
773 return 0;
774 }
775 int debugSymbolTable_t::addSymbolAtBankOffset(int bank, int ofs, const char *name, const char *comment)
776 {
777 int result = -1;
778 debugSymbol_t *sym = new debugSymbol_t(ofs, name, comment);
779
780 result = addSymbolAtBankOffset(bank, ofs, sym);
781
782 if (result)
783 { // Symbol add failed
784 delete sym;
785 }
786 return result;
787 }
788 //--------------------------------------------------------------
789 int debugSymbolTable_t::addSymbolAtBankOffset( int bank, int ofs, debugSymbol_t *sym )
790 {
791 int result = -1;
792 debugSymbolPage_t *page;
793 std::map <int, debugSymbolPage_t*>::iterator it;
794 FCEU::autoScopedLock alock(cs);
795
796 it = pageMap.find( bank );
797
798 if ( it == pageMap.end() )
799 {
800 page = new debugSymbolPage_t(bank);
801 pageMap[ bank ] = page;
802 }
803 else
804 {
805 page = it->second;
806 }
807 result = page->addSymbol( sym );
808
809 return result;
810 }
811 //--------------------------------------------------------------
812 int debugSymbolTable_t::deleteSymbolAtBankOffset( int bank, int ofs )
813 {
814 debugSymbolPage_t *page;
815 std::map <int, debugSymbolPage_t*>::iterator it;
816 FCEU::autoScopedLock alock(cs);
817
818 it = pageMap.find( bank );
819
820 if ( it == pageMap.end() )
821 {
822 return -1;
823 }
824 else
825 {
826 page = it->second;
827 }
828
829 return page->deleteSymbolAtOffset( ofs );
830 }
831 //--------------------------------------------------------------
832 int debugSymbolTable_t::updateSymbol(debugSymbol_t *sym)
833 {
834 FCEU::autoScopedLock alock(cs);
835
836 if (sym->page == nullptr)
837 {
838 return -1;
839 }
840 return sym->page->updateSymbol(sym);
841 }
842 //--------------------------------------------------------------
843 debugSymbol_t *debugSymbolTable_t::getSymbolAtBankOffset( int bank, int ofs )
844 {
845 FCEU::autoScopedLock alock(cs);
846
847 auto it = pageMap.find( bank );
848
849 return it != pageMap.end() ? it->second->getSymbolAtOffset( ofs ) : nullptr;
850 }
851 //--------------------------------------------------------------
852 debugSymbol_t *debugSymbolTable_t::getSymbol( int bank, const std::string &name )
853 {
854 FCEU::autoScopedLock alock(cs);
855
856 auto it = pageMap.find( bank );
857
858 return it != pageMap.end() ? it->second->getSymbol( name ) : nullptr;
859 }
860 //--------------------------------------------------------------
861 debugSymbol_t *debugSymbolTable_t::getSymbolAtAnyBank( const std::string &name )
862 {
863 FCEU::autoScopedLock alock(cs);
864
865 for (auto &page : pageMap)
866 {
867 auto sym = getSymbol( page.first, name );
868
869 if ( sym )
870 {
871 return sym;
872 }
873 }
874
875 return nullptr;
876 }
877 //--------------------------------------------------------------
878 void debugSymbolTable_t::save(void)
879 {
880 debugSymbolPage_t *page;
881 std::map <int, debugSymbolPage_t*>::iterator it;
882 FCEU::autoScopedLock alock(cs);
883
884 for (it=pageMap.begin(); it!=pageMap.end(); it++)
885 {
886 page = it->second;
887
888 page->save();
889 }
890 }
891 //--------------------------------------------------------------
892 void debugSymbolTable_t::print(void)
893 {
894 debugSymbolPage_t *page;
895 std::map <int, debugSymbolPage_t*>::iterator it;
896 FCEU::autoScopedLock alock(cs);
897
898 for (it=pageMap.begin(); it!=pageMap.end(); it++)
899 {
900 page = it->second;
901
902 page->print();
903 }
904 }
905 //--------------------------------------------------------------
906 const char *debugSymbolTable_t::errorMessage(void)
907 {
908 return dbgSymTblErrMsg;
909 }
910 //--------------------------------------------------------------
0 #ifndef _DEBUGSYMBOLTABLE_H_
1 #define _DEBUGSYMBOLTABLE_H_
2
3 #include <string>
4 #include <map>
5
6 #include "utils/mutex.h"
7
8 class debugSymbolPage_t;
9 class debugSymbolTable_t;
10
11 class debugSymbol_t
12 {
13 public:
14 debugSymbol_t(void)
15 {
16 ofs = 0;
17 page = nullptr;
18 };
19
20 debugSymbol_t( int ofs, const char *name = nullptr, const char *comment = nullptr )
21 {
22 this->ofs = ofs;
23
24 if (name)
25 {
26 this->_name.assign(name);
27 }
28 if ( comment )
29 {
30 this->_comment.assign( comment );
31 }
32 page = nullptr;
33 }
34
35 const std::string &name(void)
36 {
37 return _name;
38 }
39
40 const std::string &comment(void)
41 {
42 return _comment;
43 }
44
45 void commentAssign( std::string str )
46 {
47 _comment.assign(str);
48 return;
49 }
50
51 void commentAssign( const char *str )
52 {
53 _comment.assign(str);
54 return;
55 }
56
57 int offset(void)
58 {
59 return ofs;
60 }
61
62 void setOffset( int o )
63 {
64 if (o != ofs)
65 {
66 ofs = o;
67 }
68 }
69
70 int updateName( const char *name, int arrayIndex = -1 );
71
72 void trimTrailingSpaces(void);
73
74 private:
75
76 int ofs;
77 std::string _name;
78 std::string _comment;
79 debugSymbolPage_t *page;
80
81 friend class debugSymbolPage_t;
82 friend class debugSymbolTable_t;
83 };
84
85 class debugSymbolPage_t
86 {
87 public:
88 debugSymbolPage_t(int page);
89 ~debugSymbolPage_t(void);
90
91 int save(void);
92 void print(void);
93 int size(void){ return symMap.size(); }
94
95 int addSymbol( debugSymbol_t *sym );
96
97 int deleteSymbolAtOffset( int ofs );
98
99 int updateSymbol( debugSymbol_t *sym );
100
101 debugSymbol_t *getSymbolAtOffset( int ofs );
102
103 debugSymbol_t *getSymbol( const std::string &name );
104
105 int pageNum(void)
106 {
107 return _pageNum;
108 }
109
110 const char *pageName(void)
111 {
112 return _pageName;
113 }
114
115 private:
116 int _pageNum;
117 char _pageName[8];
118 std::map <int, debugSymbol_t*> symMap;
119 std::map <std::string, debugSymbol_t*> symNameMap;
120
121 friend class debugSymbolTable_t;
122 };
123
124 class debugSymbolTable_t
125 {
126
127 public:
128 debugSymbolTable_t(void);
129 ~debugSymbolTable_t(void);
130
131 int loadFileNL( int addr );
132 int loadGameSymbols(void);
133 int numPages(void){ return pageMap.size(); }
134
135 void save(void);
136 void clear(void);
137 void print(void);
138
139 debugSymbol_t *getSymbolAtBankOffset( int bank, int ofs );
140
141 debugSymbol_t *getSymbol( int bank, const std::string& name);
142
143 debugSymbol_t *getSymbolAtAnyBank( const std::string& name);
144
145 int addSymbolAtBankOffset( int bank, int ofs, debugSymbol_t *sym );
146
147 int addSymbolAtBankOffset(int bank, int ofs, const char* name, const char* comment = nullptr);
148
149 int deleteSymbolAtBankOffset( int bank, int ofs );
150
151 int updateSymbol( debugSymbol_t *sym );
152
153 const char *errorMessage(void);
154
155 private:
156 std::map <int, debugSymbolPage_t*> pageMap;
157 FCEU::mutex *cs;
158
159 int loadRegisterMap(void);
160
161 };
162
163 extern debugSymbolTable_t debugSymbolTable;
164
165 #endif
2222 const char *FCEUD_GetCompilerString();
2323
2424 //This makes me feel dirty for some reason.
25 void FCEU_printf(const char *format, ...);
25 void FCEU_printf( __FCEU_PRINTF_FORMAT const char *format, ...) __FCEU_PRINTF_ATTRIBUTE( 1, 2 );
2626 #define FCEUI_printf FCEU_printf
2727
2828 //Video interface
191191 int32 FCEUI_GetDesiredFPS(void);
192192 void FCEUI_SaveSnapshot(void);
193193 void FCEUI_SaveSnapshotAs(void);
194 void FCEU_DispMessage(const char *format, int disppos, ...);
194 void FCEU_DispMessage( __FCEU_PRINTF_FORMAT const char *format, int disppos, ...) __FCEU_PRINTF_ATTRIBUTE( 1, 3 );
195195 #define FCEUI_DispMessage FCEU_DispMessage
196196
197197 int FCEUI_DecodePAR(const char *code, int *a, int *v, int *c, int *type);
206206 void FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current, void *data), void *data);
207207 void FCEUI_CheatSearchBegin(void);
208208 void FCEUI_CheatSearchEnd(int type, uint8 v1, uint8 v2);
209 void FCEUI_ListCheats(int (*callb)(char *name, uint32 a, uint8 v, int compare, int s, int type, void *data), void *data);
210
211 int FCEUI_GetCheat(uint32 which, char **name, uint32 *a, uint8 *v, int *compare, int *s, int *type);
212 int FCEUI_SetCheat(uint32 which, const char *name, int32 a, int32 v, int compare,int s, int type);
209 void FCEUI_ListCheats(int (*callb)(const char *name, uint32 a, uint8 v, int compare, int s, int type, void *data), void *data);
210
211 int FCEUI_GetCheat(uint32 which, std::string *name, uint32 *a, uint8 *v, int *compare, int *s, int *type);
212 int FCEUI_SetCheat(uint32 which, const std::string *name, int32 a, int32 v, int compare,int s, int type);
213213
214214 void FCEUI_CheatSearchShowExcluded(void);
215215 void FCEUI_CheatSearchSetCurrentAsOriginal(void);
253253 uint8 FCEUI_VSUniGetDIPs(void);
254254 void FCEUI_VSUniSetDIP(int w, int state);
255255 void FCEUI_VSUniCoin(void);
256 void FCEUI_VSUniCoin2(void);
257 void FCEUI_VSUniService(void);
256258
257259 void FCEUI_FDSInsert(void); //mbg merge 7/17/06 changed to void fn(void) to make it an EMUCMDFN
258260 //int FCEUI_FDSEject(void);
329331 ///the driver should log the current instruction, if it wants (we should move the code in the win driver that does this to the shared area)
330332 void FCEUD_TraceInstruction(uint8 *opcode, int size);
331333
334 ///the driver should flush its trace log
335 void FCEUD_FlushTrace();
336
332337 ///the driver might should update its NTView (only used if debugging support is compiled in)
333338 void FCEUD_UpdateNTView(int scanline, bool drawall);
334339
146146
147147 hbox1 = new QHBoxLayout();
148148 lbl = new QLabel();
149 lbl->setText("<a href=\"http://fceux.com\">Website</a>");
149 lbl->setText("<a href=\"https://fceux.com\">Website</a>");
150150 lbl->setTextInteractionFlags(Qt::TextBrowserInteraction);
151151 lbl->setOpenExternalLinks(true);
152152
840840 va_copy( vl2, vl );
841841
842842 vfprintf( avLogFp, fmt, vl2 );
843
844 va_end(vl2);
843845 }
844846
845847 av_log_default_callback( avcl, level, fmt, vl );
850852 int loadCodecConfig( int type, const char *codec_name, AVCodecContext *ctx)
851853 {
852854 int i,j;
853 char filename[512];
855 char filename[4096];
854856 char line[512];
855857 char section[256], id[256], val[256];
856858 void *obj, *child;
857859 FILE *fp;
858860 const char *baseDir = FCEUI_GetBaseDirectory();
859861
860 sprintf( filename, "%s/avi/%s.conf", baseDir, codec_name );
862 snprintf( filename, sizeof(filename), "%s/avi/%s.conf", baseDir, codec_name );
863
864 filename[sizeof(filename)-1] = 0;
861865
862866 fp = fopen( filename, "r");
863867
988992 void *obj, *child = NULL;
989993 FILE *fp;
990994 uint8_t *str;
991 char filename[512];
995 char filename[4096];
992996 const AVOption *opt;
993997 bool useOpt;
994998 const char *baseDir = FCEUI_GetBaseDirectory();
995999
996 sprintf( filename, "%s/avi/%s.conf", baseDir, codec_name );
1000 snprintf( filename, sizeof(filename), "%s/avi/%s.conf", baseDir, codec_name );
1001
1002 filename[sizeof(filename)-1] = 0;
9971003
9981004 fp = fopen( filename, "w");
9991005
12821288 return 0;
12831289 }
12841290
1285 static AVFrame *alloc_audio_frame(enum AVSampleFormat sample_fmt,
1286 uint64_t channel_layout,
1287 int sample_rate, int nb_samples)
1291 static AVFrame *alloc_audio_frame(const AVCodecContext *c,
1292 int nb_samples)
12881293 {
12891294 AVFrame *frame = av_frame_alloc();
12901295 int ret;
12931298 fprintf(stderr, "Error allocating an audio frame\n");
12941299 return NULL;
12951300 }
1296 frame->format = sample_fmt;
1297 frame->channel_layout = channel_layout;
1298 frame->sample_rate = sample_rate;
1301 frame->format = c->sample_fmt;
1302 #if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 28, 100)
1303 frame->channel_layout = c->channel_layout;
1304 #else
1305 av_channel_layout_copy(&frame->ch_layout, &c->ch_layout);
1306 #endif
1307 frame->sample_rate = c->sample_rate;
12991308 frame->nb_samples = nb_samples;
13001309
13011310 if (nb_samples)
13091318 }
13101319 return frame;
13111320 }
1321
1322 #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
1323 static int select_audio_channel_layout(const OutputStream *ost, const AVCodec *codec, AVChannelLayout *dst)
1324 {
1325 int best_nb_channels = 0;
1326 const AVChannelLayout *p, *best_ch_layout;
1327 #if __cplusplus >= 202002L
1328 const AVChannelLayout defaultLayout = AV_CHANNEL_LAYOUT_MONO;
1329 #else
1330 AVChannelLayout defaultLayout;
1331 av_channel_layout_from_mask( &defaultLayout, AV_CH_LAYOUT_MONO );
1332 #endif
1333
1334 if (!codec->ch_layouts)
1335 {
1336 return av_channel_layout_copy(dst, &defaultLayout);
1337 }
1338
1339 best_ch_layout = p = codec->ch_layouts;
1340 while (p && p->nb_channels)
1341 {
1342 int nb_channels = p->nb_channels;
1343
1344 if ( ost->chanLayout > 0 )
1345 {
1346 if (ost->chanLayout == p->u.mask)
1347 {
1348 best_ch_layout = p;
1349 best_nb_channels = nb_channels;
1350 break;
1351 }
1352 }
1353 if (nb_channels > best_nb_channels)
1354 {
1355 best_ch_layout = p;
1356 best_nb_channels = nb_channels;
1357 }
1358 p++;
1359 }
1360 return av_channel_layout_copy(dst, best_ch_layout);
1361 }
1362 #endif
13121363
13131364 static int initAudioStream( const char *codec_name, OutputStream *ost )
13141365 {
14031454 }
14041455
14051456 // Channel Layout Selection
1457 #if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 28, 100)
14061458 if ( ost->chanLayout > 0 )
14071459 {
14081460 c->channel_layout = ost->chanLayout;
14291481 c->channel_layout = codec->channel_layouts ? codec->channel_layouts[0] : AV_CH_LAYOUT_STEREO;
14301482 }
14311483 c->channels = av_get_channel_layout_nb_channels(c->channel_layout);
1484 #else
1485 if (select_audio_channel_layout( ost, codec, &c->ch_layout) )
1486 {
1487 fprintf( avLogFp, "Error selecting the audio channel layout\n");
1488 return -1;
1489 }
1490 #endif
14321491 c->bit_rate = 64000;
14331492 //ost->st->time_base = (AVRational){ 1, c->sample_rate };
14341493 ost->st->time_base.num = 1;
14511510 }
14521511 av_opt_set_sample_fmt(ost->swr_ctx, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
14531512 av_opt_set_int(ost->swr_ctx, "in_sample_rate", audioSampleRate, 0);
1513 #if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 28, 100)
14541514 av_opt_set_int(ost->swr_ctx, "in_channel_layout", AV_CH_LAYOUT_MONO, 0);
1515 #else
1516 #if __cplusplus >= 202002L
1517 AVChannelLayout src_ch_layout = AV_CHANNEL_LAYOUT_MONO;
1518 #else
1519 AVChannelLayout src_ch_layout;
1520 av_channel_layout_from_mask( &src_ch_layout, AV_CH_LAYOUT_MONO );
1521 #endif
1522 av_opt_set_chlayout(ost->swr_ctx, "in_chlayout", &src_ch_layout, 0);
1523 #endif
14551524 av_opt_set_sample_fmt(ost->swr_ctx, "out_sample_fmt", c->sample_fmt, 0);
14561525 av_opt_set_int(ost->swr_ctx, "out_sample_rate", c->sample_rate, 0);
1526 #if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 28, 100)
14571527 av_opt_set_int(ost->swr_ctx, "out_channel_layout", c->channel_layout, 0);
1528 #else
1529 av_opt_set_chlayout(ost->swr_ctx, "out_chlayout", &c->ch_layout, 0);
1530 #endif
14581531
14591532 ret = swr_init(ost->swr_ctx);
14601533 if (ret < 0)
14951568 ost->frameSize = nb_samples;
14961569 ost->bytesPerSample = av_get_bytes_per_sample( c->sample_fmt );
14971570
1498 ost->frame = alloc_audio_frame(c->sample_fmt, c->channel_layout, c->sample_rate, nb_samples);
1499 ost->tmp_frame = alloc_audio_frame(c->sample_fmt, c->channel_layout, c->sample_rate, nb_samples);
1500 //ost->tmp_frame = alloc_audio_frame(AV_SAMPLE_FMT_S16, AV_CH_LAYOUT_MONO, audioSampleRate, nb_samples);
1571 ost->frame = alloc_audio_frame(c, nb_samples);
1572 ost->tmp_frame = alloc_audio_frame(c, nb_samples);
15011573
15021574 //printf("Audio: FMT:%i ChanLayout:%li Rate:%i FrameSize:%i bytesPerSample:%i \n",
15031575 // c->sample_fmt, c->channel_layout, c->sample_rate, nb_samples, ost->bytesPerSample );
18531925
18541926 ret = av_samples_copy( ost->frame->data, ost->tmp_frame->data,
18551927 ost->frame->nb_samples, srcOffset, copySize,
1856 ost->frame->channels, ost->enc->sample_fmt );
1928 #if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 28, 100)
1929 ost->frame->channels,
1930 #else
1931 ost->frame->ch_layout.nb_channels,
1932 #endif
1933 ost->enc->sample_fmt );
18571934
18581935 if ( ret < 0 )
18591936 {
20602137 char fourcc[8];
20612138 gwavi_audio_t audioConfig;
20622139 double fps;
2063 char fileName[1024];
2140 std::string fileName;
20642141 char txt[512];
20652142 const char *romFile;
20662143
20732150
20742151 if ( filepath != NULL )
20752152 {
2076 strcpy( fileName, filepath );
2153 fileName.assign( filepath );
20772154 }
20782155 else
20792156 {
20922169
20932170 if ( lastPath.size() > 0 )
20942171 {
2095 strcpy( fileName, lastPath.c_str() );
2096 strcat( fileName, "/" );
2172 fileName.assign( lastPath.c_str() );
2173 fileName.append( "/" );
20972174 }
20982175 else if ( baseDir )
20992176 {
2100 strcpy( fileName, baseDir );
2101 strcat( fileName, "/avi/" );
2177 fileName.assign( baseDir );
2178 fileName.append( "/avi/" );
21022179 }
21032180 else
21042181 {
2105 fileName[0] = 0;
2106 }
2107 strcat( fileName, base );
2108 strcat( fileName, ".avi");
2109 //printf("AVI Filepath:'%s'\n", fileName );
2182 fileName.clear();
2183 }
2184 fileName.append( base );
2185 fileName.append(".avi");
2186 //printf("AVI Filepath:'%s'\n", fileName.c_str() );
21102187 }
21112188 else
21122189 {
21142191 }
21152192 }
21162193
2117 if ( fileName[0] != 0 )
2118 {
2119 QFile file(fileName);
2194 if ( fileName.size() > 0 )
2195 {
2196 QFile file(fileName.c_str());
21202197
21212198 if ( file.exists() )
21222199 {
21242201 std::string msg;
21252202
21262203 msg = "Pre-existing AVI file will be overwritten:\n\n" +
2127 std::string(fileName) + "\n\nReplace file?";
2204 fileName + "\n\nReplace file?";
21282205
21292206 ret = QMessageBox::warning( consoleWindow, QObject::tr("Overwrite Warning"),
21302207 QString::fromStdString(msg), QMessageBox::Yes | QMessageBox::No );
22222299 #ifdef _USE_LIBAV
22232300 if ( aviDriver == AVI_DRIVER_LIBAV )
22242301 {
2225 if ( LIBAV::initMedia( fileName ) )
2302 if ( LIBAV::initMedia( fileName.c_str() ) )
22262303 {
22272304 char msg[512];
22282305 fprintf( avLogFp, "Error: Failed to open AVI file.\n");
22372314 {
22382315 gwavi = new gwavi_t();
22392316
2240 if ( gwavi->open( fileName, nes_shm->video.ncol, nes_shm->video.nrow, fourcc, fps, recordAudio ? &audioConfig : NULL ) )
2317 if ( gwavi->open( fileName.c_str(), nes_shm->video.ncol, nes_shm->video.nrow, fourcc, fps, recordAudio ? &audioConfig : NULL ) )
22412318 {
22422319 char msg[512];
22432320 fprintf( avLogFp, "Error: Failed to open AVI file.\n");
30903167 {
30913168 return;
30923169 }
3170 #if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 28, 100)
30933171 if ( c->channel_layouts )
30943172 {
30953173 int i=0;
31013179
31023180 audioChanLayout->addItem( tr(layoutDesc), (unsigned long long)c->channel_layouts[i] );
31033181
3104 if ( LIBAV::audio_st.chanLayout == c->channel_layouts[i] )
3182 if ( static_cast<uint64_t>(LIBAV::audio_st.chanLayout) == c->channel_layouts[i] )
31053183 {
31063184 audioChanLayout->setCurrentIndex( audioChanLayout->count() - 1 );
31073185 formatOk = true;
31083186 }
31093187 i++;
31103188 }
3111 }
3189
3190 }
3191 #else
3192 const AVChannelLayout *p = c->ch_layouts;
3193
3194 while (p && p->nb_channels)
3195 {
3196 char layoutDesc[256];
3197
3198 av_channel_layout_describe(p, layoutDesc, sizeof(layoutDesc));
3199
3200 audioChanLayout->addItem( tr(layoutDesc), (unsigned long long)p->u.mask );
3201
3202 if ( LIBAV::audio_st.chanLayout == p->u.mask )
3203 {
3204 audioChanLayout->setCurrentIndex( audioChanLayout->count() - 1 );
3205 formatOk = true;
3206 }
3207 p++;
3208 }
3209 #endif
31123210 if ( !formatOk )
31133211 {
31143212 LIBAV::audio_st.chanLayout = -1;
33323430 break;
33333431 case AV_OPT_TYPE_INT:
33343432 case AV_OPT_TYPE_INT64:
3433 #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 58, 100)
33353434 case AV_OPT_TYPE_UINT64:
3435 #endif
33363436 {
33373437 int64_t i;
33383438
37043804 {
37053805 case AV_OPT_TYPE_INT:
37063806 case AV_OPT_TYPE_INT64:
3807 #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 58, 100)
37073808 case AV_OPT_TYPE_UINT64:
3809 #endif
37083810 {
37093811 int64_t val;
37103812
39694071 {
39704072 case AV_OPT_TYPE_INT:
39714073 case AV_OPT_TYPE_INT64:
4074 #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 58, 100)
39724075 case AV_OPT_TYPE_UINT64:
4076 #endif
39734077 {
39744078 if ( intEntry )
39754079 {
40594163 {
40604164 case AV_OPT_TYPE_INT:
40614165 case AV_OPT_TYPE_INT64:
4166 #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 58, 100)
40624167 case AV_OPT_TYPE_UINT64:
4168 #endif
40634169 {
40644170 if ( intEntry )
40654171 {
847847 }
848848 else if ( strcmp( strhType, "auds" ) == 0 )
849849 {
850 data.malloc( item->getSize()+8 );
851
852 avi->getChunkData( item->filePos(), data.buf, item->getSize()+8 );
850 size_t dataSize = item->getSize()+8;
851
852 data.malloc( dataSize );
853
854 avi->getChunkData( item->filePos(), data.buf, dataSize );
853855
854856 sprintf( stmp, "%c%c%c%c", data.buf[0], data.buf[1], data.buf[2], data.buf[3] );
855857
904906
905907 twi = new QTreeWidgetItem();
906908 twi->setText( 0, tr("nBitsPerSample") );
907 twi->setText( 2, tr(stmp) );
908 item->addChild(twi);
909
910 sprintf( stmp, "%u", data.readU16(24) );
911
912 twi = new QTreeWidgetItem();
913 twi->setText( 0, tr("cbSize") );
914909 twi->setText( 2, tr(stmp) );
915910 item->addChild(twi);
916911 }
949944
950945 sprintf( stmp, "%u", data.readU32(8) );
951946
952 for (i=0; i<item->getSize(); i++)
953 {
954 if ( i >= ( sizeof(stmp)-1 ) )
947 for (i=0; i < static_cast<int>(item->getSize()); i++)
948 {
949 if ( i >= (static_cast<int>(sizeof(stmp))-1 ) )
955950 {
956951 i = sizeof(stmp)-1; break;
957952 }
5151 {
5252 if (win != NULL)
5353 {
54 win->activateWindow();
55 win->raise();
56 win->setFocus();
5457 return;
5558 }
5659 win = new GuiCheatsDialog_t(parent);
194197
195198 hbox->addWidget(lbl);
196199 hbox->addWidget(cheatCmpEntry);
200
201 vbox1->addLayout(hbox);
202
203 hbox = new QHBoxLayout();
204 lbl = new QLabel(tr("Type:"));
205 typeEntry = new QComboBox();
206 typeEntry->addItem(tr("0: Periodic Set (Every Frame)"), 0 );
207 typeEntry->addItem(tr("1: Substitute/Freeze"), 1 );
208 typeEntry->setCurrentIndex(1);
209
210 hbox->addWidget(lbl,1);
211 hbox->addWidget(typeEntry,10);
197212
198213 vbox1->addLayout(hbox);
199214
434449
435450 setLayout(mainLayout);
436451
452 modCheatBtn->setDefault(true);
453
437454 connect(srchResetBtn, SIGNAL(clicked(void)), this, SLOT(resetSearchCallback(void)));
438455 connect(knownValBtn, SIGNAL(clicked(void)), this, SLOT(knownValueCallback(void)));
439456 connect(eqValBtn, SIGNAL(clicked(void)), this, SLOT(equalValueCallback(void)));
669686 FCEU_WRAPPER_UNLOCK();
670687 }
671688 //----------------------------------------------------------------------------
672 int GuiCheatsDialog_t::activeCheatListCB(char *name, uint32 a, uint8 v, int c, int s, int type, void *data)
689 int GuiCheatsDialog_t::activeCheatListCB(const char *name, uint32 a, uint8 v, int c, int s, int type, void *data)
673690 {
674691 QTreeWidgetItem *item;
675692 char codeStr[32];
709726 return 1;
710727 }
711728 //----------------------------------------------------------------------------
712 static int activeCheatListCB(char *name, uint32 a, uint8 v, int c, int s, int type, void *data)
729 static int activeCheatListCB(const char *name, uint32 a, uint8 v, int c, int s, int type, void *data)
713730 {
714731 return win->activeCheatListCB(name, a, v, c, s, type, data);
715732 }
717734 void GuiCheatsDialog_t::showActiveCheatList(bool redraw)
718735 {
719736 win = this;
737
738 enaCheats->setChecked(!globalCheatDisabled);
720739
721740 actvCheatRedraw = redraw;
722741
735754 int ret, useNativeFileDialogVal;
736755 QString filename;
737756 std::string last;
738 char dir[512];
757 std::string dir;
739758 QFileDialog dialog(this, tr("Open Cheat File"));
740759
741760 dialog.setFileMode(QFileDialog::ExistingFile);
750769
751770 getDirFromFile(last.c_str(), dir);
752771
753 dialog.setDirectory(tr(dir));
772 dialog.setDirectory(tr(dir.c_str()));
754773
755774 // Check config option to use native file dialog or not
756775 g_config->getOption("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
799818 FILE *fp;
800819 int ret, useNativeFileDialogVal;
801820 QString filename;
802 char dir[512];
821 char dir[4096];
803822 QFileDialog dialog(this, tr("Save Cheat File"));
804823
805824 dialog.setFileMode(QFileDialog::AnyFile);
870889 uint32 a = 0;
871890 uint8 v = 0;
872891 int c = -1;
892 int t = 1;
873893 std::string name, cmpStr;
874894
875895 a = strtoul(cheatAddrEntry->displayText().toStdString().c_str(), NULL, 16);
889909
890910 name = cheatNameEntry->text().toStdString();
891911
912 t = typeEntry->currentData().toInt();
913
892914 FCEU_WRAPPER_LOCK();
893 FCEUI_AddCheat(name.c_str(), a, v, c, 1);
915 FCEUI_AddCheat(name.c_str(), a, v, c, t);
894916 FCEU_WRAPPER_UNLOCK();
895917
896918 showActiveCheatList(true);
920942 cheatAddrEntry->setText(tr(""));
921943 cheatValEntry->setText(tr(""));
922944 cheatCmpEntry->setText(tr(""));
945 typeEntry->setCurrentIndex(0);
923946 }
924947 //----------------------------------------------------------------------------
925948 void GuiCheatsDialog_t::updateCheatParameters(void)
968991
969992 //printf("Name: %s \n", name.c_str() );
970993
994 type = typeEntry->currentData().toInt();
995
971996 FCEU_WRAPPER_LOCK();
972997
973 FCEUI_SetCheat(row, name.c_str(), a, v, c, s, type);
998 FCEUI_SetCheat(row, &name, a, v, c, s, type);
974999
9751000 FCEU_WRAPPER_UNLOCK();
9761001
9821007 uint32 a = 0;
9831008 uint8 v = 0;
9841009 int c = -1, s = 0, type = 0;
985 char *name = NULL;
1010 std::string name;
9861011 char stmp[64];
9871012
9881013 int row = actvCheatList->indexOfTopLevelItem(item);
10201045 cheatCmpEntry->setText(tr(""));
10211046 }
10221047
1023 if (name != NULL)
1024 {
1025 cheatNameEntry->setText(tr(name));
1026 }
1027 else
1028 {
1029 cheatNameEntry->setText(tr(""));
1030 }
1048 cheatNameEntry->setText(tr(name.c_str()));
1049
1050 typeEntry->setCurrentIndex(type);
10311051 }
10321052 //----------------------------------------------------------------------------
10331053 void GuiCheatsDialog_t::globalEnableCheats(int state)
2929
3030 int addSearchResult(uint32_t a, uint8_t last, uint8_t current);
3131
32 int activeCheatListCB(char *name, uint32 a, uint8 v, int c, int s, int type, void *data);
32 int activeCheatListCB(const char *name, uint32 a, uint8 v, int c, int s, int type, void *data);
3333
3434 void showActiveCheatList(bool redraw);
3535
6666 QLineEdit *neValEntry;
6767 QLineEdit *grValEntry;
6868 QLineEdit *ltValEntry;
69 QComboBox *typeEntry;
6970 QFont font;
7071
7172 int fontCharWidth;
5050 static bool autoSaveArmedCDL = false;
5151 static char loadedcdfile[512] = {0};
5252
53 static int getDefaultCDLFile(char *filepath);
53 static int getDefaultCDLFile(std::string &filepath);
5454
5555 static CodeDataLoggerDialog_t *cdlWin = NULL;
5656 //----------------------------------------------------
279279
280280 if (autoLoadCDL)
281281 {
282 char nameo[2048];
282 std::string nameo;
283283 getDefaultCDLFile(nameo);
284 LoadCDLog(nameo);
284 LoadCDLog(nameo.c_str());
285285 }
286286
287287 restoreGeometry(settings.value("cdLogger/geometry").toByteArray());
443443
444444 if (romFile != NULL)
445445 {
446 char dir[512], base[256];
447
448 parseFilepath(romFile, dir, base);
449
450 strcat(base, ".cdl");
451
452 dialog.setDirectory(tr(dir));
453
454 dialog.selectFile(tr(base));
446 std::string dir, base;
447
448 parseFilepath(romFile, &dir, &base);
449
450 base.append(".cdl");
451
452 dialog.setDirectory(tr(dir.c_str()));
453
454 dialog.selectFile(tr(base.c_str()));
455455 }
456456
457457 // Check config option to use native file dialog or not
488488 {
489489 int ret, useNativeFileDialogVal;
490490 QString filename;
491 char dir[512];
491 std::string dir;
492492 const char *romFile;
493493 QFileDialog dialog(this, tr("Load CDL File"));
494494
506506 {
507507 getDirFromFile(romFile, dir);
508508
509 dialog.setDirectory(tr(dir));
509 dialog.setDirectory(tr(dir.c_str()));
510510 }
511511
512512 // Check config option to use native file dialog or not
586586
587587 if (romFile != NULL)
588588 {
589 char dir[512], base[256];
590
591 parseFilepath(romFile, dir, base);
592
593 dialog.setDirectory(tr(dir));
589 std::string dir;
590
591 parseFilepath(romFile, &dir);
592
593 dialog.setDirectory(tr(dir.c_str()));
594594 }
595595
596596 // Check config option to use native file dialog or not
724724 SaveStrippedROM(1);
725725 }
726726 //----------------------------------------------------
727 static int getDefaultCDLFile(char *filepath)
727 static int getDefaultCDLFile(std::string &filepath)
728728 {
729729 const char *romFile;
730 char dir[512], baseFile[256];
731
732 filepath[0] = 0;
730 std::string dir, baseFile;
731
732 filepath.clear();
733733
734734 romFile = getRomFile();
735735
738738 return -1;
739739 }
740740
741 parseFilepath(romFile, dir, baseFile);
742
743 if (dir[0] == 0)
744 {
745 sprintf(filepath, "%s.cdl", baseFile);
741 parseFilepath(romFile, &dir, &baseFile);
742
743 if (dir.size() == 0)
744 {
745 filepath.assign(baseFile);
746 filepath.append(".cdl");
746747 }
747748 else
748749 {
749 sprintf(filepath, "%s/%s.cdl", dir, baseFile);
750 filepath.assign(dir);
751 filepath.append(baseFile);
752 filepath.append(".cdl");
750753 }
751754
752755 //printf("%s\n", filepath );
937940 return;
938941
939942 // try to load respective CDL file
940 char nameo[1024];
943 std::string nameo;
941944 getDefaultCDLFile(nameo);
942945
943946 FILE *FP;
944 FP = fopen(nameo, "rb");
947 FP = fopen(nameo.c_str(), "rb");
945948 if (FP != NULL)
946949 {
947950 // .cdl file with this ROM name exists
950953 //{
951954 // DoCDLogger();
952955 //}
953 if (LoadCDLog(nameo))
956 if (LoadCDLog(nameo.c_str()))
954957 {
955958 StartCDLogging();
956959 }
966969 {
967970 if (loadedcdfile[0] == 0)
968971 {
969 char nameo[1024];
972 std::string nameo;
970973 getDefaultCDLFile(nameo);
971 RenameCDLog(nameo);
974 RenameCDLog(nameo.c_str());
972975 }
973976
974977 FILE *FP;
31893189 //----------------------------------------------------------------------------
31903190 void QAsmView::toggleBreakpoint(int line)
31913191 {
3192 if ( line < asmEntry.size() )
3192 if ( static_cast<size_t>(line) < asmEntry.size() )
31933193 {
31943194 int bpNum = isBreakpointAtLine(line);
31953195
32293229 {
32303230 if ( watchpoint[i].endaddress )
32313231 {
3232 if ( (romAddr >= watchpoint[i].address) &&
3233 romAddr < watchpoint[i].endaddress )
3232 if ( ( static_cast<unsigned int>(romAddr) >= watchpoint[i].address) &&
3233 static_cast<unsigned int>(romAddr) < watchpoint[i].endaddress )
32343234 {
32353235 return i;
32363236 }
32373237 }
32383238 else
32393239 {
3240 if (romAddr == watchpoint[i].address)
3240 if ( static_cast<unsigned int>(romAddr) == watchpoint[i].address)
32413241 {
32423242 return i;
32433243 }
32473247 {
32483248 if ( watchpoint[i].endaddress )
32493249 {
3250 if ( (cpuAddr >= watchpoint[i].address) &&
3251 cpuAddr < watchpoint[i].endaddress )
3250 if ( ( static_cast<unsigned int>(cpuAddr) >= watchpoint[i].address) &&
3251 static_cast<unsigned int>(cpuAddr) < watchpoint[i].endaddress )
32523252 {
32533253 return i;
32543254 }
32553255 }
32563256 else
32573257 {
3258 if (cpuAddr == watchpoint[i].address)
3258 if ( static_cast<unsigned int>(cpuAddr) == watchpoint[i].address)
32593259 {
32603260 return i;
32613261 }
32673267 //----------------------------------------------------------------------------
32683268 int QAsmView::isBreakpointAtLine( int l )
32693269 {
3270 if ( l < asmEntry.size() )
3270 if ( static_cast<size_t>(l) < asmEntry.size() )
32713271 {
32723272 if ( asmEntry[l]->type == dbg_asm_entry_t::ASM_TEXT )
32733273 {
32893289 {
32903290 int addr = -1;
32913291
3292 if ( (selAddrLine >= 0) && (selAddrLine < asmEntry.size()) )
3292 if ( (selAddrLine >= 0) && (static_cast<size_t>(selAddrLine) < asmEntry.size()) )
32933293 {
32943294 if ( selAddrValue == asmEntry[ selAddrLine ]->addr )
32953295 {
33103310 //----------------------------------------------------------------------------
33113311 int QAsmView::getAsmAddrFromLine(int line)
33123312 {
3313 if ( (line >= 0) && (line < asmEntry.size()) )
3313 if ( (line >= 0) && (static_cast<size_t>(line) < asmEntry.size()) )
33143314 {
33153315 return asmEntry[line]->addr;
33163316 }
34233423 }
34243424
34253425 // Don't stop on an symbol name or comment line, search for next assembly line
3426 while ( (line < asmEntry.size()) && (asmEntry[line]->type != dbg_asm_entry_t::ASM_TEXT) )
3426 while ( (static_cast<size_t>(line) < asmEntry.size()) && (asmEntry[line]->type != dbg_asm_entry_t::ASM_TEXT) )
34273427 {
34283428 line++;
34293429 }
35453545 {
35463546 uint8_t cdl_data;
35473547 instruction_addr = GetNesFileAddress(addr) - 16;
3548 if ( (instruction_addr >= 0) && (instruction_addr < cdloggerdataSize) )
3548 if ( (instruction_addr >= 0) && (static_cast<unsigned int>(instruction_addr) < cdloggerdataSize) )
35493549 {
35503550 cdl_data = cdloggerdata[instruction_addr] & 3;
35513551 if (cdl_data == 3)
36763676 char stmp[256];
36773677 //printf("Debug symbol Found at $%04X \n", dbgSym->ofs );
36783678
3679 if ( dbgSym->name.size() > 0 )
3679 if ( dbgSym->name().size() > 0 )
36803680 {
36813681 d = new dbg_asm_entry_t();
36823682
36833683 *d = *a;
36843684 d->type = dbg_asm_entry_t::SYMBOL_NAME;
3685 d->text.assign( " " + dbgSym->name );
3685 d->text.assign( " " + dbgSym->name() );
36863686 d->text.append( ":");
36873687 d->line = asmEntry.size();
36883688
36903690 }
36913691
36923692 i=0; j=0;
3693 c = dbgSym->comment.c_str();
3693 c = dbgSym->comment().c_str();
36943694
36953695 while ( c[i] != 0 )
36963696 {
37453745
37463746 a->line = asmEntry.size();
37473747
3748 if ( maxLineLen < line.size() )
3748 if ( static_cast<size_t>(maxLineLen) < line.size() )
37493749 {
37503750 maxLineLen = line.size();
37513751 }
43344334 }
43354335 }
43364336 //----------------------------------------------------------------------------
4337 static int getGameDebugBreakpointFileName(char *filepath)
4337 static int getGameDebugBreakpointFileName(std::string &filepath)
43384338 {
43394339 int i,j;
43404340 const char *romFile;
43514351
43524352 if ( romFile[i] == '|' )
43534353 {
4354 filepath[i] = '.';
4354 filepath.push_back('.');
43554355 }
43564356 else
43574357 {
4358 if ( romFile[i] == '/' )
4358 if ( (romFile[i] == '/') || (romFile[i] == '\\') )
43594359 {
43604360 j = -1;
43614361 }
43634363 {
43644364 j = i;
43654365 }
4366 filepath[i] = romFile[i];
4366 filepath.push_back(romFile[i]);
43674367 }
43684368 i++;
43694369 }
4370 if ( j >= 0 )
4371 {
4372 filepath[j] = 0; i=j;
4373 }
4374
4375 filepath[i] = '.'; i++;
4376 filepath[i] = 'd'; i++;
4377 filepath[i] = 'b'; i++;
4378 filepath[i] = 'g'; i++;
4379 filepath[i] = 0;
4370 if ( (j >= 0) && (static_cast<size_t>(j) < filepath.size()) )
4371 {
4372 filepath.erase(j);
4373 }
4374 filepath.append(".fdb");
43804375
43814376 return 0;
43824377 }
43854380 {
43864381 int i;
43874382 FILE *fp;
4388 char stmp[512];
43894383 char flags[8];
43904384 debuggerBookmark_t *bm;
4385 std::string fileName;
43914386
43924387 // If no breakpoints are loaded, skip saving
43934388 if ( !force && (numWPs == 0) && (dbgBmMgr.size() == 0) )
43944389 {
43954390 return;
43964391 }
4397 if ( getGameDebugBreakpointFileName( stmp ) )
4392 if ( getGameDebugBreakpointFileName( fileName ) )
43984393 {
43994394 printf("Error: Failed to get save file name for debug\n");
44004395 return;
44014396 }
44024397
4403 printf("Debug Save File: '%s' \n", stmp );
4404
4405 fp = fopen( stmp, "w");
4398 printf("Debug Save File: '%s' \n", fileName.c_str());
4399
4400 fp = fopen( fileName.c_str(), "w");
44064401
44074402 if ( fp == NULL )
44084403 {
4409 printf("Error: Failed to open file '%s' for writing\n", stmp );
4404 printf("Error: Failed to open file '%s' for writing\n", fileName.c_str() );
44104405 return;
44114406 }
44124407
45314526 FILE *fp;
45324527 char stmp[512];
45334528 char id[64], data[128];
4529 std::string fileName;
45344530
45354531 // If no debug windows are open, skip loading breakpoints
45364532 if ( dbgWin == NULL )
45384534 printf("No Debug Windows Open: Skipping loading of breakpoint data\n");
45394535 return;
45404536 }
4541 if ( getGameDebugBreakpointFileName( stmp ) )
4537 if ( getGameDebugBreakpointFileName( fileName ) )
45424538 {
45434539 printf("Error: Failed to get load file name for debug\n");
45444540 return;
45454541 }
45464542
4547 //printf("Debug Load File: '%s' \n", stmp );
4548
4549 fp = fopen( stmp, "r");
4543 //printf("Debug Load File: '%s' \n", fileName.c_str() );
4544
4545 fp = fopen( fileName.c_str(), "r");
45504546
45514547 if ( fp == NULL )
45524548 {
4553 printf("Error: Failed to open file '%s' for writing\n", stmp );
4549 printf("Warning: Failed to open file '%s' for reading\n", fileName.c_str() );
45544550 return;
45554551 }
45564552
49574953 //----------------------------------------------------------------------------
49584954 void QAsmView::gotoLine( int line )
49594955 {
4960 if ( (line >= 0) && (line < asmEntry.size()) )
4956 if ( (line >= 0) && (static_cast<size_t>(line) < asmEntry.size()) )
49614957 {
49624958 if ( curNavLoc.addr != asmEntry[line]->addr )
49634959 { // Don't push back to back duplicates into the navigation history
50245020 //----------------------------------------------------------------------------
50255021 void QAsmView::setSelAddrToLine( int line )
50265022 {
5027 if ( (line >= 0) && (line < asmEntry.size()) )
5023 if ( (line >= 0) && (static_cast<size_t>(line) < asmEntry.size()) )
50285024 {
50295025 int addr = asmEntry[line]->addr;
50305026 selAddrLine = line;
51775173
51785174 line = lineOffset + c.y();
51795175
5180 opcodeValid = (line < asmEntry.size()) && (asmEntry[line]->size > 0) &&
5176 opcodeValid = (static_cast<size_t>(line) < asmEntry.size()) && (asmEntry[line]->size > 0) &&
51815177 (asmEntry[line]->type == dbg_asm_entry_t::ASM_TEXT);
51825178
51835179 showOpcodeDesc = (c.x() >= opcodeLinePos) && (c.x() < operandLinePos) && opcodeValid;
51845180
51855181 showAddrDesc = (c.x() >= pcLocLinePos) && (c.x() < byteCodeLinePos) && opcodeValid;
51865182
5187 if ( (c.x() > operandLinePos) && opcodeValid && (asmEntry[line]->sym.name.size() > 0) )
5188 {
5189 size_t subStrLoc = asmEntry[line]->text.find( asmEntry[line]->sym.name, operandLinePos );
5190
5191 if ( (subStrLoc != std::string::npos) && (subStrLoc > operandLinePos) )
5183 if ( (c.x() > operandLinePos) && opcodeValid && (asmEntry[line]->sym.name().size() > 0) )
5184 {
5185 size_t subStrLoc = asmEntry[line]->text.find( asmEntry[line]->sym.name(), operandLinePos );
5186
5187 if ( (subStrLoc != std::string::npos) && (subStrLoc > static_cast<size_t>(operandLinePos)) )
51925188 {
51935189 //printf("Line:%i asmEntry DB Sym: %zi '%s'\n", line, subStrLoc, asmEntry[line]->sym.name.c_str() );
51945190 int symTextStart = subStrLoc;
5195 int symTextEnd = subStrLoc + asmEntry[line]->sym.name.size();
5191 int symTextEnd = subStrLoc + asmEntry[line]->sym.name().size();
51965192
51975193 if ( (c.x() >= symTextStart) && (c.x() < symTextEnd) )
51985194 {
52025198 }
52035199
52045200 if ( opcodeValid && (c.x() > operandLinePos) &&
5205 (c.x() < asmEntry[line]->text.size()) )
5201 ( static_cast<size_t>(c.x()) < asmEntry[line]->text.size()) )
52065202 {
52075203 i = c.x();
52085204
52565252 }
52575253 else if ( showSymHexDecode )
52585254 {
5259 sprintf( stmp, "$%04X", asmEntry[line]->sym.ofs );
5255 sprintf( stmp, "$%04X", asmEntry[line]->sym.offset() );
52605256
52615257 QToolTip::showText(helpEvent->globalPos(), tr(stmp), this );
52625258 }
55555551
55565552 //printf("c (%i,%i) : Line %i : %04X \n", c.x(), c.y(), line, asmEntry[line]->addr );
55575553
5558 if ( line < asmEntry.size() )
5554 if ( static_cast<size_t>(line) < asmEntry.size() )
55595555 {
55605556 int addr;
55615557
56545650 }
56555651 hlgtXd = (hlgtXe - hlgtXs);
56565652
5657 if ( hlgtXs < asmEntry[l]->text.size() )
5653 if ( static_cast<size_t>(hlgtXs) < asmEntry[l]->text.size() )
56585654 {
56595655 s = asmEntry[l]->text.substr( hlgtXs, hlgtXd );
56605656 }
57455741 selAddrType = 0;
57465742 selAddrText[0] = 0;
57475743
5748 if ( line < asmEntry.size() )
5744 if ( static_cast<size_t>(line) < asmEntry.size() )
57495745 {
57505746 int i,j, addr = -1, addrTextLoc = -1, selChar;
57515747 int symTextStart = -1, symTextEnd = -1;
57565752
57575753 if ( asmEntry[line]->type == dbg_asm_entry_t::ASM_TEXT )
57585754 {
5759 if ( selChar < (int)asmEntry[line]->text.size() )
5755 if ( static_cast<size_t>(selChar) < asmEntry[line]->text.size() )
57605756 {
57615757 i = selChar;
57625758
5763 if ( asmEntry[line]->sym.name.size() > 0 )
5759 if ( asmEntry[line]->sym.name().size() > 0 )
57645760 {
5765 size_t subStrLoc = asmEntry[line]->text.find( asmEntry[line]->sym.name, operandLinePos );
5766
5767 if ( (subStrLoc != std::string::npos) && (subStrLoc > operandLinePos) )
5761 size_t subStrLoc = asmEntry[line]->text.find( asmEntry[line]->sym.name(), operandLinePos );
5762
5763 if ( (subStrLoc != std::string::npos) && (subStrLoc > static_cast<size_t>(operandLinePos)) )
57685764 {
57695765 //printf("Line:%i asmEntry DB Sym: %zi '%s'\n", line, subStrLoc, asmEntry[line]->sym.name.c_str() );
57705766 symTextStart = subStrLoc;
5771 symTextEnd = subStrLoc + asmEntry[line]->sym.name.size();
5767 symTextEnd = subStrLoc + asmEntry[line]->sym.name().size();
57725768 }
57735769 }
57745770
57775773 selAddrLine = line;
57785774 selAddrChar = symTextStart;
57795775 selAddrWidth = symTextEnd - symTextStart;
5780 selAddrValue = addr = asmEntry[line]->sym.ofs;
5776 selAddrValue = addr = asmEntry[line]->sym.offset();
57815777 selAddrType = 0;
57825778
57835779 if ( selAddrWidth >= (int)sizeof(selAddrText) )
57845780 {
57855781 selAddrWidth = sizeof(selAddrText)-1;
57865782 }
5787 strncpy( selAddrText, asmEntry[line]->sym.name.c_str(), selAddrWidth );
5783 strncpy( selAddrText, asmEntry[line]->sym.name().c_str(), selAddrWidth );
57885784 selAddrText[ selAddrWidth ] = 0;
57895785 }
57905786 else if ( isxdigit( asmEntry[line]->text[i] ) )
59835979
59845980 ctxMenuAddr = -1;
59855981
5986 if ( line < asmEntry.size() )
5987 {
5988 int addr, romAddr;
5982 if ( static_cast<size_t>(line) < asmEntry.size() )
5983 {
5984 int addr, romAddr, bank = -1;
59895985
59905986 if ( selAddrValue < 0 )
59915987 {
60346030 act->setShortcut( QKeySequence(tr("B")));
60356031 connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuAddBP(void)) );
60366032
6037 act = new QAction(tr("Add &Symbolic Debug Marker"), &menu);
6033 int cpuAddr = getAsmAddrFromLine( getCtxMenuLine() );
6034 if ( cpuAddr >= 0x8000 )
6035 {
6036 bank = getBank(cpuAddr);
6037 }
6038 if ( debugSymbolTable.getSymbolAtBankOffset( bank, cpuAddr ) )
6039 {
6040 act = new QAction(tr("Edit &Symbolic Debug Marker"), &menu);
6041 }
6042 else
6043 {
6044 act = new QAction(tr("Add &Symbolic Debug Marker"), &menu);
6045 }
60386046 menu.addAction(act);
60396047 act->setShortcut( QKeySequence(tr("S")));
60406048 connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuAddSym(void)) );
60416049
6042 act = new QAction(tr("Add Book&mark"), &menu);
6050 if ( dbgBmMgr.getAddr( cpuAddr ) )
6051 {
6052 act = new QAction(tr("Edit Book&mark"), &menu);
6053 }
6054 else
6055 {
6056 act = new QAction(tr("Add Book&mark"), &menu);
6057 }
60436058 menu.addAction(act);
60446059 act->setShortcut( QKeySequence(tr("M")));
60456060 connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuAddBM(void)) );
63496364 lineIsPC = false;
63506365 }
63516366
6352 if ( l < asmEntry.size() )
6367 if ( static_cast<size_t>(l) < asmEntry.size() )
63536368 {
63546369 //if ( asmEntry[l]->type != dbg_asm_entry_t::ASM_TEXT )
63556370 //{
63816396 if ( (selAddrLine == l) )
63826397 { // Highlight ASM line for selected address.
63836398 if ( !txtHlgtSet && (selAddr == selAddrValue) &&
6384 (asmEntry[l]->text.size() >= (selAddrChar + selAddrWidth) ) &&
6399 (asmEntry[l]->text.size() >= static_cast<size_t>(selAddrChar + selAddrWidth) ) &&
63856400 ( asmEntry[l]->text.compare( selAddrChar, selAddrWidth, selAddrText ) == 0 ) )
63866401 {
63876402 int ax;
64366451 }
64376452 hlgtXd = (hlgtXe - hlgtXs);
64386453
6439 if ( hlgtXs < asmEntry[l]->text.size() )
6454 if ( static_cast<size_t>(hlgtXs) < asmEntry[l]->text.size() )
64406455 {
64416456 s = asmEntry[l]->text.substr( hlgtXs, hlgtXd );
64426457 }
64686483 x = -pxLineXScroll;
64696484 l = lineOffset + row;
64706485
6471 if ( l < asmEntry.size() )
6486 if ( static_cast<size_t>(l) < asmEntry.size() )
64726487 {
64736488 if ( asmPC != NULL )
64746489 {
5353
5454 // Enable Sound Select
5555 enaChkbox = new QCheckBox(tr("Enable Sound"));
56 // Speaker Mute Select
57 muteChkbox = new QCheckBox(tr("Mute Speaker Output"));
5658 // Enable Low Pass Filter Select
5759 enaLowPass = new QCheckBox(tr("Enable Low Pass Filter"));
5860
5961 setCheckBoxFromProperty(enaChkbox, "SDL.Sound");
62 setCheckBoxFromProperty(muteChkbox, "SDL.Sound.Mute");
6063 setCheckBoxFromProperty(enaLowPass, "SDL.Sound.LowPass");
6164
6265 connect(enaChkbox, SIGNAL(stateChanged(int)), this, SLOT(enaSoundStateChange(int)));
66 connect(muteChkbox, SIGNAL(stateChanged(int)), this, SLOT(enaSpeakerMuteChange(int)));
6367 connect(enaLowPass, SIGNAL(stateChanged(int)), this, SLOT(enaSoundLowPassChange(int)));
6468
6569 vbox1->addWidget(enaChkbox);
70 vbox1->addWidget(muteChkbox);
6671 vbox1->addWidget(enaLowPass);
6772
6873 // Audio Quality Select
329334 sprintf( stmp, "Sink Starve Count: %u", nes_shm->sndBuf.starveCounter );
330335
331336 starveLbl->setText( tr(stmp) );
337
338 if ( FCEUD_SoundIsMuted() != muteChkbox->isChecked() )
339 {
340 muteChkbox->setChecked( FCEUD_SoundIsMuted() );
341 }
332342 }
333343 //----------------------------------------------------
334344 void ConsoleSndConfDialog_t::setSliderEnables(void)
535545 }
536546 }
537547 //----------------------------------------------------
548 void ConsoleSndConfDialog_t::enaSpeakerMuteChange(int value)
549 {
550 FCEUD_MuteSoundOutput( value ? true : false );
551 }
552 //----------------------------------------------------
538553 void ConsoleSndConfDialog_t::enaSoundLowPassChange(int value)
539554 {
540555 if (value)
3030
3131 int sndQuality;
3232 QCheckBox *enaChkbox;
33 QCheckBox *muteChkbox;
3334 QCheckBox *enaLowPass;
3435 QCheckBox *swapDutyChkbox;
3536 QCheckBox *useGlobalFocus;
6768 void noiseChanged(int value);
6869 void pcmChanged(int value);
6970 void enaSoundStateChange(int value);
71 void enaSpeakerMuteChange(int value);
7072 void enaSoundLowPassChange(int value);
7173 void swapDutyCallback(int value);
7274 void useGlobalFocusChanged(int value);
2020 #include <stdio.h>
2121 #include <stdlib.h>
2222 #include <string.h>
23 #include <string>
2324
2425 #include <QWindow>
2526 #include <QScreen>
2627 #include <QToolTip>
28 #include <QFileInfo>
2729 #include <QApplication>
2830
2931 #if WIN32
4547 #include "Qt/fceuWrapper.h"
4648 #include "Qt/ConsoleUtilities.h"
4749
48 //---------------------------------------------------------------------------
49 int getDirFromFile( const char *path, char *dir )
50 {
51 int i, lastSlash = -1, lastPeriod = -1;
52
53 i=0;
54 while ( path[i] != 0 )
55 {
56 if ( path[i] == '/' )
57 {
58 lastSlash = i;
59 }
60 else if ( path[i] == '.' )
61 {
62 lastPeriod = i;
63 }
64 dir[i] = path[i]; i++;
65 }
66 dir[i] = 0;
67
68 if ( lastPeriod >= 0 )
69 {
70 if ( lastPeriod > lastSlash )
71 {
72 dir[lastSlash] = 0;
73 }
50 static std::string fceuExecPath;
51 //---------------------------------------------------------------------------
52 int getDirFromFile( const char *path, std::string &dir )
53 {
54 dir.clear();
55
56 if (path[0] != 0)
57 {
58 QFileInfo fi;
59
60 fi.setFile( QString(path) );
61
62 if (fi.exists())
63 {
64 dir = fi.canonicalPath().toStdString();
65 }
66 else
67 {
68 dir = fi.absolutePath().toStdString();
69 }
70 //printf("Dir: '%s'\n", dir.c_str());
7471 }
7572
7673 return 0;
7875 //---------------------------------------------------------------------------
7976 const char *getRomFile( void )
8077 {
81 static char filePath[2048];
78 static std::string filePath;
8279
8380 if ( GameInfo )
8481 {
8784
8885 if ( GameInfo->archiveFilename != NULL )
8986 {
90 char dir[1024], base[512], suffix[64];
91
92 parseFilepath( GameInfo->archiveFilename, dir, base, suffix );
93
94 filePath[0] = 0;
95
96 if ( dir[0] != 0 )
97 {
98 strcat( filePath, dir );
99 }
100
101 parseFilepath( GameInfo->filename, dir, base, suffix );
102
103 strcat( filePath, base );
104 strcat( filePath, suffix );
105
106 //printf("ArchivePath: '%s' \n", filePath );
107
108 return filePath;
87 std::string dir, base, suffix;
88
89 parseFilepath( GameInfo->archiveFilename, &dir, &base, &suffix );
90
91 filePath.clear();
92
93 if ( dir.size() != 0 )
94 {
95 filePath.append( dir );
96 }
97
98 parseFilepath( GameInfo->filename, &dir, &base, &suffix );
99
100 filePath.append( base );
101 filePath.append( suffix );
102
103 //printf("ArchivePath: '%s' \n", filePath.c_str() );
104
105 return filePath.c_str();
109106 }
110107 else
111108 {
112109 return GameInfo->filename;
113110 }
114111 }
115 return NULL;
112 return nullptr;
116113 }
117114 //---------------------------------------------------------------------------
118115 // Return file base name stripping out preceding path and trailing suffix.
162159 return end;
163160 }
164161 //---------------------------------------------------------------------------
165 int parseFilepath( const char *filepath, char *dir, char *base, char *suffix )
166 {
167 int i=0,j=0,end=0;
168
169 if ( suffix != NULL )
170 {
171 suffix[0] = 0;
172 }
162 int parseFilepath( const char *filepath, std::string *dir, std::string *base, std::string *suffix )
163 {
164 if (dir)
165 {
166 dir->clear();
167 }
168 if (base)
169 {
170 base->clear();
171 }
172 if (suffix)
173 {
174 suffix->clear();
175 }
176
177 size_t i=0,j=0;
178
173179 if ( filepath == NULL )
174180 {
175 if ( dir ) dir[0] = 0;
176 if ( base ) base[0] = 0;
177 if ( suffix) suffix[0] = 0;
178181 return 0;
179182 }
180183 i=0; j=0;
186189 }
187190 if ( dir )
188191 {
189 dir[i] = filepath[i];
192 dir->push_back(filepath[i]);
190193 }
191194 i++;
192195 }
193 if ( dir )
194 {
195 dir[j] = 0;
196 if (dir)
197 {
198 if (j > 0)
199 {
200 dir->erase(j);
201 }
196202 }
197203 i = j;
198204
199 if ( base == NULL )
200 {
201 return end;
202 }
203
204 j=0;
205205 while ( filepath[i] != 0 )
206206 {
207 base[j] = filepath[i]; i++; j++;
208 }
209 base[j] = 0; end=j;
210
211 if ( suffix )
212 {
213 suffix[0] = 0;
214 }
215
216 while ( j > 1 )
217 {
218 j--;
219 if ( base[j] == '.' )
220 {
221 if ( suffix )
222 {
223 strcpy( suffix, &base[j] );
224 }
225 end=j; base[j] = 0;
226 break;
227 }
228 }
229 return end;
207 if (filepath[i] == '.')
208 {
209 j = i;
210 }
211 if (base)
212 {
213 base->push_back(filepath[i]);
214 }
215 i++;
216 }
217
218 if (filepath[j] == '.')
219 {
220 if ( suffix )
221 {
222 suffix->assign( &filepath[j] );
223 }
224 if (base)
225 {
226 i = base->find_last_of('.');
227
228 if ( i != std::string::npos )
229 {
230 base->erase(i);
231 }
232 }
233 }
234 return 0;
230235 }
231236 //---------------------------------------------------------------------------
232237 // Returns the path of fceux.exe as a string.
233 int fceuExecutablePath( char *outputPath, int outputSize )
234 {
235 if ( (outputPath == NULL) || (outputSize <= 0) )
236 {
237 return -1;
238 }
239 outputPath[0] = 0;
238 static int _fceuExecutablePath( std::string &outputPath )
239 {
240 outputPath.clear();
240241
241242 #ifdef WIN32
242243 char fullPath[2048];
247248 GetModuleFileNameA(NULL, fullPath, 2048);
248249 _splitpath(fullPath, driveLetter, directory, NULL, NULL);
249250 snprintf(finalPath, sizeof(finalPath), "%s%s", driveLetter, directory);
250 strncpy( outputPath, finalPath, outputSize );
251 outputPath[outputSize-1] = 0;
251 outputPath.assign( finalPath );
252252
253253 return 0;
254254 #elif __linux__ || __unix__
266266 if ( dir )
267267 {
268268 //printf("DIR Path: '%s' \n", dir );
269 strncpy( outputPath, dir, outputSize );
270 outputPath[outputSize-1] = 0;
269 outputPath.assign( dir );
271270 return 0;
272271 }
273272 }
287286 if ( dir )
288287 {
289288 //printf("DIR Path: '%s' \n", dir );
290 strncpy( outputPath, dir, outputSize );
291 outputPath[outputSize-1] = 0;
289 outputPath.assign( dir );
292290 return 0;
293291 }
294292 }
295293 #endif
296294 return -1;
295 }
296 //---------------------------------------------------------------------------
297 const char *fceuExecutablePath(void)
298 {
299 if (fceuExecPath.size() == 0)
300 {
301 _fceuExecutablePath( fceuExecPath );
302 }
303 return fceuExecPath.c_str();
297304 }
298305 //---------------------------------------------------------------------------
299306 int fceuLoadConfigColor( const char *confName, QColor *color )
00 // ConsoleUtilities.h
11
22 #pragma once
3
4 #include <string>
35
46 #include <QColor>
57 #include <QTimer>
810 #include <QHelpEvent>
911 #include <QCheckBox>
1012
11 int getDirFromFile( const char *path, char *dir );
13 int getDirFromFile( const char *path, std::string &dir );
1214
1315 const char *getRomFile( void );
1416
15 int getFileBaseName( const char *filepath, char *base, char *suffix = NULL );
17 int getFileBaseName( const char *filepath, char *base, char *suffix = nullptr );
1618
17 int parseFilepath( const char *filepath, char *dir, char *base, char *suffix = NULL );
19 int parseFilepath( const char *filepath, std::string *dir, std::string *base = nullptr, std::string *suffix = nullptr );
1820
19 int fceuExecutablePath( char *outputPath, int outputSize );
21 const char *fceuExecutablePath(void);
2022
2123 int fceuLoadConfigColor( const char *confName, QColor *color );
2224
8383 setMinimumWidth( 256 );
8484 setMinimumHeight( 224 );
8585 setFocusPolicy(Qt::StrongFocus);
86 //setAttribute(Qt::WA_OpaquePaintEvent);
8687
8788 localBufSize = (4 * GL_NES_WIDTH) * (4 * GL_NES_HEIGHT) * sizeof(uint32_t);
8889
271272 GL_BGRA, GL_UNSIGNED_BYTE, 0 );
272273 }
273274
275 glEnable(GL_BLEND);
276 glBlendFunc(GL_ONE, GL_ONE);
277 //glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
274278 //printf("Texture Built: %ix%i\n", w, h);
275279 }
276280
346350 initializeOpenGLFunctions();
347351 // Set up the rendering context, load shaders and other resources, etc.:
348352 //QOpenGLFunctions *gl = QOpenGLContext::currentContext()->functions();
349 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
353 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
350354
351355 chkExtnsGL();
352356 //printf("GL Init!\n");
665669 }
666670 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
667671
672 glEnable(GL_BLEND);
673 glBlendFunc(GL_ONE, GL_ZERO);
674 //glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
668675
669676 if ( textureType == GL_TEXTURE_RECTANGLE )
670677 {
3535 #include <QWindow>
3636 #include <QScreen>
3737 #include <QHeaderView>
38 #include <QFileInfo>
3839 #include <QFileDialog>
3940 #include <QMessageBox>
4041 #include <QInputDialog>
434435 void consoleWin_t::winActiveChanged(void)
435436 {
436437 QWidget *w;
438 bool muteWindow = false;
437439
438440 w = this->window();
439441
449451 {
450452 if ( hdl->isActive() )
451453 {
452 FCEUD_MuteSoundOutput(false);
454 muteWindow = false;
453455 }
454456 else
455457 {
456 FCEUD_MuteSoundOutput(true);
458 muteWindow = true;
457459 }
458460 }
459461 }
460462 }
463 FCEUD_MuteSoundWindow(muteWindow);
461464 }
462465
463466 QSize consoleWin_t::calcRequiredSize(void)
775778 {
776779 QList<QUrl> urls = event->mimeData()->urls();
777780
778 FCEU_WRAPPER_LOCK();
779 LoadGame( urls[0].toString( QUrl::PreferLocalFile ).toStdString().c_str() );
780 FCEU_WRAPPER_UNLOCK();
781 event->accept();
781 QString filename = urls[0].toString( QUrl::PreferLocalFile );
782
783 QFileInfo fi( filename );
784 QString suffix = fi.suffix();
785
786 //printf("DragNDrop Suffix: %s\n", suffix.toStdString().c_str() );
787
788 if ( suffix.compare("lua", Qt::CaseInsensitive) == 0 )
789 {
790 int luaLoadSuccess;
791
792 FCEU_WRAPPER_LOCK();
793 luaLoadSuccess = FCEU_LoadLuaCode( filename.toStdString().c_str() );
794 FCEU_WRAPPER_UNLOCK();
795
796 if (luaLoadSuccess)
797 {
798 g_config->setOption("SDL.LastLoadLua", filename.toStdString().c_str());
799 }
800 event->accept();
801 }
802 else
803 {
804 int romLoadSuccess;
805
806 FCEU_WRAPPER_LOCK();
807 romLoadSuccess = LoadGame( filename.toStdString().c_str() );
808 FCEU_WRAPPER_UNLOCK();
809
810 if (!romLoadSuccess)
811 {
812 printf("DragNDrop ROM Load Failed for %s\n", filename.toStdString().c_str() );
813 }
814 event->accept();
815 }
782816 }
783817 }
784818
849883 Hotkeys[HK_FRAME_ADVANCE].getShortcut()->setEnabled(false);
850884 Hotkeys[HK_TURBO ].getShortcut()->setEnabled(false);
851885
886 connect( Hotkeys[ HK_VOLUME_MUTE ].getShortcut(), SIGNAL(activated()), this, SLOT(muteSoundVolume(void)) );
852887 connect( Hotkeys[ HK_VOLUME_DOWN ].getShortcut(), SIGNAL(activated()), this, SLOT(decrSoundVolume(void)) );
853888 connect( Hotkeys[ HK_VOLUME_UP ].getShortcut(), SIGNAL(activated()), this, SLOT(incrSoundVolume(void)) );
854889
861896 connect( Hotkeys[ HK_TOGGLE_BG ].getShortcut(), SIGNAL(activated()), this, SLOT(toggleBackground(void)) );
862897 connect( Hotkeys[ HK_TOGGLE_FG ].getShortcut(), SIGNAL(activated()), this, SLOT(toggleForeground(void)) );
863898 connect( Hotkeys[ HK_FKB_ENABLE ].getShortcut(), SIGNAL(activated()), this, SLOT(toggleFamKeyBrdEnable(void)) );
899 connect( Hotkeys[ HK_TOGGLE_ALL_CHEATS ].getShortcut(), SIGNAL(activated()), this, SLOT(toggleGlobalCheatEnable(void)) );
864900
865901 connect( Hotkeys[ HK_SAVE_STATE_0 ].getShortcut(), SIGNAL(activated()), this, SLOT(saveState0(void)) );
866902 connect( Hotkeys[ HK_SAVE_STATE_1 ].getShortcut(), SIGNAL(activated()), this, SLOT(saveState1(void)) );
892928 QActionGroup *group;
893929 int useNativeMenuBar;
894930 int customAutofireOnFrames, customAutofireOffFrames;
895 ColorMenuItem *bgColorItem;
896931 //QShortcut *shortcut;
897932
898933 menubar = new consoleMenuBar(this);
12521287
12531288 optMenu->addAction(act);
12541289
1290 optMenu->addSeparator();
1291
12551292 // Options -> Video BG Color
12561293 fceuLoadConfigColor( "SDL.VideoBgColor", &videoBgColor );
12571294
1258 bgColorItem = new ColorMenuItem( tr("BG Side Panel Color"), "SDL.VideoBgColor", this );
1259 bgColorItem->connectColor( &videoBgColor );
1260
1261 optMenu->addAction(bgColorItem);
1262
1263 connect( bgColorItem, SIGNAL(colorChanged(QColor&)), this, SLOT(videoBgColorChanged(QColor&)) );
1295 bgColorMenuItem = new ColorMenuItem( tr("BG Side Panel Color"), "SDL.VideoBgColor", this );
1296 bgColorMenuItem->connectColor( &videoBgColor );
1297
1298 optMenu->addAction(bgColorMenuItem);
1299
1300 connect( bgColorMenuItem, SIGNAL(colorChanged(QColor&)), this, SLOT(videoBgColorChanged(QColor&)) );
1301
1302 // Options -> Use BG Palette for Video BG Color
1303 g_config->getOption( "SDL.UseBgPaletteForVideo", &usePaletteForVideoBg );
1304
1305 act = new QAction(tr("Use BG Palette for Video BG Color"), this);
1306 //act->setShortcut( QKeySequence(tr("Alt+/")));
1307 act->setCheckable(true);
1308 act->setChecked( usePaletteForVideoBg );
1309 act->setStatusTip(tr("Use BG Palette for Video BG Color"));
1310 //act->setIcon( style()->standardIcon( QStyle::SP_TitleBarMaxButton ) );
1311 connect(act, SIGNAL(triggered(bool)), this, SLOT(toggleUseBgPaletteForVideo(bool)) );
1312
1313 optMenu->addAction(act);
1314
1315 bgColorMenuItem->setEnabled( !usePaletteForVideoBg );
12641316 //-----------------------------------------------------------------------
12651317 // Emulation
12661318
12801332 connect( Hotkeys[ HK_POWER ].getShortcut(), SIGNAL(activated()), this, SLOT(powerConsoleCB(void)) );
12811333
12821334 // Emulation -> Reset
1283 resetAct = new QAction(tr("&Reset"), this);
1335 resetAct = new QAction(tr("Hard &Reset"), this);
12841336 //resetAct->setShortcut( QKeySequence(tr("Ctrl+R")));
1285 resetAct->setStatusTip(tr("Reset Console"));
1337 resetAct->setStatusTip(tr("Hard Reset of Console"));
12861338 resetAct->setIcon( style()->standardIcon( QStyle::SP_DialogResetButton ) );
12871339 connect(resetAct, SIGNAL(triggered()), this, SLOT(consoleHardReset(void)) );
12881340
12891341 emuMenu->addAction(resetAct);
12901342
1291 Hotkeys[ HK_RESET ].setAction( resetAct );
1292 connect( Hotkeys[ HK_RESET ].getShortcut(), SIGNAL(activated()), this, SLOT(consoleHardReset(void)) );
1343 Hotkeys[ HK_HARD_RESET ].setAction( resetAct );
1344 connect( Hotkeys[ HK_HARD_RESET ].getShortcut(), SIGNAL(activated()), this, SLOT(consoleHardReset(void)) );
12931345
12941346 // Emulation -> Soft Reset
12951347 sresetAct = new QAction(tr("&Soft Reset"), this);
12991351 connect(sresetAct, SIGNAL(triggered()), this, SLOT(consoleSoftReset(void)) );
13001352
13011353 emuMenu->addAction(sresetAct);
1354
1355 Hotkeys[ HK_SOFT_RESET ].setAction( sresetAct );
1356 connect( Hotkeys[ HK_SOFT_RESET ].getShortcut(), SIGNAL(activated()), this, SLOT(consoleSoftReset(void)) );
13021357
13031358 // Emulation -> Pause
13041359 pauseAct = new QAction(tr("&Pause"), this);
17291784
17301785 debugMenu->addAction(ggEncodeAct);
17311786
1732 // Debug -> iNES Header Editor
1733 iNesEditAct = new QAction(tr("&iNES Header Editor..."), this);
1787 // Debug -> NES Header Editor
1788 iNesEditAct = new QAction(tr("NES Header Edito&r..."), this);
17341789 //iNesEditAct->setShortcut( QKeySequence(tr("Shift+F7")));
1735 iNesEditAct->setStatusTip(tr("Open iNES Header Editor"));
1790 iNesEditAct->setStatusTip(tr("Open NES Header Editor"));
17361791 connect(iNesEditAct, SIGNAL(triggered()), this, SLOT(openNesHeaderEditor(void)) );
17371792
17381793 debugMenu->addAction(iNesEditAct);
21472202 g_config->save();
21482203 }
21492204 //---------------------------------------------------------------------------
2205 void consoleWin_t::toggleUseBgPaletteForVideo(bool checked)
2206 {
2207 usePaletteForVideoBg = checked;
2208
2209 g_config->setOption( "SDL.UseBgPaletteForVideo", usePaletteForVideoBg );
2210 g_config->save();
2211
2212 if ( !usePaletteForVideoBg )
2213 {
2214 fceuLoadConfigColor( "SDL.VideoBgColor", &videoBgColor );
2215 }
2216 bgColorMenuItem->setEnabled( !usePaletteForVideoBg );
2217 }
2218 //---------------------------------------------------------------------------
21502219 void consoleWin_t::closeApp(void)
21512220 {
21522221 nes_shm->runEmulator = 0;
22802349 int ret, useNativeFileDialogVal;
22812350 QString filename;
22822351 std::string last;
2283 char dir[512];
2284 char *romDir;
2352 std::string dir;
2353 const char *romDir;
22852354 QFileDialog dialog(this, tr("Open ROM File") );
22862355 QList<QUrl> urls;
22872356 QDir d;
23232392
23242393 g_config->getOption ("SDL.LastOpenFile", &last );
23252394
2326 getDirFromFile( last.c_str(), dir );
2327
2328 dialog.setDirectory( tr(dir) );
2395 getDirFromFile( last.c_str(), dir);
2396
2397 dialog.setDirectory( tr(dir.c_str()) );
23292398
23302399 // Check config option to use native file dialog or not
23312400 g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
23832452 int ret, useNativeFileDialogVal;
23842453 QString filename;
23852454 std::string last;
2386 char dir[512];
2387 char *romDir;
2455 std::string dir;
2456 const char *romDir;
23882457 QFileDialog dialog(this, tr("Load NSF File") );
23892458 QList<QUrl> urls;
23902459 QDir d;
24182487
24192488 getDirFromFile( last.c_str(), dir );
24202489
2421 dialog.setDirectory( tr(dir) );
2490 dialog.setDirectory( tr(dir.c_str()) );
24222491
24232492 // Check config option to use native file dialog or not
24242493 g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
24572526 int ret, useNativeFileDialogVal;
24582527 QString filename;
24592528 std::string last;
2460 char dir[512];
2529 std::string dir;
24612530 const char *base;
24622531 QFileDialog dialog(this, tr("Load State From File") );
24632532 QList<QUrl> urls;
25022571
25032572 getDirFromFile( last.c_str(), dir );
25042573
2505 dialog.setDirectory( tr(dir) );
2574 dialog.setDirectory( tr(dir.c_str()) );
25062575
25072576 // Check config option to use native file dialog or not
25082577 g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
25412610 int ret, useNativeFileDialogVal;
25422611 QString filename;
25432612 std::string last;
2544 char dir[512];
2613 std::string dir;
25452614 const char *base;
25462615 QFileDialog dialog(this, tr("Save State To File") );
25472616 QList<QUrl> urls;
25932662 }
25942663 getDirFromFile( last.c_str(), dir );
25952664
2596 dialog.setDirectory( tr(dir) );
2665 dialog.setDirectory( tr(dir.c_str()) );
25972666
25982667 // Check config option to use native file dialog or not
25992668 g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
30543123 {
30553124 iNesHeaderEditor_t *win;
30563125
3057 //printf("Open iNES Header Editor Window\n");
3126 //printf("Open NES Header Editor Window\n");
30583127
30593128 win = new iNesHeaderEditor_t(this);
30603129
31703239 void consoleWin_t::toggleFamKeyBrdEnable(void)
31713240 {
31723241 toggleFamilyKeyboardFunc();
3242 }
3243
3244 extern int globalCheatDisabled;
3245
3246 void consoleWin_t::toggleGlobalCheatEnable(void)
3247 {
3248 FCEU_WRAPPER_LOCK();
3249 FCEUI_GlobalToggleCheat(globalCheatDisabled);
3250 FCEU_WRAPPER_UNLOCK();
3251
3252 g_config->setOption("SDL.CheatsDisabled", globalCheatDisabled);
3253 g_config->save();
3254
3255 updateCheatDialog();
31733256 }
31743257
31753258 void consoleWin_t::warnAmbiguousShortcut( QShortcut *shortcut)
33273410 int ret, useNativeFileDialogVal;
33283411 QString filename;
33293412 std::string last;
3330 char dir[512];
3413 std::string dir;
33313414 QFileDialog dialog(this, tr("Open Game Genie ROM") );
33323415 QList<QUrl> urls;
33333416
33483431
33493432 getDirFromFile( last.c_str(), dir );
33503433
3351 dialog.setDirectory( tr(dir) );
3434 dialog.setDirectory( tr(dir.c_str()) );
33523435
33533436 // Check config option to use native file dialog or not
33543437 g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
34223505 int ret, useNativeFileDialogVal;
34233506 QString filename;
34243507 std::string last;
3425 char dir[512];
3508 std::string dir;
34263509 QFileDialog dialog(this, tr("Load FDS BIOS (disksys.rom)") );
34273510 QList<QUrl> urls;
34283511
34413524
34423525 g_config->getOption ("SDL.LastOpenFile", &last );
34433526
3444 getDirFromFile( last.c_str(), dir );
3445
3446 dialog.setDirectory( tr(dir) );
3527 getDirFromFile( last.c_str(), dir);
3528
3529 dialog.setDirectory( tr(dir.c_str()) );
34473530
34483531 // Check config option to use native file dialog or not
34493532 g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
35563639 if ( QDialog::Accepted == ret )
35573640 {
35583641 frameAdvance_Delay = dialog.intValue();
3642
3643 g_config->setOption("SDL.FrameAdvanceDelay", frameAdvance_Delay );
3644 g_config->save();
35593645 }
35603646 }
35613647
36533739 g_config->setOption("SDL.AutofireCustomOffFrames" , autoFireOffFrames);
36543740 g_config->save();
36553741 }
3742 }
3743
3744 void consoleWin_t::muteSoundVolume(void)
3745 {
3746 FCEU_WRAPPER_LOCK();
3747 FCEUD_SoundToggle();
3748 FCEU_WRAPPER_UNLOCK();
36563749 }
36573750
36583751 void consoleWin_t::incrSoundVolume(void)
39484041 if ( !FCEUI_WaveRecordRunning() )
39494042 {
39504043 const char *romFile;
3951 char fileName[1024];
4044 std::string fileName;
39524045
39534046 romFile = getRomFile();
39544047
39644057
39654058 if ( lastPath.size() > 0 )
39664059 {
3967 strcpy( fileName, lastPath.c_str() );
3968 strcat( fileName, "/" );
4060 fileName.assign( lastPath );
4061 fileName.append( "/" );
39694062 }
39704063 else if ( baseDir )
39714064 {
3972 strcpy( fileName, baseDir );
3973 strcat( fileName, "/wav/" );
4065 fileName.assign( baseDir );
4066 fileName.append( "/wav/" );
39744067 }
39754068 else
39764069 {
3977 fileName[0] = 0;
4070 fileName.clear();
39784071 }
3979 strcat( fileName, base );
3980 strcat( fileName, ".wav");
4072 fileName.append( base );
4073 fileName.append(".wav");
39814074 //printf("WAV Filepath:'%s'\n", fileName );
39824075 }
39834076 else
39854078 return;
39864079 }
39874080 FCEU_WRAPPER_LOCK();
3988 FCEUI_BeginWaveRecord( fileName );
4081 FCEUI_BeginWaveRecord( fileName.c_str() );
39894082 FCEU_WRAPPER_UNLOCK();
39904083 }
39914084 }
39994092 int ret, useNativeFileDialogVal;
40004093 QString filename;
40014094 std::string lastPath;
4002 //char dir[512];
40034095 const char *base, *rom;
40044096 QFileDialog dialog(this, tr("Save WAV Movie for Recording") );
40054097 QList<QUrl> urls;
41394231
41404232 void consoleWin_t::openOnlineDocs(void)
41414233 {
4142 if ( QDesktopServices::openUrl( QUrl("http://fceux.com/web/help/fceux.html") ) == false )
4143 {
4144 QueueErrorMsgWindow("Error: Failed to open link to: http://fceux.com/web/help/fceux.html");
4234 if ( QDesktopServices::openUrl( QUrl("https://fceux.com/web/help/fceux.html") ) == false )
4235 {
4236 QueueErrorMsgWindow("Error: Failed to open link to: https://fceux.com/web/help/fceux.html");
41454237 }
41464238 return;
41474239 }
47204812 consoleRecentRomAction::consoleRecentRomAction(QString desc, QWidget *parent)
47214813 : QAction( desc, parent )
47224814 {
4815 QString txt;
4816 QFileInfo fi(desc);
4817
47234818 path = desc.toStdString();
4819
4820 txt = fi.fileName();
4821 txt += QString("\t");
4822 txt += desc;
4823
4824 setText( txt );
47244825 }
47254826 //----------------------------------------------------------------------------
47264827 consoleRecentRomAction::~consoleRecentRomAction(void)
2626 #include <QRecursiveMutex>
2727 #endif
2828
29 #include "Qt/ColorMenu.h"
2930 #include "Qt/ConsoleViewerGL.h"
3031 #include "Qt/ConsoleViewerSDL.h"
3132 #include "Qt/GamePadConf.h"
258259
259260 QTimer *gameTimer;
260261 QColor videoBgColor;
262 ColorMenuItem *bgColorMenuItem;
261263
262264 std::string errorMsg;
263265 bool errorMsgValid;
402404 void stopMovie(void);
403405 void playMovieFromBeginning(void);
404406 void setCustomAutoFire(void);
407 void muteSoundVolume(void);
405408 void incrSoundVolume(void);
406409 void decrSoundVolume(void);
407410 void toggleLagCounterDisplay(void);
414417 void toggleBackground(void);
415418 void toggleForeground(void);
416419 void toggleFamKeyBrdEnable(void);
420 void toggleGlobalCheatEnable(void);
417421 void saveState0(void);
418422 void saveState1(void);
419423 void saveState2(void);
451455 void winActiveChanged(void);
452456 void emuFrameFinish(void);
453457 void toggleMenuAutoHide(bool);
458 void toggleUseBgPaletteForVideo(bool);
454459 void videoBgColorChanged( QColor &c );
455460 void loadRomRequestCB( QString s );
456461
247247 //*********************************************************************************
248248 int FamilyKeyboardWidget::getKeyAtPoint( QPoint p )
249249 {
250 for (int i=0; i<NUM_KEYS; i++)
250 for (int i=0; i < static_cast<int>(NUM_KEYS); i++)
251251 {
252252 if ( key[i].rect.contains(p) )
253253 {
10281028 //----------------------------------------------------------------------------
10291029 int FKBConfigDialog::getButtonIndexFromName( const char *buttonName )
10301030 {
1031 for (int j=0; j<FamilyKeyboardWidget::NUM_KEYS; j++)
1031 for (int j=0; j < static_cast<int>(FamilyKeyboardWidget::NUM_KEYS); j++)
10321032 {
10331033 if ( strcmp( buttonName, FamilyKeyBoardNames[j] ) == 0 )
10341034 {
432432 //----------------------------------------------------------------------------
433433 void GameGenieDialog_t::ListGGAddresses(void)
434434 {
435 int i; //mbg merge 7/18/06 changed from int
436435 int a = -1; int v = -1; int c = -1;
437436 QTreeWidgetItem *item;
438437 char str[32];
459458
460459 if (a != -1 && v != -1)
461460 {
462 for (i = 0; i < PRGsize[0]; i += 0x2000)
461 for (unsigned int i = 0; i < PRGsize[0]; i += 0x2000)
463462 {
464463 if (c == -1 || PRGptr[0][i + (a & 0x1FFF)] == c)
465464 {
603603 mapSel->addItem(tr("default"), 0);
604604 n = 1;
605605
606 for (size_t i = 0; i < fileList.size(); i++)
606 for (int i = 0; i < static_cast<int>(fileList.size()); i++)
607607 {
608608 size_t suffixIdx;
609609 std::string fileName = fileList[i].toStdString();
618618 if (fileName.compare("default") == 0)
619619 continue;
620620
621 mapSel->addItem(tr(fileName.c_str()), (int)i + 1);
621 mapSel->addItem(tr(fileName.c_str()), i + 1);
622622
623623 if (mapName.compare(fileName) == 0)
624624 {
368368 int ret, useNativeFileDialogVal; //, useCustom;
369369 QString filename;
370370 std::string last, iniPath;
371 char dir[512];
372 char exePath[512];
371 std::string dir;
372 const char *exePath = nullptr;
373373 QFileDialog dialog(this, tr("Open Qt Stylesheet (QSS)"));
374374 QList<QUrl> urls;
375375 QDir d;
376376
377 fceuExecutablePath(exePath, sizeof(exePath));
377 exePath = fceuExecutablePath();
378378
379379 //urls = dialog.sidebarUrls();
380380 urls << QUrl::fromLocalFile(QDir::rootPath());
420420
421421 getDirFromFile(last.c_str(), dir);
422422
423 dialog.setDirectory(tr(dir));
423 dialog.setDirectory(tr(dir.c_str()));
424424
425425 // Check config option to use native file dialog or not
426426 g_config->getOption("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
472472 int ret, useNativeFileDialogVal; //, useCustom;
473473 QString filename;
474474 std::string last, iniPath;
475 char dir[512];
476 char exePath[512];
475 std::string dir;
476 const char *exePath = nullptr;
477477 QFileDialog dialog(this, tr("Open Qt QPalette File (QPAL)"));
478478 QList<QUrl> urls;
479479 QDir d;
480480
481 fceuExecutablePath(exePath, sizeof(exePath));
481 exePath = fceuExecutablePath();
482482
483483 //urls = dialog.sidebarUrls();
484484 urls << QUrl::fromLocalFile(QDir::rootPath());
524524
525525 getDirFromFile(last.c_str(), dir);
526526
527 dialog.setDirectory(tr(dir));
527 dialog.setDirectory(tr(dir.c_str()));
528528
529529 // Check config option to use native file dialog or not
530530 g_config->getOption("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
752752
753753 if ( rccFilePath.size() == 0 )
754754 {
755 char dir[1024], rccBase[256], tmpFile[2048];
756
757 parseFilepath( s.c_str(), dir, rccBase, NULL );
758
759 sprintf( tmpFile, "%s%s.rcc", dir, rccBase );
760
761 //printf("RCC: '%s%s'\n", dir, rccBase );
762
763 if ( QResource::registerResource( tmpFile ) )
755 std::string dir, rccBase, tmpFile;
756
757 parseFilepath( s.c_str(), &dir, &rccBase, nullptr );
758
759 tmpFile.assign(dir);
760 tmpFile.append(rccBase);
761 tmpFile.append(".rcc");
762
763 //printf("RCC: '%s%s'\n", dir.c_str(), rccBase.c_str() );
764
765 if ( QResource::registerResource( tmpFile.c_str() ) )
764766 {
765767 //printf("Loaded RCC File: '%s'\n", tmpFile );
766768 rccFilePath.assign( tmpFile );
11751177 int ret, useNativeFileDialogVal; //, useCustom;
11761178 QString filename;
11771179 std::string last, iniPath;
1178 char dir[512];
1179 char exePath[512];
1180 std::string dir;
1181 const char *exePath = nullptr;
11801182 QFileDialog dialog(this, tr("Save QPalette (qpal)"));
11811183 QList<QUrl> urls;
11821184 QDir d;
11831185 QPalette pal = this->palette();
11841186
1185 fceuExecutablePath(exePath, sizeof(exePath));
1187 exePath = fceuExecutablePath();
11861188
11871189 //urls = dialog.sidebarUrls();
11881190 urls << QUrl::fromLocalFile(QDir::rootPath());
12291231
12301232 getDirFromFile(last.c_str(), dir);
12311233
1232 dialog.setDirectory(tr(dir));
1234 dialog.setDirectory(tr(dir.c_str()));
12331235
12341236 // Check config option to use native file dialog or not
12351237 g_config->getOption("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
16101612 grid->addWidget( lbl, 2, 0 );
16111613
16121614 lbl = new QLabel();
1613 lbl->setText("<a href=\"http://fceux.com\">Website Link</a>");
1615 lbl->setText("<a href=\"https://fceux.com\">Website Link</a>");
16141616 lbl->setTextInteractionFlags(Qt::TextBrowserInteraction);
16151617 lbl->setOpenExternalLinks(false);
16161618 grid->addWidget( lbl, 2, 1 );
148148 int ret, useNativeFileDialogVal;
149149 QString filename;
150150 std::string last;
151 char dir[512];
151 std::string dir;
152152 QFileDialog dialog(this, tr("Open Help File") );
153153 QList<QUrl> urls;
154154 //QDir d;
176176 {
177177 getDirFromFile( last.c_str(), dir );
178178
179 dialog.setDirectory( tr(dir) );
179 dialog.setDirectory( tr(dir.c_str()) );
180180 }
181181 else
182182 {
321321 //----------------------------------------------------------------------------
322322 static int writeMem( int mode, unsigned int addr, int value )
323323 {
324 bool updateDebugger = false;
325
324326 value = value & 0x000000ff;
325327
326328 switch ( mode )
338340 {
339341 wfunc ((uint32) addr,
340342 (uint8) (value & 0x000000ff));
343
344 updateDebugger = true;
341345 }
342346 }
343347 else
373377 {
374378 if (addr < 16)
375379 {
376 fprintf( stdout, "You can't edit ROM header here, however you can use iNES Header Editor to edit the header if it's an iNES format file.");
380 fprintf( stdout, "You can't edit ROM header here, however you can use NES Header Editor to edit the header if it's an iNES or NES2.0 format file.");
377381 }
378382 else if ( (addr >= 16) && (addr < PRGsize[0]+16) )
379383 {
383387 {
384388 *(uint8 *)(GetNesCHRPointer(addr-16-PRGsize[0])) = value;
385389 }
390 updateDebugger = true;
386391 }
387392 break;
388393 }
389394
390395 hexEditorRequestUpdateAll();
391396
392 return 0;
397 if ( updateDebugger )
398 {
399 if (debuggerWindowIsOpen())
400 {
401 updateAllDebuggerWindows();
402 }
403 }
404
405 return 0;
393406 }
394407 //----------------------------------------------------------------------------
395408
396409 static int convToXchar( int i )
397410 {
398 int c = 0;
411 int c = 0;
399412
400413 if ( (i >= 0) && (i < 10) )
401414 {
402 c = i + '0';
415 c = i + '0';
403416 }
404417 else if ( i < 16 )
405418 {
719732 return -1;
720733 }
721734
722 for (int i=0; i<v.size(); i++)
735 for (size_t i=0; i<v.size(); i++)
723736 {
724737 fprintf( fp, "%s:%08X:%s\n",
725738 memViewNames[ v[i]->mode ], v[i]->addr, v[i]->desc );
24412454 return -1;
24422455 }
24432456 match = 1;
2444 for (int i=0; i<varray.size(); i++)
2445 {
2446 if ( (addr+i) >= mb.size() )
2457 for (size_t i=0; i<varray.size(); i++)
2458 {
2459 if ( (addr+i) >= static_cast<size_t>(mb.size()) )
24472460 {
24482461 match = 0; break;
24492462 }
32423255 }
32433256 }
32443257 //----------------------------------------------------------------------------
3245 static int RamFreezeCB(char *name, uint32 a, uint8 v, int compare,int s,int type, void *data)
3258 static int RamFreezeCB(const char *name, uint32 a, uint8 v, int compare,int s,int type, void *data)
32463259 {
32473260 return ((QHexEdit*)data)->FreezeRam( name, a, v, compare, s, type );
32483261 }
32593272 // printf("$%04X:%02X %i: %s\n", a, v, s, name );
32603273 //}
32613274
3262 if ( a == frzRamAddr )
3275 if ( a == static_cast<uint32_t>(frzRamAddr) )
32633276 {
32643277 switch ( frzRamMode )
32653278 {
42044217
42054218 win->show();
42064219 }
4220 else
4221 {
4222 win->activateWindow();
4223 win->raise();
4224 win->setFocus();
4225 }
42074226
42084227 win->editor->setMode( mode );
42094228 win->editor->setAddr( addr );
527527
528528 if (romFile != NULL)
529529 {
530 char dirStr[256], base[256];
531
532 parseFilepath(romFile, dirStr, base);
533
534 strcat(base, ".pre");
535
536 dialog.selectFile(tr(base));
530 std::string base;
531
532 parseFilepath(romFile, nullptr, &base);
533
534 base.append(".pre");
535
536 dialog.selectFile(tr(base.c_str()));
537537 }
538538
539539 dialog.setDirectory(tr(path.c_str()));
278278 int ret, useNativeFileDialogVal;
279279 QString filename;
280280 std::string last;
281 char dir[2048];
282 char exePath[2048];
283 const char *luaPath;
281 std::string dir;
282 const char *exePath = nullptr;
283 const char *luaPath = nullptr;
284284 QFileDialog dialog(this, tr("Open LUA Script"));
285285 QList<QUrl> urls;
286286 QDir d;
287287
288 fceuExecutablePath(exePath, sizeof(exePath));
288 exePath = fceuExecutablePath();
289289
290290 //urls = dialog.sidebarUrls();
291291 urls << QUrl::fromLocalFile(QDir::rootPath());
380380
381381 getDirFromFile(last.c_str(), dir);
382382
383 dialog.setDirectory(tr(dir));
383 dialog.setDirectory(tr(dir.c_str()));
384384
385385 // Check config option to use native file dialog or not
386386 g_config->getOption("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
505505 updateLuaDisplay = true;
506506 }
507507 //----------------------------------------------------
508 #ifdef WIN32
509 int LuaPrintfToWindowConsole(_In_z_ _Printf_format_string_ const char *format, ...)
510 #else
511 int LuaPrintfToWindowConsole(const char *__restrict format, ...) throw()
512 #endif
508 int LuaPrintfToWindowConsole( __FCEU_PRINTF_FORMAT const char * format, ...)
513509 {
514510 int retval;
515511 va_list args;
5353 };
5454
5555 // Formatted print
56 #ifdef WIN32
57 int LuaPrintfToWindowConsole(_In_z_ _Printf_format_string_ const char *format, ...);
58 #elif __linux__
59 #ifdef __THROWNL
60 int LuaPrintfToWindowConsole(const char *__restrict format, ...)
61 __THROWNL __attribute__((__format__(__printf__, 1, 2)));
62 #else
63 int LuaPrintfToWindowConsole(const char *__restrict format, ...) throw() __attribute__((__format__(__printf__, 1, 2)));
64 #endif
65 #else
66 int LuaPrintfToWindowConsole(const char *__restrict format, ...) throw();
67 #endif
56 int LuaPrintfToWindowConsole( __FCEU_PRINTF_FORMAT const char *format, ...) __FCEU_PRINTF_ATTRIBUTE( 1, 2 );
6857
6958 void PrintToWindowConsole(intptr_t hDlgAsInt, const char *str);
7059
4949 QVBoxLayout *vbox1, *vbox2;
5050 QPushButton *closeButton;
5151 std::vector <std::string> aviDriverList;
52 int aviDriver;
52 int aviDriver=0;
5353
5454 setWindowTitle("Movie Options");
5555
145145 break;
146146 }
147147
148 if ( i == aviDriver )
148 if ( i == static_cast<size_t>(aviDriver) )
149149 {
150150 aviBackend->setCurrentIndex(i);
151151 aviPageStack->setCurrentIndex(i);
6464 movSelBox = new QComboBox();
6565 movBrowseBtn = new QPushButton(tr("Browse"));
6666
67 movSelBox->setMaximumWidth(512);
68
6769 hbox->addWidget(lbl, 1);
6870 hbox->addWidget(movSelBox, 100);
6971 hbox->addWidget(movBrowseBtn, 1);
415417 std::string path, last;
416418 const char *romFile;
417419 const char *baseDir = FCEUI_GetBaseDirectory();
420 std::string lastDir;
418421 char md5[256];
419 char dir[512], base[256];
420422
421423 md5[0] = 0;
422424
433435
434436 if (romFile != NULL)
435437 {
436 parseFilepath(romFile, dir, base);
437
438 path = std::string(dir);
438 std::string dir;
439
440 parseFilepath(romFile, &dir);
441
442 path = dir;
439443
440444 scanDirectory(path.c_str(), md5);
441445 }
442446
443447 g_config->getOption("SDL.LastOpenMovie", &last);
444448
445 getDirFromFile(last.c_str(), dir);
446
447 scanDirectory(dir, md5);
449 getDirFromFile(last.c_str(), lastDir);
450
451 scanDirectory(lastDir.c_str(), md5);
448452 }
449453 //----------------------------------------------------------------------------
450454 void MoviePlayDialog_t::playMovie(void)
494498 int ret, useNativeFileDialogVal;
495499 QString filename;
496500 std::string last;
497 char dir[512];
501 std::string dir;
498502 char md5Match = 0;
499503 QFileDialog dialog(this, tr("Open FM2 Movie"));
500504
510514
511515 getDirFromFile(last.c_str(), dir);
512516
513 dialog.setDirectory(tr(dir));
517 dialog.setDirectory(tr(dir.c_str()));
514518
515519 // Check config option to use native file dialog or not
516520 g_config->getOption("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
178178 int ret, useNativeFileDialogVal;
179179 QString filename;
180180 std::string last;
181 char dir[512];
181 std::string dir;
182182 const char *base;
183183 QFileDialog dialog(this, tr("Load State From File") );
184184 QList<QUrl> urls;
223223
224224 getDirFromFile( last.c_str(), dir );
225225
226 dialog.setDirectory( tr(dir) );
226 dialog.setDirectory( tr(dir.c_str()) );
227227
228228 // Check config option to use native file dialog or not
229229 g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
315315 int ret, useNativeFileDialogVal;
316316 QString filename;
317317 std::string last;
318 char dir[512];
318 std::string dir;
319319 QFileDialog dialog(this, tr("Save FM2 Movie for Recording") );
320320
321321 dialog.setFileMode(QFileDialog::AnyFile);
331331
332332 getDirFromFile( last.c_str(), dir );
333333
334 dialog.setDirectory( tr(dir) );
334 dialog.setDirectory( tr(dir.c_str()) );
335335
336336 // Check config option to use native file dialog or not
337337 g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
493493 int ret, useNativeFileDialogVal;
494494 QString filename;
495495 std::string last, iniPath;
496 char dir[512];
497 char exePath[512];
496 std::string dir;
497 const char *exePath = nullptr;
498498 QFileDialog dialog(this, tr("Open NES Palette"));
499499 QList<QUrl> urls;
500500 QDir d;
501501
502 fceuExecutablePath(exePath, sizeof(exePath));
502 exePath = fceuExecutablePath();
503503
504504 //urls = dialog.sidebarUrls();
505505 urls << QUrl::fromLocalFile(QDir::rootPath());
576576
577577 getDirFromFile(last.c_str(), dir);
578578
579 dialog.setDirectory(tr(dir));
579 dialog.setDirectory(tr(dir.c_str()));
580580
581581 // Check config option to use native file dialog or not
582582 g_config->getOption("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
313313 {
314314 int ret, useNativeFileDialogVal;
315315 QString filename;
316 char dir[512];
317 char exePath[512];
316 std::string dir;
317 const char *exePath = nullptr;
318318 std::string last, iniPath;
319319 QFileDialog dialog(this, tr("Open Palette From File") );
320320 QList<QUrl> urls;
321321 QDir d;
322322
323 fceuExecutablePath( exePath, sizeof(exePath) );
323 exePath = fceuExecutablePath();
324324
325325 //urls = dialog.sidebarUrls();
326326 urls << QUrl::fromLocalFile( QDir::rootPath() );
402402 }
403403 getDirFromFile( last.c_str(), dir );
404404
405 dialog.setDirectory( tr(dir) );
405 dialog.setDirectory( tr(dir.c_str()) );
406406
407407 // Check config option to use native file dialog or not
408408 g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
17771777 selAddr = -1;
17781778 selLine++;
17791779
1780 if (selLine >= actvSrchList.size())
1780 if ( static_cast<size_t>(selLine) >= actvSrchList.size())
17811781 {
17821782 selLine = actvSrchList.size() - 1;
17831783 }
543543
544544 if ( romFile != NULL )
545545 {
546 char dir[512], base[256];
547
548 parseFilepath( romFile, dir, base );
549
550 strcat( base, ".wch");
551
552 dialog.setDirectory( tr(dir) );
553
554 dialog.selectFile( tr(base) );
546 std::string dir, base;
547
548 parseFilepath( romFile, &dir, &base );
549
550 base.append(".wch");
551
552 dialog.setDirectory( tr(dir.c_str()) );
553
554 dialog.selectFile( tr(base.c_str()) );
555555 }
556556
557557 // Check config option to use native file dialog or not
603603
604604 if ( romFile != NULL )
605605 {
606 char dir[512], base[256];
607
608 parseFilepath( romFile, dir, base );
609
610 strcat( base, ".wch");
611
612 dialog.setDirectory( tr(dir) );
613
614 dialog.selectFile( tr(base) );
606 std::string dir, base;
607
608 parseFilepath( romFile, &dir, &base );
609
610 base.append(".wch");
611
612 dialog.setDirectory( tr(dir.c_str()) );
613
614 dialog.selectFile( tr(base.c_str()) );
615615 }
616616
617617 // Check config option to use native file dialog or not
650650
651651 if ( saveFileName.size() > 0 )
652652 {
653 char file[512];
654
655 strcpy( file, saveFileName.c_str() );
656
657 saveWatchFile( file );
653 saveWatchFile( saveFileName.c_str() );
658654 }
659655 else
660656 {
686682
687683 if ( romFile != NULL )
688684 {
689 char dir[512], base[256];
690
691 parseFilepath( romFile, dir, base );
692
693 strcat( base, ".wch");
694
695 dialog.setDirectory( tr(dir) );
696
697 dialog.selectFile( tr(base) );
685 std::string dir, base;
686
687 parseFilepath( romFile, &dir, &base );
688
689 base.append(".wch");
690
691 dialog.setDirectory( tr(dir.c_str()) );
692
693 dialog.selectFile( tr(base.c_str()) );
698694 }
699695
700696 // Check config option to use native file dialog or not
844840 okButton->setDefault(true);
845841
846842 connect( okButton, SIGNAL(clicked(void)), &dialog, SLOT(accept(void)) );
847 connect( cancelButton, SIGNAL(clicked(void)), &dialog, SLOT(reject(void)) );
843 connect( cancelButton, SIGNAL(clicked(void)), &dialog, SLOT(reject(void)) );
848844
849845 if ( rw != NULL )
850846 {
874870 }
875871 else
876872 {
877 signedTypeBtn->setChecked( rw->type == 's' );
878 unsignedTypeBtn->setChecked( rw->type != 's' );
873 signedTypeBtn->setChecked( rw->type == 's' );
874 unsignedTypeBtn->setChecked( rw->type != 's' );
879875 dataSize1Btn->setChecked( rw->size == 1 );
880876 dataSize2Btn->setChecked( rw->size == 2 );
881877 dataSize4Btn->setChecked( rw->size == 4 );
883879 }
884880 else
885881 {
886 signedTypeBtn->setChecked( true );
887 unsignedTypeBtn->setChecked( false );
882 signedTypeBtn->setChecked( true );
883 unsignedTypeBtn->setChecked( false );
888884 dataSize1Btn->setChecked( true );
889885 dataSize2Btn->setChecked( false );
890886 dataSize4Btn->setChecked( false );
914910 if ( (rw == NULL) || mode )
915911 {
916912 ramWatchList.add_entry( notesEntry->text().toStdString().c_str(),
917 addr, unsignedTypeBtn->isChecked(), size, isSep);
913 addr, unsignedTypeBtn->isChecked() ? 'u' : 's', size, isSep);
918914 }
919915 else
920916 {
3434 #include "Qt/fceuWrapper.h"
3535 #include "Qt/SymbolicDebug.h"
3636 #include "Qt/ConsoleUtilities.h"
37
38 debugSymbolTable_t debugSymbolTable;
39
40 //--------------------------------------------------------------
41 // debugSymbolPage_t
42 //--------------------------------------------------------------
43 debugSymbolPage_t::debugSymbolPage_t(void)
44 {
45 pageNum = -1;
46
47 }
48 //--------------------------------------------------------------
49 debugSymbolPage_t::~debugSymbolPage_t(void)
50 {
51 std::map <int, debugSymbol_t*>::iterator it;
52
53 for (it=symMap.begin(); it!=symMap.end(); it++)
54 {
55 delete it->second;
56 }
57 symMap.clear();
58 }
59 //--------------------------------------------------------------
60 int debugSymbolPage_t::addSymbol( debugSymbol_t*sym )
61 {
62 std::map <int, debugSymbol_t*>::iterator it;
63
64 it = symMap.find( sym->ofs );
65
66 if ( it != symMap.end() )
67 {
68 return -1;
69 }
70 symMap[ sym->ofs ] = sym;
71
72 return 0;
73 }
74 //--------------------------------------------------------------
75 debugSymbol_t *debugSymbolPage_t::getSymbolAtOffset( int ofs )
76 {
77 debugSymbol_t*sym = NULL;
78 std::map <int, debugSymbol_t*>::iterator it;
79
80 it = symMap.find( ofs );
81
82 if ( it != symMap.end() )
83 {
84 sym = it->second;
85 }
86 return sym;
87 }
88 //--------------------------------------------------------------
89 int debugSymbolPage_t::deleteSymbolAtOffset( int ofs )
90 {
91 debugSymbol_t*sym = NULL;
92 std::map <int, debugSymbol_t*>::iterator it;
93
94 it = symMap.find( ofs );
95
96 if ( it != symMap.end() )
97 {
98 sym = it->second;
99 symMap.erase(it);
100 }
101 else
102 {
103 return -1;
104 }
105 if ( sym != NULL )
106 {
107 delete sym;
108 }
109 return 0;
110 }
111 //--------------------------------------------------------------
112 int debugSymbolPage_t::save(void)
113 {
114 FILE *fp;
115 debugSymbol_t *sym;
116 std::map <int, debugSymbol_t*>::iterator it;
117 const char *romFile;
118 char stmp[512];
119 int i,j;
120
121 if ( symMap.size() == 0 )
122 {
123 //printf("Skipping Empty Debug Page Save\n");
124 return 0;
125 }
126 if ( pageNum == -2 )
127 {
128 //printf("Skipping Register Debug Page Save\n");
129 return 0;
130 }
131
132 romFile = getRomFile();
133
134 if ( romFile == NULL )
135 {
136 return -1;
137 }
138 i=0;
139 while ( romFile[i] != 0 )
140 {
141
142 if ( romFile[i] == '|' )
143 {
144 stmp[i] = '.';
145 }
146 else
147 {
148 stmp[i] = romFile[i];
149 }
150 i++;
151 }
152 stmp[i] = 0;
153
154 if ( pageNum < 0 )
155 {
156 strcat( stmp, ".ram.nl" );
157 }
158 else
159 {
160 char suffix[32];
161
162 sprintf( suffix, ".%X.nl", pageNum );
163
164 strcat( stmp, suffix );
165 }
166
167 fp = fopen( stmp, "w" );
168
169 if ( fp == NULL )
170 {
171 printf("Error: Could not open file '%s' for writing\n", stmp );
172 return -1;
173 }
174
175 for (it=symMap.begin(); it!=symMap.end(); it++)
176 {
177 const char *c;
178
179 sym = it->second;
180
181 i=0; j=0; c = sym->comment.c_str();
182
183 while ( c[i] != 0 )
184 {
185 if ( c[i] == '\n' )
186 {
187 i++; break;
188 }
189 else
190 {
191 stmp[j] = c[i]; j++; i++;
192 }
193 }
194 stmp[j] = 0;
195
196 fprintf( fp, "$%04X#%s#%s\n", sym->ofs, sym->name.c_str(), stmp );
197
198 j=0;
199 while ( c[i] != 0 )
200 {
201 if ( c[i] == '\n' )
202 {
203 i++; stmp[j] = 0;
204
205 if ( j > 0 )
206 {
207 fprintf( fp, "\\%s\n", stmp );
208 }
209 j=0;
210 }
211 else
212 {
213 stmp[j] = c[i]; j++; i++;
214 }
215 }
216 }
217
218 fclose(fp);
219
220 return 0;
221 }
222 //--------------------------------------------------------------
223 void debugSymbolPage_t::print(void)
224 {
225 FILE *fp;
226 debugSymbol_t *sym;
227 std::map <int, debugSymbol_t*>::iterator it;
228
229 fp = stdout;
230
231 fprintf( fp, "Page: %X \n", pageNum );
232
233 for (it=symMap.begin(); it!=symMap.end(); it++)
234 {
235 sym = it->second;
236
237 fprintf( fp, " Sym: $%04X '%s' \n", sym->ofs, sym->name.c_str() );
238 }
239 }
240 //--------------------------------------------------------------
241 // debugSymbolTable_t
242 //--------------------------------------------------------------
243 debugSymbolTable_t::debugSymbolTable_t(void)
244 {
245
246 }
247 //--------------------------------------------------------------
248 debugSymbolTable_t::~debugSymbolTable_t(void)
249 {
250 this->clear();
251 }
252 //--------------------------------------------------------------
253 void debugSymbolTable_t::clear(void)
254 {
255 std::map <int, debugSymbolPage_t*>::iterator it;
256
257 for (it=pageMap.begin(); it!=pageMap.end(); it++)
258 {
259 delete it->second;
260 }
261 pageMap.clear();
262 }
263 //--------------------------------------------------------------
264 int generateNLFilenameForAddress(int address, char *NLfilename)
265 {
266 int bank;
267
268 if (address < 0x8000)
269 {
270 bank = -1;
271 }
272 else
273 {
274 bank = getBank(address);
275 #ifdef DW3_NL_0F_1F_HACK
276 if(bank == 0x0F)
277 bank = 0x1F;
278 #endif
279 }
280 return generateNLFilenameForBank( bank, NLfilename );
281 }
282 //--------------------------------------------------------------
283 int generateNLFilenameForBank(int bank, char *NLfilename)
284 {
285 int i;
286 const char *romFile;
287
288 romFile = getRomFile();
289
290 if ( romFile == NULL )
291 {
292 return -1;
293 }
294 i=0;
295 while ( romFile[i] != 0 )
296 {
297
298 if ( romFile[i] == '|' )
299 {
300 NLfilename[i] = '.';
301 }
302 else
303 {
304 NLfilename[i] = romFile[i];
305 }
306 i++;
307 }
308 NLfilename[i] = 0;
309
310 if (bank < 0)
311 {
312 // The NL file for the RAM addresses has the name nesrom.nes.ram.nl
313 strcat(NLfilename, ".ram.nl");
314 }
315 else
316 {
317 char stmp[64];
318 #ifdef DW3_NL_0F_1F_HACK
319 if(bank == 0x0F)
320 bank = 0x1F;
321 #endif
322 sprintf( stmp, ".%X.nl", bank);
323 strcat(NLfilename, stmp );
324 }
325 return 0;
326 }
327 //--------------------------------------------------------------
328 int debugSymbolTable_t::loadFileNL( int bank )
329 {
330 FILE *fp;
331 int i, j, ofs, lineNum = 0, literal = 0, array = 0;
332 char fileName[512], line[512];
333 char stmp[512];
334 debugSymbolPage_t *page = NULL;
335 debugSymbol_t *sym = NULL;
336
337 //printf("Looking to Load Debug Bank: $%X \n", bank );
338
339 if ( generateNLFilenameForBank( bank, fileName ) )
340 {
341 return -1;
342 }
343 //printf("Loading NL File: %s\n", fileName );
344
345 fp = ::fopen( fileName, "r" );
346
347 if ( fp == NULL )
348 {
349 return -1;
350 }
351 page = new debugSymbolPage_t;
352
353 page->pageNum = bank;
354
355 pageMap[ page->pageNum ] = page;
356
357 while ( fgets( line, sizeof(line), fp ) != 0 )
358 {
359 i=0; lineNum++;
360 //printf("%4i:%s", lineNum, line );
361
362 if ( line[i] == '\\' )
363 {
364 // Line is a comment continuation line.
365 i++;
366
367 j=0;
368 stmp[j] = '\n'; j++;
369
370 while ( line[i] != 0 )
371 {
372 stmp[j] = line[i]; j++; i++;
373 }
374 stmp[j] = 0;
375
376 j--;
377 while ( j >= 0 )
378 {
379 if ( isspace( stmp[j] ) )
380 {
381 stmp[j] = 0;
382 }
383 else
384 {
385 break;
386 }
387 j--;
388 }
389 if ( sym != NULL )
390 {
391 sym->comment.append( stmp );
392 }
393 }
394 else if ( line[i] == '$' )
395 {
396 // Line is a new debug offset
397 array = 0;
398
399 j=0; i++;
400 if ( !isxdigit( line[i] ) )
401 {
402 printf("Error: Invalid Offset on Line %i of File %s\n", lineNum, fileName );
403 }
404 while ( isxdigit( line[i] ) )
405 {
406 stmp[j] = line[i]; i++; j++;
407 }
408 stmp[j] = 0;
409
410 ofs = strtol( stmp, NULL, 16 );
411
412 if ( line[i] == '/' )
413 {
414 j=0; i++;
415 while ( isxdigit( line[i] ) )
416 {
417 stmp[j] = line[i]; i++; j++;
418 }
419 stmp[j] = 0;
420
421 array = strtol( stmp, NULL, 16 );
422 }
423
424 if ( line[i] != '#' )
425 {
426 printf("Error: Missing field delimiter following offset $%X on Line %i of File %s\n", ofs, lineNum, fileName );
427 continue;
428 }
429 i++;
430
431 while ( isspace(line[i]) ) i++;
432
433 j = 0;
434 while ( line[i] != 0 )
435 {
436 if ( line[i] == '\\' )
437 {
438 if ( literal )
439 {
440 switch ( line[i] )
441 {
442 case 'r':
443 stmp[j] = '\r';
444 break;
445 case 'n':
446 stmp[j] = '\n';
447 break;
448 case 't':
449 stmp[j] = '\t';
450 break;
451 default:
452 stmp[j] = line[i];
453 break;
454 }
455 j++; i++;
456 literal = 0;
457 }
458 else
459 {
460 i++;
461 literal = !literal;
462 }
463 }
464 else if ( line[i] == '#' )
465 {
466 break;
467 }
468 else
469 {
470 stmp[j] = line[i]; j++; i++;
471 }
472 }
473 stmp[j] = 0;
474
475 j--;
476 while ( j >= 0 )
477 {
478 if ( isspace( stmp[j] ) )
479 {
480 stmp[j] = 0;
481 }
482 else
483 {
484 break;
485 }
486 j--;
487 }
488
489 if ( line[i] != '#' )
490 {
491 printf("Error: Missing field delimiter following name '%s' on Line %i of File %s\n", stmp, lineNum, fileName );
492 continue;
493 }
494 i++;
495
496 sym = new debugSymbol_t();
497
498 if ( sym == NULL )
499 {
500 printf("Error: Failed to allocate memory for offset $%04X Name '%s' on Line %i of File %s\n", ofs, stmp, lineNum, fileName );
501 continue;
502 }
503 sym->ofs = ofs;
504 sym->name.assign( stmp );
505
506 while ( isspace( line[i] ) ) i++;
507
508 j=0;
509 while ( line[i] != 0 )
510 {
511 stmp[j] = line[i]; j++; i++;
512 }
513 stmp[j] = 0;
514
515 j--;
516 while ( j >= 0 )
517 {
518 if ( isspace( stmp[j] ) )
519 {
520 stmp[j] = 0;
521 }
522 else
523 {
524 break;
525 }
526 j--;
527 }
528
529 sym->comment.assign( stmp );
530
531 if ( array > 0 )
532 {
533 debugSymbol_t *arraySym = NULL;
534
535 for (j=0; j<array; j++)
536 {
537 arraySym = new debugSymbol_t();
538
539 if ( arraySym )
540 {
541 arraySym->ofs = sym->ofs + j;
542
543 sprintf( stmp, "[%i]", j );
544 arraySym->name.assign( sym->name );
545 arraySym->name.append( stmp );
546 arraySym->comment.assign( sym->comment );
547
548 if ( page->addSymbol( arraySym ) )
549 {
550 printf("Error: Failed to add symbol for offset $%04X Name '%s' on Line %i of File %s\n", ofs, arraySym->name.c_str(), lineNum, fileName );
551 delete arraySym; arraySym = NULL; // Failed to add symbol
552 }
553 }
554 }
555 delete sym; sym = NULL; // Delete temporary symbol
556 }
557 else
558 {
559 if ( page->addSymbol( sym ) )
560 {
561 printf("Error: Failed to add symbol for offset $%04X Name '%s' on Line %i of File %s\n", ofs, sym->name.c_str(), lineNum, fileName );
562 delete sym; sym = NULL; // Failed to add symbol
563 }
564 }
565 }
566 }
567
568 ::fclose(fp);
569
570 return 0;
571 }
572 //--------------------------------------------------------------
573 int debugSymbolTable_t::loadRegisterMap(void)
574 {
575 debugSymbolPage_t *page;
576
577 page = new debugSymbolPage_t();
578
579 page->pageNum = -2;
580
581 page->addSymbol( new debugSymbol_t( 0x2000, "PPU_CTRL" ) );
582 page->addSymbol( new debugSymbol_t( 0x2001, "PPU_MASK" ) );
583 page->addSymbol( new debugSymbol_t( 0x2002, "PPU_STATUS" ) );
584 page->addSymbol( new debugSymbol_t( 0x2003, "PPU_OAM_ADDR" ) );
585 page->addSymbol( new debugSymbol_t( 0x2004, "PPU_OAM_DATA" ) );
586 page->addSymbol( new debugSymbol_t( 0x2005, "PPU_SCROLL" ) );
587 page->addSymbol( new debugSymbol_t( 0x2006, "PPU_ADDRESS" ) );
588 page->addSymbol( new debugSymbol_t( 0x2007, "PPU_DATA" ) );
589 page->addSymbol( new debugSymbol_t( 0x4000, "SQ1_VOL" ) );
590 page->addSymbol( new debugSymbol_t( 0x4001, "SQ1_SWEEP" ) );
591 page->addSymbol( new debugSymbol_t( 0x4002, "SQ1_LO" ) );
592 page->addSymbol( new debugSymbol_t( 0x4003, "SQ1_HI" ) );
593 page->addSymbol( new debugSymbol_t( 0x4004, "SQ2_VOL" ) );
594 page->addSymbol( new debugSymbol_t( 0x4005, "SQ2_SWEEP" ) );
595 page->addSymbol( new debugSymbol_t( 0x4006, "SQ2_LO" ) );
596 page->addSymbol( new debugSymbol_t( 0x4007, "SQ2_HI" ) );
597 page->addSymbol( new debugSymbol_t( 0x4008, "TRI_LINEAR" ) );
598 // page->addSymbol( new debugSymbol_t( 0x4009, "UNUSED" ) );
599 page->addSymbol( new debugSymbol_t( 0x400A, "TRI_LO" ) );
600 page->addSymbol( new debugSymbol_t( 0x400B, "TRI_HI" ) );
601 page->addSymbol( new debugSymbol_t( 0x400C, "NOISE_VOL" ) );
602 // page->addSymbol( new debugSymbol_t( 0x400D, "UNUSED" ) );
603 page->addSymbol( new debugSymbol_t( 0x400E, "NOISE_LO" ) );
604 page->addSymbol( new debugSymbol_t( 0x400F, "NOISE_HI" ) );
605 page->addSymbol( new debugSymbol_t( 0x4010, "DMC_FREQ" ) );
606 page->addSymbol( new debugSymbol_t( 0x4011, "DMC_RAW" ) );
607 page->addSymbol( new debugSymbol_t( 0x4012, "DMC_START" ) );
608 page->addSymbol( new debugSymbol_t( 0x4013, "DMC_LEN" ) );
609 page->addSymbol( new debugSymbol_t( 0x4014, "OAM_DMA" ) );
610 page->addSymbol( new debugSymbol_t( 0x4015, "APU_STATUS" ) );
611 page->addSymbol( new debugSymbol_t( 0x4016, "JOY1" ) );
612 page->addSymbol( new debugSymbol_t( 0x4017, "JOY2_FRAME" ) );
613
614 pageMap[ page->pageNum ] = page;
615
616 return 0;
617 }
618 //--------------------------------------------------------------
619 int debugSymbolTable_t::loadGameSymbols(void)
620 {
621 int nPages, pageSize, romSize = 0x10000;
622
623 this->save();
624 this->clear();
625
626 if ( GameInfo != NULL )
627 {
628 romSize = 16 + CHRsize[0] + PRGsize[0];
629 }
630
631 loadFileNL( -1 );
632
633 loadRegisterMap();
634
635 pageSize = (1<<debuggerPageSize);
636
637 //nPages = 1<<(15-debuggerPageSize);
638 nPages = romSize / pageSize;
639
640 //printf("RomSize: %i NumPages: %i \n", romSize, nPages );
641
642 for(int i=0;i<nPages;i++)
643 {
644 //printf("Loading Page Offset: $%06X\n", pageSize*i );
645
646 loadFileNL( i );
647 }
648
649 //print();
650
651 return 0;
652 }
653 //--------------------------------------------------------------
654 int debugSymbolTable_t::addSymbolAtBankOffset( int bank, int ofs, debugSymbol_t *sym )
655 {
656 debugSymbolPage_t *page;
657 std::map <int, debugSymbolPage_t*>::iterator it;
658
659 it = pageMap.find( bank );
660
661 if ( it == pageMap.end() )
662 {
663 page = new debugSymbolPage_t();
664 page->pageNum = bank;
665 pageMap[ bank ] = page;
666 }
667 else
668 {
669 page = it->second;
670 }
671 page->addSymbol( sym );
672
673 return 0;
674 }
675 //--------------------------------------------------------------
676 int debugSymbolTable_t::deleteSymbolAtBankOffset( int bank, int ofs )
677 {
678 debugSymbolPage_t *page;
679 std::map <int, debugSymbolPage_t*>::iterator it;
680
681 it = pageMap.find( bank );
682
683 if ( it == pageMap.end() )
684 {
685 return -1;
686 }
687 else
688 {
689 page = it->second;
690 }
691
692 return page->deleteSymbolAtOffset( ofs );
693 }
694 //--------------------------------------------------------------
695 debugSymbol_t *debugSymbolTable_t::getSymbolAtBankOffset( int bank, int ofs )
696 {
697 debugSymbol_t*sym = NULL;
698 std::map <int, debugSymbolPage_t*>::iterator it;
699
700 it = pageMap.find( bank );
701
702 if ( it != pageMap.end() )
703 {
704 sym = (it->second)->getSymbolAtOffset( ofs );
705 }
706 return sym;
707 }
708 //--------------------------------------------------------------
709 void debugSymbolTable_t::save(void)
710 {
711 debugSymbolPage_t *page;
712 std::map <int, debugSymbolPage_t*>::iterator it;
713
714 for (it=pageMap.begin(); it!=pageMap.end(); it++)
715 {
716 page = it->second;
717
718 page->save();
719 }
720 }
721 //--------------------------------------------------------------
722 void debugSymbolTable_t::print(void)
723 {
724 debugSymbolPage_t *page;
725 std::map <int, debugSymbolPage_t*>::iterator it;
726
727 for (it=pageMap.begin(); it!=pageMap.end(); it++)
728 {
729 page = it->second;
730
731 page->print();
732 }
733 }
37 #include "Qt/ConsoleWindow.h"
38
39
73440 //--------------------------------------------------------------
73541 debugSymbol_t *replaceSymbols( int flags, int addr, char *str )
73642 {
75662 {
75763 if ( flags & ASM_DEBUG_REPLACE )
75864 {
759 strcpy( str, sym->name.c_str() );
65 strcpy( str, sym->name().c_str() );
76066 }
76167 else
76268 {
76874 {
76975 sprintf( str, "$%04X ", addr );
77076 }
771 strcat( str, sym->name.c_str() );
77 strcat( str, sym->name().c_str() );
77278 }
77379 }
77480 else
1335641 hbox->addWidget( okButton );
1336642
1337643 connect( okButton, SIGNAL(clicked(void)), this, SLOT(accept(void)) );
1338 connect( cancelButton, SIGNAL(clicked(void)), this, SLOT(reject(void)) );
644 connect( cancelButton, SIGNAL(clicked(void)), this, SLOT(reject(void)) );
1339645
1340646 deleteBox->setEnabled( false );
1341647 okButton->setDefault(true);
1342648
1343649 if ( sym != NULL )
1344650 {
1345 nameEntry->setText( tr(sym->name.c_str()) );
1346 commentEntry->setPlainText( tr(sym->comment.c_str()) );
651 nameEntry->setText( tr(sym->name().c_str()) );
652 commentEntry->setPlainText( tr(sym->comment().c_str()) );
1347653 }
1348654
1349655 setLayout( mainLayout );
1361667 //--------------------------------------------------------------
1362668 void SymbolEditWindow::closeEvent(QCloseEvent *event)
1363669 {
1364 //printf("Symbolic Debug Close Window Event\n");
1365 done(0);
670 //printf("Symbolic Debug Close Window Event\n");
671 done(0);
1366672 deleteLater();
1367 event->accept();
673 event->accept();
1368674 }
1369675 //--------------------------------------------------------------
1370676 void SymbolEditWindow::closeWindow(void)
1371677 {
1372 //printf("Close Window\n");
1373 done(0);
678 //printf("Close Window\n");
679 done(0);
1374680 deleteLater();
1375681 }
1376682 //--------------------------------------------------------------
1414720 //--------------------------------------------------------------
1415721 void SymbolEditWindow::setAddr( int addrIn )
1416722 {
1417 char stmp[512];
723 char stmp[64];
724 std::string filename;
725 size_t size;
1418726
1419727 addr = addrIn;
1420728
1434742 }
1435743 }
1436744
1437 generateNLFilenameForAddress( addr, stmp );
1438
1439 filepath->setText( tr(stmp) );
1440 filepath->setMinimumWidth( charWidth * (filepath->text().size() + 4) );
745 generateNLFilenameForAddress( addr, filename );
746
747 filepath->setText( tr(filename.c_str()) );
748
749 size = filepath->text().size();
750
751 // Limit max size so that widget size doesn't explode on a large file path.
752 if (size > 32) size = 32;
753
754 filepath->setMinimumWidth( charWidth * (size + 4) );
1441755 }
1442756 //--------------------------------------------------------------
1443757 void SymbolEditWindow::setBank( int bankIn )
1451765
1452766 if ( sym != NULL )
1453767 {
1454 nameEntry->setText( tr(sym->name.c_str()) );
1455 commentEntry->setPlainText( tr(sym->comment.c_str()) );
768 nameEntry->setText( tr(sym->name().c_str()) );
769 commentEntry->setPlainText( tr(sym->comment().c_str()) );
1456770 deleteBox->setEnabled( true );
1457771
1458772 determineArrayStart();
1501815
1502816 if ( deleteBox->isChecked() )
1503817 {
1504 if ( sym != NULL )
818 if ( sym != nullptr )
1505819 {
1506820 debugSymbolTable.deleteSymbolAtBankOffset( b, a );
1507821 }
1508822 }
1509823 else
1510824 {
1511 if ( sym == NULL )
825 if ( sym == nullptr )
1512826 {
1513 sym = new debugSymbol_t();
1514
1515 sym->ofs = a;
1516
1517 debugSymbolTable.addSymbolAtBankOffset( b, a, sym );
1518
827 sym = new debugSymbol_t(a);
828
829 if ( debugSymbolTable.addSymbolAtBankOffset( b, a, sym ) )
830 {
831 if (consoleWindow)
832 {
833 consoleWindow->QueueErrorMsgWindow( debugSymbolTable.errorMessage() );
834 }
835 delete sym;
836 }
1519837 isNew = true;
1520838 }
1521 sym->ofs = a;
839 sym->setOffset(a);
1522840
1523841 if ( (i == 0) || isNew || arrayNameOverWrite->isChecked() )
1524842 {
1528846 {
1529847 if ( isNew || arrayCommentOverWrite->isChecked() || (i == 0) )
1530848 {
1531 sym->comment = commentEntry->toPlainText().toStdString();
849 sym->commentAssign( commentEntry->toPlainText().toStdString() );
1532850 }
1533851 }
1534852 sym->trimTrailingSpaces();
1546864 }
1547865 else if ( sym == NULL )
1548866 {
1549 sym = new debugSymbol_t();
1550 sym->ofs = addr;
1551 sym->name = nameEntry->text().toStdString();
1552 sym->comment = commentEntry->toPlainText().toStdString();
1553
1554 debugSymbolTable.addSymbolAtBankOffset( bank, addr, sym );
1555 }
1556 else
1557 {
1558 sym->name = nameEntry->text().toStdString();
1559 sym->comment = commentEntry->toPlainText().toStdString();
1560 }
1561 sym->trimTrailingSpaces();
867 sym = new debugSymbol_t( addr, nameEntry->text().toStdString().c_str(),
868 commentEntry->toPlainText().toStdString().c_str());
869
870 if ( debugSymbolTable.addSymbolAtBankOffset( bank, addr, sym ) )
871 {
872 if (consoleWindow)
873 {
874 consoleWindow->QueueErrorMsgWindow( debugSymbolTable.errorMessage() );
875 }
876 delete sym;
877 }
878 }
879 else
880 {
881 if ( sym->updateName( nameEntry->text().toStdString().c_str() ) )
882 {
883 if (consoleWindow)
884 {
885 consoleWindow->QueueErrorMsgWindow( debugSymbolTable.errorMessage() );
886 }
887 }
888 sym->commentAssign( commentEntry->toPlainText().toStdString().c_str() );
889 sym->trimTrailingSpaces();
890 }
1562891 }
1563892 debugSymbolTable.save(); // Save table to disk immediately after an add, edit, or delete
1564893 FCEU_WRAPPER_UNLOCK();
1666995 }
1667996
1668997 // Reform with base string and new index.
1669 sym->name.assign( stmp );
1670
1671 sym->trimTrailingSpaces();
1672
1673 sprintf( stmp, "[%i]", idx );
1674
1675 sym->name.append( stmp );
1676
1677 }
1678 //--------------------------------------------------------------
998 if ( sym->updateName( stmp, idx ) )
999 {
1000 if (consoleWindow)
1001 {
1002 consoleWindow->QueueErrorMsgWindow( debugSymbolTable.errorMessage() );
1003 }
1004 }
1005 }
1006 //--------------------------------------------------------------
33 #define __SYMBOLIC_DEBUG_H__
44
55 #include <string>
6 #include <list>
7 #include <map>
86
97 #include <QWidget>
108 #include <QDialog>
2321 #include <QLineEdit>
2422 #include <QPlainTextEdit>
2523
26 struct debugSymbol_t
27 {
28 int ofs;
29 std::string name;
30 std::string comment;
24 #include "../../debugsymboltable.h"
3125
32 debugSymbol_t(void)
33 {
34 ofs = 0;
35 };
36
37 debugSymbol_t( int ofs, const char *name, const char *comment = NULL )
38 {
39 this->ofs = ofs;
40 this->name.assign( name );
41
42 if ( comment )
43 {
44 this->comment.assign( comment );
45 }
46 }
47
48 void trimTrailingSpaces(void)
49 {
50 while ( name.size() > 0 )
51 {
52 if ( isspace( name.back() ) )
53 {
54 name.pop_back();
55 }
56 else
57 {
58 break;
59 }
60 }
61 while ( comment.size() > 0 )
62 {
63 if ( isspace( comment.back() ) )
64 {
65 comment.pop_back();
66 }
67 else
68 {
69 break;
70 }
71 }
72 }
73 };
74
75 struct debugSymbolPage_t
76 {
77 int pageNum;
78
79 debugSymbolPage_t(void);
80 ~debugSymbolPage_t(void);
81
82 int save(void);
83 void print(void);
84 int size(void){ return symMap.size(); }
85
86 int addSymbol( debugSymbol_t *sym );
87
88 int deleteSymbolAtOffset( int ofs );
89
90 debugSymbol_t *getSymbolAtOffset( int ofs );
91
92
93 std::map <int, debugSymbol_t*> symMap;
94 };
95
96 class debugSymbolTable_t
97 {
98
99 public:
100 debugSymbolTable_t(void);
101 ~debugSymbolTable_t(void);
102
103 int loadFileNL( int addr );
104 int loadGameSymbols(void);
105 int numPages(void){ return pageMap.size(); }
106
107 void save(void);
108 void clear(void);
109 void print(void);
110
111 debugSymbol_t *getSymbolAtBankOffset( int bank, int ofs );
112
113 int addSymbolAtBankOffset( int bank, int ofs, debugSymbol_t *sym );
114
115 int deleteSymbolAtBankOffset( int bank, int ofs );
116
117 private:
118 std::map <int, debugSymbolPage_t*> pageMap;
119
120 int loadRegisterMap(void);
121
122 };
123
124 extern debugSymbolTable_t debugSymbolTable;
12526
12627 class SymbolEditWindow : public QDialog
12728 {
17778 };
17879
17980
180 int generateNLFilenameForBank(int bank, char *NLfilename);
181 int generateNLFilenameForAddress(int address, char *NLfilename);
81 int generateNLFilenameForBank(int bank, std::string &NLfilename);
82 int generateNLFilenameForAddress(int address, std::string &NLfilename);
18283
18384 #define ASM_DEBUG_SYMS 0x0001
18485 #define ASM_DEBUG_REGS 0x0002
931931 actGroup->addAction(act);
932932 patternMenu->addAction(act);
933933
934 act->setChecked( taseditorConfig.currentPattern == i );
934 act->setChecked( static_cast<size_t>(taseditorConfig.currentPattern) == i );
935935 }
936936
937937 // Help
63876387
63886388 lineNum = lineOffset + row;
63896389
6390 if ( lineNum >= currMovieData.records.size() )
6390 if ( static_cast<size_t>(lineNum) >= currMovieData.records.size() )
63916391 {
63926392 break;
63936393 }
73047304 TasRecentProjectAction::TasRecentProjectAction(QString desc, QWidget *parent)
73057305 : QAction( desc, parent )
73067306 {
7307 QString txt;
7308 QFileInfo fi(desc);
7309
73077310 path = desc.toStdString();
7311
7312 txt = fi.fileName();
7313 txt += QString("\t");
7314 txt += desc;
7315
7316 setText( txt );
73087317 }
73097318 //----------------------------------------------------------------------------
73107319 TasRecentProjectAction::~TasRecentProjectAction(void)
358358 // returns true if couldn't load
359359 bool GREENZONE::load(EMUFILE *is, unsigned int offset)
360360 {
361 int frame = 0, prev_frame = -1, size = 0;
361 int frame = 0, prev_frame = -1;
362 unsigned int size = 0;
362363 int last_tick = -1;
363364 char save_id[GREENZONE_ID_LEN];
364365
374375 return false;
375376 }
376377 // read "GREENZONE" string
377 if ((int)is->fread(save_id, GREENZONE_ID_LEN) < GREENZONE_ID_LEN) goto error;
378 if (is->fread(save_id, GREENZONE_ID_LEN) < GREENZONE_ID_LEN) goto error;
378379 if (!strcmp(greenzone_skipsave_id, save_id))
379380 {
380381 // string says to skip loading Greenzone
418419 // read LagLog
419420 lagLog.load(is);
420421 // read size
421 if (read32le(&size, is) && size >= 0 && size <= currMovieData.getNumRecords())
422 if (read32le(&size, is) && size <= static_cast<unsigned int>(currMovieData.getNumRecords()))
422423 {
423424 greenzoneSize = size;
424425 savestates.resize(greenzoneSize);
460461 if ((int)savestates.size() <= frame)
461462 savestates.resize(frame + 1);
462463 savestates[frame].resize(size);
463 if ((int)is->fread(&savestates[frame][0], size) < size) break;
464 if (is->fread(&savestates[frame][0], size) < size) break;
464465 prev_frame = frame; // successfully read one Greenzone frame info
465466 }
466467 }
179179 inputType = tmp;
180180 // read data
181181 alreadyCompressed = true;
182 int comprlen;
182 unsigned int comprlen;
183183 uLongf destlen;
184184 // read and uncompress joysticks data
185185 destlen = size * BYTES_PER_JOYSTICK * joysticksPerFrame[inputType];
186186 joysticks.resize(destlen);
187187 // read size
188188 if (!read32le(&comprlen, is)) return true;
189 if (comprlen <= 0) return true;
189 if (comprlen == 0) return true;
190190 compressedJoysticks.resize(comprlen);
191191 if (is->fread(&compressedJoysticks[0], comprlen) != comprlen) return true;
192192 int e = uncompress(&joysticks[0], &destlen, &compressedJoysticks[0], comprlen);
211211 hotChanges.resize(destlen);
212212 // read size
213213 if (!read32le(&comprlen, is)) return true;
214 if (comprlen <= 0) return true;
214 if (comprlen == 0) return true;
215215 compressedHotChanges.resize(comprlen);
216216 if (is->fread(&compressedHotChanges[0], comprlen) != comprlen) return true;
217217 e = uncompress(&hotChanges[0], &destlen, &compressedHotChanges[0], comprlen);
221221 }
222222 bool INPUTLOG::skipLoad(EMUFILE *is)
223223 {
224 int tmp;
224 unsigned int tmp;
225225 uint8 tmp1;
226226 // skip vars
227227 if (is->fseek(sizeof(int) + // size
3232
3333 void LAGLOG::compressData(void)
3434 {
35 int len = lagLog.size() * sizeof(uint8);
35 unsigned int len = lagLog.size() * sizeof(uint8);
3636 if (len)
3737 {
3838 uLongf comprlen = (len>>9)+12 + len;
3939 compressedLagLog.resize(comprlen, LAGGED_UNKNOWN);
4040 compress(&compressedLagLog[0], &comprlen, (uint8*)&lagLog[0], len);
4141 compressedLagLog.resize(comprlen);
42 } else
42 }
43 else
4344 {
4445 // LagLog can even be empty
4546 compressedLagLog.resize(0);
5859 void LAGLOG::save(EMUFILE *os)
5960 {
6061 // write size
61 int size = lagLog.size();
62 unsigned int size = lagLog.size();
6263 write32le(size, os);
6364 if (size)
6465 {
7273 // returns true if couldn't load
7374 bool LAGLOG::load(EMUFILE *is)
7475 {
75 int size;
76 unsigned int size;
7677 if (read32le(&size, is))
7778 {
7879 alreadyCompressed = true;
8081 if (size)
8182 {
8283 // read and uncompress array
83 int comprlen;
84 unsigned int comprlen;
8485 uLongf destlen = size * sizeof(int);
8586 if (!read32le(&comprlen, is)) return true;
86 if (comprlen <= 0) return true;
87 if (comprlen == 0) return true;
8788 compressedLagLog.resize(comprlen);
8889 if (is->fread(&compressedLagLog[0], comprlen) != comprlen) return true;
8990 int e = uncompress((uint8*)&lagLog[0], &destlen, &compressedLagLog[0], comprlen);
9091 if (e != Z_OK && e != Z_BUF_ERROR) return true;
91 } else
92 }
93 else
9294 {
9395 compressedLagLog.resize(0);
9496 }
99101 }
100102 bool LAGLOG::skipLoad(EMUFILE *is)
101103 {
102 int size;
104 unsigned int size;
103105 if (read32le(&size, is))
104106 {
105107 if (size)
116118 // -------------------------------------------------------------------------------------------------
117119 void LAGLOG::invalidateFromFrame(int frame)
118120 {
119 if (frame >= 0 && frame < (int)lagLog.size())
121 if (frame >= 0 && static_cast<size_t>(frame) < lagLog.size())
120122 {
121123 lagLog.resize(frame);
122124 alreadyCompressed = false;
125127
126128 void LAGLOG::setLagInfo(int frame, bool lagFlag)
127129 {
128 if ((int)lagLog.size() <= frame)
130 if (lagLog.size() <= static_cast<size_t>(frame))
129131 lagLog.resize(frame + 1, LAGGED_UNKNOWN);
130132
131133 if (lagFlag)
137139 }
138140 void LAGLOG::eraseFrame(int frame, int numFrames)
139141 {
140 if (frame < (int)lagLog.size())
142 if ( static_cast<size_t>(frame) < lagLog.size())
141143 {
142144 if (numFrames == 1)
143145 {
144146 // erase 1 frame
145147 lagLog.erase(lagLog.begin() + frame);
146148 alreadyCompressed = false;
147 } else if (numFrames > 1)
149 }
150 else if (numFrames > 1)
148151 {
149152 // erase many frames
150 if (frame + numFrames > (int)lagLog.size())
151 numFrames = (int)lagLog.size() - frame;
153 if ( static_cast<size_t>(frame + numFrames) > lagLog.size())
154 numFrames = static_cast<int>(lagLog.size()) - frame;
152155 lagLog.erase(lagLog.begin() + frame, lagLog.begin() + (frame + numFrames));
153156 alreadyCompressed = false;
154157 }
156159 }
157160 void LAGLOG::insertFrame(int frame, bool lagFlag, int numFrames)
158161 {
159 if (frame < (int)lagLog.size())
162 if ( static_cast<size_t>(frame) < lagLog.size())
160163 {
161164 // insert
162165 lagLog.insert(lagLog.begin() + frame, numFrames, (lagFlag) ? LAGGED_YES : LAGGED_NO);
163 } else
166 }
167 else
164168 {
165169 // append
166170 lagLog.resize(frame + 1, LAGGED_UNKNOWN);
179183 }
180184 int LAGLOG::getLagInfoAtFrame(int frame)
181185 {
182 if (frame < (int)lagLog.size())
186 if (static_cast<size_t>(frame) < lagLog.size())
183187 return lagLog[frame];
184188 else
185189 return LAGGED_UNKNOWN;
2626 void MARKERS::save(EMUFILE *os)
2727 {
2828 // write size
29 int size = markersArray.size();
30 int len;
29 uint32_t size = markersArray.size();
3130 write32le(size, os);
3231 // write array
3332 if (!alreadyCompressed)
3736 // write notes
3837 size = notes.size();
3938 write32le(size, os);
40 for (int i = 0; i < size; ++i)
39 for (unsigned int i = 0; i < size; ++i)
4140 {
42 len = notes[i].length() + 1;
41 uint32_t len = notes[i].length() + 1;
4342 if (len > MAX_NOTE_LEN) len = MAX_NOTE_LEN;
4443 write32le(len, os);
4544 os->fwrite(notes[i].c_str(), len);
4847 // returns true if couldn't load
4948 bool MARKERS::load(EMUFILE *is)
5049 {
51 int size;
50 uint32_t size=0;
5251 if (read32le(&size, is))
5352 {
5453 markersArray.resize(size);
5554 // read and uncompress array
5655 alreadyCompressed = true;
57 int comprlen, len;
56 uint32_t comprlen, len;
5857 uLongf destlen = size * sizeof(int);
5958 if (!read32le(&comprlen, is)) return true;
6059 if (comprlen <= 0) return true;
6362 int e = uncompress((uint8*)&markersArray[0], &destlen, &compressedMarkersArray[0], comprlen);
6463 if (e != Z_OK && e != Z_BUF_ERROR) return true;
6564 // read notes
66 if (read32le(&size, is) && size >= 0)
65 if (read32le(&size, is))
6766 {
6867 notes.resize(size);
6968 char temp_str[MAX_NOTE_LEN];
70 for (int i = 0; i < size; ++i)
69 for (unsigned int i = 0; i < size; ++i)
7170 {
72 if (!read32le(&len, is) || len < 0) return true;
73 if ((int)is->fread(temp_str, len) < len) return true;
71 if (!read32le(&len, is) || (len > MAX_NOTE_LEN) ) return true;
72 if (is->fread(temp_str, len) < len) return true;
73 temp_str[sizeof(temp_str)-1] = 0;
7474 notes[i] = temp_str;
7575 }
7676 // all ok
8484 if (!(is->fseek(sizeof(int), SEEK_CUR)))
8585 {
8686 // read array
87 int comprlen, len;
87 uint32_t comprlen, len;
8888 if (!read32le(&comprlen, is)) return true;
8989 if (is->fseek(comprlen, SEEK_CUR) != 0) return true;
9090 // read notes
91 if (read32le(&comprlen, is) && comprlen >= 0)
91 if (read32le(&comprlen, is))
9292 {
93 for (int i = 0; i < comprlen; ++i)
93 for (unsigned int i = 0; i < comprlen; ++i)
9494 {
95 if (!read32le(&len, is) || len < 0) return true;
95 if (!read32le(&len, is) || (len > MAX_NOTE_LEN) ) return true;
9696 if (is->fseek(len, SEEK_CUR) != 0) return true;
9797 }
9898 // all ok
104104
105105 void MARKERS::compressData()
106106 {
107 int len = markersArray.size() * sizeof(int);
107 uint32_t len = markersArray.size() * sizeof(int);
108108 uLongf comprlen = (len>>9)+12 + len;
109109 compressedMarkersArray.resize(comprlen);
110110 compress(&compressedMarkersArray[0], &comprlen, (uint8*)&markersArray[0], len);
414414 void TASEDITOR_PROJECT::renameProject(const char* newFullName, bool filenameIsCorrect)
415415 {
416416 projectFile = newFullName;
417 char drv[512], dir[512], name[512], ext[512]; // For getting the filename
417 char drv[512], dir[4096], name[512], ext[512]; // For getting the filename
418418 splitpath(newFullName, drv, dir, name, ext);
419419 projectName = name;
420420 std::string thisfm2name = name;
2525 #ifdef WIN32
2626 #include <windows.h>
2727 #else
28 #include <unistd.h>
2829 #include <sys/types.h>
2930 #include <sys/stat.h>
3031 #include <fcntl.h>
110111 static int recBufNum = 0;
111112 static traceRecord_t *logBuf = NULL;
112113 static int logBufMax = 3000000;
113 static int logBufHead = 0;
114 static int logBufTail = 0;
114 // logBufHead and logBufTail are volatile because they are shared use by both the emulation and disk logger threads.
115 // Ensure that the compiler doesn't do any thread caching optimizations on them so that changes to these
116 // variables are immediately visible by the other thread.
117 static volatile int logBufHead = 0;
118 static volatile int logBufTail = 0;
115119 static bool overrunWarningArmed = true;
116120 static TraceLoggerDialog_t *traceLogWindow = NULL;
117121 static void pushMsgToLogBuffer(const char *msg);
572576
573577 if (romFile != NULL)
574578 {
575 char dir[1024];
579 std::string dir;
576580 getDirFromFile(romFile, dir);
577 dialog.setDirectory(tr(dir));
581 dialog.setDirectory(tr(dir.c_str()));
578582 }
579583
580584 if ( logFilePath.size() != 0 )
581585 {
582 char dir[1024];
586 std::string dir;
583587 getDirFromFile(logFilePath.c_str(), dir);
584 dialog.setDirectory(tr(dir));
588 dialog.setDirectory(tr(dir.c_str()));
585589 }
586590
587591 // Check config option to use native file dialog or not
12901294 {
12911295 return logging;
12921296 }
1297
1298 void FCEUD_FlushTrace()
1299 {
1300 //not needed, since it's doing something in a thread, i guess.
1301 //seems weird that there's no way to rendezvous with it
1302 }
1303
12931304 //----------------------------------------------------
12941305 //todo: really speed this up
12951306 void FCEUD_TraceInstruction(uint8 *opcode, int size)
16451656 selAddrValue = -1;
16461657 selAddrText[0] = 0;
16471658
1648 if (x < lineText[y].size())
1659 if ( static_cast<size_t>(x) < lineText[y].size())
16491660 {
16501661 int ax = x;
16511662
25072518 char buf[8192];
25082519 int i,idx=0;
25092520 int blockSize = 4 * 1024;
2521 bool dataNeedsFlush = true;
2522 bool isPaused = false;
25102523
25112524 //printf("Trace Log Disk Start\n");
25122525
25492562
25502563 while ( !isInterruptionRequested() )
25512564 {
2565 isPaused = FCEUI_EmulationPaused() ? true : false;
2566
25522567 while (logBufHead != logBufTail)
25532568 {
25542569 logBuf[logBufTail].convToText(line);
25742589 }
25752590 idx = 0;
25762591 #endif
2592 dataNeedsFlush = true;
2593 }
2594 }
2595
2596 if (isPaused)
2597 {
2598 // If paused, the user might be at a breakpoint or doing some
2599 // debugging. So make sure all data is flushed to disk for viewing.
2600 // Only flush data when paused, to keep write efficiency up.
2601 if ( idx > 0 )
2602 {
2603 #ifdef WIN32
2604 DWORD bytesWritten;
2605 WriteFile( logFile, buf, idx, &bytesWritten, NULL ); idx = 0;
2606 #else
2607 if ( write( logFile, buf, idx ) < 0 )
2608 {
2609 // HANDLE ERROR TODO
2610 }
2611 idx = 0;
2612 #endif
2613 dataNeedsFlush = true;
2614 }
2615 if (dataNeedsFlush)
2616 {
2617 //printf("Flushing Trace Log Disk Buffers\n");
2618 #ifdef WIN32
2619 FlushFileBuffers( logFile );
2620 #else
2621 if ( fsync( logFile ) )
2622 {
2623 printf("Trace Log fsync error\n");
2624 }
2625 #endif
2626 dataNeedsFlush = false;
25772627 }
25782628 }
25792629 SDL_Delay(1);
137137 }
138138
139139 int
140 gwavi_t::write_chars_bin(FILE *out, const char *s, int count)
140 gwavi_t::write_chars_bin(FILE *out, const char *s, size_t count)
141141 {
142142 if (fwrite(s, 1, count, out) != count)
143143 return -1;
213213 }
214214
215215 int
216 gwavi_t::read_chars_bin(FILE *in, char *s, int count)
216 gwavi_t::read_chars_bin(FILE *in, char *s, size_t count)
217217 {
218218 if (fread(s, 1, count, in) != count)
219219 return -1;
10361036
10371037 int gwavi_t::getChunkData( long long int fpos, unsigned char *buf, size_t size )
10381038 {
1039 int ret;
10391040 long long int prev_fpos;
10401041
10411042 prev_fpos = ftell(in);
10421043
10431044 fseek( in, fpos, SEEK_SET );
10441045
1045 fread( buf, 1, size, in );
1046 ret = fread( buf, 1, size, in ) != size;
10461047
10471048 fseek( in, prev_fpos, SEEK_SET );
10481049
1049 return 0;
1050 return ret;
10501051 }
10511052
10521053 unsigned int gwavi_t::readAviHeader(void)
296296 int write_byte(FILE *fp, unsigned char n);
297297 int write_short(FILE *fp, unsigned int n);
298298 int write_chars(FILE *fp, const char *s);
299 int write_chars_bin(FILE *fp, const char *s, int count);
299 int write_chars_bin(FILE *fp, const char *s, size_t count);
300300 int peak_chunk( FILE *fp, long int idx, char *fourcc, unsigned int *size );
301301
302302 int read_int(FILE *fp, int &n);
304304 int read_short(FILE *fp, int16_t &n);
305305 int read_short(FILE *fp, int &n);
306306 int read_ushort(FILE *fp, uint16_t &n);
307 int read_chars_bin(FILE *fp, char *s, int count);
307 int read_chars_bin(FILE *fp, char *s, size_t count);
308308 unsigned int readList(int lvl);
309309 unsigned int readChunk(const char *id, int lvl);
310310 unsigned int readAviHeader(void);
8282 case HK_CHEAT_MENU:
8383 name = "CheatMenu"; keySeq = ""; title = "Open Cheat Window"; group = "Tools";
8484 break;
85 case HK_TOGGLE_ALL_CHEATS:
86 name = "ToggleCheats"; keySeq = ""; title = "Toggle Global Cheat Enable"; group = "Tools";
87 break;
8588 case HK_BIND_STATE:
8689 name = "BindState"; keySeq = ""; title = "Bind Save State to Movie"; group = "Movie";
8790 break;
183186 case HK_POWER:
184187 name = "Power"; keySeq = ""; title = "Power"; group = "Emulation";
185188 break;
186 case HK_RESET:
187 name = "Reset"; keySeq = "Ctrl+R"; title = "Reset"; group = "Emulation";
189 case HK_SOFT_RESET:
190 name = "SoftReset"; keySeq = "Ctrl+R"; title = "Soft Reset"; group = "Emulation";
191 break;
192 case HK_HARD_RESET:
193 name = "HardReset"; keySeq = "Ctrl+Shift+R"; title = "Hard Reset"; group = "Emulation";
188194 break;
189195 case HK_PAUSE:
190196 name = "Pause"; keySeq = "Pause"; title = "Pause"; group = "Emulation";
288294 case HK_SELECT_STATE_PREV:
289295 name = "SelectStatePrev"; keySeq = ""; title = "Select Previous State Slot"; group = "State";
290296 break;
297 case HK_VOLUME_MUTE:
298 name = "VolumeMute"; keySeq = ""; title = "Sound Volume Mute"; group = "Sound";
299 break;
291300 case HK_VOLUME_DOWN:
292 name = "VolumeDown"; keySeq = "";
301 name = "VolumeDown"; keySeq = ""; title = "Sound Volume Down"; group = "Sound";
293302 break;
294303 case HK_VOLUME_UP:
295 name = "VolumeUp"; keySeq = "";
304 name = "VolumeUp"; keySeq = ""; title = "Sound Volume Up"; group = "Sound";
296305 break;
297306 case HK_FKB_ENABLE:
298307 name = "FKB_Enable"; keySeq = "ScrollLock"; title = "Toggle Family Keyboard Enable";
422431 static void
423432 GetBaseDirectory(std::string &dir)
424433 {
425 char *home = getenv("FCEUX_HOME");
434 const char *home = getenv("FCEUX_HOME");
435 const char *conf = getenv("FCEUX_CONFIG_DIR");
426436
427437 #ifdef WIN32
428438 // Windows users want base directory to be where executable resides.
443453 }
444454 #endif
445455
446 if (home)
456 if (conf)
457 {
458 dir = std::string(conf);
459 }
460 else if (home)
447461 {
448462 dir = std::string(home) + "/.fceux";
449 } else {
463 }
464 else
465 {
450466 #ifdef WIN32
451 home = new char[MAX_PATH + 1];
452 GetModuleFileNameA(NULL, home, MAX_PATH + 1);
453
454 char *lastBS = strrchr(home,'\\');
467 char *exePath = new char[MAX_PATH + 1];
468 GetModuleFileNameA(NULL, exePath, MAX_PATH + 1);
469
470 char *lastBS = strrchr(exePath,'\\');
455471 if(lastBS) {
456472 *lastBS = 0;
457473 }
458474
459 dir = std::string(home);
460 delete[] home;
475 dir = std::string(exePath);
476 delete[] exePath;
461477 #else
462478 dir = "";
463479 #endif
482498
483499 // sound options
484500 config->addOption('s', "sound", "SDL.Sound", 1);
501 config->addOption("soundMute", "SDL.Sound.Mute", 0);
485502 config->addOption("volume", "SDL.Sound.Volume", 255);
486503 config->addOption("trianglevol", "SDL.Sound.TriangleVolume", 255);
487504 config->addOption("square1vol", "SDL.Sound.Square1Volume", 255);
504521 config->addOption("nospritelim", "SDL.DisableSpriteLimit", 0);
505522 config->addOption("swapduty", "SDL.SwapDuty", 0);
506523 config->addOption("ramInit", "SDL.RamInitMethod", 0);
524 config->addOption("SDL.FrameAdvanceDelay", 40);
507525
508526 // color control
509527 config->addOption('p', "palette", "SDL.Palette", "");
528546 config->addOption('f', "fullscreen", "SDL.Fullscreen", 0);
529547 config->addOption("videoDriver", "SDL.VideoDriver", 0);
530548 config->addOption("SDL.VideoBgColor", "#000000");
549 config->addOption("SDL.UseBgPaletteForVideo", false);
531550 config->addOption("SDL.VideoVsync", 1);
532551
533552 // set x/y res to 0 for automatic fullscreen resolution detection (no change)
10751094 config->getOption("SDL.VBlankScanlines" , &vblankscanlines );
10761095 config->getOption("SDL.Skip7bitOverClocking", &skip_7bit_overclocking );
10771096 config->getOption("SDL.ShowGuiMessages" , &vidGuiMsgEna );
1097 config->getOption("SDL.FrameAdvanceDelay" , &frameAdvance_Delay );
10781098
10791099 config->getOption("SDL.PAL", &region);
10801100 FCEUI_SetRegion(region);
1313 HK_OPEN_ROM=0, HK_CLOSE_ROM,
1414
1515 // Emulation power, reset, pause, quit
16 HK_POWER, HK_RESET, HK_PAUSE, HK_QUIT,
16 HK_POWER, HK_SOFT_RESET, HK_HARD_RESET, HK_PAUSE, HK_QUIT,
1717
1818 // Emulation Execution Control
1919 HK_FRAME_ADVANCE, HK_DECREASE_SPEED, HK_INCREASE_SPEED, HK_TURBO,
5252 // Display
5353 HK_TOGGLE_FG, HK_TOGGLE_BG, HK_TOGGLE_INPUT_DISPLAY, HK_LAG_COUNTER_DISPLAY,
5454
55 HK_CHEAT_MENU, HK_LOAD_LUA,
55 HK_CHEAT_MENU, HK_TOGGLE_ALL_CHEATS, HK_LOAD_LUA,
5656 HK_MUTE_CAPTURE,
5757 HK_FA_LAG_SKIP,
58 HK_VOLUME_DOWN, HK_VOLUME_UP,
58 HK_VOLUME_MUTE, HK_VOLUME_DOWN, HK_VOLUME_UP,
5959 HK_FKB_ENABLE,
6060 HK_MAX};
6161
1212 int KillSound(void);
1313 uint32 GetMaxSound(void);
1414 uint32 GetWriteSound(void);
15 bool FCEUD_SoundIsMuted(void);
1516 void FCEUD_MuteSoundOutput(bool value);
17 void FCEUD_MuteSoundWindow(bool value);
1618
1719 void SilenceSound(int s); /* DOS and SDL */
1820
3838 #include "Qt/unix-netplay.h"
3939 #include "Qt/AviRecord.h"
4040 #include "Qt/HexEditor.h"
41 #include "Qt/CheatsConf.h"
4142 #include "Qt/SymbolicDebug.h"
4243 #include "Qt/CodeDataLogger.h"
4344 #include "Qt/ConsoleDebugger.h"
8788 bool suggestReadOnlyReplay = true;
8889 bool showStatusIconOpt = true;
8990 bool drawInputAidsEnable = true;
91 bool usePaletteForVideoBg = false;
9092 unsigned int gui_draw_area_width = 256;
9193 unsigned int gui_draw_area_height = 256;
9294
350352 }
351353
352354 debugSymbolTable.loadGameSymbols();
355
356 updateCheatDialog();
353357
354358 CDLoggerROMChanged();
355359
641645 static void ShowUsage(const char *prog)
642646 {
643647 int i,j;
648 FCEUD_Message("Starting " FCEU_NAME_AND_VERSION "...\n");
644649 printf("\nUsage is as follows:\n%s <options> filename\n\n",prog);
645650 puts(DriverUsage);
646651 #ifdef _S9XLUA_H
680685
681686 }
682687
688 // Pre-GUI initialization.
689 int fceuWrapperPreInit( int argc, char *argv[] )
690 {
691 for (int i=0; i<argc; i++)
692 {
693 if ( (strcmp(argv[i], "--help") == 0) || (strcmp(argv[i],"-h") == 0) )
694 {
695 ShowUsage(argv[0]);
696 exit(0);
697 }
698 else if ( strcmp(argv[i], "--no-gui") == 0)
699 {
700 printf("Error: Qt/SDL version does not support --no-gui option.\n");
701 exit(1);
702 }
703 else if ( strcmp(argv[i], "--version") == 0)
704 {
705 printf("%i.%i.%i\n", FCEU_VERSION_MAJOR, FCEU_VERSION_MINOR, FCEU_VERSION_PATCH);
706 exit(0);
707 }
708 }
709 return 0;
710 }
711
683712 int fceuWrapperInit( int argc, char *argv[] )
684713 {
685714 int opt, error;
686715 std::string s;
687
688 for (int i=0; i<argc; i++)
689 {
690 if ( (strcmp(argv[i], "--help") == 0) || (strcmp(argv[i],"-h") == 0) )
691 {
692 ShowUsage(argv[0]);
693 exit(0);
694 }
695 }
696716
697717 FCEUD_Message("Starting " FCEU_NAME_AND_VERSION "...\n");
698718
867887 extern std::vector<std::string> subtitleMessages;
868888 float fps = (md.palFlag == 0 ? 60.0988 : 50.0069); // NTSC vs PAL
869889 float subduration = 3; // seconds for the subtitles to be displayed
870 for (int i = 0; i < subtitleFrames.size(); i++)
890 for (size_t i = 0; i < subtitleFrames.size(); i++)
871891 {
872 fprintf(srtfile, "%i\n", i+1); // starts with 1, not 0
892 fprintf(srtfile, "%zi\n", i+1); // starts with 1, not 0
873893 double seconds, ms, endseconds, endms;
874894 seconds = subtitleFrames[i]/fps;
875895 if (i+1 < subtitleFrames.size()) // there's another subtitle coming after this one
953973
954974 if (romIndex >= 0)
955975 {
956 // load the specified game
957 error = LoadGame(argv[romIndex]);
958 if (error != 1)
959 {
960 DriverKill();
961 SDL_Quit();
976 QFileInfo fi( argv[romIndex] );
977
978 // Resolve absolute path to file
979 if ( fi.exists() )
980 {
981 std::string fullpath = fi.canonicalFilePath().toStdString().c_str();
982
983 error = LoadGame( fullpath.c_str() );
984
985 if (error != 1)
986 {
987 DriverKill();
988 SDL_Quit();
989 return -1;
990 }
991 g_config->setOption("SDL.LastOpenFile", fullpath.c_str() );
992 g_config->save();
993 }
994 else
995 {
996 // File was not found
962997 return -1;
963998 }
964 g_config->setOption("SDL.LastOpenFile", argv[romIndex]);
965 g_config->save();
966999 }
9671000
9681001 aviRecordInit();
14761509
14771510 for (size_t i=0; i<asr.files.size(); i++)
14781511 {
1479 char base[512], suffix[32];
1512 char base[512], suffix[128];
14801513
14811514 getFileBaseName( asr.files[i].name.c_str(), base, suffix );
14821515
1717 extern bool emulatorCycleToggle;
1818 extern bool showStatusIconOpt;
1919 extern bool drawInputAidsEnable;
20 extern bool usePaletteForVideoBg;
2021 extern unsigned int gui_draw_area_width;
2122 extern unsigned int gui_draw_area_height;
2223 extern unsigned int emulatorCycleCount;
2930 int reloadLastGame(void);
3031 int LoadGameFromLua( const char *path );
3132
33 int fceuWrapperPreInit( int argc, char *argv[] );
3234 int fceuWrapperInit( int argc, char *argv[] );
3335 int fceuWrapperMemoryCleanup( void );
3436 int fceuWrapperClose( void );
188188 fontCharWidth = fm.width(QLatin1Char('2'));
189189 #endif
190190
191 setWindowTitle("iNES Header Editor");
191 setWindowTitle("NES Header Editor");
192192
193193 //resize( 512, 512 );
194194
196196 hdrLayout = new QVBoxLayout();
197197 hbox1 = new QHBoxLayout();
198198 hbox = new QHBoxLayout();
199 hdrBox = new QGroupBox( tr("iNES Header") );
199 hdrBox = new QGroupBox( tr("NES Header") );
200200 box = new QGroupBox( tr("Version:") );
201201
202202 mainLayout->addWidget( hdrBox );
549549 //----------------------------------------------------------------------------
550550 void iNesHeaderEditor_t::closeEvent(QCloseEvent *event)
551551 {
552 //printf("iNES Header Editor Close Window Event\n");
552 //printf("NES Header Editor Close Window Event\n");
553553 done(0);
554554 deleteLater();
555555 event->accept();
694694 {
695695 case errors::OPEN_FAILED:
696696 {
697 char buf[2200];
698 sprintf(buf, "Error opening %s!", LoadedRomFName);
697 char buf[5120];
698 snprintf(buf, sizeof(buf), "Error opening %s!", LoadedRomFName);
699699 showErrorMsgWindow( buf );
700700 break;
701701 }
702702 case errors::INVALID_HEADER:
703 //MessageBox(parent, "Invalid iNES header.", "iNES Header Editor", MB_OK | MB_ICONERROR);
704 showErrorMsgWindow( "Invalid iNES header." );
703 //MessageBox(parent, "Invalid NES header.", "NES Header Editor", MB_OK | MB_ICONERROR);
704 showErrorMsgWindow( "Invalid NES header." );
705705 break;
706706 case errors::FDS_HEADER:
707 //MessageBox(parent, "Editing header of an FDS file is not supported.", "iNES Header Editor", MB_OK | MB_ICONERROR);
707 //MessageBox(parent, "Editing header of an FDS file is not supported.", "NES Header Editor", MB_OK | MB_ICONERROR);
708708 showErrorMsgWindow("Editing header of an FDS file is not supported.");
709709 break;
710710 case errors::UNIF_HEADER:
711 //MessageBox(parent, "Editing header of a UNIF file is not supported.", "iNES Header Editor", MB_OK | MB_ICONERROR);
711 //MessageBox(parent, "Editing header of a UNIF file is not supported.", "NES Header Editor", MB_OK | MB_ICONERROR);
712712 showErrorMsgWindow("Editing header of a UNIF file is not supported.");
713713 break;
714714 case errors::NSF_HEADER:
715715 // case errors::NSF2_HEADER:
716716 // case errors::NSFE_HEADER:
717 //MessageBox(parent, "Editing header of an NSF file is not supported.", "iNES Header Editor", MB_OK | MB_ICONERROR);
717 //MessageBox(parent, "Editing header of an NSF file is not supported.", "NES Header Editor", MB_OK | MB_ICONERROR);
718718 showErrorMsgWindow("Editing header of an NSF file is not supported.");
719719 break;
720720 }
736736 FCEUFILE* source = FCEU_fopen(LoadedRomFName, NULL, "rb", 0, -1, ext);
737737 if (!source)
738738 {
739 sprintf(buf, "Opening source file %s failed.", LoadedRomFName);
740 showErrorMsgWindow(buf);
739 char msg[5120];
740 snprintf(msg, sizeof(msg), "Opening source file %s failed.", LoadedRomFName);
741 showErrorMsgWindow(msg);
741742 return false;
742743 }
743744
745746 FILE* target = FCEUD_UTF8fopen(path, "wb");
746747 if (!target)
747748 {
748 sprintf(buf, "Creating target file %s failed.", path);
749 showErrorMsgWindow(buf);
749 char msg[5120];
750 snprintf(msg, sizeof(msg), "Creating target file %s failed.", path);
751 showErrorMsgWindow(msg);
750752 return false;
751753 }
752754
775777 int ret, useNativeFileDialogVal;
776778 QString filename;
777779 std::string last;
778 char dir[512];
780 std::string dir;
779781 QFileDialog dialog(this, tr("Open NES File") );
780782
781783 const QStringList filters(
796798
797799 getDirFromFile( last.c_str(), dir );
798800
799 dialog.setDirectory( tr(dir) );
801 dialog.setDirectory( tr(dir.c_str()) );
800802
801803 // Check config option to use native file dialog or not
802804 g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
824826
825827 if ( GameInfo == NULL )
826828 {
827 strcpy( LoadedRomFName, filename.toStdString().c_str() );
829 strncpy( LoadedRomFName, filename.toStdString().c_str(), sizeof(LoadedRomFName)-1 );
830 LoadedRomFName[sizeof(LoadedRomFName)-1] = 0;
828831 }
829832
830833 return true;
835838 int ret, useNativeFileDialogVal;
836839 QString filename;
837840 std::string last;
838 char dir[512];
841 std::string dir;
839842 QFileDialog dialog(this, tr("Save iNES File") );
840843
841844 dialog.setFileMode(QFileDialog::AnyFile);
849852
850853 getDirFromFile( LoadedRomFName, dir );
851854
852 dialog.setDirectory( tr(dir) );
855 dialog.setDirectory( tr(dir.c_str()) );
853856
854857 // Check config option to use native file dialog or not
855858 g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal);
11961199 }
11971200
11981201 // Input Device:
1199 int input = header->reserved[1] & 0x3F;
1202 int input = header->expansion & 0x3F;
12001203 for (i=0; i<inputDevBox->count(); i++)
12011204 {
12021205 if ( inputDevBox->itemData(i).toInt() == input )
12061209 }
12071210
12081211 // Miscellaneous ROM Area(s)
1209 sprintf(buf, "%d", header->reserved[0] & 3);
1212 sprintf(buf, "%d", header->misc_roms & 3);
12101213 miscRomsEdit->setText( tr(buf) );
12111214
12121215 // Trainer
19191922 int input = inputDevBox->itemData(idx).toInt();
19201923 if (input <= 0x3F)
19211924 {
1922 _header.reserved[1] |= input & 0x3F;
1925 _header.expansion |= input & 0x3F;
19231926 }
19241927 else
19251928 {
19431946 showErrorMsgWindow("Miscellaneous ROM(s) count has exceeded the limit of iNES 2.0 (3)");
19441947 return false;
19451948 }
1946 _header.reserved[0] |= misc_roms & 3;
1949 _header.misc_roms |= misc_roms & 3;
19471950 }
19481951
19491952 // iNES 1.0 unofficial properties
20212024 printf("%02X ", _header->VRAM_size);
20222025 printf("%02X ", _header->TV_system);
20232026 printf("%02X ", _header->VS_hardware);
2024 printf("%02X ", _header->reserved[0]);
2025 printf("%02X\n", _header->reserved[1]);
2026 }
2027 //----------------------------------------------------------------------------
2027 printf("%02X ", _header->misc_roms);
2028 printf("%02X\n", _header->expansion);
2029 }
2030 //----------------------------------------------------------------------------
6464 static int buttonConfigInProgress = 0;
6565
6666 extern int gametype;
67 static int DTestButton(ButtConfig *bc);
67 static int DTestButton(ButtConfig *bc, bool isFKB = false);
6868
6969 //std::list<gamepad_function_key_t *> gpKeySeqList;
7070
155155 return g_keyState[k];
156156 }
157157 return 0;
158 }
159
160 const uint8_t *QtSDL_getKeyboardState( int *bufSize )
161 {
162 if (bufSize != nullptr)
163 {
164 *bufSize = SDL_NUM_SCANCODES;
165 }
166 return g_keyState;
158167 }
159168
160169 //static int
14061415 * Tests to see if a specified button is currently pressed.
14071416 */
14081417 static int
1409 DTestButton(ButtConfig *bc)
1410 {
1411
1418 DTestButton(ButtConfig *bc, bool isFKB)
1419 {
14121420 if (bc->ButtType == BUTTC_KEYBOARD)
14131421 {
1414 if (g_keyState[SDL_GetScancodeFromKey(bc->ButtonNum)])
1422 bool ignoreKB = false;
1423 bool fkbActv = g_fkbEnabled && (CurInputType[2] == SIFC_FKB);
1424
1425 if (fkbActv)
1426 {
1427 ignoreKB = !isFKB;
1428 }
1429 if (!ignoreKB && g_keyState[SDL_GetScancodeFromKey(bc->ButtonNum)])
14151430 {
14161431 bc->state = 1;
14171432 return 1;
17431758 CurInputType[1] = port1;
17441759 CurInputType[2] = fcexp;
17451760 }
1761 if (CurInputType[2] != SIFC_FKB)
1762 {
1763 g_fkbEnabled = false;
1764 }
17461765
17471766 replaceP2StartWithMicrophone = microphone;
17481767
18701889
18711890 vkeyDown = getFamilyKeyboardVirtualKey(50);
18721891
1873 leftShiftDown = DTestButton(&fkbmap[50]) || vkeyDown;
1892 leftShiftDown = DTestButton(&fkbmap[50], true) || vkeyDown;
18741893
18751894 for (x = 0; x < FAMILYKEYBOARD_NUM_BUTTONS; x++)
18761895 {
18861905
18871906 vkeyDown = getFamilyKeyboardVirtualKey(x);
18881907
1889 if (DTestButton(&fkbmap[x]) || vkeyDown)
1908 if (DTestButton(&fkbmap[x], true) || vkeyDown)
18901909 {
18911910 fkbkeys[x] = 1;
18921911
19081927 }
19091928 }
19101929
1911 const uint8 *getFamilyKeyboardState(void)
1930 const uint8_t *getFamilyKeyboardState(void)
19121931 {
19131932 return fkbkeys;
19141933 }
24132432 QDir dir;
24142433 std::string path;
24152434 const char *baseDir = FCEUI_GetBaseDirectory();
2416 char base[256];
2435 char base[512];
24172436
24182437 path = std::string(baseDir) + "/input/presets/";
24192438
24612480 QDir dir;
24622481 std::string path;
24632482 const char *baseDir = FCEUI_GetBaseDirectory();
2464 char base[256], line[256];
2483 char base[512], line[256];
24652484 char id[128], val[128];
24662485 int i, j;
24672486
147147 int loadInputSettingsFromFile( const char *filename = NULL );
148148 void toggleFamilyKeyboardFunc(void);
149149 bool isFamilyKeyboardActv(void);
150 const uint8 *getFamilyKeyboardState(void);
150 const uint8_t *getFamilyKeyboardState(void);
151 const uint8_t *QtSDL_getKeyboardState( int *bufSize );
151152
152153 #endif
153154
2626
2727 using namespace Qt;
2828
29 /* scan code to virtual keys */
30 struct _KeyValue
31 {
32 int vkey, key;
33 };
34
35 /* for readability */
36 typedef int NativeScanCode;
37
2938 #if defined(WIN32)
3039
3140 #include <windows.h>
6877 static uint32_t CtrlKeyCodeR = 0xffe4;
6978 static uint32_t AltKeyCodeR = 0xffea;
7079 static uint32_t MetaKeyCodeR = 0xffe8;
80 #endif
81
82 /* map to convert keyboard native scan code to qt keys */
83 static QMap<NativeScanCode, _KeyValue> s_nativeScanCodesMap =
84 #if defined(WIN32)
85 {
86 { 1, { VK_ESCAPE , Qt::Key_Escape }},
87 { 2, { '1' , Qt::Key_1 }},
88 { 3, { '2' , Qt::Key_2 }},
89 { 4, { '3' , Qt::Key_3 }},
90 { 5, { '4' , Qt::Key_4 }},
91 { 6, { '5' , Qt::Key_5 }},
92 { 7, { '6' , Qt::Key_6 }},
93 { 8, { '7' , Qt::Key_7 }},
94 { 9, { '8' , Qt::Key_8 }},
95 { 10, { '9' , Qt::Key_9 }},
96 { 11, { '0' , Qt::Key_0 }},
97 { 12, { VK_OEM_MINUS , Qt::Key_Minus }},
98 { 13, { VK_OEM_PLUS , Qt::Key_Equal }},
99 { 14, { VK_BACK , Qt::Key_Backspace }},
100 { 15, { VK_TAB , Qt::Key_Tab }},
101 { 16, { 'Q' , Qt::Key_Q }},
102 { 17, { 'W' , Qt::Key_W }},
103 { 18, { 'E' , Qt::Key_E }},
104 { 19, { 'R' , Qt::Key_R }},
105 { 20, { 'T' , Qt::Key_T }},
106 { 21, { 'Y' , Qt::Key_Y }},
107 { 22, { 'U' , Qt::Key_U }},
108 { 23, { 'I' , Qt::Key_I }},
109 { 24, { 'O' , Qt::Key_O }},
110 { 25, { 'P' , Qt::Key_P }},
111 { 26, { VK_OEM_4 , Qt::Key_BracketLeft }},
112 { 27, { VK_OEM_6 , Qt::Key_BracketRight }},
113 { 28, { VK_RETURN , Qt::Key_Return }},
114 { 29, { VK_LCONTROL , Qt::Key_Control }},
115 { 30, { 'A' , Qt::Key_A }},
116 { 31, { 'S' , Qt::Key_S }},
117 { 32, { 'D' , Qt::Key_D }},
118 { 33, { 'F' , Qt::Key_F }},
119 { 34, { 'G' , Qt::Key_G }},
120 { 35, { 'H' , Qt::Key_H }},
121 { 36, { 'J' , Qt::Key_J }},
122 { 37, { 'K' , Qt::Key_K }},
123 { 38, { 'L' , Qt::Key_L }},
124 { 39, { VK_OEM_1 , Qt::Key_Semicolon }},
125 { 40, { VK_OEM_7 , Qt::Key_Apostrophe }},
126 { 41, { VK_OEM_3 , Qt::Key_QuoteLeft }},
127 { 42, { VK_LSHIFT , Qt::Key_Shift }},
128 { 43, { VK_OEM_5 , Qt::Key_Backslash }},
129 { 44, { 'Z' , Qt::Key_Z }},
130 { 45, { 'X' , Qt::Key_X }},
131 { 46, { 'C' , Qt::Key_C }},
132 { 47, { 'V' , Qt::Key_V }},
133 { 48, { 'B' , Qt::Key_B }},
134 { 49, { 'N' , Qt::Key_N }},
135 { 50, { 'M' , Qt::Key_M }},
136 { 51, { VK_OEM_COMMA , Qt::Key_Comma }},
137 { 52, { VK_OEM_PERIOD , Qt::Key_Period }},
138 { 53, { VK_OEM_2 , Qt::Key_Slash }},
139 { 54, { VK_RSHIFT , Qt::Key_Shift }},
140 { 55, { VK_MULTIPLY , Qt::Key_Asterisk }},
141 { 56, { VK_LMENU , Qt::Key_Alt }},
142 { 58, { VK_CAPITAL , Qt::Key_CapsLock }},
143 { 59, { VK_F1 , Qt::Key_F1 }},
144 { 60, { VK_F2 , Qt::Key_F2 }},
145 { 61, { VK_F3 , Qt::Key_F3 }},
146 { 62, { VK_F4 , Qt::Key_F4 }},
147 { 63, { VK_F5 , Qt::Key_F5 }},
148 { 64, { VK_F6 , Qt::Key_F6 }},
149 { 65, { VK_F7 , Qt::Key_F7 }},
150 { 66, { VK_F8 , Qt::Key_F8 }},
151 { 67, { VK_F9 , Qt::Key_F9 }},
152 { 68, { VK_F10 , Qt::Key_F10 }},
153 { 69, { VK_PAUSE , Qt::Key_Pause }},
154 { 70, { VK_SCROLL , Qt::Key_ScrollLock }},
155 { 71, { VK_HOME , Qt::Key_Home }},
156 { 74, { VK_SUBTRACT , Qt::Key_Minus }},
157 { 76, { VK_CLEAR , Qt::Key_Clear }},
158 { 78, { VK_ADD , Qt::Key_Plus }},
159 { 79, { VK_END , Qt::Key_End }},
160 { 82, { VK_INSERT , Qt::Key_Insert }},
161 { 83, { VK_DELETE , Qt::Key_Delete }},
162 { 87, { VK_F11 , Qt::Key_F11 }},
163 { 88, { VK_F12 , Qt::Key_F12 }},
164 {256, { VK_MEDIA_NEXT_TRACK, Qt::Key_MediaNext }},
165 {284, { VK_RETURN , Qt::Key_Enter }},
166 {285, { VK_RCONTROL , Qt::Key_Control }},
167 {309, { VK_DIVIDE , Qt::Key_Slash }},
168 {312, { VK_RMENU , Qt::Key_Alt }},
169 {325, { VK_NUMLOCK , Qt::Key_NumLock }},
170 {338, { VK_INSERT , Qt::Key_Insert }},
171 {339, { VK_DELETE , Qt::Key_Delete }},
172 {347, { VK_LWIN , Qt::Key_Meta }},
173 {348, { VK_RWIN , Qt::Key_Meta }},
174 {349, { VK_APPS , Qt::Key_Menu }},
175 };
176 #elif defined(__APPLE__)
177 // QKeyEvent::nativeScanCode() does not return valid codes for Mac OS
178 {
179 { 0, { 0, 0 }},
180 };
181 #else // Unix / Linux
182 {
183 #if defined(_HAS_XKB)
184 { 9, { XKB_KEY_Escape , Qt::Key_Escape }},
185 { 10, { XKB_KEY_1 , Qt::Key_1 }},
186 { 11, { XKB_KEY_2 , Qt::Key_2 }},
187 { 12, { XKB_KEY_3 , Qt::Key_3 }},
188 { 13, { XKB_KEY_4 , Qt::Key_4 }},
189 { 14, { XKB_KEY_5 , Qt::Key_5 }},
190 { 15, { XKB_KEY_6 , Qt::Key_6 }},
191 { 16, { XKB_KEY_7 , Qt::Key_7 }},
192 { 17, { XKB_KEY_8 , Qt::Key_8 }},
193 { 18, { XKB_KEY_9 , Qt::Key_9 }},
194 { 19, { XKB_KEY_0 , Qt::Key_0 }},
195 { 20, { XKB_KEY_minus , Qt::Key_Minus }},
196 { 21, { XKB_KEY_equal , Qt::Key_Equal }},
197 { 22, { XKB_KEY_BackSpace , Qt::Key_Backspace }},
198 { 23, { XKB_KEY_Tab , Qt::Key_Tab }},
199 { 24, { XKB_KEY_q , Qt::Key_Q }},
200 { 25, { XKB_KEY_w , Qt::Key_W }},
201 { 26, { XKB_KEY_e , Qt::Key_E }},
202 { 27, { XKB_KEY_r , Qt::Key_R }},
203 { 28, { XKB_KEY_t , Qt::Key_T }},
204 { 29, { XKB_KEY_y , Qt::Key_Y }},
205 { 30, { XKB_KEY_u , Qt::Key_U }},
206 { 31, { XKB_KEY_i , Qt::Key_I }},
207 { 32, { XKB_KEY_o , Qt::Key_O }},
208 { 33, { XKB_KEY_p , Qt::Key_P }},
209 { 34, { XKB_KEY_bracketleft , Qt::Key_BracketLeft }},
210 { 35, { XKB_KEY_bracketright , Qt::Key_BracketRight }},
211 { 36, { XKB_KEY_Return , Qt::Key_Return }},
212 { 37, { XKB_KEY_Control_L , Qt::Key_Control }},
213 { 38, { XKB_KEY_a , Qt::Key_A }},
214 { 39, { XKB_KEY_s , Qt::Key_S }},
215 { 40, { XKB_KEY_d , Qt::Key_D }},
216 { 41, { XKB_KEY_f , Qt::Key_F }},
217 { 42, { XKB_KEY_g , Qt::Key_G }},
218 { 43, { XKB_KEY_h , Qt::Key_H }},
219 { 44, { XKB_KEY_j , Qt::Key_J }},
220 { 45, { XKB_KEY_k , Qt::Key_K }},
221 { 46, { XKB_KEY_l , Qt::Key_L }},
222 { 47, { XKB_KEY_semicolon , Qt::Key_Semicolon }},
223 { 48, { XKB_KEY_apostrophe , Qt::Key_Apostrophe }},
224 { 49, { XKB_KEY_grave , Qt::Key_QuoteLeft }},
225 { 50, { XKB_KEY_Shift_L , Qt::Key_Shift }},
226 { 51, { XKB_KEY_backslash , Qt::Key_Backslash }},
227 { 52, { XKB_KEY_z , Qt::Key_Z }},
228 { 53, { XKB_KEY_x , Qt::Key_X }},
229 { 54, { XKB_KEY_c , Qt::Key_C }},
230 { 55, { XKB_KEY_v , Qt::Key_V }},
231 { 56, { XKB_KEY_b , Qt::Key_B }},
232 { 57, { XKB_KEY_n , Qt::Key_N }},
233 { 58, { XKB_KEY_m , Qt::Key_M }},
234 { 59, { XKB_KEY_comma , Qt::Key_Comma }},
235 { 60, { XKB_KEY_period , Qt::Key_Period }},
236 { 61, { XKB_KEY_slash , Qt::Key_Slash }},
237 { 62, { XKB_KEY_Shift_R , Qt::Key_Shift }},
238 { 63, { XKB_KEY_KP_Multiply , Qt::Key_Asterisk }},
239 { 64, { XKB_KEY_Alt_L , Qt::Key_Alt }},
240 { 66, { XKB_KEY_Caps_Lock , Qt::Key_CapsLock }},
241 { 67, { XKB_KEY_F1 , Qt::Key_F1 }},
242 { 68, { XKB_KEY_F2 , Qt::Key_F2 }},
243 { 69, { XKB_KEY_F3 , Qt::Key_F3 }},
244 { 70, { XKB_KEY_F4 , Qt::Key_F4 }},
245 { 71, { XKB_KEY_F5 , Qt::Key_F5 }},
246 { 72, { XKB_KEY_F6 , Qt::Key_F6 }},
247 { 73, { XKB_KEY_F7 , Qt::Key_F7 }},
248 { 74, { XKB_KEY_F8 , Qt::Key_F8 }},
249 { 75, { XKB_KEY_F9 , Qt::Key_F9 }},
250 { 76, { XKB_KEY_F10 , Qt::Key_F10 }},
251 { 77, { XKB_KEY_Num_Lock , Qt::Key_NumLock }},
252 { 78, { XKB_KEY_Scroll_Lock , Qt::Key_ScrollLock }},
253 { 79, { XKB_KEY_KP_7 , Qt::Key_7 }},
254 { 80, { XKB_KEY_KP_8 , Qt::Key_8 }},
255 { 81, { XKB_KEY_KP_9 , Qt::Key_9 }},
256 { 82, { XKB_KEY_KP_Subtract , Qt::Key_Minus }},
257 { 83, { XKB_KEY_KP_4 , Qt::Key_4 }},
258 { 84, { XKB_KEY_KP_5 , Qt::Key_5 }},
259 { 85, { XKB_KEY_KP_6 , Qt::Key_6 }},
260 { 86, { XKB_KEY_KP_Add , Qt::Key_Plus }},
261 { 87, { XKB_KEY_KP_1 , Qt::Key_1 }},
262 { 88, { XKB_KEY_KP_2 , Qt::Key_2 }},
263 { 89, { XKB_KEY_KP_3 , Qt::Key_3 }},
264 { 90, { XKB_KEY_KP_0 , Qt::Key_0 }},
265 { 91, { XKB_KEY_KP_Decimal , Qt::Key_Period }},
266 { 95, { XKB_KEY_F11 , Qt::Key_F11 }},
267 { 96, { XKB_KEY_F12 , Qt::Key_F12 }},
268 {104, { XKB_KEY_KP_Enter , Qt::Key_Enter }},
269 {105, { XKB_KEY_Control_R , Qt::Key_Control }},
270 {106, { XKB_KEY_KP_Divide , Qt::Key_Slash }},
271 {108, { XKB_KEY_Alt_R , Qt::Key_Alt }},
272 {110, { XKB_KEY_Home , Qt::Key_Home }},
273 {111, { XKB_KEY_Up , Qt::Key_Up }},
274 {112, { XKB_KEY_Page_Up , Qt::Key_PageUp }},
275 {113, { XKB_KEY_Left , Qt::Key_Left }},
276 {114, { XKB_KEY_Right , Qt::Key_Right }},
277 {115, { XKB_KEY_End , Qt::Key_End }},
278 {116, { XKB_KEY_Down , Qt::Key_Down }},
279 {117, { XKB_KEY_Page_Down , Qt::Key_PageDown }},
280 {118, { XKB_KEY_Insert , Qt::Key_Insert }},
281 {119, { XKB_KEY_Delete , Qt::Key_Delete }},
282 {127, { XKB_KEY_Pause , Qt::Key_Pause }},
283 {134, { XKB_KEY_Super_R , Qt::Key_Meta }},
284 #else
285 { 9, { 0xff1b , Qt::Key_Escape }},
286 { 10, { 0x0031 , Qt::Key_1 }},
287 { 11, { 0x0032 , Qt::Key_2 }},
288 { 12, { 0x0033 , Qt::Key_3 }},
289 { 13, { 0x0034 , Qt::Key_4 }},
290 { 14, { 0x0035 , Qt::Key_5 }},
291 { 15, { 0x0036 , Qt::Key_6 }},
292 { 16, { 0x0037 , Qt::Key_7 }},
293 { 17, { 0x0038 , Qt::Key_8 }},
294 { 18, { 0x0039 , Qt::Key_9 }},
295 { 19, { 0x0030 , Qt::Key_0 }},
296 { 20, { 0x002d , Qt::Key_Minus }},
297 { 21, { 0x003d , Qt::Key_Equal }},
298 { 22, { 0xff08 , Qt::Key_Backspace }},
299 { 23, { 0xff09 , Qt::Key_Tab }},
300 { 24, { 0x0071 , Qt::Key_Q }},
301 { 25, { 0x0077 , Qt::Key_W }},
302 { 26, { 0x0065 , Qt::Key_E }},
303 { 27, { 0x0072 , Qt::Key_R }},
304 { 28, { 0x0074 , Qt::Key_T }},
305 { 29, { 0x0079 , Qt::Key_Y }},
306 { 30, { 0x0075 , Qt::Key_U }},
307 { 31, { 0x0069 , Qt::Key_I }},
308 { 32, { 0x006f , Qt::Key_O }},
309 { 33, { 0x0070 , Qt::Key_P }},
310 { 34, { 0x005b , Qt::Key_BracketLeft }},
311 { 35, { 0x005d , Qt::Key_BracketRight }},
312 { 36, { 0xff0d , Qt::Key_Return }},
313 { 37, { 0xffe3 , Qt::Key_Control }},
314 { 38, { 0x0061 , Qt::Key_A }},
315 { 39, { 0x0073 , Qt::Key_S }},
316 { 40, { 0x0064 , Qt::Key_D }},
317 { 41, { 0x0066 , Qt::Key_F }},
318 { 42, { 0x0067 , Qt::Key_G }},
319 { 43, { 0x0068 , Qt::Key_H }},
320 { 44, { 0x006a , Qt::Key_J }},
321 { 45, { 0x006b , Qt::Key_K }},
322 { 46, { 0x006c , Qt::Key_L }},
323 { 47, { 0x003b , Qt::Key_Semicolon }},
324 { 48, { 0x0027 , Qt::Key_Apostrophe }},
325 { 49, { 0x0060 , Qt::Key_QuoteLeft }},
326 { 50, { 0xffe1 , Qt::Key_Shift }},
327 { 51, { 0x005c , Qt::Key_Backslash }},
328 { 52, { 0x007a , Qt::Key_Z }},
329 { 53, { 0x0078 , Qt::Key_X }},
330 { 54, { 0x0063 , Qt::Key_C }},
331 { 55, { 0x0076 , Qt::Key_V }},
332 { 56, { 0x0062 , Qt::Key_B }},
333 { 57, { 0x006e , Qt::Key_N }},
334 { 58, { 0x006d , Qt::Key_M }},
335 { 59, { 0x002c , Qt::Key_Comma }},
336 { 60, { 0x002e , Qt::Key_Period }},
337 { 61, { 0x002f , Qt::Key_Slash }},
338 { 62, { 0xffe2 , Qt::Key_Shift }},
339 { 63, { 0xffaa , Qt::Key_Asterisk }},
340 { 64, { 0xffe9 , Qt::Key_Alt }},
341 { 66, { 0xffe5 , Qt::Key_CapsLock }},
342 { 67, { 0xffbe , Qt::Key_F1 }},
343 { 68, { 0xffbf , Qt::Key_F2 }},
344 { 69, { 0xffc0 , Qt::Key_F3 }},
345 { 70, { 0xffc1 , Qt::Key_F4 }},
346 { 71, { 0xffc2 , Qt::Key_F5 }},
347 { 72, { 0xffc3 , Qt::Key_F6 }},
348 { 73, { 0xffc4 , Qt::Key_F7 }},
349 { 74, { 0xffc5 , Qt::Key_F8 }},
350 { 75, { 0xffc6 , Qt::Key_F9 }},
351 { 76, { 0xffc7 , Qt::Key_F10 }},
352 { 77, { 0xff7f , Qt::Key_NumLock }},
353 { 78, { 0xff14 , Qt::Key_ScrollLock }},
354 { 79, { 0xffb7 , Qt::Key_7 }},
355 { 80, { 0xffb8 , Qt::Key_8 }},
356 { 81, { 0xffb9 , Qt::Key_9 }},
357 { 82, { 0xffad , Qt::Key_Minus }},
358 { 83, { 0xffb4 , Qt::Key_4 }},
359 { 84, { 0xffb5 , Qt::Key_5 }},
360 { 85, { 0xffb6 , Qt::Key_6 }},
361 { 86, { 0xffab , Qt::Key_Plus }},
362 { 87, { 0xffb1 , Qt::Key_1 }},
363 { 88, { 0xffb2 , Qt::Key_2 }},
364 { 89, { 0xffb3 , Qt::Key_3 }},
365 { 90, { 0xffb0 , Qt::Key_0 }},
366 { 91, { 0xffae , Qt::Key_Period }},
367 { 95, { 0xffc8 , Qt::Key_F11 }},
368 { 96, { 0xffc9 , Qt::Key_F12 }},
369 {104, { 0xff8d , Qt::Key_Enter }},
370 {105, { 0xffe4 , Qt::Key_Control }},
371 {106, { 0xffaf , Qt::Key_Slash }},
372 {108, { 0xffea , Qt::Key_Alt }},
373 {110, { 0xff50 , Qt::Key_Home }},
374 {111, { 0xff52 , Qt::Key_Up }},
375 {112, { 0xff55 , Qt::Key_PageUp }},
376 {113, { 0xff51 , Qt::Key_Left }},
377 {114, { 0xff53 , Qt::Key_Right }},
378 {115, { 0xff57 , Qt::Key_End }},
379 {116, { 0xff54 , Qt::Key_Down }},
380 {117, { 0xff56 , Qt::Key_PageDown }},
381 {118, { 0xff63 , Qt::Key_Insert }},
382 {119, { 0xffff , Qt::Key_Delete }},
383 {127, { 0xff13 , Qt::Key_Pause }},
384 {134, { 0xffec , Qt::Key_Meta }},
385 #endif
386 };
71387 #endif
72388
73389 SDL_Scancode convQtKey2SDLScanCode(Qt::Key q, uint32_t nativeVirtualKey)
13541670
13551671 vkey = event->nativeVirtualKey();
13561672
1673 // auto nsc = event->nativeScanCode();
1674 // qDebug() << __PRETTY_FUNCTION__ << nsc << vkey << event->key();
1675
13571676 sdlev.key.keysym.sym = convQtKey2SDLKeyCode((Qt::Key)event->key(), vkey);
13581677
13591678 sdlev.key.keysym.scancode = SDL_GetScancodeFromKey(sdlev.key.keysym.sym);
13841703
13851704 //printf("Modifiers: %08X -> %08X \n", event->modifiers(), sdlev.key.keysym.mod );
13861705
1706 /* when we're unable to convert qt keys to sdl, we do keyboard native scan code conversion */
1707 if (sdlev.key.keysym.scancode == SDL_SCANCODE_UNKNOWN)
1708 {
1709 int nativeKey = event->nativeScanCode();
1710 auto value = s_nativeScanCodesMap.value (nativeKey, _KeyValue {0, 0});
1711 if (value.key != 0 && value.vkey != 0)
1712 {
1713 sdlev.key.keysym.sym = convQtKey2SDLKeyCode ((Qt::Key)value.key, value.vkey);
1714 sdlev.key.keysym.scancode = SDL_GetScancodeFromKey (sdlev.key.keysym.sym);
1715 }
1716 }
1717
13871718 if (sdlev.key.keysym.scancode != SDL_SCANCODE_UNKNOWN)
13881719 {
13891720 SDL_PushEvent(&sdlev);
4242 switch (type)
4343 {
4444 case QtDebugMsg:
45 sprintf( cmsg, "Qt Debug: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
45 snprintf( cmsg, sizeof(cmsg), "Qt Debug: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
4646 FCEUD_Message(cmsg);
4747 break;
4848 case QtInfoMsg:
49 sprintf( cmsg, "Qt Info: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
49 snprintf( cmsg, sizeof(cmsg), "Qt Info: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
5050 FCEUD_Message(cmsg);
5151 break;
5252 case QtWarningMsg:
53 sprintf( cmsg, "Qt Warning: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
53 snprintf( cmsg, sizeof(cmsg), "Qt Warning: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
5454 FCEUD_Message(cmsg);
5555 break;
5656 case QtCriticalMsg:
57 sprintf( cmsg, "Qt Critical: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
57 snprintf( cmsg, sizeof(cmsg), "Qt Critical: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
5858 FCEUD_PrintError(cmsg);
5959 break;
6060 case QtFatalMsg:
61 sprintf( cmsg, "Qt Fatal: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
61 snprintf( cmsg, sizeof(cmsg), "Qt Fatal: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
6262 FCEUD_PrintError(cmsg);
6363 break;
6464 }
65 cmsg[sizeof(cmsg)-1] = 0;
6566 fprintf(stderr, "%s", cmsg );
6667 }
6768
9495
9596 int main( int argc, char *argv[] )
9697 {
97 int retval;
98 int retval = 0;
99
100 fceuWrapperPreInit(argc, argv);
101
98102 qInstallMessageHandler(MessageOutput);
99103 QApplication app(argc, argv);
100104
2828 #define EO_SUBASE 2
2929 #define EO_CLIPSIDES 8
3030 #define EO_SNAPNAME 16
31 #define EO_FOURSCORE 32
3231 #define EO_NOTHROTTLE 64
3332 #define EO_GAMEGENIE 128
3433 #define EO_PAL 256
3534 #define EO_LOWPASS 512
3635 #define EO_AUTOHIDE 1024
36 #define EO_FOURSCORE 32768 // for compatibility with non-Qt
3737
3838 extern int _sound;
3939 extern long soundrate;
11321132
11331133 xx = 0; yy = 0;
11341134
1135 showSelector = (cycleCount < 20);
1135 showSelector = (cycleCount < 20) && (selTile.x() >= 0) && (selTile.y() >= 0);
11361136
11371137 if ( mode == 1 )
11381138 {
4141 static unsigned int s_BufferSize75;
4242 static unsigned int s_BufferRead;
4343 static unsigned int s_BufferWrite;
44 static volatile unsigned int s_BufferIn;
44 static volatile unsigned int s_BufferIn = 0;
4545 static unsigned int s_SampleRate = 44100;
4646 static double noiseGate = 0.0;
4747 static double noiseGateRate = 0.010;
4848 static bool noiseGateActive = true;
49 static bool muteSoundOutput = false;
49 static bool windowSoundMute = false;
5050 static bool fillInit = 1;
51
52 static int s_mute = 0;
51 static const unsigned int supportedSampleRates[] = { 11025, 22050, 44100, 48000, 96000, 0 };
52
53 static bool s_mute = false;
5354
5455 extern int EmulationPaused;
5556 extern double frmRateAdjRatio;
9899 noiseGateActive = 1;
99100 return;
100101 }
101 mute = EmulationPaused || muteSoundOutput;
102 mute = EmulationPaused || windowSoundMute || s_mute;
102103
103104 if ( mute || noiseGateActive )
104105 {
185186 int
186187 InitSound()
187188 {
188 int sound, soundrate, soundbufsize, soundvolume, soundtrianglevolume, soundsquare1volume, soundsquare2volume, soundnoisevolume, soundpcmvolume, soundq;
189 int i, sound, soundrate, soundbufsize, soundvolume, soundtrianglevolume, soundsquare1volume, soundsquare2volume, soundnoisevolume, soundpcmvolume, soundq;
189190 SDL_AudioSpec spec;
190191 const char *driverName;
191192 int frmRateSampleAdj = 0;
192193 int samplesPerFrame;
194 bool sampleRateIsSupported = false;
193195
194196 g_config->getOption("SDL.Sound", &sound);
195197 if (!sound)
206208 }
207209
208210 // load configuration variables
211 g_config->getOption("SDL.Sound.Mute", &s_mute);
209212 g_config->getOption("SDL.Sound.Rate", &soundrate);
210213 g_config->getOption("SDL.Sound.BufSize", &soundbufsize);
211214 g_config->getOption("SDL.Sound.Volume", &soundvolume);
216219 g_config->getOption("SDL.Sound.NoiseVolume", &soundnoisevolume);
217220 g_config->getOption("SDL.Sound.PCMVolume", &soundpcmvolume);
218221
222 i = 0;
223 while (supportedSampleRates[i] != 0)
224 {
225 if ( static_cast<unsigned int>(soundrate) == supportedSampleRates[i])
226 {
227 sampleRateIsSupported = true;
228 break;
229 }
230 i++;
231 }
232
233 if (!sampleRateIsSupported)
234 {
235 printf("Error: Audio Sample Rate %i is either invalid or not supported, reverting to default of 44100\n", soundrate);
236 soundrate = 44100;
237 g_config->setOption("SDL.Sound.Rate", soundrate);
238 }
239
240 if ( (soundbufsize < 15) || (soundbufsize > 200) )
241 {
242 printf("Error: Audio Buffer Size of %i ms is invalid, reverting to default of 128\n", soundbufsize);
243 soundbufsize = 128;
244 g_config->setOption("SDL.Sound.BufSize", soundbufsize);
245 }
246
219247 spec.freq = s_SampleRate = soundrate;
220248 spec.format = AUDIO_S16SYS;
221249 spec.channels = 1;
233261 s_BufferSize = soundbufsize * soundrate / 1000;
234262
235263 // For safety, set a bare minimum:
236 if (s_BufferSize < spec.samples * 4)
264 if (s_BufferSize < static_cast<unsigned int>(spec.samples * 4))
237265 {
238266 s_BufferSize = spec.samples * 4;
239267 }
491519 free((void *)s_Buffer);
492520 s_Buffer = 0;
493521 }
522 s_BufferIn = 0;
494523 return 0;
495524 }
496525
523552 break;
524553 }
525554
526 s_mute = 0;
555 s_mute = false;
556 g_config->setOption("SDL.Sound.Mute", s_mute);
557
527558 FCEUI_SetSoundVolume(soundvolume);
528559 g_config->setOption("SDL.Sound.Volume", soundvolume);
529560
536567 void
537568 FCEUD_SoundToggle(void)
538569 {
539 if(s_mute) {
540 int soundvolume;
541 g_config->getOption("SDL.SoundVolume", &soundvolume);
542
543 s_mute = 0;
544 FCEUI_SetSoundVolume(soundvolume);
545 FCEU_DispMessage("Sound mute off.",0);
546 } else {
547 s_mute = 1;
548 FCEUI_SetSoundVolume(0);
549 FCEU_DispMessage("Sound mute on.",0);
550 }
570 FCEUD_MuteSoundOutput( !s_mute );
571 }
572
573 bool FCEUD_SoundIsMuted(void)
574 {
575 return s_mute;
551576 }
552577
553578 void FCEUD_MuteSoundOutput( bool value )
554579 {
555 muteSoundOutput = value;
556 }
580 if (value != s_mute)
581 {
582 g_config->setOption("SDL.Sound.Mute", value);
583
584 if (value)
585 {
586 FCEU_DispMessage("Sound mute on.",0);
587 }
588 else
589 {
590 FCEU_DispMessage("Sound mute off.",0);
591 }
592 }
593 s_mute = value;
594 }
595
596 // This function is used by the GUI to mute sound when main window is not in focus.
597 void FCEUD_MuteSoundWindow( bool value )
598 {
599 windowSoundMute = value;
600 }
3636 #include "Qt/sdl-video.h"
3737 #include "Qt/AviRecord.h"
3838 #include "Qt/fceuWrapper.h"
39 #include "Qt/ConsoleWindow.h"
3940
4041 #ifdef CREATE_AVI
4142 #include "../videolog/nesvideos-piece.h"
7374 extern int input_display;
7475 extern int frame_display;
7576 extern int rerecord_display;
77 extern uint8 PALRAM[0x20];
7678
7779 /**
7880 * Attempts to destroy the graphical video display. Returns 0 on
497499 {
498500 int i = nes_shm->pixBufIdx;
499501
502 if (usePaletteForVideoBg)
503 {
504 unsigned char r, g, b;
505 FCEUD_GetPalette(0x80 | PALRAM[0], &r, &g, &b);
506
507 if (consoleWindow)
508 {
509 QColor *bgColor = consoleWindow->getVideoBgColorPtr();
510
511 *bgColor = QColor::fromRgb(r,g,b);
512 }
513 }
514
500515 doBlitScreen(XBuf, (uint8_t*)nes_shm->pixbuf[i]);
501516
502517 nes_shm->pixBufIdx = (i+1) % NES_VIDEO_BUFLEN;
119119 if(TSocket < 0) {
120120 const char* s = "Error creating stream socket.";
121121 puts(s);
122 FCEU_DispMessage(s,0);
122 FCEU_DispMessage("%s",0,s);
123123 FCEUD_NetworkClose();
124124 return 0;
125125 }
302302 size = recv(s_Socket, data, len, MSG_WAITALL);
303303 #endif
304304
305 if(size == len) {
305 if( static_cast<uint32>(size) == len) {
306306 //unsigned long beefie;
307307
308308 FD_ZERO(&funfun);
2525 static void GetString(char *s, int max)
2626 {
2727 int x;
28 fgets(s,max,stdin);
28 if ( fgets(s,max,stdin) == nullptr )
29 {
30 s[0] = 0;
31 return;
32 }
2933
3034 for(x=0;x<max;x++)
3135 if(s[x]=='\n')
4044 {
4145 char buf[32];
4246
43 fgets(buf,ARRAY_SIZE(buf),stdin);
47 if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr )
48 {
49 return def;
50 }
4451 if(buf[0]=='\n')
4552 return(def);
4653 if(buf[0]=='$')
5562 {
5663 char buf[32];
5764
58 fgets(buf,ARRAY_SIZE(buf),stdin);
65 if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr )
66 {
67 return def;
68 }
5969 if(buf[0]=='\n')
6070 return(def);
6171 sscanf(buf,"%u",&def);
6676 {
6777 char buf[32];
6878
69 fgets(buf,ARRAY_SIZE(buf),stdin);
79 if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr )
80 {
81 return def;
82 }
7083 if(buf[0]=='\n')
7184 return(def);
7285 sscanf(buf,"%d",&def);
7790 {
7891 char buf[32];
7992 printf("(Y/N)[%s]: ",def?"Y":"N");
80 fgets(buf,ARRAY_SIZE(buf),stdin);
93 if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr )
94 {
95 return def;
96 }
8197 if(buf[0]=='y' || buf[0]=='Y')
8298 return(1);
8399 if(buf[0]=='n' || buf[0]=='N')
113129
114130 tryagain:
115131 printf(" <'Enter' to continue, (S)top, or enter a number.> ");
116 fgets(buf,ARRAY_SIZE(buf),stdin);
132 if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr )
133 {
134 return -1;
135 }
117136 if(buf[0]=='s' || buf[0]=='S') return(-1);
118137 if(buf[0]=='\n') return(0);
119138 if(!sscanf(buf,"%d",&num))
127146
128147 tryagain2:
129148 printf(" <'Enter' to make no selection or enter a number.> ");
130 fgets(buf,ARRAY_SIZE(buf),stdin);
149 if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr )
150 {
151 return -1;
152 }
131153 if(buf[0]=='\n') return(0);
132154 if(!sscanf(buf,"%d",&num))
133155 return(0);
198220
199221 static void ModifyCheat(int num)
200222 {
201 char *name;
223 std::string name;
224 std::string *pName;
202225 char buf[256];
203226 uint32 A;
204227 uint8 V;
210233
211234 FCEUI_GetCheat(num, &name, &A, &V, &compare, &s, &type);
212235
213 printf("Name [%s]: ",name);
236 printf("Name [%s]: ",name.c_str());
214237 GetString(buf,256);
215238
216239 /* This obviously doesn't allow for cheats with no names. Bah. Who wants
218241 */
219242
220243 if(buf[0])
221 name=buf; // Change name when FCEUI_SetCheat() is called.
244 pName=&name; // Change name when FCEUI_SetCheat() is called.
222245 else
223 name=0; // Don't change name when FCEUI_SetCheat() is called.
246 pName=nullptr; // Don't change name when FCEUI_SetCheat() is called.
224247
225248 printf("Address [$%04x]: ",(unsigned int)A);
226249 A=GetH16(A);
239262 if(t=='Y' || t=='y') s=1;
240263 else if(t=='N' || t=='n') s=0;
241264
242 FCEUI_SetCheat(num,name,A,V,compare,s,type);
265 FCEUI_SetCheat(num,pName,A,V,compare,s,type);
243266 }
244267
245268
319342 }
320343
321344 static int lid;
322 static int clistcallb(char *name, uint32 a, uint8 v, int compare, int s, int type, void *data)
345 static int clistcallb(const char *name, uint32 a, uint8 v, int compare, int s, int type, void *data)
323346 {
324347 char tmp[512];
325348 int ret;
347370 {
348371 char tmp[32];
349372 printf(" <(T)oggle status, (M)odify, or (D)elete this cheat.> ");
350 fgets(tmp,ARRAY_SIZE(tmp),stdin);
373 if ( fgets(tmp,ARRAY_SIZE(tmp),stdin) == nullptr )
374 {
375 tmp[0] = 0;
376 }
351377 switch(tolower(tmp[0]))
352378 {
353379 case 't':ToggleCheat(which);
404430 clo:
405431
406432 printf("\nSelection [%d]> ",def+1);
407 fgets(tmp,ARRAY_SIZE(tmp),stdin);
433 if ( fgets(tmp,ARRAY_SIZE(tmp),stdin) == nullptr )
434 {
435 return def;
436 }
408437 if(tmp[0]=='\n')
409438 return def;
410439 c=tolower(tmp[0]);
503532
504533 recommand:
505534 printf("Command> ");
506 fgets(buf,ARRAY_SIZE(buf),stdin);
535 if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr )
536 {
537 return;
538 }
507539 c=tolower(buf[0]);
508540 if(c=='\n')
509541 goto recommand;
144144 {
145145 if(!c) // String, allocate some memory.
146146 {
147 // Windows enforces a 32767 character limit for text boxes by default
148 // If a string exceeds this length, it's probably a corrupt file
149 if (s > 32768)
150 goto gogl;
151
147152 if(!(*(char **)v=(char*)malloc(s)))
148153 goto gogl;
149154
207212 if(*(char **)cfgst[x].ptr)
208213 {
209214 // Only save it if there IS a string.
210 unsigned int len = strlen(*(char **)cfgst[x].ptr);
215 size_t len = strlen(*(char **)cfgst[x].ptr);
211216 SetValueR(fp,cfgst[x].name,*(char **)cfgst[x].ptr, len + 1);
212217 }
213218 }
640640 int
641641 Config::_loadFile(const char* fname)
642642 {
643 signed int pos, eqPos;
643 size_t pos=0, eqPos=0;
644644 std::fstream config;
645645 std::map<std::string, int>::iterator int_i;
646646 std::map<std::string, double>::iterator dbl_i;
655655 configFile = fname;
656656 }
657657 std::string line, name, value;
658 char buf[1024];
658 char buf[4096];
659659
660660 // set the exception handling to catch i/o errors
661661 config.exceptions(std::fstream::badbit);
670670
671671 while(!config.eof()) {
672672 // read a line
673 config.getline(buf, 1024);
673 config.getline(buf, sizeof(buf));
674674 line = buf;
675675
676676 // check line validity
722722 std::map<std::string, double>::iterator dbl_i;
723723 std::map<std::string, std::string>::iterator str_i;
724724 std::string configFile = _dir + "/" + cfgFile;
725 char buf[1024];
725 char buf[4096];
726726
727727 // set the exception handling to catch i/o errors
728728 config.exceptions(std::ios::failbit | std::ios::badbit);
740740 // write each configuration setting
741741 for(int_i = _intOptMap.begin(); int_i != _intOptMap.end(); int_i++)
742742 {
743 snprintf(buf, 1024, "%s = %d\n",
743 snprintf(buf, sizeof(buf), "%s = %d\n",
744744 int_i->first.c_str(), int_i->second);
745745 config.write(buf, strlen(buf));
746746 }
747747 for(dbl_i = _dblOptMap.begin(); dbl_i != _dblOptMap.end(); dbl_i++)
748748 {
749 snprintf(buf, 1024, "%s = %f\n",
749 snprintf(buf, sizeof(buf), "%s = %f\n",
750750 dbl_i->first.c_str(), dbl_i->second);
751751 config.write(buf, strlen(buf));
752752 }
753753 for(str_i = _strOptMap.begin(); str_i != _strOptMap.end(); str_i++)
754754 {
755 snprintf(buf, 1024, "%s = %s\n",
755 snprintf(buf, sizeof(buf), "%s = %s\n",
756756 str_i->first.c_str(), str_i->second.c_str());
757757 config.write(buf, strlen(buf));
758758 }
237237 {
238238 if(palettetranslate)
239239 {
240 free(palettetranslate);
240 FCEU_free(palettetranslate);
241241 palettetranslate=NULL;
242242 }
243243
244244 if(specbuf8bpp)
245245 {
246 free(specbuf8bpp);
246 FCEU_free(specbuf8bpp);
247247 specbuf8bpp = NULL;
248248 }
249249 if(specbuf32bpp)
250250 {
251 free(specbuf32bpp);
251 FCEU_free(specbuf32bpp);
252252 specbuf32bpp = NULL;
253253 }
254254 if(specbuf)
258258 hq3x_Kill();
259259 else
260260 hq2x_Kill();
261 free(specbuf);
261 FCEU_free(specbuf);
262262 specbuf=NULL;
263263 }
264264 if (nes_ntsc) {
265 free(nes_ntsc);
265 FCEU_free(nes_ntsc);
266266 nes_ntsc = NULL;
267267 }
268268 if (ntscblit) {
465465 /* Todo: Make sure 24bpp code works right with big-endian cpus */
466466
467467 //takes a pointer to XBuf and applies fully modern deemph palettizing
468 template<int SCALE> static u32 _ModernDeemphColorMap(u8* src, u8* srcbuf)
468 template<int SCALE> static u32 _ModernDeemphColorMap(const u8* src, const u8* srcbuf)
469469 {
470470 u8 pixel = *src;
471471
491491 return color;
492492 }
493493
494 u32 ModernDeemphColorMap(u8* src, u8* srcbuf, int scale)
494 u32 ModernDeemphColorMap(const u8* src, const u8* srcbuf, int scale)
495495 {
496496 if(scale == 1) return _ModernDeemphColorMap<1>(src,srcbuf);
497497 else if(scale == 2) return _ModernDeemphColorMap<2>(src,srcbuf);
502502 else if(scale == 7) return _ModernDeemphColorMap<7>(src,srcbuf);
503503 else if(scale == 8) return _ModernDeemphColorMap<8>(src,srcbuf);
504504 else if(scale == 9) return _ModernDeemphColorMap<9>(src,srcbuf);
505 else { abort(); return 0; }
506 }
507
508 typedef u32 (*ModernDeemphColorMapFuncPtr)( u8*, u8* );
505 else { FCEU_abort("unhandled ModernDeemphColorMap scale"); return 0; }
506 }
507
508 typedef u32 (*ModernDeemphColorMapFuncPtr)( const u8*, const u8* );
509509
510510 static ModernDeemphColorMapFuncPtr getModernDeemphColorMapFunc(int scale)
511511 {
512 ModernDeemphColorMapFuncPtr ptr = NULL;
512 ModernDeemphColorMapFuncPtr ptr;
513513
514514 if(scale == 1) ptr = &_ModernDeemphColorMap<1>;
515515 else if(scale == 2) ptr = &_ModernDeemphColorMap<2>;
520520 else if(scale == 7) ptr = &_ModernDeemphColorMap<7>;
521521 else if(scale == 8) ptr = &_ModernDeemphColorMap<8>;
522522 else if(scale == 9) ptr = &_ModernDeemphColorMap<9>;
523 else { abort(); ptr = NULL; }
523 else { FCEU_abort("unhandled ModernDeemphColorMap scale"); ptr = nullptr; }
524524
525525 return ptr;
526526 }
2828 int shiftr[3], int shiftl[3]);
2929
3030
31 u32 ModernDeemphColorMap(u8* src, u8* srcbuf, int scale);
31 u32 ModernDeemphColorMap(const u8* src, const u8* srcbuf, int scale);
17081708 }
17091709 }
17101710
1711 void FCEUD_FlushTrace()
1712 {
1713 // Place holder to allow for compiling. GTK GUI doesn't support this. Qt Does.
1714 }
1715
17111716 void FCEUD_TraceInstruction(uint8 *opcode, int size)
17121717 {
17131718 // Place holder to allow for compiling. GTK GUI doesn't support this. Qt Does.
276276 {
277277 if (addr < 16)
278278 {
279 fprintf( stdout, "You can't edit ROM header here, however you can use iNES Header Editor to edit the header if it's an iNES format file.");
279 fprintf( stdout, "You can't edit ROM header here, however you can use NES Header Editor to edit the header if it's an iNES or NES2.0 format file.");
280280 }
281281 else if ( (addr >= 16) && (addr < PRGsize[0]+16) )
282282 {
528528 /**
529529 * Unimplemented.
530530 */
531 void FCEUD_FlushTrace()
532 {
533 }
534
535 /**
536 * Unimplemented.
537 */
531538 void FCEUD_TraceInstruction() {
532539 return;
533540 }
2222 #include "emufile.h"
2323 #include "utils/xstring.h"
2424
25 #include <stdio.h>
2526 #include <vector>
2627
2728 bool EMUFILE::readAllBytes(std::vector<u8>* dstbuf, const std::string& fname)
2829 {
2930 EMUFILE_FILE file(fname.c_str(),"rb");
3031 if(file.fail()) return false;
31 int size = file.size();
32 size_t size = file.size();
3233 dstbuf->resize(size);
3334 file.fread(&dstbuf->at(0),size);
3435 return true;
3536 }
3637
3738 size_t EMUFILE_MEMORY::_fread(const void *ptr, size_t bytes){
38 u32 remain = len-pos;
39 u32 todo = std::min<u32>(remain,(u32)bytes);
39 size_t remain = len-pos;
40 size_t todo = std::min<size_t>(remain,bytes);
4041 if(len==0)
4142 {
4243 failbit = true;
7778 }
7879
7980
80 void EMUFILE_FILE::truncate(s32 length)
81 void EMUFILE_FILE::truncate(size_t length)
8182 {
8283 ::fflush(fp);
8384 #ifdef _MSC_VER
8485 _chsize(_fileno(fp),length);
8586 #else
86 ftruncate(fileno(fp),length);
87 if ( ftruncate(fileno(fp),length) != 0 )
88 {
89 printf("Warning: EMUFILE_FILE::truncate failed\n");
90 }
8791 #endif
8892 // this is probably wrong if mode is "wb"
8993 fclose(fp);
5858 bool fail(bool unset=false) { bool ret = failbit; if(unset) unfail(); return ret; }
5959 void unfail() { failbit=false; }
6060
61 bool eof() { return size()==ftell(); }
61 bool eof() { return size() == static_cast<size_t>(ftell()); }
6262
6363 size_t fread(const void *ptr, size_t bytes){
6464 return _fread(ptr,bytes);
108108 double readdouble();
109109 size_t readdouble(double* val);
110110
111 virtual int fseek(int offset, int origin) = 0;
112
113 virtual int ftell() = 0;
114 virtual int size() = 0;
111 virtual int fseek(long int offset, int origin) = 0;
112
113 virtual long int ftell() = 0;
114 virtual size_t size() = 0;
115115 virtual void fflush() = 0;
116116
117 virtual void truncate(s32 length) = 0;
117 virtual void truncate(size_t length) = 0;
118118 };
119119
120120 //todo - handle read-only specially?
122122 protected:
123123 std::vector<u8> *vec;
124124 bool ownvec;
125 s32 pos, len;
126
127 void reserve(u32 amt) {
125 long int pos;
126 size_t len;
127
128 void reserve(size_t amt) {
128129 if(vec->size() < amt)
129130 vec->resize(amt);
130131 }
132133 public:
133134
134135 EMUFILE_MEMORY(std::vector<u8> *underlying) : vec(underlying), ownvec(false), pos(0), len((s32)underlying->size()) { }
135 EMUFILE_MEMORY(u32 preallocate) : vec(new std::vector<u8>()), ownvec(true), pos(0), len(0) {
136 EMUFILE_MEMORY(size_t preallocate) : vec(new std::vector<u8>()), ownvec(true), pos(0), len(0) {
136137 vec->resize(preallocate);
137138 len = preallocate;
138139 }
139140 EMUFILE_MEMORY() : vec(new std::vector<u8>()), ownvec(true), pos(0), len(0) { vec->reserve(1024); }
140 EMUFILE_MEMORY(void* buf, s32 size) : vec(new std::vector<u8>()), ownvec(true), pos(0), len(size) {
141 EMUFILE_MEMORY(void* buf, size_t size) : vec(new std::vector<u8>()), ownvec(true), pos(0), len(size) {
141142 vec->resize(size);
142143 if(size != 0)
143144 memcpy(&vec->front(),buf,size);
149150
150151 virtual EMUFILE* memwrap();
151152
152 virtual void truncate(s32 length)
153 virtual void truncate(size_t length)
153154 {
154155 vec->resize(length);
155156 len = length;
156 if(pos>length) pos=length;
157 if (static_cast<size_t>(pos) > length) pos=static_cast<long int>(length);
157158 }
158159
159160 u8* buf() {
191192 //if(_fread(&temp,1) != 1)
192193 // return EOF;
193194 //else return temp;
194 u32 remain = len-pos;
195 size_t remain = len-pos;
195196 if(remain<1) {
196197 failbit = true;
197198 return -1;
215216 //they handle the return values correctly
216217
217218 virtual void fwrite(const void *ptr, size_t bytes){
218 reserve(pos+(s32)bytes);
219 reserve(pos+bytes);
219220 memcpy(buf()+pos,ptr,bytes);
220 pos += (s32)bytes;
221 len = std::max<int>(pos,len);
222 }
223
224 virtual int fseek(int offset, int origin){
221 pos += static_cast<long>(bytes);
222 len = std::max<size_t>(pos,len);
223 }
224
225 virtual int fseek(long int offset, int origin){
225226 //work differently for read-only...?
226227 switch(origin) {
227228 case SEEK_SET:
231232 pos += offset;
232233 break;
233234 case SEEK_END:
234 pos = size()+offset;
235 pos = (long int)(size()+offset);
235236 break;
236237 default:
237238 assert(false);
240241 return 0;
241242 }
242243
243 virtual int ftell() {
244 virtual long int ftell() {
244245 return pos;
245246 }
246247
247248 virtual void fflush() {}
248249
249 void set_len(s32 length)
250 void set_len(size_t length)
250251 {
251252 len = length;
252 if(pos > length)
253 pos = length;
253 if (static_cast<size_t>(pos) > length)
254 pos = static_cast<long>(length);
254255 }
255256 void trim()
256257 {
257258 vec->resize(len);
258259 }
259260
260 virtual int size() { return (int)len; }
261 virtual size_t size() { return len; }
261262 };
262263
263264 class EMUFILE_FILE : public EMUFILE {
287288
288289 bool is_open() { return fp != NULL; }
289290
290 virtual void truncate(s32 length);
291 virtual void truncate(size_t length);
291292
292293 virtual int fprintf(const char *format, ...) {
293294 va_list argptr;
320321 failbit = true;
321322 }
322323
323 virtual int fseek(int offset, int origin) {
324 virtual int fseek(long int offset, int origin) {
324325 return ::fseek(fp, offset, origin);
325326 }
326327
327 virtual int ftell() {
328 return (u32)::ftell(fp);
329 }
330
331 virtual int size() {
332 int oldpos = ftell();
328 virtual long int ftell() {
329 return ::ftell(fp);
330 }
331
332 virtual size_t size() {
333 long int oldpos = ftell();
333334 fseek(0,SEEK_END);
334 int len = ftell();
335 long int len = ftell();
335336 fseek(oldpos,SEEK_SET);
336 return len;
337 return static_cast<size_t>(len);
337338 }
338339
339340 virtual void fflush() {
180180 }
181181
182182 #ifdef __WIN_DRIVER__
183 extern char LoadedRomFName[2048];
184183 if (storePreferences(mass_replace(LoadedRomFName, "|", ".").c_str()))
185184 FCEUD_PrintError("Couldn't store debugging data");
186185 CDLoggerROMClosed();
225224 currFrameCounter = 0;
226225
227226 //Reset flags for Undo/Redo/Auto Savestating //adelikat: TODO: maybe this stuff would be cleaner as a struct or class
228 lastSavestateMade[0] = 0;
227 lastSavestateMade.clear();
229228 undoSS = false;
230229 redoSS = false;
231 lastLoadstateMade[0] = 0;
230 lastLoadstateMade.clear();
232231 undoLS = false;
233232 redoLS = false;
234233 AutoSS = false;
420419 //----------
421420 //attempt to open the files
422421 FCEUFILE *fp;
423 char fullname[2048]; // this name contains both archive name and ROM file name
422 std::string fullname; // this name contains both archive name and ROM file name
424423 int lastpal = PAL;
425424 int lastdendy = dendy;
426425
430429 // currently there's only one situation:
431430 // the user clicked cancel form the open from archive dialog
432431 int userCancel = 0;
433 fp = FCEU_fopen(name, 0, "rb", 0, -1, romextensions, &userCancel);
432 fp = FCEU_fopen(name, LoadedRomFNamePatchToUse[0] ? LoadedRomFNamePatchToUse : nullptr, "rb", 0, -1, romextensions, &userCancel);
434433
435434 if (!fp)
436435 {
442441 }
443442 else if (fp->archiveFilename != "")
444443 {
445 strcpy(fullname, fp->archiveFilename.c_str());
446 strcat(fullname, "|");
447 strcat(fullname, fp->filename.c_str());
448 } else
449 strcpy(fullname, name);
444 fullname.assign(fp->archiveFilename.c_str());
445 fullname.append("|");
446 fullname.append(fp->filename.c_str());
447 }
448 else
449 {
450 fullname.assign(name);
451 }
450452
451453 // reset loaded game BEFORE it's loading.
452454 ResetGameLoaded();
453455 //file opened ok. start loading.
454 FCEU_printf("Loading %s...\n\n", fullname);
456 FCEU_printf("Loading %s...\n\n", fullname.c_str());
455457 GetFileBase(fp->filename.c_str());
456458 //reset parameters so they're cleared just in case a format's loader doesn't know to do the clearing
457459 MasterRomInfoParams = TMasterRomInfoParams();
483485 bool FCEUXLoad(const char *name, FCEUFILE * fp);
484486
485487 int load_result;
486 load_result = iNESLoad(fullname, fp, OverwriteVidMode);
488 load_result = iNESLoad(fullname.c_str(), fp, OverwriteVidMode);
487489 if (load_result == LOADER_INVALID_FORMAT)
488490 {
489 load_result = NSFLoad(fullname, fp);
491 load_result = NSFLoad(fullname.c_str(), fp);
490492 if (load_result == LOADER_INVALID_FORMAT)
491493 {
492 load_result = UNIFLoad(fullname, fp);
494 load_result = UNIFLoad(fullname.c_str(), fp);
493495 if (load_result == LOADER_INVALID_FORMAT)
494496 {
495 load_result = FDSLoad(fullname, fp);
497 load_result = FDSLoad(fullname.c_str(), fp);
496498 }
497499 }
498500 }
501503
502504 #ifdef __WIN_DRIVER__
503505 // ################################## Start of SP CODE ###########################
504 extern char LoadedRomFName[2048];
505506 extern int loadDebugDataFailed;
506507
507508 if ((loadDebugDataFailed = loadPreferences(mass_replace(LoadedRomFName, "|", ".").c_str())))
724725 ///Skip may be passed in, if FRAMESKIP is #defined, to cause this to emulate more than one frame
725726 void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int skip) {
726727 //skip initiates frame skip if 1, or frame skip and sound skip if 2
727 int r, ssize;
728 FCEU_MAYBE_UNUSED int r;
729 int ssize;
728730
729731 JustFrameAdvanced = false;
730732
741743 {
742744 EmulationPaused = EMULATIONPAUSED_FA;
743745 }
744 if (frameAdvance_Delay_count < frameAdvanceDelayScaled)
746 if ( static_cast<unsigned int>(frameAdvance_Delay_count) < frameAdvanceDelayScaled)
745747 {
746748 frameAdvance_Delay_count++;
747749 }
806808 r = FCEUPPU_Loop(skip);
807809
808810 if (skip != 2) ssize = FlushEmulateSound(); //If skip = 2 we are skipping sound processing
811
812 //flush tracer once a frame, since we're likely to end up back at a user interaction loop after this with emulation paused
813 FCEUD_FlushTrace();
809814
810815 #ifdef _S9XLUA_H
811816 CallRegisteredLuaFunctions(LUACALL_AFTEREMULATION);
10601065
10611066 FCEUS FSettings;
10621067
1063 void FCEU_printf(const char *format, ...)
1068 void FCEU_printf( __FCEU_PRINTF_FORMAT const char *format, ...)
10641069 {
10651070 char temp[2048];
10661071
10801085 va_end(ap);
10811086 }
10821087
1083 void FCEU_PrintError(const char *format, ...)
1088 void FCEU_PrintError( __FCEU_PRINTF_FORMAT const char *format, ...)
10841089 {
10851090 char temp[2048];
10861091
12271232 //ideally maybe we shouldnt be using this, but i need it for quick merging
12281233 void FCEUI_SetEmulationPaused(int val) {
12291234 EmulationPaused = val;
1235 if(EmulationPaused)
1236 FCEUD_FlushTrace();
12301237 }
12311238
12321239 void FCEUI_ToggleEmulationPause(void)
12331240 {
12341241 EmulationPaused = (EmulationPaused & EMULATIONPAUSED_PAUSED) ^ EMULATIONPAUSED_PAUSED;
12351242 DebuggerWasUpdated = false;
1243 if(EmulationPaused)
1244 FCEUD_FlushTrace();
12361245 }
12371246
12381247 void FCEUI_FrameAdvanceEnd(void) {
12401249 }
12411250
12421251 void FCEUI_FrameAdvance(void) {
1252 frameAdvance_Delay_count = 0;
12431253 frameAdvanceRequested = true;
1244 frameAdvance_Delay_count = 0;
12451254 }
12461255
12471256 static int AutosaveCounter = 0;
12581267 FCEUSS_Save(f, false);
12591268 AutoSS = true; //Flag that an auto-savestate was made
12601269 free(f);
1261 f = NULL;
1270 f = NULL;
12621271 AutosaveStatus[AutosaveIndex] = 1;
12631272 }
12641273 }
138138
139139 bool CheckFileExists(const char* filename); //Receives a filename (fullpath) and checks to see if that file exists
140140
141 void FCEU_PrintError(const char *format, ...);
142 void FCEU_printf(const char *format, ...);
143 void FCEU_DispMessage(const char *format, int disppos, ...);
144 void FCEU_DispMessageOnMovie(const char *format, ...);
141 void FCEU_PrintError( __FCEU_PRINTF_FORMAT const char *format, ...) __FCEU_PRINTF_ATTRIBUTE( 1, 2 );
142 void FCEU_printf( __FCEU_PRINTF_FORMAT const char *format, ...) __FCEU_PRINTF_ATTRIBUTE( 1, 2 );
143 void FCEU_DispMessage( __FCEU_PRINTF_FORMAT const char *format, int disppos, ...) __FCEU_PRINTF_ATTRIBUTE( 1, 3 );
144 void FCEU_DispMessageOnMovie( __FCEU_PRINTF_FORMAT const char *format, ...) __FCEU_PRINTF_ATTRIBUTE( 1, 2 );
145145 void FCEU_TogglePPU();
146146
147147 void SetNESDeemph_OldHacky(uint8 d, int force);
2828 #include "state.h"
2929 #include "file.h"
3030 #include "cart.h"
31 #include "ines.h"
3132 #include "netplay.h"
3233 #include "driver.h"
3334 #include "movie.h"
222223 FCEU_DispMessage("Disk %d Side %c Selected", 0, SelectDisk >> 1, (SelectDisk & 1) ? 'B' : 'A');
223224 }
224225
225 #define IRQ_Repeat (IRQa & 0x01)
226 #define IRQ_Enabled (IRQa & 0x02)
226 #define IRQ_Repeat 0x01
227 #define IRQ_Enabled 0x02
227228
228229 static void FDSFix(int a) {
229 if ((IRQa & IRQ_Enabled) && IRQCount) {
230 if (IRQa & IRQ_Enabled) {
230231 IRQCount -= a;
231232 if (IRQCount <= 0) {
232233 IRQCount = IRQLatch;
234 /* Puff Puff Golf notes:
235 Game freezes while music playing ingame after inserting Disk Side B.
236 IRQ is usually fired at scanline 169 and 183 for music to work.
237
238 At some point after inserting disk B, an IRQ is fired at scanline 174 which
239 will just freeze game while music plays.
240
241 If you ignore triggering IRQ altogether, game plays but no music
242 */
233243 X6502_IRQBegin(FCEU_IQEXT);
234244 if (!(IRQa & IRQ_Repeat)) {
235245 IRQa &= ~IRQ_Enabled;
573583 static DECLFW(FDSWrite) {
574584 switch (A) {
575585 case 0x4020:
576 X6502_IRQEnd(FCEU_IQEXT);
577586 IRQLatch &= 0xFF00;
578587 IRQLatch |= V;
579588 break;
580589 case 0x4021:
581 X6502_IRQEnd(FCEU_IQEXT);
582590 IRQLatch &= 0xFF;
583591 IRQLatch |= V << 8;
584592 break;
585593 case 0x4022:
586 X6502_IRQEnd(FCEU_IQEXT);
587 IRQCount = IRQLatch;
588 IRQa = V & 3;
594 if (FDSRegs[3] & 1) {
595 IRQa = V & 0x03;
596 if (IRQa & IRQ_Enabled) {
597 IRQCount = IRQLatch;
598 } else {
599 X6502_IRQEnd(FCEU_IQEXT);
600 }
601 }
589602 break;
590 case 0x4023: break;
603 case 0x4023:
604 if (!(V & 0x01)) {
605 IRQa &= ~IRQ_Enabled;
606 X6502_IRQEnd(FCEU_IQEXT);
607 X6502_IRQEnd(FCEU_IQEXT2);
608 }
609 break;
591610 case 0x4024:
592611 if (mapperFDS_diskinsert && ~mapperFDS_control & 0x04) {
593612
833852 free(fn);
834853 }
835854
836 extern char LoadedRomFName[2048];
837855 strcpy(LoadedRomFName, name); //For the debugger list
838856
839857 GameInfo->type = GIT_FDS;
6868
6969 if(!ips) return;
7070
71 char* buf = (char*)FCEU_dmalloc(fp->size);
71 char* buf = (char*)FCEU_malloc(fp->size);
7272 memcpy(buf,fp->EnsureMemorystream()->buf(),fp->size);
7373
7474
107107 if((offset+size)>(uint32)fp->size)
108108 {
109109 // Probably a little slow.
110 char *newbuf=(char *)realloc(buf,offset+size);
111 if(!newbuf)
112 {
113 free(buf); buf=NULL;
114 FCEU_printf(" Oops. IPS patch %d(type RLE) goes beyond end of file. Could not allocate memory.\n",count);
115 goto end;
116 }
110 char *newbuf=(char *)FCEU_realloc(buf,offset+size);
117111 buf=newbuf;
118112 memset(buf+fp->size,0,offset+size-fp->size);
119113 fp->size=offset+size;
132126 if((offset+size)>(uint32)fp->size)
133127 {
134128 // Probably a little slow.
135 char *newbuf=(char *)realloc(buf,offset+size);
136 if(!newbuf)
137 {
138 free(buf); buf=NULL;
139 FCEU_printf(" Oops. IPS patch %d(type normal) goes beyond end of file. Could not allocate memory.\n",count);
140 goto end;
141 }
129 char *newbuf=(char *)FCEU_realloc(buf,offset+size);
142130 buf=newbuf;
143131 memset(buf+fp->size,0,offset+size-fp->size);
144 }
145 fread(buf+offset,1,size,ips);
132 fp->size=offset+size;
133 }
134 if ( fread(buf+offset,1,size,ips) != static_cast<size_t>(size) )
135 {
136 FCEU_printf(" Warn IPS data read came up short!\n");
137 }
146138 }
147139 count++;
148140 }
325317 {
326318 uint32 magic;
327319
328 magic = fp->fgetc();
329 magic|=fp->fgetc()<<8;
330 magic|=fp->fgetc()<<16;
320 magic = (fp->fgetc() & 0x00ff);
321 magic|= (fp->fgetc() & 0x00ff) << 8;
322 magic|= (fp->fgetc() & 0x00ff) << 16;
331323 fp->fseek(0,SEEK_SET);
332324
333325 if(magic==0x088b1f) {
337329 if(gzfile) {
338330 delete fp;
339331
340 int size;
332 size_t size;
341333 for(size=0; gzgetc(gzfile) != EOF; size++) {}
342334 EMUFILE_MEMORY* ms = new EMUFILE_MEMORY(size);
343335 gzseek(gzfile,0,SEEK_SET);
456448 std::string GetMfn() //Retrieves the movie filename from curMovieFilename (for adding to savestate and auto-save files)
457449 {
458450 std::string movieFilenamePart;
459 extern char curMovieFilename[512];
460 if(*curMovieFilename)
461 {
451 if (!curMovieFilename.empty())
452 {
462453 char drv[PATH_MAX], dir[PATH_MAX], name[PATH_MAX], ext[PATH_MAX];
463 splitpath(curMovieFilename,drv,dir,name,ext);
454 splitpath(curMovieFilename.c_str(),drv,dir,name,ext);
464455 movieFilenamePart = std::string(".") + name;
465 }
456 }
466457 return movieFilenamePart;
467458 }
468459
494485 va_list ap;
495486 int ret;
496487
497 if(!(*strp=(char*)FCEU_dmalloc(2048))) //mbg merge 7/17/06 cast to char*
488 if(!(*strp=(char*)FCEU_malloc(2048))) //mbg merge 7/17/06 cast to char*
498489 return(0);
499490 va_start(ap,fmt);
500491 ret=vsnprintf(*strp,2048,fmt,ap);
3434 int archiveIndex;
3535
3636 //the size of the file
37 int size;
37 size_t size;
3838
3939 //whether the file is contained in an archive
4040 bool isArchive() { return archiveCount > 0; }
1515 GIV_USER = 2, //What was set by FCEUI_SetVidSys().
1616 };
1717
18 enum EGIPPU
19 {
20 GIPPU_USER = 0,
21 GIPPU_RP2C04_0001 = 1,
22 GIPPU_RP2C04_0002 = 2,
23 GIPPU_RP2C04_0003 = 3,
24 GIPPU_RP2C04_0004 = 4,
25 GIPPU_RC2C03B = 5,
26 GIPPU_RC2C05_01 = 6,
27 GIPPU_RC2C05_02 = 7,
28 GIPPU_RC2C05_03 = 8,
29 GIPPU_RC2C05_04 = 9,
30 };
31
32 enum EGIVS
33 {
34 EGIVS_NORMAL = 0,
35 EGIVS_RBI = 1, // RBI Baseball protection
36 EGIVS_TKO = 2, // TKO Boxing protection
37 EGIVS_XEVIOUS = 3, // Super Xevious protection
38 };
39
1840 enum ESIS
1941 {
2042 SIS_NONE = 0,
2143 SIS_DATACH = 1,
2244 SIS_NWC = 2,
23 SIS_VSUNISYSTEM = 3,
45 SIS_VSUNISYSTEM = 3, // Is it used?
2446 SIS_NSF = 4,
2547 };
2648
4264
4365 SI_COUNT = SI_LCDCOMP_ZAPPER
4466 };
67
68
4569
4670 inline const char* ESI_Name(ESI esi)
4771 {
136160 ESI input[2]; //Desired input for emulated input ports 1 and 2; -1 for unknown desired input.
137161 ESIFC inputfc; //Desired Famicom expansion port device. -1 for unknown desired input.
138162 ESIS cspecial; //Special cart expansion: DIP switches, barcode reader, etc.
163 EGIPPU vs_ppu; //PPU type for Vs. System
164 EGIVS vs_type; //Vs. System type
165 uint8 vs_cswitch; // Switch first and second controllers for Vs. System
139166
140167 MD5DATA MD5;
141168
3636 #include "cheat.h"
3737 #include "vsuni.h"
3838 #include "driver.h"
39 #include "input.h"
3940
4041 #include <cstdio>
4142 #include <cstdlib>
5354 static CartInfo iNESCart;
5455
5556 uint8 Mirroring = 0;
57 uint8 MirroringAs2bits = 0;
5658 uint32 ROM_size = 0;
5759 uint32 VROM_size = 0;
58 char LoadedRomFName[2048]; //mbg merge 7/17/06 added
60 char LoadedRomFName[4096]; //mbg merge 7/17/06 added
61 char LoadedRomFNamePatchToUse[4096];
5962
6063 static int CHRRAMSize = -1;
6164 static int iNES_Init(int num);
106109 if (iNESCart.Close)
107110 iNESCart.Close();
108111 if (ROM) {
109 free(ROM);
112 FCEU_free(ROM);
110113 ROM = NULL;
111114 }
112115 if (VROM) {
113 free(VROM);
116 FCEU_free(VROM);
114117 VROM = NULL;
115118 }
116119 if (trainerpoo) {
140143 ESIFC inputfc;
141144 };
142145
146 /*
147 * Function to set input controllers based on CRC
148 */
143149 static void SetInput(void) {
144150 static struct INPSEL moo[] =
145151 {
152158 {0x48ca0ee1, SI_GAMEPAD, SI_GAMEPAD, SIFC_BWORLD }, // Barcode World
153159 {0x4318a2f8, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Barker Bill's Trick Shooting
154160 {0x6cca1c1f, SI_GAMEPAD, SI_GAMEPAD, SIFC_FTRAINERB }, // Dai Undoukai
155 {0x24598791, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Duck Hunt
161 {0x24598791, SI_GAMEPAD, SI_ZAPPER, SIFC_NONE }, // Duck Hunt
156162 {0xd5d6eac4, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Edu (As)
157 {0xe9a7fe9e, SI_UNSET, SI_MOUSE, SIFC_NONE }, // Educational Computer 2000
163 {0xe9a7fe9e, SI_UNSET, SI_MOUSE, SIFC_SUBORKB }, // Educational Computer 2000
158164 {0x8f7b1669, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // FP BASIC 3.3 by maxzhou88
159165 {0xf7606810, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC 2.0A
160166 {0x895037bc, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC 2.1a
214220 {0x67b126b9, SI_GAMEPAD, SI_GAMEPAD, SIFC_FAMINETSYS }, // Famicom Network System
215221 {0x00000000, SI_UNSET, SI_UNSET, SIFC_UNSET }
216222 };
223
217224 int x = 0;
218225
219226 while (moo[x].input1 >= 0 || moo[x].input2 >= 0 || moo[x].inputfc >= 0) {
223230 GameInfo->inputfc = moo[x].inputfc;
224231 break;
225232 }
233 x++;
234 }
235 }
236
237 struct INPSEL_NES20 {
238 uint8 expansion_id;
239 ESI input1;
240 ESI input2;
241 ESIFC inputfc;
242 };
243
244 /*
245 * Function to set input controllers based on NES 2.0 header
246 */
247 extern int eoptions;
248 static void SetInputNes20(uint8 expansion) {
249 static struct INPSEL_NES20 moo[] =
250 {
251 {0x01, SI_GAMEPAD, SI_GAMEPAD, SIFC_UNSET }, // Standard NES/Famicom controllers
252 {0x02, SI_GAMEPAD, SI_GAMEPAD, SIFC_NONE }, // NES Four Score/Satellite with two additional standard controllers
253 {0x03, SI_GAMEPAD, SI_GAMEPAD, SIFC_4PLAYER }, // Famicom Four Players Adapter with two additional standard controllers using the "simple" protocol
254 {0x04, SI_GAMEPAD, SI_GAMEPAD, SIFC_NONE }, // Vs. System (1P via $4016)
255 {0x05, SI_GAMEPAD, SI_GAMEPAD, SIFC_NONE }, // Vs. System (1P via $4017)
256 {0x07, SI_ZAPPER, SI_NONE, SIFC_NONE }, // Vs. Zapper
257 {0x08, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Zapper ($4017)
258 {0x0A, SI_UNSET, SI_UNSET, SIFC_SHADOW }, // Bandai Hyper Shot Lightgun
259 {0x0B, SI_UNSET, SI_POWERPADA, SIFC_UNSET }, // Power Pad Side A
260 {0x0C, SI_UNSET, SI_POWERPADB, SIFC_UNSET }, // Power Pad Side B
261 {0x0D, SI_UNSET, SI_UNSET, SIFC_FTRAINERA }, // Family Trainer Side A
262 {0x0E, SI_UNSET, SI_UNSET, SIFC_FTRAINERB }, // Family Trainer Side B
263 {0x0F, SI_UNSET, SI_ARKANOID, SIFC_UNSET }, // Arkanoid Vaus Controller (NES)
264 {0x10, SI_UNSET, SI_UNSET, SIFC_ARKANOID }, // Arkanoid Vaus Controller (Famicom)
265 {0x12, SI_UNSET, SI_UNSET, SIFC_HYPERSHOT }, // Konami Hyper Shot Controller
266 {0x15, SI_UNSET, SI_UNSET, SIFC_MAHJONG }, // Jissen Mahjong Controller
267 {0x17, SI_UNSET, SI_UNSET, SIFC_OEKAKIDS }, // Oeka Kids Tablet
268 {0x18, SI_UNSET, SI_UNSET, SIFC_BWORLD }, // Sunsoft Barcode Battler
269 {0x1B, SI_UNSET, SI_UNSET, SIFC_TOPRIDER }, // Top Rider (Inflatable Bicycle)
270 {0x23, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC Keyboard plus Famicom Data Recorder
271 {0x24, SI_UNSET, SI_UNSET, SIFC_PEC586KB }, // Dongda PEC-586 Keyboard
272 {0x26, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // Subor Keyboard
273 //{0x27, SI_UNSET, SI_MOUSE, SIFC_SUBORKB }, // Subor Keyboard plus mouse (3x8-bit protocol)
274 {0x28, SI_UNSET, SI_MOUSE, SIFC_SUBORKB }, // Subor Keyboard plus mouse (24-bit protocol)
275 {0x29, SI_UNSET, SI_SNES_MOUSE, SIFC_UNSET }, // SNES Mouse
276 {0, SI_UNSET, SI_UNSET, SIFC_UNSET }
277 };
278
279 int x = 0;
280
281 if (expansion == 0x02)
282 eoptions |= 32768; // dirty hack to enable Four-Score
283 GameInfo->vs_cswitch = expansion == 0x05;
284
285 while (moo[x].expansion_id) {
286 if (moo[x].expansion_id == expansion) {
287 GameInfo->input[0] = moo[x].input1;
288 GameInfo->input[1] = moo[x].input2;
289 GameInfo->inputfc = moo[x].inputfc;
290 break; }
226291 x++;
227292 }
228293 }
275340 const TMasterRomInfo* MasterRomInfo;
276341 TMasterRomInfoParams MasterRomInfoParams;
277342
278 static void CheckHInfo(void) {
343 static void CheckHInfo(uint64 partialmd5) {
279344 /* ROM images that have the battery-backed bit set in the header that really
280345 don't have battery-backed RAM is not that big of a problem, so I'll
281346 treat this differently by only listing games that should have battery-backed RAM.
326391 #include "ines-correct.h"
327392 };
328393 int32 tofix = 0, x, mask;
329 uint64 partialmd5 = 0;
330
331 for (x = 0; x < 8; x++)
332 partialmd5 |= (uint64)iNESCart.MD5[15 - x] << (x * 8);
333 CheckBad(partialmd5);
334394
335395 MasterRomInfo = NULL;
336 for (int i = 0; i < ARRAY_SIZE(sMasterRomInfo); i++) {
396 for (size_t i = 0; i < ARRAY_SIZE(sMasterRomInfo); i++) {
337397 const TMasterRomInfo& info = sMasterRomInfo[i];
338398 if (info.md5lower != partialmd5)
339399 continue;
342402 if (!info.params) break;
343403
344404 std::vector<std::string> toks = tokenize_str(info.params, ",");
345 for (int j = 0; j < (int)toks.size(); j++) {
405 for (size_t j = 0; j < toks.size(); j++) {
346406 std::vector<std::string> parts = tokenize_str(toks[j], "=");
347407 MasterRomInfoParams[parts[0]] = parts[1];
348408 }
672732 {"", 215, UNL8237_Init},
673733 {"", 216, Mapper216_Init},
674734 {"", 217, Mapper217_Init}, // Redefined to a new Discrete BMC mapper
675 // {"", 218, Mapper218_Init},
735 {"", 218, Mapper218_Init},
676736 {"UNLA9746", 219, UNLA9746_Init},
677737 {"Debug Mapper", 220, QTAi_Init},
678738 {"UNLN625092", 221, UNLN625092_Init},
709769 {"SAN GUO ZHI PIRATE", 252, Mapper252_Init},
710770 {"DRAGON BALL PIRATE", 253, Mapper253_Init},
711771 {"", 254, Mapper254_Init},
712 // {"", 255, Mapper255_Init}, // No good dumps for this mapper
772 {"", 255, Mapper255_Init}, // dupe of 225
713773
714774 //-------- Mappers 256-511 is the Supplementary Multilingual Plane ----------
715775 //-------- Mappers 512-767 is the Supplementary Ideographic Plane -----------
726786 {"F-15 MMC3 Based", 259, BMCF15_Init},
727787 {"HP10xx/H20xx Boards", 260, BMCHPxx_Init},
728788 {"810544-CA-1", 261, BMC810544CA1_Init},
729 {"SMD132/SMD133", 268, SMD132_SMD133_Init},
789 {"AA6023/AA6023B", 268, AA6023_Init},
790 {"COOLGIRL", 342, COOLGIRL_Init },
791 {"FAM250/81-01-39-C/SCHI-24", 354, Mapper354_Init },
730792
731793 {"Impact Soft MMC3 Flash Board", 406, Mapper406_Init },
794 {"INX_007T_V01", 470, INX_007T_Init },
732795
733796 {"KONAMI QTAi Board", 547, QTAi_Init },
734797
736799 };
737800
738801 int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) {
802 int result;
739803 struct md5_context md5;
804 uint64 partialmd5 = 0;
805 const char* mappername = "Not Listed";
740806
741807 if (FCEU_fread(&head, 1, 16, fp) != 16 || memcmp(&head, "NES\x1A", 4))
742808 return LOADER_INVALID_FORMAT;
764830 Mirroring = 2;
765831 } else
766832 Mirroring = (head.ROM_type & 1);
833
834 MirroringAs2bits = head.ROM_type & 1;
835 if (head.ROM_type & 8) MirroringAs2bits |= 2;
767836
768837 int not_round_size;
769838 if (!iNES2) {
808877 }
809878 }
810879
811 if ((ROM = (uint8*)FCEU_malloc(ROM_size << 14)) == NULL)
812 return 0;
880 ROM = (uint8*)FCEU_malloc(ROM_size << 14);
813881 memset(ROM, 0xFF, ROM_size << 14);
814882
815883 if (VROM_size) {
816 if ((VROM = (uint8*)FCEU_malloc(VROM_size << 13)) == NULL) {
817 free(ROM);
818 ROM = NULL;
819 FCEU_PrintError("Unable to allocate memory.");
820 return LOADER_HANDLED_ERROR;
821 }
884 VROM = (uint8*)FCEU_malloc(VROM_size << 13);
822885 memset(VROM, 0xFF, VROM_size << 13);
886 }
887
888 // Set Vs. System flag if need
889 if (!iNES2) {
890 GameInfo->type = !(head.ROM_type2 & 1) ? GIT_CART : GIT_VSUNI;
891 }
892 else {
893 switch (!(head.ROM_type2 & 2) ? (head.ROM_type2 & 3) : (head.VS_hardware & 0xF)) {
894 case 0:
895 GameInfo->type = GIT_CART;
896 break;
897 case 1:
898 GameInfo->type = GIT_VSUNI;
899 break;
900 default:
901 FCEU_PrintError("Game type is not supported at all.");
902 goto init_error;
903 }
904 }
905
906 // Set Vs. System PPU type if need
907 if (GameInfo->type == GIT_VSUNI && !(head.ROM_type2 & 2)) {
908 switch (head.VS_hardware & 0xF) {
909 case 0x0: GameInfo->vs_ppu = GIPPU_RC2C03B; break;
910 //case 0x1: GameInfo->vs_ppu = GIPPU_RPC2C03C; break;
911 case 0x2: GameInfo->vs_ppu = GIPPU_RP2C04_0001; break;
912 case 0x3: GameInfo->vs_ppu = GIPPU_RP2C04_0002; break;
913 case 0x4: GameInfo->vs_ppu = GIPPU_RP2C04_0003; break;
914 case 0x5: GameInfo->vs_ppu = GIPPU_RP2C04_0004; break;
915 case 0x6: GameInfo->vs_ppu = GIPPU_RC2C03B; break;
916 //case 0x7: GameInfo->ppu = GIPPU_RPC2C03C; break;
917 case 0x8: GameInfo->vs_ppu = GIPPU_RC2C05_01; break;
918 case 0x9: GameInfo->vs_ppu = GIPPU_RC2C05_02; break;
919 case 0xA: GameInfo->vs_ppu = GIPPU_RC2C05_03; break;
920 case 0xB: GameInfo->vs_ppu = GIPPU_RC2C05_04; break;
921 //case 0xC: GameInfo->ppu = GIPPU_RPC2C05_05; break;
922 default:
923 FCEU_PrintError("Vs. System PPU type is not supported at all.");
924 goto init_error;
925 }
926
927 switch (head.VS_hardware >> 4) {
928 case 0x0: GameInfo->vs_type = EGIVS_NORMAL; break;
929 case 0x1: GameInfo->vs_type = EGIVS_RBI; break;
930 case 0x2: GameInfo->vs_type = EGIVS_TKO; break;
931 case 0x3: GameInfo->vs_type = EGIVS_XEVIOUS; break;
932 default:
933 FCEU_PrintError("Vs. System type is not supported at all.");
934 goto init_error;
935 }
823936 }
824937
825938 if (head.ROM_type & 4) { /* Trainer */
837950 if (VROM_size)
838951 FCEU_fread(VROM, 0x2000, VROM_size, fp);
839952
840 md5_starts(&md5);
953 md5_starts(&md5);
841954 md5_update(&md5, ROM, ROM_size << 14);
842955
843956 iNESGameCRC32 = CalcCRC32(0, ROM, ROM_size << 14);
848961 }
849962 md5_finish(&md5, iNESCart.MD5);
850963 memcpy(&GameInfo->MD5, &iNESCart.MD5, sizeof(iNESCart.MD5));
964 for (int x = 0; x < 8; x++)
965 partialmd5 |= (uint64)iNESCart.MD5[7 - x] << (x * 8);
851966
852967 iNESCart.CRC32 = iNESGameCRC32;
853968
854969 FCEU_printf(" PRG ROM: %d x 16KiB = %d KiB\n", round ? ROM_size : not_round_size, (round ? ROM_size : not_round_size) * 16);
855970 FCEU_printf(" CHR ROM: %d x 8KiB = %d KiB\n", VROM_size, VROM_size * 8);
856 FCEU_printf(" ROM CRC32: 0x%08lx\n", iNESGameCRC32);
971 FCEU_printf(" ROM CRC32: 0x%08x\n", iNESGameCRC32);
857972 {
858973 int x;
859974 FCEU_printf(" ROM MD5: 0x");
862977 FCEU_printf("\n");
863978 }
864979
865 const char* mappername = "Not Listed";
866
867 for (int mappertest = 0; mappertest < (sizeof bmap / sizeof bmap[0]) - 1; mappertest++) {
980 for (size_t mappertest = 0; mappertest < (sizeof bmap / sizeof bmap[0]) - 1; mappertest++) {
868981 if (bmap[mappertest].number == MapperNo) {
869982 mappername = bmap[mappertest].name;
870983 break;
8901003 }
8911004
8921005 SetInput();
893 CheckHInfo();
894 {
895 int x;
896 uint64 partialmd5 = 0;
897
898 for (x = 0; x < 8; x++) {
899 partialmd5 |= (uint64)iNESCart.MD5[7 - x] << (x * 8);
900 }
901
902 FCEU_VSUniCheck(partialmd5, &MapperNo, &Mirroring);
903 }
1006 // Input can be overriden by NES 2.0 header
1007 if (iNES2) SetInputNes20(head.expansion);
1008 CheckHInfo(partialmd5);
1009 FCEU_VSUniCheck(partialmd5, &MapperNo, &Mirroring);
1010 CheckBad(partialmd5);
1011
9041012 /* Must remain here because above functions might change value of
9051013 VROM_size and free(VROM).
9061014 */
9171025
9181026 iNESCart.battery = (head.ROM_type & 2) ? 1 : 0;
9191027 iNESCart.mirror = Mirroring;
920
921 int result = iNES_Init(MapperNo);
1028 iNESCart.mirrorAs2Bits = MirroringAs2bits;
1029
1030 result = iNES_Init(MapperNo);
9221031 switch(result)
9231032 {
9241033 case 0:
9301039 FCEU_PrintError("Unable to allocate CHR-RAM.");
9311040 break;
9321041 }
1042
1043 init_error:
9331044 if (ROM) free(ROM);
9341045 if (VROM) free(VROM);
9351046 if (trainerpoo) free(trainerpoo);
9941105 //caitsith2: done. iNesSave() now gets filename and calls iNesSaveAs with that filename.
9951106 FILE *fp;
9961107
997 if (GameInfo->type != GIT_CART) return 0;
1108 if ((GameInfo->type != GIT_CART) && (GameInfo->type != GIT_VSUNI)) return 0;
9981109 if (GameInterface != iNESGI) return 0;
9991110
10001111 fp = fopen(name, "wb");
2323 #include <stdlib.h>
2424 #include <string.h>
2525 #include <map>
26
27 #include "cart.h"
2628
2729 struct TMasterRomInfo
2830 {
4244 extern uint32 VROM_size;
4345 extern uint32 ROM_size;
4446 extern uint8 *ExtraNTARAM;
47 extern uint8 **VPageR;
4548 extern int iNesSave(void); //bbit Edited: line added
4649 extern int iNesSaveAs(const char* name);
47 extern char LoadedRomFName[2048]; //bbit Edited: line added
50 extern char LoadedRomFName[4096]; //bbit Edited: line added
51 extern char LoadedRomFNamePatchToUse[4096];
4852 extern char *iNesShortFName(void);
4953 extern const TMasterRomInfo* MasterRomInfo;
5054 extern TMasterRomInfoParams MasterRomInfoParams;
5155
5256 //mbg merge 7/19/06 changed to c++ decl format
5357 struct iNES_HEADER {
54 char ID[4]; /*NES^Z*/ // 0-3
55 uint8 ROM_size; // 4
56 uint8 VROM_size; // 5
57 uint8 ROM_type; // 6
58 uint8 ROM_type2; // 7
59 uint8 ROM_type3; // 8
60 uint8 Upper_ROM_VROM_size; // 9
61 uint8 RAM_size; // 10
62 uint8 VRAM_size; // 11
63 uint8 TV_system; // 12
64 uint8 VS_hardware; // 13
65 uint8 reserved[2]; // 14, 15
58 char ID[4]; /*NES^Z*/ // 0-3
59 uint8 ROM_size; // 4
60 uint8 VROM_size; // 5
61 uint8 ROM_type; // 6
62 uint8 ROM_type2; // 7
63 uint8 ROM_type3; // 8
64 uint8 Upper_ROM_VROM_size; // 9
65 uint8 RAM_size; // 10
66 uint8 VRAM_size; // 11
67 uint8 TV_system; // 12
68 uint8 VS_hardware; // 13
69 uint8 misc_roms; // 14
70 uint8 expansion; // 15
6671
6772 void cleanup()
6873 {
241246 void Mapper214_Init(CartInfo *);
242247 void Mapper216_Init(CartInfo *);
243248 void Mapper217_Init(CartInfo *);
249 void Mapper218_Init(CartInfo *);
244250 void Mapper220_Init(CartInfo *);
245251 void Mapper222_Init(CartInfo *);
246252 void Mapper225_Init(CartInfo *);
267273 void Mapper252_Init(CartInfo *);
268274 void Mapper253_Init(CartInfo *);
269275 void Mapper254_Init(CartInfo *);
276 void Mapper255_Init(CartInfo *);
277 void Mapper354_Init(CartInfo *);
270278 void Mapper406_Init(CartInfo *);
279
280 void INX_007T_Init(CartInfo* info);
271281
272282 typedef struct {
273283 const char *name;
105105 }
106106
107107 extern uint8 coinon;
108 extern uint8 coinon2;
109 extern uint8 service;
108110
109111 //set to true if the fourscore is attached
110112 static bool FSAttached = false;
430432 portFC.driver->Update(portFC.ptr,portFC.attrib);
431433 }
432434
433 if(GameInfo->type==GIT_VSUNI)
434 if(coinon) coinon--;
435 if (GameInfo->type == GIT_VSUNI) {
436 if (coinon) coinon--;
437 if (coinon2) coinon2--;
438 if (service) service--;
439 }
435440
436441 if(FCEUnetplay)
437442 NetplayUpdate(joy);
453458
454459 ret|=(vsdip&3)<<3;
455460 if(coinon)
456 ret|=0x4;
461 ret |= 0x20;
462 if (coinon2)
463 ret |= 0x40;
464 if (service)
465 ret |= 0x04;
457466 return ret;
458467 }
459468
667676 {
668677 case FCEUNPCMD_FDSINSERT: FCEU_FDSInsert();break;
669678 case FCEUNPCMD_FDSSELECT: FCEU_FDSSelect();break;
670 case FCEUNPCMD_VSUNICOIN: FCEU_VSUniCoin(); break;
679 case FCEUNPCMD_VSUNICOIN: FCEU_VSUniCoin(0); break;
680 case FCEUNPCMD_VSUNICOIN2: FCEU_VSUniCoin(1); break;
681 case FCEUNPCMD_VSUNISERVICE: FCEU_VSUniService(); break;
671682 case FCEUNPCMD_VSUNIDIP0:
672683 case FCEUNPCMD_VSUNIDIP0+1:
673684 case FCEUNPCMD_VSUNIDIP0+2:
723734 return;
724735
725736 FCEU_QSimpleCommand(FCEUNPCMD_VSUNICOIN);
737 }
738
739 void FCEUI_VSUniCoin2(void)
740 {
741 if (!FCEU_IsValidUI(FCEUI_INSERT_COIN))
742 return;
743
744 FCEU_QSimpleCommand(FCEUNPCMD_VSUNICOIN2);
745 }
746
747 void FCEUI_VSUniService(void)
748 {
749 if (!FCEU_IsValidUI(FCEUI_INSERT_COIN))
750 return;
751
752 FCEU_QSimpleCommand(FCEUNPCMD_VSUNISERVICE);
726753 }
727754
728755 //Resets the frame counter if movie inactive and rom is reset or power-cycle
797824 static void RamSearchOpGTE(void);
798825 static void RamSearchOpEQ(void);
799826 static void RamSearchOpNE(void);
827 static void ToggleCheats(void);
800828 static void DebuggerStepInto(void);
801829 static void FA_SkipLag(void);
802830 static void OpenRom(void);
899927 { EMUCMD_FDS_EJECT_INSERT, EMUCMDTYPE_FDS, FCEUI_FDSInsert, 0, 0, "Eject or Insert FDS Disk", EMUCMDFLAG_TASEDITOR },
900928 { EMUCMD_FDS_SIDE_SELECT, EMUCMDTYPE_FDS, FCEUI_FDSSelect, 0, 0, "Switch FDS Disk Side", EMUCMDFLAG_TASEDITOR },
901929
902 { EMUCMD_VSUNI_COIN, EMUCMDTYPE_VSUNI, FCEUI_VSUniCoin, 0, 0, "Insert Coin", EMUCMDFLAG_TASEDITOR },
903 { EMUCMD_VSUNI_TOGGLE_DIP_0, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 0", 0 },
904 { EMUCMD_VSUNI_TOGGLE_DIP_1, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 1", 0 },
905 { EMUCMD_VSUNI_TOGGLE_DIP_2, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 2", 0 },
906 { EMUCMD_VSUNI_TOGGLE_DIP_3, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 3", 0 },
907 { EMUCMD_VSUNI_TOGGLE_DIP_4, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 4", 0 },
908 { EMUCMD_VSUNI_TOGGLE_DIP_5, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 5", 0 },
909 { EMUCMD_VSUNI_TOGGLE_DIP_6, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 6", 0 },
910 { EMUCMD_VSUNI_TOGGLE_DIP_7, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 7", 0 },
911 { EMUCMD_VSUNI_TOGGLE_DIP_8, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 8", 0 },
912 { EMUCMD_VSUNI_TOGGLE_DIP_9, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dipswitch 9", 0 },
930 { EMUCMD_VSUNI_COIN, EMUCMDTYPE_VSUNI, FCEUI_VSUniCoin, 0, 0, "Insert Coin #1", EMUCMDFLAG_TASEDITOR },
931 { EMUCMD_VSUNI_COIN_2, EMUCMDTYPE_VSUNI, FCEUI_VSUniCoin2, 0, 0, "Insert Coin #2", EMUCMDFLAG_TASEDITOR },
932 { EMUCMD_VSUNI_SERVICE_BUTTON, EMUCMDTYPE_VSUNI, FCEUI_VSUniService, 0, 0, "Service Button", EMUCMDFLAG_TASEDITOR },
933 { EMUCMD_VSUNI_TOGGLE_DIP_0, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dip Switch 0", 0 },
934 { EMUCMD_VSUNI_TOGGLE_DIP_1, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dip Switch 1", 0 },
935 { EMUCMD_VSUNI_TOGGLE_DIP_2, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dip Switch 2", 0 },
936 { EMUCMD_VSUNI_TOGGLE_DIP_3, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dip Switch 3", 0 },
937 { EMUCMD_VSUNI_TOGGLE_DIP_4, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dip Switch 4", 0 },
938 { EMUCMD_VSUNI_TOGGLE_DIP_5, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dip Switch 5", 0 },
939 { EMUCMD_VSUNI_TOGGLE_DIP_6, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dip Switch 6", 0 },
940 { EMUCMD_VSUNI_TOGGLE_DIP_7, EMUCMDTYPE_VSUNI, CommandToggleDip, 0, 0, "Toggle Dip Switch 7", 0 },
913941
914942 { EMUCMD_MISC_AUTOSAVE, EMUCMDTYPE_MISC, FCEUI_RewindToLastAutosave, 0, 0, "Load Last Auto-save", 0},
915943 { EMUCMD_MISC_SHOWSTATES, EMUCMDTYPE_MISC, ViewSlots, 0, 0, "View save slots", 0 },
944972 { EMUCMD_TOOL_RAMSEARCHGTE, EMUCMDTYPE_TOOL, RamSearchOpGTE, 0, 0, "Ram Search - Greater Than or Equal", 0},
945973 { EMUCMD_TOOL_RAMSEARCHEQ, EMUCMDTYPE_TOOL, RamSearchOpEQ, 0, 0, "Ram Search - Equal", 0},
946974 { EMUCMD_TOOL_RAMSEARCHNE, EMUCMDTYPE_TOOL, RamSearchOpNE, 0, 0, "Ram Search - Not Equal", 0},
975 { EMUCMD_TOOL_TOGGLECHEATS, EMUCMDTYPE_TOOL, ToggleCheats, 0, 0, "Toggle Cheats", 0},
947976 { EMUCMD_RERECORD_DISPLAY_TOGGLE, EMUCMDTYPE_MISC, FCEUI_MovieToggleRerecordDisplay,0, 0, "Toggle Rerecord Display", EMUCMDFLAG_TASEDITOR },
948977
949978 { EMUCMD_TASEDITOR_REWIND, EMUCMDTYPE_TASEDITOR, TaseditorRewindOn, TaseditorRewindOff, 0, "Frame Rewind", EMUCMDFLAG_TASEDITOR },
959988
960989 #define NUM_EMU_CMDS (sizeof(FCEUI_CommandTable)/sizeof(FCEUI_CommandTable[0]))
961990
962 static int execcmd, i;
991 static int execcmd;
963992
964993 void FCEUI_HandleEmuCommands(TestCommandState* testfn)
965994 {
966995 bool taseditor = FCEUMOV_Mode(MOVIEMODE_TASEDITOR);
967 for(i=0; i<NUM_EMU_CMDS; ++i)
996 for(size_t i=0; i<NUM_EMU_CMDS; ++i)
968997 {
969998 int new_state;
970999 int old_state = FCEUI_CommandTable[i].state;
12671296 #endif
12681297 }
12691298
1299 extern int globalCheatDisabled;
1300 extern unsigned int FrozenAddressCount;
1301 static void ToggleCheats()
1302 {
1303 FCEUI_GlobalToggleCheat(globalCheatDisabled);
1304 FCEU_DispMessage("%d cheats active", 0, FrozenAddressCount);
1305 #ifdef __WIN_DRIVER__
1306 UpdateCheatRelatedWindow();
1307 UpdateCheatListGroupBoxUI();
1308 #endif
1309 }
1310
12701311 static void DebuggerStepInto()
12711312 {
12721313 #ifdef __WIN_DRIVER__
13231364
13241365 static void UndoRedoSavestate(void)
13251366 {
1326 // FIXME this will always evaluate to true, should this be
1327 // if (*lastSavestateMade...) to check if it holds a string or just
1328 // a '\0'?
1329 if (lastSavestateMade && (undoSS || redoSS))
1367 if ( !lastSavestateMade.empty() && (undoSS || redoSS))
13301368 SwapSaveState();
13311369 }
13321370
13791417 **/
13801418 EMUCMDTABLE* GetEmuCommandById(int cmd)
13811419 {
1382 for (i = 0; i<NUM_EMU_CMDS; ++i)
1420 for (size_t i = 0; i<NUM_EMU_CMDS; ++i)
13831421 {
13841422 if (FCEUI_CommandTable[i].cmd == cmd)
13851423 return &FCEUI_CommandTable[i];
196196 EMUCMD_VSUNI_TOGGLE_DIP_5,
197197 EMUCMD_VSUNI_TOGGLE_DIP_6,
198198 EMUCMD_VSUNI_TOGGLE_DIP_7,
199 EMUCMD_VSUNI_TOGGLE_DIP_8,
200 EMUCMD_VSUNI_TOGGLE_DIP_9,
199 EMUCMD_VSUNI_COIN_2,
200 EMUCMD_VSUNI_SERVICE_BUTTON,
201201 EMUCMD_MISC_AUTOSAVE,
202202 EMUCMD_MISC_SHOWSTATES,
203203 EMUCMD_MISC_USE_INPUT_PRESET_1,
258258 EMUCMD_MOVIE_RECORD_MODE_OVERWRITE,
259259 EMUCMD_MOVIE_RECORD_MODE_INSERT,
260260
261 EMUCMD_TOOL_TOGGLECHEATS,
262
261263 EMUCMD_MAX
262264 };
263265
2323 #include "file.h"
2424 #include "video.h"
2525 #include "debug.h"
26 #include "debugsymboltable.h"
2627 #include "sound.h"
2728 #include "drawing.h"
2829 #include "state.h"
5354 #ifdef __SDL__
5455
5556 #ifdef __QT_DRIVER__
57 #include "drivers/Qt/sdl.h"
58 #include "drivers/Qt/main.h"
59 #include "drivers/Qt/input.h"
5660 #include "drivers/Qt/fceuWrapper.h"
5761 #include "drivers/Qt/TasEditor/selection.h"
5862 #include "drivers/Qt/TasEditor/laglog.h"
181185 persisted = true;
182186 FILE* inf = fopen(filename.c_str(),"rb");
183187 fseek(inf,0,SEEK_END);
184 int len = ftell(inf);
188 long int len = ftell(inf);
185189 fseek(inf,0,SEEK_SET);
186190 data = new EMUFILE_MEMORY(len);
187 fread(data->buf(),1,len,inf);
191 if ( fread(data->buf(),1,len,inf) != static_cast<size_t>(len) )
192 {
193 FCEU_printf("Warning: LuaSaveState::ensureLoad failed to load full buffer.\n");
194 }
188195 fclose(inf);
189196 }
190197 };
249256 static int frameAdvanceWaiting = FALSE;
250257
251258 // We save our pause status in the case of a natural death.
252 static int wasPaused = FALSE;
259 //static int wasPaused = FALSE;
253260
254261 // Transparency strength. 255=opaque, 0=so transparent it's invisible
255262 static int transparencyModifier = 255;
655662 return 0;
656663 #elif defined(__QT_DRIVER__)
657664 const char *nameo2 = luaL_checkstring(L,1);
658 char nameo[2048];
659
660 strncpy(nameo, nameo2, sizeof(nameo));
661 nameo[sizeof(nameo)-1] = 0;
662
663 LoadGameFromLua( nameo );
665 std::string nameo;
666
667 nameo.assign( nameo2 );
668
669 LoadGameFromLua( nameo.c_str() );
664670
665671 //lua_cpcall(L, emu_wait_for_rom_load, NULL);
666672 //printf("Attempting to Load ROM: '%s'\n", nameo );
742748
743749 while (FCEUI_GetCheat(i,NULL,&Caddr,&Cval,&Ccompare,NULL,&Ctype)) {
744750
745 if ((GGaddr == Caddr) && (GGval == Cval) && (GGcomp == Ccompare) && (Ctype == 1)) {
751 if ((static_cast<uint32>(GGaddr) == Caddr) && (GGval == static_cast<int>(Cval)) && (GGcomp == Ccompare) && (Ctype == 1)) {
746752 // Already Added, so consider it a success
747753 lua_pushboolean(L, true);
748754 return 1;
772778 int GGaddr, GGcomp, GGval;
773779 uint32 i=0;
774780
775 char * Cname;
781 std::string Cname;
776782 uint32 Caddr;
777783 uint8 Cval;
778784 int Ccompare, Ctype;
785791
786792 while (FCEUI_GetCheat(i,&Cname,&Caddr,&Cval,&Ccompare,NULL,&Ctype)) {
787793
788 if ((!strcmp(msg,Cname)) && (GGaddr == Caddr) && (GGval == Cval) && (GGcomp == Ccompare) && (Ctype == 1)) {
794 if ((Cname == msg) && (static_cast<uint32>(GGaddr) == Caddr) && (GGval == static_cast<int>(Cval)) && (GGcomp == Ccompare) && (Ctype == 1)) {
789795 // Delete cheat code
790796 if (FCEUI_DelCheat(i)) {
791797 lua_pushboolean(L, true);
13011307 for(int i=0;i<4;i++)
13021308 {
13031309 int r = 0;
1304 fread(&r, 1, 1, file);
1310 if ( fread(&r, 1, 1, file) == 0)
1311 {
1312 break;
1313 }
13051314 rv |= r << (i*8);
13061315 }
13071316 value = rv;
13451354 break;
13461355
13471356 cur->data = new unsigned char [cur->size];
1348 fread(cur->data, cur->size, 1, file);
1357 if ( fread(cur->data, cur->size, 1, file) == 0 )
1358 {
1359 memset( cur->data, 0, cur->size );
1360 }
13491361
13501362 Record* next = new Record();
13511363 memcpy(next, cur, sizeof(Record));
16311643 if(remaining <= 0)
16321644 return;
16331645
1634 const char* str = ptr; // for debugging
1646 //const char* str = ptr; // for debugging
16351647
16361648 // if there is a __tostring metamethod then call it
16371649 int usedMeta = luaL_callmeta(L, i, "__tostring");
19932005 {
19942006 const char* qualifiedRegisterName = luaL_checkstring(L,1);
19952007 lua_settop(L,0);
1996 for(int cpu = 0; cpu < sizeof(cpuToRegisterMaps)/sizeof(*cpuToRegisterMaps); cpu++)
2008 for(size_t cpu = 0; cpu < sizeof(cpuToRegisterMaps)/sizeof(*cpuToRegisterMaps); cpu++)
19972009 {
19982010 cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu];
19992011 int cpuNameLen = strlen(ctrm.cpuName);
20272039 const char* qualifiedRegisterName = luaL_checkstring(L,1);
20282040 unsigned long value = (unsigned long)(luaL_checkinteger(L,2));
20292041 lua_settop(L,0);
2030 for(int cpu = 0; cpu < sizeof(cpuToRegisterMaps)/sizeof(*cpuToRegisterMaps); cpu++)
2042 for(size_t cpu = 0; cpu < sizeof(cpuToRegisterMaps)/sizeof(*cpuToRegisterMaps); cpu++)
20312043 {
20322044 cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu];
20332045 int cpuNameLen = strlen(ctrm.cpuName);
22432255 #endif
22442256 lua_settop(L, 0);
22452257 lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]);
2246 for(int i = address; i != address+size; i++)
2258 for(unsigned int i = address; i != address+size; i++)
22472259 {
22482260 lua_rawgeti(L, -1, i);
22492261 if (lua_isfunction(L, -1))
24472459 case LUAMEMHOOK_WRITE: return LUAMEMHOOK_WRITE_SUB;
24482460 case LUAMEMHOOK_READ: return LUAMEMHOOK_READ_SUB;
24492461 case LUAMEMHOOK_EXEC: return LUAMEMHOOK_EXEC_SUB;
2462 default: return hookType;
24502463 }
24512464 }
24522465 return hookType;
24562469 {
24572470 return memory_registerHook(L, MatchHookTypeToCPU(L,LUAMEMHOOK_WRITE), 1);
24582471 }
2472 FCEU_MAYBE_UNUSED
24592473 static int memory_registerread(lua_State *L)
24602474 {
24612475 return memory_registerHook(L, MatchHookTypeToCPU(L,LUAMEMHOOK_READ), 1);
26372651 }
26382652 }
26392653 }
2654 #elif defined(__QT_DRIVER__)
2655 // Qt/SDL
2656 {
2657 const uint8_t *keyBuf = QtSDL_getKeyboardState(nullptr);
2658
2659 if (keyBuf)
2660 {
2661 char keyName[64];
2662 const char *keyOut = nullptr;
2663
2664 for (int i=0; i<SDL_NUM_SCANCODES; i++)
2665 {
2666 if (keyBuf[i])
2667 {
2668 SDL_Keycode k = SDL_GetKeyFromScancode( static_cast<SDL_Scancode>(i) );
2669
2670 const char* name = SDL_GetKeyName(k);
2671
2672 //printf("Key:%i '%s'\n", i, name);
2673
2674 if ( isalpha(name[0]) || isdigit(name[0]) )
2675 { // If name starts with letters or number, copy name without spaces
2676 int ii=0, jj=0;
2677 while (name[ii] != 0)
2678 {
2679 if ( isalpha(name[ii]) || isdigit(name[ii]) || (name[ii] == '_') )
2680 {
2681 keyName[jj] = name[ii]; jj++;
2682 }
2683 ii++;
2684 }
2685 keyName[jj] = 0;
2686
2687 keyOut = keyName;
2688 }
2689 else
2690 { // Handle special char names
2691 switch (name[0])
2692 {
2693 case '[':
2694 keyOut = "LeftBracket";
2695 break;
2696 case ']':
2697 keyOut = "RightBracket";
2698 break;
2699 case '{':
2700 keyOut = "LeftBrace";
2701 break;
2702 case '}':
2703 keyOut = "RightBrace";
2704 break;
2705 case ',':
2706 keyOut = "Comma";
2707 break;
2708 case '.':
2709 keyOut = "Period";
2710 break;
2711 case '~':
2712 keyOut = "Tilde";
2713 break;
2714 case '`':
2715 keyOut = "Backtick";
2716 break;
2717 case '|':
2718 keyOut = "VerticalBar";
2719 break;
2720 case '/':
2721 keyOut = "Slash";
2722 break;
2723 case '\\':
2724 keyOut = "BackSlash";
2725 break;
2726 case '+':
2727 keyOut = "Plus";
2728 break;
2729 case '=':
2730 keyOut = "Equals";
2731 break;
2732 case '_':
2733 keyOut = "Underscore";
2734 break;
2735 case '-':
2736 keyOut = "Minus";
2737 break;
2738 case ';':
2739 keyOut = "SemiColon";
2740 break;
2741 case ':':
2742 keyOut = "Colon";
2743 break;
2744 case '\'':
2745 case '\"':
2746 keyOut = "Quote";
2747 break;
2748 default:
2749 keyOut = name;
2750 break;
2751 }
2752
2753 }
2754 lua_pushboolean(L, true);
2755 lua_setfield(L, -2, keyOut);
2756 }
2757 }
2758 }
2759 }
26402760 #else
26412761 //SDL TODO: implement this for keyboard!!
26422762 #endif
31163236 {
31173237 LuaSaveData saveData;
31183238
3119 char luaSaveFilename [512];
3120 strncpy(luaSaveFilename, filename, 512);
3121 luaSaveFilename[512-(1+7/*strlen(".luasav")*/)] = '\0';
3122 strcat(luaSaveFilename, ".luasav");
3123 FILE* luaSaveFile = fopen(luaSaveFilename, "rb");
3239 std::string luaSaveFilename;
3240 luaSaveFilename.assign( filename );
3241 luaSaveFilename.append( ".luasav");
3242 FILE* luaSaveFile = fopen(luaSaveFilename.c_str(), "rb");
31243243 if(luaSaveFile)
31253244 {
31263245 saveData.ImportRecords(luaSaveFile);
37423861 *colour = ((rand()*255/RAND_MAX) << 8) | ((rand()*255/RAND_MAX) << 16) | ((rand()*255/RAND_MAX) << 24) | 0xFF;
37433862 return true;
37443863 }
3745 for(int i = 0; i < sizeof(s_colorMapping)/sizeof(*s_colorMapping); i++) {
3864 for(size_t i = 0; i < sizeof(s_colorMapping)/sizeof(*s_colorMapping); i++) {
37463865 if(!stricmp(str,s_colorMapping[i].name)) {
37473866 *colour = s_colorMapping[i].value;
37483867 return true;
37783897 lua_pushnil(L); // first key
37793898 int keyIndex = lua_gettop(L);
37803899 int valueIndex = keyIndex + 1;
3781 bool first = true;
37823900 while(lua_next(L, offset))
37833901 {
37843902 bool keyIsString = (lua_type(L, keyIndex) == LUA_TSTRING);
39844102 }
39854103
39864104 // (old) gui.box(x1, y1, x2, y2, color)
4105 FCEU_MAYBE_UNUSED
39874106 static int gui_box_old(lua_State *L) {
39884107
39894108 int x1,y1,x2,y2;
43134432 }
43144433 }
43154434
4435 FCEU_MAYBE_UNUSED
43164436 static int strlinelen(const char* string)
43174437 {
43184438 const char* s = string;
43234443 return s - string;
43244444 }
43254445
4446 FCEU_MAYBE_UNUSED
43264447 static void LuaDisplayString (const char *string, int y, int x, uint32 color, uint32 outlineColor)
43274448 {
43284449 if(!string)
44904611 return;
44914612
44924613 size_t len = l;
4493 int defaultAlpha = std::max<int>(0, std::min<int>(transparencyModifier, 255));
4614 //int defaultAlpha = std::max<int>(0, std::min<int>(transparencyModifier, 255));
44944615 int diffx;
44954616 int diffy = std::max<int>(0, std::min<int>(7, LUA_SCREEN_HEIGHT - y));
44964617
45594680 // main HUD.
45604681 static int gui_text(lua_State *L) {
45614682
4562 extern int font_height;
4683 //extern int font_height;
45634684 const char *msg;
45644685 int x, y;
45654686 size_t l;
49565077 return 0;
49575078 }
49585079
5080 // debugger.getsymboloffset()
5081 static int debugger_getsymboloffset(lua_State *L)
5082 {
5083 debugSymbol_t *sym = NULL;
5084
5085 const char *name = luaL_checkstring(L, 1);
5086
5087 if (lua_type(L, 2) == LUA_TNUMBER)
5088 {
5089 int bank = luaL_checkinteger(L, 2);
5090 sym = debugSymbolTable.getSymbol(bank, name);
5091 }
5092 else
5093 {
5094 sym = debugSymbolTable.getSymbolAtAnyBank(name);
5095 }
5096
5097 lua_pushinteger(L, sym ? sym->offset() : -1);
5098 return 1;
5099 }
5100
49595101 // TAS Editor functions library
49605102
49615103 // bool taseditor.registerauto()
49775119 if (!lua_isnil(L,1))
49785120 luaL_checktype(L, 1, LUA_TFUNCTION);
49795121
4980 const char* caption = NULL;
5122 FCEU_MAYBE_UNUSED const char* caption = NULL;
49815123 if (!lua_isnil(L, 2))
49825124 caption = lua_tostring(L, 2);
49835125
53635505 assert(iicon >= 0 && iicon <= 3);
53645506 if(!(iicon >= 0 && iicon <= 3)) iicon = 0;
53655507
5508 #ifdef __WIN_DRIVER__
53665509 static const char * const titles [] = {"Notice", "Question", "Warning", "Error"};
53675510 const char* answer = "ok";
53685511
5369 #ifdef __WIN_DRIVER__
53705512 static const int etypes [] = {MB_OK, MB_YESNO, MB_YESNOCANCEL, MB_OKCANCEL, MB_ABORTRETRYIGNORE};
53715513 static const int eicons [] = {MB_ICONINFORMATION, MB_ICONQUESTION, MB_ICONWARNING, MB_ICONERROR};
53725514 //StopSound(); //mbg merge 7/27/08
55115653 // We don't want parameters
55125654 if (!t[0]) {
55135655 fprintf(stderr, "[Press Enter]");
5514 fgets(buffer, sizeof(buffer), stdin);
5656 if ( fgets(buffer, sizeof(buffer), stdin) == nullptr )
5657 {
5658 FCEU_printf("Error: fgets from stdin failed\n");
5659 }
55155660 // We're done
55165661 return 0;
55175662
55185663 }
55195664 fprintf(stderr, "(%s): ", t);
5520 fgets(buffer, sizeof(buffer), stdin);
5665 if ( fgets(buffer, sizeof(buffer), stdin) == nullptr )
5666 {
5667 FCEU_printf("Error: fgets from stdin failed\n");
5668 buffer[0] = 0;
5669 }
55215670
55225671 // Check if the option is in the list
55235672 if (strchr(t, tolower(buffer[0]))) {
55705719 // TODO: more sophisticated interface
55715720 char filename[PATH_MAX];
55725721 printf("Enter %s filename: ", saveFile ? "save" : "open");
5573 fgets(filename, PATH_MAX, stdin);
5722 if ( fgets(filename, PATH_MAX, stdin) == nullptr )
5723 {
5724 FCEU_printf("Warning: fgets from stdin failed\n");
5725 filename[0] = 0;
5726 }
55745727 lua_newtable(L);
55755728 lua_pushstring(L, filename);
55765729 lua_rawseti(L, -2, 1);
58015954 }
58025955
58035956 // The function called periodically to ensure Lua doesn't run amok.
5957 FCEU_MAYBE_UNUSED
58045958 static void FCEU_LuaHookFunction(lua_State *L, lua_Debug *dbg) {
58055959
58065960 if (numTries-- == 0) {
61266280 {"getinstructionscount", debugger_getinstructionscount},
61276281 {"resetcyclescount", debugger_resetcyclescount},
61286282 {"resetinstructionscount", debugger_resetinstructionscount},
6283 {"getsymboloffset", debugger_getsymboloffset},
61296284 {NULL,NULL}
61306285 };
61316286
62876442
62886443 getfilepath = getfilepath.substr(0,getfilepath.find_last_of("/\\") + 1);
62896444
6290 SetCurrentDir(getfilepath.c_str());
6445 if ( SetCurrentDir(getfilepath.c_str()) != 0 )
6446 {
6447 FCEU_printf("Warning: Failed chdir failed to set current dir to: %s\n", getfilepath.c_str() );
6448 }
62916449
62926450 //stop any lua we might already have had running
62936451 FCEU_LuaStop();
113113 { 0 }
114114 };
115115
116 char curMovieFilename[512] = {0};
116 std::string curMovieFilename;
117117 MovieData currMovieData;
118118 MovieData defaultMovieData;
119119 int currRerecordCount; // Keep the global value
408408 , rerecordCount(0)
409409 , binaryFlag(false)
410410 , loadFrameCount(-1)
411 , fourscore(false)
411412 , microphone(false)
412413 , RAMInitOption(0)
413414 , RAMInitSeed(0)
691692 {
692693 LoadFM2_binarychunk(movieData, fp, size);
693694 return true;
694 } else if (isnewline && movieData.loadFrameCount == movieData.records.size())
695 } else if (isnewline && static_cast<size_t>(movieData.loadFrameCount) == movieData.records.size())
695696 // exit prematurely if loaded the specified amound of records
696697 return true;
697698 switch(state)
805806 FCEU_PrintError("Error opening movie output file: %s", fname);
806807 return NULL;
807808 }
808 strcpy(curMovieFilename, fname);
809 if ( fname != curMovieFilename.c_str() )
810 {
811 curMovieFilename.assign(fname);
812 }
809813
810814 return osRecordingMovie;
811815 }
825829 bool recording = (movieMode == MOVIEMODE_RECORD);
826830 assert((NULL != osRecordingMovie) == (recording != justToggledRecording) && "osRecordingMovie should be consistent with movie mode!");
827831
828 if (NULL == openRecordingMovie(curMovieFilename))
832 if (NULL == openRecordingMovie(curMovieFilename.c_str()))
829833 return;
830834
831835 currMovieData.dump(osRecordingMovie, false/*currMovieData.binaryFlag*/, recording);
873877 {
874878 assert(movieMode == MOVIEMODE_INACTIVE);
875879
876 curMovieFilename[0] = 0; //No longer a current movie filename
880 curMovieFilename.clear(); //No longer a current movie filename
877881 freshMovie = false; //No longer a fresh movie loaded
878882 if (bindSavestate) AutoSS = false; //If bind movies to savestates is true, then there is no longer a valid auto-save to load
879883
989993 return false;
990994 }
991995
992 if(currCartInfo->SaveGameLen[i] != len)
996 if(currCartInfo->SaveGameLen[i] != static_cast<unsigned int>(len))
993997 {
994998 FCEU_PrintError("movie battery load mismatch 3");
995999 return false;
10381042
10391043 currMovieData = MovieData();
10401044
1041 strcpy(curMovieFilename, fname);
1045 curMovieFilename.assign(fname);
10421046 FCEUFILE *fp = FCEU_fopen(fname,0,"rb",0);
10431047 if (!fp) return false;
10441048 if(fp->isArchive() && !_read_only) {
12191223 if (mr->command_fds_select())
12201224 FCEU_FDSSelect();
12211225 if (mr->command_vs_insertcoin())
1222 FCEU_VSUniCoin();
1226 FCEU_VSUniCoin(0);
1227 if (mr->command_vs_insertcoin2())
1228 FCEU_VSUniCoin(1);
1229 if (mr->command_vs_service())
1230 FCEU_VSUniService();
12231231 _currCommand = 0;
12241232 } else
12251233 #endif
12471255 if(mr->command_fds_select())
12481256 FCEU_FDSSelect();
12491257 if (mr->command_vs_insertcoin())
1250 FCEU_VSUniCoin();
1258 FCEU_VSUniCoin(0);
1259 if (mr->command_vs_insertcoin2())
1260 FCEU_VSUniCoin(1);
1261 if (mr->command_vs_service())
1262 FCEU_VSUniService();
12511263
12521264 joyports[0].load(mr);
12531265 joyports[1].load(mr);
12541266 }
12551267
12561268 //if we are on the last frame, then pause the emulator if the player requested it
1257 if (currFrameCounter == currMovieData.records.size()-1)
1269 if ( static_cast<size_t>(currFrameCounter) == currMovieData.records.size()-1)
12581270 {
12591271 if(FCEUD_PauseAfterPlayback())
12601272 {
13251337 case FCEUNPCMD_FDSINSERT: cmd = MOVIECMD_FDS_INSERT; break;
13261338 case FCEUNPCMD_FDSSELECT: cmd = MOVIECMD_FDS_SELECT; break;
13271339 case FCEUNPCMD_VSUNICOIN: cmd = MOVIECMD_VS_INSERTCOIN; break;
1340 case FCEUNPCMD_VSUNICOIN2: cmd = MOVIECMD_VS_INSERTCOIN2; break;
1341 case FCEUNPCMD_VSUNISERVICE: cmd = MOVIECMD_VS_SERVICE; break;
13281342 // all other netplay commands (e.g. FCEUNPCMD_VSUNIDIP0) are not supported by movie recorder for now
13291343 default: return;
13301344 }
14331447 #endif
14341448 movie_readonly = true;
14351449 }
1436 if (FCEU_isFileInArchive(curMovieFilename))
1450 if (FCEU_isFileInArchive(curMovieFilename.c_str()))
14371451 {
14381452 //a little rule: cant load states in read+write mode with a movie from an archive.
14391453 //so we are going to switch it to readonly mode in that case
15681582 //TODO: turn frame counter to red to get attention
15691583 if (!backupSavestates) //If backups are disabled we can just resume normally since we can't restore so stop movie and inform user
15701584 {
1571 FCEU_PrintError("Error: Savestate taken from a frame (%d) after the final frame in the savestated movie (%d) cannot be verified against current movie (%d). This is not permitted.\nUnable to restore backup, movie playback stopped.", currFrameCounter, tempMovieData.records.size() - 1, currMovieData.records.size() - 1);
1585 FCEU_PrintError("Error: Savestate taken from a frame (%d) after the final frame in the savestated movie (%zi) cannot be verified against current movie (%zi). This is not permitted.\nUnable to restore backup, movie playback stopped.", currFrameCounter, tempMovieData.records.size() - 1, currMovieData.records.size() - 1);
15721586 FCEUI_StopMovie();
15731587 } else
1574 FCEU_PrintError("Savestate taken from a frame (%d) after the final frame in the savestated movie (%d) cannot be verified against current movie (%d). This is not permitted.", currFrameCounter, tempMovieData.records.size() - 1, currMovieData.records.size() - 1);
1588 FCEU_PrintError("Savestate taken from a frame (%d) after the final frame in the savestated movie (%zi) cannot be verified against current movie (%zi). This is not permitted.", currFrameCounter, tempMovieData.records.size() - 1, currMovieData.records.size() - 1);
15751589 return false;
15761590 }
15771591 }
17271741 strcpy(message, "Movie is now Read+Write");
17281742
17291743 strcat(message, GetMovieModeStr());
1730 FCEU_DispMessage(message,0);
1744 FCEU_DispMessage("%s",0,message);
17311745 }
17321746
17331747 void FCEUI_MovieToggleRecording()
17711785
17721786 strcat(message, GetMovieModeStr());
17731787
1774 FCEU_DispMessage(message, 0);
1788 FCEU_DispMessage("%s",0,message);
17751789 }
17761790
17771791 void FCEUI_MovieInsertFrame()
17981812 strcat(message, GetMovieModeStr());
17991813 }
18001814
1801 FCEU_DispMessage(message, 0);
1815 FCEU_DispMessage("%s",0,message);
18021816 }
18031817
18041818 void FCEUI_MovieDeleteFrame()
18361850 strcat(message, GetMovieModeStr());
18371851 }
18381852
1839 FCEU_DispMessage(message, 0);
1853 FCEU_DispMessage("%s",0,message);
18401854 }
18411855
18421856 void FCEUI_MovieTruncate()
18741888 strcat(message, GetMovieModeStr());
18751889 }
18761890
1877 FCEU_DispMessage(message, 0);
1891 FCEU_DispMessage("%s",0,message);
18781892 }
18791893
18801894 void FCEUI_MovieNextRecordMode()
19441958 #endif
19451959 }
19461960
1947 string FCEUI_GetMovieName(void)
1961 std::string FCEUI_GetMovieName(void)
19481962 {
19491963 return curMovieFilename;
19501964 }
20382052 void FCEUI_MakeBackupMovie(bool dispMessage)
20392053 {
20402054 //This function generates backup movie files
2041 string currentFn; //Current movie fillename
2042 string backupFn; //Target backup filename
2043 string tempFn; //temp used in back filename creation
2055 std::string currentFn; //Current movie fillename
2056 std::string backupFn; //Target backup filename
2057 std::string tempFn; //temp used in back filename creation
20442058 stringstream stream;
20452059 int x; //Temp variable for string manip
20462060 bool exist = false; //Used to test if filename exists
8080 MOVIECMD_POWER = 2,
8181 MOVIECMD_FDS_INSERT = 4,
8282 MOVIECMD_FDS_SELECT = 8,
83 MOVIECMD_VS_INSERTCOIN = 16
83 MOVIECMD_VS_INSERTCOIN = 16,
84 MOVIECMD_VS_INSERTCOIN2 = 32,
85 MOVIECMD_VS_SERVICE = 64
8486 };
8587
8688 EMOVIEMODE FCEUMOV_Mode();
130132 bool command_fds_insert() { return (commands & MOVIECMD_FDS_INSERT) != 0; }
131133 bool command_fds_select() { return (commands & MOVIECMD_FDS_SELECT) != 0; }
132134 bool command_vs_insertcoin() { return (commands & MOVIECMD_VS_INSERTCOIN) != 0; }
135 bool command_vs_insertcoin2() { return (commands & MOVIECMD_VS_INSERTCOIN2) != 0; }
136 bool command_vs_service() { return (commands & MOVIECMD_VS_SERVICE) != 0; }
133137
134138 void toggleBit(int joy, int bit)
135139 {
209213 //whether microphone is enabled
210214 bool microphone;
211215
212 int getNumRecords() { return (int)records.size(); }
216 int getNumRecords() { return static_cast<int>( records.size() ); }
213217
214218 int RAMInitOption, RAMInitSeed;
215219
271275 extern EMOVIEMODE movieMode;
272276 extern MovieData currMovieData;
273277 extern int currFrameCounter;
274 extern char curMovieFilename[512];
278 extern std::string curMovieFilename;
275279 extern bool subtitlesOnAVI;
276280 extern bool freshMovie;
277281 extern bool movie_readonly;
121121 FCEUX_fstat(fileno(fp),&sb);
122122 len = sb.st_size;
123123 buf = (char*)FCEU_dmalloc(len); //mbg merge 7/17/06 added cast
124 fread(buf, 1, len, fp);
124 if ( fread(buf, 1, len, fp) != static_cast<size_t>(len) )
125 {
126 FCEU_printf("Warning: FCEUNET_SendFile failed to load complete file.\n");
127 }
125128 fclose(fp);
126129
127130 cbuf = (char*)FCEU_dmalloc(4 + len + len / 1000 + 12); //mbg merge 7/17/06 added cast
66 #define FCEUNPCMD_POWER 0x02
77
88 #define FCEUNPCMD_VSUNICOIN 0x07
9 #define FCEUNPCMD_VSUNIDIP0 0x08
9 #define FCEUNPCMD_VSUNIDIP0 0x08
10 #define FCEUNPCMD_VSUNICOIN2 0x20
11 #define FCEUNPCMD_VSUNISERVICE 0x21
12
1013 #define FCEUNPCMD_FDSINSERTx 0x10
1114 #define FCEUNPCMD_FDSINSERT 0x18
1215 //#define FCEUNPCMD_FDSEJECT 0x19
3131 #include "file.h"
3232 #include "fds.h"
3333 #include "cart.h"
34 #include "ines.h"
3435 #include "input.h"
3536 #include "state.h"
3637 #include "driver.h"
122123 static uint16 InitAddr; //configuration
123124 static uint16 LoadAddr; //configuration
124125
125 extern char LoadedRomFName[2048];
126
127126 NSF_HEADER NSFHeader; //mbg merge 6/29/06 - needs to be global
128127
129128 void NSFMMC5_Close(void);
4747 static uint8 joopcmd;
4848 static uint32 framets = 0;
4949 static uint32 frameptr = 0;
50 static uint8* moviedata = NULL;
50 static uint8* moviedata = nullptr;
5151 static uint32 moviedatasize = 0;
5252 static uint32 firstframeoffset = 0;
5353 static uint32 savestate_offset = 0;
625625 //ResetInputTypes();
626626
627627 fp->fseek(firstframeoffset,SEEK_SET);
628 moviedata = (uint8*)realloc(moviedata, moviedatasize);
628 uint8 *newMovieData = (uint8*)realloc(moviedata, moviedatasize);
629 if (newMovieData)
630 {
631 moviedata = newMovieData;
632 }
633 else
634 {
635 if (moviedata)
636 {
637 free(moviedata); moviedata = nullptr;
638 }
639 return FCM_CONVERTRESULT_REALLOC_FAIL;
640 }
629641 fp->fread((char*)moviedata,moviedatasize);
630642
631643 frameptr = 0;
668680 md.ports[0] = md.ports[1] = SI_GAMEPAD;
669681 }
670682
671 free(moviedata);
672 moviedata = 0;
683 if (moviedata)
684 {
685 free(moviedata);
686 moviedata = nullptr;
687 }
673688
674689 delete fp;
675690 return FCM_CONVERTRESULT_SUCCESS;
99 FCM_CONVERTRESULT_OLDVERSION,
1010 FCM_CONVERTRESULT_UNSUPPORTEDVERSION,
1111 FCM_CONVERTRESULT_STARTFROMSAVESTATENOTSUPPORTED,
12 FCM_CONVERTRESULT_REALLOC_FAIL,
1213 };
1314
1415 inline const char * EFCM_CONVERTRESULT_message(EFCM_CONVERTRESULT e)
8686 (type) (y + to_rgb [4] * i + to_rgb [5] * q)\
8787 )
8888
89 FCEU_MAYBE_UNUSED
8990 static void ApplyDeemphasisNTSC(int entry, u8& r, u8& g, u8& b)
9091 {
9192 static float const to_float = 1.0f / 0xFF;
251252 }
252253
253254 //classic algorithm
255 FCEU_MAYBE_UNUSED
254256 static void ApplyDeemphasisClassic(int entry, u8& r, u8& g, u8& b)
255257 {
256258 //DEEMPH BITS MAY BE ORDERED WRONG. PLEASE CHECK
33 #define EMPTY_PALETTE_64 EMPTY_PALETTE_16 EMPTY_PALETTE_16 EMPTY_PALETTE_16 EMPTY_PALETTE_16
44 #define EMPTY_PALETTE_DEEMPH_X_7 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64 EMPTY_PALETTE_64
55
6 //this assumes the color is already shifted <<2, as it is in these cases
7 #define P64RPC(x) ( ((x)&~3) | (((x)>>6)&3))
8
69 pal rp2c04001[512] = {
710 #include "rp2c04001.h"
811 EMPTY_PALETTE_DEEMPH_X_7
2225 EMPTY_PALETTE_DEEMPH_X_7
2326 };
2427
28 #undef P64RPC
29
2530 // Fixed palette entries used by the GUI
2631 pal palette_unvarying[] = {
27 { 0x00<<2,0x00<<2,0x00<<2}, // 0 = Black
28 { 0x3F<<2,0x3F<<2,0x34<<2}, // 1 = White
29 { 0x00<<2,0x00<<2,0x00<<2}, // 2 = Black
30 { 0x1d<<2,0x1d<<2,0x24<<2}, // 3 = Greyish
32 { 0x00,0x00,0x00}, // 0 = Black
33 { 0xFF,0xFF,0xD3}, // 1 = White
34 { 0x00,0x00,0x00}, // 2 = Black
35 { 0x75,0x75,0x92}, // 3 = Greyish
3136 { 190, 0, 0}, // 4 = Reddish
3237 { 51,255, 51}, // 5 = Bright green
3338 { 49, 14,200}, // 6 = Ultramarine Blue
5156 };
5257
5358
59 #define P64(x) (((x)<<2)|((x>>4)&3))
60
5461 // Default palette
5562 pal palette[512] = {
56
57 { 0x1D<<2, 0x1D<<2, 0x1D<<2 }, /* Value 0 */
58 { 0x09<<2, 0x06<<2, 0x23<<2 }, /* Value 1 */
59 { 0x00<<2, 0x00<<2, 0x2A<<2 }, /* Value 2 */
60 { 0x11<<2, 0x00<<2, 0x27<<2 }, /* Value 3 */
61 { 0x23<<2, 0x00<<2, 0x1D<<2 }, /* Value 4 */
62 { 0x2A<<2, 0x00<<2, 0x04<<2 }, /* Value 5 */
63 { 0x29<<2, 0x00<<2, 0x00<<2 }, /* Value 6 */
64 { 0x1F<<2, 0x02<<2, 0x00<<2 }, /* Value 7 */
65 { 0x10<<2, 0x0B<<2, 0x00<<2 }, /* Value 8 */
66 { 0x00<<2, 0x11<<2, 0x00<<2 }, /* Value 9 */
67 { 0x00<<2, 0x14<<2, 0x00<<2 }, /* Value 10 */
68 { 0x00<<2, 0x0F<<2, 0x05<<2 }, /* Value 11 */
69 { 0x06<<2, 0x0F<<2, 0x17<<2 }, /* Value 12 */
70 { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 13 */
71 { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 14 */
72 { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 15 */
73 { 0x2F<<2, 0x2F<<2, 0x2F<<2 }, /* Value 16 */
74 { 0x00<<2, 0x1C<<2, 0x3B<<2 }, /* Value 17 */
75 { 0x08<<2, 0x0E<<2, 0x3B<<2 }, /* Value 18 */
76 { 0x20<<2, 0x00<<2, 0x3C<<2 }, /* Value 19 */
77 { 0x2F<<2, 0x00<<2, 0x2F<<2 }, /* Value 20 */
78 { 0x39<<2, 0x00<<2, 0x16<<2 }, /* Value 21 */
79 { 0x36<<2, 0x0A<<2, 0x00<<2 }, /* Value 22 */
80 { 0x32<<2, 0x13<<2, 0x03<<2 }, /* Value 23 */
81 { 0x22<<2, 0x1C<<2, 0x00<<2 }, /* Value 24 */
82 { 0x00<<2, 0x25<<2, 0x00<<2 }, /* Value 25 */
83 { 0x00<<2, 0x2A<<2, 0x00<<2 }, /* Value 26 */
84 { 0x00<<2, 0x24<<2, 0x0E<<2 }, /* Value 27 */
85 { 0x00<<2, 0x20<<2, 0x22<<2 }, /* Value 28 */
86 { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 29 */
87 { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 30 */
88 { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 31 */
89 { 0x3F<<2, 0x3F<<2, 0x3F<<2 }, /* Value 32 */
90 { 0x0F<<2, 0x2F<<2, 0x3F<<2 }, /* Value 33 */
91 { 0x17<<2, 0x25<<2, 0x3F<<2 }, /* Value 34 */
92 { 0x33<<2, 0x22<<2, 0x3F<<2 }, /* Value 35 */
93 { 0x3D<<2, 0x1E<<2, 0x3F<<2 }, /* Value 36 */
94 { 0x3F<<2, 0x1D<<2, 0x2D<<2 }, /* Value 37 */
95 { 0x3F<<2, 0x1D<<2, 0x18<<2 }, /* Value 38 */
96 { 0x3F<<2, 0x26<<2, 0x0E<<2 }, /* Value 39 */
97 { 0x3C<<2, 0x2F<<2, 0x0F<<2 }, /* Value 40 */
98 { 0x20<<2, 0x34<<2, 0x04<<2 }, /* Value 41 */
99 { 0x13<<2, 0x37<<2, 0x12<<2 }, /* Value 42 */
100 { 0x16<<2, 0x3E<<2, 0x26<<2 }, /* Value 43 */
101 { 0x00<<2, 0x3A<<2, 0x36<<2 }, /* Value 44 */
102 { 0x1E<<2, 0x1E<<2, 0x1E<<2 }, /* Value 45 */
103 { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 46 */
104 { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 47 */
105 { 0x3F<<2, 0x3F<<2, 0x3F<<2 }, /* Value 48 */
106 { 0x2A<<2, 0x39<<2, 0x3F<<2 }, /* Value 49 */
107 { 0x31<<2, 0x35<<2, 0x3F<<2 }, /* Value 50 */
108 { 0x35<<2, 0x32<<2, 0x3F<<2 }, /* Value 51 */
109 { 0x3F<<2, 0x31<<2, 0x3F<<2 }, /* Value 52 */
110 { 0x3F<<2, 0x31<<2, 0x36<<2 }, /* Value 53 */
111 { 0x3F<<2, 0x2F<<2, 0x2C<<2 }, /* Value 54 */
112 { 0x3F<<2, 0x36<<2, 0x2A<<2 }, /* Value 55 */
113 { 0x3F<<2, 0x39<<2, 0x28<<2 }, /* Value 56 */
114 { 0x38<<2, 0x3F<<2, 0x28<<2 }, /* Value 57 */
115 { 0x2A<<2, 0x3C<<2, 0x2F<<2 }, /* Value 58 */
116 { 0x2C<<2, 0x3F<<2, 0x33<<2 }, /* Value 59 */
117 { 0x27<<2, 0x3F<<2, 0x3C<<2 }, /* Value 60 */
118 { 0x31<<2, 0x31<<2, 0x31<<2 }, /* Value 61 */
119 { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 62 */
120 { 0x00<<2, 0x00<<2, 0x00<<2 }, /* Value 63 */
63 { P64(0x1D), P64(0x1D), P64(0x1D)}, /* Value 0 */
64 { P64(0x09), P64(0x06), P64(0x23)}, /* Value 1 */
65 { P64(0x00), P64(0x00), P64(0x2A)}, /* Value 2 */
66 { P64(0x11), P64(0x00), P64(0x27)}, /* Value 3 */
67 { P64(0x23), P64(0x00), P64(0x1D)}, /* Value 4 */
68 { P64(0x2A), P64(0x00), P64(0x04)}, /* Value 5 */
69 { P64(0x29), P64(0x00), P64(0x00)}, /* Value 6 */
70 { P64(0x1F), P64(0x02), P64(0x00)}, /* Value 7 */
71 { P64(0x10), P64(0x0B), P64(0x00)}, /* Value 8 */
72 { P64(0x00), P64(0x11), P64(0x00)}, /* Value 9 */
73 { P64(0x00), P64(0x14), P64(0x00)}, /* Value 10 */
74 { P64(0x00), P64(0x0F), P64(0x05)}, /* Value 11 */
75 { P64(0x06), P64(0x0F), P64(0x17)}, /* Value 12 */
76 { P64(0x00), P64(0x00), P64(0x00)}, /* Value 13 */
77 { P64(0x00), P64(0x00), P64(0x00)}, /* Value 14 */
78 { P64(0x00), P64(0x00), P64(0x00)}, /* Value 15 */
79 { P64(0x2F), P64(0x2F), P64(0x2F)}, /* Value 16 */
80 { P64(0x00), P64(0x1C), P64(0x3B)}, /* Value 17 */
81 { P64(0x08), P64(0x0E), P64(0x3B)}, /* Value 18 */
82 { P64(0x20), P64(0x00), P64(0x3C)}, /* Value 19 */
83 { P64(0x2F), P64(0x00), P64(0x2F)}, /* Value 20 */
84 { P64(0x39), P64(0x00), P64(0x16)}, /* Value 21 */
85 { P64(0x36), P64(0x0A), P64(0x00)}, /* Value 22 */
86 { P64(0x32), P64(0x13), P64(0x03)}, /* Value 23 */
87 { P64(0x22), P64(0x1C), P64(0x00)}, /* Value 24 */
88 { P64(0x00), P64(0x25), P64(0x00)}, /* Value 25 */
89 { P64(0x00), P64(0x2A), P64(0x00)}, /* Value 26 */
90 { P64(0x00), P64(0x24), P64(0x0E)}, /* Value 27 */
91 { P64(0x00), P64(0x20), P64(0x22)}, /* Value 28 */
92 { P64(0x00), P64(0x00), P64(0x00)}, /* Value 29 */
93 { P64(0x00), P64(0x00), P64(0x00)}, /* Value 30 */
94 { P64(0x00), P64(0x00), P64(0x00)}, /* Value 31 */
95 { P64(0x3F), P64(0x3F), P64(0x3F)}, /* Value 32 */
96 { P64(0x0F), P64(0x2F), P64(0x3F)}, /* Value 33 */
97 { P64(0x17), P64(0x25), P64(0x3F)}, /* Value 34 */
98 { P64(0x33), P64(0x22), P64(0x3F)}, /* Value 35 */
99 { P64(0x3D), P64(0x1E), P64(0x3F)}, /* Value 36 */
100 { P64(0x3F), P64(0x1D), P64(0x2D)}, /* Value 37 */
101 { P64(0x3F), P64(0x1D), P64(0x18)}, /* Value 38 */
102 { P64(0x3F), P64(0x26), P64(0x0E)}, /* Value 39 */
103 { P64(0x3C), P64(0x2F), P64(0x0F)}, /* Value 40 */
104 { P64(0x20), P64(0x34), P64(0x04)}, /* Value 41 */
105 { P64(0x13), P64(0x37), P64(0x12)}, /* Value 42 */
106 { P64(0x16), P64(0x3E), P64(0x26)}, /* Value 43 */
107 { P64(0x00), P64(0x3A), P64(0x36)}, /* Value 44 */
108 { P64(0x1E), P64(0x1E), P64(0x1E)}, /* Value 45 */
109 { P64(0x00), P64(0x00), P64(0x00)}, /* Value 46 */
110 { P64(0x00), P64(0x00), P64(0x00)}, /* Value 47 */
111 { P64(0x3F), P64(0x3F), P64(0x3F)}, /* Value 48 */
112 { P64(0x2A), P64(0x39), P64(0x3F)}, /* Value 49 */
113 { P64(0x31), P64(0x35), P64(0x3F)}, /* Value 50 */
114 { P64(0x35), P64(0x32), P64(0x3F)}, /* Value 51 */
115 { P64(0x3F), P64(0x31), P64(0x3F)}, /* Value 52 */
116 { P64(0x3F), P64(0x31), P64(0x36)}, /* Value 53 */
117 { P64(0x3F), P64(0x2F), P64(0x2C)}, /* Value 54 */
118 { P64(0x3F), P64(0x36), P64(0x2A)}, /* Value 55 */
119 { P64(0x3F), P64(0x39), P64(0x28)}, /* Value 56 */
120 { P64(0x38), P64(0x3F), P64(0x28)}, /* Value 57 */
121 { P64(0x2A), P64(0x3C), P64(0x2F)}, /* Value 58 */
122 { P64(0x2C), P64(0x3F), P64(0x33)}, /* Value 59 */
123 { P64(0x27), P64(0x3F), P64(0x3C)}, /* Value 60 */
124 { P64(0x31), P64(0x31), P64(0x31)}, /* Value 61 */
125 { P64(0x00), P64(0x00), P64(0x00)}, /* Value 62 */
126 { P64(0x00), P64(0x00), P64(0x00)}, /* Value 63 */
127
128 #undef P64
121129
122130 //luke's .16+ palette
123131 //{0x60, 0x60, 0x60}, /* Value 0 */
0 {0xfc, 0xc4, 0xd8},
1 {0x40, 0x88, 0xfc},
2 {0xd8, 0x28, 0x00},
3 {0x5c, 0x94, 0xfc},
4 {0x00, 0x80, 0x88},
5 {0x00, 0x44, 0x00},
6 {0x00, 0x00, 0x00},
7 {0xe4, 0x00, 0x58},
8 {0xfc, 0xfc, 0xfc},
9 {0x74, 0x74, 0x74},
10 {0xfc, 0x98, 0x38},
11 {0xa8, 0x00, 0x10},
12 {0x8c, 0x00, 0x74},
13 {0xfc, 0x98, 0x38},
14 {0x40, 0x2c, 0x00},
15 {0xfc, 0xfc, 0xfc},
16 {0x3c, 0xbc, 0xfc},
17 {0x00, 0x00, 0x00},
18 {0x00, 0x00, 0x00},
19 {0x80, 0xd0, 0x10},
20 {0x9c, 0xfc, 0xf0},
21 {0xc4, 0xd4, 0xfc},
22 {0xfc, 0xbc, 0xb0},
23 {0x20, 0x38, 0xec},
24 {0x00, 0x00, 0x00},
25 {0x58, 0xf8, 0x98},
26 {0x00, 0x00, 0x00},
27 {0x00, 0x00, 0x00},
28 {0xfc, 0xfc, 0xfc},
29 {0xbc, 0xbc, 0xbc},
30 {0xf4, 0x78, 0xfc},
31 {0x24, 0x18, 0x8c},
32 {0x00, 0x00, 0x00},
33 {0xa8, 0xe4, 0xfc},
34 {0x00, 0x00, 0x00},
35 {0x4c, 0xdc, 0x48},
36 {0x00, 0xe8, 0xd8},
37 {0x18, 0x3c, 0x5c},
38 {0x00, 0x00, 0x00},
39 {0x00, 0x00, 0x00},
40 {0x00, 0x00, 0x00},
41 {0x7c, 0x08, 0x00},
42 {0xfc, 0xc4, 0xfc},
43 {0xa4, 0x00, 0x00},
44 {0x80, 0x00, 0xf0},
45 {0x00, 0x00, 0xa8},
46 {0xfc, 0x74, 0x60},
47 {0x00, 0x00, 0x00},
48 {0x00, 0x00, 0x00},
49 {0x00, 0x94, 0x00},
50 {0xbc, 0xbc, 0xbc},
51 {0x00, 0x50, 0x00},
52 {0xe0, 0xfc, 0xa0},
53 {0x00, 0x00, 0x00},
54 {0xfc, 0xd8, 0xa8},
55 {0xc8, 0x4c, 0x0c},
56 {0x00, 0x00, 0x00},
57 {0x00, 0x70, 0xec},
58 {0x00, 0x44, 0x00},
59 {0x00, 0x00, 0x00},
60 {0xe0, 0xfc, 0xa0},
61 {0xfc, 0x74, 0xb4},
62 {0x88, 0x70, 0x00},
63 {0x00, 0x00, 0x00},
0 {P64RPC(0xfc), P64RPC(0xc4), P64RPC(0xd8)},
1 {P64RPC(0x40), P64RPC(0x88), P64RPC(0xfc)},
2 {P64RPC(0xd8), P64RPC(0x28), P64RPC(0x00)},
3 {P64RPC(0x5c), P64RPC(0x94), P64RPC(0xfc)},
4 {P64RPC(0x00), P64RPC(0x80), P64RPC(0x88)},
5 {P64RPC(0x00), P64RPC(0x44), P64RPC(0x00)},
6 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
7 {P64RPC(0xe4), P64RPC(0x00), P64RPC(0x58)},
8 {P64RPC(0xfc), P64RPC(0xfc), P64RPC(0xfc)},
9 {P64RPC(0x74), P64RPC(0x74), P64RPC(0x74)},
10 {P64RPC(0xfc), P64RPC(0x98), P64RPC(0x38)},
11 {P64RPC(0xa8), P64RPC(0x00), P64RPC(0x10)},
12 {P64RPC(0x8c), P64RPC(0x00), P64RPC(0x74)},
13 {P64RPC(0xfc), P64RPC(0x98), P64RPC(0x38)},
14 {P64RPC(0x40), P64RPC(0x2c), P64RPC(0x00)},
15 {P64RPC(0xfc), P64RPC(0xfc), P64RPC(0xfc)},
16 {P64RPC(0x3c), P64RPC(0xbc), P64RPC(0xfc)},
17 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
18 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
19 {P64RPC(0x80), P64RPC(0xd0), P64RPC(0x10)},
20 {P64RPC(0x9c), P64RPC(0xfc), P64RPC(0xf0)},
21 {P64RPC(0xc4), P64RPC(0xd4), P64RPC(0xfc)},
22 {P64RPC(0xfc), P64RPC(0xbc), P64RPC(0xb0)},
23 {P64RPC(0x20), P64RPC(0x38), P64RPC(0xec)},
24 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
25 {P64RPC(0x58), P64RPC(0xf8), P64RPC(0x98)},
26 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
27 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
28 {P64RPC(0xfc), P64RPC(0xfc), P64RPC(0xfc)},
29 {P64RPC(0xbc), P64RPC(0xbc), P64RPC(0xbc)},
30 {P64RPC(0xf4), P64RPC(0x78), P64RPC(0xfc)},
31 {P64RPC(0x24), P64RPC(0x18), P64RPC(0x8c)},
32 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
33 {P64RPC(0xa8), P64RPC(0xe4), P64RPC(0xfc)},
34 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
35 {P64RPC(0x4c), P64RPC(0xdc), P64RPC(0x48)},
36 {P64RPC(0x00), P64RPC(0xe8), P64RPC(0xd8)},
37 {P64RPC(0x18), P64RPC(0x3c), P64RPC(0x5c)},
38 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
39 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
40 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
41 {P64RPC(0x7c), P64RPC(0x08), P64RPC(0x00)},
42 {P64RPC(0xfc), P64RPC(0xc4), P64RPC(0xfc)},
43 {P64RPC(0xa4), P64RPC(0x00), P64RPC(0x00)},
44 {P64RPC(0x80), P64RPC(0x00), P64RPC(0xf0)},
45 {P64RPC(0x00), P64RPC(0x00), P64RPC(0xa8)},
46 {P64RPC(0xfc), P64RPC(0x74), P64RPC(0x60)},
47 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
48 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
49 {P64RPC(0x00), P64RPC(0x94), P64RPC(0x00)},
50 {P64RPC(0xbc), P64RPC(0xbc), P64RPC(0xbc)},
51 {P64RPC(0x00), P64RPC(0x50), P64RPC(0x00)},
52 {P64RPC(0xe0), P64RPC(0xfc), P64RPC(0xa0)},
53 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
54 {P64RPC(0xfc), P64RPC(0xd8), P64RPC(0xa8)},
55 {P64RPC(0xc8), P64RPC(0x4c), P64RPC(0x0c)},
56 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
57 {P64RPC(0x00), P64RPC(0x70), P64RPC(0xec)},
58 {P64RPC(0x00), P64RPC(0x44), P64RPC(0x00)},
59 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
60 {P64RPC(0xe0), P64RPC(0xfc), P64RPC(0xa0)},
61 {P64RPC(0xfc), P64RPC(0x74), P64RPC(0xb4)},
62 {P64RPC(0x88), P64RPC(0x70), P64RPC(0x00)},
63 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
0 {0x00, 0x00, 0x00},
1 {0xfc, 0x98, 0x38},
2 {0x88, 0x70, 0x00},
3 {0x00, 0x00, 0x00},
4 {0xa8, 0xf0, 0xbc},
5 {0xfc, 0x74, 0xb4},
6 {0x00, 0x00, 0x00},
7 {0xa8, 0xe4, 0xfc},
8 {0xd8, 0x28, 0x00},
9 {0x80, 0x00, 0xf0},
10 {0xfc, 0xe4, 0xa0},
11 {0xfc, 0xc4, 0xfc},
12 {0xfc, 0xfc, 0xfc},
13 {0x40, 0x88, 0xfc},
14 {0x00, 0x00, 0x00},
15 {0x00, 0x3c, 0x14},
16 {0x00, 0x00, 0x00},
17 {0x3c, 0xbc, 0xfc},
18 {0xa4, 0x00, 0x00},
19 {0x00, 0x00, 0x00},
20 {0x00, 0x90, 0x38},
21 {0x80, 0xd0, 0x10},
22 {0x00, 0x00, 0x00},
23 {0x5c, 0x94, 0xfc},
24 {0x00, 0x00, 0x00},
25 {0xf4, 0x78, 0xfc},
26 {0x00, 0x00, 0x00},
27 {0x58, 0xf8, 0x98},
28 {0x00, 0x00, 0x00},
29 {0x40, 0x2c, 0x00},
30 {0x00, 0x00, 0x00},
31 {0x44, 0x00, 0x9c},
32 {0x00, 0x00, 0x00},
33 {0xfc, 0xbc, 0xb0},
34 {0xfc, 0x74, 0x60},
35 {0xd4, 0xc8, 0xfc},
36 {0x00, 0x70, 0xec},
37 {0x00, 0x00, 0x00},
38 {0xbc, 0xbc, 0xbc},
39 {0x00, 0x00, 0xa8},
40 {0xbc, 0x00, 0xbc},
41 {0x00, 0x00, 0x00},
42 {0x74, 0x74, 0x74},
43 {0x00, 0x44, 0x00},
44 {0x20, 0x38, 0xec},
45 {0x00, 0x00, 0x00},
46 {0xfc, 0xd8, 0xa8},
47 {0xfc, 0xfc, 0xfc},
48 {0x00, 0x00, 0x00},
49 {0x00, 0x00, 0x00},
50 {0x4c, 0xdc, 0x48},
51 {0xc8, 0x4c, 0x0c},
52 {0x18, 0x3c, 0x5c},
53 {0x24, 0x18, 0x8c},
54 {0xe4, 0x00, 0x58},
55 {0x00, 0x94, 0x00},
56 {0x00, 0x00, 0x00},
57 {0x00, 0xe8, 0xd8},
58 {0x7c, 0x08, 0x00},
59 {0xfc, 0xd8, 0xa8},
60 {0x00, 0x00, 0x00},
61 {0xa8, 0x00, 0x10},
62 {0x00, 0x50, 0x00},
63 {0x74, 0x74, 0x74},
0 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
1 {P64RPC(0xfc), P64RPC(0x98), P64RPC(0x38)},
2 {P64RPC(0x88), P64RPC(0x70), P64RPC(0x00)},
3 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
4 {P64RPC(0xa8), P64RPC(0xf0), P64RPC(0xbc)},
5 {P64RPC(0xfc), P64RPC(0x74), P64RPC(0xb4)},
6 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
7 {P64RPC(0xa8), P64RPC(0xe4), P64RPC(0xfc)},
8 {P64RPC(0xd8), P64RPC(0x28), P64RPC(0x00)},
9 {P64RPC(0x80), P64RPC(0x00), P64RPC(0xf0)},
10 {P64RPC(0xfc), P64RPC(0xe4), P64RPC(0xa0)},
11 {P64RPC(0xfc), P64RPC(0xc4), P64RPC(0xfc)},
12 {P64RPC(0xfc), P64RPC(0xfc), P64RPC(0xfc)},
13 {P64RPC(0x40), P64RPC(0x88), P64RPC(0xfc)},
14 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
15 {P64RPC(0x00), P64RPC(0x3c), P64RPC(0x14)},
16 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
17 {P64RPC(0x3c), P64RPC(0xbc), P64RPC(0xfc)},
18 {P64RPC(0xa4), P64RPC(0x00), P64RPC(0x00)},
19 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
20 {P64RPC(0x00), P64RPC(0x90), P64RPC(0x38)},
21 {P64RPC(0x80), P64RPC(0xd0), P64RPC(0x10)},
22 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
23 {P64RPC(0x5c), P64RPC(0x94), P64RPC(0xfc)},
24 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
25 {P64RPC(0xf4), P64RPC(0x78), P64RPC(0xfc)},
26 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
27 {P64RPC(0x58), P64RPC(0xf8), P64RPC(0x98)},
28 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
29 {P64RPC(0x40), P64RPC(0x2c), P64RPC(0x00)},
30 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
31 {P64RPC(0x44), P64RPC(0x00), P64RPC(0x9c)},
32 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
33 {P64RPC(0xfc), P64RPC(0xbc), P64RPC(0xb0)},
34 {P64RPC(0xfc), P64RPC(0x74), P64RPC(0x60)},
35 {P64RPC(0xd4), P64RPC(0xc8), P64RPC(0xfc)},
36 {P64RPC(0x00), P64RPC(0x70), P64RPC(0xec)},
37 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
38 {P64RPC(0xbc), P64RPC(0xbc), P64RPC(0xbc)},
39 {P64RPC(0x00), P64RPC(0x00), P64RPC(0xa8)},
40 {P64RPC(0xbc), P64RPC(0x00), P64RPC(0xbc)},
41 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
42 {P64RPC(0x74), P64RPC(0x74), P64RPC(0x74)},
43 {P64RPC(0x00), P64RPC(0x44), P64RPC(0x00)},
44 {P64RPC(0x20), P64RPC(0x38), P64RPC(0xec)},
45 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
46 {P64RPC(0xfc), P64RPC(0xd8), P64RPC(0xa8)},
47 {P64RPC(0xfc), P64RPC(0xfc), P64RPC(0xfc)},
48 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
49 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
50 {P64RPC(0x4c), P64RPC(0xdc), P64RPC(0x48)},
51 {P64RPC(0xc8), P64RPC(0x4c), P64RPC(0x0c)},
52 {P64RPC(0x18), P64RPC(0x3c), P64RPC(0x5c)},
53 {P64RPC(0x24), P64RPC(0x18), P64RPC(0x8c)},
54 {P64RPC(0xe4), P64RPC(0x00), P64RPC(0x58)},
55 {P64RPC(0x00), P64RPC(0x94), P64RPC(0x00)},
56 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
57 {P64RPC(0x00), P64RPC(0xe8), P64RPC(0xd8)},
58 {P64RPC(0x7c), P64RPC(0x08), P64RPC(0x00)},
59 {P64RPC(0xfc), P64RPC(0xd8), P64RPC(0xa8)},
60 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
61 {P64RPC(0xa8), P64RPC(0x00), P64RPC(0x10)},
62 {P64RPC(0x00), P64RPC(0x50), P64RPC(0x00)},
63 {P64RPC(0x74), P64RPC(0x74), P64RPC(0x74)},
0 {0x44, 0x00, 0x9c},
1 {0x00, 0x00, 0x00},
2 {0x00, 0x00, 0x00},
3 {0x74, 0x74, 0x74},
4 {0x00, 0xa8, 0x00},
5 {0xfc, 0xfc, 0xfc},
6 {0xa8, 0xe4, 0xfc},
7 {0x00, 0x44, 0x00},
8 {0x24, 0x18, 0x8c},
9 {0x00, 0x00, 0x00},
10 {0xfc, 0xbc, 0xb0},
11 {0x40, 0x2c, 0x00},
12 {0xe4, 0x00, 0x58},
13 {0x00, 0x00, 0x00},
14 {0x00, 0x00, 0x00},
15 {0xfc, 0xfc, 0xfc},
16 {0x5c, 0x94, 0xfc},
17 {0x00, 0x80, 0x88},
18 {0x00, 0x00, 0x00},
19 {0x20, 0x38, 0xec},
20 {0x00, 0x94, 0x00},
21 {0x88, 0x70, 0x00},
22 {0xc8, 0x4c, 0x0c},
23 {0x00, 0x90, 0x38},
24 {0x74, 0x74, 0x74},
25 {0x00, 0x00, 0x00},
26 {0x00, 0x00, 0x00},
27 {0x00, 0x00, 0xa8},
28 {0xd8, 0x28, 0x00},
29 {0xa4, 0x00, 0x00},
30 {0x00, 0x00, 0x00},
31 {0xfc, 0xc4, 0xd8},
32 {0x40, 0x88, 0xfc},
33 {0x00, 0x00, 0x00},
34 {0x00, 0x00, 0x00},
35 {0xfc, 0xd8, 0xa8},
36 {0x00, 0x00, 0x00},
37 {0xfc, 0x98, 0x38},
38 {0xfc, 0x74, 0x60},
39 {0xfc, 0xfc, 0xfc},
40 {0x80, 0xd0, 0x10},
41 {0x00, 0x00, 0x00},
42 {0x3c, 0xbc, 0xfc},
43 {0xf4, 0x78, 0xfc},
44 {0x00, 0x70, 0xec},
45 {0x00, 0x00, 0x00},
46 {0x00, 0x00, 0x00},
47 {0x00, 0x00, 0x00},
48 {0x00, 0xe8, 0xd8},
49 {0x00, 0x00, 0x00},
50 {0x00, 0x00, 0x00},
51 {0x00, 0x00, 0x00},
52 {0x7c, 0x08, 0x00},
53 {0x4c, 0xdc, 0x48},
54 {0xf0, 0xbc, 0x3c},
55 {0x00, 0x00, 0x00},
56 {0x00, 0x50, 0x00},
57 {0x00, 0x00, 0x00},
58 {0xc4, 0xd4, 0xfc},
59 {0xfc, 0xd8, 0xa8},
60 {0x80, 0x00, 0xf0},
61 {0x00, 0x00, 0x00},
62 {0x00, 0x00, 0x00},
63 {0x18, 0x3c, 0x5c},
0 {P64RPC(0x44), P64RPC(0x00), P64RPC(0x9c)},
1 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
2 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
3 {P64RPC(0x74), P64RPC(0x74), P64RPC(0x74)},
4 {P64RPC(0x00), P64RPC(0xa8), P64RPC(0x00)},
5 {P64RPC(0xfc), P64RPC(0xfc), P64RPC(0xfc)},
6 {P64RPC(0xa8), P64RPC(0xe4), P64RPC(0xfc)},
7 {P64RPC(0x00), P64RPC(0x44), P64RPC(0x00)},
8 {P64RPC(0x24), P64RPC(0x18), P64RPC(0x8c)},
9 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
10 {P64RPC(0xfc), P64RPC(0xbc), P64RPC(0xb0)},
11 {P64RPC(0x40), P64RPC(0x2c), P64RPC(0x00)},
12 {P64RPC(0xe4), P64RPC(0x00), P64RPC(0x58)},
13 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
14 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
15 {P64RPC(0xfc), P64RPC(0xfc), P64RPC(0xfc)},
16 {P64RPC(0x5c), P64RPC(0x94), P64RPC(0xfc)},
17 {P64RPC(0x00), P64RPC(0x80), P64RPC(0x88)},
18 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
19 {P64RPC(0x20), P64RPC(0x38), P64RPC(0xec)},
20 {P64RPC(0x00), P64RPC(0x94), P64RPC(0x00)},
21 {P64RPC(0x88), P64RPC(0x70), P64RPC(0x00)},
22 {P64RPC(0xc8), P64RPC(0x4c), P64RPC(0x0c)},
23 {P64RPC(0x00), P64RPC(0x90), P64RPC(0x38)},
24 {P64RPC(0x74), P64RPC(0x74), P64RPC(0x74)},
25 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
26 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
27 {P64RPC(0x00), P64RPC(0x00), P64RPC(0xa8)},
28 {P64RPC(0xd8), P64RPC(0x28), P64RPC(0x00)},
29 {P64RPC(0xa4), P64RPC(0x00), P64RPC(0x00)},
30 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
31 {P64RPC(0xfc), P64RPC(0xc4), P64RPC(0xd8)},
32 {P64RPC(0x40), P64RPC(0x88), P64RPC(0xfc)},
33 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
34 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
35 {P64RPC(0xfc), P64RPC(0xd8), P64RPC(0xa8)},
36 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
37 {P64RPC(0xfc), P64RPC(0x98), P64RPC(0x38)},
38 {P64RPC(0xfc), P64RPC(0x74), P64RPC(0x60)},
39 {P64RPC(0xfc), P64RPC(0xfc), P64RPC(0xfc)},
40 {P64RPC(0x80), P64RPC(0xd0), P64RPC(0x10)},
41 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
42 {P64RPC(0x3c), P64RPC(0xbc), P64RPC(0xfc)},
43 {P64RPC(0xf4), P64RPC(0x78), P64RPC(0xfc)},
44 {P64RPC(0x00), P64RPC(0x70), P64RPC(0xec)},
45 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
46 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
47 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
48 {P64RPC(0x00), P64RPC(0xe8), P64RPC(0xd8)},
49 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
50 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
51 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
52 {P64RPC(0x7c), P64RPC(0x08), P64RPC(0x00)},
53 {P64RPC(0x4c), P64RPC(0xdc), P64RPC(0x48)},
54 {P64RPC(0xf0), P64RPC(0xbc), P64RPC(0x3c)},
55 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
56 {P64RPC(0x00), P64RPC(0x50), P64RPC(0x00)},
57 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
58 {P64RPC(0xc4), P64RPC(0xd4), P64RPC(0xfc)},
59 {P64RPC(0xfc), P64RPC(0xd8), P64RPC(0xa8)},
60 {P64RPC(0x80), P64RPC(0x00), P64RPC(0xf0)},
61 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
62 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
63 {P64RPC(0x18), P64RPC(0x3c), P64RPC(0x5c)},
0 {0x88, 0x70, 0x00},
1 {0x00, 0x00, 0x00},
2 {0x00, 0x80, 0x88},
3 {0xf0, 0xbc, 0x3c},
4 {0x00, 0x00, 0x00},
5 {0x00, 0x00, 0x00},
6 {0x24, 0x18, 0x8c},
7 {0xc8, 0x4c, 0x0c},
8 {0xbc, 0xbc, 0xbc},
9 {0x00, 0x00, 0x00},
10 {0x4c, 0xdc, 0x48},
11 {0x00, 0x00, 0x00},
12 {0xfc, 0xbc, 0xb0},
13 {0xfc, 0xd8, 0xa8},
14 {0x00, 0xa8, 0x00},
15 {0x00, 0x00, 0x00},
16 {0xfc, 0x74, 0xb4},
17 {0x00, 0x00, 0x00},
18 {0x20, 0x38, 0xec},
19 {0x00, 0x00, 0x00},
20 {0x00, 0x00, 0x00},
21 {0x00, 0x00, 0x00},
22 {0x00, 0x00, 0x00},
23 {0xfc, 0x74, 0x60},
24 {0x00, 0x00, 0x00},
25 {0x00, 0x00, 0x00},
26 {0x5c, 0x94, 0xfc},
27 {0x00, 0x94, 0x00},
28 {0x00, 0x00, 0x00},
29 {0x00, 0x00, 0x00},
30 {0xa8, 0xf0, 0xbc},
31 {0x3c, 0xbc, 0xfc},
32 {0xa8, 0x00, 0x10},
33 {0x00, 0x50, 0x00},
34 {0x7c, 0x08, 0x00},
35 {0x00, 0x00, 0xa8},
36 {0x80, 0x00, 0xf0},
37 {0x00, 0x00, 0x00},
38 {0x74, 0x74, 0x74},
39 {0xe4, 0x00, 0x58},
40 {0x18, 0x3c, 0x5c},
41 {0x00, 0x00, 0x00},
42 {0x00, 0x70, 0xec},
43 {0x00, 0x00, 0x00},
44 {0x00, 0x00, 0x00},
45 {0xfc, 0xe4, 0xa0},
46 {0x00, 0x00, 0x00},
47 {0x00, 0x00, 0x00},
48 {0x00, 0x00, 0x00},
49 {0x00, 0x00, 0x00},
50 {0x40, 0x2c, 0x00},
51 {0xd8, 0x28, 0x00},
52 {0x00, 0x00, 0x00},
53 {0x00, 0x00, 0x00},
54 {0xfc, 0xfc, 0xfc},
55 {0x9c, 0xfc, 0xf0},
56 {0x00, 0x00, 0x00},
57 {0xfc, 0x98, 0x38},
58 {0x00, 0x00, 0x00},
59 {0xa8, 0xe4, 0xfc},
60 {0x80, 0xd0, 0x10},
61 {0x00, 0x00, 0x00},
62 {0xfc, 0xfc, 0xfc},
63 {0x00, 0x44, 0x00},
0 {P64RPC(0x88), P64RPC(0x70), P64RPC(0x00)},
1 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
2 {P64RPC(0x00), P64RPC(0x80), P64RPC(0x88)},
3 {P64RPC(0xf0), P64RPC(0xbc), P64RPC(0x3c)},
4 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
5 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
6 {P64RPC(0x24), P64RPC(0x18), P64RPC(0x8c)},
7 {P64RPC(0xc8), P64RPC(0x4c), P64RPC(0x0c)},
8 {P64RPC(0xbc), P64RPC(0xbc), P64RPC(0xbc)},
9 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
10 {P64RPC(0x4c), P64RPC(0xdc), P64RPC(0x48)},
11 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
12 {P64RPC(0xfc), P64RPC(0xbc), P64RPC(0xb0)},
13 {P64RPC(0xfc), P64RPC(0xd8), P64RPC(0xa8)},
14 {P64RPC(0x00), P64RPC(0xa8), P64RPC(0x00)},
15 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
16 {P64RPC(0xfc), P64RPC(0x74), P64RPC(0xb4)},
17 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
18 {P64RPC(0x20), P64RPC(0x38), P64RPC(0xec)},
19 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
20 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
21 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
22 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
23 {P64RPC(0xfc), P64RPC(0x74), P64RPC(0x60)},
24 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
25 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
26 {P64RPC(0x5c), P64RPC(0x94), P64RPC(0xfc)},
27 {P64RPC(0x00), P64RPC(0x94), P64RPC(0x00)},
28 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
29 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
30 {P64RPC(0xa8), P64RPC(0xf0), P64RPC(0xbc)},
31 {P64RPC(0x3c), P64RPC(0xbc), P64RPC(0xfc)},
32 {P64RPC(0xa8), P64RPC(0x00), P64RPC(0x10)},
33 {P64RPC(0x00), P64RPC(0x50), P64RPC(0x00)},
34 {P64RPC(0x7c), P64RPC(0x08), P64RPC(0x00)},
35 {P64RPC(0x00), P64RPC(0x00), P64RPC(0xa8)},
36 {P64RPC(0x80), P64RPC(0x00), P64RPC(0xf0)},
37 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
38 {P64RPC(0x74), P64RPC(0x74), P64RPC(0x74)},
39 {P64RPC(0xe4), P64RPC(0x00), P64RPC(0x58)},
40 {P64RPC(0x18), P64RPC(0x3c), P64RPC(0x5c)},
41 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
42 {P64RPC(0x00), P64RPC(0x70), P64RPC(0xec)},
43 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
44 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
45 {P64RPC(0xfc), P64RPC(0xe4), P64RPC(0xa0)},
46 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
47 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
48 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
49 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
50 {P64RPC(0x40), P64RPC(0x2c), P64RPC(0x00)},
51 {P64RPC(0xd8), P64RPC(0x28), P64RPC(0x00)},
52 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
53 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
54 {P64RPC(0xfc), P64RPC(0xfc), P64RPC(0xfc)},
55 {P64RPC(0x9c), P64RPC(0xfc), P64RPC(0xf0)},
56 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
57 {P64RPC(0xfc), P64RPC(0x98), P64RPC(0x38)},
58 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
59 {P64RPC(0xa8), P64RPC(0xe4), P64RPC(0xfc)},
60 {P64RPC(0x80), P64RPC(0xd0), P64RPC(0x10)},
61 {P64RPC(0x00), P64RPC(0x00), P64RPC(0x00)},
62 {P64RPC(0xfc), P64RPC(0xfc), P64RPC(0xfc)},
63 {P64RPC(0x00), P64RPC(0x44), P64RPC(0x00)},
5656
5757 #define PPU_status (PPU[2])
5858
59 #define READPALNOGS(ofs) (PALRAM[(ofs)])
5960 #define READPAL(ofs) (PALRAM[(ofs)] & (GRAYSCALE ? 0x30 : 0xFF))
6061 #define READUPAL(ofs) (UPALRAM[(ofs)] & (GRAYSCALE ? 0x30 : 0xFF))
6162
454455 unsigned char *cdloggervdata = NULL;
455456 unsigned int cdloggerVideoDataSize = 0;
456457
457 int GetCHRAddress(int A) {
458 if (cdloggerVideoDataSize) {
459 int result = &VPage[A >> 10][A] - CHRptr[0];
458 int GetCHRAddress(int A)
459 {
460 if (cdloggerVideoDataSize)
461 {
462 int result = -1;
463 if ( (A >= 0) && (A < 0x2000) )
464 {
465 result = &VPage[A >> 10][A] - CHRptr[0];
466 }
460467 if ((result >= 0) && (result < (int)cdloggerVideoDataSize))
468 {
461469 return result;
462 } else
463 if(A < 0x2000) return A;
470 }
471 }
472 else
473 {
474 if ( (A >= 0) && (A < 0x2000) ) return A;
475 }
464476 return -1;
465477 }
466478
19861998 struct BGData {
19871999 struct Record {
19882000 uint8 nt, pecnt, at, pt[2], qtnt;
2001 uint8 ppu1[8];
19892002
19902003 INLINE void Read() {
19912004 NTRefreshAddr = RefreshAddr = ppur.get_ntread();
19972010 }
19982011 pecnt = (RefreshAddr & 1) << 3;
19992012 nt = CALL_PPUREAD(RefreshAddr);
2000 runppu(kFetchTime);
2013 ppu1[0] = PPU[1];
2014 runppu(1);
2015 ppu1[1] = PPU[1];
2016 runppu(1);
2017
2018
20012019
20022020 RefreshAddr = ppur.get_atread();
20032021 at = CALL_PPUREAD(RefreshAddr);
20092027 at <<= 2;
20102028 //horizontal scroll clocked at cycle 3 and then
20112029 //vertical scroll at 251
2030 ppu1[2] = PPU[1];
20122031 runppu(1);
20132032 if (PPUON) {
20142033 ppur.increment_hsc();
20152034 if (ppur.status.cycle == 251)
20162035 ppur.increment_vs();
20172036 }
2037 ppu1[3] = PPU[1];
20182038 runppu(1);
20192039
20202040 ppur.par = nt;
20212041 RefreshAddr = ppur.get_ptread();
20222042 if (PEC586Hack) {
20232043 pt[0] = CALL_PPUREAD(RefreshAddr | pecnt);
2024 runppu(kFetchTime);
2044 ppu1[4] = PPU[1];
2045 runppu(1);
2046 ppu1[5] = PPU[1];
2047 runppu(1);
20252048 pt[1] = CALL_PPUREAD(RefreshAddr | pecnt);
2026 runppu(kFetchTime);
2049 ppu1[6] = PPU[1];
2050 runppu(1);
2051 ppu1[7] = PPU[1];
2052 runppu(1);
20272053 } else if (QTAIHack && (qtnt & 0x40)) {
20282054 pt[0] = *(CHRptr[0] + RefreshAddr);
2029 runppu(kFetchTime);
2055 ppu1[4] = PPU[1];
2056 runppu(1);
2057 ppu1[5] = PPU[1];
2058 runppu(1);
20302059 RefreshAddr |= 8;
20312060 pt[1] = *(CHRptr[0] + RefreshAddr);
2032 runppu(kFetchTime);
2061 ppu1[6] = PPU[1];
2062 runppu(1);
2063 ppu1[7] = PPU[1];
2064 runppu(1);
20332065 } else {
20342066 if (ScreenON)
20352067 RENDER_LOG(RefreshAddr);
20362068 pt[0] = CALL_PPUREAD(RefreshAddr);
2037 runppu(kFetchTime);
2069 ppu1[4] = PPU[1];
2070 runppu(1);
2071 ppu1[5] = PPU[1];
2072 runppu(1);
20382073 RefreshAddr |= 8;
20392074 if (ScreenON)
20402075 RENDER_LOG(RefreshAddr);
20412076 pt[1] = CALL_PPUREAD(RefreshAddr);
2042 runppu(kFetchTime);
2077 ppu1[6] = PPU[1];
2078 runppu(1);
2079 ppu1[7] = PPU[1];
2080 runppu(1);
20432081 }
20442082 }
20452083 };
22152253 pixel = ((pt[0] >> (7 - bgpx)) & 1) | (((pt[1] >> (7 - bgpx)) & 1) << 1) | bgdata.main[bgtile].at;
22162254 }
22172255 if (renderbg)
2218 pixelcolor = READPAL(pixel);
2256 pixelcolor = READPALNOGS(pixel);
22192257
22202258 //look for a sprite to be drawn
22212259 bool havepixel = false;
22602298 spixel |= (oam[2] & 3) << 2;
22612299
22622300 if (rendersprites)
2263 pixelcolor = READPAL(0x10 + spixel);
2301 pixelcolor = READPALNOGS(0x10 + spixel);
22642302 }
22652303 }
22662304
2267 *ptr++ = PaletteAdjustPixel(pixelcolor);
2268 *dptr++= PPU[1]>>5; //grab deemph
2305 //apply grayscale.. kind of clunky
2306 //really we need to read the entire palette instead of just ppu1
2307 //this will be needed for special color effects probably (very fine rainbows and whatnot?)
2308 //are you allowed to chang the palette mid-line anyway? well you can definitely change the grayscale flag as we know from the FF1 "polygon" effect
2309 if(bgdata.main[xt+2].ppu1[xp]&1)
2310 pixelcolor &= 0x30;
2311
2312 //this does deemph stuff inside it.. which is probably wrong...
2313 *ptr = PaletteAdjustPixel(pixelcolor);
2314
2315 ptr++;
2316
2317 //grab deemph..
2318 //I guess this works the same way as the grayscale, ideally?
2319 *dptr++ = bgdata.main[xt+2].ppu1[xp]>>5;
22692320 }
22702321 }
22712322 }
55 #endif
66
77 #ifndef PPUT_MMC5SP
8 uint8 zz;
8 FCEU_MAYBE_UNUSED uint8 zz;
99 #else
1010 uint8 xs, ys;
1111 xs = X1;
533533 PrepDPCM();
534534 else
535535 {
536 SIRQStat|=0x80;
537 if(DMCFormat&0x80)
536 if(DMCFormat&0x80) {
537 SIRQStat|=0x80;
538538 X6502_IRQBegin(FCEU_IQDPCM);
539 }
539540 }
540541 }
541542 }
6969 //tells the save system innards that we're loading the old format
7070 bool FCEU_state_loading_old_format = false;
7171
72 char lastSavestateMade[2048]; //Stores the filename of the last savestate made (needed for UndoSavestate)
72 std::string lastSavestateMade; //Stores the filename of the last savestate made (needed for UndoSavestate)
7373 bool undoSS = false; //This will be true if there is lastSavestateMade, it was made since ROM was loaded, a backup state for lastSavestateMade exists
7474 bool redoSS = false; //This will be true if UndoSaveState is run, will turn false when a new savestate is made
7575
76 char lastLoadstateMade[2048]; //Stores the filename of the last state loaded (needed for Undo/Redo loadstate)
76 std::string lastLoadstateMade; //Stores the filename of the last state loaded (needed for Undo/Redo loadstate)
7777 bool undoLS = false; //This will be true if a backupstate was made and it was made since ROM was loaded
7878 bool redoLS = false; //This will be true if a backupstate was loaded, meaning redoLoadState can be run
7979
8787 // temporary buffer for compressed data of a savestate
8888 std::vector<uint8> compressed_buf;
8989
90 #define SFMDATA_SIZE (64)
90 #define SFMDATA_SIZE (128)
9191 static SFORMAT SFMDATA[SFMDATA_SIZE];
9292 static int SFEXINDEX;
9393
109109 { &X.Y, 1, "Y\0\0"},
110110 { &X.S, 1, "S\0\0"},
111111 { &X.P, 1, "P\0\0"},
112 { &X.DB, 1, "DB"},
112 { &X.DB, 1, "DB\0"},
113113 { &RAM, 0x800 | FCEUSTATE_INDIRECT, "RAM", },
114114 { 0 }
115115 };
132132
133133 while(sf->v)
134134 {
135 if(sf->s==~0) //Link to another struct
135 if(sf->s==~0u) //Link to another struct
136136 {
137137 uint32 tmp;
138138
190190 {
191191 while(sf->v)
192192 {
193 if(sf->s==~0) // Link to another SFORMAT structure.
193 if(sf->s==~0u) // Link to another SFORMAT structure.
194194 {
195195 SFORMAT *tmp;
196196 if((tmp= CheckS((SFORMAT *)sf->v, tsize, desc) ))
306306 // load back buffer
307307 {
308308 extern uint8 *XBackBuf;
309 if(is->fread((char*)XBackBuf,size) != size)
310 ret = false;
309 //ignore 8 garbage bytes, whose idea was it to write these or even have them there in the first place
310 if(size == 256*256+8)
311 {
312 if(is->fread((char*)XBackBuf,256*256) != 256*256)
313 ret = false;
314 is->fseek(8,SEEK_CUR);
315 }
316 else
317 {
318 if(is->fread((char*)XBackBuf,size) != size)
319 ret = false;
320 }
321
311322
312323 //MBG TODO - can this be moved to a better place?
313324 //does it even make sense, displaying XBuf when its XBackBuf we just loaded?
314325 #ifdef __WIN_DRIVER__
315 else
326 if(ret)
316327 {
317328 FCEUD_BlitScreen(XBuf);
318329 UpdateFCEUWindow();
403414 // save back buffer
404415 {
405416 extern uint8 *XBackBuf;
406 uint32 size = 256 * 256 + 8;
417 uint32 size = 256 * 256;
407418 os->fputc(8);
408419 write32le(size, os);
409420 os->fwrite((char*)XBackBuf,size);
415426 if(SPostSave) SPostSave();
416427
417428 //save the length of the file
418 int len = memory_savestate.size();
429 size_t len = memory_savestate.size();
419430
420431 //sanity check: len and totalsize should be the same
421432 if(len != totalsize)
426437
427438 int error = Z_OK;
428439 uint8* cbuf = (uint8*)memory_savestate.buf();
429 uLongf comprlen = -1;
440 uLongf comprlen = ~0lu;
430441 if(compressionLevel != Z_NO_COMPRESSION && (compressSavestates || FCEUMOV_Mode(MOVIEMODE_TASEDITOR)))
431442 {
432443 // worst case compression: zlib says "0.1% larger than sourceLen plus 12 bytes"
445456
446457 //dump it to the destination file
447458 outstream->fwrite((char*)header,16);
448 outstream->fwrite((char*)cbuf,comprlen==-1?totalsize:comprlen);
459 outstream->fwrite((char*)cbuf,comprlen==~0lu?totalsize:comprlen);
449460
450461 return error == Z_OK;
451462 }
454465 void FCEUSS_Save(const char *fname, bool display_message)
455466 {
456467 EMUFILE* st = 0;
457 char fn[2048];
468 std::string fn;
458469
459470 if (geniestage==1)
460471 {
466477 if(fname) //If filename is given use it.
467478 {
468479 st = FCEUD_UTF8_fstream(fname, "wb");
469 strcpy(fn, fname);
480 fn.assign(fname);
470481 }
471482 else //Else, generate one
472483 {
473484 //FCEU_PrintError("daCurrentState=%d",CurrentState);
474 strcpy(fn, FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0).c_str());
485 fn = FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0);
475486
476487 //backup existing savestate first
477 if (CheckFileExists(fn) && backupSavestates) //adelikat: If the files exists and we are allowed to make backup savestates
478 {
479 CreateBackupSaveState(fn); //Make a backup of previous savestate before overwriting it
480 strcpy(lastSavestateMade,fn); //Remember what the last savestate filename was (for undoing later)
488 if (CheckFileExists(fn.c_str()) && backupSavestates) //adelikat: If the files exists and we are allowed to make backup savestates
489 {
490 CreateBackupSaveState(fn.c_str()); //Make a backup of previous savestate before overwriting it
491 lastSavestateMade.assign(fn); //Remember what the last savestate filename was (for undoing later)
481492 undoSS = true; //Backup was created so undo is possible
482493 }
483494 else
484495 undoSS = false; //so backup made so lastSavestateMade does have a backup file, so no undo
485496
486 st = FCEUD_UTF8_fstream(fn,"wb");
497 st = FCEUD_UTF8_fstream(fn.c_str(),"wb");
487498 }
488499
489500 if (st == NULL || st->get_fp() == NULL)
499510 LuaSaveData saveData;
500511 CallRegisteredLuaSaveFunctions(CurrentState, saveData);
501512
502 char luaSaveFilename [512];
503 strncpy(luaSaveFilename, fn, 512);
504 luaSaveFilename[512-(1+7/*strlen(".luasav")*/)] = '\0';
505 strcat(luaSaveFilename, ".luasav");
513 std::string luaSaveFilename;
514 luaSaveFilename.assign(fn.c_str());
515 luaSaveFilename.append(".luasav");
506516 if(saveData.recordList)
507517 {
508 FILE* luaSaveFile = fopen(luaSaveFilename, "wb");
518 FILE* luaSaveFile = fopen(luaSaveFilename.c_str(), "wb");
509519 if(luaSaveFile)
510520 {
511521 saveData.ExportRecords(luaSaveFile);
514524 }
515525 else
516526 {
517 unlink(luaSaveFilename);
527 unlink(luaSaveFilename.c_str());
518528 }
519529 }
520530 #endif
654664 return ret;
655665 }
656666
657 int totalsize = FCEU_de32lsb(header + 4);
658 int stateversion = FCEU_de32lsb(header + 8);
659 int comprlen = FCEU_de32lsb(header + 12);
667 size_t totalsize = FCEU_de32lsb(header + 4);
668 int stateversion = FCEU_de32lsb(header + 8);
669 uint32_t comprlen = FCEU_de32lsb(header + 12);
660670
661671 // reinit memory_savestate
662672 // memory_savestate is global variable which already has its vector of bytes, so no need to allocate memory every time we use save/loadstate
663 if ((int)(memory_savestate.get_vec())->size() < totalsize)
673 if ((memory_savestate.get_vec())->size() < totalsize)
664674 (memory_savestate.get_vec())->resize(totalsize);
665675 memory_savestate.set_len(totalsize);
666676 memory_savestate.unfail();
667677 memory_savestate.fseek(0, SEEK_SET);
668678
669 if(comprlen != -1)
679 if(comprlen != ~0u)
670680 {
671681 // the savestate is compressed: read from is to compressed_buf, then decompress from compressed_buf to memory_savestate.vec
672 if ((int)compressed_buf.size() < comprlen) compressed_buf.resize(comprlen);
682 if (compressed_buf.size() < comprlen) compressed_buf.resize(comprlen);
673683 is->fread(&compressed_buf[0], comprlen);
674684
675685 uLongf uncomprlen = totalsize;
711721
712722 bool FCEUSS_Load(const char *fname, bool display_message)
713723 {
714 EMUFILE* st;
715 char fn[2048];
724 fceuScopedPtr <EMUFILE> st; // fceuScopedPtr will auto delete the allocated EMUFILE at function return.
725 std::string fn;
716726
717727 //mbg movie - this needs to be overhauled
718728 ////this fixes read-only toggle problems
730740 if (fname)
731741 {
732742 st = FCEUD_UTF8_fstream(fname, "rb");
733 strcpy(fn, fname);
734 } else
735 {
736 strcpy(fn, FCEU_MakeFName(FCEUMKF_STATE,CurrentState,fname).c_str());
737 st=FCEUD_UTF8_fstream(fn,"rb");
738 strcpy(lastLoadstateMade,fn);
739 }
740
741 if (st == NULL || (st->get_fp() == NULL))
743 fn.assign(fname);
744 }
745 else
746 {
747 fn = FCEU_MakeFName(FCEUMKF_STATE,CurrentState,fname);
748 st=FCEUD_UTF8_fstream(fn.c_str(),"rb");
749 lastLoadstateMade.assign(fn);
750 }
751
752 if (st.get() == NULL || (st.get()->get_fp() == NULL))
742753 {
743754 if (display_message)
744755 {
745756 FCEU_DispMessage("State %d load error.", 0, CurrentState);
746 //FCEU_DispMessage("State %d load error. Filename: %s", 0, CurrentState, fn);
757 //FCEU_DispMessage("State %d load error. Filename: %s", 0, CurrentState, fn.c_str());
747758 }
748759 SaveStateStatus[CurrentState] = 0;
749760 return false;
752763 //If in bot mode, don't do a backup when loading.
753764 //Otherwise you eat at the hard disk, since so many
754765 //states are being loaded.
755 if (FCEUSS_LoadFP(st, backupSavestates ? SSLOADPARAM_BACKUP : SSLOADPARAM_NOBACKUP))
766 if (FCEUSS_LoadFP(st.get(), backupSavestates ? SSLOADPARAM_BACKUP : SSLOADPARAM_NOBACKUP))
756767 {
757768 if (fname)
758769 {
759770 char szFilename[260]={0};
760771 splitpath(fname, 0, 0, szFilename, 0);
761 if (display_message)
772 if (display_message)
762773 {
763 FCEU_DispMessage("State %s loaded.", 0, szFilename);
764 //FCEU_DispMessage("State %s loaded. Filename: %s", 0, szFilename, fn);
765 }
766 } else
767 {
768 if (display_message)
774 FCEU_DispMessage("State %s loaded.", 0, szFilename);
775 //FCEU_DispMessage("State %s loaded. Filename: %s", 0, szFilename, fn.c_str());
776 }
777 }
778 else
779 {
780 if (display_message)
769781 {
770 FCEU_DispMessage("State %d loaded.", 0, CurrentState);
771 //FCEU_DispMessage("State %d loaded. Filename: %s", 0, CurrentState, fn);
772 }
782 FCEU_DispMessage("State %d loaded.", 0, CurrentState);
783 //FCEU_DispMessage("State %d loaded. Filename: %s", 0, CurrentState, fn.c_str());
784 }
773785 SaveStateStatus[CurrentState] = 1;
774786 }
775 delete st;
776787
777788 #ifdef _S9XLUA_H
778789 if (!internalSaveLoad)
779790 {
780791 LuaSaveData saveData;
781792
782 char luaSaveFilename [512];
783 strncpy(luaSaveFilename, fn, 512);
784 luaSaveFilename[512-(1+7/*strlen(".luasav")*/)] = '\0';
785 strcat(luaSaveFilename, ".luasav");
786 FILE* luaSaveFile = fopen(luaSaveFilename, "rb");
793 std::string luaSaveFilename;
794 luaSaveFilename.assign(fn.c_str());
795 luaSaveFilename.append(".luasav");
796 FILE* luaSaveFile = fopen(luaSaveFilename.c_str(), "rb");
787797 if(luaSaveFile)
788798 {
789799 saveData.ImportRecords(luaSaveFile);
795805 #endif
796806
797807 #ifdef __WIN_DRIVER__
798 Update_RAM_Search(); // Update_RAM_Watch() is also called.
808 Update_RAM_Search(); // Update_RAM_Watch() is also called.
799809 #endif
800810
801811 //Update input display if movie is loaded
805815 cur_input_display = FCEU_GetJoyJoy(); //Input display should show the last buttons pressed (stored in the savestate)
806816
807817 return true;
808 } else
818 }
819 else
809820 {
810821 if(!fname)
811822 SaveStateStatus[CurrentState] = 1;
815826 FCEU_DispMessage("Error(s) reading state %d!", 0, CurrentState);
816827 //FCEU_DispMessage("Error(s) reading state %d! Filename: %s", 0, CurrentState, fn);
817828 }
818 delete st;
819829 return 0;
820830 }
821831 }
847857 for(x=0;x<SFEXINDEX;x++)
848858 {
849859 if(SFMDATA[x].desc)
850 free( (void*)SFMDATA[x].desc);
860 FCEU_free( (void*)SFMDATA[x].desc);
851861 }
852862 // adelikat, 3/14/09: had to add this to clear out the size parameter. NROM(mapper 0) games were having savestate crashes if loaded after a non NROM game because the size variable was carrying over and causing savestates to save too much data
853863 SFMDATA[0].s = 0;
862872 //do not accept extra state information if a null pointer was provided for v, so list won't terminate early
863873 if (v == 0) return;
864874
865 if(s==~0)
875 if(s==~0u)
866876 {
867877 SFORMAT* sf = (SFORMAT*)v;
868878 std::map<std::string,bool> names;
10551065 //Both files must exist
10561066 //--------------------------------------------------------------------------------------------
10571067
1058 if (!lastSavestateMade)
1068 if (lastSavestateMade.empty())
10591069 {
10601070 FCEUI_DispMessage("Can't Undo",0);
10611071 FCEUI_printf("Undo savestate was attempted but unsuccessful because there was not a recently used savestate.\n");
10621072 return; //If there is no last savestate, can't undo
10631073 }
1064 string backup = GenerateBackupSaveStateFn(lastSavestateMade); //Get filename of backup state
1074 string backup = GenerateBackupSaveStateFn(lastSavestateMade.c_str()); //Get filename of backup state
10651075 if (!CheckFileExists(backup.c_str()))
10661076 {
10671077 FCEUI_DispMessage("Can't Undo",0);
10751085 string temp = backup; //Put backup filename in temp
10761086 temp.append("x"); //Add x
10771087
1078 rename(backup.c_str(),temp.c_str()); //rename backup file to temp file
1079 rename(lastSavestateMade,backup.c_str()); //rename current as backup
1080 rename(temp.c_str(),lastSavestateMade); //rename backup as current
1088 rename(backup.c_str(),temp.c_str()); //rename backup file to temp file
1089 rename(lastSavestateMade.c_str(),backup.c_str()); //rename current as backup
1090 rename(temp.c_str(),lastSavestateMade.c_str()); //rename backup as current
10811091
10821092 undoSS = true; //Just in case, if this was run, then there is definately a last savestate and backup
10831093 if (redoSS) //This was a redo function, so if run again it will be an undo again
11021112 string filename;
11031113 int x;
11041114
1105 filename = strdup(FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0).c_str()); //Generate normal savestate filename
1115 filename = FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0); //Generate normal savestate filename
11061116 x = filename.find_last_of("."); //Find last dot
11071117 filename = filename.substr(0,x); //Chop off file extension
11081118 filename.append(".bak.fc0"); //add .bak
11601170 void RedoLoadState()
11611171 {
11621172 if (!redoLS) return;
1163 if (lastLoadstateMade && redoLS)
1164 {
1165 FCEUSS_Load(lastLoadstateMade);
1166 FCEUI_printf("Redoing %s\n",lastLoadstateMade);
1173 if (!lastLoadstateMade.empty() && redoLS)
1174 {
1175 FCEUSS_Load(lastLoadstateMade.c_str());
1176 FCEUI_printf("Redoing %s\n",lastLoadstateMade.c_str());
11671177 }
11681178 redoLS = false; //Flag that RedoLoadState can not be run again
11691179 undoLS = true; //Flag that LoadBackup can be run again
1616 * along with this program; if not, write to the Free Software
1717 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1818 */
19 #include <string>
1920
2021 enum ENUM_SSLOADPARAMS
2122 {
6667 void RedoLoadState(); //reloads a loadstate if backupsavestate was run
6768 void SwapSaveState(); //Swaps a savestate with its backup state
6869
69 extern char lastSavestateMade[2048]; //Filename of last savestate used
70 extern std::string lastSavestateMade; //Filename of last savestate used
7071 extern bool undoSS; //undo savestate flag
7172 extern bool redoSS; //redo savestate flag
72 extern char lastLoadstateMade[2048]; //Filename of last state loaded
73 extern std::string lastLoadstateMade; //Filename of last state loaded
7374 extern bool undoLS; //undo loadstate flag
7475 extern bool redoLS; //redo savestate flag
7576 extern bool backupSavestates; //Whether or not to make backups, true by default
6060 #ifdef __MINGW32__
6161 #define alloca __builtin_alloca
6262 #endif
63
64 //#include <typeinfo>
6365
6466 #include <sys/types.h>
6567 #include <sys/stat.h>
130132
131133 #endif
132134
133 #if defined(WIN32) && !defined(__QT_DRIVER__)
135 #if defined(WIN32) && !defined(__QT_DRIVER__) && !defined(__WIN_DRIVER__)
134136 #define __WIN_DRIVER__
135137 #endif
136138
142144 #define CTASSERT(x) typedef char __assert ## y[(x) ? 1 : -1];
143145 #endif
144146
147 #define __FCEU_STRINGIZE2(x) #x
148 #define __FCEU_STRINGIZE(x) __FCEU_STRINGIZE2(x)
149
150 #define FCEU_CPP_HAS_STD(x) ( defined(__cplusplus) && (__cplusplus >= x) )
151
152 #ifdef __has_cpp_attribute
153 #define FCEU_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
154 #else
155 #define FCEU_HAS_CPP_ATTRIBUTE(x) 0
156 #endif
157
158 #define FCEU_UNUSED(x) (void)(x)
159
160 #if FCEU_CPP_HAS_STD(201603L) || FCEU_HAS_CPP_ATTRIBUTE(maybe_unused)
161 #define FCEU_MAYBE_UNUSED [[maybe_unused]]
162 #else
163 #define FCEU_MAYBE_UNUSED
164 #endif
165
166 #if defined(_MSC_VER)
167 // Microsoft compiler won't catch format issues, but VS IDE can catch on analysis mode
168 #define __FCEU_PRINTF_FORMAT _In_z_ _Printf_format_string_
169 #define __FCEU_PRINTF_ATTRIBUTE( fmt, va )
170
171 #elif defined(__GNUC__) || defined(__clang__) || FCEU_HAS_CPP_ATTRIBUTE(format)
172 // GCC and Clang compilers will perform printf format type checks, useful for catching format errors.
173 #define __FCEU_PRINTF_FORMAT
174 #define __FCEU_PRINTF_ATTRIBUTE( fmt, va ) __attribute__((__format__(__printf__, fmt, va)))
175
176 #else
177 #define __FCEU_PRINTF_FORMAT
178 #define __FCEU_PRINTF_ATTRIBUTE( fmt, va )
179 #endif
180
181 // Scoped pointer ensures that memory pointed to by this object gets cleaned up
182 // and deallocated when this object goes out of scope. Helps prevent memory leaks
183 // on temporary memory allocations in functions with early outs.
184 template <typename T>
185 class fceuScopedPtr
186 {
187 public:
188 fceuScopedPtr( T *ptrIn = nullptr )
189 {
190 //printf("Scoped Pointer Constructor <%s>: %p\n", typeid(T).name(), ptrIn );
191 ptr = ptrIn;
192 }
193
194 ~fceuScopedPtr(void)
195 {
196 //printf("Scoped Pointer Destructor <%s>: %p\n", typeid(T).name(), ptr );
197 if (ptr)
198 {
199 delete ptr;
200 ptr = nullptr;
201 }
202 }
203
204 T* operator= (T *ptrIn)
205 {
206 ptr = ptrIn;
207 return ptr;
208 }
209
210 T* get(void)
211 {
212 return ptr;
213 }
214
215 void Delete(void)
216 {
217 if (ptr)
218 {
219 delete ptr;
220 ptr = nullptr;
221 }
222 }
223
224 private:
225 T *ptr;
226
227 };
228
145229 #include "utils/endian.h"
146230
147231 #endif
139139 return(0);
140140 FCEU_printf(" %02x", t);
141141 }
142 FCEU_printf("\n Default Name/Attribute Table Mirroring: Horizontal\n", uchead.info);
142 FCEU_printf("\n Default Name/Attribute Table Mirroring: Horizontal\n");
143143 mirrortodo = 0;
144144 }
145145 return(1);
474474 { "FNS", FNS_Init, BMCFLAG_16KCHRR },
475475 { "BS-400R", BS400R_Init, 0 },
476476 { "BS-4040R", BS4040R_Init, 0 },
477 { "COOLGIRL", COOLGIRL_Init, 0 },
477478
478479 { 0, 0, 0 }
479480 };
161161 void FNS_Init(CartInfo *info);
162162 void BS400R_Init(CartInfo *info);
163163 void BS4040R_Init(CartInfo *info);
164 void SMD132_SMD133_Init(CartInfo *info);
164 void AA6023_Init(CartInfo *info);
165 void COOLGIRL_Init(CartInfo* info);
165166
166167 extern uint8 *UNIFchrrama; // Meh. So I can stop CHR RAM
167168 // bank switcherooing with certain boards...
2727 #include "../fceu.h"
2828 #include "memory.h"
2929
30 ///allocates the specified number of bytes. exits process if this fails
30 void *FCEU_amalloc(size_t size, size_t alignment)
31 {
32 size = (size + alignment - 1) & ~(alignment-1);
33
34 #ifdef _MSC_VER
35 void *ret = _aligned_malloc(size,alignment);
36 #else
37 void *ret = aligned_alloc(alignment,size);
38 #endif
39
40 if(!ret)
41 FCEU_abort("Error allocating memory!");
42
43 return ret;
44 }
45
46 void FCEU_afree(void* ptr)
47 {
48 #ifdef _MSC_VER
49 _aligned_free(ptr);
50 #else
51 free(ptr);
52 #endif
53 }
54
55 static void *_FCEU_malloc(uint32 size)
56 {
57 void* ret = malloc(size);
58
59 if(!ret)
60 FCEU_abort("Error allocating memory!");
61
62 return ret;
63 }
64
65 static void _FCEU_free(void* ptr)
66 {
67 free(ptr);
68 }
69
3170 void *FCEU_gmalloc(uint32 size)
3271 {
33
34 void *ret;
35 ret=malloc(size);
36 if(!ret)
37 {
38 FCEU_PrintError("Error allocating memory! Doing a hard exit.");
39 exit(1);
40 }
41 FCEU_MemoryRand((uint8*)ret,size,true); // initialize according to RAMInitOption, default zero
42 return ret;
72 void *ret = _FCEU_malloc(size);
73
74 // initialize according to RAMInitOption, default zero
75 FCEU_MemoryRand((uint8*)ret,size,true);
76
77 return ret;
4378 }
4479
45 ///allocates the specified number of bytes. returns null if this fails
4680 void *FCEU_malloc(uint32 size)
4781 {
48 void *ret;
49 ret=malloc(size);
50 if(!ret)
51 {
52 FCEU_PrintError("Error allocating memory!");
53 return(0);
54 }
55 memset(ret,0,size); // initialize to 0
56 return ret;
82 void *ret = _FCEU_malloc(size);
83 memset(ret, 0, size);
84 return ret;
5785 }
5886
59 ///frees memory allocated with FCEU_gmalloc
6087 void FCEU_gfree(void *ptr)
6188 {
62 free(ptr);
89 _FCEU_free(ptr);
6390 }
6491
65 ///frees memory allocated with FCEU_malloc
66 void FCEU_free(void *ptr) // Might do something with this and FCEU_malloc later...
92 void FCEU_free(void *ptr)
6793 {
68 free(ptr);
94 _FCEU_free(ptr);
6995 }
7096
7197 void *FCEU_dmalloc(uint32 size)
7298 {
73 return malloc(size);
99 return FCEU_malloc(size);
74100 }
75101
76102 void FCEU_dfree(void *ptr)
77103 {
78 free(ptr);
104 return FCEU_free(ptr);
79105 }
106
107 void* FCEU_realloc(void* ptr, size_t size)
108 {
109 return realloc(ptr,size);
110 }
111
112 void FCEU_abort(const char* message)
113 {
114 if(message) FCEU_PrintError("%s", message);
115 abort();
116 }
2323
2424 #define FCEU_dwmemset(d,c,n) {int _x; for(_x=n-4;_x>=0;_x-=4) *(uint32 *)&(d)[_x]=c;}
2525
26 void *FCEU_malloc(uint32 size); // initialized to 0
27 void *FCEU_gmalloc(uint32 size); // used by boards for WRAM etc, initialized to 0 (default) or other via RAMInitOption
26 //returns a buffer initialized to 0
27 void *FCEU_malloc(uint32 size);
28
29 //returns a buffer, with jumbled initial contents
30 //used by boards for WRAM etc, initialized to 0 (default) or other via RAMInitOption
31 void *FCEU_gmalloc(uint32 size);
32
33 //free memory allocated with FCEU_gmalloc
2834 void FCEU_gfree(void *ptr);
35
36 //returns an aligned buffer, initialized to 0
37 //the alignment will default to the largest thing you could ever sensibly want for massively aligned cache friendly buffers
38 void *FCEU_amalloc(size_t size, size_t alignment = 256);
39
40 //frees memory allocated with FCEU_amalloc
41 void FCEU_afree(void* ptr);
42
43 //free memory allocated with FCEU_malloc
2944 void FCEU_free(void *ptr);
30 void FCEU_memmove(void *d, void *s, uint32 l);
3145
32 // wrapper for debugging when its needed, otherwise act like
33 // normal malloc/free
46 //reallocate memory allocated with FCEU_malloc
47 void* FCEU_realloc(void* ptr, size_t size);
48
49 //don't use these. change them if you find them.
3450 void *FCEU_dmalloc(uint32 size);
51
52 //don't use these. change them if you find them.
3553 void FCEU_dfree(void *ptr);
54
55 //aborts the process for fatal errors
56 void FCEU_abort(const char* message = nullptr);
0 // mutex.cpp
1 #include <cstdio>
2
3 #include "mutex.h"
4
5 namespace FCEU
6 {
7
8 //-----------------------------------------------------
9 // Cross platform mutex
10 // __QT_DRIVER__ multi-threaded application that uses Qt mutex implementation for synchronization
11 // __WIN_DRIVER__ is single thread application so sync methods are unimplemented.
12 //-----------------------------------------------------
13 mutex::mutex(void)
14 {
15 #ifdef __QT_DRIVER__
16 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
17 mtx = new QRecursiveMutex();
18 #else
19 mtx = new QMutex( QMutex::Recursive );
20 #endif
21 #endif
22
23 }
24
25 mutex::~mutex(void)
26 {
27 #ifdef __QT_DRIVER__
28 if (mtx)
29 {
30 delete mtx;
31 mtx = nullptr;
32 }
33 #endif
34 }
35
36 void mutex::lock(void)
37 {
38 #ifdef __QT_DRIVER__
39 mtx->lock();
40 #endif
41 }
42
43 void mutex::unlock(void)
44 {
45 #ifdef __QT_DRIVER__
46 mtx->unlock();
47 #endif
48 }
49
50 //-----------------------------------------------------
51 // Scoped AutoLock
52 //-----------------------------------------------------
53 autoScopedLock::autoScopedLock( mutex *mtx )
54 {
55 m = mtx;
56 if (m)
57 {
58 m->lock();
59 }
60 }
61
62 autoScopedLock::~autoScopedLock(void)
63 {
64 if (m)
65 {
66 m->unlock();
67 }
68 }
69
70 };
0 // mutex.h
1
2 #ifdef __QT_DRIVER__
3 #include <QMutex>
4 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
5 #include <QRecursiveMutex>
6 #endif
7 #endif
8
9 namespace FCEU
10 {
11 class mutex
12 {
13 public:
14 mutex(void);
15 ~mutex(void);
16
17 void lock(void);
18 void unlock(void);
19
20 private:
21 #ifdef __QT_DRIVER__
22 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
23 QRecursiveMutex *mtx;
24 #else
25 QMutex *mtx;
26 #endif
27 #endif
28 };
29
30 class autoScopedLock
31 {
32 public:
33 autoScopedLock( mutex *mtx );
34 ~autoScopedLock(void);
35
36 private:
37 mutex *m;
38 };
39
40 };
193193 data[62] = '+'; // 62
194194 data[63] = '/'; // 63
195195 // create ascii->value mapping (but due to overlap, write it to highbit region)
196 for(a=0; a<64; ++a) data[data[a]^0x80] = a; //
196 for(a=0; a<64; ++a) data[data[a]^0x80] = static_cast<unsigned char>(a); //
197197 data[((unsigned char)'=') ^ 0x80] = 0;
198198 }
199199 unsigned char operator[] (size_t pos) const { return data[pos]; }
6161
6262 #define FCEU_VERSION_MAJOR 2
6363 #define FCEU_VERSION_MINOR 6
64 #define FCEU_VERSION_PATCH 4
64 #define FCEU_VERSION_PATCH 5
6565
6666 #define FCEU_VERSION_NUMERIC ( (FCEU_VERSION_MAJOR*10000) + (FCEU_VERSION_MINOR*100) + (FCEU_VERSION_PATCH) )
6767 #define FCEU_VERSION_MAJOR_DECODE(x) ( (x / 10000) )
6868 #define FCEU_VERSION_MINOR_DECODE(x) ( (x / 100) % 100 )
6969 #define FCEU_VERSION_PATCH_DECODE(x) (x % 100)
7070
71 #define FCEU_VERSION_STRING "2.6.4" FCEU_SUBVERSION_STRING FCEU_FEATURE_STRING FCEU_COMPILER
71 #define FCEU_VERSION_STRING "2.6.5" FCEU_SUBVERSION_STRING FCEU_FEATURE_STRING FCEU_COMPILER
7272 #define FCEU_NAME_AND_VERSION FCEU_NAME " " FCEU_VERSION_STRING
7373
7474 #endif
9090 {
9191 if ( XBuf )
9292 {
93 FCEU_free(XBuf); XBuf = NULL;
93 FCEU_afree(XBuf); XBuf = NULL;
9494 }
9595 if ( XBackBuf )
9696 {
97 FCEU_free(XBackBuf); XBackBuf = NULL;
97 FCEU_afree(XBackBuf); XBackBuf = NULL;
9898 }
9999 if ( XDBuf )
100100 {
101 FCEU_free(XDBuf); XDBuf = NULL;
101 FCEU_afree(XDBuf); XDBuf = NULL;
102102 }
103103 if ( XDBackBuf )
104104 {
105 FCEU_free(XDBackBuf); XDBackBuf = NULL;
105 FCEU_afree(XDBackBuf); XDBackBuf = NULL;
106106 }
107107 //printf("Video Core Cleanup\n");
108108 }
115115 int FCEU_InitVirtualVideo(void)
116116 {
117117 //Some driver code may allocate XBuf externally.
118 //256 bytes per scanline, * 240 scanline maximum, +16 for alignment,
118 //256 bytes per scanline, * 240 scanline maximum
119119 if(XBuf)
120120 return 1;
121121
122 XBuf = (u8*)FCEU_malloc(256 * 256 + 16);
123 XBackBuf = (u8*)FCEU_malloc(256 * 256 + 16);
124 XDBuf = (u8*)FCEU_malloc(256 * 256 + 16);
125 XDBackBuf = (u8*)FCEU_malloc(256 * 256 + 16);
126 if(!XBuf || !XBackBuf || !XDBuf || !XDBackBuf)
127 {
128 return 0;
129 }
122 XBuf = (u8*)FCEU_amalloc(256 * 256);
123 XBackBuf = (u8*)FCEU_amalloc(256 * 256);
124 XDBuf = (u8*)FCEU_amalloc(256 * 256);
125 XDBackBuf = (u8*)FCEU_amalloc(256 * 256);
126
130127
131128 xbsave = XBuf;
132
133 if( sizeof(uint8*) == 4 )
134 {
135 uintptr_t m = (uintptr_t)XBuf;
136 m = ( 8 - m) & 7;
137 XBuf+=m;
138 }
139129
140130 memset(XBuf,128,256*256);
141131 memset(XBackBuf,128,256*256);
142 memset(XBuf,128,256*256);
143 memset(XBackBuf,128,256*256);
132 memset(XDBuf,0,256*256);
133 memset(XDBackBuf,0,256*256);
144134
145135 return 1;
146136 }
399389 FCEUI_AviVideoUpdate(XBuf);
400390 }
401391
402 void FCEU_DispMessageOnMovie(const char *format, ...)
392 void FCEU_DispMessageOnMovie( __FCEU_PRINTF_FORMAT const char *format, ...)
403393 {
404394 va_list ap;
405395
418408 guiMessage.howlong = 0;
419409 }
420410
421 void FCEU_DispMessage(const char *format, int disppos=0, ...)
411 void FCEU_DispMessage( __FCEU_PRINTF_FORMAT const char *format, int disppos=0, ...)
422412 {
423413 va_list ap;
424414
431421 vsnprintf(temp,sizeof(temp),format,ap);
432422 va_end(ap);
433423 strcat(temp, "\n");
434 FCEU_printf(temp);
424 FCEU_printf("%s",temp);
435425
436426 if ( vidGuiMsgEna )
437427 {
66 void ResetScreenshotsCounter();
77 uint32 GetScreenPixel(int x, int y, bool usebackup);
88 int GetScreenPixelPalette(int x, int y, bool usebackup);
9
10 //in case we need more flags in the future we can change the size here
11 //bit0 : monochrome bit
12 //bit5 : emph red
13 //bit6 : emph green
14 //bit7 : emph blue
15 typedef uint8 xfbuf_t;
16
917 extern uint8 *XBuf;
1018 extern uint8 *XBackBuf;
1119 extern uint8 *XDBuf;
1220 extern uint8 *XDBackBuf;
21 extern xfbuf_t *XFBuf;
22
1323 extern int ClipSidesOffset;
1424
1525 struct GUIMESSAGE
2525 #include "vsuni.h"
2626 #include "state.h"
2727 #include "driver.h"
28 #include "cart.h"
29 #include "ines.h"
2830
2931 #include <cstring>
3032 #include <cstdio>
3133
32 #define IOPTION_GUN 0x1
33 #define IOPTION_SWAPDIRAB 0x2
34
35 #define IOPTION_PREDIP 0x10
36 typedef struct {
37 const char *name;
38 uint64 md5partial;
39 int mapper;
40 int mirroring;
41 int ppu;
42 int ioption;
43 int predip;
44 } VSUNIENTRY;
45
46 VSUNIENTRY *curvs;
47
48 static uint8 DIPS = 0;
34 static int DIPS_howlong = 0;
4935 uint8 vsdip = 0;
5036
51 void FCEUI_VSUniToggleDIPView(void) {
52 DIPS = !DIPS;
53 }
54
5537 void FCEU_VSUniToggleDIP(int w) {
38 if (GameInfo->type != GIT_VSUNI) {
39 FCEU_DispMessage("Not Vs. System; toggle DIP switch.", 0);
40 return;
41 }
5642 vsdip ^= 1 << w;
43 DIPS_howlong = 180;
44 FCEU_DispMessage("DIP switch %d is %s.", 0, w, vsdip & (1 << w) ? "on" : "off");
5745 }
5846
5947 void FCEUI_VSUniSetDIP(int w, int state) {
6553 return(vsdip);
6654 }
6755
68 static uint8 secdata[2][32] =
56 static uint8 secdata_tko[32] =
6957 {
70 {
71 0xff, 0xbf, 0xb7, 0x97, 0x97, 0x17, 0x57, 0x4f,
72 0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90, 0x94, 0x14,
73 0x56, 0x4e, 0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90,
74 0xd4, 0x5c, 0x3e, 0x26, 0x87, 0x83, 0x13, 0x00
75 },
76 {
77 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00,
78 0x00, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x94, 0x00,
79 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
81 }
58 0xff, 0xbf, 0xb7, 0x97, 0x97, 0x17, 0x57, 0x4f,
59 0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90, 0x94, 0x14,
60 0x56, 0x4e, 0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90,
61 0xd4, 0x5c, 0x3e, 0x26, 0x87, 0x83, 0x13, 0x00
62 };
63 static uint8 secdata_rbi[32] =
64 {
65 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00,
66 0x00, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x94, 0x00,
67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8269 };
8370
8471 static uint8 *secptr;
9279 }
9380 return(0x00);
9481 }
82
9583 uint8 coinon = 0;
96
97 void FCEU_VSUniCoin(void) {
98 coinon = 6;
99 }
100
101 static int curppu;
102 static int64 curmd5;
103
104 #define RP2C04_001 1
105 #define RP2C04_002 2
106 #define RP2C04_003 3
107 #define RP2C05_004 4
108 #define RCP2C03B 5
109 #define RC2C05_01 6
110 #define RC2C05_02 7
111 #define RC2C05_03 8
112 #define RC2C05_04 9
84 uint8 coinon2 = 0;
85 uint8 service = 0;
86
87 void FCEU_VSUniCoin(uint8 slot) {
88 if (GameInfo->type != GIT_VSUNI)
89 FCEU_DispMessage("Not Vs. System; can't insert coin.", 0);
90 else {
91 switch (slot) {
92 case 0:
93 coinon = 6; break;
94 case 1:
95 coinon2 = 6; break;
96 }
97 }
98 }
99
100 void FCEU_VSUniService() {
101 if (GameInfo->type != GIT_VSUNI)
102 FCEU_DispMessage("Not Vs. System; can't press service button.", 0);
103 else
104 service = 6;
105 }
113106
114107 static readfunc OldReadPPU;
115108 static writefunc OldWritePPU[2];
125118 static DECLFR(A2002_MBJ) { // Mighty Bomb Jack
126119 return((OldReadPPU(A) & ~0x3F) | 0x3D);
127120 }
128
129121 static DECLFW(B2000_2001_2C05) {
130122 OldWritePPU[(A & 1) ^ 1](A ^ 1, V);
131123 }
124
132125 static uint8 xevselect = 0;
133126 static DECLFR(XevRead) {
134127 if (A == 0x54FF) {
145138 }
146139
147140 void FCEU_VSUniSwap(uint8 *j0, uint8 *j1) {
148 if (curvs->ioption & IOPTION_SWAPDIRAB) {
141 if (GameInfo->vs_cswitch) {
149142 uint16 t = *j0;
150143 *j0 = (*j0 & 0xC) | (*j1 & 0xF3);
151144 *j1 = (*j1 & 0xC) | (t & 0xF3);
153146 }
154147
155148 void FCEU_VSUniPower(void) {
156 coinon = 0;
149 coinon = coinon2 = service = 0;
157150 VSindex = 0;
158151
159152 if (secptr)
160153 SetReadHandler(0x5e00, 0x5e01, VSSecRead);
161154
162 if (curppu == RC2C05_04) {
155 switch (GameInfo->vs_ppu) {
156 case GIPPU_RP2C04_0001:
157 case GIPPU_RP2C04_0002:
158 case GIPPU_RP2C04_0003:
159 case GIPPU_RP2C04_0004:
160 default_palette_selection = GameInfo->vs_ppu;
161 break;
162 default:
163 // nothing todo
164 break;
165 }
166 if (GameInfo->vs_ppu == GIPPU_RC2C05_04) {
163167 OldReadPPU = GetReadHandler(0x2002);
164168 SetReadHandler(0x2002, 0x2002, A2002_Topgun);
165 } else if (curppu == RC2C05_03) {
169 } else if (GameInfo->vs_ppu == GIPPU_RC2C05_03) {
166170 OldReadPPU = GetReadHandler(0x2002);
167171 SetReadHandler(0x2002, 0x2002, A2002_Gumshoe);
168 } else if (curppu == RC2C05_02) {
172 } else if (GameInfo->vs_ppu == GIPPU_RC2C05_02) {
169173 OldReadPPU = GetReadHandler(0x2002);
170174 SetReadHandler(0x2002, 0x2002, A2002_MBJ);
171175 }
172 if (curppu == RC2C05_04 || curppu == RC2C05_01 || curppu == RC2C05_03 || curppu == RC2C05_02) {
176 if (GameInfo->vs_ppu == GIPPU_RC2C05_01 || GameInfo->vs_ppu == GIPPU_RC2C05_02 || GameInfo->vs_ppu == GIPPU_RC2C05_03 || GameInfo->vs_ppu == GIPPU_RC2C05_04) {
173177 OldWritePPU[0] = GetWriteHandler(0x2000);
174178 OldWritePPU[1] = GetWriteHandler(0x2001);
175179 SetWriteHandler(0x2000, 0x2001, B2000_2001_2C05);
176180 }
177 if (curmd5 == 0x2d396247cf58f9faLL) { /* Super Xevious */
181 if (GameInfo->vs_type == EGIVS_XEVIOUS) { /* Super Xevious */
178182 SetReadHandler(0x5400, 0x57FF, XevRead);
179183 }
180184 }
251255
252256 VSUNIENTRY VSUniGames[] =
253257 {
254 { "Baseball", 0x691d4200ea42be45ULL, 99, 2, RP2C04_001, 0 },
255 { "Battle City", 0x8540949d74c4d0ebULL, 99, 2, RP2C04_001, 0 },
256 { "Battle City(Bootleg)", 0x8093cbe7137ac031ULL, 99, 2, RP2C04_001, 0 },
257
258 { "Clu Clu Land", 0x1b8123218f62b1eeULL, 99, 2, RP2C05_004, IOPTION_SWAPDIRAB },
259 { "Dr Mario", 0xe1af09c477dc0081ULL, 1, 0, RP2C04_003, IOPTION_SWAPDIRAB },
260 { "Duck Hunt", 0x47735d1e5f1205bbULL, 99, 2, RCP2C03B, IOPTION_GUN },
261 { "Excitebike", 0x3dcd1401bcafde77ULL, 99, 2, RP2C04_003, 0 },
262 { "Excitebike (J)", 0x7ea51c9d007375f0ULL, 99, 2, RP2C05_004, 0 },
263 { "Freedom Force", 0xed96436bd1b5e688ULL, 4, 0, RP2C04_001, IOPTION_GUN }, /* Wrong color in game select screen? */
264 { "Stroke and Match Golf", 0x612325606e82bc66ULL, 99, 2, RP2C04_002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x01 },
265
266 { "Goonies", 0xb4032d694e1d2733ULL, 151, 1, RP2C04_003, 0 },
267 { "Gradius", 0x50687ae63bdad976ULL, 151, 1, RP2C04_001, IOPTION_SWAPDIRAB },
268 { "Gumshoe", 0x87161f8ee37758d3ULL, 99, 2, RC2C05_03, IOPTION_GUN },
269 { "Gumshoe", 0xb8500780bf69ce29ULL, 99, 2, RC2C05_03, IOPTION_GUN },
270 { "Hogan's Alley", 0xd78b7f0bb621fb45ULL, 99, 2, RP2C04_001, IOPTION_GUN },
271 { "Ice Climber", 0xd21e999513435e2aULL, 99, 2, RP2C05_004, IOPTION_SWAPDIRAB },
272 { "Ladies Golf", 0x781b24be57ef6785ULL, 99, 2, RP2C04_002, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1 },
273
274 { "Mach Rider", 0x015672618af06441ULL, 99, 2, RP2C04_002, 0 },
275 { "Mach Rider (J)", 0xa625afb399811a8aULL, 99, 2, RP2C04_001, 0 },
276 { "Mighty Bomb Jack", 0xe6a89f4873fac37bULL, 0, 2, RC2C05_02, 0 },
277 { "Ninja Jajamaru Kun", 0xb26a2c31474099c0ULL, 99, 2, RC2C05_01, IOPTION_SWAPDIRAB },
278 { "Pinball", 0xc5f49d3de7f2e9b8ULL, 99, 2, RP2C04_001, IOPTION_PREDIP, 0x01 },
279 { "Pinball (J)", 0x66ab1a3828cc901cULL, 99, 2, RCP2C03B, IOPTION_PREDIP, 0x1 },
280 { "Platoon", 0x160f237351c19f1fULL, 68, 1, RP2C04_001, 0 },
281 { "RBI Baseball", 0x6a02d345812938afULL, 4, 1, RP2C04_001, IOPTION_SWAPDIRAB },
282 { "Soccer", 0xd4e7a9058780eda3ULL, 99, 2, RP2C04_003, IOPTION_SWAPDIRAB },
283 { "Star Luster", 0x8360e134b316d94cULL, 99, 2, RCP2C03B, 0 },
284 { "Stroke and Match Golf (J)", 0x869bb83e02509747ULL, 99, 2, RCP2C03B, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x1 },
285 { "Super Sky Kid", 0x78d04c1dd4ec0101ULL, 4, 1, RCP2C03B, IOPTION_SWAPDIRAB | IOPTION_PREDIP, 0x20 },
286
287 { "Super Xevious", 0x2d396247cf58f9faULL, 206, 0, RP2C04_001, 0 },
288 { "Tetris", 0x531a5e8eea4ce157ULL, 99, 2, RCP2C03B, IOPTION_PREDIP, 0x20 },
289 { "Top Gun", 0xf1dea36e6a7b531dULL, 2, 0, RC2C05_04, 0 },
290 { "VS Castlevania", 0x92fd6909c81305b9ULL, 2, 1, RP2C04_002, 0 },
291 { "VS Slalom", 0x4889b5a50a623215ULL, 0, 1, RP2C04_002, 0 },
292 { "VS Super Mario Bros", 0x39d8cfa788e20b6cULL, 99, 2, RP2C05_004, 0 },
293 { "VS Super Mario Bros [a1]", 0xfc182e5aefbce14dULL, 99, 2, RP2C05_004, 0 },
294 { "VS TKO Boxing", 0x6e1ee06171d8ce3aULL, 4, 1, RP2C04_003, IOPTION_PREDIP, 0x00 },
258 { "Baseball", 0x691d4200ea42be45ULL, 99, 2, GIPPU_RP2C04_0001, 0, 0, EGIVS_NORMAL },
259 { "Battle City", 0x8540949d74c4d0ebULL, 99, 2, GIPPU_RP2C04_0001, 0, 0, EGIVS_NORMAL },
260 { "Battle City(Bootleg)", 0x8093cbe7137ac031ULL, 99, 2, GIPPU_RP2C04_0001, 0, 0, EGIVS_NORMAL },
261
262 { "Clu Clu Land", 0x1b8123218f62b1eeULL, 99, 2, GIPPU_RP2C04_0004, VS_OPTION_SWAPDIRAB, 0, EGIVS_NORMAL },
263 { "Dr Mario", 0xe1af09c477dc0081ULL, 1, 0, GIPPU_RP2C04_0003, VS_OPTION_SWAPDIRAB, 0, EGIVS_NORMAL },
264 { "Duck Hunt", 0x47735d1e5f1205bbULL, 99, 2, GIPPU_RC2C03B, VS_OPTION_GUN, 0, EGIVS_NORMAL },
265 { "Excitebike", 0x3dcd1401bcafde77ULL, 99, 2, GIPPU_RP2C04_0003, 0, 0, EGIVS_NORMAL },
266 { "Excitebike (J)", 0x7ea51c9d007375f0ULL, 99, 2, GIPPU_RP2C04_0004, 0, 0, EGIVS_NORMAL },
267 { "Freedom Force", 0xed96436bd1b5e688ULL, 4, 0, GIPPU_RP2C04_0001, VS_OPTION_GUN, 0, EGIVS_NORMAL }, /* Wrong color in game select screen? */
268 { "Stroke and Match Golf", 0x612325606e82bc66ULL, 99, 2, GIPPU_RP2C04_0002, VS_OPTION_SWAPDIRAB | VS_OPTION_PREDIP, 0x01, EGIVS_NORMAL },
269
270 { "Goonies", 0xb4032d694e1d2733ULL, 151, 1, GIPPU_RP2C04_0003, 0, 0, EGIVS_NORMAL },
271 { "Gradius", 0x50687ae63bdad976ULL, 151, 1, GIPPU_RP2C04_0001, VS_OPTION_SWAPDIRAB, 0, EGIVS_NORMAL },
272 { "Gumshoe", 0x87161f8ee37758d3ULL, 99, 2, GIPPU_RC2C05_03, VS_OPTION_GUN, 0, EGIVS_NORMAL },
273 { "Gumshoe", 0xb8500780bf69ce29ULL, 99, 2, GIPPU_RC2C05_03, VS_OPTION_GUN, 0, EGIVS_NORMAL },
274 { "Hogan's Alley", 0xd78b7f0bb621fb45ULL, 99, 2, GIPPU_RP2C04_0001, VS_OPTION_GUN, 0, EGIVS_NORMAL },
275 { "Ice Climber", 0xd21e999513435e2aULL, 99, 2, GIPPU_RP2C04_0004, VS_OPTION_SWAPDIRAB, 0, EGIVS_NORMAL },
276 { "Ladies Golf", 0x781b24be57ef6785ULL, 99, 2, GIPPU_RP2C04_0002, VS_OPTION_SWAPDIRAB | VS_OPTION_PREDIP, 0x1, EGIVS_NORMAL },
277
278 { "Mach Rider", 0x015672618af06441ULL, 99, 2, GIPPU_RP2C04_0002, 0, 0, EGIVS_NORMAL },
279 { "Mach Rider (J)", 0xa625afb399811a8aULL, 99, 2, GIPPU_RP2C04_0001, 0, 0, EGIVS_NORMAL },
280 { "Mighty Bomb Jack", 0xe6a89f4873fac37bULL, 0, 2, GIPPU_RC2C05_02, 0, 0, EGIVS_NORMAL },
281 { "Ninja Jajamaru Kun", 0xb26a2c31474099c0ULL, 99, 2, GIPPU_RC2C05_01, VS_OPTION_SWAPDIRAB, 0, EGIVS_NORMAL },
282 { "Pinball", 0xc5f49d3def2e9b8ULL, 99, 2, GIPPU_RP2C04_0001, VS_OPTION_PREDIP, 0x01, EGIVS_NORMAL },
283 { "Pinball (J)", 0x66ab1a3828cc901cULL, 99, 2, GIPPU_RC2C03B, VS_OPTION_PREDIP, 0x01, EGIVS_NORMAL },
284 { "Platoon", 0x160f237351c19f1fULL, 68, 1, GIPPU_RP2C04_0001, 0, 0, EGIVS_NORMAL },
285 { "RBI Baseball", 0x6a02d345812938afULL, 4, 1, GIPPU_RP2C04_0001, VS_OPTION_SWAPDIRAB, 0, EGIVS_RBI },
286 { "Soccer", 0xd4e7a9058780eda3ULL, 99, 2, GIPPU_RP2C04_0003, VS_OPTION_SWAPDIRAB, 0, EGIVS_NORMAL },
287 { "Star Luster", 0x8360e134b316d94cULL, 99, 2, GIPPU_RC2C03B, 0, 0, EGIVS_NORMAL },
288 { "Stroke and Match Golf (J)", 0x869bb83e02509747ULL, 99, 2, GIPPU_RC2C03B, VS_OPTION_SWAPDIRAB | VS_OPTION_PREDIP, 0x01, EGIVS_NORMAL },
289 { "Super Sky Kid", 0x78d04c1dd4ec0101ULL, 4, 1, GIPPU_RC2C03B, VS_OPTION_SWAPDIRAB | VS_OPTION_PREDIP, 0x20, EGIVS_NORMAL },
290
291 { "Super Xevious", 0x2d396247cf58f9faULL, 206, 0, GIPPU_RP2C04_0001, 0, 0, EGIVS_XEVIOUS },
292 { "Tetris", 0x531a5e8eea4ce157ULL, 99, 2, GIPPU_RC2C03B, VS_OPTION_PREDIP, 0x20, EGIVS_NORMAL },
293 { "Top Gun", 0xf1dea36e6a7b531dULL, 2, 0, GIPPU_RC2C05_04, 0, 0, EGIVS_NORMAL },
294 { "VS Castlevania", 0x92fd6909c81305b9ULL, 2, 1, GIPPU_RP2C04_0002, 0, 0, EGIVS_NORMAL },
295 { "VS Slalom", 0x4889b5a50a623215ULL, 0, 1, GIPPU_RP2C04_0002, 0, 0, EGIVS_NORMAL },
296 { "VS Super Mario Bros", 0x39d8cfa788e20b6cULL, 99, 2, GIPPU_RP2C04_0004, 0, 0, EGIVS_NORMAL },
297 { "VS Super Mario Bros [a1]", 0xfc182e5aefbce14dULL, 99, 2, GIPPU_RP2C04_0004, 0, 0, EGIVS_NORMAL },
298 { "VS TKO Boxing", 0x6e1ee06171d8ce3aULL, 4, 1, GIPPU_RP2C04_0003, VS_OPTION_PREDIP, 0x00, EGIVS_TKO },
295299 { 0 }
296300 };
297301
300304
301305 while (vs->name) {
302306 if (md5partial == vs->md5partial) {
303 if (vs->ppu < RCP2C03B) default_palette_selection = vs->ppu;
304 *MapperNo = vs->mapper;
305 *Mirroring = vs->mirroring;
306 GameInfo->type = GIT_VSUNI;
307 GameInfo->cspecial = SIS_VSUNISYSTEM;
308 GameInfo->inputfc = SIFC_NONE;
309 curppu = vs->ppu;
310 curmd5 = md5partial;
307 int32 tofix = 0;
308 if (*MapperNo != vs->mapper) {
309 tofix |= 1;
310 *MapperNo = vs->mapper;
311 }
312 if (*Mirroring != vs->mirroring) {
313 tofix |= 2;
314 *Mirroring = vs->mirroring;
315 }
316 if (GameInfo->type != GIT_VSUNI) {
317 tofix |= 4;
318 GameInfo->type = GIT_VSUNI;
319 }
320 if (GameInfo->vs_type != vs->type) {
321 tofix |= 8;
322 GameInfo->vs_type = vs->type;
323 }
324 if (vs->ppu && (GameInfo->vs_ppu != vs->ppu)) {
325 tofix |= 16;
326 GameInfo->vs_ppu = vs->ppu;
327 }
311328
312329 secptr = 0;
313
330 switch (GameInfo->vs_type)
314331 {
315 static int64 tko = 0x6e1ee06171d8ce3aULL, rbi = 0x6a02d345812938afULL;
316 if (md5partial == tko)
317 secptr = secdata[0];
318 if (md5partial == rbi)
319 secptr = secdata[1];
332 case EGIVS_RBI: secptr = secdata_rbi; break;
333 case EGIVS_TKO: secptr = secdata_tko; break;
334 default: secptr = 0; break;
320335 }
321336
322337 vsdip = 0x0;
323 if (vs->ioption & IOPTION_PREDIP) {
338 if (vs->ioption & VS_OPTION_PREDIP) {
324339 vsdip = vs->predip;
325340 }
326 if (vs->ioption & IOPTION_GUN) {
341 if ((vs->ioption & VS_OPTION_GUN) && !head.expansion) {
342 tofix |= 32;
327343 GameInfo->input[0] = SI_ZAPPER;
328344 GameInfo->input[1] = SI_NONE;
329 } else {
345 GameInfo->inputfc = SIFC_NONE;
346 }
347 else if (!head.expansion) {
330348 GameInfo->input[0] = GameInfo->input[1] = SI_GAMEPAD;
331 }
332 curvs = vs;
349 GameInfo->inputfc = SIFC_NONE;
350 }
351 if ((vs->ioption & VS_OPTION_SWAPDIRAB) && !GameInfo->vs_cswitch) {
352 tofix |= 64;
353 GameInfo->vs_cswitch = 1;
354 }
355
356 if (tofix) {
357 char gigastr[768];
358 strcpy(gigastr, "The iNES header contains incorrect information. For now, the information will be corrected in RAM. ");
359 if (tofix & 4) {
360 sprintf(gigastr + strlen(gigastr), "Game type should be set to Vs. System. ");
361 }
362 if (tofix & 1)
363 sprintf(gigastr + strlen(gigastr), "The mapper number should be set to %d. ", *MapperNo);
364 if (tofix & 2) {
365 const char* mstr[3] = { "Horizontal", "Vertical", "Four-screen" };
366 sprintf(gigastr + strlen(gigastr), "Mirroring should be set to \"%s\". ", mstr[vs->mirroring & 3]);
367 }
368 if (tofix & 8) {
369 const char* mstr[4] = { "Normal", "RBI Baseball protection", "TKO Boxing protection", "Super Xevious protection"};
370 sprintf(gigastr + strlen(gigastr), "Vs. System type should be set to \"%s\". ", mstr[vs->type]);
371 }
372 if (tofix & 16)
373 {
374 const char* mstr[10] = { "Default", "RP2C04-0001", "RP2C04-0002", "RP2C04-0003", "RP2C04-0004", "RC2C03B", "RC2C05-01", "RC2C05-02" , "RC2C05-03" , "RC2C05-04" };
375 sprintf(gigastr + strlen(gigastr), "Vs. System PPU should be set to \"%s\". ", mstr[vs->ppu]);
376 }
377 if (tofix & 32)
378 sprintf(gigastr + strlen(gigastr), "The controller type should be set to zapper. ");
379 if (tofix & 64)
380 sprintf(gigastr + strlen(gigastr), "The controllers should be swapped. ");
381 strcat(gigastr, "\n");
382 FCEU_printf("%s", gigastr);
383 }
384
333385 return;
334386 }
335387 vs++;
340392 uint32 *dest;
341393 int y, x;
342394
343 if (!DIPS) return;
395 if (DIPS_howlong-- <= 0) return;
344396
345397 dest = (uint32*)(XBuf + 256 * 12 + 164);
346398 for (y = 24; y; y--, dest += (256 - 72) >> 2) {
370422 SFORMAT FCEUVSUNI_STATEINFO[] = {
371423 { &vsdip, 1, "vsdp" },
372424 { &coinon, 1, "vscn" },
425 { &coinon2, 1, "vsc2" },
426 { &service, 1, "vssv" },
373427 { &VSindex, 1, "vsin" },
374428 { 0 }
375429 };
0 enum IOPTION {
1 VS_OPTION_GUN = 0x1,
2 VS_OPTION_SWAPDIRAB = 0x2,
3 VS_OPTION_PREDIP = 0x10,
4 };
5
6 typedef struct {
7 const char* name;
8 uint64 md5partial;
9 int mapper;
10 int mirroring;
11 EGIPPU ppu;
12 int ioption;
13 int predip;
14 EGIVS type;
15 } VSUNIENTRY;
16
017 void FCEU_VSUniPower(void);
118 void FCEU_VSUniCheck(uint64 md5partial, int *, uint8 *);
219 void FCEU_VSUniDraw(uint8 *XBuf);
320
421 void FCEU_VSUniToggleDIP(int); /* For movies and netplay */
5 void FCEU_VSUniCoin(void);
22 void FCEU_VSUniCoin(uint8 slot);
23 void FCEU_VSUniService();
624 void FCEU_VSUniSwap(uint8 *j0, uint8 *j1);
317317 #define LD_ZP(op) {uint8 A; uint8 x; GetZP(A); x=RdRAM(A); op; break;}
318318 #define LD_ZPX(op) {uint8 A; uint8 x; GetZPI(A,_X); x=RdRAM(A); op; break;}
319319 #define LD_ZPY(op) {uint8 A; uint8 x; GetZPI(A,_Y); x=RdRAM(A); op; break;}
320 #define LD_AB(op) {unsigned int A; uint8 x; GetAB(A); x=RdMem(A); op; break; }
321 #define LD_ABI(reg,op) {unsigned int A; uint8 x; GetABIRD(A,reg); x=RdMem(A); op; break;}
320 #define LD_AB(op) {unsigned int A; FCEU_MAYBE_UNUSED uint8 x; GetAB(A); x=RdMem(A); op; break; }
321 #define LD_ABI(reg,op) {unsigned int A; FCEU_MAYBE_UNUSED uint8 x; GetABIRD(A,reg); x=RdMem(A); op; break;}
322322 #define LD_ABX(op) LD_ABI(_X,op)
323323 #define LD_ABY(op) LD_ABI(_Y,op)
324324 #define LD_IX(op) {unsigned int A; uint8 x; GetIX(A); x=RdMem(A); op; break;}