mirror of https://github.com/bsnes-emu/bsnes.git
183 lines
5.1 KiB
C++
183 lines
5.1 KiB
C++
#include <gb/gb.hpp>
|
|
|
|
namespace GameBoy {
|
|
|
|
Cartridge cartridge;
|
|
#include "mbc0/mbc0.cpp"
|
|
#include "mbc1/mbc1.cpp"
|
|
#include "mbc1m/mbc1m.cpp"
|
|
#include "mbc2/mbc2.cpp"
|
|
#include "mbc3/mbc3.cpp"
|
|
#include "mbc5/mbc5.cpp"
|
|
#include "mbc6/mbc6.cpp"
|
|
#include "mbc7/mbc7.cpp"
|
|
#include "mmm01/mmm01.cpp"
|
|
#include "huc1/huc1.cpp"
|
|
#include "huc3/huc3.cpp"
|
|
#include "tama/tama.cpp"
|
|
#include "serialization.cpp"
|
|
|
|
auto Cartridge::load() -> bool {
|
|
information = {};
|
|
rom = {};
|
|
ram = {};
|
|
rtc = {};
|
|
mapper = &mbc0;
|
|
accelerometer = false;
|
|
rumble = false;
|
|
|
|
if(Model::GameBoy()) {
|
|
if(auto loaded = platform->load(ID::GameBoy, "Game Boy", "gb")) {
|
|
information.pathID = loaded.pathID();
|
|
} else return false;
|
|
}
|
|
|
|
if(Model::GameBoyColor()) {
|
|
if(auto loaded = platform->load(ID::GameBoyColor, "Game Boy Color", "gbc")) {
|
|
information.pathID = loaded.pathID();
|
|
} else return false;
|
|
}
|
|
|
|
if(Model::SuperGameBoy()) {
|
|
if(auto loaded = platform->load(ID::SuperGameBoy, "Game Boy", "gb")) {
|
|
information.pathID = loaded.pathID();
|
|
} else return false;
|
|
}
|
|
|
|
if(auto fp = platform->open(pathID(), "manifest.bml", File::Read, File::Required)) {
|
|
information.manifest = fp->reads();
|
|
} else return false;
|
|
|
|
auto document = BML::unserialize(information.manifest);
|
|
information.title = document["game/label"].text();
|
|
|
|
auto mapperID = document["game/board"].text();
|
|
if(mapperID == "MBC0" ) mapper = &mbc0;
|
|
if(mapperID == "MBC1" ) mapper = &mbc1;
|
|
if(mapperID == "MBC1M") mapper = &mbc1m;
|
|
if(mapperID == "MBC2" ) mapper = &mbc2;
|
|
if(mapperID == "MBC3" ) mapper = &mbc3;
|
|
if(mapperID == "MBC5" ) mapper = &mbc5;
|
|
if(mapperID == "MBC6" ) mapper = &mbc6;
|
|
if(mapperID == "MBC7" ) mapper = &mbc7;
|
|
if(mapperID == "MMM01") mapper = &mmm01;
|
|
if(mapperID == "HuC1" ) mapper = &huc1;
|
|
if(mapperID == "HuC3" ) mapper = &huc3;
|
|
if(mapperID == "TAMA" ) mapper = &tama;
|
|
|
|
accelerometer = (bool)document["game/board/accelerometer"];
|
|
rumble = (bool)document["game/board/rumble"];
|
|
|
|
if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=ROM,content=Program)"]}) {
|
|
rom.size = max(0x4000, (uint)memory.size);
|
|
rom.data = memory::allocate<uint8>(rom.size, 0xff);
|
|
if(auto fp = platform->open(pathID(), memory.name(), File::Read, File::Required)) {
|
|
fp->read(rom.data, min(rom.size, fp->size()));
|
|
}
|
|
}
|
|
|
|
if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=RAM,content=Save)"]}) {
|
|
ram.size = memory.size;
|
|
ram.data = memory::allocate<uint8>(ram.size, 0xff);
|
|
if(memory.nonVolatile) {
|
|
if(auto fp = platform->open(pathID(), memory.name(), File::Read, File::Optional)) {
|
|
fp->read(ram.data, min(ram.size, fp->size()));
|
|
}
|
|
}
|
|
}
|
|
|
|
if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=RTC,content=Time)"]}) {
|
|
rtc.size = memory.size;
|
|
rtc.data = memory::allocate<uint8>(rtc.size, 0xff);
|
|
if(memory.nonVolatile) {
|
|
if(auto fp = platform->open(pathID(), memory.name(), File::Read, File::Optional)) {
|
|
fp->read(rtc.data, min(rtc.size, fp->size()));
|
|
}
|
|
}
|
|
}
|
|
|
|
information.sha256 = Hash::SHA256(rom.data, rom.size).digest();
|
|
return true;
|
|
}
|
|
|
|
auto Cartridge::save() -> void {
|
|
auto document = BML::unserialize(information.manifest);
|
|
|
|
if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=RAM,content=Save)"]}) {
|
|
if(memory.nonVolatile) {
|
|
if(auto fp = platform->open(pathID(), memory.name(), File::Write)) {
|
|
fp->write(ram.data, ram.size);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=RTC,content=Time)"]}) {
|
|
if(memory.nonVolatile) {
|
|
if(auto fp = platform->open(pathID(), memory.name(), File::Write)) {
|
|
fp->write(rtc.data, rtc.size);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
auto Cartridge::unload() -> void {
|
|
delete[] rom.data;
|
|
delete[] ram.data;
|
|
delete[] rtc.data;
|
|
rom = {};
|
|
ram = {};
|
|
rtc = {};
|
|
}
|
|
|
|
auto Cartridge::readIO(uint16 addr) -> uint8 {
|
|
if(addr == 0xff50) return 0xff;
|
|
|
|
if(bootromEnable) {
|
|
const uint8* data = nullptr;
|
|
if(Model::GameBoy()) data = system.bootROM.dmg;
|
|
if(Model::GameBoyColor()) data = system.bootROM.cgb;
|
|
if(Model::SuperGameBoy()) data = system.bootROM.sgb;
|
|
if(addr >= 0x0000 && addr <= 0x00ff) return data[addr];
|
|
if(addr >= 0x0200 && addr <= 0x08ff && Model::GameBoyColor()) return data[addr - 0x100];
|
|
}
|
|
|
|
return mapper->read(addr);
|
|
}
|
|
|
|
auto Cartridge::writeIO(uint16 addr, uint8 data) -> void {
|
|
if(bootromEnable && addr == 0xff50) {
|
|
bootromEnable = false;
|
|
return;
|
|
}
|
|
|
|
mapper->write(addr, data);
|
|
}
|
|
|
|
auto Cartridge::power() -> void {
|
|
for(uint n = 0x0000; n <= 0x7fff; n++) bus.mmio[n] = this;
|
|
for(uint n = 0xa000; n <= 0xbfff; n++) bus.mmio[n] = this;
|
|
bus.mmio[0xff50] = this;
|
|
|
|
bootromEnable = true;
|
|
|
|
mapper->power();
|
|
}
|
|
|
|
auto Cartridge::second() -> void {
|
|
mapper->second();
|
|
}
|
|
|
|
auto Cartridge::Memory::read(uint address) const -> uint8 {
|
|
if(!size) return 0xff;
|
|
if(address >= size) address %= size;
|
|
return data[address];
|
|
}
|
|
|
|
auto Cartridge::Memory::write(uint address, uint8 byte) -> void {
|
|
if(!size) return;
|
|
if(address >= size) address %= size;
|
|
data[address] = byte;
|
|
}
|
|
|
|
}
|