mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-06-03 12:27:21 +12:00
Merge branch 'master' into specialized-shaderz
This commit is contained in:
commit
9dc12e0681
77 changed files with 2403 additions and 305 deletions
|
@ -1,6 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "helpers.hpp"
|
||||
#include "kernel/kernel_types.hpp"
|
||||
#include "memory.hpp"
|
||||
#include "result/result.hpp"
|
||||
|
||||
|
@ -65,10 +68,11 @@ namespace Applets {
|
|||
};
|
||||
|
||||
struct Parameter {
|
||||
u32 senderID;
|
||||
u32 destID;
|
||||
u32 signal;
|
||||
std::vector<u8> data;
|
||||
u32 senderID; // ID of the parameter sender
|
||||
u32 destID; // ID of the app to receive parameter
|
||||
u32 signal; // Signal type (eg request)
|
||||
u32 object; // Some applets will also respond with shared memory handles for transferring data between the sender and called
|
||||
std::vector<u8> data; // Misc data
|
||||
};
|
||||
|
||||
class AppletBase {
|
||||
|
@ -80,7 +84,7 @@ namespace Applets {
|
|||
virtual const char* name() = 0;
|
||||
|
||||
// Called by APT::StartLibraryApplet and similar
|
||||
virtual Result::HorizonResult start() = 0;
|
||||
virtual Result::HorizonResult start(const MemoryBlock* sharedMem, const std::vector<u8>& parameters, u32 appID) = 0;
|
||||
// Transfer parameters from application -> applet
|
||||
virtual Result::HorizonResult receiveParameter(const Parameter& parameter) = 0;
|
||||
virtual void reset() = 0;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include <optional>
|
||||
|
||||
#include "applets/error_applet.hpp"
|
||||
#include "applets/mii_selector.hpp"
|
||||
#include "applets/software_keyboard.hpp"
|
||||
#include "helpers.hpp"
|
||||
|
@ -11,6 +12,7 @@ namespace Applets {
|
|||
class AppletManager {
|
||||
MiiSelectorApplet miiSelector;
|
||||
SoftwareKeyboardApplet swkbd;
|
||||
ErrorApplet error;
|
||||
std::optional<Applets::Parameter> nextParameter = std::nullopt;
|
||||
|
||||
public:
|
||||
|
|
15
include/applets/error_applet.hpp
Normal file
15
include/applets/error_applet.hpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include <string>
|
||||
|
||||
#include "applets/applet.hpp"
|
||||
|
||||
namespace Applets {
|
||||
class ErrorApplet final : public AppletBase {
|
||||
public:
|
||||
virtual const char* name() override { return "Error/EULA Agreement"; }
|
||||
virtual Result::HorizonResult start(const MemoryBlock* sharedMem, const std::vector<u8>& parameters, u32 appID) override;
|
||||
virtual Result::HorizonResult receiveParameter(const Applets::Parameter& parameter) override;
|
||||
virtual void reset() override;
|
||||
|
||||
ErrorApplet(Memory& memory, std::optional<Parameter>& nextParam) : AppletBase(memory, nextParam) {}
|
||||
};
|
||||
} // namespace Applets
|
|
@ -1,13 +1,83 @@
|
|||
#include <string>
|
||||
|
||||
#include "applets/applet.hpp"
|
||||
#include "swap.hpp"
|
||||
|
||||
namespace Applets {
|
||||
struct MiiConfig {
|
||||
u8 enableCancelButton;
|
||||
u8 enableGuestMii;
|
||||
u8 showOnTopScreen;
|
||||
std::array<u8, 0x5> pad1;
|
||||
std::array<u16_le, 0x40> title;
|
||||
std::array<u8, 0x4> pad2;
|
||||
u8 showGuestMiis;
|
||||
std::array<u8, 0x3> pad3;
|
||||
u32 initiallySelectedIndex;
|
||||
std::array<u8, 0x6> guestMiiWhitelist;
|
||||
std::array<u8, 0x64> userMiiWhitelist;
|
||||
std::array<u8, 0x2> pad4;
|
||||
u32 magicValue;
|
||||
};
|
||||
static_assert(sizeof(MiiConfig) == 0x104, "Mii config size is wrong");
|
||||
|
||||
// Some members of this struct are not properly aligned so we need pragma pack
|
||||
#pragma pack(push, 1)
|
||||
struct MiiData {
|
||||
u8 version;
|
||||
u8 miiOptions;
|
||||
u8 miiPos;
|
||||
u8 consoleID;
|
||||
|
||||
u64_be systemID;
|
||||
u32_be miiID;
|
||||
std::array<u8, 0x6> creatorMAC;
|
||||
u16 padding;
|
||||
|
||||
u16_be miiDetails;
|
||||
std::array<char16_t, 0xA> miiName;
|
||||
u8 height;
|
||||
u8 width;
|
||||
|
||||
u8 faceStyle;
|
||||
u8 faceDetails;
|
||||
u8 hairStyle;
|
||||
u8 hairDetails;
|
||||
u32_be eyeDetails;
|
||||
u32_be eyebrowDetails;
|
||||
u16_be noseDetails;
|
||||
u16_be mouthDetails;
|
||||
u16_be moustacheDetails;
|
||||
u16_be beardDetails;
|
||||
u16_be glassesDetails;
|
||||
u16_be moleDetails;
|
||||
|
||||
std::array<char16_t, 0xA> authorName;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
static_assert(sizeof(MiiData) == 0x5C, "MiiData structure has incorrect size");
|
||||
|
||||
struct MiiResult {
|
||||
u32_be returnCode;
|
||||
u32_be isGuestMiiSelected;
|
||||
u32_be selectedGuestMiiIndex;
|
||||
MiiData selectedMiiData;
|
||||
u16_be unknown1;
|
||||
u16_be miiChecksum;
|
||||
std::array<u16_le, 0xC> guestMiiName;
|
||||
};
|
||||
static_assert(sizeof(MiiResult) == 0x84, "MiiResult structure has incorrect size");
|
||||
|
||||
class MiiSelectorApplet final : public AppletBase {
|
||||
public:
|
||||
virtual const char* name() override { return "Mii Selector"; }
|
||||
virtual Result::HorizonResult start() override;
|
||||
virtual Result::HorizonResult start(const MemoryBlock* sharedMem, const std::vector<u8>& parameters, u32 appID) override;
|
||||
virtual Result::HorizonResult receiveParameter(const Applets::Parameter& parameter) override;
|
||||
virtual void reset() override;
|
||||
|
||||
MiiResult output;
|
||||
MiiConfig config;
|
||||
MiiResult getDefaultMii();
|
||||
MiiSelectorApplet(Memory& memory, std::optional<Parameter>& nextParam) : AppletBase(memory, nextParam) {}
|
||||
};
|
||||
} // namespace Applets
|
|
@ -1,13 +1,162 @@
|
|||
#include <array>
|
||||
|
||||
#include "applets/applet.hpp"
|
||||
#include "swap.hpp"
|
||||
|
||||
namespace Applets {
|
||||
// Software keyboard definitions adapted from libctru/Citra
|
||||
// Keyboard input filtering flags. Allows the caller to specify what input is explicitly not allowed
|
||||
namespace SoftwareKeyboardFilter {
|
||||
enum Filter : u32 {
|
||||
Digits = 1, // Disallow the use of more than a certain number of digits (0 or more)
|
||||
At = 1 << 1, // Disallow the use of the @ sign.
|
||||
Percent = 1 << 2, // Disallow the use of the % sign.
|
||||
Backslash = 1 << 3, // Disallow the use of the \ sign.
|
||||
Profanity = 1 << 4, // Disallow profanity using Nintendo's profanity filter.
|
||||
Callback = 1 << 5, // Use a callback in order to check the input.
|
||||
};
|
||||
} // namespace SoftwareKeyboardFilter
|
||||
|
||||
// Keyboard features.
|
||||
namespace SoftwareKeyboardFeature {
|
||||
enum Feature {
|
||||
Parental = 1, // Parental PIN mode.
|
||||
DarkenTopScreen = 1 << 1, // Darken the top screen when the keyboard is shown.
|
||||
PredictiveInput = 1 << 2, // Enable predictive input (necessary for Kanji input in JPN systems).
|
||||
Multiline = 1 << 3, // Enable multiline input.
|
||||
FixedWidth = 1 << 4, // Enable fixed-width mode.
|
||||
AllowHome = 1 << 5, // Allow the usage of the HOME button.
|
||||
AllowReset = 1 << 6, // Allow the usage of a software-reset combination.
|
||||
AllowPower = 1 << 7, // Allow the usage of the POWER button.
|
||||
DefaultQWERTY = 1 << 9, // Default to the QWERTY page when the keyboard is shown.
|
||||
};
|
||||
} // namespace SoftwareKeyboardFeature
|
||||
|
||||
class SoftwareKeyboardApplet final : public AppletBase {
|
||||
public:
|
||||
static constexpr int MAX_BUTTON = 3; // Maximum number of buttons that can be in the keyboard.
|
||||
static constexpr int MAX_BUTTON_TEXT_LEN = 16; // Maximum button text length, in UTF-16 code units.
|
||||
static constexpr int MAX_HINT_TEXT_LEN = 64; // Maximum hint text length, in UTF-16 code units.
|
||||
static constexpr int MAX_CALLBACK_MSG_LEN = 256; // Maximum filter callback error message length, in UTF-16 code units.
|
||||
|
||||
// Keyboard types
|
||||
enum class SoftwareKeyboardType : u32 {
|
||||
Normal, // Normal keyboard with several pages (QWERTY/accents/symbol/mobile)
|
||||
QWERTY, // QWERTY keyboard only.
|
||||
NumPad, // Number pad.
|
||||
Western, // On JPN systems, a text keyboard without Japanese input capabilities, otherwise same as SWKBD_TYPE_NORMAL.
|
||||
};
|
||||
|
||||
// Keyboard dialog buttons.
|
||||
enum class SoftwareKeyboardButtonConfig : u32 {
|
||||
SingleButton, // Ok button
|
||||
DualButton, // Cancel | Ok buttons
|
||||
TripleButton, // Cancel | I Forgot | Ok buttons
|
||||
NoButton, // No button (returned by swkbdInputText in special cases)
|
||||
};
|
||||
|
||||
// Accepted input types.
|
||||
enum class SoftwareKeyboardValidInput : u32 {
|
||||
Anything, // All inputs are accepted.
|
||||
NotEmpty, // Empty inputs are not accepted.
|
||||
NotEmptyNotBlank, // Empty or blank inputs (consisting solely of whitespace) are not accepted.
|
||||
NotBlank, // Blank inputs (consisting solely of whitespace) are not accepted, but empty inputs are.
|
||||
FixedLen, // The input must have a fixed length (specified by maxTextLength in swkbdInit)
|
||||
};
|
||||
|
||||
// Keyboard password modes.
|
||||
enum class SoftwareKeyboardPasswordMode : u32 {
|
||||
None, // Characters are not concealed.
|
||||
Hide, // Characters are concealed immediately.
|
||||
HideDelay, // Characters are concealed a second after they've been typed.
|
||||
};
|
||||
|
||||
// Keyboard filter callback return values.
|
||||
enum class SoftwareKeyboardCallbackResult : u32 {
|
||||
OK, // Specifies that the input is valid.
|
||||
Close, // Displays an error message, then closes the keyboard.
|
||||
Continue, // Displays an error message and continues displaying the keyboard.
|
||||
};
|
||||
|
||||
// Keyboard return values.
|
||||
enum class SoftwareKeyboardResult : s32 {
|
||||
None = -1, // Dummy/unused.
|
||||
InvalidInput = -2, // Invalid parameters to swkbd.
|
||||
OutOfMem = -3, // Out of memory.
|
||||
|
||||
D0Click = 0, // The button was clicked in 1-button dialogs.
|
||||
D1Click0, // The left button was clicked in 2-button dialogs.
|
||||
D1Click1, // The right button was clicked in 2-button dialogs.
|
||||
D2Click0, // The left button was clicked in 3-button dialogs.
|
||||
D2Click1, // The middle button was clicked in 3-button dialogs.
|
||||
D2Click2, // The right button was clicked in 3-button dialogs.
|
||||
|
||||
HomePressed = 10, // The HOME button was pressed.
|
||||
ResetPressed, // The soft-reset key combination was pressed.
|
||||
PowerPressed, // The POWER button was pressed.
|
||||
|
||||
ParentalOK = 20, // The parental PIN was verified successfully.
|
||||
ParentalFail, // The parental PIN was incorrect.
|
||||
|
||||
BannedInput = 30, // The filter callback returned SoftwareKeyboardCallback::CLOSE.
|
||||
};
|
||||
|
||||
struct SoftwareKeyboardConfig {
|
||||
enum_le<SoftwareKeyboardType> type;
|
||||
enum_le<SoftwareKeyboardButtonConfig> numButtonsM1;
|
||||
enum_le<SoftwareKeyboardValidInput> validInput;
|
||||
enum_le<SoftwareKeyboardPasswordMode> passwordMode;
|
||||
s32_le isParentalScreen;
|
||||
s32_le darkenTopScreen;
|
||||
u32_le filterFlags;
|
||||
u32_le saveStateFlags;
|
||||
u16_le maxTextLength;
|
||||
u16_le dictWordCount;
|
||||
u16_le maxDigits;
|
||||
std::array<std::array<u16_le, MAX_BUTTON_TEXT_LEN + 1>, MAX_BUTTON> buttonText;
|
||||
std::array<u16_le, 2> numpadKeys;
|
||||
std::array<u16_le, MAX_HINT_TEXT_LEN + 1> hintText; // Text to display when asking the user for input
|
||||
bool predictiveInput;
|
||||
bool multiline;
|
||||
bool fixedWidth;
|
||||
bool allowHome;
|
||||
bool allowReset;
|
||||
bool allowPower;
|
||||
bool unknown;
|
||||
bool defaultQwerty;
|
||||
std::array<bool, 4> buttonSubmitsText;
|
||||
u16_le language;
|
||||
|
||||
u32_le initialTextOffset; // Offset of the default text in the output SharedMemory
|
||||
u32_le dictOffset;
|
||||
u32_le initialStatusOffset;
|
||||
u32_le initialLearningOffset;
|
||||
u32_le sharedMemorySize; // Size of the SharedMemory
|
||||
u32_le version;
|
||||
|
||||
enum_le<SoftwareKeyboardResult> returnCode;
|
||||
|
||||
u32_le statusOffset;
|
||||
u32_le learningOffset;
|
||||
|
||||
u32_le textOffset; // Offset in the SharedMemory where the output text starts
|
||||
u16_le textLength; // Length in characters of the output text
|
||||
|
||||
enum_le<SoftwareKeyboardCallbackResult> callbackResult;
|
||||
std::array<u16_le, MAX_CALLBACK_MSG_LEN + 1> callbackMessage;
|
||||
bool skipAtCheck;
|
||||
std::array<u8, 0xAB> pad;
|
||||
};
|
||||
static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software keyboard config size is wrong");
|
||||
|
||||
virtual const char* name() override { return "Software Keyboard"; }
|
||||
virtual Result::HorizonResult start() override;
|
||||
virtual Result::HorizonResult start(const MemoryBlock* sharedMem, const std::vector<u8>& parameters, u32 appID) override;
|
||||
virtual Result::HorizonResult receiveParameter(const Applets::Parameter& parameter) override;
|
||||
virtual void reset() override;
|
||||
|
||||
SoftwareKeyboardApplet(Memory& memory, std::optional<Parameter>& nextParam) : AppletBase(memory, nextParam) {}
|
||||
void closeKeyboard(u32 appID);
|
||||
|
||||
SoftwareKeyboardConfig config;
|
||||
};
|
||||
} // namespace Applets
|
|
@ -24,6 +24,7 @@ class Cheats {
|
|||
|
||||
Cheats(Memory& mem, HIDService& hid);
|
||||
u32 addCheat(const Cheat& cheat);
|
||||
u32 addCheat(const u8* data, size_t size);
|
||||
void removeCheat(u32 id);
|
||||
void enableCheat(u32 id);
|
||||
void disableCheat(u32 id);
|
||||
|
@ -32,6 +33,7 @@ class Cheats {
|
|||
|
||||
void clear();
|
||||
bool haveCheats() const { return cheatsLoaded; }
|
||||
static constexpr u32 badCheatHandle = 0xFFFFFFFF;
|
||||
|
||||
private:
|
||||
ActionReplay ar; // An ActionReplay cheat machine for executing CTRPF codes
|
||||
|
|
|
@ -9,15 +9,18 @@
|
|||
#include "helpers.hpp"
|
||||
#include "kernel.hpp"
|
||||
#include "memory.hpp"
|
||||
#include "scheduler.hpp"
|
||||
|
||||
class Emulator;
|
||||
class CPU;
|
||||
|
||||
class MyEnvironment final : public Dynarmic::A32::UserCallbacks {
|
||||
public:
|
||||
u64 ticksLeft = 0;
|
||||
u64 totalTicks = 0;
|
||||
Memory& mem;
|
||||
Kernel& kernel;
|
||||
public:
|
||||
u64 ticksLeft = 0;
|
||||
u64 totalTicks = 0;
|
||||
Memory& mem;
|
||||
Kernel& kernel;
|
||||
Scheduler& scheduler;
|
||||
|
||||
u64 getCyclesForInstruction(bool isThumb, u32 instruction);
|
||||
|
||||
|
@ -76,54 +79,56 @@ public:
|
|||
std::terminate();
|
||||
}
|
||||
|
||||
void CallSVC(u32 swi) override {
|
||||
kernel.serviceSVC(swi);
|
||||
}
|
||||
void CallSVC(u32 swi) override {
|
||||
kernel.serviceSVC(swi);
|
||||
}
|
||||
|
||||
void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override {
|
||||
switch (exception) {
|
||||
case Dynarmic::A32::Exception::UnpredictableInstruction:
|
||||
Helpers::panic("Unpredictable instruction at pc = %08X", pc);
|
||||
break;
|
||||
void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override {
|
||||
switch (exception) {
|
||||
case Dynarmic::A32::Exception::UnpredictableInstruction:
|
||||
Helpers::panic("Unpredictable instruction at pc = %08X", pc);
|
||||
break;
|
||||
|
||||
default: Helpers::panic("Fired exception oops");
|
||||
}
|
||||
}
|
||||
default: Helpers::panic("Fired exception oops");
|
||||
}
|
||||
}
|
||||
|
||||
void AddTicks(u64 ticks) override {
|
||||
totalTicks += ticks;
|
||||
void AddTicks(u64 ticks) override {
|
||||
scheduler.currentTimestamp += ticks;
|
||||
|
||||
if (ticks > ticksLeft) {
|
||||
ticksLeft = 0;
|
||||
return;
|
||||
}
|
||||
ticksLeft -= ticks;
|
||||
}
|
||||
if (ticks > ticksLeft) {
|
||||
ticksLeft = 0;
|
||||
return;
|
||||
}
|
||||
ticksLeft -= ticks;
|
||||
}
|
||||
|
||||
u64 GetTicksRemaining() override {
|
||||
return ticksLeft;
|
||||
}
|
||||
u64 GetTicksRemaining() override {
|
||||
return ticksLeft;
|
||||
}
|
||||
|
||||
u64 GetTicksForCode(bool isThumb, u32 vaddr, u32 instruction) override {
|
||||
return getCyclesForInstruction(isThumb, instruction);
|
||||
}
|
||||
u64 GetTicksForCode(bool isThumb, u32 vaddr, u32 instruction) override {
|
||||
return getCyclesForInstruction(isThumb, instruction);
|
||||
}
|
||||
|
||||
MyEnvironment(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
||||
MyEnvironment(Memory& mem, Kernel& kernel, Scheduler& scheduler) : mem(mem), kernel(kernel), scheduler(scheduler) {}
|
||||
};
|
||||
|
||||
class CPU {
|
||||
std::unique_ptr<Dynarmic::A32::Jit> jit;
|
||||
std::shared_ptr<CP15> cp15;
|
||||
std::unique_ptr<Dynarmic::A32::Jit> jit;
|
||||
std::shared_ptr<CP15> cp15;
|
||||
|
||||
// Make exclusive monitor with only 1 CPU core
|
||||
Dynarmic::ExclusiveMonitor exclusiveMonitor{1};
|
||||
MyEnvironment env;
|
||||
Memory& mem;
|
||||
// Make exclusive monitor with only 1 CPU core
|
||||
Dynarmic::ExclusiveMonitor exclusiveMonitor{1};
|
||||
MyEnvironment env;
|
||||
Memory& mem;
|
||||
Scheduler& scheduler;
|
||||
Emulator& emu;
|
||||
|
||||
public:
|
||||
static constexpr u64 ticksPerSec = 268111856;
|
||||
public:
|
||||
static constexpr u64 ticksPerSec = Scheduler::arm11Clock;
|
||||
|
||||
CPU(Memory& mem, Kernel& kernel);
|
||||
CPU(Memory& mem, Kernel& kernel, Emulator& emu);
|
||||
void reset();
|
||||
|
||||
void setReg(int index, u32 value) {
|
||||
|
@ -162,29 +167,20 @@ public:
|
|||
}
|
||||
|
||||
u64 getTicks() {
|
||||
return env.totalTicks;
|
||||
return scheduler.currentTimestamp;
|
||||
}
|
||||
|
||||
// Get reference to tick count. Memory needs access to this
|
||||
u64& getTicksRef() {
|
||||
return env.totalTicks;
|
||||
return scheduler.currentTimestamp;
|
||||
}
|
||||
|
||||
void clearCache() { jit->ClearCache(); }
|
||||
|
||||
void runFrame() {
|
||||
env.ticksLeft = ticksPerSec / 60;
|
||||
execute:
|
||||
const auto exitReason = jit->Run();
|
||||
|
||||
if (static_cast<u32>(exitReason) != 0) [[unlikely]] {
|
||||
// Cache invalidation needs to exit the JIT so it returns a CacheInvalidation HaltReason. In our case, we just go back to executing
|
||||
// The goto might be terrible but it does guarantee that this does not recursively call run and crash, instead getting optimized to a jump
|
||||
if (Dynarmic::Has(exitReason, Dynarmic::HaltReason::CacheInvalidation)) {
|
||||
goto execute;
|
||||
} else {
|
||||
Helpers::panic("Exit reason: %d\nPC: %08X", static_cast<u32>(exitReason), getReg(15));
|
||||
}
|
||||
}
|
||||
Scheduler& getScheduler() {
|
||||
return scheduler;
|
||||
}
|
||||
|
||||
void addTicks(u64 ticks) { env.AddTicks(ticks); }
|
||||
|
||||
void clearCache() { jit->ClearCache(); }
|
||||
void runFrame();
|
||||
};
|
|
@ -15,6 +15,7 @@
|
|||
#include "io_file.hpp"
|
||||
#include "lua_manager.hpp"
|
||||
#include "memory.hpp"
|
||||
#include "scheduler.hpp"
|
||||
|
||||
#ifdef PANDA3DS_ENABLE_HTTP_SERVER
|
||||
#include "http_server.hpp"
|
||||
|
@ -42,6 +43,7 @@ class Emulator {
|
|||
Kernel kernel;
|
||||
Crypto::AESEngine aesEngine;
|
||||
Cheats cheats;
|
||||
Scheduler scheduler;
|
||||
|
||||
// Variables to keep track of whether the user is controlling the 3DS analog stick with their keyboard
|
||||
// This is done so when a gamepad is connected, we won't automatically override the 3DS analog stick settings with the gamepad's state
|
||||
|
@ -85,6 +87,8 @@ class Emulator {
|
|||
// change ROMs. If Reload is selected, the emulator will reload its selected ROM. This is useful for eg a "reset" button that keeps the current
|
||||
// ROM and just resets the emu
|
||||
enum class ReloadOption { NoReload, Reload };
|
||||
// Used in CPU::runFrame
|
||||
bool frameDone = false;
|
||||
|
||||
Emulator();
|
||||
~Emulator();
|
||||
|
@ -94,6 +98,8 @@ class Emulator {
|
|||
void reset(ReloadOption reload);
|
||||
void run(void* frontend = nullptr);
|
||||
void runFrame();
|
||||
// Poll the scheduler for events
|
||||
void pollScheduler();
|
||||
|
||||
void resume(); // Resume the emulator
|
||||
void pause(); // Pause the emulator
|
||||
|
@ -121,6 +127,7 @@ class Emulator {
|
|||
Cheats& getCheats() { return cheats; }
|
||||
ServiceManager& getServiceManager() { return kernel.getServiceManager(); }
|
||||
LuaManager& getLua() { return lua; }
|
||||
Scheduler& getScheduler() { return scheduler; }
|
||||
|
||||
RendererType getRendererType() const { return config.rendererType; }
|
||||
Renderer* getRenderer() { return gpu.getRenderer(); }
|
||||
|
@ -128,6 +135,8 @@ class Emulator {
|
|||
|
||||
std::filesystem::path getConfigPath();
|
||||
std::filesystem::path getAndroidAppPath();
|
||||
// Get the root path for the emulator's app data
|
||||
std::filesystem::path getAppDataRoot();
|
||||
|
||||
std::span<u8> getSMDH();
|
||||
};
|
||||
|
|
|
@ -5,8 +5,10 @@
|
|||
using Result::HorizonResult;
|
||||
|
||||
class SDMCArchive : public ArchiveBase {
|
||||
public:
|
||||
SDMCArchive(Memory& mem) : ArchiveBase(mem) {}
|
||||
bool isWriteOnly = false; // There's 2 variants of the SDMC archive: Regular one (Read/Write) and write-only
|
||||
|
||||
public:
|
||||
SDMCArchive(Memory& mem, bool writeOnly = false) : ArchiveBase(mem), isWriteOnly(writeOnly) {}
|
||||
|
||||
u64 getFreeBytes() override { return 1_GB; }
|
||||
std::string name() override { return "SDMC"; }
|
||||
|
|
|
@ -53,6 +53,7 @@ namespace KernelHandles {
|
|||
GSPSharedMemHandle = MaxServiceHandle + 1, // Handle for the GSP shared memory
|
||||
FontSharedMemHandle,
|
||||
CSNDSharedMemHandle,
|
||||
APTCaptureSharedMemHandle, // Shared memory for display capture info,
|
||||
HIDSharedMemHandle,
|
||||
|
||||
MinSharedMemHandle = GSPSharedMemHandle,
|
||||
|
|
|
@ -70,6 +70,7 @@ public:
|
|||
Handle makeMutex(bool locked = false); // Needs to be public to be accessible to the APT/DSP services
|
||||
Handle makeSemaphore(u32 initialCount, u32 maximumCount); // Needs to be public to be accessible to the service manager port
|
||||
Handle makeTimer(ResetType resetType);
|
||||
void pollTimers();
|
||||
|
||||
// Signals an event, returns true on success or false if the event does not exist
|
||||
bool signalEvent(Handle e);
|
||||
|
@ -94,7 +95,7 @@ public:
|
|||
void releaseMutex(Mutex* moo);
|
||||
void cancelTimer(Timer* timer);
|
||||
void signalTimer(Handle timerHandle, Timer* timer);
|
||||
void updateTimer(Handle timerHandle, Timer* timer);
|
||||
u64 getWakeupTick(s64 ns);
|
||||
|
||||
// Wake up the thread with the highest priority out of all threads in the waitlist
|
||||
// Returns the index of the woken up thread
|
||||
|
@ -137,6 +138,7 @@ public:
|
|||
void duplicateHandle();
|
||||
void exitThread();
|
||||
void mapMemoryBlock();
|
||||
void unmapMemoryBlock();
|
||||
void queryMemory();
|
||||
void getCurrentProcessorNumber();
|
||||
void getProcessID();
|
||||
|
|
|
@ -83,56 +83,53 @@ struct Port {
|
|||
};
|
||||
|
||||
struct Session {
|
||||
Handle portHandle; // The port this session is subscribed to
|
||||
Session(Handle portHandle) : portHandle(portHandle) {}
|
||||
Handle portHandle; // The port this session is subscribed to
|
||||
Session(Handle portHandle) : portHandle(portHandle) {}
|
||||
};
|
||||
|
||||
enum class ThreadStatus {
|
||||
Running, // Currently running
|
||||
Ready, // Ready to run
|
||||
WaitArbiter, // Waiting on an address arbiter
|
||||
WaitSleep, // Waiting due to a SleepThread SVC
|
||||
WaitSync1, // Waiting for the single object in the wait list to be ready
|
||||
WaitSyncAny, // Wait for one object of the many that might be in the wait list to be ready
|
||||
WaitSyncAll, // Waiting for ALL sync objects in its wait list to be ready
|
||||
WaitIPC, // Waiting for the reply from an IPC request
|
||||
Dormant, // Created but not yet made ready
|
||||
Dead // Run to completion, or forcefully terminated
|
||||
Running, // Currently running
|
||||
Ready, // Ready to run
|
||||
WaitArbiter, // Waiting on an address arbiter
|
||||
WaitSleep, // Waiting due to a SleepThread SVC
|
||||
WaitSync1, // Waiting for the single object in the wait list to be ready
|
||||
WaitSyncAny, // Wait for one object of the many that might be in the wait list to be ready
|
||||
WaitSyncAll, // Waiting for ALL sync objects in its wait list to be ready
|
||||
WaitIPC, // Waiting for the reply from an IPC request
|
||||
Dormant, // Created but not yet made ready
|
||||
Dead // Run to completion, or forcefully terminated
|
||||
};
|
||||
|
||||
struct Thread {
|
||||
u32 initialSP; // Initial r13 value
|
||||
u32 entrypoint; // Initial r15 value
|
||||
u32 priority;
|
||||
u32 arg;
|
||||
ProcessorID processorID;
|
||||
ThreadStatus status;
|
||||
Handle handle; // OS handle for this thread
|
||||
int index; // Index of the thread. 0 for the first thread, 1 for the second, and so on
|
||||
u32 initialSP; // Initial r13 value
|
||||
u32 entrypoint; // Initial r15 value
|
||||
u32 priority;
|
||||
u32 arg;
|
||||
ProcessorID processorID;
|
||||
ThreadStatus status;
|
||||
Handle handle; // OS handle for this thread
|
||||
int index; // Index of the thread. 0 for the first thread, 1 for the second, and so on
|
||||
|
||||
// The waiting address for threads that are waiting on an AddressArbiter
|
||||
u32 waitingAddress;
|
||||
// The waiting address for threads that are waiting on an AddressArbiter
|
||||
u32 waitingAddress;
|
||||
|
||||
// The nanoseconds until a thread wakes up from being asleep or from timing out while waiting on an arbiter
|
||||
u64 waitingNanoseconds;
|
||||
// The tick this thread went to sleep on
|
||||
u64 sleepTick;
|
||||
// For WaitSynchronization(N): A vector of objects this thread is waiting for
|
||||
std::vector<Handle> waitList;
|
||||
// For WaitSynchronizationN: Shows whether the object should wait for all objects in the wait list or just one
|
||||
bool waitAll;
|
||||
// For WaitSynchronizationN: The "out" pointer
|
||||
u32 outPointer;
|
||||
// For WaitSynchronization(N): A vector of objects this thread is waiting for
|
||||
std::vector<Handle> waitList;
|
||||
// For WaitSynchronizationN: Shows whether the object should wait for all objects in the wait list or just one
|
||||
bool waitAll;
|
||||
// For WaitSynchronizationN: The "out" pointer
|
||||
u32 outPointer;
|
||||
u64 wakeupTick;
|
||||
|
||||
// Thread context used for switching between threads
|
||||
std::array<u32, 16> gprs;
|
||||
std::array<u32, 32> fprs; // Stored as u32 because dynarmic does it
|
||||
u32 cpsr;
|
||||
u32 fpscr;
|
||||
u32 tlsBase; // Base pointer for thread-local storage
|
||||
// Thread context used for switching between threads
|
||||
std::array<u32, 16> gprs;
|
||||
std::array<u32, 32> fprs; // Stored as u32 because dynarmic does it
|
||||
u32 cpsr;
|
||||
u32 fpscr;
|
||||
u32 tlsBase; // Base pointer for thread-local storage
|
||||
|
||||
// A list of threads waiting for this thread to terminate. Yes, threads are sync objects too.
|
||||
u64 threadsWaitingForTermination;
|
||||
// A list of threads waiting for this thread to terminate. Yes, threads are sync objects too.
|
||||
u64 threadsWaitingForTermination;
|
||||
};
|
||||
|
||||
static const char* kernelObjectTypeToString(KernelObjectType t) {
|
||||
|
@ -177,13 +174,12 @@ struct Timer {
|
|||
u64 waitlist; // Refer to the getWaitlist function below for documentation
|
||||
ResetType resetType = ResetType::OneShot;
|
||||
|
||||
u64 startTick; // CPU tick the timer started
|
||||
u64 currentDelay; // Number of ns until the timer fires next time
|
||||
u64 fireTick; // CPU tick the timer will be fired
|
||||
u64 interval; // Number of ns until the timer fires for the second and future times
|
||||
bool fired; // Has this timer been signalled?
|
||||
bool running; // Is this timer running or stopped?
|
||||
|
||||
Timer(ResetType type) : resetType(type), startTick(0), currentDelay(0), interval(0), waitlist(0), fired(false), running(false) {}
|
||||
Timer(ResetType type) : resetType(type), fireTick(0), interval(0), waitlist(0), fired(false), running(false) {}
|
||||
};
|
||||
|
||||
struct MemoryBlock {
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
#include <cstdarg>
|
||||
#include <fstream>
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
namespace Log {
|
||||
// Our logger class
|
||||
template <bool enabled>
|
||||
|
@ -12,7 +16,11 @@ namespace Log {
|
|||
|
||||
std::va_list args;
|
||||
va_start(args, fmt);
|
||||
#ifdef __ANDROID__
|
||||
__android_log_vprint(ANDROID_LOG_DEFAULT, "Panda3DS", fmt, args);
|
||||
#else
|
||||
std::vprintf(fmt, args);
|
||||
#endif
|
||||
va_end(args);
|
||||
}
|
||||
};
|
||||
|
@ -81,4 +89,4 @@ namespace Log {
|
|||
#else
|
||||
#define MAKE_LOG_FUNCTION(functionName, logger) MAKE_LOG_FUNCTION_USER(functionName, logger)
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -112,11 +112,12 @@ class Memory {
|
|||
// This tracks our OS' memory allocations
|
||||
std::vector<KernelMemoryTypes::MemoryInfo> memoryInfo;
|
||||
|
||||
std::array<SharedMemoryBlock, 4> sharedMemBlocks = {
|
||||
std::array<SharedMemoryBlock, 5> sharedMemBlocks = {
|
||||
SharedMemoryBlock(0, 0, KernelHandles::FontSharedMemHandle), // Shared memory for the system font (size is 0 because we read the size from the cmrc filesystem
|
||||
SharedMemoryBlock(0, 0x1000, KernelHandles::GSPSharedMemHandle), // GSP shared memory
|
||||
SharedMemoryBlock(0, 0x1000, KernelHandles::HIDSharedMemHandle), // HID shared memory
|
||||
SharedMemoryBlock(0, 0x3000, KernelHandles::CSNDSharedMemHandle), // CSND shared memory
|
||||
SharedMemoryBlock(0, 0xE7000, KernelHandles::APTCaptureSharedMemHandle), // APT Capture Buffer memory
|
||||
};
|
||||
|
||||
public:
|
||||
|
|
26
include/panda_qt/cheats_window.hpp
Normal file
26
include/panda_qt/cheats_window.hpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <QAction>
|
||||
#include <QWidget>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
|
||||
#include "emulator.hpp"
|
||||
|
||||
class QListWidget;
|
||||
|
||||
class CheatsWindow final : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CheatsWindow(Emulator* emu, const std::filesystem::path& path, QWidget* parent = nullptr);
|
||||
~CheatsWindow() = default;
|
||||
|
||||
private:
|
||||
void addEntry();
|
||||
void removeClicked();
|
||||
|
||||
QListWidget* cheatList;
|
||||
std::filesystem::path cheatPath;
|
||||
Emulator* emu;
|
||||
};
|
|
@ -5,6 +5,7 @@
|
|||
#include <QtWidgets>
|
||||
#include <atomic>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
@ -12,16 +13,38 @@
|
|||
#include "emulator.hpp"
|
||||
#include "panda_qt/about_window.hpp"
|
||||
#include "panda_qt/config_window.hpp"
|
||||
#include "panda_qt/cheats_window.hpp"
|
||||
#include "panda_qt/screen.hpp"
|
||||
#include "panda_qt/text_editor.hpp"
|
||||
#include "services/hid.hpp"
|
||||
|
||||
struct CheatMessage {
|
||||
u32 handle;
|
||||
std::vector<uint8_t> cheat;
|
||||
std::function<void(u32)> callback;
|
||||
};
|
||||
|
||||
class MainWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
// Types of messages we might send from the GUI thread to the emulator thread
|
||||
enum class MessageType { LoadROM, Reset, Pause, Resume, TogglePause, DumpRomFS, PressKey, ReleaseKey, LoadLuaScript };
|
||||
enum class MessageType {
|
||||
LoadROM,
|
||||
Reset,
|
||||
Pause,
|
||||
Resume,
|
||||
TogglePause,
|
||||
DumpRomFS,
|
||||
PressKey,
|
||||
ReleaseKey,
|
||||
SetCirclePadX,
|
||||
SetCirclePadY,
|
||||
LoadLuaScript,
|
||||
EditCheat,
|
||||
PressTouchscreen,
|
||||
ReleaseTouchscreen,
|
||||
};
|
||||
|
||||
// Tagged union representing our message queue messages
|
||||
struct EmulatorMessage {
|
||||
|
@ -36,9 +59,22 @@ class MainWindow : public QMainWindow {
|
|||
u32 key;
|
||||
} key;
|
||||
|
||||
struct {
|
||||
s16 value;
|
||||
} circlepad;
|
||||
|
||||
struct {
|
||||
std::string* str;
|
||||
} string;
|
||||
|
||||
struct {
|
||||
CheatMessage* c;
|
||||
} cheat;
|
||||
|
||||
struct {
|
||||
u16 x;
|
||||
u16 y;
|
||||
} touchscreen;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -54,6 +90,7 @@ class MainWindow : public QMainWindow {
|
|||
ScreenWidget screen;
|
||||
AboutWindow* aboutWindow;
|
||||
ConfigWindow* configWindow;
|
||||
CheatsWindow* cheatsEditor;
|
||||
TextEditorWindow* luaEditor;
|
||||
QMenuBar* menuBar = nullptr;
|
||||
|
||||
|
@ -63,6 +100,7 @@ class MainWindow : public QMainWindow {
|
|||
void selectROM();
|
||||
void dumpRomFS();
|
||||
void openLuaEditor();
|
||||
void openCheatsEditor();
|
||||
void showAboutMenu();
|
||||
void sendMessage(const EmulatorMessage& message);
|
||||
void dispatchMessage(const EmulatorMessage& message);
|
||||
|
@ -77,5 +115,9 @@ class MainWindow : public QMainWindow {
|
|||
|
||||
void keyPressEvent(QKeyEvent* event) override;
|
||||
void keyReleaseEvent(QKeyEvent* event) override;
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||
|
||||
void loadLuaScript(const std::string& code);
|
||||
void editCheat(u32 handle, const std::vector<uint8_t>& cheat, const std::function<void(u32)>& callback);
|
||||
};
|
89
include/scheduler.hpp
Normal file
89
include/scheduler.hpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
#pragma once
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <boost/container/static_vector.hpp>
|
||||
#include <limits>
|
||||
|
||||
#include "helpers.hpp"
|
||||
#include "logger.hpp"
|
||||
|
||||
struct Scheduler {
|
||||
enum class EventType {
|
||||
VBlank = 0, // End of frame event
|
||||
UpdateTimers = 1, // Update kernel timer objects
|
||||
Panic = 2, // Dummy event that is always pending and should never be triggered (Timestamp = UINT64_MAX)
|
||||
TotalNumberOfEvents // How many event types do we have in total?
|
||||
};
|
||||
static constexpr usize totalNumberOfEvents = static_cast<usize>(EventType::TotalNumberOfEvents);
|
||||
static constexpr u64 arm11Clock = 268111856;
|
||||
|
||||
template <typename Key, typename Val, usize size>
|
||||
using EventMap = boost::container::flat_multimap<Key, Val, std::less<Key>, boost::container::static_vector<std::pair<Key, Val>, size>>;
|
||||
|
||||
EventMap<u64, EventType, totalNumberOfEvents> events;
|
||||
u64 currentTimestamp = 0;
|
||||
u64 nextTimestamp = 0;
|
||||
|
||||
// Set nextTimestamp to the timestamp of the next event
|
||||
void updateNextTimestamp() { nextTimestamp = events.cbegin()->first; }
|
||||
|
||||
void addEvent(EventType type, u64 timestamp) {
|
||||
events.emplace(timestamp, type);
|
||||
updateNextTimestamp();
|
||||
}
|
||||
|
||||
void removeEvent(EventType type) {
|
||||
for (auto it = events.begin(); it != events.end(); it++) {
|
||||
// Find first event of type "type" and remove it.
|
||||
// Our scheduler shouldn't have duplicate events, so it's safe to exit when an event is found
|
||||
if (it->second == type) {
|
||||
events.erase(it);
|
||||
updateNextTimestamp();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void reset() {
|
||||
currentTimestamp = 0;
|
||||
|
||||
// Clear any pending events
|
||||
events.clear();
|
||||
addEvent(Scheduler::EventType::VBlank, arm11Clock / 60);
|
||||
|
||||
// Add a dummy event to always keep the scheduler non-empty
|
||||
addEvent(EventType::Panic, std::numeric_limits<u64>::max());
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits<s64>::max() / arm11Clock;
|
||||
|
||||
public:
|
||||
// Function for converting time units to cycles for various kernel functions
|
||||
// Thank you Citra
|
||||
static constexpr s64 nsToCycles(float ns) { return s64(arm11Clock * (0.000000001f) * ns); }
|
||||
static constexpr s64 nsToCycles(int ns) { return arm11Clock * s64(ns) / 1000000000; }
|
||||
|
||||
static constexpr s64 nsToCycles(s64 ns) {
|
||||
if (ns / 1000000000 > static_cast<s64>(MAX_VALUE_TO_MULTIPLY)) {
|
||||
return std::numeric_limits<s64>::max();
|
||||
}
|
||||
|
||||
if (ns > static_cast<s64>(MAX_VALUE_TO_MULTIPLY)) {
|
||||
return arm11Clock * (ns / 1000000000);
|
||||
}
|
||||
|
||||
return (arm11Clock * ns) / 1000000000;
|
||||
}
|
||||
|
||||
static constexpr s64 nsToCycles(u64 ns) {
|
||||
if (ns / 1000000000 > MAX_VALUE_TO_MULTIPLY) {
|
||||
return std::numeric_limits<s64>::max();
|
||||
}
|
||||
|
||||
if (ns > MAX_VALUE_TO_MULTIPLY) {
|
||||
return arm11Clock * (s64(ns) / 1000000000);
|
||||
}
|
||||
|
||||
return (arm11Clock * s64(ns)) / 1000000000;
|
||||
}
|
||||
};
|
|
@ -14,6 +14,7 @@ class BOSSService {
|
|||
void cancelTask(u32 messagePointer);
|
||||
void initializeSession(u32 messagePointer);
|
||||
void getErrorCode(u32 messagePointer);
|
||||
void getNewArrivalFlag(u32 messagePointer);
|
||||
void getNsDataIdList(u32 messagePointer, u32 commandWord);
|
||||
void getOptoutFlag(u32 messagePointer);
|
||||
void getStorageEntryInfo(u32 messagePointer); // Unknown what this is, name taken from Citra
|
||||
|
|
|
@ -12,22 +12,45 @@
|
|||
class Kernel;
|
||||
|
||||
class CAMService {
|
||||
using Event = std::optional<Handle>;
|
||||
|
||||
struct Port {
|
||||
Event bufferErrorInterruptEvent = std::nullopt;
|
||||
Event receiveEvent = std::nullopt;
|
||||
u16 transferBytes;
|
||||
|
||||
void reset() {
|
||||
bufferErrorInterruptEvent = std::nullopt;
|
||||
receiveEvent = std::nullopt;
|
||||
transferBytes = 256;
|
||||
}
|
||||
};
|
||||
|
||||
Handle handle = KernelHandles::CAM;
|
||||
Memory& mem;
|
||||
Kernel& kernel;
|
||||
MAKE_LOG_FUNCTION(log, camLogger)
|
||||
|
||||
using Event = std::optional<Handle>;
|
||||
static constexpr size_t portCount = 4; // PORT_NONE, PORT_CAM1, PORT_CAM2, PORT_BOTH
|
||||
std::array<Event, portCount> bufferErrorInterruptEvents;
|
||||
static constexpr size_t portCount = 2;
|
||||
std::array<Port, portCount> ports;
|
||||
|
||||
// Service commands
|
||||
void driverInitialize(u32 messagePointer);
|
||||
void driverFinalize(u32 messagePointer);
|
||||
void getMaxBytes(u32 messagePointer);
|
||||
void getMaxLines(u32 messagePointer);
|
||||
void getBufferErrorInterruptEvent(u32 messagePointer);
|
||||
void getSuitableY2RCoefficients(u32 messagePointer);
|
||||
void getTransferBytes(u32 messagePointer);
|
||||
void setContrast(u32 messagePointer);
|
||||
void setFrameRate(u32 messagePointer);
|
||||
void setReceiving(u32 messagePointer);
|
||||
void setSize(u32 messagePointer);
|
||||
void setTransferBytes(u32 messagePointer);
|
||||
void setTransferLines(u32 messagePointer);
|
||||
void setTrimming(u32 messagePointer);
|
||||
void setTrimmingParamsCenter(u32 messagePointer);
|
||||
void startCapture(u32 messagePointer);
|
||||
|
||||
public:
|
||||
CAMService(Memory& mem, Kernel& kernel) : mem(mem), kernel(kernel) {}
|
||||
|
|
|
@ -26,6 +26,7 @@ class FSService {
|
|||
SelfNCCHArchive selfNcch;
|
||||
SaveDataArchive saveData;
|
||||
SDMCArchive sdmc;
|
||||
SDMCArchive sdmcWriteOnly;
|
||||
NCCHArchive ncch;
|
||||
|
||||
// UserSaveData archives
|
||||
|
@ -61,6 +62,7 @@ class FSService {
|
|||
void getFreeBytes(u32 messagePointer);
|
||||
void getFormatInfo(u32 messagePointer);
|
||||
void getPriority(u32 messagePointer);
|
||||
void getSdmcArchiveResource(u32 messagePointer);
|
||||
void getThisSaveDataSecureValue(u32 messagePointer);
|
||||
void theGameboyVCFunction(u32 messagePointer);
|
||||
void initialize(u32 messagePointer);
|
||||
|
@ -81,9 +83,9 @@ class FSService {
|
|||
|
||||
public:
|
||||
FSService(Memory& mem, Kernel& kernel, const EmulatorConfig& config)
|
||||
: mem(mem), saveData(mem), sharedExtSaveData_nand(mem, "../SharedFiles/NAND", true), extSaveData_sdmc(mem, "SDMC"), sdmc(mem), selfNcch(mem),
|
||||
ncch(mem), userSaveData1(mem, ArchiveID::UserSaveData1), userSaveData2(mem, ArchiveID::UserSaveData2), kernel(kernel), config(config),
|
||||
systemSaveData(mem) {}
|
||||
: mem(mem), saveData(mem), sharedExtSaveData_nand(mem, "../SharedFiles/NAND", true), extSaveData_sdmc(mem, "SDMC"), sdmc(mem),
|
||||
sdmcWriteOnly(mem, true), selfNcch(mem), ncch(mem), userSaveData1(mem, ArchiveID::UserSaveData1),
|
||||
userSaveData2(mem, ArchiveID::UserSaveData2), kernel(kernel), config(config), systemSaveData(mem) {}
|
||||
|
||||
void reset();
|
||||
void handleSyncRequest(u32 messagePointer);
|
||||
|
|
|
@ -60,12 +60,22 @@ class GPUService {
|
|||
};
|
||||
static_assert(sizeof(FramebufferUpdate) == 64, "GSP::GPU::FramebufferUpdate has the wrong size");
|
||||
|
||||
// Used for saving and restoring GPU state via ImportDisplayCaptureInfo
|
||||
struct CaptureInfo {
|
||||
u32 leftFramebuffer; // Left framebuffer VA
|
||||
u32 rightFramebuffer; // Right framebuffer VA (Top screen only)
|
||||
u32 format;
|
||||
u32 stride;
|
||||
};
|
||||
static_assert(sizeof(CaptureInfo) == 16, "GSP::GPU::CaptureInfo has the wrong size");
|
||||
|
||||
// Service commands
|
||||
void acquireRight(u32 messagePointer);
|
||||
void flushDataCache(u32 messagePointer);
|
||||
void importDisplayCaptureInfo(u32 messagePointer);
|
||||
void registerInterruptRelayQueue(u32 messagePointer);
|
||||
void releaseRight(u32 messagePointer);
|
||||
void restoreVramSysArea(u32 messagePointer);
|
||||
void saveVramSysArea(u32 messagePointer);
|
||||
void setAxiConfigQoSMode(u32 messagePointer);
|
||||
void setBufferSwap(u32 messagePointer);
|
||||
|
@ -86,6 +96,15 @@ class GPUService {
|
|||
|
||||
void setBufferSwapImpl(u32 screen_id, const FramebufferInfo& info);
|
||||
|
||||
// Get the framebuffer info in shared memory for a given screen
|
||||
FramebufferUpdate* getFramebufferInfo(int screen) {
|
||||
// TODO: Offset depends on GSP thread being triggered
|
||||
return reinterpret_cast<FramebufferUpdate*>(&sharedMem[0x200 + screen * sizeof(FramebufferUpdate)]);
|
||||
}
|
||||
|
||||
FramebufferUpdate* getTopFramebufferInfo() { return getFramebufferInfo(0); }
|
||||
FramebufferUpdate* getBottomFramebufferInfo() { return getFramebufferInfo(1); }
|
||||
|
||||
public:
|
||||
GPUService(Memory& mem, GPU& gpu, Kernel& kernel, u32& currentPID) : mem(mem), gpu(gpu),
|
||||
kernel(kernel), currentPID(currentPID) {}
|
||||
|
|
|
@ -17,6 +17,7 @@ class PTMService {
|
|||
void getAdapterState(u32 messagePointer);
|
||||
void getBatteryChargeState(u32 messagePointer);
|
||||
void getBatteryLevel(u32 messagePointer);
|
||||
void getPedometerState(u32 messagePointer);
|
||||
void getStepHistory(u32 messagePointer);
|
||||
void getStepHistoryAll(u32 messagePointer);
|
||||
void getTotalStepCount(u32 messagePointer);
|
||||
|
|
|
@ -98,6 +98,7 @@ class Y2RService {
|
|||
void setSendingY(u32 messagePointer);
|
||||
void setSendingU(u32 messagePointer);
|
||||
void setSendingV(u32 messagePointer);
|
||||
void setSendingYUV(u32 messagePointer);
|
||||
void setSpacialDithering(u32 messagePointer);
|
||||
void setStandardCoeff(u32 messagePointer);
|
||||
void setTemporalDithering(u32 messagePointer);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue