Update to v089r07 release.

byuu says:

Not even purify makes compatible images for this WIP.
Unless you want to figure it out yourself, I'd suggest waiting for an
updated tool before using subsequent WIPs.

Changelog:
- MSU1 initializes data port + audio track to 0
- MSU1 implements audio track error flag on $2000.d3
- manifest.xml now controls file names for cartridge folders ... mostly

Regressions:
- Super Game Boy support is broken
- Sufami Turbo support is broken

So, basically Emulator::Interface() now has:

    void load(const string &manifest);
    void save();

The first one will analyze the manifest, and call all the ROM + RAM
loadRequest() commands necessary to run the game.
The second one will call saveRequest() commands on all writable and
non-volatile storage (basically if it's a RAM type and has a filename
specified, it gets saved to disk.)
save() shrinks the size of Emulator::Interface() by hiding information
one is unlikely to care about. It also makes it much easier to save.
The core auto-calls this when you unload a game as well. So the only
time you ever have to worry about it is if you want to save RAM files
mid-game (in case you want to do periodic backups in case of a crash.)
This commit is contained in:
Tim Allen 2012-05-26 18:18:42 +10:00
parent d418eda97c
commit 9a8a54c75e
64 changed files with 465 additions and 281 deletions

View File

@ -3,7 +3,7 @@
namespace Emulator {
static const char Name[] = "bsnes";
static const char Version[] = "089.06";
static const char Version[] = "089.07";
static const char Author[] = "byuu";
static const char License[] = "GPLv3";
}

View File

