Update to v092 release.

In the release thread, byuu says:

    The first official release of higan has been posted. higan is the
    new name for bsnes, and it continues with the latter's version
    numbering.

    Note that as of now, bsnes still exists. It's a module distributed
    inside of higan. bsnes is now specific to my SNES emulator.

    Due to last minute changes to the emulator interface, and missing
    support in ananke, I wasn't able to include Cydrak's Nintendo DS
    emulator dasShiny in this build, but I hope to do so in the next
    release.

    http://code.google.com/p/higan/downloads/list

    For both new and experienced users, please read the higan user guide
    first:

    http://byuu.org/higan/user-guide

In the v091 WIP thread, byuu says:

    r15->r16:
    - BS-X MaskROM handling (partial ... need to split bsx/flash away
      from sfc/chip, restructure code - it requires tagging the base
      cart markup for now, but it needs to parse the slotted cart
      markup)
    - phoenixflags / phoenixlink += -m32
    - nall/sort stability
    - if(input.poll(scancode[activeScancode]) == false) return;
    - MSU1 / USART need to use interface->path(1)
    - MSU1 needs to use Markup::Document, not XML::Document
    - case-insensitive folder listings
    - remove nall/emulation/system.hpp files (move to ananke)
    - remove rom/ram id= checks with indexing
    X have cores ask for manifest.bml (skipped for v092's release, too
      big a change)
    - rename compatibility profile to balanced (so people don't assume
      it has better compatibility than accuracy)
This commit is contained in:
Tim Allen 2013-01-14 23:10:20 +11:00
parent b389d17c9a
commit 032e924495
92 changed files with 2212 additions and 2873 deletions

View File

@ -2,11 +2,20 @@ include nall/Makefile
include phoenix/Makefile
path := /usr/local/lib
flags := -std=gnu++11 -I. -O3 -fomit-frame-pointer
flags := -I. -O3 -fomit-frame-pointer
ifeq ($(arch),win32)
flags := -m32 $(flags)
endif
all:
$(cpp) $(flags) -fPIC -o ananke.o -c ananke.cpp
ifeq ($(platform),x)
$(cpp) $(flags) -shared -Wl,-soname,libananke.so.1 -o libananke.so ananke.o
else ifeq ($(platform),win)
$(cpp) $(flags) -fPIC -o phoenix.o -c phoenix/phoenix.cpp $(phoenixflags)
$(cpp) $(flags) -shared -o phoenix.dll phoenix.o $(phoenixlink)
$(cpp) $(flags) -shared -o ananke.dll ananke.o -L. -lphoenix
endif
resource: force
sourcery resource/resource.bml resource/resource.cpp resource/resource.hpp
@ -16,13 +25,17 @@ clean:
-@$(call delete,*.so)
install: uninstall
ifeq ($(platform),x)
if [ ! -d ~/.config/ananke ]; then mkdir ~/.config/ananke; fi
sudo cp libananke.so $(path)/libananke.so.1
sudo ln -s $(path)/libananke.so.1 $(path)/libananke.so
endif
uninstall:
ifeq ($(platform),x)
if [ -f $(path)/libananke.so ]; then sudo rm $(path)/libananke.so; fi
if [ -f $(path)/libananke.so.1 ]; then sudo rm $(path)/libananke.so.1; fi
endif
sync:
ifeq ($(shell id -un),byuu)

View File

