mirror of https://github.com/bsnes-emu/bsnes.git
Update to v094r39 release.
byuu says: Changelog: - SNES mid-scanline BGMODE fixes finally merged (can run atx2.zip{mode7.smc}+mtest(2).sfc properly now) - Makefile now discards all built-in rules and variables - switch on bool warning disabled for GCC now as well (was already disabled for Clang) - when loading a game, if any required files are missing, display a warning message box (manifest.bml, program.rom, bios.rom, etc) - when loading a game (or a game slot), if manifest.bml is missing, it will invoke icarus to try and generate it - if that fails (icarus is missing or the folder is bad), you will get a warning telling you that the manifest can't be loaded The warning prompt on missing files work for both games and the .sys folders and their files. For some reason, failing to load the DMG/CGB BIOS is causing a crash before I can display the modal dialog. I have no idea why, and the stack frame backtrace is junk. I also can't seem to abort the failed loading process. If I call Program::unloadMedia(), I get a nasty segfault. Again with a really nasty stack trace. So for now, it'll just end up sitting there emulating an empty ROM (solid black screen.) In time, I'd like to fix that too. Lastly, I need a better method than popen for Windows. popen is kind of ugly and flashes a console window for a brief second even if the application launched is linked with -mwindows. Not sure if there even is one (I need to read the stdout result, so CreateProcess may not work unless I do something nasty like "> %tmp%/temp") I'm also using the regular popen instead of _wpopen, so for this WIP, it won't work if your game folder has non-English letters in the path.
This commit is contained in:
parent
1b0b54a690
commit
0271d6a12b
|
@ -8,7 +8,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "094.38";
|
||||
static const string Version = "094.39";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -47,8 +47,8 @@ struct Interface {
|
|||
vector<Port> port;
|
||||
|
||||
struct Bind {
|
||||
virtual auto loadRequest(unsigned, string, string) -> void {}
|
||||
virtual auto loadRequest(unsigned, string) -> void {}
|
||||
virtual auto loadRequest(unsigned, string, string, bool) -> void {}
|
||||
virtual auto loadRequest(unsigned, string, bool) -> void {}
|
||||
virtual auto saveRequest(unsigned, string) -> void {}
|
||||
virtual auto videoColor(unsigned, uint16_t, uint16_t, uint16_t, uint16_t) -> uint32_t { return 0u; }
|
||||
virtual auto videoRefresh(const uint32_t*, const uint32_t*, unsigned, unsigned, unsigned) -> void {}
|
||||
|
@ -62,8 +62,8 @@ struct Interface {
|
|||
Bind* bind = nullptr;
|
||||
|
||||
//callback bindings (provided by user interface)
|
||||
auto loadRequest(unsigned id, string name, string type) -> void { return bind->loadRequest(id, name, type); }
|
||||
auto loadRequest(unsigned id, string path) -> void { return bind->loadRequest(id, path); }
|
||||
auto loadRequest(unsigned id, string name, string type, bool required) -> void { return bind->loadRequest(id, name, type, required); }
|
||||
auto loadRequest(unsigned id, string path, bool required) -> void { return bind->loadRequest(id, path, required); }
|
||||
auto saveRequest(unsigned id, string path) -> void { return bind->saveRequest(id, path); }
|
||||
auto videoColor(unsigned source, uint16_t alpha, uint16_t red, uint16_t green, uint16_t blue) -> uint32_t { return bind->videoColor(source, alpha, red, green, blue); }
|
||||
auto videoRefresh(const uint32_t* palette, const uint32_t* data, unsigned pitch, unsigned width, unsigned height) -> void { return bind->videoRefresh(palette, data, pitch, width, height); }
|
||||
|
|
|
@ -104,10 +104,10 @@ Board::Board(Markup::Node& document) {
|
|||
if(chrrom.size) chrrom.data = new uint8[chrrom.size]();
|
||||
if(chrram.size) chrram.data = new uint8[chrram.size]();
|
||||
|
||||
if(auto name = prom["name"].text()) interface->loadRequest(ID::ProgramROM, name);
|
||||
if(auto name = pram["name"].text()) interface->loadRequest(ID::ProgramRAM, name);
|
||||
if(auto name = crom["name"].text()) interface->loadRequest(ID::CharacterROM, name);
|
||||
if(auto name = cram["name"].text()) interface->loadRequest(ID::CharacterRAM, name);
|
||||
if(auto name = prom["name"].text()) interface->loadRequest(ID::ProgramROM, name, true);
|
||||
if(auto name = pram["name"].text()) interface->loadRequest(ID::ProgramRAM, name, false);
|
||||
if(auto name = crom["name"].text()) interface->loadRequest(ID::CharacterROM, name, true);
|
||||
if(auto name = cram["name"].text()) interface->loadRequest(ID::CharacterRAM, name, false);
|
||||
|
||||
if(auto name = pram["name"].text()) Famicom::cartridge.memory.append({ID::ProgramRAM, name});
|
||||
if(auto name = cram["name"].text()) Famicom::cartridge.memory.append({ID::CharacterRAM, name});
|
||||
|
|
|
@ -19,7 +19,7 @@ void Cartridge::main() {
|
|||
}
|
||||
|
||||
void Cartridge::load() {
|
||||
interface->loadRequest(ID::Manifest, "manifest.bml");
|
||||
interface->loadRequest(ID::Manifest, "manifest.bml", true);
|
||||
|
||||
Board::load(information.markup); //this call will set Cartridge::board if successful
|
||||
if(board == nullptr) return;
|
||||
|
|
|
@ -26,6 +26,8 @@ string Interface::sha256() {
|
|||
|
||||
unsigned Interface::group(unsigned id) {
|
||||
switch(id) {
|
||||
case ID::SystemManifest:
|
||||
return 0;
|
||||
case ID::Manifest:
|
||||
case ID::ProgramROM:
|
||||
case ID::ProgramRAM:
|
||||
|
@ -48,7 +50,13 @@ void Interface::save() {
|
|||
}
|
||||
|
||||
void Interface::load(unsigned id, const stream& stream) {
|
||||
if(id == ID::Manifest) cartridge.information.markup = stream.text();
|
||||
if(id == ID::SystemManifest) {
|
||||
system.information.manifest = stream.text();
|
||||
}
|
||||
|
||||
if(id == ID::Manifest) {
|
||||
cartridge.information.markup = stream.text();
|
||||
}
|
||||
|
||||
if(id == ID::ProgramROM) {
|
||||
stream.read(cartridge.board->prgrom.data, min(cartridge.board->prgrom.size, stream.size()));
|
||||
|
|
|
@ -9,6 +9,8 @@ struct ID {
|
|||
};
|
||||
|
||||
enum : unsigned {
|
||||
SystemManifest,
|
||||
|
||||
Manifest,
|
||||
ProgramROM,
|
||||
ProgramRAM,
|
||||
|
|
|
@ -42,8 +42,8 @@ void System::runthreadtosave() {
|
|||
}
|
||||
|
||||
void System::load() {
|
||||
string manifest = string::read({interface->path(ID::System), "manifest.bml"});
|
||||
auto document = BML::unserialize(manifest);
|
||||
interface->loadRequest(ID::SystemManifest, "manifest.bml", true);
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
|
||||
serialize_init();
|
||||
}
|
||||
|
|
|
@ -17,6 +17,10 @@ struct System {
|
|||
void serialize_all(serializer&);
|
||||
void serialize_init();
|
||||
unsigned serialize_size;
|
||||
|
||||
struct Information {
|
||||
string manifest;
|
||||
} information;
|
||||
};
|
||||
|
||||
extern System system;
|
||||
|
|
|
@ -35,7 +35,7 @@ void Cartridge::load(System::Revision revision) {
|
|||
|
||||
system.revision = revision; //needed for ID::Manifest to return correct group ID
|
||||
if(revision != System::Revision::SuperGameBoy) {
|
||||
interface->loadRequest(ID::Manifest, "manifest.bml");
|
||||
interface->loadRequest(ID::Manifest, "manifest.bml", true);
|
||||
}
|
||||
|
||||
information.mapper = Mapper::Unknown;
|
||||
|
@ -74,8 +74,8 @@ void Cartridge::load(System::Revision revision) {
|
|||
|
||||
//Super Game Boy core loads memory from Super Famicom core
|
||||
if(revision != System::Revision::SuperGameBoy) {
|
||||
if(auto name = rom["name"].text()) interface->loadRequest(ID::ROM, name);
|
||||
if(auto name = ram["name"].text()) interface->loadRequest(ID::RAM, name);
|
||||
if(auto name = rom["name"].text()) interface->loadRequest(ID::ROM, name, true);
|
||||
if(auto name = ram["name"].text()) interface->loadRequest(ID::RAM, name, false);
|
||||
if(auto name = ram["name"].text()) memory.append({ID::RAM, name});
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ string Interface::sha256() {
|
|||
|
||||
unsigned Interface::group(unsigned id) {
|
||||
switch(id) {
|
||||
case ID::SystemManifest:
|
||||
case ID::GameBoyBootROM:
|
||||
case ID::SuperGameBoyBootROM:
|
||||
case ID::GameBoyColorBootROM:
|
||||
|
@ -68,6 +69,10 @@ void Interface::save() {
|
|||
}
|
||||
|
||||
void Interface::load(unsigned id, const stream& stream) {
|
||||
if(id == ID::SystemManifest) {
|
||||
system.information.manifest = stream.text();
|
||||
}
|
||||
|
||||
if(id == ID::GameBoyBootROM) {
|
||||
stream.read(system.bootROM.dmg, min( 256u, stream.size()));
|
||||
}
|
||||
|
@ -80,7 +85,9 @@ void Interface::load(unsigned id, const stream& stream) {
|
|||
stream.read(system.bootROM.cgb, min(2048u, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::Manifest) cartridge.information.markup = stream.text();
|
||||
if(id == ID::Manifest) {
|
||||
cartridge.information.markup = stream.text();
|
||||
}
|
||||
|
||||
if(id == ID::ROM) {
|
||||
stream.read(cartridge.romdata, min(cartridge.romsize, stream.size()));
|
||||
|
|
|
@ -11,6 +11,7 @@ struct ID {
|
|||
};
|
||||
|
||||
enum : unsigned {
|
||||
SystemManifest,
|
||||
GameBoyBootROM,
|
||||
SuperGameBoyBootROM,
|
||||
GameBoyColorBootROM,
|
||||
|
|
|
@ -49,16 +49,14 @@ void System::load(Revision revision) {
|
|||
serialize_init();
|
||||
if(revision == Revision::SuperGameBoy) return; //Super Famicom core loads boot ROM for SGB
|
||||
|
||||
string manifest = string::read({interface->path(ID::System), "manifest.bml"});
|
||||
auto document = BML::unserialize(manifest);
|
||||
interface->loadRequest(ID::SystemManifest, "manifest.bml", true);
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
|
||||
auto bootROM = document["system/cpu/rom/name"].text();
|
||||
interface->loadRequest(
|
||||
revision == Revision::GameBoy ? ID::GameBoyBootROM : ID::GameBoyColorBootROM,
|
||||
bootROM
|
||||
);
|
||||
if(!file::exists({interface->path(ID::System), bootROM})) {
|
||||
interface->notify("Error: required Game Boy firmware boot.rom not found.\n");
|
||||
if(auto bootROM = document["system/cpu/rom/name"].text()) {
|
||||
interface->loadRequest(
|
||||
revision == Revision::GameBoy ? ID::GameBoyBootROM : ID::GameBoyColorBootROM,
|
||||
bootROM, true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,10 @@ struct System {
|
|||
void serialize_init();
|
||||
|
||||
System();
|
||||
|
||||
struct Information {
|
||||
string manifest;
|
||||
} information;
|
||||
};
|
||||
|
||||
#include <gb/interface/interface.hpp>
|
||||
|
|
|
@ -12,7 +12,7 @@ string Cartridge::title() {
|
|||
}
|
||||
|
||||
void Cartridge::load() {
|
||||
interface->loadRequest(ID::Manifest, "manifest.bml");
|
||||
interface->loadRequest(ID::Manifest, "manifest.bml", true);
|
||||
|
||||
auto document = BML::unserialize(information.markup);
|
||||
information.title = document["information/title"].text();
|
||||
|
@ -20,7 +20,7 @@ void Cartridge::load() {
|
|||
unsigned rom_size = 0;
|
||||
if(document["cartridge/rom"]) {
|
||||
auto info = document["cartridge/rom"];
|
||||
interface->loadRequest(ID::ROM, info["name"].text());
|
||||
interface->loadRequest(ID::ROM, info["name"].text(), true);
|
||||
rom_size = info["size"].decimal();
|
||||
for(unsigned addr = rom_size; addr < rom.size; addr++) {
|
||||
rom.data[addr] = rom.data[Bus::mirror(addr, rom_size)];
|
||||
|
@ -40,7 +40,7 @@ void Cartridge::load() {
|
|||
ram.mask = ram.size - 1;
|
||||
for(unsigned n = 0; n < ram.size; n++) ram.data[n] = 0xff;
|
||||
|
||||
interface->loadRequest(ID::RAM, info["name"].text());
|
||||
interface->loadRequest(ID::RAM, info["name"].text(), false);
|
||||
memory.append({ID::RAM, info["name"].text()});
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ void Cartridge::load() {
|
|||
eeprom.test = rom_size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
|
||||
for(unsigned n = 0; n < eeprom.size; n++) eeprom.data[n] = 0xff;
|
||||
|
||||
interface->loadRequest(ID::EEPROM, info["name"].text());
|
||||
interface->loadRequest(ID::EEPROM, info["name"].text(), false);
|
||||
memory.append({ID::EEPROM, info["name"].text()});
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ void Cartridge::load() {
|
|||
if(!flashrom.id && flashrom.size == 64 * 1024) flashrom.id = 0x1cc2;
|
||||
if(!flashrom.id && flashrom.size == 128 * 1024) flashrom.id = 0x09c2;
|
||||
|
||||
interface->loadRequest(ID::FlashROM, info["name"].text());
|
||||
interface->loadRequest(ID::FlashROM, info["name"].text(), false);
|
||||
memory.append({ID::FlashROM, info["name"].text()});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ bool Interface::loaded() {
|
|||
|
||||
unsigned Interface::group(unsigned id) {
|
||||
switch(id) {
|
||||
case ID::SystemManifest:
|
||||
case ID::BIOS:
|
||||
return ID::System;
|
||||
case ID::Manifest:
|
||||
|
@ -46,11 +47,17 @@ void Interface::save() {
|
|||
}
|
||||
|
||||
void Interface::load(unsigned id, const stream& stream) {
|
||||
if(id == ID::SystemManifest) {
|
||||
system.information.manifest = stream.text();
|
||||
}
|
||||
|
||||
if(id == ID::BIOS) {
|
||||
stream.read(bios.data, min(bios.size, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::Manifest) cartridge.information.markup = stream.text();
|
||||
if(id == ID::Manifest) {
|
||||
cartridge.information.markup = stream.text();
|
||||
}
|
||||
|
||||
if(id == ID::ROM) {
|
||||
stream.read(cartridge.rom.data, min(cartridge.rom.size, stream.size()));
|
||||
|
|
|
@ -9,6 +9,7 @@ struct ID {
|
|||
};
|
||||
|
||||
enum : unsigned {
|
||||
SystemManifest,
|
||||
BIOS,
|
||||
|
||||
Manifest,
|
||||
|
|
|
@ -24,13 +24,11 @@ void System::power() {
|
|||
}
|
||||
|
||||
void System::load() {
|
||||
string manifest = string::read({interface->path(ID::System), "manifest.bml"});
|
||||
auto document = BML::unserialize(manifest);
|
||||
interface->loadRequest(ID::SystemManifest, "manifest.bml", true);
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
|
||||
auto bios = document["system/cpu/rom/name"].text();
|
||||
interface->loadRequest(ID::BIOS, bios);
|
||||
if(!file::exists({interface->path(ID::System), bios})) {
|
||||
interface->notify("Error: required Game Boy Advance firmware bios.rom not found.\n");
|
||||
if(auto bios = document["system/cpu/rom/name"].text()) {
|
||||
interface->loadRequest(ID::BIOS, bios, true);
|
||||
}
|
||||
|
||||
serialize_init();
|
||||
|
|
|
@ -31,6 +31,10 @@ struct System {
|
|||
void serialize(serializer&);
|
||||
void serialize_all(serializer&);
|
||||
void serialize_init();
|
||||
|
||||
struct Information {
|
||||
string manifest;
|
||||
} information;
|
||||
};
|
||||
|
||||
extern BIOS bios;
|
||||
|
|
|
@ -1353,12 +1353,14 @@ struct mListViewItem : mObject {
|
|||
auto backgroundColor() const -> Color;
|
||||
auto cell(unsigned position) const -> ListViewCell;
|
||||
auto cells() const -> unsigned;
|
||||
auto checkable() const -> bool;
|
||||
auto checked() const -> bool;
|
||||
auto foregroundColor() const -> Color;
|
||||
auto remove() -> type& override;
|
||||
auto remove(sListViewCell cell) -> type&;
|
||||
auto selected() const -> bool;
|
||||
auto setBackgroundColor(Color color = {}) -> type&;
|
||||
auto setCheckable(bool checkable = true) -> type&;
|
||||
auto setChecked(bool checked = true) -> type&;
|
||||
auto setFocused() -> type& override;
|
||||
auto setForegroundColor(Color color = {}) -> type&;
|
||||
|
@ -1369,6 +1371,7 @@ struct mListViewItem : mObject {
|
|||
struct State {
|
||||
Color backgroundColor;
|
||||
vector<sListViewCell> cells;
|
||||
bool checkable = true;
|
||||
bool checked = false;
|
||||
Color foregroundColor;
|
||||
bool selected = false;
|
||||
|
|
|
@ -502,11 +502,13 @@ struct ListViewItem : sListViewItem {
|
|||
auto backgroundColor() const { return self().backgroundColor(); }
|
||||
auto cell(unsigned position) const { return self().cell(position); }
|
||||
auto cells() const { return self().cells(); }
|
||||
auto checkable() const { return self().checkable(); }
|
||||
auto checked() const { return self().checked(); }
|
||||
auto foregroundColor() const { return self().foregroundColor(); }
|
||||
auto remove(sListViewCell cell) { return self().remove(cell), *this; }
|
||||
auto selected() const { return self().selected(); }
|
||||
auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; }
|
||||
auto setCheckable(bool checkable = true) { return self().setCheckable(checkable), *this; }
|
||||
auto setChecked(bool checked = true) { return self().setChecked(checked), *this; }
|
||||
auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; }
|
||||
auto setSelected(bool selected = true) { return self().setSelected(selected), *this; }
|
||||
|
|
|
@ -26,8 +26,12 @@ auto mListViewItem::cells() const -> unsigned {
|
|||
return state.cells.size();
|
||||
}
|
||||
|
||||
auto mListViewItem::checkable() const -> bool {
|
||||
return state.checkable;
|
||||
}
|
||||
|
||||
auto mListViewItem::checked() const -> bool {
|
||||
return state.checked;
|
||||
return state.checkable && state.checked;
|
||||
}
|
||||
|
||||
auto mListViewItem::foregroundColor() const -> Color {
|
||||
|
@ -59,6 +63,12 @@ auto mListViewItem::setBackgroundColor(Color color) -> type& {
|
|||
return *this;
|
||||
}
|
||||
|
||||
auto mListViewItem::setCheckable(bool checkable) -> type& {
|
||||
state.checkable = checkable;
|
||||
signal(setCheckable, checkable);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto mListViewItem::setChecked(bool checked) -> type& {
|
||||
state.checked = checked;
|
||||
signal(setChecked, checked);
|
||||
|
|
|
@ -163,7 +163,6 @@ auto BrowserDialogWindow::setPath(string path) -> void {
|
|||
|
||||
view.reset();
|
||||
view.append(ListViewColumn().setExpandable());
|
||||
view.append(ListViewColumn().setForegroundColor({192, 128, 128}));
|
||||
|
||||
auto contents = directory::icontents(path);
|
||||
bool folderMode = state.action == "openFolder";
|
||||
|
@ -175,7 +174,6 @@ auto BrowserDialogWindow::setPath(string path) -> void {
|
|||
|
||||
view.append(ListViewItem()
|
||||
.append(ListViewCell().setText(content).setIcon(Icon::Emblem::Folder))
|
||||
.append(ListViewCell().setText(octal(file_system_object::mode({path, content}) & 0777, 3L)))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -186,7 +184,6 @@ auto BrowserDialogWindow::setPath(string path) -> void {
|
|||
|
||||
view.append(ListViewItem()
|
||||
.append(ListViewCell().setText(content).setIcon(folderMode ? Icon::Action::Open : Icon::Emblem::File))
|
||||
.append(ListViewCell().setText(octal(file_system_object::mode({path, content}) & 0777, 3L)))
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ auto pListViewColumn::construct() -> void {
|
|||
gtkCellToggle = gtk_cell_renderer_toggle_new();
|
||||
gtk_tree_view_column_pack_start(gtkColumn, gtkCellToggle, false);
|
||||
gtk_tree_view_column_set_attributes(gtkColumn, gtkCellToggle, "active", 0, nullptr);
|
||||
gtk_tree_view_column_set_cell_data_func(gtkColumn, GTK_CELL_RENDERER(gtkCellToggle), (GtkTreeCellDataFunc)ListView_cellRendererToggleDataFunc, (gpointer)_parent(), nullptr);
|
||||
}
|
||||
|
||||
gtkCellIcon = gtk_cell_renderer_pixbuf_new();
|
||||
|
|
|
@ -17,6 +17,9 @@ auto pListViewItem::remove(sListViewCell cell) -> void {
|
|||
auto pListViewItem::setBackgroundColor(Color color) -> void {
|
||||
}
|
||||
|
||||
auto pListViewItem::setCheckable(bool checkable) -> void {
|
||||
}
|
||||
|
||||
auto pListViewItem::setChecked(bool checked) -> void {
|
||||
if(auto parent = _parent()) {
|
||||
gtk_list_store_set(parent->gtkListStore, >kIter, 0, checked, -1);
|
||||
|
|
|
@ -8,6 +8,7 @@ struct pListViewItem : pObject {
|
|||
auto append(sListViewCell cell) -> void;
|
||||
auto remove(sListViewCell cell) -> void;
|
||||
auto setBackgroundColor(Color color) -> void;
|
||||
auto setCheckable(bool checkable) -> void;
|
||||
auto setChecked(bool checked) -> void;
|
||||
auto setFocused() -> void;
|
||||
auto setForegroundColor(Color color) -> void;
|
||||
|
|
|
@ -9,6 +9,8 @@ static auto ListView_edit(GtkCellRendererText* renderer, const char* path, const
|
|||
static auto ListView_headerActivate(GtkTreeViewColumn* column, pListView* p) -> void { return p->_doHeaderActivate(column); }
|
||||
static auto ListView_mouseMoveEvent(GtkWidget*, GdkEvent*, pListView* p) -> signed { return p->_doMouseMove(); }
|
||||
static auto ListView_popup(GtkTreeView*, pListView* p) -> void { return p->_doContext(); }
|
||||
|
||||
static auto ListView_cellRendererToggleDataFunc(GtkTreeViewColumn* column, GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter, pListView* p) -> void { return p->_doCellRendererToggleDataFunc(renderer, iter); }
|
||||
static auto ListView_toggle(GtkCellRendererToggle*, const char* path, pListView* p) -> void { return p->_doToggle(path); }
|
||||
|
||||
auto pListView::construct() -> void {
|
||||
|
@ -276,6 +278,15 @@ auto pListView::_doActivate() -> void {
|
|||
if(!locked()) self().doActivate();
|
||||
}
|
||||
|
||||
auto pListView::_doCellRendererToggleDataFunc(GtkCellRenderer* renderer, GtkTreeIter* iter) -> void {
|
||||
auto path = gtk_tree_model_get_string_from_iter(gtkTreeModel, iter);
|
||||
auto row = decimal(path);
|
||||
if(auto item = self().item(row)) {
|
||||
gtk_cell_renderer_set_visible(renderer, state().checkable && item->state.checkable);
|
||||
}
|
||||
g_free(path);
|
||||
}
|
||||
|
||||
auto pListView::_doChange() -> void {
|
||||
if(!locked()) _updateSelected();
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ struct pListView : pWidget {
|
|||
auto _columnWidth(unsigned column) -> unsigned;
|
||||
auto _createModel() -> void;
|
||||
auto _doActivate() -> void;
|
||||
auto _doCellRendererToggleDataFunc(GtkCellRenderer* renderer, GtkTreeIter* iter) -> void;
|
||||
auto _doChange() -> void;
|
||||
auto _doContext() -> void;
|
||||
auto _doEdit(GtkCellRendererText* renderer, const char* path, const char* text) -> void;
|
||||
|
|
|
@ -18,7 +18,7 @@ auto pCheckLabel::destruct() -> void {
|
|||
DestroyWindow(hwnd);
|
||||
}
|
||||
|
||||
auto pCheckLabel::minimumSize() -> Size {
|
||||
auto pCheckLabel::minimumSize() const -> Size {
|
||||
auto size = pFont::size(hfont, state().text);
|
||||
return {size.width() + 20, size.height() + 4};
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace hiro {
|
|||
struct pCheckLabel : pWidget {
|
||||
Declare(CheckLabel, Widget)
|
||||
|
||||
auto minimumSize() -> Size;
|
||||
auto minimumSize() const -> Size override;
|
||||
auto setChecked(bool checked) -> void;
|
||||
auto setText(const string& text) -> void;
|
||||
|
||||
|
|
|
@ -17,6 +17,9 @@ auto pListViewItem::remove(sListViewCell cell) -> void {
|
|||
auto pListViewItem::setBackgroundColor(Color color) -> void {
|
||||
}
|
||||
|
||||
auto pListViewItem::setCheckable(bool checkable) -> void {
|
||||
}
|
||||
|
||||
auto pListViewItem::setChecked(bool checked) -> void {
|
||||
if(auto parent = _parent()) {
|
||||
parent->lock();
|
||||
|
|
|
@ -8,6 +8,7 @@ struct pListViewItem : pObject {
|
|||
auto append(sListViewCell cell) -> void;
|
||||
auto remove(sListViewCell cell) -> void;
|
||||
auto setBackgroundColor(Color color) -> void;
|
||||
auto setCheckable(bool checkable) -> void;
|
||||
auto setChecked(bool checked) -> void;
|
||||
auto setFocused() -> void;
|
||||
auto setForegroundColor(Color color) -> void;
|
||||
|
|
|
@ -275,7 +275,7 @@ auto pListView::onCustomDraw(LPARAM lparam) -> LRESULT {
|
|||
HBRUSH brush = CreateSolidBrush(selected ? GetSysColor(COLOR_HIGHLIGHT) : CreateRGB(_backgroundColor(row, column)));
|
||||
FillRect(hdc, &rc, brush);
|
||||
DeleteObject(brush);
|
||||
if(state().checkable && column == 0) {
|
||||
if(state().checkable && self().item(row).checkable() && column == 0) {
|
||||
if(auto htheme = OpenThemeData(hwnd, L"BUTTON")) {
|
||||
unsigned state = checked ? CBS_CHECKEDNORMAL : CBS_UNCHECKEDNORMAL;
|
||||
SIZE size;
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
# disable built-in rules and variables
|
||||
MAKEFLAGS := Rr
|
||||
.SUFFIXES:
|
||||
|
||||
[A-Z] = A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
|
||||
[a-z] = a b c d e f g h i j k l m n o p q r s t u v w x y z
|
||||
[0-9] = 0 1 2 3 4 5 6 7 8 9
|
||||
|
|
|
@ -37,11 +37,15 @@ namespace nall {
|
|||
#elif defined(__GNUC__)
|
||||
#define COMPILER_GCC
|
||||
auto Intrinsics::compiler() -> Compiler { return Compiler::GCC; }
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
|
||||
#pragma GCC diagnostic ignored "-Wpragmas"
|
||||
#pragma GCC diagnostic ignored "-Wswitch-bool"
|
||||
#elif defined(_MSC_VER)
|
||||
#define COMPILER_VISUALCPP
|
||||
auto Intrinsics::compiler() -> Compiler { return Compiler::VisualCPP; }
|
||||
|
||||
#pragma warning(disable:4996) //disable libc "deprecation" warnings
|
||||
#pragma warning(disable:4996) //libc "deprecation" warnings
|
||||
#else
|
||||
#warning "unable to detect compiler"
|
||||
#define COMPILER_UNKNOWN
|
||||
|
|
|
@ -340,6 +340,7 @@ template<typename... P> auto append(lstring& self, const string& value, P&&... p
|
|||
inline auto append(lstring& self) -> lstring&;
|
||||
inline auto find(const lstring& self, const string& source) -> maybe<unsigned>;
|
||||
inline auto ifind(const lstring& self, const string& source) -> maybe<unsigned>;
|
||||
inline auto match(const lstring& self, const string& pattern) -> lstring;
|
||||
inline auto merge(const lstring& self, const string& separator) -> string;
|
||||
inline auto strip(lstring& self) -> lstring&;
|
||||
|
||||
|
@ -368,6 +369,7 @@ struct lstring : vector<string> {
|
|||
template<typename... P> auto append(P&&... p) -> type& { return nall::append(*this, forward<P>(p)...); }
|
||||
auto find(const string& source) const -> maybe<unsigned> { return nall::find(*this, source); }
|
||||
auto ifind(const string& source) const -> maybe<unsigned> { return nall::ifind(*this, source); }
|
||||
auto match(const string& pattern) const -> lstring { return nall::match(*this, pattern); }
|
||||
auto merge(const string& separator) const -> string { return nall::merge(*this, separator); }
|
||||
auto strip() -> type& { return nall::strip(*this); }
|
||||
|
||||
|
|
|
@ -46,6 +46,14 @@ auto ifind(const lstring& self, const string& source) -> maybe<unsigned> {
|
|||
return nothing;
|
||||
}
|
||||
|
||||
auto match(const lstring& self, const string& pattern) -> lstring {
|
||||
lstring result;
|
||||
for(unsigned n = 0; n < self.size(); n++) {
|
||||
if(self[n].match(pattern)) result.append(self[n]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
auto merge(const lstring& self, const string& separator) -> string {
|
||||
string output;
|
||||
for(unsigned n = 0; n < self.size(); n++) {
|
||||
|
|
|
@ -62,7 +62,7 @@ auto Cartridge::load() -> void {
|
|||
information.title.sufamiTurboA = "";
|
||||
information.title.sufamiTurboB = "";
|
||||
|
||||
interface->loadRequest(ID::Manifest, "manifest.bml");
|
||||
interface->loadRequest(ID::Manifest, "manifest.bml", true);
|
||||
parseMarkup(information.markup.cartridge);
|
||||
|
||||
//Super Game Boy
|
||||
|
@ -115,7 +115,7 @@ auto Cartridge::load() -> void {
|
|||
}
|
||||
|
||||
auto Cartridge::loadSuperGameBoy() -> void {
|
||||
interface->loadRequest(ID::SuperGameBoyManifest, "manifest.bml");
|
||||
interface->loadRequest(ID::SuperGameBoyManifest, "manifest.bml", true);
|
||||
auto document = BML::unserialize(information.markup.gameBoy);
|
||||
information.title.gameBoy = document["information/title"].text();
|
||||
|
||||
|
@ -125,13 +125,13 @@ auto Cartridge::loadSuperGameBoy() -> void {
|
|||
GameBoy::cartridge.information.markup = information.markup.gameBoy;
|
||||
GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy);
|
||||
|
||||
if(auto name = rom["name"].text()) interface->loadRequest(ID::SuperGameBoyROM, name);
|
||||
if(auto name = ram["name"].text()) interface->loadRequest(ID::SuperGameBoyRAM, name);
|
||||
if(auto name = rom["name"].text()) interface->loadRequest(ID::SuperGameBoyROM, name, true);
|
||||
if(auto name = ram["name"].text()) interface->loadRequest(ID::SuperGameBoyRAM, name, false);
|
||||
if(auto name = ram["name"].text()) memory.append({ID::SuperGameBoyRAM, name});
|
||||
}
|
||||
|
||||
auto Cartridge::loadSatellaview() -> void {
|
||||
interface->loadRequest(ID::SatellaviewManifest, "manifest.bml");
|
||||
interface->loadRequest(ID::SatellaviewManifest, "manifest.bml", true);
|
||||
auto document = BML::unserialize(information.markup.satellaview);
|
||||
information.title.satellaview = document["information/title"].text();
|
||||
|
||||
|
@ -140,14 +140,14 @@ auto Cartridge::loadSatellaview() -> void {
|
|||
if(rom["name"]) {
|
||||
unsigned size = rom["size"].decimal();
|
||||
satellaviewcartridge.memory.map(allocate<uint8>(size, 0xff), size);
|
||||
interface->loadRequest(ID::SatellaviewROM, rom["name"].text());
|
||||
interface->loadRequest(ID::SatellaviewROM, rom["name"].text(), true);
|
||||
|
||||
satellaviewcartridge.readonly = (rom["type"].text() == "MaskROM");
|
||||
}
|
||||
}
|
||||
|
||||
auto Cartridge::loadSufamiTurboA() -> void {
|
||||
interface->loadRequest(ID::SufamiTurboSlotAManifest, "manifest.bml");
|
||||
interface->loadRequest(ID::SufamiTurboSlotAManifest, "manifest.bml", true);
|
||||
auto document = BML::unserialize(information.markup.sufamiTurboA);
|
||||
information.title.sufamiTurboA = document["information/title"].text();
|
||||
|
||||
|
@ -157,23 +157,23 @@ auto Cartridge::loadSufamiTurboA() -> void {
|
|||
if(rom["name"]) {
|
||||
unsigned size = rom["size"].decimal();
|
||||
sufamiturboA.rom.map(allocate<uint8>(size, 0xff), size);
|
||||
interface->loadRequest(ID::SufamiTurboSlotAROM, rom["name"].text());
|
||||
interface->loadRequest(ID::SufamiTurboSlotAROM, rom["name"].text(), true);
|
||||
}
|
||||
|
||||
if(ram["name"]) {
|
||||
unsigned size = ram["size"].decimal();
|
||||
sufamiturboA.ram.map(allocate<uint8>(size, 0xff), size);
|
||||
interface->loadRequest(ID::SufamiTurboSlotARAM, ram["name"].text());
|
||||
interface->loadRequest(ID::SufamiTurboSlotARAM, ram["name"].text(), false);
|
||||
memory.append({ID::SufamiTurboSlotARAM, ram["name"].text()});
|
||||
}
|
||||
|
||||
if(document["cartridge/linkable"]) {
|
||||
interface->loadRequest(ID::SufamiTurboSlotB, "Sufami Turbo - Slot B", "st");
|
||||
interface->loadRequest(ID::SufamiTurboSlotB, "Sufami Turbo - Slot B", "st", false);
|
||||
}
|
||||
}
|
||||
|
||||
auto Cartridge::loadSufamiTurboB() -> void {
|
||||
interface->loadRequest(ID::SufamiTurboSlotBManifest, "manifest.bml");
|
||||
interface->loadRequest(ID::SufamiTurboSlotBManifest, "manifest.bml", true);
|
||||
auto document = BML::unserialize(information.markup.sufamiTurboB);
|
||||
information.title.sufamiTurboB = document["information/title"].text();
|
||||
|
||||
|
@ -183,13 +183,13 @@ auto Cartridge::loadSufamiTurboB() -> void {
|
|||
if(rom["name"]) {
|
||||
unsigned size = rom["size"].decimal();
|
||||
sufamiturboB.rom.map(allocate<uint8>(size, 0xff), size);
|
||||
interface->loadRequest(ID::SufamiTurboSlotBROM, rom["name"].text());
|
||||
interface->loadRequest(ID::SufamiTurboSlotBROM, rom["name"].text(), true);
|
||||
}
|
||||
|
||||
if(ram["name"]) {
|
||||
unsigned size = ram["size"].decimal();
|
||||
sufamiturboB.ram.map(allocate<uint8>(size, 0xff), size);
|
||||
interface->loadRequest(ID::SufamiTurboSlotBRAM, ram["name"].text());
|
||||
interface->loadRequest(ID::SufamiTurboSlotBRAM, ram["name"].text(), false);
|
||||
memory.append({ID::SufamiTurboSlotBRAM, ram["name"].text()});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ auto Cartridge::parseMarkupMemory(MappedRAM& ram, Markup::Node node, unsigned id
|
|||
unsigned size = node["size"].decimal();
|
||||
ram.map(allocate<uint8>(size, 0xff), size);
|
||||
if(name) {
|
||||
interface->loadRequest(id, name);
|
||||
interface->loadRequest(id, name, !writable); //treat ROM as required; RAM as optional
|
||||
if(writable) memory.append({id, name});
|
||||
}
|
||||
}
|
||||
|
@ -83,10 +83,10 @@ auto Cartridge::parseMarkupICD2(Markup::Node root) -> void {
|
|||
icd2.revision = max(1, root["revision"].decimal());
|
||||
|
||||
GameBoy::cartridge.load_empty(GameBoy::System::Revision::SuperGameBoy);
|
||||
interface->loadRequest(ID::SuperGameBoy, "Game Boy", "gb");
|
||||
interface->loadRequest(ID::SuperGameBoy, "Game Boy", "gb", false);
|
||||
|
||||
string bootROMName = root["rom/name"].text();
|
||||
interface->loadRequest(ID::SuperGameBoyBootROM, bootROMName);
|
||||
interface->loadRequest(ID::SuperGameBoyBootROM, bootROMName, true);
|
||||
|
||||
for(auto node : root.find("map")) {
|
||||
if(node["id"].text() == "io") {
|
||||
|
@ -309,10 +309,10 @@ auto Cartridge::parseMarkupARMDSP(Markup::Node root) -> void {
|
|||
string dataROMName = rom(1)["name"].text();
|
||||
string dataRAMName = ram(0)["name"].text();
|
||||
|
||||
interface->loadRequest(ID::ArmDSPPROM, programROMName);
|
||||
interface->loadRequest(ID::ArmDSPDROM, dataROMName);
|
||||
interface->loadRequest(ID::ArmDSPPROM, programROMName, true);
|
||||
interface->loadRequest(ID::ArmDSPDROM, dataROMName, true);
|
||||
if(dataRAMName.empty() == false) {
|
||||
interface->loadRequest(ID::ArmDSPRAM, dataRAMName);
|
||||
interface->loadRequest(ID::ArmDSPRAM, dataRAMName, false);
|
||||
memory.append({ID::ArmDSPRAM, dataRAMName});
|
||||
}
|
||||
|
||||
|
@ -344,9 +344,9 @@ auto Cartridge::parseMarkupHitachiDSP(Markup::Node root, unsigned roms) -> void
|
|||
string dataROMName = rom(1)["name"].text();
|
||||
string dataRAMName = ram(1)["name"].text();
|
||||
|
||||
interface->loadRequest(ID::HitachiDSPDROM, dataROMName);
|
||||
interface->loadRequest(ID::HitachiDSPDROM, dataROMName, true);
|
||||
if(dataRAMName.empty() == false) {
|
||||
interface->loadRequest(ID::HitachiDSPDRAM, dataRAMName);
|
||||
interface->loadRequest(ID::HitachiDSPDRAM, dataRAMName, false);
|
||||
}
|
||||
|
||||
for(auto node : root.find("map")) {
|
||||
|
@ -394,19 +394,19 @@ auto Cartridge::parseMarkupNECDSP(Markup::Node root) -> void {
|
|||
string dataRAMName = ram(0)["name"].text();
|
||||
|
||||
if(necdsp.revision == NECDSP::Revision::uPD7725) {
|
||||
interface->loadRequest(ID::Nec7725DSPPROM, programROMName);
|
||||
interface->loadRequest(ID::Nec7725DSPDROM, dataROMName);
|
||||
interface->loadRequest(ID::Nec7725DSPPROM, programROMName, true);
|
||||
interface->loadRequest(ID::Nec7725DSPDROM, dataROMName, true);
|
||||
if(dataRAMName.empty() == false) {
|
||||
interface->loadRequest(ID::Nec7725DSPRAM, dataRAMName);
|
||||
interface->loadRequest(ID::Nec7725DSPRAM, dataRAMName, false);
|
||||
memory.append({ID::Nec7725DSPRAM, dataRAMName});
|
||||
}
|
||||
}
|
||||
|
||||
if(necdsp.revision == NECDSP::Revision::uPD96050) {
|
||||
interface->loadRequest(ID::Nec96050DSPPROM, programROMName);
|
||||
interface->loadRequest(ID::Nec96050DSPDROM, dataROMName);
|
||||
interface->loadRequest(ID::Nec96050DSPPROM, programROMName, true);
|
||||
interface->loadRequest(ID::Nec96050DSPDROM, dataROMName, true);
|
||||
if(dataRAMName.empty() == false) {
|
||||
interface->loadRequest(ID::Nec96050DSPRAM, dataRAMName);
|
||||
interface->loadRequest(ID::Nec96050DSPRAM, dataRAMName, false);
|
||||
memory.append({ID::Nec96050DSPRAM, dataRAMName});
|
||||
}
|
||||
}
|
||||
|
@ -431,7 +431,7 @@ auto Cartridge::parseMarkupEpsonRTC(Markup::Node root) -> void {
|
|||
hasEpsonRTC = true;
|
||||
|
||||
string name = root["ram/name"].text();
|
||||
interface->loadRequest(ID::EpsonRTC, name);
|
||||
interface->loadRequest(ID::EpsonRTC, name, false);
|
||||
memory.append({ID::EpsonRTC, name});
|
||||
|
||||
for(auto node : root.find("map")) {
|
||||
|
@ -447,7 +447,7 @@ auto Cartridge::parseMarkupSharpRTC(Markup::Node root) -> void {
|
|||
hasSharpRTC = true;
|
||||
|
||||
string name = root["ram/name"].text();
|
||||
interface->loadRequest(ID::SharpRTC, name);
|
||||
interface->loadRequest(ID::SharpRTC, name, false);
|
||||
memory.append({ID::SharpRTC, name});
|
||||
|
||||
for(auto node : root.find("map")) {
|
||||
|
|
|
@ -5,19 +5,19 @@ namespace SuperFamicom {
|
|||
|
||||
Cheat cheat;
|
||||
|
||||
void Cheat::reset() {
|
||||
auto Cheat::reset() -> void {
|
||||
codes.reset();
|
||||
}
|
||||
|
||||
void Cheat::append(unsigned addr, unsigned data) {
|
||||
auto Cheat::append(unsigned addr, unsigned data) -> void {
|
||||
codes.append({addr, Unused, data});
|
||||
}
|
||||
|
||||
void Cheat::append(unsigned addr, unsigned comp, unsigned data) {
|
||||
auto Cheat::append(unsigned addr, unsigned comp, unsigned data) -> void {
|
||||
codes.append({addr, comp, data});
|
||||
}
|
||||
|
||||
maybe<unsigned> Cheat::find(unsigned addr, unsigned comp) {
|
||||
auto Cheat::find(unsigned addr, unsigned comp) -> maybe<unsigned> {
|
||||
//WRAM mirroring: $00-3f,80-bf:0000-1fff -> $7e:0000-1fff
|
||||
if((addr & 0x40e000) == 0x000000) addr = 0x7e0000 | (addr & 0x1fff);
|
||||
|
||||
|
@ -26,6 +26,7 @@ maybe<unsigned> Cheat::find(unsigned addr, unsigned comp) {
|
|||
return code.data;
|
||||
}
|
||||
}
|
||||
|
||||
return nothing;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
struct Cheat {
|
||||
enum : unsigned { Unused = ~0u };
|
||||
|
||||
alwaysinline auto enable() const -> bool { return codes.size() > 0; }
|
||||
|
||||
auto reset() -> void;
|
||||
auto append(unsigned addr, unsigned data) -> void;
|
||||
auto append(unsigned addr, unsigned comp, unsigned data) -> void;
|
||||
auto find(unsigned addr, unsigned comp) -> maybe<unsigned>;
|
||||
|
||||
struct Code {
|
||||
unsigned addr;
|
||||
unsigned comp;
|
||||
unsigned data;
|
||||
};
|
||||
vector<Code> codes;
|
||||
enum : unsigned { Unused = ~0u };
|
||||
|
||||
alwaysinline bool enable() const { return codes.size() > 0; }
|
||||
void reset();
|
||||
void append(unsigned addr, unsigned data);
|
||||
void append(unsigned addr, unsigned comp, unsigned data);
|
||||
maybe<unsigned> find(unsigned addr, unsigned comp);
|
||||
};
|
||||
|
||||
extern Cheat cheat;
|
||||
|
|
|
@ -10,21 +10,25 @@ namespace SuperFamicom {
|
|||
#include "justifier/justifier.cpp"
|
||||
#include "usart/usart.cpp"
|
||||
|
||||
void Controller::Enter() {
|
||||
Controller::Controller(bool port) : port(port) {
|
||||
if(!thread) create(Controller::Enter, 1);
|
||||
}
|
||||
|
||||
auto Controller::Enter() -> void {
|
||||
if(co_active() == input.port1->thread) input.port1->enter();
|
||||
if(co_active() == input.port2->thread) input.port2->enter();
|
||||
}
|
||||
|
||||
void Controller::enter() {
|
||||
auto Controller::enter() -> void {
|
||||
while(true) step(1);
|
||||
}
|
||||
|
||||
void Controller::step(unsigned clocks) {
|
||||
auto Controller::step(unsigned clocks) -> void {
|
||||
clock += clocks * (uint64)cpu.frequency;
|
||||
synchronize_cpu();
|
||||
}
|
||||
|
||||
void Controller::synchronize_cpu() {
|
||||
auto Controller::synchronize_cpu() -> void {
|
||||
if(CPU::Threaded == true) {
|
||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
|
||||
} else {
|
||||
|
@ -32,22 +36,18 @@ void Controller::synchronize_cpu() {
|
|||
}
|
||||
}
|
||||
|
||||
bool Controller::iobit() {
|
||||
auto Controller::iobit() -> bool {
|
||||
switch(port) {
|
||||
case Controller::Port1: return cpu.pio() & 0x40;
|
||||
case Controller::Port2: return cpu.pio() & 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::iobit(bool data) {
|
||||
auto Controller::iobit(bool data) -> void {
|
||||
switch(port) {
|
||||
case Controller::Port1: bus.write(0x4201, (cpu.pio() & ~0x40) | (data << 6)); break;
|
||||
case Controller::Port2: bus.write(0x4201, (cpu.pio() & ~0x80) | (data << 7)); break;
|
||||
}
|
||||
}
|
||||
|
||||
Controller::Controller(bool port) : port(port) {
|
||||
if(!thread) create(Controller::Enter, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,18 +13,21 @@
|
|||
|
||||
struct Controller : Thread {
|
||||
enum : bool { Port1 = 0, Port2 = 1 };
|
||||
const bool port;
|
||||
|
||||
static void Enter();
|
||||
virtual void enter();
|
||||
void step(unsigned clocks);
|
||||
void synchronize_cpu();
|
||||
|
||||
bool iobit();
|
||||
void iobit(bool data);
|
||||
virtual uint2 data() { return 0; }
|
||||
virtual void latch(bool data) {}
|
||||
Controller(bool port);
|
||||
|
||||
static auto Enter() -> void;
|
||||
virtual auto enter() -> void;
|
||||
|
||||
auto step(unsigned clocks) -> void;
|
||||
auto synchronize_cpu() -> void;
|
||||
|
||||
auto iobit() -> bool;
|
||||
auto iobit(bool data) -> void;
|
||||
virtual auto data() -> uint2 { return 0; }
|
||||
virtual auto latch(bool data) -> void {}
|
||||
|
||||
const bool port;
|
||||
};
|
||||
|
||||
#include "gamepad/gamepad.hpp"
|
||||
|
|
|
@ -4,31 +4,150 @@ namespace SuperFamicom {
|
|||
|
||||
Interface* interface = nullptr;
|
||||
|
||||
string Interface::title() {
|
||||
Interface::Interface() {
|
||||
interface = this;
|
||||
system.init();
|
||||
|
||||
information.name = "Super Famicom";
|
||||
information.width = 256;
|
||||
information.height = 240;
|
||||
information.overscan = true;
|
||||
information.aspectRatio = 8.0 / 7.0;
|
||||
information.resettable = true;
|
||||
information.capability.states = true;
|
||||
information.capability.cheats = true;
|
||||
|
||||
media.append({ID::SuperFamicom, "Super Famicom", "sfc", true });
|
||||
media.append({ID::SuperFamicom, "Game Boy", "gb", false});
|
||||
media.append({ID::SuperFamicom, "BS-X Satellaview", "bs", false});
|
||||
media.append({ID::SuperFamicom, "Sufami Turbo", "st", false});
|
||||
|
||||
{ Device device{0, ID::Port1 | ID::Port2, "Controller"};
|
||||
device.input.append({ 0, 0, "B" });
|
||||
device.input.append({ 1, 0, "Y" });
|
||||
device.input.append({ 2, 0, "Select"});
|
||||
device.input.append({ 3, 0, "Start" });
|
||||
device.input.append({ 4, 0, "Up" });
|
||||
device.input.append({ 5, 0, "Down" });
|
||||
device.input.append({ 6, 0, "Left" });
|
||||
device.input.append({ 7, 0, "Right" });
|
||||
device.input.append({ 8, 0, "A" });
|
||||
device.input.append({ 9, 0, "X" });
|
||||
device.input.append({10, 0, "L" });
|
||||
device.input.append({11, 0, "R" });
|
||||
device.order = {4, 5, 6, 7, 0, 8, 1, 9, 10, 11, 2, 3};
|
||||
this->device.append(device);
|
||||
}
|
||||
|
||||
{ Device device{1, ID::Port1 | ID::Port2, "Multitap"};
|
||||
for(unsigned p = 1, n = 0; p <= 4; p++, n += 12) {
|
||||
device.input.append({n + 0, 0, {"Port ", p, " - ", "B" }});
|
||||
device.input.append({n + 1, 0, {"Port ", p, " - ", "Y" }});
|
||||
device.input.append({n + 2, 0, {"Port ", p, " - ", "Select"}});
|
||||
device.input.append({n + 3, 0, {"Port ", p, " - ", "Start" }});
|
||||
device.input.append({n + 4, 0, {"Port ", p, " - ", "Up" }});
|
||||
device.input.append({n + 5, 0, {"Port ", p, " - ", "Down" }});
|
||||
device.input.append({n + 6, 0, {"Port ", p, " - ", "Left" }});
|
||||
device.input.append({n + 7, 0, {"Port ", p, " - ", "Right" }});
|
||||
device.input.append({n + 8, 0, {"Port ", p, " - ", "A" }});
|
||||
device.input.append({n + 9, 0, {"Port ", p, " - ", "X" }});
|
||||
device.input.append({n + 10, 0, {"Port ", p, " - ", "L" }});
|
||||
device.input.append({n + 11, 0, {"Port ", p, " - ", "R" }});
|
||||
device.order.append(n + 4, n + 5, n + 6, n + 7, n + 0, n + 8);
|
||||
device.order.append(n + 1, n + 9, n + 10, n + 11, n + 2, n + 3);
|
||||
}
|
||||
this->device.append(device);
|
||||
}
|
||||
|
||||
{ Device device{2, ID::Port1 | ID::Port2, "Mouse"};
|
||||
device.input.append({0, 1, "X-axis"});
|
||||
device.input.append({1, 1, "Y-axis"});
|
||||
device.input.append({2, 0, "Left" });
|
||||
device.input.append({3, 0, "Right" });
|
||||
device.order = {0, 1, 2, 3};
|
||||
this->device.append(device);
|
||||
}
|
||||
|
||||
{ Device device{3, ID::Port2, "Super Scope"};
|
||||
device.input.append({0, 1, "X-axis" });
|
||||
device.input.append({1, 1, "Y-axis" });
|
||||
device.input.append({2, 0, "Trigger"});
|
||||
device.input.append({3, 0, "Cursor" });
|
||||
device.input.append({4, 0, "Turbo" });
|
||||
device.input.append({5, 0, "Pause" });
|
||||
device.order = {0, 1, 2, 3, 4, 5};
|
||||
this->device.append(device);
|
||||
}
|
||||
|
||||
{ Device device{4, ID::Port2, "Justifier"};
|
||||
device.input.append({0, 1, "X-axis" });
|
||||
device.input.append({1, 1, "Y-axis" });
|
||||
device.input.append({2, 0, "Trigger"});
|
||||
device.input.append({3, 0, "Start" });
|
||||
device.order = {0, 1, 2, 3};
|
||||
this->device.append(device);
|
||||
}
|
||||
|
||||
{ Device device{5, ID::Port2, "Justifiers"};
|
||||
device.input.append({0, 1, "Port 1 - X-axis" });
|
||||
device.input.append({1, 1, "Port 1 - Y-axis" });
|
||||
device.input.append({2, 0, "Port 1 - Trigger"});
|
||||
device.input.append({3, 0, "Port 1 - Start" });
|
||||
device.order.append(0, 1, 2, 3);
|
||||
device.input.append({4, 1, "Port 2 - X-axis" });
|
||||
device.input.append({5, 1, "Port 2 - Y-axis" });
|
||||
device.input.append({6, 0, "Port 2 - Trigger"});
|
||||
device.input.append({7, 0, "Port 2 - Start" });
|
||||
device.order.append(4, 5, 6, 7);
|
||||
this->device.append(device);
|
||||
}
|
||||
|
||||
{ Device device{6, ID::Port1, "Serial USART"};
|
||||
this->device.append(device);
|
||||
}
|
||||
|
||||
{ Device device{7, ID::Port1 | ID::Port2, "None"};
|
||||
this->device.append(device);
|
||||
}
|
||||
|
||||
port.append({0, "Port 1"});
|
||||
port.append({1, "Port 2"});
|
||||
|
||||
for(auto& device : this->device) {
|
||||
for(auto& port : this->port) {
|
||||
if(device.portmask & (1 << port.id)) {
|
||||
port.device.append(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Interface::title() -> string {
|
||||
return cartridge.title();
|
||||
}
|
||||
|
||||
double Interface::videoFrequency() {
|
||||
auto Interface::videoFrequency() -> double {
|
||||
switch(system.region()) { default:
|
||||
case System::Region::NTSC: return system.cpu_frequency() / (262.0 * 1364.0 - 4.0);
|
||||
case System::Region::PAL: return system.cpu_frequency() / (312.0 * 1364.0);
|
||||
}
|
||||
}
|
||||
|
||||
double Interface::audioFrequency() {
|
||||
auto Interface::audioFrequency() -> double {
|
||||
return system.apu_frequency() / 768.0;
|
||||
}
|
||||
|
||||
bool Interface::loaded() {
|
||||
auto Interface::loaded() -> bool {
|
||||
return cartridge.loaded();
|
||||
}
|
||||
|
||||
string Interface::sha256() {
|
||||
auto Interface::sha256() -> string {
|
||||
return cartridge.sha256();
|
||||
}
|
||||
|
||||
unsigned Interface::group(unsigned id) {
|
||||
auto Interface::group(unsigned id) -> unsigned {
|
||||
switch(id) {
|
||||
case ID::SystemManifest:
|
||||
case ID::IPLROM:
|
||||
return 0;
|
||||
case ID::Manifest:
|
||||
|
@ -94,7 +213,7 @@ unsigned Interface::group(unsigned id) {
|
|||
throw;
|
||||
}
|
||||
|
||||
void Interface::load(unsigned id) {
|
||||
auto Interface::load(unsigned id) -> void {
|
||||
if(id == ID::SuperFamicom) cartridge.load();
|
||||
if(id == ID::SuperGameBoy) cartridge.loadSuperGameBoy();
|
||||
if(id == ID::Satellaview) cartridge.loadSatellaview();
|
||||
|
@ -102,13 +221,17 @@ void Interface::load(unsigned id) {
|
|||
if(id == ID::SufamiTurboSlotB) cartridge.loadSufamiTurboB();
|
||||
}
|
||||
|
||||
void Interface::save() {
|
||||
auto Interface::save() -> void {
|
||||
for(auto& memory : cartridge.memory) {
|
||||
saveRequest(memory.id, memory.name);
|
||||
}
|
||||
}
|
||||
|
||||
void Interface::load(unsigned id, const stream& stream) {
|
||||
auto Interface::load(unsigned id, const stream& stream) -> void {
|
||||
if(id == ID::SystemManifest) {
|
||||
system.information.manifest = stream.text();
|
||||
}
|
||||
|
||||
if(id == ID::IPLROM) {
|
||||
stream.read(smp.iplrom, min(64u, stream.size()));
|
||||
}
|
||||
|
@ -219,7 +342,7 @@ void Interface::load(unsigned id, const stream& stream) {
|
|||
if(id == ID::SufamiTurboSlotBRAM) sufamiturboB.ram.read(stream);
|
||||
}
|
||||
|
||||
void Interface::save(unsigned id, const stream& stream) {
|
||||
auto Interface::save(unsigned id, const stream& stream) -> void {
|
||||
if(id == ID::RAM) stream.write(cartridge.ram.data(), cartridge.ram.size());
|
||||
if(id == ID::EventRAM) stream.write(event.ram.data(), event.ram.size());
|
||||
if(id == ID::SA1IRAM) stream.write(sa1.iram.data(), sa1.iram.size());
|
||||
|
@ -267,48 +390,48 @@ void Interface::save(unsigned id, const stream& stream) {
|
|||
if(id == ID::SufamiTurboSlotBRAM) stream.write(sufamiturboB.ram.data(), sufamiturboB.ram.size());
|
||||
}
|
||||
|
||||
void Interface::unload() {
|
||||
auto Interface::unload() -> void {
|
||||
save();
|
||||
cartridge.unload();
|
||||
}
|
||||
|
||||
void Interface::connect(unsigned port, unsigned device) {
|
||||
auto Interface::connect(unsigned port, unsigned device) -> void {
|
||||
input.connect(port, (Input::Device)device);
|
||||
}
|
||||
|
||||
void Interface::power() {
|
||||
auto Interface::power() -> void {
|
||||
system.power();
|
||||
}
|
||||
|
||||
void Interface::reset() {
|
||||
auto Interface::reset() -> void {
|
||||
system.reset();
|
||||
}
|
||||
|
||||
void Interface::run() {
|
||||
auto Interface::run() -> void {
|
||||
system.run();
|
||||
}
|
||||
|
||||
bool Interface::rtc() {
|
||||
auto Interface::rtc() -> bool {
|
||||
if(cartridge.hasEpsonRTC()) return true;
|
||||
if(cartridge.hasSharpRTC()) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Interface::rtcsync() {
|
||||
auto Interface::rtcsync() -> void {
|
||||
if(cartridge.hasEpsonRTC()) epsonrtc.sync();
|
||||
if(cartridge.hasSharpRTC()) sharprtc.sync();
|
||||
}
|
||||
|
||||
serializer Interface::serialize() {
|
||||
auto Interface::serialize() -> serializer {
|
||||
system.runtosave();
|
||||
return system.serialize();
|
||||
}
|
||||
|
||||
bool Interface::unserialize(serializer& s) {
|
||||
auto Interface::unserialize(serializer& s) -> bool {
|
||||
return system.unserialize(s);
|
||||
}
|
||||
|
||||
void Interface::cheatSet(const lstring& list) {
|
||||
auto Interface::cheatSet(const lstring& list) -> void {
|
||||
cheat.reset();
|
||||
|
||||
//Super Game Boy
|
||||
|
@ -336,134 +459,8 @@ void Interface::cheatSet(const lstring& list) {
|
|||
}
|
||||
}
|
||||
|
||||
void Interface::paletteUpdate(PaletteMode mode) {
|
||||
auto Interface::paletteUpdate(PaletteMode mode) -> void {
|
||||
video.generate_palette(mode);
|
||||
}
|
||||
|
||||
Interface::Interface() {
|
||||
interface = this;
|
||||
system.init();
|
||||
|
||||
information.name = "Super Famicom";
|
||||
information.width = 256;
|
||||
information.height = 240;
|
||||
information.overscan = true;
|
||||
information.aspectRatio = 8.0 / 7.0;
|
||||
information.resettable = true;
|
||||
information.capability.states = true;
|
||||
information.capability.cheats = true;
|
||||
|
||||
media.append({ID::SuperFamicom, "Super Famicom", "sfc", true });
|
||||
media.append({ID::SuperFamicom, "Game Boy", "gb", false});
|
||||
media.append({ID::SuperFamicom, "BS-X Satellaview", "bs", false});
|
||||
media.append({ID::SuperFamicom, "Sufami Turbo", "st", false});
|
||||
|
||||
{
|
||||
Device device{0, ID::Port1 | ID::Port2, "Controller"};
|
||||
device.input.append({ 0, 0, "B" });
|
||||
device.input.append({ 1, 0, "Y" });
|
||||
device.input.append({ 2, 0, "Select"});
|
||||
device.input.append({ 3, 0, "Start" });
|
||||
device.input.append({ 4, 0, "Up" });
|
||||
device.input.append({ 5, 0, "Down" });
|
||||
device.input.append({ 6, 0, "Left" });
|
||||
device.input.append({ 7, 0, "Right" });
|
||||
device.input.append({ 8, 0, "A" });
|
||||
device.input.append({ 9, 0, "X" });
|
||||
device.input.append({10, 0, "L" });
|
||||
device.input.append({11, 0, "R" });
|
||||
device.order = {4, 5, 6, 7, 0, 8, 1, 9, 10, 11, 2, 3};
|
||||
this->device.append(device);
|
||||
}
|
||||
|
||||
{
|
||||
Device device{1, ID::Port1 | ID::Port2, "Multitap"};
|
||||
for(unsigned p = 1, n = 0; p <= 4; p++, n += 12) {
|
||||
device.input.append({n + 0, 0, {"Port ", p, " - ", "B" }});
|
||||
device.input.append({n + 1, 0, {"Port ", p, " - ", "Y" }});
|
||||
device.input.append({n + 2, 0, {"Port ", p, " - ", "Select"}});
|
||||
device.input.append({n + 3, 0, {"Port ", p, " - ", "Start" }});
|
||||
device.input.append({n + 4, 0, {"Port ", p, " - ", "Up" }});
|
||||
device.input.append({n + 5, 0, {"Port ", p, " - ", "Down" }});
|
||||
device.input.append({n + 6, 0, {"Port ", p, " - ", "Left" }});
|
||||
device.input.append({n + 7, 0, {"Port ", p, " - ", "Right" }});
|
||||
device.input.append({n + 8, 0, {"Port ", p, " - ", "A" }});
|
||||
device.input.append({n + 9, 0, {"Port ", p, " - ", "X" }});
|
||||
device.input.append({n + 10, 0, {"Port ", p, " - ", "L" }});
|
||||
device.input.append({n + 11, 0, {"Port ", p, " - ", "R" }});
|
||||
device.order.append(n + 4, n + 5, n + 6, n + 7, n + 0, n + 8);
|
||||
device.order.append(n + 1, n + 9, n + 10, n + 11, n + 2, n + 3);
|
||||
}
|
||||
this->device.append(device);
|
||||
}
|
||||
|
||||
{
|
||||
Device device{2, ID::Port1 | ID::Port2, "Mouse"};
|
||||
device.input.append({0, 1, "X-axis"});
|
||||
device.input.append({1, 1, "Y-axis"});
|
||||
device.input.append({2, 0, "Left" });
|
||||
device.input.append({3, 0, "Right" });
|
||||
device.order = {0, 1, 2, 3};
|
||||
this->device.append(device);
|
||||
}
|
||||
|
||||
{
|
||||
Device device{3, ID::Port2, "Super Scope"};
|
||||
device.input.append({0, 1, "X-axis" });
|
||||
device.input.append({1, 1, "Y-axis" });
|
||||
device.input.append({2, 0, "Trigger"});
|
||||
device.input.append({3, 0, "Cursor" });
|
||||
device.input.append({4, 0, "Turbo" });
|
||||
device.input.append({5, 0, "Pause" });
|
||||
device.order = {0, 1, 2, 3, 4, 5};
|
||||
this->device.append(device);
|
||||
}
|
||||
|
||||
{
|
||||
Device device{4, ID::Port2, "Justifier"};
|
||||
device.input.append({0, 1, "X-axis" });
|
||||
device.input.append({1, 1, "Y-axis" });
|
||||
device.input.append({2, 0, "Trigger"});
|
||||
device.input.append({3, 0, "Start" });
|
||||
device.order = {0, 1, 2, 3};
|
||||
this->device.append(device);
|
||||
}
|
||||
|
||||
{
|
||||
Device device{5, ID::Port2, "Justifiers"};
|
||||
device.input.append({0, 1, "Port 1 - X-axis" });
|
||||
device.input.append({1, 1, "Port 1 - Y-axis" });
|
||||
device.input.append({2, 0, "Port 1 - Trigger"});
|
||||
device.input.append({3, 0, "Port 1 - Start" });
|
||||
device.order.append(0, 1, 2, 3);
|
||||
device.input.append({4, 1, "Port 2 - X-axis" });
|
||||
device.input.append({5, 1, "Port 2 - Y-axis" });
|
||||
device.input.append({6, 0, "Port 2 - Trigger"});
|
||||
device.input.append({7, 0, "Port 2 - Start" });
|
||||
device.order.append(4, 5, 6, 7);
|
||||
this->device.append(device);
|
||||
}
|
||||
|
||||
{
|
||||
Device device{6, ID::Port1, "Serial USART"};
|
||||
this->device.append(device);
|
||||
}
|
||||
|
||||
{
|
||||
Device device{7, ID::Port1 | ID::Port2, "None"};
|
||||
this->device.append(device);
|
||||
}
|
||||
|
||||
port.append({0, "Port 1"});
|
||||
port.append({1, "Port 2"});
|
||||
|
||||
for(auto& device : this->device) {
|
||||
for(auto& port : this->port) {
|
||||
if(device.portmask & (1 << port.id)) {
|
||||
port.device.append(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ struct ID {
|
|||
SufamiTurboSlotB,
|
||||
|
||||
//memory (files)
|
||||
SystemManifest,
|
||||
IPLROM,
|
||||
|
||||
Manifest,
|
||||
|
@ -89,36 +90,36 @@ struct ID {
|
|||
};
|
||||
|
||||
struct Interface : Emulator::Interface {
|
||||
string title();
|
||||
double videoFrequency();
|
||||
double audioFrequency();
|
||||
|
||||
bool loaded();
|
||||
string sha256();
|
||||
unsigned group(unsigned id);
|
||||
void load(unsigned id);
|
||||
void save();
|
||||
void load(unsigned id, const stream& stream);
|
||||
void save(unsigned id, const stream& stream);
|
||||
void unload();
|
||||
|
||||
void connect(unsigned port, unsigned device);
|
||||
void power();
|
||||
void reset();
|
||||
void run();
|
||||
|
||||
bool rtc();
|
||||
void rtcsync();
|
||||
|
||||
serializer serialize();
|
||||
bool unserialize(serializer&);
|
||||
|
||||
void cheatSet(const lstring&);
|
||||
|
||||
void paletteUpdate(PaletteMode mode);
|
||||
|
||||
Interface();
|
||||
|
||||
auto title() -> string;
|
||||
auto videoFrequency() -> double;
|
||||
auto audioFrequency() -> double;
|
||||
|
||||
auto loaded() -> bool;
|
||||
auto sha256() -> string;
|
||||
auto group(unsigned id) -> unsigned;
|
||||
auto load(unsigned id) -> void;
|
||||
auto save() -> void;
|
||||
auto load(unsigned id, const stream& stream) -> void;
|
||||
auto save(unsigned id, const stream& stream) -> void;
|
||||
auto unload() -> void;
|
||||
|
||||
auto connect(unsigned port, unsigned device) -> void;
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
auto run() -> void;
|
||||
|
||||
auto rtc() -> bool;
|
||||
auto rtcsync() -> void;
|
||||
|
||||
auto serialize() -> serializer;
|
||||
auto unserialize(serializer&) -> bool;
|
||||
|
||||
auto cheatSet(const lstring&) -> void;
|
||||
|
||||
auto paletteUpdate(PaletteMode mode) -> void;
|
||||
|
||||
vector<Device> device;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
//Memory
|
||||
|
||||
unsigned Memory::size() const { return 0; }
|
||||
auto Memory::size() const -> unsigned { return 0; }
|
||||
|
||||
//StaticRAM
|
||||
|
||||
uint8* StaticRAM::data() { return data_; }
|
||||
unsigned StaticRAM::size() const { return size_; }
|
||||
|
||||
uint8 StaticRAM::read(unsigned addr) { return data_[addr]; }
|
||||
void StaticRAM::write(unsigned addr, uint8 n) { data_[addr] = n; }
|
||||
uint8& StaticRAM::operator[](unsigned addr) { return data_[addr]; }
|
||||
const uint8& StaticRAM::operator[](unsigned addr) const { return data_[addr]; }
|
||||
|
||||
StaticRAM::StaticRAM(unsigned n) : size_(n) { data_ = new uint8[size_]; }
|
||||
StaticRAM::~StaticRAM() { delete[] data_; }
|
||||
|
||||
auto StaticRAM::data() -> uint8* { return data_; }
|
||||
auto StaticRAM::size() const -> unsigned { return size_; }
|
||||
|
||||
auto StaticRAM::read(unsigned addr) -> uint8 { return data_[addr]; }
|
||||
auto StaticRAM::write(unsigned addr, uint8 n) -> void { data_[addr] = n; }
|
||||
auto StaticRAM::operator[](unsigned addr) -> uint8& { return data_[addr]; }
|
||||
auto StaticRAM::operator[](unsigned addr) const -> const uint8& { return data_[addr]; }
|
||||
|
||||
//MappedRAM
|
||||
|
||||
void MappedRAM::reset() {
|
||||
auto MappedRAM::reset() -> void {
|
||||
if(data_) {
|
||||
delete[] data_;
|
||||
data_ = nullptr;
|
||||
|
@ -26,13 +26,13 @@ void MappedRAM::reset() {
|
|||
write_protect_ = false;
|
||||
}
|
||||
|
||||
void MappedRAM::map(uint8* source, unsigned length) {
|
||||
auto MappedRAM::map(uint8* source, unsigned length) -> void {
|
||||
reset();
|
||||
data_ = source;
|
||||
size_ = data_ ? length : 0;
|
||||
}
|
||||
|
||||
void MappedRAM::copy(const stream& memory) {
|
||||
auto MappedRAM::copy(const stream& memory) -> void {
|
||||
if(data_) delete[] data_;
|
||||
//round size up to multiple of 256-bytes
|
||||
size_ = (memory.size() & ~255) + ((bool)(memory.size() & 255) << 8);
|
||||
|
@ -40,22 +40,21 @@ void MappedRAM::copy(const stream& memory) {
|
|||
memory.read(data_, memory.size());
|
||||
}
|
||||
|
||||
void MappedRAM::read(const stream& memory) {
|
||||
auto MappedRAM::read(const stream& memory) -> void {
|
||||
memory.read(data_, min(memory.size(), size_));
|
||||
}
|
||||
|
||||
void MappedRAM::write_protect(bool status) { write_protect_ = status; }
|
||||
uint8* MappedRAM::data() { return data_; }
|
||||
unsigned MappedRAM::size() const { return size_; }
|
||||
auto MappedRAM::write_protect(bool status) -> void { write_protect_ = status; }
|
||||
auto MappedRAM::data() -> uint8* { return data_; }
|
||||
auto MappedRAM::size() const -> unsigned { return size_; }
|
||||
|
||||
uint8 MappedRAM::read(unsigned addr) { return data_[addr]; }
|
||||
void MappedRAM::write(unsigned addr, uint8 n) { if(!write_protect_) data_[addr] = n; }
|
||||
const uint8& MappedRAM::operator[](unsigned addr) const { return data_[addr]; }
|
||||
MappedRAM::MappedRAM() : data_(nullptr), size_(0), write_protect_(false) {}
|
||||
auto MappedRAM::read(unsigned addr) -> uint8 { return data_[addr]; }
|
||||
auto MappedRAM::write(unsigned addr, uint8 n) -> void { if(!write_protect_) data_[addr] = n; }
|
||||
auto MappedRAM::operator[](unsigned addr) const -> const uint8& { return data_[addr]; }
|
||||
|
||||
//Bus
|
||||
|
||||
unsigned Bus::mirror(unsigned addr, unsigned size) {
|
||||
auto Bus::mirror(unsigned addr, unsigned size) -> unsigned {
|
||||
if(size == 0) return 0;
|
||||
unsigned base = 0;
|
||||
unsigned mask = 1 << 23;
|
||||
|
@ -71,7 +70,7 @@ unsigned Bus::mirror(unsigned addr, unsigned size) {
|
|||
return base + addr;
|
||||
}
|
||||
|
||||
unsigned Bus::reduce(unsigned addr, unsigned mask) {
|
||||
auto Bus::reduce(unsigned addr, unsigned mask) -> unsigned {
|
||||
while(mask) {
|
||||
unsigned bits = (mask & -mask) - 1;
|
||||
addr = ((addr >> 1) & ~bits) | (addr & bits);
|
||||
|
@ -80,7 +79,7 @@ unsigned Bus::reduce(unsigned addr, unsigned mask) {
|
|||
return addr;
|
||||
}
|
||||
|
||||
uint8 Bus::read(unsigned addr) {
|
||||
auto Bus::read(unsigned addr) -> uint8 {
|
||||
uint8 data = reader[lookup[addr]](target[addr]);
|
||||
|
||||
if(cheat.enable()) {
|
||||
|
@ -90,6 +89,6 @@ uint8 Bus::read(unsigned addr) {
|
|||
return data;
|
||||
}
|
||||
|
||||
void Bus::write(unsigned addr, uint8 data) {
|
||||
auto Bus::write(unsigned addr, uint8 data) -> void {
|
||||
return writer[lookup[addr]](target[addr], data);
|
||||
}
|
||||
|
|
|
@ -5,32 +5,17 @@ namespace SuperFamicom {
|
|||
|
||||
Bus bus;
|
||||
|
||||
void Bus::map(
|
||||
const function<uint8 (unsigned)>& reader,
|
||||
const function<void (unsigned, uint8)>& writer,
|
||||
unsigned banklo, unsigned bankhi,
|
||||
unsigned addrlo, unsigned addrhi,
|
||||
unsigned size, unsigned base, unsigned mask
|
||||
) {
|
||||
assert(banklo <= bankhi && banklo <= 0xff);
|
||||
assert(addrlo <= addrhi && addrlo <= 0xffff);
|
||||
assert(idcount < 255);
|
||||
|
||||
unsigned id = idcount++;
|
||||
this->reader[id] = reader;
|
||||
this->writer[id] = writer;
|
||||
|
||||
for(unsigned bank = banklo; bank <= bankhi; bank++) {
|
||||
for(unsigned addr = addrlo; addr <= addrhi; addr++) {
|
||||
unsigned offset = reduce(bank << 16 | addr, mask);
|
||||
if(size) offset = base + mirror(offset, size - base);
|
||||
lookup[bank << 16 | addr] = id;
|
||||
target[bank << 16 | addr] = offset;
|
||||
}
|
||||
}
|
||||
Bus::Bus() {
|
||||
lookup = new uint8 [16 * 1024 * 1024];
|
||||
target = new uint32[16 * 1024 * 1024];
|
||||
}
|
||||
|
||||
void Bus::map_reset() {
|
||||
Bus::~Bus() {
|
||||
delete[] lookup;
|
||||
delete[] target;
|
||||
}
|
||||
|
||||
auto Bus::reset() -> void {
|
||||
function<uint8 (unsigned)> reader = [](unsigned) { return cpu.regs.mdr; };
|
||||
function<void (unsigned, uint8)> writer = [](unsigned, uint8) {};
|
||||
|
||||
|
@ -38,7 +23,7 @@ void Bus::map_reset() {
|
|||
map(reader, writer, 0x00, 0xff, 0x0000, 0xffff);
|
||||
}
|
||||
|
||||
void Bus::map_xml() {
|
||||
auto Bus::map() -> void {
|
||||
for(auto& m : cartridge.mapping) {
|
||||
lstring part = m.addr.split(":", 1L);
|
||||
lstring banks = part(0).split(",");
|
||||
|
@ -57,14 +42,29 @@ void Bus::map_xml() {
|
|||
}
|
||||
}
|
||||
|
||||
Bus::Bus() {
|
||||
lookup = new uint8 [16 * 1024 * 1024];
|
||||
target = new uint32[16 * 1024 * 1024];
|
||||
}
|
||||
auto Bus::map(
|
||||
const function<uint8 (unsigned)>& reader,
|
||||
const function<void (unsigned, uint8)>& writer,
|
||||
unsigned banklo, unsigned bankhi,
|
||||
unsigned addrlo, unsigned addrhi,
|
||||
unsigned size, unsigned base, unsigned mask
|
||||
) -> void {
|
||||
assert(banklo <= bankhi && banklo <= 0xff);
|
||||
assert(addrlo <= addrhi && addrlo <= 0xffff);
|
||||
assert(idcount < 255);
|
||||
|
||||
Bus::~Bus() {
|
||||
delete[] lookup;
|
||||
delete[] target;
|
||||
unsigned id = idcount++;
|
||||
this->reader[id] = reader;
|
||||
this->writer[id] = writer;
|
||||
|
||||
for(unsigned bank = banklo; bank <= bankhi; bank++) {
|
||||
for(unsigned addr = addrlo; addr <= addrhi; addr++) {
|
||||
unsigned offset = reduce(bank << 16 | addr, mask);
|
||||
if(size) offset = base + mirror(offset, size - base);
|
||||
lookup[bank << 16 | addr] = id;
|
||||
target[bank << 16 | addr] = offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,74 +1,72 @@
|
|||
struct Memory {
|
||||
virtual inline unsigned size() const;
|
||||
virtual uint8 read(unsigned addr) = 0;
|
||||
virtual void write(unsigned addr, uint8 data) = 0;
|
||||
virtual inline auto size() const -> unsigned;
|
||||
virtual auto read(unsigned addr) -> uint8 = 0;
|
||||
virtual auto write(unsigned addr, uint8 data) -> void = 0;
|
||||
};
|
||||
|
||||
struct StaticRAM : Memory {
|
||||
inline uint8* data();
|
||||
inline unsigned size() const;
|
||||
|
||||
inline uint8 read(unsigned addr);
|
||||
inline void write(unsigned addr, uint8 n);
|
||||
inline uint8& operator[](unsigned addr);
|
||||
inline const uint8& operator[](unsigned addr) const;
|
||||
|
||||
inline StaticRAM(unsigned size);
|
||||
inline ~StaticRAM();
|
||||
|
||||
inline auto data() -> uint8*;
|
||||
inline auto size() const -> unsigned;
|
||||
|
||||
inline auto read(unsigned addr) -> uint8;
|
||||
inline auto write(unsigned addr, uint8 n) -> void;
|
||||
inline auto operator[](unsigned addr) -> uint8&;
|
||||
inline auto operator[](unsigned addr) const -> const uint8&;
|
||||
|
||||
private:
|
||||
uint8* data_;
|
||||
unsigned size_;
|
||||
uint8* data_ = nullptr;
|
||||
unsigned size_ = 0;
|
||||
};
|
||||
|
||||
struct MappedRAM : Memory {
|
||||
inline void reset();
|
||||
inline void map(uint8*, unsigned);
|
||||
inline void copy(const stream& memory);
|
||||
inline void read(const stream& memory);
|
||||
inline auto reset() -> void;
|
||||
inline auto map(uint8*, unsigned) -> void;
|
||||
inline auto copy(const stream& memory) -> void;
|
||||
inline auto read(const stream& memory) -> void;
|
||||
|
||||
inline void write_protect(bool status);
|
||||
inline uint8* data();
|
||||
inline unsigned size() const;
|
||||
inline auto write_protect(bool status) -> void;
|
||||
inline auto data() -> uint8*;
|
||||
inline auto size() const -> unsigned;
|
||||
|
||||
inline uint8 read(unsigned addr);
|
||||
inline void write(unsigned addr, uint8 n);
|
||||
inline const uint8& operator[](unsigned addr) const;
|
||||
inline MappedRAM();
|
||||
inline auto read(unsigned addr) -> uint8;
|
||||
inline auto write(unsigned addr, uint8 n) -> void;
|
||||
inline auto operator[](unsigned addr) const -> const uint8&;
|
||||
|
||||
private:
|
||||
uint8* data_;
|
||||
unsigned size_;
|
||||
bool write_protect_;
|
||||
uint8* data_ = nullptr;
|
||||
unsigned size_ = 0;
|
||||
bool write_protect_ = false;
|
||||
};
|
||||
|
||||
struct Bus {
|
||||
alwaysinline static unsigned mirror(unsigned addr, unsigned size);
|
||||
alwaysinline static unsigned reduce(unsigned addr, unsigned mask);
|
||||
alwaysinline static auto mirror(unsigned addr, unsigned size) -> unsigned;
|
||||
alwaysinline static auto reduce(unsigned addr, unsigned mask) -> unsigned;
|
||||
|
||||
alwaysinline uint8 read(unsigned addr);
|
||||
alwaysinline void write(unsigned addr, uint8 data);
|
||||
Bus();
|
||||
~Bus();
|
||||
|
||||
uint8* lookup;
|
||||
uint32* target;
|
||||
alwaysinline auto read(unsigned addr) -> uint8;
|
||||
alwaysinline auto write(unsigned addr, uint8 data) -> void;
|
||||
|
||||
unsigned idcount;
|
||||
function<uint8 (unsigned)> reader[256];
|
||||
function<void (unsigned, uint8)> writer[256];
|
||||
|
||||
void map(
|
||||
auto reset() -> void;
|
||||
auto map() -> void;
|
||||
auto map(
|
||||
const function<uint8 (unsigned)>& reader,
|
||||
const function<void (unsigned, uint8)>& writer,
|
||||
unsigned banklo, unsigned bankhi,
|
||||
unsigned addrlo, unsigned addrhi,
|
||||
unsigned size = 0, unsigned base = 0, unsigned mask = 0
|
||||
);
|
||||
) -> void;
|
||||
|
||||
void map_reset();
|
||||
void map_xml();
|
||||
uint8* lookup = nullptr;
|
||||
uint32* target = nullptr;
|
||||
|
||||
Bus();
|
||||
~Bus();
|
||||
unsigned idcount = 0;
|
||||
function<uint8 (unsigned)> reader[256];
|
||||
function<void (unsigned, uint8)> writer[256];
|
||||
};
|
||||
|
||||
extern Bus bus;
|
||||
|
|
|
@ -169,14 +169,13 @@ void PPU::Background::run(bool screen) {
|
|||
if(hires == false) return;
|
||||
}
|
||||
|
||||
if(regs.mode == Mode::Inactive) return;
|
||||
if(regs.mode == Mode::Mode7) return run_mode7();
|
||||
|
||||
if(tile_counter-- == 0) {
|
||||
tile_counter = 7;
|
||||
get_tile();
|
||||
}
|
||||
|
||||
if(regs.mode == Mode::Mode7) return run_mode7();
|
||||
|
||||
uint8 palette = get_tile_color();
|
||||
if(x == 0) mosaic.hcounter = 1;
|
||||
if(x >= 0 && --mosaic.hcounter == 0) {
|
||||
|
|
|
@ -2,31 +2,25 @@
|
|||
|
||||
Scheduler scheduler;
|
||||
|
||||
void Scheduler::enter() {
|
||||
host_thread = co_active();
|
||||
co_switch(thread);
|
||||
}
|
||||
|
||||
void Scheduler::exit(ExitReason reason) {
|
||||
exit_reason = reason;
|
||||
thread = co_active();
|
||||
co_switch(host_thread);
|
||||
}
|
||||
|
||||
void Scheduler::debug() {
|
||||
exit(ExitReason::DebuggerEvent);
|
||||
}
|
||||
|
||||
void Scheduler::init() {
|
||||
auto Scheduler::init() -> void {
|
||||
host_thread = co_active();
|
||||
thread = cpu.thread;
|
||||
sync = SynchronizeMode::None;
|
||||
}
|
||||
|
||||
Scheduler::Scheduler() {
|
||||
host_thread = nullptr;
|
||||
thread = nullptr;
|
||||
exit_reason = ExitReason::UnknownEvent;
|
||||
auto Scheduler::enter() -> void {
|
||||
host_thread = co_active();
|
||||
co_switch(thread);
|
||||
}
|
||||
|
||||
auto Scheduler::exit(ExitReason reason) -> void {
|
||||
exit_reason = reason;
|
||||
thread = co_active();
|
||||
co_switch(host_thread);
|
||||
}
|
||||
|
||||
auto Scheduler::debug() -> void {
|
||||
exit(ExitReason::DebuggerEvent);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
struct Scheduler : property<Scheduler> {
|
||||
struct Scheduler {
|
||||
enum class SynchronizeMode : unsigned { None, CPU, All } sync;
|
||||
enum class ExitReason : unsigned { UnknownEvent, FrameEvent, SynchronizeEvent, DebuggerEvent };
|
||||
readonly<ExitReason> exit_reason;
|
||||
|
||||
cothread_t host_thread; //program thread (used to exit emulation)
|
||||
cothread_t thread; //active emulation thread (used to enter emulation)
|
||||
auto init() -> void;
|
||||
auto enter() -> void;
|
||||
auto exit(ExitReason) -> void;
|
||||
auto debug() -> void;
|
||||
|
||||
void enter();
|
||||
void exit(ExitReason);
|
||||
void debug();
|
||||
|
||||
void init();
|
||||
Scheduler();
|
||||
cothread_t host_thread = nullptr; //program thread (used to exit emulation)
|
||||
cothread_t thread = nullptr; //active emulation thread (used to enter emulation)
|
||||
ExitReason exit_reason = ExitReason::UnknownEvent;
|
||||
};
|
||||
|
||||
extern Scheduler scheduler;
|
||||
|
|
|
@ -5,23 +5,23 @@ namespace SuperFamicom {
|
|||
|
||||
SatellaviewCartridge satellaviewcartridge;
|
||||
|
||||
void SatellaviewCartridge::init() {
|
||||
auto SatellaviewCartridge::init() -> void {
|
||||
}
|
||||
|
||||
void SatellaviewCartridge::load() {
|
||||
auto SatellaviewCartridge::load() -> void {
|
||||
if(memory.size() == 0) {
|
||||
memory.map(allocate<uint8>(1024 * 1024, 0xff), 1024 * 1024);
|
||||
}
|
||||
}
|
||||
|
||||
void SatellaviewCartridge::unload() {
|
||||
auto SatellaviewCartridge::unload() -> void {
|
||||
memory.reset();
|
||||
}
|
||||
|
||||
void SatellaviewCartridge::power() {
|
||||
auto SatellaviewCartridge::power() -> void {
|
||||
}
|
||||
|
||||
void SatellaviewCartridge::reset() {
|
||||
auto SatellaviewCartridge::reset() -> void {
|
||||
regs.command = 0;
|
||||
regs.write_old = 0x00;
|
||||
regs.write_new = 0x00;
|
||||
|
@ -32,11 +32,11 @@ void SatellaviewCartridge::reset() {
|
|||
memory.write_protect(!regs.write_enable);
|
||||
}
|
||||
|
||||
unsigned SatellaviewCartridge::size() const {
|
||||
auto SatellaviewCartridge::size() const -> unsigned {
|
||||
return memory.size();
|
||||
}
|
||||
|
||||
uint8 SatellaviewCartridge::read(unsigned addr) {
|
||||
auto SatellaviewCartridge::read(unsigned addr) -> uint8 {
|
||||
if(readonly) return memory.read(bus.mirror(addr, memory.size()));
|
||||
|
||||
if(addr == 0x0002) {
|
||||
|
@ -65,7 +65,7 @@ uint8 SatellaviewCartridge::read(unsigned addr) {
|
|||
return memory.read(addr);
|
||||
}
|
||||
|
||||
void SatellaviewCartridge::write(unsigned addr, uint8 data) {
|
||||
auto SatellaviewCartridge::write(unsigned addr, uint8 data) -> void {
|
||||
if(readonly) return;
|
||||
|
||||
if((addr & 0xff0000) == 0) {
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
struct SatellaviewCartridge : Memory {
|
||||
auto init() -> void;
|
||||
auto load() -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto size() const -> unsigned;
|
||||
auto read(unsigned addr) -> uint8;
|
||||
auto write(unsigned addr, uint8 data) -> void;
|
||||
|
||||
MappedRAM memory;
|
||||
bool readonly;
|
||||
|
||||
void init();
|
||||
void load();
|
||||
void unload();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
unsigned size() const;
|
||||
uint8 read(unsigned addr);
|
||||
void write(unsigned addr, uint8 data);
|
||||
|
||||
private:
|
||||
struct {
|
||||
unsigned command;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#ifdef SUFAMITURBO_CPP
|
||||
|
||||
void SufamiTurboCartridge::serialize(serializer& s) {
|
||||
auto SufamiTurboCartridge::serialize(serializer& s) -> void {
|
||||
s.array(ram.data(), ram.size());
|
||||
}
|
||||
|
||||
|
|
|
@ -7,10 +7,10 @@ namespace SuperFamicom {
|
|||
SufamiTurboCartridge sufamiturboA;
|
||||
SufamiTurboCartridge sufamiturboB;
|
||||
|
||||
void SufamiTurboCartridge::load() {
|
||||
auto SufamiTurboCartridge::load() -> void {
|
||||
}
|
||||
|
||||
void SufamiTurboCartridge::unload() {
|
||||
auto SufamiTurboCartridge::unload() -> void {
|
||||
rom.reset();
|
||||
ram.reset();
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
struct SufamiTurboCartridge {
|
||||
auto load() -> void;
|
||||
auto unload() -> void;
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
MappedRAM rom;
|
||||
MappedRAM ram;
|
||||
|
||||
void load();
|
||||
void unload();
|
||||
void serialize(serializer&);
|
||||
};
|
||||
|
||||
extern SufamiTurboCartridge sufamiturboA;
|
||||
|
|
|
@ -18,7 +18,7 @@ void System::run() {
|
|||
scheduler.sync = Scheduler::SynchronizeMode::None;
|
||||
|
||||
scheduler.enter();
|
||||
if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) {
|
||||
if(scheduler.exit_reason == Scheduler::ExitReason::FrameEvent) {
|
||||
video.update();
|
||||
}
|
||||
}
|
||||
|
@ -54,8 +54,8 @@ void System::runtosave() {
|
|||
void System::runthreadtosave() {
|
||||
while(true) {
|
||||
scheduler.enter();
|
||||
if(scheduler.exit_reason() == Scheduler::ExitReason::SynchronizeEvent) break;
|
||||
if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) {
|
||||
if(scheduler.exit_reason == Scheduler::ExitReason::SynchronizeEvent) break;
|
||||
if(scheduler.exit_reason == Scheduler::ExitReason::FrameEvent) {
|
||||
video.update();
|
||||
}
|
||||
}
|
||||
|
@ -93,13 +93,12 @@ void System::term() {
|
|||
}
|
||||
|
||||
void System::load() {
|
||||
string manifest = string::read({interface->path(ID::System), "manifest.bml"});
|
||||
auto document = BML::unserialize(manifest);
|
||||
//string manifest = string::read({interface->path(ID::System), "manifest.bml"});
|
||||
interface->loadRequest(ID::SystemManifest, "manifest.bml", true);
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
|
||||
auto iplrom = document["system/smp/rom/name"].text();
|
||||
interface->loadRequest(ID::IPLROM, iplrom);
|
||||
if(!file::exists({interface->path(ID::System), iplrom})) {
|
||||
interface->notify("Error: required Super Famicom firmware ipl.rom not found.\n");
|
||||
if(auto iplrom = document["system/smp/rom/name"].text()) {
|
||||
interface->loadRequest(ID::IPLROM, iplrom, true);
|
||||
}
|
||||
|
||||
region = configuration.region;
|
||||
|
@ -113,8 +112,8 @@ void System::load() {
|
|||
|
||||
audio.coprocessor_enable(false);
|
||||
|
||||
bus.map_reset();
|
||||
bus.map_xml();
|
||||
bus.reset();
|
||||
bus.map();
|
||||
|
||||
cpu.enable();
|
||||
ppu.enable();
|
||||
|
|
|
@ -29,6 +29,10 @@ struct System : property<System> {
|
|||
|
||||
System();
|
||||
|
||||
struct Information {
|
||||
string manifest;
|
||||
} information;
|
||||
|
||||
private:
|
||||
void runthreadtosave();
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//request from emulation core to load non-volatile media folder
|
||||
auto Program::loadRequest(unsigned id, string name, string type) -> void {
|
||||
auto Program::loadRequest(unsigned id, string name, string type, bool required) -> void {
|
||||
string location = BrowserDialog()
|
||||
.setTitle({"Load ", name})
|
||||
.setPath({config->library.location, name})
|
||||
|
@ -13,16 +13,38 @@ auto Program::loadRequest(unsigned id, string name, string type) -> void {
|
|||
}
|
||||
|
||||
//request from emulation core to load non-volatile media file
|
||||
auto Program::loadRequest(unsigned id, string path) -> void {
|
||||
string location = {mediaPaths(emulator->group(id)), path};
|
||||
if(!file::exists(location)) return;
|
||||
mmapstream stream{location};
|
||||
return emulator->load(id, stream);
|
||||
auto Program::loadRequest(unsigned id, string filename, bool required) -> void {
|
||||
string pathname = mediaPaths(emulator->group(id));
|
||||
string location = {pathname, filename};
|
||||
if(file::exists(location)) {
|
||||
mmapstream stream{location};
|
||||
return emulator->load(id, stream);
|
||||
}
|
||||
if(filename == "manifest.bml") {
|
||||
string manifest;
|
||||
if(auto fp = popen(string{"icarus -m \"", pathname, "\""}, "r")) {
|
||||
while(true) {
|
||||
auto byte = fgetc(fp);
|
||||
if(byte == EOF) break;
|
||||
manifest.append((char)byte);
|
||||
}
|
||||
pclose(fp);
|
||||
}
|
||||
if(manifest) {
|
||||
memorystream stream{manifest.binary(), manifest.size()};
|
||||
return emulator->load(id, stream);
|
||||
}
|
||||
}
|
||||
if(required) MessageDialog().setTitle("higan").setText({
|
||||
"Missing required file: ", location.filename(), "\n\n",
|
||||
"From location:\n", location.pathname()
|
||||
}).error();
|
||||
}
|
||||
|
||||
//request from emulation core to save non-volatile media file
|
||||
auto Program::saveRequest(unsigned id, string path) -> void {
|
||||
string location = {mediaPaths(emulator->group(id)), path};
|
||||
auto Program::saveRequest(unsigned id, string filename) -> void {
|
||||
string pathname = mediaPaths(emulator->group(id));
|
||||
string location = {pathname, filename};
|
||||
filestream stream{location, file::mode::write};
|
||||
return emulator->save(id, stream);
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ struct Program : Emulator::Interface::Bind {
|
|||
auto quit() -> void;
|
||||
|
||||
//interface.cpp
|
||||
auto loadRequest(unsigned id, string name, string type) -> void override;
|
||||
auto loadRequest(unsigned id, string path) -> void override;
|
||||
auto loadRequest(unsigned id, string name, string type, bool required) -> void override;
|
||||
auto loadRequest(unsigned id, string path, bool required) -> void override;
|
||||
auto saveRequest(unsigned id, string path) -> void override;
|
||||
auto videoColor(unsigned source, uint16 alpha, uint16 red, uint16 green, uint16 blue) -> uint32 override;
|
||||
auto videoRefresh(const uint32* palette, const uint32* data, unsigned pitch, unsigned width, unsigned height) -> void override;
|
||||
|
|
Loading…
Reference in New Issue