bsnes/gba/cartridge/cartridge.cpp

177 lines
5.1 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");
auto document = Markup::Document(information.markup);
information.title = document["information/title"].text();
unsigned rom_size = 0;
if(document["cartridge/rom"].exists()) {
auto info = document["cartridge/rom"];
interface->loadRequest(ID::ROM, info["name"].data);
rom_size = numeral(info["size"].data);
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"].exists()) {
auto info = document["cartridge/ram"];
if(info["type"].data == "SRAM" || info["type"].data == "FRAM") {
has_sram = true;
ram.size = numeral(info["size"].data);
ram.mask = ram.size - 1;
for(unsigned n = 0; n < ram.size; n++) ram.data[n] = 0xff;
interface->loadRequest(ID::RAM, info["name"].data);
memory.append({ID::RAM, info["name"].data});
}
if(info["type"].data == "EEPROM") {
has_eeprom = true;
eeprom.size = numeral(info["size"].data);
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"].data);
memory.append({ID::EEPROM, info["name"].data});
}
if(info["type"].data == "FlashROM") {
has_flashrom = true;
flashrom.id = numeral(info["id"].data);
flashrom.size = numeral(info["size"].data);
for(unsigned n = 0; n < flashrom.size; n++) flashrom.data[n] = 0xff;
interface->loadRequest(ID::FlashROM, info["name"].data);
memory.append({ID::FlashROM, info["name"].data});
}
}
sha256 = nall::sha256(rom.data, rom_size);
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 0u;
}
uint32 Cartridge::read(uint8 *data, uint32 addr, uint32 size) {
if(size == Word) addr &= ~3;
if(size == Half) addr &= ~1;
data += addr;
if(size == Word) return data[0] << 0 | data[1] << 8 | data[2] << 16 | data[3] << 24;
if(size == Half) return data[0] << 0 | data[1] << 8;
return data[0];
}
void Cartridge::write(uint8 *data, uint32 addr, uint32 size, uint32 word) {
if(size == Word) addr &= ~3;
if(size == Half) addr &= ~1;
data += addr;
switch(size) {
case Word: data[3] = word >> 24;
data[2] = word >> 16;
case Half: data[1] = word >> 8;
case Byte: data[0] = word >> 0;
}
}
#define RAM_ANALYZE
uint32 Cartridge::read(uint32 addr, uint32 size) {
#ifdef RAM_ANALYZE
if((addr & 0x0e000000) == 0x0e000000) {
static bool once = true;
if(once) once = false, print("* SRAM/FlashROM read detected\n");
}
#endif
if(has_sram && (addr & 0x0e000000 ) == 0x0e000000 ) return read(ram.data, addr & ram.mask, size);
if(has_eeprom && (addr & eeprom.mask) == eeprom.test) return eeprom.read();
if(has_flashrom && (addr & 0x0e000000 ) == 0x0e000000 ) return flashrom.read(addr);
if(addr < 0x0e000000) return read(rom.data, addr & 0x01ffffff, size);
return cpu.pipeline.fetch.instruction;
}
void Cartridge::write(uint32 addr, uint32 size, uint32 word) {
#ifdef RAM_ANALYZE
if((addr & 0x0e000000) == 0x0e000000) {
static bool once = true;
if(once) once = false, print("* SRAM/FlashROM write detected\n");
}
if((addr & 0x0f000000) == 0x0d000000) {
static bool once = true;
if(once) once = false, print("* EEPROM write detected\n");
}
if((addr & 0x0e00ffff) == 0x0e005555 && (word & 0xff) == 0xaa) {
static bool once = true;
if(once) once = false, print("* FlashROM write detected\n");
}
#endif
if(has_sram && (addr & 0x0e000000 ) == 0x0e000000 ) return write(ram.data, addr & ram.mask, size, word);
if(has_eeprom && (addr & eeprom.mask) == eeprom.test) return eeprom.write(word & 1);
if(has_flashrom && (addr & 0x0e000000 ) == 0x0e000000 ) 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;
}
}