diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7bb7eb8..fdee724 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,6 +7,7 @@ target_sources( Interpreter/Interpreter.h Interpreter/Interpreter.cpp Graphics/Graphics.h Graphics/Graphics.cpp UI/UIManager.h UI/UIManager.cpp - UI/Chip8Display.h UI/Chip8Display.cpp + UI/Display.h UI/Display.cpp + UI/ControlPanel.h UI/ControlPanel.cpp ) target_link_libraries(${PROJECT_NAME} PRIVATE vendor) \ No newline at end of file diff --git a/src/Machine.cpp b/src/Machine.cpp index bebc433..96a4fd8 100644 --- a/src/Machine.cpp +++ b/src/Machine.cpp @@ -1,11 +1,9 @@ #include "Machine.h" -#include - #include "Graphics/Graphics.h" #include "Interpreter/Interpreter.h" #include "SDL3/SDL.h" -#include "UI/Chip8Display.h" +#include "UI/Display.h" #include "UI/UIManager.h" #include "imgui_impl_sdl3.h" diff --git a/src/Machine.h b/src/Machine.h index e6f2dfe..e48bc79 100644 --- a/src/Machine.h +++ b/src/Machine.h @@ -4,7 +4,7 @@ #include "Graphics/Graphics.h" #include "Interpreter/Interpreter.h" #include "SDL3/SDL_events.h" -#include "UI/Chip8Display.h" +#include "UI/Display.h" #include "UI/UIManager.h" class Machine { diff --git a/src/old/Chip8ControlPanel.cpp b/src/UI/ControlPanel.cpp similarity index 77% rename from src/old/Chip8ControlPanel.cpp rename to src/UI/ControlPanel.cpp index c6645e4..c0f9d56 100644 --- a/src/old/Chip8ControlPanel.cpp +++ b/src/UI/ControlPanel.cpp @@ -1,16 +1,21 @@ -#include "../Chip8ControlPanel.h" +#include "ControlPanel.h" #include - #include "imgui.h" -void Chip8ControlPanel::render() { +ControlPanel::ControlPanel( + std::shared_ptr graphics, + std::shared_ptr machine_state +): graphics{std::move(graphics)}, + machine_state{std::move(machine_state)} {} + +void ControlPanel::render() { constexpr auto full_width = ImVec2(-FLT_MIN, 0.0f); if (ImGui::Begin("Chip-8 - Controls")) { ImGui::Button("Load Rom", full_width); if (ImGui::Button(run ? "Pause" : "Run", full_width)) { - run = !run; + this->run = !run; } ImGui::Text("Status: %s", "Stopped"); diff --git a/src/UI/ControlPanel.h b/src/UI/ControlPanel.h new file mode 100644 index 0000000..3c1273a --- /dev/null +++ b/src/UI/ControlPanel.h @@ -0,0 +1,26 @@ +#ifndef CONTROLPANEL_H +#define CONTROLPANEL_H +#include + +#include "../Graphics/Graphics.h" +#include "../Interpreter/MachineState.h" + + +class ControlPanel { + std::shared_ptr graphics; + std::shared_ptr machine_state; + + bool run = false; + int steps = 1; + int speed = 100; +public: + ControlPanel( + std::shared_ptr graphics, + std::shared_ptr machine_state + ); + + void render() ; +}; + + +#endif //CONTROLPANEL_H diff --git a/src/UI/Chip8Display.cpp b/src/UI/Display.cpp similarity index 89% rename from src/UI/Chip8Display.cpp rename to src/UI/Display.cpp index 3a22779..54a531d 100644 --- a/src/UI/Chip8Display.cpp +++ b/src/UI/Display.cpp @@ -1,4 +1,4 @@ -#include "Chip8Display.h" +#include "Display.h" #include #include @@ -12,7 +12,7 @@ void SDLTextureDestroyer::operator()(SDL_Texture* texture) const { SDL_DestroyTexture(texture); } -Chip8Display::Chip8Display(std::shared_ptr graphics, std::shared_ptr machine_state): +Display::Display(std::shared_ptr graphics, std::shared_ptr machine_state): graphics{std::move(graphics)}, machine_state{std::move(machine_state)}, width(64), @@ -21,7 +21,7 @@ Chip8Display::Chip8Display(std::shared_ptr graphics, std::shared_ptr Chip8Display::create_texture() const { +std::unique_ptr Display::create_texture() const { SDL_Texture* raw_texture = SDL_CreateTexture(this->graphics->get_renderer().get(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, width, height); if (!raw_texture) { @@ -33,12 +33,12 @@ std::unique_ptr Chip8Display::create_texture() return std::unique_ptr(raw_texture); } -void Chip8Display::render() const { +void Display::render() const { update_texture(); display_widget(); } -void Chip8Display::update_texture() const { +void Display::update_texture() const { SDL_Surface* surface = nullptr; const auto& display = machine_state->display; @@ -78,7 +78,7 @@ void Chip8Display::update_texture() const { } } -void Chip8Display::display_widget() const { +void Display::display_widget() const { ImGui::Begin("CHIP-8 - Display"); const ImVec2 available_size = ImGui::GetContentRegionAvail(); diff --git a/src/UI/Chip8Display.h b/src/UI/Display.h similarity index 87% rename from src/UI/Chip8Display.h rename to src/UI/Display.h index c5215a2..5030566 100644 --- a/src/UI/Chip8Display.h +++ b/src/UI/Display.h @@ -1,5 +1,5 @@ -#ifndef CHIP8DISPLAY_H -#define CHIP8DISPLAY_H +#ifndef DISPLAY_H +#define DISPLAY_H #include #include "../Graphics/Color.h" @@ -11,7 +11,7 @@ struct SDLTextureDestroyer { void operator()(SDL_Texture* texture) const; }; -class Chip8Display { +class Display { std::shared_ptr graphics; std::shared_ptr machine_state; @@ -26,8 +26,9 @@ class Chip8Display { std::unique_ptr create_texture() const; void update_texture() const; void display_widget() const; + public: - Chip8Display( + Display( std::shared_ptr graphics, std::shared_ptr machine_state ); @@ -36,4 +37,4 @@ public: }; -#endif //CHIP8DISPLAY_H +#endif //DISPLAY_H diff --git a/src/UI/UIManager.cpp b/src/UI/UIManager.cpp index 4576eba..9689307 100644 --- a/src/UI/UIManager.cpp +++ b/src/UI/UIManager.cpp @@ -3,8 +3,10 @@ UIManager::UIManager(std::shared_ptr graphics, std::shared_ptr machine_state): graphics{std::move(graphics)}, machine_state{std::move(machine_state)}, - chip8_display{std::make_unique(this->graphics, this->machine_state)} {} + display{std::make_unique(this->graphics, this->machine_state)}, + control_panel{std::make_unique(this->graphics, this->machine_state)} {} -void UIManager::render() const { - this->chip8_display->render(); +void UIManager::render() { + this->display->render(); + this->control_panel->render(); } diff --git a/src/UI/UIManager.h b/src/UI/UIManager.h index 58c3430..12d28b7 100644 --- a/src/UI/UIManager.h +++ b/src/UI/UIManager.h @@ -2,19 +2,21 @@ #define UIMANAGER_H #include -#include "Chip8Display.h" +#include "ControlPanel.h" +#include "Display.h" #include "../Graphics/Graphics.h" class UIManager { std::shared_ptr graphics; std::shared_ptr machine_state; - std::unique_ptr chip8_display; + std::unique_ptr display; + std::unique_ptr control_panel; public: UIManager(std::shared_ptr graphics, std::shared_ptr machine_state); - void render() const; + void render() ; }; #endif //UIMANAGER_H diff --git a/src/old/Chip8.cpp b/src/old/Chip8.cpp deleted file mode 100644 index 5d82c58..0000000 --- a/src/old/Chip8.cpp +++ /dev/null @@ -1,133 +0,0 @@ -#include "../Chip8.h" - -#include -#include -#include -#include - -#include "bitops.h" - -Chip8::Chip8(): machine_state{std::make_shared()}, - graphics{machine_state}, - interpreter{machine_state, 0}, - target_cycle_time{1.0 / 700.0}, - last_update_time{0}, - accumulator{0}, - run{true}, - step{false} {} - -bool Chip8::init() { - if (!graphics.init()) { - return false; - } - - last_update_time = SDL_GetTicks(); - accumulator = 0; - - const auto rom = read_rom("roms/1-chip8-logo.ch8"); - interpreter.load_rom(rom); - - return true; -} - -void Chip8::set_keyboard_state(std::span keyboard_state) { - this->keyboard_state = keyboard_state; -} - -std::vector Chip8::read_rom(const std::string& path) { - std::ifstream rom_file(path, std::ios::binary); - - rom_file.seekg(0, std::ios::end); - const std::streampos file_size = rom_file.tellg(); - rom_file.seekg(0, std::ios::beg); - - std::cout << "ROM size: " << file_size << std::endl; - - std::vector rom(file_size); - - rom.insert( - rom.begin(), - std::istreambuf_iterator(rom_file), - std::istreambuf_iterator() - ); - - return rom; -} - -void Chip8::load_keyboard() { - machine_state->keyboard = keyboard_state[SDL_SCANCODE_X] ? bit_set(machine_state->keyboard, 0x0) : bit_clear(machine_state->keyboard, 0x0); - machine_state->keyboard = keyboard_state[SDL_SCANCODE_1] ? bit_set(machine_state->keyboard, 0x1) : bit_clear(machine_state->keyboard, 0x1); - machine_state->keyboard = keyboard_state[SDL_SCANCODE_2] ? bit_set(machine_state->keyboard, 0x2) : bit_clear(machine_state->keyboard, 0x2); - machine_state->keyboard = keyboard_state[SDL_SCANCODE_3] ? bit_set(machine_state->keyboard, 0x3) : bit_clear(machine_state->keyboard, 0x3); - machine_state->keyboard = keyboard_state[SDL_SCANCODE_Q] ? bit_set(machine_state->keyboard, 0x4) : bit_clear(machine_state->keyboard, 0x4); - machine_state->keyboard = keyboard_state[SDL_SCANCODE_W] ? bit_set(machine_state->keyboard, 0x5) : bit_clear(machine_state->keyboard, 0x5); - machine_state->keyboard = keyboard_state[SDL_SCANCODE_E] ? bit_set(machine_state->keyboard, 0x6) : bit_clear(machine_state->keyboard, 0x6); - machine_state->keyboard = keyboard_state[SDL_SCANCODE_A] ? bit_set(machine_state->keyboard, 0x7) : bit_clear(machine_state->keyboard, 0x7); - machine_state->keyboard = keyboard_state[SDL_SCANCODE_S] ? bit_set(machine_state->keyboard, 0x8) : bit_clear(machine_state->keyboard, 0x8); - machine_state->keyboard = keyboard_state[SDL_SCANCODE_D] ? bit_set(machine_state->keyboard, 0x9) : bit_clear(machine_state->keyboard, 0x9); - machine_state->keyboard = keyboard_state[SDL_SCANCODE_Z] ? bit_set(machine_state->keyboard, 0xA) : bit_clear(machine_state->keyboard, 0xA); - machine_state->keyboard = keyboard_state[SDL_SCANCODE_C] ? bit_set(machine_state->keyboard, 0xB) : bit_clear(machine_state->keyboard, 0xB); - machine_state->keyboard = keyboard_state[SDL_SCANCODE_4] ? bit_set(machine_state->keyboard, 0xC) : bit_clear(machine_state->keyboard, 0xC); - machine_state->keyboard = keyboard_state[SDL_SCANCODE_R] ? bit_set(machine_state->keyboard, 0xD) : bit_clear(machine_state->keyboard, 0xD); - machine_state->keyboard = keyboard_state[SDL_SCANCODE_F] ? bit_set(machine_state->keyboard, 0xE) : bit_clear(machine_state->keyboard, 0xE); - machine_state->keyboard = keyboard_state[SDL_SCANCODE_V] ? bit_set(machine_state->keyboard, 0xF) : bit_clear(machine_state->keyboard, 0xF); -} - - -void Chip8::iterate() { - load_keyboard(); - - std::stringstream buffer; - buffer << std::format( - "PC: {:03X} | SP: {:02X} | I {:02X} | DT {:02X} | ST {:02X} | INST: {:02X}{:02X} | V0-VF: ", - machine_state->pc, - machine_state->sp, - machine_state->i, - machine_state->dt, - machine_state->st, - machine_state->memory[machine_state->pc], - machine_state->memory[machine_state->pc + 1] - ); - for (int i = 0; i < 16; ++i) { - buffer << std::format("{:02X}", machine_state->v[i]); - if (i < 15) buffer << ","; - } - buffer << " | "; - - if (run) { - execute_instructions(); - } else if (step) { - execute_instruction(); - step = false; - last_update_time = SDL_GetTicks(); - } else { - last_update_time = SDL_GetTicks(); - } - - - graphics.draw(); -} - -void Chip8::execute_instructions() { - const auto current_time = SDL_GetTicks(); - const auto delta_time = static_cast(current_time - last_update_time) / 1000.0; - last_update_time = current_time; - accumulator += delta_time; - - while (accumulator >= target_cycle_time) { - execute_instruction(); - accumulator -= target_cycle_time; - } -} - -void Chip8::execute_instruction() { - interpreter.run(); -} - -void Chip8::on_keydown(SDL_Scancode scancode) { - if (scancode == SDL_SCANCODE_F1) { - run = !run; - } else if (scancode == SDL_SCANCODE_F2) { - step = true; - } -} diff --git a/src/old/Chip8.h b/src/old/Chip8.h deleted file mode 100644 index 980c491..0000000 --- a/src/old/Chip8.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef CHIP8_H -#define CHIP8_H -#include - -#include "Graphics.h" -#include "Interpreter.h" - - -class Chip8 { - std::shared_ptr machine_state; - Graphics graphics; - Interpreter interpreter; - - double target_cycle_time; - - Uint64 last_update_time; - double accumulator; - - std::span keyboard_state; - bool run; - bool step; - - void load_keyboard(); - void execute_instructions(); - void execute_instruction(); -public: - Chip8(); - - bool init(); - - void iterate(); - - std::vector read_rom(const std::string& path); - - void set_keyboard_state(std::span keyboard_state); - void on_keydown(SDL_Scancode scancode); -}; - - -#endif //CHIP8_H diff --git a/src/old/Chip8ControlPanel.h b/src/old/Chip8ControlPanel.h deleted file mode 100644 index 5ecd428..0000000 --- a/src/old/Chip8ControlPanel.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef CHIP8CONTROLPANEL_H -#define CHIP8CONTROLPANEL_H - - -class Chip8ControlPanel { - bool run = false; - int steps = 10; - int speed = 700; -public: - void render(); -}; - - -#endif //CHIP8CONTROLPANEL_H diff --git a/src/old/Graphics.cpp b/src/old/Graphics.cpp deleted file mode 100644 index 1dfeff5..0000000 --- a/src/old/Graphics.cpp +++ /dev/null @@ -1,173 +0,0 @@ -// -// Created by ryuuji on 6/20/25. -// - -#include "../Graphics.h" -#include "Chip8ControlPanel.h" - -#include -#include - -#include "imgui.h" -#include "imgui_impl_sdl3.h" -#include "imgui_impl_sdlrenderer3.h" - -void SDLWindowDestroyer::operator()(SDL_Window* window) const { - std::cout << "Destroying window" << std::endl; - SDL_DestroyWindow(window); -} - -void SDLRendererDestroyer::operator()(SDL_Renderer* renderer) const { - std::cout << "Destroying renderer" << std::endl; - SDL_DestroyRenderer(renderer); -} - -void SDLTextureDestroyer::operator()(SDL_Texture* texture) const { - std::cout << "Destroying texture" << std::endl; - SDL_DestroyTexture(texture); -} - -Graphics::Graphics(std::shared_ptr machine_state): machine_state{std::move(machine_state)}, - window_width{1920}, - window_height{1080}, - chip8_width(64), - chip8_height(32), - main_scale(1.0f) {} - -bool Graphics::init_sdl() { - SDL_SetAppMetadata("CHIP-8 Emulator", "0.0.1", "fun.skrd.chip8"); - - if (!SDL_Init(SDL_INIT_VIDEO)) { - SDL_Log("Couldn't initialize SDL: %s", SDL_GetError()); - return false; - } - - SDL_Window* raw_window = nullptr; - SDL_Renderer* raw_renderer = nullptr; - - main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()); - SDL_WindowFlags window_flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY; - - if (!SDL_CreateWindowAndRenderer("CHIP-8 Emulator", window_width * main_scale, window_height * main_scale, window_flags, &raw_window, &raw_renderer)) { - SDL_Log("Couldn't create window/renderer: %s", SDL_GetError()); - return false; - } - - this->window = std::unique_ptr(raw_window); - this->renderer = std::unique_ptr(raw_renderer); - - SDL_SetRenderVSync(renderer.get(), 1); - SDL_SetWindowPosition(window.get(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); - SDL_ShowWindow(window.get()); - - SDL_Texture* raw_texture = SDL_CreateTexture(renderer.get(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, chip8_width, chip8_height); - this->texture = std::unique_ptr(raw_texture); - SDL_SetTextureScaleMode(texture.get(), SDL_SCALEMODE_NEAREST); - - return true; -} - -bool Graphics::init_imgui() { - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - - ImGuiIO& io = ImGui::GetIO(); - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; - - ImGui::StyleColorsDark(); - ImGuiStyle& style = ImGui::GetStyle(); - style.ScaleAllSizes(main_scale); - style.FontScaleDpi = main_scale; - - ImGui_ImplSDL3_InitForSDLRenderer(window.get(), renderer.get()); - ImGui_ImplSDLRenderer3_Init(renderer.get()); - - return true; -} - - -bool Graphics::init() { - if (!init_sdl()) { - return false; - } - - if (!init_imgui()) { - return false; - } - - return true; -} - -void Graphics::draw() { - if (SDL_GetWindowFlags(window.get()) & SDL_WINDOW_MINIMIZED) { - SDL_Delay(10); - } - - build_chip8_texture(); - - ImGuiIO& io = ImGui::GetIO(); - - ImGui_ImplSDLRenderer3_NewFrame(); - ImGui_ImplSDL3_NewFrame(); - ImGui::NewFrame(); - ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport()); - - draw_chip8_widget(); - ctrPanel.render(); - - ImGui::Render(); - SDL_SetRenderScale(renderer.get(), io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y); - SDL_SetRenderDrawColor(renderer.get(), 0, 0, 0, 0xFF); - SDL_RenderClear(renderer.get()); - - ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), renderer.get()); - SDL_RenderPresent(renderer.get()); -} - -void Graphics::build_chip8_texture() { - SDL_Surface* surface = nullptr; - auto& display = machine_state->display; - - if (SDL_LockTextureToSurface(texture.get(), nullptr, &surface)) { - SDL_FillSurfaceRect(surface, nullptr, SDL_MapRGB(SDL_GetPixelFormatDetails(surface->format), nullptr, 0, 0, 0)); - - for (int i = 0; i < display.size(); i++) { - if (display[i]) { - int x = (i % chip8_width); - int y = (i / chip8_width); - - SDL_Rect rect = {x, y, 1, 1}; - Uint32 color = SDL_MapRGB( - SDL_GetPixelFormatDetails(surface->format), - nullptr, - 0, - 255, - 0 - ); - - - SDL_FillSurfaceRect(surface, &rect, color); - } - } - SDL_UnlockTexture(texture.get()); - } -} - -void Graphics::draw_chip8_widget() { - ImGui::Begin("CHIP-8 - Display"); - - const ImVec2 available_size = ImGui::GetContentRegionAvail(); - - const int scale_x = static_cast(static_cast(available_size.x) / static_cast(chip8_width)); - const int scale_y = static_cast(static_cast(available_size.y) / static_cast(chip8_height)); - const int scale = std::max(1, std::min(scale_x, scale_y)); - const ImVec2 scaled_size(static_cast(chip8_width * scale), static_cast(chip8_height * scale)); - - const ImVec2 cursor_pos = ImGui::GetCursorPos(); - const ImVec2 center_offset((available_size.x - scaled_size.x) / 2, (available_size.y - scaled_size.y) / 2); - ImGui::SetCursorPos(ImVec2(cursor_pos.x + center_offset.x, cursor_pos.y + center_offset.y)); - - ImGui::Image(static_cast(reinterpret_cast(texture.get())), scaled_size); - ImGui::End(); -} diff --git a/src/old/Graphics.h b/src/old/Graphics.h deleted file mode 100644 index ec02a2c..0000000 --- a/src/old/Graphics.h +++ /dev/null @@ -1,57 +0,0 @@ -// -// Created by ryuuji on 6/20/25. -// - -#ifndef RENDERER_H -#define RENDERER_H -#include -#include - -#include "Chip8ControlPanel.h" -#include "imgui.h" -#include "MachineState.h" -#include "SDL3/SDL.h" - -struct SDLWindowDestroyer { - void operator()(SDL_Window *window) const; -}; -struct SDLRendererDestroyer { - void operator()(SDL_Renderer *renderer) const; -}; -struct SDLTextureDestroyer { - void operator()(SDL_Texture *texture) const; -}; - -class Graphics { - std::shared_ptr machine_state; - - std::unique_ptr window; - std::unique_ptr renderer; - std::unique_ptr texture; - - Chip8ControlPanel ctrPanel; - - int window_width; - int window_height; - - int chip8_width; - int chip8_height; - - float main_scale; - - bool init_sdl(); - bool init_imgui(); - - void build_chip8_texture(); - void draw_chip8_widget(); - -public: - Graphics(std::shared_ptr machine_state); - - bool init(); - void draw(); -}; - - - -#endif //RENDERER_H diff --git a/src/old/Interpreter.cpp b/src/old/Interpreter.cpp deleted file mode 100644 index fea2fae..0000000 --- a/src/old/Interpreter.cpp +++ /dev/null @@ -1,496 +0,0 @@ -#include "../Interpreter.h" - -#include -#include -#include -#include -#include -#include - -#include "SDL3/SDL_log.h" - -Interpreter::Interpreter(std::shared_ptr machine_state, uint8_t quirks): - machine_state{std::move(machine_state)}, - quirks{quirks} { - this->random_generator = std::mt19937(std::random_device{}()); - this->load_fonts(); -} - -void Interpreter::load_fonts() { - constexpr uint8_t font_set[] = { - 0xF0, 0x90, 0x90, 0x90, 0xF0, // 0 - 0x20, 0x60, 0x20, 0x20, 0x70, // 1 - 0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2 - 0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3 - 0x90, 0x90, 0xF0, 0x10, 0x10, // 4 - 0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5 - 0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6 - 0xF0, 0x10, 0x20, 0x40, 0x40, // 7 - 0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8 - 0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9 - 0xF0, 0x90, 0xF0, 0x90, 0x90, // A - 0xE0, 0x90, 0xE0, 0x90, 0xE0, // B - 0xF0, 0x80, 0x80, 0x80, 0xF0, // C - 0xE0, 0x90, 0x90, 0x90, 0xE0, // D - 0xF0, 0x80, 0xF0, 0x80, 0xF0, // E - 0xF0, 0x80, 0xF0, 0x80, 0x80 // F - }; - - std::copy(std::begin(font_set), std::end(font_set), machine_state->memory.begin() + 0x050); -} - - -void Interpreter::load_rom(const std::vector& rom) { - std::copy(std::begin(rom), std::end(rom), machine_state->memory.begin() + 0x200); -} - -Instruction Interpreter::decode_next() { - const uint8_t high_word = machine_state->memory[machine_state->pc]; - const uint8_t low_word = machine_state->memory[machine_state->pc + 1]; - const uint16_t word = (high_word << 8) | low_word; - - const uint8_t operation = (word & 0xF000) >> 12; - const uint8_t x = (word & 0x0F00) >> 8; - const uint8_t y = (word & 0x00F0) >> 4; - const uint8_t n = word & 0x000F; - const uint8_t kk = word & 0x00FF; - const uint16_t nnn = word & 0x0FFF; - - OpCode op_code = OpCode::NOP; - - if (operation == 0) { - if (kk == 0xE0) { - op_code = OpCode::CLS; - } else if (kk == 0xEE) { - op_code = OpCode::RET; - } - } else if (operation == 1) { - op_code = OpCode::JP_ADDR; - } else if (operation == 2) { - op_code = OpCode::CALL_ADDR; - } else if (operation == 3) { - op_code = OpCode::SE_VX_BYTE; - } else if (operation == 4) { - op_code = OpCode::SNE_VX_BYTE; - } else if (operation == 5) { - op_code = OpCode::SE_VX_VY; - } else if (operation == 6) { - op_code = OpCode::LD_VX_BYTE; - } else if (operation == 7) { - op_code = OpCode::ADD_VX_BYTE; - } else if (operation == 8) { - if (n == 0) { - op_code = OpCode::LD_VX_VY; - } else if (n == 1) { - op_code = OpCode::OR_VX_VY; - } else if (n == 2) { - op_code = OpCode::AND_VX_VY; - } else if (n == 3) { - op_code = OpCode::XOR_VX_VY; - } else if (n == 4) { - op_code = OpCode::ADD_VX_VY; - } else if (n == 5) { - op_code = OpCode::SUB_VX_VY; - } else if (n == 6) { - op_code = OpCode::SHR_VX_VY; - } else if (n == 7) { - op_code = OpCode::SUBN_VX_VY; - } else if (n == 0xE) { - op_code = OpCode::SHL_VX_VY; - } - } else if (operation == 9) { - op_code = OpCode::SNE_VX_VY; - } else if (operation == 0xA) { - op_code = OpCode::LD_I_ADDR; - } else if (operation == 0xB) { - op_code = OpCode::JP_V0_ADDR; - } else if (operation == 0xC) { - op_code = OpCode::RND_VX_BYTE; - } else if (operation == 0xD) { - op_code = OpCode::DRW_VX_VY_NIBBLE; - } else if (operation == 0xE) { - if (kk == 0x9E) { - op_code = OpCode::SKP_VX; - } else if (kk == 0xA1) { - op_code = OpCode::SKNP_VX; - } - } else if (operation == 0xF) { - if (kk == 0x07) { - op_code = OpCode::LD_VX_DT; - } else if (kk == 0x0A) { - op_code = OpCode::LD_VX_K; - } else if (kk == 0x15) { - op_code = OpCode::LD_DT_VX; - } else if (kk == 0x18) { - op_code = OpCode::LD_ST_VX; - } else if (kk == 0x1E) { - op_code = OpCode::ADD_I_VX; - } else if (kk == 0x29) { - op_code = OpCode::LD_F_VX; - } else if (kk == 0x33) { - op_code = OpCode::LD_B_VX; - } else if (kk == 0x55) { - op_code = OpCode::LD_I_VX; - } else if (kk == 0x65) { - op_code = OpCode::LD_VX_I; - } - } - - return Instruction{ - .op_code = op_code, - .operation = operation, - .instruction = word, - .x = x, - .y = y, - .n = n, - .kk = kk, - .nnn = nnn - }; -} - -void Interpreter::execute(const Instruction& instruction) { - if (instruction.op_code == OpCode::CLS) cls(instruction); - else if (instruction.op_code == OpCode::RET) ret(instruction); - else if (instruction.op_code == OpCode::SYS_ADDR) sys_addr(instruction); - else if (instruction.op_code == OpCode::JP_ADDR) jp_addr(instruction); - else if (instruction.op_code == OpCode::CALL_ADDR) call_addr(instruction); - else if (instruction.op_code == OpCode::SE_VX_BYTE) se_vx_byte(instruction); - else if (instruction.op_code == OpCode::SNE_VX_BYTE) sne_vx_byte(instruction); - else if (instruction.op_code == OpCode::SE_VX_VY) se_vx_vy(instruction); - else if (instruction.op_code == OpCode::LD_VX_BYTE) ld_vx_byte(instruction); - else if (instruction.op_code == OpCode::ADD_VX_BYTE) add_vx_byte(instruction); - else if (instruction.op_code == OpCode::LD_VX_VY) ld_vx_vy(instruction); - else if (instruction.op_code == OpCode::OR_VX_VY) or_vx_vy(instruction); - else if (instruction.op_code == OpCode::AND_VX_VY) and_vx_vy(instruction); - else if (instruction.op_code == OpCode::XOR_VX_VY) xor_vx_vy(instruction); - else if (instruction.op_code == OpCode::ADD_VX_VY) add_vx_vy(instruction); - else if (instruction.op_code == OpCode::SUB_VX_VY) sub_vx_vy(instruction); - else if (instruction.op_code == OpCode::SHR_VX_VY) shr_vx_vy(instruction); - else if (instruction.op_code == OpCode::SUBN_VX_VY) subn_vx_vy(instruction); - else if (instruction.op_code == OpCode::SHL_VX_VY) shl_vx_vy(instruction); - else if (instruction.op_code == OpCode::SNE_VX_VY) sne_vx_vy(instruction); - else if (instruction.op_code == OpCode::LD_I_ADDR) ld_i_addr(instruction); - else if (instruction.op_code == OpCode::JP_V0_ADDR) jp_v0_addr(instruction); - else if (instruction.op_code == OpCode::RND_VX_BYTE) rnd_vx_byte(instruction); - else if (instruction.op_code == OpCode::DRW_VX_VY_NIBBLE) drw_vx_vy_nibble(instruction); - else if (instruction.op_code == OpCode::SKP_VX) skp_vx(instruction); - else if (instruction.op_code == OpCode::SKNP_VX) sknp_vx(instruction); - else if (instruction.op_code == OpCode::LD_VX_DT) ld_vx_dt(instruction); - else if (instruction.op_code == OpCode::LD_VX_K) ld_vx_k(instruction); - else if (instruction.op_code == OpCode::LD_DT_VX) ld_dt_vx(instruction); - else if (instruction.op_code == OpCode::LD_ST_VX) ld_st_vx(instruction); - else if (instruction.op_code == OpCode::ADD_I_VX) add_i_vx(instruction); - else if (instruction.op_code == OpCode::LD_F_VX) ld_f_vx(instruction); - else if (instruction.op_code == OpCode::LD_B_VX) ld_b_vx(instruction); - else if (instruction.op_code == OpCode::LD_I_VX) ld_i_vx(instruction); - else if (instruction.op_code == OpCode::LD_VX_I) ld_vx_i(instruction); - else if (instruction.op_code == OpCode::NOP) nop(instruction); -} - - -void Interpreter::run() { - const Instruction instruction = decode_next(); - - machine_state->pc += 2; - - execute(instruction); - - if (machine_state->pc >= 0xFFF) { - SDL_Log("PC Outside of memory, going back 0x200"); - machine_state->pc = 0x200; - } -} - -void Interpreter::sys_addr(const Instruction& instruction) { - // NOP -} - -void Interpreter::nop(const Instruction& instruction) { - // NOP -} - -void Interpreter::cls(const Instruction& instruction) { - machine_state->display.fill(false); -} - -void Interpreter::ret(const Instruction& instruction) { - machine_state->sp -= 1; - machine_state->pc = machine_state->stack[machine_state->sp]; -} - -void Interpreter::jp_addr(const Instruction& instruction) { - machine_state->pc = instruction.nnn; -} - -void Interpreter::call_addr(const Instruction& instruction) { - machine_state->stack[machine_state->sp] = machine_state->pc; - machine_state->sp += 1; - machine_state->pc = instruction.nnn; -} - -void Interpreter::se_vx_byte(const Instruction& instruction) { - if (machine_state->v[instruction.x] == instruction.kk) { - machine_state->pc += 2; - } -} - -void Interpreter::sne_vx_byte(const Instruction& instruction) { - if (machine_state->v[instruction.x] != instruction.kk) { - machine_state->pc += 2; - } -} - -void Interpreter::se_vx_vy(const Instruction& instruction) { - if (machine_state->v[instruction.x] == machine_state->v[instruction.y]) { - machine_state->pc += 2; - } -} - -void Interpreter::ld_vx_byte(const Instruction& instruction) { - machine_state->v[instruction.x] = instruction.kk; -} - -void Interpreter::add_vx_byte(const Instruction& instruction) { - machine_state->v[instruction.x] += instruction.kk; -} - -void Interpreter::ld_vx_vy(const Instruction& instruction) { - machine_state->v[instruction.x] = machine_state->v[instruction.y]; -} - -void Interpreter::or_vx_vy(const Instruction& instruction) { - machine_state->v[instruction.x] |= machine_state->v[instruction.y]; -} - -void Interpreter::and_vx_vy(const Instruction& instruction) { - machine_state->v[instruction.x] &= machine_state->v[instruction.y]; -} - -void Interpreter::xor_vx_vy(const Instruction& instruction) { - machine_state->v[instruction.x] ^= machine_state->v[instruction.y]; -} - -void Interpreter::add_vx_vy(const Instruction& instruction) { - auto& vx = machine_state->v[instruction.x]; - auto& vy = machine_state->v[instruction.y]; - auto& vf = machine_state->v[0xF]; - - if (vx + vy > 0xFF) { - vf = 1; - } else { - vf = 0; - } - - vx += vy; -} - -void Interpreter::sub_vx_vy(const Instruction& instruction) { - auto& vx = machine_state->v[instruction.x]; - auto& vy = machine_state->v[instruction.y]; - auto& vf = machine_state->v[0xF]; - - if (vx > vy) { - vf = 1; - } else { - vf = 0; - } - - vx -= vy; -} - -void Interpreter::shr_vx_vy(const Instruction& instruction) { - auto& vx = machine_state->v[instruction.x]; - auto& vy = machine_state->v[instruction.y]; - auto& vf = machine_state->v[0xF]; - - if (quirks & static_cast(InterpreterQuirks::COSMAC_SHIFT)) { - vx = vy; - } - - if (vx & 0x01) { - vf = 1; - } else { - vf = 0; - } - - vx = vx >> 1; -} - -void Interpreter::subn_vx_vy(const Instruction& instruction) { - auto& vx = machine_state->v[instruction.x]; - auto& vy = machine_state->v[instruction.y]; - auto& vf = machine_state->v[0xF]; - - if (vy > vx) { - vf = 1; - } else { - vf = 0; - } - - vx = vy - vx; -} - -void Interpreter::shl_vx_vy(const Instruction& instruction) { - auto& vx = machine_state->v[instruction.x]; - auto& vy = machine_state->v[instruction.y]; - auto& vf = machine_state->v[0xF]; - - if (quirks & static_cast(InterpreterQuirks::COSMAC_SHIFT)) { - vx = vy; - } - - if (vx & 0x80) { - vf = 1; - } else { - vf = 0; - } - - vx = vx << 1; -} - -void Interpreter::sne_vx_vy(const Instruction& instruction) { - if (machine_state->v[instruction.x] != machine_state->v[instruction.y]) { - machine_state->pc += 2; - } -} - -void Interpreter::ld_i_addr(const Instruction& instruction) { - machine_state->i = instruction.nnn; -} - -void Interpreter::jp_v0_addr(const Instruction& instruction) { - if (quirks & static_cast(InterpreterQuirks::SUPER_CHIP_JUMP)) { - machine_state->pc = instruction.nnn + machine_state->v[instruction.x]; - } else { - machine_state->pc = instruction.nnn + machine_state->v[0]; - } -} - -void Interpreter::rnd_vx_byte(const Instruction& instruction) { - auto random = std::uniform_int_distribution(0, 0xFF); - const auto value = random(random_generator); - - machine_state->v[instruction.x] = value & instruction.kk; -} - -void Interpreter::drw_vx_vy_nibble(const Instruction& instruction) { - auto& memory = machine_state->memory; - auto& display = machine_state->display; - auto& vx = machine_state->v[instruction.x]; - auto& vy = machine_state->v[instruction.y]; - auto& vf = machine_state->v[0xF]; - - const uint8_t start_x = vx & 63; - const uint8_t start_y = vy & 31; - vf = 0; - - for (auto row = 0; row < instruction.n; row++) { - const auto current_y = start_y + row; - - if (current_y > 31) { - break; - } - - const auto sprite_byte = memory[machine_state->i + row]; - - for (auto bit = 0; bit < 8; bit++) { - const auto current_x = start_x + bit; - - if (current_x > 63) { - break; - } - - const auto pixel = (sprite_byte >> (7 - bit)) & 0x01; - const auto index = (current_y * 64) + current_x; - - if (pixel) { - if (display[index]) { - display[index] = false; - vf = 1; - } else { - display[index] = true; - } - } - } - } -} - -void Interpreter::skp_vx(const Instruction& instruction) { - if (machine_state->keyboard & (1 << instruction.x)) { - machine_state->pc += 2; - } -} - -void Interpreter::sknp_vx(const Instruction& instruction) { - if (!(machine_state->keyboard & (1 << instruction.x))) { - machine_state->pc += 2; - } -} - -void Interpreter::ld_vx_dt(const Instruction& instruction) { - machine_state->v[instruction.x] = machine_state->dt; -} - -void Interpreter::ld_vx_k(const Instruction& instruction) { - if (machine_state->keyboard == 0) { - machine_state->pc -= 2; - return; - } - - for (auto key = 0; key < 16; key++) { - if (machine_state->keyboard & (1 << key)) { - machine_state->v[instruction.x] = key; - break; - } - } -} - -void Interpreter::ld_dt_vx(const Instruction& instruction) { - machine_state->dt = machine_state->v[instruction.x]; -} - -void Interpreter::ld_st_vx(const Instruction& instruction) { - machine_state->st = machine_state->v[instruction.x]; -} - -void Interpreter::add_i_vx(const Instruction& instruction) { - machine_state->i += machine_state->v[instruction.x]; -} - -void Interpreter::ld_f_vx(const Instruction& instruction) { - auto& vx = machine_state->v[instruction.x]; - machine_state->i = ((vx & 0xF) * 5) + 0x50; -} - -void Interpreter::ld_b_vx(const Instruction& instruction) { - const auto number = machine_state->v[instruction.x]; - machine_state->memory[machine_state->i] = number / 100; - machine_state->memory[machine_state->i + 1] = (number - (machine_state->memory[machine_state->i] * 100)) / 10; - machine_state->memory[machine_state->i + 2] = number - (machine_state->memory[machine_state->i] * 100) - (machine_state->memory[machine_state->i + 1] * 10); -} - -void Interpreter::ld_i_vx(const Instruction& instruction) { - bool use_quirk = quirks & static_cast(InterpreterQuirks::COSMAC_STORE_AND_LOAD); - - for (auto reg = 0; reg <= instruction.x; reg++) { - if (use_quirk) { - machine_state->memory[machine_state->i] = machine_state->v[reg]; - machine_state->i++; - } else { - machine_state->memory[machine_state->i + reg] = machine_state->v[reg]; - } - } -} - -void Interpreter::ld_vx_i(const Instruction& instruction) { - bool use_quirk = quirks & static_cast(InterpreterQuirks::COSMAC_STORE_AND_LOAD); - - for (auto reg = 0; reg <= instruction.x; reg++) { - if (use_quirk) { - machine_state->v[reg] = machine_state->memory[machine_state->i]; - machine_state->i++; - } else { - machine_state->v[reg] = machine_state->memory[machine_state->i + reg]; - } - } -} diff --git a/src/old/Interpreter.h b/src/old/Interpreter.h deleted file mode 100644 index b29e30c..0000000 --- a/src/old/Interpreter.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef INTERPRETER_H -#define INTERPRETER_H -#include -#include -#include -#include -#include - -#include "../MachineState.h" - -enum class InterpreterQuirks { - COSMAC_SHIFT = 1 << 0, - SUPER_CHIP_JUMP = 1 << 1, - COSMAC_STORE_AND_LOAD = 1 << 2, -}; - -enum class OpCode { - CLS, // 00E0 - CLS - RET, // 00EE - RET - SYS_ADDR, // 0nnn - SYS addr - JP_ADDR, // 1nnn - JP addr - CALL_ADDR, // 2nnn - CALL addr - SE_VX_BYTE, // 3xkk - SE Vx, byte - SNE_VX_BYTE, // 4xkk - SNE Vx, byte - SE_VX_VY, // 5xy0 - SE Vx, Vy - LD_VX_BYTE, // 6xkk - LD Vx, byte - ADD_VX_BYTE, // 7xkk - ADD Vx, byte - LD_VX_VY, // 8xy0 - LD Vx, Vy - OR_VX_VY, // 8xy1 - OR Vx, Vy - AND_VX_VY, // 8xy2 - AND Vx, Vy - XOR_VX_VY, // 8xy3 - XOR Vx, Vy - ADD_VX_VY, // 8xy4 - ADD Vx, Vy - SUB_VX_VY, // 8xy5 - SUB Vx, Vy - SHR_VX_VY, // 8xy6 - SHR Vx {, Vy} - SUBN_VX_VY, // 8xy7 - SUBN Vx, Vy - SHL_VX_VY, // 8xyE - SHL Vx {, Vy} - SNE_VX_VY, // 9xy0 - SNE Vx, Vy - LD_I_ADDR, // Annn - LD I, addr - JP_V0_ADDR, // Bnnn - JP V0, addr - RND_VX_BYTE, // Cxkk - RND Vx, byte - DRW_VX_VY_NIBBLE, // Dxyn - DRW Vx, Vy, nibble - SKP_VX, // Ex9E - SKP Vx - SKNP_VX, // ExA1 - SKNP Vx - LD_VX_DT, // Fx07 - LD Vx, DT - LD_VX_K, // Fx0A - LD Vx, K - LD_DT_VX, // Fx15 - LD DT, Vx - LD_ST_VX, // Fx18 - LD ST, Vx - ADD_I_VX, // Fx1E - ADD I, Vx - LD_F_VX, // Fx29 - LD F, Vx - LD_B_VX, // Fx33 - LD B, Vx - LD_I_VX, // Fx55 - LD [I], Vx - LD_VX_I, // Fx65 - LD Vx, [I] - NOP, // INVALID OPERATION -}; - -struct Instruction { - OpCode op_code; - uint8_t operation; - uint16_t instruction; - uint8_t x; - uint8_t y; - uint8_t n; - uint8_t kk; - uint16_t nnn; -}; - -class Interpreter { - std::shared_ptr machine_state; - - std::mt19937 random_generator; - uint8_t quirks; - - void load_fonts(); - - Instruction decode_next(); - void execute(const Instruction& instruction); - - void sys_addr(const Instruction& instruction); - void nop(const Instruction& instruction); - void cls(const Instruction& instruction); - void ret(const Instruction& instruction); - void jp_addr(const Instruction& instruction); - void call_addr(const Instruction& instruction); - void se_vx_byte(const Instruction& instruction); - void sne_vx_byte(const Instruction& instruction); - void se_vx_vy(const Instruction& instruction); - void ld_vx_byte(const Instruction& instruction); - void add_vx_byte(const Instruction& instruction); - void ld_vx_vy(const Instruction& instruction); - void or_vx_vy(const Instruction& instruction); - void and_vx_vy(const Instruction& instruction); - void xor_vx_vy(const Instruction& instruction); - void add_vx_vy(const Instruction& instruction); - void sub_vx_vy(const Instruction& instruction); - void shr_vx_vy(const Instruction& instruction); - void subn_vx_vy(const Instruction& instruction); - void shl_vx_vy(const Instruction& instruction); - void sne_vx_vy(const Instruction& instruction); - void ld_i_addr(const Instruction& instruction); - void jp_v0_addr(const Instruction& instruction); - void jump_with_offset_super_chip(const Instruction& instruction); - void rnd_vx_byte(const Instruction& instruction); - void drw_vx_vy_nibble(const Instruction& instruction); - void skp_vx(const Instruction& instruction); - void sknp_vx(const Instruction& instruction); - void ld_vx_dt(const Instruction& instruction); - void ld_vx_k(const Instruction& instruction); - void ld_dt_vx(const Instruction& instruction); - void ld_st_vx(const Instruction& instruction); - void add_i_vx(const Instruction& instruction); - void ld_f_vx(const Instruction& instruction); - void ld_b_vx(const Instruction& instruction); - void ld_i_vx(const Instruction& instruction); - void ld_vx_i(const Instruction& instruction); - -public: - Interpreter(std::shared_ptr machine_state, uint8_t quirks); - - void load_rom(const std::vector& rom); - - void run(); -}; - - -#endif //INTERPRETER_H diff --git a/src/old/MachineState.h b/src/old/MachineState.h deleted file mode 100644 index 1aeebce..0000000 --- a/src/old/MachineState.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef MACHINESTATE_H -#define MACHINESTATE_H -#include -#include - -struct MachineState { - std::array memory{}; - std::array v{}; - std::array stack{}; - std::array display{}; - uint16_t keyboard = 0; - uint16_t pc = 0x200; - uint8_t sp = 0; - uint16_t i = 0; - uint8_t dt = 0; - uint8_t st = 0; -}; - -#endif //MACHINESTATE_H diff --git a/src/old/bitops.h b/src/old/bitops.h deleted file mode 100644 index c303fc8..0000000 --- a/src/old/bitops.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// Created by ryuuji on 6/21/25. -// - -#ifndef BITOPS_H -#define BITOPS_H -#include - -template -T bit_set(const T number, const int bit) { - static_assert(std::is_unsigned_v, "T must be an unsigned integral type"); - return number | (1 << bit); -} - -template -T bit_clear(const T number, const int bit) { - static_assert(std::is_unsigned_v, "T must be an unsigned integral type"); - return number & ~(1 << bit); -} - -template -T bit_toggle(const T number, const int bit) { - static_assert(std::is_unsigned_v, "T must be an unsigned integral type"); - return number ^ (1 << bit); -} - -template -bool bit_check(const T number, const int bit) { - static_assert(std::is_unsigned_v, "T must be an unsigned integral type"); - return (number >> bit) & 1; -} - -#endif //BITOPS_H diff --git a/src/old/main.cpp b/src/old/main.cpp deleted file mode 100644 index 303cf6b..0000000 --- a/src/old/main.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#define SDL_MAIN_USE_CALLBACKS 1 -#include - -#include "Chip8.h" -#include "imgui_impl_sdl3.h" - -SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) { - const auto chip8 = new Chip8(); - *appstate = chip8; - - if (!chip8->init()) { - return SDL_APP_FAILURE; - } - - int num_keys; - const bool* kb_state = SDL_GetKeyboardState(&num_keys); - const std::span kb_state_view(kb_state, num_keys); - chip8->set_keyboard_state(kb_state_view); - - return SDL_APP_CONTINUE; -} - -SDL_AppResult SDL_AppIterate(void* appstate) { - const auto chip8 = static_cast(appstate); - - chip8->iterate(); - - return SDL_APP_CONTINUE; -} - -SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) { - const auto chip8 = static_cast(appstate); - - ImGui_ImplSDL3_ProcessEvent(event); - - if (event->type == SDL_EVENT_QUIT) { - return SDL_APP_SUCCESS; - } - - if (event->type == SDL_EVENT_KEY_DOWN) { - chip8->on_keydown(event->key.scancode); - } - - - return SDL_APP_CONTINUE; -} - -void SDL_AppQuit(void* appstate, SDL_AppResult result) { - const auto chip8 = static_cast(appstate); - delete chip8; -}