mirror of https://github.com/bsnes-emu/bsnes.git
Update to v099r07 release.
byuu says: Changelog: - (hopefully) fixed BS Memory and Sufami Turbo slot loading - ported GB, GBA, WS cores to use nall/vfs - completely removed loadRequest, saveRequest functionality from Emulator::Interface and ui-tomoko - loadRequest(folder) is now load(folder) - save states now use a shared Emulator::SerializerVersion string - whenever this is bumped, all older states will break; but this makes bumping state versions way easier - also, the version string makes it a lot easier to identify compatibility windows for save states - SNES PPU now uses uint16 vram[32768] for memory accesses [hex_usr] NOTE: Super Game Boy loading is currently broken, and I'm not entirely sure how to fix it :/ The file loading handoff was -really- complicated, and so I'm kind of at a loss ... so for now, don't try it. Everything else should theoretically work, so please report any bugs you find. So, this is pretty much it. I'd be very curious to hear feedback from people who objected to the old nall/stream design, whether they are happy with the new file loading system or think it could use further improvements. The 16-bit VRAM turned out to be a wash on performance (roughly the same as before. 1fps slower on Zelda 3, 1fps faster on Yoshi's Island.) The main reason for this was because Yoshi's Island was breaking horribly until I changed the vramRead, vramWrite functions to take uint15 instead of uint16. I suspect the issue is we're using uint16s in some areas now that need to be uint15, and this game is setting the VRAM address to 0x8000+, causing us to go out of bounds on memory accesses. But ... I want to go ahead and do something cute for fun, and just because we can ... and this new interface is so incredibly perfect for it!! I want to support an SNES unit with 128KiB of VRAM. Not out of the box, but as a fun little tweakable thing. The SNES was clearly designed to support that, they just didn't use big enough VRAM chips, and left one of the lines disconnected. So ... let's connect it anyway! In the end, if we design it right, the only code difference should be one area where we mask by 15-bits instead of by 16-bits.
This commit is contained in:
parent
875f031182
commit
ccd8878d75
|
@ -4,16 +4,20 @@
|
|||
#include <nall/vfs.hpp>
|
||||
using namespace nall;
|
||||
|
||||
#include <libco/libco.h>
|
||||
#include <audio/audio.hpp>
|
||||
#include <video/video.hpp>
|
||||
#include <resource/resource.hpp>
|
||||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "099.06";
|
||||
static const string Version = "099.07";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
||||
//incremented only when serialization format changes
|
||||
static const string SerializerVersion = "099.07";
|
||||
}
|
||||
|
||||
#include "interface.hpp"
|
||||
|
|
|
@ -48,9 +48,7 @@ struct Interface {
|
|||
struct Bind {
|
||||
virtual auto path(uint) -> string { return ""; }
|
||||
virtual auto open(uint, string, vfs::file::mode, bool) -> vfs::shared::file { return {}; }
|
||||
virtual auto loadRequest(uint, string, string, bool) -> void {}
|
||||
virtual auto loadRequest(uint, string, bool) -> void {}
|
||||
virtual auto saveRequest(uint, string) -> void {}
|
||||
virtual auto load(uint, string, string, bool) -> void {}
|
||||
virtual auto videoRefresh(const uint32*, uint, uint, uint) -> void {}
|
||||
virtual auto audioSample(const double*, uint) -> void {}
|
||||
virtual auto inputPoll(uint, uint, uint) -> int16 { return 0; }
|
||||
|
@ -63,9 +61,7 @@ struct Interface {
|
|||
//callback bindings (provided by user interface)
|
||||
auto path(uint id) -> string { return bind->path(id); }
|
||||
auto open(uint id, string name, vfs::file::mode mode, bool required = false) -> vfs::shared::file { return bind->open(id, name, mode, required); }
|
||||
auto loadRequest(uint id, string name, string type, bool required) -> void { return bind->loadRequest(id, name, type, required); }
|
||||
auto loadRequest(uint id, string path, bool required) -> void { return bind->loadRequest(id, path, required); }
|
||||
auto saveRequest(uint id, string path) -> void { return bind->saveRequest(id, path); }
|
||||
auto load(uint id, string name, string type, bool required = false) -> void { return bind->load(id, name, type, required); }
|
||||
auto videoRefresh(const uint32* data, uint pitch, uint width, uint height) -> void { return bind->videoRefresh(data, pitch, width, height); }
|
||||
auto audioSample(const double* samples, uint channels) -> void { return bind->audioSample(samples, channels); }
|
||||
auto inputPoll(uint port, uint device, uint input) -> int16 { return bind->inputPoll(port, device, input); }
|
||||
|
@ -88,11 +84,8 @@ struct Interface {
|
|||
//media interface
|
||||
virtual auto loaded() -> bool { return false; }
|
||||
virtual auto sha256() -> string { return ""; }
|
||||
virtual auto group(uint id) -> uint { return 0; }
|
||||
virtual auto load(uint id) -> void {}
|
||||
virtual auto save() -> void {}
|
||||
virtual auto load(uint id, const stream& memory) -> void {}
|
||||
virtual auto save(uint id, const stream& memory) -> void {}
|
||||
virtual auto unload() -> void {}
|
||||
|
||||
//system interface
|
||||
|
|
|
@ -42,22 +42,22 @@ Board::Board(Markup::Node& document) {
|
|||
if(chrram.size) chrram.data = new uint8_t[chrram.size]();
|
||||
|
||||
if(prgrom.name = prom["name"].text()) {
|
||||
if(auto fp = interface->open(ID::Famicom, prgrom.name, vfs::file::mode::read, true)) {
|
||||
if(auto fp = interface->open(ID::Famicom, prgrom.name, File::Read, File::Required)) {
|
||||
fp->read(prgrom.data, min(prgrom.size, fp->size()));
|
||||
}
|
||||
}
|
||||
if(prgram.name = pram["name"].text()) {
|
||||
if(auto fp = interface->open(ID::Famicom, prgram.name, vfs::file::mode::read)) {
|
||||
if(auto fp = interface->open(ID::Famicom, prgram.name, File::Read)) {
|
||||
fp->read(prgram.data, min(prgram.size, fp->size()));
|
||||
}
|
||||
}
|
||||
if(chrrom.name = crom["name"].text()) {
|
||||
if(auto fp = interface->open(ID::Famicom, chrrom.name, vfs::file::mode::read, true)) {
|
||||
if(auto fp = interface->open(ID::Famicom, chrrom.name, File::Read, File::Required)) {
|
||||
fp->read(chrrom.data, min(chrrom.size, fp->size()));
|
||||
}
|
||||
}
|
||||
if(chrram.name = cram["name"].text()) {
|
||||
if(auto fp = interface->open(ID::Famicom, chrram.name, vfs::file::mode::read)) {
|
||||
if(auto fp = interface->open(ID::Famicom, chrram.name, File::Read)) {
|
||||
fp->read(chrram.data, min(chrram.size, fp->size()));
|
||||
}
|
||||
}
|
||||
|
@ -67,14 +67,16 @@ Board::Board(Markup::Node& document) {
|
|||
}
|
||||
|
||||
auto Board::save() -> void {
|
||||
if(auto name = prgram.name) {
|
||||
if(auto fp = interface->open(ID::Famicom, name, vfs::file::mode::write)) {
|
||||
auto document = BML::unserialize(cartridge.manifest());
|
||||
|
||||
if(auto name = document["board/prg/ram/name"].text()) {
|
||||
if(auto fp = interface->open(ID::Famicom, name, File::Write)) {
|
||||
fp->write(prgram.data, prgram.size);
|
||||
}
|
||||
}
|
||||
|
||||
if(auto name = chrram.name) {
|
||||
if(auto fp = interface->open(ID::Famicom, name, vfs::file::mode::write)) {
|
||||
if(auto name = document["board/chr/ram/name"].text()) {
|
||||
if(auto fp = interface->open(ID::Famicom, name, File::Write)) {
|
||||
fp->write(chrram.data, chrram.size);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,18 +6,6 @@ namespace Famicom {
|
|||
#include "board/board.cpp"
|
||||
Cartridge cartridge;
|
||||
|
||||
auto Cartridge::sha256() const -> string {
|
||||
return _sha256;
|
||||
}
|
||||
|
||||
auto Cartridge::manifest() const -> string {
|
||||
return information.markup;
|
||||
}
|
||||
|
||||
auto Cartridge::title() const -> string {
|
||||
return information.title;
|
||||
}
|
||||
|
||||
auto Cartridge::Enter() -> void {
|
||||
while(true) scheduler.synchronize(), cartridge.main();
|
||||
}
|
||||
|
@ -27,19 +15,19 @@ auto Cartridge::main() -> void {
|
|||
}
|
||||
|
||||
auto Cartridge::load() -> bool {
|
||||
if(auto fp = interface->open(ID::Famicom, "manifest.bml", vfs::file::mode::read, true)) {
|
||||
information.markup = fp->reads();
|
||||
if(auto fp = interface->open(ID::Famicom, "manifest.bml", File::Read, File::Required)) {
|
||||
information.manifest = fp->reads();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
Board::load(information.markup); //this call will set Cartridge::board if successful
|
||||
Board::load(information.manifest); //this call will set Cartridge::board if successful
|
||||
if(!board) return false;
|
||||
|
||||
Hash::SHA256 sha;
|
||||
sha.data(board->prgrom.data, board->prgrom.size);
|
||||
sha.data(board->chrrom.data, board->chrrom.size);
|
||||
_sha256 = sha.digest();
|
||||
information.sha256 = sha.digest();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,9 +5,9 @@ struct Cartridge : Thread {
|
|||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
|
||||
auto sha256() const -> string;
|
||||
auto manifest() const -> string;
|
||||
auto title() const -> string;
|
||||
auto sha256() const -> string { return information.sha256; }
|
||||
auto manifest() const -> string { return information.manifest; }
|
||||
auto title() const -> string { return information.title; }
|
||||
|
||||
auto load() -> bool;
|
||||
auto save() -> void;
|
||||
|
@ -19,13 +19,13 @@ struct Cartridge : Thread {
|
|||
auto serialize(serializer&) -> void;
|
||||
|
||||
struct Information {
|
||||
string markup;
|
||||
string sha256;
|
||||
string manifest;
|
||||
string title;
|
||||
} information;
|
||||
|
||||
//privileged:
|
||||
Board* board = nullptr;
|
||||
string _sha256;
|
||||
|
||||
auto prg_read(uint addr) -> uint8;
|
||||
auto prg_write(uint addr, uint8 data) -> void;
|
||||
|
|
|
@ -7,14 +7,13 @@
|
|||
#include <processor/r6502/r6502.hpp>
|
||||
|
||||
namespace Famicom {
|
||||
namespace Info {
|
||||
static const uint SerializerVersion = 3;
|
||||
}
|
||||
}
|
||||
struct File {
|
||||
static const auto Read = vfs::file::mode::read;
|
||||
static const auto Write = vfs::file::mode::write;
|
||||
static const auto Optional = false;
|
||||
static const auto Required = true;
|
||||
};
|
||||
|
||||
#include <libco/libco.h>
|
||||
|
||||
namespace Famicom {
|
||||
struct Thread {
|
||||
~Thread() {
|
||||
if(thread) co_delete(thread);
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
auto System::serialize() -> serializer {
|
||||
serializer s(_serializeSize);
|
||||
|
||||
uint signature = 0x31545342, version = Info::SerializerVersion;
|
||||
char hash[64], description[512];
|
||||
memcpy(&hash, (const char*)cartridge.sha256(), 64);
|
||||
memset(&description, 0, sizeof description);
|
||||
uint signature = 0x31545342;
|
||||
char version[16] = {0};
|
||||
char hash[64] = {0};
|
||||
char description[512] = {0};
|
||||
memory::copy(&version, (const char*)Emulator::SerializerVersion, Emulator::SerializerVersion.size());
|
||||
memory::copy(&hash, (const char*)cartridge.sha256(), 64);
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.array(version);
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
|
@ -16,16 +18,18 @@ auto System::serialize() -> serializer {
|
|||
}
|
||||
|
||||
auto System::unserialize(serializer& s) -> bool {
|
||||
uint signature, version;
|
||||
char hash[64], description[512];
|
||||
uint signature;
|
||||
char version[16];
|
||||
char hash[64];
|
||||
char description[512];
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.array(version);
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
if(signature != 0x31545342) return false;
|
||||
if(version != Info::SerializerVersion) return false;
|
||||
if(string{version} != Emulator::SerializerVersion) return false;
|
||||
|
||||
power();
|
||||
serializeAll(s);
|
||||
|
@ -46,11 +50,13 @@ auto System::serializeAll(serializer& s) -> void {
|
|||
auto System::serializeInit() -> void {
|
||||
serializer s;
|
||||
|
||||
uint signature = 0, version = 0;
|
||||
char hash[64], description[512];
|
||||
uint signature = 0;
|
||||
char version[16];
|
||||
char hash[64];
|
||||
char description[512];
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.array(version);
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ auto System::runToSave() -> void {
|
|||
}
|
||||
|
||||
auto System::load() -> bool {
|
||||
if(auto fp = interface->open(ID::System, "manifest.bml", vfs::file::mode::read, true)) {
|
||||
if(auto fp = interface->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
||||
information.manifest = fp->reads();
|
||||
} else {
|
||||
return false;
|
||||
|
|
|
@ -14,28 +14,17 @@ namespace GameBoy {
|
|||
#include "serialization.cpp"
|
||||
Cartridge cartridge;
|
||||
|
||||
auto Cartridge::manifest() const -> string {
|
||||
return information.markup;
|
||||
}
|
||||
auto Cartridge::load(System::Revision revision) -> bool {
|
||||
information = Information();
|
||||
if(revision == System::Revision::GameBoy) information.mode = ID::GameBoy;
|
||||
if(revision == System::Revision::SuperGameBoy) information.mode = ID::SuperGameBoy;
|
||||
if(revision == System::Revision::GameBoyColor) information.mode = ID::GameBoyColor;
|
||||
|
||||
auto Cartridge::title() const -> string {
|
||||
return information.title;
|
||||
}
|
||||
if(auto fp = interface->open(mode(), "manifest.bml", File::Read, File::Required)) {
|
||||
information.manifest = fp->reads();
|
||||
} else return false;
|
||||
|
||||
auto Cartridge::load(System::Revision revision) -> void {
|
||||
information.markup = "";
|
||||
interface->loadRequest(ID::Manifest, "manifest.bml", !system.sgb());
|
||||
|
||||
information.mapper = Mapper::Unknown;
|
||||
information.ram = false;
|
||||
information.battery = false;
|
||||
information.rtc = false;
|
||||
information.rumble = false;
|
||||
|
||||
information.romsize = 0;
|
||||
information.ramsize = 0;
|
||||
|
||||
auto document = BML::unserialize(information.markup);
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
information.title = document["information/title"].text();
|
||||
|
||||
auto mapperid = document["board/mapper"].text();
|
||||
|
@ -61,9 +50,16 @@ auto Cartridge::load(System::Revision revision) -> void {
|
|||
ramsize = ram["size"].natural();
|
||||
ramdata = allocate<uint8>(ramsize, 0xff);
|
||||
|
||||
if(auto name = rom["name"].text()) interface->loadRequest(ID::ROM, name, !system.sgb());
|
||||
if(auto name = ram["name"].text()) interface->loadRequest(ID::RAM, name, false);
|
||||
if(auto name = ram["name"].text()) memory.append({ID::RAM, name});
|
||||
if(auto name = rom["name"].text()) {
|
||||
if(auto fp = interface->open(mode(), name, File::Read, File::Required)) {
|
||||
fp->read(romdata, min(romsize, fp->size()));
|
||||
}
|
||||
}
|
||||
if(auto name = ram["name"].text()) {
|
||||
if(auto fp = interface->open(mode(), name, File::Read, File::Optional)) {
|
||||
fp->read(ramdata, min(ramsize, fp->size()));
|
||||
}
|
||||
}
|
||||
|
||||
information.romsize = romsize;
|
||||
information.ramsize = ramsize;
|
||||
|
@ -82,6 +78,17 @@ auto Cartridge::load(System::Revision revision) -> void {
|
|||
}
|
||||
|
||||
sha256 = Hash::SHA256(romdata, romsize).digest();
|
||||
return true;
|
||||
}
|
||||
|
||||
auto Cartridge::save() -> void {
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
|
||||
if(auto name = document["board/ram/name"].text()) {
|
||||
if(auto fp = interface->open(mode(), name, File::Write)) {
|
||||
fp->write(ramdata, ramsize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Cartridge::unload() -> void {
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
struct Cartridge : MMIO, property<Cartridge> {
|
||||
auto load(System::Revision revision) -> void;
|
||||
auto manifest() const -> string { return information.manifest; }
|
||||
auto title() const -> string { return information.title; }
|
||||
auto mode() const -> uint { return information.mode; }
|
||||
|
||||
auto load(System::Revision revision) -> bool;
|
||||
auto save() -> void;
|
||||
auto unload() -> void;
|
||||
|
||||
auto rom_read(uint addr) -> uint8;
|
||||
|
@ -38,28 +43,20 @@ struct Cartridge : MMIO, property<Cartridge> {
|
|||
};
|
||||
|
||||
struct Information {
|
||||
string markup;
|
||||
string manifest;
|
||||
string title;
|
||||
uint mode = 0;
|
||||
|
||||
Mapper mapper;
|
||||
bool ram;
|
||||
bool battery;
|
||||
bool rtc;
|
||||
bool rumble;
|
||||
Mapper mapper = Mapper::Unknown;
|
||||
boolean ram;
|
||||
boolean battery;
|
||||
boolean rtc;
|
||||
boolean rumble;
|
||||
|
||||
uint romsize;
|
||||
uint ramsize;
|
||||
uint romsize = 0;
|
||||
uint ramsize = 0;
|
||||
} information;
|
||||
|
||||
auto manifest() const -> string;
|
||||
auto title() const -> string;
|
||||
|
||||
struct Memory {
|
||||
uint id;
|
||||
string name;
|
||||
};
|
||||
vector<Memory> memory;
|
||||
|
||||
readonly<string> sha256;
|
||||
|
||||
uint8* romdata = nullptr;
|
||||
|
|
|
@ -7,14 +7,13 @@
|
|||
#include <processor/lr35902/lr35902.hpp>
|
||||
|
||||
namespace GameBoy {
|
||||
namespace Info {
|
||||
static const uint SerializerVersion = 5;
|
||||
}
|
||||
}
|
||||
struct File {
|
||||
static const auto Read = vfs::file::mode::read;
|
||||
static const auto Write = vfs::file::mode::write;
|
||||
static const auto Optional = false;
|
||||
static const auto Required = true;
|
||||
};
|
||||
|
||||
#include <libco/libco.h>
|
||||
|
||||
namespace GameBoy {
|
||||
struct Thread {
|
||||
~Thread() {
|
||||
if(thread) co_delete(thread);
|
||||
|
|
|
@ -124,26 +124,6 @@ auto Interface::sha256() -> string {
|
|||
return cartridge.sha256();
|
||||
}
|
||||
|
||||
auto Interface::group(uint id) -> uint {
|
||||
switch(id) {
|
||||
case ID::SystemManifest:
|
||||
case ID::GameBoyBootROM:
|
||||
case ID::SuperGameBoyBootROM:
|
||||
case ID::GameBoyColorBootROM:
|
||||
return 0;
|
||||
case ID::Manifest:
|
||||
case ID::ROM:
|
||||
case ID::RAM:
|
||||
switch(system.revision()) {
|
||||
case System::Revision::GameBoy: return ID::GameBoy;
|
||||
case System::Revision::SuperGameBoy: return ID::SuperGameBoy;
|
||||
case System::Revision::GameBoyColor: return ID::GameBoyColor;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
auto Interface::load(uint id) -> void {
|
||||
if(id == ID::GameBoy) system.load(System::Revision::GameBoy);
|
||||
if(id == ID::SuperGameBoy) system.load(System::Revision::SuperGameBoy);
|
||||
|
@ -151,45 +131,7 @@ auto Interface::load(uint id) -> void {
|
|||
}
|
||||
|
||||
auto Interface::save() -> void {
|
||||
for(auto& memory : cartridge.memory) {
|
||||
interface->saveRequest(memory.id, memory.name);
|
||||
}
|
||||
}
|
||||
|
||||
auto Interface::load(uint id, const stream& stream) -> void {
|
||||
if(id == ID::SystemManifest) {
|
||||
system.information.manifest = stream.text();
|
||||
}
|
||||
|
||||
if(id == ID::GameBoyBootROM) {
|
||||
stream.read((uint8_t*)system.bootROM.dmg, min( 256u, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::SuperGameBoyBootROM) {
|
||||
stream.read((uint8_t*)system.bootROM.sgb, min( 256u, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::GameBoyColorBootROM) {
|
||||
stream.read((uint8_t*)system.bootROM.cgb, min(2048u, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::Manifest) {
|
||||
cartridge.information.markup = stream.text();
|
||||
}
|
||||
|
||||
if(id == ID::ROM) {
|
||||
stream.read((uint8_t*)cartridge.romdata, min(cartridge.romsize, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::RAM) {
|
||||
stream.read((uint8_t*)cartridge.ramdata, min(stream.size(), cartridge.ramsize));
|
||||
}
|
||||
}
|
||||
|
||||
auto Interface::save(uint id, const stream& stream) -> void {
|
||||
if(id == ID::RAM) {
|
||||
stream.write((uint8_t*)cartridge.ramdata, cartridge.ramsize);
|
||||
}
|
||||
system.save();
|
||||
}
|
||||
|
||||
auto Interface::unload() -> void {
|
||||
|
|
|
@ -36,11 +36,8 @@ struct Interface : Emulator::Interface {
|
|||
|
||||
auto loaded() -> bool;
|
||||
auto sha256() -> string;
|
||||
auto group(uint id) -> uint;
|
||||
auto load(uint id) -> void;
|
||||
auto save() -> void;
|
||||
auto load(uint id, const stream& stream) -> void;
|
||||
auto save(uint id, const stream& stream) -> void;
|
||||
auto unload() -> void;
|
||||
|
||||
auto power() -> void;
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
auto System::serialize() -> serializer {
|
||||
serializer s(_serializeSize);
|
||||
|
||||
uint signature = 0x31545342, version = Info::SerializerVersion;
|
||||
char hash[64], description[512];
|
||||
memcpy(&hash, (const char*)cartridge.sha256(), 64);
|
||||
memset(&description, 0, sizeof description);
|
||||
uint signature = 0x31545342;
|
||||
char version[16] = {0};
|
||||
char hash[64] = {0};
|
||||
char description[512] = {0};
|
||||
memory::copy(&version, (const char*)Emulator::SerializerVersion, Emulator::SerializerVersion.size());
|
||||
memory::copy(&hash, (const char*)cartridge.sha256(), 64);
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.array(version);
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
|
@ -16,16 +18,18 @@ auto System::serialize() -> serializer {
|
|||
}
|
||||
|
||||
auto System::unserialize(serializer& s) -> bool {
|
||||
uint signature, version;
|
||||
char hash[64], description[512];
|
||||
uint signature;
|
||||
char version[16] = {0};
|
||||
char hash[64] = {0};
|
||||
char description[512];
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.array(version);
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
if(signature != 0x31545342) return false;
|
||||
if(version != Info::SerializerVersion) return false;
|
||||
if(string{version} != Emulator::SerializerVersion) return false;
|
||||
|
||||
power();
|
||||
serializeAll(s);
|
||||
|
@ -47,11 +51,13 @@ auto System::serializeAll(serializer& s) -> void {
|
|||
auto System::serializeInit() -> void {
|
||||
serializer s;
|
||||
|
||||
uint signature = 0, version = 0;
|
||||
char hash[64], description[512];
|
||||
uint signature = 0;
|
||||
char version[16] = {0};
|
||||
char hash[64] = {0};
|
||||
char description[512] = {0};
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.array(version);
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
|
|
|
@ -6,16 +6,6 @@ namespace GameBoy {
|
|||
#include "serialization.cpp"
|
||||
System system;
|
||||
|
||||
auto System::loaded() const -> bool { return _loaded; }
|
||||
auto System::revision() const -> Revision { return _revision; }
|
||||
auto System::clocksExecuted() const -> uint { return _clocksExecuted; }
|
||||
|
||||
System::System() {
|
||||
for(auto& byte : bootROM.dmg) byte = 0;
|
||||
for(auto& byte : bootROM.sgb) byte = 0;
|
||||
for(auto& byte : bootROM.cgb) byte = 0;
|
||||
}
|
||||
|
||||
auto System::run() -> void {
|
||||
scheduler.enter();
|
||||
}
|
||||
|
@ -30,27 +20,33 @@ auto System::init() -> void {
|
|||
assert(interface != nullptr);
|
||||
}
|
||||
|
||||
auto System::load(Revision revision) -> void {
|
||||
auto System::load(Revision revision) -> bool {
|
||||
_revision = revision;
|
||||
|
||||
interface->loadRequest(ID::SystemManifest, "manifest.bml", true);
|
||||
if(auto fp = interface->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
||||
information.manifest = fp->reads();
|
||||
} else return false;
|
||||
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
string path = "system/cpu/rom/name";
|
||||
if(revision == Revision::SuperGameBoy) path = "board/icd2/rom/name";
|
||||
|
||||
if(auto bootROM = document[path].text()) {
|
||||
interface->loadRequest(
|
||||
revision == Revision::GameBoy ? ID::GameBoyBootROM
|
||||
: revision == Revision::SuperGameBoy ? ID::SuperGameBoyBootROM
|
||||
: revision == Revision::GameBoyColor ? ID::GameBoyColorBootROM
|
||||
: ID::GameBoyBootROM,
|
||||
bootROM, true
|
||||
);
|
||||
if(auto name = document[path].text()) {
|
||||
if(auto fp = interface->open(ID::System, name, File::Read, File::Required)) {
|
||||
if(revision == Revision::GameBoy) fp->read(bootROM.dmg, 256);
|
||||
if(revision == Revision::SuperGameBoy) fp->read(bootROM.sgb, 256);
|
||||
if(revision == Revision::GameBoyColor) fp->read(bootROM.cgb, 2048);
|
||||
}
|
||||
}
|
||||
|
||||
cartridge.load(revision);
|
||||
serializeInit();
|
||||
_loaded = true;
|
||||
return _loaded = true;
|
||||
}
|
||||
|
||||
auto System::save() -> void {
|
||||
if(!loaded()) return;
|
||||
cartridge.save();
|
||||
}
|
||||
|
||||
auto System::unload() -> void {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class Interface;
|
||||
struct Interface;
|
||||
|
||||
enum class Input : uint {
|
||||
Up, Down, Left, Right, B, A, Select, Start,
|
||||
|
@ -11,11 +11,9 @@ struct System {
|
|||
GameBoyColor,
|
||||
};
|
||||
|
||||
System();
|
||||
|
||||
auto loaded() const -> bool;
|
||||
auto revision() const -> Revision;
|
||||
auto clocksExecuted() const -> uint;
|
||||
auto loaded() const -> bool { return _loaded; }
|
||||
auto revision() const -> Revision { return _revision; }
|
||||
auto clocksExecuted() const -> uint { return _clocksExecuted; }
|
||||
|
||||
inline auto dmg() const { return _revision == Revision::GameBoy; }
|
||||
inline auto sgb() const { return _revision == Revision::SuperGameBoy; }
|
||||
|
@ -25,7 +23,8 @@ struct System {
|
|||
auto runToSave() -> void;
|
||||
|
||||
auto init() -> void;
|
||||
auto load(Revision) -> void;
|
||||
auto load(Revision) -> bool;
|
||||
auto save() -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
|
||||
|
|
|
@ -23,62 +23,57 @@ Cartridge::~Cartridge() {
|
|||
delete[] flash.data;
|
||||
}
|
||||
|
||||
auto Cartridge::sha256() const -> string {
|
||||
return information.sha256;
|
||||
}
|
||||
auto Cartridge::load() -> bool {
|
||||
information = Information();
|
||||
|
||||
auto Cartridge::manifest() const -> string {
|
||||
return information.markup;
|
||||
}
|
||||
if(auto fp = interface->open(ID::GameBoyAdvance, "manifest.bml", File::Read, File::Required)) {
|
||||
information.manifest = fp->reads();
|
||||
} else return false;
|
||||
|
||||
auto Cartridge::title() const -> string {
|
||||
return information.title;
|
||||
}
|
||||
|
||||
auto Cartridge::load() -> void {
|
||||
interface->loadRequest(ID::Manifest, "manifest.bml", true);
|
||||
|
||||
auto document = BML::unserialize(information.markup);
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
information.title = document["information/title"].text();
|
||||
|
||||
hasSRAM = false;
|
||||
hasEEPROM = false;
|
||||
hasFLASH = false;
|
||||
|
||||
if(auto info = document["board/rom"]) {
|
||||
mrom.size = min(32 * 1024 * 1024, info["size"].natural());
|
||||
|
||||
interface->loadRequest(ID::MROM, info["name"].text(), true);
|
||||
if(auto node = document["board/rom"]) {
|
||||
mrom.size = min(32 * 1024 * 1024, node["size"].natural());
|
||||
if(auto fp = interface->open(ID::GameBoyAdvance, node["name"].text(), File::Read, File::Required)) {
|
||||
fp->read(mrom.data, mrom.size);
|
||||
}
|
||||
}
|
||||
|
||||
if(auto info = document["board/ram"]) {
|
||||
if(info["type"].text() == "sram") {
|
||||
if(auto node = document["board/ram"]) {
|
||||
if(node["type"].text() == "sram") {
|
||||
hasSRAM = true;
|
||||
sram.size = min(32 * 1024, info["size"].natural());
|
||||
sram.size = min(32 * 1024, node["size"].natural());
|
||||
sram.mask = sram.size - 1;
|
||||
for(auto n : range(sram.size)) sram.data[n] = 0xff;
|
||||
|
||||
interface->loadRequest(ID::SRAM, info["name"].text(), false);
|
||||
memory.append({ID::SRAM, info["name"].text()});
|
||||
if(auto fp = interface->open(ID::GameBoyAdvance, node["name"].text(), File::Read)) {
|
||||
fp->read(sram.data, sram.size);
|
||||
}
|
||||
}
|
||||
|
||||
if(info["type"].text() == "eeprom") {
|
||||
if(node["type"].text() == "eeprom") {
|
||||
hasEEPROM = true;
|
||||
eeprom.size = min(8 * 1024, info["size"].natural());
|
||||
eeprom.size = min(8 * 1024, node["size"].natural());
|
||||
eeprom.bits = eeprom.size <= 512 ? 6 : 14;
|
||||
if(eeprom.size == 0) eeprom.size = 8192, eeprom.bits = 0; //auto-detect size
|
||||
eeprom.mask = mrom.size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000;
|
||||
eeprom.test = mrom.size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
|
||||
for(auto n : range(eeprom.size)) eeprom.data[n] = 0xff;
|
||||
|
||||
interface->loadRequest(ID::EEPROM, info["name"].text(), false);
|
||||
memory.append({ID::EEPROM, info["name"].text()});
|
||||
if(auto fp = interface->open(ID::GameBoyAdvance, node["name"].text(), File::Read)) {
|
||||
fp->read(eeprom.data, eeprom.size);
|
||||
}
|
||||
}
|
||||
|
||||
if(info["type"].text() == "flash") {
|
||||
if(node["type"].text() == "flash") {
|
||||
hasFLASH = true;
|
||||
flash.id = info["id"].natural();
|
||||
flash.size = min(128 * 1024, info["size"].natural());
|
||||
flash.id = node["id"].natural();
|
||||
flash.size = min(128 * 1024, node["size"].natural());
|
||||
for(auto n : range(flash.size)) flash.data[n] = 0xff;
|
||||
|
||||
//if flash ID not provided; guess that it's a Macronix chip
|
||||
|
@ -86,16 +81,28 @@ auto Cartridge::load() -> void {
|
|||
if(!flash.id && flash.size == 64 * 1024) flash.id = 0x1cc2;
|
||||
if(!flash.id && flash.size == 128 * 1024) flash.id = 0x09c2;
|
||||
|
||||
interface->loadRequest(ID::FLASH, info["name"].text(), false);
|
||||
memory.append({ID::FLASH, info["name"].text()});
|
||||
if(auto fp = interface->open(ID::GameBoyAdvance, node["name"].text(), File::Read)) {
|
||||
fp->read(flash.data, flash.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
information.sha256 = Hash::SHA256(mrom.data, mrom.size).digest();
|
||||
return true;
|
||||
}
|
||||
|
||||
auto Cartridge::save() -> void {
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
if(auto node = document["board/ram"]) {
|
||||
if(auto fp = interface->open(ID::GameBoyAdvance, node["name"].text(), File::Write)) {
|
||||
if(node["type"].text() == "sram") fp->write(sram.data, sram.size);
|
||||
if(node["type"].text() == "eeprom") fp->write(eeprom.data, eeprom.size);
|
||||
if(node["type"].text() == "flash") fp->write(flash.data, flash.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Cartridge::unload() -> void {
|
||||
memory.reset();
|
||||
}
|
||||
|
||||
auto Cartridge::power() -> void {
|
||||
|
|
|
@ -1,26 +1,21 @@
|
|||
struct Cartridge {
|
||||
#include "memory.hpp"
|
||||
|
||||
auto sha256() const -> string;
|
||||
auto manifest() const -> string;
|
||||
auto title() const -> string;
|
||||
auto sha256() const -> string { return information.sha256; }
|
||||
auto manifest() const -> string { return information.manifest; }
|
||||
auto title() const -> string { return information.title; }
|
||||
|
||||
struct Information {
|
||||
string markup;
|
||||
string sha256;
|
||||
string manifest;
|
||||
string title;
|
||||
} information;
|
||||
|
||||
struct Media {
|
||||
uint id;
|
||||
string name;
|
||||
};
|
||||
vector<Media> memory;
|
||||
|
||||
Cartridge();
|
||||
~Cartridge();
|
||||
|
||||
auto load() -> void;
|
||||
auto load() -> bool;
|
||||
auto save() -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
|
||||
|
|
|
@ -6,14 +6,6 @@
|
|||
#include <emulator/emulator.hpp>
|
||||
#include <processor/arm/arm.hpp>
|
||||
|
||||
namespace GameBoyAdvance {
|
||||
namespace Info {
|
||||
static const uint SerializerVersion = 4;
|
||||
}
|
||||
}
|
||||
|
||||
#include <libco/libco.h>
|
||||
|
||||
namespace GameBoyAdvance {
|
||||
enum : uint { //mode flags for bus read, write:
|
||||
Nonsequential = 1, //N cycle
|
||||
|
@ -27,6 +19,13 @@ namespace GameBoyAdvance {
|
|||
Signed = 256, //sign extended
|
||||
};
|
||||
|
||||
struct File {
|
||||
static const auto Read = vfs::file::mode::read;
|
||||
static const auto Write = vfs::file::mode::write;
|
||||
static const auto Optional = false;
|
||||
static const auto Required = true;
|
||||
};
|
||||
|
||||
struct Thread {
|
||||
~Thread() {
|
||||
if(thread) co_delete(thread);
|
||||
|
|
|
@ -85,74 +85,12 @@ auto Interface::loaded() -> bool {
|
|||
return system.loaded();
|
||||
}
|
||||
|
||||
auto Interface::group(uint id) -> uint {
|
||||
switch(id) {
|
||||
case ID::SystemManifest:
|
||||
case ID::BIOS:
|
||||
return ID::System;
|
||||
case ID::Manifest:
|
||||
case ID::MROM:
|
||||
case ID::SRAM:
|
||||
case ID::EEPROM:
|
||||
case ID::FLASH:
|
||||
return ID::GameBoyAdvance;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
auto Interface::load(uint id) -> void {
|
||||
system.load();
|
||||
}
|
||||
|
||||
auto Interface::save() -> void {
|
||||
for(auto& memory : cartridge.memory) {
|
||||
interface->saveRequest(memory.id, memory.name);
|
||||
}
|
||||
}
|
||||
|
||||
auto Interface::load(uint id, const stream& stream) -> void {
|
||||
if(id == ID::SystemManifest) {
|
||||
system.information.manifest = stream.text();
|
||||
}
|
||||
|
||||
if(id == ID::BIOS) {
|
||||
stream.read((uint8_t*)bios.data, min(bios.size, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::Manifest) {
|
||||
cartridge.information.markup = stream.text();
|
||||
}
|
||||
|
||||
if(id == ID::MROM) {
|
||||
stream.read((uint8_t*)cartridge.mrom.data, min(cartridge.mrom.size, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::SRAM) {
|
||||
stream.read((uint8_t*)cartridge.sram.data, min(cartridge.sram.size, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::EEPROM) {
|
||||
stream.read((uint8_t*)cartridge.eeprom.data, min(cartridge.eeprom.size, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::FLASH) {
|
||||
stream.read((uint8_t*)cartridge.flash.data, min(cartridge.flash.size, stream.size()));
|
||||
}
|
||||
}
|
||||
|
||||
auto Interface::save(uint id, const stream& stream) -> void {
|
||||
if(id == ID::SRAM) {
|
||||
stream.write((uint8_t*)cartridge.sram.data, cartridge.sram.size);
|
||||
}
|
||||
|
||||
if(id == ID::EEPROM) {
|
||||
stream.write((uint8_t*)cartridge.eeprom.data, cartridge.eeprom.size);
|
||||
}
|
||||
|
||||
if(id == ID::FLASH) {
|
||||
stream.write((uint8_t*)cartridge.flash.data, cartridge.flash.size);
|
||||
}
|
||||
system.save();
|
||||
}
|
||||
|
||||
auto Interface::unload() -> void {
|
||||
|
|
|
@ -6,17 +6,6 @@ struct ID {
|
|||
GameBoyAdvance,
|
||||
};
|
||||
|
||||
enum : uint {
|
||||
SystemManifest,
|
||||
BIOS,
|
||||
|
||||
Manifest,
|
||||
MROM,
|
||||
SRAM,
|
||||
EEPROM,
|
||||
FLASH,
|
||||
};
|
||||
|
||||
enum : uint {
|
||||
Device = 1,
|
||||
};
|
||||
|
@ -33,11 +22,8 @@ struct Interface : Emulator::Interface {
|
|||
auto audioFrequency() -> double;
|
||||
|
||||
auto loaded() -> bool;
|
||||
auto group(uint id) -> uint;
|
||||
auto load(uint id) -> void;
|
||||
auto save() -> void;
|
||||
auto load(uint id, const stream& stream) -> void;
|
||||
auto save(uint id, const stream& stream) -> void;
|
||||
auto unload() -> void;
|
||||
|
||||
auto power() -> void;
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
auto System::serialize() -> serializer {
|
||||
serializer s(_serializeSize);
|
||||
|
||||
uint signature = 0x31545342, version = Info::SerializerVersion;
|
||||
char hash[64], description[512];
|
||||
memcpy(&hash, (const char*)cartridge.sha256(), 64);
|
||||
memset(&description, 0, sizeof description);
|
||||
uint signature = 0x31545342;
|
||||
char version[16] = {0};
|
||||
char hash[64] = {0};
|
||||
char description[512] = {0};
|
||||
memory::copy(&version, (const char*)Emulator::SerializerVersion, Emulator::SerializerVersion.size());
|
||||
memory::copy(&hash, (const char*)cartridge.sha256(), 64);
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.array(version);
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
|
@ -16,16 +18,18 @@ auto System::serialize() -> serializer {
|
|||
}
|
||||
|
||||
auto System::unserialize(serializer& s) -> bool {
|
||||
uint signature, version;
|
||||
char hash[64], description[512];
|
||||
uint signature = 0;
|
||||
char version[16] = {0};
|
||||
char hash[64] = {0};
|
||||
char description[512] = {0};
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.array(version);
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
if(signature != 0x31545342) return false;
|
||||
if(version != Info::SerializerVersion) return false;
|
||||
if(string{version} != Emulator::SerializerVersion) return false;
|
||||
|
||||
power();
|
||||
serializeAll(s);
|
||||
|
@ -49,11 +53,13 @@ auto System::serializeAll(serializer& s) -> void {
|
|||
auto System::serializeInit() -> void {
|
||||
serializer s;
|
||||
|
||||
uint signature = 0, version = 0;
|
||||
char hash[64], description[512];
|
||||
uint signature = 0;
|
||||
char version[16] = {0};
|
||||
char hash[64] = {0};
|
||||
char description[512] = {0};
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.array(version);
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
|
|
|
@ -8,8 +8,6 @@ namespace GameBoyAdvance {
|
|||
BIOS bios;
|
||||
System system;
|
||||
|
||||
auto System::loaded() const -> bool { return _loaded; }
|
||||
|
||||
auto System::init() -> void {
|
||||
}
|
||||
|
||||
|
@ -34,17 +32,26 @@ auto System::power() -> void {
|
|||
scheduler.power();
|
||||
}
|
||||
|
||||
auto System::load() -> void {
|
||||
interface->loadRequest(ID::SystemManifest, "manifest.bml", true);
|
||||
auto System::load() -> bool {
|
||||
if(auto fp = interface->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
||||
information.manifest = fp->reads();
|
||||
} else return false;
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
|
||||
if(auto bios = document["system/cpu/rom/name"].text()) {
|
||||
interface->loadRequest(ID::BIOS, bios, true);
|
||||
if(auto name = document["system/cpu/rom/name"].text()) {
|
||||
if(auto fp = interface->open(ID::System, name, File::Read, File::Required)) {
|
||||
fp->read(bios.data, bios.size);
|
||||
}
|
||||
}
|
||||
|
||||
cartridge.load();
|
||||
serializeInit();
|
||||
_loaded = true;
|
||||
return _loaded = true;
|
||||
}
|
||||
|
||||
auto System::save() -> void {
|
||||
if(!loaded()) return;
|
||||
cartridge.save();
|
||||
}
|
||||
|
||||
auto System::unload() -> void {
|
||||
|
|
|
@ -15,11 +15,12 @@ struct BIOS : Memory {
|
|||
};
|
||||
|
||||
struct System {
|
||||
auto loaded() const -> bool;
|
||||
auto loaded() const -> bool { return _loaded; }
|
||||
|
||||
auto init() -> void;
|
||||
auto term() -> void;
|
||||
auto load() -> void;
|
||||
auto load() -> bool;
|
||||
auto save() -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
auto run() -> void;
|
||||
|
|
|
@ -89,7 +89,7 @@ private:
|
|||
auto loadOBC1(Markup::Node) -> void;
|
||||
auto loadMSU1(Markup::Node) -> void;
|
||||
|
||||
auto loadMemory(MappedRAM&, Markup::Node, bool writable, uint id = 1) -> void;
|
||||
auto loadMemory(MappedRAM&, Markup::Node, bool required, uint id = 1) -> void;
|
||||
auto loadMap(Markup::Node, SuperFamicom::Memory&) -> void;
|
||||
auto loadMap(Markup::Node, const function<uint8 (uint24, uint8)>&, const function<void (uint24, uint8)>&) -> void;
|
||||
|
||||
|
|
|
@ -3,6 +3,9 @@ auto Cartridge::loadCartridge(Markup::Node node) -> void {
|
|||
auto board = node["board"];
|
||||
_region = board["region"].text() == "pal" ? Region::PAL : Region::NTSC;
|
||||
|
||||
if(board["mcc"] || board["bsmemory"]) interface->load(ID::BSMemory, "BS Memory", "bs");
|
||||
if(board["sufamiturbo"]) interface->load(ID::SufamiTurboA, "Sufami Turbo", "st");
|
||||
|
||||
if(auto node = board["rom"]) loadROM(node);
|
||||
if(auto node = board["ram"]) loadRAM(node);
|
||||
if(auto node = board["icd2"]) loadICD2(node);
|
||||
|
@ -23,9 +26,6 @@ auto Cartridge::loadCartridge(Markup::Node node) -> void {
|
|||
if(auto node = board["sdd1"]) loadSDD1(node);
|
||||
if(auto node = board["obc1"]) loadOBC1(node);
|
||||
if(auto node = board["msu1"]) loadMSU1(node);
|
||||
|
||||
if(board["mcc"] || board["bsmemory"]) interface->loadRequest(ID::BSMemory, "BS Memory", "bs", false);
|
||||
if(board["sufamiturbo"]) interface->loadRequest(ID::SufamiTurboA, "Sufami Turbo", "st", false);
|
||||
}
|
||||
|
||||
auto Cartridge::loadGameBoy(Markup::Node node) -> void {
|
||||
|
@ -35,185 +35,185 @@ auto Cartridge::loadBSMemory(Markup::Node node) -> void {
|
|||
information.title.bsMemory = node["information/title"].text();
|
||||
bsmemory.readonly = (node["board/rom/type"].text() == "mrom");
|
||||
|
||||
loadMemory(bsmemory.memory, node["board/rom"], false);
|
||||
loadMemory(bsmemory.memory, node["board/rom"], File::Required, ID::BSMemory);
|
||||
}
|
||||
|
||||
auto Cartridge::loadSufamiTurboA(Markup::Node node) -> void {
|
||||
information.title.sufamiTurboA = node["information/title"].text();
|
||||
|
||||
loadMemory(sufamiturboA.rom, node["rom"], ID::SufamiTurboA);
|
||||
loadMemory(sufamiturboA.ram, node["ram"], ID::SufamiTurboA);
|
||||
loadMemory(sufamiturboA.rom, node["board/rom"], File::Required, ID::SufamiTurboA);
|
||||
loadMemory(sufamiturboA.ram, node["board/ram"], File::Optional, ID::SufamiTurboA);
|
||||
|
||||
if(node["board/linkable"]) interface->loadRequest(ID::SufamiTurboB, "Sufami Turbo", "st", false);
|
||||
if(node["board/linkable"]) interface->load(ID::SufamiTurboB, "Sufami Turbo", "st");
|
||||
}
|
||||
|
||||
auto Cartridge::loadSufamiTurboB(Markup::Node node) -> void {
|
||||
information.title.sufamiTurboB = node["information/title"].text();
|
||||
|
||||
loadMemory(sufamiturboB.rom, node["rom"], ID::SufamiTurboB);
|
||||
loadMemory(sufamiturboB.ram, node["ram"], ID::SufamiTurboB);
|
||||
loadMemory(sufamiturboB.rom, node["board/rom"], File::Required, ID::SufamiTurboB);
|
||||
loadMemory(sufamiturboB.ram, node["board/ram"], File::Optional, ID::SufamiTurboB);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto Cartridge::loadROM(Markup::Node root) -> void {
|
||||
loadMemory(rom, root, false);
|
||||
for(auto node : root.find("map")) loadMap(node, rom);
|
||||
auto Cartridge::loadROM(Markup::Node node) -> void {
|
||||
loadMemory(rom, node, File::Required);
|
||||
for(auto leaf : node.find("map")) loadMap(leaf, rom);
|
||||
}
|
||||
|
||||
auto Cartridge::loadRAM(Markup::Node root) -> void {
|
||||
loadMemory(ram, root, true);
|
||||
for(auto node : root.find("map")) loadMap(node, ram);
|
||||
auto Cartridge::loadRAM(Markup::Node node) -> void {
|
||||
loadMemory(ram, node, File::Optional);
|
||||
for(auto leaf : node.find("map")) loadMap(leaf, ram);
|
||||
}
|
||||
|
||||
auto Cartridge::loadICD2(Markup::Node root) -> void {
|
||||
auto Cartridge::loadICD2(Markup::Node node) -> void {
|
||||
has.GameBoySlot = true;
|
||||
has.ICD2 = true;
|
||||
icd2.revision = max(1, root["revision"].natural());
|
||||
icd2.revision = max(1, node["revision"].natural());
|
||||
|
||||
//Game Boy core loads data through ICD2 interface
|
||||
for(auto node : root.find("map")) loadMap(node, {&ICD2::read, &icd2}, {&ICD2::write, &icd2});
|
||||
for(auto leaf : node.find("map")) loadMap(leaf, {&ICD2::read, &icd2}, {&ICD2::write, &icd2});
|
||||
}
|
||||
|
||||
auto Cartridge::loadMCC(Markup::Node root) -> void {
|
||||
auto Cartridge::loadMCC(Markup::Node node) -> void {
|
||||
has.BSMemorySlot = true;
|
||||
has.MCC = true;
|
||||
|
||||
loadMemory(mcc.rom, root["rom"], false);
|
||||
loadMemory(mcc.ram, root["ram"], true);
|
||||
loadMemory(mcc.rom, node["rom"], File::Required);
|
||||
loadMemory(mcc.ram, node["ram"], File::Optional);
|
||||
|
||||
for(auto node : root.find("map")) node.text() == "mcu"
|
||||
? loadMap(node, {&MCC::mcuRead, &mcc}, {&MCC::mcuWrite, &mcc})
|
||||
: loadMap(node, {&MCC::read, &mcc}, {&MCC::write, &mcc});
|
||||
for(auto node : root["ram"].find("map")) loadMap(node, mcc.ram);
|
||||
for(auto leaf : node.find("map")) leaf.text() == "mcu"
|
||||
? loadMap(leaf, {&MCC::mcuRead, &mcc}, {&MCC::mcuWrite, &mcc})
|
||||
: loadMap(leaf, {&MCC::read, &mcc}, {&MCC::write, &mcc});
|
||||
for(auto leaf : node["ram"].find("map")) loadMap(leaf, mcc.ram);
|
||||
}
|
||||
|
||||
auto Cartridge::loadBSMemoryPack(Markup::Node root) -> void {
|
||||
auto Cartridge::loadBSMemoryPack(Markup::Node node) -> void {
|
||||
has.BSMemorySlot = true;
|
||||
|
||||
for(auto node : root.find("map")) {
|
||||
for(auto leaf : node.find("map")) {
|
||||
if(bsmemory.memory.size() == 0) continue;
|
||||
loadMap(node, bsmemory);
|
||||
loadMap(leaf, bsmemory);
|
||||
}
|
||||
}
|
||||
|
||||
auto Cartridge::loadSufamiTurbo(Markup::Node root, bool slot) -> void {
|
||||
auto Cartridge::loadSufamiTurbo(Markup::Node node, bool slot) -> void {
|
||||
has.SufamiTurboSlots = true;
|
||||
|
||||
for(auto node : root["rom"].find("map")) {
|
||||
for(auto leaf : node["rom"].find("map")) {
|
||||
auto& cart = (slot == 0 ? sufamiturboA : sufamiturboB);
|
||||
if(cart.rom.size() == 0) continue;
|
||||
loadMap(node, cart.rom);
|
||||
loadMap(leaf, cart.rom);
|
||||
}
|
||||
|
||||
for(auto node : root["ram"].find("map")) {
|
||||
for(auto leaf : node["ram"].find("map")) {
|
||||
auto& cart = (slot == 0 ? sufamiturboA : sufamiturboB);
|
||||
if(cart.ram.size() == 0) continue;
|
||||
loadMap(node, cart.ram);
|
||||
loadMap(leaf, cart.ram);
|
||||
}
|
||||
}
|
||||
|
||||
auto Cartridge::loadNSS(Markup::Node root) -> void {
|
||||
auto Cartridge::loadNSS(Markup::Node node) -> void {
|
||||
has.NSSDIP = true;
|
||||
nss.dip = interface->dipSettings(root);
|
||||
nss.dip = interface->dipSettings(node);
|
||||
|
||||
for(auto node : root.find("map")) loadMap(node, {&NSS::read, &nss}, {&NSS::write, &nss});
|
||||
for(auto leaf : node.find("map")) loadMap(leaf, {&NSS::read, &nss}, {&NSS::write, &nss});
|
||||
}
|
||||
|
||||
auto Cartridge::loadEvent(Markup::Node root) -> void {
|
||||
auto roms = root.find("rom");
|
||||
auto Cartridge::loadEvent(Markup::Node node) -> void {
|
||||
auto roms = node.find("rom");
|
||||
if(roms.size() != 4) return;
|
||||
|
||||
has.Event = true;
|
||||
|
||||
for(uint n : range(4)) loadMemory(event.rom[n], roms[n], false);
|
||||
loadMemory(event.ram, root["ram"], true);
|
||||
for(uint n : range(4)) loadMemory(event.rom[n], roms[n], File::Required);
|
||||
loadMemory(event.ram, node["ram"], File::Optional);
|
||||
|
||||
event.board = Event::Board::CampusChallenge92;
|
||||
if(root.text() == "CC92") event.board = Event::Board::CampusChallenge92;
|
||||
if(root.text() == "PF94") event.board = Event::Board::Powerfest94;
|
||||
event.timer = root["timer"].natural();
|
||||
if(node.text() == "CC92") event.board = Event::Board::CampusChallenge92;
|
||||
if(node.text() == "PF94") event.board = Event::Board::Powerfest94;
|
||||
event.timer = node["timer"].natural();
|
||||
|
||||
for(auto node : root.find("map")) node.text() == "mcu"
|
||||
? loadMap(node, {&Event::mcuRead, &event}, {&Event::mcuWrite, &event})
|
||||
: loadMap(node, {&Event::read, &event}, {&Event::write, &event});
|
||||
for(auto node : root["ram"].find("map")) loadMap(node, event.ram);
|
||||
for(auto leaf : node.find("map")) leaf.text() == "mcu"
|
||||
? loadMap(leaf, {&Event::mcuRead, &event}, {&Event::mcuWrite, &event})
|
||||
: loadMap(leaf, {&Event::read, &event}, {&Event::write, &event});
|
||||
for(auto leaf : node["ram"].find("map")) loadMap(leaf, event.ram);
|
||||
}
|
||||
|
||||
auto Cartridge::loadSA1(Markup::Node root) -> void {
|
||||
auto Cartridge::loadSA1(Markup::Node node) -> void {
|
||||
has.SA1 = true;
|
||||
|
||||
loadMemory(sa1.rom, root["rom"], false);
|
||||
loadMemory(sa1.bwram, root["bwram"], true);
|
||||
loadMemory(sa1.iram, root["iram"], true);
|
||||
loadMemory(sa1.rom, node["rom"], File::Required);
|
||||
loadMemory(sa1.bwram, node["bwram"], File::Optional);
|
||||
loadMemory(sa1.iram, node["iram"], File::Optional);
|
||||
|
||||
for(auto node : root.find("map")) loadMap(node, {&SA1::readIO, &sa1}, {&SA1::writeIO, &sa1});
|
||||
for(auto node : root["rom"].find("map")) loadMap(node, {&SA1::mmcromRead, &sa1}, {&SA1::mmcromWrite, &sa1});
|
||||
for(auto node : root["bwram"].find("map")) loadMap(node, {&SA1::mmcbwramRead, &sa1}, {&SA1::mmcbwramWrite, &sa1});
|
||||
for(auto node : root["iram"].find("map")) loadMap(node, sa1.cpuiram);
|
||||
for(auto leaf : node.find("map")) loadMap(leaf, {&SA1::readIO, &sa1}, {&SA1::writeIO, &sa1});
|
||||
for(auto leaf : node["rom"].find("map")) loadMap(leaf, {&SA1::mmcromRead, &sa1}, {&SA1::mmcromWrite, &sa1});
|
||||
for(auto leaf : node["bwram"].find("map")) loadMap(leaf, {&SA1::mmcbwramRead, &sa1}, {&SA1::mmcbwramWrite, &sa1});
|
||||
for(auto leaf : node["iram"].find("map")) loadMap(leaf, sa1.cpuiram);
|
||||
}
|
||||
|
||||
auto Cartridge::loadSuperFX(Markup::Node root) -> void {
|
||||
auto Cartridge::loadSuperFX(Markup::Node node) -> void {
|
||||
has.SuperFX = true;
|
||||
|
||||
loadMemory(superfx.rom, root["rom"], false);
|
||||
loadMemory(superfx.ram, root["ram"], true);
|
||||
loadMemory(superfx.rom, node["rom"], File::Required);
|
||||
loadMemory(superfx.ram, node["ram"], File::Optional);
|
||||
|
||||
for(auto node : root.find("map")) loadMap(node, {&SuperFX::readIO, &superfx}, {&SuperFX::writeIO, &superfx});
|
||||
for(auto node : root["rom"].find("map")) loadMap(node, superfx.cpurom);
|
||||
for(auto node : root["ram"].find("map")) loadMap(node, superfx.cpuram);
|
||||
for(auto leaf : node.find("map")) loadMap(leaf, {&SuperFX::readIO, &superfx}, {&SuperFX::writeIO, &superfx});
|
||||
for(auto leaf : node["rom"].find("map")) loadMap(leaf, superfx.cpurom);
|
||||
for(auto leaf : node["ram"].find("map")) loadMap(leaf, superfx.cpuram);
|
||||
}
|
||||
|
||||
auto Cartridge::loadARMDSP(Markup::Node root) -> void {
|
||||
auto Cartridge::loadARMDSP(Markup::Node node) -> void {
|
||||
has.ARMDSP = true;
|
||||
|
||||
if(auto fp = interface->open(ID::SuperFamicom, root["prom"]["name"].text(), File::Read, File::Required)) {
|
||||
if(auto fp = interface->open(ID::SuperFamicom, node["prom"]["name"].text(), File::Read, File::Required)) {
|
||||
for(auto n : range(128 * 1024)) armdsp.programROM[n] = fp->read();
|
||||
}
|
||||
if(auto fp = interface->open(ID::SuperFamicom, root["drom"]["name"].text(), File::Read, File::Required)) {
|
||||
if(auto fp = interface->open(ID::SuperFamicom, node["drom"]["name"].text(), File::Read, File::Required)) {
|
||||
for(auto n : range( 32 * 1024)) armdsp.dataROM[n] = fp->read();
|
||||
}
|
||||
if(auto fp = interface->open(ID::SuperFamicom, root["ram"]["name"].text(), File::Read)) {
|
||||
if(auto fp = interface->open(ID::SuperFamicom, node["ram"]["name"].text(), File::Read)) {
|
||||
for(auto n : range( 16 * 1024)) armdsp.programRAM[n] = fp->read();
|
||||
}
|
||||
|
||||
for(auto node : root.find("map")) loadMap(node, {&ArmDSP::read, &armdsp}, {&ArmDSP::write, &armdsp});
|
||||
for(auto leaf : node.find("map")) loadMap(leaf, {&ArmDSP::read, &armdsp}, {&ArmDSP::write, &armdsp});
|
||||
}
|
||||
|
||||
auto Cartridge::loadHitachiDSP(Markup::Node root, uint roms) -> void {
|
||||
auto Cartridge::loadHitachiDSP(Markup::Node node, uint roms) -> void {
|
||||
has.HitachiDSP = true;
|
||||
|
||||
hitachidsp.Frequency = root["frequency"].natural();
|
||||
hitachidsp.Frequency = node["frequency"].natural();
|
||||
if(hitachidsp.Frequency == 0) hitachidsp.frequency = 20000000;
|
||||
hitachidsp.Roms = roms; //1 or 2
|
||||
|
||||
loadMemory(hitachidsp.rom, root["rom"], false);
|
||||
loadMemory(hitachidsp.ram, root["ram"], true);
|
||||
loadMemory(hitachidsp.rom, node["rom"], File::Required);
|
||||
loadMemory(hitachidsp.ram, node["ram"], File::Optional);
|
||||
|
||||
for(auto& word : hitachidsp.dataROM) word = 0x000000;
|
||||
for(auto& word : hitachidsp.dataRAM) word = 0x00;
|
||||
|
||||
if(auto fp = interface->open(ID::SuperFamicom, root["drom"]["name"].text(), File::Read, File::Required)) {
|
||||
if(auto fp = interface->open(ID::SuperFamicom, node["drom"]["name"].text(), File::Read, File::Required)) {
|
||||
for(auto n : range(1 * 1024)) hitachidsp.dataROM[n] = fp->readl(3);
|
||||
}
|
||||
if(auto fp = interface->open(ID::SuperFamicom, root["dram"]["name"].text(), File::Read)) {
|
||||
if(auto fp = interface->open(ID::SuperFamicom, node["dram"]["name"].text(), File::Read)) {
|
||||
for(auto n : range(3 * 1024)) hitachidsp.dataRAM[n] = fp->readl(1);
|
||||
}
|
||||
|
||||
for(auto node : root.find("map")) loadMap(node, {&HitachiDSP::dspRead, &hitachidsp}, {&HitachiDSP::dspWrite, &hitachidsp});
|
||||
for(auto node : root["rom"].find("map")) loadMap(node, {&HitachiDSP::romRead, &hitachidsp}, {&HitachiDSP::romWrite, &hitachidsp});
|
||||
for(auto node : root["ram"].find("map")) loadMap(node, {&HitachiDSP::ramRead, &hitachidsp}, {&HitachiDSP::ramWrite, &hitachidsp});
|
||||
for(auto node : root["dram"].find("map")) loadMap(node, {&HitachiDSP::dramRead, &hitachidsp}, {&HitachiDSP::dramWrite, &hitachidsp});
|
||||
for(auto leaf : node.find("map")) loadMap(leaf, {&HitachiDSP::dspRead, &hitachidsp}, {&HitachiDSP::dspWrite, &hitachidsp});
|
||||
for(auto leaf : node["rom"].find("map")) loadMap(leaf, {&HitachiDSP::romRead, &hitachidsp}, {&HitachiDSP::romWrite, &hitachidsp});
|
||||
for(auto leaf : node["ram"].find("map")) loadMap(leaf, {&HitachiDSP::ramRead, &hitachidsp}, {&HitachiDSP::ramWrite, &hitachidsp});
|
||||
for(auto leaf : node["dram"].find("map")) loadMap(leaf, {&HitachiDSP::dramRead, &hitachidsp}, {&HitachiDSP::dramWrite, &hitachidsp});
|
||||
}
|
||||
|
||||
auto Cartridge::loadNECDSP(Markup::Node root) -> void {
|
||||
auto Cartridge::loadNECDSP(Markup::Node node) -> void {
|
||||
has.NECDSP = true;
|
||||
|
||||
necdsp.frequency = root["frequency"].natural();
|
||||
necdsp.frequency = node["frequency"].natural();
|
||||
if(necdsp.frequency == 0) necdsp.frequency = 8000000;
|
||||
necdsp.revision
|
||||
= root["model"].text() == "uPD7725" ? NECDSP::Revision::uPD7725
|
||||
: root["model"].text() == "uPD96050" ? NECDSP::Revision::uPD96050
|
||||
= node["model"].text() == "uPD7725" ? NECDSP::Revision::uPD7725
|
||||
: node["model"].text() == "uPD96050" ? NECDSP::Revision::uPD96050
|
||||
: NECDSP::Revision::uPD7725;
|
||||
|
||||
for(auto& word : necdsp.programROM) word = 0x000000;
|
||||
|
@ -224,89 +224,89 @@ auto Cartridge::loadNECDSP(Markup::Node root) -> void {
|
|||
if(necdsp.revision == NECDSP::Revision::uPD7725 ) memory::assign(size, 2048, 1024, 256);
|
||||
if(necdsp.revision == NECDSP::Revision::uPD96050) memory::assign(size, 16384, 2048, 2048);
|
||||
|
||||
if(auto fp = interface->open(ID::SuperFamicom, root["prom"]["name"].text(), File::Read, File::Required)) {
|
||||
if(auto fp = interface->open(ID::SuperFamicom, node["prom"]["name"].text(), File::Read, File::Required)) {
|
||||
for(auto n : range(size[0])) necdsp.programROM[n] = fp->readl(3);
|
||||
}
|
||||
if(auto fp = interface->open(ID::SuperFamicom, root["drom"]["name"].text(), File::Read, File::Required)) {
|
||||
if(auto fp = interface->open(ID::SuperFamicom, node["drom"]["name"].text(), File::Read, File::Required)) {
|
||||
for(auto n : range(size[1])) necdsp.dataROM[n] = fp->readl(2);
|
||||
}
|
||||
if(auto fp = interface->open(ID::SuperFamicom, root["dram"]["name"].text(), File::Read)) {
|
||||
if(auto fp = interface->open(ID::SuperFamicom, node["dram"]["name"].text(), File::Read)) {
|
||||
for(auto n : range(size[2])) necdsp.dataRAM[n] = fp->readl(2);
|
||||
}
|
||||
|
||||
for(auto node : root.find("map")) loadMap(node, {&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp});
|
||||
for(auto node : root["dram"].find("map")) loadMap(node, {&NECDSP::readRAM, &necdsp}, {&NECDSP::writeRAM, &necdsp});
|
||||
for(auto leaf : node.find("map")) loadMap(leaf, {&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp});
|
||||
for(auto leaf : node["dram"].find("map")) loadMap(leaf, {&NECDSP::readRAM, &necdsp}, {&NECDSP::writeRAM, &necdsp});
|
||||
}
|
||||
|
||||
auto Cartridge::loadEpsonRTC(Markup::Node root) -> void {
|
||||
auto Cartridge::loadEpsonRTC(Markup::Node node) -> void {
|
||||
has.EpsonRTC = true;
|
||||
|
||||
if(auto fp = interface->open(ID::SuperFamicom, root["ram"]["name"].text(), File::Read)) {
|
||||
if(auto fp = interface->open(ID::SuperFamicom, node["ram"]["name"].text(), File::Read)) {
|
||||
uint8 data[16] = {0};
|
||||
for(auto& byte : data) fp->read();
|
||||
epsonrtc.load(data);
|
||||
}
|
||||
|
||||
for(auto node : root.find("map")) loadMap(node, {&EpsonRTC::read, &epsonrtc}, {&EpsonRTC::write, &epsonrtc});
|
||||
for(auto leaf : node.find("map")) loadMap(leaf, {&EpsonRTC::read, &epsonrtc}, {&EpsonRTC::write, &epsonrtc});
|
||||
}
|
||||
|
||||
auto Cartridge::loadSharpRTC(Markup::Node root) -> void {
|
||||
auto Cartridge::loadSharpRTC(Markup::Node node) -> void {
|
||||
has.SharpRTC = true;
|
||||
|
||||
if(auto fp = interface->open(ID::SuperFamicom, root["ram"]["name"].text(), File::Read)) {
|
||||
if(auto fp = interface->open(ID::SuperFamicom, node["ram"]["name"].text(), File::Read)) {
|
||||
uint8 data[16] = {0};
|
||||
for(auto& byte : data) fp->read();
|
||||
sharprtc.load(data);
|
||||
}
|
||||
|
||||
for(auto node : root.find("map")) loadMap(node, {&SharpRTC::read, &sharprtc}, {&SharpRTC::write, &sharprtc});
|
||||
for(auto leaf : node.find("map")) loadMap(leaf, {&SharpRTC::read, &sharprtc}, {&SharpRTC::write, &sharprtc});
|
||||
}
|
||||
|
||||
auto Cartridge::loadSPC7110(Markup::Node root) -> void {
|
||||
auto Cartridge::loadSPC7110(Markup::Node node) -> void {
|
||||
has.SPC7110 = true;
|
||||
|
||||
loadMemory(spc7110.prom, root["prom"], false);
|
||||
loadMemory(spc7110.drom, root["drom"], false);
|
||||
loadMemory(spc7110.ram, root["ram"], true);
|
||||
loadMemory(spc7110.prom, node["prom"], File::Required);
|
||||
loadMemory(spc7110.drom, node["drom"], File::Required);
|
||||
loadMemory(spc7110.ram, node["ram"], File::Optional);
|
||||
|
||||
for(auto node : root.find("map")) node.text() == "mcu"
|
||||
? loadMap(node, {&SPC7110::mcuromRead, &spc7110}, {&SPC7110::mcuromWrite, &spc7110})
|
||||
: loadMap(node, {&SPC7110::read, &spc7110}, {&SPC7110::write, &spc7110});
|
||||
for(auto node : root["ram"].find("map")) loadMap(node, {&SPC7110::mcuramRead, &spc7110}, {&SPC7110::mcuramWrite, &spc7110});
|
||||
for(auto leaf : node.find("map")) leaf.text() == "mcu"
|
||||
? loadMap(leaf, {&SPC7110::mcuromRead, &spc7110}, {&SPC7110::mcuromWrite, &spc7110})
|
||||
: loadMap(leaf, {&SPC7110::read, &spc7110}, {&SPC7110::write, &spc7110});
|
||||
for(auto leaf : node["ram"].find("map")) loadMap(leaf, {&SPC7110::mcuramRead, &spc7110}, {&SPC7110::mcuramWrite, &spc7110});
|
||||
}
|
||||
|
||||
auto Cartridge::loadSDD1(Markup::Node root) -> void {
|
||||
auto Cartridge::loadSDD1(Markup::Node node) -> void {
|
||||
has.SDD1 = true;
|
||||
|
||||
loadMemory(sdd1.rom, root["rom"], false);
|
||||
loadMemory(sdd1.ram, root["ram"], true);
|
||||
loadMemory(sdd1.rom, node["rom"], File::Required);
|
||||
loadMemory(sdd1.ram, node["ram"], File::Optional);
|
||||
|
||||
for(auto node : root.find("map")) loadMap(node, {&SDD1::read, &sdd1}, {&SDD1::write, &sdd1});
|
||||
for(auto node : root["rom"].find("map")) loadMap(node, {&SDD1::mcuromRead, &sdd1}, {&SDD1::mcuromWrite, &sdd1});
|
||||
for(auto node : root["ram"].find("map")) loadMap(node, {&SDD1::mcuramRead, &sdd1}, {&SDD1::mcuramWrite, &sdd1});
|
||||
for(auto leaf : node.find("map")) loadMap(leaf, {&SDD1::read, &sdd1}, {&SDD1::write, &sdd1});
|
||||
for(auto leaf : node["rom"].find("map")) loadMap(leaf, {&SDD1::mcuromRead, &sdd1}, {&SDD1::mcuromWrite, &sdd1});
|
||||
for(auto leaf : node["ram"].find("map")) loadMap(leaf, {&SDD1::mcuramRead, &sdd1}, {&SDD1::mcuramWrite, &sdd1});
|
||||
}
|
||||
|
||||
auto Cartridge::loadOBC1(Markup::Node root) -> void {
|
||||
auto Cartridge::loadOBC1(Markup::Node node) -> void {
|
||||
has.OBC1 = true;
|
||||
|
||||
loadMemory(obc1.ram, root["ram"], true);
|
||||
loadMemory(obc1.ram, node["ram"], File::Optional);
|
||||
|
||||
for(auto node : root.find("map")) loadMap(node, {&OBC1::read, &obc1}, {&OBC1::write, &obc1});
|
||||
for(auto leaf : node.find("map")) loadMap(leaf, {&OBC1::read, &obc1}, {&OBC1::write, &obc1});
|
||||
}
|
||||
|
||||
auto Cartridge::loadMSU1(Markup::Node root) -> void {
|
||||
auto Cartridge::loadMSU1(Markup::Node node) -> void {
|
||||
has.MSU1 = true;
|
||||
|
||||
for(auto node : root.find("map")) loadMap(node, {&MSU1::read, &msu1}, {&MSU1::write, &msu1});
|
||||
for(auto leaf : node.find("map")) loadMap(leaf, {&MSU1::read, &msu1}, {&MSU1::write, &msu1});
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto Cartridge::loadMemory(MappedRAM& ram, Markup::Node node, bool writable, uint id) -> void {
|
||||
auto Cartridge::loadMemory(MappedRAM& ram, Markup::Node node, bool required, uint id) -> void {
|
||||
auto name = node["name"].text();
|
||||
auto size = node["size"].natural();
|
||||
ram.allocate(size);
|
||||
if(auto fp = interface->open(id, name, File::Read, !writable)) { //treat ROM as required; RAM as optional
|
||||
if(auto fp = interface->open(id, name, File::Read, required)) {
|
||||
fp->read(ram.data(), ram.size());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ auto ICD2::load() -> void {
|
|||
hook = GameBoy::interface->hook;
|
||||
GameBoy::interface->bind = this;
|
||||
GameBoy::interface->hook = this;
|
||||
interface->loadRequest(ID::GameBoy, "Game Boy", "gb", false);
|
||||
interface->load(ID::GameBoy, "Game Boy", "gb");
|
||||
GameBoy::interface->load(GameBoy::ID::SuperGameBoy);
|
||||
cartridge.loadGameBoy();
|
||||
}
|
||||
|
|
|
@ -17,9 +17,7 @@ struct ICD2 : Emulator::Interface::Bind, GameBoy::Interface::Hook, Cothread {
|
|||
auto lcdOutput(uint2 color) -> void override;
|
||||
auto joypWrite(bool p15, bool p14) -> void override;
|
||||
|
||||
auto loadRequest(uint id, string name, string type, bool required) -> void override;
|
||||
auto loadRequest(uint id, string name, bool required) -> void override;
|
||||
auto saveRequest(uint id, string name) -> void override;
|
||||
auto load(uint id, string name, string type, bool required) -> void override;
|
||||
|
||||
auto videoRefresh(const uint32* data, uint pitch, uint width, uint height) -> void override;
|
||||
auto audioSample(const double* samples, uint channels) -> void override;
|
||||
|
|
|
@ -85,9 +85,10 @@ auto ICD2::joypWrite(bool p15, bool p14) -> void {
|
|||
packetLock = true;
|
||||
}
|
||||
|
||||
auto ICD2::loadRequest(uint id, string name, string type, bool required) -> void {
|
||||
auto ICD2::load(uint id, string name, string type, bool required) -> void {
|
||||
}
|
||||
|
||||
/*
|
||||
auto ICD2::loadRequest(uint id, string name, bool required) -> void {
|
||||
if(id == GameBoy::ID::SystemManifest) {
|
||||
interface->loadRequest(ID::SuperGameBoyManifest, name, required);
|
||||
|
@ -115,6 +116,7 @@ auto ICD2::saveRequest(uint id, string name) -> void {
|
|||
interface->saveRequest(ID::GameBoyRAM, name);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
auto ICD2::videoRefresh(const uint32* data, uint pitch, uint width, uint height) -> void {
|
||||
}
|
||||
|
|
|
@ -183,20 +183,6 @@ auto Interface::sha256() -> string {
|
|||
return cartridge.sha256();
|
||||
}
|
||||
|
||||
//deprecated
|
||||
auto Interface::group(uint id) -> uint {
|
||||
switch(id) {
|
||||
case ID::SuperGameBoyManifest:
|
||||
case ID::SuperGameBoyBootROM:
|
||||
return 1;
|
||||
case ID::GameBoyManifest:
|
||||
case ID::GameBoyROM:
|
||||
case ID::GameBoyRAM:
|
||||
return 2;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
auto Interface::load(uint id) -> void {
|
||||
if(id == ID::SuperFamicom) system.load();
|
||||
if(id == ID::BSMemory) cartridge.loadBSMemory();
|
||||
|
@ -208,40 +194,6 @@ auto Interface::save() -> void {
|
|||
system.save();
|
||||
}
|
||||
|
||||
//deprecated
|
||||
auto Interface::load(uint id, const stream& stream) -> void {
|
||||
#if defined(SFC_SUPERGAMEBOY)
|
||||
if(id == ID::SuperGameBoyManifest) {
|
||||
GameBoy::interface->load(GameBoy::ID::SystemManifest, stream);
|
||||
}
|
||||
|
||||
if(id == ID::SuperGameBoyBootROM) {
|
||||
GameBoy::interface->load(GameBoy::ID::SuperGameBoyBootROM, stream);
|
||||
}
|
||||
|
||||
if(id == ID::GameBoyManifest) {
|
||||
GameBoy::interface->load(GameBoy::ID::Manifest, stream);
|
||||
}
|
||||
|
||||
if(id == ID::GameBoyROM) {
|
||||
GameBoy::interface->load(GameBoy::ID::ROM, stream);
|
||||
}
|
||||
|
||||
if(id == ID::GameBoyRAM) {
|
||||
GameBoy::interface->load(GameBoy::ID::RAM, stream);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//deprecated
|
||||
auto Interface::save(uint id, const stream& stream) -> void {
|
||||
#if defined(SFC_SUPERGAMEBOY)
|
||||
if(id == ID::GameBoyRAM) {
|
||||
GameBoy::interface->save(GameBoy::ID::RAM, stream);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
auto Interface::unload() -> void {
|
||||
save();
|
||||
system.unload();
|
||||
|
|
|
@ -27,6 +27,8 @@ struct ID {
|
|||
};
|
||||
|
||||
struct Interface : Emulator::Interface {
|
||||
using Emulator::Interface::load;
|
||||
|
||||
Interface();
|
||||
|
||||
auto manifest() -> string;
|
||||
|
@ -38,11 +40,8 @@ struct Interface : Emulator::Interface {
|
|||
|
||||
auto loaded() -> bool;
|
||||
auto sha256() -> string;
|
||||
auto group(uint id) -> uint;
|
||||
auto load(uint id) -> void;
|
||||
auto save() -> void;
|
||||
auto load(uint id, const stream& stream) -> void;
|
||||
auto save(uint id, const stream& stream) -> void;
|
||||
auto unload() -> void;
|
||||
|
||||
auto connect(uint port, uint device) -> void;
|
||||
|
|
|
@ -30,24 +30,6 @@ auto MappedRAM::allocate(uint size) -> void {
|
|||
memory::fill(_data, _size, 0xff);
|
||||
}
|
||||
|
||||
auto MappedRAM::map(uint8* source, uint length) -> void {
|
||||
reset();
|
||||
_data = source;
|
||||
_size = _data ? length : 0;
|
||||
}
|
||||
|
||||
auto MappedRAM::copy(const stream& memory) -> void {
|
||||
if(_data) delete[] _data;
|
||||
//round size up to multiple of 256-bytes
|
||||
_size = (memory.size() & ~255) + ((bool)(memory.size() & 255) << 8);
|
||||
_data = new uint8[_size]();
|
||||
memory.read((uint8_t*)_data, memory.size());
|
||||
}
|
||||
|
||||
auto MappedRAM::read(const stream& memory) -> void {
|
||||
memory.read((uint8_t*)_data, min(memory.size(), _size));
|
||||
}
|
||||
|
||||
auto MappedRAM::writeProtect(bool writeProtect) -> void { _writeProtect = writeProtect; }
|
||||
auto MappedRAM::data() -> uint8* { return _data; }
|
||||
auto MappedRAM::size() const -> uint { return _size; }
|
||||
|
|
|
@ -24,9 +24,6 @@ private:
|
|||
struct MappedRAM : Memory {
|
||||
inline auto reset() -> void;
|
||||
inline auto allocate(uint) -> void;
|
||||
inline auto map(uint8*, uint) -> void;
|
||||
inline auto copy(const stream& memory) -> void;
|
||||
inline auto read(const stream& memory) -> void;
|
||||
|
||||
inline auto writeProtect(bool writeProtect) -> void;
|
||||
inline auto data() -> uint8*;
|
||||
|
|
|
@ -56,7 +56,7 @@ auto PPU::Background::getTile() -> void {
|
|||
uint paletteOffset = (ppu.r.bgMode == 0 ? id << 5 : 0);
|
||||
uint paletteSize = 2 << colorDepth;
|
||||
uint tileMask = 0x0fff >> colorDepth;
|
||||
uint tiledataIndex = r.tiledataAddress >> (4 + colorDepth);
|
||||
uint tiledataIndex = r.tiledataAddress >> (3 + colorDepth);
|
||||
|
||||
uint tileHeight = (r.tileSize == TileSize::Size8x8 ? 3 : 4);
|
||||
uint tileWidth = (!hires ? tileHeight : 4);
|
||||
|
@ -116,12 +116,12 @@ auto PPU::Background::getTile() -> void {
|
|||
uint tx = hoffset >> tileWidth;
|
||||
uint ty = voffset >> tileHeight;
|
||||
|
||||
uint16 offset = ((ty & 0x1f) << 5) + (tx & 0x1f);
|
||||
uint15 offset = ((ty & 0x1f) << 5) + (tx & 0x1f);
|
||||
if(tx & 0x20) offset += screenX;
|
||||
if(ty & 0x20) offset += screenY;
|
||||
|
||||
uint16 address = r.screenAddress + (offset << 1);
|
||||
tile = (ppu.vram[address + 0] << 0) + (ppu.vram[address + 1] << 8);
|
||||
uint15 address = r.screenAddress + offset;
|
||||
tile = ppu.vram[address];
|
||||
bool mirrorY = tile & 0x8000;
|
||||
bool mirrorX = tile & 0x4000;
|
||||
priority = r.priority[bool(tile & 0x2000)];
|
||||
|
@ -133,20 +133,16 @@ auto PPU::Background::getTile() -> void {
|
|||
uint16 character = ((tile & 0x03ff) + tiledataIndex) & tileMask;
|
||||
|
||||
if(mirrorY) voffset ^= 7;
|
||||
offset = (character << (4 + colorDepth)) + ((voffset & 7) << 1);
|
||||
offset = (character << (3 + colorDepth)) + (voffset & 7);
|
||||
|
||||
switch(r.mode) {
|
||||
case Mode::BPP8:
|
||||
data[1].byte(3) = ppu.vram[offset + 49];
|
||||
data[1].byte(2) = ppu.vram[offset + 48];
|
||||
data[1].byte(1) = ppu.vram[offset + 33];
|
||||
data[1].byte(0) = ppu.vram[offset + 32];
|
||||
data[1].bits(16,31) = ppu.vram[offset + 24];
|
||||
data[1].bits( 0,15) = ppu.vram[offset + 16];
|
||||
case Mode::BPP4:
|
||||
data[0].byte(3) = ppu.vram[offset + 17];
|
||||
data[0].byte(2) = ppu.vram[offset + 16];
|
||||
data[0].bits(16,31) = ppu.vram[offset + 8];
|
||||
case Mode::BPP2:
|
||||
data[0].byte(1) = ppu.vram[offset + 1];
|
||||
data[0].byte(0) = ppu.vram[offset + 0];
|
||||
data[0].bits( 0,15) = ppu.vram[offset + 0];
|
||||
}
|
||||
|
||||
if(mirrorX) for(auto n : range(2)) {
|
||||
|
@ -211,8 +207,8 @@ auto PPU::Background::getTileColor() -> uint {
|
|||
}
|
||||
|
||||
auto PPU::Background::reset() -> void {
|
||||
r.tiledataAddress = (random(0x0000) & 0x07) << 13;
|
||||
r.screenAddress = (random(0x0000) & 0x7c) << 9;
|
||||
r.tiledataAddress = (random(0x0000) & 0x07) << 12;
|
||||
r.screenAddress = (random(0x0000) & 0x7c) << 8;
|
||||
r.screenSize = random(0);
|
||||
r.mosaic = random(0);
|
||||
r.tileSize = random(0);
|
||||
|
@ -274,6 +270,6 @@ auto PPU::Background::getTile(uint x, uint y) -> uint {
|
|||
if(x & 0x20) offset += screenX;
|
||||
if(y & 0x20) offset += screenY;
|
||||
|
||||
uint16 address = r.screenAddress + (offset << 1);
|
||||
return (ppu.vram[address + 0] << 0) + (ppu.vram[address + 1] << 8);
|
||||
uint15 address = r.screenAddress + offset;
|
||||
return ppu.vram[address];
|
||||
}
|
||||
|
|
|
@ -50,8 +50,8 @@ auto PPU::Background::runMode7() -> void {
|
|||
case 1:
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tile = ppu.vram[((py >> 3) * 128 + (px >> 3)) << 1];
|
||||
palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
tile = ppu.vram[(py >> 3) * 128 + (px >> 3)].byte(0);
|
||||
palette = ppu.vram[(tile << 6) + ((py & 7) << 3) + (px & 7)].byte(1);
|
||||
break;
|
||||
|
||||
//palette color 0 outside of screen area
|
||||
|
@ -61,8 +61,8 @@ auto PPU::Background::runMode7() -> void {
|
|||
} else {
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tile = ppu.vram[((py >> 3) * 128 + (px >> 3)) << 1];
|
||||
palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
tile = ppu.vram[(py >> 3) * 128 + (px >> 3)].byte(0);
|
||||
palette = ppu.vram[(tile << 6) + ((py & 7) << 3) + (px & 7)].byte(1);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -73,9 +73,9 @@ auto PPU::Background::runMode7() -> void {
|
|||
} else {
|
||||
px &= 1023;
|
||||
py &= 1023;
|
||||
tile = ppu.vram[((py >> 3) * 128 + (px >> 3)) << 1];
|
||||
tile = ppu.vram[(py >> 3) * 128 + (px >> 3)].byte(0);
|
||||
}
|
||||
palette = ppu.vram[(((tile << 6) + ((py & 7) << 3) + (px & 7)) << 1) + 1];
|
||||
palette = ppu.vram[(tile << 6) + ((py & 7) << 3) + (px & 7)].byte(1);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
auto PPU::getVramAddress() -> uint16 {
|
||||
uint16 address = r.vramAddress;
|
||||
switch(r.vramMapping) {
|
||||
case 0: break; //direct mapping
|
||||
case 1: address = (address & 0xff00) | ((address & 0x001f) << 3) | ((address >> 5) & 7); break;
|
||||
case 2: address = (address & 0xfe00) | ((address & 0x003f) << 3) | ((address >> 6) & 7); break;
|
||||
case 3: address = (address & 0xfc00) | ((address & 0x007f) << 3) | ((address >> 7) & 7); break;
|
||||
case 0: return (address);
|
||||
case 1: return (address & 0xff00) | ((address & 0x001f) << 3) | ((address >> 5) & 7);
|
||||
case 2: return (address & 0xfe00) | ((address & 0x003f) << 3) | ((address >> 6) & 7);
|
||||
case 3: return (address & 0xfc00) | ((address & 0x007f) << 3) | ((address >> 7) & 7);
|
||||
}
|
||||
return address << 1;
|
||||
unreachable;
|
||||
}
|
||||
|
||||
auto PPU::vramRead(uint addr) -> uint8 {
|
||||
auto PPU::vramRead(bool chip, uint15 addr) -> uint8 {
|
||||
uint8 data = 0x00;
|
||||
if(r.displayDisable || vcounter() >= vdisp()) {
|
||||
data = vram[addr];
|
||||
debugger.vramRead(addr, data);
|
||||
data = vram[addr].byte(chip);
|
||||
debugger.vramRead(addr << 1 | chip, data);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
auto PPU::vramWrite(uint addr, uint8 data) -> void {
|
||||
auto PPU::vramWrite(bool chip, uint15 addr, uint8 data) -> void {
|
||||
if(r.displayDisable || vcounter() >= vdisp()) {
|
||||
vram[addr] = data;
|
||||
debugger.vramWrite(addr, data);
|
||||
vram[addr].byte(chip) = data;
|
||||
debugger.vramWrite(addr << 1 | chip, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,12 +51,11 @@ auto PPU::read(uint24 addr, uint8 data) -> uint8 {
|
|||
|
||||
//VMDATALREAD
|
||||
case 0x2139: {
|
||||
uint16 address = getVramAddress() + 0;
|
||||
auto address = getVramAddress();
|
||||
ppu1.mdr = latch.vram >> 0;
|
||||
if(r.vramIncrementMode == 0) {
|
||||
address.bit(0) = 0;
|
||||
latch.vram.byte(0) = vramRead(address + 0);
|
||||
latch.vram.byte(1) = vramRead(address + 1);
|
||||
latch.vram.byte(0) = vramRead(0, address);
|
||||
latch.vram.byte(1) = vramRead(1, address);
|
||||
r.vramAddress += r.vramIncrementSize;
|
||||
}
|
||||
return ppu1.mdr;
|
||||
|
@ -64,12 +63,11 @@ auto PPU::read(uint24 addr, uint8 data) -> uint8 {
|
|||
|
||||
//VMDATAHREAD
|
||||
case 0x213a: {
|
||||
uint16 address = getVramAddress() + 1;
|
||||
uint16 address = getVramAddress();
|
||||
ppu1.mdr = latch.vram >> 8;
|
||||
if(r.vramIncrementMode == 1) {
|
||||
address.bit(0) = 0;
|
||||
latch.vram.byte(0) = vramRead(address + 0);
|
||||
latch.vram.byte(1) = vramRead(address + 1);
|
||||
latch.vram.byte(0) = vramRead(0, address);
|
||||
latch.vram.byte(1) = vramRead(1, address);
|
||||
r.vramAddress += r.vramIncrementSize;
|
||||
}
|
||||
return ppu1.mdr;
|
||||
|
@ -164,7 +162,7 @@ auto PPU::write(uint24 addr, uint8 data) -> void {
|
|||
|
||||
//OBSEL
|
||||
case 0x2101: {
|
||||
obj.r.tiledataAddress = data.bits(0,1) << 14;
|
||||
obj.r.tiledataAddress = data.bits(0,1) << 13;
|
||||
obj.r.nameSelect = data.bits(3,4);
|
||||
obj.r.baseSize = data.bits(5,7);
|
||||
return;
|
||||
|
@ -228,42 +226,42 @@ auto PPU::write(uint24 addr, uint8 data) -> void {
|
|||
//BG1SC
|
||||
case 0x2107: {
|
||||
bg1.r.screenSize = data.bits(0,1);
|
||||
bg1.r.screenAddress = data.bits(2,6) << 11;
|
||||
bg1.r.screenAddress = data.bits(2,6) << 10;
|
||||
return;
|
||||
}
|
||||
|
||||
//BG2SC
|
||||
case 0x2108: {
|
||||
bg2.r.screenSize = data.bits(0,1);
|
||||
bg2.r.screenAddress = data.bits(2,6) << 11;
|
||||
bg2.r.screenAddress = data.bits(2,6) << 10;
|
||||
return;
|
||||
}
|
||||
|
||||
//BG3SC
|
||||
case 0x2109: {
|
||||
bg3.r.screenSize = data.bits(0,1);
|
||||
bg3.r.screenAddress = data.bits(2,6) << 11;
|
||||
bg3.r.screenAddress = data.bits(2,6) << 10;
|
||||
return;
|
||||
}
|
||||
|
||||
//BG4SC
|
||||
case 0x210a: {
|
||||
bg4.r.screenSize = data.bits(0,1);
|
||||
bg4.r.screenAddress = data.bits(2,6) << 11;
|
||||
bg4.r.screenAddress = data.bits(2,6) << 10;
|
||||
return;
|
||||
}
|
||||
|
||||
//BG12NBA
|
||||
case 0x210b: {
|
||||
bg1.r.tiledataAddress = data.bits(0,2) << 13;
|
||||
bg2.r.tiledataAddress = data.bits(4,6) << 13;
|
||||
bg1.r.tiledataAddress = data.bits(0,2) << 12;
|
||||
bg2.r.tiledataAddress = data.bits(4,6) << 12;
|
||||
return;
|
||||
}
|
||||
|
||||
//BG34NBA
|
||||
case 0x210c: {
|
||||
bg3.r.tiledataAddress = data.bits(0,2) << 13;
|
||||
bg4.r.tiledataAddress = data.bits(4,6) << 13;
|
||||
bg3.r.tiledataAddress = data.bits(0,2) << 12;
|
||||
bg4.r.tiledataAddress = data.bits(4,6) << 12;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -346,9 +344,9 @@ auto PPU::write(uint24 addr, uint8 data) -> void {
|
|||
case 0x2116: {
|
||||
r.vramAddress &= 0xff00;
|
||||
r.vramAddress |= (data << 0);
|
||||
uint16 address = getVramAddress();
|
||||
latch.vram.byte(0) = vramRead(address + 0);
|
||||
latch.vram.byte(1) = vramRead(address + 1);
|
||||
auto address = getVramAddress();
|
||||
latch.vram.byte(0) = vramRead(0, address);
|
||||
latch.vram.byte(1) = vramRead(1, address);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -356,24 +354,24 @@ auto PPU::write(uint24 addr, uint8 data) -> void {
|
|||
case 0x2117: {
|
||||
r.vramAddress &= 0x00ff;
|
||||
r.vramAddress |= (data << 8);
|
||||
uint16 address = getVramAddress();
|
||||
latch.vram.byte(0) = vramRead(address + 0);
|
||||
latch.vram.byte(1) = vramRead(address + 1);
|
||||
auto address = getVramAddress();
|
||||
latch.vram.byte(0) = vramRead(0, address);
|
||||
latch.vram.byte(1) = vramRead(1, address);
|
||||
return;
|
||||
}
|
||||
|
||||
//VMDATAL
|
||||
case 0x2118: {
|
||||
uint16 address = getVramAddress() + 0;
|
||||
vramWrite(address, data);
|
||||
auto address = getVramAddress();
|
||||
vramWrite(0, address, data);
|
||||
if(r.vramIncrementMode == 0) r.vramAddress += r.vramIncrementSize;
|
||||
return;
|
||||
}
|
||||
|
||||
//VMDATAH
|
||||
case 0x2119: {
|
||||
uint16 address = getVramAddress() + 1;
|
||||
vramWrite(address, data);
|
||||
auto address = getVramAddress();
|
||||
vramWrite(1, address, data);
|
||||
if(r.vramIncrementMode == 1) r.vramAddress += r.vramIncrementSize;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ auto PPU::Object::tilefetch() -> void {
|
|||
uint16 chrx = (sprite.character >> 0) & 15;
|
||||
uint16 chry = (sprite.character >> 4) & 15;
|
||||
if(sprite.nameSelect) {
|
||||
tiledataAddress += (256 * 32) + (r.nameSelect << 13);
|
||||
tiledataAddress += (256 * 16) + (r.nameSelect << 12);
|
||||
}
|
||||
chry += (y >> 3);
|
||||
chry &= 15;
|
||||
|
@ -138,15 +138,13 @@ auto PPU::Object::tilefetch() -> void {
|
|||
oamTile[n].hflip = sprite.hflip;
|
||||
|
||||
uint mx = !sprite.hflip ? tx : (tileWidth - 1) - tx;
|
||||
uint pos = tiledataAddress + ((chry + ((chrx + mx) & 15)) << 5);
|
||||
uint16 addr = (pos & 0xffe0) + ((y & 7) * 2);
|
||||
uint pos = tiledataAddress + ((chry + ((chrx + mx) & 15)) << 4);
|
||||
uint15 addr = (pos & 0x7ff0) + (y & 7);
|
||||
|
||||
oamTile[n].data.byte(0) = ppu.vram[addr + 0];
|
||||
oamTile[n].data.byte(1) = ppu.vram[addr + 1];
|
||||
oamTile[n].data.bits( 0,15) = ppu.vram[addr + 0];
|
||||
ppu.addClocks(2);
|
||||
|
||||
oamTile[n].data.byte(2) = ppu.vram[addr + 16];
|
||||
oamTile[n].data.byte(3) = ppu.vram[addr + 17];
|
||||
oamTile[n].data.bits(16,31) = ppu.vram[addr + 8];
|
||||
ppu.addClocks(2);
|
||||
}
|
||||
}
|
||||
|
@ -198,7 +196,7 @@ auto PPU::Object::reset() -> void {
|
|||
|
||||
r.baseSize = random(0);
|
||||
r.nameSelect = random(0);
|
||||
r.tiledataAddress = (random(0x0000) & 3) << 14;
|
||||
r.tiledataAddress = (random(0x0000) & 3) << 13;
|
||||
r.firstSprite = 0;
|
||||
|
||||
for(auto& p : r.priority) p = 0;
|
||||
|
|
|
@ -88,7 +88,7 @@ auto PPU::addClocks(uint clocks) -> void {
|
|||
}
|
||||
|
||||
auto PPU::power() -> void {
|
||||
for(auto& n : vram) n = random(0x00);
|
||||
for(auto& n : vram) n = random(0x0000);
|
||||
for(auto& n : oam) n = random(0x00);
|
||||
for(auto& n : cgram) n = random(0x00);
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@ struct PPU : Thread, PPUcounter {
|
|||
|
||||
//memory.cpp
|
||||
alwaysinline auto getVramAddress() -> uint16;
|
||||
alwaysinline auto vramRead(uint addr) -> uint8;
|
||||
alwaysinline auto vramWrite(uint addr, uint8 data) -> void;
|
||||
alwaysinline auto vramRead(bool chip, uint15 addr) -> uint8;
|
||||
alwaysinline auto vramWrite(bool chip, uint15 addr, uint8 data) -> void;
|
||||
alwaysinline auto oamRead(uint addr) -> uint8;
|
||||
alwaysinline auto oamWrite(uint addr, uint8 data) -> void;
|
||||
alwaysinline auto cgramRead(uint addr) -> uint8;
|
||||
|
@ -32,7 +32,7 @@ struct PPU : Thread, PPUcounter {
|
|||
auto updateVideoMode() -> void;
|
||||
|
||||
privileged:
|
||||
uint8 vram[64 * 1024];
|
||||
uint16 vram[32 * 1024];
|
||||
uint8 oam[544];
|
||||
uint8 cgram[512];
|
||||
|
||||
|
|
|
@ -11,23 +11,16 @@
|
|||
#include <processor/spc700/spc700.hpp>
|
||||
#include <processor/upd96050/upd96050.hpp>
|
||||
|
||||
namespace SuperFamicom {
|
||||
namespace Info {
|
||||
static const uint SerializerVersion = 30;
|
||||
}
|
||||
}
|
||||
|
||||
#include <libco/libco.h>
|
||||
|
||||
#if defined(SFC_SUPERGAMEBOY)
|
||||
#include <gb/gb.hpp>
|
||||
#endif
|
||||
|
||||
namespace SuperFamicom {
|
||||
struct File {
|
||||
static const vfs::file::mode Read = vfs::file::mode::read;
|
||||
static const vfs::file::mode Write = vfs::file::mode::write;
|
||||
static const bool Required = true;
|
||||
static const auto Read = vfs::file::mode::read;
|
||||
static const auto Write = vfs::file::mode::write;
|
||||
static const auto Optional = false;
|
||||
static const auto Required = true;
|
||||
};
|
||||
|
||||
struct Thread {
|
||||
|
|
|
@ -9,7 +9,7 @@ auto BSMemory::init() -> void {
|
|||
|
||||
auto BSMemory::load() -> void {
|
||||
if(memory.size() == 0) {
|
||||
memory.map(allocate<uint8>(1024 * 1024, 0xff), 1024 * 1024);
|
||||
memory.allocate(1024 * 1024);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,13 +2,14 @@ auto System::serialize() -> serializer {
|
|||
serializer s(_serializeSize);
|
||||
|
||||
uint signature = 0x31545342;
|
||||
uint version = Info::SerializerVersion;
|
||||
char version[16] = {0};
|
||||
char hash[64] = {0};
|
||||
char description[512] = {0};
|
||||
memory::copy(&version, (const char*)Emulator::SerializerVersion, Emulator::SerializerVersion.size());
|
||||
memory::copy(&hash, (const char*)cartridge.sha256(), 64);
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.array(version);
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
|
@ -18,17 +19,17 @@ auto System::serialize() -> serializer {
|
|||
|
||||
auto System::unserialize(serializer& s) -> bool {
|
||||
uint signature = 0;
|
||||
uint version = 0;
|
||||
char version[16] = {0};
|
||||
char hash[64] = {0};
|
||||
char description[512] = {0};
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.array(version);
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
if(signature != 0x31545342) return false;
|
||||
if(version != Info::SerializerVersion) return false;
|
||||
if(string{version} != Emulator::SerializerVersion) return false;
|
||||
|
||||
power();
|
||||
serializeAll(s);
|
||||
|
@ -75,12 +76,12 @@ auto System::serializeInit() -> void {
|
|||
serializer s;
|
||||
|
||||
uint signature = 0;
|
||||
uint version = 0;
|
||||
char version[16] = {0};
|
||||
char hash[64] = {0};
|
||||
char description[512] = {0};
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.array(version);
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
|
|
|
@ -12,8 +12,7 @@ auto Program::open(uint id, string name, vfs::file::mode mode, bool required) ->
|
|||
return {};
|
||||
}
|
||||
|
||||
//request from emulation core to load non-volatile media folder
|
||||
auto Program::loadRequest(uint id, string name, string type, bool required) -> void {
|
||||
auto Program::load(uint id, string name, string type, bool required) -> void {
|
||||
string location = BrowserDialog()
|
||||
.setTitle({"Load ", name})
|
||||
.setPath({settings["Library/Location"].text(), name})
|
||||
|
@ -26,41 +25,6 @@ auto Program::loadRequest(uint id, string name, string type, bool required) -> v
|
|||
emulator->load(id);
|
||||
}
|
||||
|
||||
//request from emulation core to load non-volatile media file
|
||||
auto Program::loadRequest(uint id, string filename, bool required) -> void {
|
||||
string pathname = mediumPaths(emulator->group(id));
|
||||
string location = {pathname, filename};
|
||||
|
||||
if(filename == "manifest.bml" && pathname && !pathname.endsWith(".sys/")) {
|
||||
if(!file::exists(location) || settings["Library/IgnoreManifests"].boolean()) {
|
||||
if(auto manifest = execute("icarus", "--manifest", pathname)) {
|
||||
memorystream stream{manifest.output.data<uint8_t>(), manifest.output.size()};
|
||||
return emulator->load(id, stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(file::exists(location)) {
|
||||
mmapstream stream{location};
|
||||
return emulator->load(id, stream);
|
||||
}
|
||||
|
||||
if(required) MessageDialog().setTitle("higan").setText({
|
||||
"Missing required file: ", nall::filename(location), "\n\n",
|
||||
"From location:\n", nall::pathname(location)
|
||||
}).error();
|
||||
}
|
||||
|
||||
//request from emulation core to save non-volatile media file
|
||||
auto Program::saveRequest(uint id, string filename) -> void {
|
||||
string pathname = mediumPaths(emulator->group(id));
|
||||
string location = {pathname, filename};
|
||||
if(!pathname) return; //should never occur
|
||||
|
||||
filestream stream{location, file::mode::write};
|
||||
return emulator->save(id, stream);
|
||||
}
|
||||
|
||||
auto Program::videoRefresh(const uint32* data, uint pitch, uint width, uint height) -> void {
|
||||
uint32_t* output;
|
||||
uint length;
|
||||
|
|
|
@ -8,9 +8,7 @@ struct Program : Emulator::Interface::Bind {
|
|||
//interface.cpp
|
||||
auto path(uint id) -> string override;
|
||||
auto open(uint id, string name, vfs::file::mode mode, bool required) -> vfs::shared::file override;
|
||||
auto loadRequest(uint id, string name, string type, bool required) -> void override;
|
||||
auto loadRequest(uint id, string path, bool required) -> void override;
|
||||
auto saveRequest(uint id, string path) -> void override;
|
||||
auto load(uint id, string name, string type, bool required) -> void override;
|
||||
auto videoRefresh(const uint32* data, uint pitch, uint width, uint height) -> void override;
|
||||
auto audioSample(const double* samples, uint channels) -> void override;
|
||||
auto inputPoll(uint port, uint device, uint input) -> int16 override;
|
||||
|
|
|
@ -41,12 +41,17 @@ auto Cartridge::power() -> void {
|
|||
r.sramBank = 0xff;
|
||||
}
|
||||
|
||||
auto Cartridge::load() -> void {
|
||||
information.manifest = "";
|
||||
information.title = "";
|
||||
information.sha256 = "";
|
||||
auto Cartridge::mode() const -> uint {
|
||||
return system.model() == Model::WonderSwan ? ID::WonderSwan : ID::WonderSwanColor;
|
||||
}
|
||||
|
||||
auto Cartridge::load() -> bool {
|
||||
information = Information();
|
||||
|
||||
if(auto fp = interface->open(mode(), "manifest.bml", File::Read, File::Required)) {
|
||||
information.manifest = fp->reads();
|
||||
} else return false;
|
||||
|
||||
interface->loadRequest(ID::Manifest, "manifest.bml", true);
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
|
||||
if(auto node = document["board/rom"]) {
|
||||
|
@ -56,7 +61,9 @@ auto Cartridge::load() -> void {
|
|||
if(rom.size) {
|
||||
rom.data = new uint8[rom.mask + 1];
|
||||
memory::fill(rom.data, rom.mask + 1, 0xff);
|
||||
if(rom.name) interface->loadRequest(ID::ROM, rom.name, true);
|
||||
if(rom.name) if(auto fp = interface->open(mode(), rom.name, File::Read, File::Required)) {
|
||||
fp->read(rom.data, rom.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,7 +75,9 @@ auto Cartridge::load() -> void {
|
|||
if(ram.size) {
|
||||
ram.data = new uint8[ram.mask + 1];
|
||||
memory::fill(ram.data, ram.mask + 1, 0xff);
|
||||
if(ram.name) interface->loadRequest(ID::RAM, ram.name, false);
|
||||
if(ram.name) if(auto fp = interface->open(mode(), ram.name, File::Read)) {
|
||||
fp->read(ram.data, ram.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,7 +86,9 @@ auto Cartridge::load() -> void {
|
|||
eeprom.setSize(node["size"].natural() / sizeof(uint16));
|
||||
if(eeprom.size()) {
|
||||
eeprom.erase();
|
||||
if(eeprom.name()) interface->loadRequest(ID::EEPROM, eeprom.name(), false);
|
||||
if(eeprom.name()) if(auto fp = interface->open(mode(), eeprom.name(), File::Read)) {
|
||||
fp->read(eeprom.data(), eeprom.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -89,13 +100,38 @@ auto Cartridge::load() -> void {
|
|||
if(rtc.size) {
|
||||
rtc.data = new uint8[rtc.mask + 1];
|
||||
memory::fill(rtc.data, rtc.mask + 1, 0x00);
|
||||
if(rtc.name) interface->loadRequest(ID::RTC, rtc.name, false);
|
||||
if(rtc.name) if(auto fp = interface->open(mode(), rtc.name, File::Read)) {
|
||||
fp->read(rtc.data, rtc.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
information.title = document["information/title"].text();
|
||||
information.orientation = document["information/orientation"].text() == "vertical";
|
||||
information.sha256 = Hash::SHA256(rom.data, rom.size).digest();
|
||||
return true;
|
||||
}
|
||||
|
||||
auto Cartridge::save() -> void {
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
|
||||
if(auto name = document["board/ram/name"].text()) {
|
||||
if(auto fp = interface->open(mode(), name, File::Write)) {
|
||||
fp->write(ram.data, ram.size);
|
||||
}
|
||||
}
|
||||
|
||||
if(auto name = document["board/eeprom/name"].text()) {
|
||||
if(auto fp = interface->open(mode(), name, File::Write)) {
|
||||
fp->write(eeprom.data(), eeprom.size());
|
||||
}
|
||||
}
|
||||
|
||||
if(auto name = document["board/rtc/name"].text()) {
|
||||
if(auto fp = interface->open(mode(), name, File::Write)) {
|
||||
fp->write(rtc.data, rtc.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Cartridge::unload() -> void {
|
||||
|
|
|
@ -4,7 +4,9 @@ struct Cartridge : Thread, IO {
|
|||
auto step(uint clocks) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
auto load() -> void;
|
||||
auto mode() const -> uint;
|
||||
auto load() -> bool;
|
||||
auto save() -> void;
|
||||
auto unload() -> void;
|
||||
|
||||
//memory.cpp
|
||||
|
@ -32,10 +34,10 @@ struct Cartridge : Thread, IO {
|
|||
auto serialize(serializer&) -> void;
|
||||
|
||||
struct Information {
|
||||
string sha256;
|
||||
string manifest;
|
||||
string title;
|
||||
bool orientation; //0 = horizontal; 1 = vertical
|
||||
string sha256;
|
||||
} information;
|
||||
|
||||
struct Registers {
|
||||
|
|
|
@ -107,88 +107,13 @@ auto Interface::sha256() -> string {
|
|||
return cartridge.information.sha256;
|
||||
}
|
||||
|
||||
auto Interface::group(uint id) -> uint {
|
||||
switch(id) {
|
||||
case ID::SystemManifest:
|
||||
case ID::SystemIPLROM:
|
||||
case ID::SystemEEPROM:
|
||||
return 0;
|
||||
case ID::Manifest:
|
||||
case ID::ROM:
|
||||
case ID::RAM:
|
||||
case ID::EEPROM:
|
||||
case ID::RTC:
|
||||
switch(system.model()) {
|
||||
case Model::WonderSwan:
|
||||
return ID::WonderSwan;
|
||||
case Model::WonderSwanColor:
|
||||
case Model::SwanCrystal:
|
||||
return ID::WonderSwanColor;
|
||||
}
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
auto Interface::load(uint id) -> void {
|
||||
if(id == ID::WonderSwan) system.load(Model::WonderSwan);
|
||||
if(id == ID::WonderSwanColor) system.load(Model::WonderSwanColor);
|
||||
}
|
||||
|
||||
auto Interface::save() -> void {
|
||||
if(auto name = system.eeprom.name()) interface->saveRequest(ID::SystemEEPROM, name);
|
||||
if(auto name = cartridge.ram.name) interface->saveRequest(ID::RAM, name);
|
||||
if(auto name = cartridge.eeprom.name()) interface->saveRequest(ID::EEPROM, name);
|
||||
if(auto name = cartridge.rtc.name) interface->saveRequest(ID::RTC, name);
|
||||
}
|
||||
|
||||
auto Interface::load(uint id, const stream& stream) -> void {
|
||||
if(id == ID::SystemManifest) {
|
||||
system.information.manifest = stream.text();
|
||||
}
|
||||
|
||||
if(id == ID::SystemEEPROM) {
|
||||
stream.read((uint8_t*)system.eeprom.data(), min(system.eeprom.size() * sizeof(uint16), stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::Manifest) {
|
||||
cartridge.information.manifest = stream.text();
|
||||
}
|
||||
|
||||
if(id == ID::ROM) {
|
||||
stream.read((uint8_t*)cartridge.rom.data, min(cartridge.rom.size, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::RAM) {
|
||||
stream.read((uint8_t*)cartridge.ram.data, min(cartridge.ram.size, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::EEPROM) {
|
||||
stream.read((uint8_t*)cartridge.eeprom.data(), min(cartridge.eeprom.size() * sizeof(uint16), stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::RTC) {
|
||||
stream.read((uint8_t*)cartridge.rtc.data, min(cartridge.rtc.size, stream.size()));
|
||||
cartridge.rtcLoad();
|
||||
}
|
||||
}
|
||||
|
||||
auto Interface::save(uint id, const stream& stream) -> void {
|
||||
if(id == ID::SystemEEPROM) {
|
||||
stream.write((uint8_t*)system.eeprom.data(), system.eeprom.size() * sizeof(uint16));
|
||||
}
|
||||
|
||||
if(id == ID::RAM) {
|
||||
stream.write((uint8_t*)cartridge.ram.data, cartridge.ram.size);
|
||||
}
|
||||
|
||||
if(id == ID::EEPROM) {
|
||||
stream.write((uint8_t*)cartridge.eeprom.data(), cartridge.eeprom.size() * sizeof(uint16));
|
||||
}
|
||||
|
||||
if(id == ID::RTC) {
|
||||
cartridge.rtcSave();
|
||||
stream.write((uint8_t*)cartridge.rtc.data, cartridge.rtc.size);
|
||||
}
|
||||
system.save();
|
||||
}
|
||||
|
||||
auto Interface::unload() -> void {
|
||||
|
|
|
@ -37,11 +37,8 @@ struct Interface : Emulator::Interface {
|
|||
|
||||
auto loaded() -> bool override;
|
||||
auto sha256() -> string override;
|
||||
auto group(uint id) -> uint override;
|
||||
auto load(uint id) -> void override;
|
||||
auto save() -> void override;
|
||||
auto load(uint id, const stream& stream) -> void override;
|
||||
auto save(uint id, const stream& stream) -> void override;
|
||||
auto unload() -> void override;
|
||||
|
||||
auto power() -> void override;
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
auto System::serializeInit() -> void {
|
||||
serializer s;
|
||||
|
||||
uint signature = 0, version = 0;
|
||||
char hash[64], description[512];
|
||||
uint signature = 0;
|
||||
char version[16] = {0};
|
||||
char hash[64] = {0};
|
||||
char description[512] = {0};
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.array(version);
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
|
@ -16,13 +18,15 @@ auto System::serializeInit() -> void {
|
|||
auto System::serialize() -> serializer {
|
||||
serializer s(_serializeSize);
|
||||
|
||||
uint signature = 0x31545342, version = Info::SerializerVersion;
|
||||
char hash[64], description[512];
|
||||
uint signature = 0x31545342;
|
||||
char version[16] = {0};
|
||||
char hash[64] = {0};
|
||||
char description[512] = {0};
|
||||
memory::copy(&version, (const char*)Emulator::SerializerVersion, Emulator::SerializerVersion.size());
|
||||
memory::copy(&hash, (const char*)cartridge.information.sha256, 64);
|
||||
memory::fill(&description, 512);
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.array(version);
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
|
@ -31,16 +35,18 @@ auto System::serialize() -> serializer {
|
|||
}
|
||||
|
||||
auto System::unserialize(serializer& s) -> bool {
|
||||
uint signature, version;
|
||||
char hash[64], description[512];
|
||||
uint signature = 0;
|
||||
char version[16] = {0};
|
||||
char hash[64] = {0};
|
||||
char description[512] = {0};
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.array(version);
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
if(signature != 0x31545342) return false;
|
||||
if(version != Info::SerializerVersion) return false;
|
||||
if(string{version} != Emulator::SerializerVersion) return false;
|
||||
|
||||
power();
|
||||
serializeAll(s);
|
||||
|
|
|
@ -7,14 +7,6 @@ System system;
|
|||
#include "video.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto System::loaded() const -> bool { return _loaded; }
|
||||
auto System::model() const -> Model { return _model; }
|
||||
auto System::orientation() const -> bool { return _orientation; }
|
||||
auto System::color() const -> bool { return r.color; }
|
||||
auto System::planar() const -> bool { return r.format == 0; }
|
||||
auto System::packed() const -> bool { return r.format == 1; }
|
||||
auto System::depth() const -> bool { return r.color && r.depth == 1; }
|
||||
|
||||
auto System::init() -> void {
|
||||
assert(interface != nullptr);
|
||||
}
|
||||
|
@ -22,10 +14,13 @@ auto System::init() -> void {
|
|||
auto System::term() -> void {
|
||||
}
|
||||
|
||||
auto System::load(Model model) -> void {
|
||||
auto System::load(Model model) -> bool {
|
||||
_model = model;
|
||||
|
||||
interface->loadRequest(ID::SystemManifest, "manifest.bml", true);
|
||||
if(auto fp = interface->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
||||
information.manifest = fp->reads();
|
||||
} else return false;
|
||||
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
|
||||
//note: IPLROM is currently undumped; otherwise we'd load it here ...
|
||||
|
@ -36,13 +31,21 @@ auto System::load(Model model) -> void {
|
|||
eeprom.erase();
|
||||
//initialize user-data section
|
||||
for(uint addr = 0x0030; addr <= 0x003a; addr++) eeprom[addr] = 0x0000;
|
||||
interface->loadRequest(ID::SystemEEPROM, eeprom.name(), false);
|
||||
if(auto fp = interface->open(ID::System, eeprom.name(), File::Read)) {
|
||||
fp->read(eeprom.data(), eeprom.size());
|
||||
}
|
||||
}
|
||||
|
||||
cartridge.load();
|
||||
serializeInit();
|
||||
_orientation = cartridge.information.orientation;
|
||||
_loaded = true;
|
||||
return _loaded = true;
|
||||
}
|
||||
|
||||
auto System::save() -> void {
|
||||
if(!loaded()) return;
|
||||
|
||||
cartridge.save();
|
||||
}
|
||||
|
||||
auto System::unload() -> void {
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
struct System : IO {
|
||||
auto loaded() const -> bool;
|
||||
auto model() const -> Model;
|
||||
auto orientation() const -> bool;
|
||||
auto color() const -> bool;
|
||||
auto planar() const -> bool;
|
||||
auto packed() const -> bool;
|
||||
auto depth() const -> bool;
|
||||
auto loaded() const -> bool { return _loaded; }
|
||||
auto model() const -> Model { return _model; }
|
||||
auto orientation() const -> bool { return _orientation; }
|
||||
auto color() const -> bool { return r.color; }
|
||||
auto planar() const -> bool { return r.format == 0; }
|
||||
auto packed() const -> bool { return r.format == 1; }
|
||||
auto depth() const -> bool { return r.color && r.depth == 1; }
|
||||
|
||||
auto init() -> void;
|
||||
auto term() -> void;
|
||||
auto load(Model) -> void;
|
||||
auto load(Model) -> bool;
|
||||
auto save() -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
auto run() -> void;
|
||||
|
|
|
@ -6,14 +6,6 @@
|
|||
#include <emulator/emulator.hpp>
|
||||
#include <processor/v30mz/v30mz.hpp>
|
||||
|
||||
namespace WonderSwan {
|
||||
namespace Info {
|
||||
static const uint SerializerVersion = 2;
|
||||
}
|
||||
}
|
||||
|
||||
#include <libco/libco.h>
|
||||
|
||||
namespace WonderSwan {
|
||||
enum class Model : uint {
|
||||
WonderSwan, //SW-001 (ASWAN)
|
||||
|
@ -23,6 +15,13 @@ namespace WonderSwan {
|
|||
|
||||
enum : uint { Byte = 1, Word = 2, Long = 4 };
|
||||
|
||||
struct File {
|
||||
static const auto Read = vfs::file::mode::read;
|
||||
static const auto Write = vfs::file::mode::write;
|
||||
static const auto Optional = false;
|
||||
static const auto Required = true;
|
||||
};
|
||||
|
||||
struct Thread {
|
||||
~Thread() {
|
||||
if(thread) co_delete(thread);
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include <nall/utility.hpp>
|
||||
#include <nall/varint.hpp>
|
||||
#include <nall/hash/sha256.hpp>
|
||||
#include <nall/stream/memory.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
#include <nall/shared-pointer.hpp>
|
||||
#include <nall/sort.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/stream.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/thread.hpp>
|
||||
#include <nall/traits.hpp>
|
||||
|
|
|
@ -215,6 +215,9 @@ private:
|
|||
}
|
||||
|
||||
using boolean = nall::Boolean;
|
||||
//note: these conflict with nall/atoi.hpp functions
|
||||
//using integer = nall::Integer<sizeof( int) * 8>;
|
||||
//using natural = nall::Natural<sizeof(uint) * 8>;
|
||||
|
||||
using int1 = nall::Integer< 1>;
|
||||
using int2 = nall::Integer< 2>;
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/filemap.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/decode/gzip.hpp>
|
||||
#include <nall/decode/zip.hpp>
|
||||
|
||||
#include <nall/stream/stream.hpp>
|
||||
#include <nall/stream/memory.hpp>
|
||||
#include <nall/stream/mmap.hpp>
|
||||
#include <nall/stream/file.hpp>
|
||||
#include <nall/stream/gzip.hpp>
|
||||
#include <nall/stream/zip.hpp>
|
||||
#include <nall/stream/auto.hpp>
|
|
@ -1,21 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace nall {
|
||||
|
||||
#define autostream(...) (*makestream(__VA_ARGS__))
|
||||
|
||||
inline auto makestream(const string& path) -> std::unique_ptr<stream> {
|
||||
if(path.iendsWith(".gz")) return std::unique_ptr<stream>(new gzipstream(filestream{path}));
|
||||
if(path.iendsWith(".zip")) return std::unique_ptr<stream>(new zipstream(filestream{path}));
|
||||
return std::unique_ptr<stream>(new mmapstream(path));
|
||||
}
|
||||
|
||||
inline auto makestream(uint8_t* data, uint size) -> std::unique_ptr<stream> {
|
||||
return std::unique_ptr<stream>(new memorystream(data, size));
|
||||
}
|
||||
|
||||
inline auto makestream(const uint8_t* data, uint size) -> std::unique_ptr<stream> {
|
||||
return std::unique_ptr<stream>(new memorystream(data, size));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <nall/file.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct filestream : stream {
|
||||
using stream::read;
|
||||
using stream::write;
|
||||
|
||||
filestream(const string& filename) {
|
||||
pfile.open(filename, file::mode::readwrite);
|
||||
pwritable = pfile.open();
|
||||
if(!pwritable) pfile.open(filename, file::mode::read);
|
||||
}
|
||||
|
||||
filestream(const string& filename, file::mode mode) {
|
||||
pfile.open(filename, mode);
|
||||
pwritable = mode == file::mode::write || mode == file::mode::readwrite;
|
||||
}
|
||||
|
||||
auto seekable() const -> bool { return true; }
|
||||
auto readable() const -> bool { return true; }
|
||||
auto writable() const -> bool { return pwritable; }
|
||||
auto randomaccess() const -> bool { return false; }
|
||||
|
||||
auto size() const -> uint { return pfile.size(); }
|
||||
auto offset() const -> uint { return pfile.offset(); }
|
||||
auto seek(uint offset) const -> void { pfile.seek(offset); }
|
||||
|
||||
auto read() const -> uint8_t { return pfile.read(); }
|
||||
auto write(uint8_t data) const -> void { pfile.write(data); }
|
||||
|
||||
private:
|
||||
mutable file pfile;
|
||||
bool pwritable;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <nall/decode/gzip.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct gzipstream : memorystream {
|
||||
using stream::read;
|
||||
using stream::write;
|
||||
|
||||
gzipstream(const stream& stream) {
|
||||
uint size = stream.size();
|
||||
auto data = new uint8_t[size];
|
||||
stream.read(data, size);
|
||||
|
||||
Decode::GZIP archive;
|
||||
bool result = archive.decompress(data, size);
|
||||
delete[] data;
|
||||
if(!result) return;
|
||||
|
||||
psize = archive.size;
|
||||
pdata = new uint8_t[psize];
|
||||
memcpy(pdata, archive.data, psize);
|
||||
}
|
||||
|
||||
~gzipstream() {
|
||||
if(pdata) delete[] pdata;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <nall/stream/stream.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct memorystream : stream {
|
||||
using stream::read;
|
||||
using stream::write;
|
||||
|
||||
memorystream() = default;
|
||||
|
||||
memorystream(uint8_t* data, uint size) {
|
||||
pdata = data;
|
||||
psize = size;
|
||||
pwritable = true;
|
||||
}
|
||||
|
||||
memorystream(const uint8_t* data, uint size) {
|
||||
pdata = (uint8_t*)data;
|
||||
psize = size;
|
||||
pwritable = false;
|
||||
}
|
||||
|
||||
auto seekable() const -> bool { return true; }
|
||||
auto readable() const -> bool { return true; }
|
||||
auto writable() const -> bool { return pwritable; }
|
||||
auto randomaccess() const -> bool { return true; }
|
||||
|
||||
auto data() const -> uint8_t* { return pdata; }
|
||||
auto size() const -> uint { return psize; }
|
||||
auto offset() const -> uint { return poffset; }
|
||||
auto seek(uint offset) const -> void { poffset = offset; }
|
||||
|
||||
auto read() const -> uint8_t { return pdata[poffset++]; }
|
||||
auto write(uint8_t data) const -> void { pdata[poffset++] = data; }
|
||||
|
||||
auto read(uint offset) const -> uint8_t { return pdata[offset]; }
|
||||
auto write(uint offset, uint8_t data) const -> void { pdata[offset] = data; }
|
||||
|
||||
protected:
|
||||
mutable uint8_t* pdata = nullptr;
|
||||
mutable uint psize = 0;
|
||||
mutable uint poffset = 0;
|
||||
mutable bool pwritable = false;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <nall/filemap.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct mmapstream : stream {
|
||||
using stream::read;
|
||||
using stream::write;
|
||||
|
||||
mmapstream(const string& filename) {
|
||||
pmmap.open(filename, filemap::mode::readwrite);
|
||||
pwritable = pmmap.open();
|
||||
if(!pwritable) pmmap.open(filename, filemap::mode::read);
|
||||
pdata = pmmap.data();
|
||||
poffset = 0;
|
||||
}
|
||||
|
||||
auto seekable() const -> bool { return true; }
|
||||
auto readable() const -> bool { return true; }
|
||||
auto writable() const -> bool { return pwritable; }
|
||||
auto randomaccess() const -> bool { return true; }
|
||||
|
||||
auto size() const -> uint { return pmmap.size(); }
|
||||
auto offset() const -> uint { return poffset; }
|
||||
auto seek(uint offset) const -> void { poffset = offset; }
|
||||
|
||||
auto read() const -> uint8_t { return pdata[poffset++]; }
|
||||
auto write(uint8_t data) const -> void { pdata[poffset++] = data; }
|
||||
|
||||
auto read(uint offset) const -> uint8_t { return pdata[offset]; }
|
||||
auto write(uint offset, uint8_t data) const -> void { pdata[offset] = data; }
|
||||
|
||||
private:
|
||||
mutable filemap pmmap;
|
||||
mutable uint8_t* pdata = nullptr;
|
||||
mutable uint poffset = 0;
|
||||
mutable bool pwritable = false;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct stream {
|
||||
stream() = default;
|
||||
virtual ~stream() = default;
|
||||
|
||||
stream(const stream&) = delete;
|
||||
auto operator=(const stream&) -> stream& = delete;
|
||||
|
||||
virtual auto seekable() const -> bool = 0;
|
||||
virtual auto readable() const -> bool = 0;
|
||||
virtual auto writable() const -> bool = 0;
|
||||
virtual auto randomaccess() const -> bool = 0;
|
||||
|
||||
virtual auto data() const -> uint8_t* { return nullptr; }
|
||||
virtual auto size() const -> uint = 0;
|
||||
virtual auto offset() const -> uint = 0;
|
||||
virtual auto seek(uint offset) const -> void = 0;
|
||||
|
||||
virtual auto read() const -> uint8_t = 0;
|
||||
virtual auto write(uint8_t data) const -> void = 0;
|
||||
|
||||
virtual auto read(uint) const -> uint8_t { return 0; }
|
||||
virtual auto write(uint, uint8_t) const -> void {}
|
||||
|
||||
explicit operator bool() const {
|
||||
return size();
|
||||
}
|
||||
|
||||
auto end() const -> bool {
|
||||
return offset() >= size();
|
||||
}
|
||||
|
||||
auto readl(uint length = 1) const -> uintmax {
|
||||
uintmax data = 0, shift = 0;
|
||||
while(length--) { data |= read() << shift; shift += 8; }
|
||||
return data;
|
||||
}
|
||||
|
||||
auto readm(uint length = 1) const -> uintmax {
|
||||
uintmax data = 0;
|
||||
while(length--) data = (data << 8) | read();
|
||||
return data;
|
||||
}
|
||||
|
||||
auto read(uint8_t* data, uint length) const -> void {
|
||||
while(length--) *data++ = read();
|
||||
}
|
||||
|
||||
auto text() const -> string {
|
||||
string buffer;
|
||||
buffer.resize(size());
|
||||
seek(0);
|
||||
read((uint8_t*)buffer.get(), size());
|
||||
return buffer;
|
||||
}
|
||||
|
||||
auto writel(uintmax data, uint length = 1) const -> void {
|
||||
while(length--) {
|
||||
write(data);
|
||||
data >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
auto writem(uintmax data, uint length = 1) const -> void {
|
||||
uintmax shift = 8 * length;
|
||||
while(length--) {
|
||||
shift -= 8;
|
||||
write(data >> shift);
|
||||
}
|
||||
}
|
||||
|
||||
auto write(const uint8_t* data, uint length) const -> void {
|
||||
while(length--) write(*data++);
|
||||
}
|
||||
|
||||
struct byte {
|
||||
byte(const stream& s, uint offset) : s(s), offset(offset) {}
|
||||
operator uint8_t() const { return s.read(offset); }
|
||||
auto operator=(uint8_t data) -> byte& { s.write(offset, data); return *this; }
|
||||
|
||||
private:
|
||||
const stream& s;
|
||||
const uint offset;
|
||||
};
|
||||
|
||||
auto operator[](uint offset) const -> byte {
|
||||
return byte(*this, offset);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <nall/stream/stream.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct vectorstream : stream {
|
||||
using stream::read;
|
||||
using stream::write;
|
||||
|
||||
vectorstream(vector<uint8_t>& memory) : memory(memory), pwritable(true) {}
|
||||
vectorstream(const vector<uint8_t>& memory) : memory((vector<uint8_t>&)memory), pwritable(false) {}
|
||||
|
||||
auto seekable() const -> bool { return true; }
|
||||
auto readable() const -> bool { return true; }
|
||||
auto writable() const -> bool { return pwritable; }
|
||||
auto randomaccess() const -> bool { return true; }
|
||||
|
||||
auto data() const -> uint8_t* { return memory.data(); }
|
||||
auto size() const -> uint { return memory.size(); }
|
||||
auto offset() const -> uint { return poffset; }
|
||||
auto seek(uint offset) const -> void { poffset = offset; }
|
||||
|
||||
auto read() const -> uint8_t { return memory[poffset++]; }
|
||||
auto write(uint8_t data) const -> void { memory[poffset++] = data; }
|
||||
|
||||
auto read(uint offset) const -> uint8_t { return memory[offset]; }
|
||||
auto write(uint offset, uint8_t data) const -> void { memory[offset] = data; }
|
||||
|
||||
protected:
|
||||
vector<uint8_t>& memory;
|
||||
mutable uint poffset = 0;
|
||||
mutable bool pwritable = false;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <nall/decode/zip.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct zipstream : memorystream {
|
||||
using stream::read;
|
||||
using stream::write;
|
||||
|
||||
zipstream(const stream& stream, const string& filter = "*") {
|
||||
uint size = stream.size();
|
||||
auto data = new uint8_t[size];
|
||||
stream.read(data, size);
|
||||
|
||||
Decode::ZIP archive;
|
||||
if(archive.open(data, size) == false) return;
|
||||
delete[] data;
|
||||
|
||||
for(auto& file : archive.file) {
|
||||
if(file.name.match(filter)) {
|
||||
auto buffer = archive.extract(file);
|
||||
psize = buffer.size();
|
||||
pdata = buffer.release();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~zipstream() {
|
||||
if(pdata) delete[] pdata;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
Loading…
Reference in New Issue