diff --git a/CMakeLists.txt b/CMakeLists.txt index 4fde60ef..0bc21f49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,7 +69,7 @@ else() message(FATAL_ERROR "Currently unsupported CPU architecture") endif() -set(SOURCE_FILES src/main.cpp src/emulator.cpp src/core/CPU/cpu_dynarmic.cpp src/core/CPU/dynarmic_cycles.cpp +set(SOURCE_FILES src/main.cpp src/emulator.cpp src/io_file.cpp src/core/CPU/cpu_dynarmic.cpp src/core/CPU/dynarmic_cycles.cpp src/core/memory.cpp ) set(CRYPTO_SOURCE_FILES src/core/crypto/aes_engine.cpp) diff --git a/include/emulator.hpp b/include/emulator.hpp index 59a7a293..10279443 100644 --- a/include/emulator.hpp +++ b/include/emulator.hpp @@ -44,48 +44,7 @@ class Emulator { NCSD loadedNCSD; public: - Emulator() : kernel(cpu, memory, gpu), cpu(memory, kernel), gpu(memory), memory(cpu.getTicksRef()) { - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0) { - Helpers::panic("Failed to initialize SDL2"); - } - - // Make SDL use consistent positional button mapping - SDL_SetHint(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, "0"); - if (SDL_Init(SDL_INIT_GAMECONTROLLER) < 0) { - Helpers::warn("Failed to initialize SDL2 GameController: %s", SDL_GetError()); - } - - // Request OpenGL 4.1 Core (Max available on MacOS) - // MacOS gets mad if we don't explicitly demand a core profile - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); - window = SDL_CreateWindow("Alber", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL); - - if (window == nullptr) { - Helpers::panic("Window creation failed: %s", SDL_GetError()); - } - - glContext = SDL_GL_CreateContext(window); - if (glContext == nullptr) { - Helpers::panic("OpenGL context creation failed: %s", SDL_GetError()); - } - - if (!gladLoadGL(reinterpret_cast(SDL_GL_GetProcAddress))) { - Helpers::panic("OpenGL init failed: %s", SDL_GetError()); - } - - if (SDL_WasInit(SDL_INIT_GAMECONTROLLER)) { - gameController = SDL_GameControllerOpen(0); - - if (gameController != nullptr) { - SDL_Joystick* stick = SDL_GameControllerGetJoystick(gameController); - gameControllerID = SDL_JoystickInstanceID(stick); - } - } - - reset(); - } + Emulator(); void step(); void render(); diff --git a/include/io_file.hpp b/include/io_file.hpp index 41e2285c..0e5d7c53 100644 --- a/include/io_file.hpp +++ b/include/io_file.hpp @@ -1,136 +1,36 @@ #pragma once #include -#include #include #include -#include - -#ifdef _MSC_VER -// 64 bit offsets for MSVC -#define fseeko _fseeki64 -#define ftello _ftelli64 -#define fileno _fileno - -#pragma warning(disable : 4996) -#endif - -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif - -#ifdef WIN32 -#include // For _chsize_s -#else -#include // For ftruncate -#endif class IOFile { - FILE* handle = nullptr; - static inline std::filesystem::path appData = ""; // Directory for holding app data. AppData on Windows + FILE* handle = nullptr; + static inline std::filesystem::path appData = ""; // Directory for holding app data. AppData on Windows -public: - IOFile() {} - IOFile(FILE* handle) : handle(handle) {} - IOFile(const std::filesystem::path& path, const char* permissions = "rb") { - open(path, permissions); - } + public: + IOFile() {} + IOFile(FILE* handle) : handle(handle) {} + IOFile(const std::filesystem::path& path, const char* permissions = "rb"); - bool isOpen() { - return handle != nullptr; - } + bool isOpen() { return handle != nullptr; } + bool open(const std::filesystem::path& path, const char* permissions = "rb"); + bool open(const char* filename, const char* permissions = "rb"); + void close(); - bool open(const std::filesystem::path& path, const char* permissions = "rb") { - const auto str = path.string(); // For some reason converting paths directly with c_str() doesn't work - return open(str.c_str(), permissions); - } + std::pair read(void* data, std::size_t length, std::size_t dataSize); + std::pair readBytes(void* data, std::size_t count); - bool open(const char* filename, const char* permissions = "rb") { - handle = std::fopen(filename, permissions); - return isOpen(); - } + std::pair write(const void* data, std::size_t length, std::size_t dataSize); + std::pair writeBytes(const void* data, std::size_t count); - void close() { - if (isOpen()) { - fclose(handle); - handle = nullptr; - } - } + std::optional size(); - std::pair read(void* data, std::size_t length, std::size_t dataSize) { - if (!isOpen()) { - return { false, std::numeric_limits::max() }; - } + bool seek(std::int64_t offset, int origin = SEEK_SET); + bool rewind(); + FILE* getHandle(); + static void setAppDataDir(const std::filesystem::path& dir); + static std::filesystem::path getAppData() { return appData; } - if (length == 0) return { true, 0 }; - return { true, std::fread(data, dataSize, length, handle) }; - } - - auto readBytes(void* data, std::size_t count) { - return read(data, count, sizeof(std::uint8_t)); - } - - std::pair write(const void* data, std::size_t length, std::size_t dataSize) { - if (!isOpen()) { - return { false, std::numeric_limits::max() }; - } - - if (length == 0) return { true, 0 }; - return { true, std::fwrite(data, dataSize, length, handle) }; - } - - auto writeBytes(const void* data, std::size_t count) { - return write(data, count, sizeof(std::uint8_t)); - } - - std::optional size() { - if (!isOpen()) return {}; - - std::uint64_t pos = ftello(handle); - if (fseeko(handle, 0, SEEK_END) != 0) { - return {}; - } - - std::uint64_t size = ftello(handle); - if ((size != pos) && (fseeko(handle, pos, SEEK_SET) != 0)) { - return {}; - } - - return size; - } - - bool seek(std::int64_t offset, int origin = SEEK_SET) { - if (!isOpen() || fseeko(handle, offset, origin) != 0) - return false; - - return true; - } - - bool rewind() { - return seek(0, SEEK_SET); - } - - FILE* getHandle() { - return handle; - } - - static void setAppDataDir(const std::filesystem::path& dir) { - if (dir == "") Helpers::panic("Failed to set app data directory"); - appData = dir; - } - - // Sets the size of the file to "size" and returns whether it succeeded or not - bool setSize(std::uint64_t size) { - if (!isOpen()) return false; - bool success; - -#ifdef WIN32 - success = _chsize_s(_fileno(handle), size) == 0; -#else - success = ftruncate(fileno(handle), size) == 0; -#endif - fflush(handle); - return success; - } - - static std::filesystem::path getAppData() { return IOFile::appData; } + // Sets the size of the file to "size" and returns whether it succeeded or not + bool setSize(std::uint64_t size); }; \ No newline at end of file diff --git a/src/emulator.cpp b/src/emulator.cpp index 3a862231..2c8fadc8 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -1,5 +1,48 @@ #include "emulator.hpp" +Emulator::Emulator() : kernel(cpu, memory, gpu), cpu(memory, kernel), gpu(memory), memory(cpu.getTicksRef()) { + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0) { + Helpers::panic("Failed to initialize SDL2"); + } + + // Make SDL use consistent positional button mapping + SDL_SetHint(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, "0"); + if (SDL_Init(SDL_INIT_GAMECONTROLLER) < 0) { + Helpers::warn("Failed to initialize SDL2 GameController: %s", SDL_GetError()); + } + + // Request OpenGL 4.1 Core (Max available on MacOS) + // MacOS gets mad if we don't explicitly demand a core profile + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); + window = SDL_CreateWindow("Alber", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL); + + if (window == nullptr) { + Helpers::panic("Window creation failed: %s", SDL_GetError()); + } + + glContext = SDL_GL_CreateContext(window); + if (glContext == nullptr) { + Helpers::panic("OpenGL context creation failed: %s", SDL_GetError()); + } + + if (!gladLoadGL(reinterpret_cast(SDL_GL_GetProcAddress))) { + Helpers::panic("OpenGL init failed: %s", SDL_GetError()); + } + + if (SDL_WasInit(SDL_INIT_GAMECONTROLLER)) { + gameController = SDL_GameControllerOpen(0); + + if (gameController != nullptr) { + SDL_Joystick* stick = SDL_GameControllerGetJoystick(gameController); + gameControllerID = SDL_JoystickInstanceID(stick); + } + } + + reset(); +} + void Emulator::reset() { cpu.reset(); gpu.reset(); diff --git a/src/io_file.cpp b/src/io_file.cpp new file mode 100644 index 00000000..e3f04dc0 --- /dev/null +++ b/src/io_file.cpp @@ -0,0 +1,108 @@ +#include "io_file.hpp" + +#include "helpers.hpp" + +#ifdef _MSC_VER +// 64 bit offsets for MSVC +#define fseeko _fseeki64 +#define ftello _ftelli64 +#define fileno _fileno + +#pragma warning(disable : 4996) +#endif + +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#ifdef WIN32 +#include // For _chsize_s +#else +#include // For ftruncate +#endif + +IOFile::IOFile(const std::filesystem::path& path, const char* permissions) { open(path, permissions); } + +bool IOFile::open(const std::filesystem::path& path, const char* permissions) { + const auto str = path.string(); // For some reason converting paths directly with c_str() doesn't work + return open(str.c_str(), permissions); +} + +bool IOFile::open(const char* filename, const char* permissions) { + handle = std::fopen(filename, permissions); + return isOpen(); +} + +void IOFile::close() { + if (isOpen()) { + fclose(handle); + handle = nullptr; + } +} + +std::pair IOFile::read(void* data, std::size_t length, std::size_t dataSize) { + if (!isOpen()) { + return {false, std::numeric_limits::max()}; + } + + if (length == 0) return {true, 0}; + return {true, std::fread(data, dataSize, length, handle)}; +} + +std::pair IOFile::write(const void* data, std::size_t length, std::size_t dataSize) { + if (!isOpen()) { + return {false, std::numeric_limits::max()}; + } + + if (length == 0) { + return {true, 0}; + } else { + return {true, std::fwrite(data, dataSize, length, handle)}; + } +} + +std::pair IOFile::readBytes(void* data, std::size_t count) { return read(data, count, sizeof(std::uint8_t)); } +std::pair IOFile::writeBytes(const void* data, std::size_t count) { return write(data, count, sizeof(std::uint8_t)); } + +std::optional IOFile::size() { + if (!isOpen()) return {}; + + std::uint64_t pos = ftello(handle); + if (fseeko(handle, 0, SEEK_END) != 0) { + return {}; + } + + std::uint64_t size = ftello(handle); + if ((size != pos) && (fseeko(handle, pos, SEEK_SET) != 0)) { + return {}; + } + + return size; +} + +bool IOFile::seek(std::int64_t offset, int origin) { + if (!isOpen() || fseeko(handle, offset, origin) != 0) return false; + + return true; +} + +bool IOFile::rewind() { return seek(0, SEEK_SET); } +FILE* IOFile::getHandle() { return handle; } + +void IOFile::setAppDataDir(const std::filesystem::path& dir) { + if (dir == "") Helpers::panic("Failed to set app data directory"); + appData = dir; +} + +bool IOFile::setSize(std::uint64_t size) { + if (!isOpen()) return false; + bool success; + +#ifdef WIN32 + success = _chsize_s(_fileno(handle), size) == 0; +#else + success = ftruncate(fileno(handle), size) == 0; +#endif + fflush(handle); + return success; +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index d78dc407..9637e83f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,7 +5,7 @@ int main (int argc, char *argv[]) { emu.initGraphicsContext(); - auto romPath = std::filesystem::current_path() / (argc > 1 ? argv[1] : "OoT Demo Encrypted.3ds"); + auto romPath = std::filesystem::current_path() / (argc > 1 ? argv[1] : "teapot.elf"); if (!emu.loadROM(romPath)) { // For some reason just .c_str() doesn't show the proper path Helpers::panic("Failed to load ROM file: %s", romPath.string().c_str());