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
|
||||
|
||||
flags += -I. -I.. -O3
|
||||
objects := libco audio video resource
|
||||
objects := libco emulator audio video resource
|
||||
|
||||
# profile-guided optimization mode
|
||||
# pgo := instrument
|
||||
|
@ -52,10 +52,11 @@ compile = \
|
|||
|
||||
all: build;
|
||||
|
||||
obj/libco.o: ../libco/libco.c $(call rwildcard,../libco/)
|
||||
obj/audio.o: audio/audio.cpp $(call rwildcard,audio/)
|
||||
obj/video.o: video/video.cpp $(call rwildcard,video/)
|
||||
obj/resource.o: resource/resource.cpp $(call rwildcard,resource/)
|
||||
obj/libco.o: ../libco/libco.c $(call rwildcard,../libco)
|
||||
obj/emulator.o: emulator/emulator.cpp $(call rwildcard,emulator)
|
||||
obj/audio.o: audio/audio.cpp $(call rwildcard,audio)
|
||||
obj/video.o: video/video.cpp $(call rwildcard,video)
|
||||
obj/resource.o: resource/resource.cpp $(call rwildcard,resource)
|
||||
|
||||
ui := target-$(target)
|
||||
include $(ui)/GNUmakefile
|
||||
|
|
|
@ -6,6 +6,8 @@ namespace Emulator {
|
|||
Audio audio;
|
||||
|
||||
auto Audio::reset(maybe<uint> channels_, maybe<double> frequency_) -> void {
|
||||
interface = nullptr;
|
||||
|
||||
if(channels_) channels = channels_();
|
||||
if(frequency_) frequency = frequency_();
|
||||
|
||||
|
@ -81,7 +83,7 @@ auto Audio::process() -> void {
|
|||
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 {
|
||||
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 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 {
|
||||
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 License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -2,6 +2,18 @@
|
|||
|
||||
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 Information {
|
||||
string manufacturer;
|
||||
|
@ -38,30 +50,6 @@ struct Interface {
|
|||
};
|
||||
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
|
||||
virtual auto manifest() -> string = 0;
|
||||
virtual auto title() -> string = 0;
|
||||
|
@ -118,4 +106,6 @@ struct File {
|
|||
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(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()));
|
||||
}
|
||||
}
|
||||
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()));
|
||||
}
|
||||
}
|
||||
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()));
|
||||
}
|
||||
}
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
@ -70,13 +70,13 @@ auto Board::save() -> void {
|
|||
auto document = BML::unserialize(cartridge.manifest());
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,11 +15,11 @@ auto Cartridge::main() -> void {
|
|||
}
|
||||
|
||||
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();
|
||||
} 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();
|
||||
} else {
|
||||
return false;
|
||||
|
|
|
@ -3,7 +3,7 @@ Gamepad::Gamepad(bool port) : Controller(port) {
|
|||
|
||||
auto Gamepad::data() -> uint3 {
|
||||
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++) {
|
||||
case 0: return a;
|
||||
|
@ -24,13 +24,13 @@ auto Gamepad::latch(bool data) -> void {
|
|||
counter = 0;
|
||||
|
||||
if(latched == 0) {
|
||||
a = interface->inputPoll(port, ID::Device::Gamepad, A);
|
||||
b = interface->inputPoll(port, ID::Device::Gamepad, B);
|
||||
select = interface->inputPoll(port, ID::Device::Gamepad, Select);
|
||||
start = interface->inputPoll(port, ID::Device::Gamepad, Start);
|
||||
up = interface->inputPoll(port, ID::Device::Gamepad, Up);
|
||||
down = interface->inputPoll(port, ID::Device::Gamepad, Down);
|
||||
left = interface->inputPoll(port, ID::Device::Gamepad, Left);
|
||||
right = interface->inputPoll(port, ID::Device::Gamepad, Right);
|
||||
a = platform->inputPoll(port, ID::Device::Gamepad, A);
|
||||
b = platform->inputPoll(port, ID::Device::Gamepad, B);
|
||||
select = platform->inputPoll(port, ID::Device::Gamepad, Select);
|
||||
start = platform->inputPoll(port, ID::Device::Gamepad, Start);
|
||||
up = platform->inputPoll(port, ID::Device::Gamepad, Up);
|
||||
down = platform->inputPoll(port, ID::Device::Gamepad, Down);
|
||||
left = platform->inputPoll(port, ID::Device::Gamepad, Left);
|
||||
right = platform->inputPoll(port, ID::Device::Gamepad, Right);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <processor/r6502/r6502.hpp>
|
||||
|
||||
namespace Famicom {
|
||||
#define platform Emulator::platform
|
||||
using File = Emulator::File;
|
||||
using Scheduler = Emulator::Scheduler;
|
||||
using Cheat = Emulator::Cheat;
|
||||
|
|
|
@ -2,12 +2,9 @@
|
|||
|
||||
namespace Famicom {
|
||||
|
||||
Interface* interface = nullptr;
|
||||
Settings settings;
|
||||
|
||||
Interface::Interface() {
|
||||
interface = this;
|
||||
|
||||
information.manufacturer = "Nintendo";
|
||||
information.name = "Famicom";
|
||||
information.overscan = true;
|
||||
|
@ -134,7 +131,7 @@ auto Interface::sha256() -> string {
|
|||
}
|
||||
|
||||
auto Interface::load(uint id) -> bool {
|
||||
return system.load();
|
||||
return system.load(this);
|
||||
}
|
||||
|
||||
auto Interface::save() -> void {
|
||||
|
@ -147,7 +144,7 @@ auto Interface::unload() -> void {
|
|||
}
|
||||
|
||||
auto Interface::connect(uint port, uint device) -> void {
|
||||
Famicom::peripherals.connect(port, device);
|
||||
peripherals.connect(port, device);
|
||||
}
|
||||
|
||||
auto Interface::power() -> void {
|
||||
|
|
|
@ -64,7 +64,6 @@ struct Settings {
|
|||
uint expansionPort = 0;
|
||||
};
|
||||
|
||||
extern Interface* interface;
|
||||
extern Settings settings;
|
||||
|
||||
}
|
||||
|
|
|
@ -21,15 +21,17 @@ auto System::runToSave() -> void {
|
|||
for(auto peripheral : cpu.peripherals) scheduler.synchronize(*peripheral);
|
||||
}
|
||||
|
||||
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();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
if(!cartridge.load()) return false;
|
||||
|
||||
this->interface = interface;
|
||||
information.colorburst = Emulator::Constants::Colorburst::NTSC;
|
||||
serializeInit();
|
||||
return information.loaded = true;
|
||||
|
|
|
@ -5,7 +5,7 @@ struct System {
|
|||
auto run() -> void;
|
||||
auto runToSave() -> void;
|
||||
|
||||
auto load() -> bool;
|
||||
auto load(Emulator::Interface*) -> bool;
|
||||
auto save() -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
|
@ -26,13 +26,15 @@ struct System {
|
|||
auto serializeAll(serializer&) -> void;
|
||||
auto serializeInit() -> void;
|
||||
|
||||
private:
|
||||
Emulator::Interface* interface = nullptr;
|
||||
|
||||
struct Information {
|
||||
bool loaded = false;
|
||||
double colorburst = 0.0;
|
||||
string manifest;
|
||||
} information;
|
||||
|
||||
private:
|
||||
uint _serializeSize = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ auto APU::main() -> void {
|
|||
stream->sample(sequencer.left / 32768.0, sequencer.right / 32768.0);
|
||||
} else {
|
||||
double samples[] = {sequencer.left / 32768.0, sequencer.right / 32768.0};
|
||||
interface->audioSample(samples, 2);
|
||||
//interface->audioSample(samples, 2);
|
||||
}
|
||||
|
||||
if(cycle == 0) { //512hz
|
||||
|
|
|
@ -19,23 +19,23 @@ auto Cartridge::load(System::Revision revision) -> bool {
|
|||
|
||||
switch(revision) {
|
||||
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();
|
||||
} else return false;
|
||||
break;
|
||||
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();
|
||||
} else return false;
|
||||
break;
|
||||
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();
|
||||
} else return false;
|
||||
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();
|
||||
} else return false;
|
||||
|
||||
|
@ -64,12 +64,12 @@ auto Cartridge::load(System::Revision revision) -> bool {
|
|||
ram.data = (uint8*)memory::allocate(ram.size, 0xff);
|
||||
|
||||
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()));
|
||||
}
|
||||
}
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ auto Cartridge::save() -> void {
|
|||
auto document = BML::unserialize(information.manifest);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,15 +8,15 @@ auto CPU::wramAddress(uint16 addr) const -> uint {
|
|||
auto CPU::joypPoll() -> void {
|
||||
uint button = 0, dpad = 0;
|
||||
|
||||
button |= interface->inputPoll(0, 0, (uint)Input::Start) << 3;
|
||||
button |= interface->inputPoll(0, 0, (uint)Input::Select) << 2;
|
||||
button |= interface->inputPoll(0, 0, (uint)Input::B) << 1;
|
||||
button |= interface->inputPoll(0, 0, (uint)Input::A) << 0;
|
||||
button |= platform->inputPoll(0, 0, (uint)Input::Start) << 3;
|
||||
button |= platform->inputPoll(0, 0, (uint)Input::Select) << 2;
|
||||
button |= platform->inputPoll(0, 0, (uint)Input::B) << 1;
|
||||
button |= platform->inputPoll(0, 0, (uint)Input::A) << 0;
|
||||
|
||||
dpad |= interface->inputPoll(0, 0, (uint)Input::Down) << 3;
|
||||
dpad |= interface->inputPoll(0, 0, (uint)Input::Up) << 2;
|
||||
dpad |= interface->inputPoll(0, 0, (uint)Input::Left) << 1;
|
||||
dpad |= interface->inputPoll(0, 0, (uint)Input::Right) << 0;
|
||||
dpad |= platform->inputPoll(0, 0, (uint)Input::Down) << 3;
|
||||
dpad |= platform->inputPoll(0, 0, (uint)Input::Up) << 2;
|
||||
dpad |= platform->inputPoll(0, 0, (uint)Input::Left) << 1;
|
||||
dpad |= platform->inputPoll(0, 0, (uint)Input::Right) << 0;
|
||||
|
||||
if(system.revision() != System::Revision::SuperGameBoy) {
|
||||
//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
|
||||
status.p15 = data & 0x20;
|
||||
status.p14 = data & 0x10;
|
||||
interface->joypWrite(status.p15, status.p14);
|
||||
//interface->joypWrite(status.p15, status.p14);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <processor/lr35902/lr35902.hpp>
|
||||
|
||||
namespace GameBoy {
|
||||
#define platform Emulator::platform
|
||||
using File = Emulator::File;
|
||||
using Scheduler = Emulator::Scheduler;
|
||||
using Cheat = Emulator::Cheat;
|
||||
|
|
|
@ -2,11 +2,9 @@
|
|||
|
||||
namespace GameBoy {
|
||||
|
||||
Interface* interface = nullptr;
|
||||
Settings settings;
|
||||
|
||||
Interface::Interface() {
|
||||
interface = this;
|
||||
hook = nullptr;
|
||||
|
||||
information.manufacturer = "Nintendo";
|
||||
|
@ -134,9 +132,9 @@ auto Interface::sha256() -> string {
|
|||
}
|
||||
|
||||
auto Interface::load(uint id) -> bool {
|
||||
if(id == ID::GameBoy) return system.load(System::Revision::GameBoy);
|
||||
if(id == ID::SuperGameBoy) return system.load(System::Revision::SuperGameBoy);
|
||||
if(id == ID::GameBoyColor) return system.load(System::Revision::GameBoyColor);
|
||||
if(id == ID::GameBoy) return system.load(this, System::Revision::GameBoy);
|
||||
if(id == ID::SuperGameBoy) return system.load(this, System::Revision::SuperGameBoy);
|
||||
if(id == ID::GameBoyColor) return system.load(this, System::Revision::GameBoyColor);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,6 @@ struct Settings {
|
|||
bool colorEmulation = true;
|
||||
};
|
||||
|
||||
extern Interface* interface;
|
||||
extern Settings settings;
|
||||
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ auto PPU::runDMG() -> void {
|
|||
|
||||
uint32* output = screen + status.ly * 160 + px++;
|
||||
*output = color;
|
||||
interface->lcdOutput(color); //Super Game Boy notification
|
||||
//interface->lcdOutput(color); //Super Game Boy notification
|
||||
}
|
||||
|
||||
auto PPU::runBackgroundDMG() -> void {
|
||||
|
|
|
@ -16,7 +16,7 @@ auto PPU::Enter() -> void {
|
|||
|
||||
auto PPU::main() -> void {
|
||||
status.lx = 0;
|
||||
interface->lcdScanline(); //Super Game Boy notification
|
||||
//interface->lcdScanline(); //Super Game Boy notification
|
||||
|
||||
if(status.ly <= 143) {
|
||||
mode(2);
|
||||
|
|
|
@ -22,10 +22,10 @@ auto System::init() -> void {
|
|||
assert(interface != nullptr);
|
||||
}
|
||||
|
||||
auto System::load(Revision revision) -> bool {
|
||||
auto System::load(Emulator::Interface* interface, Revision revision) -> bool {
|
||||
_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();
|
||||
} else return false;
|
||||
|
||||
|
@ -34,7 +34,7 @@ auto System::load(Revision revision) -> bool {
|
|||
if(revision == Revision::SuperGameBoy) path = "board/icd2/rom/name";
|
||||
|
||||
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::SuperGameBoy) fp->read(bootROM.sgb, 256);
|
||||
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;
|
||||
serializeInit();
|
||||
this->interface = interface;
|
||||
return _loaded = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
struct Interface;
|
||||
|
||||
enum class Input : uint {
|
||||
Up, Down, Left, Right, B, A, Select, Start,
|
||||
};
|
||||
|
@ -23,7 +21,7 @@ struct System {
|
|||
auto runToSave() -> void;
|
||||
|
||||
auto init() -> void;
|
||||
auto load(Revision) -> bool;
|
||||
auto load(Emulator::Interface*, Revision) -> bool;
|
||||
auto save() -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
|
@ -40,6 +38,8 @@ struct System {
|
|||
auto serializeAll(serializer&) -> void;
|
||||
auto serializeInit() -> void;
|
||||
|
||||
Emulator::Interface* interface = nullptr;
|
||||
|
||||
struct BootROM {
|
||||
uint8 dmg[ 256];
|
||||
uint8 sgb[ 256];
|
||||
|
|
|
@ -26,11 +26,11 @@ Cartridge::~Cartridge() {
|
|||
auto Cartridge::load() -> bool {
|
||||
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();
|
||||
} 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();
|
||||
} else return false;
|
||||
|
||||
|
@ -43,7 +43,7 @@ auto Cartridge::load() -> bool {
|
|||
|
||||
if(auto node = document["board/rom"]) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ auto Cartridge::load() -> bool {
|
|||
sram.mask = sram.size - 1;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ auto Cartridge::load() -> bool {
|
|||
eeprom.test = mrom.size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ auto Cartridge::load() -> bool {
|
|||
if(!flash.id && flash.size == 64 * 1024) flash.id = 0x1cc2;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ auto Cartridge::load() -> bool {
|
|||
auto Cartridge::save() -> void {
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
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() == "eeprom") fp->write(eeprom.data, eeprom.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
|
||||
for(auto n : range(10)) {
|
||||
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 == 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};
|
||||
if(auto result = player.keyinput()) return 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 & 0x30) == 0x30) result &= (uint8)~0x30; //left+right cannot be pressed simultaneously
|
||||
return result ^ 0xff;
|
||||
|
@ -72,8 +72,8 @@ auto CPU::readIO(uint32 addr) -> uint8 {
|
|||
case 0x04000131: {
|
||||
if(auto result = player.keyinput()) return result() >> 8;
|
||||
uint8 result = 0;
|
||||
result |= interface->inputPoll(0, 0, 7) << 0;
|
||||
result |= interface->inputPoll(0, 0, 6) << 1;
|
||||
result |= platform->inputPoll(0, 0, 7) << 0;
|
||||
result |= platform->inputPoll(0, 0, 6) << 1;
|
||||
return result ^ 0x03;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <processor/arm/arm.hpp>
|
||||
|
||||
namespace GameBoyAdvance {
|
||||
#define platform Emulator::platform
|
||||
using File = Emulator::File;
|
||||
using Scheduler = Emulator::Scheduler;
|
||||
extern Scheduler scheduler;
|
||||
|
|
|
@ -2,12 +2,9 @@
|
|||
|
||||
namespace GameBoyAdvance {
|
||||
|
||||
Interface* interface = nullptr;
|
||||
Settings settings;
|
||||
|
||||
Interface::Interface() {
|
||||
interface = this;
|
||||
|
||||
information.manufacturer = "Nintendo";
|
||||
information.name = "Game Boy Advance";
|
||||
information.overscan = false;
|
||||
|
@ -96,7 +93,7 @@ auto Interface::loaded() -> bool {
|
|||
}
|
||||
|
||||
auto Interface::load(uint id) -> bool {
|
||||
return system.load();
|
||||
return system.load(this);
|
||||
}
|
||||
|
||||
auto Interface::save() -> void {
|
||||
|
|
|
@ -53,7 +53,6 @@ struct Settings {
|
|||
bool colorEmulation = true;
|
||||
};
|
||||
|
||||
extern Interface* interface;
|
||||
extern Settings settings;
|
||||
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ auto Player::write(uint2 addr, uint8 byte) -> void {
|
|||
|
||||
if(addr == 3 && status.packet == 15) {
|
||||
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);
|
||||
}
|
||||
|
||||
auto System::load() -> bool {
|
||||
if(auto fp = interface->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
||||
auto System::load(Emulator::Interface* interface) -> bool {
|
||||
if(auto fp = platform->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
||||
information.manifest = fp->reads();
|
||||
} else return false;
|
||||
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if(!cartridge.load()) return false;
|
||||
|
||||
serializeInit();
|
||||
this->interface = interface;
|
||||
return _loaded = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ struct System {
|
|||
|
||||
auto init() -> void;
|
||||
auto term() -> void;
|
||||
auto load() -> bool;
|
||||
auto load(Emulator::Interface*) -> bool;
|
||||
auto save() -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
|
@ -38,6 +38,9 @@ struct System {
|
|||
auto serializeAll(serializer&) -> void;
|
||||
auto serializeInit() -> void;
|
||||
|
||||
private:
|
||||
Emulator::Interface* interface = nullptr;
|
||||
|
||||
struct Information {
|
||||
string manifest;
|
||||
} information;
|
||||
|
|
|
@ -5,13 +5,13 @@ namespace MegaDrive {
|
|||
Cartridge cartridge;
|
||||
|
||||
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();
|
||||
} 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();
|
||||
} else return false;
|
||||
|
||||
|
@ -24,7 +24,7 @@ auto Cartridge::load() -> bool {
|
|||
if(rom.size) {
|
||||
rom.data = new uint8[rom.mask + 1];
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ auto Cartridge::load() -> bool {
|
|||
if(ram.size) {
|
||||
ram.data = new uint8[ram.mask + 1];
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ auto Cartridge::save() -> void {
|
|||
auto document = BML::unserialize(information.manifest);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,19 +5,19 @@ auto Gamepad::readData() -> uint8 {
|
|||
uint6 data;
|
||||
|
||||
if(select == 0) {
|
||||
data.bit(0) = interface->inputPoll(port, ID::Device::Gamepad, Up);
|
||||
data.bit(1) = interface->inputPoll(port, ID::Device::Gamepad, Down);
|
||||
data.bit(0) = platform->inputPoll(port, ID::Device::Gamepad, Up);
|
||||
data.bit(1) = platform->inputPoll(port, ID::Device::Gamepad, Down);
|
||||
data.bit(2) = 1;
|
||||
data.bit(3) = 1;
|
||||
data.bit(4) = interface->inputPoll(port, ID::Device::Gamepad, A);
|
||||
data.bit(5) = interface->inputPoll(port, ID::Device::Gamepad, Start);
|
||||
data.bit(4) = platform->inputPoll(port, ID::Device::Gamepad, A);
|
||||
data.bit(5) = platform->inputPoll(port, ID::Device::Gamepad, Start);
|
||||
} else {
|
||||
data.bit(0) = interface->inputPoll(port, ID::Device::Gamepad, Up);
|
||||
data.bit(1) = interface->inputPoll(port, ID::Device::Gamepad, Down);
|
||||
data.bit(2) = interface->inputPoll(port, ID::Device::Gamepad, Left);
|
||||
data.bit(3) = interface->inputPoll(port, ID::Device::Gamepad, Right);
|
||||
data.bit(4) = interface->inputPoll(port, ID::Device::Gamepad, B);
|
||||
data.bit(5) = interface->inputPoll(port, ID::Device::Gamepad, C);
|
||||
data.bit(0) = platform->inputPoll(port, ID::Device::Gamepad, Up);
|
||||
data.bit(1) = platform->inputPoll(port, ID::Device::Gamepad, Down);
|
||||
data.bit(2) = platform->inputPoll(port, ID::Device::Gamepad, Left);
|
||||
data.bit(3) = platform->inputPoll(port, ID::Device::Gamepad, Right);
|
||||
data.bit(4) = platform->inputPoll(port, ID::Device::Gamepad, B);
|
||||
data.bit(5) = platform->inputPoll(port, ID::Device::Gamepad, C);
|
||||
}
|
||||
|
||||
data = ~data;
|
||||
|
|
|
@ -2,12 +2,9 @@
|
|||
|
||||
namespace MegaDrive {
|
||||
|
||||
Interface* interface = nullptr;
|
||||
Settings settings;
|
||||
|
||||
Interface::Interface() {
|
||||
interface = this;
|
||||
|
||||
information.manufacturer = "Sega";
|
||||
information.name = "Mega Drive";
|
||||
information.overscan = true;
|
||||
|
@ -97,7 +94,7 @@ auto Interface::loaded() -> bool {
|
|||
}
|
||||
|
||||
auto Interface::load(uint id) -> bool {
|
||||
return system.load();
|
||||
return system.load(this);
|
||||
}
|
||||
|
||||
auto Interface::save() -> void {
|
||||
|
@ -109,7 +106,7 @@ auto Interface::unload() -> void {
|
|||
}
|
||||
|
||||
auto Interface::connect(uint port, uint device) -> void {
|
||||
MegaDrive::peripherals.connect(port, device);
|
||||
peripherals.connect(port, device);
|
||||
}
|
||||
|
||||
auto Interface::power() -> void {
|
||||
|
|
|
@ -58,7 +58,6 @@ struct Settings {
|
|||
uint extensionPort = 0;
|
||||
};
|
||||
|
||||
extern Interface* interface;
|
||||
extern Settings settings;
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <processor/z80/z80.hpp>
|
||||
|
||||
namespace MegaDrive {
|
||||
#define platform Emulator::platform
|
||||
using File = Emulator::File;
|
||||
using Scheduler = Emulator::Scheduler;
|
||||
extern Scheduler scheduler;
|
||||
|
|
|
@ -10,14 +10,18 @@ auto System::run() -> void {
|
|||
if(scheduler.enter() == Scheduler::Event::Frame) vdp.refresh();
|
||||
}
|
||||
|
||||
auto System::load() -> bool {
|
||||
information = Information();
|
||||
if(auto fp = interface->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
||||
auto System::load(Emulator::Interface* interface) -> bool {
|
||||
information = {};
|
||||
|
||||
if(auto fp = platform->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
||||
information.manifest = fp->reads();
|
||||
} else return false;
|
||||
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
if(!cartridge.load()) return false;
|
||||
|
||||
information.colorburst = Emulator::Constants::Colorburst::NTSC;
|
||||
this->interface = interface;
|
||||
return information.loaded = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,15 @@ struct System {
|
|||
|
||||
auto run() -> void;
|
||||
|
||||
auto load() -> bool;
|
||||
auto load(Emulator::Interface*) -> bool;
|
||||
auto save() -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
private:
|
||||
Emulator::Interface* interface = nullptr;
|
||||
|
||||
struct Information {
|
||||
bool loaded = false;
|
||||
string manifest;
|
||||
|
|
|
@ -19,6 +19,11 @@ auto Bus::in(uint8 addr) -> uint8 {
|
|||
switch(addr >> 6) {
|
||||
|
||||
case 0: {
|
||||
if(system.model() == Model::GameGear) {
|
||||
auto hardware = peripherals.hardware->readData();
|
||||
return hardware.bit(6) << 7 | 0x7f;
|
||||
}
|
||||
|
||||
return 0xff; //SMS1 = MDR, SMS2 = 0xff
|
||||
}
|
||||
|
||||
|
@ -31,16 +36,26 @@ auto Bus::in(uint8 addr) -> uint8 {
|
|||
}
|
||||
|
||||
case 3: {
|
||||
auto A = peripherals.controllerPort1->readData();
|
||||
auto B = peripherals.controllerPort2->readData();
|
||||
if(system.model() == Model::MasterSystem) {
|
||||
auto hardware = peripherals.hardware->readData();
|
||||
auto port1 = peripherals.controllerPort1->readData();
|
||||
auto port2 = peripherals.controllerPort2->readData();
|
||||
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 {
|
||||
//d4 = reset button
|
||||
//d5 = cartridge CONT pin
|
||||
return B.bits(2,5) << 0 | 1 << 4 | 1 << 5 | A.bit(6) << 6 | B.bit(6) << 7;
|
||||
return port2.bits(2,5) << 0 | hardware.bit(0) << 4 | 1 << 5 | port1.bit(6) << 6 | port2.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()) {
|
||||
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();
|
||||
} else return false;
|
||||
break;
|
||||
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();
|
||||
} else return false;
|
||||
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();
|
||||
} else return false;
|
||||
|
||||
|
@ -34,7 +34,7 @@ auto Cartridge::load() -> bool {
|
|||
if(rom.size) {
|
||||
rom.data = new uint8[rom.mask + 1];
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ auto Cartridge::load() -> bool {
|
|||
if(ram.size) {
|
||||
ram.data = new uint8[ram.mask + 1];
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ auto Cartridge::save() -> void {
|
|||
auto document = BML::unserialize(information.manifest);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -75,9 +75,6 @@ auto Cartridge::unload() -> void {
|
|||
}
|
||||
|
||||
auto Cartridge::power() -> void {
|
||||
}
|
||||
|
||||
auto Cartridge::reset() -> void {
|
||||
memory::fill(&mapper, sizeof(Mapper));
|
||||
mapper.romPage0 = 0;
|
||||
mapper.romPage1 = 1;
|
||||
|
|
|
@ -9,7 +9,6 @@ struct Cartridge {
|
|||
auto unload() -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
//mapper.cpp
|
||||
auto read(uint16 addr) -> maybe<uint8>;
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace MasterSystem {
|
||||
|
||||
#include "mastersystem/mastersystem.cpp"
|
||||
#include "gamegear/gamegear.cpp"
|
||||
#include "gamepad/gamepad.cpp"
|
||||
|
||||
Controller::Controller(uint port) : port(port) {
|
||||
|
@ -14,8 +16,9 @@ Controller::~Controller() {
|
|||
auto Controller::Enter() -> void {
|
||||
while(true) {
|
||||
scheduler.synchronize();
|
||||
if(peripherals.controllerPort1->active()) peripherals.controllerPort1->main();
|
||||
if(peripherals.controllerPort2->active()) peripherals.controllerPort2->main();
|
||||
if(auto device = peripherals.hardware) if(device->active()) device->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;
|
||||
auto main() -> void;
|
||||
|
||||
virtual auto readData() -> uint7 { return 0x7f; }
|
||||
virtual auto readData() -> uint8 { return 0xff; }
|
||||
|
||||
const uint port;
|
||||
};
|
||||
|
||||
#include "mastersystem/mastersystem.hpp"
|
||||
#include "gamegear/gamegear.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) {
|
||||
}
|
||||
|
||||
auto Gamepad::readData() -> uint7 {
|
||||
uint7 data;
|
||||
|
||||
data.bit(0) = !interface->inputPoll(port, ID::Device::Gamepad, Up);
|
||||
data.bit(1) = !interface->inputPoll(port, ID::Device::Gamepad, Down);
|
||||
data.bit(2) = !interface->inputPoll(port, ID::Device::Gamepad, Left);
|
||||
data.bit(3) = !interface->inputPoll(port, ID::Device::Gamepad, Right);
|
||||
data.bit(4) = !interface->inputPoll(port, ID::Device::Gamepad, One);
|
||||
data.bit(5) = !interface->inputPoll(port, ID::Device::Gamepad, Two);
|
||||
data.bit(6) = 1;
|
||||
|
||||
auto Gamepad::readData() -> uint8 {
|
||||
uint8 data = 0xff;
|
||||
data.bit(0) = !platform->inputPoll(port, ID::Device::Gamepad, Up);
|
||||
data.bit(1) = !platform->inputPoll(port, ID::Device::Gamepad, Down);
|
||||
data.bit(2) = !platform->inputPoll(port, ID::Device::Gamepad, Left);
|
||||
data.bit(3) = !platform->inputPoll(port, ID::Device::Gamepad, Right);
|
||||
data.bit(4) = !platform->inputPoll(port, ID::Device::Gamepad, One);
|
||||
data.bit(5) = !platform->inputPoll(port, ID::Device::Gamepad, Two);
|
||||
return data;
|
||||
}
|
||||
|
|
|
@ -5,5 +5,5 @@ struct Gamepad : Controller {
|
|||
|
||||
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 {
|
||||
Z80::bus = &MasterSystem::bus;
|
||||
Z80::power();
|
||||
}
|
||||
|
||||
auto CPU::reset() -> void {
|
||||
Z80::reset();
|
||||
create(CPU::Enter, system.colorburst());
|
||||
|
||||
memory::fill(&state, sizeof(State));
|
||||
|
|
|
@ -9,7 +9,6 @@ struct CPU : Processor::Z80, Thread {
|
|||
auto setINT(bool value) -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
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 {
|
||||
|
||||
Interface* interface = nullptr;
|
||||
Settings settings;
|
||||
|
||||
Interface::Interface() {
|
||||
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;
|
||||
}
|
||||
#include "master-system.cpp"
|
||||
#include "game-gear.cpp"
|
||||
|
||||
}
|
||||
|
|
|
@ -8,20 +8,56 @@ struct ID {
|
|||
};
|
||||
|
||||
struct Port { enum : uint {
|
||||
Hardware,
|
||||
Controller1,
|
||||
Controller2,
|
||||
};};
|
||||
|
||||
struct Device { enum : uint {
|
||||
None,
|
||||
MasterSystemControls,
|
||||
GameGearControls,
|
||||
Gamepad,
|
||||
};};
|
||||
};
|
||||
|
||||
struct Interface : Emulator::Interface {
|
||||
struct MasterSystemInterface : Emulator::Interface {
|
||||
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 title() -> string override;
|
||||
|
@ -41,7 +77,6 @@ struct Interface : Emulator::Interface {
|
|||
|
||||
auto connect(uint port, uint device) -> void override;
|
||||
auto power() -> void override;
|
||||
auto reset() -> void override;
|
||||
auto run() -> void override;
|
||||
|
||||
auto serialize() -> serializer override;
|
||||
|
@ -53,11 +88,11 @@ struct Interface : Emulator::Interface {
|
|||
};
|
||||
|
||||
struct Settings {
|
||||
uint hardware = 0;
|
||||
uint controllerPort1 = 0;
|
||||
uint controllerPort2 = 0;
|
||||
};
|
||||
|
||||
extern Interface* interface;
|
||||
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>
|
||||
|
||||
namespace MasterSystem {
|
||||
#define platform Emulator::platform
|
||||
using File = Emulator::File;
|
||||
using Scheduler = Emulator::Scheduler;
|
||||
extern Scheduler scheduler;
|
||||
struct Interface;
|
||||
|
||||
enum class Model : uint {
|
||||
MasterSystem,
|
||||
|
|
|
@ -19,9 +19,6 @@ auto PSG::step(uint clocks) -> void {
|
|||
}
|
||||
|
||||
auto PSG::power() -> void {
|
||||
}
|
||||
|
||||
auto PSG::reset() -> void {
|
||||
create(PSG::Enter, system.colorburst());
|
||||
stream = Emulator::audio.createStream(2, system.colorburst());
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ struct PSG : Thread {
|
|||
auto step(uint clocks) -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
};
|
||||
|
||||
extern PSG psg;
|
||||
|
|
|
@ -1,26 +1,40 @@
|
|||
Peripherals peripherals;
|
||||
|
||||
auto Peripherals::unload() -> void {
|
||||
delete hardware;
|
||||
delete controllerPort1;
|
||||
delete controllerPort2;
|
||||
hardware = nullptr;
|
||||
controllerPort1 = nullptr;
|
||||
controllerPort2 = nullptr;
|
||||
}
|
||||
|
||||
auto Peripherals::reset() -> void {
|
||||
connect(ID::Port::Hardware, settings.hardware);
|
||||
connect(ID::Port::Controller1, settings.controllerPort1);
|
||||
connect(ID::Port::Controller2, settings.controllerPort2);
|
||||
}
|
||||
|
||||
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) {
|
||||
settings.controllerPort1 = device;
|
||||
if(!system.loaded()) return;
|
||||
|
||||
delete controllerPort1;
|
||||
switch(device) { default:
|
||||
case ID::Device::None: controllerPort1 = new Controller(0); break;
|
||||
case ID::Device::Gamepad: controllerPort1 = new Gamepad(0); break;
|
||||
case ID::Device::None: controllerPort1 = new Controller(ID::Port::Controller1); 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;
|
||||
switch(device) { default:
|
||||
case ID::Device::None: controllerPort2 = new Controller(1); break;
|
||||
case ID::Device::Gamepad: controllerPort2 = new Gamepad(1); break;
|
||||
case ID::Device::None: controllerPort2 = new Controller(ID::Port::Controller2); 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(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();
|
||||
}
|
||||
|
||||
auto System::load(Model model) -> bool {
|
||||
auto System::load(Emulator::Interface* interface, Model model) -> bool {
|
||||
information = {};
|
||||
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();
|
||||
} else return false;
|
||||
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
if(!cartridge.load()) return false;
|
||||
|
||||
this->interface = interface;
|
||||
information.colorburst = Emulator::Constants::Colorburst::NTSC;
|
||||
return information.loaded = true;
|
||||
}
|
||||
|
@ -35,14 +36,6 @@ auto System::unload() -> void {
|
|||
}
|
||||
|
||||
auto System::power() -> void {
|
||||
cartridge.power();
|
||||
cpu.power();
|
||||
vdp.power();
|
||||
psg.power();
|
||||
reset();
|
||||
}
|
||||
|
||||
auto System::reset() -> void {
|
||||
Emulator::video.reset();
|
||||
Emulator::video.setInterface(interface);
|
||||
Emulator::video.setPalette();
|
||||
|
@ -51,10 +44,10 @@ auto System::reset() -> void {
|
|||
Emulator::audio.setInterface(interface);
|
||||
|
||||
scheduler.reset();
|
||||
cartridge.reset();
|
||||
cpu.reset();
|
||||
vdp.reset();
|
||||
psg.reset();
|
||||
cartridge.power();
|
||||
cpu.power();
|
||||
vdp.power();
|
||||
psg.power();
|
||||
scheduler.primary(cpu);
|
||||
|
||||
peripherals.reset();
|
||||
|
|
|
@ -5,14 +5,15 @@ struct System {
|
|||
|
||||
auto run() -> void;
|
||||
|
||||
auto load(Model model) -> bool;
|
||||
auto load(Emulator::Interface* interface, Model model) -> bool;
|
||||
auto save() -> void;
|
||||
auto unload() -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
private:
|
||||
Emulator::Interface* interface = nullptr;
|
||||
|
||||
struct Information {
|
||||
bool loaded = false;
|
||||
Model model = Model::MasterSystem;
|
||||
|
@ -26,6 +27,7 @@ struct Peripherals {
|
|||
auto reset() -> void;
|
||||
auto connect(uint port, uint device) -> void;
|
||||
|
||||
Controller* hardware = nullptr;
|
||||
Controller* controllerPort1 = nullptr;
|
||||
Controller* controllerPort2 = nullptr;
|
||||
};
|
||||
|
|
|
@ -51,9 +51,6 @@ auto VDP::Background::run() -> void {
|
|||
}
|
||||
|
||||
auto VDP::Background::power() -> void {
|
||||
}
|
||||
|
||||
auto VDP::Background::reset() -> void {
|
||||
memory::fill(&state, sizeof(State));
|
||||
memory::fill(&output, sizeof(Output));
|
||||
}
|
||||
|
|
|
@ -50,7 +50,10 @@ auto VDP::data(uint8 data) -> void {
|
|||
if(io.code <= 2) {
|
||||
vram[io.address++] = data;
|
||||
} 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::reset() -> void {
|
||||
memory::fill(&state, sizeof(State));
|
||||
memory::fill(&output, sizeof(Output));
|
||||
}
|
||||
|
|
|
@ -29,19 +29,20 @@ auto VDP::main() -> void {
|
|||
sprite.scanline();
|
||||
|
||||
//684 clocks/scanline
|
||||
uint y = io.vcounter;
|
||||
for(uint x : range(256)) {
|
||||
background.run();
|
||||
sprite.run();
|
||||
step(2);
|
||||
|
||||
uint6 color = cram[io.backdropColor];
|
||||
uint12 color = palette(io.backdropColor);
|
||||
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) {
|
||||
color = cram[16 | sprite.output.color];
|
||||
color = palette(16 | sprite.output.color);
|
||||
}
|
||||
if(x <= 7 && io.leftClip) color = cram[io.backdropColor];
|
||||
if(!io.displayEnable || io.vcounter >= vlines()) color = 0;
|
||||
if(x <= 7 && io.leftClip) color = palette(io.backdropColor);
|
||||
if(!io.displayEnable || y >= vlines()) color = 0;
|
||||
buffer[io.vcounter * 256 + x] = color;
|
||||
}
|
||||
step(172);
|
||||
|
@ -65,9 +66,15 @@ auto VDP::step(uint clocks) -> void {
|
|||
}
|
||||
|
||||
auto VDP::refresh() -> void {
|
||||
if(system.model() == Model::MasterSystem) {
|
||||
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 {
|
||||
if(io.lines240) return 240;
|
||||
if(io.lines224) return 224;
|
||||
|
@ -79,17 +86,24 @@ auto VDP::vblank() -> bool {
|
|||
}
|
||||
|
||||
auto VDP::power() -> void {
|
||||
background.power();
|
||||
sprite.power();
|
||||
}
|
||||
|
||||
auto VDP::reset() -> void {
|
||||
create(VDP::Enter, system.colorburst() * 15.0 / 5.0);
|
||||
|
||||
memory::fill(&io, sizeof(IO));
|
||||
|
||||
background.reset();
|
||||
sprite.reset();
|
||||
background.power();
|
||||
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 power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
//io.cpp
|
||||
auto vcounter() -> uint8;
|
||||
|
@ -28,7 +27,6 @@ struct VDP : Thread {
|
|||
auto run() -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
struct State {
|
||||
uint x;
|
||||
|
@ -48,7 +46,6 @@ struct VDP : Thread {
|
|||
auto run() -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
struct Object {
|
||||
uint8 x;
|
||||
|
@ -69,9 +66,11 @@ struct VDP : Thread {
|
|||
} sprite;
|
||||
|
||||
private:
|
||||
auto palette(uint5 index) -> uint12;
|
||||
|
||||
uint32 buffer[256 * 262];
|
||||
uint8 vram[0x4000];
|
||||
uint8 cram[0x20];
|
||||
uint8 cram[0x40]; //MS = 0x20, GG = 0x40
|
||||
|
||||
struct IO {
|
||||
uint vcounter; //vertical counter
|
||||
|
|
|
@ -7,11 +7,11 @@ Cartridge cartridge;
|
|||
auto Cartridge::load() -> bool {
|
||||
information = {};
|
||||
|
||||
if(auto pathID = interface->load(ID::PCEngine, "PC Engine", "pce")) {
|
||||
if(auto pathID = platform->load(ID::PCEngine, "PC Engine", "pce")) {
|
||||
information.pathID = pathID();
|
||||
} 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();
|
||||
} else return false;
|
||||
|
||||
|
@ -23,7 +23,7 @@ auto Cartridge::load() -> bool {
|
|||
if(rom.size) {
|
||||
rom.data = new uint8[rom.size]();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ auto Cartridge::load() -> bool {
|
|||
if(ram.size) {
|
||||
ram.data = new uint8[ram.size]();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ auto Cartridge::save() -> void {
|
|||
auto document = BML::unserialize(information.manifest);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,13 @@ auto CPU::Enter() -> void {
|
|||
}
|
||||
|
||||
auto CPU::main() -> void {
|
||||
#if 1
|
||||
static uint counter = 0;
|
||||
if(++counter < 10) {
|
||||
print(disassemble(r.pc), "\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
instruction();
|
||||
}
|
||||
|
||||
|
@ -24,4 +31,20 @@ auto CPU::power() -> void {
|
|||
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 {
|
||||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
auto step(uint clocks) -> void;
|
||||
auto step(uint clocks) -> void override;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
|
@ -2,12 +2,9 @@
|
|||
|
||||
namespace PCEngine {
|
||||
|
||||
Interface* interface = nullptr;
|
||||
Settings settings;
|
||||
|
||||
Interface::Interface() {
|
||||
interface = this;
|
||||
|
||||
information.manufacturer = "NEC";
|
||||
information.name = "PC Engine";
|
||||
information.overscan = true;
|
||||
|
@ -80,7 +77,7 @@ auto Interface::loaded() -> bool {
|
|||
}
|
||||
|
||||
auto Interface::load(uint id) -> bool {
|
||||
if(id == ID::PCEngine) return system.load();
|
||||
if(id == ID::PCEngine) return system.load(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,6 @@ struct Settings {
|
|||
uint controllerPort = 0;
|
||||
};
|
||||
|
||||
extern Interface* interface;
|
||||
extern Settings settings;
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <processor/huc6280/huc6280.hpp>
|
||||
|
||||
namespace PCEngine {
|
||||
#define platform Emulator::platform
|
||||
using File = Emulator::File;
|
||||
using Scheduler = Emulator::Scheduler;
|
||||
extern Scheduler scheduler;
|
||||
|
|
|
@ -10,16 +10,17 @@ auto System::run() -> void {
|
|||
if(scheduler.enter() == Scheduler::Event::Frame) vdc.refresh();
|
||||
}
|
||||
|
||||
auto System::load() -> bool {
|
||||
auto System::load(Emulator::Interface* interface) -> bool {
|
||||
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();
|
||||
} else return false;
|
||||
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
if(!cartridge.load()) return false;
|
||||
|
||||
this->interface = interface;
|
||||
information.colorburst = Emulator::Constants::Colorburst::NTSC;
|
||||
return information.loaded = true;
|
||||
}
|
||||
|
|
|
@ -4,13 +4,15 @@ struct System {
|
|||
|
||||
auto run() -> void;
|
||||
|
||||
auto load() -> bool;
|
||||
auto load(Emulator::Interface*) -> bool;
|
||||
auto save() -> void;
|
||||
auto unload() -> void;
|
||||
|
||||
auto power() -> void;
|
||||
|
||||
private:
|
||||
Emulator::Interface* interface = nullptr;
|
||||
|
||||
struct Information {
|
||||
bool loaded = false;
|
||||
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 {
|
||||
|
||||
#define L lastCycle();
|
||||
#include "memory.cpp"
|
||||
#include "instruction.cpp"
|
||||
#include "instructions.cpp"
|
||||
#include "disassembler.cpp"
|
||||
#undef L
|
||||
|
||||
auto HuC6280::power() -> void {
|
||||
}
|
||||
|
||||
auto HuC6280::instruction() -> void {
|
||||
step(1);
|
||||
r.a = 0x00;
|
||||
r.x = 0x00;
|
||||
r.y = 0x00;
|
||||
r.s = 0x00;
|
||||
r.pc = 0x0000;
|
||||
r.p = 0x00;
|
||||
r.mdr = 0x00;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,9 +6,56 @@ namespace Processor {
|
|||
|
||||
struct HuC6280 {
|
||||
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;
|
||||
|
||||
//memory.cpp
|
||||
auto io() -> uint8;
|
||||
auto opcode() -> uint8;
|
||||
auto operand() -> uint8;
|
||||
|
||||
//instruction.cpp
|
||||
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 {
|
||||
information = Information();
|
||||
has = Has();
|
||||
information = {};
|
||||
has = {};
|
||||
|
||||
if(auto pathID = interface->load(ID::SuperFamicom, "Super Famicom", "sfc")) {
|
||||
if(auto pathID = platform->load(ID::SuperFamicom, "Super Famicom", "sfc")) {
|
||||
information.pathID = pathID();
|
||||
} 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();
|
||||
} else return false;
|
||||
auto document = BML::unserialize(information.manifest.cartridge);
|
||||
|
@ -99,7 +99,7 @@ auto Cartridge::loadGameBoy() -> 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();
|
||||
} else return false;
|
||||
loadBSMemory(BML::unserialize(information.manifest.bsMemory));
|
||||
|
@ -107,7 +107,7 @@ auto Cartridge::loadBSMemory() -> 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();
|
||||
} else return false;
|
||||
loadSufamiTurboA(BML::unserialize(information.manifest.sufamiTurboA));
|
||||
|
@ -115,7 +115,7 @@ auto Cartridge::loadSufamiTurboA() -> 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();
|
||||
} else return false;
|
||||
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;
|
||||
|
||||
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();
|
||||
loadBSMemory();
|
||||
}
|
||||
}
|
||||
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();
|
||||
loadSufamiTurboA();
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ auto Cartridge::loadSufamiTurboA(Markup::Node node) -> void {
|
|||
loadMemory(sufamiturboA.ram, node["board/ram"], File::Optional, sufamiturboA.pathID);
|
||||
|
||||
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();
|
||||
loadSufamiTurboB();
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ auto Cartridge::loadSufamiTurbo(Markup::Node node, bool slot) -> void {
|
|||
|
||||
auto Cartridge::loadNSS(Markup::Node node) -> void {
|
||||
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});
|
||||
}
|
||||
|
@ -182,13 +182,13 @@ auto Cartridge::loadSuperFX(Markup::Node node) -> void {
|
|||
auto Cartridge::loadARMDSP(Markup::Node node) -> void {
|
||||
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();
|
||||
}
|
||||
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();
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -208,10 +208,10 @@ auto Cartridge::loadHitachiDSP(Markup::Node node, uint roms) -> void {
|
|||
for(auto& word : hitachidsp.dataROM) word = 0x000000;
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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::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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -256,7 +256,7 @@ auto Cartridge::loadNECDSP(Markup::Node node) -> void {
|
|||
auto Cartridge::loadEpsonRTC(Markup::Node node) -> void {
|
||||
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};
|
||||
for(auto& byte : data) fp->read();
|
||||
epsonrtc.load(data);
|
||||
|
@ -268,7 +268,7 @@ auto Cartridge::loadEpsonRTC(Markup::Node node) -> void {
|
|||
auto Cartridge::loadSharpRTC(Markup::Node node) -> void {
|
||||
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};
|
||||
for(auto& byte : data) fp->read();
|
||||
sharprtc.load(data);
|
||||
|
@ -322,7 +322,7 @@ auto Cartridge::loadMemory(MappedRAM& ram, Markup::Node node, bool required, may
|
|||
auto name = node["name"].text();
|
||||
auto size = node["size"].natural();
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ auto Cartridge::saveSuperFX(Markup::Node node) -> void {
|
|||
auto Cartridge::saveARMDSP(Markup::Node node) -> void {
|
||||
if(!node["ram/volatile"]) {
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ auto Cartridge::saveHitachiDSP(Markup::Node node) -> void {
|
|||
|
||||
if(!node["dram/volatile"]) {
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ auto Cartridge::saveNECDSP(Markup::Node node) -> void {
|
|||
if(!node["dram/volatile"]) {
|
||||
uint size = necdsp.revision == NECDSP::Revision::uPD7725 ? 256 : 2048;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ auto Cartridge::saveNECDSP(Markup::Node node) -> void {
|
|||
auto Cartridge::saveEpsonRTC(Markup::Node node) -> void {
|
||||
if(!node["ram/volatile"]) {
|
||||
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};
|
||||
epsonrtc.save(data);
|
||||
fp->write(data, 16);
|
||||
|
@ -101,7 +101,7 @@ auto Cartridge::saveEpsonRTC(Markup::Node node) -> void {
|
|||
auto Cartridge::saveSharpRTC(Markup::Node node) -> void {
|
||||
if(!node["ram/volatile"]) {
|
||||
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};
|
||||
sharprtc.save(data);
|
||||
fp->write(data, 16);
|
||||
|
@ -129,7 +129,7 @@ auto Cartridge::saveMemory(MappedRAM& memory, Markup::Node node, maybe<uint> id)
|
|||
if(!node || node["volatile"]) return;
|
||||
auto name = node["name"].text();
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ Gamepad::Gamepad(bool port) : Controller(port) {
|
|||
|
||||
auto Gamepad::data() -> uint2 {
|
||||
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
|
||||
switch(counter++) {
|
||||
|
@ -32,17 +32,17 @@ auto Gamepad::latch(bool data) -> void {
|
|||
counter = 0;
|
||||
|
||||
if(latched == 0) {
|
||||
b = interface->inputPoll(port, ID::Device::Gamepad, B);
|
||||
y = interface->inputPoll(port, ID::Device::Gamepad, Y);
|
||||
select = interface->inputPoll(port, ID::Device::Gamepad, Select);
|
||||
start = interface->inputPoll(port, ID::Device::Gamepad, Start);
|
||||
up = interface->inputPoll(port, ID::Device::Gamepad, Up);
|
||||
down = interface->inputPoll(port, ID::Device::Gamepad, Down);
|
||||
left = interface->inputPoll(port, ID::Device::Gamepad, Left);
|
||||
right = interface->inputPoll(port, ID::Device::Gamepad, Right);
|
||||
a = interface->inputPoll(port, ID::Device::Gamepad, A);
|
||||
x = interface->inputPoll(port, ID::Device::Gamepad, X);
|
||||
l = interface->inputPoll(port, ID::Device::Gamepad, L);
|
||||
r = interface->inputPoll(port, ID::Device::Gamepad, R);
|
||||
b = platform->inputPoll(port, ID::Device::Gamepad, B);
|
||||
y = platform->inputPoll(port, ID::Device::Gamepad, Y);
|
||||
select = platform->inputPoll(port, ID::Device::Gamepad, Select);
|
||||
start = platform->inputPoll(port, ID::Device::Gamepad, Start);
|
||||
up = platform->inputPoll(port, ID::Device::Gamepad, Up);
|
||||
down = platform->inputPoll(port, ID::Device::Gamepad, Down);
|
||||
left = platform->inputPoll(port, ID::Device::Gamepad, Left);
|
||||
right = platform->inputPoll(port, ID::Device::Gamepad, Right);
|
||||
a = platform->inputPoll(port, ID::Device::Gamepad, A);
|
||||
x = platform->inputPoll(port, ID::Device::Gamepad, X);
|
||||
l = platform->inputPoll(port, ID::Device::Gamepad, L);
|
||||
r = platform->inputPoll(port, ID::Device::Gamepad, R);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,8 +53,8 @@ auto Justifier::main() -> void {
|
|||
}
|
||||
|
||||
if(next < prev) {
|
||||
int nx1 = interface->inputPoll(port, device, 0 + X);
|
||||
int ny1 = interface->inputPoll(port, device, 0 + Y);
|
||||
int nx1 = platform->inputPoll(port, device, 0 + X);
|
||||
int ny1 = platform->inputPoll(port, device, 0 + Y);
|
||||
nx1 += player1.x;
|
||||
ny1 += player1.y;
|
||||
player1.x = max(-16, min(256 + 16, nx1));
|
||||
|
@ -64,8 +64,8 @@ auto Justifier::main() -> void {
|
|||
}
|
||||
|
||||
if(next < prev && chained) {
|
||||
int nx2 = interface->inputPoll(port, device, 4 + X);
|
||||
int ny2 = interface->inputPoll(port, device, 4 + Y);
|
||||
int nx2 = platform->inputPoll(port, device, 4 + X);
|
||||
int ny2 = platform->inputPoll(port, device, 4 + Y);
|
||||
nx2 += player2.x;
|
||||
ny2 += player2.y;
|
||||
player2.x = max(-16, min(256 + 16, nx2));
|
||||
|
@ -83,13 +83,13 @@ auto Justifier::data() -> uint2 {
|
|||
if(counter >= 32) return 1;
|
||||
|
||||
if(counter == 0) {
|
||||
player1.trigger = interface->inputPoll(port, device, 0 + Trigger);
|
||||
player1.start = interface->inputPoll(port, device, 0 + Start);
|
||||
player1.trigger = platform->inputPoll(port, device, 0 + Trigger);
|
||||
player1.start = platform->inputPoll(port, device, 0 + Start);
|
||||
}
|
||||
|
||||
if(counter == 0 && chained) {
|
||||
player2.trigger = interface->inputPoll(port, device, 4 + Trigger);
|
||||
player2.start = interface->inputPoll(port, device, 4 + Start);
|
||||
player2.trigger = platform->inputPoll(port, device, 4 + Trigger);
|
||||
player2.start = platform->inputPoll(port, device, 4 + Start);
|
||||
}
|
||||
|
||||
switch(counter++) {
|
||||
|
|
|
@ -64,10 +64,10 @@ auto Mouse::latch(bool data) -> void {
|
|||
latched = data;
|
||||
counter = 0;
|
||||
|
||||
x = interface->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
|
||||
l = interface->inputPoll(port, ID::Device::Mouse, Left);
|
||||
r = interface->inputPoll(port, ID::Device::Mouse, Right);
|
||||
x = platform->inputPoll(port, ID::Device::Mouse, X); //-n = left, 0 = center, +n = right
|
||||
y = platform->inputPoll(port, ID::Device::Mouse, Y); //-n = up, 0 = center, +n = down
|
||||
l = platform->inputPoll(port, ID::Device::Mouse, Left);
|
||||
r = platform->inputPoll(port, ID::Device::Mouse, Right);
|
||||
|
||||
dx = x < 0; //0 = right, 1 = left
|
||||
dy = y < 0; //0 = down, 1 = up
|
||||
|
|
|
@ -53,18 +53,18 @@ auto SuperMultitap::latch(bool data) -> void {
|
|||
if(latched == 0) {
|
||||
for(uint id : range(4)) {
|
||||
auto& gamepad = gamepads[id];
|
||||
gamepad.b = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + B);
|
||||
gamepad.y = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Y);
|
||||
gamepad.select = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Select);
|
||||
gamepad.start = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Start);
|
||||
gamepad.up = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Up);
|
||||
gamepad.down = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Down);
|
||||
gamepad.left = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Left);
|
||||
gamepad.right = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Right);
|
||||
gamepad.a = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + A);
|
||||
gamepad.x = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + X);
|
||||
gamepad.l = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + L);
|
||||
gamepad.r = interface->inputPoll(port, ID::Device::SuperMultitap, id * 12 + R);
|
||||
gamepad.b = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + B);
|
||||
gamepad.y = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Y);
|
||||
gamepad.select = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Select);
|
||||
gamepad.start = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Start);
|
||||
gamepad.up = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Up);
|
||||
gamepad.down = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Down);
|
||||
gamepad.left = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Left);
|
||||
gamepad.right = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Right);
|
||||
gamepad.a = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + A);
|
||||
gamepad.x = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + X);
|
||||
gamepad.l = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + L);
|
||||
gamepad.r = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + R);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,8 +53,8 @@ auto SuperScope::main() -> void {
|
|||
|
||||
if(next < prev) {
|
||||
//Vcounter wrapped back to zero; update cursor coordinates for start of new frame
|
||||
int nx = interface->inputPoll(port, ID::Device::SuperScope, X);
|
||||
int ny = interface->inputPoll(port, ID::Device::SuperScope, Y);
|
||||
int nx = platform->inputPoll(port, ID::Device::SuperScope, X);
|
||||
int ny = platform->inputPoll(port, ID::Device::SuperScope, Y);
|
||||
nx += x;
|
||||
ny += y;
|
||||
x = max(-16, min(256 + 16, nx));
|
||||
|
@ -74,7 +74,7 @@ auto SuperScope::data() -> uint2 {
|
|||
|
||||
if(counter == 0) {
|
||||
//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) {
|
||||
turbo = !turbo; //toggle state
|
||||
sprite->setPixels(turbo ? Resource::Sprite::CrosshairRed : Resource::Sprite::CrosshairGreen);
|
||||
|
@ -84,7 +84,7 @@ auto SuperScope::data() -> uint2 {
|
|||
//trigger is a button
|
||||
//if turbo is active, trigger is level sensitive; otherwise, it is edge sensitive
|
||||
trigger = false;
|
||||
bool newtrigger = interface->inputPoll(port, ID::Device::SuperScope, Trigger);
|
||||
bool newtrigger = platform->inputPoll(port, ID::Device::SuperScope, Trigger);
|
||||
if(newtrigger && (turbo || !triggerlock)) {
|
||||
trigger = true;
|
||||
triggerlock = true;
|
||||
|
@ -93,11 +93,11 @@ auto SuperScope::data() -> uint2 {
|
|||
}
|
||||
|
||||
//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 = false;
|
||||
bool newpause = interface->inputPoll(port, ID::Device::SuperScope, Pause);
|
||||
bool newpause = platform->inputPoll(port, ID::Device::SuperScope, Pause);
|
||||
if(newpause && !pauselock) {
|
||||
pause = true;
|
||||
pauselock = true;
|
||||
|
|
|
@ -84,7 +84,7 @@ auto MSU1::dataOpen() -> void {
|
|||
auto document = BML::unserialize(cartridge.information.manifest.cartridge);
|
||||
string name = document["board/msu1/rom/name"].text();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ auto MSU1::audioOpen() -> void {
|
|||
name = track["name"].text();
|
||||
break;
|
||||
}
|
||||
if(audioFile = interface->open(ID::SuperFamicom, name, File::Read)) {
|
||||
if(audioFile = platform->open(ID::SuperFamicom, name, File::Read)) {
|
||||
if(audioFile->size() >= 8) {
|
||||
uint32 header = audioFile->readm(4);
|
||||
if(header == 0x4d535531) { //"MSU1"
|
||||
|
|
|
@ -18,11 +18,11 @@ S21FX::S21FX() {
|
|||
ram[1] = 0xfc;
|
||||
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());
|
||||
}
|
||||
|
||||
string filename{interface->path(ID::SuperFamicom), "21fx.so"};
|
||||
string filename{platform->path(ID::SuperFamicom), "21fx.so"};
|
||||
if(link.openAbsolute(filename)) {
|
||||
linkInit = link.sym("fx_init");
|
||||
linkMain = link.sym("fx_main");
|
||||
|
|
|
@ -2,11 +2,9 @@
|
|||
|
||||
namespace SuperFamicom {
|
||||
|
||||
Interface* interface = nullptr;
|
||||
Settings settings;
|
||||
|
||||
Interface::Interface() {
|
||||
interface = this;
|
||||
system.init();
|
||||
|
||||
information.manufacturer = "Nintendo";
|
||||
|
@ -185,7 +183,7 @@ auto Interface::sha256() -> string {
|
|||
}
|
||||
|
||||
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::SufamiTurboA) return cartridge.loadSufamiTurboA();
|
||||
if(id == ID::SufamiTurboB) return cartridge.loadSufamiTurboB();
|
||||
|
@ -202,7 +200,7 @@ auto Interface::unload() -> void {
|
|||
}
|
||||
|
||||
auto Interface::connect(uint port, uint device) -> void {
|
||||
SuperFamicom::peripherals.connect(port, device);
|
||||
peripherals.connect(port, device);
|
||||
}
|
||||
|
||||
auto Interface::power() -> void {
|
||||
|
|
|
@ -81,7 +81,6 @@ struct Settings {
|
|||
bool random = true;
|
||||
};
|
||||
|
||||
extern Interface* interface;
|
||||
extern Settings settings;
|
||||
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#endif
|
||||
|
||||
namespace SuperFamicom {
|
||||
#define platform Emulator::platform
|
||||
using File = Emulator::File;
|
||||
using Scheduler = Emulator::Scheduler;
|
||||
using Cheat = Emulator::Cheat;
|
||||
|
|
|
@ -18,7 +18,7 @@ auto SMP::main() -> void {
|
|||
|
||||
auto SMP::load(Markup::Node node) -> bool {
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -24,8 +24,6 @@ auto System::runToSave() -> void {
|
|||
}
|
||||
|
||||
auto System::init() -> void {
|
||||
assert(interface != nullptr);
|
||||
|
||||
icd2.init();
|
||||
mcc.init();
|
||||
nss.init();
|
||||
|
@ -48,10 +46,10 @@ auto System::init() -> void {
|
|||
auto System::term() -> void {
|
||||
}
|
||||
|
||||
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();
|
||||
} else return false;
|
||||
|
||||
|
@ -93,6 +91,7 @@ auto System::load() -> bool {
|
|||
if(cartridge.has.SufamiTurboSlots) sufamiturboA.load(), sufamiturboB.load();
|
||||
|
||||
serializeInit();
|
||||
this->interface = interface;
|
||||
return information.loaded = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
struct Interface;
|
||||
|
||||
struct System {
|
||||
enum class Region : bool { NTSC = 0, PAL = 1 };
|
||||
|
||||
|
@ -12,7 +10,7 @@ struct System {
|
|||
|
||||
auto init() -> void;
|
||||
auto term() -> void;
|
||||
auto load() -> bool;
|
||||
auto load(Emulator::Interface*) -> bool;
|
||||
auto save() -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
|
@ -27,6 +25,8 @@ struct System {
|
|||
auto unserialize(serializer&) -> bool;
|
||||
|
||||
private:
|
||||
Emulator::Interface* interface = nullptr;
|
||||
|
||||
struct Information {
|
||||
string manifest;
|
||||
bool loaded = false;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name := higan
|
||||
flags += -DSFC_SUPERGAMEBOY
|
||||
#flags += -DSFC_SUPERGAMEBOY
|
||||
|
||||
include fc/GNUmakefile
|
||||
include sfc/GNUmakefile
|
||||
|
|
|
@ -17,15 +17,16 @@ Program::Program(string_vector args) {
|
|||
program = this;
|
||||
Application::onMain({&Program::main, this});
|
||||
|
||||
Emulator::platform = this;
|
||||
emulators.append(new Famicom::Interface);
|
||||
emulators.append(new SuperFamicom::Interface);
|
||||
emulators.append(new MasterSystem::Interface);
|
||||
emulators.append(new MasterSystem::MasterSystemInterface);
|
||||
emulators.append(new MegaDrive::Interface);
|
||||
emulators.append(new PCEngine::Interface);
|
||||
emulators.append(new GameBoy::Interface);
|
||||
emulators.append(new GameBoyAdvance::Interface);
|
||||
emulators.append(new MasterSystem::GameGearInterface);
|
||||
emulators.append(new WonderSwan::Interface);
|
||||
for(auto& emulator : emulators) emulator->bind = this;
|
||||
|
||||
new Presentation;
|
||||
presentation->setVisible();
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue