Update to v097r03 release.

byuu says:

So, this WIP starts work on something new for higan. Obviously, I can't
keep it a secret until it's ready, because I want to continue daily WIP
releases, and of course, solicit feedback as I go along.
This commit is contained in:
Tim Allen 2016-01-27 22:31:39 +11:00
parent 344e63d928
commit d7998b23ef
34 changed files with 856 additions and 9 deletions

View File

@ -4,6 +4,7 @@ fc := fc
sfc := sfc
gb := gb
gba := gba
ws := ws
profile := accuracy
target := tomoko

View File

@ -1,6 +1,6 @@
[Desktop Entry]
Name=higan
Comment=Nintendo emulator
Comment=Emulator
Exec=higan
Icon=higan
Terminal=false

View File

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

View File

@ -7,6 +7,7 @@ processor_objects += $(if $(findstring r6502,$(processors)),processor-r6502)
processor_objects += $(if $(findstring r65816,$(processors)),processor-r65816)
processor_objects += $(if $(findstring spc700,$(processors)),processor-spc700)
processor_objects += $(if $(findstring upd96050,$(processors)),processor-upd96050)
processor_objects += $(if $(findstring v30mz,$(processors)),processor-v30mz)
objects += $(processor_objects)
processor := processor
@ -18,3 +19,4 @@ obj/processor-r6502.o: $(processor)/r6502/r6502.cpp $(call rwildcard,$(proces
obj/processor-r65816.o: $(processor)/r65816/r65816.cpp $(call rwildcard,$(processor)/r65816)
obj/processor-spc700.o: $(processor)/spc700/spc700.cpp $(call rwildcard,$(processor)/spc700)
obj/processor-upd96050.o: $(processor)/upd96050/upd96050.cpp $(call rwildcard,$(processor)/upd96050)
obj/processor-v30mz.o: $(processor)/v30mz/v30mz.cpp $(call rwildcard,$(processor)/v30mz)

View File

@ -0,0 +1,25 @@
#include <processor/processor.hpp>
#include "v30mz.hpp"
namespace Processor {
auto V30MZ::exec() -> void {
step(1);
}
auto V30MZ::power() -> void {
r.ax = 0x0000;
r.cx = 0x0000;
r.dx = 0x0000;
r.bx = 0x0000;
r.sp = 0x0000;
r.bp = 0x0000;
r.si = 0x0000;
r.di = 0x0000;
r.es = 0x0000;
r.cs = 0xffff;
r.ss = 0x0000;
r.ds = 0x0000;
}
}

View File

@ -0,0 +1,31 @@
//NEC V30MZ
#pragma once
namespace Processor {
struct V30MZ {
virtual auto step(uint clocks) -> void = 0;
virtual auto read(uint32 addr) -> uint8 = 0;
virtual auto write(uint32 addr, uint8 data) -> void = 0;
auto exec() -> void;
auto power() -> void;
struct Registers {
struct { uint16 ax; uint8 order_lsb2(al, ah); };
struct { uint16 cx; uint8 order_lsb2(cl, ch); };
struct { uint16 dx; uint8 order_lsb2(dl, dh); };
struct { uint16 bx; uint8 order_lsb2(bl, bh); };
uint16 sp;
uint16 bp;
uint16 si;
uint16 di;
uint16 es;
uint16 cs;
uint16 ss;
uint16 ds;
} r;
};
}

View File

@ -0,0 +1 @@
system name:WonderSwan Color

View File

@ -0,0 +1 @@
system name:WonderSwan

View File

@ -1,6 +1,6 @@
name := higan
processors := arm gsu hg51b lr35902 r6502 r65816 spc700 upd96050
processors := arm gsu hg51b lr35902 r6502 r65816 spc700 upd96050 v30mz
include processor/GNUmakefile
include emulator/GNUmakefile
@ -8,6 +8,7 @@ include fc/GNUmakefile
include sfc/GNUmakefile
include gb/GNUmakefile
include gba/GNUmakefile
include ws/GNUmakefile
ui_objects := ui-tomoko ui-program ui-configuration ui-input
ui_objects += ui-settings ui-tools ui-presentation
@ -90,12 +91,12 @@ else ifeq ($(platform),macosx)
else ifneq ($(filter $(platform),linux bsd),)
mkdir -p $(prefix)/bin/
mkdir -p $(prefix)/share/icons/
mkdir -p $(prefix)/$(name)/
mkdir -p ~/Emulation/System/
mkdir -p $(prefix)/share/$(name)/
cp out/$(name) $(prefix)/bin/$(name)
cp data/$(name).desktop $(prefix)/share/applications/$(name).desktop
cp data/$(name).png $(prefix)/share/icons/$(name).png
cp data/cheats.bml $(prefix)/$(name)/cheats.bml
cp -R profile/* $(prefix)/$(name)/
cp data/cheats.bml $(prefix)/share/$(name)/cheats.bml
cp -R profile/* $(prefix)/share/$(name)/
endif
uninstall:

View File

@ -3,6 +3,7 @@
#include <sfc/interface/interface.hpp>
#include <gb/interface/interface.hpp>
#include <gba/interface/interface.hpp>
#include <ws/interface/interface.hpp>
#include "interface.cpp"
#include "media.cpp"
#include "state.cpp"
@ -17,6 +18,7 @@ Program::Program(lstring args) {
emulators.append(new SuperFamicom::Interface);
emulators.append(new GameBoy::Interface);
emulators.append(new GameBoyAdvance::Interface);
emulators.append(new WonderSwan::Interface);
for(auto& emulator : emulators) emulator->bind = this;
new InputManager;

View File

@ -2,7 +2,7 @@
unique_pointer<Video> video;
unique_pointer<Audio> audio;
unique_pointer<Input> input;
unique_pointer<Emulator::Interface> emulator;
Emulator::Interface* emulator = nullptr;
auto locate(string name) -> string {
string location = {programpath(), name};

View File

@ -9,7 +9,7 @@ extern unique_pointer<Audio> audio;
extern unique_pointer<Input> input;
#include <emulator/emulator.hpp>
extern unique_pointer<Emulator::Interface> emulator;
extern Emulator::Interface* emulator;
#include "program/program.hpp"
#include "configuration/configuration.hpp"

13
higan/ws/GNUmakefile Normal file
View File

@ -0,0 +1,13 @@
ws_objects := ws-interface ws-system ws-scheduler
ws_objects += ws-memory ws-cartridge
ws_objects += ws-cpu ws-ppu ws-apu
objects += $(ws_objects)
obj/ws-interface.o: $(ws)/interface/interface.cpp $(call rwildcard,$(ws)/interface/)
obj/ws-system.o: $(ws)/system/system.cpp $(call rwildcard,$(ws)/system/)
obj/ws-scheduler.o: $(ws)/scheduler/scheduler.cpp $(call rwildcard,$(ws)/scheduler/)
obj/ws-memory.o: $(ws)/memory/memory.cpp $(call rwildcard,$(ws)/memory/)
obj/ws-cartridge.o: $(ws)/cartridge/cartridge.cpp $(call rwildcard,$(ws)/cartridge/)
obj/ws-cpu.o: $(ws)/cpu/cpu.cpp $(call rwildcard,$(ws)/cpu/)
obj/ws-ppu.o: $(ws)/ppu/ppu.cpp $(call rwildcard,$(ws)/ppu/)
obj/ws-apu.o: $(ws)/apu/apu.cpp $(call rwildcard,$(ws)/apu/)

31
higan/ws/apu/apu.cpp Normal file
View File

@ -0,0 +1,31 @@
#include <ws/ws.hpp>
namespace WonderSwan {
APU apu;
auto APU::Enter() -> void {
apu.main();
}
auto APU::main() -> void {
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
step(128);
interface->audioSample(0, 0);
}
}
auto APU::step(uint clocks) -> void {
clock += clocks;
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
}
auto APU::power() -> void {
create(APU::Enter, 3072000);
}
}

9
higan/ws/apu/apu.hpp Normal file
View File

@ -0,0 +1,9 @@
struct APU : Thread {
static auto Enter() -> void;
auto main() -> void;
auto step(uint clocks) -> void;
auto power() -> void;
};
extern APU apu;

View File

@ -0,0 +1,60 @@
#include <ws/ws.hpp>
namespace WonderSwan {
Cartridge cartridge;
#include "memory.cpp"
auto Cartridge::loaded() const -> bool {
return _loaded;
}
auto Cartridge::load() -> void {
information.manifest = "";
information.title = "";
information.sha256 = "";
interface->loadRequest(ID::Manifest, "manifest.bml", true);
auto document = BML::unserialize(information.manifest);
if(auto node = document["board/rom"]) {
rom.name = node["name"].text();
rom.size = node["size"].natural();
if(rom.size) rom.data = new uint8[rom.size]();
if(rom.name) interface->loadRequest(ID::ROM, rom.name, true);
}
if(auto node = document["board/ram"]) {
ram.name = node["name"].text();
ram.size = node["size"].natural();
if(ram.size) ram.data = new uint8[ram.size]();
if(ram.name) interface->loadRequest(ID::RAM, ram.name, true);
}
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;
rom.name = "";
delete[] ram.data;
ram.data = nullptr;
ram.size = 0;
ram.name = "";
}
auto Cartridge::power() -> void {
r.bank_rom0 = 0x00;
r.bank_rom1 = 0x00;
r.bank_rom2 = 0x00;
r.bank_sram = 0x00;
}
}

View File

@ -0,0 +1,37 @@
struct Cartridge {
auto loaded() const -> bool;
auto load() -> void;
auto unload() -> void;
auto power() -> void;
auto romRead(uint addr) -> uint8;
auto romWrite(uint addr, uint8 data) -> void;
auto ramRead(uint addr) -> uint8;
auto ramWrite(uint addr, uint8 data) -> void;
struct Registers {
uint8 bank_rom0;
uint8 bank_rom1;
uint8 bank_rom2;
uint8 bank_sram;
} r;
struct Memory {
uint8* data = nullptr;
uint size = 0;
string name;
} rom, ram;
struct Information {
string manifest;
string title;
string sha256;
} information;
privileged:
bool _loaded = false;
};
extern Cartridge cartridge;

View File

@ -0,0 +1,26 @@
//20000-fffff
auto Cartridge::romRead(uint addr) -> uint8 {
switch(addr >> 16) {
case 2: addr = r.bank_rom0 << 16 | (uint16)addr; break; //20000-2ffff
case 3: addr = r.bank_rom1 << 16 | (uint16)addr; break; //30000-3ffff
default: addr = r.bank_rom2 << 16 | (uint16)addr; break; //40000-fffff
}
if(!rom.data || addr >= rom.size) return 0x00;
return rom.data[addr];
}
auto Cartridge::romWrite(uint addr, uint8 data) -> void {
}
//10000-1ffff
auto Cartridge::ramRead(uint addr) -> uint8 {
addr = r.bank_sram << 16 | (uint16)addr;
if(!ram.data || addr >= ram.size) return 0x00;
return ram.data[addr];
}
auto Cartridge::ramWrite(uint addr, uint8 data) -> void {
addr = r.bank_sram << 16 | (uint16)addr;
if(!ram.data || addr >= ram.size) return;
ram.data[addr] = data;
}

44
higan/ws/cpu/cpu.cpp Normal file
View File

@ -0,0 +1,44 @@
#include <ws/ws.hpp>
namespace WonderSwan {
CPU cpu;
#include "memory.cpp"
auto CPU::Enter() -> void {
cpu.main();
}
auto CPU::main() -> void {
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::CPU) {
scheduler.sync = Scheduler::SynchronizeMode::All;
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
exec();
}
}
auto CPU::step(uint clocks) -> void {
ppu.clock -= clocks;
if(ppu.clock < 0) co_switch(ppu.thread);
apu.clock -= clocks;
if(apu.clock < 0) co_switch(apu.thread);
}
auto CPU::read(uint32 addr) -> uint8 {
return bus.read(addr);
}
auto CPU::write(uint32 addr, uint8 data) -> void {
return bus.write(addr, data);
}
auto CPU::power() -> void {
V30MZ::power();
create(CPU::Enter, 3072000);
}
}

14
higan/ws/cpu/cpu.hpp Normal file
View File

@ -0,0 +1,14 @@
struct CPU : Processor::V30MZ, Thread {
static auto Enter() -> void;
auto main() -> void;
auto step(uint clocks) -> void override;
auto read(uint32 addr) -> uint8 override;
auto write(uint32 addr, uint8 data) -> void override;
auto power() -> void;
auto ramRead(uint addr) -> uint8;
auto ramWrite(uint addr, uint8 data) -> void;
};
extern CPU cpu;

9
higan/ws/cpu/memory.cpp Normal file
View File

@ -0,0 +1,9 @@
auto CPU::ramRead(uint addr) -> uint8 {
uint mask = system.monochrome() ? 0x3fff : 0xffff;
return iram[addr & mask];
}
auto CPU::ramWrite(uint addr, uint8 data) -> void {
uint mask = system.monochrome() ? 0x3fff : 0xffff;
iram[addr & mask] = data;
}

View File

@ -0,0 +1,151 @@
#include <ws/ws.hpp>
namespace WonderSwan {
Interface* interface = nullptr;
Settings settings;
Interface::Interface() {
interface = this;
information.name = "WonderSwan";
information.width = 224; //note: technically 224x144; but screen can be rotated
information.height = 224; //by using a square size; this can be done in the core
information.overscan = false;
information.aspectRatio = 1.0;
information.resettable = false;
information.capability.states = false;
information.capability.cheats = false;
media.append({ID::WonderSwan, "WonderSwan", "ws", true});
media.append({ID::WonderSwanColor, "WonderSwan Color", "wsc", true});
{ Device device{0, ID::Device, "Controller"};
device.input.append({ 0, 0, "X1" });
device.input.append({ 1, 0, "X2" });
device.input.append({ 2, 0, "X3" });
device.input.append({ 3, 0, "X4" });
device.input.append({ 4, 0, "Y1" });
device.input.append({ 5, 0, "Y2" });
device.input.append({ 6, 0, "Y3" });
device.input.append({ 7, 0, "Y4" });
device.input.append({ 8, 0, "B" });
device.input.append({ 9, 0, "A" });
device.input.append({10, 0, "Sound"});
device.input.append({11, 0, "Start"});
device.order = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
this->device.append(device);
}
port.append({0, "Device", {device[0]}});
}
auto Interface::manifest() -> string {
return cartridge.information.manifest;
}
auto Interface::title() -> string {
return cartridge.information.title;
}
auto Interface::videoFrequency() -> double {
return 3072000.0 / (159.0 * 256.0); //~75.47hz
}
auto Interface::audioFrequency() -> double {
return 3072000.0 / 128.0; //24Khz
}
auto Interface::loaded() -> bool {
return cartridge.loaded();
}
auto Interface::sha256() -> string {
return cartridge.information.sha256;
}
auto Interface::group(uint id) -> uint {
switch(id) {
case ID::SystemManifest:
return 0;
case ID::Manifest:
case ID::ROM:
case ID::RAM:
switch(system.revision()) {
case System::Revision::WonderSwan:
return ID::WonderSwan;
case System::Revision::WonderSwanColor:
case System::Revision::SwanCrystal:
return ID::WonderSwanColor;
}
}
throw;
}
auto Interface::load(uint id) -> void {
if(id == ID::WonderSwan) system.load(System::Revision::WonderSwan);
if(id == ID::WonderSwanColor) system.load(System::Revision::WonderSwanColor);
}
auto Interface::save() -> void {
if(cartridge.ram.name) interface->saveRequest(ID::RAM, cartridge.ram.name);
}
auto Interface::load(uint id, const stream& stream) -> void {
if(id == ID::SystemManifest) {
system.information.manifest = stream.text();
}
if(id == ID::Manifest) {
cartridge.information.manifest = stream.text();
}
if(id == ID::ROM) {
stream.read(cartridge.rom.data, min(cartridge.rom.size, stream.size()));
}
if(id == ID::RAM) {
stream.read(cartridge.ram.data, min(cartridge.ram.size, stream.size()));
}
}
auto Interface::save(uint id, const stream& stream) -> void {
if(id == ID::RAM) {
stream.write(cartridge.ram.data, cartridge.ram.size);
}
}
auto Interface::unload() -> void {
save();
}
auto Interface::power() -> void {
system.power();
}
auto Interface::run() -> void {
system.run();
}
auto Interface::serialize() -> serializer {
return {};
}
auto Interface::unserialize(serializer& s) -> bool {
return false;
}
auto Interface::cap(const string& name) -> bool {
return false;
}
auto Interface::get(const string& name) -> any {
return {};
}
auto Interface::set(const string& name, const any& value) -> bool {
return false;
}
}

View File

@ -0,0 +1,60 @@
namespace WonderSwan {
struct ID {
enum : uint {
System,
WonderSwan,
WonderSwanColor,
};
enum : uint {
SystemManifest,
Manifest,
ROM,
RAM,
};
enum : uint {
Device = 1,
};
};
struct Interface : Emulator::Interface {
Interface();
auto manifest() -> string override;
auto title() -> string override;
auto videoFrequency() -> double override;
auto audioFrequency() -> double override;
auto loaded() -> bool override;
auto sha256() -> string override;
auto group(uint id) -> uint override;
auto load(uint id) -> void override;
auto save() -> void override;
auto load(uint id, const stream& stream) -> void override;
auto save(uint id, const stream& stream) -> void override;
auto unload() -> void override;
auto power() -> void override;
auto run() -> void override;
auto serialize() -> serializer override;
auto unserialize(serializer&) -> bool override;
auto cap(const string& name) -> bool override;
auto get(const string& name) -> any override;
auto set(const string& name, const any& value) -> bool override;
private:
vector<Device> device;
};
struct Settings {
};
extern Interface* interface;
extern Settings settings;
}

View File

@ -0,0 +1,26 @@
#include <ws/ws.hpp>
namespace WonderSwan {
uint8 iram[64 * 1024] = {0};
IO* io[256];
Bus bus;
auto IO::power() -> void {
static IO unmapped;
for(auto& n : io) n = &unmapped;
}
auto Bus::read(uint20 addr) -> uint8 {
if(addr < 0x10000) return cpu.ramRead(addr);
if(addr < 0x20000) return cartridge.ramRead(addr);
return cartridge.romRead(addr);
}
auto Bus::write(uint20 addr, uint8 data) -> void {
if(addr < 0x10000) return cpu.ramWrite(addr, data);
if(addr < 0x20000) return cartridge.ramWrite(addr, data);
return cartridge.romWrite(addr, data);
}
}

View File

@ -0,0 +1,15 @@
struct IO {
static auto power() -> void;
virtual auto in(uint8 addr) -> uint8 { return 0x00; }
virtual auto out(uint8 addr, uint8 data) -> void {}
};
struct Bus {
auto read(uint20 addr) -> uint8;
auto write(uint20 addr, uint8 data) -> void;
};
extern uint8 iram[64 * 1024];
extern IO* io[256];
extern Bus bus;

44
higan/ws/ppu/ppu.cpp Normal file
View File

@ -0,0 +1,44 @@
#include <ws/ws.hpp>
namespace WonderSwan {
PPU ppu;
#include "video.cpp"
auto PPU::Enter() -> void {
ppu.main();
}
auto PPU::main() -> void {
while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
step(256);
status.hclk = 0;
if(++status.vclk == 159) {
status.vclk = 0;
video.refresh();
}
}
}
auto PPU::step(uint clocks) -> void {
status.hclk += clocks;
clock += clocks;
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
}
auto PPU::power() -> void {
create(PPU::Enter, 3072000);
for(auto& n : output) n = 0;
status.vclk = 0;
status.hclk = 0;
}
}

18
higan/ws/ppu/ppu.hpp Normal file
View File

@ -0,0 +1,18 @@
#include "video.hpp"
struct PPU : Thread {
static auto Enter() -> void;
auto main() -> void;
auto step(uint clocks) -> void;
auto power() -> void;
uint16 output[224 * 144] = {0};
struct Status {
uint vclk;
uint hclk;
} status;
};
extern PPU ppu;

49
higan/ws/ppu/video.cpp Normal file
View File

@ -0,0 +1,49 @@
Video video;
Video::Video() {
output = new uint32[224 * 224];
paletteLiteral = new uint32[1 << 12];
paletteStandard = new uint32[1 << 12];
}
auto Video::power() -> void {
memory::fill(output(), 224 * 224 * sizeof(uint32));
if(system.monochrome()) {
for(auto color : range(16)) {
paletteLiteral[color] = color;
uint L = image::normalize(15 - color, 4, 16);
paletteStandard[color] = interface->videoColor(L, L, L);
}
}
if(system.color()) {
for(auto color : range(1 << 12)) {
paletteLiteral[color] = color;
uint R = (uint4)(color >> 8);
uint G = (uint4)(color >> 4);
uint B = (uint4)(color >> 0);
R = image::normalize(R, 4, 16);
G = image::normalize(G, 4, 16);
B = image::normalize(B, 4, 16);
paletteStandard[color] = interface->videoColor(R, G, B);
}
}
}
auto Video::refresh() -> void {
for(uint y = 0; y < 144; y++) {
auto source = ppu.output + y * 224;
auto target = output() + y * 224;
for(uint x = 0; x < 224; x++) {
auto color = paletteStandard[*source++];
*target++ = color;
}
}
interface->videoRefresh(output(), 224 * sizeof(uint32), 224, 224);
scheduler.exit(Scheduler::ExitReason::FrameEvent);
}

13
higan/ws/ppu/video.hpp Normal file
View File

@ -0,0 +1,13 @@
struct Video {
Video();
auto power() -> void;
auto refresh() -> void;
private:
unique_pointer<uint32[]> output;
unique_pointer<uint32[]> paletteLiteral;
unique_pointer<uint32[]> paletteStandard;
};
extern Video video;

View File

@ -0,0 +1,23 @@
#include <ws/ws.hpp>
namespace WonderSwan {
Scheduler scheduler;
auto Scheduler::enter() -> void {
host = co_active();
co_switch(active);
}
auto Scheduler::exit(ExitReason reason) -> void {
exitReason = reason;
active = co_active();
co_switch(host);
}
auto Scheduler::power() -> void {
host = co_active();
active = cpu.thread;
}
}

View File

@ -0,0 +1,15 @@
struct Scheduler {
enum class SynchronizeMode : uint { None, CPU, All };
enum class ExitReason : uint { UnknownEvent, FrameEvent, SynchronizeEvent };
auto enter() -> void;
auto exit(ExitReason reason) -> void;
auto power() -> void;
cothread_t host = nullptr;
cothread_t active = nullptr;
SynchronizeMode sync = SynchronizeMode::None;
ExitReason exitReason = ExitReason::UnknownEvent;
};
extern Scheduler scheduler;

View File

@ -0,0 +1,50 @@
#include <ws/ws.hpp>
namespace WonderSwan {
System system;
auto System::revision() const -> Revision {
return _revision;
}
auto System::monochrome() const -> bool {
return revision() == Revision::WonderSwan;
}
auto System::color() const -> bool {
return revision() != Revision::WonderSwan;
}
auto System::init() -> void {
}
auto System::term() -> void {
}
auto System::load(Revision revision) -> void {
_revision = revision;
interface->loadRequest(ID::SystemManifest, "manifest.bml", true);
auto document = BML::unserialize(information.manifest);
cartridge.load();
}
auto System::power() -> void {
IO::power();
cpu.power();
ppu.power();
apu.power();
cartridge.power();
scheduler.power();
}
auto System::run() -> void {
while(true) {
scheduler.enter();
if(scheduler.exitReason == Scheduler::ExitReason::FrameEvent) break;
}
}
}

View File

@ -0,0 +1,22 @@
struct System {
enum class Revision : uint { WonderSwan, WonderSwanColor, SwanCrystal };
auto revision() const -> Revision;
auto monochrome() const -> bool;
auto color() const -> bool;
auto init() -> void;
auto term() -> void;
auto load(Revision) -> void;
auto power() -> void;
auto run() -> void;
struct Information {
string manifest;
} information;
privileged:
Revision _revision;
};
extern System system;

54
higan/ws/ws.hpp Normal file
View File

@ -0,0 +1,54 @@
#pragma once
#include <emulator/emulator.hpp>
#include <processor/v30mz/v30mz.hpp>
namespace WonderSwan {
namespace Info {
static const string Name = "bws";
static const uint SerializerVersion = 0;
}
}
/*
bws - WonderSwan, WonderSwan Color, and SwanCrystal emulator
author: byuu
license: GPLv3
project started: 2016-01-26
*/
#include <libco/libco.h>
namespace WonderSwan {
struct Thread {
~Thread() {
if(thread) co_delete(thread);
}
auto create(auto (*entrypoint)() -> void, uint frequency) -> void {
if(thread) co_delete(thread);
thread = co_create(65536 * sizeof(void*), entrypoint);
this->frequency = frequency;
clock = 0;
}
auto serialize(serializer& s) -> void {
s.integer(frequency);
s.integer(clock);
}
cothread_t thread = nullptr;
uint frequency = 0;
int64 clock = 0;
};
#include <ws/system/system.hpp>
#include <ws/scheduler/scheduler.hpp>
#include <ws/memory/memory.hpp>
#include <ws/cartridge/cartridge.hpp>
#include <ws/cpu/cpu.hpp>
#include <ws/ppu/ppu.hpp>
#include <ws/apu/apu.hpp>
}
#include <ws/interface/interface.hpp>