diff --git a/.gitignore b/.gitignore
index b1aff46..5917506 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,4 +13,4 @@ _deps
CMakeUserPresets.json
cmake-build-debug
imgui.ini
-
+cmake-build*/
\ No newline at end of file
diff --git a/.idea/dictionaries/project.xml b/.idea/dictionaries/project.xml
new file mode 100644
index 0000000..3a18f12
--- /dev/null
+++ b/.idea/dictionaries/project.xml
@@ -0,0 +1,8 @@
+
+
+
+ cosmac
+ skrd
+
+
+
\ No newline at end of file
diff --git a/.idea/editor.xml b/.idea/editor.xml
index 2d5e37e..7729b27 100644
--- a/.idea/editor.xml
+++ b/.idea/editor.xml
@@ -112,7 +112,7 @@
-
+
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..511dd31
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index fe44e63..b6372e6 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -13,4 +13,5 @@
+
\ No newline at end of file
diff --git a/src/Graphics/Chip8Display.cpp b/src/Graphics/Chip8Display.cpp
index c3d669b..2dce3fd 100644
--- a/src/Graphics/Chip8Display.cpp
+++ b/src/Graphics/Chip8Display.cpp
@@ -1,5 +1,6 @@
#include "Chip8Display.h"
+#include
#include
#include
#include
@@ -12,15 +13,21 @@ void SDLTextureDestroyer::operator()(SDL_Texture* texture) const {
SDL_DestroyTexture(texture);
}
-Chip8Display::Chip8Display(std::shared_ptr machine_state, SDL_Renderer& renderer):
+Chip8Display::Chip8Display(std::shared_ptr machine_state, std::shared_ptr renderer):
machine_state{std::move(machine_state)},
- renderer{renderer},
+ renderer{std::move(renderer)},
width(64),
- height(32) {
+ height(32),
+ background_color{0x00, 0x2b, 0x59},
+ foreground_color(0x00, 0xb9, 0xbe) {
+ SDL_Texture* raw_texture = SDL_CreateTexture(this->renderer.get(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, width, height);
+
+ if (!raw_texture) {
+ throw std::runtime_error(std::format("Couldn't create texture: {}", SDL_GetError()));
+ }
- SDL_Texture* raw_texture = SDL_CreateTexture(&renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, width, height);
this->texture = std::unique_ptr(raw_texture);
- SDL_SetTextureScaleMode(texture.get(), SDL_SCALEMODE_LINEAR);
+ SDL_SetTextureScaleMode(this->texture.get(), SDL_SCALEMODE_NEAREST);
}
void Chip8Display::render() const {
@@ -28,36 +35,45 @@ void Chip8Display::render() const {
display_widget();
}
-void Chip8Display::update() const {
-}
+void Chip8Display::update() const {}
void Chip8Display::update_texture() const {
SDL_Surface* surface = nullptr;
const 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));
+ if (SDL_LockTextureToSurface(this->texture.get(), nullptr, &surface)) {
+ SDL_FillSurfaceRect(
+ surface,
+ nullptr,
+ SDL_MapRGB(
+ SDL_GetPixelFormatDetails(surface->format),
+ nullptr,
+ this->background_color.r,
+ this->background_color.g,
+ this->background_color.b
+ )
+ );
for (int i = 0; i < display.size(); i++) {
if (display[i]) {
- const int x = (i % width);
- const int y = (i / width);
+ const int x = (i % this->width);
+ const int y = (i / this->width);
SDL_Rect rect = {x, y, 1, 1};
- Uint32 color = SDL_MapRGB(
+ const Uint32 color = SDL_MapRGB(
SDL_GetPixelFormatDetails(surface->format),
nullptr,
- 0,
- 255,
- 0
+ this->foreground_color.r,
+ this->foreground_color.g,
+ this->foreground_color.b
);
SDL_FillSurfaceRect(surface, &rect, color);
}
}
- SDL_UnlockTexture(texture.get());
+ SDL_UnlockTexture(this->texture.get());
} else {
- SDL_Log("Failed to lock texture: %s", SDL_GetError());
+ throw std::runtime_error(std::format("Couldn't get texture lock onto surface: {}", SDL_GetError()));
}
}
@@ -66,15 +82,15 @@ void Chip8Display::display_widget() const {
const ImVec2 available_size = ImGui::GetContentRegionAvail();
- const int scale_x = static_cast(static_cast(available_size.x) / static_cast(width));
- const int scale_y = static_cast(static_cast(available_size.y) / static_cast(height));
+ const int scale_x = static_cast(static_cast(available_size.x) / static_cast(this->width));
+ const int scale_y = static_cast(static_cast(available_size.y) / static_cast(this->height));
const int scale = std::max(1, std::min(scale_x, scale_y));
- const ImVec2 scaled_size(static_cast(width * scale), static_cast(height * scale));
+ const ImVec2 scaled_size(static_cast(this->width * scale), static_cast(this->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((ImTextureID)((intptr_t)texture.get()), scaled_size);
+ ImGui::Image(static_cast(reinterpret_cast(texture.get())), scaled_size);
ImGui::End();
}
diff --git a/src/Graphics/Chip8Display.h b/src/Graphics/Chip8Display.h
index ae04fed..7ec1f57 100644
--- a/src/Graphics/Chip8Display.h
+++ b/src/Graphics/Chip8Display.h
@@ -2,6 +2,7 @@
#define CHIP8DISPLAY_H
#include
+#include "Color.h"
#include "../Interpreter/MachineState.h"
#include "SDL3/SDL.h"
@@ -11,11 +12,14 @@ struct SDLTextureDestroyer {
class Chip8Display {
std::shared_ptr machine_state;
- SDL_Renderer& renderer;
+ std::shared_ptr renderer;
int width;
int height;
+ Color background_color;
+ Color foreground_color;
+
std::unique_ptr texture;
void update_texture() const;
@@ -24,7 +28,7 @@ class Chip8Display {
public:
Chip8Display(
std::shared_ptr machine_state,
- SDL_Renderer& renderer
+ std::shared_ptr renderer
);
void update() const;
diff --git a/src/Graphics/Color.h b/src/Graphics/Color.h
new file mode 100644
index 0000000..fb5d5f8
--- /dev/null
+++ b/src/Graphics/Color.h
@@ -0,0 +1,13 @@
+#ifndef COLOR_H
+#define COLOR_H
+#include
+
+struct Color {
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+
+ Color(const uint8_t r, const uint8_t g, const uint8_t b) : r(r), g(g), b(b) {}
+};
+
+#endif //COLOR_H
diff --git a/src/Graphics/Graphics.cpp b/src/Graphics/Graphics.cpp
index 832419d..d4745fd 100644
--- a/src/Graphics/Graphics.cpp
+++ b/src/Graphics/Graphics.cpp
@@ -1,6 +1,8 @@
#include "Graphics.h"
+#include
#include
+#include
#include "imgui.h"
#include "imgui_impl_sdl3.h"
@@ -10,11 +12,7 @@ void SDLWindowDestroyer::operator()(SDL_Window* window) const {
SDL_DestroyWindow(window);
}
-void SDLRendererDestroyer::operator()(SDL_Renderer* renderer) const {
- SDL_DestroyRenderer(renderer);
-}
-
-Graphics::Graphics(): window_width{1920}, window_height{1080}, main_scale{1.0f} {
+Graphics::Graphics(): window_width{1366}, window_height{768}, main_scale{1.0f} {
create_sdl();
create_imgui();
}
@@ -29,13 +27,13 @@ void Graphics::create_sdl() {
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;
+ this->main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay());
+ constexpr 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,
+ std::floor(static_cast(this->window_width) * main_scale),
+ std::floor(static_cast(this->window_height) * main_scale),
window_flags,
&raw_window,
&raw_renderer
@@ -43,15 +41,15 @@ void Graphics::create_sdl() {
throw std::runtime_error(std::format("Couldn't create window/renderer: {}", SDL_GetError()));
}
- window = std::unique_ptr(raw_window);
- renderer = std::unique_ptr(raw_renderer);
+ this->window = std::unique_ptr(raw_window);
+ this->renderer = std::shared_ptr(raw_renderer, SDL_DestroyRenderer);
- SDL_SetRenderVSync(renderer.get(), 1);
- SDL_SetWindowPosition(window.get(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
- SDL_ShowWindow(window.get());
+ SDL_SetRenderVSync(this->renderer.get(), 1);
+ SDL_SetWindowPosition(this->window.get(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
+ SDL_ShowWindow(this->window.get());
}
-void Graphics::create_imgui() {
+void Graphics::create_imgui() const {
IMGUI_CHECKVERSION();
ImGui::CreateContext();
@@ -61,37 +59,32 @@ void Graphics::create_imgui() {
ImGui::StyleColorsDark();
ImGuiStyle& style = ImGui::GetStyle();
- style.ScaleAllSizes(main_scale);
- style.FontScaleDpi = main_scale;
+ style.ScaleAllSizes(this->main_scale);
+ style.FontScaleDpi = this->main_scale;
- ImGui_ImplSDL3_InitForSDLRenderer(window.get(), renderer.get());
- ImGui_ImplSDLRenderer3_Init(renderer.get());
+ ImGui_ImplSDL3_InitForSDLRenderer(this->window.get(), this->renderer.get());
+ ImGui_ImplSDLRenderer3_Init(this->renderer.get());
}
-SDL_Renderer& Graphics::get_renderer() {
- return *renderer;
+std::shared_ptr Graphics::get_renderer() {
+ return this->renderer;
}
-
-void Graphics::start_render() {
- if (SDL_GetWindowFlags(window.get()) & SDL_WINDOW_MINIMIZED) {
- SDL_Delay(10);
- }
-
+void Graphics::start_render() const {
ImGui_ImplSDLRenderer3_NewFrame();
ImGui_ImplSDL3_NewFrame();
ImGui::NewFrame();
ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport());
}
-void Graphics::end_render() {
- ImGuiIO& io = ImGui::GetIO();
+void Graphics::end_render() const {
+ const ImGuiIO& io = ImGui::GetIO();
ImGui::Render();
- SDL_SetRenderScale(renderer.get(), io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
- SDL_SetRenderDrawColor(renderer.get(), 0, 0, 0, 0xFF);
- SDL_RenderClear(renderer.get());
+ SDL_SetRenderScale(this->renderer.get(), io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
+ SDL_SetRenderDrawColor(this->renderer.get(), 0, 0, 0, 0xFF);
+ SDL_RenderClear(this->renderer.get());
- ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), renderer.get());
- SDL_RenderPresent(renderer.get());
+ ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), this->renderer.get());
+ SDL_RenderPresent(this->renderer.get());
}
diff --git a/src/Graphics/Graphics.h b/src/Graphics/Graphics.h
index 68af503..48a1545 100644
--- a/src/Graphics/Graphics.h
+++ b/src/Graphics/Graphics.h
@@ -2,34 +2,28 @@
#define GRAPHICS_H
#include
-
-#include "Chip8Display.h"
#include "SDL3/SDL.h"
struct SDLWindowDestroyer {
void operator()(SDL_Window* window) const;
};
-struct SDLRendererDestroyer {
- void operator()(SDL_Renderer* renderer) const;
-};
-
class Graphics {
int window_width;
int window_height;
float main_scale;
std::unique_ptr window;
- std::unique_ptr renderer;
+ std::shared_ptr renderer;
void create_sdl();
- void create_imgui();
+ void create_imgui() const;
public:
Graphics();
- void start_render();
- void end_render();
- SDL_Renderer& get_renderer();
+ void start_render() const;
+ void end_render() const;
+ std::shared_ptr get_renderer();
};
#endif //GRAPHICS_H
diff --git a/src/Interpreter/Interpreter.cpp b/src/Interpreter/Interpreter.cpp
index d012158..ff94886 100644
--- a/src/Interpreter/Interpreter.cpp
+++ b/src/Interpreter/Interpreter.cpp
@@ -5,24 +5,29 @@
Interpreter::Interpreter(std::shared_ptr machine_state):
machine_state{std::move(machine_state)},
- random_generator{std::random_device{}()} {}
-
-void Interpreter::tick() {
- 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 auto instruction = decode(word);
- machine_state->pc += 2;
- execute_instruction(instruction);
-
- if (machine_state->pc >= 0xFFF) {
- std::cout << "PC Outside of memory, going back 0x200" << std::endl;
- machine_state->pc = 0x200;
+ random_generator{std::random_device{}()} {
+ srand(time(nullptr));
+ for (bool& display : this->machine_state->display) {
+ display = rand() % 100 > 50;
}
}
-Instruction Interpreter::decode(const uint16_t word) {
+void Interpreter::tick() {
+ const uint8_t high_word = this->machine_state->memory[this->machine_state->pc];
+ const uint8_t low_word = this->machine_state->memory[this->machine_state->pc + 1];
+ const uint16_t word = high_word << 8 | low_word;
+
+ const auto instruction = this->decode(word);
+ this->machine_state->pc += 2;
+ this->execute_instruction(instruction);
+
+ if (this->machine_state->pc >= 0xFFF) {
+ std::cout << "PC Outside of memory, going back 0x200" << std::endl;
+ this->machine_state->pc = 0x200;
+ }
+}
+
+Instruction Interpreter::decode(const uint16_t word) const {
const uint8_t operation = (word & 0xF000) >> 12;
const uint8_t x = (word & 0x0F00) >> 8;
const uint8_t y = (word & 0x00F0) >> 4;
@@ -125,118 +130,117 @@ Instruction Interpreter::decode(const uint16_t word) {
}
void Interpreter::execute_instruction(const Instruction& instruction) {
- if (instruction.op_code == OpCode::CLS) cls();
- else if (instruction.op_code == OpCode::RET) ret();
- else if (instruction.op_code == OpCode::SYS_ADDR) sys_addr();
- 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();
+ if (instruction.op_code == OpCode::CLS) this->cls();
+ else if (instruction.op_code == OpCode::RET) this->ret();
+ else if (instruction.op_code == OpCode::SYS_ADDR) this->sys_addr();
+ else if (instruction.op_code == OpCode::JP_ADDR) this->jp_addr(instruction);
+ else if (instruction.op_code == OpCode::CALL_ADDR) this->call_addr(instruction);
+ else if (instruction.op_code == OpCode::SE_VX_BYTE) this->se_vx_byte(instruction);
+ else if (instruction.op_code == OpCode::SNE_VX_BYTE) this->sne_vx_byte(instruction);
+ else if (instruction.op_code == OpCode::SE_VX_VY) this->se_vx_vy(instruction);
+ else if (instruction.op_code == OpCode::LD_VX_BYTE) this->ld_vx_byte(instruction);
+ else if (instruction.op_code == OpCode::ADD_VX_BYTE) this->add_vx_byte(instruction);
+ else if (instruction.op_code == OpCode::LD_VX_VY) this->ld_vx_vy(instruction);
+ else if (instruction.op_code == OpCode::OR_VX_VY) this->or_vx_vy(instruction);
+ else if (instruction.op_code == OpCode::AND_VX_VY) this->and_vx_vy(instruction);
+ else if (instruction.op_code == OpCode::XOR_VX_VY) this->xor_vx_vy(instruction);
+ else if (instruction.op_code == OpCode::ADD_VX_VY) this->add_vx_vy(instruction);
+ else if (instruction.op_code == OpCode::SUB_VX_VY) this->sub_vx_vy(instruction);
+ else if (instruction.op_code == OpCode::SHR_VX_VY) this->shr_vx_vy(instruction);
+ else if (instruction.op_code == OpCode::SUBN_VX_VY) this->subn_vx_vy(instruction);
+ else if (instruction.op_code == OpCode::SHL_VX_VY) this->shl_vx_vy(instruction);
+ else if (instruction.op_code == OpCode::SNE_VX_VY) this->sne_vx_vy(instruction);
+ else if (instruction.op_code == OpCode::LD_I_ADDR) this->ld_i_addr(instruction);
+ else if (instruction.op_code == OpCode::JP_V0_ADDR) this->jp_v0_addr(instruction);
+ else if (instruction.op_code == OpCode::RND_VX_BYTE) this->rnd_vx_byte(instruction);
+ else if (instruction.op_code == OpCode::DRW_VX_VY_NIBBLE) this->drw_vx_vy_nibble(instruction);
+ else if (instruction.op_code == OpCode::SKP_VX) this->skp_vx(instruction);
+ else if (instruction.op_code == OpCode::SKNP_VX) this->sknp_vx(instruction);
+ else if (instruction.op_code == OpCode::LD_VX_DT) this->ld_vx_dt(instruction);
+ else if (instruction.op_code == OpCode::LD_VX_K) this->ld_vx_k(instruction);
+ else if (instruction.op_code == OpCode::LD_DT_VX) this->ld_dt_vx(instruction);
+ else if (instruction.op_code == OpCode::LD_ST_VX) this->ld_st_vx(instruction);
+ else if (instruction.op_code == OpCode::ADD_I_VX) this->add_i_vx(instruction);
+ else if (instruction.op_code == OpCode::LD_F_VX) this->ld_f_vx(instruction);
+ else if (instruction.op_code == OpCode::LD_B_VX) this->ld_b_vx(instruction);
+ else if (instruction.op_code == OpCode::LD_I_VX) this->ld_i_vx(instruction);
+ else if (instruction.op_code == OpCode::LD_VX_I) this->ld_vx_i(instruction);
+ else if (instruction.op_code == OpCode::NOP) this->nop();
}
-
-void Interpreter::sys_addr() {
+void Interpreter::sys_addr() const {
// NOP
}
-void Interpreter::nop() {
+void Interpreter::nop() const {
// NOP
}
void Interpreter::cls() const {
- machine_state->display.fill(false);
+ this->machine_state->display.fill(false);
}
void Interpreter::ret() const {
- machine_state->sp -= 1;
- machine_state->pc = machine_state->stack[machine_state->sp];
+ this->machine_state->sp -= 1;
+ this->machine_state->pc = this->machine_state->stack[this->machine_state->sp];
}
void Interpreter::jp_addr(const Instruction& instruction) const {
- machine_state->pc = instruction.nnn;
+ this->machine_state->pc = instruction.nnn;
}
void Interpreter::call_addr(const Instruction& instruction) const {
- machine_state->stack[machine_state->sp] = machine_state->pc;
- machine_state->sp += 1;
- machine_state->pc = instruction.nnn;
+ this->machine_state->stack[this->machine_state->sp] = this->machine_state->pc;
+ this->machine_state->sp += 1;
+ this->machine_state->pc = instruction.nnn;
}
void Interpreter::se_vx_byte(const Instruction& instruction) const {
- if (machine_state->v[instruction.x] == instruction.kk) {
- machine_state->pc += 2;
+ if (this->machine_state->v[instruction.x] == instruction.kk) {
+ this->machine_state->pc += 2;
}
}
void Interpreter::sne_vx_byte(const Instruction& instruction) const {
- if (machine_state->v[instruction.x] != instruction.kk) {
- machine_state->pc += 2;
+ if (this->machine_state->v[instruction.x] != instruction.kk) {
+ this->machine_state->pc += 2;
}
}
void Interpreter::se_vx_vy(const Instruction& instruction) const {
- if (machine_state->v[instruction.x] == machine_state->v[instruction.y]) {
- machine_state->pc += 2;
+ if (this->machine_state->v[instruction.x] == this->machine_state->v[instruction.y]) {
+ this->machine_state->pc += 2;
}
}
void Interpreter::ld_vx_byte(const Instruction& instruction) const {
- machine_state->v[instruction.x] = instruction.kk;
+ this->machine_state->v[instruction.x] = instruction.kk;
}
void Interpreter::add_vx_byte(const Instruction& instruction) const {
- machine_state->v[instruction.x] += instruction.kk;
+ this->machine_state->v[instruction.x] += instruction.kk;
}
void Interpreter::ld_vx_vy(const Instruction& instruction) const {
- machine_state->v[instruction.x] = machine_state->v[instruction.y];
+ this->machine_state->v[instruction.x] = this->machine_state->v[instruction.y];
}
void Interpreter::or_vx_vy(const Instruction& instruction) const {
- machine_state->v[instruction.x] |= machine_state->v[instruction.y];
+ this->machine_state->v[instruction.x] |= this->machine_state->v[instruction.y];
}
void Interpreter::and_vx_vy(const Instruction& instruction) const {
- machine_state->v[instruction.x] &= machine_state->v[instruction.y];
+ this->machine_state->v[instruction.x] &= this->machine_state->v[instruction.y];
}
void Interpreter::xor_vx_vy(const Instruction& instruction) const {
- machine_state->v[instruction.x] ^= machine_state->v[instruction.y];
+ this->machine_state->v[instruction.x] ^= this->machine_state->v[instruction.y];
}
void Interpreter::add_vx_vy(const Instruction& instruction) const {
- auto& vx = machine_state->v[instruction.x];
- const auto& vy = machine_state->v[instruction.y];
- auto& vf = machine_state->v[0xF];
+ auto& vx = this->machine_state->v[instruction.x];
+ const auto& vy = this->machine_state->v[instruction.y];
+ auto& vf = this->machine_state->v[0xF];
if (vx + vy > 0xFF) {
vf = 1;
@@ -248,9 +252,9 @@ void Interpreter::add_vx_vy(const Instruction& instruction) const {
}
void Interpreter::sub_vx_vy(const Instruction& instruction) const {
- auto& vx = machine_state->v[instruction.x];
- const auto& vy = machine_state->v[instruction.y];
- auto& vf = machine_state->v[0xF];
+ auto& vx = this->machine_state->v[instruction.x];
+ const auto& vy = this->machine_state->v[instruction.y];
+ auto& vf = this->machine_state->v[0xF];
if (vx > vy) {
vf = 1;
@@ -262,9 +266,9 @@ void Interpreter::sub_vx_vy(const Instruction& instruction) const {
}
void Interpreter::shr_vx_vy(const Instruction& instruction) const {
- auto& vx = machine_state->v[instruction.x];
- const auto& vy = machine_state->v[instruction.y];
- auto& vf = machine_state->v[0xF];
+ auto& vx = this->machine_state->v[instruction.x];
+ const auto& vy = this->machine_state->v[instruction.y];
+ auto& vf = this->machine_state->v[0xF];
if (quirks & static_cast(InterpreterQuirks::COSMAC_SHIFT)) {
vx = vy;
@@ -280,9 +284,9 @@ void Interpreter::shr_vx_vy(const Instruction& instruction) const {
}
void Interpreter::subn_vx_vy(const Instruction& instruction) const {
- auto& vx = machine_state->v[instruction.x];
- const auto& vy = machine_state->v[instruction.y];
- auto& vf = machine_state->v[0xF];
+ auto& vx = this->machine_state->v[instruction.x];
+ const auto& vy = this->machine_state->v[instruction.y];
+ auto& vf = this->machine_state->v[0xF];
if (vy > vx) {
vf = 1;
@@ -294,11 +298,11 @@ void Interpreter::subn_vx_vy(const Instruction& instruction) const {
}
void Interpreter::shl_vx_vy(const Instruction& instruction) const {
- auto& vx = machine_state->v[instruction.x];
- const auto& vy = machine_state->v[instruction.y];
- auto& vf = machine_state->v[0xF];
+ auto& vx = this->machine_state->v[instruction.x];
+ const auto& vy = this->machine_state->v[instruction.y];
+ auto& vf = this->machine_state->v[0xF];
- if (quirks & static_cast(InterpreterQuirks::COSMAC_SHIFT)) {
+ if (this->quirks & static_cast(InterpreterQuirks::COSMAC_SHIFT)) {
vx = vy;
}
@@ -312,36 +316,37 @@ void Interpreter::shl_vx_vy(const Instruction& instruction) const {
}
void Interpreter::sne_vx_vy(const Instruction& instruction) const {
- if (machine_state->v[instruction.x] != machine_state->v[instruction.y]) {
- machine_state->pc += 2;
+ if (this->machine_state->v[instruction.x] != this->machine_state->v[instruction.y]) {
+ this->machine_state->pc += 2;
}
}
void Interpreter::ld_i_addr(const Instruction& instruction) const {
- machine_state->i = instruction.nnn;
+ this->machine_state->i = instruction.nnn;
}
void Interpreter::jp_v0_addr(const Instruction& instruction) const {
- if (quirks & static_cast(InterpreterQuirks::SUPER_CHIP_JUMP)) {
- machine_state->pc = instruction.nnn + machine_state->v[instruction.x];
+ if (this->quirks & static_cast(InterpreterQuirks::SUPER_CHIP_JUMP)) {
+ this->machine_state->pc = instruction.nnn + this->machine_state->v[instruction.x];
} else {
- machine_state->pc = instruction.nnn + machine_state->v[0];
+ this->machine_state->pc = instruction.nnn + this->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);
+ auto distribution = std::uniform_int_distribution(0, 0xFF);
+ const auto value = distribution(this->random_generator);
- machine_state->v[instruction.x] = value & instruction.kk;
+ this->machine_state->v[instruction.x] = value & instruction.kk;
}
void Interpreter::drw_vx_vy_nibble(const Instruction& instruction) const {
- const auto& memory = machine_state->memory;
- auto& display = machine_state->display;
- const auto& vx = machine_state->v[instruction.x];
- const auto& vy = machine_state->v[instruction.y];
- auto& vf = machine_state->v[0xF];
+ const auto& memory = this->machine_state->memory;
+ auto& display = this->machine_state->display;
+ const auto& vx = this->machine_state->v[instruction.x];
+ const auto& vy = this->machine_state->v[instruction.y];
+ auto& vf = this->machine_state->v[0xF];
+ auto& i = this->machine_state->i;
const uint8_t start_x = vx & 63;
const uint8_t start_y = vy & 31;
@@ -354,7 +359,7 @@ void Interpreter::drw_vx_vy_nibble(const Instruction& instruction) const {
break;
}
- const auto sprite_byte = memory[machine_state->i + row];
+ const auto sprite_byte = memory[i + row];
for (auto bit = 0; bit < 8; bit++) {
const auto current_x = start_x + bit;
@@ -379,80 +384,80 @@ void Interpreter::drw_vx_vy_nibble(const Instruction& instruction) const {
}
void Interpreter::skp_vx(const Instruction& instruction) const {
- if (machine_state->keyboard & 1 << instruction.x) {
- machine_state->pc += 2;
+ if (this->machine_state->keyboard & 1 << instruction.x) {
+ this->machine_state->pc += 2;
}
}
void Interpreter::sknp_vx(const Instruction& instruction) const {
- if (!(machine_state->keyboard & 1 << instruction.x)) {
- machine_state->pc += 2;
+ if (!(this->machine_state->keyboard & 1 << instruction.x)) {
+ this->machine_state->pc += 2;
}
}
void Interpreter::ld_vx_dt(const Instruction& instruction) const {
- machine_state->v[instruction.x] = machine_state->dt;
+ this->machine_state->v[instruction.x] = this->machine_state->dt;
}
void Interpreter::ld_vx_k(const Instruction& instruction) const {
- if (machine_state->keyboard == 0) {
- machine_state->pc -= 2;
+ if (this->machine_state->keyboard == 0) {
+ this->machine_state->pc -= 2;
return;
}
for (auto key = 0; key < 16; key++) {
- if (machine_state->keyboard & 1 << key) {
- machine_state->v[instruction.x] = key;
+ if (this->machine_state->keyboard & 1 << key) {
+ this->machine_state->v[instruction.x] = key;
break;
}
}
}
void Interpreter::ld_dt_vx(const Instruction& instruction) const {
- machine_state->dt = machine_state->v[instruction.x];
+ this->machine_state->dt = this->machine_state->v[instruction.x];
}
void Interpreter::ld_st_vx(const Instruction& instruction) const {
- machine_state->st = machine_state->v[instruction.x];
+ this->machine_state->st = this->machine_state->v[instruction.x];
}
void Interpreter::add_i_vx(const Instruction& instruction) const {
- machine_state->i += machine_state->v[instruction.x];
+ this->machine_state->i += this->machine_state->v[instruction.x];
}
void Interpreter::ld_f_vx(const Instruction& instruction) const {
- machine_state->i = (machine_state->v[instruction.x] & 0xF) * 5 + 0x50;
+ this->machine_state->i = (this->machine_state->v[instruction.x] & 0xF) * 5 + 0x50;
}
void Interpreter::ld_b_vx(const Instruction& instruction) const {
- 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;
+ const auto number = this->machine_state->v[instruction.x];
+ this->machine_state->memory[this->machine_state->i] = number / 100;
+ this->machine_state->memory[this->machine_state->i + 1] = (number - this->machine_state->memory[this->machine_state->i] * 100) / 10;
+ this->machine_state->memory[this->machine_state->i + 2] = number - this->machine_state->memory[this->machine_state->i] * 100 - this->machine_state->memory[this->machine_state->i + 1] * 10;
}
void Interpreter::ld_i_vx(const Instruction& instruction) const {
- const bool use_quirk = quirks & static_cast(InterpreterQuirks::COSMAC_STORE_AND_LOAD);
+ const bool use_quirk = this->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++;
+ this->machine_state->memory[this->machine_state->i] = this->machine_state->v[reg];
+ this->machine_state->i++;
} else {
- machine_state->memory[machine_state->i + reg] = machine_state->v[reg];
+ this->machine_state->memory[this->machine_state->i + reg] = this->machine_state->v[reg];
}
}
}
void Interpreter::ld_vx_i(const Instruction& instruction) const {
- const bool use_quirk = quirks & static_cast(InterpreterQuirks::COSMAC_STORE_AND_LOAD);
+ const bool use_quirk = this->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++;
+ this->machine_state->v[reg] = this->machine_state->memory[this->machine_state->i];
+ this->machine_state->i++;
} else {
- machine_state->v[reg] = machine_state->memory[machine_state->i + reg];
+ this->machine_state->v[reg] = this->machine_state->memory[this->machine_state->i + reg];
}
}
}
diff --git a/src/Interpreter/Interpreter.h b/src/Interpreter/Interpreter.h
index e8b62b5..b2b436a 100644
--- a/src/Interpreter/Interpreter.h
+++ b/src/Interpreter/Interpreter.h
@@ -8,8 +8,8 @@
#include "MachineState.h"
enum class InterpreterQuirks {
- COSMAC_SHIFT = 1 << 0,
- SUPER_CHIP_JUMP = 1 << 1,
+ COSMAC_SHIFT = 1 << 0,
+ SUPER_CHIP_JUMP = 1 << 1,
COSMAC_STORE_AND_LOAD = 1 << 2,
};
@@ -19,11 +19,11 @@ class Interpreter {
uint8_t quirks = 0;
- static Instruction decode(uint16_t word);
+ Instruction decode(uint16_t word) const;
void execute_instruction(const Instruction& instruction);
- static void sys_addr();
- static void nop();
+ void sys_addr() const;
+ void nop() const;
void cls() const;
void ret() const;
void jp_addr(const Instruction& instruction) const;
@@ -66,5 +66,4 @@ public:
};
-
#endif //INTERPRETER_H
diff --git a/src/Machine.cpp b/src/Machine.cpp
index 2bb57a2..0f8486d 100644
--- a/src/Machine.cpp
+++ b/src/Machine.cpp
@@ -13,17 +13,15 @@ Machine::Machine():
accumulator{0} {}
void Machine::iterate() {
- execute_interpreter();
-
- chip8_display->update();
-
- graphics->start_render();
+ this->execute_interpreter();
+ this->chip8_display->update();
+ this->graphics->start_render();
ImGui::ShowDemoWindow();
- chip8_display->render();
- graphics->end_render();
+ this->chip8_display->render();
+ this->graphics->end_render();
}
-bool Machine::on_event(const SDL_Event* event) {
+bool Machine::on_event(const SDL_Event* event) const {
ImGui_ImplSDL3_ProcessEvent(event);
if (event->type == SDL_EVENT_QUIT) {
@@ -34,15 +32,15 @@ bool Machine::on_event(const SDL_Event* event) {
}
void Machine::execute_interpreter() {
- const auto target_cycle_time = 1.0 / ips;
+ const auto target_cycle_time = 1.0 / this->ips;
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;
+ const auto delta_time = static_cast(current_time - this->last_update_time) / 1000.0;
+ this->last_update_time = current_time;
+ this->accumulator += delta_time;
// ReSharper disable once CppDFALoopConditionNotUpdated
- while (accumulator >= target_cycle_time) {
- interpreter->tick();
- accumulator -= target_cycle_time;
+ while (this->accumulator >= target_cycle_time) {
+ this->interpreter->tick();
+ this->accumulator -= target_cycle_time;
}
}
diff --git a/src/Machine.h b/src/Machine.h
index 0badf18..ed386a8 100644
--- a/src/Machine.h
+++ b/src/Machine.h
@@ -10,6 +10,7 @@ class Machine {
std::shared_ptr machine_state;
std::unique_ptr interpreter;
std::unique_ptr graphics;
+
std::unique_ptr chip8_display;
int ips;
@@ -21,7 +22,7 @@ void execute_interpreter();
public:
Machine();
void iterate();
- static bool on_event(const SDL_Event* event);
+ bool on_event(const SDL_Event* event) const;
};
#endif //MACHINE_H
diff --git a/src/old/MachineState.h b/src/old/MachineState.h
new file mode 100644
index 0000000..1aeebce
--- /dev/null
+++ b/src/old/MachineState.h
@@ -0,0 +1,19 @@
+#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/main.cpp b/src/old/main.cpp
new file mode 100644
index 0000000..303cf6b
--- /dev/null
+++ b/src/old/main.cpp
@@ -0,0 +1,51 @@
+#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;
+}