@ -24,12 +24,6 @@ struct Interface {
vector<Media> firmware;
vector<Media> media;
struct Memory {
unsigned id;
string name;
};
vector<Memory> memory;
struct Device {
unsigned id;
unsigned portmask;
@ -52,8 +46,9 @@ struct Interface {
vector<Port> port;
struct Bind {
virtual void loadRequest(unsigned, const string&) {}
virtual void loadRequest(unsigned, const string&, const string&, const string&) {}
virtual void loadRequest(unsigned, const string&) {}
virtual void saveRequest(unsigned, const string&) {}
virtual uint32_t videoColor(unsigned, uint16_t, uint16_t, uint16_t) { return 0u; }
virtual void videoRefresh(const uint32_t*, unsigned, unsigned, unsigned) {}
virtual void audioSample(int16_t, int16_t) {}
@ -63,8 +58,9 @@ struct Interface {
} *bind;
//callback bindings (provided by user interface)
void loadRequest(unsigned id, const string &path) { return bind->loadRequest(id, path); }
void loadRequest(unsigned id, const string &name, const string &type, const string &path) { return bind->loadRequest(id, name, type, path); }
void loadRequest(unsigned id, const string &path) { return bind->loadRequest(id, path); }
void saveRequest(unsigned id, const string &path) { return bind->saveRequest(id, path); }
uint32_t videoColor(unsigned source, uint16_t red, uint16_t green, uint16_t blue) { return bind->videoColor(source, red, green, blue); }
void videoRefresh(const uint32_t *data, unsigned pitch, unsigned width, unsigned height) { return bind->videoRefresh(data, pitch, width, height); }
void audioSample(int16_t lsample, int16_t rsample) { return bind->audioSample(lsample, rsample); }
@ -80,6 +76,8 @@ struct Interface {
virtual bool loaded() { return false; }
virtual string sha256() { return ""; }
virtual unsigned group(unsigned id) { return 0u; }
virtual void load(unsigned id, const string &manifest) {}
virtual void save() {}
virtual void load(unsigned id, const stream &memory, const string &markup = "") {}
virtual void save(unsigned id, const stream &memory) {}
virtual void unload() {}

View File

@ -111,7 +111,7 @@ void serialize(serializer &s) {
s.integer(irq_latch);
}
BandaiFCG(XML::Document &document, const stream &memory) : Board(document, memory) {
BandaiFCG(XML::Document &document) : Board(document) {
}
};

View File

@ -71,10 +71,6 @@ void Board::chr_write(unsigned addr, uint8 data) {
if(chrram.size) chrram.data[mirror(addr, chrram.size)] = data;
}
Board::Memory& Board::memory() {
return prgram;
}
void Board::power() {
}
@ -86,24 +82,35 @@ void Board::serialize(serializer &s) {
if(chrram.size) s.array(chrram.data, chrram.size);
}
Board::Board(XML::Document &document, const stream &memory) {
Board::Board(XML::Document &document) {
cartridge.board = this;
auto &cartridge = document["cartridge"];
information.type = cartridge["board"]["type"].data;
information.battery = cartridge["prg"]["ram"]["nonvolatile"].data == "true";
prgrom.size = numeral(cartridge["prg"]["rom"]["size"].data);
prgram.size = numeral(cartridge["prg"]["ram"]["size"].data);
chrrom.size = numeral(cartridge["chr"]["rom"]["size"].data);
chrram.size = numeral(cartridge["chr"]["ram"]["size"].data);
auto &prom = cartridge["prg"]["rom"];
auto &pram = cartridge["prg"]["ram"];
auto &crom = cartridge["chr"]["rom"];
auto &cram = cartridge["chr"]["ram"];
prgrom.size = numeral(prom["size"].data);
prgram.size = numeral(pram["size"].data);
chrrom.size = numeral(crom["size"].data);
chrram.size = numeral(cram["size"].data);
if(prgrom.size) prgrom.data = new uint8[prgrom.size]();
if(prgram.size) prgram.data = new uint8[prgram.size]();
if(chrrom.size) chrrom.data = new uint8[chrrom.size]();
if(chrram.size) chrram.data = new uint8[chrram.size]();
if(prgrom.size) memory.read(prgrom.data, prgrom.size);
if(chrrom.size) memory.read(chrrom.data, chrrom.size);
if(prom["name"].data) interface->loadRequest(ID::ProgramROM, prom["name"].data);
if(pram["name"].data) interface->loadRequest(ID::ProgramRAM, pram["name"].data);
if(crom["name"].data) interface->loadRequest(ID::CharacterROM, crom["name"].data);
if(cram["name"].data) interface->loadRequest(ID::CharacterRAM, cram["name"].data);
if(pram["name"].data) Famicom::cartridge.memory.append({ID::ProgramRAM, pram["name"].data});
if(cram["name"].data) Famicom::cartridge.memory.append({ID::CharacterRAM, cram["name"].data});
prgram.writable = true;
chrram.writable = true;
@ -112,56 +119,56 @@ Board::Board(XML::Document &document, const stream &memory) {
Board::~Board() {
}
Board* Board::load(const string &markup, const stream &memory) {
XML::Document document(markup);
Board* Board::load(const string &manifest) {
XML::Document document(manifest);
string type = document["cartridge"]["board"]["type"].data;
if(type == "BANDAI-FCG") return new BandaiFCG(document, memory);
if(type == "BANDAI-FCG" ) return new BandaiFCG(document);
if(type == "KONAMI-VRC-1") return new KonamiVRC1(document, memory);
if(type == "KONAMI-VRC-2") return new KonamiVRC2(document, memory);
if(type == "KONAMI-VRC-3") return new KonamiVRC3(document, memory);
if(type == "KONAMI-VRC-4") return new KonamiVRC4(document, memory);
if(type == "KONAMI-VRC-6") return new KonamiVRC6(document, memory);
if(type == "KONAMI-VRC-7") return new KonamiVRC7(document, memory);
if(type == "KONAMI-VRC-1") return new KonamiVRC1(document);
if(type == "KONAMI-VRC-2") return new KonamiVRC2(document);
if(type == "KONAMI-VRC-3") return new KonamiVRC3(document);
if(type == "KONAMI-VRC-4") return new KonamiVRC4(document);
if(type == "KONAMI-VRC-6") return new KonamiVRC6(document);
if(type == "KONAMI-VRC-7") return new KonamiVRC7(document);
if(type == "NES-AMROM" ) return new NES_AxROM(document, memory);
if(type == "NES-ANROM" ) return new NES_AxROM(document, memory);
if(type == "NES-AN1ROM" ) return new NES_AxROM(document, memory);
if(type == "NES-AOROM" ) return new NES_AxROM(document, memory);
if(type == "NES-AMROM" ) return new NES_AxROM(document);
if(type == "NES-ANROM" ) return new NES_AxROM(document);
if(type == "NES-AN1ROM" ) return new NES_AxROM(document);
if(type == "NES-AOROM" ) return new NES_AxROM(document);
if(type == "NES-BNROM" ) return new NES_BNROM(document, memory);
if(type == "NES-BNROM" ) return new NES_BNROM(document);
if(type == "NES-CNROM" ) return new NES_CNROM(document, memory);
if(type == "NES-CNROM" ) return new NES_CNROM(document);
if(type == "NES-EKROM" ) return new NES_ExROM(document, memory);
if(type == "NES-ELROM" ) return new NES_ExROM(document, memory);
if(type == "NES-ETROM" ) return new NES_ExROM(document, memory);
if(type == "NES-EWROM" ) return new NES_ExROM(document, memory);
if(type == "NES-EKROM" ) return new NES_ExROM(document);
if(type == "NES-ELROM" ) return new NES_ExROM(document);
if(type == "NES-ETROM" ) return new NES_ExROM(document);
if(type == "NES-EWROM" ) return new NES_ExROM(document);
if(type == "NES-FJROM" ) return new NES_FxROM(document, memory);
if(type == "NES-FKROM" ) return new NES_FxROM(document, memory);
if(type == "NES-FJROM" ) return new NES_FxROM(document);
if(type == "NES-FKROM" ) return new NES_FxROM(document);
if(type == "NES-GNROM" ) return new NES_GxROM(document, memory);
if(type == "NES-MHROM" ) return new NES_GxROM(document, memory);
if(type == "NES-GNROM" ) return new NES_GxROM(document);
if(type == "NES-MHROM" ) return new NES_GxROM(document);
if(type == "NES-HKROM" ) return new NES_HKROM(document, memory);
if(type == "NES-HKROM" ) return new NES_HKROM(document);
if(type == "NES-NROM-128") return new NES_NROM(document, memory);
if(type == "NES-NROM-256") return new NES_NROM(document, memory);
if(type == "NES-NROM-128") return new NES_NROM(document);
if(type == "NES-NROM-256") return new NES_NROM(document);
if(type == "NES-PEEOROM" ) return new NES_PxROM(document, memory);
if(type == "NES-PNROM" ) return new NES_PxROM(document, memory);
if(type == "NES-PEEOROM" ) return new NES_PxROM(document);
if(type == "NES-PNROM" ) return new NES_PxROM(document);
if(type == "NES-SNROM" ) return new NES_SxROM(document, memory);
if(type == "NES-SXROM" ) return new NES_SxROM(document, memory);
if(type == "NES-SNROM" ) return new NES_SxROM(document);
if(type == "NES-SXROM" ) return new NES_SxROM(document);
if(type == "NES-TLROM" ) return new NES_TxROM(document, memory);
if(type == "NES-TLROM" ) return new NES_TxROM(document);
if(type == "NES-UNROM" ) return new NES_UxROM(document, memory);
if(type == "NES-UOROM" ) return new NES_UxROM(document, memory);
if(type == "NES-UNROM" ) return new NES_UxROM(document);
if(type == "NES-UOROM" ) return new NES_UxROM(document);
if(type == "SUNSOFT-5B" ) return new Sunsoft5B(document, memory);
if(type == "SUNSOFT-5B" ) return new Sunsoft5B(document);
return nullptr;
}

View File

@ -25,16 +25,14 @@ struct Board {
virtual inline void scanline(unsigned y) {}
virtual Memory& memory();
virtual void power();
virtual void reset();
virtual void serialize(serializer&);
Board(XML::Document &document, const stream &memory);
Board(XML::Document &document);
virtual ~Board();
static Board* load(const string &markup, const stream &memory);
static Board* load(const string &manifest);
struct Information {
string type;

View File

@ -34,7 +34,7 @@ void serialize(serializer &s) {
vrc1.serialize(s);
}
KonamiVRC1(XML::Document &document, const stream &memory) : Board(document, memory), vrc1(*this) {
KonamiVRC1(XML::Document &document) : Board(document), vrc1(*this) {
}
};

View File

@ -49,7 +49,7 @@ void serialize(serializer &s) {
vrc2.serialize(s);
}
KonamiVRC2(XML::Document &document, const stream &memory) : Board(document, memory), vrc2(*this) {
KonamiVRC2(XML::Document &document) : Board(document), vrc2(*this) {
settings.pinout.a0 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a0"].data);
settings.pinout.a1 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a1"].data);
}

View File

@ -50,7 +50,7 @@ void serialize(serializer &s) {
vrc3.serialize(s);
}
KonamiVRC3(XML::Document &document, const stream &memory) : Board(document, memory), vrc3(*this) {
KonamiVRC3(XML::Document &document) : Board(document), vrc3(*this) {
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
}

View File

@ -53,7 +53,7 @@ void serialize(serializer &s) {
vrc4.serialize(s);
}
KonamiVRC4(XML::Document &document, const stream &memory) : Board(document, memory), vrc4(*this) {
KonamiVRC4(XML::Document &document) : Board(document), vrc4(*this) {
settings.pinout.a0 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a0"].data);
settings.pinout.a1 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a1"].data);
}

View File

@ -36,7 +36,7 @@ void main() { vrc6.main(); }
void power() { vrc6.power(); }
void reset() { vrc6.reset(); }
KonamiVRC6(XML::Document &document, const stream &memory) : Board(document, memory), vrc6(*this) {
KonamiVRC6(XML::Document &document) : Board(document), vrc6(*this) {
}
};

View File

@ -41,7 +41,7 @@ void serialize(serializer &s) {
vrc7.serialize(s);
}
KonamiVRC7(XML::Document &document, const stream &memory) : Board(document, memory), vrc7(*this) {
KonamiVRC7(XML::Document &document) : Board(document), vrc7(*this) {
}
};

View File

@ -45,7 +45,7 @@ void serialize(serializer &s) {
s.integer(mirror_select);
}
NES_AxROM(XML::Document &document, const stream &memory) : Board(document, memory) {
NES_AxROM(XML::Document &document) : Board(document) {
}
};

View File

@ -45,7 +45,7 @@ void serialize(serializer &s) {
s.integer(prg_bank);
}
NES_BNROM(XML::Document &document, const stream &memory) : Board(document, memory) {
NES_BNROM(XML::Document &document) : Board(document) {
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
}

View File

@ -47,7 +47,7 @@ void serialize(serializer &s) {
s.integer(chr_bank);
}
NES_CNROM(XML::Document &document, const stream &memory) : Board(document, memory) {
NES_CNROM(XML::Document &document) : Board(document) {
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
}

View File

@ -46,7 +46,7 @@ void serialize(serializer &s) {
mmc5.serialize(s);
}
NES_ExROM(XML::Document &document, const stream &memory) : Board(document, memory), mmc5(*this) {
NES_ExROM(XML::Document &document) : Board(document), mmc5(*this) {
revision = Revision::ELROM;
}

View File

@ -84,7 +84,7 @@ void serialize(serializer &s) {
s.array(latch);
}
NES_FxROM(XML::Document &document, const stream &memory) : Board(document, memory) {
NES_FxROM(XML::Document &document) : Board(document) {
revision = Revision::FKROM;
}

View File

@ -54,7 +54,7 @@ void serialize(serializer &s) {
s.integer(chr_bank);
}
NES_GxROM(XML::Document &document, const stream &memory) : Board(document, memory) {
NES_GxROM(XML::Document &document) : Board(document) {
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
}

View File

@ -42,7 +42,7 @@ void serialize(serializer &s) {
mmc6.serialize(s);
}
NES_HKROM(XML::Document &document, const stream &memory) : Board(document, memory), mmc6(*this) {
NES_HKROM(XML::Document &document) : Board(document), mmc6(*this) {
}
};

View File

@ -36,7 +36,7 @@ void serialize(serializer &s) {
Board::serialize(s);
}
NES_NROM(XML::Document &document, const stream &memory) : Board(document, memory) {
NES_NROM(XML::Document &document) : Board(document) {
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
}

View File

@ -90,7 +90,7 @@ void serialize(serializer &s) {
s.array(latch);
}
NES_PxROM(XML::Document &document, const stream &memory) : Board(document, memory) {
NES_PxROM(XML::Document &document) : Board(document) {
revision = Revision::PNROM;
}

View File

@ -94,7 +94,7 @@ void serialize(serializer &s) {
mmc1.serialize(s);
}
NES_SxROM(XML::Document &document, const stream &memory) : Board(document, memory), mmc1(*this) {
NES_SxROM(XML::Document &document) : Board(document), mmc1(*this) {
revision = Revision::SXROM;
}

View File

@ -60,7 +60,7 @@ void serialize(serializer &s) {
mmc3.serialize(s);
}
NES_TxROM(XML::Document &document, const stream &memory) : Board(document, memory), mmc3(*this) {
NES_TxROM(XML::Document &document) : Board(document), mmc3(*this) {
revision = Revision::TLROM;
}

View File

@ -48,7 +48,7 @@ void serialize(serializer &s) {
s.integer(prg_bank);
}
NES_UxROM(XML::Document &document, const stream &memory) : Board(document, memory) {
NES_UxROM(XML::Document &document) : Board(document) {
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
}

View File

@ -220,7 +220,7 @@ void serialize(serializer &s) {
pulse[2].serialize(s);
}
Sunsoft5B(XML::Document &document, const stream &memory) : Board(document, memory) {
Sunsoft5B(XML::Document &document) : Board(document) {
}
};

View File

@ -14,16 +14,14 @@ void Cartridge::main() {
board->main();
}
void Cartridge::load(const string &markup, const stream &memory) {
information.markup = markup;
void Cartridge::load(const string &manifest) {
information.markup = manifest;
board = Board::load(markup, memory);
Board::load(manifest); //this call will set Cartridge::board if successful
if(board == nullptr) return;
interface->memory.append({ID::RAM, "save.ram"});
sha256_ctx sha;
uint8_t hash[32];
uint8 hash[32];
sha256_init(&sha);
sha256_chunk(&sha, board->prgrom.data, board->prgrom.size);
sha256_chunk(&sha, board->chrrom.data, board->chrrom.size);
@ -40,14 +38,7 @@ void Cartridge::load(const string &markup, const stream &memory) {
void Cartridge::unload() {
if(loaded == false) return;
loaded = false;
}
unsigned Cartridge::ram_size() {
return board->memory().size;
}
uint8* Cartridge::ram_data() {
return board->memory().data;
memory.reset();
}
void Cartridge::power() {

View File

@ -5,12 +5,9 @@ struct Cartridge : Thread, property<Cartridge> {
static void Main();
void main();
void load(const string &markup, const stream &memory);
void load(const string &manifest);
void unload();
unsigned ram_size();
uint8* ram_data();
void power();
void reset();
@ -21,6 +18,12 @@ struct Cartridge : Thread, property<Cartridge> {
string markup;
} information;
struct Memory {
unsigned id;
string name;
};
vector<Memory> memory;
void serialize(serializer&);
Cartridge();

View File

@ -1,7 +1,7 @@
struct Input {
enum class Device : unsigned {
None,
Joypad,
None,
};
void latch(bool data);

View File

@ -20,26 +20,46 @@ string Interface::sha256() {
return cartridge.sha256();
}
void Interface::load(unsigned id, const stream &stream, const string &markup) {
if(id == ID::ROM) {
cartridge.load(markup, stream);
system.power();
input.connect(0, Input::Device::Joypad);
input.connect(1, Input::Device::Joypad);
void Interface::load(unsigned id, const string &manifest) {
cartridge.load(manifest);
}
void Interface::save() {
for(auto &memory : cartridge.memory) {
saveRequest(memory.id, memory.name);
}
}
void Interface::load(unsigned id, const stream &stream, const string &manifest) {
if(id == ID::ProgramROM) {
stream.read(cartridge.board->prgrom.data, min(cartridge.board->prgrom.size, stream.size()));
}
if(id == ID::RAM) {
stream.read(cartridge.ram_data(), min(stream.size(), cartridge.ram_size()));
if(id == ID::ProgramRAM) {
stream.read(cartridge.board->prgram.data, min(cartridge.board->prgram.size, stream.size()));
}
if(id == ID::CharacterROM) {
stream.read(cartridge.board->chrrom.data, min(cartridge.board->chrrom.size, stream.size()));
}
if(id == ID::CharacterRAM) {
stream.read(cartridge.board->chrram.data, min(cartridge.board->chrram.size, stream.size()));
}
}
void Interface::save(unsigned id, const stream &stream) {
if(id == ID::RAM) {
stream.write(cartridge.ram_data(), cartridge.ram_size());
if(id == ID::ProgramRAM) {
stream.write(cartridge.board->prgram.data, cartridge.board->prgram.size);
}
if(id == ID::CharacterRAM) {
stream.write(cartridge.board->chrram.data, cartridge.board->chrram.size);
}
}
void Interface::unload() {
save();
cartridge.unload();
}
@ -90,7 +110,7 @@ Interface::Interface() {
information.aspectRatio = 8.0 / 7.0;
information.resettable = true;
media.append({ID::ROM, "Famicom", "sys", "program.rom", "fc"});
media.append({ID::Famicom, "Famicom", "sys", "program.rom", "fc"});
{
Device device{0, ID::Port1 | ID::Port2, "Controller"};

View File

@ -4,8 +4,14 @@ namespace Famicom {
struct ID {
enum : unsigned {
ROM,
RAM,
Famicom,
};
enum : unsigned {
ProgramROM,
ProgramRAM,
CharacterROM,
CharacterRAM,
};
enum : unsigned {
@ -20,7 +26,9 @@ struct Interface : Emulator::Interface {
bool loaded();
string sha256();
void load(unsigned id, const stream &stream, const string &markup = "");
void load(unsigned id, const string &manifest);
void save();
void load(unsigned id, const stream &stream, const string &manifest = "");
void save(unsigned id, const stream &stream);
void unload();

View File

@ -14,12 +14,8 @@ namespace GameBoy {
#include "serialization.cpp"
Cartridge cartridge;
void Cartridge::load(System::Revision revision, const string &markup, const stream &memory) {
romsize = memory.size() ? memory.size() : 32768u;
romdata = allocate<uint8>(romsize, 0xff);
memory.read(romdata, memory.size());
information.markup = markup;
void Cartridge::load(System::Revision revision, const string &manifest, bool preloaded) {
information.markup = manifest;
information.mapper = Mapper::Unknown;
information.ram = false;
information.battery = false;
@ -29,7 +25,7 @@ void Cartridge::load(System::Revision revision, const string &markup, const stre
information.romsize = 0;
information.ramsize = 0;
XML::Document document(markup);
XML::Document document(manifest);
auto &mapperid = document["cartridge"]["mapper"].data;
if(mapperid == "none" ) information.mapper = Mapper::MBC0;
@ -44,9 +40,24 @@ void Cartridge::load(System::Revision revision, const string &markup, const stre
information.rtc = document["cartridge"]["rtc"].data == "true";
information.rumble = document["cartridge"]["rumble"].data == "true";
auto &rom = document["cartridge"]["rom"];
auto &ram = document["cartridge"]["ram"];
romsize = numeral(rom["size"].data);
romdata = allocate<uint8>(romsize, 0xff);
ramsize = numeral(ram["size"].data);
ramdata = allocate<uint8>(ramsize, 0xff);
if(preloaded == false) {
if(rom["name"].exists()) interface->loadRequest(ID::ROM, rom["name"].data);
if(ram["name"].exists()) interface->loadRequest(ID::RAM, ram["name"].data);
if(ram["name"].exists()) memory.append({ID::RAM, ram["name"].data});
}
information.romsize = numeral(document["cartridge"]["rom"]["size"].data);
information.ramsize = numeral(document["cartridge"]["ram"]["size"].data);
information.battery = document["cartridge"]["ram"]["nonvolatile"].data == "true";
information.battery = ram["name"].exists();
switch(information.mapper) { default:
case Mapper::MBC0: mapper = &mbc0; break;
@ -59,19 +70,17 @@ void Cartridge::load(System::Revision revision, const string &markup, const stre
case Mapper::HuC3: mapper = &huc3; break;
}
ramdata = new uint8_t[ramsize = information.ramsize]();
system.load(revision);
loaded = true;
sha256 = nall::sha256(romdata, romsize);
if(ramsize) interface->memory.append({ID::RAM, "save.ram"});
}
void Cartridge::unload() {
if(loaded == false) return;
if(romdata) { delete[] romdata; romdata = 0; }
if(ramdata) { delete[] ramdata; ramdata = 0; }
if(romdata) { delete[] romdata; romdata = nullptr; }
if(ramdata) { delete[] ramdata; ramdata = nullptr; }
loaded = false;
}

View File

@ -33,6 +33,12 @@ struct Cartridge : MMIO, property<Cartridge> {
unsigned ramsize;
} information;
struct Memory {
unsigned id;
string name;
};
vector<Memory> memory;
readonly<bool> loaded;
readonly<string> sha256;
@ -45,7 +51,7 @@ struct Cartridge : MMIO, property<Cartridge> {
MMIO *mapper;
bool bootrom_enable;
void load(System::Revision revision, const string &markup, const stream &memory);
void load(System::Revision revision, const string &manifest, bool preloaded = false);
void unload();
uint8 rom_read(unsigned addr);

View File

@ -28,7 +28,19 @@ string Interface::sha256() {
return cartridge.sha256();
}
void Interface::load(unsigned id, const stream &stream, const string &markup) {
void Interface::load(unsigned id, const string &manifest) {
if(id == ID::GameBoy) cartridge.load(System::Revision::GameBoy, manifest);
if(id == ID::SuperGameBoy) cartridge.load(System::Revision::SuperGameBoy, manifest);
if(id == ID::GameBoyColor) cartridge.load(System::Revision::GameBoyColor, manifest);
}
void Interface::save() {
for(auto &memory : cartridge.memory) {
interface->saveRequest(memory.id, memory.name);
}
}
void Interface::load(unsigned id, const stream &stream, const string &manifest) {
if(id == ID::GameBoyBootROM) {
stream.read(system.bootROM.dmg, min( 256u, stream.size()));
}
@ -41,14 +53,8 @@ void Interface::load(unsigned id, const stream &stream, const string &markup) {
stream.read(system.bootROM.cgb, min(2048u, stream.size()));
}
if(id == ID::GameBoyROM) {
cartridge.load(System::Revision::GameBoy, markup, stream);
system.power();
}
if(id == ID::GameBoyColorROM) {
cartridge.load(System::Revision::GameBoyColor, markup, stream);
system.power();
if(id == ID::ROM) {
stream.read(cartridge.romdata, min(cartridge.romsize, stream.size()));
}
if(id == ID::RAM) {
@ -63,6 +69,7 @@ void Interface::save(unsigned id, const stream &stream) {
}
void Interface::unload() {
save();
cartridge.unload();
}
@ -118,8 +125,8 @@ Interface::Interface() {
firmware.append({ID::SuperGameBoyBootROM, "Super Game Boy", "sfc", "boot.rom"});
firmware.append({ID::GameBoyColorBootROM, "Game Boy Color", "sys", "boot.rom"});
media.append({ID::GameBoyROM, "Game Boy", "sys", "program.rom", "gb" });
media.append({ID::GameBoyColorROM, "Game Boy Color", "sys", "program.rom", "gbc"});
media.append({ID::GameBoy, "Game Boy", "sys", "program.rom", "gb" });
media.append({ID::GameBoyColor, "Game Boy Color", "sys", "program.rom", "gbc"});
{
Device device{0, ID::Device, "Controller"};

View File

@ -3,12 +3,19 @@ namespace GameBoy {
#endif
struct ID {
enum : unsigned {
GameBoy,
SuperGameBoy,
GameBoyColor,
};
enum : unsigned {
GameBoyBootROM,
SuperGameBoyBootROM,
GameBoyColorBootROM,
GameBoyROM,
GameBoyColorROM,
ROM,
RAM,
};
@ -32,7 +39,9 @@ struct Interface : Emulator::Interface {
bool loaded();
string sha256();
void load(unsigned id, const stream &stream, const string &markup = "");
void load(unsigned id, const string &manifest);
void save();
void load(unsigned id, const stream &stream, const string &manifest = "");
void save(unsigned id, const stream &stream);
void unload();

View File

@ -7,14 +7,18 @@ namespace GameBoyAdvance {
#include "serialization.cpp"
Cartridge cartridge;
bool Cartridge::load(const string &markup, const stream &memory) {
information.markup = markup;
XML::Document document(markup);
void Cartridge::load(const string &manifest) {
information.markup = manifest;
XML::Document document(manifest);
unsigned size = memory.size();
memory.read(rom.data, min(rom.size, size));
for(unsigned addr = size; addr < rom.size; addr++) {
rom.data[addr] = rom.data[Bus::mirror(addr, size)];
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;
@ -30,7 +34,8 @@ bool Cartridge::load(const string &markup, const stream &memory) {
ram.mask = ram.size - 1;
for(unsigned n = 0; n < ram.size; n++) ram.data[n] = 0xff;
interface->memory.append({2, "save.ram"});
interface->loadRequest(ID::RAM, info["name"].data);
memory.append({ID::RAM, info["name"].data});
}
if(info["type"].data == "EEPROM") {
@ -38,11 +43,12 @@ bool Cartridge::load(const string &markup, const stream &memory) {
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 = size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000;
eeprom.test = size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
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->memory.append({3, "save.ram"});
interface->loadRequest(ID::EEPROM, info["name"].data);
memory.append({ID::EEPROM, info["name"].data});
}
if(info["type"].data == "FlashROM") {
@ -51,19 +57,21 @@ bool Cartridge::load(const string &markup, const stream &memory) {
flashrom.size = numeral(info["size"].data);
for(unsigned n = 0; n < flashrom.size; n++) flashrom.data[n] = 0xff;
interface->memory.append({4, "save.ram"});
interface->loadRequest(ID::FlashROM, info["name"].data);
memory.append({ID::FlashROM, info["name"].data});
}
}
sha256 = nall::sha256(rom.data, size);
sha256 = nall::sha256(rom.data, rom_size);
system.load();
return loaded = true;
loaded = true;
}
void Cartridge::unload() {
if(loaded == false) return;
loaded = false;
memory.reset();
}
void Cartridge::power() {

View File

@ -12,7 +12,13 @@ struct Cartridge : property<Cartridge> {
string markup;
} information;
bool load(const string &markup, const stream &memory);
struct Media {
unsigned id;
string name;
};
vector<Media> memory;
void load(const string &manifest);
void unload();
void power();

View File

@ -16,15 +16,23 @@ bool Interface::loaded() {
return cartridge.loaded();
}
void Interface::load(unsigned id, const stream &stream, const string &markup) {
void Interface::load(unsigned id, const string &manifest) {
cartridge.load(manifest);
}
void Interface::save() {
for(auto &memory : cartridge.memory) {
interface->saveRequest(memory.id, memory.name);
}
}
void Interface::load(unsigned id, const stream &stream, const string &manifest) {
if(id == ID::BIOS) {
stream.read(bios.data, min(bios.size, stream.size()));
}
if(id == ID::ROM) {
memory.reset();
cartridge.load(markup, stream);
system.power();
stream.read(cartridge.rom.data, min(cartridge.rom.size, stream.size()));
}
if(id == ID::RAM) {
@ -55,6 +63,7 @@ void Interface::save(unsigned id, const stream &stream) {
}
void Interface::unload() {
save();
cartridge.unload();
}
@ -95,7 +104,7 @@ Interface::Interface() {
firmware.append({ID::BIOS, "Game Boy Advance", "sys", "bios.rom"});
media.append({ID::ROM, "Game Boy Advance", "sys", "program.rom", "gba"});
media.append({ID::GameBoyAdvance, "Game Boy Advance", "sys", "program.rom", "gba"});
{
Device device{0, ID::Device, "Controller"};

View File

@ -3,6 +3,10 @@ namespace GameBoyAdvance {
#endif
struct ID {
enum : unsigned {
GameBoyAdvance,
};
enum : unsigned {
BIOS,
ROM,
@ -21,7 +25,9 @@ struct Interface : Emulator::Interface {
double audioFrequency();
bool loaded();
void load(unsigned id, const stream &stream, const string &markup = "");
void load(unsigned id, const string &manifest);
void save();
void load(unsigned id, const stream &stream, const string &manifest = "");
void save(unsigned id, const stream &stream);
void unload();

View File

@ -1,6 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<cartridge region="NTSC">
<rom name="program.rom" size="0x100000"/>
<ram name="save.ram" size="0x8000"/>
<bsx>
<psram name="bsx.ram" size="0x40000"/>
<mcu>
<map address="00-3f:8000-ffff"/>
<map address="80-bf:8000-ffff"/>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<cartridge region="NTSC">
<boot firmware="boot.rom" sha256="0e4ddff32fc9d1eeaae812a157dd246459b00c9e14f2f61751f661f32361e360"/>
<rom>
<rom name="program.rom" size="0x80000">
<map mode="linear" address="00-7f:8000-ffff"/>
<map mode="linear" address="80-ff:8000-ffff"/>
</rom>

View File

@ -32,13 +32,13 @@ endif
obj/sfc-interface.o : $(sfc)/interface/interface.cpp $(call rwildcard,$(sfc)/interface)
obj/sfc-system.o : $(sfc)/system/system.cpp $(call rwildcard,$(sfc)/system/)
obj/sfc-controller.o: $(sfc)/controller/controller.cpp $(call rwildcard,$(sfc)/controller/)
obj/sfc-cartridge.o : $(sfc)/cartridge/cartridge.cpp $(sfc)/cartridge/*
obj/sfc-cheat.o : $(sfc)/cheat/cheat.cpp $(sfc)/cheat/*
obj/sfc-memory.o : $(sfc)/memory/memory.cpp $(call rwildcard,$(sfc)/memory/)
obj/sfc-cpu.o : $(sfccpu)/cpu.cpp $(call rwildcard,$(sfccpu)/)
obj/sfc-smp.o : $(sfcsmp)/smp.cpp $(call rwildcard,$(sfcsmp)/)
obj/sfc-dsp.o : $(sfcdsp)/dsp.cpp $(call rwildcard,$(sfcdsp)/)
obj/sfc-ppu.o : $(sfcppu)/ppu.cpp $(call rwildcard,$(sfcppu)/)
obj/sfc-cartridge.o : $(sfc)/cartridge/cartridge.cpp $(sfc)/cartridge/*
obj/sfc-cheat.o : $(sfc)/cheat/cheat.cpp $(sfc)/cheat/*
obj/sfc-icd2.o : $(sfc)/chip/icd2/icd2.cpp $(call rwildcard,$(sfc)/chip/icd2/)
obj/sfc-bsx.o : $(sfc)/chip/bsx/bsx.cpp $(call rwildcard,$(sfc)/chip/bsx/)

View File

@ -8,11 +8,62 @@ namespace SuperFamicom {
Cartridge cartridge;
void Cartridge::load(const string &manifest) {
region = Region::NTSC;
has_gb_slot = false;
has_bs_cart = false;
has_bs_slot = false;
has_st_slots = false;
has_nss_dip = false;
has_sa1 = false;
has_superfx = false;
has_armdsp = false;
has_hitachidsp = false;
has_necdsp = false;
has_epsonrtc = false;
has_sharprtc = false;
has_spc7110 = false;
has_sdd1 = false;
has_obc1 = false;
has_msu1 = false;
has_link = false;
parse_markup(manifest);
//print(manifest, "\n\n");
//Super Game Boy
if(cartridge.has_gb_slot()) {
sha256 = nall::sha256(GameBoy::cartridge.romdata, GameBoy::cartridge.romsize);
}
//Broadcast Satellaview
else if(cartridge.has_bs_cart() && cartridge.has_bs_slot()) {
sha256 = nall::sha256(bsxflash.memory.data(), bsxflash.memory.size());
}
//Sufami Turbo
else if(cartridge.has_st_slots()) {
sha256 = nall::sha256(sufamiturbo.slotA.rom.data(), sufamiturbo.slotA.rom.size());
}
//Super Famicom
else {
sha256 = nall::sha256(rom.data(), rom.size());
}
rom.write_protect(true);
ram.write_protect(false);
system.load();
loaded = true;
}
void Cartridge::load(const string &markup, const stream &stream) {
rom.copy(stream);
region = Region::NTSC;
ram_size = 0;
//ram_size = 0;
has_gb_slot = false;
has_bs_cart = false;
@ -55,10 +106,10 @@ void Cartridge::load(const string &markup, const stream &stream) {
sha256 = nall::sha256(rom.data(), rom.size());
}
if(ram_size > 0) {
ram.map(allocate<uint8>(ram_size, 0xff), ram_size);
interface->memory.append({ID::RAM, "save.ram"});
}
// if(ram_size > 0) {
// ram.map(allocate<uint8>(ram_size, 0xff), ram_size);
// interface->memory.append({ID::RAM, "save.ram"});
// }
rom.write_protect(true);
ram.write_protect(false);
@ -75,6 +126,7 @@ void Cartridge::unload() {
ram.reset();
loaded = false;
memory.reset();
}
Cartridge::Cartridge() {

View File

@ -20,7 +20,6 @@ struct Cartridge : property<Cartridge> {
readonly<string> sha256;
readonly<Region> region;
readonly<unsigned> ram_size;
readonly<bool> has_gb_slot;
readonly<bool> has_bs_cart;
@ -53,10 +52,17 @@ struct Cartridge : property<Cartridge> {
Mapping();
Mapping(const function<uint8 (unsigned)>&, const function<void (unsigned, uint8)>&);
Mapping(Memory&);
Mapping(SuperFamicom::Memory&);
};
linear_vector<Mapping> mapping;
vector<Mapping> mapping;
struct Memory {
unsigned id;
string name;
};
vector<Memory> memory;
void load(const string &manifest);
void load(const string &markup, const stream &stream);
void unload();
@ -67,6 +73,7 @@ struct Cartridge : property<Cartridge> {
private:
void parse_markup(const char*);
void parse_markup_map(Mapping&, XML::Node&);
void parse_markup_memory(MappedRAM&, XML::Node&, unsigned id, bool writable);
void parse_markup_rom(XML::Node&);
void parse_markup_ram(XML::Node&);

View File

@ -62,10 +62,22 @@ void Cartridge::parse_markup_map(Mapping &m, XML::Node &map) {
}
}
void Cartridge::parse_markup_memory(MappedRAM &ram, XML::Node &node, unsigned id, bool writable) {
string name = node["name"].data;
unsigned size = numeral(node["size"].data);
ram.map(allocate<uint8>(size, 0xff), size);
if(name.empty() == false) {
interface->loadRequest(id, name);
if(writable) memory.append({id, name});
}
}
//
void Cartridge::parse_markup_rom(XML::Node &root) {
if(root.exists() == false) return;
parse_markup_memory(rom, root, ID::ROM, false);
for(auto &node : root) {
if(node.name != "map") continue;
Mapping m(rom);
@ -77,11 +89,12 @@ void Cartridge::parse_markup_rom(XML::Node &root) {
void Cartridge::parse_markup_ram(XML::Node &root) {
if(root.exists() == false) return;
ram_size = numeral(root["size"].data);
parse_markup_memory(ram, root, ID::RAM, true);
for(auto &node : root) {
Mapping m(ram);
parse_markup_map(m, node);
if(m.size == 0) m.size = ram_size;
if(m.size == 0) m.size = ram.size();
mapping.append(m);
}
}
@ -103,7 +116,7 @@ void Cartridge::parse_markup_icd2(XML::Node &root) {
for(auto &node : root) {
if(node.name != "map") continue;
Mapping m({ &ICD2::read, &icd2 }, { &ICD2::write, &icd2 });
Mapping m({&ICD2::read, &icd2}, {&ICD2::write, &icd2});
parse_markup_map(m, node);
mapping.append(m);
}
@ -116,6 +129,10 @@ void Cartridge::parse_markup_bsx(XML::Node &root) {
interface->loadRequest(ID::BsxFlashROM, "BS-X Satellaview", "bs", "program.rom");
if(has_bs_cart) {
parse_markup_memory(bsxcartridge.psram, root["psram"], ID::BsxPSRAM, true);
}
for(auto &node : root["slot"]) {
if(node.name != "map") continue;
Mapping m(bsxflash.memory);
@ -125,14 +142,14 @@ void Cartridge::parse_markup_bsx(XML::Node &root) {
for(auto &node : root["mmio"]) {
if(node.name != "map") continue;
Mapping m({ &BSXCartridge::mmio_read, &bsxcartridge }, { &BSXCartridge::mmio_write, &bsxcartridge });
Mapping m({&BSXCartridge::mmio_read, &bsxcartridge}, {&BSXCartridge::mmio_write, &bsxcartridge});
parse_markup_map(m, node);
mapping.append(m);
}
for(auto &node : root["mcu"]) {
if(node.name != "map") continue;
Mapping m({ &BSXCartridge::mcu_read, &bsxcartridge }, { &BSXCartridge::mcu_write, &bsxcartridge });
Mapping m({&BSXCartridge::mcu_read, &bsxcartridge}, {&BSXCartridge::mcu_write, &bsxcartridge});
parse_markup_map(m, node);
mapping.append(m);
}
@ -152,7 +169,7 @@ void Cartridge::parse_markup_sufamiturbo(XML::Node &root) {
if(node.name == "rom") {
for(auto &leaf : node) {
if(leaf.name != "map") continue;
Memory &memory = slotid == 0 ? sufamiturbo.slotA.rom : sufamiturbo.slotB.rom;
SuperFamicom::Memory &memory = slotid == 0 ? sufamiturbo.slotA.rom : sufamiturbo.slotB.rom;
Mapping m(memory);
parse_markup_map(m, leaf);
if(m.size == 0) m.size = memory.size();
@ -163,7 +180,7 @@ void Cartridge::parse_markup_sufamiturbo(XML::Node &root) {
unsigned ram_size = numeral(node["size"].data);
for(auto &leaf : node) {
if(leaf.name != "map") continue;
Memory &memory = slotid == 0 ? sufamiturbo.slotA.ram : sufamiturbo.slotB.ram;
SuperFamicom::Memory &memory = slotid == 0 ? sufamiturbo.slotA.ram : sufamiturbo.slotB.ram;
Mapping m(memory);
parse_markup_map(m, leaf);
if(m.size == 0) m.size = ram_size;
@ -193,14 +210,14 @@ void Cartridge::parse_markup_sa1(XML::Node &root) {
for(auto &node : mcurom) {
if(node.name != "map") continue;
Mapping m({ &SA1::mmc_read, &sa1 }, { &SA1::mmc_write, &sa1 });
Mapping m({&SA1::mmc_read, &sa1}, {&SA1::mmc_write, &sa1});
parse_markup_map(m, node);
mapping.append(m);
}
for(auto &node : mcuram) {
if(node.name != "map") continue;
Mapping m({ &SA1::mmc_cpu_read, &sa1 }, { &SA1::mmc_cpu_write, &sa1 });
Mapping m({&SA1::mmc_cpu_read, &sa1}, {&SA1::mmc_cpu_write, &sa1});
parse_markup_map(m, node);
mapping.append(m);
}
@ -213,18 +230,18 @@ void Cartridge::parse_markup_sa1(XML::Node &root) {
mapping.append(m);
}
ram_size = numeral(bwram["size"].data);
parse_markup_memory(ram, bwram, ID::RAM, true);
for(auto &node : bwram) {
if(node.name != "map") continue;
Mapping m(sa1.cpubwram);
parse_markup_map(m, node);
if(m.size == 0) m.size = ram_size;
if(m.size == 0) m.size = ram.size();
mapping.append(m);
}
for(auto &node : mmio) {
if(node.name != "map") continue;
Mapping m({ &SA1::mmio_read, &sa1 }, { &SA1::mmio_write, &sa1 });
Mapping m({&SA1::mmio_read, &sa1}, {&SA1::mmio_write, &sa1});
parse_markup_map(m, node);
mapping.append(m);
}
@ -236,6 +253,8 @@ void Cartridge::parse_markup_superfx(XML::Node &root) {
for(auto &node : root) {
if(node.name == "rom") {
parse_markup_memory(rom, node, ID::ROM, false);
for(auto &leaf : node) {
if(leaf.name != "map") continue;
Mapping m(superfx.rom);
@ -244,22 +263,20 @@ void Cartridge::parse_markup_superfx(XML::Node &root) {
}
}
if(node.name == "ram") {
parse_markup_memory(ram, node, ID::RAM, false);
for(auto &leaf : node) {
if(leaf.name == "size") {
ram_size = numeral(leaf.data);
continue;
}
if(leaf.name != "map") continue;
Mapping m(superfx.ram);
parse_markup_map(m, leaf);
if(m.size == 0) m.size = ram_size;
if(m.size == 0) m.size = ram.size();
mapping.append(m);
}
}
if(node.name == "mmio") {
for(auto &leaf : node) {
if(leaf.name != "map") continue;
Mapping m({ &SuperFX::mmio_read, &superfx }, { &SuperFX::mmio_write, &superfx });
Mapping m({&SuperFX::mmio_read, &superfx}, {&SuperFX::mmio_write, &superfx});
parse_markup_map(m, leaf);
mapping.append(m);
}
@ -338,6 +355,9 @@ void Cartridge::parse_markup_necdsp(XML::Node &root) {
if(necdsp.revision == NECDSP::Revision::uPD96050) {
interface->loadRequest(ID::Nec96050DSP, firmware);
string name = root["ram"]["name"].data;
interface->loadRequest(ID::NecDSPRAM, name);
memory.append({ID::NecDSPRAM, name});
}
for(auto &node : root) {
@ -369,6 +389,10 @@ void Cartridge::parse_markup_epsonrtc(XML::Node &root) {
if(root.exists() == false) return;
has_epsonrtc = true;
string name = root["name"].data;
interface->loadRequest(ID::EpsonRTC, name);
memory.append({ID::EpsonRTC, name});
for(auto &node : root) {
if(node.name != "map") continue;
Mapping m({&EpsonRTC::read, &epsonrtc}, {&EpsonRTC::write, &epsonrtc});
@ -381,6 +405,10 @@ void Cartridge::parse_markup_sharprtc(XML::Node &root) {
if(root.exists() == false) return;
has_sharprtc = true;
string name = root["name"].data;
interface->loadRequest(ID::SharpRTC, name);
memory.append({ID::SharpRTC, name});
for(auto &node : root) {
if(node.name != "map") continue;
Mapping m({&SharpRTC::read, &sharprtc}, {&SharpRTC::write, &sharprtc});
@ -404,8 +432,6 @@ void Cartridge::parse_markup_spc7110(XML::Node &root) {
spc7110.drom_base = numeral(mcurom["data"]["offset"].data);
spc7110.drom_size = numeral(mcurom["data"]["size"].data);
ram_size = numeral(mcuram["size"].data);
for(auto &node : mmio) {
if(node.name != "map") continue;
Mapping m({&SPC7110::mmio_read, &spc7110}, {&SPC7110::mmio_write, &spc7110});
@ -509,9 +535,9 @@ Cartridge::Mapping::Mapping() {
banklo = bankhi = addrlo = addrhi = offset = size = 0;
}
Cartridge::Mapping::Mapping(Memory &memory) {
read = { &Memory::read, &memory };
write = { &Memory::write, &memory };
Cartridge::Mapping::Mapping(SuperFamicom::Memory &memory) {
read = {&SuperFamicom::Memory::read, &memory};
write = {&SuperFamicom::Memory::write, &memory};
mode = Bus::MapMode::Direct;
banklo = bankhi = addrlo = addrhi = offset = size = 0;
}

View File

@ -7,13 +7,6 @@ void BSXCartridge::init() {
}
void BSXCartridge::load() {
sram.map(allocate<uint8>(32 * 1024, 0xff), 32 * 1024);
sram.write_protect(false);
interface->memory.append({ID::BsxRAM, "save.ram"});
psram.map(allocate<uint8>(512 * 1024, 0xff), 512 * 1024);
psram.write_protect(false);
interface->memory.append({ID::BsxPSRAM, "bsx.ram"});
}
void BSXCartridge::unload() {
@ -106,7 +99,7 @@ uint8 BSXCartridge::mmio_read(unsigned addr) {
}
if((addr & 0xf8f000) == 0x105000) { //$10-17:5000-5fff
return memory_read(sram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff));
return memory_read(cartridge.ram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff));
}
return 0x00;
@ -121,7 +114,7 @@ void BSXCartridge::mmio_write(unsigned addr, uint8 data) {
}
if((addr & 0xf8f000) == 0x105000) { //$10-17:5000-5fff
return memory_write(sram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff), data);
return memory_write(cartridge.ram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff), data);
}
}

View File

@ -1,5 +1,4 @@
struct BSXCartridge {
MappedRAM sram;
MappedRAM psram;
void init();

View File

@ -1,4 +1,3 @@
void BSXCartridge::serialize(serializer &s) {
s.array(sram.data(), sram.size());
s.array(psram.data(), psram.size());
}

View File

@ -41,7 +41,7 @@ void EpsonRTC::init() {
}
void EpsonRTC::load() {
interface->memory.append({ID::EpsonRTC, "rtc.ram"});
return;
secondlo = 0;
secondhi = 0;

View File

@ -167,11 +167,11 @@ void EpsonRTC::load(const uint8 *data) {
void EpsonRTC::save(uint8 *data) {
data[0] = secondlo << 0 | secondhi << 4 | batteryfailure << 7;
data[1] = minutelo << 0 | minutehi << 4 | resync << 7;
data[2] = hourlo << 0 | hourhi << 4 | meridian << 6;
data[3] = daylo << 0 | dayhi << 4 | dayram << 6;
data[4] = monthlo << 0 | monthhi << 4 | monthram << 5;
data[2] = hourlo << 0 | hourhi << 4 | meridian << 6 | resync << 7;
data[3] = daylo << 0 | dayhi << 4 | dayram << 6 | resync << 7;
data[4] = monthlo << 0 | monthhi << 4 | monthram << 5 | resync << 7;
data[5] = yearlo << 0 | yearhi << 4;
data[6] = weekday << 0 | hold << 4 | calendar << 5 | irqflag << 6 | roundseconds << 7;
data[6] = weekday << 0 | resync << 3 | hold << 4 | calendar << 5 | irqflag << 6 | roundseconds << 7;
data[7] = irqmask << 0 | irqduty << 1 | irqperiod << 2 | pause << 4 | stop << 5 | atime << 6 | test << 7;
uint64 timestamp = (uint64)time(0);

View File

@ -147,12 +147,6 @@ void EpsonRTC::tick_day() {
return tick_month();
}
if(days == 31 && (dayhi == 3 && (daylo & 3))) {
daylo = 1;
dayhi = 0;
return tick_month();
}
if(daylo <= 8 || daylo == 12) {
daylo++;
} else {

View File

@ -37,8 +37,6 @@ void ICD2::load() {
hook = GameBoy::interface->hook;
GameBoy::interface->bind = this;
GameBoy::interface->hook = this;
interface->memory.append({ID::SuperGameBoyRAM, "save.ram"});
}
void ICD2::unload() {

View File

@ -10,6 +10,8 @@ MSU1 msu1;
void MSU1::Enter() { msu1.enter(); }
void MSU1::enter() {
for(unsigned addr = 0; addr <= 7; addr++) mmio_write(addr, 0x00);
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
@ -75,6 +77,7 @@ void MSU1::reset() {
mmio.audio_busy = true;
mmio.audio_repeat = false;
mmio.audio_play = false;
mmio.audio_error = false;
}
uint8 MSU1::mmio_read(unsigned addr) {
@ -86,6 +89,7 @@ uint8 MSU1::mmio_read(unsigned addr) {
| (mmio.audio_busy << 6)
| (mmio.audio_repeat << 5)
| (mmio.audio_play << 4)
| (mmio.audio_error << 3)
| (Revision << 0);
case 1:
if(mmio.data_busy) return 0x00;
@ -97,9 +101,8 @@ uint8 MSU1::mmio_read(unsigned addr) {
case 4: return 'M';
case 5: return 'S';
case 6: return 'U';
case 7: return '0' + Revision;
case 7: return '1';
}
throw;
}
void MSU1::mmio_write(unsigned addr, uint8 data) {
@ -128,6 +131,7 @@ void MSU1::mmio_write(unsigned addr, uint8 data) {
mmio.audio_busy = false;
mmio.audio_repeat = false;
mmio.audio_play = false;
mmio.audio_error = !audiofile.open();
break;
case 6:
mmio.audio_volume = data;

View File

@ -21,6 +21,7 @@ private:
AudioBusy = 0x40,
AudioRepeating = 0x20,
AudioPlaying = 0x10,
AudioError = 0x08,
Revision = 0x01,
};
@ -36,6 +37,7 @@ private:
bool audio_busy;
bool audio_repeat;
bool audio_play;
bool audio_error;
} mmio;
};

View File

@ -14,6 +14,7 @@ void MSU1::serialize(serializer &s) {
s.integer(mmio.audio_busy);
s.integer(mmio.audio_repeat);
s.integer(mmio.audio_play);
s.integer(mmio.audio_error);
if(datafile.open()) datafile.close();
if(datafile.open({interface->path(0), "msu1.rom"}, file::mode::read)) {

View File

@ -33,9 +33,6 @@ void NECDSP::init() {
}
void NECDSP::load() {
if(revision == Revision::uPD96050) {
interface->memory.append({ID::NecDSPRAM, "upd96050.ram"});
}
}
void NECDSP::unload() {

View File

@ -29,7 +29,7 @@ void SharpRTC::init() {
}
void SharpRTC::load() {
interface->memory.append({ID::SharpRTC, "rtc.ram"});
return;
second = 0;
minute = 0;
@ -37,6 +37,7 @@ void SharpRTC::load() {
day = 0;
month = 0;
year = 0;
weekday = 0;
}
void SharpRTC::unload() {

View File

@ -10,15 +10,11 @@ void SufamiTurbo::load() {
slotA.ram.map(allocate<uint8>(128 * 1024, 0xff), 128 * 1024);
slotB.ram.map(allocate<uint8>(128 * 1024, 0xff), 128 * 1024);
if(slotA.rom.data()) {
interface->memory.append({ID::SufamiTurboSlotARAM, "save.ram"});
} else {
if(slotA.rom.data() == nullptr) {
slotA.rom.map(allocate<uint8>(128 * 1024, 0xff), 128 * 1024);
}
if(slotB.rom.data()) {
interface->memory.append({ID::SufamiTurboSlotBRAM, "save.ram"});
} else {
if(slotB.rom.data() == nullptr) {
slotB.rom.map(allocate<uint8>(128 * 1024, 0xff), 128 * 1024);
}
}

View File

@ -32,7 +32,6 @@ unsigned Interface::group(unsigned id) {
case ID::Nec7725DSP:
case ID::Nec96050DSP:
case ID::NecDSPRAM:
case ID::BsxRAM:
case ID::BsxPSRAM:
return 0;
case ID::SuperGameBoyROM:
@ -50,14 +49,23 @@ unsigned Interface::group(unsigned id) {
return 0;
}
void Interface::load(unsigned id, const stream &stream, const string &markup) {
void Interface::load(unsigned id, const string &manifest) {
cartridge.load(manifest);
}
void Interface::save() {
for(auto &memory : cartridge.memory) {
saveRequest(memory.id, memory.name);
}
}
void Interface::load(unsigned id, const stream &stream, const string &manifest) {
if(id == ID::IPLROM) {
stream.read(smp.iplrom, min(64u, stream.size()));
}
if(id == ID::ROM) {
cartridge.load(markup, stream);
system.power();
stream.read(cartridge.rom.data(), min(cartridge.rom.size(), stream.size()));
}
if(id == ID::RAM) {
@ -99,7 +107,8 @@ void Interface::load(unsigned id, const stream &stream, const string &markup) {
}
if(id == ID::SuperGameBoyROM) {
GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy, markup, stream);
GameBoy::interface->load(GameBoy::ID::ROM, stream);
GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy, manifest, true);
}
if(id == ID::SuperGameBoyRAM) {
@ -110,10 +119,6 @@ void Interface::load(unsigned id, const stream &stream, const string &markup) {
bsxflash.memory.copy(stream);
}
if(id == ID::BsxRAM) {
stream.read(bsxcartridge.sram.data(), min(stream.size(), bsxcartridge.sram.size()));
}
if(id == ID::BsxPSRAM) {
stream.read(bsxcartridge.psram.data(), min(stream.size(), bsxcartridge.psram.size()));
}
@ -160,10 +165,6 @@ void Interface::save(unsigned id, const stream &stream) {
stream.write(GameBoy::cartridge.ramdata, GameBoy::cartridge.ramsize);
}
if(id == ID::BsxRAM) {
stream.write(bsxcartridge.sram.data(), bsxcartridge.sram.size());
}
if(id == ID::BsxPSRAM) {
stream.write(bsxcartridge.psram.data(), bsxcartridge.psram.size());
}
@ -179,6 +180,7 @@ void Interface::save(unsigned id, const stream &stream) {
}
void Interface::unload() {
save();
cartridge.unload();
tracerEnable(false);
}
@ -285,10 +287,10 @@ Interface::Interface() {
firmware.append({ID::IPLROM, "Super Famicom", "sys", "spc700.rom"});
media.append({ID::ROM, "Super Famicom", "sys", "program.rom", "sfc"});
media.append({ID::ROM, "Super Game Boy", "sfc", "program.rom", "gb" });
media.append({ID::ROM, "BS-X Satellaview", "sfc", "program.rom", "bs" });
media.append({ID::ROM, "Sufami Turbo", "sfc", "program.rom", "st" });
media.append({ID::SuperFamicom, "Super Famicom", "sys", "program.rom", "sfc"});
media.append({ID::SuperFamicom, "Super Game Boy", "sfc", "program.rom", "gb" });
media.append({ID::SuperFamicom, "BS-X Satellaview", "sfc", "program.rom", "bs" });
media.append({ID::SuperFamicom, "Sufami Turbo", "sfc", "program.rom", "st" });
{
Device device{0, ID::Port1 | ID::Port2, "Controller"};

View File

@ -3,6 +3,10 @@ namespace SuperFamicom {
#endif
struct ID {
enum : unsigned {
SuperFamicom,
};
enum : unsigned {
IPLROM,
@ -22,7 +26,6 @@ struct ID {
SuperGameBoyRAM,
BsxFlashROM,
BsxRAM,
BsxPSRAM,
SufamiTurboSlotAROM,
@ -44,6 +47,8 @@ struct Interface : Emulator::Interface {
bool loaded();
string sha256();
unsigned group(unsigned id);
void load(unsigned id, const string &manifest);
void save();
void load(unsigned id, const stream &stream, const string &markup = "");
void save(unsigned id, const stream &stream);
void unload();

View File

@ -62,7 +62,7 @@ void System::runthreadtosave() {
}
void System::init() {
assert(interface != 0);
assert(interface != nullptr);
bsxsatellaview.init();
icd2.init();

View File

@ -187,6 +187,7 @@ void InputManager::saveConfiguration() {
InputManager::InputManager() {
inputManager = this;
activeScancode = 0;
bootstrap();
}

View File

@ -1,13 +1,16 @@
#include "../ethos.hpp"
Interface *interface = nullptr;
void Interface::loadRequest(unsigned id, const string &path) {
return utility->loadMedia(id, path);
void Interface::loadRequest(unsigned id, const string &name, const string &type, const string &path) {
return utility->loadRequest(id, name, type, path);
}
void Interface::loadRequest(unsigned id, const string &name, const string &type, const string &path) {
if(name.empty() && type.empty()) return utility->loadMedia(id, path);
return utility->loadMedia(id, name, type, path);
void Interface::loadRequest(unsigned id, const string &path) {
return utility->loadRequest(id, path);
}
void Interface::saveRequest(unsigned id, const string &path) {
return utility->saveRequest(id, path);
}
uint32_t Interface::videoColor(unsigned source, uint16_t r, uint16_t g, uint16_t b) {

View File

@ -1,5 +1,6 @@
struct Interface : Emulator::Interface::Bind {
void loadRequest(unsigned id, const string &path);
void saveRequest(unsigned id, const string &path);
void loadRequest(unsigned id, const string &name, const string &type, const string &path);
uint32_t videoColor(unsigned source, uint16_t red, uint16_t green, uint16_t blue);
void videoRefresh(const uint32_t *data, unsigned pitch, unsigned width, unsigned height);

View File

@ -7,13 +7,17 @@ void Utility::setInterface(Emulator::Interface *emulator) {
presentation->synchronize();
}
//load menu option selected
void Utility::loadMedia(Emulator::Interface *emulator, Emulator::Interface::Media &media) {
string pathname = application->path({media.name, ".", media.type, "/"});
if(!file::exists({pathname, media.path})) pathname = browser->select({"Load ", media.name}, media.extension);
if(!file::exists({pathname, media.path})) return;
string pathname;
if(media.type != "sys") pathname = application->path({media.name, ".", media.type, "/"});
if(!directory::exists(pathname)) pathname = browser->select({"Load ", media.name}, media.extension);
if(!directory::exists(pathname)) return;
if(!file::exists({pathname, "manifest.xml"})) return;
loadMedia(emulator, media, pathname);
}
//load menu cartridge selected or command-line load
void Utility::loadMedia(Emulator::Interface *emulator, Emulator::Interface::Media &media, const string &pathname) {
unload();
setInterface(emulator);
@ -22,52 +26,60 @@ void Utility::loadMedia(Emulator::Interface *emulator, Emulator::Interface::Medi
string manifest;
manifest.readfile({pathname, "manifest.xml"});
auto memory = file::read({pathname, media.path});
system().load(media.id, vectorstream{memory}, manifest);
system().load(media.id, manifest);
system().power();
if(this->pathname.size() == 0) this->pathname.append(pathname);
presentation->setSystemName(media.name);
load();
}
void Utility::loadMedia(unsigned id, const string &path) {
string pathname = {this->path(system().group(id)), path};
if(file::exists(pathname)) {
mmapstream stream(pathname);
return system().load(id, stream);
}
}
void Utility::loadMedia(unsigned id, const string &name, const string &type, const string &path) {
//request from emulation core to load non-volatile media folder
void Utility::loadRequest(unsigned id, const string &name, const string &type, const string &path) {
string pathname = browser->select({"Load ", name}, type);
if(pathname.empty()) return;
this->path(system().group(id)) = pathname;
this->pathname.append(pathname);
string markup;
markup.readfile({pathname, "manifest.xml"});
string manifest;
manifest.readfile({pathname, "manifest.xml"});
mmapstream stream({pathname, path});
system().load(id, stream, markup);
system().load(id, stream, manifest);
}
//request from emulation core to load non-volatile media file
void Utility::loadRequest(unsigned id, const string &path) {
string pathname = {this->path(system().group(id)), path};
if(file::exists(pathname) == false) return;
mmapstream stream(pathname);
return system().load(id, stream);
}
//request from emulation core to save non-volatile media file
void Utility::saveRequest(unsigned id, const string &path) {
string pathname = {this->path(system().group(id)), path};
filestream stream(pathname, file::mode::write);
return system().save(id, stream);
}
void Utility::loadMemory() {
for(auto &memory : system().memory) {
string pathname = path(system().group(memory.id));
if(file::exists({pathname, memory.name}) == false) continue;
filestream fs({pathname, memory.name});
system().load(memory.id, fs);
}
// for(auto &memory : system().memory) {
// string pathname = path(system().group(memory.id));
// if(file::exists({pathname, memory.name}) == false) continue;
// filestream fs({pathname, memory.name});
// system().load(memory.id, fs);
// }
cheatEditor->load({pathname[0], "cheats.xml"});
stateManager->load({pathname[0], "bsnes/states.bsa"}, 1);
}
void Utility::saveMemory() {
for(auto &memory : system().memory) {
string pathname = path(system().group(memory.id));
filestream fs({pathname, memory.name}, file::mode::write);
system().save(memory.id, fs);
}
// for(auto &memory : system().memory) {
// string pathname = path(system().group(memory.id));
// filestream fs({pathname, memory.name}, file::mode::write);
// system().save(memory.id, fs);
// }
cheatEditor->save({pathname[0], "cheats.xml"});
stateManager->save({pathname[0], "bsnes/states.bsa"}, 1);

View File

@ -1,9 +1,12 @@
struct Utility {
void setInterface(Emulator::Interface *emulator);
void loadMedia(Emulator::Interface *emulator, Emulator::Interface::Media &media);
void loadMedia(Emulator::Interface *emulator, Emulator::Interface::Media &media, const string &pathname);
void loadMedia(unsigned id, const string &path);
void loadMedia(unsigned id, const string &name, const string &type, const string &path);
void loadRequest(unsigned id, const string &name, const string &type, const string &path);
void loadRequest(unsigned id, const string &path);
void saveRequest(unsigned id, const string &path);
void loadMemory();
void saveMemory();