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 {
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/";

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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