1#include "../include/cartridge.hpp"
2#include "../include/success.hpp"
3#include "../include/readROM.hpp"
4#include "../include/ProcessingUnit.hpp"
5#include "../include/interrupt_controller.hpp"
6#include "../include/timer.hpp"
7#include "../include/mmu.hpp"
8#include "../include/ppu.hpp"
13#include <SFML/Graphics.hpp>
19 if (joy.right) direction &= ~0x01;
20 if (joy.left) direction &= ~0x02;
21 if (joy.up) direction &= ~0x04;
22 if (joy.down) direction &= ~0x08;
24 if (joy.a) action &= ~0x01;
25 if (joy.b) action &= ~0x02;
26 if (joy.select) action &= ~0x04;
27 if (joy.start) action &= ~0x08;
29 mmu.set_joypad_state(action, direction);
32int main(
const int argc,
char **argv)
34 bool debug_mode =
false;
35 bool fullscreen_mode =
false;
37 for (
int i = 1; i < argc; ++i) {
38 if (std::strcmp(argv[i],
"--debug") == 0 || std::strcmp(argv[i],
"-d") == 0) {
40 }
else if (std::strcmp(argv[i],
"--fullscreen") == 0 || std::strcmp(argv[i],
"-f") == 0) {
41 fullscreen_mode =
true;
47 if (rom_path.empty()) {
48 std::cerr <<
"Usage: gb_emu <rom_file> [--debug]\n";
53 const std::vector<u8> rom_data = load_rom(rom_path.c_str());
58 MMU mmu(cartridge, ppu, timer, ic);
66 std::memcpy(&header, &rom_data[0x100],
sizeof(
rom_header));
68 std::memcpy(title, header.title, 16);
72 info.type = header.type;
73 info.rom_size = header.rom_size;
74 info.ram_size = header.ram_size;
75 info.rom_bytes = rom_data;
76 ppu.set_rom_info(info);
78 ppu.init_window(debug_mode, title, fullscreen_mode);
79 std::cout <<
"Running in " << (debug_mode ?
"Debug/Feature" :
"Simple") <<
" Mode...\n";
86 while (ppu.isOpen()) {
87 ppu.handleEvents(joypad);
88 update_joypad(mmu, joypad);
90 if (ppu.isResetRequested()) {
93 ppu.clearResetRequest();
96 const float dt = clock.restart().asSeconds();
98 if (!ppu.isPaused()) {
99 const int loops = ppu.isTurbo() ? 2 : 1;
100 for (
int loop = 0; loop < loops; ++loop) {
101 int frame_cycles = 0;
102 static int instr_count = 0;
103 static bool trace_enabled = (std::getenv(
"EMU_TRACE") !=
nullptr);
104 static std::ofstream trace_file;
105 if (trace_enabled && !trace_file.is_open()) {
106 trace_file.open(
"cpu_trace.log");
108 while (!ppu.is_frame_ready() && ((ppu.read(0xFF40) & 0x80) || frame_cycles < 70224)) {
109 const u16 pc_before = cpu.get_pc();
110 const u8 opcode = mmu.read(pc_before);
112 if (trace_enabled && instr_count % 10000 == 0 && instr_count < 1000000) {
113 trace_file <<
"Instr: " << std::dec << instr_count
114 <<
" | PC: 0x" << std::hex << pc_before
115 <<
" | Op: 0x" << (int)opcode
116 <<
" | AF: 0x" << cpu.get_af()
117 <<
" | BC: 0x" << cpu.get_bc()
118 <<
" | DE: 0x" << cpu.get_de()
119 <<
" | HL: 0x" << cpu.get_hl()
120 <<
" | SP: 0x" << cpu.get_sp()
121 <<
" | LY: 0x" << (int)ppu.read(0xFF44)
122 <<
" | Bank: " << (int)mmu.get_current_rom_bank()
128 int used = cpu.step(mmu);
129 cycles +=
static_cast<u64
>(used);
130 frame_cycles += used;
132 mmu.step_timer(used);
134 ppu.recordOpcode(pc_before, opcode);
135 ppu.checkBreakpoint(pc_before);
137 if (ppu.isPaused()) {
141 if (ppu.is_frame_ready()) {
142 ppu.clear_frame_ready();
146 char* frame_limit_env = std::getenv(
"EMU_FRAME_LIMIT");
147 int limit = frame_limit_env ? std::atoi(frame_limit_env) : -1;
148 if (limit > 0 && frame_count >= limit) {
149 std::cout <<
"Reached frame limit of " << limit <<
", exiting cleanly.\n";
153 if (ppu.isStepRequested()) {
154 const u16 pc_before = cpu.get_pc();
155 const u8 opcode = mmu.read(pc_before);
157 int used = cpu.step(mmu);
158 cycles +=
static_cast<u64
>(used);
160 mmu.step_timer(used);
162 ppu.recordOpcode(pc_before, opcode);
163 ppu.checkBreakpoint(pc_before);
165 ppu.clearStepRequest();
169 ppu.update(dt, cycles);
173 if (std::getenv(
"EMU_SAVE_PNG") !=
nullptr) {
174 sf::Image img({160, 144},
reinterpret_cast<const uint8_t*
>(ppu.get_framebuffer()));
175 (void)img.saveToFile(
"framebuffer.png");
176 std::cout <<
"Saved framebuffer.png\n";
179 std::cout << std::dec <<
"\n" << cycles <<
" cycles executed" << std::endl;
180 }
catch (
const std::exception &e) {
181 std::cerr <<
"Error: " << e.what() << std::endl;