update Cheat files

This commit is contained in:
Nayla Hanegan 2023-04-20 20:32:13 -04:00
parent 9ab8c1e433
commit cbfd634a4b
No known key found for this signature in database
GPG key ID: BAFE9001DA16CFA2
217 changed files with 2263 additions and 1880 deletions

View file

@ -1,250 +0,0 @@
# - Find SDL2
# Find the SDL2 headers and libraries
#
# SDL2::SDL2 - Imported target to use for building a library
# SDL2::SDL2main - Imported interface target to use if you want SDL and SDLmain.
# SDL2_FOUND - True if SDL2 was found.
# SDL2_DYNAMIC - If we found a DLL version of SDL (meaning you might want to copy a DLL from SDL2::SDL2)
#
# Original Author:
# 2015 Ryan Pavlik <ryan.pavlik@gmail.com> <abiryan@ryand.net>
#
# Copyright Sensics, Inc. 2015.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
# Set up architectures (for windows) and prefixes (for mingw builds)
if(WIN32)
if(MINGW)
include(MinGWSearchPathExtras OPTIONAL)
if(MINGWSEARCH_TARGET_TRIPLE)
set(SDL2_PREFIX ${MINGWSEARCH_TARGET_TRIPLE})
endif()
endif()
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(SDL2_LIB_PATH_SUFFIX lib/x64)
if(NOT MSVC AND NOT SDL2_PREFIX)
set(SDL2_PREFIX x86_64-w64-mingw32)
endif()
else()
set(SDL2_LIB_PATH_SUFFIX lib/x86)
if(NOT MSVC AND NOT SDL2_PREFIX)
set(SDL2_PREFIX i686-w64-mingw32)
endif()
endif()
endif()
if(SDL2_PREFIX)
set(SDL2_ORIGPREFIXPATH ${CMAKE_PREFIX_PATH})
if(SDL2_ROOT_DIR)
list(APPEND CMAKE_PREFIX_PATH "${SDL2_ROOT_DIR}")
endif()
if(CMAKE_PREFIX_PATH)
foreach(_prefix ${CMAKE_PREFIX_PATH})
list(APPEND CMAKE_PREFIX_PATH "${_prefix}/${SDL2_PREFIX}")
endforeach()
endif()
if(MINGWSEARCH_PREFIXES)
list(APPEND CMAKE_PREFIX_PATH ${MINGWSEARCH_PREFIXES})
endif()
endif()
# Invoke pkgconfig for hints
find_package(PkgConfig QUIET)
set(SDL2_INCLUDE_HINTS)
set(SDL2_LIB_HINTS)
if(PKG_CONFIG_FOUND)
pkg_search_module(SDL2PC QUIET sdl2)
if(SDL2PC_INCLUDE_DIRS)
set(SDL2_INCLUDE_HINTS ${SDL2PC_INCLUDE_DIRS})
endif()
if(SDL2PC_LIBRARY_DIRS)
set(SDL2_LIB_HINTS ${SDL2PC_LIBRARY_DIRS})
endif()
endif()
include(FindPackageHandleStandardArgs)
find_library(SDL2_LIBRARY
NAMES
SDL2
HINTS
${SDL2_LIB_HINTS}
PATHS
${SDL2_ROOT_DIR}
ENV SDL2DIR
PATH_SUFFIXES lib SDL2 ${SDL2_LIB_PATH_SUFFIX})
set(_sdl2_framework FALSE)
# Some special-casing if we've found/been given a framework.
# Handles whether we're given the library inside the framework or the framework itself.
if(APPLE AND "${SDL2_LIBRARY}" MATCHES "(/[^/]+)*.framework(/.*)?$")
set(_sdl2_framework TRUE)
set(SDL2_FRAMEWORK "${SDL2_LIBRARY}")
# Move up in the directory tree as required to get the framework directory.
while("${SDL2_FRAMEWORK}" MATCHES "(/[^/]+)*.framework(/.*)$" AND NOT "${SDL2_FRAMEWORK}" MATCHES "(/[^/]+)*.framework$")
get_filename_component(SDL2_FRAMEWORK "${SDL2_FRAMEWORK}" DIRECTORY)
endwhile()
if("${SDL2_FRAMEWORK}" MATCHES "(/[^/]+)*.framework$")
set(SDL2_FRAMEWORK_NAME ${CMAKE_MATCH_1})
# If we found a framework, do a search for the header ahead of time that will be more likely to get the framework header.
find_path(SDL2_INCLUDE_DIR
NAMES
SDL_haptic.h # this file was introduced with SDL2
HINTS
"${SDL2_FRAMEWORK}/Headers/")
else()
# For some reason we couldn't get the framework directory itself.
# Shouldn't happen, but might if something is weird.
unset(SDL2_FRAMEWORK)
endif()
endif()
find_path(SDL2_INCLUDE_DIR
NAMES
SDL_haptic.h # this file was introduced with SDL2
HINTS
${SDL2_INCLUDE_HINTS}
PATHS
${SDL2_ROOT_DIR}
ENV SDL2DIR
PATH_SUFFIXES include include/sdl2 include/SDL2 SDL2)
if(WIN32 AND SDL2_LIBRARY)
find_file(SDL2_RUNTIME_LIBRARY
NAMES
SDL2.dll
libSDL2.dll
HINTS
${SDL2_LIB_HINTS}
PATHS
${SDL2_ROOT_DIR}
ENV SDL2DIR
PATH_SUFFIXES bin lib ${SDL2_LIB_PATH_SUFFIX})
endif()
if(WIN32 OR ANDROID OR IOS OR (APPLE AND NOT _sdl2_framework))
set(SDL2_EXTRA_REQUIRED SDL2_SDLMAIN_LIBRARY)
find_library(SDL2_SDLMAIN_LIBRARY
NAMES
SDL2main
PATHS
${SDL2_ROOT_DIR}
ENV SDL2DIR
PATH_SUFFIXES lib ${SDL2_LIB_PATH_SUFFIX})
endif()
if(MINGW AND NOT SDL2PC_FOUND)
find_library(SDL2_MINGW_LIBRARY mingw32)
find_library(SDL2_MWINDOWS_LIBRARY mwindows)
endif()
if(SDL2_PREFIX)
# Restore things the way they used to be.
set(CMAKE_PREFIX_PATH ${SDL2_ORIGPREFIXPATH})
endif()
# handle the QUIETLY and REQUIRED arguments and set QUATLIB_FOUND to TRUE if
# all listed variables are TRUE
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(SDL2
DEFAULT_MSG
SDL2_LIBRARY
SDL2_INCLUDE_DIR
${SDL2_EXTRA_REQUIRED})
if(SDL2_FOUND)
if(NOT TARGET SDL2::SDL2)
# Create SDL2::SDL2
if(WIN32 AND SDL2_RUNTIME_LIBRARY)
set(SDL2_DYNAMIC TRUE)
add_library(SDL2::SDL2 SHARED IMPORTED)
set_target_properties(SDL2::SDL2
PROPERTIES
IMPORTED_IMPLIB "${SDL2_LIBRARY}"
IMPORTED_LOCATION "${SDL2_RUNTIME_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIR}"
)
else()
add_library(SDL2::SDL2 UNKNOWN IMPORTED)
if(SDL2_FRAMEWORK AND SDL2_FRAMEWORK_NAME)
# Handle the case that SDL2 is a framework and we were able to decompose it above.
set_target_properties(SDL2::SDL2 PROPERTIES
IMPORTED_LOCATION "${SDL2_FRAMEWORK}/${SDL2_FRAMEWORK_NAME}")
elseif(_sdl2_framework AND SDL2_LIBRARY MATCHES "(/[^/]+)*.framework$")
# Handle the case that SDL2 is a framework and SDL_LIBRARY is just the framework itself.
# This takes the basename of the framework, without the extension,
# and sets it (as a child of the framework) as the imported location for the target.
# This is the library symlink inside of the framework.
set_target_properties(SDL2::SDL2 PROPERTIES
IMPORTED_LOCATION "${SDL2_LIBRARY}/${CMAKE_MATCH_1}")
else()
# Handle non-frameworks (including non-Mac), as well as the case that we're given the library inside of the framework
set_target_properties(SDL2::SDL2 PROPERTIES
IMPORTED_LOCATION "${SDL2_LIBRARY}")
endif()
set_target_properties(SDL2::SDL2
PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIR}"
)
endif()
if(APPLE)
# Need Cocoa here, is always a framework
find_library(SDL2_COCOA_LIBRARY Cocoa)
list(APPEND SDL2_EXTRA_REQUIRED SDL2_COCOA_LIBRARY)
if(SDL2_COCOA_LIBRARY)
set_target_properties(SDL2::SDL2 PROPERTIES
IMPORTED_LINK_INTERFACE_LIBRARIES ${SDL2_COCOA_LIBRARY})
endif()
endif()
# Compute what to do with SDL2main
set(SDL2MAIN_LIBRARIES SDL2::SDL2)
add_library(SDL2::SDL2main INTERFACE IMPORTED)
if(SDL2_SDLMAIN_LIBRARY)
add_library(SDL2::SDL2main_real STATIC IMPORTED)
set_target_properties(SDL2::SDL2main_real
PROPERTIES
IMPORTED_LOCATION "${SDL2_SDLMAIN_LIBRARY}")
set(SDL2MAIN_LIBRARIES SDL2::SDL2main_real ${SDL2MAIN_LIBRARIES})
endif()
if(MINGW)
# MinGW requires some additional libraries to appear earlier in the link line.
if(SDL2PC_LIBRARIES)
# Use pkgconfig-suggested extra libraries if available.
list(REMOVE_ITEM SDL2PC_LIBRARIES SDL2main SDL2)
set(SDL2MAIN_LIBRARIES ${SDL2PC_LIBRARIES} ${SDL2MAIN_LIBRARIES})
else()
# fall back to extra libraries specified in pkg-config in
# an official binary distro of SDL2 for MinGW I downloaded
if(SDL2_MINGW_LIBRARY)
set(SDL2MAIN_LIBRARIES ${SDL2_MINGW_LIBRARY} ${SDL2MAIN_LIBRARIES})
endif()
if(SDL2_MWINDOWS_LIBRARY)
set(SDL2MAIN_LIBRARIES ${SDL2_MWINDOWS_LIBRARY} ${SDL2MAIN_LIBRARIES})
endif()
endif()
set_target_properties(SDL2::SDL2main
PROPERTIES
INTERFACE_COMPILE_DEFINITIONS "main=SDL_main")
endif()
set_target_properties(SDL2::SDL2main
PROPERTIES
INTERFACE_LINK_LIBRARIES "${SDL2MAIN_LIBRARIES}")
endif()
mark_as_advanced(SDL2_ROOT_DIR)
endif()
mark_as_advanced(SDL2_LIBRARY
SDL2_RUNTIME_LIBRARY
SDL2_INCLUDE_DIR
SDL2_SDLMAIN_LIBRARY
SDL2_COCOA_LIBRARY
SDL2_MINGW_LIBRARY
SDL2_MWINDOWS_LIBRARY)

View file

@ -6,6 +6,10 @@ cmake_minimum_required(VERSION 3.13)
cmake_policy(SET CMP0079 NEW) # let target_link_libraries() link to a target defined in a different directory cmake_policy(SET CMP0079 NEW) # let target_link_libraries() link to a target defined in a different directory
cmake_policy(SET CMP0080 OLD) # allow using BundleUtilities at configure time cmake_policy(SET CMP0080 OLD) # allow using BundleUtilities at configure time
if (POLICY CMP0099)
cmake_policy(SET CMP0099 NEW) # Propagate INTERFACE_LINK_OPTIONS from private dependencies, used by MacOS framework builds of SDL
endif()
# Weird chicken-and-egg problem: We can't check the compiler before the project() call, but we have to set the policies before it. # Weird chicken-and-egg problem: We can't check the compiler before the project() call, but we have to set the policies before it.
# So we do this in two steps: Set the policies if they exist, then error out afterwards if we end up being MSVC and they don't exist. # So we do this in two steps: Set the policies if they exist, then error out afterwards if we end up being MSVC and they don't exist.
if (POLICY CMP0117) if (POLICY CMP0117)
@ -693,7 +697,11 @@ endif()
add_subdirectory(Externals/imgui) add_subdirectory(Externals/imgui)
add_subdirectory(Externals/implot) add_subdirectory(Externals/implot)
add_subdirectory(Externals/glslang) add_subdirectory(Externals/glslang)
add_subdirectory(Externals/spirv_cross) # SPIRV-Cross is used on Windows for GLSL to HLSL conversion for the Direct3D 11 and Direct3D 12
# video backends, and on Apple devices for the Metal video backend.
if(WIN32 OR APPLE)
add_subdirectory(Externals/spirv_cross)
endif()
if(ENABLE_VULKAN) if(ENABLE_VULKAN)
add_definitions(-DHAS_VULKAN) add_definitions(-DHAS_VULKAN)

View file

@ -499,7 +499,6 @@ a9010014 39200002
04456F08 C0028008 04456F08 C0028008
0445650C 3BFF0004 0445650C 3BFF0004
E2000001 80008000 E2000001 80008000
*Board animations happen faster. *Board animations happen faster.
$QOL - Increased Capsule Throwing Speed [gamemasterplc] $QOL - Increased Capsule Throwing Speed [gamemasterplc]
@ -523,7 +522,7 @@ $QOL - Instant Text Display [gamemasterplc]
0404a560 38000000 0404a560 38000000
*Text is displayed instantly. *Text is displayed instantly.
$QOL - Show Controller Port Number of Who Paused in Mini-Games [gamemasterplc] $QOL - Show Controller Port Number of Who Paused [gamemasterplc]
C2040178 00000002 C2040178 00000002
807F0050 906D0000 807F0050 906D0000
38600000 00000000 38600000 00000000
@ -710,30 +709,30 @@ C20C8FA0 0000001B
*Improves the RNG of what items are received. *Improves the RNG of what items are received.
*Null items can be retrieved. To Dispose of throw on any space. *Null items can be retrieved. To Dispose of throw on any space.
$Mechanics - Last 5 Turns Happens on the First Turn [Nayla] $Mechanics: "Last 5 Turns" Event - Happens on the First Turn [Nayla]
0480CB88 2C040001 0480CB88 2C040001
0408CB8C 41800048 0408CB8C 41800048
$Mechanics - Last 5 Turns is x3 Coins on Spaces [Nayla] $Mechanics: "Last 5 Turns" Event - is x3 Coins on Spaces [Nayla]
040FB87C 38A00000 040FB87C 38A00000
040FB8EC 3A600000 040FB8EC 3A600000
*Last 5 Turns Event is always x3 Coins on Spaces. *Last 5 Turns Event is always x3 Coins on Spaces.
$Mechanics - Last 5 Turns is 5 Star Spaces [Nayla] $Mechanics: "Last 5 Turns" Event - is 5 Star Spaces [Nayla]
040FB87C 38A00003 040FB87C 38A00003
040FB8EC 3A600003 040FB8EC 3A600003
*Last 5 Turns Event is always 5 Star Spaces. *Last 5 Turns Event is always 5 Star Spaces.
$Mechanics - Last 5 Turns is Capsule Spaces on Every Space [Nayla] $Mechanics: "Last 5 Turns" Event - is All Capsule Spaces [Nayla]
040FB87C 38A00001 040FB87C 38A00001
040FB8EC 3A600001 040FB8EC 3A600001
*Last 5 Turns Event forces all spaces to Have Capsule Events. *Last 5 Turns Event forces all spaces to Have Capsule Events.
$Mechanics - Last 5 Turns is Disabled [Nayla] $Mechanics: "Last 5 Turns" Event - is Disabled [Nayla]
0408D1F4 41800048 0408D1F4 41800048
*Last 5 Turns Event never happens. *Last 5 Turns Event never happens.
$Mechanics - Last 5 Turns is Red Spaces are Bowser Spaces [Nayla] $Mechanics: "Last 5 Turns" Event - is Red Spaces are Bowser Spaces [Nayla]
040FB87C 38A00002 040FB87C 38A00002
040FB8EC 3A6000012 040FB8EC 3A6000012
*Last 5 Turns Event forces Red Spaces to turn into Bowser Spaces. *Last 5 Turns Event forces Red Spaces to turn into Bowser Spaces.
@ -785,7 +784,7 @@ B00D8CD4 AAAD8CD4
$Mechanics - Same Space Duels Always Happen [Nayla] $Mechanics - Same Space Duels Always Happen [Nayla]
04094740 60000000 04094740 60000000
*Duels never happen if you are on the same space. *Duels always happen if you are on the same space
$Mechanics - Same Space Duels Don't Happen [Nayla] $Mechanics - Same Space Duels Don't Happen [Nayla]
04094740 48000030 04094740 48000030

View file

@ -508,7 +508,7 @@ $QOL - Instant Text Display [Celerizer]
0404f51c 38000000 0404f51c 38000000
*Text is displayed instantly. *Text is displayed instantly.
$QOL - Show Controller Port Number of Who Paused in Mini-Games [Celerizer] $QOL - Show Controller Port Number of Who Paused [Celerizer]
C20456D4 00000002 C20456D4 00000002
807F0050 906D0000 807F0050 906D0000
38600000 00000000 38600000 00000000
@ -543,6 +543,12 @@ F6000001 80008180
80A405A0 38800001 80A405A0 38800001
14000000 38A0FFFF 14000000 38A0FFFF
E0000000 80008000 E0000000 80008000
F6000002 80008180
5460D808 54640FFE
7C040050 5400283E
14000020 3C80FFFF
14000024 6084FFFF
E0000000 80008000
*Unlocks Everything in the game. *Unlocks Everything in the game.
$Board - Faire Square: Free Whomps [gamemasterplc] $Board - Faire Square: Free Whomps [gamemasterplc]
@ -791,7 +797,7 @@ $Mechanics - Gain 20 Coins on Blue Spaces
$Mechanics - Gain 40 Coins on Blue Spaces $Mechanics - Gain 40 Coins on Blue Spaces
0415F1E8 3BC00028 0415F1E8 3BC00028
$Mechanics - Last 5 Turns Happens on the First Turn [Ralf] $Mechanics: "Last 5 Turns" Event - Happens on the First Turn [Ralf]
06005170 0000001C 06005170 0000001C
3C608026 88835B74 3C608026 88835B74
88035B75 7C040050 88035B75 7C040050
@ -800,7 +806,7 @@ $Mechanics - Last 5 Turns Happens on the First Turn [Ralf]
0414B6C8 60000000 0414B6C8 60000000
0414B704 4BEB9A6D 0414B704 4BEB9A6D
$Mechanics - Last 5 Turns Happens after Turn 5 [Ralf] $Mechanics: "Last 5 Turns" Event - Happens after Turn 5 [Ralf]
06005170 0000001C 06005170 0000001C
3C608026 88835B74 3C608026 88835B74
88035B75 7C040050 88035B75 7C040050
@ -809,24 +815,24 @@ $Mechanics - Last 5 Turns Happens after Turn 5 [Ralf]
0414B6C8 60000000 0414B6C8 60000000
0414B704 4BEB9A6D 0414B704 4BEB9A6D
$Mechanics - Last 5 Turns is x3 Coins on Spaces [gamemasterplc] $Mechanics: "Last 5 Turns" Event - is x3 Coins on Spaces [gamemasterplc]
04202314 38000000 04202314 38000000
*Last 5 Turns Event is always x3 Coins on spaces. *Last 5 Turns Event is always x3 Coins on spaces.
$Mechanics - Last 5 Turns is 40 Coin Bonus [gamemasterplc] $Mechanics: "Last 5 Turns" Event - is 40 Coin Bonus [gamemasterplc]
04202314 38000001 04202314 38000001
*Last 5 Turns Event is always a 40 coin bonus for last place. *Last 5 Turns Event is always a 40 coin bonus for last place.
$Mechanics - Last 5 Turns is 5 Character Spaces [gamemasterplc] $Mechanics: "Last 5 Turns" Event - is 5 Character Spaces [gamemasterplc]
04202314 38000002 [gamemasterplc] 04202314 38000002 [gamemasterplc]
*Last 5 Turns Event is always 5 extra character spaces for last place. *Last 5 Turns Event is always 5 extra character spaces for last place.
$Mechanics - Last 5 Turns is Bowser Revolution [gamemasterplc] $Mechanics: "Last 5 Turns" Event - is Bowser Revolution [gamemasterplc]
04202314 38000003 04202314 38000003
*Last 5 Turns Event is always a Bowser Revolution. *Last 5 Turns Event is always a Bowser Revolution.
*This makes everyones coins equal. *This makes everyones coins equal.
$Mechanics - Last 5 Turns is Disabled [Ralf] $Mechanics: "Last 5 Turns" Event - is Disabled [Ralf]
0414B6C8 4800007C 0414B6C8 4800007C
*Last 5 Turns event is disabled *Last 5 Turns event is disabled

View file

@ -629,7 +629,7 @@ $QOL - Instant Text Display [gamemasterplc]
04050a70 38800000 04050a70 38800000
*Text is displayed instantly. *Text is displayed instantly.
$QOL - Show Controller Port Number of Who Paused in Mini-Games [gamemasterplc] $QOL - Show Controller Port Number of Who Paused [gamemasterplc]
c2047400 00000002 c2047400 00000002
807f0050 906d0000 807f0050 906d0000
38600000 00000000 38600000 00000000
@ -1039,10 +1039,6 @@ $Mechanics - Hammer Bro Orb Steals 20 Coins [Ralf]
*Hammer Bro steals 20 coins instead of 10 when landing on his space. *Hammer Bro steals 20 coins instead of 10 when landing on his space.
$Mechanics - Happening Star Becomes Star Star [Airsola] $Mechanics - Happening Star Becomes Star Star [Airsola]
204e4ae0 48000210
044e4a38 48000014
044e4a6c 38000000
e2000001 80008000
204e16ec 8903001f 204e16ec 8903001f
044e16ec 8903003b 044e16ec 8903003b
e2000001 80008000 e2000001 80008000
@ -1050,7 +1046,6 @@ e2000001 80008000
044e1a0c 8903003b 044e1a0c 8903003b
e2000001 80008000 e2000001 80008000
*The Happening Star will become a bonus star awarded to the player who held the highest amount of stars at any point of the game. Recommended only for Windmillville, or Pyramid Park. *The Happening Star will become a bonus star awarded to the player who held the highest amount of stars at any point of the game. Recommended only for Windmillville, or Pyramid Park.
*Incompatible with Fixed Bonus Star because it implements it.
$Mechanics - Improved Duel Results [Airsola] $Mechanics - Improved Duel Results [Airsola]
c21d8ed0 00000007 c21d8ed0 00000007
@ -1071,38 +1066,38 @@ C21D8ED0 00000003
60000000 00000000 60000000 00000000
*(X) -> 1/2 Coins *(X) -> 1/2 Coins
$Mechanics - Last 5 Turns Event Happens on the First Turn [Ralf] $Mechanics: "Last 5 Turns" Event - Happens on the First Turn [Ralf]
04152070 2C040001 04152070 2C040001
04152074 4080011C 04152074 4080011C
041521AC 2C040001 041521AC 2C040001
041521B0 41800044 041521B0 41800044
$Mechanics - Last 5 Turns Event Happens after Turn 5 [Ralf] $Mechanics: "Last 5 Turns" Event - Happens after Turn 5 [Ralf]
04152070 2C040006 04152070 2C040006
04152074 4080011C 04152074 4080011C
041521AC 2C040006 041521AC 2C040006
041521B0 41800044 041521B0 41800044
$Mechanics - Last 5 Turns Event Is Always x3 Coins on Spaces [gamemasterplc] $Mechanics: "Last 5 Turns" Event - is x3 Coins on Spaces [gamemasterplc]
042311A8 38000000 042311A8 38000000
$Mechanics - Last 5 Turns Event Is Always 10 More Koopa Kid Spaces [gamemasterplc] $Mechanics: "Last 5 Turns" Event - is Always 10 More Koopa Kid Spaces [gamemasterplc]
042311A8 38000001 042311A8 38000001
$Mechanics - Last 5 Turns Event Is Always 40 Coin Bonus [gamemasterplc] $Mechanics: "Last 5 Turns" Event - is Always 40 Coin Bonus [gamemasterplc]
042311A8 38000002 042311A8 38000002
$Mechanics - Last 5 Turns Event Is Always Stars are 10 Coins [gamemasterplc] $Mechanics: "Last 5 Turns" Event - is Always Stars are 10 Coins [gamemasterplc]
042311A8 38000003 042311A8 38000003
$Mechanics - Last 5 Turns Event Is Always Red Spaces are Bowser Spaces [gamemasterplc] $Mechanics: "Last 5 Turns" Event - is Always Red Spaces are Bowser Spaces [gamemasterplc]
042311A8 38000004 042311A8 38000004
$Mechanics - Last 5 Turns Event Is Always Chain Chomp Ride for 5 Coins (Pyramid Park) [gamemasterplc] $Mechanics: "Last 5 Turns" Event - is Always Chain Chomp Ride for 5 Coins (Pyramid Park) [gamemasterplc]
042311A8 38000005 042311A8 38000005
*Only use on Pyramid Park *Only use on Pyramid Park
$Mechanics - Last 5 Turns Event Is Disabled [Ralf] $Mechanics: "Last 5 Turns" Event - is Disabled [Ralf]
04152074 60000000 04152074 60000000
041521B0 48000044 041521B0 48000044
@ -1137,10 +1132,6 @@ $Mechanics - Microphone Always Off [gamemasterplc]
*Microphone game setting stays off while playing Mario Party 7. *Microphone game setting stays off while playing Mario Party 7.
$Mechanics - Orb Star Becomes Coin Star [Airsola] $Mechanics - Orb Star Becomes Coin Star [Airsola]
204e4ae0 48000210
044e4a38 48000014
044e4a6c 38000000
e2000001 80008000
204e16b0 a8ca003c 204e16b0 a8ca003c
044e16b0 a8ca002c 044e16b0 a8ca002c
e2000001 80008000 e2000001 80008000
@ -1148,8 +1139,6 @@ e2000001 80008000
044e18d4 a8c3002c 044e18d4 a8c3002c
e2000001 80008000 e2000001 80008000
*The return of the classic Coin Star. *The return of the classic Coin Star.
*Incompatible with Fixed Bonus Star because it implements it.
$Mechanics - Orbs Can Only Be Placed On Your Current Space [gamemasterplc] $Mechanics - Orbs Can Only Be Placed On Your Current Space [gamemasterplc]
041e7128 60000000 041e7128 60000000
@ -1162,7 +1151,7 @@ $Mechanics - Piranha Plant Takes ALL Coins [gamemasterplc]
$Mechanics - Slow Shroom Orb Rolls 1-3 [gamemasterplc] $Mechanics - Slow Shroom Orb Rolls 1-3 [gamemasterplc]
0418CCC8 38000003 0418CCC8 38000003
0418D1AC 40820020 0418D1AC 40820020
*Orb is morew balanced. *Orb is more balanced.
$Mechanics - Slow Shroom Orb Rolls 1-5 [gamemasterplc] $Mechanics - Slow Shroom Orb Rolls 1-5 [gamemasterplc]
0418ccc8 38000005 0418ccc8 38000005
@ -1172,7 +1161,6 @@ $Mechanics - Slow Shroom Orb Rolls 1-5 [gamemasterplc]
$Mechanics - Stars Cost 40 coins [Ralf] $Mechanics - Stars Cost 40 coins [Ralf]
0418876c 3b800005 0418876c 3b800005
04188774 3b80000A 04188774 3b80000A
*Only works in Grand Canal and Bowser's Enchanted Inferno *Only works in Grand Canal and Bowser's Enchanted Inferno
$Mechanics - Use Multiple Orbs in the Same Turn [Ralf] $Mechanics - Use Multiple Orbs in the Same Turn [Ralf]
@ -1229,7 +1217,7 @@ $Minigame: La Bomba - Always 4 Bombs [Airsola, Rain]
044e8cf4 00000004 044e8cf4 00000004
e2000001 80008000 e2000001 80008000
$Minigame: Jump Man - Player is Slower $Minigame: Jump Man - Player is Slower [gamemasterplc]
204EF0C0 40768000 204EF0C0 40768000
044EF0B8 3C430C12 044EF0B8 3C430C12
E2000001 80008000 E2000001 80008000
@ -1263,7 +1251,7 @@ $Minigame: Target Tag - All Targets Worth 50 Points [gamemasterplc]
044EAC28 38800032 044EAC28 38800032
E2000001 80008000 E2000001 80008000
$Minigame: Vine Country - DK is Faster $Minigame: Vine Country - DK is Faster [gamemasterplc]
204E5EE8 901F0174 204E5EE8 901F0174
044E5EE4 3803FFFE 044E5EE4 3803FFFE
E2000001 80008000 E2000001 80008000

