bsnes/sfc/cartridge/cartridge.cpp
Tim Allen 0271d6a12b Update to v094r39 release.
byuu says:

Changelog:
- SNES mid-scanline BGMODE fixes finally merged (can run
  atx2.zip{mode7.smc}+mtest(2).sfc properly now)
- Makefile now discards all built-in rules and variables
- switch on bool warning disabled for GCC now as well (was already
  disabled for Clang)
- when loading a game, if any required files are missing, display
  a warning message box (manifest.bml, program.rom, bios.rom, etc)
- when loading a game (or a game slot), if manifest.bml is missing, it
  will invoke icarus to try and generate it
  - if that fails (icarus is missing or the folder is bad), you will get
    a warning telling you that the manifest can't be loaded

The warning prompt on missing files work for both games and the .sys
folders and their files. For some reason, failing to load the DMG/CGB
BIOS is causing a crash before I can display the modal dialog. I have no
idea why, and the stack frame backtrace is junk.

I also can't seem to abort the failed loading process. If I call
Program::unloadMedia(), I get a nasty segfault. Again with a really
nasty stack trace. So for now, it'll just end up sitting there emulating
an empty ROM (solid black screen.) In time, I'd like to fix that too.

Lastly, I need a better method than popen for Windows. popen is kind of
ugly and flashes a console window for a brief second even if the
application launched is linked with -mwindows. Not sure if there even is
one (I need to read the stdout result, so CreateProcess may not work
unless I do something nasty like "> %tmp%/temp") I'm also using the
regular popen instead of _wpopen, so for this WIP, it won't work if your
game folder has non-English letters in the path.
2015-08-04 19:02:04 +10:00

208 lines
6.6 KiB
C++

