summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitmodules6
-rw-r--r--README.md2
-rw-r--r--src/citra/emu_window/emu_window_glfw.cpp2
-rw-r--r--src/citra_qt/bootmanager.cpp103
-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/graphics_breakpoints_p.h2
-rw-r--r--src/citra_qt/debugger/profiler.cpp4
-rw-r--r--src/citra_qt/debugger/profiler.h2
-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/citra_qt/util/spinbox.cpp3
-rw-r--r--src/common/emu_window.cpp22
-rw-r--r--src/common/emu_window.h5
-rw-r--r--src/common/thread.h81
-rw-r--r--src/core/CMakeLists.txt1
-rw-r--r--src/core/arm/dyncom/arm_dyncom.cpp10
-rw-r--r--src/core/arm/dyncom/arm_dyncom.h2
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp35
-rw-r--r--src/core/arm/interpreter/armcopro.cpp142
-rw-r--r--src/core/arm/interpreter/arminit.cpp39
-rw-r--r--src/core/arm/skyeye_common/armdefs.h83
-rw-r--r--src/core/arm/skyeye_common/armemu.h21
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.cpp621
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.h22
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp_helper.h3
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpsingle.cpp72
-rw-r--r--src/core/core.h3
-rw-r--r--src/core/core_timing.cpp10
-rw-r--r--src/core/file_sys/disk_archive.h2
-rw-r--r--src/core/hle/config_mem.cpp6
-rw-r--r--src/core/hle/config_mem.h2
-rw-r--r--src/core/hle/hle.cpp55
-rw-r--r--src/core/hle/hle.h27
-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.cpp5
-rw-r--r--src/core/hle/service/apt/apt.cpp17
-rw-r--r--src/core/hle/service/cfg/cfg.cpp6
-rw-r--r--src/core/hle/service/dsp_dsp.cpp28
-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/ptm/ptm_sysm.cpp2
-rw-r--r--src/core/hle/service/service.cpp43
-rw-r--r--src/core/hle/service/service.h55
-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/hle/svc.cpp37
-rw-r--r--src/core/hle/svc.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/loader/ncch.cpp33
-rw-r--r--src/core/loader/ncch.h18
-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
-rw-r--r--src/core/system.cpp12
-rw-r--r--src/core/system.h21
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp2
-rw-r--r--src/video_core/rasterizer.cpp4
69 files changed, 661 insertions, 1537 deletions
diff --git a/.gitmodules b/.gitmodules
index a9e0a5c1a..598e4c64d 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,9 +1,9 @@
-[submodule "externals/inih/inih"]
+[submodule "inih"]
path = externals/inih/inih
url = https://github.com/svn2github/inih
-[submodule "externals/boost"]
+[submodule "boost"]
path = externals/boost
url = https://github.com/citra-emu/ext-boost.git
-[submodule "externals/nihstro"]
+[submodule "nihstro"]
path = externals/nihstro
url = https://github.com/neobrain/nihstro.git
diff --git a/README.md b/README.md
index 40a380f50..af65f2b0e 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ Citra Emulator
Citra is an experimental open-source Nintendo 3DS emulator/debugger written in C++. It is written with portability in mind, with builds actively maintained for Windows, Linux and OS X. Citra only emulates a subset of 3DS hardware, and therefore is generally only useful for running/debugging homebrew applications. At this time, Citra is even able to boot several commercial games! Most of these do not run to a playable state, but we are working every day to advance the project forward.
-Citra is licensed under the GPLv2. Refer to the license.txt file included. Please read the [FAQ](https://github.com/citra-emu/citra/wiki/FAQ) before getting started with the project.
+Citra is licensed under the GPLv2 (or any later version). Refer to the license.txt file included. Please read the [FAQ](https://github.com/citra-emu/citra/wiki/FAQ) before getting started with the project.
For development discussion, please join us @ #citra on [freenode](http://webchat.freenode.net/?channels=citra).
diff --git a/src/citra/emu_window/emu_window_glfw.cpp b/src/citra/emu_window/emu_window_glfw.cpp
index 997e3bc7d..f879ee7ca 100644
--- a/src/citra/emu_window/emu_window_glfw.cpp
+++ b/src/citra/emu_window/emu_window_glfw.cpp
@@ -31,7 +31,7 @@ void EmuWindow_GLFW::OnMouseButtonEvent(GLFWwindow* win, int button, int action,
}
void EmuWindow_GLFW::OnCursorPosEvent(GLFWwindow* win, double x, double y) {
- GetEmuWindow(win)->TouchMoved(static_cast<unsigned>(x), static_cast<unsigned>(y));
+ GetEmuWindow(win)->TouchMoved(static_cast<unsigned>(std::max(x, 0.0)), static_cast<unsigned>(std::max(y, 0.0)));
}
/// Called by GLFW when a key event occurs
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index b81bd6167..a7f949411 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -10,6 +10,7 @@
#include "common/common.h"
#include "bootmanager.h"
+#include "main.h"
#include "core/core.h"
#include "core/settings.h"
@@ -27,43 +28,33 @@
#define COPYRIGHT "Copyright (C) 2013-2014 Citra Team"
EmuThread::EmuThread(GRenderWindow* render_window) :
- filename(""), exec_cpu_step(false), cpu_running(false),
- stop_run(false), render_window(render_window)
-{
-}
+ exec_step(false), running(false), stop_run(false), render_window(render_window) {
-void EmuThread::SetFilename(std::string filename)
-{
- this->filename = filename;
+ connect(this, SIGNAL(started()), render_window, SLOT(moveContext()));
}
-void EmuThread::run()
-{
+void EmuThread::run() {
stop_run = false;
// holds whether the cpu was running during the last iteration,
// so that the DebugModeLeft signal can be emitted before the
// next execution step
bool was_active = false;
- while (!stop_run)
- {
- if (cpu_running)
- {
+ while (!stop_run) {
+ if (running) {
if (!was_active)
emit DebugModeLeft();
Core::RunLoop();
- was_active = cpu_running || exec_cpu_step;
- if (!was_active)
+ was_active = running || exec_step;
+ if (!was_active && !stop_run)
emit DebugModeEntered();
- }
- else if (exec_cpu_step)
- {
+ } else if (exec_step) {
if (!was_active)
emit DebugModeLeft();
- exec_cpu_step = false;
+ exec_step = false;
Core::SingleStep();
emit DebugModeEntered();
yieldCurrentThread();
@@ -71,47 +62,10 @@ void EmuThread::run()
was_active = false;
}
}
- render_window->moveContext();
-
- Core::Stop();
-}
-
-void EmuThread::Stop()
-{
- if (!isRunning())
- {
- LOG_WARNING(Frontend, "EmuThread::Stop called while emu thread wasn't running, returning...");
- return;
- }
- stop_run = true;
- // Release emu threads from any breakpoints, so that this doesn't hang forever.
- Pica::g_debug_context->ClearBreakpoints();
-
- //core::g_state = core::SYS_DIE;
-
- // TODO: Waiting here is just a bad workaround for retarded shutdown logic.
- wait(1000);
- if (isRunning())
- {
- LOG_WARNING(Frontend, "EmuThread still running, terminating...");
- quit();
-
- // TODO: Waiting 50 seconds can be necessary if the logging subsystem has a lot of spam
- // queued... This should be fixed.
- wait(50000);
- if (isRunning())
- {
- LOG_CRITICAL(Frontend, "EmuThread STILL running, something is wrong here...");
- terminate();
- }
- }
- LOG_INFO(Frontend, "EmuThread stopped");
-
- System::Shutdown();
+ render_window->moveContext();
}
-
// This class overrides paintEvent and resizeEvent to prevent the GUI thread from stealing GL context.
// The corresponding functionality is handled in EmuThread instead
class GGLWidgetInternal : public QGLWidget
@@ -133,13 +87,9 @@ private:
GRenderWindow* parent;
};
-EmuThread& GRenderWindow::GetEmuThread()
-{
- return emu_thread;
-}
+GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread) :
+ QWidget(parent), emu_thread(emu_thread), keyboard_id(0) {
-GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this), keyboard_id(0)
-{
std::string window_title = Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc);
setWindowTitle(QString::fromStdString(window_title));
@@ -160,7 +110,6 @@ GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this
layout->addWidget(child);
layout->setMargin(0);
setLayout(layout);
- connect(&emu_thread, SIGNAL(started()), this, SLOT(moveContext()));
OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
@@ -180,29 +129,17 @@ void GRenderWindow::moveContext()
// We need to move GL context to the swapping thread in Qt5
#if QT_VERSION > QT_VERSION_CHECK(5, 0, 0)
// If the thread started running, move the GL Context to the new thread. Otherwise, move it back.
- child->context()->moveToThread((QThread::currentThread() == qApp->thread()) ? &emu_thread : qApp->thread());
+ auto thread = (QThread::currentThread() == qApp->thread() && emu_thread != nullptr) ? emu_thread : qApp->thread();
+ child->context()->moveToThread(thread);
#endif
}
-GRenderWindow::~GRenderWindow()
-{
- if (emu_thread.isRunning())
- emu_thread.Stop();
-}
-
void GRenderWindow::SwapBuffers()
{
// MakeCurrent is already called in renderer_opengl
child->swapBuffers();
}
-void GRenderWindow::closeEvent(QCloseEvent* event)
-{
- if (emu_thread.isRunning())
- emu_thread.Stop();
- QWidget::closeEvent(event);
-}
-
void GRenderWindow::MakeCurrent()
{
child->makeCurrent();
@@ -288,7 +225,7 @@ void GRenderWindow::mousePressEvent(QMouseEvent *event)
void GRenderWindow::mouseMoveEvent(QMouseEvent *event)
{
auto pos = event->pos();
- this->TouchMoved(static_cast<unsigned>(pos.x()), static_cast<unsigned>(pos.y()));
+ this->TouchMoved(static_cast<unsigned>(std::max(pos.x(), 0)), static_cast<unsigned>(std::max(pos.y(), 0)));
}
void GRenderWindow::mouseReleaseEvent(QMouseEvent *event)
@@ -335,3 +272,11 @@ void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height)
void GRenderWindow::OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) {
setMinimumSize(minimal_size.first, minimal_size.second);
}
+
+void GRenderWindow::OnEmulationStarting(EmuThread* emu_thread) {
+ this->emu_thread = emu_thread;
+}
+
+void GRenderWindow::OnEmulationStopping() {
+ emu_thread = nullptr;
+}
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 @@
#include "common/common.h"
#include "common/emu_window.h"
+#include "common/thread.h"
class QScreen;
class QKeyEvent;
class GRenderWindow;
+class GMainWindow;
class EmuThread : public QThread
{
Q_OBJECT
public:
- /**
- * Set image filename
- *
- * @param filename
- * @warning Only call when not running!
- */
- void SetFilename(std::string filename);
+ EmuThread(GRenderWindow* render_window);
/**
* Start emulation (on new thread)
- *
* @warning Only call when not running!
*/
void run() override;
/**
- * Allow the CPU to process a single instruction (if cpu is not running)
- *
+ * Steps the emulation thread by a single CPU instruction (if the CPU is not already running)
* @note This function is thread-safe
*/
- void ExecStep() { exec_cpu_step = true; }
+ void ExecStep() { exec_step = true; }
/**
- * Allow the CPU to continue processing instructions without interruption
- *
+ * Sets whether the emulation thread is running or not
+ * @param running Boolean value, set the emulation thread to running if true
* @note This function is thread-safe
*/
- void SetCpuRunning(bool running) { cpu_running = running; }
+ void SetRunning(bool running) { this->running = running; }
/**
- * Allow the CPU to continue processing instructions without interruption
- *
- * @note This function is thread-safe
- */
- bool IsCpuRunning() { return cpu_running; }
-
+ * Check if the emulation thread is running or not
+ * @return True if the emulation thread is running, otherwise false
+ * @note This function is thread-safe
+ */
+ bool IsRunning() { return running; }
-public slots:
/**
- * Stop emulation and wait for the thread to finish.
- *
- * @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.
- * @note: This function is thread-safe.
+ * Requests for the emulation thread to stop running
*/
- void Stop();
+ void RequestStop() {
+ stop_run = true;
+ running = false;
+ };
private:
- friend class GRenderWindow;
-
- EmuThread(GRenderWindow* render_window);
-
- std::string filename;
-
- bool exec_cpu_step;
- bool cpu_running;
+ bool exec_step;
+ bool running;
std::atomic<bool> stop_run;
GRenderWindow* render_window;
@@ -100,10 +86,7 @@ class GRenderWindow : public QWidget, public EmuWindow
Q_OBJECT
public:
- GRenderWindow(QWidget* parent = NULL);
- ~GRenderWindow();
-
- void closeEvent(QCloseEvent*) override;
+ GRenderWindow(QWidget* parent, EmuThread* emu_thread);
// EmuWindow implementation
void SwapBuffers() override;
@@ -116,8 +99,6 @@ public:
void restoreGeometry(const QByteArray& geometry); // overridden
QByteArray saveGeometry(); // overridden
- EmuThread& GetEmuThread();
-
void keyPressEvent(QKeyEvent* event) override;
void keyReleaseEvent(QKeyEvent* event) override;
@@ -134,15 +115,18 @@ public:
public slots:
void moveContext(); // overridden
+ void OnEmulationStarting(EmuThread* emu_thread);
+ void OnEmulationStopping();
+
private:
void OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) override;
QGLWidget* child;
- EmuThread emu_thread;
-
QByteArray geometry;
/// Device id of keyboard for use with KeyMap
int keyboard_id;
+
+ EmuThread* emu_thread;
};
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 @@
#include "core/arm/disassembler/arm_disasm.h"
-DisassemblerModel::DisassemblerModel(QObject* parent) : QAbstractListModel(parent), base_address(0), code_size(0), program_counter(0), selection(QModelIndex()) {
-
+DisassemblerModel::DisassemblerModel(QObject* parent) :
+ QAbstractListModel(parent), base_address(0), code_size(0), program_counter(0), selection(QModelIndex()) {
}
int DisassemblerModel::columnCount(const QModelIndex& parent) const {
@@ -158,34 +158,28 @@ void DisassemblerModel::SetNextInstruction(unsigned int address) {
emit dataChanged(prev_index, prev_index);
}
-DisassemblerWidget::DisassemblerWidget(QWidget* parent, EmuThread& emu_thread) : QDockWidget(parent), base_addr(0), emu_thread(emu_thread)
-{
- disasm_ui.setupUi(this);
+DisassemblerWidget::DisassemblerWidget(QWidget* parent, EmuThread* emu_thread) :
+ QDockWidget(parent), emu_thread(emu_thread), base_addr(0) {
- model = new DisassemblerModel(this);
- disasm_ui.treeView->setModel(model);
+ disasm_ui.setupUi(this);
RegisterHotkey("Disassembler", "Start/Stop", QKeySequence(Qt::Key_F5), Qt::ApplicationShortcut);
RegisterHotkey("Disassembler", "Step", QKeySequence(Qt::Key_F10), Qt::ApplicationShortcut);
RegisterHotkey("Disassembler", "Step into", QKeySequence(Qt::Key_F11), Qt::ApplicationShortcut);
RegisterHotkey("Disassembler", "Set Breakpoint", QKeySequence(Qt::Key_F9), Qt::ApplicationShortcut);
- connect(disasm_ui.button_breakpoint, SIGNAL(clicked()), model, SLOT(OnSetOrUnsetBreakpoint()));
connect(disasm_ui.button_step, SIGNAL(clicked()), this, SLOT(OnStep()));
connect(disasm_ui.button_pause, SIGNAL(clicked()), this, SLOT(OnPause()));
connect(disasm_ui.button_continue, SIGNAL(clicked()), this, SLOT(OnContinue()));
- connect(disasm_ui.treeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
- model, SLOT(OnSelectionChanged(const QModelIndex&)));
-
connect(GetHotkey("Disassembler", "Start/Stop", this), SIGNAL(activated()), this, SLOT(OnToggleStartStop()));
connect(GetHotkey("Disassembler", "Step", this), SIGNAL(activated()), this, SLOT(OnStep()));
connect(GetHotkey("Disassembler", "Step into", this), SIGNAL(activated()), this, SLOT(OnStepInto()));
- connect(GetHotkey("Disassembler", "Set Breakpoint", this), SIGNAL(activated()), model, SLOT(OnSetOrUnsetBreakpoint()));
+
+ setEnabled(false);
}
-void DisassemblerWidget::Init()
-{
+void DisassemblerWidget::Init() {
model->ParseFromAddress(Core::g_app_core->GetPC());
disasm_ui.treeView->resizeColumnToContents(0);
@@ -197,25 +191,21 @@ void DisassemblerWidget::Init()
disasm_ui.treeView->selectionModel()->setCurrentIndex(model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
}
-void DisassemblerWidget::OnContinue()
-{
- emu_thread.SetCpuRunning(true);
+void DisassemblerWidget::OnContinue() {
+ emu_thread->SetRunning(true);
}
-void DisassemblerWidget::OnStep()
-{
+void DisassemblerWidget::OnStep() {
OnStepInto(); // change later
}
-void DisassemblerWidget::OnStepInto()
-{
- emu_thread.SetCpuRunning(false);
- emu_thread.ExecStep();
+void DisassemblerWidget::OnStepInto() {
+ emu_thread->SetRunning(false);
+ emu_thread->ExecStep();
}
-void DisassemblerWidget::OnPause()
-{
- emu_thread.SetCpuRunning(false);
+void DisassemblerWidget::OnPause() {
+ emu_thread->SetRunning(false);
// TODO: By now, the CPU might not have actually stopped...
if (Core::g_app_core) {
@@ -223,17 +213,15 @@ void DisassemblerWidget::OnPause()
}
}
-void DisassemblerWidget::OnToggleStartStop()
-{
- emu_thread.SetCpuRunning(!emu_thread.IsCpuRunning());
+void DisassemblerWidget::OnToggleStartStop() {
+ emu_thread->SetRunning(!emu_thread->IsRunning());
}
-void DisassemblerWidget::OnDebugModeEntered()
-{
+void DisassemblerWidget::OnDebugModeEntered() {
ARMword next_instr = Core::g_app_core->GetPC();
if (model->GetBreakPoints().IsAddressBreakPoint(next_instr))
- emu_thread.SetCpuRunning(false);
+ emu_thread->SetRunning(false);
model->SetNextInstruction(next_instr);
@@ -242,16 +230,35 @@ void DisassemblerWidget::OnDebugModeEntered()
disasm_ui.treeView->selectionModel()->setCurrentIndex(model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
}
-void DisassemblerWidget::OnDebugModeLeft()
-{
-
+void DisassemblerWidget::OnDebugModeLeft() {
}
-int DisassemblerWidget::SelectedRow()
-{
+int DisassemblerWidget::SelectedRow() {
QModelIndex index = disasm_ui.treeView->selectionModel()->currentIndex();
if (!index.isValid())
return -1;
return disasm_ui.treeView->selectionModel()->currentIndex().row();
}
+
+void DisassemblerWidget::OnEmulationStarting(EmuThread* emu_thread) {
+ this->emu_thread = emu_thread;
+
+ model = new DisassemblerModel(this);
+ disasm_ui.treeView->setModel(model);
+
+ connect(disasm_ui.treeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
+ model, SLOT(OnSelectionChanged(const QModelIndex&)));
+ connect(disasm_ui.button_breakpoint, SIGNAL(clicked()), model, SLOT(OnSetOrUnsetBreakpoint()));
+ connect(GetHotkey("Disassembler", "Set Breakpoint", this), SIGNAL(activated()), model, SLOT(OnSetOrUnsetBreakpoint()));
+
+ Init();
+ setEnabled(true);
+}
+
+void DisassemblerWidget::OnEmulationStopping() {
+ disasm_ui.treeView->setModel(nullptr);
+ delete model;
+ emu_thread = nullptr;
+ setEnabled(false);
+}
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
Q_OBJECT
public:
- DisassemblerWidget(QWidget* parent, EmuThread& emu_thread);
+ DisassemblerWidget(QWidget* parent, EmuThread* emu_thread);
void Init();
@@ -65,6 +65,9 @@ public slots:
void OnDebugModeEntered();
void OnDebugModeLeft();
+ void OnEmulationStarting(EmuThread* emu_thread);
+ void OnEmulationStopping();
+
private:
// returns -1 if no row is selected
int SelectedRow();
@@ -75,5 +78,5 @@ private:
u32 base_addr;
- EmuThread& emu_thread;
+ EmuThread* emu_thread;
};
diff --git a/src/citra_qt/debugger/graphics_breakpoints_p.h b/src/citra_qt/debugger/graphics_breakpoints_p.h
index 232bfc863..34e72e859 100644
--- a/src/citra_qt/debugger/graphics_breakpoints_p.h
+++ b/src/citra_qt/debugger/graphics_breakpoints_p.h
@@ -25,7 +25,7 @@ public:
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
- bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
+ bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
public slots:
void OnBreakPointHit(Pica::DebugContext::Event event);
diff --git a/src/citra_qt/debugger/profiler.cpp b/src/citra_qt/debugger/profiler.cpp
index ae0568b6a..2ac1748b7 100644
--- a/src/citra_qt/debugger/profiler.cpp
+++ b/src/citra_qt/debugger/profiler.cpp
@@ -26,7 +26,7 @@ static QVariant GetDataForColumn(int col, const AggregatedDuration& duration)
static const TimingCategoryInfo* GetCategoryInfo(int id)
{
const auto& categories = GetProfilingManager().GetTimingCategoriesInfo();
- if (id >= categories.size()) {
+ if ((size_t)id >= categories.size()) {
return nullptr;
} else {
return &categories[id];
@@ -98,7 +98,7 @@ QVariant ProfilerModel::data(const QModelIndex& index, int role) const
const TimingCategoryInfo* info = GetCategoryInfo(index.row() - 2);
return info != nullptr ? QString(info->name) : QVariant();
} else {
- if (index.row() - 2 < results.time_per_category.size()) {
+ if (index.row() - 2 < (int)results.time_per_category.size()) {
return GetDataForColumn(index.column(), results.time_per_category[index.row() - 2]);
} else {
return QVariant();
diff --git a/src/citra_qt/debugger/profiler.h b/src/citra_qt/debugger/profiler.h
index a6d87aa0f..fabf279b8 100644
--- a/src/citra_qt/debugger/profiler.h
+++ b/src/citra_qt/debugger/profiler.h
@@ -18,7 +18,7 @@ class ProfilerModel : public QAbstractItemModel
public:
ProfilerModel(QObject* parent);
- QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex& child) const override;
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
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 @@
#include "core/core.h"
#include "core/arm/arm_interface.h"
-RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent)
-{
+RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent) {
cpu_regs_ui.setupUi(this);
tree = cpu_regs_ui.treeWidget;
@@ -18,8 +17,7 @@ RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent)
registers->setExpanded(true);
CSPR->setExpanded(true);
- for (int i = 0; i < 16; ++i)
- {
+ for (int i = 0; i < 16; ++i) {
QTreeWidgetItem* child = new QTreeWidgetItem(QStringList(QString("R[%1]").arg(i, 2, 10, QLatin1Char('0'))));
registers->addChild(child);
}
@@ -39,12 +37,16 @@ RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent)
CSPR->addChild(new QTreeWidgetItem(QStringList("C")));
CSPR->addChild(new QTreeWidgetItem(QStringList("Z")));
CSPR->addChild(new QTreeWidgetItem(QStringList("N")));
+
+ setEnabled(false);
}
-void RegistersWidget::OnDebugModeEntered()
-{
+void RegistersWidget::OnDebugModeEntered() {
ARM_Interface* app_core = Core::g_app_core;
+ if (app_core == nullptr)
+ return;
+
for (int i = 0; i < 16; ++i)
registers->child(i)->setText(1, QString("0x%1").arg(app_core->GetReg(i), 8, 16, QLatin1Char('0')));
@@ -66,7 +68,22 @@ void RegistersWidget::OnDebugModeEntered()
CSPR->child(14)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 31) & 0x1)); // N - Negative/Less than
}
-void RegistersWidget::OnDebugModeLeft()
-{
+void RegistersWidget::OnDebugModeLeft() {
+}
+
+void RegistersWidget::OnEmulationStarting(EmuThread* emu_thread) {
+ setEnabled(true);
+}
+
+void RegistersWidget::OnEmulationStopping() {
+ // Reset widget text
+ for (int i = 0; i < 16; ++i)
+ registers->child(i)->setText(1, QString(""));
+
+ for (int i = 0; i < 15; ++i)
+ CSPR->child(i)->setText(1, QString(""));
+
+ CSPR->setText(1, QString(""));
+ setEnabled(false);
}
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 @@
#include <QTreeWidgetItem>
class QTreeWidget;
+class EmuThread;
class RegistersWidget : public QDockWidget
{
@@ -20,6 +21,9 @@ public slots:
void OnDebugModeEntered();
void OnDebugModeLeft();
+ void OnEmulationStarting(EmuThread* emu_thread);
+ void OnEmulationStopping();
+
private:
Ui::ARMRegisters cpu_regs_ui;
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 @@
#include "common/logging/log.h"
#include "common/logging/backend.h"
#include "common/logging/filter.h"
+#include "common/make_unique.h"
#include "common/platform.h"
#include "common/scope_exit.h"
@@ -46,7 +47,7 @@
#include "version.h"
-GMainWindow::GMainWindow()
+GMainWindow::GMainWindow() : emu_thread(nullptr)
{
Pica::g_debug_context = Pica::DebugContext::Construct();
@@ -55,14 +56,14 @@ GMainWindow::GMainWindow()
ui.setupUi(this);
statusBar()->hide();
- render_window = new GRenderWindow;
+ render_window = new GRenderWindow(this, emu_thread.get());
render_window->hide();
profilerWidget = new ProfilerWidget(this);
addDockWidget(Qt::BottomDockWidgetArea, profilerWidget);
profilerWidget->hide();
- disasmWidget = new DisassemblerWidget(this, render_window->GetEmuThread());
+ disasmWidget = new DisassemblerWidget(this, emu_thread.get());
addDockWidget(Qt::BottomDockWidgetArea, disasmWidget);
disasmWidget->hide();
@@ -138,14 +139,12 @@ GMainWindow::GMainWindow()
connect(ui.action_Single_Window_Mode, SIGNAL(triggered(bool)), this, SLOT(ToggleWindowMode()));
connect(ui.action_Hotkeys, SIGNAL(triggered()), this, SLOT(OnOpenHotkeysDialog()));
- // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views before the CPU continues
- connect(&render_window->GetEmuThread(), SIGNAL(DebugModeEntered()), disasmWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection);
- connect(&render_window->GetEmuThread(), SIGNAL(DebugModeEntered()), registersWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection);
- connect(&render_window->GetEmuThread(), SIGNAL(DebugModeEntered()), callstackWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection);
-
- connect(&render_window->GetEmuThread(), SIGNAL(DebugModeLeft()), disasmWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection);
- connect(&render_window->GetEmuThread(), SIGNAL(DebugModeLeft()), registersWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection);
- connect(&render_window->GetEmuThread(), SIGNAL(DebugModeLeft()), callstackWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection);
+ connect(this, SIGNAL(EmulationStarting(EmuThread*)), disasmWidget, SLOT(OnEmulationStarting(EmuThread*)));
+ connect(this, SIGNAL(EmulationStopping()), disasmWidget, SLOT(OnEmulationStopping()));
+ connect(this, SIGNAL(EmulationStarting(EmuThread*)), registersWidget, SLOT(OnEmulationStarting(EmuThread*)));
+ connect(this, SIGNAL(EmulationStopping()), registersWidget, SLOT(OnEmulationStopping()));
+ connect(this, SIGNAL(EmulationStarting(EmuThread*)), render_window, SLOT(OnEmulationStarting(EmuThread*)));
+ connect(this, SIGNAL(EmulationStopping()), render_window, SLOT(OnEmulationStopping()));
// Setup hotkeys
RegisterHotkey("Main Window", "Load File", QKeySequence::Open);
@@ -196,32 +195,76 @@ void GMainWindow::OnDisplayTitleBars(bool show)
}
}
-void GMainWindow::BootGame(std::string filename)
-{
+void GMainWindow::BootGame(std::string filename) {
LOG_INFO(Frontend, "Citra starting...\n");
+
+ // Initialize the core emulation
System::Init(render_window);
- // Load a game or die...
+ // Load the game
if (Loader::ResultStatus::Success != Loader::LoadFile(filename)) {
LOG_CRITICAL(Frontend, "Failed to load ROM!");
+ System::Shutdown();
+ return;
}
- disasmWidget->Init();
+ // Create and start the emulation thread
+ emu_thread = Common::make_unique<EmuThread>(render_window);
+ emit EmulationStarting(emu_thread.get());
+ emu_thread->start();
+
+ // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views before the CPU continues
+ connect(emu_thread.get(), SIGNAL(DebugModeEntered()), disasmWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection);
+ connect(emu_thread.get(), SIGNAL(DebugModeEntered()), registersWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection);
+ connect(emu_thread.get(), SIGNAL(DebugModeEntered()), callstackWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection);
+ connect(emu_thread.get(), SIGNAL(DebugModeLeft()), disasmWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection);
+ connect(emu_thread.get(), SIGNAL(DebugModeLeft()), registersWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection);
+ connect(emu_thread.get(), SIGNAL(DebugModeLeft()), callstackWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection);
+
+ // Update the GUI
registersWidget->OnDebugModeEntered();
callstackWidget->OnDebugModeEntered();
-
- render_window->GetEmuThread().SetFilename(filename);
- render_window->GetEmuThread().start();
-
render_window->show();
+
OnStartGame();
}
+void GMainWindow::ShutdownGame() {
+ emu_thread->RequestStop();
+
+ // Release emu threads from any breakpoints
+ // This belongs after RequestStop() and before wait() because if emulation stops on a GPU
+ // breakpoint after (or before) RequestStop() is called, the emulation would never be able
+ // to continue out to the main loop and terminate. Thus wait() would hang forever.
+ // TODO(bunnei): This function is not thread safe, but it's being used as if it were
+ Pica::g_debug_context->ClearBreakpoints();
+
+ emit EmulationStopping();
+
+ // Wait for emulation thread to complete and delete it
+ emu_thread->wait();
+ emu_thread = nullptr;
+
+ // Shutdown the core emulation
+ System::Shutdown();
+
+ // Update the GUI
+ ui.action_Start->setEnabled(false);
+ ui.action_Pause->setEnabled(false);
+ ui.action_Stop->setEnabled(false);
+ render_window->hide();
+}
+
void GMainWindow::OnMenuLoadFile()
{
QString filename = QFileDialog::getOpenFileName(this, tr("Load File"), QString(), tr("3DS executable (*.3ds *.3dsx *.elf *.axf *.bin *.cci *.cxi)"));
- if (filename.size())
- BootGame(filename.toLatin1().data());
+ if (filename.size()) {
+ // Shutdown previous session if the emu thread is still active...
+ if (emu_thread != nullptr)
+ ShutdownGame();
+
+ BootGame(filename.toLatin1().data());
+ }
}
void GMainWindow::OnMenuLoadSymbolMap() {
@@ -232,7 +275,7 @@ void GMainWindow::OnMenuLoadSymbolMap() {
void GMainWindow::OnStartGame()
{
- render_window->GetEmuThread().SetCpuRunning(true);
+ emu_thread->SetRunning(true);
ui.action_Start->setEnabled(false);
ui.action_Pause->setEnabled(true);
@@ -241,21 +284,15 @@ void GMainWindow::OnStartGame()
void GMainWindow::OnPauseGame()
{
- render_window->GetEmuThread().SetCpuRunning(false);
+ emu_thread->SetRunning(false);
ui.action_Start->setEnabled(true);
ui.action_Pause->setEnabled(false);
ui.action_Stop->setEnabled(true);
}
-void GMainWindow::OnStopGame()
-{
- render_window->GetEmuThread().SetCpuRunning(false);
- // TODO: Shutdown core
-
- ui.action_Start->setEnabled(true);
- ui.action_Pause->setEnabled(false);
- ui.action_Stop->setEnabled(false);
+void GMainWindow::OnStopGame() {
+ ShutdownGame();
}
void GMainWindow::OnOpenHotkeysDialog()
@@ -265,24 +302,22 @@ void GMainWindow::OnOpenHotkeysDialog()
}
-void GMainWindow::ToggleWindowMode()
-{
- bool enable = ui.action_Single_Window_Mode->isChecked();
- if (!enable && render_window->parent() != nullptr)
- {
- ui.horizontalLayout->removeWidget(render_window);
- render_window->setParent(nullptr);
- render_window->setVisible(true);
- render_window->RestoreGeometry();
- render_window->setFocusPolicy(Qt::NoFocus);
- }
- else if (enable && render_window->parent() == nullptr)
- {
+void GMainWindow::ToggleWindowMode() {
+ if (ui.action_Single_Window_Mode->isChecked()) {
+ // Render in the main window...
render_window->BackupGeometry();
ui.horizontalLayout->addWidget(render_window);
render_window->setVisible(true);
render_window->setFocusPolicy(Qt::ClickFocus);
render_window->setFocus();
+
+ } else {
+ // Render in a separate window...
+ ui.horizontalLayout->removeWidget(render_window);
+ render_window->setParent(nullptr);
+ render_window->setVisible(true);
+ render_window->RestoreGeometry();
+ render_window->setFocusPolicy(Qt::NoFocus);
}
}
@@ -303,6 +338,8 @@ void GMainWindow::closeEvent(QCloseEvent* event)
settings.setValue("firstStart", false);
SaveHotkeys(settings);
+ ShutdownGame();
+
render_window->close();
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 @@
#ifndef _CITRA_QT_MAIN_HXX_
#define _CITRA_QT_MAIN_HXX_
+#include <memory>
#include <QMainWindow>
#include "ui_main.h"
class GImageInfo;
class GRenderWindow;
+class EmuThread;
class ProfilerWidget;
class DisassemblerWidget;
class RegistersWidget;
@@ -34,8 +36,27 @@ public:
GMainWindow();
~GMainWindow();
+signals:
+
+ /**
+ * Signal that is emitted when a new EmuThread has been created and an emulation session is
+ * about to start. At this time, the core system emulation has been initialized, and all
+ * emulation handles and memory should be valid.
+ *
+ * @param emu_thread Pointer to the newly created EmuThread (to be used by widgets that need to
+ * access/change emulation state).
+ */
+ void EmulationStarting(EmuThread* emu_thread);
+
+ /**
+ * Signal that is emitted when emulation is about to stop. At this time, the EmuThread and core
+ * system emulation handles and memory are still valid, but are about become invalid.
+ */
+ void EmulationStopping();
+
private:
void BootGame(std::string filename);
+ void ShutdownGame();
void closeEvent(QCloseEvent* event) override;
@@ -55,6 +76,8 @@ private:
GRenderWindow* render_window;
+ std::unique_ptr<EmuThread> emu_thread;
+
ProfilerWidget* profilerWidget;
DisassemblerWidget* disasmWidget;
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 @@
</property>
</action>
<action name="action_Start">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
<property name="text">
<string>&amp;Start</string>
</property>
diff --git a/src/citra_qt/util/spinbox.cpp b/src/citra_qt/util/spinbox.cpp
index 2e2076a27..de4060116 100644
--- a/src/citra_qt/util/spinbox.cpp
+++ b/src/citra_qt/util/spinbox.cpp
@@ -29,6 +29,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include <cstdlib>
#include <QLineEdit>
#include <QRegExpValidator>
@@ -206,7 +207,7 @@ QString CSpinBox::TextFromValue()
{
return prefix
+ QString(HasSign() ? ((value < 0) ? "-" : "+") : "")
- + QString("%1").arg(abs(value), num_digits, base, QLatin1Char('0')).toUpper()
+ + QString("%1").arg(std::abs(value), num_digits, base, QLatin1Char('0')).toUpper()
+ suffix;
}
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp
index 6516fc633..f5b6c7301 100644
--- a/src/common/emu_window.cpp
+++ b/src/common/emu_window.cpp
@@ -28,6 +28,17 @@ static bool IsWithinTouchscreen(const EmuWindow::FramebufferLayout& layout, unsi
framebuffer_x < layout.bottom_screen.right);
}
+std::tuple<unsigned,unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) {
+
+ new_x = std::max(new_x, framebuffer_layout.bottom_screen.left);
+ new_x = std::min(new_x, framebuffer_layout.bottom_screen.right-1);
+
+ new_y = std::max(new_y, framebuffer_layout.bottom_screen.top);
+ new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom-1);
+
+ return std::make_tuple(new_x, new_y);
+}
+
void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) {
if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
return;
@@ -52,14 +63,13 @@ void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) {
if (!touch_pressed)
return;
- if (IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
- TouchPressed(framebuffer_x, framebuffer_y);
- else
- TouchReleased();
+ if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
+ std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y);
+
+ TouchPressed(framebuffer_x, framebuffer_y);
}
-EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width,
- unsigned height) {
+EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width, unsigned height) {
ASSERT(width > 0);
ASSERT(height > 0);
diff --git a/src/common/emu_window.h b/src/common/emu_window.h
index c8e2de04a..e0fc12a48 100644
--- a/src/common/emu_window.h
+++ b/src/common/emu_window.h
@@ -206,5 +206,10 @@ private:
u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320)
u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240)
+ /**
+ * Clip the provided coordinates to be inside the touchscreen area.
+ */
+ std::tuple<unsigned,unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y);
+
Service::HID::PadState pad_state;
};
diff --git a/src/common/thread.h b/src/common/thread.h
index a45728e1e..5fdb6baeb 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -51,109 +51,60 @@ int CurrentThreadId();
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask);
void SetCurrentThreadAffinity(u32 mask);
-class Event
-{
+class Event {
public:
- Event()
- : is_set(false)
- {}
+ Event() : is_set(false) {}
- void Set()
- {
+ void Set() {
std::lock_guard<std::mutex> lk(m_mutex);
- if (!is_set)
- {
+ if (!is_set) {
is_set = true;
m_condvar.notify_one();
}
}
- void Wait()
- {
+ void Wait() {
std::unique_lock<std::mutex> lk(m_mutex);
- m_condvar.wait(lk, IsSet(this));
+ m_condvar.wait(lk, [&]{ return is_set; });
is_set = false;
}
- void Reset()
- {
+ void Reset() {
std::unique_lock<std::mutex> lk(m_mutex);
// no other action required, since wait loops on the predicate and any lingering signal will get cleared on the first iteration
is_set = false;
}
private:
- class IsSet
- {
- public:
- IsSet(const Event* ev)
- : m_event(ev)
- {}
-
- bool operator()()
- {
- return m_event->is_set;
- }
-
- private:
- const Event* const m_event;
- };
-
- volatile bool is_set;
+ bool is_set;
std::condition_variable m_condvar;
std::mutex m_mutex;
};
-// TODO: doesn't work on windows with (count > 2)
-class Barrier
-{
+class Barrier {
public:
- Barrier(size_t count)
- : m_count(count), m_waiting(0)
- {}
+ Barrier(size_t count) : m_count(count), m_waiting(0) {}
- // block until "count" threads call Sync()
- bool Sync()
- {
+ /// Blocks until all "count" threads have called Sync()
+ void Sync() {
std::unique_lock<std::mutex> lk(m_mutex);
// TODO: broken when next round of Sync()s
// is entered before all waiting threads return from the notify_all
- if (m_count == ++m_waiting)
- {
+ if (++m_waiting == m_count) {
m_waiting = 0;
m_condvar.notify_all();
- return true;
- }
- else
- {
- m_condvar.wait(lk, IsDoneWating(this));
- return false;
+ } else {
+ m_condvar.wait(lk, [&]{ return m_waiting == 0; });
}
}
private:
- class IsDoneWating
- {
- public:
- IsDoneWating(const Barrier* bar)
- : m_bar(bar)
- {}
-
- bool operator()()
- {
- return (0 == m_bar->m_waiting);
- }
-
- private:
- const Barrier* const m_bar;
- };
-
std::condition_variable m_condvar;
std::mutex m_mutex;
const size_t m_count;
- volatile size_t m_waiting;
+ size_t m_waiting;
};
void SleepCurrentThread(int ms);
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 0528175ba..42733b95e 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -6,7 +6,6 @@ set(SRCS
arm/dyncom/arm_dyncom_interpreter.cpp
arm/dyncom/arm_dyncom_run.cpp
arm/dyncom/arm_dyncom_thumb.cpp
- arm/interpreter/armcopro.cpp
arm/interpreter/arminit.cpp
arm/interpreter/armsupp.cpp
arm/skyeye_common/vfp/vfp.cpp
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp
index 1b1d01420..128413262 100644
--- a/src/core/arm/dyncom/arm_dyncom.cpp
+++ b/src/core/arm/dyncom/arm_dyncom.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/make_unique.h"
+
#include "core/arm/skyeye_common/armemu.h"
#include "core/arm/skyeye_common/vfp/vfp.h"
@@ -17,7 +19,7 @@ const static cpu_config_t s_arm11_cpu_info = {
};
ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) {
- state = std::unique_ptr<ARMul_State>(new ARMul_State);
+ state = Common::make_unique<ARMul_State>();
ARMul_NewState(state.get());
ARMul_SelectProcessor(state.get(), ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop);
@@ -31,7 +33,6 @@ ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) {
// Reset the core to initial state
ARMul_Reset(state.get());
- state->NextInstr = RESUME; // NOTE: This will be overwritten by LoadContext
state->Emulate = RUN;
// Switch to the desired privilege mode.
@@ -99,7 +100,6 @@ void ARM_DynCom::ResetContext(Core::ThreadContext& context, u32 stack_top, u32 e
context.pc = entry_point;
context.sp = stack_top;
context.cpsr = 0x1F; // Usermode
- context.mode = 8; // Instructs dyncom CPU core to start execution as if it's "resuming" a thread.
}
void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) {
@@ -113,8 +113,6 @@ void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) {
ctx.fpscr = state->VFP[1];
ctx.fpexc = state->VFP[2];
-
- ctx.mode = state->NextInstr;
}
void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) {
@@ -128,8 +126,6 @@ void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) {
state->VFP[1] = ctx.fpscr;
state->VFP[2] = ctx.fpexc;
-
- state->NextInstr = ctx.mode;
}
void ARM_DynCom::PrepareReschedule() {
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h
index 822b3bbb9..2488c879c 100644
--- a/src/core/arm/dyncom/arm_dyncom.h
+++ b/src/core/arm/dyncom/arm_dyncom.h
@@ -27,7 +27,7 @@ public:
void AddTicks(u64 ticks) override;
- void ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg);
+ void ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) override;
void SaveContext(Core::ThreadContext& ctx) override;
void LoadContext(const Core::ThreadContext& ctx) override;
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index fde11e4ff..5ee99e93a 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -6,13 +6,12 @@
#include <algorithm>
#include <cstdio>
-#include <unordered_map>
#include "common/logging/log.h"
#include "common/profiler.h"
#include "core/mem_map.h"
-#include "core/hle/hle.h"
+#include "core/hle/svc.h"
#include "core/arm/disassembler/arm_disasm.h"
#include "core/arm/dyncom/arm_dyncom_interpreter.h"
#include "core/arm/dyncom/arm_dyncom_thumb.h"
@@ -3533,25 +3532,6 @@ const transop_fp_t arm_instruction_trans[] = {
INTERPRETER_TRANSLATE(blx_1_thumb)
};
-typedef std::unordered_map<u32, int> bb_map;
-static bb_map CreamCache;
-
-static void insert_bb(unsigned int addr, int start) {
- CreamCache[addr] = start;
-}
-
-static int find_bb(unsigned int addr, int& start) {
- int ret = -1;
- bb_map::const_iterator it = CreamCache.find(addr);
- if (it != CreamCache.end()) {
- start = static_cast<int>(it->second);
- ret = 0;
- } else {
- ret = -1;
- }
- return ret;
-}
-
enum {
FETCH_SUCCESS,
FETCH_FAILURE
@@ -3674,7 +3654,9 @@ translated:
}
ret = inst_base->br;
};
- insert_bb(pc_start, bb_start);
+
+ cpu->instruction_cache[pc_start] = bb_start;
+
return KEEP_GOING;
}
@@ -4001,9 +3983,14 @@ unsigned InterpreterMainLoop(ARMul_State* state) {
phys_addr = cpu->Reg[15];
- if (find_bb(cpu->Reg[15], ptr) == -1)
+ // Find the cached instruction cream, otherwise translate it...
+ auto itr = cpu->instruction_cache.find(cpu->Reg[15]);
+ if (itr != cpu->instruction_cache.end()) {
+ ptr = itr->second;
+ } else {
if (InterpreterTranslate(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION)
goto END;
+ }
inst_base = (arm_inst *)&inst_buf[ptr];
GOTO_NEXT_INST;
@@ -6247,7 +6234,7 @@ unsigned InterpreterMainLoop(ARMul_State* state) {
SWI_INST:
{
if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
- HLE::CallSVC(Memory::Read32(cpu->Reg[15]));
+ SVC::CallSVC(Memory::Read32(cpu->Reg[15]));
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
diff --git a/src/core/arm/interpreter/armcopro.cpp b/src/core/arm/interpreter/armcopro.cpp
deleted file mode 100644
index 4ae0c52e4..000000000
--- a/src/core/arm/interpreter/armcopro.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/* armcopro.c -- co-processor interface: ARM6 Instruction Emulator.
- Copyright (C) 1994, 2000 Advanced RISC Machines Ltd.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-#include "core/arm/skyeye_common/armdefs.h"
-#include "core/arm/skyeye_common/armemu.h"
-#include "core/arm/skyeye_common/vfp/vfp.h"
-
-// Dummy Co-processors.
-
-static unsigned int NoCoPro3R(ARMul_State* state, unsigned int a, ARMword b)
-{
- return ARMul_CANT;
-}
-
-static unsigned int NoCoPro4R(ARMul_State* state, unsigned int a, ARMword b, ARMword c)
-{
- return ARMul_CANT;
-}
-
-static unsigned int NoCoPro4W(ARMul_State* state, unsigned int a, ARMword b, ARMword* c)
-{
- return ARMul_CANT;
-}
-
-static unsigned int NoCoPro5R(ARMul_State* state, unsigned int a, ARMword b, ARMword c, ARMword d)
-{
- return ARMul_CANT;
-}
-
-static unsigned int NoCoPro5W(ARMul_State* state, unsigned int a, ARMword b, ARMword* c, ARMword* d)
-{
- return ARMul_CANT;
-}
-
-// Install co-processor instruction handlers in this routine.
-void ARMul_CoProInit(ARMul_State* state)
-{
- // Initialise tham all first.
- for (unsigned int i = 0; i < 16; i++)
- ARMul_CoProDetach(state, i);
-
- // Install CoPro Instruction handlers here.
- // The format is:
- // ARMul_CoProAttach (state, CP Number, Init routine, Exit routine
- // LDC routine, STC routine, MRC routine, MCR routine,
- // CDP routine, Read Reg routine, Write Reg routine).
- if (state->is_v6) {
- ARMul_CoProAttach(state, 10, VFPInit, NULL, VFPLDC, VFPSTC,
- VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL);
- ARMul_CoProAttach(state, 11, VFPInit, NULL, VFPLDC, VFPSTC,
- VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL);
-
- /*ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL,
- MMUMRC, MMUMCR, NULL, NULL, NULL, NULL, NULL);*/
- }
-
- // No handlers below here.
-
- // Call all the initialisation routines.
- for (unsigned int i = 0; i < 16; i++) {
- if (state->CPInit[i])
- (state->CPInit[i]) (state);
- }
-}
-
-// Install co-processor finalisation routines in this routine.
-void ARMul_CoProExit(ARMul_State * state)
-{
- for (unsigned int i = 0; i < 16; i++)
- if (state->CPExit[i])
- (state->CPExit[i]) (state);
-
- // Detach all handlers.
- for (unsigned int i = 0; i < 16; i++)
- ARMul_CoProDetach(state, i);
-}
-
-// Routines to hook Co-processors into ARMulator.
-
-void
-ARMul_CoProAttach(ARMul_State* state,
-unsigned number,
-ARMul_CPInits* init,
-ARMul_CPExits* exit,
-ARMul_LDCs* ldc,
-ARMul_STCs* stc,
-ARMul_MRCs* mrc,
-ARMul_MCRs* mcr,
-ARMul_MRRCs* mrrc,
-ARMul_MCRRs* mcrr,
-ARMul_CDPs* cdp,
-ARMul_CPReads* read, ARMul_CPWrites* write)
-{
- if (init != NULL)
- state->CPInit[number] = init;
- if (exit != NULL)
- state->CPExit[number] = exit;
- if (ldc != NULL)
- state->LDC[number] = ldc;
- if (stc != NULL)
- state->STC[number] = stc;
- if (mrc != NULL)
- state->MRC[number] = mrc;
- if (mcr != NULL)
- state->MCR[number] = mcr;
- if (mrrc != NULL)
- state->MRRC[number] = mrrc;
- if (mcrr != NULL)
- state->MCRR[number] = mcrr;
- if (cdp != NULL)
- state->CDP[number] = cdp;
- if (read != NULL)
- state->CPRead[number] = read;
- if (write != NULL)
- state->CPWrite[number] = write;
-}
-
-void ARMul_CoProDetach(ARMul_State* state, unsigned number)
-{
- ARMul_CoProAttach(state, number, NULL, NULL,
- NoCoPro4R, NoCoPro4W, NoCoPro4W, NoCoPro4R,
- NoCoPro5W, NoCoPro5R, NoCoPro3R, NULL, NULL);
-
- state->CPInit[number] = NULL;
- state->CPExit[number] = NULL;
- state->CPRead[number] = NULL;
- state->CPWrite[number] = NULL;
-}
diff --git a/src/core/arm/interpreter/arminit.cpp b/src/core/arm/interpreter/arminit.cpp
index 1d732fe84..31b2bab06 100644
--- a/src/core/arm/interpreter/arminit.cpp
+++ b/src/core/arm/interpreter/arminit.cpp
@@ -19,31 +19,16 @@
#include "core/mem_map.h"
#include "core/arm/skyeye_common/armdefs.h"
#include "core/arm/skyeye_common/armemu.h"
+#include "core/arm/skyeye_common/vfp/vfp.h"
/***************************************************************************\
* Returns a new instantiation of the ARMulator's state *
\***************************************************************************/
ARMul_State* ARMul_NewState(ARMul_State* state)
{
- memset(state, 0, sizeof(ARMul_State));
-
state->Emulate = RUN;
- for (unsigned int i = 0; i < 16; i++) {
- state->Reg[i] = 0;
- for (unsigned int j = 0; j < 7; j++)
- state->RegBank[j][i] = 0;
- }
- for (unsigned int i = 0; i < 7; i++)
- state->Spsr[i] = 0;
-
state->Mode = USER32MODE;
- state->VectorCatch = 0;
- state->Aborted = false;
- state->Reseted = false;
- state->Inted = 3;
- state->LastInted = 3;
-
state->lateabtSig = HIGH;
state->bigendSig = LOW;
@@ -56,15 +41,11 @@ ARMul_State* ARMul_NewState(ARMul_State* state)
void ARMul_SelectProcessor(ARMul_State* state, unsigned properties)
{
- state->is_v4 = (properties & (ARM_v4_Prop | ARM_v5_Prop)) != 0;
- state->is_v5 = (properties & ARM_v5_Prop) != 0;
- state->is_v5e = (properties & ARM_v5e_Prop) != 0;
- state->is_v6 = (properties & ARM_v6_Prop) != 0;
- state->is_v7 = (properties & ARM_v7_Prop) != 0;
-
- // Only initialse the coprocessor support once we
- // know what kind of chip we are dealing with.
- ARMul_CoProInit(state);
+ state->is_v4 = (properties & (ARM_v4_Prop | ARM_v5_Prop)) != 0;
+ state->is_v5 = (properties & ARM_v5_Prop) != 0;
+ state->is_v5e = (properties & ARM_v5e_Prop) != 0;
+ state->is_v6 = (properties & ARM_v6_Prop) != 0;
+ state->is_v7 = (properties & ARM_v7_Prop) != 0;
}
// Resets certain MPCore CP15 values to their ARM-defined reset values.
@@ -130,26 +111,20 @@ static void ResetMPCoreCP15Registers(ARMul_State* cpu)
\***************************************************************************/
void ARMul_Reset(ARMul_State* state)
{
- state->NextInstr = 0;
+ VFPInit(state);
state->Reg[15] = 0;
state->Cpsr = INTBITS | SVC32MODE;
state->Mode = SVC32MODE;
-
state->Bank = SVCBANK;
- FLUSHPIPE;
ResetMPCoreCP15Registers(state);
- state->EndCondition = 0;
- state->ErrorCode = 0;
-
state->NresetSig = HIGH;
state->NfiqSig = HIGH;
state->NirqSig = HIGH;
state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
state->abortSig = LOW;
- state->AbortAddr = 1;
state->NumInstrs = 0;
}
diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h
index 743e935f0..85d523bc2 100644
--- a/src/core/arm/skyeye_common/armdefs.h
+++ b/src/core/arm/skyeye_common/armdefs.h
@@ -17,6 +17,8 @@
#pragma once
+#include <unordered_map>
+
#include "common/common_types.h"
#include "core/arm/skyeye_common/arm_regformat.h"
#include "core/arm/skyeye_common/skyeye_defs.h"
@@ -53,26 +55,11 @@ typedef u64 ARMdword; // must be 64 bits wide
typedef u32 ARMword; // must be 32 bits wide
typedef u16 ARMhword; // must be 16 bits wide
typedef u8 ARMbyte; // must be 8 bits wide
-typedef struct ARMul_State ARMul_State;
-
-typedef unsigned ARMul_CPInits(ARMul_State* state);
-typedef unsigned ARMul_CPExits(ARMul_State* state);
-typedef unsigned ARMul_LDCs(ARMul_State* state, unsigned type, ARMword instr, ARMword value);
-typedef unsigned ARMul_STCs(ARMul_State* state, unsigned type, ARMword instr, ARMword* value);
-typedef unsigned ARMul_MRCs(ARMul_State* state, unsigned type, ARMword instr, ARMword* value);
-typedef unsigned ARMul_MCRs(ARMul_State* state, unsigned type, ARMword instr, ARMword value);
-typedef unsigned ARMul_MRRCs(ARMul_State* state, unsigned type, ARMword instr, ARMword* value1, ARMword* value2);
-typedef unsigned ARMul_MCRRs(ARMul_State* state, unsigned type, ARMword instr, ARMword value1, ARMword value2);
-typedef unsigned ARMul_CDPs(ARMul_State* state, unsigned type, ARMword instr);
-typedef unsigned ARMul_CPReads(ARMul_State* state, unsigned reg, ARMword* value);
-typedef unsigned ARMul_CPWrites(ARMul_State* state, unsigned reg, ARMword value);
#define VFP_REG_NUM 64
struct ARMul_State
{
ARMword Emulate; // To start and stop emulation
- unsigned EndCondition; // Reason for stopping
- unsigned ErrorCode; // Type of illegal instruction
// Order of the following register should not be modified
ARMword Reg[16]; // The current register file
@@ -101,8 +88,6 @@ struct ARMul_State
ARMword ExtReg[VFP_REG_NUM];
/* ---- End of the ordered registers ---- */
- ARMword RegBank[7][16]; // all the registers
-
ARMword NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed
unsigned int shifter_carry_out;
@@ -114,24 +99,7 @@ struct ARMul_State
unsigned long long NumInstrs; // The number of instructions executed
unsigned NumInstrsToExecute;
- unsigned NextInstr;
- unsigned VectorCatch; // Caught exception mask
-
- ARMul_CPInits* CPInit[16]; // Coprocessor initialisers
- ARMul_CPExits* CPExit[16]; // Coprocessor finalisers
- ARMul_LDCs* LDC[16]; // LDC instruction
- ARMul_STCs* STC[16]; // STC instruction
- ARMul_MRCs* MRC[16]; // MRC instruction
- ARMul_MCRs* MCR[16]; // MCR instruction
- ARMul_MRRCs* MRRC[16]; // MRRC instruction
- ARMul_MCRRs* MCRR[16]; // MCRR instruction
- ARMul_CDPs* CDP[16]; // CDP instruction
- ARMul_CPReads* CPRead[16]; // Read CP register
- ARMul_CPWrites* CPWrite[16]; // Write CP register
- unsigned char* CPData[16]; // Coprocessor data
- unsigned char const* CPRegWords[16]; // Map of coprocessor register sizes
-
- unsigned NresetSig; // Reset the processor
+ unsigned NresetSig; // Reset the processor
unsigned NfiqSig;
unsigned NirqSig;
@@ -173,13 +141,6 @@ So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model)
*/
unsigned lateabtSig;
- bool Aborted; // Sticky flag for aborts
- bool Reseted; // Sticky flag for Reset
- ARMword Inted, LastInted; // Sticky flags for interrupts
- ARMword Base; // Extra hand for base writeback
- ARMword AbortAddr; // To keep track of Prefetch aborts
- ARMword Vector; // Synthesize aborts in cycle modes
-
// For differentiating ARM core emulaiton.
bool is_v4; // Are we emulating a v4 architecture (or higher)?
bool is_v5; // Are we emulating a v5 architecture?
@@ -194,13 +155,9 @@ So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model)
// Added by ksh in 2005-10-1
cpu_config_t* cpu;
- u32 CurrInstr;
- u32 last_pc; // The last PC executed
- u32 last_instr; // The last instruction executed
- u32 WriteAddr[17];
- u32 WriteData[17];
- u32 WritePc[17];
- u32 CurrWrite;
+ // TODO(bunnei): Move this cache to a better place - it should be per codeset (likely per
+ // process for our purposes), not per ARMul_State (which tracks CPU core state).
+ std::unordered_map<u32, int> instruction_cache;
};
/***************************************************************************\
@@ -286,34 +243,6 @@ enum {
ARMul_INC = 3
};
-enum {
- ARMul_CP13_R0_FIQ = 0x1,
- ARMul_CP13_R0_IRQ = 0x2,
- ARMul_CP13_R8_PMUS = 0x1,
-
- ARMul_CP14_R0_ENABLE = 0x0001,
- ARMul_CP14_R0_CLKRST = 0x0004,
- ARMul_CP14_R0_CCD = 0x0008,
- ARMul_CP14_R0_INTEN0 = 0x0010,
- ARMul_CP14_R0_INTEN1 = 0x0020,
- ARMul_CP14_R0_INTEN2 = 0x0040,
- ARMul_CP14_R0_FLAG0 = 0x0100,
- ARMul_CP14_R0_FLAG1 = 0x0200,
- ARMul_CP14_R0_FLAG2 = 0x0400,
- ARMul_CP14_R10_MOE_IB = 0x0004,
- ARMul_CP14_R10_MOE_DB = 0x0008,
- ARMul_CP14_R10_MOE_BT = 0x000c,
- ARMul_CP15_R1_ENDIAN = 0x0080,
- ARMul_CP15_R1_ALIGN = 0x0002,
- ARMul_CP15_R5_X = 0x0400,
- ARMul_CP15_R5_ST_ALIGN = 0x0001,
- ARMul_CP15_R5_IMPRE = 0x0406,
- ARMul_CP15_R5_MMU_EXCPT = 0x0400,
- ARMul_CP15_DBCON_M = 0x0100,
- ARMul_CP15_DBCON_E1 = 0x000c,
- ARMul_CP15_DBCON_E0 = 0x0003
-};
-
/***************************************************************************\
* Definitons of things in the host environment *
\***************************************************************************/
diff --git a/src/core/arm/skyeye_common/armemu.h b/src/core/arm/skyeye_common/armemu.h
index 2a1c50779..7e0965052 100644
--- a/src/core/arm/skyeye_common/armemu.h
+++ b/src/core/arm/skyeye_common/armemu.h
@@ -38,16 +38,6 @@ enum : u32 {
INTBITS = 0x1C0,
};
-// Different ways to start the next instruction.
-enum {
- SEQ = 0,
- NONSEQ = 1,
- PCINCEDSEQ = 2,
- PCINCEDNONSEQ = 3,
- PRIMEPIPE = 4,
- RESUME = 8
-};
-
// Values for Emulate.
enum {
STOP = 0, // Stop
@@ -55,14 +45,3 @@ enum {
ONCE = 2, // Execute just one interation
RUN = 3 // Continuous execution
};
-
-#define FLUSHPIPE state->NextInstr |= PRIMEPIPE
-
-// Coprocessor support functions.
-extern void ARMul_CoProInit(ARMul_State*);
-extern void ARMul_CoProExit(ARMul_State*);
-extern void ARMul_CoProAttach(ARMul_State*, unsigned, ARMul_CPInits*,
- ARMul_CPExits*, ARMul_LDCs*, ARMul_STCs*,
- ARMul_MRCs*, ARMul_MCRs*, ARMul_MRRCs*, ARMul_MCRRs*,
- ARMul_CDPs*, ARMul_CPReads*, ARMul_CPWrites*);
-extern void ARMul_CoProDetach(ARMul_State*, unsigned);
diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp
index d793261fd..d0fa157a2 100644
--- a/src/core/arm/skyeye_common/vfp/vfp.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfp.cpp
@@ -37,296 +37,18 @@ unsigned VFPInit(ARMul_State* state)
return 0;
}
-unsigned VFPMRC(ARMul_State* state, unsigned type, u32 instr, u32* value)
-{
- /* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
- int CoProc = BITS(instr, 8, 11); /* 10 or 11 */
- int OPC_1 = BITS(instr, 21, 23);
- int Rt = BITS(instr, 12, 15);
- int CRn = BITS(instr, 16, 19);
- int CRm = BITS(instr, 0, 3);
- int OPC_2 = BITS(instr, 5, 7);
-
- /* TODO check access permission */
-
- /* CRn/opc1 CRm/opc2 */
-
- if (CoProc == 10 || CoProc == 11)
- {
- if (OPC_1 == 0x0 && CRm == 0 && (OPC_2 & 0x3) == 0)
- {
- /* VMOV r to s */
- /* Transfering Rt is not mandatory, as the value of interest is pointed by value */
- VMOVBRS(state, BIT(instr, 20), Rt, BIT(instr, 7)|CRn<<1, value);
- return ARMul_DONE;
- }
-
- if (OPC_1 == 0x7 && CRm == 0 && OPC_2 == 0)
- {
- VMRS(state, CRn, Rt, value);
- return ARMul_DONE;
- }
- }
- LOG_WARNING(Core_ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
- instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
-
- return ARMul_CANT;
-}
-
-unsigned VFPMCR(ARMul_State* state, unsigned type, u32 instr, u32 value)
-{
- /* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
- int CoProc = BITS(instr, 8, 11); /* 10 or 11 */
- int OPC_1 = BITS(instr, 21, 23);
- int Rt = BITS(instr, 12, 15);
- int CRn = BITS(instr, 16, 19);
- int CRm = BITS(instr, 0, 3);
- int OPC_2 = BITS(instr, 5, 7);
-
- /* TODO check access permission */
-
- /* CRn/opc1 CRm/opc2 */
- if (CoProc == 10 || CoProc == 11)
- {
- if (OPC_1 == 0x0 && CRm == 0 && (OPC_2 & 0x3) == 0)
- {
- /* VMOV s to r */
- /* Transfering Rt is not mandatory, as the value of interest is pointed by value */
- VMOVBRS(state, BIT(instr, 20), Rt, BIT(instr, 7)|CRn<<1, &value);
- return ARMul_DONE;
- }
-
- if (OPC_1 == 0x7 && CRm == 0 && OPC_2 == 0)
- {
- VMSR(state, CRn, Rt);
- return ARMul_DONE;
- }
-
- if ((OPC_1 & 0x4) == 0 && CoProc == 11 && CRm == 0)
- {
- VFP_DEBUG_UNIMPLEMENTED(VMOVBRC);
- return ARMul_DONE;
- }
-
- if (CoProc == 11 && CRm == 0)
- {
- VFP_DEBUG_UNIMPLEMENTED(VMOVBCR);
- return ARMul_DONE;
- }
- }
- LOG_WARNING(Core_ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
- instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
-
- return ARMul_CANT;
-}
-
-unsigned VFPMRRC(ARMul_State* state, unsigned type, u32 instr, u32* value1, u32* value2)
-{
- /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
- int CoProc = BITS(instr, 8, 11); /* 10 or 11 */
- int OPC_1 = BITS(instr, 4, 7);
- int Rt = BITS(instr, 12, 15);
- int Rt2 = BITS(instr, 16, 19);
- int CRm = BITS(instr, 0, 3);
-
- if (CoProc == 10 || CoProc == 11)
- {
- if (CoProc == 10 && (OPC_1 & 0xD) == 1)
- {
- VMOVBRRSS(state, BIT(instr, 20), Rt, Rt2, BIT(instr, 5)<<4|CRm, value1, value2);
- return ARMul_DONE;
- }
-
- if (CoProc == 11 && (OPC_1 & 0xD) == 1)
- {
- /* Transfering Rt and Rt2 is not mandatory, as the value of interest is pointed by value1 and value2 */
- VMOVBRRD(state, BIT(instr, 20), Rt, Rt2, BIT(instr, 5)<<4|CRm, value1, value2);
- return ARMul_DONE;
- }
- }
- LOG_WARNING(Core_ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
- instr, CoProc, OPC_1, Rt, Rt2, CRm);
-
- return ARMul_CANT;
-}
-
-unsigned VFPMCRR(ARMul_State* state, unsigned type, u32 instr, u32 value1, u32 value2)
-{
- /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
- int CoProc = BITS(instr, 8, 11); /* 10 or 11 */
- int OPC_1 = BITS(instr, 4, 7);
- int Rt = BITS(instr, 12, 15);
- int Rt2 = BITS(instr, 16, 19);
- int CRm = BITS(instr, 0, 3);
-
- /* TODO check access permission */
-
- /* CRn/opc1 CRm/opc2 */
-
- if (CoProc == 11 || CoProc == 10)
- {
- if (CoProc == 10 && (OPC_1 & 0xD) == 1)
- {
- VMOVBRRSS(state, BIT(instr, 20), Rt, Rt2, BIT(instr, 5)<<4|CRm, &value1, &value2);
- return ARMul_DONE;
- }
-
- if (CoProc == 11 && (OPC_1 & 0xD) == 1)
- {
- /* Transfering Rt and Rt2 is not mandatory, as the value of interest is pointed by value1 and value2 */
- VMOVBRRD(state, BIT(instr, 20), Rt, Rt2, BIT(instr, 5)<<4|CRm, &value1, &value2);
- return ARMul_DONE;
- }
- }
- LOG_WARNING(Core_ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
- instr, CoProc, OPC_1, Rt, Rt2, CRm);
-
- return ARMul_CANT;
-}
-
-unsigned VFPSTC(ARMul_State* state, unsigned type, u32 instr, u32 * value)
-{
- /* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */
- int CoProc = BITS(instr, 8, 11); /* 10 or 11 */
- int CRd = BITS(instr, 12, 15);
- int Rn = BITS(instr, 16, 19);
- int imm8 = BITS(instr, 0, 7);
- int P = BIT(instr, 24);
- int U = BIT(instr, 23);
- int D = BIT(instr, 22);
- int W = BIT(instr, 21);
-
- /* TODO check access permission */
-
- /* VSTM */
- if ( (P|U|D|W) == 0 ) {
- LOG_ERROR(Core_ARM11, "In %s, UNDEFINED\n", __FUNCTION__);
- exit(-1);
- }
- if (CoProc == 10 || CoProc == 11) {
-#if 1
- if (P == 0 && U == 0 && W == 0) {
- LOG_ERROR(Core_ARM11, "VSTM Related encodings\n");
- exit(-1);
- }
- if (P == U && W == 1) {
- LOG_ERROR(Core_ARM11, "UNDEFINED\n");
- exit(-1);
- }
-#endif
-
- if (P == 1 && W == 0)
- {
- return VSTR(state, type, instr, value);
- }
-
- if (P == 1 && U == 0 && W == 1 && Rn == 0xD)
- {
- return VPUSH(state, type, instr, value);
- }
-
- return VSTM(state, type, instr, value);
- }
- LOG_WARNING(Core_ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
- instr, CoProc, CRd, Rn, imm8, P, U, D, W);
-
- return ARMul_CANT;
-}
-
-unsigned VFPLDC(ARMul_State* state, unsigned type, u32 instr, u32 value)
+void VMSR(ARMul_State* state, ARMword reg, ARMword Rt)
{
- /* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */
- int CoProc = BITS(instr, 8, 11); /* 10 or 11 */
- int CRd = BITS(instr, 12, 15);
- int Rn = BITS(instr, 16, 19);
- int imm8 = BITS(instr, 0, 7);
- int P = BIT(instr, 24);
- int U = BIT(instr, 23);
- int D = BIT(instr, 22);
- int W = BIT(instr, 21);
-
- /* TODO check access permission */
-
- if ( (P|U|D|W) == 0 ) {
- LOG_ERROR(Core_ARM11, "In %s, UNDEFINED\n", __FUNCTION__);
- exit(-1);
- }
- if (CoProc == 10 || CoProc == 11)
+ if (reg == 1)
{
- if (P == 1 && W == 0)
- {
- return VLDR(state, type, instr, value);
- }
-
- if (P == 0 && U == 1 && W == 1 && Rn == 0xD)
- {
- return VPOP(state, type, instr, value);
- }
-
- return VLDM(state, type, instr, value);
+ state->VFP[VFP_FPSCR] = state->Reg[Rt];
}
- LOG_WARNING(Core_ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
- instr, CoProc, CRd, Rn, imm8, P, U, D, W);
-
- return ARMul_CANT;
-}
-
-unsigned VFPCDP(ARMul_State* state, unsigned type, u32 instr)
-{
- /* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */
- int CoProc = BITS(instr, 8, 11); /* 10 or 11 */
- int OPC_1 = BITS(instr, 20, 23);
- int CRd = BITS(instr, 12, 15);
- int CRn = BITS(instr, 16, 19);
- int CRm = BITS(instr, 0, 3);
- int OPC_2 = BITS(instr, 5, 7);
-
- /* TODO check access permission */
-
- /* CRn/opc1 CRm/opc2 */
-
- if (CoProc == 10 || CoProc == 11)
+ else if (reg == 8)
{
- if ((OPC_1 & 0xB) == 0xB && BITS(instr, 4, 7) == 0)
- {
- unsigned int single = BIT(instr, 8) == 0;
- unsigned int d = (single ? BITS(instr, 12,15)<<1 | BIT(instr, 22) : BITS(instr, 12,15) | BIT(instr, 22)<<4);
- unsigned int imm;
- instr = BITS(instr, 16, 19) << 4 | BITS(instr, 0, 3); // FIXME dirty workaround to get a correct imm
-
- if (single)
- imm = BIT(instr, 7)<<31 | (BIT(instr, 6)==0)<<30 | (BIT(instr, 6) ? 0x1f : 0)<<25 | BITS(instr, 0, 5)<<19;
- else
- imm = BIT(instr, 7)<<31 | (BIT(instr, 6)==0)<<30 | (BIT(instr, 6) ? 0xff : 0)<<22 | BITS(instr, 0, 5)<<16;
-
- VMOVI(state, single, d, imm);
- return ARMul_DONE;
- }
-
- if ((OPC_1 & 0xB) == 0xB && CRn == 0 && (OPC_2 & 0x6) == 0x2)
- {
- unsigned int single = BIT(instr, 8) == 0;
- unsigned int d = (single ? BITS(instr, 12,15)<<1 | BIT(instr, 22) : BITS(instr, 12,15) | BIT(instr, 22)<<4);
- unsigned int m = (single ? BITS(instr, 0, 3)<<1 | BIT(instr, 5) : BITS(instr, 0, 3) | BIT(instr, 5)<<4);
- VMOVR(state, single, d, m);
- return ARMul_DONE;
- }
-
- int exceptions = 0;
- if (CoProc == 10)
- exceptions = vfp_single_cpdo(state, instr, state->VFP[VFP_FPSCR]);
- else
- exceptions = vfp_double_cpdo(state, instr, state->VFP[VFP_FPSCR]);
-
- vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_FPSCR]);
-
- return ARMul_DONE;
+ state->VFP[VFP_FPEXC] = state->Reg[Rt];
}
- LOG_WARNING(Core_ARM11, "Can't identify %x\n", instr);
- return ARMul_CANT;
}
-/* ----------- MRC ------------ */
void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value)
{
if (to_arm)
@@ -338,43 +60,7 @@ void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword*
state->ExtReg[n] = *value;
}
}
-void VMRS(ARMul_State* state, ARMword reg, ARMword Rt, ARMword* value)
-{
- if (reg == 1)
- {
- if (Rt != 15)
- {
- *value = state->VFP[VFP_FPSCR];
- }
- else
- {
- *value = state->VFP[VFP_FPSCR] ;
- }
- }
- else
- {
- switch (reg)
- {
- case 0:
- *value = state->VFP[VFP_FPSID];
- break;
- case 6:
- /* MVFR1, VFPv3 only ? */
- LOG_TRACE(Core_ARM11, "\tr%d <= MVFR1 unimplemented\n", Rt);
- break;
- case 7:
- /* MVFR0, VFPv3 only? */
- LOG_TRACE(Core_ARM11, "\tr%d <= MVFR0 unimplemented\n", Rt);
- break;
- case 8:
- *value = state->VFP[VFP_FPEXC];
- break;
- default:
- LOG_TRACE(Core_ARM11, "\tSUBARCHITECTURE DEFINED\n");
- break;
- }
- }
-}
+
void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2)
{
if (to_arm)
@@ -402,301 +88,6 @@ void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMwor
}
}
-/* ----------- MCR ------------ */
-void VMSR(ARMul_State* state, ARMword reg, ARMword Rt)
-{
- if (reg == 1)
- {
- state->VFP[VFP_FPSCR] = state->Reg[Rt];
- }
- else if (reg == 8)
- {
- state->VFP[VFP_FPEXC] = state->Reg[Rt];
- }
-}
-
-/* Memory operation are not inlined, as old Interpreter and Fast interpreter
- don't have the same memory operation interface.
- Old interpreter framework does one access to coprocessor per data, and
- handles already data write, as well as address computation,
- which is not the case for Fast interpreter. Therefore, implementation
- of vfp instructions in old interpreter and fast interpreter are separate. */
-
-/* ----------- STC ------------ */
-int VSTR(ARMul_State* state, int type, ARMword instr, ARMword* value)
-{
- static int i = 0;
- static int single_reg, add, d, n, imm32, regs;
- if (type == ARMul_FIRST)
- {
- single_reg = BIT(instr, 8) == 0; // Double precision
- add = BIT(instr, 23);
- imm32 = BITS(instr, 0,7)<<2; // may not be used
- d = single_reg ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); /* Base register */
- n = BITS(instr, 16, 19); // destination register
-
- i = 0;
- regs = 1;
-
- return ARMul_DONE;
- }
- else if (type == ARMul_DATA)
- {
- if (single_reg)
- {
- *value = state->ExtReg[d+i];
- i++;
- if (i < regs)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- else
- {
- /* FIXME Careful of endianness, may need to rework this */
- *value = state->ExtReg[d*2+i];
- i++;
- if (i < regs*2)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- }
-
- return -1;
-}
-int VPUSH(ARMul_State* state, int type, ARMword instr, ARMword* value)
-{
- static int i = 0;
- static int single_regs, d, imm32, regs;
- if (type == ARMul_FIRST)
- {
- single_regs = BIT(instr, 8) == 0; // Single precision
- d = single_regs ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); // Base register
- imm32 = BITS(instr, 0,7)<<2; // may not be used
- regs = single_regs ? BITS(instr, 0, 7) : BITS(instr, 1, 7); // FSTMX if regs is odd
-
- state->Reg[R13] = state->Reg[R13] - imm32;
-
- i = 0;
-
- return ARMul_DONE;
- }
- else if (type == ARMul_DATA)
- {
- if (single_regs)
- {
- *value = state->ExtReg[d + i];
- i++;
- if (i < regs)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- else
- {
- /* FIXME Careful of endianness, may need to rework this */
- *value = state->ExtReg[d*2 + i];
- i++;
- if (i < regs*2)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- }
-
- return -1;
-}
-int VSTM(ARMul_State* state, int type, ARMword instr, ARMword* value)
-{
- static int i = 0;
- static int single_regs, add, wback, d, n, imm32, regs;
- if (type == ARMul_FIRST)
- {
- single_regs = BIT(instr, 8) == 0; // Single precision
- add = BIT(instr, 23);
- wback = BIT(instr, 21); // write-back
- d = single_regs ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); // Base register
- n = BITS(instr, 16, 19); // destination register
- imm32 = BITS(instr, 0,7) * 4; // may not be used
- regs = single_regs ? BITS(instr, 0, 7) : BITS(instr, 0, 7)>>1; // FSTMX if regs is odd
-
- if (wback) {
- state->Reg[n] = (add ? state->Reg[n] + imm32 : state->Reg[n] - imm32);
- }
-
- i = 0;
-
- return ARMul_DONE;
- }
- else if (type == ARMul_DATA)
- {
- if (single_regs)
- {
- *value = state->ExtReg[d + i];
- i++;
- if (i < regs)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- else
- {
- /* FIXME Careful of endianness, may need to rework this */
- *value = state->ExtReg[d*2 + i];
- i++;
- if (i < regs*2)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- }
-
- return -1;
-}
-
-/* ----------- LDC ------------ */
-int VPOP(ARMul_State* state, int type, ARMword instr, ARMword value)
-{
- static int i = 0;
- static int single_regs, d, imm32, regs;
- if (type == ARMul_FIRST)
- {
- single_regs = BIT(instr, 8) == 0; // Single precision
- d = single_regs ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); // Base register
- imm32 = BITS(instr, 0, 7)<<2; // may not be used
- regs = single_regs ? BITS(instr, 0, 7) : BITS(instr, 1, 7); // FLDMX if regs is odd
-
- state->Reg[R13] = state->Reg[R13] + imm32;
-
- i = 0;
-
- return ARMul_DONE;
- }
- else if (type == ARMul_TRANSFER)
- {
- return ARMul_DONE;
- }
- else if (type == ARMul_DATA)
- {
- if (single_regs)
- {
- state->ExtReg[d + i] = value;
- i++;
- if (i < regs)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- else
- {
- /* FIXME Careful of endianness, may need to rework this */
- state->ExtReg[d*2 + i] = value;
- i++;
- if (i < regs*2)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- }
-
- return -1;
-}
-int VLDR(ARMul_State* state, int type, ARMword instr, ARMword value)
-{
- static int i = 0;
- static int single_reg, add, d, n, imm32, regs;
- if (type == ARMul_FIRST)
- {
- single_reg = BIT(instr, 8) == 0; // Double precision
- add = BIT(instr, 23);
- imm32 = BITS(instr, 0, 7)<<2; // may not be used
- d = single_reg ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); // Base register
- n = BITS(instr, 16, 19); // destination register
-
- i = 0;
- regs = 1;
-
- return ARMul_DONE;
- }
- else if (type == ARMul_TRANSFER)
- {
- return ARMul_DONE;
- }
- else if (type == ARMul_DATA)
- {
- if (single_reg)
- {
- state->ExtReg[d+i] = value;
- i++;
- if (i < regs)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- else
- {
- /* FIXME Careful of endianness, may need to rework this */
- state->ExtReg[d*2+i] = value;
- i++;
- if (i < regs*2)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- }
-
- return -1;
-}
-int VLDM(ARMul_State* state, int type, ARMword instr, ARMword value)
-{
- static int i = 0;
- static int single_regs, add, wback, d, n, imm32, regs;
- if (type == ARMul_FIRST)
- {
- single_regs = BIT(instr, 8) == 0; // Single precision
- add = BIT(instr, 23);
- wback = BIT(instr, 21); // write-back
- d = single_regs ? BITS(instr, 12, 15)<<1|BIT(instr, 22) : BIT(instr, 22)<<4|BITS(instr, 12, 15); // Base register
- n = BITS(instr, 16, 19); // destination register
- imm32 = BITS(instr, 0, 7) * 4; // may not be used
- regs = single_regs ? BITS(instr, 0, 7) : BITS(instr, 0, 7)>>1; // FLDMX if regs is odd
-
- if (wback) {
- state->Reg[n] = (add ? state->Reg[n] + imm32 : state->Reg[n] - imm32);
- }
-
- i = 0;
-
- return ARMul_DONE;
- }
- else if (type == ARMul_DATA)
- {
- if (single_regs)
- {
- state->ExtReg[d + i] = value;
- i++;
- if (i < regs)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- else
- {
- /* FIXME Careful of endianness, may need to rework this */
- state->ExtReg[d*2 + i] = value;
- i++;
- if (i < regs*2)
- return ARMul_INC;
- else
- return ARMul_DONE;
- }
- }
-
- return -1;
-}
-
-/* ----------- CDP ------------ */
void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm)
{
if (single)
diff --git a/src/core/arm/skyeye_common/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h
index 1b72383e7..727350f14 100644
--- a/src/core/arm/skyeye_common/vfp/vfp.h
+++ b/src/core/arm/skyeye_common/vfp/vfp.h
@@ -28,13 +28,6 @@
#define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
unsigned VFPInit(ARMul_State* state);
-unsigned VFPMRC(ARMul_State* state, unsigned type, ARMword instr, ARMword* value);
-unsigned VFPMCR(ARMul_State* state, unsigned type, ARMword instr, ARMword value);
-unsigned VFPMRRC(ARMul_State* state, unsigned type, ARMword instr, ARMword* value1, ARMword* value2);
-unsigned VFPMCRR(ARMul_State* state, unsigned type, ARMword instr, ARMword value1, ARMword value2);
-unsigned VFPSTC(ARMul_State* state, unsigned type, ARMword instr, ARMword* value);
-unsigned VFPLDC(ARMul_State* state, unsigned type, ARMword instr, ARMword value);
-unsigned VFPCDP(ARMul_State* state, unsigned type, ARMword instr);
s32 vfp_get_float(ARMul_State* state, u32 reg);
void vfp_put_float(ARMul_State* state, s32 val, u32 reg);
@@ -44,23 +37,10 @@ void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpsc
u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
-// MRC
-void VMRS(ARMul_State* state, ARMword reg, ARMword Rt, ARMword* value);
+void VMSR(ARMul_State* state, ARMword reg, ARMword Rt);
void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value);
void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2);
void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2);
void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm);
void VMOVR(ARMul_State* state, ARMword single, ARMword d, ARMword imm);
-// MCR
-void VMSR(ARMul_State* state, ARMword reg, ARMword Rt);
-
-// STC
-int VSTM(ARMul_State* state, int type, ARMword instr, ARMword* value);
-int VPUSH(ARMul_State* state, int type, ARMword instr, ARMword* value);
-int VSTR(ARMul_State* state, int type, ARMword instr, ARMword* value);
-
-// LDC
-int VLDM(ARMul_State* state, int type, ARMword instr, ARMword value);
-int VPOP(ARMul_State* state, int type, ARMword instr, ARMword value);
-int VLDR(ARMul_State* state, int type, ARMword instr, ARMword value);
diff --git a/src/core/arm/skyeye_common/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h
index 5d1b4e53f..6b3dae280 100644
--- a/src/core/arm/skyeye_common/vfp/vfp_helper.h
+++ b/src/core/arm/skyeye_common/vfp/vfp_helper.h
@@ -36,9 +36,6 @@
#include "common/common_types.h"
#include "core/arm/skyeye_common/armdefs.h"
-#define pr_info //printf
-#define pr_debug //printf
-
#define do_div(n, base) {n/=base;}
enum : u32 {
diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
index 8b2dfa388..a78bdc430 100644
--- a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
@@ -51,6 +51,8 @@
* ===========================================================================
*/
+#include "common/logging/log.h"
+
#include "core/arm/skyeye_common/vfp/vfp_helper.h"
#include "core/arm/skyeye_common/vfp/asm_vfp.h"
#include "core/arm/skyeye_common/vfp/vfp.h"
@@ -63,8 +65,8 @@ static struct vfp_single vfp_single_default_qnan = {
static void vfp_single_dump(const char *str, struct vfp_single *s)
{
- pr_debug("VFP: %s: sign=%d exponent=%d significand=%08x\n",
- str, s->sign != 0, s->exponent, s->significand);
+ LOG_DEBUG(Core_ARM11, "%s: sign=%d exponent=%d significand=%08x",
+ str, s->sign != 0, s->exponent, s->significand);
}
static void vfp_single_normalise_denormal(struct vfp_single *vs)
@@ -154,7 +156,7 @@ u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single *vs,
} else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vs->sign != 0))
incr = (1 << (VFP_SINGLE_LOW_BITS + 1)) - 1;
- pr_debug("VFP: rounding increment = 0x%08x\n", incr);
+ LOG_DEBUG(Core_ARM11, "rounding increment = 0x%08x", incr);
/*
* Is our rounding going to overflow?
@@ -209,10 +211,8 @@ pack:
vfp_single_dump("pack: final", vs);
{
s32 d = vfp_single_pack(vs);
-#if 1
- pr_debug("VFP: %s: d(s%d)=%08x exceptions=%08x\n", func,
- sd, d, exceptions);
-#endif
+ LOG_DEBUG(Core_ARM11, "%s: d(s%d)=%08x exceptions=%08x", func,
+ sd, d, exceptions);
vfp_put_float(state, d, sd);
}
@@ -302,7 +302,7 @@ u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand)
u32 z, a;
if ((significand & 0xc0000000) != 0x40000000) {
- pr_debug("VFP: estimate_sqrt: invalid significand\n");
+ LOG_DEBUG(Core_ARM11, "invalid significand");
}
a = significand << 1;
@@ -392,7 +392,7 @@ sqrt_invalid:
term = (u64)vsd.significand * vsd.significand;
rem = ((u64)vsm.significand << 32) - term;
- pr_debug("VFP: term=%016llx rem=%016llx\n", term, rem);
+ LOG_DEBUG(Core_ARM11, "term=%016lx rem=%016lx", term, rem);
while (rem < 0) {
vsd.significand -= 1;
@@ -624,7 +624,7 @@ static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 f
}
}
- pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
+ LOG_DEBUG(Core_ARM11, "ftoui: d(s%d)=%08x exceptions=%08x", sd, d, exceptions);
vfp_put_float(state, d, sd);
@@ -703,7 +703,7 @@ static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 f
}
}
- pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
+ LOG_DEBUG(Core_ARM11, "ftosi: d(s%d)=%08x exceptions=%08x", sd, d, exceptions);
vfp_put_float(state, (s32)d, sd);
@@ -800,7 +800,7 @@ vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn,
if (vsn->significand & 0x80000000 ||
vsm->significand & 0x80000000) {
- pr_info("VFP: bad FP values in %s\n", __func__);
+ LOG_WARNING(Core_ARM11, "bad FP values");
vfp_single_dump("VSN", vsn);
vfp_single_dump("VSM", vsm);
}
@@ -871,7 +871,7 @@ vfp_single_multiply(struct vfp_single *vsd, struct vfp_single *vsn, struct vfp_s
struct vfp_single *t = vsn;
vsn = vsm;
vsm = t;
- pr_debug("VFP: swapping M <-> N\n");
+ LOG_DEBUG(Core_ARM11, "swapping M <-> N");
}
vsd->sign = vsn->sign ^ vsm->sign;
@@ -924,7 +924,7 @@ vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fp
s32 v;
v = vfp_get_float(state, sn);
- pr_debug("VFP: s%u = %08x\n", sn, v);
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sn, v);
vfp_single_unpack(&vsn, v);
if (vsn.exponent == 0 && vsn.significand)
vfp_single_normalise_denormal(&vsn);
@@ -939,7 +939,7 @@ vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fp
vsp.sign = vfp_sign_negate(vsp.sign);
v = vfp_get_float(state, sd);
- pr_debug("VFP: s%u = %08x\n", sd, v);
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sd, v);
vfp_single_unpack(&vsn, v);
if (vsn.exponent == 0 && vsn.significand != 0)
vfp_single_normalise_denormal(&vsn);
@@ -961,7 +961,7 @@ vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fp
*/
static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
{
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sn, sd);
return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, 0, "fmac");
}
@@ -970,7 +970,8 @@ static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
*/
static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
{
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sd, sn);
+ // TODO: this one has its arguments inverted, investigate.
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sd, sn);
return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_MULTIPLY, "fnmac");
}
@@ -979,7 +980,7 @@ static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr
*/
static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
{
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sn, sd);
return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT, "fmsc");
}
@@ -988,7 +989,7 @@ static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
*/
static u32 vfp_single_fnmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
{
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sn, sd);
return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc");
}
@@ -1001,7 +1002,7 @@ static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
u32 exceptions;
s32 n = vfp_get_float(state, sn);
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, n);
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sn, n);
vfp_single_unpack(&vsn, n);
if (vsn.exponent == 0 && vsn.significand)
@@ -1024,7 +1025,7 @@ static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr
u32 exceptions;
s32 n = vfp_get_float(state, sn);
- pr_debug("VFP: s%u = %08x\n", sn, n);
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sn, n);
vfp_single_unpack(&vsn, n);
if (vsn.exponent == 0 && vsn.significand)
@@ -1048,7 +1049,7 @@ static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
u32 exceptions;
s32 n = vfp_get_float(state, sn);
- pr_debug("VFP: s%u = %08x\n", sn, n);
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sn, n);
/*
* Unpack and normalise denormals.
@@ -1071,7 +1072,7 @@ static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
*/
static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
{
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sn, sd);
/*
* Subtraction is addition with one sign inverted.
*/
@@ -1091,7 +1092,7 @@ static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
s32 n = vfp_get_float(state, sn);
int tm, tn;
- pr_debug("VFP: s%u = %08x\n", sn, n);
+ LOG_DEBUG(Core_ARM11, "s%u = %08x", sn, n);
vfp_single_unpack(&vsn, n);
vfp_single_unpack(&vsm, m);
@@ -1213,7 +1214,6 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
unsigned int sm = vfp_get_sm(inst);
unsigned int vecitr, veclen, vecstride;
struct op *fop;
- pr_debug("In %s\n", __FUNCTION__);
vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK);
@@ -1239,11 +1239,11 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
else
veclen = fpscr & FPSCR_LENGTH_MASK;
- pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
- (veclen >> FPSCR_LENGTH_BIT) + 1);
+ LOG_DEBUG(Core_ARM11, "vecstride=%u veclen=%u", vecstride,
+ (veclen >> FPSCR_LENGTH_BIT) + 1);
if (!fop->fn) {
- printf("VFP: could not find single op %d, inst=0x%x@0x%x\n", FEXT_TO_IDX(inst), inst, state->Reg[15]);
+ LOG_CRITICAL(Core_ARM11, "could not find single op %d, inst=0x%x@0x%x", FEXT_TO_IDX(inst), inst, state->Reg[15]);
exit(-1);
goto invalid;
}
@@ -1255,17 +1255,17 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
type = (fop->flags & OP_DD) ? 'd' : 's';
if (op == FOP_EXT)
- pr_debug("VFP: itr%d (%c%u) = op[%u] (s%u=%08x)\n",
- vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
- sm, m);
+ LOG_DEBUG(Core_ARM11, "itr%d (%c%u) = op[%u] (s%u=%08x)",
+ vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
+ sm, m);
else
- pr_debug("VFP: itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)\n",
- vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
- FOP_TO_IDX(op), sm, m);
+ LOG_DEBUG(Core_ARM11, "itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)",
+ vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
+ FOP_TO_IDX(op), sm, m);
except = fop->fn(state, dest, sn, m, fpscr);
- pr_debug("VFP: itr%d: exceptions=%08x\n",
- vecitr >> FPSCR_LENGTH_BIT, except);
+ LOG_DEBUG(Core_ARM11, "itr%d: exceptions=%08x",
+ vecitr >> FPSCR_LENGTH_BIT, except);
exceptions |= except;
diff --git a/src/core/core.h b/src/core/core.h
index 5e132cb5a..278f0f1cc 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -21,9 +21,6 @@ struct ThreadContext {
u32 fpu_registers[32];
u32 fpscr;
u32 fpexc;
-
- // These are not part of native ThreadContext, but needed by emu
- u32 mode;
};
extern ARM_Interface* g_app_core; ///< ARM11 application core
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() {
last_global_time_us = 0;
has_ts_events = 0;
mhz_change_callbacks.clear();
+
+ first = nullptr;
+ ts_first = nullptr;
+ ts_last = nullptr;
+
+ event_pool = nullptr;
+ event_ts_pool = nullptr;
+ allocated_ts_events = 0;
+
+ advance_callback = nullptr;
}
void Shutdown() {
diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h
index dbbdced74..770bd715e 100644
--- a/src/core/file_sys/disk_archive.h
+++ b/src/core/file_sys/disk_archive.h
@@ -24,7 +24,7 @@ class DiskArchive : public ArchiveBackend {
public:
DiskArchive(const std::string& mount_point_) : mount_point(mount_point_) {}
- virtual std::string GetName() const { return "DiskArchive: " + mount_point; }
+ virtual std::string GetName() const override { return "DiskArchive: " + mount_point; }
std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override;
bool DeleteFile(const Path& path) const override;
diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/config_mem.cpp
index 40bae9346..9fcfcc285 100644
--- a/src/core/hle/config_mem.cpp
+++ b/src/core/hle/config_mem.cpp
@@ -61,12 +61,13 @@ template void Read<u16>(u16 &var, const u32 addr);
template void Read<u8>(u8 &var, const u32 addr);
void Init() {
+ memset(&config_mem, 0, sizeof(config_mem));
+
config_mem.update_flag = 0; // No update
config_mem.sys_core_ver = 0x2;
config_mem.unit_info = 0x1; // Bit 0 set for Retail
config_mem.prev_firm = 0;
config_mem.app_mem_type = 0x2; // Default app mem type is 0
- config_mem.unit_info = 0x1; // Bit 0 set for Retail
config_mem.app_mem_alloc = 0x06000000; // Set to 96MB, since some games use more than the default (64MB)
config_mem.base_mem_alloc = 0x01400000; // Default base memory is 20MB
config_mem.sys_mem_alloc = Memory::FCRAM_SIZE - (config_mem.app_mem_alloc + config_mem.base_mem_alloc);
@@ -77,4 +78,7 @@ void Init() {
config_mem.firm_sys_core_ver = 0x2;
}
+void Shutdown() {
+}
+
} // 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);
void Init();
+void Shutdown();
+
} // namespace
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp
index 1aaeaa9c9..fdeb9a028 100644
--- a/src/core/hle/hle.cpp
+++ b/src/core/hle/hle.cpp
@@ -2,12 +2,11 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <vector>
-
-#include "common/profiler.h"
+#include "common/assert.h"
+#include "common/logging/log.h"
#include "core/arm/arm_interface.h"
-#include "core/mem_map.h"
+#include "core/core.h"
#include "core/hle/hle.h"
#include "core/hle/config_mem.h"
#include "core/hle/shared_page.h"
@@ -18,35 +17,7 @@
namespace HLE {
-Common::Profiling::TimingCategory profiler_svc("SVC Calls");
-
-static std::vector<ModuleDef> g_module_db;
-
-bool g_reschedule = false; ///< If true, immediately reschedules the CPU to a new thread
-
-static const FunctionDef* GetSVCInfo(u32 opcode) {
- u32 func_num = opcode & 0xFFFFFF; // 8 bits
- if (func_num > 0xFF) {
- LOG_ERROR(Kernel_SVC,"unknown svc=0x%02X", func_num);
- return nullptr;
- }
- return &g_module_db[0].func_table[func_num];
-}
-
-void CallSVC(u32 opcode) {
- Common::Profiling::ScopeTimer timer_svc(profiler_svc);
-
- const FunctionDef *info = GetSVCInfo(opcode);
-
- if (!info) {
- return;
- }
- if (info->func) {
- info->func();
- } else {
- LOG_ERROR(Kernel_SVC, "unimplemented SVC function %s(..)", info->name.c_str());
- }
-}
+bool g_reschedule; ///< If true, immediately reschedules the CPU to a new thread
void Reschedule(const char *reason) {
DEBUG_ASSERT_MSG(reason != nullptr && strlen(reason) < 256, "Reschedule: Invalid or too long reason.");
@@ -62,31 +33,21 @@ void Reschedule(const char *reason) {
g_reschedule = true;
}
-void RegisterModule(std::string name, int num_functions, const FunctionDef* func_table) {
- ModuleDef module = {name, num_functions, func_table};
- g_module_db.push_back(module);
-}
-
-static void RegisterAllModules() {
- SVC::Register();
-}
-
void Init() {
Service::Init();
-
- RegisterAllModules();
-
ConfigMem::Init();
SharedPage::Init();
+ g_reschedule = false;
+
LOG_DEBUG(Kernel, "initialized OK");
}
void Shutdown() {
+ ConfigMem::Shutdown();
+ SharedPage::Shutdown();
Service::Shutdown();
- g_module_db.clear();
-
LOG_DEBUG(Kernel, "shutdown OK");
}
diff --git a/src/core/hle/hle.h b/src/core/hle/hle.h
index 3f6f9a4b5..23de1aab7 100644
--- a/src/core/hle/hle.h
+++ b/src/core/hle/hle.h
@@ -4,40 +4,13 @@
#pragma once
-#include <string>
-
-#include "common/common_types.h"
-#include "core/core.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
namespace HLE {
extern bool g_reschedule; ///< If true, immediately reschedules the CPU to a new thread
-typedef u32 Addr;
-typedef void (*Func)();
-
-struct FunctionDef {
- u32 id;
- Func func;
- std::string name;
-};
-
-struct ModuleDef {
- std::string name;
- int num_funcs;
- const FunctionDef* func_table;
-};
-
-void RegisterModule(std::string name, int num_functions, const FunctionDef *func_table);
-
-void CallSVC(u32 opcode);
-
void Reschedule(const char *reason);
void Init();
-
void Shutdown();
} // namespace
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 @@
namespace Kernel {
-unsigned int Object::next_object_id = 0;
-
-SharedPtr<Thread> g_main_thread = nullptr;
+unsigned int Object::next_object_id;
+SharedPtr<Thread> g_main_thread;
HandleTable g_handle_table;
-u64 g_program_id = 0;
+u64 g_program_id;
void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) {
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
@@ -138,6 +137,10 @@ void HandleTable::Clear() {
void Init() {
Kernel::ThreadingInit();
Kernel::TimersInit();
+
+ Object::next_object_id = 0;
+ g_program_id = 0;
+ g_main_thread = nullptr;
}
/// 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:
return false;
}
+public:
+ static unsigned int next_object_id;
+
private:
friend void intrusive_ptr_add_ref(Object*);
friend void intrusive_ptr_release(Object*);
- static unsigned int next_object_id;
-
unsigned int ref_count = 0;
unsigned int object_id = next_object_id++;
};
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 @@
namespace Kernel {
/// Event type for the thread wake up event
-static int ThreadWakeupEventType = -1;
+static int ThreadWakeupEventType;
bool Thread::ShouldWait() {
return status != THREADSTATUS_DEAD;
@@ -42,7 +42,7 @@ static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST+1> ready_queue;
static Thread* current_thread;
// The first available thread id at startup
-static u32 next_thread_id = 1;
+static u32 next_thread_id;
/**
* Creates a new thread ID
@@ -497,6 +497,12 @@ void Thread::SetWaitSynchronizationOutput(s32 output) {
void ThreadingInit() {
ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);
+ current_thread = nullptr;
+ next_thread_id = 1;
+
+ thread_list.clear();
+ ready_queue.clear();
+
// Setup the idle thread
SetupIdleThread();
}
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index 610e26a3c..36979248d 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -12,7 +12,7 @@
namespace Kernel {
/// The event type of the generic timer callback event
-static int timer_callback_event_type = -1;
+static int timer_callback_event_type;
// TODO(yuriks): This can be removed if Timer objects are explicitly pooled in the future, allowing
// us to simply use a pool index or similar.
static Kernel::HandleTable timer_callback_handle_table;
@@ -66,7 +66,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) {
SharedPtr<Timer> timer = timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle));
if (timer == nullptr) {
- LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08X", timer_handle);
+ LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08lX", timer_handle);
return;
}
@@ -89,6 +89,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) {
}
void TimersInit() {
+ timer_callback_handle_table.Clear();
timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback);
}
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 {
static const VAddr SHARED_FONT_VADDR = 0x18000000;
/// Handle to shared memory region designated to for shared system font
-static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem = nullptr;
+static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem;
-static Kernel::SharedPtr<Kernel::Mutex> lock = nullptr;
-static Kernel::SharedPtr<Kernel::Event> notification_event = nullptr; ///< APT notification event
-static Kernel::SharedPtr<Kernel::Event> start_event = nullptr; ///< APT start event
+static Kernel::SharedPtr<Kernel::Mutex> lock;
+static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
+static Kernel::SharedPtr<Kernel::Event> start_event; ///< APT start event
static std::vector<u8> shared_font;
-static u32 cpu_percent = 0; ///< CPU time available to the running application
+static u32 cpu_percent; ///< CPU time available to the running application
void Initialize(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
@@ -309,6 +309,7 @@ void Init() {
}
lock = Kernel::Mutex::Create(false, "APT_U:Lock");
+
cpu_percent = 0;
// TODO(bunnei): Check if these are created in Initialize or on APT process startup.
@@ -317,7 +318,11 @@ void Init() {
}
void Shutdown() {
-
+ shared_font.clear();
+ shared_font_mem = nullptr;
+ lock = nullptr;
+ notification_event = nullptr;
+ start_event = nullptr;
}
} // namespace APT
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
index fe1245fe8..5eccdecf7 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -53,12 +53,12 @@ ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, u8* output) {
});
if (itr == std::end(config->block_entries)) {
- LOG_ERROR(Service_CFG, "Config block %u with flags %u was not found", block_id, flag);
+ LOG_ERROR(Service_CFG, "Config block 0x%X with flags %u and size %u was not found", block_id, flag, size);
return ResultCode(ErrorDescription::NotFound, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent);
}
if (itr->size != size) {
- LOG_ERROR(Service_CFG, "Invalid size %u for config block %u with flags %u", size, block_id, flag);
+ LOG_ERROR(Service_CFG, "Invalid size %u for config block 0x%X with flags %u", size, block_id, flag);
return ResultCode(ErrorDescription::InvalidSize, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent);
}
@@ -207,6 +207,7 @@ void Init() {
// Initialize the Username block
// TODO(Subv): Initialize this directly in the variable when MSVC supports char16_t string literals
+ memset(&CONSOLE_USERNAME_BLOCK, 0, sizeof(CONSOLE_USERNAME_BLOCK));
CONSOLE_USERNAME_BLOCK.ng_word = 0;
CONSOLE_USERNAME_BLOCK.zero = 0;
@@ -219,7 +220,6 @@ void Init() {
}
void Shutdown() {
-
}
} // namespace CFG
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
index f16f84e67..2e759a3e3 100644
--- a/src/core/hle/service/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -11,7 +11,7 @@
namespace DSP_DSP {
-static u32 read_pipe_count = 0;
+static u32 read_pipe_count;
static Kernel::SharedPtr<Kernel::Event> semaphore_event;
static Kernel::SharedPtr<Kernel::Event> interrupt_event;
@@ -42,7 +42,7 @@ static void ConvertProcessAddressFromDspDram(Service::Interface* self) {
cmd_buff[1] = 0; // No error
cmd_buff[2] = (addr << 1) + (Memory::DSP_MEMORY_VADDR + 0x40000);
- LOG_WARNING(Service_DSP, "(STUBBED) called with address %u", addr);
+ LOG_WARNING(Service_DSP, "(STUBBED) called with address 0x%08X", addr);
}
/**
@@ -60,12 +60,19 @@ static void ConvertProcessAddressFromDspDram(Service::Interface* self) {
static void LoadComponent(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 size = cmd_buff[1];
+ u32 unk1 = cmd_buff[2];
+ u32 unk2 = cmd_buff[3];
+ u32 new_size = cmd_buff[4];
+ u32 buffer = cmd_buff[5];
+
cmd_buff[1] = 0; // No error
cmd_buff[2] = 1; // Pretend that we actually loaded the DSP firmware
// TODO(bunnei): Implement real DSP firmware loading
- LOG_WARNING(Service_DSP, "(STUBBED) called");
+ LOG_WARNING(Service_DSP, "(STUBBED) called size=0x%X, unk1=0x%08X, unk2=0x%08X, new_size=0x%X, buffer=0x%08X",
+ size, unk1, unk2, new_size, buffer);
}
/**
@@ -106,7 +113,7 @@ static void FlushDataCache(Service::Interface* self) {
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- LOG_DEBUG(Service_DSP, "(STUBBED) called address=0x%08X, size=0x%08X, process=0x%08X",
+ LOG_DEBUG(Service_DSP, "(STUBBED) called address=0x%08X, size=0x%X, process=0x%08X",
address, size, process);
}
@@ -122,6 +129,10 @@ static void FlushDataCache(Service::Interface* self) {
static void RegisterInterruptEvents(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 param0 = cmd_buff[1];
+ u32 param1 = cmd_buff[2];
+ u32 event_handle = cmd_buff[4];
+
auto evt = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]);
if (evt != nullptr) {
interrupt_event = evt;
@@ -133,7 +144,7 @@ static void RegisterInterruptEvents(Service::Interface* self) {
cmd_buff[1] = -1;
}
- LOG_WARNING(Service_DSP, "(STUBBED) called");
+ LOG_WARNING(Service_DSP, "(STUBBED) called param0=%u, param1=%u, event_handle=0x%08X", param0, param1, event_handle);
}
/**
@@ -174,7 +185,7 @@ static void WriteProcessPipe(Service::Interface* self) {
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- LOG_WARNING(Service_DSP, "(STUBBED) called number=%u, size=0x%08X, new_size=0x%08X, buffer=0x%08X",
+ LOG_WARNING(Service_DSP, "(STUBBED) called number=%u, size=0x%X, new_size=0x%X, buffer=0x%08X",
number, size, new_size, buffer);
}
@@ -192,6 +203,8 @@ static void WriteProcessPipe(Service::Interface* self) {
static void ReadPipeIfPossible(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 unk1 = cmd_buff[1];
+ u32 unk2 = cmd_buff[2];
u32 size = cmd_buff[3] & 0xFFFF;// Lower 16 bits are size
VAddr addr = cmd_buff[0x41];
@@ -217,7 +230,8 @@ static void ReadPipeIfPossible(Service::Interface* self) {
cmd_buff[1] = 0; // No error
cmd_buff[2] = (read_pipe_count - initial_size) * sizeof(u16);
- LOG_WARNING(Service_DSP, "(STUBBED) called size=0x%08X, buffer=0x%08X", size, addr);
+ LOG_WARNING(Service_DSP, "(STUBBED) called unk1=0x%08X, unk2=0x%08X, size=0x%X, buffer=0x%08X",
+ unk1, unk2, size, addr);
}
/**
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 {
static const int MAX_CIRCLEPAD_POS = 0x9C; ///< Max value for a circle pad position
// Handle to shared memory region designated to HID_User service
-static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem = nullptr;
+static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
// Event handles
-static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_1 = nullptr;
-static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_2 = nullptr;
-static Kernel::SharedPtr<Kernel::Event> event_accelerometer = nullptr;
-static Kernel::SharedPtr<Kernel::Event> event_gyroscope = nullptr;
-static Kernel::SharedPtr<Kernel::Event> event_debug_pad = nullptr;
+static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_1;
+static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_2;
+static Kernel::SharedPtr<Kernel::Event> event_accelerometer;
+static Kernel::SharedPtr<Kernel::Event> event_gyroscope;
+static Kernel::SharedPtr<Kernel::Event> event_debug_pad;
-static u32 next_pad_index = 0;
-static u32 next_touch_index = 0;
+static u32 next_pad_index;
+static u32 next_touch_index;
// TODO(peachum):
// Add a method for setting analog input from joystick device for the circle Pad.
@@ -175,6 +175,12 @@ void Init() {
}
void Shutdown() {
+ shared_mem = nullptr;
+ event_pad_or_touch_1 = nullptr;
+ event_pad_or_touch_2 = nullptr;
+ event_accelerometer = nullptr;
+ event_gyroscope = nullptr;
+ event_debug_pad = nullptr;
}
} // 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 @@
namespace Service {
namespace IR {
-static Kernel::SharedPtr<Kernel::Event> handle_event = nullptr;
-static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory = nullptr;
+static Kernel::SharedPtr<Kernel::Event> handle_event;
+static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory;
void GetHandles(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
@@ -41,6 +41,8 @@ void Init() {
}
void Shutdown() {
+ shared_memory = nullptr;
+ handle_event = nullptr;
}
} // 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 @@
namespace NWM_UDS {
-static Kernel::SharedPtr<Kernel::Event> handle_event = nullptr;
+static Kernel::SharedPtr<Kernel::Event> handle_event;
/**
* 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 };
/// Id of the SharedExtData archive used by the PTM process
static const std::vector<u8> ptm_shared_extdata_id = {0, 0, 0, 0, 0x0B, 0, 0, 0xF0, 0, 0, 0, 0};
-static bool shell_open = true;
+static bool shell_open;
-static bool battery_is_charging = true;
+static bool battery_is_charging;
u32 GetAdapterState() {
// TODO(purpasmart96): This function is only a stub,
@@ -43,6 +43,9 @@ void Init() {
AddService(new PTM_Sysm_Interface);
AddService(new PTM_U_Interface);
+ shell_open = true;
+ battery_is_charging = true;
+
// Open the SharedExtSaveData archive 0xF000000B and create the gamecoin.dat file if it doesn't exist
FileSys::Path archive_path(ptm_shared_extdata_id);
auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path);
diff --git a/src/core/hle/service/ptm/ptm_sysm.cpp b/src/core/hle/service/ptm/ptm_sysm.cpp
index 2d841f69c..13322bdbb 100644
--- a/src/core/hle/service/ptm/ptm_sysm.cpp
+++ b/src/core/hle/service/ptm/ptm_sysm.cpp
@@ -16,7 +16,7 @@ namespace PTM {
* 1: Result code, 0 on success, otherwise error code
* 2: Whether the system is going through a power off
*/
-void IsLegacyPowerOff(Service::Interface* self) {
+static void IsLegacyPowerOff(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw;
cmd_buff[2] = 0;
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 134ff1740..d50327cb9 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -51,6 +51,49 @@ namespace Service {
std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports;
std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services;
+/**
+ * Creates a function string for logging, complete with the name (or header code, depending
+ * on what's passed in) the port name, and all the cmd_buff arguments.
+ */
+static std::string MakeFunctionString(const char* name, const char* port_name, const u32* cmd_buff) {
+ // Number of params == bits 0-5 + bits 6-11
+ int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F);
+
+ std::string function_string = Common::StringFromFormat("function '%s': port=%s", name, port_name);
+ for (int i = 1; i <= num_params; ++i) {
+ function_string += Common::StringFromFormat(", cmd_buff[%i]=%u", i, cmd_buff[i]);
+ }
+ return function_string;
+}
+
+ResultVal<bool> Interface::SyncRequest() {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ auto itr = m_functions.find(cmd_buff[0]);
+
+ if (itr == m_functions.end() || itr->second.func == nullptr) {
+ std::string function_name = (itr == m_functions.end()) ? Common::StringFromFormat("0x%08X", cmd_buff[0]) : itr->second.name;
+ LOG_ERROR(Service, "unknown / unimplemented %s", MakeFunctionString(function_name.c_str(), GetPortName().c_str(), cmd_buff).c_str());
+
+ // TODO(bunnei): Hack - ignore error
+ cmd_buff[1] = 0;
+ return MakeResult<bool>(false);
+ } else {
+ LOG_TRACE(Service, "%s", MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str());
+ }
+
+ itr->second.func(this);
+
+ return MakeResult<bool>(false); // TODO: Implement return from actual function
+}
+
+void Interface::Register(const FunctionInfo* functions, size_t n) {
+ m_functions.reserve(n);
+ for (size_t i = 0; i < n; ++i) {
+ // Usually this array is sorted by id already, so hint to instead at the end
+ m_functions.emplace_hint(m_functions.cend(), functions[i].id, functions[i]);
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// Module interface
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index bfe16ebad..21ada67b5 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -4,20 +4,15 @@
#pragma once
-#include <algorithm>
#include <string>
#include <unordered_map>
-#include <vector>
#include <boost/container/flat_map.hpp>
#include "common/common.h"
-#include "common/string_util.h"
-#include "core/mem_map.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/session.h"
-#include "core/hle/svc.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace Service
@@ -26,31 +21,11 @@ namespace Service {
static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters)
-class Manager;
-
/// Interface to a CTROS service
class Interface : public Kernel::Session {
// TODO(yuriks): An "Interface" being a Kernel::Object is mostly non-sense. Interface should be
// just something that encapsulates a session and acts as a helper to implement service
// processes.
-
- friend class Manager;
-
- /**
- * Creates a function string for logging, complete with the name (or header code, depending
- * on what's passed in) the port name, and all the cmd_buff arguments.
- */
- std::string MakeFunctionString(const char* name, const char* port_name, const u32* cmd_buff) {
- // Number of params == bits 0-5 + bits 6-11
- int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F);
-
- std::string function_string = Common::StringFromFormat("function '%s': port=%s", name, port_name);
- for (int i = 1; i <= num_params; ++i) {
- function_string += Common::StringFromFormat(", cmd_buff[%i]=%u", i, cmd_buff[i]);
- }
- return function_string;
- }
-
public:
std::string GetName() const override { return GetPortName(); }
@@ -70,25 +45,7 @@ public:
return "[UNKNOWN SERVICE PORT]";
}
- ResultVal<bool> SyncRequest() override {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- auto itr = m_functions.find(cmd_buff[0]);
-
- if (itr == m_functions.end() || itr->second.func == nullptr) {
- std::string function_name = (itr == m_functions.end()) ? Common::StringFromFormat("0x%08X", cmd_buff[0]) : itr->second.name;
- LOG_ERROR(Service, "unknown / unimplemented %s", MakeFunctionString(function_name.c_str(), GetPortName().c_str(), cmd_buff).c_str());
-
- // TODO(bunnei): Hack - ignore error
- cmd_buff[1] = 0;
- return MakeResult<bool>(false);
- } else {
- LOG_TRACE(Service, "%s", MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str());
- }
-
- itr->second.func(this);
-
- return MakeResult<bool>(false); // TODO: Implement return from actual function
- }
+ ResultVal<bool> SyncRequest() override;
protected:
@@ -96,14 +53,12 @@ protected:
* Registers the functions in the service
*/
template <size_t N>
- void Register(const FunctionInfo (&functions)[N]) {
- m_functions.reserve(N);
- for (auto& fn : functions) {
- // Usually this array is sorted by id already, so hint to instead at the end
- m_functions.emplace_hint(m_functions.cend(), fn.id, fn);
- }
+ inline void Register(const FunctionInfo (&functions)[N]) {
+ Register(functions, N);
}
+ void Register(const FunctionInfo* functions, size_t n);
+
private:
boost::container::flat_map<u32, FunctionInfo> m_functions;
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 @@
namespace Y2R_U {
-static Kernel::SharedPtr<Kernel::Event> completion_event = 0;
+static Kernel::SharedPtr<Kernel::Event> completion_event;
/**
* 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);
template void Read<u8>(u8 &var, const u32 addr);
void Set3DSlider(float amount) {
+ memset(&shared_page, 0, sizeof(shared_page));
+
shared_page.sliderstate_3d = amount;
shared_page.ledstate_3d = (amount == 0.0f); // off when non-zero
}
@@ -71,4 +73,7 @@ void Init() {
Set3DSlider(0.0f);
}
+void Shutdown() {
+}
+
} // 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);
void Init();
+void Shutdown();
+
} // namespace
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 76e9b171a..2da488d83 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -4,6 +4,7 @@
#include <map>
+#include "common/profiler.h"
#include "common/string_util.h"
#include "common/symbols.h"
@@ -606,7 +607,17 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32
return RESULT_SUCCESS;
}
-const HLE::FunctionDef SVC_Table[] = {
+namespace {
+ struct FunctionDef {
+ using Func = void();
+
+ u32 id;
+ Func* func;
+ const char* name;
+ };
+}
+
+static const FunctionDef SVC_Table[] = {
{0x00, nullptr, "Unknown"},
{0x01, HLE::Wrap<ControlMemory>, "ControlMemory"},
{0x02, HLE::Wrap<QueryMemory>, "QueryMemory"},
@@ -735,8 +746,28 @@ const HLE::FunctionDef SVC_Table[] = {
{0x7D, nullptr, "QueryProcessMemory"},
};
-void Register() {
- HLE::RegisterModule("SVC_Table", ARRAY_SIZE(SVC_Table), SVC_Table);
+Common::Profiling::TimingCategory profiler_svc("SVC Calls");
+
+static const FunctionDef* GetSVCInfo(u32 opcode) {
+ u32 func_num = opcode & 0xFFFFFF; // 8 bits
+ if (func_num >= ARRAY_SIZE(SVC_Table)) {
+ LOG_ERROR(Kernel_SVC, "unknown svc=0x%02X", func_num);
+ return nullptr;
+ }
+ return &SVC_Table[func_num];
+}
+
+void CallSVC(u32 opcode) {
+ Common::Profiling::ScopeTimer timer_svc(profiler_svc);
+
+ const FunctionDef *info = GetSVCInfo(opcode);
+ if (info) {
+ if (info->func) {
+ info->func();
+ } else {
+ LOG_ERROR(Kernel_SVC, "unimplemented SVC function %s(..)", info->name);
+ }
+ }
}
} // namespace
diff --git a/src/core/hle/svc.h b/src/core/hle/svc.h
index 5d020a5ba..4389aa73d 100644
--- a/src/core/hle/svc.h
+++ b/src/core/hle/svc.h
@@ -41,6 +41,6 @@ enum ArbitrationType {
namespace SVC {
-void Register();
+void CallSVC(u32 opcode);
} // 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 {
Regs g_regs;
/// True if the current frame was skipped
-bool g_skip_frame = false;
-
+bool g_skip_frame;
/// 268MHz / gpu_refresh_rate frames per second
static u64 frame_ticks;
/// Event id for CoreTiming
@@ -38,7 +37,7 @@ static int vblank_event;
/// Total number of frames drawn
static u64 frame_count;
/// True if the last frame was skipped
-static bool last_skip_frame = false;
+static bool last_skip_frame;
template <typename T>
inline void Read(T &var, const u32 raw_addr) {
@@ -320,6 +319,8 @@ static void VBlankCallback(u64 userdata, int cycles_late) {
/// Initialize hardware
void Init() {
+ memset(&g_regs, 0, sizeof(g_regs));
+
auto& framebuffer_top = g_regs.framebuffer_config[0];
auto& framebuffer_sub = g_regs.framebuffer_config[1];
@@ -349,6 +350,7 @@ void Init() {
frame_ticks = 268123480 / Settings::values.gpu_refresh_rate;
last_skip_frame = false;
g_skip_frame = false;
+ frame_count = 0;
vblank_event = CoreTiming::RegisterEvent("GPU::VBlankCallback", VBlankCallback);
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() {
/// Shutdown hardware
void Shutdown() {
+ GPU::Shutdown();
+ LCD::Shutdown();
LOG_DEBUG(HW, "shutdown OK");
}
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);
/// Initialize hardware
void Init() {
+ memset(&g_regs, 0, sizeof(g_regs));
LOG_DEBUG(HW_LCD, "initialized OK");
}
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index aaaa4d650..4efed78bf 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -198,20 +198,33 @@ ResultStatus AppLoader_NCCH::Load() {
if (file->ReadBytes(&exheader_header, sizeof(ExHeader_Header)) != sizeof(ExHeader_Header))
return ResultStatus::Error;
- is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1;
- entry_point = exheader_header.codeset_info.text.address;
-
- LOG_INFO(Loader, "Name: %s", exheader_header.codeset_info.name);
- LOG_DEBUG(Loader, "Code compressed: %s", is_compressed ? "yes" : "no");
- LOG_DEBUG(Loader, "Entry point: 0x%08X", entry_point);
+ is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1;
+ entry_point = exheader_header.codeset_info.text.address;
+ code_size = exheader_header.codeset_info.text.code_size;
+ stack_size = exheader_header.codeset_info.stack_size;
+ bss_size = exheader_header.codeset_info.bss_size;
+ core_version = exheader_header.arm11_system_local_caps.core_version;
+ priority = exheader_header.arm11_system_local_caps.priority;
+ resource_limit_category = exheader_header.arm11_system_local_caps.resource_limit_category;
+
+ LOG_INFO(Loader, "Name: %s" , exheader_header.codeset_info.name);
+ LOG_DEBUG(Loader, "Code compressed: %s" , is_compressed ? "yes" : "no");
+ LOG_DEBUG(Loader, "Entry point: 0x%08X", entry_point);
+ LOG_DEBUG(Loader, "Code size: 0x%08X", code_size);
+ LOG_DEBUG(Loader, "Stack size: 0x%08X", stack_size);
+ LOG_DEBUG(Loader, "Bss size: 0x%08X", bss_size);
+ LOG_DEBUG(Loader, "Core version: %d" , core_version);
+ LOG_DEBUG(Loader, "Thread priority: 0x%X" , priority);
+ LOG_DEBUG(Loader, "Resource limit descriptor: 0x%08X", exheader_header.arm11_system_local_caps.resource_limit_descriptor);
+ LOG_DEBUG(Loader, "Resource limit category: %d" , resource_limit_category);
// Read ExeFS...
exefs_offset = ncch_header.exefs_offset * kBlockSize;
u32 exefs_size = ncch_header.exefs_size * kBlockSize;
- LOG_DEBUG(Loader, "ExeFS offset: 0x%08X", exefs_offset);
- LOG_DEBUG(Loader, "ExeFS size: 0x%08X", exefs_size);
+ LOG_DEBUG(Loader, "ExeFS offset: 0x%08X", exefs_offset);
+ LOG_DEBUG(Loader, "ExeFS size: 0x%08X", exefs_size);
file->Seek(exefs_offset + ncch_offset, SEEK_SET);
if (file->ReadBytes(&exefs_header, sizeof(ExeFs_Header)) != sizeof(ExeFs_Header))
@@ -247,8 +260,8 @@ ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const {
u32 romfs_offset = ncch_offset + (ncch_header.romfs_offset * kBlockSize) + 0x1000;
u32 romfs_size = (ncch_header.romfs_size * kBlockSize) - 0x1000;
- LOG_DEBUG(Loader, "RomFS offset: 0x%08X", romfs_offset);
- LOG_DEBUG(Loader, "RomFS size: 0x%08X", romfs_size);
+ LOG_DEBUG(Loader, "RomFS offset: 0x%08X", romfs_offset);
+ LOG_DEBUG(Loader, "RomFS size: 0x%08X", romfs_size);
buffer.resize(romfs_size);
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
index f6f670060..3dd151dbd 100644
--- a/src/core/loader/ncch.h
+++ b/src/core/loader/ncch.h
@@ -43,6 +43,8 @@ struct NCCH_Header {
u8 romfs_super_block_hash[0x20];
};
+static_assert(sizeof(NCCH_Header) == 0x200, "NCCH header structure size is wrong");
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// ExeFS (executable file system) headers
@@ -77,11 +79,11 @@ struct ExHeader_CodeSetInfo {
u8 name[8];
ExHeader_SystemInfoFlags flags;
ExHeader_CodeSegmentInfo text;
- u8 stacksize[4];
+ u32 stack_size;
ExHeader_CodeSegmentInfo ro;
u8 reserved[4];
ExHeader_CodeSegmentInfo data;
- u8 bsssize[4];
+ u32 bss_size;
};
struct ExHeader_DependencyList{
@@ -107,9 +109,9 @@ struct ExHeader_ARM11_SystemLocalCaps{
u32 core_version;
u8 flags[3];
u8 priority;
- u8 resource_limit_descriptor[0x16][2];
+ u8 resource_limit_descriptor[0x10][2];
ExHeader_StorageInfo storage_info;
- u8 service_access_control[0x32][8];
+ u8 service_access_control[0x20][8];
u8 ex_service_access_control[0x2][8];
u8 reserved[0xf];
u8 resource_limit_category;
@@ -141,6 +143,8 @@ struct ExHeader_Header{
} access_desc;
};
+static_assert(sizeof(ExHeader_Header) == 0x800, "ExHeader structure size is wrong");
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// Loader namespace
@@ -224,6 +228,12 @@ private:
bool is_compressed = false;
u32 entry_point = 0;
+ u32 code_size = 0;
+ u32 stack_size = 0;
+ u32 bss_size = 0;
+ u32 core_version = 0;
+ u8 priority = 0;
+ u8 resource_limit_category = 0;
u32 ncch_offset = 0; // Offset to NCCH header, can be 0 or after NCSD header
u32 exefs_offset = 0;
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 @@
namespace Memory {
-u8* g_base = nullptr; ///< The base pointer to the auto-mirrored arena.
-
-static MemArena arena; ///< The MemArena class
-
-u8* g_exefs_code = nullptr; ///< ExeFS:/.code is loaded here
-u8* g_system_mem = nullptr; ///< System memory
-u8* g_heap = nullptr; ///< Application heap (main memory)
-u8* g_heap_linear = nullptr; ///< Linear heap
-u8* g_vram = nullptr; ///< Video memory (VRAM) pointer
-u8* g_shared_mem = nullptr; ///< Shared memory
-u8* g_dsp_mem = nullptr; ///< DSP memory
-u8* g_kernel_mem; ///< Kernel memory
-
-static u8* physical_bootrom = nullptr; ///< Bootrom physical memory
-static u8* uncached_bootrom = nullptr;
-
-static u8* physical_exefs_code = nullptr; ///< Phsical ExeFS:/.code is loaded here
-static u8* physical_system_mem = nullptr; ///< System physical memory
-static u8* physical_fcram = nullptr; ///< Main physical memory (FCRAM)
-static u8* physical_heap_gsp = nullptr; ///< GSP heap physical memory
-static u8* physical_vram = nullptr; ///< Video physical memory (VRAM)
-static u8* physical_shared_mem = nullptr; ///< Physical shared memory
-static u8* physical_dsp_mem = nullptr; ///< Physical DSP memory
-static u8* physical_kernel_mem; ///< Kernel memory
+u8* g_base; ///< The base pointer to the auto-mirrored arena.
+
+static MemArena arena; ///< The MemArena class
+
+u8* g_exefs_code; ///< ExeFS:/.code is loaded here
+u8* g_system_mem; ///< System memory
+u8* g_heap; ///< Application heap (main memory)
+u8* g_heap_linear; ///< Linear heap
+u8* g_vram; ///< Video memory (VRAM) pointer
+u8* g_shared_mem; ///< Shared memory
+u8* g_dsp_mem; ///< DSP memory
+u8* g_kernel_mem; ///< Kernel memory
+
+static u8* physical_bootrom; ///< Bootrom physical memory
+static u8* uncached_bootrom;
+
+static u8* physical_exefs_code; ///< Phsical ExeFS:/.code is loaded here
+static u8* physical_system_mem; ///< System physical memory
+static u8* physical_fcram; ///< Main physical memory (FCRAM)
+static u8* physical_heap_gsp; ///< GSP heap physical memory
+static u8* physical_vram; ///< Video physical memory (VRAM)
+static u8* physical_shared_mem; ///< Physical shared memory
+static u8* physical_dsp_mem; ///< Physical DSP memory
+static u8* physical_kernel_mem; ///< Kernel memory
// We don't declare the IO region in here since its handled by other means.
static MemoryView g_views[] = {
@@ -73,6 +73,7 @@ void Init() {
}
g_base = MemoryMap_Setup(g_views, kNumMemViews, flags, &arena);
+ MemBlock_Init();
LOG_DEBUG(HW_Memory, "initialized OK, RAM at %p (mirror at 0 @ %p)", g_heap,
physical_fcram);
@@ -81,9 +82,29 @@ void Init() {
void Shutdown() {
u32 flags = 0;
MemoryMap_Shutdown(g_views, kNumMemViews, flags, &arena);
-
arena.ReleaseSpace();
+ MemBlock_Shutdown();
+
g_base = nullptr;
+ g_exefs_code = nullptr;
+ g_system_mem = nullptr;
+ g_heap = nullptr;
+ g_heap_linear = nullptr;
+ g_vram = nullptr;
+ g_shared_mem = nullptr;
+ g_dsp_mem = nullptr;
+ g_kernel_mem = nullptr;
+
+ physical_bootrom = nullptr;
+ uncached_bootrom = nullptr;
+ physical_exefs_code = nullptr;
+ physical_system_mem = nullptr;
+ physical_fcram = nullptr;
+ physical_heap_gsp = nullptr;
+ physical_vram = nullptr;
+ physical_shared_mem = nullptr;
+ physical_dsp_mem = nullptr;
+ physical_kernel_mem = nullptr;
LOG_DEBUG(HW_Memory, "shutdown OK");
}
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);
*/
u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions);
+/// Initialize mapped memory blocks
+void MemBlock_Init();
+
+/// Shutdown mapped memory blocks
+void MemBlock_Shutdown();
+
inline const char* GetCharPointer(const VAddr address) {
return (const char *)GetPointer(address);
}
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 {
static std::map<u32, MemoryBlock> heap_map;
static std::map<u32, MemoryBlock> heap_linear_map;
-static std::map<u32, MemoryBlock> shared_map;
/// Convert a physical address to virtual address
VAddr PhysicalToVirtualAddress(const PAddr addr) {
@@ -185,12 +184,6 @@ u8 *GetPointer(const VAddr vaddr) {
}
}
-/**
- * Maps a block of memory on the heap
- * @param size Size of block in bytes
- * @param operation Memory map operation type
- * @param flags Memory allocation flags
- */
u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions) {
MemoryBlock block;
@@ -208,12 +201,6 @@ u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions) {
return block.GetVirtualAddress();
}
-/**
- * Maps a block of memory on the linear heap
- * @param size Size of block in bytes
- * @param operation Memory map operation type
- * @param flags Memory allocation flags
- */
u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions) {
MemoryBlock block;
@@ -231,6 +218,14 @@ u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions) {
return block.GetVirtualAddress();
}
+void MemBlock_Init() {
+}
+
+void MemBlock_Shutdown() {
+ heap_map.clear();
+ heap_linear_map.clear();
+}
+
u8 Read8(const VAddr addr) {
u8 data = 0;
Read<u8>(data, addr);
diff --git a/src/core/system.cpp b/src/core/system.cpp
index f4c2df1cd..561ff82f0 100644
--- a/src/core/system.cpp
+++ b/src/core/system.cpp
@@ -14,11 +14,6 @@
namespace System {
-volatile State g_state;
-
-void UpdateState(State state) {
-}
-
void Init(EmuWindow* emu_window) {
Core::Init();
CoreTiming::Init();
@@ -29,13 +24,6 @@ void Init(EmuWindow* emu_window) {
VideoCore::Init(emu_window);
}
-void RunLoopFor(int cycles) {
- RunLoopUntil(CoreTiming::GetTicks() + cycles);
-}
-
-void RunLoopUntil(u64 global_cycles) {
-}
-
void Shutdown() {
VideoCore::Shutdown();
HLE::Shutdown();
diff --git a/src/core/system.h b/src/core/system.h
index 05d836530..59a75ca12 100644
--- a/src/core/system.h
+++ b/src/core/system.h
@@ -4,30 +4,11 @@
#pragma once
-#include "common/emu_window.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
+class EmuWindow;
namespace System {
-// State of the full emulator
-enum State {
- STATE_NULL = 0, ///< System is in null state, nothing initialized
- STATE_IDLE, ///< System is in an initialized state, but not running
- STATE_RUNNING, ///< System is running
- STATE_LOADING, ///< System is loading a ROM
- STATE_HALTED, ///< System is halted (error)
- STATE_STALLED, ///< System is stalled (unused)
- STATE_DEBUG, ///< System is in a special debug mode (unused)
- STATE_DIE ///< System is shutting down
-};
-
-extern volatile State g_state;
-
-void UpdateState(State state);
void Init(EmuWindow* emu_window);
-void RunLoopFor(int cycles);
-void RunLoopUntil(u64 global_cycles);
void Shutdown();
}
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index c460146cb..2d9d8ab1f 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -507,7 +507,7 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture
// Add modifier
unsigned table_index = (x < 2) ? table_index_1.Value() : table_index_2.Value();
- static const auto etc1_modifier_table = std::array<std::array<u8, 2>, 8>{{
+ static const std::array<std::array<u8, 2>, 8> etc1_modifier_table = {{
{ 2, 8 }, { 5, 17 }, { 9, 29 }, { 13, 42 },
{ 18, 60 }, { 24, 80 }, { 33, 106 }, { 47, 183 }
}};
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index dd46f0ec3..6ec253601 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -342,10 +342,10 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
case Regs::TextureConfig::MirroredRepeat:
{
- int coord = (int)((unsigned)val % (2 * size));
+ unsigned int coord = ((unsigned)val % (2 * size));
if (coord >= size)
coord = 2 * size - 1 - coord;
- return coord;
+ return (int)coord;
}
default: