mirror of
https://github.com/flyinghead/flycast.git
synced 2026-11-07 17:11:09 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa97a6d64f | ||
|
|
72136c2bfc | ||
|
|
7457db8bba | ||
|
|
69125b490e | ||
|
|
3c94cd3194 | ||
|
|
75ff5409f4 | ||
|
|
642fad9a6e | ||
|
|
5ae7ac3eca | ||
|
|
885862a45e | ||
|
|
9b751fced8 | ||
|
|
76bf574668 | ||
|
|
c77c3ab015 | ||
|
|
8acd81cc43 | ||
|
|
c0e52b9a1a | ||
|
|
0840da1bd5 | ||
|
|
852df89f93 | ||
|
|
b5eb8694f6 | ||
|
|
f4986008fe | ||
|
|
d6644c4935 | ||
|
|
5bb8c86903 | ||
|
|
a659b57e63 | ||
|
|
44e96c544b | ||
|
|
0a5b8891a8 | ||
|
|
6a5db32d5d | ||
|
|
b0f3e065be | ||
|
|
fe895211c1 | ||
|
|
907131b7f5 | ||
|
|
76508146ae | ||
|
|
867b519a2b | ||
|
|
74852520dc | ||
|
|
faec4d8e50 | ||
|
|
d2aca1d621 | ||
|
|
05961ac883 | ||
|
|
afd07c25ba | ||
|
|
7ab92d88b1 | ||
|
|
3780299803 | ||
|
|
d78bb9ed3f | ||
|
|
b5f1552ed8 | ||
|
|
917cc7f27c | ||
|
|
2327e73ee7 | ||
|
|
397ddef68c | ||
|
|
3ec7f293ee | ||
|
|
26c8e8dab8 | ||
|
|
fdcea88519 | ||
|
|
bf6c73060b | ||
|
|
ddcd3861d3 | ||
|
|
971d47eb42 | ||
|
|
13bd42bdab | ||
|
|
71ac212dc7 | ||
|
|
2319a00c4f | ||
|
|
1268077f6b | ||
|
|
5c579de459 | ||
|
|
167faff1f3 | ||
|
|
22ad95cbfe | ||
|
|
db8508cefc | ||
|
|
5ac0772a2a | ||
|
|
e2c2d6606d | ||
|
|
48361f58b6 | ||
|
|
dcb439f74a | ||
|
|
739a27be63 | ||
|
|
e84cdce398 | ||
|
|
af2fe242f9 | ||
|
|
0fb177bf85 | ||
|
|
baab70c509 | ||
|
|
bc1c70bd1a | ||
|
|
12929c4571 | ||
|
|
62522e4eb3 | ||
|
|
221060cc70 | ||
|
|
58d1f7cee1 | ||
|
|
430256266f | ||
|
|
f9e38b11d9 | ||
|
|
78e075546a | ||
|
|
0e23b0bedd | ||
|
|
903c768f7f | ||
|
|
cd22ba1a2b | ||
|
|
cce8cb8528 | ||
|
|
6c6b447ea1 | ||
|
|
4554450d1d | ||
|
|
a0d1dbf833 | ||
|
|
a1a89df17f | ||
|
|
cf36384481 | ||
|
|
9103371362 | ||
|
|
1b5ad34c8e | ||
|
|
c57e88850c | ||
|
|
101a831534 | ||
|
|
3cc991fa4f | ||
|
|
c348f4ccad | ||
|
|
0181685d2f | ||
|
|
39bb94dd55 | ||
|
|
77a2bbbb8d | ||
|
|
afb0a80de1 | ||
|
|
49932e02a6 | ||
|
|
990a4ad583 | ||
|
|
fc9e1e401b | ||
|
|
15ca7e82bd | ||
|
|
3b81bbcae5 | ||
|
|
902fc2cbe8 | ||
|
|
50f5dabf4a | ||
|
|
aa6c9e2106 | ||
|
|
919fdb3594 | ||
|
|
c625cc68bf | ||
|
|
d732140bf9 | ||
|
|
db525bd5db | ||
|
|
039c666247 | ||
|
|
ed5c24c281 | ||
|
|
f2f4010203 | ||
|
|
a9e261d280 | ||
|
|
a710674cd4 | ||
|
|
ddfc00ed9f | ||
|
|
ac71970561 | ||
|
|
fd50529d86 | ||
|
|
52d95e537c | ||
|
|
15b21fff2b | ||
|
|
f46bccfecd | ||
|
|
1f55973f72 | ||
|
|
e0058c17ff | ||
|
|
bf61f5cfe8 | ||
|
|
8dcc25e1a9 | ||
|
|
a428167dc6 | ||
|
|
48e3a3eb68 | ||
|
|
a635fb3f77 | ||
|
|
320f679038 | ||
|
|
94c20ba29f | ||
|
|
8baebcfb5b | ||
|
|
7fcce4a59b | ||
|
|
554ffcd08f | ||
|
|
af0574c04e | ||
|
|
6c38295d62 | ||
|
|
55e613fae5 | ||
|
|
a5bad2b9b7 | ||
|
|
ebb251d8cf | ||
|
|
56768f2d3d | ||
|
|
5b3d36e081 | ||
|
|
ad08590197 | ||
|
|
53b5588bda | ||
|
|
1015a8c098 | ||
|
|
27ddc215cc | ||
|
|
c11a6cd432 | ||
|
|
3a62e432da | ||
|
|
9c3f60c26c | ||
|
|
e5863920c4 | ||
|
|
7f61b44d42 | ||
|
|
a5660fa2b4 | ||
|
|
ecc03e3ebc | ||
|
|
a92c2899c8 | ||
|
|
af4638e83f | ||
|
|
cecf1a5497 | ||
|
|
f2374982b8 | ||
|
|
d736dd027d | ||
|
|
214db9e0b1 | ||
|
|
3bbc89afc9 | ||
|
|
e35ccbbb18 | ||
|
|
8d071bf4ea | ||
|
|
a14086d484 | ||
|
|
20d25059bf | ||
|
|
ccee7162bc | ||
|
|
debbae6ab1 | ||
|
|
2c6f01ae38 | ||
|
|
0362fd1079 | ||
|
|
38765dc89a | ||
|
|
78306b3c12 | ||
|
|
e51a291195 | ||
|
|
d551848a9b | ||
|
|
fe6247dded | ||
|
|
5fb8b458bb | ||
|
|
340c55c570 | ||
|
|
de1322b928 | ||
|
|
010d257b69 | ||
|
|
e5d517dad2 | ||
|
|
965dea5fe6 | ||
|
|
1ffcc75031 | ||
|
|
e084cc9a3a | ||
|
|
6ed78d1202 | ||
|
|
270eaa1452 | ||
|
|
e1038ea632 | ||
|
|
8947100701 | ||
|
|
cb99e7d920 | ||
|
|
b048921c11 | ||
|
|
4335aa563f |
No files matched your search
@@ -18,7 +18,7 @@ jobs:
|
||||
matrix:
|
||||
config:
|
||||
- {name: i686-pc-windows-msvc, os: windows-latest, shell: cmd, arch: x86, cmakeArgs: -G Ninja, buildType: Release}
|
||||
- {name: apple-darwin, os: macos-latest, shell: sh, cmakeArgs: -G Xcode, destDir: osx, buildType: Release}
|
||||
- {name: apple-darwin, os: macos-latest, shell: sh, cmakeArgs: -G Xcode -DAPPLE_BREAKPAD=ON, destDir: osx, buildType: RelWithDebInfo}
|
||||
- {name: apple-ios, os: macos-latest, shell: sh, cmakeArgs: -DCMAKE_SYSTEM_NAME=iOS -G Xcode, destDir: ios, buildType: Release}
|
||||
- {name: x86_64-pc-linux-gnu, os: ubuntu-latest, shell: sh, cmakeArgs: -G Ninja, buildType: Release}
|
||||
- {name: x86_64-pc-windows-msvc, os: windows-latest, shell: cmd, arch: x64, cmakeArgs: -G Ninja, buildType: Release}
|
||||
@@ -30,8 +30,8 @@ jobs:
|
||||
- name: Set up build environment (macOS)
|
||||
run: |
|
||||
brew update
|
||||
brew install libao ldid libomp ninja pulseaudio
|
||||
wget https://sdk.lunarg.com/sdk/download/1.3.204.1/mac/vulkansdk-macos-1.3.204.1.dmg
|
||||
brew install libao ldid ninja pulseaudio
|
||||
VULKAN_VER=1.3.211.0 && aria2c --parameterized-uri=true https://{sdk.lunarg.com/sdk/download/$VULKAN_VER/mac,distfiles.macports.org/MoltenVK}/vulkansdk-macos-$VULKAN_VER.dmg
|
||||
hdiutil attach ./vulkansdk-macos-*.dmg
|
||||
sudo /Volumes/vulkansdk-macos-*/InstallVulkan.app/Contents/MacOS/InstallVulkan --root $HOME/VulkanSDK --accept-licenses --default-answer --confirm-command install
|
||||
hdiutil detach /Volumes/vulkansdk-macos-*
|
||||
@@ -67,6 +67,10 @@ jobs:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
|
||||
- name: Compile a universal OpenMP (macOS)
|
||||
run: export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1; brew reinstall --build-from-source --formula ./shell/apple/libomp.rb
|
||||
if: runner.os == 'macOS'
|
||||
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
@@ -126,7 +130,7 @@ jobs:
|
||||
shell: bash
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }}
|
||||
|
||||
- name: Upload symbols to S3
|
||||
- name: Upload symbols to S3 (Windows-MinGW, macOS)
|
||||
run: aws s3 sync symbols s3://flycast-symbols/${{ matrix.config.destDir }} --follow-symlinks
|
||||
shell: bash
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' && matrix.config.name == 'x86_64-w64-mingw32' }}
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' && (matrix.config.name == 'x86_64-w64-mingw32' || matrix.config.name == 'apple-darwin') }}
|
||||
@@ -17,7 +17,8 @@ jobs:
|
||||
- name: Setup Java JDK
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 1.8
|
||||
distribution: 'temurin'
|
||||
java-version: 8
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v3
|
||||
|
||||
@@ -14,7 +14,8 @@ jobs:
|
||||
- name: Setup Java JDK
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 1.8
|
||||
distribution: 'temurin'
|
||||
java-version: 8
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v3
|
||||
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
|
||||
- name: CMake
|
||||
run: |
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 17 2022" -A x64 -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0 -DCMAKE_SYSTEM_PROCESSOR=AMD64 -DCMAKE_CROSSCOMPILING=OFF -DUSE_VULKAN=OFF -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%\scripts\buildsystems\vcpkg.cmake
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 17 2022" -A x64 -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0.22000.0 -DCMAKE_SYSTEM_PROCESSOR=AMD64 -DCMAKE_CROSSCOMPILING=OFF -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%\scripts\buildsystems\vcpkg.cmake
|
||||
cmake --build build --config Release --parallel 2
|
||||
shell: cmd
|
||||
|
||||
|
||||
@@ -52,10 +52,16 @@ include:
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/android-cmake.yml'
|
||||
|
||||
################################## CONSOLES ################################
|
||||
# Nintendo Switch
|
||||
# - project: 'libretro-infrastructure/ci-templates'
|
||||
# file: '/libnx-static.yml'
|
||||
|
||||
# Stages for building
|
||||
stages:
|
||||
- build-prepare
|
||||
- build-shared
|
||||
# - build-static
|
||||
|
||||
##############################################################################
|
||||
#################################### STAGES ##################################
|
||||
@@ -116,3 +122,10 @@ android-x86:
|
||||
extends:
|
||||
- .libretro-android-cmake-x86
|
||||
- .core-defs-android
|
||||
|
||||
################################### CONSOLES #################################
|
||||
# Nintendo Switch
|
||||
#libretro-build-libnx-aarch64:
|
||||
# extends:
|
||||
# - .libretro-libnx-static-retroarch-master
|
||||
# - .core-defs
|
||||
+141
-43
@@ -19,6 +19,7 @@ option(USE_VULKAN "Build with Vulkan support" ON)
|
||||
option(LIBRETRO "Build libretro core" OFF)
|
||||
option(USE_OPENGL "Use Open GL API" ON)
|
||||
option(USE_VIDEOCORE "RPI: use the legacy Broadcom GLES libraries" OFF)
|
||||
option(APPLE_BREAKPAD "macOS: Build breakpad client and dump symbols" OFF)
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/shell/cmake")
|
||||
|
||||
@@ -119,7 +120,7 @@ elseif(LIBRETRO)
|
||||
else()
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE "-lGLESv2")
|
||||
endif()
|
||||
else()
|
||||
elseif(USE_OPENGL)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE HAVE_OPENGL)
|
||||
if(APPLE)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-framework,OpenGL")
|
||||
@@ -144,6 +145,7 @@ endif()
|
||||
|
||||
if(WINDOWS_STORE)
|
||||
set(USE_OPENGL OFF)
|
||||
set(USE_VULKAN OFF)
|
||||
target_compile_features(${PROJECT_NAME} PRIVATE c_std_11 cxx_std_17)
|
||||
else()
|
||||
target_compile_features(${PROJECT_NAME} PRIVATE c_std_11 cxx_std_11)
|
||||
@@ -198,23 +200,84 @@ if(NOT LIBRETRO)
|
||||
endif()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC breakpad_client)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_BREAKPAD)
|
||||
elseif(APPLE AND NOT IOS AND APPLE_BREAKPAD)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/deps/breakpad/src/client/minidump_file_writer-inl.h
|
||||
core/deps/breakpad/src/client/minidump_file_writer.cc
|
||||
core/deps/breakpad/src/client/minidump_file_writer.h
|
||||
core/deps/breakpad/src/client/mac/handler/breakpad_nlist_64.cc
|
||||
core/deps/breakpad/src/client/mac/handler/breakpad_nlist_64.h
|
||||
core/deps/breakpad/src/client/mac/handler/dynamic_images.cc
|
||||
core/deps/breakpad/src/client/mac/handler/dynamic_images.h
|
||||
core/deps/breakpad/src/client/mac/handler/exception_handler.cc
|
||||
core/deps/breakpad/src/client/mac/handler/exception_handler.h
|
||||
core/deps/breakpad/src/client/mac/handler/minidump_generator.cc
|
||||
core/deps/breakpad/src/client/mac/handler/minidump_generator.h
|
||||
core/deps/breakpad/src/client/mac/handler/protected_memory_allocator.cc
|
||||
core/deps/breakpad/src/client/mac/handler/protected_memory_allocator.h
|
||||
core/deps/breakpad/src/client/mac/crash_generation/ConfigFile.h
|
||||
core/deps/breakpad/src/client/mac/crash_generation/ConfigFile.mm
|
||||
core/deps/breakpad/src/client/mac/crash_generation/client_info.h
|
||||
core/deps/breakpad/src/client/mac/crash_generation/crash_generation_client.h
|
||||
core/deps/breakpad/src/client/mac/crash_generation/crash_generation_client.cc
|
||||
core/deps/breakpad/src/common/convert_UTF.cc
|
||||
core/deps/breakpad/src/common/convert_UTF.h
|
||||
core/deps/breakpad/src/common/md5.cc
|
||||
core/deps/breakpad/src/common/string_conversion.cc
|
||||
core/deps/breakpad/src/common/string_conversion.h
|
||||
core/deps/breakpad/src/common/mac/file_id.cc
|
||||
core/deps/breakpad/src/common/mac/file_id.h
|
||||
core/deps/breakpad/src/common/mac/MachIPC.mm
|
||||
core/deps/breakpad/src/common/mac/MachIPC.h
|
||||
core/deps/breakpad/src/common/mac/bootstrap_compat.cc
|
||||
core/deps/breakpad/src/common/mac/bootstrap_compat.h
|
||||
core/deps/breakpad/src/common/mac/macho_id.cc
|
||||
core/deps/breakpad/src/common/mac/macho_id.h
|
||||
core/deps/breakpad/src/common/mac/macho_utilities.cc
|
||||
core/deps/breakpad/src/common/mac/macho_utilities.h
|
||||
core/deps/breakpad/src/common/mac/macho_walker.cc
|
||||
core/deps/breakpad/src/common/mac/macho_walker.h
|
||||
core/deps/breakpad/src/common/mac/string_utilities.cc
|
||||
core/deps/breakpad/src/common/mac/string_utilities.h
|
||||
)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/core/deps/breakpad/src)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_BREAKPAD)
|
||||
add_custom_target(dump_syms COMMAND xcodebuild -project ${CMAKE_CURRENT_SOURCE_DIR}/core/deps/breakpad/src/tools/mac/dump_syms/dump_syms.xcodeproj -target dump_syms -configuration Release CONFIGURATION_BUILD_DIR=${CMAKE_CURRENT_SOURCE_DIR}/build/breakpad)
|
||||
ADD_DEPENDENCIES(${PROJECT_NAME} dump_syms)
|
||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
||||
COMMAND sleep 20
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build/breakpad/dump_syms
|
||||
-a x86_64
|
||||
-g ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/Flycast.app.dSYM
|
||||
${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/Flycast.app/Contents/MacOS/Flycast > Flycast.sym
|
||||
COMMAND mkdir -p ../symbols/Flycast/`head -1 Flycast.sym | awk '{ print $4 }'`
|
||||
COMMAND mv Flycast.sym ../symbols/Flycast/`head -1 Flycast.sym | awk '{ print $4 }'`
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build/breakpad/dump_syms
|
||||
-a arm64
|
||||
-g ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/Flycast.app.dSYM
|
||||
${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/Flycast.app/Contents/MacOS/Flycast > Flycast.sym
|
||||
COMMAND mkdir -p ../symbols/Flycast/`head -1 Flycast.sym | awk '{ print $4 }'`
|
||||
COMMAND mv Flycast.sym ../symbols/Flycast/`head -1 Flycast.sym | awk '{ print $4 }'`
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(OpenMP)
|
||||
if(OpenMP_CXX_FOUND AND NOT APPLE AND USE_OPENMP)
|
||||
if(MINGW)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE "-static -lgomp -lpthread")
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -fopenmp)
|
||||
elseif(ANDROID)
|
||||
# Reference: https://android.googlesource.com/platform/ndk/+/refs/heads/master/tests/device/openmp/CMakeLists.txt
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_OPTIONS -fopenmp)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE -fopenmp -static-openmp)
|
||||
else()
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE OpenMP::OpenMP_CXX)
|
||||
if(USE_OPENMP)
|
||||
find_package(OpenMP)
|
||||
if(OpenMP_CXX_FOUND)
|
||||
if(MINGW)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE "-static -lgomp -lpthread")
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -fopenmp)
|
||||
elseif(ANDROID)
|
||||
# Reference: https://android.googlesource.com/platform/ndk/+/refs/heads/master/tests/device/openmp/CMakeLists.txt
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_OPTIONS -fopenmp)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE -fopenmp -static-openmp)
|
||||
elseif(APPLE)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE OpenMP::OpenMP_CXX -static-openmp)
|
||||
else()
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE OpenMP::OpenMP_CXX)
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE TARGET_NO_OPENMP)
|
||||
endif()
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build shared library" OFF)
|
||||
@@ -245,18 +308,11 @@ if(NOT LIBRETRO)
|
||||
endif()
|
||||
|
||||
if(NOT ANDROID AND NOT IOS)
|
||||
if(APPLE)
|
||||
# Patch SDL
|
||||
execute_process(COMMAND git apply -p1 ${CMAKE_CURRENT_SOURCE_DIR}/core/deps/patches/SDL.patch
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/core/deps/SDL)
|
||||
else()
|
||||
if(NOT APPLE)
|
||||
find_package(SDL2)
|
||||
endif()
|
||||
if(NOT SDL2_FOUND)
|
||||
add_subdirectory(core/deps/SDL EXCLUDE_FROM_ALL)
|
||||
if(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
target_compile_definitions(SDL2-static PRIVATE HAVE_LIBC)
|
||||
endif()
|
||||
set(SDL2_FOUND 1)
|
||||
endif()
|
||||
|
||||
@@ -549,15 +605,18 @@ if(LIBRETRO)
|
||||
core/deps/libretro-common/compat/fopen_utf8.c
|
||||
core/deps/libretro-common/compat/compat_strcasestr.c
|
||||
core/deps/libretro-common/file/retro_dirent.c
|
||||
core/deps/libretro-common/string/stdstring.c
|
||||
core/deps/libretro-common/glsm/glsm.c
|
||||
core/deps/libretro-common/glsym/rglgen.c)
|
||||
if(ANDROID OR USE_GLES)
|
||||
target_sources(${PROJECT_NAME} PRIVATE core/deps/libretro-common/glsym/glsym_es3.c)
|
||||
elseif(USE_GLES2)
|
||||
target_sources(${PROJECT_NAME} PRIVATE core/deps/libretro-common/glsym/glsym_es2.c)
|
||||
else()
|
||||
target_sources(${PROJECT_NAME} PRIVATE core/deps/libretro-common/glsym/glsym_gl.c)
|
||||
core/deps/libretro-common/string/stdstring.c)
|
||||
if(USE_OPENGL)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/deps/libretro-common/glsm/glsm.c
|
||||
core/deps/libretro-common/glsym/rglgen.c)
|
||||
if(ANDROID OR USE_GLES)
|
||||
target_sources(${PROJECT_NAME} PRIVATE core/deps/libretro-common/glsym/glsym_es3.c)
|
||||
elseif(USE_GLES2)
|
||||
target_sources(${PROJECT_NAME} PRIVATE core/deps/libretro-common/glsym/glsym_es2.c)
|
||||
else()
|
||||
target_sources(${PROJECT_NAME} PRIVATE core/deps/libretro-common/glsym/glsym_gl.c)
|
||||
endif()
|
||||
endif()
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
shell/libretro/audiostream.cpp
|
||||
@@ -595,6 +654,7 @@ if(NOT LIBRETRO)
|
||||
endif()
|
||||
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/hw/hwreg.h
|
||||
core/hw/aica/aica.cpp
|
||||
core/hw/aica/aica.h
|
||||
core/hw/aica/aica_if.cpp
|
||||
@@ -620,7 +680,6 @@ target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/hw/arm7/arm7_rec.cpp
|
||||
core/hw/arm7/arm7_rec.h
|
||||
core/hw/arm7/arm-new.h
|
||||
core/hw/arm7/vbaARM.cpp
|
||||
core/hw/bba/bba.h
|
||||
core/hw/bba/bba.cpp
|
||||
core/hw/bba/rtl8139c.h
|
||||
@@ -676,6 +735,11 @@ target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/hw/naomi/naomi_roms.cpp
|
||||
core/hw/naomi/naomi_roms.h
|
||||
core/hw/naomi/naomi_roms_input.h
|
||||
core/hw/naomi/card_reader.h
|
||||
core/hw/naomi/card_reader.cpp
|
||||
core/hw/pvr/elan.cpp
|
||||
core/hw/pvr/elan.h
|
||||
core/hw/pvr/elan_struct.h
|
||||
core/hw/pvr/helper_classes.h
|
||||
core/hw/pvr/pvr.cpp
|
||||
core/hw/pvr/pvr.h
|
||||
@@ -696,7 +760,6 @@ target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/hw/pvr/ta.h
|
||||
core/hw/pvr/ta_structs.h
|
||||
core/hw/pvr/ta_vtx.cpp
|
||||
core/hw/sh4/dyna
|
||||
core/hw/sh4/dyna/blockmanager.cpp
|
||||
core/hw/sh4/dyna/blockmanager.h
|
||||
core/hw/sh4/dyna/decoder.cpp
|
||||
@@ -711,12 +774,10 @@ target_sources(${PROJECT_NAME} PRIVATE
|
||||
core/hw/sh4/dyna/ssa.h
|
||||
core/hw/sh4/dyna/ssa_regalloc.h
|
||||
core/hw/sh4/fsca-table.h
|
||||
core/hw/sh4/interpr
|
||||
core/hw/sh4/interpr/sh4_fpu.cpp
|
||||
core/hw/sh4/interpr/sh4_interpreter.cpp
|
||||
core/hw/sh4/interpr/sh4_opcodes.cpp
|
||||
core/hw/sh4/interpr/sh4_opcodes.h
|
||||
core/hw/sh4/modules
|
||||
core/hw/sh4/modules/bsc.cpp
|
||||
core/hw/sh4/modules/ccn.cpp
|
||||
core/hw/sh4/modules/ccn.h
|
||||
@@ -920,7 +981,9 @@ if(USE_OPENGL)
|
||||
core/rend/gles/gltex.cpp
|
||||
core/rend/gles/quad.cpp
|
||||
core/rend/gles/postprocess.cpp
|
||||
core/rend/gles/postprocess.h)
|
||||
core/rend/gles/postprocess.h
|
||||
core/rend/gles/naomi2.cpp
|
||||
core/rend/gles/naomi2.h)
|
||||
|
||||
if(NOT LIBRETRO)
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
@@ -935,7 +998,9 @@ if(USE_OPENGL)
|
||||
core/rend/gl4/abuffer.cpp
|
||||
core/rend/gl4/gl4.h
|
||||
core/rend/gl4/gldraw.cpp
|
||||
core/rend/gl4/gles.cpp)
|
||||
core/rend/gl4/gles.cpp
|
||||
core/rend/gl4/gl4naomi2.cpp
|
||||
core/rend/gl4/gl4naomi2.h)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -1047,8 +1112,32 @@ if(USE_VULKAN)
|
||||
endif()
|
||||
|
||||
if(WIN32 AND NOT LIBRETRO AND NOT WINDOWS_STORE)
|
||||
add_subdirectory(core/rend/dx9)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE dx9renderer)
|
||||
set(REND_DX9_FILES
|
||||
core/rend/dx9/d3d_overlay.h
|
||||
core/rend/dx9/d3d_overlay.cpp
|
||||
core/rend/dx9/d3d_renderer.h
|
||||
core/rend/dx9/d3d_renderer.cpp
|
||||
core/rend/dx9/d3d_shaders.h
|
||||
core/rend/dx9/d3d_shaders.cpp
|
||||
core/rend/dx9/d3d_texture.h
|
||||
core/rend/dx9/d3d_texture.cpp
|
||||
core/rend/dx9/dx9_driver.h
|
||||
core/rend/dx9/dxcontext.cpp
|
||||
core/rend/dx9/dxcontext.h
|
||||
core/rend/dx9/imgui_impl_dx9.h
|
||||
core/rend/dx9/imgui_impl_dx9.cpp)
|
||||
target_sources(${PROJECT_NAME} PRIVATE ${REND_DX9_FILES})
|
||||
|
||||
if(NOT MINGW)
|
||||
set_source_files_properties(${REND_DX9_FILES} PROPERTIES INCLUDE_DIRECTORIES "$ENV{DXSDK_DIR}/Include")
|
||||
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
target_link_directories(${PROJECT_NAME} PUBLIC "$ENV{DXSDK_DIR}/Lib/x64")
|
||||
else()
|
||||
target_link_directories(${PROJECT_NAME} PUBLIC "$ENV{DXSDK_DIR}/Lib/x86")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC d3d9 d3dx9)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
@@ -1076,6 +1165,8 @@ if(WIN32)
|
||||
core/rend/dx11/dx11context_lr.cpp
|
||||
core/rend/dx11/dx11context_lr.h
|
||||
core/rend/dx11/dx11_driver.h
|
||||
core/rend/dx11/dx11_naomi2.cpp
|
||||
core/rend/dx11/dx11_naomi2.h
|
||||
core/rend/dx11/oit/dx11_oitbuffers.h
|
||||
core/rend/dx11/oit/dx11_oitrenderer.cpp
|
||||
core/rend/dx11/oit/dx11_oitshaders.cpp
|
||||
@@ -1345,6 +1436,10 @@ if(NOT LIBRETRO)
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING "1.0"
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION "1"
|
||||
MACOSX_BUNDLE_COPYRIGHT "Copyright © 2019 Flycast contributors. All rights reserved."
|
||||
XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf"
|
||||
XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT[variant=RelWithDebInfo] "dwarf-with-dsym"
|
||||
XCODE_ATTRIBUTE_CLANG_DEBUG_INFORMATION_LEVEL[variant=RelWithDebInfo] "line-tables-only"
|
||||
XCODE_ATTRIBUTE_DEPLOYMENT_POSTPROCESSING[variant=RelWithDebInfo] YES
|
||||
XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME "AppIcon"
|
||||
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.flyinghead.Flycast"
|
||||
BUILD_WITH_INSTALL_RPATH TRUE
|
||||
@@ -1354,17 +1449,17 @@ if(NOT LIBRETRO)
|
||||
find_library(AUDIO_UNIT_LIBRARY AudioUnit)
|
||||
find_library(FOUNDATION_LIBRARY Foundation)
|
||||
find_library(AUDIO_TOOLBOX_LIBRARY AudioToolbox)
|
||||
find_library(MULTITOUCH_SUPPORT_LIBRARY MultitouchSupport /System/Library/PrivateFrameworks)
|
||||
find_library(OPENGL_LIBRARY OpenGL)
|
||||
find_library(IOSURFACE_LIBRARY IOSurface)
|
||||
find_library(MULTITOUCH_SUPPORT_LIBRARY MultitouchSupport /System/Library/PrivateFrameworks)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
${AUDIO_UNIT_LIBRARY}
|
||||
${FOUNDATION_LIBRARY}
|
||||
${AUDIO_TOOLBOX_LIBRARY}
|
||||
${MULTITOUCH_SUPPORT_LIBRARY}
|
||||
${OPENGL_LIBRARY}
|
||||
${IOSURFACE_LIBRARY})
|
||||
${IOSURFACE_LIBRARY}
|
||||
${MULTITOUCH_SUPPORT_LIBRARY})
|
||||
|
||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy "$ENV{VULKAN_SDK}/lib/libMoltenVK.dylib"
|
||||
@@ -1403,7 +1498,7 @@ if(NOT LIBRETRO)
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES RESOURCE "${ResourceFiles}")
|
||||
else()
|
||||
target_sources(${PROJECT_NAME} PRIVATE shell/windows/flycast.rc)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE dsound opengl32 winmm ws2_32 wsock32 xinput9_1_0)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE dsound opengl32 winmm ws2_32 wsock32 xinput9_1_0 cfgmgr32)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
@@ -1469,3 +1564,6 @@ if(UNIX AND NOT APPLE AND NOT ANDROID AND NOT LIBRETRO)
|
||||
)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
file(GLOB_RECURSE SRC_FILES *.h *.cpp *.c *.cc *.mm)
|
||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SRC_FILES})
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||

|
||||
|
||||
**Flycast** is a multi-platform Sega Dreamcast, Naomi and Atomiswave emulator derived from [**reicast**](https://reicast.com/).
|
||||
**Flycast** is a multi-platform Sega Dreamcast, Naomi, Naomi 2, and Atomiswave emulator derived from [**reicast**](https://github.com/skmp/reicast-emulator).
|
||||
|
||||
Information about configuration and supported features can be found on [**TheArcadeStriker's flycast wiki**](https://github.com/TheArcadeStriker/flycast-wiki/wiki).
|
||||
|
||||
@@ -17,30 +17,34 @@ Join us on our [**Discord server**](https://discord.gg/X8YWP8w) for a chat.
|
||||
|
||||
### Flatpak (Linux)
|
||||
|
||||
1. [Set up Flatpak](https://www.flatpak.org/setup/)
|
||||
1. [Set up Flatpak](https://www.flatpak.org/setup/).
|
||||
|
||||
2. Install Flycast from [Flathub](https://flathub.org/apps/details/org.flycast.Flycast)
|
||||
2. Install Flycast from [Flathub](https://flathub.org/apps/details/org.flycast.Flycast):
|
||||
|
||||
`flatpak install -y org.flycast.Flycast`
|
||||
|
||||
3. Run Flycast
|
||||
3. Run Flycast:
|
||||
|
||||
`flatpak run org.flycast.Flycast`
|
||||
|
||||
### Homebrew (MacOS)
|
||||
|
||||
1. [Set up Homebrew](https://brew.sh)
|
||||
1. [Set up Homebrew](https://brew.sh).
|
||||
|
||||
2. Install Flycast via Homebrew
|
||||
2. Install Flycast via Homebrew:
|
||||
|
||||
`brew install --cask flycast`
|
||||
|
||||
### Xbox One
|
||||
### Xbox One/Series
|
||||
|
||||
Open [**gamr13's github page**](https://gamr13.github.io/) from your console.
|
||||
#### Retail:
|
||||
Open [**gamr13's github page**](https://gamr13.github.io/) from your Xbox console.
|
||||
|
||||
#### Dev Mode:
|
||||
Grab the latest build from [**the builds page**](https://flyinghead.github.io/flycast-builds/), or the [**GitHub Actions**](https://github.com/flyinghead/flycast/actions/workflows/uwp.yml). Then install it using the **Xbox Device Portal**.
|
||||
|
||||
### Binaries
|
||||
|
||||
Get fresh builds for your system [**on the builds page**](https://flyinghead.github.io/flycast-builds/).
|
||||
|
||||
**New:** Now automated test results are available as well.
|
||||
**New:** Now automated test results are available as well.
|
||||
@@ -82,6 +82,13 @@ s32 cfgLoadInt(const std::string& section, const std::string& key, s32 def)
|
||||
return cfgdb.get_int(section, key, def);
|
||||
}
|
||||
|
||||
int64_t cfgLoadInt64(const std::string& section, const std::string& key, int64_t def) {
|
||||
return cfgdb.get_int64(section, key, def);
|
||||
}
|
||||
void cfgSaveInt64(const std::string& section, const std::string& key, int64_t value) {
|
||||
cfgdb.set_int64(section, key, value);
|
||||
}
|
||||
|
||||
void cfgSaveBool(const std::string& section, const std::string& key, bool value)
|
||||
{
|
||||
cfgSaveStr(section, key, value ? "yes" : "no");
|
||||
@@ -112,6 +119,11 @@ void cfgDeleteSection(const std::string& section)
|
||||
cfgdb.delete_section(section);
|
||||
}
|
||||
|
||||
void cfgDeleteEntry(const std::string& section, const std::string& key)
|
||||
{
|
||||
cfgdb.delete_entry(section, key);
|
||||
}
|
||||
|
||||
void cfgSetAutoSave(bool autoSave)
|
||||
{
|
||||
::autoSave = autoSave;
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
bool cfgOpen();
|
||||
s32 cfgLoadInt(const std::string& section, const std::string& key, s32 def);
|
||||
void cfgSaveInt(const std::string& section, const std::string& key, s32 value);
|
||||
int64_t cfgLoadInt64(const std::string& section, const std::string& key, int64_t def);
|
||||
void cfgSaveInt64(const std::string& section, const std::string& key, int64_t value);
|
||||
std::string cfgLoadStr(const std::string& section, const std::string& key, const std::string& def);
|
||||
void cfgSaveStr(const std::string& section, const std::string& key, const std::string& value);
|
||||
void cfgSaveBool(const std::string& section, const std::string& key, bool value);
|
||||
@@ -17,3 +19,4 @@ bool ParseCommandLine(int argc, char *argv[]);
|
||||
void cfgSetAutoSave(bool autoSave);
|
||||
bool cfgHasSection(const std::string& section);
|
||||
void cfgDeleteSection(const std::string& section);
|
||||
void cfgDeleteEntry(const std::string& section, const std::string& key);
|
||||
@@ -24,6 +24,14 @@ int ConfigEntry::get_int()
|
||||
}
|
||||
}
|
||||
|
||||
int64_t ConfigEntry::get_int64()
|
||||
{
|
||||
int base = 10;
|
||||
if (strstr(this->value.c_str(), "0x") != nullptr)
|
||||
base = 16;
|
||||
return (int64_t)strtoll(this->value.c_str(), nullptr, base);
|
||||
}
|
||||
|
||||
bool ConfigEntry::get_bool()
|
||||
{
|
||||
if (stricmp(this->value.c_str(), "yes") == 0 ||
|
||||
@@ -158,6 +166,19 @@ int ConfigFile::get_int(const std::string& section_name, const std::string& entr
|
||||
}
|
||||
}
|
||||
|
||||
int64_t ConfigFile::get_int64(const std::string& section_name, const std::string& entry_name, int64_t default_value)
|
||||
{
|
||||
ConfigEntry* entry = this->get_entry(section_name, entry_name);
|
||||
if (entry == NULL)
|
||||
{
|
||||
return default_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return entry->get_int64();
|
||||
}
|
||||
}
|
||||
|
||||
bool ConfigFile::get_bool(const std::string& section_name, const std::string& entry_name, bool default_value)
|
||||
{
|
||||
ConfigEntry* entry = this->get_entry(section_name, entry_name);
|
||||
@@ -188,6 +209,13 @@ void ConfigFile::set_int(const std::string& section_name, const std::string& ent
|
||||
this->set(section_name, entry_name, str_value.str(), is_virtual);
|
||||
}
|
||||
|
||||
void ConfigFile::set_int64(const std::string& section_name, const std::string& entry_name, int64_t value, bool is_virtual)
|
||||
{
|
||||
std::stringstream str_value;
|
||||
str_value << value;
|
||||
this->set(section_name, entry_name, str_value.str(), is_virtual);
|
||||
}
|
||||
|
||||
void ConfigFile::set_bool(const std::string& section_name, const std::string& entry_name, bool value, bool is_virtual)
|
||||
{
|
||||
std::string str_value = (value ? "yes" : "no");
|
||||
|
||||
@@ -11,6 +11,7 @@ struct ConfigEntry {
|
||||
const std::string& get_string() const;
|
||||
int get_int();
|
||||
bool get_bool();
|
||||
int64_t get_int64();
|
||||
};
|
||||
|
||||
struct ConfigSection {
|
||||
@@ -41,10 +42,12 @@ struct ConfigFile {
|
||||
/* getting values */
|
||||
std::string get(const std::string& section_name, const std::string& entry_name, const std::string& default_value = "");
|
||||
int get_int(const std::string& section_name, const std::string& entry_name, int default_value = 0);
|
||||
int64_t get_int64(const std::string& section_name, const std::string& entry_name, int64_t default_value = 0);
|
||||
bool get_bool(const std::string& section_name, const std::string& entry_name, bool default_value = false);
|
||||
/* setting values */
|
||||
void set(const std::string& section_name, const std::string& entry_name, const std::string& value, bool is_virtual = false);
|
||||
void set_int(const std::string& section_name, const std::string& entry_name, int value, bool is_virtual = false);
|
||||
void set_int64(const std::string& section_name, const std::string& entry_name, int64_t value, bool is_virtual = false);
|
||||
void set_bool(const std::string& section_name, const std::string& entry_name, bool value, bool is_virtual = false);
|
||||
|
||||
void delete_section(const std::string& section_name);
|
||||
|
||||
+9
-1
@@ -17,6 +17,7 @@
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "option.h"
|
||||
#include "network/naomi_network.h"
|
||||
|
||||
namespace config {
|
||||
|
||||
@@ -36,6 +37,7 @@ Option<bool> ForceWindowsCE("Dreamcast.ForceWindowsCE");
|
||||
Option<bool> AutoLoadState("Dreamcast.AutoLoadState");
|
||||
Option<bool> AutoSaveState("Dreamcast.AutoSaveState");
|
||||
Option<int> SavestateSlot("Dreamcast.SavestateSlot");
|
||||
Option<bool> ForceFreePlay("ForceFreePlay", true);
|
||||
|
||||
// Sound
|
||||
|
||||
@@ -93,11 +95,13 @@ Option<int> MaxThreads("pvr.MaxThreads", 3);
|
||||
Option<int> AutoSkipFrame("pvr.AutoSkipFrame", 0);
|
||||
Option<int> RenderResolution("rend.Resolution", 480);
|
||||
Option<bool> VSync("rend.vsync", true);
|
||||
Option<u64> PixelBufferSize("rend.PixelBufferSize", 512 * 1024 * 1024);
|
||||
Option<int64_t> PixelBufferSize("rend.PixelBufferSize", 512 * 1024 * 1024);
|
||||
Option<int> AnisotropicFiltering("rend.AnisotropicFiltering", 1);
|
||||
Option<int> TextureFiltering("rend.TextureFiltering", 0); // Default
|
||||
Option<bool> ThreadedRendering("rend.ThreadedRendering", true);
|
||||
Option<bool> DupeFrames("rend.DupeFrames", false);
|
||||
Option<int> PerPixelLayers("rend.PerPixelLayers", 32);
|
||||
Option<bool> NativeDepthInterpolation("rend.NativeDepthInterpolation", false);
|
||||
|
||||
// Misc
|
||||
|
||||
@@ -117,12 +121,16 @@ Option<bool> NetworkEnable("Enable", false, "network");
|
||||
Option<bool> ActAsServer("ActAsServer", false, "network");
|
||||
OptionString DNS("DNS", "46.101.91.123", "network");
|
||||
OptionString NetworkServer("server", "", "network");
|
||||
Option<int> LocalPort("LocalPort", NaomiNetwork::SERVER_PORT, "network");
|
||||
Option<bool> EmulateBBA("EmulateBBA", false, "network");
|
||||
Option<bool> EnableUPnP("EnableUPnP", true, "network");
|
||||
Option<bool> GGPOEnable("GGPO", false, "network");
|
||||
Option<int> GGPODelay("GGPODelay", 0, "network");
|
||||
Option<bool> NetworkStats("Stats", true, "network");
|
||||
Option<int> GGPOAnalogAxes("GGPOAnalogAxes", 0, "network");
|
||||
Option<bool> GGPOChat("GGPOChat", true, "network");
|
||||
Option<bool> GGPOChatTimeoutToggle("GGPOChatTimeoutToggle", true, "network");
|
||||
Option<int> GGPOChatTimeout("GGPOChatTimeout", 10, "network");
|
||||
|
||||
#ifdef SUPPORT_DISPMANX
|
||||
Option<bool> DispmanxMaintainAspect("maintain_aspect", true, "dispmanx");
|
||||
|
||||
+28
-3
@@ -142,7 +142,11 @@ public:
|
||||
else if (PerGameOption && settings.hasPerGameConfig())
|
||||
{
|
||||
if (value == doLoad(section, name))
|
||||
{
|
||||
// delete existing per-game option if any
|
||||
cfgDeleteEntry(settings.gameId, section + "." + name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (PerGameOption && settings.hasPerGameConfig())
|
||||
doSave(settings.gameId, section + "." + name);
|
||||
@@ -175,9 +179,16 @@ protected:
|
||||
return cfgLoadBool(section, name, value);
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
enable_if_t<std::is_same<U, int64_t>::value, T>
|
||||
doLoad(const std::string& section, const std::string& name) const
|
||||
{
|
||||
return cfgLoadInt64(section, name, value);
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
enable_if_t<(std::is_integral<U>::value || std::is_enum<U>::value)
|
||||
&& !std::is_same<U, bool>::value, T>
|
||||
&& !std::is_same<U, bool>::value && !std::is_same<U, int64_t>::value, T>
|
||||
doLoad(const std::string& section, const std::string& name) const
|
||||
{
|
||||
return (T)cfgLoadInt(section, name, (int)value);
|
||||
@@ -267,9 +278,16 @@ protected:
|
||||
cfgSaveBool(section, name, value);
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
enable_if_t<std::is_same<U, int64_t>::value>
|
||||
doSave(const std::string& section, const std::string& name) const
|
||||
{
|
||||
cfgSaveInt64(section, name, value);
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
enable_if_t<(std::is_integral<U>::value || std::is_enum<U>::value)
|
||||
&& !std::is_same<U, bool>::value>
|
||||
&& !std::is_same<U, bool>::value && !std::is_same<U, int64_t>::value>
|
||||
doSave(const std::string& section, const std::string& name) const
|
||||
{
|
||||
cfgSaveInt(section, name, (int)value);
|
||||
@@ -355,6 +373,7 @@ extern Option<bool> ForceWindowsCE;
|
||||
extern Option<bool> AutoLoadState;
|
||||
extern Option<bool> AutoSaveState;
|
||||
extern Option<int> SavestateSlot;
|
||||
extern Option<bool> ForceFreePlay;
|
||||
|
||||
// Sound
|
||||
|
||||
@@ -421,6 +440,7 @@ constexpr bool Clipping = true;
|
||||
#ifndef LIBRETRO
|
||||
extern Option<int> TextureUpscale;
|
||||
extern Option<int> MaxFilteredTextureSize;
|
||||
extern Option<int> PerPixelLayers;
|
||||
#endif
|
||||
extern Option<float> ExtraDepthScale;
|
||||
extern Option<bool> CustomTextures;
|
||||
@@ -438,11 +458,12 @@ extern Option<int> MaxThreads;
|
||||
extern Option<int> AutoSkipFrame; // 0: none, 1: some, 2: more
|
||||
extern Option<int> RenderResolution;
|
||||
extern Option<bool> VSync;
|
||||
extern Option<u64> PixelBufferSize;
|
||||
extern Option<int64_t> PixelBufferSize;
|
||||
extern Option<int> AnisotropicFiltering;
|
||||
extern Option<int> TextureFiltering; // 0: default, 1: force nearest, 2: force linear
|
||||
extern Option<bool> ThreadedRendering;
|
||||
extern Option<bool> DupeFrames;
|
||||
extern Option<bool> NativeDepthInterpolation;
|
||||
|
||||
// Misc
|
||||
|
||||
@@ -462,12 +483,16 @@ extern Option<bool> NetworkEnable;
|
||||
extern Option<bool> ActAsServer;
|
||||
extern OptionString DNS;
|
||||
extern OptionString NetworkServer;
|
||||
extern Option<int> LocalPort;
|
||||
extern Option<bool> EmulateBBA;
|
||||
extern Option<bool> EnableUPnP;
|
||||
extern Option<bool> GGPOEnable;
|
||||
extern Option<int> GGPODelay;
|
||||
extern Option<bool> NetworkStats;
|
||||
extern Option<int> GGPOAnalogAxes;
|
||||
extern Option<bool> GGPOChat;
|
||||
extern Option<bool> GGPOChatTimeoutToggle;
|
||||
extern Option<int> GGPOChatTimeout;
|
||||
|
||||
#ifdef SUPPORT_DISPMANX
|
||||
extern Option<bool> DispmanxMaintainAspect;
|
||||
|
||||
+306
-253
@@ -25,285 +25,315 @@
|
||||
#include "reios/reios.h"
|
||||
#include "cfg/cfg.h"
|
||||
#include "cfg/ini.h"
|
||||
#include "emulator.h"
|
||||
|
||||
const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
{
|
||||
{ "MK-51064", nullptr, { 0x39EFF4, 0 }, { 0x43700000 } }, // 18 wheeler (USA)
|
||||
{ "MK-5106450", nullptr, { 0x39EFF4, 0 }, { 0x43700000 } }, // 18 wheeler (PAL)
|
||||
{ "HDR-0080", nullptr, { 0x6625C0, 0 }, { 0x43700000 } }, // 18 wheeler (JP)
|
||||
{ "T-9708N", nullptr, { 0x0AD5B0, 0x112E00, 0 }, { 0x4A2671C4, 0x401CCCCD } }, // 4 Wheel Thunder (USA)
|
||||
{ "MK-5119050", nullptr, { 0x104A34, 0 }, { 0x3F52CCCD } }, // 90 Minutes - Sega Championship Football (PAL)
|
||||
{ "T40209D 50", nullptr, { 0x2A8750, 0 }, { 0x3F400000 } }, // AeroWings 2 (PAL)
|
||||
{ "T34101M", nullptr, { 0x24CF20, 0x24CEEC, 0 }, { 0x3FAAAAAB, 0x43F00000, 0 } }, // Animastar (JP)
|
||||
{ "MK-51171", nullptr, { 0xCA20B8, 0 }, { 0x43700000 } }, // Alien Front Online (USA)
|
||||
{ "T2101M", nullptr, { 0x13E8B4, 0x13E8E4, 0 }, { 0x43F00000, 0x3F400000 } }, // Berserk (JP)
|
||||
{ "T13001D 18", nullptr, { 0x2DAC44, 0 }, { 0x3F400000 } }, // Blue Stinger (En, De) (PAL)
|
||||
{ "xxxxxxxxxx", nullptr, { 0x2DAB84, 0 }, { 0x3F400000 } }, // Blue Stinger (Fr) (PAL)
|
||||
{ "T13001D-05", nullptr, { 0x2D9C84, 0 }, { 0x3F400000 } }, // Blue Stinger (Es, It?) (PAL)
|
||||
{ "T13001N", nullptr, { 0x2D9CA4, 0 }, { 0x3F400000 } }, // Blue Stinger (USA)
|
||||
{ "HDR-0003", nullptr, { 0x2D6D80, 0 }, { 0x3F400000 } }, // Blue Stinger (JP)
|
||||
{ "T42903M", nullptr, { 0x286E2C, 0x286E5C, 0 }, { 0x43F00000, 0x3F400000 } }, // Bomber Hehhe! (JP)
|
||||
{ "MK-51065", nullptr, { 0x387B84, 0x387BB4, 0 }, { 0x43F00000, 0x3F400000 } }, // Bomberman Online (USA)
|
||||
{ "T6801M", nullptr, { 0x042F3C, 0 }, { 0x4384BC09 } }, // Buggy Heat (JP)
|
||||
{ "T46601D 05", nullptr, { 0xBB3D14, 0 }, { 0x440A7C9A } }, // Cannon Spike (PAL)
|
||||
{ "T1215N", nullptr, { 0xBB3C74, 0 }, { 0x440A7C9A } }, // Cannon Spike (USA)
|
||||
{ "T44901D 50", nullptr, { 0xB0109C, 0xB010CC, 0 }, { 0x43F00000, 0x3F400000 } }, // Carrier (PAL)
|
||||
{ "T5701N", nullptr, { 0xAFD93C, 0xAFD96C, 0 }, { 0x43F00000, 0x3F400000 } }, // Carrier (USA)
|
||||
{ "MK-51064", nullptr, { 0x39EFF4 }, { 0x43700000 } }, // 18 wheeler (USA)
|
||||
{ "MK-5106450", nullptr, { 0x39EFF4 }, { 0x43700000 } }, // 18 wheeler (PAL)
|
||||
{ "HDR-0080", nullptr, { 0x6625C0 }, { 0x43700000 } }, // 18 wheeler (JP)
|
||||
{ "T-9708N", nullptr, { 0x0AD5B0, 0x112E00 }, { 0x4A2671C4, 0x401CCCCD } }, // 4 Wheel Thunder (USA)
|
||||
{ "MK-5119050", nullptr, { 0x104A34 }, { 0x3F52CCCD } }, // 90 Minutes - Sega Championship Football (PAL)
|
||||
{ "T40209D 50", nullptr, { 0x2A8750 }, { 0x3F400000 } }, // AeroWings 2 (PAL)
|
||||
{ "T34101M", nullptr, { 0x24CF20, 0x24CEEC }, { 0x3FAAAAAB, 0x43F00000 } }, // Animastar (JP)
|
||||
{ "MK-51171", nullptr, { 0xCA20B8 }, { 0x43700000 } }, // Alien Front Online (USA)
|
||||
{ "T2101M", nullptr, { 0x13E8B4, 0x13E8E4 }, { 0x43F00000, 0x3F400000 } }, // Berserk (JP)
|
||||
{ "T13001D 18", nullptr, { 0x2DAC44 }, { 0x3F400000 } }, // Blue Stinger (En, De) (PAL)
|
||||
{ "xxxxxxxxxx", nullptr, { 0x2DAB84 }, { 0x3F400000 } }, // Blue Stinger (Fr) (PAL)
|
||||
{ "T13001D-05", nullptr, { 0x2D9C84 }, { 0x3F400000 } }, // Blue Stinger (Es, It?) (PAL)
|
||||
{ "T13001N", nullptr, { 0x2D9CA4 }, { 0x3F400000 } }, // Blue Stinger (USA)
|
||||
{ "HDR-0003", nullptr, { 0x2D6D80 }, { 0x3F400000 } }, // Blue Stinger (JP)
|
||||
{ "T42903M", nullptr, { 0x286E2C, 0x286E5C }, { 0x43F00000, 0x3F400000 } }, // Bomber Hehhe! (JP)
|
||||
{ "MK-51065", nullptr, { 0x387B84, 0x387BB4 }, { 0x43F00000, 0x3F400000 } }, // Bomberman Online (USA)
|
||||
{ "T6801M", nullptr, { 0x042F3C }, { 0x4384BC09 } }, // Buggy Heat (JP)
|
||||
{ "T46601D 05", nullptr, { 0xBB3D14 }, { 0x440A7C9A } }, // Cannon Spike (PAL)
|
||||
{ "T1215N", nullptr, { 0xBB3C74 }, { 0x440A7C9A } }, // Cannon Spike (USA)
|
||||
{ "T44901D 50", nullptr, { 0xB0109C, 0xB010CC }, { 0x43F00000, 0x3F400000 } }, // Carrier (PAL)
|
||||
{ "T5701N", nullptr, { 0xAFD93C, 0xAFD96C }, { 0x43F00000, 0x3F400000 } }, // Carrier (USA)
|
||||
// Capcom vs. SNK Pro (JP)
|
||||
// You can see the end of the backgrounds on each side. The HUD is shifted to the right.
|
||||
// Code 2 sets HUD and movements of the characters to a 4:3 zone
|
||||
{ "T1247M", nullptr, { 0x1E8238, 0x3D3658, 0x3D3628, 0 }, { 0x43F00000, 0x43D20000, 0x43700000 } },
|
||||
{ "T1247M", nullptr, { 0x1E8238, 0x3D3658, 0x3D3628 }, { 0x43F00000, 0x43D20000, 0x43700000 } },
|
||||
// Capcom vs. SNK 2 (JP)
|
||||
// You can see the end of the backgrounds on each side.
|
||||
{ "T1249M", nullptr, { 0x39BFD8, 0x34E9E8, 0x34EFBC, 0 }, { 0x43700000, 0x3F400000, 0x3F400000 } },
|
||||
{ "T44902D 50", nullptr, { 0x1DBFF8, 0 }, { 0x43700000 } }, // Charge ‘n Blast (PAL)
|
||||
{ "T4402M", nullptr, { 0x1DA9E0, 0 }, { 0x43700000 } }, // Charge ‘n Blast (JP)
|
||||
{ "MK-5104950", nullptr, { 0x2D2D40, 0x2D2D70, 0 }, { 0x3F400000, 0xC2700000 } }, // ChuChu Rocket! (PAL)
|
||||
{ "T44903D 50", nullptr, { 0x315300, 0x315334, 0 }, { 0x43F00000, 0x3FAAAAAB } }, // Coaster Works (PAL)
|
||||
{ "T1249M", nullptr, { 0x39BFD8, 0x34E9E8, 0x34EFBC }, { 0x43700000, 0x3F400000, 0x3F400000 } },
|
||||
{ "T44902D 50", nullptr, { 0x1DBFF8 }, { 0x43700000 } }, // Charge ‘n Blast (PAL)
|
||||
{ "T4402M", nullptr, { 0x1DA9E0 }, { 0x43700000 } }, // Charge ‘n Blast (JP)
|
||||
{ "MK-5104950", nullptr, { 0x2D2D40, 0x2D2D70 }, { 0x3F400000, 0xC2700000 } }, // ChuChu Rocket! (PAL)
|
||||
{ "T44903D 50", nullptr, { 0x315300, 0x315334 }, { 0x43F00000, 0x3FAAAAAB } }, // Coaster Works (PAL)
|
||||
// Confidential Mission (PAL) 022F0D58 43700000 - Only works on real Dreamcast
|
||||
{ "T36901M", nullptr, { 0x1C8A98, 0 }, { 0x3F400000 } }, // Cool Boarders (JP)
|
||||
{ "T3106M", nullptr, { 0x60B59C, 0 }, { 0x3F400000 } }, // Cool Cool Toon (JP)
|
||||
{ "HDR-0176", nullptr, { 0x240FAC, 0 }, { 0x3F400000 } }, // Cosmic Smash (JP)
|
||||
{ "MK-51035", " U ", { 0x2B08B0, 0 }, { 0x43700000 } }, // Crazy Taxi (USA)
|
||||
{ "MK-51035", " E ", { 0x2B3410, 0 }, { 0x43700000 } }, // Crazy Taxi (PAL)
|
||||
{ "MK-5113650", nullptr, { 0x2BFB70, 0 }, { 0x43700000 } }, // Crazy Taxi 2 (PAL)
|
||||
{ "MK-51136", nullptr, { 0x2BDDD0, 0 }, { 0x43700000 } }, // Crazy Taxi 2 (USA)
|
||||
// { "HDR-0159", nullptr, { 0x2FBBD0, 0 }, { 0x43700000 } }, // Crazy Taxi 2 (JP) not working
|
||||
{ "T13004N", nullptr, { 0x016D94, 0 }, { 0x44234E73 } }, // Cyber Troopers - Virtual On - Oratorio Tangram (USA)
|
||||
{ "T36901M", nullptr, { 0x1C8A98 }, { 0x3F400000 } }, // Cool Boarders (JP)
|
||||
{ "T3106M", nullptr, { 0x60B59C }, { 0x3F400000 } }, // Cool Cool Toon (JP)
|
||||
{ "HDR-0176", nullptr, { 0x240FAC }, { 0x3F400000 } }, // Cosmic Smash (JP)
|
||||
{ "MK-51035", " U ", { 0x2B08B0 }, { 0x43700000 } }, // Crazy Taxi (USA)
|
||||
{ "MK-51035", " E ", { 0x2B3410 }, { 0x43700000 } }, // Crazy Taxi (PAL)
|
||||
{ "MK-5113650", nullptr, { 0x2BFB70 }, { 0x43700000 } }, // Crazy Taxi 2 (PAL)
|
||||
{ "MK-51136", nullptr, { 0x2BDDD0 }, { 0x43700000 } }, // Crazy Taxi 2 (USA)
|
||||
// { "HDR-0159", nullptr, { 0x2FBBD0 }, { 0x43700000 } }, // Crazy Taxi 2 (JP) not working
|
||||
{ "T13004N", nullptr, { 0x016D94 }, { 0x44234E73 } }, // Cyber Troopers - Virtual On - Oratorio Tangram (USA)
|
||||
// D2 (USA)
|
||||
{ "MK-51036", nullptr, { 0x4B5CF4, 0x4B5CC4, 0x3E92A0, 0x3E92A8, 0x3E92C0, 0x3E92C8 },
|
||||
{ 0x3F400000, 0x43F00000, 0, 0, 0, 0 } },
|
||||
// D2 (JP)
|
||||
{ "T30006M", nullptr, { 0x4CF42C, 0x4CF45C, 0x3E1A36, 0x3E1A34, 0x3E1A3C, 0x3E1A54, 0x3E1A5C, 0 },
|
||||
{ "T30006M", nullptr, { 0x4CF42C, 0x4CF45C, 0x3E1A36, 0x3E1A34, 0x3E1A3C, 0x3E1A54, 0x3E1A5C },
|
||||
{ 0x43F00000, 0x3F400000, 0x08010000, 0, 0, 0, 0 } },
|
||||
{ "MK-5103750", nullptr, { 0x1FE270, 0 }, { 0x43700000 } }, // Daytona USA (PAL)
|
||||
{ "MK-51037", nullptr, { 0x1FC6D0, 0 }, { 0x43700000 } }, // Daytona USA (USA)
|
||||
{ "T9501N-50", nullptr, { 0x9821D4, 0 }, { 0x3F400000 } }, // Deadly Skies (PAL)
|
||||
{ "T8116D 50", nullptr, { 0x2E5530, 0 }, { 0x43700000 } }, // Dead or Alive 2 (PAL)
|
||||
{ "T3601N", nullptr, { 0x2F0670, 0 }, { 0x43700000 } }, // Dead or Alive 2 (USA)
|
||||
{ "T3602M", nullptr, { 0x2FF798, 0 }, { 0x43700000 } }, // Dead or Alive 2 (JP)
|
||||
{ "T3601M", nullptr, { 0x2FBBD0, 0x1E6658, 0 }, { 0x43700000, 0x4414C000 } }, // Dead or Alive 2: Limited Edition (JP) (code 1 fixes HUD)
|
||||
{ "T2401N", nullptr, { 0x8BD5B4, 0x8BD5E4, 0 }, { 0x43F00000, 0x3F400000 } }, // Death Crimson OX (USA)
|
||||
{ "T23201M", nullptr, { 0x819F44, 0x819F74, 0 }, { 0x43F00000, 0x3F400000 } }, // Death Crimson 2 (JP)
|
||||
{ "T17714D50", nullptr, { 0x0D2ED0, 0x0D2ED4, 0 }, { 0x3FAAAAAB, 0x3F400000 } }, // Donald Duck: Quack Attack (PAL) (Code 1 corrects the HUD)
|
||||
{ "T12503D-50", nullptr, { 0x49CB24, 0 }, { 0x3F0CCCCD } }, // Dragons Blood (PAL)
|
||||
{ "T17716D 50", nullptr, { 0xF97F40, 0x08DCF8, 0 }, { 0x00000168, 0 } }, // Dragonriders: Chronicles of Pern (PAL)
|
||||
{ "T17720N", nullptr, { 0xF97F40, 0x08DCF4, 0 }, { 0x00000168, 0 } }, // Dragonriders: Chronicles of Pern (USA) (Code 1 removes black bars)
|
||||
{ "MK-5101350", nullptr, { 0x4FCBC0, 0 }, { 0x43700000 } }, // Dynamite Cop (PAL)
|
||||
{ "MK-51013", nullptr, { 0x4FCBC0, 0 }, { 0x43700000 } }, // Dynamite Cop (USA)
|
||||
{ "MK-5103750", nullptr, { 0x1FE270 }, { 0x43700000 } }, // Daytona USA (PAL)
|
||||
{ "MK-51037", nullptr, { 0x1FC6D0 }, { 0x43700000 } }, // Daytona USA (USA)
|
||||
{ "T9501N-50", nullptr, { 0x9821D4 }, { 0x3F400000 } }, // Deadly Skies (PAL)
|
||||
{ "T8116D 50", nullptr, { 0x2E5530 }, { 0x43700000 } }, // Dead or Alive 2 (PAL)
|
||||
{ "T3601N", nullptr, { 0x2F0670 }, { 0x43700000 } }, // Dead or Alive 2 (USA)
|
||||
{ "T3602M", nullptr, { 0x2FF798 }, { 0x43700000 } }, // Dead or Alive 2 (JP)
|
||||
{ "T3601M", nullptr, { 0x2FBBD0 }, { 0x43700000 } }, // Dead or Alive 2: Limited Edition (JP)
|
||||
{ "T2401N", nullptr, { 0x8BD5B4, 0x8BD5E4 }, { 0x43F00000, 0x3F400000 } }, // Death Crimson OX (USA)
|
||||
{ "T23201M", nullptr, { 0x819F44, 0x819F74 }, { 0x43F00000, 0x3F400000 } }, // Death Crimson 2 (JP)
|
||||
{ "T17714D50", nullptr, { 0x0D2ED0, 0x0D2ED4 }, { 0x3FAAAAAB, 0x3F400000 } }, // Donald Duck: Quack Attack (PAL) (Code 1 corrects the HUD)
|
||||
{ "T12503D-50", nullptr, { 0x49CB24 }, { 0x3F0CCCCD } }, // Dragons Blood (PAL)
|
||||
{ "T17716D 50", nullptr, { 0xF97F40, 0x08DCF8 }, { 0x00000168, 0 } }, // Dragonriders: Chronicles of Pern (PAL)
|
||||
{ "T17720N", nullptr, { 0xF97F40, 0x08DCF4 }, { 0x00000168, 0 } }, // Dragonriders: Chronicles of Pern (USA) (Code 1 removes black bars)
|
||||
{ "MK-5101350", nullptr, { 0x4FCBC0 }, { 0x43700000 } }, // Dynamite Cop (PAL)
|
||||
{ "MK-51013", nullptr, { 0x4FCBC0 }, { 0x43700000 } }, // Dynamite Cop (USA)
|
||||
{ "HDR-0020", nullptr, { 0x4FA848 }, { 0x43700000 } }, // Dynamite Deka 2 (JP)
|
||||
// Draconus: Cult of the Wyrm (USA)
|
||||
// Code 1-2 increases drawing distance
|
||||
{ "T40203N", nullptr, { 0x49D7F4, 0x49D8CC, 0x49D6F8, 0 }, { 0x3F07C3BB, 0x447A0000, 0x3FAAAAAB } },
|
||||
{ "T40203N", nullptr, { 0x49D7F4, 0x49D8CC, 0x49D6F8 }, { 0x3F07C3BB, 0x447A0000, 0x3FAAAAAB } },
|
||||
// Ecco the Dolphin: Defender of the Future (PAL)
|
||||
{ "MK-5103350", nullptr, { 0x275418, 0x040E68, 0x040D1C, 0 }, { 0x49D9A5DA, 0x3F100000, 0x3F100000 } },
|
||||
{ "T17705D 05", nullptr, { 0x304870, 0 }, { 0x3F400000 } }, // Evolution - The World of Sacred Device (PAL)
|
||||
{ "T45005D 50", nullptr, { 0x36CE5C, 0x36CE8C, 0 }, { 0x43F00000, 0x3F400000 } }, // Evolution 2 - Far Off Promise (PAL)
|
||||
{ "T1711N", nullptr, { 0x36C76C, 0x36C73C, 0 }, { 0x3F400000, 0x43F00000 } }, // Evolution 2 - Far Off Promise (USA)
|
||||
{ "T8118D 50", nullptr, { 0x2C6B7C, 0 }, { 0x00004000 } }, // Ferrari F355 Challenge (PAL) vga mode only
|
||||
{ "HDR-0100", nullptr, { 0x3235D4, 0 }, { 0x00004000 } }, // Ferrari F355 Challenge (JP) vga mode only
|
||||
{ "MK-5115450", nullptr, { 0x3D3B10, 0 }, { 0x43700000 } }, // Fighting Vipers 2 (PAL)
|
||||
{ "HDR-0133", nullptr, { 0x3D3AF0, 0 }, { 0x43700000 } }, // Fighting Vipers 2 (JP)
|
||||
{ "MK-51114", nullptr, { 0x132DD8, 0xA26CA8, 0xA26738, 0xA275B8, 0xA26AD8, 0xA26908, 0 },
|
||||
{ "MK-5103350", nullptr, { 0x275418, 0x040E68, 0x040D1C }, { 0x49D9A5DA, 0x3F100000, 0x3F100000 } },
|
||||
{ "T17705D 05", nullptr, { 0x304870 }, { 0x3F400000 } }, // Evolution - The World of Sacred Device (PAL)
|
||||
{ "T45005D 50", nullptr, { 0x36CE5C, 0x36CE8C }, { 0x43F00000, 0x3F400000 } }, // Evolution 2 - Far Off Promise (PAL)
|
||||
{ "T1711N", nullptr, { 0x36C76C, 0x36C73C }, { 0x3F400000, 0x43F00000 } }, // Evolution 2 - Far Off Promise (USA)
|
||||
{ "T8118D 50", nullptr, { 0x2C6B7C }, { 0x00004000 } }, // Ferrari F355 Challenge (PAL) vga mode only
|
||||
{ "HDR-0100", nullptr, { 0x3235D4 }, { 0x00004000 } }, // Ferrari F355 Challenge (JP) vga mode only
|
||||
{ "MK-5115450", nullptr, { 0x3D3B10 }, { 0x43700000 } }, // Fighting Vipers 2 (PAL)
|
||||
{ "HDR-0133", nullptr, { 0x3D3AF0 }, { 0x43700000 } }, // Fighting Vipers 2 (JP)
|
||||
{ "MK-51114", nullptr, { 0x132DD8, 0xA26CA8, 0xA26738, 0xA275B8, 0xA26AD8, 0xA26908 },
|
||||
{ 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000 } }, // Floigan Bros. Ep. 1 (PAL)
|
||||
{ "T34201M", nullptr, { 0x586290, 0x586260, 0 }, { 0x3F400000, 0x43F00000 } }, // Frame Gride (JP)
|
||||
{ "T-8113D-50", nullptr, { 0x55A354, 0 }, { 0x3FAAAAAB } }, // Fur Fighters (PAL)
|
||||
{ "T-8107N", nullptr, { 0x55A374, 0 }, { 0x3FAAAAAB } }, // Fur Fighters (USA)
|
||||
{ "T9707D 50", nullptr, { 0x2E7CD0, 0x2E7D04, 0x2E7D10, 0x2E7D0C, 0 },
|
||||
{ "T34201M", nullptr, { 0x586290, 0x586260 }, { 0x3F400000, 0x43F00000 } }, // Frame Gride (JP)
|
||||
{ "T-8113D-50", nullptr, { 0x55A354 }, { 0x3FAAAAAB } }, // Fur Fighters (PAL)
|
||||
{ "T-8107N", nullptr, { 0x55A374 }, { 0x3FAAAAAB } }, // Fur Fighters (USA)
|
||||
{ "T9707D 50", nullptr, { 0x2E7CD0, 0x2E7D04, 0x2E7D10, 0x2E7D0C },
|
||||
{ 0x43BEAE39, 0x3DCCCCCD , 0x44A00000, 0xC4200000 } }, // Gauntlet Legends (PAL)
|
||||
{ "HDR-0004", nullptr, { 0x364A64, 0 }, { 0x43BA0000 } }, // Godzilla Generations (JP)
|
||||
{ "HDR-0047", nullptr, { 0x7C3F24, 0x7C3F54, 0 }, { 0x43F00000, 0x3F400000 } }, // Godzilla Generations Maximum Impact (JP)
|
||||
{ "T41501M", nullptr, { 0x282604, 0x282634, 0 }, { 0x43F00000, 0x3F400000 } }, // Golem no Maigo (aka The Lost Golem) (JP)
|
||||
{ "T1219M", nullptr, { 0xBC3C94, 0 }, { 0x440A7C9A } }, // Gun Spike (JP)
|
||||
{ "T13301N", nullptr, { 0x88E780, 0 }, { 0x3F400000 } }, // Gundam Side Story (USA)
|
||||
// { "T11001N", nullptr, { 0xC3D6BC, 0xD204A8, 0xD32FC8, 0xC7CF84, 0xD20548, 0 },
|
||||
{ "HDR-0004", nullptr, { 0x364A64 }, { 0x43BA0000 } }, // Godzilla Generations (JP)
|
||||
{ "HDR-0047", nullptr, { 0x7C3F24, 0x7C3F54 }, { 0x43F00000, 0x3F400000 } }, // Godzilla Generations Maximum Impact (JP)
|
||||
{ "T41501M", nullptr, { 0x282604, 0x282634 }, { 0x43F00000, 0x3F400000 } }, // Golem no Maigo (aka The Lost Golem) (JP)
|
||||
{ "T1219M", nullptr, { 0xBC3C94 }, { 0x440A7C9A } }, // Gun Spike (JP)
|
||||
{ "T13301N", nullptr, { 0x88E780 }, { 0x3F400000 } }, // Gundam Side Story (USA)
|
||||
// { "T11001N", nullptr, { 0xC3D6BC, 0xD204A8, 0xD32FC8, 0xC7CF84, 0xD20548 },
|
||||
// { 0x00363031, 0x00000356, 0x00000280, 0x00000280, 0x00000280 } }, // Half-Life. Not working
|
||||
{ "MK-5104150", nullptr, { 0x23FCC4, 0 }, { 0x44558000 } }, // Headhunter (PAL)
|
||||
{ "MK-5100250", nullptr, { 0x4C6708, 0 }, { 0x43700000 } }, // House of the Dead 2, The (PAL)
|
||||
{ "MK-51002", nullptr, { 0x4C6088, 0 }, { 0x43700000 } }, // House of the Dead 2, The (USA)
|
||||
{ "T38706M", nullptr, { 0xC0CFA0, 0 }, { 0x3F400000 } }, // Ikaruga (JP)
|
||||
{ "T46001N", nullptr, { 0x1C8A98, 0 }, { 0x3F400000 } }, // Illbleed (USA)
|
||||
{ "T44904D 50", nullptr, { 0x18C15C, 0x18C18C, 0 }, { 0x43F00000, 0x3F400000 } }, // Iron Aces (PAL)
|
||||
{ "MK-51058", nullptr, { 0x32E0FC, 0x32E12C, 0 }, { 0x43F00000, 0x3F400000 } }, // Jet Grind Radio (USA)
|
||||
{ "MK-5105850", nullptr, { 0x32F9EC, 0x32F9BC, 0 }, { 0x3F400000, 0x43F00000 } }, // Jet Set Radio (PAL)
|
||||
{ "HDR-0078", nullptr, { 0x327A8C, 0x327A5C, 0 }, { 0x3F400000, 0x43F00000 } }, // Jet Set Radio (De La) (JP)
|
||||
{ "T22902D 50", nullptr, { 0x278508, 0 }, { 0x43700000 } }, // Kao The Kangaroo (PAL)
|
||||
{ "T22903N", nullptr, { 0x2780A8, 0 }, { 0x43700000 } }, // Kao The Kangaroo (USA)
|
||||
{ "T47803M", nullptr, { 0x0FDFAC, 0 }, { 0x3F400000 } }, // Karous (JP)
|
||||
// { "T41901N", nullptr, { 0x53F580, 0xEFB748, 0xEFB750, 0 }, { 0xC4200000, 0x43A00000, 0x43200000 } }, // KISS Psycho Circus – The Nightmare Child (USA)
|
||||
{ "T2501M", nullptr, { 0x24A878, 0x24A8A8, 0 }, { 0x43F00000, 0x3F400000 } }, // Langrisser Millenium (JP)
|
||||
{ "T15111D 50", nullptr, { 0x29B90C, 0 }, { 0x3F400000 } }, // Le Mans 24 Hours (PAL)
|
||||
{ "T15116N", nullptr, { 0x2198EC, 0 }, { 0x3F400000 } }, // Looney Tunes: Space Race (USA)
|
||||
{ "MK-5105050", nullptr, { 0x33818C, 0 }, { 0x3FA66666 } }, // Maken X (PAL)
|
||||
{ "MK-51050", nullptr, { 0x30CB4C, 0 }, { 0x3F400000 } }, // Maken X (USA)
|
||||
{ "T1212N", nullptr, { 0x2D6B18, 0x268390, 0x268ED8, 0x268934, 0x26947C, 0x269A20, 0x269FC4, 0 },
|
||||
{ "MK-5104150", nullptr, { 0x23FCC4 }, { 0x44558000 } }, // Headhunter (PAL)
|
||||
{ "MK-5100250", nullptr, { 0x4C6708 }, { 0x43700000 } }, // House of the Dead 2, The (PAL)
|
||||
{ "MK-51002", nullptr, { 0x4C6088 }, { 0x43700000 } }, // House of the Dead 2, The (USA)
|
||||
{ "T38706M", nullptr, { 0xC0CFA0 }, { 0x3F400000 } }, // Ikaruga (JP)
|
||||
{ "T46001N", nullptr, { 0x1C8A98 }, { 0x3F400000 } }, // Illbleed (USA)
|
||||
{ "T44904D 50", nullptr, { 0x18C15C, 0x18C18C }, { 0x43F00000, 0x3F400000 } }, // Iron Aces (PAL)
|
||||
{ "MK-51058", nullptr, { 0x32E0FC, 0x32E12C }, { 0x43F00000, 0x3F400000 } }, // Jet Grind Radio (USA)
|
||||
{ "MK-5105850", nullptr, { 0x32F9EC, 0x32F9BC }, { 0x3F400000, 0x43F00000 } }, // Jet Set Radio (PAL)
|
||||
{ "HDR-0078", nullptr, { 0x327A8C, 0x327A5C }, { 0x3F400000, 0x43F00000 } }, // Jet Set Radio (De La) (JP)
|
||||
{ "T22902D 50", nullptr, { 0x278508 }, { 0x43700000 } }, // Kao The Kangaroo (PAL)
|
||||
{ "T22903N", nullptr, { 0x2780A8 }, { 0x43700000 } }, // Kao The Kangaroo (USA)
|
||||
{ "T47803M", nullptr, { 0x0FDFAC }, { 0x3F400000 } }, // Karous (JP)
|
||||
// { "T41901N", nullptr, { 0x53F580, 0xEFB748, 0xEFB750 }, { 0xC4200000, 0x43A00000, 0x43200000 } }, // KISS Psycho Circus – The Nightmare Child (USA)
|
||||
{ "T2501M", nullptr, { 0x24A878, 0x24A8A8 }, { 0x43F00000, 0x3F400000 } }, // Langrisser Millenium (JP)
|
||||
{ "T15111D 50", nullptr, { 0x29B90C }, { 0x3F400000 } }, // Le Mans 24 Hours (PAL)
|
||||
{ "T15116N", nullptr, { 0x2198EC }, { 0x3F400000 } }, // Looney Tunes: Space Race (USA)
|
||||
{ "MK-5105050", nullptr, { 0x33818C }, { 0x3FA66666 } }, // Maken X (PAL)
|
||||
{ "MK-51050", nullptr, { 0x30CB4C }, { 0x3F400000 } }, // Maken X (USA)
|
||||
{ "T1212N", nullptr, { 0x2D6B18, 0x268390, 0x268ED8, 0x268934, 0x26947C, 0x269A20, 0x269FC4 },
|
||||
{ 0x43700000, 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000 } }, // Marvel vs. Capcom 2 (USA)
|
||||
{ "T1215M", nullptr, { 0x2FE2C0, 0x28FB38, 0x290680, 0x2900DC, 0x290C24, 0x2911C8, 0x29176C, 0 },
|
||||
{ "T1215M", nullptr, { 0x2FE2C0, 0x28FB38, 0x290680, 0x2900DC, 0x290C24, 0x2911C8, 0x29176C },
|
||||
{ 0x43700000, 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000 } }, // Marvel vs. Capcom 2 (JP)
|
||||
{ "T41402N", nullptr, { 0x551B80, 0 }, { 0x3F400000 } }, // Max Steel - Covert Missions (USA)
|
||||
{ "MK-5102250", "V1.001", { 0x107FDC, 0x11253C, 0 }, { 0x3F99999A, 0x3F900000 } }, // Metropolis Street Racer (v1.001) (PAL)
|
||||
{ "MK-5102250", "V1.009", { 0x106B5C, 0x1111F4, 0 }, { 0x3F99999A, 0x3F900000 } }, // Metropolis Street Racer (v1.009) (PAL)
|
||||
{ "MK-51012", nullptr, { 0x10A01C, 0x1146FC, 0 }, { 0x3F99999A, 0x3F900000 } }, // Metropolis Street Racer (USA)
|
||||
{ "T0000M", nullptr, { 0x1CAEAC, 0x1CAEDC, 0 }, { 0x43F00000, 0x3F400000 } }, // Millenium Racer Y2K Fighters
|
||||
{ "T1221M", nullptr, { 0x426B74, 0 }, { 0x43F00000 } }, // Moero! Justice Gauken (JP)
|
||||
{ "T9701D", nullptr, { 0x31290C, 0 }, { 0x3F400000 } }, // Mortal Kombat Gold (PAL)
|
||||
{ "T-9701N", nullptr, { 0x337B8C, 0 }, { 0x3FA66666 } }, // Mortal Kombat Gold (USA)
|
||||
{ "T7020D", nullptr, { 0x1A5D40, 0x1A5D18, 0x1A5D38, 0x1A5D34, 0x1A5D30, 0x1A5D3C, 0x1A5D0C, 0x1A5D08, 0x1ACB78, 0 },
|
||||
{ "T41402N", nullptr, { 0x551B80 }, { 0x3F400000 } }, // Max Steel - Covert Missions (USA)
|
||||
{ "MK-5102250", "V1.001", { 0x107FDC, 0x11253C }, { 0x3F99999A, 0x3F900000 } }, // Metropolis Street Racer (v1.001) (PAL)
|
||||
{ "MK-5102250", "V1.009", { 0x106B5C, 0x1111F4 }, { 0x3F99999A, 0x3F900000 } }, // Metropolis Street Racer (v1.009) (PAL)
|
||||
{ "MK-51012", nullptr, { 0x10A01C, 0x1146FC }, { 0x3F99999A, 0x3F900000 } }, // Metropolis Street Racer (USA)
|
||||
{ "T0000M", nullptr, { 0x1CAEAC, 0x1CAEDC }, { 0x43F00000, 0x3F400000 } }, // Millenium Racer Y2K Fighters
|
||||
{ "T1221M", nullptr, { 0x426B74 }, { 0x43F00000 } }, // Moero! Justice Gauken (JP)
|
||||
{ "T9701D", nullptr, { 0x31290C }, { 0x3F400000 } }, // Mortal Kombat Gold (PAL)
|
||||
{ "T-9701N", nullptr, { 0x337B8C }, { 0x3FA66666 } }, // Mortal Kombat Gold (USA)
|
||||
{ "T7020D", nullptr, { 0x1A5D40, 0x1A5D18, 0x1A5D38, 0x1A5D34, 0x1A5D30, 0x1A5D3C, 0x1A5D0C, 0x1A5D08, 0x1ACB78 },
|
||||
{ 0x3F59999A, 0x44084000, 0x3FB1EB85, 0x3FAAAAAB, 0x3F800000, 0x3FA66666, 0xC31B0000, 0x42700000, 0x44160000 } }, // Mr Driller (PAL)
|
||||
{ "T7604M", nullptr, { 0x43BDA4, 0x43BDD8, 0x4319E8, 0x431A08, 0x431A28, 0x431A48, 0 },
|
||||
{ "T7604M", nullptr, { 0x43BDA4, 0x43BDD8, 0x4319E8, 0x431A08, 0x431A28, 0x431A48 },
|
||||
{ 0x43700000, 0x3F9AF5C2, 0x42200000, 0x42200000, 0x438C0000, 0x438C0000 } }, // Nanatsu no Hikan - Senritsu no Bishou (JP)
|
||||
{ "HDR-0079", nullptr, { 0x353744, 0x353774, 0x353778, 0 },
|
||||
{ "HDR-0079", nullptr, { 0x353744, 0x353774, 0x353778 },
|
||||
{ 0x43F00000, 0x3F400000, 0x3F800000 } }, // Napple Tale: Arsia in Daydream (JP)
|
||||
//crash { "MK-51178", nullptr, { 0x23AF00, 0x23B160, 0x144D40, 0x2105B4, 0x705B40, 0 },
|
||||
//crash { "MK-51178", nullptr, { 0x23AF00, 0x23B160, 0x144D40, 0x2105B4, 0x705B40 },
|
||||
// { 0xBFAAAAAB, 0xBFAAAAAB, 0xBFAAAAAB, 0xBFAAAAAB, 0x44558000 } }, // NBA 2K2
|
||||
{ "T9504M", nullptr, { 0xCDE848, 0xCDE844, 0 }, { 0x3F400000, 0x3FA00000 } }, // Nightmare Creatures II (USA)
|
||||
{ "T-9502D-50", nullptr, { 0xBDE9B0, 0xBDE9C4, 0 }, { 0x3F400000, 0x3FA00000 } }, // Nightmare Creatures II (PAL)
|
||||
{ "MK-5110250", nullptr, { 0x87B5A4, 0 }, { 0x43700000 } }, // Outtrigger (PAL)
|
||||
{ "HDR-0118", nullptr, { 0x83E284, 0 }, { 0x43700000 } }, // Outtrigger (JP)
|
||||
{ "T15103D 50", nullptr, { 0x1EEE78, 0 }, { 0x3F400000 } }, // PenPen (PAL)
|
||||
{ "T17001M", nullptr, { 0x1C3828, 0 }, { 0x3F400000 } }, // PenPen TriIcelon (JP)
|
||||
{ "MK-5110050", nullptr, { 0x548E04, 0x0923C0, 0 }, { 0x43E80000, 0x3F966666 } }, // Phantasy Star Online (PAL) TODO
|
||||
{ "MK-51100", nullptr, { 0x548E84, 0x0925A4, 0 }, { 0x43D20000, 0x3FA66666 } }, // Phantasy Star Online (USA) TODO
|
||||
{ "HDR-0129", nullptr, { 0x57E344, 0x091794, 0 }, { 0x43D20000, 0x3FA66666 } }, // Phantasy Star Online (JP) TODO
|
||||
{ "MK-5119350", nullptr, { 0x57552C, 0x0A2DD4, 0 }, { 0x43F00000, 0x3F911111 } }, // Phantasy Star Online Ver. 2 (PAL) TODO
|
||||
{ "MK-51193", nullptr, { 0x0A3138, 0x58C8CC, 0 }, { 0x3F911111, 0x43F00000 } }, // Phantasy Star Online Ver. 2 (USA) TODO
|
||||
{ "T1207N", nullptr, { 0x7D463C, 0 }, { 0x3F400000 } }, // Plasma Sword - Nightmare of Bilstein (USA)
|
||||
{ "T36801D 50", nullptr, { 0x7FD3C8, 0 }, { 0x43700000 } }, // Power Stone (PAL)
|
||||
{ "T1201N", nullptr, { 0x7FCEE8, 0 }, { 0x43700000 } }, // Power Stone (USA)
|
||||
{ "T36812D 50", nullptr, { 0x868BA8, 0 }, { 0x43700000 } }, // Power Stone 2 (PAL)
|
||||
{ "T1211N", nullptr, { 0x8689A8, 0 }, { 0x43700000 } }, // Power Stone 2 (USA)
|
||||
{ "T1218M", nullptr, { 0x849AA0, 0 }, { 0x43700000 } }, // Power Stone 2 (JP)
|
||||
{ "T7022D 50", nullptr, { 0x33414C, 0 }, { 0x43F00000 } }, // Project Justice (PAL)
|
||||
{ "T1219N", nullptr, { 0x33374C, 0 }, { 0x43F00000 } }, // Project Justice (USA)
|
||||
{ "MK-51162", nullptr, { 0x204308, 0 }, { 0x3FE38E39 } }, // Propeller Arena
|
||||
{ "T-8106D-50", nullptr, { 0x7DA39C, 0 }, { 0x3F400000 } }, // Psychic Force 2012 (PAL)
|
||||
{ "T9901M", nullptr, { 0x1AD848, 0 }, { 0x3F400000 } }, // Rainbow Cotton (JP)
|
||||
{ "T9711D 50", nullptr, { 0x1574D8, 0 }, { 0x43700000 } }, // Ready 2 Rumble Boxing Round 2 (PAL)
|
||||
{ "T7012D 05", nullptr, { 0x4FF93C, 0x4FF96C, 0 }, { 0x43F00000, 0x3F400000 } }, // Record of Lodoss War (En) (PAL)
|
||||
{ "xxxxxxxxxx", nullptr, { 0x4FF25C, 0x4FF28C, 0 }, { 0x43F00000, 0x3F400000 } }, // Record of Lodoss War (De) (PAL)
|
||||
{ "T7012D 09", nullptr, { 0x50499C, 0x5049CC, 0 }, { 0x43F00000, 0x3F400000 } }, // Record of Lodoss War (Fr) (PAL)
|
||||
{ "MK-5102151", nullptr, { 0x3511A0, 0 }, { 0x3FC58577 } }, // Red Dog (PAL)
|
||||
{ "HDR-0074", nullptr, { 0x1FF60C, 0x1FF610, 0x1FF5DC, 0 }, { 0x3F400000, 0x3F800000, 0x43DC0000 } }, //Rent a Hero n°1
|
||||
{ "T9504M", nullptr, { 0xCDE848, 0xCDE844 }, { 0x3F400000, 0x3FA00000 } }, // Nightmare Creatures II (USA)
|
||||
{ "T-9502D-50", nullptr, { 0xBDE9B0, 0xBDE9C4 }, { 0x3F400000, 0x3FA00000 } }, // Nightmare Creatures II (PAL)
|
||||
{ "MK-5110250", nullptr, { 0x87B5A4 }, { 0x43700000 } }, // Outtrigger (PAL)
|
||||
{ "HDR-0118", nullptr, { 0x83E284 }, { 0x43700000 } }, // Outtrigger (JP)
|
||||
{ "T15103D 50", nullptr, { 0x1EEE78 }, { 0x3F400000 } }, // PenPen (PAL)
|
||||
{ "T17001M", nullptr, { 0x1C3828 }, { 0x3F400000 } }, // PenPen TriIcelon (JP)
|
||||
{ "MK-5110050", nullptr, { 0x548E04, 0x0923C0 }, { 0x43E80000, 0x3F966666 } }, // Phantasy Star Online (PAL) TODO
|
||||
{ "MK-51100", nullptr, { 0x548E84, 0x0925A4 }, { 0x43D20000, 0x3FA66666 } }, // Phantasy Star Online (USA) TODO
|
||||
{ "HDR-0129", nullptr, { 0x57E344, 0x091794 }, { 0x43D20000, 0x3FA66666 } }, // Phantasy Star Online (JP) TODO
|
||||
{ "MK-5119350", nullptr, { 0x57552C, 0x0A2DD4 }, { 0x43F00000, 0x3F911111 } }, // Phantasy Star Online Ver. 2 (PAL) TODO
|
||||
{ "MK-51193", nullptr, { 0x0A3138, 0x58C8CC }, { 0x3F911111, 0x43F00000 } }, // Phantasy Star Online Ver. 2 (USA) TODO
|
||||
{ "T1207N", nullptr, { 0x7D463C }, { 0x3F400000 } }, // Plasma Sword - Nightmare of Bilstein (USA)
|
||||
{ "T36801D 50", nullptr, { 0x7FD3C8 }, { 0x43700000 } }, // Power Stone (PAL)
|
||||
{ "T1201N", nullptr, { 0x7FCEE8 }, { 0x43700000 } }, // Power Stone (USA)
|
||||
{ "T36812D 50", nullptr, { 0x868BA8 }, { 0x43700000 } }, // Power Stone 2 (PAL)
|
||||
{ "T1211N", nullptr, { 0x8689A8 }, { 0x43700000 } }, // Power Stone 2 (USA)
|
||||
{ "T1218M", nullptr, { 0x849AA0 }, { 0x43700000 } }, // Power Stone 2 (JP)
|
||||
{ "T7022D 50", nullptr, { 0x33414C }, { 0x43F00000 } }, // Project Justice (PAL)
|
||||
{ "T1219N", nullptr, { 0x33374C }, { 0x43F00000 } }, // Project Justice (USA)
|
||||
{ "MK-51162", nullptr, { 0x204308 }, { 0x3FE38E39 } }, // Propeller Arena
|
||||
{ "T-8106D-50", nullptr, { 0x7DA39C }, { 0x3F400000 } }, // Psychic Force 2012 (PAL)
|
||||
{ "T9901M", nullptr, { 0x1AD848 }, { 0x3F400000 } }, // Rainbow Cotton (JP)
|
||||
{ "T9711D 50", nullptr, { 0x1574D8 }, { 0x43700000 } }, // Ready 2 Rumble Boxing Round 2 (PAL)
|
||||
{ "T7012D 05", nullptr, { 0x4FF93C, 0x4FF96C }, { 0x43F00000, 0x3F400000 } }, // Record of Lodoss War (En) (PAL)
|
||||
{ "xxxxxxxxxx", nullptr, { 0x4FF25C, 0x4FF28C }, { 0x43F00000, 0x3F400000 } }, // Record of Lodoss War (De) (PAL)
|
||||
{ "T7012D 09", nullptr, { 0x50499C, 0x5049CC }, { 0x43F00000, 0x3F400000 } }, // Record of Lodoss War (Fr) (PAL)
|
||||
{ "MK-5102151", nullptr, { 0x3511A0 }, { 0x3FC58577 } }, // Red Dog (PAL)
|
||||
{ "HDR-0074", nullptr, { 0x1FF60C, 0x1FF610, 0x1FF5DC }, { 0x3F400000, 0x3F800000, 0x43DC0000 } }, //Rent a Hero n°1
|
||||
// Resident Evil: Code Veronica (De) (PAL)
|
||||
// Code 1-4 removes the black bars on top and bottom in FMV
|
||||
{ "xxxxxxxxxx", nullptr, { 0x32A380, 0x383E18, 0x383E38, 0x383E58, 0x383E78, 0 },
|
||||
{ "xxxxxxxxxx", nullptr, { 0x32A380, 0x383E18, 0x383E38, 0x383E58, 0x383E78 },
|
||||
{ 0x3F400000, 0x43F00000, 0, 0x43F00000, 0 } },
|
||||
// Resident Evil: Code Veronica (Fr) (PAL)
|
||||
// Code 1-4 removes the black bars on top and bottom in FMV
|
||||
{ "T36806D 09", nullptr, { 0x32A380, 0x383E18, 0x383E38, 0x383E58, 0x383E78, 0 },
|
||||
{ "T36806D 09", nullptr, { 0x32A380, 0x383E18, 0x383E38, 0x383E58, 0x383E78 },
|
||||
{ 0x3F400000, 0x43F00000, 0, 0x43F00000, 0 } },
|
||||
// Resident Evil: Code Veronica (Sp) (PAL)
|
||||
{ "xxxxxxxxxx", nullptr, { 0x32A3A0, /* 0x383E18, 0x383E38, 0x383E58, 0x383E78, */ 0 },
|
||||
{ "xxxxxxxxxx", nullptr, { 0x32A3A0 /*, 0x383E18, 0x383E38, 0x383E58, 0x383E78 */ },
|
||||
{ 0x3F400000, 0x43F00000, 0, 0x43F00000, 0 } },
|
||||
// Resident Evil: Code Veronica (USA)
|
||||
// Code 1-4 removes the black bars on top and bottom in FMV
|
||||
{ "T1204N", nullptr, { 0x329E40, 0x3838D8, 0x3838F8, 0x383918, 0x383938, 0 },
|
||||
{ "T1204N", "RESIDENT EVIL CODE VERONICA ",
|
||||
{ 0x329E40, 0x3838D8, 0x3838F8, 0x383918, 0x383938 },
|
||||
{ 0x3F400000, 0x43F00000, 0, 0x43F00000, 0 } },
|
||||
{ "T8107D 50", nullptr, { 0x0464FC, 0x046210, 0 }, { 0x3A888889, 0x44200000 } }, // Re-Volt (PAL) Code 1 is a render fix
|
||||
{ "MK-5119250", nullptr, { 0x0C5EB4, 0 }, { 0x3A888889 } }, // Rez (PAL)
|
||||
{ "T15122N", nullptr, { 0x8E7A80, 0x8E7AB4, 0 }, { 0x43E10000, 0x3FAAAAAB } }, // Ring, The - Terror's Realm (USA)
|
||||
{ "MK-51010", nullptr, { 0x1A4D2C, 0x1A4D5C, 0 }, { 0x43F00000, 0x3F400000 } }, // Rippin' Riders (USA)
|
||||
{ "HDR-0044", nullptr, { 0x298A94, 0x298AC4, 0 }, { 0x43F00000, 0x3F400000 } }, // Roommania #203 (JP)
|
||||
{ "MK-5109250", nullptr, { 0x29E6C4, 0 }, { 0x3F400000 } }, // Samba De Amigo (PAL)
|
||||
{ "T41301N", nullptr, { 0x77A178, 0 }, { 0x3F400000 } }, // Seventh Cross Evolution (USA)
|
||||
{ "T8104D 58", nullptr, { 0x2C03F8, 0 }, { 0x44558000 } }, // Shadow Man (PAL)
|
||||
{ "T-8106N", nullptr, { 0x2C03F4, 0 }, { 0x3F400000 } }, // Shadow Man (USA)
|
||||
{ "MK-51048", nullptr, { 0x4AA4DC, 0x2B4E30, 0 }, { 0x3F400000, 0x3F400000 } }, // Seaman (USA)
|
||||
{ "MK-5105350", nullptr, { 0x5D613C, 0 }, { 0x3F400000 } }, // Sega GT (PAL)
|
||||
{ "MK-51096", nullptr, { 0x495050, 0 }, { 0x43700000 } }, // Sega Marine Fishing (USA)
|
||||
// { "MK-51019", nullptr, { 0xB83A48, 0 }, { 0x3F400000 } }, // Sega Rally 2 (USA) not working?
|
||||
// { "HDR0010", nullptr, { 0xBD9BA0, 0 }, { 0x3F400000 } }, // Sega Rally 2 (JP) not working?
|
||||
{ "HDR-0151", nullptr, { 0xAF57DC, 0xAF580C, 0x2122A0, 0 },
|
||||
{ "T8107D 50", nullptr, { 0x0464FC, 0x046210 }, { 0x3A888889, 0x44200000 } }, // Re-Volt (PAL) Code 1 is a render fix
|
||||
{ "MK-5119250", nullptr, { 0x0C5EB4 }, { 0x3A888889 } }, // Rez (PAL)
|
||||
{ "T15122N", nullptr, { 0x8E7A80, 0x8E7AB4 }, { 0x43E10000, 0x3FAAAAAB } }, // Ring, The - Terror's Realm (USA)
|
||||
{ "MK-51010", nullptr, { 0x1A4D2C, 0x1A4D5C }, { 0x43F00000, 0x3F400000 } }, // Rippin' Riders (USA)
|
||||
{ "HDR-0044", nullptr, { 0x298A94, 0x298AC4 }, { 0x43F00000, 0x3F400000 } }, // Roommania #203 (JP)
|
||||
{ "MK-5109250", nullptr, { 0x29E6C4 }, { 0x3F400000 } }, // Samba De Amigo (PAL)
|
||||
{ "T41301N", nullptr, { 0x77A178 }, { 0x3F400000 } }, // Seventh Cross Evolution (USA)
|
||||
{ "T8104D 58", nullptr, { 0x2C03F8 }, { 0x44558000 } }, // Shadow Man (PAL)
|
||||
{ "T-8106N", nullptr, { 0x2C03F4 }, { 0x3F400000 } }, // Shadow Man (USA)
|
||||
{ "MK-51048", nullptr, { 0x4AA4DC, 0x2B4E30 }, { 0x3F400000, 0x3F400000 } }, // Seaman (USA)
|
||||
{ "MK-5105350", nullptr, { 0x5D613C }, { 0x3F400000 } }, // Sega GT (PAL)
|
||||
{ "MK-51096", nullptr, { 0x495050 }, { 0x43700000 } }, // Sega Marine Fishing (USA)
|
||||
// { "MK-51019", nullptr, { 0xB83A48 }, { 0x3F400000 } }, // Sega Rally 2 (USA) not working?
|
||||
// { "HDR0010", nullptr, { 0xBD9BA0 }, { 0x3F400000 } }, // Sega Rally 2 (JP) not working?
|
||||
{ "HDR-0151", nullptr, { 0xAF57DC, 0xAF580C, 0x2122A0 },
|
||||
{ 0x43F00000, 0x3F400000, 0x3F400000 } }, // SGGG – Segagaga (JP)
|
||||
{ "MK-5105950", nullptr, { 0x231EF8, 0x1EF370, 0 }, { 0x43800000, 0x7C1EF400 } }, // Shenmue (PAL) code 1 reduces clipping
|
||||
{ "MK-51059", nullptr, { 0x230250, 0 }, { 0x43800000 } }, // Shenmue (USA) Clipping
|
||||
{ "HDR-0016", nullptr, { 0x22E8A0, 0x1EBE70, 0 }, { 0x43800000, 0x7C1EBF00 } }, // Shenmue (JP) code 1 reduces clipping
|
||||
{ "MK-5118450", nullptr, { 0x31186C, 0 }, { 0x43800000 } }, // Shenmue II (PAL) 01160FF4 0000E100 for black bars in cutscenes
|
||||
{ "MK-5105950", nullptr, { 0x231EF8, 0x1EF370 }, { 0x43800000, 0x7C1EF400 } }, // Shenmue (PAL) code 1 reduces clipping
|
||||
{ "MK-51059", nullptr, { 0x230250 }, { 0x43800000 }, { 0x43a00000 } }, // Shenmue (USA) Clipping
|
||||
{ "HDR-0016", nullptr, { 0x22E8A0, 0x1EBE70 }, { 0x43800000, 0x7C1EBF00 } }, // Shenmue (JP) code 1 reduces clipping
|
||||
{ "MK-5118450", nullptr, { 0x31186C }, { 0x43800000 } }, // Shenmue II (PAL) 01160FF4 0000E100 for black bars in cutscenes
|
||||
// Shenmue II (PAL) Alternative code without clipping or black bars. Might be demanding on real hardware.
|
||||
// 02311880 C3A00000, 0227E198 35AA359E, 01160FF4 0000E100
|
||||
{ "HDR-0164", nullptr, { 0x30D67C, 0 }, { 0x43700000 } }, // Shenmue II (JP) Clipping
|
||||
{ "T9505D", nullptr, { 0xD1FB14, 0x096A4C, 0 }, { 0x3F400000, 0x3FAAAAAB } }, // Silent Scope (PAL) Choose 60Hz in game options
|
||||
{ "MK-51052", " E ", { 0x502A84, 0 }, { 0x3F400000 } }, // Skies of Arcadia (PAL)
|
||||
{ "MK-51052", " U ", { 0x599158, 0 }, { 0x3F400000 } }, // Skies of Arcadia (USA)
|
||||
{ "T15104D 50", nullptr, { 0x17EF68, 0 }, { 0x43F00010 } }, // Slave Zero (PAL) Widescreen, but a bit zoomed in
|
||||
{ "MK-5101050", nullptr, { 0x1A50EC, 0x1A511C, 0 }, { 0x43F00000, 0x3F400000 } }, // Snow Surfers (PAL)
|
||||
{ "MK-5100050", nullptr, { 0x88F528, 0x88F55C, 0 }, { 0x43F00000, 0x3FA66666 } }, // Sonic Adventure (PAL)
|
||||
{ "MK-51000", nullptr, { 0x88F5E8, 0x88F61C, 0 }, { 0x43F00000, 0x3FAAAAAB } }, // Sonic Adventure (USA)
|
||||
{ "MK-51117", nullptr, { 0x28DEF8, 0x28DF28, 0 }, { 0x43F00000, 0x3f400000 } }, // Sonic Adventure 2 (USA)
|
||||
{ "HDR-0165", nullptr, { 0x28DF28, 0x28DEF8, 0 }, { 0x3F400000, 0x43F00000 } }, // Sonic Adventure 2 (JP)
|
||||
{ "MK-51060", nullptr, { 0x112A2C, 0 }, { 0x3F400000 } }, // Sonic Shuffle (US)
|
||||
{ "MK-5106050", nullptr, { 0x110B4C, 0 }, { 0x3F400000 } }, // Sonic Shuffle (PAL)
|
||||
{ "T9103M", nullptr, { 0x25C714, 0x25C744, 0 }, { 0x43F00000, 0x3F400000 } }, // Sorcerian - Shichisei Mahou no Shito
|
||||
{ "T1401D 50", nullptr, { 0x2D6138, 0 }, { 0x3F400000 } }, // Soul Calibur (PAL)
|
||||
{ "T1401N", nullptr, { 0x266C28, 0 }, { 0x3F400000 } }, // Soul Calibur (USA)
|
||||
{ "T36802N", " E ", { 0x129FA0, 0x12A9BC, 0x1C9FDC, 0 },
|
||||
{ "HDR-0164", nullptr, { 0x30D67C }, { 0x43700000 } }, // Shenmue II (JP) Clipping
|
||||
{ "T9505D", nullptr, { 0xD1FB14, 0x096A4C }, { 0x3F400000, 0x3FAAAAAB } }, // Silent Scope (PAL) Choose 60Hz in game options
|
||||
{ "MK-51052", " E ", { 0x502A84 }, { 0x3F400000 } }, // Skies of Arcadia (PAL)
|
||||
{ "MK-51052", " U ", { 0x599158 }, { 0x3F400000 } }, // Skies of Arcadia (USA)
|
||||
{ "T15104D 50", nullptr, { 0x17EF68 }, { 0x43F00010 } }, // Slave Zero (PAL) Widescreen, but a bit zoomed in
|
||||
{ "MK-5101050", nullptr, { 0x1A50EC, 0x1A511C }, { 0x43F00000, 0x3F400000 } }, // Snow Surfers (PAL)
|
||||
{ "MK-5100050", nullptr, { 0x88F528, 0x88F55C }, { 0x43F00000, 0x3FA66666 } }, // Sonic Adventure (PAL)
|
||||
{ "MK-51000", nullptr, { 0x88F5E8, 0x88F61C }, { 0x43F00000, 0x3FAAAAAB } }, // Sonic Adventure (USA)
|
||||
{ "MK-51117", nullptr, { 0x28DEF8, 0x28DF28 }, { 0x43F00000, 0x3f400000 } }, // Sonic Adventure 2 (USA)
|
||||
{ "HDR-0165", nullptr, { 0x28DF28, 0x28DEF8 }, { 0x3F400000, 0x43F00000 } }, // Sonic Adventure 2 (JP)
|
||||
{ "MK-51060", nullptr, { 0x112A2C }, { 0x3F400000 } }, // Sonic Shuffle (US)
|
||||
{ "MK-5106050", nullptr, { 0x110B4C }, { 0x3F400000 } }, // Sonic Shuffle (PAL)
|
||||
{ "T9103M", nullptr, { 0x25C714, 0x25C744 }, { 0x43F00000, 0x3F400000 } }, // Sorcerian - Shichisei Mahou no Shito
|
||||
{ "T1401D 50", nullptr, { 0x2D6138 }, { 0x3F400000 } }, // Soul Calibur (PAL)
|
||||
{ "T1401N", nullptr, { 0x266C28 }, { 0x3F400000 } }, // Soul Calibur (USA)
|
||||
{ "T36802N", " E ", { 0x129FA0, 0x12A9BC, 0x1C9FDC },
|
||||
{ 0x3EF55555, 0x3EF55555, 0x000000F0 } }, // Soul Reaver (PAL) Code 2 is a Render Fix
|
||||
{ "HDR-0190", nullptr, { 0x14D3E0, 0 }, { 0x3F400000 } }, // Space Channel 5 Part 2 (JP)
|
||||
{ "T1216M", nullptr, { 0x017C38, 0x17F00, 0 }, { 0x3A99999A, 0x3A99999A } }, // Spawn - In the Demon's Hand v1.003 (JP)
|
||||
{ "T1216N", nullptr, { 0x017C58, 0x17F20, 0 }, { 0x3A99999A, 0x3A99999A } }, // Spawn - In the Demon's Hand v1.000 (US)
|
||||
{ "T36816D 50", nullptr, { 0x017C78, 0x17F40, 0 }, { 0x3A99999A, 0x3A99999A } }, // Spawn - In the Demon's Hand v1.000 (EU)
|
||||
{ "HDR-0190", nullptr, { 0x14D3E0 }, { 0x3F400000 } }, // Space Channel 5 Part 2 (JP)
|
||||
{ "T1216M", nullptr, { 0x017C38, 0x17F00 }, { 0x3A99999A, 0x3A99999A } }, // Spawn - In the Demon's Hand v1.003 (JP)
|
||||
{ "T1216N", nullptr, { 0x017C58, 0x17F20 }, { 0x3A99999A, 0x3A99999A } }, // Spawn - In the Demon's Hand v1.000 (US)
|
||||
{ "T36816D 50", nullptr, { 0x017C78, 0x17F40 }, { 0x3A99999A, 0x3A99999A } }, // Spawn - In the Demon's Hand v1.000 (EU)
|
||||
// Star Wars Episode I Racer (USA)
|
||||
// Code 1-4 removes the black bars on top and bottom in FMV
|
||||
{ "T23001N", nullptr, { 0x17AE20, 0x29A96C, 0x29A98C, 0x29A9AC, 0x29A9CC, 0 },
|
||||
{ "T23001N", nullptr, { 0x17AE20, 0x29A96C, 0x29A98C, 0x29A9AC, 0x29A9CC },
|
||||
{ 0x3F400000, 0x42900000, 0x42900000, 0x43CE0000, 0x43CE0000 } },
|
||||
{ "T40206N", nullptr, { 0x43296C, 0 }, { 0x3F400000, 0 } }, // Super Magnetic Neo (US)
|
||||
{ "T40206D 50", nullptr, { 0x43E34C, 0 }, { 0x3F400000, 0 } }, // Super Magnetic Neo (EU)
|
||||
// { "T7014D 50", nullptr, { 0xE2B234, 0 }, { 0x3F800000 } }, // Super Runabout (PAL) doesn't work?
|
||||
{ "T17721D 50", nullptr, { 0x45CED4, 0 }, { 0x3F400000 } }, // Surf Rocket Racers (PAL) alt: 021EBF40 3F400000
|
||||
{ "T17703D 50", nullptr, { 0xCD8950, 0 }, { 0x3F111111 } }, // Suzuki Alstare Extreme Racing
|
||||
{ "T36807D 05", nullptr, { 0x140F74, 0x140FA4, 0 }, { 0x43FA0000, 0x3F400000 } }, // Sword of Bersek (PAL)
|
||||
{ "T-36805N", nullptr, { 0x13F1C4, 0x13F194, 0 }, { 0x3F400000, 0x43F00000 } }, // Sword of Bersek (USA)
|
||||
{ "MK-51186", nullptr, { 0x4A19B0, 0 }, { 0x43700000 } }, // Tennis 2K2 (USA)
|
||||
{ "T15123N", nullptr, { 0x29B7BC, 0 }, { 0x3F400000 } }, // Test Drive Le Mans (USA) doesn't work?
|
||||
{ "T20801M", nullptr, { 0x1AAC80, 0x1AACB0, 0 }, { 0x43F00000, 0x3F400000 } }, // Tetris 4D (JP)
|
||||
{ "MK-5101153", nullptr, { 0x14EFA8, 0x14EFD8, 0 }, { 0x43F00000, 0x3F400000 } }, // Timestalkers (PAL)
|
||||
{ "T7009D50", nullptr, { 0x39173C, 0 }, { 0x3F400000 } }, // Tech Romancer (PAL)
|
||||
{ "T35402M", nullptr, { 0x315370, 0x3153A0, 0 }, { 0x43F00000, 0x3F400000 } }, // Tokyo Bus Guide (JP) doesn't work?
|
||||
{ "T40201D 50", nullptr, { 0x1D9F10, 0 }, { 0x3F400000 } }, // Tokyo Highway Challenge (PAL)
|
||||
{ "T40210D 50", nullptr, { 0x21E4F8, 0 }, { 0x43700000 } }, // Tokyo Highway Challenge 2 (PAL)
|
||||
{ "xxxxxxxxxx", nullptr, { 0x21DEF8, 0 }, { 0x3F400000 } }, // Tokyo Street Racer 2 (USA)
|
||||
// { "T36804D05", nullptr, { 0xB75E28, 0 }, { 0x3EC00000 } }, // Tomb Raider: The Last Revelation (UK) (PAL) clipping, use hex patch instead
|
||||
{ "T13008D 05", nullptr, { 0x1D7C20, 0 }, { 0x3FA66666 } }, // Tony Hawk's Pro Skater 2 (PAL)
|
||||
{ "T13006N", nullptr, { 0x1D77A0, 0 }, { 0x3FA66666 } }, // Tony Hawk's Pro Skater 2 (USA)
|
||||
{ "MK-5102050", nullptr, { 0x0D592C, 0 }, { 0x3FD00000 } }, // Toy Commander (PAL)
|
||||
{ "xxxxxxxxxx", nullptr, { 0x469FCC, 0x469FFC, 0 }, { 0x44700000, 0x3F400000 } }, // Toyota Doricatch Series: Land Cruiser 100/Cygnus
|
||||
{ "MK-5109505", nullptr, { 0x1B2718, 0 }, { 0x3F400000 } }, // UEFA Dream Soccer (PAL)
|
||||
{ "T40203D 50", nullptr, { 0x1D74E8, 0x1D7518, 0 }, { 0x43F00000, 0x3F400000 } }, // Ultimate Fighting Championship (PAL)
|
||||
{ "T40204N", nullptr, { 0x1A9684, 0 }, { 0x3F400000 } }, // Ultimate Fighting Championship (USA) problems with cam in game
|
||||
{ "T-8110D-50", nullptr, { 0x0C6B90, 0x0C6B94, 0 }, { 0x43F00000, 0x43870000 } }, // Vanishing Point (PAL)
|
||||
// { "MK-5109450", nullptr, { 0x244134, 0x7A73B8, 0x7830D8, 0x7A74B8, 0x783138, 0x7A85A0, 0x6C7928, 0x6C7930, 0x6C7948, 0x6C7950, 0 },
|
||||
{ "T40206N", nullptr, { 0x43296C }, { 0x3F400000 } }, // Super Magnetic Neo (US)
|
||||
{ "T40206D 50", nullptr, { 0x43E34C }, { 0x3F400000 } }, // Super Magnetic Neo (EU)
|
||||
// { "T7014D 50", nullptr, { 0xE2B234 }, { 0x3F800000 } }, // Super Runabout (PAL) doesn't work?
|
||||
{ "T17721D 50", nullptr, { 0x45CED4 }, { 0x3F400000 } }, // Surf Rocket Racers (PAL) alt: 021EBF40 3F400000
|
||||
{ "T17703D 50", nullptr, { 0xCD8950 }, { 0x3F111111 } }, // Suzuki Alstare Extreme Racing
|
||||
{ "T36807D 05", nullptr, { 0x140F74, 0x140FA4 }, { 0x43FA0000, 0x3F400000 } }, // Sword of Bersek (PAL)
|
||||
{ "T-36805N", nullptr, { 0x13F1C4, 0x13F194 }, { 0x3F400000, 0x43F00000 } }, // Sword of Bersek (USA)
|
||||
{ "MK-51186", nullptr, { 0x4A19B0 }, { 0x43700000 } }, // Tennis 2K2 (USA)
|
||||
{ "T15123N", nullptr, { 0x29B7BC }, { 0x3F400000 } }, // Test Drive Le Mans (USA) doesn't work?
|
||||
{ "T20801M", nullptr, { 0x1AAC80, 0x1AACB0 }, { 0x43F00000, 0x3F400000 } }, // Tetris 4D (JP)
|
||||
{ "MK-5101153", nullptr, { 0x14EFA8, 0x14EFD8 }, { 0x43F00000, 0x3F400000 } }, // Timestalkers (PAL)
|
||||
{ "T7009D50", nullptr, { 0x39173C }, { 0x3F400000 } }, // Tech Romancer (PAL)
|
||||
{ "T35402M", nullptr, { 0x315370, 0x3153A0 }, { 0x43F00000, 0x3F400000 } }, // Tokyo Bus Guide (JP) doesn't work?
|
||||
{ "T40201D 50", nullptr, { 0x1D9F10 }, { 0x3F400000 } }, // Tokyo Highway Challenge (PAL)
|
||||
{ "T40210D 50", nullptr, { 0x21E4F8 }, { 0x43700000 } }, // Tokyo Highway Challenge 2 (PAL)
|
||||
{ "xxxxxxxxxx", nullptr, { 0x21DEF8 }, { 0x3F400000 } }, // Tokyo Street Racer 2 (USA)
|
||||
// { "T36804D05", nullptr, { 0xB75E28 }, { 0x3EC00000 } }, // Tomb Raider: The Last Revelation (UK) (PAL) clipping, use hex patch instead
|
||||
{ "T13008D 05", nullptr, { 0x1D7C20 }, { 0x3FA66666 } }, // Tony Hawk's Pro Skater 2 (PAL)
|
||||
{ "T13006N", nullptr, { 0x1D77A0 }, { 0x3FA66666 } }, // Tony Hawk's Pro Skater 2 (USA)
|
||||
{ "MK-5102050", nullptr, { 0x0D592C }, { 0x3FD00000 } }, // Toy Commander (PAL)
|
||||
{ "xxxxxxxxxx", nullptr, { 0x469FCC, 0x469FFC }, { 0x44700000, 0x3F400000 } }, // Toyota Doricatch Series: Land Cruiser 100/Cygnus
|
||||
{ "MK-5109505", nullptr, { 0x1B2718 }, { 0x3F400000 } }, // UEFA Dream Soccer (PAL)
|
||||
{ "T40203D 50", nullptr, { 0x1D74E8, 0x1D7518 }, { 0x43F00000, 0x3F400000 } }, // Ultimate Fighting Championship (PAL)
|
||||
{ "T40204N", nullptr, { 0x1A9684 }, { 0x3F400000 } }, // Ultimate Fighting Championship (USA) problems with cam in game
|
||||
{ "T-8110D-50", nullptr, { 0x0C6B90, 0x0C6B94 }, { 0x43F00000, 0x43870000 } }, // Vanishing Point (PAL)
|
||||
// { "MK-5109450", nullptr, { 0x244134, 0x7A73B8, 0x7830D8, 0x7A74B8, 0x783138, 0x7A85A0, 0x6C7928, 0x6C7930, 0x6C7948, 0x6C7950 },
|
||||
//crash { 0x43F00000, 0x3F9C932E, 0x3F9C932E, 0x3F9C932E, 0x3F9C932E, 0x3F400000, 0, 0, 0, 0 } }, // Virtua Athlete 2K (PAL)
|
||||
{ "MK-5100150", nullptr, { 0x19D718, 0 }, { 0x43700000 } }, // Virtua Fighter 3 TB (PAL)
|
||||
{ "HDR-0002", nullptr, { 0x199FB0, 0 }, { 0x43700000 } }, // Virtua Fighter 3 TB (JP)
|
||||
{ "MK-5105450", nullptr, { 0x456378, 0 }, { 0x43700000 } }, // Virtua Tennis (v1.001) (PAL)
|
||||
{ "MK-51054", nullptr, { 0x450A90, 0 }, { 0x43700000 } }, // Virtua Tennis (USA)
|
||||
{ "MK-5118650", nullptr, { 0x4A4A20, 0 }, { 0x43700000 } }, // Virtua Tennis 2 (PAL)
|
||||
// { "T0000", nullptr, { 0x3A514C, 0x3A6170, 0 }, { 0x3F400000, 0x00000356 } }, // Volgarr the Viking. Not working
|
||||
{ "xxxxxxxxxx", nullptr, { 0x20BB68, 0x1ACBD0, 0x1B9ADC, 0 }, // Code 1 reduces clipping. Code 2 fixes the clock.
|
||||
{ "MK-5100150", nullptr, { 0x19D718 }, { 0x43700000 } }, // Virtua Fighter 3 TB (PAL)
|
||||
{ "HDR-0002", nullptr, { 0x199FB0 }, { 0x43700000 } }, // Virtua Fighter 3 TB (JP)
|
||||
{ "MK-5105450", nullptr, { 0x456378 }, { 0x43700000 } }, // Virtua Tennis (v1.001) (PAL)
|
||||
{ "MK-51054", nullptr, { 0x450A90 }, { 0x43700000 } }, // Virtua Tennis (USA)
|
||||
{ "MK-5118650", nullptr, { 0x4A4A20 }, { 0x43700000 } }, // Virtua Tennis 2 (PAL)
|
||||
// { "T0000", nullptr, { 0x3A514C, 0x3A6170 }, { 0x3F400000, 0x00000356 } }, // Volgarr the Viking. Not working
|
||||
{ "xxxxxxxxxx", nullptr, { 0x20BB68, 0x1ACBD0, 0x1B9ADC }, // Code 1 reduces clipping. Code 2 fixes the clock.
|
||||
{ 0x43700000, 0x7C1ACC60, 0x3F400000 } }, // What's Shenmue (JP)
|
||||
{ "T40504D 50", nullptr, { 0x75281C, 0 }, { 0x3F400000 } }, // Wetrix+ (PAL) not working?
|
||||
{ "MK-51152", nullptr, { 0x014E90, 0 }, { 0x43700000 } }, // World Series Baseball 2K2 (USA)
|
||||
{ "T20401M", nullptr, { 0x323CB0, 0x1ACBD0, 0x1B9ADC, 0 }, // Code 1 reduces clipping. Code 2 fixes the HUD.
|
||||
{ "T40504D 50", nullptr, { 0x75281C }, { 0x3F400000 } }, // Wetrix+ (PAL) not working?
|
||||
{ "MK-51152", nullptr, { 0x014E90 }, { 0x43700000 } }, // World Series Baseball 2K2 (USA)
|
||||
{ "T20401M", nullptr, { 0x323CB0, 0x1ACBD0, 0x1B9ADC }, // Code 1 reduces clipping. Code 2 fixes the HUD.
|
||||
{ 0x43700000, 0x1ACC60, 0x3F400000 } }, // Zero Gunner 2 (JP)
|
||||
{ "MK-5103850", nullptr, { 0x9484E8, 0 }, { 0x43700000 } }, // Zombie Revenge (PAL)
|
||||
{ "MK-51038", nullptr, { 0x948058, 0 }, { 0x43700000 } }, // Zombie Revenge (USA)
|
||||
{ "HDR-0026", nullptr, { 0x948B18, 0 }, { 0x43700000 } }, // Zombie Revenge (JP)
|
||||
{ "T43301M", nullptr, { 0x4B0218, 0 }, { 0x3F400000 } }, // Zusar Vasar (JP)
|
||||
{ "MK-5103850", nullptr, { 0x9484E8 }, { 0x43700000 } }, // Zombie Revenge (PAL)
|
||||
{ "MK-51038", nullptr, { 0x948058 }, { 0x43700000 } }, // Zombie Revenge (USA)
|
||||
{ "HDR-0026", nullptr, { 0x948B18 }, { 0x43700000 } }, // Zombie Revenge (JP)
|
||||
{ "T43301M", nullptr, { 0x4B0218 }, { 0x3F400000 } }, // Zusar Vasar (JP)
|
||||
|
||||
{ nullptr },
|
||||
};
|
||||
const WidescreenCheat CheatManager::naomi_widescreen_cheats[] =
|
||||
{
|
||||
{ "KNIGHTS OF VALOUR THE 7 SPIRITS", nullptr, { 0x475B70, 0x475B40, 0 }, { 0x3F400000, 0x43F00000 } },
|
||||
{ "Dolphin Blue", nullptr, { 0x3F2E2C, 0x3F2190, 0x3F2E6C, 0x3F215C, 0 },
|
||||
{ "KNIGHTS OF VALOUR THE 7 SPIRITS", nullptr, { 0x475B70, 0x475B40 }, { 0x3F400000, 0x43F00000 } },
|
||||
{ "Dolphin Blue", nullptr, { 0x3F2E2C, 0x3F2190, 0x3F2E6C, 0x3F215C },
|
||||
{ 0x43B90000, 0x3FAA9FBE, 0x43B90000, 0x43F00000 } },
|
||||
{ "METAL SLUG 6", nullptr, { 0xE93478, 0xE9347C, 0 }, { 0x3F400000, 0x3F8872B0 } },
|
||||
{ "TOY FIGHTER", nullptr, { 0x133E58, 0 }, { 0x43700000 } },
|
||||
{ "METAL SLUG 6", nullptr, { 0xE93478, 0xE9347C }, { 0x3F400000, 0x3F8872B0 } },
|
||||
{ "TOY FIGHTER", nullptr, { 0x133E58 }, { 0x43700000 } },
|
||||
{ "LUPIN THE THIRD -THE SHOOTING-", nullptr, { 0x045490 }, { 0x3F400000 } },
|
||||
{ "VF4 FINAL TUNED JAPAN", nullptr, { 0x02B834, 0x0AFB90 }, { 0x3FE38E39, 0x3FE38E39 } },
|
||||
{ "DYNAMITE DEKA EX", nullptr, { 0x0E3598, 0x0C8E84 }, { 0x3FE38E38, 0x3FE38E38 } },
|
||||
{ "DEAD OR ALIVE 2", "doa2m", { 0x085B5C, 0x086AE8 }, { 0x3FE38E39, 0x3FE38E39 } },
|
||||
{ "SLASHOUT JAPAN VERSION", nullptr, { 0x3DDBE4 }, { 0x43CFDC86 } },
|
||||
{ "SPIKERS BATTLE JAPAN VERSION", nullptr, { 0x3626C4 }, { 0x43A551B0 } },
|
||||
{ " 18WHEELER", "18wheelr", { 0x5C64A8 }, { 0x43700000 } },
|
||||
{ "BEACH SPIKERS JAPAN", nullptr, { 0x065A7C }, { 0x44558000 } },
|
||||
{ "GUN SPIKE", nullptr, { 0x21A94 }, { 0x3FE38E39 } },
|
||||
{ "INITIAL D Ver.3", "initdv3e", { 0x1D0B34 }, { 0x3FE38E39 } },
|
||||
{ "AIRLINE PILOTS IN JAPAN", "alpilotj", { 0x1D62550 }, { 0x43700000 } },
|
||||
{ "MONKEY BALL JAPAN VERSION", nullptr, { 0x345B4, 0x45244, 0x454CC }, { 0x3FE38E39, 0x3FE38E39, 0x3FE38E39 } },
|
||||
{ "ZOMBIE REVENGE IN JAPAN", "zombrvn", { 0x7A4808 }, { 0x43700000 } },
|
||||
{ "ZOMBIE REVENGE IN JAPAN", "zombrvno", { 0x7A2E50 }, { 0x43700000 } },
|
||||
|
||||
{ nullptr },
|
||||
};
|
||||
CheatManager cheatManager;
|
||||
|
||||
static void vblankCallback(Event event, void *param)
|
||||
{
|
||||
((CheatManager *)param)->apply();
|
||||
}
|
||||
|
||||
void CheatManager::setActive(bool active)
|
||||
{
|
||||
this->active = active;
|
||||
if (active || widescreen_cheat != nullptr)
|
||||
EventManager::listen(Event::VBlank, vblankCallback, this);
|
||||
else
|
||||
EventManager::unlisten(Event::VBlank, vblankCallback, this);
|
||||
}
|
||||
|
||||
void CheatManager::loadCheatFile(const std::string& filename)
|
||||
{
|
||||
#ifndef LIBRETRO
|
||||
@@ -349,7 +379,7 @@ void CheatManager::loadCheatFile(const std::string& filename)
|
||||
if (cheat.type != Cheat::Type::disabled)
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
active = !cheats.empty();
|
||||
setActive(!cheats.empty());
|
||||
INFO_LOG(COMMON, "%d cheats loaded", (int)cheats.size());
|
||||
cfgSaveStr("cheats", gameId, filename);
|
||||
#endif
|
||||
@@ -357,51 +387,66 @@ void CheatManager::loadCheatFile(const std::string& filename)
|
||||
|
||||
void CheatManager::reset(const std::string& gameId)
|
||||
{
|
||||
widescreen_cheat = nullptr;
|
||||
if (this->gameId != gameId)
|
||||
{
|
||||
cheats.clear();
|
||||
active = false;
|
||||
setActive(false);
|
||||
this->gameId = gameId;
|
||||
#ifndef LIBRETRO
|
||||
std::string cheatFile = cfgLoadStr("cheats", gameId, "");
|
||||
if (!cheatFile.empty())
|
||||
loadCheatFile(cheatFile);
|
||||
#endif
|
||||
}
|
||||
widescreen_cheat = nullptr;
|
||||
if (!config::WidescreenGameHacks)
|
||||
return;
|
||||
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
||||
{
|
||||
for (int i = 0; widescreen_cheats[i].game_id != nullptr; i++)
|
||||
if (gameId == "VF4 FINAL TUNED JAPAN")
|
||||
{
|
||||
if (!strcmp(gameId.c_str(), widescreen_cheats[i].game_id)
|
||||
&& (widescreen_cheats[i].area_or_version == nullptr
|
||||
|| !strncmp(ip_meta.area_symbols, widescreen_cheats[i].area_or_version, sizeof(ip_meta.area_symbols))
|
||||
|| !strncmp(ip_meta.product_version, widescreen_cheats[i].area_or_version, sizeof(ip_meta.product_version))))
|
||||
{
|
||||
widescreen_cheat = &widescreen_cheats[i];
|
||||
NOTICE_LOG(COMMON, "Applying widescreen hack to game %s", gameId.c_str());
|
||||
break;
|
||||
}
|
||||
setActive(true);
|
||||
cheats.emplace_back(Cheat::Type::setValue, "Skip DIMM version check", true, 16, 0x0007f486, 0xe001); // mov #1, r0
|
||||
cheats.back().builtIn = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (config::WidescreenGameHacks)
|
||||
{
|
||||
for (int i = 0; naomi_widescreen_cheats[i].game_id != nullptr; i++)
|
||||
if (settings.platform.isConsole())
|
||||
{
|
||||
if (!strcmp(gameId.c_str(), naomi_widescreen_cheats[i].game_id))
|
||||
for (int i = 0; widescreen_cheats[i].game_id != nullptr; i++)
|
||||
{
|
||||
widescreen_cheat = &naomi_widescreen_cheats[i];
|
||||
NOTICE_LOG(COMMON, "Applying widescreen hack to game %s", gameId.c_str());
|
||||
break;
|
||||
if (!strcmp(gameId.c_str(), widescreen_cheats[i].game_id)
|
||||
&& (widescreen_cheats[i].area_or_version == nullptr
|
||||
|| !strncmp(ip_meta.area_symbols, widescreen_cheats[i].area_or_version, sizeof(ip_meta.area_symbols))
|
||||
|| !strncmp(ip_meta.product_version, widescreen_cheats[i].area_or_version, sizeof(ip_meta.product_version))
|
||||
|| !strncmp(ip_meta.software_name, widescreen_cheats[i].area_or_version, sizeof(ip_meta.software_name))))
|
||||
{
|
||||
widescreen_cheat = &widescreen_cheats[i];
|
||||
NOTICE_LOG(COMMON, "Applying widescreen hack to game %s", gameId.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string romName = get_file_basename(settings.content.path);
|
||||
size_t folder_pos = get_last_slash_pos(romName);
|
||||
if (folder_pos != std::string::npos)
|
||||
romName = romName.substr(folder_pos + 1);
|
||||
|
||||
for (int i = 0; naomi_widescreen_cheats[i].game_id != nullptr; i++)
|
||||
{
|
||||
if (!strcmp(gameId.c_str(), naomi_widescreen_cheats[i].game_id)
|
||||
&& (naomi_widescreen_cheats[i].area_or_version == nullptr
|
||||
|| !strcmp(romName.c_str(), naomi_widescreen_cheats[i].area_or_version)))
|
||||
{
|
||||
widescreen_cheat = &naomi_widescreen_cheats[i];
|
||||
NOTICE_LOG(COMMON, "Applying widescreen hack to game %s", gameId.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (widescreen_cheat != nullptr)
|
||||
for (size_t i = 0; i < ARRAY_SIZE(widescreen_cheat->addresses) && widescreen_cheat->addresses[i] != 0; i++)
|
||||
verify(widescreen_cheat->addresses[i] < RAM_SIZE);
|
||||
}
|
||||
if (widescreen_cheat == nullptr)
|
||||
return;
|
||||
for (size_t i = 0; i < ARRAY_SIZE(widescreen_cheat->addresses) && widescreen_cheat->addresses[i] != 0; i++)
|
||||
verify(widescreen_cheat->addresses[i] < RAM_SIZE);
|
||||
setActive(active);
|
||||
}
|
||||
|
||||
u32 CheatManager::readRam(u32 addr, u32 bits)
|
||||
@@ -440,7 +485,12 @@ void CheatManager::apply()
|
||||
if (widescreen_cheat != nullptr)
|
||||
{
|
||||
for (size_t i = 0; i < ARRAY_SIZE(widescreen_cheat->addresses) && widescreen_cheat->addresses[i] != 0; i++)
|
||||
writeRam(widescreen_cheat->addresses[i], widescreen_cheat->values[i], 32);
|
||||
{
|
||||
u32 address = widescreen_cheat->addresses[i];
|
||||
u32 curVal = readRam(address, 32);
|
||||
if (curVal != widescreen_cheat->values[i] && (widescreen_cheat->origValues[i] == 0 || widescreen_cheat->origValues[i] == curVal))
|
||||
writeRam(address, widescreen_cheat->values[i], 32);
|
||||
}
|
||||
}
|
||||
if (active && !settings.network.online)
|
||||
{
|
||||
@@ -495,9 +545,9 @@ void CheatManager::apply()
|
||||
u32 address = cheat.address;
|
||||
for (u32 repeat = 0; repeat < cheat.repeatCount; repeat++)
|
||||
{
|
||||
u32 curVal = readRam(address, cheat.size);
|
||||
if (cheat.size < 8)
|
||||
{
|
||||
u8 curVal = readRam(address, 8);
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
int bitmask = 1 << i;
|
||||
@@ -506,7 +556,8 @@ void CheatManager::apply()
|
||||
valueToSet = (valueToSet & ~bitmask) | (curVal & bitmask);
|
||||
}
|
||||
}
|
||||
writeRam(address, valueToSet, cheat.size);
|
||||
if (curVal != valueToSet)
|
||||
writeRam(address, valueToSet, cheat.size);
|
||||
address += cheat.repeatAddressIncrement * cheat.size / 8;
|
||||
valueToSet += cheat.repeatValueIncrement;
|
||||
}
|
||||
@@ -733,7 +784,7 @@ void CheatManager::addGameSharkCheat(const std::string& name, const std::string&
|
||||
throw FlycastException("Unsupported cheat type");
|
||||
}
|
||||
}
|
||||
active = !cheats.empty();
|
||||
setActive(!cheats.empty());
|
||||
#ifndef LIBRETRO
|
||||
std::string path = cfgLoadStr("cheats", gameId, "");
|
||||
if (path == "")
|
||||
@@ -750,10 +801,11 @@ void CheatManager::saveCheatFile(const std::string& filename)
|
||||
#ifndef LIBRETRO
|
||||
emucfg::ConfigFile cfg;
|
||||
|
||||
cfg.set_int("", "cheats", cheats.size());
|
||||
int i = 0;
|
||||
for (const Cheat& cheat : cheats)
|
||||
{
|
||||
if (cheat.builtIn)
|
||||
continue;
|
||||
std::string prefix = "cheat" + std::to_string(i) + "_";
|
||||
cfg.set_int("", prefix + "address", cheat.address);
|
||||
cfg.set_int("", prefix + "address_bit_position", cheat.valueMask);
|
||||
@@ -793,6 +845,7 @@ void CheatManager::saveCheatFile(const std::string& filename)
|
||||
cfg.set_int("", prefix + "repeat_add_to_address", cheat.repeatAddressIncrement);
|
||||
i++;
|
||||
}
|
||||
cfg.set_int("", "cheats", i);
|
||||
FILE *fp = nowide::fopen(filename.c_str(), "w");
|
||||
if (fp == nullptr)
|
||||
throw FlycastException("Can't save cheat file");
|
||||
|
||||
+22
-10
@@ -27,6 +27,7 @@ struct WidescreenCheat
|
||||
const char *area_or_version;
|
||||
u32 addresses[16];
|
||||
u32 values[16];
|
||||
u32 origValues[16];
|
||||
};
|
||||
|
||||
struct Cheat
|
||||
@@ -42,17 +43,27 @@ struct Cheat
|
||||
runNextIfLt,
|
||||
copy
|
||||
};
|
||||
Type type = Type::disabled;
|
||||
Type type;
|
||||
std::string description;
|
||||
bool enabled = false;
|
||||
u32 size = 0;
|
||||
u32 address = 0;
|
||||
u32 value = 0;
|
||||
u8 valueMask = 0;
|
||||
u32 repeatCount = 1;
|
||||
u32 repeatValueIncrement = 0;
|
||||
u32 repeatAddressIncrement = 0;
|
||||
u32 destAddress = 0;
|
||||
bool enabled;
|
||||
u32 size;
|
||||
u32 address;
|
||||
u32 value;
|
||||
u8 valueMask;
|
||||
u32 repeatCount;
|
||||
u32 repeatValueIncrement;
|
||||
u32 repeatAddressIncrement;
|
||||
u32 destAddress;
|
||||
bool builtIn;
|
||||
|
||||
Cheat(Type type = Type::disabled, const std::string& description = "", bool enabled = false, u32 size = 0, u32 address = 0,
|
||||
u32 value = 0, u8 valueMask = 0, u32 repeatCount = 1, u32 repeatValueIncrement = 0,
|
||||
u32 repeatAddressIncrement = 0, u32 destAddress = 0, bool builtIn = false)
|
||||
: type(type), description(description), enabled(enabled), size(size), address(address), value(value), valueMask(valueMask),
|
||||
repeatCount(repeatCount), repeatValueIncrement(repeatValueIncrement), repeatAddressIncrement(repeatAddressIncrement),
|
||||
destAddress(destAddress), builtIn(builtIn)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class CheatManager
|
||||
@@ -73,6 +84,7 @@ public:
|
||||
private:
|
||||
u32 readRam(u32 addr, u32 bits);
|
||||
void writeRam(u32 addr, u32 value, u32 bits);
|
||||
void setActive(bool active);
|
||||
|
||||
static const WidescreenCheat widescreen_cheats[];
|
||||
static const WidescreenCheat naomi_widescreen_cheats[];
|
||||
|
||||
@@ -247,7 +247,7 @@ public:
|
||||
void restart()
|
||||
{
|
||||
emu.unloadGame();
|
||||
emu.loadGame(settings.content.path);
|
||||
emu.loadGame(settings.content.path.c_str());
|
||||
emu.start();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
Submodule core/deps/SDL updated: b424665e08...8c9beb0c87.
@@ -825,6 +825,7 @@ enum ImGuiWindowFlags_
|
||||
ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,
|
||||
ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse,
|
||||
ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,
|
||||
ImGuiWindowFlags_DragScrolling = 1 << 21, // Allow scrolling by dragging content
|
||||
|
||||
// [Internal]
|
||||
ImGuiWindowFlags_NavFlattened = 1 << 23, // [BETA] Allow gamepad/keyboard navigation to cross over parent border to this child (only use on child that have no scrolling!)
|
||||
|
||||
@@ -645,10 +645,16 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
|
||||
if (delta.x != 0.f || delta.y != 0.f)
|
||||
{
|
||||
ClearActiveID();
|
||||
// Find an ancestor window that allows drag scrolling.
|
||||
ImGuiWindow *scrollableWindow = window;
|
||||
while ((scrollableWindow->Flags & ImGuiWindowFlags_ChildWindow) && scrollableWindow->ScrollMax.x == 0.0f && scrollableWindow->ScrollMax.y == 0.0f)
|
||||
while (scrollableWindow != nullptr
|
||||
&& (scrollableWindow->Flags & ImGuiWindowFlags_ChildWindow)
|
||||
&& !(scrollableWindow->Flags & ImGuiWindowFlags_DragScrolling)
|
||||
&& scrollableWindow->ScrollMax.x == 0.0f
|
||||
&& scrollableWindow->ScrollMax.y == 0.0f)
|
||||
scrollableWindow = scrollableWindow->ParentWindow;
|
||||
scrollableWindow->DragScrolling = true;
|
||||
if (scrollableWindow != nullptr && (scrollableWindow->Flags & ImGuiWindowFlags_DragScrolling))
|
||||
scrollableWindow->DragScrolling = true;
|
||||
held = false;
|
||||
pressed = false;
|
||||
}
|
||||
@@ -1706,8 +1712,6 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi
|
||||
SetItemDefaultFocus();
|
||||
PopID();
|
||||
}
|
||||
// no drag scrolling on combo popup
|
||||
GetCurrentWindow()->DragScrolling = false;
|
||||
|
||||
EndCombo();
|
||||
return value_changed;
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index 9411c76e7..c48243e31 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -1970,9 +1970,7 @@ elseif(APPLE)
|
||||
endif()
|
||||
|
||||
if(SDL_VULKAN OR SDL_METAL OR SDL_RENDER_METAL)
|
||||
- set(ORIG_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
|
||||
- set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -ObjC")
|
||||
- check_c_source_compiles("
|
||||
+ check_objc_source_compiles("
|
||||
#include <AvailabilityMacros.h>
|
||||
#import <Metal/Metal.h>
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
@@ -1980,11 +1978,7 @@ elseif(APPLE)
|
||||
#if (!TARGET_CPU_X86_64 && !TARGET_CPU_ARM64)
|
||||
#error Metal doesn't work on this configuration
|
||||
#endif
|
||||
- int main(void) {
|
||||
- return 0;
|
||||
- }
|
||||
- " HAVE_FRAMEWORK_METAL)
|
||||
- set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS})
|
||||
+ int main(void) {}" HAVE_FRAMEWORK_METAL)
|
||||
if(HAVE_FRAMEWORK_METAL)
|
||||
set(SDL_FRAMEWORK_METAL 1)
|
||||
set(SDL_FRAMEWORK_QUARTZCORE 1)
|
||||
+48
-22
@@ -38,7 +38,6 @@
|
||||
#include "hw/mem/mem_watch.h"
|
||||
#include "network/net_handshake.h"
|
||||
#include "rend/gui.h"
|
||||
#include "lua/lua.h"
|
||||
#include "network/naomi_network.h"
|
||||
#include "serialize.h"
|
||||
#include "hw/pvr/pvr.h"
|
||||
@@ -48,7 +47,7 @@ settings_t settings;
|
||||
|
||||
static void loadSpecialSettings()
|
||||
{
|
||||
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
||||
if (settings.platform.isConsole())
|
||||
{
|
||||
std::string prod_id(ip_meta.product_number, sizeof(ip_meta.product_number));
|
||||
prod_id = trim_trailing_ws(prod_id);
|
||||
@@ -96,7 +95,7 @@ static void loadSpecialSettings()
|
||||
// JSR (EU)
|
||||
|| prod_id == "MK-5105850")
|
||||
{
|
||||
INFO_LOG(BOOT, "Enabling render to texture buffer for game %s", prod_id.c_str());
|
||||
INFO_LOG(BOOT, "Enabling RTT Copy to VRAM for game %s", prod_id.c_str());
|
||||
config::RenderToTextureBuffer.override(true);
|
||||
}
|
||||
if (prod_id == "HDR-0176" || prod_id == "RDC-0057")
|
||||
@@ -194,17 +193,8 @@ static void loadSpecialSettings()
|
||||
}
|
||||
if (prod_id == "T9512N" // The Grinch (US)
|
||||
|| prod_id == "T9503D" // The Grinch (EU)
|
||||
|| prod_id == "T0000M" // Hell Gate FIXME
|
||||
|| prod_id == "MK-51012" // Metropolis Street Racer (US)
|
||||
|| prod_id == "MK-5102250" // Metropolis Street Racer (EU)
|
||||
|| prod_id == "T-31101N" // Psychic Force 2012 (US)
|
||||
|| prod_id == "T1101M" // Psychic Force 2012 (JP)
|
||||
|| prod_id == "T-8106D-50" // Psychic Force 2012 (EU)
|
||||
|| prod_id == "T-9707N" // San Francisco Rush 2049 (US)
|
||||
|| prod_id == "T-9709D-50" // San Francisco Rush 2049 (EU)
|
||||
|| prod_id == "MK-51146" // Sega Smashpack vol.1 (Sega Swirl)
|
||||
|| prod_id == "MK-51152" // World Series Baseball 2K2
|
||||
|| prod_id == "T20401M" // Zero Gunner
|
||||
|| prod_id == "12502D-50" // Caesar's palace 2000 (EU)
|
||||
|| prod_id == "T7001D 50" // Jimmy White's 2 Cueball
|
||||
|| prod_id == "T17717D 50" // The Next Tetris (EU)
|
||||
@@ -216,8 +206,19 @@ static void loadSpecialSettings()
|
||||
NOTICE_LOG(BOOT, "Forcing real BIOS");
|
||||
config::UseReios.override(false);
|
||||
}
|
||||
if (prod_id == "T-9707N" // San Francisco Rush 2049 (US)
|
||||
|| prod_id == "MK-51146") // Sega Smash Pack - Volume 1
|
||||
{
|
||||
NOTICE_LOG(BOOT, "Forcing NTSC broadcasting");
|
||||
config::Broadcast.override(0);
|
||||
}
|
||||
else if (prod_id == "T-9709D-50") // San Francisco Rush 2049 (EU)
|
||||
{
|
||||
NOTICE_LOG(BOOT, "Forcing PAL broadcasting");
|
||||
config::Broadcast.override(1);
|
||||
}
|
||||
}
|
||||
else if (settings.platform.system == DC_PLATFORM_NAOMI || settings.platform.system == DC_PLATFORM_ATOMISWAVE)
|
||||
else if (settings.platform.isArcade())
|
||||
{
|
||||
NOTICE_LOG(BOOT, "Game ID is [%s]", naomi_game_id);
|
||||
if (!strcmp("SAMURAI SPIRITS 6", naomi_game_id))
|
||||
@@ -230,6 +231,11 @@ static void loadSpecialSettings()
|
||||
INFO_LOG(BOOT, "Enabling translucent depth multipass for game %s", naomi_game_id);
|
||||
config::TranslucentPolygonDepthMask.override(true);
|
||||
}
|
||||
if (!strcmp(naomi_game_id, "BEACH SPIKERS JAPAN"))
|
||||
{
|
||||
INFO_LOG(BOOT, "Enabling RTT Copy to VRAM for game %s", naomi_game_id);
|
||||
config::RenderToTextureBuffer.override(true);
|
||||
}
|
||||
// Input configuration
|
||||
settings.input.JammaSetup = JVS::Default;
|
||||
if (!strcmp("DYNAMIC GOLF", naomi_game_id)
|
||||
@@ -255,7 +261,8 @@ static void loadSpecialSettings()
|
||||
INFO_LOG(BOOT, "Enabling specific JVS setup for game %s", naomi_game_id);
|
||||
settings.input.JammaSetup = JVS::SegaMarineFishing;
|
||||
}
|
||||
else if (!strcmp("RINGOUT 4X4 JAPAN", naomi_game_id))
|
||||
else if (!strcmp("RINGOUT 4X4 JAPAN", naomi_game_id)
|
||||
|| !strcmp("VIRTUA ATHLETE", naomi_game_id))
|
||||
{
|
||||
INFO_LOG(BOOT, "Enabling specific JVS setup for game %s", naomi_game_id);
|
||||
settings.input.JammaSetup = JVS::DualIOBoards4P;
|
||||
@@ -337,7 +344,7 @@ void dc_reset(bool hard)
|
||||
sh4_sched_reset(hard);
|
||||
pvr::reset(hard);
|
||||
libAICA_Reset(hard);
|
||||
libARM_Reset(hard);
|
||||
aicaarm::reset();
|
||||
sh4_cpu.Reset(true);
|
||||
mem_Reset(hard);
|
||||
}
|
||||
@@ -362,6 +369,13 @@ static void setPlatform(int platform)
|
||||
settings.platform.bios_size = 2 * 1024 * 1024;
|
||||
settings.platform.flash_size = 32 * 1024; // battery-backed ram
|
||||
break;
|
||||
case DC_PLATFORM_NAOMI2:
|
||||
settings.platform.ram_size = 32 * 1024 * 1024;
|
||||
settings.platform.vram_size = 16 * 1024 * 1024; // 2x16 MB VRAM, only 16 emulated
|
||||
settings.platform.aram_size = 8 * 1024 * 1024;
|
||||
settings.platform.bios_size = 2 * 1024 * 1024;
|
||||
settings.platform.flash_size = 32 * 1024; // battery-backed ram
|
||||
break;
|
||||
case DC_PLATFORM_ATOMISWAVE:
|
||||
settings.platform.ram_size = 16 * 1024 * 1024;
|
||||
settings.platform.vram_size = 8 * 1024 * 1024;
|
||||
@@ -392,7 +406,7 @@ void Emulator::init()
|
||||
|
||||
pvr::init();
|
||||
libAICA_Init();
|
||||
libARM_Init();
|
||||
aicaarm::init();
|
||||
mem_Init();
|
||||
reios_init();
|
||||
|
||||
@@ -446,11 +460,14 @@ void Emulator::loadGame(const char *path, LoadProgress *progress)
|
||||
mem_map_default();
|
||||
|
||||
config::Settings::instance().reset();
|
||||
dc_reset(true);
|
||||
config::Settings::instance().load(false);
|
||||
dc_reset(true);
|
||||
memset(&settings.network.md5, 0, sizeof(settings.network.md5));
|
||||
|
||||
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
||||
if (settings.platform.isNaomi2() && config::RendererType == RenderType::DirectX9)
|
||||
throw FlycastException("DirectX 9 doesn't support Naomi 2 games. Select a different graphics API");
|
||||
|
||||
if (settings.platform.isConsole())
|
||||
{
|
||||
if (settings.content.path.empty())
|
||||
{
|
||||
@@ -491,7 +508,7 @@ void Emulator::loadGame(const char *path, LoadProgress *progress)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (settings.platform.system == DC_PLATFORM_NAOMI || settings.platform.system == DC_PLATFORM_ATOMISWAVE)
|
||||
else if (settings.platform.isArcade())
|
||||
{
|
||||
LoadRomFiles();
|
||||
naomi_cart_LoadRom(path, progress);
|
||||
@@ -499,7 +516,11 @@ void Emulator::loadGame(const char *path, LoadProgress *progress)
|
||||
// Reload the BIOS in case a game-specific region is set
|
||||
naomi_cart_LoadBios(path);
|
||||
}
|
||||
mcfg_DestroyDevices();
|
||||
mcfg_CreateDevices();
|
||||
if (settings.platform.isNaomi())
|
||||
// Must be done after the maple devices are created and EEPROM is accessible
|
||||
naomi_cart_ConfigureEEPROM();
|
||||
cheatManager.reset(settings.content.gameId);
|
||||
if (cheatManager.isWidescreen())
|
||||
{
|
||||
@@ -573,7 +594,6 @@ void Emulator::term()
|
||||
sh4_cpu.Term();
|
||||
custom_texture.Terminate(); // lr: avoid deadlock on exit (win32)
|
||||
reios_term();
|
||||
libARM_Term();
|
||||
libAICA_Term();
|
||||
pvr::term();
|
||||
mem_Term();
|
||||
@@ -617,7 +637,7 @@ void Emulator::requestReset()
|
||||
void loadGameSpecificSettings()
|
||||
{
|
||||
char *reios_id;
|
||||
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
||||
if (settings.platform.isConsole())
|
||||
{
|
||||
static char _disk_id[sizeof(ip_meta.product_number) + 1];
|
||||
|
||||
@@ -644,6 +664,12 @@ void loadGameSpecificSettings()
|
||||
|
||||
// Reload per-game settings
|
||||
config::Settings::instance().load(true);
|
||||
|
||||
if (config::ForceWindowsCE)
|
||||
{
|
||||
config::ExtraDepthScale.override(0.1f);
|
||||
config::FullMMU.override(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Emulator::step()
|
||||
@@ -812,7 +838,7 @@ bool Emulator::render()
|
||||
|
||||
void Emulator::vblank()
|
||||
{
|
||||
lua::vblank();
|
||||
EventManager::event(Event::VBlank);
|
||||
// Time out if a frame hasn't been rendered for 50 ms
|
||||
if (sh4_sched_now64() - startTime <= 10000000)
|
||||
return;
|
||||
|
||||
@@ -45,6 +45,7 @@ enum class Event {
|
||||
Resume,
|
||||
Terminate,
|
||||
LoadState,
|
||||
VBlank,
|
||||
};
|
||||
|
||||
class EventManager
|
||||
|
||||
+23
-13
@@ -18,6 +18,7 @@ InterruptInfo* MCIRE;
|
||||
InterruptInfo* SCIEB;
|
||||
InterruptInfo* SCIPD;
|
||||
InterruptInfo* SCIRE;
|
||||
std::deque<u8> midiSendBuffer;
|
||||
|
||||
//Interrupts
|
||||
//arm side
|
||||
@@ -135,7 +136,7 @@ static void AicaInternalDMA()
|
||||
// to regs
|
||||
u32 addr = CommonData->DRGA << 2;
|
||||
for (u32 i = 0; i < CommonData->DLG; i++, addr += 4)
|
||||
WriteMem_aica_reg(addr, 0, 4);
|
||||
WriteMem_aica_reg(addr, (u32)0);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -148,13 +149,13 @@ static void AicaInternalDMA()
|
||||
{
|
||||
// reg to wave mem
|
||||
for (u32 i = 0; i < len; i++, waddr += 4, raddr += 4)
|
||||
*(u32*)&aica_ram[waddr] = ReadMem_aica_reg(raddr, 4);
|
||||
*(u32*)&aica_ram[waddr] = ReadMem_aica_reg<u32>(raddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// wave mem to regs
|
||||
for (u32 i = 0; i < len; i++, waddr += 4, raddr += 4)
|
||||
WriteMem_aica_reg(raddr, *(u32*)&aica_ram[waddr], 4);
|
||||
WriteMem_aica_reg(raddr, *(u32*)&aica_ram[waddr]);
|
||||
}
|
||||
}
|
||||
CommonData->DEXE = 0;
|
||||
@@ -165,9 +166,10 @@ static void AicaInternalDMA()
|
||||
}
|
||||
|
||||
//Memory i/o
|
||||
template<u32 sz>
|
||||
void WriteAicaReg(u32 reg,u32 data)
|
||||
template<typename T>
|
||||
void WriteAicaReg(u32 reg, T data)
|
||||
{
|
||||
constexpr size_t sz = sizeof(T);
|
||||
switch (reg)
|
||||
{
|
||||
case SCIPD_addr:
|
||||
@@ -204,36 +206,44 @@ void WriteAicaReg(u32 reg,u32 data)
|
||||
break;
|
||||
|
||||
case TIMER_A:
|
||||
WriteMemArr<sz>(aica_reg, reg, data);
|
||||
WriteMemArr(aica_reg, reg, data);
|
||||
timers[0].RegisterWrite();
|
||||
break;
|
||||
|
||||
case TIMER_B:
|
||||
WriteMemArr<sz>(aica_reg, reg, data);
|
||||
WriteMemArr(aica_reg, reg, data);
|
||||
timers[1].RegisterWrite();
|
||||
break;
|
||||
|
||||
case TIMER_C:
|
||||
WriteMemArr<sz>(aica_reg, reg, data);
|
||||
WriteMemArr(aica_reg, reg, data);
|
||||
timers[2].RegisterWrite();
|
||||
break;
|
||||
|
||||
// DEXE, DDIR, DLG
|
||||
case 0x288C:
|
||||
WriteMemArr<sz>(aica_reg, reg, data);
|
||||
WriteMemArr(aica_reg, reg, data);
|
||||
AicaInternalDMA();
|
||||
break;
|
||||
|
||||
default:
|
||||
WriteMemArr<sz>(aica_reg, reg, data);
|
||||
WriteMemArr(aica_reg, reg, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template void WriteAicaReg<>(u32 reg, u8 data);
|
||||
template void WriteAicaReg<>(u32 reg, u16 data);
|
||||
template void WriteAicaReg<>(u32 reg, u32 data);
|
||||
|
||||
|
||||
template void WriteAicaReg<1>(u32 reg,u32 data);
|
||||
template void WriteAicaReg<2>(u32 reg,u32 data);
|
||||
void aica_midiSend(u8 data)
|
||||
{
|
||||
midiSendBuffer.push_back(data);
|
||||
SCIPD->MIDI_IN = 1;
|
||||
update_arm_interrupts();
|
||||
MCIPD->MIDI_IN = 1;
|
||||
UpdateSh4Ints();
|
||||
}
|
||||
|
||||
//misc :p
|
||||
s32 libAICA_Init()
|
||||
|
||||
+4
-2
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include <deque>
|
||||
|
||||
#define SCIEB_addr 0x289C
|
||||
#define SCIPD_addr (0x289C+4)
|
||||
@@ -299,12 +300,13 @@ extern InterruptInfo* MCIRE;
|
||||
extern InterruptInfo* SCIEB;
|
||||
extern InterruptInfo* SCIPD;
|
||||
extern InterruptInfo* SCIRE;
|
||||
extern std::deque<u8> midiSendBuffer;
|
||||
|
||||
extern CommonData_struct* CommonData;
|
||||
extern DSPData_struct* DSPData;
|
||||
|
||||
template<u32 sz>
|
||||
void WriteAicaReg(u32 reg,u32 data);
|
||||
template<typename T>
|
||||
void WriteAicaReg(u32 reg, T data);
|
||||
|
||||
class AicaTimer
|
||||
{
|
||||
|
||||
+37
-15
@@ -45,23 +45,28 @@ u32 GetRTC_now()
|
||||
return (20 * 365 + 5) * 24 * 60 * 60 + rawtime + time_offset;
|
||||
}
|
||||
|
||||
u32 ReadMem_aica_rtc(u32 addr, u32 sz)
|
||||
template<typename T>
|
||||
T ReadMem_aica_rtc(u32 addr)
|
||||
{
|
||||
switch (addr & 0xFF)
|
||||
{
|
||||
case 0:
|
||||
return RealTimeClock >> 16;
|
||||
return (T)(RealTimeClock >> 16);
|
||||
case 4:
|
||||
return RealTimeClock & 0xFFFF;
|
||||
return (T)(RealTimeClock & 0xFFFF);
|
||||
case 8:
|
||||
return 0;
|
||||
}
|
||||
|
||||
WARN_LOG(AICA, "ReadMem_aica_rtc: invalid address %x sz %d", addr, sz);
|
||||
WARN_LOG(AICA, "ReadMem_aica_rtc: invalid address %x sz %d", addr, (int)sizeof(T));
|
||||
return 0;
|
||||
}
|
||||
template u8 ReadMem_aica_rtc<>(u32 addr);
|
||||
template u16 ReadMem_aica_rtc<>(u32 addr);
|
||||
template u32 ReadMem_aica_rtc<>(u32 addr);
|
||||
|
||||
void WriteMem_aica_rtc(u32 addr, u32 data, u32 sz)
|
||||
template<typename T>
|
||||
void WriteMem_aica_rtc(u32 addr, T data)
|
||||
{
|
||||
switch (addr & 0xFF)
|
||||
{
|
||||
@@ -86,31 +91,41 @@ void WriteMem_aica_rtc(u32 addr, u32 data, u32 sz)
|
||||
break;
|
||||
|
||||
default:
|
||||
WARN_LOG(AICA, "WriteMem_aica_rtc: invalid address %x sz %d data %x", addr, sz, data);
|
||||
WARN_LOG(AICA, "WriteMem_aica_rtc: invalid address %x sz %d data %x", addr, (int)sizeof(T), data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
template void WriteMem_aica_rtc<>(u32 addr, u8 data);
|
||||
template void WriteMem_aica_rtc<>(u32 addr, u16 data);
|
||||
template void WriteMem_aica_rtc<>(u32 addr, u32 data);
|
||||
|
||||
u32 ReadMem_aica_reg(u32 addr, u32 sz)
|
||||
template<typename T>
|
||||
T ReadMem_aica_reg(u32 addr)
|
||||
{
|
||||
addr &= 0x7FFF;
|
||||
if (sz == 1)
|
||||
if (sizeof(T) == 1)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x2C00:
|
||||
return ARMRST;
|
||||
return (T)ARMRST;
|
||||
case 0x2C01:
|
||||
return VREG;
|
||||
return (T)VREG;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (addr == 0x2C00)
|
||||
return (VREG << 8) | ARMRST;
|
||||
return (T)((VREG << 8) | ARMRST);
|
||||
|
||||
return libAICA_ReadReg(addr, sz);
|
||||
if (sizeof(T) == 4)
|
||||
return aicaReadReg<u16>(addr);
|
||||
else
|
||||
return aicaReadReg<T>(addr);
|
||||
}
|
||||
template u8 ReadMem_aica_reg<>(u32 addr);
|
||||
template u16 ReadMem_aica_reg<>(u32 addr);
|
||||
template u32 ReadMem_aica_reg<>(u32 addr);
|
||||
|
||||
static void ArmSetRST()
|
||||
{
|
||||
@@ -118,11 +133,12 @@ static void ArmSetRST()
|
||||
aicaarm::enable(ARMRST == 0);
|
||||
}
|
||||
|
||||
void WriteMem_aica_reg(u32 addr,u32 data,u32 sz)
|
||||
template<typename T>
|
||||
void WriteMem_aica_reg(u32 addr, T data)
|
||||
{
|
||||
addr &= 0x7FFF;
|
||||
|
||||
if (sz == 1)
|
||||
if (sizeof(T) == 1)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
@@ -147,8 +163,14 @@ void WriteMem_aica_reg(u32 addr,u32 data,u32 sz)
|
||||
ArmSetRST();
|
||||
return;
|
||||
}
|
||||
libAICA_WriteReg(addr, data, sz);
|
||||
if (sizeof(T) == 4)
|
||||
aicaWriteReg(addr, (u16)data);
|
||||
else
|
||||
aicaWriteReg(addr, data);
|
||||
}
|
||||
template void WriteMem_aica_reg<>(u32 addr, u8 data);
|
||||
template void WriteMem_aica_reg<>(u32 addr, u16 data);
|
||||
template void WriteMem_aica_reg<>(u32 addr, u32 data);
|
||||
|
||||
static int DreamcastSecond(int tag, int c, int j)
|
||||
{
|
||||
|
||||
@@ -5,14 +5,16 @@
|
||||
extern u32 VREG;
|
||||
extern VArray2 aica_ram;
|
||||
u32 GetRTC_now();
|
||||
u32 ReadMem_aica_rtc(u32 addr,u32 sz);
|
||||
void WriteMem_aica_rtc(u32 addr,u32 data,u32 sz);
|
||||
u32 ReadMem_aica_reg(u32 addr,u32 sz);
|
||||
void WriteMem_aica_reg(u32 addr,u32 data,u32 sz);
|
||||
template<typename T> T ReadMem_aica_rtc(u32 addr);
|
||||
template<typename T> void WriteMem_aica_rtc(u32 addr, T data);
|
||||
template<typename T> T ReadMem_aica_reg(u32 addr);
|
||||
template<typename T> void WriteMem_aica_reg(u32 addr, T data);
|
||||
|
||||
void aica_Init();
|
||||
void aica_Reset(bool hard);
|
||||
void aica_Term();
|
||||
void aica_setMidiReceiver(void (*handler)(u8 data));
|
||||
void aica_midiSend(u8 data);
|
||||
|
||||
void aica_sb_Init();
|
||||
void aica_sb_Reset(bool hard);
|
||||
|
||||
+54
-57
@@ -3,22 +3,26 @@
|
||||
#include "aica_if.h"
|
||||
#include "dsp.h"
|
||||
#include "sgc_if.h"
|
||||
#include "hw/hwreg.h"
|
||||
|
||||
alignas(4) u8 aica_reg[0x8000];
|
||||
|
||||
static void (*midiReceiver)(u8 data);
|
||||
|
||||
//Aica read/write (both sh4 & arm)
|
||||
|
||||
//00000000~007FFFFF @DRAM_AREA*
|
||||
//00800000~008027FF @CHANNEL_DATA
|
||||
//00802800~00802FFF @COMMON_DATA
|
||||
//00803000~00807FFF @DSP_DATA
|
||||
template<u32 sz>
|
||||
u32 ReadReg(u32 addr)
|
||||
template<typename T>
|
||||
T aicaReadReg(u32 addr)
|
||||
{
|
||||
addr &= 0x7FFF;
|
||||
|
||||
if (addr >= 0x2800 && addr < 0x2818)
|
||||
{
|
||||
if (sz == 1)
|
||||
ReadCommonReg(addr, true);
|
||||
else
|
||||
ReadCommonReg(addr, false);
|
||||
ReadCommonReg(addr, sizeof(T) == 1);
|
||||
}
|
||||
else if (addr >= 0x4000 && addr < 0x4580)
|
||||
{
|
||||
@@ -47,7 +51,7 @@ u32 ReadReg(u32 addr)
|
||||
else
|
||||
v &= 0xf;
|
||||
}
|
||||
if (sz == 1)
|
||||
if (sizeof(T) == 1)
|
||||
{
|
||||
if (addr & 1)
|
||||
v >>= 8;
|
||||
@@ -56,42 +60,55 @@ u32 ReadReg(u32 addr)
|
||||
}
|
||||
return v;
|
||||
}
|
||||
return ReadMemArr<sz>(aica_reg, addr);
|
||||
return ReadMemArr<T>(aica_reg, addr);
|
||||
}
|
||||
template u8 aicaReadReg<u8>(u32 addr);
|
||||
template u16 aicaReadReg<u16>(u32 addr);
|
||||
template u32 aicaReadReg<u32>(u32 addr);
|
||||
|
||||
static void writeCommonReg8(u32 reg, u8 data)
|
||||
{
|
||||
WriteMemArr(aica_reg, reg, data);
|
||||
if (reg == 0x2804 || reg == 0x2805)
|
||||
{
|
||||
using namespace dsp;
|
||||
state.RBL = (8192 << CommonData->RBL) - 1;
|
||||
state.RBP = (CommonData->RBP * 2048) & ARAM_MASK;
|
||||
state.dirty = true;
|
||||
}
|
||||
else if (reg == 0x280c) { // MOBUF
|
||||
if (midiReceiver != nullptr)
|
||||
midiReceiver(data);
|
||||
}
|
||||
}
|
||||
|
||||
template<u32 sz>
|
||||
void WriteReg(u32 addr,u32 data)
|
||||
template<typename T>
|
||||
void aicaWriteReg(u32 addr, T data)
|
||||
{
|
||||
constexpr size_t sz = sizeof(T);
|
||||
addr &= 0x7FFF;
|
||||
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
//Channel data
|
||||
u32 chan = addr >> 7;
|
||||
u32 reg = addr & 0x7F;
|
||||
WriteMemArr<sz>(aica_reg, addr, data);
|
||||
WriteMemArr(aica_reg, addr, data);
|
||||
WriteChannelReg(chan, reg, sz);
|
||||
return;
|
||||
}
|
||||
|
||||
if (addr < 0x2800)
|
||||
{
|
||||
if (sz == 1)
|
||||
WriteMemArr<1>(aica_reg, addr, data);
|
||||
else
|
||||
WriteMemArr<2>(aica_reg, addr, data);
|
||||
WriteMemArr(aica_reg, addr, data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (addr < 0x2818)
|
||||
{
|
||||
if (sz == 1)
|
||||
{
|
||||
WriteCommonReg8(addr, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteCommonReg8(addr, data & 0xFF);
|
||||
WriteCommonReg8(addr + 1, data >> 8);
|
||||
}
|
||||
writeCommonReg8(addr, data & 0xFF);
|
||||
if (sz == 2)
|
||||
writeCommonReg8(addr + 1, data >> 8);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -128,7 +145,7 @@ void WriteReg(u32 addr,u32 data)
|
||||
v = (v & ~0xff) | (data & 0xff);
|
||||
// else ignored
|
||||
}
|
||||
DEBUG_LOG(AICA, "DSP TEMP/MEMS register write<%d> @ %x = %d", sz, addr, v);
|
||||
DEBUG_LOG(AICA, "DSP TEMP/MEMS register write<%d> @ %x = %d", (int)sz, addr, v);
|
||||
}
|
||||
// DSP MIXS
|
||||
else
|
||||
@@ -154,55 +171,35 @@ void WriteReg(u32 addr,u32 data)
|
||||
v = (v & ~0xf) | (data & 0xf);
|
||||
// else ignored
|
||||
}
|
||||
DEBUG_LOG(AICA, "DSP MIXS register write<%d> @ %x = %d", sz, addr, v);
|
||||
DEBUG_LOG(AICA, "DSP MIXS register write<%d> @ %x = %d", (int)sz, addr, v);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (sz == 1)
|
||||
{
|
||||
WriteMemArr<1>(aica_reg, addr, data);
|
||||
dsp::writeProg(addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteMemArr<2>(aica_reg, addr, data);
|
||||
dsp::writeProg(addr);
|
||||
WriteMemArr(aica_reg, addr, data);
|
||||
dsp::writeProg(addr);
|
||||
if (sz == 2)
|
||||
dsp::writeProg(addr + 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (sz == 1)
|
||||
WriteAicaReg<1>(addr, data);
|
||||
else
|
||||
WriteAicaReg<2>(addr, data);
|
||||
}
|
||||
|
||||
//Aica reads (both sh4&arm)
|
||||
u32 libAICA_ReadReg(u32 addr, u32 size)
|
||||
{
|
||||
if (size == 1)
|
||||
return ReadReg<1>(addr & 0x7FFF);
|
||||
else
|
||||
return ReadReg<2>(addr & 0x7FFF);
|
||||
}
|
||||
|
||||
void libAICA_WriteReg(u32 addr, u32 data, u32 size)
|
||||
{
|
||||
if (size == 1)
|
||||
WriteReg<1>(addr & 0x7FFF, data);
|
||||
else
|
||||
WriteReg<2>(addr & 0x7FFF, data);
|
||||
WriteAicaReg(addr, data);
|
||||
}
|
||||
template void aicaWriteReg<>(u32 addr, u8 data);
|
||||
template void aicaWriteReg<>(u32 addr, u16 data);
|
||||
template void aicaWriteReg<>(u32 addr, u32 data);
|
||||
|
||||
void init_mem()
|
||||
{
|
||||
memset(aica_reg, 0, sizeof(aica_reg));
|
||||
aica_ram.data[ARAM_SIZE - 1] = 1;
|
||||
aica_ram.Zero();
|
||||
midiReceiver = nullptr;
|
||||
}
|
||||
|
||||
void term_mem()
|
||||
{
|
||||
}
|
||||
|
||||
void aica_setMidiReceiver(void (*handler)(u8 data)) {
|
||||
midiReceiver = handler;
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
u32 libAICA_ReadReg(u32 addr,u32 size);
|
||||
void libAICA_WriteReg(u32 addr,u32 data,u32 size);
|
||||
template<typename T> T aicaReadReg(u32 addr);
|
||||
template<typename T> void aicaWriteReg(u32 addr, T data);
|
||||
|
||||
void init_mem();
|
||||
void term_mem();
|
||||
|
||||
+69
-45
@@ -27,6 +27,7 @@
|
||||
#include "hw/gdrom/gdrom_if.h"
|
||||
#include "cfg/option.h"
|
||||
#include "serialize.h"
|
||||
#include "hw/hwreg.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
@@ -779,7 +780,6 @@ struct ChannelEx
|
||||
FEG.ReleaseRate = FEG_SPS[EG_EffRate(base_rate, ccd->FRR)];
|
||||
}
|
||||
|
||||
//WHEE :D!
|
||||
void RegWrite(u32 offset, int size)
|
||||
{
|
||||
switch(offset)
|
||||
@@ -1024,7 +1024,7 @@ void StreamStep(ChannelEx* ch)
|
||||
else
|
||||
{
|
||||
CA = ch->loop.LSA;
|
||||
key_printf("[%d]LPCTL : Looping LSA %x LEA %x", ch->ChannelNumber, ch->loop.LSA, ch->loop.LEA);
|
||||
key_printf("[%d]LPCTL : Looping LSA %x LEA %x AEG %x", ch->ChannelNumber, ch->loop.LSA, ch->loop.LEA, ch->AEG.GetValue());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1040,52 +1040,60 @@ void StreamStep(ChannelEx* ch)
|
||||
|
||||
}
|
||||
|
||||
template<s32 ALFOWS>
|
||||
enum class LFOType
|
||||
{
|
||||
Sawtooth,
|
||||
Square,
|
||||
Triangle,
|
||||
Random
|
||||
};
|
||||
|
||||
template<LFOType Type>
|
||||
void CalcAlfo(ChannelEx* ch)
|
||||
{
|
||||
u32 rv;
|
||||
switch(ALFOWS)
|
||||
switch(Type)
|
||||
{
|
||||
case 0: // Sawtooth
|
||||
case LFOType::Sawtooth:
|
||||
rv=ch->lfo.state;
|
||||
break;
|
||||
|
||||
case 1: // Square
|
||||
case LFOType::Square:
|
||||
rv=ch->lfo.state&0x80?255:0;
|
||||
break;
|
||||
|
||||
case 2: // Triangle
|
||||
case LFOType::Triangle:
|
||||
rv=(ch->lfo.state&0x7f)^(ch->lfo.state&0x80 ? 0x7F:0);
|
||||
rv<<=1;
|
||||
break;
|
||||
|
||||
case 3:// Random ! .. not :p
|
||||
case LFOType::Random: // ... not so much
|
||||
rv=(ch->lfo.state>>3)^(ch->lfo.state<<3)^(ch->lfo.state&0xE3);
|
||||
break;
|
||||
}
|
||||
ch->lfo.alfo=rv>>ch->lfo.alfo_shft;
|
||||
}
|
||||
|
||||
template<s32 PLFOWS>
|
||||
template<LFOType Type>
|
||||
void CalcPlfo(ChannelEx* ch)
|
||||
{
|
||||
u32 rv;
|
||||
switch(PLFOWS)
|
||||
switch(Type)
|
||||
{
|
||||
case 0: // sawtooth
|
||||
case LFOType::Sawtooth:
|
||||
rv = ch->lfo.state;
|
||||
break;
|
||||
|
||||
case 1: // square
|
||||
case LFOType::Square:
|
||||
rv = ch->lfo.state & 0x80 ? 0xff : 0;
|
||||
break;
|
||||
|
||||
case 2: // triangle
|
||||
case LFOType::Triangle:
|
||||
rv = (ch->lfo.state & 0x7f) ^ (ch->lfo.state & 0x80 ? 0x7F : 0);
|
||||
rv <<= 1;
|
||||
break;
|
||||
|
||||
case 3:// random ! .. not :p
|
||||
case LFOType::Random:
|
||||
rv = (ch->lfo.state >> 3) ^ (ch->lfo.state << 3) ^ (ch->lfo.state & 0xE3);
|
||||
break;
|
||||
}
|
||||
@@ -1220,25 +1228,25 @@ static void staticinitialise()
|
||||
STREAM_INITAL_STEP_LUT[3]=&StepDecodeSampleInitial<3>;
|
||||
STREAM_INITAL_STEP_LUT[4]=&StepDecodeSampleInitial<-1>;
|
||||
|
||||
AEG_STEP_LUT[0]=&AegStep<0>;
|
||||
AEG_STEP_LUT[1]=&AegStep<1>;
|
||||
AEG_STEP_LUT[2]=&AegStep<2>;
|
||||
AEG_STEP_LUT[3]=&AegStep<3>;
|
||||
AEG_STEP_LUT[EG_Attack] = &AegStep<EG_Attack>;
|
||||
AEG_STEP_LUT[EG_Decay1] = &AegStep<EG_Decay1>;
|
||||
AEG_STEP_LUT[EG_Decay2] = &AegStep<EG_Decay2>;
|
||||
AEG_STEP_LUT[EG_Release] = &AegStep<EG_Release>;
|
||||
|
||||
FEG_STEP_LUT[0]=&FegStep<0>;
|
||||
FEG_STEP_LUT[1]=&FegStep<1>;
|
||||
FEG_STEP_LUT[2]=&FegStep<2>;
|
||||
FEG_STEP_LUT[3]=&FegStep<3>;
|
||||
FEG_STEP_LUT[EG_Attack] = &FegStep<EG_Attack>;
|
||||
FEG_STEP_LUT[EG_Decay1] = &FegStep<EG_Decay1>;
|
||||
FEG_STEP_LUT[EG_Decay2] = &FegStep<EG_Decay2>;
|
||||
FEG_STEP_LUT[EG_Release] = &FegStep<EG_Release>;
|
||||
|
||||
ALFOWS_CALC[0]=&CalcAlfo<0>;
|
||||
ALFOWS_CALC[1]=&CalcAlfo<1>;
|
||||
ALFOWS_CALC[2]=&CalcAlfo<2>;
|
||||
ALFOWS_CALC[3]=&CalcAlfo<3>;
|
||||
ALFOWS_CALC[(int)LFOType::Sawtooth] = &CalcAlfo<LFOType::Sawtooth>;
|
||||
ALFOWS_CALC[(int)LFOType::Square] = &CalcAlfo<LFOType::Square>;
|
||||
ALFOWS_CALC[(int)LFOType::Triangle] = &CalcAlfo<LFOType::Triangle>;
|
||||
ALFOWS_CALC[(int)LFOType::Random] = &CalcAlfo<LFOType::Random>;
|
||||
|
||||
PLFOWS_CALC[0]=&CalcPlfo<0>;
|
||||
PLFOWS_CALC[1]=&CalcPlfo<1>;
|
||||
PLFOWS_CALC[2]=&CalcPlfo<2>;
|
||||
PLFOWS_CALC[3]=&CalcPlfo<3>;
|
||||
PLFOWS_CALC[(int)LFOType::Sawtooth] = &CalcPlfo<LFOType::Sawtooth>;
|
||||
PLFOWS_CALC[(int)LFOType::Square] = &CalcPlfo<LFOType::Square>;
|
||||
PLFOWS_CALC[(int)LFOType::Triangle] = &CalcPlfo<LFOType::Triangle>;
|
||||
PLFOWS_CALC[(int)LFOType::Random] = &CalcPlfo<LFOType::Random>;
|
||||
}
|
||||
|
||||
ChannelEx ChannelEx::Chans[64];
|
||||
@@ -1330,10 +1338,23 @@ void ReadCommonReg(u32 reg,bool byte)
|
||||
{
|
||||
case 0x2808:
|
||||
case 0x2809:
|
||||
CommonData->MIEMP = 1;
|
||||
CommonData->MOEMP = 1;
|
||||
if (!midiSendBuffer.empty())
|
||||
{
|
||||
if (!byte || reg == 0x2808)
|
||||
{
|
||||
CommonData->MIBUF = midiSendBuffer.front();
|
||||
midiSendBuffer.pop_front();
|
||||
}
|
||||
CommonData->MIEMP = 0;
|
||||
CommonData->MIFUL = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
CommonData->MIEMP = 1;
|
||||
CommonData->MIFUL = 0;
|
||||
}
|
||||
CommonData->MIOVF = 0;
|
||||
CommonData->MIFUL = 0;
|
||||
CommonData->MOEMP = 1;
|
||||
CommonData->MOFUL = 0;
|
||||
break;
|
||||
case 0x2810: // EG, SGC, LP
|
||||
@@ -1365,18 +1386,6 @@ void ReadCommonReg(u32 reg,bool byte)
|
||||
}
|
||||
}
|
||||
|
||||
void WriteCommonReg8(u32 reg,u32 data)
|
||||
{
|
||||
WriteMemArr<1>(aica_reg, reg, data);
|
||||
if (reg == 0x2804 || reg == 0x2805)
|
||||
{
|
||||
using namespace dsp;
|
||||
state.RBL = (8192 << CommonData->RBL) - 1;
|
||||
state.RBP = (CommonData->RBP * 2048) & ARAM_MASK;
|
||||
state.dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void vmuBeep(int on, int period)
|
||||
{
|
||||
if (on == 0 || period == 0 || on < period)
|
||||
@@ -1631,6 +1640,9 @@ void channel_serialize(Serializer& ser)
|
||||
ser << beepCounter;
|
||||
ser << cdda_sector;
|
||||
ser << cdda_index;
|
||||
ser << (u32)midiSendBuffer.size();
|
||||
for (u8 b : midiSendBuffer)
|
||||
ser << b;
|
||||
}
|
||||
|
||||
void channel_deserialize(Deserializer& deser)
|
||||
@@ -1765,4 +1777,16 @@ void channel_deserialize(Deserializer& deser)
|
||||
deser.skip(4 * 64); // mxlr
|
||||
deser.skip(4); // samples_gen
|
||||
}
|
||||
midiSendBuffer.clear();
|
||||
if (deser.version() >= Deserializer::V28)
|
||||
{
|
||||
u32 size;
|
||||
deser >> size;
|
||||
for (u32 i = 0; i < size; i++)
|
||||
{
|
||||
u8 b;
|
||||
deser >> b;
|
||||
midiSendBuffer.push_back(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,8 +52,7 @@ struct DSP_OUT_VOL_REG
|
||||
|
||||
typedef s32 SampleType;
|
||||
|
||||
void ReadCommonReg(u32 reg,bool byte);
|
||||
void WriteCommonReg8(u32 reg,u32 data);
|
||||
void ReadCommonReg(u32 reg, bool byte);
|
||||
void channel_serialize(Serializer& ctx);
|
||||
void channel_deserialize(Deserializer& ctx);
|
||||
void vmuBeep(int on, int period);
|
||||
@@ -15,9 +15,7 @@
|
||||
#define reg arm_Reg
|
||||
#define armNextPC reg[R15_ARM_NEXT].I
|
||||
|
||||
#define CPUUpdateTicksAccesint(a) 1
|
||||
#define CPUUpdateTicksAccessSeq32(a) 1
|
||||
#define CPUUpdateTicksAccesshort(a) 1
|
||||
#define CPUUpdateTicksAccess32(a) 1
|
||||
#define CPUUpdateTicksAccess16(a) 1
|
||||
|
||||
|
||||
+2
-1
@@ -98,7 +98,8 @@ typedef union
|
||||
|
||||
alignas(8) extern reg_pair arm_Reg[RN_ARM_REG_COUNT];
|
||||
|
||||
#define ARM_CYCLES_PER_SAMPLE 256
|
||||
// AICA ARM cpu clock: 22.5792 MHz
|
||||
#define ARM_CYCLES_PER_SAMPLE 512
|
||||
extern int arm7ClockTicks;
|
||||
|
||||
void CPUFiq();
|
||||
|
||||
@@ -145,6 +145,7 @@ static ArmOp decodeArmOp(u32 opcode, u32 arm_pc)
|
||||
//NV condition means VFP on newer cores, let interpreter handle it...
|
||||
op.op_type = ArmOp::FALLBACK;
|
||||
op.arg[0] = ArmOp::Operand(opcode);
|
||||
op.cycles = 0;
|
||||
return op;
|
||||
}
|
||||
if (op.condition != ArmOp::AL)
|
||||
@@ -237,6 +238,7 @@ static ArmOp decodeArmOp(u32 opcode, u32 arm_pc)
|
||||
else
|
||||
{
|
||||
op.arg[argidx].shift_reg = ArmOp::Register((Arm7Reg)bits.shift_reg);
|
||||
op.cycles++;
|
||||
}
|
||||
// Compute pc-relative addresses
|
||||
if (op.arg[argidx].getReg().armreg == RN_PC)
|
||||
@@ -274,6 +276,7 @@ static ArmOp decodeArmOp(u32 opcode, u32 arm_pc)
|
||||
op.op_type = ArmOp::B;
|
||||
op.flags |= ArmOp::OP_SETS_PC;
|
||||
op.rd = ArmOp::Operand();
|
||||
op.cycles += 3;
|
||||
return op;
|
||||
}
|
||||
if (op.condition != ArmOp::AL || (op.flags & ArmOp::OP_SETS_FLAGS))
|
||||
@@ -287,7 +290,10 @@ static ArmOp decodeArmOp(u32 opcode, u32 arm_pc)
|
||||
op.cycles = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
op.rd.getReg().armreg = R15_ARM_NEXT;
|
||||
op.cycles++;
|
||||
}
|
||||
op.flags |= ArmOp::OP_SETS_PC;
|
||||
}
|
||||
if (op.op_type == ArmOp::ADC || op.op_type == ArmOp::SBC || op.op_type == ArmOp::RSC)
|
||||
@@ -317,6 +323,7 @@ static ArmOp decodeArmOp(u32 opcode, u32 arm_pc)
|
||||
return op;
|
||||
}
|
||||
op.rd.setReg(R15_ARM_NEXT);
|
||||
op.cycles++;
|
||||
}
|
||||
op.cycles += 4;
|
||||
}
|
||||
@@ -417,7 +424,9 @@ static ArmOp decodeArmOp(u32 opcode, u32 arm_pc)
|
||||
|
||||
arm_printf("ARM: MEM TFX R %08X -> %08X", opcode, newbits.full);
|
||||
|
||||
return decodeArmOp(newbits.full, arm_pc);
|
||||
op = decodeArmOp(newbits.full, arm_pc);
|
||||
op.cycles += 4;
|
||||
return op;
|
||||
}
|
||||
//STM common case
|
||||
else
|
||||
@@ -448,7 +457,9 @@ static ArmOp decodeArmOp(u32 opcode, u32 arm_pc)
|
||||
|
||||
arm_printf("ARM: MEM TFX W %08X -> %08X", opcode, newbits.full);
|
||||
|
||||
return decodeArmOp(newbits.full, arm_pc);
|
||||
op = decodeArmOp(newbits.full, arm_pc);
|
||||
op.cycles += 4;
|
||||
return op;
|
||||
}
|
||||
}
|
||||
op.op_type = ArmOp::FALLBACK;
|
||||
|
||||
+23
-17
@@ -41,19 +41,22 @@ void e68k_AcceptInterrupt()
|
||||
}
|
||||
|
||||
//Reg reads from arm side ..
|
||||
template <u32 sz,class T>
|
||||
template <typename T>
|
||||
T arm_ReadReg(u32 addr)
|
||||
{
|
||||
addr&=0x7FFF;
|
||||
if (addr==REG_L)
|
||||
return e68k_reg_L;
|
||||
else if(addr==REG_M)
|
||||
return e68k_reg_M; //shouldn't really happen
|
||||
addr &= 0x7FFF;
|
||||
if (addr == REG_L)
|
||||
return (T)e68k_reg_L;
|
||||
else if (addr == REG_M)
|
||||
return (T)e68k_reg_M; //shouldn't really happen
|
||||
else if (sizeof(T) == 4)
|
||||
return aicaReadReg<u16>(addr);
|
||||
else
|
||||
return libAICA_ReadReg(addr,sz);
|
||||
}
|
||||
template <u32 sz,class T>
|
||||
void arm_WriteReg(u32 addr,T data)
|
||||
return aicaReadReg<T>(addr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void arm_WriteReg(u32 addr, T data)
|
||||
{
|
||||
addr &= 0x7FFF;
|
||||
if (addr == REG_L)
|
||||
@@ -68,7 +71,10 @@ void arm_WriteReg(u32 addr,T data)
|
||||
}
|
||||
else
|
||||
{
|
||||
return libAICA_WriteReg(addr, data, sz);
|
||||
if (sizeof(T) == 4)
|
||||
aicaWriteReg(addr, (u16)data);
|
||||
else
|
||||
aicaWriteReg(addr, data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,10 +83,10 @@ void arm_WriteReg(u32 addr,T data)
|
||||
//00802800~00802FFF @COMMON_DATA
|
||||
//00803000~00807FFF @DSP_DATA
|
||||
|
||||
template u8 arm_ReadReg<1,u8>(u32 adr);
|
||||
template u16 arm_ReadReg<2,u16>(u32 adr);
|
||||
template u32 arm_ReadReg<4,u32>(u32 adr);
|
||||
template u8 arm_ReadReg<u8>(u32 adr);
|
||||
template u16 arm_ReadReg<u16>(u32 adr);
|
||||
template u32 arm_ReadReg<u32>(u32 adr);
|
||||
|
||||
template void arm_WriteReg<1>(u32 adr,u8 data);
|
||||
template void arm_WriteReg<2>(u32 adr,u16 data);
|
||||
template void arm_WriteReg<4>(u32 adr,u32 data);
|
||||
template void arm_WriteReg<>(u32 adr,u8 data);
|
||||
template void arm_WriteReg<>(u32 adr,u16 data);
|
||||
template void arm_WriteReg<>(u32 adr,u32 data);
|
||||
+22
-24
@@ -2,54 +2,52 @@
|
||||
#include "types.h"
|
||||
#include "hw/aica/aica_if.h"
|
||||
|
||||
template <u32 sz,class T>
|
||||
T arm_ReadReg(u32 addr);
|
||||
template <u32 sz,class T>
|
||||
void arm_WriteReg(u32 addr,T data);
|
||||
template <typename T> T arm_ReadReg(u32 addr);
|
||||
template <typename T> void arm_WriteReg(u32 addr, T data);
|
||||
|
||||
template<int sz,typename T>
|
||||
template<typename T>
|
||||
static inline T DYNACALL ReadMemArm(u32 addr)
|
||||
{
|
||||
addr&=0x00FFFFFF;
|
||||
if (addr<0x800000)
|
||||
addr &= 0x00FFFFFF;
|
||||
if (addr < 0x800000)
|
||||
{
|
||||
T rv=*(T*)&aica_ram[addr&(ARAM_MASK-(sz-1))];
|
||||
T rv = *(T *)&aica_ram[addr & (ARAM_MASK - (sizeof(T) - 1))];
|
||||
|
||||
if (unlikely(sz==4 && addr&3))
|
||||
if (unlikely(sizeof(T) == 4 && (addr & 3) != 0))
|
||||
{
|
||||
u32 sf=(addr&3)*8;
|
||||
return (rv>>sf) | (rv<<(32-sf));
|
||||
u32 sf = (addr & 3) * 8;
|
||||
return (rv >> sf) | (rv << (32 - sf));
|
||||
}
|
||||
else
|
||||
return rv;
|
||||
}
|
||||
else
|
||||
{
|
||||
return arm_ReadReg<sz,T>(addr);
|
||||
return arm_ReadReg<T>(addr);
|
||||
}
|
||||
}
|
||||
|
||||
template<int sz,typename T>
|
||||
static inline void DYNACALL WriteMemArm(u32 addr,T data)
|
||||
template<typename T>
|
||||
static inline void DYNACALL WriteMemArm(u32 addr, T data)
|
||||
{
|
||||
addr&=0x00FFFFFF;
|
||||
if (addr<0x800000)
|
||||
addr &= 0x00FFFFFF;
|
||||
if (addr < 0x800000)
|
||||
{
|
||||
*(T*)&aica_ram[addr&(ARAM_MASK-(sz-1))]=data;
|
||||
*(T *)&aica_ram[addr & (ARAM_MASK - (sizeof(T) - 1))] = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
arm_WriteReg<sz,T>(addr,data);
|
||||
arm_WriteReg(addr, data);
|
||||
}
|
||||
}
|
||||
|
||||
#define arm_ReadMem8 ReadMemArm<1,u8>
|
||||
#define arm_ReadMem16 ReadMemArm<2,u16>
|
||||
#define arm_ReadMem32 ReadMemArm<4,u32>
|
||||
#define arm_ReadMem8 ReadMemArm<u8>
|
||||
#define arm_ReadMem16 ReadMemArm<u16>
|
||||
#define arm_ReadMem32 ReadMemArm<u32>
|
||||
|
||||
#define arm_WriteMem8 WriteMemArm<1,u8>
|
||||
#define arm_WriteMem16 WriteMemArm<2,u16>
|
||||
#define arm_WriteMem32 WriteMemArm<4,u32>
|
||||
#define arm_WriteMem8 WriteMemArm<u8>
|
||||
#define arm_WriteMem16 WriteMemArm<u16>
|
||||
#define arm_WriteMem32 WriteMemArm<u32>
|
||||
|
||||
extern bool aica_interr;
|
||||
extern u32 aica_reg_L;
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
// nullAICA.cpp : Defines the entry point for the DLL application.
|
||||
//
|
||||
|
||||
#include "arm7.h"
|
||||
|
||||
//called when plugin is used by emu (you should do first time init here)
|
||||
s32 libARM_Init()
|
||||
{
|
||||
aicaarm::init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//called when plugin is unloaded by emu, only if dcInit is called (eg, not called to enumerate plugins)
|
||||
void libARM_Term()
|
||||
{
|
||||
//arm7_Term ?
|
||||
}
|
||||
|
||||
//It's supposed to reset anything
|
||||
void libARM_Reset(bool hard)
|
||||
{
|
||||
aicaarm::reset();
|
||||
aicaarm::enable(false);
|
||||
}
|
||||
@@ -152,7 +152,8 @@ struct flash_syscfg_block {
|
||||
// last set time (seconds since 1/1/1950 00:00)
|
||||
u16 time_lo;
|
||||
u16 time_hi;
|
||||
u8 unknown1;
|
||||
// in 15 mins increment, from -48 (West) to +52 (East), unused
|
||||
int8_t time_zone;
|
||||
u8 lang;
|
||||
u8 mono;
|
||||
u8 autostart;
|
||||
|
||||
@@ -456,6 +456,69 @@ void gd_process_ata_cmd()
|
||||
};
|
||||
}
|
||||
|
||||
static u16 ccitt_crc(void *data, int len)
|
||||
{
|
||||
static constexpr u16 crctable[256] = {
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
|
||||
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
|
||||
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
|
||||
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
|
||||
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
|
||||
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
|
||||
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
|
||||
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
|
||||
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
|
||||
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
|
||||
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
|
||||
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
|
||||
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
|
||||
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
|
||||
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
|
||||
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
|
||||
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
|
||||
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
|
||||
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
|
||||
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
|
||||
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
|
||||
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
|
||||
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
|
||||
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
|
||||
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
|
||||
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
|
||||
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
|
||||
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0,
|
||||
};
|
||||
|
||||
u16 crc = 0;
|
||||
u8 *p = (u8 *)data;
|
||||
|
||||
while (len-- > 0)
|
||||
crc = ((crc & 0xff) << 8) ^ crctable[((crc >> 8) & 0xff) ^ *p++];
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
static int bin2bcd(int v)
|
||||
{
|
||||
return (v % 10) | ((v / 10) << 4);
|
||||
}
|
||||
|
||||
static void encodeSubcode(u8 *buffer, u8 data)
|
||||
{
|
||||
buffer[0] = (data & 0x80) ? 0x40 : 0;
|
||||
buffer[1] = (data & 0x40) ? 0x40 : 0;
|
||||
buffer[2] = (data & 0x20) ? 0x40 : 0;
|
||||
buffer[3] = (data & 0x10) ? 0x40 : 0;
|
||||
buffer[4] = (data & 0x08) ? 0x40 : 0;
|
||||
buffer[5] = (data & 0x04) ? 0x40 : 0;
|
||||
buffer[6] = (data & 0x02) ? 0x40 : 0;
|
||||
buffer[7] = (data & 0x01) ? 0x40 : 0;
|
||||
}
|
||||
|
||||
u32 gd_get_subcode(u32 format, u32 fad, u8 *subc_info)
|
||||
{
|
||||
subc_info[0] = 0;
|
||||
@@ -481,7 +544,33 @@ u32 gd_get_subcode(u32 format, u32 fad, u8 *subc_info)
|
||||
case 0: // Raw subcode
|
||||
subc_info[2] = 0;
|
||||
subc_info[3] = 100;
|
||||
libGDR_ReadSubChannel(subc_info + 4, 100 - 4);
|
||||
// usually not available so let's fake it (Q data only)
|
||||
//libGDR_ReadSubChannel(subc_info + 4, 100 - 4);
|
||||
{
|
||||
u32 curFad = cdda.status == cdda_t::Playing || cdda.status == cdda_t::Paused ? cdda.CurrAddr.FAD : fad;
|
||||
u32 elapsed;
|
||||
u32 tracknum = libGDR_GetTrackNumber(curFad, elapsed);
|
||||
u8 Qch[12];
|
||||
Qch[0] = (SecNumber.DiscFormat == 0 ? 0 : 0x40) | 1;
|
||||
Qch[1] = bin2bcd(tracknum);
|
||||
Qch[2] = bin2bcd(1); // index
|
||||
Qch[3] = bin2bcd(elapsed / 60 / 75); // min
|
||||
Qch[4] = bin2bcd((elapsed / 75) % 60); // sec
|
||||
Qch[5] = bin2bcd(elapsed % 75); // frame
|
||||
Qch[6] = 0;
|
||||
Qch[7] = bin2bcd(curFad / 60 / 75); // toc min
|
||||
Qch[8] = bin2bcd((curFad / 75) % 60); // toc sec
|
||||
Qch[9] = bin2bcd(curFad % 75); // toc frame
|
||||
u16 crc = ccitt_crc(Qch, 10);
|
||||
Qch[10] = crc >> 8;
|
||||
Qch[11] = crc;
|
||||
u8 *p = &subc_info[4];
|
||||
for (u8 q : Qch)
|
||||
{
|
||||
encodeSubcode(p, q);
|
||||
p += 8;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // Q data only
|
||||
|
||||
+151
-48
@@ -10,29 +10,32 @@
|
||||
//asic_RLXXPending: Update the intc flags for pending interrupts
|
||||
static void asic_RL6Pending()
|
||||
{
|
||||
bool t1=(SB_ISTNRM & SB_IML6NRM)!=0;
|
||||
bool t2=(SB_ISTERR & SB_IML6ERR)!=0;
|
||||
bool t3=(SB_ISTEXT & SB_IML6EXT)!=0;
|
||||
bool t1 = (SB_ISTNRM & SB_IML6NRM) != 0;
|
||||
bool t2 = (SB_ISTERR & SB_IML6ERR) != 0;
|
||||
bool t3 = (SB_ISTEXT & SB_IML6EXT) != 0;
|
||||
bool t4 = (SB_ISTNRM1 & SB_IML6NRM) != 0;
|
||||
|
||||
InterruptPend(sh4_IRL_9,t1|t2|t3);
|
||||
InterruptPend(sh4_IRL_9,t1 | t2 | t3 | t4);
|
||||
}
|
||||
|
||||
static void asic_RL4Pending()
|
||||
{
|
||||
bool t1=(SB_ISTNRM & SB_IML4NRM)!=0;
|
||||
bool t2=(SB_ISTERR & SB_IML4ERR)!=0;
|
||||
bool t3=(SB_ISTEXT & SB_IML4EXT)!=0;
|
||||
bool t1 = (SB_ISTNRM & SB_IML4NRM) != 0;
|
||||
bool t2 = (SB_ISTERR & SB_IML4ERR) != 0;
|
||||
bool t3 = (SB_ISTEXT & SB_IML4EXT) != 0;
|
||||
bool t4 = (SB_ISTNRM1 & SB_IML4NRM) != 0;
|
||||
|
||||
InterruptPend(sh4_IRL_11,t1|t2|t3);
|
||||
InterruptPend(sh4_IRL_11, t1 | t2 | t3 | t4);
|
||||
}
|
||||
|
||||
static void asic_RL2Pending()
|
||||
{
|
||||
bool t1=(SB_ISTNRM & SB_IML2NRM)!=0;
|
||||
bool t2=(SB_ISTERR & SB_IML2ERR)!=0;
|
||||
bool t3=(SB_ISTEXT & SB_IML2EXT)!=0;
|
||||
bool t1 = (SB_ISTNRM & SB_IML2NRM) != 0;
|
||||
bool t2 = (SB_ISTERR & SB_IML2ERR) != 0;
|
||||
bool t3 = (SB_ISTEXT & SB_IML2EXT) != 0;
|
||||
bool t4 = (SB_ISTNRM1 & SB_IML2NRM) != 0;
|
||||
|
||||
InterruptPend(sh4_IRL_13,t1|t2|t3);
|
||||
InterruptPend(sh4_IRL_13, t1 | t2 | t3 | t4);
|
||||
}
|
||||
|
||||
void asic_RaiseInterrupt(HollyInterruptID inter)
|
||||
@@ -56,13 +59,36 @@ void asic_RaiseInterrupt(HollyInterruptID inter)
|
||||
asic_RL6Pending();
|
||||
}
|
||||
|
||||
void asic_RaiseInterruptBothCLX(HollyInterruptID inter)
|
||||
{
|
||||
u8 type = inter >> 8;
|
||||
u32 mask = 1 << (u8)inter;
|
||||
switch(type)
|
||||
{
|
||||
case 0:
|
||||
SB_ISTNRM1 |= mask;
|
||||
SB_ISTNRM |= mask;
|
||||
break;
|
||||
case 1:
|
||||
SB_ISTEXT |= mask;
|
||||
break;
|
||||
case 2:
|
||||
SB_ISTERR |= mask;
|
||||
break;
|
||||
}
|
||||
asic_RL2Pending();
|
||||
asic_RL4Pending();
|
||||
asic_RL6Pending();
|
||||
}
|
||||
|
||||
template<bool Naomi2>
|
||||
static u32 Read_SB_ISTNRM(u32 addr)
|
||||
{
|
||||
/* Note that the two highest bits indicate
|
||||
* the OR'ed result of all the bits in
|
||||
* SB_ISTEXT and SB_ISTERR, respectively,
|
||||
* and writes to these two bits are ignored. */
|
||||
u32 tmp = SB_ISTNRM & 0x3FFFFFFF;
|
||||
u32 tmp = (Naomi2 && (addr & 0x02000000) != 0 ? SB_ISTNRM1 : SB_ISTNRM) & 0x3FFFFFFF;
|
||||
|
||||
if (SB_ISTEXT)
|
||||
tmp|=0x40000000;
|
||||
@@ -73,10 +99,14 @@ static u32 Read_SB_ISTNRM(u32 addr)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template<bool Naomi2>
|
||||
static void Write_SB_ISTNRM(u32 addr, u32 data)
|
||||
{
|
||||
/* writing a 1 clears the interrupt */
|
||||
SB_ISTNRM &= ~data;
|
||||
if (Naomi2 && (addr & 0x02000000) != 0)
|
||||
SB_ISTNRM1 &= ~data;
|
||||
else
|
||||
SB_ISTNRM &= ~data;
|
||||
|
||||
asic_RL2Pending();
|
||||
asic_RL4Pending();
|
||||
@@ -118,91 +148,107 @@ static void Write_SB_ISTERR(u32 addr, u32 data)
|
||||
asic_RL6Pending();
|
||||
}
|
||||
|
||||
template<bool Naomi2>
|
||||
static void Write_SB_IML6NRM(u32 addr, u32 data)
|
||||
{
|
||||
SB_IML6NRM=data;
|
||||
if (Naomi2 && (addr & 0x2000000) != 0)
|
||||
// Ignore CLXB settings
|
||||
return;
|
||||
SB_IML6NRM = data;
|
||||
|
||||
asic_RL6Pending();
|
||||
}
|
||||
|
||||
template<bool Naomi2>
|
||||
static void Write_SB_IML4NRM(u32 addr, u32 data)
|
||||
{
|
||||
SB_IML4NRM=data;
|
||||
if (Naomi2 && (addr & 0x2000000) != 0)
|
||||
// Ignore CLXB settings
|
||||
return;
|
||||
SB_IML4NRM = data;
|
||||
|
||||
asic_RL4Pending();
|
||||
}
|
||||
|
||||
template<bool Naomi2>
|
||||
static void Write_SB_IML2NRM(u32 addr, u32 data)
|
||||
{
|
||||
SB_IML2NRM=data;
|
||||
if (Naomi2 && (addr & 0x2000000) != 0)
|
||||
// Ignore CLXB settings
|
||||
return;
|
||||
SB_IML2NRM = data;
|
||||
|
||||
asic_RL2Pending();
|
||||
}
|
||||
|
||||
template<bool Naomi2>
|
||||
static void Write_SB_IML6EXT(u32 addr, u32 data)
|
||||
{
|
||||
SB_IML6EXT=data;
|
||||
if (Naomi2 && (addr & 0x2000000) != 0)
|
||||
// Ignore CLXB settings
|
||||
return;
|
||||
SB_IML6EXT = data;
|
||||
|
||||
asic_RL6Pending();
|
||||
}
|
||||
|
||||
template<bool Naomi2>
|
||||
static void Write_SB_IML4EXT(u32 addr, u32 data)
|
||||
{
|
||||
SB_IML4EXT=data;
|
||||
if (Naomi2 && (addr & 0x2000000) != 0)
|
||||
// Ignore CLXB settings
|
||||
return;
|
||||
SB_IML4EXT = data;
|
||||
|
||||
asic_RL4Pending();
|
||||
}
|
||||
|
||||
template<bool Naomi2>
|
||||
static void Write_SB_IML2EXT(u32 addr, u32 data)
|
||||
{
|
||||
SB_IML2EXT=data;
|
||||
if (Naomi2 && (addr & 0x2000000) != 0)
|
||||
// Ignore CLXB settings
|
||||
return;
|
||||
SB_IML2EXT = data;
|
||||
|
||||
asic_RL2Pending();
|
||||
}
|
||||
|
||||
template<bool Naomi2>
|
||||
static void Write_SB_IML6ERR(u32 addr, u32 data)
|
||||
{
|
||||
SB_IML6ERR=data;
|
||||
if (Naomi2 && (addr & 0x2000000) != 0)
|
||||
// Ignore CLXB settings
|
||||
return;
|
||||
SB_IML6ERR = data;
|
||||
|
||||
asic_RL6Pending();
|
||||
}
|
||||
|
||||
template<bool Naomi2>
|
||||
static void Write_SB_IML4ERR(u32 addr, u32 data)
|
||||
{
|
||||
SB_IML4ERR=data;
|
||||
if (Naomi2 && (addr & 0x2000000) != 0)
|
||||
// Ignore CLXB settings
|
||||
return;
|
||||
SB_IML4ERR = data;
|
||||
|
||||
asic_RL4Pending();
|
||||
}
|
||||
|
||||
template<bool Naomi2>
|
||||
static void Write_SB_IML2ERR(u32 addr, u32 data)
|
||||
{
|
||||
SB_IML2ERR=data;
|
||||
if (Naomi2 && (addr & 0x2000000) != 0)
|
||||
// Ignore CLXB settings
|
||||
return;
|
||||
SB_IML2ERR = data;
|
||||
|
||||
asic_RL2Pending();
|
||||
}
|
||||
|
||||
void asic_reg_Init()
|
||||
{
|
||||
sb_rio_register(SB_ISTNRM_addr,RIO_FUNC,&Read_SB_ISTNRM,&Write_SB_ISTNRM);
|
||||
sb_rio_register(SB_ISTEXT_addr,RIO_WF,0,&Write_SB_ISTEXT);
|
||||
sb_rio_register(SB_ISTERR_addr,RIO_WF,0,&Write_SB_ISTERR);
|
||||
|
||||
//NRM
|
||||
//6
|
||||
sb_rio_register(SB_IML6NRM_addr,RIO_WF,0,&Write_SB_IML6NRM);
|
||||
//4
|
||||
sb_rio_register(SB_IML4NRM_addr,RIO_WF,0,&Write_SB_IML4NRM);
|
||||
//2
|
||||
sb_rio_register(SB_IML2NRM_addr,RIO_WF,0,&Write_SB_IML2NRM);
|
||||
//EXT
|
||||
//6
|
||||
sb_rio_register(SB_IML6EXT_addr,RIO_WF,0,&Write_SB_IML6EXT);
|
||||
//4
|
||||
sb_rio_register(SB_IML4EXT_addr,RIO_WF,0,&Write_SB_IML4EXT);
|
||||
//2
|
||||
sb_rio_register(SB_IML2EXT_addr,RIO_WF,0,&Write_SB_IML2EXT);
|
||||
//ERR
|
||||
//6
|
||||
sb_rio_register(SB_IML6ERR_addr,RIO_WF,0,&Write_SB_IML6ERR);
|
||||
//4
|
||||
sb_rio_register(SB_IML4ERR_addr,RIO_WF,0,&Write_SB_IML4ERR);
|
||||
//2
|
||||
sb_rio_register(SB_IML2ERR_addr,RIO_WF,0,&Write_SB_IML2ERR);
|
||||
}
|
||||
|
||||
void asic_reg_Term()
|
||||
@@ -212,6 +258,63 @@ void asic_reg_Term()
|
||||
//Reset -> Reset - Initialise to default values
|
||||
void asic_reg_Reset(bool hard)
|
||||
{
|
||||
if (hard)
|
||||
{
|
||||
sb_rio_register(SB_ISTEXT_addr, RIO_WF, 0, &Write_SB_ISTEXT);
|
||||
sb_rio_register(SB_ISTERR_addr, RIO_WF, 0, &Write_SB_ISTERR);
|
||||
|
||||
if (settings.platform.isNaomi2())
|
||||
{
|
||||
sb_rio_register(SB_ISTNRM_addr, RIO_FUNC, &Read_SB_ISTNRM<true>, &Write_SB_ISTNRM<true>);
|
||||
|
||||
//NRM
|
||||
//6
|
||||
sb_rio_register(SB_IML6NRM_addr, RIO_WF, 0, &Write_SB_IML6NRM<true>);
|
||||
//4
|
||||
sb_rio_register(SB_IML4NRM_addr, RIO_WF, 0, &Write_SB_IML4NRM<true>);
|
||||
//2
|
||||
sb_rio_register(SB_IML2NRM_addr, RIO_WF, 0, &Write_SB_IML2NRM<true>);
|
||||
//EXT
|
||||
//6
|
||||
sb_rio_register(SB_IML6EXT_addr, RIO_WF, 0, &Write_SB_IML6EXT<true>);
|
||||
//4
|
||||
sb_rio_register(SB_IML4EXT_addr, RIO_WF, 0, &Write_SB_IML4EXT<true>);
|
||||
//2
|
||||
sb_rio_register(SB_IML2EXT_addr, RIO_WF, 0, &Write_SB_IML2EXT<true>);
|
||||
//ERR
|
||||
//6
|
||||
sb_rio_register(SB_IML6ERR_addr, RIO_WF, 0, &Write_SB_IML6ERR<true>);
|
||||
//4
|
||||
sb_rio_register(SB_IML4ERR_addr, RIO_WF, 0, &Write_SB_IML4ERR<true>);
|
||||
//2
|
||||
sb_rio_register(SB_IML2ERR_addr, RIO_WF, 0, &Write_SB_IML2ERR<true>);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb_rio_register(SB_ISTNRM_addr, RIO_FUNC, &Read_SB_ISTNRM<false>, &Write_SB_ISTNRM<false>);
|
||||
|
||||
//NRM
|
||||
//6
|
||||
sb_rio_register(SB_IML6NRM_addr, RIO_WF, 0, &Write_SB_IML6NRM<false>);
|
||||
//4
|
||||
sb_rio_register(SB_IML4NRM_addr, RIO_WF, 0, &Write_SB_IML4NRM<false>);
|
||||
//2
|
||||
sb_rio_register(SB_IML2NRM_addr, RIO_WF, 0, &Write_SB_IML2NRM<false>);
|
||||
//EXT
|
||||
//6
|
||||
sb_rio_register(SB_IML6EXT_addr, RIO_WF, 0, &Write_SB_IML6EXT<false>);
|
||||
//4
|
||||
sb_rio_register(SB_IML4EXT_addr, RIO_WF, 0, &Write_SB_IML4EXT<false>);
|
||||
//2
|
||||
sb_rio_register(SB_IML2EXT_addr, RIO_WF, 0, &Write_SB_IML2EXT<false>);
|
||||
//ERR
|
||||
//6
|
||||
sb_rio_register(SB_IML6ERR_addr, RIO_WF, 0, &Write_SB_IML6ERR<false>);
|
||||
//4
|
||||
sb_rio_register(SB_IML4ERR_addr, RIO_WF, 0, &Write_SB_IML4ERR<false>);
|
||||
//2
|
||||
sb_rio_register(SB_IML2ERR_addr, RIO_WF, 0, &Write_SB_IML2ERR<false>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
void asic_RaiseInterrupt(HollyInterruptID inter);
|
||||
void asic_CancelInterrupt(HollyInterruptID inter);
|
||||
void asic_RaiseInterruptBothCLX(HollyInterruptID inter);
|
||||
|
||||
//Init/Res/Term for regs
|
||||
void asic_reg_Init();
|
||||
|
||||
+165
-8
@@ -26,34 +26,190 @@ std::array<RegisterStruct, 0x540> sb_regs;
|
||||
// much empty space
|
||||
|
||||
u32 SB_ISTNRM;
|
||||
u32 SB_ISTNRM1;
|
||||
|
||||
#define SB_REG_NAME(r) { r##_addr, #r },
|
||||
const std::map<u32, const char *> sb_reg_names = {
|
||||
SB_REG_NAME(SB_C2DSTAT)
|
||||
SB_REG_NAME(SB_C2DLEN)
|
||||
SB_REG_NAME(SB_C2DST)
|
||||
SB_REG_NAME(SB_SDSTAW)
|
||||
SB_REG_NAME(SB_SDBAAW)
|
||||
SB_REG_NAME(SB_SDWLT)
|
||||
SB_REG_NAME(SB_SDLAS)
|
||||
SB_REG_NAME(SB_SDST)
|
||||
SB_REG_NAME(SB_SDDIV)
|
||||
SB_REG_NAME(SB_DBREQM)
|
||||
SB_REG_NAME(SB_BAVLWC)
|
||||
SB_REG_NAME(SB_C2DPRYC)
|
||||
SB_REG_NAME(SB_C2DMAXL)
|
||||
SB_REG_NAME(SB_TFREM)
|
||||
SB_REG_NAME(SB_LMMODE0)
|
||||
SB_REG_NAME(SB_LMMODE1)
|
||||
SB_REG_NAME(SB_FFST)
|
||||
SB_REG_NAME(SB_SFRES)
|
||||
SB_REG_NAME(SB_SBREV)
|
||||
SB_REG_NAME(SB_RBSPLT)
|
||||
SB_REG_NAME(SB_ISTNRM)
|
||||
SB_REG_NAME(SB_ISTEXT)
|
||||
SB_REG_NAME(SB_ISTERR)
|
||||
SB_REG_NAME(SB_IML2NRM)
|
||||
SB_REG_NAME(SB_IML2EXT)
|
||||
SB_REG_NAME(SB_IML2ERR)
|
||||
SB_REG_NAME(SB_IML4NRM)
|
||||
SB_REG_NAME(SB_IML4EXT)
|
||||
SB_REG_NAME(SB_IML4ERR)
|
||||
SB_REG_NAME(SB_IML6NRM)
|
||||
SB_REG_NAME(SB_IML6EXT)
|
||||
SB_REG_NAME(SB_IML6ERR)
|
||||
SB_REG_NAME(SB_PDTNRM)
|
||||
SB_REG_NAME(SB_PDTEXT)
|
||||
SB_REG_NAME(SB_G2DTNRM)
|
||||
SB_REG_NAME(SB_G2DTEXT)
|
||||
SB_REG_NAME(SB_MDSTAR)
|
||||
SB_REG_NAME(SB_MDTSEL)
|
||||
SB_REG_NAME(SB_MDEN)
|
||||
SB_REG_NAME(SB_MDST)
|
||||
SB_REG_NAME(SB_MSYS)
|
||||
SB_REG_NAME(SB_MST)
|
||||
SB_REG_NAME(SB_MSHTCL)
|
||||
SB_REG_NAME(SB_MDAPRO)
|
||||
SB_REG_NAME(SB_MMSEL)
|
||||
SB_REG_NAME(SB_MTXDAD)
|
||||
SB_REG_NAME(SB_MRXDAD)
|
||||
SB_REG_NAME(SB_MRXDBD)
|
||||
SB_REG_NAME(SB_GDSTAR)
|
||||
SB_REG_NAME(SB_GDLEN)
|
||||
SB_REG_NAME(SB_GDDIR)
|
||||
SB_REG_NAME(SB_GDEN)
|
||||
SB_REG_NAME(SB_GDST)
|
||||
SB_REG_NAME(SB_G1RRC)
|
||||
SB_REG_NAME(SB_G1RWC)
|
||||
SB_REG_NAME(SB_G1FRC)
|
||||
SB_REG_NAME(SB_G1FWC)
|
||||
SB_REG_NAME(SB_G1CRC)
|
||||
SB_REG_NAME(SB_G1CWC)
|
||||
SB_REG_NAME(SB_G1GDRC)
|
||||
SB_REG_NAME(SB_G1GDWC)
|
||||
SB_REG_NAME(SB_G1SYSM)
|
||||
SB_REG_NAME(SB_G1CRDYC)
|
||||
SB_REG_NAME(SB_GDAPRO)
|
||||
SB_REG_NAME(SB_GDSTARD)
|
||||
SB_REG_NAME(SB_GDLEND)
|
||||
SB_REG_NAME(SB_ADSTAG)
|
||||
SB_REG_NAME(SB_ADSTAR)
|
||||
SB_REG_NAME(SB_ADLEN)
|
||||
SB_REG_NAME(SB_ADDIR)
|
||||
SB_REG_NAME(SB_ADTSEL)
|
||||
SB_REG_NAME(SB_ADEN)
|
||||
SB_REG_NAME(SB_ADST)
|
||||
SB_REG_NAME(SB_ADSUSP)
|
||||
SB_REG_NAME(SB_E1STAG)
|
||||
SB_REG_NAME(SB_E1STAR)
|
||||
SB_REG_NAME(SB_E1LEN)
|
||||
SB_REG_NAME(SB_E1DIR)
|
||||
SB_REG_NAME(SB_E1TSEL)
|
||||
SB_REG_NAME(SB_E1EN)
|
||||
SB_REG_NAME(SB_E1ST)
|
||||
SB_REG_NAME(SB_E1SUSP)
|
||||
SB_REG_NAME(SB_E2STAG)
|
||||
SB_REG_NAME(SB_E2STAR)
|
||||
SB_REG_NAME(SB_E2LEN)
|
||||
SB_REG_NAME(SB_E2DIR)
|
||||
SB_REG_NAME(SB_E2TSEL)
|
||||
SB_REG_NAME(SB_E2EN)
|
||||
SB_REG_NAME(SB_E2ST)
|
||||
SB_REG_NAME(SB_E2SUSP)
|
||||
SB_REG_NAME(SB_DDSTAG)
|
||||
SB_REG_NAME(SB_DDSTAR)
|
||||
SB_REG_NAME(SB_DDLEN)
|
||||
SB_REG_NAME(SB_DDDIR)
|
||||
SB_REG_NAME(SB_DDTSEL)
|
||||
SB_REG_NAME(SB_DDEN)
|
||||
SB_REG_NAME(SB_DDST)
|
||||
SB_REG_NAME(SB_DDSUSP)
|
||||
SB_REG_NAME(SB_G2ID)
|
||||
SB_REG_NAME(SB_G2DSTO)
|
||||
SB_REG_NAME(SB_G2TRTO)
|
||||
SB_REG_NAME(SB_G2MDMTO)
|
||||
SB_REG_NAME(SB_G2MDMW)
|
||||
SB_REG_NAME(SB_G2APRO)
|
||||
SB_REG_NAME(SB_ADSTAGD)
|
||||
SB_REG_NAME(SB_ADSTARD)
|
||||
SB_REG_NAME(SB_ADLEND)
|
||||
SB_REG_NAME(SB_E1STAGD)
|
||||
SB_REG_NAME(SB_E1STARD)
|
||||
SB_REG_NAME(SB_E1LEND)
|
||||
SB_REG_NAME(SB_E2STAGD)
|
||||
SB_REG_NAME(SB_E2STARD)
|
||||
SB_REG_NAME(SB_E2LEND)
|
||||
SB_REG_NAME(SB_DDSTAGD)
|
||||
SB_REG_NAME(SB_DDSTARD)
|
||||
SB_REG_NAME(SB_DDLEND)
|
||||
SB_REG_NAME(SB_PDSTAP)
|
||||
SB_REG_NAME(SB_PDSTAR)
|
||||
SB_REG_NAME(SB_PDLEN)
|
||||
SB_REG_NAME(SB_PDDIR)
|
||||
SB_REG_NAME(SB_PDTSEL)
|
||||
SB_REG_NAME(SB_PDEN)
|
||||
SB_REG_NAME(SB_PDST)
|
||||
SB_REG_NAME(SB_PDAPRO)
|
||||
SB_REG_NAME(SB_PDSTAPD)
|
||||
SB_REG_NAME(SB_PDSTARD)
|
||||
SB_REG_NAME(SB_PDLEND)
|
||||
};
|
||||
#undef SB_REG_NAME
|
||||
|
||||
static const char *regName(u32 addr)
|
||||
{
|
||||
static char regName[10];
|
||||
auto it = sb_reg_names.find(addr & 0x7fffff); // (addr - 0x5f6800) & 0x1fff);
|
||||
if (it == sb_reg_names.end())
|
||||
{
|
||||
sprintf(regName, "?%06x", addr& 0x7fffff);
|
||||
return regName;
|
||||
}
|
||||
else
|
||||
return it->second;
|
||||
}
|
||||
|
||||
u32 sb_ReadMem(u32 addr,u32 sz)
|
||||
{
|
||||
u32 offset = (addr - SB_BASE) >> 2;
|
||||
u32 offset = ((addr - SB_BASE) >> 2) & 0x1fff;
|
||||
u32 rv;
|
||||
|
||||
if (!(sb_regs[offset].flags & (REG_RF|REG_WO)))
|
||||
{
|
||||
if (sz==4)
|
||||
return sb_regs[offset].data32;
|
||||
rv = sb_regs[offset].data32;
|
||||
else if (sz==2)
|
||||
return sb_regs[offset].data16;
|
||||
rv = sb_regs[offset].data16;
|
||||
else
|
||||
return sb_regs[offset].data8;
|
||||
rv = sb_regs[offset].data8;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((sb_regs[offset].flags & REG_WO) || sb_regs[offset].readFunctionAddr == NULL)
|
||||
{
|
||||
INFO_LOG(HOLLY, "sb_ReadMem write-only reg %08x %d", addr, sz);
|
||||
return 0;
|
||||
rv = 0;
|
||||
}
|
||||
return sb_regs[offset].readFunctionAddr(addr);
|
||||
else
|
||||
rv = sb_regs[offset].readFunctionAddr(addr);
|
||||
}
|
||||
if ((addr & 0xffffff) != 0x5f6c18) // SB_MDST
|
||||
DEBUG_LOG(HOLLY, "read(%d) %s.%c == %x", sz, regName(addr),
|
||||
((addr >> 26) & 7) == 2 ? 'b' : (addr & 0x2000000) ? '1' : '0',
|
||||
rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void sb_WriteMem(u32 addr,u32 data,u32 sz)
|
||||
{
|
||||
u32 offset = (addr - SB_BASE) >> 2;
|
||||
DEBUG_LOG(HOLLY, "write(%d) %s.%c = %x", sz, regName(addr),
|
||||
((addr >> 26) & 7) == 2 ? 'b' : (addr & 0x2000000) ? '1' : '0',
|
||||
data);
|
||||
u32 offset = ((addr - SB_BASE) >> 2) & 0x1fff;
|
||||
|
||||
if (!(sb_regs[offset].flags & REG_WF))
|
||||
{
|
||||
@@ -593,6 +749,7 @@ void sb_Reset(bool hard)
|
||||
reg.reset();
|
||||
}
|
||||
SB_ISTNRM = 0;
|
||||
SB_ISTNRM1 = 0;
|
||||
SB_FFST_rc = 0;
|
||||
SB_FFST = 0;
|
||||
|
||||
@@ -600,7 +757,7 @@ void sb_Reset(bool hard)
|
||||
ModemReset();
|
||||
|
||||
asic_reg_Reset(hard);
|
||||
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
||||
if (settings.platform.isConsole())
|
||||
gdrom_reg_Reset(hard);
|
||||
else
|
||||
naomi_reg_Reset(hard);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include "hw/hwreg.h"
|
||||
#include <array>
|
||||
|
||||
u32 sb_ReadMem(u32 addr,u32 sz);
|
||||
@@ -365,6 +366,9 @@ extern u32 SB_FFST;
|
||||
|
||||
//0x005F6900 SB_ISTNRM RW Normal interrupt status
|
||||
extern u32 SB_ISTNRM;
|
||||
//0x025F6900 SB_ISTNRM1 RW Normal interrupt status CLXB (Naomi 2)
|
||||
extern u32 SB_ISTNRM1;
|
||||
|
||||
//0x005F6904 SB_ISTEXT R External interrupt status
|
||||
#define SB_ISTEXT SB_REG_32(ISTEXT)
|
||||
//0x005F6908 SB_ISTERR RW Error interrupt status
|
||||
|
||||
+56
-26
@@ -31,6 +31,8 @@ static std::string getRomPrefix()
|
||||
return "dc_";
|
||||
case DC_PLATFORM_NAOMI:
|
||||
return "naomi_";
|
||||
case DC_PLATFORM_NAOMI2:
|
||||
return "naomi2_";
|
||||
case DC_PLATFORM_ATOMISWAVE:
|
||||
return "aw_";
|
||||
default:
|
||||
@@ -107,7 +109,7 @@ static void add_isp_to_nvmem(DCFlashChip *flash)
|
||||
|
||||
static void fixUpDCFlash()
|
||||
{
|
||||
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
||||
if (settings.platform.isConsole())
|
||||
{
|
||||
static_cast<DCFlashChip*>(sys_nvmem)->Validate();
|
||||
|
||||
@@ -138,6 +140,7 @@ static void fixUpDCFlash()
|
||||
memset(&syscfg, 0xff, sizeof(syscfg));
|
||||
syscfg.time_lo = 0;
|
||||
syscfg.time_hi = 0;
|
||||
syscfg.time_zone = 0;
|
||||
syscfg.lang = 0;
|
||||
syscfg.mono = 0;
|
||||
syscfg.autostart = 1;
|
||||
@@ -158,19 +161,34 @@ static void fixUpDCFlash()
|
||||
if (!memcmp(console_id, "\377\377\377\377\377\377", 6))
|
||||
{
|
||||
srand(now);
|
||||
u8 sum = 0;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
console_id[i] = rand();
|
||||
console_id[i + 0xA0] = console_id[i]; // copy at 1A0F8
|
||||
sum += console_id[i];
|
||||
}
|
||||
console_id[-1] = console_id[0xA0 - 1] = sum;
|
||||
console_id[-2] = console_id[0xA0 - 2] = ~sum;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fix checksum
|
||||
u8 sum = 0;
|
||||
for (int i = 0; i < 6; i++)
|
||||
sum += console_id[i];
|
||||
console_id[-1] = console_id[0xA0 - 1] = sum;
|
||||
console_id[-2] = console_id[0xA0 - 2] = ~sum;
|
||||
}
|
||||
// must be != 0xff
|
||||
console_id[7] = console_id[0xA0 + 7] = 0xfe;
|
||||
}
|
||||
}
|
||||
|
||||
static bool nvmem_load()
|
||||
{
|
||||
bool rc;
|
||||
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
||||
if (settings.platform.isConsole())
|
||||
rc = sys_nvmem->Load(getRomPrefix(), "%nvmem.bin", "nvram");
|
||||
else
|
||||
rc = sys_nvmem->Load(hostfs::getArcadeFlashPath() + ".nvmem");
|
||||
@@ -180,7 +198,7 @@ static bool nvmem_load()
|
||||
if (config::GGPOEnable)
|
||||
sys_nvmem->digest(settings.network.md5.nvmem);
|
||||
|
||||
if (settings.platform.system == DC_PLATFORM_ATOMISWAVE)
|
||||
if (settings.platform.isAtomiswave())
|
||||
{
|
||||
sys_rom->Load(hostfs::getArcadeFlashPath() + ".nvmem2");
|
||||
if (config::GGPOEnable)
|
||||
@@ -193,7 +211,7 @@ static bool nvmem_load()
|
||||
bool LoadRomFiles()
|
||||
{
|
||||
nvmem_load();
|
||||
if (settings.platform.system != DC_PLATFORM_ATOMISWAVE)
|
||||
if (!settings.platform.isAtomiswave())
|
||||
{
|
||||
if (sys_rom->Load(getRomPrefix(), "%boot.bin;%boot.bin.bin;%bios.bin;%bios.bin.bin", "bootrom"))
|
||||
{
|
||||
@@ -201,7 +219,7 @@ bool LoadRomFiles()
|
||||
sys_rom->digest(settings.network.md5.bios);
|
||||
bios_loaded = true;
|
||||
}
|
||||
else if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
||||
else if (settings.platform.isConsole())
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -210,11 +228,11 @@ bool LoadRomFiles()
|
||||
|
||||
void SaveRomFiles()
|
||||
{
|
||||
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
||||
if (settings.platform.isConsole())
|
||||
sys_nvmem->Save(getRomPrefix(), "nvmem.bin", "nvmem");
|
||||
else
|
||||
sys_nvmem->Save(hostfs::getArcadeFlashPath() + ".nvmem");
|
||||
if (settings.platform.system == DC_PLATFORM_ATOMISWAVE)
|
||||
if (settings.platform.isAtomiswave())
|
||||
((WritableChip *)sys_rom)->Save(hostfs::getArcadeFlashPath() + ".nvmem2");
|
||||
}
|
||||
|
||||
@@ -258,12 +276,16 @@ static void WriteAWBios(u32 addr, u32 data, u32 sz)
|
||||
//0x00800000- 0x00FFFFFF :AICA- Wave Memory
|
||||
//0x01000000- 0x01FFFFFF :Ext. Device
|
||||
//0x02000000- 0x03FFFFFF* :Image Area* 2MB
|
||||
// Naomi 2:
|
||||
//0x025F6800- 0x025F69FF :PVR#2 system registers
|
||||
//0x025F7C00- 0x025F7CFF :PVR#2 PVR i/f Control Reg.
|
||||
//0x025F8000- 0x025F9FFF :PVR#2 TA / PVR Core Reg.
|
||||
|
||||
template<typename T, u32 System, bool Mirror>
|
||||
T DYNACALL ReadMem_area0(u32 addr)
|
||||
T DYNACALL ReadMem_area0(u32 paddr)
|
||||
{
|
||||
constexpr u32 sz = (u32)sizeof(T);
|
||||
addr &= 0x01FFFFFF;
|
||||
u32 addr = paddr & 0x01FFFFFF;
|
||||
const u32 base = addr >> 21;
|
||||
|
||||
switch (expected(base, 2))
|
||||
@@ -303,14 +325,14 @@ T DYNACALL ReadMem_area0(u32 addr)
|
||||
}
|
||||
// All SB registers
|
||||
if (addr >= 0x005F6800 && addr <= 0x005F7CFF)
|
||||
return (T)sb_ReadMem(addr, sz);
|
||||
return (T)sb_ReadMem(paddr, sz);
|
||||
// TA / PVR core registers
|
||||
if (addr >= 0x005F8000 && addr <= 0x005F9FFF)
|
||||
{
|
||||
if (sz != 4)
|
||||
// House of the Dead 2
|
||||
return 0;
|
||||
return (T)pvr_ReadReg(addr);
|
||||
return (T)pvr_ReadReg(paddr);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
@@ -331,10 +353,10 @@ T DYNACALL ReadMem_area0(u32 addr)
|
||||
}
|
||||
// AICA sound registers
|
||||
if (addr >= 0x00700000 && addr <= 0x00707FFF)
|
||||
return (T)ReadMem_aica_reg(addr, sz);
|
||||
return ReadMem_aica_reg<T>(addr);
|
||||
// AICA RTC registers
|
||||
if (addr >= 0x00710000 && addr <= 0x0071000B)
|
||||
return (T)ReadMem_aica_rtc(addr, sz);
|
||||
return ReadMem_aica_rtc<T>(addr);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
@@ -342,12 +364,15 @@ T DYNACALL ReadMem_area0(u32 addr)
|
||||
case 6:
|
||||
case 7:
|
||||
// AICA ram
|
||||
return (T)ReadMemArr<sz>(aica_ram.data, addr & ARAM_MASK);
|
||||
return ReadMemArr<T>(aica_ram.data, addr & ARAM_MASK);
|
||||
|
||||
default:
|
||||
// G2 Ext area
|
||||
if (System == DC_PLATFORM_NAOMI)
|
||||
return (T)libExtDevice_ReadMem_A0_010(addr, sz);
|
||||
if (System == DC_PLATFORM_NAOMI || System == DC_PLATFORM_NAOMI2)
|
||||
{
|
||||
INFO_LOG(MEMORY, "Read<%d> from G2 Ext area not implemented @ %08x", sz, addr);
|
||||
return (T)0;
|
||||
}
|
||||
else if (config::EmulateBBA)
|
||||
return (T)bba_ReadMem(addr, sz);
|
||||
else
|
||||
@@ -358,10 +383,10 @@ T DYNACALL ReadMem_area0(u32 addr)
|
||||
}
|
||||
|
||||
template<typename T, u32 System, bool Mirror>
|
||||
void DYNACALL WriteMem_area0(u32 addr, T data)
|
||||
void DYNACALL WriteMem_area0(u32 paddr, T data)
|
||||
{
|
||||
constexpr u32 sz = (u32)sizeof(T);
|
||||
addr &= 0x01FFFFFF;//to get rid of non needed bits
|
||||
u32 addr = paddr & 0x01FFFFFF;//to get rid of non needed bits
|
||||
|
||||
const u32 base = addr >> 21;
|
||||
|
||||
@@ -410,14 +435,14 @@ void DYNACALL WriteMem_area0(u32 addr, T data)
|
||||
// All SB registers
|
||||
if (addr >= 0x005F6800 && addr <= 0x005F7CFF)
|
||||
{
|
||||
sb_WriteMem(addr, data, sz);
|
||||
sb_WriteMem(paddr, data, sz);
|
||||
return;
|
||||
}
|
||||
// TA / PVR core registers
|
||||
if (addr >= 0x005F8000 && addr <= 0x005F9FFF)
|
||||
{
|
||||
verify(sz == 4);
|
||||
pvr_WriteReg(addr, data);
|
||||
pvr_WriteReg(paddr, data);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -439,13 +464,13 @@ void DYNACALL WriteMem_area0(u32 addr, T data)
|
||||
// AICA sound registers
|
||||
if (addr >= 0x00700000 && addr <= 0x00707FFF)
|
||||
{
|
||||
WriteMem_aica_reg(addr, data, sz);
|
||||
WriteMem_aica_reg(addr, data);
|
||||
return;
|
||||
}
|
||||
// AICA RTC registers
|
||||
if (addr >= 0x00710000 && addr <= 0x0071000B)
|
||||
{
|
||||
WriteMem_aica_rtc(addr, data, sz);
|
||||
WriteMem_aica_rtc(addr, data);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -454,18 +479,18 @@ void DYNACALL WriteMem_area0(u32 addr, T data)
|
||||
case 6:
|
||||
case 7:
|
||||
// AICA ram
|
||||
WriteMemArr<sz>(aica_ram.data, addr & ARAM_MASK, data);
|
||||
WriteMemArr(aica_ram.data, addr & ARAM_MASK, data);
|
||||
return;
|
||||
|
||||
default:
|
||||
// G2 Ext area
|
||||
if (System == DC_PLATFORM_NAOMI)
|
||||
libExtDevice_WriteMem_A0_010(addr, data, sz);
|
||||
if (System == DC_PLATFORM_NAOMI || System == DC_PLATFORM_NAOMI2)
|
||||
INFO_LOG(MEMORY, "Write<%d> to G2 Ext area not implemented @ %08x: %x", sz, addr, (u32)data);
|
||||
else if (config::EmulateBBA)
|
||||
bba_WriteMem(addr, data, sz);
|
||||
return;
|
||||
}
|
||||
INFO_LOG(COMMON, "Write to area0_32 not implemented [Unassigned], addr=%x,data=%x,size=%d", addr, data, sz);
|
||||
INFO_LOG(MEMORY, "Write to area0_32 not implemented [Unassigned], addr=%x,data=%x,size=%d", addr, data, sz);
|
||||
}
|
||||
|
||||
//Init/Res/Term
|
||||
@@ -497,6 +522,7 @@ void sh4_area0_Reset(bool hard)
|
||||
reios_set_flash(sys_nvmem);
|
||||
break;
|
||||
case DC_PLATFORM_NAOMI:
|
||||
case DC_PLATFORM_NAOMI2:
|
||||
sys_rom = new RomChip(settings.platform.bios_size);
|
||||
sys_nvmem = new SRamChip(settings.platform.flash_size);
|
||||
break;
|
||||
@@ -551,6 +577,10 @@ void map_area0_init()
|
||||
area0_handler = registerHandler(DC_PLATFORM_NAOMI, false);
|
||||
area0_mirror_handler = registerHandler(DC_PLATFORM_NAOMI, true);
|
||||
break;
|
||||
case DC_PLATFORM_NAOMI2:
|
||||
area0_handler = registerHandler(DC_PLATFORM_NAOMI2, false);
|
||||
area0_mirror_handler = registerHandler(DC_PLATFORM_NAOMI2, true);
|
||||
break;
|
||||
case DC_PLATFORM_ATOMISWAVE:
|
||||
area0_handler = registerHandler(DC_PLATFORM_ATOMISWAVE, false);
|
||||
area0_mirror_handler = registerHandler(DC_PLATFORM_ATOMISWAVE, true);
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
typedef u32 RegReadAddrFP(u32 addr);
|
||||
typedef void RegWriteAddrFP(u32 addr, u32 data);
|
||||
|
||||
/*
|
||||
Read Write Const
|
||||
D D N -> 0 -> RIO_DATA
|
||||
D F N -> WF -> RIO_WF
|
||||
F F N -> RF|WF -> RIO_FUNC
|
||||
D X N -> RO|WF -> RIO_RO
|
||||
F X N -> RF|WF|RO -> RIO_RO_FUNC
|
||||
D X Y -> CONST|RO|WF-> RIO_CONST
|
||||
X F N -> RF|WF|WO -> RIO_WO_FUNC
|
||||
*/
|
||||
enum RegStructFlags
|
||||
{
|
||||
REG_RF = 8,
|
||||
REG_WF = 16,
|
||||
REG_RO = 32,
|
||||
REG_WO = 64,
|
||||
REG_NO_ACCESS = REG_RO | REG_WO,
|
||||
};
|
||||
|
||||
enum RegIO
|
||||
{
|
||||
RIO_DATA = 0,
|
||||
RIO_WF = REG_WF,
|
||||
RIO_FUNC = REG_WF | REG_RF,
|
||||
RIO_RO = REG_RO | REG_WF,
|
||||
RIO_RO_FUNC = REG_RO | REG_RF | REG_WF,
|
||||
RIO_CONST = REG_RO | REG_WF,
|
||||
RIO_WO_FUNC = REG_WF | REG_RF | REG_WO,
|
||||
RIO_NO_ACCESS = REG_WF | REG_RF | REG_NO_ACCESS
|
||||
};
|
||||
|
||||
struct RegisterStruct
|
||||
{
|
||||
union
|
||||
{
|
||||
u32 data32; //stores data of reg variable [if used] 32b
|
||||
u16 data16; //stores data of reg variable [if used] 16b
|
||||
u8 data8; //stores data of reg variable [if used] 8b
|
||||
|
||||
RegReadAddrFP* readFunctionAddr; //stored pointer to reg read function
|
||||
};
|
||||
|
||||
RegWriteAddrFP* writeFunctionAddr; //stored pointer to reg write function
|
||||
|
||||
u32 flags; //Access flags !
|
||||
|
||||
void reset()
|
||||
{
|
||||
if (!(flags & (REG_RO | REG_RF)))
|
||||
data32 = 0;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
T ReadMemArr(const u8 *array, u32 addr)
|
||||
{
|
||||
return *(const T *)&array[addr];
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void WriteMemArr(u8 *array, u32 addr, T data)
|
||||
{
|
||||
*(T *)&array[addr] = data;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ void MapleConfigMap::GetInput(PlainJoystickState* pjs)
|
||||
{
|
||||
const MapleInputState& inputState = mapleInputState[playerNum()];
|
||||
|
||||
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
||||
if (settings.platform.isConsole())
|
||||
{
|
||||
pjs->kcode = inputState.kcode;
|
||||
pjs->joy[PJAI_X1] = GetBtFromSgn(inputState.fullAxes[PJAI_X1]);
|
||||
@@ -79,7 +79,7 @@ void MapleConfigMap::GetInput(PlainJoystickState* pjs)
|
||||
pjs->trigger[PJTI_R] = inputState.halfAxes[PJTI_R];
|
||||
pjs->trigger[PJTI_L] = inputState.halfAxes[PJTI_L];
|
||||
}
|
||||
else if (settings.platform.system == DC_PLATFORM_ATOMISWAVE)
|
||||
else if (settings.platform.isAtomiswave())
|
||||
{
|
||||
#ifdef LIBRETRO
|
||||
pjs->kcode = inputState.kcode;
|
||||
@@ -209,7 +209,6 @@ static void mcfg_Create(MapleDeviceType type, u32 bus, u32 port, s32 player_num
|
||||
|
||||
static void createNaomiDevices()
|
||||
{
|
||||
mcfg_DestroyDevices();
|
||||
mcfg_Create(MDT_NaomiJamma, 0, 5);
|
||||
if (settings.input.JammaSetup == JVS::Keyboard)
|
||||
{
|
||||
@@ -229,7 +228,6 @@ static void createNaomiDevices()
|
||||
|
||||
static void createAtomiswaveDevices()
|
||||
{
|
||||
mcfg_DestroyDevices();
|
||||
// Looks like two controllers needs to be on bus 0 and 1 for digital inputs
|
||||
// Then other devices on port 2 and 3 for analog axes, light guns, ...
|
||||
mcfg_Create(MDT_SegaController, 0, 5);
|
||||
@@ -347,6 +345,7 @@ void mcfg_CreateDevices()
|
||||
createDreamcastDevices();
|
||||
break;
|
||||
case DC_PLATFORM_NAOMI:
|
||||
case DC_PLATFORM_NAOMI2:
|
||||
createNaomiDevices();
|
||||
break;
|
||||
case DC_PLATFORM_ATOMISWAVE:
|
||||
|
||||
@@ -1331,7 +1331,7 @@ maple_device* maple_Create(MapleDeviceType type)
|
||||
switch(type)
|
||||
{
|
||||
case MDT_SegaController:
|
||||
if (settings.platform.system != DC_PLATFORM_ATOMISWAVE)
|
||||
if (!settings.platform.isAtomiswave())
|
||||
rv = new maple_sega_controller();
|
||||
else
|
||||
rv = new maple_atomiswave_controller();
|
||||
@@ -1358,7 +1358,7 @@ maple_device* maple_Create(MapleDeviceType type)
|
||||
break;
|
||||
|
||||
case MDT_LightGun:
|
||||
if (settings.platform.system != DC_PLATFORM_ATOMISWAVE)
|
||||
if (!settings.platform.isAtomiswave())
|
||||
rv = new maple_lightgun();
|
||||
else
|
||||
rv = new atomiswave_lightgun();
|
||||
|
||||
@@ -66,7 +66,7 @@ void maple_vblank()
|
||||
maple_ddt_pending_reset = false;
|
||||
}
|
||||
}
|
||||
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
||||
if (settings.platform.isConsole())
|
||||
maple_handle_reconnect();
|
||||
}
|
||||
|
||||
|
||||
+16
-13
@@ -65,7 +65,7 @@ const char *GetCurrentGameButtonName(DreamcastKey key)
|
||||
val >>= 1;
|
||||
}
|
||||
u32 arcade_key;
|
||||
if (settings.platform.system == DC_PLATFORM_NAOMI)
|
||||
if (settings.platform.isNaomi())
|
||||
{
|
||||
if (pos >= ARRAY_SIZE(naomi_button_mapping))
|
||||
return nullptr;
|
||||
@@ -643,8 +643,17 @@ maple_naomi_jamma::maple_naomi_jamma()
|
||||
io_boards.push_back(std::unique_ptr<jvs_837_13844>(new jvs_837_13844(1, this)));
|
||||
break;
|
||||
case JVS::DualIOBoards4P:
|
||||
io_boards.push_back(std::unique_ptr<jvs_837_13551>(new jvs_837_13551(1, this)));
|
||||
io_boards.push_back(std::unique_ptr<jvs_837_13551>(new jvs_837_13551(2, this, 2)));
|
||||
if (!strcmp(naomi_game_id, "VIRTUA ATHLETE"))
|
||||
{
|
||||
// reverse the board order so that P1 is P1
|
||||
io_boards.push_back(std::unique_ptr<jvs_837_13551>(new jvs_837_13551(1, this, 2)));
|
||||
io_boards.push_back(std::unique_ptr<jvs_837_13551>(new jvs_837_13551(2, this, 0)));
|
||||
}
|
||||
else
|
||||
{
|
||||
io_boards.push_back(std::unique_ptr<jvs_837_13551>(new jvs_837_13551(1, this)));
|
||||
io_boards.push_back(std::unique_ptr<jvs_837_13551>(new jvs_837_13551(2, this, 2)));
|
||||
}
|
||||
break;
|
||||
case JVS::LightGun:
|
||||
io_boards.push_back(std::unique_ptr<jvs_namco_jyu>(new jvs_namco_jyu(1, this)));
|
||||
@@ -847,7 +856,7 @@ void maple_naomi_jamma::handle_86_subcommand()
|
||||
u8 channel = 0;
|
||||
if (dma_count_in >= 3)
|
||||
{
|
||||
if (dma_buffer_in[1] > 31 && dma_buffer_in[1] != 0xff && dma_count_in >= 8) // TODO what is this?
|
||||
if (subcode != 0x13 && dma_count_in >= 8)
|
||||
{
|
||||
node_id = dma_buffer_in[6];
|
||||
len = dma_buffer_in[7];
|
||||
@@ -972,7 +981,7 @@ void maple_naomi_jamma::handle_86_subcommand()
|
||||
{
|
||||
int address = dma_buffer_in[1];
|
||||
int size = dma_buffer_in[2];
|
||||
DEBUG_LOG(MAPLE, "EEprom write %08X %08X\n", address, size);
|
||||
DEBUG_LOG(MAPLE, "EEprom write %08x %08x", address, size);
|
||||
//printState(Command,buffer_in,buffer_in_len);
|
||||
address = address % sizeof(eeprom);
|
||||
size = std::min((int)sizeof(eeprom) - address, size);
|
||||
@@ -1609,14 +1618,8 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
|
||||
}
|
||||
else
|
||||
{
|
||||
// specs:
|
||||
//u16 x = mo_x_abs * 0xFFFF / 639;
|
||||
//u16 y = (479 - mo_y_abs) * 0xFFFF / 479;
|
||||
// Ninja Assault:
|
||||
u32 xr = 0x19d - 0x37;
|
||||
u32 yr = 0x1fe - 0x40;
|
||||
x = mapleInputState[playerNum].absPos.x * xr / 639 + 0x37;
|
||||
y = mapleInputState[playerNum].absPos.y * yr / 479 + 0x40;
|
||||
x = mapleInputState[playerNum].absPos.x;
|
||||
y = mapleInputState[playerNum].absPos.y;
|
||||
}
|
||||
LOGJVS("lightgun %4x,%4x ", x, y);
|
||||
JVS_OUT(x >> 8); // X, MSB
|
||||
|
||||
+23
-6
@@ -1,6 +1,7 @@
|
||||
#include "_vmem.h"
|
||||
#include "hw/aica/aica_if.h"
|
||||
#include "hw/pvr/pvr_mem.h"
|
||||
#include "hw/pvr/elan.h"
|
||||
#include "hw/sh4/dyna/blockmanager.h"
|
||||
#include "hw/sh4/sh4_mem.h"
|
||||
#include "oslib/oslib.h"
|
||||
@@ -24,6 +25,11 @@ static _vmem_WriteMem32FP* _vmem_WF32[HANDLER_COUNT];
|
||||
//upper 8b of the address
|
||||
static void* _vmem_MemInfo_ptr[0x100];
|
||||
|
||||
#define MAP_RAM_START_OFFSET 0
|
||||
#define MAP_VRAM_START_OFFSET (MAP_RAM_START_OFFSET+RAM_SIZE)
|
||||
#define MAP_ARAM_START_OFFSET (MAP_VRAM_START_OFFSET+VRAM_SIZE)
|
||||
#define MAP_ERAM_START_OFFSET (MAP_ARAM_START_OFFSET+ARAM_SIZE)
|
||||
|
||||
void* _vmem_read_const(u32 addr,bool& ismem,u32 sz)
|
||||
{
|
||||
u32 page=addr>>24;
|
||||
@@ -417,7 +423,8 @@ static void _vmem_set_p0_mappings()
|
||||
{0x05000000, 0x06000000, 0, 0, false}, // 32 bit path (unused)
|
||||
{0x06000000, 0x07000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // VRAM mirror
|
||||
{0x07000000, 0x08000000, 0, 0, false}, // 32 bit path (unused) mirror
|
||||
{0x08000000, 0x0C000000, 0, 0, false}, // Area 2
|
||||
{0x08000000, 0x0A000000, 0, 0, false}, // Area 2
|
||||
{0x0A000000, 0x0C000000, MAP_ERAM_START_OFFSET, elan::ELAN_RAM_SIZE, true}, // Area 2 (Elan RAM)
|
||||
{0x0C000000, 0x10000000, MAP_RAM_START_OFFSET, RAM_SIZE, true}, // Area 3 (main RAM + 3 mirrors)
|
||||
{0x10000000, 0x80000000, 0, 0, false}, // Area 4-7 (unused)
|
||||
};
|
||||
@@ -434,7 +441,7 @@ bool _vmem_reserve()
|
||||
// Use vmem only if settings mandate so, and if we have proper exception handlers.
|
||||
#if !defined(TARGET_NO_EXCEPTIONS)
|
||||
if (!settings.dynarec.disable_nvmem)
|
||||
vmemstatus = vmem_platform_init((void**)&virt_ram_base, (void**)&p_sh4rcb);
|
||||
vmemstatus = vmem_platform_init((void**)&virt_ram_base, (void**)&p_sh4rcb, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX + elan::ELAN_RAM_SIZE);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
@@ -451,6 +458,8 @@ static void _vmem_term_mappings()
|
||||
vram.data = nullptr;
|
||||
free_pages(aica_ram.data);
|
||||
aica_ram.data = nullptr;
|
||||
free_pages(elan::RAM);
|
||||
elan::RAM = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,6 +487,8 @@ void _vmem_init_mappings()
|
||||
|
||||
aica_ram.size = ARAM_SIZE;
|
||||
aica_ram.data = (u8*)malloc_pages(ARAM_SIZE);
|
||||
|
||||
elan::RAM = (u8*)malloc_pages(elan::ELAN_RAM_SIZE);
|
||||
}
|
||||
else {
|
||||
NOTICE_LOG(VMEM, "Info: nvmem is enabled, with addr space of size %s", vmemstatus == MemType4GB ? "4GB" : "512MB");
|
||||
@@ -493,7 +504,8 @@ void _vmem_init_mappings()
|
||||
{0x05000000, 0x06000000, 0, 0, false}, // 32 bit path (unused)
|
||||
{0x06000000, 0x07000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // VRAM mirror
|
||||
{0x07000000, 0x08000000, 0, 0, false}, // 32 bit path (unused) mirror
|
||||
{0x08000000, 0x0C000000, 0, 0, false}, // Area 2
|
||||
{0x08000000, 0x0A000000, 0, 0, false}, // Area 2
|
||||
{0x0A000000, 0x0C000000, MAP_ERAM_START_OFFSET, elan::ELAN_RAM_SIZE, true}, // Area 2 (Elan RAM)
|
||||
{0x0C000000, 0x10000000, MAP_RAM_START_OFFSET, RAM_SIZE, true}, // Area 3 (main RAM + 3 mirrors)
|
||||
{0x10000000, 0x20000000, 0, 0, false}, // Area 4-7 (unused)
|
||||
// This is outside of the 512MB addr space. We map 8MB in all cases to help some games read past the end of aica ram
|
||||
@@ -505,6 +517,7 @@ void _vmem_init_mappings()
|
||||
aica_ram.data = &virt_ram_base[0x20000000]; // Points to the writable AICA addrspace
|
||||
vram.data = &virt_ram_base[0x04000000]; // Points to first vram mirror (writable and lockable)
|
||||
mem_b.data = &virt_ram_base[0x0C000000]; // Main memory, first mirror
|
||||
elan::RAM = &virt_ram_base[0x0A000000];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -520,7 +533,8 @@ void _vmem_init_mappings()
|
||||
{0x85000000, 0x86000000, 0, 0, false}, // 32 bit path (unused)
|
||||
{0x86000000, 0x87000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // VRAM mirror
|
||||
{0x87000000, 0x88000000, 0, 0, false}, // 32 bit path (unused) mirror
|
||||
{0x88000000, 0x8C000000, 0, 0, false}, // Area 2
|
||||
{0x88000000, 0x8A000000, 0, 0, false}, // Area 2
|
||||
{0x8A000000, 0x8C000000, MAP_ERAM_START_OFFSET, elan::ELAN_RAM_SIZE, true}, // Area 2 (Elan RAM)
|
||||
{0x8C000000, 0x90000000, MAP_RAM_START_OFFSET, RAM_SIZE, true}, // Area 3 (main RAM + 3 mirrors)
|
||||
{0x90000000, 0xA0000000, 0, 0, false}, // Area 4-7 (unused)
|
||||
// P2
|
||||
@@ -533,7 +547,8 @@ void _vmem_init_mappings()
|
||||
{0xA5000000, 0xA6000000, 0, 0, false}, // 32 bit path (unused)
|
||||
{0xA6000000, 0xA7000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // VRAM mirror
|
||||
{0xA7000000, 0xA8000000, 0, 0, false}, // 32 bit path (unused) mirror
|
||||
{0xA8000000, 0xAC000000, 0, 0, false}, // Area 2
|
||||
{0xA8000000, 0xAA000000, 0, 0, false}, // Area 2
|
||||
{0xAA000000, 0xAC000000, MAP_ERAM_START_OFFSET, elan::ELAN_RAM_SIZE, true}, // Area 2 (Elan RAM)
|
||||
{0xAC000000, 0xB0000000, MAP_RAM_START_OFFSET, RAM_SIZE, true}, // Area 3 (main RAM + 3 mirrors)
|
||||
{0xB0000000, 0xC0000000, 0, 0, false}, // Area 4-7 (unused)
|
||||
// P3
|
||||
@@ -546,7 +561,8 @@ void _vmem_init_mappings()
|
||||
{0xC5000000, 0xC6000000, 0, 0, false}, // 32 bit path (unused)
|
||||
{0xC6000000, 0xC7000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // VRAM mirror
|
||||
{0xC7000000, 0xC8000000, 0, 0, false}, // 32 bit path (unused) mirror
|
||||
{0xC8000000, 0xCC000000, 0, 0, false}, // Area 2
|
||||
{0xC8000000, 0xCA000000, 0, 0, false}, // Area 2
|
||||
{0xCA000000, 0xCC000000, MAP_ERAM_START_OFFSET, elan::ELAN_RAM_SIZE, true}, // Area 2 (Elan RAM)
|
||||
{0xCC000000, 0xD0000000, MAP_RAM_START_OFFSET, RAM_SIZE, true}, // Area 3 (main RAM + 3 mirrors)
|
||||
{0xD0000000, 0x100000000L, 0, 0, false}, // Area 4-7 (unused)
|
||||
};
|
||||
@@ -556,6 +572,7 @@ void _vmem_init_mappings()
|
||||
aica_ram.data = &virt_ram_base[0x80800000]; // Points to the first AICA addrspace in P1
|
||||
vram.data = &virt_ram_base[0x84000000]; // Points to first vram mirror (writable and lockable) in P1
|
||||
mem_b.data = &virt_ram_base[0x8C000000]; // Main memory, first mirror in P1
|
||||
elan::RAM = &virt_ram_base[0x8A000000];
|
||||
|
||||
vmem_4gb_space = true;
|
||||
}
|
||||
|
||||
+1
-5
@@ -15,7 +15,7 @@ struct vmem_mapping {
|
||||
|
||||
// Platform specific vmemory API
|
||||
// To initialize (maybe) the vmem subsystem
|
||||
VMemType vmem_platform_init(void **vmem_base_addr, void **sh4rcb_addr);
|
||||
VMemType vmem_platform_init(void **vmem_base_addr, void **sh4rcb_addr, size_t ramSize);
|
||||
// To reset the on-demand allocated pages.
|
||||
void vmem_platform_reset_mem(void *ptr, unsigned size_bytes);
|
||||
// To handle a fault&allocate an ondemand page.
|
||||
@@ -109,10 +109,6 @@ static inline bool _nvmem_4gb_space() {
|
||||
}
|
||||
void _vmem_bm_reset();
|
||||
|
||||
#define MAP_RAM_START_OFFSET 0
|
||||
#define MAP_VRAM_START_OFFSET (MAP_RAM_START_OFFSET+RAM_SIZE)
|
||||
#define MAP_ARAM_START_OFFSET (MAP_VRAM_START_OFFSET+VRAM_SIZE)
|
||||
|
||||
void _vmem_protect_vram(u32 addr, u32 size);
|
||||
void _vmem_unprotect_vram(u32 addr, u32 size);
|
||||
u32 _vmem_get_vram_offset(void *addr);
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace memwatch
|
||||
VramWatcher vramWatcher;
|
||||
RamWatcher ramWatcher;
|
||||
AicaRamWatcher aramWatcher;
|
||||
ElanRamWatcher elanWatcher;
|
||||
|
||||
void AicaRamWatcher::protectMem(u32 addr, u32 size)
|
||||
{
|
||||
@@ -107,5 +108,63 @@ u32 AicaRamWatcher::getMemOffset(void *p)
|
||||
return addr;
|
||||
}
|
||||
|
||||
void ElanRamWatcher::protectMem(u32 addr, u32 size)
|
||||
{
|
||||
using namespace elan;
|
||||
size = std::min(ELAN_RAM_SIZE - addr, size) & ~PAGE_MASK;
|
||||
if (_nvmem_enabled())
|
||||
{
|
||||
mem_region_lock(virt_ram_base + 0x0a000000 + addr, size); // P0
|
||||
if (_nvmem_4gb_space())
|
||||
{
|
||||
mem_region_lock(virt_ram_base + 0x8a000000 + addr, size); // P1
|
||||
mem_region_lock(virt_ram_base + 0xaa000000 + addr, size); // P2
|
||||
}
|
||||
} else {
|
||||
mem_region_lock(RAM + addr, size);
|
||||
}
|
||||
}
|
||||
|
||||
void ElanRamWatcher::unprotectMem(u32 addr, u32 size)
|
||||
{
|
||||
using namespace elan;
|
||||
size = std::min(ELAN_RAM_SIZE - addr, size) & ~PAGE_MASK;
|
||||
if (_nvmem_enabled())
|
||||
{
|
||||
mem_region_unlock(virt_ram_base + 0x0a000000 + addr, size); // P0
|
||||
if (_nvmem_4gb_space())
|
||||
{
|
||||
mem_region_unlock(virt_ram_base + 0x8a000000 + addr, size); // P1
|
||||
mem_region_unlock(virt_ram_base + 0xaa000000 + addr, size); // P2
|
||||
}
|
||||
} else {
|
||||
mem_region_unlock(RAM + addr, size);
|
||||
}
|
||||
}
|
||||
|
||||
u32 ElanRamWatcher::getMemOffset(void *p)
|
||||
{
|
||||
using namespace elan;
|
||||
u32 addr;
|
||||
if (_nvmem_enabled())
|
||||
{
|
||||
if ((u8 *)p < virt_ram_base || (u8 *)p >= virt_ram_base + 0x100000000L)
|
||||
return -1;
|
||||
addr = (u32)((u8 *)p - virt_ram_base);
|
||||
u32 area = (addr >> 29) & 7;
|
||||
if (area != 0 && area != 4 && area != 5) // P0, P1 or P2 only
|
||||
return -1;
|
||||
addr &= 0x1fffffff;
|
||||
if (addr < 0x0a000000 || addr >= 0x0a000000 + ELAN_RAM_SIZE)
|
||||
return -1;
|
||||
addr &= ELAN_RAM_MASK;
|
||||
} else {
|
||||
if ((u8 *)p < RAM || (u8 *)p >= &RAM[ELAN_RAM_SIZE])
|
||||
return -1;
|
||||
addr = (u32)((u8 *)p - RAM);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "hw/sh4/dyna/blockmanager.h"
|
||||
#include "hw/sh4/sh4_mem.h"
|
||||
#include "hw/pvr/pvr_mem.h"
|
||||
#include "hw/pvr/elan.h"
|
||||
#include "rend/TexCache.h"
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
@@ -148,9 +149,26 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class ElanRamWatcher : public Watcher<ElanRamWatcher>
|
||||
{
|
||||
friend class Watcher<ElanRamWatcher>;
|
||||
|
||||
protected:
|
||||
void protectMem(u32 addr, u32 size);
|
||||
void unprotectMem(u32 addr, u32 size);
|
||||
u32 getMemOffset(void *p);
|
||||
|
||||
public:
|
||||
void *getMemPage(u32 addr)
|
||||
{
|
||||
return &elan::RAM[addr];
|
||||
}
|
||||
};
|
||||
|
||||
extern VramWatcher vramWatcher;
|
||||
extern RamWatcher ramWatcher;
|
||||
extern AicaRamWatcher aramWatcher;
|
||||
extern ElanRamWatcher elanWatcher;
|
||||
|
||||
inline static bool writeAccess(void *p)
|
||||
{
|
||||
@@ -166,6 +184,8 @@ inline static bool writeAccess(void *p)
|
||||
VramLockedWrite((u8 *)p);
|
||||
return true;
|
||||
}
|
||||
if (settings.platform.isNaomi2() && elanWatcher.hit(p))
|
||||
return true;
|
||||
return aramWatcher.hit(p);
|
||||
}
|
||||
|
||||
@@ -176,6 +196,7 @@ inline static void protect()
|
||||
vramWatcher.protect();
|
||||
ramWatcher.protect();
|
||||
aramWatcher.protect();
|
||||
elanWatcher.protect();
|
||||
}
|
||||
|
||||
inline static void reset()
|
||||
@@ -183,6 +204,7 @@ inline static void reset()
|
||||
vramWatcher.reset();
|
||||
ramWatcher.reset();
|
||||
aramWatcher.reset();
|
||||
elanWatcher.reset();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -410,18 +410,53 @@ void AWCartridge::AdvancePtr(u32 size)
|
||||
dma_offset += size;
|
||||
}
|
||||
|
||||
std::string AWCartridge::GetGameId()
|
||||
struct AtomiswaveBootID
|
||||
{
|
||||
if (RomSize < 0x30 + 0x20)
|
||||
return "(ROM too small)";
|
||||
char boardName[16]; // SYSTEM_X_APP
|
||||
char vendorName[32];
|
||||
char gameTitle[32];
|
||||
char year[4];
|
||||
char month[2];
|
||||
char day[2];
|
||||
u32 _unkn0;
|
||||
u32 _unkn1;
|
||||
u32 _unkn2;
|
||||
u32 gamePC;
|
||||
u32 _unkn3;
|
||||
u32 testPC;
|
||||
};
|
||||
|
||||
dma_offset = 0x30;
|
||||
u32 limit = 0x20;
|
||||
char *name = (char *)GetDmaPtr(limit);
|
||||
std::string game_id(name, limit);
|
||||
while (!game_id.empty() && game_id.back() == ' ')
|
||||
game_id.pop_back();
|
||||
return game_id;
|
||||
bool AWCartridge::GetBootId(RomBootID *bootId)
|
||||
{
|
||||
if (RomSize < sizeof(AtomiswaveBootID))
|
||||
return false;
|
||||
AtomiswaveBootID awBootId;
|
||||
u8 *p = (u8 *)&awBootId;
|
||||
u32 size = sizeof(AtomiswaveBootID);
|
||||
dma_offset = 0;
|
||||
recalc_dma_offset(EPR);
|
||||
while (size > 0)
|
||||
{
|
||||
u32 chunkSize = size;
|
||||
void *src = GetDmaPtr(chunkSize);
|
||||
if (chunkSize == 0)
|
||||
return false;
|
||||
memcpy(p, src, chunkSize);
|
||||
p += chunkSize;
|
||||
size -= chunkSize;
|
||||
AdvancePtr(chunkSize);
|
||||
}
|
||||
memset(bootId, 0, sizeof(RomBootID));
|
||||
memcpy(bootId->boardName, awBootId.boardName, sizeof(bootId->boardName));
|
||||
memcpy(bootId->vendorName, awBootId.vendorName, sizeof(bootId->vendorName));
|
||||
memcpy(bootId->gameTitle[0], awBootId.gameTitle, sizeof(bootId->gameTitle[0]));
|
||||
bootId->gamePC = awBootId.gamePC;
|
||||
bootId->testPC = awBootId.testPC;
|
||||
bootId->year = atoi(std::string(awBootId.year, awBootId.year + 4).c_str());
|
||||
bootId->month = atoi(std::string(awBootId.month, awBootId.month + 2).c_str());
|
||||
bootId->day = atoi(std::string(awBootId.day, awBootId.day + 2).c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AWCartridge::Serialize(Serializer& ser) const
|
||||
|
||||
@@ -25,7 +25,7 @@ public:
|
||||
|
||||
void *GetDmaPtr(u32 &size) override;
|
||||
void AdvancePtr(u32 size) override;
|
||||
std::string GetGameId() override;
|
||||
bool GetBootId(RomBootID *bootId) override;
|
||||
|
||||
void SetKey(u32 key) override;
|
||||
void Serialize(Serializer& ser) const override;
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
Copyright 2022 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "card_reader.h"
|
||||
#include "oslib/oslib.h"
|
||||
|
||||
namespace card_reader {
|
||||
|
||||
InitialDCardReader initialDCardReader;
|
||||
|
||||
bool CardReader::loadCard(u8 *cardData, u32 len)
|
||||
{
|
||||
std::string path = hostfs::getArcadeFlashPath() + ".card";
|
||||
FILE *fp = nowide::fopen(path.c_str(), "rb");
|
||||
if (fp == nullptr)
|
||||
return false;
|
||||
|
||||
DEBUG_LOG(NAOMI, "Loading card file from %s", path.c_str());
|
||||
if (fread(cardData, 1, len, fp) != len)
|
||||
WARN_LOG(NAOMI, "Truncated or empty card file: %s" ,path.c_str());
|
||||
fclose(fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CardReader::saveCard(const u8 *cardData, u32 len)
|
||||
{
|
||||
std::string path = hostfs::getArcadeFlashPath() + ".card";
|
||||
FILE *fp = nowide::fopen(path.c_str(), "wb");
|
||||
if (fp == nullptr)
|
||||
{
|
||||
WARN_LOG(NAOMI, "Can't create card file %s: errno %d", path.c_str(), errno);
|
||||
return;
|
||||
}
|
||||
DEBUG_LOG(NAOMI, "Saving card file to %s", path.c_str());
|
||||
if (fwrite(cardData, 1, len, fp) != len)
|
||||
WARN_LOG(NAOMI, "Truncated write to file: %s", path.c_str());
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void InitialDCardReader::write(u8 b)
|
||||
{
|
||||
if (inBufferIdx == 0 && b == 5)
|
||||
{
|
||||
DEBUG_LOG(NAOMI, "Received RQ(5)");
|
||||
handleCommand();
|
||||
return;
|
||||
}
|
||||
inBuffer[inBufferIdx++] = b;
|
||||
if (inBufferIdx >= 3)
|
||||
{
|
||||
if (inBuffer[0] != 2)
|
||||
{
|
||||
INFO_LOG(NAOMI, "Unexpected cmd start byte %x", inBuffer[0]);
|
||||
inBufferIdx = 0;
|
||||
return;
|
||||
}
|
||||
u32 len = inBuffer[1];
|
||||
if (inBufferIdx < len + 2)
|
||||
{
|
||||
if (inBufferIdx == sizeof(inBuffer))
|
||||
{
|
||||
WARN_LOG(NAOMI, "Card reader buffer overflow");
|
||||
inBufferIdx = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
u32 crc = calcCrc(&inBuffer[1], inBufferIdx - 2);
|
||||
if (crc != inBuffer[inBufferIdx - 1])
|
||||
{
|
||||
INFO_LOG(NAOMI, "Wrong crc: expected %x got %x", crc, inBuffer[inBufferIdx - 1]);
|
||||
inBufferIdx = 0;
|
||||
return;
|
||||
}
|
||||
DEBUG_LOG(NAOMI, "Received cmd %x len %d", inBuffer[2], inBuffer[1]);
|
||||
outBuffer[outBufferLen++] = 6; // ACK
|
||||
rxCommandLen = inBufferIdx - 3;
|
||||
memcpy(rxCommand, inBuffer + 2, rxCommandLen);
|
||||
inBufferIdx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
u8 InitialDCardReader::read()
|
||||
{
|
||||
verify(outBufferIdx < outBufferLen);
|
||||
u8 b = outBuffer[outBufferIdx++];
|
||||
DEBUG_LOG(NAOMI, "Sending %x", b);
|
||||
if (outBufferIdx == outBufferLen)
|
||||
outBufferIdx = outBufferLen = 0;
|
||||
return b;
|
||||
}
|
||||
|
||||
void InitialDCardReader::insertCard()
|
||||
{
|
||||
cardInserted = loadCard(cardData, sizeof(cardData));
|
||||
if (cardInserted)
|
||||
INFO_LOG(NAOMI, "Card inserted");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
Copyright 2022 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
Initial D card reader protocol (from my good friend Metallic)
|
||||
|
||||
>>> SEND PKT: [START 02][LEN][CMD][0][0][0]{optional data}[STOP 03][CRC]
|
||||
<<< RECV ACK: [OK 06]
|
||||
>>> SEND REQ: [RQ 05]
|
||||
<<< RECV PKT: [START 02][LEN][CMD][RESULT1][RESULT2][RESULT3]{optional data}[STOP 03][CRC]
|
||||
<<< RECV ERR: [15]
|
||||
RESULT1 (SENSORS): binary value SSTCCCCC
|
||||
S - Shutter state:
|
||||
0 - "ERROR"
|
||||
1 - "CLOSED"
|
||||
2 - "OPEN"
|
||||
3 - "NOW" (both open and close sensors)
|
||||
T - Stocker (card dispenser) state:
|
||||
0 - "NO" (empty)
|
||||
1 - "OK" (full)
|
||||
C - Card sensors:
|
||||
0 - "NO CARD"
|
||||
1 - "CARD EXIST (ENTER)" (card inserted in front of shutter)
|
||||
18 - "CARD EXIST" (card loaded inside of reader)
|
||||
other - "CARD EXIST (OTHER)"
|
||||
RESULT2: char 01235QRSTUV`
|
||||
Error ENUM "OK", "READ ERR", "WRITE ERR", "STOP ERR", "PRINT ERR", "READERR T1", "READERR T2", "READERR T3",
|
||||
"READERR T12", "READERR T13", "READERR T23", "SHUT ERR"
|
||||
RESULT3 (CMD_STATE): char 02345
|
||||
State ENUM "OK", "DISABLE", "BUSY", "CARD WAIT", "NO CARD IN BOX"
|
||||
|
||||
Protocol dumps and more:
|
||||
https://www.arcade-projects.com/threads/naomi-2-chihiro-triforce-card-reader-emulator-initial-d3-wmmt-mario-kart-f-zero-ax.814/
|
||||
*/
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include "hw/sh4/modules/modules.h"
|
||||
|
||||
namespace card_reader {
|
||||
|
||||
class CardReader
|
||||
{
|
||||
protected:
|
||||
u8 calcCrc(u8 *data, u32 len)
|
||||
{
|
||||
u32 crc = 0;
|
||||
for (u32 i = 0; i < len; i++)
|
||||
crc ^= data[i];
|
||||
return crc;
|
||||
}
|
||||
|
||||
bool loadCard(u8 *cardData, u32 len);
|
||||
void saveCard(const u8 *cardData, u32 len);
|
||||
};
|
||||
|
||||
class InitialDCardReader : public CardReader, SerialPipe
|
||||
{
|
||||
public:
|
||||
void write(u8 b) override;
|
||||
u8 read() override;
|
||||
|
||||
int available() override {
|
||||
return outBufferLen - outBufferIdx;
|
||||
}
|
||||
|
||||
void insertCard();
|
||||
void init() {
|
||||
serial_setPipe(this);
|
||||
}
|
||||
|
||||
private:
|
||||
enum Commands
|
||||
{
|
||||
CARD_INIT = 0x10,
|
||||
CARD_GET_CARD_STATE = 0x20,
|
||||
CARD_IS_PRESENT = 0x40, // cancel?
|
||||
CARD_LOAD_CARD = 0xB0,
|
||||
CARD_CLEAN_CARD = 0xA0,
|
||||
CARD_READ = 0x33,
|
||||
CARD_WRITE = 0x53,
|
||||
CARD_WRITE_INFO = 0x7C,
|
||||
CARD_PRINT = 0x78,
|
||||
CARD_7A = 0x7A,
|
||||
CARD_7D = 0x7D,
|
||||
CARD_DOOR = 0xD0,
|
||||
CARD_EJECT = 0x80,
|
||||
CARD_NEW = 0xB0,
|
||||
};
|
||||
|
||||
u8 getStatus1()
|
||||
{
|
||||
return ((doorOpen ? 2 : 1) << 6) | 0x20 | (cardInserted ? 0x18 : 0);
|
||||
}
|
||||
|
||||
void handleCommand()
|
||||
{
|
||||
if (rxCommandLen == 0)
|
||||
return;
|
||||
outBuffer[outBufferLen++] = 2;
|
||||
u32 crcIdx = outBufferLen;
|
||||
u8 len = 6;
|
||||
u8 status1 = getStatus1();
|
||||
u8 status2 = '0';
|
||||
u8 status3 = '0';
|
||||
switch (rxCommand[0])
|
||||
{
|
||||
case CARD_DOOR:
|
||||
doorOpen = rxCommand[4] == '1';
|
||||
status1 = getStatus1();
|
||||
break;
|
||||
|
||||
case CARD_NEW:
|
||||
cardInserted = true;
|
||||
doorOpen = false;
|
||||
status1 = getStatus1();
|
||||
break;
|
||||
|
||||
case CARD_WRITE:
|
||||
memcpy(cardData, &rxCommand[7], sizeof(cardData));
|
||||
saveCard(cardData, sizeof(cardData));
|
||||
break;
|
||||
|
||||
case CARD_READ:
|
||||
if (cardInserted && !doorOpen)
|
||||
len = 6 + sizeof(cardData);
|
||||
else
|
||||
status3 = cardInserted ? '0' : '4';
|
||||
break;
|
||||
|
||||
case CARD_EJECT:
|
||||
cardInserted = false;
|
||||
status1 = getStatus1();
|
||||
break;
|
||||
|
||||
case CARD_IS_PRESENT:
|
||||
case CARD_GET_CARD_STATE:
|
||||
case CARD_INIT:
|
||||
case CARD_7A:
|
||||
case CARD_PRINT:
|
||||
case CARD_WRITE_INFO:
|
||||
case CARD_CLEAN_CARD:
|
||||
break;
|
||||
|
||||
default:
|
||||
WARN_LOG(NAOMI, "Unknown command %x", rxCommand[0]);
|
||||
break;
|
||||
}
|
||||
outBuffer[outBufferLen++] = len;
|
||||
outBuffer[outBufferLen++] = rxCommand[0];
|
||||
outBuffer[outBufferLen++] = status1;
|
||||
outBuffer[outBufferLen++] = status2;
|
||||
outBuffer[outBufferLen++] = status3;
|
||||
if (rxCommand[0] == CARD_READ && cardInserted && !doorOpen)
|
||||
{
|
||||
memcpy(&outBuffer[outBufferLen], cardData, sizeof(cardData));
|
||||
outBufferLen += sizeof(cardData);
|
||||
}
|
||||
outBuffer[outBufferLen++] = 3;
|
||||
outBuffer[outBufferLen] = calcCrc(&outBuffer[crcIdx], outBufferLen - crcIdx);
|
||||
outBufferLen++;
|
||||
}
|
||||
|
||||
u8 inBuffer[256];
|
||||
u32 inBufferIdx;
|
||||
|
||||
u8 rxCommand[256];
|
||||
u32 rxCommandLen;
|
||||
|
||||
u8 outBuffer[256];
|
||||
u32 outBufferIdx;
|
||||
u32 outBufferLen;
|
||||
|
||||
u8 cardData[207];
|
||||
bool doorOpen = false;
|
||||
bool cardInserted = false;
|
||||
};
|
||||
extern InitialDCardReader initialDCardReader;
|
||||
|
||||
inline static void insertCard() {
|
||||
initialDCardReader.insertCard();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -627,14 +627,3 @@ bool GDCartridge::Read(u32 offset, u32 size, void *dst)
|
||||
memcpy(dst, &dimm_data[addr], std::min(size, dimm_data_size - addr));
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string GDCartridge::GetGameId()
|
||||
{
|
||||
if (dimm_data_size < 0x30 + 0x20)
|
||||
return "(ROM too small)";
|
||||
|
||||
std::string game_id((char *)(dimm_data + 0x30), 0x20);
|
||||
while (!game_id.empty() && game_id.back() == ' ')
|
||||
game_id.pop_back();
|
||||
return game_id;
|
||||
}
|
||||
@@ -33,7 +33,6 @@ public:
|
||||
void* GetDmaPtr(u32 &size) override;
|
||||
void AdvancePtr(u32 size) override;
|
||||
bool Read(u32 offset, u32 size, void* dst) override;
|
||||
std::string GetGameId() override;
|
||||
|
||||
void SetGDRomName(const char *name, const char *parentName) { this->gdrom_name = name; this->gdrom_parent_name = parentName; }
|
||||
|
||||
|
||||
@@ -273,26 +273,21 @@ M4Cartridge::~M4Cartridge()
|
||||
free(m_key_data);
|
||||
}
|
||||
|
||||
std::string M4Cartridge::GetGameId()
|
||||
bool M4Cartridge::GetBootId(RomBootID *bootId)
|
||||
{
|
||||
if (RomSize < 0x30 + 0x20)
|
||||
return "(ROM too small)";
|
||||
|
||||
std::string game_id;
|
||||
if (RomPtr[0] == 'N' && RomPtr[1] == 'A')
|
||||
game_id = std::string((char *)(RomPtr + 0x30), 0x20);
|
||||
else
|
||||
if (RomSize < sizeof(RomBootID))
|
||||
return false;
|
||||
RomBootID *pBootId = (RomBootID *)RomPtr;
|
||||
if (memcmp(pBootId->boardName, "NAOMI", 5))
|
||||
{
|
||||
rom_cur_address = 0;
|
||||
enc_reset();
|
||||
enc_fill();
|
||||
|
||||
game_id = std::string((char *)(buffer + 0x30), 0x20);
|
||||
pBootId = (RomBootID *)buffer;
|
||||
}
|
||||
memcpy(bootId, pBootId, sizeof(RomBootID));
|
||||
|
||||
while (!game_id.empty() && game_id.back() == ' ')
|
||||
game_id.pop_back();
|
||||
return game_id;
|
||||
return true;
|
||||
}
|
||||
|
||||
void M4Cartridge::Serialize(Serializer& ser) const
|
||||
|
||||
@@ -44,9 +44,9 @@ public:
|
||||
|
||||
void* GetDmaPtr(u32 &size) override;
|
||||
void AdvancePtr(u32 size) override;
|
||||
std::string GetGameId() override;
|
||||
void Serialize(Serializer& ser) const override;
|
||||
void Deserialize(Deserializer& deser) override;
|
||||
bool GetBootId(RomBootID *bootId) override;
|
||||
|
||||
void SetKey(u32 key) override { this->m4id = key; }
|
||||
void SetKeyData(u8 *key_data) override { this->m_key_data = key_data; }
|
||||
|
||||
+71
-6
@@ -9,12 +9,12 @@
|
||||
#include "hw/maple/maple_cfg.h"
|
||||
#include "hw/sh4/sh4_sched.h"
|
||||
#include "hw/sh4/modules/dmac.h"
|
||||
#include "hw/aica/aica_if.h"
|
||||
|
||||
#include "naomi.h"
|
||||
#include "naomi_cart.h"
|
||||
#include "naomi_regs.h"
|
||||
#include "naomi_m3comm.h"
|
||||
#include "network/naomi_network.h"
|
||||
#include "serialize.h"
|
||||
|
||||
//#define NAOMI_COMM
|
||||
@@ -46,6 +46,9 @@ P-Z (0x50-0x5A)
|
||||
static u8 BSerial[]="\xB7"/*CRC1*/"\x19"/*CRC2*/"0123234437897584372973927387463782196719782697849162342198671923649";
|
||||
static u8 GSerial[]="\xB7"/*CRC1*/"\x19"/*CRC2*/"0123234437897584372973927387463782196719782697849162342198671923649";
|
||||
|
||||
static u8 midiTxBuf[4];
|
||||
static u32 midiTxBufIndex;
|
||||
|
||||
static unsigned int ShiftCRC(unsigned int CRC,unsigned int rounds)
|
||||
{
|
||||
const unsigned int Magic=0x10210000;
|
||||
@@ -367,6 +370,10 @@ void naomi_process(u32 command, u32 offsetl, u32 parameterl, u32 parameterh)
|
||||
DEBUG_LOG(NAOMI, "Naomi process 0x%04X 0x%04X 0x%04X 0x%04X", command, offsetl, parameterl, parameterh);
|
||||
DEBUG_LOG(NAOMI, "Possible format 0 %d 0x%02X 0x%04X",command >> 15,(command & 0x7e00) >> 9, command & 0x1FF);
|
||||
DEBUG_LOG(NAOMI, "Possible format 1 0x%02X 0x%02X", (command & 0xFF00) >> 8,command & 0xFF);
|
||||
// command: param1 & 3f << 9 | param2
|
||||
// offsetl, paraml, paramh: params 3 4 5
|
||||
// HOLLY::SB_IML2EXT |= 8 when done
|
||||
|
||||
|
||||
u32 param=(command&0xFF);
|
||||
if (param==0xFF)
|
||||
@@ -406,7 +413,8 @@ void WriteMem_naomi(u32 address, u32 data, u32 size)
|
||||
INFO_LOG(NAOMI, "called without cartridge");
|
||||
return;
|
||||
}
|
||||
if (address >= NAOMI_COMM2_CTRL_addr && address <= NAOMI_COMM2_STATUS1_addr && settings.platform.system == DC_PLATFORM_NAOMI)
|
||||
if (address >= NAOMI_COMM2_CTRL_addr && address <= NAOMI_COMM2_STATUS1_addr
|
||||
&& settings.platform.isNaomi())
|
||||
m3comm.WriteMem(address, data, size);
|
||||
else
|
||||
CurrentCartridge->WriteMem(address, data, size);
|
||||
@@ -532,7 +540,6 @@ void naomi_reg_Term()
|
||||
}
|
||||
#endif
|
||||
m3comm.closeNetwork();
|
||||
naomiNetwork.terminate();
|
||||
}
|
||||
|
||||
void naomi_reg_Reset(bool hard)
|
||||
@@ -565,13 +572,13 @@ void naomi_reg_Reset(bool hard)
|
||||
reg_dimm_parameterh = 0;
|
||||
reg_dimm_status = 0x11;
|
||||
m3comm.closeNetwork();
|
||||
naomiNetwork.terminate();
|
||||
if (hard)
|
||||
naomi_cart_Close();
|
||||
}
|
||||
|
||||
static u8 aw_maple_devs;
|
||||
static u64 coin_chute_time[4];
|
||||
static u8 ffbOuput;
|
||||
|
||||
u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size) {
|
||||
addr &= 0x7ff;
|
||||
@@ -628,7 +635,8 @@ u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size) {
|
||||
case 0x288:
|
||||
// ??? Dolphin Blue
|
||||
return 0;
|
||||
|
||||
case 0x28c:
|
||||
return ffbOuput;
|
||||
}
|
||||
INFO_LOG(NAOMI, "Unhandled read @ %x sz %d", addr, size);
|
||||
return 0xFF;
|
||||
@@ -646,7 +654,12 @@ void libExtDevice_WriteMem_A0_006(u32 addr,u32 data,u32 size) {
|
||||
case 0x288:
|
||||
// ??? Dolphin Blue
|
||||
return;
|
||||
//case 0x28C: // Wheel force feedback?
|
||||
case 0x28C: // Wheel force feedback
|
||||
// bit 0 direction (0 pos, 1 neg)
|
||||
// bit 1-4 strength
|
||||
ffbOuput = data;
|
||||
DEBUG_LOG(NAOMI, "AW output %02x", data);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -681,6 +694,8 @@ void naomi_Serialize(Serializer& ser)
|
||||
ser << aw_maple_devs;
|
||||
ser << coin_chute_time;
|
||||
ser << aw_ram_test_skipped;
|
||||
ser << midiTxBuf;
|
||||
ser << midiTxBufIndex;
|
||||
// TODO serialize m3comm?
|
||||
}
|
||||
void naomi_Deserialize(Deserializer& deser)
|
||||
@@ -722,4 +737,54 @@ void naomi_Deserialize(Deserializer& deser)
|
||||
deser >> coin_chute_time;
|
||||
deser >> aw_ram_test_skipped;
|
||||
}
|
||||
if (deser.version() >= Deserializer::V27)
|
||||
{
|
||||
deser >> midiTxBuf;
|
||||
deser >> midiTxBufIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
midiTxBufIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void midiSend(u8 b1, u8 b2, u8 b3)
|
||||
{
|
||||
aica_midiSend(b1);
|
||||
aica_midiSend(b2);
|
||||
aica_midiSend(b3);
|
||||
aica_midiSend((b1 ^ b2 ^ b3) & 0x7f);
|
||||
}
|
||||
|
||||
static void forceFeedbackMidiReceiver(u8 data)
|
||||
{
|
||||
static float position = 8192.f;
|
||||
static float torque;
|
||||
position = std::min(16383.f, std::max(0.f, position + torque));
|
||||
if (data & 0x80)
|
||||
midiTxBufIndex = 0;
|
||||
midiTxBuf[midiTxBufIndex] = data;
|
||||
if (midiTxBufIndex == 3 && ((midiTxBuf[0] ^ midiTxBuf[1] ^ midiTxBuf[2]) & 0x7f) == midiTxBuf[3])
|
||||
{
|
||||
if (midiTxBuf[0] == 0x84)
|
||||
torque = ((midiTxBuf[1] << 7) | midiTxBuf[2]) - 0x80;
|
||||
else if (midiTxBuf[0] == 0xff)
|
||||
{
|
||||
torque = 0;
|
||||
position = 8192;
|
||||
}
|
||||
// required: b1 & 0x1f == 0x10 && b1 & 0x40 == 0
|
||||
midiSend(0x90, ((int)position >> 7) & 0x7f, (int)position & 0x7f);
|
||||
|
||||
// decoding from FFB Arcade Plugin (by Boomslangnz)
|
||||
// https://github.com/Boomslangnz/FFBArcadePlugin/blob/master/Game%20Files/Demul.cpp
|
||||
if (midiTxBuf[0] == 0x85 && midiTxBuf[1] == 0x3f)
|
||||
MapleConfigMap::UpdateVibration(0, std::max(0.f, (float)(midiTxBuf[2] - 1) / 24.f), 0.f, 5);
|
||||
}
|
||||
midiTxBufIndex = (midiTxBufIndex + 1) % ARRAY_SIZE(midiTxBuf);
|
||||
}
|
||||
|
||||
void initMidiForceFeedback()
|
||||
{
|
||||
aica_setMidiReceiver(forceFeedbackMidiReceiver);
|
||||
}
|
||||
@@ -25,3 +25,8 @@ extern u32 reg_dimm_offsetl;
|
||||
extern u32 reg_dimm_parameterl;
|
||||
extern u32 reg_dimm_parameterh;
|
||||
extern u32 reg_dimm_status;
|
||||
|
||||
void initMidiForceFeedback();
|
||||
|
||||
u32 libExtDevice_ReadMem_A0_006(u32 addr, u32 size);
|
||||
void libExtDevice_WriteMem_A0_006(u32 addr, u32 data, u32 size);
|
||||
+105
-52
@@ -37,6 +37,8 @@
|
||||
#include "cfg/option.h"
|
||||
#include "oslib/oslib.h"
|
||||
#include "serialize.h"
|
||||
#include "card_reader.h"
|
||||
#include "naomi_flashrom.h"
|
||||
|
||||
Cartridge *CurrentCartridge;
|
||||
bool bios_loaded = false;
|
||||
@@ -75,7 +77,10 @@ static bool loadBios(const char *filename, Archive *child_archive, Archive *pare
|
||||
for (int romid = 0; bios->blobs[romid].filename != NULL; romid++)
|
||||
{
|
||||
if (region == -1)
|
||||
{
|
||||
region = bios->blobs[romid].region;
|
||||
config::Region.override(region);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bios->blobs[romid].region != (u32)region)
|
||||
@@ -150,7 +155,7 @@ static bool loadBios(const char *filename, Archive *child_archive, Archive *pare
|
||||
if (config::GGPOEnable)
|
||||
md5.getDigest(settings.network.md5.bios);
|
||||
|
||||
if (settings.platform.system == DC_PLATFORM_ATOMISWAVE)
|
||||
if (settings.platform.isAtomiswave())
|
||||
// Reload the writeable portion of the FlashROM
|
||||
sys_rom->Reload();
|
||||
|
||||
@@ -187,12 +192,9 @@ void naomi_cart_LoadBios(const char *filename)
|
||||
const char *bios = "naomi";
|
||||
if (game->bios != nullptr)
|
||||
bios = game->bios;
|
||||
u32 region_flag = std::min((int)config::Region, (int)game->region_flag);
|
||||
if (game->region_flag == REGION_EXPORT_ONLY)
|
||||
region_flag = REGION_EXPORT;
|
||||
if (!loadBios(bios, archive.get(), parent_archive.get(), region_flag))
|
||||
if (!loadBios(bios, archive.get(), parent_archive.get(), config::Region))
|
||||
{
|
||||
WARN_LOG(NAOMI, "Warning: Region %d bios not found in %s", region_flag, bios);
|
||||
WARN_LOG(NAOMI, "Warning: Region %d bios not found in %s", (int)config::Region, bios);
|
||||
if (!loadBios(bios, archive.get(), parent_archive.get(), -1))
|
||||
{
|
||||
// If a specific BIOS is needed for this game, fail.
|
||||
@@ -205,7 +207,7 @@ void naomi_cart_LoadBios(const char *filename)
|
||||
bios_loaded = true;
|
||||
}
|
||||
|
||||
static void naomi_cart_LoadZip(const char *filename, LoadProgress *progress)
|
||||
static void loadMameRom(const char *filename, LoadProgress *progress)
|
||||
{
|
||||
Game *game = FindGame(filename);
|
||||
if (game == NULL)
|
||||
@@ -395,11 +397,8 @@ static void naomi_cart_LoadZip(const char *filename, LoadProgress *progress)
|
||||
}
|
||||
md5.getDigest(settings.network.md5.game);
|
||||
}
|
||||
|
||||
strcpy(naomi_game_id, CurrentCartridge->GetGameId().c_str());
|
||||
if (naomi_game_id[0] == '\0')
|
||||
strcpy(naomi_game_id, game->name);
|
||||
NOTICE_LOG(NAOMI, "NAOMI GAME ID [%s]", naomi_game_id);
|
||||
// Default game name if ROM boot id isn't found
|
||||
strcpy(naomi_game_id, game->name);
|
||||
|
||||
} catch (...) {
|
||||
delete CurrentCartridge;
|
||||
@@ -408,18 +407,8 @@ static void naomi_cart_LoadZip(const char *filename, LoadProgress *progress)
|
||||
}
|
||||
}
|
||||
|
||||
void naomi_cart_LoadRom(const char* file, LoadProgress *progress)
|
||||
static void loadDecryptedRom(const char* file, LoadProgress *progress)
|
||||
{
|
||||
naomi_cart_Close();
|
||||
|
||||
std::string extension = get_file_extension(file);
|
||||
|
||||
if (extension == "zip" || extension == "7z")
|
||||
{
|
||||
naomi_cart_LoadZip(file, progress);
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to load BIOS from naomi.zip
|
||||
if (!loadBios("naomi", NULL, NULL, config::Region))
|
||||
{
|
||||
@@ -437,6 +426,7 @@ void naomi_cart_LoadRom(const char* file, LoadProgress *progress)
|
||||
std::vector<u32> fsize;
|
||||
u32 romSize = 0;
|
||||
|
||||
std::string extension = get_file_extension(file);
|
||||
if (extension == "lst")
|
||||
{
|
||||
// LST file
|
||||
@@ -567,8 +557,55 @@ void naomi_cart_LoadRom(const char* file, LoadProgress *progress)
|
||||
DEBUG_LOG(NAOMI, "Legacy ROM loaded successfully");
|
||||
|
||||
CurrentCartridge = new DecryptedCartridge(romBase, romSize);
|
||||
strcpy(naomi_game_id, CurrentCartridge->GetGameId().c_str());
|
||||
NOTICE_LOG(NAOMI, "NAOMI GAME ID [%s]", naomi_game_id);
|
||||
}
|
||||
|
||||
void naomi_cart_LoadRom(const char* file, LoadProgress *progress)
|
||||
{
|
||||
naomi_cart_Close();
|
||||
|
||||
std::string extension = get_file_extension(file);
|
||||
|
||||
if (extension == "zip" || extension == "7z")
|
||||
loadMameRom(file, progress);
|
||||
else
|
||||
loadDecryptedRom(file, progress);
|
||||
|
||||
RomBootID bootId;
|
||||
if (CurrentCartridge->GetBootId(&bootId))
|
||||
{
|
||||
std::string gameId = trim_trailing_ws(std::string(bootId.gameTitle[0], &bootId.gameTitle[0][32]));
|
||||
if (strlen(gameId.c_str()) > 0)
|
||||
strcpy(naomi_game_id, gameId.c_str());
|
||||
NOTICE_LOG(NAOMI, "NAOMI GAME ID [%s] region %x players %x vertical %x", naomi_game_id, (u8)bootId.country, bootId.cabinet, bootId.vertical);
|
||||
|
||||
if (gameId == "INITIAL D"
|
||||
|| gameId == "INITIAL D Ver.2"
|
||||
|| gameId == "INITIAL D Ver.3"
|
||||
|| gameId == "INITIAL D CYCRAFT")
|
||||
{
|
||||
card_reader::initialDCardReader.init();
|
||||
initMidiForceFeedback();
|
||||
}
|
||||
else if (gameId == "SAMPLE GAME MAX LONG NAME-") // Driving Simulator
|
||||
{
|
||||
initMidiForceFeedback();
|
||||
}
|
||||
}
|
||||
else
|
||||
NOTICE_LOG(NAOMI, "NAOMI GAME ID [%s]", naomi_game_id);
|
||||
}
|
||||
|
||||
void naomi_cart_ConfigureEEPROM()
|
||||
{
|
||||
if (!settings.platform.isNaomi())
|
||||
return;
|
||||
|
||||
RomBootID bootId;
|
||||
if (CurrentCartridge->GetBootId(&bootId)
|
||||
&& (!memcmp(bootId.boardName, "NAOMI", 5) || !memcmp(bootId.boardName, "Naomi2", 6)))
|
||||
configure_naomi_eeprom(&bootId);
|
||||
else
|
||||
WARN_LOG(NAOMI, "Can't read ROM boot ID");
|
||||
}
|
||||
|
||||
void naomi_cart_Close()
|
||||
@@ -586,6 +623,8 @@ int naomi_cart_GetPlatform(const char *path)
|
||||
return DC_PLATFORM_NAOMI;
|
||||
else if (game->cart_type == AW)
|
||||
return DC_PLATFORM_ATOMISWAVE;
|
||||
else if (game->bios != nullptr && !strcmp("naomi2", game->bios))
|
||||
return DC_PLATFORM_NAOMI2;
|
||||
else
|
||||
return DC_PLATFORM_NAOMI;
|
||||
}
|
||||
@@ -638,19 +677,25 @@ void* Cartridge::GetPtr(u32 offset, u32& size)
|
||||
return &RomPtr[offset];
|
||||
}
|
||||
|
||||
std::string Cartridge::GetGameId() {
|
||||
if (RomSize < 0x30 + 0x20)
|
||||
return "(ROM too small)";
|
||||
|
||||
std::string game_id((char *)RomPtr + 0x30, 0x20);
|
||||
if (game_id == "AWNAOMI " && RomSize >= 0xFF50)
|
||||
bool NaomiCartridge::GetBootId(RomBootID *bootId)
|
||||
{
|
||||
if (RomSize < sizeof(RomBootID))
|
||||
return false;
|
||||
u8 *p = (u8 *)bootId;
|
||||
u32 size = sizeof(RomBootID);
|
||||
DmaOffset = 0;
|
||||
while (size > 0)
|
||||
{
|
||||
game_id = std::string((char *)RomPtr + 0xFF30, 0x20);
|
||||
u32 chunkSize = size;
|
||||
void *src = GetDmaPtr(chunkSize);
|
||||
if (chunkSize == 0)
|
||||
return false;
|
||||
memcpy(p, src, chunkSize);
|
||||
p += chunkSize;
|
||||
size -= chunkSize;
|
||||
AdvancePtr(chunkSize);
|
||||
}
|
||||
while (!game_id.empty() && game_id.back() == ' ')
|
||||
game_id.pop_back();
|
||||
|
||||
return game_id;
|
||||
return true;
|
||||
}
|
||||
|
||||
void* NaomiCartridge::GetDmaPtr(u32& size)
|
||||
@@ -672,7 +717,7 @@ u32 NaomiCartridge::ReadMem(u32 address, u32 size)
|
||||
switch(address & 255)
|
||||
{
|
||||
case 0x3c: // 5f703c: DIMM COMMAND
|
||||
DEBUG_LOG(NAOMI, "DIMM COMMAND read<%d>", size);
|
||||
//DEBUG_LOG(NAOMI, "DIMM COMMAND read<%d>", size);
|
||||
return 0xffff; //reg_dimm_command
|
||||
case 0x40: // 5f7040: DIMM OFFSETL
|
||||
DEBUG_LOG(NAOMI, "DIMM OFFSETL read<%d>", size);
|
||||
@@ -683,8 +728,8 @@ u32 NaomiCartridge::ReadMem(u32 address, u32 size)
|
||||
case 0x48: // 5f7048: DIMM PARAMETERH
|
||||
DEBUG_LOG(NAOMI, "DIMM PARAMETERH read<%d>", size);
|
||||
return reg_dimm_parameterh;
|
||||
case 0x04C: // 5f704c: DIMM STATUS
|
||||
DEBUG_LOG(NAOMI, "DIMM STATUS read<%d>", size);
|
||||
case 0x4c: // 5f704c: DIMM STATUS
|
||||
DEBUG_LOG(NAOMI, "DIMM STATUS read<%d>: %x", size, reg_dimm_status);
|
||||
return reg_dimm_status;
|
||||
|
||||
case NAOMI_ROM_OFFSETH_addr&255:
|
||||
@@ -756,23 +801,24 @@ void NaomiCartridge::WriteMem(u32 address, u32 data, u32 size)
|
||||
reg_dimm_status |= 1;*/
|
||||
}
|
||||
reg_dimm_command = data;
|
||||
DEBUG_LOG(NAOMI, "DIMM COMMAND Write: %X <= %X, %d", address, data, size);
|
||||
DEBUG_LOG(NAOMI, "DIMM COMMAND Write<%d>: %x", size, data);
|
||||
return;
|
||||
|
||||
case 0x40: // 5f7040: DIMM OFFSETL
|
||||
reg_dimm_offsetl = data;
|
||||
DEBUG_LOG(NAOMI, "DIMM OFFSETL Write: %X <= %X, %d", address, data, size);
|
||||
DEBUG_LOG(NAOMI, "DIMM OFFSETL Write<%d>: %x", size, data);
|
||||
return;
|
||||
case 0x44: // 5f7044: DIMM PARAMETERL
|
||||
reg_dimm_parameterl = data;
|
||||
DEBUG_LOG(NAOMI, "DIMM PARAMETERL Write: %X <= %X, %d", address, data, size);
|
||||
DEBUG_LOG(NAOMI, "DIMM PARAMETERL Write<%d>: %x", size, data);
|
||||
return;
|
||||
case 0x48: // 5f7048: DIMM PARAMETERH
|
||||
reg_dimm_parameterh = data;
|
||||
DEBUG_LOG(NAOMI, "DIMM PARAMETERH Write: %X <= %X, %d", address, data, size);
|
||||
DEBUG_LOG(NAOMI, "DIMM PARAMETERH Write<%d>: %x", size, data);
|
||||
return;
|
||||
|
||||
case 0x4C: // 5f704c: DIMM STATUS
|
||||
DEBUG_LOG(NAOMI, "DIMM STATUS Write<%d>: %x", size, data);
|
||||
if (data&0x100)
|
||||
{
|
||||
asic_CancelInterrupt(holly_EXP_PCI);
|
||||
@@ -784,8 +830,7 @@ void NaomiCartridge::WriteMem(u32 address, u32 data, u32 size)
|
||||
fclose(ramd);*/
|
||||
naomi_process(reg_dimm_command, reg_dimm_offsetl, reg_dimm_parameterl, reg_dimm_parameterh);
|
||||
}
|
||||
reg_dimm_status = data & ~0x100;
|
||||
DEBUG_LOG(NAOMI, "DIMM STATUS Write: %X <= %X, %d", address, data, size);
|
||||
reg_dimm_status = (data & ~0x100) | 1;
|
||||
return;
|
||||
|
||||
//These are known to be valid on normal ROMs and DIMM board
|
||||
@@ -853,6 +898,9 @@ void NaomiCartridge::WriteMem(u32 address, u32 data, u32 size)
|
||||
DEBUG_LOG(NAOMI, "naomi WriteMem: %X <= %X, %d", address, data, size);
|
||||
return;
|
||||
|
||||
case NAOMI_LED_addr & 0xff:
|
||||
return;
|
||||
|
||||
default: break;
|
||||
}
|
||||
DEBUG_LOG(NAOMI, "naomi?WTF? WriteMem: %X <= %X, %d", address, data, size);
|
||||
@@ -951,16 +999,21 @@ u16 M2Cartridge::ReadCipheredData(u32 offset)
|
||||
|
||||
}
|
||||
|
||||
std::string M2Cartridge::GetGameId()
|
||||
bool M2Cartridge::GetBootId(RomBootID *bootId)
|
||||
{
|
||||
std::string game_id = NaomiCartridge::GetGameId();
|
||||
if ((game_id.size() < 2 || ((u8)game_id[0] == 0xff && (u8)game_id[1] == 0xff)) && RomSize >= 0x800050)
|
||||
if (RomSize < sizeof(RomBootID))
|
||||
return false;
|
||||
RomBootID *pBootId = (RomBootID *)RomPtr;
|
||||
if ((pBootId->gameTitle[0][0] == '\0'
|
||||
|| ((u8)pBootId->gameTitle[0][0] == 0xff && (u8)pBootId->gameTitle[0][1] == 0xff)))
|
||||
{
|
||||
game_id = std::string((char *)RomPtr + 0x800030, 0x20);
|
||||
while (!game_id.empty() && game_id.back() == ' ')
|
||||
game_id.pop_back();
|
||||
if (RomSize < 0x800000 + sizeof(RomBootID))
|
||||
return false;
|
||||
pBootId = (RomBootID *)(RomPtr + 0x800000);
|
||||
}
|
||||
return game_id;
|
||||
memcpy(bootId, pBootId, sizeof(RomBootID));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void M2Cartridge::Serialize(Serializer& ser) const {
|
||||
|
||||
@@ -5,6 +5,44 @@
|
||||
#include "types.h"
|
||||
#include "emulator.h"
|
||||
|
||||
struct RomBootID
|
||||
{
|
||||
char boardName[16];
|
||||
char vendorName[32];
|
||||
char gameTitle[8][32];
|
||||
u16 year;
|
||||
u8 month;
|
||||
u8 day;
|
||||
char gameID[4]; // copied to eeprom[3]
|
||||
u16 romMode; // != 0 => offset | 0x20000000
|
||||
u16 romWaitFlag; // != 0 => configure G1 BUS
|
||||
u32 romWait[8]; // init values for SB_G1RRC, SB_G1RWC, SB_G1FRC, SB_G1FWC, SB_G1CRC, SB_G1CWC, SB_G1GDRC, SB_G1GDWC
|
||||
u16 romID[22][3]; // M2/M4-type ROM checksums
|
||||
u8 coinFlag[8][16];// Init instructions for EEPROM for each region
|
||||
// b0: if 0, use default BIOS settings, if 1, use settings below
|
||||
// b1: bit 0: vertical monitor, bit 1: forces attract mode sound off
|
||||
// b2: coin chute type: 0 common, 1; individual
|
||||
// b3: default coin setting (1-28)
|
||||
// b4: coin 1 rate (for manual coin setting)
|
||||
// b5: coin 2 rate (for manual coin setting)
|
||||
// b6: credit rate (for manual coin setting)
|
||||
// b7: bonus credit rate (for manual coin setting)
|
||||
// b8-15: coin sequences
|
||||
char sequence[8][32];// text ("CREDIT TO START", "CREDIT TO CONTINUE", ...)
|
||||
u32 gameLoad[8][3]; // regions to copy from ROM to system RAM: offset, RAM address, length (offset=0xffffffff means end of list)
|
||||
u32 testLoad[8][3]; // same for game test mode
|
||||
u32 gamePC; // main game entry point
|
||||
u32 testPC; // test mode entry point
|
||||
u8 country; // supported regions bitmap
|
||||
u8 cabinet; // supported # of players bitmap: b0 1 player, b1 2 players, ...
|
||||
u8 resolution; // 0: 31kHz, 1: 15kHz
|
||||
u8 vertical; // b0: horizontal mode, b1: vertical mode
|
||||
u8 serialID; // if 1, check the ROM/DIMM board serial# eeprom
|
||||
u8 _res[211]; // _res[210]: if 0xFF then the header is unencrypted. if not then the header is encrypted starting at offset 0x010.
|
||||
|
||||
// Note: this structure is copied to system RAM by the BIOS at location 0c01f400
|
||||
};
|
||||
|
||||
class Cartridge
|
||||
{
|
||||
public:
|
||||
@@ -23,11 +61,11 @@ public:
|
||||
virtual void* GetPtr(u32 offset, u32& size);
|
||||
virtual void* GetDmaPtr(u32 &size) = 0;
|
||||
virtual void AdvancePtr(u32 size) = 0;
|
||||
virtual std::string GetGameId();
|
||||
virtual void Serialize(Serializer& ser) const {}
|
||||
virtual void Deserialize(Deserializer& deser) {}
|
||||
virtual void SetKey(u32 key) { }
|
||||
virtual void SetKeyData(u8 *key_data) { }
|
||||
virtual bool GetBootId(RomBootID *bootId) = 0;
|
||||
|
||||
protected:
|
||||
u8* RomPtr;
|
||||
@@ -45,6 +83,7 @@ public:
|
||||
void AdvancePtr(u32 size) override {}
|
||||
void Serialize(Serializer& ser) const override;
|
||||
void Deserialize(Deserializer& deser) override;
|
||||
bool GetBootId(RomBootID *bootId) override;
|
||||
|
||||
void SetKey(u32 key) override { this->key = key; }
|
||||
|
||||
@@ -75,7 +114,7 @@ public:
|
||||
void Serialize(Serializer& ser) const override;
|
||||
void Deserialize(Deserializer& deser) override;
|
||||
void* GetDmaPtr(u32& size) override;
|
||||
std::string GetGameId() override;
|
||||
bool GetBootId(RomBootID *bootId) override;
|
||||
|
||||
private:
|
||||
u8 naomi_cart_ram[64 * 1024];
|
||||
@@ -91,6 +130,7 @@ void naomi_cart_LoadRom(const char* file, LoadProgress *progress);
|
||||
void naomi_cart_Close();
|
||||
int naomi_cart_GetPlatform(const char *path);
|
||||
void naomi_cart_LoadBios(const char *filename);
|
||||
void naomi_cart_ConfigureEEPROM();
|
||||
|
||||
extern char naomi_game_id[];
|
||||
extern u8 *naomi_default_eeprom;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "hw/flashrom/flashrom.h"
|
||||
#include "hw/holly/sb_mem.h"
|
||||
#include "hw/maple/maple_devs.h"
|
||||
#include "cfg/option.h"
|
||||
|
||||
extern WritableChip *sys_nvmem;
|
||||
|
||||
@@ -88,8 +89,7 @@ void write_naomi_flash(u32 addr, u8 value)
|
||||
// eeprom layout:
|
||||
// Offset Size
|
||||
// 0 2 CRC of bytes [2,17]
|
||||
// 2 1 size of record (16, sometimes 1, ignored)
|
||||
// 3 15 data
|
||||
// 2 16 data
|
||||
// 18 18 same record repeated
|
||||
// 36 2 CRC of bytes [44,44+size[
|
||||
// 38 1 record size
|
||||
@@ -98,10 +98,27 @@ void write_naomi_flash(u32 addr, u8 value)
|
||||
// 44 size*2 Record data, repeated twice
|
||||
//
|
||||
// The first record contains naomi bios settings, and the second one game-specific settings
|
||||
// common settings:
|
||||
// 2 b0 vertical screen
|
||||
// b4 attract mode sound
|
||||
// 3 Game serial ID (4 chars)
|
||||
// 7 unknown (9 or x18)
|
||||
// 8 b0: coin chute type (0 common, 1 individual)
|
||||
// b4-5: cabinet type (0: 1P, 10: 2P, 20: 2P, 30: 4P)
|
||||
// 9 coin setting (-1), 27 is manual
|
||||
// 10 coin to credit
|
||||
// 11 chute 1 multiplier
|
||||
// 12 chute 2 multiplier
|
||||
// 13 bonus adder (coins)
|
||||
// 14 coin sequence: b0-3 seq 1, b4-7 seq 2
|
||||
// 15 coin sequence: b0-3 seq 3, b4-7 seq 4
|
||||
// 16 coin sequence: b0-3 seq 5, b4-7 seq 6
|
||||
// 17 coin sequence: b0-3 seq 7, b4-7 seq 8
|
||||
//
|
||||
|
||||
void write_naomi_eeprom(u32 offset, u8 value)
|
||||
{
|
||||
if (offset >= 3 && offset < 20)
|
||||
if (offset >= 2 && offset < 18)
|
||||
{
|
||||
EEPROM[offset] = value;
|
||||
EEPROM[offset + 18] = value;
|
||||
@@ -121,3 +138,173 @@ void write_naomi_eeprom(u32 offset, u8 value)
|
||||
else
|
||||
WARN_LOG(NAOMI, "EEPROM record doesn't exist or is too short");
|
||||
}
|
||||
|
||||
static u8 readEeprom(u32 offset)
|
||||
{
|
||||
return EEPROM[offset & 127];
|
||||
}
|
||||
|
||||
static bool initEeprom(const RomBootID *bootId)
|
||||
{
|
||||
if (!memcmp(bootId->gameID, &EEPROM[3], sizeof(bootId->gameID)))
|
||||
return false;
|
||||
NOTICE_LOG(NAOMI, "Initializing Naomi EEPROM for game %.32s", bootId->gameTitle[0]);
|
||||
for (int i = 0; i < 4; i++)
|
||||
write_naomi_eeprom(3 + i, bootId->gameID[i]);
|
||||
write_naomi_eeprom(7, 9); // FIXME 9 or 0x18?
|
||||
if (bootId->cabinet & 8)
|
||||
write_naomi_eeprom(8, 30);
|
||||
else if (bootId->cabinet & 4)
|
||||
write_naomi_eeprom(8, 20);
|
||||
else if (bootId->cabinet & 2)
|
||||
write_naomi_eeprom(8, 10);
|
||||
else
|
||||
write_naomi_eeprom(8, 0);
|
||||
if (bootId->coinFlag[0][1] == 1)
|
||||
{
|
||||
// ROM-specific defaults
|
||||
write_naomi_eeprom(2, bootId->coinFlag[0][3] | (((bootId->coinFlag[0][3] & 2) ^ 2) << 3));
|
||||
write_naomi_eeprom(9, bootId->coinFlag[0][3] - 1);
|
||||
write_naomi_eeprom(10, bootId->coinFlag[0][6]);
|
||||
write_naomi_eeprom(11, bootId->coinFlag[0][4]);
|
||||
write_naomi_eeprom(12, bootId->coinFlag[0][5]);
|
||||
write_naomi_eeprom(13, bootId->coinFlag[0][7]);
|
||||
write_naomi_eeprom(14, bootId->coinFlag[0][8] | (bootId->coinFlag[0][9] << 4));
|
||||
write_naomi_eeprom(15, bootId->coinFlag[0][10] | (bootId->coinFlag[0][11] << 4));
|
||||
write_naomi_eeprom(16, bootId->coinFlag[0][12] | (bootId->coinFlag[0][13] << 4));
|
||||
write_naomi_eeprom(17, bootId->coinFlag[0][14] | (bootId->coinFlag[0][15] << 4));
|
||||
}
|
||||
else
|
||||
{
|
||||
// BIOS defaults
|
||||
write_naomi_eeprom(2, (bootId->vertical & 2) ? 0x11 : 0x10);
|
||||
write_naomi_eeprom(9, 0);
|
||||
write_naomi_eeprom(10, 1);
|
||||
write_naomi_eeprom(11, 1);
|
||||
write_naomi_eeprom(12, 1);
|
||||
write_naomi_eeprom(13, 0);
|
||||
write_naomi_eeprom(14, 0x11);
|
||||
write_naomi_eeprom(15, 0x11);
|
||||
write_naomi_eeprom(16, 0x11);
|
||||
write_naomi_eeprom(17, 0x11);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void configure_naomi_eeprom(const RomBootID *bootId)
|
||||
{
|
||||
initEeprom(bootId);
|
||||
// Horizontal / vertical screen orientation
|
||||
if (bootId->vertical & 2)
|
||||
{
|
||||
NOTICE_LOG(NAOMI, "EEPROM: vertical monitor orientation");
|
||||
write_naomi_eeprom(2, readEeprom(2) | 1);
|
||||
config::Rotate90.override(true);
|
||||
}
|
||||
else if (bootId->vertical & 1)
|
||||
{
|
||||
NOTICE_LOG(NAOMI, "EEPROM: horizontal monitor orientation");
|
||||
write_naomi_eeprom(2, readEeprom(2) & ~1);
|
||||
}
|
||||
// Number of players
|
||||
if (bootId->cabinet != 0)
|
||||
{
|
||||
int nPlayers = readEeprom(8) >> 4; // 0 to 3
|
||||
if (!(bootId->cabinet & (1 << nPlayers)))
|
||||
{
|
||||
u8 coinChute = readEeprom(8) & 1;
|
||||
if (bootId->cabinet & 8)
|
||||
{
|
||||
NOTICE_LOG(NAOMI, "EEPROM: 4-player cabinet");
|
||||
write_naomi_eeprom(8, 0x30 | coinChute);
|
||||
}
|
||||
else if (bootId->cabinet & 4)
|
||||
{
|
||||
NOTICE_LOG(NAOMI, "EEPROM: 3-player cabinet");
|
||||
write_naomi_eeprom(8, 0x20 | coinChute);
|
||||
}
|
||||
else if (bootId->cabinet & 2)
|
||||
{
|
||||
NOTICE_LOG(NAOMI, "EEPROM: 2-player cabinet");
|
||||
write_naomi_eeprom(8, 0x10 | coinChute);
|
||||
}
|
||||
else if (bootId->cabinet & 1)
|
||||
{
|
||||
NOTICE_LOG(NAOMI, "EEPROM: 1-player cabinet");
|
||||
write_naomi_eeprom(8, 0x00 | coinChute);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Region
|
||||
if (bootId->country != 0 && (bootId->country & (1 << config::Region)) == 0)
|
||||
{
|
||||
if (bootId->country & 2)
|
||||
{
|
||||
NOTICE_LOG(NAOMI, "Forcing region USA");
|
||||
config::Region.override(1);
|
||||
}
|
||||
else if (bootId->country & 4)
|
||||
{
|
||||
NOTICE_LOG(NAOMI, "Forcing region Export");
|
||||
config::Region.override(2);
|
||||
}
|
||||
else if (bootId->country & 1)
|
||||
{
|
||||
NOTICE_LOG(NAOMI, "Forcing region Japan");
|
||||
config::Region.override(0);
|
||||
}
|
||||
else if (bootId->country & 8)
|
||||
{
|
||||
NOTICE_LOG(NAOMI, "Forcing region Korea");
|
||||
config::Region.override(3);
|
||||
}
|
||||
naomi_cart_LoadBios(settings.content.path.c_str());
|
||||
}
|
||||
// Coin settings
|
||||
if (config::ForceFreePlay)
|
||||
write_naomi_eeprom(9, 27 - 1);
|
||||
}
|
||||
|
||||
static u32 aw_crc32(const void *data, size_t len)
|
||||
{
|
||||
constexpr u32 POLY = 0xEDB88320;
|
||||
const u8 *buffer = (const u8 *)data;
|
||||
u32 crc = -1;
|
||||
|
||||
while (len--)
|
||||
{
|
||||
crc = crc ^ *buffer++;
|
||||
for (int bit = 0; bit < 8; bit++)
|
||||
{
|
||||
if (crc & 1)
|
||||
crc = (crc >> 1) ^ POLY;
|
||||
else
|
||||
crc = crc >> 1;
|
||||
}
|
||||
}
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
void configure_maxspeed_flash(bool enableNetwork, bool master)
|
||||
{
|
||||
if (enableNetwork)
|
||||
{
|
||||
sys_nvmem->data[0x3358] = 0;
|
||||
sys_nvmem->data[0x46ac] = 0;
|
||||
sys_nvmem->data[0x335c] = !master;
|
||||
sys_nvmem->data[0x46b0] = !master;
|
||||
}
|
||||
else
|
||||
{
|
||||
sys_nvmem->data[0x3358] = 1;
|
||||
sys_nvmem->data[0x46ac] = 1;
|
||||
}
|
||||
u32 crc = aw_crc32(&sys_nvmem->data[0x2200], 0x1354);
|
||||
*(u32 *)&sys_nvmem->data[0x34] = crc;
|
||||
*(u32 *)&sys_nvmem->data[0x38] = crc;
|
||||
*(u32 *)&sys_nvmem->data[0x84] = crc;
|
||||
*(u32 *)&sys_nvmem->data[0x88] = crc;
|
||||
crc = aw_crc32(&sys_nvmem->data[0x20], 0x44);
|
||||
*(u32 *)&sys_nvmem->data[0x64] = crc;
|
||||
*(u32 *)&sys_nvmem->data[0xb4] = crc;
|
||||
}
|
||||
@@ -20,6 +20,9 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include "naomi_cart.h"
|
||||
|
||||
void write_naomi_flash(u32 addr, u8 value);
|
||||
void write_naomi_eeprom(u32 offset, u8 value);
|
||||
void configure_naomi_eeprom(const RomBootID *bootId);
|
||||
void configure_maxspeed_flash(bool enableNetwork, bool master);
|
||||
+89
-108
@@ -18,69 +18,89 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
//
|
||||
// Optical communication board (837-13691)
|
||||
// Ring topology
|
||||
// 10 Mbps
|
||||
// Max packet size 0x4000
|
||||
//
|
||||
#include "naomi_m3comm.h"
|
||||
#include "naomi_regs.h"
|
||||
#include "hw/holly/sb.h"
|
||||
#include "hw/sh4/sh4_mem.h"
|
||||
#include "network/naomi_network.h"
|
||||
#include "emulator.h"
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
constexpr u16 COMM_CTRL_CPU_RAM = 1 << 0;
|
||||
constexpr u16 COMM_CTRL_RESET = 1 << 5; // rising edge
|
||||
constexpr u16 COMM_CTRL_G1DMA = 1 << 14; // active low
|
||||
|
||||
struct CommBoardStat
|
||||
{
|
||||
u16 transmode; // communication mode (0: master, positive value: slave)
|
||||
u16 totalnode; // Total number of nodes (same value is entered in upper and lower 8 bits)
|
||||
u16 nodeID; // Local node ID (the same value is entered in the upper and lower 8 bits)
|
||||
u16 transcnt; // counter (value increases by 1 per frame)
|
||||
u16 cts; // CTS timer value (for debugging)
|
||||
u16 dma_rx_addr; // DMA receive address (for debugging)
|
||||
u16 dma_rx_size; // DMA receive size (for debugging)
|
||||
u16 dma_tx_addr; // DMA transmit address (for debugging)
|
||||
u16 dma_tx_size; // DMA transmission size (for debugging)
|
||||
u16 dummy[7];
|
||||
};
|
||||
|
||||
static inline u16 swap16(u16 w)
|
||||
{
|
||||
return (w >> 8) | (w << 8);
|
||||
}
|
||||
|
||||
static void vblankCallback(Event event, void *param) {
|
||||
((NaomiM3Comm *)param)->vblank();
|
||||
}
|
||||
|
||||
void NaomiM3Comm::closeNetwork()
|
||||
{
|
||||
network_stopping = true;
|
||||
EventManager::unlisten(Event::VBlank, vblankCallback, this);
|
||||
naomiNetwork.shutdown();
|
||||
if (thread && thread->joinable())
|
||||
thread->join();
|
||||
}
|
||||
|
||||
void NaomiM3Comm::connectNetwork()
|
||||
{
|
||||
gui_display_notification("Network started", 5000);
|
||||
packet_number = 0;
|
||||
if (naomiNetwork.syncNetwork())
|
||||
slot_count = naomiNetwork.getSlotCount();
|
||||
slot_id = naomiNetwork.getSlotId();
|
||||
if (slot_count >= 2)
|
||||
{
|
||||
slot_count = naomiNetwork.slotCount();
|
||||
slot_id = naomiNetwork.slotId();
|
||||
connectedState(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
connectedState(false);
|
||||
network_stopping = true;
|
||||
naomiNetwork.shutdown();
|
||||
connectedState();
|
||||
EventManager::listen(Event::VBlank, vblankCallback, this);
|
||||
}
|
||||
}
|
||||
|
||||
void NaomiM3Comm::receiveNetwork()
|
||||
bool NaomiM3Comm::receiveNetwork()
|
||||
{
|
||||
const u32 slot_size = swap16(*(u16*)&m68k_ram[0x204]);
|
||||
const u32 packet_size = slot_size * slot_count;
|
||||
|
||||
std::unique_ptr<u8[]> buf(new u8[packet_size]);
|
||||
|
||||
if (naomiNetwork.receive(buf.get(), packet_size))
|
||||
{
|
||||
packet_number += slot_count - 1;
|
||||
*(u16*)&comm_ram[6] = swap16(packet_number);
|
||||
std::unique_lock<std::mutex> lock(mem_mutex);
|
||||
memcpy(&comm_ram[0x100 + slot_size], buf.get(), packet_size);
|
||||
}
|
||||
u16 packetNumber;
|
||||
if (!naomiNetwork.receive(buf.get(), packet_size, &packetNumber))
|
||||
return false;
|
||||
|
||||
*(u16*)&comm_ram[6] = swap16(packetNumber);
|
||||
memcpy(&comm_ram[0x100 + slot_size], buf.get(), packet_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NaomiM3Comm::sendNetwork()
|
||||
{
|
||||
if (naomiNetwork.hasToken())
|
||||
{
|
||||
const u32 packet_size = swap16(*(u16*)&m68k_ram[0x204]) * slot_count;
|
||||
std::unique_lock<std::mutex> lock(mem_mutex);
|
||||
naomiNetwork.send(&comm_ram[0x100], packet_size);
|
||||
packet_number++;
|
||||
*(u16*)&comm_ram[6] = swap16(packet_number);
|
||||
}
|
||||
const u32 packet_size = swap16(*(u16*)&m68k_ram[0x204]) * slot_count;
|
||||
naomiNetwork.send(&comm_ram[0x100], packet_size, packet_number);
|
||||
packet_number++;
|
||||
}
|
||||
|
||||
u32 NaomiM3Comm::ReadMem(u32 address, u32 size)
|
||||
@@ -98,13 +118,13 @@ u32 NaomiM3Comm::ReadMem(u32 address, u32 size)
|
||||
case NAOMI_COMM2_DATA_addr & 255:
|
||||
{
|
||||
u16 value;
|
||||
if (comm_ctrl & 1)
|
||||
if (comm_ctrl & COMM_CTRL_CPU_RAM)
|
||||
value = *(u16*)&m68k_ram[comm_offset];
|
||||
else
|
||||
// TODO u16 *commram = (u16*)membank("comm_ram")->base();
|
||||
value = *(u16*)&comm_ram[comm_offset];
|
||||
value = swap16(value);
|
||||
DEBUG_LOG(NAOMI, "NAOMI_COMM2_DATA %s read @ %04x: %x", (comm_ctrl & 1) ? "m68k ram" : "comm ram", comm_offset, value);
|
||||
DEBUG_LOG(NAOMI, "NAOMI_COMM2_DATA %s read @ %04x: %x", (comm_ctrl & COMM_CTRL_CPU_RAM) ? "m68k ram" : "comm ram", comm_offset, value);
|
||||
comm_offset += 2;
|
||||
return value;
|
||||
}
|
||||
@@ -123,11 +143,8 @@ u32 NaomiM3Comm::ReadMem(u32 address, u32 size)
|
||||
}
|
||||
}
|
||||
|
||||
void NaomiM3Comm::connectedState(bool success)
|
||||
void NaomiM3Comm::connectedState()
|
||||
{
|
||||
if (!success)
|
||||
return;
|
||||
|
||||
memset(&comm_ram[0xf000], 0, 16);
|
||||
comm_ram[0xf000] = 1;
|
||||
comm_ram[0xf001] = 1;
|
||||
@@ -136,39 +153,16 @@ void NaomiM3Comm::connectedState(bool success)
|
||||
|
||||
u32 slot_size = swap16(*(u16*)&m68k_ram[0x204]);
|
||||
|
||||
memset(&comm_ram[0], 0, 32);
|
||||
// 80000
|
||||
comm_ram[0] = 0;
|
||||
comm_ram[1] = slot_id == 0 ? 0 : 1;
|
||||
// 80002
|
||||
comm_ram[2] = 0x01;
|
||||
comm_ram[3] = 0x01;
|
||||
// 80004
|
||||
if (slot_id == 0)
|
||||
{
|
||||
comm_ram[4] = 0;
|
||||
comm_ram[5] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
comm_ram[4] = 1;
|
||||
comm_ram[5] = 1;
|
||||
}
|
||||
// 80006: packet number
|
||||
comm_ram[6] = 0;
|
||||
comm_ram[7] = 0;
|
||||
// 80008
|
||||
comm_ram[8] = slot_id == 0 ? 0x78 : 0x73;
|
||||
comm_ram[9] = slot_id == 0 ? 0x30 : 0xa2;
|
||||
// 8000A
|
||||
*(u16 *)(comm_ram + 10) = 0x100 + slot_size; // offset of recvd data
|
||||
// 8000C
|
||||
*(u16 *)(comm_ram + 12) = slot_size * slot_count; // recvd data size
|
||||
// 8000E
|
||||
*(u16 *)(comm_ram + 14) = 0x100; // offset of sent data
|
||||
// 80010
|
||||
*(u16 *)(comm_ram + 16) = 0x80 + slot_size * slot_count; // sent data size
|
||||
// FIXME wrungp uses 100, others 80
|
||||
CommBoardStat& stat = *(CommBoardStat *)&comm_ram[0];
|
||||
memset(&stat, 0, sizeof(stat));
|
||||
stat.transmode = swap16(slot_id == 0 ? 0 : 1);
|
||||
stat.totalnode = slot_count | (slot_count << 8);
|
||||
stat.nodeID = slot_id | (slot_id << 8);
|
||||
stat.cts = swap16(slot_id == 0 ? 0x7830 : 0x73a2);
|
||||
stat.dma_rx_addr = swap16(0x100 + slot_size);
|
||||
stat.dma_rx_size = swap16(slot_size * slot_count);
|
||||
stat.dma_tx_addr = swap16(0x100);
|
||||
stat.dma_tx_size = swap16(slot_size * slot_count);
|
||||
|
||||
comm_status0 = 0xff01; // But 1 at connect time before f000 is read
|
||||
comm_status1 = (slot_count << 8) | slot_id;
|
||||
@@ -183,20 +177,19 @@ void NaomiM3Comm::WriteMem(u32 address, u32 data, u32 size)
|
||||
// bit 1: comm RAM bank (seems R/O for SH4)
|
||||
// bit 5: M68K Reset
|
||||
// bit 6: ???
|
||||
// bit 7: might be M68K IRQ 5 or 2
|
||||
// bit 7: might be M68K IRQ 5 or 2 - set to 0 by nlCbIntr()
|
||||
// bit 14: G1 DMA bus master 0 - active / 1 - disabled
|
||||
// bit 15: 0 - enable / 1 - disable this device ???
|
||||
if (data & (1 << 5))
|
||||
if ((comm_ctrl & COMM_CTRL_RESET) == 0 && (data & COMM_CTRL_RESET) != 0)
|
||||
{
|
||||
DEBUG_LOG(NAOMI, "NAOMI_COMM2_CTRL m68k reset");
|
||||
memset(&comm_ram[0], 0, 32);
|
||||
comm_status0 = 0; // varies...
|
||||
comm_status1 = 0;
|
||||
if (!thread || !thread->joinable())
|
||||
startThread();
|
||||
connectNetwork();
|
||||
}
|
||||
comm_ctrl = (u16)(data & ~(1 << 5));
|
||||
//DEBUG_LOG(NAOMI, "NAOMI_COMM2_CTRL set to %x", comm_ctrl);
|
||||
comm_ctrl = (u16)data;
|
||||
DEBUG_LOG(NAOMI, "NAOMI_COMM2_CTRL = %x", comm_ctrl);
|
||||
return;
|
||||
|
||||
case NAOMI_COMM2_OFFSET_addr & 255:
|
||||
@@ -207,7 +200,7 @@ void NaomiM3Comm::WriteMem(u32 address, u32 data, u32 size)
|
||||
case NAOMI_COMM2_DATA_addr & 255:
|
||||
DEBUG_LOG(NAOMI, "NAOMI_COMM2_DATA written @ %04x %04x", comm_offset, (u16)data);
|
||||
data = swap16(data);
|
||||
if (comm_ctrl & 1)
|
||||
if (comm_ctrl & COMM_CTRL_CPU_RAM)
|
||||
*(u16*)&m68k_ram[comm_offset] = (u16)data;
|
||||
else
|
||||
*(u16*)&comm_ram[comm_offset] = (u16)data;
|
||||
@@ -232,11 +225,10 @@ void NaomiM3Comm::WriteMem(u32 address, u32 data, u32 size)
|
||||
|
||||
bool NaomiM3Comm::DmaStart(u32 addr, u32 data)
|
||||
{
|
||||
if (comm_ctrl & 0x4000)
|
||||
if (comm_ctrl & COMM_CTRL_G1DMA)
|
||||
return false;
|
||||
|
||||
DEBUG_LOG(NAOMI, "NaomiM3Comm: DMA addr %08X <-> %04x len %d %s", SB_GDSTAR, comm_offset, SB_GDLEN, SB_GDDIR == 0 ? "OUT" : "IN");
|
||||
std::unique_lock<std::mutex> lock(mem_mutex);
|
||||
if (SB_GDDIR == 0)
|
||||
{
|
||||
// Network write
|
||||
@@ -246,7 +238,8 @@ bool NaomiM3Comm::DmaStart(u32 addr, u32 data)
|
||||
else
|
||||
{
|
||||
// Network read
|
||||
if (SB_GDLEN == 32 && (comm_ctrl & 1) == 0)
|
||||
/*
|
||||
if (SB_GDLEN == 32 && (comm_ctrl & COMM_CTRL_CPU_RAM) == 0)
|
||||
{
|
||||
char buf[32 * 5 + 1];
|
||||
buf[0] = 0;
|
||||
@@ -257,42 +250,30 @@ bool NaomiM3Comm::DmaStart(u32 addr, u32 data)
|
||||
}
|
||||
DEBUG_LOG(NAOMI, "Comm RAM read @%x: %s", comm_offset, buf);
|
||||
}
|
||||
*/
|
||||
for (u32 i = 0; i < SB_GDLEN; i++)
|
||||
WriteMem8_nommu(SB_GDSTAR + i, comm_ram[comm_offset++]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void NaomiM3Comm::startThread()
|
||||
void NaomiM3Comm::vblank()
|
||||
{
|
||||
network_stopping = false;
|
||||
thread = std::unique_ptr<std::thread>(new std::thread([this]() {
|
||||
using the_clock = std::chrono::high_resolution_clock;
|
||||
if ((comm_ctrl & COMM_CTRL_RESET) == 0 || comm_status1 == 0)
|
||||
return;
|
||||
|
||||
connectNetwork();
|
||||
|
||||
the_clock::time_point token_time = the_clock::now();
|
||||
|
||||
while (!network_stopping)
|
||||
{
|
||||
naomiNetwork.pipeSlaves();
|
||||
receiveNetwork();
|
||||
|
||||
if (slot_id == 0 && naomiNetwork.hasToken())
|
||||
{
|
||||
const auto target_duration = std::chrono::milliseconds(10);
|
||||
auto duration = the_clock::now() - token_time;
|
||||
if (duration < target_duration)
|
||||
{
|
||||
DEBUG_LOG(NAOMI, "Sleeping for %ld ms", (long)std::chrono::duration_cast<std::chrono::milliseconds>(target_duration - duration).count());
|
||||
std::this_thread::sleep_for(target_duration - duration);
|
||||
}
|
||||
token_time = the_clock::now();
|
||||
}
|
||||
|
||||
sendNetwork();
|
||||
|
||||
}
|
||||
DEBUG_LOG(NAOMI, "Network thread exiting");
|
||||
}));
|
||||
using the_clock = std::chrono::high_resolution_clock;
|
||||
the_clock::time_point start = the_clock::now();
|
||||
try {
|
||||
bool received = false;
|
||||
do {
|
||||
received = receiveNetwork();
|
||||
} while (!received && the_clock::now() - start < std::chrono::milliseconds(100));
|
||||
if (!received)
|
||||
INFO_LOG(NETWORK, "No data received");
|
||||
sendNetwork();
|
||||
} catch (const FlycastException& e) {
|
||||
comm_status0 = 0;
|
||||
comm_status1 = 0;
|
||||
}
|
||||
}
|
||||
@@ -20,10 +20,6 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
class NaomiM3Comm
|
||||
{
|
||||
@@ -33,13 +29,13 @@ public:
|
||||
bool DmaStart(u32 addr, u32 data);
|
||||
|
||||
void closeNetwork();
|
||||
void vblank();
|
||||
|
||||
private:
|
||||
void connectNetwork();
|
||||
void receiveNetwork();
|
||||
bool receiveNetwork();
|
||||
void sendNetwork();
|
||||
void connectedState(bool success);
|
||||
void startThread();
|
||||
void connectedState();
|
||||
|
||||
u16 comm_ctrl = 0xC000;
|
||||
u16 comm_offset = 0;
|
||||
@@ -51,7 +47,4 @@ private:
|
||||
|
||||
int slot_count = 0;
|
||||
int slot_id = 0;
|
||||
std::atomic<bool> network_stopping{ false };
|
||||
std::unique_ptr<std::thread> thread;
|
||||
std::mutex mem_mutex;
|
||||
};
|
||||
@@ -19,6 +19,7 @@ enum
|
||||
NAOMI_COMM2_STATUS0_addr = 0x5F7024,
|
||||
NAOMI_COMM2_STATUS1_addr = 0x5F7028,
|
||||
|
||||
NAOMI_LED_addr = 0x5F7068,
|
||||
NAOMI_BOARDID_WRITE_addr = 0x5F7078,
|
||||
NAOMI_BOARDID_READ_addr = 0x5F707C,
|
||||
NAOMI_COMM_OFFSET_addr = 0x5F7050,
|
||||
|
||||
+887
-254
File diff suppressed because it is too large.
Load diff
@@ -44,15 +44,6 @@ enum CartridgeType {
|
||||
GD
|
||||
};
|
||||
|
||||
enum RegionType {
|
||||
REGION_JAPAN = 0,
|
||||
REGION_USA = 1,
|
||||
REGION_EXPORT = 2,
|
||||
REGION_KOREA = 3,
|
||||
REGION_AUSTRALIA = 4,
|
||||
REGION_EXPORT_ONLY = 5
|
||||
};
|
||||
|
||||
enum RotationType {
|
||||
ROT0 = 0,
|
||||
ROT270 = 3,
|
||||
@@ -85,7 +76,6 @@ struct Game
|
||||
u32 key;
|
||||
const char *bios;
|
||||
CartridgeType cart_type;
|
||||
RegionType region_flag;
|
||||
RotationType rotation_flag;
|
||||
struct
|
||||
{
|
||||
|
||||
@@ -601,3 +601,80 @@ static InputDescriptors fotns_inputs = AW_5_BUTTONS("LP", "HP", "BOOST", "LK", "
|
||||
static InputDescriptors mslug6_inputs = AW_5_BUTTONS("SHOOT", "JUMP", "GRENADE", "METAL SLUG ATTACK", "SWITCH WEAPONS");
|
||||
|
||||
static InputDescriptors rumblef_inputs = AW_5_BUTTONS("LP", "SP", "Dodge", "LK", "SK");
|
||||
|
||||
static InputDescriptors kingrt66_inputs = {
|
||||
{
|
||||
{ NAOMI_BTN0_KEY, "HORN" },
|
||||
{ NAOMI_BTN1_KEY, "WIPER" },
|
||||
{ NAOMI_DOWN_KEY, "VIEW" },
|
||||
{ NAOMI_BTN2_KEY, "SHIFT L", 0, NAOMI_DOWN_KEY }, // This button uses P2 inputs for P1
|
||||
{ NAOMI_BTN3_KEY, "SHIFT H", 0, NAOMI_UP_KEY }, // This button uses P2 inputs for P1
|
||||
{ NAOMI_BTN4_KEY, "SHIFT R", 0, NAOMI_LEFT_KEY | NAOMI_DOWN_KEY },
|
||||
// This button uses P2 inputs for P1
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
},
|
||||
{
|
||||
{ "HANDLE", Full, 0 },
|
||||
{ "ACCEL", Half, 4 },
|
||||
{ "BRAKE", Half, 5 },
|
||||
},
|
||||
};
|
||||
|
||||
static InputDescriptors clubkart_inputs = {
|
||||
{
|
||||
{ NAOMI_DOWN_KEY, "VIEW" },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
},
|
||||
{
|
||||
{ "HANDLE", Full, 0 },
|
||||
{ "ACCEL", Half, 4 },
|
||||
{ "BRAKE", Half, 5 },
|
||||
},
|
||||
};
|
||||
|
||||
static InputDescriptors initd_inputs = {
|
||||
{
|
||||
{ NAOMI_DOWN_KEY, "VIEW" },
|
||||
{ NAOMI_BTN0_KEY, "GEAR UP", 0, NAOMI_UP_KEY }, // This button uses P2 inputs for P1
|
||||
{ NAOMI_BTN1_KEY, "GEAR DOWN", 0, NAOMI_DOWN_KEY }, // This button uses P2 inputs for P1
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
},
|
||||
{
|
||||
{ "HANDLE", Full, 0 },
|
||||
{ "ACCEL", Half, 4 },
|
||||
{ "BRAKE", Half, 5 },
|
||||
},
|
||||
};
|
||||
|
||||
static InputDescriptors wldrider_inputs = {
|
||||
{
|
||||
{ NAOMI_UP_KEY, "PUSH", NAOMI_LEFT_KEY },
|
||||
{ NAOMI_DOWN_KEY, "PULL", NAOMI_RIGHT_KEY },
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
},
|
||||
{
|
||||
{ "Handlebar", Full, 0 },
|
||||
{ "Accelerator", Half, 4 },
|
||||
{ "Front Brake", Half, 5 },
|
||||
{ "Rear Brake", Full, 2 },
|
||||
},
|
||||
};
|
||||
|
||||
static InputDescriptors soulsurfer_inputs = {
|
||||
{
|
||||
{ NAOMI_LEFT_KEY, "LEFT", NAOMI_BTN0_KEY },
|
||||
{ NAOMI_RIGHT_KEY, "RIGHT", NAOMI_BTN1_KEY },
|
||||
{ NAOMI_BTN4_KEY, "FLOORMAT" }, // TODO this should always be on
|
||||
NAO_START_DESC
|
||||
NAO_BASE_BTN_DESC
|
||||
},
|
||||
{
|
||||
{ "SWING", Full, 2 },
|
||||
{ "ROLL", Full, 0 },
|
||||
{ "PITCH", Full, 1, true },
|
||||
},
|
||||
};
|
||||
+26
-169
@@ -1,7 +1,5 @@
|
||||
#include "Renderer_if.h"
|
||||
#include "spg.h"
|
||||
#include "cheats.h"
|
||||
#include "hw/mem/_vmem.h"
|
||||
#include "hw/pvr/pvr_mem.h"
|
||||
#include "rend/TexCache.h"
|
||||
#include "cfg/option.h"
|
||||
@@ -10,7 +8,6 @@
|
||||
#include "serialize.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <zlib.h>
|
||||
|
||||
void retro_rend_present();
|
||||
#ifndef LIBRETRO
|
||||
@@ -42,160 +39,8 @@ static bool pend_rend;
|
||||
|
||||
TA_context* _pvrrc;
|
||||
|
||||
static void dump_frame(const char* file, TA_context* ctx, u8* vram, const u8* vram_ref = NULL) {
|
||||
FILE* fw = fopen(file, "wb");
|
||||
|
||||
//append to it
|
||||
fseek(fw, 0, SEEK_END);
|
||||
|
||||
u32 bytes = ctx->tad.End() - ctx->tad.thd_root;
|
||||
|
||||
fwrite("TAFRAME4", 1, 8, fw);
|
||||
|
||||
fwrite(&ctx->rend.isRTT, 1, sizeof(ctx->rend.isRTT), fw);
|
||||
u32 zero = 0;
|
||||
fwrite(&zero, 1, sizeof(bool), fw); // Was autosort
|
||||
fwrite(&ctx->rend.fb_X_CLIP.full, 1, sizeof(ctx->rend.fb_X_CLIP.full), fw);
|
||||
fwrite(&ctx->rend.fb_Y_CLIP.full, 1, sizeof(ctx->rend.fb_Y_CLIP.full), fw);
|
||||
|
||||
fwrite(ctx->rend.global_param_op.head(), 1, sizeof(PolyParam), fw);
|
||||
fwrite(ctx->rend.verts.head(), 1, 4 * sizeof(Vertex), fw);
|
||||
|
||||
u32 t = VRAM_SIZE;
|
||||
fwrite(&t, 1, sizeof(t), fw);
|
||||
|
||||
u8* compressed;
|
||||
uLongf compressed_size;
|
||||
u8* src_vram = vram;
|
||||
|
||||
if (vram_ref) {
|
||||
src_vram = (u8*)malloc(VRAM_SIZE);
|
||||
|
||||
for (u32 i = 0; i < VRAM_SIZE; i++) {
|
||||
src_vram[i] = vram[i] ^ vram_ref[i];
|
||||
}
|
||||
}
|
||||
|
||||
compressed = (u8*)malloc(VRAM_SIZE+16);
|
||||
compressed_size = VRAM_SIZE;
|
||||
verify(compress(compressed, &compressed_size, src_vram, VRAM_SIZE) == Z_OK);
|
||||
fwrite(&compressed_size, 1, sizeof(compressed_size), fw);
|
||||
fwrite(compressed, 1, compressed_size, fw);
|
||||
free(compressed);
|
||||
|
||||
if (src_vram != vram)
|
||||
free(src_vram);
|
||||
|
||||
fwrite(&bytes, 1, sizeof(t), fw);
|
||||
compressed = (u8*)malloc(bytes + 16);
|
||||
compressed_size = VRAM_SIZE;
|
||||
verify(compress(compressed, &compressed_size, ctx->tad.thd_root, bytes) == Z_OK);
|
||||
fwrite(&compressed_size, 1, sizeof(compressed_size), fw);
|
||||
fwrite(compressed, 1, compressed_size, fw);
|
||||
free(compressed);
|
||||
|
||||
fwrite(&ctx->tad.render_pass_count, 1, sizeof(u32), fw);
|
||||
for (u32 i = 0; i < ctx->tad.render_pass_count; i++) {
|
||||
u32 offset = ctx->tad.render_passes[i] - ctx->tad.thd_root;
|
||||
fwrite(&offset, 1, sizeof(offset), fw);
|
||||
}
|
||||
|
||||
fwrite(pvr_regs, 1, sizeof(pvr_regs), fw);
|
||||
|
||||
fclose(fw);
|
||||
}
|
||||
|
||||
TA_context* read_frame(const char* file, u8* vram_ref = NULL) {
|
||||
|
||||
FILE* fw = fopen(file, "rb");
|
||||
if (fw == NULL)
|
||||
die("Cannot open frame to display");
|
||||
char id0[8] = { 0 };
|
||||
u32 t = 0;
|
||||
|
||||
if (fread(id0, 1, 8, fw) != 8) {
|
||||
fclose(fw);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (memcmp(id0, "TAFRAME", 7) != 0 || (id0[7] != '3' && id0[7] != '4')) {
|
||||
fclose(fw);
|
||||
return 0;
|
||||
}
|
||||
u32 sizeofPolyParam = sizeof(PolyParam);
|
||||
u32 sizeofVertex = sizeof(Vertex);
|
||||
if (id0[7] == '3')
|
||||
{
|
||||
sizeofPolyParam -= 12;
|
||||
sizeofVertex -= 16;
|
||||
}
|
||||
|
||||
TA_context* ctx = tactx_Alloc();
|
||||
|
||||
ctx->Reset();
|
||||
|
||||
ctx->tad.Clear();
|
||||
|
||||
verify(fread(&ctx->rend.isRTT, 1, sizeof(ctx->rend.isRTT), fw) == sizeof(ctx->rend.isRTT));
|
||||
verify(fread(&t, 1, sizeof(bool), fw) == sizeof(bool)); // Was autosort
|
||||
verify(fread(&ctx->rend.fb_X_CLIP.full, 1, sizeof(ctx->rend.fb_X_CLIP.full), fw) == sizeof(ctx->rend.fb_X_CLIP.full));
|
||||
verify(fread(&ctx->rend.fb_Y_CLIP.full, 1, sizeof(ctx->rend.fb_Y_CLIP.full), fw) == sizeof(ctx->rend.fb_Y_CLIP.full));
|
||||
|
||||
verify(fread(ctx->rend.global_param_op.Append(), 1, sizeofPolyParam, fw) == sizeofPolyParam);
|
||||
Vertex *vtx = ctx->rend.verts.Append(4);
|
||||
for (int i = 0; i < 4; i++)
|
||||
verify(fread(vtx + i, 1, sizeofVertex, fw) == sizeofVertex);
|
||||
|
||||
verify(fread(&t, 1, sizeof(t), fw) == sizeof(t));
|
||||
verify(t == VRAM_SIZE);
|
||||
|
||||
_vmem_unprotect_vram(0, VRAM_SIZE);
|
||||
|
||||
uLongf compressed_size;
|
||||
|
||||
verify(fread(&compressed_size, 1, sizeof(compressed_size), fw) == sizeof(compressed_size));
|
||||
|
||||
u8* gz_stream = (u8*)malloc(compressed_size);
|
||||
verify(fread(gz_stream, 1, compressed_size, fw) == compressed_size);
|
||||
uLongf tl = t;
|
||||
verify(uncompress(vram.data, &tl, gz_stream, compressed_size) == Z_OK);
|
||||
free(gz_stream);
|
||||
|
||||
verify(fread(&t, 1, sizeof(t), fw) == sizeof(t));
|
||||
verify(fread(&compressed_size, 1, sizeof(compressed_size), fw) == sizeof(compressed_size));
|
||||
gz_stream = (u8*)malloc(compressed_size);
|
||||
verify(fread(gz_stream, 1, compressed_size, fw) == compressed_size);
|
||||
tl = t;
|
||||
verify(uncompress(ctx->tad.thd_data, &tl, gz_stream, compressed_size) == Z_OK);
|
||||
free(gz_stream);
|
||||
|
||||
ctx->tad.thd_data += t;
|
||||
|
||||
if (fread(&t, 1, sizeof(t), fw) > 0) {
|
||||
ctx->tad.render_pass_count = t;
|
||||
for (u32 i = 0; i < t; i++) {
|
||||
u32 offset;
|
||||
verify(fread(&offset, 1, sizeof(offset), fw) == sizeof(offset));
|
||||
ctx->tad.render_passes[i] = ctx->tad.thd_root + offset;
|
||||
}
|
||||
}
|
||||
verify(fread(pvr_regs, 1, sizeof(pvr_regs), fw) == sizeof(pvr_regs));
|
||||
|
||||
fclose(fw);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
bool dump_frame_switch = false;
|
||||
|
||||
static bool rend_frame(TA_context* ctx)
|
||||
{
|
||||
if (dump_frame_switch) {
|
||||
char name[32];
|
||||
sprintf(name, "dcframe-%d", FrameCount);
|
||||
dump_frame(name, _pvrrc, &vram[0]);
|
||||
dump_frame_switch = false;
|
||||
}
|
||||
bool proc = renderer->Process(ctx);
|
||||
|
||||
if (!proc || (!ctx->rend.isRTT && !ctx->rend.isRenderFramebuffer))
|
||||
@@ -343,11 +188,29 @@ void rend_reset()
|
||||
fb_w_cur = 1;
|
||||
}
|
||||
|
||||
void rend_start_render()
|
||||
void rend_start_render(TA_context *ctx)
|
||||
{
|
||||
render_called = true;
|
||||
pend_rend = false;
|
||||
TA_context* ctx = tactx_Pop(CORE_CURRENT_CTX);
|
||||
if (ctx == nullptr)
|
||||
{
|
||||
u32 addresses[MAX_PASSES];
|
||||
int count = getTAContextAddresses(addresses);
|
||||
if (count > 0)
|
||||
{
|
||||
ctx = tactx_Pop(addresses[0]);
|
||||
if (ctx != nullptr)
|
||||
{
|
||||
TA_context *linkedCtx = ctx;
|
||||
for (int i = 1; i < count; i++)
|
||||
{
|
||||
linkedCtx->nextContext = tactx_Pop(addresses[i]);
|
||||
if (linkedCtx->nextContext != nullptr)
|
||||
linkedCtx = linkedCtx->nextContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No end of render interrupt when rendering the framebuffer
|
||||
if (!ctx || !ctx->rend.isRenderFramebuffer)
|
||||
@@ -371,6 +234,8 @@ void rend_start_render()
|
||||
FillBGP(ctx);
|
||||
|
||||
ctx->rend.isRTT = (FB_W_SOF1 & 0x1000000) != 0;
|
||||
ctx->rend.fb_W_SOF1 = FB_W_SOF1;
|
||||
ctx->rend.fb_W_CTRL.full = FB_W_CTRL.full;
|
||||
|
||||
ctx->rend.fb_X_CLIP = FB_X_CLIP;
|
||||
ctx->rend.fb_Y_CLIP = FB_Y_CLIP;
|
||||
@@ -380,7 +245,7 @@ void rend_start_render()
|
||||
ctx->rend.fog_clamp_max = FOG_CLAMP_MAX;
|
||||
}
|
||||
|
||||
if (!config::DelayFrameSwapping)
|
||||
if (!config::DelayFrameSwapping && !ctx->rend.isRTT)
|
||||
ggpo::endOfFrame();
|
||||
palette_update();
|
||||
if (QueueRender(ctx))
|
||||
@@ -405,21 +270,13 @@ void rend_vblank()
|
||||
if (!render_called && fb_dirty && FB_R_CTRL.fb_enable)
|
||||
{
|
||||
DEBUG_LOG(PVR, "Direct framebuffer write detected");
|
||||
u32 saved_ctx_addr = PARAM_BASE;
|
||||
bool restore_ctx = ta_ctx != NULL;
|
||||
PARAM_BASE = 0xF00000;
|
||||
SetCurrentTARC(CORE_CURRENT_CTX);
|
||||
ta_ctx->Reset();
|
||||
ta_ctx->rend.isRenderFramebuffer = true;
|
||||
rend_start_render();
|
||||
PARAM_BASE = saved_ctx_addr;
|
||||
if (restore_ctx)
|
||||
SetCurrentTARC(CORE_CURRENT_CTX);
|
||||
TA_context *ctx = tactx_Alloc();
|
||||
ctx->rend.isRenderFramebuffer = true;
|
||||
rend_start_render(ctx);
|
||||
fb_dirty = false;
|
||||
}
|
||||
render_called = false;
|
||||
check_framebuffer_write();
|
||||
cheatManager.apply();
|
||||
emu.vblank();
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ extern u32 FrameCount;
|
||||
void rend_init_renderer();
|
||||
void rend_term_renderer();
|
||||
void rend_vblank();
|
||||
void rend_start_render();
|
||||
void rend_start_render(TA_context *ctx = nullptr);
|
||||
void rend_end_render();
|
||||
void rend_cancel_emu_wait();
|
||||
bool rend_single_frame(const bool& enabled);
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright 2022 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
namespace elan {
|
||||
|
||||
void init();
|
||||
void reset(bool hard);
|
||||
void term();
|
||||
|
||||
void vmem_init();
|
||||
void vmem_map(u32 base);
|
||||
|
||||
void serialize(Serializer& ser);
|
||||
void deserialize(Deserializer& deser);
|
||||
|
||||
extern u8 *RAM;
|
||||
constexpr u32 ELAN_RAM_SIZE = 32 * 1024 * 1024;
|
||||
constexpr u32 ELAN_RAM_MASK = ELAN_RAM_SIZE - 1;
|
||||
}
|
||||
@@ -0,0 +1,575 @@
|
||||
/*
|
||||
Copyright 2022 flyinghead
|
||||
|
||||
This file is part of Flycast.
|
||||
|
||||
Flycast is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Flycast is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
namespace elan
|
||||
{
|
||||
|
||||
union PCW
|
||||
{
|
||||
enum Command {
|
||||
null = 0,
|
||||
_matrix2 = 1,
|
||||
_matrix1 = 2,
|
||||
projMatrix = 3,
|
||||
matrixOrLight = 4,
|
||||
gmp = 5,
|
||||
ich = 7,
|
||||
model = 8,
|
||||
registerWait = 0xe,
|
||||
link = 0xf
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
// Obj Control
|
||||
u32 uv16bit : 1;
|
||||
u32 gouraud : 1;
|
||||
u32 offset : 1;
|
||||
u32 texture : 1;
|
||||
u32 colType : 2;
|
||||
u32 volume : 1;
|
||||
u32 shadow : 1;
|
||||
|
||||
// Naomi 2
|
||||
u32 n2Command : 4;
|
||||
u32 reserved : 4;
|
||||
|
||||
// Group Control
|
||||
u32 userClip : 2;
|
||||
u32 stripLen : 2;
|
||||
u32 parallelLight:1;
|
||||
u32 res_2 : 2;
|
||||
u32 groupEnable : 1;
|
||||
|
||||
// Para Control
|
||||
u32 listType : 3;
|
||||
u32 naomi2 : 1;
|
||||
u32 endOfStrip : 1;
|
||||
u32 paraType : 3;
|
||||
};
|
||||
u8 objectControl;
|
||||
u32 full;
|
||||
};
|
||||
|
||||
struct ElanBase
|
||||
{
|
||||
PCW pcw;
|
||||
};
|
||||
|
||||
struct Model : public ElanBase
|
||||
{
|
||||
// 08000800
|
||||
struct {
|
||||
u32 _res:27;
|
||||
u32 cwCulling:1;
|
||||
u32 openVolume:1;
|
||||
u32 _res0:3;
|
||||
} param;
|
||||
TSP tsp;
|
||||
u32 zero; // 0
|
||||
u32 offset;
|
||||
u32 one; // 1
|
||||
u32 size;
|
||||
u32 _res0; // 0
|
||||
};
|
||||
static_assert(sizeof(Model) % 32 == 0, "Invalid size for Model");
|
||||
|
||||
struct InstanceMatrix : public ElanBase
|
||||
{
|
||||
// 08000400
|
||||
u32 id1; // f
|
||||
u32 id2; // 7f
|
||||
u32 _res[5];
|
||||
|
||||
u32 _res1; // 08000200
|
||||
float envMapU; // env map U offset
|
||||
float lm00;
|
||||
float lm10;
|
||||
float lm20;
|
||||
float lm01;
|
||||
float lm11;
|
||||
float lm21;
|
||||
float lm02;
|
||||
float lm12;
|
||||
float lm22;
|
||||
float envMapV; // env map V offset
|
||||
float _res2[4];
|
||||
|
||||
u32 _res3; // 08000100
|
||||
float _near;
|
||||
float tm00;
|
||||
float tm01;
|
||||
float tm02;
|
||||
float tm10;
|
||||
float tm11;
|
||||
float tm12;
|
||||
float tm20;
|
||||
float tm21;
|
||||
float tm22;
|
||||
float tm30;
|
||||
float tm31;
|
||||
float tm32;
|
||||
float _far;
|
||||
float mproj6; // 1 / near
|
||||
|
||||
bool isInstanceMatrix() const {
|
||||
return id1 == 0xf && id2 == 0x7f;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(InstanceMatrix) % 32 == 0, "Invalid size for InstanceMatrix");
|
||||
|
||||
struct ProjMatrix : public ElanBase
|
||||
{
|
||||
// 08000300
|
||||
u32 _res;
|
||||
float fx, tx;
|
||||
float fy, ty;
|
||||
u32 _res0[2];
|
||||
};
|
||||
static_assert(sizeof(ProjMatrix) % 32 == 0, "Invalid size for ProjMatrix");
|
||||
|
||||
// Global Model Parameters
|
||||
struct GMP : public ElanBase
|
||||
{
|
||||
// 08000500
|
||||
struct {
|
||||
u32 frac0:5;
|
||||
u32 exp0:3;
|
||||
u32 frac1:5;
|
||||
u32 exp1:3;
|
||||
|
||||
float getCoef0() {
|
||||
return pow(2.f, exp0 - 1.f) * (1 + (float)frac0 / 32);
|
||||
}
|
||||
float getCoef1() {
|
||||
return pow(2.f, exp1 - 1.f) * (1 + (float)frac1 / 32);
|
||||
}
|
||||
} gloss;
|
||||
union {
|
||||
struct {
|
||||
u32 d0:1; // diffuse
|
||||
u32 s0:1; // specular
|
||||
u32 a0:1; // alpha?
|
||||
u32 f0:1; // fog?
|
||||
|
||||
u32 d1:1;
|
||||
u32 s1:1;
|
||||
u32 a1:1;
|
||||
u32 f1:1;
|
||||
|
||||
u32 vol1UsesVol0UV:1;
|
||||
u32 b0:1; // constant color
|
||||
u32 b1:1;
|
||||
u32 e0:1; // environmental mapping
|
||||
u32 e1:1;
|
||||
|
||||
u32 _res:19;
|
||||
};
|
||||
u32 full;
|
||||
} paramSelect;
|
||||
// (e=env)
|
||||
// ee000 1111 1111 specular, lambert
|
||||
// ee110 0000 0000 vertex color
|
||||
// ee110 1111 1111 constant
|
||||
// 00000 1111 1111 bump shading?
|
||||
|
||||
// seen:
|
||||
// 00110 1111 1111 (b0 and b1 set)
|
||||
// 11000 1111 1111 (e0 and e1 set, followed by vtx type2 (vtx only))
|
||||
// 11110 1111 1111 (everything! except v1uv0, rt66, vtx type2 (vtx only))
|
||||
// 00110 0000 0000 (b0 and b1, vf4)
|
||||
// 00000 1010 1010 specular and fog? soul surfer
|
||||
// 00010 0010 0010 b0, s0 s1 (initd, headlights)
|
||||
// 00010 1111 1111 2-volume (clubk2k3 road surface)
|
||||
|
||||
u32 diffuse0;
|
||||
u32 specular0;
|
||||
u32 diffuse1;
|
||||
u32 specular1;
|
||||
u32 _reserved;
|
||||
u32 _reserved0;
|
||||
u32 tex0;
|
||||
u32 _reserved1;
|
||||
u32 pal0;
|
||||
u32 _reserved2;
|
||||
u32 tex1;
|
||||
u32 _reserved3;
|
||||
u32 pal1;
|
||||
};
|
||||
static_assert(sizeof(GMP) % 32 == 0, "Invalid size for GMP");
|
||||
|
||||
union HeaderAndNormal
|
||||
{
|
||||
struct {
|
||||
u32 nx:8;
|
||||
u32 ny:8;
|
||||
u32 nz:8;
|
||||
|
||||
u32 _res:5;
|
||||
u32 strip:1;
|
||||
u32 fan:1;
|
||||
u32 endOfStrip:1;
|
||||
};
|
||||
u32 full;
|
||||
|
||||
bool isFirstOrSecond() const { return strip == 0 && fan == 0; }
|
||||
bool isThird() const { return strip == 1 && fan == 1; }
|
||||
bool isFan() const { return strip == 0 && fan == 1; }
|
||||
bool isStrip() const { return strip == 1 && fan == 0; }
|
||||
};
|
||||
|
||||
struct N2_VERTEX
|
||||
{
|
||||
HeaderAndNormal header;
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
};
|
||||
|
||||
struct Normal
|
||||
{
|
||||
float nx;
|
||||
float ny;
|
||||
float nz;
|
||||
u32 _reserved;
|
||||
};
|
||||
|
||||
struct UnpackedUV
|
||||
{
|
||||
float u;
|
||||
float v;
|
||||
};
|
||||
|
||||
struct PackedUV
|
||||
{
|
||||
u32 uv0;
|
||||
u32 uv1;
|
||||
};
|
||||
|
||||
struct PackedRGB
|
||||
{
|
||||
u32 argb0;
|
||||
u32 argb1;
|
||||
};
|
||||
|
||||
struct BumpMap
|
||||
{
|
||||
struct {
|
||||
u8 bumpDegree;
|
||||
u8 fixedOffset;
|
||||
u8 _res[2];
|
||||
} scaleFactor;
|
||||
// Normal vectors
|
||||
struct {
|
||||
int8_t x;
|
||||
int8_t y;
|
||||
int8_t z;
|
||||
u8 _res;
|
||||
} tangent;
|
||||
struct {
|
||||
int8_t x;
|
||||
int8_t y;
|
||||
int8_t z;
|
||||
u8 _res;
|
||||
} bitangent;
|
||||
u32 _res;
|
||||
};
|
||||
|
||||
//
|
||||
// textured, 1 or 2 para
|
||||
//
|
||||
struct N2_VERTEX_VU : public N2_VERTEX
|
||||
{
|
||||
UnpackedUV uv;
|
||||
};
|
||||
|
||||
//
|
||||
// textured, 1 or 2 para with unpacked normal
|
||||
//
|
||||
struct N2_VERTEX_VNU : public N2_VERTEX
|
||||
{
|
||||
Normal normal;
|
||||
UnpackedUV uv;
|
||||
};
|
||||
|
||||
//
|
||||
// for colored vertex, 1 para
|
||||
//
|
||||
struct N2_VERTEX_VUR : public N2_VERTEX
|
||||
{
|
||||
UnpackedUV uv;
|
||||
PackedRGB rgb;
|
||||
};
|
||||
|
||||
//
|
||||
// for bumpmapped, 1 para
|
||||
//
|
||||
struct N2_VERTEX_VUB : public N2_VERTEX
|
||||
{
|
||||
UnpackedUV uv;
|
||||
BumpMap bump;
|
||||
};
|
||||
|
||||
struct N2_VERTEX_VR : public N2_VERTEX
|
||||
{
|
||||
PackedRGB rgb;
|
||||
};
|
||||
|
||||
struct ICHList : public ElanBase
|
||||
{
|
||||
enum {
|
||||
VTX_TYPE_V = 0x00000002,
|
||||
VTX_TYPE_VU = 0x0000000A,
|
||||
VTX_TYPE_VNU = 0x0000000E,
|
||||
VTX_TYPE_VR = 0X00000042,
|
||||
VTX_TYPE_VUR = 0x0000004A,
|
||||
VTX_TYPE_VUB = 0x0000010A,
|
||||
};
|
||||
|
||||
// 08000700
|
||||
ISP_TSP isp;
|
||||
TSP tsp0;
|
||||
TCW tcw0;
|
||||
TSP tsp1;
|
||||
TCW tcw1;
|
||||
u32 flags;
|
||||
u32 vtxCount;
|
||||
|
||||
u32 vertexSize() const
|
||||
{
|
||||
switch (flags)
|
||||
{
|
||||
case VTX_TYPE_V: return sizeof(N2_VERTEX);
|
||||
case VTX_TYPE_VU: return sizeof(N2_VERTEX_VU);
|
||||
case VTX_TYPE_VNU: return sizeof(N2_VERTEX_VNU);
|
||||
case VTX_TYPE_VR: return sizeof(N2_VERTEX_VR);
|
||||
case VTX_TYPE_VUR: return sizeof(N2_VERTEX_VUR);
|
||||
case VTX_TYPE_VUB: return sizeof(N2_VERTEX_VUB);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(ICHList) % 32 == 0, "Invalid size for ICHList");
|
||||
|
||||
struct RegisterWait : public ElanBase
|
||||
{
|
||||
// 08000e00
|
||||
u32 offset; // -1
|
||||
u32 _res; // d, or 1080000d when waiting for ta reg
|
||||
u32 mask; // 0
|
||||
u32 _res0[4];
|
||||
};
|
||||
static_assert(sizeof(RegisterWait) % 32 == 0, "Invalid size for RegisterWait");
|
||||
|
||||
struct Link : public ElanBase
|
||||
{
|
||||
// 08000f00
|
||||
u32 offset;
|
||||
u32 vramAddress; // for texture DMA xfers, otherwise 09000000
|
||||
u32 size;
|
||||
u32 _res0[4];
|
||||
};
|
||||
static_assert(sizeof(Link) % 32 == 0, "Invalid size for Link");
|
||||
|
||||
constexpr size_t MAX_LIGHTS = 16;
|
||||
|
||||
struct LightModel : public ElanBase
|
||||
{
|
||||
// 08000400
|
||||
struct {
|
||||
u32 zero:4;
|
||||
u32 lightFlag:1;
|
||||
u32 useAmbientBase0:1; // When on, ambient color is multiplied with vertex color.
|
||||
u32 useAmbientOffset0:1;// Otherwise it's added to the diffuse/offset color as is.
|
||||
u32 useAmbientBase1:1; // Same for volume1
|
||||
u32 useAmbientOffset1:1;
|
||||
u32 useBaseOver:1; // diffusion saturated light: overflow ambient+diffuse into specular
|
||||
|
||||
u32 _res:2;
|
||||
u32 bumpId1:4;
|
||||
u32 bumpId2:4;
|
||||
u32 _res0:12;
|
||||
};
|
||||
u16 diffuseMask0;
|
||||
u16 specularMask0;
|
||||
u32 ambientBase0;
|
||||
u32 ambientOffset0;
|
||||
u16 diffuseMask1;
|
||||
u16 specularMask1;
|
||||
u32 ambientBase1;
|
||||
u32 ambientOffset1;
|
||||
|
||||
bool isDiffuse(int lightId, int volume) const {
|
||||
if (volume == 0)
|
||||
return (diffuseMask0 & (1 << lightId)) != 0;
|
||||
else
|
||||
return (diffuseMask1 & (1 << lightId)) != 0;
|
||||
}
|
||||
|
||||
bool isSpecular(int lightId, int volume) const {
|
||||
if (volume == 0)
|
||||
return (specularMask0 & (1 << lightId)) != 0;
|
||||
else
|
||||
return (specularMask1 & (1 << lightId)) != 0;
|
||||
}
|
||||
};
|
||||
|
||||
// dmode, smode
|
||||
enum {
|
||||
// diffuse and specular
|
||||
N2_LMETHOD_SINGLE_SIDED,
|
||||
N2_LMETHOD_DOUBLE_SIDED,
|
||||
N2_LMETHOD_DOUBLE_SIDED_WITH_TOLERANCE,
|
||||
N2_LMETHOD_SPECIAL_EFFECT,
|
||||
// diffuse only
|
||||
N2_LMETHOD_THIN_SURFACE,
|
||||
N2_LMETHOD_BUMP_MAP
|
||||
};
|
||||
|
||||
// routing
|
||||
enum {
|
||||
N2_LFUNC_BASEDIFF_BASESPEC_ADD,
|
||||
N2_LFUNC_BASEDIFF_OFFSSPEC_ADD,
|
||||
N2_LFUNC_OFFSDIFF_BASESPEC_ADD,
|
||||
N2_LFUNC_OFFSDIFF_OFFSSPEC_ADD,
|
||||
N2_LFUNC_ALPHADIFF_ADD,
|
||||
N2_LFUNC_ALPHAATTEN_ADD,
|
||||
N2_LFUNC_FOGDIFF_ADD,
|
||||
N2_LFUNC_FOGATTENUATION_ADD,
|
||||
N2_LFUNC_BASEDIFF_BASESPEC_SUB,
|
||||
N2_LFUNC_BASEDIFF_OFFSSPEC_SUB,
|
||||
N2_LFUNC_OFFSDIFF_BASESPEC_SUB,
|
||||
N2_LFUNC_OFFSDIFF_OFFSSPEC_SUB,
|
||||
N2_LFUNC_ALPHADIFF_SUB,
|
||||
N2_LFUNC_ALPHAATTEN_SUB,
|
||||
N2_LFUNC_FOGDIFF_SUB,
|
||||
N2_LFUNC_FOGATTEN_SUB,
|
||||
};
|
||||
|
||||
struct ParallelLight : public ElanBase
|
||||
{
|
||||
// 08100400
|
||||
struct {
|
||||
u32 lightId:4;
|
||||
u32 _res:4;
|
||||
u32 blue:8;
|
||||
u32 green:8;
|
||||
u32 red:8;
|
||||
};
|
||||
struct {
|
||||
u32 dirZ:8;
|
||||
u32 dirY:8;
|
||||
u32 dirX:8;
|
||||
|
||||
u32 routing:4;
|
||||
u32 dmode:2;
|
||||
u32 _res1:2;
|
||||
};
|
||||
u32 _res2[5];
|
||||
|
||||
float getDirX() const {
|
||||
return (((int8_t)dirX << 4) | (int)((pcw.full >> 16) & 0xf)) / 2047.f;
|
||||
}
|
||||
float getDirY() const {
|
||||
return (((int8_t)dirY << 4) | (int)((pcw.full >> 4) & 0xf)) / 2047.f;
|
||||
}
|
||||
float getDirZ() const {
|
||||
return (((int8_t)dirZ << 4) | (int)((pcw.full >> 0) & 0xf)) / 2047.f;
|
||||
}
|
||||
};
|
||||
|
||||
struct PointLight : public ElanBase
|
||||
{
|
||||
// 08000400
|
||||
struct {
|
||||
u32 lightId:4;
|
||||
u32 _res:1;
|
||||
u32 dmode:3;
|
||||
u32 blue:8;
|
||||
u32 green:8;
|
||||
u32 red:8;
|
||||
};
|
||||
struct {
|
||||
u32 dirZ:8;
|
||||
u32 dirY:8;
|
||||
u32 dirX:8;
|
||||
|
||||
u32 routing:4;
|
||||
u32 smode:2;
|
||||
u32 one:1;
|
||||
u32 dattenmode:1;
|
||||
};
|
||||
float posX;
|
||||
float posY;
|
||||
float posZ;
|
||||
u16 _distA;
|
||||
u16 _distB;
|
||||
u16 _angleA;
|
||||
u16 _angleB;
|
||||
|
||||
float getDirX() const {
|
||||
return (((int8_t)dirX << 4) | (int)((pcw.full >> 16) & 0xf)) / 2047.f;
|
||||
}
|
||||
float getDirY() const {
|
||||
return (((int8_t)dirY << 4) | (int)((pcw.full >> 4) & 0xf)) / 2047.f;
|
||||
}
|
||||
float getDirZ() const {
|
||||
return (((int8_t)dirZ << 4) | (int)((pcw.full >> 0) & 0xf)) / 2047.f;
|
||||
}
|
||||
|
||||
static float f16tof32(u16 v)
|
||||
{
|
||||
u32 z = v << 16;
|
||||
return (float&)z;
|
||||
}
|
||||
|
||||
float distA() const { return f16tof32(_distA); }
|
||||
float distB() const { return f16tof32(_distB); }
|
||||
float angleA() const { return f16tof32(_angleA); }
|
||||
float angleB() const { return f16tof32(_angleB); }
|
||||
|
||||
float attnMinDistance() const {
|
||||
return -distB() / (distA() - 1);
|
||||
}
|
||||
|
||||
float attnMaxDistance() const {
|
||||
return -distB() / distA();
|
||||
}
|
||||
|
||||
float attnDist(float dist) const {
|
||||
float rv;
|
||||
if (dattenmode)
|
||||
rv = distB() * dist + distA();
|
||||
else
|
||||
rv = distB() / dist + distA();
|
||||
return std::max(0.f, std::min(1.f, rv));
|
||||
}
|
||||
|
||||
bool isAttnDist() const {
|
||||
return distA() != 1 || distB() != 0;
|
||||
}
|
||||
|
||||
bool isAttnAngle() const {
|
||||
return angleA() != 1 || angleB() != 0;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "rend/TexCache.h"
|
||||
#include "serialize.h"
|
||||
#include "pvr_mem.h"
|
||||
#include "elan.h"
|
||||
|
||||
// ta.cpp
|
||||
extern u8 ta_fsm[2049]; //[2048] stores the current state
|
||||
@@ -43,17 +44,21 @@ void reset(bool hard)
|
||||
if (hard)
|
||||
rend_reset();
|
||||
tactx_Term();
|
||||
elan::reset(hard);
|
||||
ta_parse_reset();
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
spg_Init();
|
||||
elan::init();
|
||||
}
|
||||
|
||||
void term()
|
||||
{
|
||||
tactx_Term();
|
||||
spg_Term();
|
||||
elan::term();
|
||||
}
|
||||
|
||||
void serialize(Serializer& ser)
|
||||
@@ -72,6 +77,7 @@ void serialize(Serializer& ser)
|
||||
|
||||
if (!ser.rollback())
|
||||
ser.serialize(vram.data, vram.size);
|
||||
elan::serialize(ser);
|
||||
}
|
||||
|
||||
void deserialize(Deserializer& deser)
|
||||
@@ -135,6 +141,7 @@ void deserialize(Deserializer& deser)
|
||||
|
||||
if (!deser.rollback())
|
||||
deser.deserialize(vram.data, vram.size);
|
||||
elan::deserialize(deser);
|
||||
pal_needs_update = true;
|
||||
}
|
||||
|
||||
|
||||
+105
-1
@@ -3,20 +3,124 @@
|
||||
#include "Renderer_if.h"
|
||||
#include "ta.h"
|
||||
#include "spg.h"
|
||||
#include <map>
|
||||
|
||||
bool pal_needs_update=true;
|
||||
bool fog_needs_update=true;
|
||||
|
||||
u8 pvr_regs[pvr_RegSize];
|
||||
|
||||
#define PVR_REG_NAME(r) { r##_addr, #r },
|
||||
const std::map<u32, const char *> pvr_reg_names = {
|
||||
PVR_REG_NAME(ID)
|
||||
PVR_REG_NAME(REVISION)
|
||||
PVR_REG_NAME(SOFTRESET)
|
||||
PVR_REG_NAME(STARTRENDER)
|
||||
PVR_REG_NAME(TEST_SELECT)
|
||||
PVR_REG_NAME(PARAM_BASE)
|
||||
PVR_REG_NAME(REGION_BASE)
|
||||
PVR_REG_NAME(SPAN_SORT_CFG)
|
||||
PVR_REG_NAME(VO_BORDER_COL)
|
||||
PVR_REG_NAME(FB_R_CTRL)
|
||||
PVR_REG_NAME(FB_W_CTRL)
|
||||
PVR_REG_NAME(FB_W_LINESTRIDE)
|
||||
PVR_REG_NAME(FB_R_SOF1)
|
||||
PVR_REG_NAME(FB_R_SOF2)
|
||||
PVR_REG_NAME(FB_R_SIZE)
|
||||
PVR_REG_NAME(FB_W_SOF1)
|
||||
PVR_REG_NAME(FB_W_SOF2)
|
||||
PVR_REG_NAME(FB_X_CLIP)
|
||||
PVR_REG_NAME(FB_Y_CLIP)
|
||||
PVR_REG_NAME(FPU_SHAD_SCALE)
|
||||
PVR_REG_NAME(FPU_CULL_VAL)
|
||||
PVR_REG_NAME(FPU_PARAM_CFG)
|
||||
PVR_REG_NAME(HALF_OFFSET)
|
||||
PVR_REG_NAME(FPU_PERP_VAL)
|
||||
PVR_REG_NAME(ISP_BACKGND_D)
|
||||
PVR_REG_NAME(ISP_BACKGND_T)
|
||||
PVR_REG_NAME(ISP_FEED_CFG)
|
||||
PVR_REG_NAME(SDRAM_REFRESH)
|
||||
PVR_REG_NAME(SDRAM_ARB_CFG)
|
||||
PVR_REG_NAME(SDRAM_CFG)
|
||||
PVR_REG_NAME(FOG_COL_RAM)
|
||||
PVR_REG_NAME(FOG_COL_VERT)
|
||||
PVR_REG_NAME(FOG_DENSITY)
|
||||
PVR_REG_NAME(FOG_CLAMP_MAX)
|
||||
PVR_REG_NAME(FOG_CLAMP_MIN)
|
||||
PVR_REG_NAME(SPG_TRIGGER_POS)
|
||||
PVR_REG_NAME(SPG_HBLANK_INT)
|
||||
PVR_REG_NAME(SPG_VBLANK_INT)
|
||||
PVR_REG_NAME(SPG_CONTROL)
|
||||
PVR_REG_NAME(SPG_HBLANK)
|
||||
PVR_REG_NAME(SPG_LOAD)
|
||||
PVR_REG_NAME(SPG_VBLANK)
|
||||
PVR_REG_NAME(SPG_WIDTH)
|
||||
PVR_REG_NAME(TEXT_CONTROL)
|
||||
PVR_REG_NAME(VO_CONTROL)
|
||||
PVR_REG_NAME(VO_STARTX)
|
||||
PVR_REG_NAME(VO_STARTY)
|
||||
PVR_REG_NAME(SCALER_CTL)
|
||||
PVR_REG_NAME(PAL_RAM_CTRL)
|
||||
PVR_REG_NAME(SPG_STATUS)
|
||||
PVR_REG_NAME(FB_BURSTCTRL)
|
||||
PVR_REG_NAME(FB_C_SOF)
|
||||
PVR_REG_NAME(Y_COEFF)
|
||||
PVR_REG_NAME(PT_ALPHA_REF)
|
||||
PVR_REG_NAME(TA_OL_BASE)
|
||||
PVR_REG_NAME(TA_ISP_BASE)
|
||||
PVR_REG_NAME(TA_OL_LIMIT)
|
||||
PVR_REG_NAME(TA_ISP_LIMIT)
|
||||
PVR_REG_NAME(TA_NEXT_OPB)
|
||||
PVR_REG_NAME(TA_ITP_CURRENT)
|
||||
PVR_REG_NAME(TA_GLOB_TILE_CLIP)
|
||||
PVR_REG_NAME(TA_ALLOC_CTRL)
|
||||
PVR_REG_NAME(TA_LIST_INIT)
|
||||
PVR_REG_NAME(TA_YUV_TEX_BASE)
|
||||
PVR_REG_NAME(TA_YUV_TEX_CTRL)
|
||||
PVR_REG_NAME(TA_YUV_TEX_CNT)
|
||||
PVR_REG_NAME(TA_LIST_CONT)
|
||||
PVR_REG_NAME(TA_NEXT_OPB_INIT)
|
||||
PVR_REG_NAME(SIGNATURE1)
|
||||
PVR_REG_NAME(SIGNATURE2)
|
||||
};
|
||||
#undef PVR_REG_NAME
|
||||
|
||||
static const char *regName(u32 paddr)
|
||||
{
|
||||
u32 addr = paddr & pvr_RegMask;
|
||||
static char regName[32];
|
||||
auto it = pvr_reg_names.find(addr);
|
||||
if (it == pvr_reg_names.end())
|
||||
{
|
||||
if (addr >= FOG_TABLE_START_addr && addr <= FOG_TABLE_END_addr)
|
||||
sprintf(regName, "FOG_TABLE[%x]", addr - FOG_TABLE_START_addr);
|
||||
else if (addr >= TA_OL_POINTERS_START_addr && addr <= TA_OL_POINTERS_END_addr)
|
||||
sprintf(regName, "TA_OL_POINTERS[%x]", addr - TA_OL_POINTERS_START_addr);
|
||||
else if (addr >= PALETTE_RAM_START_addr && addr <= PALETTE_RAM_END_addr)
|
||||
sprintf(regName, "PALETTE[%x]", addr - PALETTE_RAM_START_addr);
|
||||
else
|
||||
sprintf(regName, "?%08x", paddr);
|
||||
return regName;
|
||||
}
|
||||
else
|
||||
return it->second;
|
||||
}
|
||||
|
||||
u32 pvr_ReadReg(u32 addr)
|
||||
{
|
||||
if ((addr & pvr_RegMask) != SPG_STATUS_addr)
|
||||
DEBUG_LOG(PVR, "read %s.%c == %x", regName(addr),
|
||||
((addr >> 26) & 7) == 2 ? 'b' : (addr & 0x2000000) ? '1' : '0',
|
||||
PvrReg(addr, u32));
|
||||
return PvrReg(addr,u32);
|
||||
}
|
||||
|
||||
void pvr_WriteReg(u32 paddr,u32 data)
|
||||
{
|
||||
u32 addr = paddr & pvr_RegMask;
|
||||
DEBUG_LOG(PVR, "write %s.%c = %x", regName(paddr),
|
||||
((paddr >> 26) & 7) == 2 ? 'b' : (paddr & 0x2000000) ? '1' : '0',
|
||||
data);
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
@@ -46,7 +150,7 @@ void pvr_WriteReg(u32 paddr,u32 data)
|
||||
|
||||
case TA_LIST_CONT_addr:
|
||||
//a write of anything works ?
|
||||
ta_vtx_ListCont();
|
||||
ta_vtx_ListInit();
|
||||
break;
|
||||
|
||||
case SPG_CONTROL_addr:
|
||||
|
||||
@@ -471,7 +471,8 @@ union FOG_DENSITY_type
|
||||
#define TA_LIST_CONT_addr 0x00000160 // RW TA continuation processing
|
||||
#define TA_NEXT_OPB_INIT_addr 0x00000164 // RW Additional OPB starting address
|
||||
|
||||
|
||||
#define SIGNATURE1_addr 0x00000180 // ?
|
||||
#define SIGNATURE2_addr 0x00000184 // ?
|
||||
|
||||
#define FOG_TABLE_START_addr 0x00000200 // RW Look-up table Fog data
|
||||
#define FOG_TABLE_END_addr 0x000003FC
|
||||
@@ -575,7 +576,3 @@ union FOG_DENSITY_type
|
||||
#define FOG_TABLE (&PvrReg(FOG_TABLE_START_addr,u32)) // RW Look-up table Fog data
|
||||
#define TA_OL_POINTERS (&PvrReg(TA_OL_POINTERS_START_addr),u32) // R TA object List Pointer data
|
||||
#define PALETTE_RAM (&PvrReg(PALETTE_RAM_START_addr,u32)) // RW Palette RAM
|
||||
|
||||
|
||||
#define TA_CURRENT_CTX (TA_ISP_BASE & 0xF00000)
|
||||
#define CORE_CURRENT_CTX (PARAM_BASE & 0xF00000)
|
||||
+15
-3
@@ -255,6 +255,9 @@ int spg_line_sched(int tag, int cycl, int jit)
|
||||
if (lightgun_line != 0xffff && min_scanline < lightgun_line)
|
||||
min_active = std::min(min_active, lightgun_line);
|
||||
|
||||
if (SPG_HBLANK_INT.hblank_int_mode == 0 && min_scanline < SPG_HBLANK_INT.line_comp_val)
|
||||
min_active = std::min(min_active, SPG_HBLANK_INT.line_comp_val);
|
||||
|
||||
min_active = std::max(min_active,min_scanline);
|
||||
|
||||
return (min_active - prv_cur_scanline) * Line_Cycles;
|
||||
@@ -280,9 +283,18 @@ void read_lightgun_position(int x, int y)
|
||||
|
||||
int rend_end_sch(int tag, int cycl, int jitt)
|
||||
{
|
||||
asic_RaiseInterrupt(holly_RENDER_DONE);
|
||||
asic_RaiseInterrupt(holly_RENDER_DONE_isp);
|
||||
asic_RaiseInterrupt(holly_RENDER_DONE_vd);
|
||||
if (settings.platform.isNaomi2())
|
||||
{
|
||||
asic_RaiseInterruptBothCLX(holly_RENDER_DONE);
|
||||
asic_RaiseInterruptBothCLX(holly_RENDER_DONE_isp);
|
||||
asic_RaiseInterruptBothCLX(holly_RENDER_DONE_vd);
|
||||
}
|
||||
else
|
||||
{
|
||||
asic_RaiseInterrupt(holly_RENDER_DONE);
|
||||
asic_RaiseInterrupt(holly_RENDER_DONE_isp);
|
||||
asic_RaiseInterrupt(holly_RENDER_DONE_vd);
|
||||
}
|
||||
rend_end_render();
|
||||
return 0;
|
||||
}
|
||||
|
||||
+241
-10
@@ -1,6 +1,7 @@
|
||||
#include "ta.h"
|
||||
#include "ta_ctx.h"
|
||||
#include "hw/holly/holly_intc.h"
|
||||
#include "pvr_mem.h"
|
||||
|
||||
/*
|
||||
Threaded TA Implementation
|
||||
@@ -223,7 +224,10 @@ static NOINLINE void DYNACALL ta_handle_cmd(u32 trans)
|
||||
ta_fsm_cl=dat->pcw.ListType;
|
||||
//printf("List %d ended\n",ta_fsm_cl);
|
||||
|
||||
asic_RaiseInterrupt( ListEndInterrupt[ta_fsm_cl]);
|
||||
if (settings.platform.isNaomi2())
|
||||
asic_RaiseInterruptBothCLX(ListEndInterrupt[ta_fsm_cl]);
|
||||
else
|
||||
asic_RaiseInterrupt(ListEndInterrupt[ta_fsm_cl]);
|
||||
ta_fsm_cl=7;
|
||||
trans=TAS_NS;
|
||||
}
|
||||
@@ -259,25 +263,252 @@ static NOINLINE void DYNACALL ta_handle_cmd(u32 trans)
|
||||
|
||||
static OnLoad ol_fillfsm(&fill_fsm);
|
||||
|
||||
void ta_vtx_ListCont()
|
||||
{
|
||||
SetCurrentTARC(TA_CURRENT_CTX);
|
||||
ta_tad.Continue();
|
||||
/*
|
||||
Volume,Col_Type,Texture,Offset,Gouraud,16bit_UV
|
||||
|
||||
ta_cur_state=TAS_NS;
|
||||
ta_fsm_cl = 7;
|
||||
0 0 0 (0) x invalid Polygon Type 0 Polygon Type 0
|
||||
0 0 1 x x 0 Polygon Type 0 Polygon Type 3
|
||||
0 0 1 x x 1 Polygon Type 0 Polygon Type 4
|
||||
|
||||
0 1 0 (0) x invalid Polygon Type 0 Polygon Type 1
|
||||
0 1 1 x x 0 Polygon Type 0 Polygon Type 5
|
||||
0 1 1 x x 1 Polygon Type 0 Polygon Type 6
|
||||
|
||||
0 2 0 (0) x invalid Polygon Type 1 Polygon Type 2
|
||||
0 2 1 0 x 0 Polygon Type 1 Polygon Type 7
|
||||
0 2 1 0 x 1 Polygon Type 1 Polygon Type 8
|
||||
0 2 1 1 x 0 Polygon Type 2 Polygon Type 7
|
||||
0 2 1 1 x 1 Polygon Type 2 Polygon Type 8
|
||||
|
||||
0 3 0 (0) x invalid Polygon Type 0 Polygon Type 2
|
||||
0 3 1 x x 0 Polygon Type 0 Polygon Type 7
|
||||
0 3 1 x x 1 Polygon Type 0 Polygon Type 8
|
||||
|
||||
1 0 0 (0) x invalid Polygon Type 3 Polygon Type 9
|
||||
1 0 1 x x 0 Polygon Type 3 Polygon Type 11
|
||||
1 0 1 x x 1 Polygon Type 3 Polygon Type 12
|
||||
|
||||
1 2 0 (0) x invalid Polygon Type 4 Polygon Type 10
|
||||
1 2 1 x x 0 Polygon Type 4 Polygon Type 13
|
||||
1 2 1 x x 1 Polygon Type 4 Polygon Type 14
|
||||
|
||||
1 3 0 (0) x invalid Polygon Type 3 Polygon Type 10
|
||||
1 3 1 x x 0 Polygon Type 3 Polygon Type 13
|
||||
1 3 1 x x 1 Polygon Type 3 Polygon Type 14
|
||||
|
||||
Sprites :
|
||||
(0) (0) 0 (0) (0) invalid Sprite Sprite Type 0
|
||||
(0) (0) 1 x (0) (1) Sprite Sprite Type 1
|
||||
|
||||
*/
|
||||
//helpers 0-14
|
||||
u32 TaTypeLut::poly_data_type_id(PCW pcw)
|
||||
{
|
||||
if (pcw.Texture)
|
||||
{
|
||||
//textured
|
||||
if (pcw.Volume==0)
|
||||
{ //single volume
|
||||
if (pcw.Col_Type==0)
|
||||
{
|
||||
if (pcw.UV_16bit==0)
|
||||
return 3; //(Textured, Packed Color , 32b uv)
|
||||
else
|
||||
return 4; //(Textured, Packed Color , 16b uv)
|
||||
}
|
||||
else if (pcw.Col_Type==1)
|
||||
{
|
||||
if (pcw.UV_16bit==0)
|
||||
return 5; //(Textured, Floating Color , 32b uv)
|
||||
else
|
||||
return 6; //(Textured, Floating Color , 16b uv)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pcw.UV_16bit==0)
|
||||
return 7; //(Textured, Intensity , 32b uv)
|
||||
else
|
||||
return 8; //(Textured, Intensity , 16b uv)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//two volumes
|
||||
if (pcw.Col_Type==0)
|
||||
{
|
||||
if (pcw.UV_16bit==0)
|
||||
return 11; //(Textured, Packed Color, with Two Volumes)
|
||||
|
||||
else
|
||||
return 12; //(Textured, Packed Color, 16bit UV, with Two Volumes)
|
||||
|
||||
}
|
||||
else if (pcw.Col_Type==1)
|
||||
{
|
||||
//die ("invalid");
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pcw.UV_16bit==0)
|
||||
return 13; //(Textured, Intensity, with Two Volumes)
|
||||
|
||||
else
|
||||
return 14; //(Textured, Intensity, 16bit UV, with Two Volumes)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//non textured
|
||||
if (pcw.Volume==0)
|
||||
{ //single volume
|
||||
if (pcw.Col_Type==0)
|
||||
return 0; //(Non-Textured, Packed Color)
|
||||
else if (pcw.Col_Type==1)
|
||||
return 1; //(Non-Textured, Floating Color)
|
||||
else
|
||||
return 2; //(Non-Textured, Intensity)
|
||||
}
|
||||
else
|
||||
{
|
||||
//two volumes
|
||||
if (pcw.Col_Type==0)
|
||||
return 9; //(Non-Textured, Packed Color, with Two Volumes)
|
||||
else if (pcw.Col_Type==1)
|
||||
{
|
||||
//die ("invalid");
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 10; //(Non-Textured, Intensity, with Two Volumes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//0-4 | 0x80
|
||||
u32 TaTypeLut::poly_header_type_size(PCW pcw)
|
||||
{
|
||||
if (pcw.Volume == 0)
|
||||
{
|
||||
if ( pcw.Col_Type<2 ) //0,1
|
||||
{
|
||||
return 0 | 0; //Polygon Type 0 -- SZ32
|
||||
}
|
||||
else if ( pcw.Col_Type == 2 )
|
||||
{
|
||||
if (pcw.Texture)
|
||||
{
|
||||
if (pcw.Offset)
|
||||
{
|
||||
return 2 | 0x80; //Polygon Type 2 -- SZ64
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1 | 0; //Polygon Type 1 -- SZ32
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1 | 0; //Polygon Type 1 -- SZ32
|
||||
}
|
||||
}
|
||||
else //col_type ==3
|
||||
{
|
||||
return 0 | 0; //Polygon Type 0 -- SZ32
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( pcw.Col_Type==0 ) //0
|
||||
{
|
||||
return 3 | 0; //Polygon Type 3 -- SZ32
|
||||
}
|
||||
else if ( pcw.Col_Type==2 ) //2
|
||||
{
|
||||
return 4 | 0x80; //Polygon Type 4 -- SZ64
|
||||
}
|
||||
else if ( pcw.Col_Type==3 ) //3
|
||||
{
|
||||
return 3 | 0; //Polygon Type 3 -- SZ32
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0xFFDDEEAA;//die ("data->pcw.Col_Type==1 && volume ==1");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TaTypeLut::TaTypeLut()
|
||||
{
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
PCW pcw;
|
||||
pcw.obj_ctrl = i;
|
||||
u32 rv = poly_data_type_id(pcw);
|
||||
u32 type = poly_header_type_size(pcw);
|
||||
|
||||
if (type & 0x80)
|
||||
rv |= SZ64 << 30;
|
||||
else
|
||||
rv |= SZ32 << 30;
|
||||
|
||||
rv |= (type & 0x7F) << 8;
|
||||
|
||||
table[i] = rv;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 opbSize(int n)
|
||||
{
|
||||
return n == 0 ? 0 : 16 << n;
|
||||
}
|
||||
|
||||
static void markObjectListBlocks()
|
||||
{
|
||||
u32 addr = TA_OL_BASE;
|
||||
// opaque
|
||||
u32 opBlockSize = opbSize(TA_ALLOC_CTRL & 3);
|
||||
if (opBlockSize == 0)
|
||||
{
|
||||
// skip modvols OPBs
|
||||
addr += opbSize((TA_ALLOC_CTRL >> 4) & 3) * (TA_GLOB_TILE_CLIP.tile_y_num + 1) * (TA_GLOB_TILE_CLIP.tile_x_num + 1);
|
||||
// transparent
|
||||
opBlockSize = opbSize((TA_ALLOC_CTRL >> 8) & 3);
|
||||
if (opBlockSize == 0)
|
||||
{
|
||||
// skip TR modvols OPBs
|
||||
addr += opbSize((TA_ALLOC_CTRL >> 12) & 3) * (TA_GLOB_TILE_CLIP.tile_y_num + 1) * (TA_GLOB_TILE_CLIP.tile_x_num + 1);
|
||||
// punch-through
|
||||
opBlockSize = opbSize((TA_ALLOC_CTRL >> 16) & 3);
|
||||
if (opBlockSize == 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (int y = 0; y <= TA_GLOB_TILE_CLIP.tile_y_num; y++)
|
||||
for (int x = 0; x <= TA_GLOB_TILE_CLIP.tile_x_num; x++)
|
||||
{
|
||||
pvr_write32p(addr, TA_OL_BASE);
|
||||
addr += opBlockSize;
|
||||
}
|
||||
}
|
||||
|
||||
void ta_vtx_ListInit()
|
||||
{
|
||||
SetCurrentTARC(TA_CURRENT_CTX);
|
||||
SetCurrentTARC(TA_OL_BASE);
|
||||
ta_tad.ClearPartial();
|
||||
markObjectListBlocks();
|
||||
|
||||
ta_cur_state=TAS_NS;
|
||||
ta_cur_state = TAS_NS;
|
||||
ta_fsm_cl = 7;
|
||||
if (settings.platform.isNaomi2())
|
||||
ta_parse_reset();
|
||||
}
|
||||
|
||||
void ta_vtx_SoftReset()
|
||||
{
|
||||
ta_cur_state=TAS_NS;
|
||||
ta_cur_state = TAS_NS;
|
||||
}
|
||||
|
||||
static INLINE
|
||||
|
||||
+6
-2
@@ -3,16 +3,18 @@
|
||||
#include "ta_ctx.h"
|
||||
#include "hw/sh4/sh4_if.h"
|
||||
|
||||
constexpr u32 SZ32 = 1;
|
||||
constexpr u32 SZ64 = 2;
|
||||
|
||||
struct TA_context;
|
||||
|
||||
void ta_vtx_ListCont();
|
||||
void ta_vtx_ListInit();
|
||||
void ta_vtx_SoftReset();
|
||||
|
||||
void DYNACALL ta_vtx_data32(const SQBuffer *data);
|
||||
void ta_vtx_data(const SQBuffer *data, u32 size);
|
||||
|
||||
bool ta_parse_vdrc(TA_context *ctx, bool bgraColors = false);
|
||||
bool ta_parse(TA_context *ctx);
|
||||
|
||||
class TaTypeLut
|
||||
{
|
||||
@@ -25,4 +27,6 @@ public:
|
||||
|
||||
private:
|
||||
TaTypeLut();
|
||||
u32 poly_data_type_id(PCW pcw);
|
||||
u32 poly_header_type_size(PCW pcw);
|
||||
};
|
||||
+77
-77
@@ -11,8 +11,8 @@ static int RenderCount;
|
||||
TA_context* ta_ctx;
|
||||
tad_context ta_tad;
|
||||
|
||||
TA_context* vd_ctx;
|
||||
rend_context vd_rc;
|
||||
static void tactx_Recycle(TA_context* ctx);
|
||||
static TA_context *tactx_Find(u32 addr, bool allocnew = false);
|
||||
|
||||
void SetCurrentTARC(u32 addr)
|
||||
{
|
||||
@@ -106,62 +106,58 @@ static std::mutex mtx_pool;
|
||||
static std::vector<TA_context*> ctx_pool;
|
||||
static std::vector<TA_context*> ctx_list;
|
||||
|
||||
TA_context* tactx_Alloc()
|
||||
TA_context *tactx_Alloc()
|
||||
{
|
||||
TA_context* rv = 0;
|
||||
TA_context *ctx = nullptr;
|
||||
|
||||
mtx_pool.lock();
|
||||
if (!ctx_pool.empty())
|
||||
{
|
||||
rv = ctx_pool[ctx_pool.size()-1];
|
||||
ctx = ctx_pool.back();
|
||||
ctx_pool.pop_back();
|
||||
}
|
||||
mtx_pool.unlock();
|
||||
|
||||
if (!rv)
|
||||
{
|
||||
rv = new TA_context();
|
||||
rv->Alloc();
|
||||
}
|
||||
|
||||
return rv;
|
||||
if (ctx == nullptr)
|
||||
{
|
||||
ctx = new TA_context();
|
||||
ctx->Alloc();
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void tactx_Recycle(TA_context* poped_ctx)
|
||||
static void tactx_Recycle(TA_context* ctx)
|
||||
{
|
||||
if (ctx->nextContext != nullptr)
|
||||
tactx_Recycle(ctx->nextContext);
|
||||
mtx_pool.lock();
|
||||
if (ctx_pool.size() > 3)
|
||||
{
|
||||
if (ctx_pool.size()>2)
|
||||
{
|
||||
poped_ctx->Free();
|
||||
delete poped_ctx;
|
||||
}
|
||||
else
|
||||
{
|
||||
poped_ctx->Reset();
|
||||
ctx_pool.push_back(poped_ctx);
|
||||
}
|
||||
delete ctx;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->Reset();
|
||||
ctx_pool.push_back(ctx);
|
||||
}
|
||||
mtx_pool.unlock();
|
||||
}
|
||||
|
||||
TA_context* tactx_Find(u32 addr, bool allocnew)
|
||||
static TA_context *tactx_Find(u32 addr, bool allocnew)
|
||||
{
|
||||
for (size_t i=0; i<ctx_list.size(); i++)
|
||||
{
|
||||
if (ctx_list[i]->Address==addr)
|
||||
return ctx_list[i];
|
||||
}
|
||||
for (TA_context *ctx : ctx_list)
|
||||
if (ctx->Address == addr)
|
||||
return ctx;
|
||||
|
||||
if (allocnew)
|
||||
{
|
||||
TA_context* rv = tactx_Alloc();
|
||||
rv->Address=addr;
|
||||
ctx_list.push_back(rv);
|
||||
TA_context *ctx = tactx_Alloc();
|
||||
ctx->Address = addr;
|
||||
ctx_list.push_back(ctx);
|
||||
|
||||
return rv;
|
||||
return ctx;
|
||||
}
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TA_context* tactx_Pop(u32 addr)
|
||||
@@ -188,20 +184,13 @@ void tactx_Term()
|
||||
if (ta_ctx != nullptr)
|
||||
SetCurrentTARC(TACTX_NONE);
|
||||
|
||||
for (size_t i = 0; i < ctx_list.size(); i++)
|
||||
{
|
||||
ctx_list[i]->Free();
|
||||
delete ctx_list[i];
|
||||
}
|
||||
for (TA_context *ctx : ctx_list)
|
||||
delete ctx;
|
||||
ctx_list.clear();
|
||||
|
||||
mtx_pool.lock();
|
||||
{
|
||||
for (size_t i = 0; i < ctx_pool.size(); i++)
|
||||
{
|
||||
ctx_pool[i]->Free();
|
||||
delete ctx_pool[i];
|
||||
}
|
||||
}
|
||||
for (TA_context *ctx : ctx_pool)
|
||||
delete ctx;
|
||||
ctx_pool.clear();
|
||||
mtx_pool.unlock();
|
||||
}
|
||||
@@ -212,8 +201,8 @@ static void serializeContext(Serializer& ser, const TA_context *ctx)
|
||||
{
|
||||
if (ser.dryrun())
|
||||
{
|
||||
// Maximum size: address, size, data, render pass count, render passes
|
||||
ser.skip(4 + 4 + TA_DATA_SIZE + 4 + ARRAY_SIZE(tad_context::render_passes) * 4);
|
||||
// Maximum size: address, size, data
|
||||
ser.skip(4 + 4 + TA_DATA_SIZE);
|
||||
return;
|
||||
}
|
||||
if (ctx == nullptr)
|
||||
@@ -226,12 +215,6 @@ static void serializeContext(Serializer& ser, const TA_context *ctx)
|
||||
const u32 taSize = tad.thd_data - tad.thd_root;
|
||||
ser << taSize;
|
||||
ser.serialize(tad.thd_root, taSize);
|
||||
ser << tad.render_pass_count;
|
||||
for (u32 i = 0; i < tad.render_pass_count; i++)
|
||||
{
|
||||
u32 offset = (u32)(tad.render_passes[i] - tad.thd_root);
|
||||
ser << offset;
|
||||
}
|
||||
}
|
||||
|
||||
static void deserializeContext(Deserializer& deser, TA_context **pctx)
|
||||
@@ -249,39 +232,56 @@ static void deserializeContext(Deserializer& deser, TA_context **pctx)
|
||||
tad_context& tad = (*pctx)->tad;
|
||||
deser.deserialize(tad.thd_root, size);
|
||||
tad.thd_data = tad.thd_root + size;
|
||||
if (deser.version() >= Deserializer::V12 || (deser.version() >= Deserializer::V12_LIBRETRO && deser.version() < Deserializer::V5))
|
||||
if ((deser.version() >= Deserializer::V12 && deser.version() < Deserializer::V26)
|
||||
|| (deser.version() >= Deserializer::V12_LIBRETRO && deser.version() < Deserializer::V5))
|
||||
{
|
||||
deser >> tad.render_pass_count;
|
||||
for (u32 i = 0; i < tad.render_pass_count; i++)
|
||||
{
|
||||
u32 offset;
|
||||
deser >> offset;
|
||||
tad.render_passes[i] = tad.thd_root + offset;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tad.render_pass_count = 0;
|
||||
u32 render_pass_count;
|
||||
deser >> render_pass_count;
|
||||
deser.skip(sizeof(u32) * render_pass_count);
|
||||
}
|
||||
}
|
||||
|
||||
void SerializeTAContext(Serializer& ser)
|
||||
{
|
||||
serializeContext(ser, ta_ctx);
|
||||
if (TA_CURRENT_CTX != CORE_CURRENT_CTX)
|
||||
serializeContext(ser, tactx_Find(TA_CURRENT_CTX, false));
|
||||
else
|
||||
serializeContext(ser, nullptr);
|
||||
|
||||
ser << (u32)ctx_list.size();
|
||||
int curCtx = -1;
|
||||
for (const auto& ctx : ctx_list)
|
||||
{
|
||||
if (ctx == ::ta_ctx)
|
||||
curCtx = (int)(&ctx - &ctx_list[0]);
|
||||
serializeContext(ser, ctx);
|
||||
}
|
||||
ser << curCtx;
|
||||
}
|
||||
|
||||
void DeserializeTAContext(Deserializer& deser)
|
||||
{
|
||||
if (::ta_ctx != nullptr)
|
||||
SetCurrentTARC(TACTX_NONE);
|
||||
TA_context *ta_cur_ctx;
|
||||
deserializeContext(deser, &ta_cur_ctx);
|
||||
if (ta_cur_ctx != nullptr)
|
||||
SetCurrentTARC(ta_cur_ctx->Address);
|
||||
if (deser.version() >= Deserializer::V20)
|
||||
if (deser.version() >= Deserializer::V25)
|
||||
{
|
||||
u32 listSize;
|
||||
deser >> listSize;
|
||||
for (const auto& ctx : ctx_list)
|
||||
tactx_Recycle(ctx);
|
||||
ctx_list.clear();
|
||||
for (u32 i = 0; i < listSize; i++)
|
||||
{
|
||||
TA_context *ctx;
|
||||
deserializeContext(deser, &ctx);
|
||||
}
|
||||
int curCtx;
|
||||
deser >> curCtx;
|
||||
if (curCtx != -1)
|
||||
SetCurrentTARC(ctx_list[curCtx]->Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
TA_context *ta_cur_ctx;
|
||||
deserializeContext(deser, &ta_cur_ctx);
|
||||
if (ta_cur_ctx != nullptr)
|
||||
SetCurrentTARC(ta_cur_ctx->Address);
|
||||
if (deser.version() >= Deserializer::V20)
|
||||
deserializeContext(deser, &ta_cur_ctx);
|
||||
}
|
||||
}
|
||||
+173
-43
@@ -9,6 +9,7 @@
|
||||
#include <mutex>
|
||||
|
||||
class BaseTextureCacheData;
|
||||
struct N2LightModel;
|
||||
|
||||
//Vertex storage types
|
||||
struct Vertex
|
||||
@@ -25,6 +26,9 @@ struct Vertex
|
||||
u8 spc1[4];
|
||||
|
||||
float u1,v1;
|
||||
|
||||
// Naomi2 normal
|
||||
float nx,ny,nz;
|
||||
};
|
||||
|
||||
struct PolyParam
|
||||
@@ -33,9 +37,6 @@ struct PolyParam
|
||||
u32 count;
|
||||
|
||||
BaseTextureCacheData *texture;
|
||||
#if !defined(HOST_64BIT_CPU)
|
||||
u32 _pad0;
|
||||
#endif
|
||||
|
||||
TSP tsp;
|
||||
TCW tcw;
|
||||
@@ -47,9 +48,64 @@ struct PolyParam
|
||||
TSP tsp1;
|
||||
TCW tcw1;
|
||||
BaseTextureCacheData *texture1;
|
||||
#if !defined(HOST_64BIT_CPU)
|
||||
u32 _pad1;
|
||||
#endif
|
||||
|
||||
const float *mvMatrix;
|
||||
const float *normalMatrix;
|
||||
const float *projMatrix;
|
||||
float glossCoef[2];
|
||||
const N2LightModel *lightModel;
|
||||
bool envMapping[2];
|
||||
bool constantColor[2];
|
||||
|
||||
void init()
|
||||
{
|
||||
first = 0;
|
||||
count = 0;
|
||||
texture = nullptr;
|
||||
tsp.full = 0;
|
||||
tcw.full = 0;
|
||||
pcw.full = 0;
|
||||
isp.full = 0;
|
||||
zvZ = 0;
|
||||
tileclip = 0;
|
||||
tsp1.full = -1;
|
||||
tcw1.full = -1;
|
||||
texture1 = nullptr;
|
||||
|
||||
mvMatrix = nullptr;
|
||||
normalMatrix = nullptr;
|
||||
projMatrix = nullptr;
|
||||
glossCoef[0] = 0;
|
||||
glossCoef[1] = 0;
|
||||
lightModel = nullptr;
|
||||
envMapping[0] = false;
|
||||
envMapping[1] = false;
|
||||
constantColor[0] = false;
|
||||
constantColor[1] = false;
|
||||
}
|
||||
|
||||
bool equivalentIgnoreCullingDirection(const PolyParam& other) const
|
||||
{
|
||||
return ((pcw.full ^ other.pcw.full) & 0x300CE) == 0
|
||||
&& ((isp.full ^ other.isp.full) & 0xF4000000) == 0
|
||||
&& tcw.full == other.tcw.full
|
||||
&& tsp.full == other.tsp.full
|
||||
&& tileclip == other.tileclip
|
||||
&& tcw1.full == other.tcw1.full
|
||||
&& tsp1.full == other.tsp1.full
|
||||
&& mvMatrix == other.mvMatrix
|
||||
&& normalMatrix == other.normalMatrix
|
||||
&& projMatrix == other.projMatrix
|
||||
&& glossCoef[0] == other.glossCoef[0]
|
||||
&& glossCoef[1] == other.glossCoef[1]
|
||||
&& lightModel == other.lightModel
|
||||
&& envMapping[0] == other.envMapping[0]
|
||||
&& constantColor[0] == other.constantColor[0]
|
||||
&& envMapping[1] == other.envMapping[1]
|
||||
&& constantColor[1] == other.constantColor[1];
|
||||
}
|
||||
|
||||
bool isNaomi2() const { return projMatrix != nullptr; }
|
||||
};
|
||||
|
||||
struct ModifierVolumeParam
|
||||
@@ -57,6 +113,20 @@ struct ModifierVolumeParam
|
||||
u32 first;
|
||||
u32 count;
|
||||
ISP_Modvol isp;
|
||||
|
||||
const float *mvMatrix;
|
||||
const float *projMatrix;
|
||||
|
||||
void init()
|
||||
{
|
||||
first = 0;
|
||||
count = 0;
|
||||
isp.full = 0;
|
||||
mvMatrix = nullptr;
|
||||
projMatrix = nullptr;
|
||||
}
|
||||
|
||||
bool isNaomi2() const { return projMatrix != nullptr; }
|
||||
};
|
||||
|
||||
struct ModTriangle
|
||||
@@ -64,18 +134,17 @@ struct ModTriangle
|
||||
f32 x0,y0,z0,x1,y1,z1,x2,y2,z2;
|
||||
};
|
||||
|
||||
constexpr size_t MAX_PASSES = 10;
|
||||
|
||||
struct tad_context
|
||||
{
|
||||
u8* thd_data;
|
||||
u8* thd_root;
|
||||
u8* thd_old_data;
|
||||
u8 *render_passes[10];
|
||||
u32 render_pass_count;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
thd_old_data = thd_data = thd_root;
|
||||
render_pass_count = 0;
|
||||
}
|
||||
|
||||
void ClearPartial()
|
||||
@@ -84,13 +153,6 @@ struct tad_context
|
||||
thd_data = thd_root;
|
||||
}
|
||||
|
||||
void Continue()
|
||||
{
|
||||
render_passes[render_pass_count] = End();
|
||||
if (render_pass_count < sizeof(render_passes) / sizeof(u8*) - 1)
|
||||
render_pass_count++;
|
||||
}
|
||||
|
||||
u8* End()
|
||||
{
|
||||
return thd_data == thd_root ? thd_old_data : thd_data;
|
||||
@@ -98,10 +160,9 @@ struct tad_context
|
||||
|
||||
void Reset(u8* ptr)
|
||||
{
|
||||
thd_data = thd_root = thd_old_data = ptr;
|
||||
render_pass_count = 0;
|
||||
thd_root = ptr;
|
||||
Clear();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct RenderPass {
|
||||
@@ -114,6 +175,48 @@ struct RenderPass {
|
||||
u32 mvo_tr_count;
|
||||
};
|
||||
|
||||
struct N2Matrix
|
||||
{
|
||||
float mat[16];
|
||||
};
|
||||
|
||||
struct N2Light
|
||||
{
|
||||
float color[4];
|
||||
float direction[4]; // For parallel/spot
|
||||
float position[4]; // For spot/point
|
||||
|
||||
int parallel;
|
||||
int routing;
|
||||
int dmode;
|
||||
int smode;
|
||||
|
||||
int diffuse[2];
|
||||
int specular[2];
|
||||
|
||||
float attnDistA;
|
||||
float attnDistB;
|
||||
float attnAngleA; // For spot
|
||||
float attnAngleB;
|
||||
int distAttnMode; // For spot/point
|
||||
int _pad[3];
|
||||
};
|
||||
|
||||
struct N2LightModel
|
||||
{
|
||||
N2Light lights[16];
|
||||
|
||||
float ambientBase[2][4]; // base ambient colors
|
||||
float ambientOffset[2][4]; // offset ambient colors
|
||||
int ambientMaterialBase[2]; // base ambient light is multiplied by model material/color
|
||||
int ambientMaterialOffset[2];// offset ambient light is multiplied by model material/color
|
||||
|
||||
int lightCount;
|
||||
int useBaseOver; // base color overflows into offset color
|
||||
int bumpId1; // Light index for vol0 bump mapping
|
||||
int bumpId2; // Light index for vol1 bump mapping
|
||||
};
|
||||
|
||||
struct rend_context
|
||||
{
|
||||
u8* proc_start;
|
||||
@@ -129,6 +232,8 @@ struct rend_context
|
||||
FB_X_CLIP_type fb_X_CLIP;
|
||||
FB_Y_CLIP_type fb_Y_CLIP;
|
||||
u32 fb_W_LINESTRIDE;
|
||||
u32 fb_W_SOF1;
|
||||
FB_W_CTRL_type fb_W_CTRL;
|
||||
|
||||
RGBAColor fog_clamp_min;
|
||||
RGBAColor fog_clamp_max;
|
||||
@@ -144,6 +249,9 @@ struct rend_context
|
||||
List<PolyParam> global_param_tr;
|
||||
List<RenderPass> render_passes;
|
||||
|
||||
List<N2Matrix> matrices;
|
||||
List<N2LightModel> lightModels;
|
||||
|
||||
void Clear()
|
||||
{
|
||||
verts.Clear();
|
||||
@@ -156,12 +264,20 @@ struct rend_context
|
||||
global_param_mvo_tr.Clear();
|
||||
render_passes.Clear();
|
||||
|
||||
Overrun=false;
|
||||
fZ_min= 1000000.0f;
|
||||
fZ_max= 1.0f;
|
||||
// Reserve space for background poly
|
||||
global_param_op.Append()->init();
|
||||
verts.Append(4);
|
||||
|
||||
Overrun = false;
|
||||
fZ_min = 1000000.0f;
|
||||
fZ_max = 1.0f;
|
||||
isRenderFramebuffer = false;
|
||||
matrices.Clear();
|
||||
lightModels.Clear();
|
||||
}
|
||||
|
||||
void newRenderPass();
|
||||
|
||||
u32 getFramebufferWidth() const {
|
||||
u32 w = fb_X_CLIP.max + 1;
|
||||
if (fb_W_LINESTRIDE != 0)
|
||||
@@ -180,15 +296,13 @@ struct rend_context
|
||||
struct TA_context
|
||||
{
|
||||
u32 Address;
|
||||
u32 LastUsed;
|
||||
|
||||
std::mutex thd_inuse;
|
||||
std::mutex rend_inuse;
|
||||
|
||||
tad_context tad;
|
||||
rend_context rend;
|
||||
|
||||
|
||||
TA_context *nextContext = nullptr;
|
||||
/*
|
||||
Dreamcast games use up to 20k vtx, 30k idx, 1k (in total) parameters.
|
||||
at 30 fps, thats 600kvtx (900 stripped)
|
||||
@@ -205,20 +319,18 @@ struct TA_context
|
||||
sa2: idx: 36094, vtx: 24520, op: 1330, pt: 10, tr: 177, mvo: 39, modt: 360, ov: 0
|
||||
*/
|
||||
|
||||
void MarkRend(u32 render_pass)
|
||||
void MarkRend()
|
||||
{
|
||||
verify(render_pass <= tad.render_pass_count);
|
||||
|
||||
rend.proc_start = render_pass == 0 ? tad.thd_root : tad.render_passes[render_pass - 1];
|
||||
rend.proc_end = render_pass == tad.render_pass_count ? tad.End() : tad.render_passes[render_pass];
|
||||
rend.proc_start = tad.thd_root;
|
||||
rend.proc_end = tad.End();
|
||||
}
|
||||
|
||||
void Alloc()
|
||||
{
|
||||
tad.Reset((u8*)allocAligned(32, TA_DATA_SIZE));
|
||||
|
||||
rend.verts.InitBytes(4 * 1024 * 1024, &rend.Overrun, "verts"); //up to 4 mb of vtx data/frame = ~ 96k vtx/frame
|
||||
rend.idx.Init(120 * 1024, &rend.Overrun, "idx"); //up to 120K indexes ( idx have stripification overhead )
|
||||
rend.verts.Init(320 * 1024, &rend.Overrun, "verts");
|
||||
rend.idx.Init(320 * 1024, &rend.Overrun, "idx");
|
||||
rend.global_param_op.Init(16384, &rend.Overrun, "global_param_op");
|
||||
rend.global_param_pt.Init(5120, &rend.Overrun, "global_param_pt");
|
||||
rend.global_param_mvo.Init(4096, &rend.Overrun, "global_param_mvo");
|
||||
@@ -227,7 +339,9 @@ struct TA_context
|
||||
|
||||
rend.modtrig.Init(16384, &rend.Overrun, "modtrig");
|
||||
|
||||
rend.render_passes.Init(sizeof(RenderPass) * 10, &rend.Overrun, "render_passes"); // 10 render passes
|
||||
rend.render_passes.Init(sizeof(RenderPass) * MAX_PASSES, &rend.Overrun, "render_passes"); // 10 render passes
|
||||
rend.matrices.Init(2000, &rend.Overrun, "matrices");
|
||||
rend.lightModels.Init(150, &rend.Overrun, "lightModels");
|
||||
|
||||
Reset();
|
||||
}
|
||||
@@ -236,13 +350,14 @@ struct TA_context
|
||||
{
|
||||
verify(tad.End() - tad.thd_root <= TA_DATA_SIZE);
|
||||
tad.Clear();
|
||||
nextContext = nullptr;
|
||||
rend_inuse.lock();
|
||||
rend.Clear();
|
||||
rend.proc_end = rend.proc_start = tad.thd_root;
|
||||
rend_inuse.unlock();
|
||||
}
|
||||
|
||||
void Free()
|
||||
~TA_context()
|
||||
{
|
||||
verify(tad.End() - tad.thd_root <= TA_DATA_SIZE);
|
||||
freeAligned(tad.thd_root);
|
||||
@@ -255,22 +370,18 @@ struct TA_context
|
||||
rend.global_param_mvo.Free();
|
||||
rend.global_param_mvo_tr.Free();
|
||||
rend.render_passes.Free();
|
||||
rend.matrices.Free();
|
||||
rend.lightModels.Free();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
extern TA_context* ta_ctx;
|
||||
extern tad_context ta_tad;
|
||||
|
||||
extern TA_context* vd_ctx;
|
||||
extern rend_context vd_rc;
|
||||
|
||||
TA_context* tactx_Find(u32 addr, bool allocnew=false);
|
||||
TA_context* tactx_Pop(u32 addr);
|
||||
|
||||
TA_context* tactx_Alloc();
|
||||
void tactx_Recycle(TA_context* poped_ctx);
|
||||
void tactx_Term();
|
||||
TA_context *tactx_Alloc();
|
||||
|
||||
/*
|
||||
Ta Context
|
||||
|
||||
@@ -286,7 +397,26 @@ void FinishRender(TA_context* ctx);
|
||||
|
||||
//must be moved to proper header
|
||||
void FillBGP(TA_context* ctx);
|
||||
bool UsingAutoSort(int pass_number);
|
||||
bool rend_framePending();
|
||||
void SerializeTAContext(Serializer& ser);
|
||||
void DeserializeTAContext(Deserializer& deser);
|
||||
|
||||
void ta_add_poly(const PolyParam& pp);
|
||||
void ta_add_poly(int listType, const ModifierVolumeParam& mvp);
|
||||
void ta_add_vertex(const Vertex& vtx);
|
||||
void ta_add_triangle(const ModTriangle& tri);
|
||||
float* ta_add_matrix(const float *matrix);
|
||||
N2LightModel *ta_add_light(const N2LightModel& light);
|
||||
u32 ta_add_ta_data(u32 *data, u32 size);
|
||||
int getTAContextAddresses(u32 *addresses);
|
||||
u32 ta_get_tileclip();
|
||||
void ta_set_tileclip(u32 tileclip);
|
||||
u32 ta_get_list_type();
|
||||
void ta_set_list_type(u32 listType);
|
||||
void ta_parse_reset();
|
||||
|
||||
class TAParserException : public FlycastException
|
||||
{
|
||||
public:
|
||||
TAParserException() : FlycastException("") {}
|
||||
};
|
||||
@@ -1,11 +1,6 @@
|
||||
//structs were getting tooo many , so i moved em here !
|
||||
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
//bits that affect drawing (for caching params)
|
||||
#define PCW_DRAW_MASK (0x000000CE)
|
||||
|
||||
#pragma pack(push, 1) // n = 1
|
||||
// Global Param/misc structs
|
||||
//4B
|
||||
@@ -37,13 +32,6 @@ union PCW
|
||||
u32 ParaType : 3;
|
||||
};
|
||||
u8 obj_ctrl;
|
||||
struct
|
||||
{
|
||||
u32 padin : 8;
|
||||
u32 S6X : 1; //set by TA preprocessing if sz64
|
||||
u32 padin2 : 19;
|
||||
u32 PTEOS : 4;
|
||||
};
|
||||
u32 full;
|
||||
};
|
||||
|
||||
|
||||
+584
-573
File diff suppressed because it is too large.
Load diff
@@ -112,10 +112,7 @@ struct shil_param
|
||||
bool is_r32() const { return is_r32i() || is_r32f(); }
|
||||
bool is_r64() const { return is_r64f(); } //just here for symmetry ...
|
||||
|
||||
bool is_imm_s8() const { return is_imm() && is_s8(_imm); }
|
||||
bool is_imm_u8() const { return is_imm() && is_u8(_imm); }
|
||||
bool is_imm_s16() const { return is_imm() && is_s16(_imm); }
|
||||
bool is_imm_u16() const { return is_imm() && is_u16(_imm); }
|
||||
bool is_imm_s8() const { return is_imm() && (int8_t)_imm == (int32_t)_imm; }
|
||||
|
||||
u32* reg_ptr() const { verify(is_reg()); return GetRegPtr(_reg); }
|
||||
s32 reg_nofs() const { verify(is_reg()); return (s32)((u8*)GetRegPtr(_reg) - (u8*)GetRegPtr(reg_xf_0)-sizeof(Sh4cntx)); }
|
||||
|
||||
@@ -12,7 +12,7 @@ BSC_PDTRA_type BSC_PDTRA;
|
||||
void write_BSC_PCTRA(u32 addr, u32 data)
|
||||
{
|
||||
BSC_PCTRA.full = data;
|
||||
if (settings.platform.system == DC_PLATFORM_NAOMI)
|
||||
if (settings.platform.isNaomi())
|
||||
NaomiBoardIDWriteControl((u16)data);
|
||||
//else
|
||||
//printf("C:BSC_PCTRA = %08X\n",data);
|
||||
@@ -23,13 +23,13 @@ void write_BSC_PDTRA(u32 addr, u32 data)
|
||||
BSC_PDTRA.full=(u16)data;
|
||||
//printf("D:BSC_PDTRA = %04x\n", (u16)data);
|
||||
|
||||
if (settings.platform.system == DC_PLATFORM_NAOMI)
|
||||
if (settings.platform.isNaomi())
|
||||
NaomiBoardIDWrite((u16)data);
|
||||
}
|
||||
|
||||
u32 read_BSC_PDTRA(u32 addr)
|
||||
{
|
||||
if (settings.platform.system == DC_PLATFORM_NAOMI)
|
||||
if (settings.platform.isNaomi())
|
||||
{
|
||||
return NaomiBoardIDRead();
|
||||
}
|
||||
|
||||
@@ -20,9 +20,21 @@ void intc_init();
|
||||
void intc_reset();
|
||||
void intc_term();
|
||||
|
||||
struct SerialPipe
|
||||
{
|
||||
// Serial TX
|
||||
virtual void write(u8 data) = 0;
|
||||
// RX buffer Size
|
||||
virtual int available() = 0;
|
||||
// Serial RX
|
||||
virtual u8 read() = 0;
|
||||
|
||||
virtual ~SerialPipe() = default;
|
||||
};
|
||||
void serial_init();
|
||||
void serial_reset();
|
||||
void serial_reset(bool hard);
|
||||
void serial_term();
|
||||
void serial_setPipe(SerialPipe *pipe);
|
||||
|
||||
void ubc_init();
|
||||
void ubc_reset();
|
||||
|
||||
@@ -15,8 +15,9 @@
|
||||
#include "hw/sh4/sh4_mmr.h"
|
||||
#include "hw/sh4/sh4_interrupts.h"
|
||||
#include "cfg/option.h"
|
||||
#include "modules.h"
|
||||
|
||||
static int tty = 1; // stdout by default
|
||||
static SerialPipe *serialPipe;
|
||||
|
||||
SCIF_SCFSR2_type SCIF_SCFSR2;
|
||||
SCIF_SCSCR2_type SCIF_SCSCR2;
|
||||
@@ -66,8 +67,9 @@ static void Serial_UpdateInterrupts()
|
||||
|
||||
static void SerialWrite(u32 addr, u32 data)
|
||||
{
|
||||
if (config::SerialConsole)
|
||||
write(tty, &data, 1);
|
||||
//DEBUG_LOG(COMMON, "serial %02x", data);
|
||||
if (serialPipe != nullptr)
|
||||
serialPipe->write(data);
|
||||
|
||||
SCIF_SCFSR2.TDFE = 1;
|
||||
SCIF_SCFSR2.TEND = 1;
|
||||
@@ -78,18 +80,17 @@ static void SerialWrite(u32 addr, u32 data)
|
||||
//SCIF_SCFSR2 read
|
||||
static u32 ReadSerialStatus(u32 addr)
|
||||
{
|
||||
#if defined(__unix__) || defined(__APPLE__)
|
||||
int count = 0;
|
||||
if (config::SerialConsole && tty != 1
|
||||
&& ioctl(tty, FIONREAD, &count) == 0 && count > 0)
|
||||
if (serialPipe != nullptr)
|
||||
{
|
||||
return SCIF_SCFSR2.full | 2;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
return SCIF_SCFSR2.full | 0;
|
||||
constexpr int trigLevels[] { 1, 4, 8, 14 };
|
||||
int avail = serialPipe->available();
|
||||
|
||||
if (avail >= trigLevels[SCIF_SCFCR2.RTRG1 * 2 + SCIF_SCFCR2.RTRG0])
|
||||
return SCIF_SCFSR2.full | 3; // RDF | DR
|
||||
else if (avail >= 1)
|
||||
return SCIF_SCFSR2.full | 1; // DR
|
||||
}
|
||||
return SCIF_SCFSR2.full;
|
||||
}
|
||||
|
||||
static void WriteSerialStatus(u32 addr,u32 data)
|
||||
@@ -108,14 +109,19 @@ static void WriteSerialStatus(u32 addr,u32 data)
|
||||
//SCIF_SCFDR2 - 16b
|
||||
static u32 Read_SCFDR2(u32 addr)
|
||||
{
|
||||
return 0;
|
||||
if (serialPipe != nullptr && serialPipe->available() > 0)
|
||||
return 1; // TODO more?
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
//SCIF_SCFRDR2
|
||||
static u32 ReadSerialData(u32 addr)
|
||||
{
|
||||
u8 data = 0;
|
||||
if (tty != 1)
|
||||
read(tty, &data, 1);
|
||||
if (serialPipe != nullptr)
|
||||
data = serialPipe->read();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -133,6 +139,65 @@ static void SCSCR2_write(u32 addr, u32 data)
|
||||
Serial_UpdateInterrupts();
|
||||
}
|
||||
|
||||
struct PTYPipe : public SerialPipe
|
||||
{
|
||||
void write(u8 data) override {
|
||||
if (config::SerialConsole)
|
||||
::write(tty, &data, 1);
|
||||
}
|
||||
|
||||
int available() override {
|
||||
int count = 0;
|
||||
#if defined(__unix__) || defined(__APPLE__)
|
||||
if (config::SerialConsole && tty != 1)
|
||||
ioctl(tty, FIONREAD, &count);
|
||||
#endif
|
||||
return count;
|
||||
}
|
||||
|
||||
u8 read() override {
|
||||
u8 data = 0;
|
||||
if (tty != 1)
|
||||
::read(tty, &data, 1);
|
||||
return data;
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
#if defined(__unix__) || defined(__APPLE__)
|
||||
if (config::SerialConsole && config::SerialPTY && tty == 1)
|
||||
{
|
||||
tty = open("/dev/ptmx", O_RDWR | O_NDELAY | O_NOCTTY | O_NONBLOCK);
|
||||
if (tty < 0)
|
||||
{
|
||||
ERROR_LOG(BOOT, "Cannot open /dev/ptmx: errno %d", errno);
|
||||
tty = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
grantpt(tty);
|
||||
unlockpt(tty);
|
||||
NOTICE_LOG(BOOT, "Pseudoterminal is at %s", ptsname(tty));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
serial_setPipe(this);
|
||||
}
|
||||
|
||||
void term()
|
||||
{
|
||||
if (tty != 1)
|
||||
{
|
||||
::close(tty);
|
||||
tty = 1;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int tty = 1;
|
||||
};
|
||||
static PTYPipe ptyPipe;
|
||||
|
||||
//Init term res
|
||||
void serial_init()
|
||||
{
|
||||
@@ -171,21 +236,6 @@ void serial_init()
|
||||
//SCIF SCLSR2 0xFFE80024 0x1FE80024 16 0x0000 0x0000 Held Held Pclk
|
||||
sh4_rio_reg(SCIF,SCIF_SCLSR2_addr,RIO_DATA,16);
|
||||
|
||||
#if defined(__unix__) || defined(__APPLE__)
|
||||
if (config::SerialConsole && config::SerialPTY)
|
||||
{
|
||||
tty = open("/dev/ptmx", O_RDWR | O_NDELAY | O_NOCTTY | O_NONBLOCK);
|
||||
if (tty < 0)
|
||||
ERROR_LOG(BOOT, "Cannot open /dev/ptmx: errno %d", errno);
|
||||
else
|
||||
{
|
||||
grantpt(tty);
|
||||
unlockpt(tty);
|
||||
NOTICE_LOG(BOOT, "Pseudoterminal is at %s", ptsname(tty));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Serial Communication Interface
|
||||
sh4_rio_reg(SCI, SCI_SCSMR1_addr, RIO_DATA, 8);
|
||||
sh4_rio_reg(SCI, SCI_SCBRR1_addr, RIO_DATA, 8);
|
||||
@@ -195,7 +245,8 @@ void serial_init()
|
||||
sh4_rio_reg(SCI, SCI_SCRDR1_addr, RIO_RO, 8);
|
||||
sh4_rio_reg(SCI, SCI_SCSPTR1_addr, RIO_DATA, 8);
|
||||
}
|
||||
void serial_reset()
|
||||
|
||||
void serial_reset(bool hard)
|
||||
{
|
||||
/*
|
||||
SCIF SCSMR2 H'FFE8 0000 H'1FE8 0000 16 H'0000 H'0000 Held Held Pclk
|
||||
@@ -224,14 +275,17 @@ void serial_reset()
|
||||
SCI_SCSSR1 = 0x84;
|
||||
SCI_SCRDR1 = 0;
|
||||
SCI_SCSPTR1 = 0;
|
||||
|
||||
if (hard)
|
||||
ptyPipe.init();
|
||||
}
|
||||
|
||||
void serial_term()
|
||||
{
|
||||
if (tty > 2)
|
||||
{
|
||||
close(tty);
|
||||
tty = 1;
|
||||
}
|
||||
ptyPipe.term();
|
||||
}
|
||||
|
||||
void serial_setPipe(SerialPipe *pipe)
|
||||
{
|
||||
serialPipe = pipe;
|
||||
}
|
||||
+8
-13
@@ -7,6 +7,7 @@
|
||||
#include "sh4_mem.h"
|
||||
#include "hw/holly/sb_mem.h"
|
||||
#include "sh4_mmr.h"
|
||||
#include "hw/pvr/elan.h"
|
||||
#include "hw/pvr/pvr_mem.h"
|
||||
#include "hw/sh4/sh4_core.h"
|
||||
#include "hw/mem/_vmem.h"
|
||||
@@ -50,14 +51,7 @@ static void map_area1(u32 base)
|
||||
_vmem_mirror_mapping(0x06 | base, 0x04 | base, 0x02);
|
||||
}
|
||||
|
||||
//AREA 2
|
||||
static void map_area2_init()
|
||||
{
|
||||
}
|
||||
|
||||
static void map_area2(u32 base)
|
||||
{
|
||||
}
|
||||
//AREA 2: Naomi2 elan
|
||||
|
||||
//AREA 3
|
||||
static void map_area3_init()
|
||||
@@ -96,14 +90,15 @@ static void map_area4(u32 base)
|
||||
template <class T>
|
||||
T DYNACALL ReadMem_extdev_T(u32 addr)
|
||||
{
|
||||
return (T)libExtDevice_ReadMem_A5(addr, sizeof(T));
|
||||
INFO_LOG(SH4, "Read ext. device (Area 5) undefined @ %08x", addr);
|
||||
return (T)0;
|
||||
}
|
||||
|
||||
//Write Ext.Device
|
||||
template <class T>
|
||||
void DYNACALL WriteMem_extdev_T(u32 addr,T data)
|
||||
{
|
||||
libExtDevice_WriteMem_A5(addr, data, sizeof(T));
|
||||
INFO_LOG(SH4, "Write ext. device (Area 5) undefined @ %08x: %x", addr, (u32)data);
|
||||
}
|
||||
|
||||
_vmem_handler area5_handler;
|
||||
@@ -152,7 +147,7 @@ void mem_map_default()
|
||||
//Init Memmaps (register handlers)
|
||||
map_area0_init();
|
||||
map_area1_init();
|
||||
map_area2_init();
|
||||
elan::vmem_init();
|
||||
map_area3_init();
|
||||
map_area4_init();
|
||||
map_area5_init();
|
||||
@@ -164,7 +159,7 @@ void mem_map_default()
|
||||
{
|
||||
map_area0(i << 5); //Bios,Flahsrom,i/f regs,Ext. Device,Sound Ram
|
||||
map_area1(i << 5); //VRAM
|
||||
map_area2(i << 5); //Unassigned
|
||||
elan::vmem_map(i << 5); // Naomi2 Elan
|
||||
map_area3(i << 5); //RAM
|
||||
map_area4(i << 5); //TA
|
||||
map_area5(i << 5); //Ext. Device
|
||||
@@ -195,7 +190,7 @@ void mem_Reset(bool hard)
|
||||
|
||||
//Reset registers
|
||||
sh4_area0_Reset(hard);
|
||||
sh4_mmr_reset(true);
|
||||
sh4_mmr_reset(hard);
|
||||
}
|
||||
|
||||
void mem_Term()
|
||||
|
||||
+25
-27
@@ -781,39 +781,37 @@ void sh4_mmr_init()
|
||||
|
||||
void sh4_mmr_reset(bool hard)
|
||||
{
|
||||
if (hard)
|
||||
{
|
||||
for (auto& reg : CCN)
|
||||
reg.reset();
|
||||
for (auto& reg : UBC)
|
||||
reg.reset();
|
||||
for (auto& reg : BSC)
|
||||
reg.reset();
|
||||
for (auto& reg : DMAC)
|
||||
reg.reset();
|
||||
for (auto& reg : CPG)
|
||||
reg.reset();
|
||||
for (auto& reg : RTC)
|
||||
reg.reset();
|
||||
for (auto& reg : INTC)
|
||||
reg.reset();
|
||||
for (auto& reg : TMU)
|
||||
reg.reset();
|
||||
for (auto& reg : SCI)
|
||||
reg.reset();
|
||||
for (auto& reg : SCIF)
|
||||
reg.reset();
|
||||
}
|
||||
for (auto& reg : CCN)
|
||||
reg.reset();
|
||||
for (auto& reg : UBC)
|
||||
reg.reset();
|
||||
for (auto& reg : BSC)
|
||||
reg.reset();
|
||||
for (auto& reg : DMAC)
|
||||
reg.reset();
|
||||
for (auto& reg : CPG)
|
||||
reg.reset();
|
||||
for (auto& reg : RTC)
|
||||
reg.reset();
|
||||
for (auto& reg : INTC)
|
||||
reg.reset();
|
||||
for (auto& reg : TMU)
|
||||
reg.reset();
|
||||
for (auto& reg : SCI)
|
||||
reg.reset();
|
||||
for (auto& reg : SCIF)
|
||||
reg.reset();
|
||||
|
||||
OnChipRAM = {};
|
||||
//Reset register values
|
||||
bsc_reset(hard);
|
||||
ccn_reset(hard);
|
||||
bsc_reset(true);
|
||||
ccn_reset(true);
|
||||
cpg_reset();
|
||||
dmac_reset();
|
||||
intc_reset();
|
||||
rtc_reset();
|
||||
serial_reset();
|
||||
tmu_reset(hard);
|
||||
serial_reset(hard);
|
||||
tmu_reset(true);
|
||||
ubc_reset();
|
||||
|
||||
MMU_reset();
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
#include <array>
|
||||
#include "types.h"
|
||||
#include "../sh4/sh4_if.h"
|
||||
#include "sh4_if.h"
|
||||
#include "hw/hwreg.h"
|
||||
|
||||
//For mem mapping
|
||||
void map_area7_init();
|
||||
|
||||
@@ -491,12 +491,28 @@ std::string disassemble_op(const char* tx1, u32 pc, u16 opcode)
|
||||
}
|
||||
else if (strcmp2(tx1,"FREG_N>"))
|
||||
{
|
||||
sprintf(buf,"FR%d=%f ", GetN(opcode), p_sh4rcb->cntx.xffr[16 + GetN(opcode)]);
|
||||
regs += buf;
|
||||
sprintf(buf,"FR%d",GetN(opcode));
|
||||
}
|
||||
else if (strcmp2(tx1,"FREG_M>"))
|
||||
{
|
||||
sprintf(buf,"FR%d=%f ", GetM(opcode), p_sh4rcb->cntx.xffr[16 + GetM(opcode)]);
|
||||
regs += buf;
|
||||
sprintf(buf,"FR%d",GetM(opcode));
|
||||
}
|
||||
else if (strcmp2(tx1, "FREG_M_SD_F>"))
|
||||
{
|
||||
sprintf(buf,"FR%d=%f ", GetM(opcode), p_sh4rcb->cntx.xffr[16 + GetM(opcode)]);
|
||||
regs += buf;
|
||||
sprintf(buf,"FR%d", GetM(opcode));
|
||||
}
|
||||
else if (strcmp2(tx1,"FREG_0>"))
|
||||
{
|
||||
sprintf(buf,"FR0=%f ", p_sh4rcb->cntx.xffr[16]);
|
||||
regs += buf;
|
||||
sprintf(buf,"FR0");
|
||||
}
|
||||
else if (strcmp2(tx1,"RM_BANK>"))
|
||||
{
|
||||
sprintf(buf,"R%d_BANK",GetM(opcode)&0x7);
|
||||
|
||||
@@ -46,6 +46,7 @@ enum DreamcastKey
|
||||
EMU_BTN_MENU,
|
||||
EMU_BTN_FFORWARD,
|
||||
EMU_BTN_ESCAPE,
|
||||
EMU_BTN_INSERT_CARD,
|
||||
|
||||
// Real axes
|
||||
DC_AXIS_TRIGGERS = 0x1000000,
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "rend/gui.h"
|
||||
#include "emulator.h"
|
||||
#include "hw/maple/maple_devs.h"
|
||||
#include "hw/naomi/card_reader.h"
|
||||
#include "stdclass.h"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -86,6 +87,10 @@ bool GamepadDevice::handleButtonInput(int port, DreamcastKey key, bool pressed)
|
||||
if (pressed && !gui_is_open())
|
||||
settings.input.fastForwardMode = !settings.input.fastForwardMode && !settings.network.online;
|
||||
break;
|
||||
case EMU_BTN_INSERT_CARD:
|
||||
if (pressed && settings.platform.isNaomi())
|
||||
card_reader::insertCard();
|
||||
break;
|
||||
case DC_AXIS_LT:
|
||||
if (port >= 0)
|
||||
lt[port] = pressed ? 255 : 0;
|
||||
@@ -286,7 +291,7 @@ void GamepadDevice::load_system_mappings()
|
||||
{
|
||||
std::shared_ptr<GamepadDevice> gamepad = GetGamepad(i);
|
||||
if (!gamepad->find_mapping())
|
||||
gamepad->resetMappingToDefault(settings.platform.system != DC_PLATFORM_DREAMCAST, true);
|
||||
gamepad->resetMappingToDefault(settings.platform.isArcade(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,6 +345,7 @@ bool GamepadDevice::find_mapping(int system /* = settings.platform.system */)
|
||||
if (cloneMapping)
|
||||
input_mapper = std::make_shared<InputMapping>(*input_mapper);
|
||||
perGameMapping = perGame;
|
||||
rumblePower = input_mapper->rumblePower;
|
||||
return true;
|
||||
}
|
||||
if (!perGame)
|
||||
|
||||
@@ -56,7 +56,20 @@ public:
|
||||
|
||||
virtual void rumble(float power, float inclination, u32 duration_ms) {}
|
||||
virtual void update_rumble() {}
|
||||
bool is_rumble_enabled() const { return _rumble_enabled; }
|
||||
bool is_rumble_enabled() const { return rumbleEnabled; }
|
||||
int get_rumble_power() const { return rumblePower; }
|
||||
void set_rumble_power(int power) {
|
||||
if (power != this->rumblePower)
|
||||
{
|
||||
this->rumblePower = power;
|
||||
if (input_mapper != nullptr)
|
||||
{
|
||||
input_mapper->rumblePower = power;
|
||||
input_mapper->set_dirty();
|
||||
save_mapping();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Register(const std::shared_ptr<GamepadDevice>& gamepad);
|
||||
|
||||
@@ -95,7 +108,8 @@ protected:
|
||||
std::string _name;
|
||||
std::string _unique_id;
|
||||
std::shared_ptr<InputMapping> input_mapper;
|
||||
bool _rumble_enabled = true;
|
||||
bool rumbleEnabled = false;
|
||||
int rumblePower = 100;
|
||||
|
||||
private:
|
||||
bool handleButtonInput(int port, DreamcastKey key, bool pressed);
|
||||
|
||||
@@ -480,8 +480,8 @@ void KeyboardDeviceTemplate<Keycode>::keyboard_input(Keycode keycode, bool press
|
||||
// or the corresponding maple device (if any) isn't a keyboard
|
||||
else if (gui_is_open()
|
||||
|| port == (int)ARRAY_SIZE(kb_key)
|
||||
|| (settings.platform.system == DC_PLATFORM_DREAMCAST && config::MapleMainDevices[port] != MDT_Keyboard)
|
||||
|| (settings.platform.system == DC_PLATFORM_NAOMI && settings.input.JammaSetup != JVS::Keyboard)
|
||||
|| settings.platform.system == DC_PLATFORM_ATOMISWAVE)
|
||||
|| (settings.platform.isConsole() && config::MapleMainDevices[port] != MDT_Keyboard)
|
||||
|| (settings.platform.isNaomi() && settings.input.JammaSetup != JVS::Keyboard)
|
||||
|| settings.platform.isAtomiswave())
|
||||
gamepad_btn_input(dc_keycode, pressed);
|
||||
}
|
||||
@@ -55,6 +55,7 @@ button_list[] =
|
||||
{ DC_AXIS_LEFT, "compat", "btn_analog_left" },
|
||||
{ DC_AXIS_RIGHT, "compat", "btn_analog_right" },
|
||||
{ DC_BTN_RELOAD, "dreamcast", "reload" },
|
||||
{ EMU_BTN_INSERT_CARD, "emulator", "insert_card" },
|
||||
};
|
||||
|
||||
static struct
|
||||
@@ -185,6 +186,7 @@ void InputMapping::load(FILE* fp)
|
||||
dz = std::min(dz, 100);
|
||||
dz = std::max(dz, 0);
|
||||
this->dead_zone = (float)dz / 100.f;
|
||||
this->rumblePower = mf.get_int("emulator", "rumble_power", this->rumblePower);
|
||||
|
||||
version = mf.get_int("emulator", "version", 1);
|
||||
if (version < 3)
|
||||
@@ -412,6 +414,7 @@ bool InputMapping::save(const std::string& name)
|
||||
|
||||
mf.set("emulator", "mapping_name", this->name);
|
||||
mf.set_int("emulator", "dead_zone", (int)std::round(this->dead_zone * 100.f));
|
||||
mf.set_int("emulator", "rumble_power", this->rumblePower);
|
||||
mf.set_int("emulator", "version", 3);
|
||||
|
||||
int bindIndex = 0;
|
||||
|
||||
Loaded 100 of 252 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user