#include #define SUPERGAMEBOY_CPP namespace SNES { SuperGameBoy supergameboy; #include "serialization.cpp" void SuperGameBoy::Enter() { supergameboy.enter(); } void SuperGameBoy::enter() { if(!sgb_run) while(true) { if(scheduler.sync == Scheduler::SynchronizeMode::All) { scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); } audio.coprocessor_sample(0, 0); step(1); synchronize_cpu(); } while(true) { if(scheduler.sync == Scheduler::SynchronizeMode::All) { scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); } unsigned samples = sgb_run(samplebuffer, 16); for(unsigned i = 0; i < samples; i++) { int16 left = samplebuffer[i] >> 0; int16 right = samplebuffer[i] >> 16; //SNES audio is notoriously quiet; lower Game Boy samples to match SGB sound effects audio.coprocessor_sample(left / 3, right / 3); } step(samples); synchronize_cpu(); } } void SuperGameBoy::save() { if(sgb_save) sgb_save(); } uint8 SuperGameBoy::mmio_read(unsigned addr) { addr &= 0xffff; if(addr == 0x2181) return mmio[0]->mmio_read(addr); if(addr == 0x2182) return mmio[1]->mmio_read(addr); if(addr == 0x420b) return mmio[2]->mmio_read(addr); return 0x00; } void SuperGameBoy::mmio_write(unsigned addr, uint8 data) { addr &= 0xffff; if(addr == 0x2181) { row = (row & 0xff00) | (data << 0); mmio[0]->mmio_write(addr, data); } if(addr == 0x2182) { row = (row & 0x00ff) | (data << 8); mmio[1]->mmio_write(addr, data); } if(addr == 0x420b) { if(data == 0x10 && sgb_row) { if(row >= 0x5000 && row <= 0x6540) sgb_row((row - 0x5000) / 320); if(row >= 0x6800 && row <= 0x7d40) sgb_row((row - 0x6800) / 320); } mmio[2]->mmio_write(addr, data); } } uint8 SuperGameBoy::read(unsigned addr) { if(sgb_read) return sgb_read(addr); return 0x00; } void SuperGameBoy::write(unsigned addr, uint8 data) { if(sgb_write) sgb_write(addr, data); } void SuperGameBoy::init() { if(open("supergameboy")) { sgb_rom = sym("sgb_rom"); sgb_ram = sym("sgb_ram"); sgb_rtc = sym("sgb_rtc"); sgb_init = sym("sgb_init"); sgb_term = sym("sgb_term"); sgb_power = sym("sgb_power"); sgb_reset = sym("sgb_reset"); sgb_row = sym("sgb_row"); sgb_read = sym("sgb_read"); sgb_write = sym("sgb_write"); sgb_run = sym("sgb_run"); sgb_save = sym("sgb_save"); sgb_serialize = sym("sgb_serialize"); } } void SuperGameBoy::enable() { mmio[0] = memory::mmio.mmio[0x2181 - 0x2000]; mmio[1] = memory::mmio.mmio[0x2182 - 0x2000]; mmio[2] = memory::mmio.mmio[0x420b - 0x2000]; memory::mmio.map(0x2181, *this); memory::mmio.map(0x2182, *this); memory::mmio.map(0x420b, *this); } void SuperGameBoy::power() { unsigned frequency = (cartridge.supergameboy_version() == Cartridge::SuperGameBoyVersion::Version1 ? system.cpu_frequency() / 10 : 2097152); create(SuperGameBoy::Enter, frequency); audio.coprocessor_enable(true); audio.coprocessor_frequency(cartridge.supergameboy_version() == Cartridge::SuperGameBoyVersion::Version1 ? 2147727.0 : 2097152.0); sgb_rom(memory::gbrom.data(), memory::gbrom.size() == -1U ? 0 : memory::gbrom.size()); sgb_ram(memory::gbram.data(), memory::gbram.size() == -1U ? 0 : memory::gbram.size()); sgb_rtc(memory::gbrtc.data(), memory::gbrtc.size() == -1U ? 0 : memory::gbrtc.size()); bool version = (cartridge.supergameboy_version() == Cartridge::SuperGameBoyVersion::Version1) ? 0 : 1; if(sgb_init) sgb_init(version); if(sgb_power) sgb_power(); } void SuperGameBoy::reset() { unsigned frequency = (cartridge.supergameboy_version() == Cartridge::SuperGameBoyVersion::Version1 ? system.cpu_frequency() / 10 : 2097152); create(SuperGameBoy::Enter, frequency); if(sgb_reset) sgb_reset(); } void SuperGameBoy::unload() { if(sgb_term) sgb_term(); } }