summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/arm/arm_interface.h2
-rw-r--r--src/core/arm/dyncom/arm_dyncom.cpp8
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp75
-rw-r--r--src/core/core.cpp13
-rw-r--r--src/core/core_timing.cpp709
-rw-r--r--src/core/core_timing.h77
-rw-r--r--src/core/file_sys/archive_extsavedata.cpp18
-rw-r--r--src/core/file_sys/archive_extsavedata.h2
-rw-r--r--src/core/file_sys/archive_savedata.cpp18
-rw-r--r--src/core/file_sys/archive_savedatacheck.cpp15
-rw-r--r--src/core/file_sys/archive_sdmc.cpp4
-rw-r--r--src/core/file_sys/archive_systemsavedata.cpp7
-rw-r--r--src/core/file_sys/archive_systemsavedata.h2
-rw-r--r--src/core/hle/kernel/kernel.cpp2
-rw-r--r--src/core/hle/kernel/thread.cpp25
-rw-r--r--src/core/hle/kernel/thread.h11
-rw-r--r--src/core/hle/service/cfg/cfg.cpp4
-rw-r--r--src/core/hle/service/fs/archive.cpp26
-rw-r--r--src/core/hle/service/fs/archive.h5
-rw-r--r--src/core/hle/service/gsp_gpu.cpp5
-rw-r--r--src/core/hle/service/ptm_u.cpp6
-rw-r--r--src/core/hle/service/service.cpp14
-rw-r--r--src/core/hle/service/service.h15
23 files changed, 571 insertions, 492 deletions
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 3b7209418..d3bd4a9a3 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -103,6 +103,8 @@ public:
return num_instructions;
}
+ s64 down_count; ///< A decreasing counter of remaining cycles before the next event, decreased by the cpu run loop
+
protected:
/**
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp
index a838fd25a..c779e3fd4 100644
--- a/src/core/arm/dyncom/arm_dyncom.cpp
+++ b/src/core/arm/dyncom/arm_dyncom.cpp
@@ -9,6 +9,8 @@
#include "core/arm/dyncom/arm_dyncom.h"
#include "core/arm/dyncom/arm_dyncom_interpreter.h"
+#include "core/core_timing.h"
+
const static cpu_config_t s_arm11_cpu_info = {
"armv6", "arm11", 0x0007b000, 0x0007f000, NONCACHE
};
@@ -77,6 +79,9 @@ u64 ARM_DynCom::GetTicks() const {
void ARM_DynCom::AddTicks(u64 ticks) {
this->ticks += ticks;
+ down_count -= ticks;
+ if (down_count < 0)
+ CoreTiming::Advance();
}
void ARM_DynCom::ExecuteInstructions(int num_instructions) {
@@ -85,7 +90,8 @@ void ARM_DynCom::ExecuteInstructions(int num_instructions) {
// Dyncom only breaks on instruction dispatch. This only happens on every instruction when
// executing one instruction at a time. Otherwise, if a block is being executed, more
// instructions may actually be executed than specified.
- ticks += InterpreterMainLoop(state.get());
+ unsigned ticks_executed = InterpreterMainLoop(state.get());
+ AddTicks(ticks_executed);
}
void ARM_DynCom::SaveContext(ThreadContext& ctx) {
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index 9b291862c..7c710ccde 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -947,6 +947,15 @@ typedef struct _smla_inst {
unsigned int Rn;
} smla_inst;
+typedef struct smlalxy_inst {
+ unsigned int x;
+ unsigned int y;
+ unsigned int RdLo;
+ unsigned int RdHi;
+ unsigned int Rm;
+ unsigned int Rn;
+} smlalxy_inst;
+
typedef struct ssat_inst {
unsigned int Rn;
unsigned int Rd;
@@ -2403,7 +2412,25 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(smlal)(unsigned int inst, int index)
return inst_base;
}
-ARM_INST_PTR INTERPRETER_TRANSLATE(smlalxy)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SMLALXY"); }
+ARM_INST_PTR INTERPRETER_TRANSLATE(smlalxy)(unsigned int inst, int index)
+{
+ arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlalxy_inst));
+ smlalxy_inst* const inst_cream = (smlalxy_inst*)inst_base->component;
+
+ inst_base->cond = BITS(inst, 28, 31);
+ inst_base->idx = index;
+ inst_base->br = NON_BRANCH;
+ inst_base->load_r15 = 0;
+
+ inst_cream->x = BIT(inst, 5);
+ inst_cream->y = BIT(inst, 6);
+ inst_cream->RdLo = BITS(inst, 12, 15);
+ inst_cream->RdHi = BITS(inst, 16, 19);
+ inst_cream->Rn = BITS(inst, 0, 4);
+ inst_cream->Rm = BITS(inst, 8, 11);
+
+ return inst_base;
+}
ARM_INST_PTR INTERPRETER_TRANSLATE(smlaw)(unsigned int inst, int index)
{
@@ -5686,6 +5713,34 @@ unsigned InterpreterMainLoop(ARMul_State* state) {
}
SMLALXY_INST:
+ {
+ if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
+ smlalxy_inst* const inst_cream = (smlalxy_inst*)inst_base->component;
+
+ u64 operand1 = RN;
+ u64 operand2 = RM;
+
+ if (inst_cream->x != 0)
+ operand1 >>= 16;
+ if (inst_cream->y != 0)
+ operand2 >>= 16;
+ operand1 &= 0xFFFF;
+ if (operand1 & 0x8000)
+ operand1 -= 65536;
+ operand2 &= 0xFFFF;
+ if (operand2 & 0x8000)
+ operand2 -= 65536;
+
+ u64 dest = ((u64)RDHI << 32 | RDLO) + (operand1 * operand2);
+ RDLO = (dest & 0xFFFFFFFF);
+ RDHI = ((dest >> 32) & 0xFFFFFFFF);
+ }
+
+ cpu->Reg[15] += GET_INST_SIZE(cpu);
+ INC_PC(sizeof(smlalxy_inst));
+ FETCH_INST;
+ GOTO_NEXT_INST;
+ }
SMLAW_INST:
{
@@ -5836,16 +5891,13 @@ unsigned InterpreterMainLoop(ARMul_State* state) {
SMULW_INST:
{
- if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
- smlad_inst *inst_cream = (smlad_inst *)inst_base->component;
- int64_t rm = RM;
- int64_t rn = RN;
- if (inst_cream->m)
- rm = BITS(rm, 16, 31);
- else
- rm = BITS(rm, 0, 15);
- int64_t rst = rm * rn;
- RD = BITS(rst, 16, 47);
+ if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
+ smlad_inst* const inst_cream = (smlad_inst*)inst_base->component;
+
+ s16 rm = (inst_cream->m == 1) ? ((RM >> 16) & 0xFFFF) : (RM & 0xFFFF);
+
+ s64 result = (s64)rm * (s64)(s32)RN;
+ RD = BITS(result, 16, 47);
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
INC_PC(sizeof(smlad_inst));
@@ -6267,6 +6319,7 @@ unsigned InterpreterMainLoop(ARMul_State* state) {
addr = RN;
unsigned int value = Memory::Read8(addr);
Memory::Write8(addr, (RM & 0xFF));
+ RD = value;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
INC_PC(sizeof(swp_inst));
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 8ac4481cc..98f8a7dff 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -5,6 +5,7 @@
#include "common/common_types.h"
#include "core/core.h"
+#include "core/core_timing.h"
#include "core/settings.h"
#include "core/arm/disassembler/arm_disasm.h"
@@ -23,7 +24,17 @@ ARM_Interface* g_sys_core = nullptr; ///< ARM11 system (OS) core
/// Run the core CPU loop
void RunLoop(int tight_loop) {
- g_app_core->Run(tight_loop);
+ // If the current thread is an idle thread, then don't execute instructions,
+ // instead advance to the next event and try to yield to the next thread
+ if (Kernel::IsIdleThread(Kernel::GetCurrentThreadHandle())) {
+ LOG_TRACE(Core_ARM11, "Idling");
+ CoreTiming::Idle();
+ CoreTiming::Advance();
+ HLE::Reschedule(__func__);
+ } else {
+ g_app_core->Run(tight_loop);
+ }
+
HW::Update();
if (HLE::g_reschedule) {
Kernel::Reschedule();
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 321648b37..833199680 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -1,16 +1,14 @@
-// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
+// Copyright (c) 2012- PPSSPP Project / Dolphin Project.
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <vector>
-#include <cstdio>
#include <atomic>
+#include <cstdio>
#include <mutex>
+#include <vector>
#include "common/chunk_file.h"
-#include "common/msg_handler.h"
-#include "common/string_util.h"
-
+#include "common/log.h"
#include "core/core.h"
#include "core/core_timing.h"
@@ -22,16 +20,15 @@ int g_clock_rate_arm11 = 268123480;
namespace CoreTiming
{
-
struct EventType
{
EventType() {}
- EventType(TimedCallback cb, const char *n)
+ EventType(TimedCallback cb, const char* n)
: callback(cb), name(n) {}
TimedCallback callback;
- const char *name;
+ const char* name;
};
std::vector<EventType> event_types;
@@ -41,262 +38,247 @@ struct BaseEvent
s64 time;
u64 userdata;
int type;
- // Event *next;
};
typedef LinkedListItem<BaseEvent> Event;
-Event *first;
-Event *tsFirst;
-Event *tsLast;
+Event* first;
+Event* ts_first;
+Event* ts_last;
// event pools
-Event *eventPool = 0;
-Event *eventTsPool = 0;
-int allocatedTsEvents = 0;
+Event* event_pool = 0;
+Event* event_ts_pool = 0;
+int allocated_ts_events = 0;
// Optimization to skip MoveEvents when possible.
-std::atomic<u32> hasTsEvents;
+std::atomic<bool> has_ts_events(false);
-// Downcount has been moved to currentMIPS, to save a couple of clocks in every ARM JIT block
-// as we can already reach that structure through a register.
-int slicelength;
+int g_slice_length;
-MEMORY_ALIGNED16(s64) globalTimer;
-s64 idledCycles;
+s64 global_timer;
+s64 idled_cycles;
+s64 last_global_time_ticks;
+s64 last_global_time_us;
-static std::recursive_mutex externalEventSection;
+static std::recursive_mutex external_event_section;
// Warning: not included in save state.
-void(*advanceCallback)(int cyclesExecuted) = nullptr;
+using AdvanceCallback = void(int cycles_executed);
+AdvanceCallback* advance_callback = nullptr;
+std::vector<MHzChangeCallback> mhz_change_callbacks;
-void SetClockFrequencyMHz(int cpuMhz)
-{
- g_clock_rate_arm11 = cpuMhz * 1000000;
+void FireMhzChange() {
+ for (auto callback : mhz_change_callbacks)
+ callback();
+}
+
+void SetClockFrequencyMHz(int cpu_mhz) {
+ // When the mhz changes, we keep track of what "time" it was before hand.
+ // This way, time always moves forward, even if mhz is changed.
+ last_global_time_us = GetGlobalTimeUs();
+ last_global_time_ticks = GetTicks();
+
+ g_clock_rate_arm11 = cpu_mhz * 1000000;
// TODO: Rescale times of scheduled events?
+
+ FireMhzChange();
}
-int GetClockFrequencyMHz()
-{
+int GetClockFrequencyMHz() {
return g_clock_rate_arm11 / 1000000;
}
+u64 GetGlobalTimeUs() {
+ s64 ticks_since_last = GetTicks() - last_global_time_ticks;
+ int freq = GetClockFrequencyMHz();
+ s64 us_since_last = ticks_since_last / freq;
+ return last_global_time_us + us_since_last;
+}
-Event* GetNewEvent()
-{
- if (!eventPool)
+Event* GetNewEvent() {
+ if (!event_pool)
return new Event;
- Event* ev = eventPool;
- eventPool = ev->next;
- return ev;
+ Event* event = event_pool;
+ event_pool = event->next;
+ return event;
}
-Event* GetNewTsEvent()
-{
- allocatedTsEvents++;
+Event* GetNewTsEvent() {
+ allocated_ts_events++;
- if (!eventTsPool)
+ if (!event_ts_pool)
return new Event;
- Event* ev = eventTsPool;
- eventTsPool = ev->next;
- return ev;
+ Event* event = event_ts_pool;
+ event_ts_pool = event->next;
+ return event;
}
-void FreeEvent(Event* ev)
-{
- ev->next = eventPool;
- eventPool = ev;
+void FreeEvent(Event* event) {
+ event->next = event_pool;
+ event_pool = event;
}
-void FreeTsEvent(Event* ev)
-{
- ev->next = eventTsPool;
- eventTsPool = ev;
- allocatedTsEvents--;
+void FreeTsEvent(Event* event) {
+ event->next = event_ts_pool;
+ event_ts_pool = event;
+ allocated_ts_events--;
}
-int RegisterEvent(const char *name, TimedCallback callback)
-{
+int RegisterEvent(const char* name, TimedCallback callback) {
event_types.push_back(EventType(callback, name));
return (int)event_types.size() - 1;
}
-void AntiCrashCallback(u64 userdata, int cyclesLate)
-{
- LOG_CRITICAL(Core, "Savestate broken: an unregistered event was called.");
+void AntiCrashCallback(u64 userdata, int cycles_late) {
+ LOG_CRITICAL(Core_Timing, "Savestate broken: an unregistered event was called.");
Core::Halt("invalid timing events");
}
-void RestoreRegisterEvent(int event_type, const char *name, TimedCallback callback)
-{
+void RestoreRegisterEvent(int event_type, const char* name, TimedCallback callback) {
if (event_type >= (int)event_types.size())
event_types.resize(event_type + 1, EventType(AntiCrashCallback, "INVALID EVENT"));
event_types[event_type] = EventType(callback, name);
}
-void UnregisterAllEvents()
-{
+void UnregisterAllEvents() {
if (first)
PanicAlert("Cannot unregister events with events pending");
event_types.clear();
}
-void Init()
-{
- //currentMIPS->downcount = INITIAL_SLICE_LENGTH;
- //slicelength = INITIAL_SLICE_LENGTH;
- globalTimer = 0;
- idledCycles = 0;
- hasTsEvents = 0;
+void Init() {
+ Core::g_app_core->down_count = INITIAL_SLICE_LENGTH;
+ g_slice_length = INITIAL_SLICE_LENGTH;
+ global_timer = 0;
+ idled_cycles = 0;
+ last_global_time_ticks = 0;
+ last_global_time_us = 0;
+ has_ts_events = 0;
+ mhz_change_callbacks.clear();
}
-void Shutdown()
-{
+void Shutdown() {
MoveEvents();
ClearPendingEvents();
UnregisterAllEvents();
- while (eventPool)
- {
- Event *ev = eventPool;
- eventPool = ev->next;
- delete ev;
+ while (event_pool) {
+ Event* event = event_pool;
+ event_pool = event->next;
+ delete event;
}
- std::lock_guard<std::recursive_mutex> lk(externalEventSection);
- while (eventTsPool)
- {
- Event *ev = eventTsPool;
- eventTsPool = ev->next;
- delete ev;
+ std::lock_guard<std::recursive_mutex> lock(external_event_section);
+ while (event_ts_pool) {
+ Event* event = event_ts_pool;
+ event_ts_pool = event->next;
+ delete event;
}
}
-u64 GetTicks()
-{
- LOG_ERROR(Core, "Unimplemented function!");
- return 0;
- //return (u64)globalTimer + slicelength - currentMIPS->downcount;
+u64 GetTicks() {
+ return (u64)global_timer + g_slice_length - Core::g_app_core->down_count;
}
-u64 GetIdleTicks()
-{
- return (u64)idledCycles;
+u64 GetIdleTicks() {
+ return (u64)idled_cycles;
}
// This is to be called when outside threads, such as the graphics thread, wants to
// schedule things to be executed on the main thread.
-void ScheduleEvent_Threadsafe(s64 cyclesIntoFuture, int event_type, u64 userdata)
-{
- std::lock_guard<std::recursive_mutex> lk(externalEventSection);
- Event *ne = GetNewTsEvent();
- ne->time = GetTicks() + cyclesIntoFuture;
- ne->type = event_type;
- ne->next = 0;
- ne->userdata = userdata;
- if (!tsFirst)
- tsFirst = ne;
- if (tsLast)
- tsLast->next = ne;
- tsLast = ne;
-
- hasTsEvents.store(1, std::memory_order_release);
+void ScheduleEvent_Threadsafe(s64 cycles_into_future, int event_type, u64 userdata) {
+ std::lock_guard<std::recursive_mutex> lock(external_event_section);
+ Event* new_event = GetNewTsEvent();
+ new_event->time = GetTicks() + cycles_into_future;
+ new_event->type = event_type;
+ new_event->next = 0;
+ new_event->userdata = userdata;
+ if (!ts_first)
+ ts_first = new_event;
+ if (ts_last)
+ ts_last->next = new_event;
+ ts_last = new_event;
+
+ has_ts_events = true;
}
// Same as ScheduleEvent_Threadsafe(0, ...) EXCEPT if we are already on the CPU thread
// in which case the event will get handled immediately, before returning.
-void ScheduleEvent_Threadsafe_Immediate(int event_type, u64 userdata)
-{
+void ScheduleEvent_Threadsafe_Immediate(int event_type, u64 userdata) {
if (false) //Core::IsCPUThread())
{
- std::lock_guard<std::recursive_mutex> lk(externalEventSection);
+ std::lock_guard<std::recursive_mutex> lock(external_event_section);
event_types[event_type].callback(userdata, 0);
}
else
ScheduleEvent_Threadsafe(0, event_type, userdata);
}
-void ClearPendingEvents()
-{
- while (first)
- {
- Event *e = first->next;
+void ClearPendingEvents() {
+ while (first) {
+ Event* event = first->next;
FreeEvent(first);
- first = e;
+ first = event;
}
}
-void AddEventToQueue(Event* ne)
-{
- Event* prev = nullptr;
- Event** pNext = &first;
- for (;;)
- {
- Event*& next = *pNext;
- if (!next || ne->time < next->time)
- {
- ne->next = next;
- next = ne;
+void AddEventToQueue(Event* new_event) {
+ Event* prev_event = nullptr;
+ Event** next_event = &first;
+ for (;;) {
+ Event*& next = *next_event;
+ if (!next || new_event->time < next->time) {
+ new_event->next = next;
+ next = new_event;
break;
}
- prev = next;
- pNext = &prev->next;
+ prev_event = next;
+ next_event = &prev_event->next;
}
}
-// This must be run ONLY from within the cpu thread
-// cyclesIntoFuture may be VERY inaccurate if called from anything else
-// than Advance
-void ScheduleEvent(s64 cyclesIntoFuture, int event_type, u64 userdata)
-{
- Event *ne = GetNewEvent();
- ne->userdata = userdata;
- ne->type = event_type;
- ne->time = GetTicks() + cyclesIntoFuture;
- AddEventToQueue(ne);
+void ScheduleEvent(s64 cycles_into_future, int event_type, u64 userdata) {
+ Event* new_event = GetNewEvent();
+ new_event->userdata = userdata;
+ new_event->type = event_type;
+ new_event->time = GetTicks() + cycles_into_future;
+ AddEventToQueue(new_event);
}
-// Returns cycles left in timer.
-s64 UnscheduleEvent(int event_type, u64 userdata)
-{
+s64 UnscheduleEvent(int event_type, u64 userdata) {
s64 result = 0;
if (!first)
return result;
- while (first)
- {
- if (first->type == event_type && first->userdata == userdata)
- {
- result = first->time - globalTimer;
+ while (first) {
+ if (first->type == event_type && first->userdata == userdata) {
+ result = first->time - GetTicks();
- Event *next = first->next;
+ Event* next = first->next;
FreeEvent(first);
first = next;
- }
- else
- {
+ } else {
break;
}
}
if (!first)
return result;
- Event *prev = first;
- Event *ptr = prev->next;
- while (ptr)
- {
- if (ptr->type == event_type && ptr->userdata == userdata)
- {
- result = ptr->time - globalTimer;
- prev->next = ptr->next;
+ Event* prev_event = first;
+ Event* ptr = prev_event->next;
+
+ while (ptr) {
+ if (ptr->type == event_type && ptr->userdata == userdata) {
+ result = ptr->time - GetTicks();
+
+ prev_event->next = ptr->next;
FreeEvent(ptr);
- ptr = prev->next;
- }
- else
- {
- prev = ptr;
+ ptr = prev_event->next;
+ } else {
+ prev_event = ptr;
ptr = ptr->next;
}
}
@@ -304,51 +286,44 @@ s64 UnscheduleEvent(int event_type, u64 userdata)
return result;
}
-s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata)
-{
+s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata) {
s64 result = 0;
- std::lock_guard<std::recursive_mutex> lk(externalEventSection);
- if (!tsFirst)
+ std::lock_guard<std::recursive_mutex> lock(external_event_section);
+ if (!ts_first)
return result;
- while (tsFirst)
- {
- if (tsFirst->type == event_type && tsFirst->userdata == userdata)
- {
- result = tsFirst->time - globalTimer;
- Event *next = tsFirst->next;
- FreeTsEvent(tsFirst);
- tsFirst = next;
- }
- else
- {
+ while (ts_first) {
+ if (ts_first->type == event_type && ts_first->userdata == userdata) {
+ result = ts_first->time - GetTicks();
+
+ Event* next = ts_first->next;
+ FreeTsEvent(ts_first);
+ ts_first = next;
+ } else {
break;
}
}
- if (!tsFirst)
+
+ if (!ts_first)
{
- tsLast = nullptr;
+ ts_last = nullptr;
return result;
}
- Event *prev = tsFirst;
- Event *ptr = prev->next;
- while (ptr)
- {
- if (ptr->type == event_type && ptr->userdata == userdata)
- {
- result = ptr->time - globalTimer;
-
- prev->next = ptr->next;
- if (ptr == tsLast)
- tsLast = prev;
- FreeTsEvent(ptr);
- ptr = prev->next;
- }
- else
- {
- prev = ptr;
- ptr = ptr->next;
+ Event* prev_event = ts_first;
+ Event* next = prev_event->next;
+ while (next) {
+ if (next->type == event_type && next->userdata == userdata) {
+ result = next->time - GetTicks();
+
+ prev_event->next = next->next;
+ if (next == ts_last)
+ ts_last = prev_event;
+ FreeTsEvent(next);
+ next = prev_event->next;
+ } else {
+ prev_event = next;
+ next = next->next;
}
}
@@ -356,271 +331,217 @@ s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata)
}
// Warning: not included in save state.
-void RegisterAdvanceCallback(void(*callback)(int cyclesExecuted))
-{
- advanceCallback = callback;
+void RegisterAdvanceCallback(AdvanceCallback* callback) {
+ advance_callback = callback;
}
-bool IsScheduled(int event_type)
-{
+void RegisterMHzChangeCallback(MHzChangeCallback callback) {
+ mhz_change_callbacks.push_back(callback);
+}
+
+bool IsScheduled(int event_type) {
if (!first)
return false;
- Event *e = first;
- while (e) {
- if (e->type == event_type)
+ Event* event = first;
+ while (event) {
+ if (event->type == event_type)
return true;
- e = e->next;
+ event = event->next;
}
return false;
}
-void RemoveEvent(int event_type)
-{
+void RemoveEvent(int event_type) {
if (!first)
return;
- while (first)
- {
- if (first->type == event_type)
- {
+ while (first) {
+ if (first->type == event_type) {
Event *next = first->next;
FreeEvent(first);
first = next;
- }
- else
- {
+ } else {
break;
}
}
if (!first)
return;
- Event *prev = first;
- Event *ptr = prev->next;
- while (ptr)
- {
- if (ptr->type == event_type)
- {
- prev->next = ptr->next;
- FreeEvent(ptr);
- ptr = prev->next;
- }
- else
- {
- prev = ptr;
- ptr = ptr->next;
+ Event* prev = first;
+ Event* next = prev->next;
+ while (next) {
+ if (next->type == event_type) {
+ prev->next = next->next;
+ FreeEvent(next);
+ next = prev->next;
+ } else {
+ prev = next;
+ next = next->next;
}
}
}
-void RemoveThreadsafeEvent(int event_type)
-{
- std::lock_guard<std::recursive_mutex> lk(externalEventSection);
- if (!tsFirst)
- {
+void RemoveThreadsafeEvent(int event_type) {
+ std::lock_guard<std::recursive_mutex> lock(external_event_section);
+ if (!ts_first)
return;
- }
- while (tsFirst)
- {
- if (tsFirst->type == event_type)
- {
- Event *next = tsFirst->next;
- FreeTsEvent(tsFirst);
- tsFirst = next;
- }
- else
- {
+
+ while (ts_first) {
+ if (ts_first->type == event_type) {
+ Event* next = ts_first->next;
+ FreeTsEvent(ts_first);
+ ts_first = next;
+ } else {
break;
}
}
- if (!tsFirst)
- {
- tsLast = nullptr;
+
+ if (!ts_first) {
+ ts_last = nullptr;
return;
}
- Event *prev = tsFirst;
- Event *ptr = prev->next;
- while (ptr)
- {
- if (ptr->type == event_type)
- {
- prev->next = ptr->next;
- if (ptr == tsLast)
- tsLast = prev;
- FreeTsEvent(ptr);
- ptr = prev->next;
- }
- else
- {
- prev = ptr;
- ptr = ptr->next;
+
+ Event* prev = ts_first;
+ Event* next = prev->next;
+ while (next) {
+ if (next->type == event_type) {
+ prev->next = next->next;
+ if (next == ts_last)
+ ts_last = prev;
+ FreeTsEvent(next);
+ next = prev->next;
+ } else {
+ prev = next;
+ next = next->next;
}
}
}
-void RemoveAllEvents(int event_type)
-{
+void RemoveAllEvents(int event_type) {
RemoveThreadsafeEvent(event_type);
RemoveEvent(event_type);
}
-//This raise only the events required while the fifo is processing data
-void ProcessFifoWaitEvents()
-{
- while (first)
- {
- if (first->time <= globalTimer)
- {
- //LOG(TIMER, "[Scheduler] %s (%lld, %lld) ",
- // first->name ? first->name : "?", (u64)globalTimer, (u64)first->time);
+// This raise only the events required while the fifo is processing data
+void ProcessFifoWaitEvents() {
+ while (first) {
+ if (first->time <= (s64)GetTicks()) {
Event* evt = first;
first = first->next;
- event_types[evt->type].callback(evt->userdata, (int)(globalTimer - evt->time));
+ event_types[evt->type].callback(evt->userdata, (int)(GetTicks() - evt->time));
FreeEvent(evt);
- }
- else
- {
+ } else {
break;
}
}
}
-void MoveEvents()
-{
- hasTsEvents.store(0, std::memory_order_release);
+void MoveEvents() {
+ has_ts_events = false;
- std::lock_guard<std::recursive_mutex> lk(externalEventSection);
+ std::lock_guard<std::recursive_mutex> lock(external_event_section);
// Move events from async queue into main queue
- while (tsFirst)
- {
- Event *next = tsFirst->next;
- AddEventToQueue(tsFirst);
- tsFirst = next;
+ while (ts_first) {
+ Event* next = ts_first->next;
+ AddEventToQueue(ts_first);
+ ts_first = next;
}
- tsLast = nullptr;
+ ts_last = nullptr;
// Move free events to threadsafe pool
- while (allocatedTsEvents > 0 && eventPool)
- {
- Event *ev = eventPool;
- eventPool = ev->next;
- ev->next = eventTsPool;
- eventTsPool = ev;
- allocatedTsEvents--;
+ while (allocated_ts_events > 0 && event_pool) {
+ Event* event = event_pool;
+ event_pool = event->next;
+ event->next = event_ts_pool;
+ event_ts_pool = event;
+ allocated_ts_events--;
}
}
-void Advance()
-{
- LOG_ERROR(Core, "Unimplemented function!");
- //int cyclesExecuted = slicelength - currentMIPS->downcount;
- //globalTimer += cyclesExecuted;
- //currentMIPS->downcount = slicelength;
-
- //if (Common::AtomicLoadAcquire(hasTsEvents))
- // MoveEvents();
- //ProcessFifoWaitEvents();
-
- //if (!first)
- //{
- // // WARN_LOG(TIMER, "WARNING - no events in queue. Setting currentMIPS->downcount to 10000");
- // currentMIPS->downcount += 10000;
- //}
- //else
- //{
- // slicelength = (int)(first->time - globalTimer);
- // if (slicelength > MAX_SLICE_LENGTH)
- // slicelength = MAX_SLICE_LENGTH;
- // currentMIPS->downcount = slicelength;
- //}
- //if (advanceCallback)
- // advanceCallback(cyclesExecuted);
-}
-
-void LogPendingEvents()
-{
- Event *ptr = first;
- while (ptr)
- {
- //INFO_LOG(TIMER, "PENDING: Now: %lld Pending: %lld Type: %d", globalTimer, ptr->time, ptr->type);
- ptr = ptr->next;
- }
+void ForceCheck() {
+ int cycles_executed = g_slice_length - Core::g_app_core->down_count;
+ global_timer += cycles_executed;
+ // This will cause us to check for new events immediately.
+ Core::g_app_core->down_count = 0;
+ // But let's not eat a bunch more time in Advance() because of this.
+ g_slice_length = 0;
}
-void Idle(int maxIdle)
-{
- LOG_ERROR(Core, "Unimplemented function!");
- //int cyclesDown = currentMIPS->downcount;
- //if (maxIdle != 0 && cyclesDown > maxIdle)
- // cyclesDown = maxIdle;
-
- //if (first && cyclesDown > 0)
- //{
- // int cyclesExecuted = slicelength - currentMIPS->downcount;
- // int cyclesNextEvent = (int) (first->time - globalTimer);
-
- // if (cyclesNextEvent < cyclesExecuted + cyclesDown)
- // {
- // cyclesDown = cyclesNextEvent - cyclesExecuted;
- // // Now, now... no time machines, please.
- // if (cyclesDown < 0)
- // cyclesDown = 0;
- // }
- //}
-
- //INFO_LOG(TIME, "Idle for %i cycles! (%f ms)", cyclesDown, cyclesDown / (float)(g_clock_rate_arm11 * 0.001f));
-
- //idledCycles += cyclesDown;
- //currentMIPS->downcount -= cyclesDown;
- //if (currentMIPS->downcount == 0)
- // currentMIPS->downcount = -1;
-}
-
-std::string GetScheduledEventsSummary()
-{
- Event *ptr = first;
- std::string text = "Scheduled events\n";
- text.reserve(1000);
- while (ptr)
- {
- unsigned int t = ptr->type;
- if (t >= event_types.size())
- PanicAlert("Invalid event type"); // %i", t);
- const char *name = event_types[ptr->type].name;
- if (!name)
- name = "[unknown]";
+void Advance() {
+ int cycles_executed = g_slice_length - Core::g_app_core->down_count;
+ global_timer += cycles_executed;
+ Core::g_app_core->down_count = g_slice_length;
- text += Common::StringFromFormat("%s : %i %08x%08x\n", name, (int)ptr->time,
- (u32)(ptr->userdata >> 32), (u32)(ptr->userdata));
+ if (has_ts_events)
+ MoveEvents();
+ ProcessFifoWaitEvents();
- ptr = ptr->next;
+ if (!first) {
+ if (g_slice_length < 10000) {
+ g_slice_length += 10000;
+ Core::g_app_core->down_count += g_slice_length;
+ }
+ } else {
+ // Note that events can eat cycles as well.
+ int target = (int)(first->time - global_timer);
+ if (target > MAX_SLICE_LENGTH)
+ target = MAX_SLICE_LENGTH;
+
+ const int diff = target - g_slice_length;
+ g_slice_length += diff;
+ Core::g_app_core->down_count += diff;
}
- return text;
+ if (advance_callback)
+ advance_callback(cycles_executed);
}
-void Event_DoState(PointerWrap &p, BaseEvent *ev)
-{
- p.Do(*ev);
+void LogPendingEvents() {
+ Event* event = first;
+ while (event) {
+ //LOG_TRACE(Core_Timing, "PENDING: Now: %lld Pending: %lld Type: %d", globalTimer, next->time, next->type);
+ event = event->next;
+ }
}
-void DoState(PointerWrap &p)
-{
- std::lock_guard<std::recursive_mutex> lk(externalEventSection);
+void Idle(int max_idle) {
+ int cycles_down = Core::g_app_core->down_count;
+ if (max_idle != 0 && cycles_down > max_idle)
+ cycles_down = max_idle;
- auto s = p.Section("CoreTiming", 1);
- if (!s)
- return;
+ if (first && cycles_down > 0) {
+ int cycles_executed = g_slice_length - Core::g_app_core->down_count;
+ int cycles_next_event = (int)(first->time - global_timer);
- int n = (int)event_types.size();
- p.Do(n);
- // These (should) be filled in later by the modules.
- event_types.resize(n, EventType(AntiCrashCallback, "INVALID EVENT"));
+ if (cycles_next_event < cycles_executed + cycles_down) {
+ cycles_down = cycles_next_event - cycles_executed;
+ // Now, now... no time machines, please.
+ if (cycles_down < 0)
+ cycles_down = 0;
+ }
+ }
- p.DoLinkedList<BaseEvent, GetNewEvent, FreeEvent, Event_DoState>(first, (Event **)nullptr);
- p.DoLinkedList<BaseEvent, GetNewTsEvent, FreeTsEvent, Event_DoState>(tsFirst, &tsLast);
+ LOG_TRACE(Core_Timing, "Idle for %i cycles! (%f ms)", cycles_down, cycles_down / (float)(g_clock_rate_arm11 * 0.001f));
- p.Do(g_clock_rate_arm11);
- p.Do(slicelength);
- p.Do(globalTimer);
- p.Do(idledCycles);
+ idled_cycles += cycles_down;
+ Core::g_app_core->down_count -= cycles_down;
+ if (Core::g_app_core->down_count == 0)
+ Core::g_app_core->down_count = -1;
+}
+
+std::string GetScheduledEventsSummary() {
+ Event* event = first;
+ std::string text = "Scheduled events\n";
+ text.reserve(1000);
+ while (event) {
+ unsigned int t = event->type;
+ if (t >= event_types.size())
+ PanicAlert("Invalid event type"); // %i", t);
+ const char* name = event_types[event->type].name;
+ if (!name)
+ name = "[unknown]";
+ text += Common::StringFromFormat("%s : %i %08x%08x\n", name, (int)event->time,
+ (u32)(event->userdata >> 32), (u32)(event->userdata));
+ event = event->next;
+ }
+ return text;
}
} // namespace
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 496234538..d62ff3604 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -1,9 +1,11 @@
-// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
+// Copyright (c) 2012- PPSSPP Project / Dolphin Project.
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
+#include <string>
+
// This is a system to schedule events into the emulated machine's future. Time is measured
// in main CPU clock cycles.
@@ -12,14 +14,14 @@
// See HW/SystemTimers.cpp for the main part of Dolphin's usage of this scheduler.
-// The int cyclesLate that the callbacks get is how many cycles late it was.
+// The int cycles_late that the callbacks get is how many cycles late it was.
// So to schedule a new event on a regular basis:
// inside callback:
-// ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever")
+// ScheduleEvent(periodInCycles - cycles_late, callback, "whatever")
-#include "common/common.h"
+#include <functional>
-class PointerWrap;
+#include "common/common.h"
extern int g_clock_rate_arm11;
@@ -55,55 +57,84 @@ inline s64 cyclesToUs(s64 cycles) {
return cycles / (g_clock_rate_arm11 / 1000000);
}
-namespace CoreTiming {
+inline u64 cyclesToMs(s64 cycles) {
+ return cycles / (g_clock_rate_arm11 / 1000);
+}
+namespace CoreTiming
+{
void Init();
void Shutdown();
-typedef void(*TimedCallback)(u64 userdata, int cyclesLate);
+typedef void(*MHzChangeCallback)();
+typedef std::function<void(u64 userdata, int cycles_late)> TimedCallback;
u64 GetTicks();
u64 GetIdleTicks();
-
-// Returns the event_type identifier.
-int RegisterEvent(const char *name, TimedCallback callback);
-// For save states.
+u64 GetGlobalTimeUs();
+
+/**
+ * Registers an event type with the specified name and callback
+ * @param name Name of the event type
+ * @param callback Function that will execute when this event fires
+ * @returns An identifier for the event type that was registered
+ */
+int RegisterEvent(const char* name, TimedCallback callback);
+/// For save states.
void RestoreRegisterEvent(int event_type, const char *name, TimedCallback callback);
void UnregisterAllEvents();
-// userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from disk,
-// when we implement state saves.
-void ScheduleEvent(s64 cyclesIntoFuture, int event_type, u64 userdata = 0);
-void ScheduleEvent_Threadsafe(s64 cyclesIntoFuture, int event_type, u64 userdata = 0);
+/// userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from disk,
+/// when we implement state saves.
+/**
+ * Schedules an event to run after the specified number of cycles,
+ * with an optional parameter to be passed to the callback handler.
+ * This must be run ONLY from within the cpu thread.
+ * @param cycles_into_future The number of cycles after which this event will be fired
+ * @param event_type The event type to fire, as returned from RegisterEvent
+ * @param userdata Optional parameter to pass to the callback when fired
+ */
+void ScheduleEvent(s64 cycles_into_future, int event_type, u64 userdata = 0);
+
+void ScheduleEvent_Threadsafe(s64 cycles_into_future, int event_type, u64 userdata = 0);
void ScheduleEvent_Threadsafe_Immediate(int event_type, u64 userdata = 0);
+
+/**
+ * Unschedules an event with the specified type and userdata
+ * @param event_type The type of event to unschedule, as returned from RegisterEvent
+ * @param userdata The userdata that identifies this event, as passed to ScheduleEvent
+ * @returns The remaining ticks until the next invocation of the event callback
+ */
s64 UnscheduleEvent(int event_type, u64 userdata);
+
s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata);
void RemoveEvent(int event_type);
void RemoveThreadsafeEvent(int event_type);
void RemoveAllEvents(int event_type);
bool IsScheduled(int event_type);
+/// Runs any pending events and updates downcount for the next slice of cycles
void Advance();
void MoveEvents();
void ProcessFifoWaitEvents();
+void ForceCheck();
-// Pretend that the main CPU has executed enough cycles to reach the next event.
+/// Pretend that the main CPU has executed enough cycles to reach the next event.
void Idle(int maxIdle = 0);
-// Clear all pending events. This should ONLY be done on exit or state load.
+/// Clear all pending events. This should ONLY be done on exit or state load.
void ClearPendingEvents();
void LogPendingEvents();
-// Warning: not included in save states.
-void RegisterAdvanceCallback(void(*callback)(int cyclesExecuted));
+/// Warning: not included in save states.
+void RegisterAdvanceCallback(void(*callback)(int cycles_executed));
+void RegisterMHzChangeCallback(MHzChangeCallback callback);
std::string GetScheduledEventsSummary();
-void DoState(PointerWrap &p);
-
-void SetClockFrequencyMHz(int cpuMhz);
+void SetClockFrequencyMHz(int cpu_mhz);
int GetClockFrequencyMHz();
-extern int slicelength;
+extern int g_slice_length;
} // namespace
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp
index 4759ef3ae..0805f42ae 100644
--- a/src/core/file_sys/archive_extsavedata.cpp
+++ b/src/core/file_sys/archive_extsavedata.cpp
@@ -9,6 +9,7 @@
#include "core/file_sys/archive_extsavedata.h"
#include "core/file_sys/disk_archive.h"
+#include "core/hle/service/fs/archive.h"
#include "core/settings.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -19,15 +20,22 @@ namespace FileSys {
static std::string GetExtSaveDataPath(const std::string& mount_point, const Path& path) {
std::vector<u8> vec_data = path.AsBinary();
const u32* data = reinterpret_cast<const u32*>(vec_data.data());
- u32 media_type = data[0];
u32 save_low = data[1];
u32 save_high = data[2];
- return Common::StringFromFormat("%s%s/%08X/%08X/", mount_point.c_str(), media_type == 0 ? "nand" : "sdmc", save_high, save_low);
+ return Common::StringFromFormat("%s%08X/%08X/", mount_point.c_str(), save_high, save_low);
}
-Archive_ExtSaveData::Archive_ExtSaveData(const std::string& mount_point)
- : DiskArchive(mount_point), concrete_mount_point(mount_point) {
- LOG_INFO(Service_FS, "Directory %s set as base for ExtSaveData.", this->mount_point.c_str());
+static std::string GetExtDataContainerPath(const std::string& mount_point, bool shared) {
+ if (shared)
+ return Common::StringFromFormat("%sdata/%s/extdata/", mount_point.c_str(), SYSTEM_ID.c_str());
+
+ return Common::StringFromFormat("%sNintendo 3DS/%s/%s/extdata/", mount_point.c_str(),
+ SYSTEM_ID.c_str(), SDCARD_ID.c_str());
+}
+
+Archive_ExtSaveData::Archive_ExtSaveData(const std::string& mount_location, bool shared)
+ : DiskArchive(GetExtDataContainerPath(mount_location, shared)) {
+ LOG_INFO(Service_FS, "Directory %s set as base for ExtSaveData.", mount_point.c_str());
}
bool Archive_ExtSaveData::Initialize() {
diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h
index a3a144799..fb7f209d2 100644
--- a/src/core/file_sys/archive_extsavedata.h
+++ b/src/core/file_sys/archive_extsavedata.h
@@ -17,7 +17,7 @@ namespace FileSys {
/// File system interface to the ExtSaveData archive
class Archive_ExtSaveData final : public DiskArchive {
public:
- Archive_ExtSaveData(const std::string& mount_point);
+ Archive_ExtSaveData(const std::string& mount_point, bool shared);
/**
* Initialize the archive.
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp
index 280d4ff5d..3baee5294 100644
--- a/src/core/file_sys/archive_savedata.cpp
+++ b/src/core/file_sys/archive_savedata.cpp
@@ -9,6 +9,7 @@
#include "core/file_sys/archive_savedata.h"
#include "core/file_sys/disk_archive.h"
+#include "core/hle/service/fs/archive.h"
#include "core/settings.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -16,14 +17,25 @@
namespace FileSys {
-Archive_SaveData::Archive_SaveData(const std::string& mount_point)
- : DiskArchive(mount_point) {
+static std::string GetSaveDataContainerPath(const std::string& sdmc_directory) {
+ return Common::StringFromFormat("%sNintendo 3DS/%s/%s/title/", sdmc_directory.c_str(),
+ SYSTEM_ID.c_str(), SDCARD_ID.c_str());
+}
+
+static std::string GetSaveDataPath(const std::string& mount_location, u64 program_id) {
+ u32 high = program_id >> 32;
+ u32 low = program_id & 0xFFFFFFFF;
+ return Common::StringFromFormat("%s%08x/%08x/data/00000001/", mount_location.c_str(), high, low);
+}
+
+Archive_SaveData::Archive_SaveData(const std::string& sdmc_directory)
+ : DiskArchive(GetSaveDataContainerPath(sdmc_directory)) {
LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str());
}
ResultCode Archive_SaveData::Open(const Path& path) {
if (concrete_mount_point.empty())
- concrete_mount_point = Common::StringFromFormat("%s%016X", mount_point.c_str(), Kernel::g_program_id) + DIR_SEP;
+ concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_program_id);
if (!FileUtil::Exists(concrete_mount_point)) {
// When a SaveData archive is created for the first time, it is not yet formatted
// and the save file/directory structure expected by the game has not yet been initialized.
diff --git a/src/core/file_sys/archive_savedatacheck.cpp b/src/core/file_sys/archive_savedatacheck.cpp
index 233158a0c..a7a507536 100644
--- a/src/core/file_sys/archive_savedatacheck.cpp
+++ b/src/core/file_sys/archive_savedatacheck.cpp
@@ -5,13 +5,24 @@
#include "common/file_util.h"
#include "core/file_sys/archive_savedatacheck.h"
+#include "core/hle/service/fs/archive.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
namespace FileSys {
-Archive_SaveDataCheck::Archive_SaveDataCheck(const std::string& mount_loc) : mount_point(mount_loc) {
+static std::string GetSaveDataCheckContainerPath(const std::string& nand_directory) {
+ return Common::StringFromFormat("%s%s/title/", nand_directory.c_str(), SYSTEM_ID.c_str());
+}
+
+static std::string GetSaveDataCheckPath(const std::string& mount_point, u32 high, u32 low) {
+ return Common::StringFromFormat("%s%08x/%08x/content/00000000.app.romfs",
+ mount_point.c_str(), high, low);
+}
+
+Archive_SaveDataCheck::Archive_SaveDataCheck(const std::string& nand_directory) :
+ mount_point(GetSaveDataCheckContainerPath(nand_directory)) {
}
ResultCode Archive_SaveDataCheck::Open(const Path& path) {
@@ -23,7 +34,7 @@ ResultCode Archive_SaveDataCheck::Open(const Path& path) {
// this archive again with a different path, will corrupt the previously open file.
auto vec = path.AsBinary();
const u32* data = reinterpret_cast<u32*>(vec.data());
- std::string file_path = Common::StringFromFormat("%s%08x%08x.bin", mount_point.c_str(), data[1], data[0]);
+ std::string file_path = GetSaveDataCheckPath(mount_point, data[1], data[0]);
FileUtil::IOFile file(file_path, "rb");
std::fill(raw_data.begin(), raw_data.end(), 0);
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp
index 1c1c170b6..26b03e82f 100644
--- a/src/core/file_sys/archive_sdmc.cpp
+++ b/src/core/file_sys/archive_sdmc.cpp
@@ -16,8 +16,8 @@
namespace FileSys {
-Archive_SDMC::Archive_SDMC(const std::string& mount_point) : DiskArchive(mount_point) {
- LOG_INFO(Service_FS, "Directory %s set as SDMC.", mount_point.c_str());
+Archive_SDMC::Archive_SDMC(const std::string& sdmc_directory) : DiskArchive(sdmc_directory) {
+ LOG_INFO(Service_FS, "Directory %s set as SDMC.", sdmc_directory.c_str());
}
bool Archive_SDMC::Initialize() {
diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp
index 0da32d510..c2a5d641a 100644
--- a/src/core/file_sys/archive_systemsavedata.cpp
+++ b/src/core/file_sys/archive_systemsavedata.cpp
@@ -9,6 +9,7 @@
#include "core/file_sys/archive_systemsavedata.h"
#include "core/file_sys/disk_archive.h"
+#include "core/hle/service/fs/archive.h"
#include "core/settings.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -22,8 +23,12 @@ static std::string GetSystemSaveDataPath(const std::string& mount_point, u64 sav
return Common::StringFromFormat("%s%08X/%08X/", mount_point.c_str(), save_low, save_high);
}
+static std::string GetSystemSaveDataContainerPath(const std::string& mount_point) {
+ return Common::StringFromFormat("%sdata/%s/sysdata/", mount_point.c_str(), SYSTEM_ID.c_str());
+}
+
Archive_SystemSaveData::Archive_SystemSaveData(const std::string& mount_point, u64 save_id)
- : DiskArchive(GetSystemSaveDataPath(mount_point, save_id)) {
+ : DiskArchive(GetSystemSaveDataPath(GetSystemSaveDataContainerPath(mount_point), save_id)) {
LOG_INFO(Service_FS, "Directory %s set as SystemSaveData.", this->mount_point.c_str());
}
diff --git a/src/core/file_sys/archive_systemsavedata.h b/src/core/file_sys/archive_systemsavedata.h
index 55d85193c..c8f5845ca 100644
--- a/src/core/file_sys/archive_systemsavedata.h
+++ b/src/core/file_sys/archive_systemsavedata.h
@@ -15,8 +15,6 @@
namespace FileSys {
/// File system interface to the SystemSaveData archive
-/// TODO(Subv): This archive should point to a location in the NAND,
-/// specifically nand:/data/<ID0>/sysdata/<SaveID-Low>/<SaveID-High>
class Archive_SystemSaveData final : public DiskArchive {
public:
Archive_SystemSaveData(const std::string& mount_point, u64 save_id);
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index e59ed1b57..ae2c11a1c 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -124,6 +124,8 @@ bool LoadExec(u32 entry_point) {
// 0x30 is the typical main thread priority I've seen used so far
g_main_thread = Kernel::SetupMainThread(0x30);
+ // Setup the idle thread
+ Kernel::SetupIdleThread();
return true;
}
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 872df2d14..58fb62e89 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -11,6 +11,7 @@
#include "common/thread_queue_list.h"
#include "core/core.h"
+#include "core/core_timing.h"
#include "core/hle/hle.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/thread.h"
@@ -34,6 +35,7 @@ public:
inline bool IsReady() const { return (status & THREADSTATUS_READY) != 0; }
inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; }
inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; }
+ inline bool IsIdle() const { return idle; }
ResultVal<bool> WaitSynchronization() override {
const bool wait = status != THREADSTATUS_DORMANT;
@@ -69,13 +71,16 @@ public:
std::vector<Handle> waiting_threads;
std::string name;
+
+ /// Whether this thread is intended to never actually be executed, i.e. always idle
+ bool idle = false;
};
// Lists all thread ids that aren't deleted/etc.
static std::vector<Handle> thread_queue;
// Lists only ready thread ids.
-static Common::ThreadQueueList<Handle> thread_ready_queue;
+static Common::ThreadQueueList<Handle, THREADPRIO_LOWEST+1> thread_ready_queue;
static Handle current_thread_handle;
static Thread* current_thread;
@@ -444,7 +449,14 @@ ResultCode SetThreadPriority(Handle handle, s32 priority) {
return RESULT_SUCCESS;
}
-/// Sets up the primary application thread
+Handle SetupIdleThread() {
+ Handle handle;
+ Thread* thread = CreateThread(handle, "idle", 0, THREADPRIO_LOWEST, THREADPROCESSORID_0, 0, 0);
+ thread->idle = true;
+ CallThread(thread);
+ return handle;
+}
+
Handle SetupMainThread(s32 priority, int stack_size) {
Handle handle;
@@ -497,6 +509,15 @@ void Reschedule() {
ResumeThreadFromWait(prev->GetHandle());
}
+bool IsIdleThread(Handle handle) {
+ Thread* thread = g_handle_table.Get<Thread>(handle);
+ if (!thread) {
+ LOG_ERROR(Kernel, "Thread not found %u", handle);
+ return false;
+ }
+ return thread->IsIdle();
+}
+
ResultCode GetThreadId(u32* thread_id, Handle handle) {
Thread* thread = g_handle_table.Get<Thread>(handle);
if (thread == nullptr)
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 0e1397cd9..dfe92d162 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -104,6 +104,17 @@ ResultVal<u32> GetThreadPriority(const Handle handle);
/// Set the priority of the thread specified by handle
ResultCode SetThreadPriority(Handle handle, s32 priority);
+/**
+ * Sets up the idle thread, this is a thread that is intended to never execute instructions,
+ * only to advance the timing. It is scheduled when there are no other ready threads in the thread queue
+ * and will try to yield on every call.
+ * @returns The handle of the idle thread
+ */
+Handle SetupIdleThread();
+
+/// Whether the current thread is an idle thread
+bool IsIdleThread(Handle thread);
+
/// Initialize threading
void ThreadingInit();
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
index 161aa8531..8812c49ef 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -161,9 +161,9 @@ ResultCode FormatConfig() {
void CFGInit() {
// TODO(Subv): In the future we should use the FS service to query this archive,
// currently it is not possible because you can only have one open archive of the same type at any time
- std::string syssavedata_directory = FileUtil::GetUserPath(D_SYSSAVEDATA_IDX);
+ std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX);
cfg_system_save_data = Common::make_unique<FileSys::Archive_SystemSaveData>(
- syssavedata_directory, CFG_SAVE_ID);
+ nand_directory, CFG_SAVE_ID);
if (!cfg_system_save_data->Initialize()) {
LOG_CRITICAL(Service_CFG, "Could not initialize SystemSaveData archive for the CFG:U service");
return;
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index f761c6ab9..958dd9344 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -36,6 +36,10 @@ namespace std {
};
}
+/// TODO(Subv): Confirm length of these strings
+const std::string SYSTEM_ID = "00000000000000000000000000000000";
+const std::string SDCARD_ID = "00000000000000000000000000000000";
+
namespace Service {
namespace FS {
@@ -432,11 +436,11 @@ ResultCode FormatSaveData() {
void ArchiveInit() {
next_handle = 1;
- // TODO(Link Mauve): Add the other archive types (see here for the known types:
- // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes). Currently the only half-finished
- // archive type is SDMC, so it is the only one getting exposed.
+ // TODO(Subv): Add the other archive types (see here for the known types:
+ // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes).
std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX);
+ std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX);
auto sdmc_archive = Common::make_unique<FileSys::Archive_SDMC>(sdmc_directory);
if (sdmc_archive->Initialize())
CreateArchive(std::move(sdmc_archive), ArchiveIdCode::SDMC);
@@ -444,28 +448,24 @@ void ArchiveInit() {
LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str());
// Create the SaveData archive
- std::string savedata_directory = FileUtil::GetUserPath(D_SAVEDATA_IDX);
- auto savedata_archive = Common::make_unique<FileSys::Archive_SaveData>(savedata_directory);
+ auto savedata_archive = Common::make_unique<FileSys::Archive_SaveData>(sdmc_directory);
CreateArchive(std::move(savedata_archive), ArchiveIdCode::SaveData);
- std::string extsavedata_directory = FileUtil::GetUserPath(D_EXTSAVEDATA);
- auto extsavedata_archive = Common::make_unique<FileSys::Archive_ExtSaveData>(extsavedata_directory);
+ auto extsavedata_archive = Common::make_unique<FileSys::Archive_ExtSaveData>(sdmc_directory, false);
if (extsavedata_archive->Initialize())
CreateArchive(std::move(extsavedata_archive), ArchiveIdCode::ExtSaveData);
else
- LOG_ERROR(Service_FS, "Can't instantiate ExtSaveData archive with path %s", extsavedata_directory.c_str());
+ LOG_ERROR(Service_FS, "Can't instantiate ExtSaveData archive with path %s", extsavedata_archive->GetMountPoint().c_str());
- std::string sharedextsavedata_directory = FileUtil::GetUserPath(D_EXTSAVEDATA);
- auto sharedextsavedata_archive = Common::make_unique<FileSys::Archive_ExtSaveData>(sharedextsavedata_directory);
+ auto sharedextsavedata_archive = Common::make_unique<FileSys::Archive_ExtSaveData>(nand_directory, true);
if (sharedextsavedata_archive->Initialize())
CreateArchive(std::move(sharedextsavedata_archive), ArchiveIdCode::SharedExtSaveData);
else
LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s",
- sharedextsavedata_directory.c_str());
+ sharedextsavedata_archive->GetMountPoint().c_str());
// Create the SaveDataCheck archive, basically a small variation of the RomFS archive
- std::string savedatacheck_directory = FileUtil::GetUserPath(D_SAVEDATACHECK_IDX);
- auto savedatacheck_archive = Common::make_unique<FileSys::Archive_SaveDataCheck>(savedatacheck_directory);
+ auto savedatacheck_archive = Common::make_unique<FileSys::Archive_SaveDataCheck>(nand_directory);
CreateArchive(std::move(savedatacheck_archive), ArchiveIdCode::SaveDataCheck);
}
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index 9e9efa019..b3f2134f2 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -10,6 +10,11 @@
#include "core/hle/kernel/kernel.h"
#include "core/hle/result.h"
+/// The unique system identifier hash, also known as ID0
+extern const std::string SYSTEM_ID;
+/// The scrambled SD card CID, also known as ID1
+extern const std::string SDCARD_ID;
+
namespace Service {
namespace FS {
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 0127d4ee5..26a43217e 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -291,8 +291,11 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
// Update framebuffer information if requested
for (int screen_id = 0; screen_id < 2; ++screen_id) {
FrameBufferUpdate* info = GetFrameBufferInfo(thread_id, screen_id);
- if (info->is_dirty)
+
+ if (info->is_dirty) {
SetBufferSwap(screen_id, info->framebuffer_info[info->index]);
+ info->framebuffer_info->active_fb = info->framebuffer_info->active_fb ^ 1;
+ }
info->is_dirty = false;
}
diff --git a/src/core/hle/service/ptm_u.cpp b/src/core/hle/service/ptm_u.cpp
index 9cc700c46..fd79cd8ab 100644
--- a/src/core/hle/service/ptm_u.cpp
+++ b/src/core/hle/service/ptm_u.cpp
@@ -142,10 +142,10 @@ Interface::Interface() {
Register(FunctionTable, ARRAY_SIZE(FunctionTable));
// Create the SharedExtSaveData archive 0xF000000B and the gamecoin.dat file
// TODO(Subv): In the future we should use the FS service to query this archive
- std::string extsavedata_directory = FileUtil::GetUserPath(D_EXTSAVEDATA);
- ptm_shared_extsavedata = Common::make_unique<FileSys::Archive_ExtSaveData>(extsavedata_directory);
+ std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX);
+ ptm_shared_extsavedata = Common::make_unique<FileSys::Archive_ExtSaveData>(nand_directory, true);
if (!ptm_shared_extsavedata->Initialize()) {
- LOG_CRITICAL(Service_PTM, "Could not initialize ExtSaveData archive for the PTM:U service");
+ LOG_CRITICAL(Service_PTM, "Could not initialize SharedExtSaveData archive for the PTM:U service");
return;
}
FileSys::Path archive_path(ptm_shared_extdata_id);
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index c5233e687..0c5597283 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -46,36 +46,22 @@ Manager* g_manager = nullptr; ///< Service manager
////////////////////////////////////////////////////////////////////////////////////////////////////
// Service Manager class
-Manager::Manager() {
-}
-
-Manager::~Manager() {
- for(Interface* service : m_services) {
- DeleteService(service->GetPortName());
- }
-}
-
-/// Add a service to the manager (does not create it though)
void Manager::AddService(Interface* service) {
// TOOD(yuriks): Fix error reporting
m_port_map[service->GetPortName()] = Kernel::g_handle_table.Create(service).ValueOr(INVALID_HANDLE);
m_services.push_back(service);
}
-/// Removes a service from the manager, also frees memory
void Manager::DeleteService(const std::string& port_name) {
Interface* service = FetchFromPortName(port_name);
m_services.erase(std::remove(m_services.begin(), m_services.end(), service), m_services.end());
m_port_map.erase(port_name);
- delete service;
}
-/// Get a Service Interface from its Handle
Interface* Manager::FetchFromHandle(Handle handle) {
return Kernel::g_handle_table.Get<Interface>(handle);
}
-/// Get a Service Interface from its port
Interface* Manager::FetchFromPortName(const std::string& port_name) {
auto itr = m_port_map.find(port_name);
if (itr == m_port_map.end()) {
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 28b4ccd17..41ba1e554 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -114,29 +114,22 @@ private:
/// Simple class to manage accessing services from ports and UID handles
class Manager {
-
public:
- Manager();
-
- ~Manager();
-
- /// Add a service to the manager (does not create it though)
+ /// Add a service to the manager
void AddService(Interface* service);
- /// Removes a service from the manager (does not delete it though)
+ /// Removes a service from the manager
void DeleteService(const std::string& port_name);
- /// Get a Service Interface from its UID
- Interface* FetchFromHandle(u32 uid);
+ /// Get a Service Interface from its Handle
+ Interface* FetchFromHandle(Handle handle);
/// Get a Service Interface from its port
Interface* FetchFromPortName(const std::string& port_name);
private:
-
std::vector<Interface*> m_services;
std::map<std::string, u32> m_port_map;
-
};
/// Initialize ServiceManager