diff options
Diffstat (limited to 'src')
37 files changed, 408 insertions, 311 deletions
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index b81bd6167..66a9e6fba 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | 10 | ||
| 11 | #include "common/common.h" | 11 | #include "common/common.h" |
| 12 | #include "bootmanager.h" | 12 | #include "bootmanager.h" |
| 13 | #include "main.h" | ||
| 13 | 14 | ||
| 14 | #include "core/core.h" | 15 | #include "core/core.h" |
| 15 | #include "core/settings.h" | 16 | #include "core/settings.h" |
| @@ -27,43 +28,33 @@ | |||
| 27 | #define COPYRIGHT "Copyright (C) 2013-2014 Citra Team" | 28 | #define COPYRIGHT "Copyright (C) 2013-2014 Citra Team" |
| 28 | 29 | ||
| 29 | EmuThread::EmuThread(GRenderWindow* render_window) : | 30 | EmuThread::EmuThread(GRenderWindow* render_window) : |
| 30 | filename(""), exec_cpu_step(false), cpu_running(false), | 31 | exec_step(false), running(false), stop_run(false), render_window(render_window) { |
| 31 | stop_run(false), render_window(render_window) | ||
| 32 | { | ||
| 33 | } | ||
| 34 | 32 | ||
| 35 | void EmuThread::SetFilename(std::string filename) | 33 | connect(this, SIGNAL(started()), render_window, SLOT(moveContext())); |
| 36 | { | ||
| 37 | this->filename = filename; | ||
| 38 | } | 34 | } |
| 39 | 35 | ||
| 40 | void EmuThread::run() | 36 | void EmuThread::run() { |
| 41 | { | ||
| 42 | stop_run = false; | 37 | stop_run = false; |
| 43 | 38 | ||
| 44 | // holds whether the cpu was running during the last iteration, | 39 | // holds whether the cpu was running during the last iteration, |
| 45 | // so that the DebugModeLeft signal can be emitted before the | 40 | // so that the DebugModeLeft signal can be emitted before the |
| 46 | // next execution step | 41 | // next execution step |
| 47 | bool was_active = false; | 42 | bool was_active = false; |
| 48 | while (!stop_run) | 43 | while (!stop_run) { |
| 49 | { | 44 | if (running) { |
| 50 | if (cpu_running) | ||
| 51 | { | ||
| 52 | if (!was_active) | 45 | if (!was_active) |
| 53 | emit DebugModeLeft(); | 46 | emit DebugModeLeft(); |
| 54 | 47 | ||
| 55 | Core::RunLoop(); | 48 | Core::RunLoop(); |
| 56 | 49 | ||
| 57 | was_active = cpu_running || exec_cpu_step; | 50 | was_active = running || exec_step; |
| 58 | if (!was_active) | 51 | if (!was_active && !stop_run) |
| 59 | emit DebugModeEntered(); | 52 | emit DebugModeEntered(); |
| 60 | } | 53 | } else if (exec_step) { |
| 61 | else if (exec_cpu_step) | ||
| 62 | { | ||
| 63 | if (!was_active) | 54 | if (!was_active) |
| 64 | emit DebugModeLeft(); | 55 | emit DebugModeLeft(); |
| 65 | 56 | ||
| 66 | exec_cpu_step = false; | 57 | exec_step = false; |
| 67 | Core::SingleStep(); | 58 | Core::SingleStep(); |
| 68 | emit DebugModeEntered(); | 59 | emit DebugModeEntered(); |
| 69 | yieldCurrentThread(); | 60 | yieldCurrentThread(); |
| @@ -71,47 +62,10 @@ void EmuThread::run() | |||
| 71 | was_active = false; | 62 | was_active = false; |
| 72 | } | 63 | } |
| 73 | } | 64 | } |
| 74 | render_window->moveContext(); | ||
| 75 | |||
| 76 | Core::Stop(); | ||
| 77 | } | ||
| 78 | |||
| 79 | void EmuThread::Stop() | ||
| 80 | { | ||
| 81 | if (!isRunning()) | ||
| 82 | { | ||
| 83 | LOG_WARNING(Frontend, "EmuThread::Stop called while emu thread wasn't running, returning..."); | ||
| 84 | return; | ||
| 85 | } | ||
| 86 | stop_run = true; | ||
| 87 | 65 | ||
| 88 | // Release emu threads from any breakpoints, so that this doesn't hang forever. | 66 | render_window->moveContext(); |
| 89 | Pica::g_debug_context->ClearBreakpoints(); | ||
| 90 | |||
| 91 | //core::g_state = core::SYS_DIE; | ||
| 92 | |||
| 93 | // TODO: Waiting here is just a bad workaround for retarded shutdown logic. | ||
| 94 | wait(1000); | ||
| 95 | if (isRunning()) | ||
| 96 | { | ||
| 97 | LOG_WARNING(Frontend, "EmuThread still running, terminating..."); | ||
| 98 | quit(); | ||
| 99 | |||
| 100 | // TODO: Waiting 50 seconds can be necessary if the logging subsystem has a lot of spam | ||
| 101 | // queued... This should be fixed. | ||
| 102 | wait(50000); | ||
| 103 | if (isRunning()) | ||
| 104 | { | ||
| 105 | LOG_CRITICAL(Frontend, "EmuThread STILL running, something is wrong here..."); | ||
| 106 | terminate(); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | LOG_INFO(Frontend, "EmuThread stopped"); | ||
| 110 | |||
| 111 | System::Shutdown(); | ||
| 112 | } | 67 | } |
| 113 | 68 | ||
| 114 | |||
| 115 | // This class overrides paintEvent and resizeEvent to prevent the GUI thread from stealing GL context. | 69 | // This class overrides paintEvent and resizeEvent to prevent the GUI thread from stealing GL context. |
| 116 | // The corresponding functionality is handled in EmuThread instead | 70 | // The corresponding functionality is handled in EmuThread instead |
| 117 | class GGLWidgetInternal : public QGLWidget | 71 | class GGLWidgetInternal : public QGLWidget |
| @@ -133,13 +87,9 @@ private: | |||
| 133 | GRenderWindow* parent; | 87 | GRenderWindow* parent; |
| 134 | }; | 88 | }; |
| 135 | 89 | ||
| 136 | EmuThread& GRenderWindow::GetEmuThread() | 90 | GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread) : |
| 137 | { | 91 | QWidget(parent), emu_thread(emu_thread), keyboard_id(0) { |
| 138 | return emu_thread; | ||
| 139 | } | ||
| 140 | 92 | ||
| 141 | GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this), keyboard_id(0) | ||
| 142 | { | ||
| 143 | std::string window_title = Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc); | 93 | std::string window_title = Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc); |
| 144 | setWindowTitle(QString::fromStdString(window_title)); | 94 | setWindowTitle(QString::fromStdString(window_title)); |
| 145 | 95 | ||
| @@ -160,7 +110,6 @@ GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this | |||
| 160 | layout->addWidget(child); | 110 | layout->addWidget(child); |
| 161 | layout->setMargin(0); | 111 | layout->setMargin(0); |
| 162 | setLayout(layout); | 112 | setLayout(layout); |
| 163 | connect(&emu_thread, SIGNAL(started()), this, SLOT(moveContext())); | ||
| 164 | 113 | ||
| 165 | OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size); | 114 | OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size); |
| 166 | 115 | ||
| @@ -180,29 +129,17 @@ void GRenderWindow::moveContext() | |||
| 180 | // We need to move GL context to the swapping thread in Qt5 | 129 | // We need to move GL context to the swapping thread in Qt5 |
| 181 | #if QT_VERSION > QT_VERSION_CHECK(5, 0, 0) | 130 | #if QT_VERSION > QT_VERSION_CHECK(5, 0, 0) |
| 182 | // If the thread started running, move the GL Context to the new thread. Otherwise, move it back. | 131 | // If the thread started running, move the GL Context to the new thread. Otherwise, move it back. |
| 183 | child->context()->moveToThread((QThread::currentThread() == qApp->thread()) ? &emu_thread : qApp->thread()); | 132 | auto thread = (QThread::currentThread() == qApp->thread() && emu_thread != nullptr) ? emu_thread : qApp->thread(); |
| 133 | child->context()->moveToThread(thread); | ||
| 184 | #endif | 134 | #endif |
| 185 | } | 135 | } |
| 186 | 136 | ||
| 187 | GRenderWindow::~GRenderWindow() | ||
| 188 | { | ||
| 189 | if (emu_thread.isRunning()) | ||
| 190 | emu_thread.Stop(); | ||
| 191 | } | ||
| 192 | |||
| 193 | void GRenderWindow::SwapBuffers() | 137 | void GRenderWindow::SwapBuffers() |
| 194 | { | 138 | { |
| 195 | // MakeCurrent is already called in renderer_opengl | 139 | // MakeCurrent is already called in renderer_opengl |
| 196 | child->swapBuffers(); | 140 | child->swapBuffers(); |
| 197 | } | 141 | } |
| 198 | 142 | ||
| 199 | void GRenderWindow::closeEvent(QCloseEvent* event) | ||
| 200 | { | ||
| 201 | if (emu_thread.isRunning()) | ||
| 202 | emu_thread.Stop(); | ||
| 203 | QWidget::closeEvent(event); | ||
| 204 | } | ||
| 205 | |||
| 206 | void GRenderWindow::MakeCurrent() | 143 | void GRenderWindow::MakeCurrent() |
| 207 | { | 144 | { |
| 208 | child->makeCurrent(); | 145 | child->makeCurrent(); |
| @@ -335,3 +272,11 @@ void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height) | |||
| 335 | void GRenderWindow::OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) { | 272 | void GRenderWindow::OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) { |
| 336 | setMinimumSize(minimal_size.first, minimal_size.second); | 273 | setMinimumSize(minimal_size.first, minimal_size.second); |
| 337 | } | 274 | } |
| 275 | |||
| 276 | void GRenderWindow::OnEmulationStarting(EmuThread* emu_thread) { | ||
| 277 | this->emu_thread = emu_thread; | ||
| 278 | } | ||
| 279 | |||
| 280 | void GRenderWindow::OnEmulationStopping() { | ||
| 281 | emu_thread = nullptr; | ||
| 282 | } | ||
diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h index 288da45a1..715faf2d7 100644 --- a/src/citra_qt/bootmanager.h +++ b/src/citra_qt/bootmanager.h | |||
| @@ -9,72 +9,58 @@ | |||
| 9 | 9 | ||
| 10 | #include "common/common.h" | 10 | #include "common/common.h" |
| 11 | #include "common/emu_window.h" | 11 | #include "common/emu_window.h" |
| 12 | #include "common/thread.h" | ||
| 12 | 13 | ||
| 13 | class QScreen; | 14 | class QScreen; |
| 14 | class QKeyEvent; | 15 | class QKeyEvent; |
| 15 | 16 | ||
| 16 | class GRenderWindow; | 17 | class GRenderWindow; |
| 18 | class GMainWindow; | ||
| 17 | 19 | ||
| 18 | class EmuThread : public QThread | 20 | class EmuThread : public QThread |
| 19 | { | 21 | { |
| 20 | Q_OBJECT | 22 | Q_OBJECT |
| 21 | 23 | ||
| 22 | public: | 24 | public: |
| 23 | /** | 25 | EmuThread(GRenderWindow* render_window); |
| 24 | * Set image filename | ||
| 25 | * | ||
| 26 | * @param filename | ||
| 27 | * @warning Only call when not running! | ||
| 28 | */ | ||
| 29 | void SetFilename(std::string filename); | ||
| 30 | 26 | ||
| 31 | /** | 27 | /** |
| 32 | * Start emulation (on new thread) | 28 | * Start emulation (on new thread) |
| 33 | * | ||
| 34 | * @warning Only call when not running! | 29 | * @warning Only call when not running! |
| 35 | */ | 30 | */ |
| 36 | void run() override; | 31 | void run() override; |
| 37 | 32 | ||
| 38 | /** | 33 | /** |
| 39 | * Allow the CPU to process a single instruction (if cpu is not running) | 34 | * Steps the emulation thread by a single CPU instruction (if the CPU is not already running) |
| 40 | * | ||
| 41 | * @note This function is thread-safe | 35 | * @note This function is thread-safe |
| 42 | */ | 36 | */ |
| 43 | void ExecStep() { exec_cpu_step = true; } | 37 | void ExecStep() { exec_step = true; } |
| 44 | 38 | ||
| 45 | /** | 39 | /** |
| 46 | * Allow the CPU to continue processing instructions without interruption | 40 | * Sets whether the emulation thread is running or not |
| 47 | * | 41 | * @param running Boolean value, set the emulation thread to running if true |
| 48 | * @note This function is thread-safe | 42 | * @note This function is thread-safe |
| 49 | */ | 43 | */ |
| 50 | void SetCpuRunning(bool running) { cpu_running = running; } | 44 | void SetRunning(bool running) { this->running = running; } |
| 51 | 45 | ||
| 52 | /** | 46 | /** |
| 53 | * Allow the CPU to continue processing instructions without interruption | 47 | * Check if the emulation thread is running or not |
| 54 | * | 48 | * @return True if the emulation thread is running, otherwise false |
| 55 | * @note This function is thread-safe | 49 | * @note This function is thread-safe |
| 56 | */ | 50 | */ |
| 57 | bool IsCpuRunning() { return cpu_running; } | 51 | bool IsRunning() { return running; } |
| 58 | |||
| 59 | 52 | ||
| 60 | public slots: | ||
| 61 | /** | 53 | /** |
| 62 | * Stop emulation and wait for the thread to finish. | 54 | * Requests for the emulation thread to stop running |
| 63 | * | ||
| 64 | * @details: This function will wait a second for the thread to finish; if it hasn't finished until then, we'll terminate() it and wait another second, hoping that it will be terminated by then. | ||
| 65 | * @note: This function is thread-safe. | ||
| 66 | */ | 55 | */ |
| 67 | void Stop(); | 56 | void RequestStop() { |
| 57 | stop_run = true; | ||
| 58 | running = false; | ||
| 59 | }; | ||
| 68 | 60 | ||
| 69 | private: | 61 | private: |
| 70 | friend class GRenderWindow; | 62 | bool exec_step; |
| 71 | 63 | bool running; | |
| 72 | EmuThread(GRenderWindow* render_window); | ||
| 73 | |||
| 74 | std::string filename; | ||
| 75 | |||
| 76 | bool exec_cpu_step; | ||
| 77 | bool cpu_running; | ||
| 78 | std::atomic<bool> stop_run; | 64 | std::atomic<bool> stop_run; |
| 79 | 65 | ||
| 80 | GRenderWindow* render_window; | 66 | GRenderWindow* render_window; |
| @@ -100,10 +86,7 @@ class GRenderWindow : public QWidget, public EmuWindow | |||
| 100 | Q_OBJECT | 86 | Q_OBJECT |
| 101 | 87 | ||
| 102 | public: | 88 | public: |
| 103 | GRenderWindow(QWidget* parent = NULL); | 89 | GRenderWindow(QWidget* parent, EmuThread* emu_thread); |
| 104 | ~GRenderWindow(); | ||
| 105 | |||
| 106 | void closeEvent(QCloseEvent*) override; | ||
| 107 | 90 | ||
| 108 | // EmuWindow implementation | 91 | // EmuWindow implementation |
| 109 | void SwapBuffers() override; | 92 | void SwapBuffers() override; |
| @@ -116,8 +99,6 @@ public: | |||
| 116 | void restoreGeometry(const QByteArray& geometry); // overridden | 99 | void restoreGeometry(const QByteArray& geometry); // overridden |
| 117 | QByteArray saveGeometry(); // overridden | 100 | QByteArray saveGeometry(); // overridden |
| 118 | 101 | ||
| 119 | EmuThread& GetEmuThread(); | ||
| 120 | |||
| 121 | void keyPressEvent(QKeyEvent* event) override; | 102 | void keyPressEvent(QKeyEvent* event) override; |
| 122 | void keyReleaseEvent(QKeyEvent* event) override; | 103 | void keyReleaseEvent(QKeyEvent* event) override; |
| 123 | 104 | ||
| @@ -134,15 +115,18 @@ public: | |||
| 134 | public slots: | 115 | public slots: |
| 135 | void moveContext(); // overridden | 116 | void moveContext(); // overridden |
| 136 | 117 | ||
| 118 | void OnEmulationStarting(EmuThread* emu_thread); | ||
| 119 | void OnEmulationStopping(); | ||
| 120 | |||
| 137 | private: | 121 | private: |
| 138 | void OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) override; | 122 | void OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) override; |
| 139 | 123 | ||
| 140 | QGLWidget* child; | 124 | QGLWidget* child; |
| 141 | 125 | ||
| 142 | EmuThread emu_thread; | ||
| 143 | |||
| 144 | QByteArray geometry; | 126 | QByteArray geometry; |
| 145 | 127 | ||
| 146 | /// Device id of keyboard for use with KeyMap | 128 | /// Device id of keyboard for use with KeyMap |
| 147 | int keyboard_id; | 129 | int keyboard_id; |
| 130 | |||
| 131 | EmuThread* emu_thread; | ||
| 148 | }; | 132 | }; |
diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp index f620687ae..08c6b49bd 100644 --- a/src/citra_qt/debugger/disassembler.cpp +++ b/src/citra_qt/debugger/disassembler.cpp | |||
| @@ -18,8 +18,8 @@ | |||
| 18 | #include "core/arm/disassembler/arm_disasm.h" | 18 | #include "core/arm/disassembler/arm_disasm.h" |
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | DisassemblerModel::DisassemblerModel(QObject* parent) : QAbstractListModel(parent), base_address(0), code_size(0), program_counter(0), selection(QModelIndex()) { | 21 | DisassemblerModel::DisassemblerModel(QObject* parent) : |
| 22 | 22 | QAbstractListModel(parent), base_address(0), code_size(0), program_counter(0), selection(QModelIndex()) { | |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | int DisassemblerModel::columnCount(const QModelIndex& parent) const { | 25 | int DisassemblerModel::columnCount(const QModelIndex& parent) const { |
| @@ -158,34 +158,28 @@ void DisassemblerModel::SetNextInstruction(unsigned int address) { | |||
| 158 | emit dataChanged(prev_index, prev_index); | 158 | emit dataChanged(prev_index, prev_index); |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | DisassemblerWidget::DisassemblerWidget(QWidget* parent, EmuThread& emu_thread) : QDockWidget(parent), base_addr(0), emu_thread(emu_thread) | 161 | DisassemblerWidget::DisassemblerWidget(QWidget* parent, EmuThread* emu_thread) : |
| 162 | { | 162 | QDockWidget(parent), emu_thread(emu_thread), base_addr(0) { |
| 163 | disasm_ui.setupUi(this); | ||
| 164 | 163 | ||
| 165 | model = new DisassemblerModel(this); | 164 | disasm_ui.setupUi(this); |
| 166 | disasm_ui.treeView->setModel(model); | ||
| 167 | 165 | ||
| 168 | RegisterHotkey("Disassembler", "Start/Stop", QKeySequence(Qt::Key_F5), Qt::ApplicationShortcut); | 166 | RegisterHotkey("Disassembler", "Start/Stop", QKeySequence(Qt::Key_F5), Qt::ApplicationShortcut); |
| 169 | RegisterHotkey("Disassembler", "Step", QKeySequence(Qt::Key_F10), Qt::ApplicationShortcut); | 167 | RegisterHotkey("Disassembler", "Step", QKeySequence(Qt::Key_F10), Qt::ApplicationShortcut); |
| 170 | RegisterHotkey("Disassembler", "Step into", QKeySequence(Qt::Key_F11), Qt::ApplicationShortcut); | 168 | RegisterHotkey("Disassembler", "Step into", QKeySequence(Qt::Key_F11), Qt::ApplicationShortcut); |
| 171 | RegisterHotkey("Disassembler", "Set Breakpoint", QKeySequence(Qt::Key_F9), Qt::ApplicationShortcut); | 169 | RegisterHotkey("Disassembler", "Set Breakpoint", QKeySequence(Qt::Key_F9), Qt::ApplicationShortcut); |
| 172 | 170 | ||
| 173 | connect(disasm_ui.button_breakpoint, SIGNAL(clicked()), model, SLOT(OnSetOrUnsetBreakpoint())); | ||
| 174 | connect(disasm_ui.button_step, SIGNAL(clicked()), this, SLOT(OnStep())); | 171 | connect(disasm_ui.button_step, SIGNAL(clicked()), this, SLOT(OnStep())); |
| 175 | connect(disasm_ui.button_pause, SIGNAL(clicked()), this, SLOT(OnPause())); | 172 | connect(disasm_ui.button_pause, SIGNAL(clicked()), this, SLOT(OnPause())); |
| 176 | connect(disasm_ui.button_continue, SIGNAL(clicked()), this, SLOT(OnContinue())); | 173 | connect(disasm_ui.button_continue, SIGNAL(clicked()), this, SLOT(OnContinue())); |
| 177 | 174 | ||
| 178 | connect(disasm_ui.treeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), | ||
| 179 | model, SLOT(OnSelectionChanged(const QModelIndex&))); | ||
| 180 | |||
| 181 | connect(GetHotkey("Disassembler", "Start/Stop", this), SIGNAL(activated()), this, SLOT(OnToggleStartStop())); | 175 | connect(GetHotkey("Disassembler", "Start/Stop", this), SIGNAL(activated()), this, SLOT(OnToggleStartStop())); |
| 182 | connect(GetHotkey("Disassembler", "Step", this), SIGNAL(activated()), this, SLOT(OnStep())); | 176 | connect(GetHotkey("Disassembler", "Step", this), SIGNAL(activated()), this, SLOT(OnStep())); |
| 183 | connect(GetHotkey("Disassembler", "Step into", this), SIGNAL(activated()), this, SLOT(OnStepInto())); | 177 | connect(GetHotkey("Disassembler", "Step into", this), SIGNAL(activated()), this, SLOT(OnStepInto())); |
| 184 | connect(GetHotkey("Disassembler", "Set Breakpoint", this), SIGNAL(activated()), model, SLOT(OnSetOrUnsetBreakpoint())); | 178 | |
| 179 | setEnabled(false); | ||
| 185 | } | 180 | } |
| 186 | 181 | ||
| 187 | void DisassemblerWidget::Init() | 182 | void DisassemblerWidget::Init() { |
| 188 | { | ||
| 189 | model->ParseFromAddress(Core::g_app_core->GetPC()); | 183 | model->ParseFromAddress(Core::g_app_core->GetPC()); |
| 190 | 184 | ||
| 191 | disasm_ui.treeView->resizeColumnToContents(0); | 185 | disasm_ui.treeView->resizeColumnToContents(0); |
| @@ -197,25 +191,21 @@ void DisassemblerWidget::Init() | |||
| 197 | disasm_ui.treeView->selectionModel()->setCurrentIndex(model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); | 191 | disasm_ui.treeView->selectionModel()->setCurrentIndex(model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); |
| 198 | } | 192 | } |
| 199 | 193 | ||
| 200 | void DisassemblerWidget::OnContinue() | 194 | void DisassemblerWidget::OnContinue() { |
| 201 | { | 195 | emu_thread->SetRunning(true); |
| 202 | emu_thread.SetCpuRunning(true); | ||
| 203 | } | 196 | } |
| 204 | 197 | ||
| 205 | void DisassemblerWidget::OnStep() | 198 | void DisassemblerWidget::OnStep() { |
| 206 | { | ||
| 207 | OnStepInto(); // change later | 199 | OnStepInto(); // change later |
| 208 | } | 200 | } |
| 209 | 201 | ||
| 210 | void DisassemblerWidget::OnStepInto() | 202 | void DisassemblerWidget::OnStepInto() { |
| 211 | { | 203 | emu_thread->SetRunning(false); |
| 212 | emu_thread.SetCpuRunning(false); | 204 | emu_thread->ExecStep(); |
| 213 | emu_thread.ExecStep(); | ||
| 214 | } | 205 | } |
| 215 | 206 | ||
| 216 | void DisassemblerWidget::OnPause() | 207 | void DisassemblerWidget::OnPause() { |
| 217 | { | 208 | emu_thread->SetRunning(false); |
| 218 | emu_thread.SetCpuRunning(false); | ||
| 219 | 209 | ||
| 220 | // TODO: By now, the CPU might not have actually stopped... | 210 | // TODO: By now, the CPU might not have actually stopped... |
| 221 | if (Core::g_app_core) { | 211 | if (Core::g_app_core) { |
| @@ -223,17 +213,15 @@ void DisassemblerWidget::OnPause() | |||
| 223 | } | 213 | } |
| 224 | } | 214 | } |
| 225 | 215 | ||
| 226 | void DisassemblerWidget::OnToggleStartStop() | 216 | void DisassemblerWidget::OnToggleStartStop() { |
| 227 | { | 217 | emu_thread->SetRunning(!emu_thread->IsRunning()); |
| 228 | emu_thread.SetCpuRunning(!emu_thread.IsCpuRunning()); | ||
| 229 | } | 218 | } |
| 230 | 219 | ||
| 231 | void DisassemblerWidget::OnDebugModeEntered() | 220 | void DisassemblerWidget::OnDebugModeEntered() { |
| 232 | { | ||
| 233 | ARMword next_instr = Core::g_app_core->GetPC(); | 221 | ARMword next_instr = Core::g_app_core->GetPC(); |
| 234 | 222 | ||
| 235 | if (model->GetBreakPoints().IsAddressBreakPoint(next_instr)) | 223 | if (model->GetBreakPoints().IsAddressBreakPoint(next_instr)) |
| 236 | emu_thread.SetCpuRunning(false); | 224 | emu_thread->SetRunning(false); |
| 237 | 225 | ||
| 238 | model->SetNextInstruction(next_instr); | 226 | model->SetNextInstruction(next_instr); |
| 239 | 227 | ||
| @@ -242,16 +230,35 @@ void DisassemblerWidget::OnDebugModeEntered() | |||
| 242 | disasm_ui.treeView->selectionModel()->setCurrentIndex(model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); | 230 | disasm_ui.treeView->selectionModel()->setCurrentIndex(model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); |
| 243 | } | 231 | } |
| 244 | 232 | ||
| 245 | void DisassemblerWidget::OnDebugModeLeft() | 233 | void DisassemblerWidget::OnDebugModeLeft() { |
| 246 | { | ||
| 247 | |||
| 248 | } | 234 | } |
| 249 | 235 | ||
| 250 | int DisassemblerWidget::SelectedRow() | 236 | int DisassemblerWidget::SelectedRow() { |
| 251 | { | ||
| 252 | QModelIndex index = disasm_ui.treeView->selectionModel()->currentIndex(); | 237 | QModelIndex index = disasm_ui.treeView->selectionModel()->currentIndex(); |
| 253 | if (!index.isValid()) | 238 | if (!index.isValid()) |
| 254 | return -1; | 239 | return -1; |
| 255 | 240 | ||
| 256 | return disasm_ui.treeView->selectionModel()->currentIndex().row(); | 241 | return disasm_ui.treeView->selectionModel()->currentIndex().row(); |
| 257 | } | 242 | } |
| 243 | |||
| 244 | void DisassemblerWidget::OnEmulationStarting(EmuThread* emu_thread) { | ||
| 245 | this->emu_thread = emu_thread; | ||
| 246 | |||
| 247 | model = new DisassemblerModel(this); | ||
| 248 | disasm_ui.treeView->setModel(model); | ||
| 249 | |||
| 250 | connect(disasm_ui.treeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), | ||
| 251 | model, SLOT(OnSelectionChanged(const QModelIndex&))); | ||
| 252 | connect(disasm_ui.button_breakpoint, SIGNAL(clicked()), model, SLOT(OnSetOrUnsetBreakpoint())); | ||
| 253 | connect(GetHotkey("Disassembler", "Set Breakpoint", this), SIGNAL(activated()), model, SLOT(OnSetOrUnsetBreakpoint())); | ||
| 254 | |||
| 255 | Init(); | ||
| 256 | setEnabled(true); | ||
| 257 | } | ||
| 258 | |||
| 259 | void DisassemblerWidget::OnEmulationStopping() { | ||
| 260 | disasm_ui.treeView->setModel(nullptr); | ||
| 261 | delete model; | ||
| 262 | emu_thread = nullptr; | ||
| 263 | setEnabled(false); | ||
| 264 | } | ||
diff --git a/src/citra_qt/debugger/disassembler.h b/src/citra_qt/debugger/disassembler.h index 5e19d7c51..45b0a7e08 100644 --- a/src/citra_qt/debugger/disassembler.h +++ b/src/citra_qt/debugger/disassembler.h | |||
| @@ -51,7 +51,7 @@ class DisassemblerWidget : public QDockWidget | |||
| 51 | Q_OBJECT | 51 | Q_OBJECT |
| 52 | 52 | ||
| 53 | public: | 53 | public: |
| 54 | DisassemblerWidget(QWidget* parent, EmuThread& emu_thread); | 54 | DisassemblerWidget(QWidget* parent, EmuThread* emu_thread); |
| 55 | 55 | ||
| 56 | void Init(); | 56 | void Init(); |
| 57 | 57 | ||
| @@ -65,6 +65,9 @@ public slots: | |||
| 65 | void OnDebugModeEntered(); | 65 | void OnDebugModeEntered(); |
| 66 | void OnDebugModeLeft(); | 66 | void OnDebugModeLeft(); |
| 67 | 67 | ||
| 68 | void OnEmulationStarting(EmuThread* emu_thread); | ||
| 69 | void OnEmulationStopping(); | ||
| 70 | |||
| 68 | private: | 71 | private: |
| 69 | // returns -1 if no row is selected | 72 | // returns -1 if no row is selected |
| 70 | int SelectedRow(); | 73 | int SelectedRow(); |
| @@ -75,5 +78,5 @@ private: | |||
| 75 | 78 | ||
| 76 | u32 base_addr; | 79 | u32 base_addr; |
| 77 | 80 | ||
| 78 | EmuThread& emu_thread; | 81 | EmuThread* emu_thread; |
| 79 | }; | 82 | }; |
diff --git a/src/citra_qt/debugger/registers.cpp b/src/citra_qt/debugger/registers.cpp index ab3666156..5527a2afd 100644 --- a/src/citra_qt/debugger/registers.cpp +++ b/src/citra_qt/debugger/registers.cpp | |||
| @@ -7,8 +7,7 @@ | |||
| 7 | #include "core/core.h" | 7 | #include "core/core.h" |
| 8 | #include "core/arm/arm_interface.h" | 8 | #include "core/arm/arm_interface.h" |
| 9 | 9 | ||
| 10 | RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent) | 10 | RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent) { |
| 11 | { | ||
| 12 | cpu_regs_ui.setupUi(this); | 11 | cpu_regs_ui.setupUi(this); |
| 13 | 12 | ||
| 14 | tree = cpu_regs_ui.treeWidget; | 13 | tree = cpu_regs_ui.treeWidget; |
| @@ -18,8 +17,7 @@ RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent) | |||
| 18 | registers->setExpanded(true); | 17 | registers->setExpanded(true); |
| 19 | CSPR->setExpanded(true); | 18 | CSPR->setExpanded(true); |
| 20 | 19 | ||
| 21 | for (int i = 0; i < 16; ++i) | 20 | for (int i = 0; i < 16; ++i) { |
| 22 | { | ||
| 23 | QTreeWidgetItem* child = new QTreeWidgetItem(QStringList(QString("R[%1]").arg(i, 2, 10, QLatin1Char('0')))); | 21 | QTreeWidgetItem* child = new QTreeWidgetItem(QStringList(QString("R[%1]").arg(i, 2, 10, QLatin1Char('0')))); |
| 24 | registers->addChild(child); | 22 | registers->addChild(child); |
| 25 | } | 23 | } |
| @@ -39,12 +37,16 @@ RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent) | |||
| 39 | CSPR->addChild(new QTreeWidgetItem(QStringList("C"))); | 37 | CSPR->addChild(new QTreeWidgetItem(QStringList("C"))); |
| 40 | CSPR->addChild(new QTreeWidgetItem(QStringList("Z"))); | 38 | CSPR->addChild(new QTreeWidgetItem(QStringList("Z"))); |
| 41 | CSPR->addChild(new QTreeWidgetItem(QStringList("N"))); | 39 | CSPR->addChild(new QTreeWidgetItem(QStringList("N"))); |
| 40 | |||
| 41 | setEnabled(false); | ||
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | void RegistersWidget::OnDebugModeEntered() | 44 | void RegistersWidget::OnDebugModeEntered() { |
| 45 | { | ||
| 46 | ARM_Interface* app_core = Core::g_app_core; | 45 | ARM_Interface* app_core = Core::g_app_core; |
| 47 | 46 | ||
| 47 | if (app_core == nullptr) | ||
| 48 | return; | ||
| 49 | |||
| 48 | for (int i = 0; i < 16; ++i) | 50 | for (int i = 0; i < 16; ++i) |
| 49 | registers->child(i)->setText(1, QString("0x%1").arg(app_core->GetReg(i), 8, 16, QLatin1Char('0'))); | 51 | registers->child(i)->setText(1, QString("0x%1").arg(app_core->GetReg(i), 8, 16, QLatin1Char('0'))); |
| 50 | 52 | ||
| @@ -66,7 +68,22 @@ void RegistersWidget::OnDebugModeEntered() | |||
| 66 | CSPR->child(14)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 31) & 0x1)); // N - Negative/Less than | 68 | CSPR->child(14)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 31) & 0x1)); // N - Negative/Less than |
| 67 | } | 69 | } |
| 68 | 70 | ||
| 69 | void RegistersWidget::OnDebugModeLeft() | 71 | void RegistersWidget::OnDebugModeLeft() { |
| 70 | { | 72 | } |
| 73 | |||
| 74 | void RegistersWidget::OnEmulationStarting(EmuThread* emu_thread) { | ||
| 75 | setEnabled(true); | ||
| 76 | } | ||
| 77 | |||
| 78 | void RegistersWidget::OnEmulationStopping() { | ||
| 79 | // Reset widget text | ||
| 80 | for (int i = 0; i < 16; ++i) | ||
| 81 | registers->child(i)->setText(1, QString("")); | ||
| 82 | |||
| 83 | for (int i = 0; i < 15; ++i) | ||
| 84 | CSPR->child(i)->setText(1, QString("")); | ||
| 85 | |||
| 86 | CSPR->setText(1, QString("")); | ||
| 71 | 87 | ||
| 88 | setEnabled(false); | ||
| 72 | } | 89 | } |
diff --git a/src/citra_qt/debugger/registers.h b/src/citra_qt/debugger/registers.h index bf8955625..68e3fb908 100644 --- a/src/citra_qt/debugger/registers.h +++ b/src/citra_qt/debugger/registers.h | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <QTreeWidgetItem> | 8 | #include <QTreeWidgetItem> |
| 9 | 9 | ||
| 10 | class QTreeWidget; | 10 | class QTreeWidget; |
| 11 | class EmuThread; | ||
| 11 | 12 | ||
| 12 | class RegistersWidget : public QDockWidget | 13 | class RegistersWidget : public QDockWidget |
| 13 | { | 14 | { |
| @@ -20,6 +21,9 @@ public slots: | |||
| 20 | void OnDebugModeEntered(); | 21 | void OnDebugModeEntered(); |
| 21 | void OnDebugModeLeft(); | 22 | void OnDebugModeLeft(); |
| 22 | 23 | ||
| 24 | void OnEmulationStarting(EmuThread* emu_thread); | ||
| 25 | void OnEmulationStopping(); | ||
| 26 | |||
| 23 | private: | 27 | private: |
| 24 | Ui::ARMRegisters cpu_regs_ui; | 28 | Ui::ARMRegisters cpu_regs_ui; |
| 25 | 29 | ||
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index e5ca04124..dd0e4de8f 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include "common/logging/log.h" | 15 | #include "common/logging/log.h" |
| 16 | #include "common/logging/backend.h" | 16 | #include "common/logging/backend.h" |
| 17 | #include "common/logging/filter.h" | 17 | #include "common/logging/filter.h" |
| 18 | #include "common/make_unique.h" | ||
| 18 | #include "common/platform.h" | 19 | #include "common/platform.h" |
| 19 | #include "common/scope_exit.h" | 20 | #include "common/scope_exit.h" |
| 20 | 21 | ||
| @@ -46,7 +47,7 @@ | |||
| 46 | 47 | ||
| 47 | #include "version.h" | 48 | #include "version.h" |
| 48 | 49 | ||
| 49 | GMainWindow::GMainWindow() | 50 | GMainWindow::GMainWindow() : emu_thread(nullptr) |
| 50 | { | 51 | { |
| 51 | Pica::g_debug_context = Pica::DebugContext::Construct(); | 52 | Pica::g_debug_context = Pica::DebugContext::Construct(); |
| 52 | 53 | ||
| @@ -55,14 +56,14 @@ GMainWindow::GMainWindow() | |||
| 55 | ui.setupUi(this); | 56 | ui.setupUi(this); |
| 56 | statusBar()->hide(); | 57 | statusBar()->hide(); |
| 57 | 58 | ||
| 58 | render_window = new GRenderWindow; | 59 | render_window = new GRenderWindow(this, emu_thread.get()); |
| 59 | render_window->hide(); | 60 | render_window->hide(); |
| 60 | 61 | ||
| 61 | profilerWidget = new ProfilerWidget(this); | 62 | profilerWidget = new ProfilerWidget(this); |
| 62 | addDockWidget(Qt::BottomDockWidgetArea, profilerWidget); | 63 | addDockWidget(Qt::BottomDockWidgetArea, profilerWidget); |
| 63 | profilerWidget->hide(); | 64 | profilerWidget->hide(); |
| 64 | 65 | ||
| 65 | disasmWidget = new DisassemblerWidget(this, render_window->GetEmuThread()); | 66 | disasmWidget = new DisassemblerWidget(this, emu_thread.get()); |
| 66 | addDockWidget(Qt::BottomDockWidgetArea, disasmWidget); | 67 | addDockWidget(Qt::BottomDockWidgetArea, disasmWidget); |
| 67 | disasmWidget->hide(); | 68 | disasmWidget->hide(); |
| 68 | 69 | ||
| @@ -138,14 +139,12 @@ GMainWindow::GMainWindow() | |||
| 138 | connect(ui.action_Single_Window_Mode, SIGNAL(triggered(bool)), this, SLOT(ToggleWindowMode())); | 139 | connect(ui.action_Single_Window_Mode, SIGNAL(triggered(bool)), this, SLOT(ToggleWindowMode())); |
| 139 | connect(ui.action_Hotkeys, SIGNAL(triggered()), this, SLOT(OnOpenHotkeysDialog())); | 140 | connect(ui.action_Hotkeys, SIGNAL(triggered()), this, SLOT(OnOpenHotkeysDialog())); |
| 140 | 141 | ||
| 141 | // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views before the CPU continues | 142 | connect(this, SIGNAL(EmulationStarting(EmuThread*)), disasmWidget, SLOT(OnEmulationStarting(EmuThread*))); |
| 142 | connect(&render_window->GetEmuThread(), SIGNAL(DebugModeEntered()), disasmWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection); | 143 | connect(this, SIGNAL(EmulationStopping()), disasmWidget, SLOT(OnEmulationStopping())); |
| 143 | connect(&render_window->GetEmuThread(), SIGNAL(DebugModeEntered()), registersWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection); | 144 | connect(this, SIGNAL(EmulationStarting(EmuThread*)), registersWidget, SLOT(OnEmulationStarting(EmuThread*))); |
| 144 | connect(&render_window->GetEmuThread(), SIGNAL(DebugModeEntered()), callstackWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection); | 145 | connect(this, SIGNAL(EmulationStopping()), registersWidget, SLOT(OnEmulationStopping())); |
| 145 | 146 | connect(this, SIGNAL(EmulationStarting(EmuThread*)), render_window, SLOT(OnEmulationStarting(EmuThread*))); | |
| 146 | connect(&render_window->GetEmuThread(), SIGNAL(DebugModeLeft()), disasmWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection); | 147 | connect(this, SIGNAL(EmulationStopping()), render_window, SLOT(OnEmulationStopping())); |
| 147 | connect(&render_window->GetEmuThread(), SIGNAL(DebugModeLeft()), registersWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection); | ||
| 148 | connect(&render_window->GetEmuThread(), SIGNAL(DebugModeLeft()), callstackWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection); | ||
| 149 | 148 | ||
| 150 | // Setup hotkeys | 149 | // Setup hotkeys |
| 151 | RegisterHotkey("Main Window", "Load File", QKeySequence::Open); | 150 | RegisterHotkey("Main Window", "Load File", QKeySequence::Open); |
| @@ -196,32 +195,76 @@ void GMainWindow::OnDisplayTitleBars(bool show) | |||
| 196 | } | 195 | } |
| 197 | } | 196 | } |
| 198 | 197 | ||
| 199 | void GMainWindow::BootGame(std::string filename) | 198 | void GMainWindow::BootGame(std::string filename) { |
| 200 | { | ||
| 201 | LOG_INFO(Frontend, "Citra starting...\n"); | 199 | LOG_INFO(Frontend, "Citra starting...\n"); |
| 200 | |||
| 201 | // Initialize the core emulation | ||
| 202 | System::Init(render_window); | 202 | System::Init(render_window); |
| 203 | 203 | ||
| 204 | // Load a game or die... | 204 | // Load the game |
| 205 | if (Loader::ResultStatus::Success != Loader::LoadFile(filename)) { | 205 | if (Loader::ResultStatus::Success != Loader::LoadFile(filename)) { |
| 206 | LOG_CRITICAL(Frontend, "Failed to load ROM!"); | 206 | LOG_CRITICAL(Frontend, "Failed to load ROM!"); |
| 207 | System::Shutdown(); | ||
| 208 | return; | ||
| 207 | } | 209 | } |
| 208 | 210 | ||
| 209 | disasmWidget->Init(); | 211 | // Create and start the emulation thread |
| 212 | emu_thread = Common::make_unique<EmuThread>(render_window); | ||
| 213 | emit EmulationStarting(emu_thread.get()); | ||
| 214 | emu_thread->start(); | ||
| 215 | |||
| 216 | // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views before the CPU continues | ||
| 217 | connect(emu_thread.get(), SIGNAL(DebugModeEntered()), disasmWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection); | ||
| 218 | connect(emu_thread.get(), SIGNAL(DebugModeEntered()), registersWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection); | ||
| 219 | connect(emu_thread.get(), SIGNAL(DebugModeEntered()), callstackWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection); | ||
| 220 | connect(emu_thread.get(), SIGNAL(DebugModeLeft()), disasmWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection); | ||
| 221 | connect(emu_thread.get(), SIGNAL(DebugModeLeft()), registersWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection); | ||
| 222 | connect(emu_thread.get(), SIGNAL(DebugModeLeft()), callstackWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection); | ||
| 223 | |||
| 224 | // Update the GUI | ||
| 210 | registersWidget->OnDebugModeEntered(); | 225 | registersWidget->OnDebugModeEntered(); |
| 211 | callstackWidget->OnDebugModeEntered(); | 226 | callstackWidget->OnDebugModeEntered(); |
| 212 | |||
| 213 | render_window->GetEmuThread().SetFilename(filename); | ||
| 214 | render_window->GetEmuThread().start(); | ||
| 215 | |||
| 216 | render_window->show(); | 227 | render_window->show(); |
| 228 | |||
| 217 | OnStartGame(); | 229 | OnStartGame(); |
| 218 | } | 230 | } |
| 219 | 231 | ||
| 232 | void GMainWindow::ShutdownGame() { | ||
| 233 | emu_thread->RequestStop(); | ||
| 234 | |||
| 235 | // Release emu threads from any breakpoints | ||
| 236 | // This belongs after RequestStop() and before wait() because if emulation stops on a GPU | ||
| 237 | // breakpoint after (or before) RequestStop() is called, the emulation would never be able | ||
| 238 | // to continue out to the main loop and terminate. Thus wait() would hang forever. | ||
| 239 | // TODO(bunnei): This function is not thread safe, but it's being used as if it were | ||
| 240 | Pica::g_debug_context->ClearBreakpoints(); | ||
| 241 | |||
| 242 | emit EmulationStopping(); | ||
| 243 | |||
| 244 | // Wait for emulation thread to complete and delete it | ||
| 245 | emu_thread->wait(); | ||
| 246 | emu_thread = nullptr; | ||
| 247 | |||
| 248 | // Shutdown the core emulation | ||
| 249 | System::Shutdown(); | ||
| 250 | |||
| 251 | // Update the GUI | ||
| 252 | ui.action_Start->setEnabled(false); | ||
| 253 | ui.action_Pause->setEnabled(false); | ||
| 254 | ui.action_Stop->setEnabled(false); | ||
| 255 | render_window->hide(); | ||
| 256 | } | ||
| 257 | |||
| 220 | void GMainWindow::OnMenuLoadFile() | 258 | void GMainWindow::OnMenuLoadFile() |
| 221 | { | 259 | { |
| 222 | QString filename = QFileDialog::getOpenFileName(this, tr("Load File"), QString(), tr("3DS executable (*.3ds *.3dsx *.elf *.axf *.bin *.cci *.cxi)")); | 260 | QString filename = QFileDialog::getOpenFileName(this, tr("Load File"), QString(), tr("3DS executable (*.3ds *.3dsx *.elf *.axf *.bin *.cci *.cxi)")); |
| 223 | if (filename.size()) | 261 | if (filename.size()) { |
| 224 | BootGame(filename.toLatin1().data()); | 262 | // Shutdown previous session if the emu thread is still active... |
| 263 | if (emu_thread != nullptr) | ||
| 264 | ShutdownGame(); | ||
| 265 | |||
| 266 | BootGame(filename.toLatin1().data()); | ||
| 267 | } | ||
| 225 | } | 268 | } |
| 226 | 269 | ||
| 227 | void GMainWindow::OnMenuLoadSymbolMap() { | 270 | void GMainWindow::OnMenuLoadSymbolMap() { |
| @@ -232,7 +275,7 @@ void GMainWindow::OnMenuLoadSymbolMap() { | |||
| 232 | 275 | ||
| 233 | void GMainWindow::OnStartGame() | 276 | void GMainWindow::OnStartGame() |
| 234 | { | 277 | { |
| 235 | render_window->GetEmuThread().SetCpuRunning(true); | 278 | emu_thread->SetRunning(true); |
| 236 | 279 | ||
| 237 | ui.action_Start->setEnabled(false); | 280 | ui.action_Start->setEnabled(false); |
| 238 | ui.action_Pause->setEnabled(true); | 281 | ui.action_Pause->setEnabled(true); |
| @@ -241,21 +284,15 @@ void GMainWindow::OnStartGame() | |||
| 241 | 284 | ||
| 242 | void GMainWindow::OnPauseGame() | 285 | void GMainWindow::OnPauseGame() |
| 243 | { | 286 | { |
| 244 | render_window->GetEmuThread().SetCpuRunning(false); | 287 | emu_thread->SetRunning(false); |
| 245 | 288 | ||
| 246 | ui.action_Start->setEnabled(true); | 289 | ui.action_Start->setEnabled(true); |
| 247 | ui.action_Pause->setEnabled(false); | 290 | ui.action_Pause->setEnabled(false); |
| 248 | ui.action_Stop->setEnabled(true); | 291 | ui.action_Stop->setEnabled(true); |
| 249 | } | 292 | } |
| 250 | 293 | ||
| 251 | void GMainWindow::OnStopGame() | 294 | void GMainWindow::OnStopGame() { |
| 252 | { | 295 | ShutdownGame(); |
| 253 | render_window->GetEmuThread().SetCpuRunning(false); | ||
| 254 | // TODO: Shutdown core | ||
| 255 | |||
| 256 | ui.action_Start->setEnabled(true); | ||
| 257 | ui.action_Pause->setEnabled(false); | ||
| 258 | ui.action_Stop->setEnabled(false); | ||
| 259 | } | 296 | } |
| 260 | 297 | ||
| 261 | void GMainWindow::OnOpenHotkeysDialog() | 298 | void GMainWindow::OnOpenHotkeysDialog() |
| @@ -265,24 +302,22 @@ void GMainWindow::OnOpenHotkeysDialog() | |||
| 265 | } | 302 | } |
| 266 | 303 | ||
| 267 | 304 | ||
| 268 | void GMainWindow::ToggleWindowMode() | 305 | void GMainWindow::ToggleWindowMode() { |
| 269 | { | 306 | if (ui.action_Single_Window_Mode->isChecked()) { |
| 270 | bool enable = ui.action_Single_Window_Mode->isChecked(); | 307 | // Render in the main window... |
| 271 | if (!enable && render_window->parent() != nullptr) | ||
| 272 | { | ||
| 273 | ui.horizontalLayout->removeWidget(render_window); | ||
| 274 | render_window->setParent(nullptr); | ||
| 275 | render_window->setVisible(true); | ||
| 276 | render_window->RestoreGeometry(); | ||
| 277 | render_window->setFocusPolicy(Qt::NoFocus); | ||
| 278 | } | ||
| 279 | else if (enable && render_window->parent() == nullptr) | ||
| 280 | { | ||
| 281 | render_window->BackupGeometry(); | 308 | render_window->BackupGeometry(); |
| 282 | ui.horizontalLayout->addWidget(render_window); | 309 | ui.horizontalLayout->addWidget(render_window); |
| 283 | render_window->setVisible(true); | 310 | render_window->setVisible(true); |
| 284 | render_window->setFocusPolicy(Qt::ClickFocus); | 311 | render_window->setFocusPolicy(Qt::ClickFocus); |
| 285 | render_window->setFocus(); | 312 | render_window->setFocus(); |
| 313 | |||
| 314 | } else { | ||
| 315 | // Render in a separate window... | ||
| 316 | ui.horizontalLayout->removeWidget(render_window); | ||
| 317 | render_window->setParent(nullptr); | ||
| 318 | render_window->setVisible(true); | ||
| 319 | render_window->RestoreGeometry(); | ||
| 320 | render_window->setFocusPolicy(Qt::NoFocus); | ||
| 286 | } | 321 | } |
| 287 | } | 322 | } |
| 288 | 323 | ||
| @@ -303,6 +338,8 @@ void GMainWindow::closeEvent(QCloseEvent* event) | |||
| 303 | settings.setValue("firstStart", false); | 338 | settings.setValue("firstStart", false); |
| 304 | SaveHotkeys(settings); | 339 | SaveHotkeys(settings); |
| 305 | 340 | ||
| 341 | ShutdownGame(); | ||
| 342 | |||
| 306 | render_window->close(); | 343 | render_window->close(); |
| 307 | 344 | ||
| 308 | QWidget::closeEvent(event); | 345 | QWidget::closeEvent(event); |
diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h index 9b57c5772..3e29534fb 100644 --- a/src/citra_qt/main.h +++ b/src/citra_qt/main.h | |||
| @@ -5,12 +5,14 @@ | |||
| 5 | #ifndef _CITRA_QT_MAIN_HXX_ | 5 | #ifndef _CITRA_QT_MAIN_HXX_ |
| 6 | #define _CITRA_QT_MAIN_HXX_ | 6 | #define _CITRA_QT_MAIN_HXX_ |
| 7 | 7 | ||
| 8 | #include <memory> | ||
| 8 | #include <QMainWindow> | 9 | #include <QMainWindow> |
| 9 | 10 | ||
| 10 | #include "ui_main.h" | 11 | #include "ui_main.h" |
| 11 | 12 | ||
| 12 | class GImageInfo; | 13 | class GImageInfo; |
| 13 | class GRenderWindow; | 14 | class GRenderWindow; |
| 15 | class EmuThread; | ||
| 14 | class ProfilerWidget; | 16 | class ProfilerWidget; |
| 15 | class DisassemblerWidget; | 17 | class DisassemblerWidget; |
| 16 | class RegistersWidget; | 18 | class RegistersWidget; |
| @@ -34,8 +36,27 @@ public: | |||
| 34 | GMainWindow(); | 36 | GMainWindow(); |
| 35 | ~GMainWindow(); | 37 | ~GMainWindow(); |
| 36 | 38 | ||
| 39 | signals: | ||
| 40 | |||
| 41 | /** | ||
| 42 | * Signal that is emitted when a new EmuThread has been created and an emulation session is | ||
| 43 | * about to start. At this time, the core system emulation has been initialized, and all | ||
| 44 | * emulation handles and memory should be valid. | ||
| 45 | * | ||
| 46 | * @param emu_thread Pointer to the newly created EmuThread (to be used by widgets that need to | ||
| 47 | * access/change emulation state). | ||
| 48 | */ | ||
| 49 | void EmulationStarting(EmuThread* emu_thread); | ||
| 50 | |||
| 51 | /** | ||
| 52 | * Signal that is emitted when emulation is about to stop. At this time, the EmuThread and core | ||
| 53 | * system emulation handles and memory are still valid, but are about become invalid. | ||
| 54 | */ | ||
| 55 | void EmulationStopping(); | ||
| 56 | |||
| 37 | private: | 57 | private: |
| 38 | void BootGame(std::string filename); | 58 | void BootGame(std::string filename); |
| 59 | void ShutdownGame(); | ||
| 39 | 60 | ||
| 40 | void closeEvent(QCloseEvent* event) override; | 61 | void closeEvent(QCloseEvent* event) override; |
| 41 | 62 | ||
| @@ -55,6 +76,8 @@ private: | |||
| 55 | 76 | ||
| 56 | GRenderWindow* render_window; | 77 | GRenderWindow* render_window; |
| 57 | 78 | ||
| 79 | std::unique_ptr<EmuThread> emu_thread; | ||
| 80 | |||
| 58 | ProfilerWidget* profilerWidget; | 81 | ProfilerWidget* profilerWidget; |
| 59 | DisassemblerWidget* disasmWidget; | 82 | DisassemblerWidget* disasmWidget; |
| 60 | RegistersWidget* registersWidget; | 83 | RegistersWidget* registersWidget; |
diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui index a3752ac1e..689806465 100644 --- a/src/citra_qt/main.ui +++ b/src/citra_qt/main.ui | |||
| @@ -90,6 +90,9 @@ | |||
| 90 | </property> | 90 | </property> |
| 91 | </action> | 91 | </action> |
| 92 | <action name="action_Start"> | 92 | <action name="action_Start"> |
| 93 | <property name="enabled"> | ||
| 94 | <bool>false</bool> | ||
| 95 | </property> | ||
| 93 | <property name="text"> | 96 | <property name="text"> |
| 94 | <string>&Start</string> | 97 | <string>&Start</string> |
| 95 | </property> | 98 | </property> |
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp index bc1e969e4..128413262 100644 --- a/src/core/arm/dyncom/arm_dyncom.cpp +++ b/src/core/arm/dyncom/arm_dyncom.cpp | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/make_unique.h" | ||
| 6 | |||
| 5 | #include "core/arm/skyeye_common/armemu.h" | 7 | #include "core/arm/skyeye_common/armemu.h" |
| 6 | #include "core/arm/skyeye_common/vfp/vfp.h" | 8 | #include "core/arm/skyeye_common/vfp/vfp.h" |
| 7 | 9 | ||
| @@ -17,7 +19,7 @@ const static cpu_config_t s_arm11_cpu_info = { | |||
| 17 | }; | 19 | }; |
| 18 | 20 | ||
| 19 | ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) { | 21 | ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) { |
| 20 | state = std::unique_ptr<ARMul_State>(new ARMul_State); | 22 | state = Common::make_unique<ARMul_State>(); |
| 21 | 23 | ||
| 22 | ARMul_NewState(state.get()); | 24 | ARMul_NewState(state.get()); |
| 23 | ARMul_SelectProcessor(state.get(), ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop); | 25 | ARMul_SelectProcessor(state.get(), ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop); |
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index fde11e4ff..991da740b 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp | |||
| @@ -6,7 +6,6 @@ | |||
| 6 | 6 | ||
| 7 | #include <algorithm> | 7 | #include <algorithm> |
| 8 | #include <cstdio> | 8 | #include <cstdio> |
| 9 | #include <unordered_map> | ||
| 10 | 9 | ||
| 11 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| 12 | #include "common/profiler.h" | 11 | #include "common/profiler.h" |
| @@ -3533,25 +3532,6 @@ const transop_fp_t arm_instruction_trans[] = { | |||
| 3533 | INTERPRETER_TRANSLATE(blx_1_thumb) | 3532 | INTERPRETER_TRANSLATE(blx_1_thumb) |
| 3534 | }; | 3533 | }; |
| 3535 | 3534 | ||
| 3536 | typedef std::unordered_map<u32, int> bb_map; | ||
| 3537 | static bb_map CreamCache; | ||
| 3538 | |||
| 3539 | static void insert_bb(unsigned int addr, int start) { | ||
| 3540 | CreamCache[addr] = start; | ||
| 3541 | } | ||
| 3542 | |||
| 3543 | static int find_bb(unsigned int addr, int& start) { | ||
| 3544 | int ret = -1; | ||
| 3545 | bb_map::const_iterator it = CreamCache.find(addr); | ||
| 3546 | if (it != CreamCache.end()) { | ||
| 3547 | start = static_cast<int>(it->second); | ||
| 3548 | ret = 0; | ||
| 3549 | } else { | ||
| 3550 | ret = -1; | ||
| 3551 | } | ||
| 3552 | return ret; | ||
| 3553 | } | ||
| 3554 | |||
| 3555 | enum { | 3535 | enum { |
| 3556 | FETCH_SUCCESS, | 3536 | FETCH_SUCCESS, |
| 3557 | FETCH_FAILURE | 3537 | FETCH_FAILURE |
| @@ -3674,7 +3654,9 @@ translated: | |||
| 3674 | } | 3654 | } |
| 3675 | ret = inst_base->br; | 3655 | ret = inst_base->br; |
| 3676 | }; | 3656 | }; |
| 3677 | insert_bb(pc_start, bb_start); | 3657 | |
| 3658 | cpu->instruction_cache[pc_start] = bb_start; | ||
| 3659 | |||
| 3678 | return KEEP_GOING; | 3660 | return KEEP_GOING; |
| 3679 | } | 3661 | } |
| 3680 | 3662 | ||
| @@ -4001,9 +3983,14 @@ unsigned InterpreterMainLoop(ARMul_State* state) { | |||
| 4001 | 3983 | ||
| 4002 | phys_addr = cpu->Reg[15]; | 3984 | phys_addr = cpu->Reg[15]; |
| 4003 | 3985 | ||
| 4004 | if (find_bb(cpu->Reg[15], ptr) == -1) | 3986 | // Find the cached instruction cream, otherwise translate it... |
| 3987 | auto itr = cpu->instruction_cache.find(cpu->Reg[15]); | ||
| 3988 | if (itr != cpu->instruction_cache.end()) { | ||
| 3989 | ptr = itr->second; | ||
| 3990 | } else { | ||
| 4005 | if (InterpreterTranslate(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION) | 3991 | if (InterpreterTranslate(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION) |
| 4006 | goto END; | 3992 | goto END; |
| 3993 | } | ||
| 4007 | 3994 | ||
| 4008 | inst_base = (arm_inst *)&inst_buf[ptr]; | 3995 | inst_base = (arm_inst *)&inst_buf[ptr]; |
| 4009 | GOTO_NEXT_INST; | 3996 | GOTO_NEXT_INST; |
diff --git a/src/core/arm/interpreter/arminit.cpp b/src/core/arm/interpreter/arminit.cpp index 6ac45c396..31b2bab06 100644 --- a/src/core/arm/interpreter/arminit.cpp +++ b/src/core/arm/interpreter/arminit.cpp | |||
| @@ -26,8 +26,6 @@ | |||
| 26 | \***************************************************************************/ | 26 | \***************************************************************************/ |
| 27 | ARMul_State* ARMul_NewState(ARMul_State* state) | 27 | ARMul_State* ARMul_NewState(ARMul_State* state) |
| 28 | { | 28 | { |
| 29 | memset(state, 0, sizeof(ARMul_State)); | ||
| 30 | |||
| 31 | state->Emulate = RUN; | 29 | state->Emulate = RUN; |
| 32 | state->Mode = USER32MODE; | 30 | state->Mode = USER32MODE; |
| 33 | 31 | ||
diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h index 08da6d9eb..85d523bc2 100644 --- a/src/core/arm/skyeye_common/armdefs.h +++ b/src/core/arm/skyeye_common/armdefs.h | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | 17 | ||
| 18 | #pragma once | 18 | #pragma once |
| 19 | 19 | ||
| 20 | #include <unordered_map> | ||
| 21 | |||
| 20 | #include "common/common_types.h" | 22 | #include "common/common_types.h" |
| 21 | #include "core/arm/skyeye_common/arm_regformat.h" | 23 | #include "core/arm/skyeye_common/arm_regformat.h" |
| 22 | #include "core/arm/skyeye_common/skyeye_defs.h" | 24 | #include "core/arm/skyeye_common/skyeye_defs.h" |
| @@ -152,6 +154,10 @@ So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model) | |||
| 152 | 154 | ||
| 153 | // Added by ksh in 2005-10-1 | 155 | // Added by ksh in 2005-10-1 |
| 154 | cpu_config_t* cpu; | 156 | cpu_config_t* cpu; |
| 157 | |||
| 158 | // TODO(bunnei): Move this cache to a better place - it should be per codeset (likely per | ||
| 159 | // process for our purposes), not per ARMul_State (which tracks CPU core state). | ||
| 160 | std::unordered_map<u32, int> instruction_cache; | ||
| 155 | }; | 161 | }; |
| 156 | 162 | ||
| 157 | /***************************************************************************\ | 163 | /***************************************************************************\ |
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 6f716b1ca..f70c84c3d 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp | |||
| @@ -160,6 +160,16 @@ void Init() { | |||
| 160 | last_global_time_us = 0; | 160 | last_global_time_us = 0; |
| 161 | has_ts_events = 0; | 161 | has_ts_events = 0; |
| 162 | mhz_change_callbacks.clear(); | 162 | mhz_change_callbacks.clear(); |
| 163 | |||
| 164 | first = nullptr; | ||
| 165 | ts_first = nullptr; | ||
| 166 | ts_last = nullptr; | ||
| 167 | |||
| 168 | event_pool = nullptr; | ||
| 169 | event_ts_pool = nullptr; | ||
| 170 | allocated_ts_events = 0; | ||
| 171 | |||
| 172 | advance_callback = nullptr; | ||
| 163 | } | 173 | } |
| 164 | 174 | ||
| 165 | void Shutdown() { | 175 | void Shutdown() { |
diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/config_mem.cpp index 30d73adac..9fcfcc285 100644 --- a/src/core/hle/config_mem.cpp +++ b/src/core/hle/config_mem.cpp | |||
| @@ -61,6 +61,8 @@ template void Read<u16>(u16 &var, const u32 addr); | |||
| 61 | template void Read<u8>(u8 &var, const u32 addr); | 61 | template void Read<u8>(u8 &var, const u32 addr); |
| 62 | 62 | ||
| 63 | void Init() { | 63 | void Init() { |
| 64 | memset(&config_mem, 0, sizeof(config_mem)); | ||
| 65 | |||
| 64 | config_mem.update_flag = 0; // No update | 66 | config_mem.update_flag = 0; // No update |
| 65 | config_mem.sys_core_ver = 0x2; | 67 | config_mem.sys_core_ver = 0x2; |
| 66 | config_mem.unit_info = 0x1; // Bit 0 set for Retail | 68 | config_mem.unit_info = 0x1; // Bit 0 set for Retail |
| @@ -76,4 +78,7 @@ void Init() { | |||
| 76 | config_mem.firm_sys_core_ver = 0x2; | 78 | config_mem.firm_sys_core_ver = 0x2; |
| 77 | } | 79 | } |
| 78 | 80 | ||
| 81 | void Shutdown() { | ||
| 82 | } | ||
| 83 | |||
| 79 | } // namespace | 84 | } // namespace |
diff --git a/src/core/hle/config_mem.h b/src/core/hle/config_mem.h index 94853901a..cbb478fb3 100644 --- a/src/core/hle/config_mem.h +++ b/src/core/hle/config_mem.h | |||
| @@ -20,4 +20,6 @@ void Read(T &var, const u32 addr); | |||
| 20 | 20 | ||
| 21 | void Init(); | 21 | void Init(); |
| 22 | 22 | ||
| 23 | void Shutdown(); | ||
| 24 | |||
| 23 | } // namespace | 25 | } // namespace |
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp index c645d6563..191d0411e 100644 --- a/src/core/hle/hle.cpp +++ b/src/core/hle/hle.cpp | |||
| @@ -23,7 +23,7 @@ Common::Profiling::TimingCategory profiler_svc("SVC Calls"); | |||
| 23 | 23 | ||
| 24 | static std::vector<ModuleDef> g_module_db; | 24 | static std::vector<ModuleDef> g_module_db; |
| 25 | 25 | ||
| 26 | bool g_reschedule = false; ///< If true, immediately reschedules the CPU to a new thread | 26 | bool g_reschedule; ///< If true, immediately reschedules the CPU to a new thread |
| 27 | 27 | ||
| 28 | static const FunctionDef* GetSVCInfo(u32 opcode) { | 28 | static const FunctionDef* GetSVCInfo(u32 opcode) { |
| 29 | u32 func_num = opcode & 0xFFFFFF; // 8 bits | 29 | u32 func_num = opcode & 0xFFFFFF; // 8 bits |
| @@ -73,17 +73,20 @@ static void RegisterAllModules() { | |||
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | void Init() { | 75 | void Init() { |
| 76 | Service::Init(); | ||
| 77 | |||
| 78 | RegisterAllModules(); | 76 | RegisterAllModules(); |
| 79 | 77 | ||
| 78 | Service::Init(); | ||
| 80 | ConfigMem::Init(); | 79 | ConfigMem::Init(); |
| 81 | SharedPage::Init(); | 80 | SharedPage::Init(); |
| 82 | 81 | ||
| 82 | g_reschedule = false; | ||
| 83 | |||
| 83 | LOG_DEBUG(Kernel, "initialized OK"); | 84 | LOG_DEBUG(Kernel, "initialized OK"); |
| 84 | } | 85 | } |
| 85 | 86 | ||
| 86 | void Shutdown() { | 87 | void Shutdown() { |
| 88 | ConfigMem::Shutdown(); | ||
| 89 | SharedPage::Shutdown(); | ||
| 87 | Service::Shutdown(); | 90 | Service::Shutdown(); |
| 88 | 91 | ||
| 89 | g_module_db.clear(); | 92 | g_module_db.clear(); |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 6261b82b6..fca582bbe 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -14,11 +14,10 @@ | |||
| 14 | 14 | ||
| 15 | namespace Kernel { | 15 | namespace Kernel { |
| 16 | 16 | ||
| 17 | unsigned int Object::next_object_id = 0; | 17 | unsigned int Object::next_object_id; |
| 18 | 18 | SharedPtr<Thread> g_main_thread; | |
| 19 | SharedPtr<Thread> g_main_thread = nullptr; | ||
| 20 | HandleTable g_handle_table; | 19 | HandleTable g_handle_table; |
| 21 | u64 g_program_id = 0; | 20 | u64 g_program_id; |
| 22 | 21 | ||
| 23 | void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) { | 22 | void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) { |
| 24 | auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); | 23 | auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); |
| @@ -138,6 +137,10 @@ void HandleTable::Clear() { | |||
| 138 | void Init() { | 137 | void Init() { |
| 139 | Kernel::ThreadingInit(); | 138 | Kernel::ThreadingInit(); |
| 140 | Kernel::TimersInit(); | 139 | Kernel::TimersInit(); |
| 140 | |||
| 141 | Object::next_object_id = 0; | ||
| 142 | g_program_id = 0; | ||
| 143 | g_main_thread = nullptr; | ||
| 141 | } | 144 | } |
| 142 | 145 | ||
| 143 | /// Shutdown the kernel | 146 | /// Shutdown the kernel |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 2d295ea00..ab06fa025 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -95,12 +95,13 @@ public: | |||
| 95 | return false; | 95 | return false; |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | public: | ||
| 99 | static unsigned int next_object_id; | ||
| 100 | |||
| 98 | private: | 101 | private: |
| 99 | friend void intrusive_ptr_add_ref(Object*); | 102 | friend void intrusive_ptr_add_ref(Object*); |
| 100 | friend void intrusive_ptr_release(Object*); | 103 | friend void intrusive_ptr_release(Object*); |
| 101 | 104 | ||
| 102 | static unsigned int next_object_id; | ||
| 103 | |||
| 104 | unsigned int ref_count = 0; | 105 | unsigned int ref_count = 0; |
| 105 | unsigned int object_id = next_object_id++; | 106 | unsigned int object_id = next_object_id++; |
| 106 | }; | 107 | }; |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 33d66b986..d678f5f6f 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -23,7 +23,7 @@ | |||
| 23 | namespace Kernel { | 23 | namespace Kernel { |
| 24 | 24 | ||
| 25 | /// Event type for the thread wake up event | 25 | /// Event type for the thread wake up event |
| 26 | static int ThreadWakeupEventType = -1; | 26 | static int ThreadWakeupEventType; |
| 27 | 27 | ||
| 28 | bool Thread::ShouldWait() { | 28 | bool Thread::ShouldWait() { |
| 29 | return status != THREADSTATUS_DEAD; | 29 | return status != THREADSTATUS_DEAD; |
| @@ -42,7 +42,7 @@ static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST+1> ready_queue; | |||
| 42 | static Thread* current_thread; | 42 | static Thread* current_thread; |
| 43 | 43 | ||
| 44 | // The first available thread id at startup | 44 | // The first available thread id at startup |
| 45 | static u32 next_thread_id = 1; | 45 | static u32 next_thread_id; |
| 46 | 46 | ||
| 47 | /** | 47 | /** |
| 48 | * Creates a new thread ID | 48 | * Creates a new thread ID |
| @@ -497,6 +497,12 @@ void Thread::SetWaitSynchronizationOutput(s32 output) { | |||
| 497 | void ThreadingInit() { | 497 | void ThreadingInit() { |
| 498 | ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); | 498 | ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); |
| 499 | 499 | ||
| 500 | current_thread = nullptr; | ||
| 501 | next_thread_id = 1; | ||
| 502 | |||
| 503 | thread_list.clear(); | ||
| 504 | ready_queue.clear(); | ||
| 505 | |||
| 500 | // Setup the idle thread | 506 | // Setup the idle thread |
| 501 | SetupIdleThread(); | 507 | SetupIdleThread(); |
| 502 | } | 508 | } |
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 1ec2a4b10..36979248d 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | namespace Kernel { | 12 | namespace Kernel { |
| 13 | 13 | ||
| 14 | /// The event type of the generic timer callback event | 14 | /// The event type of the generic timer callback event |
| 15 | static int timer_callback_event_type = -1; | 15 | static int timer_callback_event_type; |
| 16 | // TODO(yuriks): This can be removed if Timer objects are explicitly pooled in the future, allowing | 16 | // TODO(yuriks): This can be removed if Timer objects are explicitly pooled in the future, allowing |
| 17 | // us to simply use a pool index or similar. | 17 | // us to simply use a pool index or similar. |
| 18 | static Kernel::HandleTable timer_callback_handle_table; | 18 | static Kernel::HandleTable timer_callback_handle_table; |
| @@ -89,6 +89,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { | |||
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | void TimersInit() { | 91 | void TimersInit() { |
| 92 | timer_callback_handle_table.Clear(); | ||
| 92 | timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback); | 93 | timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback); |
| 93 | } | 94 | } |
| 94 | 95 | ||
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 190c5df7a..98ae80b3a 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp | |||
| @@ -28,15 +28,15 @@ namespace APT { | |||
| 28 | static const VAddr SHARED_FONT_VADDR = 0x18000000; | 28 | static const VAddr SHARED_FONT_VADDR = 0x18000000; |
| 29 | 29 | ||
| 30 | /// Handle to shared memory region designated to for shared system font | 30 | /// Handle to shared memory region designated to for shared system font |
| 31 | static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem = nullptr; | 31 | static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; |
| 32 | 32 | ||
| 33 | static Kernel::SharedPtr<Kernel::Mutex> lock = nullptr; | 33 | static Kernel::SharedPtr<Kernel::Mutex> lock; |
| 34 | static Kernel::SharedPtr<Kernel::Event> notification_event = nullptr; ///< APT notification event | 34 | static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event |
| 35 | static Kernel::SharedPtr<Kernel::Event> start_event = nullptr; ///< APT start event | 35 | static Kernel::SharedPtr<Kernel::Event> start_event; ///< APT start event |
| 36 | 36 | ||
| 37 | static std::vector<u8> shared_font; | 37 | static std::vector<u8> shared_font; |
| 38 | 38 | ||
| 39 | static u32 cpu_percent = 0; ///< CPU time available to the running application | 39 | static u32 cpu_percent; ///< CPU time available to the running application |
| 40 | 40 | ||
| 41 | void Initialize(Service::Interface* self) { | 41 | void Initialize(Service::Interface* self) { |
| 42 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 42 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| @@ -309,6 +309,7 @@ void Init() { | |||
| 309 | } | 309 | } |
| 310 | 310 | ||
| 311 | lock = Kernel::Mutex::Create(false, "APT_U:Lock"); | 311 | lock = Kernel::Mutex::Create(false, "APT_U:Lock"); |
| 312 | |||
| 312 | cpu_percent = 0; | 313 | cpu_percent = 0; |
| 313 | 314 | ||
| 314 | // TODO(bunnei): Check if these are created in Initialize or on APT process startup. | 315 | // TODO(bunnei): Check if these are created in Initialize or on APT process startup. |
| @@ -317,7 +318,11 @@ void Init() { | |||
| 317 | } | 318 | } |
| 318 | 319 | ||
| 319 | void Shutdown() { | 320 | void Shutdown() { |
| 320 | 321 | shared_font.clear(); | |
| 322 | shared_font_mem = nullptr; | ||
| 323 | lock = nullptr; | ||
| 324 | notification_event = nullptr; | ||
| 325 | start_event = nullptr; | ||
| 321 | } | 326 | } |
| 322 | 327 | ||
| 323 | } // namespace APT | 328 | } // namespace APT |
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index 6af0352ac..5eccdecf7 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp | |||
| @@ -207,6 +207,7 @@ void Init() { | |||
| 207 | 207 | ||
| 208 | // Initialize the Username block | 208 | // Initialize the Username block |
| 209 | // TODO(Subv): Initialize this directly in the variable when MSVC supports char16_t string literals | 209 | // TODO(Subv): Initialize this directly in the variable when MSVC supports char16_t string literals |
| 210 | memset(&CONSOLE_USERNAME_BLOCK, 0, sizeof(CONSOLE_USERNAME_BLOCK)); | ||
| 210 | CONSOLE_USERNAME_BLOCK.ng_word = 0; | 211 | CONSOLE_USERNAME_BLOCK.ng_word = 0; |
| 211 | CONSOLE_USERNAME_BLOCK.zero = 0; | 212 | CONSOLE_USERNAME_BLOCK.zero = 0; |
| 212 | 213 | ||
| @@ -219,7 +220,6 @@ void Init() { | |||
| 219 | } | 220 | } |
| 220 | 221 | ||
| 221 | void Shutdown() { | 222 | void Shutdown() { |
| 222 | |||
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | } // namespace CFG | 225 | } // namespace CFG |
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp index 4d6c70f4d..2e759a3e3 100644 --- a/src/core/hle/service/dsp_dsp.cpp +++ b/src/core/hle/service/dsp_dsp.cpp | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | namespace DSP_DSP { | 12 | namespace DSP_DSP { |
| 13 | 13 | ||
| 14 | static u32 read_pipe_count = 0; | 14 | static u32 read_pipe_count; |
| 15 | static Kernel::SharedPtr<Kernel::Event> semaphore_event; | 15 | static Kernel::SharedPtr<Kernel::Event> semaphore_event; |
| 16 | static Kernel::SharedPtr<Kernel::Event> interrupt_event; | 16 | static Kernel::SharedPtr<Kernel::Event> interrupt_event; |
| 17 | 17 | ||
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 9ca5d13d4..0f30f743a 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -20,17 +20,17 @@ namespace HID { | |||
| 20 | static const int MAX_CIRCLEPAD_POS = 0x9C; ///< Max value for a circle pad position | 20 | static const int MAX_CIRCLEPAD_POS = 0x9C; ///< Max value for a circle pad position |
| 21 | 21 | ||
| 22 | // Handle to shared memory region designated to HID_User service | 22 | // Handle to shared memory region designated to HID_User service |
| 23 | static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem = nullptr; | 23 | static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; |
| 24 | 24 | ||
| 25 | // Event handles | 25 | // Event handles |
| 26 | static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_1 = nullptr; | 26 | static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_1; |
| 27 | static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_2 = nullptr; | 27 | static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_2; |
| 28 | static Kernel::SharedPtr<Kernel::Event> event_accelerometer = nullptr; | 28 | static Kernel::SharedPtr<Kernel::Event> event_accelerometer; |
| 29 | static Kernel::SharedPtr<Kernel::Event> event_gyroscope = nullptr; | 29 | static Kernel::SharedPtr<Kernel::Event> event_gyroscope; |
| 30 | static Kernel::SharedPtr<Kernel::Event> event_debug_pad = nullptr; | 30 | static Kernel::SharedPtr<Kernel::Event> event_debug_pad; |
| 31 | 31 | ||
| 32 | static u32 next_pad_index = 0; | 32 | static u32 next_pad_index; |
| 33 | static u32 next_touch_index = 0; | 33 | static u32 next_touch_index; |
| 34 | 34 | ||
| 35 | // TODO(peachum): | 35 | // TODO(peachum): |
| 36 | // Add a method for setting analog input from joystick device for the circle Pad. | 36 | // Add a method for setting analog input from joystick device for the circle Pad. |
| @@ -175,6 +175,12 @@ void Init() { | |||
| 175 | } | 175 | } |
| 176 | 176 | ||
| 177 | void Shutdown() { | 177 | void Shutdown() { |
| 178 | shared_mem = nullptr; | ||
| 179 | event_pad_or_touch_1 = nullptr; | ||
| 180 | event_pad_or_touch_2 = nullptr; | ||
| 181 | event_accelerometer = nullptr; | ||
| 182 | event_gyroscope = nullptr; | ||
| 183 | event_debug_pad = nullptr; | ||
| 178 | } | 184 | } |
| 179 | 185 | ||
| 180 | } // namespace HID | 186 | } // namespace HID |
diff --git a/src/core/hle/service/ir/ir.cpp b/src/core/hle/service/ir/ir.cpp index 58dfd8e1a..15ac477ef 100644 --- a/src/core/hle/service/ir/ir.cpp +++ b/src/core/hle/service/ir/ir.cpp | |||
| @@ -15,8 +15,8 @@ | |||
| 15 | namespace Service { | 15 | namespace Service { |
| 16 | namespace IR { | 16 | namespace IR { |
| 17 | 17 | ||
| 18 | static Kernel::SharedPtr<Kernel::Event> handle_event = nullptr; | 18 | static Kernel::SharedPtr<Kernel::Event> handle_event; |
| 19 | static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory = nullptr; | 19 | static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory; |
| 20 | 20 | ||
| 21 | void GetHandles(Service::Interface* self) { | 21 | void GetHandles(Service::Interface* self) { |
| 22 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 22 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| @@ -41,6 +41,8 @@ void Init() { | |||
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | void Shutdown() { | 43 | void Shutdown() { |
| 44 | shared_memory = nullptr; | ||
| 45 | handle_event = nullptr; | ||
| 44 | } | 46 | } |
| 45 | 47 | ||
| 46 | } // namespace IR | 48 | } // namespace IR |
diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm_uds.cpp index 1cee81ab2..4b06efc3a 100644 --- a/src/core/hle/service/nwm_uds.cpp +++ b/src/core/hle/service/nwm_uds.cpp | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | namespace NWM_UDS { | 12 | namespace NWM_UDS { |
| 13 | 13 | ||
| 14 | static Kernel::SharedPtr<Kernel::Event> handle_event = nullptr; | 14 | static Kernel::SharedPtr<Kernel::Event> handle_event; |
| 15 | 15 | ||
| 16 | /** | 16 | /** |
| 17 | * NWM_UDS::Shutdown service function | 17 | * NWM_UDS::Shutdown service function |
diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp index 57a301bec..d44510c1b 100644 --- a/src/core/hle/service/ptm/ptm.cpp +++ b/src/core/hle/service/ptm/ptm.cpp | |||
| @@ -18,9 +18,9 @@ static const GameCoin default_game_coin = { 0x4F00, 42, 0, 0, 0, 2014, 12, 29 }; | |||
| 18 | /// Id of the SharedExtData archive used by the PTM process | 18 | /// Id of the SharedExtData archive used by the PTM process |
| 19 | static const std::vector<u8> ptm_shared_extdata_id = {0, 0, 0, 0, 0x0B, 0, 0, 0xF0, 0, 0, 0, 0}; | 19 | static const std::vector<u8> ptm_shared_extdata_id = {0, 0, 0, 0, 0x0B, 0, 0, 0xF0, 0, 0, 0, 0}; |
| 20 | 20 | ||
| 21 | static bool shell_open = true; | 21 | static bool shell_open; |
| 22 | 22 | ||
| 23 | static bool battery_is_charging = true; | 23 | static bool battery_is_charging; |
| 24 | 24 | ||
| 25 | u32 GetAdapterState() { | 25 | u32 GetAdapterState() { |
| 26 | // TODO(purpasmart96): This function is only a stub, | 26 | // TODO(purpasmart96): This function is only a stub, |
| @@ -43,6 +43,9 @@ void Init() { | |||
| 43 | AddService(new PTM_Sysm_Interface); | 43 | AddService(new PTM_Sysm_Interface); |
| 44 | AddService(new PTM_U_Interface); | 44 | AddService(new PTM_U_Interface); |
| 45 | 45 | ||
| 46 | shell_open = true; | ||
| 47 | battery_is_charging = true; | ||
| 48 | |||
| 46 | // Open the SharedExtSaveData archive 0xF000000B and create the gamecoin.dat file if it doesn't exist | 49 | // Open the SharedExtSaveData archive 0xF000000B and create the gamecoin.dat file if it doesn't exist |
| 47 | FileSys::Path archive_path(ptm_shared_extdata_id); | 50 | FileSys::Path archive_path(ptm_shared_extdata_id); |
| 48 | auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); | 51 | auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path); |
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp index 6607965e1..33ecf64a2 100644 --- a/src/core/hle/service/y2r_u.cpp +++ b/src/core/hle/service/y2r_u.cpp | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | namespace Y2R_U { | 12 | namespace Y2R_U { |
| 13 | 13 | ||
| 14 | static Kernel::SharedPtr<Kernel::Event> completion_event = 0; | 14 | static Kernel::SharedPtr<Kernel::Event> completion_event; |
| 15 | 15 | ||
| 16 | /** | 16 | /** |
| 17 | * Y2R_U::IsBusyConversion service function | 17 | * Y2R_U::IsBusyConversion service function |
diff --git a/src/core/hle/shared_page.cpp b/src/core/hle/shared_page.cpp index 568dad684..94fae2551 100644 --- a/src/core/hle/shared_page.cpp +++ b/src/core/hle/shared_page.cpp | |||
| @@ -62,6 +62,8 @@ template void Read<u16>(u16 &var, const u32 addr); | |||
| 62 | template void Read<u8>(u8 &var, const u32 addr); | 62 | template void Read<u8>(u8 &var, const u32 addr); |
| 63 | 63 | ||
| 64 | void Set3DSlider(float amount) { | 64 | void Set3DSlider(float amount) { |
| 65 | memset(&shared_page, 0, sizeof(shared_page)); | ||
| 66 | |||
| 65 | shared_page.sliderstate_3d = amount; | 67 | shared_page.sliderstate_3d = amount; |
| 66 | shared_page.ledstate_3d = (amount == 0.0f); // off when non-zero | 68 | shared_page.ledstate_3d = (amount == 0.0f); // off when non-zero |
| 67 | } | 69 | } |
| @@ -71,4 +73,7 @@ void Init() { | |||
| 71 | Set3DSlider(0.0f); | 73 | Set3DSlider(0.0f); |
| 72 | } | 74 | } |
| 73 | 75 | ||
| 76 | void Shutdown() { | ||
| 77 | } | ||
| 78 | |||
| 74 | } // namespace | 79 | } // namespace |
diff --git a/src/core/hle/shared_page.h b/src/core/hle/shared_page.h index 8f93545ec..1b6e4e581 100644 --- a/src/core/hle/shared_page.h +++ b/src/core/hle/shared_page.h | |||
| @@ -23,4 +23,6 @@ void Set3DSlider(float amount); | |||
| 23 | 23 | ||
| 24 | void Init(); | 24 | void Init(); |
| 25 | 25 | ||
| 26 | void Shutdown(); | ||
| 27 | |||
| 26 | } // namespace | 28 | } // namespace |
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index 308ea2035..0ad7e2963 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp | |||
| @@ -29,8 +29,7 @@ namespace GPU { | |||
| 29 | Regs g_regs; | 29 | Regs g_regs; |
| 30 | 30 | ||
| 31 | /// True if the current frame was skipped | 31 | /// True if the current frame was skipped |
| 32 | bool g_skip_frame = false; | 32 | bool g_skip_frame; |
| 33 | |||
| 34 | /// 268MHz / gpu_refresh_rate frames per second | 33 | /// 268MHz / gpu_refresh_rate frames per second |
| 35 | static u64 frame_ticks; | 34 | static u64 frame_ticks; |
| 36 | /// Event id for CoreTiming | 35 | /// Event id for CoreTiming |
| @@ -38,7 +37,7 @@ static int vblank_event; | |||
| 38 | /// Total number of frames drawn | 37 | /// Total number of frames drawn |
| 39 | static u64 frame_count; | 38 | static u64 frame_count; |
| 40 | /// True if the last frame was skipped | 39 | /// True if the last frame was skipped |
| 41 | static bool last_skip_frame = false; | 40 | static bool last_skip_frame; |
| 42 | 41 | ||
| 43 | template <typename T> | 42 | template <typename T> |
| 44 | inline void Read(T &var, const u32 raw_addr) { | 43 | inline void Read(T &var, const u32 raw_addr) { |
| @@ -320,6 +319,8 @@ static void VBlankCallback(u64 userdata, int cycles_late) { | |||
| 320 | 319 | ||
| 321 | /// Initialize hardware | 320 | /// Initialize hardware |
| 322 | void Init() { | 321 | void Init() { |
| 322 | memset(&g_regs, 0, sizeof(g_regs)); | ||
| 323 | |||
| 323 | auto& framebuffer_top = g_regs.framebuffer_config[0]; | 324 | auto& framebuffer_top = g_regs.framebuffer_config[0]; |
| 324 | auto& framebuffer_sub = g_regs.framebuffer_config[1]; | 325 | auto& framebuffer_sub = g_regs.framebuffer_config[1]; |
| 325 | 326 | ||
| @@ -349,6 +350,7 @@ void Init() { | |||
| 349 | frame_ticks = 268123480 / Settings::values.gpu_refresh_rate; | 350 | frame_ticks = 268123480 / Settings::values.gpu_refresh_rate; |
| 350 | last_skip_frame = false; | 351 | last_skip_frame = false; |
| 351 | g_skip_frame = false; | 352 | g_skip_frame = false; |
| 353 | frame_count = 0; | ||
| 352 | 354 | ||
| 353 | vblank_event = CoreTiming::RegisterEvent("GPU::VBlankCallback", VBlankCallback); | 355 | vblank_event = CoreTiming::RegisterEvent("GPU::VBlankCallback", VBlankCallback); |
| 354 | CoreTiming::ScheduleEvent(frame_ticks, vblank_event); | 356 | CoreTiming::ScheduleEvent(frame_ticks, vblank_event); |
diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp index bed50af50..236958139 100644 --- a/src/core/hw/hw.cpp +++ b/src/core/hw/hw.cpp | |||
| @@ -63,6 +63,8 @@ void Init() { | |||
| 63 | 63 | ||
| 64 | /// Shutdown hardware | 64 | /// Shutdown hardware |
| 65 | void Shutdown() { | 65 | void Shutdown() { |
| 66 | GPU::Shutdown(); | ||
| 67 | LCD::Shutdown(); | ||
| 66 | LOG_DEBUG(HW, "shutdown OK"); | 68 | LOG_DEBUG(HW, "shutdown OK"); |
| 67 | } | 69 | } |
| 68 | 70 | ||
diff --git a/src/core/hw/lcd.cpp b/src/core/hw/lcd.cpp index 7986f3ddb..8a09c3bc0 100644 --- a/src/core/hw/lcd.cpp +++ b/src/core/hw/lcd.cpp | |||
| @@ -55,6 +55,7 @@ template void Write<u8>(u32 addr, const u8 data); | |||
| 55 | 55 | ||
| 56 | /// Initialize hardware | 56 | /// Initialize hardware |
| 57 | void Init() { | 57 | void Init() { |
| 58 | memset(&g_regs, 0, sizeof(g_regs)); | ||
| 58 | LOG_DEBUG(HW_LCD, "initialized OK"); | 59 | LOG_DEBUG(HW_LCD, "initialized OK"); |
| 59 | } | 60 | } |
| 60 | 61 | ||
diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp index a14e8303e..22e359b3e 100644 --- a/src/core/mem_map.cpp +++ b/src/core/mem_map.cpp | |||
| @@ -11,30 +11,30 @@ | |||
| 11 | 11 | ||
| 12 | namespace Memory { | 12 | namespace Memory { |
| 13 | 13 | ||
| 14 | u8* g_base = nullptr; ///< The base pointer to the auto-mirrored arena. | 14 | u8* g_base; ///< The base pointer to the auto-mirrored arena. |
| 15 | 15 | ||
| 16 | static MemArena arena; ///< The MemArena class | 16 | static MemArena arena; ///< The MemArena class |
| 17 | 17 | ||
| 18 | u8* g_exefs_code = nullptr; ///< ExeFS:/.code is loaded here | 18 | u8* g_exefs_code; ///< ExeFS:/.code is loaded here |
| 19 | u8* g_system_mem = nullptr; ///< System memory | 19 | u8* g_system_mem; ///< System memory |
| 20 | u8* g_heap = nullptr; ///< Application heap (main memory) | 20 | u8* g_heap; ///< Application heap (main memory) |
| 21 | u8* g_heap_linear = nullptr; ///< Linear heap | 21 | u8* g_heap_linear; ///< Linear heap |
| 22 | u8* g_vram = nullptr; ///< Video memory (VRAM) pointer | 22 | u8* g_vram; ///< Video memory (VRAM) pointer |
| 23 | u8* g_shared_mem = nullptr; ///< Shared memory | 23 | u8* g_shared_mem; ///< Shared memory |
| 24 | u8* g_dsp_mem = nullptr; ///< DSP memory | 24 | u8* g_dsp_mem; ///< DSP memory |
| 25 | u8* g_kernel_mem; ///< Kernel memory | 25 | u8* g_kernel_mem; ///< Kernel memory |
| 26 | 26 | ||
| 27 | static u8* physical_bootrom = nullptr; ///< Bootrom physical memory | 27 | static u8* physical_bootrom; ///< Bootrom physical memory |
| 28 | static u8* uncached_bootrom = nullptr; | 28 | static u8* uncached_bootrom; |
| 29 | 29 | ||
| 30 | static u8* physical_exefs_code = nullptr; ///< Phsical ExeFS:/.code is loaded here | 30 | static u8* physical_exefs_code; ///< Phsical ExeFS:/.code is loaded here |
| 31 | static u8* physical_system_mem = nullptr; ///< System physical memory | 31 | static u8* physical_system_mem; ///< System physical memory |
| 32 | static u8* physical_fcram = nullptr; ///< Main physical memory (FCRAM) | 32 | static u8* physical_fcram; ///< Main physical memory (FCRAM) |
| 33 | static u8* physical_heap_gsp = nullptr; ///< GSP heap physical memory | 33 | static u8* physical_heap_gsp; ///< GSP heap physical memory |
| 34 | static u8* physical_vram = nullptr; ///< Video physical memory (VRAM) | 34 | static u8* physical_vram; ///< Video physical memory (VRAM) |
| 35 | static u8* physical_shared_mem = nullptr; ///< Physical shared memory | 35 | static u8* physical_shared_mem; ///< Physical shared memory |
| 36 | static u8* physical_dsp_mem = nullptr; ///< Physical DSP memory | 36 | static u8* physical_dsp_mem; ///< Physical DSP memory |
| 37 | static u8* physical_kernel_mem; ///< Kernel memory | 37 | static u8* physical_kernel_mem; ///< Kernel memory |
| 38 | 38 | ||
| 39 | // We don't declare the IO region in here since its handled by other means. | 39 | // We don't declare the IO region in here since its handled by other means. |
| 40 | static MemoryView g_views[] = { | 40 | static MemoryView g_views[] = { |
| @@ -73,6 +73,7 @@ void Init() { | |||
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | g_base = MemoryMap_Setup(g_views, kNumMemViews, flags, &arena); | 75 | g_base = MemoryMap_Setup(g_views, kNumMemViews, flags, &arena); |
| 76 | MemBlock_Init(); | ||
| 76 | 77 | ||
| 77 | LOG_DEBUG(HW_Memory, "initialized OK, RAM at %p (mirror at 0 @ %p)", g_heap, | 78 | LOG_DEBUG(HW_Memory, "initialized OK, RAM at %p (mirror at 0 @ %p)", g_heap, |
| 78 | physical_fcram); | 79 | physical_fcram); |
| @@ -81,9 +82,29 @@ void Init() { | |||
| 81 | void Shutdown() { | 82 | void Shutdown() { |
| 82 | u32 flags = 0; | 83 | u32 flags = 0; |
| 83 | MemoryMap_Shutdown(g_views, kNumMemViews, flags, &arena); | 84 | MemoryMap_Shutdown(g_views, kNumMemViews, flags, &arena); |
| 84 | |||
| 85 | arena.ReleaseSpace(); | 85 | arena.ReleaseSpace(); |
| 86 | MemBlock_Shutdown(); | ||
| 87 | |||
| 86 | g_base = nullptr; | 88 | g_base = nullptr; |
| 89 | g_exefs_code = nullptr; | ||
| 90 | g_system_mem = nullptr; | ||
| 91 | g_heap = nullptr; | ||
| 92 | g_heap_linear = nullptr; | ||
| 93 | g_vram = nullptr; | ||
| 94 | g_shared_mem = nullptr; | ||
| 95 | g_dsp_mem = nullptr; | ||
| 96 | g_kernel_mem = nullptr; | ||
| 97 | |||
| 98 | physical_bootrom = nullptr; | ||
| 99 | uncached_bootrom = nullptr; | ||
| 100 | physical_exefs_code = nullptr; | ||
| 101 | physical_system_mem = nullptr; | ||
| 102 | physical_fcram = nullptr; | ||
| 103 | physical_heap_gsp = nullptr; | ||
| 104 | physical_vram = nullptr; | ||
| 105 | physical_shared_mem = nullptr; | ||
| 106 | physical_dsp_mem = nullptr; | ||
| 107 | physical_kernel_mem = nullptr; | ||
| 87 | 108 | ||
| 88 | LOG_DEBUG(HW_Memory, "shutdown OK"); | 109 | LOG_DEBUG(HW_Memory, "shutdown OK"); |
| 89 | } | 110 | } |
diff --git a/src/core/mem_map.h b/src/core/mem_map.h index ff730593e..1af02973b 100644 --- a/src/core/mem_map.h +++ b/src/core/mem_map.h | |||
| @@ -171,6 +171,12 @@ u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions); | |||
| 171 | */ | 171 | */ |
| 172 | u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions); | 172 | u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions); |
| 173 | 173 | ||
| 174 | /// Initialize mapped memory blocks | ||
| 175 | void MemBlock_Init(); | ||
| 176 | |||
| 177 | /// Shutdown mapped memory blocks | ||
| 178 | void MemBlock_Shutdown(); | ||
| 179 | |||
| 174 | inline const char* GetCharPointer(const VAddr address) { | 180 | inline const char* GetCharPointer(const VAddr address) { |
| 175 | return (const char *)GetPointer(address); | 181 | return (const char *)GetPointer(address); |
| 176 | } | 182 | } |
diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp index 5878b99dc..8759ebdfb 100644 --- a/src/core/mem_map_funcs.cpp +++ b/src/core/mem_map_funcs.cpp | |||
| @@ -15,7 +15,6 @@ namespace Memory { | |||
| 15 | 15 | ||
| 16 | static std::map<u32, MemoryBlock> heap_map; | 16 | static std::map<u32, MemoryBlock> heap_map; |
| 17 | static std::map<u32, MemoryBlock> heap_linear_map; | 17 | static std::map<u32, MemoryBlock> heap_linear_map; |
| 18 | static std::map<u32, MemoryBlock> shared_map; | ||
| 19 | 18 | ||
| 20 | /// Convert a physical address to virtual address | 19 | /// Convert a physical address to virtual address |
| 21 | VAddr PhysicalToVirtualAddress(const PAddr addr) { | 20 | VAddr PhysicalToVirtualAddress(const PAddr addr) { |
| @@ -185,12 +184,6 @@ u8 *GetPointer(const VAddr vaddr) { | |||
| 185 | } | 184 | } |
| 186 | } | 185 | } |
| 187 | 186 | ||
| 188 | /** | ||
| 189 | * Maps a block of memory on the heap | ||
| 190 | * @param size Size of block in bytes | ||
| 191 | * @param operation Memory map operation type | ||
| 192 | * @param flags Memory allocation flags | ||
| 193 | */ | ||
| 194 | u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions) { | 187 | u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions) { |
| 195 | MemoryBlock block; | 188 | MemoryBlock block; |
| 196 | 189 | ||
| @@ -208,12 +201,6 @@ u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions) { | |||
| 208 | return block.GetVirtualAddress(); | 201 | return block.GetVirtualAddress(); |
| 209 | } | 202 | } |
| 210 | 203 | ||
| 211 | /** | ||
| 212 | * Maps a block of memory on the linear heap | ||
| 213 | * @param size Size of block in bytes | ||
| 214 | * @param operation Memory map operation type | ||
| 215 | * @param flags Memory allocation flags | ||
| 216 | */ | ||
| 217 | u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions) { | 204 | u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions) { |
| 218 | MemoryBlock block; | 205 | MemoryBlock block; |
| 219 | 206 | ||
| @@ -231,6 +218,14 @@ u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions) { | |||
| 231 | return block.GetVirtualAddress(); | 218 | return block.GetVirtualAddress(); |
| 232 | } | 219 | } |
| 233 | 220 | ||
| 221 | void MemBlock_Init() { | ||
| 222 | } | ||
| 223 | |||
| 224 | void MemBlock_Shutdown() { | ||
| 225 | heap_map.clear(); | ||
| 226 | heap_linear_map.clear(); | ||
| 227 | } | ||
| 228 | |||
| 234 | u8 Read8(const VAddr addr) { | 229 | u8 Read8(const VAddr addr) { |
| 235 | u8 data = 0; | 230 | u8 data = 0; |
| 236 | Read<u8>(data, addr); | 231 | Read<u8>(data, addr); |