mirror of https://github.com/bsnes-emu/bsnes.git
Update to v073r03 release.
byuu says: Changelog: - much tighter SGB integration, but this is still a work-in-progress - memory::gb(rom,ram,rtc) is gone, uses GameBoy:: memory structures directly (a big gain, no need to copy memory to save and load) - UI-based cartridge loading works with GameBoy:: directly as well - libsnes will need to be updated internally to reflect this - games can save and load (even before bgameboy can, hah) - save states hooked up, but they crash the DMG. I don't know why, as if it was hard enough saving states with libco, try doing it for an emulator inside an emulator >_< - last remnants of old SGB stuff removed, <sueprgameboy> XML converted to <icd2> - looks like the XML list idea is looking pretty useless for SNES::Cartridge now that bgameboy handles its own XML mapping
This commit is contained in:
commit
4dbce5a0b2
|
@ -13,84 +13,63 @@ namespace GameBoy {
|
|||
#include "mmm01/mmm01.cpp"
|
||||
#include "huc1/huc1.cpp"
|
||||
#include "huc3/huc3.cpp"
|
||||
#include "serialization.cpp"
|
||||
Cartridge cartridge;
|
||||
|
||||
void Cartridge::load(uint8_t *data, unsigned size) {
|
||||
void Cartridge::load(const string &xml, uint8_t *data, unsigned size) {
|
||||
//uint32_t crc = crc32_calculate(data, size);
|
||||
//print("CRC32 = ", hex<4>(crc), "\n");
|
||||
|
||||
romdata = new uint8[romsize = size];
|
||||
memcpy(romdata, data, size);
|
||||
|
||||
char name[17];
|
||||
memcpy(name, romdata + 0x0134, 16);
|
||||
name[16] = 0;
|
||||
info.name = name;
|
||||
info.name.rtrim();
|
||||
|
||||
info.cgbflag = romdata[0x0143];
|
||||
info.sgbflag = romdata[0x0146];
|
||||
|
||||
info.mapper = Mapper::Unknown;
|
||||
info.ram = false;
|
||||
info.battery = false;
|
||||
info.rtc = false;
|
||||
info.rumble = false;
|
||||
|
||||
switch(romdata[0x0147]) {
|
||||
case 0x00: info.mapper = Mapper::MBC0; break;
|
||||
case 0x01: info.mapper = Mapper::MBC1; break;
|
||||
case 0x02: info.mapper = Mapper::MBC1; info.ram = true; break;
|
||||
case 0x03: info.mapper = Mapper::MBC1; info.ram = true; info.battery = true; break;
|
||||
case 0x05: info.mapper = Mapper::MBC2; info.ram = true; break;
|
||||
case 0x06: info.mapper = Mapper::MBC2; info.ram = true; info.battery = true; break;
|
||||
case 0x08: info.mapper = Mapper::MBC0; info.ram = true; break;
|
||||
case 0x09: info.mapper = Mapper::MBC0; info.ram = true; info.battery = true; break;
|
||||
case 0x0b: info.mapper = Mapper::MMM01; break;
|
||||
case 0x0c: info.mapper = Mapper::MMM01; info.ram = true; break;
|
||||
case 0x0d: info.mapper = Mapper::MMM01; info.ram = true; info.battery = true; break;
|
||||
case 0x0f: info.mapper = Mapper::MBC3; info.rtc = true; info.battery = true; break;
|
||||
case 0x10: info.mapper = Mapper::MBC3; info.rtc = true; info.ram = true; info.battery = true; break;
|
||||
case 0x11: info.mapper = Mapper::MBC3; break;
|
||||
case 0x12: info.mapper = Mapper::MBC3; info.ram = true; break;
|
||||
case 0x13: info.mapper = Mapper::MBC3; info.ram = true; info.battery = true; break;
|
||||
case 0x19: info.mapper = Mapper::MBC5; break;
|
||||
case 0x1a: info.mapper = Mapper::MBC5; info.ram = true; break;
|
||||
case 0x1b: info.mapper = Mapper::MBC5; info.ram = true; info.battery = true; break;
|
||||
case 0x1c: info.mapper = Mapper::MBC5; info.rumble = true; break;
|
||||
case 0x1d: info.mapper = Mapper::MBC5; info.rumble = true; info.ram = true; break;
|
||||
case 0x1e: info.mapper = Mapper::MBC5; info.rumble = true; info.ram = true; info.battery = true; break;
|
||||
case 0xfc: break; //Pocket Camera
|
||||
case 0xfd: break; //Bandai TAMA5
|
||||
case 0xfe: info.mapper = Mapper::HuC3; break;
|
||||
case 0xff: info.mapper = Mapper::HuC1; info.ram = true; info.battery = true; break;
|
||||
info.romsize = 0;
|
||||
info.ramsize = 0;
|
||||
|
||||
xml_element document = xml_parse(xml);
|
||||
foreach(head, document.element) {
|
||||
if(head.name == "cartridge") {
|
||||
foreach(attr, head.attribute) {
|
||||
if(attr.name == "mapper") {
|
||||
if(attr.content == "none") info.mapper = Mapper::MBC0;
|
||||
if(attr.content == "MBC1") info.mapper = Mapper::MBC1;
|
||||
if(attr.content == "MBC2") info.mapper = Mapper::MBC2;
|
||||
if(attr.content == "MBC3") info.mapper = Mapper::MBC3;
|
||||
if(attr.content == "MBC5") info.mapper = Mapper::MBC5;
|
||||
if(attr.content == "MMM01") info.mapper = Mapper::MMM01;
|
||||
if(attr.content == "HuC1") info.mapper = Mapper::HuC1;
|
||||
if(attr.content == "HuC3") info.mapper = Mapper::HuC3;
|
||||
}
|
||||
|
||||
if(attr.name == "rtc") info.rtc = (attr.content == "true" ? true : false);
|
||||
if(attr.name == "rumble") info.rumble = (attr.content == "true" ? true : false);
|
||||
}
|
||||
|
||||
foreach(elem, head.element) {
|
||||
if(elem.name == "rom") {
|
||||
foreach(attr, elem.attribute) {
|
||||
if(attr.name == "size") info.romsize = hex(attr.content);
|
||||
}
|
||||
}
|
||||
|
||||
if(elem.name == "ram") {
|
||||
info.ram = true;
|
||||
foreach(attr, elem.attribute) {
|
||||
if(attr.name == "size") info.ramsize = hex(attr.content);
|
||||
if(attr.name == "battery") info.battery = (attr.content == "true" ? true : false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//print("Mapper: ", hex<2>(romdata[0x0147]), "\n");
|
||||
|
||||
switch(romdata[0x0148]) { default:
|
||||
case 0x00: info.romsize = 2 * 16 * 1024; break;
|
||||
case 0x01: info.romsize = 4 * 16 * 1024; break;
|
||||
case 0x02: info.romsize = 8 * 16 * 1024; break;
|
||||
case 0x03: info.romsize = 16 * 16 * 1024; break;
|
||||
case 0x04: info.romsize = 32 * 16 * 1024; break;
|
||||
case 0x05: info.romsize = 64 * 16 * 1024; break;
|
||||
case 0x06: info.romsize = 128 * 16 * 1024; break;
|
||||
case 0x07: info.romsize = 256 * 16 * 1024; break;
|
||||
case 0x52: info.romsize = 72 * 16 * 1024; break;
|
||||
case 0x53: info.romsize = 80 * 16 * 1024; break;
|
||||
case 0x54: info.romsize = 96 * 16 * 1024; break;
|
||||
}
|
||||
|
||||
switch(romdata[0x0149]) { default:
|
||||
case 0x00: info.ramsize = 0 * 1024; break;
|
||||
case 0x01: info.ramsize = 2 * 1024; break;
|
||||
case 0x02: info.ramsize = 8 * 1024; break;
|
||||
case 0x03: info.ramsize = 32 * 1024; break;
|
||||
}
|
||||
|
||||
if(info.mapper == Mapper::MBC2) info.ramsize = 512; //512 x 4-bit
|
||||
|
||||
ramdata = new uint8_t[ramsize = info.ramsize]();
|
||||
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,9 +21,7 @@ struct Cartridge : property<Cartridge> {
|
|||
};
|
||||
|
||||
struct Information {
|
||||
string name;
|
||||
uint8 cgbflag;
|
||||
uint8 sgbflag;
|
||||
string xml;
|
||||
|
||||
Mapper mapper;
|
||||
bool ram;
|
||||
|
@ -43,7 +41,7 @@ struct Cartridge : property<Cartridge> {
|
|||
uint8_t *ramdata;
|
||||
unsigned ramsize;
|
||||
|
||||
void load(uint8_t *data, unsigned size);
|
||||
void load(const string &xml, uint8_t *data, unsigned size);
|
||||
void unload();
|
||||
|
||||
uint8 rom_read(unsigned addr);
|
||||
|
@ -54,6 +52,7 @@ struct Cartridge : property<Cartridge> {
|
|||
void power();
|
||||
void map();
|
||||
|
||||
void serialize(serializer&);
|
||||
Cartridge();
|
||||
~Cartridge();
|
||||
};
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
void Cartridge::serialize(serializer &s) {
|
||||
if(info.battery) s.array(ramdata, ramsize);
|
||||
|
||||
s.integer(mbc1.ram_enable);
|
||||
s.integer(mbc1.rom_select);
|
||||
s.integer(mbc1.ram_select);
|
||||
s.integer(mbc1.mode_select);
|
||||
|
||||
s.integer(mbc2.ram_enable);
|
||||
s.integer(mbc2.rom_select);
|
||||
|
||||
s.integer(mbc3.ram_enable);
|
||||
s.integer(mbc3.rom_select);
|
||||
s.integer(mbc3.ram_select);
|
||||
s.integer(mbc3.rtc_latch);
|
||||
|
||||
s.integer(mbc3.rtc_halt);
|
||||
s.integer(mbc3.rtc_second);
|
||||
s.integer(mbc3.rtc_minute);
|
||||
s.integer(mbc3.rtc_hour);
|
||||
s.integer(mbc3.rtc_day);
|
||||
s.integer(mbc3.rtc_day_carry);
|
||||
|
||||
s.integer(mbc3.rtc_latch_second);
|
||||
s.integer(mbc3.rtc_latch_minute);
|
||||
s.integer(mbc3.rtc_latch_hour);
|
||||
s.integer(mbc3.rtc_latch_day);
|
||||
s.integer(mbc3.rtc_latch_day_carry);
|
||||
|
||||
s.integer(mbc5.ram_enable);
|
||||
s.integer(mbc5.rom_select);
|
||||
s.integer(mbc5.ram_select);
|
||||
|
||||
s.integer(mmm01.rom_mode);
|
||||
s.integer(mmm01.rom_base);
|
||||
|
||||
s.integer(mmm01.ram_enable);
|
||||
s.integer(mmm01.rom_select);
|
||||
s.integer(mmm01.ram_select);
|
||||
|
||||
s.integer(huc1.ram_enable);
|
||||
s.integer(huc1.rom_select);
|
||||
s.integer(huc1.ram_select);
|
||||
|
||||
s.integer(huc3.ram_enable);
|
||||
s.integer(huc3.rom_select);
|
||||
s.integer(huc3.ram_select);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -6,6 +6,7 @@ namespace GameBoy {
|
|||
#include "core/core.cpp"
|
||||
#include "mmio/mmio.cpp"
|
||||
#include "timing/timing.cpp"
|
||||
#include "serialization.cpp"
|
||||
CPU cpu;
|
||||
|
||||
void CPU::Main() {
|
||||
|
@ -14,6 +15,11 @@ void CPU::Main() {
|
|||
|
||||
void CPU::main() {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::CPU) {
|
||||
scheduler.sync = Scheduler::SynchronizeMode::All;
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
if(trace) print(disassemble(r[PC]), "\n");
|
||||
interrupt_test();
|
||||
uint8 opcode = op_read(r[PC]++);
|
||||
|
|
|
@ -67,6 +67,8 @@ struct CPU : Processor, MMIO {
|
|||
void interrupt_test();
|
||||
void interrupt_exec(uint16 pc);
|
||||
void power();
|
||||
|
||||
void serialize(serializer&);
|
||||
CPU();
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
#ifdef CPU_CPP
|
||||
|
||||
void CPU::serialize(serializer &s) {
|
||||
s.array(wram);
|
||||
s.array(hram);
|
||||
|
||||
s.integer(r.a.data);
|
||||
s.integer(r.f.z);
|
||||
s.integer(r.f.n);
|
||||
s.integer(r.f.h);
|
||||
s.integer(r.f.c);
|
||||
s.integer(r.b.data);
|
||||
s.integer(r.c.data);
|
||||
s.integer(r.d.data);
|
||||
s.integer(r.e.data);
|
||||
s.integer(r.h.data);
|
||||
s.integer(r.l.data);
|
||||
s.integer(r.sp.data);
|
||||
s.integer(r.pc.data);
|
||||
|
||||
s.integer(status.clock);
|
||||
s.integer(status.halt);
|
||||
s.integer(status.stop);
|
||||
|
||||
s.integer(status.ime);
|
||||
s.integer(status.timer0);
|
||||
s.integer(status.timer1);
|
||||
s.integer(status.timer2);
|
||||
s.integer(status.timer3);
|
||||
|
||||
s.integer(status.p15);
|
||||
s.integer(status.p14);
|
||||
s.integer(status.joyp);
|
||||
s.integer(status.mlt_req);
|
||||
|
||||
s.integer(status.div);
|
||||
s.integer(status.tima);
|
||||
s.integer(status.tma);
|
||||
s.integer(status.timer_enable);
|
||||
s.integer(status.timer_clock);
|
||||
|
||||
s.integer(status.interrupt_request_joypad);
|
||||
s.integer(status.interrupt_request_serial);
|
||||
s.integer(status.interrupt_request_timer);
|
||||
s.integer(status.interrupt_request_stat);
|
||||
s.integer(status.interrupt_request_vblank);
|
||||
|
||||
s.integer(status.interrupt_enable_joypad);
|
||||
s.integer(status.interrupt_enable_serial);
|
||||
s.integer(status.interrupt_enable_timer);
|
||||
s.integer(status.interrupt_enable_stat);
|
||||
s.integer(status.interrupt_enable_vblank);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
void CPU::add_clocks(unsigned clocks) {
|
||||
system.clocks_executed += clocks;
|
||||
scheduler.exit();
|
||||
scheduler.exit(Scheduler::ExitReason::StepEvent);
|
||||
|
||||
status.clock += clocks;
|
||||
if(status.clock >= 4 * 1024 * 1024) {
|
||||
|
|
|
@ -5,14 +5,17 @@
|
|||
namespace GameBoy {
|
||||
namespace Info {
|
||||
static const char Name[] = "bgameboy";
|
||||
static const char Version[] = "000.10";
|
||||
static const char Version[] = "000.11";
|
||||
static unsigned SerializerVersion = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#include <libco/libco.h>
|
||||
|
||||
#include <nall/foreach.hpp>
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/property.hpp>
|
||||
#include <nall/serializer.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
using namespace nall;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
namespace GameBoy {
|
||||
|
||||
#include "mmio/mmio.cpp"
|
||||
#include "serialization.cpp"
|
||||
LCD lcd;
|
||||
|
||||
void LCD::Main() {
|
||||
|
@ -12,6 +13,10 @@ void LCD::Main() {
|
|||
|
||||
void LCD::main() {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
add_clocks(4);
|
||||
|
||||
if(status.lx == 320) {
|
||||
|
@ -25,7 +30,9 @@ void LCD::add_clocks(unsigned clocks) {
|
|||
if(status.lx >= 456) scanline();
|
||||
|
||||
cpu.clock -= clocks;
|
||||
if(cpu.clock <= 0) co_switch(scheduler.active_thread = cpu.thread);
|
||||
if(cpu.clock <= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) {
|
||||
co_switch(scheduler.active_thread = cpu.thread);
|
||||
}
|
||||
}
|
||||
|
||||
void LCD::scanline() {
|
||||
|
@ -50,7 +57,7 @@ void LCD::frame() {
|
|||
cpu.mmio_joyp_poll();
|
||||
|
||||
status.ly = 0;
|
||||
scheduler.exit();
|
||||
scheduler.exit(Scheduler::ExitReason::FrameEvent);
|
||||
}
|
||||
|
||||
void LCD::render() {
|
||||
|
@ -221,4 +228,7 @@ void LCD::power() {
|
|||
status.wx = 0;
|
||||
}
|
||||
|
||||
LCD::LCD() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -63,6 +63,9 @@ struct LCD : Processor, MMIO {
|
|||
void render_obj();
|
||||
|
||||
void power();
|
||||
|
||||
void serialize(serializer&);
|
||||
LCD();
|
||||
};
|
||||
|
||||
extern LCD lcd;
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
#ifdef LCD_CPP
|
||||
|
||||
void LCD::serialize(serializer &s) {
|
||||
s.integer(status.lx);
|
||||
|
||||
s.integer(status.display_enable);
|
||||
s.integer(status.window_tilemap_select);
|
||||
s.integer(status.window_display_enable);
|
||||
s.integer(status.bg_tiledata_select);
|
||||
s.integer(status.bg_tilemap_select);
|
||||
s.integer(status.obj_size);
|
||||
s.integer(status.obj_enable);
|
||||
s.integer(status.bg_enable);
|
||||
|
||||
s.integer(status.interrupt_lyc);
|
||||
s.integer(status.interrupt_oam);
|
||||
s.integer(status.interrupt_vblank);
|
||||
s.integer(status.interrupt_hblank);
|
||||
|
||||
s.integer(status.scy);
|
||||
s.integer(status.scx);
|
||||
s.integer(status.ly);
|
||||
s.integer(status.lyc);
|
||||
|
||||
s.array(status.bgp);
|
||||
s.array(status.obp[0]);
|
||||
s.array(status.obp[1]);
|
||||
|
||||
s.integer(status.wy);
|
||||
s.integer(status.wx);
|
||||
|
||||
s.array(screen);
|
||||
s.array(vram);
|
||||
s.array(oam);
|
||||
s.array(line);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -51,10 +51,6 @@ void Bus::write(uint16 addr, uint8 data) {
|
|||
|
||||
void Bus::power() {
|
||||
for(unsigned n = 0; n < 65536; n++) mmio[n] = &unmapped;
|
||||
reset();
|
||||
}
|
||||
|
||||
void Bus::reset() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,15 +21,11 @@ struct Unmapped : MMIO {
|
|||
};
|
||||
|
||||
struct Bus {
|
||||
Memory cartrom;
|
||||
Memory cartram;
|
||||
|
||||
MMIO *mmio[65536];
|
||||
uint8 read(uint16 addr);
|
||||
void write(uint16 addr, uint8 data);
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
};
|
||||
|
||||
extern Unmapped unmapped;
|
||||
|
|
|
@ -10,7 +10,8 @@ void Scheduler::enter() {
|
|||
co_switch(active_thread);
|
||||
}
|
||||
|
||||
void Scheduler::exit() {
|
||||
void Scheduler::exit(ExitReason reason) {
|
||||
exit_reason = reason;
|
||||
active_thread = co_active();
|
||||
co_switch(host_thread);
|
||||
}
|
||||
|
@ -26,6 +27,7 @@ void Scheduler::init() {
|
|||
}
|
||||
|
||||
Scheduler::Scheduler() {
|
||||
exit_reason = ExitReason::UnknownEvent;
|
||||
host_thread = 0;
|
||||
active_thread = 0;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
struct Scheduler {
|
||||
struct Scheduler : property<Scheduler> {
|
||||
enum class SynchronizeMode : unsigned { None, CPU, All } sync;
|
||||
enum class ExitReason : unsigned { UnknownEvent, StepEvent, FrameEvent, SynchronizeEvent };
|
||||
readonly<ExitReason> exit_reason;
|
||||
|
||||
cothread_t host_thread;
|
||||
cothread_t active_thread;
|
||||
|
||||
void enter();
|
||||
void exit();
|
||||
void exit(ExitReason);
|
||||
void swapto(Processor&);
|
||||
|
||||
void init();
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
#ifdef SYSTEM_CPP
|
||||
|
||||
serializer System::serialize() {
|
||||
serializer s(serialize_size);
|
||||
|
||||
unsigned signature = 0x31545342, version = Info::SerializerVersion, crc32 = 0;
|
||||
char description[512];
|
||||
memset(&description, 0, sizeof description);
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.integer(crc32);
|
||||
s.array(description);
|
||||
|
||||
serialize_all(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
bool System::unserialize(serializer &s) {
|
||||
unsigned signature, version, crc32;
|
||||
char description[512];
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.integer(crc32);
|
||||
s.array(description);
|
||||
|
||||
if(signature != 0x31545342) return false;
|
||||
if(version != Info::SerializerVersion) return false;
|
||||
//if(crc32 != 0) return false;
|
||||
|
||||
serialize_all(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
void System::serialize(serializer &s) {
|
||||
s.integer(clocks_executed);
|
||||
}
|
||||
|
||||
void System::serialize_all(serializer &s) {
|
||||
cartridge.serialize(s);
|
||||
system.serialize(s);
|
||||
cpu.serialize(s);
|
||||
lcd.serialize(s);
|
||||
}
|
||||
|
||||
void System::serialize_init() {
|
||||
serializer s;
|
||||
|
||||
unsigned signature = 0, version = 0, crc32 = 0;
|
||||
char description[512];
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.integer(crc32);
|
||||
s.array(description);
|
||||
|
||||
serialize_all(s);
|
||||
serialize_size = s.size();
|
||||
}
|
||||
|
||||
#endif
|
|
@ -5,8 +5,34 @@ namespace GameBoy {
|
|||
|
||||
#include "bootrom-dmg.cpp"
|
||||
#include "bootrom-sgb.cpp"
|
||||
#include "serialization.cpp"
|
||||
System system;
|
||||
|
||||
void System::run() {
|
||||
scheduler.sync = Scheduler::SynchronizeMode::None;
|
||||
|
||||
scheduler.enter();
|
||||
if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
void System::runtosave() {
|
||||
scheduler.sync = Scheduler::SynchronizeMode::CPU;
|
||||
runthreadtosave();
|
||||
|
||||
scheduler.active_thread = lcd.thread;
|
||||
runthreadtosave();
|
||||
}
|
||||
|
||||
void System::runthreadtosave() {
|
||||
while(true) {
|
||||
scheduler.enter();
|
||||
if(scheduler.exit_reason() == Scheduler::ExitReason::SynchronizeEvent) break;
|
||||
if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8 System::mmio_read(uint16 addr) {
|
||||
if((addr & 0xff00) == 0x0000) {
|
||||
return BootROM::sgb[addr];
|
||||
|
@ -34,11 +60,8 @@ void System::power() {
|
|||
for(unsigned n = 0x0000; n <= 0x00ff; n++) bus.mmio[n] = this;
|
||||
bus.mmio[0xff50] = this;
|
||||
|
||||
system.clocks_executed = 0;
|
||||
}
|
||||
|
||||
void System::run() {
|
||||
scheduler.enter();
|
||||
clocks_executed = 0;
|
||||
serialize_init();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,15 +10,28 @@ struct System : MMIO {
|
|||
static const uint8 sgb[256];
|
||||
} bootROM;
|
||||
|
||||
void run();
|
||||
void runtosave();
|
||||
void runthreadtosave();
|
||||
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
void init(Interface*);
|
||||
void power();
|
||||
void run();
|
||||
|
||||
Interface *interface;
|
||||
unsigned clocks_executed;
|
||||
|
||||
//serialization.cpp
|
||||
unsigned serialize_size;
|
||||
|
||||
serializer serialize();
|
||||
bool unserialize(serializer&);
|
||||
|
||||
void serialize(serializer&);
|
||||
void serialize_all(serializer&);
|
||||
void serialize_init();
|
||||
};
|
||||
|
||||
#include <gameboy/interface/interface.hpp>
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
#ifndef NALL_GAMEBOY_CARTRIDGE_HPP
|
||||
#define NALL_GAMEBOY_CARTRIDGE_HPP
|
||||
|
||||
namespace nall {
|
||||
|
||||
class GameBoyCartridge {
|
||||
public:
|
||||
string xml;
|
||||
inline GameBoyCartridge(const uint8_t *data, unsigned size);
|
||||
|
||||
//private:
|
||||
struct Information {
|
||||
string mapper;
|
||||
bool ram;
|
||||
bool battery;
|
||||
bool rtc;
|
||||
bool rumble;
|
||||
|
||||
unsigned romsize;
|
||||
unsigned ramsize;
|
||||
} info;
|
||||
};
|
||||
|
||||
GameBoyCartridge::GameBoyCartridge(const uint8_t *romdata, unsigned romsize) {
|
||||
xml = "<?xml version='1.0' encoding='UTF-8'?>\n";
|
||||
if(romsize < 0x4000) return;
|
||||
|
||||
info.mapper = "unknown";
|
||||
info.ram = false;
|
||||
info.battery = false;
|
||||
info.rtc = false;
|
||||
info.rumble = false;
|
||||
|
||||
info.romsize = 0;
|
||||
info.ramsize = 0;
|
||||
|
||||
switch(romdata[0x0147]) {
|
||||
case 0x00: info.mapper = "none"; break;
|
||||
case 0x01: info.mapper = "MBC1"; break;
|
||||
case 0x02: info.mapper = "MBC1"; info.ram = true; break;
|
||||
case 0x03: info.mapper = "MBC1"; info.ram = true; info.battery = true; break;
|
||||
case 0x05: info.mapper = "MBC2"; info.ram = true; break;
|
||||
case 0x06: info.mapper = "MBC2"; info.ram = true; info.battery = true; break;
|
||||
case 0x08: info.mapper = "none"; info.ram = true; break;
|
||||
case 0x09: info.mapper = "MBC0"; info.ram = true; info.battery = true; break;
|
||||
case 0x0b: info.mapper = "MMM01"; break;
|
||||
case 0x0c: info.mapper = "MMM01"; info.ram = true; break;
|
||||
case 0x0d: info.mapper = "MMM01"; info.ram = true; info.battery = true; break;
|
||||
case 0x0f: info.mapper = "MBC3"; info.rtc = true; info.battery = true; break;
|
||||
case 0x10: info.mapper = "MBC3"; info.rtc = true; info.ram = true; info.battery = true; break;
|
||||
case 0x11: info.mapper = "MBC3"; break;
|
||||
case 0x12: info.mapper = "MBC3"; info.ram = true; break;
|
||||
case 0x13: info.mapper = "MBC3"; info.ram = true; info.battery = true; break;
|
||||
case 0x19: info.mapper = "MBC5"; break;
|
||||
case 0x1a: info.mapper = "MBC5"; info.ram = true; break;
|
||||
case 0x1b: info.mapper = "MBC5"; info.ram = true; info.battery = true; break;
|
||||
case 0x1c: info.mapper = "MBC5"; info.rumble = true; break;
|
||||
case 0x1d: info.mapper = "MBC5"; info.rumble = true; info.ram = true; break;
|
||||
case 0x1e: info.mapper = "MBC5"; info.rumble = true; info.ram = true; info.battery = true; break;
|
||||
case 0xfc: break; //Pocket Camera
|
||||
case 0xfd: break; //Bandai TAMA5
|
||||
case 0xfe: info.mapper = "HuC3"; break;
|
||||
case 0xff: info.mapper = "HuC1"; info.ram = true; info.battery = true; break;
|
||||
}
|
||||
|
||||
switch(romdata[0x0148]) { default:
|
||||
case 0x00: info.romsize = 2 * 16 * 1024; break;
|
||||
case 0x01: info.romsize = 4 * 16 * 1024; break;
|
||||
case 0x02: info.romsize = 8 * 16 * 1024; break;
|
||||
case 0x03: info.romsize = 16 * 16 * 1024; break;
|
||||
case 0x04: info.romsize = 32 * 16 * 1024; break;
|
||||
case 0x05: info.romsize = 64 * 16 * 1024; break;
|
||||
case 0x06: info.romsize = 128 * 16 * 1024; break;
|
||||
case 0x07: info.romsize = 256 * 16 * 1024; break;
|
||||
case 0x52: info.romsize = 72 * 16 * 1024; break;
|
||||
case 0x53: info.romsize = 80 * 16 * 1024; break;
|
||||
case 0x54: info.romsize = 96 * 16 * 1024; break;
|
||||
}
|
||||
|
||||
switch(romdata[0x0149]) { default:
|
||||
case 0x00: info.ramsize = 0 * 1024; break;
|
||||
case 0x01: info.ramsize = 2 * 1024; break;
|
||||
case 0x02: info.ramsize = 8 * 1024; break;
|
||||
case 0x03: info.ramsize = 32 * 1024; break;
|
||||
}
|
||||
|
||||
if(info.mapper == "MBC2") info.ramsize = 512; //512 x 4-bit
|
||||
|
||||
xml << "<cartridge mapper='" << info.mapper << "'";
|
||||
if(info.rtc) xml << " rtc='true'";
|
||||
if(info.rumble) xml << " rumble='true'";
|
||||
xml << ">\n";
|
||||
|
||||
xml << " <rom size='" << hex(romsize) << "'/>\n"; //TODO: trust/check info.romsize?
|
||||
|
||||
if(info.ramsize > 0)
|
||||
xml << " <ram size='" << hex(info.ramsize) << "' battery='" << info.battery << "'/>\n";
|
||||
|
||||
xml << "</cartridge>\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -145,23 +145,23 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
|
|||
xml << " <map mode='linear' address='00-7f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-ff:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <supergameboy revision='1'>\n";
|
||||
xml << " <icd2 revision='1'>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:6000-7fff'/>\n";
|
||||
xml << " <map address='80-bf:6000-7fff'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </supergameboy>\n";
|
||||
xml << " </icd2>\n";
|
||||
} else if(type == TypeSuperGameBoy2Bios) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='linear' address='00-7f:8000-ffff'/>\n";
|
||||
xml << " <map mode='linear' address='80-ff:8000-ffff'/>\n";
|
||||
xml << " </rom>\n";
|
||||
xml << " <supergameboy revision='2'>\n";
|
||||
xml << " <icd2 revision='2'>\n";
|
||||
xml << " <mmio>\n";
|
||||
xml << " <map address='00-3f:6000-7fff'/>\n";
|
||||
xml << " <map address='80-bf:6000-7fff'/>\n";
|
||||
xml << " </mmio>\n";
|
||||
xml << " </supergameboy>\n";
|
||||
xml << " </icd2>\n";
|
||||
} else if(has_spc7110) {
|
||||
xml << " <rom>\n";
|
||||
xml << " <map mode='shadow' address='00-0f:8000-ffff'/>\n";
|
||||
|
|
|
@ -14,7 +14,6 @@ namespace memory {
|
|||
MappedRAM bsxflash, bsxram, bsxpram;
|
||||
MappedRAM stArom, stAram;
|
||||
MappedRAM stBrom, stBram;
|
||||
MappedRAM gbrom, gbram, gbrtc;
|
||||
};
|
||||
|
||||
Cartridge cartridge;
|
||||
|
@ -25,8 +24,6 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
|
|||
ram_size = 0;
|
||||
spc7110_data_rom_offset = 0x100000;
|
||||
supergameboy_version = SuperGameBoyVersion::Version1;
|
||||
supergameboy_ram_size = 0;
|
||||
supergameboy_rtc_size = 0;
|
||||
|
||||
has_bsx_slot = false;
|
||||
has_superfx = false;
|
||||
|
@ -45,7 +42,7 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
|
|||
has_serial = false;
|
||||
|
||||
parse_xml(xml_list);
|
||||
//print(xml_list[0], "\n");
|
||||
//foreach(xml_item, xml_list) print(xml_item, "\n\n");
|
||||
|
||||
if(ram_size > 0) {
|
||||
memory::cartram.map(allocate<uint8_t>(ram_size, 0xff), ram_size);
|
||||
|
@ -65,13 +62,6 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
|
|||
if(memory::stBrom.data()) memory::stBram.map(allocate<uint8_t>(128 * 1024, 0xff), 128 * 1024);
|
||||
}
|
||||
|
||||
if(mode == Mode::SuperGameBoy) {
|
||||
if(memory::gbrom.data()) {
|
||||
if(supergameboy_ram_size) memory::gbram.map(allocate<uint8_t>(supergameboy_ram_size, 0xff), supergameboy_ram_size);
|
||||
if(supergameboy_rtc_size) memory::gbrtc.map(allocate<uint8_t>(supergameboy_rtc_size, 0x00), supergameboy_rtc_size);
|
||||
}
|
||||
}
|
||||
|
||||
memory::cartrom.write_protect(true);
|
||||
memory::cartram.write_protect(false);
|
||||
memory::cartrtc.write_protect(false);
|
||||
|
@ -82,15 +72,11 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
|
|||
memory::stAram.write_protect(false);
|
||||
memory::stBrom.write_protect(true);
|
||||
memory::stBram.write_protect(false);
|
||||
memory::gbrom.write_protect(true);
|
||||
memory::gbram.write_protect(false);
|
||||
memory::gbrtc.write_protect(false);
|
||||
|
||||
unsigned checksum = ~0; foreach(n, memory::cartrom ) checksum = crc32_adjust(checksum, n);
|
||||
if(memory::bsxflash.size() != 0 && memory::bsxflash.size() != ~0) foreach(n, memory::bsxflash) checksum = crc32_adjust(checksum, n);
|
||||
if(memory::stArom.size() != 0 && memory::stArom.size() != ~0) foreach(n, memory::stArom ) checksum = crc32_adjust(checksum, n);
|
||||
if(memory::stBrom.size() != 0 && memory::stBrom.size() != ~0) foreach(n, memory::stBrom ) checksum = crc32_adjust(checksum, n);
|
||||
if(memory::gbrom.size() != 0 && memory::gbrom.size() != ~0) foreach(n, memory::gbrom ) checksum = crc32_adjust(checksum, n);
|
||||
crc32 = ~checksum;
|
||||
|
||||
sha256_ctx sha;
|
||||
|
@ -105,7 +91,6 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
|
|||
sha256 = hash;
|
||||
|
||||
bus.load_cart();
|
||||
system.serialize_init();
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
|
@ -120,9 +105,6 @@ void Cartridge::unload() {
|
|||
memory::stAram.reset();
|
||||
memory::stBrom.reset();
|
||||
memory::stBram.reset();
|
||||
memory::gbrom.reset();
|
||||
memory::gbram.reset();
|
||||
memory::gbrtc.reset();
|
||||
|
||||
if(loaded == false) return;
|
||||
bus.unload_cart();
|
||||
|
|
|
@ -31,8 +31,6 @@ public:
|
|||
readonly<unsigned> ram_size;
|
||||
readonly<unsigned> spc7110_data_rom_offset;
|
||||
readonly<SuperGameBoyVersion> supergameboy_version;
|
||||
readonly<unsigned> supergameboy_ram_size;
|
||||
readonly<unsigned> supergameboy_rtc_size;
|
||||
|
||||
readonly<bool> has_bsx_slot;
|
||||
readonly<bool> has_superfx;
|
||||
|
@ -83,6 +81,7 @@ private:
|
|||
|
||||
void xml_parse_rom(xml_element&);
|
||||
void xml_parse_ram(xml_element&);
|
||||
void xml_parse_icd2(xml_element&);
|
||||
void xml_parse_superfx(xml_element&);
|
||||
void xml_parse_sa1(xml_element&);
|
||||
void xml_parse_upd77c25(xml_element&);
|
||||
|
@ -109,7 +108,6 @@ namespace memory {
|
|||
extern MappedRAM bsxflash, bsxram, bsxpram;
|
||||
extern MappedRAM stArom, stAram;
|
||||
extern MappedRAM stBrom, stBram;
|
||||
extern MappedRAM gbrom, gbram, gbrtc;
|
||||
};
|
||||
|
||||
extern Cartridge cartridge;
|
||||
|
|
|
@ -24,14 +24,6 @@ void Cartridge::serialize(serializer &s) {
|
|||
if(memory::stBram.size() != 0 && memory::stBram.size() != ~0) {
|
||||
s.array(memory::stBram.data(), memory::stBram.size());
|
||||
}
|
||||
|
||||
if(memory::gbram.size() != 0 && memory::gbram.size() != ~0) {
|
||||
s.array(memory::gbram.data(), memory::gbram.size());
|
||||
}
|
||||
|
||||
if(memory::gbrtc.size() != 0 && memory::gbrtc.size() != ~0) {
|
||||
s.array(memory::gbrtc.data(), memory::gbrtc.size());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,12 +32,12 @@ void Cartridge::parse_xml_cartridge(const char *data) {
|
|||
foreach(node, head.element) {
|
||||
if(node.name == "rom") xml_parse_rom(node);
|
||||
if(node.name == "ram") xml_parse_ram(node);
|
||||
if(node.name == "icd2") xml_parse_icd2(node);
|
||||
if(node.name == "superfx") xml_parse_superfx(node);
|
||||
if(node.name == "sa1") xml_parse_sa1(node);
|
||||
if(node.name == "upd77c25") xml_parse_upd77c25(node);
|
||||
if(node.name == "bsx") xml_parse_bsx(node);
|
||||
if(node.name == "sufamiturbo") xml_parse_sufamiturbo(node);
|
||||
if(node.name == "supergameboy") xml_parse_supergameboy(node);
|
||||
if(node.name == "srtc") xml_parse_srtc(node);
|
||||
if(node.name == "sdd1") xml_parse_sdd1(node);
|
||||
if(node.name == "spc7110") xml_parse_spc7110(node);
|
||||
|
@ -59,28 +59,6 @@ void Cartridge::parse_xml_sufami_turbo(const char *data, bool slot) {
|
|||
}
|
||||
|
||||
void Cartridge::parse_xml_gameboy(const char *data) {
|
||||
xml_element document = xml_parse(data);
|
||||
if(document.element.size() == 0) return;
|
||||
|
||||
foreach(head, document.element) {
|
||||
if(head.name == "cartridge") {
|
||||
foreach(attr, head.attribute) {
|
||||
if(attr.name == "rtc") {
|
||||
supergameboy_rtc_size = (attr.content == "true") ? 4 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
foreach(leaf, head.element) {
|
||||
if(leaf.name == "ram") {
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "size") {
|
||||
supergameboy_ram_size = hex(attr.content);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::xml_parse_rom(xml_element &root) {
|
||||
|
@ -117,6 +95,31 @@ void Cartridge::xml_parse_ram(xml_element &root) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::xml_parse_icd2(xml_element &root) {
|
||||
if(mode != Mode::SuperGameBoy) return;
|
||||
|
||||
foreach(attr, root.attribute) {
|
||||
if(attr.name == "revision") {
|
||||
if(attr.content == "1") supergameboy_version = SuperGameBoyVersion::Version1;
|
||||
if(attr.content == "2") supergameboy_version = SuperGameBoyVersion::Version2;
|
||||
}
|
||||
}
|
||||
|
||||
foreach(node, root.element) {
|
||||
if(node.name == "mmio") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m((Memory&)icd2);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::xml_parse_superfx(xml_element &root) {
|
||||
has_superfx = true;
|
||||
|
||||
|
@ -382,31 +385,6 @@ void Cartridge::xml_parse_sufamiturbo(xml_element &root) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::xml_parse_supergameboy(xml_element &root) {
|
||||
if(mode != Mode::SuperGameBoy) return;
|
||||
|
||||
foreach(attr, root.attribute) {
|
||||
if(attr.name == "revision") {
|
||||
if(attr.content == "1") supergameboy_version = SuperGameBoyVersion::Version1;
|
||||
if(attr.content == "2") supergameboy_version = SuperGameBoyVersion::Version2;
|
||||
}
|
||||
}
|
||||
|
||||
foreach(node, root.element) {
|
||||
if(node.name == "mmio") {
|
||||
foreach(leaf, node.element) {
|
||||
if(leaf.name == "map") {
|
||||
Mapping m((Memory&)icd2);
|
||||
foreach(attr, leaf.attribute) {
|
||||
if(attr.name == "address") xml_parse_address(m, attr.content);
|
||||
}
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::xml_parse_srtc(xml_element &root) {
|
||||
has_srtc = true;
|
||||
|
||||
|
|
|
@ -5,12 +5,17 @@ namespace SNES {
|
|||
|
||||
#include "interface/interface.cpp"
|
||||
#include "mmio/mmio.cpp"
|
||||
#include "serialization.cpp"
|
||||
ICD2 icd2;
|
||||
|
||||
void ICD2::Enter() { icd2.enter(); }
|
||||
|
||||
void ICD2::enter() {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
if(r6003 & 0x80) {
|
||||
GameBoy::system.run();
|
||||
step(GameBoy::system.clocks_executed);
|
||||
|
@ -63,7 +68,6 @@ void ICD2::reset() {
|
|||
pulselock = true;
|
||||
|
||||
GameBoy::system.init(this);
|
||||
GameBoy::cartridge.load(memory::gbrom.data(), memory::gbrom.size());
|
||||
GameBoy::system.power();
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ public:
|
|||
void power();
|
||||
void reset();
|
||||
|
||||
void serialize(serializer&);
|
||||
|
||||
private:
|
||||
#include "interface/interface.hpp"
|
||||
#include "mmio/mmio.hpp"
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
#ifdef ICD2_CPP
|
||||
|
||||
void ICD2::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
|
||||
GameBoy::system.runtosave();
|
||||
GameBoy::system.serialize_all(s);
|
||||
|
||||
for(unsigned n = 0; n < 64; n++) s.array(packet[n].data);
|
||||
s.integer(packetsize);
|
||||
|
||||
s.integer(joyp_id);
|
||||
s.integer(joyp15lock);
|
||||
s.integer(joyp14lock);
|
||||
s.integer(pulselock);
|
||||
s.integer(strobelock);
|
||||
s.integer(packetlock);
|
||||
s.array(joyp_packet.data);
|
||||
s.integer(packetoffset);
|
||||
s.integer(bitdata);
|
||||
s.integer(bitoffset);
|
||||
|
||||
s.integer(r2181);
|
||||
s.integer(r2182);
|
||||
|
||||
s.integer(r6000);
|
||||
s.integer(r6003);
|
||||
s.integer(r6004);
|
||||
s.integer(r6005);
|
||||
s.integer(r6006);
|
||||
s.integer(r6007);
|
||||
s.array(r7000);
|
||||
s.integer(r7800);
|
||||
s.integer(mlt_req);
|
||||
|
||||
s.array(vram);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,7 +1,7 @@
|
|||
namespace SNES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bsnes";
|
||||
static const char Version[] = "073.02";
|
||||
static const char Version[] = "073.03";
|
||||
static const unsigned SerializerVersion = 16;
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ namespace SNES {
|
|||
#include <nall/utility.hpp>
|
||||
#include <nall/varint.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
#include <nall/gameboy/cartridge.hpp>
|
||||
using namespace nall;
|
||||
|
||||
#include <gameboy/gameboy.hpp>
|
||||
|
|
|
@ -57,7 +57,7 @@ void System::serialize_all(serializer &s) {
|
|||
ppu.serialize(s);
|
||||
dsp.serialize(s);
|
||||
|
||||
//if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) supergameboy.serialize(s);
|
||||
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.serialize(s);
|
||||
if(cartridge.has_superfx()) superfx.serialize(s);
|
||||
if(cartridge.has_sa1()) sa1.serialize(s);
|
||||
if(cartridge.has_upd77c25()) upd77c25.serialize(s);
|
||||
|
@ -71,7 +71,7 @@ void System::serialize_all(serializer &s) {
|
|||
if(cartridge.has_serial()) serial.serialize(s);
|
||||
}
|
||||
|
||||
//called once upon cartridge load event: perform dry-run state save.
|
||||
//perform dry-run state save:
|
||||
//determines exactly how many bytes are needed to save state for this cartridge,
|
||||
//as amount varies per game (eg different RAM sizes, special chips, etc.)
|
||||
void System::serialize_init() {
|
||||
|
|
|
@ -167,6 +167,7 @@ void System::power() {
|
|||
if(cartridge.has_serial()) cpu.coprocessors.append(&serial);
|
||||
|
||||
scheduler.init();
|
||||
serialize_init();
|
||||
|
||||
input.update();
|
||||
//video.update();
|
||||
|
@ -206,6 +207,7 @@ void System::reset() {
|
|||
if(cartridge.has_serial()) cpu.coprocessors.append(&serial);
|
||||
|
||||
scheduler.init();
|
||||
serialize_init();
|
||||
|
||||
input.port_set_device(0, config.controller_port1);
|
||||
input.port_set_device(1, config.controller_port2);
|
||||
|
@ -214,7 +216,6 @@ void System::reset() {
|
|||
}
|
||||
|
||||
void System::unload() {
|
||||
//if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) supergameboy.unload();
|
||||
}
|
||||
|
||||
void System::scanline() {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <nall/input.hpp>
|
||||
#include <nall/ups.hpp>
|
||||
#include <nall/snes/cartridge.hpp>
|
||||
#include <nall/gameboy/cartridge.hpp>
|
||||
using namespace nall;
|
||||
|
||||
#include <ruby/ruby.hpp>
|
||||
|
|
|
@ -56,12 +56,28 @@ bool Cartridge::loadSufamiTurbo(const char *basename, const char *slotAname, con
|
|||
bool Cartridge::loadSuperGameBoy(const char *basename, const char *slotname) {
|
||||
unload();
|
||||
if(loadCartridge(SNES::memory::cartrom, baseXML, basename) == false) return false;
|
||||
loadCartridge(SNES::memory::gbrom, slotAXML, slotname);
|
||||
|
||||
file fp;
|
||||
if(fp.open(slotname, file::mode::read)) {
|
||||
unsigned size = fp.size();
|
||||
uint8_t *data = new uint8_t[size];
|
||||
fp.read(data, size);
|
||||
fp.close();
|
||||
|
||||
GameBoyCartridge info(data, size);
|
||||
GameBoy::cartridge.load(info.xml, data, size);
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
SNES::cartridge.basename = baseName = nall::basename(basename);
|
||||
slotAName = nall::basename(slotname);
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::SuperGameBoy, { baseXML, slotAXML });
|
||||
loadMemory(SNES::memory::gbram, slotAName, ".sav");
|
||||
loadMemory(SNES::memory::gbrtc, slotAName, ".rtc");
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::SuperGameBoy, { baseXML, "" });
|
||||
|
||||
if(GameBoy::cartridge.info.battery && fp.open(string(slotAName, ".sav"), file::mode::read)) {
|
||||
fp.read(GameBoy::cartridge.ramdata, min(GameBoy::cartridge.ramsize, fp.size()));
|
||||
fp.close();
|
||||
}
|
||||
|
||||
utility.cartridgeLoaded();
|
||||
return true;
|
||||
}
|
||||
|
@ -75,8 +91,15 @@ void Cartridge::unload() {
|
|||
saveMemory(SNES::memory::bsxpram, baseName, ".psr");
|
||||
saveMemory(SNES::memory::stAram, slotAName, ".srm");
|
||||
saveMemory(SNES::memory::stBram, slotBName, ".srm");
|
||||
saveMemory(SNES::memory::gbram, slotAName, ".sav");
|
||||
saveMemory(SNES::memory::gbrtc, slotAName, ".rtc");
|
||||
|
||||
if(SNES::cartridge.mode() == SNES::Cartridge::Mode::SuperGameBoy) {
|
||||
file fp;
|
||||
if(GameBoy::cartridge.info.battery && fp.open(string(slotAName, ".sav"), file::mode::write)) {
|
||||
fp.write(GameBoy::cartridge.ramdata, GameBoy::cartridge.ramsize);
|
||||
fp.close();
|
||||
}
|
||||
}
|
||||
|
||||
utility.cartridgeUnloaded();
|
||||
baseName = slotAName = slotBName = "";
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue