#include "libsnes.hpp" #include #include #include #include #include using namespace nall; struct Interface : public SNES::Interface { typedef SNES::Interface BaseType; snes_video_refresh_t pvideo_refresh; snes_audio_sample_t paudio_sample; snes_input_poll_t pinput_poll; snes_input_state_t pinput_state; snes_input_notify_t pinput_notify; snes_path_request_t ppath_request; snes_allocSharedMemory_t pallocSharedMemory; snes_freeSharedMemory_t pfreeSharedMemory; snes_trace_t ptrace; string basename; uint32_t *buffer; uint32_t *palette; //zero 11-sep-2012 time_t randomSeed() { return 0; } //zero 26-sep-2012 std::queue messages; //zero 17-oct-2012 int backdropColor; int getBackdropColor() { return backdropColor; } void videoRefresh(const uint32_t *data, bool hires, bool interlace, bool overscan) { unsigned width = hires ? 512 : 256; unsigned height = overscan ? 239 : 224; unsigned pitch = 1024 >> interlace; if(interlace) height <<= 1; data += 9 * 1024; //skip front porch for(unsigned y = 0; y < height; y++) { const uint32_t *sp = data + y * pitch; uint32_t *dp = buffer + y * pitch; for(unsigned x = 0; x < width; x++) { *dp++ = palette[*sp++]; } } if(pvideo_refresh) pvideo_refresh(buffer, width, height); if(pinput_poll) pinput_poll(); } void audioSample(int16_t left, int16_t right) { if(paudio_sample) return paudio_sample(left, right); } //zero 27-sep-2012 snes_scanlineStart_t pScanlineStart; void scanlineStart(int line) { if(pScanlineStart) pScanlineStart((int)line); } int16_t inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id) { if(pinput_state) return pinput_state(port?1:0, (unsigned)device, index, id); return 0; } void inputNotify(int index) { if (pinput_notify) pinput_notify(index); } void message(const string &text) { messages.push(text); } void cpuTrace(const char *msg) { if (ptrace) ptrace((const char *)msg); } string path(SNES::Cartridge::Slot slot, const string &hint) { if(ppath_request) { const char* path = ppath_request((int)slot, (const char*)hint); return path; } return { basename, hint }; } //zero 23-dec-2012 void* allocSharedMemory(const char* memtype, size_t amt, int initialByte = -1) { void* ret; //if pallocSharedMemory isnt set up yet, we're going to have serious problems ret = pallocSharedMemory(memtype,amt); if(initialByte != -1) { for(unsigned i = 0; i < amt; i++) ((uint8*)ret)[i] = (uint8)initialByte; } return ret; } void freeSharedMemory(void* ptr) { if(!pfreeSharedMemory) return; //?? pfreeSharedMemory(ptr); } Interface() : pvideo_refresh(0), paudio_sample(0), pinput_poll(0), pinput_state(0), pinput_notify(0), ppath_request(0), pScanlineStart(0), pallocSharedMemory(0), pfreeSharedMemory(0), backdropColor(-1), ptrace(0) { buffer = new uint32_t[512 * 480]; palette = new uint32_t[16 * 32768]; } ~Interface() { delete[] buffer; delete[] palette; } }; void pwrap_init(); static Interface *iface = nullptr; namespace SNES { SNES::Interface *interface() { if(iface != nullptr) return iface; iface = new ::Interface(); pwrap_init(); return iface; } } const char* snes_library_id(void) { static string version = {"bsnes v", Version}; return version; } unsigned snes_library_revision_major(void) { return 1; } unsigned snes_library_revision_minor(void) { return 3; } void snes_set_allocSharedMemory(snes_allocSharedMemory_t cb) { iface->pallocSharedMemory = cb; } void snes_set_freeSharedMemory(snes_freeSharedMemory_t cb) { iface->pfreeSharedMemory = cb; } void snes_set_video_refresh(snes_video_refresh_t video_refresh) { iface->pvideo_refresh = video_refresh; } void snes_set_color_lut(uint32_t * colors) { for (int i = 0; i < 16 * 32768; i++) iface->palette[i] = colors[i]; } void snes_set_audio_sample(snes_audio_sample_t audio_sample) { iface->paudio_sample = audio_sample; } void snes_set_input_poll(snes_input_poll_t input_poll) { iface->pinput_poll = input_poll; } void snes_set_input_state(snes_input_state_t input_state) { iface->pinput_state = input_state; } void snes_set_input_notify(snes_input_notify_t input_notify) { iface->pinput_notify = input_notify; } void snes_set_path_request(snes_path_request_t path_request) { iface->ppath_request = path_request; } void snes_set_controller_port_device(bool port, unsigned device) { SNES::input.connect(port, (SNES::Input::Device)device); } void snes_set_cartridge_basename(const char *basename) { iface->basename = basename; } template inline void reconstruct(T* t) { t->~T(); memset(t,0,sizeof(*t)); new(t) T(); } void snes_init(void) { //force everything to get initialized, even thuogh it probably already is SNES::interface(); //zero 01-dec-2012 - due to systematic variable initialization fails in bsnes components, these reconstructions are necessary, //and the previous comment here which called this paranoid has been removed. reconstruct(&SNES::icd2); reconstruct(&SNES::nss); reconstruct(&SNES::superfx); reconstruct(&SNES::sa1); reconstruct(&SNES::necdsp); reconstruct(&SNES::hitachidsp); reconstruct(&SNES::armdsp); reconstruct(&SNES::bsxsatellaview); reconstruct(&SNES::bsxcartridge); reconstruct(&SNES::bsxflash); reconstruct(&SNES::srtc); SNES::srtc.initialize(); reconstruct(&SNES::sdd1); reconstruct(&SNES::spc7110); SNES::spc7110.initialize(); reconstruct(&SNES::obc1); reconstruct(&SNES::msu1); reconstruct(&SNES::link); reconstruct(&SNES::video); reconstruct(&SNES::audio); //zero 01-dec-2012 - forgot to do all these. massive desync chaos! //remove these to make it easier to find initialization fails in the component power-ons / constructors / etc. //or just forget about it. this snes_init gets called paranoidly frequently by bizhawk, so things should stay zeroed correctly reconstruct(&SNES::cpu); SNES::cpu.initialize(); reconstruct(&SNES::smp); SNES::smp.initialize(); reconstruct(&SNES::dsp); reconstruct(&SNES::ppu); SNES::ppu.initialize(); SNES::system.init(); //zero 26-aug-2013 - yup. still more reconstruct(&GameBoy::cpu); GameBoy::cpu.initialize(); SNES::input.connect(SNES::Controller::Port1, SNES::Input::Device::Joypad); SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::Joypad); } void snes_term(void) { SNES::system.term(); } void snes_power(void) { SNES::system.power(); } void snes_reset(void) { SNES::system.reset(); } void snes_run(void) { SNES::system.run(); } unsigned snes_serialize_size(void) { return SNES::system.serialize_size(); } bool snes_serialize(uint8_t *data, unsigned size) { SNES::system.runtosave(); serializer s = SNES::system.serialize(); if(s.size() > size) return false; memcpy(data, s.data(), s.size()); return true; } bool snes_unserialize(const uint8_t *data, unsigned size) { serializer s(data, size); return SNES::system.unserialize(s); } struct CheatList { bool enable; string code; CheatList() : enable(false) {} }; static linear_vector cheatList; void snes_cheat_reset(void) { cheatList.reset(); GameBoy::cheat.reset(); GameBoy::cheat.synchronize(); SNES::cheat.reset(); SNES::cheat.synchronize(); } void snes_cheat_set(unsigned index, bool enable, const char *code) { cheatList[index].enable = enable; cheatList[index].code = code; lstring list; for(unsigned n = 0; n < cheatList.size(); n++) { if(cheatList[n].enable) list.append(cheatList[n].code); } if(SNES::cartridge.mode() == SNES::Cartridge::Mode::SuperGameBoy) { GameBoy::cheat.reset(); for(auto &code : list) { lstring codelist; codelist.split("+", code); for(auto &part : codelist) { unsigned addr, data, comp; if(GameBoy::Cheat::decode(part, addr, data, comp)) { GameBoy::cheat.append({ addr, data, comp }); } } } GameBoy::cheat.synchronize(); return; } SNES::cheat.reset(); for(auto &code : list) { lstring codelist; codelist.split("+", code); for(auto &part : codelist) { unsigned addr, data; if(SNES::Cheat::decode(part, addr, data)) { SNES::cheat.append({ addr, data }); } } } SNES::cheat.synchronize(); } //zero 21-sep-2012 void snes_set_scanlineStart(snes_scanlineStart_t cb) { iface->pScanlineStart = cb; } //zero 03-sep-2012 bool snes_check_cartridge(const uint8_t *rom_data, unsigned rom_size) { //tries to determine whether this rom is a snes rom - BUT THIS TRIES TO ACCEPT EVERYTHING! so we cant really use it SnesCartridge temp(rom_data, rom_size); return temp.type != SnesCartridge::TypeUnknown && temp.type != SnesCartridge::TypeGameBoy; } //zero 05-sep-2012 int snes_peek_logical_register(int reg) { switch(reg) { //$2105 #if !defined(PROFILE_PERFORMANCE) case SNES_REG_BG_MODE: return SNES::ppu.regs.bg_mode; case SNES_REG_BG3_PRIORITY: return SNES::ppu.regs.bg3_priority; case SNES_REG_BG1_TILESIZE: return SNES::ppu.regs.bg_tilesize[SNES::PPU::BG1]; case SNES_REG_BG2_TILESIZE: return SNES::ppu.regs.bg_tilesize[SNES::PPU::BG2]; case SNES_REG_BG3_TILESIZE: return SNES::ppu.regs.bg_tilesize[SNES::PPU::BG3]; case SNES_REG_BG4_TILESIZE: return SNES::ppu.regs.bg_tilesize[SNES::PPU::BG4]; //$2107 case SNES_REG_BG1_SCADDR: return SNES::ppu.regs.bg_scaddr[SNES::PPU::BG1]>>9; case SNES_REG_BG1_SCSIZE: return SNES::ppu.regs.bg_scsize[SNES::PPU::BG1]; //$2108 case SNES_REG_BG2_SCADDR: return SNES::ppu.regs.bg_scaddr[SNES::PPU::BG2]>>9; case SNES_REG_BG2_SCSIZE: return SNES::ppu.regs.bg_scsize[SNES::PPU::BG2]; //$2109 case SNES_REG_BG3_SCADDR: return SNES::ppu.regs.bg_scaddr[SNES::PPU::BG3]>>9; case SNES_REG_BG3_SCSIZE: return SNES::ppu.regs.bg_scsize[SNES::PPU::BG3]; //$210A case SNES_REG_BG4_SCADDR: return SNES::ppu.regs.bg_scaddr[SNES::PPU::BG4]>>9; case SNES_REG_BG4_SCSIZE: return SNES::ppu.regs.bg_scsize[SNES::PPU::BG4]; //$210B case SNES_REG_BG1_TDADDR: return SNES::ppu.regs.bg_tdaddr[SNES::PPU::BG1]>>13; case SNES_REG_BG2_TDADDR: return SNES::ppu.regs.bg_tdaddr[SNES::PPU::BG2]>>13; //$210C case SNES_REG_BG3_TDADDR: return SNES::ppu.regs.bg_tdaddr[SNES::PPU::BG3]>>13; case SNES_REG_BG4_TDADDR: return SNES::ppu.regs.bg_tdaddr[SNES::PPU::BG4]>>13; //$2133 SETINI case SNES_REG_SETINI_MODE7_EXTBG: return SNES::ppu.regs.mode7_extbg?1:0; case SNES_REG_SETINI_HIRES: return SNES::ppu.regs.pseudo_hires?1:0; case SNES_REG_SETINI_OVERSCAN: return SNES::ppu.regs.overscan?1:0; case SNES_REG_SETINI_OBJ_INTERLACE: return SNES::ppu.regs.oam_interlace?1:0; case SNES_REG_SETINI_SCREEN_INTERLACE: return SNES::ppu.regs.interlace?1:0; //$2130 CGWSEL case SNES_REG_CGWSEL_COLORMASK: return SNES::ppu.regs.color_mask; case SNES_REG_CGWSEL_COLORSUBMASK: return SNES::ppu.regs.colorsub_mask; case SNES_REG_CGWSEL_ADDSUBMODE: return SNES::ppu.regs.addsub_mode?1:0; case SNES_REG_CGWSEL_DIRECTCOLOR: return SNES::ppu.regs.direct_color?1:0; //$2101 OBSEL case SNES_REG_OBSEL_NAMEBASE: return SNES::ppu.regs.oam_tdaddr>>14; case SNES_REG_OBSEL_NAMESEL: return SNES::ppu.regs.oam_nameselect; case SNES_REG_OBSEL_SIZE: return SNES::ppu.regs.oam_basesize; //$2131 CGADSUB //enum { BG1 = 0, BG2 = 1, BG3 = 2, BG4 = 3, OAM = 4, BACK = 5, COL = 5 }; case SNES_REG_CGADSUB_MODE: return SNES::ppu.regs.color_mode; case SNES_REG_CGADSUB_HALF: return SNES::ppu.regs.color_halve; case SNES_REG_CGADSUB_BG4: return SNES::ppu.regs.color_enabled[3]; case SNES_REG_CGADSUB_BG3: return SNES::ppu.regs.color_enabled[2]; case SNES_REG_CGADSUB_BG2: return SNES::ppu.regs.color_enabled[1]; case SNES_REG_CGADSUB_BG1: return SNES::ppu.regs.color_enabled[0]; case SNES_REG_CGADSUB_OBJ: return SNES::ppu.regs.color_enabled[4]; case SNES_REG_CGADSUB_BACKDROP: return SNES::ppu.regs.color_enabled[5]; //$212C TM case SNES_REG_TM_BG1: return SNES::ppu.regs.bg_enabled[0]; case SNES_REG_TM_BG2: return SNES::ppu.regs.bg_enabled[1]; case SNES_REG_TM_BG3: return SNES::ppu.regs.bg_enabled[2]; case SNES_REG_TM_BG4: return SNES::ppu.regs.bg_enabled[3]; case SNES_REG_TM_OBJ: return SNES::ppu.regs.bg_enabled[4]; //$212D TM case SNES_REG_TS_BG1: return SNES::ppu.regs.bgsub_enabled[0]; case SNES_REG_TS_BG2: return SNES::ppu.regs.bgsub_enabled[1]; case SNES_REG_TS_BG3: return SNES::ppu.regs.bgsub_enabled[2]; case SNES_REG_TS_BG4: return SNES::ppu.regs.bgsub_enabled[3]; case SNES_REG_TS_OBJ: return SNES::ppu.regs.bgsub_enabled[4]; //Mode7 regs case SNES_REG_M7SEL_REPEAT: return SNES::ppu.regs.mode7_repeat; case SNES_REG_M7SEL_HFLIP: return SNES::ppu.regs.mode7_vflip; case SNES_REG_M7SEL_VFLIP: return SNES::ppu.regs.mode7_hflip; case SNES_REG_M7A: return SNES::ppu.regs.m7a; case SNES_REG_M7B: return SNES::ppu.regs.m7b; case SNES_REG_M7C: return SNES::ppu.regs.m7c; case SNES_REG_M7D: return SNES::ppu.regs.m7d; case SNES_REG_M7X: return SNES::ppu.regs.m7x; case SNES_REG_M7Y: return SNES::ppu.regs.m7y; //BG scroll regs case SNES_REG_BG1HOFS: return SNES::ppu.regs.bg_hofs[0] & 0x3FF; case SNES_REG_BG1VOFS: return SNES::ppu.regs.bg_vofs[0] & 0x3FF; case SNES_REG_BG2HOFS: return SNES::ppu.regs.bg_hofs[1] & 0x3FF; case SNES_REG_BG2VOFS: return SNES::ppu.regs.bg_vofs[1] & 0x3FF; case SNES_REG_BG3HOFS: return SNES::ppu.regs.bg_hofs[2] & 0x3FF; case SNES_REG_BG3VOFS: return SNES::ppu.regs.bg_vofs[2] & 0x3FF; case SNES_REG_BG4HOFS: return SNES::ppu.regs.bg_hofs[3] & 0x3FF; case SNES_REG_BG4VOFS: return SNES::ppu.regs.bg_vofs[3] & 0x3FF; case SNES_REG_M7HOFS: return SNES::ppu.regs.m7_hofs & 0x1FFF; //rememebr to make these signed with <<19>>19 case SNES_REG_M7VOFS: return SNES::ppu.regs.m7_vofs & 0x1FFF; //rememebr to make these signed with <<19>>19 #endif } return 0; } bool snes_load_cartridge_normal( const char *rom_xml, const uint8_t *rom_data, unsigned rom_size ) { snes_cheat_reset(); if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size); string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SnesCartridge(rom_data, rom_size).markup; SNES::cartridge.load(SNES::Cartridge::Mode::Normal, { xmlrom }); SNES::system.power(); return true; } bool snes_load_cartridge_bsx_slotted( const char *rom_xml, const uint8_t *rom_data, unsigned rom_size, const char *bsx_xml, const uint8_t *bsx_data, unsigned bsx_size ) { snes_cheat_reset(); if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size); string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SnesCartridge(rom_data, rom_size).markup; if(bsx_data) SNES::bsxflash.memory.copy(bsx_data, bsx_size); string xmlbsx = (bsx_xml && *bsx_xml) ? string(bsx_xml) : SnesCartridge(bsx_data, bsx_size).markup; SNES::cartridge.load(SNES::Cartridge::Mode::BsxSlotted, xmlrom); SNES::system.power(); return true; } bool snes_load_cartridge_bsx( const char *rom_xml, const uint8_t *rom_data, unsigned rom_size, const char *bsx_xml, const uint8_t *bsx_data, unsigned bsx_size ) { snes_cheat_reset(); if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size); string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SnesCartridge(rom_data, rom_size).markup; if(bsx_data) SNES::bsxflash.memory.copy(bsx_data, bsx_size); string xmlbsx = (bsx_xml && *bsx_xml) ? string(bsx_xml) : SnesCartridge(bsx_data, bsx_size).markup; SNES::cartridge.load(SNES::Cartridge::Mode::Bsx, xmlrom); SNES::system.power(); return true; } bool snes_load_cartridge_sufami_turbo( const char *rom_xml, const uint8_t *rom_data, unsigned rom_size, const char *sta_xml, const uint8_t *sta_data, unsigned sta_size, const char *stb_xml, const uint8_t *stb_data, unsigned stb_size ) { snes_cheat_reset(); if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size); string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SnesCartridge(rom_data, rom_size).markup; if(sta_data) SNES::sufamiturbo.slotA.rom.copy(sta_data, sta_size); string xmlsta = (sta_xml && *sta_xml) ? string(sta_xml) : SnesCartridge(sta_data, sta_size).markup; if(stb_data) SNES::sufamiturbo.slotB.rom.copy(stb_data, stb_size); string xmlstb = (stb_xml && *stb_xml) ? string(stb_xml) : SnesCartridge(stb_data, stb_size).markup; SNES::cartridge.load(SNES::Cartridge::Mode::SufamiTurbo, xmlrom); SNES::system.power(); return true; } bool snes_load_cartridge_super_game_boy( const char *rom_xml, const uint8_t *rom_data, unsigned rom_size, const char *dmg_xml, const uint8_t *dmg_data, unsigned dmg_size ) { snes_cheat_reset(); if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size); string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SnesCartridge(rom_data, rom_size).markup; if(dmg_data) { //GameBoyCartridge needs to modify dmg_data (for MMM01 emulation); so copy data uint8_t *data = new uint8_t[dmg_size]; memcpy(data, dmg_data, dmg_size); string xmldmg = (dmg_xml && *dmg_xml) ? string(dmg_xml) : GameBoyCartridge(data, dmg_size).markup; GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy, xmldmg, data, dmg_size); delete[] data; } SNES::cartridge.load(SNES::Cartridge::Mode::SuperGameBoy, xmlrom); SNES::system.power(); return true; } void snes_unload_cartridge(void) { SNES::cartridge.unload(); } bool snes_get_region(void) { return SNES::system.region() == SNES::System::Region::NTSC ? 0 : 1; } uint8_t* snes_get_memory_data(unsigned id) { if(SNES::cartridge.loaded() == false) return 0; switch(id) { case SNES_MEMORY_CARTRIDGE_RAM: return SNES::cartridge.ram.data(); case SNES_MEMORY_CARTRIDGE_RTC: if(SNES::cartridge.has_srtc()) return SNES::srtc.rtc; if(SNES::cartridge.has_spc7110rtc()) return SNES::spc7110.rtc; return 0; case SNES_MEMORY_BSX_RAM: if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break; return SNES::bsxcartridge.sram.data(); case SNES_MEMORY_BSX_PRAM: if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break; return SNES::bsxcartridge.psram.data(); case SNES_MEMORY_SUFAMI_TURBO_A_RAM: if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break; return SNES::sufamiturbo.slotA.ram.data(); case SNES_MEMORY_SUFAMI_TURBO_B_RAM: if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break; return SNES::sufamiturbo.slotB.ram.data(); case SNES_MEMORY_GAME_BOY_CARTRAM: if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break; return GameBoy::cartridge.ramdata; //case SNES_MEMORY_GAME_BOY_RTC: // if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break; // return GameBoy::cartridge.rtcdata; case SNES_MEMORY_GAME_BOY_WRAM: if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break; return GameBoy::cpu.wram; case SNES_MEMORY_GAME_BOY_HRAM: if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break; return GameBoy::cpu.hram; case SNES_MEMORY_WRAM: return SNES::cpu.wram; case SNES_MEMORY_APURAM: return SNES::smp.apuram; case SNES_MEMORY_VRAM: return SNES::ppu.vram; case SNES_MEMORY_OAM: return SNES::ppu.oam; case SNES_MEMORY_CGRAM: return SNES::ppu.cgram; case SNES_MEMORY_CARTRIDGE_ROM: return SNES::cartridge.rom.data(); } return 0; } const char* snes_get_memory_id_name(unsigned id) { if(SNES::cartridge.loaded() == false) return nullptr; switch(id) { case SNES_MEMORY_CARTRIDGE_RAM: return "CARTRIDGE_RAM"; case SNES_MEMORY_CARTRIDGE_RTC: if(SNES::cartridge.has_srtc()) return "RTC"; if(SNES::cartridge.has_spc7110rtc()) return "SPC7110_RTC"; return nullptr; case SNES_MEMORY_BSX_RAM: if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break; return "BSX_SRAM"; case SNES_MEMORY_BSX_PRAM: if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break; return "BSX_PSRAM"; case SNES_MEMORY_SUFAMI_TURBO_A_RAM: if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break; return "SUFAMI_SLOTARAM"; case SNES_MEMORY_SUFAMI_TURBO_B_RAM: if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break; return "SUFAMI_SLOTBRAM"; case SNES_MEMORY_GAME_BOY_CARTRAM: if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break; //return GameBoy::cartridge.ramdata; return "SGB_CARTRAM"; //case SNES_MEMORY_GAME_BOY_RTC: // if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break; // return GameBoy::cartridge.rtcdata; case SNES_MEMORY_GAME_BOY_WRAM: if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break; //see notes in SetupMemoryDomains in bizhawk return "SGB_WRAM"; case SNES_MEMORY_GAME_BOY_HRAM: if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break; return "SGB_HRAM"; case SNES_MEMORY_WRAM: //return SNES::cpu.wram; return "WRAM"; case SNES_MEMORY_APURAM: //return SNES::smp.apuram; return "APURAM"; case SNES_MEMORY_VRAM: return "VRAM"; case SNES_MEMORY_OAM: return "OAM"; case SNES_MEMORY_CGRAM: return "CGRAM"; case SNES_MEMORY_CARTRIDGE_ROM: return "CARTRIDGE_ROM"; } return nullptr; } unsigned snes_get_memory_size(unsigned id) { if(SNES::cartridge.loaded() == false) return 0; unsigned size = 0; switch(id) { case SNES_MEMORY_CARTRIDGE_RAM: size = SNES::cartridge.ram.size(); break; case SNES_MEMORY_CARTRIDGE_RTC: if(SNES::cartridge.has_srtc() || SNES::cartridge.has_spc7110rtc()) size = 20; break; case SNES_MEMORY_BSX_RAM: if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break; size = SNES::bsxcartridge.sram.size(); break; case SNES_MEMORY_BSX_PRAM: if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break; size = SNES::bsxcartridge.psram.size(); break; case SNES_MEMORY_SUFAMI_TURBO_A_RAM: if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break; size = SNES::sufamiturbo.slotA.ram.size(); break; case SNES_MEMORY_SUFAMI_TURBO_B_RAM: if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break; size = SNES::sufamiturbo.slotB.ram.size(); break; case SNES_MEMORY_GAME_BOY_CARTRAM: if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break; size = GameBoy::cartridge.ramsize; break; //case SNES_MEMORY_GAME_BOY_RTC: // if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break; // size = GameBoy::cartridge.rtcsize; // break; case SNES_MEMORY_GAME_BOY_WRAM: if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break; //see notes in SetupMemoryDomains in bizhawk size = 32768; break; case SNES_MEMORY_GAME_BOY_HRAM: if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break; size = 128; break; case SNES_MEMORY_WRAM: size = 128 * 1024; break; case SNES_MEMORY_APURAM: size = 64 * 1024; break; case SNES_MEMORY_VRAM: size = 64 * 1024; break; case SNES_MEMORY_OAM: size = 544; break; case SNES_MEMORY_CGRAM: size = 512; break; case SNES_MEMORY_CARTRIDGE_ROM: size = SNES::cartridge.rom.size(); break; } if(size == -1U) size = 0; return size; } uint8_t bus_read(unsigned addr) { return SNES::bus.read(addr); } void bus_write(unsigned addr, uint8_t val) { SNES::bus.write(addr, val); } int snes_poll_message() { if(iface->messages.empty()) return -1; return iface->messages.front().length(); } void snes_dequeue_message(char* buffer) { int len = iface->messages.front().length(); memcpy(buffer,(const char*)iface->messages.front(),len); iface->messages.pop(); } void snes_set_backdropColor(int color) { iface->backdropColor = color; } void snes_set_trace_callback(snes_trace_t callback) { if (callback) { iface->wanttrace = true; iface->ptrace = callback; } else { iface->wanttrace = false; iface->ptrace = 0; } }