From 20dfbbbe55448618137f026b92acceb3d418af4f Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 7 Jan 2025 02:24:59 -0800 Subject: [PATCH 01/32] CMake: Strip mgba-headless, fix up packaging a bit --- CMakeLists.txt | 11 ++++++++++- src/platform/cmake/DebugStrip.cmake | 12 ++++++++++++ src/platform/qt/CMakeLists.txt | 12 +----------- src/platform/sdl/CMakeLists.txt | 9 +-------- 4 files changed, 24 insertions(+), 20 deletions(-) create mode 100644 src/platform/cmake/DebugStrip.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f4737fdd..f71f46bf0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -158,6 +158,7 @@ endif() include(FindFeature) include(FindFunction) +include(DebugStrip) # Version information add_custom_target(${BINARY_NAME}-version-info ALL @@ -1040,6 +1041,7 @@ endif() if(BUILD_HEADLESS) add_executable(${BINARY_NAME}-headless ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/headless-main.c) target_link_libraries(${BINARY_NAME}-headless ${BINARY_NAME}) + debug_strip(${BINARY_NAME}-headless) target_compile_definitions(${BINARY_NAME}-headless PRIVATE "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}") install(TARGETS ${BINARY_NAME}-headless DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${BINARY_NAME}-headless) endif() @@ -1220,7 +1222,6 @@ elseif(BUILD_STATIC) cpack_add_component(lib${BINARY_NAME} GROUP dev) endif() cpack_add_component(${BINARY_NAME}-dev GROUP dev) -cpack_add_component(${BINARY_NAME}-headless GROUP dev) if(3DS) cpack_add_component(${BINARY_NAME}-3ds GROUP base) @@ -1242,6 +1243,11 @@ if(SDL_FOUND) cpack_add_component(${BINARY_NAME}-sdl GROUP sdl) endif() +if(BUILD_HEADLESS) + cpack_add_component_group(headless PARENT_GROUP base) + cpack_add_component(${BINARY_NAME}-headless GROUP headless) +endif() + if(DISTBUILD) cpack_add_component_group(debug PARENT_GROUP dev) if(BUILD_SHARED AND NOT IS_EMBEDDED) @@ -1256,6 +1262,9 @@ if(DISTBUILD) if(SDL_FOUND) cpack_add_component(${BINARY_NAME}-sdl-dbg GROUP debug) endif() + if(BUILD_HEADLESS) + cpack_add_component(${BINARY_NAME}-headless-dbg GROUP debug) + endif() if(WIN32) cpack_add_component_group(installer PARENT_GROUP base) endif() diff --git a/src/platform/cmake/DebugStrip.cmake b/src/platform/cmake/DebugStrip.cmake new file mode 100644 index 000000000..7e2b842a4 --- /dev/null +++ b/src/platform/cmake/DebugStrip.cmake @@ -0,0 +1,12 @@ +function(debug_strip TARGET) + if(DISTBUILD AND NOT APPLE) + if(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") + add_custom_command(TARGET ${TARGET} POST_BUILD COMMAND "${OBJCOPY}" --only-keep-debug "$" "$.debug") + add_custom_command(TARGET ${TARGET} POST_BUILD COMMAND "${STRIP}" "$") + add_custom_command(TARGET ${TARGET} POST_BUILD COMMAND "${OBJCOPY}" --add-gnu-debuglink "$.debug" "$") + install(FILES "$.debug" DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${TARGET}-dbg) + elseif(BUILD_STATIC AND (CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")) + add_custom_command(TARGET ${TARGET} POST_BUILD COMMAND "${STRIP}" "$") + endif() + endif() +endfunction() diff --git a/src/platform/qt/CMakeLists.txt b/src/platform/qt/CMakeLists.txt index a5fe5b8a8..3122c70e0 100644 --- a/src/platform/qt/CMakeLists.txt +++ b/src/platform/qt/CMakeLists.txt @@ -536,17 +536,7 @@ elseif(WIN32) endif() endif() -if(DISTBUILD AND NOT APPLE) - if(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") - add_custom_command(TARGET ${BINARY_NAME}-qt POST_BUILD COMMAND "${OBJCOPY}" --only-keep-debug "$" "$.debug") - add_custom_command(TARGET ${BINARY_NAME}-qt POST_BUILD COMMAND "${STRIP}" "$") - add_custom_command(TARGET ${BINARY_NAME}-qt POST_BUILD COMMAND "${OBJCOPY}" --add-gnu-debuglink "$.debug" "$") - install(FILES "$.debug" DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${BINARY_NAME}-qt-dbg) - elseif(BUILD_STATIC AND (CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")) - add_custom_command(TARGET ${BINARY_NAME}-qt POST_BUILD COMMAND "${STRIP}" "$") - endif() -endif() - +debug_strip(${BINARY_NAME}-qt) install(TARGETS ${BINARY_NAME}-qt RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${BINARY_NAME}-qt BUNDLE DESTINATION ${APPDIR} COMPONENT ${BINARY_NAME}-qt) diff --git a/src/platform/sdl/CMakeLists.txt b/src/platform/sdl/CMakeLists.txt index 5246f959b..2399dc599 100644 --- a/src/platform/sdl/CMakeLists.txt +++ b/src/platform/sdl/CMakeLists.txt @@ -115,11 +115,4 @@ if(UNIX) install(FILES ${PROJECT_SOURCE_DIR}/doc/mgba.6 DESTINATION ${MANDIR}/man6 COMPONENT ${BINARY_NAME}-sdl) endif() -if(DISTBUILD AND CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") - if(NOT APPLE) - add_custom_command(TARGET ${BINARY_NAME}-sdl POST_BUILD COMMAND "${OBJCOPY}" --only-keep-debug "$" "$.debug") - add_custom_command(TARGET ${BINARY_NAME}-sdl POST_BUILD COMMAND "${STRIP}" "$") - add_custom_command(TARGET ${BINARY_NAME}-sdl POST_BUILD COMMAND "${OBJCOPY}" --add-gnu-debuglink "$.debug" "$") - install(FILES "$.debug" DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${BINARY_NAME}-sdl-dbg) - endif() -endif() +debug_strip(${BINARY_NAME}-sdl) From 838439dcef803a68deea0a6ea62c6f22210aeb21 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 7 Jan 2025 02:44:03 -0800 Subject: [PATCH 02/32] Headless: goto considered harmful --- src/platform/headless-main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/platform/headless-main.c b/src/platform/headless-main.c index f501e52b2..61110b1e8 100644 --- a/src/platform/headless-main.c +++ b/src/platform/headless-main.c @@ -75,6 +75,7 @@ int main(int argc, char * argv[]) { bool cleanExit = false; int uncleanExit = 1; + size_t i; struct HeadlessOpts headlessOpts = { 3, NULL }; StringListInit(&headlessOpts.scripts, 0); @@ -206,7 +207,6 @@ int main(int argc, char * argv[]) { mScriptContextAttachCore(&scriptContext, core); - size_t i; for (i = 0; i < StringListSize(&headlessOpts.scripts); ++i) { if (!mScriptContextLoadFile(&scriptContext, *StringListGetPointer(&headlessOpts.scripts, i))) { mLOG(STATUS, ERROR, "Failed to load script \"%s\"", *StringListGetPointer(&headlessOpts.scripts, i)); @@ -253,7 +253,6 @@ loadError: } argsExit: - size_t i; for (i = 0; i < StringListSize(&headlessOpts.scripts); ++i) { free(*StringListGetPointer(&headlessOpts.scripts, i)); } From 7643a044f42de69486e63d8ffdd401ca621f0fc9 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 9 Jan 2025 00:37:54 -0800 Subject: [PATCH 03/32] mGUI: Wrap around menu cursor when navigating past end (closes #3356) --- CHANGES | 1 + src/util/gui/menu.c | 20 ++++++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index b87501580..84f785795 100644 --- a/CHANGES +++ b/CHANGES @@ -41,6 +41,7 @@ Misc: - Libretro: Add Super Game Boy Color support (closes mgba.io/i/3188) - mGUI: Enable auto-softpatching (closes mgba.io/i/2899) - mGUI: Persist fast forwarding after closing menu (fixes mgba.io/i/2414) + - mGUI: Wrap around menu cursor when navigating past end (closes mgba.io/i/3356) - Qt: Handle multiple save game files for disparate games separately (fixes mgba.io/i/2887) - Qt: Remove maligned double-click-to-fullscreen shortcut (closes mgba.io/i/2632) - Qt: Pass logging context through to video proxy thread (fixes mgba.io/i/3095) diff --git a/src/util/gui/menu.c b/src/util/gui/menu.c index 2109bf8e1..3aeff4533 100644 --- a/src/util/gui/menu.c +++ b/src/util/gui/menu.c @@ -119,12 +119,6 @@ static enum GUIMenuExitReason GUIMenuPollInput(struct GUIParams* params, struct state->cursor = GUIPollCursor(params, &state->cx, &state->cy); // Check for new direction presses - if (newInput & (1 << GUI_INPUT_UP) && menu->index > 0) { - --menu->index; - } - if (newInput & (1 << GUI_INPUT_DOWN) && menu->index < GUIMenuItemListSize(&menu->items) - 1) { - ++menu->index; - } if (newInput & (1 << GUI_INPUT_LEFT)) { struct GUIMenuItem* item = GUIMenuItemListGetPointer(&menu->items, menu->index); if (item->validStates && !item->readonly) { @@ -145,6 +139,20 @@ static enum GUIMenuExitReason GUIMenuPollInput(struct GUIParams* params, struct menu->index = GUIMenuItemListSize(&menu->items) - 1; } } + if (newInput & (1 << GUI_INPUT_UP)) { + if (menu->index > 0) { + --menu->index; + } else { + menu->index = GUIMenuItemListSize(&menu->items) - 1; + } + } + if (newInput & (1 << GUI_INPUT_DOWN)) { + if (menu->index < GUIMenuItemListSize(&menu->items) - 1) { + ++menu->index; + } else { + menu->index = 0; + } + } // Handle cursor movement if (state->cursor != GUI_CURSOR_NOT_PRESENT) { From 080a79fdeebd556645b019f1e33047f6a675655e Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 9 Jan 2025 01:54:10 -0800 Subject: [PATCH 04/32] CMake: Work around CMake dependency dedupliation issues --- CMakeLists.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f71f46bf0..42712e91c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -949,6 +949,14 @@ if(NOT SKIP_LIBRARY) file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/mgba-util) + if(BUILD_STATIC) + # Some versions of CMake are remarkably bad about deduplicating this list, + # leading to issues with static linking. Let's do it manually. + list(REVERSE DEPENDENCY_LIB) + list(REMOVE_DUPLICATES DEPENDENCY_LIB) + list(REVERSE DEPENDENCY_LIB) + endif() + target_link_libraries(${BINARY_NAME} ${DEBUGGER_LIB} ${DEPENDENCY_LIB} ${OS_LIB}) install(TARGETS ${BINARY_NAME} LIBRARY DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME} NAMELINK_SKIP ARCHIVE DESTINATION ${LIBDIR} RUNTIME DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME}) if(BUILD_SHARED) @@ -1040,7 +1048,7 @@ endif() if(BUILD_HEADLESS) add_executable(${BINARY_NAME}-headless ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/headless-main.c) - target_link_libraries(${BINARY_NAME}-headless ${BINARY_NAME}) + target_link_libraries(${BINARY_NAME}-headless ${PLATFORM_LIBRARY} ${BINARY_NAME}) debug_strip(${BINARY_NAME}-headless) target_compile_definitions(${BINARY_NAME}-headless PRIVATE "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}") install(TARGETS ${BINARY_NAME}-headless DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${BINARY_NAME}-headless) From 77e50f7aec87d0e5fda0e68b8c0b62af18d66933 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 10 Jan 2025 02:45:27 -0800 Subject: [PATCH 05/32] Feature: Add ability for subparsers to consume extra arguments --- include/mgba/feature/commandline.h | 1 + src/feature/commandline.c | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/include/mgba/feature/commandline.h b/include/mgba/feature/commandline.h index 17af655fe..9ce118fd2 100644 --- a/include/mgba/feature/commandline.h +++ b/include/mgba/feature/commandline.h @@ -44,6 +44,7 @@ struct mSubParser { bool (*parse)(struct mSubParser* parser, int option, const char* arg); bool (*parseLong)(struct mSubParser* parser, const char* option, const char* arg); void (*apply)(struct mSubParser* parser, struct mCoreConfig* config); + bool (*handleExtraArg)(struct mSubParser* parser, const char* arg); const char* extraOptions; const struct mOption* longOptions; void* opts; diff --git a/src/feature/commandline.c b/src/feature/commandline.c index fca5c7747..1e22a4f2c 100644 --- a/src/feature/commandline.c +++ b/src/feature/commandline.c @@ -187,7 +187,21 @@ bool mArgumentsParse(struct mArguments* args, int argc, char* const* argv, struc argc -= optind; argv += optind; if (argc > 1) { - return false; + for (j = 0; j < argc; ++j) { + bool handled = false; + for (i = 0; i < nSubparsers; ++i) { + if (!subparsers[i].handleExtraArg) { + continue; + } + handled = subparsers[i].handleExtraArg(&subparsers[i], argv[j]); + if (handled) { + break; + } + } + if (!handled) { + return false; + } + } } else if (argc == 1) { args->fname = strdup(argv[0]); } else { @@ -303,6 +317,7 @@ void mSubParserGraphicsInit(struct mSubParser* parser, struct mGraphicsOpts* opt parser->apply = _applyGraphicsArgs; parser->extraOptions = GRAPHICS_OPTIONS; parser->longOptions = _graphicsLongOpts; + parser->handleExtraArg = NULL; opts->multiplier = 0; opts->fullscreen = false; } From f58f9746d72f4aba3682aec6febcf5d9ad214683 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 10 Jan 2025 02:46:58 -0800 Subject: [PATCH 06/32] Qt: Allow passing multiple games on command line for multiplayer (closes #3061) --- CHANGES | 1 + src/platform/qt/ConfigController.cpp | 8 ++++++++ src/platform/qt/ConfigController.h | 2 ++ src/platform/qt/GBAApp.cpp | 20 ++++++++++++++++++++ src/platform/qt/GBAApp.h | 2 ++ src/platform/qt/main.cpp | 3 +-- 6 files changed, 34 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 84f785795..68638bb67 100644 --- a/CHANGES +++ b/CHANGES @@ -47,6 +47,7 @@ Misc: - Qt: Pass logging context through to video proxy thread (fixes mgba.io/i/3095) - Qt: Show maker code and game version in ROM info - Qt: Show a dummy shader settings tab if shaders aren't supported + - Qt: Allow passing multiple games on command line for multiplayer (closes mgba.io/i/3061) - Res: Port NSO-gba-colors shader (closes mgba.io/i/2834) - Scripting: Add `callbacks:oneshot` for single-call callbacks - Updater: Fix rewriting folders and files on Windows (fixes mgba.io/i/3384) diff --git a/src/platform/qt/ConfigController.cpp b/src/platform/qt/ConfigController.cpp index ed000ab3b..a12768709 100644 --- a/src/platform/qt/ConfigController.cpp +++ b/src/platform/qt/ConfigController.cpp @@ -196,6 +196,14 @@ ConfigController::ConfigController(QObject* parent) m_subparsers[1].extraOptions = nullptr; m_subparsers[1].longOptions = s_frontendOptions; m_subparsers[1].opts = this; + m_subparsers[1].handleExtraArg = [](struct mSubParser* parser, const char* arg) { + ConfigController* self = static_cast(parser->opts); + if (self->m_fnames.count() >= MAX_GBAS) { + return false; + } + self->m_fnames.append(QString::fromUtf8(arg)); + return true; + }; } ConfigController::~ConfigController() { diff --git a/src/platform/qt/ConfigController.h b/src/platform/qt/ConfigController.h index 4325a46ba..5aa9b7ac2 100644 --- a/src/platform/qt/ConfigController.h +++ b/src/platform/qt/ConfigController.h @@ -102,6 +102,7 @@ public: const mArguments* args() const { return &m_args; } const mGraphicsOpts* graphicsOpts() const { return &m_graphicsOpts; } + QStringList fileNames() const { return m_fnames; } void usage(const char* arg0) const; static const QString& configDir(); @@ -129,6 +130,7 @@ private: mArguments m_args{}; mGraphicsOpts m_graphicsOpts{}; std::array m_subparsers; + QStringList m_fnames; bool m_parsed = false; QHash m_argvOptions; diff --git a/src/platform/qt/GBAApp.cpp b/src/platform/qt/GBAApp.cpp index 90fc89170..258df9f0c 100644 --- a/src/platform/qt/GBAApp.cpp +++ b/src/platform/qt/GBAApp.cpp @@ -397,6 +397,26 @@ void GBAApp::finishJob(qint64 jobId) { m_workerJobCallbacks.remove(jobId); } +void GBAApp::initMultiplayer() { + QStringList fnames = m_configController->fileNames(); + if (fnames.count() < 2) { + return; + } + + Window* w = m_windows[0]; + for (const auto& fname : fnames) { + if (!w) { + w = newWindow(); + } + if (!w) { + break; + } + CoreController* core = m_manager.loadGame(fname); + w->setController(core, fname); + w = nullptr; + } +} + GBAApp::WorkerJob::WorkerJob(qint64 id, std::function&& job, GBAApp* owner) : m_id(id) , m_job(std::move(job)) diff --git a/src/platform/qt/GBAApp.h b/src/platform/qt/GBAApp.h index 2388bc297..43848b183 100644 --- a/src/platform/qt/GBAApp.h +++ b/src/platform/qt/GBAApp.h @@ -82,6 +82,8 @@ public: ApplicationUpdater* updater() { return &m_updater; } QString invokeOnExit() { return m_invokeOnExit; } + void initMultiplayer(); + public slots: void restartForUpdate(); Window* newWindow(); diff --git a/src/platform/qt/main.cpp b/src/platform/qt/main.cpp index f98d2cd88..48f1984f7 100644 --- a/src/platform/qt/main.cpp +++ b/src/platform/qt/main.cpp @@ -131,10 +131,9 @@ int main(int argc, char* argv[]) { } Window* w = application.newWindow(); - w->loadConfig(); w->argumentsPassed(); - w->show(); + application.initMultiplayer(); int ret = application.exec(); if (ret != 0) { From a2fda7f44155a5adb9a9477e46955f815dc7740d Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 11 Jan 2025 14:50:30 -0800 Subject: [PATCH 07/32] Qt: Split MemoryAccessLogView and MemoryAccessLogController --- src/platform/qt/CMakeLists.txt | 1 + src/platform/qt/CoreController.cpp | 14 ++ src/platform/qt/CoreController.h | 7 + src/platform/qt/MemoryAccessLogController.cpp | 118 +++++++++++++++ src/platform/qt/MemoryAccessLogController.h | 66 +++++++++ src/platform/qt/MemoryAccessLogView.cpp | 135 +++++++----------- src/platform/qt/MemoryAccessLogView.h | 17 +-- src/platform/qt/Window.cpp | 7 +- 8 files changed, 272 insertions(+), 93 deletions(-) create mode 100644 src/platform/qt/MemoryAccessLogController.cpp create mode 100644 src/platform/qt/MemoryAccessLogController.h diff --git a/src/platform/qt/CMakeLists.txt b/src/platform/qt/CMakeLists.txt index 3122c70e0..910ab9b57 100644 --- a/src/platform/qt/CMakeLists.txt +++ b/src/platform/qt/CMakeLists.txt @@ -261,6 +261,7 @@ if(ENABLE_DEBUGGERS) DebuggerController.cpp DebuggerConsole.cpp DebuggerConsoleController.cpp + MemoryAccessLogController.cpp MemoryAccessLogView.cpp) endif() diff --git a/src/platform/qt/CoreController.cpp b/src/platform/qt/CoreController.cpp index 2496f8039..152efc222 100644 --- a/src/platform/qt/CoreController.cpp +++ b/src/platform/qt/CoreController.cpp @@ -8,6 +8,7 @@ #include "ConfigController.h" #include "InputController.h" #include "LogController.h" +#include "MemoryAccessLogController.h" #include "MultiplayerController.h" #include "Override.h" @@ -459,6 +460,15 @@ void CoreController::setLogger(LogController* logger) { connect(this, &CoreController::logPosted, m_log, &LogController::postLog); } +#ifdef ENABLE_DEBUGGERS +std::weak_ptr CoreController::memoryAccessLogController() { + if (!m_malController) { + m_malController = std::make_shared(this); + } + return m_malController; +} +#endif + void CoreController::start() { QSize size(screenDimensions()); m_activeBuffer.resize(size.width() * size.height() * sizeof(mColor)); @@ -479,6 +489,10 @@ void CoreController::start() { void CoreController::stop() { setSync(false); #ifdef ENABLE_DEBUGGERS + if (m_malController) { + m_malController->stop(); + } + detachDebugger(); #endif setPaused(false); diff --git a/src/platform/qt/CoreController.h b/src/platform/qt/CoreController.h index 57eb9ffe0..a2ebe410e 100644 --- a/src/platform/qt/CoreController.h +++ b/src/platform/qt/CoreController.h @@ -40,6 +40,7 @@ namespace QGBA { class ConfigController; class InputController; class LogController; +class MemoryAccessLogController; class MultiplayerController; class Override; @@ -113,6 +114,8 @@ public: void detachDebugger(); void attachDebuggerModule(mDebuggerModule*, bool interrupt = true); void detachDebuggerModule(mDebuggerModule*); + + std::weak_ptr memoryAccessLogController(); #endif void setMultiplayerController(MultiplayerController*); @@ -326,6 +329,10 @@ private: GBASIODolphin m_dolphin; #endif +#ifdef ENABLE_DEBUGGERS + std::shared_ptr m_malController; +#endif + mVideoLogContext* m_vl = nullptr; VFile* m_vlVf = nullptr; diff --git a/src/platform/qt/MemoryAccessLogController.cpp b/src/platform/qt/MemoryAccessLogController.cpp new file mode 100644 index 000000000..95200e53e --- /dev/null +++ b/src/platform/qt/MemoryAccessLogController.cpp @@ -0,0 +1,118 @@ +/* Copyright (c) 2013-2025 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "MemoryAccessLogController.h" + +#include "GBAApp.h" +#include "LogController.h" +#include "utils.h" +#include "VFileDevice.h" + +using namespace QGBA; + +MemoryAccessLogController::MemoryAccessLogController(CoreController* controller, QObject* parent) + : QObject(parent) + , m_controller(controller) +{ + mCore* core = m_controller->thread()->core; + const mCoreMemoryBlock* info; + size_t nBlocks = core->listMemoryBlocks(core, &info); + + for (size_t i = 0; i < nBlocks; ++i) { + if (!(info[i].flags & mCORE_MEMORY_MAPPED)) { + continue; + } + m_regions.append({ + QString::fromUtf8(info[i].longName), + QString::fromUtf8(info[i].internalName) + }); + } +} + +MemoryAccessLogController::~MemoryAccessLogController() { + stop(); +} + +bool MemoryAccessLogController::canExport() const { + return m_regionMapping.contains("cart0"); +} + +void MemoryAccessLogController::updateRegion(const QString& internalName, bool checked) { + if (checked) { + m_watchedRegions += internalName; + } else { + m_watchedRegions -= internalName; + } + if (!m_active) { + return; + } + m_regionMapping[internalName] = mDebuggerAccessLoggerWatchMemoryBlockName(&m_logger, internalName.toUtf8().constData(), activeFlags()); + emit regionMappingChanged(internalName, checked); +} + +void MemoryAccessLogController::setFile(const QString& path) { + m_path = path; +} + +void MemoryAccessLogController::start(bool loadExisting, bool logExtra) { + int flags = O_CREAT | O_RDWR; + if (!loadExisting) { + flags |= O_TRUNC; + } + VFile* vf = VFileDevice::open(m_path, flags); + if (!vf) { + LOG(QT, ERROR) << tr("Failed to open memory log file"); + return; + } + m_logExtra = logExtra; + + mDebuggerAccessLoggerInit(&m_logger); + CoreController::Interrupter interrupter(m_controller); + m_controller->attachDebuggerModule(&m_logger.d); + if (!mDebuggerAccessLoggerOpen(&m_logger, vf, flags)) { + mDebuggerAccessLoggerDeinit(&m_logger); + LOG(QT, ERROR) << tr("Failed to open memory log file"); + return; + } + + m_active = true; + emit loggingChanged(true); + for (const auto& region : m_watchedRegions) { + m_regionMapping[region] = mDebuggerAccessLoggerWatchMemoryBlockName(&m_logger, region.toUtf8().constData(), activeFlags()); + } + interrupter.resume(); +} + +void MemoryAccessLogController::stop() { + if (!m_active) { + return; + } + CoreController::Interrupter interrupter(m_controller); + m_controller->detachDebuggerModule(&m_logger.d); + mDebuggerAccessLoggerDeinit(&m_logger); + emit loggingChanged(false); + interrupter.resume(); + m_active = false; +} + +mDebuggerAccessLogRegionFlags MemoryAccessLogController::activeFlags() const { + mDebuggerAccessLogRegionFlags loggerFlags = 0; + if (m_logExtra) { + loggerFlags = mDebuggerAccessLogRegionFlagsFillHasExBlock(loggerFlags); + } + return loggerFlags; +} + +void MemoryAccessLogController::exportFile(const QString& filename) { + VFile* vf = VFileDevice::open(filename, O_CREAT | O_TRUNC | O_WRONLY); + if (!vf) { + // log error + return; + } + + CoreController::Interrupter interrupter(m_controller); + mDebuggerAccessLoggerCreateShadowFile(&m_logger, m_regionMapping[QString("cart0")], vf, 0); + vf->close(vf); +} diff --git a/src/platform/qt/MemoryAccessLogController.h b/src/platform/qt/MemoryAccessLogController.h new file mode 100644 index 000000000..42ef655c3 --- /dev/null +++ b/src/platform/qt/MemoryAccessLogController.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2013-2025 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#pragma once + +#include +#include + +#include + +#include "CoreController.h" + +#include + +namespace QGBA { + +class MemoryAccessLogController : public QObject { +Q_OBJECT + +public: + struct Region { + QString longName; + QString internalName; + }; + + MemoryAccessLogController(CoreController* controller, QObject* parent = nullptr); + ~MemoryAccessLogController(); + + QVector listRegions() const { return m_regions; } + QSet watchedRegions() const { return m_watchedRegions; } + + bool canExport() const; + mPlatform platform() const { return m_controller->platform(); } + + QString file() const { return m_path; } + bool active() const { return m_active; } + +public slots: + void updateRegion(const QString& internalName, bool enable); + void setFile(const QString& path); + + void start(bool loadExisting, bool logExtra); + void stop(); + + void exportFile(const QString& filename); + +signals: + void loggingChanged(bool active); + void regionMappingChanged(const QString& internalName, bool active); + +private: + bool m_logExtra = false; + QString m_path; + CoreController* m_controller; + QSet m_watchedRegions; + QHash m_regionMapping; + QVector m_regions; + struct mDebuggerAccessLogger m_logger{}; + bool m_active = false; + + mDebuggerAccessLogRegionFlags activeFlags() const; +}; + +} diff --git a/src/platform/qt/MemoryAccessLogView.cpp b/src/platform/qt/MemoryAccessLogView.cpp index 3c846b440..97a0c932e 100644 --- a/src/platform/qt/MemoryAccessLogView.cpp +++ b/src/platform/qt/MemoryAccessLogView.cpp @@ -9,104 +9,66 @@ #include "GBAApp.h" #include "LogController.h" +#include "MemoryAccessLogController.h" #include "utils.h" #include "VFileDevice.h" using namespace QGBA; -MemoryAccessLogView::MemoryAccessLogView(std::shared_ptr controller, QWidget* parent) +MemoryAccessLogView::MemoryAccessLogView(std::weak_ptr controller, QWidget* parent) : QWidget(parent) - , m_controller(std::move(controller)) + , m_controller(controller) { m_ui.setupUi(this); + std::shared_ptr controllerPtr = m_controller.lock(); connect(m_ui.browse, &QAbstractButton::clicked, this, &MemoryAccessLogView::selectFile); connect(m_ui.exportButton, &QAbstractButton::clicked, this, &MemoryAccessLogView::exportFile); - connect(this, &MemoryAccessLogView::loggingChanged, m_ui.start, &QWidget::setDisabled); - connect(this, &MemoryAccessLogView::loggingChanged, m_ui.stop, &QWidget::setEnabled); - connect(this, &MemoryAccessLogView::loggingChanged, m_ui.filename, &QWidget::setDisabled); - connect(this, &MemoryAccessLogView::loggingChanged, m_ui.browse, &QWidget::setDisabled); + connect(controllerPtr.get(), &MemoryAccessLogController::regionMappingChanged, this, &MemoryAccessLogView::updateRegion); + connect(controllerPtr.get(), &MemoryAccessLogController::loggingChanged, this, &MemoryAccessLogView::handleStartStop); - mCore* core = m_controller->thread()->core; - const mCoreMemoryBlock* info; - size_t nBlocks = core->listMemoryBlocks(core, &info); + bool active = controllerPtr->active(); + auto watchedRegions = controllerPtr->watchedRegions(); QVBoxLayout* regionBox = static_cast(m_ui.regionBox->layout()); - for (size_t i = 0; i < nBlocks; ++i) { - if (!(info[i].flags & mCORE_MEMORY_MAPPED)) { - continue; - } - QCheckBox* region = new QCheckBox(QString::fromUtf8(info[i].longName)); + for (const auto& info : controllerPtr->listRegions()) { + QCheckBox* region = new QCheckBox(info.longName); regionBox->addWidget(region); - QString name(QString::fromUtf8(info[i].internalName)); + QString name(info.internalName); m_regionBoxes[name] = region; connect(region, &QAbstractButton::toggled, this, [this, name](bool checked) { - updateRegion(name, checked); + std::shared_ptr controllerPtr = m_controller.lock(); + if (!controllerPtr) { + return; + } + controllerPtr->updateRegion(name, checked); }); } + + handleStartStop(active); } -MemoryAccessLogView::~MemoryAccessLogView() { - stop(); -} - -void MemoryAccessLogView::updateRegion(const QString& internalName, bool checked) { - if (checked) { - m_watchedRegions += internalName; - } else { - m_watchedRegions -= internalName; - } - if (!m_active) { - return; - } +void MemoryAccessLogView::updateRegion(const QString& internalName, bool) { m_regionBoxes[internalName]->setEnabled(false); - m_regionMapping[internalName] = mDebuggerAccessLoggerWatchMemoryBlockName(&m_logger, internalName.toUtf8().constData(), activeFlags()); } void MemoryAccessLogView::start() { - int flags = O_CREAT | O_RDWR; - if (!m_ui.loadExisting->isChecked()) { - flags |= O_TRUNC; - } - VFile* vf = VFileDevice::open(m_ui.filename->text(), flags); - if (!vf) { - // log error + std::shared_ptr controllerPtr = m_controller.lock(); + if (!controllerPtr) { return; } - mDebuggerAccessLoggerInit(&m_logger); - CoreController::Interrupter interrupter(m_controller); - m_controller->attachDebuggerModule(&m_logger.d); - if (!mDebuggerAccessLoggerOpen(&m_logger, vf, flags)) { - mDebuggerAccessLoggerDeinit(&m_logger); - LOG(QT, ERROR) << tr("Failed to open memory log file"); - return; - } - - m_active = true; - emit loggingChanged(true); - for (const auto& region : m_watchedRegions) { - m_regionBoxes[region]->setEnabled(false); - m_regionMapping[region] = mDebuggerAccessLoggerWatchMemoryBlockName(&m_logger, region.toUtf8().constData(), activeFlags()); - } - interrupter.resume(); - - if (m_watchedRegions.contains(QString("cart0"))) { - m_ui.exportButton->setEnabled(true); - } + controllerPtr->setFile(m_ui.filename->text()); + controllerPtr->start(m_ui.loadExisting->isChecked(), m_ui.logExtra->isChecked()); } void MemoryAccessLogView::stop() { - if (!m_active) { + std::shared_ptr controllerPtr = m_controller.lock(); + if (!controllerPtr) { return; } - CoreController::Interrupter interrupter(m_controller); - m_controller->detachDebuggerModule(&m_logger.d); - mDebuggerAccessLoggerDeinit(&m_logger); - emit loggingChanged(false); - interrupter.resume(); - - for (const auto& region : m_watchedRegions) { + controllerPtr->stop(); + for (const auto& region : controllerPtr->watchedRegions()) { m_regionBoxes[region]->setEnabled(true); } m_ui.exportButton->setEnabled(false); @@ -119,30 +81,41 @@ void MemoryAccessLogView::selectFile() { } } -mDebuggerAccessLogRegionFlags MemoryAccessLogView::activeFlags() const { - mDebuggerAccessLogRegionFlags loggerFlags = 0; - if (m_ui.logExtra->isChecked()) { - loggerFlags = mDebuggerAccessLogRegionFlagsFillHasExBlock(loggerFlags); - } - return loggerFlags; -} - void MemoryAccessLogView::exportFile() { - if (!m_regionMapping.contains("cart0")) { + std::shared_ptr controllerPtr = m_controller.lock(); + if (!controllerPtr) { + return; + } + if (!controllerPtr->canExport()) { return; } - QString filename = GBAApp::app()->getSaveFileName(this, tr("Select access log file"), romFilters(false, m_controller->platform(), true)); + QString filename = GBAApp::app()->getSaveFileName(this, tr("Select access log file"), romFilters(false, controllerPtr->platform(), true)); if (filename.isEmpty()) { return; } - VFile* vf = VFileDevice::open(filename, O_CREAT | O_TRUNC | O_WRONLY); - if (!vf) { - // log error + controllerPtr->exportFile(filename); +} + +void MemoryAccessLogView::handleStartStop(bool start) { + std::shared_ptr controllerPtr = m_controller.lock(); + if (!controllerPtr) { return; } + m_ui.filename->setText(controllerPtr->file()); - CoreController::Interrupter interrupter(m_controller); - mDebuggerAccessLoggerCreateShadowFile(&m_logger, m_regionMapping[QString("cart0")], vf, 0); - vf->close(vf); + auto watchedRegions = controllerPtr->watchedRegions(); + for (const auto& region : watchedRegions) { + m_regionBoxes[region]->setDisabled(start); + m_regionBoxes[region]->setChecked(true); + } + + if (watchedRegions.contains(QString("cart0"))) { + m_ui.exportButton->setEnabled(start); + } + + m_ui.start->setDisabled(start); + m_ui.stop->setEnabled(start); + m_ui.filename->setDisabled(start); + m_ui.browse->setDisabled(start); } diff --git a/src/platform/qt/MemoryAccessLogView.h b/src/platform/qt/MemoryAccessLogView.h index ffe31cc43..e221a5d9d 100644 --- a/src/platform/qt/MemoryAccessLogView.h +++ b/src/platform/qt/MemoryAccessLogView.h @@ -18,12 +18,14 @@ namespace QGBA { +class MemoryAccessLogController; + class MemoryAccessLogView : public QWidget { Q_OBJECT public: - MemoryAccessLogView(std::shared_ptr controller, QWidget* parent = nullptr); - ~MemoryAccessLogView(); + MemoryAccessLogView(std::weak_ptr controller, QWidget* parent = nullptr); + ~MemoryAccessLogView() = default; private slots: void updateRegion(const QString& internalName, bool enable); @@ -34,20 +36,13 @@ private slots: void exportFile(); -signals: - void loggingChanged(bool active); + void handleStartStop(bool start); private: Ui::MemoryAccessLogView m_ui; - std::shared_ptr m_controller; - QSet m_watchedRegions; + std::weak_ptr m_controller; QHash m_regionBoxes; - QHash m_regionMapping; - struct mDebuggerAccessLogger m_logger{}; - bool m_active = false; - - mDebuggerAccessLogRegionFlags activeFlags() const; }; } diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index bc956fcc4..1be4a998c 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -1767,7 +1767,12 @@ void Window::setupMenu(QMenuBar* menubar) { addGameAction(tr("View &I/O registers..."), "ioViewer", openControllerTView(), "stateViews"); #ifdef ENABLE_DEBUGGERS - addGameAction(tr("Log memory &accesses..."), "memoryAccessView", openControllerTView(), "tools"); + addGameAction(tr("Log memory &accesses..."), "memoryAccessView", [this]() { + std::weak_ptr controller = m_controller->memoryAccessLogController(); + MemoryAccessLogView* view = new MemoryAccessLogView(controller); + connect(m_controller.get(), &CoreController::stopping, view, &QWidget::close); + openView(view); + }, "tools"); #endif #if defined(USE_FFMPEG) && defined(M_CORE_GBA) From 3e5e20c6f0bcbe33231bebddaf7ba4593a350ada Mon Sep 17 00:00:00 2001 From: Felipe Date: Thu, 12 Dec 2024 13:12:40 +0000 Subject: [PATCH 08/32] Qt: Update translation (Portuguese (Brazil)) Translation: mGBA/Qt Translate-URL: https://hosted.weblate.org/projects/mgba/mgba-qt/pt_BR/ --- src/platform/qt/ts/mgba-pt_BR.ts | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/platform/qt/ts/mgba-pt_BR.ts b/src/platform/qt/ts/mgba-pt_BR.ts index e132eaeb3..9b3ca1750 100644 --- a/src/platform/qt/ts/mgba-pt_BR.ts +++ b/src/platform/qt/ts/mgba-pt_BR.ts @@ -3262,7 +3262,7 @@ Tamanho do download: %3 Info - Informações + Info @@ -3829,12 +3829,12 @@ Tamanho do download: %3 Clearing invalid save ID - + Limpando a ID inválida do save Clearing invalid preferred ID - + Limpando a ID inválida preferida @@ -4367,7 +4367,7 @@ Tamanho do download: %3 File information - + Informação do arquivo @@ -4377,12 +4377,12 @@ Tamanho do download: %3 MD5 - + MD5 ROM header - + Cabeçalho da ROM @@ -4857,7 +4857,9 @@ Tamanho do download: %3 Shaders are not supported when the display driver is not OpenGL. If it is set to OpenGL and you still see this, your graphics card or drivers may be too old. - + Os shaders não são suportados quando o driver de exibição não é OpenGL. + +Se ele está definido como OpenGL e você ainda ver isto sua placa gráfica ou drivers podem ser muito antigos. @@ -5666,17 +5668,17 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may mGBA Shaders - + Shaders do mGBA Error loading shader - + Erro ao carregar o shader The shader "%1" could not be loaded successfully. - + O shader "%1" não pôde ser carregado com sucesso. From 34c992eb2314930f0bd04519e5925b5cbb85d7c6 Mon Sep 17 00:00:00 2001 From: Daniel Nylander Date: Thu, 12 Dec 2024 13:59:39 +0000 Subject: [PATCH 09/32] Qt: Update translation (Swedish) Translation: mGBA/Qt Translate-URL: https://hosted.weblate.org/projects/mgba/mgba-qt/sv/ --- src/platform/qt/ts/mgba-sv.ts | 118 +++++++++++++++++----------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/src/platform/qt/ts/mgba-sv.ts b/src/platform/qt/ts/mgba-sv.ts index b0ddef6a8..bd6bfb078 100644 --- a/src/platform/qt/ts/mgba-sv.ts +++ b/src/platform/qt/ts/mgba-sv.ts @@ -1158,7 +1158,7 @@ Hämtningsstorlek: %3 B - + B @@ -2742,13 +2742,13 @@ Hämtningsstorlek: %3 Serial - + Serienummer Joypad - + Joypad @@ -2902,28 +2902,28 @@ Hämtningsstorlek: %3 Color 0 shade - + Färg 0-skugga Color 1 shade - + Färg 1-skugga Color 2 shade - + Färg 2-skugga Color 3 shade - + Färg 3-skugga @@ -2938,7 +2938,7 @@ Hämtningsstorlek: %3 VRAM bank - + VRAM-bank @@ -3348,7 +3348,7 @@ Hämtningsstorlek: %3 Offset - Förskjut + Marginal @@ -3482,7 +3482,7 @@ Hämtningsstorlek: %3 Byte Count: - + Antal byte: @@ -4030,7 +4030,7 @@ Hämtningsstorlek: %3 Game Overrides - + Spelförbättringar @@ -4118,7 +4118,7 @@ Hämtningsstorlek: %3 Game Boy Player features - + Game Boy Player-funktioner @@ -4138,7 +4138,7 @@ Hämtningsstorlek: %3 Memory bank controller - + Minnesbankskontroller @@ -4148,12 +4148,12 @@ Hämtningsstorlek: %3 Sprite Colors 1 - + Spritefärger 1 Sprite Colors 2 - + Spritefärger 2 @@ -4367,7 +4367,7 @@ Hämtningsstorlek: %3 File information - + Filinformation @@ -4377,12 +4377,12 @@ Hämtningsstorlek: %3 MD5 - + MD5 ROM header - + ROM-header @@ -4440,7 +4440,7 @@ Hämtningsstorlek: %3 <html><head/><body><p>To file a bug report, please first generate a report file to attach to the bug report you're about to file. It is recommended that you include the save files, as these often help with debugging issues. This will collect some information about the version of {projectName} you're running, your configuration, your computer, and the game you currently have open (if any). Once this collection is completed you can review all of the information gathered below and save it to a zip file. The collection will automatically attempt to redact any personal information, such as your username if it's in any of the paths gathered, but just in case you can edit it afterwards. After you have generated and saved it, please click the button below or go to <a href="https://mgba.io/i/"><span style=" text-decoration: underline; color:#2980b9;">mgba.io/i</span></a> to file the bug report on GitHub. Make sure to attach the report you generated!</p></body></html> - + <html><head/><body><p>För att rapportera en bugg eller fel så måste du generera en rapportfil att lägga till i felrapporten som du håller på att skicka in. Det rekommenderas att du inkluderar sparade filer eftersom dessa hjälper till att felsöka problem. Detta kommer att samla in viss information om versionen av {projectName} som du använder, din konfiguration, din dator samt spelet som du för närvarande har öppet (om något). När detta har samlats in så kan du granska all information nedan och spara det till en zip-fil. Personlig information kommer att undantas från den samlade informationen om det går, så som ditt användarnamn om det finns i någon sökväg, men du kan även redigera det i efterhand. Efter att du har genererat och sparat det, klicka på knappen nedan eller gå till <a href="https://mgba.io/i/"><span style=" text-decoration: underline; color:#2980b9;">mgba.io/i</span></a> för att skicka in felrapporten på GitHub. Försäkra dig om att lägga till rapporten som du genererat!</p></body></html> @@ -4779,13 +4779,13 @@ Hämtningsstorlek: %3 Set Y - + Ställ in Y Set X - + Ställ in X @@ -5122,7 +5122,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may FPS target: - + Bilder/s: @@ -5350,7 +5350,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Periodically autosave state - + Autospara tillstånd periodiskt @@ -5360,7 +5360,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Show frame count in OSD - + Visa bilder/s i OSD @@ -5370,7 +5370,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Custom border: - + Anpassad ram: @@ -5381,32 +5381,32 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Unbounded - Obunden + Obunden Fast forward (held) speed: - + Hastighet för snabbspolning (håll): Autofire interval: - + Intervall för autofire: Enable rewind - + Aktivera tillbakaspolning Rewind history: - + Historik för tillbakaspolning: Rewind speed: - + Hastighet för tillbakaspolning: @@ -5436,7 +5436,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Save state extra data: - + Extradata för sparade tillstånd: @@ -5447,7 +5447,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Load state extra data: - + Extradata för inlästa tillstånd: @@ -5647,7 +5647,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Super Game Boy borders - + Super Game Boy-ramar @@ -5666,17 +5666,17 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may mGBA Shaders - + mGBA-shaders Error loading shader - + Fel vid inläsning av shader The shader "%1" could not be loaded successfully. - + Shadern "%1" kunde inte läsas in korrekt. @@ -5726,7 +5726,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Unload Shader - + Läs ur shader @@ -6035,7 +6035,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Select e-Reader dotcode - + Välj e-Reader-punktkod @@ -6094,17 +6094,17 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Unimplemented BIOS call - + Ej implementerat BIOS-anrop This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. - + Detta spel använder ett BIOS-anrop som inte är implementerat. Använd ett officiellt BIOS för bästa upplevelse. Failed to create an appropriate display device, falling back to software display. Games may run slowly, especially with larger windows. - + Misslyckades med att skapa en lämplig visningsenhet, faller tillbaka på programvaruvisning. Spel kan bli långsamma, speciellt med större fönster. @@ -6556,7 +6556,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Frame&skip - + Hoppa över &bildrutor @@ -6566,7 +6566,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may FPS target - + Bilder/s @@ -6621,7 +6621,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Game &overrides... - + Spel&förbättringar... @@ -6636,7 +6636,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Create forwarder... - + Skapa forwarder... @@ -6661,7 +6661,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Game state views - + Visa speltillstånd @@ -6726,62 +6726,62 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may GameShark Button (held) - + GameShark-knapp (håll) Autofire - + Autofire Autofire A - + Autofire A Autofire B - + Autofire B Autofire L - + Autofire L Autofire R - + Autofire R Autofire Start - + Autofire Start Autofire Select - + Autofire Select Autofire Up - + Autofire upp Autofire Right - + Autofire höger Autofire Down - + Autofire ner Autofire Left - + Autofire vänster From 0880b007fa78a5d115b8ac28478bedd0b7380f9f Mon Sep 17 00:00:00 2001 From: Momo cao Date: Thu, 12 Dec 2024 14:50:19 +0000 Subject: [PATCH 10/32] Qt: Update translation (Spanish) Translation: mGBA/Qt Translate-URL: https://hosted.weblate.org/projects/mgba/mgba-qt/es/ --- src/platform/qt/ts/mgba-es.ts | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/platform/qt/ts/mgba-es.ts b/src/platform/qt/ts/mgba-es.ts index 65223278e..d1701d571 100644 --- a/src/platform/qt/ts/mgba-es.ts +++ b/src/platform/qt/ts/mgba-es.ts @@ -3829,12 +3829,12 @@ Tamaño de descarga: %3 Clearing invalid save ID - + Borrando identificador de guardado inválido Clearing invalid preferred ID - + Borrando identificador inválido preferido @@ -4367,7 +4367,7 @@ Tamaño de descarga: %3 File information - + Información de archivo @@ -4377,12 +4377,12 @@ Tamaño de descarga: %3 MD5 - + MD5 ROM header - + Cabecera de ROM @@ -4857,7 +4857,9 @@ Tamaño de descarga: %3 Shaders are not supported when the display driver is not OpenGL. If it is set to OpenGL and you still see this, your graphics card or drivers may be too old. - + Los shader no están disponibles cuando el controlador de pantalla no es OpenGL. + +Si está configurado como OpenGL y estás viendo esto, tu tarjeta gráfica o controladores son demasiado antiguos. @@ -5666,17 +5668,17 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may mGBA Shaders - + Shaders de mGBA Error loading shader - + Error al cargar shader The shader "%1" could not be loaded successfully. - + El shader "%1" falló al cargarse. From e3f3baed510f0ca18978acb54cc6b678a0683fa6 Mon Sep 17 00:00:00 2001 From: reimu105 Date: Sun, 15 Dec 2024 01:56:41 +0000 Subject: [PATCH 11/32] Qt: Update translation (Chinese (Traditional Han script)) Translation: mGBA/Qt Translate-URL: https://hosted.weblate.org/projects/mgba/mgba-qt/zh_Hant/ --- src/platform/qt/ts/mgba-zh_Hant.ts | 266 ++++++++++++++--------------- 1 file changed, 133 insertions(+), 133 deletions(-) diff --git a/src/platform/qt/ts/mgba-zh_Hant.ts b/src/platform/qt/ts/mgba-zh_Hant.ts index 8cbb231b5..5b5c96e52 100644 --- a/src/platform/qt/ts/mgba-zh_Hant.ts +++ b/src/platform/qt/ts/mgba-zh_Hant.ts @@ -6,22 +6,22 @@ Game Boy Advance ROMs (%1) - Game Boy Advance ROMs (%1) + Game Boy Advance ROMs (%1) Game Boy ROMs (%1) - Game Boy ROMs (%1) + Game Boy ROMs (%1) All ROMs (%1) - 所有 ROMs (%1) + 所有 ROMs (%1) %1 Video Logs (*.mvl) - %1 影片記錄檔 (*.mvl) + %1 影片記錄檔 (*.mvl) @@ -29,7 +29,7 @@ About - 關於 + 關於 @@ -193,17 +193,17 @@ Download size: %3 Can't set format of context-less audio device - + 無法設定無上下文音訊設備的格式 Audio device is missing its core - + 音訊設備缺少其核心 Writing data to read-only audio device - + 將資料寫入唯讀音訊設備 @@ -211,7 +211,7 @@ Download size: %3 Can't start an audio processor without input - + 無輸入時無法啟動音訊處理器 @@ -219,7 +219,7 @@ Download size: %3 Can't start an audio processor without input - + 無輸入時無法啟動音訊處理器 @@ -242,12 +242,12 @@ Download size: %3 Save - + 儲存 Load - + 載入 @@ -287,28 +287,28 @@ Download size: %3 BattleChip data missing - + 缺少 BattleChip 數據 BattleChip data is missing. BattleChip Gates will still work, but some graphics will be missing. Would you like to download the data now? - + 缺少 BattleChip 數據。 BattleChip Gate 仍然可以使用,但一些圖形將會遺失。您要立即下載資料嗎? Select deck file - + 選擇卡座文件 Incompatible deck - + 不相容的卡座 The selected deck is not compatible with this Chip Gate - + 所選卡座與此 Chip Gate 不相容 @@ -341,7 +341,7 @@ Download size: %3 Some cheats could not be added. Please ensure they're formatted correctly and/or try other cheat types. - + 無法新增某些作弊碼。請確認它們的格式是否正確並且/或嘗試其它的作弊類型。 @@ -356,12 +356,12 @@ Download size: %3 Load - + 載入 Save - + 儲存 @@ -389,23 +389,23 @@ Download size: %3 Reset r%1-%2 %3 - + 重置 r%1-%2 %3 Rewinding not currently enabled - + 目前未開啟倒帶 Reset the game? - + 要重置遊戲嗎? Most games will require a reset to load the new save. Do you want to reset now? - + 大多數遊戲需要重置才能載入新的檔案。您要立即重啟嗎? @@ -474,7 +474,7 @@ Download size: %3 Could not open CLI history for writing - + 無法開啟用於寫入的 CLI 歷史 @@ -482,7 +482,7 @@ Download size: %3 Failed to create an OpenGL 3 context, trying old-style... - + 建立OpenGL3環境失敗,請嘗試舊形式... @@ -525,12 +525,12 @@ Download size: %3 Couldn't Connect - + 無法連接 Could not connect to Dolphin. - + 無法連線到 Dolphin。 @@ -538,12 +538,12 @@ Download size: %3 3DS - + 3DS Vita - + Vita @@ -551,12 +551,12 @@ Download size: %3 Icon - + 圖示 Banner - + 橫幅 @@ -564,7 +564,7 @@ Download size: %3 Bubble - + 氣泡 @@ -574,7 +574,7 @@ Download size: %3 Startup - + 啟動 @@ -582,17 +582,17 @@ Download size: %3 Create forwarder - + 建立轉發器 Files - + 文件 ROM file: - + ROM 文件: @@ -604,127 +604,127 @@ Download size: %3 Output filename: - + 輸出檔名: Forwarder base: - + 轉發器基礎: Latest stable version - + 最新穩定版本 Latest development build - + 最新開發版本 Specific file - + 指定文件 Base file: - + 基礎文件: System - + 系統 3DS - + 3DS Vita - + Vita Presentation - + 介紹 Title: - + 標題: Images: - + 圖像: Use default image - + 使用預設影像 Preferred size: - + 首選大小: Select image file - + 選擇圖像文件 Select ROM file - + 選擇ROM文件 Select output filename - + 選擇輸出檔名 Select base file - + 選擇基礎文件 Build finished - + 已完成建置 Forwarder finished building - + 已完成建置轉發器 Build failed - + 建置失敗 Failed to build forwarder - + 建立轉發器失敗 %1 installable package (*.%2) - + %1 個可安裝套件 (*.%2) Select an image - + 選擇一個影像 Image files (*.png *.jpg *.bmp) - + 圖片檔案 (*.png *.jpg *.bmp) @@ -866,22 +866,22 @@ Download size: %3 Write watchpoints behavior - + 編寫觀察點行為 Standard GDB - + 標準 GDB Internal change detection - + 內部變化檢測 Break on all writes - + 中斷所有寫入操作 @@ -939,7 +939,7 @@ Download size: %3 Start - + 開始 @@ -983,102 +983,102 @@ Download size: %3 Game Boy (DMG) - + Game Boy (DMG) Game Boy Pocket (MGB) - + Game Boy Pocket (MGB) Super Game Boy (SGB) - + Super Game Boy (SGB) Super Game Boy 2 (SGB) - + Super Game Boy 2 (SGB) Game Boy Color (CGB) - + Game Boy Color (CGB) Game Boy Advance (AGB) - + Game Boy Advance (AGB) Super Game Boy Color (SGB + CGB) - + Super Game Boy Color (SGB + CGB) ROM Only - + 僅 ROM MBC1 - + MBC1 MBC2 - + MBC2 MBC3 - + MBC3 MBC3 + RTC - + MBC3 + 實時時鐘 MBC5 - + MBC5 MBC5 + Rumble - + MBC5 + 震動 MBC6 - + MBC6 MBC7 (Tilt) - + MBC7 (Tilt) MMM01 - + MMM01 HuC-1 - + HuC-1 HuC-3 - + HuC-3 Pocket Cam - + 袖珍攝影機 @@ -1088,57 +1088,57 @@ Download size: %3 Wisdom Tree - + Wisdom Tree NT (old 1) - + NT (舊 1) NT (old 2) - + NT (舊 2) NT (new) - + NT(新) Pokémon Jade/Diamond - + 寶可夢翡翠/鑽石 BBD - + BBD Hitek - + Hitek GGB-81 - + GGB-81 Li Cheng - + Li Cheng Sachen (MMC1) - + Sachen (MMC1) Sachen (MMC2) - + Sachen (MMC2) @@ -3338,7 +3338,7 @@ Download size: %3 Map Addr. - 映射位址 + 映射位址。 @@ -3408,12 +3408,12 @@ Download size: %3 Memory access logging - + 記憶體存取日誌 Log file - + 紀錄檔案 @@ -3423,27 +3423,27 @@ Download size: %3 Log additional information (uses 3× space) - + 記錄額外資訊(使用 3x 空間) Load existing file if present - + 存在的情況下載入已有文件 Regions - + 區域 Export ROM snapshot - + 匯出ROM快照 Start - + 啟動 @@ -3453,18 +3453,18 @@ Download size: %3 Failed to open memory log file - + 打開記憶體日誌檔案失敗 Select access log file - + 選擇訪問日誌文件 Memory access logs (*.mal) - + 記憶體存取日誌(*.mal) @@ -3808,7 +3808,7 @@ Download size: %3 Load - + 載入 @@ -3816,7 +3816,7 @@ Download size: %3 Frame %1 - + 帧 %1 @@ -3824,17 +3824,17 @@ Download size: %3 Trying to detach a multiplayer player that's not attached - + 嘗試斷開與未連接的多人玩家的連接 Clearing invalid save ID - + 清理非法存檔ID Clearing invalid preferred ID - + 清理非法優先ID @@ -4407,7 +4407,7 @@ Download size: %3 Game ID: - 遊戲 ID + 遊戲 ID: @@ -5506,12 +5506,12 @@ Download size: %3 Default sprite colors 1: - 預設角色圖顏色組 1 + 預設角色圖顏色組 1: Default sprite colors 2: - 預設角色圖顏色組 2 + 預設角色圖顏色組 2: @@ -6213,7 +6213,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may %1 of %2 e-Reader cards converted successfully. - %1 張 e-Reader 卡片轉換成功。 (共 %2 張) + %2 張電子閱讀器卡中的 %1 張已成功轉換。 @@ -6243,17 +6243,17 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Scan e-Reader dotcodes... - 掃描 e-Reader 點碼 + 掃描 e-Reader 點碼... Convert e-Reader card image to raw... - 轉換 e-Reader 卡片圖檔為原始資料 + 轉換 e-Reader 卡片圖檔為原始資料... ROM &info... - ROM 資訊 (&I) + ROM 資訊 (&I)... @@ -6344,12 +6344,12 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Import GameShark Save... - 匯入 GameShark 存檔 + 匯入 GameShark 存檔... Export GameShark Save... - 匯出 GameShark 存檔 + 匯出 GameShark 存檔... @@ -6614,12 +6614,12 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may View &logs... - 查看記錄檔 (&L) + 查看記錄檔 (&L)... Game &overrides... - 遊戲替代 (&O) + 遊戲替代 (&O)... @@ -6629,7 +6629,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may &Cheats... - 金手指 (&C) + 金手指 (&C)... @@ -6654,7 +6654,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Start &GDB server... - 啟動 GDB 伺服器 (&G) + 啟動 GDB 伺服器 (&G)... @@ -6664,27 +6664,27 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may View &palette... - 檢視調色盤 (&P) + 檢視調色盤 (&P)... View &sprites... - 檢視角色圖 (&S) + 檢視角色圖 (&S)... View &tiles... - 檢視圖塊 (&T) + 檢視圖塊 (&T)... View &map... - 檢視映射 (&M) + 檢視映射 (&M)... &Frame inspector... - 畫格檢視器 (&F) + 畫格檢視器 (&F)... @@ -6699,7 +6699,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may View &I/O registers... - 檢視 I/O 暫存器 (&I) + 檢視 I/O 暫存器 (&I)... From d96ff26983feb612400f54d1aaa141f05f922ade Mon Sep 17 00:00:00 2001 From: Roll8ack Date: Mon, 16 Dec 2024 03:24:29 +0000 Subject: [PATCH 12/32] Qt: Update translation (Chinese (Simplified Han script)) Translation: mGBA/Qt Translate-URL: https://hosted.weblate.org/projects/mgba/mgba-qt/zh_Hans/ --- src/platform/qt/ts/mgba-zh_CN.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/platform/qt/ts/mgba-zh_CN.ts b/src/platform/qt/ts/mgba-zh_CN.ts index a051d76fb..801bacb8f 100644 --- a/src/platform/qt/ts/mgba-zh_CN.ts +++ b/src/platform/qt/ts/mgba-zh_CN.ts @@ -3829,17 +3829,17 @@ Download size: %3 Clearing invalid save ID - + 清理非法存档ID Clearing invalid preferred ID - + 清理非法优先ID Trying to get player ID for a multiplayer player that's not attached - 尝试获取未连接的多人玩家的 ID + 尝试获取多人联机中未连接上的玩家ID From 61d1dc742dad10878bc7c90ab96f467e8627f1c3 Mon Sep 17 00:00:00 2001 From: Artur Dudka Date: Wed, 25 Dec 2024 12:41:21 +0000 Subject: [PATCH 13/32] Qt: Update translation (Polish) Translation: mGBA/Qt Translate-URL: https://hosted.weblate.org/projects/mgba/mgba-qt/pl/ --- src/platform/qt/ts/mgba-pl.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/platform/qt/ts/mgba-pl.ts b/src/platform/qt/ts/mgba-pl.ts index e4b191608..e50eb3d4c 100644 --- a/src/platform/qt/ts/mgba-pl.ts +++ b/src/platform/qt/ts/mgba-pl.ts @@ -3408,12 +3408,12 @@ Rozmiar pobierania: %3 Memory access logging - + Logowanie dostępu do pamięci Log file - + Plik logów @@ -3423,7 +3423,7 @@ Rozmiar pobierania: %3 Log additional information (uses 3× space) - + Loguj dodatkowe informacje (używa 3× miejsca) @@ -3433,12 +3433,12 @@ Rozmiar pobierania: %3 Regions - + Regiony Export ROM snapshot - + Eksportuj zrzut ROMu @@ -3453,7 +3453,7 @@ Rozmiar pobierania: %3 Failed to open memory log file - + Błąd odczytu pliku logów pamięci @@ -4367,7 +4367,7 @@ Rozmiar pobierania: %3 File information - + Informacje o pliku @@ -4377,12 +4377,12 @@ Rozmiar pobierania: %3 MD5 - + MD5 ROM header - + Nagłówek ROMu @@ -4402,7 +4402,7 @@ Rozmiar pobierania: %3 Revision: - + Rewizja: @@ -5668,12 +5668,12 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may mGBA Shaders - + Shadery mGBA Error loading shader - + Błąd wczytywania shaderu From 87bf98233847dad51c1eb8246e05775c92af0c61 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 11 Jan 2025 14:54:53 -0800 Subject: [PATCH 14/32] Qt: Update translations --- src/platform/qt/ts/mgba-de.ts | 74 +++++++++++++++------------- src/platform/qt/ts/mgba-en.ts | 74 +++++++++++++++------------- src/platform/qt/ts/mgba-es.ts | 74 +++++++++++++++------------- src/platform/qt/ts/mgba-fr.ts | 74 +++++++++++++++------------- src/platform/qt/ts/mgba-hu.ts | 74 +++++++++++++++------------- src/platform/qt/ts/mgba-it.ts | 74 +++++++++++++++------------- src/platform/qt/ts/mgba-ja.ts | 74 +++++++++++++++------------- src/platform/qt/ts/mgba-ko.ts | 74 +++++++++++++++------------- src/platform/qt/ts/mgba-ms.ts | 74 +++++++++++++++------------- src/platform/qt/ts/mgba-nb_NO.ts | 74 +++++++++++++++------------- src/platform/qt/ts/mgba-pl.ts | 74 +++++++++++++++------------- src/platform/qt/ts/mgba-pt_BR.ts | 74 +++++++++++++++------------- src/platform/qt/ts/mgba-pt_PT.ts | 74 +++++++++++++++------------- src/platform/qt/ts/mgba-ru.ts | 74 +++++++++++++++------------- src/platform/qt/ts/mgba-sv.ts | 74 +++++++++++++++------------- src/platform/qt/ts/mgba-template.ts | 74 +++++++++++++++------------- src/platform/qt/ts/mgba-tr.ts | 74 +++++++++++++++------------- src/platform/qt/ts/mgba-zh_CN.ts | 74 +++++++++++++++------------- src/platform/qt/ts/mgba-zh_Hant.ts | 76 +++++++++++++++-------------- 19 files changed, 742 insertions(+), 666 deletions(-) diff --git a/src/platform/qt/ts/mgba-de.ts b/src/platform/qt/ts/mgba-de.ts index b430e2758..726f511d6 100644 --- a/src/platform/qt/ts/mgba-de.ts +++ b/src/platform/qt/ts/mgba-de.ts @@ -387,48 +387,48 @@ Download-Größe: %3 QGBA::CoreController - + Reset r%1-%2 %3 r%1-%2 %3 zurücksetzen - - + + Rewinding not currently enabled Zurückspulen ist derzeit nicht aktiviert - + Reset the game? Spiel zurücksetzen? - + Most games will require a reset to load the new save. Do you want to reset now? Die meisten Spiele müssen zurückgesetzt werden, um einen neuen Spielstand zu laden. Möchtest Du das Spiel jetzt zurücksetzen? - + Failed to open save file: %1 Fehler beim Öffnen der Speicherdatei: %1 - + Failed to open game file: %1 Fehler beim Öffnen der Spieldatei: %1 - + Can't yank pack in unexpected platform! Das GamePak kann nur auf unterstützten Plattformen herausgezogen werden! - + Failed to open snapshot file for reading: %1 Konnte Snapshot-Datei %1 nicht zum Lesen öffnen - + Failed to open snapshot file for writing: %1 Konnte Snapshot-Datei %1 nicht zum Schreiben öffnen @@ -3403,6 +3403,15 @@ Download-Größe: %3 Portable Network Graphics (*.png) + + QGBA::MemoryAccessLogController + + + + Failed to open memory log file + + + QGBA::MemoryAccessLogView @@ -3451,18 +3460,13 @@ Download-Größe: %3 Stopp - - Failed to open memory log file - - - - - + + Select access log file - + Memory access logs (*.mal) @@ -6187,7 +6191,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may ROM ersetzen... - + Convert e-Reader card image to raw... Lesegerät-Kartenbild in Rohdaten umwandeln … @@ -6498,7 +6502,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may - + Clear Leeren @@ -6714,77 +6718,77 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may &I/O-Register betrachten... - + Record debug video log... Video-Protokoll aufzeichnen... - + Stop debug video log Aufzeichnen des Video-Protokolls beenden - + Exit fullscreen Vollbildmodus beenden - + GameShark Button (held) GameShark-Taste (gehalten) - + Autofire Autofeuer - + Autofire A Autofeuer A - + Autofire B Autofeuer B - + Autofire L Autofeuer L - + Autofire R Autofeuer R - + Autofire Start Autofeuer Start - + Autofire Select Autofeuer Select - + Autofire Up Autofeuer nach oben - + Autofire Right Autofeuer rechts - + Autofire Down Autofeuer nach unten - + Autofire Left Autofeuer links diff --git a/src/platform/qt/ts/mgba-en.ts b/src/platform/qt/ts/mgba-en.ts index 316c5d2c3..20b0fe65b 100644 --- a/src/platform/qt/ts/mgba-en.ts +++ b/src/platform/qt/ts/mgba-en.ts @@ -381,48 +381,48 @@ Download size: %3 QGBA::CoreController - + Reset r%1-%2 %3 - - + + Rewinding not currently enabled - + Reset the game? - + Most games will require a reset to load the new save. Do you want to reset now? - + Failed to open save file: %1 - + Failed to open game file: %1 - + Can't yank pack in unexpected platform! - + Failed to open snapshot file for reading: %1 - + Failed to open snapshot file for writing: %1 @@ -3397,6 +3397,15 @@ Download size: %3 + + QGBA::MemoryAccessLogController + + + + Failed to open memory log file + + + QGBA::MemoryAccessLogView @@ -3445,18 +3454,13 @@ Download size: %3 - - Failed to open memory log file - - - - - + + Select access log file - + Memory access logs (*.mal) @@ -6230,7 +6234,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may - + Convert e-Reader card image to raw... @@ -6701,82 +6705,82 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may - + Record debug video log... - + Stop debug video log - + Exit fullscreen - + GameShark Button (held) - + Autofire - + Autofire A - + Autofire B - + Autofire L - + Autofire R - + Autofire Start - + Autofire Select - + Autofire Up - + Autofire Right - + Autofire Down - + Autofire Left - + Clear diff --git a/src/platform/qt/ts/mgba-es.ts b/src/platform/qt/ts/mgba-es.ts index d1701d571..6aa86cb78 100644 --- a/src/platform/qt/ts/mgba-es.ts +++ b/src/platform/qt/ts/mgba-es.ts @@ -387,48 +387,48 @@ Tamaño de descarga: %3 QGBA::CoreController - + Reset r%1-%2 %3 Reiniciar r%1-%2 %3 - - + + Rewinding not currently enabled Rebobinado desactivado actualmente - + Reset the game? ¿Reiniciar el juego? - + Most games will require a reset to load the new save. Do you want to reset now? La mayoría de juegos requieren reiniciar para cargar la nueva partida guardada. ¿Quieres reiniciar ahora? - + Failed to open save file: %1 Error al abrir el archivo de guardado: %1 - + Failed to open game file: %1 Error al abrir el archivo del juego: %1 - + Can't yank pack in unexpected platform! ¡No se puede quitar el cartucho en esta plataforma! - + Failed to open snapshot file for reading: %1 Error al leer del archivo de captura: %1 - + Failed to open snapshot file for writing: %1 Error al escribir al archivo de captura: %1 @@ -3403,6 +3403,15 @@ Tamaño de descarga: %3 Gráficos de red portátiles (*.png) + + QGBA::MemoryAccessLogController + + + + Failed to open memory log file + Error al abrir el archivo de registro de memoria + + QGBA::MemoryAccessLogView @@ -3451,18 +3460,13 @@ Tamaño de descarga: %3 Detener - - Failed to open memory log file - Error al abrir el archivo de registro de memoria - - - - + + Select access log file Seleccionar archivo de registro de acceso - + Memory access logs (*.mal) Archivos de registro de memoria (*.mal) @@ -6224,7 +6228,7 @@ Si está configurado como OpenGL y estás viendo esto, tu tarjeta gráfica o con Sensores del cartucho... - + Clear Limpiar @@ -6285,7 +6289,7 @@ Si está configurado como OpenGL y estás viendo esto, tu tarjeta gráfica o con Cargar partida guardada temporal... - + Convert e-Reader card image to raw... Convertir imagen de tarjeta e-Reader a archivo en bruto... @@ -6716,77 +6720,77 @@ Si está configurado como OpenGL y estás viendo esto, tu tarjeta gráfica o con Registrar &accesoa la memoria… - + Record debug video log... Grabar registro de depuración de vídeo... - + Stop debug video log Detener registro de depuración de vídeo - + Exit fullscreen Salir de pantalla completa - + GameShark Button (held) Botón GameShark (mantener) - + Autofire Disparo automático - + Autofire A Disparo automático A - + Autofire B Disparo automático B - + Autofire L Disparo automático L - + Autofire R Disparo automático R - + Autofire Start Disparo automático Start - + Autofire Select Disparo automático Select - + Autofire Up Disparo automático arriba - + Autofire Right Disparo automático derecha - + Autofire Down Disparo automático abajo - + Autofire Left Disparo automático izquierda diff --git a/src/platform/qt/ts/mgba-fr.ts b/src/platform/qt/ts/mgba-fr.ts index 04411e5c3..628941e50 100644 --- a/src/platform/qt/ts/mgba-fr.ts +++ b/src/platform/qt/ts/mgba-fr.ts @@ -388,48 +388,48 @@ Taille du téléchargement : %3 QGBA::CoreController - + Reset r%1-%2 %3 Réinitialiser r%1-%2 %3 - - + + Rewinding not currently enabled Le rembobinage n'est pas actuellement activé - + Reset the game? Réinitialiser le jeu ? - + Most games will require a reset to load the new save. Do you want to reset now? La plupart des jeux nécessitent une réinitialisation pour charger la nouvelle sauvegarde. Voulez-vous réinitialiser maintenant ? - + Failed to open save file: %1 Échec de l'ouverture du fichier de sauvegarde : %1 - + Failed to open game file: %1 Échec de l'ouverture du fichier de jeu : %1 - + Can't yank pack in unexpected platform! - + Failed to open snapshot file for reading: %1 Échec de l'ouverture de l'instantané pour lire : %1 - + Failed to open snapshot file for writing: %1 Échec de l'ouverture de l'instantané pour écrire : %1 @@ -3421,6 +3421,15 @@ Taille du téléchargement : %3 Portable Network Graphics (*.png) + + QGBA::MemoryAccessLogController + + + + Failed to open memory log file + + + QGBA::MemoryAccessLogView @@ -3469,18 +3478,13 @@ Taille du téléchargement : %3 Arrêter - - Failed to open memory log file - - - - - + + Select access log file - + Memory access logs (*.mal) @@ -6241,7 +6245,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may - + Convert e-Reader card image to raw... @@ -6728,82 +6732,82 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Voir les registres d'&E/S... - + Record debug video log... Enregistrer le journal vidéo de débogage... - + Stop debug video log Arrêter le journal vidéo de débogage - + Exit fullscreen Quitter le plein écran - + GameShark Button (held) Bouton GameShark (maintenir) - + Autofire Tir automatique - + Autofire A Tir automatique A - + Autofire B Tir automatique B - + Autofire L Tir automatique L - + Autofire R Tir automatique R - + Autofire Start Tir automatique Start - + Autofire Select Tir automatique Select - + Autofire Up Tir automatique Up - + Autofire Right Tir automatique Right - + Autofire Down Tir automatique Down - + Autofire Left Tir automatique Gauche - + Clear Vider diff --git a/src/platform/qt/ts/mgba-hu.ts b/src/platform/qt/ts/mgba-hu.ts index b7da40d8c..95f654c8a 100644 --- a/src/platform/qt/ts/mgba-hu.ts +++ b/src/platform/qt/ts/mgba-hu.ts @@ -388,48 +388,48 @@ Letöltendő adat: %3 QGBA::CoreController - + Reset r%1-%2 %3 - - + + Rewinding not currently enabled Visszatekerés jelenleg nem engedélyezett - + Reset the game? - + Most games will require a reset to load the new save. Do you want to reset now? - + Failed to open save file: %1 Nem sikerült a mentésfájl megnyitása: %1 - + Failed to open game file: %1 Nem sikerült a játékfájl megnyitása: %1 - + Can't yank pack in unexpected platform! A játékkazettát nem lehet kirántani ismeretlen platformon! - + Failed to open snapshot file for reading: %1 A pillanatkép fájljának olvasásra való megnyitása sikertelen: %1 - + Failed to open snapshot file for writing: %1 A pillanatkép fájljának írásra való megnyitása sikertelen: %1 @@ -3404,6 +3404,15 @@ Letöltendő adat: %3 Portable Network Graphics (*.png) + + QGBA::MemoryAccessLogController + + + + Failed to open memory log file + + + QGBA::MemoryAccessLogView @@ -3452,18 +3461,13 @@ Letöltendő adat: %3 - - Failed to open memory log file - - - - - + + Select access log file - + Memory access logs (*.mal) @@ -6235,7 +6239,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may - + Convert e-Reader card image to raw... @@ -6706,82 +6710,82 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may - + Record debug video log... - + Stop debug video log - + Exit fullscreen - + GameShark Button (held) - + Autofire - + Autofire A - + Autofire B - + Autofire L - + Autofire R - + Autofire Start - + Autofire Select - + Autofire Up - + Autofire Right - + Autofire Down - + Autofire Left - + Clear Napló törlése diff --git a/src/platform/qt/ts/mgba-it.ts b/src/platform/qt/ts/mgba-it.ts index 6aaf5d809..f12794bb1 100644 --- a/src/platform/qt/ts/mgba-it.ts +++ b/src/platform/qt/ts/mgba-it.ts @@ -387,48 +387,48 @@ Dimensione del download: %3 QGBA::CoreController - + Reset r%1-%2 %3 Reset r%1-%2 %3 - - + + Rewinding not currently enabled La funzione 'riavvolgi' non è attualmente abilitata - + Reset the game? Riavviare il gioco? - + Most games will require a reset to load the new save. Do you want to reset now? La maggior parte dei giochi richiede un riavvio per caricare il nuovo salvataggio. Vuoi riavviare ora? - + Failed to open save file: %1 Impossibile aprire il file di salvataggio: %1 - + Failed to open game file: %1 Impossibile aprire il file di gioco: %1 - + Can't yank pack in unexpected platform! Non riesco a strappare il pacchetto in una piattaforma inaspettata! - + Failed to open snapshot file for reading: %1 Impossibile aprire il file snapshot per la lettura: %1 - + Failed to open snapshot file for writing: %1 Impossibile aprire il file snapshot per la scrittura: %1 @@ -3403,6 +3403,15 @@ Dimensione del download: %3 Portable Network Graphics (*.png) + + QGBA::MemoryAccessLogController + + + + Failed to open memory log file + Impossibile aprire il file di registro della memoria + + QGBA::MemoryAccessLogView @@ -3451,18 +3460,13 @@ Dimensione del download: %3 Ferma - - Failed to open memory log file - Impossibile aprire il file di registro della memoria - - - - + + Select access log file Seleziona il file di registro di accesso - + Memory access logs (*.mal) Registri degli accessi alla memoria (*.mal) @@ -6187,7 +6191,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Scansiona e-Reader dotcode... - + Convert e-Reader card image to raw... Converti immagini carte e-Reader in raw... @@ -6709,82 +6713,82 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Registra memoria &accessi... - + Record debug video log... Salva registro video di debug... - + Stop debug video log Ferma registro video di debug - + Exit fullscreen Esci da Schermo Intero - + GameShark Button (held) Pulsante GameShark (tieni premuto) - + Autofire Pulsanti Autofire - + Autofire A Autofire A - + Autofire B Autofire B - + Autofire L Autofire L - + Autofire R Autofire R - + Autofire Start Autofire Start - + Autofire Select Autofire Select - + Autofire Up Autofire Su - + Autofire Right AAutofire Destra - + Autofire Down Autofire Giù - + Autofire Left Autofire Sinistra - + Clear Pulisci diff --git a/src/platform/qt/ts/mgba-ja.ts b/src/platform/qt/ts/mgba-ja.ts index 8a2425753..5d4fa2a78 100644 --- a/src/platform/qt/ts/mgba-ja.ts +++ b/src/platform/qt/ts/mgba-ja.ts @@ -387,48 +387,48 @@ Download size: %3 QGBA::CoreController - + Reset r%1-%2 %3 - - + + Rewinding not currently enabled - + Reset the game? - + Most games will require a reset to load the new save. Do you want to reset now? - + Failed to open save file: %1 セーブファイルを開けませんでした: %1 - + Failed to open game file: %1 ゲームファイルを開けませんでした: %1 - + Can't yank pack in unexpected platform! 予期しないプラットフォームでパックをヤンクすることはできません! - + Failed to open snapshot file for reading: %1 読み取り用のスナップショットファイルを開けませんでした: %1 - + Failed to open snapshot file for writing: %1 書き込み用のスナップショットファイルを開けませんでした: %1 @@ -3403,6 +3403,15 @@ Download size: %3 Portable Network Graphics (*.png) + + QGBA::MemoryAccessLogController + + + + Failed to open memory log file + + + QGBA::MemoryAccessLogView @@ -3451,18 +3460,13 @@ Download size: %3 停止 - - Failed to open memory log file - - - - - + + Select access log file - + Memory access logs (*.mal) @@ -6225,7 +6229,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may カートリッジセンサー... - + Clear 消去 @@ -6286,7 +6290,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may - + Convert e-Reader card image to raw... @@ -6712,77 +6716,77 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may - + Record debug video log... デバッグビデオログ... - + Stop debug video log デバッグビデオログを停止 - + Exit fullscreen 全画面表示を終了 - + GameShark Button (held) GameSharkボタン(押し) - + Autofire 連打 - + Autofire A 連打 A - + Autofire B 連打 B - + Autofire L 連打 L - + Autofire R 連打 R - + Autofire Start 連打 Start - + Autofire Select 連打 Select - + Autofire Up 連打 上 - + Autofire Right 連打 右 - + Autofire Down 連打 下 - + Autofire Left 連打 左 diff --git a/src/platform/qt/ts/mgba-ko.ts b/src/platform/qt/ts/mgba-ko.ts index e6363dd49..18fc7ea44 100644 --- a/src/platform/qt/ts/mgba-ko.ts +++ b/src/platform/qt/ts/mgba-ko.ts @@ -387,48 +387,48 @@ Download size: %3 QGBA::CoreController - + Reset r%1-%2 %3 r%1-%2 %3 재설정 - - + + Rewinding not currently enabled 현재 활성화되지 않은 되감기 - + Reset the game? 게임을 재설정하겠습니까? - + Most games will require a reset to load the new save. Do you want to reset now? 대부분의 게임은 새로운 저장을 로드하려면 재설정이 필요합니다. 지금 재설정하겠습니까? - + Failed to open save file: %1 저장 파일을 열지 못했습니다: %1 - + Failed to open game file: %1 게임 파일을 열지 못했습니다: %1 - + Can't yank pack in unexpected platform! 예기치 않은 플랫폼에서 팩을 잡아당길 수 없습니다! - + Failed to open snapshot file for reading: %1 읽기 용 스냅샷 파일을 열지 못했습니다: %1 - + Failed to open snapshot file for writing: %1 쓰기 용 스냅샷 파일을 열지 못했습니다: %1 @@ -3403,6 +3403,15 @@ Download size: %3 휴대용 네트워크 그래픽 (*.png) + + QGBA::MemoryAccessLogController + + + + Failed to open memory log file + 메모리 로그 파일을 열 수 없음 + + QGBA::MemoryAccessLogView @@ -3451,18 +3460,13 @@ Download size: %3 정지 - - Failed to open memory log file - 메모리 로그 파일을 열 수 없음 - - - - + + Select access log file 접속 파일 선택 - + Memory access logs (*.mal) 메모리 접속 로그 (*.mal) @@ -6215,7 +6219,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may 게임 상태 보기 - + Convert e-Reader card image to raw... e-리더 카드 이미지를 원시 데이터로 변환... @@ -6707,82 +6711,82 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may 메모리 및 접속 기록... - + Record debug video log... 디버그 비디오 로그 녹화... - + Stop debug video log 디버그 비디오 로그 중지 - + Exit fullscreen 전체화면 종료 - + GameShark Button (held) 게임샤크 버튼 (누름) - + Autofire 연사 - + Autofire A 연사 A - + Autofire B 연사 B - + Autofire L 연사 L - + Autofire R 연사 R - + Autofire Start 연사 시작 - + Autofire Select 연사 선택 - + Clear 지움 - + Autofire Up 연사 위쪽 - + Autofire Right 연사 오른쪽 - + Autofire Down 연사 아래쪽 - + Autofire Left 연사 왼쪽 diff --git a/src/platform/qt/ts/mgba-ms.ts b/src/platform/qt/ts/mgba-ms.ts index d8b2f9b09..077aad1e6 100644 --- a/src/platform/qt/ts/mgba-ms.ts +++ b/src/platform/qt/ts/mgba-ms.ts @@ -381,48 +381,48 @@ Download size: %3 QGBA::CoreController - + Reset r%1-%2 %3 - - + + Rewinding not currently enabled - + Reset the game? - + Most games will require a reset to load the new save. Do you want to reset now? - + Failed to open save file: %1 Gagal membuka fail tersimpan: %1 - + Failed to open game file: %1 Gagal membuka fail permainan: %1 - + Can't yank pack in unexpected platform! - + Failed to open snapshot file for reading: %1 Gagal membuka fail snapshot untuk baca: %1 - + Failed to open snapshot file for writing: %1 Gagal membuka fail snapshot untuk menulis: %1 @@ -3397,6 +3397,15 @@ Download size: %3 Grafik Rangkaian Mudah Alih (*.png) + + QGBA::MemoryAccessLogController + + + + Failed to open memory log file + + + QGBA::MemoryAccessLogView @@ -3445,18 +3454,13 @@ Download size: %3 Henti - - Failed to open memory log file - - - - - + + Select access log file - + Memory access logs (*.mal) @@ -6230,7 +6234,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may - + Convert e-Reader card image to raw... @@ -6701,82 +6705,82 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may - + Record debug video log... Rakam log video nyahpepijat... - + Stop debug video log Henti log video nyahpepijat - + Exit fullscreen Keluar skrinpenuh - + GameShark Button (held) Butang GameShark (pegang) - + Autofire - + Autofire A - + Autofire B - + Autofire L - + Autofire R - + Autofire Start - + Autofire Select - + Autofire Up - + Autofire Right - + Autofire Down - + Autofire Left - + Clear Kosongkan diff --git a/src/platform/qt/ts/mgba-nb_NO.ts b/src/platform/qt/ts/mgba-nb_NO.ts index f62f3793a..3042bccf2 100644 --- a/src/platform/qt/ts/mgba-nb_NO.ts +++ b/src/platform/qt/ts/mgba-nb_NO.ts @@ -385,48 +385,48 @@ Nedlastningsstørrelse: %3 QGBA::CoreController - + Reset r%1-%2 %3 - - + + Rewinding not currently enabled - + Reset the game? Vil du starte spillet på nytt? - + Most games will require a reset to load the new save. Do you want to reset now? - + Failed to open save file: %1 - + Failed to open game file: %1 Klarte ikke å åpne spillfil: %1 - + Can't yank pack in unexpected platform! - + Failed to open snapshot file for reading: %1 - + Failed to open snapshot file for writing: %1 @@ -3401,6 +3401,15 @@ Nedlastningsstørrelse: %3 Portable Network Graphics (*.png) + + QGBA::MemoryAccessLogController + + + + Failed to open memory log file + + + QGBA::MemoryAccessLogView @@ -3449,18 +3458,13 @@ Nedlastningsstørrelse: %3 Stopp - - Failed to open memory log file - - - - - + + Select access log file - + Memory access logs (*.mal) @@ -6234,7 +6238,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Skann e-Reader-punktkoder... - + Convert e-Reader card image to raw... @@ -6705,82 +6709,82 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may - + Record debug video log... - + Stop debug video log - + Exit fullscreen Gå ut av fullskjerm - + GameShark Button (held) - + Autofire - + Autofire A - + Autofire B - + Autofire L - + Autofire R - + Autofire Start - + Autofire Select - + Autofire Up - + Autofire Right - + Autofire Down - + Autofire Left - + Clear Tøm diff --git a/src/platform/qt/ts/mgba-pl.ts b/src/platform/qt/ts/mgba-pl.ts index e50eb3d4c..15b04da90 100644 --- a/src/platform/qt/ts/mgba-pl.ts +++ b/src/platform/qt/ts/mgba-pl.ts @@ -387,48 +387,48 @@ Rozmiar pobierania: %3 QGBA::CoreController - + Reset r%1-%2 %3 Reset r%1-%2 %3 - - + + Rewinding not currently enabled Przewijanie nie jest obecnie włączone - + Reset the game? Zresetować grę? - + Most games will require a reset to load the new save. Do you want to reset now? Większość gier wymaga zresetowania, aby wczytać nowy zapis. Czy chcesz teraz zresetować? - + Failed to open save file: %1 Nie udało się otworzyć pliku zapisu: %1 - + Failed to open game file: %1 Nie udało się otworzyć pliku gry: %1 - + Can't yank pack in unexpected platform! Nie można wyciągnąć pack na nieoczekiwanej platformie! - + Failed to open snapshot file for reading: %1 Nie udało się otworzyć pliku snapshot do odczytu: %1 - + Failed to open snapshot file for writing: %1 Nie udało się otworzyć pliku snapshot do zapisu: %1 @@ -3403,6 +3403,15 @@ Rozmiar pobierania: %3 Portable Network Graphics (*.png) + + QGBA::MemoryAccessLogController + + + + Failed to open memory log file + Błąd odczytu pliku logów pamięci + + QGBA::MemoryAccessLogView @@ -3451,18 +3460,13 @@ Rozmiar pobierania: %3 Stop - - Failed to open memory log file - Błąd odczytu pliku logów pamięci - - - - + + Select access log file - + Memory access logs (*.mal) @@ -6240,7 +6244,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Skanuj kody kropkowe czytnika e-Reader... - + Convert e-Reader card image to raw... Konwertuj obraz karty czytnika e-Reader na surowy... @@ -6711,82 +6715,82 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may - + Record debug video log... Nagraj dziennik wideo debugowania... - + Stop debug video log Zatrzymaj dziennik wideo debugowania - + Exit fullscreen Wyłączyć tryb pełnoekranowy - + GameShark Button (held) Przycisk GameShark (przytrzymany) - + Autofire Turbo - + Autofire A Turbo A - + Autofire B Turbo B - + Autofire L Turbo L - + Autofire R Turbo R - + Autofire Start Turbo Start - + Autofire Select Turbo Select - + Autofire Up Turbo Góra - + Autofire Right Turbo Prawo - + Autofire Down Turbo Dół - + Autofire Left Turbo Lewo - + Clear Wyczyść diff --git a/src/platform/qt/ts/mgba-pt_BR.ts b/src/platform/qt/ts/mgba-pt_BR.ts index 9b3ca1750..dbe2b3b46 100644 --- a/src/platform/qt/ts/mgba-pt_BR.ts +++ b/src/platform/qt/ts/mgba-pt_BR.ts @@ -387,48 +387,48 @@ Tamanho do download: %3 QGBA::CoreController - + Reset r%1-%2 %3 Resetar r%1-%2 %3 - - + + Rewinding not currently enabled O rebobinamento não está ativado atualmente - + Reset the game? Resetar o jogo? - + Most games will require a reset to load the new save. Do you want to reset now? A maioria dos jogos requerirão um reset pra carregar o novo save. Você quer resetar agora? - + Failed to open save file: %1 Falhou em abrir o arquivo do save: %1 - + Failed to open game file: %1 Falhou em abrir o arquivo do jogo: %1 - + Can't yank pack in unexpected platform! Não pode arrancar o pacote numa plataforma inesperada! - + Failed to open snapshot file for reading: %1 Falhou em abrir o arquivo do snapshot pra leitura: %1 - + Failed to open snapshot file for writing: %1 Falhou em abrir o arquivo do snapshot pra gravação: %1 @@ -3403,6 +3403,15 @@ Tamanho do download: %3 Gráficos Portáteis da Rede (*.png) + + QGBA::MemoryAccessLogController + + + + Failed to open memory log file + Falhou em abrir o arquivo do registro da memória + + QGBA::MemoryAccessLogView @@ -3451,18 +3460,13 @@ Tamanho do download: %3 Parar - - Failed to open memory log file - Falhou em abrir o arquivo do registro da memória - - - - + + Select access log file Selecionar o arquivo de registro do acesso - + Memory access logs (*.mal) Registros de acesso a memória (*.mal) @@ -6224,7 +6228,7 @@ Se ele está definido como OpenGL e você ainda ver isto sua placa gráfica ou d Sensores do Game Pak... - + Clear Limpar @@ -6285,7 +6289,7 @@ Se ele está definido como OpenGL e você ainda ver isto sua placa gráfica ou d Carregar save temporário do jogo... - + Convert e-Reader card image to raw... Converter a imagem do cartão do e-Reader pro natural... @@ -6716,77 +6720,77 @@ Se ele está definido como OpenGL e você ainda ver isto sua placa gráfica ou d Registrar os acessos a &memória... - + Record debug video log... Gravar registro do vídeo de debug... - + Stop debug video log Parar o registro do vídeo de debug - + Exit fullscreen Sair da tela cheia - + GameShark Button (held) Botão do GameShark (pressionado) - + Autofire Auto-disparar - + Autofire A Auto-disparar A - + Autofire B Auto-disparar B - + Autofire L Auto-disparar L - + Autofire R Auto-disparar R - + Autofire Start Auto-disparar Start - + Autofire Select Auto-disparar Select - + Autofire Up Auto-disparar Pra Cima - + Autofire Right Auto-disparar Direita - + Autofire Down Auto-disparar Pra Baixo - + Autofire Left Auto-disparar Esquerda diff --git a/src/platform/qt/ts/mgba-pt_PT.ts b/src/platform/qt/ts/mgba-pt_PT.ts index 5f4a2e76f..7953a6d35 100644 --- a/src/platform/qt/ts/mgba-pt_PT.ts +++ b/src/platform/qt/ts/mgba-pt_PT.ts @@ -387,48 +387,48 @@ Tamanho da descarga: %3 QGBA::CoreController - + Reset r%1-%2 %3 Resetar r%1-%2 %3 - - + + Rewinding not currently enabled O rebobinamento não está ativado atualmente - + Reset the game? Resetar o jogo? - + Most games will require a reset to load the new save. Do you want to reset now? A maioria dos jogos requerirão um reset para carregar o novo save. Quer resetar agora? - + Failed to open save file: %1 Falha ao abrir o ficheiro dde gravação: %1 - + Failed to open game file: %1 Falha ao abrir o ficheiro do jogo: %1 - + Can't yank pack in unexpected platform! Não pode arrancar o pacote numa plataforma inesperada! - + Failed to open snapshot file for reading: %1 Falha ao abrir o ficheiro do snapshot para leitura: %1 - + Failed to open snapshot file for writing: %1 Falha ao abrir o ficheiro do snapshot para gravação: %1 @@ -3403,6 +3403,15 @@ Tamanho da descarga: %3 Gráficos Portáteis da Rede (*.png) + + QGBA::MemoryAccessLogController + + + + Failed to open memory log file + + + QGBA::MemoryAccessLogView @@ -3451,18 +3460,13 @@ Tamanho da descarga: %3 Parar - - Failed to open memory log file - - - - - + + Select access log file - + Memory access logs (*.mal) @@ -6238,7 +6242,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Escanear dotcodes do e-Reader... - + Convert e-Reader card image to raw... Converter imagem do cartão do e-Reader para natural... @@ -6709,82 +6713,82 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may - + Record debug video log... Gravar registo do vídeo de debug... - + Stop debug video log Parar o registo do vídeo de debug - + Exit fullscreen Sair do ecrã inteiro - + GameShark Button (held) Botão do GameShark (segurado) - + Autofire Auto-disparar - + Autofire A Auto-disparar A - + Autofire B Auto-disparar B - + Autofire L Auto-disparar L - + Autofire R Auto-disparar R - + Autofire Start Auto-disparar Start - + Autofire Select Auto-disparar Select - + Autofire Up Auto-disparar Para Cima - + Autofire Right Auto-disparar Direita - + Autofire Down Auto-disparar Para Baixo - + Autofire Left Auto-disparar Esquerda - + Clear Limpar diff --git a/src/platform/qt/ts/mgba-ru.ts b/src/platform/qt/ts/mgba-ru.ts index 35b3f0ecb..40cd31946 100644 --- a/src/platform/qt/ts/mgba-ru.ts +++ b/src/platform/qt/ts/mgba-ru.ts @@ -387,48 +387,48 @@ Download size: %3 QGBA::CoreController - + Reset r%1-%2 %3 Сброс r%1-%2 %3 - - + + Rewinding not currently enabled Обратная перемотка выключена - + Reset the game? Перезагрузить игру? - + Most games will require a reset to load the new save. Do you want to reset now? Большинству игр нужна перезагрузка, чтобы загрузить новое сохранение. Перезагрузить сейчас? - + Failed to open save file: %1 Не удалось открыть файл сохранения: %1 - + Failed to open game file: %1 Не удалось открыть файл игры: %1 - + Can't yank pack in unexpected platform! Невозможно пнуть картридж на неожиданной платформе! - + Failed to open snapshot file for reading: %1 Не удалось открыть файл изображения для считывания: %1 - + Failed to open snapshot file for writing: %1 Не удалось открыть файл изображения для записи: %1 @@ -3403,6 +3403,15 @@ Download size: %3 Portable Network Graphics (*.png) + + QGBA::MemoryAccessLogController + + + + Failed to open memory log file + + + QGBA::MemoryAccessLogView @@ -3451,18 +3460,13 @@ Download size: %3 - - Failed to open memory log file - - - - - + + Select access log file - + Memory access logs (*.mal) @@ -6240,7 +6244,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Сканировать dot-коды e-Reader... - + Convert e-Reader card image to raw... Конвертировать карту e-Reader в raw... @@ -6711,82 +6715,82 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may - + Record debug video log... Запись отладочного видеожурнала... - + Stop debug video log Закончить запись отладочного видеожурнала - + Exit fullscreen Выйти из полноэкранного режима - + GameShark Button (held) Кнопка GameShark (удерживается) - + Autofire Автострельба - + Autofire A A (автострельба) - + Autofire B B (автострельба) - + Autofire L L (автострельба) - + Autofire R R (автострельба) - + Autofire Start Start (автострельба) - + Autofire Select Select (автострельба) - + Autofire Up Вверх (автострельба) - + Autofire Right Вправо (автострельба) - + Autofire Down Вниз (автострельба) - + Autofire Left Влево (автострельба) - + Clear Очистить diff --git a/src/platform/qt/ts/mgba-sv.ts b/src/platform/qt/ts/mgba-sv.ts index bd6bfb078..49fdcb432 100644 --- a/src/platform/qt/ts/mgba-sv.ts +++ b/src/platform/qt/ts/mgba-sv.ts @@ -387,48 +387,48 @@ Hämtningsstorlek: %3 QGBA::CoreController - + Reset r%1-%2 %3 Starta om r%1-%2 %3 - - + + Rewinding not currently enabled - + Reset the game? Starta om spelet? - + Most games will require a reset to load the new save. Do you want to reset now? De flesta spel kommer att kräva en omstart för att läsa in ny sparning. Vill du starta om nu? - + Failed to open save file: %1 Misslyckades med att öppna sparad fil: %1 - + Failed to open game file: %1 Misslyckades med att öppna spelfil: %1 - + Can't yank pack in unexpected platform! - + Failed to open snapshot file for reading: %1 Misslyckades med att öppna ögonblicksfil för läsning: %1 - + Failed to open snapshot file for writing: %1 Misslyckades med att öppna ögonblicksfil för skrivning: %1 @@ -3403,6 +3403,15 @@ Hämtningsstorlek: %3 Portable Network Graphics (*.png) + + QGBA::MemoryAccessLogController + + + + Failed to open memory log file + Misslyckades med att öppna minnesloggfil + + QGBA::MemoryAccessLogView @@ -3451,18 +3460,13 @@ Hämtningsstorlek: %3 Stoppa - - Failed to open memory log file - Misslyckades med att öppna minnesloggfil - - - - + + Select access log file Välj åtkomstloggfil - + Memory access logs (*.mal) Minnesåtkomstloggar (*.mal) @@ -6238,7 +6242,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Skanna e-Reader-punktkoder... - + Convert e-Reader card image to raw... Konvertera e-Reader-kortavbilder till raw... @@ -6709,82 +6713,82 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may Logga minneså&tkomster... - + Record debug video log... Spela in felsökningsvideologg... - + Stop debug video log Stoppa felsökningsvideologg - + Exit fullscreen Avsluta helskärm - + GameShark Button (held) GameShark-knapp (håll) - + Autofire Autofire - + Autofire A Autofire A - + Autofire B Autofire B - + Autofire L Autofire L - + Autofire R Autofire R - + Autofire Start Autofire Start - + Autofire Select Autofire Select - + Autofire Up Autofire upp - + Autofire Right Autofire höger - + Autofire Down Autofire ner - + Autofire Left Autofire vänster - + Clear Töm diff --git a/src/platform/qt/ts/mgba-template.ts b/src/platform/qt/ts/mgba-template.ts index 0155d9c06..77294e94d 100644 --- a/src/platform/qt/ts/mgba-template.ts +++ b/src/platform/qt/ts/mgba-template.ts @@ -381,48 +381,48 @@ Download size: %3 QGBA::CoreController - + Reset r%1-%2 %3 - - + + Rewinding not currently enabled - + Reset the game? - + Most games will require a reset to load the new save. Do you want to reset now? - + Failed to open save file: %1 - + Failed to open game file: %1 - + Can't yank pack in unexpected platform! - + Failed to open snapshot file for reading: %1 - + Failed to open snapshot file for writing: %1 @@ -3397,6 +3397,15 @@ Download size: %3 + + QGBA::MemoryAccessLogController + + + + Failed to open memory log file + + + QGBA::MemoryAccessLogView @@ -3445,18 +3454,13 @@ Download size: %3 - - Failed to open memory log file - - - - - + + Select access log file - + Memory access logs (*.mal) @@ -6228,7 +6232,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may - + Convert e-Reader card image to raw... @@ -6699,82 +6703,82 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may - + Record debug video log... - + Stop debug video log - + Exit fullscreen - + GameShark Button (held) - + Autofire - + Autofire A - + Autofire B - + Autofire L - + Autofire R - + Autofire Start - + Autofire Select - + Autofire Up - + Autofire Right - + Autofire Down - + Autofire Left - + Clear diff --git a/src/platform/qt/ts/mgba-tr.ts b/src/platform/qt/ts/mgba-tr.ts index aaafaf988..6db0c47a6 100644 --- a/src/platform/qt/ts/mgba-tr.ts +++ b/src/platform/qt/ts/mgba-tr.ts @@ -387,48 +387,48 @@ Yeni sürüm: %2 QGBA::CoreController - + Reset r%1-%2 %3 - - + + Rewinding not currently enabled - + Reset the game? Oyun sıfırlansım mı? - + Most games will require a reset to load the new save. Do you want to reset now? - + Failed to open save file: %1 Kayıt dosyası açılamadı: %1 - + Failed to open game file: %1 Oyun dosyası açılamadı: %1 - + Can't yank pack in unexpected platform! Beklenmedik bir platformda kartı çıkaramazsın! - + Failed to open snapshot file for reading: %1 Anlık görüntü dosyası okuma için açılamadı: %1 - + Failed to open snapshot file for writing: %1 Anlık görüntü dosyası yazma için açılamadı: %1 @@ -3403,6 +3403,15 @@ Yeni sürüm: %2 + + QGBA::MemoryAccessLogController + + + + Failed to open memory log file + + + QGBA::MemoryAccessLogView @@ -3451,18 +3460,13 @@ Yeni sürüm: %2 Durdur - - Failed to open memory log file - - - - - + + Select access log file - + Memory access logs (*.mal) @@ -6220,7 +6224,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may - + Convert e-Reader card image to raw... e-Okuyucu kart resimlerini rawa dönüştür... @@ -6707,82 +6711,82 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may &I/O kayıtlarını görüntüle - + Record debug video log... Hata ayıklama video günlüğünü kaydet... - + Stop debug video log Hata ayıklama video günlüğünü durdur - + Exit fullscreen Tam ekrandan çık - + GameShark Button (held) GameShark Butonu (basılı tutun) - + Autofire Otomatik basma - + Autofire A Otomatik basma A - + Autofire B Otomatik basma B - + Autofire L Otomatik basma L - + Autofire R Otomatik basma R - + Autofire Start Otomatik basma Start - + Autofire Select Otomatik basma Select - + Autofire Up Otomatik basma Up - + Autofire Right Otomatik basma Right - + Autofire Down Otomatik basma Down - + Autofire Left Otomatik basma Sol - + Clear Temizle diff --git a/src/platform/qt/ts/mgba-zh_CN.ts b/src/platform/qt/ts/mgba-zh_CN.ts index 801bacb8f..0518b256b 100644 --- a/src/platform/qt/ts/mgba-zh_CN.ts +++ b/src/platform/qt/ts/mgba-zh_CN.ts @@ -387,48 +387,48 @@ Download size: %3 QGBA::CoreController - + Reset r%1-%2 %3 重置 r%1-%2 %3 - - + + Rewinding not currently enabled 当前未开启倒带 - + Reset the game? 要重置游戏吗? - + Most games will require a reset to load the new save. Do you want to reset now? 大多数游戏需要重置才能加载新的存档。您要立即重启吗? - + Failed to open save file: %1 打开存档失败: %1 - + Failed to open game file: %1 打开游戏文件失败: %1 - + Can't yank pack in unexpected platform! 无法在意外平台上抽出卡带! - + Failed to open snapshot file for reading: %1 读取快照文件失败: %1 - + Failed to open snapshot file for writing: %1 写入快照文件失败: %1 @@ -3403,6 +3403,15 @@ Download size: %3 便携式网络图形 (*.png) + + QGBA::MemoryAccessLogController + + + + Failed to open memory log file + 打开内存日志文件失败 + + QGBA::MemoryAccessLogView @@ -3451,18 +3460,13 @@ Download size: %3 停止 - - Failed to open memory log file - 打开内存日志文件失败 - - - - + + Select access log file 选择访问日志文件 - + Memory access logs (*.mal) 内存访问日志(*.mal) @@ -6236,7 +6240,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may 扫描 e-Reader 点码... - + Convert e-Reader card image to raw... 将 e-Reader 卡片图像转换为原始数据... @@ -6707,82 +6711,82 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may 记录内存访问(&a)... - + Record debug video log... 记录调试视频日志... - + Stop debug video log 停止记录调试视频日志 - + Exit fullscreen 退出全屏 - + GameShark Button (held) GameShark 键 (长按) - + Autofire 连发 - + Autofire A 连发 A - + Autofire B 连发 B - + Autofire L 连发 L - + Autofire R 连发 R - + Autofire Start 连发 Start - + Autofire Select 连发 Select - + Autofire Up 连发 上 - + Autofire Right 连发 右 - + Autofire Down 连发 下 - + Autofire Left 连发 左 - + Clear 清除 diff --git a/src/platform/qt/ts/mgba-zh_Hant.ts b/src/platform/qt/ts/mgba-zh_Hant.ts index 5b5c96e52..e764abb92 100644 --- a/src/platform/qt/ts/mgba-zh_Hant.ts +++ b/src/platform/qt/ts/mgba-zh_Hant.ts @@ -387,48 +387,48 @@ Download size: %3 QGBA::CoreController - + Reset r%1-%2 %3 重置 r%1-%2 %3 - - + + Rewinding not currently enabled 目前未開啟倒帶 - + Reset the game? 要重置遊戲嗎? - + Most games will require a reset to load the new save. Do you want to reset now? 大多數遊戲需要重置才能載入新的檔案。您要立即重啟嗎? - + Failed to open save file: %1 存檔開啟失敗: %1 - + Failed to open game file: %1 遊戲開啟失敗: %1 - + Can't yank pack in unexpected platform! 無法在預料外的平台拔除卡帶! - + Failed to open snapshot file for reading: %1 讀取快照失敗: %1 - + Failed to open snapshot file for writing: %1 寫入快照失敗: %1 @@ -3403,6 +3403,15 @@ Download size: %3 複製 + + QGBA::MemoryAccessLogController + + + + Failed to open memory log file + 打開記憶體日誌檔案失敗 + + QGBA::MemoryAccessLogView @@ -3451,18 +3460,13 @@ Download size: %3 停止 - - Failed to open memory log file - 打開記憶體日誌檔案失敗 - - - - + + Select access log file 選擇訪問日誌文件 - + Memory access logs (*.mal) 記憶體存取日誌(*.mal) @@ -4450,7 +4454,7 @@ Download size: %3 Save - + 儲存 @@ -6246,7 +6250,7 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may 掃描 e-Reader 點碼... - + Convert e-Reader card image to raw... 轉換 e-Reader 卡片圖檔為原始資料... @@ -6707,82 +6711,82 @@ If it is set to OpenGL and you still see this, your graphics card or drivers may - + Record debug video log... 錄製除錯影片記錄檔。 - + Stop debug video log 停止除錯影片記錄檔 - + Exit fullscreen 離開全螢幕 - + GameShark Button (held) Gameshark 按鈕 (長按) - + Autofire 自動連射 - + Autofire A 自動連射 A - + Autofire B 自動連射 B - + Autofire L 自動連射 L - + Autofire R 自動連射 R - + Autofire Start 自動連射 Start - + Autofire Select 自動連射 Select - + Autofire Up 自動連射 上 - + Autofire Right 自動連射 右 - + Autofire Down 自動連射 下 - + Autofire Left 自動連射 左 - + Clear 清除 From 511437312ccf917dcc816618e2a0595aecc32e59 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 11 Jan 2025 19:47:21 -0800 Subject: [PATCH 15/32] Qt: Revamp memory view layout --- src/platform/qt/MemoryView.cpp | 20 +- src/platform/qt/MemoryView.ui | 471 +++++++++++++++------------------ 2 files changed, 221 insertions(+), 270 deletions(-) diff --git a/src/platform/qt/MemoryView.cpp b/src/platform/qt/MemoryView.cpp index 4383867e0..cdb754bfe 100644 --- a/src/platform/qt/MemoryView.cpp +++ b/src/platform/qt/MemoryView.cpp @@ -133,20 +133,10 @@ MemoryView::MemoryView(std::shared_ptr controller, QWidget* pare } } - connect(m_ui.width8, &QAbstractButton::clicked, [this]() { - m_ui.hexfield->setAlignment(1); - m_sintValidator.setWidth(1); - m_uintValidator.setWidth(1); - }); - connect(m_ui.width16, &QAbstractButton::clicked, [this]() { - m_ui.hexfield->setAlignment(2); - m_sintValidator.setWidth(2); - m_uintValidator.setWidth(2); - }); - connect(m_ui.width32, &QAbstractButton::clicked, [this]() { - m_ui.hexfield->setAlignment(4); - m_sintValidator.setWidth(4); - m_uintValidator.setWidth(4); + connect(m_ui.width, &QComboBox::currentIndexChanged, [this](int index) { + m_ui.hexfield->setAlignment(1 << index); + m_sintValidator.setWidth(1 << index); + m_uintValidator.setWidth(1 << index); }); connect(m_ui.setAddress, static_cast(&QSpinBox::valueChanged), this, static_cast(&MemoryView::jumpToAddress)); @@ -258,7 +248,7 @@ void MemoryView::updateStatus() { mCore* core = m_controller->thread()->core; QByteArray selection(m_ui.hexfield->serialize()); QString text(m_ui.hexfield->decodeText(selection)); - m_ui.stringVal->setText(text); + m_ui.stringVal->setPlainText(text); if (m_selection.first & (align - 1) || m_selection.second - m_selection.first != align) { m_ui.sintVal->clear(); diff --git a/src/platform/qt/MemoryView.ui b/src/platform/qt/MemoryView.ui index 45879db88..06ab570d1 100644 --- a/src/platform/qt/MemoryView.ui +++ b/src/platform/qt/MemoryView.ui @@ -6,167 +6,14 @@ 0 0 - 874 - 900 + 708 + 549 Memory - - - - - - - - - - Qt::Horizontal - - - - 0 - 0 - - - - - - - - Inspect Address: - - - - - - - -1 - - - 0 - - - 16 - - - - - - - : - - - - - - - true - - - 0x - - - 268435455 - - - 16 - - - 16 - - - - - - - - - - - Set Alignment: - - - - - - - Qt::Horizontal - - - - 0 - 0 - - - - - - - - &1 Byte - - - true - - - - - - - Qt::Horizontal - - - - 0 - 0 - - - - - - - - &2 Bytes - - - - - - - Qt::Horizontal - - - - 0 - 0 - - - - - - - - &4 Bytes - - - - - - - Qt::Horizontal - - - - 0 - 0 - - - - - - + @@ -175,72 +22,255 @@ 0 + + + 200 + 0 + + - - - + + + + + + - + - Unsigned Integer: + Address: - - - 10 + + + Qt::Horizontal - + + + 0 + 0 + + + + + + + + -1 + + + 0 + + + 16 + + + + + + + : + + + + + + + + 100 + 0 + + + true + + 0x + + + 268435455 + + + 16 + + + 16 + - + - + - Signed Integer: + Alignment: - - - 11 - - - true + + + + 0 + 0 + + + + 1 Byte + + + + + 2 Bytes + + + + + 4 Bytes + + - - - - + + + + + 0 + 0 + + + + + + + + + + Signed: + + + + + + + 11 + + + true + + + + + + + + + + Unsigned: + + + + + + + 10 + + + true + + + + + + + + + + String: + + + + + + + + 0 + 0 + + + + Load TBL + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + + + - String: + Copy Selection - - - - true + + + + Save Selection - - + + - Load TBL + Paste + + + + + + + Save Range + + + + + + + + 0 + 0 + + + + Load @@ -248,58 +278,6 @@ - - - - - - Copy Selection - - - - - - - Paste - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Save Selection - - - - - - - Save Range - - - - - - - Load - - - - - @@ -310,23 +288,6 @@ 1 - - regions - segments - setAddress - width8 - width16 - width32 - sintVal - uintVal - stringVal - loadTBL - copy - paste - save - saveRange - load - From 75dc29085307fbf03ceddca5092988c8e0c5f900 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 12 Jan 2025 04:30:12 -0800 Subject: [PATCH 16/32] Debugger: Expose mDebuggerAccessLoggerGetRegion --- .../mgba/internal/debugger/access-logger.h | 2 + src/debugger/access-logger.c | 174 +++++++++--------- 2 files changed, 89 insertions(+), 87 deletions(-) diff --git a/include/mgba/internal/debugger/access-logger.h b/include/mgba/internal/debugger/access-logger.h index 26186ac20..b839bd5b1 100644 --- a/include/mgba/internal/debugger/access-logger.h +++ b/include/mgba/internal/debugger/access-logger.h @@ -46,6 +46,8 @@ int mDebuggerAccessLoggerWatchMemoryBlockName(struct mDebuggerAccessLogger*, con bool mDebuggerAccessLoggerCreateShadowFile(struct mDebuggerAccessLogger*, int region, struct VFile*, uint8_t fill); +struct mDebuggerAccessLogRegion* mDebuggerAccessLoggerGetRegion(struct mDebuggerAccessLogger*, uint32_t address, int segment, size_t* offset); + CXX_GUARD_END #endif diff --git a/src/debugger/access-logger.c b/src/debugger/access-logger.c index 41c780c4e..e38eead03 100644 --- a/src/debugger/access-logger.c +++ b/src/debugger/access-logger.c @@ -62,74 +62,61 @@ static void _mDebuggerAccessLoggerEntered(struct mDebuggerModule* debugger, enum break; } - size_t i; - for (i = 0; i < mDebuggerAccessLogRegionListSize(&logger->regions); ++i) { - struct mDebuggerAccessLogRegion* region = mDebuggerAccessLogRegionListGetPointer(&logger->regions, i); - if (info->address < region->start || info->address >= region->end) { - continue; - } - size_t offset = info->address - region->start; - if (info->segment > 0) { - uint32_t segmentSize = region->end - region->segmentStart; - offset %= segmentSize; - offset += segmentSize * info->segment; - } + size_t offset; + struct mDebuggerAccessLogRegion* region = mDebuggerAccessLoggerGetRegion(logger, info->address, info->segment, &offset); + if (!region) { + return; + } + offset &= -info->width; - if (offset >= region->size) { - continue; - } - - offset &= -info->width; - - int j; - switch (reason) { - case DEBUGGER_ENTER_WATCHPOINT: - for (j = 0; j < info->width; ++j) { - if (info->type.wp.accessType & WATCHPOINT_WRITE) { - region->block[offset + j] = mDebuggerAccessLogFlagsFillWrite(region->block[offset + j]); - } - if (info->type.wp.accessType & WATCHPOINT_READ) { - region->block[offset + j] = mDebuggerAccessLogFlagsFillRead(region->block[offset + j]); - } + int i; + switch (reason) { + case DEBUGGER_ENTER_WATCHPOINT: + for (i = 0; i < info->width; ++i) { + if (info->type.wp.accessType & WATCHPOINT_WRITE) { + region->block[offset + i] = mDebuggerAccessLogFlagsFillWrite(region->block[offset + i]); } - switch (info->width) { - case 1: - region->block[offset] = mDebuggerAccessLogFlagsFillAccess8(region->block[offset]); - break; - case 2: - region->block[offset] = mDebuggerAccessLogFlagsFillAccess16(region->block[offset]); - region->block[offset + 1] = mDebuggerAccessLogFlagsFillAccess16(region->block[offset + 1]); - break; - case 4: - region->block[offset] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset]); - region->block[offset + 1] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset + 1]); - region->block[offset + 2] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset + 2]); - region->block[offset + 3] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset + 3]); - break; - case 8: - region->block[offset] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset]); - region->block[offset + 1] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 1]); - region->block[offset + 2] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 2]); - region->block[offset + 3] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 3]); - region->block[offset + 4] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 4]); - region->block[offset + 5] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 5]); - region->block[offset + 6] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 6]); - region->block[offset + 7] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 7]); - break; + if (info->type.wp.accessType & WATCHPOINT_READ) { + region->block[offset + i] = mDebuggerAccessLogFlagsFillRead(region->block[offset + i]); } + } + switch (info->width) { + case 1: + region->block[offset] = mDebuggerAccessLogFlagsFillAccess8(region->block[offset]); break; - case DEBUGGER_ENTER_ILLEGAL_OP: - region->block[offset] = mDebuggerAccessLogFlagsFillExecute(region->block[offset]); - if (region->blockEx) { - uint16_t ex; - LOAD_16LE(ex, 0, ®ion->blockEx[offset]); - ex = mDebuggerAccessLogFlagsExFillErrorIllegalOpcode(ex); - STORE_16LE(ex, 0, ®ion->blockEx[offset]); - } + case 2: + region->block[offset] = mDebuggerAccessLogFlagsFillAccess16(region->block[offset]); + region->block[offset + 1] = mDebuggerAccessLogFlagsFillAccess16(region->block[offset + 1]); break; - default: + case 4: + region->block[offset] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset]); + region->block[offset + 1] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset + 1]); + region->block[offset + 2] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset + 2]); + region->block[offset + 3] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset + 3]); + break; + case 8: + region->block[offset] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset]); + region->block[offset + 1] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 1]); + region->block[offset + 2] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 2]); + region->block[offset + 3] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 3]); + region->block[offset + 4] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 4]); + region->block[offset + 5] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 5]); + region->block[offset + 6] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 6]); + region->block[offset + 7] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 7]); break; } + break; + case DEBUGGER_ENTER_ILLEGAL_OP: + region->block[offset] = mDebuggerAccessLogFlagsFillExecute(region->block[offset]); + if (region->blockEx) { + uint16_t ex; + LOAD_16LE(ex, 0, ®ion->blockEx[offset]); + ex = mDebuggerAccessLogFlagsExFillErrorIllegalOpcode(ex); + STORE_16LE(ex, 0, ®ion->blockEx[offset]); + } + break; + default: + break; } } @@ -139,34 +126,22 @@ static void _mDebuggerAccessLoggerCallback(struct mDebuggerModule* debugger) { struct mDebuggerInstructionInfo info; logger->d.p->platform->nextInstructionInfo(logger->d.p->platform, &info); + size_t offset; + struct mDebuggerAccessLogRegion* region = mDebuggerAccessLoggerGetRegion(logger, info.address, info.segment, &offset); + if (!region) { + return; + } + size_t i; - for (i = 0; i < mDebuggerAccessLogRegionListSize(&logger->regions); ++i) { - struct mDebuggerAccessLogRegion* region = mDebuggerAccessLogRegionListGetPointer(&logger->regions, i); - if (info.address < region->start || info.address >= region->end) { - continue; - } - size_t offset = info.address - region->start; - if (info.segment > 0) { - uint32_t segmentSize = region->end - region->segmentStart; - offset %= segmentSize; - offset += segmentSize * info.segment; - } + for (i = 0; i < info.width; ++i) { + uint16_t ex = 0; + region->block[offset + i] = mDebuggerAccessLogFlagsFillExecute(region->block[offset + i]); + region->block[offset + i] |= info.flags[i]; - if (offset >= region->size) { - continue; - } - - size_t j; - for (j = 0; j < info.width; ++j) { - uint16_t ex = 0; - region->block[offset + j] = mDebuggerAccessLogFlagsFillExecute(region->block[offset + j]); - region->block[offset + j] |= info.flags[j]; - - if (region->blockEx) { - LOAD_16LE(ex, 0, ®ion->blockEx[offset + j]); - ex |= info.flagsEx[j]; - STORE_16LE(ex, 0, ®ion->blockEx[offset + j]); - } + if (region->blockEx) { + LOAD_16LE(ex, 0, ®ion->blockEx[offset + i]); + ex |= info.flagsEx[i]; + STORE_16LE(ex, 0, ®ion->blockEx[offset + i]); } } } @@ -518,3 +493,28 @@ bool mDebuggerAccessLoggerCreateShadowFile(struct mDebuggerAccessLogger* logger, } return true; } + +struct mDebuggerAccessLogRegion* mDebuggerAccessLoggerGetRegion(struct mDebuggerAccessLogger* logger, uint32_t address, int segment, size_t* offsetOut) { + size_t i; + for (i = 0; i < mDebuggerAccessLogRegionListSize(&logger->regions); ++i) { + struct mDebuggerAccessLogRegion* region = mDebuggerAccessLogRegionListGetPointer(&logger->regions, i); + if (address < region->start || address >= region->end) { + continue; + } + size_t offset = address - region->start; + if (segment > 0) { + uint32_t segmentSize = region->end - region->segmentStart; + offset %= segmentSize; + offset += segmentSize * segment; + } + + if (offset >= region->size) { + continue; + } + if (offsetOut) { + *offsetOut = offset; + } + return region; + } + return NULL; +} From 159b0dc445e97712ac2cd2cbdb4178bd4ce09407 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 12 Jan 2025 06:00:40 -0800 Subject: [PATCH 17/32] Qt: Add access log view to memory view --- src/platform/qt/CMakeLists.txt | 1 + src/platform/qt/MemoryAccessLogController.cpp | 41 +++ src/platform/qt/MemoryAccessLogController.h | 15 + src/platform/qt/MemoryAccessLogModel.cpp | 283 ++++++++++++++++++ src/platform/qt/MemoryAccessLogModel.h | 55 ++++ src/platform/qt/MemoryView.cpp | 24 ++ src/platform/qt/MemoryView.h | 5 + src/platform/qt/MemoryView.ui | 60 +++- 8 files changed, 473 insertions(+), 11 deletions(-) create mode 100644 src/platform/qt/MemoryAccessLogModel.cpp create mode 100644 src/platform/qt/MemoryAccessLogModel.h diff --git a/src/platform/qt/CMakeLists.txt b/src/platform/qt/CMakeLists.txt index 910ab9b57..9858fddb0 100644 --- a/src/platform/qt/CMakeLists.txt +++ b/src/platform/qt/CMakeLists.txt @@ -262,6 +262,7 @@ if(ENABLE_DEBUGGERS) DebuggerConsole.cpp DebuggerConsoleController.cpp MemoryAccessLogController.cpp + MemoryAccessLogModel.cpp MemoryAccessLogView.cpp) endif() diff --git a/src/platform/qt/MemoryAccessLogController.cpp b/src/platform/qt/MemoryAccessLogController.cpp index 95200e53e..9691dcadf 100644 --- a/src/platform/qt/MemoryAccessLogController.cpp +++ b/src/platform/qt/MemoryAccessLogController.cpp @@ -10,8 +10,14 @@ #include "utils.h" #include "VFileDevice.h" +#include + using namespace QGBA; +int MemoryAccessLogController::Flags::count() const { + return popcount32(flags) + popcount32(flagsEx); +} + MemoryAccessLogController::MemoryAccessLogController(CoreController* controller, QObject* parent) : QObject(parent) , m_controller(controller) @@ -39,6 +45,17 @@ bool MemoryAccessLogController::canExport() const { return m_regionMapping.contains("cart0"); } +MemoryAccessLogController::Flags MemoryAccessLogController::flagsForAddress(uint32_t addresss, int segment) { + uint32_t offset = cacheRegion(addresss, segment); + if (!m_cachedRegion) { + return { 0, 0 }; + } + return { + m_cachedRegion->blockEx ? m_cachedRegion->blockEx[offset] : mDebuggerAccessLogFlagsEx{}, + m_cachedRegion->block ? m_cachedRegion->block[offset] : mDebuggerAccessLogFlags{}, + }; +} + void MemoryAccessLogController::updateRegion(const QString& internalName, bool checked) { if (checked) { m_watchedRegions += internalName; @@ -116,3 +133,27 @@ void MemoryAccessLogController::exportFile(const QString& filename) { mDebuggerAccessLoggerCreateShadowFile(&m_logger, m_regionMapping[QString("cart0")], vf, 0); vf->close(vf); } + +uint32_t MemoryAccessLogController::cacheRegion(uint32_t address, int segment) { + if (m_cachedRegion && (address < m_cachedRegion->start || address >= m_cachedRegion->end)) { + m_cachedRegion = nullptr; + } + if (!m_cachedRegion) { + m_cachedRegion = mDebuggerAccessLoggerGetRegion(&m_logger, address, segment, nullptr); + } + if (!m_cachedRegion) { + return 0; + } + + size_t offset = address - m_cachedRegion->start; + if (segment > 0) { + uint32_t segmentSize = m_cachedRegion->end - m_cachedRegion->segmentStart; + offset %= segmentSize; + offset += segmentSize * segment; + } + if (offset >= m_cachedRegion->size) { + m_cachedRegion = nullptr; + return cacheRegion(address, segment); + } + return offset; +} diff --git a/src/platform/qt/MemoryAccessLogController.h b/src/platform/qt/MemoryAccessLogController.h index 42ef655c3..79553b333 100644 --- a/src/platform/qt/MemoryAccessLogController.h +++ b/src/platform/qt/MemoryAccessLogController.h @@ -12,6 +12,7 @@ #include "CoreController.h" +#include #include namespace QGBA { @@ -25,6 +26,16 @@ public: QString internalName; }; + struct Flags { + mDebuggerAccessLogFlagsEx flagsEx; + mDebuggerAccessLogFlags flags; + + int count() const; + bool operator==(const Flags& other) const { return flags == other.flags && flagsEx == other.flagsEx; } + bool operator!=(const Flags& other) const { return flags != other.flags || flagsEx != other.flagsEx; } + operator bool() const { return flags || flagsEx; } + }; + MemoryAccessLogController(CoreController* controller, QObject* parent = nullptr); ~MemoryAccessLogController(); @@ -34,6 +45,8 @@ public: bool canExport() const; mPlatform platform() const { return m_controller->platform(); } + Flags flagsForAddress(uint32_t address, int segment = -1); + QString file() const { return m_path; } bool active() const { return m_active; } @@ -59,8 +72,10 @@ private: QVector m_regions; struct mDebuggerAccessLogger m_logger{}; bool m_active = false; + mDebuggerAccessLogRegion* m_cachedRegion = nullptr; mDebuggerAccessLogRegionFlags activeFlags() const; + uint32_t cacheRegion(uint32_t address, int segment); }; } diff --git a/src/platform/qt/MemoryAccessLogModel.cpp b/src/platform/qt/MemoryAccessLogModel.cpp new file mode 100644 index 000000000..23eb34f4c --- /dev/null +++ b/src/platform/qt/MemoryAccessLogModel.cpp @@ -0,0 +1,283 @@ +/* Copyright (c) 2013-2025 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "MemoryAccessLogModel.h" + +#include + +using namespace QGBA; + +MemoryAccessLogModel::MemoryAccessLogModel(std::weak_ptr controller, mPlatform platform) + : m_controller(controller) + , m_platform(platform) +{ +} + +QVariant MemoryAccessLogModel::data(const QModelIndex& index, int role) const { + if (role != Qt::DisplayRole) { + return {}; + } + if (index.column() != 0) { + return {}; + } + int blockIndex = -1; + int flagIndex = -1; + QModelIndex parent = index.parent(); + if (!parent.isValid()) { + blockIndex = index.row(); + } else { + blockIndex = parent.row(); + flagIndex = index.row(); + } + + if (blockIndex < 0 || blockIndex >= m_cachedBlocks.count()) { + return {}; + } + + const Block& block = m_cachedBlocks[blockIndex]; + + if (flagIndex < 0) { + return QString("0x%1 – 0x%2") + .arg(QString("%0").arg(block.region.first, 8, 16, QChar('0')).toUpper()) + .arg(QString("%0").arg(block.region.second, 8, 16, QChar('0')).toUpper()); + } + for (int i = 0; i < 8; ++i) { + if (!(block.flags.flags & (1 << i))) { + continue; + } + if (flagIndex == 0) { + switch (i) { + case 0: + return tr("Data read"); + case 1: + return tr("Data written"); + case 2: + return tr("Code executed"); + case 3: + return tr("Code aborted"); + case 4: + return tr("8-bit access"); + case 5: + return tr("16-bit access"); + case 6: + return tr("32-bit access"); + case 7: + return tr("64-bit access"); + default: + Q_UNREACHABLE(); + } + } + --flagIndex; + } + for (int i = 0; i < 16; ++i) { + if (!(block.flags.flagsEx & (1 << i))) { + continue; + } + if (flagIndex == 0) { + switch (i) { + case 0: + return tr("Accessed by instruction"); + case 1: + return tr("Accessed by DMA"); + case 2: + return tr("Accessed by BIOS"); + case 3: + return tr("Compressed data"); + case 4: + return tr("Accessed by memory copy"); + case 5: + return tr("(Unknown extra bit 5)"); + case 6: + return tr("(Unknown extra bit 6)"); + case 7: + return tr("(Unknown extra bit 7)"); + case 8: + return tr("Invalid instruction"); + case 9: + return tr("Invalid read"); + case 10: + return tr("Invalid write"); + case 11: + return tr("Invalid executable address"); + case 12: + return tr("(Private bit 0)"); + case 13: + return tr("(Private bit 1)"); + case 14: + switch (m_platform) { + case mPLATFORM_GBA: + return tr("ARM code"); + default: + return tr("(Private bit 2)"); + } + case 15: + switch (m_platform) { + case mPLATFORM_GBA: + return tr("Thumb code"); + default: + return tr("(Private bit 2)"); + } + default: + Q_UNREACHABLE(); + } + } + --flagIndex; + } + return tr("(Unknown)"); +} + +QModelIndex MemoryAccessLogModel::index(int row, int column, const QModelIndex& parent) const { + if (column != 0) { + return {}; + } + if (parent.isValid()) { + return createIndex(row, 0, parent.row()); + } + return createIndex(row, 0, std::numeric_limits::max()); +} + +QModelIndex MemoryAccessLogModel::parent(const QModelIndex& index) const { + if (!index.isValid()) { + return {}; + } + quintptr row = index.internalId(); + if (row >= std::numeric_limits::max()) { + return {}; + } + return createIndex(row, 0, std::numeric_limits::max()); +} + +int MemoryAccessLogModel::rowCount(const QModelIndex& parent) const { + int blockIndex = -1; + if (!parent.isValid()) { + return m_cachedBlocks.count(); + } else if (parent.column() != 0) { + return 0; + } else if (parent.parent().isValid()) { + return 0; + } else { + blockIndex = parent.row(); + } + + if (blockIndex < 0 || blockIndex >= m_cachedBlocks.count()) { + return 0; + } + + const Block& block = m_cachedBlocks[blockIndex]; + return block.flags.count(); +} + +void MemoryAccessLogModel::updateSelection(uint32_t start, uint32_t end) { + std::shared_ptr controller = m_controller.lock(); + if (!controller) { + return; + } + QVector newBlocks; + uint32_t lastStart = start; + auto lastFlags = controller->flagsForAddress(m_base + start, m_segment); + + for (uint32_t address = start; address < end; ++address) { + auto flags = controller->flagsForAddress(m_base + address, m_segment); + if (flags == lastFlags) { + continue; + } + if (lastFlags) { + newBlocks.append({ lastFlags, qMakePair(lastStart, address) }); + } + lastFlags = flags; + lastStart = address; + } + if (lastFlags) { + newBlocks.append({ lastFlags, qMakePair(lastStart, end) }); + } + + if (m_cachedBlocks.count() == 0 || newBlocks.count() == 0) { + beginResetModel(); + m_cachedBlocks = newBlocks; + endResetModel(); + return; + } + + QPair changed{ -1, -1 }; + for (int i = 0; i < m_cachedBlocks.count() && i < newBlocks.count(); ++i) { + const Block& oldBlock = m_cachedBlocks.at(i); + const Block& newBlock = newBlocks.at(i); + + if (oldBlock != newBlock) { + changed = qMakePair(i, m_cachedBlocks.count()); + break; + } + } + + if (m_cachedBlocks.count() > newBlocks.count()) { + beginRemoveRows({}, newBlocks.count(), m_cachedBlocks.count()); + m_cachedBlocks.resize(newBlocks.count()); + endRemoveRows(); + changed.second = newBlocks.count(); + } + + if (m_cachedBlocks.count() < newBlocks.count()) { + beginInsertRows({}, m_cachedBlocks.count(), newBlocks.count()); + if (changed.first < 0) { + // Only new rows + m_cachedBlocks = newBlocks; + endInsertRows(); + return; + } + } + + if (changed.first < 0) { + // No changed rows, though some might have been removed + return; + } + + for (int i = 0; i < m_cachedBlocks.count() && i < newBlocks.count(); ++i) { + const Block& oldBlock = m_cachedBlocks.at(i); + const Block& newBlock = newBlocks.at(i); + if (oldBlock.flags != newBlock.flags) { + int oldFlags = oldBlock.flags.count(); + int newFlags = newBlock.flags.count(); + if (oldFlags > newFlags) { + beginRemoveRows(createIndex(i, 0, std::numeric_limits::max()), newFlags, oldFlags); + } else if (oldFlags < newFlags) { + beginInsertRows(createIndex(i, 0, std::numeric_limits::max()), oldFlags, newFlags); + } + m_cachedBlocks[i] = newBlock; + emit dataChanged(createIndex(0, 0, i), createIndex(std::min(oldFlags, newFlags), 0, i)); + if (oldFlags > newFlags) { + endRemoveRows(); + } else if (oldFlags < newFlags) { + endInsertRows(); + } + } + } + emit dataChanged(createIndex(changed.first, 0, std::numeric_limits::max()), + createIndex(changed.second, 0, std::numeric_limits::max())); + + if (m_cachedBlocks.count() < newBlocks.count()) { + m_cachedBlocks = newBlocks; + endInsertRows(); + } +} + +void MemoryAccessLogModel::setSegment(int segment) { + if (m_segment == segment) { + return; + } + beginResetModel(); + m_segment = segment; + m_cachedBlocks.clear(); + endResetModel(); +} + +void MemoryAccessLogModel::setRegion(uint32_t base, uint32_t, bool useSegments) { + if (m_base == base) { + return; + } + beginResetModel(); + m_segment = useSegments ? 0 : -1; + m_cachedBlocks.clear(); + endResetModel(); +} diff --git a/src/platform/qt/MemoryAccessLogModel.h b/src/platform/qt/MemoryAccessLogModel.h new file mode 100644 index 000000000..b18f0dee5 --- /dev/null +++ b/src/platform/qt/MemoryAccessLogModel.h @@ -0,0 +1,55 @@ +/* Copyright (c) 2013-2025 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#pragma once + +#include +#include + +#include "MemoryAccessLogController.h" + +struct mCheatDevice; +struct mCheatSet; + +namespace QGBA { + +class MemoryAccessLogModel : public QAbstractItemModel { +Q_OBJECT + +public: + MemoryAccessLogModel(std::weak_ptr controller, mPlatform platform); + + virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; + + virtual QModelIndex index(int row, int column, const QModelIndex& parent) const override; + virtual QModelIndex parent(const QModelIndex& index) const override; + + virtual int columnCount(const QModelIndex& = QModelIndex()) const override { return 1; } + virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override; + +public slots: + void updateSelection(uint32_t start, uint32_t end); + void setSegment(int segment); + void setRegion(uint32_t base, uint32_t segmentSize, bool useSegments); + +private: + struct Block { + MemoryAccessLogController::Flags flags; + QPair region; + + bool operator==(const Block& other) const { return flags == other.flags && region == other.region; } + bool operator!=(const Block& other) const { return flags != other.flags || region != other.region; } + }; + + int flagCount(int index) const; + + std::weak_ptr m_controller; + mPlatform m_platform; + uint32_t m_base = 0; + int m_segment = -1; + QVector m_cachedBlocks; +}; + +} diff --git a/src/platform/qt/MemoryView.cpp b/src/platform/qt/MemoryView.cpp index cdb754bfe..009d789aa 100644 --- a/src/platform/qt/MemoryView.cpp +++ b/src/platform/qt/MemoryView.cpp @@ -7,6 +7,7 @@ #include "MemoryView.h" #include "CoreController.h" +#include "MemoryAccessLogView.h" #include "MemoryDump.h" #include @@ -107,6 +108,9 @@ QValidator::State IntValidator::validate(QString& input, int&) const { MemoryView::MemoryView(std::shared_ptr controller, QWidget* parent) : QWidget(parent) , m_controller(controller) +#ifdef ENABLE_DEBUGGERS + , m_malModel(controller->memoryAccessLogController(), controller->platform()) +#endif { m_ui.setupUi(this); @@ -189,6 +193,22 @@ MemoryView::MemoryView(std::shared_ptr controller, QWidget* pare } update(); }); + +#ifdef ENABLE_DEBUGGERS + connect(m_ui.hexfield, &MemoryModel::selectionChanged, &m_malModel, &MemoryAccessLogModel::updateSelection); + connect(m_ui.segments, static_cast(&QSpinBox::valueChanged), + &m_malModel, &MemoryAccessLogModel::setSegment); + connect(m_ui.accessLoggerButton, &QAbstractButton::clicked, this, [this]() { + std::weak_ptr controller = m_controller->memoryAccessLogController(); + MemoryAccessLogView* view = new MemoryAccessLogView(controller); + connect(m_controller.get(), &CoreController::stopping, view, &QWidget::close); + view->setAttribute(Qt::WA_DeleteOnClose); + view->show(); + }); + m_ui.accessLog->setModel(&m_malModel); +#else + m_ui.accessLog->hide(); +#endif } void MemoryView::setIndex(int index) { @@ -206,6 +226,10 @@ void MemoryView::setIndex(int index) { m_ui.segmentColon->setVisible(info.maxSegment > 0); m_ui.segments->setMaximum(info.maxSegment); m_ui.hexfield->setRegion(info.start, info.end - info.start, info.shortName); + +#ifdef ENABLE_DEBUGGERS + m_malModel.setRegion(info.start, info.segmentStart - info.start, info.maxSegment > 0); +#endif } void MemoryView::setSegment(int segment) { diff --git a/src/platform/qt/MemoryView.h b/src/platform/qt/MemoryView.h index f68052a06..d6a5c6f93 100644 --- a/src/platform/qt/MemoryView.h +++ b/src/platform/qt/MemoryView.h @@ -8,6 +8,7 @@ #include #include "MemoryModel.h" +#include "MemoryAccessLogModel.h" #include "ui_MemoryView.h" @@ -54,6 +55,10 @@ private: std::shared_ptr m_controller; QPair m_region; QPair m_selection; + +#ifdef ENABLE_DEBUGGERS + MemoryAccessLogModel m_malModel; +#endif }; } diff --git a/src/platform/qt/MemoryView.ui b/src/platform/qt/MemoryView.ui index 06ab570d1..73407fdd1 100644 --- a/src/platform/qt/MemoryView.ui +++ b/src/platform/qt/MemoryView.ui @@ -31,14 +31,14 @@ - + - + - + Address: @@ -105,9 +105,9 @@ - + - + Alignment: @@ -141,7 +141,7 @@ - + 0 @@ -151,9 +151,9 @@ - + - + Signed: @@ -173,7 +173,7 @@ - + Unsigned: @@ -193,7 +193,7 @@ - + String: @@ -232,7 +232,7 @@ - + @@ -276,6 +276,44 @@ + + + + + 0 + 0 + + + + Selected address accesses + + + + + + + 0 + 0 + + + + Qt::ElideNone + + + false + + + + + + + Logging configuration + + + + + + From 762a54a388aca616c799c4a8542a89aae9450c45 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 12 Jan 2025 06:01:10 -0800 Subject: [PATCH 18/32] Core: Threads should not attempt to exit a thread that is already dead --- src/core/thread.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/thread.c b/src/core/thread.c index 988ce0848..92d134120 100644 --- a/src/core/thread.c +++ b/src/core/thread.c @@ -507,6 +507,10 @@ void mCoreThreadClearCrashed(struct mCoreThread* threadContext) { void mCoreThreadEnd(struct mCoreThread* threadContext) { MutexLock(&threadContext->impl->stateMutex); + if (threadContext->impl->state == mTHREAD_SHUTDOWN) { + MutexUnlock(&threadContext->impl->stateMutex); + return; + } _waitOnInterrupt(threadContext->impl); threadContext->impl->state = mTHREAD_EXITING; ConditionWake(&threadContext->impl->stateOnThreadCond); From 6be223d84a4f319f82d07b9569541934cc1f66d9 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 12 Jan 2025 06:14:10 -0800 Subject: [PATCH 19/32] Qt: Defer destroying the CoreController until after the CoreController::stopping slots finish --- src/platform/qt/Window.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index 1be4a998c..a224c3ba4 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -972,7 +972,12 @@ void Window::gameStopped() { #endif } - m_controller.reset(); + std::shared_ptr controller; + m_controller.swap(controller); + QTimer::singleShot(0, this, [controller]() { + // Destroy the controller after everything else has cleaned up + Q_UNUSED(controller); + }); detachWidget(); updateTitle(); @@ -2155,11 +2160,6 @@ void Window::setController(CoreController* controller, const QString& fname) { connect(m_controller.get(), &CoreController::started, this, &Window::gameStarted); connect(m_controller.get(), &CoreController::started, GBAApp::app(), &GBAApp::suspendScreensaver); connect(m_controller.get(), &CoreController::stopping, this, &Window::gameStopped); - { - connect(m_controller.get(), &CoreController::stopping, [this]() { - m_controller.reset(); - }); - } connect(m_controller.get(), &CoreController::stopping, GBAApp::app(), &GBAApp::resumeScreensaver); connect(m_controller.get(), &CoreController::paused, this, &Window::updateFrame); From 8c2e2e1d4628e8794fa547a9acce5d18fe8f585a Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 12 Jan 2025 16:22:34 -0800 Subject: [PATCH 20/32] Qt: Fix build --- src/platform/qt/MemoryView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/qt/MemoryView.cpp b/src/platform/qt/MemoryView.cpp index 009d789aa..dd0bc18a3 100644 --- a/src/platform/qt/MemoryView.cpp +++ b/src/platform/qt/MemoryView.cpp @@ -137,7 +137,7 @@ MemoryView::MemoryView(std::shared_ptr controller, QWidget* pare } } - connect(m_ui.width, &QComboBox::currentIndexChanged, [this](int index) { + connect(m_ui.width, static_cast(&QComboBox::currentIndexChanged), [this](int index) { m_ui.hexfield->setAlignment(1 << index); m_sintValidator.setWidth(1 << index); m_uintValidator.setWidth(1 << index); From deb4f547fa395e182cf2af5bc6feebb5d2bb3470 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 12 Jan 2025 22:41:29 -0800 Subject: [PATCH 21/32] Qt: GB memory access logger fixes --- src/platform/qt/MemoryAccessLogModel.cpp | 26 ++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/platform/qt/MemoryAccessLogModel.cpp b/src/platform/qt/MemoryAccessLogModel.cpp index 23eb34f4c..6fa8592d0 100644 --- a/src/platform/qt/MemoryAccessLogModel.cpp +++ b/src/platform/qt/MemoryAccessLogModel.cpp @@ -39,9 +39,23 @@ QVariant MemoryAccessLogModel::data(const QModelIndex& index, int role) const { const Block& block = m_cachedBlocks[blockIndex]; if (flagIndex < 0) { - return QString("0x%1 – 0x%2") - .arg(QString("%0").arg(block.region.first, 8, 16, QChar('0')).toUpper()) - .arg(QString("%0").arg(block.region.second, 8, 16, QChar('0')).toUpper()); + if (m_platform == mPLATFORM_GB) { + if (m_segment < 0) { + return QString("$%1 – $%2") + .arg(QString("%0").arg(block.region.first, 4, 16, QChar('0')).toUpper()) + .arg(QString("%0").arg(block.region.second, 4, 16, QChar('0')).toUpper()); + } else { + return QString("$%1:%3 – $%2:%4") + .arg(QString("%0").arg(m_segment, 2, 16, QChar('0')).toUpper()) + .arg(QString("%0").arg(m_segment, 2, 16, QChar('0')).toUpper()) + .arg(QString("%0").arg(block.region.first, 4, 16, QChar('0')).toUpper()) + .arg(QString("%0").arg(block.region.second, 4, 16, QChar('0')).toUpper()); + } + } else { + return QString("0x%1 – 0x%2") + .arg(QString("%0").arg(block.region.first, 8, 16, QChar('0')).toUpper()) + .arg(QString("%0").arg(block.region.second, 8, 16, QChar('0')).toUpper()); + } } for (int i = 0; i < 8; ++i) { if (!(block.flags.flags & (1 << i))) { @@ -109,6 +123,8 @@ QVariant MemoryAccessLogModel::data(const QModelIndex& index, int role) const { switch (m_platform) { case mPLATFORM_GBA: return tr("ARM code"); + case mPLATFORM_GB: + return tr("Instruction opcode"); default: return tr("(Private bit 2)"); } @@ -116,8 +132,10 @@ QVariant MemoryAccessLogModel::data(const QModelIndex& index, int role) const { switch (m_platform) { case mPLATFORM_GBA: return tr("Thumb code"); + case mPLATFORM_GB: + return tr("Instruction operand"); default: - return tr("(Private bit 2)"); + return tr("(Private bit 3)"); } default: Q_UNREACHABLE(); From b8c890e1bc3c4910044ce00413214ee9c48930db Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 14 Jan 2025 03:20:01 -0800 Subject: [PATCH 22/32] Debugger: Plumb access source information through to access logger --- include/mgba/core/cpu.h | 9 ++++++ include/mgba/debugger/debugger.h | 1 + include/mgba/internal/arm/arm.h | 2 ++ include/mgba/internal/sm83/sm83.h | 2 ++ src/arm/debugger/memory-debugger.c | 1 + src/debugger/access-logger.c | 43 +++++++++++++++++++++++++++++ src/gb/memory.c | 8 ++++++ src/gba/bios.c | 27 ++++++++++++++++++ src/gba/dma.c | 3 ++ src/gba/memory.c | 10 +++++++ src/sm83/debugger/memory-debugger.c | 1 + 11 files changed, 107 insertions(+) diff --git a/include/mgba/core/cpu.h b/include/mgba/core/cpu.h index 71f3398c2..e538f4a59 100644 --- a/include/mgba/core/cpu.h +++ b/include/mgba/core/cpu.h @@ -20,6 +20,15 @@ enum mCPUComponentType { CPU_COMPONENT_MAX }; +enum mMemoryAccessSource { + mACCESS_UNKNOWN = 0, + mACCESS_PROGRAM, + mACCESS_DMA, + mACCESS_SYSTEM, + mACCESS_DECOMPRESS, + mACCESS_COPY, +}; + struct mCPUComponent { uint32_t id; void (*init)(void* cpu, struct mCPUComponent* component); diff --git a/include/mgba/debugger/debugger.h b/include/mgba/debugger/debugger.h index eb69faaf4..7cf89882b 100644 --- a/include/mgba/debugger/debugger.h +++ b/include/mgba/debugger/debugger.h @@ -111,6 +111,7 @@ struct mDebuggerEntryInfo { uint32_t newValue; enum mWatchpointType watchType; enum mWatchpointType accessType; + enum mMemoryAccessSource accessSource; } wp; struct { diff --git a/include/mgba/internal/arm/arm.h b/include/mgba/internal/arm/arm.h index 5f25acf90..5ef2da965 100644 --- a/include/mgba/internal/arm/arm.h +++ b/include/mgba/internal/arm/arm.h @@ -132,6 +132,8 @@ struct ARMMemory { uint32_t activeNonseqCycles16; int32_t (*stall)(struct ARMCore*, int32_t wait); void (*setActiveRegion)(struct ARMCore*, uint32_t address); + + enum mMemoryAccessSource accessSource; }; struct ARMCoprocessor { diff --git a/include/mgba/internal/sm83/sm83.h b/include/mgba/internal/sm83/sm83.h index 86b4d374b..7f0fabd7a 100644 --- a/include/mgba/internal/sm83/sm83.h +++ b/include/mgba/internal/sm83/sm83.h @@ -61,6 +61,8 @@ struct SM83Memory { uint16_t activeMask; uint16_t activeRegionEnd; void (*setActiveRegion)(struct SM83Core*, uint16_t address); + + enum mMemoryAccessSource accessSource; }; struct SM83InterruptHandler { diff --git a/src/arm/debugger/memory-debugger.c b/src/arm/debugger/memory-debugger.c index 7dce87795..b0b48423b 100644 --- a/src/arm/debugger/memory-debugger.c +++ b/src/arm/debugger/memory-debugger.c @@ -121,6 +121,7 @@ static void _checkWatchpoints(struct ARMDebugger* debugger, uint32_t address, en info.type.wp.newValue = newValue; info.type.wp.watchType = watchpoint->type; info.type.wp.accessType = type; + info.type.wp.accessSource = debugger->cpu->memory.accessSource; info.address = address; info.segment = 0; info.width = width; diff --git a/src/debugger/access-logger.c b/src/debugger/access-logger.c index e38eead03..d8275a970 100644 --- a/src/debugger/access-logger.c +++ b/src/debugger/access-logger.c @@ -69,9 +69,29 @@ static void _mDebuggerAccessLoggerEntered(struct mDebuggerModule* debugger, enum } offset &= -info->width; + mDebuggerAccessLogFlagsEx flagsEx = 0; int i; switch (reason) { case DEBUGGER_ENTER_WATCHPOINT: + switch (info->type.wp.accessSource) { + case mACCESS_PROGRAM: + flagsEx = mDebuggerAccessLogFlagsExFillAccessProgram(flagsEx); + break; + case mACCESS_DMA: + flagsEx = mDebuggerAccessLogFlagsExFillAccessDMA(flagsEx); + break; + case mACCESS_SYSTEM: + flagsEx = mDebuggerAccessLogFlagsExFillAccessSystem(flagsEx); + break; + case mACCESS_DECOMPRESS: + flagsEx = mDebuggerAccessLogFlagsExFillAccessDecompress(flagsEx); + break; + case mACCESS_COPY: + flagsEx = mDebuggerAccessLogFlagsExFillAccessCopy(flagsEx); + break; + case mACCESS_UNKNOWN: + break; + } for (i = 0; i < info->width; ++i) { if (info->type.wp.accessType & WATCHPOINT_WRITE) { region->block[offset + i] = mDebuggerAccessLogFlagsFillWrite(region->block[offset + i]); @@ -83,16 +103,29 @@ static void _mDebuggerAccessLoggerEntered(struct mDebuggerModule* debugger, enum switch (info->width) { case 1: region->block[offset] = mDebuggerAccessLogFlagsFillAccess8(region->block[offset]); + if (region->blockEx) { + region->blockEx[offset] |= flagsEx; + } break; case 2: region->block[offset] = mDebuggerAccessLogFlagsFillAccess16(region->block[offset]); region->block[offset + 1] = mDebuggerAccessLogFlagsFillAccess16(region->block[offset + 1]); + if (region->blockEx) { + region->blockEx[offset] |= flagsEx; + region->blockEx[offset + 1] |= flagsEx; + } break; case 4: region->block[offset] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset]); region->block[offset + 1] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset + 1]); region->block[offset + 2] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset + 2]); region->block[offset + 3] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset + 3]); + if (region->blockEx) { + region->blockEx[offset] |= flagsEx; + region->blockEx[offset + 1] |= flagsEx; + region->blockEx[offset + 2] |= flagsEx; + region->blockEx[offset + 3] |= flagsEx; + } break; case 8: region->block[offset] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset]); @@ -103,6 +136,16 @@ static void _mDebuggerAccessLoggerEntered(struct mDebuggerModule* debugger, enum region->block[offset + 5] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 5]); region->block[offset + 6] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 6]); region->block[offset + 7] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 7]); + if (region->blockEx) { + region->blockEx[offset] |= flagsEx; + region->blockEx[offset + 1] |= flagsEx; + region->blockEx[offset + 2] |= flagsEx; + region->blockEx[offset + 3] |= flagsEx; + region->blockEx[offset + 4] |= flagsEx; + region->blockEx[offset + 5] |= flagsEx; + region->blockEx[offset + 6] |= flagsEx; + region->blockEx[offset + 7] |= flagsEx; + } break; } break; diff --git a/src/gb/memory.c b/src/gb/memory.c index dccd91e08..fdacc1a9b 100644 --- a/src/gb/memory.c +++ b/src/gb/memory.c @@ -148,6 +148,7 @@ void GBMemoryInit(struct GB* gb) { cpu->memory.store8 = GBStore8; cpu->memory.currentSegment = GBCurrentSegment; cpu->memory.setActiveRegion = GBSetActiveRegion; + cpu->memory.accessSource = mACCESS_UNKNOWN; gb->memory.wram = 0; gb->memory.wramBank = 0; @@ -205,6 +206,7 @@ void GBMemoryReset(struct GB* gb) { gb->memory.hdmaDest = 0; gb->memory.isHdma = false; + gb->cpu->memory.accessSource = mACCESS_UNKNOWN; gb->memory.dmaEvent.context = gb; gb->memory.dmaEvent.name = "GB DMA"; @@ -576,10 +578,13 @@ void _GBMemoryDMAService(struct mTiming* timing, void* context, uint32_t cyclesL struct GB* gb = context; int dmaRemaining = gb->memory.dmaRemaining; gb->memory.dmaRemaining = 0; + enum mMemoryAccessSource oldAccess = gb->cpu->memory.accessSource; + gb->cpu->memory.accessSource = mACCESS_DMA; uint8_t b = GBLoad8(gb->cpu, gb->memory.dmaSource); // TODO: Can DMA write OAM during modes 2-3? gb->video.oam.raw[gb->memory.dmaDest] = b; gb->video.renderer->writeOAM(gb->video.renderer, gb->memory.dmaDest); + gb->cpu->memory.accessSource = oldAccess; ++gb->memory.dmaSource; ++gb->memory.dmaDest; gb->memory.dmaRemaining = dmaRemaining - 1; @@ -591,8 +596,11 @@ void _GBMemoryDMAService(struct mTiming* timing, void* context, uint32_t cyclesL void _GBMemoryHDMAService(struct mTiming* timing, void* context, uint32_t cyclesLate) { struct GB* gb = context; gb->cpuBlocked = true; + enum mMemoryAccessSource oldAccess = gb->cpu->memory.accessSource; + gb->cpu->memory.accessSource = mACCESS_DMA; uint8_t b = gb->cpu->memory.load8(gb->cpu, gb->memory.hdmaSource); gb->cpu->memory.store8(gb->cpu, gb->memory.hdmaDest, b); + gb->cpu->memory.accessSource = oldAccess; ++gb->memory.hdmaSource; ++gb->memory.hdmaDest; --gb->memory.hdmaRemaining; diff --git a/src/gba/bios.c b/src/gba/bios.c index 1ff5004d3..c7b963a40 100644 --- a/src/gba/bios.c +++ b/src/gba/bios.c @@ -174,6 +174,8 @@ static void _BgAffineSet(struct GBA* gba) { int destination = cpu->gprs[1]; float a, b, c, d; float rx, ry; + enum mMemoryAccessSource oldAccess = cpu->memory.accessSource; + cpu->memory.accessSource = mACCESS_SYSTEM; while (i--) { // [ sx 0 0 ] [ cos(theta) -sin(theta) 0 ] [ 1 0 cx - ox ] [ A B rx ] // [ 0 sy 0 ] * [ sin(theta) cos(theta) 0 ] * [ 0 1 cy - oy ] = [ C D ry ] @@ -205,6 +207,7 @@ static void _BgAffineSet(struct GBA* gba) { cpu->memory.store32(cpu, destination + 12, ry * 256, 0); destination += 16; } + cpu->memory.accessSource = oldAccess; } static void _ObjAffineSet(struct GBA* gba) { @@ -216,6 +219,8 @@ static void _ObjAffineSet(struct GBA* gba) { int destination = cpu->gprs[1]; int diff = cpu->gprs[3]; float a, b, c, d; + enum mMemoryAccessSource oldAccess = cpu->memory.accessSource; + cpu->memory.accessSource = mACCESS_SYSTEM; while (i--) { // [ sx 0 ] [ cos(theta) -sin(theta) ] [ A B ] // [ 0 sy ] * [ sin(theta) cos(theta) ] = [ C D ] @@ -237,6 +242,7 @@ static void _ObjAffineSet(struct GBA* gba) { cpu->memory.store16(cpu, destination + diff * 3, d * 256, 0); destination += diff * 4; } + cpu->memory.accessSource = oldAccess; } static void _MidiKey2Freq(struct GBA* gba) { @@ -244,7 +250,10 @@ static void _MidiKey2Freq(struct GBA* gba) { int oldRegion = gba->memory.activeRegion; gba->memory.activeRegion = GBA_REGION_BIOS; + enum mMemoryAccessSource oldAccess = cpu->memory.accessSource; + cpu->memory.accessSource = mACCESS_SYSTEM; uint32_t key = cpu->memory.load32(cpu, cpu->gprs[0] + 4, 0); + cpu->memory.accessSource = oldAccess; gba->memory.activeRegion = oldRegion; cpu->gprs[0] = key / exp2f((180.f - cpu->gprs[1] - cpu->gprs[2] / 256.f) / 12.f); @@ -624,6 +633,8 @@ static void _unLz77(struct GBA* gba, int width) { uint32_t source = cpu->gprs[0]; uint32_t dest = cpu->gprs[1]; int cycles = 20; + enum mMemoryAccessSource oldAccess = cpu->memory.accessSource; + cpu->memory.accessSource = mACCESS_DECOMPRESS; int remaining = (cpu->memory.load32(cpu, source, &cycles) & 0xFFFFFF00) >> 8; // We assume the signature byte (0x10) is correct int blockheader = 0; // Some compilers warn if this isn't set, even though it's trivially provably always set @@ -698,6 +709,7 @@ static void _unLz77(struct GBA* gba, int width) { blocksRemaining = 8; } } + cpu->memory.accessSource = oldAccess; cpu->gprs[0] = source; cpu->gprs[1] = dest; cpu->gprs[3] = 0; @@ -713,6 +725,8 @@ static void _unHuffman(struct GBA* gba) { struct ARMCore* cpu = gba->cpu; uint32_t source = cpu->gprs[0] & 0xFFFFFFFC; uint32_t dest = cpu->gprs[1]; + enum mMemoryAccessSource oldAccess = cpu->memory.accessSource; + cpu->memory.accessSource = mACCESS_DECOMPRESS; uint32_t header = cpu->memory.load32(cpu, source, 0); int remaining = header >> 8; unsigned bits = header & 0xF; @@ -722,6 +736,7 @@ static void _unHuffman(struct GBA* gba) { } if (32 % bits || bits == 1) { mLOG(GBA_BIOS, STUB, "Unimplemented unaligned Huffman"); + cpu->memory.accessSource = oldAccess; return; } // We assume the signature byte (0x20) is correct @@ -773,6 +788,7 @@ static void _unHuffman(struct GBA* gba) { } } } + cpu->memory.accessSource = oldAccess; cpu->gprs[0] = source; cpu->gprs[1] = dest; } @@ -780,6 +796,8 @@ static void _unHuffman(struct GBA* gba) { static void _unRl(struct GBA* gba, int width) { struct ARMCore* cpu = gba->cpu; uint32_t source = cpu->gprs[0]; + enum mMemoryAccessSource oldAccess = cpu->memory.accessSource; + cpu->memory.accessSource = mACCESS_DECOMPRESS; int remaining = (cpu->memory.load32(cpu, source & 0xFFFFFFFC, 0) & 0xFFFFFF00) >> 8; int padding = (4 - remaining) & 0x3; // We assume the signature byte (0x30) is correct @@ -846,6 +864,7 @@ static void _unRl(struct GBA* gba, int width) { ++dest; } } + cpu->memory.accessSource = oldAccess; cpu->gprs[0] = source; cpu->gprs[1] = dest; } @@ -854,6 +873,8 @@ static void _unFilter(struct GBA* gba, int inwidth, int outwidth) { struct ARMCore* cpu = gba->cpu; uint32_t source = cpu->gprs[0] & 0xFFFFFFFC; uint32_t dest = cpu->gprs[1]; + enum mMemoryAccessSource oldAccess = cpu->memory.accessSource; + cpu->memory.accessSource = mACCESS_DECOMPRESS; uint32_t header = cpu->memory.load32(cpu, source, 0); int remaining = header >> 8; // We assume the signature nybble (0x8) is correct @@ -888,6 +909,7 @@ static void _unFilter(struct GBA* gba, int inwidth, int outwidth) { old = new; source += inwidth; } + cpu->memory.accessSource = oldAccess; cpu->gprs[0] = source; cpu->gprs[1] = dest; } @@ -897,6 +919,8 @@ static void _unBitPack(struct GBA* gba) { uint32_t source = cpu->gprs[0]; uint32_t dest = cpu->gprs[1]; uint32_t info = cpu->gprs[2]; + enum mMemoryAccessSource oldAccess = cpu->memory.accessSource; + cpu->memory.accessSource = mACCESS_DECOMPRESS; unsigned sourceLen = cpu->memory.load16(cpu, info, 0); unsigned sourceWidth = cpu->memory.load8(cpu, info + 2, 0); unsigned destWidth = cpu->memory.load8(cpu, info + 3, 0); @@ -908,6 +932,7 @@ static void _unBitPack(struct GBA* gba) { break; default: mLOG(GBA_BIOS, GAME_ERROR, "Bad BitUnPack source width: %u", sourceWidth); + cpu->memory.accessSource = oldAccess; return; } switch (destWidth) { @@ -920,6 +945,7 @@ static void _unBitPack(struct GBA* gba) { break; default: mLOG(GBA_BIOS, GAME_ERROR, "Bad BitUnPack destination width: %u", destWidth); + cpu->memory.accessSource = oldAccess; return; } uint32_t bias = cpu->memory.load32(cpu, info + 4, 0); @@ -949,6 +975,7 @@ static void _unBitPack(struct GBA* gba) { dest += 4; } } + cpu->memory.accessSource = oldAccess; cpu->gprs[0] = source; cpu->gprs[1] = dest; } diff --git a/src/gba/dma.c b/src/gba/dma.c index e9044d26a..3e3e8222d 100644 --- a/src/gba/dma.c +++ b/src/gba/dma.c @@ -248,10 +248,12 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { uint32_t dest = info->nextDest; uint32_t sourceRegion = source >> BASE_OFFSET; uint32_t destRegion = dest >> BASE_OFFSET; + enum mMemoryAccessSource oldAccess = cpu->memory.accessSource; int32_t cycles = 2; gba->cpuBlocked = true; gba->performingDMA = 1 | (number << 1); + cpu->memory.accessSource = mACCESS_DMA; if (info->count == info->nextCount) { if (width == 4) { @@ -315,6 +317,7 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { --info->nextCount; gba->performingDMA = 0; + cpu->memory.accessSource = oldAccess; int i; for (i = 0; i < 4; ++i) { diff --git a/src/gba/memory.c b/src/gba/memory.c index 4f074657a..27e289c8e 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -82,6 +82,7 @@ void GBAMemoryInit(struct GBA* gba) { cpu->memory.activeSeqCycles16 = 0; cpu->memory.activeNonseqCycles32 = 0; cpu->memory.activeNonseqCycles16 = 0; + cpu->memory.accessSource = mACCESS_UNKNOWN; gba->memory.biosPrefetch = 0; gba->memory.agbPrintProtect = 0; @@ -132,6 +133,7 @@ void GBAMemoryReset(struct GBA* gba) { gba->memory.prefetch = false; gba->memory.lastPrefetchedPc = 0; + gba->cpu->memory.accessSource = mACCESS_UNKNOWN; if (!gba->memory.wram || !gba->memory.iwram) { GBAMemoryDeinit(gba); @@ -299,22 +301,27 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { memory->activeRegion = newRegion; switch (newRegion) { case GBA_REGION_BIOS: + cpu->memory.accessSource = mACCESS_SYSTEM; cpu->memory.activeRegion = memory->bios; cpu->memory.activeMask = GBA_SIZE_BIOS - 1; break; case GBA_REGION_EWRAM: + cpu->memory.accessSource = mACCESS_PROGRAM; cpu->memory.activeRegion = memory->wram; cpu->memory.activeMask = GBA_SIZE_EWRAM - 1; break; case GBA_REGION_IWRAM: + cpu->memory.accessSource = mACCESS_PROGRAM; cpu->memory.activeRegion = memory->iwram; cpu->memory.activeMask = GBA_SIZE_IWRAM - 1; break; case GBA_REGION_PALETTE_RAM: + cpu->memory.accessSource = mACCESS_PROGRAM; cpu->memory.activeRegion = (uint32_t*) gba->video.palette; cpu->memory.activeMask = GBA_SIZE_PALETTE_RAM - 1; break; case GBA_REGION_VRAM: + cpu->memory.accessSource = mACCESS_PROGRAM; if (address & 0x10000) { cpu->memory.activeRegion = (uint32_t*) &gba->video.vram[0x8000]; cpu->memory.activeMask = 0x00007FFF; @@ -324,6 +331,7 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { } break; case GBA_REGION_OAM: + cpu->memory.accessSource = mACCESS_PROGRAM; cpu->memory.activeRegion = (uint32_t*) gba->video.oam.raw; cpu->memory.activeMask = GBA_SIZE_OAM - 1; break; @@ -333,6 +341,7 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { case GBA_REGION_ROM1_EX: case GBA_REGION_ROM2: case GBA_REGION_ROM2_EX: + cpu->memory.accessSource = mACCESS_PROGRAM; cpu->memory.activeRegion = memory->rom; cpu->memory.activeMask = memory->romMask; if ((address & (GBA_SIZE_ROM0 - 1)) < memory->romSize) { @@ -345,6 +354,7 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { } // Fall through default: + cpu->memory.accessSource = mACCESS_UNKNOWN; memory->activeRegion = -1; cpu->memory.activeRegion = (uint32_t*) _deadbeef; cpu->memory.activeMask = 0; diff --git a/src/sm83/debugger/memory-debugger.c b/src/sm83/debugger/memory-debugger.c index a35c2afeb..345dc50bf 100644 --- a/src/sm83/debugger/memory-debugger.c +++ b/src/sm83/debugger/memory-debugger.c @@ -61,6 +61,7 @@ static void _checkWatchpoints(struct SM83Debugger* debugger, uint16_t address, e info.type.wp.newValue = newValue; info.type.wp.watchType = watchpoint->type; info.type.wp.accessType = type; + info.type.wp.accessSource = debugger->cpu->memory.accessSource; info.address = address; info.segment = debugger->originalMemory.currentSegment(debugger->cpu, address); info.width = 1; From 311d9f3550824c473958b66ce6211a5092d23b66 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 14 Jan 2025 03:38:30 -0800 Subject: [PATCH 23/32] Debugger: Unroll watchpoint access loop --- src/debugger/access-logger.c | 43 ++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/debugger/access-logger.c b/src/debugger/access-logger.c index d8275a970..fbe681432 100644 --- a/src/debugger/access-logger.c +++ b/src/debugger/access-logger.c @@ -69,6 +69,7 @@ static void _mDebuggerAccessLoggerEntered(struct mDebuggerModule* debugger, enum } offset &= -info->width; + mDebuggerAccessLogFlags flags = 0; mDebuggerAccessLogFlagsEx flagsEx = 0; int i; switch (reason) { @@ -92,34 +93,32 @@ static void _mDebuggerAccessLoggerEntered(struct mDebuggerModule* debugger, enum case mACCESS_UNKNOWN: break; } - for (i = 0; i < info->width; ++i) { - if (info->type.wp.accessType & WATCHPOINT_WRITE) { - region->block[offset + i] = mDebuggerAccessLogFlagsFillWrite(region->block[offset + i]); - } - if (info->type.wp.accessType & WATCHPOINT_READ) { - region->block[offset + i] = mDebuggerAccessLogFlagsFillRead(region->block[offset + i]); - } + if (info->type.wp.accessType & WATCHPOINT_WRITE) { + flags = mDebuggerAccessLogFlagsFillWrite(flags); + } + if (info->type.wp.accessType & WATCHPOINT_READ) { + flags = mDebuggerAccessLogFlagsFillRead(flags); } switch (info->width) { case 1: - region->block[offset] = mDebuggerAccessLogFlagsFillAccess8(region->block[offset]); + region->block[offset] = flags | mDebuggerAccessLogFlagsFillAccess8(region->block[offset]); if (region->blockEx) { region->blockEx[offset] |= flagsEx; } break; case 2: - region->block[offset] = mDebuggerAccessLogFlagsFillAccess16(region->block[offset]); - region->block[offset + 1] = mDebuggerAccessLogFlagsFillAccess16(region->block[offset + 1]); + region->block[offset] = flags | mDebuggerAccessLogFlagsFillAccess16(region->block[offset]); + region->block[offset + 1] = flags | mDebuggerAccessLogFlagsFillAccess16(region->block[offset + 1]); if (region->blockEx) { region->blockEx[offset] |= flagsEx; region->blockEx[offset + 1] |= flagsEx; } break; case 4: - region->block[offset] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset]); - region->block[offset + 1] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset + 1]); - region->block[offset + 2] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset + 2]); - region->block[offset + 3] = mDebuggerAccessLogFlagsFillAccess32(region->block[offset + 3]); + region->block[offset] = flags | mDebuggerAccessLogFlagsFillAccess32(region->block[offset]); + region->block[offset + 1] = flags | mDebuggerAccessLogFlagsFillAccess32(region->block[offset + 1]); + region->block[offset + 2] = flags | mDebuggerAccessLogFlagsFillAccess32(region->block[offset + 2]); + region->block[offset + 3] = flags | mDebuggerAccessLogFlagsFillAccess32(region->block[offset + 3]); if (region->blockEx) { region->blockEx[offset] |= flagsEx; region->blockEx[offset + 1] |= flagsEx; @@ -128,14 +127,14 @@ static void _mDebuggerAccessLoggerEntered(struct mDebuggerModule* debugger, enum } break; case 8: - region->block[offset] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset]); - region->block[offset + 1] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 1]); - region->block[offset + 2] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 2]); - region->block[offset + 3] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 3]); - region->block[offset + 4] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 4]); - region->block[offset + 5] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 5]); - region->block[offset + 6] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 6]); - region->block[offset + 7] = mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 7]); + region->block[offset] = flags | mDebuggerAccessLogFlagsFillAccess64(region->block[offset]); + region->block[offset + 1] = flags | mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 1]); + region->block[offset + 2] = flags | mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 2]); + region->block[offset + 3] = flags | mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 3]); + region->block[offset + 4] = flags | mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 4]); + region->block[offset + 5] = flags | mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 5]); + region->block[offset + 6] = flags | mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 6]); + region->block[offset + 7] = flags | mDebuggerAccessLogFlagsFillAccess64(region->block[offset + 7]); if (region->blockEx) { region->blockEx[offset] |= flagsEx; region->blockEx[offset + 1] |= flagsEx; From 7012f9c6662e564d9a64e3d0dd86aa1028f8853d Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 15 Jan 2025 23:46:20 -0800 Subject: [PATCH 24/32] Debugger: Allow memory access logs to operate read-only --- include/mgba/debugger/debugger.h | 1 + .../mgba/internal/debugger/access-logger.h | 4 ++ src/debugger/access-logger.c | 48 +++++++++++++++---- src/platform/qt/MemoryAccessLogController.cpp | 1 + src/platform/test/fuzz-main.c | 1 + 5 files changed, 46 insertions(+), 9 deletions(-) diff --git a/include/mgba/debugger/debugger.h b/include/mgba/debugger/debugger.h index 7cf89882b..230a95564 100644 --- a/include/mgba/debugger/debugger.h +++ b/include/mgba/debugger/debugger.h @@ -257,6 +257,7 @@ bool mDebuggerIsShutdown(const struct mDebugger*); struct mDebuggerModule* mDebuggerCreateModule(enum mDebuggerType type, struct mCore*); void mDebuggerModuleSetNeedsCallback(struct mDebuggerModule*); +void mDebuggerModuleClearNeedsCallback(struct mDebuggerModule*); bool mDebuggerLookupIdentifier(struct mDebugger* debugger, const char* name, int32_t* value, int* segment); diff --git a/include/mgba/internal/debugger/access-logger.h b/include/mgba/internal/debugger/access-logger.h index b839bd5b1..180168f3a 100644 --- a/include/mgba/internal/debugger/access-logger.h +++ b/include/mgba/internal/debugger/access-logger.h @@ -23,6 +23,7 @@ struct mDebuggerAccessLogRegion { uint32_t segmentStart; mDebuggerAccessLogFlags* block; mDebuggerAccessLogFlagsEx* blockEx; + ssize_t watchpoint; }; DECLARE_VECTOR(mDebuggerAccessLogRegionList, struct mDebuggerAccessLogRegion); @@ -41,6 +42,9 @@ void mDebuggerAccessLoggerDeinit(struct mDebuggerAccessLogger*); bool mDebuggerAccessLoggerOpen(struct mDebuggerAccessLogger*, struct VFile*, int mode); bool mDebuggerAccessLoggerClose(struct mDebuggerAccessLogger*); +void mDebuggerAccessLoggerStart(struct mDebuggerAccessLogger*); +void mDebuggerAccessLoggerStop(struct mDebuggerAccessLogger*); + int mDebuggerAccessLoggerWatchMemoryBlockId(struct mDebuggerAccessLogger*, size_t id, mDebuggerAccessLogRegionFlags); int mDebuggerAccessLoggerWatchMemoryBlockName(struct mDebuggerAccessLogger*, const char* internalName, mDebuggerAccessLogRegionFlags); diff --git a/src/debugger/access-logger.c b/src/debugger/access-logger.c index fbe681432..7133565e9 100644 --- a/src/debugger/access-logger.c +++ b/src/debugger/access-logger.c @@ -71,7 +71,6 @@ static void _mDebuggerAccessLoggerEntered(struct mDebuggerModule* debugger, enum mDebuggerAccessLogFlags flags = 0; mDebuggerAccessLogFlagsEx flagsEx = 0; - int i; switch (reason) { case DEBUGGER_ENTER_WATCHPOINT: switch (info->type.wp.accessSource) { @@ -257,13 +256,18 @@ static bool _setupRegion(struct mDebuggerAccessLogger* logger, struct mDebuggerA return false; } - struct mWatchpoint wp = { - .segment = -1, - .minAddress = region->start, - .maxAddress = region->end, - .type = WATCHPOINT_RW, - }; - logger->d.p->platform->setWatchpoint(logger->d.p->platform, &logger->d, &wp); + if (region->watchpoint < 0) { + struct mWatchpoint wp = { + .segment = -1, + .minAddress = region->start, + .maxAddress = region->end, + .type = WATCHPOINT_RW, + }; + region->watchpoint = logger->d.p->platform->setWatchpoint(logger->d.p->platform, &logger->d, &wp); + } + if (region->watchpoint < 0) { + return false; + } mDebuggerModuleSetNeedsCallback(&logger->d); return true; } @@ -307,7 +311,7 @@ static bool mDebuggerAccessLoggerLoad(struct mDebuggerAccessLogger* logger) { LOAD_32LE(region->end, 0, &info->end); LOAD_32LE(region->size, 0, &info->size); LOAD_32LE(region->segmentStart, 0, &info->segmentStart); - if (!_setupRegion(logger, region, info)) { + if (!_mapRegion(logger, region, info)) { mDebuggerAccessLogRegionListClear(&logger->regions); return false; } @@ -352,6 +356,30 @@ bool mDebuggerAccessLoggerOpen(struct mDebuggerAccessLogger* logger, struct VFil return loaded; } +void mDebuggerAccessLoggerStart(struct mDebuggerAccessLogger* logger) { + size_t i; + for (i = 0; i < logger->mapped->header.nRegions; ++i) { + struct mDebuggerAccessLogRegionInfo* info = &logger->mapped->regionInfo[i]; + struct mDebuggerAccessLogRegion* region = mDebuggerAccessLogRegionListGetPointer(&logger->regions, i); + if (!_setupRegion(logger, region, info)) { + return; + } + } +} + +void mDebuggerAccessLoggerStop(struct mDebuggerAccessLogger* logger) { + size_t i; + for (i = 0; i < logger->mapped->header.nRegions; ++i) { + struct mDebuggerAccessLogRegion* region = mDebuggerAccessLogRegionListGetPointer(&logger->regions, i); + if (region->watchpoint < 0) { + continue; + } + logger->d.p->platform->clearBreakpoint(logger->d.p->platform, region->watchpoint); + region->watchpoint = -1; + } + logger->d.needsCallback = false; +} + static int _mDebuggerAccessLoggerWatchMemoryBlock(struct mDebuggerAccessLogger* logger, const struct mCoreMemoryBlock* block, mDebuggerAccessLogRegionFlags flags) { if (mDebuggerAccessLogRegionListSize(&logger->regions) >= logger->mapped->header.regionCapacity) { return -1; @@ -423,6 +451,7 @@ static int _mDebuggerAccessLoggerWatchMemoryBlock(struct mDebuggerAccessLogger* region->size = block->size; region->segmentStart = block->segmentStart; region->block = (mDebuggerAccessLogFlags*) ((uintptr_t) logger->backing + fileEnd); + region->watchpoint = -1; struct mDebuggerAccessLogRegionInfo* info = &logger->mapped->regionInfo[id]; STORE_32LE(region->start, 0, &info->start); @@ -451,6 +480,7 @@ bool mDebuggerAccessLoggerClose(struct mDebuggerAccessLogger* logger) { if (!logger->backing) { return true; } + mDebuggerAccessLoggerStop(logger); mDebuggerAccessLogRegionListClear(&logger->regions); logger->backing->unmap(logger->backing, logger->mapped, logger->backing->size(logger->backing)); logger->mapped = NULL; diff --git a/src/platform/qt/MemoryAccessLogController.cpp b/src/platform/qt/MemoryAccessLogController.cpp index 9691dcadf..c2f2216d5 100644 --- a/src/platform/qt/MemoryAccessLogController.cpp +++ b/src/platform/qt/MemoryAccessLogController.cpp @@ -93,6 +93,7 @@ void MemoryAccessLogController::start(bool loadExisting, bool logExtra) { LOG(QT, ERROR) << tr("Failed to open memory log file"); return; } + mDebuggerAccessLoggerStart(&m_logger); m_active = true; emit loggingChanged(true); diff --git a/src/platform/test/fuzz-main.c b/src/platform/test/fuzz-main.c index 143edaba1..5fdfff8a3 100644 --- a/src/platform/test/fuzz-main.c +++ b/src/platform/test/fuzz-main.c @@ -130,6 +130,7 @@ int main(int argc, char** argv) { mDebuggerAccessLoggerInit(&accessLog); mDebuggerAttachModule(&debugger, &accessLog.d); mDebuggerAccessLoggerOpen(&accessLog, vf, O_RDWR); + mDebuggerAccessLoggerStart(&accessLog); hasDebugger = true; } From 4cc49a670079a8e3c6b6c7cf5b4a30091e7f5ddc Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 18 Jan 2025 23:46:24 -0800 Subject: [PATCH 25/32] Qt: Let memory access logs be loaded read-only --- src/platform/qt/MemoryAccessLogController.cpp | 59 ++++++++++++----- src/platform/qt/MemoryAccessLogController.h | 6 ++ src/platform/qt/MemoryAccessLogView.cpp | 54 +++++++++++---- src/platform/qt/MemoryAccessLogView.h | 4 ++ src/platform/qt/MemoryAccessLogView.ui | 65 +++++++++++++++++-- 5 files changed, 155 insertions(+), 33 deletions(-) diff --git a/src/platform/qt/MemoryAccessLogController.cpp b/src/platform/qt/MemoryAccessLogController.cpp index c2f2216d5..d62b2f8a5 100644 --- a/src/platform/qt/MemoryAccessLogController.cpp +++ b/src/platform/qt/MemoryAccessLogController.cpp @@ -65,7 +65,9 @@ void MemoryAccessLogController::updateRegion(const QString& internalName, bool c if (!m_active) { return; } - m_regionMapping[internalName] = mDebuggerAccessLoggerWatchMemoryBlockName(&m_logger, internalName.toUtf8().constData(), activeFlags()); + if (checked && !m_regionMapping.contains(internalName)) { + m_regionMapping[internalName] = mDebuggerAccessLoggerWatchMemoryBlockName(&m_logger, internalName.toUtf8().constData(), activeFlags()); + } emit regionMappingChanged(internalName, checked); } @@ -74,6 +76,38 @@ void MemoryAccessLogController::setFile(const QString& path) { } void MemoryAccessLogController::start(bool loadExisting, bool logExtra) { + if (!m_loaded) { + load(loadExisting); + } + if (!m_loaded) { + return; + } + CoreController::Interrupter interrupter(m_controller); + mDebuggerAccessLoggerStart(&m_logger); + m_logExtra = logExtra; + + m_active = true; + for (const auto& region : m_watchedRegions) { + m_regionMapping[region] = mDebuggerAccessLoggerWatchMemoryBlockName(&m_logger, region.toUtf8().constData(), activeFlags()); + } + emit loggingChanged(true); +} + +void MemoryAccessLogController::stop() { + if (!m_active) { + return; + } + CoreController::Interrupter interrupter(m_controller); + mDebuggerAccessLoggerStop(&m_logger); + emit loggingChanged(false); + interrupter.resume(); + m_active = false; +} + +void MemoryAccessLogController::load(bool loadExisting) { + if (m_loaded) { + return; + } int flags = O_CREAT | O_RDWR; if (!loadExisting) { flags |= O_TRUNC; @@ -83,7 +117,6 @@ void MemoryAccessLogController::start(bool loadExisting, bool logExtra) { LOG(QT, ERROR) << tr("Failed to open memory log file"); return; } - m_logExtra = logExtra; mDebuggerAccessLoggerInit(&m_logger); CoreController::Interrupter interrupter(m_controller); @@ -93,26 +126,22 @@ void MemoryAccessLogController::start(bool loadExisting, bool logExtra) { LOG(QT, ERROR) << tr("Failed to open memory log file"); return; } - mDebuggerAccessLoggerStart(&m_logger); - - m_active = true; - emit loggingChanged(true); - for (const auto& region : m_watchedRegions) { - m_regionMapping[region] = mDebuggerAccessLoggerWatchMemoryBlockName(&m_logger, region.toUtf8().constData(), activeFlags()); - } - interrupter.resume(); + emit loaded(true); + m_loaded = true; } -void MemoryAccessLogController::stop() { - if (!m_active) { +void MemoryAccessLogController::unload() { + if (m_active) { + stop(); + } + if (m_active) { return; } CoreController::Interrupter interrupter(m_controller); m_controller->detachDebuggerModule(&m_logger.d); mDebuggerAccessLoggerDeinit(&m_logger); - emit loggingChanged(false); - interrupter.resume(); - m_active = false; + emit loaded(false); + m_loaded = false; } mDebuggerAccessLogRegionFlags MemoryAccessLogController::activeFlags() const { diff --git a/src/platform/qt/MemoryAccessLogController.h b/src/platform/qt/MemoryAccessLogController.h index 79553b333..b2df55214 100644 --- a/src/platform/qt/MemoryAccessLogController.h +++ b/src/platform/qt/MemoryAccessLogController.h @@ -49,6 +49,7 @@ public: QString file() const { return m_path; } bool active() const { return m_active; } + bool isLoaded() const { return m_loaded; } public slots: void updateRegion(const QString& internalName, bool enable); @@ -57,9 +58,13 @@ public slots: void start(bool loadExisting, bool logExtra); void stop(); + void load(bool loadExisting); + void unload(); + void exportFile(const QString& filename); signals: + void loaded(bool loaded); void loggingChanged(bool active); void regionMappingChanged(const QString& internalName, bool active); @@ -71,6 +76,7 @@ private: QHash m_regionMapping; QVector m_regions; struct mDebuggerAccessLogger m_logger{}; + bool m_loaded = false; bool m_active = false; mDebuggerAccessLogRegion* m_cachedRegion = nullptr; diff --git a/src/platform/qt/MemoryAccessLogView.cpp b/src/platform/qt/MemoryAccessLogView.cpp index 97a0c932e..a06c649ae 100644 --- a/src/platform/qt/MemoryAccessLogView.cpp +++ b/src/platform/qt/MemoryAccessLogView.cpp @@ -26,8 +26,10 @@ MemoryAccessLogView::MemoryAccessLogView(std::weak_ptractive(); + bool loaded = controllerPtr->isLoaded(); auto watchedRegions = controllerPtr->watchedRegions(); QVBoxLayout* regionBox = static_cast(m_ui.regionBox->layout()); @@ -46,11 +48,14 @@ MemoryAccessLogView::MemoryAccessLogView(std::weak_ptrsetEnabled(false); +void MemoryAccessLogView::updateRegion(const QString& internalName, bool checked) { + if (checked) { + m_regionBoxes[internalName]->setEnabled(false); + } } void MemoryAccessLogView::start() { @@ -68,10 +73,23 @@ void MemoryAccessLogView::stop() { return; } controllerPtr->stop(); - for (const auto& region : controllerPtr->watchedRegions()) { - m_regionBoxes[region]->setEnabled(true); +} + +void MemoryAccessLogView::load() { + std::shared_ptr controllerPtr = m_controller.lock(); + if (!controllerPtr) { + return; } - m_ui.exportButton->setEnabled(false); + controllerPtr->setFile(m_ui.filename->text()); + controllerPtr->load(m_ui.loadExisting->isChecked()); +} + +void MemoryAccessLogView::unload() { + std::shared_ptr controllerPtr = m_controller.lock(); + if (!controllerPtr) { + return; + } + controllerPtr->unload(); } void MemoryAccessLogView::selectFile() { @@ -110,12 +128,26 @@ void MemoryAccessLogView::handleStartStop(bool start) { m_regionBoxes[region]->setChecked(true); } - if (watchedRegions.contains(QString("cart0"))) { - m_ui.exportButton->setEnabled(start); - } - m_ui.start->setDisabled(start); m_ui.stop->setEnabled(start); - m_ui.filename->setDisabled(start); - m_ui.browse->setDisabled(start); + m_ui.unload->setDisabled(start || !controllerPtr->isLoaded()); +} + +void MemoryAccessLogView::handleLoadUnload(bool load) { + std::shared_ptr controllerPtr = m_controller.lock(); + if (!controllerPtr) { + return; + } + m_ui.filename->setText(controllerPtr->file()); + + if (load && controllerPtr->canExport()) { + m_ui.exportButton->setEnabled(true); + } else if (!load) { + m_ui.exportButton->setEnabled(false); + } + + m_ui.load->setDisabled(load); + m_ui.unload->setEnabled(load); + m_ui.filename->setDisabled(load); + m_ui.browse->setDisabled(load); } diff --git a/src/platform/qt/MemoryAccessLogView.h b/src/platform/qt/MemoryAccessLogView.h index e221a5d9d..f1f7c0388 100644 --- a/src/platform/qt/MemoryAccessLogView.h +++ b/src/platform/qt/MemoryAccessLogView.h @@ -34,9 +34,13 @@ private slots: void start(); void stop(); + void load(); + void unload(); + void exportFile(); void handleStartStop(bool start); + void handleLoadUnload(bool load); private: Ui::MemoryAccessLogView m_ui; diff --git a/src/platform/qt/MemoryAccessLogView.ui b/src/platform/qt/MemoryAccessLogView.ui index fe9450f53..9fadd0870 100644 --- a/src/platform/qt/MemoryAccessLogView.ui +++ b/src/platform/qt/MemoryAccessLogView.ui @@ -6,8 +6,8 @@ 0 0 - 385 - 380 + 311 + 387 @@ -22,25 +22,25 @@ Log file - - + + - + Browse - + Log additional information (uses 3× space) - + Load existing file if present @@ -50,6 +50,23 @@ + + + + Load + + + + + + + false + + + Unload + + + @@ -124,9 +141,43 @@ + + load + clicked() + QGBA::MemoryAccessLogView + load() + + + 81 + 152 + + + 192 + 189 + + + + + unload + clicked() + QGBA::MemoryAccessLogView + unload() + + + 226 + 152 + + + 192 + 189 + + + start() stop() + load() + unload() From 4189a4d7317040cc0b6317fac2049043a8a24d82 Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Sat, 18 Jan 2025 22:07:01 +0900 Subject: [PATCH 26/32] docs: add Japanese README I created Japanese translated README. --- README_JP.md | 268 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 README_JP.md diff --git a/README_JP.md b/README_JP.md new file mode 100644 index 000000000..41bca336b --- /dev/null +++ b/README_JP.md @@ -0,0 +1,268 @@ +mGBA +==== + +mGBAは、ゲームボーイアドバンスのゲームを実行するためのエミュレーターです。mGBAの目標は、既存の多くのゲームボーイアドバンスエミュレーターよりも高速かつ正確であり、他のエミュレーターにはない機能を追加することです。また、ゲームボーイおよびゲームボーイカラーのゲームもサポートしています。 + +最新のニュースとダウンロードは、[mgba.io](https://mgba.io/)で見つけることができます。 + +[![Build status](https://buildbot.mgba.io/badges/build-win32.svg)](https://buildbot.mgba.io) +[![Translation status](https://hosted.weblate.org/widgets/mgba/-/svg-badge.svg)](https://hosted.weblate.org/engage/mgba) + +特徴 +-------- + +- 高精度なゲームボーイアドバンスハードウェアのサポート[[1]](#missing)。 +- ゲームボーイ/ゲームボーイカラーのハードウェアサポート。 +- 高速なエミュレーション。ネットブックなどの低スペックハードウェアでもフルスピードで動作することが知られています。 +- 重量級と軽量級のフロントエンドのためのQtおよびSDLポート。 +- ローカル(同じコンピュータ)リンクケーブルのサポート。 +- フラッシュメモリサイズを含む保存タイプの検出[[2]](#flashdetect)。 +- モーションセンサーと振動機能を備えたカートリッジのサポート(ゲームコントローラーでのみ使用可能)。 +- 設定なしでもリアルタイムクロックのサポート。 +- ボクタイゲームのためのソーラーセンサーのサポート。 +- ゲームボーイカメラとゲームボーイプリンターのサポート。 +- 内蔵BIOS実装と外部BIOSファイルの読み込み機能。 +- Luaを使用したスクリプトサポート。 +- Tabキーを押し続けることでターボ/早送りサポート。 +- バッククォートを押し続けることで巻き戻し。 +- 最大10まで設定可能なフレームスキップ。 +- スクリーンショットのサポート。 +- チートコードのサポート。 +- 9つのセーブステートスロット。セーブステートはスクリーンショットとしても表示可能。 +- ビデオ、GIF、WebP、およびAPNGの録画。 +- e-Readerのサポート。 +- キーボードとゲームパッドのリマップ可能なコントロール。 +- ZIPおよび7zファイルからの読み込み。 +- IPS、UPS、およびBPSパッチのサポート。 +- コマンドラインインターフェースとGDBリモートサポートを介したゲームデバッグ、GhidraおよびIDA Proと互換性あり。 +- 設定可能なエミュレーションの巻き戻し。 +- GameSharkおよびAction Replayスナップショットの読み込みおよびエクスポートのサポート。 +- RetroArch/LibretroおよびOpenEmu用のコア。 +- [Weblate](https://hosted.weblate.org/engage/mgba)を介した複数の言語のコミュニティ提供の翻訳。 +- その他、多くの小さな機能。 + +#### ゲームボーイマッパー + +以下のマッパーが完全にサポートされています: + +- MBC1 +- MBC1M +- MBC2 +- MBC3 +- MBC3+RTC +- MBC30 +- MBC5 +- MBC5+Rumble +- MBC7 +- Wisdom Tree(非公式) +- NT "old type" 1 and 2(非公式マルチカート) +- NT "new type"(非公式MBC5類似) +- Pokémon Jade/Diamond(非公式) +- Sachen MMC1(非公式) + +以下のマッパーが部分的にサポートされています: + +- MBC6(フラッシュメモリ書き込みサポートなし) +- MMM01 +- Pocket Cam +- TAMA5(RTCサポート不完全) +- HuC-1(IRサポートなし) +- HuC-3(IRサポートなし) +- Sachen MMC2(代替配線サポートなし) +- BBD(ロゴ切り替えなし) +- Hitek(ロゴ切り替えなし) +- GGB-81(ロゴ切り替えなし) +- Li Cheng(ロゴ切り替えなし) + +### 計画されている機能 + +- ネットワーク対応のマルチプレイヤーリンクケーブルサポート。 +- Dolphin/JOYバスリンクケーブルサポート。 +- MP2kオーディオミキシング、ハードウェアより高品質のサウンド。 +- ツールアシストランのための再録サポート。 +- 包括的なデバッグスイート。 +- ワイヤレスアダプターのサポート。 + +サポートされているプラットフォーム +------------------- + +- Windows 7以降 +- OS X 10.9(Mavericks)[[3]](#osxver)以降 +- Linux +- FreeBSD +- Nintendo 3DS +- Nintendo Switch +- Wii +- PlayStation Vita + +他のUnix系プラットフォーム(OpenBSDなど)も動作することが知られていますが、テストされておらず、完全にはサポートされていません。 + +### システム要件 + +要件は最小限です。Windows Vista以降を実行できるコンピュータであれば、エミュレーションを処理できるはずです。OpenGL 1.1以降のサポートも必要であり、シェーダーや高度な機能にはOpenGL 3.2以降が必要です。 + +ダウンロード +--------- + +ダウンロードは公式ウェブサイトの[ダウンロード][downloads]セクションで見つけることができます。ソースコードは[GitHub][source]で見つけることができます。 + +コントロール +-------- + +コントロールは設定メニューで設定可能です。多くのゲームコントローラーはデフォルトで自動的にマッピングされるはずです。デフォルトのキーボードコントロールは次のとおりです: + +- **A**:X +- **B**:Z +- **L**:A +- **R**:S +- **Start**:Enter +- **Select**:Backspace + +コンパイル +--------- + +コンパイルにはCMake 3.1以降の使用が必要です。GCC、Clang、およびVisual Studio 2019はmGBAのコンパイルに使用できることが知られています。 + +#### Dockerビルド + +ほとんどのプラットフォームでのビルドにはDockerを使用することをお勧めします。いくつかのプラットフォームでmGBAをビルドするために必要なツールチェーンと依存関係を含むいくつかのDockerイメージが提供されています。 + +注意:Windows 10以前の古いWindowsシステムを使用している場合、DockerがVirtualBox共有フォルダーを使用して現在の`mgba`チェックアウトディレクトリをDockerイメージの作業ディレクトリに正しくマッピングするように構成する必要がある場合があります。(詳細については、issue [#1985](https://mgba.io/i/1985)を参照してください。) + +Dockerイメージを使用してmGBAをビルドするには、mGBAのチェックアウトのルートで次のコマンドを実行します: + + docker run --rm -it -v ${PWD}:/home/mgba/src mgba/windows:w32 + +Dockerコンテナを起動した後、ビルド成果物を含む`build-win32`ディレクトリが生成されます。他のプラットフォーム用のDockerイメージに置き換えると、対応する他のディレクトリが生成されます。Docker Hubで利用可能なDockerイメージは次のとおりです: + +- mgba/3ds +- mgba/switch +- mgba/ubuntu:xenial +- mgba/ubuntu:bionic +- mgba/ubuntu:focal +- mgba/ubuntu:groovy +- mgba/vita +- mgba/wii +- mgba/windows:w32 +- mgba/windows:w64 + +ビルドプロセスを高速化したい場合は、`-e MAKEFLAGS=-jN`フラグを追加して、`N`個のCPUコアでmGBAの並列ビルドを行うことを検討してください。 + +#### *nixビルド + +UnixベースのシステムでCMakeを使用してビルドするには、次のコマンドを実行することをお勧めします: + + mkdir build + cd build + cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr .. + make + sudo make install + +これにより、mGBAがビルドされ、`/usr/bin`および`/usr/lib`にインストールされます。インストールされている依存関係は自動的に検出され、依存関係が見つからない場合に無効になる機能は、`cmake`コマンドを実行した後に警告として表示されます。 + +macOSを使用している場合、手順は少し異なります。homebrewパッケージマネージャーを使用していると仮定すると、依存関係を取得してビルドするための推奨コマンドは次のとおりです: + + brew install cmake ffmpeg libzip qt5 sdl2 libedit lua pkg-config + mkdir build + cd build + cmake -DCMAKE_PREFIX_PATH=`brew --prefix qt5` .. + make + +macOSでは`make install`を実行しないでください。正しく動作しないためです。 + +#### Windows開発者ビルド + +##### MSYS2 + +Windowsでの開発用ビルドにはMSYS2を使用することをお勧めします。MSYS2の[ウェブサイト](https://msys2.github.io)に記載されているインストール手順に従ってください。32ビットバージョン(「MSYS2 MinGW 32-bit」)を実行していることを確認してください(x86_64用にビルドする場合は64ビットバージョン「MSYS2 MinGW 64-bit」を実行してください)。必要な依存関係をインストールするために次の追加コマンド(中括弧を含む)を実行します(このコマンドは1100MiB以上のパッケージをダウンロードするため、長時間かかることに注意してください): + + pacman -Sy --needed base-devel git ${MINGW_PACKAGE_PREFIX}-{cmake,ffmpeg,gcc,gdb,libelf,libepoxy,libzip,lua,pkgconf,qt5,SDL2,ntldd-git} + +次のコマンドを実行してソースコードをチェックアウトします: + + git clone https://github.com/mgba-emu/mgba.git + +最後に、次のコマンドを実行してビルドします: + + mkdir -p mgba/build + cd mgba/build + cmake .. -G "MSYS Makefiles" + make -j$(nproc --ignore=1) + +このWindows用mGBAビルドは、実行に必要なDLLが分散しているため、配布には適していないことに注意してください。ただし、開発には最適です。ただし、そのようなビルドを配布する必要がある場合(たとえば、MSYS2環境がインストールされていないマシンでのテスト用)、`cpack -G ZIP`を実行すると、必要なDLLをすべて含むzipファイルが準備されます。 + +##### Visual Studio + +Visual Studioを使用してビルドするには、同様に複雑なセットアップが必要です。まず、[vcpkg](https://github.com/Microsoft/vcpkg)をインストールする必要があります。vcpkgをインストールした後、いくつかの追加パッケージをインストールする必要があります: + + vcpkg install ffmpeg[vpx,x264] libepoxy libpng libzip lua sdl2 sqlite3 + +このインストールでは、Nvidiaハードウェアでのハードウェアアクセラレーションビデオエンコーディングはサポートされません。これが重要な場合は、事前にCUDAをインストールし、前のコマンドに`ffmpeg[vpx,x264,nvcodec]`を置き換えます。 + +Qtもインストールする必要があります。ただし、Qtは合理的な組織ではなく、困窮している会社によって所有および運営されているため、最新バージョンのオフラインオープンソースエディションインストーラーは存在しないため、[旧バージョンのインストーラー](https://download.qt.io/official_releases/qt/5.12/5.12.9/qt-opensource-windows-x86-5.12.9.exe)に戻る必要があります(これには無用なアカウントの作成が必要ですが、一時的に無効なプロキシを設定するか、ネットワークを無効にすることで回避できます)、オンラインインストーラーを使用する(いずれにしてもアカウントが必要です)、またはvcpkgを使用してビルドする(遅い)。これらはすべて良い選択肢ではありません。インストーラーを使用する場合は、適用可能なMSVCバージョンをインストールする必要があります。オフラインインストーラーはMSVC 2019をサポートしていないことに注意してください。vcpkgを使用する場合、次のようにインストールする必要があります。特にクアッドコア以下のコンピュータではかなりの時間がかかります: + + vcpkg install qt5-base qt5-multimedia + +次に、Visual Studioを開き、「リポジトリのクローンを作成」を選択し、`https://github.com/mgba-emu/mgba.git`を入力します。Visual Studioがクローンを完了したら、「ファイル」>「CMake」に移動し、チェックアウトされたリポジトリのルートにあるCMakeLists.txtファイルを開きます。そこから、他のVisual Studio CMakeプロジェクトと同様にVisual StudioでmGBAを開発できます。 + +#### ツールチェーンビルド + +devkitARM(3DS用)、devkitPPC(Wii用)、devkitA64(Switch用)、またはvitasdk(PS Vita用)を持っている場合は、次のコマンドを使用してビルドできます: + + mkdir build + cd build + cmake -DCMAKE_TOOLCHAIN_FILE=../src/platform/3ds/CMakeToolchain.txt .. + make + +次のプラットフォーム用に`-DCMAKE_TOOLCHAIN_FILE`パラメータを置き換えます: + +- 3DS:`../src/platform/3ds/CMakeToolchain.txt` +- Switch:`../src/platform/switch/CMakeToolchain.txt` +- Vita:`../src/platform/psp2/CMakeToolchain.vitasdk` +- Wii:`../src/platform/wii/CMakeToolchain.txt` + +### 依存関係 + +mGBAには厳密な依存関係はありませんが、特定の機能には次のオプションの依存関係が必要です。依存関係が見つからない場合、これらの機能は無効になります。 + +- Qt 5:GUIフロントエンド用。オーディオにはQt MultimediaまたはSDLが必要です。 +- SDL:より基本的なフロントエンドおよびQtフロントエンドでのゲームパッドサポート用。SDL 2が推奨されますが、1.2もサポートされています。 +- zlibおよびlibpng:スクリーンショットサポートおよびPNG内セーブステートサポート用。 +- libedit:コマンドラインデバッガーサポート用。 +- ffmpegまたはlibav:ビデオ、GIF、WebP、およびAPNGの録画用。 +- libzipまたはzlib:zipファイルに保存されたROMの読み込み用。 +- SQLite3:ゲームデータベース用。 +- libelf:ELF読み込み用。 +- Lua:スクリプト用。 +- json-c:スクリプトの`storage` API用。 + +SQLite3、libpng、およびzlibはエミュレーターに含まれているため、最初に外部でコンパイルする必要はありません。 + +脚注 +--------- + +[1] 現在欠けている機能は次のとおりです + +- モード3、4、および5のOBJウィンドウ([バグ#5](http://mgba.io/b/5)) + +[2] フラッシュメモリサイズの検出は一部のケースで機能しません。これらは実行時に構成できますが、そのようなケースに遭遇した場合はバグを報告することをお勧めします。 + +[3] 10.9はQtポートにのみ必要です。10.7またはそれ以前のバージョンでQtポートをビルドまたは実行することは可能かもしれませんが、公式にはサポートされていません。SDLポートは10.5で動作することが知られており、古いバージョンでも動作する可能性があります。 + +[downloads]: http://mgba.io/downloads.html +[source]: https://github.com/mgba-emu/mgba/ + +著作権 +--------- + +mGBAの著作権は© 2013 – 2023 Jeffrey Pfauに帰属します。これは[Mozilla Public License version 2.0](https://www.mozilla.org/MPL/2.0/)の下で配布されています。配布されたLICENSEファイルにライセンスのコピーが含まれています。 + +mGBAには次のサードパーティライブラリが含まれています: + +- [inih](https://github.com/benhoyt/inih)、著作権© 2009 – 2020 Ben Hoyt、BSD 3-clauseライセンスの下で使用。 +- [LZMA SDK](http://www.7-zip.org/sdk.html)、パブリックドメイン。 +- [MurmurHash3](https://github.com/aappleby/smhasher)、Austin Applebyによる実装、パブリックドメイン。 +- [getopt for MSVC](https://github.com/skandhurkat/Getopt-for-Visual-Studio/)、パブリックドメイン。 +- [SQLite3](https://www.sqlite.org)、パブリックドメイン。 + +ゲームパブリッシャーであり、商業利用のためにmGBAのライセンスを取得したい場合は、[licensing@mgba.io](mailto:licensing@mgba.io)までメールでお問い合わせください。 From e518a5ced001834ad09b23b489159c1b00d70035 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 19 Jan 2025 16:57:30 -0800 Subject: [PATCH 27/32] Debugger: Define and use mDebuggerModuleClearNeedsCallback --- src/debugger/access-logger.c | 2 +- src/debugger/debugger.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/debugger/access-logger.c b/src/debugger/access-logger.c index 7133565e9..b9e8222d1 100644 --- a/src/debugger/access-logger.c +++ b/src/debugger/access-logger.c @@ -377,7 +377,7 @@ void mDebuggerAccessLoggerStop(struct mDebuggerAccessLogger* logger) { logger->d.p->platform->clearBreakpoint(logger->d.p->platform, region->watchpoint); region->watchpoint = -1; } - logger->d.needsCallback = false; + mDebuggerModuleClearNeedsCallback(&logger->d); } static int _mDebuggerAccessLoggerWatchMemoryBlock(struct mDebuggerAccessLogger* logger, const struct mCoreMemoryBlock* block, mDebuggerAccessLogRegionFlags flags) { diff --git a/src/debugger/debugger.c b/src/debugger/debugger.c index a03f106d9..995a28099 100644 --- a/src/debugger/debugger.c +++ b/src/debugger/debugger.c @@ -320,3 +320,8 @@ void mDebuggerModuleSetNeedsCallback(struct mDebuggerModule* debugger) { debugger->needsCallback = true; mDebuggerUpdatePaused(debugger->p); } + +void mDebuggerModuleClearNeedsCallback(struct mDebuggerModule* debugger) { + debugger->needsCallback = false; + mDebuggerUpdatePaused(debugger->p); +} From ed64b35db7b933dc77cdd706ab7662d1e1166925 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 19 Jan 2025 18:41:06 -0800 Subject: [PATCH 28/32] CMake: Default macOS SDK version to OS version if not found --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 42712e91c..ad464bab0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -241,6 +241,10 @@ endif() if(APPLE) execute_process(COMMAND xcrun --show-sdk-version OUTPUT_VARIABLE MACOSX_SDK) + if(NOT MACOSX_SDK) + message(WARNING "Could not detect SDK version; defaulting to system version. Is SDKROOT set?") + set(MACOSX_SDK ${CMAKE_SYSTEM_VERSION}) + endif() add_definitions(-D_DARWIN_C_SOURCE) list(APPEND OS_LIB "-framework Foundation") From 2c0e57284104a6ed5824a8bc678775f699c0ec43 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 20 Jan 2025 00:26:05 -0800 Subject: [PATCH 29/32] CHANGES: Add missing entries --- CHANGES | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGES b/CHANGES index 68638bb67..b740f4657 100644 --- a/CHANGES +++ b/CHANGES @@ -1,11 +1,17 @@ 0.11.0: (Future) Features: + - Forwarder support for 3DS and Vita + - Custom border support - New option to lock the maximum frame size + - Memory access and information logging - Scripting: New `input` API for getting raw keyboard/mouse/controller state - Scripting: New `storage` API for saving data for a script, e.g. settings + - Scripting: New `image` and `canvas` APIs for drawing images and displaying on-screen - Scripting: Debugger integration to allow for breakpoints and watchpoints - New unlicensed GB mappers: NT (older types 1 and 2), Li Cheng, GGB-81 + - Initial support for bootleg GBA multicarts - Debugger: Add range watchpoints + - "Headless" frontend for running tests, automation, etc. Emulation fixes: - ARM: Add framework for coprocessor support - GB Serialize: Add missing Pocket Cam state to savestates @@ -30,6 +36,7 @@ Misc: - Core: Handle relative paths for saves, screenshots, etc consistently (fixes mgba.io/i/2826) - Core: Improve rumble emulation by averaging state over entire frame (fixes mgba.io/i/3232) - Core: Add MD5 hashing for ROMs + - Core: Add support for specifying an arbitrary portable directory - GB: Prevent incompatible BIOSes from being used on differing models - GB Serialize: Add missing savestate support for MBC6 and NT (newer) - GBA: Improve detection of valid ELF ROMs @@ -48,7 +55,11 @@ Misc: - Qt: Show maker code and game version in ROM info - Qt: Show a dummy shader settings tab if shaders aren't supported - Qt: Allow passing multiple games on command line for multiplayer (closes mgba.io/i/3061) + - Qt: Support building against Qt 6 + - Qt: Add shortcuts to increment fast forward speed (mgba.io/i/2903) + - Res: Port hq2x and OmniScale shaders from SameBoy - Res: Port NSO-gba-colors shader (closes mgba.io/i/2834) + - Res: Update gba-colors shader (closes mgba.io/i/2976) - Scripting: Add `callbacks:oneshot` for single-call callbacks - Updater: Fix rewriting folders and files on Windows (fixes mgba.io/i/3384) From 7fe4f4593ed4124412dc1224404f55131a5c0238 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 20 Jan 2025 16:51:18 -0800 Subject: [PATCH 30/32] GBA Savedata: Rename flash ID constants, add missing entries --- include/mgba/internal/gba/savedata.h | 10 +++++++--- src/gba/savedata.c | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/mgba/internal/gba/savedata.h b/include/mgba/internal/gba/savedata.h index e69d07834..7fec242c4 100644 --- a/include/mgba/internal/gba/savedata.h +++ b/include/mgba/internal/gba/savedata.h @@ -45,9 +45,13 @@ enum FlashStateMachine { FLASH_STATE_CONTINUE = 2, }; -enum FlashManufacturer { - FLASH_MFG_PANASONIC = 0x1B32, - FLASH_MFG_SANYO = 0x1362 +enum FlashId { + FLASH_ATMEL_AT29LV512 = 0x3D1F, // 512k + FLASH_MACRONIX_MX29L512 = 0x1CC2, // 512k, unused + FLASH_MACRONIX_MX29L010 = 0x09C2, // 1M + FLASH_PANASONIC_MN63F805MNP = 0x1B32, // 512k, unused + FLASH_SANYO_LE26FV10N1TS = 0x1362, // 1M + FLASH_SST_39LVF512 = 0xD4BF, // 512k }; enum { diff --git a/src/gba/savedata.c b/src/gba/savedata.c index 50d2be381..13204cbb3 100644 --- a/src/gba/savedata.c +++ b/src/gba/savedata.c @@ -372,11 +372,11 @@ uint8_t GBASavedataReadFlash(struct GBASavedata* savedata, uint16_t address) { if (savedata->command == FLASH_COMMAND_ID) { if (savedata->type == GBA_SAVEDATA_FLASH512) { if (address < 2) { - return FLASH_MFG_PANASONIC >> (address * 8); + return FLASH_PANASONIC_MN63F805MNP >> (address * 8); } } else if (savedata->type == GBA_SAVEDATA_FLASH1M) { if (address < 2) { - return FLASH_MFG_SANYO >> (address * 8); + return FLASH_SANYO_LE26FV10N1TS >> (address * 8); } } } From 2dd11712db3cb8763c6b9f06b6b12ce1ffd34945 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 21 Jan 2025 00:33:20 -0800 Subject: [PATCH 31/32] Python: Fix some missing constants (fixes #3402) --- src/platform/python/mgba/gba.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/platform/python/mgba/gba.py b/src/platform/python/mgba/gba.py index 0c249cec5..91ac3254e 100644 --- a/src/platform/python/mgba/gba.py +++ b/src/platform/python/mgba/gba.py @@ -54,7 +54,7 @@ class GBA(Core): class GBAMemory(Memory): - def __init__(self, core, romSize=lib.SIZE_CART0): + def __init__(self, core, romSize=lib.GBA_SIZE_ROM0): super(GBAMemory, self).__init__(core, 0x100000000) self.bios = Memory(core, lib.GBA_SIZE_BIOS, lib.GBA_BASE_BIOS) @@ -64,11 +64,10 @@ class GBAMemory(Memory): self.palette = Memory(core, lib.GBA_SIZE_PALETTE_RAM, lib.GBA_BASE_PALETTE_RAM) self.vram = Memory(core, lib.GBA_SIZE_VRAM, lib.GBA_BASE_VRAM) self.oam = Memory(core, lib.GBA_SIZE_OAM, lib.GBA_BASE_OAM) - self.cart0 = Memory(core, romSize, lib.BASE_CART0) - self.cart1 = Memory(core, romSize, lib.BASE_CART1) - self.cart2 = Memory(core, romSize, lib.BASE_CART2) - self.cart = self.cart0 - self.rom = self.cart0 + self.rom0 = Memory(core, romSize, lib.GBA_BASE_ROM0) + self.rom1 = Memory(core, romSize, lib.GBA_BASE_ROM1) + self.rom2 = Memory(core, romSize, lib.GBA_BASE_ROM2) + self.rom = self.rom0 self.sram = Memory(core, lib.GBA_SIZE_SRAM, lib.GBA_BASE_SRAM) From 92e10f31eaadb64b96c73e0da23406c8565a0ed3 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 21 Jan 2025 00:50:34 -0800 Subject: [PATCH 32/32] Qt: Fix regression where loading BIOS creates a save file (fixes #3359) --- CHANGES | 1 + src/platform/qt/CoreController.cpp | 3 +++ src/platform/qt/CoreController.h | 2 ++ src/platform/qt/CoreManager.cpp | 1 + 4 files changed, 7 insertions(+) diff --git a/CHANGES b/CHANGES index b740f4657..a4057d775 100644 --- a/CHANGES +++ b/CHANGES @@ -32,6 +32,7 @@ Other fixes: - mGUI: Load parent directory if last used directory is missing (fixes mgba.io/i/3379) - Qt: Fix savestate preview sizes with different scales (fixes mgba.io/i/2560) - Qt: Fix potential crash when configuring shortcuts + - Qt: Fix regression where loading BIOS creates a save file (fixes mgba.io/i/3359) Misc: - Core: Handle relative paths for saves, screenshots, etc consistently (fixes mgba.io/i/2826) - Core: Improve rumble emulation by averaging state over entire frame (fixes mgba.io/i/3232) diff --git a/src/platform/qt/CoreController.cpp b/src/platform/qt/CoreController.cpp index 152efc222..53d5b3892 100644 --- a/src/platform/qt/CoreController.cpp +++ b/src/platform/qt/CoreController.cpp @@ -1267,6 +1267,9 @@ void CoreController::finishFrame() { } void CoreController::updatePlayerSave() { + if (m_saveBlocked) { + return; + } int savePlayerId = m_multiplayer->saveId(this); QString saveSuffix; diff --git a/src/platform/qt/CoreController.h b/src/platform/qt/CoreController.h index a2ebe410e..4de454d4b 100644 --- a/src/platform/qt/CoreController.h +++ b/src/platform/qt/CoreController.h @@ -176,6 +176,7 @@ public slots: void scanCards(const QStringList&); void replaceGame(const QString&); void yankPak(); + void blockSave() { m_saveBlocked = true; } void addKey(int key); void clearKey(int key); @@ -263,6 +264,7 @@ private: bool m_patched = false; bool m_preload = false; + bool m_saveBlocked = false; uint32_t m_crc32; QString m_internalTitle; diff --git a/src/platform/qt/CoreManager.cpp b/src/platform/qt/CoreManager.cpp index b2f7cabf0..385b3440b 100644 --- a/src/platform/qt/CoreManager.cpp +++ b/src/platform/qt/CoreManager.cpp @@ -169,6 +169,7 @@ CoreController* CoreManager::loadBIOS(int platform, const QString& path) { mDirectorySetAttachBase(&core->dirs, VDirOpen(bytes.constData())); CoreController* cc = new CoreController(core); + cc->blockSave(); if (m_multiplayer) { cc->setMultiplayerController(m_multiplayer); }