#include <sfc/sfc.hpp>
#define CARTRIDGE_CPP
namespace SuperFamicom {
#include "markup.cpp"
#include "serialization.cpp"
Cartridge cartridge;
auto Cartridge::title() -> string {
if(information.title.gameBoy.empty() == false) {
return {information.title.cartridge, " + ", information.title.gameBoy};
}
if(information.title.satellaview.empty() == false) {
return {information.title.cartridge, " + ", information.title.satellaview};
}
if(information.title.sufamiTurboA.empty() == false) {
if(information.title.sufamiTurboB.empty() == true) {
return {information.title.cartridge, " + ", information.title.sufamiTurboA};
} else {
return {information.title.cartridge, " + ", information.title.sufamiTurboA, " + ", information.title.sufamiTurboB};
}
}
return information.title.cartridge;
}
auto Cartridge::load() -> void {
_region = Region::NTSC;
hasICD2 = false;
hasMCC = false;
hasNSSDIP = false;
hasEvent = false;
hasSA1 = false;
hasSuperFX = false;
hasARMDSP = false;
hasHitachiDSP = false;
hasNECDSP = false;
hasEpsonRTC = false;
hasSharpRTC = false;
hasSPC7110 = false;
hasSDD1 = false;
hasOBC1 = false;
hasMSU1 = false;
hasSuperGameBoySlot = false;
hasSatellaviewSlot = false;
hasSufamiTurboSlots = false;
information.markup.cartridge = "";
information.markup.gameBoy = "";
information.markup.satellaview = "";
information.markup.sufamiTurboA = "";
information.markup.sufamiTurboB = "";
information.title.cartridge = "";
information.title.gameBoy = "";
information.title.satellaview = "";
information.title.sufamiTurboA = "";
information.title.sufamiTurboB = "";
interface->loadRequest(ID::Manifest, "manifest.bml", true);
parseMarkup(information.markup.cartridge);
//Super Game Boy
if(cartridge.hasICD2()) {
_sha256 = Hash::SHA256(GameBoy::cartridge.romdata, GameBoy::cartridge.romsize).digest();
}
//Broadcast Satellaview
else if(cartridge.hasMCC() && cartridge.hasSatellaviewSlot()) {
_sha256 = Hash::SHA256(satellaviewcartridge.memory.data(), satellaviewcartridge.memory.size()).digest();
}
//Sufami Turbo
else if(cartridge.hasSufamiTurboSlots()) {
Hash::SHA256 sha;
sha.data(sufamiturboA.rom.data(), sufamiturboA.rom.size());
sha.data(sufamiturboB.rom.data(), sufamiturboB.rom.size());
_sha256 = sha.digest();
}
//Super Famicom
else {
Hash::SHA256 sha;
//hash each ROM image that exists; any with size() == 0 is ignored by sha256_chunk()
sha.data(rom.data(), rom.size());
sha.data(mcc.rom.data(), mcc.rom.size());
sha.data(sa1.rom.data(), sa1.rom.size());
sha.data(superfx.rom.data(), superfx.rom.size());
sha.data(hitachidsp.rom.data(), hitachidsp.rom.size());
sha.data(spc7110.prom.data(), spc7110.prom.size());
sha.data(spc7110.drom.data(), spc7110.drom.size());
sha.data(sdd1.rom.data(), sdd1.rom.size());
//hash all firmware that exists
vector<uint8> buffer;
buffer = armdsp.firmware();
sha.data(buffer.data(), buffer.size());
buffer = hitachidsp.firmware();
sha.data(buffer.data(), buffer.size());
buffer = necdsp.firmware();
sha.data(buffer.data(), buffer.size());
//finalize hash
_sha256 = sha.digest();
}
rom.write_protect(true);
ram.write_protect(false);
system.load();
_loaded = true;
}
auto Cartridge::loadSuperGameBoy() -> void {
interface->loadRequest(ID::SuperGameBoyManifest, "manifest.bml", true);
auto document = BML::unserialize(information.markup.gameBoy);
information.title.gameBoy = document["information/title"].text();
auto rom = document["cartridge/rom"];
auto ram = document["cartridge/ram"];
GameBoy::cartridge.information.markup = information.markup.gameBoy;
GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy);
if(auto name = rom["name"].text()) interface->loadRequest(ID::SuperGameBoyROM, name, true);
if(auto name = ram["name"].text()) interface->loadRequest(ID::SuperGameBoyRAM, name, false);
if(auto name = ram["name"].text()) memory.append({ID::SuperGameBoyRAM, name});
}
auto Cartridge::loadSatellaview() -> void {
interface->loadRequest(ID::SatellaviewManifest, "manifest.bml", true);
auto document = BML::unserialize(information.markup.satellaview);
information.title.satellaview = document["information/title"].text();
auto rom = document["cartridge/rom"];
if(rom["name"]) {
unsigned size = rom["size"].decimal();
satellaviewcartridge.memory.map(allocate<uint8>(size, 0xff), size);
interface->loadRequest(ID::SatellaviewROM, rom["name"].text(), true);
satellaviewcartridge.readonly = (rom["type"].text() == "MaskROM");
}
}
auto Cartridge::loadSufamiTurboA() -> void {
interface->loadRequest(ID::SufamiTurboSlotAManifest, "manifest.bml", true);
auto document = BML::unserialize(information.markup.sufamiTurboA);
information.title.sufamiTurboA = document["information/title"].text();
auto rom = document["cartridge/rom"];
auto ram = document["cartridge/ram"];
if(rom["name"]) {
unsigned size = rom["size"].decimal();
sufamiturboA.rom.map(allocate<uint8>(size, 0xff), size);
interface->loadRequest(ID::SufamiTurboSlotAROM, rom["name"].text(), true);
}
if(ram["name"]) {
unsigned size = ram["size"].decimal();
sufamiturboA.ram.map(allocate<uint8>(size, 0xff), size);
interface->loadRequest(ID::SufamiTurboSlotARAM, ram["name"].text(), false);
memory.append({ID::SufamiTurboSlotARAM, ram["name"].text()});
}
if(document["cartridge/linkable"]) {
interface->loadRequest(ID::SufamiTurboSlotB, "Sufami Turbo - Slot B", "st", false);
}
}
auto Cartridge::loadSufamiTurboB() -> void {
interface->loadRequest(ID::SufamiTurboSlotBManifest, "manifest.bml", true);
auto document = BML::unserialize(information.markup.sufamiTurboB);
information.title.sufamiTurboB = document["information/title"].text();
auto rom = document["cartridge/rom"];
auto ram = document["cartridge/ram"];
if(rom["name"]) {
unsigned size = rom["size"].decimal();
sufamiturboB.rom.map(allocate<uint8>(size, 0xff), size);
interface->loadRequest(ID::SufamiTurboSlotBROM, rom["name"].text(), true);
}
if(ram["name"]) {
unsigned size = ram["size"].decimal();
sufamiturboB.ram.map(allocate<uint8>(size, 0xff), size);
interface->loadRequest(ID::SufamiTurboSlotBRAM, ram["name"].text(), false);
memory.append({ID::SufamiTurboSlotBRAM, ram["name"].text()});
}
}
auto Cartridge::unload() -> void {
if(_loaded) {
system.unload();
rom.reset();
ram.reset();
_loaded = false;
memory.reset();
}
}
}