Compare commits

..

1 Commits

Author SHA1 Message Date
jacky400 af310ddff8 Update buffer_base.h 2022-04-24 15:38:22 +08:00
455 changed files with 17599 additions and 24770 deletions
+2 -17
View File
@@ -1,27 +1,12 @@
#!/bin/bash -ex
set -e
cd /yuzu
ccache -s
mkdir build || true && cd build
LDFLAGS="-fuse-ld=lld"
# -femulated-tls required due to an incompatibility between GCC and Clang
# TODO(lat9nq): If this is widespread, we probably need to add this to CMakeLists where appropriate
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_FLAGS="-femulated-tls" \
-DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWClangCross.cmake" \
-DDISPLAY_VERSION=$1 \
-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
-DENABLE_QT_TRANSLATION=ON \
-DUSE_CCACHE=ON \
-DYUZU_USE_BUNDLED_SDL2=OFF \
-DYUZU_USE_EXTERNAL_SDL2=OFF \
-GNinja
ninja yuzu yuzu-cmd
cmake .. -G Ninja -DDISPLAY_VERSION=$1 -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_QT_TRANSLATION=ON
ninja
ccache -s
+1 -1
View File
@@ -8,7 +8,7 @@ steps:
displayName: 'Install vulkan-sdk'
- script: python -m pip install --upgrade pip conan
displayName: 'Install conan'
- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 17 2022" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release .. && cd ..
- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release .. && cd ..
displayName: 'Configure CMake'
- task: MSBuild@1
displayName: 'Build'
+1 -1
View File
@@ -47,7 +47,7 @@ stages:
timeoutInMinutes: 120
displayName: 'msvc'
pool:
vmImage: windows-2022
vmImage: windows-2019
steps:
- template: ./templates/sync-source.yml
parameters:
+1 -1
View File
@@ -12,7 +12,7 @@ stages:
timeoutInMinutes: 120
displayName: 'windows-msvc'
pool:
vmImage: windows-2022
vmImage: windows-2019
steps:
- template: ./templates/sync-source.yml
parameters:
+15 -22
View File
@@ -218,13 +218,8 @@ if (Boost_FOUND)
list(APPEND Boost_LIBRARIES Boost::context)
endif()
else()
message(STATUS "Boost 1.79.0 or newer not found, falling back to Conan")
list(APPEND CONAN_REQUIRED_LIBS "boost/1.79.0")
endif()
# boost:asio has functions that require AcceptEx et al
if (MINGW)
find_library(MSWSOCK_LIBRARY mswsock REQUIRED)
message(STATUS "Boost 1.73.0 or newer not found, falling back to Conan")
list(APPEND CONAN_REQUIRED_LIBS "boost/1.78.0")
endif()
# Attempt to locate any packages that are required and report the missing ones in CONAN_REQUIRED_LIBS
@@ -410,11 +405,13 @@ if (CONAN_REQUIRED_LIBS)
# Download conan.cmake automatically, you can also just copy the conan.cmake file
if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake")
message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan")
file(DOWNLOAD "https://raw.githubusercontent.com/conan-io/cmake-conan/release/0.18/conan.cmake" "${CMAKE_BINARY_DIR}/conan.cmake")
# TODO: Use a tagged release. The latest tagged release does not support VS2022 as of this writing.
file(DOWNLOAD "https://raw.githubusercontent.com/conan-io/cmake-conan/43e385830ee35377dbd2dcbe8d5a9e750301ea00/conan.cmake"
"${CMAKE_BINARY_DIR}/conan.cmake")
endif()
include(${CMAKE_BINARY_DIR}/conan.cmake)
conan_check(VERSION 1.45.0 REQUIRED)
conan_check(VERSION 1.41.0 REQUIRED)
# Manually add iconv to fix a dep conflict between qt and sdl2
# We don't need to add it through find_package or anything since the other two can find it just fine
@@ -644,18 +641,14 @@ endif()
# =========================
# Install freedesktop.org metadata files, following those specifications:
# https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html
# https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
# https://specifications.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html
# https://www.freedesktop.org/software/appstream/docs/
# http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html
# http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
# http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html
if(ENABLE_QT AND UNIX AND NOT APPLE)
install(FILES "dist/org.yuzu_emu.yuzu.desktop"
DESTINATION "share/applications")
install(FILES "dist/yuzu.svg"
DESTINATION "share/icons/hicolor/scalable/apps"
RENAME "org.yuzu_emu.yuzu.svg")
install(FILES "dist/org.yuzu_emu.yuzu.xml"
DESTINATION "share/mime/packages")
install(FILES "dist/org.yuzu_emu.yuzu.metainfo.xml"
DESTINATION "share/metainfo")
install(FILES "${PROJECT_SOURCE_DIR}/dist/yuzu.desktop"
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/applications")
install(FILES "${PROJECT_SOURCE_DIR}/dist/yuzu.svg"
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps")
install(FILES "${PROJECT_SOURCE_DIR}/dist/yuzu.xml"
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/mime/packages")
endif()
-55
View File
@@ -1,55 +0,0 @@
set(MINGW_PREFIX /usr/x86_64-w64-mingw32/)
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
set(CMAKE_FIND_ROOT_PATH ${MINGW_PREFIX})
set(SDL2_PATH ${MINGW_PREFIX})
set(MINGW_TOOL_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-)
# Specify the cross compiler
set(CMAKE_C_COMPILER ${MINGW_TOOL_PREFIX}clang)
set(CMAKE_CXX_COMPILER ${MINGW_TOOL_PREFIX}clang++)
set(CMAKE_RC_COMPILER ${MINGW_TOOL_PREFIX}windres)
set(CMAKE_C_COMPILER_AR ${MINGW_TOOL_PREFIX}ar)
set(CMAKE_CXX_COMPILER_AR ${MINGW_TOOL_PREFIX}ar)
set(CMAKE_C_COMPILER_RANLIB ${MINGW_TOOL_PREFIX}ranlib)
set(CMAKE_CXX_COMPILER_RANLIB ${MINGW_TOOL_PREFIX}ranlib)
# Mingw tools
set(STRIP ${MINGW_TOOL_PREFIX}strip)
set(WINDRES ${MINGW_TOOL_PREFIX}windres)
set(ENV{PKG_CONFIG} ${MINGW_TOOL_PREFIX}pkg-config)
# ccache wrapper
option(USE_CCACHE "Use ccache for compilation" OFF)
if(USE_CCACHE)
find_program(CCACHE ccache)
if(CCACHE)
message(STATUS "Using ccache found in PATH")
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE})
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE})
else(CCACHE)
message(WARNING "USE_CCACHE enabled, but no ccache found")
endif(CCACHE)
endif(USE_CCACHE)
# Search for programs in the build host directories
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# Echo modified cmake vars to screen for debugging purposes
if(NOT DEFINED ENV{MINGW_DEBUG_INFO})
message("")
message("Custom cmake vars: (blank = system default)")
message("-----------------------------------------")
message("* CMAKE_C_COMPILER : ${CMAKE_C_COMPILER}")
message("* CMAKE_CXX_COMPILER : ${CMAKE_CXX_COMPILER}")
message("* CMAKE_RC_COMPILER : ${CMAKE_RC_COMPILER}")
message("* WINDRES : ${WINDRES}")
message("* ENV{PKG_CONFIG} : $ENV{PKG_CONFIG}")
message("* STRIP : ${STRIP}")
message("* USE_CCACHE : ${USE_CCACHE}")
message("")
# So that the debug info only appears once
set(ENV{MINGW_DEBUG_INFO} SHOWN)
endif()
+556 -680
View File
File diff suppressed because it is too large Load Diff
+556 -680
View File
File diff suppressed because it is too large Load Diff
+556 -680
View File
File diff suppressed because it is too large Load Diff
+554 -686
View File
File diff suppressed because it is too large Load Diff
+607 -731
View File
File diff suppressed because it is too large Load Diff
+556 -689
View File
File diff suppressed because it is too large Load Diff
+613 -738
View File
File diff suppressed because it is too large Load Diff
+570 -697
View File
File diff suppressed because it is too large Load Diff
+562 -686
View File
File diff suppressed because it is too large Load Diff
+690 -820
View File
File diff suppressed because it is too large Load Diff
+569 -716
View File
File diff suppressed because it is too large Load Diff
+558 -682
View File
File diff suppressed because it is too large Load Diff
+558 -682
View File
File diff suppressed because it is too large Load Diff
+559 -683
View File
File diff suppressed because it is too large Load Diff
+551 -684
View File
File diff suppressed because it is too large Load Diff
+558 -688
View File
File diff suppressed because it is too large Load Diff
+837 -977
View File
File diff suppressed because it is too large Load Diff
+555 -679
View File
File diff suppressed because it is too large Load Diff
+558 -682
View File
File diff suppressed because it is too large Load Diff
+555 -679
View File
File diff suppressed because it is too large Load Diff
+555 -679
View File
File diff suppressed because it is too large Load Diff
+553 -683
View File
File diff suppressed because it is too large Load Diff
+552 -682
View File
File diff suppressed because it is too large Load Diff
-56
View File
@@ -1,56 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>org.yuzu_emu.yuzu</id>
<metadata_license>CC0-1.0</metadata_license>
<name>yuzu</name>
<summary>Nintendo Switch emulator</summary>
<description>
<p>yuzu is the world's most popular, open-source, Nintendo Switch emulator — started by the creators of Citra.</p>
<p>The emulator is capable of running most commercial games at full speed, provided you meet the necessary hardware requirements.</p>
<p>For a full list of games yuzu support, please visit our Compatibility page.</p>
<p>Check out our website for the latest news on exciting features, monthly progress reports, and more!</p>
</description>
<categories>
<category>Game</category>
<category>Emulator</category>
</categories>
<keywords>
<keyword>switch</keyword>
<keyword>emulator</keyword>
</keywords>
<url type="homepage">https://yuzu-emu.org/</url>
<url type="bugtracker">https://github.com/yuzu-emu/yuzu/issues</url>
<url type="faq">https://yuzu-emu.org/wiki/faq/</url>
<url type="help">https://yuzu-emu.org/wiki/home/</url>
<url type="donation">https://yuzu-emu.org/donate/</url>
<url type="translate">https://www.transifex.com/projects/p/yuzu</url>
<url type="contact">https://community.citra-emu.org/</url>
<url type="vcs-browser">https://github.com/yuzu-emu/yuzu</url>
<url type="contribute">https://yuzu-emu.org/wiki/contributing/</url>
<launchable type="desktop-id">org.yuzu_emu.yuzu.desktop</launchable>
<provides>
<binary>yuzu</binary>
<binary>yuzu-cmd</binary>
</provides>
<supports>
<control>pointing</control>
<control>keyboard</control>
<control>gamepad</control>
</supports>
<requires>
<memory>8192</memory>
</requires>
<recommends>
<memory>16384</memory>
</recommends>
<project_license>GPL-3.0-or-later</project_license>
<developer_name>yuzu Emulator Team</developer_name>
<content_rating type="oars-1.0"/>
<screenshots>
<screenshot type="default">https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/001-Super%20Mario%20Odyssey%20.png</screenshot>
<screenshot>https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/004-The%20Legend%20of%20Zelda%20Skyward%20Sword%20HD.png</screenshot>
<screenshot>https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/007-Pokemon%20Sword.png</screenshot>
<screenshot>https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/010-Hyrule%20Warriors%20Age%20of%20Calamity.png</screenshot>
<screenshot>https://raw.githubusercontent.com/yuzu-emu/yuzu-emu.github.io/master/images/screenshots/039-Pok%C3%A9mon%20Mystery%20Dungeon%20Rescue%20Team%20DX.png.png.png</screenshot>
</screenshots>
</component>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 10 KiB

