diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 3c0ebc41..a096703f 100755 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -3,7 +3,7 @@ namespace Emulator { static const char Name[] = "higan"; - static const char Version[] = "091.09"; + static const char Version[] = "091.10"; static const char Author[] = "byuu"; static const char License[] = "GPLv3"; } diff --git a/higan/emulator/interface.hpp b/higan/emulator/interface.hpp index 2cf11968..efef6592 100755 --- a/higan/emulator/interface.hpp +++ b/higan/emulator/interface.hpp @@ -56,6 +56,7 @@ struct Interface { virtual void audioSample(int16_t, int16_t) {} virtual int16_t inputPoll(unsigned, unsigned, unsigned) { return 0; } virtual unsigned dipSettings(const Markup::Node&) { return 0; } + virtual string scoreServer() { return ""; } virtual string path(unsigned) { return ""; } virtual void notify(const string &text) { print(text, "\n"); } } *bind; @@ -69,6 +70,7 @@ struct Interface { void audioSample(int16_t lsample, int16_t rsample) { return bind->audioSample(lsample, rsample); } int16_t inputPoll(unsigned port, unsigned device, unsigned input) { return bind->inputPoll(port, device, input); } unsigned dipSettings(const Markup::Node &node) { return bind->dipSettings(node); } + string scoreServer() { return bind->scoreServer(); } string path(unsigned group) { return bind->path(group); } template void notify(Args&... args) { return bind->notify({std::forward(args)...}); } diff --git a/higan/nall/string/platform.hpp b/higan/nall/string/platform.hpp index d7e701ee..5c44a313 100755 --- a/higan/nall/string/platform.hpp +++ b/higan/nall/string/platform.hpp @@ -6,12 +6,12 @@ string activepath() { string result; #ifdef _WIN32 wchar_t path[PATH_MAX] = L""; - _wgetcwd(path, PATH_MAX); + auto unused = _wgetcwd(path, PATH_MAX); result = (const char*)utf8_t(path); result.transform("\\", "/"); #else char path[PATH_MAX] = ""; - getcwd(path, PATH_MAX); + auto unused = getcwd(path, PATH_MAX); result = path; #endif if(result.empty()) result = "."; diff --git a/higan/sfc/Makefile b/higan/sfc/Makefile index 81e59e8b..e0625b21 100755 --- a/higan/sfc/Makefile +++ b/higan/sfc/Makefile @@ -6,7 +6,7 @@ sfc_objects += sfc-sa1 sfc-superfx sfc_objects += sfc-armdsp sfc-hitachidsp sfc-necdsp sfc_objects += sfc-epsonrtc sfc-sharprtc sfc_objects += sfc-spc7110 sfc-sdd1 sfc-obc1 -sfc_objects += sfc-msu1 +sfc_objects += sfc-hsu1 sfc-msu1 objects += $(sfc_objects) ifeq ($(profile),accuracy) @@ -60,4 +60,5 @@ obj/sfc-spc7110.o : $(sfc)/chip/spc7110/spc7110.cpp $(sfc)/chip/spc7110/* obj/sfc-sdd1.o : $(sfc)/chip/sdd1/sdd1.cpp $(sfc)/chip/sdd1/* obj/sfc-obc1.o : $(sfc)/chip/obc1/obc1.cpp $(sfc)/chip/obc1/* +obj/sfc-hsu1.o : $(sfc)/chip/hsu1/hsu1.cpp $(sfc)/chip/hsu1/* obj/sfc-msu1.o : $(sfc)/chip/msu1/msu1.cpp $(sfc)/chip/msu1/* diff --git a/higan/sfc/cartridge/cartridge.cpp b/higan/sfc/cartridge/cartridge.cpp index 1a0370f8..75f58edf 100755 --- a/higan/sfc/cartridge/cartridge.cpp +++ b/higan/sfc/cartridge/cartridge.cpp @@ -26,6 +26,7 @@ void Cartridge::load(const string &manifest) { has_spc7110 = false; has_sdd1 = false; has_obc1 = false; + has_hsu1 = false; has_msu1 = false; this->manifest = manifest; diff --git a/higan/sfc/cartridge/cartridge.hpp b/higan/sfc/cartridge/cartridge.hpp index 33372d25..042a00ed 100755 --- a/higan/sfc/cartridge/cartridge.hpp +++ b/higan/sfc/cartridge/cartridge.hpp @@ -38,6 +38,7 @@ struct Cartridge : property { readonly has_spc7110; readonly has_sdd1; readonly has_obc1; + readonly has_hsu1; readonly has_msu1; struct Mapping { @@ -93,6 +94,7 @@ private: void parse_markup_spc7110(Markup::Node); void parse_markup_sdd1(Markup::Node); void parse_markup_obc1(Markup::Node); + void parse_markup_hsu1(Markup::Node); void parse_markup_msu1(Markup::Node); }; diff --git a/higan/sfc/cartridge/markup.cpp b/higan/sfc/cartridge/markup.cpp index d8e456ed..8e5eae02 100755 --- a/higan/sfc/cartridge/markup.cpp +++ b/higan/sfc/cartridge/markup.cpp @@ -25,6 +25,7 @@ void Cartridge::parse_markup(const char *markup) { parse_markup_spc7110(board["spc7110"]); parse_markup_sdd1(board["sdd1"]); parse_markup_obc1(board["obc1"]); + parse_markup_hsu1(board["hsu1"]); parse_markup_msu1(board["msu1"]); } @@ -564,6 +565,21 @@ void Cartridge::parse_markup_obc1(Markup::Node root) { } } +void Cartridge::parse_markup_hsu1(Markup::Node root) { + if(root.exists() == false) return; + has_hsu1 = true; + + for(auto &node : root) { + if(node.name != "map") continue; + + if(node["id"].data == "io") { + Mapping m({&HSU1::read, &hsu1}, {&HSU1::write, &hsu1}); + parse_markup_map(m, node); + mapping.append(m); + } + } +} + void Cartridge::parse_markup_msu1(Markup::Node root) { if(root.exists() == false) return; has_msu1 = true; diff --git a/higan/sfc/chip/chip.hpp b/higan/sfc/chip/chip.hpp index b5c12532..6d7637a7 100755 --- a/higan/sfc/chip/chip.hpp +++ b/higan/sfc/chip/chip.hpp @@ -23,6 +23,7 @@ struct Coprocessor : Thread { #include #include +#include #include void Coprocessor::step(unsigned clocks) { diff --git a/higan/sfc/chip/hsu1/hsu1.cpp b/higan/sfc/chip/hsu1/hsu1.cpp new file mode 100644 index 00000000..0ccb9cf7 --- /dev/null +++ b/higan/sfc/chip/hsu1/hsu1.cpp @@ -0,0 +1,66 @@ +#include + +#define HSU1_CPP +namespace SuperFamicom { + +#include "serialization.cpp" +HSU1 hsu1; + +void HSU1::init() { +} + +void HSU1::load() { +} + +void HSU1::unload() { +} + +void HSU1::power() { +} + +void HSU1::reset() { + packetlength = 0; +} + +uint8 HSU1::read(unsigned addr) { + return cpu.regs.mdr; +} + +void HSU1::write(unsigned addr, uint8 data) { + packet[packetlength] = data; + if(packetlength < sizeof(packet)) packetlength++; + if(data) return; + + lstring side = interface->scoreServer().split<1>("@"); + string username = side(0).split<1>(":")(0); + string password = side(0).split<1>(":")(1); + string servername = side(1).ltrim<1>("http://"); + side = servername.split<1>("/"); + string host = side(0).split<1>(":")(0); + string port = side(0).split<1>(":")(1); + string path = side(1); + if(port.empty()) port = "80"; + + http server; + if(server.connect(host, decimal(port))) { + string content = { + "username:", username, "\r\n", + "password:", password, "\r\n", + "sha256:", interface->sha256(), "\r\n", + "data:", (const char*)packet, "\r\n", + "emulator:bsnes\r\n" + }; + string packet = { + "POST ", path, " HTTP/1.0\r\n", + "Host: ", host, "\r\n", + "Connection: close\r\n", + "Content-Type: text/plain; charset=utf-8\r\n", + "Content-Length: ", content.length(), "\r\n", + "\r\n", + content + }; + server.send(packet); + } +} + +} diff --git a/higan/sfc/chip/hsu1/hsu1.hpp b/higan/sfc/chip/hsu1/hsu1.hpp new file mode 100644 index 00000000..13e79cb8 --- /dev/null +++ b/higan/sfc/chip/hsu1/hsu1.hpp @@ -0,0 +1,18 @@ +struct HSU1 { + void init(); + void load(); + void unload(); + void power(); + void reset(); + + uint8 read(unsigned addr); + void write(unsigned addr, uint8 data); + + void serialize(serializer&); + +private: + uint8 packet[512]; + unsigned packetlength; +}; + +extern HSU1 hsu1; diff --git a/higan/sfc/chip/hsu1/serialization.cpp b/higan/sfc/chip/hsu1/serialization.cpp new file mode 100644 index 00000000..257a3f38 --- /dev/null +++ b/higan/sfc/chip/hsu1/serialization.cpp @@ -0,0 +1,8 @@ +#ifdef HSU1_CPP + +void HSU1::serialize(serializer &s) { + s.array(packet); + s.integer(packetlength); +} + +#endif diff --git a/higan/sfc/memory/memory-inline.hpp b/higan/sfc/memory/memory-inline.hpp index c72d5bbc..e07bd098 100755 --- a/higan/sfc/memory/memory-inline.hpp +++ b/higan/sfc/memory/memory-inline.hpp @@ -73,12 +73,14 @@ unsigned Bus::mirror(unsigned addr, unsigned size) { return base; } -unsigned Bus::recode(unsigned addr, unsigned mask) { +unsigned Bus::reduce(unsigned addr, unsigned mask) { + unsigned result = 0, length = 0; for(unsigned n = 0; n < 24; n++) { unsigned bit = 1 << n; - if(mask & bit) addr = ((addr >> (n + 1)) << n) | (addr & (bit - 1)); + if(mask & bit) continue; + result |= (bool)(addr & bit) << length++; } - return addr; + return result; } uint8 Bus::read(unsigned addr) { diff --git a/higan/sfc/memory/memory.cpp b/higan/sfc/memory/memory.cpp index f9de79d8..105059df 100755 --- a/higan/sfc/memory/memory.cpp +++ b/higan/sfc/memory/memory.cpp @@ -22,7 +22,7 @@ void Bus::map( for(unsigned bank = banklo; bank <= bankhi; bank++) { for(unsigned addr = addrlo; addr <= addrhi; addr++) { - unsigned offset = recode(bank << 16 | addr, mask); + 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; diff --git a/higan/sfc/memory/memory.hpp b/higan/sfc/memory/memory.hpp index b590262f..34e483cf 100755 --- a/higan/sfc/memory/memory.hpp +++ b/higan/sfc/memory/memory.hpp @@ -44,7 +44,7 @@ private: struct Bus { alwaysinline static unsigned mirror(unsigned addr, unsigned size); - alwaysinline static unsigned recode(unsigned addr, unsigned mask); + alwaysinline static unsigned reduce(unsigned addr, unsigned mask); alwaysinline uint8 read(unsigned addr); alwaysinline void write(unsigned addr, uint8 data); diff --git a/higan/sfc/system/serialization.cpp b/higan/sfc/system/serialization.cpp index 970164ca..66231c92 100755 --- a/higan/sfc/system/serialization.cpp +++ b/higan/sfc/system/serialization.cpp @@ -71,6 +71,7 @@ void System::serialize_all(serializer &s) { if(cartridge.has_spc7110()) spc7110.serialize(s); if(cartridge.has_sdd1()) sdd1.serialize(s); if(cartridge.has_obc1()) obc1.serialize(s); + if(cartridge.has_hsu1()) hsu1.serialize(s); if(cartridge.has_msu1()) msu1.serialize(s); } diff --git a/higan/sfc/system/system.cpp b/higan/sfc/system/system.cpp index 08afe2f7..4ec55718 100755 --- a/higan/sfc/system/system.cpp +++ b/higan/sfc/system/system.cpp @@ -80,6 +80,7 @@ void System::init() { spc7110.init(); sdd1.init(); obc1.init(); + hsu1.init(); msu1.init(); video.init(); @@ -136,6 +137,7 @@ void System::load() { if(cartridge.has_spc7110()) spc7110.load(); if(cartridge.has_sdd1()) sdd1.load(); if(cartridge.has_obc1()) obc1.load(); + if(cartridge.has_hsu1()) hsu1.load(); if(cartridge.has_msu1()) msu1.load(); serialize_init(); @@ -160,6 +162,7 @@ void System::unload() { if(cartridge.has_spc7110()) spc7110.unload(); if(cartridge.has_sdd1()) sdd1.unload(); if(cartridge.has_obc1()) obc1.unload(); + if(cartridge.has_hsu1()) hsu1.unload(); if(cartridge.has_msu1()) msu1.unload(); } @@ -187,6 +190,7 @@ void System::power() { if(cartridge.has_spc7110()) spc7110.power(); if(cartridge.has_sdd1()) sdd1.power(); if(cartridge.has_obc1()) obc1.power(); + if(cartridge.has_hsu1()) hsu1.power(); if(cartridge.has_msu1()) msu1.power(); reset(); @@ -214,6 +218,7 @@ void System::reset() { if(cartridge.has_spc7110()) spc7110.reset(); if(cartridge.has_sdd1()) sdd1.reset(); if(cartridge.has_obc1()) obc1.reset(); + if(cartridge.has_hsu1()) hsu1.reset(); if(cartridge.has_msu1()) msu1.reset(); if(cartridge.has_gb_slot()) cpu.coprocessors.append(&icd2); diff --git a/higan/target-ethos/configuration/configuration.cpp b/higan/target-ethos/configuration/configuration.cpp index 392e4eec..c4bae5fd 100755 --- a/higan/target-ethos/configuration/configuration.cpp +++ b/higan/target-ethos/configuration/configuration.cpp @@ -26,6 +26,9 @@ Configuration::Configuration() { append(input.focusAllow = false, "Input::Focus::AllowInput"); append(timing.video = 60.0, "Timing::Video"); append(timing.audio = 48000.0, "Timing::Audio"); + append(highScores.hostname = "", "HighScores::Hostname"); + append(highScores.username = "", "HighScores::Username"); + append(highScores.password = "", "HighScores::Password"); append(path.game = {userpath(), "Emulation/"}, "Path::Game"); load(); } diff --git a/higan/target-ethos/configuration/configuration.hpp b/higan/target-ethos/configuration/configuration.hpp index 8f20e3e9..af18b9af 100755 --- a/higan/target-ethos/configuration/configuration.hpp +++ b/higan/target-ethos/configuration/configuration.hpp @@ -35,6 +35,12 @@ struct Configuration : configuration { double audio; } timing; + struct HighScores { + string hostname; + string username; + string password; + } highScores; + struct Path { string game; } path; diff --git a/higan/target-ethos/ethos.cpp b/higan/target-ethos/ethos.cpp index 49986a46..0e27a373 100755 --- a/higan/target-ethos/ethos.cpp +++ b/higan/target-ethos/ethos.cpp @@ -97,6 +97,7 @@ Application::Application(int argc, char **argv) { inputSettings = new InputSettings; hotkeySettings = new HotkeySettings; timingSettings = new TimingSettings; + scoreSettings = new ScoreSettings; driverSettings = new DriverSettings; settings = new Settings; cheatDatabase = new CheatDatabase; diff --git a/higan/target-ethos/interface/interface.cpp b/higan/target-ethos/interface/interface.cpp index a8ba194f..56941a63 100755 --- a/higan/target-ethos/interface/interface.cpp +++ b/higan/target-ethos/interface/interface.cpp @@ -111,6 +111,14 @@ unsigned Interface::dipSettings(const Markup::Node &node) { return dipSwitches->run(node); } +string Interface::scoreServer() { + return string { + config->highScores.username, ":", + config->highScores.password, "@", + config->highScores.hostname + }; +} + string Interface::path(unsigned group) { return utility->path(group); } diff --git a/higan/target-ethos/interface/interface.hpp b/higan/target-ethos/interface/interface.hpp index ba34746e..d5c0af55 100755 --- a/higan/target-ethos/interface/interface.hpp +++ b/higan/target-ethos/interface/interface.hpp @@ -7,6 +7,7 @@ struct Interface : Emulator::Interface::Bind { void audioSample(int16_t lsample, int16_t rsample); int16_t inputPoll(unsigned port, unsigned device, unsigned input); unsigned dipSettings(const Markup::Node &node); + string scoreServer(); string path(unsigned group); void notify(const string &text); }; diff --git a/higan/target-ethos/settings/scores.cpp b/higan/target-ethos/settings/scores.cpp new file mode 100644 index 00000000..56c26f0b --- /dev/null +++ b/higan/target-ethos/settings/scores.cpp @@ -0,0 +1,32 @@ +ScoreSettings *scoreSettings = nullptr; + +ScoreSettings::ScoreSettings() { + title.setFont(application->titleFont); + title.setText("High Score Server Configuration"); + hostLabel.setText("Hostname:"); + userLabel.setText("Username:"); + passLabel.setText("Password:"); + + unsigned width = max( + Font(application->normalFont).geometry("Hostname:").width, + Font(application->normalFont).geometry("Username:").width + ); + + append(title, {~0, 0}, 5); + append(serverLayout, {~0, 0}, 5); + serverLayout.append(hostLabel, {width, 0}, 5); + serverLayout.append(hostEdit, {~0, 0}); + append(loginLayout, {~0, 0}); + loginLayout.append(userLabel, {width, 0}, 5); + loginLayout.append(userEdit, {~0, 0}, 5); + loginLayout.append(passLabel, {0, 0}, 5); + loginLayout.append(passEdit, {~0, 0}); + + hostEdit.setText(config->highScores.hostname); + userEdit.setText(config->highScores.username); + passEdit.setText(config->highScores.password); + + hostEdit.onChange = [&] { config->highScores.hostname = hostEdit.text(); }; + userEdit.onChange = [&] { config->highScores.username = userEdit.text(); }; + passEdit.onChange = [&] { config->highScores.password = passEdit.text(); }; +} diff --git a/higan/target-ethos/settings/scores.hpp b/higan/target-ethos/settings/scores.hpp new file mode 100644 index 00000000..43f46324 --- /dev/null +++ b/higan/target-ethos/settings/scores.hpp @@ -0,0 +1,15 @@ +struct ScoreSettings : SettingsLayout { + Label title; + HorizontalLayout serverLayout; + Label hostLabel; + LineEdit hostEdit; + HorizontalLayout loginLayout; + Label userLabel; + LineEdit userEdit; + Label passLabel; + LineEdit passEdit; + + ScoreSettings(); +}; + +extern ScoreSettings *scoreSettings; diff --git a/higan/target-ethos/settings/settings.cpp b/higan/target-ethos/settings/settings.cpp index 87b4545e..b9f6cd2f 100755 --- a/higan/target-ethos/settings/settings.cpp +++ b/higan/target-ethos/settings/settings.cpp @@ -4,6 +4,7 @@ #include "input.cpp" #include "hotkey.cpp" #include "timing.cpp" +#include "scores.cpp" #include "driver.cpp" Settings *settings = nullptr; @@ -31,6 +32,7 @@ Settings::Settings() { panelList.append("Input"); panelList.append("Hotkeys"); panelList.append("Timing"); + panelList.append("Scores"); panelList.append("Driver"); append(layout); @@ -40,6 +42,7 @@ Settings::Settings() { append(*inputSettings); append(*hotkeySettings); append(*timingSettings); + append(*scoreSettings); append(*driverSettings); onClose = [&] { @@ -59,6 +62,7 @@ void Settings::panelChanged() { inputSettings->setVisible(false); hotkeySettings->setVisible(false); timingSettings->setVisible(false); + scoreSettings->setVisible(false); driverSettings->setVisible(false); if(panelList.selected() == false) return; @@ -68,6 +72,7 @@ void Settings::panelChanged() { case 2: return inputSettings->setVisible(); case 3: return hotkeySettings->setVisible(); case 4: return timingSettings->setVisible(); - case 5: return driverSettings->setVisible(); + case 5: return scoreSettings->setVisible(); + case 6: return driverSettings->setVisible(); } } diff --git a/higan/target-ethos/settings/settings.hpp b/higan/target-ethos/settings/settings.hpp index d436cdc1..3f6ceee1 100755 --- a/higan/target-ethos/settings/settings.hpp +++ b/higan/target-ethos/settings/settings.hpp @@ -11,6 +11,7 @@ struct SettingsLayout : HorizontalLayout { #include "input.hpp" #include "hotkey.hpp" #include "timing.hpp" +#include "scores.hpp" #include "driver.hpp" struct Settings : Window {