37 absl::Status
Init(
const std::string& rom_path) {
39 if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_EVENTS) < 0) {
40 return absl::InternalError(
41 absl::StrCat(
"SDL_Init failed: ", SDL_GetError()));
46 FILE* file = fopen(rom_path.c_str(),
"rb");
48 return absl::NotFoundError(
49 absl::StrCat(
"Failed to open ROM: ", rom_path));
52 fseek(file, 0, SEEK_END);
53 size_t size = ftell(file);
54 fseek(file, 0, SEEK_SET);
57 if (fread(
rom_data_.data(), 1, size, file) != size) {
59 return absl::InternalError(
"Failed to read ROM data");
63 printf(
"Loaded ROM: %zu bytes\n", size);
66 snes_ = std::make_unique<Snes>();
70 printf(
"SNES initialized and reset\n");
71 printf(
"APU PC after reset: $%04X\n",
snes_->apu().spc700().PC);
72 printf(
"APU cycles: %llu\n",
snes_->apu().GetCycles());
74 return absl::OkStatus();
77 absl::Status
RunFrames(
int max_frames,
int log_interval) {
79 bool infinite = (max_frames == 0);
81 printf(
"Starting emulation (max_frames=%d, log_interval=%d)\n", max_frames,
84 while (infinite || frame < max_frames) {
90 if (log_interval > 0 && frame % log_interval == 0) {
96 while (SDL_PollEvent(&event)) {
97 if (event.type == SDL_QUIT) {
98 printf(
"SDL_QUIT received, stopping emulation\n");
99 return absl::OkStatus();
104 if (frame % 60 == 0) {
105 uint16_t current_pc =
snes_->apu().spc700().PC;
106 if (current_pc ==
last_pc_ && frame > 60) {
109 fprintf(stderr,
"ERROR: APU stuck at PC=$%04X for %d frames\n",
112 "ERROR: This likely indicates a hang or infinite loop\n");
113 return absl::InternalError(
"APU stuck in infinite loop");
121 uint8_t game_module =
snes_->get_ram()[0x10];
122 uint8_t submodule =
snes_->get_ram()[0x11];
123 static uint8_t last_module = 0xFF;
124 static uint8_t last_submodule = 0xFF;
125 if (game_module != last_module || submodule != last_submodule) {
126 printf(
"[GAME] Frame %d: Module 0x%02X -> 0x%02X, Sub 0x%02X -> 0x%02X\n",
127 frame, last_module, game_module, last_submodule, submodule);
128 last_module = game_module;
129 last_submodule = submodule;
134 printf(
"Emulation complete: %d frames\n", frame);
135 return absl::OkStatus();
140 auto& apu =
snes_->apu();
141 auto& spc = apu.spc700();
142 auto& tracker =
snes_->apu_handshake_tracker();
144 printf(
"=== Frame %d APU State ===\n", frame);
145 printf(
" SPC700 PC: $%04X\n", spc.PC);
146 printf(
" SPC700 A: $%02X\n", spc.A);
147 printf(
" SPC700 X: $%02X\n", spc.X);
148 printf(
" SPC700 Y: $%02X\n", spc.Y);
149 printf(
" SPC700 SP: $%02X\n", spc.SP);
150 printf(
" SPC700 PSW: N=%d V=%d P=%d B=%d H=%d I=%d Z=%d C=%d\n", spc.PSW.N,
151 spc.PSW.V, spc.PSW.P, spc.PSW.B, spc.PSW.H, spc.PSW.I, spc.PSW.Z,
153 printf(
" APU Cycles: %llu\n", apu.GetCycles());
156 printf(
" Input Ports: F4=$%02X F5=$%02X F6=$%02X F7=$%02X\n",
157 apu.in_ports_[0], apu.in_ports_[1], apu.in_ports_[2],
159 printf(
" Output Ports: F4=$%02X F5=$%02X F6=$%02X F7=$%02X\n",
160 apu.out_ports_[0], apu.out_ports_[1], apu.out_ports_[2],
164 const char* handshake_phase =
"UNKNOWN";
165 switch (tracker.GetPhase()) {
167 handshake_phase =
"RESET";
170 handshake_phase =
"IPL_BOOT";
173 handshake_phase =
"WAITING_BBAA";
176 handshake_phase =
"HANDSHAKE_CC";
179 handshake_phase =
"TRANSFER_ACTIVE";
182 handshake_phase =
"TRANSFER_DONE";
185 handshake_phase =
"RUNNING";
188 printf(
" Handshake: %s\n", handshake_phase);
192 printf(
" Zero Page: $00=$%02X $01=$%02X $02=$%02X $03=$%02X\n", ram[0x00],
193 ram[0x01], ram[0x02], ram[0x03]);
196 uint16_t reset_vector =
197 static_cast<uint16_t
>(ram[0xFFFE] | (ram[0xFFFF] << 8));
198 printf(
" Reset Vector ($FFFE-$FFFF): $%04X\n", reset_vector);