mirror of https://github.com/bsnes-emu/bsnes.git
Update to v094r18 release.
byuu says: Okay yeah, lots of SNES coprocessor games were horribly broken. They should be fixed now with the below changes: Old syntax: auto programROM = root["rom[0]/name"].text(); auto dataROM = root["rom[1]/name"].text(); load_memory(root["ram[0]"]); New syntax: auto rom = root.find("rom"); auto ram = root.find("ram"); auto programROM = rom(0)["name"].text(); auto dataROM = rom(1)["name"].text(); load_memory(ram(0)); Since I'm now relying on the XShm driver, which is multi-threaded, I'm now compiling higan with -fopenmp. On FreeBSD, this requires linking with -Wl,-rpath=/usr/local/lib -Wl,-rpath=/usr/local/lib/gcc49 to get the right version of GOMP. This gives a pretty nice speed boost for XShm, I go from around 101fps to 111fps at 4x scale on the accuracy profile. The combination of inlining the accuracy-PPU and parallelizing the XShm renderer about evenly compensates now for the ~20% CPU overclock I gave up a while ago. The WIP also has some other niceties from the newer version of nall. Most noticeably, cheat code database searching is now instantaneous. No more 3-second stall.
This commit is contained in:
parent
39ca8a2fab
commit
fc8eba133d
15
GNUmakefile
15
GNUmakefile
|
@ -12,8 +12,8 @@ target := tomoko
|
||||||
# console := true
|
# console := true
|
||||||
|
|
||||||
# compiler
|
# compiler
|
||||||
flags += -I. -O3
|
flags += -I. -O3 -fopenmp
|
||||||
link +=
|
link += -fopenmp
|
||||||
objects := libco
|
objects := libco
|
||||||
|
|
||||||
# profile-guided optimization mode
|
# profile-guided optimization mode
|
||||||
|
@ -39,15 +39,20 @@ ifeq ($(platform),windows)
|
||||||
link += -mwindows
|
link += -mwindows
|
||||||
endif
|
endif
|
||||||
link += -mthreads -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32 -lole32 -lws2_32
|
link += -mthreads -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32 -lole32 -lws2_32
|
||||||
link += -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc
|
link += -Wl,-enable-auto-import
|
||||||
|
link += -Wl,-enable-runtime-pseudo-reloc
|
||||||
else ifeq ($(platform),macosx)
|
else ifeq ($(platform),macosx)
|
||||||
flags += -march=native
|
flags += -march=native
|
||||||
else ifeq ($(platform),linux)
|
else ifeq ($(platform),linux)
|
||||||
flags += -march=native
|
flags += -march=native
|
||||||
link += -Wl,-export-dynamic -lX11 -lXext -ldl
|
link += -Wl,-export-dynamic
|
||||||
|
link += -lX11 -lXext -ldl
|
||||||
else ifeq ($(platform),bsd)
|
else ifeq ($(platform),bsd)
|
||||||
flags += -march=native
|
flags += -march=native
|
||||||
link += -Wl,-export-dynamic -lX11 -lXext
|
link += -Wl,-rpath=/usr/local/lib
|
||||||
|
link += -Wl,-rpath=/usr/local/lib/gcc49
|
||||||
|
link += -Wl,-export-dynamic
|
||||||
|
link += -lX11 -lXext
|
||||||
else
|
else
|
||||||
$(error unsupported platform.)
|
$(error unsupported platform.)
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const char Name[] = "higan";
|
static const char Name[] = "higan";
|
||||||
static const char Version[] = "094.17";
|
static const char Version[] = "094.18";
|
||||||
static const char Author[] = "byuu";
|
static const char Author[] = "byuu";
|
||||||
static const char License[] = "GPLv3";
|
static const char License[] = "GPLv3";
|
||||||
static const char Website[] = "http://byuu.org/";
|
static const char Website[] = "http://byuu.org/";
|
||||||
|
|
|
@ -94,10 +94,10 @@ Board::Board(Markup::Node& document) {
|
||||||
auto crom = cartridge["chr/rom"];
|
auto crom = cartridge["chr/rom"];
|
||||||
auto cram = cartridge["chr/ram"];
|
auto cram = cartridge["chr/ram"];
|
||||||
|
|
||||||
prgrom.size = prom["size"].text().numeral();
|
prgrom.size = prom["size"].decimal();
|
||||||
prgram.size = pram["size"].text().numeral();
|
prgram.size = pram["size"].decimal();
|
||||||
chrrom.size = crom["size"].text().numeral();
|
chrrom.size = crom["size"].decimal();
|
||||||
chrram.size = cram["size"].text().numeral();
|
chrram.size = cram["size"].decimal();
|
||||||
|
|
||||||
if(prgrom.size) prgrom.data = new uint8[prgrom.size]();
|
if(prgrom.size) prgrom.data = new uint8[prgrom.size]();
|
||||||
if(prgram.size) prgram.data = new uint8[prgram.size]();
|
if(prgram.size) prgram.data = new uint8[prgram.size]();
|
||||||
|
|
|
@ -74,9 +74,9 @@ void Cartridge::load(System::Revision revision) {
|
||||||
|
|
||||||
//Super Game Boy core loads memory from Super Famicom core
|
//Super Game Boy core loads memory from Super Famicom core
|
||||||
if(revision != System::Revision::SuperGameBoy) {
|
if(revision != System::Revision::SuperGameBoy) {
|
||||||
if(rom["name"]) interface->loadRequest(ID::ROM, rom["name"].text());
|
if(auto name = rom["name"].text()) interface->loadRequest(ID::ROM, name);
|
||||||
if(ram["name"]) interface->loadRequest(ID::RAM, ram["name"].text());
|
if(auto name = ram["name"].text()) interface->loadRequest(ID::RAM, name);
|
||||||
if(ram["name"]) memory.append({ID::RAM, ram["name"].text()});
|
if(auto name = ram["name"].text()) memory.append({ID::RAM, name});
|
||||||
}
|
}
|
||||||
|
|
||||||
information.romsize = rom["size"].decimal();
|
information.romsize = rom["size"].decimal();
|
||||||
|
|
|
@ -1,152 +0,0 @@
|
||||||
#ifndef NALL_COMPOSITOR_HPP
|
|
||||||
#define NALL_COMPOSITOR_HPP
|
|
||||||
|
|
||||||
#include <nall/intrinsics.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct compositor {
|
|
||||||
inline static bool enabled();
|
|
||||||
inline static bool enable(bool status);
|
|
||||||
|
|
||||||
#if defined(PLATFORM_XORG)
|
|
||||||
enum class Compositor : unsigned { Unknown, Metacity, Xfwm4 };
|
|
||||||
inline static Compositor detect();
|
|
||||||
|
|
||||||
inline static bool enabled_metacity();
|
|
||||||
inline static bool enable_metacity(bool status);
|
|
||||||
|
|
||||||
inline static bool enabled_xfwm4();
|
|
||||||
inline static bool enable_xfwm4(bool status);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(PLATFORM_XORG)
|
|
||||||
|
|
||||||
//Metacity
|
|
||||||
|
|
||||||
bool compositor::enabled_metacity() {
|
|
||||||
FILE* fp = popen("gconftool-2 --get /apps/metacity/general/compositing_manager", "r");
|
|
||||||
if(!fp) return false;
|
|
||||||
|
|
||||||
char buffer[512];
|
|
||||||
if(!fgets(buffer, sizeof buffer, fp)) return false;
|
|
||||||
|
|
||||||
if(!memcmp(buffer, "true", 4)) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compositor::enable_metacity(bool status) {
|
|
||||||
FILE* fp;
|
|
||||||
if(status) {
|
|
||||||
fp = popen("gconftool-2 --set --type bool /apps/metacity/general/compositing_manager true", "r");
|
|
||||||
} else {
|
|
||||||
fp = popen("gconftool-2 --set --type bool /apps/metacity/general/compositing_manager false", "r");
|
|
||||||
}
|
|
||||||
if(!fp) return false;
|
|
||||||
pclose(fp);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Xfwm4
|
|
||||||
|
|
||||||
bool compositor::enabled_xfwm4() {
|
|
||||||
FILE* fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing'", "r");
|
|
||||||
if(!fp) return false;
|
|
||||||
|
|
||||||
char buffer[512];
|
|
||||||
if(!fgets(buffer, sizeof buffer, fp)) return false;
|
|
||||||
|
|
||||||
if(!memcmp(buffer, "true", 4)) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compositor::enable_xfwm4(bool status) {
|
|
||||||
FILE* fp;
|
|
||||||
if(status) {
|
|
||||||
fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing' -t 'bool' -s 'true'", "r");
|
|
||||||
} else {
|
|
||||||
fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing' -t 'bool' -s 'false'", "r");
|
|
||||||
}
|
|
||||||
if(!fp) return false;
|
|
||||||
pclose(fp);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//General
|
|
||||||
|
|
||||||
compositor::Compositor compositor::detect() {
|
|
||||||
Compositor result = Compositor::Unknown;
|
|
||||||
|
|
||||||
FILE* fp;
|
|
||||||
char buffer[512];
|
|
||||||
|
|
||||||
fp = popen("pidof metacity", "r");
|
|
||||||
if(fp && fgets(buffer, sizeof buffer, fp)) result = Compositor::Metacity;
|
|
||||||
pclose(fp);
|
|
||||||
|
|
||||||
fp = popen("pidof xfwm4", "r");
|
|
||||||
if(fp && fgets(buffer, sizeof buffer, fp)) result = Compositor::Xfwm4;
|
|
||||||
pclose(fp);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compositor::enabled() {
|
|
||||||
switch(detect()) {
|
|
||||||
case Compositor::Metacity: return enabled_metacity();
|
|
||||||
case Compositor::Xfwm4: return enabled_xfwm4();
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compositor::enable(bool status) {
|
|
||||||
switch(detect()) {
|
|
||||||
case Compositor::Metacity: return enable_metacity(status);
|
|
||||||
case Compositor::Xfwm4: return enable_xfwm4(status);
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(PLATFORM_WINDOWS)
|
|
||||||
|
|
||||||
bool compositor::enabled() {
|
|
||||||
HMODULE module = GetModuleHandleW(L"dwmapi");
|
|
||||||
if(module == nullptr) module = LoadLibraryW(L"dwmapi");
|
|
||||||
if(module == nullptr) return false;
|
|
||||||
|
|
||||||
auto pDwmIsCompositionEnabled = (HRESULT (WINAPI*)(BOOL*))GetProcAddress(module, "DwmIsCompositionEnabled");
|
|
||||||
if(pDwmIsCompositionEnabled == nullptr) return false;
|
|
||||||
|
|
||||||
BOOL result;
|
|
||||||
if(pDwmIsCompositionEnabled(&result) != S_OK) return false;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compositor::enable(bool status) {
|
|
||||||
HMODULE module = GetModuleHandleW(L"dwmapi");
|
|
||||||
if(module == nullptr) module = LoadLibraryW(L"dwmapi");
|
|
||||||
if(module == nullptr) return false;
|
|
||||||
|
|
||||||
auto pDwmEnableComposition = (HRESULT (WINAPI*)(UINT))GetProcAddress(module, "DwmEnableComposition");
|
|
||||||
if(pDwmEnableComposition == nullptr) return false;
|
|
||||||
|
|
||||||
if(pDwmEnableComposition(status) != S_OK) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
bool compositor::enabled() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compositor::enable(bool) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
#ifndef NALL_DATABASE_SQLITE3_HPP
|
||||||
|
#define NALL_DATABASE_SQLITE3_HPP
|
||||||
|
|
||||||
|
/* SQLite3 C++ RAII wrapper for nall
|
||||||
|
*
|
||||||
|
* Note on code below: it is safe (no-op) to call sqlite3_* functions on null sqlite3 objects
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
#include <nall/stdint.hpp>
|
||||||
|
#include <nall/string.hpp>
|
||||||
|
|
||||||
|
namespace nall { namespace Database {
|
||||||
|
|
||||||
|
struct SQLite3 {
|
||||||
|
struct Statement {
|
||||||
|
using type = Statement;
|
||||||
|
|
||||||
|
Statement(sqlite3_stmt* stmt) : stmt(stmt) {}
|
||||||
|
Statement(const Statement& source) { operator=(source); }
|
||||||
|
Statement(Statement&& source) { operator=(move(source)); }
|
||||||
|
|
||||||
|
auto operator=(const Statement& source) -> type& { stmt = source.stmt, stepped = source.stepped, response = source.response; return *this; }
|
||||||
|
auto operator=(Statement&& source) -> type& { operator=(source); source.stmt = nullptr, source.stepped = false, source.response = SQLITE_OK; return *this; }
|
||||||
|
explicit operator bool() { return !finished(); }
|
||||||
|
|
||||||
|
auto bind(unsigned column, nullptr_t) -> type& { sqlite3_bind_null(stmt, 1 + column); return *this; }
|
||||||
|
auto bind(unsigned column, int32_t value) -> type& { sqlite3_bind_int(stmt, 1 + column, value); return *this; }
|
||||||
|
auto bind(unsigned column, uint32_t value) -> type& { sqlite3_bind_int(stmt, 1 + column, value); return *this; }
|
||||||
|
auto bind(unsigned column, int64_t value) -> type& { sqlite3_bind_int64(stmt, 1 + column, value); return *this; }
|
||||||
|
auto bind(unsigned column, uint64_t value) -> type& { sqlite3_bind_int64(stmt, 1 + column, value); return *this; }
|
||||||
|
auto bind(unsigned column, double value) -> type& { sqlite3_bind_double(stmt, 1 + column, value); return *this; }
|
||||||
|
auto bind(unsigned column, const string& value) -> type& { sqlite3_bind_text(stmt, 1 + column, value.data(), value.size(), SQLITE_TRANSIENT); return *this; }
|
||||||
|
auto bind(unsigned column, const vector<uint8_t>& value) -> type& { sqlite3_bind_blob(stmt, 1 + column, value.data(), value.size(), SQLITE_TRANSIENT); return *this; }
|
||||||
|
|
||||||
|
auto integer(unsigned column) -> int64_t { return sqlite3_column_int64(handle(), column); }
|
||||||
|
auto decimal(unsigned column) -> uint64_t { return sqlite3_column_int64(handle(), column); }
|
||||||
|
auto real(unsigned column) -> double { return sqlite3_column_double(handle(), column); }
|
||||||
|
|
||||||
|
auto text(unsigned column) -> string {
|
||||||
|
string result;
|
||||||
|
if(auto text = sqlite3_column_text(handle(), column)) {
|
||||||
|
result.resize(sqlite3_column_bytes(handle(), column));
|
||||||
|
memory::copy(result.pointer(), text, result.size());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto data(unsigned column) -> vector<uint8_t> {
|
||||||
|
vector<uint8_t> result;
|
||||||
|
if(auto data = sqlite3_column_blob(handle(), column)) {
|
||||||
|
result.resize(sqlite3_column_bytes(handle(), column));
|
||||||
|
memory::copy(result.data(), data, result.size());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto integer() -> int64_t { return integer(column++); }
|
||||||
|
auto decimal() -> uint64_t { return decimal(column++); }
|
||||||
|
auto real() -> double { return real(column++); }
|
||||||
|
auto text() -> string { return text(column++); }
|
||||||
|
auto data() -> vector<uint8_t> { return data(column++); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
auto step() -> bool { stepped = true; response = sqlite3_step(stmt); return response == SQLITE_ROW; }
|
||||||
|
auto handle() -> sqlite3_stmt* { if(!stepped) step(); return stmt; }
|
||||||
|
auto finished() -> bool { handle(); return response != SQLITE_ROW; }
|
||||||
|
auto finalize() -> void { handle(); sqlite3_finalize(stmt); stmt = nullptr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
sqlite3_stmt* stmt = nullptr;
|
||||||
|
bool stepped = false;
|
||||||
|
int response = SQLITE_OK;
|
||||||
|
unsigned column = 0; //this value is not copied/moved via operator=
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Query : Statement {
|
||||||
|
Query(sqlite3_stmt* stmt) : Statement(stmt) {}
|
||||||
|
Query(const Query& source) : Statement(source) {}
|
||||||
|
Query(Query&& source) : Statement(move(source)) {}
|
||||||
|
~Query() { finalize(); }
|
||||||
|
|
||||||
|
auto operator=(const Query& source) -> Query& { return Statement::operator=(source), *this; }
|
||||||
|
auto operator=(Query&& source) -> Query& { return Statement::operator=(move(source)), *this; }
|
||||||
|
explicit operator bool() { return !finished(); }
|
||||||
|
|
||||||
|
using Statement::step;
|
||||||
|
using Statement::finalize;
|
||||||
|
|
||||||
|
struct Iterator {
|
||||||
|
auto operator*() -> Statement { return Statement(query); }
|
||||||
|
auto operator!=(const Iterator& source) const -> bool { return finished != source.finished; }
|
||||||
|
auto operator++() -> Iterator& { finished = !query.step(); return *this; }
|
||||||
|
Iterator(Query& query, bool finished) : query(query), finished(finished) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Query& query;
|
||||||
|
bool finished = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto begin() -> Iterator { return Iterator(*this, finished()); }
|
||||||
|
auto end() -> Iterator { return Iterator(*this, true); }
|
||||||
|
};
|
||||||
|
|
||||||
|
SQLite3() = default;
|
||||||
|
SQLite3(const string& filename) { open(filename); }
|
||||||
|
~SQLite3() { close(); }
|
||||||
|
|
||||||
|
explicit operator bool() const { return database; }
|
||||||
|
|
||||||
|
auto open(const string& filename) -> bool {
|
||||||
|
close();
|
||||||
|
sqlite3_open(filename, &database);
|
||||||
|
return database;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto close() -> void {
|
||||||
|
sqlite3_close(database);
|
||||||
|
database = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... P> auto execute(const string& statement, P&&... p) -> Query {
|
||||||
|
if(!database) return {nullptr};
|
||||||
|
|
||||||
|
sqlite3_stmt* stmt = nullptr;
|
||||||
|
sqlite3_prepare_v2(database, statement.data(), statement.size(), &stmt, nullptr);
|
||||||
|
if(!stmt) {
|
||||||
|
if(debug) print("[sqlite3_prepare_v2] ", sqlite3_errmsg(database), "\n");
|
||||||
|
return {nullptr};
|
||||||
|
}
|
||||||
|
|
||||||
|
Query query{stmt};
|
||||||
|
_bind(query, 0, forward<P>(p)...);
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lastInsertID() const -> uint64_t {
|
||||||
|
return database ? sqlite3_last_insert_rowid(database) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto setDebug(bool debug = true) -> void {
|
||||||
|
this->debug = debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
auto _bind(Query&, unsigned) -> void {}
|
||||||
|
template<typename T, typename... P> auto _bind(Query& query, unsigned column, const T& value, P&&... p) -> void {
|
||||||
|
query.bind(column, value);
|
||||||
|
_bind(query, column + 1, forward<P>(p)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool debug = false;
|
||||||
|
sqlite3* database = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
#endif
|
|
@ -6,10 +6,10 @@
|
||||||
#include <nall/string.hpp>
|
#include <nall/string.hpp>
|
||||||
#include <nall/hash/crc32.hpp>
|
#include <nall/hash/crc32.hpp>
|
||||||
|
|
||||||
namespace nall {
|
namespace nall { namespace Encode {
|
||||||
|
|
||||||
struct zip {
|
struct ZIP {
|
||||||
zip(const string& filename) {
|
ZIP(const string& filename) {
|
||||||
fp.open(filename, file::mode::write);
|
fp.open(filename, file::mode::write);
|
||||||
time_t currentTime = time(nullptr);
|
time_t currentTime = time(nullptr);
|
||||||
tm* info = localtime(¤tTime);
|
tm* info = localtime(¤tTime);
|
||||||
|
@ -40,7 +40,7 @@ struct zip {
|
||||||
fp.write(data, size); //file data
|
fp.write(data, size); //file data
|
||||||
}
|
}
|
||||||
|
|
||||||
~zip() {
|
~ZIP() {
|
||||||
//central directory
|
//central directory
|
||||||
unsigned baseOffset = fp.offset();
|
unsigned baseOffset = fp.offset();
|
||||||
for(auto& entry : directory) {
|
for(auto& entry : directory) {
|
||||||
|
@ -90,6 +90,6 @@ protected:
|
||||||
vector<entry_t> directory;
|
vector<entry_t> directory;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}}
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -21,7 +21,7 @@
|
||||||
#include <nall/bit.hpp>
|
#include <nall/bit.hpp>
|
||||||
#include <nall/bitvector.hpp>
|
#include <nall/bitvector.hpp>
|
||||||
#include <nall/bmp.hpp>
|
#include <nall/bmp.hpp>
|
||||||
//#include <nall/config.hpp>
|
#include <nall/config.hpp>
|
||||||
#include <nall/directory.hpp>
|
#include <nall/directory.hpp>
|
||||||
#include <nall/dl.hpp>
|
#include <nall/dl.hpp>
|
||||||
#include <nall/endian.hpp>
|
#include <nall/endian.hpp>
|
||||||
|
@ -55,7 +55,6 @@
|
||||||
#include <nall/utility.hpp>
|
#include <nall/utility.hpp>
|
||||||
#include <nall/varint.hpp>
|
#include <nall/varint.hpp>
|
||||||
#include <nall/vector.hpp>
|
#include <nall/vector.hpp>
|
||||||
#include <nall/zip.hpp>
|
|
||||||
#include <nall/decode/bmp.hpp>
|
#include <nall/decode/bmp.hpp>
|
||||||
#include <nall/decode/gzip.hpp>
|
#include <nall/decode/gzip.hpp>
|
||||||
#include <nall/decode/inflate.hpp>
|
#include <nall/decode/inflate.hpp>
|
||||||
|
|
|
@ -27,6 +27,11 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__SIZEOF_INT128__)
|
||||||
|
using int128_t = signed __int128;
|
||||||
|
using uint128_t = unsigned __int128;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
static_assert(sizeof(int8_t) == 1, "int8_t is not of the correct size" );
|
static_assert(sizeof(int8_t) == 1, "int8_t is not of the correct size" );
|
||||||
|
|
|
@ -211,8 +211,6 @@ public:
|
||||||
auto operator> (const char* s) const -> bool { return strcmp(data(), s) > 0; }
|
auto operator> (const char* s) const -> bool { return strcmp(data(), s) > 0; }
|
||||||
auto operator>=(const char* s) const -> bool { return strcmp(data(), s) >= 0; }
|
auto operator>=(const char* s) const -> bool { return strcmp(data(), s) >= 0; }
|
||||||
|
|
||||||
auto operator+=(const string& s) -> type& { return append(s); }
|
|
||||||
|
|
||||||
string(const string& source) : string() { operator=(source); }
|
string(const string& source) : string() { operator=(source); }
|
||||||
string(string&& source) : string() { operator=(std::move(source)); }
|
string(string&& source) : string() { operator=(std::move(source)); }
|
||||||
|
|
||||||
|
|
|
@ -14,26 +14,26 @@ using SharedNode = shared_pointer<ManagedNode>;
|
||||||
struct ManagedNode : Markup::ManagedNode {
|
struct ManagedNode : Markup::ManagedNode {
|
||||||
protected:
|
protected:
|
||||||
//test to verify if a valid character for a node name
|
//test to verify if a valid character for a node name
|
||||||
bool valid(char p) const { //A-Z, a-z, 0-9, -.
|
auto valid(char p) const -> bool { //A-Z, a-z, 0-9, -.
|
||||||
return p - 'A' < 26u || p - 'a' < 26u || p - '0' < 10u || p - '-' < 2u;
|
return p - 'A' < 26u || p - 'a' < 26u || p - '0' < 10u || p - '-' < 2u;
|
||||||
}
|
}
|
||||||
|
|
||||||
//determine indentation level, without incrementing pointer
|
//determine indentation level, without incrementing pointer
|
||||||
unsigned readDepth(const char* p) {
|
auto readDepth(const char* p) -> unsigned {
|
||||||
unsigned depth = 0;
|
unsigned depth = 0;
|
||||||
while(p[depth] == '\t' || p[depth] == ' ') depth++;
|
while(p[depth] == '\t' || p[depth] == ' ') depth++;
|
||||||
return depth;
|
return depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
//determine indentation level
|
//determine indentation level
|
||||||
unsigned parseDepth(const char*& p) {
|
auto parseDepth(const char*& p) -> unsigned {
|
||||||
unsigned depth = readDepth(p);
|
unsigned depth = readDepth(p);
|
||||||
p += depth;
|
p += depth;
|
||||||
return depth;
|
return depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
//read name
|
//read name
|
||||||
void parseName(const char*& p) {
|
auto parseName(const char*& p) -> void {
|
||||||
unsigned length = 0;
|
unsigned length = 0;
|
||||||
while(valid(p[length])) length++;
|
while(valid(p[length])) length++;
|
||||||
if(length == 0) throw "Invalid node name";
|
if(length == 0) throw "Invalid node name";
|
||||||
|
@ -41,7 +41,7 @@ protected:
|
||||||
p += length;
|
p += length;
|
||||||
}
|
}
|
||||||
|
|
||||||
void parseData(const char*& p) {
|
auto parseData(const char*& p) -> void {
|
||||||
if(*p == '=' && *(p + 1) == '\"') {
|
if(*p == '=' && *(p + 1) == '\"') {
|
||||||
unsigned length = 2;
|
unsigned length = 2;
|
||||||
while(p[length] && p[length] != '\n' && p[length] != '\"') length++;
|
while(p[length] && p[length] != '\n' && p[length] != '\"') length++;
|
||||||
|
@ -63,7 +63,7 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
//read all attributes for a node
|
//read all attributes for a node
|
||||||
void parseAttributes(const char*& p) {
|
auto parseAttributes(const char*& p) -> void {
|
||||||
while(*p && *p != '\n') {
|
while(*p && *p != '\n') {
|
||||||
if(*p != ' ') throw "Invalid node name";
|
if(*p != ' ') throw "Invalid node name";
|
||||||
while(*p == ' ') p++; //skip excess spaces
|
while(*p == ' ') p++; //skip excess spaces
|
||||||
|
@ -81,7 +81,7 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
//read a node and all of its child nodes
|
//read a node and all of its child nodes
|
||||||
void parseNode(const lstring& text, unsigned& y) {
|
auto parseNode(const lstring& text, unsigned& y) -> void {
|
||||||
const char* p = text[y++];
|
const char* p = text[y++];
|
||||||
_metadata = parseDepth(p);
|
_metadata = parseDepth(p);
|
||||||
parseName(p);
|
parseName(p);
|
||||||
|
@ -106,22 +106,32 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
//read top-level nodes
|
//read top-level nodes
|
||||||
void parse(const string& document) {
|
auto parse(string document) -> void {
|
||||||
lstring text = string{document}.replace("\r", "").split("\n");
|
//in order to simplify the parsing logic; we do an initial pass to normalize the data
|
||||||
|
//the below code will turn '\r\n' into '\n'; skip empty lines; and skip comment lines
|
||||||
//remove empty lines and comment lines
|
char* p = document.pointer(), *output = p;
|
||||||
for(unsigned y = 0; y < text.size();) {
|
while(*p) {
|
||||||
unsigned x = 0;
|
char* origin = p;
|
||||||
bool empty = true;
|
bool empty = true;
|
||||||
while(x < text[y].size()) {
|
while(*p) {
|
||||||
if(text[y][x] == ' ' || text[y][x] == '\t') { x++; continue; }
|
//scan for first non-whitespace character. if it's a line feed or comment; skip the line
|
||||||
empty = (text[y][x + 0] == '/' && text[y][x + 1] == '/');
|
if(p[0] == ' ' || p[0] == '\t') { p++; continue; }
|
||||||
|
empty = p[0] == '\r' || p[0] == '\n' || (p[0] == '/' && p[1] == '/');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(empty) text.remove(y);
|
while(*p) {
|
||||||
else y++;
|
if(p[0] == '\r') p[0] = '\n'; //turns '\r\n' into '\n\n' (second '\n' will be skipped)
|
||||||
|
if(*p++ == '\n') break; //include '\n' in the output to be copied
|
||||||
}
|
}
|
||||||
|
if(empty) continue;
|
||||||
|
|
||||||
|
memory::move(output, origin, p - origin);
|
||||||
|
output += p - origin;
|
||||||
|
}
|
||||||
|
document.resize(document.size() - (p - output)).rtrim("\n");
|
||||||
|
if(document.size() == 0) return; //empty document
|
||||||
|
|
||||||
|
auto text = document.split("\n");
|
||||||
unsigned y = 0;
|
unsigned y = 0;
|
||||||
while(y < text.size()) {
|
while(y < text.size()) {
|
||||||
SharedNode node(new ManagedNode);
|
SharedNode node(new ManagedNode);
|
||||||
|
|
|
@ -75,7 +75,7 @@ auto configpath() -> string {
|
||||||
// c:/users/username/appdata/local/
|
// c:/users/username/appdata/local/
|
||||||
auto localpath() -> string {
|
auto localpath() -> string {
|
||||||
#if defined(PLATFORM_WINDOWS)
|
#if defined(PLATFORM_WINDOWS)
|
||||||
whcar_t path[PATH_MAX] = L"";
|
wchar_t path[PATH_MAX] = L"";
|
||||||
SHGetFolderPathW(nullptr, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path);
|
SHGetFolderPathW(nullptr, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path);
|
||||||
string result = (const char*)utf8_t(path);
|
string result = (const char*)utf8_t(path);
|
||||||
result.transform("\\", "/");
|
result.transform("\\", "/");
|
||||||
|
|
|
@ -124,9 +124,9 @@ void Cartridge::load_super_game_boy() {
|
||||||
GameBoy::cartridge.information.markup = information.markup.gameBoy;
|
GameBoy::cartridge.information.markup = information.markup.gameBoy;
|
||||||
GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy);
|
GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy);
|
||||||
|
|
||||||
if(rom["name"]) interface->loadRequest(ID::SuperGameBoyROM, rom["name"].text());
|
if(auto name = rom["name"].text()) interface->loadRequest(ID::SuperGameBoyROM, name);
|
||||||
if(ram["name"]) interface->loadRequest(ID::SuperGameBoyRAM, ram["name"].text());
|
if(auto name = ram["name"].text()) interface->loadRequest(ID::SuperGameBoyRAM, name);
|
||||||
if(ram["name"]) memory.append({ID::SuperGameBoyRAM, ram["name"].text()});
|
if(auto name = ram["name"].text()) memory.append({ID::SuperGameBoyRAM, name});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::load_satellaview() {
|
void Cartridge::load_satellaview() {
|
||||||
|
|
|
@ -147,7 +147,7 @@ void Cartridge::parse_markup_sufamiturbo(Markup::Node root, bool slot) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto node : root.find("map")) {
|
for(auto node : root.find("map")) {
|
||||||
SufamiTurboCartridge &cart = (slot == 0 ? sufamiturboA : sufamiturboB);
|
SufamiTurboCartridge& cart = (slot == 0 ? sufamiturboA : sufamiturboB);
|
||||||
|
|
||||||
if(node["id"].text() == "rom") {
|
if(node["id"].text() == "rom") {
|
||||||
if(cart.rom.size() == 0) continue;
|
if(cart.rom.size() == 0) continue;
|
||||||
|
@ -234,9 +234,12 @@ void Cartridge::parse_markup_sa1(Markup::Node root) {
|
||||||
if(!root) return;
|
if(!root) return;
|
||||||
has_sa1 = true;
|
has_sa1 = true;
|
||||||
|
|
||||||
parse_markup_memory(sa1.rom, root["rom"], ID::SA1ROM, false);
|
auto rom = root.find("rom");
|
||||||
parse_markup_memory(sa1.bwram, root["ram"].at(0), ID::SA1BWRAM, true);
|
auto ram = root.find("ram");
|
||||||
parse_markup_memory(sa1.iram, root["ram"].at(1), ID::SA1IRAM, true);
|
|
||||||
|
parse_markup_memory(sa1.rom, rom(0), ID::SA1ROM, false);
|
||||||
|
parse_markup_memory(sa1.bwram, ram(0), ID::SA1BWRAM, true);
|
||||||
|
parse_markup_memory(sa1.iram, ram(1), ID::SA1IRAM, true);
|
||||||
|
|
||||||
for(auto node : root.find("map")) {
|
for(auto node : root.find("map")) {
|
||||||
if(node["id"].text() == "io") {
|
if(node["id"].text() == "io") {
|
||||||
|
@ -270,8 +273,11 @@ void Cartridge::parse_markup_superfx(Markup::Node root) {
|
||||||
if(!root) return;
|
if(!root) return;
|
||||||
has_superfx = true;
|
has_superfx = true;
|
||||||
|
|
||||||
parse_markup_memory(superfx.rom, root["rom"], ID::SuperFXROM, false);
|
auto rom = root.find("rom");
|
||||||
parse_markup_memory(superfx.ram, root["ram"], ID::SuperFXRAM, true);
|
auto ram = root.find("ram");
|
||||||
|
|
||||||
|
parse_markup_memory(superfx.rom, rom(0), ID::SuperFXROM, false);
|
||||||
|
parse_markup_memory(superfx.ram, ram(0), ID::SuperFXRAM, true);
|
||||||
|
|
||||||
for(auto node : root.find("map")) {
|
for(auto node : root.find("map")) {
|
||||||
if(node["id"].text() == "io") {
|
if(node["id"].text() == "io") {
|
||||||
|
@ -300,9 +306,12 @@ void Cartridge::parse_markup_armdsp(Markup::Node root) {
|
||||||
if(!root) return;
|
if(!root) return;
|
||||||
has_armdsp = true;
|
has_armdsp = true;
|
||||||
|
|
||||||
string programROMName = root["rom"].at(0)["name"].text();
|
auto rom = root.find("rom");
|
||||||
string dataROMName = root["rom"].at(1)["name"].text();
|
auto ram = root.find("ram");
|
||||||
string dataRAMName = root["ram/name"].text();
|
|
||||||
|
string programROMName = rom(0)["name"].text();
|
||||||
|
string dataROMName = rom(1)["name"].text();
|
||||||
|
string dataRAMName = ram(0)["name"].text();
|
||||||
|
|
||||||
interface->loadRequest(ID::ArmDSPPROM, programROMName);
|
interface->loadRequest(ID::ArmDSPPROM, programROMName);
|
||||||
interface->loadRequest(ID::ArmDSPDROM, dataROMName);
|
interface->loadRequest(ID::ArmDSPDROM, dataROMName);
|
||||||
|
@ -324,8 +333,11 @@ void Cartridge::parse_markup_hitachidsp(Markup::Node root, unsigned roms) {
|
||||||
if(!root) return;
|
if(!root) return;
|
||||||
has_hitachidsp = true;
|
has_hitachidsp = true;
|
||||||
|
|
||||||
parse_markup_memory(hitachidsp.rom, root["rom"].at(0), ID::HitachiDSPROM, false);
|
auto rom = root.find("rom");
|
||||||
parse_markup_memory(hitachidsp.ram, root["ram"].at(1), ID::HitachiDSPRAM, true);
|
auto ram = root.find("ram");
|
||||||
|
|
||||||
|
parse_markup_memory(hitachidsp.rom, rom(0), ID::HitachiDSPROM, false);
|
||||||
|
parse_markup_memory(hitachidsp.ram, ram(0), ID::HitachiDSPRAM, true);
|
||||||
|
|
||||||
for(auto& word : hitachidsp.dataROM) word = 0x000000;
|
for(auto& word : hitachidsp.dataROM) word = 0x000000;
|
||||||
for(auto& word : hitachidsp.dataRAM) word = 0x00;
|
for(auto& word : hitachidsp.dataRAM) word = 0x00;
|
||||||
|
@ -334,8 +346,8 @@ void Cartridge::parse_markup_hitachidsp(Markup::Node root, unsigned roms) {
|
||||||
if(hitachidsp.Frequency == 0) hitachidsp.frequency = 20000000;
|
if(hitachidsp.Frequency == 0) hitachidsp.frequency = 20000000;
|
||||||
hitachidsp.Roms = roms;
|
hitachidsp.Roms = roms;
|
||||||
|
|
||||||
string dataROMName = root["rom"].at(1)["name"].text();
|
string dataROMName = rom(1)["name"].text();
|
||||||
string dataRAMName = root["ram"].at(1)["name"].text();
|
string dataRAMName = ram(1)["name"].text();
|
||||||
|
|
||||||
interface->loadRequest(ID::HitachiDSPDROM, dataROMName);
|
interface->loadRequest(ID::HitachiDSPDROM, dataROMName);
|
||||||
if(dataRAMName.empty() == false) {
|
if(dataRAMName.empty() == false) {
|
||||||
|
@ -380,9 +392,12 @@ void Cartridge::parse_markup_necdsp(Markup::Node root) {
|
||||||
: root["model"].text() == "uPD96050" ? NECDSP::Revision::uPD96050
|
: root["model"].text() == "uPD96050" ? NECDSP::Revision::uPD96050
|
||||||
: NECDSP::Revision::uPD7725;
|
: NECDSP::Revision::uPD7725;
|
||||||
|
|
||||||
string programROMName = root["rom"].at(0)["name"].text();
|
auto rom = root.find("rom");
|
||||||
string dataROMName = root["rom"].at(1)["name"].text();
|
auto ram = root.find("ram");
|
||||||
string dataRAMName = root["ram/name"].text();
|
|
||||||
|
string programROMName = rom(0)["name"].text();
|
||||||
|
string dataROMName = rom(1)["name"].text();
|
||||||
|
string dataRAMName = ram(0)["name"].text();
|
||||||
|
|
||||||
if(necdsp.revision == NECDSP::Revision::uPD7725) {
|
if(necdsp.revision == NECDSP::Revision::uPD7725) {
|
||||||
interface->loadRequest(ID::Nec7725DSPPROM, programROMName);
|
interface->loadRequest(ID::Nec7725DSPPROM, programROMName);
|
||||||
|
@ -456,9 +471,12 @@ void Cartridge::parse_markup_spc7110(Markup::Node root) {
|
||||||
if(!root) return;
|
if(!root) return;
|
||||||
has_spc7110 = true;
|
has_spc7110 = true;
|
||||||
|
|
||||||
parse_markup_memory(spc7110.prom, root["rom"].at(0), ID::SPC7110PROM, false);
|
auto rom = root.find("rom");
|
||||||
parse_markup_memory(spc7110.drom, root["rom"].at(1), ID::SPC7110DROM, false);
|
auto ram = root.find("ram");
|
||||||
parse_markup_memory(spc7110.ram, root["ram"], ID::SPC7110RAM, true);
|
|
||||||
|
parse_markup_memory(spc7110.prom, rom(0), ID::SPC7110PROM, false);
|
||||||
|
parse_markup_memory(spc7110.drom, rom(1), ID::SPC7110DROM, false);
|
||||||
|
parse_markup_memory(spc7110.ram, ram(0), ID::SPC7110RAM, true);
|
||||||
|
|
||||||
for(auto node : root.find("map")) {
|
for(auto node : root.find("map")) {
|
||||||
if(node["id"].text() == "io") {
|
if(node["id"].text() == "io") {
|
||||||
|
@ -485,8 +503,11 @@ void Cartridge::parse_markup_sdd1(Markup::Node root) {
|
||||||
if(!root) return;
|
if(!root) return;
|
||||||
has_sdd1 = true;
|
has_sdd1 = true;
|
||||||
|
|
||||||
parse_markup_memory(sdd1.rom, root["rom"], ID::SDD1ROM, false);
|
auto rom = root.find("rom");
|
||||||
parse_markup_memory(sdd1.ram, root["ram"], ID::SDD1RAM, true);
|
auto ram = root.find("ram");
|
||||||
|
|
||||||
|
parse_markup_memory(sdd1.rom, rom(0), ID::SDD1ROM, false);
|
||||||
|
parse_markup_memory(sdd1.ram, ram(0), ID::SDD1RAM, true);
|
||||||
|
|
||||||
for(auto node : root.find("map")) {
|
for(auto node : root.find("map")) {
|
||||||
if(node["id"].text() == "io") {
|
if(node["id"].text() == "io") {
|
||||||
|
|
Loading…
Reference in New Issue