mirror of https://github.com/bsnes-emu/bsnes.git
172 lines
5.0 KiB
C++
172 lines
5.0 KiB
C++
#include <gba/gba.hpp>
|
|
|
|
namespace GameBoyAdvance {
|
|
|
|
#include "eeprom.cpp"
|
|
#include "flashrom.cpp"
|
|
#include "serialization.cpp"
|
|
Cartridge cartridge;
|
|
|
|
string Cartridge::title() {
|
|
return information.title;
|
|
}
|
|
|
|
void Cartridge::load() {
|
|
interface->loadRequest(ID::Manifest, "manifest.bml", true);
|
|
|
|
auto document = BML::unserialize(information.markup);
|
|
information.title = document["information/title"].text();
|
|
|
|
unsigned rom_size = 0;
|
|
if(document["cartridge/rom"]) {
|
|
auto info = document["cartridge/rom"];
|
|
interface->loadRequest(ID::ROM, info["name"].text(), true);
|
|
rom_size = info["size"].decimal();
|
|
for(unsigned addr = rom_size; addr < rom.size; addr++) {
|
|
rom.data[addr] = rom.data[Bus::mirror(addr, rom_size)];
|
|
}
|
|
}
|
|
|
|
has_sram = false;
|
|
has_eeprom = false;
|
|
has_flashrom = false;
|
|
|
|
if(document["cartridge/ram"]) {
|
|
auto info = document["cartridge/ram"];
|
|
|
|
if(info["type"].text() == "SRAM" || info["type"].text() == "FRAM") {
|
|
has_sram = true;
|
|
ram.size = info["size"].decimal();
|
|
ram.mask = ram.size - 1;
|
|
for(unsigned n = 0; n < ram.size; n++) ram.data[n] = 0xff;
|
|
|
|
interface->loadRequest(ID::RAM, info["name"].text(), false);
|
|
memory.append({ID::RAM, info["name"].text()});
|
|
}
|
|
|
|
if(info["type"].text() == "EEPROM") {
|
|
has_eeprom = true;
|
|
eeprom.size = info["size"].decimal();
|
|
eeprom.bits = eeprom.size <= 512 ? 6 : 14;
|
|
if(eeprom.size == 0) eeprom.size = 8192, eeprom.bits = 0; //auto-detect size
|
|
eeprom.mask = rom_size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000;
|
|
eeprom.test = rom_size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
|
|
for(unsigned n = 0; n < eeprom.size; n++) eeprom.data[n] = 0xff;
|
|
|
|
interface->loadRequest(ID::EEPROM, info["name"].text(), false);
|
|
memory.append({ID::EEPROM, info["name"].text()});
|
|
}
|
|
|
|
if(info["type"].text() == "FlashROM") {
|
|
has_flashrom = true;
|
|
flashrom.id = info["id"].decimal();
|
|
flashrom.size = info["size"].decimal();
|
|
for(unsigned n = 0; n < flashrom.size; n++) flashrom.data[n] = 0xff;
|
|
|
|
//if FlashROM ID not provided; guess that it's a Macronix chip
|
|
//this will not work for all games; in which case, the ID must be specified manually
|
|
if(!flashrom.id && flashrom.size == 64 * 1024) flashrom.id = 0x1cc2;
|
|
if(!flashrom.id && flashrom.size == 128 * 1024) flashrom.id = 0x09c2;
|
|
|
|
interface->loadRequest(ID::FlashROM, info["name"].text(), false);
|
|
memory.append({ID::FlashROM, info["name"].text()});
|
|
}
|
|
}
|
|
|
|
sha256 = Hash::SHA256(rom.data, rom_size).digest();
|
|
|
|
system.load();
|
|
loaded = true;
|
|
}
|
|
|
|
void Cartridge::unload() {
|
|
if(loaded == false) return;
|
|
loaded = false;
|
|
memory.reset();
|
|
}
|
|
|
|
void Cartridge::power() {
|
|
eeprom.power();
|
|
flashrom.power();
|
|
}
|
|
|
|
uint8* Cartridge::ram_data() {
|
|
if(has_sram) return ram.data;
|
|
if(has_eeprom) return eeprom.data;
|
|
if(has_flashrom) return flashrom.data;
|
|
return nullptr;
|
|
}
|
|
|
|
unsigned Cartridge::ram_size() {
|
|
if(has_sram) return ram.size;
|
|
if(has_eeprom) return eeprom.size;
|
|
if(has_flashrom) return flashrom.size;
|
|
return 0;
|
|
}
|
|
|
|
auto Cartridge::read(uint8 *data, unsigned mode, uint32 addr) -> uint32 {
|
|
if(mode & Word) addr &= ~3;
|
|
if(mode & Half) addr &= ~1;
|
|
data += addr;
|
|
if(mode & Word) return data[0] << 0 | data[1] << 8 | data[2] << 16 | data[3] << 24;
|
|
if(mode & Half) return data[0] << 0 | data[1] << 8;
|
|
if(mode & Byte) return data[0];
|
|
return 0; //should never occur
|
|
}
|
|
|
|
auto Cartridge::write(uint8 *data, unsigned mode, uint32 addr, uint32 word) -> void {
|
|
if(mode & Word) addr &= ~3;
|
|
if(mode & Half) addr &= ~1;
|
|
data += addr;
|
|
if(mode & Word) {
|
|
data[0] = word >> 0;
|
|
data[1] = word >> 8;
|
|
data[2] = word >> 16;
|
|
data[3] = word >> 24;
|
|
} else if(mode & Half) {
|
|
data[0] = word >> 0;
|
|
data[1] = word >> 8;
|
|
} else if(mode & Byte) {
|
|
data[0] = word >> 0;
|
|
}
|
|
}
|
|
|
|
#define RAM_ANALYZE
|
|
|
|
auto Cartridge::rom_read(unsigned mode, uint32 addr) -> uint32 {
|
|
if(has_eeprom && (addr & eeprom.mask) == eeprom.test) return eeprom.read();
|
|
return read(rom.data, mode, addr & 0x01ff'ffff);
|
|
}
|
|
|
|
auto Cartridge::rom_write(unsigned mode, uint32 addr, uint32 word) -> void {
|
|
if(has_eeprom && (addr & eeprom.mask) == eeprom.test) return eeprom.write(word & 1);
|
|
}
|
|
|
|
auto Cartridge::ram_read(unsigned mode, uint32 addr) -> uint32 {
|
|
if(has_sram) return read(ram.data, mode, addr & ram.mask);
|
|
if(has_flashrom) return flashrom.read(addr);
|
|
return cpu.pipeline.fetch.instruction;
|
|
}
|
|
|
|
auto Cartridge::ram_write(unsigned mode, uint32 addr, uint32 word) -> void {
|
|
if(has_sram) return write(ram.data, mode, addr & ram.mask, word);
|
|
if(has_flashrom) return flashrom.write(addr, word);
|
|
}
|
|
|
|
Cartridge::Cartridge() {
|
|
loaded = false;
|
|
rom.data = new uint8[rom.size = 32 * 1024 * 1024];
|
|
ram.data = new uint8[ram.size = 32 * 1024];
|
|
eeprom.data = new uint8[eeprom.size = 8 * 1024];
|
|
flashrom.data = new uint8[flashrom.size = 128 * 1024];
|
|
}
|
|
|
|
Cartridge::~Cartridge() {
|
|
delete[] rom.data;
|
|
delete[] ram.data;
|
|
delete[] eeprom.data;
|
|
delete[] flashrom.data;
|
|
}
|
|
|
|
}
|