mirror of
https://github.com/libretro/bsnes-libretro.git
synced 2024-11-27 02:50:32 +00:00
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:
parent
a89a3da77a
commit
32a95a9761
@ -6,7 +6,7 @@ using namespace nall;
|
||||
|
||||
namespace Emulator {
|
||||
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 License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
@ -6,10 +6,6 @@ namespace Famicom {
|
||||
#include "board/board.cpp"
|
||||
Cartridge cartridge;
|
||||
|
||||
auto Cartridge::loaded() const -> bool {
|
||||
return _loaded;
|
||||
}
|
||||
|
||||
auto Cartridge::sha256() const -> string {
|
||||
return _sha256;
|
||||
}
|
||||
@ -40,14 +36,9 @@ auto Cartridge::load() -> void {
|
||||
sha.data(board->prgrom.data, board->prgrom.size);
|
||||
sha.data(board->chrrom.data, board->chrrom.size);
|
||||
_sha256 = sha.digest();
|
||||
|
||||
system.load();
|
||||
_loaded = true;
|
||||
}
|
||||
|
||||
auto Cartridge::unload() -> void {
|
||||
if(!loaded()) return;
|
||||
_loaded = false;
|
||||
memory.reset();
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,6 @@ struct Cartridge : Thread {
|
||||
static auto Main() -> void;
|
||||
auto main() -> void;
|
||||
|
||||
auto loaded() const -> bool;
|
||||
auto sha256() const -> string;
|
||||
auto manifest() const -> string;
|
||||
auto title() const -> string;
|
||||
@ -31,7 +30,6 @@ struct Cartridge : Thread {
|
||||
|
||||
//privileged:
|
||||
Board* board = nullptr;
|
||||
bool _loaded = false;
|
||||
string _sha256;
|
||||
|
||||
auto prg_read(uint addr) -> uint8;
|
||||
|
@ -63,7 +63,7 @@ auto Interface::audioFrequency() -> double {
|
||||
}
|
||||
|
||||
auto Interface::loaded() -> bool {
|
||||
return cartridge.loaded();
|
||||
return system.loaded();
|
||||
}
|
||||
|
||||
auto Interface::sha256() -> string {
|
||||
@ -86,7 +86,7 @@ auto Interface::group(uint id) -> uint {
|
||||
}
|
||||
|
||||
auto Interface::load(uint id) -> void {
|
||||
cartridge.load();
|
||||
system.load();
|
||||
}
|
||||
|
||||
auto Interface::save() -> void {
|
||||
@ -133,7 +133,7 @@ auto Interface::save(uint id, const stream& stream) -> void {
|
||||
|
||||
auto Interface::unload() -> void {
|
||||
save();
|
||||
cartridge.unload();
|
||||
system.unload();
|
||||
}
|
||||
|
||||
auto Interface::power() -> void {
|
||||
@ -149,7 +149,7 @@ auto Interface::run() -> void {
|
||||
}
|
||||
|
||||
auto Interface::serialize() -> serializer {
|
||||
system.runtosave();
|
||||
system.runToSave();
|
||||
return system.serialize();
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
auto System::serialize() -> serializer {
|
||||
serializer s(serialize_size);
|
||||
serializer s(_serializeSize);
|
||||
|
||||
uint signature = 0x31545342, version = Info::SerializerVersion;
|
||||
char hash[64], description[512];
|
||||
@ -11,7 +11,7 @@ auto System::serialize() -> serializer {
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
serialize_all(s);
|
||||
serializeAll(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -28,14 +28,14 @@ auto System::unserialize(serializer& s) -> bool {
|
||||
if(version != Info::SerializerVersion) return false;
|
||||
|
||||
power();
|
||||
serialize_all(s);
|
||||
serializeAll(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto System::serialize(serializer& s) -> void {
|
||||
}
|
||||
|
||||
auto System::serialize_all(serializer& s) -> void {
|
||||
auto System::serializeAll(serializer& s) -> void {
|
||||
system.serialize(s);
|
||||
input.serialize(s);
|
||||
cartridge.serialize(s);
|
||||
@ -44,7 +44,7 @@ auto System::serialize_all(serializer& s) -> void {
|
||||
ppu.serialize(s);
|
||||
}
|
||||
|
||||
auto System::serialize_init() -> void {
|
||||
auto System::serializeInit() -> void {
|
||||
serializer s;
|
||||
|
||||
uint signature = 0, version = 0;
|
||||
@ -55,6 +55,6 @@ auto System::serialize_init() -> void {
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
serialize_all(s);
|
||||
serialize_size = s.size();
|
||||
serializeAll(s);
|
||||
_serializeSize = s.size();
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ namespace Famicom {
|
||||
#include "serialization.cpp"
|
||||
System system;
|
||||
|
||||
auto System::loaded() const -> bool { return _loaded; }
|
||||
|
||||
auto System::run() -> void {
|
||||
scheduler.enter();
|
||||
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;
|
||||
runthreadtosave();
|
||||
runThreadToSave();
|
||||
|
||||
scheduler.sync = Scheduler::SynchronizeMode::All;
|
||||
scheduler.thread = cpu.thread;
|
||||
runthreadtosave();
|
||||
runThreadToSave();
|
||||
|
||||
scheduler.sync = Scheduler::SynchronizeMode::All;
|
||||
scheduler.thread = apu.thread;
|
||||
runthreadtosave();
|
||||
runThreadToSave();
|
||||
|
||||
scheduler.sync = Scheduler::SynchronizeMode::All;
|
||||
scheduler.thread = cartridge.thread;
|
||||
runthreadtosave();
|
||||
runThreadToSave();
|
||||
|
||||
scheduler.sync = Scheduler::SynchronizeMode::None;
|
||||
}
|
||||
|
||||
auto System::runthreadtosave() -> void {
|
||||
auto System::runThreadToSave() -> void {
|
||||
while(true) {
|
||||
scheduler.enter();
|
||||
if(scheduler.exit_reason() == Scheduler::ExitReason::SynchronizeEvent) break;
|
||||
@ -44,8 +46,15 @@ auto System::runthreadtosave() -> void {
|
||||
auto System::load() -> void {
|
||||
interface->loadRequest(ID::SystemManifest, "manifest.bml", true);
|
||||
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 {
|
||||
|
@ -1,9 +1,12 @@
|
||||
struct System {
|
||||
auto loaded() const -> bool;
|
||||
|
||||
auto run() -> void;
|
||||
auto runtosave() -> void;
|
||||
auto runthreadtosave() -> void;
|
||||
auto runToSave() -> void;
|
||||
auto runThreadToSave() -> void;
|
||||
|
||||
auto load() -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
@ -14,14 +17,16 @@ struct System {
|
||||
auto unserialize(serializer&) -> bool;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
auto serialize_all(serializer&) -> void;
|
||||
auto serialize_init() -> void;
|
||||
auto serializeAll(serializer&) -> void;
|
||||
auto serializeInit() -> void;
|
||||
|
||||
struct Information {
|
||||
string manifest;
|
||||
} information;
|
||||
|
||||
uint serialize_size;
|
||||
private:
|
||||
bool _loaded = false;
|
||||
uint _serializeSize = 0;
|
||||
};
|
||||
|
||||
extern System system;
|
||||
|
@ -13,15 +13,6 @@ namespace GameBoy {
|
||||
#include "serialization.cpp"
|
||||
Cartridge cartridge;
|
||||
|
||||
Cartridge::Cartridge() {
|
||||
loaded = false;
|
||||
sha256 = "";
|
||||
}
|
||||
|
||||
Cartridge::~Cartridge() {
|
||||
unload();
|
||||
}
|
||||
|
||||
auto Cartridge::manifest() const -> string {
|
||||
return information.markup;
|
||||
}
|
||||
@ -30,25 +21,9 @@ auto Cartridge::title() const -> string {
|
||||
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 {
|
||||
unload();
|
||||
|
||||
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.markup = "";
|
||||
interface->loadRequest(ID::Manifest, "manifest.bml", !system.sgb());
|
||||
|
||||
information.mapper = Mapper::Unknown;
|
||||
information.ram = false;
|
||||
@ -78,21 +53,18 @@ auto Cartridge::load(System::Revision revision) -> void {
|
||||
auto rom = document["board/rom"];
|
||||
auto ram = document["board/ram"];
|
||||
|
||||
romsize = rom["size"].natural();
|
||||
romsize = max(32768u, rom["size"].natural());
|
||||
romdata = allocate<uint8>(romsize, 0xff);
|
||||
|
||||
ramsize = ram["size"].natural();
|
||||
ramdata = allocate<uint8>(ramsize, 0xff);
|
||||
|
||||
//Super Game Boy core loads memory from Super Famicom core
|
||||
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()) memory.append({ID::RAM, name});
|
||||
}
|
||||
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});
|
||||
|
||||
information.romsize = rom["size"].natural();
|
||||
information.ramsize = ram["size"].natural();
|
||||
information.romsize = romsize;
|
||||
information.ramsize = ramsize;
|
||||
information.battery = (bool)ram["name"];
|
||||
|
||||
switch(information.mapper) { default:
|
||||
@ -107,14 +79,11 @@ auto Cartridge::load(System::Revision revision) -> void {
|
||||
}
|
||||
|
||||
sha256 = Hash::SHA256(romdata, romsize).digest();
|
||||
loaded = true;
|
||||
system.load(revision);
|
||||
}
|
||||
|
||||
auto Cartridge::unload() -> void {
|
||||
if(romdata) { delete[] romdata; romdata = nullptr; romsize = 0; }
|
||||
if(ramdata) { delete[] ramdata; ramdata = nullptr; ramsize = 0; }
|
||||
loaded = false;
|
||||
}
|
||||
|
||||
auto Cartridge::rom_read(uint addr) -> uint8 {
|
||||
@ -144,7 +113,7 @@ auto Cartridge::mmio_read(uint16 addr) -> uint8 {
|
||||
|
||||
if(bootrom_enable) {
|
||||
const uint8* data = nullptr;
|
||||
switch(system.revision) { default:
|
||||
switch(system.revision()) { default:
|
||||
case System::Revision::GameBoy: data = system.bootROM.dmg; break;
|
||||
case System::Revision::SuperGameBoy: data = system.bootROM.sgb; break;
|
||||
case System::Revision::GameBoyColor: data = system.bootROM.cgb; break;
|
||||
|
@ -1,8 +1,4 @@
|
||||
struct Cartridge : MMIO, property<Cartridge> {
|
||||
Cartridge();
|
||||
~Cartridge();
|
||||
|
||||
auto load_empty(System::Revision revision) -> void;
|
||||
auto load(System::Revision revision) -> void;
|
||||
auto unload() -> void;
|
||||
|
||||
@ -62,7 +58,6 @@ struct Cartridge : MMIO, property<Cartridge> {
|
||||
};
|
||||
vector<Memory> memory;
|
||||
|
||||
readonly<bool> loaded;
|
||||
readonly<string> sha256;
|
||||
|
||||
uint8* romdata = nullptr;
|
||||
|
@ -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::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
|
||||
//however, Super Game Boy BIOS is able to set these bits together
|
||||
if(dpad & 4) dpad &= ~8; //disallow up+down
|
||||
|
@ -3,7 +3,7 @@
|
||||
// 154 scanlines/frame
|
||||
|
||||
auto CPU::add_clocks(uint clocks) -> void {
|
||||
if(system.sgb()) system.clocks_executed += clocks;
|
||||
if(system.sgb()) system._clocksExecuted += clocks;
|
||||
|
||||
while(clocks--) {
|
||||
if(++status.clock == 0) {
|
||||
|
@ -57,7 +57,7 @@ auto Interface::audioFrequency() -> double {
|
||||
}
|
||||
|
||||
auto Interface::loaded() -> bool {
|
||||
return cartridge.loaded();
|
||||
return system.loaded();
|
||||
}
|
||||
|
||||
auto Interface::sha256() -> string {
|
||||
@ -74,7 +74,7 @@ auto Interface::group(uint id) -> uint {
|
||||
case ID::Manifest:
|
||||
case ID::ROM:
|
||||
case ID::RAM:
|
||||
switch(system.revision) {
|
||||
switch(system.revision()) {
|
||||
case System::Revision::GameBoy: return ID::GameBoy;
|
||||
case System::Revision::SuperGameBoy: return ID::SuperGameBoy;
|
||||
case System::Revision::GameBoyColor: return ID::GameBoyColor;
|
||||
@ -85,9 +85,9 @@ auto Interface::group(uint id) -> uint {
|
||||
}
|
||||
|
||||
auto Interface::load(uint id) -> void {
|
||||
if(id == ID::GameBoy) cartridge.load(System::Revision::GameBoy);
|
||||
if(id == ID::SuperGameBoy) cartridge.load(System::Revision::SuperGameBoy);
|
||||
if(id == ID::GameBoyColor) cartridge.load(System::Revision::GameBoyColor);
|
||||
if(id == ID::GameBoy) system.load(System::Revision::GameBoy);
|
||||
if(id == ID::SuperGameBoy) system.load(System::Revision::SuperGameBoy);
|
||||
if(id == ID::GameBoyColor) system.load(System::Revision::GameBoyColor);
|
||||
}
|
||||
|
||||
auto Interface::save() -> void {
|
||||
@ -134,7 +134,7 @@ auto Interface::save(uint id, const stream& stream) -> void {
|
||||
|
||||
auto Interface::unload() -> void {
|
||||
save();
|
||||
cartridge.unload();
|
||||
system.unload();
|
||||
}
|
||||
|
||||
auto Interface::power() -> void {
|
||||
@ -150,7 +150,7 @@ auto Interface::run() -> void {
|
||||
}
|
||||
|
||||
auto Interface::serialize() -> serializer {
|
||||
system.runtosave();
|
||||
system.runToSave();
|
||||
return system.serialize();
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
auto System::serialize() -> serializer {
|
||||
serializer s(serialize_size);
|
||||
serializer s(_serializeSize);
|
||||
|
||||
uint signature = 0x31545342, version = Info::SerializerVersion;
|
||||
char hash[64], description[512];
|
||||
@ -11,7 +11,7 @@ auto System::serialize() -> serializer {
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
serialize_all(s);
|
||||
serializeAll(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -28,15 +28,15 @@ auto System::unserialize(serializer& s) -> bool {
|
||||
if(version != Info::SerializerVersion) return false;
|
||||
|
||||
power();
|
||||
serialize_all(s);
|
||||
serializeAll(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
system.serialize(s);
|
||||
cpu.serialize(s);
|
||||
@ -44,7 +44,7 @@ auto System::serialize_all(serializer& s) -> void {
|
||||
apu.serialize(s);
|
||||
}
|
||||
|
||||
auto System::serialize_init() -> void {
|
||||
auto System::serializeInit() -> void {
|
||||
serializer s;
|
||||
|
||||
uint signature = 0, version = 0, crc32 = 0;
|
||||
@ -55,6 +55,6 @@ auto System::serialize_init() -> void {
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
serialize_all(s);
|
||||
serialize_size = s.size();
|
||||
serializeAll(s);
|
||||
_serializeSize = s.size();
|
||||
}
|
||||
|
@ -5,6 +5,10 @@ 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;
|
||||
@ -20,22 +24,22 @@ auto System::run() -> void {
|
||||
}
|
||||
}
|
||||
|
||||
auto System::runtosave() -> void {
|
||||
auto System::runToSave() -> void {
|
||||
scheduler.sync = Scheduler::SynchronizeMode::CPU;
|
||||
runthreadtosave();
|
||||
runThreadToSave();
|
||||
|
||||
scheduler.sync = Scheduler::SynchronizeMode::All;
|
||||
scheduler.active_thread = ppu.thread;
|
||||
runthreadtosave();
|
||||
runThreadToSave();
|
||||
|
||||
scheduler.sync = Scheduler::SynchronizeMode::All;
|
||||
scheduler.active_thread = apu.thread;
|
||||
runthreadtosave();
|
||||
runThreadToSave();
|
||||
|
||||
scheduler.sync = Scheduler::SynchronizeMode::None;
|
||||
}
|
||||
|
||||
auto System::runthreadtosave() -> void {
|
||||
auto System::runThreadToSave() -> void {
|
||||
while(true) {
|
||||
scheduler.enter();
|
||||
if(scheduler.exit_reason == Scheduler::ExitReason::SynchronizeEvent) break;
|
||||
@ -50,19 +54,32 @@ auto System::init() -> void {
|
||||
}
|
||||
|
||||
auto System::load(Revision revision) -> void {
|
||||
this->revision = revision;
|
||||
serialize_init();
|
||||
if(revision == Revision::SuperGameBoy) return; //Super Famicom core loads boot ROM for SGB
|
||||
_revision = revision;
|
||||
|
||||
interface->loadRequest(ID::SystemManifest, "manifest.bml", true);
|
||||
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(
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
cartridge.load(revision);
|
||||
serializeInit();
|
||||
_loaded = true;
|
||||
}
|
||||
|
||||
auto System::unload() -> void {
|
||||
if(!loaded()) return;
|
||||
cartridge.unload();
|
||||
_loaded = false;
|
||||
}
|
||||
|
||||
auto System::power() -> void {
|
||||
@ -74,7 +91,7 @@ auto System::power() -> void {
|
||||
video.power();
|
||||
scheduler.init();
|
||||
|
||||
clocks_executed = 0;
|
||||
_clocksExecuted = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,20 +9,25 @@ struct System {
|
||||
GameBoy,
|
||||
SuperGameBoy,
|
||||
GameBoyColor,
|
||||
} revision;
|
||||
};
|
||||
|
||||
System();
|
||||
|
||||
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 loaded() const -> bool;
|
||||
auto revision() const -> Revision;
|
||||
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 runtosave() -> void;
|
||||
auto runthreadtosave() -> void;
|
||||
auto runToSave() -> void;
|
||||
auto runThreadToSave() -> void;
|
||||
|
||||
auto init() -> void;
|
||||
auto load(Revision) -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
|
||||
//serialization.cpp
|
||||
@ -30,8 +35,8 @@ struct System {
|
||||
auto unserialize(serializer&) -> bool;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
auto serialize_all(serializer&) -> void;
|
||||
auto serialize_init() -> void;
|
||||
auto serializeAll(serializer&) -> void;
|
||||
auto serializeInit() -> void;
|
||||
|
||||
struct BootROM {
|
||||
uint8 dmg[ 256];
|
||||
@ -43,8 +48,10 @@ struct System {
|
||||
string manifest;
|
||||
} information;
|
||||
|
||||
uint clocks_executed = 0;
|
||||
uint serialize_size = 0;
|
||||
bool _loaded = false;
|
||||
Revision _revision = Revision::GameBoy;
|
||||
uint _serializeSize = 0;
|
||||
uint _clocksExecuted = 0;
|
||||
};
|
||||
|
||||
#include <gb/interface/interface.hpp>
|
||||
|
@ -23,10 +23,6 @@ Cartridge::~Cartridge() {
|
||||
delete[] flash.data;
|
||||
}
|
||||
|
||||
auto Cartridge::loaded() const -> bool {
|
||||
return isLoaded;
|
||||
}
|
||||
|
||||
auto Cartridge::sha256() const -> string {
|
||||
return information.sha256;
|
||||
}
|
||||
@ -96,16 +92,10 @@ auto Cartridge::load() -> void {
|
||||
}
|
||||
|
||||
information.sha256 = Hash::SHA256(mrom.data, mrom.size).digest();
|
||||
|
||||
system.load();
|
||||
isLoaded = true;
|
||||
}
|
||||
|
||||
auto Cartridge::unload() -> void {
|
||||
if(isLoaded) {
|
||||
isLoaded = false;
|
||||
memory.reset();
|
||||
}
|
||||
memory.reset();
|
||||
}
|
||||
|
||||
auto Cartridge::power() -> void {
|
||||
|
@ -1,7 +1,6 @@
|
||||
struct Cartridge {
|
||||
#include "memory.hpp"
|
||||
|
||||
auto loaded() const -> bool;
|
||||
auto sha256() const -> string;
|
||||
auto manifest() const -> string;
|
||||
auto title() const -> string;
|
||||
@ -31,7 +30,6 @@ struct Cartridge {
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
private:
|
||||
bool isLoaded = false;
|
||||
bool hasSRAM = false;
|
||||
bool hasEEPROM = false;
|
||||
bool hasFLASH = false;
|
||||
|
@ -57,7 +57,7 @@ auto Interface::audioFrequency() -> double {
|
||||
}
|
||||
|
||||
auto Interface::loaded() -> bool {
|
||||
return cartridge.loaded();
|
||||
return system.loaded();
|
||||
}
|
||||
|
||||
auto Interface::group(uint id) -> uint {
|
||||
@ -77,7 +77,7 @@ auto Interface::group(uint id) -> uint {
|
||||
}
|
||||
|
||||
auto Interface::load(uint id) -> void {
|
||||
cartridge.load();
|
||||
system.load();
|
||||
}
|
||||
|
||||
auto Interface::save() -> void {
|
||||
@ -132,7 +132,7 @@ auto Interface::save(uint id, const stream& stream) -> void {
|
||||
|
||||
auto Interface::unload() -> void {
|
||||
save();
|
||||
cartridge.unload();
|
||||
system.unload();
|
||||
}
|
||||
|
||||
auto Interface::power() -> void {
|
||||
@ -148,7 +148,7 @@ auto Interface::run() -> void {
|
||||
}
|
||||
|
||||
auto Interface::serialize() -> serializer {
|
||||
system.runtosave();
|
||||
system.runToSave();
|
||||
return system.serialize();
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
auto System::serialize() -> serializer {
|
||||
serializer s(serialize_size);
|
||||
serializer s(_serializeSize);
|
||||
|
||||
uint signature = 0x31545342, version = Info::SerializerVersion;
|
||||
char hash[64], description[512];
|
||||
@ -11,7 +11,7 @@ auto System::serialize() -> serializer {
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
serialize_all(s);
|
||||
serializeAll(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ auto System::unserialize(serializer& s) -> bool {
|
||||
if(version != Info::SerializerVersion) return false;
|
||||
|
||||
power();
|
||||
serialize_all(s);
|
||||
serializeAll(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ auto System::serialize(serializer& s) -> void {
|
||||
s.integer(bios.mdr);
|
||||
}
|
||||
|
||||
auto System::serialize_all(serializer& s) -> void {
|
||||
auto System::serializeAll(serializer& s) -> void {
|
||||
cartridge.serialize(s);
|
||||
system.serialize(s);
|
||||
cpu.serialize(s);
|
||||
@ -46,7 +46,7 @@ auto System::serialize_all(serializer& s) -> void {
|
||||
player.serialize(s);
|
||||
}
|
||||
|
||||
auto System::serialize_init() -> void {
|
||||
auto System::serializeInit() -> void {
|
||||
serializer s;
|
||||
|
||||
uint signature = 0, version = 0;
|
||||
@ -57,6 +57,6 @@ auto System::serialize_init() -> void {
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
serialize_all(s);
|
||||
serialize_size = s.size();
|
||||
serializeAll(s);
|
||||
_serializeSize = s.size();
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ namespace GameBoyAdvance {
|
||||
BIOS bios;
|
||||
System system;
|
||||
|
||||
auto System::loaded() const -> bool { return _loaded; }
|
||||
|
||||
auto System::init() -> void {
|
||||
}
|
||||
|
||||
@ -32,7 +34,15 @@ auto System::load() -> void {
|
||||
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 {
|
||||
@ -43,22 +53,22 @@ auto System::run() -> void {
|
||||
video.refresh();
|
||||
}
|
||||
|
||||
auto System::runtosave() -> void {
|
||||
auto System::runToSave() -> void {
|
||||
scheduler.sync = Scheduler::SynchronizeMode::CPU;
|
||||
runthreadtosave();
|
||||
runThreadToSave();
|
||||
|
||||
scheduler.sync = Scheduler::SynchronizeMode::All;
|
||||
scheduler.active = ppu.thread;
|
||||
runthreadtosave();
|
||||
runThreadToSave();
|
||||
|
||||
scheduler.sync = Scheduler::SynchronizeMode::All;
|
||||
scheduler.active = apu.thread;
|
||||
runthreadtosave();
|
||||
runThreadToSave();
|
||||
|
||||
scheduler.sync = Scheduler::SynchronizeMode::None;
|
||||
}
|
||||
|
||||
auto System::runthreadtosave() -> void {
|
||||
auto System::runThreadToSave() -> void {
|
||||
while(true) {
|
||||
scheduler.enter();
|
||||
if(scheduler.exit_reason() == Scheduler::ExitReason::SynchronizeEvent) break;
|
||||
|
@ -15,26 +15,30 @@ struct BIOS : Memory {
|
||||
};
|
||||
|
||||
struct System {
|
||||
auto loaded() const -> bool;
|
||||
|
||||
auto init() -> void;
|
||||
auto term() -> void;
|
||||
auto load() -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
auto run() -> void;
|
||||
auto runtosave() -> void;
|
||||
auto runthreadtosave() -> void;
|
||||
auto runToSave() -> void;
|
||||
auto runThreadToSave() -> void;
|
||||
|
||||
auto serialize() -> serializer;
|
||||
auto unserialize(serializer&) -> bool;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
auto serialize_all(serializer&) -> void;
|
||||
auto serialize_init() -> void;
|
||||
auto serializeAll(serializer&) -> void;
|
||||
auto serializeInit() -> void;
|
||||
|
||||
struct Information {
|
||||
string manifest;
|
||||
} information;
|
||||
|
||||
uint serialize_size;
|
||||
bool _loaded = false;
|
||||
uint _serializeSize = 0;
|
||||
};
|
||||
|
||||
extern BIOS bios;
|
||||
|
@ -94,7 +94,7 @@ auto Cartridge::load() -> void {
|
||||
|
||||
//Game Boy
|
||||
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
|
||||
@ -136,25 +136,13 @@ auto Cartridge::load() -> void {
|
||||
|
||||
rom.write_protect(true);
|
||||
ram.write_protect(false);
|
||||
|
||||
system.load();
|
||||
_loaded = true;
|
||||
}
|
||||
|
||||
auto Cartridge::loadGameBoy() -> void {
|
||||
interface->loadRequest(ID::GameBoyManifest, "manifest.bml", true);
|
||||
auto document = BML::unserialize(information.markup.gameBoy);
|
||||
information.title.gameBoy = document["information/title"].text();
|
||||
|
||||
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});
|
||||
//invoked from ICD2::load()
|
||||
_sha256 = GameBoy::interface->sha256();
|
||||
information.markup.gameBoy = GameBoy::interface->manifest();
|
||||
information.title.gameBoy = GameBoy::interface->title();
|
||||
}
|
||||
|
||||
auto Cartridge::loadBSMemory() -> void {
|
||||
@ -182,13 +170,13 @@ auto Cartridge::loadSufamiTurboA() -> void {
|
||||
auto ram = document["board/ram"];
|
||||
|
||||
if(rom["name"]) {
|
||||
unsigned size = rom["size"].natural();
|
||||
uint size = rom["size"].natural();
|
||||
sufamiturboA.rom.map(allocate<uint8>(size, 0xff), size);
|
||||
interface->loadRequest(ID::SufamiTurboSlotAROM, rom["name"].text(), true);
|
||||
}
|
||||
|
||||
if(ram["name"]) {
|
||||
unsigned size = ram["size"].natural();
|
||||
uint size = ram["size"].natural();
|
||||
sufamiturboA.ram.map(allocate<uint8>(size, 0xff), size);
|
||||
interface->loadRequest(ID::SufamiTurboSlotARAM, ram["name"].text(), false);
|
||||
memory.append({ID::SufamiTurboSlotARAM, ram["name"].text()});
|
||||
@ -208,13 +196,13 @@ auto Cartridge::loadSufamiTurboB() -> void {
|
||||
auto ram = document["board/ram"];
|
||||
|
||||
if(rom["name"]) {
|
||||
unsigned size = rom["size"].natural();
|
||||
uint size = rom["size"].natural();
|
||||
sufamiturboB.rom.map(allocate<uint8>(size, 0xff), size);
|
||||
interface->loadRequest(ID::SufamiTurboSlotBROM, rom["name"].text(), true);
|
||||
}
|
||||
|
||||
if(ram["name"]) {
|
||||
unsigned size = ram["size"].natural();
|
||||
uint size = ram["size"].natural();
|
||||
sufamiturboB.ram.map(allocate<uint8>(size, 0xff), size);
|
||||
interface->loadRequest(ID::SufamiTurboSlotBRAM, ram["name"].text(), false);
|
||||
memory.append({ID::SufamiTurboSlotBRAM, ram["name"].text()});
|
||||
@ -222,14 +210,9 @@ auto Cartridge::loadSufamiTurboB() -> void {
|
||||
}
|
||||
|
||||
auto Cartridge::unload() -> void {
|
||||
if(_loaded) {
|
||||
system.unload();
|
||||
rom.reset();
|
||||
ram.reset();
|
||||
|
||||
_loaded = false;
|
||||
memory.reset();
|
||||
}
|
||||
rom.reset();
|
||||
ram.reset();
|
||||
memory.reset();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,6 @@
|
||||
struct Cartridge : property<Cartridge> {
|
||||
enum class Region : unsigned { NTSC, PAL };
|
||||
|
||||
Cartridge() = default;
|
||||
~Cartridge() { unload(); }
|
||||
|
||||
auto loaded() const -> bool { return _loaded; }
|
||||
auto sha256() const -> string { return _sha256; }
|
||||
auto region() const -> Region { return _region; }
|
||||
|
||||
@ -83,6 +79,7 @@ private:
|
||||
auto loadSufamiTurboA() -> void;
|
||||
auto loadSufamiTurboB() -> void;
|
||||
friend class Interface;
|
||||
friend class ICD2;
|
||||
|
||||
//markup.cpp
|
||||
auto parseMarkup(const string&) -> void;
|
||||
@ -110,7 +107,6 @@ private:
|
||||
auto parseMarkupOBC1(Markup::Node) -> void;
|
||||
auto parseMarkupMSU1(Markup::Node) -> void;
|
||||
|
||||
bool _loaded = false;
|
||||
string _sha256;
|
||||
Region _region = Region::NTSC;
|
||||
};
|
||||
|
@ -92,10 +92,7 @@ auto Cartridge::parseMarkupICD2(Markup::Node root) -> void {
|
||||
hasICD2 = true;
|
||||
icd2.revision = max(1, root["revision"].natural());
|
||||
|
||||
GameBoy::cartridge.load_empty(GameBoy::System::Revision::SuperGameBoy);
|
||||
interface->loadRequest(ID::GameBoy, "Game Boy", "gb", false);
|
||||
|
||||
interface->loadRequest(ID::SuperGameBoyBootROM, root["brom"]["name"].text(), true);
|
||||
//Game Boy core loads data through ICD2 interface
|
||||
|
||||
for(auto node : root.find("map")) {
|
||||
parseMarkupMap(node, {&ICD2::read, &icd2}, {&ICD2::write, &icd2});
|
||||
|
@ -13,22 +13,11 @@
|
||||
//Teensy D5 <> Teensy D7
|
||||
|
||||
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"};
|
||||
if(openAbsolute(filename)) {
|
||||
init = sym("usart_init");
|
||||
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::write, this}
|
||||
);
|
||||
main();
|
||||
main({});
|
||||
}
|
||||
while(true) step(10000000);
|
||||
while(true) step(10'000'000);
|
||||
}
|
||||
|
||||
auto USART::quit() -> bool {
|
||||
@ -56,8 +45,8 @@ auto USART::quit() -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto USART::usleep(unsigned milliseconds) -> void {
|
||||
step(10 * milliseconds);
|
||||
auto USART::usleep(uint microseconds) -> void {
|
||||
step(10 * microseconds);
|
||||
}
|
||||
|
||||
auto USART::readable() -> bool {
|
||||
@ -91,7 +80,7 @@ auto USART::data() -> uint2 {
|
||||
if(iobit()) {
|
||||
if(counter >= 16) return 1;
|
||||
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++;
|
||||
return result;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ struct USART : Controller, public library {
|
||||
auto enter() -> void;
|
||||
|
||||
auto quit() -> bool;
|
||||
auto usleep(unsigned milliseconds) -> void;
|
||||
auto usleep(uint microseconds) -> void;
|
||||
auto readable() -> bool;
|
||||
auto read() -> uint8;
|
||||
auto writable() -> bool;
|
||||
@ -15,26 +15,26 @@ struct USART : Controller, public library {
|
||||
auto latch(bool data) -> void;
|
||||
|
||||
private:
|
||||
bool latched;
|
||||
bool data1;
|
||||
bool data2;
|
||||
unsigned counter;
|
||||
bool latched = 0;
|
||||
bool data1 = 0;
|
||||
bool data2 = 0;
|
||||
uint counter = 0;
|
||||
|
||||
uint8 rxlength;
|
||||
uint8 rxdata;
|
||||
uint8 rxlength = 0;
|
||||
uint8 rxdata = 0;
|
||||
vector<uint8> rxbuffer;
|
||||
|
||||
uint8 txlength;
|
||||
uint8 txdata;
|
||||
uint8 txlength = 0;
|
||||
uint8 txdata = 0;
|
||||
vector<uint8> txbuffer;
|
||||
|
||||
function<void (
|
||||
function<bool ()>, //quit
|
||||
function<void (unsigned)>, //usleep
|
||||
function<bool ()>, //readable
|
||||
function<uint8 ()>, //read
|
||||
function<bool ()>, //writable
|
||||
function<void (uint8)> //write
|
||||
function<bool ()>, //quit
|
||||
function<void (uint)>, //usleep
|
||||
function<bool ()>, //readable
|
||||
function<uint8 ()>, //read
|
||||
function<bool ()>, //writable
|
||||
function<void (uint8)> //write
|
||||
)> init;
|
||||
function<void ()> main;
|
||||
function<void (lstring)> main;
|
||||
};
|
||||
|
@ -12,14 +12,14 @@ auto ICD2::Enter() -> void { icd2.enter(); }
|
||||
auto ICD2::enter() -> void {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
GameBoy::system.runtosave();
|
||||
GameBoy::system.runToSave();
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
if(r6003 & 0x80) {
|
||||
GameBoy::system.run();
|
||||
step(GameBoy::system.clocks_executed);
|
||||
GameBoy::system.clocks_executed = 0;
|
||||
step(GameBoy::system._clocksExecuted);
|
||||
GameBoy::system._clocksExecuted = 0;
|
||||
} else { //DMG halted
|
||||
audio.coprocessorSample(0, 0);
|
||||
step(1);
|
||||
@ -36,9 +36,13 @@ auto ICD2::load() -> void {
|
||||
hook = GameBoy::interface->hook;
|
||||
GameBoy::interface->bind = 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 {
|
||||
GameBoy::interface->unload();
|
||||
GameBoy::interface->bind = bind;
|
||||
GameBoy::interface->hook = hook;
|
||||
}
|
||||
|
@ -16,10 +16,11 @@ struct ICD2 : Emulator::Interface::Bind, GameBoy::Interface::Hook, Coprocessor {
|
||||
uint revision;
|
||||
|
||||
private:
|
||||
Emulator::Interface::Bind* bind = nullptr;
|
||||
GameBoy::Interface::Hook* hook = nullptr;
|
||||
#include "interface/interface.hpp"
|
||||
#include "mmio/mmio.hpp"
|
||||
|
||||
Emulator::Interface::Bind* bind = nullptr;
|
||||
GameBoy::Interface::Hook* hook = nullptr;
|
||||
};
|
||||
|
||||
extern ICD2 icd2;
|
||||
|
@ -85,8 +85,35 @@ auto ICD2::joypWrite(bool p15, bool p14) -> void {
|
||||
packetlock = true;
|
||||
}
|
||||
|
||||
auto ICD2::videoColor(uint source, uint16 red, uint16 green, uint16 blue) -> uint32 {
|
||||
return source;
|
||||
auto ICD2::loadRequest(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);
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -1,11 +1,14 @@
|
||||
auto lcdScanline() -> void;
|
||||
auto lcdOutput(uint2 color) -> void;
|
||||
auto joypWrite(bool p15, bool p14) -> void;
|
||||
auto lcdScanline() -> void override;
|
||||
auto lcdOutput(uint2 color) -> void override;
|
||||
auto joypWrite(bool p15, bool p14) -> void override;
|
||||
|
||||
auto videoColor(uint source, uint16 red, uint16 green, uint16 blue) -> uint32;
|
||||
auto videoRefresh(const uint32* data, uint pitch, uint width, uint height) -> void;
|
||||
auto audioSample(int16 lsample, int16 rsample) -> void;
|
||||
auto inputPoll(uint port, uint device, uint id) -> int16;
|
||||
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 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 {
|
||||
auto operator[](uint addr) -> uint8& { return data[addr & 15]; }
|
||||
|
@ -1,6 +1,6 @@
|
||||
auto ICD2::serialize(serializer& s) -> void {
|
||||
Thread::serialize(s);
|
||||
GameBoy::system.serialize_all(s);
|
||||
GameBoy::system.serializeAll(s);
|
||||
|
||||
for(auto n : range(64)) s.array(packet[n].data);
|
||||
s.integer(packetsize);
|
||||
|
@ -154,7 +154,7 @@ auto Interface::audioFrequency() -> double {
|
||||
}
|
||||
|
||||
auto Interface::loaded() -> bool {
|
||||
return cartridge.loaded();
|
||||
return system.loaded();
|
||||
}
|
||||
|
||||
auto Interface::sha256() -> string {
|
||||
@ -200,6 +200,7 @@ auto Interface::group(uint id) -> uint {
|
||||
case ID::SDD1ROM:
|
||||
case ID::SDD1RAM:
|
||||
case ID::OBC1RAM:
|
||||
case ID::SuperGameBoyManifest:
|
||||
case ID::SuperGameBoyBootROM:
|
||||
case ID::MCCROM:
|
||||
case ID::MCCRAM:
|
||||
@ -229,8 +230,7 @@ auto Interface::group(uint id) -> uint {
|
||||
}
|
||||
|
||||
auto Interface::load(uint id) -> void {
|
||||
if(id == ID::SuperFamicom) cartridge.load();
|
||||
if(id == ID::GameBoy) cartridge.loadGameBoy();
|
||||
if(id == ID::SuperFamicom) system.load();
|
||||
if(id == ID::BSMemory) cartridge.loadBSMemory();
|
||||
if(id == ID::SufamiTurboSlotA) cartridge.loadSufamiTurboA();
|
||||
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::SuperGameBoyBootROM) {
|
||||
stream.read(GameBoy::system.bootROM.sgb, min(stream.size(), 256u));
|
||||
}
|
||||
|
||||
if(id == ID::MCCROM) mcc.rom.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) {
|
||||
stream.read(GameBoy::cartridge.romdata, min(GameBoy::cartridge.romsize, stream.size()));
|
||||
GameBoy::interface->load(GameBoy::ID::ROM, stream);
|
||||
}
|
||||
|
||||
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();
|
||||
@ -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::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());
|
||||
|
||||
@ -405,7 +413,7 @@ auto Interface::save(uint id, const stream& stream) -> void {
|
||||
|
||||
auto Interface::unload() -> void {
|
||||
save();
|
||||
cartridge.unload();
|
||||
system.unload();
|
||||
}
|
||||
|
||||
auto Interface::connect(uint port, uint device) -> void {
|
||||
|
@ -60,11 +60,12 @@ struct ID {
|
||||
|
||||
OBC1RAM,
|
||||
|
||||
SuperGameBoyBootROM,
|
||||
|
||||
MCCROM,
|
||||
MCCRAM,
|
||||
|
||||
SuperGameBoyManifest,
|
||||
SuperGameBoyBootROM,
|
||||
|
||||
GameBoyManifest,
|
||||
GameBoyROM,
|
||||
GameBoyRAM,
|
||||
|
@ -10,6 +10,7 @@ System system;
|
||||
|
||||
#include <sfc/scheduler/scheduler.cpp>
|
||||
|
||||
auto System::loaded() const -> bool { return _loaded; }
|
||||
auto System::region() const -> Region { return _region; }
|
||||
auto System::expansionPort() const -> Device::ID { return _expansionPort; }
|
||||
auto System::cpuFrequency() const -> uint { return _cpuFrequency; }
|
||||
@ -95,6 +96,7 @@ auto System::load() -> void {
|
||||
interface->loadRequest(ID::IPLROM, iplrom, true);
|
||||
}
|
||||
|
||||
cartridge.load();
|
||||
_region = cartridge.region() == Cartridge::Region::NTSC ? Region::NTSC : Region::PAL;
|
||||
_expansionPort = (Device::ID)settings.expansionPort;
|
||||
_cpuFrequency = region() == Region::NTSC ? 21477272 : 21281370;
|
||||
@ -129,9 +131,11 @@ auto System::load() -> void {
|
||||
if(cartridge.hasSufamiTurboSlots()) sufamiturboA.load(), sufamiturboB.load();
|
||||
|
||||
serializeInit();
|
||||
_loaded = true;
|
||||
}
|
||||
|
||||
auto System::unload() -> void {
|
||||
if(!loaded()) return;
|
||||
if(expansionPort() == Device::ID::Satellaview) satellaview.unload();
|
||||
if(expansionPort() == Device::ID::eBoot) eboot.unload();
|
||||
|
||||
@ -153,6 +157,9 @@ auto System::unload() -> void {
|
||||
|
||||
if(cartridge.hasBSMemorySlot()) bsmemory.unload();
|
||||
if(cartridge.hasSufamiTurboSlots()) sufamiturboA.unload(), sufamiturboB.unload();
|
||||
|
||||
cartridge.unload();
|
||||
_loaded = false;
|
||||
}
|
||||
|
||||
auto System::power() -> void {
|
||||
|
@ -5,6 +5,7 @@ struct Interface;
|
||||
struct System {
|
||||
enum class Region : bool { NTSC = 0, PAL = 1 };
|
||||
|
||||
auto loaded() const -> bool;
|
||||
auto region() const -> Region;
|
||||
auto expansionPort() const -> Device::ID;
|
||||
auto cpuFrequency() const -> uint;
|
||||
@ -34,6 +35,7 @@ private:
|
||||
auto serializeAll(serializer&) -> void;
|
||||
auto serializeInit() -> void;
|
||||
|
||||
bool _loaded = false;
|
||||
Region _region = Region::NTSC;
|
||||
Device::ID _expansionPort = Device::ID::None;
|
||||
uint _cpuFrequency = 0;
|
||||
|
@ -192,10 +192,8 @@ auto Presentation::updateEmulator() -> void {
|
||||
if(devices.objectCount() > 1) {
|
||||
auto path = string{emulator->information.name, "/", port.name}.replace(" ", "");
|
||||
auto device = settings(path).text();
|
||||
for(auto object : devices.objects()) {
|
||||
if(auto item = object.cast<MenuRadioItem>()) {
|
||||
if(item.text() == device) item.setChecked().doActivate();
|
||||
}
|
||||
for(auto item : devices.objects<MenuRadioItem>()) {
|
||||
if(item.text() == device) item.setChecked();
|
||||
}
|
||||
menu.setVisible();
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ auto Program::loadRequest(uint id, string filename, bool required) -> void {
|
||||
string pathname = mediaPaths(emulator->group(id));
|
||||
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(auto manifest = execute("icarus", "--manifest", pathname)) {
|
||||
memorystream stream{(const uint8*)manifest.data(), manifest.size()};
|
||||
|
@ -6,23 +6,24 @@ auto Program::loadMedia(string location) -> void {
|
||||
string type = suffixname(location).ltrim(".", 1L);
|
||||
for(auto& emulator : emulators) {
|
||||
for(auto& media : emulator->media) {
|
||||
if(media.bootable == false) continue;
|
||||
if(!media.bootable) continue;
|
||||
if(media.type != type) continue;
|
||||
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();
|
||||
|
||||
mediaPaths(0) = locate({media.name, ".sys/"});
|
||||
mediaPaths(media.id) = location;
|
||||
folderPaths.append(location);
|
||||
|
||||
emulator = &emulator_;
|
||||
emulator = &interface;
|
||||
connectDevices(); //(expansion port) devices must be connected prior to load
|
||||
emulator->load(media.id);
|
||||
dsp.setFrequency(emulator->audioFrequency());
|
||||
updateAudio(); //audio must be updated after load (audio frequency varies by region)
|
||||
emulator->power();
|
||||
|
||||
presentation->resizeViewport();
|
||||
|
@ -30,6 +30,7 @@ struct Program : Emulator::Interface::Bind {
|
||||
//utility.cpp
|
||||
auto powerCycle() -> void;
|
||||
auto softReset() -> void;
|
||||
auto connectDevices() -> void;
|
||||
auto showMessage(const string& text) -> void;
|
||||
auto updateStatusText() -> void;
|
||||
auto updateVideoShader() -> void;
|
||||
|
@ -11,6 +11,20 @@ auto Program::softReset() -> void {
|
||||
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 {
|
||||
statusTime = time(0);
|
||||
statusMessage = text;
|
||||
@ -52,8 +66,8 @@ auto Program::updateVideoShader() -> void {
|
||||
auto Program::updateAudio() -> void {
|
||||
if(!audio) return;
|
||||
audio->clear();
|
||||
audio->set(Audio::Frequency, settings["Audio/Frequency"].natural());
|
||||
audio->set(Audio::Latency, settings["Audio/Latency"].natural());
|
||||
audio->set(Audio::Frequency, (uint)settings["Audio/Frequency"].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() == "Hermite") dsp.setResampler(DSP::ResampleEngine::Hermite);
|
||||
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 outputRatio = settings["Timing/Audio"].real() / settings["Timing/Video"].real();
|
||||
|
||||
dsp.setFrequency(inputRatio / outputRatio * settings["Audio/Frequency"].natural());
|
||||
}
|
||||
|
@ -5,10 +5,6 @@ namespace WonderSwan {
|
||||
Cartridge cartridge;
|
||||
#include "memory.cpp"
|
||||
|
||||
auto Cartridge::loaded() const -> bool {
|
||||
return _loaded;
|
||||
}
|
||||
|
||||
auto Cartridge::load() -> void {
|
||||
information.manifest = "";
|
||||
information.title = "";
|
||||
@ -35,12 +31,9 @@ auto Cartridge::load() -> void {
|
||||
|
||||
information.title = document["information/title"].text();
|
||||
information.sha256 = Hash::SHA256(rom.data, rom.size).digest();
|
||||
_loaded = true;
|
||||
}
|
||||
|
||||
auto Cartridge::unload() -> void {
|
||||
_loaded = false;
|
||||
|
||||
delete[] rom.data;
|
||||
rom.data = nullptr;
|
||||
rom.size = 0;
|
||||
|
@ -1,6 +1,4 @@
|
||||
struct Cartridge : IO {
|
||||
auto loaded() const -> bool;
|
||||
|
||||
auto load() -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
@ -33,9 +31,6 @@ struct Cartridge : IO {
|
||||
string title;
|
||||
string sha256;
|
||||
} information;
|
||||
|
||||
privileged:
|
||||
bool _loaded = false;
|
||||
};
|
||||
|
||||
extern Cartridge cartridge;
|
||||
|
@ -75,7 +75,7 @@ auto Interface::audioFrequency() -> double {
|
||||
}
|
||||
|
||||
auto Interface::loaded() -> bool {
|
||||
return cartridge.loaded();
|
||||
return system.loaded();
|
||||
}
|
||||
|
||||
auto Interface::sha256() -> string {
|
||||
|
@ -4,9 +4,8 @@ namespace WonderSwan {
|
||||
|
||||
System system;
|
||||
|
||||
auto System::revision() const -> Revision {
|
||||
return _revision;
|
||||
}
|
||||
auto System::loaded() const -> bool { return _loaded; }
|
||||
auto System::revision() const -> Revision { return _revision; }
|
||||
|
||||
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 ...
|
||||
|
||||
cartridge.load();
|
||||
_loaded = true;
|
||||
}
|
||||
|
||||
auto System::unload() -> void {
|
||||
if(!loaded()) return;
|
||||
cartridge.unload();
|
||||
_loaded = false;
|
||||
}
|
||||
|
||||
auto System::power() -> void {
|
||||
|
@ -5,11 +5,13 @@ struct System {
|
||||
SwanCrystal, //SCT-001 (SPHINX2)
|
||||
};
|
||||
|
||||
auto loaded() const -> bool;
|
||||
auto revision() const -> Revision;
|
||||
|
||||
auto init() -> void;
|
||||
auto term() -> void;
|
||||
auto load(Revision) -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
auto run() -> void;
|
||||
|
||||
@ -18,6 +20,7 @@ struct System {
|
||||
} information;
|
||||
|
||||
privileged:
|
||||
bool _loaded = false;
|
||||
Revision _revision = Revision::WonderSwan;
|
||||
};
|
||||
|
||||
|
@ -7827,7 +7827,7 @@ cartridge sha256:4d7fc331a811b8dc630b469262fd6f45e289243cef83101f32038158967d1b2
|
||||
: map address=40-7d,c0-ff:0000-7fff mask=0x8000
|
||||
: icd2 revision=1
|
||||
: 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
|
||||
: serial: SNS-A-SG-USA
|
||||
|
@ -218,7 +218,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size, bool
|
||||
" map address=40-7d,c0-ff:0000-7fff mask=0x8000\n"
|
||||
" icd2 revision=1\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"
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -8,18 +8,16 @@ using namespace nall;
|
||||
#include <sys/resource.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define usartproc dllexport
|
||||
|
||||
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 () -> uint8> usart_read;
|
||||
static function<auto () -> bool> usart_writable;
|
||||
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 (uint milliseconds) -> void> usleep,
|
||||
function<auto (uint microseconds) -> void> usleep,
|
||||
function<auto () -> bool> readable,
|
||||
function<auto () -> uint8> read,
|
||||
function<auto () -> bool> writable,
|
||||
@ -33,7 +31,7 @@ extern "C" usartproc auto usart_init(
|
||||
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;
|
||||
}
|
||||
|
||||
static auto usarthw_usleep(uint milliseconds) -> void {
|
||||
usleep(milliseconds);
|
||||
static auto usarthw_usleep(uint microseconds) -> void {
|
||||
usleep(microseconds);
|
||||
}
|
||||
|
||||
static auto usarthw_readable() -> bool {
|
||||
|
Loading…
Reference in New Issue
Block a user