summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/citra_qt/bootmanager.cpp101
-rw-r--r--src/citra_qt/bootmanager.h68
-rw-r--r--src/citra_qt/debugger/disassembler.cpp81
-rw-r--r--src/citra_qt/debugger/disassembler.h7
-rw-r--r--src/citra_qt/debugger/registers.cpp33
-rw-r--r--src/citra_qt/debugger/registers.h4
-rw-r--r--src/citra_qt/main.cpp125
-rw-r--r--src/citra_qt/main.h23
-rw-r--r--src/citra_qt/main.ui3
-rw-r--r--src/core/arm/dyncom/arm_dyncom.cpp4
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp31
-rw-r--r--src/core/arm/interpreter/arminit.cpp2
-rw-r--r--src/core/arm/skyeye_common/armdefs.h6
-rw-r--r--src/core/core_timing.cpp10
-rw-r--r--src/core/hle/config_mem.cpp5
-rw-r--r--src/core/hle/config_mem.h2
-rw-r--r--src/core/hle/hle.cpp9
-rw-r--r--src/core/hle/kernel/kernel.cpp11
-rw-r--r--src/core/hle/kernel/kernel.h5
-rw-r--r--src/core/hle/kernel/thread.cpp10
-rw-r--r--src/core/hle/kernel/timer.cpp3
-rw-r--r--src/core/hle/service/apt/apt.cpp17
-rw-r--r--src/core/hle/service/cfg/cfg.cpp2
-rw-r--r--src/core/hle/service/dsp_dsp.cpp2
-rw-r--r--src/core/hle/service/hid/hid.cpp22
-rw-r--r--src/core/hle/service/ir/ir.cpp6
-rw-r--r--src/core/hle/service/nwm_uds.cpp2
-rw-r--r--src/core/hle/service/ptm/ptm.cpp7
-rw-r--r--src/core/hle/service/y2r_u.cpp2
-rw-r--r--src/core/hle/shared_page.cpp5
-rw-r--r--src/core/hle/shared_page.h2
-rw-r--r--src/core/hw/gpu.cpp8
-rw-r--r--src/core/hw/hw.cpp2
-rw-r--r--src/core/hw/lcd.cpp1
-rw-r--r--src/core/mem_map.cpp71
-rw-r--r--src/core/mem_map.h6
-rw-r--r--src/core/mem_map_funcs.cpp21
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
29EmuThread::EmuThread(GRenderWindow* render_window) : 30EmuThread::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
35void EmuThread::SetFilename(std::string filename) 33 connect(this, SIGNAL(started()), render_window, SLOT(moveContext()));
36{
37 this->filename = filename;
38} 34}
39 35
40void EmuThread::run() 36void 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
79void 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
117class GGLWidgetInternal : public QGLWidget 71class GGLWidgetInternal : public QGLWidget
@@ -133,13 +87,9 @@ private:
133 GRenderWindow* parent; 87 GRenderWindow* parent;
134}; 88};
135 89
136EmuThread& GRenderWindow::GetEmuThread() 90GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread) :
137{ 91 QWidget(parent), emu_thread(emu_thread), keyboard_id(0) {
138 return emu_thread;
139}
140 92
141GRenderWindow::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
187GRenderWindow::~GRenderWindow()
188{
189 if (emu_thread.isRunning())
190 emu_thread.Stop();
191}
192
193void GRenderWindow::SwapBuffers() 137void 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
199void GRenderWindow::closeEvent(QCloseEvent* event)
200{
201 if (emu_thread.isRunning())
202 emu_thread.Stop();
203 QWidget::closeEvent(event);
204}
205
206void GRenderWindow::MakeCurrent() 143void GRenderWindow::MakeCurrent()
207{ 144{
208 child->makeCurrent(); 145 child->makeCurrent();
@@ -335,3 +272,11 @@ void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height)
335void GRenderWindow::OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) { 272void 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
276void GRenderWindow::OnEmulationStarting(EmuThread* emu_thread) {
277 this->emu_thread = emu_thread;
278}
279
280void 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
13class QScreen; 14class QScreen;
14class QKeyEvent; 15class QKeyEvent;
15 16
16class GRenderWindow; 17class GRenderWindow;
18class GMainWindow;
17 19
18class EmuThread : public QThread 20class EmuThread : public QThread
19{ 21{
20 Q_OBJECT 22 Q_OBJECT
21 23
22public: 24public:
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
60public 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
69private: 61private:
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
102public: 88public:
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:
134public slots: 115public slots:
135 void moveContext(); // overridden 116 void moveContext(); // overridden
136 117
118 void OnEmulationStarting(EmuThread* emu_thread);
119 void OnEmulationStopping();
120
137private: 121private:
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
21DisassemblerModel::DisassemblerModel(QObject* parent) : QAbstractListModel(parent), base_address(0), code_size(0), program_counter(0), selection(QModelIndex()) { 21DisassemblerModel::DisassemblerModel(QObject* parent) :
22 22 QAbstractListModel(parent), base_address(0), code_size(0), program_counter(0), selection(QModelIndex()) {
23} 23}
24 24
25int DisassemblerModel::columnCount(const QModelIndex& parent) const { 25int 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
161DisassemblerWidget::DisassemblerWidget(QWidget* parent, EmuThread& emu_thread) : QDockWidget(parent), base_addr(0), emu_thread(emu_thread) 161DisassemblerWidget::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
187void DisassemblerWidget::Init() 182void 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
200void DisassemblerWidget::OnContinue() 194void DisassemblerWidget::OnContinue() {
201{ 195 emu_thread->SetRunning(true);
202 emu_thread.SetCpuRunning(true);
203} 196}
204 197
205void DisassemblerWidget::OnStep() 198void DisassemblerWidget::OnStep() {
206{
207 OnStepInto(); // change later 199 OnStepInto(); // change later
208} 200}
209 201
210void DisassemblerWidget::OnStepInto() 202void 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
216void DisassemblerWidget::OnPause() 207void 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
226void DisassemblerWidget::OnToggleStartStop() 216void DisassemblerWidget::OnToggleStartStop() {
227{ 217 emu_thread->SetRunning(!emu_thread->IsRunning());
228 emu_thread.SetCpuRunning(!emu_thread.IsCpuRunning());
229} 218}
230 219
231void DisassemblerWidget::OnDebugModeEntered() 220void 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
245void DisassemblerWidget::OnDebugModeLeft() 233void DisassemblerWidget::OnDebugModeLeft() {
246{
247
248} 234}
249 235
250int DisassemblerWidget::SelectedRow() 236int 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
244void 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
259void 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
53public: 53public:
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
68private: 71private:
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
10RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent) 10RegistersWidget::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
44void RegistersWidget::OnDebugModeEntered() 44void 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
69void RegistersWidget::OnDebugModeLeft() 71void RegistersWidget::OnDebugModeLeft() {
70{ 72}
73
74void RegistersWidget::OnEmulationStarting(EmuThread* emu_thread) {
75 setEnabled(true);
76}
77
78void 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
10class QTreeWidget; 10class QTreeWidget;
11class EmuThread;
11 12
12class RegistersWidget : public QDockWidget 13class 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
23private: 27private:
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
49GMainWindow::GMainWindow() 50GMainWindow::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
199void GMainWindow::BootGame(std::string filename) 198void 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
232void 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
220void GMainWindow::OnMenuLoadFile() 258void 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
227void GMainWindow::OnMenuLoadSymbolMap() { 270void GMainWindow::OnMenuLoadSymbolMap() {
@@ -232,7 +275,7 @@ void GMainWindow::OnMenuLoadSymbolMap() {
232 275
233void GMainWindow::OnStartGame() 276void 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
242void GMainWindow::OnPauseGame() 285void 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
251void GMainWindow::OnStopGame() 294void 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
261void GMainWindow::OnOpenHotkeysDialog() 298void GMainWindow::OnOpenHotkeysDialog()
@@ -265,24 +302,22 @@ void GMainWindow::OnOpenHotkeysDialog()
265} 302}
266 303
267 304
268void GMainWindow::ToggleWindowMode() 305void 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
12class GImageInfo; 13class GImageInfo;
13class GRenderWindow; 14class GRenderWindow;
15class EmuThread;
14class ProfilerWidget; 16class ProfilerWidget;
15class DisassemblerWidget; 17class DisassemblerWidget;
16class RegistersWidget; 18class RegistersWidget;
@@ -34,8 +36,27 @@ public:
34 GMainWindow(); 36 GMainWindow();
35 ~GMainWindow(); 37 ~GMainWindow();
36 38
39signals:
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
37private: 57private:
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>&amp;Start</string> 97 <string>&amp;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
19ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) { 21ARM_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
3536typedef std::unordered_map<u32, int> bb_map;
3537static bb_map CreamCache;
3538
3539static void insert_bb(unsigned int addr, int start) {
3540 CreamCache[addr] = start;
3541}
3542
3543static 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
3555enum { 3535enum {
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\***************************************************************************/
27ARMul_State* ARMul_NewState(ARMul_State* state) 27ARMul_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
165void Shutdown() { 175void 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);
61template void Read<u8>(u8 &var, const u32 addr); 61template void Read<u8>(u8 &var, const u32 addr);
62 62
63void Init() { 63void 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
81void 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
21void Init(); 21void Init();
22 22
23void 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
24static std::vector<ModuleDef> g_module_db; 24static std::vector<ModuleDef> g_module_db;
25 25
26bool g_reschedule = false; ///< If true, immediately reschedules the CPU to a new thread 26bool g_reschedule; ///< If true, immediately reschedules the CPU to a new thread
27 27
28static const FunctionDef* GetSVCInfo(u32 opcode) { 28static 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
75void Init() { 75void 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
86void Shutdown() { 87void 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
15namespace Kernel { 15namespace Kernel {
16 16
17unsigned int Object::next_object_id = 0; 17unsigned int Object::next_object_id;
18 18SharedPtr<Thread> g_main_thread;
19SharedPtr<Thread> g_main_thread = nullptr;
20HandleTable g_handle_table; 19HandleTable g_handle_table;
21u64 g_program_id = 0; 20u64 g_program_id;
22 21
23void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) { 22void 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() {
138void Init() { 137void 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
98public:
99 static unsigned int next_object_id;
100
98private: 101private:
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 @@
23namespace Kernel { 23namespace Kernel {
24 24
25/// Event type for the thread wake up event 25/// Event type for the thread wake up event
26static int ThreadWakeupEventType = -1; 26static int ThreadWakeupEventType;
27 27
28bool Thread::ShouldWait() { 28bool 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;
42static Thread* current_thread; 42static Thread* current_thread;
43 43
44// The first available thread id at startup 44// The first available thread id at startup
45static u32 next_thread_id = 1; 45static 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) {
497void ThreadingInit() { 497void 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 @@
12namespace Kernel { 12namespace Kernel {
13 13
14/// The event type of the generic timer callback event 14/// The event type of the generic timer callback event
15static int timer_callback_event_type = -1; 15static 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.
18static Kernel::HandleTable timer_callback_handle_table; 18static Kernel::HandleTable timer_callback_handle_table;
@@ -89,6 +89,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) {
89} 89}
90 90
91void TimersInit() { 91void 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 {
28static const VAddr SHARED_FONT_VADDR = 0x18000000; 28static 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
31static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem = nullptr; 31static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem;
32 32
33static Kernel::SharedPtr<Kernel::Mutex> lock = nullptr; 33static Kernel::SharedPtr<Kernel::Mutex> lock;
34static Kernel::SharedPtr<Kernel::Event> notification_event = nullptr; ///< APT notification event 34static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
35static Kernel::SharedPtr<Kernel::Event> start_event = nullptr; ///< APT start event 35static Kernel::SharedPtr<Kernel::Event> start_event; ///< APT start event
36 36
37static std::vector<u8> shared_font; 37static std::vector<u8> shared_font;
38 38
39static u32 cpu_percent = 0; ///< CPU time available to the running application 39static u32 cpu_percent; ///< CPU time available to the running application
40 40
41void Initialize(Service::Interface* self) { 41void 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
319void Shutdown() { 320void 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
221void Shutdown() { 222void 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
12namespace DSP_DSP { 12namespace DSP_DSP {
13 13
14static u32 read_pipe_count = 0; 14static u32 read_pipe_count;
15static Kernel::SharedPtr<Kernel::Event> semaphore_event; 15static Kernel::SharedPtr<Kernel::Event> semaphore_event;
16static Kernel::SharedPtr<Kernel::Event> interrupt_event; 16static 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 {
20static const int MAX_CIRCLEPAD_POS = 0x9C; ///< Max value for a circle pad position 20static 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
23static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem = nullptr; 23static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
24 24
25// Event handles 25// Event handles
26static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_1 = nullptr; 26static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_1;
27static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_2 = nullptr; 27static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_2;
28static Kernel::SharedPtr<Kernel::Event> event_accelerometer = nullptr; 28static Kernel::SharedPtr<Kernel::Event> event_accelerometer;
29static Kernel::SharedPtr<Kernel::Event> event_gyroscope = nullptr; 29static Kernel::SharedPtr<Kernel::Event> event_gyroscope;
30static Kernel::SharedPtr<Kernel::Event> event_debug_pad = nullptr; 30static Kernel::SharedPtr<Kernel::Event> event_debug_pad;
31 31
32static u32 next_pad_index = 0; 32static u32 next_pad_index;
33static u32 next_touch_index = 0; 33static 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
177void Shutdown() { 177void 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 @@
15namespace Service { 15namespace Service {
16namespace IR { 16namespace IR {
17 17
18static Kernel::SharedPtr<Kernel::Event> handle_event = nullptr; 18static Kernel::SharedPtr<Kernel::Event> handle_event;
19static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory = nullptr; 19static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory;
20 20
21void GetHandles(Service::Interface* self) { 21void 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
43void Shutdown() { 43void 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
12namespace NWM_UDS { 12namespace NWM_UDS {
13 13
14static Kernel::SharedPtr<Kernel::Event> handle_event = nullptr; 14static 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
19static const std::vector<u8> ptm_shared_extdata_id = {0, 0, 0, 0, 0x0B, 0, 0, 0xF0, 0, 0, 0, 0}; 19static const std::vector<u8> ptm_shared_extdata_id = {0, 0, 0, 0, 0x0B, 0, 0, 0xF0, 0, 0, 0, 0};
20 20
21static bool shell_open = true; 21static bool shell_open;
22 22
23static bool battery_is_charging = true; 23static bool battery_is_charging;
24 24
25u32 GetAdapterState() { 25u32 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
12namespace Y2R_U { 12namespace Y2R_U {
13 13
14static Kernel::SharedPtr<Kernel::Event> completion_event = 0; 14static 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);
62template void Read<u8>(u8 &var, const u32 addr); 62template void Read<u8>(u8 &var, const u32 addr);
63 63
64void Set3DSlider(float amount) { 64void 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
76void 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
24void Init(); 24void Init();
25 25
26void 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 {
29Regs g_regs; 29Regs g_regs;
30 30
31/// True if the current frame was skipped 31/// True if the current frame was skipped
32bool g_skip_frame = false; 32bool g_skip_frame;
33
34/// 268MHz / gpu_refresh_rate frames per second 33/// 268MHz / gpu_refresh_rate frames per second
35static u64 frame_ticks; 34static 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
39static u64 frame_count; 38static u64 frame_count;
40/// True if the last frame was skipped 39/// True if the last frame was skipped
41static bool last_skip_frame = false; 40static bool last_skip_frame;
42 41
43template <typename T> 42template <typename T>
44inline void Read(T &var, const u32 raw_addr) { 43inline 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
322void Init() { 321void 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
65void Shutdown() { 65void 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
57void Init() { 57void 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
12namespace Memory { 12namespace Memory {
13 13
14u8* g_base = nullptr; ///< The base pointer to the auto-mirrored arena. 14u8* g_base; ///< The base pointer to the auto-mirrored arena.
15 15
16static MemArena arena; ///< The MemArena class 16static MemArena arena; ///< The MemArena class
17 17
18u8* g_exefs_code = nullptr; ///< ExeFS:/.code is loaded here 18u8* g_exefs_code; ///< ExeFS:/.code is loaded here
19u8* g_system_mem = nullptr; ///< System memory 19u8* g_system_mem; ///< System memory
20u8* g_heap = nullptr; ///< Application heap (main memory) 20u8* g_heap; ///< Application heap (main memory)
21u8* g_heap_linear = nullptr; ///< Linear heap 21u8* g_heap_linear; ///< Linear heap
22u8* g_vram = nullptr; ///< Video memory (VRAM) pointer 22u8* g_vram; ///< Video memory (VRAM) pointer
23u8* g_shared_mem = nullptr; ///< Shared memory 23u8* g_shared_mem; ///< Shared memory
24u8* g_dsp_mem = nullptr; ///< DSP memory 24u8* g_dsp_mem; ///< DSP memory
25u8* g_kernel_mem; ///< Kernel memory 25u8* g_kernel_mem; ///< Kernel memory
26 26
27static u8* physical_bootrom = nullptr; ///< Bootrom physical memory 27static u8* physical_bootrom; ///< Bootrom physical memory
28static u8* uncached_bootrom = nullptr; 28static u8* uncached_bootrom;
29 29
30static u8* physical_exefs_code = nullptr; ///< Phsical ExeFS:/.code is loaded here 30static u8* physical_exefs_code; ///< Phsical ExeFS:/.code is loaded here
31static u8* physical_system_mem = nullptr; ///< System physical memory 31static u8* physical_system_mem; ///< System physical memory
32static u8* physical_fcram = nullptr; ///< Main physical memory (FCRAM) 32static u8* physical_fcram; ///< Main physical memory (FCRAM)
33static u8* physical_heap_gsp = nullptr; ///< GSP heap physical memory 33static u8* physical_heap_gsp; ///< GSP heap physical memory
34static u8* physical_vram = nullptr; ///< Video physical memory (VRAM) 34static u8* physical_vram; ///< Video physical memory (VRAM)
35static u8* physical_shared_mem = nullptr; ///< Physical shared memory 35static u8* physical_shared_mem; ///< Physical shared memory
36static u8* physical_dsp_mem = nullptr; ///< Physical DSP memory 36static u8* physical_dsp_mem; ///< Physical DSP memory
37static u8* physical_kernel_mem; ///< Kernel memory 37static 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.
40static MemoryView g_views[] = { 40static 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() {
81void Shutdown() { 82void 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 */
172u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions); 172u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions);
173 173
174/// Initialize mapped memory blocks
175void MemBlock_Init();
176
177/// Shutdown mapped memory blocks
178void MemBlock_Shutdown();
179
174inline const char* GetCharPointer(const VAddr address) { 180inline 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
16static std::map<u32, MemoryBlock> heap_map; 16static std::map<u32, MemoryBlock> heap_map;
17static std::map<u32, MemoryBlock> heap_linear_map; 17static std::map<u32, MemoryBlock> heap_linear_map;
18static std::map<u32, MemoryBlock> shared_map;
19 18
20/// Convert a physical address to virtual address 19/// Convert a physical address to virtual address
21VAddr PhysicalToVirtualAddress(const PAddr addr) { 20VAddr 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 */
194u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions) { 187u32 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 */
217u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions) { 204u32 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
221void MemBlock_Init() {
222}
223
224void MemBlock_Shutdown() {
225 heap_map.clear();
226 heap_linear_map.clear();
227}
228
234u8 Read8(const VAddr addr) { 229u8 Read8(const VAddr addr) {
235 u8 data = 0; 230 u8 data = 0;
236 Read<u8>(data, addr); 231 Read<u8>(data, addr);