mirror of https://github.com/bsnes-emu/bsnes.git
Update to v086r02 release.
byuu says: Fixed Super Game Boy RAM saving and loading. It plainly wasn't hooked up at all. Was apparently hard-coded before it became a multi-emulator. I also fixed a crashing issue when loading Satellaview-slotted or Satellaview games without specifying the sub-cart, wasn't setting has_bsx_slot = true, so the raw memory wasn't being allocated internally when it wasn't mapped in. Of course a better fix would be to just not physically map the ranges if the things aren't present. Kind of a lazy hack to map blank cartridges there, but oh well. Oh, fixed title displays as well; and did the best I could for now with regards to multi-file path saving.
This commit is contained in:
parent
a37ce1cb2f
commit
6cfb9e89e7
|
@ -1,7 +1,7 @@
|
||||||
#ifndef BASE_HPP
|
#ifndef BASE_HPP
|
||||||
#define BASE_HPP
|
#define BASE_HPP
|
||||||
|
|
||||||
const char Version[] = "086.01";
|
const char Version[] = "086.02";
|
||||||
|
|
||||||
#include <nall/platform.hpp>
|
#include <nall/platform.hpp>
|
||||||
#include <nall/algorithm.hpp>
|
#include <nall/algorithm.hpp>
|
||||||
|
|
|
@ -34,7 +34,7 @@ void Cartridge::load(Mode cartridge_mode, const char *markup) {
|
||||||
nvram.reset();
|
nvram.reset();
|
||||||
|
|
||||||
parse_markup(markup);
|
parse_markup(markup);
|
||||||
//print(markup, "\n\n");
|
print(markup, "\n\n");
|
||||||
|
|
||||||
if(ram_size > 0) {
|
if(ram_size > 0) {
|
||||||
ram.map(allocate<uint8>(ram_size, 0xff), ram_size);
|
ram.map(allocate<uint8>(ram_size, 0xff), ram_size);
|
||||||
|
|
|
@ -334,6 +334,7 @@ void Cartridge::parse_markup_hitachidsp(XML::Node &root) {
|
||||||
void Cartridge::parse_markup_bsx(XML::Node &root) {
|
void Cartridge::parse_markup_bsx(XML::Node &root) {
|
||||||
if(root.exists() == false) return;
|
if(root.exists() == false) return;
|
||||||
if(mode != Mode::BsxSlotted && mode != Mode::Bsx) return;
|
if(mode != Mode::BsxSlotted && mode != Mode::Bsx) return;
|
||||||
|
has_bsx_slot = true;
|
||||||
|
|
||||||
for(auto &node : root["slot"]) {
|
for(auto &node : root["slot"]) {
|
||||||
if(node.name != "map") continue;
|
if(node.name != "map") continue;
|
||||||
|
|
|
@ -16,11 +16,13 @@ bool InterfaceGameBoy::loadCartridge(GameBoy::System::Revision revision, const s
|
||||||
interface->base = { true, filename };
|
interface->base = { true, filename };
|
||||||
} else {
|
} else {
|
||||||
if(file::read(filename, data, size) == false) return false;
|
if(file::read(filename, data, size) == false) return false;
|
||||||
interface->base.name = { false, nall::basename(filename) };
|
interface->base = { false, nall::basename(filename) };
|
||||||
}
|
}
|
||||||
|
|
||||||
interface->unloadCartridge();
|
interface->unloadCartridge();
|
||||||
//interface->applyPatch(interface->baseName, data, size);
|
interface->game = interface->base;
|
||||||
|
interface->cartridgeTitle = interface->base.title();
|
||||||
|
interface->applyPatch(interface->base, data, size);
|
||||||
|
|
||||||
string markup;
|
string markup;
|
||||||
markup.readfile(interface->base.filename("manifest.xml", ".xml"));
|
markup.readfile(interface->base.filename("manifest.xml", ".xml"));
|
||||||
|
|
|
@ -28,6 +28,17 @@ string CartridgePath::filename(const string &folderName, const string &fileName)
|
||||||
return { name, fileName };
|
return { name, fileName };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string CartridgePath::title() const {
|
||||||
|
if(name.empty()) return "";
|
||||||
|
if(folder) {
|
||||||
|
string title = name;
|
||||||
|
title.rtrim<1>("/");
|
||||||
|
title = notdir(nall::basename(title));
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
return notdir(nall::basename(name));
|
||||||
|
}
|
||||||
|
|
||||||
void Interface::bindControllers() {
|
void Interface::bindControllers() {
|
||||||
switch(mode()) {
|
switch(mode()) {
|
||||||
case Mode::NES:
|
case Mode::NES:
|
||||||
|
@ -85,10 +96,10 @@ void Interface::loadCartridge(Mode mode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bindControllers();
|
bindControllers();
|
||||||
cheatEditor->load(base.filename("cheats.xml", ".cht"));
|
cheatEditor->load(game.filename("cheats.xml", ".cht"));
|
||||||
stateManager->load(base.filename("states.bsa", ".bsa"), 0u);
|
stateManager->load(game.filename("states.bsa", ".bsa"), 0u);
|
||||||
dipSwitches->load();
|
dipSwitches->load();
|
||||||
utility->showMessage({ "Loaded ", notdir(baseName) });
|
utility->showMessage({ "Loaded ", cartridgeTitle });
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Interface::loadCartridge(const string &filename) {
|
bool Interface::loadCartridge(const string &filename) {
|
||||||
|
@ -103,8 +114,8 @@ bool Interface::loadCartridge(const string &filename) {
|
||||||
void Interface::unloadCartridge() {
|
void Interface::unloadCartridge() {
|
||||||
if(cartridgeLoaded() == false) return;
|
if(cartridgeLoaded() == false) return;
|
||||||
cheatDatabase->setVisible(false);
|
cheatDatabase->setVisible(false);
|
||||||
cheatEditor->save(base.filename("cheats.xml", ".cht"));
|
cheatEditor->save(game.filename("cheats.xml", ".cht"));
|
||||||
stateManager->save(base.filename("states.bsa", ".bsa"), 0u);
|
stateManager->save(game.filename("states.bsa", ".bsa"), 0u);
|
||||||
setCheatCodes();
|
setCheatCodes();
|
||||||
|
|
||||||
switch(mode()) {
|
switch(mode()) {
|
||||||
|
@ -113,7 +124,7 @@ void Interface::unloadCartridge() {
|
||||||
case Mode::GameBoy: gameBoy.unloadCartridge(); break;
|
case Mode::GameBoy: gameBoy.unloadCartridge(); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface->baseName = "";
|
cartridgeTitle = "";
|
||||||
utility->setMode(mode = Mode::None);
|
utility->setMode(mode = Mode::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +156,7 @@ bool Interface::unserialize(serializer &s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Interface::saveState(unsigned slot) {
|
bool Interface::saveState(unsigned slot) {
|
||||||
string filename = base.filename({ "state-", slot, ".bst" }, { "-", slot, ".bst" });
|
string filename = game.filename({ "state-", slot, ".bst" }, { "-", slot, ".bst" });
|
||||||
serializer s = serialize();
|
serializer s = serialize();
|
||||||
bool result = file::write(filename, s.data(), s.size());
|
bool result = file::write(filename, s.data(), s.size());
|
||||||
utility->showMessage(result == true ? string{ "Saved state ", slot } : "Failed to save state");
|
utility->showMessage(result == true ? string{ "Saved state ", slot } : "Failed to save state");
|
||||||
|
@ -153,7 +164,7 @@ bool Interface::saveState(unsigned slot) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Interface::loadState(unsigned slot) {
|
bool Interface::loadState(unsigned slot) {
|
||||||
string filename = base.filename({ "state-", slot, ".bst" }, { "-", slot, ".bst" });
|
string filename = game.filename({ "state-", slot, ".bst" }, { "-", slot, ".bst" });
|
||||||
uint8_t *data;
|
uint8_t *data;
|
||||||
unsigned size;
|
unsigned size;
|
||||||
if(file::read(filename, data, size) == false) {
|
if(file::read(filename, data, size) == false) {
|
||||||
|
@ -193,8 +204,8 @@ Interface::Interface() : core(nullptr) {
|
||||||
|
|
||||||
//internal
|
//internal
|
||||||
|
|
||||||
bool Interface::applyPatch(const string &filename, uint8_t *&data, unsigned &size) {
|
bool Interface::applyPatch(CartridgePath &filepath, uint8_t *&data, unsigned &size) {
|
||||||
string patchname = { nall::basename(filename), ".bps" };
|
string patchname = filepath.filename("patch.bps", ".bps");
|
||||||
if(file::exists(patchname) == false) return false;
|
if(file::exists(patchname) == false) return false;
|
||||||
|
|
||||||
bpspatch bps;
|
bpspatch bps;
|
||||||
|
|
|
@ -13,6 +13,7 @@ struct CartridgePath {
|
||||||
bool folder;
|
bool folder;
|
||||||
string name;
|
string name;
|
||||||
string filename(const string &folderName, const string &fileName) const;
|
string filename(const string &folderName, const string &fileName) const;
|
||||||
|
string title() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "nes/nes.hpp"
|
#include "nes/nes.hpp"
|
||||||
|
@ -61,14 +62,13 @@ struct Interface : property<Interface> {
|
||||||
|
|
||||||
Interface();
|
Interface();
|
||||||
|
|
||||||
bool applyPatch(const string &filename, uint8_t *&data, unsigned &size);
|
bool applyPatch(CartridgePath &filepath, uint8_t *&data, unsigned &size);
|
||||||
void videoRefresh(const uint32_t *input, unsigned inputPitch, unsigned width, unsigned height);
|
void videoRefresh(const uint32_t *input, unsigned inputPitch, unsigned width, unsigned height);
|
||||||
|
|
||||||
CartridgePath base;
|
CartridgePath base; //base cartridge connected to emulated system
|
||||||
vector<CartridgePath> slot;
|
CartridgePath slot[2]; //slot cartridges connected to base cartridge
|
||||||
|
CartridgePath game; //where to store resources (cheats.xml, states.bsa, ...)
|
||||||
//deprecated
|
string cartridgeTitle; //combined name of game ([base] + [slot ...])
|
||||||
string baseName; // = "/path/to/cartridge" (no extension)
|
|
||||||
|
|
||||||
InterfaceCore *core;
|
InterfaceCore *core;
|
||||||
InterfaceNES nes;
|
InterfaceNES nes;
|
||||||
|
|
|
@ -48,7 +48,9 @@ bool InterfaceNES::loadCartridge(const string &filename) {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface->unloadCartridge();
|
interface->unloadCartridge();
|
||||||
//interface->applyPatch(interface->base.filename("patch.bps", ".bps"), data, size);
|
interface->game = interface->base;
|
||||||
|
interface->cartridgeTitle = interface->base.title();
|
||||||
|
interface->applyPatch(interface->base, data, size);
|
||||||
|
|
||||||
string markup;
|
string markup;
|
||||||
markup.readfile(interface->base.filename("manifest.xml", ".xml"));
|
markup.readfile(interface->base.filename("manifest.xml", ".xml"));
|
||||||
|
|
|
@ -31,6 +31,7 @@ bool InterfaceSNES::cartridgeLoaded() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InterfaceSNES::loadCartridge(const string &filename, CartridgePath &cartridge, uint8_t *&data, unsigned &size) {
|
bool InterfaceSNES::loadCartridge(const string &filename, CartridgePath &cartridge, uint8_t *&data, unsigned &size) {
|
||||||
|
data = nullptr, size = 0u;
|
||||||
auto backup = cartridge;
|
auto backup = cartridge;
|
||||||
string suffix;
|
string suffix;
|
||||||
if(filename.endswith("/")) {
|
if(filename.endswith("/")) {
|
||||||
|
@ -43,7 +44,7 @@ bool InterfaceSNES::loadCartridge(const string &filename, CartridgePath &cartrid
|
||||||
cartridge = backup;
|
cartridge = backup;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
//interface->applyPatch(filename, data, size);
|
interface->applyPatch(cartridge, data, size);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +52,10 @@ bool InterfaceSNES::loadCartridge(string basename) {
|
||||||
uint8_t *data;
|
uint8_t *data;
|
||||||
unsigned size;
|
unsigned size;
|
||||||
if(loadCartridge(basename, interface->base, data, size) == false) return false;
|
if(loadCartridge(basename, interface->base, data, size) == false) return false;
|
||||||
|
|
||||||
interface->unloadCartridge();
|
interface->unloadCartridge();
|
||||||
|
interface->game = interface->base;
|
||||||
|
interface->cartridgeTitle = interface->base.title();
|
||||||
|
|
||||||
string markup;
|
string markup;
|
||||||
markup.readfile(interface->base.filename("manifest.xml", ".xml"));
|
markup.readfile(interface->base.filename("manifest.xml", ".xml"));
|
||||||
|
@ -73,8 +77,12 @@ bool InterfaceSNES::loadSatellaviewSlottedCartridge(string basename, string slot
|
||||||
uint8_t *data[2];
|
uint8_t *data[2];
|
||||||
unsigned size[2];
|
unsigned size[2];
|
||||||
if(loadCartridge(basename, interface->base, data[0], size[0]) == false) return false;
|
if(loadCartridge(basename, interface->base, data[0], size[0]) == false) return false;
|
||||||
loadCartridge(slotname, interface->slot(0), data[1], size[1]);
|
loadCartridge(slotname, interface->slot[0], data[1], size[1]);
|
||||||
|
|
||||||
interface->unloadCartridge();
|
interface->unloadCartridge();
|
||||||
|
interface->game = !data[1] ? interface->base : interface->slot[0]; //TODO: subfolder for folders; concatenation for files
|
||||||
|
interface->cartridgeTitle = interface->base.title();
|
||||||
|
if(data[1]) interface->cartridgeTitle.append(" + ", interface->slot[0].title());
|
||||||
|
|
||||||
string markup;
|
string markup;
|
||||||
markup.readfile(interface->base.filename("manifest.xml", ".xml"));
|
markup.readfile(interface->base.filename("manifest.xml", ".xml"));
|
||||||
|
@ -98,8 +106,12 @@ bool InterfaceSNES::loadSatellaviewCartridge(string basename, string slotname) {
|
||||||
uint8_t *data[2];
|
uint8_t *data[2];
|
||||||
unsigned size[2];
|
unsigned size[2];
|
||||||
if(loadCartridge(basename, interface->base, data[0], size[0]) == false) return false;
|
if(loadCartridge(basename, interface->base, data[0], size[0]) == false) return false;
|
||||||
loadCartridge(slotname, interface->slot(0), data[1], size[1]);
|
loadCartridge(slotname, interface->slot[0], data[1], size[1]);
|
||||||
|
|
||||||
interface->unloadCartridge();
|
interface->unloadCartridge();
|
||||||
|
interface->game = !data[1] ? interface->base : interface->slot[0];
|
||||||
|
interface->cartridgeTitle = interface->base.title();
|
||||||
|
if(data[1]) interface->cartridgeTitle = interface->slot[0].title();
|
||||||
|
|
||||||
string markup;
|
string markup;
|
||||||
markup.readfile(interface->base.filename("manifest.xml", ".xml"));
|
markup.readfile(interface->base.filename("manifest.xml", ".xml"));
|
||||||
|
@ -123,9 +135,17 @@ bool InterfaceSNES::loadSufamiTurboCartridge(string basename, string slotAname,
|
||||||
uint8_t *data[3];
|
uint8_t *data[3];
|
||||||
unsigned size[3];
|
unsigned size[3];
|
||||||
if(loadCartridge(basename, interface->base, data[0], size[0]) == false) return false;
|
if(loadCartridge(basename, interface->base, data[0], size[0]) == false) return false;
|
||||||
loadCartridge(slotAname, interface->slot(0), data[1], size[1]);
|
loadCartridge(slotAname, interface->slot[0], data[1], size[1]);
|
||||||
loadCartridge(slotBname, interface->slot(1), data[2], size[2]);
|
loadCartridge(slotBname, interface->slot[1], data[2], size[2]);
|
||||||
|
|
||||||
interface->unloadCartridge();
|
interface->unloadCartridge();
|
||||||
|
interface->game = !data[1] ? interface->base : interface->slot[0]; //TODO: subfolder for folders; concatenation for files
|
||||||
|
interface->cartridgeTitle = interface->base.title();
|
||||||
|
if( data[1] && !data[2]) interface->cartridgeTitle = interface->slot[0].title();
|
||||||
|
if(!data[1] && data[2]) interface->cartridgeTitle = interface->slot[1].title();
|
||||||
|
if( data[1] && data[2]) interface->cartridgeTitle = {
|
||||||
|
interface->slot[0].title(), " + ", interface->slot[1].title()
|
||||||
|
};
|
||||||
|
|
||||||
string markup;
|
string markup;
|
||||||
markup.readfile(interface->base.filename("manifest.xml", ".xml"));
|
markup.readfile(interface->base.filename("manifest.xml", ".xml"));
|
||||||
|
@ -151,8 +171,12 @@ bool InterfaceSNES::loadSuperGameBoyCartridge(string basename, string slotname)
|
||||||
uint8_t *data[2];
|
uint8_t *data[2];
|
||||||
unsigned size[2];
|
unsigned size[2];
|
||||||
if(loadCartridge(basename, interface->base, data[0], size[0]) == false) return false;
|
if(loadCartridge(basename, interface->base, data[0], size[0]) == false) return false;
|
||||||
loadCartridge(slotname, interface->slot(0), data[1], size[1]);
|
loadCartridge(slotname, interface->slot[0], data[1], size[1]);
|
||||||
|
|
||||||
interface->unloadCartridge();
|
interface->unloadCartridge();
|
||||||
|
interface->game = !data[1] ? interface->base : interface->slot[0];
|
||||||
|
interface->cartridgeTitle = interface->base.title();
|
||||||
|
if(data[1]) interface->cartridgeTitle = interface->slot[0].title();
|
||||||
|
|
||||||
string markup;
|
string markup;
|
||||||
markup.readfile(interface->base.filename("manifest.xml", ".xml"));
|
markup.readfile(interface->base.filename("manifest.xml", ".xml"));
|
||||||
|
@ -179,8 +203,6 @@ bool InterfaceSNES::loadSuperGameBoyCartridge(string basename, string slotname)
|
||||||
void InterfaceSNES::unloadCartridge() {
|
void InterfaceSNES::unloadCartridge() {
|
||||||
saveMemory();
|
saveMemory();
|
||||||
SNES::cartridge.unload();
|
SNES::cartridge.unload();
|
||||||
interface->base.name = "";
|
|
||||||
interface->slot.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InterfaceSNES::power() {
|
void InterfaceSNES::power() {
|
||||||
|
@ -225,6 +247,17 @@ void InterfaceSNES::loadMemory() {
|
||||||
delete[] data;
|
delete[] data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(SNES::cartridge.mode() == SNES::Cartridge::Mode::SuperGameBoy) {
|
||||||
|
if(GameBoy::cartridge.ramsize) {
|
||||||
|
uint8_t *data;
|
||||||
|
unsigned size;
|
||||||
|
if(file::read(interface->slot[0].filename("program.ram", ".sav"), data, size)) {
|
||||||
|
memcpy(GameBoy::cartridge.ramdata, data, min(GameBoy::cartridge.ramsize, size));
|
||||||
|
delete[] data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InterfaceSNES::saveMemory() {
|
void InterfaceSNES::saveMemory() {
|
||||||
|
@ -236,6 +269,14 @@ void InterfaceSNES::saveMemory() {
|
||||||
|
|
||||||
file::write(filename, memory.data, memory.size);
|
file::write(filename, memory.data, memory.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(SNES::cartridge.mode() == SNES::Cartridge::Mode::SuperGameBoy) {
|
||||||
|
if(GameBoy::cartridge.ramsize) {
|
||||||
|
file::write(interface->slot[0].filename("program.ram", ".sav"),
|
||||||
|
GameBoy::cartridge.ramdata, GameBoy::cartridge.ramsize
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
serializer InterfaceSNES::serialize() {
|
serializer InterfaceSNES::serialize() {
|
||||||
|
|
|
@ -17,13 +17,13 @@ void Utility::setMode(Interface::Mode mode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(mode == Interface::Mode::NES) {
|
else if(mode == Interface::Mode::NES) {
|
||||||
mainWindow->setTitle(notdir(interface->baseName));
|
mainWindow->setTitle(interface->cartridgeTitle);
|
||||||
mainWindow->nesMenu.setVisible(true);
|
mainWindow->nesMenu.setVisible(true);
|
||||||
dspaudio.setChannels(1);
|
dspaudio.setChannels(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(mode == Interface::Mode::SNES) {
|
else if(mode == Interface::Mode::SNES) {
|
||||||
mainWindow->setTitle(notdir(interface->baseName));
|
mainWindow->setTitle(interface->cartridgeTitle);
|
||||||
mainWindow->snesMenu.setVisible(true);
|
mainWindow->snesMenu.setVisible(true);
|
||||||
dspaudio.setChannels(2);
|
dspaudio.setChannels(2);
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ void Utility::setMode(Interface::Mode mode) {
|
||||||
mainWindow->gameBoyMenu.setText(
|
mainWindow->gameBoyMenu.setText(
|
||||||
GameBoy::system.cgb() == false ? "Game Boy" : "Game Boy Color"
|
GameBoy::system.cgb() == false ? "Game Boy" : "Game Boy Color"
|
||||||
);
|
);
|
||||||
mainWindow->setTitle(notdir(interface->baseName));
|
mainWindow->setTitle(interface->cartridgeTitle);
|
||||||
mainWindow->gameBoyMenu.setVisible(true);
|
mainWindow->gameBoyMenu.setVisible(true);
|
||||||
dspaudio.setChannels(2);
|
dspaudio.setChannels(2);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue