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:
Tim Allen 2016-06-24 22:09:30 +10:00
parent 875f031182
commit ccd8878d75
65 changed files with 534 additions and 1177 deletions

View File

@ -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"

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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 {

View File

@ -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;

View File

@ -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);

View File

@ -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 {

View File

@ -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;

View File

@ -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);

View File

@ -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 {

View File

@ -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;

View File

@ -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 {

View File

@ -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;

View File

@ -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);

View File

@ -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 {

View File

@ -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;

View File

@ -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);

View File

@ -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 {

View File

@ -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;

View File

@ -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;

View File

@ -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());
}
}

View File

@ -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();
}

View File

@ -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;

View File

@ -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 {
}

View File

@ -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();

View File

@ -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;

View File

@ -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; }

View File

@ -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*;

View File

@ -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];
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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];

View File

@ -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 {

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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;

View File

@ -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);

View File

@ -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 {

View File

@ -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;

View File

@ -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);

View File

@ -7,7 +7,6 @@
#include <nall/utility.hpp>
#include <nall/varint.hpp>
#include <nall/hash/sha256.hpp>
#include <nall/stream/memory.hpp>
namespace nall {

View File

@ -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>

View File

@ -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>;

View File

@ -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>

View File

@ -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));
}
}

View File

@ -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;
};
}

View File

@ -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;
}
};
}

View File

@ -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;
};
}

View File

@ -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;
};
}

View File

@ -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);
}
};
}

View File

@ -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;
};
}

View File

@ -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;
}
};
}