mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
d418eda97c
commit
9a8a54c75e
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const char Name[] = "bsnes";
|
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 Author[] = "byuu";
|
||||||
static const char License[] = "GPLv3";
|
static const char License[] = "GPLv3";
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,6 @@ struct Interface {
|
||||||
vector<Media> firmware;
|
vector<Media> firmware;
|
||||||
vector<Media> media;
|
vector<Media> media;
|
||||||
|
|
||||||
struct Memory {
|
|
||||||
unsigned id;
|
|
||||||
string name;
|
|
||||||
};
|
|
||||||
vector<Memory> memory;
|
|
||||||
|
|
||||||
struct Device {
|
struct Device {
|
||||||
unsigned id;
|
unsigned id;
|
||||||
unsigned portmask;
|
unsigned portmask;
|
||||||
|
@ -52,8 +46,9 @@ struct Interface {
|
||||||
vector<Port> port;
|
vector<Port> port;
|
||||||
|
|
||||||
struct Bind {
|
struct Bind {
|
||||||
virtual void loadRequest(unsigned, const string&) {}
|
|
||||||
virtual void loadRequest(unsigned, const string&, const string&, 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 uint32_t videoColor(unsigned, uint16_t, uint16_t, uint16_t) { return 0u; }
|
||||||
virtual void videoRefresh(const uint32_t*, unsigned, unsigned, unsigned) {}
|
virtual void videoRefresh(const uint32_t*, unsigned, unsigned, unsigned) {}
|
||||||
virtual void audioSample(int16_t, int16_t) {}
|
virtual void audioSample(int16_t, int16_t) {}
|
||||||
|
@ -63,8 +58,9 @@ struct Interface {
|
||||||
} *bind;
|
} *bind;
|
||||||
|
|
||||||
//callback bindings (provided by user interface)
|
//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 &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); }
|
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 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); }
|
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 bool loaded() { return false; }
|
||||||
virtual string sha256() { return ""; }
|
virtual string sha256() { return ""; }
|
||||||
virtual unsigned group(unsigned id) { return 0u; }
|
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 load(unsigned id, const stream &memory, const string &markup = "") {}
|
||||||
virtual void save(unsigned id, const stream &memory) {}
|
virtual void save(unsigned id, const stream &memory) {}
|
||||||
virtual void unload() {}
|
virtual void unload() {}
|
||||||
|
|
|
@ -111,7 +111,7 @@ void serialize(serializer &s) {
|
||||||
s.integer(irq_latch);
|
s.integer(irq_latch);
|
||||||
}
|
}
|
||||||
|
|
||||||
BandaiFCG(XML::Document &document, const stream &memory) : Board(document, memory) {
|
BandaiFCG(XML::Document &document) : Board(document) {
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -71,10 +71,6 @@ void Board::chr_write(unsigned addr, uint8 data) {
|
||||||
if(chrram.size) chrram.data[mirror(addr, chrram.size)] = data;
|
if(chrram.size) chrram.data[mirror(addr, chrram.size)] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
Board::Memory& Board::memory() {
|
|
||||||
return prgram;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Board::power() {
|
void Board::power() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,24 +82,35 @@ void Board::serialize(serializer &s) {
|
||||||
if(chrram.size) s.array(chrram.data, chrram.size);
|
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"];
|
auto &cartridge = document["cartridge"];
|
||||||
|
|
||||||
information.type = cartridge["board"]["type"].data;
|
information.type = cartridge["board"]["type"].data;
|
||||||
information.battery = cartridge["prg"]["ram"]["nonvolatile"].data == "true";
|
information.battery = cartridge["prg"]["ram"]["nonvolatile"].data == "true";
|
||||||
|
|
||||||
prgrom.size = numeral(cartridge["prg"]["rom"]["size"].data);
|
auto &prom = cartridge["prg"]["rom"];
|
||||||
prgram.size = numeral(cartridge["prg"]["ram"]["size"].data);
|
auto &pram = cartridge["prg"]["ram"];
|
||||||
chrrom.size = numeral(cartridge["chr"]["rom"]["size"].data);
|
auto &crom = cartridge["chr"]["rom"];
|
||||||
chrram.size = numeral(cartridge["chr"]["ram"]["size"].data);
|
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(prgrom.size) prgrom.data = new uint8[prgrom.size]();
|
||||||
if(prgram.size) prgram.data = new uint8[prgram.size]();
|
if(prgram.size) prgram.data = new uint8[prgram.size]();
|
||||||
if(chrrom.size) chrrom.data = new uint8[chrrom.size]();
|
if(chrrom.size) chrrom.data = new uint8[chrrom.size]();
|
||||||
if(chrram.size) chrram.data = new uint8[chrram.size]();
|
if(chrram.size) chrram.data = new uint8[chrram.size]();
|
||||||
|
|
||||||
if(prgrom.size) memory.read(prgrom.data, prgrom.size);
|
if(prom["name"].data) interface->loadRequest(ID::ProgramROM, prom["name"].data);
|
||||||
if(chrrom.size) memory.read(chrrom.data, chrrom.size);
|
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;
|
prgram.writable = true;
|
||||||
chrram.writable = true;
|
chrram.writable = true;
|
||||||
|
@ -112,56 +119,56 @@ Board::Board(XML::Document &document, const stream &memory) {
|
||||||
Board::~Board() {
|
Board::~Board() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Board* Board::load(const string &markup, const stream &memory) {
|
Board* Board::load(const string &manifest) {
|
||||||
XML::Document document(markup);
|
XML::Document document(manifest);
|
||||||
string type = document["cartridge"]["board"]["type"].data;
|
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-1") return new KonamiVRC1(document);
|
||||||
if(type == "KONAMI-VRC-2") return new KonamiVRC2(document, memory);
|
if(type == "KONAMI-VRC-2") return new KonamiVRC2(document);
|
||||||
if(type == "KONAMI-VRC-3") return new KonamiVRC3(document, memory);
|
if(type == "KONAMI-VRC-3") return new KonamiVRC3(document);
|
||||||
if(type == "KONAMI-VRC-4") return new KonamiVRC4(document, memory);
|
if(type == "KONAMI-VRC-4") return new KonamiVRC4(document);
|
||||||
if(type == "KONAMI-VRC-6") return new KonamiVRC6(document, memory);
|
if(type == "KONAMI-VRC-6") return new KonamiVRC6(document);
|
||||||
if(type == "KONAMI-VRC-7") return new KonamiVRC7(document, memory);
|
if(type == "KONAMI-VRC-7") return new KonamiVRC7(document);
|
||||||
|
|
||||||
if(type == "NES-AMROM" ) return new NES_AxROM(document, memory);
|
if(type == "NES-AMROM" ) return new NES_AxROM(document);
|
||||||
if(type == "NES-ANROM" ) return new NES_AxROM(document, memory);
|
if(type == "NES-ANROM" ) return new NES_AxROM(document);
|
||||||
if(type == "NES-AN1ROM" ) return new NES_AxROM(document, memory);
|
if(type == "NES-AN1ROM" ) return new NES_AxROM(document);
|
||||||
if(type == "NES-AOROM" ) return new NES_AxROM(document, memory);
|
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-EKROM" ) return new NES_ExROM(document);
|
||||||
if(type == "NES-ELROM" ) return new NES_ExROM(document, memory);
|
if(type == "NES-ELROM" ) return new NES_ExROM(document);
|
||||||
if(type == "NES-ETROM" ) return new NES_ExROM(document, memory);
|
if(type == "NES-ETROM" ) return new NES_ExROM(document);
|
||||||
if(type == "NES-EWROM" ) return new NES_ExROM(document, memory);
|
if(type == "NES-EWROM" ) return new NES_ExROM(document);
|
||||||
|
|
||||||
if(type == "NES-FJROM" ) return new NES_FxROM(document, memory);
|
if(type == "NES-FJROM" ) return new NES_FxROM(document);
|
||||||
if(type == "NES-FKROM" ) return new NES_FxROM(document, memory);
|
if(type == "NES-FKROM" ) return new NES_FxROM(document);
|
||||||
|
|
||||||
if(type == "NES-GNROM" ) return new NES_GxROM(document, memory);
|
if(type == "NES-GNROM" ) return new NES_GxROM(document);
|
||||||
if(type == "NES-MHROM" ) return new NES_GxROM(document, memory);
|
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-128") return new NES_NROM(document);
|
||||||
if(type == "NES-NROM-256") return new NES_NROM(document, memory);
|
if(type == "NES-NROM-256") return new NES_NROM(document);
|
||||||
|
|
||||||
if(type == "NES-PEEOROM" ) return new NES_PxROM(document, memory);
|
if(type == "NES-PEEOROM" ) return new NES_PxROM(document);
|
||||||
if(type == "NES-PNROM" ) return new NES_PxROM(document, memory);
|
if(type == "NES-PNROM" ) return new NES_PxROM(document);
|
||||||
|
|
||||||
if(type == "NES-SNROM" ) return new NES_SxROM(document, memory);
|
if(type == "NES-SNROM" ) return new NES_SxROM(document);
|
||||||
if(type == "NES-SXROM" ) return new NES_SxROM(document, memory);
|
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-UNROM" ) return new NES_UxROM(document);
|
||||||
if(type == "NES-UOROM" ) return new NES_UxROM(document, memory);
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,16 +25,14 @@ struct Board {
|
||||||
|
|
||||||
virtual inline void scanline(unsigned y) {}
|
virtual inline void scanline(unsigned y) {}
|
||||||
|
|
||||||
virtual Memory& memory();
|
|
||||||
|
|
||||||
virtual void power();
|
virtual void power();
|
||||||
virtual void reset();
|
virtual void reset();
|
||||||
|
|
||||||
virtual void serialize(serializer&);
|
virtual void serialize(serializer&);
|
||||||
Board(XML::Document &document, const stream &memory);
|
Board(XML::Document &document);
|
||||||
virtual ~Board();
|
virtual ~Board();
|
||||||
|
|
||||||
static Board* load(const string &markup, const stream &memory);
|
static Board* load(const string &manifest);
|
||||||
|
|
||||||
struct Information {
|
struct Information {
|
||||||
string type;
|
string type;
|
||||||
|
|
|
@ -34,7 +34,7 @@ void serialize(serializer &s) {
|
||||||
vrc1.serialize(s);
|
vrc1.serialize(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
KonamiVRC1(XML::Document &document, const stream &memory) : Board(document, memory), vrc1(*this) {
|
KonamiVRC1(XML::Document &document) : Board(document), vrc1(*this) {
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -49,7 +49,7 @@ void serialize(serializer &s) {
|
||||||
vrc2.serialize(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.a0 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a0"].data);
|
||||||
settings.pinout.a1 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a1"].data);
|
settings.pinout.a1 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a1"].data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ void serialize(serializer &s) {
|
||||||
vrc3.serialize(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;
|
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ void serialize(serializer &s) {
|
||||||
vrc4.serialize(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.a0 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a0"].data);
|
||||||
settings.pinout.a1 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a1"].data);
|
settings.pinout.a1 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a1"].data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ void main() { vrc6.main(); }
|
||||||
void power() { vrc6.power(); }
|
void power() { vrc6.power(); }
|
||||||
void reset() { vrc6.reset(); }
|
void reset() { vrc6.reset(); }
|
||||||
|
|
||||||
KonamiVRC6(XML::Document &document, const stream &memory) : Board(document, memory), vrc6(*this) {
|
KonamiVRC6(XML::Document &document) : Board(document), vrc6(*this) {
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,7 +41,7 @@ void serialize(serializer &s) {
|
||||||
vrc7.serialize(s);
|
vrc7.serialize(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
KonamiVRC7(XML::Document &document, const stream &memory) : Board(document, memory), vrc7(*this) {
|
KonamiVRC7(XML::Document &document) : Board(document), vrc7(*this) {
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -45,7 +45,7 @@ void serialize(serializer &s) {
|
||||||
s.integer(mirror_select);
|
s.integer(mirror_select);
|
||||||
}
|
}
|
||||||
|
|
||||||
NES_AxROM(XML::Document &document, const stream &memory) : Board(document, memory) {
|
NES_AxROM(XML::Document &document) : Board(document) {
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -45,7 +45,7 @@ void serialize(serializer &s) {
|
||||||
s.integer(prg_bank);
|
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;
|
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ void serialize(serializer &s) {
|
||||||
s.integer(chr_bank);
|
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;
|
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ void serialize(serializer &s) {
|
||||||
mmc5.serialize(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;
|
revision = Revision::ELROM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ void serialize(serializer &s) {
|
||||||
s.array(latch);
|
s.array(latch);
|
||||||
}
|
}
|
||||||
|
|
||||||
NES_FxROM(XML::Document &document, const stream &memory) : Board(document, memory) {
|
NES_FxROM(XML::Document &document) : Board(document) {
|
||||||
revision = Revision::FKROM;
|
revision = Revision::FKROM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ void serialize(serializer &s) {
|
||||||
s.integer(chr_bank);
|
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;
|
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ void serialize(serializer &s) {
|
||||||
mmc6.serialize(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) {
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -36,7 +36,7 @@ void serialize(serializer &s) {
|
||||||
Board::serialize(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;
|
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,7 @@ void serialize(serializer &s) {
|
||||||
s.array(latch);
|
s.array(latch);
|
||||||
}
|
}
|
||||||
|
|
||||||
NES_PxROM(XML::Document &document, const stream &memory) : Board(document, memory) {
|
NES_PxROM(XML::Document &document) : Board(document) {
|
||||||
revision = Revision::PNROM;
|
revision = Revision::PNROM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ void serialize(serializer &s) {
|
||||||
mmc1.serialize(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;
|
revision = Revision::SXROM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ void serialize(serializer &s) {
|
||||||
mmc3.serialize(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;
|
revision = Revision::TLROM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ void serialize(serializer &s) {
|
||||||
s.integer(prg_bank);
|
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;
|
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -220,7 +220,7 @@ void serialize(serializer &s) {
|
||||||
pulse[2].serialize(s);
|
pulse[2].serialize(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sunsoft5B(XML::Document &document, const stream &memory) : Board(document, memory) {
|
Sunsoft5B(XML::Document &document) : Board(document) {
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,16 +14,14 @@ void Cartridge::main() {
|
||||||
board->main();
|
board->main();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::load(const string &markup, const stream &memory) {
|
void Cartridge::load(const string &manifest) {
|
||||||
information.markup = markup;
|
information.markup = manifest;
|
||||||
|
|
||||||
board = Board::load(markup, memory);
|
Board::load(manifest); //this call will set Cartridge::board if successful
|
||||||
if(board == nullptr) return;
|
if(board == nullptr) return;
|
||||||
|
|
||||||
interface->memory.append({ID::RAM, "save.ram"});
|
|
||||||
|
|
||||||
sha256_ctx sha;
|
sha256_ctx sha;
|
||||||
uint8_t hash[32];
|
uint8 hash[32];
|
||||||
sha256_init(&sha);
|
sha256_init(&sha);
|
||||||
sha256_chunk(&sha, board->prgrom.data, board->prgrom.size);
|
sha256_chunk(&sha, board->prgrom.data, board->prgrom.size);
|
||||||
sha256_chunk(&sha, board->chrrom.data, board->chrrom.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() {
|
void Cartridge::unload() {
|
||||||
if(loaded == false) return;
|
if(loaded == false) return;
|
||||||
loaded = false;
|
loaded = false;
|
||||||
}
|
memory.reset();
|
||||||
|
|
||||||
unsigned Cartridge::ram_size() {
|
|
||||||
return board->memory().size;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8* Cartridge::ram_data() {
|
|
||||||
return board->memory().data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::power() {
|
void Cartridge::power() {
|
||||||
|
|
|
@ -5,12 +5,9 @@ struct Cartridge : Thread, property<Cartridge> {
|
||||||
static void Main();
|
static void Main();
|
||||||
void main();
|
void main();
|
||||||
|
|
||||||
void load(const string &markup, const stream &memory);
|
void load(const string &manifest);
|
||||||
void unload();
|
void unload();
|
||||||
|
|
||||||
unsigned ram_size();
|
|
||||||
uint8* ram_data();
|
|
||||||
|
|
||||||
void power();
|
void power();
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
@ -21,6 +18,12 @@ struct Cartridge : Thread, property<Cartridge> {
|
||||||
string markup;
|
string markup;
|
||||||
} information;
|
} information;
|
||||||
|
|
||||||
|
struct Memory {
|
||||||
|
unsigned id;
|
||||||
|
string name;
|
||||||
|
};
|
||||||
|
vector<Memory> memory;
|
||||||
|
|
||||||
void serialize(serializer&);
|
void serialize(serializer&);
|
||||||
Cartridge();
|
Cartridge();
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
struct Input {
|
struct Input {
|
||||||
enum class Device : unsigned {
|
enum class Device : unsigned {
|
||||||
None,
|
|
||||||
Joypad,
|
Joypad,
|
||||||
|
None,
|
||||||
};
|
};
|
||||||
|
|
||||||
void latch(bool data);
|
void latch(bool data);
|
||||||
|
|
|
@ -20,26 +20,46 @@ string Interface::sha256() {
|
||||||
return cartridge.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::ROM) {
|
cartridge.load(manifest);
|
||||||
cartridge.load(markup, stream);
|
}
|
||||||
system.power();
|
|
||||||
input.connect(0, Input::Device::Joypad);
|
void Interface::save() {
|
||||||
input.connect(1, Input::Device::Joypad);
|
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) {
|
if(id == ID::ProgramRAM) {
|
||||||
stream.read(cartridge.ram_data(), min(stream.size(), cartridge.ram_size()));
|
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) {
|
void Interface::save(unsigned id, const stream &stream) {
|
||||||
if(id == ID::RAM) {
|
if(id == ID::ProgramRAM) {
|
||||||
stream.write(cartridge.ram_data(), cartridge.ram_size());
|
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() {
|
void Interface::unload() {
|
||||||
|
save();
|
||||||
cartridge.unload();
|
cartridge.unload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +110,7 @@ Interface::Interface() {
|
||||||
information.aspectRatio = 8.0 / 7.0;
|
information.aspectRatio = 8.0 / 7.0;
|
||||||
information.resettable = true;
|
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"};
|
Device device{0, ID::Port1 | ID::Port2, "Controller"};
|
||||||
|
|
|
@ -4,8 +4,14 @@ namespace Famicom {
|
||||||
|
|
||||||
struct ID {
|
struct ID {
|
||||||
enum : unsigned {
|
enum : unsigned {
|
||||||
ROM,
|
Famicom,
|
||||||
RAM,
|
};
|
||||||
|
|
||||||
|
enum : unsigned {
|
||||||
|
ProgramROM,
|
||||||
|
ProgramRAM,
|
||||||
|
CharacterROM,
|
||||||
|
CharacterRAM,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum : unsigned {
|
enum : unsigned {
|
||||||
|
@ -20,7 +26,9 @@ struct Interface : Emulator::Interface {
|
||||||
|
|
||||||
bool loaded();
|
bool loaded();
|
||||||
string sha256();
|
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 save(unsigned id, const stream &stream);
|
||||||
void unload();
|
void unload();
|
||||||
|
|
||||||
|
|
|
@ -14,12 +14,8 @@ namespace GameBoy {
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
Cartridge cartridge;
|
Cartridge cartridge;
|
||||||
|
|
||||||
void Cartridge::load(System::Revision revision, const string &markup, const stream &memory) {
|
void Cartridge::load(System::Revision revision, const string &manifest, bool preloaded) {
|
||||||
romsize = memory.size() ? memory.size() : 32768u;
|
information.markup = manifest;
|
||||||
romdata = allocate<uint8>(romsize, 0xff);
|
|
||||||
memory.read(romdata, memory.size());
|
|
||||||
|
|
||||||
information.markup = markup;
|
|
||||||
information.mapper = Mapper::Unknown;
|
information.mapper = Mapper::Unknown;
|
||||||
information.ram = false;
|
information.ram = false;
|
||||||
information.battery = false;
|
information.battery = false;
|
||||||
|
@ -29,7 +25,7 @@ void Cartridge::load(System::Revision revision, const string &markup, const stre
|
||||||
information.romsize = 0;
|
information.romsize = 0;
|
||||||
information.ramsize = 0;
|
information.ramsize = 0;
|
||||||
|
|
||||||
XML::Document document(markup);
|
XML::Document document(manifest);
|
||||||
|
|
||||||
auto &mapperid = document["cartridge"]["mapper"].data;
|
auto &mapperid = document["cartridge"]["mapper"].data;
|
||||||
if(mapperid == "none" ) information.mapper = Mapper::MBC0;
|
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.rtc = document["cartridge"]["rtc"].data == "true";
|
||||||
information.rumble = document["cartridge"]["rumble"].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.romsize = numeral(document["cartridge"]["rom"]["size"].data);
|
||||||
information.ramsize = numeral(document["cartridge"]["ram"]["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:
|
switch(information.mapper) { default:
|
||||||
case Mapper::MBC0: mapper = &mbc0; break;
|
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;
|
case Mapper::HuC3: mapper = &huc3; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ramdata = new uint8_t[ramsize = information.ramsize]();
|
|
||||||
system.load(revision);
|
system.load(revision);
|
||||||
|
|
||||||
loaded = true;
|
loaded = true;
|
||||||
sha256 = nall::sha256(romdata, romsize);
|
sha256 = nall::sha256(romdata, romsize);
|
||||||
if(ramsize) interface->memory.append({ID::RAM, "save.ram"});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::unload() {
|
void Cartridge::unload() {
|
||||||
if(loaded == false) return;
|
if(loaded == false) return;
|
||||||
|
|
||||||
if(romdata) { delete[] romdata; romdata = 0; }
|
if(romdata) { delete[] romdata; romdata = nullptr; }
|
||||||
if(ramdata) { delete[] ramdata; ramdata = 0; }
|
if(ramdata) { delete[] ramdata; ramdata = nullptr; }
|
||||||
loaded = false;
|
loaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,12 @@ struct Cartridge : MMIO, property<Cartridge> {
|
||||||
unsigned ramsize;
|
unsigned ramsize;
|
||||||
} information;
|
} information;
|
||||||
|
|
||||||
|
struct Memory {
|
||||||
|
unsigned id;
|
||||||
|
string name;
|
||||||
|
};
|
||||||
|
vector<Memory> memory;
|
||||||
|
|
||||||
readonly<bool> loaded;
|
readonly<bool> loaded;
|
||||||
readonly<string> sha256;
|
readonly<string> sha256;
|
||||||
|
|
||||||
|
@ -45,7 +51,7 @@ struct Cartridge : MMIO, property<Cartridge> {
|
||||||
MMIO *mapper;
|
MMIO *mapper;
|
||||||
bool bootrom_enable;
|
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();
|
void unload();
|
||||||
|
|
||||||
uint8 rom_read(unsigned addr);
|
uint8 rom_read(unsigned addr);
|
||||||
|
|
|
@ -28,7 +28,19 @@ string Interface::sha256() {
|
||||||
return cartridge.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) {
|
if(id == ID::GameBoyBootROM) {
|
||||||
stream.read(system.bootROM.dmg, min( 256u, stream.size()));
|
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()));
|
stream.read(system.bootROM.cgb, min(2048u, stream.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == ID::GameBoyROM) {
|
if(id == ID::ROM) {
|
||||||
cartridge.load(System::Revision::GameBoy, markup, stream);
|
stream.read(cartridge.romdata, min(cartridge.romsize, stream.size()));
|
||||||
system.power();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(id == ID::GameBoyColorROM) {
|
|
||||||
cartridge.load(System::Revision::GameBoyColor, markup, stream);
|
|
||||||
system.power();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == ID::RAM) {
|
if(id == ID::RAM) {
|
||||||
|
@ -63,6 +69,7 @@ void Interface::save(unsigned id, const stream &stream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interface::unload() {
|
void Interface::unload() {
|
||||||
|
save();
|
||||||
cartridge.unload();
|
cartridge.unload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,8 +125,8 @@ Interface::Interface() {
|
||||||
firmware.append({ID::SuperGameBoyBootROM, "Super Game Boy", "sfc", "boot.rom"});
|
firmware.append({ID::SuperGameBoyBootROM, "Super Game Boy", "sfc", "boot.rom"});
|
||||||
firmware.append({ID::GameBoyColorBootROM, "Game Boy Color", "sys", "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::GameBoy, "Game Boy", "sys", "program.rom", "gb" });
|
||||||
media.append({ID::GameBoyColorROM, "Game Boy Color", "sys", "program.rom", "gbc"});
|
media.append({ID::GameBoyColor, "Game Boy Color", "sys", "program.rom", "gbc"});
|
||||||
|
|
||||||
{
|
{
|
||||||
Device device{0, ID::Device, "Controller"};
|
Device device{0, ID::Device, "Controller"};
|
||||||
|
|
|
@ -3,12 +3,19 @@ namespace GameBoy {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct ID {
|
struct ID {
|
||||||
|
enum : unsigned {
|
||||||
|
GameBoy,
|
||||||
|
SuperGameBoy,
|
||||||
|
GameBoyColor,
|
||||||
|
};
|
||||||
|
|
||||||
enum : unsigned {
|
enum : unsigned {
|
||||||
GameBoyBootROM,
|
GameBoyBootROM,
|
||||||
SuperGameBoyBootROM,
|
SuperGameBoyBootROM,
|
||||||
GameBoyColorBootROM,
|
GameBoyColorBootROM,
|
||||||
GameBoyROM,
|
GameBoyROM,
|
||||||
GameBoyColorROM,
|
GameBoyColorROM,
|
||||||
|
ROM,
|
||||||
RAM,
|
RAM,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,7 +39,9 @@ struct Interface : Emulator::Interface {
|
||||||
|
|
||||||
bool loaded();
|
bool loaded();
|
||||||
string sha256();
|
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 save(unsigned id, const stream &stream);
|
||||||
void unload();
|
void unload();
|
||||||
|
|
||||||
|
|
|
@ -7,14 +7,18 @@ namespace GameBoyAdvance {
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
Cartridge cartridge;
|
Cartridge cartridge;
|
||||||
|
|
||||||
bool Cartridge::load(const string &markup, const stream &memory) {
|
void Cartridge::load(const string &manifest) {
|
||||||
information.markup = markup;
|
information.markup = manifest;
|
||||||
XML::Document document(markup);
|
XML::Document document(manifest);
|
||||||
|
|
||||||
unsigned size = memory.size();
|
unsigned rom_size = 0;
|
||||||
memory.read(rom.data, min(rom.size, size));
|
if(document["cartridge"]["rom"].exists()) {
|
||||||
for(unsigned addr = size; addr < rom.size; addr++) {
|
auto &info = document["cartridge"]["rom"];
|
||||||
rom.data[addr] = rom.data[Bus::mirror(addr, size)];
|
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_sram = false;
|
||||||
|
@ -30,7 +34,8 @@ bool Cartridge::load(const string &markup, const stream &memory) {
|
||||||
ram.mask = ram.size - 1;
|
ram.mask = ram.size - 1;
|
||||||
for(unsigned n = 0; n < ram.size; n++) ram.data[n] = 0xff;
|
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") {
|
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.size = numeral(info["size"].data);
|
||||||
eeprom.bits = eeprom.size <= 512 ? 6 : 14;
|
eeprom.bits = eeprom.size <= 512 ? 6 : 14;
|
||||||
if(eeprom.size == 0) eeprom.size = 8192, eeprom.bits = 0; //auto-detect size
|
if(eeprom.size == 0) eeprom.size = 8192, eeprom.bits = 0; //auto-detect size
|
||||||
eeprom.mask = size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000;
|
eeprom.mask = rom_size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000;
|
||||||
eeprom.test = size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
|
eeprom.test = rom_size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
|
||||||
for(unsigned n = 0; n < eeprom.size; n++) eeprom.data[n] = 0xff;
|
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") {
|
if(info["type"].data == "FlashROM") {
|
||||||
|
@ -51,19 +57,21 @@ bool Cartridge::load(const string &markup, const stream &memory) {
|
||||||
flashrom.size = numeral(info["size"].data);
|
flashrom.size = numeral(info["size"].data);
|
||||||
for(unsigned n = 0; n < flashrom.size; n++) flashrom.data[n] = 0xff;
|
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();
|
system.load();
|
||||||
return loaded = true;
|
loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::unload() {
|
void Cartridge::unload() {
|
||||||
if(loaded == false) return;
|
if(loaded == false) return;
|
||||||
loaded = false;
|
loaded = false;
|
||||||
|
memory.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::power() {
|
void Cartridge::power() {
|
||||||
|
|
|
@ -12,7 +12,13 @@ struct Cartridge : property<Cartridge> {
|
||||||
string markup;
|
string markup;
|
||||||
} information;
|
} 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 unload();
|
||||||
void power();
|
void power();
|
||||||
|
|
||||||
|
|
|
@ -16,15 +16,23 @@ bool Interface::loaded() {
|
||||||
return cartridge.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) {
|
if(id == ID::BIOS) {
|
||||||
stream.read(bios.data, min(bios.size, stream.size()));
|
stream.read(bios.data, min(bios.size, stream.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == ID::ROM) {
|
if(id == ID::ROM) {
|
||||||
memory.reset();
|
stream.read(cartridge.rom.data, min(cartridge.rom.size, stream.size()));
|
||||||
cartridge.load(markup, stream);
|
|
||||||
system.power();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == ID::RAM) {
|
if(id == ID::RAM) {
|
||||||
|
@ -55,6 +63,7 @@ void Interface::save(unsigned id, const stream &stream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interface::unload() {
|
void Interface::unload() {
|
||||||
|
save();
|
||||||
cartridge.unload();
|
cartridge.unload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +104,7 @@ Interface::Interface() {
|
||||||
|
|
||||||
firmware.append({ID::BIOS, "Game Boy Advance", "sys", "bios.rom"});
|
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"};
|
Device device{0, ID::Device, "Controller"};
|
||||||
|
|
|
@ -3,6 +3,10 @@ namespace GameBoyAdvance {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct ID {
|
struct ID {
|
||||||
|
enum : unsigned {
|
||||||
|
GameBoyAdvance,
|
||||||
|
};
|
||||||
|
|
||||||
enum : unsigned {
|
enum : unsigned {
|
||||||
BIOS,
|
BIOS,
|
||||||
ROM,
|
ROM,
|
||||||
|
@ -21,7 +25,9 @@ struct Interface : Emulator::Interface {
|
||||||
double audioFrequency();
|
double audioFrequency();
|
||||||
|
|
||||||
bool loaded();
|
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 save(unsigned id, const stream &stream);
|
||||||
void unload();
|
void unload();
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<cartridge region="NTSC">
|
<cartridge region="NTSC">
|
||||||
|
<rom name="program.rom" size="0x100000"/>
|
||||||
|
<ram name="save.ram" size="0x8000"/>
|
||||||
<bsx>
|
<bsx>
|
||||||
|
<psram name="bsx.ram" size="0x40000"/>
|
||||||
<mcu>
|
<mcu>
|
||||||
<map address="00-3f:8000-ffff"/>
|
<map address="00-3f:8000-ffff"/>
|
||||||
<map address="80-bf:8000-ffff"/>
|
<map address="80-bf:8000-ffff"/>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<cartridge region="NTSC">
|
<cartridge region="NTSC">
|
||||||
<boot firmware="boot.rom" sha256="0e4ddff32fc9d1eeaae812a157dd246459b00c9e14f2f61751f661f32361e360"/>
|
<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="00-7f:8000-ffff"/>
|
||||||
<map mode="linear" address="80-ff:8000-ffff"/>
|
<map mode="linear" address="80-ff:8000-ffff"/>
|
||||||
</rom>
|
</rom>
|
||||||
|
|
|
@ -32,13 +32,13 @@ endif
|
||||||
obj/sfc-interface.o : $(sfc)/interface/interface.cpp $(call rwildcard,$(sfc)/interface)
|
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-system.o : $(sfc)/system/system.cpp $(call rwildcard,$(sfc)/system/)
|
||||||
obj/sfc-controller.o: $(sfc)/controller/controller.cpp $(call rwildcard,$(sfc)/controller/)
|
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-memory.o : $(sfc)/memory/memory.cpp $(call rwildcard,$(sfc)/memory/)
|
||||||
obj/sfc-cpu.o : $(sfccpu)/cpu.cpp $(call rwildcard,$(sfccpu)/)
|
obj/sfc-cpu.o : $(sfccpu)/cpu.cpp $(call rwildcard,$(sfccpu)/)
|
||||||
obj/sfc-smp.o : $(sfcsmp)/smp.cpp $(call rwildcard,$(sfcsmp)/)
|
obj/sfc-smp.o : $(sfcsmp)/smp.cpp $(call rwildcard,$(sfcsmp)/)
|
||||||
obj/sfc-dsp.o : $(sfcdsp)/dsp.cpp $(call rwildcard,$(sfcdsp)/)
|
obj/sfc-dsp.o : $(sfcdsp)/dsp.cpp $(call rwildcard,$(sfcdsp)/)
|
||||||
obj/sfc-ppu.o : $(sfcppu)/ppu.cpp $(call rwildcard,$(sfcppu)/)
|
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-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/)
|
obj/sfc-bsx.o : $(sfc)/chip/bsx/bsx.cpp $(call rwildcard,$(sfc)/chip/bsx/)
|
||||||
|
|
|
@ -8,11 +8,62 @@ namespace SuperFamicom {
|
||||||
|
|
||||||
Cartridge cartridge;
|
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) {
|
void Cartridge::load(const string &markup, const stream &stream) {
|
||||||
rom.copy(stream);
|
rom.copy(stream);
|
||||||
|
|
||||||
region = Region::NTSC;
|
region = Region::NTSC;
|
||||||
ram_size = 0;
|
//ram_size = 0;
|
||||||
|
|
||||||
has_gb_slot = false;
|
has_gb_slot = false;
|
||||||
has_bs_cart = 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());
|
sha256 = nall::sha256(rom.data(), rom.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
interface->memory.append({ID::RAM, "save.ram"});
|
// interface->memory.append({ID::RAM, "save.ram"});
|
||||||
}
|
// }
|
||||||
|
|
||||||
rom.write_protect(true);
|
rom.write_protect(true);
|
||||||
ram.write_protect(false);
|
ram.write_protect(false);
|
||||||
|
@ -75,6 +126,7 @@ void Cartridge::unload() {
|
||||||
ram.reset();
|
ram.reset();
|
||||||
|
|
||||||
loaded = false;
|
loaded = false;
|
||||||
|
memory.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
Cartridge::Cartridge() {
|
Cartridge::Cartridge() {
|
||||||
|
|
|
@ -20,7 +20,6 @@ struct Cartridge : property<Cartridge> {
|
||||||
readonly<string> sha256;
|
readonly<string> sha256;
|
||||||
|
|
||||||
readonly<Region> region;
|
readonly<Region> region;
|
||||||
readonly<unsigned> ram_size;
|
|
||||||
|
|
||||||
readonly<bool> has_gb_slot;
|
readonly<bool> has_gb_slot;
|
||||||
readonly<bool> has_bs_cart;
|
readonly<bool> has_bs_cart;
|
||||||
|
@ -53,10 +52,17 @@ struct Cartridge : property<Cartridge> {
|
||||||
|
|
||||||
Mapping();
|
Mapping();
|
||||||
Mapping(const function<uint8 (unsigned)>&, const function<void (unsigned, uint8)>&);
|
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 load(const string &markup, const stream &stream);
|
||||||
void unload();
|
void unload();
|
||||||
|
|
||||||
|
@ -67,6 +73,7 @@ struct Cartridge : property<Cartridge> {
|
||||||
private:
|
private:
|
||||||
void parse_markup(const char*);
|
void parse_markup(const char*);
|
||||||
void parse_markup_map(Mapping&, XML::Node&);
|
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_rom(XML::Node&);
|
||||||
void parse_markup_ram(XML::Node&);
|
void parse_markup_ram(XML::Node&);
|
||||||
|
|
|
@ -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) {
|
void Cartridge::parse_markup_rom(XML::Node &root) {
|
||||||
if(root.exists() == false) return;
|
if(root.exists() == false) return;
|
||||||
|
parse_markup_memory(rom, root, ID::ROM, false);
|
||||||
|
|
||||||
for(auto &node : root) {
|
for(auto &node : root) {
|
||||||
if(node.name != "map") continue;
|
if(node.name != "map") continue;
|
||||||
Mapping m(rom);
|
Mapping m(rom);
|
||||||
|
@ -77,11 +89,12 @@ void Cartridge::parse_markup_rom(XML::Node &root) {
|
||||||
|
|
||||||
void Cartridge::parse_markup_ram(XML::Node &root) {
|
void Cartridge::parse_markup_ram(XML::Node &root) {
|
||||||
if(root.exists() == false) return;
|
if(root.exists() == false) return;
|
||||||
ram_size = numeral(root["size"].data);
|
parse_markup_memory(ram, root, ID::RAM, true);
|
||||||
|
|
||||||
for(auto &node : root) {
|
for(auto &node : root) {
|
||||||
Mapping m(ram);
|
Mapping m(ram);
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
if(m.size == 0) m.size = ram_size;
|
if(m.size == 0) m.size = ram.size();
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,7 +116,7 @@ void Cartridge::parse_markup_icd2(XML::Node &root) {
|
||||||
|
|
||||||
for(auto &node : root) {
|
for(auto &node : root) {
|
||||||
if(node.name != "map") continue;
|
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);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
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");
|
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"]) {
|
for(auto &node : root["slot"]) {
|
||||||
if(node.name != "map") continue;
|
if(node.name != "map") continue;
|
||||||
Mapping m(bsxflash.memory);
|
Mapping m(bsxflash.memory);
|
||||||
|
@ -125,14 +142,14 @@ void Cartridge::parse_markup_bsx(XML::Node &root) {
|
||||||
|
|
||||||
for(auto &node : root["mmio"]) {
|
for(auto &node : root["mmio"]) {
|
||||||
if(node.name != "map") continue;
|
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);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto &node : root["mcu"]) {
|
for(auto &node : root["mcu"]) {
|
||||||
if(node.name != "map") continue;
|
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);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
@ -152,7 +169,7 @@ void Cartridge::parse_markup_sufamiturbo(XML::Node &root) {
|
||||||
if(node.name == "rom") {
|
if(node.name == "rom") {
|
||||||
for(auto &leaf : node) {
|
for(auto &leaf : node) {
|
||||||
if(leaf.name != "map") continue;
|
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);
|
Mapping m(memory);
|
||||||
parse_markup_map(m, leaf);
|
parse_markup_map(m, leaf);
|
||||||
if(m.size == 0) m.size = memory.size();
|
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);
|
unsigned ram_size = numeral(node["size"].data);
|
||||||
for(auto &leaf : node) {
|
for(auto &leaf : node) {
|
||||||
if(leaf.name != "map") continue;
|
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);
|
Mapping m(memory);
|
||||||
parse_markup_map(m, leaf);
|
parse_markup_map(m, leaf);
|
||||||
if(m.size == 0) m.size = ram_size;
|
if(m.size == 0) m.size = ram_size;
|
||||||
|
@ -193,14 +210,14 @@ void Cartridge::parse_markup_sa1(XML::Node &root) {
|
||||||
|
|
||||||
for(auto &node : mcurom) {
|
for(auto &node : mcurom) {
|
||||||
if(node.name != "map") continue;
|
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);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto &node : mcuram) {
|
for(auto &node : mcuram) {
|
||||||
if(node.name != "map") continue;
|
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);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
@ -213,18 +230,18 @@ void Cartridge::parse_markup_sa1(XML::Node &root) {
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
ram_size = numeral(bwram["size"].data);
|
parse_markup_memory(ram, bwram, ID::RAM, true);
|
||||||
for(auto &node : bwram) {
|
for(auto &node : bwram) {
|
||||||
if(node.name != "map") continue;
|
if(node.name != "map") continue;
|
||||||
Mapping m(sa1.cpubwram);
|
Mapping m(sa1.cpubwram);
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
if(m.size == 0) m.size = ram_size;
|
if(m.size == 0) m.size = ram.size();
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto &node : mmio) {
|
for(auto &node : mmio) {
|
||||||
if(node.name != "map") continue;
|
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);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
@ -236,6 +253,8 @@ void Cartridge::parse_markup_superfx(XML::Node &root) {
|
||||||
|
|
||||||
for(auto &node : root) {
|
for(auto &node : root) {
|
||||||
if(node.name == "rom") {
|
if(node.name == "rom") {
|
||||||
|
parse_markup_memory(rom, node, ID::ROM, false);
|
||||||
|
|
||||||
for(auto &leaf : node) {
|
for(auto &leaf : node) {
|
||||||
if(leaf.name != "map") continue;
|
if(leaf.name != "map") continue;
|
||||||
Mapping m(superfx.rom);
|
Mapping m(superfx.rom);
|
||||||
|
@ -244,22 +263,20 @@ void Cartridge::parse_markup_superfx(XML::Node &root) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(node.name == "ram") {
|
if(node.name == "ram") {
|
||||||
|
parse_markup_memory(ram, node, ID::RAM, false);
|
||||||
|
|
||||||
for(auto &leaf : node) {
|
for(auto &leaf : node) {
|
||||||
if(leaf.name == "size") {
|
|
||||||
ram_size = numeral(leaf.data);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(leaf.name != "map") continue;
|
if(leaf.name != "map") continue;
|
||||||
Mapping m(superfx.ram);
|
Mapping m(superfx.ram);
|
||||||
parse_markup_map(m, leaf);
|
parse_markup_map(m, leaf);
|
||||||
if(m.size == 0) m.size = ram_size;
|
if(m.size == 0) m.size = ram.size();
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(node.name == "mmio") {
|
if(node.name == "mmio") {
|
||||||
for(auto &leaf : node) {
|
for(auto &leaf : node) {
|
||||||
if(leaf.name != "map") continue;
|
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);
|
parse_markup_map(m, leaf);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
}
|
}
|
||||||
|
@ -338,6 +355,9 @@ void Cartridge::parse_markup_necdsp(XML::Node &root) {
|
||||||
|
|
||||||
if(necdsp.revision == NECDSP::Revision::uPD96050) {
|
if(necdsp.revision == NECDSP::Revision::uPD96050) {
|
||||||
interface->loadRequest(ID::Nec96050DSP, firmware);
|
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) {
|
for(auto &node : root) {
|
||||||
|
@ -369,6 +389,10 @@ void Cartridge::parse_markup_epsonrtc(XML::Node &root) {
|
||||||
if(root.exists() == false) return;
|
if(root.exists() == false) return;
|
||||||
has_epsonrtc = true;
|
has_epsonrtc = true;
|
||||||
|
|
||||||
|
string name = root["name"].data;
|
||||||
|
interface->loadRequest(ID::EpsonRTC, name);
|
||||||
|
memory.append({ID::EpsonRTC, name});
|
||||||
|
|
||||||
for(auto &node : root) {
|
for(auto &node : root) {
|
||||||
if(node.name != "map") continue;
|
if(node.name != "map") continue;
|
||||||
Mapping m({&EpsonRTC::read, &epsonrtc}, {&EpsonRTC::write, &epsonrtc});
|
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;
|
if(root.exists() == false) return;
|
||||||
has_sharprtc = true;
|
has_sharprtc = true;
|
||||||
|
|
||||||
|
string name = root["name"].data;
|
||||||
|
interface->loadRequest(ID::SharpRTC, name);
|
||||||
|
memory.append({ID::SharpRTC, name});
|
||||||
|
|
||||||
for(auto &node : root) {
|
for(auto &node : root) {
|
||||||
if(node.name != "map") continue;
|
if(node.name != "map") continue;
|
||||||
Mapping m({&SharpRTC::read, &sharprtc}, {&SharpRTC::write, &sharprtc});
|
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_base = numeral(mcurom["data"]["offset"].data);
|
||||||
spc7110.drom_size = numeral(mcurom["data"]["size"].data);
|
spc7110.drom_size = numeral(mcurom["data"]["size"].data);
|
||||||
|
|
||||||
ram_size = numeral(mcuram["size"].data);
|
|
||||||
|
|
||||||
for(auto &node : mmio) {
|
for(auto &node : mmio) {
|
||||||
if(node.name != "map") continue;
|
if(node.name != "map") continue;
|
||||||
Mapping m({&SPC7110::mmio_read, &spc7110}, {&SPC7110::mmio_write, &spc7110});
|
Mapping m({&SPC7110::mmio_read, &spc7110}, {&SPC7110::mmio_write, &spc7110});
|
||||||
|
@ -509,9 +535,9 @@ Cartridge::Mapping::Mapping() {
|
||||||
banklo = bankhi = addrlo = addrhi = offset = size = 0;
|
banklo = bankhi = addrlo = addrhi = offset = size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Cartridge::Mapping::Mapping(Memory &memory) {
|
Cartridge::Mapping::Mapping(SuperFamicom::Memory &memory) {
|
||||||
read = { &Memory::read, &memory };
|
read = {&SuperFamicom::Memory::read, &memory};
|
||||||
write = { &Memory::write, &memory };
|
write = {&SuperFamicom::Memory::write, &memory};
|
||||||
mode = Bus::MapMode::Direct;
|
mode = Bus::MapMode::Direct;
|
||||||
banklo = bankhi = addrlo = addrhi = offset = size = 0;
|
banklo = bankhi = addrlo = addrhi = offset = size = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,6 @@ void BSXCartridge::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BSXCartridge::load() {
|
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() {
|
void BSXCartridge::unload() {
|
||||||
|
@ -106,7 +99,7 @@ uint8 BSXCartridge::mmio_read(unsigned addr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0xf8f000) == 0x105000) { //$10-17:5000-5fff
|
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;
|
return 0x00;
|
||||||
|
@ -121,7 +114,7 @@ void BSXCartridge::mmio_write(unsigned addr, uint8 data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if((addr & 0xf8f000) == 0x105000) { //$10-17:5000-5fff
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
struct BSXCartridge {
|
struct BSXCartridge {
|
||||||
MappedRAM sram;
|
|
||||||
MappedRAM psram;
|
MappedRAM psram;
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
void BSXCartridge::serialize(serializer &s) {
|
void BSXCartridge::serialize(serializer &s) {
|
||||||
s.array(sram.data(), sram.size());
|
|
||||||
s.array(psram.data(), psram.size());
|
s.array(psram.data(), psram.size());
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ void EpsonRTC::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EpsonRTC::load() {
|
void EpsonRTC::load() {
|
||||||
interface->memory.append({ID::EpsonRTC, "rtc.ram"});
|
return;
|
||||||
|
|
||||||
secondlo = 0;
|
secondlo = 0;
|
||||||
secondhi = 0;
|
secondhi = 0;
|
||||||
|
|
|
@ -167,11 +167,11 @@ void EpsonRTC::load(const uint8 *data) {
|
||||||
void EpsonRTC::save(uint8 *data) {
|
void EpsonRTC::save(uint8 *data) {
|
||||||
data[0] = secondlo << 0 | secondhi << 4 | batteryfailure << 7;
|
data[0] = secondlo << 0 | secondhi << 4 | batteryfailure << 7;
|
||||||
data[1] = minutelo << 0 | minutehi << 4 | resync << 7;
|
data[1] = minutelo << 0 | minutehi << 4 | resync << 7;
|
||||||
data[2] = hourlo << 0 | hourhi << 4 | meridian << 6;
|
data[2] = hourlo << 0 | hourhi << 4 | meridian << 6 | resync << 7;
|
||||||
data[3] = daylo << 0 | dayhi << 4 | dayram << 6;
|
data[3] = daylo << 0 | dayhi << 4 | dayram << 6 | resync << 7;
|
||||||
data[4] = monthlo << 0 | monthhi << 4 | monthram << 5;
|
data[4] = monthlo << 0 | monthhi << 4 | monthram << 5 | resync << 7;
|
||||||
data[5] = yearlo << 0 | yearhi << 4;
|
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;
|
data[7] = irqmask << 0 | irqduty << 1 | irqperiod << 2 | pause << 4 | stop << 5 | atime << 6 | test << 7;
|
||||||
|
|
||||||
uint64 timestamp = (uint64)time(0);
|
uint64 timestamp = (uint64)time(0);
|
||||||
|
|
|
@ -147,12 +147,6 @@ void EpsonRTC::tick_day() {
|
||||||
return tick_month();
|
return tick_month();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(days == 31 && (dayhi == 3 && (daylo & 3))) {
|
|
||||||
daylo = 1;
|
|
||||||
dayhi = 0;
|
|
||||||
return tick_month();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(daylo <= 8 || daylo == 12) {
|
if(daylo <= 8 || daylo == 12) {
|
||||||
daylo++;
|
daylo++;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -37,8 +37,6 @@ void ICD2::load() {
|
||||||
hook = GameBoy::interface->hook;
|
hook = GameBoy::interface->hook;
|
||||||
GameBoy::interface->bind = this;
|
GameBoy::interface->bind = this;
|
||||||
GameBoy::interface->hook = this;
|
GameBoy::interface->hook = this;
|
||||||
|
|
||||||
interface->memory.append({ID::SuperGameBoyRAM, "save.ram"});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ICD2::unload() {
|
void ICD2::unload() {
|
||||||
|
|
|
@ -10,6 +10,8 @@ MSU1 msu1;
|
||||||
void MSU1::Enter() { msu1.enter(); }
|
void MSU1::Enter() { msu1.enter(); }
|
||||||
|
|
||||||
void MSU1::enter() {
|
void MSU1::enter() {
|
||||||
|
for(unsigned addr = 0; addr <= 7; addr++) mmio_write(addr, 0x00);
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||||
|
@ -75,6 +77,7 @@ void MSU1::reset() {
|
||||||
mmio.audio_busy = true;
|
mmio.audio_busy = true;
|
||||||
mmio.audio_repeat = false;
|
mmio.audio_repeat = false;
|
||||||
mmio.audio_play = false;
|
mmio.audio_play = false;
|
||||||
|
mmio.audio_error = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 MSU1::mmio_read(unsigned addr) {
|
uint8 MSU1::mmio_read(unsigned addr) {
|
||||||
|
@ -86,6 +89,7 @@ uint8 MSU1::mmio_read(unsigned addr) {
|
||||||
| (mmio.audio_busy << 6)
|
| (mmio.audio_busy << 6)
|
||||||
| (mmio.audio_repeat << 5)
|
| (mmio.audio_repeat << 5)
|
||||||
| (mmio.audio_play << 4)
|
| (mmio.audio_play << 4)
|
||||||
|
| (mmio.audio_error << 3)
|
||||||
| (Revision << 0);
|
| (Revision << 0);
|
||||||
case 1:
|
case 1:
|
||||||
if(mmio.data_busy) return 0x00;
|
if(mmio.data_busy) return 0x00;
|
||||||
|
@ -97,9 +101,8 @@ uint8 MSU1::mmio_read(unsigned addr) {
|
||||||
case 4: return 'M';
|
case 4: return 'M';
|
||||||
case 5: return 'S';
|
case 5: return 'S';
|
||||||
case 6: return 'U';
|
case 6: return 'U';
|
||||||
case 7: return '0' + Revision;
|
case 7: return '1';
|
||||||
}
|
}
|
||||||
throw;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MSU1::mmio_write(unsigned addr, uint8 data) {
|
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_busy = false;
|
||||||
mmio.audio_repeat = false;
|
mmio.audio_repeat = false;
|
||||||
mmio.audio_play = false;
|
mmio.audio_play = false;
|
||||||
|
mmio.audio_error = !audiofile.open();
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
mmio.audio_volume = data;
|
mmio.audio_volume = data;
|
||||||
|
|
|
@ -21,6 +21,7 @@ private:
|
||||||
AudioBusy = 0x40,
|
AudioBusy = 0x40,
|
||||||
AudioRepeating = 0x20,
|
AudioRepeating = 0x20,
|
||||||
AudioPlaying = 0x10,
|
AudioPlaying = 0x10,
|
||||||
|
AudioError = 0x08,
|
||||||
Revision = 0x01,
|
Revision = 0x01,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,6 +37,7 @@ private:
|
||||||
bool audio_busy;
|
bool audio_busy;
|
||||||
bool audio_repeat;
|
bool audio_repeat;
|
||||||
bool audio_play;
|
bool audio_play;
|
||||||
|
bool audio_error;
|
||||||
} mmio;
|
} mmio;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ void MSU1::serialize(serializer &s) {
|
||||||
s.integer(mmio.audio_busy);
|
s.integer(mmio.audio_busy);
|
||||||
s.integer(mmio.audio_repeat);
|
s.integer(mmio.audio_repeat);
|
||||||
s.integer(mmio.audio_play);
|
s.integer(mmio.audio_play);
|
||||||
|
s.integer(mmio.audio_error);
|
||||||
|
|
||||||
if(datafile.open()) datafile.close();
|
if(datafile.open()) datafile.close();
|
||||||
if(datafile.open({interface->path(0), "msu1.rom"}, file::mode::read)) {
|
if(datafile.open({interface->path(0), "msu1.rom"}, file::mode::read)) {
|
||||||
|
|
|
@ -33,9 +33,6 @@ void NECDSP::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void NECDSP::load() {
|
void NECDSP::load() {
|
||||||
if(revision == Revision::uPD96050) {
|
|
||||||
interface->memory.append({ID::NecDSPRAM, "upd96050.ram"});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NECDSP::unload() {
|
void NECDSP::unload() {
|
||||||
|
|
|
@ -29,7 +29,7 @@ void SharpRTC::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharpRTC::load() {
|
void SharpRTC::load() {
|
||||||
interface->memory.append({ID::SharpRTC, "rtc.ram"});
|
return;
|
||||||
|
|
||||||
second = 0;
|
second = 0;
|
||||||
minute = 0;
|
minute = 0;
|
||||||
|
@ -37,6 +37,7 @@ void SharpRTC::load() {
|
||||||
day = 0;
|
day = 0;
|
||||||
month = 0;
|
month = 0;
|
||||||
year = 0;
|
year = 0;
|
||||||
|
weekday = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharpRTC::unload() {
|
void SharpRTC::unload() {
|
||||||
|
|
|
@ -10,15 +10,11 @@ void SufamiTurbo::load() {
|
||||||
slotA.ram.map(allocate<uint8>(128 * 1024, 0xff), 128 * 1024);
|
slotA.ram.map(allocate<uint8>(128 * 1024, 0xff), 128 * 1024);
|
||||||
slotB.ram.map(allocate<uint8>(128 * 1024, 0xff), 128 * 1024);
|
slotB.ram.map(allocate<uint8>(128 * 1024, 0xff), 128 * 1024);
|
||||||
|
|
||||||
if(slotA.rom.data()) {
|
if(slotA.rom.data() == nullptr) {
|
||||||
interface->memory.append({ID::SufamiTurboSlotARAM, "save.ram"});
|
|
||||||
} else {
|
|
||||||
slotA.rom.map(allocate<uint8>(128 * 1024, 0xff), 128 * 1024);
|
slotA.rom.map(allocate<uint8>(128 * 1024, 0xff), 128 * 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(slotB.rom.data()) {
|
if(slotB.rom.data() == nullptr) {
|
||||||
interface->memory.append({ID::SufamiTurboSlotBRAM, "save.ram"});
|
|
||||||
} else {
|
|
||||||
slotB.rom.map(allocate<uint8>(128 * 1024, 0xff), 128 * 1024);
|
slotB.rom.map(allocate<uint8>(128 * 1024, 0xff), 128 * 1024);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,6 @@ unsigned Interface::group(unsigned id) {
|
||||||
case ID::Nec7725DSP:
|
case ID::Nec7725DSP:
|
||||||
case ID::Nec96050DSP:
|
case ID::Nec96050DSP:
|
||||||
case ID::NecDSPRAM:
|
case ID::NecDSPRAM:
|
||||||
case ID::BsxRAM:
|
|
||||||
case ID::BsxPSRAM:
|
case ID::BsxPSRAM:
|
||||||
return 0;
|
return 0;
|
||||||
case ID::SuperGameBoyROM:
|
case ID::SuperGameBoyROM:
|
||||||
|
@ -50,14 +49,23 @@ unsigned Interface::group(unsigned id) {
|
||||||
return 0;
|
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) {
|
if(id == ID::IPLROM) {
|
||||||
stream.read(smp.iplrom, min(64u, stream.size()));
|
stream.read(smp.iplrom, min(64u, stream.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == ID::ROM) {
|
if(id == ID::ROM) {
|
||||||
cartridge.load(markup, stream);
|
stream.read(cartridge.rom.data(), min(cartridge.rom.size(), stream.size()));
|
||||||
system.power();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == ID::RAM) {
|
if(id == ID::RAM) {
|
||||||
|
@ -99,7 +107,8 @@ void Interface::load(unsigned id, const stream &stream, const string &markup) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == ID::SuperGameBoyROM) {
|
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) {
|
if(id == ID::SuperGameBoyRAM) {
|
||||||
|
@ -110,10 +119,6 @@ void Interface::load(unsigned id, const stream &stream, const string &markup) {
|
||||||
bsxflash.memory.copy(stream);
|
bsxflash.memory.copy(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == ID::BsxRAM) {
|
|
||||||
stream.read(bsxcartridge.sram.data(), min(stream.size(), bsxcartridge.sram.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(id == ID::BsxPSRAM) {
|
if(id == ID::BsxPSRAM) {
|
||||||
stream.read(bsxcartridge.psram.data(), min(stream.size(), bsxcartridge.psram.size()));
|
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);
|
stream.write(GameBoy::cartridge.ramdata, GameBoy::cartridge.ramsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == ID::BsxRAM) {
|
|
||||||
stream.write(bsxcartridge.sram.data(), bsxcartridge.sram.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(id == ID::BsxPSRAM) {
|
if(id == ID::BsxPSRAM) {
|
||||||
stream.write(bsxcartridge.psram.data(), bsxcartridge.psram.size());
|
stream.write(bsxcartridge.psram.data(), bsxcartridge.psram.size());
|
||||||
}
|
}
|
||||||
|
@ -179,6 +180,7 @@ void Interface::save(unsigned id, const stream &stream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interface::unload() {
|
void Interface::unload() {
|
||||||
|
save();
|
||||||
cartridge.unload();
|
cartridge.unload();
|
||||||
tracerEnable(false);
|
tracerEnable(false);
|
||||||
}
|
}
|
||||||
|
@ -285,10 +287,10 @@ Interface::Interface() {
|
||||||
|
|
||||||
firmware.append({ID::IPLROM, "Super Famicom", "sys", "spc700.rom"});
|
firmware.append({ID::IPLROM, "Super Famicom", "sys", "spc700.rom"});
|
||||||
|
|
||||||
media.append({ID::ROM, "Super Famicom", "sys", "program.rom", "sfc"});
|
media.append({ID::SuperFamicom, "Super Famicom", "sys", "program.rom", "sfc"});
|
||||||
media.append({ID::ROM, "Super Game Boy", "sfc", "program.rom", "gb" });
|
media.append({ID::SuperFamicom, "Super Game Boy", "sfc", "program.rom", "gb" });
|
||||||
media.append({ID::ROM, "BS-X Satellaview", "sfc", "program.rom", "bs" });
|
media.append({ID::SuperFamicom, "BS-X Satellaview", "sfc", "program.rom", "bs" });
|
||||||
media.append({ID::ROM, "Sufami Turbo", "sfc", "program.rom", "st" });
|
media.append({ID::SuperFamicom, "Sufami Turbo", "sfc", "program.rom", "st" });
|
||||||
|
|
||||||
{
|
{
|
||||||
Device device{0, ID::Port1 | ID::Port2, "Controller"};
|
Device device{0, ID::Port1 | ID::Port2, "Controller"};
|
||||||
|
|
|
@ -3,6 +3,10 @@ namespace SuperFamicom {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct ID {
|
struct ID {
|
||||||
|
enum : unsigned {
|
||||||
|
SuperFamicom,
|
||||||
|
};
|
||||||
|
|
||||||
enum : unsigned {
|
enum : unsigned {
|
||||||
IPLROM,
|
IPLROM,
|
||||||
|
|
||||||
|
@ -22,7 +26,6 @@ struct ID {
|
||||||
SuperGameBoyRAM,
|
SuperGameBoyRAM,
|
||||||
|
|
||||||
BsxFlashROM,
|
BsxFlashROM,
|
||||||
BsxRAM,
|
|
||||||
BsxPSRAM,
|
BsxPSRAM,
|
||||||
|
|
||||||
SufamiTurboSlotAROM,
|
SufamiTurboSlotAROM,
|
||||||
|
@ -44,6 +47,8 @@ struct Interface : Emulator::Interface {
|
||||||
bool loaded();
|
bool loaded();
|
||||||
string sha256();
|
string sha256();
|
||||||
unsigned group(unsigned id);
|
unsigned group(unsigned id);
|
||||||
|
void load(unsigned id, const string &manifest);
|
||||||
|
void save();
|
||||||
void load(unsigned id, const stream &stream, const string &markup = "");
|
void load(unsigned id, const stream &stream, const string &markup = "");
|
||||||
void save(unsigned id, const stream &stream);
|
void save(unsigned id, const stream &stream);
|
||||||
void unload();
|
void unload();
|
||||||
|
|
|
@ -62,7 +62,7 @@ void System::runthreadtosave() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::init() {
|
void System::init() {
|
||||||
assert(interface != 0);
|
assert(interface != nullptr);
|
||||||
|
|
||||||
bsxsatellaview.init();
|
bsxsatellaview.init();
|
||||||
icd2.init();
|
icd2.init();
|
||||||
|
|
|
@ -187,6 +187,7 @@ void InputManager::saveConfiguration() {
|
||||||
|
|
||||||
InputManager::InputManager() {
|
InputManager::InputManager() {
|
||||||
inputManager = this;
|
inputManager = this;
|
||||||
|
activeScancode = 0;
|
||||||
bootstrap();
|
bootstrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
#include "../ethos.hpp"
|
#include "../ethos.hpp"
|
||||||
Interface *interface = nullptr;
|
Interface *interface = nullptr;
|
||||||
|
|
||||||
void Interface::loadRequest(unsigned id, const string &path) {
|
void Interface::loadRequest(unsigned id, const string &name, const string &type, const string &path) {
|
||||||
return utility->loadMedia(id, path);
|
return utility->loadRequest(id, name, type, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interface::loadRequest(unsigned id, const string &name, const string &type, const string &path) {
|
void Interface::loadRequest(unsigned id, const string &path) {
|
||||||
if(name.empty() && type.empty()) return utility->loadMedia(id, path);
|
return utility->loadRequest(id, path);
|
||||||
return utility->loadMedia(id, name, type, 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) {
|
uint32_t Interface::videoColor(unsigned source, uint16_t r, uint16_t g, uint16_t b) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
struct Interface : Emulator::Interface::Bind {
|
struct Interface : Emulator::Interface::Bind {
|
||||||
void loadRequest(unsigned id, const string &path);
|
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);
|
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);
|
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);
|
void videoRefresh(const uint32_t *data, unsigned pitch, unsigned width, unsigned height);
|
||||||
|
|
|
@ -7,13 +7,17 @@ void Utility::setInterface(Emulator::Interface *emulator) {
|
||||||
presentation->synchronize();
|
presentation->synchronize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//load menu option selected
|
||||||
void Utility::loadMedia(Emulator::Interface *emulator, Emulator::Interface::Media &media) {
|
void Utility::loadMedia(Emulator::Interface *emulator, Emulator::Interface::Media &media) {
|
||||||
string pathname = application->path({media.name, ".", media.type, "/"});
|
string pathname;
|
||||||
if(!file::exists({pathname, media.path})) pathname = browser->select({"Load ", media.name}, media.extension);
|
if(media.type != "sys") pathname = application->path({media.name, ".", media.type, "/"});
|
||||||
if(!file::exists({pathname, media.path})) return;
|
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);
|
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) {
|
void Utility::loadMedia(Emulator::Interface *emulator, Emulator::Interface::Media &media, const string &pathname) {
|
||||||
unload();
|
unload();
|
||||||
setInterface(emulator);
|
setInterface(emulator);
|
||||||
|
@ -22,52 +26,60 @@ void Utility::loadMedia(Emulator::Interface *emulator, Emulator::Interface::Medi
|
||||||
|
|
||||||
string manifest;
|
string manifest;
|
||||||
manifest.readfile({pathname, "manifest.xml"});
|
manifest.readfile({pathname, "manifest.xml"});
|
||||||
auto memory = file::read({pathname, media.path});
|
system().load(media.id, manifest);
|
||||||
system().load(media.id, vectorstream{memory}, manifest);
|
system().power();
|
||||||
|
|
||||||
if(this->pathname.size() == 0) this->pathname.append(pathname);
|
if(this->pathname.size() == 0) this->pathname.append(pathname);
|
||||||
presentation->setSystemName(media.name);
|
presentation->setSystemName(media.name);
|
||||||
load();
|
load();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Utility::loadMedia(unsigned id, const string &path) {
|
//request from emulation core to load non-volatile media folder
|
||||||
string pathname = {this->path(system().group(id)), path};
|
void Utility::loadRequest(unsigned id, const string &name, const string &type, const string &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) {
|
|
||||||
string pathname = browser->select({"Load ", name}, type);
|
string pathname = browser->select({"Load ", name}, type);
|
||||||
if(pathname.empty()) return;
|
if(pathname.empty()) return;
|
||||||
this->path(system().group(id)) = pathname;
|
this->path(system().group(id)) = pathname;
|
||||||
this->pathname.append(pathname);
|
this->pathname.append(pathname);
|
||||||
|
|
||||||
string markup;
|
string manifest;
|
||||||
markup.readfile({pathname, "manifest.xml"});
|
manifest.readfile({pathname, "manifest.xml"});
|
||||||
mmapstream stream({pathname, path});
|
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() {
|
void Utility::loadMemory() {
|
||||||
for(auto &memory : system().memory) {
|
// for(auto &memory : system().memory) {
|
||||||
string pathname = path(system().group(memory.id));
|
// string pathname = path(system().group(memory.id));
|
||||||
if(file::exists({pathname, memory.name}) == false) continue;
|
// if(file::exists({pathname, memory.name}) == false) continue;
|
||||||
filestream fs({pathname, memory.name});
|
// filestream fs({pathname, memory.name});
|
||||||
system().load(memory.id, fs);
|
// system().load(memory.id, fs);
|
||||||
}
|
// }
|
||||||
|
|
||||||
cheatEditor->load({pathname[0], "cheats.xml"});
|
cheatEditor->load({pathname[0], "cheats.xml"});
|
||||||
stateManager->load({pathname[0], "bsnes/states.bsa"}, 1);
|
stateManager->load({pathname[0], "bsnes/states.bsa"}, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Utility::saveMemory() {
|
void Utility::saveMemory() {
|
||||||
for(auto &memory : system().memory) {
|
// for(auto &memory : system().memory) {
|
||||||
string pathname = path(system().group(memory.id));
|
// string pathname = path(system().group(memory.id));
|
||||||
filestream fs({pathname, memory.name}, file::mode::write);
|
// filestream fs({pathname, memory.name}, file::mode::write);
|
||||||
system().save(memory.id, fs);
|
// system().save(memory.id, fs);
|
||||||
}
|
// }
|
||||||
|
|
||||||
cheatEditor->save({pathname[0], "cheats.xml"});
|
cheatEditor->save({pathname[0], "cheats.xml"});
|
||||||
stateManager->save({pathname[0], "bsnes/states.bsa"}, 1);
|
stateManager->save({pathname[0], "bsnes/states.bsa"}, 1);
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
struct Utility {
|
struct Utility {
|
||||||
void setInterface(Emulator::Interface *emulator);
|
void setInterface(Emulator::Interface *emulator);
|
||||||
|
|
||||||
void loadMedia(Emulator::Interface *emulator, Emulator::Interface::Media &media);
|
void loadMedia(Emulator::Interface *emulator, Emulator::Interface::Media &media);
|
||||||
void loadMedia(Emulator::Interface *emulator, Emulator::Interface::Media &media, const string &pathname);
|
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 loadMemory();
|
||||||
void saveMemory();
|
void saveMemory();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue