mirror of https://github.com/bsnes-emu/bsnes.git
Update to v101r31 release.
byuu says: Changelog: - converted Emulator::Interface::Bind to Emulator::Platform - temporarily disabled SGB hooks - SMS: emulated Game Gear palette (latching word-write behavior not implemented yet) - SMS: emulated Master System 'Reset' button, Game Gear 'Start' button - SMS: removed reset() functionality, driven by the mappable input now instead - SMS: split interface class in two: one for Master System, one for Game Gear - SMS: emulated Game Gear video cropping to 160x144 - PCE: started on HuC6280 CPU core—so far only registers, NOP instruction has been implemented Errata: - Super Game Boy support is broken and thus disabled - if you switch between Master System and Game Gear without restarting, bad things happen: - SMS→GG, no video output on the GG - GG→SMS, no input on the SMS I'm not sure what's causing the SMS\<-\>GG switch bug, having a hard time debugging it. Help would be very much appreciated, if anyone's up for it. Otherwise I'll keep trying to track it down on my end.
This commit is contained in:
parent
0ad70a30f8
commit
bf90bdfcc8
|
@ -4,7 +4,7 @@ target := tomoko
|
||||||
# console := true
|
# console := true
|
||||||
|
|
||||||
flags += -I. -I.. -O3
|
flags += -I. -I.. -O3
|
||||||
objects := libco audio video resource
|
objects := libco emulator audio video resource
|
||||||
|
|
||||||
# profile-guided optimization mode
|
# profile-guided optimization mode
|
||||||
# pgo := instrument
|
# pgo := instrument
|
||||||
|
@ -52,10 +52,11 @@ compile = \
|
||||||
|
|
||||||
all: build;
|
all: build;
|
||||||
|
|
||||||
obj/libco.o: ../libco/libco.c $(call rwildcard,../libco/)
|
obj/libco.o: ../libco/libco.c $(call rwildcard,../libco)
|
||||||
obj/audio.o: audio/audio.cpp $(call rwildcard,audio/)
|
obj/emulator.o: emulator/emulator.cpp $(call rwildcard,emulator)
|
||||||
obj/video.o: video/video.cpp $(call rwildcard,video/)
|
obj/audio.o: audio/audio.cpp $(call rwildcard,audio)
|
||||||
obj/resource.o: resource/resource.cpp $(call rwildcard,resource/)
|
obj/video.o: video/video.cpp $(call rwildcard,video)
|
||||||
|
obj/resource.o: resource/resource.cpp $(call rwildcard,resource)
|
||||||
|
|
||||||
ui := target-$(target)
|
ui := target-$(target)
|
||||||
include $(ui)/GNUmakefile
|
include $(ui)/GNUmakefile
|
||||||
|
|
|
@ -6,6 +6,8 @@ namespace Emulator {
|
||||||
Audio audio;
|
Audio audio;
|
||||||
|
|
||||||
auto Audio::reset(maybe<uint> channels_, maybe<double> frequency_) -> void {
|
auto Audio::reset(maybe<uint> channels_, maybe<double> frequency_) -> void {
|
||||||
|
interface = nullptr;
|
||||||
|
|
||||||
if(channels_) channels = channels_();
|
if(channels_) channels = channels_();
|
||||||
if(frequency_) frequency = frequency_();
|
if(frequency_) frequency = frequency_();
|
||||||
|
|
||||||
|
@ -81,7 +83,7 @@ auto Audio::process() -> void {
|
||||||
if(balance > 0.0) samples[0] *= 1.0 - balance;
|
if(balance > 0.0) samples[0] *= 1.0 - balance;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface->audioSample(samples, channels);
|
platform->audioSample(samples, channels);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ struct Stream;
|
||||||
|
|
||||||
struct Audio {
|
struct Audio {
|
||||||
auto reset(maybe<uint> channels = nothing, maybe<double> frequency = nothing) -> void;
|
auto reset(maybe<uint> channels = nothing, maybe<double> frequency = nothing) -> void;
|
||||||
auto setInterface(Interface*) -> void;
|
auto setInterface(Interface* interface) -> void;
|
||||||
|
|
||||||
auto setVolume(double volume) -> void;
|
auto setVolume(double volume) -> void;
|
||||||
auto setBalance(double balance) -> void;
|
auto setBalance(double balance) -> void;
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include <emulator/emulator.hpp>
|
||||||
|
|
||||||
|
namespace Emulator {
|
||||||
|
|
||||||
|
Platform* platform = nullptr;
|
||||||
|
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ using namespace nall;
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
static const string Name = "higan";
|
||||||
static const string Version = "101.30";
|
static const string Version = "101.31";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "http://byuu.org/";
|
static const string Website = "http://byuu.org/";
|
||||||
|
|
|
@ -2,6 +2,18 @@
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
|
|
||||||
|
struct Platform {
|
||||||
|
virtual auto path(uint id) -> string { return ""; }
|
||||||
|
virtual auto open(uint id, string name, vfs::file::mode mode, bool required = false) -> vfs::shared::file { return {}; }
|
||||||
|
virtual auto load(uint id, string name, string type) -> maybe<uint> { return nothing; }
|
||||||
|
virtual auto videoRefresh(const uint32* data, uint pitch, uint width, uint height) -> void {}
|
||||||
|
virtual auto audioSample(const double* samples, uint channels) -> void {}
|
||||||
|
virtual auto inputPoll(uint port, uint device, uint input) -> int16 { return 0; }
|
||||||
|
virtual auto inputRumble(uint port, uint device, uint input, bool enable) -> void {}
|
||||||
|
virtual auto dipSettings(Markup::Node node) -> uint { return 0; }
|
||||||
|
virtual auto notify(string text) -> void { print(text, "\n"); }
|
||||||
|
};
|
||||||
|
|
||||||
struct Interface {
|
struct Interface {
|
||||||
struct Information {
|
struct Information {
|
||||||
string manufacturer;
|
string manufacturer;
|
||||||
|
@ -38,30 +50,6 @@ struct Interface {
|
||||||
};
|
};
|
||||||
vector<Port> ports;
|
vector<Port> ports;
|
||||||
|
|
||||||
struct Bind {
|
|
||||||
virtual auto path(uint) -> string { return ""; }
|
|
||||||
virtual auto open(uint, string, vfs::file::mode, bool) -> vfs::shared::file { return {}; }
|
|
||||||
virtual auto load(uint, string, string) -> maybe<uint> { return nothing; }
|
|
||||||
virtual auto videoRefresh(const uint32*, uint, uint, uint) -> void {}
|
|
||||||
virtual auto audioSample(const double*, uint) -> void {}
|
|
||||||
virtual auto inputPoll(uint, uint, uint) -> int16 { return 0; }
|
|
||||||
virtual auto inputRumble(uint, uint, uint, bool) -> void {}
|
|
||||||
virtual auto dipSettings(Markup::Node) -> uint { return 0; }
|
|
||||||
virtual auto notify(string text) -> void { print(text, "\n"); }
|
|
||||||
};
|
|
||||||
Bind* bind = nullptr;
|
|
||||||
|
|
||||||
//callback bindings (provided by user interface)
|
|
||||||
auto path(uint id) -> string { return bind->path(id); }
|
|
||||||
auto open(uint id, string name, vfs::file::mode mode, bool required = false) -> vfs::shared::file { return bind->open(id, name, mode, required); }
|
|
||||||
auto load(uint id, string name, string type) -> maybe<uint> { return bind->load(id, name, type); }
|
|
||||||
auto videoRefresh(const uint32* data, uint pitch, uint width, uint height) -> void { return bind->videoRefresh(data, pitch, width, height); }
|
|
||||||
auto audioSample(const double* samples, uint channels) -> void { return bind->audioSample(samples, channels); }
|
|
||||||
auto inputPoll(uint port, uint device, uint input) -> int16 { return bind->inputPoll(port, device, input); }
|
|
||||||
auto inputRumble(uint port, uint device, uint input, bool enable) -> void { return bind->inputRumble(port, device, input, enable); }
|
|
||||||
auto dipSettings(Markup::Node node) -> uint { return bind->dipSettings(node); }
|
|
||||||
template<typename... P> auto notify(P&&... p) -> void { return bind->notify({forward<P>(p)...}); }
|
|
||||||
|
|
||||||
//information
|
//information
|
||||||
virtual auto manifest() -> string = 0;
|
virtual auto manifest() -> string = 0;
|
||||||
virtual auto title() -> string = 0;
|
virtual auto title() -> string = 0;
|
||||||
|
@ -118,4 +106,6 @@ struct File {
|
||||||
static const auto Required = true;
|
static const auto Required = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern Platform* platform;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,22 +42,22 @@ Board::Board(Markup::Node& document) {
|
||||||
if(chrram.size) chrram.data = new uint8_t[chrram.size]();
|
if(chrram.size) chrram.data = new uint8_t[chrram.size]();
|
||||||
|
|
||||||
if(prgrom.name = prom["name"].text()) {
|
if(prgrom.name = prom["name"].text()) {
|
||||||
if(auto fp = interface->open(cartridge.pathID(), prgrom.name, File::Read, File::Required)) {
|
if(auto fp = platform->open(cartridge.pathID(), prgrom.name, File::Read, File::Required)) {
|
||||||
fp->read(prgrom.data, min(prgrom.size, fp->size()));
|
fp->read(prgrom.data, min(prgrom.size, fp->size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(prgram.name = pram["name"].text()) {
|
if(prgram.name = pram["name"].text()) {
|
||||||
if(auto fp = interface->open(cartridge.pathID(), prgram.name, File::Read)) {
|
if(auto fp = platform->open(cartridge.pathID(), prgram.name, File::Read)) {
|
||||||
fp->read(prgram.data, min(prgram.size, fp->size()));
|
fp->read(prgram.data, min(prgram.size, fp->size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(chrrom.name = crom["name"].text()) {
|
if(chrrom.name = crom["name"].text()) {
|
||||||
if(auto fp = interface->open(cartridge.pathID(), chrrom.name, File::Read, File::Required)) {
|
if(auto fp = platform->open(cartridge.pathID(), chrrom.name, File::Read, File::Required)) {
|
||||||
fp->read(chrrom.data, min(chrrom.size, fp->size()));
|
fp->read(chrrom.data, min(chrrom.size, fp->size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(chrram.name = cram["name"].text()) {
|
if(chrram.name = cram["name"].text()) {
|
||||||
if(auto fp = interface->open(cartridge.pathID(), chrram.name, File::Read)) {
|
if(auto fp = platform->open(cartridge.pathID(), chrram.name, File::Read)) {
|
||||||
fp->read(chrram.data, min(chrram.size, fp->size()));
|
fp->read(chrram.data, min(chrram.size, fp->size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,13 +70,13 @@ auto Board::save() -> void {
|
||||||
auto document = BML::unserialize(cartridge.manifest());
|
auto document = BML::unserialize(cartridge.manifest());
|
||||||
|
|
||||||
if(auto name = document["board/prg/ram/name"].text()) {
|
if(auto name = document["board/prg/ram/name"].text()) {
|
||||||
if(auto fp = interface->open(cartridge.pathID(), name, File::Write)) {
|
if(auto fp = platform->open(cartridge.pathID(), name, File::Write)) {
|
||||||
fp->write(prgram.data, prgram.size);
|
fp->write(prgram.data, prgram.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(auto name = document["board/chr/ram/name"].text()) {
|
if(auto name = document["board/chr/ram/name"].text()) {
|
||||||
if(auto fp = interface->open(cartridge.pathID(), name, File::Write)) {
|
if(auto fp = platform->open(cartridge.pathID(), name, File::Write)) {
|
||||||
fp->write(chrram.data, chrram.size);
|
fp->write(chrram.data, chrram.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,11 @@ auto Cartridge::main() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::load() -> bool {
|
auto Cartridge::load() -> bool {
|
||||||
if(auto pathID = interface->load(ID::Famicom, "Famicom", "fc")) {
|
if(auto pathID = platform->load(ID::Famicom, "Famicom", "fc")) {
|
||||||
information.pathID = pathID();
|
information.pathID = pathID();
|
||||||
} else return false;
|
} else return false;
|
||||||
|
|
||||||
if(auto fp = interface->open(pathID(), "manifest.bml", File::Read, File::Required)) {
|
if(auto fp = platform->open(pathID(), "manifest.bml", File::Read, File::Required)) {
|
||||||
information.manifest = fp->reads();
|
information.manifest = fp->reads();
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -3,7 +3,7 @@ Gamepad::Gamepad(bool port) : Controller(port) {
|
||||||
|
|
||||||
auto Gamepad::data() -> uint3 {
|
auto Gamepad::data() -> uint3 {
|
||||||
if(counter >= 8) return 1;
|
if(counter >= 8) return 1;
|
||||||
if(latched == 1) return interface->inputPoll(port, ID::Device::Gamepad, A);
|
if(latched == 1) return platform->inputPoll(port, ID::Device::Gamepad, A);
|
||||||
|
|
||||||
switch(counter++) {
|
switch(counter++) {
|
||||||
case 0: return a;
|
case 0: return a;
|
||||||
|
@ -24,13 +24,13 @@ auto Gamepad::latch(bool data) -> void {
|
||||||
counter = 0;
|
counter = 0;
|
||||||
|
|
||||||
if(latched == 0) {
|
if(latched == 0) {
|
||||||
a = interface->inputPoll(port, ID::Device::Gamepad, A);
|
a = platform->inputPoll(port, ID::Device::Gamepad, A);
|
||||||
b = interface->inputPoll(port, ID::Device::Gamepad, B);
|
b = platform->inputPoll(port, ID::Device::Gamepad, B);
|
||||||
select = interface->inputPoll(port, ID::Device::Gamepad, Select);
|
select = platform->inputPoll(port, ID::Device::Gamepad, Select);
|
||||||
start = interface->inputPoll(port, ID::Device::Gamepad, Start);
|
start = platform->inputPoll(port, ID::Device::Gamepad, Start);
|
||||||
up = interface->inputPoll(port, ID::Device::Gamepad, Up);
|
up = platform->inputPoll(port, ID::Device::Gamepad, Up);
|
||||||
down = interface->inputPoll(port, ID::Device::Gamepad, Down);
|
down = platform->inputPoll(port, ID::Device::Gamepad, Down);
|
||||||
left = interface->inputPoll(port, ID::Device::Gamepad, Left);
|
left = platform->inputPoll(port, ID::Device::Gamepad, Left);
|
||||||
right = interface->inputPoll(port, ID::Device::Gamepad, Right);
|
right = platform->inputPoll(port, ID::Device::Gamepad, Right);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <processor/r6502/r6502.hpp>
|
#include <processor/r6502/r6502.hpp>
|
||||||
|
|
||||||
namespace Famicom {
|
namespace Famicom {
|
||||||
|
#define platform Emulator::platform
|
||||||
using File = Emulator::File;
|
using File = Emulator::File;
|
||||||
using Scheduler = Emulator::Scheduler;
|
using Scheduler = Emulator::Scheduler;
|
||||||
using Cheat = Emulator::Cheat;
|
using Cheat = Emulator::Cheat;
|
||||||
|
|
|
@ -2,12 +2,9 @@
|
||||||
|
|
||||||
namespace Famicom {
|
namespace Famicom {
|
||||||
|
|
||||||
Interface* interface = nullptr;
|
|
||||||
Settings settings;
|
Settings settings;
|
||||||
|
|
||||||
Interface::Interface() {
|
Interface::Interface() {
|
||||||
interface = this;
|
|
||||||
|
|
||||||
information.manufacturer = "Nintendo";
|
information.manufacturer = "Nintendo";
|
||||||
information.name = "Famicom";
|
information.name = "Famicom";
|
||||||
information.overscan = true;
|
information.overscan = true;
|
||||||
|
@ -134,7 +131,7 @@ auto Interface::sha256() -> string {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::load(uint id) -> bool {
|
auto Interface::load(uint id) -> bool {
|
||||||
return system.load();
|
return system.load(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::save() -> void {
|
auto Interface::save() -> void {
|
||||||
|
@ -147,7 +144,7 @@ auto Interface::unload() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::connect(uint port, uint device) -> void {
|
auto Interface::connect(uint port, uint device) -> void {
|
||||||
Famicom::peripherals.connect(port, device);
|
peripherals.connect(port, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::power() -> void {
|
auto Interface::power() -> void {
|
||||||
|
|
|
@ -64,7 +64,6 @@ struct Settings {
|
||||||
uint expansionPort = 0;
|
uint expansionPort = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Interface* interface;
|
|
||||||
extern Settings settings;
|
extern Settings settings;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,15 +21,17 @@ auto System::runToSave() -> void {
|
||||||
for(auto peripheral : cpu.peripherals) scheduler.synchronize(*peripheral);
|
for(auto peripheral : cpu.peripherals) scheduler.synchronize(*peripheral);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::load() -> bool {
|
auto System::load(Emulator::Interface* interface) -> bool {
|
||||||
information = Information();
|
information = Information();
|
||||||
if(auto fp = interface->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
if(auto fp = platform->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
||||||
information.manifest = fp->reads();
|
information.manifest = fp->reads();
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto document = BML::unserialize(information.manifest);
|
auto document = BML::unserialize(information.manifest);
|
||||||
if(!cartridge.load()) return false;
|
if(!cartridge.load()) return false;
|
||||||
|
|
||||||
|
this->interface = interface;
|
||||||
information.colorburst = Emulator::Constants::Colorburst::NTSC;
|
information.colorburst = Emulator::Constants::Colorburst::NTSC;
|
||||||
serializeInit();
|
serializeInit();
|
||||||
return information.loaded = true;
|
return information.loaded = true;
|
||||||
|
|
|
@ -5,7 +5,7 @@ struct System {
|
||||||
auto run() -> void;
|
auto run() -> void;
|
||||||
auto runToSave() -> void;
|
auto runToSave() -> void;
|
||||||
|
|
||||||
auto load() -> bool;
|
auto load(Emulator::Interface*) -> bool;
|
||||||
auto save() -> void;
|
auto save() -> void;
|
||||||
auto unload() -> void;
|
auto unload() -> void;
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
@ -26,13 +26,15 @@ struct System {
|
||||||
auto serializeAll(serializer&) -> void;
|
auto serializeAll(serializer&) -> void;
|
||||||
auto serializeInit() -> void;
|
auto serializeInit() -> void;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Emulator::Interface* interface = nullptr;
|
||||||
|
|
||||||
struct Information {
|
struct Information {
|
||||||
bool loaded = false;
|
bool loaded = false;
|
||||||
double colorburst = 0.0;
|
double colorburst = 0.0;
|
||||||
string manifest;
|
string manifest;
|
||||||
} information;
|
} information;
|
||||||
|
|
||||||
private:
|
|
||||||
uint _serializeSize = 0;
|
uint _serializeSize = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ auto APU::main() -> void {
|
||||||
stream->sample(sequencer.left / 32768.0, sequencer.right / 32768.0);
|
stream->sample(sequencer.left / 32768.0, sequencer.right / 32768.0);
|
||||||
} else {
|
} else {
|
||||||
double samples[] = {sequencer.left / 32768.0, sequencer.right / 32768.0};
|
double samples[] = {sequencer.left / 32768.0, sequencer.right / 32768.0};
|
||||||
interface->audioSample(samples, 2);
|
//interface->audioSample(samples, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cycle == 0) { //512hz
|
if(cycle == 0) { //512hz
|
||||||
|
|
|
@ -19,23 +19,23 @@ auto Cartridge::load(System::Revision revision) -> bool {
|
||||||
|
|
||||||
switch(revision) {
|
switch(revision) {
|
||||||
case System::Revision::GameBoy:
|
case System::Revision::GameBoy:
|
||||||
if(auto pathID = interface->load(ID::GameBoy, "Game Boy", "gb")) {
|
if(auto pathID = platform->load(ID::GameBoy, "Game Boy", "gb")) {
|
||||||
information.pathID = pathID();
|
information.pathID = pathID();
|
||||||
} else return false;
|
} else return false;
|
||||||
break;
|
break;
|
||||||
case System::Revision::SuperGameBoy:
|
case System::Revision::SuperGameBoy:
|
||||||
if(auto pathID = interface->load(ID::SuperGameBoy, "Game Boy", "gb")) {
|
if(auto pathID = platform->load(ID::SuperGameBoy, "Game Boy", "gb")) {
|
||||||
information.pathID = pathID();
|
information.pathID = pathID();
|
||||||
} else return false;
|
} else return false;
|
||||||
break;
|
break;
|
||||||
case System::Revision::GameBoyColor:
|
case System::Revision::GameBoyColor:
|
||||||
if(auto pathID = interface->load(ID::GameBoyColor, "Game Boy Color", "gbc")) {
|
if(auto pathID = platform->load(ID::GameBoyColor, "Game Boy Color", "gbc")) {
|
||||||
information.pathID = pathID();
|
information.pathID = pathID();
|
||||||
} else return false;
|
} else return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(auto fp = interface->open(pathID(), "manifest.bml", File::Read, File::Required)) {
|
if(auto fp = platform->open(pathID(), "manifest.bml", File::Read, File::Required)) {
|
||||||
information.manifest = fp->reads();
|
information.manifest = fp->reads();
|
||||||
} else return false;
|
} else return false;
|
||||||
|
|
||||||
|
@ -64,12 +64,12 @@ auto Cartridge::load(System::Revision revision) -> bool {
|
||||||
ram.data = (uint8*)memory::allocate(ram.size, 0xff);
|
ram.data = (uint8*)memory::allocate(ram.size, 0xff);
|
||||||
|
|
||||||
if(auto name = board["rom/name"].text()) {
|
if(auto name = board["rom/name"].text()) {
|
||||||
if(auto fp = interface->open(pathID(), name, File::Read, File::Required)) {
|
if(auto fp = platform->open(pathID(), name, File::Read, File::Required)) {
|
||||||
fp->read(rom.data, min(rom.size, fp->size()));
|
fp->read(rom.data, min(rom.size, fp->size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(auto name = board["ram/name"].text()) {
|
if(auto name = board["ram/name"].text()) {
|
||||||
if(auto fp = interface->open(pathID(), name, File::Read, File::Optional)) {
|
if(auto fp = platform->open(pathID(), name, File::Read, File::Optional)) {
|
||||||
fp->read(ram.data, min(ram.size, fp->size()));
|
fp->read(ram.data, min(ram.size, fp->size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ auto Cartridge::save() -> void {
|
||||||
auto document = BML::unserialize(information.manifest);
|
auto document = BML::unserialize(information.manifest);
|
||||||
|
|
||||||
if(auto name = document["board/ram/name"].text()) {
|
if(auto name = document["board/ram/name"].text()) {
|
||||||
if(auto fp = interface->open(pathID(), name, File::Write)) {
|
if(auto fp = platform->open(pathID(), name, File::Write)) {
|
||||||
fp->write(ram.data, ram.size);
|
fp->write(ram.data, ram.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,15 +8,15 @@ auto CPU::wramAddress(uint16 addr) const -> uint {
|
||||||
auto CPU::joypPoll() -> void {
|
auto CPU::joypPoll() -> void {
|
||||||
uint button = 0, dpad = 0;
|
uint button = 0, dpad = 0;
|
||||||
|
|
||||||
button |= interface->inputPoll(0, 0, (uint)Input::Start) << 3;
|
button |= platform->inputPoll(0, 0, (uint)Input::Start) << 3;
|
||||||
button |= interface->inputPoll(0, 0, (uint)Input::Select) << 2;
|
button |= platform->inputPoll(0, 0, (uint)Input::Select) << 2;
|
||||||
button |= interface->inputPoll(0, 0, (uint)Input::B) << 1;
|
button |= platform->inputPoll(0, 0, (uint)Input::B) << 1;
|
||||||
button |= interface->inputPoll(0, 0, (uint)Input::A) << 0;
|
button |= platform->inputPoll(0, 0, (uint)Input::A) << 0;
|
||||||
|
|
||||||
dpad |= interface->inputPoll(0, 0, (uint)Input::Down) << 3;
|
dpad |= platform->inputPoll(0, 0, (uint)Input::Down) << 3;
|
||||||
dpad |= interface->inputPoll(0, 0, (uint)Input::Up) << 2;
|
dpad |= platform->inputPoll(0, 0, (uint)Input::Up) << 2;
|
||||||
dpad |= interface->inputPoll(0, 0, (uint)Input::Left) << 1;
|
dpad |= platform->inputPoll(0, 0, (uint)Input::Left) << 1;
|
||||||
dpad |= interface->inputPoll(0, 0, (uint)Input::Right) << 0;
|
dpad |= platform->inputPoll(0, 0, (uint)Input::Right) << 0;
|
||||||
|
|
||||||
if(system.revision() != System::Revision::SuperGameBoy) {
|
if(system.revision() != System::Revision::SuperGameBoy) {
|
||||||
//D-pad pivot makes it impossible to press opposing directions at the same time
|
//D-pad pivot makes it impossible to press opposing directions at the same time
|
||||||
|
@ -145,7 +145,7 @@ auto CPU::writeIO(uint16 addr, uint8 data) -> void {
|
||||||
if(addr == 0xff00) { //JOYP
|
if(addr == 0xff00) { //JOYP
|
||||||
status.p15 = data & 0x20;
|
status.p15 = data & 0x20;
|
||||||
status.p14 = data & 0x10;
|
status.p14 = data & 0x10;
|
||||||
interface->joypWrite(status.p15, status.p14);
|
//interface->joypWrite(status.p15, status.p14);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <processor/lr35902/lr35902.hpp>
|
#include <processor/lr35902/lr35902.hpp>
|
||||||
|
|
||||||
namespace GameBoy {
|
namespace GameBoy {
|
||||||
|
#define platform Emulator::platform
|
||||||
using File = Emulator::File;
|
using File = Emulator::File;
|
||||||
using Scheduler = Emulator::Scheduler;
|
using Scheduler = Emulator::Scheduler;
|
||||||
using Cheat = Emulator::Cheat;
|
using Cheat = Emulator::Cheat;
|
||||||
|
|
|
@ -2,11 +2,9 @@
|
||||||
|
|
||||||
namespace GameBoy {
|
namespace GameBoy {
|
||||||
|
|
||||||
Interface* interface = nullptr;
|
|
||||||
Settings settings;
|
Settings settings;
|
||||||
|
|
||||||
Interface::Interface() {
|
Interface::Interface() {
|
||||||
interface = this;
|
|
||||||
hook = nullptr;
|
hook = nullptr;
|
||||||
|
|
||||||
information.manufacturer = "Nintendo";
|
information.manufacturer = "Nintendo";
|
||||||
|
@ -134,9 +132,9 @@ auto Interface::sha256() -> string {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::load(uint id) -> bool {
|
auto Interface::load(uint id) -> bool {
|
||||||
if(id == ID::GameBoy) return system.load(System::Revision::GameBoy);
|
if(id == ID::GameBoy) return system.load(this, System::Revision::GameBoy);
|
||||||
if(id == ID::SuperGameBoy) return system.load(System::Revision::SuperGameBoy);
|
if(id == ID::SuperGameBoy) return system.load(this, System::Revision::SuperGameBoy);
|
||||||
if(id == ID::GameBoyColor) return system.load(System::Revision::GameBoyColor);
|
if(id == ID::GameBoyColor) return system.load(this, System::Revision::GameBoyColor);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,6 @@ struct Settings {
|
||||||
bool colorEmulation = true;
|
bool colorEmulation = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Interface* interface;
|
|
||||||
extern Settings settings;
|
extern Settings settings;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ auto PPU::runDMG() -> void {
|
||||||
|
|
||||||
uint32* output = screen + status.ly * 160 + px++;
|
uint32* output = screen + status.ly * 160 + px++;
|
||||||
*output = color;
|
*output = color;
|
||||||
interface->lcdOutput(color); //Super Game Boy notification
|
//interface->lcdOutput(color); //Super Game Boy notification
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::runBackgroundDMG() -> void {
|
auto PPU::runBackgroundDMG() -> void {
|
||||||
|
|
|
@ -16,7 +16,7 @@ auto PPU::Enter() -> void {
|
||||||
|
|
||||||
auto PPU::main() -> void {
|
auto PPU::main() -> void {
|
||||||
status.lx = 0;
|
status.lx = 0;
|
||||||
interface->lcdScanline(); //Super Game Boy notification
|
//interface->lcdScanline(); //Super Game Boy notification
|
||||||
|
|
||||||
if(status.ly <= 143) {
|
if(status.ly <= 143) {
|
||||||
mode(2);
|
mode(2);
|
||||||
|
|
|
@ -22,10 +22,10 @@ auto System::init() -> void {
|
||||||
assert(interface != nullptr);
|
assert(interface != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::load(Revision revision) -> bool {
|
auto System::load(Emulator::Interface* interface, Revision revision) -> bool {
|
||||||
_revision = revision;
|
_revision = revision;
|
||||||
|
|
||||||
if(auto fp = interface->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
if(auto fp = platform->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
||||||
information.manifest = fp->reads();
|
information.manifest = fp->reads();
|
||||||
} else return false;
|
} else return false;
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ auto System::load(Revision revision) -> bool {
|
||||||
if(revision == Revision::SuperGameBoy) path = "board/icd2/rom/name";
|
if(revision == Revision::SuperGameBoy) path = "board/icd2/rom/name";
|
||||||
|
|
||||||
if(auto name = document[path].text()) {
|
if(auto name = document[path].text()) {
|
||||||
if(auto fp = interface->open(ID::System, name, File::Read, File::Required)) {
|
if(auto fp = platform->open(ID::System, name, File::Read, File::Required)) {
|
||||||
if(revision == Revision::GameBoy) fp->read(bootROM.dmg, 256);
|
if(revision == Revision::GameBoy) fp->read(bootROM.dmg, 256);
|
||||||
if(revision == Revision::SuperGameBoy) fp->read(bootROM.sgb, 256);
|
if(revision == Revision::SuperGameBoy) fp->read(bootROM.sgb, 256);
|
||||||
if(revision == Revision::GameBoyColor) fp->read(bootROM.cgb, 2048);
|
if(revision == Revision::GameBoyColor) fp->read(bootROM.cgb, 2048);
|
||||||
|
@ -43,6 +43,7 @@ auto System::load(Revision revision) -> bool {
|
||||||
|
|
||||||
if(!cartridge.load(revision)) return false;
|
if(!cartridge.load(revision)) return false;
|
||||||
serializeInit();
|
serializeInit();
|
||||||
|
this->interface = interface;
|
||||||
return _loaded = true;
|
return _loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
struct Interface;
|
|
||||||
|
|
||||||
enum class Input : uint {
|
enum class Input : uint {
|
||||||
Up, Down, Left, Right, B, A, Select, Start,
|
Up, Down, Left, Right, B, A, Select, Start,
|
||||||
};
|
};
|
||||||
|
@ -23,7 +21,7 @@ struct System {
|
||||||
auto runToSave() -> void;
|
auto runToSave() -> void;
|
||||||
|
|
||||||
auto init() -> void;
|
auto init() -> void;
|
||||||
auto load(Revision) -> bool;
|
auto load(Emulator::Interface*, Revision) -> bool;
|
||||||
auto save() -> void;
|
auto save() -> void;
|
||||||
auto unload() -> void;
|
auto unload() -> void;
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
@ -40,6 +38,8 @@ struct System {
|
||||||
auto serializeAll(serializer&) -> void;
|
auto serializeAll(serializer&) -> void;
|
||||||
auto serializeInit() -> void;
|
auto serializeInit() -> void;
|
||||||
|
|
||||||
|
Emulator::Interface* interface = nullptr;
|
||||||
|
|
||||||
struct BootROM {
|
struct BootROM {
|
||||||
uint8 dmg[ 256];
|
uint8 dmg[ 256];
|
||||||
uint8 sgb[ 256];
|
uint8 sgb[ 256];
|
||||||
|
|
|
@ -26,11 +26,11 @@ Cartridge::~Cartridge() {
|
||||||
auto Cartridge::load() -> bool {
|
auto Cartridge::load() -> bool {
|
||||||
information = Information();
|
information = Information();
|
||||||
|
|
||||||
if(auto pathID = interface->load(ID::GameBoyAdvance, "Game Boy Advance", "gba")) {
|
if(auto pathID = platform->load(ID::GameBoyAdvance, "Game Boy Advance", "gba")) {
|
||||||
information.pathID = pathID();
|
information.pathID = pathID();
|
||||||
} else return false;
|
} else return false;
|
||||||
|
|
||||||
if(auto fp = interface->open(pathID(), "manifest.bml", File::Read, File::Required)) {
|
if(auto fp = platform->open(pathID(), "manifest.bml", File::Read, File::Required)) {
|
||||||
information.manifest = fp->reads();
|
information.manifest = fp->reads();
|
||||||
} else return false;
|
} else return false;
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ auto Cartridge::load() -> bool {
|
||||||
|
|
||||||
if(auto node = document["board/rom"]) {
|
if(auto node = document["board/rom"]) {
|
||||||
mrom.size = min(32 * 1024 * 1024, node["size"].natural());
|
mrom.size = min(32 * 1024 * 1024, node["size"].natural());
|
||||||
if(auto fp = interface->open(pathID(), node["name"].text(), File::Read, File::Required)) {
|
if(auto fp = platform->open(pathID(), node["name"].text(), File::Read, File::Required)) {
|
||||||
fp->read(mrom.data, mrom.size);
|
fp->read(mrom.data, mrom.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ auto Cartridge::load() -> bool {
|
||||||
sram.mask = sram.size - 1;
|
sram.mask = sram.size - 1;
|
||||||
for(auto n : range(sram.size)) sram.data[n] = 0xff;
|
for(auto n : range(sram.size)) sram.data[n] = 0xff;
|
||||||
|
|
||||||
if(auto fp = interface->open(pathID(), node["name"].text(), File::Read)) {
|
if(auto fp = platform->open(pathID(), node["name"].text(), File::Read)) {
|
||||||
fp->read(sram.data, sram.size);
|
fp->read(sram.data, sram.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ auto Cartridge::load() -> bool {
|
||||||
eeprom.test = mrom.size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
|
eeprom.test = mrom.size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
|
||||||
for(auto n : range(eeprom.size)) eeprom.data[n] = 0xff;
|
for(auto n : range(eeprom.size)) eeprom.data[n] = 0xff;
|
||||||
|
|
||||||
if(auto fp = interface->open(pathID(), node["name"].text(), File::Read)) {
|
if(auto fp = platform->open(pathID(), node["name"].text(), File::Read)) {
|
||||||
fp->read(eeprom.data, eeprom.size);
|
fp->read(eeprom.data, eeprom.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ auto Cartridge::load() -> bool {
|
||||||
if(!flash.id && flash.size == 64 * 1024) flash.id = 0x1cc2;
|
if(!flash.id && flash.size == 64 * 1024) flash.id = 0x1cc2;
|
||||||
if(!flash.id && flash.size == 128 * 1024) flash.id = 0x09c2;
|
if(!flash.id && flash.size == 128 * 1024) flash.id = 0x09c2;
|
||||||
|
|
||||||
if(auto fp = interface->open(pathID(), node["name"].text(), File::Read)) {
|
if(auto fp = platform->open(pathID(), node["name"].text(), File::Read)) {
|
||||||
fp->read(flash.data, flash.size);
|
fp->read(flash.data, flash.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ auto Cartridge::load() -> bool {
|
||||||
auto Cartridge::save() -> void {
|
auto Cartridge::save() -> void {
|
||||||
auto document = BML::unserialize(information.manifest);
|
auto document = BML::unserialize(information.manifest);
|
||||||
if(auto node = document["board/ram"]) {
|
if(auto node = document["board/ram"]) {
|
||||||
if(auto fp = interface->open(pathID(), node["name"].text(), File::Write)) {
|
if(auto fp = platform->open(pathID(), node["name"].text(), File::Write)) {
|
||||||
if(node["type"].text() == "sram") fp->write(sram.data, sram.size);
|
if(node["type"].text() == "sram") fp->write(sram.data, sram.size);
|
||||||
if(node["type"].text() == "eeprom") fp->write(eeprom.data, eeprom.size);
|
if(node["type"].text() == "eeprom") fp->write(eeprom.data, eeprom.size);
|
||||||
if(node["type"].text() == "flash") fp->write(flash.data, flash.size);
|
if(node["type"].text() == "flash") fp->write(flash.data, flash.size);
|
||||||
|
|
|
@ -97,7 +97,7 @@ auto CPU::keypadRun() -> void {
|
||||||
bool test = regs.keypad.control.condition; //0 = OR, 1 = AND
|
bool test = regs.keypad.control.condition; //0 = OR, 1 = AND
|
||||||
for(auto n : range(10)) {
|
for(auto n : range(10)) {
|
||||||
if(!regs.keypad.control.flag[n]) continue;
|
if(!regs.keypad.control.flag[n]) continue;
|
||||||
bool input = interface->inputPoll(0, 0, lookup[n]);
|
bool input = platform->inputPoll(0, 0, lookup[n]);
|
||||||
if(regs.keypad.control.condition == 0) test |= input;
|
if(regs.keypad.control.condition == 0) test |= input;
|
||||||
if(regs.keypad.control.condition == 1) test &= input;
|
if(regs.keypad.control.condition == 1) test &= input;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ auto CPU::readIO(uint32 addr) -> uint8 {
|
||||||
static const uint lookup[] = {5, 4, 8, 9, 3, 2, 0, 1};
|
static const uint lookup[] = {5, 4, 8, 9, 3, 2, 0, 1};
|
||||||
if(auto result = player.keyinput()) return result() >> 0;
|
if(auto result = player.keyinput()) return result() >> 0;
|
||||||
uint8 result = 0;
|
uint8 result = 0;
|
||||||
for(uint n = 0; n < 8; n++) result |= interface->inputPoll(0, 0, lookup[n]) << n;
|
for(uint n = 0; n < 8; n++) result |= platform->inputPoll(0, 0, lookup[n]) << n;
|
||||||
if((result & 0xc0) == 0xc0) result &= (uint8)~0xc0; //up+down cannot be pressed simultaneously
|
if((result & 0xc0) == 0xc0) result &= (uint8)~0xc0; //up+down cannot be pressed simultaneously
|
||||||
if((result & 0x30) == 0x30) result &= (uint8)~0x30; //left+right cannot be pressed simultaneously
|
if((result & 0x30) == 0x30) result &= (uint8)~0x30; //left+right cannot be pressed simultaneously
|
||||||
return result ^ 0xff;
|
return result ^ 0xff;
|
||||||
|
@ -72,8 +72,8 @@ auto CPU::readIO(uint32 addr) -> uint8 {
|
||||||
case 0x04000131: {
|
case 0x04000131: {
|
||||||
if(auto result = player.keyinput()) return result() >> 8;
|
if(auto result = player.keyinput()) return result() >> 8;
|
||||||
uint8 result = 0;
|
uint8 result = 0;
|
||||||
result |= interface->inputPoll(0, 0, 7) << 0;
|
result |= platform->inputPoll(0, 0, 7) << 0;
|
||||||
result |= interface->inputPoll(0, 0, 6) << 1;
|
result |= platform->inputPoll(0, 0, 6) << 1;
|
||||||
return result ^ 0x03;
|
return result ^ 0x03;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <processor/arm/arm.hpp>
|
#include <processor/arm/arm.hpp>
|
||||||
|
|
||||||
namespace GameBoyAdvance {
|
namespace GameBoyAdvance {
|
||||||
|
#define platform Emulator::platform
|
||||||
using File = Emulator::File;
|
using File = Emulator::File;
|
||||||
using Scheduler = Emulator::Scheduler;
|
using Scheduler = Emulator::Scheduler;
|
||||||
extern Scheduler scheduler;
|
extern Scheduler scheduler;
|
||||||
|
|
|
@ -2,12 +2,9 @@
|
||||||
|
|
||||||
namespace GameBoyAdvance {
|
namespace GameBoyAdvance {
|
||||||
|
|
||||||
Interface* interface = nullptr;
|
|
||||||
Settings settings;
|
Settings settings;
|
||||||
|
|
||||||
Interface::Interface() {
|
Interface::Interface() {
|
||||||
interface = this;
|
|
||||||
|
|
||||||
information.manufacturer = "Nintendo";
|
information.manufacturer = "Nintendo";
|
||||||
information.name = "Game Boy Advance";
|
information.name = "Game Boy Advance";
|
||||||
information.overscan = false;
|
information.overscan = false;
|
||||||
|
@ -96,7 +93,7 @@ auto Interface::loaded() -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::load(uint id) -> bool {
|
auto Interface::load(uint id) -> bool {
|
||||||
return system.load();
|
return system.load(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::save() -> void {
|
auto Interface::save() -> void {
|
||||||
|
|
|
@ -53,7 +53,6 @@ struct Settings {
|
||||||
bool colorEmulation = true;
|
bool colorEmulation = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Interface* interface;
|
|
||||||
extern Settings settings;
|
extern Settings settings;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ auto Player::write(uint2 addr, uint8 byte) -> void {
|
||||||
|
|
||||||
if(addr == 3 && status.packet == 15) {
|
if(addr == 3 && status.packet == 15) {
|
||||||
status.rumble = (status.recv & 0xff) == 0x26; //on = 0x26, off = 0x04
|
status.rumble = (status.recv & 0xff) == 0x26; //on = 0x26, off = 0x04
|
||||||
interface->inputRumble(0, 0, 10, status.rumble);
|
platform->inputRumble(0, 0, 10, status.rumble);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,20 +34,23 @@ auto System::power() -> void {
|
||||||
scheduler.primary(cpu);
|
scheduler.primary(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::load() -> bool {
|
auto System::load(Emulator::Interface* interface) -> bool {
|
||||||
if(auto fp = interface->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
if(auto fp = platform->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
||||||
information.manifest = fp->reads();
|
information.manifest = fp->reads();
|
||||||
} else return false;
|
} else return false;
|
||||||
|
|
||||||
auto document = BML::unserialize(information.manifest);
|
auto document = BML::unserialize(information.manifest);
|
||||||
|
|
||||||
if(auto name = document["system/cpu/rom/name"].text()) {
|
if(auto name = document["system/cpu/rom/name"].text()) {
|
||||||
if(auto fp = interface->open(ID::System, name, File::Read, File::Required)) {
|
if(auto fp = platform->open(ID::System, name, File::Read, File::Required)) {
|
||||||
fp->read(bios.data, bios.size);
|
fp->read(bios.data, bios.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!cartridge.load()) return false;
|
if(!cartridge.load()) return false;
|
||||||
|
|
||||||
serializeInit();
|
serializeInit();
|
||||||
|
this->interface = interface;
|
||||||
return _loaded = true;
|
return _loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ struct System {
|
||||||
|
|
||||||
auto init() -> void;
|
auto init() -> void;
|
||||||
auto term() -> void;
|
auto term() -> void;
|
||||||
auto load() -> bool;
|
auto load(Emulator::Interface*) -> bool;
|
||||||
auto save() -> void;
|
auto save() -> void;
|
||||||
auto unload() -> void;
|
auto unload() -> void;
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
@ -38,6 +38,9 @@ struct System {
|
||||||
auto serializeAll(serializer&) -> void;
|
auto serializeAll(serializer&) -> void;
|
||||||
auto serializeInit() -> void;
|
auto serializeInit() -> void;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Emulator::Interface* interface = nullptr;
|
||||||
|
|
||||||
struct Information {
|
struct Information {
|
||||||
string manifest;
|
string manifest;
|
||||||
} information;
|
} information;
|
||||||
|
|
|
@ -5,13 +5,13 @@ namespace MegaDrive {
|
||||||
Cartridge cartridge;
|
Cartridge cartridge;
|
||||||
|
|
||||||
auto Cartridge::load() -> bool {
|
auto Cartridge::load() -> bool {
|
||||||
information = Information();
|
information = {};
|
||||||
|
|
||||||
if(auto pathID = interface->load(ID::MegaDrive, "Mega Drive", "md")) {
|
if(auto pathID = platform->load(ID::MegaDrive, "Mega Drive", "md")) {
|
||||||
information.pathID = pathID();
|
information.pathID = pathID();
|
||||||
} else return false;
|
} else return false;
|
||||||
|
|
||||||
if(auto fp = interface->open(pathID(), "manifest.bml", File::Read, File::Required)) {
|
if(auto fp = platform->open(pathID(), "manifest.bml", File::Read, File::Required)) {
|
||||||
information.manifest = fp->reads();
|
information.manifest = fp->reads();
|
||||||
} else return false;
|
} else return false;
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ auto Cartridge::load() -> bool {
|
||||||
if(rom.size) {
|
if(rom.size) {
|
||||||
rom.data = new uint8[rom.mask + 1];
|
rom.data = new uint8[rom.mask + 1];
|
||||||
if(auto name = node["name"].text()) {
|
if(auto name = node["name"].text()) {
|
||||||
if(auto fp = interface->open(pathID(), name, File::Read, File::Required)) {
|
if(auto fp = platform->open(pathID(), name, File::Read, File::Required)) {
|
||||||
fp->read(rom.data, rom.size);
|
fp->read(rom.data, rom.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ auto Cartridge::load() -> bool {
|
||||||
if(ram.size) {
|
if(ram.size) {
|
||||||
ram.data = new uint8[ram.mask + 1];
|
ram.data = new uint8[ram.mask + 1];
|
||||||
if(auto name = node["name"].text()) {
|
if(auto name = node["name"].text()) {
|
||||||
if(auto fp = interface->open(pathID(), name, File::Read)) {
|
if(auto fp = platform->open(pathID(), name, File::Read)) {
|
||||||
fp->read(ram.data, ram.size);
|
fp->read(ram.data, ram.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ auto Cartridge::save() -> void {
|
||||||
auto document = BML::unserialize(information.manifest);
|
auto document = BML::unserialize(information.manifest);
|
||||||
|
|
||||||
if(auto name = document["board/ram/name"].text()) {
|
if(auto name = document["board/ram/name"].text()) {
|
||||||
if(auto fp = interface->open(pathID(), name, File::Write)) {
|
if(auto fp = platform->open(pathID(), name, File::Write)) {
|
||||||
fp->write(ram.data, ram.size);
|
fp->write(ram.data, ram.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,19 +5,19 @@ auto Gamepad::readData() -> uint8 {
|
||||||
uint6 data;
|
uint6 data;
|
||||||
|
|
||||||
if(select == 0) {
|
if(select == 0) {
|
||||||
data.bit(0) = interface->inputPoll(port, ID::Device::Gamepad, Up);
|
data.bit(0) = platform->inputPoll(port, ID::Device::Gamepad, Up);
|
||||||
data.bit(1) = interface->inputPoll(port, ID::Device::Gamepad, Down);
|
data.bit(1) = platform->inputPoll(port, ID::Device::Gamepad, Down);
|
||||||
data.bit(2) = 1;
|
data.bit(2) = 1;
|
||||||
data.bit(3) = 1;
|
data.bit(3) = 1;
|
||||||
data.bit(4) = interface->inputPoll(port, ID::Device::Gamepad, A);
|
data.bit(4) = platform->inputPoll(port, ID::Device::Gamepad, A);
|
||||||
data.bit(5) = interface->inputPoll(port, ID::Device::Gamepad, Start);
|
data.bit(5) = platform->inputPoll(port, ID::Device::Gamepad, Start);
|
||||||
} else {
|
} else {
|
||||||
data.bit(0) = interface->inputPoll(port, ID::Device::Gamepad, Up);
|
data.bit(0) = platform->inputPoll(port, ID::Device::Gamepad, Up);
|
||||||
data.bit(1) = interface->inputPoll(port, ID::Device::Gamepad, Down);
|
data.bit(1) = platform->inputPoll(port, ID::Device::Gamepad, Down);
|
||||||
data.bit(2) = interface->inputPoll(port, ID::Device::Gamepad, Left);
|
data.bit(2) = platform->inputPoll(port, ID::Device::Gamepad, Left);
|
||||||
data.bit(3) = interface->inputPoll(port, ID::Device::Gamepad, Right);
|
data.bit(3) = platform->inputPoll(port, ID::Device::Gamepad, Right);
|
||||||
data.bit(4) = interface->inputPoll(port, ID::Device::Gamepad, B);
|
data.bit(4) = platform->inputPoll(port, ID::Device::Gamepad, B);
|
||||||
data.bit(5) = interface->inputPoll(port, ID::Device::Gamepad, C);
|
data.bit(5) = platform->inputPoll(port, ID::Device::Gamepad, C);
|
||||||
}
|
}
|
||||||
|
|
||||||
data = ~data;
|
data = ~data;
|
||||||
|
|
|
@ -2,12 +2,9 @@
|
||||||
|
|
||||||
namespace MegaDrive {
|
namespace MegaDrive {
|
||||||
|
|
||||||
Interface* interface = nullptr;
|
|
||||||
Settings settings;
|
Settings settings;
|
||||||
|
|
||||||
Interface::Interface() {
|
Interface::Interface() {
|
||||||
interface = this;
|
|
||||||
|
|
||||||
information.manufacturer = "Sega";
|
information.manufacturer = "Sega";
|
||||||
information.name = "Mega Drive";
|
information.name = "Mega Drive";
|
||||||
information.overscan = true;
|
information.overscan = true;
|
||||||
|
@ -97,7 +94,7 @@ auto Interface::loaded() -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::load(uint id) -> bool {
|
auto Interface::load(uint id) -> bool {
|
||||||
return system.load();
|
return system.load(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::save() -> void {
|
auto Interface::save() -> void {
|
||||||
|
@ -109,7 +106,7 @@ auto Interface::unload() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::connect(uint port, uint device) -> void {
|
auto Interface::connect(uint port, uint device) -> void {
|
||||||
MegaDrive::peripherals.connect(port, device);
|
peripherals.connect(port, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::power() -> void {
|
auto Interface::power() -> void {
|
||||||
|
|
|
@ -58,7 +58,6 @@ struct Settings {
|
||||||
uint extensionPort = 0;
|
uint extensionPort = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Interface* interface;
|
|
||||||
extern Settings settings;
|
extern Settings settings;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <processor/z80/z80.hpp>
|
#include <processor/z80/z80.hpp>
|
||||||
|
|
||||||
namespace MegaDrive {
|
namespace MegaDrive {
|
||||||
|
#define platform Emulator::platform
|
||||||
using File = Emulator::File;
|
using File = Emulator::File;
|
||||||
using Scheduler = Emulator::Scheduler;
|
using Scheduler = Emulator::Scheduler;
|
||||||
extern Scheduler scheduler;
|
extern Scheduler scheduler;
|
||||||
|
|
|
@ -10,14 +10,18 @@ auto System::run() -> void {
|
||||||
if(scheduler.enter() == Scheduler::Event::Frame) vdp.refresh();
|
if(scheduler.enter() == Scheduler::Event::Frame) vdp.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::load() -> bool {
|
auto System::load(Emulator::Interface* interface) -> bool {
|
||||||
information = Information();
|
information = {};
|
||||||
if(auto fp = interface->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
|
||||||
|
if(auto fp = platform->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
||||||
information.manifest = fp->reads();
|
information.manifest = fp->reads();
|
||||||
} else return false;
|
} else return false;
|
||||||
|
|
||||||
auto document = BML::unserialize(information.manifest);
|
auto document = BML::unserialize(information.manifest);
|
||||||
if(!cartridge.load()) return false;
|
if(!cartridge.load()) return false;
|
||||||
|
|
||||||
information.colorburst = Emulator::Constants::Colorburst::NTSC;
|
information.colorburst = Emulator::Constants::Colorburst::NTSC;
|
||||||
|
this->interface = interface;
|
||||||
return information.loaded = true;
|
return information.loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,15 @@ struct System {
|
||||||
|
|
||||||
auto run() -> void;
|
auto run() -> void;
|
||||||
|
|
||||||
auto load() -> bool;
|
auto load(Emulator::Interface*) -> bool;
|
||||||
auto save() -> void;
|
auto save() -> void;
|
||||||
auto unload() -> void;
|
auto unload() -> void;
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Emulator::Interface* interface = nullptr;
|
||||||
|
|
||||||
struct Information {
|
struct Information {
|
||||||
bool loaded = false;
|
bool loaded = false;
|
||||||
string manifest;
|
string manifest;
|
||||||
|
|
|
@ -19,6 +19,11 @@ auto Bus::in(uint8 addr) -> uint8 {
|
||||||
switch(addr >> 6) {
|
switch(addr >> 6) {
|
||||||
|
|
||||||
case 0: {
|
case 0: {
|
||||||
|
if(system.model() == Model::GameGear) {
|
||||||
|
auto hardware = peripherals.hardware->readData();
|
||||||
|
return hardware.bit(6) << 7 | 0x7f;
|
||||||
|
}
|
||||||
|
|
||||||
return 0xff; //SMS1 = MDR, SMS2 = 0xff
|
return 0xff; //SMS1 = MDR, SMS2 = 0xff
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,16 +36,26 @@ auto Bus::in(uint8 addr) -> uint8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
case 3: {
|
case 3: {
|
||||||
auto A = peripherals.controllerPort1->readData();
|
if(system.model() == Model::MasterSystem) {
|
||||||
auto B = peripherals.controllerPort2->readData();
|
auto hardware = peripherals.hardware->readData();
|
||||||
|
auto port1 = peripherals.controllerPort1->readData();
|
||||||
|
auto port2 = peripherals.controllerPort2->readData();
|
||||||
if(addr.bit(0) == 0) {
|
if(addr.bit(0) == 0) {
|
||||||
return A.bits(0,5) << 0 | B.bits(0,1) << 6;
|
return port1.bits(0,5) << 0 | port2.bits(0,1) << 6;
|
||||||
} else {
|
} else {
|
||||||
//d4 = reset button
|
return port2.bits(2,5) << 0 | hardware.bit(0) << 4 | 1 << 5 | port1.bit(6) << 6 | port2.bit(6) << 7;
|
||||||
//d5 = cartridge CONT pin
|
|
||||||
return B.bits(2,5) << 0 | 1 << 4 | 1 << 5 | A.bit(6) << 6 | B.bit(6) << 7;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(system.model() == Model::GameGear) {
|
||||||
|
auto hardware = peripherals.hardware->readData();
|
||||||
|
if(addr.bit(0) == 0) {
|
||||||
|
return hardware.bits(0,5) << 0 | 0xc0;
|
||||||
|
} else {
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,18 +10,18 @@ auto Cartridge::load() -> bool {
|
||||||
|
|
||||||
switch(system.model()) {
|
switch(system.model()) {
|
||||||
case Model::MasterSystem:
|
case Model::MasterSystem:
|
||||||
if(auto pathID = interface->load(ID::MasterSystem, "Master System", "ms")) {
|
if(auto pathID = platform->load(ID::MasterSystem, "Master System", "ms")) {
|
||||||
information.pathID = pathID();
|
information.pathID = pathID();
|
||||||
} else return false;
|
} else return false;
|
||||||
break;
|
break;
|
||||||
case Model::GameGear:
|
case Model::GameGear:
|
||||||
if(auto pathID = interface->load(ID::GameGear, "Game Gear", "gg")) {
|
if(auto pathID = platform->load(ID::GameGear, "Game Gear", "gg")) {
|
||||||
information.pathID = pathID();
|
information.pathID = pathID();
|
||||||
} else return false;
|
} else return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(auto fp = interface->open(pathID(), "manifest.bml", File::Read, File::Required)) {
|
if(auto fp = platform->open(pathID(), "manifest.bml", File::Read, File::Required)) {
|
||||||
information.manifest = fp->reads();
|
information.manifest = fp->reads();
|
||||||
} else return false;
|
} else return false;
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ auto Cartridge::load() -> bool {
|
||||||
if(rom.size) {
|
if(rom.size) {
|
||||||
rom.data = new uint8[rom.mask + 1];
|
rom.data = new uint8[rom.mask + 1];
|
||||||
if(auto name = node["name"].text()) {
|
if(auto name = node["name"].text()) {
|
||||||
if(auto fp = interface->open(pathID(), name, File::Read, File::Required)) {
|
if(auto fp = platform->open(pathID(), name, File::Read, File::Required)) {
|
||||||
fp->read(rom.data, rom.size);
|
fp->read(rom.data, rom.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ auto Cartridge::load() -> bool {
|
||||||
if(ram.size) {
|
if(ram.size) {
|
||||||
ram.data = new uint8[ram.mask + 1];
|
ram.data = new uint8[ram.mask + 1];
|
||||||
if(auto name = node["name"].text()) {
|
if(auto name = node["name"].text()) {
|
||||||
if(auto fp = interface->open(pathID(), name, File::Read)) {
|
if(auto fp = platform->open(pathID(), name, File::Read)) {
|
||||||
fp->read(ram.data, ram.size);
|
fp->read(ram.data, ram.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ auto Cartridge::save() -> void {
|
||||||
auto document = BML::unserialize(information.manifest);
|
auto document = BML::unserialize(information.manifest);
|
||||||
|
|
||||||
if(auto name = document["board/ram/name"].text()) {
|
if(auto name = document["board/ram/name"].text()) {
|
||||||
if(auto fp = interface->open(pathID(), name, File::Write)) {
|
if(auto fp = platform->open(pathID(), name, File::Write)) {
|
||||||
fp->write(ram.data, ram.size);
|
fp->write(ram.data, ram.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,9 +75,6 @@ auto Cartridge::unload() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::power() -> void {
|
auto Cartridge::power() -> void {
|
||||||
}
|
|
||||||
|
|
||||||
auto Cartridge::reset() -> void {
|
|
||||||
memory::fill(&mapper, sizeof(Mapper));
|
memory::fill(&mapper, sizeof(Mapper));
|
||||||
mapper.romPage0 = 0;
|
mapper.romPage0 = 0;
|
||||||
mapper.romPage1 = 1;
|
mapper.romPage1 = 1;
|
||||||
|
|
|
@ -9,7 +9,6 @@ struct Cartridge {
|
||||||
auto unload() -> void;
|
auto unload() -> void;
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
|
||||||
|
|
||||||
//mapper.cpp
|
//mapper.cpp
|
||||||
auto read(uint16 addr) -> maybe<uint8>;
|
auto read(uint16 addr) -> maybe<uint8>;
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
namespace MasterSystem {
|
namespace MasterSystem {
|
||||||
|
|
||||||
|
#include "mastersystem/mastersystem.cpp"
|
||||||
|
#include "gamegear/gamegear.cpp"
|
||||||
#include "gamepad/gamepad.cpp"
|
#include "gamepad/gamepad.cpp"
|
||||||
|
|
||||||
Controller::Controller(uint port) : port(port) {
|
Controller::Controller(uint port) : port(port) {
|
||||||
|
@ -14,8 +16,9 @@ Controller::~Controller() {
|
||||||
auto Controller::Enter() -> void {
|
auto Controller::Enter() -> void {
|
||||||
while(true) {
|
while(true) {
|
||||||
scheduler.synchronize();
|
scheduler.synchronize();
|
||||||
if(peripherals.controllerPort1->active()) peripherals.controllerPort1->main();
|
if(auto device = peripherals.hardware) if(device->active()) device->main();
|
||||||
if(peripherals.controllerPort2->active()) peripherals.controllerPort2->main();
|
if(auto device = peripherals.controllerPort1) if(device->active()) device->main();
|
||||||
|
if(auto device = peripherals.controllerPort2) if(device->active()) device->main();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,11 @@ struct Controller : Thread {
|
||||||
static auto Enter() -> void;
|
static auto Enter() -> void;
|
||||||
auto main() -> void;
|
auto main() -> void;
|
||||||
|
|
||||||
virtual auto readData() -> uint7 { return 0x7f; }
|
virtual auto readData() -> uint8 { return 0xff; }
|
||||||
|
|
||||||
const uint port;
|
const uint port;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#include "mastersystem/mastersystem.hpp"
|
||||||
|
#include "gamegear/gamegear.hpp"
|
||||||
#include "gamepad/gamepad.hpp"
|
#include "gamepad/gamepad.hpp"
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
GameGearControls::GameGearControls(uint port) : Controller(port) {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GameGearControls::readData() -> uint8 {
|
||||||
|
uint8 data = 0xff;
|
||||||
|
data.bit(0) = !platform->inputPoll(port, ID::Device::GameGearControls, Up);
|
||||||
|
data.bit(1) = !platform->inputPoll(port, ID::Device::GameGearControls, Down);
|
||||||
|
data.bit(2) = !platform->inputPoll(port, ID::Device::GameGearControls, Left);
|
||||||
|
data.bit(3) = !platform->inputPoll(port, ID::Device::GameGearControls, Right);
|
||||||
|
data.bit(4) = !platform->inputPoll(port, ID::Device::GameGearControls, One);
|
||||||
|
data.bit(5) = !platform->inputPoll(port, ID::Device::GameGearControls, Two);
|
||||||
|
data.bit(6) = !platform->inputPoll(port, ID::Device::GameGearControls, Start);
|
||||||
|
return data;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
struct GameGearControls : Controller {
|
||||||
|
enum : uint {
|
||||||
|
Up, Down, Left, Right, One, Two, Start,
|
||||||
|
};
|
||||||
|
|
||||||
|
GameGearControls(uint port);
|
||||||
|
|
||||||
|
auto readData() -> uint8 override;
|
||||||
|
};
|
|
@ -1,16 +1,13 @@
|
||||||
Gamepad::Gamepad(uint port) : Controller(port) {
|
Gamepad::Gamepad(uint port) : Controller(port) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Gamepad::readData() -> uint7 {
|
auto Gamepad::readData() -> uint8 {
|
||||||
uint7 data;
|
uint8 data = 0xff;
|
||||||
|
data.bit(0) = !platform->inputPoll(port, ID::Device::Gamepad, Up);
|
||||||
data.bit(0) = !interface->inputPoll(port, ID::Device::Gamepad, Up);
|
data.bit(1) = !platform->inputPoll(port, ID::Device::Gamepad, Down);
|
||||||
data.bit(1) = !interface->inputPoll(port, ID::Device::Gamepad, Down);
|
data.bit(2) = !platform->inputPoll(port, ID::Device::Gamepad, Left);
|
||||||
data.bit(2) = !interface->inputPoll(port, ID::Device::Gamepad, Left);
|
data.bit(3) = !platform->inputPoll(port, ID::Device::Gamepad, Right);
|
||||||
data.bit(3) = !interface->inputPoll(port, ID::Device::Gamepad, Right);
|
data.bit(4) = !platform->inputPoll(port, ID::Device::Gamepad, One);
|
||||||
data.bit(4) = !interface->inputPoll(port, ID::Device::Gamepad, One);
|
data.bit(5) = !platform->inputPoll(port, ID::Device::Gamepad, Two);
|
||||||
data.bit(5) = !interface->inputPoll(port, ID::Device::Gamepad, Two);
|
|
||||||
data.bit(6) = 1;
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,5 +5,5 @@ struct Gamepad : Controller {
|
||||||
|
|
||||||
Gamepad(uint port);
|
Gamepad(uint port);
|
||||||
|
|
||||||
auto readData() -> uint7 override;
|
auto readData() -> uint8 override;
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
MasterSystemControls::MasterSystemControls(uint port) : Controller(port) {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MasterSystemControls::readData() -> uint8 {
|
||||||
|
uint8 data = 0xff;
|
||||||
|
data.bit(0) = !platform->inputPoll(port, ID::Device::MasterSystemControls, Reset);
|
||||||
|
return data;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
struct MasterSystemControls : Controller {
|
||||||
|
enum : uint {
|
||||||
|
Reset,
|
||||||
|
};
|
||||||
|
|
||||||
|
MasterSystemControls(uint port);
|
||||||
|
|
||||||
|
auto readData() -> uint8 override;
|
||||||
|
};
|
|
@ -42,10 +42,6 @@ auto CPU::setINT(bool value) -> void {
|
||||||
auto CPU::power() -> void {
|
auto CPU::power() -> void {
|
||||||
Z80::bus = &MasterSystem::bus;
|
Z80::bus = &MasterSystem::bus;
|
||||||
Z80::power();
|
Z80::power();
|
||||||
}
|
|
||||||
|
|
||||||
auto CPU::reset() -> void {
|
|
||||||
Z80::reset();
|
|
||||||
create(CPU::Enter, system.colorburst());
|
create(CPU::Enter, system.colorburst());
|
||||||
|
|
||||||
memory::fill(&state, sizeof(State));
|
memory::fill(&state, sizeof(State));
|
||||||
|
|
|
@ -9,7 +9,6 @@ struct CPU : Processor::Z80, Thread {
|
||||||
auto setINT(bool value) -> void;
|
auto setINT(bool value) -> void;
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
|
||||||
|
|
||||||
vector<Thread*> peripherals;
|
vector<Thread*> peripherals;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
GameGearInterface::GameGearInterface() {
|
||||||
|
information.manufacturer = "Sega";
|
||||||
|
information.name = "Game Gear";
|
||||||
|
information.overscan = false;
|
||||||
|
information.resettable = false;
|
||||||
|
|
||||||
|
information.capability.states = false;
|
||||||
|
information.capability.cheats = false;
|
||||||
|
|
||||||
|
media.append({ID::GameGear, "Game Gear", "gg"});
|
||||||
|
|
||||||
|
Port hardware{ID::Port::Hardware, "Hardware"};
|
||||||
|
|
||||||
|
{ Device device{ID::Device::GameGearControls, "Controls"};
|
||||||
|
device.inputs.append({0, "Up"});
|
||||||
|
device.inputs.append({0, "Down"});
|
||||||
|
device.inputs.append({0, "Left"});
|
||||||
|
device.inputs.append({0, "Right"});
|
||||||
|
device.inputs.append({0, "1"});
|
||||||
|
device.inputs.append({0, "2"});
|
||||||
|
device.inputs.append({0, "Start"});
|
||||||
|
hardware.devices.append(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
ports.append(move(hardware));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GameGearInterface::manifest() -> string {
|
||||||
|
return cartridge.manifest();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GameGearInterface::title() -> string {
|
||||||
|
return cartridge.title();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GameGearInterface::videoSize() -> VideoSize {
|
||||||
|
return {160, 144};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GameGearInterface::videoSize(uint width, uint height, bool arc) -> VideoSize {
|
||||||
|
uint w = 160;
|
||||||
|
uint h = 144;
|
||||||
|
uint m = min(width / w, height / h);
|
||||||
|
return {w * m, h * m};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GameGearInterface::videoFrequency() -> double {
|
||||||
|
return 60.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GameGearInterface::videoColors() -> uint32 {
|
||||||
|
return 1 << 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GameGearInterface::videoColor(uint32 color) -> uint64 {
|
||||||
|
uint4 B = color >> 8;
|
||||||
|
uint4 G = color >> 4;
|
||||||
|
uint4 R = color >> 0;
|
||||||
|
|
||||||
|
uint64 r = image::normalize(R, 4, 16);
|
||||||
|
uint64 g = image::normalize(G, 4, 16);
|
||||||
|
uint64 b = image::normalize(B, 4, 16);
|
||||||
|
|
||||||
|
return r << 32 | g << 16 | b << 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GameGearInterface::audioFrequency() -> double {
|
||||||
|
return 44'100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GameGearInterface::loaded() -> bool {
|
||||||
|
return system.loaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GameGearInterface::load(uint id) -> bool {
|
||||||
|
if(id == ID::GameGear) return system.load(this, Model::GameGear);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GameGearInterface::save() -> void {
|
||||||
|
system.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GameGearInterface::unload() -> void {
|
||||||
|
system.unload();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GameGearInterface::connect(uint port, uint device) -> void {
|
||||||
|
peripherals.connect(port, device);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GameGearInterface::power() -> void {
|
||||||
|
system.power();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GameGearInterface::run() -> void {
|
||||||
|
system.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GameGearInterface::serialize() -> serializer {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GameGearInterface::unserialize(serializer& s) -> bool {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GameGearInterface::cap(const string& name) -> bool {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GameGearInterface::get(const string& name) -> any {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GameGearInterface::set(const string& name, const any& value) -> bool {
|
||||||
|
return false;
|
||||||
|
}
|
|
@ -2,142 +2,8 @@
|
||||||
|
|
||||||
namespace MasterSystem {
|
namespace MasterSystem {
|
||||||
|
|
||||||
Interface* interface = nullptr;
|
|
||||||
Settings settings;
|
Settings settings;
|
||||||
|
#include "master-system.cpp"
|
||||||
Interface::Interface() {
|
#include "game-gear.cpp"
|
||||||
interface = this;
|
|
||||||
|
|
||||||
information.manufacturer = "Sega";
|
|
||||||
information.name = "Master System";
|
|
||||||
information.overscan = true;
|
|
||||||
information.resettable = true;
|
|
||||||
|
|
||||||
information.capability.states = false;
|
|
||||||
information.capability.cheats = false;
|
|
||||||
|
|
||||||
media.append({ID::MasterSystem, "Master System", "ms"});
|
|
||||||
media.append({ID::GameGear, "Game Gear", "gg"});
|
|
||||||
|
|
||||||
Port controllerPort1{ID::Port::Controller1, "Controller Port 1"};
|
|
||||||
Port controllerPort2{ID::Port::Controller2, "Controller Port 2"};
|
|
||||||
|
|
||||||
{ Device device{ID::Device::None, "None"};
|
|
||||||
controllerPort1.devices.append(device);
|
|
||||||
controllerPort2.devices.append(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
{ Device device{ID::Device::Gamepad, "Gamepad"};
|
|
||||||
device.inputs.append({0, "Up"});
|
|
||||||
device.inputs.append({0, "Down"});
|
|
||||||
device.inputs.append({0, "Left"});
|
|
||||||
device.inputs.append({0, "Right"});
|
|
||||||
device.inputs.append({0, "1"});
|
|
||||||
device.inputs.append({0, "2"});
|
|
||||||
controllerPort1.devices.append(device);
|
|
||||||
controllerPort2.devices.append(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
ports.append(move(controllerPort1));
|
|
||||||
ports.append(move(controllerPort2));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Interface::manifest() -> string {
|
|
||||||
return cartridge.manifest();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Interface::title() -> string {
|
|
||||||
return cartridge.title();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Interface::videoSize() -> VideoSize {
|
|
||||||
return {256, 240};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Interface::videoSize(uint width, uint height, bool arc) -> VideoSize {
|
|
||||||
auto a = arc ? 8.0 / 7.0 : 1.0;
|
|
||||||
uint w = 256;
|
|
||||||
uint h = 240;
|
|
||||||
uint m = min(width / (w * a), height / h);
|
|
||||||
return {uint(w * a * m), uint(h * m)};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Interface::videoFrequency() -> double {
|
|
||||||
return 60.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Interface::videoColors() -> uint32 {
|
|
||||||
return 1 << 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Interface::videoColor(uint32 color) -> uint64 {
|
|
||||||
uint2 B = color >> 4;
|
|
||||||
uint2 G = color >> 2;
|
|
||||||
uint2 R = color >> 0;
|
|
||||||
|
|
||||||
uint64 r = image::normalize(R, 2, 16);
|
|
||||||
uint64 g = image::normalize(G, 2, 16);
|
|
||||||
uint64 b = image::normalize(B, 2, 16);
|
|
||||||
|
|
||||||
return r << 32 | g << 16 | b << 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Interface::audioFrequency() -> double {
|
|
||||||
return 44'100.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Interface::loaded() -> bool {
|
|
||||||
return system.loaded();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Interface::load(uint id) -> bool {
|
|
||||||
if(id == ID::MasterSystem) return system.load(Model::MasterSystem);
|
|
||||||
if(id == ID::GameGear) return system.load(Model::GameGear);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Interface::save() -> void {
|
|
||||||
system.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Interface::unload() -> void {
|
|
||||||
system.unload();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Interface::connect(uint port, uint device) -> void {
|
|
||||||
MasterSystem::peripherals.connect(port, device);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Interface::power() -> void {
|
|
||||||
system.power();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Interface::reset() -> void {
|
|
||||||
system.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,20 +8,56 @@ struct ID {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Port { enum : uint {
|
struct Port { enum : uint {
|
||||||
|
Hardware,
|
||||||
Controller1,
|
Controller1,
|
||||||
Controller2,
|
Controller2,
|
||||||
};};
|
};};
|
||||||
|
|
||||||
struct Device { enum : uint {
|
struct Device { enum : uint {
|
||||||
None,
|
None,
|
||||||
|
MasterSystemControls,
|
||||||
|
GameGearControls,
|
||||||
Gamepad,
|
Gamepad,
|
||||||
};};
|
};};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Interface : Emulator::Interface {
|
struct MasterSystemInterface : Emulator::Interface {
|
||||||
using Emulator::Interface::load;
|
using Emulator::Interface::load;
|
||||||
|
|
||||||
Interface();
|
MasterSystemInterface();
|
||||||
|
|
||||||
|
auto manifest() -> string override;
|
||||||
|
auto title() -> string override;
|
||||||
|
|
||||||
|
auto videoSize() -> VideoSize override;
|
||||||
|
auto videoSize(uint width, uint height, bool arc) -> VideoSize override;
|
||||||
|
auto videoFrequency() -> double override;
|
||||||
|
auto videoColors() -> uint32 override;
|
||||||
|
auto videoColor(uint32 color) -> uint64 override;
|
||||||
|
|
||||||
|
auto audioFrequency() -> double override;
|
||||||
|
|
||||||
|
auto loaded() -> bool override;
|
||||||
|
auto load(uint id) -> bool override;
|
||||||
|
auto save() -> void override;
|
||||||
|
auto unload() -> void override;
|
||||||
|
|
||||||
|
auto connect(uint port, uint device) -> 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GameGearInterface : Emulator::Interface {
|
||||||
|
using Emulator::Interface::load;
|
||||||
|
|
||||||
|
GameGearInterface();
|
||||||
|
|
||||||
auto manifest() -> string override;
|
auto manifest() -> string override;
|
||||||
auto title() -> string override;
|
auto title() -> string override;
|
||||||
|
@ -41,7 +77,6 @@ struct Interface : Emulator::Interface {
|
||||||
|
|
||||||
auto connect(uint port, uint device) -> void override;
|
auto connect(uint port, uint device) -> void override;
|
||||||
auto power() -> void override;
|
auto power() -> void override;
|
||||||
auto reset() -> void override;
|
|
||||||
auto run() -> void override;
|
auto run() -> void override;
|
||||||
|
|
||||||
auto serialize() -> serializer override;
|
auto serialize() -> serializer override;
|
||||||
|
@ -53,11 +88,11 @@ struct Interface : Emulator::Interface {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Settings {
|
struct Settings {
|
||||||
|
uint hardware = 0;
|
||||||
uint controllerPort1 = 0;
|
uint controllerPort1 = 0;
|
||||||
uint controllerPort2 = 0;
|
uint controllerPort2 = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Interface* interface;
|
|
||||||
extern Settings settings;
|
extern Settings settings;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
MasterSystemInterface::MasterSystemInterface() {
|
||||||
|
information.manufacturer = "Sega";
|
||||||
|
information.name = "Master System";
|
||||||
|
information.overscan = true;
|
||||||
|
information.resettable = false;
|
||||||
|
|
||||||
|
information.capability.states = false;
|
||||||
|
information.capability.cheats = false;
|
||||||
|
|
||||||
|
media.append({ID::MasterSystem, "Master System", "ms"});
|
||||||
|
|
||||||
|
Port hardware{ID::Port::Hardware, "Hardware"};
|
||||||
|
Port controllerPort1{ID::Port::Controller1, "Controller Port 1"};
|
||||||
|
Port controllerPort2{ID::Port::Controller2, "Controller Port 2"};
|
||||||
|
|
||||||
|
{ Device device{ID::Device::MasterSystemControls, "Controls"};
|
||||||
|
device.inputs.append({0, "Reset"});
|
||||||
|
hardware.devices.append(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ Device device{ID::Device::None, "None"};
|
||||||
|
controllerPort1.devices.append(device);
|
||||||
|
controllerPort2.devices.append(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ Device device{ID::Device::Gamepad, "Gamepad"};
|
||||||
|
device.inputs.append({0, "Up"});
|
||||||
|
device.inputs.append({0, "Down"});
|
||||||
|
device.inputs.append({0, "Left"});
|
||||||
|
device.inputs.append({0, "Right"});
|
||||||
|
device.inputs.append({0, "1"});
|
||||||
|
device.inputs.append({0, "2"});
|
||||||
|
controllerPort1.devices.append(device);
|
||||||
|
controllerPort2.devices.append(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
ports.append(move(hardware));
|
||||||
|
ports.append(move(controllerPort1));
|
||||||
|
ports.append(move(controllerPort2));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MasterSystemInterface::manifest() -> string {
|
||||||
|
return cartridge.manifest();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MasterSystemInterface::title() -> string {
|
||||||
|
return cartridge.title();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MasterSystemInterface::videoSize() -> VideoSize {
|
||||||
|
return {256, 240};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MasterSystemInterface::videoSize(uint width, uint height, bool arc) -> VideoSize {
|
||||||
|
auto a = arc ? 8.0 / 7.0 : 1.0;
|
||||||
|
uint w = 256;
|
||||||
|
uint h = 240;
|
||||||
|
uint m = min(width / (w * a), height / h);
|
||||||
|
return {uint(w * a * m), uint(h * m)};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MasterSystemInterface::videoFrequency() -> double {
|
||||||
|
return 60.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MasterSystemInterface::videoColors() -> uint32 {
|
||||||
|
return 1 << 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MasterSystemInterface::videoColor(uint32 color) -> uint64 {
|
||||||
|
uint2 B = color >> 4;
|
||||||
|
uint2 G = color >> 2;
|
||||||
|
uint2 R = color >> 0;
|
||||||
|
|
||||||
|
uint64 r = image::normalize(R, 2, 16);
|
||||||
|
uint64 g = image::normalize(G, 2, 16);
|
||||||
|
uint64 b = image::normalize(B, 2, 16);
|
||||||
|
|
||||||
|
return r << 32 | g << 16 | b << 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MasterSystemInterface::audioFrequency() -> double {
|
||||||
|
return 44'100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MasterSystemInterface::loaded() -> bool {
|
||||||
|
return system.loaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MasterSystemInterface::load(uint id) -> bool {
|
||||||
|
if(id == ID::MasterSystem) return system.load(this, Model::MasterSystem);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MasterSystemInterface::save() -> void {
|
||||||
|
system.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MasterSystemInterface::unload() -> void {
|
||||||
|
system.unload();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MasterSystemInterface::connect(uint port, uint device) -> void {
|
||||||
|
peripherals.connect(port, device);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MasterSystemInterface::power() -> void {
|
||||||
|
system.power();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MasterSystemInterface::run() -> void {
|
||||||
|
system.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MasterSystemInterface::serialize() -> serializer {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MasterSystemInterface::unserialize(serializer& s) -> bool {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MasterSystemInterface::cap(const string& name) -> bool {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MasterSystemInterface::get(const string& name) -> any {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MasterSystemInterface::set(const string& name, const any& value) -> bool {
|
||||||
|
return false;
|
||||||
|
}
|
|
@ -10,9 +10,11 @@
|
||||||
#include <processor/z80/z80.hpp>
|
#include <processor/z80/z80.hpp>
|
||||||
|
|
||||||
namespace MasterSystem {
|
namespace MasterSystem {
|
||||||
|
#define platform Emulator::platform
|
||||||
using File = Emulator::File;
|
using File = Emulator::File;
|
||||||
using Scheduler = Emulator::Scheduler;
|
using Scheduler = Emulator::Scheduler;
|
||||||
extern Scheduler scheduler;
|
extern Scheduler scheduler;
|
||||||
|
struct Interface;
|
||||||
|
|
||||||
enum class Model : uint {
|
enum class Model : uint {
|
||||||
MasterSystem,
|
MasterSystem,
|
||||||
|
|
|
@ -19,9 +19,6 @@ auto PSG::step(uint clocks) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PSG::power() -> void {
|
auto PSG::power() -> void {
|
||||||
}
|
|
||||||
|
|
||||||
auto PSG::reset() -> void {
|
|
||||||
create(PSG::Enter, system.colorburst());
|
create(PSG::Enter, system.colorburst());
|
||||||
stream = Emulator::audio.createStream(2, system.colorburst());
|
stream = Emulator::audio.createStream(2, system.colorburst());
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ struct PSG : Thread {
|
||||||
auto step(uint clocks) -> void;
|
auto step(uint clocks) -> void;
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern PSG psg;
|
extern PSG psg;
|
||||||
|
|
|
@ -1,26 +1,40 @@
|
||||||
Peripherals peripherals;
|
Peripherals peripherals;
|
||||||
|
|
||||||
auto Peripherals::unload() -> void {
|
auto Peripherals::unload() -> void {
|
||||||
|
delete hardware;
|
||||||
delete controllerPort1;
|
delete controllerPort1;
|
||||||
delete controllerPort2;
|
delete controllerPort2;
|
||||||
|
hardware = nullptr;
|
||||||
controllerPort1 = nullptr;
|
controllerPort1 = nullptr;
|
||||||
controllerPort2 = nullptr;
|
controllerPort2 = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Peripherals::reset() -> void {
|
auto Peripherals::reset() -> void {
|
||||||
|
connect(ID::Port::Hardware, settings.hardware);
|
||||||
connect(ID::Port::Controller1, settings.controllerPort1);
|
connect(ID::Port::Controller1, settings.controllerPort1);
|
||||||
connect(ID::Port::Controller2, settings.controllerPort2);
|
connect(ID::Port::Controller2, settings.controllerPort2);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Peripherals::connect(uint port, uint device) -> void {
|
auto Peripherals::connect(uint port, uint device) -> void {
|
||||||
|
cpu.peripherals.reset();
|
||||||
|
|
||||||
|
if(system.model() == Model::MasterSystem) {
|
||||||
|
if(port == ID::Port::Hardware) {
|
||||||
|
settings.hardware = device;
|
||||||
|
if(!system.loaded()) return;
|
||||||
|
|
||||||
|
delete hardware;
|
||||||
|
hardware = new MasterSystemControls(ID::Port::Hardware);
|
||||||
|
}
|
||||||
|
|
||||||
if(port == ID::Port::Controller1) {
|
if(port == ID::Port::Controller1) {
|
||||||
settings.controllerPort1 = device;
|
settings.controllerPort1 = device;
|
||||||
if(!system.loaded()) return;
|
if(!system.loaded()) return;
|
||||||
|
|
||||||
delete controllerPort1;
|
delete controllerPort1;
|
||||||
switch(device) { default:
|
switch(device) { default:
|
||||||
case ID::Device::None: controllerPort1 = new Controller(0); break;
|
case ID::Device::None: controllerPort1 = new Controller(ID::Port::Controller1); break;
|
||||||
case ID::Device::Gamepad: controllerPort1 = new Gamepad(0); break;
|
case ID::Device::Gamepad: controllerPort1 = new Gamepad(ID::Port::Controller1); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,12 +44,25 @@ auto Peripherals::connect(uint port, uint device) -> void {
|
||||||
|
|
||||||
delete controllerPort2;
|
delete controllerPort2;
|
||||||
switch(device) { default:
|
switch(device) { default:
|
||||||
case ID::Device::None: controllerPort2 = new Controller(1); break;
|
case ID::Device::None: controllerPort2 = new Controller(ID::Port::Controller2); break;
|
||||||
case ID::Device::Gamepad: controllerPort2 = new Gamepad(1); break;
|
case ID::Device::Gamepad: controllerPort2 = new Gamepad(ID::Port::Controller2); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu.peripherals.reset();
|
cpu.peripherals.append(hardware);
|
||||||
cpu.peripherals.append(controllerPort1);
|
cpu.peripherals.append(controllerPort1);
|
||||||
cpu.peripherals.append(controllerPort2);
|
cpu.peripherals.append(controllerPort2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(system.model() == Model::GameGear) {
|
||||||
|
if(port == ID::Port::Hardware) {
|
||||||
|
settings.hardware = device;
|
||||||
|
if(!system.loaded()) return;
|
||||||
|
|
||||||
|
delete hardware;
|
||||||
|
hardware = new GameGearControls(ID::Port::Hardware);
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu.peripherals.append(hardware);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,17 +10,18 @@ auto System::run() -> void {
|
||||||
if(scheduler.enter() == Scheduler::Event::Frame) vdp.refresh();
|
if(scheduler.enter() == Scheduler::Event::Frame) vdp.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::load(Model model) -> bool {
|
auto System::load(Emulator::Interface* interface, Model model) -> bool {
|
||||||
information = {};
|
information = {};
|
||||||
information.model = model;
|
information.model = model;
|
||||||
|
|
||||||
if(auto fp = interface->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
if(auto fp = platform->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
||||||
information.manifest = fp->reads();
|
information.manifest = fp->reads();
|
||||||
} else return false;
|
} else return false;
|
||||||
|
|
||||||
auto document = BML::unserialize(information.manifest);
|
auto document = BML::unserialize(information.manifest);
|
||||||
if(!cartridge.load()) return false;
|
if(!cartridge.load()) return false;
|
||||||
|
|
||||||
|
this->interface = interface;
|
||||||
information.colorburst = Emulator::Constants::Colorburst::NTSC;
|
information.colorburst = Emulator::Constants::Colorburst::NTSC;
|
||||||
return information.loaded = true;
|
return information.loaded = true;
|
||||||
}
|
}
|
||||||
|
@ -35,14 +36,6 @@ auto System::unload() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::power() -> void {
|
auto System::power() -> void {
|
||||||
cartridge.power();
|
|
||||||
cpu.power();
|
|
||||||
vdp.power();
|
|
||||||
psg.power();
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto System::reset() -> void {
|
|
||||||
Emulator::video.reset();
|
Emulator::video.reset();
|
||||||
Emulator::video.setInterface(interface);
|
Emulator::video.setInterface(interface);
|
||||||
Emulator::video.setPalette();
|
Emulator::video.setPalette();
|
||||||
|
@ -51,10 +44,10 @@ auto System::reset() -> void {
|
||||||
Emulator::audio.setInterface(interface);
|
Emulator::audio.setInterface(interface);
|
||||||
|
|
||||||
scheduler.reset();
|
scheduler.reset();
|
||||||
cartridge.reset();
|
cartridge.power();
|
||||||
cpu.reset();
|
cpu.power();
|
||||||
vdp.reset();
|
vdp.power();
|
||||||
psg.reset();
|
psg.power();
|
||||||
scheduler.primary(cpu);
|
scheduler.primary(cpu);
|
||||||
|
|
||||||
peripherals.reset();
|
peripherals.reset();
|
||||||
|
|
|
@ -5,14 +5,15 @@ struct System {
|
||||||
|
|
||||||
auto run() -> void;
|
auto run() -> void;
|
||||||
|
|
||||||
auto load(Model model) -> bool;
|
auto load(Emulator::Interface* interface, Model model) -> bool;
|
||||||
auto save() -> void;
|
auto save() -> void;
|
||||||
auto unload() -> void;
|
auto unload() -> void;
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Emulator::Interface* interface = nullptr;
|
||||||
|
|
||||||
struct Information {
|
struct Information {
|
||||||
bool loaded = false;
|
bool loaded = false;
|
||||||
Model model = Model::MasterSystem;
|
Model model = Model::MasterSystem;
|
||||||
|
@ -26,6 +27,7 @@ struct Peripherals {
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
auto connect(uint port, uint device) -> void;
|
auto connect(uint port, uint device) -> void;
|
||||||
|
|
||||||
|
Controller* hardware = nullptr;
|
||||||
Controller* controllerPort1 = nullptr;
|
Controller* controllerPort1 = nullptr;
|
||||||
Controller* controllerPort2 = nullptr;
|
Controller* controllerPort2 = nullptr;
|
||||||
};
|
};
|
||||||
|
|
|
@ -51,9 +51,6 @@ auto VDP::Background::run() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto VDP::Background::power() -> void {
|
auto VDP::Background::power() -> void {
|
||||||
}
|
|
||||||
|
|
||||||
auto VDP::Background::reset() -> void {
|
|
||||||
memory::fill(&state, sizeof(State));
|
memory::fill(&state, sizeof(State));
|
||||||
memory::fill(&output, sizeof(Output));
|
memory::fill(&output, sizeof(Output));
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,10 @@ auto VDP::data(uint8 data) -> void {
|
||||||
if(io.code <= 2) {
|
if(io.code <= 2) {
|
||||||
vram[io.address++] = data;
|
vram[io.address++] = data;
|
||||||
} else {
|
} else {
|
||||||
cram[io.address++ & 0x1f] = data;
|
uint mask = 0;
|
||||||
|
if(system.model() == Model::MasterSystem) mask = 0x1f;
|
||||||
|
if(system.model() == Model::GameGear) mask = 0x3f;
|
||||||
|
cram[io.address++ & mask] = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,9 +63,6 @@ auto VDP::Sprite::run() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto VDP::Sprite::power() -> void {
|
auto VDP::Sprite::power() -> void {
|
||||||
}
|
|
||||||
|
|
||||||
auto VDP::Sprite::reset() -> void {
|
|
||||||
memory::fill(&state, sizeof(State));
|
memory::fill(&state, sizeof(State));
|
||||||
memory::fill(&output, sizeof(Output));
|
memory::fill(&output, sizeof(Output));
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,19 +29,20 @@ auto VDP::main() -> void {
|
||||||
sprite.scanline();
|
sprite.scanline();
|
||||||
|
|
||||||
//684 clocks/scanline
|
//684 clocks/scanline
|
||||||
|
uint y = io.vcounter;
|
||||||
for(uint x : range(256)) {
|
for(uint x : range(256)) {
|
||||||
background.run();
|
background.run();
|
||||||
sprite.run();
|
sprite.run();
|
||||||
step(2);
|
step(2);
|
||||||
|
|
||||||
uint6 color = cram[io.backdropColor];
|
uint12 color = palette(io.backdropColor);
|
||||||
if(background.output.color && (background.output.priority || !sprite.output.color)) {
|
if(background.output.color && (background.output.priority || !sprite.output.color)) {
|
||||||
color = cram[background.output.palette << 4 | background.output.color];
|
color = palette(background.output.palette << 4 | background.output.color);
|
||||||
} else if(sprite.output.color) {
|
} else if(sprite.output.color) {
|
||||||
color = cram[16 | sprite.output.color];
|
color = palette(16 | sprite.output.color);
|
||||||
}
|
}
|
||||||
if(x <= 7 && io.leftClip) color = cram[io.backdropColor];
|
if(x <= 7 && io.leftClip) color = palette(io.backdropColor);
|
||||||
if(!io.displayEnable || io.vcounter >= vlines()) color = 0;
|
if(!io.displayEnable || y >= vlines()) color = 0;
|
||||||
buffer[io.vcounter * 256 + x] = color;
|
buffer[io.vcounter * 256 + x] = color;
|
||||||
}
|
}
|
||||||
step(172);
|
step(172);
|
||||||
|
@ -65,9 +66,15 @@ auto VDP::step(uint clocks) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto VDP::refresh() -> void {
|
auto VDP::refresh() -> void {
|
||||||
|
if(system.model() == Model::MasterSystem) {
|
||||||
Emulator::video.refresh(buffer, 256 * sizeof(uint32), 256, 240);
|
Emulator::video.refresh(buffer, 256 * sizeof(uint32), 256, 240);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(system.model() == Model::GameGear) {
|
||||||
|
Emulator::video.refresh(buffer + 24 * 256 + 48, 256 * sizeof(uint32), 160, 144);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto VDP::vlines() -> uint {
|
auto VDP::vlines() -> uint {
|
||||||
if(io.lines240) return 240;
|
if(io.lines240) return 240;
|
||||||
if(io.lines224) return 224;
|
if(io.lines224) return 224;
|
||||||
|
@ -79,17 +86,24 @@ auto VDP::vblank() -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto VDP::power() -> void {
|
auto VDP::power() -> void {
|
||||||
background.power();
|
|
||||||
sprite.power();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto VDP::reset() -> void {
|
|
||||||
create(VDP::Enter, system.colorburst() * 15.0 / 5.0);
|
create(VDP::Enter, system.colorburst() * 15.0 / 5.0);
|
||||||
|
|
||||||
memory::fill(&io, sizeof(IO));
|
memory::fill(&io, sizeof(IO));
|
||||||
|
|
||||||
background.reset();
|
background.power();
|
||||||
sprite.reset();
|
sprite.power();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto VDP::palette(uint5 index) -> uint12 {
|
||||||
|
if(system.model() == Model::MasterSystem) {
|
||||||
|
return cram[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(system.model() == Model::GameGear) {
|
||||||
|
return cram[index * 2 + 0] << 0 | cram[index * 2 + 1] << 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ struct VDP : Thread {
|
||||||
auto vblank() -> bool;
|
auto vblank() -> bool;
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
|
||||||
|
|
||||||
//io.cpp
|
//io.cpp
|
||||||
auto vcounter() -> uint8;
|
auto vcounter() -> uint8;
|
||||||
|
@ -28,7 +27,6 @@ struct VDP : Thread {
|
||||||
auto run() -> void;
|
auto run() -> void;
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
uint x;
|
uint x;
|
||||||
|
@ -48,7 +46,6 @@ struct VDP : Thread {
|
||||||
auto run() -> void;
|
auto run() -> void;
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
|
||||||
|
|
||||||
struct Object {
|
struct Object {
|
||||||
uint8 x;
|
uint8 x;
|
||||||
|
@ -69,9 +66,11 @@ struct VDP : Thread {
|
||||||
} sprite;
|
} sprite;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
auto palette(uint5 index) -> uint12;
|
||||||
|
|
||||||
uint32 buffer[256 * 262];
|
uint32 buffer[256 * 262];
|
||||||
uint8 vram[0x4000];
|
uint8 vram[0x4000];
|
||||||
uint8 cram[0x20];
|
uint8 cram[0x40]; //MS = 0x20, GG = 0x40
|
||||||
|
|
||||||
struct IO {
|
struct IO {
|
||||||
uint vcounter; //vertical counter
|
uint vcounter; //vertical counter
|
||||||
|
|
|
@ -7,11 +7,11 @@ Cartridge cartridge;
|
||||||
auto Cartridge::load() -> bool {
|
auto Cartridge::load() -> bool {
|
||||||
information = {};
|
information = {};
|
||||||
|
|
||||||
if(auto pathID = interface->load(ID::PCEngine, "PC Engine", "pce")) {
|
if(auto pathID = platform->load(ID::PCEngine, "PC Engine", "pce")) {
|
||||||
information.pathID = pathID();
|
information.pathID = pathID();
|
||||||
} else return false;
|
} else return false;
|
||||||
|
|
||||||
if(auto fp = interface->open(pathID(), "manifest.bml", File::Read, File::Required)) {
|
if(auto fp = platform->open(pathID(), "manifest.bml", File::Read, File::Required)) {
|
||||||
information.manifest = fp->reads();
|
information.manifest = fp->reads();
|
||||||
} else return false;
|
} else return false;
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ auto Cartridge::load() -> bool {
|
||||||
if(rom.size) {
|
if(rom.size) {
|
||||||
rom.data = new uint8[rom.size]();
|
rom.data = new uint8[rom.size]();
|
||||||
if(auto name = node["name"].text()) {
|
if(auto name = node["name"].text()) {
|
||||||
if(auto fp = interface->open(pathID(), name, File::Read, File::Required)) {
|
if(auto fp = platform->open(pathID(), name, File::Read, File::Required)) {
|
||||||
fp->read(rom.data, rom.size);
|
fp->read(rom.data, rom.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ auto Cartridge::load() -> bool {
|
||||||
if(ram.size) {
|
if(ram.size) {
|
||||||
ram.data = new uint8[ram.size]();
|
ram.data = new uint8[ram.size]();
|
||||||
if(auto name = node["name"].text()) {
|
if(auto name = node["name"].text()) {
|
||||||
if(auto fp = interface->open(pathID(), name, File::Read)) {
|
if(auto fp = platform->open(pathID(), name, File::Read)) {
|
||||||
fp->read(ram.data, ram.size);
|
fp->read(ram.data, ram.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ auto Cartridge::save() -> void {
|
||||||
auto document = BML::unserialize(information.manifest);
|
auto document = BML::unserialize(information.manifest);
|
||||||
|
|
||||||
if(auto name = document["board/ram/name"].text()) {
|
if(auto name = document["board/ram/name"].text()) {
|
||||||
if(auto fp = interface->open(pathID(), name, File::Write)) {
|
if(auto fp = platform->open(pathID(), name, File::Write)) {
|
||||||
fp->write(ram.data, ram.size);
|
fp->write(ram.data, ram.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,13 @@ auto CPU::Enter() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::main() -> void {
|
auto CPU::main() -> void {
|
||||||
|
#if 1
|
||||||
|
static uint counter = 0;
|
||||||
|
if(++counter < 10) {
|
||||||
|
print(disassemble(r.pc), "\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
instruction();
|
instruction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,4 +31,20 @@ auto CPU::power() -> void {
|
||||||
create(CPU::Enter, system.colorburst() * 6.0);
|
create(CPU::Enter, system.colorburst() * 6.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto CPU::read(uint16 addr) -> uint8 {
|
||||||
|
step(3);
|
||||||
|
return 0xea;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CPU::write(uint16 addr, uint8 data) -> void {
|
||||||
|
step(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CPU::lastCycle() -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CPU::disassembleRead(uint16 pc) -> uint8 {
|
||||||
|
return 0xea;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,16 @@
|
||||||
struct CPU : Processor::HuC6280, Thread {
|
struct CPU : Processor::HuC6280, Thread {
|
||||||
static auto Enter() -> void;
|
static auto Enter() -> void;
|
||||||
auto main() -> void;
|
auto main() -> void;
|
||||||
auto step(uint clocks) -> void;
|
auto step(uint clocks) -> void override;
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
|
||||||
|
auto read(uint16 addr) -> uint8 override;
|
||||||
|
auto write(uint16 addr, uint8 data) -> void override;
|
||||||
|
auto lastCycle() -> void override;
|
||||||
|
|
||||||
|
auto disassembleRead(uint16 addr) -> uint8 override;
|
||||||
|
|
||||||
vector<Thread*> peripherals;
|
vector<Thread*> peripherals;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,9 @@
|
||||||
|
|
||||||
namespace PCEngine {
|
namespace PCEngine {
|
||||||
|
|
||||||
Interface* interface = nullptr;
|
|
||||||
Settings settings;
|
Settings settings;
|
||||||
|
|
||||||
Interface::Interface() {
|
Interface::Interface() {
|
||||||
interface = this;
|
|
||||||
|
|
||||||
information.manufacturer = "NEC";
|
information.manufacturer = "NEC";
|
||||||
information.name = "PC Engine";
|
information.name = "PC Engine";
|
||||||
information.overscan = true;
|
information.overscan = true;
|
||||||
|
@ -80,7 +77,7 @@ auto Interface::loaded() -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::load(uint id) -> bool {
|
auto Interface::load(uint id) -> bool {
|
||||||
if(id == ID::PCEngine) return system.load();
|
if(id == ID::PCEngine) return system.load(this);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,6 @@ struct Settings {
|
||||||
uint controllerPort = 0;
|
uint controllerPort = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Interface* interface;
|
|
||||||
extern Settings settings;
|
extern Settings settings;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <processor/huc6280/huc6280.hpp>
|
#include <processor/huc6280/huc6280.hpp>
|
||||||
|
|
||||||
namespace PCEngine {
|
namespace PCEngine {
|
||||||
|
#define platform Emulator::platform
|
||||||
using File = Emulator::File;
|
using File = Emulator::File;
|
||||||
using Scheduler = Emulator::Scheduler;
|
using Scheduler = Emulator::Scheduler;
|
||||||
extern Scheduler scheduler;
|
extern Scheduler scheduler;
|
||||||
|
|
|
@ -10,16 +10,17 @@ auto System::run() -> void {
|
||||||
if(scheduler.enter() == Scheduler::Event::Frame) vdc.refresh();
|
if(scheduler.enter() == Scheduler::Event::Frame) vdc.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::load() -> bool {
|
auto System::load(Emulator::Interface* interface) -> bool {
|
||||||
information = {};
|
information = {};
|
||||||
|
|
||||||
if(auto fp = interface->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
if(auto fp = platform->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
||||||
information.manifest = fp->reads();
|
information.manifest = fp->reads();
|
||||||
} else return false;
|
} else return false;
|
||||||
|
|
||||||
auto document = BML::unserialize(information.manifest);
|
auto document = BML::unserialize(information.manifest);
|
||||||
if(!cartridge.load()) return false;
|
if(!cartridge.load()) return false;
|
||||||
|
|
||||||
|
this->interface = interface;
|
||||||
information.colorburst = Emulator::Constants::Colorburst::NTSC;
|
information.colorburst = Emulator::Constants::Colorburst::NTSC;
|
||||||
return information.loaded = true;
|
return information.loaded = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,15 @@ struct System {
|
||||||
|
|
||||||
auto run() -> void;
|
auto run() -> void;
|
||||||
|
|
||||||
auto load() -> bool;
|
auto load(Emulator::Interface*) -> bool;
|
||||||
auto save() -> void;
|
auto save() -> void;
|
||||||
auto unload() -> void;
|
auto unload() -> void;
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Emulator::Interface* interface = nullptr;
|
||||||
|
|
||||||
struct Information {
|
struct Information {
|
||||||
bool loaded = false;
|
bool loaded = false;
|
||||||
string manifest;
|
string manifest;
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
auto HuC6280::disassemble(uint16 pc) -> string {
|
||||||
|
string s{hex(r.pc, 4L), " "};
|
||||||
|
uint8 opcode = disassembleRead(pc++);
|
||||||
|
|
||||||
|
#define op(id, name, ...) case id: o = {name, string_vector{__VA_ARGS__}.merge(",")};
|
||||||
|
string o;
|
||||||
|
switch(opcode) {
|
||||||
|
op(0xea, "nop")
|
||||||
|
}
|
||||||
|
if(!o) o = {"??? (", hex(opcode, 2L), ")"};
|
||||||
|
s.append(pad(o, -16L, ' '));
|
||||||
|
#undef op
|
||||||
|
|
||||||
|
s.append(" A:", hex(r.a, 2L));
|
||||||
|
s.append(" X:", hex(r.x, 2L));
|
||||||
|
s.append(" Y:", hex(r.y, 2L));
|
||||||
|
s.append(" S:", hex(r.s, 2L));
|
||||||
|
s.append(" ");
|
||||||
|
s.append(r.p.n ? "N" : "n");
|
||||||
|
s.append(r.p.v ? "V" : "v");
|
||||||
|
s.append(r.p.t ? "T" : "t");
|
||||||
|
s.append(r.p.b ? "B" : "b");
|
||||||
|
s.append(r.p.d ? "D" : "d");
|
||||||
|
s.append(r.p.i ? "I" : "i");
|
||||||
|
s.append(r.p.z ? "Z" : "z");
|
||||||
|
s.append(r.p.c ? "C" : "c");
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
|
@ -3,11 +3,21 @@
|
||||||
|
|
||||||
namespace Processor {
|
namespace Processor {
|
||||||
|
|
||||||
|
#define L lastCycle();
|
||||||
|
#include "memory.cpp"
|
||||||
|
#include "instruction.cpp"
|
||||||
|
#include "instructions.cpp"
|
||||||
|
#include "disassembler.cpp"
|
||||||
|
#undef L
|
||||||
|
|
||||||
auto HuC6280::power() -> void {
|
auto HuC6280::power() -> void {
|
||||||
}
|
r.a = 0x00;
|
||||||
|
r.x = 0x00;
|
||||||
auto HuC6280::instruction() -> void {
|
r.y = 0x00;
|
||||||
step(1);
|
r.s = 0x00;
|
||||||
|
r.pc = 0x0000;
|
||||||
|
r.p = 0x00;
|
||||||
|
r.mdr = 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,56 @@ namespace Processor {
|
||||||
|
|
||||||
struct HuC6280 {
|
struct HuC6280 {
|
||||||
virtual auto step(uint clocks) -> void = 0;
|
virtual auto step(uint clocks) -> void = 0;
|
||||||
|
virtual auto read(uint16 addr) -> uint8 = 0;
|
||||||
|
virtual auto write(uint16 addr, uint8 data) -> void = 0;
|
||||||
|
virtual auto lastCycle() -> void = 0;
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
|
||||||
|
//memory.cpp
|
||||||
|
auto io() -> uint8;
|
||||||
|
auto opcode() -> uint8;
|
||||||
|
auto operand() -> uint8;
|
||||||
|
|
||||||
|
//instruction.cpp
|
||||||
auto instruction() -> void;
|
auto instruction() -> void;
|
||||||
|
|
||||||
|
//instructions.cpp
|
||||||
|
auto instructionNOP() -> void;
|
||||||
|
|
||||||
|
//disassembler.cpp
|
||||||
|
virtual auto disassembleRead(uint16 pc) -> uint8 = 0;
|
||||||
|
auto disassemble(uint16 pc) -> string;
|
||||||
|
|
||||||
|
struct Flags {
|
||||||
|
union {
|
||||||
|
uint8_t data = 0;
|
||||||
|
BooleanBitField<uint8_t, 0> c; //carry
|
||||||
|
BooleanBitField<uint8_t, 1> z; //zero
|
||||||
|
BooleanBitField<uint8_t, 2> i; //interrupt
|
||||||
|
BooleanBitField<uint8_t, 3> d; //decimal
|
||||||
|
BooleanBitField<uint8_t, 4> b; //break
|
||||||
|
BooleanBitField<uint8_t, 5> t; //...
|
||||||
|
BooleanBitField<uint8_t, 6> v; //overflow
|
||||||
|
BooleanBitField<uint8_t, 7> n; //negative
|
||||||
|
};
|
||||||
|
|
||||||
|
inline operator uint() const { return data; }
|
||||||
|
inline auto& operator =(uint value) { return data = value, *this; }
|
||||||
|
inline auto& operator&=(uint value) { return data &= value, *this; }
|
||||||
|
inline auto& operator|=(uint value) { return data |= value, *this; }
|
||||||
|
inline auto& operator^=(uint value) { return data ^= value, *this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Registers {
|
||||||
|
uint8 a;
|
||||||
|
uint8 x;
|
||||||
|
uint8 y;
|
||||||
|
uint8 s;
|
||||||
|
uint16 pc;
|
||||||
|
Flags p;
|
||||||
|
uint8 mdr;
|
||||||
|
} r;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
#define op(id, name, ...) case id: return instruction##name(__VA_ARGS__);
|
||||||
|
|
||||||
|
auto HuC6280::instruction() -> void {
|
||||||
|
switch(opcode()) {
|
||||||
|
op(0xea, NOP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef op
|
|
@ -0,0 +1,3 @@
|
||||||
|
auto HuC6280::instructionNOP() -> void {
|
||||||
|
L io();
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
auto HuC6280::io() -> uint8 {
|
||||||
|
return read(r.pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::opcode() -> uint8 {
|
||||||
|
return read(r.pc++);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto HuC6280::operand() -> uint8 {
|
||||||
|
return read(r.pc++);
|
||||||
|
}
|
|
@ -26,14 +26,14 @@ auto Cartridge::title() const -> string {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::load() -> bool {
|
auto Cartridge::load() -> bool {
|
||||||
information = Information();
|
information = {};
|
||||||
has = Has();
|
has = {};
|
||||||
|
|
||||||
if(auto pathID = interface->load(ID::SuperFamicom, "Super Famicom", "sfc")) {
|
if(auto pathID = platform->load(ID::SuperFamicom, "Super Famicom", "sfc")) {
|
||||||
information.pathID = pathID();
|
information.pathID = pathID();
|
||||||
} else return false;
|
} else return false;
|
||||||
|
|
||||||
if(auto fp = interface->open(ID::SuperFamicom, "manifest.bml", File::Read, File::Required)) {
|
if(auto fp = platform->open(ID::SuperFamicom, "manifest.bml", File::Read, File::Required)) {
|
||||||
information.manifest.cartridge = fp->reads();
|
information.manifest.cartridge = fp->reads();
|
||||||
} else return false;
|
} else return false;
|
||||||
auto document = BML::unserialize(information.manifest.cartridge);
|
auto document = BML::unserialize(information.manifest.cartridge);
|
||||||
|
@ -99,7 +99,7 @@ auto Cartridge::loadGameBoy() -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::loadBSMemory() -> bool {
|
auto Cartridge::loadBSMemory() -> bool {
|
||||||
if(auto fp = interface->open(bsmemory.pathID, "manifest.bml", File::Read, File::Required)) {
|
if(auto fp = platform->open(bsmemory.pathID, "manifest.bml", File::Read, File::Required)) {
|
||||||
information.manifest.bsMemory = fp->reads();
|
information.manifest.bsMemory = fp->reads();
|
||||||
} else return false;
|
} else return false;
|
||||||
loadBSMemory(BML::unserialize(information.manifest.bsMemory));
|
loadBSMemory(BML::unserialize(information.manifest.bsMemory));
|
||||||
|
@ -107,7 +107,7 @@ auto Cartridge::loadBSMemory() -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::loadSufamiTurboA() -> bool {
|
auto Cartridge::loadSufamiTurboA() -> bool {
|
||||||
if(auto fp = interface->open(sufamiturboA.pathID, "manifest.bml", File::Read, File::Required)) {
|
if(auto fp = platform->open(sufamiturboA.pathID, "manifest.bml", File::Read, File::Required)) {
|
||||||
information.manifest.sufamiTurboA = fp->reads();
|
information.manifest.sufamiTurboA = fp->reads();
|
||||||
} else return false;
|
} else return false;
|
||||||
loadSufamiTurboA(BML::unserialize(information.manifest.sufamiTurboA));
|
loadSufamiTurboA(BML::unserialize(information.manifest.sufamiTurboA));
|
||||||
|
@ -115,7 +115,7 @@ auto Cartridge::loadSufamiTurboA() -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::loadSufamiTurboB() -> bool {
|
auto Cartridge::loadSufamiTurboB() -> bool {
|
||||||
if(auto fp = interface->open(sufamiturboB.pathID, "manifest.bml", File::Read, File::Required)) {
|
if(auto fp = platform->open(sufamiturboB.pathID, "manifest.bml", File::Read, File::Required)) {
|
||||||
information.manifest.sufamiTurboB = fp->reads();
|
information.manifest.sufamiTurboB = fp->reads();
|
||||||
} else return false;
|
} else return false;
|
||||||
loadSufamiTurboB(BML::unserialize(information.manifest.sufamiTurboB));
|
loadSufamiTurboB(BML::unserialize(information.manifest.sufamiTurboB));
|
||||||
|
|
|
@ -4,13 +4,13 @@ auto Cartridge::loadCartridge(Markup::Node node) -> void {
|
||||||
information.region = board["region"].text() == "pal" ? Region::PAL : Region::NTSC;
|
information.region = board["region"].text() == "pal" ? Region::PAL : Region::NTSC;
|
||||||
|
|
||||||
if(board["mcc"] || board["bsmemory"]) {
|
if(board["mcc"] || board["bsmemory"]) {
|
||||||
if(auto pathID = interface->load(ID::BSMemory, "BS Memory", "bs")) {
|
if(auto pathID = platform->load(ID::BSMemory, "BS Memory", "bs")) {
|
||||||
bsmemory.pathID = pathID();
|
bsmemory.pathID = pathID();
|
||||||
loadBSMemory();
|
loadBSMemory();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(board["sufamiturbo"]) {
|
if(board["sufamiturbo"]) {
|
||||||
if(auto pathID = interface->load(ID::SufamiTurboA, "Sufami Turbo", "st")) {
|
if(auto pathID = platform->load(ID::SufamiTurboA, "Sufami Turbo", "st")) {
|
||||||
sufamiturboA.pathID = pathID();
|
sufamiturboA.pathID = pathID();
|
||||||
loadSufamiTurboA();
|
loadSufamiTurboA();
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ auto Cartridge::loadSufamiTurboA(Markup::Node node) -> void {
|
||||||
loadMemory(sufamiturboA.ram, node["board/ram"], File::Optional, sufamiturboA.pathID);
|
loadMemory(sufamiturboA.ram, node["board/ram"], File::Optional, sufamiturboA.pathID);
|
||||||
|
|
||||||
if(node["board/linkable"]) {
|
if(node["board/linkable"]) {
|
||||||
if(auto pathID = interface->load(ID::SufamiTurboB, "Sufami Turbo", "st")) {
|
if(auto pathID = platform->load(ID::SufamiTurboB, "Sufami Turbo", "st")) {
|
||||||
sufamiturboB.pathID = pathID();
|
sufamiturboB.pathID = pathID();
|
||||||
loadSufamiTurboB();
|
loadSufamiTurboB();
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@ auto Cartridge::loadSufamiTurbo(Markup::Node node, bool slot) -> void {
|
||||||
|
|
||||||
auto Cartridge::loadNSS(Markup::Node node) -> void {
|
auto Cartridge::loadNSS(Markup::Node node) -> void {
|
||||||
has.NSSDIP = true;
|
has.NSSDIP = true;
|
||||||
nss.dip = interface->dipSettings(node);
|
nss.dip = platform->dipSettings(node);
|
||||||
|
|
||||||
for(auto leaf : node.find("map")) loadMap(leaf, {&NSS::read, &nss}, {&NSS::write, &nss});
|
for(auto leaf : node.find("map")) loadMap(leaf, {&NSS::read, &nss}, {&NSS::write, &nss});
|
||||||
}
|
}
|
||||||
|
@ -182,13 +182,13 @@ auto Cartridge::loadSuperFX(Markup::Node node) -> void {
|
||||||
auto Cartridge::loadARMDSP(Markup::Node node) -> void {
|
auto Cartridge::loadARMDSP(Markup::Node node) -> void {
|
||||||
has.ARMDSP = true;
|
has.ARMDSP = true;
|
||||||
|
|
||||||
if(auto fp = interface->open(ID::SuperFamicom, node["prom"]["name"].text(), File::Read, File::Required)) {
|
if(auto fp = platform->open(ID::SuperFamicom, node["prom"]["name"].text(), File::Read, File::Required)) {
|
||||||
for(auto n : range(128 * 1024)) armdsp.programROM[n] = fp->read();
|
for(auto n : range(128 * 1024)) armdsp.programROM[n] = fp->read();
|
||||||
}
|
}
|
||||||
if(auto fp = interface->open(ID::SuperFamicom, node["drom"]["name"].text(), File::Read, File::Required)) {
|
if(auto fp = platform->open(ID::SuperFamicom, node["drom"]["name"].text(), File::Read, File::Required)) {
|
||||||
for(auto n : range( 32 * 1024)) armdsp.dataROM[n] = fp->read();
|
for(auto n : range( 32 * 1024)) armdsp.dataROM[n] = fp->read();
|
||||||
}
|
}
|
||||||
if(auto fp = interface->open(ID::SuperFamicom, node["ram"]["name"].text(), File::Read)) {
|
if(auto fp = platform->open(ID::SuperFamicom, node["ram"]["name"].text(), File::Read)) {
|
||||||
for(auto n : range( 16 * 1024)) armdsp.programRAM[n] = fp->read();
|
for(auto n : range( 16 * 1024)) armdsp.programRAM[n] = fp->read();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,10 +208,10 @@ auto Cartridge::loadHitachiDSP(Markup::Node node, uint roms) -> void {
|
||||||
for(auto& word : hitachidsp.dataROM) word = 0x000000;
|
for(auto& word : hitachidsp.dataROM) word = 0x000000;
|
||||||
for(auto& word : hitachidsp.dataRAM) word = 0x00;
|
for(auto& word : hitachidsp.dataRAM) word = 0x00;
|
||||||
|
|
||||||
if(auto fp = interface->open(ID::SuperFamicom, node["drom"]["name"].text(), File::Read, File::Required)) {
|
if(auto fp = platform->open(ID::SuperFamicom, node["drom"]["name"].text(), File::Read, File::Required)) {
|
||||||
for(auto n : range(1 * 1024)) hitachidsp.dataROM[n] = fp->readl(3);
|
for(auto n : range(1 * 1024)) hitachidsp.dataROM[n] = fp->readl(3);
|
||||||
}
|
}
|
||||||
if(auto fp = interface->open(ID::SuperFamicom, node["dram"]["name"].text(), File::Read)) {
|
if(auto fp = platform->open(ID::SuperFamicom, node["dram"]["name"].text(), File::Read)) {
|
||||||
for(auto n : range(3 * 1024)) hitachidsp.dataRAM[n] = fp->readl(1);
|
for(auto n : range(3 * 1024)) hitachidsp.dataRAM[n] = fp->readl(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,13 +239,13 @@ auto Cartridge::loadNECDSP(Markup::Node node) -> void {
|
||||||
if(necdsp.revision == NECDSP::Revision::uPD7725 ) memory::assign(size, 2048, 1024, 256);
|
if(necdsp.revision == NECDSP::Revision::uPD7725 ) memory::assign(size, 2048, 1024, 256);
|
||||||
if(necdsp.revision == NECDSP::Revision::uPD96050) memory::assign(size, 16384, 2048, 2048);
|
if(necdsp.revision == NECDSP::Revision::uPD96050) memory::assign(size, 16384, 2048, 2048);
|
||||||
|
|
||||||
if(auto fp = interface->open(ID::SuperFamicom, node["prom"]["name"].text(), File::Read, File::Required)) {
|
if(auto fp = platform->open(ID::SuperFamicom, node["prom"]["name"].text(), File::Read, File::Required)) {
|
||||||
for(auto n : range(size[0])) necdsp.programROM[n] = fp->readl(3);
|
for(auto n : range(size[0])) necdsp.programROM[n] = fp->readl(3);
|
||||||
}
|
}
|
||||||
if(auto fp = interface->open(ID::SuperFamicom, node["drom"]["name"].text(), File::Read, File::Required)) {
|
if(auto fp = platform->open(ID::SuperFamicom, node["drom"]["name"].text(), File::Read, File::Required)) {
|
||||||
for(auto n : range(size[1])) necdsp.dataROM[n] = fp->readl(2);
|
for(auto n : range(size[1])) necdsp.dataROM[n] = fp->readl(2);
|
||||||
}
|
}
|
||||||
if(auto fp = interface->open(ID::SuperFamicom, node["dram"]["name"].text(), File::Read)) {
|
if(auto fp = platform->open(ID::SuperFamicom, node["dram"]["name"].text(), File::Read)) {
|
||||||
for(auto n : range(size[2])) necdsp.dataRAM[n] = fp->readl(2);
|
for(auto n : range(size[2])) necdsp.dataRAM[n] = fp->readl(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,7 +256,7 @@ auto Cartridge::loadNECDSP(Markup::Node node) -> void {
|
||||||
auto Cartridge::loadEpsonRTC(Markup::Node node) -> void {
|
auto Cartridge::loadEpsonRTC(Markup::Node node) -> void {
|
||||||
has.EpsonRTC = true;
|
has.EpsonRTC = true;
|
||||||
|
|
||||||
if(auto fp = interface->open(ID::SuperFamicom, node["ram"]["name"].text(), File::Read)) {
|
if(auto fp = platform->open(ID::SuperFamicom, node["ram"]["name"].text(), File::Read)) {
|
||||||
uint8 data[16] = {0};
|
uint8 data[16] = {0};
|
||||||
for(auto& byte : data) fp->read();
|
for(auto& byte : data) fp->read();
|
||||||
epsonrtc.load(data);
|
epsonrtc.load(data);
|
||||||
|
@ -268,7 +268,7 @@ auto Cartridge::loadEpsonRTC(Markup::Node node) -> void {
|
||||||
auto Cartridge::loadSharpRTC(Markup::Node node) -> void {
|
auto Cartridge::loadSharpRTC(Markup::Node node) -> void {
|
||||||
has.SharpRTC = true;
|
has.SharpRTC = true;
|
||||||
|
|
||||||
if(auto fp = interface->open(ID::SuperFamicom, node["ram"]["name"].text(), File::Read)) {
|
if(auto fp = platform->open(ID::SuperFamicom, node["ram"]["name"].text(), File::Read)) {
|
||||||
uint8 data[16] = {0};
|
uint8 data[16] = {0};
|
||||||
for(auto& byte : data) fp->read();
|
for(auto& byte : data) fp->read();
|
||||||
sharprtc.load(data);
|
sharprtc.load(data);
|
||||||
|
@ -322,7 +322,7 @@ auto Cartridge::loadMemory(MappedRAM& ram, Markup::Node node, bool required, may
|
||||||
auto name = node["name"].text();
|
auto name = node["name"].text();
|
||||||
auto size = node["size"].natural();
|
auto size = node["size"].natural();
|
||||||
ram.allocate(size);
|
ram.allocate(size);
|
||||||
if(auto fp = interface->open(id(), name, File::Read, required)) {
|
if(auto fp = platform->open(id(), name, File::Read, required)) {
|
||||||
fp->read(ram.data(), ram.size());
|
fp->read(ram.data(), ram.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ auto Cartridge::saveSuperFX(Markup::Node node) -> void {
|
||||||
auto Cartridge::saveARMDSP(Markup::Node node) -> void {
|
auto Cartridge::saveARMDSP(Markup::Node node) -> void {
|
||||||
if(!node["ram/volatile"]) {
|
if(!node["ram/volatile"]) {
|
||||||
if(auto name = node["ram/name"].text()) {
|
if(auto name = node["ram/name"].text()) {
|
||||||
if(auto fp = interface->open(ID::SuperFamicom, name, File::Write)) {
|
if(auto fp = platform->open(ID::SuperFamicom, name, File::Write)) {
|
||||||
for(auto n : range(16 * 1024)) fp->write(armdsp.programRAM[n]);
|
for(auto n : range(16 * 1024)) fp->write(armdsp.programRAM[n]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ auto Cartridge::saveHitachiDSP(Markup::Node node) -> void {
|
||||||
|
|
||||||
if(!node["dram/volatile"]) {
|
if(!node["dram/volatile"]) {
|
||||||
if(auto name = node["dram/name"].text()) {
|
if(auto name = node["dram/name"].text()) {
|
||||||
if(auto fp = interface->open(ID::SuperFamicom, name, File::Write)) {
|
if(auto fp = platform->open(ID::SuperFamicom, name, File::Write)) {
|
||||||
for(auto n : range(3 * 1024)) fp->write(hitachidsp.dataRAM[n]);
|
for(auto n : range(3 * 1024)) fp->write(hitachidsp.dataRAM[n]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ auto Cartridge::saveNECDSP(Markup::Node node) -> void {
|
||||||
if(!node["dram/volatile"]) {
|
if(!node["dram/volatile"]) {
|
||||||
uint size = necdsp.revision == NECDSP::Revision::uPD7725 ? 256 : 2048;
|
uint size = necdsp.revision == NECDSP::Revision::uPD7725 ? 256 : 2048;
|
||||||
if(auto name = node["dram/name"].text()) {
|
if(auto name = node["dram/name"].text()) {
|
||||||
if(auto fp = interface->open(ID::SuperFamicom, name, File::Write)) {
|
if(auto fp = platform->open(ID::SuperFamicom, name, File::Write)) {
|
||||||
for(auto n : range(size)) fp->writel(necdsp.dataRAM[n], 2);
|
for(auto n : range(size)) fp->writel(necdsp.dataRAM[n], 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ auto Cartridge::saveNECDSP(Markup::Node node) -> void {
|
||||||
auto Cartridge::saveEpsonRTC(Markup::Node node) -> void {
|
auto Cartridge::saveEpsonRTC(Markup::Node node) -> void {
|
||||||
if(!node["ram/volatile"]) {
|
if(!node["ram/volatile"]) {
|
||||||
if(auto name = node["ram/name"].text()) {
|
if(auto name = node["ram/name"].text()) {
|
||||||
if(auto fp = interface->open(ID::SuperFamicom, name, File::Write)) {
|
if(auto fp = platform->open(ID::SuperFamicom, name, File::Write)) {
|
||||||
uint8 data[16] = {0};
|
uint8 data[16] = {0};
|
||||||
epsonrtc.save(data);
|
epsonrtc.save(data);
|
||||||
fp->write(data, 16);
|
fp->write(data, 16);
|
||||||
|
@ -101,7 +101,7 @@ auto Cartridge::saveEpsonRTC(Markup::Node node) -> void {
|
||||||
auto Cartridge::saveSharpRTC(Markup::Node node) -> void {
|
auto Cartridge::saveSharpRTC(Markup::Node node) -> void {
|
||||||
if(!node["ram/volatile"]) {
|
if(!node["ram/volatile"]) {
|
||||||
if(auto name = node["ram/name"].text()) {
|
if(auto name = node["ram/name"].text()) {
|
||||||
if(auto fp = interface->open(ID::SuperFamicom, name, File::Write)) {
|
if(auto fp = platform->open(ID::SuperFamicom, name, File::Write)) {
|
||||||
uint8 data[16] = {0};
|
uint8 data[16] = {0};
|
||||||
sharprtc.save(data);
|
sharprtc.save(data);
|
||||||
fp->write(data, 16);
|
fp->write(data, 16);
|
||||||
|
@ -129,7 +129,7 @@ auto Cartridge::saveMemory(MappedRAM& memory, Markup::Node node, maybe<uint> id)
|
||||||
if(!node || node["volatile"]) return;
|
if(!node || node["volatile"]) return;
|
||||||
auto name = node["name"].text();
|
auto name = node["name"].text();
|
||||||
auto size = node["size"].natural();
|
auto size = node["size"].natural();
|
||||||
if(auto fp = interface->open(id(), name, File::Write)) {
|
if(auto fp = platform->open(id(), name, File::Write)) {
|
||||||
fp->write(memory.data(), memory.size());
|
fp->write(memory.data(), memory.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ Gamepad::Gamepad(bool port) : Controller(port) {
|
||||||
|
|
||||||
auto Gamepad::data() -> uint2 {
|
auto Gamepad::data() -> uint2 {
|
||||||
if(counter >= 16) return 1;
|
if(counter >= 16) return 1;
|
||||||
if(latched == 1) return interface->inputPoll(port, ID::Device::Gamepad, B);
|
if(latched == 1) return platform->inputPoll(port, ID::Device::Gamepad, B);
|
||||||
|
|
||||||
//note: D-pad physically prevents up+down and left+right from being pressed at the same time
|
//note: D-pad physically prevents up+down and left+right from being pressed at the same time
|
||||||
switch(counter++) {
|
switch(counter++) {
|
||||||
|
@ -32,17 +32,17 @@ auto Gamepad::latch(bool data) -> void {
|
||||||
counter = 0;
|
counter = 0;
|
||||||
|
|
||||||
if(latched == 0) {
|
if(latched == 0) {
|
||||||
b = interface->inputPoll(port, ID::Device::Gamepad, B);
|
b = platform->inputPoll(port, ID::Device::Gamepad, B);
|
||||||
y = interface->inputPoll(port, ID::Device::Gamepad, Y);
|
y = platform->inputPoll(port, ID::Device::Gamepad, Y);
|
||||||
select = interface->inputPoll(port, ID::Device::Gamepad, Select);
|
select = platform->inputPoll(port, ID::Device::Gamepad, Select);
|
||||||
start = interface->inputPoll(port, ID::Device::Gamepad, Start);
|
start = platform->inputPoll(port, ID::Device::Gamepad, Start);
|
||||||
up = interface->inputPoll(port, ID::Device::Gamepad, Up);
|
up = platform->inputPoll(port, ID::Device::Gamepad, Up);
|
||||||
down = interface->inputPoll(port, ID::Device::Gamepad, Down);
|
down = platform->inputPoll(port, ID::Device::Gamepad, Down);
|
||||||
left = interface->inputPoll(port, ID::Device::Gamepad, Left);
|
left = platform->inputPoll(port, ID::Device::Gamepad, Left);
|
||||||
right = interface->inputPoll(port, ID::Device::Gamepad, Right);
|
right = platform->inputPoll(port, ID::Device::Gamepad, Right);
|
||||||
a = interface->inputPoll(port, ID::Device::Gamepad, A);
|
a = platform->inputPoll(port, ID::Device::Gamepad, A);
|
||||||
x = interface->inputPoll(port, ID::Device::Gamepad, X);
|
x = platform->inputPoll(port, ID::Device::Gamepad, X);
|
||||||
l = interface->inputPoll(port, ID::Device::Gamepad, L);
|
l = platform->inputPoll(port, ID::Device::Gamepad, L);
|
||||||
r = interface->inputPoll(port, ID::Device::Gamepad, R);
|
r = platform->inputPoll(port, ID::Device::Gamepad, R);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,8 +53,8 @@ auto Justifier::main() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(next < prev) {
|
if(next < prev) {
|
||||||
int nx1 = interface->inputPoll(port, device, 0 + X);
|
int nx1 = platform->inputPoll(port, device, 0 + X);
|
||||||
int ny1 = interface->inputPoll(port, device, 0 + Y);
|
int ny1 = platform->inputPoll(port, device, 0 + Y);
|
||||||
nx1 += player1.x;
|
nx1 += player1.x;
|
||||||
ny1 += player1.y;
|
ny1 += player1.y;
|
||||||
player1.x = max(-16, min(256 + 16, nx1));
|
player1.x = max(-16, min(256 + 16, nx1));
|
||||||
|
@ -64,8 +64,8 @@ auto Justifier::main() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(next < prev && chained) {
|
if(next < prev && chained) {
|
||||||
int nx2 = interface->inputPoll(port, device, 4 + X);
|
int nx2 = platform->inputPoll(port, device, 4 + X);
|
||||||
int ny2 = interface->inputPoll(port, device, 4 + Y);
|
int ny2 = platform->inputPoll(port, device, 4 + Y);
|
||||||
nx2 += player2.x;
|
nx2 += player2.x;
|
||||||
ny2 += player2.y;
|
ny2 += player2.y;
|
||||||
player2.x = max(-16, min(256 + 16, nx2));
|
player2.x = max(-16, min(256 + 16, nx2));
|
||||||
|
@ -83,13 +83,13 @@ auto Justifier::data() -> uint2 {
|
||||||
if(counter >= 32) return 1;
|
if(counter >= 32) return 1;
|
||||||
|
|
||||||
if(counter == 0) {
|
if(counter == 0) {
|
||||||
player1.trigger = interface->inputPoll(port, device, 0 + Trigger);
|
player1.trigger = platform->inputPoll(port, device, 0 + Trigger);
|
||||||
player1.start = interface->inputPoll(port, device, 0 + Start);
|
player1.start = platform->inputPoll(port, device, 0 + Start);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(counter == 0 && chained) {
|
if(counter == 0 && chained) {
|
||||||
player2.trigger = interface->inputPoll(port, device, 4 + Trigger);
|
player2.trigger = platform->inputPoll(port, device, 4 + Trigger);
|
||||||
player2.start = interface->inputPoll(port, device, 4 + Start);
|
player2.start = platform->inputPoll(port, device, 4 + Start);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(counter++) {
|
switch(counter++) {
|
||||||
|
|
|
@ -64,10 +64,10 @@ auto Mouse::latch(bool data) -> void {
|
||||||
latched = data;
|
latched = data;
|
||||||
counter = 0;
|
counter = 0;
|
||||||
|
|
||||||
x = interface->inputPoll(port, ID::Device::Mouse, X); //-n = left, 0 = center, +n = right
|
x = platform->inputPoll(port, ID::Device::Mouse, X); //-n = left, 0 = center, +n = right
|
||||||
y = interface->inputPoll(port, ID::Device::Mouse, Y); //-n = up, 0 = center, +n = down
|
y = platform->inputPoll(port, ID::Device::Mouse, Y); //-n = up, 0 = center, +n = down
|
||||||
l = interface->inputPoll(port, ID::Device::Mouse, Left);
|
l = platform->inputPoll(port, ID::Device::Mouse, Left);
|
||||||
r = interface->inputPoll(port, ID::Device::Mouse, Right);
|
r = platform->inputPoll(port, ID::Device::Mouse, Right);
|
||||||
|
|
||||||
dx = x < 0; //0 = right, 1 = left
|
dx = x < 0; //0 = right, 1 = left
|
||||||
dy = y < 0; //0 = down, 1 = up
|
dy = y < 0; //0 = down, 1 = up
|
||||||
|
|
|
@ -53,18 +53,18 @@ auto SuperMultitap::latch(bool data) -> void {
|
||||||
if(latched == 0) {
|
if(latched == 0) {
|
||||||
for(uint id : range(4)) {
|
for(uint id : range(4)) {
|
||||||
auto& gamepad = gamepads[id];
|
auto& gamepad = gamepads[id];
|
||||||
gamepad.b = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + B);
|
gamepad.b = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + B);
|
||||||
gamepad.y = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Y);
|
gamepad.y = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Y);
|
||||||
gamepad.select = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Select);
|
gamepad.select = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Select);
|
||||||
gamepad.start = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Start);
|
gamepad.start = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Start);
|
||||||
gamepad.up = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Up);
|
gamepad.up = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Up);
|
||||||
gamepad.down = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Down);
|
gamepad.down = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Down);
|
||||||
gamepad.left = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Left);
|
gamepad.left = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Left);
|
||||||
gamepad.right = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Right);
|
gamepad.right = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Right);
|
||||||
gamepad.a = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + A);
|
gamepad.a = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + A);
|
||||||
gamepad.x = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + X);
|
gamepad.x = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + X);
|
||||||
gamepad.l = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + L);
|
gamepad.l = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + L);
|
||||||
gamepad.r = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + R);
|
gamepad.r = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + R);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,8 +53,8 @@ auto SuperScope::main() -> void {
|
||||||
|
|
||||||
if(next < prev) {
|
if(next < prev) {
|
||||||
//Vcounter wrapped back to zero; update cursor coordinates for start of new frame
|
//Vcounter wrapped back to zero; update cursor coordinates for start of new frame
|
||||||
int nx = interface->inputPoll(port, ID::Device::SuperScope, X);
|
int nx = platform->inputPoll(port, ID::Device::SuperScope, X);
|
||||||
int ny = interface->inputPoll(port, ID::Device::SuperScope, Y);
|
int ny = platform->inputPoll(port, ID::Device::SuperScope, Y);
|
||||||
nx += x;
|
nx += x;
|
||||||
ny += y;
|
ny += y;
|
||||||
x = max(-16, min(256 + 16, nx));
|
x = max(-16, min(256 + 16, nx));
|
||||||
|
@ -74,7 +74,7 @@ auto SuperScope::data() -> uint2 {
|
||||||
|
|
||||||
if(counter == 0) {
|
if(counter == 0) {
|
||||||
//turbo is a switch; toggle is edge sensitive
|
//turbo is a switch; toggle is edge sensitive
|
||||||
bool newturbo = interface->inputPoll(port, ID::Device::SuperScope, Turbo);
|
bool newturbo = platform->inputPoll(port, ID::Device::SuperScope, Turbo);
|
||||||
if(newturbo && !oldturbo) {
|
if(newturbo && !oldturbo) {
|
||||||
turbo = !turbo; //toggle state
|
turbo = !turbo; //toggle state
|
||||||
sprite->setPixels(turbo ? Resource::Sprite::CrosshairRed : Resource::Sprite::CrosshairGreen);
|
sprite->setPixels(turbo ? Resource::Sprite::CrosshairRed : Resource::Sprite::CrosshairGreen);
|
||||||
|
@ -84,7 +84,7 @@ auto SuperScope::data() -> uint2 {
|
||||||
//trigger is a button
|
//trigger is a button
|
||||||
//if turbo is active, trigger is level sensitive; otherwise, it is edge sensitive
|
//if turbo is active, trigger is level sensitive; otherwise, it is edge sensitive
|
||||||
trigger = false;
|
trigger = false;
|
||||||
bool newtrigger = interface->inputPoll(port, ID::Device::SuperScope, Trigger);
|
bool newtrigger = platform->inputPoll(port, ID::Device::SuperScope, Trigger);
|
||||||
if(newtrigger && (turbo || !triggerlock)) {
|
if(newtrigger && (turbo || !triggerlock)) {
|
||||||
trigger = true;
|
trigger = true;
|
||||||
triggerlock = true;
|
triggerlock = true;
|
||||||
|
@ -93,11 +93,11 @@ auto SuperScope::data() -> uint2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
//cursor is a button; it is always level sensitive
|
//cursor is a button; it is always level sensitive
|
||||||
cursor = interface->inputPoll(port, ID::Device::SuperScope, Cursor);
|
cursor = platform->inputPoll(port, ID::Device::SuperScope, Cursor);
|
||||||
|
|
||||||
//pause is a button; it is always edge sensitive
|
//pause is a button; it is always edge sensitive
|
||||||
pause = false;
|
pause = false;
|
||||||
bool newpause = interface->inputPoll(port, ID::Device::SuperScope, Pause);
|
bool newpause = platform->inputPoll(port, ID::Device::SuperScope, Pause);
|
||||||
if(newpause && !pauselock) {
|
if(newpause && !pauselock) {
|
||||||
pause = true;
|
pause = true;
|
||||||
pauselock = true;
|
pauselock = true;
|
||||||
|
|
|
@ -84,7 +84,7 @@ auto MSU1::dataOpen() -> void {
|
||||||
auto document = BML::unserialize(cartridge.information.manifest.cartridge);
|
auto document = BML::unserialize(cartridge.information.manifest.cartridge);
|
||||||
string name = document["board/msu1/rom/name"].text();
|
string name = document["board/msu1/rom/name"].text();
|
||||||
if(!name) name = "msu1.rom";
|
if(!name) name = "msu1.rom";
|
||||||
if(dataFile = interface->open(ID::SuperFamicom, name, File::Read)) {
|
if(dataFile = platform->open(ID::SuperFamicom, name, File::Read)) {
|
||||||
dataFile->seek(io.dataReadOffset);
|
dataFile->seek(io.dataReadOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ auto MSU1::audioOpen() -> void {
|
||||||
name = track["name"].text();
|
name = track["name"].text();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(audioFile = interface->open(ID::SuperFamicom, name, File::Read)) {
|
if(audioFile = platform->open(ID::SuperFamicom, name, File::Read)) {
|
||||||
if(audioFile->size() >= 8) {
|
if(audioFile->size() >= 8) {
|
||||||
uint32 header = audioFile->readm(4);
|
uint32 header = audioFile->readm(4);
|
||||||
if(header == 0x4d535531) { //"MSU1"
|
if(header == 0x4d535531) { //"MSU1"
|
||||||
|
|
|
@ -18,11 +18,11 @@ S21FX::S21FX() {
|
||||||
ram[1] = 0xfc;
|
ram[1] = 0xfc;
|
||||||
ram[2] = 0xff;
|
ram[2] = 0xff;
|
||||||
|
|
||||||
if(auto buffer = file::read({interface->path(ID::System), "21fx.rom"})) {
|
if(auto buffer = file::read({platform->path(ID::System), "21fx.rom"})) {
|
||||||
memory::copy(ram, sizeof(ram), buffer.data(), buffer.size());
|
memory::copy(ram, sizeof(ram), buffer.data(), buffer.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
string filename{interface->path(ID::SuperFamicom), "21fx.so"};
|
string filename{platform->path(ID::SuperFamicom), "21fx.so"};
|
||||||
if(link.openAbsolute(filename)) {
|
if(link.openAbsolute(filename)) {
|
||||||
linkInit = link.sym("fx_init");
|
linkInit = link.sym("fx_init");
|
||||||
linkMain = link.sym("fx_main");
|
linkMain = link.sym("fx_main");
|
||||||
|
|
|
@ -2,11 +2,9 @@
|
||||||
|
|
||||||
namespace SuperFamicom {
|
namespace SuperFamicom {
|
||||||
|
|
||||||
Interface* interface = nullptr;
|
|
||||||
Settings settings;
|
Settings settings;
|
||||||
|
|
||||||
Interface::Interface() {
|
Interface::Interface() {
|
||||||
interface = this;
|
|
||||||
system.init();
|
system.init();
|
||||||
|
|
||||||
information.manufacturer = "Nintendo";
|
information.manufacturer = "Nintendo";
|
||||||
|
@ -185,7 +183,7 @@ auto Interface::sha256() -> string {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::load(uint id) -> bool {
|
auto Interface::load(uint id) -> bool {
|
||||||
if(id == ID::SuperFamicom) return system.load();
|
if(id == ID::SuperFamicom) return system.load(this);
|
||||||
if(id == ID::BSMemory) return cartridge.loadBSMemory();
|
if(id == ID::BSMemory) return cartridge.loadBSMemory();
|
||||||
if(id == ID::SufamiTurboA) return cartridge.loadSufamiTurboA();
|
if(id == ID::SufamiTurboA) return cartridge.loadSufamiTurboA();
|
||||||
if(id == ID::SufamiTurboB) return cartridge.loadSufamiTurboB();
|
if(id == ID::SufamiTurboB) return cartridge.loadSufamiTurboB();
|
||||||
|
@ -202,7 +200,7 @@ auto Interface::unload() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::connect(uint port, uint device) -> void {
|
auto Interface::connect(uint port, uint device) -> void {
|
||||||
SuperFamicom::peripherals.connect(port, device);
|
peripherals.connect(port, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::power() -> void {
|
auto Interface::power() -> void {
|
||||||
|
|
|
@ -81,7 +81,6 @@ struct Settings {
|
||||||
bool random = true;
|
bool random = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Interface* interface;
|
|
||||||
extern Settings settings;
|
extern Settings settings;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace SuperFamicom {
|
namespace SuperFamicom {
|
||||||
|
#define platform Emulator::platform
|
||||||
using File = Emulator::File;
|
using File = Emulator::File;
|
||||||
using Scheduler = Emulator::Scheduler;
|
using Scheduler = Emulator::Scheduler;
|
||||||
using Cheat = Emulator::Cheat;
|
using Cheat = Emulator::Cheat;
|
||||||
|
|
|
@ -18,7 +18,7 @@ auto SMP::main() -> void {
|
||||||
|
|
||||||
auto SMP::load(Markup::Node node) -> bool {
|
auto SMP::load(Markup::Node node) -> bool {
|
||||||
if(auto name = node["smp/rom/name"].text()) {
|
if(auto name = node["smp/rom/name"].text()) {
|
||||||
if(auto fp = interface->open(ID::System, name, File::Read, File::Required)) {
|
if(auto fp = platform->open(ID::System, name, File::Read, File::Required)) {
|
||||||
fp->read(iplrom, 64);
|
fp->read(iplrom, 64);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,6 @@ auto System::runToSave() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::init() -> void {
|
auto System::init() -> void {
|
||||||
assert(interface != nullptr);
|
|
||||||
|
|
||||||
icd2.init();
|
icd2.init();
|
||||||
mcc.init();
|
mcc.init();
|
||||||
nss.init();
|
nss.init();
|
||||||
|
@ -48,10 +46,10 @@ auto System::init() -> void {
|
||||||
auto System::term() -> void {
|
auto System::term() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::load() -> bool {
|
auto System::load(Emulator::Interface* interface) -> bool {
|
||||||
information = Information();
|
information = Information();
|
||||||
|
|
||||||
if(auto fp = interface->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
if(auto fp = platform->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
||||||
information.manifest = fp->reads();
|
information.manifest = fp->reads();
|
||||||
} else return false;
|
} else return false;
|
||||||
|
|
||||||
|
@ -93,6 +91,7 @@ auto System::load() -> bool {
|
||||||
if(cartridge.has.SufamiTurboSlots) sufamiturboA.load(), sufamiturboB.load();
|
if(cartridge.has.SufamiTurboSlots) sufamiturboA.load(), sufamiturboB.load();
|
||||||
|
|
||||||
serializeInit();
|
serializeInit();
|
||||||
|
this->interface = interface;
|
||||||
return information.loaded = true;
|
return information.loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
struct Interface;
|
|
||||||
|
|
||||||
struct System {
|
struct System {
|
||||||
enum class Region : bool { NTSC = 0, PAL = 1 };
|
enum class Region : bool { NTSC = 0, PAL = 1 };
|
||||||
|
|
||||||
|
@ -12,7 +10,7 @@ struct System {
|
||||||
|
|
||||||
auto init() -> void;
|
auto init() -> void;
|
||||||
auto term() -> void;
|
auto term() -> void;
|
||||||
auto load() -> bool;
|
auto load(Emulator::Interface*) -> bool;
|
||||||
auto save() -> void;
|
auto save() -> void;
|
||||||
auto unload() -> void;
|
auto unload() -> void;
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
@ -27,6 +25,8 @@ struct System {
|
||||||
auto unserialize(serializer&) -> bool;
|
auto unserialize(serializer&) -> bool;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Emulator::Interface* interface = nullptr;
|
||||||
|
|
||||||
struct Information {
|
struct Information {
|
||||||
string manifest;
|
string manifest;
|
||||||
bool loaded = false;
|
bool loaded = false;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
name := higan
|
name := higan
|
||||||
flags += -DSFC_SUPERGAMEBOY
|
#flags += -DSFC_SUPERGAMEBOY
|
||||||
|
|
||||||
include fc/GNUmakefile
|
include fc/GNUmakefile
|
||||||
include sfc/GNUmakefile
|
include sfc/GNUmakefile
|
||||||
|
|
|
@ -17,15 +17,16 @@ Program::Program(string_vector args) {
|
||||||
program = this;
|
program = this;
|
||||||
Application::onMain({&Program::main, this});
|
Application::onMain({&Program::main, this});
|
||||||
|
|
||||||
|
Emulator::platform = this;
|
||||||
emulators.append(new Famicom::Interface);
|
emulators.append(new Famicom::Interface);
|
||||||
emulators.append(new SuperFamicom::Interface);
|
emulators.append(new SuperFamicom::Interface);
|
||||||
emulators.append(new MasterSystem::Interface);
|
emulators.append(new MasterSystem::MasterSystemInterface);
|
||||||
emulators.append(new MegaDrive::Interface);
|
emulators.append(new MegaDrive::Interface);
|
||||||
emulators.append(new PCEngine::Interface);
|
emulators.append(new PCEngine::Interface);
|
||||||
emulators.append(new GameBoy::Interface);
|
emulators.append(new GameBoy::Interface);
|
||||||
emulators.append(new GameBoyAdvance::Interface);
|
emulators.append(new GameBoyAdvance::Interface);
|
||||||
|
emulators.append(new MasterSystem::GameGearInterface);
|
||||||
emulators.append(new WonderSwan::Interface);
|
emulators.append(new WonderSwan::Interface);
|
||||||
for(auto& emulator : emulators) emulator->bind = this;
|
|
||||||
|
|
||||||
new Presentation;
|
new Presentation;
|
||||||
presentation->setVisible();
|
presentation->setVisible();
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue