Update to v097r12 release.

byuu says:

Nothing WS-related this time.

First, I fixed expansion port device mapping. On first load, it was
mapping the expansion port device too late, so it ended up not taking
effect. I had to spin out the logic for that into
Program::connectDevices(). This was proving to be quite annoying while
testing eBoot (SNES-Hook simulation.)

Second, I fixed the audio->set(Frequency, Latency) functions to take
(uint) parameters from the configuration file, so the weird behavior
around changing settings in the audio panel should hopefully be gone
now.

Third, I rewrote the interface->load,unload functions to call into the
(Emulator)::System::load,unload functions. And I have those call out to
Cartridge::load,unload. Before, this was inverted, and Cartridge::load()
was invoking System::load(), which I felt was kind of backward.

The Super Game Boy really didn't like this change, however. And it took
me a few hours to power through it. Before, I had the Game Boy core
dummying out all the interface->(load,save)Request calls, and having the
SNES core make them for it. This is because the folder paths and IDs
will be different between the two cores.

I've redesigned things so that ICD2's Emulator::Interface overloads
loadRequest and saveRequest, and translates the requests into new
requests for the SuperFamicom core. This allows the Game Boy code to do
its own loading for everything without a bunch of Super Game Boy special
casing, and without any awkwardness around powering on with no cartridge
inserted.

This also lets the SNES side of things simply call into higher-level
GameBoy::interface->load,save(id, stream) functions instead of stabbing
at the raw underlying state inside of various Game Boy core emulation
classes. So things are a lot better abstracted now.
This commit is contained in:
Tim Allen 2016-02-08 14:17:59 +11:00
parent a89a3da77a
commit 32a95a9761
48 changed files with 311 additions and 290 deletions

View File

@ -6,7 +6,7 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "higan"; static const string Name = "higan";
static const string Version = "097.11"; static const string Version = "097.12";
static const string Author = "byuu"; static const string Author = "byuu";
static const string License = "GPLv3"; static const string License = "GPLv3";
static const string Website = "http://byuu.org/"; static const string Website = "http://byuu.org/";

View File

@ -6,10 +6,6 @@ namespace Famicom {
#include "board/board.cpp" #include "board/board.cpp"
Cartridge cartridge; Cartridge cartridge;
auto Cartridge::loaded() const -> bool {
return _loaded;
}
auto Cartridge::sha256() const -> string { auto Cartridge::sha256() const -> string {
return _sha256; return _sha256;
} }
@ -40,14 +36,9 @@ auto Cartridge::load() -> void {
sha.data(board->prgrom.data, board->prgrom.size); sha.data(board->prgrom.data, board->prgrom.size);
sha.data(board->chrrom.data, board->chrrom.size); sha.data(board->chrrom.data, board->chrrom.size);
_sha256 = sha.digest(); _sha256 = sha.digest();
system.load();
_loaded = true;
} }
auto Cartridge::unload() -> void { auto Cartridge::unload() -> void {
if(!loaded()) return;
_loaded = false;
memory.reset(); memory.reset();
} }

View File