-13
View File
@@ -58,19 +58,6 @@ QPushButton#GPUStatusBarButton:!checked {
color: #109010;
}
QPushButton#DockingStatusBarButton {
min-width: 0px;
color: #000000;
border: 1px solid transparent;
background-color: transparent;
padding: 0px 3px 0px 3px;
text-align: center;
}
QPushButton#DockingStatusBarButton:hover {
border: 1px solid #76797C;
}
QPushButton#buttonRefreshDevices {
min-width: 21px;
min-height: 21px;
-13
View File
@@ -1304,19 +1304,6 @@ QPushButton#GPUStatusBarButton:!checked {
color: #40dd40;
}
QPushButton#DockingStatusBarButton {
min-width: 0px;
color: #ffffff;
border: 1px solid transparent;
background-color: transparent;
padding: 0px 3px 0px 3px;
text-align: center;
}
QPushButton#DockingStatusBarButton:hover {
border: 1px solid #76797C;
}
QPushButton#buttonRefreshDevices {
min-width: 23px;
min-height: 23px;
-13
View File
@@ -2207,19 +2207,6 @@ QPushButton#GPUStatusBarButton:!checked {
color: #40dd40;
}
QPushButton#DockingStatusBarButton {
min-width: 0px;
color: #ffffff;
border: 1px solid transparent;
background-color: transparent;
padding: 0px 3px 0px 3px;
text-align: center;
}
QPushButton#DockingStatusBarButton:hover {
border: 1px solid #76797C;
}
QPushButton#buttonRefreshDevices {
min-width: 19px;
min-height: 19px;
+2 -2
View File
@@ -4,9 +4,9 @@ Type=Application
Name=yuzu
GenericName=Switch Emulator
Comment=Nintendo Switch video game console emulator
Icon=org.yuzu_emu.yuzu
Icon=yuzu
TryExec=yuzu
Exec=yuzu %f
Categories=Game;Emulator;Qt;
MimeType=application/x-nx-nro;application/x-nx-nso;application/x-nx-nsp;application/x-nx-xci;
Keywords=Nintendo;Switch;
Keywords=Switch;Nintendo;
+5 -5
View File
@@ -3,7 +3,7 @@
<mime-type type="application/x-nx-nro">
<comment>Nintendo Switch homebrew executable</comment>
<acronym>NRO</acronym>
<icon name="org.yuzu_emu.yuzu"/>
<icon name="yuzu"/>
<glob pattern="*.nro"/>
<magic><match value="NRO" type="string" offset="16"/></magic>
</mime-type>
@@ -11,7 +11,7 @@
<mime-type type="application/x-nx-nso">
<comment>Nintendo Switch homebrew executable</comment>
<acronym>NSO</acronym>
<icon name="org.yuzu_emu.yuzu"/>
<icon name="yuzu"/>
<glob pattern="*.nso"/>
<magic><match value="NSO" type="string" offset="0"/></magic>
</mime-type>
@@ -19,7 +19,7 @@
<mime-type type="application/x-nx-nsp">
<comment>Nintendo Switch Package</comment>
<acronym>NSP</acronym>
<icon name="org.yuzu_emu.yuzu"/>
<icon name="yuzu"/>
<glob pattern="*.nsp"/>
<magic><match value="PFS" type="string" offset="0"/></magic>
</mime-type>
@@ -27,7 +27,7 @@
<mime-type type="application/x-nx-xci">
<comment>Nintendo Switch Card Image</comment>
<acronym>XCI</acronym>
<icon name="org.yuzu_emu.yuzu"/>
<icon name="yuzu"/>
<glob pattern="*.xci"/>
</mime-type>
</mime-info>
</mime-info>
-5
View File
@@ -40,11 +40,6 @@ target_include_directories(mbedtls PUBLIC ./mbedtls/include)
add_library(microprofile INTERFACE)
target_include_directories(microprofile INTERFACE ./microprofile)
# GCC bugs
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12" AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND MINGW)
target_compile_options(microprofile INTERFACE "-Wno-array-bounds")
endif()
# libusb
if (NOT LIBUSB_FOUND OR YUZU_USE_BUNDLED_LIBUSB)
add_subdirectory(libusb)
+1 -1
View File
@@ -1246,7 +1246,7 @@ struct MicroProfileScopeLock
{
bool bUseLock;
std::recursive_mutex& m;
MicroProfileScopeLock(std::recursive_mutex& m_) : bUseLock(g_bUseLock), m(m_)
MicroProfileScopeLock(std::recursive_mutex& m) : bUseLock(g_bUseLock), m(m)
{
if(bUseLock)
m.lock();
+38 -37
View File
@@ -213,8 +213,8 @@ struct MicroProfileCustom
struct SOptionDesc
{
SOptionDesc()=default;
SOptionDesc(uint8_t nSubType_, uint8_t nIndex_, const char* fmt, ...):nSubType(nSubType_), nIndex(nIndex_)
SOptionDesc(){}
SOptionDesc(uint8_t nSubType, uint8_t nIndex, const char* fmt, ...):nSubType(nSubType), nIndex(nIndex)
{
va_list args;
va_start (args, fmt);
@@ -573,10 +573,10 @@ inline void MicroProfileToolTipMeta(MicroProfileStringArray* pToolTip)
}
else
{
for(int k = 0; k < MICROPROFILE_META_MAX; ++k)
for(int i = 0; i < MICROPROFILE_META_MAX; ++i)
{
nMetaSumInclusive[k] += nMetaSum[k];
nMetaSum[k] = 0;
nMetaSumInclusive[i] += nMetaSum[i];
nMetaSum[i] = 0;
}
}
break;
@@ -708,10 +708,10 @@ inline void MicroProfileDrawFloatTooltip(uint32_t nX, uint32_t nY, uint32_t nTok
if(UI.nMouseLeftMod)
{
int nToolTipIndex = (g_MicroProfileUI.LockedToolTipFront + MICROPROFILE_TOOLTIP_MAX_LOCKED - 1) % MICROPROFILE_TOOLTIP_MAX_LOCKED;
g_MicroProfileUI.nLockedToolTipColor[nToolTipIndex] = S.TimerInfo[nTimerId].nColor;
MicroProfileStringArrayCopy(&g_MicroProfileUI.LockedToolTips[nToolTipIndex], &ToolTip);
g_MicroProfileUI.LockedToolTipFront = nToolTipIndex;
int nIndex = (g_MicroProfileUI.LockedToolTipFront + MICROPROFILE_TOOLTIP_MAX_LOCKED - 1) % MICROPROFILE_TOOLTIP_MAX_LOCKED;
g_MicroProfileUI.nLockedToolTipColor[nIndex] = S.TimerInfo[nTimerId].nColor;
MicroProfileStringArrayCopy(&g_MicroProfileUI.LockedToolTips[nIndex], &ToolTip);
g_MicroProfileUI.LockedToolTipFront = nIndex;
}
}
@@ -917,8 +917,9 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
float fStart = floor(fMsBase*fRcpStep) * fStep;
for(float f = fStart; f < fMsEnd; )
{
float fStart = f;
float fNext = f + fStep;
MicroProfileDrawBox(((f-fMsBase) * fMsToScreen), nBaseY, (fNext-fMsBase) * fMsToScreen+1, nBaseY + nHeight, UI.nOpacityBackground | g_nMicroProfileBackColors[nColorIndex++ & 1]);
MicroProfileDrawBox(((fStart-fMsBase) * fMsToScreen), nBaseY, (fNext-fMsBase) * fMsToScreen+1, nBaseY + nHeight, UI.nOpacityBackground | g_nMicroProfileBackColors[nColorIndex++ & 1]);
f = fNext;
}
}
@@ -1115,9 +1116,9 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
nMaxStackDepth = MicroProfileMax(nMaxStackDepth, nStackPos);
float fMsStart = fToMs * MicroProfileLogTickDifference(nBaseTicks, nTickStart);
float fMsEnd2 = fToMs * MicroProfileLogTickDifference(nBaseTicks, nTickEnd);
float fMsEnd = fToMs * MicroProfileLogTickDifference(nBaseTicks, nTickEnd);
float fXStart = fMsStart * fMsToScreen;
float fXEnd = fMsEnd2 * fMsToScreen;
float fXEnd = fMsEnd * fMsToScreen;
float fYStart = (float)(nY + nStackPos * nYDelta);
float fYEnd = fYStart + (MICROPROFILE_DETAILED_BAR_HEIGHT);
float fXDist = MicroProfileMax(fXStart - fMouseX, fMouseX - fXEnd);
@@ -1268,22 +1269,22 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
if(UI.nRangeBegin != UI.nRangeEnd)
{
float fMsStart = fToMsCpu * MicroProfileLogTickDifference(nBaseTicksCpu, UI.nRangeBegin);
float fMsEnd3 = fToMsCpu * MicroProfileLogTickDifference(nBaseTicksCpu, UI.nRangeEnd);
float fMsEnd = fToMsCpu * MicroProfileLogTickDifference(nBaseTicksCpu, UI.nRangeEnd);
float fXStart = fMsStart * fMsToScreen;
float fXEnd = fMsEnd3 * fMsToScreen;
float fXEnd = fMsEnd * fMsToScreen;
MicroProfileDrawBox(fXStart, nBaseY, fXEnd, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT, MicroProfileBoxTypeFlat);
MicroProfileDrawLineVertical(fXStart, nBaseY, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT | 0x44000000);
MicroProfileDrawLineVertical(fXEnd, nBaseY, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT | 0x44000000);
fMsStart += fDetailedOffset;
fMsEnd3 += fDetailedOffset;
fMsEnd += fDetailedOffset;
char sBuffer[32];
uint32_t nLenStart = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsStart);
float fStartTextWidth = (float)((1+MICROPROFILE_TEXT_WIDTH) * nLenStart);
float fStartTextX = fXStart - fStartTextWidth - 2;
MicroProfileDrawBox(fStartTextX, nBaseY, fStartTextX + fStartTextWidth + 2, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
MicroProfileDrawText(fStartTextX+1, nBaseY, UINT32_MAX, sBuffer, nLenStart);
uint32_t nLenEnd = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsEnd3);
uint32_t nLenEnd = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsEnd);
MicroProfileDrawBox(fXEnd+1, nBaseY, fXEnd+1+(1+MICROPROFILE_TEXT_WIDTH) * nLenEnd + 3, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
MicroProfileDrawText(fXEnd+2, nBaseY+1, UINT32_MAX, sBuffer, nLenEnd);
@@ -1296,9 +1297,9 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
if(UI.nRangeBeginGpu != UI.nRangeEndGpu)
{
float fMsStart = fToMsGpu * MicroProfileLogTickDifference(nBaseTicksGpu, UI.nRangeBeginGpu);
float fMsEnd4 = fToMsGpu * MicroProfileLogTickDifference(nBaseTicksGpu, UI.nRangeEndGpu);
float fMsEnd = fToMsGpu * MicroProfileLogTickDifference(nBaseTicksGpu, UI.nRangeEndGpu);
float fXStart = fMsStart * fMsToScreen;
float fXEnd = fMsEnd4 * fMsToScreen;
float fXEnd = fMsEnd * fMsToScreen;
MicroProfileDrawBox(fXStart, nBaseY, fXEnd, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT_GPU, MicroProfileBoxTypeFlat);
MicroProfileDrawLineVertical(fXStart, nBaseY, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT_GPU | 0x44000000);
MicroProfileDrawLineVertical(fXEnd, nBaseY, nHeight, MICROPROFILE_FRAME_COLOR_HIGHTLIGHT_GPU | 0x44000000);
@@ -1306,14 +1307,14 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int
nBaseY += MICROPROFILE_TEXT_HEIGHT+1;
fMsStart += fDetailedOffset;
fMsEnd4 += fDetailedOffset;
fMsEnd += fDetailedOffset;
char sBuffer[32];
uint32_t nLenStart = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsStart);
float fStartTextWidth = (float)((1+MICROPROFILE_TEXT_WIDTH) * nLenStart);
float fStartTextX = fXStart - fStartTextWidth - 2;
MicroProfileDrawBox(fStartTextX, nBaseY, fStartTextX + fStartTextWidth + 2, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
MicroProfileDrawText(fStartTextX+1, nBaseY, UINT32_MAX, sBuffer, nLenStart);
uint32_t nLenEnd = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsEnd4);
uint32_t nLenEnd = snprintf(sBuffer, sizeof(sBuffer)-1, "%.2fms", fMsEnd);
MicroProfileDrawBox(fXEnd+1, nBaseY, fXEnd+1+(1+MICROPROFILE_TEXT_WIDTH) * nLenEnd + 3, MICROPROFILE_TEXT_HEIGHT + 2 + nBaseY, 0x33000000, MicroProfileBoxTypeFlat);
MicroProfileDrawText(fXEnd+2, nBaseY+1, UINT32_MAX, sBuffer, nLenEnd);
}
@@ -1715,8 +1716,8 @@ bool MicroProfileDrawGraph(uint32_t nScreenWidth, uint32_t nScreenHeight)
uint32_t nTextCount = 0;
uint32_t nGraphIndex = (S.nGraphPut + MICROPROFILE_GRAPH_HISTORY - int(MICROPROFILE_GRAPH_HISTORY*(1.f - fMouseXPrc))) % MICROPROFILE_GRAPH_HISTORY;
uint32_t nMouseX = UI.nMouseX;
uint32_t nMouseY = UI.nMouseY + 20;
uint32_t nX = UI.nMouseX;
uint32_t nY = UI.nMouseY + 20;
for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i)
{
@@ -1735,7 +1736,7 @@ bool MicroProfileDrawGraph(uint32_t nScreenWidth, uint32_t nScreenHeight)
}
if(nTextCount)
{
MicroProfileDrawFloatWindow(nMouseX, nMouseY, Strings.ppStrings, Strings.nNumStrings, 0, pColors);
MicroProfileDrawFloatWindow(nX, nY, Strings.ppStrings, Strings.nNumStrings, 0, pColors);
}
if(UI.nMouseRight)
@@ -2320,8 +2321,8 @@ inline void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
uint32_t nMenuX[MICROPROFILE_MENU_MAX] = {0};
uint32_t nNumMenuItems = 0;
int nMPTextLen = snprintf(buffer, 127, "MicroProfile");
MicroProfileDrawText(nX, nY, UINT32_MAX, buffer, nMPTextLen);
int nLen = snprintf(buffer, 127, "MicroProfile");
MicroProfileDrawText(nX, nY, UINT32_MAX, buffer, nLen);
nX += (sizeof("MicroProfile")+2) * (MICROPROFILE_TEXT_WIDTH+1);
pMenuText[nNumMenuItems++] = "Mode";
pMenuText[nNumMenuItems++] = "Groups";
@@ -2437,16 +2438,16 @@ inline void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
int nNumLines = 0;
bool bSelected = false;
const char* pString = CB(nNumLines, &bSelected);
uint32_t nTextWidth = 0, nTextHeight = 0;
uint32_t nWidth = 0, nHeight = 0;
while(pString)
{
nTextWidth = MicroProfileMax<int>(nTextWidth, (int)strlen(pString));
nWidth = MicroProfileMax<int>(nWidth, (int)strlen(pString));
nNumLines++;
pString = CB(nNumLines, &bSelected);
}
nTextWidth = (2+nTextWidth) * (MICROPROFILE_TEXT_WIDTH+1);
nTextHeight = nNumLines * (MICROPROFILE_TEXT_HEIGHT+1);
if(UI.nMouseY <= nY + nTextHeight+0 && UI.nMouseY >= nY-0 && UI.nMouseX <= nX + nTextWidth + 0 && UI.nMouseX >= nX - 0)
nWidth = (2+nWidth) * (MICROPROFILE_TEXT_WIDTH+1);
nHeight = nNumLines * (MICROPROFILE_TEXT_HEIGHT+1);
if(UI.nMouseY <= nY + nHeight+0 && UI.nMouseY >= nY-0 && UI.nMouseX <= nX + nWidth + 0 && UI.nMouseX >= nX - 0)
{
UI.nActiveMenu = nMenu;
}
@@ -2454,21 +2455,21 @@ inline void MicroProfileDrawMenu(uint32_t nWidth, uint32_t nHeight)
{
UI.nActiveMenu = UINT32_MAX;
}
MicroProfileDrawBox(nX, nY, nX + nTextWidth, nY + nTextHeight, 0xff000000|g_nMicroProfileBackColors[1]);
MicroProfileDrawBox(nX, nY, nX + nWidth, nY + nHeight, 0xff000000|g_nMicroProfileBackColors[1]);
for(int i = 0; i < nNumLines; ++i)
{
bool bSelected2 = false;
const char* pString2 = CB(i, &bSelected2);
bool bSelected = false;
const char* pString = CB(i, &bSelected);
if(UI.nMouseY >= nY && UI.nMouseY < nY + MICROPROFILE_TEXT_HEIGHT + 1)
{
if(UI.nMouseLeft || UI.nMouseRight)
{
CBClick[nMenu](i);
}
MicroProfileDrawBox(nX, nY, nX + nTextWidth, nY + MICROPROFILE_TEXT_HEIGHT + 1, 0xff888888);
MicroProfileDrawBox(nX, nY, nX + nWidth, nY + MICROPROFILE_TEXT_HEIGHT + 1, 0xff888888);
}
int nTextLen = snprintf(buffer, SBUF_SIZE-1, "%c %s", bSelected2 ? '*' : ' ' ,pString2);
MicroProfileDrawText(nX, nY, UINT32_MAX, buffer, nTextLen);
int nLen = snprintf(buffer, SBUF_SIZE-1, "%c %s", bSelected ? '*' : ' ' ,pString);
MicroProfileDrawText(nX, nY, UINT32_MAX, buffer, nLen);
nY += MICROPROFILE_TEXT_HEIGHT+1;
}
}
@@ -2604,7 +2605,7 @@ inline void MicroProfileDrawCustom(uint32_t nWidth, uint32_t nHeight)
for(uint32_t i = 0; i < nCount; ++i)
{
nOffsetY += (1+MICROPROFILE_TEXT_HEIGHT);
nWidth = MicroProfileMin(nMaxWidth, (uint32_t)(nMaxWidth * pMs[i] * fRcpReference));
uint32_t nWidth = MicroProfileMin(nMaxWidth, (uint32_t)(nMaxWidth * pMs[i] * fRcpReference));
MicroProfileDrawBox(nMaxOffsetX, nOffsetY, nMaxOffsetX+nWidth, nOffsetY+MICROPROFILE_TEXT_HEIGHT, pColors[i]|0xff000000);
}
}
-5
View File
@@ -65,10 +65,6 @@ if (MSVC)
/we4305 # 'context': truncation from 'type1' to 'type2'
/we4388 # 'expression': signed/unsigned mismatch
/we4389 # 'operator': signed/unsigned mismatch
/we4456 # Declaration of 'identifier' hides previous local declaration
/we4457 # Declaration of 'identifier' hides function parameter
/we4458 # Declaration of 'identifier' hides class member
/we4459 # Declaration of 'identifier' hides global declaration
/we4505 # 'function': unreferenced local function has been removed
/we4547 # 'operator': operator before comma has no effect; expected operator with side-effect
/we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'?
@@ -96,7 +92,6 @@ else()
-Werror=missing-declarations
-Werror=missing-field-initializers
-Werror=reorder
-Werror=shadow
-Werror=sign-compare
-Werror=switch
-Werror=uninitialized
+3
View File
@@ -49,6 +49,9 @@ if (NOT MSVC)
target_compile_options(audio_core PRIVATE
-Werror=conversion
-Werror=ignored-qualifiers
-Werror=shadow
-Werror=unused-parameter
-Werror=unused-variable
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable>
+4 -4
View File
@@ -98,13 +98,13 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing_, Core::Memor
AudioRenderer::~AudioRenderer() = default;
Result AudioRenderer::Start() {
ResultCode AudioRenderer::Start() {
audio_out->StartStream(stream);
ReleaseAndQueueBuffers();
return ResultSuccess;
}
Result AudioRenderer::Stop() {
ResultCode AudioRenderer::Stop() {
audio_out->StopStream(stream);
return ResultSuccess;
}
@@ -125,8 +125,8 @@ Stream::State AudioRenderer::GetStreamState() const {
return stream->GetState();
}
Result AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params,
std::vector<u8>& output_params) {
ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params,
std::vector<u8>& output_params) {
std::scoped_lock lock{mutex};
InfoUpdater info_updater{input_params, output_params, behavior_info};
+4 -4
View File
@@ -43,10 +43,10 @@ public:
Stream::ReleaseCallback&& release_callback, std::size_t instance_number);
~AudioRenderer();
[[nodiscard]] Result UpdateAudioRenderer(const std::vector<u8>& input_params,
std::vector<u8>& output_params);
[[nodiscard]] Result Start();
[[nodiscard]] Result Stop();
[[nodiscard]] ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params,
std::vector<u8>& output_params);
[[nodiscard]] ResultCode Start();
[[nodiscard]] ResultCode Stop();
void QueueMixedBuffer(Buffer::Tag tag);
void ReleaseAndQueueBuffers();
[[nodiscard]] u32 GetSampleRate() const;
+10 -10
View File
@@ -129,17 +129,17 @@ s32 ToS32(float sample) {
return static_cast<s32>(rescaled_sample);
}
constexpr std::array<u8, 20> REVERB_TAP_INDEX_1CH{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
constexpr std::array<std::size_t, 20> REVERB_TAP_INDEX_1CH{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
constexpr std::array<u8, 20> REVERB_TAP_INDEX_2CH{0, 0, 0, 1, 1, 1, 1, 0, 0, 0,
1, 1, 1, 0, 0, 0, 0, 1, 1, 1};
constexpr std::array<std::size_t, 20> REVERB_TAP_INDEX_2CH{0, 0, 0, 1, 1, 1, 1, 0, 0, 0,
1, 1, 1, 0, 0, 0, 0, 1, 1, 1};
constexpr std::array<u8, 20> REVERB_TAP_INDEX_4CH{0, 0, 0, 1, 1, 1, 1, 2, 2, 2,
1, 1, 1, 0, 0, 0, 0, 3, 3, 3};
constexpr std::array<std::size_t, 20> REVERB_TAP_INDEX_4CH{0, 0, 0, 1, 1, 1, 1, 2, 2, 2,
1, 1, 1, 0, 0, 0, 0, 3, 3, 3};
constexpr std::array<u8, 20> REVERB_TAP_INDEX_6CH{4, 0, 0, 1, 1, 1, 1, 2, 2, 2,
1, 1, 1, 0, 0, 0, 0, 3, 3, 3};
constexpr std::array<std::size_t, 20> REVERB_TAP_INDEX_6CH{4, 0, 0, 1, 1, 1, 1, 2, 2, 2,
1, 1, 1, 0, 0, 0, 0, 3, 3, 3};
template <std::size_t CHANNEL_COUNT>
void ApplyReverbGeneric(
@@ -429,7 +429,7 @@ void CommandGenerator::GenerateDataSourceCommand(ServerVoiceInfo& voice_info, Vo
in_params.node_id);
break;
default:
ASSERT_MSG(false, "Unimplemented sample format={}", in_params.sample_format);
UNREACHABLE_MSG("Unimplemented sample format={}", in_params.sample_format);
}
}
}
@@ -1312,7 +1312,7 @@ void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, std::s
samples_to_read - samples_read, channel, temp_mix_offset);
break;
default:
ASSERT_MSG(false, "Unimplemented sample format={}", in_params.sample_format);
UNREACHABLE_MSG("Unimplemented sample format={}", in_params.sample_format);
}
temp_mix_offset += samples_decoded;
+2 -2
View File
@@ -10,8 +10,8 @@
namespace AudioCommon {
namespace Audren {
constexpr Result ERR_INVALID_PARAMETERS{ErrorModule::Audio, 41};
constexpr Result ERR_SPLITTER_SORT_FAILED{ErrorModule::Audio, 43};
constexpr ResultCode ERR_INVALID_PARAMETERS{ErrorModule::Audio, 41};
constexpr ResultCode ERR_SPLITTER_SORT_FAILED{ErrorModule::Audio, 43};
} // namespace Audren
constexpr u8 BASE_REVISION = '0';
+2 -2
View File
@@ -50,7 +50,7 @@ EffectBase* EffectContext::RetargetEffect(std::size_t i, EffectType effect) {
effects[i] = std::make_unique<EffectBiquadFilter>();
break;
default:
ASSERT_MSG(false, "Unimplemented effect {}", effect);
UNREACHABLE_MSG("Unimplemented effect {}", effect);
effects[i] = std::make_unique<EffectStubbed>();
}
return GetInfo(i);
@@ -104,7 +104,7 @@ void EffectI3dl2Reverb::Update(EffectInfo::InParams& in_params) {
auto& params = GetParams();
const auto* reverb_params = reinterpret_cast<I3dl2ReverbParams*>(in_params.raw.data());
if (!ValidChannelCountForEffect(reverb_params->max_channels)) {
ASSERT_MSG(false, "Invalid reverb max channel count {}", reverb_params->max_channels);
UNREACHABLE_MSG("Invalid reverb max channel count {}", reverb_params->max_channels);
return;
}
+3 -2
View File
@@ -285,8 +285,9 @@ bool InfoUpdater::UpdateSplitterInfo(SplitterContext& splitter_context) {
return true;
}
Result InfoUpdater::UpdateMixes(MixContext& mix_context, std::size_t mix_buffer_count,
SplitterContext& splitter_context, EffectContext& effect_context) {
ResultCode InfoUpdater::UpdateMixes(MixContext& mix_context, std::size_t mix_buffer_count,
SplitterContext& splitter_context,
EffectContext& effect_context) {
std::vector<MixInfo::InParams> mix_in_params;
if (!behavior_info.IsMixInParameterDirtyOnlyUpdateSupported()) {
+2 -2
View File
@@ -32,8 +32,8 @@ public:
VAddr audio_codec_dsp_addr);
bool UpdateEffects(EffectContext& effect_context, bool is_active);
bool UpdateSplitterInfo(SplitterContext& splitter_context);
Result UpdateMixes(MixContext& mix_context, std::size_t mix_buffer_count,
SplitterContext& splitter_context, EffectContext& effect_context);
ResultCode UpdateMixes(MixContext& mix_context, std::size_t mix_buffer_count,
SplitterContext& splitter_context, EffectContext& effect_context);
bool UpdateSinks(SinkContext& sink_context);
bool UpdatePerformanceBuffer();
bool UpdateErrorInfo(BehaviorInfo& in_behavior_info);
+1 -1
View File
@@ -483,7 +483,7 @@ bool NodeStates::DepthFirstSearch(EdgeMatrix& edge_matrix) {
// Add more work
index_stack.push(j);
} else if (node_state == NodeStates::State::InFound) {
ASSERT_MSG(false, "Node start marked as found");
UNREACHABLE_MSG("Node start marked as found");
ResetState();
return false;
}
+2 -2
View File
@@ -114,7 +114,7 @@ void ServerVoiceInfo::UpdateParameters(const VoiceInfo::InParams& voice_in,
in_params.current_playstate = ServerPlayState::Play;
break;
default:
ASSERT_MSG(false, "Unknown playstate {}", voice_in.play_state);
UNREACHABLE_MSG("Unknown playstate {}", voice_in.play_state);
break;
}
@@ -410,7 +410,7 @@ bool ServerVoiceInfo::UpdateParametersForCommandGeneration(
return in_params.should_depop;
}
default:
ASSERT_MSG(false, "Invalid playstate {}", in_params.current_playstate);
UNREACHABLE_MSG("Invalid playstate {}", in_params.current_playstate);
}
return false;
-1
View File
@@ -58,7 +58,6 @@ add_library(common STATIC
div_ceil.h
dynamic_library.cpp
dynamic_library.h
elf.h
error.cpp
error.h
expected.h
+1 -6
View File
@@ -6,13 +6,8 @@
#include "common/settings.h"
void assert_fail_impl() {
void assert_handle_failure() {
if (Settings::values.use_debug_asserts) {
Crash();
}
}
[[noreturn]] void unreachable_impl() {
Crash();
throw std::runtime_error("Unreachable code");
}
+31 -30
View File
@@ -1,6 +1,6 @@
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
@@ -9,43 +9,44 @@
// Sometimes we want to try to continue even after hitting an assert.
// However touching this file yields a global recompilation as this header is included almost
// everywhere. So let's just move the handling of the failed assert to a single cpp file.
void assert_handle_failure();
void assert_fail_impl();
[[noreturn]] void unreachable_impl();
#ifdef _MSC_VER
#define YUZU_NO_INLINE __declspec(noinline)
#else
#define YUZU_NO_INLINE __attribute__((noinline))
// For asserts we'd like to keep all the junk executed when an assert happens away from the
// important code in the function. One way of doing this is to put all the relevant code inside a
// lambda and force the compiler to not inline it. Unfortunately, MSVC seems to have no syntax to
// specify __declspec on lambda functions, so what we do instead is define a noinline wrapper
// template that calls the lambda. This seems to generate an extra instruction at the call-site
// compared to the ideal implementation (which wouldn't support ASSERT_MSG parameters), but is good
// enough for our purposes.
template <typename Fn>
#if defined(_MSC_VER)
[[msvc::noinline]]
#elif defined(__GNUC__)
[[gnu::cold, gnu::noinline]]
#endif
static void
assert_noinline_call(const Fn& fn) {
fn();
assert_handle_failure();
}
#define ASSERT(_a_) \
([&]() YUZU_NO_INLINE { \
if (!(_a_)) [[unlikely]] { \
LOG_CRITICAL(Debug, "Assertion Failed!"); \
assert_fail_impl(); \
do \
if (!(_a_)) { \
assert_noinline_call([] { LOG_CRITICAL(Debug, "Assertion Failed!"); }); \
} \
}())
while (0)
#define ASSERT_MSG(_a_, ...) \
([&]() YUZU_NO_INLINE { \
if (!(_a_)) [[unlikely]] { \
LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); \
assert_fail_impl(); \
do \
if (!(_a_)) { \
assert_noinline_call([&] { LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); }); \
} \
}())
#define UNREACHABLE() \
do { \
LOG_CRITICAL(Debug, "Unreachable code!"); \
unreachable_impl(); \
} while (0)
while (0)
#define UNREACHABLE() assert_noinline_call([] { LOG_CRITICAL(Debug, "Unreachable code!"); })
#define UNREACHABLE_MSG(...) \
do { \
LOG_CRITICAL(Debug, "Unreachable code!\n" __VA_ARGS__); \
unreachable_impl(); \
} while (0)
assert_noinline_call([&] { LOG_CRITICAL(Debug, "Unreachable code!\n" __VA_ARGS__); })
#ifdef _DEBUG
#define DEBUG_ASSERT(_a_) ASSERT(_a_)
+29 -3
View File
@@ -1,6 +1,32 @@
// SPDX-FileCopyrightText: 2014 Tony Wasserka
// SPDX-FileCopyrightText: 2014 Dolphin Emulator Project
// SPDX-License-Identifier: BSD-3-Clause AND GPL-2.0-or-later
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
// Copyright 2014 Tony Wasserka
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the owner nor the names of its contributors may
// be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
-167
View File
@@ -1,167 +0,0 @@
// SPDX-FileCopyrightText: Copyright (c) 2020 Erik Rigtorp <erik@rigtorp.se>
// SPDX-License-Identifier: MIT
#pragma once
#include <atomic>
#include <bit>
#include <condition_variable>
#include <memory>
#include <mutex>
#include <new>
#include <stop_token>
#include <type_traits>
#include <utility>
namespace Common {
#if defined(__cpp_lib_hardware_interference_size)
constexpr size_t hardware_interference_size = std::hardware_destructive_interference_size;
#else
constexpr size_t hardware_interference_size = 64;
#endif
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4324)
#endif
template <typename T, size_t capacity = 0x400>
class MPSCQueue {
public:
explicit MPSCQueue() : allocator{std::allocator<Slot<T>>()} {
// Allocate one extra slot to prevent false sharing on the last slot
slots = allocator.allocate(capacity + 1);
// Allocators are not required to honor alignment for over-aligned types
// (see http://eel.is/c++draft/allocator.requirements#10) so we verify
// alignment here
if (reinterpret_cast<uintptr_t>(slots) % alignof(Slot<T>) != 0) {
allocator.deallocate(slots, capacity + 1);
throw std::bad_alloc();
}
for (size_t i = 0; i < capacity; ++i) {
std::construct_at(&slots[i]);
}
static_assert(std::has_single_bit(capacity), "capacity must be an integer power of 2");
static_assert(alignof(Slot<T>) == hardware_interference_size,
"Slot must be aligned to cache line boundary to prevent false sharing");
static_assert(sizeof(Slot<T>) % hardware_interference_size == 0,
"Slot size must be a multiple of cache line size to prevent "
"false sharing between adjacent slots");
static_assert(sizeof(MPSCQueue) % hardware_interference_size == 0,
"Queue size must be a multiple of cache line size to "
"prevent false sharing between adjacent queues");
}
~MPSCQueue() noexcept {
for (size_t i = 0; i < capacity; ++i) {
std::destroy_at(&slots[i]);
}
allocator.deallocate(slots, capacity + 1);
}
// The queue must be both non-copyable and non-movable
MPSCQueue(const MPSCQueue&) = delete;
MPSCQueue& operator=(const MPSCQueue&) = delete;
MPSCQueue(MPSCQueue&&) = delete;
MPSCQueue& operator=(MPSCQueue&&) = delete;
void Push(const T& v) noexcept {
static_assert(std::is_nothrow_copy_constructible_v<T>,
"T must be nothrow copy constructible");
emplace(v);
}
template <typename P, typename = std::enable_if_t<std::is_nothrow_constructible_v<T, P&&>>>
void Push(P&& v) noexcept {
emplace(std::forward<P>(v));
}
void Pop(T& v, std::stop_token stop) noexcept {
auto const tail = tail_.fetch_add(1);
auto& slot = slots[idx(tail)];
if (!slot.turn.test()) {
std::unique_lock lock{cv_mutex};
cv.wait(lock, stop, [&slot] { return slot.turn.test(); });
}
v = slot.move();
slot.destroy();
slot.turn.clear();
slot.turn.notify_one();
}
private:
template <typename U = T>
struct Slot {
~Slot() noexcept {
if (turn.test()) {
destroy();
}
}
template <typename... Args>
void construct(Args&&... args) noexcept {
static_assert(std::is_nothrow_constructible_v<U, Args&&...>,
"T must be nothrow constructible with Args&&...");
std::construct_at(reinterpret_cast<U*>(&storage), std::forward<Args>(args)...);
}
void destroy() noexcept {
static_assert(std::is_nothrow_destructible_v<U>, "T must be nothrow destructible");
std::destroy_at(reinterpret_cast<U*>(&storage));
}
U&& move() noexcept {
return reinterpret_cast<U&&>(storage);
}
// Align to avoid false sharing between adjacent slots
alignas(hardware_interference_size) std::atomic_flag turn{};
struct aligned_store {
struct type {
alignas(U) unsigned char data[sizeof(U)];
};
};
typename aligned_store::type storage;
};
template <typename... Args>
void emplace(Args&&... args) noexcept {
static_assert(std::is_nothrow_constructible_v<T, Args&&...>,
"T must be nothrow constructible with Args&&...");
auto const head = head_.fetch_add(1);
auto& slot = slots[idx(head)];
slot.turn.wait(true);
slot.construct(std::forward<Args>(args)...);
slot.turn.test_and_set();
cv.notify_one();
}
constexpr size_t idx(size_t i) const noexcept {
return i & mask;
}
static constexpr size_t mask = capacity - 1;
// Align to avoid false sharing between head_ and tail_
alignas(hardware_interference_size) std::atomic<size_t> head_{0};
alignas(hardware_interference_size) std::atomic<size_t> tail_{0};
std::mutex cv_mutex;
std::condition_variable_any cv;
Slot<T>* slots;
[[no_unique_address]] std::allocator<Slot<T>> allocator;
static_assert(std::is_nothrow_copy_assignable_v<T> || std::is_nothrow_move_assignable_v<T>,
"T must be nothrow copy or move assignable");
static_assert(std::is_nothrow_destructible_v<T>, "T must be nothrow destructible");
};
#ifdef _MSC_VER
#pragma warning(pop)
#endif
} // namespace Common
+20 -5
View File
@@ -1,8 +1,23 @@
// SPDX-FileCopyrightText: 2011 Google, Inc.
// SPDX-FileContributor: Geoff Pike
// SPDX-FileContributor: Jyrki Alakuijala
// SPDX-License-Identifier: MIT
// Copyright (c) 2011 Google, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// CityHash, by Geoff Pike and Jyrki Alakuijala
//
// This file provides CityHash64() and related functions.
+20 -5
View File
@@ -1,8 +1,23 @@
// SPDX-FileCopyrightText: 2011 Google, Inc.
// SPDX-FileContributor: Geoff Pike
// SPDX-FileContributor: Jyrki Alakuijala
// SPDX-License-Identifier: MIT
// Copyright (c) 2011 Google, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// CityHash, by Geoff Pike and Jyrki Alakuijala
//
// http://code.google.com/p/cityhash/
-4
View File
@@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2012 Gekko Emulator
// SPDX-FileContributor: ShizZy <shizzy247@gmail.com>
// SPDX-License-Identifier: GPL-2.0-or-later
/**
* Copyright (C) 2005-2012 Gekko Emulator
*
+2 -2
View File
@@ -33,9 +33,9 @@ void DetachedTasks::AddTask(std::function<void()> task) {
++instance->count;
std::thread([task{std::move(task)}]() {
task();
std::unique_lock thread_lock{instance->mutex};
std::unique_lock lock{instance->mutex};
--instance->count;
std::notify_all_at_thread_exit(instance->cv, std::move(thread_lock));
std::notify_all_at_thread_exit(instance->cv, std::move(lock));
}).detach();
}
+3 -2
View File
@@ -1,5 +1,6 @@
// SPDX-FileCopyrightText: 2019 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2019 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <string>
#include <utility>
+3 -2
View File
@@ -1,5 +1,6 @@
// SPDX-FileCopyrightText: 2019 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2019 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
-333
View File
@@ -1,333 +0,0 @@
// SPDX-FileCopyrightText: 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <cstddef>
#include "common_types.h"
namespace Common {
namespace ELF {
/* Type for a 16-bit quantity. */
using Elf32_Half = u16;
using Elf64_Half = u16;
/* Types for signed and unsigned 32-bit quantities. */
using Elf32_Word = u32;
using Elf32_Sword = s32;
using Elf64_Word = u32;
using Elf64_Sword = s32;
/* Types for signed and unsigned 64-bit quantities. */
using Elf32_Xword = u64;
using Elf32_Sxword = s64;
using Elf64_Xword = u64;
using Elf64_Sxword = s64;
/* Type of addresses. */
using Elf32_Addr = u32;
using Elf64_Addr = u64;
/* Type of file offsets. */
using Elf32_Off = u32;
using Elf64_Off = u64;
/* Type for section indices, which are 16-bit quantities. */
using Elf32_Section = u16;
using Elf64_Section = u16;
/* Type for version symbol information. */
using Elf32_Versym = Elf32_Half;
using Elf64_Versym = Elf64_Half;
constexpr size_t ElfIdentSize = 16;
/* The ELF file header. This appears at the start of every ELF file. */
struct Elf32_Ehdr {
std::array<u8, ElfIdentSize> e_ident; /* Magic number and other info */
Elf32_Half e_type; /* Object file type */
Elf32_Half e_machine; /* Architecture */
Elf32_Word e_version; /* Object file version */
Elf32_Addr e_entry; /* Entry point virtual address */
Elf32_Off e_phoff; /* Program header table file offset */
Elf32_Off e_shoff; /* Section header table file offset */
Elf32_Word e_flags; /* Processor-specific flags */
Elf32_Half e_ehsize; /* ELF header size in bytes */
Elf32_Half e_phentsize; /* Program header table entry size */
Elf32_Half e_phnum; /* Program header table entry count */
Elf32_Half e_shentsize; /* Section header table entry size */
Elf32_Half e_shnum; /* Section header table entry count */
Elf32_Half e_shstrndx; /* Section header string table index */
};
struct Elf64_Ehdr {
std::array<u8, ElfIdentSize> e_ident; /* Magic number and other info */
Elf64_Half e_type; /* Object file type */
Elf64_Half e_machine; /* Architecture */
Elf64_Word e_version; /* Object file version */
Elf64_Addr e_entry; /* Entry point virtual address */
Elf64_Off e_phoff; /* Program header table file offset */
Elf64_Off e_shoff; /* Section header table file offset */
Elf64_Word e_flags; /* Processor-specific flags */
Elf64_Half e_ehsize; /* ELF header size in bytes */
Elf64_Half e_phentsize; /* Program header table entry size */
Elf64_Half e_phnum; /* Program header table entry count */
Elf64_Half e_shentsize; /* Section header table entry size */
Elf64_Half e_shnum; /* Section header table entry count */
Elf64_Half e_shstrndx; /* Section header string table index */
};
constexpr u8 ElfClass32 = 1; /* 32-bit objects */
constexpr u8 ElfClass64 = 2; /* 64-bit objects */
constexpr u8 ElfData2Lsb = 1; /* 2's complement, little endian */
constexpr u8 ElfVersionCurrent = 1; /* EV_CURRENT */
constexpr u8 ElfOsAbiNone = 0; /* System V ABI */
constexpr u16 ElfTypeNone = 0; /* No file type */
constexpr u16 ElfTypeRel = 0; /* Relocatable file */
constexpr u16 ElfTypeExec = 0; /* Executable file */
constexpr u16 ElfTypeDyn = 0; /* Shared object file */
constexpr u16 ElfMachineArm = 40; /* ARM */
constexpr u16 ElfMachineAArch64 = 183; /* ARM AARCH64 */
constexpr std::array<u8, ElfIdentSize> Elf32Ident{
0x7f, 'E', 'L', 'F', ElfClass32, ElfData2Lsb, ElfVersionCurrent, ElfOsAbiNone};
constexpr std::array<u8, ElfIdentSize> Elf64Ident{
0x7f, 'E', 'L', 'F', ElfClass64, ElfData2Lsb, ElfVersionCurrent, ElfOsAbiNone};
/* Section header. */
struct Elf32_Shdr {
Elf32_Word sh_name; /* Section name (string tbl index) */
Elf32_Word sh_type; /* Section type */
Elf32_Word sh_flags; /* Section flags */
Elf32_Addr sh_addr; /* Section virtual addr at execution */
Elf32_Off sh_offset; /* Section file offset */
Elf32_Word sh_size; /* Section size in bytes */
Elf32_Word sh_link; /* Link to another section */
Elf32_Word sh_info; /* Additional section information */
Elf32_Word sh_addralign; /* Section alignment */
Elf32_Word sh_entsize; /* Entry size if section holds table */
};
struct Elf64_Shdr {
Elf64_Word sh_name; /* Section name (string tbl index) */
Elf64_Word sh_type; /* Section type */
Elf64_Xword sh_flags; /* Section flags */
Elf64_Addr sh_addr; /* Section virtual addr at execution */
Elf64_Off sh_offset; /* Section file offset */
Elf64_Xword sh_size; /* Section size in bytes */
Elf64_Word sh_link; /* Link to another section */
Elf64_Word sh_info; /* Additional section information */
Elf64_Xword sh_addralign; /* Section alignment */
Elf64_Xword sh_entsize; /* Entry size if section holds table */
};
constexpr u32 ElfShnUndef = 0; /* Undefined section */
constexpr u32 ElfShtNull = 0; /* Section header table entry unused */
constexpr u32 ElfShtProgBits = 1; /* Program data */
constexpr u32 ElfShtSymtab = 2; /* Symbol table */
constexpr u32 ElfShtStrtab = 3; /* String table */
constexpr u32 ElfShtRela = 4; /* Relocation entries with addends */
constexpr u32 ElfShtDynamic = 6; /* Dynamic linking information */
constexpr u32 ElfShtNobits = 7; /* Program space with no data (bss) */
constexpr u32 ElfShtRel = 9; /* Relocation entries, no addends */
constexpr u32 ElfShtDynsym = 11; /* Dynamic linker symbol table */
/* Symbol table entry. */
struct Elf32_Sym {
Elf32_Word st_name; /* Symbol name (string tbl index) */
Elf32_Addr st_value; /* Symbol value */
Elf32_Word st_size; /* Symbol size */
u8 st_info; /* Symbol type and binding */
u8 st_other; /* Symbol visibility */
Elf32_Section st_shndx; /* Section index */
};
struct Elf64_Sym {
Elf64_Word st_name; /* Symbol name (string tbl index) */
u8 st_info; /* Symbol type and binding */
u8 st_other; /* Symbol visibility */
Elf64_Section st_shndx; /* Section index */
Elf64_Addr st_value; /* Symbol value */
Elf64_Xword st_size; /* Symbol size */
};
/* How to extract and insert information held in the st_info field. */
static inline u8 ElfStBind(u8 st_info) {
return st_info >> 4;
}
static inline u8 ElfStType(u8 st_info) {
return st_info & 0xf;
}
static inline u8 ElfStInfo(u8 st_bind, u8 st_type) {
return static_cast<u8>((st_bind << 4) + (st_type & 0xf));
}
constexpr u8 ElfBindLocal = 0; /* Local symbol */
constexpr u8 ElfBindGlobal = 1; /* Global symbol */
constexpr u8 ElfBindWeak = 2; /* Weak symbol */
constexpr u8 ElfTypeUnspec = 0; /* Symbol type is unspecified */
constexpr u8 ElfTypeObject = 1; /* Symbol is a data object */
constexpr u8 ElfTypeFunc = 2; /* Symbol is a code object */
static inline u8 ElfStVisibility(u8 st_other) {
return static_cast<u8>(st_other & 0x3);
}
constexpr u8 ElfVisibilityDefault = 0; /* Default symbol visibility rules */
constexpr u8 ElfVisibilityInternal = 1; /* Processor specific hidden class */
constexpr u8 ElfVisibilityHidden = 2; /* Sym unavailable in other modules */
constexpr u8 ElfVisibilityProtected = 3; /* Not preemptible, not exported */
/* Relocation table entry without addend (in section of type ShtRel). */
struct Elf32_Rel {
Elf32_Addr r_offset; /* Address */
Elf32_Word r_info; /* Relocation type and symbol index */
};
/* Relocation table entry with addend (in section of type ShtRela). */
struct Elf32_Rela {
Elf32_Addr r_offset; /* Address */
Elf32_Word r_info; /* Relocation type and symbol index */
Elf32_Sword r_addend; /* Addend */
};
struct Elf64_Rela {
Elf64_Addr r_offset; /* Address */
Elf64_Xword r_info; /* Relocation type and symbol index */
Elf64_Sxword r_addend; /* Addend */
};
/* How to extract and insert information held in the r_info field. */
static inline u32 Elf32RelSymIndex(Elf32_Word r_info) {
return r_info >> 8;
}
static inline u8 Elf32RelType(Elf32_Word r_info) {
return static_cast<u8>(r_info & 0xff);
}
static inline Elf32_Word Elf32RelInfo(u32 sym_index, u8 type) {
return (sym_index << 8) + type;
}
static inline u32 Elf64RelSymIndex(Elf64_Xword r_info) {
return static_cast<u32>(r_info >> 32);
}
static inline u32 Elf64RelType(Elf64_Xword r_info) {
return r_info & 0xffffffff;
}
static inline Elf64_Xword Elf64RelInfo(u32 sym_index, u32 type) {
return (static_cast<Elf64_Xword>(sym_index) << 32) + type;
}
constexpr u32 ElfArmCopy = 20; /* Copy symbol at runtime */
constexpr u32 ElfArmGlobDat = 21; /* Create GOT entry */
constexpr u32 ElfArmJumpSlot = 22; /* Create PLT entry */
constexpr u32 ElfArmRelative = 23; /* Adjust by program base */
constexpr u32 ElfAArch64Copy = 1024; /* Copy symbol at runtime */
constexpr u32 ElfAArch64GlobDat = 1025; /* Create GOT entry */
constexpr u32 ElfAArch64JumpSlot = 1026; /* Create PLT entry */
constexpr u32 ElfAArch64Relative = 1027; /* Adjust by program base */
/* Program segment header. */
struct Elf32_Phdr {
Elf32_Word p_type; /* Segment type */
Elf32_Off p_offset; /* Segment file offset */
Elf32_Addr p_vaddr; /* Segment virtual address */
Elf32_Addr p_paddr; /* Segment physical address */
Elf32_Word p_filesz; /* Segment size in file */
Elf32_Word p_memsz; /* Segment size in memory */
Elf32_Word p_flags; /* Segment flags */
Elf32_Word p_align; /* Segment alignment */
};
struct Elf64_Phdr {
Elf64_Word p_type; /* Segment type */
Elf64_Word p_flags; /* Segment flags */
Elf64_Off p_offset; /* Segment file offset */
Elf64_Addr p_vaddr; /* Segment virtual address */
Elf64_Addr p_paddr; /* Segment physical address */
Elf64_Xword p_filesz; /* Segment size in file */
Elf64_Xword p_memsz; /* Segment size in memory */
Elf64_Xword p_align; /* Segment alignment */
};
/* Legal values for p_type (segment type). */
constexpr u32 ElfPtNull = 0; /* Program header table entry unused */
constexpr u32 ElfPtLoad = 1; /* Loadable program segment */
constexpr u32 ElfPtDynamic = 2; /* Dynamic linking information */
constexpr u32 ElfPtInterp = 3; /* Program interpreter */
constexpr u32 ElfPtNote = 4; /* Auxiliary information */
constexpr u32 ElfPtPhdr = 6; /* Entry for header table itself */
constexpr u32 ElfPtTls = 7; /* Thread-local storage segment */
/* Legal values for p_flags (segment flags). */
constexpr u32 ElfPfExec = 0; /* Segment is executable */
constexpr u32 ElfPfWrite = 1; /* Segment is writable */
constexpr u32 ElfPfRead = 2; /* Segment is readable */
/* Dynamic section entry. */
struct Elf32_Dyn {
Elf32_Sword d_tag; /* Dynamic entry type */
union {
Elf32_Word d_val; /* Integer value */
Elf32_Addr d_ptr; /* Address value */
} d_un;
};
struct Elf64_Dyn {
Elf64_Sxword d_tag; /* Dynamic entry type */
union {
Elf64_Xword d_val; /* Integer value */
Elf64_Addr d_ptr; /* Address value */
} d_un;
};
/* Legal values for d_tag (dynamic entry type). */
constexpr u32 ElfDtNull = 0; /* Marks end of dynamic section */
constexpr u32 ElfDtNeeded = 1; /* Name of needed library */
constexpr u32 ElfDtPltRelSz = 2; /* Size in bytes of PLT relocs */
constexpr u32 ElfDtPltGot = 3; /* Processor defined value */
constexpr u32 ElfDtHash = 4; /* Address of symbol hash table */
constexpr u32 ElfDtStrtab = 5; /* Address of string table */
constexpr u32 ElfDtSymtab = 6; /* Address of symbol table */
constexpr u32 ElfDtRela = 7; /* Address of Rela relocs */
constexpr u32 ElfDtRelasz = 8; /* Total size of Rela relocs */
constexpr u32 ElfDtRelaent = 9; /* Size of one Rela reloc */
constexpr u32 ElfDtStrsz = 10; /* Size of string table */
constexpr u32 ElfDtSyment = 11; /* Size of one symbol table entry */
constexpr u32 ElfDtInit = 12; /* Address of init function */
constexpr u32 ElfDtFini = 13; /* Address of termination function */
constexpr u32 ElfDtRel = 17; /* Address of Rel relocs */
constexpr u32 ElfDtRelsz = 18; /* Total size of Rel relocs */
constexpr u32 ElfDtRelent = 19; /* Size of one Rel reloc */
constexpr u32 ElfDtPltRel = 20; /* Type of reloc in PLT */
constexpr u32 ElfDtTextRel = 22; /* Reloc might modify .text */
constexpr u32 ElfDtJmpRel = 23; /* Address of PLT relocs */
constexpr u32 ElfDtBindNow = 24; /* Process relocations of object */
constexpr u32 ElfDtInitArray = 25; /* Array with addresses of init fct */
constexpr u32 ElfDtFiniArray = 26; /* Array with addresses of fini fct */
constexpr u32 ElfDtInitArraySz = 27; /* Size in bytes of DT_INIT_ARRAY */
constexpr u32 ElfDtFiniArraySz = 28; /* Size in bytes of DT_FINI_ARRAY */
constexpr u32 ElfDtSymtabShndx = 34; /* Address of SYMTAB_SHNDX section */
} // namespace ELF
} // namespace Common
+3 -1
View File
@@ -232,7 +232,9 @@ void SetYuzuPath(YuzuPath yuzu_path, const fs::path& new_path) {
fs::path GetExeDirectory() {
wchar_t exe_path[MAX_PATH];
if (GetModuleFileNameW(nullptr, exe_path, MAX_PATH) == 0) {
GetModuleFileNameW(nullptr, exe_path, MAX_PATH);
if (!exe_path) {
LOG_ERROR(Common_Filesystem,
"Failed to get the path to the executable of the current process");
}
+3 -3
View File
@@ -1,6 +1,6 @@
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/hex_util.h"
+3 -3
View File
@@ -1,6 +1,6 @@
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
-1
View File
@@ -72,7 +72,6 @@ enum class PollingError {
enum class VibrationAmplificationType {
Linear,
Exponential,
Test,
};
// Analog properties for calibration
+3 -3
View File
@@ -1,6 +1,6 @@
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
-3
View File
@@ -15,9 +15,6 @@ enum class PageType : u8 {
Unmapped,
/// Page is mapped to regular memory. This is the only type you can get pointers to.
Memory,
/// Page is mapped to regular memory, but inaccessible from CPU fastmem and must use
/// the callbacks.
DebugMemory,
/// Page is mapped to regular memory, but also needs to check for rasterizer cache flushing and
/// invalidation
RasterizerCachedMemory,
+3 -3
View File
@@ -76,7 +76,7 @@ std::string ParamPackage::Serialize() const {
std::string ParamPackage::Get(const std::string& key, const std::string& default_value) const {
auto pair = data.find(key);
if (pair == data.end()) {
LOG_TRACE(Common, "key '{}' not found", key);
LOG_DEBUG(Common, "key '{}' not found", key);
return default_value;
}
@@ -86,7 +86,7 @@ std::string ParamPackage::Get(const std::string& key, const std::string& default
int ParamPackage::Get(const std::string& key, int default_value) const {
auto pair = data.find(key);
if (pair == data.end()) {
LOG_TRACE(Common, "key '{}' not found", key);
LOG_DEBUG(Common, "key '{}' not found", key);
return default_value;
}
@@ -101,7 +101,7 @@ int ParamPackage::Get(const std::string& key, int default_value) const {
float ParamPackage::Get(const std::string& key, float default_value) const {
auto pair = data.find(key);
if (pair == data.end()) {
LOG_TRACE(Common, "key {} not found", key);
LOG_DEBUG(Common, "key {} not found", key);
return default_value;
}
+2 -3
View File
@@ -10,7 +10,7 @@
namespace Settings {
Values values;
Values values = {};
static bool configuring_global = true;
std::string GetTimeZoneString() {
@@ -70,7 +70,6 @@ void LogSettings() {
log_path("DataStorage_NANDDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir));
log_path("DataStorage_SDMCDir", Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir));
log_setting("Debugging_ProgramArgs", values.program_args.GetValue());
log_setting("Debugging_GDBStub", values.use_gdbstub.GetValue());
log_setting("Input_EnableMotion", values.motion_enabled.GetValue());
log_setting("Input_EnableVibration", values.vibration_enabled.GetValue());
log_setting("Input_EnableRawInput", values.enable_raw_input.GetValue());
@@ -147,7 +146,7 @@ void UpdateRescalingInfo() {
info.down_shift = 0;
break;
default:
ASSERT(false);
UNREACHABLE();
info.up_scale = 1;
info.down_shift = 0;
}
+2 -3
View File
@@ -496,7 +496,7 @@ struct Values {
// Renderer
RangedSetting<RendererBackend> renderer_backend{
RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Vulkan, "backend"};
RendererBackend::OpenGL, RendererBackend::OpenGL, RendererBackend::Vulkan, "backend"};
BasicSetting<bool> renderer_debug{false, "debug"};
BasicSetting<bool> renderer_shader_feedback{false, "shader_feedback"};
BasicSetting<bool> enable_nsight_aftermath{false, "nsight_aftermath"};
@@ -601,12 +601,11 @@ struct Values {
// Debugging
bool record_frame_times;
BasicSetting<bool> use_gdbstub{false, "use_gdbstub"};
BasicSetting<u16> gdbstub_port{6543, "gdbstub_port"};
BasicSetting<u16> gdbstub_port{0, "gdbstub_port"};
BasicSetting<std::string> program_args{std::string(), "program_args"};
BasicSetting<bool> dump_exefs{false, "dump_exefs"};
BasicSetting<bool> dump_nso{false, "dump_nso"};
BasicSetting<bool> dump_shaders{false, "dump_shaders"};
BasicSetting<bool> dump_macros{false, "dump_macros"};
BasicSetting<bool> enable_fs_access_log{false, "enable_fs_access_log"};
BasicSetting<bool> reporting_services{false, "reporting_services"};
BasicSetting<bool> quest_flag{false, "quest_flag"};
+3 -7
View File
@@ -1,6 +1,6 @@
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <cctype>
@@ -178,10 +178,6 @@ std::wstring UTF8ToUTF16W(const std::string& input) {
#endif
std::u16string U16StringFromBuffer(const u16* input, std::size_t length) {
return std::u16string(reinterpret_cast<const char16_t*>(input), length);
}
std::string StringFromFixedZeroTerminatedBuffer(std::string_view buffer, std::size_t max_len) {
std::size_t len = 0;
while (len < buffer.length() && len < max_len && buffer[len] != '\0') {
+3 -5
View File
@@ -1,6 +1,6 @@
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
@@ -44,8 +44,6 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
#endif
[[nodiscard]] std::u16string U16StringFromBuffer(const u16* input, std::size_t length);
/**
* Compares the string defined by the range [`begin`, `end`) to the null-terminated C-string
* `other` for equality.
+13 -3
View File
@@ -1,6 +1,16 @@
// SPDX-FileCopyrightText: 2012 PPSSPP Project
// SPDX-FileCopyrightText: 2012 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2012- PPSSPP Project / Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+3 -3
View File
@@ -1,6 +1,6 @@
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <string>
+3 -3
View File
@@ -1,6 +1,6 @@
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
+3 -3
View File
@@ -1,6 +1,6 @@
// SPDX-FileCopyrightText: 2012 PPSSPP Project
// SPDX-FileCopyrightText: 2014 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2014 Citra Emulator Project / PPSSPP Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
+3 -2
View File
@@ -1,5 +1,6 @@
// SPDX-FileCopyrightText: 2010 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
+25 -3
View File
@@ -1,10 +1,32 @@
// SPDX-FileCopyrightText: 2002 Niels Provos <provos@citi.umich.edu>
// SPDX-License-Identifier: BSD-2-Clause
/* $NetBSD: tree.h,v 1.8 2004/03/28 19:38:30 provos Exp $ */
/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */
/* $FreeBSD$ */
/*-
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
/*
+29 -3
View File
@@ -1,6 +1,32 @@
// SPDX-FileCopyrightText: 2014 Tony Wasserka
// SPDX-FileCopyrightText: 2014 Dolphin Emulator Project
// SPDX-License-Identifier: BSD-3-Clause AND GPL-2.0-or-later
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
// Copyright 2014 Tony Wasserka
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the owner nor the names of its contributors may
// be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
+6 -11
View File
@@ -36,13 +36,6 @@ add_library(core STATIC
crypto/ctr_encryption_layer.h
crypto/xts_encryption_layer.cpp
crypto/xts_encryption_layer.h
debugger/debugger_interface.h
debugger/debugger.cpp
debugger/debugger.h
debugger/gdbstub_arch.cpp
debugger/gdbstub_arch.h
debugger/gdbstub.cpp
debugger/gdbstub.h
device_memory.cpp
device_memory.h
file_sys/bis_factory.cpp
@@ -222,7 +215,7 @@ add_library(core STATIC
hle/kernel/k_page_buffer.h
hle/kernel/k_page_heap.cpp
hle/kernel/k_page_heap.h
hle/kernel/k_page_group.h
hle/kernel/k_page_linked_list.h
hle/kernel/k_page_table.cpp
hle/kernel/k_page_table.h
hle/kernel/k_port.cpp
@@ -743,11 +736,16 @@ if (MSVC)
/we4244 # 'conversion': conversion from 'type1' to 'type2', possible loss of data
/we4245 # 'conversion': conversion from 'type1' to 'type2', signed/unsigned mismatch
/we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
/we4456 # Declaration of 'identifier' hides previous local declaration
/we4457 # Declaration of 'identifier' hides function parameter
/we4458 # Declaration of 'identifier' hides class member
/we4459 # Declaration of 'identifier' hides global declaration
)
else()
target_compile_options(core PRIVATE
-Werror=conversion
-Werror=ignored-qualifiers
-Werror=shadow
$<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess>
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
@@ -763,9 +761,6 @@ create_target_directory_groups(core)
target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::Opus)
if (MINGW)
target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY})
endif()
if (ENABLE_WEB_SERVICE)
target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE)
-87
View File
@@ -9,9 +9,7 @@
#include "core/arm/arm_interface.h"
#include "core/arm/symbols.h"
#include "core/core.h"
#include "core/debugger/debugger.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/svc.h"
#include "core/loader/loader.h"
#include "core/memory.h"
@@ -90,89 +88,4 @@ void ARM_Interface::LogBacktrace() const {
}
}
void ARM_Interface::Run() {
using Kernel::StepState;
using Kernel::SuspendType;
while (true) {
Kernel::KThread* current_thread{Kernel::GetCurrentThreadPointer(system.Kernel())};
Dynarmic::HaltReason hr{};
// Notify the debugger and go to sleep if a step was performed
// and this thread has been scheduled again.
if (current_thread->GetStepState() == StepState::StepPerformed) {
system.GetDebugger().NotifyThreadStopped(current_thread);
current_thread->RequestSuspend(SuspendType::Debug);
break;
}
// Otherwise, run the thread.
system.EnterDynarmicProfile();
if (current_thread->GetStepState() == StepState::StepPending) {
hr = StepJit();
if (Has(hr, step_thread)) {
current_thread->SetStepState(StepState::StepPerformed);
}
} else {
hr = RunJit();
}
system.ExitDynarmicProfile();
// Notify the debugger and go to sleep if a breakpoint was hit.
if (Has(hr, breakpoint)) {
RewindBreakpointInstruction();
system.GetDebugger().NotifyThreadStopped(current_thread);
current_thread->RequestSuspend(SuspendType::Debug);
break;
}
if (Has(hr, watchpoint)) {
RewindBreakpointInstruction();
system.GetDebugger().NotifyThreadWatchpoint(current_thread, *HaltedWatchpoint());
current_thread->RequestSuspend(SuspendType::Debug);
break;
}
// Handle syscalls and scheduling (this may change the current thread)
if (Has(hr, svc_call)) {
Kernel::Svc::Call(system, GetSvcNumber());
}
if (Has(hr, break_loop) || !uses_wall_clock) {
break;
}
}
}
void ARM_Interface::LoadWatchpointArray(const WatchpointArray& wp) {
watchpoints = &wp;
}
const Kernel::DebugWatchpoint* ARM_Interface::MatchingWatchpoint(
VAddr addr, u64 size, Kernel::DebugWatchpointType access_type) const {
if (!watchpoints) {
return nullptr;
}
const VAddr start_address{addr};
const VAddr end_address{addr + size};
for (size_t i = 0; i < Core::Hardware::NUM_WATCHPOINTS; i++) {
const auto& watch{(*watchpoints)[i]};
if (end_address <= watch.start_address) {
continue;
}
if (start_address >= watch.end_address) {
continue;
}
if ((access_type & watch.type) == Kernel::DebugWatchpointType::None) {
continue;
}
return &watch;
}
return nullptr;
}
} // namespace Core
+8 -25
View File
@@ -5,11 +5,7 @@
#pragma once
#include <array>
#include <span>
#include <vector>
#include <dynarmic/interface/halt_reason.h>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hardware_properties.h"
@@ -20,16 +16,13 @@ struct PageTable;
namespace Kernel {
enum class VMAPermission : u8;
enum class DebugWatchpointType : u8;
struct DebugWatchpoint;
} // namespace Kernel
}
namespace Core {
class System;
class CPUInterruptHandler;
using CPUInterrupts = std::array<CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>;
using WatchpointArray = std::array<Kernel::DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>;
/// Generic ARMv8 CPU interface
class ARM_Interface {
@@ -71,7 +64,10 @@ public:
static_assert(sizeof(ThreadContext64) == 0x320);
/// Runs the CPU until an event happens
void Run();
virtual void Run() = 0;
/// Step CPU by one instruction
virtual void Step() = 0;
/// Clear all instruction cache
virtual void ClearInstructionCache() = 0;
@@ -174,11 +170,13 @@ public:
virtual void SaveContext(ThreadContext64& ctx) = 0;
virtual void LoadContext(const ThreadContext32& ctx) = 0;
virtual void LoadContext(const ThreadContext64& ctx) = 0;
void LoadWatchpointArray(const WatchpointArray& wp);
/// Clears the exclusive monitor's state.
virtual void ClearExclusiveState() = 0;
/// Prepare core for thread reschedule (if needed to correctly handle state)
virtual void PrepareReschedule() = 0;
/// Signal an interrupt and ask the core to halt as soon as possible.
virtual void SignalInterrupt() = 0;
@@ -199,28 +197,13 @@ public:
void LogBacktrace() const;
static constexpr Dynarmic::HaltReason step_thread = Dynarmic::HaltReason::Step;
static constexpr Dynarmic::HaltReason break_loop = Dynarmic::HaltReason::UserDefined2;
static constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3;
static constexpr Dynarmic::HaltReason breakpoint = Dynarmic::HaltReason::UserDefined4;
static constexpr Dynarmic::HaltReason watchpoint = Dynarmic::HaltReason::UserDefined5;
protected:
/// System context that this ARM interface is running under.
System& system;
CPUInterrupts& interrupt_handlers;
const WatchpointArray* watchpoints;
bool uses_wall_clock;
static void SymbolicateBacktrace(Core::System& system, std::vector<BacktraceEntry>& out);
const Kernel::DebugWatchpoint* MatchingWatchpoint(
VAddr addr, u64 size, Kernel::DebugWatchpointType access_type) const;
virtual Dynarmic::HaltReason RunJit() = 0;
virtual Dynarmic::HaltReason StepJit() = 0;
virtual u32 GetSvcNumber() const = 0;
virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0;
virtual void RewindBreakpointInstruction() = 0;
};
} // namespace Core
+30 -73
View File
@@ -17,8 +17,6 @@
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/debugger/debugger.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/svc.h"
#include "core/memory.h"
@@ -26,65 +24,51 @@ namespace Core {
using namespace Common::Literals;
constexpr Dynarmic::HaltReason break_loop = Dynarmic::HaltReason::UserDefined2;
constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3;
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
public:
explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_)
: parent{parent_},
memory(parent.system.Memory()), debugger_enabled{parent.system.DebuggerEnabled()} {}
: parent{parent_}, memory(parent.system.Memory()) {}
u8 MemoryRead8(u32 vaddr) override {
CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
return memory.Read8(vaddr);
}
u16 MemoryRead16(u32 vaddr) override {
CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read);
return memory.Read16(vaddr);
}
u32 MemoryRead32(u32 vaddr) override {
CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read);
return memory.Read32(vaddr);
}
u64 MemoryRead64(u32 vaddr) override {
CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);
return memory.Read64(vaddr);
}
void MemoryWrite8(u32 vaddr, u8 value) override {
if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) {
memory.Write8(vaddr, value);
}
memory.Write8(vaddr, value);
}
void MemoryWrite16(u32 vaddr, u16 value) override {
if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) {
memory.Write16(vaddr, value);
}
memory.Write16(vaddr, value);
}
void MemoryWrite32(u32 vaddr, u32 value) override {
if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) {
memory.Write32(vaddr, value);
}
memory.Write32(vaddr, value);
}
void MemoryWrite64(u32 vaddr, u64 value) override {
if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) {
memory.Write64(vaddr, value);
}
memory.Write64(vaddr, value);
}
bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override {
return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) &&
memory.WriteExclusive8(vaddr, value, expected);
return memory.WriteExclusive8(vaddr, value, expected);
}
bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override {
return CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write) &&
memory.WriteExclusive16(vaddr, value, expected);
return memory.WriteExclusive16(vaddr, value, expected);
}
bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override {
return CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write) &&
memory.WriteExclusive32(vaddr, value, expected);
return memory.WriteExclusive32(vaddr, value, expected);
}
bool MemoryWriteExclusive64(u32 vaddr, u64 value, u64 expected) override {
return CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write) &&
memory.WriteExclusive64(vaddr, value, expected);
return memory.WriteExclusive64(vaddr, value, expected);
}
void InterpreterFallback(u32 pc, std::size_t num_instructions) override {
@@ -94,21 +78,16 @@ public:
}
void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override {
if (debugger_enabled) {
parent.SaveContext(parent.breakpoint_context);
parent.jit.load()->HaltExecution(ARM_Interface::breakpoint);
return;
}
parent.LogBacktrace();
LOG_CRITICAL(Core_ARM,
"ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})",
exception, pc, MemoryReadCode(pc), parent.IsInThumbMode());
UNIMPLEMENTED();
}
void CallSVC(u32 swi) override {
parent.svc_swi = swi;
parent.jit.load()->HaltExecution(ARM_Interface::svc_call);
parent.jit.load()->HaltExecution(svc_call);
}
void AddTicks(u64 ticks) override {
@@ -134,26 +113,9 @@ public:
return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);
}
bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) {
if (!debugger_enabled) {
return true;
}
const auto match{parent.MatchingWatchpoint(addr, size, type)};
if (match) {
parent.SaveContext(parent.breakpoint_context);
parent.jit.load()->HaltExecution(ARM_Interface::watchpoint);
parent.halted_watchpoint = match;
return false;
}
return true;
}
ARM_Dynarmic_32& parent;
Core::Memory::Memory& memory;
std::size_t num_interpreted_instructions{};
bool debugger_enabled{};
static constexpr u64 minimum_run_cycles = 1000U;
};
@@ -188,11 +150,6 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
config.code_cache_size = 512_MiB;
config.far_code_offset = 400_MiB;
// Allow memory fault handling to work
if (system.DebuggerEnabled()) {
config.check_halt_on_memory_access = true;
}
// null_jit
if (!page_table) {
// Don't waste too much memory on null_jit
@@ -275,24 +232,20 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
return std::make_unique<Dynarmic::A32::Jit>(config);
}
Dynarmic::HaltReason ARM_Dynarmic_32::RunJit() {
return jit.load()->Run();
void ARM_Dynarmic_32::Run() {
while (true) {
const auto hr = jit.load()->Run();
if (Has(hr, svc_call)) {
Kernel::Svc::Call(system, svc_swi);
}
if (Has(hr, break_loop) || !uses_wall_clock) {
break;
}
}
}
Dynarmic::HaltReason ARM_Dynarmic_32::StepJit() {
return jit.load()->Step();
}
u32 ARM_Dynarmic_32::GetSvcNumber() const {
return svc_swi;
}
const Kernel::DebugWatchpoint* ARM_Dynarmic_32::HaltedWatchpoint() const {
return halted_watchpoint;
}
void ARM_Dynarmic_32::RewindBreakpointInstruction() {
LoadContext(breakpoint_context);
void ARM_Dynarmic_32::Step() {
jit.load()->Step();
}
ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_,
@@ -374,6 +327,10 @@ void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
jit.load()->LoadContext(context);
}
void ARM_Dynarmic_32::PrepareReschedule() {
jit.load()->HaltExecution(break_loop);
}
void ARM_Dynarmic_32::SignalInterrupt() {
jit.load()->HaltExecution(break_loop);
}
+3 -11
View File
@@ -41,6 +41,8 @@ public:
void SetVectorReg(int index, u128 value) override;
u32 GetPSTATE() const override;
void SetPSTATE(u32 pstate) override;
void Run() override;
void Step() override;
VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override;
void SetTPIDR_EL0(u64 value) override;
@@ -55,6 +57,7 @@ public:
void LoadContext(const ThreadContext32& ctx) override;
void LoadContext(const ThreadContext64& ctx) override {}
void PrepareReschedule() override;
void SignalInterrupt() override;
void ClearExclusiveState() override;
@@ -68,13 +71,6 @@ public:
std::vector<BacktraceEntry> GetBacktrace() const override;
protected:
Dynarmic::HaltReason RunJit() override;
Dynarmic::HaltReason StepJit() override;
u32 GetSvcNumber() const override;
const Kernel::DebugWatchpoint* HaltedWatchpoint() const override;
void RewindBreakpointInstruction() override;
private:
std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const;
@@ -100,10 +96,6 @@ private:
// SVC callback
u32 svc_swi{};
// Watchpoint info
const Kernel::DebugWatchpoint* halted_watchpoint;
ThreadContext32 breakpoint_context;
};
} // namespace Core
+33 -79
View File
@@ -15,7 +15,6 @@
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/debugger/debugger.h"
#include "core/hardware_properties.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/svc.h"
@@ -26,79 +25,61 @@ namespace Core {
using Vector = Dynarmic::A64::Vector;
using namespace Common::Literals;
constexpr Dynarmic::HaltReason break_loop = Dynarmic::HaltReason::UserDefined2;
constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3;
class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
public:
explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_)
: parent{parent_},
memory(parent.system.Memory()), debugger_enabled{parent.system.DebuggerEnabled()} {}
: parent{parent_}, memory(parent.system.Memory()) {}
u8 MemoryRead8(u64 vaddr) override {
CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
return memory.Read8(vaddr);
}
u16 MemoryRead16(u64 vaddr) override {
CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read);
return memory.Read16(vaddr);
}
u32 MemoryRead32(u64 vaddr) override {
CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read);
return memory.Read32(vaddr);
}
u64 MemoryRead64(u64 vaddr) override {
CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);
return memory.Read64(vaddr);
}
Vector MemoryRead128(u64 vaddr) override {
CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read);
return {memory.Read64(vaddr), memory.Read64(vaddr + 8)};
}
void MemoryWrite8(u64 vaddr, u8 value) override {
if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) {
memory.Write8(vaddr, value);
}
memory.Write8(vaddr, value);
}
void MemoryWrite16(u64 vaddr, u16 value) override {
if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) {
memory.Write16(vaddr, value);
}
memory.Write16(vaddr, value);
}
void MemoryWrite32(u64 vaddr, u32 value) override {
if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) {
memory.Write32(vaddr, value);
}
memory.Write32(vaddr, value);
}
void MemoryWrite64(u64 vaddr, u64 value) override {
if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) {
memory.Write64(vaddr, value);
}
memory.Write64(vaddr, value);
}
void MemoryWrite128(u64 vaddr, Vector value) override {
if (CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Write)) {
memory.Write64(vaddr, value[0]);
memory.Write64(vaddr + 8, value[1]);
}
memory.Write64(vaddr, value[0]);
memory.Write64(vaddr + 8, value[1]);
}
bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, std::uint8_t expected) override {
return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) &&
memory.WriteExclusive8(vaddr, value, expected);
return memory.WriteExclusive8(vaddr, value, expected);
}
bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, std::uint16_t expected) override {
return CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write) &&
memory.WriteExclusive16(vaddr, value, expected);
return memory.WriteExclusive16(vaddr, value, expected);
}
bool MemoryWriteExclusive32(u64 vaddr, std::uint32_t value, std::uint32_t expected) override {
return CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write) &&
memory.WriteExclusive32(vaddr, value, expected);
return memory.WriteExclusive32(vaddr, value, expected);
}
bool MemoryWriteExclusive64(u64 vaddr, std::uint64_t value, std::uint64_t expected) override {
return CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write) &&
memory.WriteExclusive64(vaddr, value, expected);
return memory.WriteExclusive64(vaddr, value, expected);
}
bool MemoryWriteExclusive128(u64 vaddr, Vector value, Vector expected) override {
return CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Write) &&
memory.WriteExclusive128(vaddr, value, expected);
return memory.WriteExclusive128(vaddr, value, expected);
}
void InterpreterFallback(u64 pc, std::size_t num_instructions) override {
@@ -138,13 +119,8 @@ public:
case Dynarmic::A64::Exception::SendEventLocal:
case Dynarmic::A64::Exception::Yield:
return;
case Dynarmic::A64::Exception::Breakpoint:
default:
if (debugger_enabled) {
parent.SaveContext(parent.breakpoint_context);
parent.jit.load()->HaltExecution(ARM_Interface::breakpoint);
return;
}
parent.LogBacktrace();
ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
static_cast<std::size_t>(exception), pc, MemoryReadCode(pc));
@@ -153,7 +129,7 @@ public:
void CallSVC(u32 swi) override {
parent.svc_swi = swi;
parent.jit.load()->HaltExecution(ARM_Interface::svc_call);
parent.jit.load()->HaltExecution(svc_call);
}
void AddTicks(u64 ticks) override {
@@ -181,27 +157,10 @@ public:
return parent.system.CoreTiming().GetClockTicks();
}
bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) {
if (!debugger_enabled) {
return true;
}
const auto match{parent.MatchingWatchpoint(addr, size, type)};
if (match) {
parent.SaveContext(parent.breakpoint_context);
parent.jit.load()->HaltExecution(ARM_Interface::watchpoint);
parent.halted_watchpoint = match;
return false;
}
return true;
}
ARM_Dynarmic_64& parent;
Core::Memory::Memory& memory;
u64 tpidrro_el0 = 0;
u64 tpidr_el0 = 0;
bool debugger_enabled{};
static constexpr u64 minimum_run_cycles = 1000U;
};
@@ -252,11 +211,6 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
config.code_cache_size = 512_MiB;
config.far_code_offset = 400_MiB;
// Allow memory fault handling to work
if (system.DebuggerEnabled()) {
config.check_halt_on_memory_access = true;
}
// null_jit
if (!page_table) {
// Don't waste too much memory on null_jit
@@ -339,24 +293,20 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
return std::make_shared<Dynarmic::A64::Jit>(config);
}
Dynarmic::HaltReason ARM_Dynarmic_64::RunJit() {
return jit.load()->Run();
void ARM_Dynarmic_64::Run() {
while (true) {
const auto hr = jit.load()->Run();
if (Has(hr, svc_call)) {
Kernel::Svc::Call(system, svc_swi);
}
if (Has(hr, break_loop) || !uses_wall_clock) {
break;
}
}
}
Dynarmic::HaltReason ARM_Dynarmic_64::StepJit() {
return jit.load()->Step();
}
u32 ARM_Dynarmic_64::GetSvcNumber() const {
return svc_swi;
}
const Kernel::DebugWatchpoint* ARM_Dynarmic_64::HaltedWatchpoint() const {
return halted_watchpoint;
}
void ARM_Dynarmic_64::RewindBreakpointInstruction() {
LoadContext(breakpoint_context);
void ARM_Dynarmic_64::Step() {
jit.load()->Step();
}
ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_,
@@ -445,6 +395,10 @@ void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
SetTPIDR_EL0(ctx.tpidr);
}
void ARM_Dynarmic_64::PrepareReschedule() {
jit.load()->HaltExecution(break_loop);
}
void ARM_Dynarmic_64::SignalInterrupt() {
jit.load()->HaltExecution(break_loop);
}
+3 -11
View File
@@ -39,6 +39,8 @@ public:
void SetVectorReg(int index, u128 value) override;
u32 GetPSTATE() const override;
void SetPSTATE(u32 pstate) override;
void Run() override;
void Step() override;
VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override;
void SetTPIDR_EL0(u64 value) override;
@@ -49,6 +51,7 @@ public:
void LoadContext(const ThreadContext32& ctx) override {}
void LoadContext(const ThreadContext64& ctx) override;
void PrepareReschedule() override;
void SignalInterrupt() override;
void ClearExclusiveState() override;
@@ -62,13 +65,6 @@ public:
std::vector<BacktraceEntry> GetBacktrace() const override;
protected:
Dynarmic::HaltReason RunJit() override;
Dynarmic::HaltReason StepJit() override;
u32 GetSvcNumber() const override;
const Kernel::DebugWatchpoint* HaltedWatchpoint() const override;
void RewindBreakpointInstruction() override;
private:
std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table,
std::size_t address_space_bits) const;
@@ -93,10 +89,6 @@ private:
// SVC callback
u32 svc_swi{};
// Breakpoint info
const Kernel::DebugWatchpoint* halted_watchpoint;
ThreadContext64 breakpoint_context;
};
} // namespace Core
+1 -1
View File
@@ -20,7 +20,7 @@ struct fmt::formatter<Dynarmic::A32::CoprocReg> {
}
template <typename FormatContext>
auto format(const Dynarmic::A32::CoprocReg& reg, FormatContext& ctx) {
return fmt::format_to(ctx.out(), "cp{}", static_cast<size_t>(reg));
return format_to(ctx.out(), "cp{}", static_cast<size_t>(reg));
}
};
+72 -13
View File
@@ -3,14 +3,73 @@
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/elf.h"
#include "core/arm/symbols.h"
#include "core/core.h"
#include "core/memory.h"
using namespace Common::ELF;
namespace Core {
namespace {
constexpr u64 ELF_DYNAMIC_TAG_NULL = 0;
constexpr u64 ELF_DYNAMIC_TAG_STRTAB = 5;
constexpr u64 ELF_DYNAMIC_TAG_SYMTAB = 6;
constexpr u64 ELF_DYNAMIC_TAG_SYMENT = 11;
enum class ELFSymbolType : u8 {
None = 0,
Object = 1,
Function = 2,
Section = 3,
File = 4,
Common = 5,
TLS = 6,
};
enum class ELFSymbolBinding : u8 {
Local = 0,
Global = 1,
Weak = 2,
};
enum class ELFSymbolVisibility : u8 {
Default = 0,
Internal = 1,
Hidden = 2,
Protected = 3,
};
struct ELF64Symbol {
u32 name_index;
union {
u8 info;
BitField<0, 4, ELFSymbolType> type;
BitField<4, 4, ELFSymbolBinding> binding;
};
ELFSymbolVisibility visibility;
u16 sh_index;
u64 value;
u64 size;
};
static_assert(sizeof(ELF64Symbol) == 0x18, "ELF64Symbol has incorrect size.");
struct ELF32Symbol {
u32 name_index;
u32 value;
u32 size;
union {
u8 info;
BitField<0, 4, ELFSymbolType> type;
BitField<4, 4, ELFSymbolBinding> binding;
};
ELFSymbolVisibility visibility;
u16 sh_index;
};
static_assert(sizeof(ELF32Symbol) == 0x10, "ELF32Symbol has incorrect size.");
} // Anonymous namespace
namespace Symbols {
template <typename Word, typename ELFSymbol, typename ByteReader>
@@ -51,15 +110,15 @@ static Symbols GetSymbols(ByteReader ReadBytes) {
const Word value = ReadWord(dynamic_index + sizeof(Word));
dynamic_index += 2 * sizeof(Word);
if (tag == ElfDtNull) {
if (tag == ELF_DYNAMIC_TAG_NULL) {
break;
}
if (tag == ElfDtStrtab) {
if (tag == ELF_DYNAMIC_TAG_STRTAB) {
string_table_offset = value;
} else if (tag == ElfDtSymtab) {
} else if (tag == ELF_DYNAMIC_TAG_SYMTAB) {
symbol_table_offset = value;
} else if (tag == ElfDtSyment) {
} else if (tag == ELF_DYNAMIC_TAG_SYMENT) {
symbol_entry_size = value;
}
}
@@ -75,14 +134,14 @@ static Symbols GetSymbols(ByteReader ReadBytes) {
ELFSymbol symbol{};
ReadBytes(&symbol, symbol_index, sizeof(ELFSymbol));
VAddr string_offset = string_table_offset + symbol.st_name;
VAddr string_offset = string_table_offset + symbol.name_index;
std::string name;
for (u8 c = Read8(string_offset); c != 0; c = Read8(++string_offset)) {
name += static_cast<char>(c);
}
symbol_index += symbol_entry_size;
out[name] = std::make_pair(symbol.st_value, symbol.st_size);
out[name] = std::make_pair(symbol.value, symbol.size);
}
return out;
@@ -93,9 +152,9 @@ Symbols GetSymbols(VAddr base, Core::Memory::Memory& memory, bool is_64) {
[&](void* ptr, size_t offset, size_t size) { memory.ReadBlock(base + offset, ptr, size); }};
if (is_64) {
return GetSymbols<u64, Elf64_Sym>(ReadBytes);
return GetSymbols<u64, ELF64Symbol>(ReadBytes);
} else {
return GetSymbols<u32, Elf32_Sym>(ReadBytes);
return GetSymbols<u32, ELF32Symbol>(ReadBytes);
}
}
@@ -105,9 +164,9 @@ Symbols GetSymbols(std::span<const u8> data, bool is_64) {
}};
if (is_64) {
return GetSymbols<u64, Elf64_Sym>(ReadBytes);
return GetSymbols<u64, ELF64Symbol>(ReadBytes);
} else {
return GetSymbols<u32, Elf32_Sym>(ReadBytes);
return GetSymbols<u32, ELF32Symbol>(ReadBytes);
}
}
+18 -39
View File
@@ -17,7 +17,6 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/cpu_manager.h"
#include "core/debugger/debugger.h"
#include "core/device_memory.h"
#include "core/file_sys/bis_factory.h"
#include "core/file_sys/mode.h"
@@ -138,6 +137,7 @@ struct System::Impl {
kernel.Suspend(false);
core_timing.SyncPause(false);
cpu_manager.Pause(false);
is_paused = false;
return status;
@@ -149,29 +149,28 @@ struct System::Impl {
core_timing.SyncPause(true);
kernel.Suspend(true);
cpu_manager.Pause(true);
is_paused = true;
return status;
}
std::unique_lock<std::mutex> StallProcesses() {
std::unique_lock<std::mutex> StallCPU() {
std::unique_lock<std::mutex> lk(suspend_guard);
kernel.Suspend(true);
core_timing.SyncPause(true);
cpu_manager.Pause(true);
return lk;
}
void UnstallProcesses() {
void UnstallCPU() {
if (!is_paused) {
core_timing.SyncPause(false);
kernel.Suspend(false);
cpu_manager.Pause(false);
}
}
void InitializeDebugger(System& system, u16 port) {
debugger = std::make_unique<Debugger>(system, port);
}
SystemResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
LOG_DEBUG(Core, "initialized OK");
@@ -330,9 +329,6 @@ struct System::Impl {
gpu_core->NotifyShutdown();
}
kernel.ShutdownCores();
cpu_manager.Shutdown();
debugger.reset();
services.reset();
service_manager.reset();
cheat_engine.reset();
@@ -440,9 +436,6 @@ struct System::Impl {
/// Network instance
Network::NetworkInstance network_instance;
/// Debugger
std::unique_ptr<Core::Debugger> debugger;
SystemResultStatus status = SystemResultStatus::Success;
std::string status_details = "";
@@ -479,6 +472,10 @@ SystemResultStatus System::Pause() {
return impl->Pause();
}
SystemResultStatus System::SingleStep() {
return SystemResultStatus::Success;
}
void System::InvalidateCpuInstructionCaches() {
impl->kernel.InvalidateAllInstructionCaches();
}
@@ -491,22 +488,12 @@ void System::Shutdown() {
impl->Shutdown();
}
void System::DetachDebugger() {
if (impl->debugger) {
impl->debugger->NotifyShutdown();
}
std::unique_lock<std::mutex> System::StallCPU() {
return impl->StallCPU();
}
std::unique_lock<std::mutex> System::StallProcesses() {
return impl->StallProcesses();
}
void System::UnstallProcesses() {
impl->UnstallProcesses();
}
void System::InitializeDebugger() {
impl->InitializeDebugger(*this, Settings::values.gdbstub_port.GetValue());
void System::UnstallCPU() {
impl->UnstallCPU();
}
SystemResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath,
@@ -518,6 +505,10 @@ bool System::IsPoweredOn() const {
return impl->is_powered_on.load(std::memory_order::relaxed);
}
void System::PrepareReschedule() {
// Deprecated, does nothing, kept for backward compatibility.
}
void System::PrepareReschedule(const u32 core_index) {
impl->kernel.PrepareReschedule(core_index);
}
@@ -822,18 +813,6 @@ bool System::IsMulticore() const {
return impl->is_multicore;
}
bool System::DebuggerEnabled() const {
return Settings::values.use_gdbstub.GetValue();
}
Core::Debugger& System::GetDebugger() {
return *impl->debugger;
}
const Core::Debugger& System::GetDebugger() const {
return *impl->debugger;
}
void System::RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback) {
impl->execute_program_callback = std::move(callback);
}
+11 -17
View File
@@ -97,7 +97,6 @@ namespace Core {
class ARM_Interface;
class CpuManager;
class Debugger;
class DeviceMemory;
class ExclusiveMonitor;
class SpeedLimiter;
@@ -148,6 +147,12 @@ public:
*/
[[nodiscard]] SystemResultStatus Pause();
/**
* Step the CPU one instruction
* @return Result status, indicating whether or not the operation succeeded.
*/
[[nodiscard]] SystemResultStatus SingleStep();
/**
* Invalidate the CPU instruction caches
* This function should only be used by GDB Stub to support breakpoints, memory updates and
@@ -160,16 +165,8 @@ public:
/// Shutdown the emulated system.
void Shutdown();
/// Forcibly detach the debugger if it is running.
void DetachDebugger();
std::unique_lock<std::mutex> StallProcesses();
void UnstallProcesses();
/**
* Initialize the debugger.
*/
void InitializeDebugger();
std::unique_lock<std::mutex> StallCPU();
void UnstallCPU();
/**
* Load an executable application.
@@ -196,6 +193,9 @@ public:
/// Gets a reference to the telemetry session for this emulation session.
[[nodiscard]] const Core::TelemetrySession& TelemetrySession() const;
/// Prepare the core emulation for a reschedule
void PrepareReschedule();
/// Prepare the core emulation for a reschedule
void PrepareReschedule(u32 core_index);
@@ -357,9 +357,6 @@ public:
[[nodiscard]] Service::Time::TimeManager& GetTimeManager();
[[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const;
[[nodiscard]] Core::Debugger& GetDebugger();
[[nodiscard]] const Core::Debugger& GetDebugger() const;
void SetExitLock(bool locked);
[[nodiscard]] bool GetExitLock() const;
@@ -381,9 +378,6 @@ public:
/// Tells if system is running on multicore.
[[nodiscard]] bool IsMulticore() const;
/// Tells if the system debugger is enabled.
[[nodiscard]] bool DebuggerEnabled() const;
/// Type used for the frontend to designate a callback for System to re-launch the application
/// using a specified program index.
using ExecuteProgramCallback = std::function<void(std::size_t)>;
+160 -39
View File
@@ -21,24 +21,23 @@ CpuManager::~CpuManager() = default;
void CpuManager::ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager,
std::size_t core) {
cpu_manager.RunThread(core);
cpu_manager.RunThread(stop_token, core);
}
void CpuManager::Initialize() {
num_cores = is_multicore ? Core::Hardware::NUM_CPU_CORES : 1;
gpu_barrier = std::make_unique<Common::Barrier>(num_cores + 1);
for (std::size_t core = 0; core < num_cores; core++) {
core_data[core].host_thread = std::jthread(ThreadStart, std::ref(*this), core);
running_mode = true;
if (is_multicore) {
for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
core_data[core].host_thread = std::jthread(ThreadStart, std::ref(*this), core);
}
} else {
core_data[0].host_thread = std::jthread(ThreadStart, std::ref(*this), 0);
}
}
void CpuManager::Shutdown() {
for (std::size_t core = 0; core < num_cores; core++) {
if (core_data[core].host_thread.joinable()) {
core_data[core].host_thread.join();
}
}
running_mode = false;
Pause(false);
}
std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() {
@@ -49,8 +48,8 @@ std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() {
return IdleThreadFunction;
}
std::function<void(void*)> CpuManager::GetShutdownThreadStartFunc() {
return ShutdownThreadFunction;
std::function<void(void*)> CpuManager::GetSuspendThreadStartFunc() {
return SuspendThreadFunction;
}
void CpuManager::GuestThreadFunction(void* cpu_manager_) {
@@ -80,12 +79,17 @@ void CpuManager::IdleThreadFunction(void* cpu_manager_) {
}
}
void CpuManager::ShutdownThreadFunction(void* cpu_manager) {
static_cast<CpuManager*>(cpu_manager)->ShutdownThread();
void CpuManager::SuspendThreadFunction(void* cpu_manager_) {
CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
if (cpu_manager->is_multicore) {
cpu_manager->MultiCoreRunSuspendThread();
} else {
cpu_manager->SingleCoreRunSuspendThread();
}
}
void* CpuManager::GetStartFuncParameter() {
return this;
void* CpuManager::GetStartFuncParamater() {
return static_cast<void*>(this);
}
///////////////////////////////////////////////////////////////////////////////
@@ -95,7 +99,7 @@ void* CpuManager::GetStartFuncParameter() {
void CpuManager::MultiCoreRunGuestThread() {
auto& kernel = system.Kernel();
kernel.CurrentScheduler()->OnThreadStart();
auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread();
auto* thread = kernel.CurrentScheduler()->GetCurrentThread();
auto& host_context = thread->GetHostContext();
host_context->SetRewindPoint(GuestRewindFunction, this);
MultiCoreRunGuestLoop();
@@ -106,10 +110,12 @@ void CpuManager::MultiCoreRunGuestLoop() {
while (true) {
auto* physical_core = &kernel.CurrentPhysicalCore();
system.EnterDynarmicProfile();
while (!physical_core->IsInterrupted()) {
physical_core->Run();
physical_core = &kernel.CurrentPhysicalCore();
}
system.ExitDynarmicProfile();
{
Kernel::KScopedDisableDispatch dd(kernel);
physical_core->ArmInterface().ClearExclusiveState();
@@ -125,6 +131,58 @@ void CpuManager::MultiCoreRunIdleThread() {
}
}
void CpuManager::MultiCoreRunSuspendThread() {
auto& kernel = system.Kernel();
kernel.CurrentScheduler()->OnThreadStart();
while (true) {
auto core = kernel.CurrentPhysicalCoreIndex();
auto& scheduler = *kernel.CurrentScheduler();
Kernel::KThread* current_thread = scheduler.GetCurrentThread();
Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context);
ASSERT(scheduler.ContextSwitchPending());
ASSERT(core == kernel.CurrentPhysicalCoreIndex());
scheduler.RescheduleCurrentCore();
}
}
void CpuManager::MultiCorePause(bool paused) {
if (!paused) {
bool all_not_barrier = false;
while (!all_not_barrier) {
all_not_barrier = true;
for (const auto& data : core_data) {
all_not_barrier &= !data.is_running.load() && data.initialized.load();
}
}
for (auto& data : core_data) {
data.enter_barrier->Set();
}
if (paused_state.load()) {
bool all_barrier = false;
while (!all_barrier) {
all_barrier = true;
for (const auto& data : core_data) {
all_barrier &= data.is_paused.load() && data.initialized.load();
}
}
for (auto& data : core_data) {
data.exit_barrier->Set();
}
}
} else {
/// Wait until all cores are paused.
bool all_barrier = false;
while (!all_barrier) {
all_barrier = true;
for (const auto& data : core_data) {
all_barrier &= data.is_paused.load() && data.initialized.load();
}
}
/// Don't release the barrier
}
paused_state = paused;
}
///////////////////////////////////////////////////////////////////////////////
/// SingleCore ///
///////////////////////////////////////////////////////////////////////////////
@@ -132,7 +190,7 @@ void CpuManager::MultiCoreRunIdleThread() {
void CpuManager::SingleCoreRunGuestThread() {
auto& kernel = system.Kernel();
kernel.CurrentScheduler()->OnThreadStart();
auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread();
auto* thread = kernel.CurrentScheduler()->GetCurrentThread();
auto& host_context = thread->GetHostContext();
host_context->SetRewindPoint(GuestRewindFunction, this);
SingleCoreRunGuestLoop();
@@ -142,10 +200,12 @@ void CpuManager::SingleCoreRunGuestLoop() {
auto& kernel = system.Kernel();
while (true) {
auto* physical_core = &kernel.CurrentPhysicalCore();
system.EnterDynarmicProfile();
if (!physical_core->IsInterrupted()) {
physical_core->Run();
physical_core = &kernel.CurrentPhysicalCore();
}
system.ExitDynarmicProfile();
kernel.SetIsPhantomModeForSingleCore(true);
system.CoreTiming().Advance();
kernel.SetIsPhantomModeForSingleCore(false);
@@ -168,11 +228,25 @@ void CpuManager::SingleCoreRunIdleThread() {
}
}
void CpuManager::SingleCoreRunSuspendThread() {
auto& kernel = system.Kernel();
kernel.CurrentScheduler()->OnThreadStart();
while (true) {
auto core = kernel.GetCurrentHostThreadID();
auto& scheduler = *kernel.CurrentScheduler();
Kernel::KThread* current_thread = scheduler.GetCurrentThread();
Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[0].host_context);
ASSERT(scheduler.ContextSwitchPending());
ASSERT(core == kernel.GetCurrentHostThreadID());
scheduler.RescheduleCurrentCore();
}
}
void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
{
auto& kernel = system.Kernel();
auto& scheduler = kernel.Scheduler(current_core);
Kernel::KThread* current_thread = scheduler.GetSchedulerCurrentThread();
Kernel::KThread* current_thread = scheduler.GetCurrentThread();
if (idle_count >= 4 || from_running_enviroment) {
if (!from_running_enviroment) {
system.CoreTiming().Idle();
@@ -184,7 +258,7 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
}
current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES);
system.CoreTiming().ResetTicks();
scheduler.Unload(scheduler.GetSchedulerCurrentThread());
scheduler.Unload(scheduler.GetCurrentThread());
auto& next_scheduler = kernel.Scheduler(current_core);
Common::Fiber::YieldTo(current_thread->GetHostContext(), *next_scheduler.ControlContext());
@@ -193,21 +267,47 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
// May have changed scheduler
{
auto& scheduler = system.Kernel().Scheduler(current_core);
scheduler.Reload(scheduler.GetSchedulerCurrentThread());
idle_count = 0;
scheduler.Reload(scheduler.GetCurrentThread());
if (!scheduler.IsIdle()) {
idle_count = 0;
}
}
}
void CpuManager::ShutdownThread() {
auto& kernel = system.Kernel();
auto core = is_multicore ? kernel.CurrentPhysicalCoreIndex() : 0;
auto* current_thread = kernel.GetCurrentEmuThread();
Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context);
UNREACHABLE();
void CpuManager::SingleCorePause(bool paused) {
if (!paused) {
bool all_not_barrier = false;
while (!all_not_barrier) {
all_not_barrier = !core_data[0].is_running.load() && core_data[0].initialized.load();
}
core_data[0].enter_barrier->Set();
if (paused_state.load()) {
bool all_barrier = false;
while (!all_barrier) {
all_barrier = core_data[0].is_paused.load() && core_data[0].initialized.load();
}
core_data[0].exit_barrier->Set();
}
} else {
/// Wait until all cores are paused.
bool all_barrier = false;
while (!all_barrier) {
all_barrier = core_data[0].is_paused.load() && core_data[0].initialized.load();
}
/// Don't release the barrier
}
paused_state = paused;
}
void CpuManager::RunThread(std::size_t core) {
void CpuManager::Pause(bool paused) {
if (is_multicore) {
MultiCorePause(paused);
} else {
SingleCorePause(paused);
}
}
void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) {
/// Initialization
system.RegisterCoreThread(core);
std::string name;
@@ -220,24 +320,45 @@ void CpuManager::RunThread(std::size_t core) {
Common::SetCurrentThreadName(name.c_str());
Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
auto& data = core_data[core];
data.enter_barrier = std::make_unique<Common::Event>();
data.exit_barrier = std::make_unique<Common::Event>();
data.host_context = Common::Fiber::ThreadToFiber();
data.is_running = false;
data.initialized = true;
const bool sc_sync = !is_async_gpu && !is_multicore;
bool sc_sync_first_use = sc_sync;
// Cleanup
SCOPE_EXIT({
data.host_context->Exit();
data.enter_barrier.reset();
data.exit_barrier.reset();
data.initialized = false;
MicroProfileOnThreadExit();
});
// Running
gpu_barrier->Sync();
/// Running
while (running_mode) {
data.is_running = false;
data.enter_barrier->Wait();
if (sc_sync_first_use) {
system.GPU().ObtainContext();
sc_sync_first_use = false;
}
if (!is_async_gpu && !is_multicore) {
system.GPU().ObtainContext();
// Emulation was stopped
if (stop_token.stop_requested()) {
return;
}
auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
data.is_running = true;
Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext());
data.is_running = false;
data.is_paused = true;
data.exit_barrier->Wait();
data.is_paused = false;
}
auto* current_thread = system.Kernel().CurrentScheduler()->GetIdleThread();
Kernel::SetCurrentThread(system.Kernel(), current_thread);
Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext());
}
} // namespace Core
+18 -11
View File
@@ -43,17 +43,15 @@ public:
is_async_gpu = is_async;
}
void OnGpuReady() {
gpu_barrier->Sync();
}
void Initialize();
void Shutdown();
void Pause(bool paused);
static std::function<void(void*)> GetGuestThreadStartFunc();
static std::function<void(void*)> GetIdleThreadStartFunc();
static std::function<void(void*)> GetShutdownThreadStartFunc();
void* GetStartFuncParameter();
static std::function<void(void*)> GetSuspendThreadStartFunc();
void* GetStartFuncParamater();
void PreemptSingleCore(bool from_running_enviroment = true);
@@ -65,34 +63,43 @@ private:
static void GuestThreadFunction(void* cpu_manager);
static void GuestRewindFunction(void* cpu_manager);
static void IdleThreadFunction(void* cpu_manager);
static void ShutdownThreadFunction(void* cpu_manager);
static void SuspendThreadFunction(void* cpu_manager);
void MultiCoreRunGuestThread();
void MultiCoreRunGuestLoop();
void MultiCoreRunIdleThread();
void MultiCoreRunSuspendThread();
void MultiCorePause(bool paused);
void SingleCoreRunGuestThread();
void SingleCoreRunGuestLoop();
void SingleCoreRunIdleThread();
void SingleCoreRunSuspendThread();
void SingleCorePause(bool paused);
static void ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, std::size_t core);
void ShutdownThread();
void RunThread(std::size_t core);
void RunThread(std::stop_token stop_token, std::size_t core);
struct CoreData {
std::shared_ptr<Common::Fiber> host_context;
std::unique_ptr<Common::Event> enter_barrier;
std::unique_ptr<Common::Event> exit_barrier;
std::atomic<bool> is_running;
std::atomic<bool> is_paused;
std::atomic<bool> initialized;
std::jthread host_thread;
};
std::unique_ptr<Common::Barrier> gpu_barrier{};
std::atomic<bool> running_mode{};
std::atomic<bool> paused_state{};
std::array<CoreData, Core::Hardware::NUM_CPU_CORES> core_data{};
bool is_async_gpu{};
bool is_multicore{};
std::atomic<std::size_t> current_core{};
std::size_t idle_count{};
std::size_t num_cores{};
static constexpr std::size_t max_cycle_runs = 5;
System& system;
+2
View File
@@ -140,6 +140,7 @@ u64 GetSignatureTypeDataSize(SignatureType type) {
return 0x3C;
}
UNREACHABLE();
return 0;
}
u64 GetSignatureTypePaddingSize(SignatureType type) {
@@ -154,6 +155,7 @@ u64 GetSignatureTypePaddingSize(SignatureType type) {
return 0x40;
}
UNREACHABLE();
return 0;
}
SignatureType Ticket::GetSignatureType() const {
-315
View File
@@ -1,315 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <mutex>
#include <thread>
#include <boost/asio.hpp>
#include <boost/process/async_pipe.hpp>
#include "common/logging/log.h"
#include "common/thread.h"
#include "core/core.h"
#include "core/debugger/debugger.h"
#include "core/debugger/debugger_interface.h"
#include "core/debugger/gdbstub.h"
#include "core/hle/kernel/global_scheduler_context.h"
template <typename Readable, typename Buffer, typename Callback>
static void AsyncReceiveInto(Readable& r, Buffer& buffer, Callback&& c) {
static_assert(std::is_trivial_v<Buffer>);
auto boost_buffer{boost::asio::buffer(&buffer, sizeof(Buffer))};
r.async_read_some(
boost_buffer, [&, c](const boost::system::error_code& error, size_t bytes_read) {
if (!error.failed()) {
const u8* buffer_start = reinterpret_cast<const u8*>(&buffer);
std::span<const u8> received_data{buffer_start, buffer_start + bytes_read};
c(received_data);
}
AsyncReceiveInto(r, buffer, c);
});
}
template <typename Readable, typename Buffer>
static std::span<const u8> ReceiveInto(Readable& r, Buffer& buffer) {
static_assert(std::is_trivial_v<Buffer>);
auto boost_buffer{boost::asio::buffer(&buffer, sizeof(Buffer))};
size_t bytes_read = r.read_some(boost_buffer);
const u8* buffer_start = reinterpret_cast<const u8*>(&buffer);
std::span<const u8> received_data{buffer_start, buffer_start + bytes_read};
return received_data;
}
enum class SignalType {
Stopped,
Watchpoint,
ShuttingDown,
};
struct SignalInfo {
SignalType type;
Kernel::KThread* thread;
const Kernel::DebugWatchpoint* watchpoint;
};
namespace Core {
class DebuggerImpl : public DebuggerBackend {
public:
explicit DebuggerImpl(Core::System& system_, u16 port)
: system{system_}, signal_pipe{io_context}, client_socket{io_context} {
frontend = std::make_unique<GDBStub>(*this, system);
InitializeServer(port);
}
~DebuggerImpl() override {
ShutdownServer();
}
bool SignalDebugger(SignalInfo signal_info) {
{
std::scoped_lock lk{connection_lock};
if (stopped) {
// Do not notify the debugger about another event.
// It should be ignored.
return false;
}
// Set up the state.
stopped = true;
info = signal_info;
}
// Write a single byte into the pipe to wake up the debug interface.
boost::asio::write(signal_pipe, boost::asio::buffer(&stopped, sizeof(stopped)));
return true;
}
std::span<const u8> ReadFromClient() override {
return ReceiveInto(client_socket, client_data);
}
void WriteToClient(std::span<const u8> data) override {
boost::asio::write(client_socket, boost::asio::buffer(data.data(), data.size_bytes()));
}
void SetActiveThread(Kernel::KThread* thread) override {
active_thread = thread;
}
Kernel::KThread* GetActiveThread() override {
return active_thread;
}
private:
void InitializeServer(u16 port) {
using boost::asio::ip::tcp;
LOG_INFO(Debug_GDBStub, "Starting server on port {}...", port);
// Run the connection thread.
connection_thread = std::jthread([&, port](std::stop_token stop_token) {
try {
// Initialize the listening socket and accept a new client.
tcp::endpoint endpoint{boost::asio::ip::address_v4::any(), port};
tcp::acceptor acceptor{io_context, endpoint};
acceptor.async_accept(client_socket, [](const auto&) {});
io_context.run_one();
io_context.restart();
if (stop_token.stop_requested()) {
return;
}
ThreadLoop(stop_token);
} catch (const std::exception& ex) {
LOG_CRITICAL(Debug_GDBStub, "Stopping server: {}", ex.what());
}
});
}
void ShutdownServer() {
connection_thread.request_stop();
io_context.stop();
connection_thread.join();
}
void ThreadLoop(std::stop_token stop_token) {
Common::SetCurrentThreadName("yuzu:Debugger");
// Set up the client signals for new data.
AsyncReceiveInto(signal_pipe, pipe_data, [&](auto d) { PipeData(d); });
AsyncReceiveInto(client_socket, client_data, [&](auto d) { ClientData(d); });
// Set the active thread.
UpdateActiveThread();
// Set up the frontend.
frontend->Connected();
// Main event loop.
while (!stop_token.stop_requested() && io_context.run()) {
}
}
void PipeData(std::span<const u8> data) {
switch (info.type) {
case SignalType::Stopped:
case SignalType::Watchpoint:
// Stop emulation.
PauseEmulation();
// Notify the client.
active_thread = info.thread;
UpdateActiveThread();
if (info.type == SignalType::Watchpoint) {
frontend->Watchpoint(active_thread, *info.watchpoint);
} else {
frontend->Stopped(active_thread);
}
break;
case SignalType::ShuttingDown:
frontend->ShuttingDown();
// Wait for emulation to shut down gracefully now.
signal_pipe.close();
client_socket.shutdown(boost::asio::socket_base::shutdown_both);
LOG_INFO(Debug_GDBStub, "Shut down server");
break;
}
}
void ClientData(std::span<const u8> data) {
const auto actions{frontend->ClientData(data)};
for (const auto action : actions) {
switch (action) {
case DebuggerAction::Interrupt: {
{
std::scoped_lock lk{connection_lock};
stopped = true;
}
PauseEmulation();
UpdateActiveThread();
frontend->Stopped(active_thread);
break;
}
case DebuggerAction::Continue:
MarkResumed([&] { ResumeEmulation(); });
break;
case DebuggerAction::StepThreadUnlocked:
MarkResumed([&] {
active_thread->SetStepState(Kernel::StepState::StepPending);
active_thread->Resume(Kernel::SuspendType::Debug);
ResumeEmulation(active_thread);
});
break;
case DebuggerAction::StepThreadLocked: {
MarkResumed([&] {
active_thread->SetStepState(Kernel::StepState::StepPending);
active_thread->Resume(Kernel::SuspendType::Debug);
});
break;
}
case DebuggerAction::ShutdownEmulation: {
// Spawn another thread that will exit after shutdown,
// to avoid a deadlock
Core::System* system_ref{&system};
std::thread t([system_ref] { system_ref->Exit(); });
t.detach();
break;
}
}
}
}
void PauseEmulation() {
// Put all threads to sleep on next scheduler round.
for (auto* thread : ThreadList()) {
thread->RequestSuspend(Kernel::SuspendType::Debug);
}
// Signal an interrupt so that scheduler will fire.
system.Kernel().InterruptAllPhysicalCores();
}
void ResumeEmulation(Kernel::KThread* except = nullptr) {
// Wake up all threads.
for (auto* thread : ThreadList()) {
if (thread == except) {
continue;
}
thread->SetStepState(Kernel::StepState::NotStepping);
thread->Resume(Kernel::SuspendType::Debug);
}
}
template <typename Callback>
void MarkResumed(Callback&& cb) {
std::scoped_lock lk{connection_lock};
stopped = false;
cb();
}
void UpdateActiveThread() {
const auto& threads{ThreadList()};
if (std::find(threads.begin(), threads.end(), active_thread) == threads.end()) {
active_thread = threads[0];
}
}
const std::vector<Kernel::KThread*>& ThreadList() {
return system.GlobalSchedulerContext().GetThreadList();
}
private:
System& system;
std::unique_ptr<DebuggerFrontend> frontend;
std::jthread connection_thread;
std::mutex connection_lock;
boost::asio::io_context io_context;
boost::process::async_pipe signal_pipe;
boost::asio::ip::tcp::socket client_socket;
SignalInfo info;
Kernel::KThread* active_thread;
bool pipe_data;
bool stopped;
std::array<u8, 4096> client_data;
};
Debugger::Debugger(Core::System& system, u16 port) {
try {
impl = std::make_unique<DebuggerImpl>(system, port);
} catch (const std::exception& ex) {
LOG_CRITICAL(Debug_GDBStub, "Failed to initialize debugger: {}", ex.what());
}
}
Debugger::~Debugger() = default;
bool Debugger::NotifyThreadStopped(Kernel::KThread* thread) {
return impl && impl->SignalDebugger(SignalInfo{SignalType::Stopped, thread, nullptr});
}
bool Debugger::NotifyThreadWatchpoint(Kernel::KThread* thread,
const Kernel::DebugWatchpoint& watch) {
return impl && impl->SignalDebugger(SignalInfo{SignalType::Watchpoint, thread, &watch});
}
void Debugger::NotifyShutdown() {
if (impl) {
impl->SignalDebugger(SignalInfo{SignalType::ShuttingDown, nullptr, nullptr});
}
}
} // namespace Core

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