New upstream version 2.6.5+dfsg1
Joe Nahmias
1 year, 2 months ago
26 | 26 | /vc/fceux.zip |
27 | 27 | /vc/fceux64.zip |
28 | 28 | |
29 | # macOS junk | |
30 | .DS_Store | |
31 | ||
29 | 32 | # linux build output |
30 | 33 | bin |
31 | 34 | src/fceux |
4 | 4 | |
5 | 5 | [NOTE: This only applies to Qt/SDL builds] |
6 | 6 | |
7 | http://www.fceux.com | |
7 | https://fceux.com | |
8 | 8 | |
9 | 9 | Last Modified: March 24, 2022 |
10 | 10 |
16 | 16 | #appveyor_build_worker_image: Ubuntu1804 |
17 | 17 | |
18 | 18 | - job_name: MacOS |
19 | appveyor_build_worker_image: macOS | |
19 | appveyor_build_worker_image: macos-bigsur | |
20 | 20 | |
21 | 21 | for: |
22 | 22 | |
26 | 26 | - job_name: Windows 32 |
27 | 27 | |
28 | 28 | build_script: |
29 | - cmd: pipelines/win32_build.bat | |
29 | - cmd: perl pipelines/build.pl win32 | |
30 | 30 | |
31 | 31 | - |
32 | 32 | matrix: |
34 | 34 | - job_name: Windows 64 |
35 | 35 | |
36 | 36 | build_script: |
37 | - cmd: pipelines/win64_build.bat | |
37 | - cmd: perl pipelines/build.pl win64 | |
38 | 38 | |
39 | 39 | - |
40 | 40 | matrix: |
42 | 42 | - job_name: Win64 Qt |
43 | 43 | |
44 | 44 | build_script: |
45 | - cmd: pipelines/qwin64_build.bat | |
45 | - cmd: perl pipelines/build.pl win64-QtSDL | |
46 | 46 | |
47 | 47 | - |
48 | 48 | matrix: |
50 | 50 | - job_name: Ubuntu |
51 | 51 | |
52 | 52 | build_script: |
53 | - sh: ./pipelines/linux_build.sh | |
53 | - sh: perl pipelines/build.pl linux | |
54 | 54 | |
55 | 55 | - |
56 | 56 | matrix: |
58 | 58 | - job_name: MacOS |
59 | 59 | |
60 | 60 | build_script: |
61 | - sh: ./pipelines/macOS_build.sh | |
61 | - sh: perl pipelines/build.pl macOS | |
62 | 62 | |
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 | } |
0 | 0 | #!/usr/bin/perl |
1 | 1 | |
2 | 2 | use strict; |
3 | use File::Basename; | |
3 | 4 | |
4 | my $VERSION="2.6.4"; | |
5 | my $dirname = dirname(__FILE__); | |
6 | ||
7 | my $VERSION=`perl $dirname/../scripts/fceuVersion.pl`; | |
5 | 8 | my $INSTALL_PREFIX="/tmp/fceux"; |
6 | 9 | my $CTL_FILENAME="$INSTALL_PREFIX/DEBIAN/control"; |
7 | 10 | my $ARCH="amd64"; |
3 | 3 | pwd |
4 | 4 | uname -a |
5 | 5 | cat /etc/os-release |
6 | env | |
6 | 7 | |
7 | 8 | SCRIPT_DIR=$( cd $(dirname $BASH_SOURCE[0]); pwd ); |
8 | 9 | |
18 | 19 | echo "APPVEYOR_SSH_KEY=$APPVEYOR_SSH_KEY"; |
19 | 20 | echo "APPVEYOR_SSH_BLOCK=$APPVEYOR_SSH_BLOCK"; |
20 | 21 | echo '****************************************' |
22 | ||
23 | if [ ! -z $FCEU_RELEASE_VERSION ]; then | |
24 | APPVEYOR_CMAKE_FLAGS=" -DPUBLIC_RELEASE=1 "; | |
25 | fi | |
21 | 26 | |
22 | 27 | echo '****************************************' |
23 | 28 | echo '****************************************' |
97 | 102 | sudo apt-get --assume-yes install libavformat-dev |
98 | 103 | sudo apt-get --assume-yes install libavutil-dev |
99 | 104 | 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 | |
101 | 106 | |
102 | 107 | # Install cppcheck |
103 | 108 | echo '****************************************' |
118 | 123 | -DCMAKE_BUILD_TYPE=Release \ |
119 | 124 | -DCMAKE_INSTALL_PREFIX=/usr \ |
120 | 125 | -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ |
126 | $APPVEYOR_CMAKE_FLAGS \ | |
121 | 127 | .. |
122 | 128 | make -j `nproc` |
123 | 129 | make install DESTDIR=$INSTALL_PREFIX |
190 | 196 | echo '**************************************************************' |
191 | 197 | sudo dpkg -i /tmp/fceux-*.deb |
192 | 198 | |
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 |
4 | 4 | pwd |
5 | 5 | uname -a |
6 | 6 | sw_vers |
7 | env | |
8 | ||
9 | SCRIPT_DIR=$( cd $(dirname $BASH_SOURCE[0]); pwd ); | |
7 | 10 | |
8 | 11 | QT_MAJOR=5; |
9 | 12 | 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"; | |
13 | 17 | SDL2_VERSION=2.0.20 |
14 | 18 | |
15 | SCRIPT_DIR=$( cd $(dirname $BASH_SOURCE[0]); pwd ); | |
19 | echo "Building Version: $FCEUX_VERSION"; | |
16 | 20 | |
17 | 21 | NPROC=`getconf _NPROCESSORS_ONLN`; |
18 | 22 | echo "Number of Processors: $NPROC"; |
32 | 36 | echo "APPVEYOR_SSH_KEY=$APPVEYOR_SSH_KEY"; |
33 | 37 | echo "APPVEYOR_SSH_BLOCK=$APPVEYOR_SSH_BLOCK"; |
34 | 38 | echo '****************************************' |
39 | ||
40 | if [ ! -z $FCEU_RELEASE_VERSION ]; then | |
41 | APPVEYOR_CMAKE_FLAGS=" -DPUBLIC_RELEASE=1 "; | |
42 | fi | |
35 | 43 | |
36 | 44 | echo '****************************************' |
37 | 45 | echo 'Install Dependency sdl2' |
120 | 128 | -DCPACK_PACKAGE_VERSION_MINOR=$FCEUX_VERSION_MINOR \ |
121 | 129 | -DCPACK_PACKAGE_VERSION_PATCH=$FCEUX_VERSION_PATCH \ |
122 | 130 | -DQT6=$USE_QT6 \ |
131 | $APPVEYOR_CMAKE_FLAGS \ | |
123 | 132 | .. || exit 1 |
124 | 133 | make -j $NPROC || exit 1 |
125 | 134 | #sudo make install || exit 1 # make install is already run by cpack |
126 | 135 | sudo cpack -G DragNDrop || exit 1 |
127 | 136 | |
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 | |
130 | 148 | |
131 | 149 | # Debug via ssh if necessary |
132 | 150 | if [ ! -z $APPVEYOR_SSH_BLOCK ]; then |
7 | 7 | |
8 | 8 | cd /d %CWD% |
9 | 9 | |
10 | set | |
10 | 11 | where cmake |
11 | 12 | where nmake |
12 | 13 | where msbuild |
20 | 21 | cd build |
21 | 22 | mkdir bin |
22 | 23 | |
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 | |
25 | 29 | |
26 | 30 | REM rmdir /q /s SDL2 |
27 | 31 | |
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 | |
30 | 34 | |
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 | |
35 | 39 | |
36 | 40 | set SDL_INSTALL_PREFIX=%CD% |
37 | 41 | set FFMPEG_INSTALL_PREFIX=%CD% |
42 | set PUBLIC_RELEASE=0 | |
43 | IF DEFINED FCEU_RELEASE_VERSION (set PUBLIC_RELEASE=1) | |
38 | 44 | |
39 | 45 | REM cmake -h |
40 | 46 | 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" .. | |
42 | 48 | |
43 | 49 | REM nmake |
44 | 50 | msbuild /m fceux.sln /p:Configuration=Release |
45 | @if ERRORLEVEL 1 goto end | |
51 | if %ERRORLEVEL% NEQ 0 EXIT /B 1 | |
46 | 52 | |
47 | 53 | 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\. | |
48 | 57 | copy %SDL_INSTALL_PREFIX%\SDL2\lib\x64\SDL2.dll bin\. |
49 | 58 | copy %FFMPEG_INSTALL_PREFIX%\ffmpeg\bin\*.dll bin\. |
50 | 59 | |
51 | 60 | windeployqt --no-compiler-runtime bin\qfceux.exe |
52 | 61 | |
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 | ||
53 | 68 | dir bin |
54 | 69 | |
55 | 70 | 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 | |
58 | 73 | |
59 | 74 | 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 | |
62 | 77 | |
63 | 78 | mkdir doc |
64 | 79 | 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 | |
67 | 82 | |
68 | 83 | cd %PROJECT_ROOT% |
69 | 84 | |
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% | |
71 | 87 | |
72 | 88 | :end |
0 | 0 | |
1 | 1 | set PROJECT_ROOT=%~dp0.. |
2 | set BUILD_CONFIG=Release | |
2 | 3 | |
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 | |
5 | 13 | |
6 | 14 | cd %PROJECT_ROOT%\vc |
7 | 15 | |
8 | 16 | REM Create Zip Archive |
9 | 17 | 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 | |
12 | 20 | |
13 | 21 | cd %PROJECT_ROOT% |
14 | 22 | |
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% | |
16 | 25 | |
17 | :end⏎ | |
26 | :end |
0 | 0 | |
1 | 1 | set PROJECT_ROOT=%~dp0.. |
2 | set BUILD_CONFIG=Release | |
2 | 3 | |
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 | |
5 | 13 | |
6 | 14 | cd %PROJECT_ROOT%\vc |
7 | 15 | |
8 | 16 | REM Create Zip Archive |
9 | 17 | |
10 | 18 | 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 | |
15 | 23 | |
16 | 24 | cd %PROJECT_ROOT% |
17 | 25 | |
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% | |
19 | 28 | |
20 | 29 | :end |
4 | 4 | ## Builds and Releases |
5 | 5 | |
6 | 6 | 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) | |
12 | 12 | * Status: [Appveyor](https://ci.appveyor.com/project/zeromus/fceux/) |
13 | 13 | |
14 | 14 | 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 | } |
3 | 3 | set(CMAKE_AUTOMOC ON) |
4 | 4 | set(CMAKE_AUTORCC ON) |
5 | 5 | set(CMAKE_AUTOUIC ON) |
6 | ||
7 | if (${PUBLIC_RELEASE}) | |
8 | add_definitions( -DPUBLIC_RELEASE=1 ) | |
9 | endif() | |
6 | 10 | |
7 | 11 | if ( ${QT6} ) |
8 | 12 | message( STATUS "GUI Frontend: Qt6") |
27 | 31 | include_directories( ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Help_INCLUDE_DIRS} ) |
28 | 32 | endif() |
29 | 33 | |
34 | ||
30 | 35 | if(WIN32) |
31 | 36 | find_package(OpenGL REQUIRED) |
32 | 37 | #find_package(Qt5 COMPONENTS Widgets OpenGL REQUIRED) |
35 | 40 | add_definitions( -DMSVC -D_CRT_SECURE_NO_WARNINGS ) |
36 | 41 | add_definitions( -D__SDL__ -D__QT_DRIVER__ -DQT_DEPRECATED_WARNINGS ) |
37 | 42 | add_definitions( -DFCEUDEF_DEBUGGER ) |
43 | add_definitions( /wd4267 /wd4244 ) | |
44 | #add_definitions( /wd4018 ) # Integer comparison sign mismatch warnings | |
38 | 45 | include_directories( ${SDL_INSTALL_PREFIX}/SDL2/include ) |
39 | 46 | include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/drivers/win/zlib ) |
40 | 47 | set( OPENGL_LDFLAGS OpenGL::GL ) |
70 | 77 | find_package(OpenGL REQUIRED) |
71 | 78 | find_package(ZLIB REQUIRED) |
72 | 79 | |
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 | |
74 | 82 | add_definitions( -DFCEUDEF_DEBUGGER ) |
75 | 83 | |
76 | 84 | #if ( ${QT6} ) |
83 | 91 | # include_directories( ${Qt5Widgets_INCLUDE_DIRS} ) |
84 | 92 | #endif() |
85 | 93 | 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() | |
86 | 103 | |
87 | 104 | # Check for libminizip |
88 | 105 | pkg_check_modules( MINIZIP REQUIRED minizip) |
260 | 277 | ${CMAKE_CURRENT_SOURCE_DIR}/conddebug.cpp |
261 | 278 | ${CMAKE_CURRENT_SOURCE_DIR}/config.cpp |
262 | 279 | ${CMAKE_CURRENT_SOURCE_DIR}/debug.cpp |
280 | ${CMAKE_CURRENT_SOURCE_DIR}/debugsymboltable.cpp | |
263 | 281 | ${CMAKE_CURRENT_SOURCE_DIR}/drawing.cpp |
264 | 282 | ${CMAKE_CURRENT_SOURCE_DIR}/fceu.cpp |
265 | 283 | ${CMAKE_CURRENT_SOURCE_DIR}/fds.cpp |
331 | 349 | ${CMAKE_CURRENT_SOURCE_DIR}/boards/32.cpp |
332 | 350 | ${CMAKE_CURRENT_SOURCE_DIR}/boards/33.cpp |
333 | 351 | ${CMAKE_CURRENT_SOURCE_DIR}/boards/34.cpp |
352 | ${CMAKE_CURRENT_SOURCE_DIR}/boards/354.cpp | |
334 | 353 | ${CMAKE_CURRENT_SOURCE_DIR}/boards/36.cpp |
335 | 354 | ${CMAKE_CURRENT_SOURCE_DIR}/boards/3d-block.cpp |
336 | 355 | ${CMAKE_CURRENT_SOURCE_DIR}/boards/40.cpp |
381 | 400 | ${CMAKE_CURRENT_SOURCE_DIR}/boards/cheapocabra.cpp |
382 | 401 | ${CMAKE_CURRENT_SOURCE_DIR}/boards/cityfighter.cpp |
383 | 402 | ${CMAKE_CURRENT_SOURCE_DIR}/boards/coolboy.cpp |
403 | ${CMAKE_CURRENT_SOURCE_DIR}/boards/coolgirl.cpp | |
384 | 404 | ${CMAKE_CURRENT_SOURCE_DIR}/boards/dance2000.cpp |
385 | 405 | ${CMAKE_CURRENT_SOURCE_DIR}/boards/datalatch.cpp |
386 | 406 | ${CMAKE_CURRENT_SOURCE_DIR}/boards/dream.cpp |
452 | 472 | ${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc7.cpp |
453 | 473 | ${CMAKE_CURRENT_SOURCE_DIR}/boards/vrc7p.cpp |
454 | 474 | ${CMAKE_CURRENT_SOURCE_DIR}/boards/yoko.cpp |
475 | ${CMAKE_CURRENT_SOURCE_DIR}/boards/inx007t.cpp | |
455 | 476 | ${CMAKE_CURRENT_SOURCE_DIR}/input/arkanoid.cpp |
456 | 477 | ${CMAKE_CURRENT_SOURCE_DIR}/input/bworld.cpp |
457 | 478 | ${CMAKE_CURRENT_SOURCE_DIR}/input/cursor.cpp |
480 | 501 | ${CMAKE_CURRENT_SOURCE_DIR}/utils/guid.cpp |
481 | 502 | ${CMAKE_CURRENT_SOURCE_DIR}/utils/md5.cpp |
482 | 503 | ${CMAKE_CURRENT_SOURCE_DIR}/utils/memory.cpp |
504 | ${CMAKE_CURRENT_SOURCE_DIR}/utils/mutex.cpp | |
483 | 505 | ) |
484 | 506 | |
485 | 507 | |
486 | 508 | set(SRC_DRIVERS_COMMON |
487 | 509 | ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/args.cpp |
488 | 510 | ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/cheat.cpp |
489 | ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/config.cpp | |
490 | 511 | ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/configSys.cpp |
491 | 512 | ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/hq2x.cpp |
492 | 513 | ${CMAKE_CURRENT_SOURCE_DIR}/drivers/common/hq3x.cpp |
577 | 598 | # the FCEUX_BUILD_TIMESTAMP preprocessor definition. |
578 | 599 | # Note: with CMake >= 3.8.0, this will respect SOURCE_DATE_EPOCH. For more info, |
579 | 600 | # 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) | |
581 | 602 | add_definitions( -DFCEUX_BUILD_TIMESTAMP=\"${BUILD_TS}\" ) |
582 | 603 | |
583 | 604 | if (WIN32) |
612 | 633 | ${CMAKE_CURRENT_BINARY_DIR}/fceux_git_info.cpp) |
613 | 634 | endif() |
614 | 635 | |
615 | target_link_libraries( ${APP_NAME} | |
636 | target_link_libraries( ${APP_NAME} ${ASAN_LDFLAGS} | |
616 | 637 | ${${Qt}Widgets_LIBRARIES} |
617 | 638 | ${${Qt}Help_LIBRARIES} |
618 | 639 | ${${Qt}OpenGL_LIBRARIES} |
47 | 47 | if (PRGsize[0] == CHRsize[0]) { // A9713 multigame extension hack! |
48 | 48 | setchr1(A, V | ((EXPREGS[3] & 0x80) << 1)); |
49 | 49 | } else { |
50 | if ((A & 0x1000) == ((MMC3_cmd & 0x80) << 5)) | |
50 | if ((A & 0x1000) == static_cast<uint32>((MMC3_cmd & 0x80) << 5)) | |
51 | 51 | setchr1(A, V | 0x100); |
52 | 52 | else |
53 | 53 | setchr1(A, V); |
21 | 21 | #include "mmc3.h" |
22 | 22 | |
23 | 23 | 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)) | |
25 | 25 | setchr1(A, V | 0x100); |
26 | 26 | else |
27 | 27 | setchr1(A, V); |
0 | 0 | /* 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 */ | |
19 | 29 | |
20 | 30 | #include "mapinc.h" |
21 | 31 | |
22 | static uint8 prot[4], prg, mode, chr, mirr; | |
32 | static uint8 extraRAM[4], prg, mode, chr, mirr; | |
23 | 33 | |
24 | 34 | static SFORMAT StateRegs[] = |
25 | 35 | { |
26 | { prot, 4, "PROT" }, | |
36 | { extraRAM, 4, "PROT" }, | |
27 | 37 | { &prg, 1, "PRG" }, |
28 | 38 | { &chr, 1, "CHR" }, |
29 | 39 | { &mode, 1, "MODE" }, |
35 | 45 | if (mode) { |
36 | 46 | setprg16(0x8000, prg); |
37 | 47 | setprg16(0xC000, prg); |
38 | } else | |
48 | } | |
49 | else | |
39 | 50 | setprg32(0x8000, prg >> 1); |
40 | 51 | setchr8(chr); |
41 | 52 | setmirror(mirr ^ 1); |
42 | 53 | } |
43 | 54 | |
44 | 55 | static DECLFW(M225Write) { |
45 | uint32 bank = (A >> 14) & 1; | |
56 | uint8 bank = (A >> 14) & 1; | |
46 | 57 | mirr = (A >> 13) & 1; |
47 | 58 | mode = (A >> 12) & 1; |
48 | 59 | chr = (A & 0x3f) | (bank << 6); |
51 | 62 | } |
52 | 63 | |
53 | 64 | 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; | |
57 | 67 | } |
58 | 68 | |
59 | 69 | static DECLFR(M225LoRead) { |
60 | if (A & 0x800) { | |
61 | return prot[A & 3] & 0x0F; | |
62 | } | |
70 | if (A & 0x800) return extraRAM[A & 3]; | |
63 | 71 | return X.DB; |
64 | 72 | } |
65 | 73 | |
66 | 74 | static void M225Power(void) { |
67 | 75 | prg = 0; |
68 | chr = 0; | |
69 | 76 | mode = 0; |
70 | mirr = 0; | |
71 | 77 | Sync(); |
72 | SetReadHandler(0x5000, 0x5FFF, M225LoRead); | |
73 | SetWriteHandler(0x5000, 0x5FFF, M225LoWrite); | |
78 | SetReadHandler(0x5000, 0x5fff, M225LoRead); | |
79 | SetWriteHandler(0x5000, 0x5fff, M225LoWrite); | |
74 | 80 | SetReadHandler(0x8000, 0xFFFF, CartBR); |
75 | 81 | SetWriteHandler(0x8000, 0xFFFF, M225Write); |
76 | 82 | } |
77 | 83 | |
78 | 84 | static void M225Reset(void) { |
79 | 85 | prg = 0; |
80 | chr = 0; | |
81 | 86 | mode = 0; |
82 | mirr = 0; | |
83 | 87 | Sync(); |
84 | 88 | } |
85 | 89 | |
93 | 97 | GameStateRestore = StateRestore; |
94 | 98 | AddExState(&StateRegs, ~0, 0, 0); |
95 | 99 | } |
100 | ||
101 | void Mapper255_Init(CartInfo *info) { | |
102 | Mapper225_Init(info); | |
103 | }⏎ |
18 | 18 | */ |
19 | 19 | |
20 | 20 | #include "mapinc.h" |
21 | #include "ines.h" | |
21 | 22 | |
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 | ||
23 | 32 | static SFORMAT StateRegs[] = |
24 | 33 | { |
25 | 34 | { &cmdreg, 2, "CREG" }, |
35 | { &openbus, 1, "OB" }, | |
36 | { &unrom, 1, "UROM" }, | |
37 | { &unromData, 1, "UDTA" }, | |
26 | 38 | { 0 } |
27 | 39 | }; |
28 | 40 | |
29 | 41 | 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); | |
39 | 71 | } |
40 | 72 | |
41 | 73 | static DECLFW(M235Write) { |
42 | 74 | 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; | |
43 | 84 | Sync(); |
44 | 85 | } |
45 | 86 | |
46 | 87 | static void M235Power(void) { |
47 | 88 | setchr8(0); |
48 | 89 | SetWriteHandler(0x8000, 0xFFFF, M235Write); |
49 | SetReadHandler(0x8000, 0xFFFF, CartBR); | |
90 | SetReadHandler(0x8000, 0xFFFF, M235Read); | |
50 | 91 | cmdreg = 0; |
92 | unromData = 0; | |
93 | unrom = 0; | |
51 | 94 | Sync(); |
52 | 95 | } |
53 | 96 | |
56 | 99 | } |
57 | 100 | |
58 | 101 | void Mapper235_Init(CartInfo *info) { |
102 | info->Reset = M235Reset; | |
59 | 103 | info->Power = M235Power; |
60 | 104 | GameStateRestore = M235Restore; |
61 | 105 | AddExState(&StateRegs, ~0, 0, 0); |
106 | ||
107 | // needs raw, non-pow2 PRGROM size for comparison | |
108 | PRGROMSize = head.ROM_size * 16384; | |
62 | 109 | } |
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 | } |
121 | 121 | if ((latche & 0x81) == 0x81) { |
122 | 122 | setprg32(0x8000, (latche & 0x38) >> 3); |
123 | 123 | } else |
124 | FCEU_printf("unrecognized command %04!\n", latche); | |
124 | FCEU_printf("unrecognized command %04x!\n", latche); | |
125 | 125 | setchr8(0); |
126 | 126 | setmirror(0); |
127 | 127 | } |
20 | 20 | * |
21 | 21 | * COOLBOY cartridges use registers at address $6xxx |
22 | 22 | * MINDKIDS cartridges use a solder pad labelled "5/6K" to select between $5000 and $6000 |
23 | * | |
23 | * | |
24 | 24 | * $xxx0 |
25 | 25 | * 7 bit 0 |
26 | 26 | * ---- ---- |
28 | 28 | * |||| |||| |
29 | 29 | * |||| |+++-- PRG offset (PRG A19, A18, A17) |
30 | 30 | * |||| +----- Alternate CHR A17 |
31 | * ||++------- PRG offset (PRG A24, A23) | |
31 | * ||++------- PRG offset (PRG A24, A23), CHR offset (CHR A19, A18) | |
32 | 32 | * |+--------- PRG mask (PRG A17 from 0: MMC3; 1: offset) |
33 | 33 | * +---------- CHR mask (CHR A17 from 0: MMC3; 1: alternate) |
34 | 34 | * |
35 | 35 | * $xxx1 |
36 | * | |
37 | 36 | * 7 bit 0 |
38 | 37 | * ---- ---- |
39 | 38 | * GHIJ KKLx |
54 | 53 | * $xxx3 |
55 | 54 | * 7 bit 0 |
56 | 55 | * ---- ---- |
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 | |
63 | 63 | * |+-+------- Banking mode |
64 | 64 | * |+--------- "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) | |
66 | 66 | * |
67 | 67 | * Also some new cartridges from MINDKIDS have /WE and /OE pins connected to mapper, |
68 | 68 | * which allows you to rewrite flash memory without soldering. |
74 | 74 | |
75 | 75 | #include "mapinc.h" |
76 | 76 | #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 | |
82 | 145 | int cbase = (MMC3_cmd & 0x80) << 5; |
83 | 146 | switch (cbase ^ A) { // Don't even try do understand |
84 | 147 | case 0x0400: |
85 | 148 | case 0x0C00: V &= 0x7F; break; |
86 | 149 | } |
87 | 150 | } |
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 | |
89 | 152 | setchr1(A, |
90 | (V & 0x80 & mask) | ((((EXPREGS[0] & 0x08) << 4) & ~mask)) // 7th bit | |
153 | (V & 0x80 & mask) | ((((EXPREGS[0] & 0b00001000) << 4) & ~mask)) // 7th bit | |
91 | 154 | | ((EXPREGS[2] & 0x0F) << 3) // 6-3 bits |
92 | 155 | | ((A >> 10) & 7) // 2-0 bits |
156 | | ((EXPREGS[0] & 0b00110000) << 4) // There are some ROMs with 1 MiB CHR-ROM | |
93 | 157 | ); |
94 | } else { | |
95 | if (EXPREGS[3] & 0x40) { // Weird mode, again | |
158 | } | |
159 | else { | |
160 | if (EXPREGS[3] & 0b01000000) { // Weird mode, again | |
96 | 161 | int cbase = (MMC3_cmd & 0x80) << 5; |
97 | 162 | switch (cbase ^ A) { // Don't even try do understand |
98 | 163 | case 0x0000: V = DRegBuf[0]; break; |
102 | 167 | } |
103 | 168 | } |
104 | 169 | // 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 | } | |
113 | 241 | |
114 | 242 | // Very weird mode |
115 | 243 | // 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)) { | |
117 | 245 | switch (A & 0xE000) { |
118 | 246 | case 0xC000: |
119 | 247 | case 0xE000: |
122 | 250 | } |
123 | 251 | } |
124 | 252 | |
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 | |
129 | 259 | mask &= 0xF0; |
130 | 260 | 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); | |
133 | 263 | 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 | } | |
145 | 283 | |
146 | 284 | // Deny any further writes when 7th bit is 1 AND 4th is 0 |
147 | 285 | if ((EXPREGS[3] & 0x90) != 0x80) { |
148 | 286 | 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) { | |
155 | 371 | MMC3RegReset(); |
156 | 372 | EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; |
373 | flash_state = 0; | |
374 | cfi_mode = 0; | |
157 | 375 | FixMMC3PRG(MMC3_cmd); |
158 | 376 | FixMMC3CHR(MMC3_cmd); |
159 | 377 | } |
160 | 378 | |
161 | static void COOLBOYPower(void) { | |
379 | static void AA6023Power(void) { | |
162 | 380 | GenMMC3Power(); |
163 | 381 | EXPREGS[0] = EXPREGS[1] = EXPREGS[2] = EXPREGS[3] = 0; |
164 | 382 | FixMMC3PRG(MMC3_cmd); |
165 | 383 | 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) { | |
173 | 393 | FixMMC3PRG(MMC3_cmd); |
174 | 394 | 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) | |
201 | 414 | { |
415 | case 2: | |
416 | regs_base = 0x7000; | |
417 | break; | |
202 | 418 | case 0: |
203 | COOLBOY_Init(info); | |
419 | case 4: | |
420 | case 6: | |
421 | case 8: | |
422 | regs_base = 0x6000; | |
204 | 423 | break; |
205 | 424 | case 1: |
206 | MINDKIDS_Init(info); | |
425 | case 3: | |
426 | case 5: | |
427 | case 7: | |
428 | case 9: | |
429 | regs_base = 0x5000; | |
207 | 430 | break; |
208 | 431 | 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 | } |
473 | 473 | Latch_Init(info, M203Sync, 0, 0x8000, 0xFFFF, 0, 0); |
474 | 474 | } |
475 | 475 | |
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 | ||
476 | 509 | //------------------ Map 240 --------------------------- |
477 | 510 | |
478 | 511 | static void M240Sync(void) { |
33 | 33 | static int kanji_pos, kanji_page, r40C0; |
34 | 34 | static int IRQa, IRQCount; |
35 | 35 | |
36 | FCEU_MAYBE_UNUSED | |
36 | 37 | static DECLFW(MBWRAM) { |
37 | 38 | if (!(DRegs[3] & 0x10)) |
38 | 39 | Page[A >> 11][A] = V; |
39 | 40 | } |
40 | 41 | |
42 | FCEU_MAYBE_UNUSED | |
41 | 43 | static DECLFR(MAWRAM) { |
42 | 44 | if (DRegs[3] & 0x10) |
43 | 45 | 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 | } |
1375 | 1375 | MMC3_IRQWrite((A & 0xFFFE) | ((A & 2) >> 1), V); |
1376 | 1376 | } |
1377 | 1377 | |
1378 | FCEU_MAYBE_UNUSED | |
1378 | 1379 | static DECLFW(M406Write) { |
1379 | 1380 | } |
1380 | 1381 |
306 | 306 | |
307 | 307 | #define MMC5_NOCARTS (sizeof(MMC5CartList) / sizeof(MMC5CartList[0])) |
308 | 308 | 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++) { | |
311 | 310 | if (crc32 == MMC5CartList[x].crc32) { |
312 | 311 | if(MMC5CartList[x].size > 1) |
313 | 312 | FCEU_printf(" >8KB external WRAM present. Use UNIF if you hack the ROM image.\n"); |
0 | 0 | /* FCE Ultra - NES/Famicom Emulator |
1 | 1 | * |
2 | 2 | * Copyright notice for this file: |
3 | * Copyright (C) 2014 CaitSith2 | |
3 | * Copyright (C) 2014 CaitSith2, 2022 Cluster | |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify |
6 | 6 | * it under the terms of the GNU General Public License as published by |
18 | 18 | */ |
19 | 19 | |
20 | 20 | /* |
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. | |
22 | 22 | * 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. |
23 | 23 | * UNIF doesn't have this problem, because unique board names can define this information. |
24 | 24 | * The UNIF names are UNROM-512-8K, UNROM-512-16K and UNROM-512-32K |
27 | 27 | * Known games to use this board are: |
28 | 28 | * Battle Kid 2: Mountain of Torment (512K PRG, 8K CHR RAM, Horizontal Mirroring, Flash disabled) |
29 | 29 | * 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) | |
30 | 31 | * Although Xmas 2013 uses a different board, where LEDs can be controlled (with writes to the $8000-BFFF space), |
31 | 32 | * it otherwise functions identically. |
32 | 33 | */ |
34 | 35 | #include "mapinc.h" |
35 | 36 | #include "../ines.h" |
36 | 37 | |
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; | |
38 | 45 | 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; | |
57 | 55 | 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) | |
77 | 68 | { |
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(); | |
97 | 139 | } |
98 | 140 | |
99 | 141 | static DECLFW(UNROM512HLatchWrite) |
100 | 142 | { |
101 | 143 | if (bus_conflict) |
102 | latche = (V == CartBR(A)) ? V : 0; | |
144 | latche = V & CartBR(A); | |
103 | 145 | else |
104 | 146 | latche = V; |
105 | 147 | 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(); | |
133 | 149 | } |
134 | 150 | |
135 | 151 | 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); | |
139 | 155 | if(!flash_save) |
140 | 156 | SetWriteHandler(0x8000, 0xFFFF, UNROM512HLatchWrite); |
141 | 157 | else |
142 | 158 | { |
143 | SetWriteHandler(0x8000,0xBFFF,UNROM512LLatchWrite); | |
159 | SetWriteHandler(0x8000,0xBFFF,UNROM512FlashWrite); | |
144 | 160 | SetWriteHandler(0xC000,0xFFFF,UNROM512HLatchWrite); |
145 | 161 | } |
146 | 162 | } |
147 | 163 | |
148 | 164 | 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; | |
229 | 168 | } |
230 | 169 | |
231 | 170 | 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? | |
242 | 179 | |
243 | 180 | int mirror = (head.ROM_type & 1) | ((head.ROM_type & 8) >> 2); |
244 | 181 | switch (mirror) |
257 | 194 | break; |
258 | 195 | } |
259 | 196 | |
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; | |
267 | 197 | if(flash_save) |
268 | 198 | { |
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"); | |
282 | 220 | AddExState(&latche, 1, 0, "LATC"); |
283 | 221 | AddExState(&bus_conflict, 1, 0, "BUSC"); |
284 | 222 | } |
22 | 22 | static bool isPirate; |
23 | 23 | static uint8 is22, reg1mask, reg2mask; |
24 | 24 | static uint16 IRQCount; |
25 | static uint8 IRQLatch, IRQa; | |
25 | static uint8 IRQLatch, IRQa, IRQMode; | |
26 | 26 | static uint8 prgreg[2], chrreg[8]; |
27 | 27 | static uint16 chrhi[8]; |
28 | 28 | static uint8 regcmd, irqcmd, mirr, big_bank; |
44 | 44 | { &IRQCount, 2, "IRQC" }, |
45 | 45 | { &IRQLatch, 1, "IRQL" }, |
46 | 46 | { &IRQa, 1, "IRQA" }, |
47 | { &IRQMode, 1, "IRQM" }, | |
47 | 48 | { 0 } |
48 | 49 | }; |
49 | 50 | |
114 | 115 | case 0x9003: regcmd = V; Sync(); break; |
115 | 116 | case 0xF000: X6502_IRQEnd(FCEU_IQEXT); IRQLatch &= 0xF0; IRQLatch |= V & 0xF; break; |
116 | 117 | 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; | |
118 | 119 | case 0xF003: X6502_IRQEnd(FCEU_IQEXT); IRQa = irqcmd; break; |
119 | 120 | } |
120 | 121 | } |
135 | 136 | void VRC24IRQHook(int a) { |
136 | 137 | #define LCYCS 341 |
137 | 138 | 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--; | |
142 | 143 | IRQCount++; |
143 | 144 | if (IRQCount & 0x100) { |
144 | 145 | X6502_IRQBegin(FCEU_IQEXT); |
145 | 146 | IRQCount = IRQLatch; |
146 | 147 | } |
147 | 148 | } |
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 | } | |
148 | 161 | } |
149 | 162 | } |
150 | 163 | } |
24 | 24 | |
25 | 25 | static uint8 is26; |
26 | 26 | static uint8 prg[2], chr[8], mirr; |
27 | static uint8 IRQLatch, IRQa, IRQd; | |
27 | static uint8 IRQLatch, IRQa, IRQd, IRQMode; | |
28 | 28 | static int32 IRQCount, CycleCount; |
29 | 29 | static uint8 *WRAM = NULL; |
30 | 30 | static uint32 WRAMSIZE; |
39 | 39 | { &IRQLatch, 1, "IRQL" }, |
40 | 40 | { &IRQCount, 4, "IRQC" }, |
41 | 41 | { &CycleCount, 4, "CYCC" }, |
42 | { &IRQMode, 1, "IRQM" }, | |
42 | 43 | { 0 } |
43 | 44 | }; |
44 | 45 | |
108 | 109 | case 0xE003: chr[7] = V; Sync(); break; |
109 | 110 | case 0xF000: IRQLatch = V; X6502_IRQEnd(FCEU_IQEXT); break; |
110 | 111 | case 0xF001: |
112 | IRQMode = V & 4; | |
111 | 113 | IRQa = V & 2; |
112 | 114 | IRQd = V & 1; |
113 | 115 | if (V & 2) |
131 | 133 | |
132 | 134 | static void VRC6IRQHook(int a) { |
133 | 135 | 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 | } | |
141 | 155 | } |
142 | 156 | } |
143 | 157 | } |
20 | 20 | #include "mapinc.h" |
21 | 21 | |
22 | 22 | static uint8 vrc7idx, preg[3], creg[8], mirr; |
23 | static uint8 IRQLatch, IRQa, IRQd; | |
23 | static uint8 IRQLatch, IRQa, IRQd, IRQMode; | |
24 | 24 | static int32 IRQCount, CycleCount; |
25 | 25 | static uint8 *WRAM = NULL; |
26 | 26 | static uint32 WRAMSIZE; |
43 | 43 | { &IRQCount, 4, "IRQC" }, |
44 | 44 | { &CycleCount, 4, "CYCC" }, |
45 | 45 | { (void**)VRC7Sound_saveptr, sizeof(*VRC7Sound) | FCEUSTATE_INDIRECT, "VRC7" }, |
46 | { &IRQMode, 1, "IRQM" }, | |
46 | 47 | {0} |
47 | 48 | }; |
48 | 49 | |
133 | 134 | case 0xE000: mirr = V & 3; Sync(); break; |
134 | 135 | case 0xE010: IRQLatch = V; X6502_IRQEnd(FCEU_IQEXT); break; |
135 | 136 | case 0xF000: |
137 | IRQMode = V & 4; | |
136 | 138 | IRQa = V & 2; |
137 | 139 | IRQd = V & 1; |
138 | 140 | if (V & 2) |
164 | 166 | |
165 | 167 | static void VRC7IRQHook(int a) { |
166 | 168 | 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 | } | |
174 | 188 | } |
175 | 189 | } |
176 | 190 | } |
561 | 561 | |
562 | 562 | std::string soot = FCEU_MakeFName(FCEUMKF_SAV, 0, "sav"); |
563 | 563 | sp = FCEUD_UTF8fopen(soot, "rb"); |
564 | if (sp != NULL) { | |
564 | if (sp != NULL) | |
565 | { | |
565 | 566 | for (int x = 0; x < 4; x++) |
567 | { | |
566 | 568 | 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 | } | |
568 | 576 | } |
569 | 577 | } |
570 | 578 | } |
14 | 14 | // to help support games like "Karnov" |
15 | 15 | // that are not really MMC3 but are |
16 | 16 | // set to mapper 4. |
17 | int mirrorAs2Bits; | |
17 | 18 | int battery; // Presence of an actual battery. |
18 | 19 | int ines2; |
19 | 20 | int submapper; // Submappers as defined by NES 2.0 |
58 | 58 | } |
59 | 59 | |
60 | 60 | |
61 | CHEATF_SUBFAST SubCheats[256] = { 0 }; | |
61 | CHEATF_SUBFAST SubCheats[256]; | |
62 | 62 | uint32 numsubcheats = 0; |
63 | 63 | int globalCheatDisabled = 0; |
64 | 64 | int disableAutoLSCheats = 0; |
151 | 151 | return count; |
152 | 152 | } |
153 | 153 | |
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); | |
155 | 155 | static void CheatMemErr(void) |
156 | 156 | { |
157 | 157 | FCEUD_PrintError("Error allocating memory for cheat data."); |
158 | 158 | } |
159 | 159 | |
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; | |
170 | 165 | temp->addr = addr; |
171 | 166 | temp->val = val; |
172 | 167 | temp->status = status; |
173 | 168 | temp->compare = compare; |
174 | 169 | temp->type = type; |
175 | temp->next = 0; | |
170 | temp->next = nullptr; | |
176 | 171 | |
177 | 172 | if(cheats) |
178 | 173 | { |
181 | 176 | } |
182 | 177 | else |
183 | 178 | cheats = cheatsl = temp; |
184 | ||
185 | return (1); | |
186 | 179 | } |
187 | 180 | |
188 | 181 | /* The "override_existing" parameter is used only in cheat dialog import. |
305 | 298 | fputc(':', fp); |
306 | 299 | |
307 | 300 | 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()); | |
309 | 302 | 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 | ||
313 | 305 | struct CHEATF *t = next; |
314 | 306 | next = next->next; |
315 | if (release) free(t); | |
307 | if (release) delete t; | |
316 | 308 | } |
317 | 309 | } |
318 | 310 | |
332 | 324 | { |
333 | 325 | struct CHEATF *last=next; |
334 | 326 | next=next->next; |
335 | free(last->name); | |
336 | free(last); | |
327 | delete last; | |
337 | 328 | if(!next) break; |
338 | 329 | } |
339 | 330 | cheats=cheatsl=0; |
378 | 369 | |
379 | 370 | int FCEUI_AddCheat(const char *name, uint32 addr, uint8 val, int compare, int type) |
380 | 371 | { |
381 | ||
382 | if(!AddCheatEntry(name, addr, val, compare, 1, type)) | |
383 | return 0; | |
372 | AddCheatEntry(name, addr, val, compare, 1, type); | |
384 | 373 | savecheats = 1; |
385 | 374 | RebuildSubCheats(); |
386 | 375 | |
414 | 403 | else |
415 | 404 | cheats=cheatsl=0; // No (more) cheats. |
416 | 405 | } |
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. | |
419 | 407 | break; |
420 | 408 | } // *END REMOVE THIS CHEAT* |
421 | 409 | |
450 | 438 | } |
451 | 439 | |
452 | 440 | |
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) | |
454 | 442 | { |
455 | 443 | struct CHEATF *next=cheats; |
456 | 444 | |
457 | 445 | while(next) |
458 | 446 | { |
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; | |
460 | 448 | next=next->next; |
461 | 449 | } |
462 | 450 | } |
463 | 451 | |
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) | |
465 | 453 | { |
466 | 454 | struct CHEATF *next=cheats; |
467 | 455 | uint32 x=0; |
599 | 587 | /* name can be NULL if the name isn't going to be changed. */ |
600 | 588 | /* same goes for a, v, and s(except the values of each one must be <0) */ |
601 | 589 | |
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) | |
603 | 591 | { |
604 | 592 | struct CHEATF *next = cheats; |
605 | 593 | uint32 x = 0; |
609 | 597 | if(x == which) |
610 | 598 | { |
611 | 599 | 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; | |
619 | 601 | if(a >= 0) |
620 | 602 | next->addr = a; |
621 | 603 | if(v >= 0) |
661 | 643 | |
662 | 644 | int FCEUI_GlobalToggleCheat(int global_enabled) |
663 | 645 | { |
664 | int _numsubcheats = numsubcheats; | |
646 | unsigned int _numsubcheats = numsubcheats; | |
665 | 647 | globalCheatDisabled = !global_enabled; |
666 | 648 | RebuildSubCheats(); |
667 | 649 | return _numsubcheats != numsubcheats; |
910 | 892 | while (cur) |
911 | 893 | { |
912 | 894 | next = cur->next; |
913 | if ( cur->name ) | |
914 | { | |
915 | free(cur->name); | |
916 | } | |
917 | free(cur); | |
895 | delete cur; | |
918 | 896 | cur = next; |
919 | 897 | } |
920 | 898 | cheats = cheatsl = 0; |
32 | 32 | int FCEU_DisableAllCheats(void); |
33 | 33 | int FCEU_DeleteAllCheats(void); |
34 | 34 | |
35 | typedef struct { | |
35 | struct CHEATF_SUBFAST | |
36 | { | |
36 | 37 | uint16 addr; |
37 | 38 | uint8 val; |
38 | 39 | int compare; |
39 | 40 | readfunc PrevRead; |
40 | } CHEATF_SUBFAST; | |
41 | ||
42 | CHEATF_SUBFAST(void) | |
43 | { | |
44 | addr = 0; val = 0; compare = 0; PrevRead = nullptr; | |
45 | } | |
46 | }; | |
41 | 47 | |
42 | 48 | struct CHEATF { |
43 | 49 | struct CHEATF *next; |
44 | char *name; | |
50 | std::string name; | |
45 | 51 | uint16 addr; |
46 | 52 | uint8 val; |
47 | 53 | int compare; /* -1 for no compare. */ |
10 | 10 | #include <cstdio> |
11 | 11 | #include <cstdlib> |
12 | 12 | |
13 | static char *aboutString = 0; | |
13 | static std::string aboutString; | |
14 | 14 | |
15 | 15 | #ifndef FCEUX_BUILD_TIMESTAMP |
16 | 16 | #define FCEUX_BUILD_TIMESTAMP __TIME__ " " __DATE__ |
17 | 17 | #endif |
18 | ||
19 | //#pragma message( "Compiling using C++ Std: " __FCEU_STRINGIZE(__cplusplus) ) | |
18 | 20 | |
19 | 21 | // returns a string suitable for use in an aboutbox |
20 | 22 | const char *FCEUI_GetAboutString(void) |
25 | 27 | "zeromus, feos\n" |
26 | 28 | "\n" |
27 | 29 | "Current Contributors:\n" |
28 | "CaH4e3, rainwarrior, owomomo, punkrockguy318\n" | |
30 | "CaH4e3, rainwarrior, owomomo, punkrockguy318, Cluster\n" | |
29 | 31 | "\n" |
30 | 32 | "Past Contributors:\n" |
31 | 33 | "xhainingx, gocha, AnS, mjbudd77\n" |
54 | 56 | "\n" |
55 | 57 | FCEUX_BUILD_TIMESTAMP "\n"; |
56 | 58 | |
57 | if (aboutString) return aboutString; | |
59 | if (aboutString.size() > 0) return aboutString.c_str(); | |
58 | 60 | |
59 | 61 | const char *compilerString = FCEUD_GetCompilerString(); |
60 | 62 | |
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]; | |
64 | 64 | |
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(); | |
67 | 72 | } |
5 | 5 | #include "cart.h" |
6 | 6 | #include "ines.h" |
7 | 7 | #include "debug.h" |
8 | #include "debugsymboltable.h" | |
8 | 9 | #include "driver.h" |
9 | 10 | #include "ppu.h" |
10 | 11 | |
40 | 41 | } |
41 | 42 | else // BT_C |
42 | 43 | { |
44 | auto sym = debugSymbolTable.getSymbolAtAnyBank(offsetBuffer); | |
45 | ||
46 | if (sym) | |
47 | { | |
48 | return sym->offset() & 0xFFFF; | |
49 | } | |
50 | ||
43 | 51 | int type = GIT_CART; |
44 | 52 | |
45 | 53 | if (GameInfo) |
641 | 649 | |
642 | 650 | ///fires a breakpoint |
643 | 651 | static void breakpoint(uint8 *opcode, uint16 A, int size) { |
644 | int i, j, romAddrPC; | |
652 | int i, romAddrPC; | |
653 | unsigned int j; | |
645 | 654 | uint8 brk_type; |
646 | 655 | uint8 stackop=0; |
647 | 656 | uint8 stackopstartaddr=0,stackopendaddr=0; |
782 | 791 | { |
783 | 792 | if (watchpoint[i].flags & BT_R) |
784 | 793 | { |
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)) ) | |
786 | 795 | { |
787 | 796 | BREAKHIT(i); |
788 | 797 | } |
813 | 822 | // TXS and TSX only deal with the pointer. |
814 | 823 | if (watchpoint[i].flags & stackop) |
815 | 824 | { |
816 | for (j = (stackopstartaddr|0x0100); j <= (stackopendaddr|0x0100); j++) | |
825 | for (j = (stackopstartaddr|0x0100); j <= (static_cast<unsigned int>(stackopendaddr)|0x0100); j++) | |
817 | 826 | { |
818 | 827 | if (watchpoint[i].endaddress) |
819 | 828 | { |
839 | 848 | // Pushes to stack |
840 | 849 | if (watchpoint[i].flags & WP_W) |
841 | 850 | { |
842 | for (j = (X.S|0x0100); j < (StackAddrBackup|0x0100); j++) | |
851 | for (j = (X.S|0x0100); j < (static_cast<unsigned int>(StackAddrBackup)|0x0100); j++) | |
843 | 852 | { |
844 | 853 | if (watchpoint[i].endaddress) |
845 | 854 | { |
857 | 866 | // Pulls from stack |
858 | 867 | if (watchpoint[i].flags & WP_R) |
859 | 868 | { |
860 | for (j = (StackAddrBackup|0x0100); j < (X.S|0x0100); j++) | |
869 | for (j = (StackAddrBackup|0x0100); j < (static_cast<unsigned int>(X.S)|0x0100); j++) | |
861 | 870 | { |
862 | 871 | if (watchpoint[i].endaddress) |
863 | 872 | { |
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 |
22 | 22 | const char *FCEUD_GetCompilerString(); |
23 | 23 | |
24 | 24 | //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 ); | |
26 | 26 | #define FCEUI_printf FCEU_printf |
27 | 27 | |
28 | 28 | //Video interface |
191 | 191 | int32 FCEUI_GetDesiredFPS(void); |
192 | 192 | void FCEUI_SaveSnapshot(void); |
193 | 193 | 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 ); | |
195 | 195 | #define FCEUI_DispMessage FCEU_DispMessage |
196 | 196 | |
197 | 197 | int FCEUI_DecodePAR(const char *code, int *a, int *v, int *c, int *type); |
206 | 206 | void FCEUI_CheatSearchGet(int (*callb)(uint32 a, uint8 last, uint8 current, void *data), void *data); |
207 | 207 | void FCEUI_CheatSearchBegin(void); |
208 | 208 | 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); | |
213 | 213 | |
214 | 214 | void FCEUI_CheatSearchShowExcluded(void); |
215 | 215 | void FCEUI_CheatSearchSetCurrentAsOriginal(void); |
253 | 253 | uint8 FCEUI_VSUniGetDIPs(void); |
254 | 254 | void FCEUI_VSUniSetDIP(int w, int state); |
255 | 255 | void FCEUI_VSUniCoin(void); |
256 | void FCEUI_VSUniCoin2(void); | |
257 | void FCEUI_VSUniService(void); | |
256 | 258 | |
257 | 259 | void FCEUI_FDSInsert(void); //mbg merge 7/17/06 changed to void fn(void) to make it an EMUCMDFN |
258 | 260 | //int FCEUI_FDSEject(void); |
329 | 331 | ///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) |
330 | 332 | void FCEUD_TraceInstruction(uint8 *opcode, int size); |
331 | 333 | |
334 | ///the driver should flush its trace log | |
335 | void FCEUD_FlushTrace(); | |
336 | ||
332 | 337 | ///the driver might should update its NTView (only used if debugging support is compiled in) |
333 | 338 | void FCEUD_UpdateNTView(int scanline, bool drawall); |
334 | 339 |
146 | 146 | |
147 | 147 | hbox1 = new QHBoxLayout(); |
148 | 148 | lbl = new QLabel(); |
149 | lbl->setText("<a href=\"http://fceux.com\">Website</a>"); | |
149 | lbl->setText("<a href=\"https://fceux.com\">Website</a>"); | |
150 | 150 | lbl->setTextInteractionFlags(Qt::TextBrowserInteraction); |
151 | 151 | lbl->setOpenExternalLinks(true); |
152 | 152 |
840 | 840 | va_copy( vl2, vl ); |
841 | 841 | |
842 | 842 | vfprintf( avLogFp, fmt, vl2 ); |
843 | ||
844 | va_end(vl2); | |
843 | 845 | } |
844 | 846 | |
845 | 847 | av_log_default_callback( avcl, level, fmt, vl ); |
850 | 852 | int loadCodecConfig( int type, const char *codec_name, AVCodecContext *ctx) |
851 | 853 | { |
852 | 854 | int i,j; |
853 | char filename[512]; | |
855 | char filename[4096]; | |
854 | 856 | char line[512]; |
855 | 857 | char section[256], id[256], val[256]; |
856 | 858 | void *obj, *child; |
857 | 859 | FILE *fp; |
858 | 860 | const char *baseDir = FCEUI_GetBaseDirectory(); |
859 | 861 | |
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; | |
861 | 865 | |
862 | 866 | fp = fopen( filename, "r"); |
863 | 867 | |
988 | 992 | void *obj, *child = NULL; |
989 | 993 | FILE *fp; |
990 | 994 | uint8_t *str; |
991 | char filename[512]; | |
995 | char filename[4096]; | |
992 | 996 | const AVOption *opt; |
993 | 997 | bool useOpt; |
994 | 998 | const char *baseDir = FCEUI_GetBaseDirectory(); |
995 | 999 | |
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; | |
997 | 1003 | |
998 | 1004 | fp = fopen( filename, "w"); |
999 | 1005 | |
1282 | 1288 | return 0; |
1283 | 1289 | } |
1284 | 1290 | |
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) | |
1288 | 1293 | { |
1289 | 1294 | AVFrame *frame = av_frame_alloc(); |
1290 | 1295 | int ret; |
1293 | 1298 | fprintf(stderr, "Error allocating an audio frame\n"); |
1294 | 1299 | return NULL; |
1295 | 1300 | } |
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; | |
1299 | 1308 | frame->nb_samples = nb_samples; |
1300 | 1309 | |
1301 | 1310 | if (nb_samples) |
1309 | 1318 | } |
1310 | 1319 | return frame; |
1311 | 1320 | } |
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 | |
1312 | 1363 | |
1313 | 1364 | static int initAudioStream( const char *codec_name, OutputStream *ost ) |
1314 | 1365 | { |
1403 | 1454 | } |
1404 | 1455 | |
1405 | 1456 | // Channel Layout Selection |
1457 | #if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 28, 100) | |
1406 | 1458 | if ( ost->chanLayout > 0 ) |
1407 | 1459 | { |
1408 | 1460 | c->channel_layout = ost->chanLayout; |
1429 | 1481 | c->channel_layout = codec->channel_layouts ? codec->channel_layouts[0] : AV_CH_LAYOUT_STEREO; |
1430 | 1482 | } |
1431 | 1483 | 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 | |
1432 | 1491 | c->bit_rate = 64000; |
1433 | 1492 | //ost->st->time_base = (AVRational){ 1, c->sample_rate }; |
1434 | 1493 | ost->st->time_base.num = 1; |
1451 | 1510 | } |
1452 | 1511 | av_opt_set_sample_fmt(ost->swr_ctx, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0); |
1453 | 1512 | av_opt_set_int(ost->swr_ctx, "in_sample_rate", audioSampleRate, 0); |
1513 | #if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 28, 100) | |
1454 | 1514 | 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 | |
1455 | 1524 | av_opt_set_sample_fmt(ost->swr_ctx, "out_sample_fmt", c->sample_fmt, 0); |
1456 | 1525 | 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) | |
1457 | 1527 | 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 | |
1458 | 1531 | |
1459 | 1532 | ret = swr_init(ost->swr_ctx); |
1460 | 1533 | if (ret < 0) |
1495 | 1568 | ost->frameSize = nb_samples; |
1496 | 1569 | ost->bytesPerSample = av_get_bytes_per_sample( c->sample_fmt ); |
1497 | 1570 | |
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); | |
1501 | 1573 | |
1502 | 1574 | //printf("Audio: FMT:%i ChanLayout:%li Rate:%i FrameSize:%i bytesPerSample:%i \n", |
1503 | 1575 | // c->sample_fmt, c->channel_layout, c->sample_rate, nb_samples, ost->bytesPerSample ); |
1853 | 1925 | |
1854 | 1926 | ret = av_samples_copy( ost->frame->data, ost->tmp_frame->data, |
1855 | 1927 | 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 ); | |
1857 | 1934 | |
1858 | 1935 | if ( ret < 0 ) |
1859 | 1936 | { |
2060 | 2137 | char fourcc[8]; |
2061 | 2138 | gwavi_audio_t audioConfig; |
2062 | 2139 | double fps; |
2063 | char fileName[1024]; | |
2140 | std::string fileName; | |
2064 | 2141 | char txt[512]; |
2065 | 2142 | const char *romFile; |
2066 | 2143 | |
2073 | 2150 | |
2074 | 2151 | if ( filepath != NULL ) |
2075 | 2152 | { |
2076 | strcpy( fileName, filepath ); | |
2153 | fileName.assign( filepath ); | |
2077 | 2154 | } |
2078 | 2155 | else |
2079 | 2156 | { |
2092 | 2169 | |
2093 | 2170 | if ( lastPath.size() > 0 ) |
2094 | 2171 | { |
2095 | strcpy( fileName, lastPath.c_str() ); | |
2096 | strcat( fileName, "/" ); | |
2172 | fileName.assign( lastPath.c_str() ); | |
2173 | fileName.append( "/" ); | |
2097 | 2174 | } |
2098 | 2175 | else if ( baseDir ) |
2099 | 2176 | { |
2100 | strcpy( fileName, baseDir ); | |
2101 | strcat( fileName, "/avi/" ); | |
2177 | fileName.assign( baseDir ); | |
2178 | fileName.append( "/avi/" ); | |
2102 | 2179 | } |
2103 | 2180 | else |
2104 | 2181 | { |
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() ); | |
2110 | 2187 | } |
2111 | 2188 | else |
2112 | 2189 | { |
2114 | 2191 | } |
2115 | 2192 | } |
2116 | 2193 | |
2117 | if ( fileName[0] != 0 ) | |
2118 | { | |
2119 | QFile file(fileName); | |
2194 | if ( fileName.size() > 0 ) | |
2195 | { | |
2196 | QFile file(fileName.c_str()); | |
2120 | 2197 | |
2121 | 2198 | if ( file.exists() ) |
2122 | 2199 | { |
2124 | 2201 | std::string msg; |
2125 | 2202 | |
2126 | 2203 | msg = "Pre-existing AVI file will be overwritten:\n\n" + |
2127 | std::string(fileName) + "\n\nReplace file?"; | |
2204 | fileName + "\n\nReplace file?"; | |
2128 | 2205 | |
2129 | 2206 | ret = QMessageBox::warning( consoleWindow, QObject::tr("Overwrite Warning"), |
2130 | 2207 | QString::fromStdString(msg), QMessageBox::Yes | QMessageBox::No ); |
2222 | 2299 | #ifdef _USE_LIBAV |
2223 | 2300 | if ( aviDriver == AVI_DRIVER_LIBAV ) |
2224 | 2301 | { |
2225 | if ( LIBAV::initMedia( fileName ) ) | |
2302 | if ( LIBAV::initMedia( fileName.c_str() ) ) | |
2226 | 2303 | { |
2227 | 2304 | char msg[512]; |
2228 | 2305 | fprintf( avLogFp, "Error: Failed to open AVI file.\n"); |
2237 | 2314 | { |
2238 | 2315 | gwavi = new gwavi_t(); |
2239 | 2316 | |
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 ) ) | |
2241 | 2318 | { |
2242 | 2319 | char msg[512]; |
2243 | 2320 | fprintf( avLogFp, "Error: Failed to open AVI file.\n"); |
3090 | 3167 | { |
3091 | 3168 | return; |
3092 | 3169 | } |
3170 | #if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 28, 100) | |
3093 | 3171 | if ( c->channel_layouts ) |
3094 | 3172 | { |
3095 | 3173 | int i=0; |
3101 | 3179 | |
3102 | 3180 | audioChanLayout->addItem( tr(layoutDesc), (unsigned long long)c->channel_layouts[i] ); |
3103 | 3181 | |
3104 | if ( LIBAV::audio_st.chanLayout == c->channel_layouts[i] ) | |
3182 | if ( static_cast<uint64_t>(LIBAV::audio_st.chanLayout) == c->channel_layouts[i] ) | |
3105 | 3183 | { |
3106 | 3184 | audioChanLayout->setCurrentIndex( audioChanLayout->count() - 1 ); |
3107 | 3185 | formatOk = true; |
3108 | 3186 | } |
3109 | 3187 | i++; |
3110 | 3188 | } |
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 | |
3112 | 3210 | if ( !formatOk ) |
3113 | 3211 | { |
3114 | 3212 | LIBAV::audio_st.chanLayout = -1; |
3332 | 3430 | break; |
3333 | 3431 | case AV_OPT_TYPE_INT: |
3334 | 3432 | case AV_OPT_TYPE_INT64: |
3433 | #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 58, 100) | |
3335 | 3434 | case AV_OPT_TYPE_UINT64: |
3435 | #endif | |
3336 | 3436 | { |
3337 | 3437 | int64_t i; |
3338 | 3438 | |
3704 | 3804 | { |
3705 | 3805 | case AV_OPT_TYPE_INT: |
3706 | 3806 | case AV_OPT_TYPE_INT64: |
3807 | #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 58, 100) | |
3707 | 3808 | case AV_OPT_TYPE_UINT64: |
3809 | #endif | |
3708 | 3810 | { |
3709 | 3811 | int64_t val; |
3710 | 3812 | |
3969 | 4071 | { |
3970 | 4072 | case AV_OPT_TYPE_INT: |
3971 | 4073 | case AV_OPT_TYPE_INT64: |
4074 | #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 58, 100) | |
3972 | 4075 | case AV_OPT_TYPE_UINT64: |
4076 | #endif | |
3973 | 4077 | { |
3974 | 4078 | if ( intEntry ) |
3975 | 4079 | { |
4059 | 4163 | { |
4060 | 4164 | case AV_OPT_TYPE_INT: |
4061 | 4165 | case AV_OPT_TYPE_INT64: |
4166 | #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 58, 100) | |
4062 | 4167 | case AV_OPT_TYPE_UINT64: |
4168 | #endif | |
4063 | 4169 | { |
4064 | 4170 | if ( intEntry ) |
4065 | 4171 | { |
847 | 847 | } |
848 | 848 | else if ( strcmp( strhType, "auds" ) == 0 ) |
849 | 849 | { |
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 ); | |
853 | 855 | |
854 | 856 | sprintf( stmp, "%c%c%c%c", data.buf[0], data.buf[1], data.buf[2], data.buf[3] ); |
855 | 857 | |
904 | 906 | |
905 | 907 | twi = new QTreeWidgetItem(); |
906 | 908 | 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") ); | |
914 | 909 | twi->setText( 2, tr(stmp) ); |
915 | 910 | item->addChild(twi); |
916 | 911 | } |
949 | 944 | |
950 | 945 | sprintf( stmp, "%u", data.readU32(8) ); |
951 | 946 | |
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 ) ) | |
955 | 950 | { |
956 | 951 | i = sizeof(stmp)-1; break; |
957 | 952 | } |
51 | 51 | { |
52 | 52 | if (win != NULL) |
53 | 53 | { |
54 | win->activateWindow(); | |
55 | win->raise(); | |
56 | win->setFocus(); | |
54 | 57 | return; |
55 | 58 | } |
56 | 59 | win = new GuiCheatsDialog_t(parent); |
194 | 197 | |
195 | 198 | hbox->addWidget(lbl); |
196 | 199 | 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); | |
197 | 212 | |
198 | 213 | vbox1->addLayout(hbox); |
199 | 214 | |
434 | 449 | |
435 | 450 | setLayout(mainLayout); |
436 | 451 | |
452 | modCheatBtn->setDefault(true); | |
453 | ||
437 | 454 | connect(srchResetBtn, SIGNAL(clicked(void)), this, SLOT(resetSearchCallback(void))); |
438 | 455 | connect(knownValBtn, SIGNAL(clicked(void)), this, SLOT(knownValueCallback(void))); |
439 | 456 | connect(eqValBtn, SIGNAL(clicked(void)), this, SLOT(equalValueCallback(void))); |
669 | 686 | FCEU_WRAPPER_UNLOCK(); |
670 | 687 | } |
671 | 688 | //---------------------------------------------------------------------------- |
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) | |
673 | 690 | { |
674 | 691 | QTreeWidgetItem *item; |
675 | 692 | char codeStr[32]; |
709 | 726 | return 1; |
710 | 727 | } |
711 | 728 | //---------------------------------------------------------------------------- |
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) | |
713 | 730 | { |
714 | 731 | return win->activeCheatListCB(name, a, v, c, s, type, data); |
715 | 732 | } |
717 | 734 | void GuiCheatsDialog_t::showActiveCheatList(bool redraw) |
718 | 735 | { |
719 | 736 | win = this; |
737 | ||
738 | enaCheats->setChecked(!globalCheatDisabled); | |
720 | 739 | |
721 | 740 | actvCheatRedraw = redraw; |
722 | 741 | |
735 | 754 | int ret, useNativeFileDialogVal; |
736 | 755 | QString filename; |
737 | 756 | std::string last; |
738 | char dir[512]; | |
757 | std::string dir; | |
739 | 758 | QFileDialog dialog(this, tr("Open Cheat File")); |
740 | 759 | |
741 | 760 | dialog.setFileMode(QFileDialog::ExistingFile); |
750 | 769 | |
751 | 770 | getDirFromFile(last.c_str(), dir); |
752 | 771 | |
753 | dialog.setDirectory(tr(dir)); | |
772 | dialog.setDirectory(tr(dir.c_str())); | |
754 | 773 | |
755 | 774 | // Check config option to use native file dialog or not |
756 | 775 | g_config->getOption("SDL.UseNativeFileDialog", &useNativeFileDialogVal); |
799 | 818 | FILE *fp; |
800 | 819 | int ret, useNativeFileDialogVal; |
801 | 820 | QString filename; |
802 | char dir[512]; | |
821 | char dir[4096]; | |
803 | 822 | QFileDialog dialog(this, tr("Save Cheat File")); |
804 | 823 | |
805 | 824 | dialog.setFileMode(QFileDialog::AnyFile); |
870 | 889 | uint32 a = 0; |
871 | 890 | uint8 v = 0; |
872 | 891 | int c = -1; |
892 | int t = 1; | |
873 | 893 | std::string name, cmpStr; |
874 | 894 | |
875 | 895 | a = strtoul(cheatAddrEntry->displayText().toStdString().c_str(), NULL, 16); |
889 | 909 | |
890 | 910 | name = cheatNameEntry->text().toStdString(); |
891 | 911 | |
912 | t = typeEntry->currentData().toInt(); | |
913 | ||
892 | 914 | FCEU_WRAPPER_LOCK(); |
893 | FCEUI_AddCheat(name.c_str(), a, v, c, 1); | |
915 | FCEUI_AddCheat(name.c_str(), a, v, c, t); | |
894 | 916 | FCEU_WRAPPER_UNLOCK(); |
895 | 917 | |
896 | 918 | showActiveCheatList(true); |
920 | 942 | cheatAddrEntry->setText(tr("")); |
921 | 943 | cheatValEntry->setText(tr("")); |
922 | 944 | cheatCmpEntry->setText(tr("")); |
945 | typeEntry->setCurrentIndex(0); | |
923 | 946 | } |
924 | 947 | //---------------------------------------------------------------------------- |
925 | 948 | void GuiCheatsDialog_t::updateCheatParameters(void) |
968 | 991 | |
969 | 992 | //printf("Name: %s \n", name.c_str() ); |
970 | 993 | |
994 | type = typeEntry->currentData().toInt(); | |
995 | ||
971 | 996 | FCEU_WRAPPER_LOCK(); |
972 | 997 | |
973 | FCEUI_SetCheat(row, name.c_str(), a, v, c, s, type); | |
998 | FCEUI_SetCheat(row, &name, a, v, c, s, type); | |
974 | 999 | |
975 | 1000 | FCEU_WRAPPER_UNLOCK(); |
976 | 1001 | |
982 | 1007 | uint32 a = 0; |
983 | 1008 | uint8 v = 0; |
984 | 1009 | int c = -1, s = 0, type = 0; |
985 | char *name = NULL; | |
1010 | std::string name; | |
986 | 1011 | char stmp[64]; |
987 | 1012 | |
988 | 1013 | int row = actvCheatList->indexOfTopLevelItem(item); |
1020 | 1045 | cheatCmpEntry->setText(tr("")); |
1021 | 1046 | } |
1022 | 1047 | |
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); | |
1031 | 1051 | } |
1032 | 1052 | //---------------------------------------------------------------------------- |
1033 | 1053 | void GuiCheatsDialog_t::globalEnableCheats(int state) |
29 | 29 | |
30 | 30 | int addSearchResult(uint32_t a, uint8_t last, uint8_t current); |
31 | 31 | |
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); | |
33 | 33 | |
34 | 34 | void showActiveCheatList(bool redraw); |
35 | 35 | |
66 | 66 | QLineEdit *neValEntry; |
67 | 67 | QLineEdit *grValEntry; |
68 | 68 | QLineEdit *ltValEntry; |
69 | QComboBox *typeEntry; | |
69 | 70 | QFont font; |
70 | 71 | |
71 | 72 | int fontCharWidth; |
50 | 50 | static bool autoSaveArmedCDL = false; |
51 | 51 | static char loadedcdfile[512] = {0}; |
52 | 52 | |
53 | static int getDefaultCDLFile(char *filepath); | |
53 | static int getDefaultCDLFile(std::string &filepath); | |
54 | 54 | |
55 | 55 | static CodeDataLoggerDialog_t *cdlWin = NULL; |
56 | 56 | //---------------------------------------------------- |
279 | 279 | |
280 | 280 | if (autoLoadCDL) |
281 | 281 | { |
282 | char nameo[2048]; | |
282 | std::string nameo; | |
283 | 283 | getDefaultCDLFile(nameo); |
284 | LoadCDLog(nameo); | |
284 | LoadCDLog(nameo.c_str()); | |
285 | 285 | } |
286 | 286 | |
287 | 287 | restoreGeometry(settings.value("cdLogger/geometry").toByteArray()); |
443 | 443 | |
444 | 444 | if (romFile != NULL) |
445 | 445 | { |
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())); | |
455 | 455 | } |
456 | 456 | |
457 | 457 | // Check config option to use native file dialog or not |
488 | 488 | { |
489 | 489 | int ret, useNativeFileDialogVal; |
490 | 490 | QString filename; |
491 | char dir[512]; | |
491 | std::string dir; | |
492 | 492 | const char *romFile; |
493 | 493 | QFileDialog dialog(this, tr("Load CDL File")); |
494 | 494 | |
506 | 506 | { |
507 | 507 | getDirFromFile(romFile, dir); |
508 | 508 | |
509 | dialog.setDirectory(tr(dir)); | |
509 | dialog.setDirectory(tr(dir.c_str())); | |
510 | 510 | } |
511 | 511 | |
512 | 512 | // Check config option to use native file dialog or not |
586 | 586 | |
587 | 587 | if (romFile != NULL) |
588 | 588 | { |
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())); | |
594 | 594 | } |
595 | 595 | |
596 | 596 | // Check config option to use native file dialog or not |
724 | 724 | SaveStrippedROM(1); |
725 | 725 | } |
726 | 726 | //---------------------------------------------------- |
727 | static int getDefaultCDLFile(char *filepath) | |
727 | static int getDefaultCDLFile(std::string &filepath) | |
728 | 728 | { |
729 | 729 | const char *romFile; |
730 | char dir[512], baseFile[256]; | |
731 | ||
732 | filepath[0] = 0; | |
730 | std::string dir, baseFile; | |
731 | ||
732 | filepath.clear(); | |
733 | 733 | |
734 | 734 | romFile = getRomFile(); |
735 | 735 | |
738 | 738 | return -1; |
739 | 739 | } |
740 | 740 | |
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"); | |
746 | 747 | } |
747 | 748 | else |
748 | 749 | { |
749 | sprintf(filepath, "%s/%s.cdl", dir, baseFile); | |
750 | filepath.assign(dir); | |
751 | filepath.append(baseFile); | |
752 | filepath.append(".cdl"); | |
750 | 753 | } |
751 | 754 | |
752 | 755 | //printf("%s\n", filepath ); |
937 | 940 | return; |
938 | 941 | |
939 | 942 | // try to load respective CDL file |
940 | char nameo[1024]; | |
943 | std::string nameo; | |
941 | 944 | getDefaultCDLFile(nameo); |
942 | 945 | |
943 | 946 | FILE *FP; |
944 | FP = fopen(nameo, "rb"); | |
947 | FP = fopen(nameo.c_str(), "rb"); | |
945 | 948 | if (FP != NULL) |
946 | 949 | { |
947 | 950 | // .cdl file with this ROM name exists |
950 | 953 | //{ |
951 | 954 | // DoCDLogger(); |
952 | 955 | //} |
953 | if (LoadCDLog(nameo)) | |
956 | if (LoadCDLog(nameo.c_str())) | |
954 | 957 | { |
955 | 958 | StartCDLogging(); |
956 | 959 | } |
966 | 969 | { |
967 | 970 | if (loadedcdfile[0] == 0) |
968 | 971 | { |
969 | char nameo[1024]; | |
972 | std::string nameo; | |
970 | 973 | getDefaultCDLFile(nameo); |
971 | RenameCDLog(nameo); | |
974 | RenameCDLog(nameo.c_str()); | |
972 | 975 | } |
973 | 976 | |
974 | 977 | FILE *FP; |
3189 | 3189 | //---------------------------------------------------------------------------- |
3190 | 3190 | void QAsmView::toggleBreakpoint(int line) |
3191 | 3191 | { |
3192 | if ( line < asmEntry.size() ) | |
3192 | if ( static_cast<size_t>(line) < asmEntry.size() ) | |
3193 | 3193 | { |
3194 | 3194 | int bpNum = isBreakpointAtLine(line); |
3195 | 3195 | |
3229 | 3229 | { |
3230 | 3230 | if ( watchpoint[i].endaddress ) |
3231 | 3231 | { |
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 ) | |
3234 | 3234 | { |
3235 | 3235 | return i; |
3236 | 3236 | } |
3237 | 3237 | } |
3238 | 3238 | else |
3239 | 3239 | { |
3240 | if (romAddr == watchpoint[i].address) | |
3240 | if ( static_cast<unsigned int>(romAddr) == watchpoint[i].address) | |
3241 | 3241 | { |
3242 | 3242 | return i; |
3243 | 3243 | } |
3247 | 3247 | { |
3248 | 3248 | if ( watchpoint[i].endaddress ) |
3249 | 3249 | { |
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 ) | |
3252 | 3252 | { |
3253 | 3253 | return i; |
3254 | 3254 | } |
3255 | 3255 | } |
3256 | 3256 | else |
3257 | 3257 | { |
3258 | if (cpuAddr == watchpoint[i].address) | |
3258 | if ( static_cast<unsigned int>(cpuAddr) == watchpoint[i].address) | |
3259 | 3259 | { |
3260 | 3260 | return i; |
3261 | 3261 | } |
3267 | 3267 | //---------------------------------------------------------------------------- |
3268 | 3268 | int QAsmView::isBreakpointAtLine( int l ) |
3269 | 3269 | { |
3270 | if ( l < asmEntry.size() ) | |
3270 | if ( static_cast<size_t>(l) < asmEntry.size() ) | |
3271 | 3271 | { |
3272 | 3272 | if ( asmEntry[l]->type == dbg_asm_entry_t::ASM_TEXT ) |
3273 | 3273 | { |
3289 | 3289 | { |
3290 | 3290 | int addr = -1; |
3291 | 3291 | |
3292 | if ( (selAddrLine >= 0) && (selAddrLine < asmEntry.size()) ) | |
3292 | if ( (selAddrLine >= 0) && (static_cast<size_t>(selAddrLine) < asmEntry.size()) ) | |
3293 | 3293 | { |
3294 | 3294 | if ( selAddrValue == asmEntry[ selAddrLine ]->addr ) |
3295 | 3295 | { |
3310 | 3310 | //---------------------------------------------------------------------------- |
3311 | 3311 | int QAsmView::getAsmAddrFromLine(int line) |
3312 | 3312 | { |
3313 | if ( (line >= 0) && (line < asmEntry.size()) ) | |
3313 | if ( (line >= 0) && (static_cast<size_t>(line) < asmEntry.size()) ) | |
3314 | 3314 | { |
3315 | 3315 | return asmEntry[line]->addr; |
3316 | 3316 | } |
3423 | 3423 | } |
3424 | 3424 | |
3425 | 3425 | // 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) ) | |
3427 | 3427 | { |
3428 | 3428 | line++; |
3429 | 3429 | } |
3545 | 3545 | { |
3546 | 3546 | uint8_t cdl_data; |
3547 | 3547 | 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) ) | |
3549 | 3549 | { |
3550 | 3550 | cdl_data = cdloggerdata[instruction_addr] & 3; |
3551 | 3551 | if (cdl_data == 3) |
3676 | 3676 | char stmp[256]; |
3677 | 3677 | //printf("Debug symbol Found at $%04X \n", dbgSym->ofs ); |
3678 | 3678 | |
3679 | if ( dbgSym->name.size() > 0 ) | |
3679 | if ( dbgSym->name().size() > 0 ) | |
3680 | 3680 | { |
3681 | 3681 | d = new dbg_asm_entry_t(); |
3682 | 3682 | |
3683 | 3683 | *d = *a; |
3684 | 3684 | d->type = dbg_asm_entry_t::SYMBOL_NAME; |
3685 | d->text.assign( " " + dbgSym->name ); | |
3685 | d->text.assign( " " + dbgSym->name() ); | |
3686 | 3686 | d->text.append( ":"); |
3687 | 3687 | d->line = asmEntry.size(); |
3688 | 3688 | |
3690 | 3690 | } |
3691 | 3691 | |
3692 | 3692 | i=0; j=0; |
3693 | c = dbgSym->comment.c_str(); | |
3693 | c = dbgSym->comment().c_str(); | |
3694 | 3694 | |
3695 | 3695 | while ( c[i] != 0 ) |
3696 | 3696 | { |
3745 | 3745 | |
3746 | 3746 | a->line = asmEntry.size(); |
3747 | 3747 | |
3748 | if ( maxLineLen < line.size() ) | |
3748 | if ( static_cast<size_t>(maxLineLen) < line.size() ) | |
3749 | 3749 | { |
3750 | 3750 | maxLineLen = line.size(); |
3751 | 3751 | } |
4334 | 4334 | } |
4335 | 4335 | } |
4336 | 4336 | //---------------------------------------------------------------------------- |
4337 | static int getGameDebugBreakpointFileName(char *filepath) | |
4337 | static int getGameDebugBreakpointFileName(std::string &filepath) | |
4338 | 4338 | { |
4339 | 4339 | int i,j; |
4340 | 4340 | const char *romFile; |
4351 | 4351 | |
4352 | 4352 | if ( romFile[i] == '|' ) |
4353 | 4353 | { |
4354 | filepath[i] = '.'; | |
4354 | filepath.push_back('.'); | |
4355 | 4355 | } |
4356 | 4356 | else |
4357 | 4357 | { |
4358 | if ( romFile[i] == '/' ) | |
4358 | if ( (romFile[i] == '/') || (romFile[i] == '\\') ) | |
4359 | 4359 | { |
4360 | 4360 | j = -1; |
4361 | 4361 | } |
4363 | 4363 | { |
4364 | 4364 | j = i; |
4365 | 4365 | } |
4366 | filepath[i] = romFile[i]; | |
4366 | filepath.push_back(romFile[i]); | |
4367 | 4367 | } |
4368 | 4368 | i++; |
4369 | 4369 | } |
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"); | |
4380 | 4375 | |
4381 | 4376 | return 0; |
4382 | 4377 | } |
4385 | 4380 | { |
4386 | 4381 | int i; |
4387 | 4382 | FILE *fp; |
4388 | char stmp[512]; | |
4389 | 4383 | char flags[8]; |
4390 | 4384 | debuggerBookmark_t *bm; |
4385 | std::string fileName; | |
4391 | 4386 | |
4392 | 4387 | // If no breakpoints are loaded, skip saving |
4393 | 4388 | if ( !force && (numWPs == 0) && (dbgBmMgr.size() == 0) ) |
4394 | 4389 | { |
4395 | 4390 | return; |
4396 | 4391 | } |
4397 | if ( getGameDebugBreakpointFileName( stmp ) ) | |
4392 | if ( getGameDebugBreakpointFileName( fileName ) ) | |
4398 | 4393 | { |
4399 | 4394 | printf("Error: Failed to get save file name for debug\n"); |
4400 | 4395 | return; |
4401 | 4396 | } |
4402 | 4397 | |
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"); | |
4406 | 4401 | |
4407 | 4402 | if ( fp == NULL ) |
4408 | 4403 | { |
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() ); | |
4410 | 4405 | return; |
4411 | 4406 | } |
4412 | 4407 | |
4531 | 4526 | FILE *fp; |
4532 | 4527 | char stmp[512]; |
4533 | 4528 | char id[64], data[128]; |
4529 | std::string fileName; | |
4534 | 4530 | |
4535 | 4531 | // If no debug windows are open, skip loading breakpoints |
4536 | 4532 | if ( dbgWin == NULL ) |
4538 | 4534 | printf("No Debug Windows Open: Skipping loading of breakpoint data\n"); |
4539 | 4535 | return; |
4540 | 4536 | } |
4541 | if ( getGameDebugBreakpointFileName( stmp ) ) | |
4537 | if ( getGameDebugBreakpointFileName( fileName ) ) | |
4542 | 4538 | { |
4543 | 4539 | printf("Error: Failed to get load file name for debug\n"); |
4544 | 4540 | return; |
4545 | 4541 | } |
4546 | 4542 | |
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"); | |
4550 | 4546 | |
4551 | 4547 | if ( fp == NULL ) |
4552 | 4548 | { |
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() ); | |
4554 | 4550 | return; |
4555 | 4551 | } |
4556 | 4552 | |
4957 | 4953 | //---------------------------------------------------------------------------- |
4958 | 4954 | void QAsmView::gotoLine( int line ) |
4959 | 4955 | { |
4960 | if ( (line >= 0) && (line < asmEntry.size()) ) | |
4956 | if ( (line >= 0) && (static_cast<size_t>(line) < asmEntry.size()) ) | |
4961 | 4957 | { |
4962 | 4958 | if ( curNavLoc.addr != asmEntry[line]->addr ) |
4963 | 4959 | { // Don't push back to back duplicates into the navigation history |
5024 | 5020 | //---------------------------------------------------------------------------- |
5025 | 5021 | void QAsmView::setSelAddrToLine( int line ) |
5026 | 5022 | { |
5027 | if ( (line >= 0) && (line < asmEntry.size()) ) | |
5023 | if ( (line >= 0) && (static_cast<size_t>(line) < asmEntry.size()) ) | |
5028 | 5024 | { |
5029 | 5025 | int addr = asmEntry[line]->addr; |
5030 | 5026 | selAddrLine = line; |
5177 | 5173 | |
5178 | 5174 | line = lineOffset + c.y(); |
5179 | 5175 | |
5180 | opcodeValid = (line < asmEntry.size()) && (asmEntry[line]->size > 0) && | |
5176 | opcodeValid = (static_cast<size_t>(line) < asmEntry.size()) && (asmEntry[line]->size > 0) && | |
5181 | 5177 | (asmEntry[line]->type == dbg_asm_entry_t::ASM_TEXT); |
5182 | 5178 | |
5183 | 5179 | showOpcodeDesc = (c.x() >= opcodeLinePos) && (c.x() < operandLinePos) && opcodeValid; |
5184 | 5180 | |
5185 | 5181 | showAddrDesc = (c.x() >= pcLocLinePos) && (c.x() < byteCodeLinePos) && opcodeValid; |
5186 | 5182 | |
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)) ) | |
5192 | 5188 | { |
5193 | 5189 | //printf("Line:%i asmEntry DB Sym: %zi '%s'\n", line, subStrLoc, asmEntry[line]->sym.name.c_str() ); |
5194 | 5190 | int symTextStart = subStrLoc; |
5195 | int symTextEnd = subStrLoc + asmEntry[line]->sym.name.size(); | |
5191 | int symTextEnd = subStrLoc + asmEntry[line]->sym.name().size(); | |
5196 | 5192 | |
5197 | 5193 | if ( (c.x() >= symTextStart) && (c.x() < symTextEnd) ) |
5198 | 5194 | { |
5202 | 5198 | } |
5203 | 5199 | |
5204 | 5200 | if ( opcodeValid && (c.x() > operandLinePos) && |
5205 | (c.x() < asmEntry[line]->text.size()) ) | |
5201 | ( static_cast<size_t>(c.x()) < asmEntry[line]->text.size()) ) | |
5206 | 5202 | { |
5207 | 5203 | i = c.x(); |
5208 | 5204 | |
5256 | 5252 | } |
5257 | 5253 | else if ( showSymHexDecode ) |
5258 | 5254 | { |
5259 | sprintf( stmp, "$%04X", asmEntry[line]->sym.ofs ); | |
5255 | sprintf( stmp, "$%04X", asmEntry[line]->sym.offset() ); | |
5260 | 5256 | |
5261 | 5257 | QToolTip::showText(helpEvent->globalPos(), tr(stmp), this ); |
5262 | 5258 | } |
5555 | 5551 | |
5556 | 5552 | //printf("c (%i,%i) : Line %i : %04X \n", c.x(), c.y(), line, asmEntry[line]->addr ); |
5557 | 5553 | |
5558 | if ( line < asmEntry.size() ) | |
5554 | if ( static_cast<size_t>(line) < asmEntry.size() ) | |
5559 | 5555 | { |
5560 | 5556 | int addr; |
5561 | 5557 | |
5654 | 5650 | } |
5655 | 5651 | hlgtXd = (hlgtXe - hlgtXs); |
5656 | 5652 | |
5657 | if ( hlgtXs < asmEntry[l]->text.size() ) | |
5653 | if ( static_cast<size_t>(hlgtXs) < asmEntry[l]->text.size() ) | |
5658 | 5654 | { |
5659 | 5655 | s = asmEntry[l]->text.substr( hlgtXs, hlgtXd ); |
5660 | 5656 | } |
5745 | 5741 | selAddrType = 0; |
5746 | 5742 | selAddrText[0] = 0; |
5747 | 5743 | |
5748 | if ( line < asmEntry.size() ) | |
5744 | if ( static_cast<size_t>(line) < asmEntry.size() ) | |
5749 | 5745 | { |
5750 | 5746 | int i,j, addr = -1, addrTextLoc = -1, selChar; |
5751 | 5747 | int symTextStart = -1, symTextEnd = -1; |
5756 | 5752 | |
5757 | 5753 | if ( asmEntry[line]->type == dbg_asm_entry_t::ASM_TEXT ) |
5758 | 5754 | { |
5759 | if ( selChar < (int)asmEntry[line]->text.size() ) | |
5755 | if ( static_cast<size_t>(selChar) < asmEntry[line]->text.size() ) | |
5760 | 5756 | { |
5761 | 5757 | i = selChar; |
5762 | 5758 | |
5763 | if ( asmEntry[line]->sym.name.size() > 0 ) | |
5759 | if ( asmEntry[line]->sym.name().size() > 0 ) | |
5764 | 5760 | { |
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)) ) | |
5768 | 5764 | { |
5769 | 5765 | //printf("Line:%i asmEntry DB Sym: %zi '%s'\n", line, subStrLoc, asmEntry[line]->sym.name.c_str() ); |
5770 | 5766 | symTextStart = subStrLoc; |
5771 | symTextEnd = subStrLoc + asmEntry[line]->sym.name.size(); | |
5767 | symTextEnd = subStrLoc + asmEntry[line]->sym.name().size(); | |
5772 | 5768 | } |
5773 | 5769 | } |
5774 | 5770 | |
5777 | 5773 | selAddrLine = line; |
5778 | 5774 | selAddrChar = symTextStart; |
5779 | 5775 | selAddrWidth = symTextEnd - symTextStart; |
5780 | selAddrValue = addr = asmEntry[line]->sym.ofs; | |
5776 | selAddrValue = addr = asmEntry[line]->sym.offset(); | |
5781 | 5777 | selAddrType = 0; |
5782 | 5778 | |
5783 | 5779 | if ( selAddrWidth >= (int)sizeof(selAddrText) ) |
5784 | 5780 | { |
5785 | 5781 | selAddrWidth = sizeof(selAddrText)-1; |
5786 | 5782 | } |
5787 | strncpy( selAddrText, asmEntry[line]->sym.name.c_str(), selAddrWidth ); | |
5783 | strncpy( selAddrText, asmEntry[line]->sym.name().c_str(), selAddrWidth ); | |
5788 | 5784 | selAddrText[ selAddrWidth ] = 0; |
5789 | 5785 | } |
5790 | 5786 | else if ( isxdigit( asmEntry[line]->text[i] ) ) |
5983 | 5979 | |
5984 | 5980 | ctxMenuAddr = -1; |
5985 | 5981 | |
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; | |
5989 | 5985 | |
5990 | 5986 | if ( selAddrValue < 0 ) |
5991 | 5987 | { |
6034 | 6030 | act->setShortcut( QKeySequence(tr("B"))); |
6035 | 6031 | connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuAddBP(void)) ); |
6036 | 6032 | |
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 | } | |
6038 | 6046 | menu.addAction(act); |
6039 | 6047 | act->setShortcut( QKeySequence(tr("S"))); |
6040 | 6048 | connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuAddSym(void)) ); |
6041 | 6049 | |
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 | } | |
6043 | 6058 | menu.addAction(act); |
6044 | 6059 | act->setShortcut( QKeySequence(tr("M"))); |
6045 | 6060 | connect( act, SIGNAL(triggered(void)), parent, SLOT(asmViewCtxMenuAddBM(void)) ); |
6349 | 6364 | lineIsPC = false; |
6350 | 6365 | } |
6351 | 6366 | |
6352 | if ( l < asmEntry.size() ) | |
6367 | if ( static_cast<size_t>(l) < asmEntry.size() ) | |
6353 | 6368 | { |
6354 | 6369 | //if ( asmEntry[l]->type != dbg_asm_entry_t::ASM_TEXT ) |
6355 | 6370 | //{ |
6381 | 6396 | if ( (selAddrLine == l) ) |
6382 | 6397 | { // Highlight ASM line for selected address. |
6383 | 6398 | if ( !txtHlgtSet && (selAddr == selAddrValue) && |
6384 | (asmEntry[l]->text.size() >= (selAddrChar + selAddrWidth) ) && | |
6399 | (asmEntry[l]->text.size() >= static_cast<size_t>(selAddrChar + selAddrWidth) ) && | |
6385 | 6400 | ( asmEntry[l]->text.compare( selAddrChar, selAddrWidth, selAddrText ) == 0 ) ) |
6386 | 6401 | { |
6387 | 6402 | int ax; |
6436 | 6451 | } |
6437 | 6452 | hlgtXd = (hlgtXe - hlgtXs); |
6438 | 6453 | |
6439 | if ( hlgtXs < asmEntry[l]->text.size() ) | |
6454 | if ( static_cast<size_t>(hlgtXs) < asmEntry[l]->text.size() ) | |
6440 | 6455 | { |
6441 | 6456 | s = asmEntry[l]->text.substr( hlgtXs, hlgtXd ); |
6442 | 6457 | } |
6468 | 6483 | x = -pxLineXScroll; |
6469 | 6484 | l = lineOffset + row; |
6470 | 6485 | |
6471 | if ( l < asmEntry.size() ) | |
6486 | if ( static_cast<size_t>(l) < asmEntry.size() ) | |
6472 | 6487 | { |
6473 | 6488 | if ( asmPC != NULL ) |
6474 | 6489 | { |
53 | 53 | |
54 | 54 | // Enable Sound Select |
55 | 55 | enaChkbox = new QCheckBox(tr("Enable Sound")); |
56 | // Speaker Mute Select | |
57 | muteChkbox = new QCheckBox(tr("Mute Speaker Output")); | |
56 | 58 | // Enable Low Pass Filter Select |
57 | 59 | enaLowPass = new QCheckBox(tr("Enable Low Pass Filter")); |
58 | 60 | |
59 | 61 | setCheckBoxFromProperty(enaChkbox, "SDL.Sound"); |
62 | setCheckBoxFromProperty(muteChkbox, "SDL.Sound.Mute"); | |
60 | 63 | setCheckBoxFromProperty(enaLowPass, "SDL.Sound.LowPass"); |
61 | 64 | |
62 | 65 | connect(enaChkbox, SIGNAL(stateChanged(int)), this, SLOT(enaSoundStateChange(int))); |
66 | connect(muteChkbox, SIGNAL(stateChanged(int)), this, SLOT(enaSpeakerMuteChange(int))); | |
63 | 67 | connect(enaLowPass, SIGNAL(stateChanged(int)), this, SLOT(enaSoundLowPassChange(int))); |
64 | 68 | |
65 | 69 | vbox1->addWidget(enaChkbox); |
70 | vbox1->addWidget(muteChkbox); | |
66 | 71 | vbox1->addWidget(enaLowPass); |
67 | 72 | |
68 | 73 | // Audio Quality Select |
329 | 334 | sprintf( stmp, "Sink Starve Count: %u", nes_shm->sndBuf.starveCounter ); |
330 | 335 | |
331 | 336 | starveLbl->setText( tr(stmp) ); |
337 | ||
338 | if ( FCEUD_SoundIsMuted() != muteChkbox->isChecked() ) | |
339 | { | |
340 | muteChkbox->setChecked( FCEUD_SoundIsMuted() ); | |
341 | } | |
332 | 342 | } |
333 | 343 | //---------------------------------------------------- |
334 | 344 | void ConsoleSndConfDialog_t::setSliderEnables(void) |
535 | 545 | } |
536 | 546 | } |
537 | 547 | //---------------------------------------------------- |
548 | void ConsoleSndConfDialog_t::enaSpeakerMuteChange(int value) | |
549 | { | |
550 | FCEUD_MuteSoundOutput( value ? true : false ); | |
551 | } | |
552 | //---------------------------------------------------- | |
538 | 553 | void ConsoleSndConfDialog_t::enaSoundLowPassChange(int value) |
539 | 554 | { |
540 | 555 | if (value) |
30 | 30 | |
31 | 31 | int sndQuality; |
32 | 32 | QCheckBox *enaChkbox; |
33 | QCheckBox *muteChkbox; | |
33 | 34 | QCheckBox *enaLowPass; |
34 | 35 | QCheckBox *swapDutyChkbox; |
35 | 36 | QCheckBox *useGlobalFocus; |
67 | 68 | void noiseChanged(int value); |
68 | 69 | void pcmChanged(int value); |
69 | 70 | void enaSoundStateChange(int value); |
71 | void enaSpeakerMuteChange(int value); | |
70 | 72 | void enaSoundLowPassChange(int value); |
71 | 73 | void swapDutyCallback(int value); |
72 | 74 | void useGlobalFocusChanged(int value); |
20 | 20 | #include <stdio.h> |
21 | 21 | #include <stdlib.h> |
22 | 22 | #include <string.h> |
23 | #include <string> | |
23 | 24 | |
24 | 25 | #include <QWindow> |
25 | 26 | #include <QScreen> |
26 | 27 | #include <QToolTip> |
28 | #include <QFileInfo> | |
27 | 29 | #include <QApplication> |
28 | 30 | |
29 | 31 | #if WIN32 |
45 | 47 | #include "Qt/fceuWrapper.h" |
46 | 48 | #include "Qt/ConsoleUtilities.h" |
47 | 49 | |
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()); | |
74 | 71 | } |
75 | 72 | |
76 | 73 | return 0; |
78 | 75 | //--------------------------------------------------------------------------- |
79 | 76 | const char *getRomFile( void ) |
80 | 77 | { |
81 | static char filePath[2048]; | |
78 | static std::string filePath; | |
82 | 79 | |
83 | 80 | if ( GameInfo ) |
84 | 81 | { |
87 | 84 | |
88 | 85 | if ( GameInfo->archiveFilename != NULL ) |
89 | 86 | { |
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(); | |
109 | 106 | } |
110 | 107 | else |
111 | 108 | { |
112 | 109 | return GameInfo->filename; |
113 | 110 | } |
114 | 111 | } |
115 | return NULL; | |
112 | return nullptr; | |
116 | 113 | } |
117 | 114 | //--------------------------------------------------------------------------- |
118 | 115 | // Return file base name stripping out preceding path and trailing suffix. |
162 | 159 | return end; |
163 | 160 | } |
164 | 161 | //--------------------------------------------------------------------------- |
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 | ||
173 | 179 | if ( filepath == NULL ) |
174 | 180 | { |
175 | if ( dir ) dir[0] = 0; | |
176 | if ( base ) base[0] = 0; | |
177 | if ( suffix) suffix[0] = 0; | |
178 | 181 | return 0; |
179 | 182 | } |
180 | 183 | i=0; j=0; |
186 | 189 | } |
187 | 190 | if ( dir ) |
188 | 191 | { |
189 | dir[i] = filepath[i]; | |
192 | dir->push_back(filepath[i]); | |
190 | 193 | } |
191 | 194 | i++; |
192 | 195 | } |
193 | if ( dir ) | |
194 | { | |
195 | dir[j] = 0; | |
196 | if (dir) | |
197 | { | |
198 | if (j > 0) | |
199 | { | |
200 | dir->erase(j); | |
201 | } | |
196 | 202 | } |
197 | 203 | i = j; |
198 | 204 | |
199 | if ( base == NULL ) | |
200 | { | |
201 | return end; | |
202 | } | |
203 | ||
204 | j=0; | |
205 | 205 | while ( filepath[i] != 0 ) |
206 | 206 | { |
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; | |
230 | 235 | } |
231 | 236 | //--------------------------------------------------------------------------- |
232 | 237 | // 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(); | |
240 | 241 | |
241 | 242 | #ifdef WIN32 |
242 | 243 | char fullPath[2048]; |
247 | 248 | GetModuleFileNameA(NULL, fullPath, 2048); |
248 | 249 | _splitpath(fullPath, driveLetter, directory, NULL, NULL); |
249 | 250 | snprintf(finalPath, sizeof(finalPath), "%s%s", driveLetter, directory); |
250 | strncpy( outputPath, finalPath, outputSize ); | |
251 | outputPath[outputSize-1] = 0; | |
251 | outputPath.assign( finalPath ); | |
252 | 252 | |
253 | 253 | return 0; |
254 | 254 | #elif __linux__ || __unix__ |
266 | 266 | if ( dir ) |
267 | 267 | { |
268 | 268 | //printf("DIR Path: '%s' \n", dir ); |
269 | strncpy( outputPath, dir, outputSize ); | |
270 | outputPath[outputSize-1] = 0; | |
269 | outputPath.assign( dir ); | |
271 | 270 | return 0; |
272 | 271 | } |
273 | 272 | } |
287 | 286 | if ( dir ) |
288 | 287 | { |
289 | 288 | //printf("DIR Path: '%s' \n", dir ); |
290 | strncpy( outputPath, dir, outputSize ); | |
291 | outputPath[outputSize-1] = 0; | |
289 | outputPath.assign( dir ); | |
292 | 290 | return 0; |
293 | 291 | } |
294 | 292 | } |
295 | 293 | #endif |
296 | 294 | 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(); | |
297 | 304 | } |
298 | 305 | //--------------------------------------------------------------------------- |
299 | 306 | int fceuLoadConfigColor( const char *confName, QColor *color ) |
0 | 0 | // ConsoleUtilities.h |
1 | 1 | |
2 | 2 | #pragma once |
3 | ||
4 | #include <string> | |
3 | 5 | |
4 | 6 | #include <QColor> |
5 | 7 | #include <QTimer> |
8 | 10 | #include <QHelpEvent> |
9 | 11 | #include <QCheckBox> |
10 | 12 | |
11 | int getDirFromFile( const char *path, char *dir ); | |
13 | int getDirFromFile( const char *path, std::string &dir ); | |
12 | 14 | |
13 | 15 | const char *getRomFile( void ); |
14 | 16 | |
15 | int getFileBaseName( const char *filepath, char *base, char *suffix = NULL ); | |
17 | int getFileBaseName( const char *filepath, char *base, char *suffix = nullptr ); | |
16 | 18 | |
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 ); | |
18 | 20 | |
19 | int fceuExecutablePath( char *outputPath, int outputSize ); | |
21 | const char *fceuExecutablePath(void); | |
20 | 22 | |
21 | 23 | int fceuLoadConfigColor( const char *confName, QColor *color ); |
22 | 24 |
83 | 83 | setMinimumWidth( 256 ); |
84 | 84 | setMinimumHeight( 224 ); |
85 | 85 | setFocusPolicy(Qt::StrongFocus); |
86 | //setAttribute(Qt::WA_OpaquePaintEvent); | |
86 | 87 | |
87 | 88 | localBufSize = (4 * GL_NES_WIDTH) * (4 * GL_NES_HEIGHT) * sizeof(uint32_t); |
88 | 89 | |
271 | 272 | GL_BGRA, GL_UNSIGNED_BYTE, 0 ); |
272 | 273 | } |
273 | 274 | |
275 | glEnable(GL_BLEND); | |
276 | glBlendFunc(GL_ONE, GL_ONE); | |
277 | //glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
274 | 278 | //printf("Texture Built: %ix%i\n", w, h); |
275 | 279 | } |
276 | 280 | |
346 | 350 | initializeOpenGLFunctions(); |
347 | 351 | // Set up the rendering context, load shaders and other resources, etc.: |
348 | 352 | //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); | |
350 | 354 | |
351 | 355 | chkExtnsGL(); |
352 | 356 | //printf("GL Init!\n"); |
665 | 669 | } |
666 | 670 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
667 | 671 | |
672 | glEnable(GL_BLEND); | |
673 | glBlendFunc(GL_ONE, GL_ZERO); | |
674 | //glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
668 | 675 | |
669 | 676 | if ( textureType == GL_TEXTURE_RECTANGLE ) |
670 | 677 | { |
35 | 35 | #include <QWindow> |
36 | 36 | #include <QScreen> |
37 | 37 | #include <QHeaderView> |
38 | #include <QFileInfo> | |
38 | 39 | #include <QFileDialog> |
39 | 40 | #include <QMessageBox> |
40 | 41 | #include <QInputDialog> |
434 | 435 | void consoleWin_t::winActiveChanged(void) |
435 | 436 | { |
436 | 437 | QWidget *w; |
438 | bool muteWindow = false; | |
437 | 439 | |
438 | 440 | w = this->window(); |
439 | 441 | |
449 | 451 | { |
450 | 452 | if ( hdl->isActive() ) |
451 | 453 | { |
452 | FCEUD_MuteSoundOutput(false); | |
454 | muteWindow = false; | |
453 | 455 | } |
454 | 456 | else |
455 | 457 | { |
456 | FCEUD_MuteSoundOutput(true); | |
458 | muteWindow = true; | |
457 | 459 | } |
458 | 460 | } |
459 | 461 | } |
460 | 462 | } |
463 | FCEUD_MuteSoundWindow(muteWindow); | |
461 | 464 | } |
462 | 465 | |
463 | 466 | QSize consoleWin_t::calcRequiredSize(void) |
775 | 778 | { |
776 | 779 | QList<QUrl> urls = event->mimeData()->urls(); |
777 | 780 | |
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 | } | |
782 | 816 | } |
783 | 817 | } |
784 | 818 | |
849 | 883 | Hotkeys[HK_FRAME_ADVANCE].getShortcut()->setEnabled(false); |
850 | 884 | Hotkeys[HK_TURBO ].getShortcut()->setEnabled(false); |
851 | 885 | |
886 | connect( Hotkeys[ HK_VOLUME_MUTE ].getShortcut(), SIGNAL(activated()), this, SLOT(muteSoundVolume(void)) ); | |
852 | 887 | connect( Hotkeys[ HK_VOLUME_DOWN ].getShortcut(), SIGNAL(activated()), this, SLOT(decrSoundVolume(void)) ); |
853 | 888 | connect( Hotkeys[ HK_VOLUME_UP ].getShortcut(), SIGNAL(activated()), this, SLOT(incrSoundVolume(void)) ); |
854 | 889 | |
861 | 896 | connect( Hotkeys[ HK_TOGGLE_BG ].getShortcut(), SIGNAL(activated()), this, SLOT(toggleBackground(void)) ); |
862 | 897 | connect( Hotkeys[ HK_TOGGLE_FG ].getShortcut(), SIGNAL(activated()), this, SLOT(toggleForeground(void)) ); |
863 | 898 | 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)) ); | |
864 | 900 | |
865 | 901 | connect( Hotkeys[ HK_SAVE_STATE_0 ].getShortcut(), SIGNAL(activated()), this, SLOT(saveState0(void)) ); |
866 | 902 | connect( Hotkeys[ HK_SAVE_STATE_1 ].getShortcut(), SIGNAL(activated()), this, SLOT(saveState1(void)) ); |
892 | 928 | QActionGroup *group; |
893 | 929 | int useNativeMenuBar; |
894 | 930 | int customAutofireOnFrames, customAutofireOffFrames; |
895 | ColorMenuItem *bgColorItem; | |
896 | 931 | //QShortcut *shortcut; |
897 | 932 | |
898 | 933 | menubar = new consoleMenuBar(this); |
1252 | 1287 | |
1253 | 1288 | optMenu->addAction(act); |
1254 | 1289 | |
1290 | optMenu->addSeparator(); | |
1291 | ||
1255 | 1292 | // Options -> Video BG Color |
1256 | 1293 | fceuLoadConfigColor( "SDL.VideoBgColor", &videoBgColor ); |
1257 | 1294 | |
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 ); | |
1264 | 1316 | //----------------------------------------------------------------------- |
1265 | 1317 | // Emulation |
1266 | 1318 | |
1280 | 1332 | connect( Hotkeys[ HK_POWER ].getShortcut(), SIGNAL(activated()), this, SLOT(powerConsoleCB(void)) ); |
1281 | 1333 | |
1282 | 1334 | // Emulation -> Reset |
1283 | resetAct = new QAction(tr("&Reset"), this); | |
1335 | resetAct = new QAction(tr("Hard &Reset"), this); | |
1284 | 1336 | //resetAct->setShortcut( QKeySequence(tr("Ctrl+R"))); |
1285 | resetAct->setStatusTip(tr("Reset Console")); | |
1337 | resetAct->setStatusTip(tr("Hard Reset of Console")); | |
1286 | 1338 | resetAct->setIcon( style()->standardIcon( QStyle::SP_DialogResetButton ) ); |
1287 | 1339 | connect(resetAct, SIGNAL(triggered()), this, SLOT(consoleHardReset(void)) ); |
1288 | 1340 | |
1289 | 1341 | emuMenu->addAction(resetAct); |
1290 | 1342 | |
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)) ); | |
1293 | 1345 | |
1294 | 1346 | // Emulation -> Soft Reset |
1295 | 1347 | sresetAct = new QAction(tr("&Soft Reset"), this); |
1299 | 1351 | connect(sresetAct, SIGNAL(triggered()), this, SLOT(consoleSoftReset(void)) ); |
1300 | 1352 | |
1301 | 1353 | emuMenu->addAction(sresetAct); |
1354 | ||
1355 | Hotkeys[ HK_SOFT_RESET ].setAction( sresetAct ); | |
1356 | connect( Hotkeys[ HK_SOFT_RESET ].getShortcut(), SIGNAL(activated()), this, SLOT(consoleSoftReset(void)) ); | |
1302 | 1357 | |
1303 | 1358 | // Emulation -> Pause |
1304 | 1359 | pauseAct = new QAction(tr("&Pause"), this); |
1729 | 1784 | |
1730 | 1785 | debugMenu->addAction(ggEncodeAct); |
1731 | 1786 | |
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); | |
1734 | 1789 | //iNesEditAct->setShortcut( QKeySequence(tr("Shift+F7"))); |
1735 | iNesEditAct->setStatusTip(tr("Open iNES Header Editor")); | |
1790 | iNesEditAct->setStatusTip(tr("Open NES Header Editor")); | |
1736 | 1791 | connect(iNesEditAct, SIGNAL(triggered()), this, SLOT(openNesHeaderEditor(void)) ); |
1737 | 1792 | |
1738 | 1793 | debugMenu->addAction(iNesEditAct); |
2147 | 2202 | g_config->save(); |
2148 | 2203 | } |
2149 | 2204 | //--------------------------------------------------------------------------- |
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 | //--------------------------------------------------------------------------- | |
2150 | 2219 | void consoleWin_t::closeApp(void) |
2151 | 2220 | { |
2152 | 2221 | nes_shm->runEmulator = 0; |
2280 | 2349 | int ret, useNativeFileDialogVal; |
2281 | 2350 | QString filename; |
2282 | 2351 | std::string last; |
2283 | char dir[512]; | |
2284 | char *romDir; | |
2352 | std::string dir; | |
2353 | const char *romDir; | |
2285 | 2354 | QFileDialog dialog(this, tr("Open ROM File") ); |
2286 | 2355 | QList<QUrl> urls; |
2287 | 2356 | QDir d; |
2323 | 2392 | |
2324 | 2393 | g_config->getOption ("SDL.LastOpenFile", &last ); |
2325 | 2394 | |
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()) ); | |
2329 | 2398 | |
2330 | 2399 | // Check config option to use native file dialog or not |
2331 | 2400 | g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); |
2383 | 2452 | int ret, useNativeFileDialogVal; |
2384 | 2453 | QString filename; |
2385 | 2454 | std::string last; |
2386 | char dir[512]; | |
2387 | char *romDir; | |
2455 | std::string dir; | |
2456 | const char *romDir; | |
2388 | 2457 | QFileDialog dialog(this, tr("Load NSF File") ); |
2389 | 2458 | QList<QUrl> urls; |
2390 | 2459 | QDir d; |
2418 | 2487 | |
2419 | 2488 | getDirFromFile( last.c_str(), dir ); |
2420 | 2489 | |
2421 | dialog.setDirectory( tr(dir) ); | |
2490 | dialog.setDirectory( tr(dir.c_str()) ); | |
2422 | 2491 | |
2423 | 2492 | // Check config option to use native file dialog or not |
2424 | 2493 | g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); |
2457 | 2526 | int ret, useNativeFileDialogVal; |
2458 | 2527 | QString filename; |
2459 | 2528 | std::string last; |
2460 | char dir[512]; | |
2529 | std::string dir; | |
2461 | 2530 | const char *base; |
2462 | 2531 | QFileDialog dialog(this, tr("Load State From File") ); |
2463 | 2532 | QList<QUrl> urls; |
2502 | 2571 | |
2503 | 2572 | getDirFromFile( last.c_str(), dir ); |
2504 | 2573 | |
2505 | dialog.setDirectory( tr(dir) ); | |
2574 | dialog.setDirectory( tr(dir.c_str()) ); | |
2506 | 2575 | |
2507 | 2576 | // Check config option to use native file dialog or not |
2508 | 2577 | g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); |
2541 | 2610 | int ret, useNativeFileDialogVal; |
2542 | 2611 | QString filename; |
2543 | 2612 | std::string last; |
2544 | char dir[512]; | |
2613 | std::string dir; | |
2545 | 2614 | const char *base; |
2546 | 2615 | QFileDialog dialog(this, tr("Save State To File") ); |
2547 | 2616 | QList<QUrl> urls; |
2593 | 2662 | } |
2594 | 2663 | getDirFromFile( last.c_str(), dir ); |
2595 | 2664 | |
2596 | dialog.setDirectory( tr(dir) ); | |
2665 | dialog.setDirectory( tr(dir.c_str()) ); | |
2597 | 2666 | |
2598 | 2667 | // Check config option to use native file dialog or not |
2599 | 2668 | g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); |
3054 | 3123 | { |
3055 | 3124 | iNesHeaderEditor_t *win; |
3056 | 3125 | |
3057 | //printf("Open iNES Header Editor Window\n"); | |
3126 | //printf("Open NES Header Editor Window\n"); | |
3058 | 3127 | |
3059 | 3128 | win = new iNesHeaderEditor_t(this); |
3060 | 3129 | |
3170 | 3239 | void consoleWin_t::toggleFamKeyBrdEnable(void) |
3171 | 3240 | { |
3172 | 3241 | 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(); | |
3173 | 3256 | } |
3174 | 3257 | |
3175 | 3258 | void consoleWin_t::warnAmbiguousShortcut( QShortcut *shortcut) |
3327 | 3410 | int ret, useNativeFileDialogVal; |
3328 | 3411 | QString filename; |
3329 | 3412 | std::string last; |
3330 | char dir[512]; | |
3413 | std::string dir; | |
3331 | 3414 | QFileDialog dialog(this, tr("Open Game Genie ROM") ); |
3332 | 3415 | QList<QUrl> urls; |
3333 | 3416 | |
3348 | 3431 | |
3349 | 3432 | getDirFromFile( last.c_str(), dir ); |
3350 | 3433 | |
3351 | dialog.setDirectory( tr(dir) ); | |
3434 | dialog.setDirectory( tr(dir.c_str()) ); | |
3352 | 3435 | |
3353 | 3436 | // Check config option to use native file dialog or not |
3354 | 3437 | g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); |
3422 | 3505 | int ret, useNativeFileDialogVal; |
3423 | 3506 | QString filename; |
3424 | 3507 | std::string last; |
3425 | char dir[512]; | |
3508 | std::string dir; | |
3426 | 3509 | QFileDialog dialog(this, tr("Load FDS BIOS (disksys.rom)") ); |
3427 | 3510 | QList<QUrl> urls; |
3428 | 3511 | |
3441 | 3524 | |
3442 | 3525 | g_config->getOption ("SDL.LastOpenFile", &last ); |
3443 | 3526 | |
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()) ); | |
3447 | 3530 | |
3448 | 3531 | // Check config option to use native file dialog or not |
3449 | 3532 | g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); |
3556 | 3639 | if ( QDialog::Accepted == ret ) |
3557 | 3640 | { |
3558 | 3641 | frameAdvance_Delay = dialog.intValue(); |
3642 | ||
3643 | g_config->setOption("SDL.FrameAdvanceDelay", frameAdvance_Delay ); | |
3644 | g_config->save(); | |
3559 | 3645 | } |
3560 | 3646 | } |
3561 | 3647 | |
3653 | 3739 | g_config->setOption("SDL.AutofireCustomOffFrames" , autoFireOffFrames); |
3654 | 3740 | g_config->save(); |
3655 | 3741 | } |
3742 | } | |
3743 | ||
3744 | void consoleWin_t::muteSoundVolume(void) | |
3745 | { | |
3746 | FCEU_WRAPPER_LOCK(); | |
3747 | FCEUD_SoundToggle(); | |
3748 | FCEU_WRAPPER_UNLOCK(); | |
3656 | 3749 | } |
3657 | 3750 | |
3658 | 3751 | void consoleWin_t::incrSoundVolume(void) |
3948 | 4041 | if ( !FCEUI_WaveRecordRunning() ) |
3949 | 4042 | { |
3950 | 4043 | const char *romFile; |
3951 | char fileName[1024]; | |
4044 | std::string fileName; | |
3952 | 4045 | |
3953 | 4046 | romFile = getRomFile(); |
3954 | 4047 | |
3964 | 4057 | |
3965 | 4058 | if ( lastPath.size() > 0 ) |
3966 | 4059 | { |
3967 | strcpy( fileName, lastPath.c_str() ); | |
3968 | strcat( fileName, "/" ); | |
4060 | fileName.assign( lastPath ); | |
4061 | fileName.append( "/" ); | |
3969 | 4062 | } |
3970 | 4063 | else if ( baseDir ) |
3971 | 4064 | { |
3972 | strcpy( fileName, baseDir ); | |
3973 | strcat( fileName, "/wav/" ); | |
4065 | fileName.assign( baseDir ); | |
4066 | fileName.append( "/wav/" ); | |
3974 | 4067 | } |
3975 | 4068 | else |
3976 | 4069 | { |
3977 | fileName[0] = 0; | |
4070 | fileName.clear(); | |
3978 | 4071 | } |
3979 | strcat( fileName, base ); | |
3980 | strcat( fileName, ".wav"); | |
4072 | fileName.append( base ); | |
4073 | fileName.append(".wav"); | |
3981 | 4074 | //printf("WAV Filepath:'%s'\n", fileName ); |
3982 | 4075 | } |
3983 | 4076 | else |
3985 | 4078 | return; |
3986 | 4079 | } |
3987 | 4080 | FCEU_WRAPPER_LOCK(); |
3988 | FCEUI_BeginWaveRecord( fileName ); | |
4081 | FCEUI_BeginWaveRecord( fileName.c_str() ); | |
3989 | 4082 | FCEU_WRAPPER_UNLOCK(); |
3990 | 4083 | } |
3991 | 4084 | } |
3999 | 4092 | int ret, useNativeFileDialogVal; |
4000 | 4093 | QString filename; |
4001 | 4094 | std::string lastPath; |
4002 | //char dir[512]; | |
4003 | 4095 | const char *base, *rom; |
4004 | 4096 | QFileDialog dialog(this, tr("Save WAV Movie for Recording") ); |
4005 | 4097 | QList<QUrl> urls; |
4139 | 4231 | |
4140 | 4232 | void consoleWin_t::openOnlineDocs(void) |
4141 | 4233 | { |
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"); | |
4145 | 4237 | } |
4146 | 4238 | return; |
4147 | 4239 | } |
4720 | 4812 | consoleRecentRomAction::consoleRecentRomAction(QString desc, QWidget *parent) |
4721 | 4813 | : QAction( desc, parent ) |
4722 | 4814 | { |
4815 | QString txt; | |
4816 | QFileInfo fi(desc); | |
4817 | ||
4723 | 4818 | path = desc.toStdString(); |
4819 | ||
4820 | txt = fi.fileName(); | |
4821 | txt += QString("\t"); | |
4822 | txt += desc; | |
4823 | ||
4824 | setText( txt ); | |
4724 | 4825 | } |
4725 | 4826 | //---------------------------------------------------------------------------- |
4726 | 4827 | consoleRecentRomAction::~consoleRecentRomAction(void) |
26 | 26 | #include <QRecursiveMutex> |
27 | 27 | #endif |
28 | 28 | |
29 | #include "Qt/ColorMenu.h" | |
29 | 30 | #include "Qt/ConsoleViewerGL.h" |
30 | 31 | #include "Qt/ConsoleViewerSDL.h" |
31 | 32 | #include "Qt/GamePadConf.h" |
258 | 259 | |
259 | 260 | QTimer *gameTimer; |
260 | 261 | QColor videoBgColor; |
262 | ColorMenuItem *bgColorMenuItem; | |
261 | 263 | |
262 | 264 | std::string errorMsg; |
263 | 265 | bool errorMsgValid; |
402 | 404 | void stopMovie(void); |
403 | 405 | void playMovieFromBeginning(void); |
404 | 406 | void setCustomAutoFire(void); |
407 | void muteSoundVolume(void); | |
405 | 408 | void incrSoundVolume(void); |
406 | 409 | void decrSoundVolume(void); |
407 | 410 | void toggleLagCounterDisplay(void); |
414 | 417 | void toggleBackground(void); |
415 | 418 | void toggleForeground(void); |
416 | 419 | void toggleFamKeyBrdEnable(void); |
420 | void toggleGlobalCheatEnable(void); | |
417 | 421 | void saveState0(void); |
418 | 422 | void saveState1(void); |
419 | 423 | void saveState2(void); |
451 | 455 | void winActiveChanged(void); |
452 | 456 | void emuFrameFinish(void); |
453 | 457 | void toggleMenuAutoHide(bool); |
458 | void toggleUseBgPaletteForVideo(bool); | |
454 | 459 | void videoBgColorChanged( QColor &c ); |
455 | 460 | void loadRomRequestCB( QString s ); |
456 | 461 |
247 | 247 | //********************************************************************************* |
248 | 248 | int FamilyKeyboardWidget::getKeyAtPoint( QPoint p ) |
249 | 249 | { |
250 | for (int i=0; i<NUM_KEYS; i++) | |
250 | for (int i=0; i < static_cast<int>(NUM_KEYS); i++) | |
251 | 251 | { |
252 | 252 | if ( key[i].rect.contains(p) ) |
253 | 253 | { |
1028 | 1028 | //---------------------------------------------------------------------------- |
1029 | 1029 | int FKBConfigDialog::getButtonIndexFromName( const char *buttonName ) |
1030 | 1030 | { |
1031 | for (int j=0; j<FamilyKeyboardWidget::NUM_KEYS; j++) | |
1031 | for (int j=0; j < static_cast<int>(FamilyKeyboardWidget::NUM_KEYS); j++) | |
1032 | 1032 | { |
1033 | 1033 | if ( strcmp( buttonName, FamilyKeyBoardNames[j] ) == 0 ) |
1034 | 1034 | { |
432 | 432 | //---------------------------------------------------------------------------- |
433 | 433 | void GameGenieDialog_t::ListGGAddresses(void) |
434 | 434 | { |
435 | int i; //mbg merge 7/18/06 changed from int | |
436 | 435 | int a = -1; int v = -1; int c = -1; |
437 | 436 | QTreeWidgetItem *item; |
438 | 437 | char str[32]; |
459 | 458 | |
460 | 459 | if (a != -1 && v != -1) |
461 | 460 | { |
462 | for (i = 0; i < PRGsize[0]; i += 0x2000) | |
461 | for (unsigned int i = 0; i < PRGsize[0]; i += 0x2000) | |
463 | 462 | { |
464 | 463 | if (c == -1 || PRGptr[0][i + (a & 0x1FFF)] == c) |
465 | 464 | { |
603 | 603 | mapSel->addItem(tr("default"), 0); |
604 | 604 | n = 1; |
605 | 605 | |
606 | for (size_t i = 0; i < fileList.size(); i++) | |
606 | for (int i = 0; i < static_cast<int>(fileList.size()); i++) | |
607 | 607 | { |
608 | 608 | size_t suffixIdx; |
609 | 609 | std::string fileName = fileList[i].toStdString(); |
618 | 618 | if (fileName.compare("default") == 0) |
619 | 619 | continue; |
620 | 620 | |
621 | mapSel->addItem(tr(fileName.c_str()), (int)i + 1); | |
621 | mapSel->addItem(tr(fileName.c_str()), i + 1); | |
622 | 622 | |
623 | 623 | if (mapName.compare(fileName) == 0) |
624 | 624 | { |
368 | 368 | int ret, useNativeFileDialogVal; //, useCustom; |
369 | 369 | QString filename; |
370 | 370 | std::string last, iniPath; |
371 | char dir[512]; | |
372 | char exePath[512]; | |
371 | std::string dir; | |
372 | const char *exePath = nullptr; | |
373 | 373 | QFileDialog dialog(this, tr("Open Qt Stylesheet (QSS)")); |
374 | 374 | QList<QUrl> urls; |
375 | 375 | QDir d; |
376 | 376 | |
377 | fceuExecutablePath(exePath, sizeof(exePath)); | |
377 | exePath = fceuExecutablePath(); | |
378 | 378 | |
379 | 379 | //urls = dialog.sidebarUrls(); |
380 | 380 | urls << QUrl::fromLocalFile(QDir::rootPath()); |
420 | 420 | |
421 | 421 | getDirFromFile(last.c_str(), dir); |
422 | 422 | |
423 | dialog.setDirectory(tr(dir)); | |
423 | dialog.setDirectory(tr(dir.c_str())); | |
424 | 424 | |
425 | 425 | // Check config option to use native file dialog or not |
426 | 426 | g_config->getOption("SDL.UseNativeFileDialog", &useNativeFileDialogVal); |
472 | 472 | int ret, useNativeFileDialogVal; //, useCustom; |
473 | 473 | QString filename; |
474 | 474 | std::string last, iniPath; |
475 | char dir[512]; | |
476 | char exePath[512]; | |
475 | std::string dir; | |
476 | const char *exePath = nullptr; | |
477 | 477 | QFileDialog dialog(this, tr("Open Qt QPalette File (QPAL)")); |
478 | 478 | QList<QUrl> urls; |
479 | 479 | QDir d; |
480 | 480 | |
481 | fceuExecutablePath(exePath, sizeof(exePath)); | |
481 | exePath = fceuExecutablePath(); | |
482 | 482 | |
483 | 483 | //urls = dialog.sidebarUrls(); |
484 | 484 | urls << QUrl::fromLocalFile(QDir::rootPath()); |
524 | 524 | |
525 | 525 | getDirFromFile(last.c_str(), dir); |
526 | 526 | |
527 | dialog.setDirectory(tr(dir)); | |
527 | dialog.setDirectory(tr(dir.c_str())); | |
528 | 528 | |
529 | 529 | // Check config option to use native file dialog or not |
530 | 530 | g_config->getOption("SDL.UseNativeFileDialog", &useNativeFileDialogVal); |
752 | 752 | |
753 | 753 | if ( rccFilePath.size() == 0 ) |
754 | 754 | { |
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() ) ) | |
764 | 766 | { |
765 | 767 | //printf("Loaded RCC File: '%s'\n", tmpFile ); |
766 | 768 | rccFilePath.assign( tmpFile ); |
1175 | 1177 | int ret, useNativeFileDialogVal; //, useCustom; |
1176 | 1178 | QString filename; |
1177 | 1179 | std::string last, iniPath; |
1178 | char dir[512]; | |
1179 | char exePath[512]; | |
1180 | std::string dir; | |
1181 | const char *exePath = nullptr; | |
1180 | 1182 | QFileDialog dialog(this, tr("Save QPalette (qpal)")); |
1181 | 1183 | QList<QUrl> urls; |
1182 | 1184 | QDir d; |
1183 | 1185 | QPalette pal = this->palette(); |
1184 | 1186 | |
1185 | fceuExecutablePath(exePath, sizeof(exePath)); | |
1187 | exePath = fceuExecutablePath(); | |
1186 | 1188 | |
1187 | 1189 | //urls = dialog.sidebarUrls(); |
1188 | 1190 | urls << QUrl::fromLocalFile(QDir::rootPath()); |
1229 | 1231 | |
1230 | 1232 | getDirFromFile(last.c_str(), dir); |
1231 | 1233 | |
1232 | dialog.setDirectory(tr(dir)); | |
1234 | dialog.setDirectory(tr(dir.c_str())); | |
1233 | 1235 | |
1234 | 1236 | // Check config option to use native file dialog or not |
1235 | 1237 | g_config->getOption("SDL.UseNativeFileDialog", &useNativeFileDialogVal); |
1610 | 1612 | grid->addWidget( lbl, 2, 0 ); |
1611 | 1613 | |
1612 | 1614 | 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>"); | |
1614 | 1616 | lbl->setTextInteractionFlags(Qt::TextBrowserInteraction); |
1615 | 1617 | lbl->setOpenExternalLinks(false); |
1616 | 1618 | grid->addWidget( lbl, 2, 1 ); |
148 | 148 | int ret, useNativeFileDialogVal; |
149 | 149 | QString filename; |
150 | 150 | std::string last; |
151 | char dir[512]; | |
151 | std::string dir; | |
152 | 152 | QFileDialog dialog(this, tr("Open Help File") ); |
153 | 153 | QList<QUrl> urls; |
154 | 154 | //QDir d; |
176 | 176 | { |
177 | 177 | getDirFromFile( last.c_str(), dir ); |
178 | 178 | |
179 | dialog.setDirectory( tr(dir) ); | |
179 | dialog.setDirectory( tr(dir.c_str()) ); | |
180 | 180 | } |
181 | 181 | else |
182 | 182 | { |
321 | 321 | //---------------------------------------------------------------------------- |
322 | 322 | static int writeMem( int mode, unsigned int addr, int value ) |
323 | 323 | { |
324 | bool updateDebugger = false; | |
325 | ||
324 | 326 | value = value & 0x000000ff; |
325 | 327 | |
326 | 328 | switch ( mode ) |
338 | 340 | { |
339 | 341 | wfunc ((uint32) addr, |
340 | 342 | (uint8) (value & 0x000000ff)); |
343 | ||
344 | updateDebugger = true; | |
341 | 345 | } |
342 | 346 | } |
343 | 347 | else |
373 | 377 | { |
374 | 378 | if (addr < 16) |
375 | 379 | { |
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."); | |
377 | 381 | } |
378 | 382 | else if ( (addr >= 16) && (addr < PRGsize[0]+16) ) |
379 | 383 | { |
383 | 387 | { |
384 | 388 | *(uint8 *)(GetNesCHRPointer(addr-16-PRGsize[0])) = value; |
385 | 389 | } |
390 | updateDebugger = true; | |
386 | 391 | } |
387 | 392 | break; |
388 | 393 | } |
389 | 394 | |
390 | 395 | hexEditorRequestUpdateAll(); |
391 | 396 | |
392 | return 0; | |
397 | if ( updateDebugger ) | |
398 | { | |
399 | if (debuggerWindowIsOpen()) | |
400 | { | |
401 | updateAllDebuggerWindows(); | |
402 | } | |
403 | } | |
404 | ||
405 | return 0; | |
393 | 406 | } |
394 | 407 | //---------------------------------------------------------------------------- |
395 | 408 | |
396 | 409 | static int convToXchar( int i ) |
397 | 410 | { |
398 | int c = 0; | |
411 | int c = 0; | |
399 | 412 | |
400 | 413 | if ( (i >= 0) && (i < 10) ) |
401 | 414 | { |
402 | c = i + '0'; | |
415 | c = i + '0'; | |
403 | 416 | } |
404 | 417 | else if ( i < 16 ) |
405 | 418 | { |
719 | 732 | return -1; |
720 | 733 | } |
721 | 734 | |
722 | for (int i=0; i<v.size(); i++) | |
735 | for (size_t i=0; i<v.size(); i++) | |
723 | 736 | { |
724 | 737 | fprintf( fp, "%s:%08X:%s\n", |
725 | 738 | memViewNames[ v[i]->mode ], v[i]->addr, v[i]->desc ); |
2441 | 2454 | return -1; |
2442 | 2455 | } |
2443 | 2456 | 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()) ) | |
2447 | 2460 | { |
2448 | 2461 | match = 0; break; |
2449 | 2462 | } |
3242 | 3255 | } |
3243 | 3256 | } |
3244 | 3257 | //---------------------------------------------------------------------------- |
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) | |
3246 | 3259 | { |
3247 | 3260 | return ((QHexEdit*)data)->FreezeRam( name, a, v, compare, s, type ); |
3248 | 3261 | } |
3259 | 3272 | // printf("$%04X:%02X %i: %s\n", a, v, s, name ); |
3260 | 3273 | //} |
3261 | 3274 | |
3262 | if ( a == frzRamAddr ) | |
3275 | if ( a == static_cast<uint32_t>(frzRamAddr) ) | |
3263 | 3276 | { |
3264 | 3277 | switch ( frzRamMode ) |
3265 | 3278 | { |
4204 | 4217 | |
4205 | 4218 | win->show(); |
4206 | 4219 | } |
4220 | else | |
4221 | { | |
4222 | win->activateWindow(); | |
4223 | win->raise(); | |
4224 | win->setFocus(); | |
4225 | } | |
4207 | 4226 | |
4208 | 4227 | win->editor->setMode( mode ); |
4209 | 4228 | win->editor->setAddr( addr ); |
527 | 527 | |
528 | 528 | if (romFile != NULL) |
529 | 529 | { |
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())); | |
537 | 537 | } |
538 | 538 | |
539 | 539 | dialog.setDirectory(tr(path.c_str())); |
278 | 278 | int ret, useNativeFileDialogVal; |
279 | 279 | QString filename; |
280 | 280 | 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; | |
284 | 284 | QFileDialog dialog(this, tr("Open LUA Script")); |
285 | 285 | QList<QUrl> urls; |
286 | 286 | QDir d; |
287 | 287 | |
288 | fceuExecutablePath(exePath, sizeof(exePath)); | |
288 | exePath = fceuExecutablePath(); | |
289 | 289 | |
290 | 290 | //urls = dialog.sidebarUrls(); |
291 | 291 | urls << QUrl::fromLocalFile(QDir::rootPath()); |
380 | 380 | |
381 | 381 | getDirFromFile(last.c_str(), dir); |
382 | 382 | |
383 | dialog.setDirectory(tr(dir)); | |
383 | dialog.setDirectory(tr(dir.c_str())); | |
384 | 384 | |
385 | 385 | // Check config option to use native file dialog or not |
386 | 386 | g_config->getOption("SDL.UseNativeFileDialog", &useNativeFileDialogVal); |
505 | 505 | updateLuaDisplay = true; |
506 | 506 | } |
507 | 507 | //---------------------------------------------------- |
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, ...) | |
513 | 509 | { |
514 | 510 | int retval; |
515 | 511 | va_list args; |
53 | 53 | }; |
54 | 54 | |
55 | 55 | // 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 ); | |
68 | 57 | |
69 | 58 | void PrintToWindowConsole(intptr_t hDlgAsInt, const char *str); |
70 | 59 |
49 | 49 | QVBoxLayout *vbox1, *vbox2; |
50 | 50 | QPushButton *closeButton; |
51 | 51 | std::vector <std::string> aviDriverList; |
52 | int aviDriver; | |
52 | int aviDriver=0; | |
53 | 53 | |
54 | 54 | setWindowTitle("Movie Options"); |
55 | 55 | |
145 | 145 | break; |
146 | 146 | } |
147 | 147 | |
148 | if ( i == aviDriver ) | |
148 | if ( i == static_cast<size_t>(aviDriver) ) | |
149 | 149 | { |
150 | 150 | aviBackend->setCurrentIndex(i); |
151 | 151 | aviPageStack->setCurrentIndex(i); |
64 | 64 | movSelBox = new QComboBox(); |
65 | 65 | movBrowseBtn = new QPushButton(tr("Browse")); |
66 | 66 | |
67 | movSelBox->setMaximumWidth(512); | |
68 | ||
67 | 69 | hbox->addWidget(lbl, 1); |
68 | 70 | hbox->addWidget(movSelBox, 100); |
69 | 71 | hbox->addWidget(movBrowseBtn, 1); |
415 | 417 | std::string path, last; |
416 | 418 | const char *romFile; |
417 | 419 | const char *baseDir = FCEUI_GetBaseDirectory(); |
420 | std::string lastDir; | |
418 | 421 | char md5[256]; |
419 | char dir[512], base[256]; | |
420 | 422 | |
421 | 423 | md5[0] = 0; |
422 | 424 | |
433 | 435 | |
434 | 436 | if (romFile != NULL) |
435 | 437 | { |
436 | parseFilepath(romFile, dir, base); | |
437 | ||
438 | path = std::string(dir); | |
438 | std::string dir; | |
439 | ||
440 | parseFilepath(romFile, &dir); | |
441 | ||
442 | path = dir; | |
439 | 443 | |
440 | 444 | scanDirectory(path.c_str(), md5); |
441 | 445 | } |
442 | 446 | |
443 | 447 | g_config->getOption("SDL.LastOpenMovie", &last); |
444 | 448 | |
445 | getDirFromFile(last.c_str(), dir); | |
446 | ||
447 | scanDirectory(dir, md5); | |
449 | getDirFromFile(last.c_str(), lastDir); | |
450 | ||
451 | scanDirectory(lastDir.c_str(), md5); | |
448 | 452 | } |
449 | 453 | //---------------------------------------------------------------------------- |
450 | 454 | void MoviePlayDialog_t::playMovie(void) |
494 | 498 | int ret, useNativeFileDialogVal; |
495 | 499 | QString filename; |
496 | 500 | std::string last; |
497 | char dir[512]; | |
501 | std::string dir; | |
498 | 502 | char md5Match = 0; |
499 | 503 | QFileDialog dialog(this, tr("Open FM2 Movie")); |
500 | 504 | |
510 | 514 | |
511 | 515 | getDirFromFile(last.c_str(), dir); |
512 | 516 | |
513 | dialog.setDirectory(tr(dir)); | |
517 | dialog.setDirectory(tr(dir.c_str())); | |
514 | 518 | |
515 | 519 | // Check config option to use native file dialog or not |
516 | 520 | g_config->getOption("SDL.UseNativeFileDialog", &useNativeFileDialogVal); |
178 | 178 | int ret, useNativeFileDialogVal; |
179 | 179 | QString filename; |
180 | 180 | std::string last; |
181 | char dir[512]; | |
181 | std::string dir; | |
182 | 182 | const char *base; |
183 | 183 | QFileDialog dialog(this, tr("Load State From File") ); |
184 | 184 | QList<QUrl> urls; |
223 | 223 | |
224 | 224 | getDirFromFile( last.c_str(), dir ); |
225 | 225 | |
226 | dialog.setDirectory( tr(dir) ); | |
226 | dialog.setDirectory( tr(dir.c_str()) ); | |
227 | 227 | |
228 | 228 | // Check config option to use native file dialog or not |
229 | 229 | g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); |
315 | 315 | int ret, useNativeFileDialogVal; |
316 | 316 | QString filename; |
317 | 317 | std::string last; |
318 | char dir[512]; | |
318 | std::string dir; | |
319 | 319 | QFileDialog dialog(this, tr("Save FM2 Movie for Recording") ); |
320 | 320 | |
321 | 321 | dialog.setFileMode(QFileDialog::AnyFile); |
331 | 331 | |
332 | 332 | getDirFromFile( last.c_str(), dir ); |
333 | 333 | |
334 | dialog.setDirectory( tr(dir) ); | |
334 | dialog.setDirectory( tr(dir.c_str()) ); | |
335 | 335 | |
336 | 336 | // Check config option to use native file dialog or not |
337 | 337 | g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); |
493 | 493 | int ret, useNativeFileDialogVal; |
494 | 494 | QString filename; |
495 | 495 | std::string last, iniPath; |
496 | char dir[512]; | |
497 | char exePath[512]; | |
496 | std::string dir; | |
497 | const char *exePath = nullptr; | |
498 | 498 | QFileDialog dialog(this, tr("Open NES Palette")); |
499 | 499 | QList<QUrl> urls; |
500 | 500 | QDir d; |
501 | 501 | |
502 | fceuExecutablePath(exePath, sizeof(exePath)); | |
502 | exePath = fceuExecutablePath(); | |
503 | 503 | |
504 | 504 | //urls = dialog.sidebarUrls(); |
505 | 505 | urls << QUrl::fromLocalFile(QDir::rootPath()); |
576 | 576 | |
577 | 577 | getDirFromFile(last.c_str(), dir); |
578 | 578 | |
579 | dialog.setDirectory(tr(dir)); | |
579 | dialog.setDirectory(tr(dir.c_str())); | |
580 | 580 | |
581 | 581 | // Check config option to use native file dialog or not |
582 | 582 | g_config->getOption("SDL.UseNativeFileDialog", &useNativeFileDialogVal); |
313 | 313 | { |
314 | 314 | int ret, useNativeFileDialogVal; |
315 | 315 | QString filename; |
316 | char dir[512]; | |
317 | char exePath[512]; | |
316 | std::string dir; | |
317 | const char *exePath = nullptr; | |
318 | 318 | std::string last, iniPath; |
319 | 319 | QFileDialog dialog(this, tr("Open Palette From File") ); |
320 | 320 | QList<QUrl> urls; |
321 | 321 | QDir d; |
322 | 322 | |
323 | fceuExecutablePath( exePath, sizeof(exePath) ); | |
323 | exePath = fceuExecutablePath(); | |
324 | 324 | |
325 | 325 | //urls = dialog.sidebarUrls(); |
326 | 326 | urls << QUrl::fromLocalFile( QDir::rootPath() ); |
402 | 402 | } |
403 | 403 | getDirFromFile( last.c_str(), dir ); |
404 | 404 | |
405 | dialog.setDirectory( tr(dir) ); | |
405 | dialog.setDirectory( tr(dir.c_str()) ); | |
406 | 406 | |
407 | 407 | // Check config option to use native file dialog or not |
408 | 408 | g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); |
1777 | 1777 | selAddr = -1; |
1778 | 1778 | selLine++; |
1779 | 1779 | |
1780 | if (selLine >= actvSrchList.size()) | |
1780 | if ( static_cast<size_t>(selLine) >= actvSrchList.size()) | |
1781 | 1781 | { |
1782 | 1782 | selLine = actvSrchList.size() - 1; |
1783 | 1783 | } |
543 | 543 | |
544 | 544 | if ( romFile != NULL ) |
545 | 545 | { |
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()) ); | |
555 | 555 | } |
556 | 556 | |
557 | 557 | // Check config option to use native file dialog or not |
603 | 603 | |
604 | 604 | if ( romFile != NULL ) |
605 | 605 | { |
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()) ); | |
615 | 615 | } |
616 | 616 | |
617 | 617 | // Check config option to use native file dialog or not |
650 | 650 | |
651 | 651 | if ( saveFileName.size() > 0 ) |
652 | 652 | { |
653 | char file[512]; | |
654 | ||
655 | strcpy( file, saveFileName.c_str() ); | |
656 | ||
657 | saveWatchFile( file ); | |
653 | saveWatchFile( saveFileName.c_str() ); | |
658 | 654 | } |
659 | 655 | else |
660 | 656 | { |
686 | 682 | |
687 | 683 | if ( romFile != NULL ) |
688 | 684 | { |
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()) ); | |
698 | 694 | } |
699 | 695 | |
700 | 696 | // Check config option to use native file dialog or not |
844 | 840 | okButton->setDefault(true); |
845 | 841 | |
846 | 842 | 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)) ); | |
848 | 844 | |
849 | 845 | if ( rw != NULL ) |
850 | 846 | { |
874 | 870 | } |
875 | 871 | else |
876 | 872 | { |
877 | signedTypeBtn->setChecked( rw->type == 's' ); | |
878 | unsignedTypeBtn->setChecked( rw->type != 's' ); | |
873 | signedTypeBtn->setChecked( rw->type == 's' ); | |
874 | unsignedTypeBtn->setChecked( rw->type != 's' ); | |
879 | 875 | dataSize1Btn->setChecked( rw->size == 1 ); |
880 | 876 | dataSize2Btn->setChecked( rw->size == 2 ); |
881 | 877 | dataSize4Btn->setChecked( rw->size == 4 ); |
883 | 879 | } |
884 | 880 | else |
885 | 881 | { |
886 | signedTypeBtn->setChecked( true ); | |
887 | unsignedTypeBtn->setChecked( false ); | |
882 | signedTypeBtn->setChecked( true ); | |
883 | unsignedTypeBtn->setChecked( false ); | |
888 | 884 | dataSize1Btn->setChecked( true ); |
889 | 885 | dataSize2Btn->setChecked( false ); |
890 | 886 | dataSize4Btn->setChecked( false ); |
914 | 910 | if ( (rw == NULL) || mode ) |
915 | 911 | { |
916 | 912 | ramWatchList.add_entry( notesEntry->text().toStdString().c_str(), |
917 | addr, unsignedTypeBtn->isChecked(), size, isSep); | |
913 | addr, unsignedTypeBtn->isChecked() ? 'u' : 's', size, isSep); | |
918 | 914 | } |
919 | 915 | else |
920 | 916 | { |
34 | 34 | #include "Qt/fceuWrapper.h" |
35 | 35 | #include "Qt/SymbolicDebug.h" |
36 | 36 | #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 | ||
734 | 40 | //-------------------------------------------------------------- |
735 | 41 | debugSymbol_t *replaceSymbols( int flags, int addr, char *str ) |
736 | 42 | { |
756 | 62 | { |
757 | 63 | if ( flags & ASM_DEBUG_REPLACE ) |
758 | 64 | { |
759 | strcpy( str, sym->name.c_str() ); | |
65 | strcpy( str, sym->name().c_str() ); | |
760 | 66 | } |
761 | 67 | else |
762 | 68 | { |
768 | 74 | { |
769 | 75 | sprintf( str, "$%04X ", addr ); |
770 | 76 | } |
771 | strcat( str, sym->name.c_str() ); | |
77 | strcat( str, sym->name().c_str() ); | |
772 | 78 | } |
773 | 79 | } |
774 | 80 | else |
1335 | 641 | hbox->addWidget( okButton ); |
1336 | 642 | |
1337 | 643 | 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)) ); | |
1339 | 645 | |
1340 | 646 | deleteBox->setEnabled( false ); |
1341 | 647 | okButton->setDefault(true); |
1342 | 648 | |
1343 | 649 | if ( sym != NULL ) |
1344 | 650 | { |
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()) ); | |
1347 | 653 | } |
1348 | 654 | |
1349 | 655 | setLayout( mainLayout ); |
1361 | 667 | //-------------------------------------------------------------- |
1362 | 668 | void SymbolEditWindow::closeEvent(QCloseEvent *event) |
1363 | 669 | { |
1364 | //printf("Symbolic Debug Close Window Event\n"); | |
1365 | done(0); | |
670 | //printf("Symbolic Debug Close Window Event\n"); | |
671 | done(0); | |
1366 | 672 | deleteLater(); |
1367 | event->accept(); | |
673 | event->accept(); | |
1368 | 674 | } |
1369 | 675 | //-------------------------------------------------------------- |
1370 | 676 | void SymbolEditWindow::closeWindow(void) |
1371 | 677 | { |
1372 | //printf("Close Window\n"); | |
1373 | done(0); | |
678 | //printf("Close Window\n"); | |
679 | done(0); | |
1374 | 680 | deleteLater(); |
1375 | 681 | } |
1376 | 682 | //-------------------------------------------------------------- |
1414 | 720 | //-------------------------------------------------------------- |
1415 | 721 | void SymbolEditWindow::setAddr( int addrIn ) |
1416 | 722 | { |
1417 | char stmp[512]; | |
723 | char stmp[64]; | |
724 | std::string filename; | |
725 | size_t size; | |
1418 | 726 | |
1419 | 727 | addr = addrIn; |
1420 | 728 | |
1434 | 742 | } |
1435 | 743 | } |
1436 | 744 | |
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) ); | |
1441 | 755 | } |
1442 | 756 | //-------------------------------------------------------------- |
1443 | 757 | void SymbolEditWindow::setBank( int bankIn ) |
1451 | 765 | |
1452 | 766 | if ( sym != NULL ) |
1453 | 767 | { |
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()) ); | |
1456 | 770 | deleteBox->setEnabled( true ); |
1457 | 771 | |
1458 | 772 | determineArrayStart(); |
1501 | 815 | |
1502 | 816 | if ( deleteBox->isChecked() ) |
1503 | 817 | { |
1504 | if ( sym != NULL ) | |
818 | if ( sym != nullptr ) | |
1505 | 819 | { |
1506 | 820 | debugSymbolTable.deleteSymbolAtBankOffset( b, a ); |
1507 | 821 | } |
1508 | 822 | } |
1509 | 823 | else |
1510 | 824 | { |
1511 | if ( sym == NULL ) | |
825 | if ( sym == nullptr ) | |
1512 | 826 | { |
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 | } | |
1519 | 837 | isNew = true; |
1520 | 838 | } |
1521 | sym->ofs = a; | |
839 | sym->setOffset(a); | |
1522 | 840 | |
1523 | 841 | if ( (i == 0) || isNew || arrayNameOverWrite->isChecked() ) |
1524 | 842 | { |
1528 | 846 | { |
1529 | 847 | if ( isNew || arrayCommentOverWrite->isChecked() || (i == 0) ) |
1530 | 848 | { |
1531 | sym->comment = commentEntry->toPlainText().toStdString(); | |
849 | sym->commentAssign( commentEntry->toPlainText().toStdString() ); | |
1532 | 850 | } |
1533 | 851 | } |
1534 | 852 | sym->trimTrailingSpaces(); |
1546 | 864 | } |
1547 | 865 | else if ( sym == NULL ) |
1548 | 866 | { |
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 | } | |
1562 | 891 | } |
1563 | 892 | debugSymbolTable.save(); // Save table to disk immediately after an add, edit, or delete |
1564 | 893 | FCEU_WRAPPER_UNLOCK(); |
1666 | 995 | } |
1667 | 996 | |
1668 | 997 | // 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 | //-------------------------------------------------------------- |
3 | 3 | #define __SYMBOLIC_DEBUG_H__ |
4 | 4 | |
5 | 5 | #include <string> |
6 | #include <list> | |
7 | #include <map> | |
8 | 6 | |
9 | 7 | #include <QWidget> |
10 | 8 | #include <QDialog> |
23 | 21 | #include <QLineEdit> |
24 | 22 | #include <QPlainTextEdit> |
25 | 23 | |
26 | struct debugSymbol_t | |
27 | { | |
28 | int ofs; | |
29 | std::string name; | |
30 | std::string comment; | |
24 | #include "../../debugsymboltable.h" | |
31 | 25 | |
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; | |
125 | 26 | |
126 | 27 | class SymbolEditWindow : public QDialog |
127 | 28 | { |
177 | 78 | }; |
178 | 79 | |
179 | 80 | |
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); | |
182 | 83 | |
183 | 84 | #define ASM_DEBUG_SYMS 0x0001 |
184 | 85 | #define ASM_DEBUG_REGS 0x0002 |
931 | 931 | actGroup->addAction(act); |
932 | 932 | patternMenu->addAction(act); |
933 | 933 | |
934 | act->setChecked( taseditorConfig.currentPattern == i ); | |
934 | act->setChecked( static_cast<size_t>(taseditorConfig.currentPattern) == i ); | |
935 | 935 | } |
936 | 936 | |
937 | 937 | // Help |
6387 | 6387 | |
6388 | 6388 | lineNum = lineOffset + row; |
6389 | 6389 | |
6390 | if ( lineNum >= currMovieData.records.size() ) | |
6390 | if ( static_cast<size_t>(lineNum) >= currMovieData.records.size() ) | |
6391 | 6391 | { |
6392 | 6392 | break; |
6393 | 6393 | } |
7304 | 7304 | TasRecentProjectAction::TasRecentProjectAction(QString desc, QWidget *parent) |
7305 | 7305 | : QAction( desc, parent ) |
7306 | 7306 | { |
7307 | QString txt; | |
7308 | QFileInfo fi(desc); | |
7309 | ||
7307 | 7310 | path = desc.toStdString(); |
7311 | ||
7312 | txt = fi.fileName(); | |
7313 | txt += QString("\t"); | |
7314 | txt += desc; | |
7315 | ||
7316 | setText( txt ); | |
7308 | 7317 | } |
7309 | 7318 | //---------------------------------------------------------------------------- |
7310 | 7319 | TasRecentProjectAction::~TasRecentProjectAction(void) |
358 | 358 | // returns true if couldn't load |
359 | 359 | bool GREENZONE::load(EMUFILE *is, unsigned int offset) |
360 | 360 | { |
361 | int frame = 0, prev_frame = -1, size = 0; | |
361 | int frame = 0, prev_frame = -1; | |
362 | unsigned int size = 0; | |
362 | 363 | int last_tick = -1; |
363 | 364 | char save_id[GREENZONE_ID_LEN]; |
364 | 365 | |
374 | 375 | return false; |
375 | 376 | } |
376 | 377 | // 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; | |
378 | 379 | if (!strcmp(greenzone_skipsave_id, save_id)) |
379 | 380 | { |
380 | 381 | // string says to skip loading Greenzone |
418 | 419 | // read LagLog |
419 | 420 | lagLog.load(is); |
420 | 421 | // read size |
421 | if (read32le(&size, is) && size >= 0 && size <= currMovieData.getNumRecords()) | |
422 | if (read32le(&size, is) && size <= static_cast<unsigned int>(currMovieData.getNumRecords())) | |
422 | 423 | { |
423 | 424 | greenzoneSize = size; |
424 | 425 | savestates.resize(greenzoneSize); |
460 | 461 | if ((int)savestates.size() <= frame) |
461 | 462 | savestates.resize(frame + 1); |
462 | 463 | 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; | |
464 | 465 | prev_frame = frame; // successfully read one Greenzone frame info |
465 | 466 | } |
466 | 467 | } |
179 | 179 | inputType = tmp; |
180 | 180 | // read data |
181 | 181 | alreadyCompressed = true; |
182 | int comprlen; | |
182 | unsigned int comprlen; | |
183 | 183 | uLongf destlen; |
184 | 184 | // read and uncompress joysticks data |
185 | 185 | destlen = size * BYTES_PER_JOYSTICK * joysticksPerFrame[inputType]; |
186 | 186 | joysticks.resize(destlen); |
187 | 187 | // read size |
188 | 188 | if (!read32le(&comprlen, is)) return true; |
189 | if (comprlen <= 0) return true; | |
189 | if (comprlen == 0) return true; | |
190 | 190 | compressedJoysticks.resize(comprlen); |
191 | 191 | if (is->fread(&compressedJoysticks[0], comprlen) != comprlen) return true; |
192 | 192 | int e = uncompress(&joysticks[0], &destlen, &compressedJoysticks[0], comprlen); |
211 | 211 | hotChanges.resize(destlen); |
212 | 212 | // read size |
213 | 213 | if (!read32le(&comprlen, is)) return true; |
214 | if (comprlen <= 0) return true; | |
214 | if (comprlen == 0) return true; | |
215 | 215 | compressedHotChanges.resize(comprlen); |
216 | 216 | if (is->fread(&compressedHotChanges[0], comprlen) != comprlen) return true; |
217 | 217 | e = uncompress(&hotChanges[0], &destlen, &compressedHotChanges[0], comprlen); |
221 | 221 | } |
222 | 222 | bool INPUTLOG::skipLoad(EMUFILE *is) |
223 | 223 | { |
224 | int tmp; | |
224 | unsigned int tmp; | |
225 | 225 | uint8 tmp1; |
226 | 226 | // skip vars |
227 | 227 | if (is->fseek(sizeof(int) + // size |
32 | 32 | |
33 | 33 | void LAGLOG::compressData(void) |
34 | 34 | { |
35 | int len = lagLog.size() * sizeof(uint8); | |
35 | unsigned int len = lagLog.size() * sizeof(uint8); | |
36 | 36 | if (len) |
37 | 37 | { |
38 | 38 | uLongf comprlen = (len>>9)+12 + len; |
39 | 39 | compressedLagLog.resize(comprlen, LAGGED_UNKNOWN); |
40 | 40 | compress(&compressedLagLog[0], &comprlen, (uint8*)&lagLog[0], len); |
41 | 41 | compressedLagLog.resize(comprlen); |
42 | } else | |
42 | } | |
43 | else | |
43 | 44 | { |
44 | 45 | // LagLog can even be empty |
45 | 46 | compressedLagLog.resize(0); |
58 | 59 | void LAGLOG::save(EMUFILE *os) |
59 | 60 | { |
60 | 61 | // write size |
61 | int size = lagLog.size(); | |
62 | unsigned int size = lagLog.size(); | |
62 | 63 | write32le(size, os); |
63 | 64 | if (size) |
64 | 65 | { |
72 | 73 | // returns true if couldn't load |
73 | 74 | bool LAGLOG::load(EMUFILE *is) |
74 | 75 | { |
75 | int size; | |
76 | unsigned int size; | |
76 | 77 | if (read32le(&size, is)) |
77 | 78 | { |
78 | 79 | alreadyCompressed = true; |
80 | 81 | if (size) |
81 | 82 | { |
82 | 83 | // read and uncompress array |
83 | int comprlen; | |
84 | unsigned int comprlen; | |
84 | 85 | uLongf destlen = size * sizeof(int); |
85 | 86 | if (!read32le(&comprlen, is)) return true; |
86 | if (comprlen <= 0) return true; | |
87 | if (comprlen == 0) return true; | |
87 | 88 | compressedLagLog.resize(comprlen); |
88 | 89 | if (is->fread(&compressedLagLog[0], comprlen) != comprlen) return true; |
89 | 90 | int e = uncompress((uint8*)&lagLog[0], &destlen, &compressedLagLog[0], comprlen); |
90 | 91 | if (e != Z_OK && e != Z_BUF_ERROR) return true; |
91 | } else | |
92 | } | |
93 | else | |
92 | 94 | { |
93 | 95 | compressedLagLog.resize(0); |
94 | 96 | } |
99 | 101 | } |
100 | 102 | bool LAGLOG::skipLoad(EMUFILE *is) |
101 | 103 | { |
102 | int size; | |
104 | unsigned int size; | |
103 | 105 | if (read32le(&size, is)) |
104 | 106 | { |
105 | 107 | if (size) |
116 | 118 | // ------------------------------------------------------------------------------------------------- |
117 | 119 | void LAGLOG::invalidateFromFrame(int frame) |
118 | 120 | { |
119 | if (frame >= 0 && frame < (int)lagLog.size()) | |
121 | if (frame >= 0 && static_cast<size_t>(frame) < lagLog.size()) | |
120 | 122 | { |
121 | 123 | lagLog.resize(frame); |
122 | 124 | alreadyCompressed = false; |
125 | 127 | |
126 | 128 | void LAGLOG::setLagInfo(int frame, bool lagFlag) |
127 | 129 | { |
128 | if ((int)lagLog.size() <= frame) | |
130 | if (lagLog.size() <= static_cast<size_t>(frame)) | |
129 | 131 | lagLog.resize(frame + 1, LAGGED_UNKNOWN); |
130 | 132 | |
131 | 133 | if (lagFlag) |
137 | 139 | } |
138 | 140 | void LAGLOG::eraseFrame(int frame, int numFrames) |
139 | 141 | { |
140 | if (frame < (int)lagLog.size()) | |
142 | if ( static_cast<size_t>(frame) < lagLog.size()) | |
141 | 143 | { |
142 | 144 | if (numFrames == 1) |
143 | 145 | { |
144 | 146 | // erase 1 frame |
145 | 147 | lagLog.erase(lagLog.begin() + frame); |
146 | 148 | alreadyCompressed = false; |
147 | } else if (numFrames > 1) | |
149 | } | |
150 | else if (numFrames > 1) | |
148 | 151 | { |
149 | 152 | // 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; | |
152 | 155 | lagLog.erase(lagLog.begin() + frame, lagLog.begin() + (frame + numFrames)); |
153 | 156 | alreadyCompressed = false; |
154 | 157 | } |
156 | 159 | } |
157 | 160 | void LAGLOG::insertFrame(int frame, bool lagFlag, int numFrames) |
158 | 161 | { |
159 | if (frame < (int)lagLog.size()) | |
162 | if ( static_cast<size_t>(frame) < lagLog.size()) | |
160 | 163 | { |
161 | 164 | // insert |
162 | 165 | lagLog.insert(lagLog.begin() + frame, numFrames, (lagFlag) ? LAGGED_YES : LAGGED_NO); |
163 | } else | |
166 | } | |
167 | else | |
164 | 168 | { |
165 | 169 | // append |
166 | 170 | lagLog.resize(frame + 1, LAGGED_UNKNOWN); |
179 | 183 | } |
180 | 184 | int LAGLOG::getLagInfoAtFrame(int frame) |
181 | 185 | { |
182 | if (frame < (int)lagLog.size()) | |
186 | if (static_cast<size_t>(frame) < lagLog.size()) | |
183 | 187 | return lagLog[frame]; |
184 | 188 | else |
185 | 189 | return LAGGED_UNKNOWN; |
26 | 26 | void MARKERS::save(EMUFILE *os) |
27 | 27 | { |
28 | 28 | // write size |
29 | int size = markersArray.size(); | |
30 | int len; | |
29 | uint32_t size = markersArray.size(); | |
31 | 30 | write32le(size, os); |
32 | 31 | // write array |
33 | 32 | if (!alreadyCompressed) |
37 | 36 | // write notes |
38 | 37 | size = notes.size(); |
39 | 38 | write32le(size, os); |
40 | for (int i = 0; i < size; ++i) | |
39 | for (unsigned int i = 0; i < size; ++i) | |
41 | 40 | { |
42 | len = notes[i].length() + 1; | |
41 | uint32_t len = notes[i].length() + 1; | |
43 | 42 | if (len > MAX_NOTE_LEN) len = MAX_NOTE_LEN; |
44 | 43 | write32le(len, os); |
45 | 44 | os->fwrite(notes[i].c_str(), len); |
48 | 47 | // returns true if couldn't load |
49 | 48 | bool MARKERS::load(EMUFILE *is) |
50 | 49 | { |
51 | int size; | |
50 | uint32_t size=0; | |
52 | 51 | if (read32le(&size, is)) |
53 | 52 | { |
54 | 53 | markersArray.resize(size); |
55 | 54 | // read and uncompress array |
56 | 55 | alreadyCompressed = true; |
57 | int comprlen, len; | |
56 | uint32_t comprlen, len; | |
58 | 57 | uLongf destlen = size * sizeof(int); |
59 | 58 | if (!read32le(&comprlen, is)) return true; |
60 | 59 | if (comprlen <= 0) return true; |
63 | 62 | int e = uncompress((uint8*)&markersArray[0], &destlen, &compressedMarkersArray[0], comprlen); |
64 | 63 | if (e != Z_OK && e != Z_BUF_ERROR) return true; |
65 | 64 | // read notes |
66 | if (read32le(&size, is) && size >= 0) | |
65 | if (read32le(&size, is)) | |
67 | 66 | { |
68 | 67 | notes.resize(size); |
69 | 68 | char temp_str[MAX_NOTE_LEN]; |
70 | for (int i = 0; i < size; ++i) | |
69 | for (unsigned int i = 0; i < size; ++i) | |
71 | 70 | { |
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; | |
74 | 74 | notes[i] = temp_str; |
75 | 75 | } |
76 | 76 | // all ok |
84 | 84 | if (!(is->fseek(sizeof(int), SEEK_CUR))) |
85 | 85 | { |
86 | 86 | // read array |
87 | int comprlen, len; | |
87 | uint32_t comprlen, len; | |
88 | 88 | if (!read32le(&comprlen, is)) return true; |
89 | 89 | if (is->fseek(comprlen, SEEK_CUR) != 0) return true; |
90 | 90 | // read notes |
91 | if (read32le(&comprlen, is) && comprlen >= 0) | |
91 | if (read32le(&comprlen, is)) | |
92 | 92 | { |
93 | for (int i = 0; i < comprlen; ++i) | |
93 | for (unsigned int i = 0; i < comprlen; ++i) | |
94 | 94 | { |
95 | if (!read32le(&len, is) || len < 0) return true; | |
95 | if (!read32le(&len, is) || (len > MAX_NOTE_LEN) ) return true; | |
96 | 96 | if (is->fseek(len, SEEK_CUR) != 0) return true; |
97 | 97 | } |
98 | 98 | // all ok |
104 | 104 | |
105 | 105 | void MARKERS::compressData() |
106 | 106 | { |
107 | int len = markersArray.size() * sizeof(int); | |
107 | uint32_t len = markersArray.size() * sizeof(int); | |
108 | 108 | uLongf comprlen = (len>>9)+12 + len; |
109 | 109 | compressedMarkersArray.resize(comprlen); |
110 | 110 | compress(&compressedMarkersArray[0], &comprlen, (uint8*)&markersArray[0], len); |
414 | 414 | void TASEDITOR_PROJECT::renameProject(const char* newFullName, bool filenameIsCorrect) |
415 | 415 | { |
416 | 416 | 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 | |
418 | 418 | splitpath(newFullName, drv, dir, name, ext); |
419 | 419 | projectName = name; |
420 | 420 | std::string thisfm2name = name; |
25 | 25 | #ifdef WIN32 |
26 | 26 | #include <windows.h> |
27 | 27 | #else |
28 | #include <unistd.h> | |
28 | 29 | #include <sys/types.h> |
29 | 30 | #include <sys/stat.h> |
30 | 31 | #include <fcntl.h> |
110 | 111 | static int recBufNum = 0; |
111 | 112 | static traceRecord_t *logBuf = NULL; |
112 | 113 | 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; | |
115 | 119 | static bool overrunWarningArmed = true; |
116 | 120 | static TraceLoggerDialog_t *traceLogWindow = NULL; |
117 | 121 | static void pushMsgToLogBuffer(const char *msg); |
572 | 576 | |
573 | 577 | if (romFile != NULL) |
574 | 578 | { |
575 | char dir[1024]; | |
579 | std::string dir; | |
576 | 580 | getDirFromFile(romFile, dir); |
577 | dialog.setDirectory(tr(dir)); | |
581 | dialog.setDirectory(tr(dir.c_str())); | |
578 | 582 | } |
579 | 583 | |
580 | 584 | if ( logFilePath.size() != 0 ) |
581 | 585 | { |
582 | char dir[1024]; | |
586 | std::string dir; | |
583 | 587 | getDirFromFile(logFilePath.c_str(), dir); |
584 | dialog.setDirectory(tr(dir)); | |
588 | dialog.setDirectory(tr(dir.c_str())); | |
585 | 589 | } |
586 | 590 | |
587 | 591 | // Check config option to use native file dialog or not |
1290 | 1294 | { |
1291 | 1295 | return logging; |
1292 | 1296 | } |
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 | ||
1293 | 1304 | //---------------------------------------------------- |
1294 | 1305 | //todo: really speed this up |
1295 | 1306 | void FCEUD_TraceInstruction(uint8 *opcode, int size) |
1645 | 1656 | selAddrValue = -1; |
1646 | 1657 | selAddrText[0] = 0; |
1647 | 1658 | |
1648 | if (x < lineText[y].size()) | |
1659 | if ( static_cast<size_t>(x) < lineText[y].size()) | |
1649 | 1660 | { |
1650 | 1661 | int ax = x; |
1651 | 1662 | |
2507 | 2518 | char buf[8192]; |
2508 | 2519 | int i,idx=0; |
2509 | 2520 | int blockSize = 4 * 1024; |
2521 | bool dataNeedsFlush = true; | |
2522 | bool isPaused = false; | |
2510 | 2523 | |
2511 | 2524 | //printf("Trace Log Disk Start\n"); |
2512 | 2525 | |
2549 | 2562 | |
2550 | 2563 | while ( !isInterruptionRequested() ) |
2551 | 2564 | { |
2565 | isPaused = FCEUI_EmulationPaused() ? true : false; | |
2566 | ||
2552 | 2567 | while (logBufHead != logBufTail) |
2553 | 2568 | { |
2554 | 2569 | logBuf[logBufTail].convToText(line); |
2574 | 2589 | } |
2575 | 2590 | idx = 0; |
2576 | 2591 | #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; | |
2577 | 2627 | } |
2578 | 2628 | } |
2579 | 2629 | SDL_Delay(1); |
137 | 137 | } |
138 | 138 | |
139 | 139 | 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) | |
141 | 141 | { |
142 | 142 | if (fwrite(s, 1, count, out) != count) |
143 | 143 | return -1; |
213 | 213 | } |
214 | 214 | |
215 | 215 | 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) | |
217 | 217 | { |
218 | 218 | if (fread(s, 1, count, in) != count) |
219 | 219 | return -1; |
1036 | 1036 | |
1037 | 1037 | int gwavi_t::getChunkData( long long int fpos, unsigned char *buf, size_t size ) |
1038 | 1038 | { |
1039 | int ret; | |
1039 | 1040 | long long int prev_fpos; |
1040 | 1041 | |
1041 | 1042 | prev_fpos = ftell(in); |
1042 | 1043 | |
1043 | 1044 | fseek( in, fpos, SEEK_SET ); |
1044 | 1045 | |
1045 | fread( buf, 1, size, in ); | |
1046 | ret = fread( buf, 1, size, in ) != size; | |
1046 | 1047 | |
1047 | 1048 | fseek( in, prev_fpos, SEEK_SET ); |
1048 | 1049 | |
1049 | return 0; | |
1050 | return ret; | |
1050 | 1051 | } |
1051 | 1052 | |
1052 | 1053 | unsigned int gwavi_t::readAviHeader(void) |
296 | 296 | int write_byte(FILE *fp, unsigned char n); |
297 | 297 | int write_short(FILE *fp, unsigned int n); |
298 | 298 | 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); | |
300 | 300 | int peak_chunk( FILE *fp, long int idx, char *fourcc, unsigned int *size ); |
301 | 301 | |
302 | 302 | int read_int(FILE *fp, int &n); |
304 | 304 | int read_short(FILE *fp, int16_t &n); |
305 | 305 | int read_short(FILE *fp, int &n); |
306 | 306 | 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); | |
308 | 308 | unsigned int readList(int lvl); |
309 | 309 | unsigned int readChunk(const char *id, int lvl); |
310 | 310 | unsigned int readAviHeader(void); |
82 | 82 | case HK_CHEAT_MENU: |
83 | 83 | name = "CheatMenu"; keySeq = ""; title = "Open Cheat Window"; group = "Tools"; |
84 | 84 | break; |
85 | case HK_TOGGLE_ALL_CHEATS: | |
86 | name = "ToggleCheats"; keySeq = ""; title = "Toggle Global Cheat Enable"; group = "Tools"; | |
87 | break; | |
85 | 88 | case HK_BIND_STATE: |
86 | 89 | name = "BindState"; keySeq = ""; title = "Bind Save State to Movie"; group = "Movie"; |
87 | 90 | break; |
183 | 186 | case HK_POWER: |
184 | 187 | name = "Power"; keySeq = ""; title = "Power"; group = "Emulation"; |
185 | 188 | 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"; | |
188 | 194 | break; |
189 | 195 | case HK_PAUSE: |
190 | 196 | name = "Pause"; keySeq = "Pause"; title = "Pause"; group = "Emulation"; |
288 | 294 | case HK_SELECT_STATE_PREV: |
289 | 295 | name = "SelectStatePrev"; keySeq = ""; title = "Select Previous State Slot"; group = "State"; |
290 | 296 | break; |
297 | case HK_VOLUME_MUTE: | |
298 | name = "VolumeMute"; keySeq = ""; title = "Sound Volume Mute"; group = "Sound"; | |
299 | break; | |
291 | 300 | case HK_VOLUME_DOWN: |
292 | name = "VolumeDown"; keySeq = ""; | |
301 | name = "VolumeDown"; keySeq = ""; title = "Sound Volume Down"; group = "Sound"; | |
293 | 302 | break; |
294 | 303 | case HK_VOLUME_UP: |
295 | name = "VolumeUp"; keySeq = ""; | |
304 | name = "VolumeUp"; keySeq = ""; title = "Sound Volume Up"; group = "Sound"; | |
296 | 305 | break; |
297 | 306 | case HK_FKB_ENABLE: |
298 | 307 | name = "FKB_Enable"; keySeq = "ScrollLock"; title = "Toggle Family Keyboard Enable"; |
422 | 431 | static void |
423 | 432 | GetBaseDirectory(std::string &dir) |
424 | 433 | { |
425 | char *home = getenv("FCEUX_HOME"); | |
434 | const char *home = getenv("FCEUX_HOME"); | |
435 | const char *conf = getenv("FCEUX_CONFIG_DIR"); | |
426 | 436 | |
427 | 437 | #ifdef WIN32 |
428 | 438 | // Windows users want base directory to be where executable resides. |
443 | 453 | } |
444 | 454 | #endif |
445 | 455 | |
446 | if (home) | |
456 | if (conf) | |
457 | { | |
458 | dir = std::string(conf); | |
459 | } | |
460 | else if (home) | |
447 | 461 | { |
448 | 462 | dir = std::string(home) + "/.fceux"; |
449 | } else { | |
463 | } | |
464 | else | |
465 | { | |
450 | 466 | #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,'\\'); | |
455 | 471 | if(lastBS) { |
456 | 472 | *lastBS = 0; |
457 | 473 | } |
458 | 474 | |
459 | dir = std::string(home); | |
460 | delete[] home; | |
475 | dir = std::string(exePath); | |
476 | delete[] exePath; | |
461 | 477 | #else |
462 | 478 | dir = ""; |
463 | 479 | #endif |
482 | 498 | |
483 | 499 | // sound options |
484 | 500 | config->addOption('s', "sound", "SDL.Sound", 1); |
501 | config->addOption("soundMute", "SDL.Sound.Mute", 0); | |
485 | 502 | config->addOption("volume", "SDL.Sound.Volume", 255); |
486 | 503 | config->addOption("trianglevol", "SDL.Sound.TriangleVolume", 255); |
487 | 504 | config->addOption("square1vol", "SDL.Sound.Square1Volume", 255); |
504 | 521 | config->addOption("nospritelim", "SDL.DisableSpriteLimit", 0); |
505 | 522 | config->addOption("swapduty", "SDL.SwapDuty", 0); |
506 | 523 | config->addOption("ramInit", "SDL.RamInitMethod", 0); |
524 | config->addOption("SDL.FrameAdvanceDelay", 40); | |
507 | 525 | |
508 | 526 | // color control |
509 | 527 | config->addOption('p', "palette", "SDL.Palette", ""); |
528 | 546 | config->addOption('f', "fullscreen", "SDL.Fullscreen", 0); |
529 | 547 | config->addOption("videoDriver", "SDL.VideoDriver", 0); |
530 | 548 | config->addOption("SDL.VideoBgColor", "#000000"); |
549 | config->addOption("SDL.UseBgPaletteForVideo", false); | |
531 | 550 | config->addOption("SDL.VideoVsync", 1); |
532 | 551 | |
533 | 552 | // set x/y res to 0 for automatic fullscreen resolution detection (no change) |
1075 | 1094 | config->getOption("SDL.VBlankScanlines" , &vblankscanlines ); |
1076 | 1095 | config->getOption("SDL.Skip7bitOverClocking", &skip_7bit_overclocking ); |
1077 | 1096 | config->getOption("SDL.ShowGuiMessages" , &vidGuiMsgEna ); |
1097 | config->getOption("SDL.FrameAdvanceDelay" , &frameAdvance_Delay ); | |
1078 | 1098 | |
1079 | 1099 | config->getOption("SDL.PAL", ®ion); |
1080 | 1100 | FCEUI_SetRegion(region); |
13 | 13 | HK_OPEN_ROM=0, HK_CLOSE_ROM, |
14 | 14 | |
15 | 15 | // 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, | |
17 | 17 | |
18 | 18 | // Emulation Execution Control |
19 | 19 | HK_FRAME_ADVANCE, HK_DECREASE_SPEED, HK_INCREASE_SPEED, HK_TURBO, |
52 | 52 | // Display |
53 | 53 | HK_TOGGLE_FG, HK_TOGGLE_BG, HK_TOGGLE_INPUT_DISPLAY, HK_LAG_COUNTER_DISPLAY, |
54 | 54 | |
55 | HK_CHEAT_MENU, HK_LOAD_LUA, | |
55 | HK_CHEAT_MENU, HK_TOGGLE_ALL_CHEATS, HK_LOAD_LUA, | |
56 | 56 | HK_MUTE_CAPTURE, |
57 | 57 | HK_FA_LAG_SKIP, |
58 | HK_VOLUME_DOWN, HK_VOLUME_UP, | |
58 | HK_VOLUME_MUTE, HK_VOLUME_DOWN, HK_VOLUME_UP, | |
59 | 59 | HK_FKB_ENABLE, |
60 | 60 | HK_MAX}; |
61 | 61 |
12 | 12 | int KillSound(void); |
13 | 13 | uint32 GetMaxSound(void); |
14 | 14 | uint32 GetWriteSound(void); |
15 | bool FCEUD_SoundIsMuted(void); | |
15 | 16 | void FCEUD_MuteSoundOutput(bool value); |
17 | void FCEUD_MuteSoundWindow(bool value); | |
16 | 18 | |
17 | 19 | void SilenceSound(int s); /* DOS and SDL */ |
18 | 20 |
38 | 38 | #include "Qt/unix-netplay.h" |
39 | 39 | #include "Qt/AviRecord.h" |
40 | 40 | #include "Qt/HexEditor.h" |
41 | #include "Qt/CheatsConf.h" | |
41 | 42 | #include "Qt/SymbolicDebug.h" |
42 | 43 | #include "Qt/CodeDataLogger.h" |
43 | 44 | #include "Qt/ConsoleDebugger.h" |
87 | 88 | bool suggestReadOnlyReplay = true; |
88 | 89 | bool showStatusIconOpt = true; |
89 | 90 | bool drawInputAidsEnable = true; |
91 | bool usePaletteForVideoBg = false; | |
90 | 92 | unsigned int gui_draw_area_width = 256; |
91 | 93 | unsigned int gui_draw_area_height = 256; |
92 | 94 | |
350 | 352 | } |
351 | 353 | |
352 | 354 | debugSymbolTable.loadGameSymbols(); |
355 | ||
356 | updateCheatDialog(); | |
353 | 357 | |
354 | 358 | CDLoggerROMChanged(); |
355 | 359 | |
641 | 645 | static void ShowUsage(const char *prog) |
642 | 646 | { |
643 | 647 | int i,j; |
648 | FCEUD_Message("Starting " FCEU_NAME_AND_VERSION "...\n"); | |
644 | 649 | printf("\nUsage is as follows:\n%s <options> filename\n\n",prog); |
645 | 650 | puts(DriverUsage); |
646 | 651 | #ifdef _S9XLUA_H |
680 | 685 | |
681 | 686 | } |
682 | 687 | |
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 | ||
683 | 712 | int fceuWrapperInit( int argc, char *argv[] ) |
684 | 713 | { |
685 | 714 | int opt, error; |
686 | 715 | 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 | } | |
696 | 716 | |
697 | 717 | FCEUD_Message("Starting " FCEU_NAME_AND_VERSION "...\n"); |
698 | 718 | |
867 | 887 | extern std::vector<std::string> subtitleMessages; |
868 | 888 | float fps = (md.palFlag == 0 ? 60.0988 : 50.0069); // NTSC vs PAL |
869 | 889 | 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++) | |
871 | 891 | { |
872 | fprintf(srtfile, "%i\n", i+1); // starts with 1, not 0 | |
892 | fprintf(srtfile, "%zi\n", i+1); // starts with 1, not 0 | |
873 | 893 | double seconds, ms, endseconds, endms; |
874 | 894 | seconds = subtitleFrames[i]/fps; |
875 | 895 | if (i+1 < subtitleFrames.size()) // there's another subtitle coming after this one |
953 | 973 | |
954 | 974 | if (romIndex >= 0) |
955 | 975 | { |
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 | |
962 | 997 | return -1; |
963 | 998 | } |
964 | g_config->setOption("SDL.LastOpenFile", argv[romIndex]); | |
965 | g_config->save(); | |
966 | 999 | } |
967 | 1000 | |
968 | 1001 | aviRecordInit(); |
1476 | 1509 | |
1477 | 1510 | for (size_t i=0; i<asr.files.size(); i++) |
1478 | 1511 | { |
1479 | char base[512], suffix[32]; | |
1512 | char base[512], suffix[128]; | |
1480 | 1513 | |
1481 | 1514 | getFileBaseName( asr.files[i].name.c_str(), base, suffix ); |
1482 | 1515 |
17 | 17 | extern bool emulatorCycleToggle; |
18 | 18 | extern bool showStatusIconOpt; |
19 | 19 | extern bool drawInputAidsEnable; |
20 | extern bool usePaletteForVideoBg; | |
20 | 21 | extern unsigned int gui_draw_area_width; |
21 | 22 | extern unsigned int gui_draw_area_height; |
22 | 23 | extern unsigned int emulatorCycleCount; |
29 | 30 | int reloadLastGame(void); |
30 | 31 | int LoadGameFromLua( const char *path ); |
31 | 32 | |
33 | int fceuWrapperPreInit( int argc, char *argv[] ); | |
32 | 34 | int fceuWrapperInit( int argc, char *argv[] ); |
33 | 35 | int fceuWrapperMemoryCleanup( void ); |
34 | 36 | int fceuWrapperClose( void ); |
188 | 188 | fontCharWidth = fm.width(QLatin1Char('2')); |
189 | 189 | #endif |
190 | 190 | |
191 | setWindowTitle("iNES Header Editor"); | |
191 | setWindowTitle("NES Header Editor"); | |
192 | 192 | |
193 | 193 | //resize( 512, 512 ); |
194 | 194 | |
196 | 196 | hdrLayout = new QVBoxLayout(); |
197 | 197 | hbox1 = new QHBoxLayout(); |
198 | 198 | hbox = new QHBoxLayout(); |
199 | hdrBox = new QGroupBox( tr("iNES Header") ); | |
199 | hdrBox = new QGroupBox( tr("NES Header") ); | |
200 | 200 | box = new QGroupBox( tr("Version:") ); |
201 | 201 | |
202 | 202 | mainLayout->addWidget( hdrBox ); |
549 | 549 | //---------------------------------------------------------------------------- |
550 | 550 | void iNesHeaderEditor_t::closeEvent(QCloseEvent *event) |
551 | 551 | { |
552 | //printf("iNES Header Editor Close Window Event\n"); | |
552 | //printf("NES Header Editor Close Window Event\n"); | |
553 | 553 | done(0); |
554 | 554 | deleteLater(); |
555 | 555 | event->accept(); |
694 | 694 | { |
695 | 695 | case errors::OPEN_FAILED: |
696 | 696 | { |
697 | char buf[2200]; | |
698 | sprintf(buf, "Error opening %s!", LoadedRomFName); | |
697 | char buf[5120]; | |
698 | snprintf(buf, sizeof(buf), "Error opening %s!", LoadedRomFName); | |
699 | 699 | showErrorMsgWindow( buf ); |
700 | 700 | break; |
701 | 701 | } |
702 | 702 | 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." ); | |
705 | 705 | break; |
706 | 706 | 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); | |
708 | 708 | showErrorMsgWindow("Editing header of an FDS file is not supported."); |
709 | 709 | break; |
710 | 710 | 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); | |
712 | 712 | showErrorMsgWindow("Editing header of a UNIF file is not supported."); |
713 | 713 | break; |
714 | 714 | case errors::NSF_HEADER: |
715 | 715 | // case errors::NSF2_HEADER: |
716 | 716 | // 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); | |
718 | 718 | showErrorMsgWindow("Editing header of an NSF file is not supported."); |
719 | 719 | break; |
720 | 720 | } |
736 | 736 | FCEUFILE* source = FCEU_fopen(LoadedRomFName, NULL, "rb", 0, -1, ext); |
737 | 737 | if (!source) |
738 | 738 | { |
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); | |
741 | 742 | return false; |
742 | 743 | } |
743 | 744 | |
745 | 746 | FILE* target = FCEUD_UTF8fopen(path, "wb"); |
746 | 747 | if (!target) |
747 | 748 | { |
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); | |
750 | 752 | return false; |
751 | 753 | } |
752 | 754 | |
775 | 777 | int ret, useNativeFileDialogVal; |
776 | 778 | QString filename; |
777 | 779 | std::string last; |
778 | char dir[512]; | |
780 | std::string dir; | |
779 | 781 | QFileDialog dialog(this, tr("Open NES File") ); |
780 | 782 | |
781 | 783 | const QStringList filters( |
796 | 798 | |
797 | 799 | getDirFromFile( last.c_str(), dir ); |
798 | 800 | |
799 | dialog.setDirectory( tr(dir) ); | |
801 | dialog.setDirectory( tr(dir.c_str()) ); | |
800 | 802 | |
801 | 803 | // Check config option to use native file dialog or not |
802 | 804 | g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); |
824 | 826 | |
825 | 827 | if ( GameInfo == NULL ) |
826 | 828 | { |
827 | strcpy( LoadedRomFName, filename.toStdString().c_str() ); | |
829 | strncpy( LoadedRomFName, filename.toStdString().c_str(), sizeof(LoadedRomFName)-1 ); | |
830 | LoadedRomFName[sizeof(LoadedRomFName)-1] = 0; | |
828 | 831 | } |
829 | 832 | |
830 | 833 | return true; |
835 | 838 | int ret, useNativeFileDialogVal; |
836 | 839 | QString filename; |
837 | 840 | std::string last; |
838 | char dir[512]; | |
841 | std::string dir; | |
839 | 842 | QFileDialog dialog(this, tr("Save iNES File") ); |
840 | 843 | |
841 | 844 | dialog.setFileMode(QFileDialog::AnyFile); |
849 | 852 | |
850 | 853 | getDirFromFile( LoadedRomFName, dir ); |
851 | 854 | |
852 | dialog.setDirectory( tr(dir) ); | |
855 | dialog.setDirectory( tr(dir.c_str()) ); | |
853 | 856 | |
854 | 857 | // Check config option to use native file dialog or not |
855 | 858 | g_config->getOption ("SDL.UseNativeFileDialog", &useNativeFileDialogVal); |
1196 | 1199 | } |
1197 | 1200 | |
1198 | 1201 | // Input Device: |
1199 | int input = header->reserved[1] & 0x3F; | |
1202 | int input = header->expansion & 0x3F; | |
1200 | 1203 | for (i=0; i<inputDevBox->count(); i++) |
1201 | 1204 | { |
1202 | 1205 | if ( inputDevBox->itemData(i).toInt() == input ) |
1206 | 1209 | } |
1207 | 1210 | |
1208 | 1211 | // Miscellaneous ROM Area(s) |
1209 | sprintf(buf, "%d", header->reserved[0] & 3); | |
1212 | sprintf(buf, "%d", header->misc_roms & 3); | |
1210 | 1213 | miscRomsEdit->setText( tr(buf) ); |
1211 | 1214 | |
1212 | 1215 | // Trainer |
1919 | 1922 | int input = inputDevBox->itemData(idx).toInt(); |
1920 | 1923 | if (input <= 0x3F) |
1921 | 1924 | { |
1922 | _header.reserved[1] |= input & 0x3F; | |
1925 | _header.expansion |= input & 0x3F; | |
1923 | 1926 | } |
1924 | 1927 | else |
1925 | 1928 | { |
1943 | 1946 | showErrorMsgWindow("Miscellaneous ROM(s) count has exceeded the limit of iNES 2.0 (3)"); |
1944 | 1947 | return false; |
1945 | 1948 | } |
1946 | _header.reserved[0] |= misc_roms & 3; | |
1949 | _header.misc_roms |= misc_roms & 3; | |
1947 | 1950 | } |
1948 | 1951 | |
1949 | 1952 | // iNES 1.0 unofficial properties |
2021 | 2024 | printf("%02X ", _header->VRAM_size); |
2022 | 2025 | printf("%02X ", _header->TV_system); |
2023 | 2026 | 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 | //---------------------------------------------------------------------------- |
64 | 64 | static int buttonConfigInProgress = 0; |
65 | 65 | |
66 | 66 | extern int gametype; |
67 | static int DTestButton(ButtConfig *bc); | |
67 | static int DTestButton(ButtConfig *bc, bool isFKB = false); | |
68 | 68 | |
69 | 69 | //std::list<gamepad_function_key_t *> gpKeySeqList; |
70 | 70 | |
155 | 155 | return g_keyState[k]; |
156 | 156 | } |
157 | 157 | 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; | |
158 | 167 | } |
159 | 168 | |
160 | 169 | //static int |
1406 | 1415 | * Tests to see if a specified button is currently pressed. |
1407 | 1416 | */ |
1408 | 1417 | static int |
1409 | DTestButton(ButtConfig *bc) | |
1410 | { | |
1411 | ||
1418 | DTestButton(ButtConfig *bc, bool isFKB) | |
1419 | { | |
1412 | 1420 | if (bc->ButtType == BUTTC_KEYBOARD) |
1413 | 1421 | { |
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)]) | |
1415 | 1430 | { |
1416 | 1431 | bc->state = 1; |
1417 | 1432 | return 1; |
1743 | 1758 | CurInputType[1] = port1; |
1744 | 1759 | CurInputType[2] = fcexp; |
1745 | 1760 | } |
1761 | if (CurInputType[2] != SIFC_FKB) | |
1762 | { | |
1763 | g_fkbEnabled = false; | |
1764 | } | |
1746 | 1765 | |
1747 | 1766 | replaceP2StartWithMicrophone = microphone; |
1748 | 1767 | |
1870 | 1889 | |
1871 | 1890 | vkeyDown = getFamilyKeyboardVirtualKey(50); |
1872 | 1891 | |
1873 | leftShiftDown = DTestButton(&fkbmap[50]) || vkeyDown; | |
1892 | leftShiftDown = DTestButton(&fkbmap[50], true) || vkeyDown; | |
1874 | 1893 | |
1875 | 1894 | for (x = 0; x < FAMILYKEYBOARD_NUM_BUTTONS; x++) |
1876 | 1895 | { |
1886 | 1905 | |
1887 | 1906 | vkeyDown = getFamilyKeyboardVirtualKey(x); |
1888 | 1907 | |
1889 | if (DTestButton(&fkbmap[x]) || vkeyDown) | |
1908 | if (DTestButton(&fkbmap[x], true) || vkeyDown) | |
1890 | 1909 | { |
1891 | 1910 | fkbkeys[x] = 1; |
1892 | 1911 | |
1908 | 1927 | } |
1909 | 1928 | } |
1910 | 1929 | |
1911 | const uint8 *getFamilyKeyboardState(void) | |
1930 | const uint8_t *getFamilyKeyboardState(void) | |
1912 | 1931 | { |
1913 | 1932 | return fkbkeys; |
1914 | 1933 | } |
2413 | 2432 | QDir dir; |
2414 | 2433 | std::string path; |
2415 | 2434 | const char *baseDir = FCEUI_GetBaseDirectory(); |
2416 | char base[256]; | |
2435 | char base[512]; | |
2417 | 2436 | |
2418 | 2437 | path = std::string(baseDir) + "/input/presets/"; |
2419 | 2438 | |
2461 | 2480 | QDir dir; |
2462 | 2481 | std::string path; |
2463 | 2482 | const char *baseDir = FCEUI_GetBaseDirectory(); |
2464 | char base[256], line[256]; | |
2483 | char base[512], line[256]; | |
2465 | 2484 | char id[128], val[128]; |
2466 | 2485 | int i, j; |
2467 | 2486 |
147 | 147 | int loadInputSettingsFromFile( const char *filename = NULL ); |
148 | 148 | void toggleFamilyKeyboardFunc(void); |
149 | 149 | bool isFamilyKeyboardActv(void); |
150 | const uint8 *getFamilyKeyboardState(void); | |
150 | const uint8_t *getFamilyKeyboardState(void); | |
151 | const uint8_t *QtSDL_getKeyboardState( int *bufSize ); | |
151 | 152 | |
152 | 153 | #endif |
153 | 154 |
26 | 26 | |
27 | 27 | using namespace Qt; |
28 | 28 | |
29 | /* scan code to virtual keys */ | |
30 | struct _KeyValue | |
31 | { | |
32 | int vkey, key; | |
33 | }; | |
34 | ||
35 | /* for readability */ | |
36 | typedef int NativeScanCode; | |
37 | ||
29 | 38 | #if defined(WIN32) |
30 | 39 | |
31 | 40 | #include <windows.h> |
68 | 77 | static uint32_t CtrlKeyCodeR = 0xffe4; |
69 | 78 | static uint32_t AltKeyCodeR = 0xffea; |
70 | 79 | 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 | }; | |
71 | 387 | #endif |
72 | 388 | |
73 | 389 | SDL_Scancode convQtKey2SDLScanCode(Qt::Key q, uint32_t nativeVirtualKey) |
1354 | 1670 | |
1355 | 1671 | vkey = event->nativeVirtualKey(); |
1356 | 1672 | |
1673 | // auto nsc = event->nativeScanCode(); | |
1674 | // qDebug() << __PRETTY_FUNCTION__ << nsc << vkey << event->key(); | |
1675 | ||
1357 | 1676 | sdlev.key.keysym.sym = convQtKey2SDLKeyCode((Qt::Key)event->key(), vkey); |
1358 | 1677 | |
1359 | 1678 | sdlev.key.keysym.scancode = SDL_GetScancodeFromKey(sdlev.key.keysym.sym); |
1384 | 1703 | |
1385 | 1704 | //printf("Modifiers: %08X -> %08X \n", event->modifiers(), sdlev.key.keysym.mod ); |
1386 | 1705 | |
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 | ||
1387 | 1718 | if (sdlev.key.keysym.scancode != SDL_SCANCODE_UNKNOWN) |
1388 | 1719 | { |
1389 | 1720 | SDL_PushEvent(&sdlev); |
42 | 42 | switch (type) |
43 | 43 | { |
44 | 44 | 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); | |
46 | 46 | FCEUD_Message(cmsg); |
47 | 47 | break; |
48 | 48 | 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); | |
50 | 50 | FCEUD_Message(cmsg); |
51 | 51 | break; |
52 | 52 | 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); | |
54 | 54 | FCEUD_Message(cmsg); |
55 | 55 | break; |
56 | 56 | 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); | |
58 | 58 | FCEUD_PrintError(cmsg); |
59 | 59 | break; |
60 | 60 | 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); | |
62 | 62 | FCEUD_PrintError(cmsg); |
63 | 63 | break; |
64 | 64 | } |
65 | cmsg[sizeof(cmsg)-1] = 0; | |
65 | 66 | fprintf(stderr, "%s", cmsg ); |
66 | 67 | } |
67 | 68 | |
94 | 95 | |
95 | 96 | int main( int argc, char *argv[] ) |
96 | 97 | { |
97 | int retval; | |
98 | int retval = 0; | |
99 | ||
100 | fceuWrapperPreInit(argc, argv); | |
101 | ||
98 | 102 | qInstallMessageHandler(MessageOutput); |
99 | 103 | QApplication app(argc, argv); |
100 | 104 |
28 | 28 | #define EO_SUBASE 2 |
29 | 29 | #define EO_CLIPSIDES 8 |
30 | 30 | #define EO_SNAPNAME 16 |
31 | #define EO_FOURSCORE 32 | |
32 | 31 | #define EO_NOTHROTTLE 64 |
33 | 32 | #define EO_GAMEGENIE 128 |
34 | 33 | #define EO_PAL 256 |
35 | 34 | #define EO_LOWPASS 512 |
36 | 35 | #define EO_AUTOHIDE 1024 |
36 | #define EO_FOURSCORE 32768 // for compatibility with non-Qt | |
37 | 37 | |
38 | 38 | extern int _sound; |
39 | 39 | extern long soundrate; |
1132 | 1132 | |
1133 | 1133 | xx = 0; yy = 0; |
1134 | 1134 | |
1135 | showSelector = (cycleCount < 20); | |
1135 | showSelector = (cycleCount < 20) && (selTile.x() >= 0) && (selTile.y() >= 0); | |
1136 | 1136 | |
1137 | 1137 | if ( mode == 1 ) |
1138 | 1138 | { |
41 | 41 | static unsigned int s_BufferSize75; |
42 | 42 | static unsigned int s_BufferRead; |
43 | 43 | static unsigned int s_BufferWrite; |
44 | static volatile unsigned int s_BufferIn; | |
44 | static volatile unsigned int s_BufferIn = 0; | |
45 | 45 | static unsigned int s_SampleRate = 44100; |
46 | 46 | static double noiseGate = 0.0; |
47 | 47 | static double noiseGateRate = 0.010; |
48 | 48 | static bool noiseGateActive = true; |
49 | static bool muteSoundOutput = false; | |
49 | static bool windowSoundMute = false; | |
50 | 50 | 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; | |
53 | 54 | |
54 | 55 | extern int EmulationPaused; |
55 | 56 | extern double frmRateAdjRatio; |
98 | 99 | noiseGateActive = 1; |
99 | 100 | return; |
100 | 101 | } |
101 | mute = EmulationPaused || muteSoundOutput; | |
102 | mute = EmulationPaused || windowSoundMute || s_mute; | |
102 | 103 | |
103 | 104 | if ( mute || noiseGateActive ) |
104 | 105 | { |
185 | 186 | int |
186 | 187 | InitSound() |
187 | 188 | { |
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; | |
189 | 190 | SDL_AudioSpec spec; |
190 | 191 | const char *driverName; |
191 | 192 | int frmRateSampleAdj = 0; |
192 | 193 | int samplesPerFrame; |
194 | bool sampleRateIsSupported = false; | |
193 | 195 | |
194 | 196 | g_config->getOption("SDL.Sound", &sound); |
195 | 197 | if (!sound) |
206 | 208 | } |
207 | 209 | |
208 | 210 | // load configuration variables |
211 | g_config->getOption("SDL.Sound.Mute", &s_mute); | |
209 | 212 | g_config->getOption("SDL.Sound.Rate", &soundrate); |
210 | 213 | g_config->getOption("SDL.Sound.BufSize", &soundbufsize); |
211 | 214 | g_config->getOption("SDL.Sound.Volume", &soundvolume); |
216 | 219 | g_config->getOption("SDL.Sound.NoiseVolume", &soundnoisevolume); |
217 | 220 | g_config->getOption("SDL.Sound.PCMVolume", &soundpcmvolume); |
218 | 221 | |
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 | ||
219 | 247 | spec.freq = s_SampleRate = soundrate; |
220 | 248 | spec.format = AUDIO_S16SYS; |
221 | 249 | spec.channels = 1; |
233 | 261 | s_BufferSize = soundbufsize * soundrate / 1000; |
234 | 262 | |
235 | 263 | // For safety, set a bare minimum: |
236 | if (s_BufferSize < spec.samples * 4) | |
264 | if (s_BufferSize < static_cast<unsigned int>(spec.samples * 4)) | |
237 | 265 | { |
238 | 266 | s_BufferSize = spec.samples * 4; |
239 | 267 | } |
491 | 519 | free((void *)s_Buffer); |
492 | 520 | s_Buffer = 0; |
493 | 521 | } |
522 | s_BufferIn = 0; | |
494 | 523 | return 0; |
495 | 524 | } |
496 | 525 | |
523 | 552 | break; |
524 | 553 | } |
525 | 554 | |
526 | s_mute = 0; | |
555 | s_mute = false; | |
556 | g_config->setOption("SDL.Sound.Mute", s_mute); | |
557 | ||
527 | 558 | FCEUI_SetSoundVolume(soundvolume); |
528 | 559 | g_config->setOption("SDL.Sound.Volume", soundvolume); |
529 | 560 | |
536 | 567 | void |
537 | 568 | FCEUD_SoundToggle(void) |
538 | 569 | { |
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; | |
551 | 576 | } |
552 | 577 | |
553 | 578 | void FCEUD_MuteSoundOutput( bool value ) |
554 | 579 | { |
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 | } |
36 | 36 | #include "Qt/sdl-video.h" |
37 | 37 | #include "Qt/AviRecord.h" |
38 | 38 | #include "Qt/fceuWrapper.h" |
39 | #include "Qt/ConsoleWindow.h" | |
39 | 40 | |
40 | 41 | #ifdef CREATE_AVI |
41 | 42 | #include "../videolog/nesvideos-piece.h" |
73 | 74 | extern int input_display; |
74 | 75 | extern int frame_display; |
75 | 76 | extern int rerecord_display; |
77 | extern uint8 PALRAM[0x20]; | |
76 | 78 | |
77 | 79 | /** |
78 | 80 | * Attempts to destroy the graphical video display. Returns 0 on |
497 | 499 | { |
498 | 500 | int i = nes_shm->pixBufIdx; |
499 | 501 | |
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 | ||
500 | 515 | doBlitScreen(XBuf, (uint8_t*)nes_shm->pixbuf[i]); |
501 | 516 | |
502 | 517 | nes_shm->pixBufIdx = (i+1) % NES_VIDEO_BUFLEN; |
119 | 119 | if(TSocket < 0) { |
120 | 120 | const char* s = "Error creating stream socket."; |
121 | 121 | puts(s); |
122 | FCEU_DispMessage(s,0); | |
122 | FCEU_DispMessage("%s",0,s); | |
123 | 123 | FCEUD_NetworkClose(); |
124 | 124 | return 0; |
125 | 125 | } |
302 | 302 | size = recv(s_Socket, data, len, MSG_WAITALL); |
303 | 303 | #endif |
304 | 304 | |
305 | if(size == len) { | |
305 | if( static_cast<uint32>(size) == len) { | |
306 | 306 | //unsigned long beefie; |
307 | 307 | |
308 | 308 | FD_ZERO(&funfun); |
25 | 25 | static void GetString(char *s, int max) |
26 | 26 | { |
27 | 27 | int x; |
28 | fgets(s,max,stdin); | |
28 | if ( fgets(s,max,stdin) == nullptr ) | |
29 | { | |
30 | s[0] = 0; | |
31 | return; | |
32 | } | |
29 | 33 | |
30 | 34 | for(x=0;x<max;x++) |
31 | 35 | if(s[x]=='\n') |
40 | 44 | { |
41 | 45 | char buf[32]; |
42 | 46 | |
43 | fgets(buf,ARRAY_SIZE(buf),stdin); | |
47 | if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr ) | |
48 | { | |
49 | return def; | |
50 | } | |
44 | 51 | if(buf[0]=='\n') |
45 | 52 | return(def); |
46 | 53 | if(buf[0]=='$') |
55 | 62 | { |
56 | 63 | char buf[32]; |
57 | 64 | |
58 | fgets(buf,ARRAY_SIZE(buf),stdin); | |
65 | if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr ) | |
66 | { | |
67 | return def; | |
68 | } | |
59 | 69 | if(buf[0]=='\n') |
60 | 70 | return(def); |
61 | 71 | sscanf(buf,"%u",&def); |
66 | 76 | { |
67 | 77 | char buf[32]; |
68 | 78 | |
69 | fgets(buf,ARRAY_SIZE(buf),stdin); | |
79 | if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr ) | |
80 | { | |
81 | return def; | |
82 | } | |
70 | 83 | if(buf[0]=='\n') |
71 | 84 | return(def); |
72 | 85 | sscanf(buf,"%d",&def); |
77 | 90 | { |
78 | 91 | char buf[32]; |
79 | 92 | 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 | } | |
81 | 97 | if(buf[0]=='y' || buf[0]=='Y') |
82 | 98 | return(1); |
83 | 99 | if(buf[0]=='n' || buf[0]=='N') |
113 | 129 | |
114 | 130 | tryagain: |
115 | 131 | 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 | } | |
117 | 136 | if(buf[0]=='s' || buf[0]=='S') return(-1); |
118 | 137 | if(buf[0]=='\n') return(0); |
119 | 138 | if(!sscanf(buf,"%d",&num)) |
127 | 146 | |
128 | 147 | tryagain2: |
129 | 148 | 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 | } | |
131 | 153 | if(buf[0]=='\n') return(0); |
132 | 154 | if(!sscanf(buf,"%d",&num)) |
133 | 155 | return(0); |
198 | 220 | |
199 | 221 | static void ModifyCheat(int num) |
200 | 222 | { |
201 | char *name; | |
223 | std::string name; | |
224 | std::string *pName; | |
202 | 225 | char buf[256]; |
203 | 226 | uint32 A; |
204 | 227 | uint8 V; |
210 | 233 | |
211 | 234 | FCEUI_GetCheat(num, &name, &A, &V, &compare, &s, &type); |
212 | 235 | |
213 | printf("Name [%s]: ",name); | |
236 | printf("Name [%s]: ",name.c_str()); | |
214 | 237 | GetString(buf,256); |
215 | 238 | |
216 | 239 | /* This obviously doesn't allow for cheats with no names. Bah. Who wants |
218 | 241 | */ |
219 | 242 | |
220 | 243 | if(buf[0]) |
221 | name=buf; // Change name when FCEUI_SetCheat() is called. | |
244 | pName=&name; // Change name when FCEUI_SetCheat() is called. | |
222 | 245 | 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. | |
224 | 247 | |
225 | 248 | printf("Address [$%04x]: ",(unsigned int)A); |
226 | 249 | A=GetH16(A); |
239 | 262 | if(t=='Y' || t=='y') s=1; |
240 | 263 | else if(t=='N' || t=='n') s=0; |
241 | 264 | |
242 | FCEUI_SetCheat(num,name,A,V,compare,s,type); | |
265 | FCEUI_SetCheat(num,pName,A,V,compare,s,type); | |
243 | 266 | } |
244 | 267 | |
245 | 268 | |
319 | 342 | } |
320 | 343 | |
321 | 344 | 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) | |
323 | 346 | { |
324 | 347 | char tmp[512]; |
325 | 348 | int ret; |
347 | 370 | { |
348 | 371 | char tmp[32]; |
349 | 372 | 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 | } | |
351 | 377 | switch(tolower(tmp[0])) |
352 | 378 | { |
353 | 379 | case 't':ToggleCheat(which); |
404 | 430 | clo: |
405 | 431 | |
406 | 432 | 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 | } | |
408 | 437 | if(tmp[0]=='\n') |
409 | 438 | return def; |
410 | 439 | c=tolower(tmp[0]); |
503 | 532 | |
504 | 533 | recommand: |
505 | 534 | printf("Command> "); |
506 | fgets(buf,ARRAY_SIZE(buf),stdin); | |
535 | if ( fgets(buf,ARRAY_SIZE(buf),stdin) == nullptr ) | |
536 | { | |
537 | return; | |
538 | } | |
507 | 539 | c=tolower(buf[0]); |
508 | 540 | if(c=='\n') |
509 | 541 | goto recommand; |
144 | 144 | { |
145 | 145 | if(!c) // String, allocate some memory. |
146 | 146 | { |
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 | ||
147 | 152 | if(!(*(char **)v=(char*)malloc(s))) |
148 | 153 | goto gogl; |
149 | 154 | |
207 | 212 | if(*(char **)cfgst[x].ptr) |
208 | 213 | { |
209 | 214 | // 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); | |
211 | 216 | SetValueR(fp,cfgst[x].name,*(char **)cfgst[x].ptr, len + 1); |
212 | 217 | } |
213 | 218 | } |
640 | 640 | int |
641 | 641 | Config::_loadFile(const char* fname) |
642 | 642 | { |
643 | signed int pos, eqPos; | |
643 | size_t pos=0, eqPos=0; | |
644 | 644 | std::fstream config; |
645 | 645 | std::map<std::string, int>::iterator int_i; |
646 | 646 | std::map<std::string, double>::iterator dbl_i; |
655 | 655 | configFile = fname; |
656 | 656 | } |
657 | 657 | std::string line, name, value; |
658 | char buf[1024]; | |
658 | char buf[4096]; | |
659 | 659 | |
660 | 660 | // set the exception handling to catch i/o errors |
661 | 661 | config.exceptions(std::fstream::badbit); |
670 | 670 | |
671 | 671 | while(!config.eof()) { |
672 | 672 | // read a line |
673 | config.getline(buf, 1024); | |
673 | config.getline(buf, sizeof(buf)); | |
674 | 674 | line = buf; |
675 | 675 | |
676 | 676 | // check line validity |
722 | 722 | std::map<std::string, double>::iterator dbl_i; |
723 | 723 | std::map<std::string, std::string>::iterator str_i; |
724 | 724 | std::string configFile = _dir + "/" + cfgFile; |
725 | char buf[1024]; | |
725 | char buf[4096]; | |
726 | 726 | |
727 | 727 | // set the exception handling to catch i/o errors |
728 | 728 | config.exceptions(std::ios::failbit | std::ios::badbit); |
740 | 740 | // write each configuration setting |
741 | 741 | for(int_i = _intOptMap.begin(); int_i != _intOptMap.end(); int_i++) |
742 | 742 | { |
743 | snprintf(buf, 1024, "%s = %d\n", | |
743 | snprintf(buf, sizeof(buf), "%s = %d\n", | |
744 | 744 | int_i->first.c_str(), int_i->second); |
745 | 745 | config.write(buf, strlen(buf)); |
746 | 746 | } |
747 | 747 | for(dbl_i = _dblOptMap.begin(); dbl_i != _dblOptMap.end(); dbl_i++) |
748 | 748 | { |
749 | snprintf(buf, 1024, "%s = %f\n", | |
749 | snprintf(buf, sizeof(buf), "%s = %f\n", | |
750 | 750 | dbl_i->first.c_str(), dbl_i->second); |
751 | 751 | config.write(buf, strlen(buf)); |
752 | 752 | } |
753 | 753 | for(str_i = _strOptMap.begin(); str_i != _strOptMap.end(); str_i++) |
754 | 754 | { |
755 | snprintf(buf, 1024, "%s = %s\n", | |
755 | snprintf(buf, sizeof(buf), "%s = %s\n", | |
756 | 756 | str_i->first.c_str(), str_i->second.c_str()); |
757 | 757 | config.write(buf, strlen(buf)); |
758 | 758 | } |
237 | 237 | { |
238 | 238 | if(palettetranslate) |
239 | 239 | { |
240 | free(palettetranslate); | |
240 | FCEU_free(palettetranslate); | |
241 | 241 | palettetranslate=NULL; |
242 | 242 | } |
243 | 243 | |
244 | 244 | if(specbuf8bpp) |
245 | 245 | { |
246 | free(specbuf8bpp); | |
246 | FCEU_free(specbuf8bpp); | |
247 | 247 | specbuf8bpp = NULL; |
248 | 248 | } |
249 | 249 | if(specbuf32bpp) |
250 | 250 | { |
251 | free(specbuf32bpp); | |
251 | FCEU_free(specbuf32bpp); | |
252 | 252 | specbuf32bpp = NULL; |
253 | 253 | } |
254 | 254 | if(specbuf) |
258 | 258 | hq3x_Kill(); |
259 | 259 | else |
260 | 260 | hq2x_Kill(); |
261 | free(specbuf); | |
261 | FCEU_free(specbuf); | |
262 | 262 | specbuf=NULL; |
263 | 263 | } |
264 | 264 | if (nes_ntsc) { |
265 | free(nes_ntsc); | |
265 | FCEU_free(nes_ntsc); | |
266 | 266 | nes_ntsc = NULL; |
267 | 267 | } |
268 | 268 | if (ntscblit) { |
465 | 465 | /* Todo: Make sure 24bpp code works right with big-endian cpus */ |
466 | 466 | |
467 | 467 | //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) | |
469 | 469 | { |
470 | 470 | u8 pixel = *src; |
471 | 471 | |
491 | 491 | return color; |
492 | 492 | } |
493 | 493 | |
494 | u32 ModernDeemphColorMap(u8* src, u8* srcbuf, int scale) | |
494 | u32 ModernDeemphColorMap(const u8* src, const u8* srcbuf, int scale) | |
495 | 495 | { |
496 | 496 | if(scale == 1) return _ModernDeemphColorMap<1>(src,srcbuf); |
497 | 497 | else if(scale == 2) return _ModernDeemphColorMap<2>(src,srcbuf); |
502 | 502 | else if(scale == 7) return _ModernDeemphColorMap<7>(src,srcbuf); |
503 | 503 | else if(scale == 8) return _ModernDeemphColorMap<8>(src,srcbuf); |
504 | 504 | 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* ); | |
509 | 509 | |
510 | 510 | static ModernDeemphColorMapFuncPtr getModernDeemphColorMapFunc(int scale) |
511 | 511 | { |
512 | ModernDeemphColorMapFuncPtr ptr = NULL; | |
512 | ModernDeemphColorMapFuncPtr ptr; | |
513 | 513 | |
514 | 514 | if(scale == 1) ptr = &_ModernDeemphColorMap<1>; |
515 | 515 | else if(scale == 2) ptr = &_ModernDeemphColorMap<2>; |
520 | 520 | else if(scale == 7) ptr = &_ModernDeemphColorMap<7>; |
521 | 521 | else if(scale == 8) ptr = &_ModernDeemphColorMap<8>; |
522 | 522 | else if(scale == 9) ptr = &_ModernDeemphColorMap<9>; |
523 | else { abort(); ptr = NULL; } | |
523 | else { FCEU_abort("unhandled ModernDeemphColorMap scale"); ptr = nullptr; } | |
524 | 524 | |
525 | 525 | return ptr; |
526 | 526 | } |
28 | 28 | int shiftr[3], int shiftl[3]); |
29 | 29 | |
30 | 30 | |
31 | u32 ModernDeemphColorMap(u8* src, u8* srcbuf, int scale);⏎ | |
31 | u32 ModernDeemphColorMap(const u8* src, const u8* srcbuf, int scale); |
1708 | 1708 | } |
1709 | 1709 | } |
1710 | 1710 | |
1711 | void FCEUD_FlushTrace() | |
1712 | { | |
1713 | // Place holder to allow for compiling. GTK GUI doesn't support this. Qt Does. | |
1714 | } | |
1715 | ||
1711 | 1716 | void FCEUD_TraceInstruction(uint8 *opcode, int size) |
1712 | 1717 | { |
1713 | 1718 | // Place holder to allow for compiling. GTK GUI doesn't support this. Qt Does. |
276 | 276 | { |
277 | 277 | if (addr < 16) |
278 | 278 | { |
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."); | |
280 | 280 | } |
281 | 281 | else if ( (addr >= 16) && (addr < PRGsize[0]+16) ) |
282 | 282 | { |
528 | 528 | /** |
529 | 529 | * Unimplemented. |
530 | 530 | */ |
531 | void FCEUD_FlushTrace() | |
532 | { | |
533 | } | |
534 | ||
535 | /** | |
536 | * Unimplemented. | |
537 | */ | |
531 | 538 | void FCEUD_TraceInstruction() { |
532 | 539 | return; |
533 | 540 | } |
22 | 22 | #include "emufile.h" |
23 | 23 | #include "utils/xstring.h" |
24 | 24 | |
25 | #include <stdio.h> | |
25 | 26 | #include <vector> |
26 | 27 | |
27 | 28 | bool EMUFILE::readAllBytes(std::vector<u8>* dstbuf, const std::string& fname) |
28 | 29 | { |
29 | 30 | EMUFILE_FILE file(fname.c_str(),"rb"); |
30 | 31 | if(file.fail()) return false; |
31 | int size = file.size(); | |
32 | size_t size = file.size(); | |
32 | 33 | dstbuf->resize(size); |
33 | 34 | file.fread(&dstbuf->at(0),size); |
34 | 35 | return true; |
35 | 36 | } |
36 | 37 | |
37 | 38 | 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); | |
40 | 41 | if(len==0) |
41 | 42 | { |
42 | 43 | failbit = true; |
77 | 78 | } |
78 | 79 | |
79 | 80 | |
80 | void EMUFILE_FILE::truncate(s32 length) | |
81 | void EMUFILE_FILE::truncate(size_t length) | |
81 | 82 | { |
82 | 83 | ::fflush(fp); |
83 | 84 | #ifdef _MSC_VER |
84 | 85 | _chsize(_fileno(fp),length); |
85 | 86 | #else |
86 | ftruncate(fileno(fp),length); | |
87 | if ( ftruncate(fileno(fp),length) != 0 ) | |
88 | { | |
89 | printf("Warning: EMUFILE_FILE::truncate failed\n"); | |
90 | } | |
87 | 91 | #endif |
88 | 92 | // this is probably wrong if mode is "wb" |
89 | 93 | fclose(fp); |
58 | 58 | bool fail(bool unset=false) { bool ret = failbit; if(unset) unfail(); return ret; } |
59 | 59 | void unfail() { failbit=false; } |
60 | 60 | |
61 | bool eof() { return size()==ftell(); } | |
61 | bool eof() { return size() == static_cast<size_t>(ftell()); } | |
62 | 62 | |
63 | 63 | size_t fread(const void *ptr, size_t bytes){ |
64 | 64 | return _fread(ptr,bytes); |
108 | 108 | double readdouble(); |
109 | 109 | size_t readdouble(double* val); |
110 | 110 | |
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; | |
115 | 115 | virtual void fflush() = 0; |
116 | 116 | |
117 | virtual void truncate(s32 length) = 0; | |
117 | virtual void truncate(size_t length) = 0; | |
118 | 118 | }; |
119 | 119 | |
120 | 120 | //todo - handle read-only specially? |
122 | 122 | protected: |
123 | 123 | std::vector<u8> *vec; |
124 | 124 | 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) { | |
128 | 129 | if(vec->size() < amt) |
129 | 130 | vec->resize(amt); |
130 | 131 | } |
132 | 133 | public: |
133 | 134 | |
134 | 135 | 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) { | |
136 | 137 | vec->resize(preallocate); |
137 | 138 | len = preallocate; |
138 | 139 | } |
139 | 140 | 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) { | |
141 | 142 | vec->resize(size); |
142 | 143 | if(size != 0) |
143 | 144 | memcpy(&vec->front(),buf,size); |
149 | 150 | |
150 | 151 | virtual EMUFILE* memwrap(); |
151 | 152 | |
152 | virtual void truncate(s32 length) | |
153 | virtual void truncate(size_t length) | |
153 | 154 | { |
154 | 155 | vec->resize(length); |
155 | 156 | len = length; |
156 | if(pos>length) pos=length; | |
157 | if (static_cast<size_t>(pos) > length) pos=static_cast<long int>(length); | |
157 | 158 | } |
158 | 159 | |
159 | 160 | u8* buf() { |
191 | 192 | //if(_fread(&temp,1) != 1) |
192 | 193 | // return EOF; |
193 | 194 | //else return temp; |
194 | u32 remain = len-pos; | |
195 | size_t remain = len-pos; | |
195 | 196 | if(remain<1) { |
196 | 197 | failbit = true; |
197 | 198 | return -1; |
215 | 216 | //they handle the return values correctly |
216 | 217 | |
217 | 218 | virtual void fwrite(const void *ptr, size_t bytes){ |
218 | reserve(pos+(s32)bytes); | |
219 | reserve(pos+bytes); | |
219 | 220 | 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){ | |
225 | 226 | //work differently for read-only...? |
226 | 227 | switch(origin) { |
227 | 228 | case SEEK_SET: |
231 | 232 | pos += offset; |
232 | 233 | break; |
233 | 234 | case SEEK_END: |
234 | pos = size()+offset; | |
235 | pos = (long int)(size()+offset); | |
235 | 236 | break; |
236 | 237 | default: |
237 | 238 | assert(false); |
240 | 241 | return 0; |
241 | 242 | } |
242 | 243 | |
243 | virtual int ftell() { | |
244 | virtual long int ftell() { | |
244 | 245 | return pos; |
245 | 246 | } |
246 | 247 | |
247 | 248 | virtual void fflush() {} |
248 | 249 | |
249 | void set_len(s32 length) | |
250 | void set_len(size_t length) | |
250 | 251 | { |
251 | 252 | len = length; |
252 | if(pos > length) | |
253 | pos = length; | |
253 | if (static_cast<size_t>(pos) > length) | |
254 | pos = static_cast<long>(length); | |
254 | 255 | } |
255 | 256 | void trim() |
256 | 257 | { |
257 | 258 | vec->resize(len); |
258 | 259 | } |
259 | 260 | |
260 | virtual int size() { return (int)len; } | |
261 | virtual size_t size() { return len; } | |
261 | 262 | }; |
262 | 263 | |
263 | 264 | class EMUFILE_FILE : public EMUFILE { |
287 | 288 | |
288 | 289 | bool is_open() { return fp != NULL; } |
289 | 290 | |
290 | virtual void truncate(s32 length); | |
291 | virtual void truncate(size_t length); | |
291 | 292 | |
292 | 293 | virtual int fprintf(const char *format, ...) { |
293 | 294 | va_list argptr; |
320 | 321 | failbit = true; |
321 | 322 | } |
322 | 323 | |
323 | virtual int fseek(int offset, int origin) { | |
324 | virtual int fseek(long int offset, int origin) { | |
324 | 325 | return ::fseek(fp, offset, origin); |
325 | 326 | } |
326 | 327 | |
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(); | |
333 | 334 | fseek(0,SEEK_END); |
334 | int len = ftell(); | |
335 | long int len = ftell(); | |
335 | 336 | fseek(oldpos,SEEK_SET); |
336 | return len; | |
337 | return static_cast<size_t>(len); | |
337 | 338 | } |
338 | 339 | |
339 | 340 | virtual void fflush() { |
180 | 180 | } |
181 | 181 | |
182 | 182 | #ifdef __WIN_DRIVER__ |
183 | extern char LoadedRomFName[2048]; | |
184 | 183 | if (storePreferences(mass_replace(LoadedRomFName, "|", ".").c_str())) |
185 | 184 | FCEUD_PrintError("Couldn't store debugging data"); |
186 | 185 | CDLoggerROMClosed(); |
225 | 224 | currFrameCounter = 0; |
226 | 225 | |
227 | 226 | //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(); | |
229 | 228 | undoSS = false; |
230 | 229 | redoSS = false; |
231 | lastLoadstateMade[0] = 0; | |
230 | lastLoadstateMade.clear(); | |
232 | 231 | undoLS = false; |
233 | 232 | redoLS = false; |
234 | 233 | AutoSS = false; |
420 | 419 | //---------- |
421 | 420 | //attempt to open the files |
422 | 421 | 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 | |
424 | 423 | int lastpal = PAL; |
425 | 424 | int lastdendy = dendy; |
426 | 425 | |
430 | 429 | // currently there's only one situation: |
431 | 430 | // the user clicked cancel form the open from archive dialog |
432 | 431 | 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); | |
434 | 433 | |
435 | 434 | if (!fp) |
436 | 435 | { |
442 | 441 | } |
443 | 442 | else if (fp->archiveFilename != "") |
444 | 443 | { |
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 | } | |
450 | 452 | |
451 | 453 | // reset loaded game BEFORE it's loading. |
452 | 454 | ResetGameLoaded(); |
453 | 455 | //file opened ok. start loading. |
454 | FCEU_printf("Loading %s...\n\n", fullname); | |
456 | FCEU_printf("Loading %s...\n\n", fullname.c_str()); | |
455 | 457 | GetFileBase(fp->filename.c_str()); |
456 | 458 | //reset parameters so they're cleared just in case a format's loader doesn't know to do the clearing |
457 | 459 | MasterRomInfoParams = TMasterRomInfoParams(); |
483 | 485 | bool FCEUXLoad(const char *name, FCEUFILE * fp); |
484 | 486 | |
485 | 487 | int load_result; |
486 | load_result = iNESLoad(fullname, fp, OverwriteVidMode); | |
488 | load_result = iNESLoad(fullname.c_str(), fp, OverwriteVidMode); | |
487 | 489 | if (load_result == LOADER_INVALID_FORMAT) |
488 | 490 | { |
489 | load_result = NSFLoad(fullname, fp); | |
491 | load_result = NSFLoad(fullname.c_str(), fp); | |
490 | 492 | if (load_result == LOADER_INVALID_FORMAT) |
491 | 493 | { |
492 | load_result = UNIFLoad(fullname, fp); | |
494 | load_result = UNIFLoad(fullname.c_str(), fp); | |
493 | 495 | if (load_result == LOADER_INVALID_FORMAT) |
494 | 496 | { |
495 | load_result = FDSLoad(fullname, fp); | |
497 | load_result = FDSLoad(fullname.c_str(), fp); | |
496 | 498 | } |
497 | 499 | } |
498 | 500 | } |
501 | 503 | |
502 | 504 | #ifdef __WIN_DRIVER__ |
503 | 505 | // ################################## Start of SP CODE ########################### |
504 | extern char LoadedRomFName[2048]; | |
505 | 506 | extern int loadDebugDataFailed; |
506 | 507 | |
507 | 508 | if ((loadDebugDataFailed = loadPreferences(mass_replace(LoadedRomFName, "|", ".").c_str()))) |
724 | 725 | ///Skip may be passed in, if FRAMESKIP is #defined, to cause this to emulate more than one frame |
725 | 726 | void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int skip) { |
726 | 727 | //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; | |
728 | 730 | |
729 | 731 | JustFrameAdvanced = false; |
730 | 732 | |
741 | 743 | { |
742 | 744 | EmulationPaused = EMULATIONPAUSED_FA; |
743 | 745 | } |
744 | if (frameAdvance_Delay_count < frameAdvanceDelayScaled) | |
746 | if ( static_cast<unsigned int>(frameAdvance_Delay_count) < frameAdvanceDelayScaled) | |
745 | 747 | { |
746 | 748 | frameAdvance_Delay_count++; |
747 | 749 | } |
806 | 808 | r = FCEUPPU_Loop(skip); |
807 | 809 | |
808 | 810 | 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(); | |
809 | 814 | |
810 | 815 | #ifdef _S9XLUA_H |
811 | 816 | CallRegisteredLuaFunctions(LUACALL_AFTEREMULATION); |
1060 | 1065 | |
1061 | 1066 | FCEUS FSettings; |
1062 | 1067 | |
1063 | void FCEU_printf(const char *format, ...) | |
1068 | void FCEU_printf( __FCEU_PRINTF_FORMAT const char *format, ...) | |
1064 | 1069 | { |
1065 | 1070 | char temp[2048]; |
1066 | 1071 | |
1080 | 1085 | va_end(ap); |
1081 | 1086 | } |
1082 | 1087 | |
1083 | void FCEU_PrintError(const char *format, ...) | |
1088 | void FCEU_PrintError( __FCEU_PRINTF_FORMAT const char *format, ...) | |
1084 | 1089 | { |
1085 | 1090 | char temp[2048]; |
1086 | 1091 | |
1227 | 1232 | //ideally maybe we shouldnt be using this, but i need it for quick merging |
1228 | 1233 | void FCEUI_SetEmulationPaused(int val) { |
1229 | 1234 | EmulationPaused = val; |
1235 | if(EmulationPaused) | |
1236 | FCEUD_FlushTrace(); | |
1230 | 1237 | } |
1231 | 1238 | |
1232 | 1239 | void FCEUI_ToggleEmulationPause(void) |
1233 | 1240 | { |
1234 | 1241 | EmulationPaused = (EmulationPaused & EMULATIONPAUSED_PAUSED) ^ EMULATIONPAUSED_PAUSED; |
1235 | 1242 | DebuggerWasUpdated = false; |
1243 | if(EmulationPaused) | |
1244 | FCEUD_FlushTrace(); | |
1236 | 1245 | } |
1237 | 1246 | |
1238 | 1247 | void FCEUI_FrameAdvanceEnd(void) { |
1240 | 1249 | } |
1241 | 1250 | |
1242 | 1251 | void FCEUI_FrameAdvance(void) { |
1252 | frameAdvance_Delay_count = 0; | |
1243 | 1253 | frameAdvanceRequested = true; |
1244 | frameAdvance_Delay_count = 0; | |
1245 | 1254 | } |
1246 | 1255 | |
1247 | 1256 | static int AutosaveCounter = 0; |
1258 | 1267 | FCEUSS_Save(f, false); |
1259 | 1268 | AutoSS = true; //Flag that an auto-savestate was made |
1260 | 1269 | free(f); |
1261 | f = NULL; | |
1270 | f = NULL; | |
1262 | 1271 | AutosaveStatus[AutosaveIndex] = 1; |
1263 | 1272 | } |
1264 | 1273 | } |
138 | 138 | |
139 | 139 | bool CheckFileExists(const char* filename); //Receives a filename (fullpath) and checks to see if that file exists |
140 | 140 | |
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 ); | |
145 | 145 | void FCEU_TogglePPU(); |
146 | 146 | |
147 | 147 | void SetNESDeemph_OldHacky(uint8 d, int force); |
28 | 28 | #include "state.h" |
29 | 29 | #include "file.h" |
30 | 30 | #include "cart.h" |
31 | #include "ines.h" | |
31 | 32 | #include "netplay.h" |
32 | 33 | #include "driver.h" |
33 | 34 | #include "movie.h" |
222 | 223 | FCEU_DispMessage("Disk %d Side %c Selected", 0, SelectDisk >> 1, (SelectDisk & 1) ? 'B' : 'A'); |
223 | 224 | } |
224 | 225 | |
225 | #define IRQ_Repeat (IRQa & 0x01) | |
226 | #define IRQ_Enabled (IRQa & 0x02) | |
226 | #define IRQ_Repeat 0x01 | |
227 | #define IRQ_Enabled 0x02 | |
227 | 228 | |
228 | 229 | static void FDSFix(int a) { |
229 | if ((IRQa & IRQ_Enabled) && IRQCount) { | |
230 | if (IRQa & IRQ_Enabled) { | |
230 | 231 | IRQCount -= a; |
231 | 232 | if (IRQCount <= 0) { |
232 | 233 | 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 | */ | |
233 | 243 | X6502_IRQBegin(FCEU_IQEXT); |
234 | 244 | if (!(IRQa & IRQ_Repeat)) { |
235 | 245 | IRQa &= ~IRQ_Enabled; |
573 | 583 | static DECLFW(FDSWrite) { |
574 | 584 | switch (A) { |
575 | 585 | case 0x4020: |
576 | X6502_IRQEnd(FCEU_IQEXT); | |
577 | 586 | IRQLatch &= 0xFF00; |
578 | 587 | IRQLatch |= V; |
579 | 588 | break; |
580 | 589 | case 0x4021: |
581 | X6502_IRQEnd(FCEU_IQEXT); | |
582 | 590 | IRQLatch &= 0xFF; |
583 | 591 | IRQLatch |= V << 8; |
584 | 592 | break; |
585 | 593 | 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 | } | |
589 | 602 | 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; | |
591 | 610 | case 0x4024: |
592 | 611 | if (mapperFDS_diskinsert && ~mapperFDS_control & 0x04) { |
593 | 612 | |
833 | 852 | free(fn); |
834 | 853 | } |
835 | 854 | |
836 | extern char LoadedRomFName[2048]; | |
837 | 855 | strcpy(LoadedRomFName, name); //For the debugger list |
838 | 856 | |
839 | 857 | GameInfo->type = GIT_FDS; |
68 | 68 | |
69 | 69 | if(!ips) return; |
70 | 70 | |
71 | char* buf = (char*)FCEU_dmalloc(fp->size); | |
71 | char* buf = (char*)FCEU_malloc(fp->size); | |
72 | 72 | memcpy(buf,fp->EnsureMemorystream()->buf(),fp->size); |
73 | 73 | |
74 | 74 | |
107 | 107 | if((offset+size)>(uint32)fp->size) |
108 | 108 | { |
109 | 109 | // 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); | |
117 | 111 | buf=newbuf; |
118 | 112 | memset(buf+fp->size,0,offset+size-fp->size); |
119 | 113 | fp->size=offset+size; |
132 | 126 | if((offset+size)>(uint32)fp->size) |
133 | 127 | { |
134 | 128 | // 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); | |
142 | 130 | buf=newbuf; |
143 | 131 | 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 | } | |
146 | 138 | } |
147 | 139 | count++; |
148 | 140 | } |
325 | 317 | { |
326 | 318 | uint32 magic; |
327 | 319 | |
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; | |
331 | 323 | fp->fseek(0,SEEK_SET); |
332 | 324 | |
333 | 325 | if(magic==0x088b1f) { |
337 | 329 | if(gzfile) { |
338 | 330 | delete fp; |
339 | 331 | |
340 | int size; | |
332 | size_t size; | |
341 | 333 | for(size=0; gzgetc(gzfile) != EOF; size++) {} |
342 | 334 | EMUFILE_MEMORY* ms = new EMUFILE_MEMORY(size); |
343 | 335 | gzseek(gzfile,0,SEEK_SET); |
456 | 448 | std::string GetMfn() //Retrieves the movie filename from curMovieFilename (for adding to savestate and auto-save files) |
457 | 449 | { |
458 | 450 | std::string movieFilenamePart; |
459 | extern char curMovieFilename[512]; | |
460 | if(*curMovieFilename) | |
461 | { | |
451 | if (!curMovieFilename.empty()) | |
452 | { | |
462 | 453 | 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); | |
464 | 455 | movieFilenamePart = std::string(".") + name; |
465 | } | |
456 | } | |
466 | 457 | return movieFilenamePart; |
467 | 458 | } |
468 | 459 | |
494 | 485 | va_list ap; |
495 | 486 | int ret; |
496 | 487 | |
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* | |
498 | 489 | return(0); |
499 | 490 | va_start(ap,fmt); |
500 | 491 | ret=vsnprintf(*strp,2048,fmt,ap); |
34 | 34 | int archiveIndex; |
35 | 35 | |
36 | 36 | //the size of the file |
37 | int size; | |
37 | size_t size; | |
38 | 38 | |
39 | 39 | //whether the file is contained in an archive |
40 | 40 | bool isArchive() { return archiveCount > 0; } |
15 | 15 | GIV_USER = 2, //What was set by FCEUI_SetVidSys(). |
16 | 16 | }; |
17 | 17 | |
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 | ||
18 | 40 | enum ESIS |
19 | 41 | { |
20 | 42 | SIS_NONE = 0, |
21 | 43 | SIS_DATACH = 1, |
22 | 44 | SIS_NWC = 2, |
23 | SIS_VSUNISYSTEM = 3, | |
45 | SIS_VSUNISYSTEM = 3, // Is it used? | |
24 | 46 | SIS_NSF = 4, |
25 | 47 | }; |
26 | 48 | |
42 | 64 | |
43 | 65 | SI_COUNT = SI_LCDCOMP_ZAPPER |
44 | 66 | }; |
67 | ||
68 | ||
45 | 69 | |
46 | 70 | inline const char* ESI_Name(ESI esi) |
47 | 71 | { |
136 | 160 | ESI input[2]; //Desired input for emulated input ports 1 and 2; -1 for unknown desired input. |
137 | 161 | ESIFC inputfc; //Desired Famicom expansion port device. -1 for unknown desired input. |
138 | 162 | 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 | |
139 | 166 | |
140 | 167 | MD5DATA MD5; |
141 | 168 |
36 | 36 | #include "cheat.h" |
37 | 37 | #include "vsuni.h" |
38 | 38 | #include "driver.h" |
39 | #include "input.h" | |
39 | 40 | |
40 | 41 | #include <cstdio> |
41 | 42 | #include <cstdlib> |
53 | 54 | static CartInfo iNESCart; |
54 | 55 | |
55 | 56 | uint8 Mirroring = 0; |
57 | uint8 MirroringAs2bits = 0; | |
56 | 58 | uint32 ROM_size = 0; |
57 | 59 | 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]; | |
59 | 62 | |
60 | 63 | static int CHRRAMSize = -1; |
61 | 64 | static int iNES_Init(int num); |
106 | 109 | if (iNESCart.Close) |
107 | 110 | iNESCart.Close(); |
108 | 111 | if (ROM) { |
109 | free(ROM); | |
112 | FCEU_free(ROM); | |
110 | 113 | ROM = NULL; |
111 | 114 | } |
112 | 115 | if (VROM) { |
113 | free(VROM); | |
116 | FCEU_free(VROM); | |
114 | 117 | VROM = NULL; |
115 | 118 | } |
116 | 119 | if (trainerpoo) { |
140 | 143 | ESIFC inputfc; |
141 | 144 | }; |
142 | 145 | |
146 | /* | |
147 | * Function to set input controllers based on CRC | |
148 | */ | |
143 | 149 | static void SetInput(void) { |
144 | 150 | static struct INPSEL moo[] = |
145 | 151 | { |
152 | 158 | {0x48ca0ee1, SI_GAMEPAD, SI_GAMEPAD, SIFC_BWORLD }, // Barcode World |
153 | 159 | {0x4318a2f8, SI_UNSET, SI_ZAPPER, SIFC_NONE }, // Barker Bill's Trick Shooting |
154 | 160 | {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 | |
156 | 162 | {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 | |
158 | 164 | {0x8f7b1669, SI_UNSET, SI_UNSET, SIFC_SUBORKB }, // FP BASIC 3.3 by maxzhou88 |
159 | 165 | {0xf7606810, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC 2.0A |
160 | 166 | {0x895037bc, SI_UNSET, SI_UNSET, SIFC_FKB }, // Family BASIC 2.1a |
214 | 220 | {0x67b126b9, SI_GAMEPAD, SI_GAMEPAD, SIFC_FAMINETSYS }, // Famicom Network System |
215 | 221 | {0x00000000, SI_UNSET, SI_UNSET, SIFC_UNSET } |
216 | 222 | }; |
223 | ||
217 | 224 | int x = 0; |
218 | 225 | |
219 | 226 | while (moo[x].input1 >= 0 || moo[x].input2 >= 0 || moo[x].inputfc >= 0) { |
223 | 230 | GameInfo->inputfc = moo[x].inputfc; |
224 | 231 | break; |
225 | 232 | } |
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; } | |
226 | 291 | x++; |
227 | 292 | } |
228 | 293 | } |
275 | 340 | const TMasterRomInfo* MasterRomInfo; |
276 | 341 | TMasterRomInfoParams MasterRomInfoParams; |
277 | 342 | |
278 | static void CheckHInfo(void) { | |
343 | static void CheckHInfo(uint64 partialmd5) { | |
279 | 344 | /* ROM images that have the battery-backed bit set in the header that really |
280 | 345 | don't have battery-backed RAM is not that big of a problem, so I'll |
281 | 346 | treat this differently by only listing games that should have battery-backed RAM. |
326 | 391 | #include "ines-correct.h" |
327 | 392 | }; |
328 | 393 | 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); | |
334 | 394 | |
335 | 395 | MasterRomInfo = NULL; |
336 | for (int i = 0; i < ARRAY_SIZE(sMasterRomInfo); i++) { | |
396 | for (size_t i = 0; i < ARRAY_SIZE(sMasterRomInfo); i++) { | |
337 | 397 | const TMasterRomInfo& info = sMasterRomInfo[i]; |
338 | 398 | if (info.md5lower != partialmd5) |
339 | 399 | continue; |
342 | 402 | if (!info.params) break; |
343 | 403 | |
344 | 404 | 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++) { | |
346 | 406 | std::vector<std::string> parts = tokenize_str(toks[j], "="); |
347 | 407 | MasterRomInfoParams[parts[0]] = parts[1]; |
348 | 408 | } |
672 | 732 | {"", 215, UNL8237_Init}, |
673 | 733 | {"", 216, Mapper216_Init}, |
674 | 734 | {"", 217, Mapper217_Init}, // Redefined to a new Discrete BMC mapper |
675 | // {"", 218, Mapper218_Init}, | |
735 | {"", 218, Mapper218_Init}, | |
676 | 736 | {"UNLA9746", 219, UNLA9746_Init}, |
677 | 737 | {"Debug Mapper", 220, QTAi_Init}, |
678 | 738 | {"UNLN625092", 221, UNLN625092_Init}, |
709 | 769 | {"SAN GUO ZHI PIRATE", 252, Mapper252_Init}, |
710 | 770 | {"DRAGON BALL PIRATE", 253, Mapper253_Init}, |
711 | 771 | {"", 254, Mapper254_Init}, |
712 | // {"", 255, Mapper255_Init}, // No good dumps for this mapper | |
772 | {"", 255, Mapper255_Init}, // dupe of 225 | |
713 | 773 | |
714 | 774 | //-------- Mappers 256-511 is the Supplementary Multilingual Plane ---------- |
715 | 775 | //-------- Mappers 512-767 is the Supplementary Ideographic Plane ----------- |
726 | 786 | {"F-15 MMC3 Based", 259, BMCF15_Init}, |
727 | 787 | {"HP10xx/H20xx Boards", 260, BMCHPxx_Init}, |
728 | 788 | {"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 }, | |
730 | 792 | |
731 | 793 | {"Impact Soft MMC3 Flash Board", 406, Mapper406_Init }, |
794 | {"INX_007T_V01", 470, INX_007T_Init }, | |
732 | 795 | |
733 | 796 | {"KONAMI QTAi Board", 547, QTAi_Init }, |
734 | 797 | |
736 | 799 | }; |
737 | 800 | |
738 | 801 | int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { |
802 | int result; | |
739 | 803 | struct md5_context md5; |
804 | uint64 partialmd5 = 0; | |
805 | const char* mappername = "Not Listed"; | |
740 | 806 | |
741 | 807 | if (FCEU_fread(&head, 1, 16, fp) != 16 || memcmp(&head, "NES\x1A", 4)) |
742 | 808 | return LOADER_INVALID_FORMAT; |
764 | 830 | Mirroring = 2; |
765 | 831 | } else |
766 | 832 | Mirroring = (head.ROM_type & 1); |
833 | ||
834 | MirroringAs2bits = head.ROM_type & 1; | |
835 | if (head.ROM_type & 8) MirroringAs2bits |= 2; | |
767 | 836 | |
768 | 837 | int not_round_size; |
769 | 838 | if (!iNES2) { |
808 | 877 | } |
809 | 878 | } |
810 | 879 | |
811 | if ((ROM = (uint8*)FCEU_malloc(ROM_size << 14)) == NULL) | |
812 | return 0; | |
880 | ROM = (uint8*)FCEU_malloc(ROM_size << 14); | |
813 | 881 | memset(ROM, 0xFF, ROM_size << 14); |
814 | 882 | |
815 | 883 | 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); | |
822 | 885 | 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 | } | |
823 | 936 | } |
824 | 937 | |
825 | 938 | if (head.ROM_type & 4) { /* Trainer */ |
837 | 950 | if (VROM_size) |
838 | 951 | FCEU_fread(VROM, 0x2000, VROM_size, fp); |
839 | 952 | |
840 | md5_starts(&md5); | |
953 | md5_starts(&md5); | |
841 | 954 | md5_update(&md5, ROM, ROM_size << 14); |
842 | 955 | |
843 | 956 | iNESGameCRC32 = CalcCRC32(0, ROM, ROM_size << 14); |
848 | 961 | } |
849 | 962 | md5_finish(&md5, iNESCart.MD5); |
850 | 963 | 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); | |
851 | 966 | |
852 | 967 | iNESCart.CRC32 = iNESGameCRC32; |
853 | 968 | |
854 | 969 | FCEU_printf(" PRG ROM: %d x 16KiB = %d KiB\n", round ? ROM_size : not_round_size, (round ? ROM_size : not_round_size) * 16); |
855 | 970 | 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); | |
857 | 972 | { |
858 | 973 | int x; |
859 | 974 | FCEU_printf(" ROM MD5: 0x"); |
862 | 977 | FCEU_printf("\n"); |
863 | 978 | } |
864 | 979 | |
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++) { | |
868 | 981 | if (bmap[mappertest].number == MapperNo) { |
869 | 982 | mappername = bmap[mappertest].name; |
870 | 983 | break; |
890 | 1003 | } |
891 | 1004 | |
892 | 1005 | 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 | ||
904 | 1012 | /* Must remain here because above functions might change value of |
905 | 1013 | VROM_size and free(VROM). |
906 | 1014 | */ |
917 | 1025 | |
918 | 1026 | iNESCart.battery = (head.ROM_type & 2) ? 1 : 0; |
919 | 1027 | iNESCart.mirror = Mirroring; |
920 | ||
921 | int result = iNES_Init(MapperNo); | |
1028 | iNESCart.mirrorAs2Bits = MirroringAs2bits; | |
1029 | ||
1030 | result = iNES_Init(MapperNo); | |
922 | 1031 | switch(result) |
923 | 1032 | { |
924 | 1033 | case 0: |
930 | 1039 | FCEU_PrintError("Unable to allocate CHR-RAM."); |
931 | 1040 | break; |
932 | 1041 | } |
1042 | ||
1043 | init_error: | |
933 | 1044 | if (ROM) free(ROM); |
934 | 1045 | if (VROM) free(VROM); |
935 | 1046 | if (trainerpoo) free(trainerpoo); |
994 | 1105 | //caitsith2: done. iNesSave() now gets filename and calls iNesSaveAs with that filename. |
995 | 1106 | FILE *fp; |
996 | 1107 | |
997 | if (GameInfo->type != GIT_CART) return 0; | |
1108 | if ((GameInfo->type != GIT_CART) && (GameInfo->type != GIT_VSUNI)) return 0; | |
998 | 1109 | if (GameInterface != iNESGI) return 0; |
999 | 1110 | |
1000 | 1111 | fp = fopen(name, "wb"); |
23 | 23 | #include <stdlib.h> |
24 | 24 | #include <string.h> |
25 | 25 | #include <map> |
26 | ||
27 | #include "cart.h" | |
26 | 28 | |
27 | 29 | struct TMasterRomInfo |
28 | 30 | { |
42 | 44 | extern uint32 VROM_size; |
43 | 45 | extern uint32 ROM_size; |
44 | 46 | extern uint8 *ExtraNTARAM; |
47 | extern uint8 **VPageR; | |
45 | 48 | extern int iNesSave(void); //bbit Edited: line added |
46 | 49 | 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]; | |
48 | 52 | extern char *iNesShortFName(void); |
49 | 53 | extern const TMasterRomInfo* MasterRomInfo; |
50 | 54 | extern TMasterRomInfoParams MasterRomInfoParams; |
51 | 55 | |
52 | 56 | //mbg merge 7/19/06 changed to c++ decl format |
53 | 57 | 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 | |
66 | 71 | |
67 | 72 | void cleanup() |
68 | 73 | { |
241 | 246 | void Mapper214_Init(CartInfo *); |
242 | 247 | void Mapper216_Init(CartInfo *); |
243 | 248 | void Mapper217_Init(CartInfo *); |
249 | void Mapper218_Init(CartInfo *); | |
244 | 250 | void Mapper220_Init(CartInfo *); |
245 | 251 | void Mapper222_Init(CartInfo *); |
246 | 252 | void Mapper225_Init(CartInfo *); |
267 | 273 | void Mapper252_Init(CartInfo *); |
268 | 274 | void Mapper253_Init(CartInfo *); |
269 | 275 | void Mapper254_Init(CartInfo *); |
276 | void Mapper255_Init(CartInfo *); | |
277 | void Mapper354_Init(CartInfo *); | |
270 | 278 | void Mapper406_Init(CartInfo *); |
279 | ||
280 | void INX_007T_Init(CartInfo* info); | |
271 | 281 | |
272 | 282 | typedef struct { |
273 | 283 | const char *name; |
105 | 105 | } |
106 | 106 | |
107 | 107 | extern uint8 coinon; |
108 | extern uint8 coinon2; | |
109 | extern uint8 service; | |
108 | 110 | |
109 | 111 | //set to true if the fourscore is attached |
110 | 112 | static bool FSAttached = false; |
430 | 432 | portFC.driver->Update(portFC.ptr,portFC.attrib); |
431 | 433 | } |
432 | 434 | |
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 | } | |
435 | 440 | |
436 | 441 | if(FCEUnetplay) |
437 | 442 | NetplayUpdate(joy); |
453 | 458 | |
454 | 459 | ret|=(vsdip&3)<<3; |
455 | 460 | if(coinon) |
456 | ret|=0x4; | |
461 | ret |= 0x20; | |
462 | if (coinon2) | |
463 | ret |= 0x40; | |
464 | if (service) | |
465 | ret |= 0x04; | |
457 | 466 | return ret; |
458 | 467 | } |
459 | 468 | |
667 | 676 | { |
668 | 677 | case FCEUNPCMD_FDSINSERT: FCEU_FDSInsert();break; |
669 | 678 | 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; | |
671 | 682 | case FCEUNPCMD_VSUNIDIP0: |
672 | 683 | case FCEUNPCMD_VSUNIDIP0+1: |
673 | 684 | case FCEUNPCMD_VSUNIDIP0+2: |
723 | 734 | return; |
724 | 735 | |
725 | 736 | 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); | |
726 | 753 | } |
727 | 754 | |
728 | 755 | //Resets the frame counter if movie inactive and rom is reset or power-cycle |
797 | 824 | static void RamSearchOpGTE(void); |
798 | 825 | static void RamSearchOpEQ(void); |
799 | 826 | static void RamSearchOpNE(void); |
827 | static void ToggleCheats(void); | |
800 | 828 | static void DebuggerStepInto(void); |
801 | 829 | static void FA_SkipLag(void); |
802 | 830 | static void OpenRom(void); |
899 | 927 | { EMUCMD_FDS_EJECT_INSERT, EMUCMDTYPE_FDS, FCEUI_FDSInsert, 0, 0, "Eject or Insert FDS Disk", EMUCMDFLAG_TASEDITOR }, |
900 | 928 | { EMUCMD_FDS_SIDE_SELECT, EMUCMDTYPE_FDS, FCEUI_FDSSelect, 0, 0, "Switch FDS Disk Side", EMUCMDFLAG_TASEDITOR }, |
901 | 929 | |
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 }, | |
913 | 941 | |
914 | 942 | { EMUCMD_MISC_AUTOSAVE, EMUCMDTYPE_MISC, FCEUI_RewindToLastAutosave, 0, 0, "Load Last Auto-save", 0}, |
915 | 943 | { EMUCMD_MISC_SHOWSTATES, EMUCMDTYPE_MISC, ViewSlots, 0, 0, "View save slots", 0 }, |
944 | 972 | { EMUCMD_TOOL_RAMSEARCHGTE, EMUCMDTYPE_TOOL, RamSearchOpGTE, 0, 0, "Ram Search - Greater Than or Equal", 0}, |
945 | 973 | { EMUCMD_TOOL_RAMSEARCHEQ, EMUCMDTYPE_TOOL, RamSearchOpEQ, 0, 0, "Ram Search - Equal", 0}, |
946 | 974 | { 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}, | |
947 | 976 | { EMUCMD_RERECORD_DISPLAY_TOGGLE, EMUCMDTYPE_MISC, FCEUI_MovieToggleRerecordDisplay,0, 0, "Toggle Rerecord Display", EMUCMDFLAG_TASEDITOR }, |
948 | 977 | |
949 | 978 | { EMUCMD_TASEDITOR_REWIND, EMUCMDTYPE_TASEDITOR, TaseditorRewindOn, TaseditorRewindOff, 0, "Frame Rewind", EMUCMDFLAG_TASEDITOR }, |
959 | 988 | |
960 | 989 | #define NUM_EMU_CMDS (sizeof(FCEUI_CommandTable)/sizeof(FCEUI_CommandTable[0])) |
961 | 990 | |
962 | static int execcmd, i; | |
991 | static int execcmd; | |
963 | 992 | |
964 | 993 | void FCEUI_HandleEmuCommands(TestCommandState* testfn) |
965 | 994 | { |
966 | 995 | 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) | |
968 | 997 | { |
969 | 998 | int new_state; |
970 | 999 | int old_state = FCEUI_CommandTable[i].state; |
1267 | 1296 | #endif |
1268 | 1297 | } |
1269 | 1298 | |
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 | ||
1270 | 1311 | static void DebuggerStepInto() |
1271 | 1312 | { |
1272 | 1313 | #ifdef __WIN_DRIVER__ |
1323 | 1364 | |
1324 | 1365 | static void UndoRedoSavestate(void) |
1325 | 1366 | { |
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)) | |
1330 | 1368 | SwapSaveState(); |
1331 | 1369 | } |
1332 | 1370 | |
1379 | 1417 | **/ |
1380 | 1418 | EMUCMDTABLE* GetEmuCommandById(int cmd) |
1381 | 1419 | { |
1382 | for (i = 0; i<NUM_EMU_CMDS; ++i) | |
1420 | for (size_t i = 0; i<NUM_EMU_CMDS; ++i) | |
1383 | 1421 | { |
1384 | 1422 | if (FCEUI_CommandTable[i].cmd == cmd) |
1385 | 1423 | return &FCEUI_CommandTable[i]; |
196 | 196 | EMUCMD_VSUNI_TOGGLE_DIP_5, |
197 | 197 | EMUCMD_VSUNI_TOGGLE_DIP_6, |
198 | 198 | 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, | |
201 | 201 | EMUCMD_MISC_AUTOSAVE, |
202 | 202 | EMUCMD_MISC_SHOWSTATES, |
203 | 203 | EMUCMD_MISC_USE_INPUT_PRESET_1, |
258 | 258 | EMUCMD_MOVIE_RECORD_MODE_OVERWRITE, |
259 | 259 | EMUCMD_MOVIE_RECORD_MODE_INSERT, |
260 | 260 | |
261 | EMUCMD_TOOL_TOGGLECHEATS, | |
262 | ||
261 | 263 | EMUCMD_MAX |
262 | 264 | }; |
263 | 265 |
23 | 23 | #include "file.h" |
24 | 24 | #include "video.h" |
25 | 25 | #include "debug.h" |
26 | #include "debugsymboltable.h" | |
26 | 27 | #include "sound.h" |
27 | 28 | #include "drawing.h" |
28 | 29 | #include "state.h" |
53 | 54 | #ifdef __SDL__ |
54 | 55 | |
55 | 56 | #ifdef __QT_DRIVER__ |
57 | #include "drivers/Qt/sdl.h" | |
58 | #include "drivers/Qt/main.h" | |
59 | #include "drivers/Qt/input.h" | |
56 | 60 | #include "drivers/Qt/fceuWrapper.h" |
57 | 61 | #include "drivers/Qt/TasEditor/selection.h" |
58 | 62 | #include "drivers/Qt/TasEditor/laglog.h" |
181 | 185 | persisted = true; |
182 | 186 | FILE* inf = fopen(filename.c_str(),"rb"); |
183 | 187 | fseek(inf,0,SEEK_END); |
184 | int len = ftell(inf); | |
188 | long int len = ftell(inf); | |
185 | 189 | fseek(inf,0,SEEK_SET); |
186 | 190 | 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 | } | |
188 | 195 | fclose(inf); |
189 | 196 | } |
190 | 197 | }; |
249 | 256 | static int frameAdvanceWaiting = FALSE; |
250 | 257 | |
251 | 258 | // We save our pause status in the case of a natural death. |
252 | static int wasPaused = FALSE; | |
259 | //static int wasPaused = FALSE; | |
253 | 260 | |
254 | 261 | // Transparency strength. 255=opaque, 0=so transparent it's invisible |
255 | 262 | static int transparencyModifier = 255; |
655 | 662 | return 0; |
656 | 663 | #elif defined(__QT_DRIVER__) |
657 | 664 | 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() ); | |
664 | 670 | |
665 | 671 | //lua_cpcall(L, emu_wait_for_rom_load, NULL); |
666 | 672 | //printf("Attempting to Load ROM: '%s'\n", nameo ); |
742 | 748 | |
743 | 749 | while (FCEUI_GetCheat(i,NULL,&Caddr,&Cval,&Ccompare,NULL,&Ctype)) { |
744 | 750 | |
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)) { | |
746 | 752 | // Already Added, so consider it a success |
747 | 753 | lua_pushboolean(L, true); |
748 | 754 | return 1; |
772 | 778 | int GGaddr, GGcomp, GGval; |
773 | 779 | uint32 i=0; |
774 | 780 | |
775 | char * Cname; | |
781 | std::string Cname; | |
776 | 782 | uint32 Caddr; |
777 | 783 | uint8 Cval; |
778 | 784 | int Ccompare, Ctype; |
785 | 791 | |
786 | 792 | while (FCEUI_GetCheat(i,&Cname,&Caddr,&Cval,&Ccompare,NULL,&Ctype)) { |
787 | 793 | |
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)) { | |
789 | 795 | // Delete cheat code |
790 | 796 | if (FCEUI_DelCheat(i)) { |
791 | 797 | lua_pushboolean(L, true); |
1301 | 1307 | for(int i=0;i<4;i++) |
1302 | 1308 | { |
1303 | 1309 | int r = 0; |
1304 | fread(&r, 1, 1, file); | |
1310 | if ( fread(&r, 1, 1, file) == 0) | |
1311 | { | |
1312 | break; | |
1313 | } | |
1305 | 1314 | rv |= r << (i*8); |
1306 | 1315 | } |
1307 | 1316 | value = rv; |
1345 | 1354 | break; |
1346 | 1355 | |
1347 | 1356 | 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 | } | |
1349 | 1361 | |
1350 | 1362 | Record* next = new Record(); |
1351 | 1363 | memcpy(next, cur, sizeof(Record)); |
1631 | 1643 | if(remaining <= 0) |
1632 | 1644 | return; |
1633 | 1645 | |
1634 | const char* str = ptr; // for debugging | |
1646 | //const char* str = ptr; // for debugging | |
1635 | 1647 | |
1636 | 1648 | // if there is a __tostring metamethod then call it |
1637 | 1649 | int usedMeta = luaL_callmeta(L, i, "__tostring"); |
1993 | 2005 | { |
1994 | 2006 | const char* qualifiedRegisterName = luaL_checkstring(L,1); |
1995 | 2007 | 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++) | |
1997 | 2009 | { |
1998 | 2010 | cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu]; |
1999 | 2011 | int cpuNameLen = strlen(ctrm.cpuName); |
2027 | 2039 | const char* qualifiedRegisterName = luaL_checkstring(L,1); |
2028 | 2040 | unsigned long value = (unsigned long)(luaL_checkinteger(L,2)); |
2029 | 2041 | 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++) | |
2031 | 2043 | { |
2032 | 2044 | cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu]; |
2033 | 2045 | int cpuNameLen = strlen(ctrm.cpuName); |
2243 | 2255 | #endif |
2244 | 2256 | lua_settop(L, 0); |
2245 | 2257 | 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++) | |
2247 | 2259 | { |
2248 | 2260 | lua_rawgeti(L, -1, i); |
2249 | 2261 | if (lua_isfunction(L, -1)) |
2447 | 2459 | case LUAMEMHOOK_WRITE: return LUAMEMHOOK_WRITE_SUB; |
2448 | 2460 | case LUAMEMHOOK_READ: return LUAMEMHOOK_READ_SUB; |
2449 | 2461 | case LUAMEMHOOK_EXEC: return LUAMEMHOOK_EXEC_SUB; |
2462 | default: return hookType; | |
2450 | 2463 | } |
2451 | 2464 | } |
2452 | 2465 | return hookType; |
2456 | 2469 | { |
2457 | 2470 | return memory_registerHook(L, MatchHookTypeToCPU(L,LUAMEMHOOK_WRITE), 1); |
2458 | 2471 | } |
2472 | FCEU_MAYBE_UNUSED | |
2459 | 2473 | static int memory_registerread(lua_State *L) |
2460 | 2474 | { |
2461 | 2475 | return memory_registerHook(L, MatchHookTypeToCPU(L,LUAMEMHOOK_READ), 1); |
2637 | 2651 | } |
2638 | 2652 | } |
2639 | 2653 | } |
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 | } | |
2640 | 2760 | #else |
2641 | 2761 | //SDL TODO: implement this for keyboard!! |
2642 | 2762 | #endif |
3116 | 3236 | { |
3117 | 3237 | LuaSaveData saveData; |
3118 | 3238 | |
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"); | |
3124 | 3243 | if(luaSaveFile) |
3125 | 3244 | { |
3126 | 3245 | saveData.ImportRecords(luaSaveFile); |
3742 | 3861 | *colour = ((rand()*255/RAND_MAX) << 8) | ((rand()*255/RAND_MAX) << 16) | ((rand()*255/RAND_MAX) << 24) | 0xFF; |
3743 | 3862 | return true; |
3744 | 3863 | } |
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++) { | |
3746 | 3865 | if(!stricmp(str,s_colorMapping[i].name)) { |
3747 | 3866 | *colour = s_colorMapping[i].value; |
3748 | 3867 | return true; |
3778 | 3897 | lua_pushnil(L); // first key |
3779 | 3898 | int keyIndex = lua_gettop(L); |
3780 | 3899 | int valueIndex = keyIndex + 1; |
3781 | bool first = true; | |
3782 | 3900 | while(lua_next(L, offset)) |
3783 | 3901 | { |
3784 | 3902 | bool keyIsString = (lua_type(L, keyIndex) == LUA_TSTRING); |
3984 | 4102 | } |
3985 | 4103 | |
3986 | 4104 | // (old) gui.box(x1, y1, x2, y2, color) |
4105 | FCEU_MAYBE_UNUSED | |
3987 | 4106 | static int gui_box_old(lua_State *L) { |
3988 | 4107 | |
3989 | 4108 | int x1,y1,x2,y2; |
4313 | 4432 | } |
4314 | 4433 | } |
4315 | 4434 | |
4435 | FCEU_MAYBE_UNUSED | |
4316 | 4436 | static int strlinelen(const char* string) |
4317 | 4437 | { |
4318 | 4438 | const char* s = string; |
4323 | 4443 | return s - string; |
4324 | 4444 | } |
4325 | 4445 | |
4446 | FCEU_MAYBE_UNUSED | |
4326 | 4447 | static void LuaDisplayString (const char *string, int y, int x, uint32 color, uint32 outlineColor) |
4327 | 4448 | { |
4328 | 4449 | if(!string) |
4490 | 4611 | return; |
4491 | 4612 | |
4492 | 4613 | 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)); | |
4494 | 4615 | int diffx; |
4495 | 4616 | int diffy = std::max<int>(0, std::min<int>(7, LUA_SCREEN_HEIGHT - y)); |
4496 | 4617 | |
4559 | 4680 | // main HUD. |
4560 | 4681 | static int gui_text(lua_State *L) { |
4561 | 4682 | |
4562 | extern int font_height; | |
4683 | //extern int font_height; | |
4563 | 4684 | const char *msg; |
4564 | 4685 | int x, y; |
4565 | 4686 | size_t l; |
4956 | 5077 | return 0; |
4957 | 5078 | } |
4958 | 5079 | |
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 | ||
4959 | 5101 | // TAS Editor functions library |
4960 | 5102 | |
4961 | 5103 | // bool taseditor.registerauto() |
4977 | 5119 | if (!lua_isnil(L,1)) |
4978 | 5120 | luaL_checktype(L, 1, LUA_TFUNCTION); |
4979 | 5121 | |
4980 | const char* caption = NULL; | |
5122 | FCEU_MAYBE_UNUSED const char* caption = NULL; | |
4981 | 5123 | if (!lua_isnil(L, 2)) |
4982 | 5124 | caption = lua_tostring(L, 2); |
4983 | 5125 | |
5363 | 5505 | assert(iicon >= 0 && iicon <= 3); |
5364 | 5506 | if(!(iicon >= 0 && iicon <= 3)) iicon = 0; |
5365 | 5507 | |
5508 | #ifdef __WIN_DRIVER__ | |
5366 | 5509 | static const char * const titles [] = {"Notice", "Question", "Warning", "Error"}; |
5367 | 5510 | const char* answer = "ok"; |
5368 | 5511 | |
5369 | #ifdef __WIN_DRIVER__ | |
5370 | 5512 | static const int etypes [] = {MB_OK, MB_YESNO, MB_YESNOCANCEL, MB_OKCANCEL, MB_ABORTRETRYIGNORE}; |
5371 | 5513 | static const int eicons [] = {MB_ICONINFORMATION, MB_ICONQUESTION, MB_ICONWARNING, MB_ICONERROR}; |
5372 | 5514 | //StopSound(); //mbg merge 7/27/08 |
5511 | 5653 | // We don't want parameters |
5512 | 5654 | if (!t[0]) { |
5513 | 5655 | 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 | } | |
5515 | 5660 | // We're done |
5516 | 5661 | return 0; |
5517 | 5662 | |
5518 | 5663 | } |
5519 | 5664 | 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 | } | |
5521 | 5670 | |
5522 | 5671 | // Check if the option is in the list |
5523 | 5672 | if (strchr(t, tolower(buffer[0]))) { |
5570 | 5719 | // TODO: more sophisticated interface |
5571 | 5720 | char filename[PATH_MAX]; |
5572 | 5721 | 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 | } | |
5574 | 5727 | lua_newtable(L); |
5575 | 5728 | lua_pushstring(L, filename); |
5576 | 5729 | lua_rawseti(L, -2, 1); |
5801 | 5954 | } |
5802 | 5955 | |
5803 | 5956 | // The function called periodically to ensure Lua doesn't run amok. |
5957 | FCEU_MAYBE_UNUSED | |
5804 | 5958 | static void FCEU_LuaHookFunction(lua_State *L, lua_Debug *dbg) { |
5805 | 5959 | |
5806 | 5960 | if (numTries-- == 0) { |
6126 | 6280 | {"getinstructionscount", debugger_getinstructionscount}, |
6127 | 6281 | {"resetcyclescount", debugger_resetcyclescount}, |
6128 | 6282 | {"resetinstructionscount", debugger_resetinstructionscount}, |
6283 | {"getsymboloffset", debugger_getsymboloffset}, | |
6129 | 6284 | {NULL,NULL} |
6130 | 6285 | }; |
6131 | 6286 | |
6287 | 6442 | |
6288 | 6443 | getfilepath = getfilepath.substr(0,getfilepath.find_last_of("/\\") + 1); |
6289 | 6444 | |
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 | } | |
6291 | 6449 | |
6292 | 6450 | //stop any lua we might already have had running |
6293 | 6451 | FCEU_LuaStop(); |
113 | 113 | { 0 } |
114 | 114 | }; |
115 | 115 | |
116 | char curMovieFilename[512] = {0}; | |
116 | std::string curMovieFilename; | |
117 | 117 | MovieData currMovieData; |
118 | 118 | MovieData defaultMovieData; |
119 | 119 | int currRerecordCount; // Keep the global value |
408 | 408 | , rerecordCount(0) |
409 | 409 | , binaryFlag(false) |
410 | 410 | , loadFrameCount(-1) |
411 | , fourscore(false) | |
411 | 412 | , microphone(false) |
412 | 413 | , RAMInitOption(0) |
413 | 414 | , RAMInitSeed(0) |
691 | 692 | { |
692 | 693 | LoadFM2_binarychunk(movieData, fp, size); |
693 | 694 | return true; |
694 | } else if (isnewline && movieData.loadFrameCount == movieData.records.size()) | |
695 | } else if (isnewline && static_cast<size_t>(movieData.loadFrameCount) == movieData.records.size()) | |
695 | 696 | // exit prematurely if loaded the specified amound of records |
696 | 697 | return true; |
697 | 698 | switch(state) |
805 | 806 | FCEU_PrintError("Error opening movie output file: %s", fname); |
806 | 807 | return NULL; |
807 | 808 | } |
808 | strcpy(curMovieFilename, fname); | |
809 | if ( fname != curMovieFilename.c_str() ) | |
810 | { | |
811 | curMovieFilename.assign(fname); | |
812 | } | |
809 | 813 | |
810 | 814 | return osRecordingMovie; |
811 | 815 | } |
825 | 829 | bool recording = (movieMode == MOVIEMODE_RECORD); |
826 | 830 | assert((NULL != osRecordingMovie) == (recording != justToggledRecording) && "osRecordingMovie should be consistent with movie mode!"); |
827 | 831 | |
828 | if (NULL == openRecordingMovie(curMovieFilename)) | |
832 | if (NULL == openRecordingMovie(curMovieFilename.c_str())) | |
829 | 833 | return; |
830 | 834 | |
831 | 835 | currMovieData.dump(osRecordingMovie, false/*currMovieData.binaryFlag*/, recording); |
873 | 877 | { |
874 | 878 | assert(movieMode == MOVIEMODE_INACTIVE); |
875 | 879 | |
876 | curMovieFilename[0] = 0; //No longer a current movie filename | |
880 | curMovieFilename.clear(); //No longer a current movie filename | |
877 | 881 | freshMovie = false; //No longer a fresh movie loaded |
878 | 882 | if (bindSavestate) AutoSS = false; //If bind movies to savestates is true, then there is no longer a valid auto-save to load |
879 | 883 | |
989 | 993 | return false; |
990 | 994 | } |
991 | 995 | |
992 | if(currCartInfo->SaveGameLen[i] != len) | |
996 | if(currCartInfo->SaveGameLen[i] != static_cast<unsigned int>(len)) | |
993 | 997 | { |
994 | 998 | FCEU_PrintError("movie battery load mismatch 3"); |
995 | 999 | return false; |
1038 | 1042 | |
1039 | 1043 | currMovieData = MovieData(); |
1040 | 1044 | |
1041 | strcpy(curMovieFilename, fname); | |
1045 | curMovieFilename.assign(fname); | |
1042 | 1046 | FCEUFILE *fp = FCEU_fopen(fname,0,"rb",0); |
1043 | 1047 | if (!fp) return false; |
1044 | 1048 | if(fp->isArchive() && !_read_only) { |
1219 | 1223 | if (mr->command_fds_select()) |
1220 | 1224 | FCEU_FDSSelect(); |
1221 | 1225 | 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(); | |
1223 | 1231 | _currCommand = 0; |
1224 | 1232 | } else |
1225 | 1233 | #endif |
1247 | 1255 | if(mr->command_fds_select()) |
1248 | 1256 | FCEU_FDSSelect(); |
1249 | 1257 | 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(); | |
1251 | 1263 | |
1252 | 1264 | joyports[0].load(mr); |
1253 | 1265 | joyports[1].load(mr); |
1254 | 1266 | } |
1255 | 1267 | |
1256 | 1268 | //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) | |
1258 | 1270 | { |
1259 | 1271 | if(FCEUD_PauseAfterPlayback()) |
1260 | 1272 | { |
1325 | 1337 | case FCEUNPCMD_FDSINSERT: cmd = MOVIECMD_FDS_INSERT; break; |
1326 | 1338 | case FCEUNPCMD_FDSSELECT: cmd = MOVIECMD_FDS_SELECT; break; |
1327 | 1339 | 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; | |
1328 | 1342 | // all other netplay commands (e.g. FCEUNPCMD_VSUNIDIP0) are not supported by movie recorder for now |
1329 | 1343 | default: return; |
1330 | 1344 | } |
1433 | 1447 | #endif |
1434 | 1448 | movie_readonly = true; |
1435 | 1449 | } |
1436 | if (FCEU_isFileInArchive(curMovieFilename)) | |
1450 | if (FCEU_isFileInArchive(curMovieFilename.c_str())) | |
1437 | 1451 | { |
1438 | 1452 | //a little rule: cant load states in read+write mode with a movie from an archive. |
1439 | 1453 | //so we are going to switch it to readonly mode in that case |
1568 | 1582 | //TODO: turn frame counter to red to get attention |
1569 | 1583 | if (!backupSavestates) //If backups are disabled we can just resume normally since we can't restore so stop movie and inform user |
1570 | 1584 | { |
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); | |
1572 | 1586 | FCEUI_StopMovie(); |
1573 | 1587 | } 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); | |
1575 | 1589 | return false; |
1576 | 1590 | } |
1577 | 1591 | } |
1727 | 1741 | strcpy(message, "Movie is now Read+Write"); |
1728 | 1742 | |
1729 | 1743 | strcat(message, GetMovieModeStr()); |
1730 | FCEU_DispMessage(message,0); | |
1744 | FCEU_DispMessage("%s",0,message); | |
1731 | 1745 | } |
1732 | 1746 | |
1733 | 1747 | void FCEUI_MovieToggleRecording() |
1771 | 1785 | |
1772 | 1786 | strcat(message, GetMovieModeStr()); |
1773 | 1787 | |
1774 | FCEU_DispMessage(message, 0); | |
1788 | FCEU_DispMessage("%s",0,message); | |
1775 | 1789 | } |
1776 | 1790 | |
1777 | 1791 | void FCEUI_MovieInsertFrame() |
1798 | 1812 | strcat(message, GetMovieModeStr()); |
1799 | 1813 | } |
1800 | 1814 | |
1801 | FCEU_DispMessage(message, 0); | |
1815 | FCEU_DispMessage("%s",0,message); | |
1802 | 1816 | } |
1803 | 1817 | |
1804 | 1818 | void FCEUI_MovieDeleteFrame() |
1836 | 1850 | strcat(message, GetMovieModeStr()); |
1837 | 1851 | } |
1838 | 1852 | |
1839 | FCEU_DispMessage(message, 0); | |
1853 | FCEU_DispMessage("%s",0,message); | |
1840 | 1854 | } |
1841 | 1855 | |
1842 | 1856 | void FCEUI_MovieTruncate() |
1874 | 1888 | strcat(message, GetMovieModeStr()); |
1875 | 1889 | } |
1876 | 1890 | |
1877 | FCEU_DispMessage(message, 0); | |
1891 | FCEU_DispMessage("%s",0,message); | |
1878 | 1892 | } |
1879 | 1893 | |
1880 | 1894 | void FCEUI_MovieNextRecordMode() |
1944 | 1958 | #endif |
1945 | 1959 | } |
1946 | 1960 | |
1947 | string FCEUI_GetMovieName(void) | |
1961 | std::string FCEUI_GetMovieName(void) | |
1948 | 1962 | { |
1949 | 1963 | return curMovieFilename; |
1950 | 1964 | } |
2038 | 2052 | void FCEUI_MakeBackupMovie(bool dispMessage) |
2039 | 2053 | { |
2040 | 2054 | //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 | |
2044 | 2058 | stringstream stream; |
2045 | 2059 | int x; //Temp variable for string manip |
2046 | 2060 | bool exist = false; //Used to test if filename exists |
80 | 80 | MOVIECMD_POWER = 2, |
81 | 81 | MOVIECMD_FDS_INSERT = 4, |
82 | 82 | MOVIECMD_FDS_SELECT = 8, |
83 | MOVIECMD_VS_INSERTCOIN = 16 | |
83 | MOVIECMD_VS_INSERTCOIN = 16, | |
84 | MOVIECMD_VS_INSERTCOIN2 = 32, | |
85 | MOVIECMD_VS_SERVICE = 64 | |
84 | 86 | }; |
85 | 87 | |
86 | 88 | EMOVIEMODE FCEUMOV_Mode(); |
130 | 132 | bool command_fds_insert() { return (commands & MOVIECMD_FDS_INSERT) != 0; } |
131 | 133 | bool command_fds_select() { return (commands & MOVIECMD_FDS_SELECT) != 0; } |
132 | 134 | 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; } | |
133 | 137 | |
134 | 138 | void toggleBit(int joy, int bit) |
135 | 139 | { |
209 | 213 | //whether microphone is enabled |
210 | 214 | bool microphone; |
211 | 215 | |
212 | int getNumRecords() { return (int)records.size(); } | |
216 | int getNumRecords() { return static_cast<int>( records.size() ); } | |
213 | 217 | |
214 | 218 | int RAMInitOption, RAMInitSeed; |
215 | 219 | |
271 | 275 | extern EMOVIEMODE movieMode; |
272 | 276 | extern MovieData currMovieData; |
273 | 277 | extern int currFrameCounter; |
274 | extern char curMovieFilename[512]; | |
278 | extern std::string curMovieFilename; | |
275 | 279 | extern bool subtitlesOnAVI; |
276 | 280 | extern bool freshMovie; |
277 | 281 | extern bool movie_readonly; |
121 | 121 | FCEUX_fstat(fileno(fp),&sb); |
122 | 122 | len = sb.st_size; |
123 | 123 | 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 | } | |
125 | 128 | fclose(fp); |
126 | 129 | |
127 | 130 | cbuf = (char*)FCEU_dmalloc(4 + len + len / 1000 + 12); //mbg merge 7/17/06 added cast |
6 | 6 | #define FCEUNPCMD_POWER 0x02 |
7 | 7 | |
8 | 8 | #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 | ||
10 | 13 | #define FCEUNPCMD_FDSINSERTx 0x10 |
11 | 14 | #define FCEUNPCMD_FDSINSERT 0x18 |
12 | 15 | //#define FCEUNPCMD_FDSEJECT 0x19 |
31 | 31 | #include "file.h" |
32 | 32 | #include "fds.h" |
33 | 33 | #include "cart.h" |
34 | #include "ines.h" | |
34 | 35 | #include "input.h" |
35 | 36 | #include "state.h" |
36 | 37 | #include "driver.h" |
122 | 123 | static uint16 InitAddr; //configuration |
123 | 124 | static uint16 LoadAddr; //configuration |
124 | 125 | |
125 | extern char LoadedRomFName[2048]; | |
126 | ||
127 | 126 | NSF_HEADER NSFHeader; //mbg merge 6/29/06 - needs to be global |
128 | 127 | |
129 | 128 | void NSFMMC5_Close(void); |
47 | 47 | static uint8 joopcmd; |
48 | 48 | static uint32 framets = 0; |
49 | 49 | static uint32 frameptr = 0; |
50 | static uint8* moviedata = NULL; | |
50 | static uint8* moviedata = nullptr; | |
51 | 51 | static uint32 moviedatasize = 0; |
52 | 52 | static uint32 firstframeoffset = 0; |
53 | 53 | static uint32 savestate_offset = 0; |
625 | 625 | //ResetInputTypes(); |
626 | 626 | |
627 | 627 | 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 | } | |
629 | 641 | fp->fread((char*)moviedata,moviedatasize); |
630 | 642 | |
631 | 643 | frameptr = 0; |
668 | 680 | md.ports[0] = md.ports[1] = SI_GAMEPAD; |
669 | 681 | } |
670 | 682 | |
671 | free(moviedata); | |
672 | moviedata = 0; | |
683 | if (moviedata) | |
684 | { | |
685 | free(moviedata); | |
686 | moviedata = nullptr; | |
687 | } | |
673 | 688 | |
674 | 689 | delete fp; |
675 | 690 | return FCM_CONVERTRESULT_SUCCESS; |
9 | 9 | FCM_CONVERTRESULT_OLDVERSION, |
10 | 10 | FCM_CONVERTRESULT_UNSUPPORTEDVERSION, |
11 | 11 | FCM_CONVERTRESULT_STARTFROMSAVESTATENOTSUPPORTED, |
12 | FCM_CONVERTRESULT_REALLOC_FAIL, | |
12 | 13 | }; |
13 | 14 | |
14 | 15 | inline const char * EFCM_CONVERTRESULT_message(EFCM_CONVERTRESULT e) |
86 | 86 | (type) (y + to_rgb [4] * i + to_rgb [5] * q)\ |
87 | 87 | ) |
88 | 88 | |
89 | FCEU_MAYBE_UNUSED | |
89 | 90 | static void ApplyDeemphasisNTSC(int entry, u8& r, u8& g, u8& b) |
90 | 91 | { |
91 | 92 | static float const to_float = 1.0f / 0xFF; |
251 | 252 | } |
252 | 253 | |
253 | 254 | //classic algorithm |
255 | FCEU_MAYBE_UNUSED | |
254 | 256 | static void ApplyDeemphasisClassic(int entry, u8& r, u8& g, u8& b) |
255 | 257 | { |
256 | 258 | //DEEMPH BITS MAY BE ORDERED WRONG. PLEASE CHECK |
3 | 3 | #define EMPTY_PALETTE_64 EMPTY_PALETTE_16 EMPTY_PALETTE_16 EMPTY_PALETTE_16 EMPTY_PALETTE_16 |
4 | 4 | #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 |
5 | 5 | |
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 | ||
6 | 9 | pal rp2c04001[512] = { |
7 | 10 | #include "rp2c04001.h" |
8 | 11 | EMPTY_PALETTE_DEEMPH_X_7 |
22 | 25 | EMPTY_PALETTE_DEEMPH_X_7 |
23 | 26 | }; |
24 | 27 | |
28 | #undef P64RPC | |
29 | ||
25 | 30 | // Fixed palette entries used by the GUI |
26 | 31 | 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 | |
31 | 36 | { 190, 0, 0}, // 4 = Reddish |
32 | 37 | { 51,255, 51}, // 5 = Bright green |
33 | 38 | { 49, 14,200}, // 6 = Ultramarine Blue |
51 | 56 | }; |
52 | 57 | |
53 | 58 | |
59 | #define P64(x) (((x)<<2)|((x>>4)&3)) | |
60 | ||
54 | 61 | // Default palette |
55 | 62 | 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 | |
121 | 129 | |
122 | 130 | //luke's .16+ palette |
123 | 131 | //{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)}, |
56 | 56 | |
57 | 57 | #define PPU_status (PPU[2]) |
58 | 58 | |
59 | #define READPALNOGS(ofs) (PALRAM[(ofs)]) | |
59 | 60 | #define READPAL(ofs) (PALRAM[(ofs)] & (GRAYSCALE ? 0x30 : 0xFF)) |
60 | 61 | #define READUPAL(ofs) (UPALRAM[(ofs)] & (GRAYSCALE ? 0x30 : 0xFF)) |
61 | 62 | |
454 | 455 | unsigned char *cdloggervdata = NULL; |
455 | 456 | unsigned int cdloggerVideoDataSize = 0; |
456 | 457 | |
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 | } | |
460 | 467 | if ((result >= 0) && (result < (int)cdloggerVideoDataSize)) |
468 | { | |
461 | 469 | return result; |
462 | } else | |
463 | if(A < 0x2000) return A; | |
470 | } | |
471 | } | |
472 | else | |
473 | { | |
474 | if ( (A >= 0) && (A < 0x2000) ) return A; | |
475 | } | |
464 | 476 | return -1; |
465 | 477 | } |
466 | 478 | |
1986 | 1998 | struct BGData { |
1987 | 1999 | struct Record { |
1988 | 2000 | uint8 nt, pecnt, at, pt[2], qtnt; |
2001 | uint8 ppu1[8]; | |
1989 | 2002 | |
1990 | 2003 | INLINE void Read() { |
1991 | 2004 | NTRefreshAddr = RefreshAddr = ppur.get_ntread(); |
1997 | 2010 | } |
1998 | 2011 | pecnt = (RefreshAddr & 1) << 3; |
1999 | 2012 | 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 | ||
2001 | 2019 | |
2002 | 2020 | RefreshAddr = ppur.get_atread(); |
2003 | 2021 | at = CALL_PPUREAD(RefreshAddr); |
2009 | 2027 | at <<= 2; |
2010 | 2028 | //horizontal scroll clocked at cycle 3 and then |
2011 | 2029 | //vertical scroll at 251 |
2030 | ppu1[2] = PPU[1]; | |
2012 | 2031 | runppu(1); |
2013 | 2032 | if (PPUON) { |
2014 | 2033 | ppur.increment_hsc(); |
2015 | 2034 | if (ppur.status.cycle == 251) |
2016 | 2035 | ppur.increment_vs(); |
2017 | 2036 | } |
2037 | ppu1[3] = PPU[1]; | |
2018 | 2038 | runppu(1); |
2019 | 2039 | |
2020 | 2040 | ppur.par = nt; |
2021 | 2041 | RefreshAddr = ppur.get_ptread(); |
2022 | 2042 | if (PEC586Hack) { |
2023 | 2043 | 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); | |
2025 | 2048 | 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); | |
2027 | 2053 | } else if (QTAIHack && (qtnt & 0x40)) { |
2028 | 2054 | pt[0] = *(CHRptr[0] + RefreshAddr); |
2029 | runppu(kFetchTime); | |
2055 | ppu1[4] = PPU[1]; | |
2056 | runppu(1); | |
2057 | ppu1[5] = PPU[1]; | |
2058 | runppu(1); | |
2030 | 2059 | RefreshAddr |= 8; |
2031 | 2060 | pt[1] = *(CHRptr[0] + RefreshAddr); |
2032 | runppu(kFetchTime); | |
2061 | ppu1[6] = PPU[1]; | |
2062 | runppu(1); | |
2063 | ppu1[7] = PPU[1]; | |
2064 | runppu(1); | |
2033 | 2065 | } else { |
2034 | 2066 | if (ScreenON) |
2035 | 2067 | RENDER_LOG(RefreshAddr); |
2036 | 2068 | pt[0] = CALL_PPUREAD(RefreshAddr); |
2037 | runppu(kFetchTime); | |
2069 | ppu1[4] = PPU[1]; | |
2070 | runppu(1); | |
2071 | ppu1[5] = PPU[1]; | |
2072 | runppu(1); | |
2038 | 2073 | RefreshAddr |= 8; |
2039 | 2074 | if (ScreenON) |
2040 | 2075 | RENDER_LOG(RefreshAddr); |
2041 | 2076 | pt[1] = CALL_PPUREAD(RefreshAddr); |
2042 | runppu(kFetchTime); | |
2077 | ppu1[6] = PPU[1]; | |
2078 | runppu(1); | |
2079 | ppu1[7] = PPU[1]; | |
2080 | runppu(1); | |
2043 | 2081 | } |
2044 | 2082 | } |
2045 | 2083 | }; |
2215 | 2253 | pixel = ((pt[0] >> (7 - bgpx)) & 1) | (((pt[1] >> (7 - bgpx)) & 1) << 1) | bgdata.main[bgtile].at; |
2216 | 2254 | } |
2217 | 2255 | if (renderbg) |
2218 | pixelcolor = READPAL(pixel); | |
2256 | pixelcolor = READPALNOGS(pixel); | |
2219 | 2257 | |
2220 | 2258 | //look for a sprite to be drawn |
2221 | 2259 | bool havepixel = false; |
2260 | 2298 | spixel |= (oam[2] & 3) << 2; |
2261 | 2299 | |
2262 | 2300 | if (rendersprites) |
2263 | pixelcolor = READPAL(0x10 + spixel); | |
2301 | pixelcolor = READPALNOGS(0x10 + spixel); | |
2264 | 2302 | } |
2265 | 2303 | } |
2266 | 2304 | |
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; | |
2269 | 2320 | } |
2270 | 2321 | } |
2271 | 2322 | } |
5 | 5 | #endif |
6 | 6 | |
7 | 7 | #ifndef PPUT_MMC5SP |
8 | uint8 zz; | |
8 | FCEU_MAYBE_UNUSED uint8 zz; | |
9 | 9 | #else |
10 | 10 | uint8 xs, ys; |
11 | 11 | xs = X1; |
533 | 533 | PrepDPCM(); |
534 | 534 | else |
535 | 535 | { |
536 | SIRQStat|=0x80; | |
537 | if(DMCFormat&0x80) | |
536 | if(DMCFormat&0x80) { | |
537 | SIRQStat|=0x80; | |
538 | 538 | X6502_IRQBegin(FCEU_IQDPCM); |
539 | } | |
539 | 540 | } |
540 | 541 | } |
541 | 542 | } |
69 | 69 | //tells the save system innards that we're loading the old format |
70 | 70 | bool FCEU_state_loading_old_format = false; |
71 | 71 | |
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) | |
73 | 73 | bool undoSS = false; //This will be true if there is lastSavestateMade, it was made since ROM was loaded, a backup state for lastSavestateMade exists |
74 | 74 | bool redoSS = false; //This will be true if UndoSaveState is run, will turn false when a new savestate is made |
75 | 75 | |
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) | |
77 | 77 | bool undoLS = false; //This will be true if a backupstate was made and it was made since ROM was loaded |
78 | 78 | bool redoLS = false; //This will be true if a backupstate was loaded, meaning redoLoadState can be run |
79 | 79 | |
87 | 87 | // temporary buffer for compressed data of a savestate |
88 | 88 | std::vector<uint8> compressed_buf; |
89 | 89 | |
90 | #define SFMDATA_SIZE (64) | |
90 | #define SFMDATA_SIZE (128) | |
91 | 91 | static SFORMAT SFMDATA[SFMDATA_SIZE]; |
92 | 92 | static int SFEXINDEX; |
93 | 93 | |
109 | 109 | { &X.Y, 1, "Y\0\0"}, |
110 | 110 | { &X.S, 1, "S\0\0"}, |
111 | 111 | { &X.P, 1, "P\0\0"}, |
112 | { &X.DB, 1, "DB"}, | |
112 | { &X.DB, 1, "DB\0"}, | |
113 | 113 | { &RAM, 0x800 | FCEUSTATE_INDIRECT, "RAM", }, |
114 | 114 | { 0 } |
115 | 115 | }; |
132 | 132 | |
133 | 133 | while(sf->v) |
134 | 134 | { |
135 | if(sf->s==~0) //Link to another struct | |
135 | if(sf->s==~0u) //Link to another struct | |
136 | 136 | { |
137 | 137 | uint32 tmp; |
138 | 138 | |
190 | 190 | { |
191 | 191 | while(sf->v) |
192 | 192 | { |
193 | if(sf->s==~0) // Link to another SFORMAT structure. | |
193 | if(sf->s==~0u) // Link to another SFORMAT structure. | |
194 | 194 | { |
195 | 195 | SFORMAT *tmp; |
196 | 196 | if((tmp= CheckS((SFORMAT *)sf->v, tsize, desc) )) |
306 | 306 | // load back buffer |
307 | 307 | { |
308 | 308 | 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 | ||
311 | 322 | |
312 | 323 | //MBG TODO - can this be moved to a better place? |
313 | 324 | //does it even make sense, displaying XBuf when its XBackBuf we just loaded? |
314 | 325 | #ifdef __WIN_DRIVER__ |
315 | else | |
326 | if(ret) | |
316 | 327 | { |
317 | 328 | FCEUD_BlitScreen(XBuf); |
318 | 329 | UpdateFCEUWindow(); |
403 | 414 | // save back buffer |
404 | 415 | { |
405 | 416 | extern uint8 *XBackBuf; |
406 | uint32 size = 256 * 256 + 8; | |
417 | uint32 size = 256 * 256; | |
407 | 418 | os->fputc(8); |
408 | 419 | write32le(size, os); |
409 | 420 | os->fwrite((char*)XBackBuf,size); |
415 | 426 | if(SPostSave) SPostSave(); |
416 | 427 | |
417 | 428 | //save the length of the file |
418 | int len = memory_savestate.size(); | |
429 | size_t len = memory_savestate.size(); | |
419 | 430 | |
420 | 431 | //sanity check: len and totalsize should be the same |
421 | 432 | if(len != totalsize) |
426 | 437 | |
427 | 438 | int error = Z_OK; |
428 | 439 | uint8* cbuf = (uint8*)memory_savestate.buf(); |
429 | uLongf comprlen = -1; | |
440 | uLongf comprlen = ~0lu; | |
430 | 441 | if(compressionLevel != Z_NO_COMPRESSION && (compressSavestates || FCEUMOV_Mode(MOVIEMODE_TASEDITOR))) |
431 | 442 | { |
432 | 443 | // worst case compression: zlib says "0.1% larger than sourceLen plus 12 bytes" |
445 | 456 | |
446 | 457 | //dump it to the destination file |
447 | 458 | outstream->fwrite((char*)header,16); |
448 | outstream->fwrite((char*)cbuf,comprlen==-1?totalsize:comprlen); | |
459 | outstream->fwrite((char*)cbuf,comprlen==~0lu?totalsize:comprlen); | |
449 | 460 | |
450 | 461 | return error == Z_OK; |
451 | 462 | } |
454 | 465 | void FCEUSS_Save(const char *fname, bool display_message) |
455 | 466 | { |
456 | 467 | EMUFILE* st = 0; |
457 | char fn[2048]; | |
468 | std::string fn; | |
458 | 469 | |
459 | 470 | if (geniestage==1) |
460 | 471 | { |
466 | 477 | if(fname) //If filename is given use it. |
467 | 478 | { |
468 | 479 | st = FCEUD_UTF8_fstream(fname, "wb"); |
469 | strcpy(fn, fname); | |
480 | fn.assign(fname); | |
470 | 481 | } |
471 | 482 | else //Else, generate one |
472 | 483 | { |
473 | 484 | //FCEU_PrintError("daCurrentState=%d",CurrentState); |
474 | strcpy(fn, FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0).c_str()); | |
485 | fn = FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0); | |
475 | 486 | |
476 | 487 | //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) | |
481 | 492 | undoSS = true; //Backup was created so undo is possible |
482 | 493 | } |
483 | 494 | else |
484 | 495 | undoSS = false; //so backup made so lastSavestateMade does have a backup file, so no undo |
485 | 496 | |
486 | st = FCEUD_UTF8_fstream(fn,"wb"); | |
497 | st = FCEUD_UTF8_fstream(fn.c_str(),"wb"); | |
487 | 498 | } |
488 | 499 | |
489 | 500 | if (st == NULL || st->get_fp() == NULL) |
499 | 510 | LuaSaveData saveData; |
500 | 511 | CallRegisteredLuaSaveFunctions(CurrentState, saveData); |
501 | 512 | |
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"); | |
506 | 516 | if(saveData.recordList) |
507 | 517 | { |
508 | FILE* luaSaveFile = fopen(luaSaveFilename, "wb"); | |
518 | FILE* luaSaveFile = fopen(luaSaveFilename.c_str(), "wb"); | |
509 | 519 | if(luaSaveFile) |
510 | 520 | { |
511 | 521 | saveData.ExportRecords(luaSaveFile); |
514 | 524 | } |
515 | 525 | else |
516 | 526 | { |
517 | unlink(luaSaveFilename); | |
527 | unlink(luaSaveFilename.c_str()); | |
518 | 528 | } |
519 | 529 | } |
520 | 530 | #endif |
654 | 664 | return ret; |
655 | 665 | } |
656 | 666 | |
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); | |
660 | 670 | |
661 | 671 | // reinit memory_savestate |
662 | 672 | // 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) | |
664 | 674 | (memory_savestate.get_vec())->resize(totalsize); |
665 | 675 | memory_savestate.set_len(totalsize); |
666 | 676 | memory_savestate.unfail(); |
667 | 677 | memory_savestate.fseek(0, SEEK_SET); |
668 | 678 | |
669 | if(comprlen != -1) | |
679 | if(comprlen != ~0u) | |
670 | 680 | { |
671 | 681 | // 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); | |
673 | 683 | is->fread(&compressed_buf[0], comprlen); |
674 | 684 | |
675 | 685 | uLongf uncomprlen = totalsize; |
711 | 721 | |
712 | 722 | bool FCEUSS_Load(const char *fname, bool display_message) |
713 | 723 | { |
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; | |
716 | 726 | |
717 | 727 | //mbg movie - this needs to be overhauled |
718 | 728 | ////this fixes read-only toggle problems |
730 | 740 | if (fname) |
731 | 741 | { |
732 | 742 | 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)) | |
742 | 753 | { |
743 | 754 | if (display_message) |
744 | 755 | { |
745 | 756 | 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()); | |
747 | 758 | } |
748 | 759 | SaveStateStatus[CurrentState] = 0; |
749 | 760 | return false; |
752 | 763 | //If in bot mode, don't do a backup when loading. |
753 | 764 | //Otherwise you eat at the hard disk, since so many |
754 | 765 | //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)) | |
756 | 767 | { |
757 | 768 | if (fname) |
758 | 769 | { |
759 | 770 | char szFilename[260]={0}; |
760 | 771 | splitpath(fname, 0, 0, szFilename, 0); |
761 | if (display_message) | |
772 | if (display_message) | |
762 | 773 | { |
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) | |
769 | 781 | { |
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 | } | |
773 | 785 | SaveStateStatus[CurrentState] = 1; |
774 | 786 | } |
775 | delete st; | |
776 | 787 | |
777 | 788 | #ifdef _S9XLUA_H |
778 | 789 | if (!internalSaveLoad) |
779 | 790 | { |
780 | 791 | LuaSaveData saveData; |
781 | 792 | |
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"); | |
787 | 797 | if(luaSaveFile) |
788 | 798 | { |
789 | 799 | saveData.ImportRecords(luaSaveFile); |
795 | 805 | #endif |
796 | 806 | |
797 | 807 | #ifdef __WIN_DRIVER__ |
798 | Update_RAM_Search(); // Update_RAM_Watch() is also called. | |
808 | Update_RAM_Search(); // Update_RAM_Watch() is also called. | |
799 | 809 | #endif |
800 | 810 | |
801 | 811 | //Update input display if movie is loaded |
805 | 815 | cur_input_display = FCEU_GetJoyJoy(); //Input display should show the last buttons pressed (stored in the savestate) |
806 | 816 | |
807 | 817 | return true; |
808 | } else | |
818 | } | |
819 | else | |
809 | 820 | { |
810 | 821 | if(!fname) |
811 | 822 | SaveStateStatus[CurrentState] = 1; |
815 | 826 | FCEU_DispMessage("Error(s) reading state %d!", 0, CurrentState); |
816 | 827 | //FCEU_DispMessage("Error(s) reading state %d! Filename: %s", 0, CurrentState, fn); |
817 | 828 | } |
818 | delete st; | |
819 | 829 | return 0; |
820 | 830 | } |
821 | 831 | } |
847 | 857 | for(x=0;x<SFEXINDEX;x++) |
848 | 858 | { |
849 | 859 | if(SFMDATA[x].desc) |
850 | free( (void*)SFMDATA[x].desc); | |
860 | FCEU_free( (void*)SFMDATA[x].desc); | |
851 | 861 | } |
852 | 862 | // 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 |
853 | 863 | SFMDATA[0].s = 0; |
862 | 872 | //do not accept extra state information if a null pointer was provided for v, so list won't terminate early |
863 | 873 | if (v == 0) return; |
864 | 874 | |
865 | if(s==~0) | |
875 | if(s==~0u) | |
866 | 876 | { |
867 | 877 | SFORMAT* sf = (SFORMAT*)v; |
868 | 878 | std::map<std::string,bool> names; |
1055 | 1065 | //Both files must exist |
1056 | 1066 | //-------------------------------------------------------------------------------------------- |
1057 | 1067 | |
1058 | if (!lastSavestateMade) | |
1068 | if (lastSavestateMade.empty()) | |
1059 | 1069 | { |
1060 | 1070 | FCEUI_DispMessage("Can't Undo",0); |
1061 | 1071 | FCEUI_printf("Undo savestate was attempted but unsuccessful because there was not a recently used savestate.\n"); |
1062 | 1072 | return; //If there is no last savestate, can't undo |
1063 | 1073 | } |
1064 | string backup = GenerateBackupSaveStateFn(lastSavestateMade); //Get filename of backup state | |
1074 | string backup = GenerateBackupSaveStateFn(lastSavestateMade.c_str()); //Get filename of backup state | |
1065 | 1075 | if (!CheckFileExists(backup.c_str())) |
1066 | 1076 | { |
1067 | 1077 | FCEUI_DispMessage("Can't Undo",0); |
1075 | 1085 | string temp = backup; //Put backup filename in temp |
1076 | 1086 | temp.append("x"); //Add x |
1077 | 1087 | |
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 | |
1081 | 1091 | |
1082 | 1092 | undoSS = true; //Just in case, if this was run, then there is definately a last savestate and backup |
1083 | 1093 | if (redoSS) //This was a redo function, so if run again it will be an undo again |
1102 | 1112 | string filename; |
1103 | 1113 | int x; |
1104 | 1114 | |
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 | |
1106 | 1116 | x = filename.find_last_of("."); //Find last dot |
1107 | 1117 | filename = filename.substr(0,x); //Chop off file extension |
1108 | 1118 | filename.append(".bak.fc0"); //add .bak |
1160 | 1170 | void RedoLoadState() |
1161 | 1171 | { |
1162 | 1172 | 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()); | |
1167 | 1177 | } |
1168 | 1178 | redoLS = false; //Flag that RedoLoadState can not be run again |
1169 | 1179 | undoLS = true; //Flag that LoadBackup can be run again |
16 | 16 | * along with this program; if not, write to the Free Software |
17 | 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
18 | 18 | */ |
19 | #include <string> | |
19 | 20 | |
20 | 21 | enum ENUM_SSLOADPARAMS |
21 | 22 | { |
66 | 67 | void RedoLoadState(); //reloads a loadstate if backupsavestate was run |
67 | 68 | void SwapSaveState(); //Swaps a savestate with its backup state |
68 | 69 | |
69 | extern char lastSavestateMade[2048]; //Filename of last savestate used | |
70 | extern std::string lastSavestateMade; //Filename of last savestate used | |
70 | 71 | extern bool undoSS; //undo savestate flag |
71 | 72 | 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 | |
73 | 74 | extern bool undoLS; //undo loadstate flag |
74 | 75 | extern bool redoLS; //redo savestate flag |
75 | 76 | extern bool backupSavestates; //Whether or not to make backups, true by default |
60 | 60 | #ifdef __MINGW32__ |
61 | 61 | #define alloca __builtin_alloca |
62 | 62 | #endif |
63 | ||
64 | //#include <typeinfo> | |
63 | 65 | |
64 | 66 | #include <sys/types.h> |
65 | 67 | #include <sys/stat.h> |
130 | 132 | |
131 | 133 | #endif |
132 | 134 | |
133 | #if defined(WIN32) && !defined(__QT_DRIVER__) | |
135 | #if defined(WIN32) && !defined(__QT_DRIVER__) && !defined(__WIN_DRIVER__) | |
134 | 136 | #define __WIN_DRIVER__ |
135 | 137 | #endif |
136 | 138 | |
142 | 144 | #define CTASSERT(x) typedef char __assert ## y[(x) ? 1 : -1]; |
143 | 145 | #endif |
144 | 146 | |
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 | ||
145 | 229 | #include "utils/endian.h" |
146 | 230 | |
147 | 231 | #endif |
139 | 139 | return(0); |
140 | 140 | FCEU_printf(" %02x", t); |
141 | 141 | } |
142 | FCEU_printf("\n Default Name/Attribute Table Mirroring: Horizontal\n", uchead.info); | |
142 | FCEU_printf("\n Default Name/Attribute Table Mirroring: Horizontal\n"); | |
143 | 143 | mirrortodo = 0; |
144 | 144 | } |
145 | 145 | return(1); |
474 | 474 | { "FNS", FNS_Init, BMCFLAG_16KCHRR }, |
475 | 475 | { "BS-400R", BS400R_Init, 0 }, |
476 | 476 | { "BS-4040R", BS4040R_Init, 0 }, |
477 | { "COOLGIRL", COOLGIRL_Init, 0 }, | |
477 | 478 | |
478 | 479 | { 0, 0, 0 } |
479 | 480 | }; |
161 | 161 | void FNS_Init(CartInfo *info); |
162 | 162 | void BS400R_Init(CartInfo *info); |
163 | 163 | void BS4040R_Init(CartInfo *info); |
164 | void SMD132_SMD133_Init(CartInfo *info); | |
164 | void AA6023_Init(CartInfo *info); | |
165 | void COOLGIRL_Init(CartInfo* info); | |
165 | 166 | |
166 | 167 | extern uint8 *UNIFchrrama; // Meh. So I can stop CHR RAM |
167 | 168 | // bank switcherooing with certain boards... |
27 | 27 | #include "../fceu.h" |
28 | 28 | #include "memory.h" |
29 | 29 | |
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 | ||
31 | 70 | void *FCEU_gmalloc(uint32 size) |
32 | 71 | { |
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; | |
43 | 78 | } |
44 | 79 | |
45 | ///allocates the specified number of bytes. returns null if this fails | |
46 | 80 | void *FCEU_malloc(uint32 size) |
47 | 81 | { |
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; | |
57 | 85 | } |
58 | 86 | |
59 | ///frees memory allocated with FCEU_gmalloc | |
60 | 87 | void FCEU_gfree(void *ptr) |
61 | 88 | { |
62 | free(ptr); | |
89 | _FCEU_free(ptr); | |
63 | 90 | } |
64 | 91 | |
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) | |
67 | 93 | { |
68 | free(ptr); | |
94 | _FCEU_free(ptr); | |
69 | 95 | } |
70 | 96 | |
71 | 97 | void *FCEU_dmalloc(uint32 size) |
72 | 98 | { |
73 | return malloc(size); | |
99 | return FCEU_malloc(size); | |
74 | 100 | } |
75 | 101 | |
76 | 102 | void FCEU_dfree(void *ptr) |
77 | 103 | { |
78 | free(ptr); | |
104 | return FCEU_free(ptr); | |
79 | 105 | } |
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 | } |
23 | 23 | |
24 | 24 | #define FCEU_dwmemset(d,c,n) {int _x; for(_x=n-4;_x>=0;_x-=4) *(uint32 *)&(d)[_x]=c;} |
25 | 25 | |
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 | |
28 | 34 | 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 | |
29 | 44 | void FCEU_free(void *ptr); |
30 | void FCEU_memmove(void *d, void *s, uint32 l); | |
31 | 45 | |
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. | |
34 | 50 | void *FCEU_dmalloc(uint32 size); |
51 | ||
52 | //don't use these. change them if you find them. | |
35 | 53 | 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 | }; |
193 | 193 | data[62] = '+'; // 62 |
194 | 194 | data[63] = '/'; // 63 |
195 | 195 | // 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); // | |
197 | 197 | data[((unsigned char)'=') ^ 0x80] = 0; |
198 | 198 | } |
199 | 199 | unsigned char operator[] (size_t pos) const { return data[pos]; } |
61 | 61 | |
62 | 62 | #define FCEU_VERSION_MAJOR 2 |
63 | 63 | #define FCEU_VERSION_MINOR 6 |
64 | #define FCEU_VERSION_PATCH 4 | |
64 | #define FCEU_VERSION_PATCH 5 | |
65 | 65 | |
66 | 66 | #define FCEU_VERSION_NUMERIC ( (FCEU_VERSION_MAJOR*10000) + (FCEU_VERSION_MINOR*100) + (FCEU_VERSION_PATCH) ) |
67 | 67 | #define FCEU_VERSION_MAJOR_DECODE(x) ( (x / 10000) ) |
68 | 68 | #define FCEU_VERSION_MINOR_DECODE(x) ( (x / 100) % 100 ) |
69 | 69 | #define FCEU_VERSION_PATCH_DECODE(x) (x % 100) |
70 | 70 | |
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 | |
72 | 72 | #define FCEU_NAME_AND_VERSION FCEU_NAME " " FCEU_VERSION_STRING |
73 | 73 | |
74 | 74 | #endif |
90 | 90 | { |
91 | 91 | if ( XBuf ) |
92 | 92 | { |
93 | FCEU_free(XBuf); XBuf = NULL; | |
93 | FCEU_afree(XBuf); XBuf = NULL; | |
94 | 94 | } |
95 | 95 | if ( XBackBuf ) |
96 | 96 | { |
97 | FCEU_free(XBackBuf); XBackBuf = NULL; | |
97 | FCEU_afree(XBackBuf); XBackBuf = NULL; | |
98 | 98 | } |
99 | 99 | if ( XDBuf ) |
100 | 100 | { |
101 | FCEU_free(XDBuf); XDBuf = NULL; | |
101 | FCEU_afree(XDBuf); XDBuf = NULL; | |
102 | 102 | } |
103 | 103 | if ( XDBackBuf ) |
104 | 104 | { |
105 | FCEU_free(XDBackBuf); XDBackBuf = NULL; | |
105 | FCEU_afree(XDBackBuf); XDBackBuf = NULL; | |
106 | 106 | } |
107 | 107 | //printf("Video Core Cleanup\n"); |
108 | 108 | } |
115 | 115 | int FCEU_InitVirtualVideo(void) |
116 | 116 | { |
117 | 117 | //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 | |
119 | 119 | if(XBuf) |
120 | 120 | return 1; |
121 | 121 | |
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 | ||
130 | 127 | |
131 | 128 | 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 | } | |
139 | 129 | |
140 | 130 | memset(XBuf,128,256*256); |
141 | 131 | 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); | |
144 | 134 | |
145 | 135 | return 1; |
146 | 136 | } |
399 | 389 | FCEUI_AviVideoUpdate(XBuf); |
400 | 390 | } |
401 | 391 | |
402 | void FCEU_DispMessageOnMovie(const char *format, ...) | |
392 | void FCEU_DispMessageOnMovie( __FCEU_PRINTF_FORMAT const char *format, ...) | |
403 | 393 | { |
404 | 394 | va_list ap; |
405 | 395 | |
418 | 408 | guiMessage.howlong = 0; |
419 | 409 | } |
420 | 410 | |
421 | void FCEU_DispMessage(const char *format, int disppos=0, ...) | |
411 | void FCEU_DispMessage( __FCEU_PRINTF_FORMAT const char *format, int disppos=0, ...) | |
422 | 412 | { |
423 | 413 | va_list ap; |
424 | 414 | |
431 | 421 | vsnprintf(temp,sizeof(temp),format,ap); |
432 | 422 | va_end(ap); |
433 | 423 | strcat(temp, "\n"); |
434 | FCEU_printf(temp); | |
424 | FCEU_printf("%s",temp); | |
435 | 425 | |
436 | 426 | if ( vidGuiMsgEna ) |
437 | 427 | { |
6 | 6 | void ResetScreenshotsCounter(); |
7 | 7 | uint32 GetScreenPixel(int x, int y, bool usebackup); |
8 | 8 | 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 | ||
9 | 17 | extern uint8 *XBuf; |
10 | 18 | extern uint8 *XBackBuf; |
11 | 19 | extern uint8 *XDBuf; |
12 | 20 | extern uint8 *XDBackBuf; |
21 | extern xfbuf_t *XFBuf; | |
22 | ||
13 | 23 | extern int ClipSidesOffset; |
14 | 24 | |
15 | 25 | struct GUIMESSAGE |
25 | 25 | #include "vsuni.h" |
26 | 26 | #include "state.h" |
27 | 27 | #include "driver.h" |
28 | #include "cart.h" | |
29 | #include "ines.h" | |
28 | 30 | |
29 | 31 | #include <cstring> |
30 | 32 | #include <cstdio> |
31 | 33 | |
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; | |
49 | 35 | uint8 vsdip = 0; |
50 | 36 | |
51 | void FCEUI_VSUniToggleDIPView(void) { | |
52 | DIPS = !DIPS; | |
53 | } | |
54 | ||
55 | 37 | void FCEU_VSUniToggleDIP(int w) { |
38 | if (GameInfo->type != GIT_VSUNI) { | |
39 | FCEU_DispMessage("Not Vs. System; toggle DIP switch.", 0); | |
40 | return; | |
41 | } | |
56 | 42 | vsdip ^= 1 << w; |
43 | DIPS_howlong = 180; | |
44 | FCEU_DispMessage("DIP switch %d is %s.", 0, w, vsdip & (1 << w) ? "on" : "off"); | |
57 | 45 | } |
58 | 46 | |
59 | 47 | void FCEUI_VSUniSetDIP(int w, int state) { |
65 | 53 | return(vsdip); |
66 | 54 | } |
67 | 55 | |
68 | static uint8 secdata[2][32] = | |
56 | static uint8 secdata_tko[32] = | |
69 | 57 | { |
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 | |
82 | 69 | }; |
83 | 70 | |
84 | 71 | static uint8 *secptr; |
92 | 79 | } |
93 | 80 | return(0x00); |
94 | 81 | } |
82 | ||
95 | 83 | 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 | } | |
113 | 106 | |
114 | 107 | static readfunc OldReadPPU; |
115 | 108 | static writefunc OldWritePPU[2]; |
125 | 118 | static DECLFR(A2002_MBJ) { // Mighty Bomb Jack |
126 | 119 | return((OldReadPPU(A) & ~0x3F) | 0x3D); |
127 | 120 | } |
128 | ||
129 | 121 | static DECLFW(B2000_2001_2C05) { |
130 | 122 | OldWritePPU[(A & 1) ^ 1](A ^ 1, V); |
131 | 123 | } |
124 | ||
132 | 125 | static uint8 xevselect = 0; |
133 | 126 | static DECLFR(XevRead) { |
134 | 127 | if (A == 0x54FF) { |
145 | 138 | } |
146 | 139 | |
147 | 140 | void FCEU_VSUniSwap(uint8 *j0, uint8 *j1) { |
148 | if (curvs->ioption & IOPTION_SWAPDIRAB) { | |
141 | if (GameInfo->vs_cswitch) { | |
149 | 142 | uint16 t = *j0; |
150 | 143 | *j0 = (*j0 & 0xC) | (*j1 & 0xF3); |
151 | 144 | *j1 = (*j1 & 0xC) | (t & 0xF3); |
153 | 146 | } |
154 | 147 | |
155 | 148 | void FCEU_VSUniPower(void) { |
156 | coinon = 0; | |
149 | coinon = coinon2 = service = 0; | |
157 | 150 | VSindex = 0; |
158 | 151 | |
159 | 152 | if (secptr) |
160 | 153 | SetReadHandler(0x5e00, 0x5e01, VSSecRead); |
161 | 154 | |
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) { | |
163 | 167 | OldReadPPU = GetReadHandler(0x2002); |
164 | 168 | SetReadHandler(0x2002, 0x2002, A2002_Topgun); |
165 | } else if (curppu == RC2C05_03) { | |
169 | } else if (GameInfo->vs_ppu == GIPPU_RC2C05_03) { | |
166 | 170 | OldReadPPU = GetReadHandler(0x2002); |
167 | 171 | SetReadHandler(0x2002, 0x2002, A2002_Gumshoe); |
168 | } else if (curppu == RC2C05_02) { | |
172 | } else if (GameInfo->vs_ppu == GIPPU_RC2C05_02) { | |
169 | 173 | OldReadPPU = GetReadHandler(0x2002); |
170 | 174 | SetReadHandler(0x2002, 0x2002, A2002_MBJ); |
171 | 175 | } |
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) { | |
173 | 177 | OldWritePPU[0] = GetWriteHandler(0x2000); |
174 | 178 | OldWritePPU[1] = GetWriteHandler(0x2001); |
175 | 179 | SetWriteHandler(0x2000, 0x2001, B2000_2001_2C05); |
176 | 180 | } |
177 | if (curmd5 == 0x2d396247cf58f9faLL) { /* Super Xevious */ | |
181 | if (GameInfo->vs_type == EGIVS_XEVIOUS) { /* Super Xevious */ | |
178 | 182 | SetReadHandler(0x5400, 0x57FF, XevRead); |
179 | 183 | } |
180 | 184 | } |
251 | 255 | |
252 | 256 | VSUNIENTRY VSUniGames[] = |
253 | 257 | { |
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 }, | |
295 | 299 | { 0 } |
296 | 300 | }; |
297 | 301 | |
300 | 304 | |
301 | 305 | while (vs->name) { |
302 | 306 | 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 | } | |
311 | 328 | |
312 | 329 | secptr = 0; |
313 | ||
330 | switch (GameInfo->vs_type) | |
314 | 331 | { |
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; | |
320 | 335 | } |
321 | 336 | |
322 | 337 | vsdip = 0x0; |
323 | if (vs->ioption & IOPTION_PREDIP) { | |
338 | if (vs->ioption & VS_OPTION_PREDIP) { | |
324 | 339 | vsdip = vs->predip; |
325 | 340 | } |
326 | if (vs->ioption & IOPTION_GUN) { | |
341 | if ((vs->ioption & VS_OPTION_GUN) && !head.expansion) { | |
342 | tofix |= 32; | |
327 | 343 | GameInfo->input[0] = SI_ZAPPER; |
328 | 344 | GameInfo->input[1] = SI_NONE; |
329 | } else { | |
345 | GameInfo->inputfc = SIFC_NONE; | |
346 | } | |
347 | else if (!head.expansion) { | |
330 | 348 | 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 | ||
333 | 385 | return; |
334 | 386 | } |
335 | 387 | vs++; |
340 | 392 | uint32 *dest; |
341 | 393 | int y, x; |
342 | 394 | |
343 | if (!DIPS) return; | |
395 | if (DIPS_howlong-- <= 0) return; | |
344 | 396 | |
345 | 397 | dest = (uint32*)(XBuf + 256 * 12 + 164); |
346 | 398 | for (y = 24; y; y--, dest += (256 - 72) >> 2) { |
370 | 422 | SFORMAT FCEUVSUNI_STATEINFO[] = { |
371 | 423 | { &vsdip, 1, "vsdp" }, |
372 | 424 | { &coinon, 1, "vscn" }, |
425 | { &coinon2, 1, "vsc2" }, | |
426 | { &service, 1, "vssv" }, | |
373 | 427 | { &VSindex, 1, "vsin" }, |
374 | 428 | { 0 } |
375 | 429 | }; |
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 | ||
0 | 17 | void FCEU_VSUniPower(void); |
1 | 18 | void FCEU_VSUniCheck(uint64 md5partial, int *, uint8 *); |
2 | 19 | void FCEU_VSUniDraw(uint8 *XBuf); |
3 | 20 | |
4 | 21 | void FCEU_VSUniToggleDIP(int); /* For movies and netplay */ |
5 | void FCEU_VSUniCoin(void); | |
22 | void FCEU_VSUniCoin(uint8 slot); | |
23 | void FCEU_VSUniService(); | |
6 | 24 | void FCEU_VSUniSwap(uint8 *j0, uint8 *j1); |
317 | 317 | #define LD_ZP(op) {uint8 A; uint8 x; GetZP(A); x=RdRAM(A); op; break;} |
318 | 318 | #define LD_ZPX(op) {uint8 A; uint8 x; GetZPI(A,_X); x=RdRAM(A); op; break;} |
319 | 319 | #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;} | |
322 | 322 | #define LD_ABX(op) LD_ABI(_X,op) |
323 | 323 | #define LD_ABY(op) LD_ABI(_Y,op) |
324 | 324 | #define LD_IX(op) {unsigned int A; uint8 x; GetIX(A); x=RdMem(A); op; break;} |