View file

@ -1,6 +1,6 @@
include(ExternalProject) include(ExternalProject)
set(MOLTENVK_VERSION "v1.2.2") set(MOLTENVK_VERSION "v1.2.3")
ExternalProject_Add(MoltenVK ExternalProject_Add(MoltenVK
GIT_REPOSITORY https://github.com/KhronosGroup/MoltenVK.git GIT_REPOSITORY https://github.com/KhronosGroup/MoltenVK.git

2
Externals/SDL/SDL vendored

@ -1 +1 @@
Subproject commit f741adc86c8f5e7fc5c1863cf0d5e08b899d6209 Subproject commit ac13ca9ab691e13e8eebe9684740ddcb0d716203

@ -1 +1 @@
Subproject commit c5304a61bcf256ae80fcd1c8f64ad9646aaea757 Subproject commit d9e990e6d13527532b7e2bb23164a1f3b7f33bb5

View file

@ -1,6 +1,6 @@
# Dolphin - A GameCube and Wii Emulator # Dolphin - A GameCube and Wii Emulator
[Homepage](https://dolphin-emu.org/) | [Project Site](https://github.com/dolphin-emu/dolphin) | [Buildbot](https://dolphin.ci/) | [Forums](https://forums.dolphin-emu.org/) | [Wiki](https://wiki.dolphin-emu.org/) | [GitHub Wiki](https://github.com/dolphin-emu/dolphin/wiki) | [Issue Tracker](https://bugs.dolphin-emu.org/projects/emulator/issues) | [Coding Style](https://github.com/dolphin-emu/dolphin/blob/master/Contributing.md) | [Transifex Page](https://explore.transifex.com/delroth/dolphin-emu/) [Homepage](https://dolphin-emu.org/) | [Project Site](https://github.com/dolphin-emu/dolphin) | [Buildbot](https://dolphin.ci/) | [Forums](https://forums.dolphin-emu.org/) | [Wiki](https://wiki.dolphin-emu.org/) | [GitHub Wiki](https://github.com/dolphin-emu/dolphin/wiki) | [Issue Tracker](https://bugs.dolphin-emu.org/projects/emulator/issues) | [Coding Style](https://github.com/dolphin-emu/dolphin/blob/master/Contributing.md) | [Transifex Page](https://app.transifex.com/delroth/dolphin-emu/dashboard/)
Dolphin is an emulator for running GameCube and Wii games on Windows, Dolphin is an emulator for running GameCube and Wii games on Windows,
Linux, macOS, and recent Android devices. It's licensed under the terms Linux, macOS, and recent Android devices. It's licensed under the terms

View file

@ -40,7 +40,6 @@ android {
} }
defaultConfig { defaultConfig {
// TODO If this is ever modified, change application_id in strings.xml
applicationId "org.dolphinemu.dolphinemu" applicationId "org.dolphinemu.dolphinemu"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 33 targetSdkVersion 33
@ -74,6 +73,7 @@ android {
signingConfig signingConfigs.release signingConfig signingConfigs.release
} }
resValue 'string', 'app_name_suffixed', 'Dolphin Emulator'
minifyEnabled true minifyEnabled true
shrinkResources true shrinkResources true
proguardFiles getDefaultProguardFile( proguardFiles getDefaultProguardFile(
@ -86,13 +86,14 @@ android {
// Signed by debug key disallowing distribution on Play Store. // Signed by debug key disallowing distribution on Play Store.
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build. // Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
debug { debug {
// TODO If this is ever modified, change application_id in debug/strings.xml resValue 'string', 'app_name_suffixed', 'Dolphin Debug'
applicationIdSuffix ".debug" applicationIdSuffix ".debug"
versionNameSuffix '-debug' versionNameSuffix '-debug'
jniDebuggable true jniDebuggable true
} }
benchmark { benchmark {
resValue 'string', 'app_name_suffixed', 'Dolphin Benchmark'
signingConfig signingConfigs.debug signingConfig signingConfigs.debug
matchingFallbacks = ['release'] matchingFallbacks = ['release']
debuggable false debuggable false

View file

@ -31,7 +31,7 @@
<application <application
android:name=".DolphinApplication" android:name=".DolphinApplication"
android:label="@string/app_name" android:label="@string/app_name_suffixed"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:requestLegacyExternalStorage="true" android:requestLegacyExternalStorage="true"
android:preserveLegacyExternalStorage="true" android:preserveLegacyExternalStorage="true"
@ -97,7 +97,7 @@
<activity <activity
android:name=".activities.CustomFilePickerActivity" android:name=".activities.CustomFilePickerActivity"
android:exported="false" android:exported="false"
android:label="@string/app_name" android:label="@string/app_name_suffixed"
android:theme="@style/Theme.Dolphin.FilePicker"> android:theme="@style/Theme.Dolphin.FilePicker">
<intent-filter> <intent-filter>

View file

@ -54,12 +54,11 @@ class DocumentProvider : DocumentsProvider() {
override fun queryRoots(projection: Array<String>?): Cursor { override fun queryRoots(projection: Array<String>?): Cursor {
val result = MatrixCursor(projection ?: DEFAULT_ROOT_PROJECTION) val result = MatrixCursor(projection ?: DEFAULT_ROOT_PROJECTION)
rootDirectory = rootDirectory ?: DirectoryInitialization.getUserDirectoryPath(context)
rootDirectory ?: return result rootDirectory ?: return result
result.newRow().apply { result.newRow().apply {
add(DocumentsContract.Root.COLUMN_ROOT_ID, ROOT_ID) add(DocumentsContract.Root.COLUMN_ROOT_ID, ROOT_ID)
add(DocumentsContract.Root.COLUMN_TITLE, context!!.getString(R.string.app_name)) add(DocumentsContract.Root.COLUMN_TITLE, context!!.getString(R.string.app_name_suffixed))
add(DocumentsContract.Root.COLUMN_ICON, R.drawable.ic_dolphin) add(DocumentsContract.Root.COLUMN_ICON, R.drawable.ic_dolphin)
add( add(
DocumentsContract.Root.COLUMN_FLAGS, DocumentsContract.Root.COLUMN_FLAGS,
@ -73,7 +72,6 @@ class DocumentProvider : DocumentsProvider() {
override fun queryDocument(documentId: String, projection: Array<String>?): Cursor { override fun queryDocument(documentId: String, projection: Array<String>?): Cursor {
val result = MatrixCursor(projection ?: DEFAULT_DOCUMENT_PROJECTION) val result = MatrixCursor(projection ?: DEFAULT_DOCUMENT_PROJECTION)
rootDirectory = rootDirectory ?: DirectoryInitialization.getUserDirectoryPath(context)
rootDirectory ?: return result rootDirectory ?: return result
val file = documentIdToPath(documentId) val file = documentIdToPath(documentId)
appendDocument(file, result) appendDocument(file, result)
@ -102,7 +100,9 @@ class DocumentProvider : DocumentsProvider() {
documentId: String, documentId: String,
mode: String, mode: String,
signal: CancellationSignal? signal: CancellationSignal?
): ParcelFileDescriptor { ): ParcelFileDescriptor? {
rootDirectory ?: return null
val file = documentIdToPath(documentId) val file = documentIdToPath(documentId)
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.parseMode(mode)) return ParcelFileDescriptor.open(file, ParcelFileDescriptor.parseMode(mode))
} }
@ -111,7 +111,9 @@ class DocumentProvider : DocumentsProvider() {
parentDocumentId: String, parentDocumentId: String,
mimeType: String, mimeType: String,
displayName: String displayName: String
): String { ): String? {
rootDirectory ?: return null
val folder = documentIdToPath(parentDocumentId) val folder = documentIdToPath(parentDocumentId)
val file = findFileNameForNewFile(File(folder, displayName)) val file = findFileNameForNewFile(File(folder, displayName))
if (mimeType == DocumentsContract.Document.MIME_TYPE_DIR) { if (mimeType == DocumentsContract.Document.MIME_TYPE_DIR) {
@ -122,56 +124,40 @@ class DocumentProvider : DocumentsProvider() {
return pathToDocumentId(file) return pathToDocumentId(file)
} }
override fun copyDocument(sourceDocumentId: String, targetParentDocumentId: String): String { override fun deleteDocument(documentId: String) {
val file = documentIdToPath(sourceDocumentId) rootDirectory ?: return
val target = documentIdToPath(targetParentDocumentId)
val copy = copyRecursively(file, File(target, file.name))
return pathToDocumentId(copy)
}
override fun removeDocument(documentId: String, parentDocumentId: String) {
val file = documentIdToPath(documentId) val file = documentIdToPath(documentId)
file.deleteRecursively() file.deleteRecursively()
} }
override fun moveDocument( override fun renameDocument(documentId: String, displayName: String): String? {
sourceDocumentId: String, rootDirectory ?: return null
sourceParentDocumentId: String,
targetParentDocumentId: String val file = documentIdToPath(documentId)
): String { val dest = findFileNameForNewFile(File(file.parentFile, displayName))
val copy = copyDocument(sourceDocumentId, targetParentDocumentId) file.renameTo(dest)
val file = documentIdToPath(sourceDocumentId) return pathToDocumentId(dest)
file.delete()
return copy
} }
override fun renameDocument(documentId: String, displayName: String): String { override fun isChildDocument(parentDocumentId: String, documentId: String): Boolean
val file = documentIdToPath(documentId) = documentId.startsWith(parentDocumentId)
file.renameTo(findFileNameForNewFile(File(file.parentFile, displayName)))
return pathToDocumentId(file)
}
override fun isChildDocument(parentDocumentId: String, documentId: String): Boolean {
val file = documentIdToPath(documentId)
val folder = documentIdToPath(parentDocumentId)
return file.relativeToOrNull(folder) != null
}
private fun appendDocument(file: File, cursor: MatrixCursor) { private fun appendDocument(file: File, cursor: MatrixCursor) {
var flags = 0 var flags = 0
if (file.isDirectory && file.canWrite()) { if (file.canWrite()) {
flags = DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE flags = if (file.isDirectory) {
} else if (file.canWrite()) { DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE
flags = DocumentsContract.Document.FLAG_SUPPORTS_WRITE } else {
DocumentsContract.Document.FLAG_SUPPORTS_WRITE
}
flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_DELETE flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_DELETE
flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_REMOVE
flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_MOVE
flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_COPY
flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_RENAME flags = flags or DocumentsContract.Document.FLAG_SUPPORTS_RENAME
// The system will handle copy + move for us
} }
val name = if (file == rootDirectory) { val name = if (file == rootDirectory) {
context!!.getString(R.string.app_name) context!!.getString(R.string.app_name_suffixed)
} else { } else {
file.name file.name
} }
@ -217,22 +203,6 @@ class DocumentProvider : DocumentsProvider() {
unusedFile = File("$pathWithoutExtension.$i.$extension") unusedFile = File("$pathWithoutExtension.$i.$extension")
i++ i++
} }
return file return unusedFile
}
private fun copyRecursively(src: File, dst: File): File {
val actualDst = findFileNameForNewFile(dst)
if (src.isDirectory) {
actualDst.mkdirs()
val children = src.listFiles()
if (children !== null) {
for (file in children) {
copyRecursively(file, File(actualDst, file.name))
}
}
} else {
src.copyTo(actualDst)
}
return actualDst
} }
} }

View file

@ -77,6 +77,7 @@ public final class MainActivity extends AppCompatActivity
setInsets(); setInsets();
ThemeHelper.enableStatusBarScrollTint(this, mBinding.appbarMain); ThemeHelper.enableStatusBarScrollTint(this, mBinding.appbarMain);
mBinding.toolbarMain.setTitle(R.string.app_name);
setSupportActionBar(mBinding.toolbarMain); setSupportActionBar(mBinding.toolbarMain);
// Set up the FAB. // Set up the FAB.

View file

@ -137,12 +137,12 @@ Java_org_dolphinemu_dolphinemu_features_cheats_model_ARCheat_loadCodes(JNIEnv* e
jint revision) jint revision)
{ {
const std::string game_id = GetJString(env, jGameID); const std::string game_id = GetJString(env, jGameID);
IniFile game_ini_local; Common::IniFile game_ini_local;
// We don't use LoadLocalGameIni() here because user cheat codes that are installed via the UI // We don't use LoadLocalGameIni() here because user cheat codes that are installed via the UI
// will always be stored in GS/${GAMEID}.ini // will always be stored in GS/${GAMEID}.ini
game_ini_local.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini"); game_ini_local.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini");
const IniFile game_ini_default = SConfig::LoadDefaultGameIni(game_id, revision); const Common::IniFile game_ini_default = SConfig::LoadDefaultGameIni(game_id, revision);
const std::vector<ActionReplay::ARCode> codes = const std::vector<ActionReplay::ARCode> codes =
ActionReplay::LoadCodes(game_ini_default, game_ini_local); ActionReplay::LoadCodes(game_ini_default, game_ini_local);
@ -167,7 +167,7 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_features_cheats_model_ARCh
const std::string game_id = GetJString(env, jGameID); const std::string game_id = GetJString(env, jGameID);
const std::string ini_path = File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini"; const std::string ini_path = File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini";
IniFile game_ini_local; Common::IniFile game_ini_local;
game_ini_local.Load(ini_path); game_ini_local.Load(ini_path);
ActionReplay::SaveCodes(&game_ini_local, vector); ActionReplay::SaveCodes(&game_ini_local, vector);
game_ini_local.Save(ini_path); game_ini_local.Save(ini_path);

View file

@ -146,12 +146,12 @@ Java_org_dolphinemu_dolphinemu_features_cheats_model_GeckoCheat_loadCodes(JNIEnv
jint revision) jint revision)
{ {
const std::string game_id = GetJString(env, jGameID); const std::string game_id = GetJString(env, jGameID);
IniFile game_ini_local; Common::IniFile game_ini_local;
// We don't use LoadLocalGameIni() here because user cheat codes that are installed via the UI // We don't use LoadLocalGameIni() here because user cheat codes that are installed via the UI
// will always be stored in GS/${GAMEID}.ini // will always be stored in GS/${GAMEID}.ini
game_ini_local.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini"); game_ini_local.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini");
const IniFile game_ini_default = SConfig::LoadDefaultGameIni(game_id, revision); const Common::IniFile game_ini_default = SConfig::LoadDefaultGameIni(game_id, revision);
const std::vector<Gecko::GeckoCode> codes = Gecko::LoadCodes(game_ini_default, game_ini_local); const std::vector<Gecko::GeckoCode> codes = Gecko::LoadCodes(game_ini_default, game_ini_local);
@ -175,7 +175,7 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_features_cheats_model_Geck
const std::string game_id = GetJString(env, jGameID); const std::string game_id = GetJString(env, jGameID);
const std::string ini_path = File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini"; const std::string ini_path = File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini";
IniFile game_ini_local; Common::IniFile game_ini_local;
game_ini_local.Load(ini_path); game_ini_local.Load(ini_path);
Gecko::SaveCodes(game_ini_local, vector); Gecko::SaveCodes(game_ini_local, vector);
game_ini_local.Save(ini_path); game_ini_local.Save(ini_path);

View file

@ -124,12 +124,12 @@ Java_org_dolphinemu_dolphinemu_features_cheats_model_PatchCheat_loadCodes(JNIEnv
jint revision) jint revision)
{ {
const std::string game_id = GetJString(env, jGameID); const std::string game_id = GetJString(env, jGameID);
IniFile game_ini_local; Common::IniFile game_ini_local;
// We don't use LoadLocalGameIni() here because user cheat codes that are installed via the UI // We don't use LoadLocalGameIni() here because user cheat codes that are installed via the UI
// will always be stored in GS/${GAMEID}.ini // will always be stored in GS/${GAMEID}.ini
game_ini_local.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini"); game_ini_local.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini");
const IniFile game_ini_default = SConfig::LoadDefaultGameIni(game_id, revision); const Common::IniFile game_ini_default = SConfig::LoadDefaultGameIni(game_id, revision);
std::vector<PatchEngine::Patch> patches; std::vector<PatchEngine::Patch> patches;
PatchEngine::LoadPatchSection("OnFrame", &patches, game_ini_default, game_ini_local); PatchEngine::LoadPatchSection("OnFrame", &patches, game_ini_default, game_ini_local);
@ -154,7 +154,7 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_features_cheats_model_Patc
const std::string game_id = GetJString(env, jGameID); const std::string game_id = GetJString(env, jGameID);
const std::string ini_path = File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini"; const std::string ini_path = File::GetUserPath(D_GAMESETTINGS_IDX) + game_id + ".ini";
IniFile game_ini_local; Common::IniFile game_ini_local;
game_ini_local.Load(ini_path); game_ini_local.Load(ini_path);
PatchEngine::SavePatchSection(&game_ini_local, vector); PatchEngine::SavePatchSection(&game_ini_local, vector);
game_ini_local.Save(ini_path); game_ini_local.Save(ini_path);

View file

@ -7,6 +7,8 @@
#include "jni/AndroidCommon/AndroidCommon.h" #include "jni/AndroidCommon/AndroidCommon.h"
#include "jni/AndroidCommon/IDCache.h" #include "jni/AndroidCommon/IDCache.h"
using Common::IniFile;
static IniFile::Section* GetSectionPointer(JNIEnv* env, jobject obj) static IniFile::Section* GetSectionPointer(JNIEnv* env, jobject obj)
{ {
return reinterpret_cast<IniFile::Section*>( return reinterpret_cast<IniFile::Section*>(

View file

@ -91,7 +91,7 @@ Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_EmulatedContro
ControllerEmu::EmulatedController* controller = EmulatedControllerFromJava(env, obj); ControllerEmu::EmulatedController* controller = EmulatedControllerFromJava(env, obj);
// Loading an empty IniFile section clears everything. // Loading an empty IniFile section clears everything.
IniFile::Section section; Common::IniFile::Section section;
controller->LoadConfig(&section); controller->LoadConfig(&section);
controller->UpdateReferences(g_controller_interface); controller->UpdateReferences(g_controller_interface);
@ -103,7 +103,7 @@ Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_EmulatedContro
{ {
ControllerEmu::EmulatedController* controller = EmulatedControllerFromJava(env, obj); ControllerEmu::EmulatedController* controller = EmulatedControllerFromJava(env, obj);
IniFile ini; Common::IniFile ini;
ini.Load(GetJString(env, j_path)); ini.Load(GetJString(env, j_path));
controller->LoadConfig(ini.GetOrCreateSection("Profile")); controller->LoadConfig(ini.GetOrCreateSection("Profile"));
@ -118,7 +118,7 @@ Java_org_dolphinemu_dolphinemu_features_input_model_controlleremu_EmulatedContro
File::CreateFullPath(path); File::CreateFullPath(path);
IniFile ini; Common::IniFile ini;
EmulatedControllerFromJava(env, obj)->SaveConfig(ini.GetOrCreateSection("Profile")); EmulatedControllerFromJava(env, obj)->SaveConfig(ini.GetOrCreateSection("Profile"));
ini.Save(path); ini.Save(path);

View file

@ -3092,7 +3092,7 @@ void ARM64FloatEmitter::FMOV(ARM64Reg Rd, uint8_t imm8)
// Vector // Vector
void ARM64FloatEmitter::ADD(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) void ARM64FloatEmitter::ADD(u8 size, ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm)
{ {
EmitThreeSame(0, IntLog2(size) - 3, 0b10000, Rd, Rn, Rm); EmitThreeSame(0, MathUtil::IntLog2(size) - 3, 0b10000, Rd, Rn, Rm);
} }
void ARM64FloatEmitter::AND(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm) void ARM64FloatEmitter::AND(ARM64Reg Rd, ARM64Reg Rn, ARM64Reg Rm)
{ {

View file

@ -41,8 +41,8 @@ add_library(common
DebugInterface.h DebugInterface.h
DynamicLibrary.cpp DynamicLibrary.cpp
DynamicLibrary.h DynamicLibrary.h
ENetUtil.cpp ENet.cpp
ENetUtil.h ENet.h
EnumFormatter.h EnumFormatter.h
EnumMap.h EnumMap.h
Event.h Event.h
@ -80,7 +80,6 @@ add_library(common
Logging/Log.h Logging/Log.h
Logging/LogManager.cpp Logging/LogManager.cpp
Logging/LogManager.h Logging/LogManager.h
MathUtil.cpp
MathUtil.h MathUtil.h
Matrix.cpp Matrix.cpp
Matrix.h Matrix.h
@ -299,7 +298,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(common PUBLIC dl rt) target_link_libraries(common PUBLIC dl rt)
endif() endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Windows") if(WIN32)
target_sources(common PRIVATE HRWrap.h HRWrap.cpp) target_sources(common PRIVATE HRWrap.h HRWrap.cpp)
endif() endif()

View file

@ -13,6 +13,8 @@
#define strerror_r(err, buf, len) strerror_s(buf, len, err) #define strerror_r(err, buf, len) strerror_s(buf, len, err)
#endif #endif
namespace Common
{
constexpr size_t BUFFER_SIZE = 256; constexpr size_t BUFFER_SIZE = 256;
// Wrapper function to get last strerror(errno) string. // Wrapper function to get last strerror(errno) string.
@ -73,3 +75,4 @@ std::optional<std::wstring> GetModuleName(void* hInstance)
return name; return name;
} }
#endif #endif
} // namespace Common

View file

@ -39,6 +39,8 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
} }
#endif // WIN32 ndef #endif // WIN32 ndef
namespace Common
{
// Wrapper function to get last strerror(errno) string. // Wrapper function to get last strerror(errno) string.
// This function might change the error code. // This function might change the error code.
std::string LastStrerrorString(); std::string LastStrerrorString();
@ -51,3 +53,4 @@ std::string GetLastErrorString();
// Obtains a full path to the specified module. // Obtains a full path to the specified module.
std::optional<std::wstring> GetModuleName(void* hInstance); std::optional<std::wstring> GetModuleName(void* hInstance);
#endif #endif
} // namespace Common

View file

@ -170,7 +170,7 @@ static std::optional<std::wstring> GetModulePath(const wchar_t* name)
if (module == nullptr) if (module == nullptr)
return std::nullopt; return std::nullopt;
return GetModuleName(module); return Common::GetModuleName(module);
} }
static bool GetModuleVersion(const wchar_t* name, Version* version) static bool GetModuleVersion(const wchar_t* name, Version* version)

View file

@ -3,42 +3,45 @@
#include "Common/Crypto/bn.h" #include "Common/Crypto/bn.h"
#include <cstddef>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
static void bn_zero(u8* d, int n) static void bn_zero(u8* d, const size_t n)
{ {
std::memset(d, 0, n); std::memset(d, 0, n);
} }
static void bn_copy(u8* d, const u8* a, int n) static void bn_copy(u8* d, const u8* a, const size_t n)
{ {
std::memcpy(d, a, n); std::memcpy(d, a, n);
} }
int bn_compare(const u8* a, const u8* b, int n) int bn_compare(const u8* a, const u8* b, const size_t n)
{ {
return std::memcmp(a, b, n); return std::memcmp(a, b, n);
} }
void bn_sub_modulus(u8* a, const u8* N, int n) void bn_sub_modulus(u8* a, const u8* N, const size_t n)
{ {
u8 c = 0; u8 c = 0;
for (int i = n - 1; i >= 0; --i) for (size_t i = n; i > 0;)
{ {
--i;
u32 dig = N[i] + c; u32 dig = N[i] + c;
c = (a[i] < dig); c = (a[i] < dig);
a[i] -= dig; a[i] -= dig;
} }
} }
void bn_add(u8* d, const u8* a, const u8* b, const u8* N, int n) void bn_add(u8* d, const u8* a, const u8* b, const u8* N, const size_t n)
{ {
u8 c = 0; u8 c = 0;
for (int i = n - 1; i >= 0; --i) for (size_t i = n; i > 0;)
{ {
--i;
u32 dig = a[i] + b[i] + c; u32 dig = a[i] + b[i] + c;
c = (dig >= 0x100); c = (dig >= 0x100);
d[i] = dig; d[i] = dig;
@ -51,11 +54,11 @@ void bn_add(u8* d, const u8* a, const u8* b, const u8* N, int n)
bn_sub_modulus(d, N, n); bn_sub_modulus(d, N, n);
} }
void bn_mul(u8* d, const u8* a, const u8* b, const u8* N, int n) void bn_mul(u8* d, const u8* a, const u8* b, const u8* N, const size_t n)
{ {
bn_zero(d, n); bn_zero(d, n);
for (int i = 0; i < n; i++) for (size_t i = 0; i < n; i++)
{ {
for (u8 mask = 0x80; mask != 0; mask >>= 1) for (u8 mask = 0x80; mask != 0; mask >>= 1)
{ {
@ -66,13 +69,13 @@ void bn_mul(u8* d, const u8* a, const u8* b, const u8* N, int n)
} }
} }
void bn_exp(u8* d, const u8* a, const u8* N, int n, const u8* e, int en) void bn_exp(u8* d, const u8* a, const u8* N, const size_t n, const u8* e, const size_t en)
{ {
u8 t[512]; u8 t[512];
bn_zero(d, n); bn_zero(d, n);
d[n - 1] = 1; d[n - 1] = 1;
for (int i = 0; i < en; i++) for (size_t i = 0; i < en; i++)
{ {
for (u8 mask = 0x80; mask != 0; mask >>= 1) for (u8 mask = 0x80; mask != 0; mask >>= 1)
{ {
@ -86,7 +89,7 @@ void bn_exp(u8* d, const u8* a, const u8* N, int n, const u8* e, int en)
} }
// only for prime N -- stupid but lazy, see if I care // only for prime N -- stupid but lazy, see if I care
void bn_inv(u8* d, const u8* a, const u8* N, int n) void bn_inv(u8* d, const u8* a, const u8* N, const size_t n)
{ {
u8 t[512], s[512]; u8 t[512], s[512];

View file

@ -3,13 +3,15 @@
#pragma once #pragma once
#include <cstddef>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
// bignum arithmetic // bignum arithmetic
int bn_compare(const u8* a, const u8* b, int n); int bn_compare(const u8* a, const u8* b, size_t n);
void bn_sub_modulus(u8* a, const u8* N, int n); void bn_sub_modulus(u8* a, const u8* N, size_t n);
void bn_add(u8* d, const u8* a, const u8* b, const u8* N, int n); void bn_add(u8* d, const u8* a, const u8* b, const u8* N, size_t n);
void bn_mul(u8* d, const u8* a, const u8* b, const u8* N, int n); void bn_mul(u8* d, const u8* a, const u8* b, const u8* N, size_t n);
void bn_inv(u8* d, const u8* a, const u8* N, int n); // only for prime N void bn_inv(u8* d, const u8* a, const u8* N, size_t n); // only for prime N
void bn_exp(u8* d, const u8* a, const u8* N, int n, const u8* e, int en); void bn_exp(u8* d, const u8* a, const u8* N, size_t n, const u8* e, size_t en);

View file

@ -126,16 +126,18 @@ InstructionAttributes CodeTrace::GetInstructionAttributes(const TraceOutput& ins
TraceOutput CodeTrace::SaveCurrentInstruction(const Core::CPUThreadGuard& guard) const TraceOutput CodeTrace::SaveCurrentInstruction(const Core::CPUThreadGuard& guard) const
{ {
auto& system = guard.GetSystem(); auto& system = guard.GetSystem();
auto& ppc_state = system.GetPPCState(); auto& power_pc = system.GetPowerPC();
auto& ppc_state = power_pc.GetPPCState();
auto& debug_interface = power_pc.GetDebugInterface();
// Quickly save instruction and memory target for fast logging. // Quickly save instruction and memory target for fast logging.
TraceOutput output; TraceOutput output;
const std::string instr = PowerPC::debug_interface.Disassemble(&guard, ppc_state.pc); const std::string instr = debug_interface.Disassemble(&guard, ppc_state.pc);
output.instruction = instr; output.instruction = instr;
output.address = ppc_state.pc; output.address = ppc_state.pc;
if (IsInstructionLoadStore(output.instruction)) if (IsInstructionLoadStore(output.instruction))
output.memory_target = PowerPC::debug_interface.GetMemoryAddressFromInstruction(instr); output.memory_target = debug_interface.GetMemoryAddressFromInstruction(instr);
return output; return output;
} }
@ -189,16 +191,17 @@ AutoStepResults CodeTrace::AutoStepping(const Core::CPUThreadGuard& guard, bool
else if (stop_on == AutoStop::Changed) else if (stop_on == AutoStop::Changed)
stop_condition = HitType::ACTIVE; stop_condition = HitType::ACTIVE;
PowerPC::breakpoints.ClearAllTemporary(); auto& power_pc = guard.GetSystem().GetPowerPC();
power_pc.GetBreakPoints().ClearAllTemporary();
using clock = std::chrono::steady_clock; using clock = std::chrono::steady_clock;
clock::time_point timeout = clock::now() + std::chrono::seconds(4); clock::time_point timeout = clock::now() + std::chrono::seconds(4);
PowerPC::CoreMode old_mode = PowerPC::GetMode(); PowerPC::CoreMode old_mode = power_pc.GetMode();
PowerPC::SetMode(PowerPC::CoreMode::Interpreter); power_pc.SetMode(PowerPC::CoreMode::Interpreter);
do do
{ {
PowerPC::SingleStep(); power_pc.SingleStep();
pc_instr = SaveCurrentInstruction(guard); pc_instr = SaveCurrentInstruction(guard);
hit = TraceLogic(pc_instr); hit = TraceLogic(pc_instr);
@ -210,7 +213,7 @@ AutoStepResults CodeTrace::AutoStepping(const Core::CPUThreadGuard& guard, bool
if (clock::now() >= timeout) if (clock::now() >= timeout)
results.timed_out = true; results.timed_out = true;
PowerPC::SetMode(old_mode); power_pc.SetMode(old_mode);
m_recording = false; m_recording = false;
results.reg_tracked = m_reg_autotrack; results.reg_tracked = m_reg_autotrack;

View file

@ -1,12 +1,12 @@
// Copyright 2015 Dolphin Emulator Project // Copyright 2015 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "Common/ENetUtil.h" #include "Common/ENet.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
namespace ENetUtil namespace Common::ENet
{ {
void WakeupThread(ENetHost* host) void WakeupThread(ENetHost* host)
{ {
@ -62,4 +62,4 @@ bool SendPacket(ENetPeer* socket, const sf::Packet& packet, u8 channel_id)
return true; return true;
} }
} // namespace ENetUtil } // namespace Common::ENet

View file

@ -3,15 +3,22 @@
// //
#pragma once #pragma once
#include <enet/enet.h> #include <memory>
#include <SFML/Network/Packet.hpp> #include <SFML/Network/Packet.hpp>
#include <enet/enet.h>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
namespace ENetUtil namespace Common::ENet
{ {
struct ENetHostDeleter
{
void operator()(ENetHost* host) const noexcept { enet_host_destroy(host); }
};
using ENetHostPtr = std::unique_ptr<ENetHost, ENetHostDeleter>;
void WakeupThread(ENetHost* host); void WakeupThread(ENetHost* host);
int ENET_CALLBACK InterceptCallback(ENetHost* host, ENetEvent* event); int ENET_CALLBACK InterceptCallback(ENetHost* host, ENetEvent* event);
bool SendPacket(ENetPeer* socket, const sf::Packet& packet, u8 channel_id); bool SendPacket(ENetPeer* socket, const sf::Packet& packet, u8 channel_id);
} // namespace ENetUtil } // namespace Common::ENet

View file

@ -358,14 +358,14 @@ u64 GetSize(FILE* f)
const u64 pos = ftello(f); const u64 pos = ftello(f);
if (fseeko(f, 0, SEEK_END) != 0) if (fseeko(f, 0, SEEK_END) != 0)
{ {
ERROR_LOG_FMT(COMMON, "GetSize: seek failed {}: {}", fmt::ptr(f), LastStrerrorString()); ERROR_LOG_FMT(COMMON, "GetSize: seek failed {}: {}", fmt::ptr(f), Common::LastStrerrorString());
return 0; return 0;
} }
const u64 size = ftello(f); const u64 size = ftello(f);
if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0))
{ {
ERROR_LOG_FMT(COMMON, "GetSize: seek failed {}: {}", fmt::ptr(f), LastStrerrorString()); ERROR_LOG_FMT(COMMON, "GetSize: seek failed {}: {}", fmt::ptr(f), Common::LastStrerrorString());
return 0; return 0;
} }
@ -379,7 +379,7 @@ bool CreateEmptyFile(const std::string& filename)
if (!File::IOFile(filename, "wb")) if (!File::IOFile(filename, "wb"))
{ {
ERROR_LOG_FMT(COMMON, "CreateEmptyFile: failed {}: {}", filename, LastStrerrorString()); ERROR_LOG_FMT(COMMON, "CreateEmptyFile: failed {}: {}", filename, Common::LastStrerrorString());
return false; return false;
} }
@ -486,7 +486,7 @@ FSTEntry ScanDirectoryTree(std::string directory, bool recursive)
} }
else if (cur_depth < prev_depth) else if (cur_depth < prev_depth)
{ {
while (dir_fsts.size() - 1 != cur_depth) while (dir_fsts.size() != static_cast<size_t>(cur_depth) + 1u)
{ {
calc_dir_size(dir_fsts.top()); calc_dir_size(dir_fsts.top());
dir_fsts.pop(); dir_fsts.pop();
@ -726,7 +726,7 @@ std::string GetBundleDirectory()
std::string GetExePath() std::string GetExePath()
{ {
#ifdef _WIN32 #ifdef _WIN32
auto exe_path = GetModuleName(nullptr); auto exe_path = Common::GetModuleName(nullptr);
if (!exe_path) if (!exe_path)
return {}; return {};
std::error_code error; std::error_code error;

View file

@ -155,7 +155,8 @@ bool GLContextGLX::Initialize(const WindowSystemInfo& wsi, bool stereo, bool cor
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, None}}; GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, None}};
s_glxError = false; s_glxError = false;
m_context = glXCreateContextAttribs(m_display, m_fbconfig, 0, True, &context_attribs[0]); m_context =
glXCreateContextAttribs(m_display, m_fbconfig, nullptr, True, &context_attribs[0]);
XSync(m_display, False); XSync(m_display, False);
if (!m_context || s_glxError) if (!m_context || s_glxError)
continue; continue;
@ -174,7 +175,8 @@ bool GLContextGLX::Initialize(const WindowSystemInfo& wsi, bool stereo, bool cor
std::array<int, 5> context_attribs_legacy = { std::array<int, 5> context_attribs_legacy = {
{GLX_CONTEXT_MAJOR_VERSION_ARB, 1, GLX_CONTEXT_MINOR_VERSION_ARB, 0, None}}; {GLX_CONTEXT_MAJOR_VERSION_ARB, 1, GLX_CONTEXT_MINOR_VERSION_ARB, 0, None}};
s_glxError = false; s_glxError = false;
m_context = glXCreateContextAttribs(m_display, m_fbconfig, 0, True, &context_attribs_legacy[0]); m_context =
glXCreateContextAttribs(m_display, m_fbconfig, nullptr, True, &context_attribs_legacy[0]);
XSync(m_display, False); XSync(m_display, False);
m_attribs.clear(); m_attribs.clear();
m_attribs.insert(m_attribs.end(), context_attribs_legacy.begin(), context_attribs_legacy.end()); m_attribs.insert(m_attribs.end(), context_attribs_legacy.begin(), context_attribs_legacy.end());

View file

@ -69,7 +69,7 @@ private:
struct Storage struct Storage
{ {
std::mutex m_mutex; std::recursive_mutex m_mutex;
std::vector<HookImpl*> m_listeners; std::vector<HookImpl*> m_listeners;
}; };

View file

@ -33,8 +33,8 @@ public:
Response Fetch(const std::string& url, Method method, const Headers& headers, const u8* payload, Response Fetch(const std::string& url, Method method, const Headers& headers, const u8* payload,
size_t size, AllowedReturnCodes codes = AllowedReturnCodes::Ok_Only); size_t size, AllowedReturnCodes codes = AllowedReturnCodes::Ok_Only);
static int CurlProgressCallback(Impl* impl, double dlnow, double dltotal, double ulnow, static int CurlProgressCallback(Impl* impl, curl_off_t dltotal, curl_off_t dlnow,
double ultotal); curl_off_t ultotal, curl_off_t ulnow);
std::string EscapeComponent(const std::string& string); std::string EscapeComponent(const std::string& string);
private: private:
@ -95,11 +95,12 @@ HttpRequest::Response HttpRequest::Post(const std::string& url, const std::strin
reinterpret_cast<const u8*>(payload.data()), payload.size(), codes); reinterpret_cast<const u8*>(payload.data()), payload.size(), codes);
} }
int HttpRequest::Impl::CurlProgressCallback(Impl* impl, double dlnow, double dltotal, double ulnow, int HttpRequest::Impl::CurlProgressCallback(Impl* impl, curl_off_t dltotal, curl_off_t dlnow,
double ultotal) curl_off_t ultotal, curl_off_t ulnow)
{ {
// Abort if callback isn't true // Abort if callback isn't true
return !impl->m_callback(dlnow, dltotal, ulnow, ultotal); return !impl->m_callback(static_cast<s64>(dltotal), static_cast<s64>(dlnow),
static_cast<s64>(ultotal), static_cast<s64>(ulnow));
} }
HttpRequest::Impl::Impl(std::chrono::milliseconds timeout_ms, ProgressCallback callback) HttpRequest::Impl::Impl(std::chrono::milliseconds timeout_ms, ProgressCallback callback)
@ -116,7 +117,7 @@ HttpRequest::Impl::Impl(std::chrono::milliseconds timeout_ms, ProgressCallback c
if (m_callback) if (m_callback)
{ {
curl_easy_setopt(m_curl.get(), CURLOPT_PROGRESSDATA, this); curl_easy_setopt(m_curl.get(), CURLOPT_PROGRESSDATA, this);
curl_easy_setopt(m_curl.get(), CURLOPT_PROGRESSFUNCTION, CurlProgressCallback); curl_easy_setopt(m_curl.get(), CURLOPT_XFERINFOFUNCTION, CurlProgressCallback);
} }
// Set up error buffer // Set up error buffer

View file

@ -25,8 +25,7 @@ public:
}; };
// Return false to abort the request // Return false to abort the request
using ProgressCallback = using ProgressCallback = std::function<bool(s64 dltotal, s64 dlnow, s64 ultotal, s64 ulnow)>;
std::function<bool(double dlnow, double dltotal, double ulnow, double ultotal)>;
explicit HttpRequest(std::chrono::milliseconds timeout_ms = std::chrono::milliseconds{3000}, explicit HttpRequest(std::chrono::milliseconds timeout_ms = std::chrono::milliseconds{3000},
ProgressCallback callback = nullptr); ProgressCallback callback = nullptr);

View file

@ -15,6 +15,8 @@
#include "Common/FileUtil.h" #include "Common/FileUtil.h"
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
namespace Common
{
void IniFile::ParseLine(std::string_view line, std::string* keyOut, std::string* valueOut) void IniFile::ParseLine(std::string_view line, std::string* keyOut, std::string* valueOut)
{ {
if (line.empty() || line.front() == '#') if (line.empty() || line.front() == '#')
@ -369,3 +371,4 @@ bool IniFile::Save(const std::string& filename)
return 0; return 0;
} }
*/ */
} // namespace Common

View file

@ -13,6 +13,8 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
namespace Common
{
struct CaseInsensitiveStringCompare struct CaseInsensitiveStringCompare
{ {
// Allow heterogenous lookup. // Allow heterogenous lookup.
@ -166,3 +168,4 @@ private:
static const std::string& NULL_STRING; static const std::string& NULL_STRING;
}; };
} // namespace Common

View file

@ -27,6 +27,8 @@
// value_type[value_size] value; // value_type[value_size] value;
//} //}
namespace Common
{
template <typename K, typename V> template <typename K, typename V>
class LinearDiskCacheReader class LinearDiskCacheReader
{ {
@ -163,3 +165,4 @@ private:
File::IOFile m_file; File::IOFile m_file;
u32 m_num_entries = 0; u32 m_num_entries = 0;
}; };
} // namespace Common

View file

@ -1,12 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "Common/MathUtil.h"
#include <numeric>
// Calculate sum of a float list
float MathFloatVectorSum(const std::vector<float>& Vec)
{
return std::accumulate(Vec.begin(), Vec.end(), 0.0f);
}

View file

@ -8,7 +8,6 @@
#include <cmath> #include <cmath>
#include <limits> #include <limits>
#include <type_traits> #include <type_traits>
#include <vector>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
@ -186,12 +185,9 @@ private:
T m_variance{}; T m_variance{};
}; };
} // namespace MathUtil
float MathFloatVectorSum(const std::vector<float>&);
// Rounds down. 0 -> undefined // Rounds down. 0 -> undefined
constexpr int IntLog2(u64 val) constexpr int IntLog2(u64 val)
{ {
return 63 - std::countl_zero(val); return 63 - std::countl_zero(val);
} }
} // namespace MathUtil

View file

@ -250,7 +250,7 @@ size_t MemPhysical()
mib[1] = HW_PHYSMEM64; mib[1] = HW_PHYSMEM64;
#endif #endif
size_t length = sizeof(size_t); size_t length = sizeof(size_t);
sysctl(mib, 2, &physical_memory, &length, NULL, 0); sysctl(mib, 2, &physical_memory, &length, nullptr, 0);
return physical_memory; return physical_memory;
#elif defined __HAIKU__ #elif defined __HAIKU__
system_info sysinfo; system_info sysinfo;

View file

@ -70,12 +70,10 @@ std::string SettingsHandler::GetValue(std::string_view key) const
void SettingsHandler::Decrypt() void SettingsHandler::Decrypt()
{ {
const u8* str = m_buffer.data();
while (m_position < m_buffer.size()) while (m_position < m_buffer.size())
{ {
decoded.push_back((u8)(m_buffer[m_position] ^ m_key)); decoded.push_back((u8)(m_buffer[m_position] ^ m_key));
m_position++; m_position++;
str++;
m_key = (m_key >> 31) | (m_key << 1); m_key = (m_key >> 31) | (m_key << 1);
} }

View file

@ -304,7 +304,7 @@ int ENET_CALLBACK TraversalClient::InterceptCallback(ENetHost* host, ENetEvent*
} }
std::unique_ptr<TraversalClient> g_TraversalClient; std::unique_ptr<TraversalClient> g_TraversalClient;
std::unique_ptr<ENetHost> g_MainNetHost; Common::ENet::ENetHostPtr g_MainNetHost;
// The settings at the previous TraversalClient reset - notably, we // The settings at the previous TraversalClient reset - notably, we
// need to know not just what port it's on, but whether it was // need to know not just what port it's on, but whether it was
@ -323,18 +323,18 @@ bool EnsureTraversalClient(const std::string& server, u16 server_port, u16 liste
g_OldListenPort = listen_port; g_OldListenPort = listen_port;
ENetAddress addr = {ENET_HOST_ANY, listen_port}; ENetAddress addr = {ENET_HOST_ANY, listen_port};
ENetHost* host = enet_host_create(&addr, // address auto host = Common::ENet::ENetHostPtr{enet_host_create(&addr, // address
50, // peerCount 50, // peerCount
NetPlay::CHANNEL_COUNT, // channelLimit NetPlay::CHANNEL_COUNT, // channelLimit
0, // incomingBandwidth 0, // incomingBandwidth
0); // outgoingBandwidth 0)}; // outgoingBandwidth
if (!host) if (!host)
{ {
g_MainNetHost.reset(); g_MainNetHost.reset();
return false; return false;
} }
host->mtu = std::min(host->mtu, NetPlay::MAX_ENET_MTU); host->mtu = std::min(host->mtu, NetPlay::MAX_ENET_MTU);
g_MainNetHost.reset(host); g_MainNetHost = std::move(host);
g_TraversalClient.reset(new TraversalClient(g_MainNetHost.get(), server, server_port)); g_TraversalClient.reset(new TraversalClient(g_MainNetHost.get(), server, server_port));
} }
return true; return true;

View file

@ -11,6 +11,7 @@
#include <enet/enet.h> #include <enet/enet.h>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/ENet.h"
#include "Common/Thread.h" #include "Common/Thread.h"
#include "Common/TraversalProto.h" #include "Common/TraversalProto.h"
@ -91,7 +92,7 @@ private:
}; };
extern std::unique_ptr<TraversalClient> g_TraversalClient; extern std::unique_ptr<TraversalClient> g_TraversalClient;
// the NetHost connected to the TraversalClient. // the NetHost connected to the TraversalClient.
extern std::unique_ptr<ENetHost> g_MainNetHost; extern Common::ENet::ENetHostPtr g_MainNetHost;
// Create g_TraversalClient and g_MainNetHost if necessary. // Create g_TraversalClient and g_MainNetHost if necessary.
bool EnsureTraversalClient(const std::string& server, u16 server_port, u16 listen_port = 0); bool EnsureTraversalClient(const std::string& server, u16 server_port, u16 listen_port = 0);
void ReleaseTraversalClient(); void ReleaseTraversalClient();

View file

@ -1,5 +1,4 @@
// Copyright 2021 Dolphin Emulator Project // SPDX-License-Identifier: CC0-1.0
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once

View file

@ -164,14 +164,14 @@ static void UnmapPortThread()
UnmapPort(s_mapped); UnmapPort(s_mapped);
} }
void UPnP::TryPortmapping(u16 port) void Common::UPnP::TryPortmapping(u16 port)
{ {
if (s_thread.joinable()) if (s_thread.joinable())
s_thread.join(); s_thread.join();
s_thread = std::thread(&MapPortThread, port); s_thread = std::thread(&MapPortThread, port);
} }
void UPnP::StopPortmapping() void Common::UPnP::StopPortmapping()
{ {
if (s_thread.joinable()) if (s_thread.joinable())
s_thread.join(); s_thread.join();

View file

@ -7,10 +7,10 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
namespace UPnP namespace Common::UPnP
{ {
void TryPortmapping(u16 port); void TryPortmapping(u16 port);
void StopPortmapping(); void StopPortmapping();
} // namespace UPnP } // namespace Common::UPnP
#endif #endif

View file

@ -1106,6 +1106,7 @@ public:
template <typename FunctionPointer> template <typename FunctionPointer>
void ABI_CallFunctionPR(FunctionPointer func, const void* ptr, X64Reg reg1) void ABI_CallFunctionPR(FunctionPointer func, const void* ptr, X64Reg reg1)
{ {
if (reg1 != ABI_PARAM2)
MOV(64, R(ABI_PARAM2), R(reg1)); MOV(64, R(ABI_PARAM2), R(reg1));
MOV(64, R(ABI_PARAM1), Imm64(reinterpret_cast<u64>(ptr))); MOV(64, R(ABI_PARAM1), Imm64(reinterpret_cast<u64>(ptr)));
ABI_CallFunction(func); ABI_CallFunction(func);

View file

@ -4,10 +4,17 @@
#ifdef USE_RETRO_ACHIEVEMENTS #ifdef USE_RETRO_ACHIEVEMENTS
#include "Core/AchievementManager.h" #include "Core/AchievementManager.h"
#include <array>
#include <rcheevos/include/rc_hash.h>
#include "Common/HttpRequest.h" #include "Common/HttpRequest.h"
#include "Common/WorkQueueThread.h" #include "Common/WorkQueueThread.h"
#include "Config/AchievementSettings.h" #include "Config/AchievementSettings.h"
#include "Core/Core.h" #include "Core/Core.h"
#include "DiscIO/Volume.h"
static constexpr bool hardcore_mode_enabled = false;
AchievementManager* AchievementManager::GetInstance() AchievementManager* AchievementManager::GetInstance()
{ {
@ -28,49 +35,337 @@ void AchievementManager::Init()
AchievementManager::ResponseType AchievementManager::Login(const std::string& password) AchievementManager::ResponseType AchievementManager::Login(const std::string& password)
{ {
if (!m_is_runtime_initialized)
return AchievementManager::ResponseType::MANAGER_NOT_INITIALIZED;
return VerifyCredentials(password); return VerifyCredentials(password);
} }
void AchievementManager::LoginAsync(const std::string& password, const LoginCallback& callback) void AchievementManager::LoginAsync(const std::string& password, const ResponseCallback& callback)
{ {
if (!m_is_runtime_initialized)
{
callback(AchievementManager::ResponseType::MANAGER_NOT_INITIALIZED);
return;
}
m_queue.EmplaceItem([this, password, callback] { callback(VerifyCredentials(password)); }); m_queue.EmplaceItem([this, password, callback] { callback(VerifyCredentials(password)); });
} }
bool AchievementManager::IsLoggedIn() const bool AchievementManager::IsLoggedIn() const
{ {
return m_login_data.response.succeeded; return !Config::Get(Config::RA_API_TOKEN).empty();
}
void AchievementManager::LoadGameByFilenameAsync(const std::string& iso_path,
const ResponseCallback& callback)
{
if (!m_is_runtime_initialized)
{
callback(AchievementManager::ResponseType::MANAGER_NOT_INITIALIZED);
return;
}
struct FilereaderState
{
int64_t position = 0;
std::unique_ptr<DiscIO::Volume> volume;
};
rc_hash_filereader volume_reader{
.open = [](const char* path_utf8) -> void* {
auto state = std::make_unique<FilereaderState>();
state->volume = DiscIO::CreateVolume(path_utf8);
if (!state->volume)
return nullptr;
return state.release();
},
.seek =
[](void* file_handle, int64_t offset, int origin) {
switch (origin)
{
case SEEK_SET:
reinterpret_cast<FilereaderState*>(file_handle)->position = offset;
break;
case SEEK_CUR:
reinterpret_cast<FilereaderState*>(file_handle)->position += offset;
break;
case SEEK_END:
// Unused
break;
}
},
.tell =
[](void* file_handle) {
return reinterpret_cast<FilereaderState*>(file_handle)->position;
},
.read =
[](void* file_handle, void* buffer, size_t requested_bytes) {
FilereaderState* filereader_state = reinterpret_cast<FilereaderState*>(file_handle);
bool success = (filereader_state->volume->Read(
filereader_state->position, requested_bytes, reinterpret_cast<u8*>(buffer),
DiscIO::PARTITION_NONE));
if (success)
{
filereader_state->position += requested_bytes;
return requested_bytes;
}
else
{
return static_cast<size_t>(0);
}
},
.close = [](void* file_handle) { delete reinterpret_cast<FilereaderState*>(file_handle); }};
rc_hash_init_custom_filereader(&volume_reader);
std::array<char, HASH_LENGTH> game_hash;
if (!rc_hash_generate_from_file(game_hash.data(), RC_CONSOLE_GAMECUBE, iso_path.c_str()))
return;
m_queue.EmplaceItem([this, callback, game_hash] {
const auto resolve_hash_response = ResolveHash(game_hash);
if (resolve_hash_response != ResponseType::SUCCESS || m_game_id == 0)
{
callback(resolve_hash_response);
return;
}
const auto start_session_response = StartRASession();
if (start_session_response != ResponseType::SUCCESS)
{
callback(start_session_response);
return;
}
const auto fetch_game_data_response = FetchGameData();
m_is_game_loaded = fetch_game_data_response == ResponseType::SUCCESS;
// Claim the lock, then queue the fetch unlock data calls, then initialize the unlock map in
// ActivateDeactiveAchievements. This allows the calls to process while initializing the
// unlock map but then forces them to wait until it's initialized before making modifications to
// it.
{
std::lock_guard lg{m_lock};
LoadUnlockData([](ResponseType r_type) {});
ActivateDeactivateAchievements();
}
ActivateDeactivateLeaderboards();
ActivateDeactivateRichPresence();
callback(fetch_game_data_response);
});
}
void AchievementManager::LoadUnlockData(const ResponseCallback& callback)
{
m_queue.EmplaceItem([this, callback] {
const auto hardcore_unlock_response = FetchUnlockData(true);
if (hardcore_unlock_response != ResponseType::SUCCESS)
{
callback(hardcore_unlock_response);
return;
}
callback(FetchUnlockData(false));
});
}
void AchievementManager::ActivateDeactivateAchievements()
{
bool enabled = Config::Get(Config::RA_ACHIEVEMENTS_ENABLED);
bool unofficial = Config::Get(Config::RA_UNOFFICIAL_ENABLED);
bool encore = Config::Get(Config::RA_ENCORE_ENABLED);
for (u32 ix = 0; ix < m_game_data.num_achievements; ix++)
{
auto iter =
m_unlock_map.insert({m_game_data.achievements[ix].id, UnlockStatus{.game_data_index = ix}});
ActivateDeactivateAchievement(iter.first->first, enabled, unofficial, encore);
}
}
void AchievementManager::ActivateDeactivateLeaderboards()
{
bool leaderboards_enabled = Config::Get(Config::RA_LEADERBOARDS_ENABLED);
for (u32 ix = 0; ix < m_game_data.num_leaderboards; ix++)
{
auto leaderboard = m_game_data.leaderboards[ix];
if (m_is_game_loaded && leaderboards_enabled && hardcore_mode_enabled)
{
rc_runtime_activate_lboard(&m_runtime, leaderboard.id, leaderboard.definition, nullptr, 0);
}
else
{
rc_runtime_deactivate_lboard(&m_runtime, m_game_data.leaderboards[ix].id);
}
}
}
void AchievementManager::ActivateDeactivateRichPresence()
{
rc_runtime_activate_richpresence(
&m_runtime,
(m_is_game_loaded && Config::Get(Config::RA_RICH_PRESENCE_ENABLED)) ?
m_game_data.rich_presence_script :
"",
nullptr, 0);
}
void AchievementManager::CloseGame()
{
m_is_game_loaded = false;
m_game_id = 0;
m_queue.Cancel();
m_unlock_map.clear();
ActivateDeactivateAchievements();
ActivateDeactivateLeaderboards();
ActivateDeactivateRichPresence();
} }
void AchievementManager::Logout() void AchievementManager::Logout()
{ {
CloseGame();
Config::SetBaseOrCurrent(Config::RA_API_TOKEN, ""); Config::SetBaseOrCurrent(Config::RA_API_TOKEN, "");
rc_api_destroy_login_response(&m_login_data);
m_login_data.response.succeeded = 0;
} }
void AchievementManager::Shutdown() void AchievementManager::Shutdown()
{ {
CloseGame();
m_is_runtime_initialized = false; m_is_runtime_initialized = false;
m_queue.Shutdown(); m_queue.Shutdown();
// DON'T log out - keep those credentials for next run. // DON'T log out - keep those credentials for next run.
rc_api_destroy_login_response(&m_login_data);
m_login_data.response.succeeded = 0;
rc_runtime_destroy(&m_runtime); rc_runtime_destroy(&m_runtime);
} }
AchievementManager::ResponseType AchievementManager::VerifyCredentials(const std::string& password) AchievementManager::ResponseType AchievementManager::VerifyCredentials(const std::string& password)
{ {
rc_api_login_response_t login_data{};
std::string username = Config::Get(Config::RA_USERNAME); std::string username = Config::Get(Config::RA_USERNAME);
std::string api_token = Config::Get(Config::RA_API_TOKEN); std::string api_token = Config::Get(Config::RA_API_TOKEN);
rc_api_login_request_t login_request = { rc_api_login_request_t login_request = {
.username = username.c_str(), .api_token = api_token.c_str(), .password = password.c_str()}; .username = username.c_str(), .api_token = api_token.c_str(), .password = password.c_str()};
ResponseType r_type = Request<rc_api_login_request_t, rc_api_login_response_t>( ResponseType r_type = Request<rc_api_login_request_t, rc_api_login_response_t>(
login_request, &m_login_data, rc_api_init_login_request, rc_api_process_login_response); login_request, &login_data, rc_api_init_login_request, rc_api_process_login_response);
if (r_type == ResponseType::SUCCESS) if (r_type == ResponseType::SUCCESS)
Config::SetBaseOrCurrent(Config::RA_API_TOKEN, m_login_data.api_token); Config::SetBaseOrCurrent(Config::RA_API_TOKEN, login_data.api_token);
rc_api_destroy_login_response(&login_data);
return r_type; return r_type;
} }
AchievementManager::ResponseType
AchievementManager::ResolveHash(std::array<char, HASH_LENGTH> game_hash)
{
rc_api_resolve_hash_response_t hash_data{};
std::string username = Config::Get(Config::RA_USERNAME);
std::string api_token = Config::Get(Config::RA_API_TOKEN);
rc_api_resolve_hash_request_t resolve_hash_request = {
.username = username.c_str(), .api_token = api_token.c_str(), .game_hash = game_hash.data()};
ResponseType r_type = Request<rc_api_resolve_hash_request_t, rc_api_resolve_hash_response_t>(
resolve_hash_request, &hash_data, rc_api_init_resolve_hash_request,
rc_api_process_resolve_hash_response);
if (r_type == ResponseType::SUCCESS)
m_game_id = hash_data.game_id;
rc_api_destroy_resolve_hash_response(&hash_data);
return r_type;
}
AchievementManager::ResponseType AchievementManager::StartRASession()
{
rc_api_start_session_response_t session_data{};
std::string username = Config::Get(Config::RA_USERNAME);
std::string api_token = Config::Get(Config::RA_API_TOKEN);
rc_api_start_session_request_t start_session_request = {
.username = username.c_str(), .api_token = api_token.c_str(), .game_id = m_game_id};
ResponseType r_type = Request<rc_api_start_session_request_t, rc_api_start_session_response_t>(
start_session_request, &session_data, rc_api_init_start_session_request,
rc_api_process_start_session_response);
rc_api_destroy_start_session_response(&session_data);
return r_type;
}
AchievementManager::ResponseType AchievementManager::FetchGameData()
{
std::string username = Config::Get(Config::RA_USERNAME);
std::string api_token = Config::Get(Config::RA_API_TOKEN);
rc_api_fetch_game_data_request_t fetch_data_request = {
.username = username.c_str(), .api_token = api_token.c_str(), .game_id = m_game_id};
return Request<rc_api_fetch_game_data_request_t, rc_api_fetch_game_data_response_t>(
fetch_data_request, &m_game_data, rc_api_init_fetch_game_data_request,
rc_api_process_fetch_game_data_response);
}
AchievementManager::ResponseType AchievementManager::FetchUnlockData(bool hardcore)
{
rc_api_fetch_user_unlocks_response_t unlock_data{};
std::string username = Config::Get(Config::RA_USERNAME);
std::string api_token = Config::Get(Config::RA_API_TOKEN);
rc_api_fetch_user_unlocks_request_t fetch_unlocks_request = {.username = username.c_str(),
.api_token = api_token.c_str(),
.game_id = m_game_id,
.hardcore = hardcore};
ResponseType r_type =
Request<rc_api_fetch_user_unlocks_request_t, rc_api_fetch_user_unlocks_response_t>(
fetch_unlocks_request, &unlock_data, rc_api_init_fetch_user_unlocks_request,
rc_api_process_fetch_user_unlocks_response);
if (r_type == ResponseType::SUCCESS)
{
std::lock_guard lg{m_lock};
bool enabled = Config::Get(Config::RA_ACHIEVEMENTS_ENABLED);
bool unofficial = Config::Get(Config::RA_UNOFFICIAL_ENABLED);
bool encore = Config::Get(Config::RA_ENCORE_ENABLED);
for (AchievementId ix = 0; ix < unlock_data.num_achievement_ids; ix++)
{
auto it = m_unlock_map.find(unlock_data.achievement_ids[ix]);
if (it == m_unlock_map.end())
continue;
it->second.remote_unlock_status =
hardcore ? UnlockStatus::UnlockType::HARDCORE : UnlockStatus::UnlockType::SOFTCORE;
ActivateDeactivateAchievement(unlock_data.achievement_ids[ix], enabled, unofficial, encore);
}
}
rc_api_destroy_fetch_user_unlocks_response(&unlock_data);
return r_type;
}
void AchievementManager::ActivateDeactivateAchievement(AchievementId id, bool enabled,
bool unofficial, bool encore)
{
auto it = m_unlock_map.find(id);
if (it == m_unlock_map.end())
return;
const UnlockStatus& status = it->second;
u32 index = status.game_data_index;
bool active = (rc_runtime_get_achievement(&m_runtime, id) != nullptr);
// Deactivate achievements if game is not loaded
bool activate = m_is_game_loaded;
// Activate achievements only if achievements are enabled
if (activate && !enabled)
activate = false;
// Deactivate if achievement is unofficial, unless unofficial achievements are enabled
if (activate && !unofficial &&
m_game_data.achievements[index].category == RC_ACHIEVEMENT_CATEGORY_UNOFFICIAL)
{
activate = false;
}
// If encore mode is on, activate/deactivate regardless of current unlock status
if (activate && !encore)
{
// Encore is off, achievement has been unlocked in this session, deactivate
activate = (status.session_unlock_count == 0);
// Encore is off, achievement has been hardcore unlocked on site, deactivate
if (activate && status.remote_unlock_status == UnlockStatus::UnlockType::HARDCORE)
activate = false;
// Encore is off, hardcore is off, achievement has been softcore unlocked on site, deactivate
if (activate && !hardcore_mode_enabled &&
status.remote_unlock_status == UnlockStatus::UnlockType::SOFTCORE)
{
activate = false;
}
}
if (!active && activate)
{
rc_runtime_activate_achievement(&m_runtime, id, m_game_data.achievements[index].definition,
nullptr, 0);
}
if (active && !activate)
rc_runtime_deactivate_achievement(&m_runtime, id);
}
// Every RetroAchievements API call, with only a partial exception for fetch_image, follows // Every RetroAchievements API call, with only a partial exception for fetch_image, follows
// the same design pattern (here, X is the name of the call): // the same design pattern (here, X is the name of the call):
// Create a specific rc_api_X_request_t struct and populate with the necessary values // Create a specific rc_api_X_request_t struct and populate with the necessary values

View file

@ -8,37 +8,58 @@
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <thread> #include <thread>
#include <unordered_map>
#include <rcheevos/include/rc_api_runtime.h>
#include <rcheevos/include/rc_api_user.h> #include <rcheevos/include/rc_api_user.h>
#include <rcheevos/include/rc_runtime.h> #include <rcheevos/include/rc_runtime.h>
#include "Common/Event.h" #include "Common/Event.h"
#include "Common/WorkQueueThread.h" #include "Common/WorkQueueThread.h"
using AchievementId = u32;
class AchievementManager class AchievementManager
{ {
public: public:
enum class ResponseType enum class ResponseType
{ {
SUCCESS, SUCCESS,
MANAGER_NOT_INITIALIZED,
INVALID_CREDENTIALS, INVALID_CREDENTIALS,
CONNECTION_FAILED, CONNECTION_FAILED,
UNKNOWN_FAILURE UNKNOWN_FAILURE
}; };
using LoginCallback = std::function<void(ResponseType)>; using ResponseCallback = std::function<void(ResponseType)>;
static AchievementManager* GetInstance(); static AchievementManager* GetInstance();
void Init(); void Init();
ResponseType Login(const std::string& password); ResponseType Login(const std::string& password);
void LoginAsync(const std::string& password, const LoginCallback& callback); void LoginAsync(const std::string& password, const ResponseCallback& callback);
bool IsLoggedIn() const; bool IsLoggedIn() const;
void LoadGameByFilenameAsync(const std::string& iso_path, const ResponseCallback& callback);
void LoadUnlockData(const ResponseCallback& callback);
void ActivateDeactivateAchievements();
void ActivateDeactivateLeaderboards();
void ActivateDeactivateRichPresence();
void CloseGame();
void Logout(); void Logout();
void Shutdown(); void Shutdown();
private: private:
AchievementManager() = default; AchievementManager() = default;
static constexpr int HASH_LENGTH = 33;
ResponseType VerifyCredentials(const std::string& password); ResponseType VerifyCredentials(const std::string& password);
ResponseType ResolveHash(std::array<char, HASH_LENGTH> game_hash);
ResponseType StartRASession();
ResponseType FetchGameData();
ResponseType FetchUnlockData(bool hardcore);
void ActivateDeactivateAchievement(AchievementId id, bool enabled, bool unofficial, bool encore);
template <typename RcRequest, typename RcResponse> template <typename RcRequest, typename RcResponse>
ResponseType Request(RcRequest rc_request, RcResponse* rc_response, ResponseType Request(RcRequest rc_request, RcResponse* rc_response,
@ -47,8 +68,25 @@ private:
rc_runtime_t m_runtime{}; rc_runtime_t m_runtime{};
bool m_is_runtime_initialized = false; bool m_is_runtime_initialized = false;
rc_api_login_response_t m_login_data{}; unsigned int m_game_id = 0;
rc_api_fetch_game_data_response_t m_game_data{};
bool m_is_game_loaded = false;
struct UnlockStatus
{
AchievementId game_data_index = 0;
enum class UnlockType
{
LOCKED,
SOFTCORE,
HARDCORE
} remote_unlock_status = UnlockType::LOCKED;
int session_unlock_count = 0;
};
std::unordered_map<AchievementId, UnlockStatus> m_unlock_map;
Common::WorkQueueThread<std::function<void()>> m_queue; Common::WorkQueueThread<std::function<void()>> m_queue;
std::recursive_mutex m_lock;
}; // class AchievementManager }; // class AchievementManager
#endif // USE_RETRO_ACHIEVEMENTS #endif // USE_RETRO_ACHIEVEMENTS

View file

@ -169,18 +169,17 @@ void AddCode(ARCode code)
} }
} }
void LoadAndApplyCodes(const IniFile& global_ini, const IniFile& local_ini) void LoadAndApplyCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini)
{ {
ApplyCodes(LoadCodes(global_ini, local_ini)); ApplyCodes(LoadCodes(global_ini, local_ini));
} }
// Parses the Action Replay section of a game ini file. // Parses the Action Replay section of a game ini file.
std::vector<ARCode> LoadCodes(const IniFile& global_ini, const IniFile& local_ini) std::vector<ARCode> LoadCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini)
{ {
std::vector<ARCode> codes; std::vector<ARCode> codes;
const IniFile* inis[2] = {&global_ini, &local_ini}; for (const auto* ini : {&global_ini, &local_ini})
for (const IniFile* ini : inis)
{ {
std::vector<std::string> lines; std::vector<std::string> lines;
std::vector<std::string> encrypted_lines; std::vector<std::string> encrypted_lines;
@ -250,7 +249,7 @@ std::vector<ARCode> LoadCodes(const IniFile& global_ini, const IniFile& local_in
return codes; return codes;
} }
void SaveCodes(IniFile* local_ini, std::span<const ARCode> codes) void SaveCodes(Common::IniFile* local_ini, std::span<const ARCode> codes)
{ {
std::vector<std::string> lines; std::vector<std::string> lines;
std::vector<std::string> enabled_lines; std::vector<std::string> enabled_lines;

View file

@ -10,7 +10,10 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
namespace Common
{
class IniFile; class IniFile;
}
namespace Core namespace Core
{ {
@ -47,10 +50,10 @@ void SetSyncedCodesAsActive();
void UpdateSyncedCodes(std::span<const ARCode> codes); void UpdateSyncedCodes(std::span<const ARCode> codes);
std::vector<ARCode> ApplyAndReturnCodes(std::span<const ARCode> codes); std::vector<ARCode> ApplyAndReturnCodes(std::span<const ARCode> codes);
void AddCode(ARCode new_code); void AddCode(ARCode new_code);
void LoadAndApplyCodes(const IniFile& global_ini, const IniFile& local_ini); void LoadAndApplyCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini);
std::vector<ARCode> LoadCodes(const IniFile& global_ini, const IniFile& local_ini); std::vector<ARCode> LoadCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini);
void SaveCodes(IniFile* local_ini, std::span<const ARCode> codes); void SaveCodes(Common::IniFile* local_ini, std::span<const ARCode> codes);
using EncryptedLine = std::string; using EncryptedLine = std::string;
std::variant<std::monostate, AREntry, EncryptedLine> DeserializeLine(const std::string& line); std::variant<std::monostate, AREntry, EncryptedLine> DeserializeLine(const std::string& line);

View file

@ -57,13 +57,14 @@ void PresetTimeBaseTicks(Core::System& system, const Core::CPUThreadGuard& guard
void CBoot::RunFunction(Core::System& system, u32 address) void CBoot::RunFunction(Core::System& system, u32 address)
{ {
auto& ppc_state = system.GetPPCState(); auto& power_pc = system.GetPowerPC();
auto& ppc_state = power_pc.GetPPCState();
ppc_state.pc = address; ppc_state.pc = address;
LR(ppc_state) = 0x00; LR(ppc_state) = 0x00;
while (ppc_state.pc != 0x00) while (ppc_state.pc != 0x00)
PowerPC::SingleStep(); power_pc.SingleStep();
} }
void CBoot::SetupMSR(PowerPC::PowerPCState& ppc_state) void CBoot::SetupMSR(PowerPC::PowerPCState& ppc_state)

View file

@ -29,6 +29,7 @@
#include "Common/IniFile.h" #include "Common/IniFile.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Core/AchievementManager.h"
#include "Core/Boot/Boot.h" #include "Core/Boot/Boot.h"
#include "Core/Config/MainSettings.h" #include "Core/Config/MainSettings.h"
#include "Core/Config/SYSCONFSettings.h" #include "Core/Config/SYSCONFSettings.h"
@ -163,6 +164,16 @@ bool BootCore(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi)
} }
} }
#ifdef USE_RETRO_ACHIEVEMENTS
std::string path = "";
if (std::holds_alternative<BootParameters::Disc>(boot->parameters))
{
path = std::get<BootParameters::Disc>(boot->parameters).path;
}
AchievementManager::GetInstance()->LoadGameByFilenameAsync(
path, [](AchievementManager::ResponseType r_type) {});
#endif // USE_RETRO_ACHIEVEMENTS
const bool load_ipl = !StartUp.bWii && !Config::Get(Config::MAIN_SKIP_IPL) && const bool load_ipl = !StartUp.bWii && !Config::Get(Config::MAIN_SKIP_IPL) &&
std::holds_alternative<BootParameters::Disc>(boot->parameters); std::holds_alternative<BootParameters::Disc>(boot->parameters);
if (load_ipl) if (load_ipl)

View file

@ -9,7 +9,7 @@
#include "Common/IniFile.h" #include "Common/IniFile.h"
template <typename T> template <typename T>
void ReadEnabledOrDisabled(const IniFile& ini, const std::string& section, bool enabled, void ReadEnabledOrDisabled(const Common::IniFile& ini, const std::string& section, bool enabled,
std::vector<T>* codes) std::vector<T>* codes)
{ {
std::vector<std::string> lines; std::vector<std::string> lines;
@ -30,7 +30,8 @@ void ReadEnabledOrDisabled(const IniFile& ini, const std::string& section, bool
} }
template <typename T> template <typename T>
void ReadEnabledAndDisabled(const IniFile& ini, const std::string& section, std::vector<T>* codes) void ReadEnabledAndDisabled(const Common::IniFile& ini, const std::string& section,
std::vector<T>* codes)
{ {
ReadEnabledOrDisabled(ini, section + "_Enabled", true, codes); ReadEnabledOrDisabled(ini, section + "_Enabled", true, codes);
ReadEnabledOrDisabled(ini, section + "_Disabled", false, codes); ReadEnabledOrDisabled(ini, section + "_Disabled", false, codes);

View file

@ -13,4 +13,13 @@ namespace Config
const Info<bool> RA_ENABLED{{System::Achievements, "Achievements", "Enabled"}, false}; const Info<bool> RA_ENABLED{{System::Achievements, "Achievements", "Enabled"}, false};
const Info<std::string> RA_USERNAME{{System::Achievements, "Achievements", "Username"}, ""}; const Info<std::string> RA_USERNAME{{System::Achievements, "Achievements", "Username"}, ""};
const Info<std::string> RA_API_TOKEN{{System::Achievements, "Achievements", "ApiToken"}, ""}; const Info<std::string> RA_API_TOKEN{{System::Achievements, "Achievements", "ApiToken"}, ""};
const Info<bool> RA_ACHIEVEMENTS_ENABLED{
{System::Achievements, "Achievements", "AchievementsEnabled"}, false};
const Info<bool> RA_LEADERBOARDS_ENABLED{
{System::Achievements, "Achievements", "LeaderboardsEnabled"}, false};
const Info<bool> RA_RICH_PRESENCE_ENABLED{
{System::Achievements, "Achievements", "RichPresenceEnabled"}, false};
const Info<bool> RA_UNOFFICIAL_ENABLED{{System::Achievements, "Achievements", "UnofficialEnabled"},
false};
const Info<bool> RA_ENCORE_ENABLED{{System::Achievements, "Achievements", "EncoreEnabled"}, false};
} // namespace Config } // namespace Config

View file

@ -11,4 +11,9 @@ namespace Config
extern const Info<bool> RA_ENABLED; extern const Info<bool> RA_ENABLED;
extern const Info<std::string> RA_USERNAME; extern const Info<std::string> RA_USERNAME;
extern const Info<std::string> RA_API_TOKEN; extern const Info<std::string> RA_API_TOKEN;
extern const Info<bool> RA_ACHIEVEMENTS_ENABLED;
extern const Info<bool> RA_LEADERBOARDS_ENABLED;
extern const Info<bool> RA_RICH_PRESENCE_ENABLED;
extern const Info<bool> RA_UNOFFICIAL_ENABLED;
extern const Info<bool> RA_ENCORE_ENABLED;
} // namespace Config } // namespace Config

View file

@ -113,14 +113,14 @@ public:
LoadFromSYSCONF(layer); LoadFromSYSCONF(layer);
for (const auto& system : system_to_ini) for (const auto& system : system_to_ini)
{ {
IniFile ini; Common::IniFile ini;
ini.Load(File::GetUserPath(system.second)); ini.Load(File::GetUserPath(system.second));
const std::list<IniFile::Section>& system_sections = ini.GetSections(); const auto& system_sections = ini.GetSections();
for (const auto& section : system_sections) for (const auto& section : system_sections)
{ {
const std::string section_name = section.GetName(); const std::string section_name = section.GetName();
const IniFile::Section::SectionMap& section_map = section.GetValues(); const auto& section_map = section.GetValues();
for (const auto& value : section_map) for (const auto& value : section_map)
{ {
@ -141,7 +141,7 @@ public:
{ {
SaveToSYSCONF(layer->GetLayer()); SaveToSYSCONF(layer->GetLayer());
std::map<Config::System, IniFile> inis; std::map<Config::System, Common::IniFile> inis;
for (const auto& system : system_to_ini) for (const auto& system : system_to_ini)
{ {
@ -176,7 +176,7 @@ public:
if (value) if (value)
{ {
IniFile::Section* ini_section = ini->second.GetOrCreateSection(location.section); auto* ini_section = ini->second.GetOrCreateSection(location.section);
ini_section->Set(location.key, *value); ini_section->Set(location.key, *value);
} }
else else

View file

@ -175,7 +175,7 @@ public:
void Load(Config::Layer* layer) override void Load(Config::Layer* layer) override
{ {
IniFile ini; Common::IniFile ini;
if (layer->GetLayer() == Config::LayerType::GlobalGame) if (layer->GetLayer() == Config::LayerType::GlobalGame)
{ {
for (const std::string& filename : GetGameIniFilenames(m_id, m_revision)) for (const std::string& filename : GetGameIniFilenames(m_id, m_revision))
@ -187,7 +187,7 @@ public:
ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + filename, true); ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + filename, true);
} }
const std::list<IniFile::Section>& system_sections = ini.GetSections(); const auto& system_sections = ini.GetSections();
for (const auto& section : system_sections) for (const auto& section : system_sections)
{ {
@ -234,11 +234,11 @@ private:
continue; continue;
} }
IniFile profile_ini; Common::IniFile profile_ini;
profile_ini.Load(ini_path); profile_ini.Load(ini_path);
const IniFile::Section* ini_section = profile_ini.GetOrCreateSection("Profile"); const auto* ini_section = profile_ini.GetOrCreateSection("Profile");
const IniFile::Section::SectionMap& section_map = ini_section->GetValues(); const auto& section_map = ini_section->GetValues();
for (const auto& value : section_map) for (const auto& value : section_map)
{ {
Config::Location location{std::get<2>(use_data), std::get<1>(use_data) + num, Config::Location location{std::get<2>(use_data), std::get<1>(use_data) + num,
@ -250,12 +250,12 @@ private:
} }
} }
void LoadFromSystemSection(Config::Layer* layer, const IniFile::Section& section) const void LoadFromSystemSection(Config::Layer* layer, const Common::IniFile::Section& section) const
{ {
const std::string section_name = section.GetName(); const std::string section_name = section.GetName();
// Regular key,value pairs // Regular key,value pairs
const IniFile::Section::SectionMap& section_map = section.GetValues(); const auto& section_map = section.GetValues();
for (const auto& value : section_map) for (const auto& value : section_map)
{ {
@ -280,7 +280,7 @@ void INIGameConfigLayerLoader::Save(Config::Layer* layer)
if (layer->GetLayer() != Config::LayerType::LocalGame) if (layer->GetLayer() != Config::LayerType::LocalGame)
return; return;
IniFile ini; Common::IniFile ini;
for (const std::string& file_name : GetGameIniFilenames(m_id, m_revision)) for (const std::string& file_name : GetGameIniFilenames(m_id, m_revision))
ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + file_name, true); ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + file_name, true);
@ -298,7 +298,7 @@ void INIGameConfigLayerLoader::Save(Config::Layer* layer)
if (value) if (value)
{ {
IniFile::Section* ini_section = ini.GetOrCreateSection(ini_location.first); auto* ini_section = ini.GetOrCreateSection(ini_location.first);
ini_section->Set(ini_location.second, *value); ini_section->Set(ini_location.second, *value);
} }
else else

View file

@ -393,40 +393,40 @@ DiscIO::Language SConfig::GetLanguageAdjustedForRegion(bool wii, DiscIO::Region
return language; return language;
} }
IniFile SConfig::LoadDefaultGameIni() const Common::IniFile SConfig::LoadDefaultGameIni() const
{ {
return LoadDefaultGameIni(GetGameID(), m_revision); return LoadDefaultGameIni(GetGameID(), m_revision);
} }
IniFile SConfig::LoadLocalGameIni() const Common::IniFile SConfig::LoadLocalGameIni() const
{ {
return LoadLocalGameIni(GetGameID(), m_revision); return LoadLocalGameIni(GetGameID(), m_revision);
} }
IniFile SConfig::LoadGameIni() const Common::IniFile SConfig::LoadGameIni() const
{ {
return LoadGameIni(GetGameID(), m_revision); return LoadGameIni(GetGameID(), m_revision);
} }
IniFile SConfig::LoadDefaultGameIni(const std::string& id, std::optional<u16> revision) Common::IniFile SConfig::LoadDefaultGameIni(const std::string& id, std::optional<u16> revision)
{ {
IniFile game_ini; Common::IniFile game_ini;
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(id, revision)) for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(id, revision))
game_ini.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename, true); game_ini.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename, true);
return game_ini; return game_ini;
} }
IniFile SConfig::LoadLocalGameIni(const std::string& id, std::optional<u16> revision) Common::IniFile SConfig::LoadLocalGameIni(const std::string& id, std::optional<u16> revision)
{ {
IniFile game_ini; Common::IniFile game_ini;
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(id, revision)) for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(id, revision))
game_ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + filename, true); game_ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + filename, true);
return game_ini; return game_ini;
} }
IniFile SConfig::LoadGameIni(const std::string& id, std::optional<u16> revision) Common::IniFile SConfig::LoadGameIni(const std::string& id, std::optional<u16> revision)
{ {
IniFile game_ini; Common::IniFile game_ini;
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(id, revision)) for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(id, revision))
game_ini.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename, true); game_ini.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename, true);
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(id, revision)) for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(id, revision))

View file

@ -14,7 +14,10 @@
#include "Common/Common.h" #include "Common/Common.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
namespace Common
{
class IniFile; class IniFile;
}
namespace Core namespace Core
{ {
@ -81,13 +84,13 @@ struct SConfig
DiscIO::Language GetCurrentLanguage(bool wii) const; DiscIO::Language GetCurrentLanguage(bool wii) const;
DiscIO::Language GetLanguageAdjustedForRegion(bool wii, DiscIO::Region region) const; DiscIO::Language GetLanguageAdjustedForRegion(bool wii, DiscIO::Region region) const;
IniFile LoadDefaultGameIni() const; Common::IniFile LoadDefaultGameIni() const;
IniFile LoadLocalGameIni() const; Common::IniFile LoadLocalGameIni() const;
IniFile LoadGameIni() const; Common::IniFile LoadGameIni() const;
static IniFile LoadDefaultGameIni(const std::string& id, std::optional<u16> revision); static Common::IniFile LoadDefaultGameIni(const std::string& id, std::optional<u16> revision);
static IniFile LoadLocalGameIni(const std::string& id, std::optional<u16> revision); static Common::IniFile LoadLocalGameIni(const std::string& id, std::optional<u16> revision);
static IniFile LoadGameIni(const std::string& id, std::optional<u16> revision); static Common::IniFile LoadGameIni(const std::string& id, std::optional<u16> revision);
SConfig(const SConfig&) = delete; SConfig(const SConfig&) = delete;
SConfig& operator=(const SConfig&) = delete; SConfig& operator=(const SConfig&) = delete;

View file

@ -38,6 +38,7 @@
#include "Common/Timer.h" #include "Common/Timer.h"
#include "Common/Version.h" #include "Common/Version.h"
#include "Core/AchievementManager.h"
#include "Core/Boot/Boot.h" #include "Core/Boot/Boot.h"
#include "Core/BootManager.h" #include "Core/BootManager.h"
#include "Core/Config/MainSettings.h" #include "Core/Config/MainSettings.h"
@ -283,6 +284,10 @@ void Stop() // - Hammertime!
if (GetState() == State::Stopping || GetState() == State::Uninitialized) if (GetState() == State::Stopping || GetState() == State::Uninitialized)
return; return;
#ifdef USE_RETRO_ACHIEVEMENTS
AchievementManager::GetInstance()->CloseGame();
#endif // USE_RETRO_ACHIEVEMENTS
s_is_stopping = true; s_is_stopping = true;
CallOnStateChangedCallbacks(State::Stopping); CallOnStateChangedCallbacks(State::Stopping);
@ -435,7 +440,8 @@ static void FifoPlayerThread(const std::optional<std::string>& savestate_path,
{ {
DeclareAsCPUThread(); DeclareAsCPUThread();
if (Core::System::GetInstance().IsDualCoreMode()) auto& system = Core::System::GetInstance();
if (system.IsDualCoreMode())
Common::SetCurrentThreadName("FIFO player thread"); Common::SetCurrentThreadName("FIFO player thread");
else else
Common::SetCurrentThreadName("FIFO-GPU thread"); Common::SetCurrentThreadName("FIFO-GPU thread");
@ -443,15 +449,14 @@ static void FifoPlayerThread(const std::optional<std::string>& savestate_path,
// Enter CPU run loop. When we leave it - we are done. // Enter CPU run loop. When we leave it - we are done.
if (auto cpu_core = FifoPlayer::GetInstance().GetCPUCore()) if (auto cpu_core = FifoPlayer::GetInstance().GetCPUCore())
{ {
PowerPC::InjectExternalCPUCore(cpu_core.get()); system.GetPowerPC().InjectExternalCPUCore(cpu_core.get());
s_is_started = true; s_is_started = true;
CPUSetInitialExecutionState(); CPUSetInitialExecutionState();
auto& system = Core::System::GetInstance();
system.GetCPU().Run(); system.GetCPU().Run();
s_is_started = false; s_is_started = false;
PowerPC::InjectExternalCPUCore(nullptr); system.GetPowerPC().InjectExternalCPUCore(nullptr);
FifoPlayer::GetInstance().Close(); FifoPlayer::GetInstance().Close();
} }
else else
@ -552,7 +557,7 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
HLE::Clear(); HLE::Clear();
CPUThreadGuard guard(system); CPUThreadGuard guard(system);
PowerPC::debug_interface.Clear(guard); system.GetPowerPC().GetDebugInterface().Clear(guard);
}}; }};
VideoBackendBase::PopulateBackendInfo(); VideoBackendBase::PopulateBackendInfo();
@ -590,7 +595,7 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
system.GetCPU().Break(); system.GetCPU().Break();
// Load GCM/DOL/ELF whatever ... we boot with the interpreter core // Load GCM/DOL/ELF whatever ... we boot with the interpreter core
PowerPC::SetMode(PowerPC::CoreMode::Interpreter); system.GetPowerPC().SetMode(PowerPC::CoreMode::Interpreter);
// Determine the CPU thread function // Determine the CPU thread function
void (*cpuThreadFunc)(const std::optional<std::string>& savestate_path, bool delete_savestate); void (*cpuThreadFunc)(const std::optional<std::string>& savestate_path, bool delete_savestate);
@ -628,11 +633,11 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
// Setup our core // Setup our core
if (Config::Get(Config::MAIN_CPU_CORE) != PowerPC::CPUCore::Interpreter) if (Config::Get(Config::MAIN_CPU_CORE) != PowerPC::CPUCore::Interpreter)
{ {
PowerPC::SetMode(PowerPC::CoreMode::JIT); system.GetPowerPC().SetMode(PowerPC::CoreMode::JIT);
} }
else else
{ {
PowerPC::SetMode(PowerPC::CoreMode::Interpreter); system.GetPowerPC().SetMode(PowerPC::CoreMode::Interpreter);
} }
UpdateTitle(); UpdateTitle();
@ -901,7 +906,7 @@ void UpdateTitle()
{ {
// Settings are shown the same for both extended and summary info // Settings are shown the same for both extended and summary info
const std::string SSettings = fmt::format( const std::string SSettings = fmt::format(
"{} {} | {} | {}", PowerPC::GetCPUName(), "{} {} | {} | {}", Core::System::GetInstance().GetPowerPC().GetCPUName(),
Core::System::GetInstance().IsDualCoreMode() ? "DC" : "SC", g_video_backend->GetDisplayName(), Core::System::GetInstance().IsDualCoreMode() ? "DC" : "SC", g_video_backend->GetDisplayName(),
Config::Get(Config::MAIN_DSP_HLE) ? "HLE" : "LLE"); Config::Get(Config::MAIN_DSP_HLE) ? "HLE" : "LLE");

View file

@ -303,8 +303,8 @@ void CoreTimingManager::MoveEvents()
void CoreTimingManager::Advance() void CoreTimingManager::Advance()
{ {
auto& system = m_system; auto& power_pc = m_system.GetPowerPC();
auto& ppc_state = m_system.GetPPCState(); auto& ppc_state = power_pc.GetPPCState();
MoveEvents(); MoveEvents();
@ -323,7 +323,7 @@ void CoreTimingManager::Advance()
m_event_queue.pop_back(); m_event_queue.pop_back();
Throttle(evt.time); Throttle(evt.time);
evt.type->callback(system, evt.userdata, m_globals.global_timer - evt.time); evt.type->callback(m_system, evt.userdata, m_globals.global_timer - evt.time);
} }
m_is_global_timer_sane = false; m_is_global_timer_sane = false;
@ -341,7 +341,7 @@ void CoreTimingManager::Advance()
// It's important to do this after processing events otherwise any exceptions will be delayed // It's important to do this after processing events otherwise any exceptions will be delayed
// until the next slice: // until the next slice:
// Pokemon Box refuses to boot if the first exception from the audio DMA is received late // Pokemon Box refuses to boot if the first exception from the audio DMA is received late
PowerPC::CheckExternalExceptions(); power_pc.CheckExternalExceptions();
} }
void CoreTimingManager::Throttle(const s64 target_cycle) void CoreTimingManager::Throttle(const s64 target_cycle)

View file

@ -32,7 +32,7 @@ void AddAutoBreakpoints()
{ {
Common::Symbol* symbol = g_symbolDB.GetSymbolFromName(bp); Common::Symbol* symbol = g_symbolDB.GetSymbolFromName(bp);
if (symbol) if (symbol)
PowerPC::breakpoints.Add(symbol->address, false); Core::System::GetInstance().GetPowerPC().GetBreakPoints().Add(symbol->address, false);
} }
#endif #endif
#endif #endif

View file

@ -36,6 +36,7 @@ void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, Common::Debug::MemoryPa
if (!PowerPC::MMU::HostIsRAMAddress(guard, address)) if (!PowerPC::MMU::HostIsRAMAddress(guard, address))
return; return;
auto& power_pc = guard.GetSystem().GetPowerPC();
for (u32 offset = 0; offset < size; ++offset) for (u32 offset = 0; offset < size; ++offset)
{ {
if (store_existing_value) if (store_existing_value)
@ -50,11 +51,11 @@ void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, Common::Debug::MemoryPa
} }
if (((address + offset) % 4) == 3) if (((address + offset) % 4) == 3)
PowerPC::ScheduleInvalidateCacheThreadSafe(Common::AlignDown(address + offset, 4)); power_pc.ScheduleInvalidateCacheThreadSafe(Common::AlignDown(address + offset, 4));
} }
if (((address + size) % 4) != 0) if (((address + size) % 4) != 0)
{ {
PowerPC::ScheduleInvalidateCacheThreadSafe( power_pc.ScheduleInvalidateCacheThreadSafe(
Common::AlignDown(address + static_cast<u32>(size), 4)); Common::AlignDown(address + static_cast<u32>(size), 4));
} }
} }
@ -347,40 +348,41 @@ bool PPCDebugInterface::IsAlive() const
bool PPCDebugInterface::IsBreakpoint(u32 address) const bool PPCDebugInterface::IsBreakpoint(u32 address) const
{ {
return PowerPC::breakpoints.IsAddressBreakPoint(address); return m_system.GetPowerPC().GetBreakPoints().IsAddressBreakPoint(address);
} }
void PPCDebugInterface::SetBreakpoint(u32 address) void PPCDebugInterface::SetBreakpoint(u32 address)
{ {
PowerPC::breakpoints.Add(address); m_system.GetPowerPC().GetBreakPoints().Add(address);
} }
void PPCDebugInterface::ClearBreakpoint(u32 address) void PPCDebugInterface::ClearBreakpoint(u32 address)
{ {
PowerPC::breakpoints.Remove(address); m_system.GetPowerPC().GetBreakPoints().Remove(address);
} }
void PPCDebugInterface::ClearAllBreakpoints() void PPCDebugInterface::ClearAllBreakpoints()
{ {
PowerPC::breakpoints.Clear(); m_system.GetPowerPC().GetBreakPoints().Clear();
} }
void PPCDebugInterface::ToggleBreakpoint(u32 address) void PPCDebugInterface::ToggleBreakpoint(u32 address)
{ {
if (PowerPC::breakpoints.IsAddressBreakPoint(address)) auto& breakpoints = m_system.GetPowerPC().GetBreakPoints();
PowerPC::breakpoints.Remove(address); if (breakpoints.IsAddressBreakPoint(address))
breakpoints.Remove(address);
else else
PowerPC::breakpoints.Add(address); breakpoints.Add(address);
} }
void PPCDebugInterface::ClearAllMemChecks() void PPCDebugInterface::ClearAllMemChecks()
{ {
PowerPC::memchecks.Clear(); m_system.GetPowerPC().GetMemChecks().Clear();
} }
bool PPCDebugInterface::IsMemCheck(u32 address, size_t size) const bool PPCDebugInterface::IsMemCheck(u32 address, size_t size) const
{ {
return PowerPC::memchecks.GetMemCheck(address, size) != nullptr; return m_system.GetPowerPC().GetMemChecks().GetMemCheck(address, size) != nullptr;
} }
void PPCDebugInterface::ToggleMemCheck(u32 address, bool read, bool write, bool log) void PPCDebugInterface::ToggleMemCheck(u32 address, bool read, bool write, bool log)
@ -397,11 +399,11 @@ void PPCDebugInterface::ToggleMemCheck(u32 address, bool read, bool write, bool
MemCheck.log_on_hit = log; MemCheck.log_on_hit = log;
MemCheck.break_on_hit = true; MemCheck.break_on_hit = true;
PowerPC::memchecks.Add(std::move(MemCheck)); m_system.GetPowerPC().GetMemChecks().Add(std::move(MemCheck));
} }
else else
{ {
PowerPC::memchecks.Remove(address); m_system.GetPowerPC().GetMemChecks().Remove(address);
} }
} }

View file

@ -6,6 +6,7 @@
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <mutex> #include <mutex>
#include <type_traits>
#include "Common/Assert.h" #include "Common/Assert.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
@ -101,14 +102,9 @@ void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile* file,
part_start = offset; part_start = offset;
// Copy cpmem now, because end_of_primitives isn't triggered until the first opcode after // Copy cpmem now, because end_of_primitives isn't triggered until the first opcode after
// primitive data, and the first opcode might update cpmem // primitive data, and the first opcode might update cpmem
#ifdef __GNUC__ static_assert(std::is_trivially_copyable_v<CPState>);
#pragma GCC diagnostic push std::memcpy(static_cast<void*>(&cpmem), static_cast<const void*>(&analyzer.m_cpmem),
#pragma GCC diagnostic ignored "-Wclass-memaccess" sizeof(CPState));
#endif
std::memcpy(&cpmem, &analyzer.m_cpmem, sizeof(CPState));
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
} }
if (analyzer.m_end_of_primitives) if (analyzer.m_end_of_primitives)
{ {

View file

@ -268,9 +268,7 @@ void FifoRecorder::StartRecording(s32 numFrames, CallbackFunc finishedCb)
RecordInitialVideoMemory(); RecordInitialVideoMemory();
} }
auto& system = Core::System::GetInstance(); const auto& fifo = Core::System::GetInstance().GetCommandProcessor().GetFifo();
auto& command_processor = system.GetCommandProcessor();
const auto& fifo = command_processor.GetFifo();
EndFrame(fifo.CPBase.load(std::memory_order_relaxed), EndFrame(fifo.CPBase.load(std::memory_order_relaxed),
fifo.CPEnd.load(std::memory_order_relaxed)); fifo.CPEnd.load(std::memory_order_relaxed));
}, },

View file

@ -127,11 +127,11 @@ std::vector<GeckoCode> DownloadCodes(std::string gametdb_id, bool* succeeded, bo
return gcodes; return gcodes;
} }
std::vector<GeckoCode> LoadCodes(const IniFile& globalIni, const IniFile& localIni) std::vector<GeckoCode> LoadCodes(const Common::IniFile& globalIni, const Common::IniFile& localIni)
{ {
std::vector<GeckoCode> gcodes; std::vector<GeckoCode> gcodes;
for (const IniFile* ini : {&globalIni, &localIni}) for (const auto* ini : {&globalIni, &localIni})
{ {
std::vector<std::string> lines; std::vector<std::string> lines;
ini->GetLines("Gecko", &lines, false); ini->GetLines("Gecko", &lines, false);
@ -239,7 +239,7 @@ static void SaveGeckoCode(std::vector<std::string>& lines, const GeckoCode& gcod
lines.push_back('*' + note); lines.push_back('*' + note);
} }
void SaveCodes(IniFile& inifile, const std::vector<GeckoCode>& gcodes) void SaveCodes(Common::IniFile& inifile, const std::vector<GeckoCode>& gcodes)
{ {
std::vector<std::string> lines; std::vector<std::string> lines;
std::vector<std::string> enabled_lines; std::vector<std::string> enabled_lines;

View file

@ -9,14 +9,17 @@
#include "Core/GeckoCode.h" #include "Core/GeckoCode.h"
namespace Common
{
class IniFile; class IniFile;
}
namespace Gecko namespace Gecko
{ {
std::vector<GeckoCode> LoadCodes(const IniFile& globalIni, const IniFile& localIni); std::vector<GeckoCode> LoadCodes(const Common::IniFile& globalIni, const Common::IniFile& localIni);
std::vector<GeckoCode> DownloadCodes(std::string gametdb_id, bool* succeeded, std::vector<GeckoCode> DownloadCodes(std::string gametdb_id, bool* succeeded,
bool use_https = true); bool use_https = true);
void SaveCodes(IniFile& inifile, const std::vector<GeckoCode>& gcodes); void SaveCodes(Common::IniFile& inifile, const std::vector<GeckoCode>& gcodes);
std::optional<GeckoCode::Code> DeserializeLine(const std::string& line); std::optional<GeckoCode::Code> DeserializeLine(const std::string& line);
} // namespace Gecko } // namespace Gecko

View file

@ -203,7 +203,7 @@ HookFlag GetHookFlagsByIndex(u32 index)
bool IsEnabled(HookFlag flag) bool IsEnabled(HookFlag flag)
{ {
return flag != HLE::HookFlag::Debug || Config::Get(Config::MAIN_ENABLE_DEBUGGING) || return flag != HLE::HookFlag::Debug || Config::Get(Config::MAIN_ENABLE_DEBUGGING) ||
PowerPC::GetMode() == PowerPC::CoreMode::Interpreter; Core::System::GetInstance().GetPowerPC().GetMode() == PowerPC::CoreMode::Interpreter;
} }
u32 UnPatch(Core::System& system, std::string_view patch_name) u32 UnPatch(Core::System& system, std::string_view patch_name)

View file

@ -19,19 +19,21 @@
namespace CPU namespace CPU
{ {
CPUManager::CPUManager() = default; CPUManager::CPUManager(Core::System& system) : m_system(system)
{
}
CPUManager::~CPUManager() = default; CPUManager::~CPUManager() = default;
void CPUManager::Init(PowerPC::CPUCore cpu_core) void CPUManager::Init(PowerPC::CPUCore cpu_core)
{ {
PowerPC::Init(cpu_core); m_system.GetPowerPC().Init(cpu_core);
m_state = State::Stepping; m_state = State::Stepping;
} }
void CPUManager::Shutdown() void CPUManager::Shutdown()
{ {
Stop(); Stop();
PowerPC::Shutdown(); m_system.GetPowerPC().Shutdown();
} }
// Requires holding m_state_change_lock // Requires holding m_state_change_lock
@ -62,11 +64,11 @@ void CPUManager::ExecutePendingJobs(std::unique_lock<std::mutex>& state_lock)
void CPUManager::Run() void CPUManager::Run()
{ {
auto& system = Core::System::GetInstance(); auto& power_pc = m_system.GetPowerPC();
// Updating the host CPU's rounding mode must be done on the CPU thread. // Updating the host CPU's rounding mode must be done on the CPU thread.
// We can't rely on PowerPC::Init doing it, since it's called from EmuThread. // We can't rely on PowerPC::Init doing it, since it's called from EmuThread.
PowerPC::RoundingModeUpdated(); PowerPC::RoundingModeUpdated(power_pc.GetPPCState());
std::unique_lock state_lock(m_state_change_lock); std::unique_lock state_lock(m_state_change_lock);
while (m_state != State::PowerDown) while (m_state != State::PowerDown)
@ -85,22 +87,22 @@ void CPUManager::Run()
// SingleStep so that the "continue", "step over" and "step out" debugger functions // SingleStep so that the "continue", "step over" and "step out" debugger functions
// work when the PC is at a breakpoint at the beginning of the block // work when the PC is at a breakpoint at the beginning of the block
// If watchpoints are enabled, any instruction could be a breakpoint. // If watchpoints are enabled, any instruction could be a breakpoint.
if (PowerPC::GetMode() != PowerPC::CoreMode::Interpreter) if (power_pc.GetMode() != PowerPC::CoreMode::Interpreter)
{ {
if (PowerPC::breakpoints.IsAddressBreakPoint(system.GetPPCState().pc) || if (power_pc.GetBreakPoints().IsAddressBreakPoint(power_pc.GetPPCState().pc) ||
PowerPC::memchecks.HasAny()) power_pc.GetMemChecks().HasAny())
{ {
m_state = State::Stepping; m_state = State::Stepping;
PowerPC::CoreMode old_mode = PowerPC::GetMode(); PowerPC::CoreMode old_mode = power_pc.GetMode();
PowerPC::SetMode(PowerPC::CoreMode::Interpreter); power_pc.SetMode(PowerPC::CoreMode::Interpreter);
PowerPC::SingleStep(); power_pc.SingleStep();
PowerPC::SetMode(old_mode); power_pc.SetMode(old_mode);
m_state = State::Running; m_state = State::Running;
} }
} }
// Enter a fast runloop // Enter a fast runloop
PowerPC::RunLoop(); power_pc.RunLoop();
state_lock.lock(); state_lock.lock();
m_state_cpu_thread_active = false; m_state_cpu_thread_active = false;
@ -147,7 +149,7 @@ void CPUManager::Run()
m_state_cpu_thread_active = true; m_state_cpu_thread_active = true;
state_lock.unlock(); state_lock.unlock();
PowerPC::SingleStep(); power_pc.SingleStep();
state_lock.lock(); state_lock.lock();
m_state_cpu_thread_active = false; m_state_cpu_thread_active = false;

View file

@ -12,7 +12,10 @@ namespace Common
{ {
class Event; class Event;
} }
namespace Core
{
class System;
}
namespace PowerPC namespace PowerPC
{ {
enum class CPUCore; enum class CPUCore;
@ -30,7 +33,7 @@ enum class State
class CPUManager class CPUManager
{ {
public: public:
CPUManager(); explicit CPUManager(Core::System& system);
CPUManager(const CPUManager& other) = delete; CPUManager(const CPUManager& other) = delete;
CPUManager(CPUManager&& other) = delete; CPUManager(CPUManager&& other) = delete;
CPUManager& operator=(const CPUManager& other) = delete; CPUManager& operator=(const CPUManager& other) = delete;
@ -130,5 +133,7 @@ private:
bool m_state_cpu_step_instruction = false; bool m_state_cpu_step_instruction = false;
Common::Event* m_state_cpu_step_instruction_sync = nullptr; Common::Event* m_state_cpu_step_instruction_sync = nullptr;
std::queue<std::function<void()>> m_pending_jobs; std::queue<std::function<void()>> m_pending_jobs;
Core::System& m_system;
}; };
} // namespace CPU } // namespace CPU

View file

@ -44,21 +44,21 @@ constexpr u32 VOICE_16_BIT_FLAG = 2;
// These are used in the pre-2020 versions version // These are used in the pre-2020 versions version
constexpr u32 VOICE_PAUSE_OLD = 0x00000004; constexpr u32 VOICE_PAUSE_OLD = 0x00000004;
constexpr u32 VOICE_LOOP_OLD = 0x00000008; // not used by the DSP constexpr u32 VOICE_LOOP_OLD [[maybe_unused]] = 0x00000008; // not used by the DSP
constexpr u32 VOICE_ONCE_OLD = 0x00000010; // not used by the DSP constexpr u32 VOICE_ONCE_OLD [[maybe_unused]] = 0x00000010; // not used by the DSP
constexpr u32 VOICE_STREAM_OLD = 0x00000020; // not used by the DSP constexpr u32 VOICE_STREAM_OLD [[maybe_unused]] = 0x00000020; // not used by the DSP
// These were changed in the 2020 version to account for the different flags // These were changed in the 2020 version to account for the different flags
constexpr u32 VOICE_PAUSE_NEW = 0x00000008; constexpr u32 VOICE_PAUSE_NEW = 0x00000008;
constexpr u32 VOICE_LOOP_NEW = 0x00000010; // not used by the DSP constexpr u32 VOICE_LOOP_NEW [[maybe_unused]] = 0x00000010; // not used by the DSP
constexpr u32 VOICE_ONCE_NEW = 0x00000020; // not used by the DSP constexpr u32 VOICE_ONCE_NEW [[maybe_unused]] = 0x00000020; // not used by the DSP
constexpr u32 VOICE_STREAM_NEW = 0x00000040; // not used by the DSP constexpr u32 VOICE_STREAM_NEW [[maybe_unused]] = 0x00000040; // not used by the DSP
// These did not change between versions // These did not change between versions
constexpr u32 VOICE_FINISHED = 0x00100000; constexpr u32 VOICE_FINISHED = 0x00100000;
constexpr u32 VOICE_STOPPED = 0x00200000; // not used by the DSP constexpr u32 VOICE_STOPPED [[maybe_unused]] = 0x00200000; // not used by the DSP
constexpr u32 VOICE_RUNNING = 0x40000000; constexpr u32 VOICE_RUNNING = 0x40000000;
constexpr u32 VOICE_USED = 0x80000000; // not used by the DSP constexpr u32 VOICE_USED [[maybe_unused]] = 0x80000000; // not used by the DSP
// 1<<4 = scale gain by 1/1, 2<<2 = PCM decoding from ARAM, 1<<0 = 8-bit reads // 1<<4 = scale gain by 1/1, 2<<2 = PCM decoding from ARAM, 1<<0 = 8-bit reads
constexpr u32 ACCELERATOR_FORMAT_8_BIT = 0x0019; constexpr u32 ACCELERATOR_FORMAT_8_BIT = 0x0019;

View file

@ -384,7 +384,8 @@ void CEXIETHERNET::BuiltInBBAInterface::HandleTCPFrame(const Common::TCPPacket&
if (size > 0) if (size > 0)
{ {
// only if contain data // only if contain data
if (static_cast<int>(this_seq - ref->ack_num) >= 0 && data.size() >= size) if (static_cast<int>(this_seq - ref->ack_num) >= 0 &&
data.size() >= static_cast<size_t>(size))
{ {
ref->tcp_socket.send(data.data(), size); ref->tcp_socket.send(data.data(), size);
ref->ack_num += size; ref->ack_num += size;

View file

@ -45,7 +45,8 @@ bool CEXIETHERNET::TAPServerNetworkInterface::Activate()
if (connect(fd, reinterpret_cast<sockaddr*>(&sun), sizeof(sun)) == -1) if (connect(fd, reinterpret_cast<sockaddr*>(&sun), sizeof(sun)) == -1)
{ {
ERROR_LOG_FMT(SP1, "Couldn't connect socket ({}), unable to init BBA", LastStrerrorString()); ERROR_LOG_FMT(SP1, "Couldn't connect socket ({}), unable to init BBA",
Common::LastStrerrorString());
close(fd); close(fd);
fd = -1; fd = -1;
return false; return false;
@ -99,14 +100,14 @@ void CEXIETHERNET::TAPServerNetworkInterface::ReadThreadHandler()
u16 size; u16 size;
if (read(fd, &size, 2) != 2) if (read(fd, &size, 2) != 2)
{ {
ERROR_LOG_FMT(SP1, "Failed to read size field from BBA: {}", LastStrerrorString()); ERROR_LOG_FMT(SP1, "Failed to read size field from BBA: {}", Common::LastStrerrorString());
} }
else else
{ {
int read_bytes = read(fd, m_eth_ref->mRecvBuffer.get(), size); int read_bytes = read(fd, m_eth_ref->mRecvBuffer.get(), size);
if (read_bytes < 0) if (read_bytes < 0)
{ {
ERROR_LOG_FMT(SP1, "Failed to read packet data from BBA: {}", LastStrerrorString()); ERROR_LOG_FMT(SP1, "Failed to read packet data from BBA: {}", Common::LastStrerrorString());
} }
else if (readEnabled.IsSet()) else if (readEnabled.IsSet())
{ {

View file

@ -448,7 +448,7 @@ void CEXIETHERNET::SendFromDirectFIFO()
const u8* frame = tx_fifo.get(); const u8* frame = tx_fifo.get();
const u16 size = Common::BitCastPtr<u16>(&mBbaMem[BBA_TXFIFOCNT]); const u16 size = Common::BitCastPtr<u16>(&mBbaMem[BBA_TXFIFOCNT]);
if (m_network_interface->SendFrame(frame, size)) if (m_network_interface->SendFrame(frame, size))
PowerPC::debug_interface.NetworkLogger()->LogBBA(frame, size); m_system.GetPowerPC().GetDebugInterface().NetworkLogger()->LogBBA(frame, size);
} }
void CEXIETHERNET::SendFromPacketBuffer() void CEXIETHERNET::SendFromPacketBuffer()
@ -561,7 +561,8 @@ bool CEXIETHERNET::RecvHandlePacket()
INFO_LOG_FMT(SP1, "{:x} {:x} {:x} {:x}", page_ptr(BBA_BP), page_ptr(BBA_RRP), page_ptr(BBA_RWP), INFO_LOG_FMT(SP1, "{:x} {:x} {:x} {:x}", page_ptr(BBA_BP), page_ptr(BBA_RRP), page_ptr(BBA_RWP),
page_ptr(BBA_RHBP)); page_ptr(BBA_RHBP));
#endif #endif
PowerPC::debug_interface.NetworkLogger()->LogBBA(mRecvBuffer.get(), mRecvBufferLength); m_system.GetPowerPC().GetDebugInterface().NetworkLogger()->LogBBA(mRecvBuffer.get(),
mRecvBufferLength);
write_ptr = &mBbaMem[page_ptr(BBA_RWP) << 8]; write_ptr = &mBbaMem[page_ptr(BBA_RWP) << 8];
descriptor = (Descriptor*)write_ptr; descriptor = (Descriptor*)write_ptr;

View file

@ -61,14 +61,7 @@ MemoryInterfaceManager::~MemoryInterfaceManager() = default;
void MemoryInterfaceManager::Init() void MemoryInterfaceManager::Init()
{ {
static_assert(std::is_trivially_copyable_v<MIMemStruct>); static_assert(std::is_trivially_copyable_v<MIMemStruct>);
#ifdef __GNUC__ std::memset(static_cast<void*>(&m_mi_mem), 0, sizeof(MIMemStruct));
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif
std::memset(&m_mi_mem, 0, sizeof(MIMemStruct));
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
} }
void MemoryInterfaceManager::Shutdown() void MemoryInterfaceManager::Shutdown()

View file

@ -24,8 +24,8 @@
namespace ProcessorInterface namespace ProcessorInterface
{ {
constexpr u32 FLIPPER_REV_A = 0x046500B0; constexpr u32 FLIPPER_REV_A [[maybe_unused]] = 0x046500B0;
constexpr u32 FLIPPER_REV_B = 0x146500B1; constexpr u32 FLIPPER_REV_B [[maybe_unused]] = 0x146500B1;
constexpr u32 FLIPPER_REV_C = 0x246500B1; constexpr u32 FLIPPER_REV_C = 0x246500B1;
ProcessorInterfaceManager::ProcessorInterfaceManager(Core::System& system) : m_system(system) ProcessorInterfaceManager::ProcessorInterfaceManager(Core::System& system) : m_system(system)

View file

@ -223,7 +223,7 @@ void TimeBaseSet()
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming(); auto& core_timing = system.GetCoreTiming();
core_timing.SetFakeTBStartTicks(core_timing.GetTicks()); core_timing.SetFakeTBStartTicks(core_timing.GetTicks());
core_timing.SetFakeTBStartValue(PowerPC::ReadFullTimeBaseValue()); core_timing.SetFakeTBStartValue(system.GetPowerPC().ReadFullTimeBaseValue());
} }
u64 GetFakeTimeBase() u64 GetFakeTimeBase()

View file

@ -136,14 +136,8 @@ static bool DeserializeExtensionState(DesiredWiimoteState* state,
return false; return false;
auto& e = state->extension.data.emplace<T>(); auto& e = state->extension.data.emplace<T>();
static_assert(std::is_trivially_copyable_v<T>); static_assert(std::is_trivially_copyable_v<T>);
#ifdef __GNUC__ std::memcpy(static_cast<void*>(&e), static_cast<const void*>(&serialized.data[offset]),
#pragma GCC diagnostic push sizeof(T));
#pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif
std::memcpy(&e, &serialized.data[offset], sizeof(T));
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
return true; return true;
} }

View file

@ -251,7 +251,7 @@ bool IsPressed(int id, bool held)
// TODO: Remove this at a future date when we're confident most configs are migrated. // TODO: Remove this at a future date when we're confident most configs are migrated.
static void LoadLegacyConfig(ControllerEmu::EmulatedController* controller) static void LoadLegacyConfig(ControllerEmu::EmulatedController* controller)
{ {
IniFile inifile; Common::IniFile inifile;
if (inifile.Load(File::GetUserPath(D_CONFIG_IDX) + "Hotkeys.ini")) if (inifile.Load(File::GetUserPath(D_CONFIG_IDX) + "Hotkeys.ini"))
{ {
if (!inifile.Exists("Hotkeys") && inifile.Exists("Hotkeys1")) if (!inifile.Exists("Hotkeys") && inifile.Exists("Hotkeys1"))

View file

@ -24,35 +24,18 @@
#include "Core/System.h" #include "Core/System.h"
#include "DiscIO/Volume.h" #include "DiscIO/Volume.h"
template <u32 addr> constexpr u32 ADDRESS_DISR = 0x0D806000;
class RegisterWrapper constexpr u32 ADDRESS_DICVR = 0x0D806004;
{ constexpr u32 ADDRESS_DICMDBUF0 = 0x0D806008;
public: constexpr u32 ADDRESS_DICMDBUF1 = 0x0D80600C;
operator u32() const constexpr u32 ADDRESS_DICMDBUF2 = 0x0D806010;
{ constexpr u32 ADDRESS_DIMAR = 0x0D806014;
auto& system = Core::System::GetInstance(); constexpr u32 ADDRESS_DILENGTH = 0x0D806018;
auto& memory = system.GetMemory(); constexpr u32 ADDRESS_DICR = 0x0D80601C;
return memory.GetMMIOMapping()->Read<u32>(addr); constexpr u32 ADDRESS_DIIMMBUF = 0x0D806020;
}
void operator=(u32 rhs)
{
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
memory.GetMMIOMapping()->Write(addr, rhs);
}
};
static RegisterWrapper<0x0D806000> DISR;
static RegisterWrapper<0x0D806004> DICVR;
static RegisterWrapper<0x0D806008> DICMDBUF0;
static RegisterWrapper<0x0D80600C> DICMDBUF1;
static RegisterWrapper<0x0D806010> DICMDBUF2;
static RegisterWrapper<0x0D806014> DIMAR;
static RegisterWrapper<0x0D806018> DILENGTH;
static RegisterWrapper<0x0D80601C> DICR;
static RegisterWrapper<0x0D806020> DIIMMBUF;
static RegisterWrapper<0x0D8000E0> HW_GPIO_OUT; constexpr u32 ADDRESS_HW_GPIO_OUT = 0x0D8000E0;
static RegisterWrapper<0x0D800194> HW_RESETS; constexpr u32 ADDRESS_HW_RESETS = 0x0D800194;
namespace IOS::HLE namespace IOS::HLE
{ {
@ -169,6 +152,7 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
auto* mmio = memory.GetMMIOMapping();
// DVDInterface's ExecuteCommand handles most of the work for most of these. // DVDInterface's ExecuteCommand handles most of the work for most of these.
// The IOCtl callback is used to generate a reply afterwards. // The IOCtl callback is used to generate a reply afterwards.
@ -176,14 +160,14 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
{ {
case DIIoctl::DVDLowInquiry: case DIIoctl::DVDLowInquiry:
INFO_LOG_FMT(IOS_DI, "DVDLowInquiry"); INFO_LOG_FMT(IOS_DI, "DVDLowInquiry");
DICMDBUF0 = 0x12000000; mmio->Write<u32>(ADDRESS_DICMDBUF0, 0x12000000);
DICMDBUF1 = 0; mmio->Write<u32>(ADDRESS_DICMDBUF1, 0);
return StartDMATransfer(0x20, request); return StartDMATransfer(0x20, request);
case DIIoctl::DVDLowReadDiskID: case DIIoctl::DVDLowReadDiskID:
INFO_LOG_FMT(IOS_DI, "DVDLowReadDiskID"); INFO_LOG_FMT(IOS_DI, "DVDLowReadDiskID");
DICMDBUF0 = 0xA8000040; mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xA8000040);
DICMDBUF1 = 0; mmio->Write<u32>(ADDRESS_DICMDBUF1, 0);
DICMDBUF2 = 0x20; mmio->Write<u32>(ADDRESS_DICMDBUF2, 0x20);
return StartDMATransfer(0x20, request); return StartDMATransfer(0x20, request);
// TODO: Include an additional read that happens on Wii discs, or at least // TODO: Include an additional read that happens on Wii discs, or at least
// emulate its side effect of disabling DTK configuration // emulate its side effect of disabling DTK configuration
@ -225,7 +209,7 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
return DIResult::CoverClosed; return DIResult::CoverClosed;
case DIIoctl::DVDLowGetCoverRegister: case DIIoctl::DVDLowGetCoverRegister:
{ {
const u32 dicvr = DICVR; const u32 dicvr = mmio->Read<u32>(ADDRESS_DICVR);
DEBUG_LOG_FMT(IOS_DI, "DVDLowGetCoverRegister {:#010x}", dicvr); DEBUG_LOG_FMT(IOS_DI, "DVDLowGetCoverRegister {:#010x}", dicvr);
return WriteIfFits(request, dicvr); return WriteIfFits(request, dicvr);
} }
@ -240,27 +224,27 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
{ {
const u8 position = memory.Read_U8(request.buffer_in + 7); const u8 position = memory.Read_U8(request.buffer_in + 7);
INFO_LOG_FMT(IOS_DI, "DVDLowReadDvdPhysical: position {:#04x}", position); INFO_LOG_FMT(IOS_DI, "DVDLowReadDvdPhysical: position {:#04x}", position);
DICMDBUF0 = 0xAD000000 | (position << 8); mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xAD000000 | (position << 8));
DICMDBUF1 = 0; mmio->Write<u32>(ADDRESS_DICMDBUF1, 0);
DICMDBUF2 = 0; mmio->Write<u32>(ADDRESS_DICMDBUF2, 0);
return StartDMATransfer(0x800, request); return StartDMATransfer(0x800, request);
} }
case DIIoctl::DVDLowReadDvdCopyright: case DIIoctl::DVDLowReadDvdCopyright:
{ {
const u8 position = memory.Read_U8(request.buffer_in + 7); const u8 position = memory.Read_U8(request.buffer_in + 7);
INFO_LOG_FMT(IOS_DI, "DVDLowReadDvdCopyright: position {:#04x}", position); INFO_LOG_FMT(IOS_DI, "DVDLowReadDvdCopyright: position {:#04x}", position);
DICMDBUF0 = 0xAD010000 | (position << 8); mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xAD010000 | (position << 8));
DICMDBUF1 = 0; mmio->Write<u32>(ADDRESS_DICMDBUF1, 0);
DICMDBUF2 = 0; mmio->Write<u32>(ADDRESS_DICMDBUF2, 0);
return StartImmediateTransfer(request); return StartImmediateTransfer(request);
} }
case DIIoctl::DVDLowReadDvdDiscKey: case DIIoctl::DVDLowReadDvdDiscKey:
{ {
const u8 position = memory.Read_U8(request.buffer_in + 7); const u8 position = memory.Read_U8(request.buffer_in + 7);
INFO_LOG_FMT(IOS_DI, "DVDLowReadDvdDiscKey: position {:#04x}", position); INFO_LOG_FMT(IOS_DI, "DVDLowReadDvdDiscKey: position {:#04x}", position);
DICMDBUF0 = 0xAD020000 | (position << 8); mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xAD020000 | (position << 8));
DICMDBUF1 = 0; mmio->Write<u32>(ADDRESS_DICMDBUF1, 0);
DICMDBUF2 = 0; mmio->Write<u32>(ADDRESS_DICMDBUF2, 0);
return StartDMATransfer(0x800, request); return StartDMATransfer(0x800, request);
} }
case DIIoctl::DVDLowGetLength: case DIIoctl::DVDLowGetLength:
@ -268,7 +252,7 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
return WriteIfFits(request, m_last_length); return WriteIfFits(request, m_last_length);
case DIIoctl::DVDLowGetImmBuf: case DIIoctl::DVDLowGetImmBuf:
{ {
const u32 diimmbuf = DIIMMBUF; const u32 diimmbuf = mmio->Read<u32>(ADDRESS_DIIMMBUF);
INFO_LOG_FMT(IOS_DI, "DVDLowGetImmBuf {:#010x}", diimmbuf); INFO_LOG_FMT(IOS_DI, "DVDLowGetImmBuf {:#010x}", diimmbuf);
return WriteIfFits(request, diimmbuf); return WriteIfFits(request, diimmbuf);
} }
@ -303,27 +287,27 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
const bool spinup = memory.Read_U32(request.buffer_in + 4); const bool spinup = memory.Read_U32(request.buffer_in + 4);
// The GPIO *disables* spinning up the drive. Normally handled via syscall 0x4e. // The GPIO *disables* spinning up the drive. Normally handled via syscall 0x4e.
const u32 old_gpio = HW_GPIO_OUT; const u32 old_gpio = mmio->Read<u32>(ADDRESS_HW_GPIO_OUT);
if (spinup) if (spinup)
HW_GPIO_OUT = old_gpio & ~static_cast<u32>(GPIO::DI_SPIN); mmio->Write<u32>(ADDRESS_HW_GPIO_OUT, old_gpio & ~static_cast<u32>(GPIO::DI_SPIN));
else else
HW_GPIO_OUT = old_gpio | static_cast<u32>(GPIO::DI_SPIN); mmio->Write<u32>(ADDRESS_HW_GPIO_OUT, old_gpio | static_cast<u32>(GPIO::DI_SPIN));
// Syscall 0x46 check_di_reset // Syscall 0x46 check_di_reset
const bool was_resetting = (HW_RESETS & (1 << 10)) == 0; const bool was_resetting = (mmio->Read<u32>(ADDRESS_HW_RESETS) & (1 << 10)) == 0;
if (was_resetting) if (was_resetting)
{ {
// This route will not generally be taken in Dolphin but is included for completeness // This route will not generally be taken in Dolphin but is included for completeness
// Syscall 0x45 deassert_di_reset // Syscall 0x45 deassert_di_reset
HW_RESETS = HW_RESETS | (1 << 10); mmio->Write<u32>(ADDRESS_HW_RESETS, mmio->Read<u32>(ADDRESS_HW_RESETS) | (1 << 10));
} }
else else
{ {
// Syscall 0x44 assert_di_reset // Syscall 0x44 assert_di_reset
HW_RESETS = HW_RESETS & ~(1 << 10); mmio->Write<u32>(ADDRESS_HW_RESETS, mmio->Read<u32>(ADDRESS_HW_RESETS) & ~(1 << 10));
// Normally IOS sleeps for 12 microseconds here, but we can't easily emulate that // Normally IOS sleeps for 12 microseconds here, but we can't easily emulate that
// Syscall 0x45 deassert_di_reset // Syscall 0x45 deassert_di_reset
HW_RESETS = HW_RESETS | (1 << 10); mmio->Write<u32>(ADDRESS_HW_RESETS, mmio->Read<u32>(ADDRESS_HW_RESETS) | (1 << 10));
} }
ResetDIRegisters(); ResetDIRegisters();
return DIResult::Success; return DIResult::Success;
@ -356,14 +340,14 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
if (range.start <= position && position <= range.end && range.start <= end && if (range.start <= position && position <= range.end && range.start <= end &&
end <= range.end) end <= range.end)
{ {
DICMDBUF0 = 0xA8000000; mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xA8000000);
DICMDBUF1 = position; mmio->Write<u32>(ADDRESS_DICMDBUF1, position);
DICMDBUF2 = length; mmio->Write<u32>(ADDRESS_DICMDBUF2, length);
if (range.is_error_001_range && Config::Get(Config::SESSION_SHOULD_FAKE_ERROR_001)) if (range.is_error_001_range && Config::Get(Config::SESSION_SHOULD_FAKE_ERROR_001))
{ {
DIMAR = request.buffer_out; mmio->Write<u32>(ADDRESS_DIMAR, request.buffer_out);
m_last_length = length; m_last_length = length;
DILENGTH = length; mmio->Write<u32>(ADDRESS_DILENGTH, length);
system.GetDVDInterface().ForceOutOfBoundsRead(DVD::ReplyType::IOS); system.GetDVDInterface().ForceOutOfBoundsRead(DVD::ReplyType::IOS);
return {}; return {};
} }
@ -403,13 +387,13 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
return DIResult::SecurityError; return DIResult::SecurityError;
case DIIoctl::DVDLowGetStatusRegister: case DIIoctl::DVDLowGetStatusRegister:
{ {
const u32 disr = DISR; const u32 disr = mmio->Read<u32>(ADDRESS_DISR);
INFO_LOG_FMT(IOS_DI, "DVDLowGetStatusRegister: {:#010x}", disr); INFO_LOG_FMT(IOS_DI, "DVDLowGetStatusRegister: {:#010x}", disr);
return WriteIfFits(request, disr); return WriteIfFits(request, disr);
} }
case DIIoctl::DVDLowGetControlRegister: case DIIoctl::DVDLowGetControlRegister:
{ {
const u32 dicr = DICR; const u32 dicr = mmio->Read<u32>(ADDRESS_DICR);
INFO_LOG_FMT(IOS_DI, "DVDLowGetControlRegister: {:#010x}", dicr); INFO_LOG_FMT(IOS_DI, "DVDLowGetControlRegister: {:#010x}", dicr);
return WriteIfFits(request, dicr); return WriteIfFits(request, dicr);
} }
@ -418,9 +402,9 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
const u8 param1 = memory.Read_U8(request.buffer_in + 7); const u8 param1 = memory.Read_U8(request.buffer_in + 7);
const u32 param2 = memory.Read_U32(request.buffer_in + 8); const u32 param2 = memory.Read_U32(request.buffer_in + 8);
INFO_LOG_FMT(IOS_DI, "DVDLowReportKey: param1 {:#04x}, param2 {:#08x}", param1, param2); INFO_LOG_FMT(IOS_DI, "DVDLowReportKey: param1 {:#04x}, param2 {:#08x}", param1, param2);
DICMDBUF0 = 0xA4000000 | (param1 << 16); mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xA4000000 | (param1 << 16));
DICMDBUF1 = param2 & 0xFFFFFF; mmio->Write<u32>(ADDRESS_DICMDBUF1, param2 & 0xFFFFFF);
DICMDBUF2 = 0; mmio->Write<u32>(ADDRESS_DICMDBUF2, 0);
return StartDMATransfer(0x20, request); return StartDMATransfer(0x20, request);
} }
case DIIoctl::DVDLowSeek: case DIIoctl::DVDLowSeek:
@ -428,8 +412,8 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
const u32 position = memory.Read_U32(request.buffer_in + 4); // 32-bit offset const u32 position = memory.Read_U32(request.buffer_in + 4); // 32-bit offset
INFO_LOG_FMT(IOS_DI, "DVDLowSeek: position {:#010x}, translated to {:#010x}", position, INFO_LOG_FMT(IOS_DI, "DVDLowSeek: position {:#010x}, translated to {:#010x}", position,
position); // TODO: do partition translation! position); // TODO: do partition translation!
DICMDBUF0 = 0xAB000000; mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xAB000000);
DICMDBUF1 = position; mmio->Write<u32>(ADDRESS_DICMDBUF1, position);
return StartImmediateTransfer(request, false); return StartImmediateTransfer(request, false);
} }
case DIIoctl::DVDLowReadDvd: case DIIoctl::DVDLowReadDvd:
@ -440,9 +424,9 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
const u32 position = memory.Read_U32(request.buffer_in + 16); const u32 position = memory.Read_U32(request.buffer_in + 16);
INFO_LOG_FMT(IOS_DI, "DVDLowReadDvd({}, {}): position {:#08x}, length {:#08x}", flag1, flag2, INFO_LOG_FMT(IOS_DI, "DVDLowReadDvd({}, {}): position {:#08x}, length {:#08x}", flag1, flag2,
position, length); position, length);
DICMDBUF0 = 0xD0000000 | ((flag1 & 1) << 7) | ((flag2 & 1) << 6); mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xD0000000 | ((flag1 & 1) << 7) | ((flag2 & 1) << 6));
DICMDBUF1 = position & 0xFFFFFF; mmio->Write<u32>(ADDRESS_DICMDBUF1, position & 0xFFFFFF);
DICMDBUF2 = length & 0xFFFFFF; mmio->Write<u32>(ADDRESS_DICMDBUF2, length & 0xFFFFFF);
return StartDMATransfer(0x800 * length, request); return StartDMATransfer(0x800 * length, request);
} }
case DIIoctl::DVDLowReadDvdConfig: case DIIoctl::DVDLowReadDvdConfig:
@ -451,41 +435,41 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
const u8 param2 = memory.Read_U8(request.buffer_in + 11); const u8 param2 = memory.Read_U8(request.buffer_in + 11);
const u32 position = memory.Read_U32(request.buffer_in + 12); const u32 position = memory.Read_U32(request.buffer_in + 12);
INFO_LOG_FMT(IOS_DI, "DVDLowReadDvdConfig({}, {}): position {:#08x}", flag1, param2, position); INFO_LOG_FMT(IOS_DI, "DVDLowReadDvdConfig({}, {}): position {:#08x}", flag1, param2, position);
DICMDBUF0 = 0xD1000000 | ((flag1 & 1) << 16) | param2; mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xD1000000 | ((flag1 & 1) << 16) | param2);
DICMDBUF1 = position & 0xFFFFFF; mmio->Write<u32>(ADDRESS_DICMDBUF1, position & 0xFFFFFF);
DICMDBUF2 = 0; mmio->Write<u32>(ADDRESS_DICMDBUF2, 0);
return StartImmediateTransfer(request); return StartImmediateTransfer(request);
} }
case DIIoctl::DVDLowStopLaser: case DIIoctl::DVDLowStopLaser:
INFO_LOG_FMT(IOS_DI, "DVDLowStopLaser"); INFO_LOG_FMT(IOS_DI, "DVDLowStopLaser");
DICMDBUF0 = 0xD2000000; mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xD2000000);
return StartImmediateTransfer(request); return StartImmediateTransfer(request);
case DIIoctl::DVDLowOffset: case DIIoctl::DVDLowOffset:
{ {
const u8 flag = memory.Read_U8(request.buffer_in + 7); const u8 flag = memory.Read_U8(request.buffer_in + 7);
const u32 offset = memory.Read_U32(request.buffer_in + 8); const u32 offset = memory.Read_U32(request.buffer_in + 8);
INFO_LOG_FMT(IOS_DI, "DVDLowOffset({}): offset {:#010x}", flag, offset); INFO_LOG_FMT(IOS_DI, "DVDLowOffset({}): offset {:#010x}", flag, offset);
DICMDBUF0 = 0xD9000000 | ((flag & 1) << 16); mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xD9000000 | ((flag & 1) << 16));
DICMDBUF1 = offset; mmio->Write<u32>(ADDRESS_DICMDBUF1, offset);
return StartImmediateTransfer(request); return StartImmediateTransfer(request);
} }
case DIIoctl::DVDLowReadDiskBca: case DIIoctl::DVDLowReadDiskBca:
INFO_LOG_FMT(IOS_DI, "DVDLowReadDiskBca"); INFO_LOG_FMT(IOS_DI, "DVDLowReadDiskBca");
DICMDBUF0 = 0xDA000000; mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xDA000000);
return StartDMATransfer(0x40, request); return StartDMATransfer(0x40, request);
case DIIoctl::DVDLowRequestDiscStatus: case DIIoctl::DVDLowRequestDiscStatus:
INFO_LOG_FMT(IOS_DI, "DVDLowRequestDiscStatus"); INFO_LOG_FMT(IOS_DI, "DVDLowRequestDiscStatus");
DICMDBUF0 = 0xDB000000; mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xDB000000);
return StartImmediateTransfer(request); return StartImmediateTransfer(request);
case DIIoctl::DVDLowRequestRetryNumber: case DIIoctl::DVDLowRequestRetryNumber:
INFO_LOG_FMT(IOS_DI, "DVDLowRequestRetryNumber"); INFO_LOG_FMT(IOS_DI, "DVDLowRequestRetryNumber");
DICMDBUF0 = 0xDC000000; mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xDC000000);
return StartImmediateTransfer(request); return StartImmediateTransfer(request);
case DIIoctl::DVDLowSetMaximumRotation: case DIIoctl::DVDLowSetMaximumRotation:
{ {
const u8 speed = memory.Read_U8(request.buffer_in + 7); const u8 speed = memory.Read_U8(request.buffer_in + 7);
INFO_LOG_FMT(IOS_DI, "DVDLowSetMaximumRotation: speed {}", speed); INFO_LOG_FMT(IOS_DI, "DVDLowSetMaximumRotation: speed {}", speed);
DICMDBUF0 = 0xDD000000 | ((speed & 3) << 16); mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xDD000000 | ((speed & 3) << 16));
return StartImmediateTransfer(request, false); return StartImmediateTransfer(request, false);
} }
case DIIoctl::DVDLowSerMeasControl: case DIIoctl::DVDLowSerMeasControl:
@ -493,12 +477,12 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
const u8 flag1 = memory.Read_U8(request.buffer_in + 7); const u8 flag1 = memory.Read_U8(request.buffer_in + 7);
const u8 flag2 = memory.Read_U8(request.buffer_in + 11); const u8 flag2 = memory.Read_U8(request.buffer_in + 11);
INFO_LOG_FMT(IOS_DI, "DVDLowSerMeasControl({}, {})", flag1, flag2); INFO_LOG_FMT(IOS_DI, "DVDLowSerMeasControl({}, {})", flag1, flag2);
DICMDBUF0 = 0xDF000000 | ((flag1 & 1) << 17) | ((flag2 & 1) << 16); mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xDF000000 | ((flag1 & 1) << 17) | ((flag2 & 1) << 16));
return StartDMATransfer(0x20, request); return StartDMATransfer(0x20, request);
} }
case DIIoctl::DVDLowRequestError: case DIIoctl::DVDLowRequestError:
INFO_LOG_FMT(IOS_DI, "DVDLowRequestError"); INFO_LOG_FMT(IOS_DI, "DVDLowRequestError");
DICMDBUF0 = 0xE0000000; mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xE0000000);
return StartImmediateTransfer(request); return StartImmediateTransfer(request);
case DIIoctl::DVDLowAudioStream: case DIIoctl::DVDLowAudioStream:
{ {
@ -507,17 +491,17 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
const u32 position = memory.Read_U32(request.buffer_in + 12); const u32 position = memory.Read_U32(request.buffer_in + 12);
INFO_LOG_FMT(IOS_DI, "DVDLowAudioStream({}): offset {:#010x} (byte {:#011x}), length {:#x}", INFO_LOG_FMT(IOS_DI, "DVDLowAudioStream({}): offset {:#010x} (byte {:#011x}), length {:#x}",
mode, position, static_cast<u64>(position) << 2, length); mode, position, static_cast<u64>(position) << 2, length);
DICMDBUF0 = 0xE1000000 | ((mode & 3) << 16); mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xE1000000 | ((mode & 3) << 16));
DICMDBUF1 = position; mmio->Write<u32>(ADDRESS_DICMDBUF1, position);
DICMDBUF2 = length; mmio->Write<u32>(ADDRESS_DICMDBUF2, length);
return StartImmediateTransfer(request, false); return StartImmediateTransfer(request, false);
} }
case DIIoctl::DVDLowRequestAudioStatus: case DIIoctl::DVDLowRequestAudioStatus:
{ {
const u8 mode = memory.Read_U8(request.buffer_in + 7); const u8 mode = memory.Read_U8(request.buffer_in + 7);
INFO_LOG_FMT(IOS_DI, "DVDLowRequestAudioStatus({})", mode); INFO_LOG_FMT(IOS_DI, "DVDLowRequestAudioStatus({})", mode);
DICMDBUF0 = 0xE2000000 | ((mode & 3) << 16); mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xE2000000 | ((mode & 3) << 16));
DICMDBUF1 = 0; mmio->Write<u32>(ADDRESS_DICMDBUF1, 0);
// Note that this command does not copy the value written to DIIMMBUF, which makes it rather // Note that this command does not copy the value written to DIIMMBUF, which makes it rather
// useless (to actually use it, DVDLowGetImmBuf would need to be used afterwards) // useless (to actually use it, DVDLowGetImmBuf would need to be used afterwards)
return StartImmediateTransfer(request, false); return StartImmediateTransfer(request, false);
@ -527,8 +511,8 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
const u8 eject = memory.Read_U8(request.buffer_in + 7); const u8 eject = memory.Read_U8(request.buffer_in + 7);
const u8 kill = memory.Read_U8(request.buffer_in + 11); const u8 kill = memory.Read_U8(request.buffer_in + 11);
INFO_LOG_FMT(IOS_DI, "DVDLowStopMotor({}, {})", eject, kill); INFO_LOG_FMT(IOS_DI, "DVDLowStopMotor({}, {})", eject, kill);
DICMDBUF0 = 0xE3000000 | ((eject & 1) << 17) | ((kill & 1) << 20); mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xE3000000 | ((eject & 1) << 17) | ((kill & 1) << 20));
DICMDBUF1 = 0; mmio->Write<u32>(ADDRESS_DICMDBUF1, 0);
return StartImmediateTransfer(request); return StartImmediateTransfer(request);
} }
case DIIoctl::DVDLowAudioBufferConfig: case DIIoctl::DVDLowAudioBufferConfig:
@ -537,8 +521,8 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
const u8 buffer_size = memory.Read_U8(request.buffer_in + 11); const u8 buffer_size = memory.Read_U8(request.buffer_in + 11);
INFO_LOG_FMT(IOS_DI, "DVDLowAudioBufferConfig: {}, buffer size {}", INFO_LOG_FMT(IOS_DI, "DVDLowAudioBufferConfig: {}, buffer size {}",
enable ? "enabled" : "disabled", buffer_size); enable ? "enabled" : "disabled", buffer_size);
DICMDBUF0 = 0xE4000000 | ((enable & 1) << 16) | (buffer_size & 0xf); mmio->Write<u32>(ADDRESS_DICMDBUF0, 0xE4000000 | ((enable & 1) << 16) | (buffer_size & 0xf));
DICMDBUF1 = 0; mmio->Write<u32>(ADDRESS_DICMDBUF1, 0);
// On the other hand, this command *does* copy DIIMMBUF, but the actual code in the drive never // On the other hand, this command *does* copy DIIMMBUF, but the actual code in the drive never
// writes anything to it, so it just copies over a stale value (e.g. from DVDLowRequestError). // writes anything to it, so it just copies over a stale value (e.g. from DVDLowRequestError).
return StartImmediateTransfer(request); return StartImmediateTransfer(request);
@ -577,11 +561,13 @@ std::optional<DIDevice::DIResult> DIDevice::StartDMATransfer(u32 command_length,
return DIResult::BadArgument; return DIResult::BadArgument;
} }
DIMAR = request.buffer_out; auto& system = Core::System::GetInstance();
auto* mmio = system.GetMemory().GetMMIOMapping();
mmio->Write<u32>(ADDRESS_DIMAR, request.buffer_out);
m_last_length = command_length; m_last_length = command_length;
DILENGTH = command_length; mmio->Write<u32>(ADDRESS_DILENGTH, command_length);
Core::System::GetInstance().GetDVDInterface().ExecuteCommand(DVD::ReplyType::IOS); system.GetDVDInterface().ExecuteCommand(DVD::ReplyType::IOS);
// Reply will be posted when done by FinishIOCtl. // Reply will be posted when done by FinishIOCtl.
return {}; return {};
} }
@ -665,10 +651,11 @@ void DIDevice::FinishDICommand(DIResult result)
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
auto* mmio = memory.GetMMIOMapping();
IOCtlRequest request{m_executing_command->m_request_address}; IOCtlRequest request{m_executing_command->m_request_address};
if (m_executing_command->m_copy_diimmbuf) if (m_executing_command->m_copy_diimmbuf)
memory.Write_U32(DIIMMBUF, request.buffer_out); memory.Write_U32(mmio->Read<u32>(ADDRESS_DIIMMBUF), request.buffer_out);
m_ios.EnqueueIPCReply(request, static_cast<s32>(result)); m_ios.EnqueueIPCReply(request, static_cast<s32>(result));

View file

@ -134,10 +134,13 @@ struct FileStatus
constexpr size_t MaxPathDepth = 8; constexpr size_t MaxPathDepth = 8;
/// The maximum number of characters a path can have. /// The maximum number of characters a path can have.
constexpr size_t MaxPathLength = 64; constexpr size_t MaxPathLength = 64;
/// The maximum number of characters a filename can have.
constexpr size_t MaxFilenameLength = 12;
/// Returns whether a Wii path is valid. /// Returns whether a Wii path is valid.
bool IsValidPath(std::string_view path); bool IsValidPath(std::string_view path);
bool IsValidNonRootPath(std::string_view path); bool IsValidNonRootPath(std::string_view path);
bool IsValidFilename(std::string_view filename);
struct SplitPathResult struct SplitPathResult
{ {

View file

@ -3,6 +3,8 @@
#include "Core/IOS/FS/FileSystem.h" #include "Core/IOS/FS/FileSystem.h"
#include <algorithm>
#include "Common/Assert.h" #include "Common/Assert.h"
#include "Common/FileUtil.h" #include "Common/FileUtil.h"
#include "Core/IOS/Device.h" #include "Core/IOS/Device.h"
@ -21,6 +23,12 @@ bool IsValidNonRootPath(std::string_view path)
path.back() != '/'; path.back() != '/';
} }
bool IsValidFilename(std::string_view filename)
{
return filename.length() <= MaxFilenameLength &&
!std::any_of(filename.begin(), filename.end(), [](char c) { return c == '/'; });
}
SplitPathResult SplitPathAndBasename(std::string_view path) SplitPathResult SplitPathAndBasename(std::string_view path)
{ {
const auto last_separator = path.rfind('/'); const auto last_separator = path.rfind('/');

View file

@ -4,6 +4,7 @@
#include "Core/IOS/FS/HostBackend/FS.h" #include "Core/IOS/FS/HostBackend/FS.h"
#include <algorithm> #include <algorithm>
#include <cmath>
#include <optional> #include <optional>
#include <string_view> #include <string_view>
#include <type_traits> #include <type_traits>
@ -11,6 +12,7 @@
#include <fmt/format.h> #include <fmt/format.h>
#include "Common/Align.h"
#include "Common/Assert.h" #include "Common/Assert.h"
#include "Common/ChunkFile.h" #include "Common/ChunkFile.h"
#include "Common/FileUtil.h" #include "Common/FileUtil.h"
@ -27,6 +29,21 @@ namespace IOS::HLE::FS
{ {
constexpr u32 BUFFER_CHUNK_SIZE = 65536; constexpr u32 BUFFER_CHUNK_SIZE = 65536;
// size of a single cluster in the NAND
constexpr u16 CLUSTER_SIZE = 16384;
// total number of clusters available in the NAND
constexpr u16 TOTAL_CLUSTERS = 0x7ec0;
// number of clusters reserved for bad blocks and similar, not accessible to normal writes
constexpr u16 RESERVED_CLUSTERS = 0x0300;
// number of clusters actually usable by the file system
constexpr u16 USABLE_CLUSTERS = TOTAL_CLUSTERS - RESERVED_CLUSTERS;
// total number of inodes available in the NAND
constexpr u16 TOTAL_INODES = 0x17ff;
HostFileSystem::HostFilename HostFileSystem::BuildFilename(const std::string& wii_path) const HostFileSystem::HostFilename HostFileSystem::BuildFilename(const std::string& wii_path) const
{ {
for (const auto& redirect : m_nand_redirects) for (const auto& redirect : m_nand_redirects)
@ -47,21 +64,6 @@ HostFileSystem::HostFilename HostFileSystem::BuildFilename(const std::string& wi
return HostFilename{m_root_path, false}; return HostFilename{m_root_path, false};
} }
// Get total filesize of contents of a directory (recursive)
// Only used for ES_GetUsage atm, could be useful elsewhere?
static u64 ComputeTotalFileSize(const File::FSTEntry& parent_entry)
{
u64 sizeOfFiles = 0;
for (const File::FSTEntry& entry : parent_entry.children)
{
if (entry.isDirectory)
sizeOfFiles += ComputeTotalFileSize(entry);
else
sizeOfFiles += entry.size;
}
return sizeOfFiles;
}
namespace namespace
{ {
struct SerializedFstEntry struct SerializedFstEntry
@ -102,6 +104,45 @@ auto GetNamePredicate(const std::string& name)
{ {
return [&name](const auto& entry) { return entry.name == name; }; return [&name](const auto& entry) { return entry.name == name; };
} }
// Convert the host directory entries into ones that can be exposed to the emulated system.
static u64 FixupDirectoryEntries(File::FSTEntry* dir, bool is_root)
{
u64 removed_entries = 0;
for (auto it = dir->children.begin(); it != dir->children.end();)
{
// Drop files in the root of the Wii NAND folder, since we store extra files there that the
// emulated system shouldn't know about.
if (is_root && !it->isDirectory)
{
++removed_entries;
it = dir->children.erase(it);
continue;
}
// Decode escaped invalid file system characters so that games (such as Harry Potter and the
// Half-Blood Prince) can find what they expect.
if (it->virtualName.find("__") != std::string::npos)
it->virtualName = Common::UnescapeFileName(it->virtualName);
// Drop files that have too long filenames.
if (!IsValidFilename(it->virtualName))
{
if (it->isDirectory)
removed_entries += it->size;
++removed_entries;
it = dir->children.erase(it);
continue;
}
if (dir->isDirectory)
removed_entries += FixupDirectoryEntries(&*it, false);
++it;
}
dir->size -= removed_entries;
return removed_entries;
}
} // namespace } // namespace
bool HostFileSystem::FstEntry::CheckPermission(Uid caller_uid, Gid caller_gid, bool HostFileSystem::FstEntry::CheckPermission(Uid caller_uid, Gid caller_gid,
@ -645,12 +686,7 @@ Result<std::vector<std::string>> HostFileSystem::ReadDirectory(Uid uid, Gid gid,
const std::string host_path = BuildFilename(path).host_path; const std::string host_path = BuildFilename(path).host_path;
File::FSTEntry host_entry = File::ScanDirectoryTree(host_path, false); File::FSTEntry host_entry = File::ScanDirectoryTree(host_path, false);
for (File::FSTEntry& child : host_entry.children) FixupDirectoryEntries(&host_entry, path == "/");
{
// Decode escaped invalid file system characters so that games (such as
// Harry Potter and the Half-Blood Prince) can find what they expect.
child.virtualName = Common::UnescapeFileName(child.virtualName);
}
// Sort files according to their order in the FST tree (issue 10234). // Sort files according to their order in the FST tree (issue 10234).
// The result should look like this: // The result should look like this:
@ -747,19 +783,33 @@ ResultCode HostFileSystem::SetMetadata(Uid caller_uid, const std::string& path,
return ResultCode::Success; return ResultCode::Success;
} }
static u64 ComputeUsedClusters(const File::FSTEntry& parent_entry)
{
u64 clusters = 0;
for (const File::FSTEntry& entry : parent_entry.children)
{
if (entry.isDirectory)
clusters += ComputeUsedClusters(entry);
else
clusters += Common::AlignUp(entry.size, CLUSTER_SIZE) / CLUSTER_SIZE;
}
return clusters;
}
Result<NandStats> HostFileSystem::GetNandStats() Result<NandStats> HostFileSystem::GetNandStats()
{ {
WARN_LOG_FMT(IOS_FS, "GET STATS - returning static values for now"); const auto root_stats = GetDirectoryStats("/");
if (!root_stats)
return root_stats.Error(); // TODO: is this right? can this fail on hardware?
// TODO: scrape the real amounts from somewhere...
NandStats stats{}; NandStats stats{};
stats.cluster_size = 0x4000; stats.cluster_size = CLUSTER_SIZE;
stats.free_clusters = 0x5DEC; stats.free_clusters = USABLE_CLUSTERS - root_stats->used_clusters;
stats.used_clusters = 0x1DD4; stats.used_clusters = root_stats->used_clusters;
stats.bad_clusters = 0x10; stats.bad_clusters = 0;
stats.reserved_clusters = 0x02F0; stats.reserved_clusters = RESERVED_CLUSTERS;
stats.free_inodes = 0x146B; stats.free_inodes = TOTAL_INODES - root_stats->used_inodes;
stats.used_inodes = 0x0394; stats.used_inodes = root_stats->used_inodes;
return stats; return stats;
} }
@ -771,19 +821,25 @@ Result<DirectoryStats> HostFileSystem::GetDirectoryStats(const std::string& wii_
DirectoryStats stats{}; DirectoryStats stats{};
std::string path(BuildFilename(wii_path).host_path); std::string path(BuildFilename(wii_path).host_path);
if (File::IsDirectory(path)) File::FileInfo info(path);
if (!info.Exists())
{
return ResultCode::NotFound;
}
if (info.IsDirectory())
{ {
File::FSTEntry parent_dir = File::ScanDirectoryTree(path, true); File::FSTEntry parent_dir = File::ScanDirectoryTree(path, true);
FixupDirectoryEntries(&parent_dir, wii_path == "/");
// add one for the folder itself // add one for the folder itself
stats.used_inodes = 1 + (u32)parent_dir.size; stats.used_inodes = static_cast<u32>(std::min<u64>(1 + parent_dir.size, TOTAL_INODES));
u64 total_size = ComputeTotalFileSize(parent_dir); // "Real" size to convert to nand blocks const u64 clusters = ComputeUsedClusters(parent_dir);
stats.used_clusters = static_cast<u32>(std::min<u64>(clusters, USABLE_CLUSTERS));
stats.used_clusters = (u32)(total_size / (16 * 1024)); // one block is 16kb
} }
else else
{ {
WARN_LOG_FMT(IOS_FS, "fsBlock failed, cannot find directory: {}", path); return ResultCode::Invalid;
} }
return stats; return stats;
} }

View file

@ -200,8 +200,9 @@ static void ResetAndPausePPC()
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
memory.Write_U32(0x48000000, 0x00000000); // b 0x0 memory.Write_U32(0x48000000, 0x00000000); // b 0x0
PowerPC::Reset(); auto& power_pc = system.GetPowerPC();
system.GetPPCState().pc = 0; power_pc.Reset();
power_pc.GetPPCState().pc = 0;
} }
static void ReleasePPC() static void ReleasePPC()

View file

@ -43,7 +43,7 @@ static void ReinitHardware()
// (and not by MIOS), causing games that use DTK to break. Perhaps MIOS doesn't actually // (and not by MIOS), causing games that use DTK to break. Perhaps MIOS doesn't actually
// reset DI fully, in such a way that the DTK config isn't cleared? // reset DI fully, in such a way that the DTK config isn't cleared?
// system.GetDVDInterface().ResetDrive(true); // system.GetDVDInterface().ResetDrive(true);
PowerPC::Reset(); system.GetPowerPC().Reset();
Wiimote::ResetAllWiimotes(); Wiimote::ResetAllWiimotes();
// Note: this is specific to Dolphin and is required because we initialised it in Wii mode. // Note: this is specific to Dolphin and is required because we initialised it in Wii mode.
auto& dsp = system.GetDSP(); auto& dsp = system.GetDSP();
@ -83,18 +83,18 @@ bool Load()
Host_NotifyMapLoaded(); Host_NotifyMapLoaded();
} }
auto& ppc_state = system.GetPPCState(); auto& power_pc = system.GetPowerPC();
const PowerPC::CoreMode core_mode = PowerPC::GetMode(); const PowerPC::CoreMode core_mode = power_pc.GetMode();
PowerPC::SetMode(PowerPC::CoreMode::Interpreter); power_pc.SetMode(PowerPC::CoreMode::Interpreter);
ppc_state.msr.Hex = 0; power_pc.GetPPCState().msr.Hex = 0;
ppc_state.pc = 0x3400; power_pc.GetPPCState().pc = 0x3400;
NOTICE_LOG_FMT(IOS, "Loaded MIOS and bootstrapped PPC."); NOTICE_LOG_FMT(IOS, "Loaded MIOS and bootstrapped PPC.");
// IOS writes 0 to 0x30f8 before bootstrapping the PPC. Once started, the IPL eventually writes // IOS writes 0 to 0x30f8 before bootstrapping the PPC. Once started, the IPL eventually writes
// 0xdeadbeef there, then waits for it to be cleared by IOS before continuing. // 0xdeadbeef there, then waits for it to be cleared by IOS before continuing.
while (memory.Read_U32(ADDRESS_INIT_SEMAPHORE) != 0xdeadbeef) while (memory.Read_U32(ADDRESS_INIT_SEMAPHORE) != 0xdeadbeef)
PowerPC::SingleStep(); power_pc.SingleStep();
PowerPC::SetMode(core_mode); power_pc.SetMode(core_mode);
memory.Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE); memory.Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE);
NOTICE_LOG_FMT(IOS, "IPL ready."); NOTICE_LOG_FMT(IOS, "IPL ready.");

View file

@ -233,6 +233,7 @@ NWC24::ErrorCode NetKDRequestDevice::KDDownload(const u16 entry_index,
IPCReply NetKDRequestDevice::HandleNWC24DownloadNowEx(const IOCtlRequest& request) IPCReply NetKDRequestDevice::HandleNWC24DownloadNowEx(const IOCtlRequest& request)
{ {
m_dl_list.ReadDlList();
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();
const u32 flags = memory.Read_U32(request.buffer_in); const u32 flags = memory.Read_U32(request.buffer_in);

View file

@ -63,7 +63,10 @@ int SSLSendWithoutSNI(void* ctx, const unsigned char* buf, size_t len)
// Log raw SSL packets if we don't dump unencrypted SSL writes // Log raw SSL packets if we don't dump unencrypted SSL writes
if (!Config::Get(Config::MAIN_NETWORK_SSL_DUMP_WRITE) && ret > 0) if (!Config::Get(Config::MAIN_NETWORK_SSL_DUMP_WRITE) && ret > 0)
PowerPC::debug_interface.NetworkLogger()->LogWrite(buf, ret, *fd, nullptr); {
Core::System::GetInstance().GetPowerPC().GetDebugInterface().NetworkLogger()->LogWrite(
buf, ret, *fd, nullptr);
}
return ret; return ret;
} }
@ -76,7 +79,10 @@ int SSLRecv(void* ctx, unsigned char* buf, size_t len)
// Log raw SSL packets if we don't dump unencrypted SSL reads // Log raw SSL packets if we don't dump unencrypted SSL reads
if (!Config::Get(Config::MAIN_NETWORK_SSL_DUMP_READ) && ret > 0) if (!Config::Get(Config::MAIN_NETWORK_SSL_DUMP_READ) && ret > 0)
PowerPC::debug_interface.NetworkLogger()->LogRead(buf, ret, *fd, nullptr); {
Core::System::GetInstance().GetPowerPC().GetDebugInterface().NetworkLogger()->LogRead(
buf, ret, *fd, nullptr);
}
return ret; return ret;
} }

View file

@ -487,8 +487,8 @@ void WiiSocket::Update(bool read, bool write, bool except)
if (ret >= 0) if (ret >= 0)
{ {
PowerPC::debug_interface.NetworkLogger()->LogSSLWrite(memory.GetPointer(BufferOut2), system.GetPowerPC().GetDebugInterface().NetworkLogger()->LogSSLWrite(
ret, ssl->hostfd); memory.GetPointer(BufferOut2), ret, ssl->hostfd);
// Return bytes written or SSL_ERR_ZERO if none // Return bytes written or SSL_ERR_ZERO if none
WriteReturnValue((ret == 0) ? SSL_ERR_ZERO : ret, BufferIn); WriteReturnValue((ret == 0) ? SSL_ERR_ZERO : ret, BufferIn);
} }
@ -521,8 +521,8 @@ void WiiSocket::Update(bool read, bool write, bool except)
if (ret >= 0) if (ret >= 0)
{ {
PowerPC::debug_interface.NetworkLogger()->LogSSLRead(memory.GetPointer(BufferIn2), system.GetPowerPC().GetDebugInterface().NetworkLogger()->LogSSLRead(
ret, ssl->hostfd); memory.GetPointer(BufferIn2), ret, ssl->hostfd);
// Return bytes read or SSL_ERR_ZERO if none // Return bytes read or SSL_ERR_ZERO if none
WriteReturnValue((ret == 0) ? SSL_ERR_ZERO : ret, BufferIn); WriteReturnValue((ret == 0) ? SSL_ERR_ZERO : ret, BufferIn);
} }
@ -595,7 +595,7 @@ void WiiSocket::Update(bool read, bool write, bool except)
const int ret = sendto(fd, data, BufferInSize, flags, to, tolen); const int ret = sendto(fd, data, BufferInSize, flags, to, tolen);
ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_SENDTO", true); ReturnValue = WiiSockMan::GetNetErrorCode(ret, "SO_SENDTO", true);
if (ret > 0) if (ret > 0)
PowerPC::debug_interface.NetworkLogger()->LogWrite(data, ret, fd, to); system.GetPowerPC().GetDebugInterface().NetworkLogger()->LogWrite(data, ret, fd, to);
INFO_LOG_FMT(IOS_NET, INFO_LOG_FMT(IOS_NET,
"{} = {} Socket: {:08x}, BufferIn: ({:08x}, {}), BufferIn2: ({:08x}, {}), " "{} = {} Socket: {:08x}, BufferIn: ({:08x}, {}), BufferIn2: ({:08x}, {}), "
@ -654,7 +654,7 @@ void WiiSocket::Update(bool read, bool write, bool except)
ReturnValue = ReturnValue =
WiiSockMan::GetNetErrorCode(ret, BufferOutSize2 ? "SO_RECVFROM" : "SO_RECV", true); WiiSockMan::GetNetErrorCode(ret, BufferOutSize2 ? "SO_RECVFROM" : "SO_RECV", true);
if (ret > 0) if (ret > 0)
PowerPC::debug_interface.NetworkLogger()->LogRead(data, ret, fd, from); system.GetPowerPC().GetDebugInterface().NetworkLogger()->LogRead(data, ret, fd, from);
INFO_LOG_FMT(IOS_NET, INFO_LOG_FMT(IOS_NET,
"{}({}, {}) Socket: {:08X}, Flags: {:08X}, " "{}({}, {}) Socket: {:08X}, Flags: {:08X}, "
@ -865,7 +865,7 @@ s32 WiiSockMan::AddSocket(s32 fd, bool is_rw)
WiiSocket& sock = WiiSockets[wii_fd]; WiiSocket& sock = WiiSockets[wii_fd];
sock.SetFd(fd); sock.SetFd(fd);
sock.SetWiiFd(wii_fd); sock.SetWiiFd(wii_fd);
PowerPC::debug_interface.NetworkLogger()->OnNewSocket(fd); Core::System::GetInstance().GetPowerPC().GetDebugInterface().NetworkLogger()->OnNewSocket(fd);
#ifdef __APPLE__ #ifdef __APPLE__
int opt_no_sigpipe = 1; int opt_no_sigpipe = 1;

View file

@ -103,7 +103,7 @@ std::optional<IPCReply> USB_HIDv4::GetDeviceChange(const IOCtlRequest& request)
IPCReply USB_HIDv4::Shutdown(const IOCtlRequest& request) IPCReply USB_HIDv4::Shutdown(const IOCtlRequest& request)
{ {
std::lock_guard lk{m_devicechange_hook_address_mutex}; std::lock_guard lk{m_devicechange_hook_address_mutex};
if (m_devicechange_hook_request != 0) if (m_devicechange_hook_request != nullptr)
{ {
auto& system = Core::System::GetInstance(); auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory(); auto& memory = system.GetMemory();

View file

@ -191,7 +191,7 @@ USB_KBD::USB_KBD(Kernel& ios, const std::string& device_name) : Device(ios, devi
std::optional<IPCReply> USB_KBD::Open(const OpenRequest& request) std::optional<IPCReply> USB_KBD::Open(const OpenRequest& request)
{ {
INFO_LOG_FMT(IOS, "USB_KBD: Open"); INFO_LOG_FMT(IOS, "USB_KBD: Open");
IniFile ini; Common::IniFile ini;
ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX)); ini.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX));
ini.GetOrCreateSection("USB Keyboard")->Get("Layout", &m_keyboard_layout, KBD_LAYOUT_QWERTY); ini.GetOrCreateSection("USB Keyboard")->Get("Layout", &m_keyboard_layout, KBD_LAYOUT_QWERTY);

View file

@ -23,7 +23,7 @@
#include "Common/CommonPaths.h" #include "Common/CommonPaths.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Crypto/SHA1.h" #include "Common/Crypto/SHA1.h"
#include "Common/ENetUtil.h" #include "Common/ENet.h"
#include "Common/FileUtil.h" #include "Common/FileUtil.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Common/MsgHandler.h" #include "Common/MsgHandler.h"
@ -168,7 +168,7 @@ NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlay
{ {
if (Connect()) if (Connect())
{ {
m_client->intercept = ENetUtil::InterceptCallback; m_client->intercept = Common::ENet::InterceptCallback;
m_thread = std::thread(&NetPlayClient::ThreadFunc, this); m_thread = std::thread(&NetPlayClient::ThreadFunc, this);
} }
} }
@ -254,7 +254,8 @@ bool NetPlayClient::Connect()
// TODO: make this not hang // TODO: make this not hang
ENetEvent netEvent; ENetEvent netEvent;
int net; int net;
while ((net = enet_host_service(m_client, &netEvent, 5000)) > 0 && netEvent.type == 42) while ((net = enet_host_service(m_client, &netEvent, 5000)) > 0 &&
netEvent.type == ENetEventType(42)) // See PR #11381 and ENetUtil::InterceptCallback
{ {
// ignore packets from traversal server // ignore packets from traversal server
} }
@ -1522,7 +1523,7 @@ void NetPlayClient::OnGameDigestAbort()
void NetPlayClient::Send(const sf::Packet& packet, const u8 channel_id) void NetPlayClient::Send(const sf::Packet& packet, const u8 channel_id)
{ {
ENetUtil::SendPacket(m_server, packet, channel_id); Common::ENet::SendPacket(m_server, packet, channel_id);
} }
void NetPlayClient::DisplayPlayersPing() void NetPlayClient::DisplayPlayersPing()
@ -1577,7 +1578,7 @@ void NetPlayClient::SendAsync(sf::Packet&& packet, const u8 channel_id)
std::lock_guard lkq(m_crit.async_queue_write); std::lock_guard lkq(m_crit.async_queue_write);
m_async_queue.Push(AsyncQueueEntry{std::move(packet), channel_id}); m_async_queue.Push(AsyncQueueEntry{std::move(packet), channel_id});
} }
ENetUtil::WakeupThread(m_client); Common::ENet::WakeupThread(m_client);
} }
// called from ---NETPLAY--- thread // called from ---NETPLAY--- thread

View file

@ -20,7 +20,7 @@
#include <fmt/format.h> #include <fmt/format.h>
#include "Common/CommonPaths.h" #include "Common/CommonPaths.h"
#include "Common/ENetUtil.h" #include "Common/ENet.h"
#include "Common/FileUtil.h" #include "Common/FileUtil.h"
#include "Common/HttpRequest.h" #include "Common/HttpRequest.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
@ -111,7 +111,7 @@ NetPlayServer::~NetPlayServer()
} }
#ifdef USE_UPNP #ifdef USE_UPNP
UPnP::StopPortmapping(); Common::UPnP::StopPortmapping();
#endif #endif
} }
@ -153,7 +153,7 @@ NetPlayServer::NetPlayServer(const u16 port, const bool forward_port, NetPlayUI*
if (m_server != nullptr) if (m_server != nullptr)
{ {
m_server->mtu = std::min(m_server->mtu, NetPlay::MAX_ENET_MTU); m_server->mtu = std::min(m_server->mtu, NetPlay::MAX_ENET_MTU);
m_server->intercept = ENetUtil::InterceptCallback; m_server->intercept = Common::ENet::InterceptCallback;
} }
SetupIndex(); SetupIndex();
@ -168,7 +168,7 @@ NetPlayServer::NetPlayServer(const u16 port, const bool forward_port, NetPlayUI*
#ifdef USE_UPNP #ifdef USE_UPNP
if (forward_port) if (forward_port)
UPnP::TryPortmapping(port); Common::UPnP::TryPortmapping(port);
#endif #endif
} }
} }
@ -701,7 +701,7 @@ void NetPlayServer::SendAsync(sf::Packet&& packet, const PlayerId pid, const u8
std::lock_guard lkq(m_crit.async_queue_write); std::lock_guard lkq(m_crit.async_queue_write);
m_async_queue.Push(AsyncQueueEntry{std::move(packet), pid, TargetMode::Only, channel_id}); m_async_queue.Push(AsyncQueueEntry{std::move(packet), pid, TargetMode::Only, channel_id});
} }
ENetUtil::WakeupThread(m_server); Common::ENet::WakeupThread(m_server);
} }
void NetPlayServer::SendAsyncToClients(sf::Packet&& packet, const PlayerId skip_pid, void NetPlayServer::SendAsyncToClients(sf::Packet&& packet, const PlayerId skip_pid,
@ -712,7 +712,7 @@ void NetPlayServer::SendAsyncToClients(sf::Packet&& packet, const PlayerId skip_
m_async_queue.Push( m_async_queue.Push(
AsyncQueueEntry{std::move(packet), skip_pid, TargetMode::AllExcept, channel_id}); AsyncQueueEntry{std::move(packet), skip_pid, TargetMode::AllExcept, channel_id});
} }
ENetUtil::WakeupThread(m_server); Common::ENet::WakeupThread(m_server);
} }
void NetPlayServer::SendChunked(sf::Packet&& packet, const PlayerId pid, const std::string& title) void NetPlayServer::SendChunked(sf::Packet&& packet, const PlayerId pid, const std::string& title)
@ -2027,10 +2027,10 @@ bool NetPlayServer::SyncCodes()
// Find all INI files // Find all INI files
const auto game_id = game->GetGameID(); const auto game_id = game->GetGameID();
const auto revision = game->GetRevision(); const auto revision = game->GetRevision();
IniFile globalIni; Common::IniFile globalIni;
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(game_id, revision)) for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(game_id, revision))
globalIni.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename, true); globalIni.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename, true);
IniFile localIni; Common::IniFile localIni;
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(game_id, revision)) for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(game_id, revision))
localIni.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + filename, true); localIni.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + filename, true);
@ -2183,7 +2183,7 @@ void NetPlayServer::SendToClients(const sf::Packet& packet, const PlayerId skip_
void NetPlayServer::Send(ENetPeer* socket, const sf::Packet& packet, const u8 channel_id) void NetPlayServer::Send(ENetPeer* socket, const sf::Packet& packet, const u8 channel_id)
{ {
ENetUtil::SendPacket(socket, packet, channel_id); Common::ENet::SendPacket(socket, packet, channel_id);
} }
void NetPlayServer::KickPlayer(PlayerId player) void NetPlayServer::KickPlayer(PlayerId player)
@ -2266,8 +2266,7 @@ u16 NetPlayServer::GetPort() const
std::unordered_set<std::string> NetPlayServer::GetInterfaceSet() const std::unordered_set<std::string> NetPlayServer::GetInterfaceSet() const
{ {
std::unordered_set<std::string> result; std::unordered_set<std::string> result;
auto lst = GetInterfaceListInternal(); for (const auto& list_entry : GetInterfaceListInternal())
for (auto list_entry : lst)
result.emplace(list_entry.first); result.emplace(list_entry.first);
return result; return result;
} }

View file

@ -102,11 +102,9 @@ std::string SerializeLine(const PatchEntry& entry)
} }
void LoadPatchSection(const std::string& section, std::vector<Patch>* patches, void LoadPatchSection(const std::string& section, std::vector<Patch>* patches,
const IniFile& globalIni, const IniFile& localIni) const Common::IniFile& globalIni, const Common::IniFile& localIni)
{ {
const IniFile* inis[2] = {&globalIni, &localIni}; for (const auto* ini : {&globalIni, &localIni})
for (const IniFile* ini : inis)
{ {
std::vector<std::string> lines; std::vector<std::string> lines;
Patch currentPatch; Patch currentPatch;
@ -152,7 +150,7 @@ void LoadPatchSection(const std::string& section, std::vector<Patch>* patches,
} }
} }
void SavePatchSection(IniFile* local_ini, const std::vector<Patch>& patches) void SavePatchSection(Common::IniFile* local_ini, const std::vector<Patch>& patches)
{ {
std::vector<std::string> lines; std::vector<std::string> lines;
std::vector<std::string> lines_enabled; std::vector<std::string> lines_enabled;
@ -177,7 +175,7 @@ void SavePatchSection(IniFile* local_ini, const std::vector<Patch>& patches)
local_ini->SetLines("OnFrame", lines); local_ini->SetLines("OnFrame", lines);
} }
static void LoadSpeedhacks(const std::string& section, IniFile& ini) static void LoadSpeedhacks(const std::string& section, Common::IniFile& ini)
{ {
std::vector<std::string> keys; std::vector<std::string> keys;
ini.GetKeys(section, &keys); ini.GetKeys(section, &keys);
@ -211,9 +209,10 @@ int GetSpeedhackCycles(const u32 addr)
void LoadPatches() void LoadPatches()
{ {
IniFile merged = SConfig::GetInstance().LoadGameIni(); const auto& sconfig = SConfig::GetInstance();
IniFile globalIni = SConfig::GetInstance().LoadDefaultGameIni(); Common::IniFile merged = sconfig.LoadGameIni();
IniFile localIni = SConfig::GetInstance().LoadLocalGameIni(); Common::IniFile globalIni = sconfig.LoadDefaultGameIni();
Common::IniFile localIni = sconfig.LoadLocalGameIni();
LoadPatchSection("OnFrame", &s_on_frame, globalIni, localIni); LoadPatchSection("OnFrame", &s_on_frame, globalIni, localIni);
@ -278,7 +277,7 @@ static void ApplyMemoryPatches(const Core::CPUThreadGuard& guard,
std::lock_guard lock(s_on_frame_memory_mutex); std::lock_guard lock(s_on_frame_memory_mutex);
for (std::size_t index : memory_patch_indices) for (std::size_t index : memory_patch_indices)
{ {
PowerPC::debug_interface.ApplyExistingPatch(guard, index); guard.GetSystem().GetPowerPC().GetDebugInterface().ApplyExistingPatch(guard, index);
} }
} }

View file

@ -9,7 +9,10 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
namespace Common
{
class IniFile; class IniFile;
}
namespace PatchEngine namespace PatchEngine
{ {
@ -47,8 +50,8 @@ int GetSpeedhackCycles(const u32 addr);
std::optional<PatchEntry> DeserializeLine(std::string line); std::optional<PatchEntry> DeserializeLine(std::string line);
std::string SerializeLine(const PatchEntry& entry); std::string SerializeLine(const PatchEntry& entry);
void LoadPatchSection(const std::string& section, std::vector<Patch>* patches, void LoadPatchSection(const std::string& section, std::vector<Patch>* patches,
const IniFile& globalIni, const IniFile& localIni); const Common::IniFile& globalIni, const Common::IniFile& localIni);
void SavePatchSection(IniFile* local_ini, const std::vector<Patch>& patches); void SavePatchSection(Common::IniFile* local_ini, const std::vector<Patch>& patches);
void LoadPatches(); void LoadPatches();
void AddMemoryPatch(std::size_t index); void AddMemoryPatch(std::size_t index);

View file

@ -16,8 +16,15 @@
#include "Core/PowerPC/Expression.h" #include "Core/PowerPC/Expression.h"
#include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/JitInterface.h"
#include "Core/PowerPC/MMU.h" #include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h" #include "Core/System.h"
BreakPoints::BreakPoints(Core::System& system) : m_system(system)
{
}
BreakPoints::~BreakPoints() = default;
bool BreakPoints::IsAddressBreakPoint(u32 address) const bool BreakPoints::IsAddressBreakPoint(u32 address) const
{ {
return std::any_of(m_breakpoints.begin(), m_breakpoints.end(), return std::any_of(m_breakpoints.begin(), m_breakpoints.end(),
@ -106,7 +113,7 @@ void BreakPoints::Add(TBreakPoint bp)
if (IsAddressBreakPoint(bp.address)) if (IsAddressBreakPoint(bp.address))
return; return;
Core::System::GetInstance().GetJitInterface().InvalidateICache(bp.address, 4, true); m_system.GetJitInterface().InvalidateICache(bp.address, 4, true);
m_breakpoints.emplace_back(std::move(bp)); m_breakpoints.emplace_back(std::move(bp));
} }
@ -142,7 +149,7 @@ void BreakPoints::Add(u32 address, bool temp, bool break_on_hit, bool log_on_hit
m_breakpoints.emplace_back(std::move(bp)); m_breakpoints.emplace_back(std::move(bp));
} }
Core::System::GetInstance().GetJitInterface().InvalidateICache(address, 4, true); m_system.GetJitInterface().InvalidateICache(address, 4, true);
} }
bool BreakPoints::ToggleBreakPoint(u32 address) bool BreakPoints::ToggleBreakPoint(u32 address)
@ -166,14 +173,14 @@ void BreakPoints::Remove(u32 address)
return; return;
m_breakpoints.erase(iter); m_breakpoints.erase(iter);
Core::System::GetInstance().GetJitInterface().InvalidateICache(address, 4, true); m_system.GetJitInterface().InvalidateICache(address, 4, true);
} }
void BreakPoints::Clear() void BreakPoints::Clear()
{ {
for (const TBreakPoint& bp : m_breakpoints) for (const TBreakPoint& bp : m_breakpoints)
{ {
Core::System::GetInstance().GetJitInterface().InvalidateICache(bp.address, 4, true); m_system.GetJitInterface().InvalidateICache(bp.address, 4, true);
} }
m_breakpoints.clear(); m_breakpoints.clear();
@ -186,7 +193,7 @@ void BreakPoints::ClearAllTemporary()
{ {
if (bp->is_temporary) if (bp->is_temporary)
{ {
Core::System::GetInstance().GetJitInterface().InvalidateICache(bp->address, 4, true); m_system.GetJitInterface().InvalidateICache(bp->address, 4, true);
bp = m_breakpoints.erase(bp); bp = m_breakpoints.erase(bp);
} }
else else
@ -196,6 +203,12 @@ void BreakPoints::ClearAllTemporary()
} }
} }
MemChecks::MemChecks(Core::System& system) : m_system(system)
{
}
MemChecks::~MemChecks() = default;
MemChecks::TMemChecksStr MemChecks::GetStrings() const MemChecks::TMemChecksStr MemChecks::GetStrings() const
{ {
TMemChecksStr mc_strings; TMemChecksStr mc_strings;
@ -279,8 +292,8 @@ void MemChecks::Add(TMemCheck memory_check)
// If this is the first one, clear the JIT cache so it can switch to // If this is the first one, clear the JIT cache so it can switch to
// watchpoint-compatible code. // watchpoint-compatible code.
if (!had_any) if (!had_any)
Core::System::GetInstance().GetJitInterface().ClearCache(); m_system.GetJitInterface().ClearCache();
Core::System::GetInstance().GetMMU().DBATUpdated(); m_system.GetMMU().DBATUpdated();
}); });
} }
@ -308,8 +321,8 @@ void MemChecks::Remove(u32 address)
Core::RunAsCPUThread([&] { Core::RunAsCPUThread([&] {
m_mem_checks.erase(iter); m_mem_checks.erase(iter);
if (!HasAny()) if (!HasAny())
Core::System::GetInstance().GetJitInterface().ClearCache(); m_system.GetJitInterface().ClearCache();
Core::System::GetInstance().GetMMU().DBATUpdated(); m_system.GetMMU().DBATUpdated();
}); });
} }
@ -317,8 +330,8 @@ void MemChecks::Clear()
{ {
Core::RunAsCPUThread([&] { Core::RunAsCPUThread([&] {
m_mem_checks.clear(); m_mem_checks.clear();
Core::System::GetInstance().GetJitInterface().ClearCache(); m_system.GetJitInterface().ClearCache();
Core::System::GetInstance().GetMMU().DBATUpdated(); m_system.GetMMU().DBATUpdated();
}); });
} }
@ -352,14 +365,14 @@ bool MemChecks::OverlapsMemcheck(u32 address, u32 length) const
}); });
} }
bool TMemCheck::Action(Common::DebugInterface* debug_interface, u64 value, u32 addr, bool write, bool TMemCheck::Action(Core::System& system, Common::DebugInterface* debug_interface, u64 value,
size_t size, u32 pc) u32 addr, bool write, size_t size, u32 pc)
{ {
if (!is_enabled) if (!is_enabled)
return false; return false;
if (((write && is_break_on_write) || (!write && is_break_on_read)) && if (((write && is_break_on_write) || (!write && is_break_on_read)) &&
EvaluateCondition(this->condition)) EvaluateCondition(system, this->condition))
{ {
if (log_on_hit) if (log_on_hit)
{ {

View file

@ -15,6 +15,10 @@ namespace Common
{ {
class DebugInterface; class DebugInterface;
} }
namespace Core
{
class System;
}
struct TBreakPoint struct TBreakPoint
{ {
@ -45,14 +49,21 @@ struct TMemCheck
std::optional<Expression> condition; std::optional<Expression> condition;
// returns whether to break // returns whether to break
bool Action(Common::DebugInterface* debug_interface, u64 value, u32 addr, bool write, size_t size, bool Action(Core::System& system, Common::DebugInterface* debug_interface, u64 value, u32 addr,
u32 pc); bool write, size_t size, u32 pc);
}; };
// Code breakpoints. // Code breakpoints.
class BreakPoints class BreakPoints
{ {
public: public:
explicit BreakPoints(Core::System& system);
BreakPoints(const BreakPoints& other) = delete;
BreakPoints(BreakPoints&& other) = delete;
BreakPoints& operator=(const BreakPoints& other) = delete;
BreakPoints& operator=(BreakPoints&& other) = delete;
~BreakPoints();
using TBreakPoints = std::vector<TBreakPoint>; using TBreakPoints = std::vector<TBreakPoint>;
using TBreakPointsStr = std::vector<std::string>; using TBreakPointsStr = std::vector<std::string>;
@ -82,12 +93,20 @@ public:
private: private:
TBreakPoints m_breakpoints; TBreakPoints m_breakpoints;
Core::System& m_system;
}; };
// Memory breakpoints // Memory breakpoints
class MemChecks class MemChecks
{ {
public: public:
explicit MemChecks(Core::System& system);
MemChecks(const MemChecks& other) = delete;
MemChecks(MemChecks&& other) = delete;
MemChecks& operator=(const MemChecks& other) = delete;
MemChecks& operator=(MemChecks&& other) = delete;
~MemChecks();
using TMemChecks = std::vector<TMemCheck>; using TMemChecks = std::vector<TMemCheck>;
using TMemChecksStr = std::vector<std::string>; using TMemChecksStr = std::vector<std::string>;
@ -109,4 +128,5 @@ public:
private: private:
TMemChecks m_mem_checks; TMemChecks m_mem_checks;
Core::System& m_system;
}; };

View file

@ -214,7 +214,7 @@ bool CachedInterpreter::CheckFPU(CachedInterpreter& cached_interpreter, u32 data
if (!ppc_state.msr.FP) if (!ppc_state.msr.FP)
{ {
ppc_state.Exceptions |= EXCEPTION_FPU_UNAVAILABLE; ppc_state.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
PowerPC::CheckExceptions(); cached_interpreter.m_system.GetPowerPC().CheckExceptions();
ppc_state.downcount -= data; ppc_state.downcount -= data;
return true; return true;
} }
@ -226,7 +226,7 @@ bool CachedInterpreter::CheckDSI(CachedInterpreter& cached_interpreter, u32 data
auto& ppc_state = cached_interpreter.m_ppc_state; auto& ppc_state = cached_interpreter.m_ppc_state;
if (ppc_state.Exceptions & EXCEPTION_DSI) if (ppc_state.Exceptions & EXCEPTION_DSI)
{ {
PowerPC::CheckExceptions(); cached_interpreter.m_system.GetPowerPC().CheckExceptions();
ppc_state.downcount -= data; ppc_state.downcount -= data;
return true; return true;
} }
@ -238,7 +238,7 @@ bool CachedInterpreter::CheckProgramException(CachedInterpreter& cached_interpre
auto& ppc_state = cached_interpreter.m_ppc_state; auto& ppc_state = cached_interpreter.m_ppc_state;
if (ppc_state.Exceptions & EXCEPTION_PROGRAM) if (ppc_state.Exceptions & EXCEPTION_PROGRAM)
{ {
PowerPC::CheckExceptions(); cached_interpreter.m_system.GetPowerPC().CheckExceptions();
ppc_state.downcount -= data; ppc_state.downcount -= data;
return true; return true;
} }
@ -247,7 +247,7 @@ bool CachedInterpreter::CheckProgramException(CachedInterpreter& cached_interpre
bool CachedInterpreter::CheckBreakpoint(CachedInterpreter& cached_interpreter, u32 data) bool CachedInterpreter::CheckBreakpoint(CachedInterpreter& cached_interpreter, u32 data)
{ {
PowerPC::CheckBreakPoints(); cached_interpreter.m_system.GetPowerPC().CheckBreakPoints();
if (cached_interpreter.m_system.GetCPU().GetState() != CPU::State::Running) if (cached_interpreter.m_system.GetCPU().GetState() != CPU::State::Running)
{ {
cached_interpreter.m_ppc_state.downcount -= data; cached_interpreter.m_ppc_state.downcount -= data;
@ -295,7 +295,7 @@ void CachedInterpreter::Jit(u32 address)
// Address of instruction could not be translated // Address of instruction could not be translated
m_ppc_state.npc = nextPC; m_ppc_state.npc = nextPC;
m_ppc_state.Exceptions |= EXCEPTION_ISI; m_ppc_state.Exceptions |= EXCEPTION_ISI;
PowerPC::CheckExceptions(); m_system.GetPowerPC().CheckExceptions();
WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC); WARN_LOG_FMT(POWERPC, "ISI exception at {:#010x}", nextPC);
return; return;
} }
@ -329,7 +329,8 @@ void CachedInterpreter::Jit(u32 address)
if (!op.skip) if (!op.skip)
{ {
const bool breakpoint = const bool breakpoint =
m_enable_debugging && PowerPC::breakpoints.IsAddressBreakPoint(op.address); m_enable_debugging &&
m_system.GetPowerPC().GetBreakPoints().IsAddressBreakPoint(op.address);
const bool check_fpu = (op.opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound; const bool check_fpu = (op.opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound;
const bool endblock = (op.opinfo->flags & FL_ENDBLOCK) != 0; const bool endblock = (op.opinfo->flags & FL_ENDBLOCK) != 0;
const bool memcheck = (op.opinfo->flags & FL_LOADSTORE) && jo.memcheck; const bool memcheck = (op.opinfo->flags & FL_LOADSTORE) && jo.memcheck;

View file

@ -267,21 +267,22 @@ std::optional<Expression> Expression::TryParse(std::string_view text)
return Expression{text, std::move(ex), std::move(vars)}; return Expression{text, std::move(ex), std::move(vars)};
} }
double Expression::Evaluate() const double Expression::Evaluate(Core::System& system) const
{ {
SynchronizeBindings(SynchronizeDirection::From); SynchronizeBindings(system, SynchronizeDirection::From);
double result = expr_eval(m_expr.get()); double result = expr_eval(m_expr.get());
SynchronizeBindings(SynchronizeDirection::To); SynchronizeBindings(system, SynchronizeDirection::To);
Reporting(result); Reporting(result);
return result; return result;
} }
void Expression::SynchronizeBindings(SynchronizeDirection dir) const void Expression::SynchronizeBindings(Core::System& system, SynchronizeDirection dir) const
{ {
auto& ppc_state = system.GetPPCState();
auto bind = m_binds.begin(); auto bind = m_binds.begin();
for (auto* v = m_vars->head; v != nullptr; v = v->next, ++bind) for (auto* v = m_vars->head; v != nullptr; v = v->next, ++bind)
{ {
@ -293,25 +294,25 @@ void Expression::SynchronizeBindings(SynchronizeDirection dir) const
break; break;
case VarBindingType::GPR: case VarBindingType::GPR:
if (dir == SynchronizeDirection::From) if (dir == SynchronizeDirection::From)
v->value = static_cast<double>(PowerPC::ppcState.gpr[bind->index]); v->value = static_cast<double>(ppc_state.gpr[bind->index]);
else else
PowerPC::ppcState.gpr[bind->index] = static_cast<u32>(static_cast<s64>(v->value)); ppc_state.gpr[bind->index] = static_cast<u32>(static_cast<s64>(v->value));
break; break;
case VarBindingType::FPR: case VarBindingType::FPR:
if (dir == SynchronizeDirection::From) if (dir == SynchronizeDirection::From)
v->value = PowerPC::ppcState.ps[bind->index].PS0AsDouble(); v->value = ppc_state.ps[bind->index].PS0AsDouble();
else else
PowerPC::ppcState.ps[bind->index].SetPS0(v->value); ppc_state.ps[bind->index].SetPS0(v->value);
break; break;
case VarBindingType::SPR: case VarBindingType::SPR:
if (dir == SynchronizeDirection::From) if (dir == SynchronizeDirection::From)
v->value = static_cast<double>(PowerPC::ppcState.spr[bind->index]); v->value = static_cast<double>(ppc_state.spr[bind->index]);
else else
PowerPC::ppcState.spr[bind->index] = static_cast<u32>(static_cast<s64>(v->value)); ppc_state.spr[bind->index] = static_cast<u32>(static_cast<s64>(v->value));
break; break;
case VarBindingType::PCtr: case VarBindingType::PCtr:
if (dir == SynchronizeDirection::From) if (dir == SynchronizeDirection::From)
v->value = static_cast<double>(PowerPC::ppcState.pc); v->value = static_cast<double>(ppc_state.pc);
break; break;
} }
} }

View file

@ -15,7 +15,8 @@ struct expr_var_list;
namespace Core namespace Core
{ {
class CPUThreadGuard; class CPUThreadGuard;
} class System;
} // namespace Core
struct ExprDeleter struct ExprDeleter
{ {
@ -36,7 +37,7 @@ class Expression
public: public:
static std::optional<Expression> TryParse(std::string_view text); static std::optional<Expression> TryParse(std::string_view text);
double Evaluate() const; double Evaluate(Core::System& system) const;
std::string GetText() const; std::string GetText() const;
@ -64,7 +65,7 @@ private:
Expression(std::string_view text, ExprPointer ex, ExprVarListPointer vars); Expression(std::string_view text, ExprPointer ex, ExprVarListPointer vars);
void SynchronizeBindings(SynchronizeDirection dir) const; void SynchronizeBindings(Core::System& system, SynchronizeDirection dir) const;
void Reporting(const double result) const; void Reporting(const double result) const;
std::string m_text; std::string m_text;
@ -73,7 +74,7 @@ private:
std::vector<VarBinding> m_binds; std::vector<VarBinding> m_binds;
}; };
inline bool EvaluateCondition(const std::optional<Expression>& condition) inline bool EvaluateCondition(Core::System& system, const std::optional<Expression>& condition)
{ {
return !condition || condition->Evaluate() != 0.0; return !condition || condition->Evaluate(system) != 0.0;
} }

View file

@ -163,17 +163,19 @@ static void RemoveBreakpoint(BreakpointType type, u32 addr, u32 len)
{ {
if (type == BreakpointType::ExecuteHard || type == BreakpointType::ExecuteSoft) if (type == BreakpointType::ExecuteHard || type == BreakpointType::ExecuteSoft)
{ {
while (PowerPC::breakpoints.IsAddressBreakPoint(addr)) auto& breakpoints = Core::System::GetInstance().GetPowerPC().GetBreakPoints();
while (breakpoints.IsAddressBreakPoint(addr))
{ {
PowerPC::breakpoints.Remove(addr); breakpoints.Remove(addr);
INFO_LOG_FMT(GDB_STUB, "gdb: removed a breakpoint: {:08x} bytes at {:08x}", len, addr); INFO_LOG_FMT(GDB_STUB, "gdb: removed a breakpoint: {:08x} bytes at {:08x}", len, addr);
} }
} }
else else
{ {
while (PowerPC::memchecks.GetMemCheck(addr, len) != nullptr) auto& memchecks = Core::System::GetInstance().GetPowerPC().GetMemChecks();
while (memchecks.GetMemCheck(addr, len) != nullptr)
{ {
PowerPC::memchecks.Remove(addr); memchecks.Remove(addr);
INFO_LOG_FMT(GDB_STUB, "gdb: removed a memcheck: {:08x} bytes at {:08x}", len, addr); INFO_LOG_FMT(GDB_STUB, "gdb: removed a memcheck: {:08x} bytes at {:08x}", len, addr);
} }
} }
@ -869,7 +871,8 @@ static bool AddBreakpoint(BreakpointType type, u32 addr, u32 len)
{ {
if (type == BreakpointType::ExecuteHard || type == BreakpointType::ExecuteSoft) if (type == BreakpointType::ExecuteHard || type == BreakpointType::ExecuteSoft)
{ {
PowerPC::breakpoints.Add(addr); auto& breakpoints = Core::System::GetInstance().GetPowerPC().GetBreakPoints();
breakpoints.Add(addr);
INFO_LOG_FMT(GDB_STUB, "gdb: added {} breakpoint: {:08x} bytes at {:08x}", INFO_LOG_FMT(GDB_STUB, "gdb: added {} breakpoint: {:08x} bytes at {:08x}",
static_cast<int>(type), len, addr); static_cast<int>(type), len, addr);
} }
@ -886,7 +889,8 @@ static bool AddBreakpoint(BreakpointType type, u32 addr, u32 len)
new_memcheck.break_on_hit = true; new_memcheck.break_on_hit = true;
new_memcheck.log_on_hit = false; new_memcheck.log_on_hit = false;
new_memcheck.is_enabled = true; new_memcheck.is_enabled = true;
PowerPC::memchecks.Add(std::move(new_memcheck)); auto& memchecks = Core::System::GetInstance().GetPowerPC().GetMemChecks();
memchecks.Add(std::move(new_memcheck));
INFO_LOG_FMT(GDB_STUB, "gdb: added {} memcheck: {:08x} bytes at {:08x}", static_cast<int>(type), INFO_LOG_FMT(GDB_STUB, "gdb: added {} memcheck: {:08x} bytes at {:08x}", static_cast<int>(type),
len, addr); len, addr);
} }
@ -1048,7 +1052,7 @@ void InitLocal(const char* socket)
addr.sun_family = AF_UNIX; addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, socket); strcpy(addr.sun_path, socket);
InitGeneric(PF_LOCAL, (const sockaddr*)&addr, sizeof(addr), NULL, NULL); InitGeneric(PF_LOCAL, (const sockaddr*)&addr, sizeof(addr), nullptr, nullptr);
} }
#endif #endif

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