diff --git a/.gitignore b/.gitignore
index 28e373e5..58a3f235 100644
--- a/.gitignore
+++ b/.gitignore
@@ -95,4 +95,4 @@ captures/
.vscode/
# Discord plugin for IntelliJ IDEA
-.idea\discord.xml
+.idea/discord.xml
diff --git a/.idea/scopes/SkylineCPP.xml b/.idea/scopes/SkylineCPP.xml
index 179a6bef..3b743f30 100644
--- a/.idea/scopes/SkylineCPP.xml
+++ b/.idea/scopes/SkylineCPP.xml
@@ -1,3 +1,3 @@
-
-
\ No newline at end of file
+
+
diff --git a/README.md b/README.md
index d1b05753..0bba4be4 100644
--- a/README.md
+++ b/README.md
@@ -10,12 +10,18 @@
- Skyline is an experimental emulator that runs on ARMv8 Android™ devices and emulates the functionality of a Nintendo Switch™ system. Skyline currently does not run any games, nor Homebrew. It's licensed under GPLv3, refer to the license file for more information.
+ Skyline is an experimental emulator that runs on ARMv8 Android™ devices and emulates the functionality of a Nintendo Switch™ system. It's licensed under GPLv3, refer to the license file for more information.
### Contact
> You can contact the core developers of Skyline at our [Discord](https://discord.gg/XnbXNQM). If you have any questions, feel free to ask.
+### Credit
+[](https://ryujinx.org/)
+[**Ryujinx**](https://ryujinx.org/)
+We've used Ryujinx throughout the project for reference, the amount of accuracy of their HLE kernel implementation is what makes them such an amazing reference.
+
+
### Disclaimer
* Nintendo Switch is a trademark of Nintendo Co., Ltd.
* Android is a trademark of Google LLC.
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 43655bb9..51267723 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -49,7 +49,8 @@
+ android:screenOrientation="landscape"
+ android:launchMode="singleInstance">
diff --git a/app/src/main/cpp/main.cpp b/app/src/main/cpp/main.cpp
index 917cc99a..c7db4637 100644
--- a/app/src/main/cpp/main.cpp
+++ b/app/src/main/cpp/main.cpp
@@ -44,12 +44,12 @@ extern "C" JNIEXPORT void Java_emu_skyline_GameActivity_executeRom(JNIEnv *env,
logger->Info("Launching ROM {}", romString);
env->ReleaseStringUTFChars(romJstring, romString);
os.Execute(romFd, static_cast(romType));
- logger->Info("Emulation has ended");
} catch (std::exception &e) {
logger->Error(e.what());
} catch (...) {
logger->Error("An unknown exception has occurred");
}
+ logger->Info("Emulation has ended");
auto end = std::chrono::steady_clock::now();
logger->Info("Done in: {} ms", (std::chrono::duration_cast(end - start).count()));
diff --git a/app/src/main/cpp/skyline/common.cpp b/app/src/main/cpp/skyline/common.cpp
index 9adb342b..d8a68ae0 100644
--- a/app/src/main/cpp/skyline/common.cpp
+++ b/app/src/main/cpp/skyline/common.cpp
@@ -18,23 +18,37 @@ namespace skyline {
void GroupMutex::lock(Group group) {
auto none = Group::None;
- constexpr u64 timeout = 1000; // The timeout in ns
- auto start = utils::GetTimeNs();
- while (next != group && !next.compare_exchange_weak(none, group)) {
- if (flag == group && ((utils::GetTimeNs() - start) > timeout)) {
- num++;
- return;
- }
+ constexpr u64 timeout = 100; // The timeout in ns
+ auto end = utils::GetTimeNs() + timeout;
+ while (true) {
+ if (next == group) {
+ if (flag == group) {
+ std::lock_guard lock(mtx);
+ if (flag == group) {
+ auto groupT = group;
+ next.compare_exchange_strong(groupT, Group::None);
+ num++;
+ return;
+ }
+ } else
+ flag.compare_exchange_weak(none, group);
+ } else if (flag == group && (next == Group::None || utils::GetTimeNs() >= end)) {
+ std::lock_guard lock(mtx);
+ if (flag == group) {
+ num++;
+ return;
+ }
+ } else
+ next.compare_exchange_weak(none, group);
+ none = Group::None;
asm volatile("yield");
}
- while (flag != group && !flag.compare_exchange_weak(none, group))
- asm volatile("yield");
- num++;
}
void GroupMutex::unlock() {
+ std::lock_guard lock(mtx);
if (!--num)
- flag.exchange(Group::None);
+ flag.exchange(next);
}
Settings::Settings(const int preferenceFd) {
@@ -118,6 +132,6 @@ namespace skyline {
gpu = std::move(std::make_shared(*this));
}
- thread_local std::shared_ptr DeviceState::thread = 0;
- thread_local ThreadContext *DeviceState::ctx = 0;
+ thread_local std::shared_ptr DeviceState::thread = nullptr;
+ thread_local ThreadContext *DeviceState::ctx = nullptr;
}
diff --git a/app/src/main/cpp/skyline/common.h b/app/src/main/cpp/skyline/common.h
index f7a6d9df..4ce173db 100644
--- a/app/src/main/cpp/skyline/common.h
+++ b/app/src/main/cpp/skyline/common.h
@@ -36,7 +36,7 @@ namespace skyline {
constexpr u8 NumRegs = 30; //!< The amount of registers that ARMv8 has
constexpr u32 TpidrroEl0 = 0x5E83; //!< ID of TPIDRRO_EL0 in MRS
constexpr u32 CntfrqEl0 = 0x5F00; //!< ID of CNTFRQ_EL0 in MRS
- constexpr u32 TegraX1Freq = 0x124F800; //!< The clock frequency of the Tegra X1 (19.2 MHz)
+ constexpr u32 TegraX1Freq = 19200000; //!< The clock frequency of the Tegra X1 (19.2 MHz)
constexpr u32 CntpctEl0 = 0x5F01; //!< ID of CNTPCT_EL0 in MRS
constexpr u32 CntvctEl0 = 0x5F02; //!< ID of CNTVCT_EL0 in MRS
// Kernel
@@ -101,18 +101,17 @@ namespace skyline {
* @return The current time in nanoseconds
*/
inline u64 GetTimeNs() {
- static u64 frequencyMs{};
- if (!frequencyMs) {
- asm("MRS %0, CNTFRQ_EL0" : "=r"(frequencyMs));
- frequencyMs *= 1000000000;
- }
+ constexpr uint64_t NsInSecond = 1000000000;
+ static u64 frequency{};
+ if (!frequency)
+ asm("MRS %0, CNTFRQ_EL0" : "=r"(frequency));
u64 ticks;
asm("MRS %0, CNTVCT_EL0" : "=r"(ticks));
- return ticks / frequencyMs;
+ return ((ticks / frequency) * NsInSecond) + (((ticks % frequency) * NsInSecond + (frequency / 2)) / frequency);
}
/**
- * @brief Aligns up a value to a multiple of twoB
+ * @brief Aligns up a value to a multiple of two
* @tparam Type The type of the values
* @param value The value to round up
* @param multiple The multiple to round up to (Should be a multiple of 2)
@@ -216,6 +215,7 @@ namespace skyline {
std::atomic flag = Group::None; //!< An atomic flag to hold which group holds the mutex
std::atomic next = Group::None; //!< An atomic flag to hold which group will hold the mutex next
std::atomic num = 0; //!< An atomic u8 keeping track of how many users are holding the mutex
+ Mutex mtx; //!< A mutex to lock before changing of num and flag
};
/**
diff --git a/app/src/main/cpp/skyline/gpu.cpp b/app/src/main/cpp/skyline/gpu.cpp
index cc2bc600..d6984297 100644
--- a/app/src/main/cpp/skyline/gpu.cpp
+++ b/app/src/main/cpp/skyline/gpu.cpp
@@ -31,9 +31,11 @@ namespace skyline::gpu {
resolution.width = static_cast(ANativeWindow_getWidth(window));
resolution.height = static_cast(ANativeWindow_getHeight(window));
format = ANativeWindow_getFormat(window);
+ surfaceUpdate = false;
+ } else if (Surface == nullptr) {
surfaceUpdate = true;
- } else
- surfaceUpdate = (Surface == nullptr);
+ return;
+ }
if (!bufferQueue.displayQueue.empty()) {
auto &buffer = bufferQueue.displayQueue.front();
bufferQueue.displayQueue.pop();
diff --git a/app/src/main/cpp/skyline/gpu/display.cpp b/app/src/main/cpp/skyline/gpu/display.cpp
index 9f5e96bf..49c7b614 100644
--- a/app/src/main/cpp/skyline/gpu/display.cpp
+++ b/app/src/main/cpp/skyline/gpu/display.cpp
@@ -62,7 +62,7 @@ namespace skyline::gpu {
break;
}
}
- sched_yield();
+ asm("yield");
}
struct {
u32 slot;
diff --git a/app/src/main/cpp/skyline/nce.cpp b/app/src/main/cpp/skyline/nce.cpp
index 8e23e364..369a766e 100644
--- a/app/src/main/cpp/skyline/nce.cpp
+++ b/app/src/main/cpp/skyline/nce.cpp
@@ -8,6 +8,7 @@
#include "nce.h"
extern bool Halt;
+extern jobject Surface;
extern skyline::GroupMutex jniMtx;
namespace skyline {
@@ -16,10 +17,17 @@ namespace skyline {
state.thread = state.process->threads.at(thread);
state.ctx = reinterpret_cast(state.thread->ctxMemory->kernel.address);
while (true) {
- std::lock_guard jniGd(jniMtx);
+ asm("yield");
if (Halt)
break;
+ if (!Surface)
+ continue;
if (state.ctx->state == ThreadState::WaitKernel) {
+ std::lock_guard jniGd(jniMtx);
+ if (Halt)
+ break;
+ if (!Surface)
+ continue;
const u16 svc = static_cast(state.ctx->commandId);
try {
if (kernel::svc::SvcTable[svc]) {
@@ -43,11 +51,14 @@ namespace skyline {
} catch (...) {
state.logger->Error("An unknown exception has occurred");
}
- if (thread == state.process->pid) {
- jniMtx.lock(GroupMutex::Group::Group2);
- state.os->KillThread(thread);
- Halt = true;
- jniMtx.unlock();
+ if (!Halt) {
+ if (thread == state.process->pid) {
+ jniMtx.lock(GroupMutex::Group::Group2);
+ state.os->KillThread(thread);
+ Halt = true;
+ jniMtx.unlock();
+ } else
+ state.os->KillThread(thread);
}
}
@@ -60,15 +71,17 @@ namespace skyline {
void NCE::Execute() {
while (true) {
- std::lock_guard jniGd(jniMtx);
+ std::lock_guard guard(jniMtx);
if (Halt)
break;
state.os->serviceManager.Loop();
state.gpu->Loop();
}
- jniMtx.lock(GroupMutex::Group::Group2);
- Halt = true;
- jniMtx.unlock();
+ if (!Halt) {
+ jniMtx.lock(GroupMutex::Group::Group2);
+ Halt = true;
+ jniMtx.unlock();
+ }
}
/**
@@ -93,7 +106,7 @@ namespace skyline {
}
void NCE::ExecuteFunction(ThreadCall call, Registers &funcRegs) {
- if(state.process->status == kernel::type::KProcess::Status::Exiting)
+ if (state.process->status == kernel::type::KProcess::Status::Exiting)
throw exception("Executing function on Exiting process");
auto thread = state.thread ? state.thread : state.process->threads.at(state.process->pid);
ExecuteFunctionCtx(call, funcRegs, reinterpret_cast(thread->ctxMemory->kernel.address));
@@ -151,67 +164,23 @@ namespace skyline {
state.logger->Debug("CPU Context:{}", regStr);
}
- const std::array cntpctEl0X0 = {
- 0xA9BF0BE1, // STP X1, X2, [SP, #-16]!
- 0x3C9F0FE0, // STR Q0, [SP, #-16]!
- 0x3C9F0FE1, // STR Q1, [SP, #-16]!
- 0x3C9F0FE2, // STR Q2, [SP, #-16]!
+ const std::array CntpctEl0 = {
+ 0xD10083FF, // SUB SP, SP, #32
+ 0xA90107E0, // STP X0, X1, [SP, #16]
+ 0xD28F0860, // MOV X0, #30787
+ 0xF2AE3680, // MOVK X0, #29108, LSL #16
0xD53BE001, // MRS X1, CNTFRQ_EL0
- 0xD53BE042, // MRS X2, CNTVCT_EL0
- 0x9E630020, // UCVTF D0, X0
- 0xD2C9F001, // MOV X1, 87411174408192
- 0xF2E82E41, // MOVK X1, 0x4172, LSL 48
- 0x9E670022, // FMOV D2, X1
- 0x9E630041, // UCVTF D1, X1
- 0x1E621800, // FDIV D0, D0, D2
- 0x1E610800, // FMUL D0, D0, D1
- 0x9E790000, // FCVTZU X0, D0
- 0x3CC107E2, // LDR Q2, [SP], #16
- 0x3CC107E1, // LDR Q1, [SP], #16
- 0x3CC107E0, // LDR Q0, [SP], #16
- 0xA8C10BE1, // LDP X1, X2, [SP], #16
- };
-
- const std::array cntpctEl0X1 = {
- 0xA9BF0BE0, // STP X0, X2, [SP, #-16]!
- 0x3C9F0FE0, // STR Q0, [SP, #-16]!
- 0x3C9F0FE1, // STR Q1, [SP, #-16]!
- 0x3C9F0FE2, // STR Q2, [SP, #-16]!
- 0xD53BE000, // MRS X0, CNTFRQ_EL0
- 0xD53BE042, // MRS X2, CNTVCT_EL0
- 0x9E630020, // UCVTF D0, X0
- 0xD2C9F000, // MOV X0, 87411174408192
- 0xF2E82E40, // MOVK X0, 0x4172, LSL 48
- 0x9E670002, // FMOV D2, X0
- 0x9E630041, // UCVTF D1, X2
- 0x1E621800, // FDIV D0, D0, D2
- 0x1E610800, // FMUL D0, D0, D1
- 0x9E790001, // FCVTZU X0, D0
- 0x3CC107E2, // LDR Q2, [SP], #16
- 0x3CC107E1, // LDR Q1, [SP], #16
- 0x3CC107E0, // LDR Q0, [SP], #16
- 0xA8C10BE0, // LDP X0, X2, [SP], #16
- };
-
- std::array cntpctEl0Xn = {
- 0xA9BF07E0, // STP X0, X1, [SP, #-16]!
- 0x3C9F0FE0, // STR Q0, [SP, #-16]!
- 0x3C9F0FE1, // STR Q1, [SP, #-16]!
- 0x3C9F0FE2, // STR Q2, [SP, #-16]!
- 0xD53BE000, // MRS X0, CNTFRQ_EL0
- 0xD53BE041, // MRS X1, CNTVCT_EL0
- 0x9E630000, // UCVTF D0, X0
- 0xD2C9F000, // MOV X0, 87411174408192
- 0xF2E82E40, // MOVK X0, 0x4172, LSL 48
- 0x9E670002, // FMOV D2, X0
- 0x9E630021, // UCVTF D1, X1
- 0x1E621800, // FDIV D0, D0, D2
- 0x1E610800, // FMUL D0, D0, D1
- 0x00000000, // FCVTZU Xn, D0 (Set at runtime)
- 0x3CC107E2, // LDR Q2, [SP], #16
- 0x3CC107E1, // LDR Q1, [SP], #16
- 0x3CC107E0, // LDR Q0, [SP], #16
- 0xA8C107E0, // LDP X0, X1, [SP], #16
+ 0xF2CB5880, // MOVK X0, #23236, LSL #32
+ 0xD345FC21, // LSR X1, X1, #5
+ 0xF2E14F80, // MOVK X0, #2684, LSL #48
+ 0x9BC07C21, // UMULH X1, X1, X0
+ 0xD347FC21, // LSR X1, X1, #7
+ 0xD53BE040, // MRS X0, CNTVCT_EL0
+ 0x9AC10801, // UDIV X1, X0, X1
+ 0x8B010421, // ADD X1, X1, X1, LSL #1
+ 0xD37AE420, // LSL X0, X1, #6
+ 0xF90003E0, // STR X0, [SP, #0]
+ 0xA94107E0, // LDP X0, X1, [SP, #16]
};
std::vector NCE::PatchCode(std::vector &code, u64 baseAddress, i64 offset) {
@@ -232,6 +201,10 @@ namespace skyline {
reinterpret_cast(&guest::svcHandler), guest::svcHandlerSize);
offset += guest::svcHandlerSize;
+ static u64 frequency{};
+ if (!frequency)
+ asm("MRS %0, CNTFRQ_EL0" : "=r"(frequency));
+
for (u32 *address = start; address < end; address++) {
auto instrSvc = reinterpret_cast(address);
auto instrMrs = reinterpret_cast(address);
@@ -275,9 +248,9 @@ namespace skyline {
strX0 = 0xF81F0FE0; // STR X0, [SP, #-16]!
offset += sizeof(strX0);
}
- u32 mrsX0 = 0xD53BD040; // MRS X0, TPIDR_EL0
+ const u32 mrsX0 = 0xD53BD040; // MRS X0, TPIDR_EL0
offset += sizeof(mrsX0);
- u32 ldrTls = 0xF9408000; // LDR X0, [X0, #256]
+ const u32 ldrTls = 0xF9408000; // LDR X0, [X0, #256]
offset += sizeof(ldrTls);
u32 movXn{};
u32 ldrX0{};
@@ -300,41 +273,41 @@ namespace skyline {
if (ldrX0)
patch.push_back(ldrX0);
patch.push_back(bret.raw);
- } else if (instrMrs->srcReg == constant::CntpctEl0) {
- instr::B bjunc(offset);
- if (instrMrs->destReg == 0)
- offset += cntpctEl0X0.size() * sizeof(u32);
- else if (instrMrs->destReg == 1)
- offset += cntpctEl0X1.size() * sizeof(u32);
- else
- offset += cntpctEl0Xn.size() * sizeof(u32);
- instr::B bret(-offset + sizeof(u32));
- offset += sizeof(bret);
+ } else if (frequency != constant::TegraX1Freq) {
+ if (instrMrs->srcReg == constant::CntpctEl0) {
+ instr::B bjunc(offset);
+ offset += CntpctEl0.size() * sizeof(u32);
+ instr::Ldr ldr(0xF94003E0); // LDR XOUT, [SP]
+ ldr.destReg = instrMrs->destReg;
+ offset += sizeof(ldr);
+ const u32 addSp = 0x910083FF; // ADD SP, SP, #32
+ offset += sizeof(addSp);
+ instr::B bret(-offset + sizeof(u32));
+ offset += sizeof(bret);
- *address = bjunc.raw;
- if (instrMrs->destReg == 0)
- for (auto &instr : cntpctEl0X0)
+ *address = bjunc.raw;
+ for (const auto &instr : CntpctEl0)
patch.push_back(instr);
- else if (instrMrs->destReg == 1)
- for (auto &instr : cntpctEl0X1)
- patch.push_back(instr);
- else {
- cntpctEl0Xn[13] = instr::Fcvtzu(regs::X(instrMrs->destReg), 0).raw;
- for (auto &instr : cntpctEl0Xn)
+ patch.push_back(ldr.raw);
+ patch.push_back(addSp);
+ patch.push_back(bret.raw);
+ } else if (instrMrs->srcReg == constant::CntfrqEl0) {
+ instr::B bjunc(offset);
+ auto movFreq = instr::MoveU32Reg(static_cast(instrMrs->destReg), constant::TegraX1Freq);
+ offset += sizeof(u32) * movFreq.size();
+ instr::B bret(-offset + sizeof(u32));
+ offset += sizeof(bret);
+
+ *address = bjunc.raw;
+ for (auto &instr : movFreq)
patch.push_back(instr);
+ patch.push_back(bret.raw);
+ }
+ } else {
+ if (instrMrs->srcReg == constant::CntpctEl0) {
+ instr::Mrs mrs(constant::CntvctEl0, regs::X(instrMrs->destReg));
+ *address = mrs.raw;
}
- patch.push_back(bret.raw);
- } else if (instrMrs->srcReg == constant::CntfrqEl0) {
- instr::B bjunc(offset);
- auto movFreq = instr::MoveU32Reg(static_cast(instrMrs->destReg), constant::TegraX1Freq);
- offset += sizeof(u32) * movFreq.size();
- instr::B bret(-offset + sizeof(u32));
- offset += sizeof(bret);
-
- *address = bjunc.raw;
- for (auto &instr : movFreq)
- patch.push_back(instr);
- patch.push_back(bret.raw);
}
}
offset -= sizeof(u32);
diff --git a/app/src/main/cpp/skyline/nce/guest.cpp b/app/src/main/cpp/skyline/nce/guest.cpp
index e9a0c670..63226960 100644
--- a/app/src/main/cpp/skyline/nce/guest.cpp
+++ b/app/src/main/cpp/skyline/nce/guest.cpp
@@ -278,10 +278,8 @@ namespace skyline::guest {
.sa_sigaction = reinterpret_cast(reinterpret_cast(signalHandler)),
.sa_flags = SA_SIGINFO,
};
- /*
for (int signal : {SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV})
sigaction(signal, &sigact, nullptr);
- */
ctx->state = ThreadState::Running;
asm("MOV LR, %0\n\t"
"MOV X0, %1\n\t"
diff --git a/app/src/main/cpp/skyline/nce/instr.h b/app/src/main/cpp/skyline/nce/instr.h
index 4460ba8b..baf170ff 100644
--- a/app/src/main/cpp/skyline/nce/instr.h
+++ b/app/src/main/cpp/skyline/nce/instr.h
@@ -302,30 +302,33 @@ namespace skyline {
};
static_assert(sizeof(Movk) == sizeof(u32));
- const std::array MoveU64Reg(regs::X destReg, u64 value) {
+ const std::vector MoveU64Reg(regs::X destReg, u64 value) {
union {
u64 val;
struct {
u16 v0;
u16 v16;
u16 v32;
- u16 v64;
+ u16 v48;
};
} val;
val.val = value;
- std::array instr;
+ std::vector instr;
instr::Movz mov0(destReg, val.v0, 0);
- instr[0] = mov0.raw;
+ instr.push_back(mov0.raw);
instr::Movk mov16(destReg, val.v16, 16);
- instr[1] = mov16.raw;
+ if (val.v16)
+ instr.push_back(mov16.raw);
instr::Movk mov32(destReg, val.v32, 32);
- instr[2] = mov32.raw;
- instr::Movk mov64(destReg, val.v64, 48);
- instr[3] = mov64.raw;
+ if (val.v32)
+ instr.push_back(mov32.raw);
+ instr::Movk mov48(destReg, val.v48, 48);
+ if (val.v48)
+ instr.push_back(mov48.raw);
return instr;
}
- const std::array MoveU32Reg(regs::X destReg, u32 value) {
+ const std::vector MoveU32Reg(regs::X destReg, u32 value) {
union {
u32 val;
struct {
@@ -334,11 +337,12 @@ namespace skyline {
};
} val;
val.val = value;
- std::array instr;
+ std::vector instr;
instr::Movz mov0(destReg, val.v0, 0);
- instr[0] = mov0.raw;
+ instr.push_back(mov0.raw);
instr::Movk mov16(destReg, val.v16, 16);
- instr[1] = mov16.raw;
+ if (val.v16)
+ instr.push_back(mov16.raw);
return instr;
}
@@ -398,44 +402,37 @@ namespace skyline {
static_assert(sizeof(Mov) == sizeof(u32));
/**
- * @brief A bit-field struct that encapsulates a FCVTZU (Scalar, Integer) instruction. See https://developer.arm.com/docs/ddi0602/d/simd-and-floating-point-instructions-alphabetic-order/fcvtzu-scalar-integer-floating-point-convert-to-unsigned-integer-rounding-toward-zero-scalar.
+ * @brief A bit-field struct that encapsulates a LDR (immediate) instruction. See https://developer.arm.com/docs/ddi0596/e/base-instructions-alphabetic-order/ldr-immediate-load-register-immediate.
*/
- struct Fcvtzu {
+ struct Ldr {
public:
/**
- * @brief Creates a FCVTZU (Scalar, Integer) instruction
- * @param destReg The destination Xn register to store the value in
- * @param srcReg The source Dn register to retrieve the value from
+ * @brief Creates a LDR (immediate) instruction
+ * @param raw The raw value of the whole instruction
*/
- Fcvtzu(regs::X destReg, u8 srcReg) {
- this->destReg = static_cast(destReg);
- this->srcReg = static_cast(srcReg);
- sig0 = 0xE40;
- ftype = 1;
- sig1 = 0x1E;
- sf = 1;
- }
+ Ldr(u32 raw) : raw(raw) {}
/**
* @brief Returns if the opcode is valid or not
* @return If the opcode represents a valid FCVTZU instruction
*/
inline bool Verify() {
- return (sig0 == 0xE40 && sig1 == 0x1E);
+ return (sig0 == 0x0 && sig1 == 0x1CA && sig2 == 0x1);
}
union {
struct __attribute__((packed)) {
u8 destReg : 5;
u8 srcReg : 5;
- u32 sig0 : 12;
- u8 ftype : 2;
- u8 sig1 : 7;
- u8 sf : 1;
+ u8 sig0 : 2;
+ u16 imm : 9;
+ u16 sig1 : 9;
+ u8 x : 1;
+ u8 sig2 : 1;
};
u32 raw{};
};
};
- static_assert(sizeof(Fcvtzu) == sizeof(u32));
+ static_assert(sizeof(Ldr) == sizeof(u32));
}
}
diff --git a/app/src/main/java/emu/skyline/GameActivity.kt b/app/src/main/java/emu/skyline/GameActivity.kt
index 188b0ed3..24fc6434 100644
--- a/app/src/main/java/emu/skyline/GameActivity.kt
+++ b/app/src/main/java/emu/skyline/GameActivity.kt
@@ -1,5 +1,6 @@
package emu.skyline
+import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.os.ParcelFileDescriptor
@@ -19,47 +20,61 @@ class GameActivity : AppCompatActivity(), SurfaceHolder.Callback, InputQueue.Cal
System.loadLibrary("skyline") // libskyline.so
}
- private lateinit var rom: Uri
private lateinit var romFd: ParcelFileDescriptor
private lateinit var preferenceFd: ParcelFileDescriptor
private lateinit var logFd: ParcelFileDescriptor
private var surface: Surface? = null
private var inputQueue: Long = 0L
+ private var shouldFinish: Boolean = true
private lateinit var gameThread: Thread
private external fun executeRom(romString: String, romType: Int, romFd: Int, preferenceFd: Int, logFd: Int)
private external fun setHalt(halt: Boolean)
private external fun setSurface(surface: Surface?)
+ fun executeRom(rom : Uri) {
+ val romType = getTitleFormat(rom, contentResolver).ordinal
+ romFd = contentResolver.openFileDescriptor(rom, "r")!!
+ gameThread = Thread {
+ while ((surface == null))
+ Thread.yield()
+ executeRom(Uri.decode(rom.toString()), romType, romFd.fd, preferenceFd.fd, logFd.fd)
+ if (shouldFinish)
+ runOnUiThread { finish() }
+ }
+ gameThread.start()
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.game_activity)
- rom = intent.data!!
- val romType = getTitleFormat(rom, contentResolver).ordinal
- romFd = contentResolver.openFileDescriptor(rom, "r")!!
val preference = File("${applicationInfo.dataDir}/shared_prefs/${applicationInfo.packageName}_preferences.xml")
preferenceFd = ParcelFileDescriptor.open(preference, ParcelFileDescriptor.MODE_READ_WRITE)
val log = File("${applicationInfo.dataDir}/skyline.log")
logFd = ParcelFileDescriptor.open(log, ParcelFileDescriptor.MODE_CREATE or ParcelFileDescriptor.MODE_READ_WRITE)
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN)
game_view.holder.addCallback(this)
- //window.takeInputQueue(this)
- gameThread = Thread {
- while ((surface == null))
- Thread.yield()
- executeRom(Uri.decode(rom.toString()), romType, romFd.fd, preferenceFd.fd, logFd.fd)
- runOnUiThread { finish() }
- }
- gameThread.start()
+ executeRom(intent.data!!)
+ }
+
+ override fun onNewIntent(intent: Intent?) {
+ shouldFinish = false
+ setHalt(true)
+ gameThread.join()
+ shouldFinish = true
+ romFd.close()
+ executeRom(intent?.data!!)
+ super.onNewIntent(intent)
}
override fun onDestroy() {
- super.onDestroy()
+ shouldFinish = false
setHalt(true)
gameThread.join()
romFd.close()
preferenceFd.close()
logFd.close()
+ super.onDestroy()
}
override fun surfaceCreated(holder: SurfaceHolder?) {