134 lines
5.0 KiB
C++
134 lines
5.0 KiB
C++
#include "Chip8.h"
|
|
|
|
#include <filesystem>
|
|
#include <format>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
|
|
#include "bitops.h"
|
|
|
|
Chip8::Chip8(): machine_state{std::make_shared<MachineState>()},
|
|
graphics{machine_state},
|
|
interpreter{machine_state, 0},
|
|
target_cycle_time{1.0 / 700.0},
|
|
last_update_time{0},
|
|
accumulator{0},
|
|
run{false},
|
|
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<const bool> keyboard_state) {
|
|
this->keyboard_state = keyboard_state;
|
|
}
|
|
|
|
std::vector<uint8_t> 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<std::uint8_t> rom(file_size);
|
|
|
|
rom.insert(
|
|
rom.begin(),
|
|
std::istreambuf_iterator<char>(rom_file),
|
|
std::istreambuf_iterator<char>()
|
|
);
|
|
|
|
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::update() {
|
|
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<double>(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;
|
|
}
|
|
}
|