@ -1,9 +1,9 @@
#include <nall/nall.hpp>
#include <nall/beat/patch.hpp>
#include <nall/emulation/famicom.hpp>
#include <nall/emulation/super-famicom.hpp>
#include <nall/emulation/game-boy.hpp>
#include <nall/emulation/game-boy-advance.hpp>
#include "heuristics/famicom.hpp"
#include "heuristics/super-famicom.hpp"
#include "heuristics/game-boy.hpp"
#include "heuristics/game-boy-advance.hpp"
using namespace nall;
#include <phoenix/phoenix.hpp>
@ -12,6 +12,7 @@ using namespace phoenix;
namespace Database {
#include "database/super-famicom.hpp"
#include "database/sufami-turbo.hpp"
#include "database/bsx-satellaview.hpp"
};
struct Ananke {
@ -49,6 +50,11 @@ struct Ananke {
string createSufamiTurboHeuristic(vector<uint8_t> &buffer);
string openSufamiTurbo(vector<uint8_t> &buffer);
//bsx-satellaview.cpp
string createBsxSatellaviewDatabase(vector<uint8_t> &buffer, Markup::Node &document, const string &manifest);
string createBsxSatellaviewHeuristic(vector<uint8_t> &buffer);
string openBsxSatellaview(vector<uint8_t> &buffer);
//game-boy.cpp
void copyGameBoySaves(const string &pathname);
string createGameBoyHeuristic(vector<uint8_t> &buffer);
@ -70,6 +76,7 @@ struct Ananke {
#include "famicom.cpp"
#include "super-famicom.cpp"
#include "sufami-turbo.cpp"
#include "bsx-satellaview.cpp"
#include "game-boy.cpp"
#include "game-boy-advance.cpp"
@ -82,8 +89,8 @@ bool Ananke::supported(const string &filename) {
if(extension == "nes") return true;
if(extension == "sfc") return true;
if(extension == "smc") return true;
if(extension == "bs" ) return true;
if(extension == "st" ) return true;
if(extension == "bs" ) return true;
if(extension == "gb" ) return true;
if(extension == "gbc") return true;
if(extension == "gba") return true;
@ -119,6 +126,7 @@ string Ananke::open(string filename) {
if(information.name.endswith(".fc") || information.name.endswith(".nes")) return openFamicom(buffer);
if(information.name.endswith(".sfc") || information.name.endswith(".smc")) return openSuperFamicom(buffer);
if(information.name.endswith(".st")) return openSufamiTurbo(buffer);
if(information.name.endswith(".bs")) return openBsxSatellaview(buffer);
if(information.name.endswith(".gb") || information.name.endswith(".gbc")) return openGameBoy(buffer);
if(information.name.endswith(".gba")) return openGameBoyAdvance(buffer);
return "";

View File

@ -0,0 +1,60 @@
string Ananke::createBsxSatellaviewDatabase(vector<uint8_t> &buffer, Markup::Node &document, const string &manifest) {
string pathname = {
userpath(), "Emulation/BS-X Satellaview/",
document["release/information/name"].text(),
" (", document["release/information/region"].text(), ")",
" (", document["release/information/revision"].text(), ")",
".bs/"
};
directory::create(pathname);
//strip "release" root node from database entry (since a single game manifest isn't part of a database)
string markup = manifest;
markup.replace("\n ", "\n");
markup.replace("information", "\ninformation");
markup.ltrim<1>("release\n");
file::write({pathname, "manifest.bml"}, markup);
file::write({pathname, "program.rom"}, buffer);
return "";
}
string Ananke::createBsxSatellaviewHeuristic(vector<uint8_t> &buffer) {
string pathname = {
userpath(), "Emulation/BS-X Satellaview/",
nall::basename(information.name),
" (!).bs/"
};
directory::create(pathname);
file::write({pathname, "manifest.bml"}, {
"cartridge\n"
" rom name=program.rom size=0x", hex(buffer.size()), " type=FlashROM\n",
"\n",
"information\n",
" title: ", nall::basename(information.name), "\n"
});
file::write({pathname, "program.rom"}, buffer);
return "";
}
string Ananke::openBsxSatellaview(vector<uint8_t> &buffer) {
string sha256 = nall::sha256(buffer.data(), buffer.size());
string databaseText = string::read({configpath(), "ananke/database/BS-X Satellaview.bml"}).strip();
if(databaseText.empty()) databaseText = string{Database::BsxSatellaview}.strip();
lstring databaseItem = databaseText.split("\n\n");
for(auto &item : databaseItem) {
item.append("\n");
auto document = Markup::Document(item);
if(document["release/information/sha256"].text() == sha256) {
return createBsxSatellaviewDatabase(buffer, document, item);
}
}
return createBsxSatellaviewHeuristic(buffer);
}

View File

@ -0,0 +1,19 @@
string BsxSatellaview = R"(
database revision=2013-01-12
release
cartridge
rom name=program.rom size=0x80000 type=MaskROM
information
title:
name: Same Game - Character Cassette
region: JP
revision: 1.0
board: BSMC-CR-01
serial: BSMC-ZS5J-JPN
sha256: 80c34b50817d58820bc8c88d2d9fa462550b4a76372e19c6467cbfbc8cf5d9ef
configuration
rom name=program.rom size=0x80000 type=MaskROM
)";

View File

@ -1,9 +1,9 @@
string SufamiTurbo = R"(
database revision=2012-12-24
database revision=2013-01-12
release
cartridge region=NTSC
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
information
@ -16,9 +16,10 @@ release
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
linkable
release
cartridge region=NTSC
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
information
@ -31,9 +32,10 @@ release
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
linkable
release
cartridge region=NTSC
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
information
@ -46,13 +48,14 @@ release
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
linkable
release
cartridge region=NTSC
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
information
title: SDガンダムジェネレーション
title: SDガンダムジェネレーション
name: SD Gundam Generation - Ichinen Sensouki
region: JP
revision: 1.0
@ -61,9 +64,10 @@ release
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
linkable
release
cartridge region=NTSC
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
information
@ -76,13 +80,14 @@ release
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
linkable
release
cartridge region=NTSC
cartridge
rom name=program.rom size=0x80000
information
title:
name: Gegege no Kitarou - Youkai Dungeon
title:
name: Gegege no Kitarou - Youkai Donjara
region: JP
revision: 1.0
serial: SFT-0106-JPN
@ -91,7 +96,7 @@ release
rom name=program.rom size=0x80000
release
cartridge region=NTSC
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
information
@ -104,9 +109,10 @@ release
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
linkable
release
cartridge region=NTSC
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
information
@ -119,9 +125,10 @@ release
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
linkable
release
cartridge region=NTSC
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
information
@ -134,20 +141,22 @@ release
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
linkable
release
cartridge region=NTSC
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
ram name=save.ram size=0x800
information
title: SDガンダムジェネレーション
name: SD Gundam Generation - Colonia Kakotouki
title: SDガンダムジェネレーション
name: SD Gundam Generation - Colony Kakutouki
region: JP
revision: 1.0
serial: SFT-0111-JPN
sha256: e639b5d5d722432b6809ccc6801dc584e1a3016379f34b335ed2dfa73b1ebf69
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
ram name=save.ram size=0x800
linkable
)";

File diff suppressed because it is too large Load Diff

View File

@ -74,7 +74,7 @@ struct FileDialog : Window {
layout.setMargin(5);
homeButton.setImage({resource::home, sizeof resource::home});
upButton.setImage({resource::up, sizeof resource::up});
filterLabel.setText("Filter: *.fc, *.sfc, *.bs, *.st, *.gb, *.gbc, *.gba, *.nes, *.smc, *.zip");
filterLabel.setText("Filter: *.fc, *.sfc, *.st, *.bs, *.gb, *.gbc, *.gba, *.nes, *.smc, *.zip");
openButton.setText("Open");
append(layout);

View File

@ -29,7 +29,7 @@ namespace nall {
for(signed i = 1, j; i < size; i++) {
T copy = std::move(list[i]);
for(j = i - 1; j >= 0; j--) {
if(lessthan(list[j], copy)) break;
if(!lessthan(copy, list[j])) break;
list[j + 1] = std::move(list[j]);
}
list[j + 1] = std::move(copy);
@ -55,7 +55,7 @@ namespace nall {
T *buffer = new T[size];
unsigned offset = 0, left = 0, right = middle;
while(left < middle && right < size) {
if(lessthan(list[left], list[right])) {
if(!lessthan(list[right], list[left])) {
buffer[offset++] = std::move(list[left++]);
} else {
buffer[offset++] = std::move(list[right++]);

View File

@ -74,7 +74,8 @@ char* integer(char *result, intmax_t value) {
buffer[size++] = '0' + n;
value /= 10;
} while(value);
buffer[size++] = negative ? '-' : '+';
if(negative) buffer[size++] = '-';
//buffer[size++] = negative ? '-' : '+';
for(signed x = size - 1, y = 0; x >= 0 && y < size; x--, y++) result[x] = buffer[y];
result[size] = 0;
@ -110,7 +111,8 @@ template<unsigned length_, char padding> string integer(intmax_t value) {
buffer[size++] = '0' + n;
value /= 10;
} while(value);
buffer[size++] = negative ? '-' : '+';
if(negative) buffer[size++] = '-';
//buffer[size++] = negative ? '-' : '+';
buffer[size] = 0;
unsigned length = (length_ == 0 ? size : length_);
@ -137,7 +139,8 @@ template<unsigned length_, char padding> string linteger(intmax_t value) {
buffer[size++] = '0' + n;
value /= 10;
} while(value);
buffer[size++] = negative ? '-' : '+';
if(negative) buffer[size++] = '-';
//buffer[size++] = negative ? '-' : '+';
buffer[size] = 0;
unsigned length = (length_ == 0 ? size : length_);

View File

@ -15,6 +15,11 @@ ifeq ($(platform),x)
else ifeq ($(platform),win)
phoenixflags := -DPHOENIX_WINDOWS
phoenixlink := -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -lshlwapi
ifeq ($(arch),win32)
phoenixflags := -m32 $(phoenixflags)
phoenixlink := -m32 $(phoenixlink)
endif
else
phoenixflags := -DPHOENIX_REFERENCE
phoenixlink :=

View File

@ -173,6 +173,10 @@ void OS::quit() {
return pOS::quit();
}
void OS::setName(const string &name) {
osState.name = name;
}
void OS::initialize() {
static bool initialized = false;
if(initialized == false) {

View File

@ -143,13 +143,14 @@ struct Object {
pObject &p;
};
struct OS : Object {
struct OS {
static void main();
static bool pendingEvents();
static void processEvents();
static void quit();
static void setName(const nall::string &name);
OS();
struct State;
static void initialize();
};

View File

@ -1,3 +1,10 @@
struct OS::State {
string name;
State() {
}
} osState;
struct Timer::State {
bool enabled;
unsigned milliseconds;

View File

@ -1,7 +1,3 @@
Geometry pWidget::minimumGeometry() {
return {0, 0, 0, 0};
}
bool pWidget::enabled() {
return gtk_widget_get_sensitive(gtkWidget);
}
@ -10,6 +6,10 @@ bool pWidget::focused() {
return GTK_WIDGET_HAS_FOCUS(gtkWidget);
}
Geometry pWidget::minimumGeometry() {
return {0, 0, 0, 0};
}
void pWidget::setEnabled(bool enabled) {
if(widget.state.abstract) enabled = false;
if(sizable.state.layout && sizable.state.layout->enabled() == false) enabled = false;

View File

@ -296,6 +296,15 @@ void pWindow::constructor() {
widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
//if program was given a name, try and set the window taskbar icon from one of the pixmaps folders
if(osState.name.empty() == false) {
if(file::exists({"/usr/share/pixmaps/", osState.name, ".png"})) {
gtk_window_set_icon_from_file(GTK_WINDOW(widget), string{"/usr/share/pixmaps/", osState.name, ".png"}, nullptr);
} else if(file::exists({"/usr/local/share/pixmaps/", osState.name, ".png"})) {
gtk_window_set_icon_from_file(GTK_WINDOW(widget), string{"/usr/local/share/pixmaps/", osState.name, ".png"}, nullptr);
}
}
if(gdk_screen_is_composited(gdk_screen_get_default())) {
gtk_widget_set_colormap(widget, gdk_screen_get_rgba_colormap(gdk_screen_get_default()));
} else {

View File

@ -1,7 +1,7 @@
/****************************************************************************
** Meta object code from reading C++ file 'platform.moc.hpp'
**
** Created: Fri Dec 21 16:30:24 2012
** Created: Wed Dec 26 00:12:14 2012
** by: The Qt Meta Object Compiler version 62 (Qt 4.6.3)
**
** WARNING! All changes made in this file will be lost!

View File

@ -266,6 +266,7 @@ struct pWidget : public pSizable {
Widget &widget;
QWidget *qtWidget;
bool focused();
virtual Geometry minimumGeometry();
void setEnabled(bool enabled);
void setFocused();

View File

@ -1,5 +1,9 @@
bool pWidget::focused() {
return qtWidget->hasFocus();
}
Geometry pWidget::minimumGeometry() {
return { 0, 0, 0, 0 };
return {0, 0, 0, 0};
}
void pWidget::setEnabled(bool enabled) {

View File

@ -179,6 +179,15 @@ void pWindow::constructor() {
qtWindow = new QtWindow(*this);
qtWindow->setWindowTitle(" ");
//if program was given a name, try and set the window taskbar icon to a matching pixmap image
if(osState.name.empty() == false) {
if(file::exists({"/usr/share/pixmaps/", osState.name, ".png"})) {
qtWindow->setWindowIcon(QIcon(string{"/usr/share/pixmaps/", osState.name, ".png"}));
} else if(file::exists({"/usr/local/share/pixmaps/", osState.name, ".png"})) {
qtWindow->setWindowIcon(QIcon(string{"/usr/local/share/pixmaps/", osState.name, ".png"}));
}
}
qtLayout = new QVBoxLayout(qtWindow);
qtLayout->setMargin(0);
qtLayout->setSpacing(0);

View File

@ -183,6 +183,7 @@ struct pWidget : public pSizable {
Widget &widget;
bool enabled();
bool focused();
Geometry minimumGeometry();
void setEnabled(bool enabled);
void setFocused();

View File

@ -2,8 +2,12 @@ bool pWidget::enabled() {
return false;
}
bool pWidget::focused() {
return false;
}
Geometry pWidget::minimumGeometry() {
return { 0, 0, 0, 0 };
return {0, 0, 0, 0};
}
void pWidget::setEnabled(bool enabled) {

View File

@ -223,6 +223,7 @@ struct pWidget : public pSizable {
HFONT hfont;
bool enabled();
bool focused();
virtual Geometry minimumGeometry();
void setEnabled(bool enabled);
void setFocused();

View File

@ -63,10 +63,25 @@ void pButton::setImage(const image &image, Orientation orientation) {
}
Button_SetImageList(hwnd, &list);
}
setText(button.state.text); //update text to display nicely with image (or lack thereof)
}
void pButton::setText(const string &text) {
SetWindowText(hwnd, utf16_t(text));
if(text.empty()) {
//bitmaps will not show up if text is empty
SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) | BS_BITMAP);
} else {
//text will not show up if BS_BITMAP is set
SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) & ~BS_BITMAP);
}
if(OsVersion() >= WindowsVista && button.state.image.empty() == false && text.empty() == false) {
//Vista+ does not add spacing between the icon and text; causing them to run into each other
SetWindowText(hwnd, utf16_t(string{" ", text}));
} else {
SetWindowText(hwnd, utf16_t(text));
}
}
void pButton::constructor() {
@ -74,7 +89,7 @@ void pButton::constructor() {
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&button);
setDefaultFont();
setImage(button.state.image, button.state.orientation);
setText(button.state.text);
//setText(button.state.text); //called by setImage();
synchronize();
}

View File

@ -2,8 +2,12 @@ bool pWidget::enabled() {
return IsWindowEnabled(hwnd);
}
bool pWidget::focused() {
return GetFocus() == hwnd;
}
Geometry pWidget::minimumGeometry() {
return { 0, 0, 0, 0 };
return {0, 0, 0, 0};
}
void pWidget::setEnabled(bool enabled) {

View File

@ -40,9 +40,9 @@ string Ananke::createSufamiTurboHeuristic(vector<uint8_t> &buffer) {
file::write({pathname, "manifest.bml"}, {
"cartridge\n",
" rom name=program.rom size=0x", hex(buffer.size()), "\n",
" ram name=save.ram size=0x2000\n"
"\n"
"information\n"
" ram name=save.ram size=0x2000\n",
"\n",
"information\n",
" title: ", nall::basename(information.name), "\n"
});
file::write({pathname, "program.rom"}, buffer);

View File

@ -3,7 +3,7 @@
namespace Emulator {
static const char Name[] = "higan";
static const char Version[] = "091.15";
static const char Version[] = "092";
static const char Author[] = "byuu";
static const char License[] = "GPLv3";
}

View File

@ -21,7 +21,7 @@ struct Interface {
unsigned id;
string name;
string type;
bool bootable; //false for slotted sub-cartridges (Super Game Boy et al)
bool bootable; //false for cartridge slots (eg Sufami Turbo cartridges)
};
vector<Media> media;
@ -75,7 +75,7 @@ struct Interface {
template<typename... Args> void notify(Args&... args) { return bind->notify({std::forward<Args>(args)...}); }
//information
virtual string title() { return ""; }
virtual string title() = 0;
virtual double videoFrequency() = 0;
virtual double audioFrequency() = 0;

View File

@ -87,12 +87,12 @@ Board::Board(Markup::Node &document) {
auto cartridge = document["cartridge"];
information.type = cartridge["board/type"].data;
information.battery = cartridge["prg/ram/nonvolatile"].exists();
information.battery = cartridge["prg/ram/name"].exists();
auto prom = cartridge["prg"]["rom"];
auto pram = cartridge["prg"]["ram"];
auto crom = cartridge["chr"]["rom"];
auto cram = cartridge["chr"]["ram"];
auto prom = cartridge["prg/rom"];
auto pram = cartridge["prg/ram"];
auto crom = cartridge["chr/rom"];
auto cram = cartridge["chr/ram"];
prgrom.size = numeral(prom["size"].data);
prgram.size = numeral(pram["size"].data);
@ -122,6 +122,7 @@ Board::~Board() {
Board* Board::load(const string &manifest) {
auto document = Markup::Document(manifest);
cartridge.information.title = document["information/title"].text();
string type = document["cartridge/board/type"].text();
if(type == "BANDAI-FCG" ) return new BandaiFCG(document);

View File

@ -42,6 +42,9 @@ void System::runthreadtosave() {
}
void System::load() {
string manifest = string::read({interface->path(ID::System), "manifest.bml"});
auto document = Markup::Document(manifest);
serialize_init();
}

View File

@ -45,8 +45,8 @@ void Cartridge::load(System::Revision revision, const string &manifest) {
information.rtc = false;
information.rumble = false;
auto rom = document["cartridge"]["rom"];
auto ram = document["cartridge"]["ram"];
auto rom = document["cartridge/rom"];
auto ram = document["cartridge/ram"];
romsize = numeral(rom["size"].data);
romdata = allocate<uint8>(romsize, 0xff);
@ -63,8 +63,8 @@ void Cartridge::load(System::Revision revision, const string &manifest) {
if(ram["name"].exists()) memory.append({ID::RAM, ram["name"].data});
}
information.romsize = numeral(document["cartridge"]["rom"]["size"].data);
information.ramsize = numeral(document["cartridge"]["ram"]["size"].data);
information.romsize = numeral(rom["size"].data);
information.ramsize = numeral(ram["size"].data);
information.battery = ram["name"].exists();
switch(information.mapper) { default:

View File

@ -49,15 +49,15 @@ void System::load(Revision revision) {
serialize_init();
if(revision == Revision::SuperGameBoy) return; //Super Famicom core loads boot ROM for SGB
string manifest, firmware;
manifest.readfile({interface->path(ID::System), "manifest.xml"});
XML::Document document(manifest);
string manifest = string::read({interface->path(ID::System), "manifest.bml"});
auto document = Markup::Document(manifest);
interface->loadRequest(
revision == Revision::GameBoy ? ID::GameBoyBootROM : ID::GameBoyColorBootROM,
document["system"]["cpu"]["firmware"]["name"].data
document["system/cpu/rom/name"].data
);
if(!file::exists({interface->path(ID::System), document["system"]["cpu"]["firmware"]["name"].data})) {
interface->notify("Error: required firmware ", firmware, " not found.\n");
if(!file::exists({interface->path(ID::System), document["system/cpu/rom/name"].data})) {
interface->notify("Error: required Game Boy firmware boot.rom not found.\n");
}
}

View File

@ -23,13 +23,12 @@ void System::power() {
}
void System::load() {
string manifest;
manifest.readfile({interface->path(ID::System), "manifest.xml"});
XML::Document document(manifest);
string firmware = document["system"]["cpu"]["firmware"]["name"].data;
interface->loadRequest(ID::BIOS, firmware);
if(!file::exists({interface->path(ID::System), firmware})) {
interface->notify("Error: required firmware ", firmware, " not found.\n");
string manifest = string::read({interface->path(ID::System), "manifest.bml"});
auto document = Markup::Document(manifest);
interface->loadRequest(ID::BIOS, document["system/cpu/rom/name"].data);
if(!file::exists({interface->path(ID::System), document["system/cpu/rom/name"].data})) {
interface->notify("Error: required Game Boy Advance firmware bios.rom not found.\n");
}
serialize_init();

View File

@ -1,173 +0,0 @@
#ifndef NALL_EMULATION_FAMICOM_HPP
#define NALL_EMULATION_FAMICOM_HPP
#include <nall/sha256.hpp>
#include <nall/string.hpp>
namespace nall {
struct FamicomCartridge {
string markup;
inline FamicomCartridge(const uint8_t *data, unsigned size);
//private:
unsigned mapper;
unsigned mirror;
unsigned prgrom;
unsigned prgram;
unsigned chrrom;
unsigned chrram;
};
FamicomCartridge::FamicomCartridge(const uint8_t *data, unsigned size) {
markup = "";
if(size < 16) return;
if(data[0] != 'N') return;
if(data[1] != 'E') return;
if(data[2] != 'S') return;
if(data[3] != 26) return;
mapper = ((data[7] >> 4) << 4) | (data[6] >> 4);
mirror = ((data[6] & 0x08) >> 2) | (data[6] & 0x01);
prgrom = data[4] * 0x4000;
chrrom = data[5] * 0x2000;
prgram = 0u;
chrram = chrrom == 0u ? 8192u : 0u;
markup.append("cartridge\n");
switch(mapper) {
default:
markup.append(" board type=NES-NROM-256\n");
markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n");
break;
case 1:
markup.append(" board type=NES-SXROM\n");
markup.append(" chip type=MMC1B2\n");
prgram = 8192;
break;
case 2:
markup.append(" board type=NES-UOROM\n");
markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n");
break;
case 3:
markup.append(" board type=NES-CNROM\n");
markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n");
break;
case 4:
//MMC3
markup.append(" board type=NES-TLROM\n");
markup.append(" chip type=MMC3B\n");
prgram = 8192;
//MMC6
//markup.append(" board type=NES-HKROM\n");
//markup.append(" chip type=MMC6n");
//prgram = 1024;
break;
case 5:
markup.append(" board type=NES-ELROM\n");
markup.append(" chip type=MMC5\n");
prgram = 65536;
break;
case 7:
markup.append(" board type=NES-AOROM\n");
break;
case 9:
markup.append(" board type=NES-PNROM\n");
markup.append(" chip type=MMC2\n");
prgram = 8192;
break;
case 10:
markup.append(" board type=NES-FKROM\n");
markup.append(" chip type=MMC4\n");
prgram = 8192;
break;
case 16:
markup.append(" board type=BANDAI-FCG\n");
markup.append(" chip type=LZ93D50\n");
break;
case 21:
case 23:
case 25:
//VRC4
markup.append(" board type=KONAMI-VRC-4\n");
markup.append(" chip type=VRC4\n");
markup.append(" pinout a0=1 a1=0\n");
prgram = 8192;
break;
case 22:
//VRC2
markup.append(" board type=KONAMI-VRC-2\n");
markup.append(" chip type=VRC2\n");
markup.append(" pinout a0=0 a1=1\n");
break;
case 24:
markup.append(" board type=KONAMI-VRC-6\n");
markup.append(" chip type=VRC6\n");
break;
case 26:
markup.append(" board type=KONAMI-VRC-6\n");
markup.append(" chip type=VRC6\n");
prgram = 8192;
break;
case 34:
markup.append(" board type=NES-BNROM\n");
markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n");
break;
case 66:
markup.append(" board type=NES-GNROM\n");
markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n");
break;
case 69:
markup.append(" board type=SUNSOFT-5B\n");
markup.append(" chip type=5B\n");
prgram = 8192;
break;
case 73:
markup.append(" board type=KONAMI-VRC-3\n");
markup.append(" chip type=VRC3\n");
markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n");
prgram = 8192;
break;
case 75:
markup.append(" board type=KONAMI-VRC-1\n");
markup.append(" chip type=VRC1\n");
break;
case 85:
markup.append(" board type=KONAMI-VRC-7\n");
markup.append(" chip type=VRC7\n");
prgram = 8192;
break;
}
markup.append(" prg\n");
if(prgrom) markup.append(" rom name=program.rom size=0x", hex(prgrom), "\n");
if(prgram) markup.append(" ram name=save.ram size=0x", hex(prgram), "\n");
markup.append(" chr\n");
if(chrrom) markup.append(" rom name=character.rom size=0x", hex(chrrom), "\n");
if(chrram) markup.append(" ram size=0x", hex(chrram), "\n");
}
}
#endif

View File

@ -1,63 +0,0 @@
#ifndef NALL_EMULATION_GAME_BOY_ADVANCE_HPP
#define NALL_EMULATION_GAME_BOY_ADVANCE_HPP
#include <nall/sha256.hpp>
#include <nall/string.hpp>
#include <nall/vector.hpp>
namespace nall {
struct GameBoyAdvanceCartridge {
string markup;
string identifiers;
inline GameBoyAdvanceCartridge(const uint8_t *data, unsigned size);
};
GameBoyAdvanceCartridge::GameBoyAdvanceCartridge(const uint8_t *data, unsigned size) {
struct Identifier {
string name;
unsigned size;
};
vector<Identifier> idlist;
idlist.append({"SRAM_V", 6});
idlist.append({"SRAM_F_V", 8});
idlist.append({"EEPROM_V", 8});
idlist.append({"FLASH_V", 7});
idlist.append({"FLASH512_V", 10});
idlist.append({"FLASH1M_V", 9});
lstring list;
for(auto &id : idlist) {
for(signed n = 0; n < size - 16; n++) {
if(!memcmp(data + n, (const char*)id.name, id.size)) {
const char *p = (const char*)data + n + id.size;
if(p[0] >= '0' && p[0] <= '9'
&& p[1] >= '0' && p[1] <= '9'
&& p[2] >= '0' && p[2] <= '9'
) {
char text[16];
memcpy(text, data + n, id.size + 3);
text[id.size + 3] = 0;
list.appendonce(text);
}
}
}
}
identifiers = list.concatenate(",");
markup = "";
markup.append("cartridge\n");
markup.append(" rom name=program.rom size=0x", hex(size), "\n");
if(0);
else if(identifiers.beginswith("SRAM_V" )) markup.append(" ram name=save.ram type=SRAM size=0x8000\n");
else if(identifiers.beginswith("SRAM_F_V" )) markup.append(" ram name=save.ram type=FRAM size=0x8000\n");
else if(identifiers.beginswith("EEPROM_V" )) markup.append(" ram name=save.ram type=EEPROM size=0x0\n");
else if(identifiers.beginswith("FLASH_V" )) markup.append(" ram name=save.ram type=FlashROM size=0x10000\n");
else if(identifiers.beginswith("FLASH512_V")) markup.append(" ram name=save.ram type=FlashROM size=0x10000\n");
else if(identifiers.beginswith("FLASH1M_V" )) markup.append(" ram name=save.ram type=FlashROM size=0x20000\n");
//if(identifiers.empty() == false) markup.append(" #detected: ", identifiers, "\n");
}
}
#endif

View File

@ -1,120 +0,0 @@
#ifndef NALL_EMULATION_GAME_BOY_HPP
#define NALL_EMULATION_GAME_BOY_HPP
#include <nall/sha256.hpp>
#include <nall/string.hpp>
namespace nall {
struct GameBoyCartridge {
string markup;
inline GameBoyCartridge(uint8_t *data, unsigned size);
//private:
struct Information {
string mapper;
bool ram;
bool battery;
bool rtc;
bool rumble;
unsigned romsize;
unsigned ramsize;
bool cgb;
bool cgbonly;
} info;
};
GameBoyCartridge::GameBoyCartridge(uint8_t *romdata, unsigned romsize) {
markup = "";
if(romsize < 0x4000) return;
info.mapper = "unknown";
info.ram = false;
info.battery = false;
info.rtc = false;
info.rumble = false;
info.romsize = 0;
info.ramsize = 0;
unsigned base = romsize - 0x8000;
if(romdata[base + 0x0104] == 0xce && romdata[base + 0x0105] == 0xed
&& romdata[base + 0x0106] == 0x66 && romdata[base + 0x0107] == 0x66
&& romdata[base + 0x0108] == 0xcc && romdata[base + 0x0109] == 0x0d
&& romdata[base + 0x0147] >= 0x0b && romdata[base + 0x0147] <= 0x0d
) {
//MMM01 stores header at bottom of image
//flip this around for consistency with all other mappers
uint8_t header[0x8000];
memcpy(header, romdata + base, 0x8000);
memmove(romdata + 0x8000, romdata, romsize - 0x8000);
memcpy(romdata, header, 0x8000);
}
info.cgb = (romdata[0x0143] & 0x80) == 0x80;
info.cgbonly = (romdata[0x0143] & 0xc0) == 0xc0;
switch(romdata[0x0147]) {
case 0x00: info.mapper = "none"; break;
case 0x01: info.mapper = "MBC1"; break;
case 0x02: info.mapper = "MBC1"; info.ram = true; break;
case 0x03: info.mapper = "MBC1"; info.ram = true; info.battery = true; break;
case 0x05: info.mapper = "MBC2"; info.ram = true; break;
case 0x06: info.mapper = "MBC2"; info.ram = true; info.battery = true; break;
case 0x08: info.mapper = "none"; info.ram = true; break;
case 0x09: info.mapper = "MBC0"; info.ram = true; info.battery = true; break;
case 0x0b: info.mapper = "MMM01"; break;
case 0x0c: info.mapper = "MMM01"; info.ram = true; break;
case 0x0d: info.mapper = "MMM01"; info.ram = true; info.battery = true; break;
case 0x0f: info.mapper = "MBC3"; info.rtc = true; info.battery = true; break;
case 0x10: info.mapper = "MBC3"; info.rtc = true; info.ram = true; info.battery = true; break;
case 0x11: info.mapper = "MBC3"; break;
case 0x12: info.mapper = "MBC3"; info.ram = true; break;
case 0x13: info.mapper = "MBC3"; info.ram = true; info.battery = true; break;
case 0x19: info.mapper = "MBC5"; break;
case 0x1a: info.mapper = "MBC5"; info.ram = true; break;
case 0x1b: info.mapper = "MBC5"; info.ram = true; info.battery = true; break;
case 0x1c: info.mapper = "MBC5"; info.rumble = true; break;
case 0x1d: info.mapper = "MBC5"; info.rumble = true; info.ram = true; break;
case 0x1e: info.mapper = "MBC5"; info.rumble = true; info.ram = true; info.battery = true; break;
case 0xfc: break; //Pocket Camera
case 0xfd: break; //Bandai TAMA5
case 0xfe: info.mapper = "HuC3"; break;
case 0xff: info.mapper = "HuC1"; info.ram = true; info.battery = true; break;
}
switch(romdata[0x0148]) { default:
case 0x00: info.romsize = 2 * 16 * 1024; break;
case 0x01: info.romsize = 4 * 16 * 1024; break;
case 0x02: info.romsize = 8 * 16 * 1024; break;
case 0x03: info.romsize = 16 * 16 * 1024; break;
case 0x04: info.romsize = 32 * 16 * 1024; break;
case 0x05: info.romsize = 64 * 16 * 1024; break;
case 0x06: info.romsize = 128 * 16 * 1024; break;
case 0x07: info.romsize = 256 * 16 * 1024; break;
case 0x52: info.romsize = 72 * 16 * 1024; break;
case 0x53: info.romsize = 80 * 16 * 1024; break;
case 0x54: info.romsize = 96 * 16 * 1024; break;
}
switch(romdata[0x0149]) { default:
case 0x00: info.ramsize = 0 * 1024; break;
case 0x01: info.ramsize = 2 * 1024; break;
case 0x02: info.ramsize = 8 * 1024; break;
case 0x03: info.ramsize = 32 * 1024; break;
}
if(info.mapper == "MBC2") info.ramsize = 512; //512 x 4-bit
markup = "";
markup.append("cartridge\n");
markup.append(" board type=", info.mapper, "\n");
markup.append(" rom name=program.rom size=0x", hex(romsize), "\n");
if(info.ramsize > 0) markup.append(" ram name=save.ram size=0x", hex(info.ramsize), "\n");
}
}
#endif

View File

@ -1,26 +0,0 @@
#ifndef NALL_EMULATION_SATELLAVIEW_HPP
#define NALL_EMULATION_SATELLAVIEW_HPP
#include <nall/sha256.hpp>
#include <nall/string.hpp>
namespace nall {
struct SatellaviewCartridge {
string markup;
inline SatellaviewCartridge(const uint8_t *data, unsigned size);
};
SatellaviewCartridge::SatellaviewCartridge(const uint8_t *data, unsigned size) {
markup = "";
markup.append("<?xml version='1.0' encoding='UTF-8'?>\n");
markup.append("<cartridge sha256='", sha256(data, size) ,"'>\n");
markup.append(" <rom name='program.rom' size='0x", hex(size), "'/>\n");
markup.append("</cartridge>\n");
markup.transform("'", "\"");
}
}
#endif

View File

@ -1,33 +0,0 @@
#ifndef NALL_EMULATION_SUFAMI_TURBO_HPP
#define NALL_EMULATION_SUFAMI_TURBO_HPP
#include <nall/sha256.hpp>
#include <nall/string.hpp>
namespace nall {
struct SufamiTurboCartridge {
string markup;
inline SufamiTurboCartridge(const uint8_t *data, unsigned size);
};
SufamiTurboCartridge::SufamiTurboCartridge(const uint8_t *data, unsigned size) {
markup = "";
if(size < 0x20000) return; //too small to be a valid game?
if(memcmp(data, "BANDAI SFC-ADX", 14)) return; //missing required header?
unsigned romsize = data[0x36] * 0x20000; //128KB
unsigned ramsize = data[0x37] * 0x800; //2KB
bool linkable = data[0x35] != 0x00; //TODO: unconfirmed
markup.append("<?xml version='1.0' encoding='UTF-8'?>\n");
markup.append("<cartridge linkable='", linkable, "' sha256='", sha256(data, size) ,"'>\n");
markup.append(" <rom name='program.rom' size='0x", hex(romsize), "'/>\n");
markup.append(" <ram name='save.ram' size='0x", hex(ramsize), "'/>\n");
markup.append("</cartridge>\n");
markup.transform("'", "\"");
}
}
#endif

View File

@ -1,814 +0,0 @@
#ifndef NALL_EMULATION_SUPER_FAMICOM_HPP
#define NALL_EMULATION_SUPER_FAMICOM_HPP
#include <nall/sha256.hpp>
#include <nall/string.hpp>
namespace nall {
struct SuperFamicomCartridge {
string markup;
inline SuperFamicomCartridge(const uint8_t *data, unsigned size);
//private:
inline void read_header(const uint8_t *data, unsigned size);
inline unsigned find_header(const uint8_t *data, unsigned size);
inline unsigned score_header(const uint8_t *data, unsigned size, unsigned addr);
enum HeaderField {
CartName = 0x00,
Mapper = 0x15,
RomType = 0x16,
RomSize = 0x17,
RamSize = 0x18,
CartRegion = 0x19,
Company = 0x1a,
Version = 0x1b,
Complement = 0x1c, //inverse checksum
Checksum = 0x1e,
ResetVector = 0x3c,
};
enum Mode {
ModeNormal,
ModeBsxSlotted,
ModeBsx,
ModeSufamiTurbo,
ModeSuperGameBoy,
};
enum Type {
TypeNormal,
TypeBsxSlotted,
TypeBsxBios,
TypeBsx,
TypeSufamiTurboBios,
TypeSufamiTurbo,
TypeSuperGameBoy1Bios,
TypeSuperGameBoy2Bios,
TypeGameBoy,
TypeUnknown,
};
enum Region {
NTSC,
PAL,
};
enum MemoryMapper {
LoROM,
HiROM,
ExLoROM,
ExHiROM,
SuperFXROM,
SA1ROM,
SPC7110ROM,
BSCLoROM,
BSCHiROM,
BSXROM,
STROM,
};
enum DSP1MemoryMapper {
DSP1Unmapped,
DSP1LoROM1MB,
DSP1LoROM2MB,
DSP1HiROM,
};
bool loaded; //is a base cartridge inserted?
unsigned crc32; //crc32 of all cartridges (base+slot(s))
unsigned rom_size;
unsigned ram_size;
bool firmware_appended; //true if firmware is appended to end of ROM data
Mode mode;
Type type;
Region region;
MemoryMapper mapper;
DSP1MemoryMapper dsp1_mapper;
bool has_bsx_slot;
bool has_superfx;
bool has_sa1;
bool has_srtc;
bool has_sdd1;
bool has_spc7110;
bool has_spc7110rtc;
bool has_cx4;
bool has_dsp1;
bool has_dsp2;
bool has_dsp3;
bool has_dsp4;
bool has_obc1;
bool has_st010;
bool has_st011;
bool has_st018;
};
SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) {
firmware_appended = false;
//skip copier header
if((size & 0x7fff) == 512) data += 512, size -= 512;
markup = "";
if(size < 0x8000) return;
read_header(data, size);
markup = "";
if(type == TypeGameBoy) return;
if(type == TypeBsx) return;
if(type == TypeSufamiTurbo) return;
const char *range = (rom_size > 0x200000) || (ram_size > 32 * 1024) ? "0000-7fff" : "0000-ffff";
markup.append("cartridge region=", region == NTSC ? "NTSC" : "PAL", "\n");
if(type == TypeSuperGameBoy1Bios || type == TypeSuperGameBoy2Bios) {
markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n"
" map id=rom address=00-7f,80-ff:8000-ffff\n"
" icd2 revision=1\n"
" rom name=boot.rom size=0x100\n"
" map id=io address=00-3f,80-bf:6000-7fff\n"
);
if((rom_size & 0x7fff) == 0x100) {
firmware_appended = true;
rom_size -= 0x100;
}
}
else if(has_cx4) {
markup.append(
" hitachidsp model=HG51B169 frequency=20000000\n"
" rom id=program name=program.rom size=0x", hex(rom_size), "\n"
" rom id=data name=cx4.data.rom size=0xc00\n"
" ram id=data size=0xc00\n"
" map id=io address=00-3f,80-bf:6000-7fff\n"
" map id=rom address=00-7f,80-ff:8000-ffff mask=0x8000\n"
" map id=ram address=70-77:0000-7fff\n"
);
if((rom_size & 0x7fff) == 0xc00) {
firmware_appended = true;
rom_size -= 0xc00;
}
}
else if(has_spc7110) {
markup.append(
" spc7110\n"
" rom id=program name=program.rom size=0x100000\n"
" rom id=data name=data.rom size=0x", hex(rom_size - 0x100000), "\n"
" ram name=save.ram size=0x", hex(ram_size), "\n"
" map id=io address=00-3f,80-bf:4800-483f\n"
" map id=io address=50:0000-ffff\n"
" map id=rom address=00-3f,80-bf:8000-ffff\n"
" map id=rom address=c0-ff:0000-ffff\n"
" map id=ram address=00-3f,80-bf:6000-7fff mask=0xe000\n"
);
}
else if(has_sdd1) {
markup.append(
" sdd1\n"
" rom name=program.rom size=0x", hex(rom_size), "\n"
);
if(ram_size > 0) markup.append(
" ram name=save.ram size=0x", hex(ram_size), "\n"
);
markup.append(
" map id=io address=00-3f,80-bf:4800-4807\n"
" map id=rom address=00-3f,80-bf:8000-ffff mask=0x8000\n"
" map id=rom address=c0-ff:0000-ffff\n"
);
if(ram_size > 0) markup.append(
" map id=ram address=20-3f,a0-bf:6000-7fff mask=0xe000\n"
" map id=ram address=70-7f:0000-7fff\n"
);
}
else if(mapper == LoROM) {
markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n"
);
if(ram_size > 0) markup.append(
" ram name=save.ram size=0x", hex(ram_size), "\n"
);
markup.append(
" map id=rom address=00-7f,80-ff:8000-ffff mask=0x8000\n"
);
if(ram_size > 0) markup.append(
" map id=ram address=70-7f,f0-ff:", range, "\n"
);
}
else if(mapper == HiROM) {
markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n"
);
if(ram_size > 0) markup.append(
" ram name=save.ram size=0x", hex(ram_size), "\n"
);
markup.append(
" map id=rom address=00-3f,80-bf:8000-ffff\n"
" map id=rom address=40-7f,c0-ff:0000-ffff\n"
);
if(ram_size > 0) markup.append(
" map id=ram address=10-3f,90-bf:6000-7fff mask=0xe000\n"
);
}
else if(mapper == ExLoROM) {
markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n"
);
if(ram_size > 0) markup.append(
" ram name=save.ram size=0x", hex(ram_size), "\n"
);
markup.append(
" map id=rom address=00-3f,80-bf:8000-ffff mask=0x8000\n"
" map id=rom address=40-7f:0000-ffff\n"
);
if(ram_size > 0) markup.append(
" map id=ram address=20-3f,a0-bf:6000-7fff\n"
" map id=ram address=70-7f:0000-7fff\n"
);
}
else if(mapper == ExHiROM) {
markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n"
);
if(ram_size > 0) markup.append(
" ram name=save.ram size=0x", hex(ram_size), "\n"
);
markup.append(
" map id=rom address=00-3f:8000-ffff offset=0x400000\n"
" map id=rom address=40-7f:0000-ffff offset=0x400000\n"
" map id=rom address=80-bf:8000-ffff offset=0x000000\n"
" map id=rom address=c0-ff:0000-ffff offset=0x000000\n"
);
if(ram_size > 0) markup.append(
" map id=ram address=20-3f,a0-bf:6000-7fff mask=0xe000\n"
" map id=ram address=70-7f:", range, "\n"
);
}
else if(mapper == SuperFXROM) {
markup.append(
" superfx revision=3\n"
" rom name=program.rom size=0x", hex(rom_size), "\n"
);
if(ram_size > 0) markup.append(
" ram name=save.ram size=0x", hex(ram_size), "\n"
);
markup.append(
" map id=io address=00-3f,80-bf:3000-32ff\n"
" map id=rom address=00-3f,80-bf:8000-ffff mask=0x8000\n"
" map id=rom address=40-5f,c0-df:0000-ffff\n"
);
if(ram_size > 0) markup.append(
" map id=ram address=00-3f,80-bf:6000-7fff size=0x2000\n"
" map id=ram address=70-71,f0-f1:0000-ffff\n"
);
}
else if(mapper == SA1ROM) {
markup.append(
" sa1\n"
" rom name=program.rom size=0x", hex(rom_size), "\n"
);
if(ram_size > 0) markup.append(
" ram id=bitmap name=save.ram size=0x", hex(ram_size), "\n"
);
markup.append(
" ram id=internal size=0x800\n"
" map id=io address=00-3f,80-bf:2200-23ff\n"
" map id=rom address=00-3f,80-bf:8000-ffff\n"
" map id=rom address=c0-ff:0000-ffff\n"
);
if(ram_size > 0) markup.append(
" map id=bwram address=00-3f,80-bf:6000-7fff\n"
" map id=bwram address=40-4f:0000-ffff\n"
);
markup.append(
" map id=iram address=00-3f,80-bf:3000-37ff\n"
);
}
else if(mapper == BSCLoROM) {
markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n"
" ram name=save.ram size=0x", hex(ram_size), "\n"
" map id=rom address=00-1f:8000-ffff offset=0x000000 mask=0x8000\n"
" map id=rom address=20-3f:8000-ffff offset=0x100000 mask=0x8000\n"
" map id=rom address=80-9f:8000-ffff offset=0x200000 mask=0x8000\n"
" map id=rom address=a0-bf:8000-ffff offset=0x100000 mask=0x8000\n"
" map id=ram address=70-7f,f0-ff:0000-7fff\n"
" bsxslot\n"
" map id=rom address=c0-ef:0000-ffff\n"
);
}
else if(mapper == BSCHiROM) {
markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n"
" ram name=save.ram size=0x", hex(ram_size), "\n"
" map id=rom address=00-1f,80-9f:8000-ffff\n"
" map id=rom address=40-5f,c0-df:0000-ffff\n"
" map id=ram address=20-3f,a0-bf:6000-7fff\n"
" bsxslot\n"
" map id=rom address=20-3f,a0-bf:8000-ffff\n"
" map id=rom address=60-7f,e0-ff:0000-ffff\n"
);
}
else if(mapper == BSXROM) {
markup.append(
" bsx\n"
" rom name=program.rom size=0x", hex(rom_size), "\n"
" ram id=save name=save.ram size=0x", hex(ram_size), "\n"
" ram id=download name=bsx.ram size=0x40000\n"
" map id=io address=00-3f,80-bf:5000-5fff\n"
" map id=rom address=00-3f,80-bf:8000-ffff\n"
" map id=rom address=40-7f,c0-ff:0000-ffff\n"
" map id=ram address=20-3f:6000-7fff\n"
);
}
else if(mapper == STROM) {
markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n"
" map id=rom address='00-1f,80-9f:8000-ffff mask=0x8000\n"
" sufamiturbo\n"
" slot id=A\n"
" map id=rom address=20-3f,a0-bf:8000-ffff mask=0x8000\n"
" map id=ram address=60-63,e0-e3:8000-ffff\n"
" slot id=B\n"
" map id=rom address=40-5f,c0-df:8000-ffff mask=0x8000\n"
" map id=ram address=70-73,f0-f3:8000-ffff\n"
);
}
if(has_spc7110rtc) {
markup.append(
" epsonrtc\n"
" ram name=rtc.ram size=0x10\n"
" map id=io address=00-3f,80-bf:4840-4842\n"
);
}
if(has_srtc) {
markup.append(
" sharprtc\n"
" ram name=rtc.ram size=0x10\n"
" map id=io address=00-3f,80-bf:2800-2801\n"
);
}
if(has_obc1) {
markup.append(
" obc1\n"
" ram name=save.ram size=0x2000\n"
" map id=io address=00-3f,80-bf:6000-7fff\n"
);
}
if(has_dsp1) {
markup.append(
" necdsp model=uPD7725 frequency=8000000\n"
" rom id=program name=dsp1b.program.rom size=0x1800\n"
" rom id=data name=dsp1b.data.rom size=0x800\n"
" ram id=data size=0x200\n"
);
if(dsp1_mapper == DSP1LoROM1MB) markup.append(
" map id=io address=20-3f,a0-bf:8000-ffff select=0x4000\n"
);
if(dsp1_mapper == DSP1LoROM2MB) markup.append(
" map id=io address=60-6f,e0-ef:0000-7fff select=0x4000\n"
);
if(dsp1_mapper == DSP1HiROM) markup.append(
" map id=io address=00-1f,80-9f:6000-7fff select=0x1000\n"
);
if((size & 0x7fff) == 0x2000) {
firmware_appended = true;
rom_size -= 0x2000;
}
}
if(has_dsp2) {
markup.append(
" necdsp model=uPD7725 frequency=8000000\n"
" rom id=program name=dsp2.program.rom size=0x1800\n"
" rom id=data name=dsp2.data.rom size=0x800\n"
" ram id=data size=0x200\n"
" map id=io address=20-3f,a0-bf:8000-ffff select=0x4000\n"
);
if((size & 0x7fff) == 0x2000) {
firmware_appended = true;
rom_size -= 0x2000;
}
}
if(has_dsp3) {
markup.append(
" necdsp model=uPD7725 frequency=8000000\n"
" rom id=program name=dsp3.program.rom size=0x1800\n"
" rom id=data name=dsp3.data.rom size=0x800\n"
" ram id=data size=0x200\n"
" map id=io address=20-3f,a0-bf:8000-ffff select=0x4000\n"
);
if((size & 0x7fff) == 0x2000) {
firmware_appended = true;
rom_size -= 0x2000;
}
}
if(has_dsp4) {
markup.append(
" necdsp model=uPD7725 frequency=8000000\n"
" rom id=program name=dsp4.program.rom size=0x1800\n"
" rom id=data name=dsp4.data.rom size=0x800\n"
" ram id=data size=0x200\n"
" map address=30-3f,b0-bf:8000-ffff select=0x4000\n"
);
if((size & 0x7fff) == 0x2000) {
firmware_appended = true;
rom_size -= 0x2000;
}
}
if(has_st010) {
markup.append(
" necdsp model=uPD96050 frequency=11000000\n"
" rom id=program name=st010.program.rom size=0xc000\n"
" rom id=data name=st010.data.rom size=0x1000\n"
" ram id=data name=save.ram size=0x1000\n"
" map id=io address=60-67,e0-e7:0000-3fff select=0x0001\n"
" map id=ram address=68-6f,e8-ef:0000-7fff\n"
);
if((size & 0xffff) == 0xd000) {
firmware_appended = true;
rom_size -= 0xd000;
}
}
if(has_st011) {
markup.append(
" necdsp model=uPD96050 frequency=15000000\n"
" rom id=program name=st011.program.rom size=0xc000\n"
" rom id=data name=st011.data.rom size=0x1000\n"
" ram id=data name=save.ram size=0x1000\n"
" map id=io address=60-67,e0-e7:0000-3fff select=0x0001\n"
" map id=ram address=68-6f,e8-ef:0000-7fff\n"
);
if((size & 0xffff) == 0xd000) {
firmware_appended = true;
rom_size -= 0xd000;
}
}
if(has_st018) {
markup.append(
" armdsp frequency=21477272\n"
" rom id=program name=st018.program.rom size=0x20000\n"
" rom id=data name=st018.data.rom size=0x8000\n"
" ram name=save.ram size=0x4000\n"
" map id=io address=00-3f,80-bf:3800-38ff\n"
);
if((size & 0x3ffff) == 0x28000) {
firmware_appended = true;
rom_size -= 0x28000;
}
}
}
void SuperFamicomCartridge::read_header(const uint8_t *data, unsigned size) {
type = TypeUnknown;
mapper = LoROM;
dsp1_mapper = DSP1Unmapped;
region = NTSC;
rom_size = size;
ram_size = 0;
has_bsx_slot = false;
has_superfx = false;
has_sa1 = false;
has_srtc = false;
has_sdd1 = false;
has_spc7110 = false;
has_spc7110rtc = false;
has_cx4 = false;
has_dsp1 = false;
has_dsp2 = false;
has_dsp3 = false;
has_dsp4 = false;
has_obc1 = false;
has_st010 = false;
has_st011 = false;
has_st018 = false;
//=====================
//detect Game Boy carts
//=====================
if(size >= 0x0140) {
if(data[0x0104] == 0xce && data[0x0105] == 0xed && data[0x0106] == 0x66 && data[0x0107] == 0x66
&& data[0x0108] == 0xcc && data[0x0109] == 0x0d && data[0x010a] == 0x00 && data[0x010b] == 0x0b) {
type = TypeGameBoy;
return;
}
}
if(size < 32768) {
type = TypeUnknown;
return;
}
const unsigned index = find_header(data, size);
const uint8_t mapperid = data[index + Mapper];
const uint8_t rom_type = data[index + RomType];
const uint8_t rom_size = data[index + RomSize];
const uint8_t company = data[index + Company];
const uint8_t regionid = data[index + CartRegion] & 0x7f;
ram_size = 1024 << (data[index + RamSize] & 7);
if(ram_size == 1024) ram_size = 0; //no RAM present
if(rom_size == 0 && ram_size) ram_size = 0; //fix for Bazooka Blitzkrieg's malformed header (swapped ROM and RAM sizes)
//0, 1, 13 = NTSC; 2 - 12 = PAL
region = (regionid <= 1 || regionid >= 13) ? NTSC : PAL;
//=======================
//detect BS-X flash carts
//=======================
if(data[index + 0x13] == 0x00 || data[index + 0x13] == 0xff) {
if(data[index + 0x14] == 0x00) {
const uint8_t n15 = data[index + 0x15];
if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) {
if(data[index + 0x1a] == 0x33 || data[index + 0x1a] == 0xff) {
type = TypeBsx;
mapper = BSXROM;
region = NTSC; //BS-X only released in Japan
return;
}
}
}
}
//=========================
//detect Sufami Turbo carts
//=========================
if(!memcmp(data, "BANDAI SFC-ADX", 14)) {
if(!memcmp(data + 16, "SFC-ADX BACKUP", 14)) {
type = TypeSufamiTurboBios;
} else {
type = TypeSufamiTurbo;
}
mapper = STROM;
region = NTSC; //Sufami Turbo only released in Japan
return; //RAM size handled outside this routine
}
//==========================
//detect Super Game Boy BIOS
//==========================
if(!memcmp(data + index, "Super GAMEBOY2", 14)) {
type = TypeSuperGameBoy2Bios;
return;
}
if(!memcmp(data + index, "Super GAMEBOY", 13)) {
type = TypeSuperGameBoy1Bios;
return;
}
//=====================
//detect standard carts
//=====================
//detect presence of BS-X flash cartridge connector (reads extended header information)
if(data[index - 14] == 'Z') {
if(data[index - 11] == 'J') {
uint8_t n13 = data[index - 13];
if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) {
if(company == 0x33 || (data[index - 10] == 0x00 && data[index - 4] == 0x00)) {
has_bsx_slot = true;
}
}
}
}
if(has_bsx_slot) {
if(!memcmp(data + index, "Satellaview BS-X ", 21)) {
//BS-X base cart
type = TypeBsxBios;
mapper = BSXROM;
region = NTSC; //BS-X only released in Japan
return; //RAM size handled internally by load_cart_bsx() -> BSXCart class
} else {
type = TypeBsxSlotted;
mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM);
region = NTSC; //BS-X slotted cartridges only released in Japan
}
} else {
//standard cart
type = TypeNormal;
if(index == 0x7fc0 && size >= 0x401000) {
mapper = ExLoROM;
} else if(index == 0x7fc0 && mapperid == 0x32) {
mapper = ExLoROM;
} else if(index == 0x7fc0) {
mapper = LoROM;
} else if(index == 0xffc0) {
mapper = HiROM;
} else { //index == 0x40ffc0
mapper = ExHiROM;
}
}
if(mapperid == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
has_superfx = true;
mapper = SuperFXROM;
ram_size = 1024 << (data[index - 3] & 7);
if(ram_size == 1024) ram_size = 0;
}
if(mapperid == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) {
has_sa1 = true;
mapper = SA1ROM;
}
if(mapperid == 0x35 && rom_type == 0x55) {
has_srtc = true;
}
if(mapperid == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
has_sdd1 = true;
}
if(mapperid == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) {
has_spc7110 = true;
has_spc7110rtc = (rom_type == 0xf9);
mapper = SPC7110ROM;
}
if(mapperid == 0x20 && rom_type == 0xf3) {
has_cx4 = true;
}
if((mapperid == 0x20 || mapperid == 0x21) && rom_type == 0x03) {
has_dsp1 = true;
}
if(mapperid == 0x30 && rom_type == 0x05 && company != 0xb2) {
has_dsp1 = true;
}
if(mapperid == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) {
has_dsp1 = true;
}
if(has_dsp1 == true) {
if((mapperid & 0x2f) == 0x20 && size <= 0x100000) {
dsp1_mapper = DSP1LoROM1MB;
} else if((mapperid & 0x2f) == 0x20) {
dsp1_mapper = DSP1LoROM2MB;
} else if((mapperid & 0x2f) == 0x21) {
dsp1_mapper = DSP1HiROM;
}
}
if(mapperid == 0x20 && rom_type == 0x05) {
has_dsp2 = true;
}
if(mapperid == 0x30 && rom_type == 0x05 && company == 0xb2) {
has_dsp3 = true;
}
if(mapperid == 0x30 && rom_type == 0x03) {
has_dsp4 = true;
}
if(mapperid == 0x30 && rom_type == 0x25) {
has_obc1 = true;
}
if(mapperid == 0x30 && rom_type == 0xf6 && rom_size >= 10) {
has_st010 = true;
}
if(mapperid == 0x30 && rom_type == 0xf6 && rom_size < 10) {
has_st011 = true;
}
if(mapperid == 0x30 && rom_type == 0xf5) {
has_st018 = true;
}
}
unsigned SuperFamicomCartridge::find_header(const uint8_t *data, unsigned size) {
unsigned score_lo = score_header(data, size, 0x007fc0);
unsigned score_hi = score_header(data, size, 0x00ffc0);
unsigned score_ex = score_header(data, size, 0x40ffc0);
if(score_ex) score_ex += 4; //favor ExHiROM on images > 32mbits
if(score_lo >= score_hi && score_lo >= score_ex) {
return 0x007fc0;
} else if(score_hi >= score_ex) {
return 0x00ffc0;
} else {
return 0x40ffc0;
}
}
unsigned SuperFamicomCartridge::score_header(const uint8_t *data, unsigned size, unsigned addr) {
if(size < addr + 64) return 0; //image too small to contain header at this location?
int score = 0;
uint16_t resetvector = data[addr + ResetVector] | (data[addr + ResetVector + 1] << 8);
uint16_t checksum = data[addr + Checksum ] | (data[addr + Checksum + 1] << 8);
uint16_t complement = data[addr + Complement ] | (data[addr + Complement + 1] << 8);
uint8_t resetop = data[(addr & ~0x7fff) | (resetvector & 0x7fff)]; //first opcode executed upon reset
uint8_t mapper = data[addr + Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit
//$00:[000-7fff] contains uninitialized RAM and MMIO.
//reset vector must point to ROM at $00:[8000-ffff] to be considered valid.
if(resetvector < 0x8000) return 0;
//some images duplicate the header in multiple locations, and others have completely
//invalid header information that cannot be relied upon.
//below code will analyze the first opcode executed at the specified reset vector to
//determine the probability that this is the correct header.
//most likely opcodes
if(resetop == 0x78 //sei
|| resetop == 0x18 //clc (clc; xce)
|| resetop == 0x38 //sec (sec; xce)
|| resetop == 0x9c //stz $nnnn (stz $4200)
|| resetop == 0x4c //jmp $nnnn
|| resetop == 0x5c //jml $nnnnnn
) score += 8;
//plausible opcodes
if(resetop == 0xc2 //rep #$nn
|| resetop == 0xe2 //sep #$nn
|| resetop == 0xad //lda $nnnn
|| resetop == 0xae //ldx $nnnn
|| resetop == 0xac //ldy $nnnn
|| resetop == 0xaf //lda $nnnnnn
|| resetop == 0xa9 //lda #$nn
|| resetop == 0xa2 //ldx #$nn
|| resetop == 0xa0 //ldy #$nn
|| resetop == 0x20 //jsr $nnnn
|| resetop == 0x22 //jsl $nnnnnn
) score += 4;
//implausible opcodes
if(resetop == 0x40 //rti
|| resetop == 0x60 //rts
|| resetop == 0x6b //rtl
|| resetop == 0xcd //cmp $nnnn
|| resetop == 0xec //cpx $nnnn
|| resetop == 0xcc //cpy $nnnn
) score -= 4;
//least likely opcodes
if(resetop == 0x00 //brk #$nn
|| resetop == 0x02 //cop #$nn
|| resetop == 0xdb //stp
|| resetop == 0x42 //wdm
|| resetop == 0xff //sbc $nnnnnn,x
) score -= 8;
//at times, both the header and reset vector's first opcode will match ...
//fallback and rely on info validity in these cases to determine more likely header.
//a valid checksum is the biggest indicator of a valid header.
if((checksum + complement) == 0xffff && (checksum != 0) && (complement != 0)) score += 4;
if(addr == 0x007fc0 && mapper == 0x20) score += 2; //0x20 is usually LoROM
if(addr == 0x00ffc0 && mapper == 0x21) score += 2; //0x21 is usually HiROM
if(addr == 0x007fc0 && mapper == 0x22) score += 2; //0x22 is usually ExLoROM
if(addr == 0x40ffc0 && mapper == 0x25) score += 2; //0x25 is usually ExHiROM
if(data[addr + Company] == 0x33) score += 2; //0x33 indicates extended header
if(data[addr + RomType] < 0x08) score++;
if(data[addr + RomSize] < 0x10) score++;
if(data[addr + RamSize] < 0x08) score++;
if(data[addr + CartRegion] < 14) score++;
if(score < 0) score = 0;
return score;
}
}
#endif

View File

@ -29,7 +29,7 @@ namespace nall {
for(signed i = 1, j; i < size; i++) {
T copy = std::move(list[i]);
for(j = i - 1; j >= 0; j--) {
if(lessthan(list[j], copy)) break;
if(!lessthan(copy, list[j])) break;
list[j + 1] = std::move(list[j]);
}
list[j + 1] = std::move(copy);
@ -55,7 +55,7 @@ namespace nall {
T *buffer = new T[size];
unsigned offset = 0, left = 0, right = middle;
while(left < middle && right < size) {
if(lessthan(list[left], list[right])) {
if(!lessthan(list[right], list[left])) {
buffer[offset++] = std::move(list[left++]);
} else {
buffer[offset++] = std::move(list[right++]);

View File

@ -15,6 +15,11 @@ ifeq ($(platform),x)
else ifeq ($(platform),win)
phoenixflags := -DPHOENIX_WINDOWS
phoenixlink := -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -lshlwapi
ifeq ($(arch),win32)
phoenixflags := -m32 $(phoenixflags)
phoenixlink := -m32 $(phoenixlink)
endif
else
phoenixflags := -DPHOENIX_REFERENCE
phoenixlink :=

View File

@ -0,0 +1 @@
system name:Famicom

View File

@ -1,3 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<system name="Famicom">
</system>

View File

@ -0,0 +1,3 @@
system name:Game Boy Advance
cpu
rom name=bios.rom size=16384

View File

@ -1,6 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<system name="Game Boy Advance">
<cpu>
<firmware name="bios.rom" size="16384" sha256="fd2547724b505f487e6dcb29ec2ecff3af35a841a77ab2e85fd87350abd36570"/>
</cpu>
</system>

View File

@ -0,0 +1,3 @@
system name:Game Boy Color
cpu
rom name=boot.rom size=2048

View File

@ -1,6 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<system name="Game Boy Color">
<cpu>
<firmware name="boot.rom" size="2048" sha256="4bf5021be357ce523a59ac5f4efff5d6371ae50112a6db0adf4a75916ad760a9"/>
</cpu>
</system>

View File

@ -0,0 +1,3 @@
system name:Game Boy
cpu
rom name=boot.rom size=256

View File

@ -1,6 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<system name="Game Boy">
<cpu>
<firmware name="boot.rom" size="256" sha256="cf053eccb4ccafff9e67339d4e78e98dce7d1ed59be819d2a1ba2232c6fce1c7"/>
</cpu>
</system>

View File

@ -1,3 +1,3 @@
system name:Super Famicom
smp
rom name=spc700.rom size=64
rom name=ipl.rom size=64

View File

@ -23,4 +23,9 @@ else ifeq ($(platform),osx)
rubylink += $(if $(findstring audio.openal,$(ruby)),-framework OpenAL)
else ifeq ($(platform),win)
rubylink += $(if $(findstring audio.openal,$(ruby)),-lopenal32)
ifeq ($(arch),win32)
rubyflags := -m32 $(rubyflags)
rubylink := -m32 $(rubylink)
endif
endif

View File

@ -15,12 +15,12 @@ ifeq ($(profile),accuracy)
sfcsmp := $(sfc)/smp
sfcdsp := $(sfc)/dsp
sfcppu := $(sfc)/ppu
else ifeq ($(profile),compatibility)
flags += -DPROFILE_COMPATIBILITY
else ifeq ($(profile),balanced)
flags += -DPROFILE_BALANCED
sfccpu := $(sfc)/cpu
sfcsmp := $(sfc)/smp
sfcdsp := $(sfc)/alt/dsp
sfcppu := $(sfc)/alt/ppu-compatibility
sfcppu := $(sfc)/alt/ppu-balanced
else ifeq ($(profile),performance)
flags += -DPROFILE_PERFORMANCE
sfccpu := $(sfc)/alt/cpu
@ -29,36 +29,36 @@ else ifeq ($(profile),performance)
sfcppu := $(sfc)/alt/ppu-performance
endif
obj/sfc-interface.o : $(sfc)/interface/interface.cpp $(call rwildcard,$(sfc)/interface)
obj/sfc-system.o : $(sfc)/system/system.cpp $(call rwildcard,$(sfc)/system/)
obj/sfc-controller.o: $(sfc)/controller/controller.cpp $(call rwildcard,$(sfc)/controller/)
obj/sfc-cartridge.o : $(sfc)/cartridge/cartridge.cpp $(sfc)/cartridge/*
obj/sfc-cheat.o : $(sfc)/cheat/cheat.cpp $(sfc)/cheat/*
obj/sfc-memory.o : $(sfc)/memory/memory.cpp $(call rwildcard,$(sfc)/memory/)
obj/sfc-cpu.o : $(sfccpu)/cpu.cpp $(call rwildcard,$(sfccpu)/)
obj/sfc-smp.o : $(sfcsmp)/smp.cpp $(call rwildcard,$(sfcsmp)/)
obj/sfc-dsp.o : $(sfcdsp)/dsp.cpp $(call rwildcard,$(sfcdsp)/)
obj/sfc-ppu.o : $(sfcppu)/ppu.cpp $(call rwildcard,$(sfcppu)/)
obj/sfc-interface.o: $(sfc)/interface/interface.cpp $(call rwildcard,$(sfc)/interface)
obj/sfc-system.o: $(sfc)/system/system.cpp $(call rwildcard,$(sfc)/system/)
obj/sfc-controller.o: $(sfc)/controller/controller.cpp $(call rwildcard,$(sfc)/controller/)
obj/sfc-cartridge.o: $(sfc)/cartridge/cartridge.cpp $(sfc)/cartridge/*
obj/sfc-cheat.o: $(sfc)/cheat/cheat.cpp $(sfc)/cheat/*
obj/sfc-memory.o: $(sfc)/memory/memory.cpp $(call rwildcard,$(sfc)/memory/)
obj/sfc-cpu.o: $(sfccpu)/cpu.cpp $(call rwildcard,$(sfccpu)/)
obj/sfc-smp.o: $(sfcsmp)/smp.cpp $(call rwildcard,$(sfcsmp)/)
obj/sfc-dsp.o: $(sfcdsp)/dsp.cpp $(call rwildcard,$(sfcdsp)/)
obj/sfc-ppu.o: $(sfcppu)/ppu.cpp $(call rwildcard,$(sfcppu)/)
obj/sfc-icd2.o : $(sfc)/chip/icd2/icd2.cpp $(call rwildcard,$(sfc)/chip/icd2/)
obj/sfc-bsx.o : $(sfc)/chip/bsx/bsx.cpp $(call rwildcard,$(sfc)/chip/bsx/)
obj/sfc-icd2.o: $(sfc)/chip/icd2/icd2.cpp $(call rwildcard,$(sfc)/chip/icd2/)
obj/sfc-bsx.o: $(sfc)/chip/bsx/bsx.cpp $(call rwildcard,$(sfc)/chip/bsx/)
obj/sfc-sufamiturbo.o: $(sfc)/chip/sufamiturbo/sufamiturbo.cpp $(sfc)/chip/sufamiturbo/*
obj/sfc-nss.o : $(sfc)/chip/nss/nss.cpp $(call rwildcard,$(sfc)/chip/nss/)
obj/sfc-event.o : $(sfc)/chip/event/event.cpp $(call rwildcard,$(sfc)/chip/event/)
obj/sfc-nss.o: $(sfc)/chip/nss/nss.cpp $(call rwildcard,$(sfc)/chip/nss/)
obj/sfc-event.o: $(sfc)/chip/event/event.cpp $(call rwildcard,$(sfc)/chip/event/)
obj/sfc-sa1.o : $(sfc)/chip/sa1/sa1.cpp $(call rwildcard,$(sfc)/chip/sa1/)
obj/sfc-superfx.o: $(sfc)/chip/superfx/superfx.cpp $(call rwildcard,$(sfc)/chip/superfx/)
obj/sfc-sa1.o: $(sfc)/chip/sa1/sa1.cpp $(call rwildcard,$(sfc)/chip/sa1/)
obj/sfc-superfx.o: $(sfc)/chip/superfx/superfx.cpp $(call rwildcard,$(sfc)/chip/superfx/)
obj/sfc-armdsp.o : $(sfc)/chip/armdsp/armdsp.cpp $(call rwildcard,$(sfc)/chip/armdsp/)
obj/sfc-hitachidsp.o: $(sfc)/chip/hitachidsp/hitachidsp.cpp $(call rwildcard,$(sfc)/chip/hitachidsp/)
obj/sfc-necdsp.o : $(sfc)/chip/necdsp/necdsp.cpp $(call rwildcard,$(sfc)/chip/necdsp/)
obj/sfc-armdsp.o: $(sfc)/chip/armdsp/armdsp.cpp $(call rwildcard,$(sfc)/chip/armdsp/)
obj/sfc-hitachidsp.o: $(sfc)/chip/hitachidsp/hitachidsp.cpp $(call rwildcard,$(sfc)/chip/hitachidsp/)
obj/sfc-necdsp.o: $(sfc)/chip/necdsp/necdsp.cpp $(call rwildcard,$(sfc)/chip/necdsp/)
obj/sfc-epsonrtc.o: $(sfc)/chip/epsonrtc/epsonrtc.cpp $(call rwildcard,$(sfc)/chip/epsonrtc/)
obj/sfc-sharprtc.o: $(sfc)/chip/sharprtc/sharprtc.cpp $(call rwildcard,$(sfc)/chip/sharprtc/)
obj/sfc-epsonrtc.o: $(sfc)/chip/epsonrtc/epsonrtc.cpp $(call rwildcard,$(sfc)/chip/epsonrtc/)
obj/sfc-sharprtc.o: $(sfc)/chip/sharprtc/sharprtc.cpp $(call rwildcard,$(sfc)/chip/sharprtc/)
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-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/*
obj/sfc-hsu1.o: $(sfc)/chip/hsu1/hsu1.cpp $(sfc)/chip/hsu1/*
obj/sfc-msu1.o: $(sfc)/chip/msu1/msu1.cpp $(sfc)/chip/msu1/*

View File

@ -49,15 +49,13 @@ void Cartridge::load(const string &manifest) {
has_hsu1 = false;
has_msu1 = false;
information.title.cartridge = "";
information.title.gameBoy = "";
information.title.satellaview = "";
information.title.cartridge = "";
information.title.gameBoy = "";
information.title.satellaview = "";
information.title.sufamiTurboA = "";
information.title.sufamiTurboB = "";
this->manifest = manifest;
parse_markup(manifest);
//print(manifest, "\n\n");
parse_markup(information.markup = manifest);
//Super Game Boy
if(cartridge.has_gb_slot()) {
@ -77,6 +75,7 @@ void Cartridge::load(const string &manifest) {
sha256_chunk(&sha, sufamiturbo.slotA.rom.data(), sufamiturbo.slotA.rom.size());
sha256_chunk(&sha, sufamiturbo.slotB.rom.data(), sufamiturbo.slotB.rom.size());
sha256_final(&sha);
sha256_hash(&sha, hash);
string result;
for(auto &byte : hash) result.append(hex<2>(byte));
sha256 = result;
@ -122,6 +121,7 @@ void Cartridge::load(const string &manifest) {
void Cartridge::load_super_game_boy(const string &manifest) {
auto document = Markup::Document(manifest);
information.title.gameBoy = document["information/title"].text();
auto rom = document["cartridge/rom"];
auto ram = document["cartridge/ram"];
@ -135,6 +135,7 @@ void Cartridge::load_super_game_boy(const string &manifest) {
void Cartridge::load_satellaview(const string &manifest) {
auto document = Markup::Document(manifest);
information.title.satellaview = document["information/title"].text();
auto rom = document["cartridge/rom"];
if(rom["name"].exists()) {
@ -147,6 +148,7 @@ void Cartridge::load_satellaview(const string &manifest) {
void Cartridge::load_sufami_turbo_a(const string &manifest) {
auto document = Markup::Document(manifest);
information.title.sufamiTurboA = document["information/title"].text();
auto rom = document["cartridge/rom"];
auto ram = document["cartridge/ram"];
@ -171,6 +173,7 @@ void Cartridge::load_sufami_turbo_a(const string &manifest) {
void Cartridge::load_sufami_turbo_b(const string &manifest) {
auto document = Markup::Document(manifest);
information.title.sufamiTurboB = document["information/title"].text();
auto rom = document["cartridge/rom"];
auto ram = document["cartridge/ram"];

View File

@ -18,7 +18,6 @@ struct Cartridge : property<Cartridge> {
readonly<bool> loaded;
readonly<string> sha256;
readonly<string> manifest;
readonly<Region> region;
@ -62,6 +61,7 @@ struct Cartridge : property<Cartridge> {
vector<Memory> memory;
struct Information {
string markup;
struct Title {
string cartridge;
string gameBoy;
@ -70,6 +70,7 @@ struct Cartridge : property<Cartridge> {
string sufamiTurboB;
} title;
} information;
string title();
void load(const string &manifest);

View File

@ -2,11 +2,10 @@
void Cartridge::parse_markup(const char *markup) {
auto document = Markup::Document(markup);
auto cartridge = document["cartridge"];
auto information = document["information"];
region = cartridge["region"].data != "PAL" ? Region::NTSC : Region::PAL;
information.title.cartridge = document["information/title"].text();
this->information.title.cartridge = information["title"].text();
auto cartridge = document["cartridge"];
region = cartridge["region"].data != "PAL" ? Region::NTSC : Region::PAL;
mapping.reset();
parse_markup_cartridge(cartridge);
@ -138,11 +137,13 @@ void Cartridge::parse_markup_bsxslot(Markup::Node root) {
if(node["id"].data == "rom") {
if(bsxflash.memory.size() == 0) continue;
Mapping m(bsxflash.memory);
Mapping m(bsxflash);
parse_markup_map(m, node);
mapping.append(m);
}
}
bsxflash.readonly = (root["rom/type"].text() == "MaskROM");
}
void Cartridge::parse_markup_sufamiturbo(Markup::Node root) {
@ -253,8 +254,8 @@ void Cartridge::parse_markup_sa1(Markup::Node root) {
has_sa1 = true;
parse_markup_memory(sa1.rom, root["rom"], ID::SA1ROM, false);
parse_markup_memory(sa1.bwram, root["ram(id=bitmap)"], ID::SA1BWRAM, true);
parse_markup_memory(sa1.iram, root["ram(id=internal)"], ID::SA1IRAM, true);
parse_markup_memory(sa1.bwram, root["ram[0]"], ID::SA1BWRAM, true);
parse_markup_memory(sa1.iram, root["ram[1]"], ID::SA1IRAM, true);
for(auto &node : root) {
if(node.name != "map") continue;
@ -322,9 +323,9 @@ void Cartridge::parse_markup_armdsp(Markup::Node root) {
if(root.exists() == false) return;
has_armdsp = true;
string programROMName = root["rom(id=program)/name"].data;
string dataROMName = root["rom(id=data)/name"].data;
string dataRAMName = root["ram(id=data)/name"].data;
string programROMName = root["rom[0]/name"].data;
string dataROMName = root["rom[1]/name"].data;
string dataRAMName = root["ram/name"].data;
interface->loadRequest(ID::ArmDSPPROM, programROMName);
interface->loadRequest(ID::ArmDSPDROM, dataROMName);
@ -348,6 +349,9 @@ void Cartridge::parse_markup_hitachidsp(Markup::Node root, unsigned roms) {
if(root.exists() == false) return;
has_hitachidsp = true;
parse_markup_memory(hitachidsp.rom, root["rom[0]"], ID::HitachiDSPROM, false);
parse_markup_memory(hitachidsp.ram, root["ram[0]"], ID::HitachiDSPRAM, true);
for(auto &n : hitachidsp.dataROM) hitachidsp.dataROM[n] = 0x000000;
for(auto &n : hitachidsp.dataRAM) hitachidsp.dataRAM[n] = 0x00;
@ -355,17 +359,14 @@ void Cartridge::parse_markup_hitachidsp(Markup::Node root, unsigned roms) {
if(hitachidsp.Frequency == 0) hitachidsp.frequency = 20000000;
hitachidsp.Roms = roms;
string dataROMName = root["rom(id=data)/name"].data;
string dataRAMName = root["ram(id=data)/name"].data;
string dataROMName = root["rom[1]/name"].data;
string dataRAMName = root["ram[1]/name"].data;
interface->loadRequest(ID::HitachiDSPDROM, dataROMName);
if(dataRAMName.empty() == false) {
interface->loadRequest(ID::HitachiDSPDRAM, dataRAMName);
}
parse_markup_memory(hitachidsp.rom, root["rom(id=program)"], ID::HitachiDSPROM, false);
parse_markup_memory(hitachidsp.ram, root["ram(id=program)"], ID::HitachiDSPRAM, true);
for(auto &node : root) {
if(node.name != "map") continue;
@ -406,9 +407,9 @@ void Cartridge::parse_markup_necdsp(Markup::Node root) {
: root["model"].data == "uPD96050" ? NECDSP::Revision::uPD96050
: NECDSP::Revision::uPD7725;
string programROMName = root["rom(id=program)/name"].data;
string dataROMName = root["rom(id=data)/name"].data;
string dataRAMName = root["ram(id=data)/name"].data;
string programROMName = root["rom[0]/name"].data;
string dataROMName = root["rom[1]/name"].data;
string dataRAMName = root["ram/name"].data;
if(necdsp.revision == NECDSP::Revision::uPD7725) {
interface->loadRequest(ID::Nec7725DSPPROM, programROMName);
@ -488,8 +489,8 @@ void Cartridge::parse_markup_spc7110(Markup::Node root) {
if(root.exists() == false) return;
has_spc7110 = true;
parse_markup_memory(spc7110.prom, root["rom(id=program)"], ID::SPC7110PROM, false);
parse_markup_memory(spc7110.drom, root["rom(id=data)"], ID::SPC7110DROM, false);
parse_markup_memory(spc7110.prom, root["rom[0]"], ID::SPC7110PROM, false);
parse_markup_memory(spc7110.drom, root["rom[1]"], ID::SPC7110DROM, false);
parse_markup_memory(spc7110.ram, root["ram"], ID::SPC7110RAM, true);
for(auto &node : root) {

View File

@ -34,6 +34,8 @@ unsigned BSXFlash::size() const {
}
uint8 BSXFlash::read(unsigned addr) {
if(readonly) return memory.read(bus.mirror(addr, memory.size()));
if(addr == 0x0002) {
if(regs.flash_enable) return 0x80;
}
@ -45,15 +47,15 @@ uint8 BSXFlash::read(unsigned addr) {
if(regs.read_enable && addr >= 0xff00 && addr <= 0xff13) {
//read flash cartridge vendor information
switch(addr - 0xff00) {
case 0x00: return 0x4d;
case 0x01: return 0x00;
case 0x02: return 0x50;
case 0x03: return 0x00;
case 0x04: return 0x00;
case 0x05: return 0x00;
case 0x06: return 0x2a; //0x2a = 8mbit, 0x2b = 16mbit (not known to exist, though BIOS recognizes ID)
case 0x07: return 0x00;
default: return 0x00;
case 0x00: return 0x4d;
case 0x01: return 0x00;
case 0x02: return 0x50;
case 0x03: return 0x00;
case 0x04: return 0x00;
case 0x05: return 0x00;
case 0x06: return 0x2a; //0x2a = 8mbit, 0x2b = 16mbit (not known to exist, though BIOS recognizes ID)
case 0x07: return 0x00;
default: return 0x00;
}
}
@ -61,15 +63,7 @@ uint8 BSXFlash::read(unsigned addr) {
}
void BSXFlash::write(unsigned addr, uint8 data) {
//there exist both read-only and read-write BS-X flash cartridges ...
//unfortunately, the vendor info is not stored inside memory dumps
//of BS-X flashcarts, so it is impossible to determine whether a
//given flashcart is writeable.
//however, it has been observed that LoROM-mapped BS-X carts always
//use read-write flashcarts, and HiROM-mapped BS-X carts always use
//read-only flashcarts.
//below is an unfortunately necessary workaround to this problem.
//if(cartridge.mapper() == Cartridge::BSCHiROM) return;
if(readonly) return;
if((addr & 0xff0000) == 0) {
regs.write_old = regs.write_new;

View File

@ -1,5 +1,6 @@
struct BSXFlash : Memory {
MappedRAM memory;
bool readonly;
void init();
void load();

View File

@ -87,25 +87,24 @@ void MSU1::reset() {
void MSU1::data_open() {
if(datafile.open()) datafile.close();
XML::Document document(cartridge.manifest());
string name = document["cartridge"]["msu1"]["rom"]["name"].data;
auto document = Markup::Document(cartridge.information.markup);
string name = document["cartridge/msu1/rom/name"].data;
if(name.empty()) name = "msu1.rom";
if(datafile.open({interface->path(0), name}, file::mode::read)) {
if(datafile.open({interface->path(ID::SuperFamicom), name}, file::mode::read)) {
datafile.seek(mmio.data_offset);
}
}
void MSU1::audio_open() {
if(audiofile.open()) audiofile.close();
XML::Document document(cartridge.manifest());
auto document = Markup::Document(cartridge.information.markup);
string name = {"track-", mmio.audio_track, ".pcm"};
for(auto &track : document["cartridge"]["msu1"]) {
if(track.name != "track") continue;
for(auto &track : document.find("cartridge/msu1/track")) {
if(numeral(track["number"].data) != mmio.audio_track) continue;
name = track["name"].data;
break;
}
if(audiofile.open({interface->path(0), name}, file::mode::read)) {
if(audiofile.open({interface->path(ID::SuperFamicom), name}, file::mode::read)) {
audiofile.seek(mmio.audio_offset);
}
}

View File

@ -122,7 +122,7 @@ USART::USART(bool port) : Controller(port) {
txlength = 0;
txdata = 0;
string filename = {interface->path(0), "usart.so"};
string filename = {interface->path(ID::SuperFamicom), "usart.so"};
if(open_absolute(filename)) {
init = sym("usart_init");
main = sym("usart_main");

View File

@ -86,7 +86,6 @@ unsigned Interface::group(unsigned id) {
return 5;
}
print(id, "\n");
throw;
}
@ -376,10 +375,10 @@ Interface::Interface() {
information.capability.states = true;
information.capability.cheats = true;
media.append({ID::SuperFamicom, "Super Famicom", "sfc", true});
media.append({ID::SuperFamicom, "Super Game Boy", "gb", false});
media.append({ID::SuperFamicom, "BS-X Satellaview", "bs", false});
media.append({ID::SuperFamicom, "Sufami Turbo", "st", false});
media.append({ID::SuperFamicom, "Super Famicom", "sfc", true });
media.append({ID::SuperFamicom, "Super Famicom", "gb", false});
media.append({ID::SuperFamicom, "Super Famicom", "bs", false});
media.append({ID::SuperFamicom, "Super Famicom", "st", false});
{
Device device{0, ID::Port1 | ID::Port2, "Controller"};

View File

@ -1,8 +1,8 @@
namespace Info {
static const char Profile[] = "Compatibility";
static const char Profile[] = "Balanced";
}
#include <sfc/cpu/cpu.hpp>
#include <sfc/smp/smp.hpp>
#include <sfc/alt/dsp/dsp.hpp>
#include <sfc/alt/ppu-compatibility/ppu.hpp>
#include <sfc/alt/ppu-balanced/ppu.hpp>

View File

@ -57,8 +57,8 @@ namespace SuperFamicom {
#if defined(PROFILE_ACCURACY)
#include "profile-accuracy.hpp"
#elif defined(PROFILE_COMPATIBILITY)
#include "profile-compatibility.hpp"
#elif defined(PROFILE_BALANCED)
#include "profile-balanced.hpp"
#elif defined(PROFILE_PERFORMANCE)
#include "profile-performance.hpp"
#endif

View File

@ -94,13 +94,12 @@ void System::term() {
}
void System::load() {
string path = interface->path(ID::System), manifest;
manifest.readfile({path, "manifest.bml"});
string manifest = string::read({interface->path(ID::System), "manifest.bml"});
auto document = Markup::Document(manifest);
string iplrom = document["system"]["smp"]["rom"]["name"].data;
interface->loadRequest(ID::IPLROM, iplrom);
if(!file::exists({interface->path(ID::System), iplrom})) {
interface->notify("Error: required firmware ", iplrom, " not found.\n");
interface->loadRequest(ID::IPLROM, document["system/smp/rom/name"].data);
if(!file::exists({interface->path(ID::System), document["system/smp/rom/name"].data})) {
interface->notify("Error: required Super Famicom firmware ipl.rom not found.\n");
}
region = config.region;

View File

@ -28,9 +28,7 @@ Browser::Browser() {
};
homeButton.onActivate = [&] {
string pathname = {userpath(), "Emulation/"};
directory::create(pathname);
setPath(pathname);
setPath({userpath(), "Emulation/"});
};
upButton.onActivate = [&] {
@ -147,7 +145,7 @@ void Browser::setPath(const string &path, unsigned selection) {
fileList.reset();
filenameList.reset();
lstring contents = directory::contents(path);
lstring contents = directory::ifolders(path);
for(auto &filename : contents) {
string suffix = {".", this->extension, "/"};

View File

@ -59,7 +59,7 @@ Presentation::Presentation() : active(nullptr) {
setStatusVisible();
loadMenu.setText("Library");
loadImport.setText("Import Game ...");
loadImport.setText("Import Game ...");
settingsMenu.setText("Settings");
videoMenu.setText("Video");
centerVideo.setText("Center");
@ -86,11 +86,8 @@ Presentation::Presentation() : active(nullptr) {
synchronizeTime.setText("Synchronize Time");
append(loadMenu);
for(auto &item : loadListSystem) loadMenu.append(*item);
if(application->ananke.opened()) {
loadMenu.append(loadSeparator);
loadMenu.append(loadImport);
}
for(auto &item : loadListSystem) loadMenu.append(*item);
if(application->ananke.opened()) loadMenu.append(loadSeparator, loadImport);
for(auto &systemItem : emulatorList) append(systemItem->menu);
append(settingsMenu);
settingsMenu.append(videoMenu);
@ -153,7 +150,7 @@ void Presentation::bootstrap() {
iEmulator->interface = emulator;
for(auto &media : emulator->media) {
if(media.bootable == false) continue; //do not add sub-cartridge slot entries to menu
if(media.bootable == false) continue;
Item *item = new Item;
item->onActivate = [=, &media] {
utility->loadMedia(iEmulator->interface, media);

View File

@ -226,7 +226,7 @@ void InputManager::poll() {
using nall::Keyboard;
activeScancode = !activeScancode;
input.poll(scancode[activeScancode]);
if(input.poll(scancode[activeScancode]) == false) return;
for(unsigned n = 0; n < Scancode::Limit; n++) {
if(scancode[0][n] != scancode[1][n]) {

View File

@ -28,8 +28,8 @@ void Utility::loadMedia(string pathname) {
//determine type by comparing extension against all emulation cores
for(auto &emulator : application->emulator) {
for(auto &media : emulator->media) {
if(type != media.type) continue;
if(media.bootable == false) continue;
if(type != media.type) continue;
return utility->loadMedia(emulator, media, {pathname, "/"});
}
}
@ -56,7 +56,6 @@ void Utility::loadMedia(Emulator::Interface *emulator, Emulator::Interface::Medi
system().load(media.id, string::read({pathname, "manifest.bml"}));
system().power();
if(this->pathname.size() == 0) this->pathname.append(pathname);
presentation->setSystemName(media.name);
load();
}

View File

@ -1,17 +0,0 @@
shader language=GLSL
vertex~
void main(void) {
gl_Position = ftransform();
gl_TexCoord[0] = gl_MultiTexCoord0;
}
fragment~ filter=linear
uniform sampler2D rubyTexture;
void main(void) {
vec4 rgb = texture2D(rubyTexture, gl_TexCoord[0].xy);
vec4 intens = smoothstep(0.2,0.8,rgb) + normalize(vec4(rgb.xyz, 1.0));
if(fract(gl_FragCoord.y * 0.5) > 0.5) intens = rgb * 0.8;
gl_FragColor = intens;
}

View File

@ -1,61 +0,0 @@
shader language=GLSL
vertex~
uniform vec2 rubyTextureSize;
void main()
{
float x = 0.5 * (1.0 / rubyTextureSize.x);
float y = 0.5 * (1.0 / rubyTextureSize.y);
vec2 dg1 = vec2( x, y);
vec2 dg2 = vec2(-x, y);
vec2 dx = vec2(x, 0.0);
vec2 dy = vec2(0.0, y);
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1].xy = gl_TexCoord[0].xy - dg1;
gl_TexCoord[1].zw = gl_TexCoord[0].xy - dy;
gl_TexCoord[2].xy = gl_TexCoord[0].xy - dg2;
gl_TexCoord[2].zw = gl_TexCoord[0].xy + dx;
gl_TexCoord[3].xy = gl_TexCoord[0].xy + dg1;
gl_TexCoord[3].zw = gl_TexCoord[0].xy + dy;
gl_TexCoord[4].xy = gl_TexCoord[0].xy + dg2;
gl_TexCoord[4].zw = gl_TexCoord[0].xy - dx;
}
fragment~ filter=linear
vec4 compress(vec4 in_color, float threshold, float ratio)
{
vec4 diff = in_color - vec4(threshold);
diff = clamp(diff, 0.0, 100.0);
return in_color - (diff * (1.0 - 1.0/ratio));
}
uniform sampler2D rubyTexture;
uniform vec2 rubyTextureSize;
void main()
{
vec3 c00 = texture2D(rubyTexture, gl_TexCoord[1].xy).xyz;
vec3 c01 = texture2D(rubyTexture, gl_TexCoord[4].zw).xyz;
vec3 c02 = texture2D(rubyTexture, gl_TexCoord[4].xy).xyz;
vec3 c10 = texture2D(rubyTexture, gl_TexCoord[1].zw).xyz;
vec3 c11 = texture2D(rubyTexture, gl_TexCoord[0].xy).xyz;
vec3 c12 = texture2D(rubyTexture, gl_TexCoord[3].zw).xyz;
vec3 c20 = texture2D(rubyTexture, gl_TexCoord[2].xy).xyz;
vec3 c21 = texture2D(rubyTexture, gl_TexCoord[2].zw).xyz;
vec3 c22 = texture2D(rubyTexture, gl_TexCoord[3].xy).xyz;
vec2 tex = gl_TexCoord[0].xy;
vec2 texsize = rubyTextureSize;
vec3 first = mix(c00, c20, fract(tex.x * texsize.x + 0.5));
vec3 second = mix(c02, c22, fract(tex.x * texsize.x + 0.5));
vec3 mid_horiz = mix(c01, c21, fract(tex.x * texsize.x + 0.5));
vec3 mid_vert = mix(c10, c12, fract(tex.y * texsize.y + 0.5));
vec3 res = mix(first, second, fract(tex.y * texsize.y + 0.5));
vec4 final = vec4(0.26 * (res + mid_horiz + mid_vert) + 3.5 * abs(res - mix(mid_horiz, mid_vert, 0.5)), 1.0);
gl_FragColor = compress(final, 0.8, 5.0);
}

View File

@ -1,4 +0,0 @@
install:
mkdir -p ~/.config/bsnes/shaders
chmod 777 ~/.config/bsnes/shaders
cp *.shader ~/.config/bsnes/shaders