@ -5,7 +5,6 @@ struct Cartridge : Thread {
static auto Main() -> void; static auto Main() -> void;
auto main() -> void; auto main() -> void;
auto loaded() const -> bool;
auto sha256() const -> string; auto sha256() const -> string;
auto manifest() const -> string; auto manifest() const -> string;
auto title() const -> string; auto title() const -> string;
@ -31,7 +30,6 @@ struct Cartridge : Thread {
//privileged: //privileged:
Board* board = nullptr; Board* board = nullptr;
bool _loaded = false;
string _sha256; string _sha256;
auto prg_read(uint addr) -> uint8; auto prg_read(uint addr) -> uint8;

View File

@ -63,7 +63,7 @@ auto Interface::audioFrequency() -> double {
} }
auto Interface::loaded() -> bool { auto Interface::loaded() -> bool {
return cartridge.loaded(); return system.loaded();
} }
auto Interface::sha256() -> string { auto Interface::sha256() -> string {
@ -86,7 +86,7 @@ auto Interface::group(uint id) -> uint {
} }
auto Interface::load(uint id) -> void { auto Interface::load(uint id) -> void {
cartridge.load(); system.load();
} }
auto Interface::save() -> void { auto Interface::save() -> void {
@ -133,7 +133,7 @@ auto Interface::save(uint id, const stream& stream) -> void {
auto Interface::unload() -> void { auto Interface::unload() -> void {
save(); save();
cartridge.unload(); system.unload();
} }
auto Interface::power() -> void { auto Interface::power() -> void {
@ -149,7 +149,7 @@ auto Interface::run() -> void {
} }
auto Interface::serialize() -> serializer { auto Interface::serialize() -> serializer {
system.runtosave(); system.runToSave();
return system.serialize(); return system.serialize();
} }

View File

@ -1,5 +1,5 @@
auto System::serialize() -> serializer { auto System::serialize() -> serializer {
serializer s(serialize_size); serializer s(_serializeSize);
uint signature = 0x31545342, version = Info::SerializerVersion; uint signature = 0x31545342, version = Info::SerializerVersion;
char hash[64], description[512]; char hash[64], description[512];
@ -11,7 +11,7 @@ auto System::serialize() -> serializer {
s.array(hash); s.array(hash);
s.array(description); s.array(description);
serialize_all(s); serializeAll(s);
return s; return s;
} }
@ -28,14 +28,14 @@ auto System::unserialize(serializer& s) -> bool {
if(version != Info::SerializerVersion) return false; if(version != Info::SerializerVersion) return false;
power(); power();
serialize_all(s); serializeAll(s);
return true; return true;
} }
auto System::serialize(serializer& s) -> void { auto System::serialize(serializer& s) -> void {
} }
auto System::serialize_all(serializer& s) -> void { auto System::serializeAll(serializer& s) -> void {
system.serialize(s); system.serialize(s);
input.serialize(s); input.serialize(s);
cartridge.serialize(s); cartridge.serialize(s);
@ -44,7 +44,7 @@ auto System::serialize_all(serializer& s) -> void {
ppu.serialize(s); ppu.serialize(s);
} }
auto System::serialize_init() -> void { auto System::serializeInit() -> void {
serializer s; serializer s;
uint signature = 0, version = 0; uint signature = 0, version = 0;
@ -55,6 +55,6 @@ auto System::serialize_init() -> void {
s.array(hash); s.array(hash);
s.array(description); s.array(description);
serialize_all(s); serializeAll(s);
serialize_size = s.size(); _serializeSize = s.size();
} }

View File

@ -5,6 +5,8 @@ namespace Famicom {
#include "serialization.cpp" #include "serialization.cpp"
System system; System system;
auto System::loaded() const -> bool { return _loaded; }
auto System::run() -> void { auto System::run() -> void {
scheduler.enter(); scheduler.enter();
if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) { if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) {
@ -12,26 +14,26 @@ auto System::run() -> void {
} }
} }
auto System::runtosave() -> void { auto System::runToSave() -> void {
scheduler.sync = Scheduler::SynchronizeMode::PPU; scheduler.sync = Scheduler::SynchronizeMode::PPU;
runthreadtosave(); runThreadToSave();
scheduler.sync = Scheduler::SynchronizeMode::All; scheduler.sync = Scheduler::SynchronizeMode::All;
scheduler.thread = cpu.thread; scheduler.thread = cpu.thread;
runthreadtosave(); runThreadToSave();
scheduler.sync = Scheduler::SynchronizeMode::All; scheduler.sync = Scheduler::SynchronizeMode::All;
scheduler.thread = apu.thread; scheduler.thread = apu.thread;
runthreadtosave(); runThreadToSave();
scheduler.sync = Scheduler::SynchronizeMode::All; scheduler.sync = Scheduler::SynchronizeMode::All;
scheduler.thread = cartridge.thread; scheduler.thread = cartridge.thread;
runthreadtosave(); runThreadToSave();
scheduler.sync = Scheduler::SynchronizeMode::None; scheduler.sync = Scheduler::SynchronizeMode::None;
} }
auto System::runthreadtosave() -> void { auto System::runThreadToSave() -> void {
while(true) { while(true) {
scheduler.enter(); scheduler.enter();
if(scheduler.exit_reason() == Scheduler::ExitReason::SynchronizeEvent) break; if(scheduler.exit_reason() == Scheduler::ExitReason::SynchronizeEvent) break;
@ -44,8 +46,15 @@ auto System::runthreadtosave() -> void {
auto System::load() -> void { auto System::load() -> void {
interface->loadRequest(ID::SystemManifest, "manifest.bml", true); interface->loadRequest(ID::SystemManifest, "manifest.bml", true);
auto document = BML::unserialize(information.manifest); auto document = BML::unserialize(information.manifest);
cartridge.load();
serializeInit();
_loaded = true;
}
serialize_init(); auto System::unload() -> void {
if(!loaded()) return;
cartridge.unload();
_loaded = false;
} }
auto System::power() -> void { auto System::power() -> void {

View File

@ -1,9 +1,12 @@
struct System { struct System {
auto loaded() const -> bool;
auto run() -> void; auto run() -> void;
auto runtosave() -> void; auto runToSave() -> void;
auto runthreadtosave() -> void; auto runThreadToSave() -> void;
auto load() -> void; auto load() -> void;
auto unload() -> void;
auto power() -> void; auto power() -> void;
auto reset() -> void; auto reset() -> void;
@ -14,14 +17,16 @@ struct System {
auto unserialize(serializer&) -> bool; auto unserialize(serializer&) -> bool;
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
auto serialize_all(serializer&) -> void; auto serializeAll(serializer&) -> void;
auto serialize_init() -> void; auto serializeInit() -> void;
struct Information { struct Information {
string manifest; string manifest;
} information; } information;
uint serialize_size; private:
bool _loaded = false;
uint _serializeSize = 0;
}; };
extern System system; extern System system;

View File

@ -13,15 +13,6 @@ namespace GameBoy {
#include "serialization.cpp" #include "serialization.cpp"
Cartridge cartridge; Cartridge cartridge;
Cartridge::Cartridge() {
loaded = false;
sha256 = "";
}
Cartridge::~Cartridge() {
unload();
}
auto Cartridge::manifest() const -> string { auto Cartridge::manifest() const -> string {
return information.markup; return information.markup;
} }
@ -30,25 +21,9 @@ auto Cartridge::title() const -> string {
return information.title; return information.title;
} }
//intended for use with Super Game Boy for when no Game Boy cartridge is inserted
auto Cartridge::load_empty(System::Revision revision) -> void {
unload();
romsize = 32768;
romdata = allocate<uint8>(romsize, 0xff);
ramsize = 0;
mapper = &mbc0;
sha256 = Hash::SHA256(romdata, romsize).digest();
loaded = true;
system.load(revision);
}
auto Cartridge::load(System::Revision revision) -> void { auto Cartridge::load(System::Revision revision) -> void {
unload(); information.markup = "";
interface->loadRequest(ID::Manifest, "manifest.bml", !system.sgb());
system.revision = revision; //needed for ID::Manifest to return correct group ID
if(revision != System::Revision::SuperGameBoy) {
interface->loadRequest(ID::Manifest, "manifest.bml", true);
}
information.mapper = Mapper::Unknown; information.mapper = Mapper::Unknown;
information.ram = false; information.ram = false;
@ -78,21 +53,18 @@ auto Cartridge::load(System::Revision revision) -> void {
auto rom = document["board/rom"]; auto rom = document["board/rom"];
auto ram = document["board/ram"]; auto ram = document["board/ram"];
romsize = rom["size"].natural(); romsize = max(32768u, rom["size"].natural());
romdata = allocate<uint8>(romsize, 0xff); romdata = allocate<uint8>(romsize, 0xff);
ramsize = ram["size"].natural(); ramsize = ram["size"].natural();
ramdata = allocate<uint8>(ramsize, 0xff); ramdata = allocate<uint8>(ramsize, 0xff);
//Super Game Boy core loads memory from Super Famicom core if(auto name = rom["name"].text()) interface->loadRequest(ID::ROM, name, !system.sgb());
if(revision != System::Revision::SuperGameBoy) {
if(auto name = rom["name"].text()) interface->loadRequest(ID::ROM, name, true);
if(auto name = ram["name"].text()) interface->loadRequest(ID::RAM, name, false); 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 = ram["name"].text()) memory.append({ID::RAM, name});
}
information.romsize = rom["size"].natural(); information.romsize = romsize;
information.ramsize = ram["size"].natural(); information.ramsize = ramsize;
information.battery = (bool)ram["name"]; information.battery = (bool)ram["name"];
switch(information.mapper) { default: switch(information.mapper) { default:
@ -107,14 +79,11 @@ auto Cartridge::load(System::Revision revision) -> void {
} }
sha256 = Hash::SHA256(romdata, romsize).digest(); sha256 = Hash::SHA256(romdata, romsize).digest();
loaded = true;
system.load(revision);
} }
auto Cartridge::unload() -> void { auto Cartridge::unload() -> void {
if(romdata) { delete[] romdata; romdata = nullptr; romsize = 0; } if(romdata) { delete[] romdata; romdata = nullptr; romsize = 0; }
if(ramdata) { delete[] ramdata; ramdata = nullptr; ramsize = 0; } if(ramdata) { delete[] ramdata; ramdata = nullptr; ramsize = 0; }
loaded = false;
} }
auto Cartridge::rom_read(uint addr) -> uint8 { auto Cartridge::rom_read(uint addr) -> uint8 {
@ -144,7 +113,7 @@ auto Cartridge::mmio_read(uint16 addr) -> uint8 {
if(bootrom_enable) { if(bootrom_enable) {
const uint8* data = nullptr; const uint8* data = nullptr;
switch(system.revision) { default: switch(system.revision()) { default:
case System::Revision::GameBoy: data = system.bootROM.dmg; break; case System::Revision::GameBoy: data = system.bootROM.dmg; break;
case System::Revision::SuperGameBoy: data = system.bootROM.sgb; break; case System::Revision::SuperGameBoy: data = system.bootROM.sgb; break;
case System::Revision::GameBoyColor: data = system.bootROM.cgb; break; case System::Revision::GameBoyColor: data = system.bootROM.cgb; break;

View File

@ -1,8 +1,4 @@
struct Cartridge : MMIO, property<Cartridge> { struct Cartridge : MMIO, property<Cartridge> {
Cartridge();
~Cartridge();
auto load_empty(System::Revision revision) -> void;
auto load(System::Revision revision) -> void; auto load(System::Revision revision) -> void;
auto unload() -> void; auto unload() -> void;
@ -62,7 +58,6 @@ struct Cartridge : MMIO, property<Cartridge> {
}; };
vector<Memory> memory; vector<Memory> memory;
readonly<bool> loaded;
readonly<string> sha256; readonly<string> sha256;
uint8* romdata = nullptr; uint8* romdata = nullptr;

View File

@ -18,7 +18,7 @@ auto CPU::mmio_joyp_poll() -> void {
dpad |= interface->inputPoll(0, 0, (uint)Input::Left) << 1; dpad |= interface->inputPoll(0, 0, (uint)Input::Left) << 1;
dpad |= interface->inputPoll(0, 0, (uint)Input::Right) << 0; dpad |= interface->inputPoll(0, 0, (uint)Input::Right) << 0;
if(system.revision != System::Revision::SuperGameBoy) { if(system.revision() != System::Revision::SuperGameBoy) {
//D-pad pivot makes it impossible to press opposing directions at the same time //D-pad pivot makes it impossible to press opposing directions at the same time
//however, Super Game Boy BIOS is able to set these bits together //however, Super Game Boy BIOS is able to set these bits together
if(dpad & 4) dpad &= ~8; //disallow up+down if(dpad & 4) dpad &= ~8; //disallow up+down

View File

@ -3,7 +3,7 @@
// 154 scanlines/frame // 154 scanlines/frame
auto CPU::add_clocks(uint clocks) -> void { auto CPU::add_clocks(uint clocks) -> void {
if(system.sgb()) system.clocks_executed += clocks; if(system.sgb()) system._clocksExecuted += clocks;
while(clocks--) { while(clocks--) {
if(++status.clock == 0) { if(++status.clock == 0) {

View File

@ -57,7 +57,7 @@ auto Interface::audioFrequency() -> double {
} }
auto Interface::loaded() -> bool { auto Interface::loaded() -> bool {
return cartridge.loaded(); return system.loaded();
} }
auto Interface::sha256() -> string { auto Interface::sha256() -> string {
@ -74,7 +74,7 @@ auto Interface::group(uint id) -> uint {
case ID::Manifest: case ID::Manifest:
case ID::ROM: case ID::ROM:
case ID::RAM: case ID::RAM:
switch(system.revision) { switch(system.revision()) {
case System::Revision::GameBoy: return ID::GameBoy; case System::Revision::GameBoy: return ID::GameBoy;
case System::Revision::SuperGameBoy: return ID::SuperGameBoy; case System::Revision::SuperGameBoy: return ID::SuperGameBoy;
case System::Revision::GameBoyColor: return ID::GameBoyColor; case System::Revision::GameBoyColor: return ID::GameBoyColor;
@ -85,9 +85,9 @@ auto Interface::group(uint id) -> uint {
} }
auto Interface::load(uint id) -> void { auto Interface::load(uint id) -> void {
if(id == ID::GameBoy) cartridge.load(System::Revision::GameBoy); if(id == ID::GameBoy) system.load(System::Revision::GameBoy);
if(id == ID::SuperGameBoy) cartridge.load(System::Revision::SuperGameBoy); if(id == ID::SuperGameBoy) system.load(System::Revision::SuperGameBoy);
if(id == ID::GameBoyColor) cartridge.load(System::Revision::GameBoyColor); if(id == ID::GameBoyColor) system.load(System::Revision::GameBoyColor);
} }
auto Interface::save() -> void { auto Interface::save() -> void {
@ -134,7 +134,7 @@ auto Interface::save(uint id, const stream& stream) -> void {
auto Interface::unload() -> void { auto Interface::unload() -> void {
save(); save();
cartridge.unload(); system.unload();
} }
auto Interface::power() -> void { auto Interface::power() -> void {
@ -150,7 +150,7 @@ auto Interface::run() -> void {
} }
auto Interface::serialize() -> serializer { auto Interface::serialize() -> serializer {
system.runtosave(); system.runToSave();
return system.serialize(); return system.serialize();
} }

View File

@ -1,5 +1,5 @@
auto System::serialize() -> serializer { auto System::serialize() -> serializer {
serializer s(serialize_size); serializer s(_serializeSize);
uint signature = 0x31545342, version = Info::SerializerVersion; uint signature = 0x31545342, version = Info::SerializerVersion;
char hash[64], description[512]; char hash[64], description[512];
@ -11,7 +11,7 @@ auto System::serialize() -> serializer {
s.array(hash); s.array(hash);
s.array(description); s.array(description);
serialize_all(s); serializeAll(s);
return s; return s;
} }
@ -28,15 +28,15 @@ auto System::unserialize(serializer& s) -> bool {
if(version != Info::SerializerVersion) return false; if(version != Info::SerializerVersion) return false;
power(); power();
serialize_all(s); serializeAll(s);
return true; return true;
} }
auto System::serialize(serializer& s) -> void { auto System::serialize(serializer& s) -> void {
s.integer(clocks_executed); s.integer(_clocksExecuted);
} }
auto System::serialize_all(serializer& s) -> void { auto System::serializeAll(serializer& s) -> void {
cartridge.serialize(s); cartridge.serialize(s);
system.serialize(s); system.serialize(s);
cpu.serialize(s); cpu.serialize(s);
@ -44,7 +44,7 @@ auto System::serialize_all(serializer& s) -> void {
apu.serialize(s); apu.serialize(s);
} }
auto System::serialize_init() -> void { auto System::serializeInit() -> void {
serializer s; serializer s;
uint signature = 0, version = 0, crc32 = 0; uint signature = 0, version = 0, crc32 = 0;
@ -55,6 +55,6 @@ auto System::serialize_init() -> void {
s.array(hash); s.array(hash);
s.array(description); s.array(description);
serialize_all(s); serializeAll(s);
serialize_size = s.size(); _serializeSize = s.size();
} }

View File

@ -5,6 +5,10 @@ namespace GameBoy {
#include "serialization.cpp" #include "serialization.cpp"
System system; 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() { System::System() {
for(auto& byte : bootROM.dmg) byte = 0; for(auto& byte : bootROM.dmg) byte = 0;
for(auto& byte : bootROM.sgb) byte = 0; for(auto& byte : bootROM.sgb) byte = 0;
@ -20,22 +24,22 @@ auto System::run() -> void {
} }
} }
auto System::runtosave() -> void { auto System::runToSave() -> void {
scheduler.sync = Scheduler::SynchronizeMode::CPU; scheduler.sync = Scheduler::SynchronizeMode::CPU;
runthreadtosave(); runThreadToSave();
scheduler.sync = Scheduler::SynchronizeMode::All; scheduler.sync = Scheduler::SynchronizeMode::All;
scheduler.active_thread = ppu.thread; scheduler.active_thread = ppu.thread;
runthreadtosave(); runThreadToSave();
scheduler.sync = Scheduler::SynchronizeMode::All; scheduler.sync = Scheduler::SynchronizeMode::All;
scheduler.active_thread = apu.thread; scheduler.active_thread = apu.thread;
runthreadtosave(); runThreadToSave();
scheduler.sync = Scheduler::SynchronizeMode::None; scheduler.sync = Scheduler::SynchronizeMode::None;
} }
auto System::runthreadtosave() -> void { auto System::runThreadToSave() -> void {
while(true) { while(true) {
scheduler.enter(); scheduler.enter();
if(scheduler.exit_reason == Scheduler::ExitReason::SynchronizeEvent) break; if(scheduler.exit_reason == Scheduler::ExitReason::SynchronizeEvent) break;
@ -50,19 +54,32 @@ auto System::init() -> void {
} }
auto System::load(Revision revision) -> void { auto System::load(Revision revision) -> void {
this->revision = revision; _revision = revision;
serialize_init();
if(revision == Revision::SuperGameBoy) return; //Super Famicom core loads boot ROM for SGB
interface->loadRequest(ID::SystemManifest, "manifest.bml", true); interface->loadRequest(ID::SystemManifest, "manifest.bml", true);
auto document = BML::unserialize(information.manifest); 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["system/cpu/rom/name"].text()) { if(auto bootROM = document[path].text()) {
interface->loadRequest( interface->loadRequest(
revision == Revision::GameBoy ? ID::GameBoyBootROM : ID::GameBoyColorBootROM, revision == Revision::GameBoy ? ID::GameBoyBootROM
: revision == Revision::SuperGameBoy ? ID::SuperGameBoyBootROM
: revision == Revision::GameBoyColor ? ID::GameBoyColorBootROM
: ID::GameBoyBootROM,
bootROM, true bootROM, true
); );
} }
cartridge.load(revision);
serializeInit();
_loaded = true;
}
auto System::unload() -> void {
if(!loaded()) return;
cartridge.unload();
_loaded = false;
} }
auto System::power() -> void { auto System::power() -> void {
@ -74,7 +91,7 @@ auto System::power() -> void {
video.power(); video.power();
scheduler.init(); scheduler.init();
clocks_executed = 0; _clocksExecuted = 0;
} }
} }

View File

@ -9,20 +9,25 @@ struct System {
GameBoy, GameBoy,
SuperGameBoy, SuperGameBoy,
GameBoyColor, GameBoyColor,
} revision; };
System(); System();
inline auto dmg() const { return revision == Revision::GameBoy; } auto loaded() const -> bool;
inline auto sgb() const { return revision == Revision::SuperGameBoy; } auto revision() const -> Revision;
inline auto cgb() const { return revision == Revision::GameBoyColor; } auto clocksExecuted() const -> uint;
inline auto dmg() const { return _revision == Revision::GameBoy; }
inline auto sgb() const { return _revision == Revision::SuperGameBoy; }
inline auto cgb() const { return _revision == Revision::GameBoyColor; }
auto run() -> void; auto run() -> void;
auto runtosave() -> void; auto runToSave() -> void;
auto runthreadtosave() -> void; auto runThreadToSave() -> void;
auto init() -> void; auto init() -> void;
auto load(Revision) -> void; auto load(Revision) -> void;
auto unload() -> void;
auto power() -> void; auto power() -> void;
//serialization.cpp //serialization.cpp
@ -30,8 +35,8 @@ struct System {
auto unserialize(serializer&) -> bool; auto unserialize(serializer&) -> bool;
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
auto serialize_all(serializer&) -> void; auto serializeAll(serializer&) -> void;
auto serialize_init() -> void; auto serializeInit() -> void;
struct BootROM { struct BootROM {
uint8 dmg[ 256]; uint8 dmg[ 256];
@ -43,8 +48,10 @@ struct System {
string manifest; string manifest;
} information; } information;
uint clocks_executed = 0; bool _loaded = false;
uint serialize_size = 0; Revision _revision = Revision::GameBoy;
uint _serializeSize = 0;
uint _clocksExecuted = 0;
}; };
#include <gb/interface/interface.hpp> #include <gb/interface/interface.hpp>

View File

@ -23,10 +23,6 @@ Cartridge::~Cartridge() {
delete[] flash.data; delete[] flash.data;
} }
auto Cartridge::loaded() const -> bool {
return isLoaded;
}
auto Cartridge::sha256() const -> string { auto Cartridge::sha256() const -> string {
return information.sha256; return information.sha256;
} }
@ -96,17 +92,11 @@ auto Cartridge::load() -> void {
} }
information.sha256 = Hash::SHA256(mrom.data, mrom.size).digest(); information.sha256 = Hash::SHA256(mrom.data, mrom.size).digest();
system.load();
isLoaded = true;
} }
auto Cartridge::unload() -> void { auto Cartridge::unload() -> void {
if(isLoaded) {
isLoaded = false;
memory.reset(); memory.reset();
} }
}
auto Cartridge::power() -> void { auto Cartridge::power() -> void {
eeprom.power(); eeprom.power();

View File

@ -1,7 +1,6 @@
struct Cartridge { struct Cartridge {
#include "memory.hpp" #include "memory.hpp"
auto loaded() const -> bool;
auto sha256() const -> string; auto sha256() const -> string;
auto manifest() const -> string; auto manifest() const -> string;
auto title() const -> string; auto title() const -> string;
@ -31,7 +30,6 @@ struct Cartridge {
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
private: private:
bool isLoaded = false;
bool hasSRAM = false; bool hasSRAM = false;
bool hasEEPROM = false; bool hasEEPROM = false;
bool hasFLASH = false; bool hasFLASH = false;

View File

@ -57,7 +57,7 @@ auto Interface::audioFrequency() -> double {
} }
auto Interface::loaded() -> bool { auto Interface::loaded() -> bool {
return cartridge.loaded(); return system.loaded();
} }
auto Interface::group(uint id) -> uint { auto Interface::group(uint id) -> uint {
@ -77,7 +77,7 @@ auto Interface::group(uint id) -> uint {
} }
auto Interface::load(uint id) -> void { auto Interface::load(uint id) -> void {
cartridge.load(); system.load();
} }
auto Interface::save() -> void { auto Interface::save() -> void {
@ -132,7 +132,7 @@ auto Interface::save(uint id, const stream& stream) -> void {
auto Interface::unload() -> void { auto Interface::unload() -> void {
save(); save();
cartridge.unload(); system.unload();
} }
auto Interface::power() -> void { auto Interface::power() -> void {
@ -148,7 +148,7 @@ auto Interface::run() -> void {
} }
auto Interface::serialize() -> serializer { auto Interface::serialize() -> serializer {
system.runtosave(); system.runToSave();
return system.serialize(); return system.serialize();
} }

View File

@ -1,5 +1,5 @@
auto System::serialize() -> serializer { auto System::serialize() -> serializer {
serializer s(serialize_size); serializer s(_serializeSize);
uint signature = 0x31545342, version = Info::SerializerVersion; uint signature = 0x31545342, version = Info::SerializerVersion;
char hash[64], description[512]; char hash[64], description[512];
@ -11,7 +11,7 @@ auto System::serialize() -> serializer {
s.array(hash); s.array(hash);
s.array(description); s.array(description);
serialize_all(s); serializeAll(s);
return s; return s;
} }
@ -28,7 +28,7 @@ auto System::unserialize(serializer& s) -> bool {
if(version != Info::SerializerVersion) return false; if(version != Info::SerializerVersion) return false;
power(); power();
serialize_all(s); serializeAll(s);
return true; return true;
} }
@ -37,7 +37,7 @@ auto System::serialize(serializer& s) -> void {
s.integer(bios.mdr); s.integer(bios.mdr);
} }
auto System::serialize_all(serializer& s) -> void { auto System::serializeAll(serializer& s) -> void {
cartridge.serialize(s); cartridge.serialize(s);
system.serialize(s); system.serialize(s);
cpu.serialize(s); cpu.serialize(s);
@ -46,7 +46,7 @@ auto System::serialize_all(serializer& s) -> void {
player.serialize(s); player.serialize(s);
} }
auto System::serialize_init() -> void { auto System::serializeInit() -> void {
serializer s; serializer s;
uint signature = 0, version = 0; uint signature = 0, version = 0;
@ -57,6 +57,6 @@ auto System::serialize_init() -> void {
s.array(hash); s.array(hash);
s.array(description); s.array(description);
serialize_all(s); serializeAll(s);
serialize_size = s.size(); _serializeSize = s.size();
} }

View File

@ -7,6 +7,8 @@ namespace GameBoyAdvance {
BIOS bios; BIOS bios;
System system; System system;
auto System::loaded() const -> bool { return _loaded; }
auto System::init() -> void { auto System::init() -> void {
} }
@ -32,7 +34,15 @@ auto System::load() -> void {
interface->loadRequest(ID::BIOS, bios, true); interface->loadRequest(ID::BIOS, bios, true);
} }
serialize_init(); cartridge.load();
serializeInit();
_loaded = true;
}
auto System::unload() -> void {
if(!loaded()) return;
cartridge.unload();
_loaded = false;
} }
auto System::run() -> void { auto System::run() -> void {
@ -43,22 +53,22 @@ auto System::run() -> void {
video.refresh(); video.refresh();
} }
auto System::runtosave() -> void { auto System::runToSave() -> void {
scheduler.sync = Scheduler::SynchronizeMode::CPU; scheduler.sync = Scheduler::SynchronizeMode::CPU;
runthreadtosave(); runThreadToSave();
scheduler.sync = Scheduler::SynchronizeMode::All; scheduler.sync = Scheduler::SynchronizeMode::All;
scheduler.active = ppu.thread; scheduler.active = ppu.thread;
runthreadtosave(); runThreadToSave();
scheduler.sync = Scheduler::SynchronizeMode::All; scheduler.sync = Scheduler::SynchronizeMode::All;
scheduler.active = apu.thread; scheduler.active = apu.thread;
runthreadtosave(); runThreadToSave();
scheduler.sync = Scheduler::SynchronizeMode::None; scheduler.sync = Scheduler::SynchronizeMode::None;
} }
auto System::runthreadtosave() -> void { auto System::runThreadToSave() -> void {
while(true) { while(true) {
scheduler.enter(); scheduler.enter();
if(scheduler.exit_reason() == Scheduler::ExitReason::SynchronizeEvent) break; if(scheduler.exit_reason() == Scheduler::ExitReason::SynchronizeEvent) break;

View File

@ -15,26 +15,30 @@ struct BIOS : Memory {
}; };
struct System { struct System {
auto loaded() const -> bool;
auto init() -> void; auto init() -> void;
auto term() -> void; auto term() -> void;
auto load() -> void; auto load() -> void;
auto unload() -> void;
auto power() -> void; auto power() -> void;
auto run() -> void; auto run() -> void;
auto runtosave() -> void; auto runToSave() -> void;
auto runthreadtosave() -> void; auto runThreadToSave() -> void;
auto serialize() -> serializer; auto serialize() -> serializer;
auto unserialize(serializer&) -> bool; auto unserialize(serializer&) -> bool;
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
auto serialize_all(serializer&) -> void; auto serializeAll(serializer&) -> void;
auto serialize_init() -> void; auto serializeInit() -> void;
struct Information { struct Information {
string manifest; string manifest;
} information; } information;
uint serialize_size; bool _loaded = false;
uint _serializeSize = 0;
}; };
extern BIOS bios; extern BIOS bios;

View File

@ -94,7 +94,7 @@ auto Cartridge::load() -> void {
//Game Boy //Game Boy
if(cartridge.hasICD2()) { if(cartridge.hasICD2()) {
_sha256 = Hash::SHA256(GameBoy::cartridge.romdata, GameBoy::cartridge.romsize).digest(); _sha256 = ""; //Game Boy cartridge not loaded yet: set later via loadGameBoy()
} }
//BS Memory //BS Memory
@ -136,25 +136,13 @@ auto Cartridge::load() -> void {
rom.write_protect(true); rom.write_protect(true);
ram.write_protect(false); ram.write_protect(false);
system.load();
_loaded = true;
} }
auto Cartridge::loadGameBoy() -> void { auto Cartridge::loadGameBoy() -> void {
interface->loadRequest(ID::GameBoyManifest, "manifest.bml", true); //invoked from ICD2::load()
auto document = BML::unserialize(information.markup.gameBoy); _sha256 = GameBoy::interface->sha256();
information.title.gameBoy = document["information/title"].text(); information.markup.gameBoy = GameBoy::interface->manifest();
information.title.gameBoy = GameBoy::interface->title();
auto rom = document["board/rom"];
auto ram = document["board/ram"];
GameBoy::cartridge.information.markup = information.markup.gameBoy;
GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy);
if(auto name = rom["name"].text()) interface->loadRequest(ID::GameBoyROM, name, true);
if(auto name = ram["name"].text()) interface->loadRequest(ID::GameBoyRAM, name, false);
if(auto name = ram["name"].text()) memory.append({ID::GameBoyRAM, name});
} }
auto Cartridge::loadBSMemory() -> void { auto Cartridge::loadBSMemory() -> void {
@ -182,13 +170,13 @@ auto Cartridge::loadSufamiTurboA() -> void {
auto ram = document["board/ram"]; auto ram = document["board/ram"];
if(rom["name"]) { if(rom["name"]) {
unsigned size = rom["size"].natural(); uint size = rom["size"].natural();
sufamiturboA.rom.map(allocate<uint8>(size, 0xff), size); sufamiturboA.rom.map(allocate<uint8>(size, 0xff), size);
interface->loadRequest(ID::SufamiTurboSlotAROM, rom["name"].text(), true); interface->loadRequest(ID::SufamiTurboSlotAROM, rom["name"].text(), true);
} }
if(ram["name"]) { if(ram["name"]) {
unsigned size = ram["size"].natural(); uint size = ram["size"].natural();
sufamiturboA.ram.map(allocate<uint8>(size, 0xff), size); sufamiturboA.ram.map(allocate<uint8>(size, 0xff), size);
interface->loadRequest(ID::SufamiTurboSlotARAM, ram["name"].text(), false); interface->loadRequest(ID::SufamiTurboSlotARAM, ram["name"].text(), false);
memory.append({ID::SufamiTurboSlotARAM, ram["name"].text()}); memory.append({ID::SufamiTurboSlotARAM, ram["name"].text()});
@ -208,13 +196,13 @@ auto Cartridge::loadSufamiTurboB() -> void {
auto ram = document["board/ram"]; auto ram = document["board/ram"];
if(rom["name"]) { if(rom["name"]) {
unsigned size = rom["size"].natural(); uint size = rom["size"].natural();
sufamiturboB.rom.map(allocate<uint8>(size, 0xff), size); sufamiturboB.rom.map(allocate<uint8>(size, 0xff), size);
interface->loadRequest(ID::SufamiTurboSlotBROM, rom["name"].text(), true); interface->loadRequest(ID::SufamiTurboSlotBROM, rom["name"].text(), true);
} }
if(ram["name"]) { if(ram["name"]) {
unsigned size = ram["size"].natural(); uint size = ram["size"].natural();
sufamiturboB.ram.map(allocate<uint8>(size, 0xff), size); sufamiturboB.ram.map(allocate<uint8>(size, 0xff), size);
interface->loadRequest(ID::SufamiTurboSlotBRAM, ram["name"].text(), false); interface->loadRequest(ID::SufamiTurboSlotBRAM, ram["name"].text(), false);
memory.append({ID::SufamiTurboSlotBRAM, ram["name"].text()}); memory.append({ID::SufamiTurboSlotBRAM, ram["name"].text()});
@ -222,14 +210,9 @@ auto Cartridge::loadSufamiTurboB() -> void {
} }
auto Cartridge::unload() -> void { auto Cartridge::unload() -> void {
if(_loaded) {
system.unload();
rom.reset(); rom.reset();
ram.reset(); ram.reset();
_loaded = false;
memory.reset(); memory.reset();
} }
}
} }

View File

@ -1,10 +1,6 @@
struct Cartridge : property<Cartridge> { struct Cartridge : property<Cartridge> {
enum class Region : unsigned { NTSC, PAL }; enum class Region : unsigned { NTSC, PAL };
Cartridge() = default;
~Cartridge() { unload(); }
auto loaded() const -> bool { return _loaded; }
auto sha256() const -> string { return _sha256; } auto sha256() const -> string { return _sha256; }
auto region() const -> Region { return _region; } auto region() const -> Region { return _region; }
@ -83,6 +79,7 @@ private:
auto loadSufamiTurboA() -> void; auto loadSufamiTurboA() -> void;
auto loadSufamiTurboB() -> void; auto loadSufamiTurboB() -> void;
friend class Interface; friend class Interface;
friend class ICD2;
//markup.cpp //markup.cpp
auto parseMarkup(const string&) -> void; auto parseMarkup(const string&) -> void;
@ -110,7 +107,6 @@ private:
auto parseMarkupOBC1(Markup::Node) -> void; auto parseMarkupOBC1(Markup::Node) -> void;
auto parseMarkupMSU1(Markup::Node) -> void; auto parseMarkupMSU1(Markup::Node) -> void;
bool _loaded = false;
string _sha256; string _sha256;
Region _region = Region::NTSC; Region _region = Region::NTSC;
}; };

View File

@ -92,10 +92,7 @@ auto Cartridge::parseMarkupICD2(Markup::Node root) -> void {
hasICD2 = true; hasICD2 = true;
icd2.revision = max(1, root["revision"].natural()); icd2.revision = max(1, root["revision"].natural());
GameBoy::cartridge.load_empty(GameBoy::System::Revision::SuperGameBoy); //Game Boy core loads data through ICD2 interface
interface->loadRequest(ID::GameBoy, "Game Boy", "gb", false);
interface->loadRequest(ID::SuperGameBoyBootROM, root["brom"]["name"].text(), true);
for(auto node : root.find("map")) { for(auto node : root.find("map")) {
parseMarkupMap(node, {&ICD2::read, &icd2}, {&ICD2::write, &icd2}); parseMarkupMap(node, {&ICD2::read, &icd2}, {&ICD2::write, &icd2});

View File

@ -13,22 +13,11 @@
//Teensy D5 <> Teensy D7 //Teensy D5 <> Teensy D7
USART::USART(bool port) : Controller(port) { USART::USART(bool port) : Controller(port) {
latched = 0;
data1 = 0;
data2 = 0;
counter = 0;
rxlength = 0;
rxdata = 0;
txlength = 0;
txdata = 0;
string filename{interface->path(ID::SuperFamicom), "usart.so"}; string filename{interface->path(ID::SuperFamicom), "usart.so"};
if(openAbsolute(filename)) { if(openAbsolute(filename)) {
init = sym("usart_init"); init = sym("usart_init");
main = sym("usart_main"); main = sym("usart_main");
if(init && main) create(Controller::Enter, 10000000); if(init && main) create(Controller::Enter, 10'000'000);
} }
} }
@ -46,9 +35,9 @@ auto USART::enter() -> void {
{&USART::writable, this}, {&USART::writable, this},
{&USART::write, this} {&USART::write, this}
); );
main(); main({});
} }
while(true) step(10000000); while(true) step(10'000'000);
} }
auto USART::quit() -> bool { auto USART::quit() -> bool {
@ -56,8 +45,8 @@ auto USART::quit() -> bool {
return false; return false;
} }
auto USART::usleep(unsigned milliseconds) -> void { auto USART::usleep(uint microseconds) -> void {
step(10 * milliseconds); step(10 * microseconds);
} }
auto USART::readable() -> bool { auto USART::readable() -> bool {
@ -91,7 +80,7 @@ auto USART::data() -> uint2 {
if(iobit()) { if(iobit()) {
if(counter >= 16) return 1; if(counter >= 16) return 1;
uint2 result = 0; uint2 result = 0;
if(counter < 12) result = interface->inputPoll(port, (unsigned)Device::ID::Gamepad, counter); if(counter < 12) result = interface->inputPoll(port, (uint)Device::ID::Gamepad, counter);
if(latched == 0) counter++; if(latched == 0) counter++;
return result; return result;
} }

View File

@ -5,7 +5,7 @@ struct USART : Controller, public library {
auto enter() -> void; auto enter() -> void;
auto quit() -> bool; auto quit() -> bool;
auto usleep(unsigned milliseconds) -> void; auto usleep(uint microseconds) -> void;
auto readable() -> bool; auto readable() -> bool;
auto read() -> uint8; auto read() -> uint8;
auto writable() -> bool; auto writable() -> bool;
@ -15,26 +15,26 @@ struct USART : Controller, public library {
auto latch(bool data) -> void; auto latch(bool data) -> void;
private: private:
bool latched; bool latched = 0;
bool data1; bool data1 = 0;
bool data2; bool data2 = 0;
unsigned counter; uint counter = 0;
uint8 rxlength; uint8 rxlength = 0;
uint8 rxdata; uint8 rxdata = 0;
vector<uint8> rxbuffer; vector<uint8> rxbuffer;
uint8 txlength; uint8 txlength = 0;
uint8 txdata; uint8 txdata = 0;
vector<uint8> txbuffer; vector<uint8> txbuffer;
function<void ( function<void (
function<bool ()>, //quit function<bool ()>, //quit
function<void (unsigned)>, //usleep function<void (uint)>, //usleep
function<bool ()>, //readable function<bool ()>, //readable
function<uint8 ()>, //read function<uint8 ()>, //read
function<bool ()>, //writable function<bool ()>, //writable
function<void (uint8)> //write function<void (uint8)> //write
)> init; )> init;
function<void ()> main; function<void (lstring)> main;
}; };

View File

@ -12,14 +12,14 @@ auto ICD2::Enter() -> void { icd2.enter(); }
auto ICD2::enter() -> void { auto ICD2::enter() -> void {
while(true) { while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::All) { if(scheduler.sync == Scheduler::SynchronizeMode::All) {
GameBoy::system.runtosave(); GameBoy::system.runToSave();
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
} }
if(r6003 & 0x80) { if(r6003 & 0x80) {
GameBoy::system.run(); GameBoy::system.run();
step(GameBoy::system.clocks_executed); step(GameBoy::system._clocksExecuted);
GameBoy::system.clocks_executed = 0; GameBoy::system._clocksExecuted = 0;
} else { //DMG halted } else { //DMG halted
audio.coprocessorSample(0, 0); audio.coprocessorSample(0, 0);
step(1); step(1);
@ -36,9 +36,13 @@ auto ICD2::load() -> void {
hook = GameBoy::interface->hook; hook = GameBoy::interface->hook;
GameBoy::interface->bind = this; GameBoy::interface->bind = this;
GameBoy::interface->hook = this; GameBoy::interface->hook = this;
interface->loadRequest(ID::GameBoy, "Game Boy", "gb", false);
GameBoy::interface->load(GameBoy::ID::SuperGameBoy);
cartridge.loadGameBoy();
} }
auto ICD2::unload() -> void { auto ICD2::unload() -> void {
GameBoy::interface->unload();
GameBoy::interface->bind = bind; GameBoy::interface->bind = bind;
GameBoy::interface->hook = hook; GameBoy::interface->hook = hook;
} }

View File

@ -16,10 +16,11 @@ struct ICD2 : Emulator::Interface::Bind, GameBoy::Interface::Hook, Coprocessor {
uint revision; uint revision;
private: private:
Emulator::Interface::Bind* bind = nullptr;
GameBoy::Interface::Hook* hook = nullptr;
#include "interface/interface.hpp" #include "interface/interface.hpp"
#include "mmio/mmio.hpp" #include "mmio/mmio.hpp"
Emulator::Interface::Bind* bind = nullptr;
GameBoy::Interface::Hook* hook = nullptr;
}; };
extern ICD2 icd2; extern ICD2 icd2;

View File

@ -85,8 +85,35 @@ auto ICD2::joypWrite(bool p15, bool p14) -> void {
packetlock = true; packetlock = true;
} }
auto ICD2::videoColor(uint source, uint16 red, uint16 green, uint16 blue) -> uint32 { auto ICD2::loadRequest(uint id, string name, string type, bool required) -> void {
return source; }
auto ICD2::loadRequest(uint id, string name, bool required) -> void {
if(id == GameBoy::ID::SystemManifest) {
interface->loadRequest(ID::SuperGameBoyManifest, name, required);
}
if(id == GameBoy::ID::SuperGameBoyBootROM) {
interface->loadRequest(ID::SuperGameBoyBootROM, name, required);
}
if(id == GameBoy::ID::Manifest) {
interface->loadRequest(ID::GameBoyManifest, name, required);
}
if(id == GameBoy::ID::ROM) {
interface->loadRequest(ID::GameBoyROM, name, required);
}
if(id == GameBoy::ID::RAM) {
interface->loadRequest(ID::GameBoyRAM, name, required);
}
}
auto ICD2::saveRequest(uint id, string name) -> void {
if(id == GameBoy::ID::RAM) {
interface->saveRequest(ID::GameBoyRAM, name);
}
} }
auto ICD2::videoRefresh(const uint32* data, uint pitch, uint width, uint height) -> void { auto ICD2::videoRefresh(const uint32* data, uint pitch, uint width, uint height) -> void {

View File

@ -1,11 +1,14 @@
auto lcdScanline() -> void; auto lcdScanline() -> void override;
auto lcdOutput(uint2 color) -> void; auto lcdOutput(uint2 color) -> void override;
auto joypWrite(bool p15, bool p14) -> void; auto joypWrite(bool p15, bool p14) -> void override;
auto videoColor(uint source, uint16 red, uint16 green, uint16 blue) -> uint32; auto loadRequest(uint id, string name, string type, bool required) -> void override;
auto videoRefresh(const uint32* data, uint pitch, uint width, uint height) -> void; auto loadRequest(uint id, string name, bool required) -> void override;
auto audioSample(int16 lsample, int16 rsample) -> void; auto saveRequest(uint id, string name) -> void override;
auto inputPoll(uint port, uint device, uint id) -> int16;
auto videoRefresh(const uint32* data, uint pitch, uint width, uint height) -> void override;
auto audioSample(int16 lsample, int16 rsample) -> void override;
auto inputPoll(uint port, uint device, uint id) -> int16 override;
struct Packet { struct Packet {
auto operator[](uint addr) -> uint8& { return data[addr & 15]; } auto operator[](uint addr) -> uint8& { return data[addr & 15]; }

View File

@ -1,6 +1,6 @@
auto ICD2::serialize(serializer& s) -> void { auto ICD2::serialize(serializer& s) -> void {
Thread::serialize(s); Thread::serialize(s);
GameBoy::system.serialize_all(s); GameBoy::system.serializeAll(s);
for(auto n : range(64)) s.array(packet[n].data); for(auto n : range(64)) s.array(packet[n].data);
s.integer(packetsize); s.integer(packetsize);

View File

@ -154,7 +154,7 @@ auto Interface::audioFrequency() -> double {
} }
auto Interface::loaded() -> bool { auto Interface::loaded() -> bool {
return cartridge.loaded(); return system.loaded();
} }
auto Interface::sha256() -> string { auto Interface::sha256() -> string {
@ -200,6 +200,7 @@ auto Interface::group(uint id) -> uint {
case ID::SDD1ROM: case ID::SDD1ROM:
case ID::SDD1RAM: case ID::SDD1RAM:
case ID::OBC1RAM: case ID::OBC1RAM:
case ID::SuperGameBoyManifest:
case ID::SuperGameBoyBootROM: case ID::SuperGameBoyBootROM:
case ID::MCCROM: case ID::MCCROM:
case ID::MCCRAM: case ID::MCCRAM:
@ -229,8 +230,7 @@ auto Interface::group(uint id) -> uint {
} }
auto Interface::load(uint id) -> void { auto Interface::load(uint id) -> void {
if(id == ID::SuperFamicom) cartridge.load(); if(id == ID::SuperFamicom) system.load();
if(id == ID::GameBoy) cartridge.loadGameBoy();
if(id == ID::BSMemory) cartridge.loadBSMemory(); if(id == ID::BSMemory) cartridge.loadBSMemory();
if(id == ID::SufamiTurboSlotA) cartridge.loadSufamiTurboA(); if(id == ID::SufamiTurboSlotA) cartridge.loadSufamiTurboA();
if(id == ID::SufamiTurboSlotB) cartridge.loadSufamiTurboB(); if(id == ID::SufamiTurboSlotB) cartridge.loadSufamiTurboB();
@ -327,21 +327,27 @@ auto Interface::load(uint id, const stream& stream) -> void {
if(id == ID::OBC1RAM) obc1.ram.read(stream); if(id == ID::OBC1RAM) obc1.ram.read(stream);
if(id == ID::SuperGameBoyBootROM) {
stream.read(GameBoy::system.bootROM.sgb, min(stream.size(), 256u));
}
if(id == ID::MCCROM) mcc.rom.read(stream); if(id == ID::MCCROM) mcc.rom.read(stream);
if(id == ID::MCCRAM) mcc.ram.read(stream); if(id == ID::MCCRAM) mcc.ram.read(stream);
if(id == ID::GameBoyManifest) cartridge.information.markup.gameBoy = stream.text(); 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) { if(id == ID::GameBoyROM) {
stream.read(GameBoy::cartridge.romdata, min(GameBoy::cartridge.romsize, stream.size())); GameBoy::interface->load(GameBoy::ID::ROM, stream);
} }
if(id == ID::GameBoyRAM) { if(id == ID::GameBoyRAM) {
stream.read(GameBoy::cartridge.ramdata, min(GameBoy::cartridge.ramsize, stream.size())); GameBoy::interface->load(GameBoy::ID::RAM, stream);
} }
if(id == ID::BSMemoryManifest) cartridge.information.markup.bsMemory = stream.text(); if(id == ID::BSMemoryManifest) cartridge.information.markup.bsMemory = stream.text();
@ -395,7 +401,9 @@ auto Interface::save(uint id, const stream& stream) -> void {
if(id == ID::SDD1RAM) stream.write(sdd1.ram.data(), sdd1.ram.size()); if(id == ID::SDD1RAM) stream.write(sdd1.ram.data(), sdd1.ram.size());
if(id == ID::OBC1RAM) stream.write(obc1.ram.data(), obc1.ram.size()); if(id == ID::OBC1RAM) stream.write(obc1.ram.data(), obc1.ram.size());
if(id == ID::GameBoyRAM) stream.write(GameBoy::cartridge.ramdata, GameBoy::cartridge.ramsize); if(id == ID::GameBoyRAM) {
GameBoy::interface->save(GameBoy::ID::RAM, stream);
}
if(id == ID::MCCRAM) stream.write(mcc.ram.data(), mcc.ram.size()); if(id == ID::MCCRAM) stream.write(mcc.ram.data(), mcc.ram.size());
@ -405,7 +413,7 @@ auto Interface::save(uint id, const stream& stream) -> void {
auto Interface::unload() -> void { auto Interface::unload() -> void {
save(); save();
cartridge.unload(); system.unload();
} }
auto Interface::connect(uint port, uint device) -> void { auto Interface::connect(uint port, uint device) -> void {

View File

@ -60,11 +60,12 @@ struct ID {
OBC1RAM, OBC1RAM,
SuperGameBoyBootROM,
MCCROM, MCCROM,
MCCRAM, MCCRAM,
SuperGameBoyManifest,
SuperGameBoyBootROM,
GameBoyManifest, GameBoyManifest,
GameBoyROM, GameBoyROM,
GameBoyRAM, GameBoyRAM,

View File

@ -10,6 +10,7 @@ System system;
#include <sfc/scheduler/scheduler.cpp> #include <sfc/scheduler/scheduler.cpp>
auto System::loaded() const -> bool { return _loaded; }
auto System::region() const -> Region { return _region; } auto System::region() const -> Region { return _region; }
auto System::expansionPort() const -> Device::ID { return _expansionPort; } auto System::expansionPort() const -> Device::ID { return _expansionPort; }
auto System::cpuFrequency() const -> uint { return _cpuFrequency; } auto System::cpuFrequency() const -> uint { return _cpuFrequency; }
@ -95,6 +96,7 @@ auto System::load() -> void {
interface->loadRequest(ID::IPLROM, iplrom, true); interface->loadRequest(ID::IPLROM, iplrom, true);
} }
cartridge.load();
_region = cartridge.region() == Cartridge::Region::NTSC ? Region::NTSC : Region::PAL; _region = cartridge.region() == Cartridge::Region::NTSC ? Region::NTSC : Region::PAL;
_expansionPort = (Device::ID)settings.expansionPort; _expansionPort = (Device::ID)settings.expansionPort;
_cpuFrequency = region() == Region::NTSC ? 21477272 : 21281370; _cpuFrequency = region() == Region::NTSC ? 21477272 : 21281370;
@ -129,9 +131,11 @@ auto System::load() -> void {
if(cartridge.hasSufamiTurboSlots()) sufamiturboA.load(), sufamiturboB.load(); if(cartridge.hasSufamiTurboSlots()) sufamiturboA.load(), sufamiturboB.load();
serializeInit(); serializeInit();
_loaded = true;
} }
auto System::unload() -> void { auto System::unload() -> void {
if(!loaded()) return;
if(expansionPort() == Device::ID::Satellaview) satellaview.unload(); if(expansionPort() == Device::ID::Satellaview) satellaview.unload();
if(expansionPort() == Device::ID::eBoot) eboot.unload(); if(expansionPort() == Device::ID::eBoot) eboot.unload();
@ -153,6 +157,9 @@ auto System::unload() -> void {
if(cartridge.hasBSMemorySlot()) bsmemory.unload(); if(cartridge.hasBSMemorySlot()) bsmemory.unload();
if(cartridge.hasSufamiTurboSlots()) sufamiturboA.unload(), sufamiturboB.unload(); if(cartridge.hasSufamiTurboSlots()) sufamiturboA.unload(), sufamiturboB.unload();
cartridge.unload();
_loaded = false;
} }
auto System::power() -> void { auto System::power() -> void {

View File

@ -5,6 +5,7 @@ struct Interface;
struct System { struct System {
enum class Region : bool { NTSC = 0, PAL = 1 }; enum class Region : bool { NTSC = 0, PAL = 1 };
auto loaded() const -> bool;
auto region() const -> Region; auto region() const -> Region;
auto expansionPort() const -> Device::ID; auto expansionPort() const -> Device::ID;
auto cpuFrequency() const -> uint; auto cpuFrequency() const -> uint;
@ -34,6 +35,7 @@ private:
auto serializeAll(serializer&) -> void; auto serializeAll(serializer&) -> void;
auto serializeInit() -> void; auto serializeInit() -> void;
bool _loaded = false;
Region _region = Region::NTSC; Region _region = Region::NTSC;
Device::ID _expansionPort = Device::ID::None; Device::ID _expansionPort = Device::ID::None;
uint _cpuFrequency = 0; uint _cpuFrequency = 0;

View File

@ -192,10 +192,8 @@ auto Presentation::updateEmulator() -> void {
if(devices.objectCount() > 1) { if(devices.objectCount() > 1) {
auto path = string{emulator->information.name, "/", port.name}.replace(" ", ""); auto path = string{emulator->information.name, "/", port.name}.replace(" ", "");
auto device = settings(path).text(); auto device = settings(path).text();
for(auto object : devices.objects()) { for(auto item : devices.objects<MenuRadioItem>()) {
if(auto item = object.cast<MenuRadioItem>()) { if(item.text() == device) item.setChecked();
if(item.text() == device) item.setChecked().doActivate();
}
} }
menu.setVisible(); menu.setVisible();
} }

View File

@ -17,7 +17,7 @@ auto Program::loadRequest(uint id, string filename, bool required) -> void {
string pathname = mediaPaths(emulator->group(id)); string pathname = mediaPaths(emulator->group(id));
string location = {pathname, filename}; string location = {pathname, filename};
if(filename == "manifest.bml" && !pathname.find(".sys/")) { if(filename == "manifest.bml" && pathname && !pathname.find(".sys/")) {
if(!file::exists(location) || settings["Library/IgnoreManifests"].boolean()) { if(!file::exists(location) || settings["Library/IgnoreManifests"].boolean()) {
if(auto manifest = execute("icarus", "--manifest", pathname)) { if(auto manifest = execute("icarus", "--manifest", pathname)) {
memorystream stream{(const uint8*)manifest.data(), manifest.size()}; memorystream stream{(const uint8*)manifest.data(), manifest.size()};

View File

@ -6,23 +6,24 @@ auto Program::loadMedia(string location) -> void {
string type = suffixname(location).ltrim(".", 1L); string type = suffixname(location).ltrim(".", 1L);
for(auto& emulator : emulators) { for(auto& emulator : emulators) {
for(auto& media : emulator->media) { for(auto& media : emulator->media) {
if(media.bootable == false) continue; if(!media.bootable) continue;
if(media.type != type) continue; if(media.type != type) continue;
return loadMedia(*emulator, media, location); return loadMedia(*emulator, media, location);
} }
} }
} }
auto Program::loadMedia(Emulator::Interface& emulator_, Emulator::Interface::Media& media, const string& location) -> void { auto Program::loadMedia(Emulator::Interface& interface, Emulator::Interface::Media& media, const string& location) -> void {
unloadMedia(); unloadMedia();
mediaPaths(0) = locate({media.name, ".sys/"}); mediaPaths(0) = locate({media.name, ".sys/"});
mediaPaths(media.id) = location; mediaPaths(media.id) = location;
folderPaths.append(location); folderPaths.append(location);
emulator = &emulator_; emulator = &interface;
connectDevices(); //(expansion port) devices must be connected prior to load
emulator->load(media.id); emulator->load(media.id);
dsp.setFrequency(emulator->audioFrequency()); updateAudio(); //audio must be updated after load (audio frequency varies by region)
emulator->power(); emulator->power();
presentation->resizeViewport(); presentation->resizeViewport();

View File

@ -30,6 +30,7 @@ struct Program : Emulator::Interface::Bind {
//utility.cpp //utility.cpp
auto powerCycle() -> void; auto powerCycle() -> void;
auto softReset() -> void; auto softReset() -> void;
auto connectDevices() -> void;
auto showMessage(const string& text) -> void; auto showMessage(const string& text) -> void;
auto updateStatusText() -> void; auto updateStatusText() -> void;
auto updateVideoShader() -> void; auto updateVideoShader() -> void;

View File

@ -11,6 +11,20 @@ auto Program::softReset() -> void {
showMessage("System reset"); showMessage("System reset");
} }
auto Program::connectDevices() -> void {
if(!emulator) return;
for(auto& port : emulator->port) {
auto path = string{emulator->information.name, "/", port.name}.replace(" ", "");
auto name = settings(path).text();
for(auto& device : port.device) {
if(device.name == name) {
emulator->connect(port.id, device.id);
break;
}
}
}
}
auto Program::showMessage(const string& text) -> void { auto Program::showMessage(const string& text) -> void {
statusTime = time(0); statusTime = time(0);
statusMessage = text; statusMessage = text;
@ -52,8 +66,8 @@ auto Program::updateVideoShader() -> void {
auto Program::updateAudio() -> void { auto Program::updateAudio() -> void {
if(!audio) return; if(!audio) return;
audio->clear(); audio->clear();
audio->set(Audio::Frequency, settings["Audio/Frequency"].natural()); audio->set(Audio::Frequency, (uint)settings["Audio/Frequency"].natural());
audio->set(Audio::Latency, settings["Audio/Latency"].natural()); audio->set(Audio::Latency, (uint)settings["Audio/Latency"].natural());
if(settings["Audio/Resampler"].text() == "Linear" ) dsp.setResampler(DSP::ResampleEngine::Linear); if(settings["Audio/Resampler"].text() == "Linear" ) dsp.setResampler(DSP::ResampleEngine::Linear);
if(settings["Audio/Resampler"].text() == "Hermite") dsp.setResampler(DSP::ResampleEngine::Hermite); if(settings["Audio/Resampler"].text() == "Hermite") dsp.setResampler(DSP::ResampleEngine::Hermite);
if(settings["Audio/Resampler"].text() == "Sinc" ) dsp.setResampler(DSP::ResampleEngine::Sinc); if(settings["Audio/Resampler"].text() == "Sinc" ) dsp.setResampler(DSP::ResampleEngine::Sinc);
@ -72,5 +86,6 @@ auto Program::updateDSP() -> void {
double inputRatio = emulator->audioFrequency() / emulator->videoFrequency(); double inputRatio = emulator->audioFrequency() / emulator->videoFrequency();
double outputRatio = settings["Timing/Audio"].real() / settings["Timing/Video"].real(); double outputRatio = settings["Timing/Audio"].real() / settings["Timing/Video"].real();
dsp.setFrequency(inputRatio / outputRatio * settings["Audio/Frequency"].natural()); dsp.setFrequency(inputRatio / outputRatio * settings["Audio/Frequency"].natural());
} }

View File

@ -5,10 +5,6 @@ namespace WonderSwan {
Cartridge cartridge; Cartridge cartridge;
#include "memory.cpp" #include "memory.cpp"
auto Cartridge::loaded() const -> bool {
return _loaded;
}
auto Cartridge::load() -> void { auto Cartridge::load() -> void {
information.manifest = ""; information.manifest = "";
information.title = ""; information.title = "";
@ -35,12 +31,9 @@ auto Cartridge::load() -> void {
information.title = document["information/title"].text(); information.title = document["information/title"].text();
information.sha256 = Hash::SHA256(rom.data, rom.size).digest(); information.sha256 = Hash::SHA256(rom.data, rom.size).digest();
_loaded = true;
} }
auto Cartridge::unload() -> void { auto Cartridge::unload() -> void {
_loaded = false;
delete[] rom.data; delete[] rom.data;
rom.data = nullptr; rom.data = nullptr;
rom.size = 0; rom.size = 0;

View File

@ -1,6 +1,4 @@
struct Cartridge : IO { struct Cartridge : IO {
auto loaded() const -> bool;
auto load() -> void; auto load() -> void;
auto unload() -> void; auto unload() -> void;
auto power() -> void; auto power() -> void;
@ -33,9 +31,6 @@ struct Cartridge : IO {
string title; string title;
string sha256; string sha256;
} information; } information;
privileged:
bool _loaded = false;
}; };
extern Cartridge cartridge; extern Cartridge cartridge;

View File

@ -75,7 +75,7 @@ auto Interface::audioFrequency() -> double {
} }
auto Interface::loaded() -> bool { auto Interface::loaded() -> bool {
return cartridge.loaded(); return system.loaded();
} }
auto Interface::sha256() -> string { auto Interface::sha256() -> string {

View File

@ -4,9 +4,8 @@ namespace WonderSwan {
System system; System system;
auto System::revision() const -> Revision { auto System::loaded() const -> bool { return _loaded; }
return _revision; auto System::revision() const -> Revision { return _revision; }
}
auto System::init() -> void { auto System::init() -> void {
} }
@ -23,6 +22,13 @@ auto System::load(Revision revision) -> void {
//note: IPLROM is currently undumped; otherwise we'd load it here ... //note: IPLROM is currently undumped; otherwise we'd load it here ...
cartridge.load(); cartridge.load();
_loaded = true;
}
auto System::unload() -> void {
if(!loaded()) return;
cartridge.unload();
_loaded = false;
} }
auto System::power() -> void { auto System::power() -> void {

View File

@ -5,11 +5,13 @@ struct System {
SwanCrystal, //SCT-001 (SPHINX2) SwanCrystal, //SCT-001 (SPHINX2)
}; };
auto loaded() const -> bool;
auto revision() const -> Revision; auto revision() const -> Revision;
auto init() -> void; auto init() -> void;
auto term() -> void; auto term() -> void;
auto load(Revision) -> void; auto load(Revision) -> void;
auto unload() -> void;
auto power() -> void; auto power() -> void;
auto run() -> void; auto run() -> void;
@ -18,6 +20,7 @@ struct System {
} information; } information;
privileged: privileged:
bool _loaded = false;
Revision _revision = Revision::WonderSwan; Revision _revision = Revision::WonderSwan;
}; };

View File

@ -7827,7 +7827,7 @@ cartridge sha256:4d7fc331a811b8dc630b469262fd6f45e289243cef83101f32038158967d1b2
: map address=40-7d,c0-ff:0000-7fff mask=0x8000 : map address=40-7d,c0-ff:0000-7fff mask=0x8000
: icd2 revision=1 : icd2 revision=1
: map address=00-3f,80-bf:6000-67ff,7000-7fff : map address=00-3f,80-bf:6000-67ff,7000-7fff
: brom name=sgb.boot.rom size=0x100 : rom name=sgb.boot.rom size=0x100
: :
:information :information
: serial: SNS-A-SG-USA : serial: SNS-A-SG-USA

View File

@ -218,7 +218,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size, bool
" map address=40-7d,c0-ff:0000-7fff mask=0x8000\n" " map address=40-7d,c0-ff:0000-7fff mask=0x8000\n"
" icd2 revision=1\n" " icd2 revision=1\n"
" map address=00-3f,80-bf:6000-67ff,7000-7fff\n" " map address=00-3f,80-bf:6000-67ff,7000-7fff\n"
" brom name=sgb.boot.rom size=0x100\n" " rom name=sgb.boot.rom size=0x100\n"
); );
} }

View File

@ -8,18 +8,16 @@ using namespace nall;
#include <sys/resource.h> #include <sys/resource.h>
#include <sys/time.h> #include <sys/time.h>
#define usartproc dllexport
static function<auto () -> bool> usart_quit; static function<auto () -> bool> usart_quit;
static function<auto (uint milliseconds) -> void> usart_usleep; static function<auto (uint microseconds) -> void> usart_usleep;
static function<auto () -> bool> usart_readable; static function<auto () -> bool> usart_readable;
static function<auto () -> uint8> usart_read; static function<auto () -> uint8> usart_read;
static function<auto () -> bool> usart_writable; static function<auto () -> bool> usart_writable;
static function<auto (uint8 data) -> void> usart_write; static function<auto (uint8 data) -> void> usart_write;
extern "C" usartproc auto usart_init( extern "C" auto usart_init(
function<auto () -> bool> quit, function<auto () -> bool> quit,
function<auto (uint milliseconds) -> void> usleep, function<auto (uint microseconds) -> void> usleep,
function<auto () -> bool> readable, function<auto () -> bool> readable,
function<auto () -> uint8> read, function<auto () -> uint8> read,
function<auto () -> bool> writable, function<auto () -> bool> writable,
@ -33,7 +31,7 @@ extern "C" usartproc auto usart_init(
usart_write = write; usart_write = write;
} }
extern "C" usartproc auto usart_main(nall::lstring) -> void; extern "C" auto usart_main(nall::lstring) -> void;
// //
@ -51,8 +49,8 @@ static auto usarthw_quit() -> bool {
return usart_sigint; return usart_sigint;
} }
static auto usarthw_usleep(uint milliseconds) -> void { static auto usarthw_usleep(uint microseconds) -> void {
usleep(milliseconds); usleep(microseconds);
} }
static auto usarthw_readable() -> bool { static auto usarthw_readable() -> bool {