12#define WRITE_STATE(file, member) \
13 file.write(reinterpret_cast<const char*>(&member), sizeof(member))
14#define READ_STATE(file, member) \
15 file.read(reinterpret_cast<char*>(&member), sizeof(member))
40 LOG_DEBUG(
"SNES",
"Initializing emulator with ROM size %zu bytes",
55 LOG_DEBUG(
"SNES",
"Emulator initialization complete");
59 LOG_DEBUG(
"SNES",
"Reset called (hard=%d)", hard);
71 memset(
ram, 0,
sizeof(
ram));
100 LOG_DEBUG(
"SNES",
"Reset complete - CPU will start at $%02X:%04X",
cpu_.
PB,
106 static int frame_log_count = 0;
107 if (frame_log_count % 60 == 0) {
108 LOG_DEBUG(
"SNES",
"Frame %d: CPU=$%02X:%04X vblank=%d frames_=%d",
114 static int vblank_loop_count = 0;
116 LOG_DEBUG(
"SNES",
"RunFrame: Entering vblank loop (in_vblank_=true)");
126 static int active_loop_count = 0;
127 if (!
in_vblank_ && active_loop_count++ < 10) {
129 "RunFrame: Entering active frame loop (in_vblank_=false, "
130 "frame=%d, frames_=%d)",
151 static int debug_count = 0;
155 "HandleInput: current_state=0x%04X auto_joy_read_=%d (A button active)",
160 input_latch(&
input1,
true);
161 input_latch(&
input2,
true);
162 input_latch(&
input1,
false);
163 input_latch(&
input2,
false);
164 for (
int i = 0; i < 16; i++) {
165 uint8_t val = input_read(&
input1);
168 val = input_read(&
input2);
174 static int debug_result_count = 0;
176 if (debug_result_count++ < 30) {
178 "HandleInput END: current_state=0x%04X, "
179 "port_auto_read[0]=0x%04X (A button status)",
259 bool starting_vblank =
false;
262 static int vblank_end_count = 0;
263 if (vblank_end_count++ < 10) {
266 "VBlank END - v_pos=0, setting in_vblank_=false at frame %d",
280 starting_vblank =
true;
282 if (starting_vblank) {
294 static int vblank_start_count = 0;
295 if (vblank_start_count++ < 10) {
298 "VBlank START - v_pos=%d, setting in_vblank_=true at frame %d",
310 static int handle_input_log = 0;
313 ">>> VBLANK: HandleInput() done, "
314 "port_auto_read[0]=0x%04X, about to call Nmi() <<<",
318 static int nmi_log_count = 0;
319 if (nmi_log_count++ < 10) {
321 "VBlank NMI check: nmi_enabled_=%d, calling Nmi()=%s",
341 for (
int i = 0; i < cycles; i += 2) {
350 count = sync_cycles - (
cycles_ % sync_cycles);
365 static int cpu_port_read_count = 0;
366 static uint8_t last_f4 = 0xFF, last_f5 = 0xFF;
367 bool value_changed = ((adr & 0x3) == 0 && val != last_f4) ||
368 ((adr & 0x3) == 1 && val != last_f5);
369 if (value_changed || cpu_port_read_count++ < 5) {
371 "CPU read APU port $21%02X (F%d) = $%02X at PC=$%02X:%04X "
372 "[AFTER CatchUp: APU_cycles=%llu CPU_cycles=%llu]",
373 0x40 + (adr & 0x3), (adr & 0x3) + 4, val,
cpu_.
PB,
cpu_.
PC,
375 if ((adr & 0x3) == 0)
377 if ((adr & 0x3) == 1)
431 static int read_count = 0;
434 ">>> Game read $4218 = $%02X (port_auto_read[0]=$%04X, "
435 "current=$%04X) at PC=$%02X:%04X <<<",
447 static int read_count = 0;
450 ">>> Game read $4219 = $%02X (port_auto_read[0]=$%04X, "
451 "current=$%04X) at PC=$%02X:%04X <<<",
464 uint8_t bank = adr >> 16;
466 if (bank == 0x7e || bank == 0x7f) {
467 return ram[((bank & 1) << 16) | adr];
469 if (bank < 0x40 || (bank >= 0x80 && bank < 0xc0)) {
473 if (adr >= 0x2100 && adr < 0x2200) {
483 if (adr >= 0x4200 && adr < 0x4220) {
485 static int rread_count = 0;
486 if ((adr == 0x4218 || adr == 0x4219) && rread_count++ < 100) {
489 ">>> Rread($%04X) from bank=$%02X PC=$%04X - calling ReadReg <<<",
494 if (adr >= 0x4300 && adr < 0x4380) {
503 uint8_t val =
Rread(adr);
518 uint32_t full_pc = (
static_cast<uint32_t
>(
cpu_.
PB) << 16) |
cpu_.
PC;
521 static int cpu_port_write_count = 0;
522 if (cpu_port_write_count++ < 10) {
524 "CPU wrote APU port $21%02X (F%d) = $%02X at PC=$%02X:%04X",
525 0x40 + (adr & 0x3), (adr & 0x3) + 4, val,
cpu_.
PB,
cpu_.
PC);
558 static int write_4200_count = 0;
559 if (write_4200_count++ < 20) {
561 "Write $%02X to $4200 at PC=$%02X:%04X (NMI=%d IRQ_H=%d "
564 (val & 0x10) ? 1 : 0, (val & 0x20) ? 1 : 0,
565 (val & 0x01) ? 1 : 0);
573 static int auto_joy_log = 0;
574 static bool last_auto_joy =
false;
576 LOG_DEBUG(
"SNES",
">>> AUTO-JOY-READ %s at PC=$%02X:%04X <<<",
593 LOG_DEBUG(
"SNES",
">>> NMI enabled CHANGED: %d -> %d <<<", old_nmi,
669 uint8_t bank = adr >> 16;
671 if (bank == 0x7e || bank == 0x7f) {
672 ram[((bank & 1) << 16) | adr] = val;
674 if (bank < 0x40 || (bank >= 0x80 && bank < 0xc0)) {
678 if (adr >= 0x2100 && adr < 0x2200) {
682 input_latch(&
input1, val & 1);
683 input_latch(&
input2, val & 1);
685 if (adr >= 0x4200 && adr < 0x4220) {
688 if (adr >= 0x4300 && adr < 0x4380) {
698 uint8_t bank = adr >> 16;
700 if ((bank < 0x40 || (bank >= 0x80 && bank < 0xc0)) && adr < 0x8000) {
702 if (adr < 0x2000 || adr >= 0x6000)
704 if (adr < 0x4000 || adr >= 0x4200)
718 uint8_t rv =
Read(adr);
755 if (button < 0 || button > 11)
770 std::ifstream file(path, std::ios::binary);
818 std::ofstream file(path, std::ios::binary);
823 uint32_t version = 1;
863 int start = (recalc) ? 0x800000 : 0;
865 for (
int i = start; i < 0x1000000; i++) {
void set_handshake_tracker(debug::ApuHandshakeTracker *tracker)
void RunCycles(uint64_t cycles)
std::array< uint8_t, 4 > out_ports_
uint64_t GetCycles() const
std::array< uint8_t, 6 > in_ports_
void set_int_delay(bool delay)
void Reset(bool hard=false)
auto open_bus() const -> uint8_t override
void set_h_pos(uint16_t value) override
void init_hdma_request() override
void set_v_pos(uint16_t value) override
auto v_pos() const -> uint16_t override
auto h_pos() const -> uint16_t override
void set_open_bus(uint8_t value) override
uint8_t cart_read(uint8_t bank, uint16_t adr)
void run_hdma_request() override
void cart_write(uint8_t bank, uint16_t adr, uint8_t val)
auto pal_timing() const -> bool override
void Initialize(const std::vector< uint8_t > &romData, bool verbose=false)
void Write(uint8_t adr, uint8_t val)
void PutPixels(uint8_t *pixel_data)
uint8_t Read(uint8_t adr, bool latch)
void SetSamples(int16_t *sample_data, int wanted_samples)
uint8_t Rread(uint32_t adr)
void RunCycles(int cycles)
uint16_t port_auto_read_[4]
void WriteBBus(uint8_t adr, uint8_t val)
uint8_t CpuRead(uint32_t adr)
void SetButtonState(int player, int button, bool pressed)
uint8_t Read(uint32_t adr)
void saveState(const std::string &path)
std::vector< uint8_t > access_time
debug::ApuHandshakeTracker apu_handshake_tracker_
void Reset(bool hard=false)
uint8_t ReadReg(uint16_t adr)
void CpuIdle(bool waiting)
void WriteReg(uint16_t adr, uint8_t val)
void CpuWrite(uint32_t adr, uint8_t val)
uint16_t multiply_result_
uint32_t next_horiz_event
uint8_t ReadBBus(uint8_t adr)
void Write(uint32_t adr, uint8_t val)
void InitAccessTime(bool recalc)
void loadState(const std::string &path)
void SyncCycles(bool start, int sync_cycles)
std::vector< uint8_t > rom_data
void Init(std::vector< uint8_t > &rom_data)
void SetPixels(uint8_t *pixel_data)
double apu_catchup_cycles_
int GetAccessTime(uint32_t adr)
void OnCpuPortWrite(uint8_t port, uint8_t value, uint32_t pc)
#define LOG_DEBUG(category, format,...)
void input_latch(Input *input, bool value)
uint8_t input_read(Input *input)
void ResetDma(MemoryImpl *memory)
void WriteDma(MemoryImpl *memory, uint16_t adr, uint8_t val)
void HandleDma(Snes *snes, MemoryImpl *memory, int cpu_cycles)
uint8_t ReadDma(MemoryImpl *memory, uint16_t adr)
void StartDma(MemoryImpl *memory, uint8_t val, bool hdma)
Main namespace for the application.
#define WRITE_STATE(file, member)
#define READ_STATE(file, member)