diff options
74 files changed, 1680 insertions, 1807 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index b0fe285db..fc742317c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,25 +15,32 @@ else() # set up output paths for executable binaries (.exe-files, and .dll-files on DLL-capable platforms) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set(CMAKE_CONFIGURATION_TYPES Debug Release RelWithDebInfo CACHE STRING "" FORCE) # Tweak optimization settings # As far as I can tell, there's no way to override the CMake defaults while leaving user # changes intact, so we'll just clobber everything and say sorry. message(STATUS "Cache compiler flags ignored, please edit CMakeLists.txt to change the flags.") - # /MP - Multi-threaded compilation - # /MD - Multi-threaded runtime - # /Ox - Full optimization + # /O2 - Optimization level 2 # /Oy- - Don't omit frame pointer # /GR- - Disable RTTI # /GS- - No stack buffer overflow checks # /EHsc - C++-only exception handling semantics - set(optimization_flags "/MP /MD /Ox /Oy- /GR- /GS- /EHsc") + set(optimization_flags "/O2 /Oy- /GR- /GS- /EHsc") + # /MP - Multi-threaded compilation # /Zi - Output debugging information # /Zo - enahnced debug info for optimized builds - set(CMAKE_C_FLAGS_RELEASE "${optimization_flags} /Zi" CACHE STRING "" FORCE) - set(CMAKE_CXX_FLAGS_RELEASE "${optimization_flags} /Zi" CACHE STRING "" FORCE) - set(CMAKE_C_FLAGS_RELWITHDEBINFO "${optimization_flags} /Zi /Zo" CACHE STRING "" FORCE) - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${optimization_flags} /Zi /Zo" CACHE STRING "" FORCE) + # /MDd - Multi-threaded Debug Runtime DLL + set(CMAKE_C_FLAGS_DEBUG "/MP /MDd /Zi" CACHE STRING "" FORCE) + set(CMAKE_CXX_FLAGS_DEBUG "/MP /MDd /Zi" CACHE STRING "" FORCE) + # /MD - Multi-threaded runtime DLL + set(CMAKE_C_FLAGS_RELEASE "${optimization_flags} /MP /MD" CACHE STRING "" FORCE) + set(CMAKE_CXX_FLAGS_RELEASE "${optimization_flags} /MP /MD" CACHE STRING "" FORCE) + set(CMAKE_C_FLAGS_RELWITHDEBINFO "${optimization_flags} /MP /MD /Zi /Zo" CACHE STRING "" FORCE) + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${optimization_flags} /MP /MD /Zi /Zo" CACHE STRING "" FORCE) + + set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG" CACHE STRING "" FORCE) + set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "/DEBUG" CACHE STRING "" FORCE) endif() add_definitions(-DSINGLETHREADED) @@ -193,3 +200,16 @@ if(ENABLE_QT) add_subdirectory(externals/qhexedit) endif() add_subdirectory(src) + +# Install freedesktop.org metadata files, following those specifications: +# 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(${CMAKE_SYSTEM_NAME} MATCHES "Linux|FreeBSD|OpenBSD|NetBSD") + install(FILES "${CMAKE_SOURCE_DIR}/dist/citra.desktop" + DESTINATION "${CMAKE_INSTALL_PREFIX}/share/applications") + install(FILES "${CMAKE_SOURCE_DIR}/dist/citra.svg" + DESTINATION "${CMAKE_INSTALL_PREFIX}/share/pixmaps") + install(FILES "${CMAKE_SOURCE_DIR}/dist/citra.xml" + DESTINATION "${CMAKE_INSTALL_PREFIX}/share/mime/packages") +endif() @@ -11,7 +11,7 @@ For development discussion, please join us @ #citra on [freenode](http://webchat ### Development -If you want to contribute please take a look at the [Contributor's Guide](CONTRIBUTING.md), [Roadmap](https://github.com/citra-emu/citra/wiki/Roadmap) and [Developer Information](https://github.com/citra-emu/citra/wiki/Developer-Information) pages. You should as well contact any of the developers in the forum in order to know about the current state of the emulator. +If you want to contribute please take a look at the [Contributor's Guide](CONTRIBUTING.md), [TODO list](https://docs.google.com/document/d/1SWIop0uBI9IW8VGg97TAtoT_CHNoP42FzYmvG1F4QDA) and [Developer Information](https://github.com/citra-emu/citra/wiki/Developer-Information). You should as well contact any of the developers in the forum in order to know about the current state of the emulator. ### Building diff --git a/appveyor.yml b/appveyor.yml index 7886b905b..f2b656729 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -25,17 +25,7 @@ before_build: - cd .. after_build: - # copy the qt dlls - - copy C:\Qt\5.4\msvc2013_64_opengl\bin\icudt53.dll build\bin\release - - copy C:\Qt\5.4\msvc2013_64_opengl\bin\icuin53.dll build\bin\release - - copy C:\Qt\5.4\msvc2013_64_opengl\bin\icuuc53.dll build\bin\release - - copy C:\Qt\5.4\msvc2013_64_opengl\bin\Qt5Core.dll build\bin\release - - copy C:\Qt\5.4\msvc2013_64_opengl\bin\Qt5Gui.dll build\bin\release - - copy C:\Qt\5.4\msvc2013_64_opengl\bin\Qt5OpenGL.dll build\bin\release - - copy C:\Qt\5.4\msvc2013_64_opengl\bin\Qt5Widgets.dll build\bin\release - - mkdir build\bin\release\platforms\ - - copy C:\Qt\5.4\msvc2013_64_opengl\plugins\platforms\qwindows.dll build\bin\release\platforms - + # copying the needed QT Dlls is now done post build. See the CMakeLists.txt file in the citra-qt folder - ps: > if (!"$env:APPVEYOR_PULL_REQUEST_TITLE" -and ("$env:APPVEYOR_REPO_BRANCH" -eq "master")) { diff --git a/dist/citra.desktop b/dist/citra.desktop new file mode 100644 index 000000000..1300d62c2 --- /dev/null +++ b/dist/citra.desktop @@ -0,0 +1,14 @@ +[Desktop Entry] +Version=1.0 +Type=Application +Name=Citra +GenericName=3DS Emulator +GenericName[fr]=Émulateur 3DS +Comment=Nintendo 3DS video game console emulator +Comment[fr]=Émulateur de console de jeu Nintendo 3DS +Icon=citra +TryExec=citra-qt +Exec=citra-qt %f +Categories=Game;Emulator;Qt; +MimeType=application/x-ctr-3dsx;application/x-ctr-cci;application/x-ctr-cia;application/x-ctr-cxi; +Keywords=3DS;Nintendo; diff --git a/dist/citra.svg b/dist/citra.svg new file mode 100644 index 000000000..7b299cd89 --- /dev/null +++ b/dist/citra.svg @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright 2014 Citra Emulator Project + Licensed under GPLv2 or any later version + Refer to the license.txt file included. +--> +<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 341.071 338.846"> + <radialGradient id="a" cx="170.5356" cy="167.271" r="170.5332" gradientTransform="matrix(1 0 0 0.9935 0 3.2396)" gradientUnits="userSpaceOnUse"> + <stop offset="0.5193" stop-color="#FFFFFF" stop-opacity="0.1"/> + <stop offset="0.9415" stop-color="#000000" stop-opacity="0.5"/> + <stop offset="1" stop-color="#1A1818" stop-opacity="0"/> + </radialGradient> + <ellipse fill="url(#a)" cx="170.535" cy="169.423" rx="170.535" ry="169.423"/> + <circle fill="#D16F17" cx="170.536" cy="167.885" r="161.557"/> + <linearGradient id="b" gradientUnits="userSpaceOnUse" x1="234.4458" y1="33.5771" x2="97.5655" y2="321.2358"> + <stop offset="0" stop-color="#FFF8BD"/> + <stop offset="1" stop-color="#F6DCAE"/> + </linearGradient> + <circle fill="url(#b)" cx="170.536" cy="167.885" r="155.295"/> + <g> + <linearGradient id="c" gradientUnits="userSpaceOnUse" x1="332.436" y1="91.7446" x2="111.1593" y2="342.0988"> + <stop offset="0" stop-color="#F7A076"/> + <stop offset="0.4455" stop-color="#F3816C"/> + <stop offset="1" stop-color="#F06878"/> + </linearGradient> + <path fill="url(#c)" stroke="#F06564" stroke-miterlimit="10" d="M309.704,123.138 + c-5.9-7.802-128.517,44.681-128.517,44.681S303.803,221.01,309.704,212.5C322.434,194.142,323.182,140.957,309.704,123.138z"/> + <linearGradient id="d" gradientUnits="userSpaceOnUse" x1="285.5845" y1="50.3345" x2="64.3074" y2="300.6891"> + <stop offset="0" stop-color="#9DC63B"/> + <stop offset="1" stop-color="#9BC183"/> + </linearGradient> + <path fill="url(#d)" stroke="#72AA42" stroke-miterlimit="10" d="M300.518,100.96c-3.98-21.983-41.059-60.12-63.189-63.188 + c-9.688-1.345-59.28,122.469-59.28,122.469S302.364,111.149,300.518,100.96z"/> + <linearGradient id="e" gradientUnits="userSpaceOnUse" x1="229.4995" y1="0.7637" x2="8.2231" y2="251.1176"> + <stop offset="0" stop-color="#D5DE26"/> + <stop offset="1" stop-color="#C5D94B"/> + </linearGradient> + <path fill="url(#e)" stroke="#BECD30" stroke-miterlimit="10" d="M215.151,28.584c-18.357-12.73-71.543-13.478-89.362,0.001 + c-7.801,5.899,44.682,128.516,44.682,128.516S223.663,34.484,215.151,28.584z"/> + <linearGradient id="f" gradientUnits="userSpaceOnUse" x1="219.3823" y1="-8.1782" x2="-1.8941" y2="242.1756"> + <stop offset="0" stop-color="#F2D200"/> + <stop offset="1" stop-color="#FDEF52"/> + </linearGradient> + <path fill="url(#f)" stroke="#E1BE29" stroke-miterlimit="10" d="M162.893,160.239c0,0-49.092-124.315-59.281-122.469 + c-21.982,3.979-60.12,41.058-63.188,63.189C39.078,110.646,162.893,160.239,162.893,160.239z"/> + <linearGradient id="g" gradientUnits="userSpaceOnUse" x1="226.0718" y1="-2.2656" x2="4.7951" y2="248.0886"> + <stop offset="0" stop-color="#FFCD10"/> + <stop offset="1" stop-color="#F29634"/> + </linearGradient> + <path fill="url(#g)" stroke="#F79421" stroke-miterlimit="10" d="M31.236,123.136c-12.73,18.357-13.479,71.543,0,89.362 + c5.898,7.801,128.516-44.682,128.516-44.682S37.135,114.625,31.236,123.136z"/> + <linearGradient id="h" gradientUnits="userSpaceOnUse" x1="272.9214" y1="39.144" x2="51.6446" y2="289.4984"> + <stop offset="0" stop-color="#F79F1C"/> + <stop offset="0.4455" stop-color="#F08021"/> + <stop offset="1" stop-color="#ED693C"/> + </linearGradient> + <path fill="url(#h)" stroke="#F16622" stroke-miterlimit="10" d="M40.422,234.676c3.979,21.982,41.057,60.12,63.188,63.188 + c9.687,1.346,59.279-122.468,59.279-122.468S38.574,224.487,40.422,234.676z"/> + <linearGradient id="i" gradientUnits="userSpaceOnUse" x1="329.0083" y1="88.7129" x2="107.7311" y2="339.0677"> + <stop offset="0" stop-color="#E47C26"/> + <stop offset="0.4455" stop-color="#DF5B27"/> + <stop offset="1" stop-color="#DD3A3A"/> + </linearGradient> + <path fill="url(#i)" stroke="#E03827" stroke-miterlimit="10" d="M125.787,307.051c18.357,12.73,71.543,13.48,89.362,0 + c7.801-5.898-44.681-128.515-44.681-128.515S117.275,301.153,125.787,307.051z"/> + <linearGradient id="j" gradientUnits="userSpaceOnUse" x1="339.1245" y1="97.6562" x2="117.8478" y2="348.0104"> + <stop offset="0" stop-color="#F3783C"/> + <stop offset="0.4455" stop-color="#EF5339"/> + <stop offset="1" stop-color="#ED294A"/> + </linearGradient> + <path fill="url(#j)" stroke="#ED2836" stroke-miterlimit="10" d="M178.047,175.398c0,0,49.09,124.315,59.28,122.467 + c21.982-3.979,60.121-41.057,63.189-63.188C301.86,224.991,178.047,175.398,178.047,175.398z"/> + </g> + <linearGradient id="k" gradientUnits="userSpaceOnUse" x1="170.5352" y1="6.3281" x2="170.5351" y2="329.4424"> + <stop offset="0" stop-color="#FFFFFF" stop-opacity="0.2"/> + <stop offset="0.4504" stop-color="#908E8E" stop-opacity="0.05"/> + <stop offset="1" stop-color="#030003" stop-opacity="0.2"/> + </linearGradient> + <circle fill="url(#k)" cx="170.536" cy="167.885" r="161.557"/> +</svg> diff --git a/dist/citra.xml b/dist/citra.xml new file mode 100644 index 000000000..bcb9acd87 --- /dev/null +++ b/dist/citra.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8"?> +<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info"> + <mime-type type="application/x-ctr-3dsx"> + <comment>3DS homebrew executable</comment> + <comment xml:lang="fr">Exécutable 3DS homebrew</comment> + <acronym>3DSX</acronym> + <icon name="citra"/> + <glob pattern="*.3dsx"/> + <magic><match value="3DSX" type="string" offset="0"/></magic> + </mime-type> + + <mime-type type="application/x-ctr-cci"> + <comment>3DS cartridge image</comment> + <comment xml:lang="fr">Image de cartouche 3DS</comment> + <acronym>CCI</acronym> + <expanded-acronym>CTR Cart Image</expanded-acronym> + <icon name="citra"/> + <glob pattern="*.cci"/> + <glob pattern="*.3ds"/> + <magic><match value="NCSD" type="string" offset="256"/></magic> + </mime-type> + + <mime-type type="application/x-ctr-cxi"> + <comment>3DS executable</comment> + <comment xml:lang="fr">Exécutable 3DS</comment> + <acronym>CXI</acronym> + <expanded-acronym>CTR eXecutable Image</expanded-acronym> + <icon name="citra"/> + <glob pattern="*.cxi"/> + <magic><match value="NCCH" type="string" offset="256"/></magic> + </mime-type> + + <mime-type type="application/x-ctr-cia"> + <comment>3DS importable archive</comment> + <comment xml:lang="fr">Archive importable 3DS</comment> + <acronym>CIA</acronym> + <expanded-acronym>CTR Importable Archive</expanded-acronym> + <icon name="citra"/> + <glob pattern="*.cia"/> + </mime-type> + + <mime-type type="application/x-ctr-smdh"> + <comment>3DS icon</comment> + <comment xml:lang="fr">Icône 3DS</comment> + <acronym>SMDH</acronym> + <expanded-acronym>System Menu Data Header</expanded-acronym> + <glob pattern="*.smdh"/> + <magic><match value="SMDH" type="string" offset="0"/></magic> + </mime-type> + + <mime-type type="application/x-ctr-cbmd"> + <comment>3DS banner</comment> + <comment xml:lang="fr">Bannière 3DS</comment> + <acronym>CBMD</acronym> + <expanded-acronym>CTR Banner Model Data</expanded-acronym> + <glob pattern="*.cbmd"/> + <magic><match value="CBMD" type="string" offset="0"/></magic> + </mime-type> +</mime-info> diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp index 1d7e7f270..ca93d5b91 100644 --- a/src/citra/citra.cpp +++ b/src/citra/citra.cpp @@ -20,14 +20,8 @@ /// Application entry point int main(int argc, char **argv) { - std::shared_ptr<Log::Logger> logger = Log::InitGlobalLogger(); Log::Filter log_filter(Log::Level::Debug); Log::SetFilter(&log_filter); - std::thread logging_thread(Log::TextLoggingLoop, logger); - SCOPE_EXIT({ - logger->Close(); - logging_thread.join(); - }); if (argc < 2) { LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified"); diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index ff780cad4..efccdbec6 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -74,3 +74,39 @@ target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS}) target_link_libraries(citra-qt ${PLATFORM_LIBRARIES}) #install(TARGETS citra-qt RUNTIME DESTINATION ${bindir}) + +if (Qt5_FOUND AND MSVC) + set(Qt5_DLL_DIR "${Qt5_DIR}/../../../bin") + set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/") + set(Qt5_DLLS + icudt*.dll + icuin*.dll + icuuc*.dll + Qt5Core$<$<CONFIG:Debug>:d>.* + Qt5Gui$<$<CONFIG:Debug>:d>.* + Qt5OpenGL$<$<CONFIG:Debug>:d>.* + Qt5Widgets$<$<CONFIG:Debug>:d>.* + ) + set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/") + set(PLATFORMS ${DLL_DEST}platforms/) + + # windows commandline expects the / to be \ so switch them + string(REPLACE "/" "\\" Qt5_DLL_DIR ${Qt5_DLL_DIR}) + string(REPLACE "/" "\\" Qt5_PLATFORMS_DIR ${Qt5_PLATFORMS_DIR}) + string(REPLACE "/" "\\" DLL_DEST ${DLL_DEST}) + string(REPLACE "/" "\\" PLATFORMS ${PLATFORMS}) + + # /NJH /NJS /NDL /NFL /NC /NS /NP - Silence any output + # cmake adds an extra check for command success which doesn't work too well with robocopy + # so trick it into thinking the command was successful with the || cmd /c "exit /b 0" + add_custom_command(TARGET citra-qt POST_BUILD + COMMAND robocopy ${Qt5_DLL_DIR} ${DLL_DEST} ${Qt5_DLLS} /NJH /NJS /NDL /NFL /NC /NS /NP || cmd /c "exit /b 0" + COMMAND if not exist ${PLATFORMS} mkdir ${PLATFORMS} 2> nul + COMMAND robocopy ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.* /NJH /NJS /NDL /NFL /NC /NS /NP || cmd /c "exit /b 0" + ) + unset(Qt5_DLLS) + unset(Qt5_DLL_DIR) + unset(Qt5_PLATFORMS_DIR) + unset(DLL_DEST) + unset(PLATFORMS) +endif() diff --git a/src/citra_qt/debugger/callstack.cpp b/src/citra_qt/debugger/callstack.cpp index 3742c2d38..94e204717 100644 --- a/src/citra_qt/debugger/callstack.cpp +++ b/src/citra_qt/debugger/callstack.cpp @@ -8,7 +8,7 @@ #include "core/core.h" #include "core/arm/arm_interface.h" -#include "core/mem_map.h" +#include "core/memory.h" #include "common/symbols.h" #include "core/arm/disassembler/arm_disasm.h" diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp index 780607e82..e99ec1b30 100644 --- a/src/citra_qt/debugger/disassembler.cpp +++ b/src/citra_qt/debugger/disassembler.cpp @@ -7,7 +7,7 @@ #include "../bootmanager.h" #include "../hotkeys.h" -#include "core/mem_map.h" +#include "core/memory.h" #include "core/core.h" #include "common/break_points.h" diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp index 3287b4706..0c1a3f47f 100644 --- a/src/citra_qt/debugger/graphics_framebuffer.cpp +++ b/src/citra_qt/debugger/graphics_framebuffer.cpp @@ -10,6 +10,8 @@ #include <QSpinBox> #include "core/hw/gpu.h" +#include "core/memory.h" + #include "video_core/color.h" #include "video_core/pica.h" #include "video_core/utils.h" diff --git a/src/citra_qt/debugger/ramview.cpp b/src/citra_qt/debugger/ramview.cpp index 7149a0485..b6ebc7fc4 100644 --- a/src/citra_qt/debugger/ramview.cpp +++ b/src/citra_qt/debugger/ramview.cpp @@ -4,8 +4,6 @@ #include "ramview.h" -#include "core/mem_map.h" - GRamView::GRamView(QWidget* parent) : QHexEdit(parent) { diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index f115c5b6a..24506deab 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -337,7 +337,9 @@ void GMainWindow::closeEvent(QCloseEvent* event) settings.setValue("firstStart", false); SaveHotkeys(settings); - ShutdownGame(); + // Shutdown session if the emu thread is active... + if (emu_thread != nullptr) + ShutdownGame(); render_window->close(); @@ -350,14 +352,8 @@ void GMainWindow::closeEvent(QCloseEvent* event) int main(int argc, char* argv[]) { - std::shared_ptr<Log::Logger> logger = Log::InitGlobalLogger(); Log::Filter log_filter(Log::Level::Info); Log::SetFilter(&log_filter); - std::thread logging_thread(Log::TextLoggingLoop, logger); - SCOPE_EXIT({ - logger->Close(); - logging_thread.join(); - }); QApplication::setAttribute(Qt::AA_X11InitThreads); QApplication app(argc, argv); diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 11659c3c5..dbaaac77b 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -9,7 +9,6 @@ set(SRCS logging/filter.cpp logging/text_formatter.cpp logging/backend.cpp - math_util.cpp memory_util.cpp misc.cpp profiler.cpp @@ -28,7 +27,6 @@ set(HEADERS common_funcs.h common_paths.h common_types.h - concurrent_ring_buffer.h cpu_detect.h debug_interface.h emu_window.h diff --git a/src/common/assert.h b/src/common/assert.h index 4f26c63e9..7b7d8bf28 100644 --- a/src/common/assert.h +++ b/src/common/assert.h @@ -8,6 +8,7 @@ #include <cstdlib> #include "common/common_funcs.h" +#include "common/logging/log.h" // 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 @@ -28,19 +29,14 @@ static void assert_noinline_call(const Fn& fn) { exit(1); // Keeps GCC's mouth shut about this actually returning } -// TODO (yuriks) allow synchronous logging so we don't need printf #define ASSERT(_a_) \ do if (!(_a_)) { assert_noinline_call([] { \ - fprintf(stderr, "Assertion Failed!\n\n Line: %d\n File: %s\n Time: %s\n", \ - __LINE__, __FILE__, __TIME__); \ + LOG_CRITICAL(Debug, "Assertion Failed!"); \ }); } while (0) #define ASSERT_MSG(_a_, ...) \ do if (!(_a_)) { assert_noinline_call([&] { \ - fprintf(stderr, "Assertion Failed!\n\n Line: %d\n File: %s\n Time: %s\n", \ - __LINE__, __FILE__, __TIME__); \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, "\n"); \ + LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); \ }); } while (0) #define UNREACHABLE() ASSERT_MSG(false, "Unreachable code!") diff --git a/src/common/common_types.h b/src/common/common_types.h index 644709ba6..f6de0adfc 100644 --- a/src/common/common_types.h +++ b/src/common/common_types.h @@ -87,29 +87,3 @@ protected: NonCopyable(NonCopyable&) = delete; NonCopyable& operator=(NonCopyable&) = delete; }; - -namespace Common { -/// Rectangle data structure -class Rect { -public: - Rect(int x0=0, int y0=0, int x1=0, int y1=0) { - x0_ = x0; - y0_ = y0; - x1_ = x1; - y1_ = y1; - } - ~Rect() { } - - int x0_; ///< Rect top left X-coordinate - int y0_; ///< Rect top left Y-coordinate - int x1_; ///< Rect bottom left X-coordinate - int y1_; ///< Rect bottom right Y-coordinate - - inline u32 width() const { return std::abs(x1_ - x0_); } - inline u32 height() const { return std::abs(y1_ - y0_); } - - inline bool operator == (const Rect& val) const { - return (x0_ == val.x0_ && y0_ == val.y0_ && x1_ == val.x1_ && y1_ == val.y1_); - } -}; -} diff --git a/src/common/concurrent_ring_buffer.h b/src/common/concurrent_ring_buffer.h deleted file mode 100644 index c5889513a..000000000 --- a/src/common/concurrent_ring_buffer.h +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <array> -#include <condition_variable> -#include <cstdint> -#include <mutex> -#include <thread> - -#include "common/common_types.h" // for NonCopyable - -namespace Common { - -/** - * A MPMC (Multiple-Producer Multiple-Consumer) concurrent ring buffer. This data structure permits - * multiple threads to push and pop from a queue of bounded size. - */ -template <typename T, size_t ArraySize> -class ConcurrentRingBuffer : private NonCopyable { -public: - /// Value returned by the popping functions when the queue has been closed. - static const size_t QUEUE_CLOSED = -1; - - ConcurrentRingBuffer() {} - - ~ConcurrentRingBuffer() { - // If for whatever reason the queue wasn't completely drained, destroy the left over items. - for (size_t i = reader_index, end = writer_index; i != end; i = (i + 1) % ArraySize) { - Data()[i].~T(); - } - } - - /** - * Pushes a value to the queue. If the queue is full, this method will block. Does nothing if - * the queue is closed. - */ - void Push(T val) { - std::unique_lock<std::mutex> lock(mutex); - if (closed) { - return; - } - - // If the buffer is full, wait - writer.wait(lock, [&]{ - return (writer_index + 1) % ArraySize != reader_index; - }); - - T* item = &Data()[writer_index]; - new (item) T(std::move(val)); - - writer_index = (writer_index + 1) % ArraySize; - - // Wake up waiting readers - lock.unlock(); - reader.notify_one(); - } - - /** - * Pops up to `dest_len` items from the queue, storing them in `dest`. This function will not - * block, and might return 0 values if there are no elements in the queue when it is called. - * - * @return The number of elements stored in `dest`. If the queue has been closed, returns - * `QUEUE_CLOSED`. - */ - size_t Pop(T* dest, size_t dest_len) { - std::unique_lock<std::mutex> lock(mutex); - if (closed && !CanRead()) { - return QUEUE_CLOSED; - } - return PopInternal(dest, dest_len); - } - - /** - * Pops up to `dest_len` items from the queue, storing them in `dest`. This function will block - * if there are no elements in the queue when it is called. - * - * @return The number of elements stored in `dest`. If the queue has been closed, returns - * `QUEUE_CLOSED`. - */ - size_t BlockingPop(T* dest, size_t dest_len) { - std::unique_lock<std::mutex> lock(mutex); - if (closed && !CanRead()) { - return QUEUE_CLOSED; - } - - while (!CanRead()) { - reader.wait(lock); - if (closed && !CanRead()) { - return QUEUE_CLOSED; - } - } - DEBUG_ASSERT(CanRead()); - return PopInternal(dest, dest_len); - } - - /** - * Closes the queue. After calling this method, `Push` operations won't have any effect, and - * `PopMany` and `PopManyBlock` will start returning `QUEUE_CLOSED`. This is intended to allow - * a graceful shutdown of all consumers. - */ - void Close() { - std::unique_lock<std::mutex> lock(mutex); - closed = true; - // We need to wake up any reader that are waiting for an item that will never come. - lock.unlock(); - reader.notify_all(); - } - - /// Returns true if `Close()` has been called. - bool IsClosed() const { - return closed; - } - -private: - size_t PopInternal(T* dest, size_t dest_len) { - size_t output_count = 0; - while (output_count < dest_len && CanRead()) { - DEBUG_ASSERT(CanRead()); - - T* item = &Data()[reader_index]; - T out_val = std::move(*item); - item->~T(); - - size_t prev_index = (reader_index + ArraySize - 1) % ArraySize; - reader_index = (reader_index + 1) % ArraySize; - if (writer_index == prev_index) { - writer.notify_one(); - } - dest[output_count++] = std::move(out_val); - } - return output_count; - } - - bool CanRead() const { - return reader_index != writer_index; - } - - T* Data() { - return static_cast<T*>(static_cast<void*>(&storage)); - } - - /// Storage for entries - typename std::aligned_storage<ArraySize * sizeof(T), - std::alignment_of<T>::value>::type storage; - - /// Data is valid in the half-open interval [reader, writer). If they are `QUEUE_CLOSED` then the - /// queue has been closed. - size_t writer_index = 0, reader_index = 0; - // True if the queue has been closed. - bool closed = false; - - /// Mutex that protects the entire data structure. - std::mutex mutex; - /// Signaling wakes up reader which is waiting for storage to be non-empty. - std::condition_variable reader; - /// Signaling wakes up writer which is waiting for storage to be non-full. - std::condition_variable writer; -}; - -} // namespace diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 7d3534a43..bd2c6a153 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -3,17 +3,17 @@ // Refer to the license.txt file included. #include <algorithm> +#include <array> +#include <cstdio> -#include "common/assert.h" - +#include "common/common_funcs.h" // snprintf compatibility define #include "common/logging/backend.h" +#include "common/logging/filter.h" #include "common/logging/log.h" #include "common/logging/text_formatter.h" namespace Log { -static std::shared_ptr<Logger> global_logger; - /// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this. #define ALL_LOG_CLASSES() \ CLS(Log) \ @@ -55,28 +55,8 @@ static std::shared_ptr<Logger> global_logger; SUB(Render, OpenGL) \ CLS(Loader) -Logger::Logger() { - // Register logging classes so that they can be queried at runtime - size_t parent_class; - all_classes.reserve((size_t)Class::Count); - -#define CLS(x) \ - all_classes.push_back(Class::x); \ - parent_class = all_classes.size() - 1; -#define SUB(x, y) \ - all_classes.push_back(Class::x##_##y); \ - all_classes[parent_class].num_children += 1; - - ALL_LOG_CLASSES() -#undef CLS -#undef SUB - - // Ensures that ALL_LOG_CLASSES isn't missing any entries. - DEBUG_ASSERT(all_classes.size() == (size_t)Class::Count); -} - // GetClassName is a macro defined by Windows.h, grrr... -const char* Logger::GetLogClassName(Class log_class) { +const char* GetLogClassName(Class log_class) { switch (log_class) { #define CLS(x) case Class::x: return #x; #define SUB(x, y) case Class::x##_##y: return #x "." #y; @@ -87,7 +67,7 @@ const char* Logger::GetLogClassName(Class log_class) { return "Unknown"; } -const char* Logger::GetLevelName(Level log_level) { +const char* GetLevelName(Level log_level) { #define LVL(x) case Level::x: return #x switch (log_level) { LVL(Trace); @@ -101,19 +81,6 @@ const char* Logger::GetLevelName(Level log_level) { #undef LVL } -void Logger::LogMessage(Entry entry) { - ring_buffer.Push(std::move(entry)); -} - -size_t Logger::GetEntries(Entry* out_buffer, size_t buffer_len) { - return ring_buffer.BlockingPop(out_buffer, buffer_len); -} - -std::shared_ptr<Logger> InitGlobalLogger() { - global_logger = std::make_shared<Logger>(); - return global_logger; -} - Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr, const char* function, const char* format, va_list args) { @@ -138,7 +105,7 @@ Entry CreateEntry(Class log_class, Level log_level, return std::move(entry); } -static Filter* filter; +static Filter* filter = nullptr; void SetFilter(Filter* new_filter) { filter = new_filter; @@ -147,7 +114,7 @@ void SetFilter(Filter* new_filter) { void LogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_nr, const char* function, const char* format, ...) { - if (!filter->CheckMessage(log_class, log_level)) + if (filter != nullptr && !filter->CheckMessage(log_class, log_level)) return; va_list args; @@ -156,12 +123,7 @@ void LogMessage(Class log_class, Level log_level, filename, line_nr, function, format, args); va_end(args); - if (global_logger != nullptr && !global_logger->IsClosed()) { - global_logger->LogMessage(std::move(entry)); - } else { - // Fall back to directly printing to stderr - PrintMessage(entry); - } + PrintColoredMessage(entry); } } diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h index 3114f864c..c1f4d08e4 100644 --- a/src/common/logging/backend.h +++ b/src/common/logging/backend.h @@ -4,17 +4,17 @@ #pragma once +#include <chrono> #include <cstdarg> -#include <memory> -#include <vector> +#include <string> +#include <utility> -#include "common/concurrent_ring_buffer.h" - -#include "common/logging/filter.h" #include "common/logging/log.h" namespace Log { +class Filter; + /** * A log entry. Log entries are store in a structured format to permit more varied output * formatting on different frontends, as well as facilitating filtering and aggregation. @@ -48,89 +48,21 @@ struct Entry { } }; -struct ClassInfo { - Class log_class; - - /** - * Total number of (direct or indirect) sub classes this class has. If any, they follow in - * sequence after this class in the class list. - */ - unsigned int num_children = 0; - - ClassInfo(Class log_class) : log_class(log_class) {} -}; - /** - * Logging management class. This class has the dual purpose of acting as an exchange point between - * the logging clients and the log outputter, as well as containing reflection info about available - * log classes. + * Returns the name of the passed log class as a C-string. Subclasses are separated by periods + * instead of underscores as in the enumeration. */ -class Logger { -private: - using Buffer = Common::ConcurrentRingBuffer<Entry, 16 * 1024 / sizeof(Entry)>; - -public: - static const size_t QUEUE_CLOSED = Buffer::QUEUE_CLOSED; - - Logger(); - - /** - * Returns a list of all vector classes and subclasses. The sequence returned is a pre-order of - * classes and subclasses, which together with the `num_children` field in ClassInfo, allows - * you to recover the hierarchy. - */ - const std::vector<ClassInfo>& GetClasses() const { return all_classes; } +const char* GetLogClassName(Class log_class); - /** - * Returns the name of the passed log class as a C-string. Subclasses are separated by periods - * instead of underscores as in the enumeration. - */ - static const char* GetLogClassName(Class log_class); - - /** - * Returns the name of the passed log level as a C-string. - */ - static const char* GetLevelName(Level log_level); - - /** - * Appends a messages to the log buffer. - * @note This function is thread safe. - */ - void LogMessage(Entry entry); - - /** - * Retrieves a batch of messages from the log buffer, blocking until they are available. - * @note This function is thread safe. - * - * @param out_buffer Destination buffer that will receive the log entries. - * @param buffer_len The maximum size of `out_buffer`. - * @return The number of entries stored. In case the logger is shutting down, `QUEUE_CLOSED` is - * returned, no entries are stored and the logger should shutdown. - */ - size_t GetEntries(Entry* out_buffer, size_t buffer_len); - - /** - * Initiates a shutdown of the logger. This will indicate to log output clients that they - * should shutdown. - */ - void Close() { ring_buffer.Close(); } - - /** - * Returns true if Close() has already been called on the Logger. - */ - bool IsClosed() const { return ring_buffer.IsClosed(); } - -private: - Buffer ring_buffer; - std::vector<ClassInfo> all_classes; -}; +/** + * Returns the name of the passed log level as a C-string. + */ +const char* GetLevelName(Level log_level); /// Creates a log entry by formatting the given source location, and message. Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr, const char* function, const char* format, va_list args); -/// Initializes the default Logger. -std::shared_ptr<Logger> InitGlobalLogger(); void SetFilter(Filter* filter); diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index 50f2e13f4..55cc8888a 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp @@ -22,16 +22,6 @@ void Filter::SetClassLevel(Class log_class, Level level) { class_levels[static_cast<size_t>(log_class)] = level; } -void Filter::SetSubclassesLevel(const ClassInfo& log_class, Level level) { - const size_t log_class_i = static_cast<size_t>(log_class.log_class); - - const size_t begin = log_class_i + 1; - const size_t end = begin + log_class.num_children; - for (size_t i = begin; begin < end; ++i) { - class_levels[i] = level; - } -} - void Filter::ParseFilterString(const std::string& filter_str) { auto clause_begin = filter_str.cbegin(); while (clause_begin != filter_str.cend()) { @@ -53,7 +43,7 @@ void Filter::ParseFilterString(const std::string& filter_str) { template <typename It> static Level GetLevelByName(const It begin, const It end) { for (u8 i = 0; i < static_cast<u8>(Level::Count); ++i) { - const char* level_name = Logger::GetLevelName(static_cast<Level>(i)); + const char* level_name = GetLevelName(static_cast<Level>(i)); if (Common::ComparePartialString(begin, end, level_name)) { return static_cast<Level>(i); } @@ -64,7 +54,7 @@ static Level GetLevelByName(const It begin, const It end) { template <typename It> static Class GetClassByName(const It begin, const It end) { for (ClassType i = 0; i < static_cast<ClassType>(Class::Count); ++i) { - const char* level_name = Logger::GetLogClassName(static_cast<Class>(i)); + const char* level_name = GetLogClassName(static_cast<Class>(i)); if (Common::ComparePartialString(begin, end, level_name)) { return static_cast<Class>(i); } @@ -72,20 +62,6 @@ static Class GetClassByName(const It begin, const It end) { return Class::Count; } -template <typename InputIt, typename T> -static InputIt find_last(InputIt begin, const InputIt end, const T& value) { - auto match = end; - while (begin != end) { - auto new_match = std::find(begin, end, value); - if (new_match != end) { - match = new_match; - ++new_match; - } - begin = new_match; - } - return match; -} - bool Filter::ParseFilterRule(const std::string::const_iterator begin, const std::string::const_iterator end) { auto level_separator = std::find(begin, end, ':'); @@ -106,22 +82,13 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin, return true; } - auto class_name_end = find_last(begin, level_separator, '.'); - if (class_name_end != level_separator && - !Common::ComparePartialString(class_name_end + 1, level_separator, "*")) { - class_name_end = level_separator; - } - - const Class log_class = GetClassByName(begin, class_name_end); + const Class log_class = GetClassByName(begin, level_separator); if (log_class == Class::Count) { LOG_ERROR(Log, "Unknown log class in filter: %s", std::string(begin, end).c_str()); return false; } - if (class_name_end == level_separator) { - SetClassLevel(log_class, level); - } - SetSubclassesLevel(log_class, level); + SetClassLevel(log_class, level); return true; } diff --git a/src/common/logging/filter.h b/src/common/logging/filter.h index b53e4e633..0b71ea3b2 100644 --- a/src/common/logging/filter.h +++ b/src/common/logging/filter.h @@ -11,8 +11,6 @@ namespace Log { -struct ClassInfo; - /** * Implements a log message filter which allows different log classes to have different minimum * severity levels. The filter can be changed at runtime and can be parsed from a string to allow @@ -27,29 +25,19 @@ public: void ResetAll(Level level); /// Sets the minimum level of `log_class` (and not of its subclasses) to `level`. void SetClassLevel(Class log_class, Level level); - /** - * Sets the minimum level of all of `log_class` subclasses to `level`. The level of `log_class` - * itself is not changed. - */ - void SetSubclassesLevel(const ClassInfo& log_class, Level level); /** * Parses a filter string and applies it to this filter. * * A filter string consists of a space-separated list of filter rules, each of the format * `<class>:<level>`. `<class>` is a log class name, with subclasses separated using periods. - * A rule for a given class also affects all of its subclasses. `*` wildcards are allowed and - * can be used to apply a rule to all classes or to all subclasses of a class without affecting - * the parent class. `<level>` a severity level name which will be set as the minimum logging - * level of the matched classes. Rules are applied left to right, with each rule overriding - * previous ones in the sequence. + * `*` is allowed as a class name and will reset all filters to the specified level. `<level>` + * a severity level name which will be set as the minimum logging level of the matched classes. + * Rules are applied left to right, with each rule overriding previous ones in the sequence. * * A few examples of filter rules: * - `*:Info` -- Resets the level of all classes to Info. - * - `Service:Info` -- Sets the level of Service and all subclasses (Service.FS, Service.APT, - * etc.) to Info. - * - `Service.*:Debug` -- Sets the level of all Service subclasses to Debug, while leaving the - * level of Service unchanged. + * - `Service:Info` -- Sets the level of Service to Info. * - `Service.FS:Trace` -- Sets the level of the Service.FS class to Trace. */ void ParseFilterString(const std::string& filter_str); diff --git a/src/common/logging/log.h b/src/common/logging/log.h index 123641cb4..fd87ddbe6 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h @@ -78,11 +78,7 @@ enum class Class : ClassType { Count ///< Total number of logging classes }; -/** - * Logs a message to the global logger. This proxy exists to avoid exposing the details of the - * Logger class, including the ConcurrentRingBuffer template, to all files that desire to log - * messages, reducing unecessary recompilations. - */ +/// Logs a message to the global logger. void LogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_nr, const char* function, #ifdef _MSC_VER diff --git a/src/common/logging/text_formatter.cpp b/src/common/logging/text_formatter.cpp index 45be6d0a1..94f3dfc1f 100644 --- a/src/common/logging/text_formatter.cpp +++ b/src/common/logging/text_formatter.cpp @@ -46,8 +46,8 @@ void FormatLogMessage(const Entry& entry, char* out_text, size_t text_len) { unsigned int time_seconds = static_cast<unsigned int>(entry.timestamp.count() / 1000000); unsigned int time_fractional = static_cast<unsigned int>(entry.timestamp.count() % 1000000); - const char* class_name = Logger::GetLogClassName(entry.log_class); - const char* level_name = Logger::GetLevelName(entry.log_level); + const char* class_name = GetLogClassName(entry.log_class); + const char* level_name = GetLevelName(entry.log_level); snprintf(out_text, text_len, "[%4u.%06u] %s <%s> %s: %s", time_seconds, time_fractional, class_name, level_name, @@ -116,19 +116,4 @@ void PrintColoredMessage(const Entry& entry) { #endif } -void TextLoggingLoop(std::shared_ptr<Logger> logger) { - std::array<Entry, 256> entry_buffer; - - while (true) { - size_t num_entries = logger->GetEntries(entry_buffer.data(), entry_buffer.size()); - if (num_entries == Logger::QUEUE_CLOSED) { - break; - } - for (size_t i = 0; i < num_entries; ++i) { - const Entry& entry = entry_buffer[i]; - PrintColoredMessage(entry); - } - } -} - } diff --git a/src/common/logging/text_formatter.h b/src/common/logging/text_formatter.h index 8474a1904..5b82f043f 100644 --- a/src/common/logging/text_formatter.h +++ b/src/common/logging/text_formatter.h @@ -5,11 +5,9 @@ #pragma once #include <cstddef> -#include <memory> namespace Log { -class Logger; struct Entry; /** @@ -31,10 +29,4 @@ void PrintMessage(const Entry& entry); /// Prints the same message as `PrintMessage`, but colored acoording to the severity level. void PrintColoredMessage(const Entry& entry); -/** - * Logging loop that repeatedly reads messages from the provided logger and prints them to the - * console. It is the baseline barebones log outputter. - */ -void TextLoggingLoop(std::shared_ptr<Logger> logger); - } diff --git a/src/common/math_util.cpp b/src/common/math_util.cpp deleted file mode 100644 index bcb70cae5..000000000 --- a/src/common/math_util.cpp +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <cstring> -#include <numeric> // Necessary on OS X, but not Linux - -#include "common/common_types.h" -#include "common/math_util.h" - -namespace MathUtil -{ - -u32 ClassifyDouble(double dvalue) -{ - // TODO: Optimize the below to be as fast as possible. - IntDouble value; - value.d = dvalue; - u64 sign = value.i & DOUBLE_SIGN; - u64 exp = value.i & DOUBLE_EXP; - if (exp > DOUBLE_ZERO && exp < DOUBLE_EXP) - { - // Nice normalized number. - return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN; - } - else - { - u64 mantissa = value.i & DOUBLE_FRAC; - if (mantissa) - { - if (exp) - { - return PPC_FPCLASS_QNAN; - } - else - { - // Denormalized number. - return sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD; - } - } - else if (exp) - { - //Infinite - return sign ? PPC_FPCLASS_NINF : PPC_FPCLASS_PINF; - } - else - { - //Zero - return sign ? PPC_FPCLASS_NZ : PPC_FPCLASS_PZ; - } - } -} - -u32 ClassifyFloat(float fvalue) -{ - // TODO: Optimize the below to be as fast as possible. - IntFloat value; - value.f = fvalue; - u32 sign = value.i & FLOAT_SIGN; - u32 exp = value.i & FLOAT_EXP; - if (exp > FLOAT_ZERO && exp < FLOAT_EXP) - { - // Nice normalized number. - return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN; - } - else - { - u32 mantissa = value.i & FLOAT_FRAC; - if (mantissa) - { - if (exp) - { - return PPC_FPCLASS_QNAN; // Quiet NAN - } - else - { - // Denormalized number. - return sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD; - } - } - else if (exp) - { - // Infinite - return sign ? PPC_FPCLASS_NINF : PPC_FPCLASS_PINF; - } - else - { - //Zero - return sign ? PPC_FPCLASS_NZ : PPC_FPCLASS_PZ; - } - } -} - - -} // namespace - -inline void MatrixMul(int n, const float *a, const float *b, float *result) -{ - for (int i = 0; i < n; ++i) - { - for (int j = 0; j < n; ++j) - { - float temp = 0; - for (int k = 0; k < n; ++k) - { - temp += a[i * n + k] * b[k * n + j]; - } - result[i * n + j] = temp; - } - } -} - -// Calculate sum of a float list -float MathFloatVectorSum(const std::vector<float>& Vec) -{ - return std::accumulate(Vec.begin(), Vec.end(), 0.0f); -} - -void Matrix33::LoadIdentity(Matrix33 &mtx) -{ - memset(mtx.data, 0, sizeof(mtx.data)); - mtx.data[0] = 1.0f; - mtx.data[4] = 1.0f; - mtx.data[8] = 1.0f; -} - -void Matrix33::RotateX(Matrix33 &mtx, float rad) -{ - float s = sin(rad); - float c = cos(rad); - memset(mtx.data, 0, sizeof(mtx.data)); - mtx.data[0] = 1; - mtx.data[4] = c; - mtx.data[5] = -s; - mtx.data[7] = s; - mtx.data[8] = c; -} -void Matrix33::RotateY(Matrix33 &mtx, float rad) -{ - float s = sin(rad); - float c = cos(rad); - memset(mtx.data, 0, sizeof(mtx.data)); - mtx.data[0] = c; - mtx.data[2] = s; - mtx.data[4] = 1; - mtx.data[6] = -s; - mtx.data[8] = c; -} - -void Matrix33::Multiply(const Matrix33 &a, const Matrix33 &b, Matrix33 &result) -{ - MatrixMul(3, a.data, b.data, result.data); -} - -void Matrix33::Multiply(const Matrix33 &a, const float vec[3], float result[3]) -{ - for (int i = 0; i < 3; ++i) { - result[i] = 0; - for (int k = 0; k < 3; ++k) { - result[i] += a.data[i * 3 + k] * vec[k]; - } - } -} - -void Matrix44::LoadIdentity(Matrix44 &mtx) -{ - memset(mtx.data, 0, sizeof(mtx.data)); - mtx.data[0] = 1.0f; - mtx.data[5] = 1.0f; - mtx.data[10] = 1.0f; - mtx.data[15] = 1.0f; -} - -void Matrix44::LoadMatrix33(Matrix44 &mtx, const Matrix33 &m33) -{ - for (int i = 0; i < 3; ++i) - { - for (int j = 0; j < 3; ++j) - { - mtx.data[i * 4 + j] = m33.data[i * 3 + j]; - } - } - - for (int i = 0; i < 3; ++i) - { - mtx.data[i * 4 + 3] = 0; - mtx.data[i + 12] = 0; - } - mtx.data[15] = 1.0f; -} - -void Matrix44::Set(Matrix44 &mtx, const float mtxArray[16]) -{ - for(int i = 0; i < 16; ++i) { - mtx.data[i] = mtxArray[i]; - } -} - -void Matrix44::Translate(Matrix44 &mtx, const float vec[3]) -{ - LoadIdentity(mtx); - mtx.data[3] = vec[0]; - mtx.data[7] = vec[1]; - mtx.data[11] = vec[2]; -} - -void Matrix44::Multiply(const Matrix44 &a, const Matrix44 &b, Matrix44 &result) -{ - MatrixMul(4, a.data, b.data, result.data); -} - diff --git a/src/common/math_util.h b/src/common/math_util.h index 52f579cf7..0b1400b41 100644 --- a/src/common/math_util.h +++ b/src/common/math_util.h @@ -4,11 +4,9 @@ #pragma once -#include "common/common_types.h" - #include <algorithm> +#include <cstdlib> #include <type_traits> -#include <vector> namespace MathUtil { @@ -19,83 +17,6 @@ inline T Clamp(const T val, const T& min, const T& max) return std::max(min, std::min(max, val)); } -static const u64 DOUBLE_SIGN = 0x8000000000000000ULL, - DOUBLE_EXP = 0x7FF0000000000000ULL, - DOUBLE_FRAC = 0x000FFFFFFFFFFFFFULL, - DOUBLE_ZERO = 0x0000000000000000ULL; - -static const u32 FLOAT_SIGN = 0x80000000, - FLOAT_EXP = 0x7F800000, - FLOAT_FRAC = 0x007FFFFF, - FLOAT_ZERO = 0x00000000; - -union IntDouble { - double d; - u64 i; -}; -union IntFloat { - float f; - u32 i; -}; - -inline bool IsNAN(double d) -{ - IntDouble x; x.d = d; - return ( ((x.i & DOUBLE_EXP) == DOUBLE_EXP) && - ((x.i & DOUBLE_FRAC) != DOUBLE_ZERO) ); -} - -inline bool IsQNAN(double d) -{ - IntDouble x; x.d = d; - return ( ((x.i & DOUBLE_EXP) == DOUBLE_EXP) && - ((x.i & 0x0007fffffffffffULL) == 0x000000000000000ULL) && - ((x.i & 0x000800000000000ULL) == 0x000800000000000ULL) ); -} - -inline bool IsSNAN(double d) -{ - IntDouble x; x.d = d; - return( ((x.i & DOUBLE_EXP) == DOUBLE_EXP) && - ((x.i & DOUBLE_FRAC) != DOUBLE_ZERO) && - ((x.i & 0x0008000000000000ULL) == DOUBLE_ZERO) ); -} - -inline float FlushToZero(float f) -{ - IntFloat x; x.f = f; - if ((x.i & FLOAT_EXP) == 0) - x.i &= FLOAT_SIGN; // turn into signed zero - return x.f; -} - -inline double FlushToZeroAsFloat(double d) -{ - IntDouble x; x.d = d; - if ((x.i & DOUBLE_EXP) < 0x3800000000000000ULL) - x.i &= DOUBLE_SIGN; // turn into signed zero - return x.d; -} - -enum PPCFpClass -{ - PPC_FPCLASS_QNAN = 0x11, - PPC_FPCLASS_NINF = 0x9, - PPC_FPCLASS_NN = 0x8, - PPC_FPCLASS_ND = 0x18, - PPC_FPCLASS_NZ = 0x12, - PPC_FPCLASS_PZ = 0x2, - PPC_FPCLASS_PD = 0x14, - PPC_FPCLASS_PN = 0x4, - PPC_FPCLASS_PINF = 0x5, -}; - -// Uses PowerPC conventions for the return value, so it can be easily -// used directly in CPU emulation. -u32 ClassifyDouble(double dvalue); -// More efficient float version. -u32 ClassifyFloat(float fvalue); - template<class T> struct Rectangle { @@ -104,101 +25,12 @@ struct Rectangle T right; T bottom; - Rectangle() - { } + Rectangle() {} - Rectangle(T theLeft, T theTop, T theRight, T theBottom) - : left(theLeft), top(theTop), right(theRight), bottom(theBottom) - { } - - bool operator==(const Rectangle& r) { return left==r.left && top==r.top && right==r.right && bottom==r.bottom; } + Rectangle(T left, T top, T right, T bottom) : left(left), top(top), right(right), bottom(bottom) {} T GetWidth() const { return std::abs(static_cast<typename std::make_signed<T>::type>(right - left)); } T GetHeight() const { return std::abs(static_cast<typename std::make_signed<T>::type>(bottom - top)); } - - // If the rectangle is in a coordinate system with a lower-left origin, use - // this Clamp. - void ClampLL(T x1, T y1, T x2, T y2) - { - if (left < x1) left = x1; - if (right > x2) right = x2; - if (top > y1) top = y1; - if (bottom < y2) bottom = y2; - } - - // If the rectangle is in a coordinate system with an upper-left origin, - // use this Clamp. - void ClampUL(T x1, T y1, T x2, T y2) - { - if (left < x1) left = x1; - if (right > x2) right = x2; - if (top < y1) top = y1; - if (bottom > y2) bottom = y2; - } }; } // namespace MathUtil - -inline float pow2f(float x) {return x * x;} -inline double pow2(double x) {return x * x;} - -float MathFloatVectorSum(const std::vector<float>&); - -#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) -#define ROUND_DOWN(x, a) ((x) & ~((a) - 1)) - -// Rounds down. 0 -> undefined -inline u64 Log2(u64 val) -{ -#if defined(__GNUC__) - return 63 - __builtin_clzll(val); - -#elif defined(_MSC_VER) && defined(_M_X64) - unsigned long result = -1; - _BitScanReverse64(&result, val); - return result; - -#else - u64 result = -1; - while (val != 0) - { - val >>= 1; - ++result; - } - return result; -#endif -} - -// Tiny matrix/vector library. -// Used for things like Free-Look in the gfx backend. - -class Matrix33 -{ -public: - static void LoadIdentity(Matrix33 &mtx); - - // set mtx to be a rotation matrix around the x axis - static void RotateX(Matrix33 &mtx, float rad); - // set mtx to be a rotation matrix around the y axis - static void RotateY(Matrix33 &mtx, float rad); - - // set result = a x b - static void Multiply(const Matrix33 &a, const Matrix33 &b, Matrix33 &result); - static void Multiply(const Matrix33 &a, const float vec[3], float result[3]); - - float data[9]; -}; - -class Matrix44 -{ -public: - static void LoadIdentity(Matrix44 &mtx); - static void LoadMatrix33(Matrix44 &mtx, const Matrix33 &m33); - static void Set(Matrix44 &mtx, const float mtxArray[16]); - - static void Translate(Matrix44 &mtx, const float vec[3]); - - static void Multiply(const Matrix44 &a, const Matrix44 &b, Matrix44 &result); - - float data[16]; -}; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ebedcb710..5caaee474 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -30,6 +30,7 @@ set(SRCS hle/kernel/kernel.cpp hle/kernel/mutex.cpp hle/kernel/process.cpp + hle/kernel/resource_limit.cpp hle/kernel/semaphore.cpp hle/kernel/session.cpp hle/kernel/shared_memory.cpp @@ -99,7 +100,7 @@ set(SRCS loader/loader.cpp loader/ncch.cpp mem_map.cpp - mem_map_funcs.cpp + memory.cpp settings.cpp system.cpp ) @@ -141,6 +142,7 @@ set(HEADERS hle/kernel/kernel.h hle/kernel/mutex.h hle/kernel/process.h + hle/kernel/resource_limit.h hle/kernel/semaphore.h hle/kernel/session.h hle/kernel/shared_memory.h @@ -211,6 +213,8 @@ set(HEADERS loader/loader.h loader/ncch.h mem_map.h + memory.h + memory_setup.h settings.h system.h ) diff --git a/src/core/arm/dyncom/arm_dyncom_dec.cpp b/src/core/arm/dyncom/arm_dyncom_dec.cpp index 12181d0ec..3887189f1 100644 --- a/src/core/arm/dyncom/arm_dyncom_dec.cpp +++ b/src/core/arm/dyncom/arm_dyncom_dec.cpp @@ -181,7 +181,11 @@ const ISEITEM arm_instruction[] = { { "ldrt", 3, 0, 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000003 }, { "mrc", 3, 6, 24, 27, 0x0000000e, 20, 20, 0x00000001, 4, 4, 0x00000001 }, { "mcr", 3, 0, 24, 27, 0x0000000e, 20, 20, 0x00000000, 4, 4, 0x00000001 }, - { "msr", 2, 0, 23, 27, 0x00000006, 20, 21, 0x00000002 }, + { "msr", 3, 0, 23, 27, 0x00000006, 20, 21, 0x00000002, 22, 22, 0x00000001 }, + { "msr", 4, 0, 23, 27, 0x00000006, 20, 21, 0x00000002, 22, 22, 0x00000000, 16, 19, 0x00000004 }, + { "msr", 5, 0, 23, 27, 0x00000006, 20, 21, 0x00000002, 22, 22, 0x00000000, 19, 19, 0x00000001, 16, 17, 0x00000000 }, + { "msr", 4, 0, 23, 27, 0x00000006, 20, 21, 0x00000002, 22, 22, 0x00000000, 16, 17, 0x00000001 }, + { "msr", 4, 0, 23, 27, 0x00000006, 20, 21, 0x00000002, 22, 22, 0x00000000, 17, 17, 0x00000001 }, { "ldrb", 3, 0, 26, 27, 0x00000001, 22, 22, 0x00000001, 20, 20, 0x00000001 }, { "strb", 3, 0, 26, 27, 0x00000001, 22, 22, 0x00000001, 20, 20, 0x00000000 }, { "ldr", 4, 0, 28, 31, 0x0000000e, 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000001 }, @@ -190,12 +194,17 @@ const ISEITEM arm_instruction[] = { { "cdp", 2, 0, 24, 27, 0x0000000e, 4, 4, 0x00000000 }, { "stc", 2, 0, 25, 27, 0x00000006, 20, 20, 0x00000000 }, { "ldc", 2, 0, 25, 27, 0x00000006, 20, 20, 0x00000001 }, - { "swi", 1, 0, 24, 27, 0x0000000f }, - { "bbl", 1, 0, 25, 27, 0x00000005 }, { "ldrexd", 2, ARMV6K, 20, 27, 0x0000001B, 4, 7, 0x00000009 }, { "strexd", 2, ARMV6K, 20, 27, 0x0000001A, 4, 7, 0x00000009 }, { "ldrexh", 2, ARMV6K, 20, 27, 0x0000001F, 4, 7, 0x00000009 }, { "strexh", 2, ARMV6K, 20, 27, 0x0000001E, 4, 7, 0x00000009 }, + { "nop", 5, ARMV6K, 23, 27, 0x00000006, 22, 22, 0x00000000, 20, 21, 0x00000002, 16, 19, 0x00000000, 0, 7, 0x00000000 }, + { "yield", 5, ARMV6K, 23, 27, 0x00000006, 22, 22, 0x00000000, 20, 21, 0x00000002, 16, 19, 0x00000000, 0, 7, 0x00000001 }, + { "wfe", 5, ARMV6K, 23, 27, 0x00000006, 22, 22, 0x00000000, 20, 21, 0x00000002, 16, 19, 0x00000000, 0, 7, 0x00000002 }, + { "wfi", 5, ARMV6K, 23, 27, 0x00000006, 22, 22, 0x00000000, 20, 21, 0x00000002, 16, 19, 0x00000000, 0, 7, 0x00000003 }, + { "sev", 5, ARMV6K, 23, 27, 0x00000006, 22, 22, 0x00000000, 20, 21, 0x00000002, 16, 19, 0x00000000, 0, 7, 0x00000004 }, + { "swi", 1, 0, 24, 27, 0x0000000f }, + { "bbl", 1, 0, 25, 27, 0x00000005 }, }; const ISEITEM arm_exclusion_code[] = { @@ -375,6 +384,10 @@ const ISEITEM arm_exclusion_code[] = { { "mrc", 0, 6, 0 }, { "mcr", 0, 0, 0 }, { "msr", 0, 0, 0 }, + { "msr", 0, 0, 0 }, + { "msr", 0, 0, 0 }, + { "msr", 0, 0, 0 }, + { "msr", 0, 0, 0 }, { "ldrb", 0, 0, 0 }, { "strb", 0, 0, 0 }, { "ldr", 0, 0, 0 }, @@ -383,12 +396,17 @@ const ISEITEM arm_exclusion_code[] = { { "cdp", 0, 0, 0 }, { "stc", 0, 0, 0 }, { "ldc", 0, 0, 0 }, - { "swi", 0, 0, 0 }, - { "bbl", 0, 0, 0 }, { "ldrexd", 0, ARMV6K, 0 }, { "strexd", 0, ARMV6K, 0 }, { "ldrexh", 0, ARMV6K, 0 }, { "strexh", 0, ARMV6K, 0 }, + { "nop", 0, ARMV6K, 0 }, + { "yield", 0, ARMV6K, 0 }, + { "wfe", 0, ARMV6K, 0 }, + { "wfi", 0, ARMV6K, 0 }, + { "sev", 0, ARMV6K, 0 }, + { "swi", 0, 0, 0 }, + { "bbl", 0, 0, 0 }, { "bl_1_thumb", 0, INVALID, 0 }, // Should be table[-4] { "bl_2_thumb", 0, INVALID, 0 }, // Should be located at the end of the table[-3] diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index 315b4cc91..66282a7e6 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -10,9 +10,10 @@ #include "common/logging/log.h" #include "common/profiler.h" -#include "core/mem_map.h" +#include "core/memory.h" #include "core/hle/svc.h" #include "core/arm/disassembler/arm_disasm.h" +#include "core/arm/dyncom/arm_dyncom_dec.h" #include "core/arm/dyncom/arm_dyncom_interpreter.h" #include "core/arm/dyncom/arm_dyncom_thumb.h" #include "core/arm/dyncom/arm_dyncom_run.h" @@ -68,6 +69,67 @@ static void remove_exclusive(ARMul_State* state, ARMword addr){ state->exclusive_tag = 0xFFFFFFFF; } +static int CondPassed(ARMul_State* cpu, unsigned int cond) { + const u32 NFLAG = cpu->NFlag; + const u32 ZFLAG = cpu->ZFlag; + const u32 CFLAG = cpu->CFlag; + const u32 VFLAG = cpu->VFlag; + + int temp = 0; + + switch (cond) { + case 0x0: + temp = ZFLAG; + break; + case 0x1: // NE + temp = !ZFLAG; + break; + case 0x2: // CS + temp = CFLAG; + break; + case 0x3: // CC + temp = !CFLAG; + break; + case 0x4: // MI + temp = NFLAG; + break; + case 0x5: // PL + temp = !NFLAG; + break; + case 0x6: // VS + temp = VFLAG; + break; + case 0x7: // VC + temp = !VFLAG; + break; + case 0x8: // HI + temp = (CFLAG && !ZFLAG); + break; + case 0x9: // LS + temp = (!CFLAG || ZFLAG); + break; + case 0xa: // GE + temp = ((!NFLAG && !VFLAG) || (NFLAG && VFLAG)); + break; + case 0xb: // LT + temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)); + break; + case 0xc: // GT + temp = ((!NFLAG && !VFLAG && !ZFLAG) || (NFLAG && VFLAG && !ZFLAG)); + break; + case 0xd: // LE + temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) || ZFLAG; + break; + case 0xe: // AL + temp = 1; + break; + case 0xf: + temp = 1; + break; + } + return temp; +} + static unsigned int DPO(Immediate)(ARMul_State* cpu, unsigned int sht_oper) { unsigned int immed_8 = BITS(sht_oper, 0, 7); unsigned int rotate_imm = BITS(sht_oper, 8, 11); @@ -224,14 +286,12 @@ static unsigned int DPO(RotateRightByRegister)(ARMul_State* cpu, unsigned int sh typedef void (*get_addr_fp_t)(ARMul_State *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int rw); -typedef struct _ldst_inst { +struct ldst_inst { unsigned int inst; get_addr_fp_t get_addr; -} ldst_inst; +}; #define DEBUG_MSG LOG_DEBUG(Core_ARM11, "inst is %x", inst); CITRA_IGNORE_EXIT(0) -int CondPassed(ARMul_State* cpu, unsigned int cond); - #define LnSWoUB(s) glue(LnSWoUB, s) #define MLnS(s) glue(MLnS, s) #define LdnStM(s) glue(LdnStM, s) @@ -647,255 +707,248 @@ static void LnSWoUB(ScaledRegisterOffset)(ARMul_State* cpu, unsigned int inst, u virt_addr = addr; } -typedef struct _arm_inst { +struct arm_inst { unsigned int idx; unsigned int cond; int br; int load_r15; char component[0]; -} arm_inst; +}; -typedef struct generic_arm_inst { +struct generic_arm_inst { u32 Ra; u32 Rm; u32 Rn; u32 Rd; u8 op1; u8 op2; -} generic_arm_inst; +}; -typedef struct _adc_inst { +struct adc_inst { unsigned int I; unsigned int S; unsigned int Rn; unsigned int Rd; unsigned int shifter_operand; shtop_fp_t shtop_func; -} adc_inst; +}; -typedef struct _add_inst { +struct add_inst { unsigned int I; unsigned int S; unsigned int Rn; unsigned int Rd; unsigned int shifter_operand; shtop_fp_t shtop_func; -} add_inst; +}; -typedef struct _orr_inst { +struct orr_inst { unsigned int I; unsigned int S; unsigned int Rn; unsigned int Rd; unsigned int shifter_operand; shtop_fp_t shtop_func; -} orr_inst; +}; -typedef struct _and_inst { +struct and_inst { unsigned int I; unsigned int S; unsigned int Rn; unsigned int Rd; unsigned int shifter_operand; shtop_fp_t shtop_func; -} and_inst; +}; -typedef struct _eor_inst { +struct eor_inst { unsigned int I; unsigned int S; unsigned int Rn; unsigned int Rd; unsigned int shifter_operand; shtop_fp_t shtop_func; -} eor_inst; +}; -typedef struct _bbl_inst { +struct bbl_inst { unsigned int L; int signed_immed_24; unsigned int next_addr; unsigned int jmp_addr; -} bbl_inst; +}; -typedef struct _bx_inst { +struct bx_inst { unsigned int Rm; -} bx_inst; +}; -typedef struct _blx_inst { +struct blx_inst { union { int32_t signed_immed_24; uint32_t Rm; } val; unsigned int inst; -} blx_inst; +}; -typedef struct _clz_inst { +struct clz_inst { unsigned int Rm; unsigned int Rd; -} clz_inst; +}; -typedef struct _cps_inst { +struct cps_inst { unsigned int imod0; unsigned int imod1; unsigned int mmod; unsigned int A, I, F; unsigned int mode; -} cps_inst; +}; -typedef struct _clrex_inst { -} clrex_inst; +struct clrex_inst { +}; -typedef struct _cpy_inst { +struct cpy_inst { unsigned int Rm; unsigned int Rd; -} cpy_inst; +}; -typedef struct _bic_inst { +struct bic_inst { unsigned int I; unsigned int S; unsigned int Rn; unsigned int Rd; unsigned int shifter_operand; shtop_fp_t shtop_func; -} bic_inst; +}; -typedef struct _sub_inst { +struct sub_inst { unsigned int I; unsigned int S; unsigned int Rn; unsigned int Rd; unsigned int shifter_operand; shtop_fp_t shtop_func; -} sub_inst; +}; -typedef struct _tst_inst { +struct tst_inst { unsigned int I; unsigned int S; unsigned int Rn; unsigned int Rd; unsigned int shifter_operand; shtop_fp_t shtop_func; -} tst_inst; +}; -typedef struct _cmn_inst { +struct cmn_inst { unsigned int I; unsigned int Rn; unsigned int shifter_operand; shtop_fp_t shtop_func; -} cmn_inst; +}; -typedef struct _teq_inst { +struct teq_inst { unsigned int I; unsigned int Rn; unsigned int shifter_operand; shtop_fp_t shtop_func; -} teq_inst; +}; -typedef struct _stm_inst { +struct stm_inst { unsigned int inst; -} stm_inst; +}; struct bkpt_inst { u32 imm; }; -struct blx1_inst { - unsigned int addr; +struct stc_inst { }; -struct blx2_inst { - unsigned int Rm; +struct ldc_inst { }; -typedef struct _stc_inst { -} stc_inst; - -typedef struct _ldc_inst { -} ldc_inst; - -typedef struct _swi_inst { +struct swi_inst { unsigned int num; -} swi_inst; +}; -typedef struct _cmp_inst { +struct cmp_inst { unsigned int I; unsigned int Rn; unsigned int shifter_operand; shtop_fp_t shtop_func; -} cmp_inst; +}; -typedef struct _mov_inst { +struct mov_inst { unsigned int I; unsigned int S; unsigned int Rd; unsigned int shifter_operand; shtop_fp_t shtop_func; -} mov_inst; +}; -typedef struct _mvn_inst { +struct mvn_inst { unsigned int I; unsigned int S; unsigned int Rd; unsigned int shifter_operand; shtop_fp_t shtop_func; -} mvn_inst; +}; -typedef struct _rev_inst { +struct rev_inst { unsigned int Rd; unsigned int Rm; unsigned int op1; unsigned int op2; -} rev_inst; +}; -typedef struct _rsb_inst { +struct rsb_inst { unsigned int I; unsigned int S; unsigned int Rn; unsigned int Rd; unsigned int shifter_operand; shtop_fp_t shtop_func; -} rsb_inst; +}; -typedef struct _rsc_inst { +struct rsc_inst { unsigned int I; unsigned int S; unsigned int Rn; unsigned int Rd; unsigned int shifter_operand; shtop_fp_t shtop_func; -} rsc_inst; +}; -typedef struct _sbc_inst { +struct sbc_inst { unsigned int I; unsigned int S; unsigned int Rn; unsigned int Rd; unsigned int shifter_operand; shtop_fp_t shtop_func; -} sbc_inst; +}; -typedef struct _mul_inst { +struct mul_inst { unsigned int S; unsigned int Rd; unsigned int Rs; unsigned int Rm; -} mul_inst; +}; -typedef struct _smul_inst { +struct smul_inst { unsigned int Rd; unsigned int Rs; unsigned int Rm; unsigned int x; unsigned int y; -} smul_inst; +}; -typedef struct _umull_inst { +struct umull_inst { unsigned int S; unsigned int RdHi; unsigned int RdLo; unsigned int Rs; unsigned int Rm; -} umull_inst; -typedef struct _smlad_inst { +}; + +struct smlad_inst { unsigned int m; unsigned int Rm; unsigned int Rd; @@ -903,58 +956,58 @@ typedef struct _smlad_inst { unsigned int Rn; unsigned int op1; unsigned int op2; -} smlad_inst; +}; -typedef struct _smla_inst { +struct smla_inst { unsigned int x; unsigned int y; unsigned int Rm; unsigned int Rd; unsigned int Rs; unsigned int Rn; -} smla_inst; +}; -typedef struct smlalxy_inst { +struct smlalxy_inst { unsigned int x; unsigned int y; unsigned int RdLo; unsigned int RdHi; unsigned int Rm; unsigned int Rn; -} smlalxy_inst; +}; -typedef struct ssat_inst { +struct ssat_inst { unsigned int Rn; unsigned int Rd; unsigned int imm5; unsigned int sat_imm; unsigned int shift_type; -} ssat_inst; +}; -typedef struct umaal_inst { +struct umaal_inst { unsigned int Rn; unsigned int Rm; unsigned int RdHi; unsigned int RdLo; -} umaal_inst; +}; -typedef struct _umlal_inst { +struct umlal_inst { unsigned int S; unsigned int Rm; unsigned int Rs; unsigned int RdHi; unsigned int RdLo; -} umlal_inst; +}; -typedef struct _smlal_inst { +struct smlal_inst { unsigned int S; unsigned int Rm; unsigned int Rs; unsigned int RdHi; unsigned int RdLo; -} smlal_inst; +}; -typedef struct smlald_inst { +struct smlald_inst { unsigned int RdLo; unsigned int RdHi; unsigned int Rm; @@ -962,17 +1015,17 @@ typedef struct smlald_inst { unsigned int swap; unsigned int op1; unsigned int op2; -} smlald_inst; +}; -typedef struct _mla_inst { +struct mla_inst { unsigned int S; unsigned int Rn; unsigned int Rd; unsigned int Rs; unsigned int Rm; -} mla_inst; +}; -typedef struct _mrc_inst { +struct mrc_inst { unsigned int opcode_1; unsigned int opcode_2; unsigned int cp_num; @@ -980,9 +1033,9 @@ typedef struct _mrc_inst { unsigned int crm; unsigned int Rd; unsigned int inst; -} mrc_inst; +}; -typedef struct _mcr_inst { +struct mcr_inst { unsigned int opcode_1; unsigned int opcode_2; unsigned int cp_num; @@ -990,77 +1043,77 @@ typedef struct _mcr_inst { unsigned int crm; unsigned int Rd; unsigned int inst; -} mcr_inst; +}; -typedef struct mcrr_inst { +struct mcrr_inst { unsigned int opcode_1; unsigned int cp_num; unsigned int crm; unsigned int rt; unsigned int rt2; -} mcrr_inst; +}; -typedef struct _mrs_inst { +struct mrs_inst { unsigned int R; unsigned int Rd; -} mrs_inst; +}; -typedef struct _msr_inst { +struct msr_inst { unsigned int field_mask; unsigned int R; unsigned int inst; -} msr_inst; +}; -typedef struct _pld_inst { -} pld_inst; +struct pld_inst { +}; -typedef struct _sxtb_inst { +struct sxtb_inst { unsigned int Rd; unsigned int Rm; unsigned int rotate; -} sxtb_inst; +}; -typedef struct _sxtab_inst { +struct sxtab_inst { unsigned int Rd; unsigned int Rn; unsigned int Rm; unsigned rotate; -} sxtab_inst; +}; -typedef struct _sxtah_inst { +struct sxtah_inst { unsigned int Rd; unsigned int Rn; unsigned int Rm; unsigned int rotate; -} sxtah_inst; +}; -typedef struct _sxth_inst { +struct sxth_inst { unsigned int Rd; unsigned int Rm; unsigned int rotate; -} sxth_inst; +}; -typedef struct _uxtab_inst { +struct uxtab_inst { unsigned int Rn; unsigned int Rd; unsigned int rotate; unsigned int Rm; -} uxtab_inst; +}; -typedef struct _uxtah_inst { +struct uxtah_inst { unsigned int Rn; unsigned int Rd; unsigned int rotate; unsigned int Rm; -} uxtah_inst; +}; -typedef struct _uxth_inst { +struct uxth_inst { unsigned int Rd; unsigned int Rm; unsigned int rotate; -} uxth_inst; +}; -typedef struct _cdp_inst { +struct cdp_inst { unsigned int opcode_1; unsigned int CRn; unsigned int CRd; @@ -1068,56 +1121,56 @@ typedef struct _cdp_inst { unsigned int opcode_2; unsigned int CRm; unsigned int inst; -}cdp_inst; +}; -typedef struct _uxtb_inst { +struct uxtb_inst { unsigned int Rd; unsigned int Rm; unsigned int rotate; -} uxtb_inst; +}; -typedef struct _swp_inst { +struct swp_inst { unsigned int Rn; unsigned int Rd; unsigned int Rm; -} swp_inst; +}; -typedef struct setend_inst { +struct setend_inst { unsigned int set_bigend; -} setend_inst; +}; -typedef struct _b_2_thumb { +struct b_2_thumb { unsigned int imm; -}b_2_thumb; -typedef struct _b_cond_thumb { +}; +struct b_cond_thumb { unsigned int imm; unsigned int cond; -}b_cond_thumb; +}; -typedef struct _bl_1_thumb { +struct bl_1_thumb { unsigned int imm; -}bl_1_thumb; -typedef struct _bl_2_thumb { +}; +struct bl_2_thumb { unsigned int imm; -}bl_2_thumb; -typedef struct _blx_1_thumb { +}; +struct blx_1_thumb { unsigned int imm; unsigned int instr; -}blx_1_thumb; +}; -typedef struct _pkh_inst { +struct pkh_inst { unsigned int Rm; unsigned int Rn; unsigned int Rd; unsigned char imm; -} pkh_inst; +}; typedef arm_inst * ARM_INST_PTR; #define CACHE_BUFFER_SIZE (64 * 1024 * 2000) -char inst_buf[CACHE_BUFFER_SIZE]; -int top = 0; -inline void *AllocBuffer(unsigned int size) { +static char inst_buf[CACHE_BUFFER_SIZE]; +static int top = 0; +static inline void *AllocBuffer(unsigned int size) { int start = top; top += size; if (top > CACHE_BUFFER_SIZE) { @@ -1127,74 +1180,6 @@ inline void *AllocBuffer(unsigned int size) { return (void *)&inst_buf[start]; } -int CondPassed(ARMul_State* cpu, unsigned int cond) { - #define NFLAG cpu->NFlag - #define ZFLAG cpu->ZFlag - #define CFLAG cpu->CFlag - #define VFLAG cpu->VFlag - - int temp = 0; - - switch (cond) { - case 0x0: - temp = ZFLAG; - break; - case 0x1: // NE - temp = !ZFLAG; - break; - case 0x6: // VS - temp = VFLAG; - break; - case 0x7: // VC - temp = !VFLAG; - break; - case 0x4: // MI - temp = NFLAG; - break; - case 0x5: // PL - temp = !NFLAG; - break; - case 0x2: // CS - temp = CFLAG; - break; - case 0x3: // CC - temp = !CFLAG; - break; - case 0x8: // HI - temp = (CFLAG && !ZFLAG); - break; - case 0x9: // LS - temp = (!CFLAG || ZFLAG); - break; - case 0xa: // GE - temp = ((!NFLAG && !VFLAG) || (NFLAG && VFLAG)); - break; - case 0xb: // LT - temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)); - break; - case 0xc: // GT - temp = ((!NFLAG && !VFLAG && !ZFLAG) || (NFLAG && VFLAG && !ZFLAG)); - break; - case 0xd: // LE - temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) || ZFLAG; - break; - case 0xe: // AL - temp = 1; - break; - case 0xf: - temp = 1; - break; - } - return temp; -} - -enum DECODE_STATUS { - DECODE_SUCCESS, - DECODE_FAILURE -}; - -int decode_arm_instr(uint32_t instr, int32_t *idx); - static shtop_fp_t get_shtop(unsigned int inst) { if (BIT(inst, 25)) { return DPO(Immediate); @@ -1393,7 +1378,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(bkpt)(unsigned int inst, int index) inst_base->br = NON_BRANCH; inst_base->load_r15 = 0; - inst_cream->imm = BITS(inst, 8, 19) | BITS(inst, 0, 3); + inst_cream->imm = (BITS(inst, 8, 19) << 4) | BITS(inst, 0, 3); return inst_base; } @@ -2052,6 +2037,19 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(orr)(unsigned int inst, int index) return inst_base; } +// NOP introduced in ARMv6K. +static ARM_INST_PTR INTERPRETER_TRANSLATE(nop)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst)); + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + return inst_base; +} + static ARM_INST_PTR INTERPRETER_TRANSLATE(pkhbt)(unsigned int inst, int index) { arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(pkh_inst)); @@ -2343,6 +2341,18 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(setend)(unsigned int inst, int index) return inst_base; } +static ARM_INST_PTR INTERPRETER_TRANSLATE(sev)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst)); + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + return inst_base; +} + static ARM_INST_PTR INTERPRETER_TRANSLATE(shadd8)(unsigned int inst, int index) { arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); @@ -3347,6 +3357,40 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb16)(unsigned int inst, int index) return INTERPRETER_TRANSLATE(uxtab16)(inst, index); } +static ARM_INST_PTR INTERPRETER_TRANSLATE(wfe)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst)); + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(wfi)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst)); + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + return inst_base; +} +static ARM_INST_PTR INTERPRETER_TRANSLATE(yield)(unsigned int inst, int index) +{ + arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst)); + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + return inst_base; +} + // Floating point VFPv3 structures and instructions #define VFP_INTERPRETER_STRUCT @@ -3536,6 +3580,10 @@ const transop_fp_t arm_instruction_trans[] = { INTERPRETER_TRANSLATE(mrc), INTERPRETER_TRANSLATE(mcr), INTERPRETER_TRANSLATE(msr), + INTERPRETER_TRANSLATE(msr), + INTERPRETER_TRANSLATE(msr), + INTERPRETER_TRANSLATE(msr), + INTERPRETER_TRANSLATE(msr), INTERPRETER_TRANSLATE(ldrb), INTERPRETER_TRANSLATE(strb), INTERPRETER_TRANSLATE(ldr), @@ -3544,12 +3592,17 @@ const transop_fp_t arm_instruction_trans[] = { INTERPRETER_TRANSLATE(cdp), INTERPRETER_TRANSLATE(stc), INTERPRETER_TRANSLATE(ldc), - INTERPRETER_TRANSLATE(swi), - INTERPRETER_TRANSLATE(bbl), INTERPRETER_TRANSLATE(ldrexd), INTERPRETER_TRANSLATE(strexd), INTERPRETER_TRANSLATE(ldrexh), INTERPRETER_TRANSLATE(strexh), + INTERPRETER_TRANSLATE(nop), + INTERPRETER_TRANSLATE(yield), + INTERPRETER_TRANSLATE(wfe), + INTERPRETER_TRANSLATE(wfi), + INTERPRETER_TRANSLATE(sev), + INTERPRETER_TRANSLATE(swi), + INTERPRETER_TRANSLATE(bbl), // All the thumb instructions should be placed the end of table INTERPRETER_TRANSLATE(b_2_thumb), @@ -3723,7 +3776,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { #define FETCH_INST if (inst_base->br != NON_BRANCH) goto DISPATCH; \ inst_base = (arm_inst *)&inst_buf[ptr] - #define INC_PC(l) ptr += sizeof(arm_inst) + l + #define INC_PC(l) ptr += sizeof(arm_inst) + l + #define INC_PC_STUB ptr += sizeof(arm_inst) // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a // clunky switch statement. @@ -3912,28 +3966,37 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { case 172: goto MRC_INST; \ case 173: goto MCR_INST; \ case 174: goto MSR_INST; \ - case 175: goto LDRB_INST; \ - case 176: goto STRB_INST; \ - case 177: goto LDR_INST; \ - case 178: goto LDRCOND_INST ; \ - case 179: goto STR_INST; \ - case 180: goto CDP_INST; \ - case 181: goto STC_INST; \ - case 182: goto LDC_INST; \ - case 183: goto SWI_INST; \ - case 184: goto BBL_INST; \ - case 185: goto LDREXD_INST; \ - case 186: goto STREXD_INST; \ - case 187: goto LDREXH_INST; \ - case 188: goto STREXH_INST; \ - case 189: goto B_2_THUMB ; \ - case 190: goto B_COND_THUMB ; \ - case 191: goto BL_1_THUMB ; \ - case 192: goto BL_2_THUMB ; \ - case 193: goto BLX_1_THUMB ; \ - case 194: goto DISPATCH; \ - case 195: goto INIT_INST_LENGTH; \ - case 196: goto END; \ + case 175: goto MSR_INST; \ + case 176: goto MSR_INST; \ + case 177: goto MSR_INST; \ + case 178: goto MSR_INST; \ + case 179: goto LDRB_INST; \ + case 180: goto STRB_INST; \ + case 181: goto LDR_INST; \ + case 182: goto LDRCOND_INST ; \ + case 183: goto STR_INST; \ + case 184: goto CDP_INST; \ + case 185: goto STC_INST; \ + case 186: goto LDC_INST; \ + case 187: goto LDREXD_INST; \ + case 188: goto STREXD_INST; \ + case 189: goto LDREXH_INST; \ + case 190: goto STREXH_INST; \ + case 191: goto NOP_INST; \ + case 192: goto YIELD_INST; \ + case 193: goto WFE_INST; \ + case 194: goto WFI_INST; \ + case 195: goto SEV_INST; \ + case 196: goto SWI_INST; \ + case 197: goto BBL_INST; \ + case 198: goto B_2_THUMB ; \ + case 199: goto B_COND_THUMB ; \ + case 200: goto BL_1_THUMB ; \ + case 201: goto BL_2_THUMB ; \ + case 202: goto BLX_1_THUMB ; \ + case 203: goto DISPATCH; \ + case 204: goto INIT_INST_LENGTH; \ + case 205: goto END; \ } #endif @@ -3979,9 +4042,11 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { &&MCRR_INST,&&MRRC_INST,&&CMP_INST,&&TST_INST,&&TEQ_INST,&&CMN_INST,&&SMULL_INST,&&UMULL_INST,&&UMLAL_INST,&&SMLAL_INST,&&MUL_INST, &&MLA_INST,&&SSAT_INST,&&USAT_INST,&&MRS_INST,&&MSR_INST,&&AND_INST,&&BIC_INST,&&LDM_INST,&&EOR_INST,&&ADD_INST,&&RSB_INST,&&RSC_INST, &&SBC_INST,&&ADC_INST,&&SUB_INST,&&ORR_INST,&&MVN_INST,&&MOV_INST,&&STM_INST,&&LDM_INST,&&LDRSH_INST,&&STM_INST,&&LDM_INST,&&LDRSB_INST, - &&STRD_INST,&&LDRH_INST,&&STRH_INST,&&LDRD_INST,&&STRT_INST,&&STRBT_INST,&&LDRBT_INST,&&LDRT_INST,&&MRC_INST,&&MCR_INST,&&MSR_INST, - &&LDRB_INST,&&STRB_INST,&&LDR_INST,&&LDRCOND_INST, &&STR_INST,&&CDP_INST,&&STC_INST,&&LDC_INST,&&SWI_INST,&&BBL_INST,&&LDREXD_INST, - &&STREXD_INST,&&LDREXH_INST,&&STREXH_INST,&&B_2_THUMB, &&B_COND_THUMB,&&BL_1_THUMB, &&BL_2_THUMB, &&BLX_1_THUMB, &&DISPATCH, + &&STRD_INST,&&LDRH_INST,&&STRH_INST,&&LDRD_INST,&&STRT_INST,&&STRBT_INST,&&LDRBT_INST,&&LDRT_INST,&&MRC_INST,&&MCR_INST, + &&MSR_INST, &&MSR_INST, &&MSR_INST, &&MSR_INST, &&MSR_INST, + &&LDRB_INST,&&STRB_INST,&&LDR_INST,&&LDRCOND_INST, &&STR_INST,&&CDP_INST,&&STC_INST,&&LDC_INST, &&LDREXD_INST, + &&STREXD_INST,&&LDREXH_INST,&&STREXH_INST, &&NOP_INST, &&YIELD_INST, &&WFE_INST, &&WFI_INST, &&SEV_INST, &&SWI_INST,&&BBL_INST, + &&B_2_THUMB, &&B_COND_THUMB,&&BL_1_THUMB, &&BL_2_THUMB, &&BLX_1_THUMB, &&DISPATCH, &&INIT_INST_LENGTH,&&END }; #endif @@ -5034,6 +5099,14 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { GOTO_NEXT_INST; } + NOP_INST: + { + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC_STUB; + FETCH_INST; + GOTO_NEXT_INST; + } + PKHBT_INST: { if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { @@ -5517,6 +5590,19 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { GOTO_NEXT_INST; } + SEV_INST: + { + // Stubbed, as SEV is a hint instruction. + if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { + LOG_TRACE(Core_ARM11, "SEV executed."); + } + + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC_STUB; + FETCH_INST; + GOTO_NEXT_INST; + } + SHADD8_INST: SHADD16_INST: SHADDSUBX_INST: @@ -6980,6 +7066,45 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { GOTO_NEXT_INST; } + WFE_INST: + { + // Stubbed, as WFE is a hint instruction. + if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { + LOG_TRACE(Core_ARM11, "WFE executed."); + } + + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC_STUB; + FETCH_INST; + GOTO_NEXT_INST; + } + + WFI_INST: + { + // Stubbed, as WFI is a hint instruction. + if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { + LOG_TRACE(Core_ARM11, "WFI executed."); + } + + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC_STUB; + FETCH_INST; + GOTO_NEXT_INST; + } + + YIELD_INST: + { + // Stubbed, as YIELD is a hint instruction. + if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { + LOG_TRACE(Core_ARM11, "YIELD executed."); + } + + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC_STUB; + FETCH_INST; + GOTO_NEXT_INST; + } + #define VFP_INTERPRETER_IMPL #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" #undef VFP_INTERPRETER_IMPL diff --git a/src/core/arm/interpreter/arminit.cpp b/src/core/arm/interpreter/arminit.cpp index 31b2bab06..680a94a39 100644 --- a/src/core/arm/interpreter/arminit.cpp +++ b/src/core/arm/interpreter/arminit.cpp @@ -16,7 +16,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <cstring> -#include "core/mem_map.h" #include "core/arm/skyeye_common/armdefs.h" #include "core/arm/skyeye_common/armemu.h" #include "core/arm/skyeye_common/vfp/vfp.h" diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp index 15c6f595b..1b078dc71 100644 --- a/src/core/arm/interpreter/armsupp.cpp +++ b/src/core/arm/interpreter/armsupp.cpp @@ -454,8 +454,6 @@ void WriteCP15Register(ARMul_State* cpu, u32 value, u32 crn, u32 opcode_1, u32 c } else if (crn == 7 && opcode_1 == 0) { - LOG_WARNING(Core_ARM11, "Cache operations are not fully implemented."); - if (crm == 0 && opcode_2 == 4) { cpu->CP15[CP15_WAIT_FOR_INTERRUPT] = value; diff --git a/src/core/arm/skyeye_common/armmmu.h b/src/core/arm/skyeye_common/armmmu.h index 0463d83c8..c67d7209b 100644 --- a/src/core/arm/skyeye_common/armmmu.h +++ b/src/core/arm/skyeye_common/armmmu.h @@ -22,7 +22,7 @@ #include "common/swap.h" -#include "core/mem_map.h" +#include "core/memory.h" #include "core/arm/skyeye_common/armdefs.h" // Register numbers in the MMU diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp index ab9fec39d..f91049585 100644 --- a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp @@ -531,7 +531,7 @@ static u32 vfp_double_fsito(ARMul_State* state, int dd, int unused, int dm, u32 LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); vdm.sign = (m & 0x80000000) >> 16; vdm.exponent = 1023 + 63 - 1; - vdm.significand = vdm.sign ? -m : m; + vdm.significand = vdm.sign ? (~m + 1) : m; return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fsito"); } @@ -669,7 +669,7 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 exceptions |= FPSCR_IXC; if (vdm.sign) - d = -d; + d = (~d + 1); } else { d = 0; if (vdm.exponent | vdm.significand) { @@ -817,7 +817,7 @@ u32 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn,struct vfp_dou m_sig = vdn->significand - m_sig; if ((s64)m_sig < 0) { vdd->sign = vfp_sign_negate(vdd->sign); - m_sig = -m_sig; + m_sig = (~m_sig + 1); } else if (m_sig == 0) { vdd->sign = (fpscr & FPSCR_RMODE_MASK) == FPSCR_ROUND_MINUSINF ? 0x8000 : 0; diff --git a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp index 72afe2164..a04bf915c 100644 --- a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp @@ -13,10 +13,10 @@ /* VMLA */ /* cond 1110 0D00 Vn-- Vd-- 101X N0M0 Vm-- */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vmla_inst { +struct vmla_inst { unsigned int instr; unsigned int dp_operation; -} vmla_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vmla)(unsigned int inst, int index) @@ -63,10 +63,10 @@ VMLA_INST: /* VNMLS */ /* cond 1110 0D00 Vn-- Vd-- 101X N1M0 Vm-- */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vmls_inst { +struct vmls_inst { unsigned int instr; unsigned int dp_operation; -} vmls_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vmls)(unsigned int inst, int index) @@ -113,10 +113,10 @@ VMLS_INST: /* VNMLA */ /* cond 1110 0D01 Vn-- Vd-- 101X N1M0 Vm-- */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vnmla_inst { +struct vnmla_inst { unsigned int instr; unsigned int dp_operation; -} vnmla_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vnmla)(unsigned int inst, int index) @@ -164,10 +164,10 @@ VNMLA_INST: /* cond 1110 0D01 Vn-- Vd-- 101X N0M0 Vm-- */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vnmls_inst { +struct vnmls_inst { unsigned int instr; unsigned int dp_operation; -} vnmls_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vnmls)(unsigned int inst, int index) @@ -214,10 +214,10 @@ VNMLS_INST: /* VNMUL */ /* cond 1110 0D10 Vn-- Vd-- 101X N0M0 Vm-- */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vnmul_inst { +struct vnmul_inst { unsigned int instr; unsigned int dp_operation; -} vnmul_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vnmul)(unsigned int inst, int index) @@ -264,10 +264,10 @@ VNMUL_INST: /* VMUL */ /* cond 1110 0D10 Vn-- Vd-- 101X N0M0 Vm-- */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vmul_inst { +struct vmul_inst { unsigned int instr; unsigned int dp_operation; -} vmul_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vmul)(unsigned int inst, int index) @@ -314,10 +314,10 @@ VMUL_INST: /* VADD */ /* cond 1110 0D11 Vn-- Vd-- 101X N0M0 Vm-- */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vadd_inst { +struct vadd_inst { unsigned int instr; unsigned int dp_operation; -} vadd_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vadd)(unsigned int inst, int index) @@ -364,10 +364,10 @@ VADD_INST: /* VSUB */ /* cond 1110 0D11 Vn-- Vd-- 101X N1M0 Vm-- */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vsub_inst { +struct vsub_inst { unsigned int instr; unsigned int dp_operation; -} vsub_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vsub)(unsigned int inst, int index) @@ -414,10 +414,10 @@ VSUB_INST: /* VDIV */ /* cond 1110 1D00 Vn-- Vd-- 101X N0M0 Vm-- */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vdiv_inst { +struct vdiv_inst { unsigned int instr; unsigned int dp_operation; -} vdiv_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vdiv)(unsigned int inst, int index) @@ -465,11 +465,11 @@ VDIV_INST: /* cond 1110 1D11 im4H Vd-- 101X 0000 im4L */ /* cond 1110 opc1 CRn- CRd- copr op20 CRm- CDP */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vmovi_inst { +struct vmovi_inst { unsigned int single; unsigned int d; unsigned int imm; -} vmovi_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovi)(unsigned int inst, int index) @@ -514,11 +514,11 @@ VMOVI_INST: /* cond 1110 1D11 0000 Vd-- 101X 01M0 Vm-- */ /* cond 1110 opc1 CRn- CRd- copr op20 CRm- CDP */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vmovr_inst { +struct vmovr_inst { unsigned int single; unsigned int d; unsigned int m; -} vmovr_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovr)(unsigned int inst, int index) @@ -609,10 +609,10 @@ VABS_INST: /* cond 1110 1D11 0001 Vd-- 101X 11M0 Vm-- */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vneg_inst { +struct vneg_inst { unsigned int instr; unsigned int dp_operation; -} vneg_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vneg)(unsigned int inst, int index) @@ -659,10 +659,10 @@ VNEG_INST: /* VSQRT */ /* cond 1110 1D11 0001 Vd-- 101X 11M0 Vm-- */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vsqrt_inst { +struct vsqrt_inst { unsigned int instr; unsigned int dp_operation; -} vsqrt_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vsqrt)(unsigned int inst, int index) @@ -709,10 +709,10 @@ VSQRT_INST: /* VCMP VCMPE */ /* cond 1110 1D11 0100 Vd-- 101X E1M0 Vm-- Encoding 1 */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vcmp_inst { +struct vcmp_inst { unsigned int instr; unsigned int dp_operation; -} vcmp_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vcmp)(unsigned int inst, int index) @@ -759,10 +759,10 @@ VCMP_INST: /* VCMP VCMPE */ /* cond 1110 1D11 0100 Vd-- 101X E1M0 Vm-- Encoding 2 */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vcmp2_inst { +struct vcmp2_inst { unsigned int instr; unsigned int dp_operation; -} vcmp2_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vcmp2)(unsigned int inst, int index) @@ -809,10 +809,10 @@ VCMP2_INST: /* VCVTBDS between double and single */ /* cond 1110 1D11 0111 Vd-- 101X 11M0 Vm-- */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vcvtbds_inst { +struct vcvtbds_inst { unsigned int instr; unsigned int dp_operation; -} vcvtbds_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vcvtbds)(unsigned int inst, int index) @@ -859,10 +859,10 @@ VCVTBDS_INST: /* VCVTBFF between floating point and fixed point */ /* cond 1110 1D11 1op2 Vd-- 101X X1M0 Vm-- */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vcvtbff_inst { +struct vcvtbff_inst { unsigned int instr; unsigned int dp_operation; -} vcvtbff_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vcvtbff)(unsigned int inst, int index) @@ -911,10 +911,10 @@ VCVTBFF_INST: /* VCVTBFI between floating point and integer */ /* cond 1110 1D11 1op2 Vd-- 101X X1M0 Vm-- */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vcvtbfi_inst { +struct vcvtbfi_inst { unsigned int instr; unsigned int dp_operation; -} vcvtbfi_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vcvtbfi)(unsigned int inst, int index) @@ -967,11 +967,11 @@ VCVTBFI_INST: /* cond 1110 000o Vn-- Rt-- 1010 N001 0000 */ /* cond 1110 op11 CRn- Rt-- copr op21 CRm- MRC */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vmovbrs_inst { +struct vmovbrs_inst { unsigned int to_arm; unsigned int t; unsigned int n; -} vmovbrs_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrs)(unsigned int inst, int index) @@ -1013,10 +1013,10 @@ VMOVBRS_INST: /* cond 1110 1110 reg- Rt-- 1010 0001 0000 */ /* cond 1110 op10 CRn- Rt-- copr op21 CRm- MCR */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vmsr_inst { +struct vmsr_inst { unsigned int reg; unsigned int Rd; -} vmsr_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vmsr)(unsigned int inst, int index) @@ -1040,7 +1040,7 @@ VMSR_INST: { if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled , - and in privilegied mode */ + and in privileged mode */ /* Exceptions must be checked, according to v7 ref manual */ CHECK_VFP_ENABLED; @@ -1060,12 +1060,12 @@ VMSR_INST: /* cond 1110 0XX0 Vd-- Rt-- 1011 DXX1 0000 */ /* cond 1110 op10 CRn- Rt-- copr op21 CRm- MCR */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vmovbrc_inst { +struct vmovbrc_inst { unsigned int esize; unsigned int index; unsigned int d; unsigned int t; -} vmovbrc_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrc)(unsigned int inst, int index) @@ -1109,10 +1109,10 @@ VMOVBRC_INST: /* cond 1110 1111 CRn- Rt-- 1010 0001 0000 */ /* cond 1110 op11 CRn- Rt-- copr op21 CRm- MRC */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vmrs_inst { +struct vmrs_inst { unsigned int reg; unsigned int Rt; -} vmrs_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vmrs)(unsigned int inst, int index) @@ -1136,7 +1136,7 @@ VMRS_INST: { if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled, - and in privilegied mode */ + and in privileged mode */ /* Exceptions must be checked, according to v7 ref manual */ CHECK_VFP_ENABLED; @@ -1191,12 +1191,12 @@ VMRS_INST: /* cond 1110 XXX1 Vd-- Rt-- 1011 NXX1 0000 */ /* cond 1110 op11 CRn- Rt-- copr op21 CRm- MCR */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vmovbcr_inst { +struct vmovbcr_inst { unsigned int esize; unsigned int index; unsigned int d; unsigned int t; -} vmovbcr_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbcr)(unsigned int inst, int index) @@ -1245,12 +1245,12 @@ VMOVBCR_INST: /* cond 1100 010X Rt2- Rt-- 1010 00X1 Vm-- */ /* cond 1100 0101 Rt2- Rt-- copr opc1 CRm- MRRC */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vmovbrrss_inst { +struct vmovbrrss_inst { unsigned int to_arm; unsigned int t; unsigned int t2; unsigned int m; -} vmovbrrss_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrrss)(unsigned int inst, int index) @@ -1294,12 +1294,12 @@ VMOVBRRSS_INST: /* cond 1100 010X Rt2- Rt-- 1011 00X1 Vm-- */ /* cond 1100 0101 Rt2- Rt-- copr opc1 CRm- MRRC */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vmovbrrd_inst { +struct vmovbrrd_inst { unsigned int to_arm; unsigned int t; unsigned int t2; unsigned int m; -} vmovbrrd_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrrd)(unsigned int inst, int index) @@ -1347,13 +1347,13 @@ VMOVBRRD_INST: /* VSTR */ /* cond 1101 UD00 Rn-- Vd-- 101X imm8 imm8 */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vstr_inst { +struct vstr_inst { unsigned int single; unsigned int n; unsigned int d; unsigned int imm32; unsigned int add; -} vstr_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vstr)(unsigned int inst, int index) @@ -1415,12 +1415,12 @@ VSTR_INST: /* VPUSH */ /* cond 1101 0D10 1101 Vd-- 101X imm8 imm8 */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vpush_inst { +struct vpush_inst { unsigned int single; unsigned int d; unsigned int imm32; unsigned int regs; -} vpush_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vpush)(unsigned int inst, int index) @@ -1488,7 +1488,7 @@ VPUSH_INST: /* VSTM */ /* cond 110P UDW0 Rn-- Vd-- 101X imm8 imm8 */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vstm_inst { +struct vstm_inst { unsigned int single; unsigned int add; unsigned int wback; @@ -1496,7 +1496,7 @@ typedef struct _vstm_inst { unsigned int n; unsigned int imm32; unsigned int regs; -} vstm_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vstm)(unsigned int inst, int index) @@ -1570,12 +1570,12 @@ VSTM_INST: /* encoding 1 */ /* VPOP */ /* cond 1100 1D11 1101 Vd-- 101X imm8 imm8 */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vpop_inst { +struct vpop_inst { unsigned int single; unsigned int d; unsigned int imm32; unsigned int regs; -} vpop_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vpop)(unsigned int inst, int index) @@ -1643,13 +1643,13 @@ VPOP_INST: /* VLDR */ /* cond 1101 UD01 Rn-- Vd-- 101X imm8 imm8 */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vldr_inst { +struct vldr_inst { unsigned int single; unsigned int n; unsigned int d; unsigned int imm32; unsigned int add; -} vldr_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vldr)(unsigned int inst, int index) @@ -1711,7 +1711,7 @@ VLDR_INST: /* VLDM */ /* cond 110P UDW1 Rn-- Vd-- 101X imm8 imm8 */ #ifdef VFP_INTERPRETER_STRUCT -typedef struct _vldm_inst { +struct vldm_inst { unsigned int single; unsigned int add; unsigned int wback; @@ -1719,7 +1719,7 @@ typedef struct _vldm_inst { unsigned int n; unsigned int imm32; unsigned int regs; -} vldm_inst; +}; #endif #ifdef VFP_INTERPRETER_TRANS static ARM_INST_PTR INTERPRETER_TRANSLATE(vldm)(unsigned int inst, int index) diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp index 4dfe0254d..a692c1909 100644 --- a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp @@ -388,7 +388,7 @@ sqrt_invalid: } else { u64 term; s64 rem; - vsm.significand <<= !(vsm.exponent & 1); + vsm.significand <<= static_cast<u32>((vsm.exponent & 1) == 0); term = (u64)vsd.significand * vsd.significand; rem = ((u64)vsm.significand << 32) - term; @@ -691,7 +691,7 @@ static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 f exceptions |= FPSCR_IXC; if (vsm.sign) - d = 0-d; + d = (~d + 1); } else { d = 0; if (vsm.exponent | vsm.significand) { @@ -843,7 +843,7 @@ vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn, m_sig = vsn->significand - m_sig; if ((s32)m_sig < 0) { vsd->sign = vfp_sign_negate(vsd->sign); - m_sig = 0-m_sig; + m_sig = (~m_sig + 1); } else if (m_sig == 0) { vsd->sign = (fpscr & FPSCR_RMODE_MASK) == FPSCR_ROUND_MINUSINF ? 0x8000 : 0; diff --git a/src/core/core.cpp b/src/core/core.cpp index 53aae8c2f..79038cd52 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -8,7 +8,6 @@ #include "core/core.h" #include "core/core_timing.h" -#include "core/mem_map.h" #include "core/settings.h" #include "core/arm/arm_interface.h" #include "core/arm/disassembler/arm_disasm.h" diff --git a/src/core/file_sys/archive_backend.cpp b/src/core/file_sys/archive_backend.cpp index 0439868ab..45a559ce8 100644 --- a/src/core/file_sys/archive_backend.cpp +++ b/src/core/file_sys/archive_backend.cpp @@ -8,7 +8,7 @@ #include "common/string_util.h" #include "core/file_sys/archive_backend.h" -#include "core/mem_map.h" +#include "core/memory.h" namespace FileSys { diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/config_mem.cpp index 35dc9cf58..aea936d2d 100644 --- a/src/core/hle/config_mem.cpp +++ b/src/core/hle/config_mem.cpp @@ -9,59 +9,14 @@ #include "common/common_funcs.h" #include "core/core.h" -#include "core/mem_map.h" +#include "core/memory.h" #include "core/hle/config_mem.h" //////////////////////////////////////////////////////////////////////////////////////////////////// namespace ConfigMem { -struct ConfigMemDef { - u8 kernel_unk; // 0 - u8 kernel_version_rev; // 1 - u8 kernel_version_min; // 2 - u8 kernel_version_maj; // 3 - u32 update_flag; // 4 - u64 ns_tid; // 8 - u32 sys_core_ver; // 10 - u8 unit_info; // 14 - u8 boot_firm; // 15 - u8 prev_firm; // 16 - INSERT_PADDING_BYTES(0x1); // 17 - u32 ctr_sdk_ver; // 18 - INSERT_PADDING_BYTES(0x30 - 0x1C); // 1C - u32 app_mem_type; // 30 - INSERT_PADDING_BYTES(0x40 - 0x34); // 34 - u32 app_mem_alloc; // 40 - u32 sys_mem_alloc; // 44 - u32 base_mem_alloc; // 48 - INSERT_PADDING_BYTES(0x60 - 0x4C); // 4C - u8 firm_unk; // 60 - u8 firm_version_rev; // 61 - u8 firm_version_min; // 62 - u8 firm_version_maj; // 63 - u32 firm_sys_core_ver; // 64 - u32 firm_ctr_sdk_ver; // 68 - INSERT_PADDING_BYTES(0x1000 - 0x6C); // 6C -}; - -static_assert(sizeof(ConfigMemDef) == Memory::CONFIG_MEMORY_SIZE, "Config Memory structure size is wrong"); - -static ConfigMemDef config_mem; - -template <typename T> -inline void Read(T &var, const u32 addr) { - u32 offset = addr - Memory::CONFIG_MEMORY_VADDR; - ASSERT(offset < Memory::CONFIG_MEMORY_SIZE); - var = *(reinterpret_cast<T*>(((uintptr_t)&config_mem) + offset)); -} - -// Explicitly instantiate template functions because we aren't defining this in the header: - -template void Read<u64>(u64 &var, const u32 addr); -template void Read<u32>(u32 &var, const u32 addr); -template void Read<u16>(u16 &var, const u32 addr); -template void Read<u8>(u8 &var, const u32 addr); +ConfigMemDef config_mem; void Init() { std::memset(&config_mem, 0, sizeof(config_mem)); diff --git a/src/core/hle/config_mem.h b/src/core/hle/config_mem.h index cbb478fb3..9825a09e8 100644 --- a/src/core/hle/config_mem.h +++ b/src/core/hle/config_mem.h @@ -9,17 +9,49 @@ // bootrom. Because we're not emulating this, and essentially just "stubbing" the functionality, I'm // putting this as a subset of HLE for now. +#include "common/common_funcs.h" #include "common/common_types.h" +#include "common/swap.h" + +#include "core/memory.h" //////////////////////////////////////////////////////////////////////////////////////////////////// namespace ConfigMem { -template <typename T> -void Read(T &var, const u32 addr); +struct ConfigMemDef { + u8 kernel_unk; // 0 + u8 kernel_version_rev; // 1 + u8 kernel_version_min; // 2 + u8 kernel_version_maj; // 3 + u32_le update_flag; // 4 + u64_le ns_tid; // 8 + u32_le sys_core_ver; // 10 + u8 unit_info; // 14 + u8 boot_firm; // 15 + u8 prev_firm; // 16 + INSERT_PADDING_BYTES(0x1); // 17 + u32_le ctr_sdk_ver; // 18 + INSERT_PADDING_BYTES(0x30 - 0x1C); // 1C + u32_le app_mem_type; // 30 + INSERT_PADDING_BYTES(0x40 - 0x34); // 34 + u32_le app_mem_alloc; // 40 + u32_le sys_mem_alloc; // 44 + u32_le base_mem_alloc; // 48 + INSERT_PADDING_BYTES(0x60 - 0x4C); // 4C + u8 firm_unk; // 60 + u8 firm_version_rev; // 61 + u8 firm_version_min; // 62 + u8 firm_version_maj; // 63 + u32_le firm_sys_core_ver; // 64 + u32_le firm_ctr_sdk_ver; // 68 + INSERT_PADDING_BYTES(0x1000 - 0x6C); // 6C +}; +static_assert(sizeof(ConfigMemDef) == Memory::CONFIG_MEMORY_SIZE, "Config Memory structure size is wrong"); + +extern ConfigMemDef config_mem; void Init(); - void Shutdown(); } // namespace diff --git a/src/core/hle/coprocessor.cpp b/src/core/hle/coprocessor.cpp deleted file mode 100644 index 425959be4..000000000 --- a/src/core/hle/coprocessor.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/coprocessor.h" -#include "core/hle/hle.h" -#include "core/mem_map.h" - -namespace HLE { - -/// Returns the coprocessor (in this case, syscore) command buffer pointer -Addr GetThreadCommandBuffer() { - // Called on insruction: mrc p15, 0, r0, c13, c0, 3 - return Memory::KERNEL_MEMORY_VADDR; -} - -/// Call an MRC (move to ARM register from coprocessor) instruction in HLE -s32 CallMRC(u32 instruction) { - CoprocessorOperation operation = (CoprocessorOperation)((instruction >> 20) & 0xFF); - - switch (operation) { - - case CALL_GET_THREAD_COMMAND_BUFFER: - return GetThreadCommandBuffer(); - - default: - DEBUG_LOG(OSHLE, "unknown MRC call 0x%08X", instruction); - break; - } - return -1; -} - -} // namespace diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index be2626eef..23c86a72d 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h @@ -7,7 +7,7 @@ #include "common/common_types.h" #include "core/arm/arm_interface.h" -#include "core/mem_map.h" +#include "core/memory.h" #include "core/hle/hle.h" namespace HLE { @@ -102,14 +102,14 @@ template<ResultCode func(u32)> void Wrap() { FuncReturn(func(PARAM(0)).raw); } -template<ResultCode func(s64*, u32, void*, s32)> void Wrap(){ - FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)), +template<ResultCode func(s64*, u32, u32*, s32)> void Wrap(){ + FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), (u32*)Memory::GetPointer(PARAM(2)), (s32)PARAM(3)).raw); } template<ResultCode func(u32*, const char*)> void Wrap() { u32 param_1 = 0; - u32 retval = func(¶m_1, Memory::GetCharPointer(PARAM(1))).raw; + u32 retval = func(¶m_1, (char*)Memory::GetPointer(PARAM(1))).raw; Core::g_app_core->SetReg(1, param_1); FuncReturn(retval); } @@ -163,7 +163,11 @@ template<void func(s64)> void Wrap() { } template<void func(const char*)> void Wrap() { - func(Memory::GetCharPointer(PARAM(0))); + func((char*)Memory::GetPointer(PARAM(0))); +} + +template<void func(u8)> void Wrap() { + func((u8)PARAM(0)); } #undef PARAM diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 9d7f6b280..a1221766e 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -5,7 +5,7 @@ #include "common/common_types.h" #include "common/logging/log.h" -#include "core/mem_map.h" +#include "core/memory.h" #include "core/hle/hle.h" #include "core/hle/kernel/address_arbiter.h" diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index b5c98b249..726e4d2ff 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -10,6 +10,7 @@ #include "core/arm/arm_interface.h" #include "core/core.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/timer.h" @@ -134,6 +135,7 @@ void HandleTable::Clear() { /// Initialize the kernel void Init() { + Kernel::ResourceLimitsInit(); Kernel::ThreadingInit(); Kernel::TimersInit(); @@ -147,6 +149,7 @@ void Init() { void Shutdown() { Kernel::ThreadingShutdown(); Kernel::TimersShutdown(); + Kernel::ResourceLimitsShutdown(); g_handle_table.Clear(); // Free all kernel objects g_current_process = nullptr; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 7c106d37c..28748c8f5 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -46,7 +46,8 @@ enum class HandleType : u32 { Process = 8, AddressArbiter = 9, Semaphore = 10, - Timer = 11 + Timer = 11, + ResourceLimit = 12, }; enum { diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 1e439db9e..b0e75ba59 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -7,8 +7,9 @@ #include "common/logging/log.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/thread.h" -#include "core/mem_map.h" +#include "core/memory.h" namespace Kernel { @@ -27,7 +28,7 @@ SharedPtr<Process> Process::Create(std::string name, u64 program_id) { } void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { - for (int i = 0; i < len; ++i) { + for (size_t i = 0; i < len; ++i) { u32 descriptor = kernel_caps[i]; u32 type = descriptor >> 20; @@ -64,8 +65,8 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { AddressMapping mapping; mapping.address = descriptor << 12; mapping.size = (end_desc << 12) - mapping.address; - mapping.writable = descriptor & (1 << 20); - mapping.unk_flag = end_desc & (1 << 20); + mapping.writable = (descriptor & (1 << 20)) != 0; + mapping.unk_flag = (end_desc & (1 << 20)) != 0; address_mappings.push_back(mapping); } else if ((type & 0xFFF) == 0xFFE) { // 0x000F diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 90881054c..7b8a68610 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -45,6 +45,8 @@ union ProcessFlags { BitField<12, 1, u16> loaded_high; ///< Application loaded high (not at 0x00100000). }; +class ResourceLimit; + class Process final : public Object { public: static SharedPtr<Process> Create(std::string name, u64 program_id); @@ -61,6 +63,8 @@ public: std::string name; /// Title ID corresponding to the process u64 program_id; + /// Resource limit descriptor for this process + SharedPtr<ResourceLimit> resource_limit; /// The process may only call SVCs which have the corresponding bit set. std::bitset<0x80> svc_access_mask; diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp new file mode 100644 index 000000000..94b3e3298 --- /dev/null +++ b/src/core/hle/kernel/resource_limit.cpp @@ -0,0 +1,157 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <cstring> + +#include "common/logging/log.h" + +#include "core/mem_map.h" +#include "core/hle/kernel/resource_limit.h" + +namespace Kernel { + +static SharedPtr<ResourceLimit> resource_limits[4]; + +ResourceLimit::ResourceLimit() {} +ResourceLimit::~ResourceLimit() {} + +SharedPtr<ResourceLimit> ResourceLimit::Create(std::string name) { + SharedPtr<ResourceLimit> resource_limit(new ResourceLimit); + + resource_limit->name = std::move(name); + return resource_limit; +} + +SharedPtr<ResourceLimit> ResourceLimit::GetForCategory(ResourceLimitCategory category) { + switch (category) + { + case ResourceLimitCategory::APPLICATION: + case ResourceLimitCategory::SYS_APPLET: + case ResourceLimitCategory::LIB_APPLET: + case ResourceLimitCategory::OTHER: + return resource_limits[static_cast<u8>(category)]; + default: + LOG_CRITICAL(Kernel, "Unknown resource limit category"); + UNREACHABLE(); + } +} + +s32 ResourceLimit::GetCurrentResourceValue(u32 resource) const { + switch (resource) { + case COMMIT: + return current_commit; + case THREAD: + return current_threads; + case EVENT: + return current_events; + case MUTEX: + return current_mutexes; + case SEMAPHORE: + return current_semaphores; + case TIMER: + return current_timers; + case SHARED_MEMORY: + return current_shared_mems; + case ADDRESS_ARBITER: + return current_address_arbiters; + case CPU_TIME: + return current_cpu_time; + default: + LOG_ERROR(Kernel, "Unknown resource type=%08X", resource); + UNIMPLEMENTED(); + return 0; + } +} + +s32 ResourceLimit::GetMaxResourceValue(u32 resource) const { + switch (resource) { + case COMMIT: + return max_commit; + case THREAD: + return max_threads; + case EVENT: + return max_events; + case MUTEX: + return max_mutexes; + case SEMAPHORE: + return max_semaphores; + case TIMER: + return max_timers; + case SHARED_MEMORY: + return max_shared_mems; + case ADDRESS_ARBITER: + return max_address_arbiters; + case CPU_TIME: + return max_cpu_time; + default: + LOG_ERROR(Kernel, "Unknown resource type=%08X", resource); + UNIMPLEMENTED(); + return 0; + } +} + +void ResourceLimitsInit() { + // Create the four resource limits that the system uses + // Create the APPLICATION resource limit + SharedPtr<ResourceLimit> resource_limit = ResourceLimit::Create("Applications"); + resource_limit->max_priority = 0x18; + resource_limit->max_commit = 0x4000000; + resource_limit->max_threads = 0x20; + resource_limit->max_events = 0x20; + resource_limit->max_mutexes = 0x20; + resource_limit->max_semaphores = 0x8; + resource_limit->max_timers = 0x8; + resource_limit->max_shared_mems = 0x10; + resource_limit->max_address_arbiters = 0x2; + resource_limit->max_cpu_time = 0x1E; + resource_limits[static_cast<u8>(ResourceLimitCategory::APPLICATION)] = resource_limit; + + // Create the SYS_APPLET resource limit + resource_limit = ResourceLimit::Create("System Applets"); + resource_limit->max_priority = 0x4; + resource_limit->max_commit = 0x5E00000; + resource_limit->max_threads = 0x1D; + resource_limit->max_events = 0xB; + resource_limit->max_mutexes = 0x8; + resource_limit->max_semaphores = 0x4; + resource_limit->max_timers = 0x4; + resource_limit->max_shared_mems = 0x8; + resource_limit->max_address_arbiters = 0x3; + resource_limit->max_cpu_time = 0x2710; + resource_limits[static_cast<u8>(ResourceLimitCategory::SYS_APPLET)] = resource_limit; + + // Create the LIB_APPLET resource limit + resource_limit = ResourceLimit::Create("Library Applets"); + resource_limit->max_priority = 0x4; + resource_limit->max_commit = 0x600000; + resource_limit->max_threads = 0xE; + resource_limit->max_events = 0x8; + resource_limit->max_mutexes = 0x8; + resource_limit->max_semaphores = 0x4; + resource_limit->max_timers = 0x4; + resource_limit->max_shared_mems = 0x8; + resource_limit->max_address_arbiters = 0x1; + resource_limit->max_cpu_time = 0x2710; + resource_limits[static_cast<u8>(ResourceLimitCategory::LIB_APPLET)] = resource_limit; + + // Create the OTHER resource limit + resource_limit = ResourceLimit::Create("Others"); + resource_limit->max_priority = 0x4; + resource_limit->max_commit = 0x2180000; + resource_limit->max_threads = 0xE1; + resource_limit->max_events = 0x108; + resource_limit->max_mutexes = 0x25; + resource_limit->max_semaphores = 0x43; + resource_limit->max_timers = 0x2C; + resource_limit->max_shared_mems = 0x1F; + resource_limit->max_address_arbiters = 0x2D; + resource_limit->max_cpu_time = 0x3E8; + resource_limits[static_cast<u8>(ResourceLimitCategory::OTHER)] = resource_limit; +} + +void ResourceLimitsShutdown() { + +} + +} // namespace diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h new file mode 100644 index 000000000..201ec0db9 --- /dev/null +++ b/src/core/hle/kernel/resource_limit.h @@ -0,0 +1,119 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +#include "core/hle/kernel/kernel.h" + +namespace Kernel { + +enum class ResourceLimitCategory : u8 { + APPLICATION = 0, + SYS_APPLET = 1, + LIB_APPLET = 2, + OTHER = 3 +}; + +enum ResourceTypes { + PRIORITY = 0, + COMMIT = 1, + THREAD = 2, + EVENT = 3, + MUTEX = 4, + SEMAPHORE = 5, + TIMER = 6, + SHARED_MEMORY = 7, + ADDRESS_ARBITER = 8, + CPU_TIME = 9, +}; + +class ResourceLimit final : public Object { +public: + /** + * Creates a resource limit object. + */ + static SharedPtr<ResourceLimit> Create(std::string name = "Unknown"); + + /** + * Retrieves the resource limit associated with the specified resource limit category. + * @param category The resource limit category + * @returns The resource limit associated with the category + */ + static SharedPtr<ResourceLimit> GetForCategory(ResourceLimitCategory category); + + std::string GetTypeName() const override { return "ResourceLimit"; } + std::string GetName() const override { return name; } + + static const HandleType HANDLE_TYPE = HandleType::ResourceLimit; + HandleType GetHandleType() const override { return HANDLE_TYPE; } + + /** + * Gets the current value for the specified resource. + * @param resource Requested resource type + * @returns The current value of the resource type + */ + s32 GetCurrentResourceValue(u32 resource) const; + + /** + * Gets the max value for the specified resource. + * @param resource Requested resource type + * @returns The max value of the resource type + */ + s32 GetMaxResourceValue(u32 resource) const; + + /// Name of resource limit object. + std::string name; + + /// Max thread priority that a process in this category can create + s32 max_priority = 0; + + /// Max memory that processes in this category can use + s32 max_commit = 0; + + ///< Max number of objects that can be collectively created by the processes in this category + s32 max_threads = 0; + s32 max_events = 0; + s32 max_mutexes = 0; + s32 max_semaphores = 0; + s32 max_timers = 0; + s32 max_shared_mems = 0; + s32 max_address_arbiters = 0; + + /// Max CPU time that the processes in this category can utilize + s32 max_cpu_time = 0; + + // TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind that + // APPLICATION resource limits should not be affected by the objects created by service modules. + // Currently we have no way of distinguishing if a Create was called by the running application, + // or by a service module. Approach this once we have separated the service modules into their own processes + + /// Current memory that the processes in this category are using + s32 current_commit = 0; + + ///< Current number of objects among all processes in this category + s32 current_threads = 0; + s32 current_events = 0; + s32 current_mutexes = 0; + s32 current_semaphores = 0; + s32 current_timers = 0; + s32 current_shared_mems = 0; + s32 current_address_arbiters = 0; + + /// Current CPU time that the processes in this category are utilizing + s32 current_cpu_time = 0; + +private: + ResourceLimit(); + ~ResourceLimit() override; +}; + +/// Initializes the resource limits +void ResourceLimitsInit(); + +// Destroys the resource limits +void ResourceLimitsShutdown(); + +} // namespace diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index 8c3886ffd..54a062971 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h @@ -6,7 +6,7 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/thread.h" -#include "core/mem_map.h" +#include "core/memory.h" namespace Kernel { diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 0c59f4876..4137683b5 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -6,7 +6,7 @@ #include "common/logging/log.h" -#include "core/mem_map.h" +#include "core/memory.h" #include "core/hle/kernel/shared_memory.h" namespace Kernel { diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index afaf0cd5d..a5f1904d7 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -21,7 +21,7 @@ #include "core/hle/kernel/thread.h" #include "core/hle/kernel/mutex.h" #include "core/hle/result.h" -#include "core/mem_map.h" +#include "core/memory.h" namespace Kernel { @@ -495,7 +495,7 @@ void Reschedule() { LOG_TRACE(Kernel, "context switch %u -> %u", cur->GetObjectId(), next->GetObjectId()); } else if (cur) { LOG_TRACE(Kernel, "context switch %u -> idle", cur->GetObjectId()); - } else { + } else if (next) { LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId()); } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 6b329c12a..389928178 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -12,7 +12,6 @@ #include "common/common_types.h" #include "core/core.h" -#include "core/mem_map.h" #include "core/hle/kernel/kernel.h" #include "core/hle/result.h" diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 09d463dd5..3fd4cfb08 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -269,8 +269,6 @@ void GetAppCpuTimeLimit(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 value = cmd_buff[1]; - ASSERT(cpu_percent != 0); - if (value != 1) { LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value); } diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index 0d2a426b0..b25c8941d 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -650,7 +650,7 @@ static void SetPriority(Service::Interface* self) { cmd_buff[1] = RESULT_SUCCESS.raw; - LOG_DEBUG(Service_FS, "called priority=0x%08X", priority); + LOG_DEBUG(Service_FS, "called priority=0x%X", priority); } /** @@ -664,12 +664,14 @@ static void SetPriority(Service::Interface* self) { static void GetPriority(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - ASSERT(priority != -1); + if (priority == -1) { + LOG_INFO(Service_FS, "priority was not set, priority=0x%X", priority); + } cmd_buff[1] = RESULT_SUCCESS.raw; cmd_buff[2] = priority; - LOG_DEBUG(Service_FS, "called priority=0x%08X", priority); + LOG_DEBUG(Service_FS, "called priority=0x%X", priority); } const Interface::FunctionInfo FunctionTable[] = { diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index c6252a03b..c11c5faba 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -5,6 +5,7 @@ #include "common/bit_field.h" #include "core/mem_map.h" +#include "core/memory.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/result.h" diff --git a/src/core/hle/shared_page.cpp b/src/core/hle/shared_page.cpp index 4f227a370..4014eee98 100644 --- a/src/core/hle/shared_page.cpp +++ b/src/core/hle/shared_page.cpp @@ -8,7 +8,7 @@ #include "common/common_funcs.h" #include "core/core.h" -#include "core/mem_map.h" +#include "core/memory.h" #include "core/hle/config_mem.h" #include "core/hle/shared_page.h" @@ -16,63 +16,12 @@ namespace SharedPage { -// see http://3dbrew.org/wiki/Configuration_Memory#Shared_Memory_Page_For_ARM11_Processes +SharedPageDef shared_page; -#pragma pack(1) -struct DateTime { - u64 date_time; // 0x0 - u64 update_tick; // 0x8 - INSERT_PADDING_BYTES(0x20 - 0x10); // 0x10 -}; - -struct SharedPageDef { - // most of these names are taken from the 3dbrew page linked above. - u32 date_time_selector; // 0x0 - u8 running_hw; // 0x4 - u8 mcu_hw_info; // 0x5: don't know what the acronyms mean - INSERT_PADDING_BYTES(0x20 - 0x6); // 0x6 - DateTime date_time_0; // 0x20 - DateTime date_time_1; // 0x40 - u8 wifi_macaddr[6]; // 0x60 - u8 wifi_unknown1; // 0x66: 3dbrew says these are "Likely wifi hardware related" - u8 wifi_unknown2; // 0x67 - INSERT_PADDING_BYTES(0x80 - 0x68); // 0x68 - float sliderstate_3d; // 0x80 - u8 ledstate_3d; // 0x84 - INSERT_PADDING_BYTES(0xA0 - 0x85); // 0x85 - u64 menu_title_id; // 0xA0 - u64 active_menu_title_id; // 0xA8 - INSERT_PADDING_BYTES(0x1000 - 0xB0); // 0xB0 -}; -#pragma pack() - -static_assert(sizeof(DateTime) == 0x20, "Datetime size is wrong"); -static_assert(sizeof(SharedPageDef) == Memory::SHARED_PAGE_SIZE, "Shared page structure size is wrong"); - -static SharedPageDef shared_page; - -template <typename T> -inline void Read(T &var, const u32 addr) { - u32 offset = addr - Memory::SHARED_PAGE_VADDR; - var = *(reinterpret_cast<T*>(((uintptr_t)&shared_page) + offset)); -} - -// Explicitly instantiate template functions because we aren't defining this in the header: -template void Read<u64>(u64 &var, const u32 addr); -template void Read<u32>(u32 &var, const u32 addr); -template void Read<u16>(u16 &var, const u32 addr); -template void Read<u8>(u8 &var, const u32 addr); - -void Set3DSlider(float amount) { +void Init() { std::memset(&shared_page, 0, sizeof(shared_page)); - shared_page.sliderstate_3d = amount; - shared_page.ledstate_3d = (amount == 0.0f); // off when non-zero -} - -void Init() { shared_page.running_hw = 0x1; // product - Set3DSlider(0.0f); } void Shutdown() { diff --git a/src/core/hle/shared_page.h b/src/core/hle/shared_page.h index 1b6e4e581..fd2ab66a2 100644 --- a/src/core/hle/shared_page.h +++ b/src/core/hle/shared_page.h @@ -11,18 +11,46 @@ */ #include "common/common_types.h" +#include "common/swap.h" //////////////////////////////////////////////////////////////////////////////////////////////////// namespace SharedPage { -template <typename T> -void Read(T &var, const u32 addr); - -void Set3DSlider(float amount); +// See http://3dbrew.org/wiki/Configuration_Memory#Shared_Memory_Page_For_ARM11_Processes + +struct DateTime { + u64_le date_time; // 0 + u64_le update_tick; // 8 + INSERT_PADDING_BYTES(0x20 - 0x10); // 10 +}; +static_assert(sizeof(DateTime) == 0x20, "Datetime size is wrong"); + +struct SharedPageDef { + // Most of these names are taken from the 3dbrew page linked above. + u32_le date_time_selector; // 0 + u8 running_hw; // 4 + /// "Microcontroller hardware info" + u8 mcu_hw_info; // 5 + INSERT_PADDING_BYTES(0x20 - 0x6); // 6 + DateTime date_time_0; // 20 + DateTime date_time_1; // 40 + u8 wifi_macaddr[6]; // 60 + u8 wifi_unknown1; // 66 + u8 wifi_unknown2; // 67 + INSERT_PADDING_BYTES(0x80 - 0x68); // 68 + float_le sliderstate_3d; // 80 + u8 ledstate_3d; // 84 + INSERT_PADDING_BYTES(0xA0 - 0x85); // 85 + u64_le menu_title_id; // A0 + u64_le active_menu_title_id; // A8 + INSERT_PADDING_BYTES(0x1000 - 0xB0); // B0 +}; +static_assert(sizeof(SharedPageDef) == Memory::SHARED_PAGE_SIZE, "Shared page structure size is wrong"); + +extern SharedPageDef shared_page; void Init(); - void Shutdown(); } // namespace diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index e8159fbdb..22adf9595 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -17,6 +17,7 @@ #include "core/hle/kernel/event.h" #include "core/hle/kernel/mutex.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/semaphore.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/thread.h" @@ -295,27 +296,65 @@ static ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 val return res; } +static void Break(u8 break_reason) { + LOG_CRITICAL(Debug_Emulated, "Emulated program broke execution!"); + std::string reason_str; + switch (break_reason) { + case 0: reason_str = "PANIC"; break; + case 1: reason_str = "ASSERT"; break; + case 2: reason_str = "USER"; break; + default: reason_str = "UNKNOWN"; break; + } + LOG_CRITICAL(Debug_Emulated, "Break reason: %s", reason_str.c_str()); +} + /// Used to output a message on a debug hardware unit - does nothing on a retail unit static void OutputDebugString(const char* string) { LOG_DEBUG(Debug_Emulated, "%s", string); } /// Get resource limit -static ResultCode GetResourceLimit(Handle* resource_limit, Handle process) { - // With regards to proceess values: - // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for - // the current KThread. - *resource_limit = 0xDEADBEEF; - LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called process=0x%08X", process); +static ResultCode GetResourceLimit(Handle* resource_limit, Handle process_handle) { + LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle); + + SharedPtr<Kernel::Process> process = Kernel::g_handle_table.Get<Kernel::Process>(process_handle); + if (process == nullptr) + return ERR_INVALID_HANDLE; + + CASCADE_RESULT(*resource_limit, Kernel::g_handle_table.Create(process->resource_limit)); + return RESULT_SUCCESS; } /// Get resource limit current values -static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names, +static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_limit_handle, u32* names, s32 name_count) { - LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%p, name_count=%d", - resource_limit, names, name_count); - Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now + LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d", + resource_limit_handle, names, name_count); + + SharedPtr<Kernel::ResourceLimit> resource_limit = Kernel::g_handle_table.Get<Kernel::ResourceLimit>(resource_limit_handle); + if (resource_limit == nullptr) + return ERR_INVALID_HANDLE; + + for (unsigned int i = 0; i < name_count; ++i) + values[i] = resource_limit->GetCurrentResourceValue(names[i]); + + return RESULT_SUCCESS; +} + +/// Get resource limit max values +static ResultCode GetResourceLimitLimitValues(s64* values, Handle resource_limit_handle, u32* names, + s32 name_count) { + LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d", + resource_limit_handle, names, name_count); + + SharedPtr<Kernel::ResourceLimit> resource_limit = Kernel::g_handle_table.Get<Kernel::ResourceLimit>(resource_limit_handle); + if (resource_limit == nullptr) + return ERR_INVALID_HANDLE; + + for (unsigned int i = 0; i < name_count; ++i) + values[i] = resource_limit->GetMaxResourceValue(names[i]); + return RESULT_SUCCESS; } @@ -707,10 +746,10 @@ static const FunctionDef SVC_Table[] = { {0x36, HLE::Wrap<GetProcessIdOfThread>, "GetProcessIdOfThread"}, {0x37, HLE::Wrap<GetThreadId>, "GetThreadId"}, {0x38, HLE::Wrap<GetResourceLimit>, "GetResourceLimit"}, - {0x39, nullptr, "GetResourceLimitLimitValues"}, + {0x39, HLE::Wrap<GetResourceLimitLimitValues>, "GetResourceLimitLimitValues"}, {0x3A, HLE::Wrap<GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"}, {0x3B, nullptr, "GetThreadContext"}, - {0x3C, nullptr, "Break"}, + {0x3C, HLE::Wrap<Break>, "Break"}, {0x3D, HLE::Wrap<OutputDebugString>, "OutputDebugString"}, {0x3E, nullptr, "ControlPerformanceCounter"}, {0x3F, nullptr, "Unknown"}, diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index e4a0e14c4..8ef1f70df 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp @@ -8,7 +8,7 @@ #include "core/settings.h" #include "core/core.h" -#include "core/mem_map.h" +#include "core/memory.h" #include "core/core_timing.h" #include "core/hle/hle.h" diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp index e28986085..ad5e929ce 100644 --- a/src/core/loader/3dsx.cpp +++ b/src/core/loader/3dsx.cpp @@ -9,10 +9,11 @@ #include "core/file_sys/archive_romfs.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/resource_limit.h" #include "core/hle/service/fs/archive.h" #include "core/loader/elf.h" #include "core/loader/ncch.h" -#include "core/mem_map.h" +#include "core/memory.h" #include "3dsx.h" @@ -233,6 +234,9 @@ ResultStatus AppLoader_THREEDSX::Load() { Kernel::g_current_process = Kernel::Process::Create(filename, 0); Kernel::g_current_process->svc_access_mask.set(); Kernel::g_current_process->address_mappings = default_address_mappings; + + // Attach the default resource limit (APPLICATION) to the process + Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); Load3DSXFile(*file, Memory::PROCESS_IMAGE_VADDR); diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 47d4e8cea..f00753a79 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -11,8 +11,9 @@ #include "common/symbols.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/resource_limit.h" #include "core/loader/elf.h" -#include "core/mem_map.h" +#include "core/memory.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // ELF Header Constants @@ -354,6 +355,9 @@ ResultStatus AppLoader_ELF::Load() { Kernel::g_current_process->svc_access_mask.set(); Kernel::g_current_process->address_mappings = default_address_mappings; + // Attach the default resource limit (APPLICATION) to the process + Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); + ElfReader elf_reader(&buffer[0]); elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR); // TODO: Fill application title diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 4f881cf6f..8b14edf00 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -13,7 +13,6 @@ #include "core/loader/3dsx.h" #include "core/loader/elf.h" #include "core/loader/ncch.h" -#include "core/mem_map.h" //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index 3325a6ab8..08993c4fa 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp @@ -11,8 +11,9 @@ #include "common/swap.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/resource_limit.h" #include "core/loader/ncch.h" -#include "core/mem_map.h" +#include "core/memory.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // Loader namespace @@ -126,6 +127,10 @@ ResultStatus AppLoader_NCCH::LoadExec() const { u64 program_id = *reinterpret_cast<u64_le const*>(&ncch_header.program_id[0]); Kernel::g_current_process = Kernel::Process::Create(process_name, program_id); + // Attach a resource limit to the process based on the resource limit category + Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory( + static_cast<Kernel::ResourceLimitCategory>(exheader_header.arm11_system_local_caps.resource_limit_category)); + // Copy data while converting endianess std::array<u32, ARRAY_SIZE(exheader_header.arm11_kernel_caps.descriptors)> kernel_caps; std::copy_n(exheader_header.arm11_kernel_caps.descriptors, kernel_caps.size(), begin(kernel_caps)); diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp index f99520464..5ecec9566 100644 --- a/src/core/mem_map.cpp +++ b/src/core/mem_map.cpp @@ -2,10 +2,16 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <map> + #include "common/common_types.h" #include "common/logging/log.h" +#include "core/hle/config_mem.h" +#include "core/hle/shared_page.h" #include "core/mem_map.h" +#include "core/memory.h" +#include "core/memory_setup.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -23,33 +29,129 @@ namespace { struct MemoryArea { u8** ptr; - size_t size; + u32 base; + u32 size; }; // We don't declare the IO regions in here since its handled by other means. static MemoryArea memory_areas[] = { - {&g_exefs_code, PROCESS_IMAGE_MAX_SIZE}, - {&g_heap, HEAP_SIZE }, - {&g_shared_mem, SHARED_MEMORY_SIZE }, - {&g_heap_linear, LINEAR_HEAP_SIZE }, - {&g_vram, VRAM_SIZE }, - {&g_dsp_mem, DSP_RAM_SIZE }, - {&g_tls_mem, TLS_AREA_SIZE }, + {&g_exefs_code, PROCESS_IMAGE_VADDR, PROCESS_IMAGE_MAX_SIZE}, + {&g_heap, HEAP_VADDR, HEAP_SIZE }, + {&g_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE }, + {&g_heap_linear, LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE }, + {&g_vram, VRAM_VADDR, VRAM_SIZE }, + {&g_dsp_mem, DSP_RAM_VADDR, DSP_RAM_SIZE }, + {&g_tls_mem, TLS_AREA_VADDR, TLS_AREA_SIZE }, +}; + +/// Represents a block of memory mapped by ControlMemory/MapMemoryBlock +struct MemoryBlock { + MemoryBlock() : handle(0), base_address(0), address(0), size(0), operation(0), permissions(0) { + } + u32 handle; + u32 base_address; + u32 address; + u32 size; + u32 operation; + u32 permissions; + + const u32 GetVirtualAddress() const{ + return base_address + address; + } }; +static std::map<u32, MemoryBlock> heap_map; +static std::map<u32, MemoryBlock> heap_linear_map; + +} + +u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions) { + MemoryBlock block; + + block.base_address = HEAP_VADDR; + block.size = size; + block.operation = operation; + block.permissions = permissions; + + if (heap_map.size() > 0) { + const MemoryBlock last_block = heap_map.rbegin()->second; + block.address = last_block.address + last_block.size; + } + heap_map[block.GetVirtualAddress()] = block; + + return block.GetVirtualAddress(); +} + +u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions) { + MemoryBlock block; + + block.base_address = LINEAR_HEAP_VADDR; + block.size = size; + block.operation = operation; + block.permissions = permissions; + + if (heap_linear_map.size() > 0) { + const MemoryBlock last_block = heap_linear_map.rbegin()->second; + block.address = last_block.address + last_block.size; + } + heap_linear_map[block.GetVirtualAddress()] = block; + + return block.GetVirtualAddress(); +} + +PAddr VirtualToPhysicalAddress(const VAddr addr) { + if (addr == 0) { + return 0; + } else if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) { + return addr - VRAM_VADDR + VRAM_PADDR; + } else if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) { + return addr - LINEAR_HEAP_VADDR + FCRAM_PADDR; + } else if (addr >= DSP_RAM_VADDR && addr < DSP_RAM_VADDR_END) { + return addr - DSP_RAM_VADDR + DSP_RAM_PADDR; + } else if (addr >= IO_AREA_VADDR && addr < IO_AREA_VADDR_END) { + return addr - IO_AREA_VADDR + IO_AREA_PADDR; + } + + LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x%08x", addr); + // To help with debugging, set bit on address so that it's obviously invalid. + return addr | 0x80000000; +} + +VAddr PhysicalToVirtualAddress(const PAddr addr) { + if (addr == 0) { + return 0; + } else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) { + return addr - VRAM_PADDR + VRAM_VADDR; + } else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) { + return addr - FCRAM_PADDR + LINEAR_HEAP_VADDR; + } else if (addr >= DSP_RAM_PADDR && addr < DSP_RAM_PADDR_END) { + return addr - DSP_RAM_PADDR + DSP_RAM_VADDR; + } else if (addr >= IO_AREA_PADDR && addr < IO_AREA_PADDR_END) { + return addr - IO_AREA_PADDR + IO_AREA_VADDR; + } + + LOG_ERROR(HW_Memory, "Unknown physical address @ 0x%08x", addr); + // To help with debugging, set bit on address so that it's obviously invalid. + return addr | 0x80000000; } void Init() { + InitMemoryMap(); + for (MemoryArea& area : memory_areas) { *area.ptr = new u8[area.size]; + MapMemoryRegion(area.base, area.size, *area.ptr); } - MemBlock_Init(); + MapMemoryRegion(CONFIG_MEMORY_VADDR, CONFIG_MEMORY_SIZE, (u8*)&ConfigMem::config_mem); + MapMemoryRegion(SHARED_PAGE_VADDR, SHARED_PAGE_SIZE, (u8*)&SharedPage::shared_page); LOG_DEBUG(HW_Memory, "initialized OK, RAM at %p", g_heap); } void Shutdown() { - MemBlock_Shutdown(); + heap_map.clear(); + heap_linear_map.clear(); + for (MemoryArea& area : memory_areas) { delete[] *area.ptr; *area.ptr = nullptr; diff --git a/src/core/mem_map.h b/src/core/mem_map.h index 71f90cb8a..945815cd6 100644 --- a/src/core/mem_map.h +++ b/src/core/mem_map.h @@ -8,121 +8,6 @@ namespace Memory { -//////////////////////////////////////////////////////////////////////////////////////////////////// - -const u32 PAGE_SIZE = 0x1000; - -/// Physical memory regions as seen from the ARM11 -enum : PAddr { - /// IO register area - IO_AREA_PADDR = 0x10100000, - IO_AREA_SIZE = 0x01000000, ///< IO area size (16MB) - IO_AREA_PADDR_END = IO_AREA_PADDR + IO_AREA_SIZE, - - /// MPCore internal memory region - MPCORE_RAM_PADDR = 0x17E00000, - MPCORE_RAM_SIZE = 0x00002000, ///< MPCore internal memory size (8KB) - MPCORE_RAM_PADDR_END = MPCORE_RAM_PADDR + MPCORE_RAM_SIZE, - - /// Video memory - VRAM_PADDR = 0x18000000, - VRAM_SIZE = 0x00600000, ///< VRAM size (6MB) - VRAM_PADDR_END = VRAM_PADDR + VRAM_SIZE, - - /// DSP memory - DSP_RAM_PADDR = 0x1FF00000, - DSP_RAM_SIZE = 0x00080000, ///< DSP memory size (512KB) - DSP_RAM_PADDR_END = DSP_RAM_PADDR + DSP_RAM_SIZE, - - /// AXI WRAM - AXI_WRAM_PADDR = 0x1FF80000, - AXI_WRAM_SIZE = 0x00080000, ///< AXI WRAM size (512KB) - AXI_WRAM_PADDR_END = AXI_WRAM_PADDR + AXI_WRAM_SIZE, - - /// Main FCRAM - FCRAM_PADDR = 0x20000000, - FCRAM_SIZE = 0x08000000, ///< FCRAM size (128MB) - FCRAM_PADDR_END = FCRAM_PADDR + FCRAM_SIZE, -}; - -/// Virtual user-space memory regions -enum : VAddr { - /// Where the application text, data and bss reside. - PROCESS_IMAGE_VADDR = 0x00100000, - PROCESS_IMAGE_MAX_SIZE = 0x03F00000, - PROCESS_IMAGE_VADDR_END = PROCESS_IMAGE_VADDR + PROCESS_IMAGE_MAX_SIZE, - - /// Area where IPC buffers are mapped onto. - IPC_MAPPING_VADDR = 0x04000000, - IPC_MAPPING_SIZE = 0x04000000, - IPC_MAPPING_VADDR_END = IPC_MAPPING_VADDR + IPC_MAPPING_SIZE, - - /// Application heap (includes stack). - HEAP_VADDR = 0x08000000, - HEAP_SIZE = 0x08000000, - HEAP_VADDR_END = HEAP_VADDR + HEAP_SIZE, - - /// Area where shared memory buffers are mapped onto. - SHARED_MEMORY_VADDR = 0x10000000, - SHARED_MEMORY_SIZE = 0x04000000, - SHARED_MEMORY_VADDR_END = SHARED_MEMORY_VADDR + SHARED_MEMORY_SIZE, - - /// Maps 1:1 to an offset in FCRAM. Used for HW allocations that need to be linear in physical memory. - LINEAR_HEAP_VADDR = 0x14000000, - LINEAR_HEAP_SIZE = 0x08000000, - LINEAR_HEAP_VADDR_END = LINEAR_HEAP_VADDR + LINEAR_HEAP_SIZE, - - /// Maps 1:1 to the IO register area. - IO_AREA_VADDR = 0x1EC00000, - IO_AREA_VADDR_END = IO_AREA_VADDR + IO_AREA_SIZE, - - /// Maps 1:1 to VRAM. - VRAM_VADDR = 0x1F000000, - VRAM_VADDR_END = VRAM_VADDR + VRAM_SIZE, - - /// Maps 1:1 to DSP memory. - DSP_RAM_VADDR = 0x1FF00000, - DSP_RAM_VADDR_END = DSP_RAM_VADDR + DSP_RAM_SIZE, - - /// Read-only page containing kernel and system configuration values. - CONFIG_MEMORY_VADDR = 0x1FF80000, - CONFIG_MEMORY_SIZE = 0x00001000, - CONFIG_MEMORY_VADDR_END = CONFIG_MEMORY_VADDR + CONFIG_MEMORY_SIZE, - - /// Usually read-only page containing mostly values read from hardware. - SHARED_PAGE_VADDR = 0x1FF81000, - SHARED_PAGE_SIZE = 0x00001000, - SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE, - - // TODO(yuriks): The size of this area is dynamic, the kernel grows - // it as more and more threads are created. For now we'll just use a - // hardcoded value. - /// Area where TLS (Thread-Local Storage) buffers are allocated. - TLS_AREA_VADDR = 0x1FF82000, - TLS_AREA_SIZE = 0x00030000, // Each TLS buffer is 0x200 bytes, allows for 300 threads - TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/// Represents a block of memory mapped by ControlMemory/MapMemoryBlock -struct MemoryBlock { - MemoryBlock() : handle(0), base_address(0), address(0), size(0), operation(0), permissions(0) { - } - u32 handle; - u32 base_address; - u32 address; - u32 size; - u32 operation; - u32 permissions; - - const u32 GetVirtualAddress() const{ - return base_address + address; - } -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// - extern u8* g_exefs_code; ///< ExeFS:/.code is loaded here extern u8* g_heap; ///< Application heap (main memory) extern u8* g_shared_mem; ///< Shared memory @@ -134,29 +19,6 @@ extern u8* g_tls_mem; ///< TLS memory void Init(); void Shutdown(); -template <typename T> -inline void Read(T &var, VAddr addr); - -template <typename T> -inline void Write(VAddr addr, T data); - -u8 Read8(VAddr addr); -u16 Read16(VAddr addr); -u32 Read32(VAddr addr); -u64 Read64(VAddr addr); - -u32 Read8_ZX(VAddr addr); -u32 Read16_ZX(VAddr addr); - -void Write8(VAddr addr, u8 data); -void Write16(VAddr addr, u16 data); -void Write32(VAddr addr, u32 data); -void Write64(VAddr addr, u64 data); - -void WriteBlock(VAddr addr, const u8* data, size_t size); - -u8* GetPointer(VAddr virtual_address); - /** * Maps a block of memory on the heap * @param size Size of block in bytes @@ -173,16 +35,6 @@ u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions); */ u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions); -/// Initialize mapped memory blocks -void MemBlock_Init(); - -/// Shutdown mapped memory blocks -void MemBlock_Shutdown(); - -inline const char* GetCharPointer(const VAddr address) { - return (const char *)GetPointer(address); -} - /** * Converts a virtual address inside a region with 1:1 mapping to physical memory to a physical * address. This should be used by services to translate addresses for use by the hardware. @@ -194,13 +46,4 @@ PAddr VirtualToPhysicalAddress(VAddr addr); */ VAddr PhysicalToVirtualAddress(PAddr addr); -/** - * Gets a pointer to the memory region beginning at the specified physical address. - * - * @note This is currently implemented using PhysicalToVirtualAddress(). - */ -inline u8* GetPhysicalPointer(PAddr address) { - return GetPointer(PhysicalToVirtualAddress(address)); -} - } // namespace diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp deleted file mode 100644 index a8e0fed07..000000000 --- a/src/core/mem_map_funcs.cpp +++ /dev/null @@ -1,283 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <map> - -#include "common/common_types.h" -#include "common/logging/log.h" -#include "common/swap.h" - -#include "core/mem_map.h" -#include "core/hw/hw.h" -#include "hle/config_mem.h" -#include "hle/shared_page.h" - -namespace Memory { - -static std::map<u32, MemoryBlock> heap_map; -static std::map<u32, MemoryBlock> heap_linear_map; - -PAddr VirtualToPhysicalAddress(const VAddr addr) { - if (addr == 0) { - return 0; - } else if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) { - return addr - VRAM_VADDR + VRAM_PADDR; - } else if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) { - return addr - LINEAR_HEAP_VADDR + FCRAM_PADDR; - } else if (addr >= DSP_RAM_VADDR && addr < DSP_RAM_VADDR_END) { - return addr - DSP_RAM_VADDR + DSP_RAM_PADDR; - } else if (addr >= IO_AREA_VADDR && addr < IO_AREA_VADDR_END) { - return addr - IO_AREA_VADDR + IO_AREA_PADDR; - } - - LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x%08x", addr); - // To help with debugging, set bit on address so that it's obviously invalid. - return addr | 0x80000000; -} - -VAddr PhysicalToVirtualAddress(const PAddr addr) { - if (addr == 0) { - return 0; - } else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) { - return addr - VRAM_PADDR + VRAM_VADDR; - } else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) { - return addr - FCRAM_PADDR + LINEAR_HEAP_VADDR; - } else if (addr >= DSP_RAM_PADDR && addr < DSP_RAM_PADDR_END) { - return addr - DSP_RAM_PADDR + DSP_RAM_VADDR; - } else if (addr >= IO_AREA_PADDR && addr < IO_AREA_PADDR_END) { - return addr - IO_AREA_PADDR + IO_AREA_VADDR; - } - - LOG_ERROR(HW_Memory, "Unknown physical address @ 0x%08x", addr); - // To help with debugging, set bit on address so that it's obviously invalid. - return addr | 0x80000000; -} - -template <typename T> -inline void Read(T &var, const VAddr vaddr) { - // TODO: Figure out the fastest order of tests for both read and write (they are probably different). - // TODO: Make sure this represents the mirrors in a correct way. - // Could just do a base-relative read, too.... TODO - - // Kernel memory command buffer - if (vaddr >= TLS_AREA_VADDR && vaddr < TLS_AREA_VADDR_END) { - var = *((const T*)&g_tls_mem[vaddr - TLS_AREA_VADDR]); - - // ExeFS:/.code is loaded here - } else if ((vaddr >= PROCESS_IMAGE_VADDR) && (vaddr < PROCESS_IMAGE_VADDR_END)) { - var = *((const T*)&g_exefs_code[vaddr - PROCESS_IMAGE_VADDR]); - - // FCRAM - linear heap - } else if ((vaddr >= LINEAR_HEAP_VADDR) && (vaddr < LINEAR_HEAP_VADDR_END)) { - var = *((const T*)&g_heap_linear[vaddr - LINEAR_HEAP_VADDR]); - - // FCRAM - application heap - } else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) { - var = *((const T*)&g_heap[vaddr - HEAP_VADDR]); - - // Shared memory - } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) { - var = *((const T*)&g_shared_mem[vaddr - SHARED_MEMORY_VADDR]); - - // Config memory - } else if ((vaddr >= CONFIG_MEMORY_VADDR) && (vaddr < CONFIG_MEMORY_VADDR_END)) { - ConfigMem::Read<T>(var, vaddr); - - // Shared page - } else if ((vaddr >= SHARED_PAGE_VADDR) && (vaddr < SHARED_PAGE_VADDR_END)) { - SharedPage::Read<T>(var, vaddr); - - // DSP memory - } else if ((vaddr >= DSP_RAM_VADDR) && (vaddr < DSP_RAM_VADDR_END)) { - var = *((const T*)&g_dsp_mem[vaddr - DSP_RAM_VADDR]); - - // VRAM - } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) { - var = *((const T*)&g_vram[vaddr - VRAM_VADDR]); - - } else { - LOG_ERROR(HW_Memory, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, vaddr); - } -} - -template <typename T> -inline void Write(const VAddr vaddr, const T data) { - - // Kernel memory command buffer - if (vaddr >= TLS_AREA_VADDR && vaddr < TLS_AREA_VADDR_END) { - *(T*)&g_tls_mem[vaddr - TLS_AREA_VADDR] = data; - - // ExeFS:/.code is loaded here - } else if ((vaddr >= PROCESS_IMAGE_VADDR) && (vaddr < PROCESS_IMAGE_VADDR_END)) { - *(T*)&g_exefs_code[vaddr - PROCESS_IMAGE_VADDR] = data; - - // FCRAM - linear heap - } else if ((vaddr >= LINEAR_HEAP_VADDR) && (vaddr < LINEAR_HEAP_VADDR_END)) { - *(T*)&g_heap_linear[vaddr - LINEAR_HEAP_VADDR] = data; - - // FCRAM - application heap - } else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) { - *(T*)&g_heap[vaddr - HEAP_VADDR] = data; - - // Shared memory - } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) { - *(T*)&g_shared_mem[vaddr - SHARED_MEMORY_VADDR] = data; - - // VRAM - } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) { - *(T*)&g_vram[vaddr - VRAM_VADDR] = data; - - // DSP memory - } else if ((vaddr >= DSP_RAM_VADDR) && (vaddr < DSP_RAM_VADDR_END)) { - *(T*)&g_dsp_mem[vaddr - DSP_RAM_VADDR] = data; - - //} else if ((vaddr & 0xFFFF0000) == 0x1FF80000) { - // ASSERT_MSG(MEMMAP, false, "umimplemented write to Configuration Memory"); - //} else if ((vaddr & 0xFFFFF000) == 0x1FF81000) { - // ASSERT_MSG(MEMMAP, false, "umimplemented write to shared page"); - - // Error out... - } else { - LOG_ERROR(HW_Memory, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, vaddr); - } -} - -u8 *GetPointer(const VAddr vaddr) { - // Kernel memory command buffer - if (vaddr >= TLS_AREA_VADDR && vaddr < TLS_AREA_VADDR_END) { - return g_tls_mem + (vaddr - TLS_AREA_VADDR); - - // ExeFS:/.code is loaded here - } else if ((vaddr >= PROCESS_IMAGE_VADDR) && (vaddr < PROCESS_IMAGE_VADDR_END)) { - return g_exefs_code + (vaddr - PROCESS_IMAGE_VADDR); - - // FCRAM - linear heap - } else if ((vaddr >= LINEAR_HEAP_VADDR) && (vaddr < LINEAR_HEAP_VADDR_END)) { - return g_heap_linear + (vaddr - LINEAR_HEAP_VADDR); - - // FCRAM - application heap - } else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) { - return g_heap + (vaddr - HEAP_VADDR); - - // Shared memory - } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) { - return g_shared_mem + (vaddr - SHARED_MEMORY_VADDR); - - // VRAM - } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) { - return g_vram + (vaddr - VRAM_VADDR); - - } else { - LOG_ERROR(HW_Memory, "unknown GetPointer @ 0x%08x", vaddr); - return 0; - } -} - -u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions) { - MemoryBlock block; - - block.base_address = HEAP_VADDR; - block.size = size; - block.operation = operation; - block.permissions = permissions; - - if (heap_map.size() > 0) { - const MemoryBlock last_block = heap_map.rbegin()->second; - block.address = last_block.address + last_block.size; - } - heap_map[block.GetVirtualAddress()] = block; - - return block.GetVirtualAddress(); -} - -u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions) { - MemoryBlock block; - - block.base_address = LINEAR_HEAP_VADDR; - block.size = size; - block.operation = operation; - block.permissions = permissions; - - if (heap_linear_map.size() > 0) { - const MemoryBlock last_block = heap_linear_map.rbegin()->second; - block.address = last_block.address + last_block.size; - } - heap_linear_map[block.GetVirtualAddress()] = block; - - return block.GetVirtualAddress(); -} - -void MemBlock_Init() { -} - -void MemBlock_Shutdown() { - heap_map.clear(); - heap_linear_map.clear(); -} - -u8 Read8(const VAddr addr) { - u8 data = 0; - Read<u8>(data, addr); - return data; -} - -u16 Read16(const VAddr addr) { - u16_le data = 0; - Read<u16_le>(data, addr); - return (u16)data; -} - -u32 Read32(const VAddr addr) { - u32_le data = 0; - Read<u32_le>(data, addr); - return (u32)data; -} - -u64 Read64(const VAddr addr) { - u64_le data = 0; - Read<u64_le>(data, addr); - return (u64)data; -} - -u32 Read8_ZX(const VAddr addr) { - return (u32)Read8(addr); -} - -u32 Read16_ZX(const VAddr addr) { - return (u32)Read16(addr); -} - -void Write8(const VAddr addr, const u8 data) { - Write<u8>(addr, data); -} - -void Write16(const VAddr addr, const u16 data) { - Write<u16_le>(addr, data); -} - -void Write32(const VAddr addr, const u32 data) { - Write<u32_le>(addr, data); -} - -void Write64(const VAddr addr, const u64 data) { - Write<u64_le>(addr, data); -} - -void WriteBlock(const VAddr addr, const u8* data, const size_t size) { - u32 offset = 0; - while (offset < (size & ~3)) { - Write32(addr + offset, *(u32*)&data[offset]); - offset += 4; - } - - if (size & 2) { - Write16(addr + offset, *(u16*)&data[offset]); - offset += 2; - } - - if (size & 1) - Write8(addr + offset, data[offset]); -} - -} // namespace diff --git a/src/core/memory.cpp b/src/core/memory.cpp new file mode 100644 index 000000000..5d8069acd --- /dev/null +++ b/src/core/memory.cpp @@ -0,0 +1,202 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <array> + +#include "common/assert.h" +#include "common/common_types.h" +#include "common/logging/log.h" +#include "common/swap.h" + +#include "core/hle/config_mem.h" +#include "core/hle/shared_page.h" +#include "core/hw/hw.h" +#include "core/mem_map.h" +#include "core/memory.h" + +namespace Memory { + +const u32 PAGE_MASK = PAGE_SIZE - 1; +const int PAGE_BITS = 12; + +enum class PageType { + /// Page is unmapped and should cause an access error. + Unmapped, + /// Page is mapped to regular memory. This is the only type you can get pointers to. + Memory, + /// Page is mapped to a I/O region. Writing and reading to this page is handled by functions. + Special, +}; + +/** + * A (reasonably) fast way of allowing switchable and remmapable process address spaces. It loosely + * mimics the way a real CPU page table works, but instead is optimized for minimal decoding and + * fetching requirements when acessing. In the usual case of an access to regular memory, it only + * requires an indexed fetch and a check for NULL. + */ +struct PageTable { + static const size_t NUM_ENTRIES = 1 << (32 - PAGE_BITS); + + /** + * Array of memory pointers backing each page. An entry can only be non-null if the + * corresponding entry in the `attributes` array is of type `Memory`. + */ + std::array<u8*, NUM_ENTRIES> pointers; + + /** + * Array of fine grained page attributes. If it is set to any value other than `Memory`, then + * the corresponding entry in `pointer` MUST be set to null. + */ + std::array<PageType, NUM_ENTRIES> attributes; +}; + +/// Singular page table used for the singleton process +static PageTable main_page_table; +/// Currently active page table +static PageTable* current_page_table = &main_page_table; + +static void MapPages(u32 base, u32 size, u8* memory, PageType type) { + LOG_DEBUG(HW_Memory, "Mapping %p onto %08X-%08X", memory, base * PAGE_SIZE, (base + size) * PAGE_SIZE); + + u32 end = base + size; + + while (base != end) { + ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at %08X", base); + + if (current_page_table->attributes[base] != PageType::Unmapped) { + LOG_ERROR(HW_Memory, "overlapping memory ranges at %08X", base * PAGE_SIZE); + } + current_page_table->attributes[base] = type; + current_page_table->pointers[base] = memory; + + base += 1; + memory += PAGE_SIZE; + } +} + +void InitMemoryMap() { + main_page_table.pointers.fill(nullptr); + main_page_table.attributes.fill(PageType::Unmapped); +} + +void MapMemoryRegion(VAddr base, u32 size, u8* target) { + ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: %08X", size); + ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: %08X", base); + MapPages(base / PAGE_SIZE, size / PAGE_SIZE, target, PageType::Memory); +} + +void MapIoRegion(VAddr base, u32 size) { + ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: %08X", size); + ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: %08X", base); + MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special); +} + +template <typename T> +T Read(const VAddr vaddr) { + const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; + if (page_pointer) { + return *reinterpret_cast<const T*>(page_pointer + (vaddr & PAGE_MASK)); + } + + PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; + switch (type) { + case PageType::Unmapped: + LOG_ERROR(HW_Memory, "unmapped Read%lu @ 0x%08X", sizeof(T) * 8, vaddr); + return 0; + case PageType::Memory: + ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); + case PageType::Special: + LOG_ERROR(HW_Memory, "I/O reads aren't implemented yet @ %08X", vaddr); + return 0; + default: + UNREACHABLE(); + } +} + +template <typename T> +void Write(const VAddr vaddr, const T data) { + u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; + if (page_pointer) { + *reinterpret_cast<T*>(page_pointer + (vaddr & PAGE_MASK)) = data; + return; + } + + PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; + switch (type) { + case PageType::Unmapped: + LOG_ERROR(HW_Memory, "unmapped Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32) data, vaddr); + return; + case PageType::Memory: + ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); + case PageType::Special: + LOG_ERROR(HW_Memory, "I/O writes aren't implemented yet @ %08X", vaddr); + return; + default: + UNREACHABLE(); + } +} + +u8* GetPointer(const VAddr vaddr) { + u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; + if (page_pointer) { + return page_pointer + (vaddr & PAGE_MASK); + } + + LOG_ERROR(HW_Memory, "unknown GetPointer @ 0x%08x", vaddr); + return nullptr; +} + +u8* GetPhysicalPointer(PAddr address) { + return GetPointer(PhysicalToVirtualAddress(address)); +} + +u8 Read8(const VAddr addr) { + return Read<u8>(addr); +} + +u16 Read16(const VAddr addr) { + return Read<u16_le>(addr); +} + +u32 Read32(const VAddr addr) { + return Read<u32_le>(addr); +} + +u64 Read64(const VAddr addr) { + return Read<u64_le>(addr); +} + +void Write8(const VAddr addr, const u8 data) { + Write<u8>(addr, data); +} + +void Write16(const VAddr addr, const u16 data) { + Write<u16_le>(addr, data); +} + +void Write32(const VAddr addr, const u32 data) { + Write<u32_le>(addr, data); +} + +void Write64(const VAddr addr, const u64 data) { + Write<u64_le>(addr, data); +} + +void WriteBlock(const VAddr addr, const u8* data, const size_t size) { + u32 offset = 0; + while (offset < (size & ~3)) { + Write32(addr + offset, *(u32*)&data[offset]); + offset += 4; + } + + if (size & 2) { + Write16(addr + offset, *(u16*)&data[offset]); + offset += 2; + } + + if (size & 1) + Write8(addr + offset, data[offset]); +} + +} // namespace diff --git a/src/core/memory.h b/src/core/memory.h new file mode 100644 index 000000000..2d225801b --- /dev/null +++ b/src/core/memory.h @@ -0,0 +1,129 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +namespace Memory { + +/** + * Page size used by the ARM architecture. This is the smallest granularity with which memory can + * be mapped. + */ +const u32 PAGE_SIZE = 0x1000; + +/// Physical memory regions as seen from the ARM11 +enum : PAddr { + /// IO register area + IO_AREA_PADDR = 0x10100000, + IO_AREA_SIZE = 0x01000000, ///< IO area size (16MB) + IO_AREA_PADDR_END = IO_AREA_PADDR + IO_AREA_SIZE, + + /// MPCore internal memory region + MPCORE_RAM_PADDR = 0x17E00000, + MPCORE_RAM_SIZE = 0x00002000, ///< MPCore internal memory size (8KB) + MPCORE_RAM_PADDR_END = MPCORE_RAM_PADDR + MPCORE_RAM_SIZE, + + /// Video memory + VRAM_PADDR = 0x18000000, + VRAM_SIZE = 0x00600000, ///< VRAM size (6MB) + VRAM_PADDR_END = VRAM_PADDR + VRAM_SIZE, + + /// DSP memory + DSP_RAM_PADDR = 0x1FF00000, + DSP_RAM_SIZE = 0x00080000, ///< DSP memory size (512KB) + DSP_RAM_PADDR_END = DSP_RAM_PADDR + DSP_RAM_SIZE, + + /// AXI WRAM + AXI_WRAM_PADDR = 0x1FF80000, + AXI_WRAM_SIZE = 0x00080000, ///< AXI WRAM size (512KB) + AXI_WRAM_PADDR_END = AXI_WRAM_PADDR + AXI_WRAM_SIZE, + + /// Main FCRAM + FCRAM_PADDR = 0x20000000, + FCRAM_SIZE = 0x08000000, ///< FCRAM size (128MB) + FCRAM_PADDR_END = FCRAM_PADDR + FCRAM_SIZE, +}; + +/// Virtual user-space memory regions +enum : VAddr { + /// Where the application text, data and bss reside. + PROCESS_IMAGE_VADDR = 0x00100000, + PROCESS_IMAGE_MAX_SIZE = 0x03F00000, + PROCESS_IMAGE_VADDR_END = PROCESS_IMAGE_VADDR + PROCESS_IMAGE_MAX_SIZE, + + /// Area where IPC buffers are mapped onto. + IPC_MAPPING_VADDR = 0x04000000, + IPC_MAPPING_SIZE = 0x04000000, + IPC_MAPPING_VADDR_END = IPC_MAPPING_VADDR + IPC_MAPPING_SIZE, + + /// Application heap (includes stack). + HEAP_VADDR = 0x08000000, + HEAP_SIZE = 0x08000000, + HEAP_VADDR_END = HEAP_VADDR + HEAP_SIZE, + + /// Area where shared memory buffers are mapped onto. + SHARED_MEMORY_VADDR = 0x10000000, + SHARED_MEMORY_SIZE = 0x04000000, + SHARED_MEMORY_VADDR_END = SHARED_MEMORY_VADDR + SHARED_MEMORY_SIZE, + + /// Maps 1:1 to an offset in FCRAM. Used for HW allocations that need to be linear in physical memory. + LINEAR_HEAP_VADDR = 0x14000000, + LINEAR_HEAP_SIZE = 0x08000000, + LINEAR_HEAP_VADDR_END = LINEAR_HEAP_VADDR + LINEAR_HEAP_SIZE, + + /// Maps 1:1 to the IO register area. + IO_AREA_VADDR = 0x1EC00000, + IO_AREA_VADDR_END = IO_AREA_VADDR + IO_AREA_SIZE, + + /// Maps 1:1 to VRAM. + VRAM_VADDR = 0x1F000000, + VRAM_VADDR_END = VRAM_VADDR + VRAM_SIZE, + + /// Maps 1:1 to DSP memory. + DSP_RAM_VADDR = 0x1FF00000, + DSP_RAM_VADDR_END = DSP_RAM_VADDR + DSP_RAM_SIZE, + + /// Read-only page containing kernel and system configuration values. + CONFIG_MEMORY_VADDR = 0x1FF80000, + CONFIG_MEMORY_SIZE = 0x00001000, + CONFIG_MEMORY_VADDR_END = CONFIG_MEMORY_VADDR + CONFIG_MEMORY_SIZE, + + /// Usually read-only page containing mostly values read from hardware. + SHARED_PAGE_VADDR = 0x1FF81000, + SHARED_PAGE_SIZE = 0x00001000, + SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE, + + // TODO(yuriks): The size of this area is dynamic, the kernel grows + // it as more and more threads are created. For now we'll just use a + // hardcoded value. + /// Area where TLS (Thread-Local Storage) buffers are allocated. + TLS_AREA_VADDR = 0x1FF82000, + TLS_AREA_SIZE = 0x00030000, // Each TLS buffer is 0x200 bytes, allows for 300 threads + TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE, +}; + +u8 Read8(VAddr addr); +u16 Read16(VAddr addr); +u32 Read32(VAddr addr); +u64 Read64(VAddr addr); + +void Write8(VAddr addr, u8 data); +void Write16(VAddr addr, u16 data); +void Write32(VAddr addr, u32 data); +void Write64(VAddr addr, u64 data); + +void WriteBlock(VAddr addr, const u8* data, size_t size); + +u8* GetPointer(VAddr virtual_address); + +/** + * Gets a pointer to the memory region beginning at the specified physical address. + * + * @note This is currently implemented using PhysicalToVirtualAddress(). + */ +u8* GetPhysicalPointer(PAddr address); + +} diff --git a/src/core/memory_setup.h b/src/core/memory_setup.h new file mode 100644 index 000000000..46263495f --- /dev/null +++ b/src/core/memory_setup.h @@ -0,0 +1,29 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +namespace Memory { + +void InitMemoryMap(); + +/** + * Maps an allocated buffer onto a region of the emulated process address space. + * + * @param base The address to start mapping at. Must be page-aligned. + * @param size The amount of bytes to map. Must be page-aligned. + * @param target Buffer with the memory backing the mapping. Must be of length at least `size`. + */ +void MapMemoryRegion(VAddr base, u32 size, u8* target); + +/** + * Maps a region of the emulated process address space as a IO region. + * @note Currently this can only be used to mark a region as being IO, since actual memory-mapped + * IO isn't yet supported. + */ +void MapIoRegion(VAddr base, u32 size); + +} diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 1ea7cad07..6121df8e3 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -74,11 +74,11 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { // Information about internal vertex attributes u32 vertex_attribute_sources[16]; boost::fill(vertex_attribute_sources, 0xdeadbeef); - u32 vertex_attribute_strides[16]; - Regs::VertexAttributeFormat vertex_attribute_formats[16]; + u32 vertex_attribute_strides[16] = {}; + Regs::VertexAttributeFormat vertex_attribute_formats[16] = {}; - u32 vertex_attribute_elements[16]; - u32 vertex_attribute_element_size[16]; + u32 vertex_attribute_elements[16] = {}; + u32 vertex_attribute_element_size[16] = {}; // Setup attribute data from loaders for (int loader = 0; loader < 12; ++loader) { @@ -127,29 +127,31 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { input.attr[0].w = debug_token; for (int i = 0; i < attribute_config.GetNumTotalAttributes(); ++i) { + // Load the default attribute if we're configured to do so, this data will be overwritten by the loader data if it's set if (attribute_config.IsDefaultAttribute(i)) { input.attr[i] = VertexShader::GetDefaultAttribute(i); LOG_TRACE(HW_GPU, "Loaded default attribute %x for vertex %x (index %x): (%f, %f, %f, %f)", i, vertex, index, input.attr[i][0].ToFloat32(), input.attr[i][1].ToFloat32(), input.attr[i][2].ToFloat32(), input.attr[i][3].ToFloat32()); - } else { - for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { - const u8* srcdata = Memory::GetPhysicalPointer(vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]); - - const float srcval = (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::BYTE) ? *(s8*)srcdata : - (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::UBYTE) ? *(u8*)srcdata : - (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? *(s16*)srcdata : - *(float*)srcdata; - - input.attr[i][comp] = float24::FromFloat32(srcval); - LOG_TRACE(HW_GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08lx + 0x%04lx: %f", - comp, i, vertex, index, - attribute_config.GetPhysicalBaseAddress(), - vertex_attribute_sources[i] - base_address, - vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i], - input.attr[i][comp].ToFloat32()); - } + } + + // Load per-vertex data from the loader arrays + for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { + const u8* srcdata = Memory::GetPhysicalPointer(vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]); + + const float srcval = (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::BYTE) ? *(s8*)srcdata : + (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::UBYTE) ? *(u8*)srcdata : + (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? *(s16*)srcdata : + *(float*)srcdata; + + input.attr[i][comp] = float24::FromFloat32(srcval); + LOG_TRACE(HW_GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08lx + 0x%04lx: %f", + comp, i, vertex, index, + attribute_config.GetPhysicalBaseAddress(), + vertex_attribute_sources[i] - base_address, + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i], + input.attr[i][comp].ToFloat32()); } } diff --git a/src/video_core/pica.h b/src/video_core/pica.h index a53429716..e9bc7fb3b 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -16,8 +16,6 @@ #include "common/common_types.h" #include "common/logging/log.h" -#include "core/mem_map.h" - namespace Pica { // Returns index corresponding to the Regs member labeled by field_name @@ -616,7 +614,7 @@ struct Regs { } inline bool IsDefaultAttribute(int id) const { - return (id >= 12) || (attribute_mask & (1 << id)) != 0; + return (id >= 12) || (attribute_mask & (1ULL << id)) != 0; } inline int GetNumTotalAttributes() const { diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 02a08b20e..59eff48f9 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -9,6 +9,8 @@ #include "common/profiler.h" #include "core/hw/gpu.h" +#include "core/memory.h" + #include "debug_utils/debug_utils.h" #include "math.h" #include "color.h" diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 0c072120d..71ceb021b 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -5,7 +5,7 @@ #include "core/hw/gpu.h" #include "core/hw/hw.h" #include "core/hw/lcd.h" -#include "core/mem_map.h" +#include "core/memory.h" #include "core/settings.h" #include "common/emu_window.h" diff --git a/src/video_core/vertex_shader.cpp b/src/video_core/vertex_shader.cpp index 4734e546a..981d1a356 100644 --- a/src/video_core/vertex_shader.cpp +++ b/src/video_core/vertex_shader.cpp @@ -8,8 +8,6 @@ #include <common/file_util.h> -#include <core/mem_map.h> - #include <nihstro/shader_bytecode.h> #include "common/profiler.h" |