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:
Tim Allen 2011-01-08 21:06:09 +11:00
commit 4dbce5a0b2
32 changed files with 548 additions and 180 deletions

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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

View File

@ -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]++);

View File

@ -67,6 +67,8 @@ struct CPU : Processor, MMIO {
void interrupt_test();
void interrupt_exec(uint16 pc);
void power();
void serialize(serializer&);
CPU();
};

View File

@ -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

View File

@ -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) {

View File

@ -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;

View File

@ -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() {
}
}

View File

@ -63,6 +63,9 @@ struct LCD : Processor, MMIO {
void render_obj();
void power();
void serialize(serializer&);
LCD();
};
extern LCD lcd;

View File

@ -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

View File

@ -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() {
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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();

View File

@ -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

View File

@ -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();
}
}

View File

@ -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>

104
bsnes/nall/gameboy/cartridge.hpp Executable file
View File

@ -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

View File

@ -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";

View File

@ -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();

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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();
}

View File

@ -8,6 +8,8 @@ public:
void power();
void reset();
void serialize(serializer&);
private:
#include "interface/interface.hpp"
#include "mmio/mmio.hpp"

View File

@ -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

View File

@ -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>

View File

@ -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() {

View File

@ -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() {

View File

@ -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>

View File

@ -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 = "";
}