mirror of https://github.com/bsnes-emu/bsnes.git
Update to v091r05 release.
[No prior releases were posted to the WIP thread. -Ed.] byuu says: Super Famicom mapping system has been reworked as discussed with the mask= changes. offset becomes base, mode is gone. Also added support for comma-separated fields in the address fields, to reduce the number of map lines needed. <?xml version="1.0" encoding="UTF-8"?> <cartridge region="NTSC"> <superfx revision="2"> <rom name="program.rom" size="0x200000"/> <ram name="save.rwm" size="0x8000"/> <map id="io" address="00-3f,80-bf:3000-32ff"/> <map id="rom" address="00-3f:8000-ffff" mask="0x8000"/> <map id="rom" address="40-5f:0000-ffff"/> <map id="ram" address="00-3f,80-bf:6000-7fff" size="0x2000"/> <map id="ram" address="70-71:0000-ffff"/> </superfx> </cartridge> Or in BML: cartridge region=NTSC superfx revision=2 rom name=program.rom size=0x200000 ram name=save.rwm size=0x8000 map id=io address=00-3f,80-bf:3000-32ff map id=rom address=00-3f:8000-ffff mask=0x8000 map id=rom address=40-5f:0000-ffff map id=ram address=00-3f,80-bf:6000-7fff size=0x2000 map id=ram address=70-71:0000-ffff As a result of the changes, old mappings will no longer work. The above XML example will run Super Mario World 2: Yoshi's Island. Otherwise, you'll have to write your own. All that's left now is to work some sort of database mapping system in, so I can start dumping carts en masse. The NES changes that FitzRoy asked for are mostly in as well. Also, part of the reason I haven't released a WIP ... but fuck it, I'm not going to wait forever to post a new WIP. I've added a skeleton driver to emulate Campus Challenge '92 and Powerfest '94. There's no actual emulation, except for the stuff I can glean from looking at the pictures of the board. It has a DSP-1 (so SR/DR registers), four ROMs that map in and out, RAM, etc. I've also added preliminary mapping to upload high scores to a website, but obviously I need the ROMs first.
This commit is contained in:
parent
94b2538af5
commit
ef746bbda4
|
@ -46,7 +46,7 @@ else ifeq ($(platform),win)
|
|||
else
|
||||
link += -mwindows
|
||||
endif
|
||||
link += -mthreads -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32 -lole32
|
||||
link += -mthreads -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32 -lole32 -lws2_32
|
||||
link += -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc
|
||||
else
|
||||
unknown_platform: help;
|
||||
|
|
|
@ -3,19 +3,22 @@
|
|||
|
||||
namespace Emulator {
|
||||
static const char Name[] = "higan";
|
||||
static const char Version[] = "091";
|
||||
static const char Version[] = "091.05";
|
||||
static const char Author[] = "byuu";
|
||||
static const char License[] = "GPLv3";
|
||||
}
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/algorithm.hpp>
|
||||
#include <nall/base64.hpp>
|
||||
#include <nall/directory.hpp>
|
||||
#include <nall/dl.hpp>
|
||||
#include <nall/dsp.hpp>
|
||||
#include <nall/endian.hpp>
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/http.hpp>
|
||||
#include <nall/invoke.hpp>
|
||||
#include <nall/priority-queue.hpp>
|
||||
#include <nall/property.hpp>
|
||||
#include <nall/random.hpp>
|
||||
|
|
|
@ -55,7 +55,7 @@ struct Interface {
|
|||
virtual void videoRefresh(const uint32_t*, unsigned, unsigned, unsigned) {}
|
||||
virtual void audioSample(int16_t, int16_t) {}
|
||||
virtual int16_t inputPoll(unsigned, unsigned, unsigned) { return 0; }
|
||||
virtual unsigned dipSettings(const XML::Node&) { return 0; }
|
||||
virtual unsigned dipSettings(const Markup::Node&) { return 0; }
|
||||
virtual string path(unsigned) { return ""; }
|
||||
virtual void notify(const string &text) { print(text, "\n"); }
|
||||
} *bind;
|
||||
|
@ -68,7 +68,7 @@ struct Interface {
|
|||
void videoRefresh(const uint32_t *data, unsigned pitch, unsigned width, unsigned height) { return bind->videoRefresh(data, pitch, width, height); }
|
||||
void audioSample(int16_t lsample, int16_t rsample) { return bind->audioSample(lsample, rsample); }
|
||||
int16_t inputPoll(unsigned port, unsigned device, unsigned input) { return bind->inputPoll(port, device, input); }
|
||||
unsigned dipSettings(const XML::Node &node) { return bind->dipSettings(node); }
|
||||
unsigned dipSettings(const Markup::Node &node) { return bind->dipSettings(node); }
|
||||
string path(unsigned group) { return bind->path(group); }
|
||||
template<typename... Args> void notify(Args&... args) { return bind->notify({std::forward<Args>(args)...}); }
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ void serialize(serializer &s) {
|
|||
s.integer(irq_latch);
|
||||
}
|
||||
|
||||
BandaiFCG(XML::Document &document) : Board(document) {
|
||||
BandaiFCG(Markup::Node &document) : Board(document) {
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -82,7 +82,7 @@ void Board::serialize(serializer &s) {
|
|||
if(chrram.size) s.array(chrram.data, chrram.size);
|
||||
}
|
||||
|
||||
Board::Board(XML::Document &document) {
|
||||
Board::Board(Markup::Node &document) {
|
||||
cartridge.board = this;
|
||||
auto &cartridge = document["cartridge"];
|
||||
|
||||
|
@ -120,7 +120,7 @@ Board::~Board() {
|
|||
}
|
||||
|
||||
Board* Board::load(const string &manifest) {
|
||||
XML::Document document(manifest);
|
||||
auto document = Markup::Document(manifest);
|
||||
string type = document["cartridge"]["board"]["type"].data;
|
||||
|
||||
if(type == "BANDAI-FCG" ) return new BandaiFCG(document);
|
||||
|
@ -154,16 +154,52 @@ Board* Board::load(const string &manifest) {
|
|||
|
||||
if(type == "NES-HKROM" ) return new NES_HKROM(document);
|
||||
|
||||
if(type == "NES-NROM" ) return new NES_NROM(document);
|
||||
if(type == "NES-NROM-128") return new NES_NROM(document);
|
||||
if(type == "NES-NROM-256") return new NES_NROM(document);
|
||||
|
||||
if(type == "NES-PEEOROM" ) return new NES_PxROM(document);
|
||||
if(type == "NES-PNROM" ) return new NES_PxROM(document);
|
||||
|
||||
if(type == "NES-SAROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SBROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SCROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SC1ROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SEROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SFROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SFEXPROM") return new NES_SxROM(document);
|
||||
if(type == "NES-SGROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SHROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SH1ROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SIROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SJROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SKROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SLROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SL1ROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SL2ROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SL3ROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SLRROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SMROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SNROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SOROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SUROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SXROM" ) return new NES_SxROM(document);
|
||||
|
||||
if(type == "NES-TBROM" ) return new NES_TxROM(document);
|
||||
if(type == "NES-TEROM" ) return new NES_TxROM(document);
|
||||
if(type == "NES-TFROM" ) return new NES_TxROM(document);
|
||||
if(type == "NES-TGROM" ) return new NES_TxROM(document);
|
||||
if(type == "NES-TKROM" ) return new NES_TxROM(document);
|
||||
if(type == "NES-TKSROM" ) return new NES_TxROM(document);
|
||||
if(type == "NES-TLROM" ) return new NES_TxROM(document);
|
||||
if(type == "NES-TL1ROM" ) return new NES_TxROM(document);
|
||||
if(type == "NES-TL2ROM" ) return new NES_TxROM(document);
|
||||
if(type == "NES-TLSROM" ) return new NES_TxROM(document);
|
||||
if(type == "NES-TNROM" ) return new NES_TxROM(document);
|
||||
if(type == "NES-TQROM" ) return new NES_TxROM(document);
|
||||
if(type == "NES-TR1ROM" ) return new NES_TxROM(document);
|
||||
if(type == "NES-TSROM" ) return new NES_TxROM(document);
|
||||
if(type == "NES-TVROM" ) return new NES_TxROM(document);
|
||||
|
||||
if(type == "NES-UNROM" ) return new NES_UxROM(document);
|
||||
if(type == "NES-UOROM" ) return new NES_UxROM(document);
|
||||
|
|
|
@ -29,7 +29,7 @@ struct Board {
|
|||
virtual void reset();
|
||||
|
||||
virtual void serialize(serializer&);
|
||||
Board(XML::Document &document);
|
||||
Board(Markup::Node &document);
|
||||
virtual ~Board();
|
||||
|
||||
static Board* load(const string &manifest);
|
||||
|
|
|
@ -34,7 +34,7 @@ void serialize(serializer &s) {
|
|||
vrc1.serialize(s);
|
||||
}
|
||||
|
||||
KonamiVRC1(XML::Document &document) : Board(document), vrc1(*this) {
|
||||
KonamiVRC1(Markup::Node &document) : Board(document), vrc1(*this) {
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -49,7 +49,7 @@ void serialize(serializer &s) {
|
|||
vrc2.serialize(s);
|
||||
}
|
||||
|
||||
KonamiVRC2(XML::Document &document) : Board(document), vrc2(*this) {
|
||||
KonamiVRC2(Markup::Node &document) : Board(document), vrc2(*this) {
|
||||
settings.pinout.a0 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a0"].data);
|
||||
settings.pinout.a1 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a1"].data);
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ void serialize(serializer &s) {
|
|||
vrc3.serialize(s);
|
||||
}
|
||||
|
||||
KonamiVRC3(XML::Document &document) : Board(document), vrc3(*this) {
|
||||
KonamiVRC3(Markup::Node &document) : Board(document), vrc3(*this) {
|
||||
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ void serialize(serializer &s) {
|
|||
vrc4.serialize(s);
|
||||
}
|
||||
|
||||
KonamiVRC4(XML::Document &document) : Board(document), vrc4(*this) {
|
||||
KonamiVRC4(Markup::Node &document) : Board(document), vrc4(*this) {
|
||||
settings.pinout.a0 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a0"].data);
|
||||
settings.pinout.a1 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a1"].data);
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ void main() { vrc6.main(); }
|
|||
void power() { vrc6.power(); }
|
||||
void reset() { vrc6.reset(); }
|
||||
|
||||
KonamiVRC6(XML::Document &document) : Board(document), vrc6(*this) {
|
||||
KonamiVRC6(Markup::Node &document) : Board(document), vrc6(*this) {
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -41,7 +41,7 @@ void serialize(serializer &s) {
|
|||
vrc7.serialize(s);
|
||||
}
|
||||
|
||||
KonamiVRC7(XML::Document &document) : Board(document), vrc7(*this) {
|
||||
KonamiVRC7(Markup::Node &document) : Board(document), vrc7(*this) {
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -45,7 +45,7 @@ void serialize(serializer &s) {
|
|||
s.integer(mirror_select);
|
||||
}
|
||||
|
||||
NES_AxROM(XML::Document &document) : Board(document) {
|
||||
NES_AxROM(Markup::Node &document) : Board(document) {
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -45,7 +45,7 @@ void serialize(serializer &s) {
|
|||
s.integer(prg_bank);
|
||||
}
|
||||
|
||||
NES_BNROM(XML::Document &document) : Board(document) {
|
||||
NES_BNROM(Markup::Node &document) : Board(document) {
|
||||
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ void serialize(serializer &s) {
|
|||
s.integer(chr_bank);
|
||||
}
|
||||
|
||||
NES_CNROM(XML::Document &document) : Board(document) {
|
||||
NES_CNROM(Markup::Node &document) : Board(document) {
|
||||
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ void serialize(serializer &s) {
|
|||
mmc5.serialize(s);
|
||||
}
|
||||
|
||||
NES_ExROM(XML::Document &document) : Board(document), mmc5(*this) {
|
||||
NES_ExROM(Markup::Node &document) : Board(document), mmc5(*this) {
|
||||
revision = Revision::ELROM;
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ void serialize(serializer &s) {
|
|||
s.array(latch);
|
||||
}
|
||||
|
||||
NES_FxROM(XML::Document &document) : Board(document) {
|
||||
NES_FxROM(Markup::Node &document) : Board(document) {
|
||||
revision = Revision::FKROM;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ void serialize(serializer &s) {
|
|||
s.integer(chr_bank);
|
||||
}
|
||||
|
||||
NES_GxROM(XML::Document &document) : Board(document) {
|
||||
NES_GxROM(Markup::Node &document) : Board(document) {
|
||||
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ void serialize(serializer &s) {
|
|||
mmc6.serialize(s);
|
||||
}
|
||||
|
||||
NES_HKROM(XML::Document &document) : Board(document), mmc6(*this) {
|
||||
NES_HKROM(Markup::Node &document) : Board(document), mmc6(*this) {
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -36,7 +36,7 @@ void serialize(serializer &s) {
|
|||
Board::serialize(s);
|
||||
}
|
||||
|
||||
NES_NROM(XML::Document &document) : Board(document) {
|
||||
NES_NROM(Markup::Node &document) : Board(document) {
|
||||
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ void serialize(serializer &s) {
|
|||
s.array(latch);
|
||||
}
|
||||
|
||||
NES_PxROM(XML::Document &document) : Board(document) {
|
||||
NES_PxROM(Markup::Node &document) : Board(document) {
|
||||
revision = Revision::PNROM;
|
||||
}
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ void serialize(serializer &s) {
|
|||
mmc1.serialize(s);
|
||||
}
|
||||
|
||||
NES_SxROM(XML::Document &document) : Board(document), mmc1(*this) {
|
||||
NES_SxROM(Markup::Node &document) : Board(document), mmc1(*this) {
|
||||
revision = Revision::SXROM;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ void serialize(serializer &s) {
|
|||
mmc3.serialize(s);
|
||||
}
|
||||
|
||||
NES_TxROM(XML::Document &document) : Board(document), mmc3(*this) {
|
||||
NES_TxROM(Markup::Node &document) : Board(document), mmc3(*this) {
|
||||
revision = Revision::TLROM;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ void serialize(serializer &s) {
|
|||
s.integer(prg_bank);
|
||||
}
|
||||
|
||||
NES_UxROM(XML::Document &document) : Board(document) {
|
||||
NES_UxROM(Markup::Node &document) : Board(document) {
|
||||
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -220,7 +220,7 @@ void serialize(serializer &s) {
|
|||
pulse[2].serialize(s);
|
||||
}
|
||||
|
||||
Sunsoft5B(XML::Document &document) : Board(document) {
|
||||
Sunsoft5B(Markup::Node &document) : Board(document) {
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -25,7 +25,7 @@ void Cartridge::load(System::Revision revision, const string &manifest) {
|
|||
information.romsize = 0;
|
||||
information.ramsize = 0;
|
||||
|
||||
XML::Document document(manifest);
|
||||
auto document = Markup::Document(manifest);
|
||||
|
||||
auto &mapperid = document["cartridge"]["board"]["type"].data;
|
||||
if(mapperid == "none" ) information.mapper = Mapper::MBC0;
|
||||
|
|
|
@ -9,7 +9,7 @@ Cartridge cartridge;
|
|||
|
||||
void Cartridge::load(const string &manifest) {
|
||||
information.markup = manifest;
|
||||
XML::Document document(manifest);
|
||||
auto document = Markup::Document(manifest);
|
||||
|
||||
unsigned rom_size = 0;
|
||||
if(document["cartridge"]["rom"].exists()) {
|
||||
|
|
|
@ -1,33 +1,38 @@
|
|||
#ifndef NALL_BASE64_HPP
|
||||
#define NALL_BASE64_HPP
|
||||
|
||||
#include <string.h>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
|
||||
namespace nall {
|
||||
struct base64 {
|
||||
static bool encode(char *&output, const uint8_t* input, unsigned inlength) {
|
||||
output = new char[inlength * 8 / 6 + 6]();
|
||||
output = new char[inlength * 8 / 6 + 8]();
|
||||
|
||||
unsigned i = 0, o = 0;
|
||||
while(i < inlength) {
|
||||
switch(i % 3) {
|
||||
case 0: {
|
||||
output[o++] = enc(input[i] >> 2);
|
||||
output[o] = enc((input[i] & 3) << 4);
|
||||
} break;
|
||||
|
||||
case 1: {
|
||||
uint8_t prev = dec(output[o]);
|
||||
output[o++] = enc(prev + (input[i] >> 4));
|
||||
output[o] = enc((input[i] & 15) << 2);
|
||||
} break;
|
||||
case 0: {
|
||||
output[o++] = enc(input[i] >> 2);
|
||||
output[o] = enc((input[i] & 3) << 4);
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: {
|
||||
uint8_t prev = dec(output[o]);
|
||||
output[o++] = enc(prev + (input[i] >> 4));
|
||||
output[o] = enc((input[i] & 15) << 2);
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
uint8_t prev = dec(output[o]);
|
||||
output[o++] = enc(prev + (input[i] >> 6));
|
||||
output[o++] = enc(input[i] & 63);
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
uint8_t prev = dec(output[o]);
|
||||
output[o++] = enc(prev + (input[i] >> 6));
|
||||
output[o++] = enc(input[i] & 63);
|
||||
} break;
|
||||
}
|
||||
|
||||
i++;
|
||||
|
@ -36,32 +41,46 @@ namespace nall {
|
|||
return true;
|
||||
}
|
||||
|
||||
static string encode(const string &data) {
|
||||
char *buffer = nullptr;
|
||||
encode(buffer, (const uint8_t*)(const char*)data, data.length());
|
||||
string result = buffer;
|
||||
delete[] buffer;
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool decode(uint8_t *&output, unsigned &outlength, const char *input) {
|
||||
unsigned inlength = strlen(input), infix = 0;
|
||||
output = new uint8_t[inlength]();
|
||||
output = new uint8_t[inlength + 1]();
|
||||
|
||||
unsigned i = 0, o = 0;
|
||||
while(i < inlength) {
|
||||
uint8_t x = dec(input[i]);
|
||||
|
||||
switch(i++ & 3) {
|
||||
case 0: {
|
||||
output[o] = x << 2;
|
||||
} break;
|
||||
|
||||
case 1: {
|
||||
output[o++] |= x >> 4;
|
||||
output[o] = (x & 15) << 4;
|
||||
} break;
|
||||
case 0: {
|
||||
output[o] = x << 2;
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
output[o++] |= x >> 2;
|
||||
output[o] = (x & 3) << 6;
|
||||
} break;
|
||||
case 1: {
|
||||
output[o++] |= x >> 4;
|
||||
output[o] = (x & 15) << 4;
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
output[o++] |= x >> 2;
|
||||
output[o] = (x & 3) << 6;
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: {
|
||||
output[o++] |= x;
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: {
|
||||
output[o++] |= x;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,9 +88,18 @@ namespace nall {
|
|||
return true;
|
||||
}
|
||||
|
||||
static string decode(const string &data) {
|
||||
uint8_t *buffer = nullptr;
|
||||
unsigned size = 0;
|
||||
decode(buffer, size, (const char*)data);
|
||||
string result = (const char*)buffer;
|
||||
delete[] buffer;
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
static char enc(uint8_t n) {
|
||||
//base64 for URL encodings
|
||||
//base64 for URL encodings (URL = -_, MIME = +/)
|
||||
static char lookup_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
return lookup_table[n & 63];
|
||||
}
|
||||
|
|
|
@ -15,6 +15,11 @@ struct bpsmulti {
|
|||
MirrorFile = 3,
|
||||
};
|
||||
|
||||
enum : unsigned {
|
||||
OriginSource = 0,
|
||||
OriginTarget = 1,
|
||||
};
|
||||
|
||||
bool create(const string &patchName, const string &sourcePath, const string &targetPath, bool delta = false, const string &metadata = "") {
|
||||
if(fp.open()) fp.close();
|
||||
fp.open(patchName, file::mode::write);
|
||||
|
@ -30,9 +35,10 @@ struct bpsmulti {
|
|||
|
||||
for(auto &targetName : targetList) {
|
||||
if(targetName.endswith("/")) {
|
||||
targetName.rtrim<1>("/");
|
||||
writeNumber(CreatePath | ((targetName.length() - 1) << 2));
|
||||
writeString(targetName);
|
||||
} else if(auto position = sourceList.find(targetName)) { //note: sourceName == targetName
|
||||
} else if(auto position = sourceList.find(targetName)) { //if sourceName == targetName
|
||||
file sp, dp;
|
||||
sp.open({sourcePath, targetName}, file::mode::read);
|
||||
dp.open({targetPath, targetName}, file::mode::read);
|
||||
|
@ -46,30 +52,32 @@ struct bpsmulti {
|
|||
cksum = crc32_adjust(cksum, byte);
|
||||
}
|
||||
|
||||
writeNumber((identical ? MirrorFile : ModifyFile) | ((targetName.length() - 1) << 2));
|
||||
writeString(targetName);
|
||||
writeNumber(targetName.length() - 1);
|
||||
writeString(targetName);
|
||||
if(identical) {
|
||||
writeNumber(MirrorFile | ((targetName.length() - 1) << 2));
|
||||
writeString(targetName);
|
||||
writeNumber(OriginSource);
|
||||
writeChecksum(~cksum);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(delta == false) {
|
||||
bpslinear patch;
|
||||
patch.source({sourcePath, targetName});
|
||||
patch.target({targetPath, targetName});
|
||||
patch.create({temppath(), "temp.bps"});
|
||||
} else {
|
||||
bpsdelta patch;
|
||||
patch.source({sourcePath, targetName});
|
||||
patch.target({targetPath, targetName});
|
||||
patch.create({temppath(), "temp.bps"});
|
||||
}
|
||||
writeNumber(ModifyFile | ((targetName.length() - 1) << 2));
|
||||
writeString(targetName);
|
||||
writeNumber(OriginSource);
|
||||
|
||||
auto buffer = file::read({temppath(), "temp.bps"});
|
||||
writeNumber(buffer.size());
|
||||
for(auto &byte : buffer) write(byte);
|
||||
if(delta == false) {
|
||||
bpslinear patch;
|
||||
patch.source({sourcePath, targetName});
|
||||
patch.target({targetPath, targetName});
|
||||
patch.create({temppath(), "temp.bps"});
|
||||
} else {
|
||||
bpsdelta patch;
|
||||
patch.source({sourcePath, targetName});
|
||||
patch.target({targetPath, targetName});
|
||||
patch.create({temppath(), "temp.bps"});
|
||||
}
|
||||
|
||||
auto buffer = file::read({temppath(), "temp.bps"});
|
||||
writeNumber(buffer.size());
|
||||
for(auto &byte : buffer) write(byte);
|
||||
}
|
||||
} else {
|
||||
writeNumber(CreateFile | ((targetName.length() - 1) << 2));
|
||||
writeString(targetName);
|
||||
|
@ -105,7 +113,7 @@ struct bpsmulti {
|
|||
string targetName = readString(targetLength);
|
||||
|
||||
if(action == CreatePath) {
|
||||
directory::create({targetPath, targetName});
|
||||
directory::create({targetPath, targetName, "/"});
|
||||
} else if(action == CreateFile) {
|
||||
file fp;
|
||||
fp.open({targetPath, targetName}, file::mode::write);
|
||||
|
@ -113,21 +121,23 @@ struct bpsmulti {
|
|||
while(fileSize--) fp.write(read());
|
||||
uint32_t cksum = readChecksum();
|
||||
} else if(action == ModifyFile) {
|
||||
auto sourceLength = readNumber() + 1;
|
||||
string sourceName = readString(sourceLength);
|
||||
auto encoding = readNumber();
|
||||
string originPath = encoding & 1 ? targetPath : sourcePath;
|
||||
string sourceName = (encoding >> 1) == 0 ? targetName : readString(encoding >> 1);
|
||||
auto patchSize = readNumber();
|
||||
vector<uint8_t> buffer;
|
||||
buffer.resize(patchSize);
|
||||
for(unsigned n = 0; n < patchSize; n++) buffer[n] = read();
|
||||
bpspatch patch;
|
||||
patch.modify(buffer.data(), buffer.size());
|
||||
patch.source({sourcePath, sourceName});
|
||||
patch.source({originPath, sourceName});
|
||||
patch.target({targetPath, targetName});
|
||||
if(patch.apply() != bpspatch::result::success) return false;
|
||||
} else if(action == MirrorFile) {
|
||||
auto sourceLength = readNumber() + 1;
|
||||
string sourceName = readString(sourceLength);
|
||||
file::copy({sourcePath, sourceName}, {targetPath, targetName});
|
||||
auto encoding = readNumber();
|
||||
string originPath = encoding & 1 ? targetPath : sourcePath;
|
||||
string sourceName = (encoding >> 1) == 0 ? targetName : readString(encoding >> 1);
|
||||
file::copy({originPath, sourceName}, {targetPath, targetName});
|
||||
uint32_t cksum = readChecksum();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,6 +74,14 @@ namespace nall {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool write(const string &filename, const vector<uint8_t> &buffer) {
|
||||
file fp;
|
||||
if(fp.open(filename, mode::write) == false) return false;
|
||||
fp.write(buffer.data(), buffer.size());
|
||||
fp.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool write(const string &filename, const uint8_t *data, unsigned size) {
|
||||
file fp;
|
||||
if(fp.open(filename, mode::write) == false) return false;
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
|
||||
#define NALL_STRING_INTERNAL_HPP
|
||||
#include <nall/string/base.hpp>
|
||||
#include <nall/string/bml.hpp>
|
||||
#include <nall/string/bsv.hpp>
|
||||
#include <nall/string/cast.hpp>
|
||||
#include <nall/string/compare.hpp>
|
||||
|
@ -44,7 +43,10 @@
|
|||
#include <nall/string/variadic.hpp>
|
||||
#include <nall/string/wildcard.hpp>
|
||||
#include <nall/string/wrapper.hpp>
|
||||
#include <nall/string/xml.hpp>
|
||||
#include <nall/string/markup/node.hpp>
|
||||
#include <nall/string/markup/bml.hpp>
|
||||
#include <nall/string/markup/xml.hpp>
|
||||
#include <nall/string/markup/document.hpp>
|
||||
#undef NALL_STRING_INTERNAL_HPP
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,151 +0,0 @@
|
|||
#ifdef NALL_STRING_INTERNAL_HPP
|
||||
|
||||
//BML v1.0 parser
|
||||
//revision 0.05
|
||||
|
||||
namespace nall {
|
||||
namespace BML {
|
||||
|
||||
inline static string indent(const char *s, unsigned depth) {
|
||||
vector<char> output;
|
||||
do {
|
||||
for(unsigned n = 0; n < depth; n++) output.append('\t');
|
||||
do output.append(*s); while(*s && *s++ != '\n');
|
||||
} while(*s);
|
||||
return output.data();
|
||||
}
|
||||
|
||||
struct Node {
|
||||
cstring name;
|
||||
cstring value;
|
||||
|
||||
private:
|
||||
vector<Node> children;
|
||||
|
||||
inline bool valid(char p) const { //A-Za-z0-9-.
|
||||
return p - 'A' < 26u | p - 'a' < 26u | p - '0' < 10u | p - '-' < 2u;
|
||||
}
|
||||
|
||||
inline unsigned parseDepth(char *&p) {
|
||||
while(*p == '\n' || *p == '#') {
|
||||
while(*p != '\n') *p++ = 0;
|
||||
*p++ = 0; //'\n'
|
||||
}
|
||||
unsigned depth = 0;
|
||||
while(p[depth] == '\t') depth++;
|
||||
return depth;
|
||||
}
|
||||
|
||||
inline void parseName(char *&p) {
|
||||
if(valid(*p) == false) throw "Missing node name";
|
||||
name = p;
|
||||
while(valid(*p)) p++;
|
||||
}
|
||||
|
||||
inline void parseValue(char *&p) {
|
||||
char terminal = *p == ':' ? '\n' : ' '; //':' or '='
|
||||
*p++ = 0;
|
||||
value = p;
|
||||
while(*p && *p != terminal && *p != '\n') p++;
|
||||
}
|
||||
|
||||
inline void parseBlock(char *&p, unsigned depth) {
|
||||
value = p;
|
||||
char *w = p;
|
||||
while(parseDepth(p) > depth) {
|
||||
p += depth + 1;
|
||||
while(*p && *p != '\n') *w++ = *p++;
|
||||
if(*p && *p != '\n') throw "Multi-line value missing line feed";
|
||||
*w++ = *p;
|
||||
}
|
||||
*(w - 1) = 0; //'\n'
|
||||
}
|
||||
|
||||
inline void parseLine(char *&p) {
|
||||
unsigned depth = parseDepth(p);
|
||||
while(*p == '\t') p++;
|
||||
|
||||
parseName(p);
|
||||
bool multiLine = *p == '~';
|
||||
if(multiLine) *p++ = 0;
|
||||
else if(*p == ':' || *p == '=') parseValue(p);
|
||||
if(*p && *p != ' ' && *p != '\n') throw "Invalid character encountered";
|
||||
|
||||
while(*p == ' ') {
|
||||
*p++ = 0;
|
||||
Node node;
|
||||
node.parseName(p);
|
||||
if(*p == ':' || *p == '=') node.parseValue(p);
|
||||
if(*p && *p != ' ' && *p != '\n') throw "Invalid character after node";
|
||||
if(*p == '\n') *p++ = 0;
|
||||
children.append(node);
|
||||
}
|
||||
|
||||
if(multiLine) return parseBlock(p, depth);
|
||||
|
||||
while(parseDepth(p) > depth) {
|
||||
Node node;
|
||||
node.parseLine(p);
|
||||
children.append(node);
|
||||
}
|
||||
}
|
||||
|
||||
inline void parse(char *&p) {
|
||||
while(*p) {
|
||||
Node node;
|
||||
node.parseLine(p);
|
||||
children.append(node);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
inline Node& operator[](const char *name) {
|
||||
for(auto &node : children) {
|
||||
if(node.name == name) return node;
|
||||
}
|
||||
static Node node;
|
||||
node.name = nullptr;
|
||||
return node;
|
||||
}
|
||||
|
||||
inline bool exists() const { return name; }
|
||||
unsigned size() const { return children.size(); }
|
||||
Node* begin() { return children.begin(); }
|
||||
Node* end() { return children.end(); }
|
||||
const Node* begin() const { return children.begin(); }
|
||||
const Node* end() const { return children.end(); }
|
||||
inline Node() : name(""), value("") {}
|
||||
friend class Document;
|
||||
};
|
||||
|
||||
struct Document : Node {
|
||||
cstring error;
|
||||
|
||||
inline bool load(const char *document) {
|
||||
if(document == nullptr) return false;
|
||||
this->document = strdup(document);
|
||||
char *p = this->document;
|
||||
try {
|
||||
this->error = nullptr;
|
||||
parse(p);
|
||||
} catch(const char *error) {
|
||||
this->error = error;
|
||||
free(this->document);
|
||||
this->document = nullptr;
|
||||
children.reset();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline Document(const char *document = "") : document(nullptr), error(nullptr) { if(*document) load(document); }
|
||||
inline ~Document() { if(document) free(document); }
|
||||
|
||||
private:
|
||||
char *document;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,147 @@
|
|||
#ifdef NALL_STRING_INTERNAL_HPP
|
||||
|
||||
//BML v1.0 parser
|
||||
//revision 0.02
|
||||
|
||||
namespace nall {
|
||||
namespace BML {
|
||||
|
||||
struct Node : Markup::Node {
|
||||
protected:
|
||||
//test to verify if a valid character for a node name
|
||||
bool valid(char p) const { //A-Z, a-z, 0-9, -./
|
||||
return p - 'A' < 26u || p - 'a' < 26u || p - '0' < 10u || p - '-' < 3u;
|
||||
}
|
||||
|
||||
//determine indentation level, without incrementing pointer
|
||||
unsigned readDepth(const char *p) {
|
||||
unsigned depth = 0;
|
||||
while(p[depth] == '\t' || p[depth] == ' ') depth++;
|
||||
return depth;
|
||||
}
|
||||
|
||||
//determine indentation level
|
||||
unsigned parseDepth(const char *&p) {
|
||||
unsigned depth = readDepth(p);
|
||||
p += depth;
|
||||
return depth;
|
||||
}
|
||||
|
||||
//read name
|
||||
void parseName(const char *&p) {
|
||||
unsigned length = 0;
|
||||
while(valid(p[length])) length++;
|
||||
if(length == 0) throw "Invalid node name";
|
||||
name = substr(p, 0, length);
|
||||
p += length;
|
||||
}
|
||||
|
||||
void parseData(const char *&p) {
|
||||
if(*p == '=' && *(p + 1) == '\"') {
|
||||
unsigned length = 2;
|
||||
while(p[length] && p[length] != '\n' && p[length] != '\"') length++;
|
||||
if(p[length] != '\"') throw "Unescaped value";
|
||||
data = substr(p, 2, length - 2);
|
||||
p += length + 1;
|
||||
} else if(*p == '=') {
|
||||
unsigned length = 1;
|
||||
while(p[length] && p[length] != '\n' && p[length] != '\"' && p[length] != ' ') length++;
|
||||
if(p[length] == '\"') throw "Illegal character in value";
|
||||
data = substr(p, 1, length - 1);
|
||||
p += length;
|
||||
} else if(*p == ':') {
|
||||
unsigned length = 1;
|
||||
while(p[length] && p[length] != '\n') length++;
|
||||
data = {substr(p, 1, length - 1), "\n"};
|
||||
p += length;
|
||||
}
|
||||
}
|
||||
|
||||
//read all attributes for a node
|
||||
void parseAttributes(const char *&p) {
|
||||
while(*p && *p != '\n') {
|
||||
if(*p != ' ') throw "Invalid node name";
|
||||
while(*p == ' ') p++; //skip excess spaces
|
||||
|
||||
Node node;
|
||||
node.attribute = true;
|
||||
unsigned length = 0;
|
||||
while(valid(p[length])) length++;
|
||||
if(length == 0) throw "Invalid attribute name";
|
||||
node.name = substr(p, 0, length);
|
||||
node.parseData(p += length);
|
||||
children.append(node);
|
||||
}
|
||||
}
|
||||
|
||||
//read a node and all of its children nodes
|
||||
void parseNode(const char *&p) {
|
||||
level = parseDepth(p);
|
||||
parseName(p);
|
||||
parseData(p);
|
||||
parseAttributes(p);
|
||||
if(*p++ != '\n') throw "Missing line feed";
|
||||
|
||||
while(*p) {
|
||||
if(*p == '\n') { p++; continue; }
|
||||
|
||||
unsigned depth = readDepth(p);
|
||||
if(depth <= level) break;
|
||||
|
||||
if(p[depth] == ':') {
|
||||
p += depth;
|
||||
unsigned length = 0;
|
||||
while(p[length] && p[length] != '\n') length++;
|
||||
data.append(substr(p, 1, length - 1), "\n");
|
||||
p += length;
|
||||
continue;
|
||||
}
|
||||
|
||||
Node node;
|
||||
node.parseNode(p);
|
||||
children.append(node);
|
||||
}
|
||||
|
||||
data.rtrim<1>("\n");
|
||||
}
|
||||
|
||||
//read top-level nodes
|
||||
void parse(const char *p) {
|
||||
while(*p) {
|
||||
Node node;
|
||||
node.parseNode(p);
|
||||
if(node.level > 0) throw "Root nodes cannot be indented";
|
||||
children.append(node);
|
||||
}
|
||||
}
|
||||
|
||||
friend class Document;
|
||||
};
|
||||
|
||||
struct Document : Node {
|
||||
string error;
|
||||
|
||||
bool load(string document) {
|
||||
name = "{root}", data = "";
|
||||
|
||||
try {
|
||||
document.replace("\r", "");
|
||||
while(document.position("\n\n")) document.replace("\n\n", "\n");
|
||||
parse(document);
|
||||
} catch(const char *perror) {
|
||||
error = perror;
|
||||
children.reset();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Document(const string &document = "") {
|
||||
load(document);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,14 @@
|
|||
#ifdef NALL_STRING_INTERNAL_HPP
|
||||
|
||||
namespace nall {
|
||||
namespace Markup {
|
||||
|
||||
inline Node Document(const string &markup) {
|
||||
if(markup.beginswith("<")) return XML::Document(markup);
|
||||
return BML::Document(markup);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,62 @@
|
|||
#ifdef NALL_STRING_INTERNAL_HPP
|
||||
|
||||
//note: specific markups inherit from Markup::Node
|
||||
//vector<Node> will slice any data; so derived nodes must not contain data nor virtual functions
|
||||
//vector<Node*> would incur a large performance penalty and greatly increased complexity
|
||||
|
||||
namespace nall {
|
||||
namespace Markup {
|
||||
|
||||
struct Node {
|
||||
string name;
|
||||
string data;
|
||||
bool attribute;
|
||||
|
||||
bool exists() const {
|
||||
return !name.empty();
|
||||
}
|
||||
|
||||
string content() const {
|
||||
return string{data}.trim(" ");
|
||||
}
|
||||
|
||||
void reset() {
|
||||
children.reset();
|
||||
}
|
||||
|
||||
Node& operator[](const string &name) {
|
||||
for(auto &node : *this) {
|
||||
if(node.name == name) return node;
|
||||
}
|
||||
static Node node;
|
||||
return node;
|
||||
}
|
||||
|
||||
const Node& operator[](const string &name) const {
|
||||
return operator[](name);
|
||||
}
|
||||
|
||||
vector<Node> operator()(const string &pattern) const {
|
||||
vector<Node> result;
|
||||
for(auto &node : *this) {
|
||||
if(node.name.wildcard(pattern)) result.append(node);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Node* begin() { return children.begin(); }
|
||||
Node* end() { return children.end(); }
|
||||
const Node* begin() const { return children.begin(); }
|
||||
const Node* end() const { return children.end(); }
|
||||
|
||||
Node() : attribute(false), level(0) {}
|
||||
|
||||
protected:
|
||||
unsigned level;
|
||||
vector<Node> children;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,19 +1,22 @@
|
|||
#ifdef NALL_STRING_INTERNAL_HPP
|
||||
|
||||
//XML v1.0 subset parser
|
||||
//revision 0.01
|
||||
//revision 0.03
|
||||
|
||||
namespace nall {
|
||||
namespace XML {
|
||||
|
||||
struct Node {
|
||||
string name;
|
||||
string data;
|
||||
bool attribute;
|
||||
vector<Node*> children;
|
||||
|
||||
inline bool exists() const {
|
||||
return !name.empty();
|
||||
struct Node : Markup::Node {
|
||||
protected:
|
||||
inline string escape() const {
|
||||
string result = data;
|
||||
result.replace("&", "&");
|
||||
result.replace("<", "<");
|
||||
result.replace(">", ">");
|
||||
if(attribute == false) return result;
|
||||
result.replace("\'", "'");
|
||||
result.replace("\"", """);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool isName(char c) const {
|
||||
|
@ -124,15 +127,14 @@ struct Node {
|
|||
if(*p == '?' || *p == '/' || *p == '>') break;
|
||||
|
||||
//parse attribute name
|
||||
Node *attribute = new Node;
|
||||
children.append(attribute);
|
||||
attribute->attribute = true;
|
||||
Node attribute;
|
||||
attribute.attribute = true;
|
||||
|
||||
const char *nameStart = p;
|
||||
while(isName(*p)) p++;
|
||||
const char *nameEnd = p;
|
||||
copy(attribute->name, nameStart, nameEnd - nameStart);
|
||||
if(attribute->name.empty()) throw "missing attribute name";
|
||||
copy(attribute.name, nameStart, nameEnd - nameStart);
|
||||
if(attribute.name.empty()) throw "missing attribute name";
|
||||
|
||||
//parse attribute data
|
||||
if(*p++ != '=') throw "missing attribute value";
|
||||
|
@ -143,7 +145,8 @@ struct Node {
|
|||
if(!*p) throw "missing attribute data terminal";
|
||||
const char *dataEnd = p++; //skip closing terminal
|
||||
|
||||
copy(attribute->data, dataStart, dataEnd - dataStart);
|
||||
copy(attribute.data, dataStart, dataEnd - dataStart);
|
||||
children.append(attribute);
|
||||
}
|
||||
|
||||
//parse closure
|
||||
|
@ -155,10 +158,9 @@ struct Node {
|
|||
|
||||
//parse element and all of its child elements
|
||||
inline void parseElement(const char *&p) {
|
||||
Node *node = new Node;
|
||||
Node node;
|
||||
if(node.parseHead(p) == false) node.parse(p);
|
||||
children.append(node);
|
||||
if(node->parseHead(p) == true) return;
|
||||
node->parse(p);
|
||||
}
|
||||
|
||||
//return true if </tag> matches this node's name
|
||||
|
@ -188,40 +190,6 @@ struct Node {
|
|||
|
||||
copy(data, dataStart, dataEnd - dataStart);
|
||||
}
|
||||
|
||||
inline void reset() {
|
||||
for(auto &child : children) delete child;
|
||||
children.reset();
|
||||
}
|
||||
|
||||
struct iterator {
|
||||
inline bool operator!=(const iterator &source) const { return index != source.index; }
|
||||
inline Node& operator*() { return *node.children[index]; }
|
||||
inline iterator& operator++() { index++; return *this; }
|
||||
inline iterator(const Node &node, unsigned index) : node(node), index(index) {}
|
||||
private:
|
||||
const Node &node;
|
||||
unsigned index;
|
||||
};
|
||||
|
||||
inline iterator begin() { return iterator(*this, 0); }
|
||||
inline iterator end() { return iterator(*this, children.size()); }
|
||||
inline const iterator begin() const { return iterator(*this, 0); }
|
||||
inline const iterator end() const { return iterator(*this, children.size()); }
|
||||
|
||||
inline Node& operator[](const char *name) {
|
||||
for(auto &node : *this) {
|
||||
if(node.name == name) return node;
|
||||
}
|
||||
static Node node;
|
||||
return node;
|
||||
}
|
||||
|
||||
inline Node() : attribute(false) {}
|
||||
inline ~Node() { reset(); }
|
||||
|
||||
Node(const Node&) = delete;
|
||||
Node& operator=(const Node&) = delete;
|
||||
};
|
||||
|
||||
struct Document : Node {
|
|
@ -63,7 +63,7 @@ string temppath() {
|
|||
#ifdef _WIN32
|
||||
wchar_t path[PATH_MAX] = L"";
|
||||
GetTempPathW(PATH_MAX, path);
|
||||
path.transform("\\", "/");
|
||||
//path.transform("\\", "/");
|
||||
return (const char*)utf8_t(path);
|
||||
#else
|
||||
return "/tmp/";
|
||||
|
|
|
@ -1,265 +0,0 @@
|
|||
#ifdef NALL_STRING_INTERNAL_HPP
|
||||
|
||||
//XML v1.0 subset parser
|
||||
//revision 0.05
|
||||
|
||||
namespace nall {
|
||||
|
||||
struct xml_attribute {
|
||||
string name;
|
||||
string content;
|
||||
virtual string parse() const;
|
||||
};
|
||||
|
||||
struct xml_element : xml_attribute {
|
||||
string parse() const;
|
||||
linear_vector<xml_attribute> attribute;
|
||||
linear_vector<xml_element> element;
|
||||
|
||||
protected:
|
||||
void parse_doctype(const char *&data);
|
||||
bool parse_head(string data);
|
||||
bool parse_body(const char *&data);
|
||||
friend xml_element xml_parse(const char *data);
|
||||
};
|
||||
|
||||
inline string xml_attribute::parse() const {
|
||||
string data;
|
||||
unsigned offset = 0;
|
||||
|
||||
const char *source = content;
|
||||
while(*source) {
|
||||
if(*source == '&') {
|
||||
if(strbegin(source, "<")) { data[offset++] = '<'; source += 4; continue; }
|
||||
if(strbegin(source, ">")) { data[offset++] = '>'; source += 4; continue; }
|
||||
if(strbegin(source, "&")) { data[offset++] = '&'; source += 5; continue; }
|
||||
if(strbegin(source, "'")) { data[offset++] = '\''; source += 6; continue; }
|
||||
if(strbegin(source, """)) { data[offset++] = '"'; source += 6; continue; }
|
||||
}
|
||||
|
||||
//reject illegal characters
|
||||
if(*source == '&') return "";
|
||||
if(*source == '<') return "";
|
||||
if(*source == '>') return "";
|
||||
|
||||
data[offset++] = *source++;
|
||||
}
|
||||
|
||||
data[offset] = 0;
|
||||
return data;
|
||||
}
|
||||
|
||||
inline string xml_element::parse() const {
|
||||
string data;
|
||||
unsigned offset = 0;
|
||||
|
||||
const char *source = content;
|
||||
while(*source) {
|
||||
if(*source == '&') {
|
||||
if(strbegin(source, "<")) { data[offset++] = '<'; source += 4; continue; }
|
||||
if(strbegin(source, ">")) { data[offset++] = '>'; source += 4; continue; }
|
||||
if(strbegin(source, "&")) { data[offset++] = '&'; source += 5; continue; }
|
||||
if(strbegin(source, "'")) { data[offset++] = '\''; source += 6; continue; }
|
||||
if(strbegin(source, """)) { data[offset++] = '"'; source += 6; continue; }
|
||||
}
|
||||
|
||||
if(strbegin(source, "<!--")) {
|
||||
if(auto pos = strpos(source, "-->")) {
|
||||
source += pos() + 3;
|
||||
continue;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
if(strbegin(source, "<![CDATA[")) {
|
||||
if(auto pos = strpos(source, "]]>")) {
|
||||
if(pos() - 9 > 0) {
|
||||
string cdata = substr(source, 9, pos() - 9);
|
||||
data.append(cdata);
|
||||
offset += strlen(cdata);
|
||||
}
|
||||
source += 9 + offset + 3;
|
||||
continue;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
//reject illegal characters
|
||||
if(*source == '&') return "";
|
||||
if(*source == '<') return "";
|
||||
if(*source == '>') return "";
|
||||
|
||||
data[offset++] = *source++;
|
||||
}
|
||||
|
||||
data[offset] = 0;
|
||||
return data;
|
||||
}
|
||||
|
||||
inline void xml_element::parse_doctype(const char *&data) {
|
||||
name = "!DOCTYPE";
|
||||
const char *content_begin = data;
|
||||
|
||||
signed counter = 0;
|
||||
while(*data) {
|
||||
char value = *data++;
|
||||
if(value == '<') counter++;
|
||||
if(value == '>') counter--;
|
||||
if(counter < 0) {
|
||||
content = substr(content_begin, 0, data - content_begin - 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw "...";
|
||||
}
|
||||
|
||||
inline bool xml_element::parse_head(string data) {
|
||||
data.qreplace("\t", " ");
|
||||
data.qreplace("\r", " ");
|
||||
data.qreplace("\n", " ");
|
||||
while(qstrpos(data, " ")) data.qreplace(" ", " ");
|
||||
data.qreplace(" =", "=");
|
||||
data.qreplace("= ", "=");
|
||||
data.rtrim();
|
||||
|
||||
lstring part;
|
||||
part.qsplit(" ", data);
|
||||
|
||||
name = part[0];
|
||||
if(name == "") throw "...";
|
||||
|
||||
for(unsigned i = 1; i < part.size(); i++) {
|
||||
lstring side;
|
||||
side.qsplit("=", part[i]);
|
||||
if(side.size() != 2) throw "...";
|
||||
|
||||
xml_attribute attr;
|
||||
attr.name = side[0];
|
||||
attr.content = side[1];
|
||||
if(strbegin(attr.content, "\"") && strend(attr.content, "\"")) attr.content.trim<1>("\"");
|
||||
else if(strbegin(attr.content, "'") && strend(attr.content, "'")) attr.content.trim<1>("'");
|
||||
else throw "...";
|
||||
attribute.append(attr);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool xml_element::parse_body(const char *&data) {
|
||||
while(true) {
|
||||
if(!*data) return false;
|
||||
if(*data++ != '<') continue;
|
||||
if(*data == '/') return false;
|
||||
|
||||
if(strbegin(data, "!DOCTYPE") == true) {
|
||||
parse_doctype(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(strbegin(data, "!--")) {
|
||||
if(auto offset = strpos(data, "-->")) {
|
||||
data += offset() + 3;
|
||||
continue;
|
||||
} else {
|
||||
throw "...";
|
||||
}
|
||||
}
|
||||
|
||||
if(strbegin(data, "![CDATA[")) {
|
||||
if(auto offset = strpos(data, "]]>")) {
|
||||
data += offset() + 3;
|
||||
continue;
|
||||
} else {
|
||||
throw "...";
|
||||
}
|
||||
}
|
||||
|
||||
auto offset = strpos(data, ">");
|
||||
if(!offset) throw "...";
|
||||
|
||||
string tag = substr(data, 0, offset());
|
||||
data += offset() + 1;
|
||||
const char *content_begin = data;
|
||||
|
||||
bool self_terminating = false;
|
||||
|
||||
if(strend(tag, "?") == true) {
|
||||
self_terminating = true;
|
||||
tag.rtrim<1>("?");
|
||||
} else if(strend(tag, "/") == true) {
|
||||
self_terminating = true;
|
||||
tag.rtrim<1>("/");
|
||||
}
|
||||
|
||||
parse_head(tag);
|
||||
if(self_terminating) return true;
|
||||
|
||||
while(*data) {
|
||||
unsigned index = element.size();
|
||||
xml_element node;
|
||||
if(node.parse_body(data) == false) {
|
||||
if(*data == '/') {
|
||||
signed length = data - content_begin - 1;
|
||||
if(length > 0) content = substr(content_begin, 0, length);
|
||||
|
||||
data++;
|
||||
auto offset = strpos(data, ">");
|
||||
if(!offset) throw "...";
|
||||
|
||||
tag = substr(data, 0, offset());
|
||||
data += offset() + 1;
|
||||
|
||||
tag.replace("\t", " ");
|
||||
tag.replace("\r", " ");
|
||||
tag.replace("\n", " ");
|
||||
while(strpos(tag, " ")) tag.replace(" ", " ");
|
||||
tag.rtrim();
|
||||
|
||||
if(name != tag) throw "...";
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
element.append(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//ensure there is only one root element
|
||||
inline bool xml_validate(xml_element &document) {
|
||||
unsigned root_counter = 0;
|
||||
|
||||
for(unsigned i = 0; i < document.element.size(); i++) {
|
||||
string &name = document.element[i].name;
|
||||
if(strbegin(name, "?")) continue;
|
||||
if(strbegin(name, "!")) continue;
|
||||
if(++root_counter > 1) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline xml_element xml_parse(const char *data) {
|
||||
xml_element self;
|
||||
|
||||
try {
|
||||
while(*data) {
|
||||
xml_element node;
|
||||
if(node.parse_body(data) == false) {
|
||||
break;
|
||||
} else {
|
||||
self.element.append(node);
|
||||
}
|
||||
}
|
||||
|
||||
if(xml_validate(self) == false) throw "...";
|
||||
return self;
|
||||
} catch(const char*) {
|
||||
xml_element empty;
|
||||
return empty;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -23,6 +23,7 @@ namespace nall {
|
|||
public:
|
||||
operator bool() const { return pool; }
|
||||
T* data() { return pool; }
|
||||
const T* data() const { return pool; }
|
||||
|
||||
bool empty() const { return objectsize == 0; }
|
||||
unsigned size() const { return objectsize; }
|
||||
|
@ -47,14 +48,15 @@ namespace nall {
|
|||
}
|
||||
|
||||
void reserve(unsigned size) {
|
||||
unsigned outputsize = min(size, objectsize);
|
||||
size = bit::round(size); //amortize growth
|
||||
T *copy = (T*)calloc(size, sizeof(T));
|
||||
for(unsigned n = 0; n < min(size, objectsize); n++) new(copy + n) T(pool[n]);
|
||||
for(unsigned n = 0; n < outputsize; n++) new(copy + n) T(pool[n]);
|
||||
for(unsigned n = 0; n < objectsize; n++) pool[n].~T();
|
||||
free(pool);
|
||||
pool = copy;
|
||||
poolsize = size;
|
||||
objectsize = min(size, objectsize);
|
||||
objectsize = outputsize;
|
||||
}
|
||||
|
||||
//requires trivial constructor
|
||||
|
@ -121,8 +123,8 @@ namespace nall {
|
|||
}
|
||||
|
||||
optional<unsigned> find(const T& data) {
|
||||
for(unsigned n = 0; n < size(); n++) if(pool[n] == data) return { true, n };
|
||||
return { false, 0u };
|
||||
for(unsigned n = 0; n < size(); n++) if(pool[n] == data) return {true, n};
|
||||
return {false, 0u};
|
||||
}
|
||||
|
||||
T& first() {
|
||||
|
|
|
@ -339,6 +339,14 @@ void Window::setResizable(bool resizable) {
|
|||
return p.setResizable(resizable);
|
||||
}
|
||||
|
||||
void Window::setSmartGeometry(const Geometry &geometry) {
|
||||
Geometry margin = p.frameMargin();
|
||||
return setGeometry({
|
||||
geometry.x + margin.x, geometry.y + margin.y,
|
||||
geometry.width, geometry.height
|
||||
});
|
||||
}
|
||||
|
||||
void Window::setStatusFont(const string &font) {
|
||||
state.statusFont = font;
|
||||
return p.setStatusFont(font);
|
||||
|
|
|
@ -202,6 +202,7 @@ struct Window : private nall::base_from_member<pWindow&>, Object {
|
|||
void setMenuVisible(bool visible = true);
|
||||
void setModal(bool modal = true);
|
||||
void setResizable(bool resizable = true);
|
||||
void setSmartGeometry(const Geometry &geometry);
|
||||
void setStatusFont(const nall::string &font);
|
||||
void setStatusText(const nall::string &text);
|
||||
void setStatusVisible(bool visible = true);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
sfc_objects := sfc-interface sfc-system sfc-controller
|
||||
sfc_objects += sfc-cartridge sfc-cheat
|
||||
sfc_objects += sfc-memory sfc-cpu sfc-smp sfc-dsp sfc-ppu
|
||||
sfc_objects += sfc-icd2 sfc-bsx sfc-sufamiturbo sfc-nss
|
||||
sfc_objects += sfc-icd2 sfc-bsx sfc-sufamiturbo sfc-nss sfc-event
|
||||
sfc_objects += sfc-sa1 sfc-superfx
|
||||
sfc_objects += sfc-armdsp sfc-hitachidsp sfc-necdsp
|
||||
sfc_objects += sfc-epsonrtc sfc-sharprtc
|
||||
|
@ -44,6 +44,7 @@ obj/sfc-icd2.o : $(sfc)/chip/icd2/icd2.cpp $(call rwildcard,$(sfc)/chip/ic
|
|||
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-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/)
|
||||
|
|
|
@ -81,27 +81,27 @@ alwaysinline void CPU::op_step() {
|
|||
}
|
||||
|
||||
void CPU::enable() {
|
||||
function<uint8 (unsigned)> read = { &CPU::mmio_read, (CPU*)&cpu };
|
||||
function<void (unsigned, uint8)> write = { &CPU::mmio_write, (CPU*)&cpu };
|
||||
function<uint8 (unsigned)> reader = { &CPU::mmio_read, (CPU*)&cpu };
|
||||
function<void (unsigned, uint8)> writer = { &CPU::mmio_write, (CPU*)&cpu };
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2140, 0x2183, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2140, 0x2183, read, write);
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x2140, 0x2183);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x2140, 0x2183);
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, read, write);
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x4016, 0x4017);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x4016, 0x4017);
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4200, 0x421f, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4200, 0x421f, read, write);
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x4200, 0x421f);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x4200, 0x421f);
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, read, write);
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x4300, 0x437f);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x4300, 0x437f);
|
||||
|
||||
read = [](unsigned addr) { return cpu.wram[addr]; };
|
||||
write = [](unsigned addr, uint8 data) { cpu.wram[addr] = data; };
|
||||
reader = [](unsigned addr) { return cpu.wram[addr]; };
|
||||
writer = [](unsigned addr, uint8 data) { cpu.wram[addr] = data; };
|
||||
|
||||
bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff, read, write, 0x000000, 0x002000);
|
||||
bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff, read, write, 0x000000, 0x002000);
|
||||
bus.map(Bus::MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff, read, write);
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x0000, 0x1fff, 0x002000);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x0000, 0x1fff, 0x002000);
|
||||
bus.map(reader, writer, 0x7e, 0x7f, 0x0000, 0xffff, 0x020000);
|
||||
}
|
||||
|
||||
void CPU::power() {
|
||||
|
|
|
@ -118,11 +118,11 @@ void PPU::frame() {
|
|||
}
|
||||
|
||||
void PPU::enable() {
|
||||
function<uint8 (unsigned)> read = { &PPU::mmio_read, (PPU*)&ppu };
|
||||
function<void (unsigned, uint8)> write = { &PPU::mmio_write, (PPU*)&ppu };
|
||||
function<uint8 (unsigned)> reader = { &PPU::mmio_read, (PPU*)&ppu };
|
||||
function<void (unsigned, uint8)> writer = { &PPU::mmio_write, (PPU*)&ppu };
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, read, write);
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x2100, 0x213f);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x2100, 0x213f);
|
||||
}
|
||||
|
||||
void PPU::power() {
|
||||
|
|
|
@ -82,11 +82,11 @@ void PPU::frame() {
|
|||
}
|
||||
|
||||
void PPU::enable() {
|
||||
function<uint8 (unsigned)> read = { &PPU::mmio_read, (PPU*)&ppu };
|
||||
function<void (unsigned, uint8)> write = { &PPU::mmio_write, (PPU*)&ppu };
|
||||
function<uint8 (unsigned)> reader = { &PPU::mmio_read, (PPU*)&ppu };
|
||||
function<void (unsigned, uint8)> writer = { &PPU::mmio_write, (PPU*)&ppu };
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, read, write);
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x2100, 0x213f);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x2100, 0x213f);
|
||||
}
|
||||
|
||||
void PPU::power() {
|
||||
|
|
|
@ -15,6 +15,7 @@ void Cartridge::load(const string &manifest) {
|
|||
has_bs_slot = false;
|
||||
has_st_slots = false;
|
||||
has_nss_dip = false;
|
||||
has_event = false;
|
||||
has_sa1 = false;
|
||||
has_superfx = false;
|
||||
has_armdsp = false;
|
||||
|
|
|
@ -27,6 +27,7 @@ struct Cartridge : property<Cartridge> {
|
|||
readonly<bool> has_bs_slot;
|
||||
readonly<bool> has_st_slots;
|
||||
readonly<bool> has_nss_dip;
|
||||
readonly<bool> has_event;
|
||||
readonly<bool> has_sa1;
|
||||
readonly<bool> has_superfx;
|
||||
readonly<bool> has_armdsp;
|
||||
|
@ -40,15 +41,12 @@ struct Cartridge : property<Cartridge> {
|
|||
readonly<bool> has_msu1;
|
||||
|
||||
struct Mapping {
|
||||
function<uint8 (unsigned)> read;
|
||||
function<void (unsigned, uint8)> write;
|
||||
Bus::MapMode mode;
|
||||
unsigned banklo;
|
||||
unsigned bankhi;
|
||||
unsigned addrlo;
|
||||
unsigned addrhi;
|
||||
unsigned offset;
|
||||
function<uint8 (unsigned)> reader;
|
||||
function<void (unsigned, uint8)> writer;
|
||||
string addr;
|
||||
unsigned size;
|
||||
unsigned base;
|
||||
unsigned mask;
|
||||
|
||||
Mapping();
|
||||
Mapping(const function<uint8 (unsigned)>&, const function<void (unsigned, uint8)>&);
|
||||
|
@ -75,26 +73,27 @@ struct Cartridge : property<Cartridge> {
|
|||
|
||||
private:
|
||||
void parse_markup(const char*);
|
||||
void parse_markup_map(Mapping&, XML::Node&);
|
||||
void parse_markup_memory(MappedRAM&, XML::Node&, unsigned id, bool writable);
|
||||
void parse_markup_map(Mapping&, Markup::Node&);
|
||||
void parse_markup_memory(MappedRAM&, Markup::Node&, unsigned id, bool writable);
|
||||
|
||||
void parse_markup_cartridge(XML::Node&);
|
||||
void parse_markup_icd2(XML::Node&);
|
||||
void parse_markup_bsx(XML::Node&);
|
||||
void parse_markup_bsxslot(XML::Node&);
|
||||
void parse_markup_sufamiturbo(XML::Node&);
|
||||
void parse_markup_nss(XML::Node&);
|
||||
void parse_markup_sa1(XML::Node&);
|
||||
void parse_markup_superfx(XML::Node&);
|
||||
void parse_markup_armdsp(XML::Node&);
|
||||
void parse_markup_hitachidsp(XML::Node&);
|
||||
void parse_markup_necdsp(XML::Node&);
|
||||
void parse_markup_epsonrtc(XML::Node&);
|
||||
void parse_markup_sharprtc(XML::Node&);
|
||||
void parse_markup_spc7110(XML::Node&);
|
||||
void parse_markup_sdd1(XML::Node&);
|
||||
void parse_markup_obc1(XML::Node&);
|
||||
void parse_markup_msu1(XML::Node&);
|
||||
void parse_markup_cartridge(Markup::Node&);
|
||||
void parse_markup_icd2(Markup::Node&);
|
||||
void parse_markup_bsx(Markup::Node&);
|
||||
void parse_markup_bsxslot(Markup::Node&);
|
||||
void parse_markup_sufamiturbo(Markup::Node&);
|
||||
void parse_markup_nss(Markup::Node&);
|
||||
void parse_markup_event(Markup::Node&);
|
||||
void parse_markup_sa1(Markup::Node&);
|
||||
void parse_markup_superfx(Markup::Node&);
|
||||
void parse_markup_armdsp(Markup::Node&);
|
||||
void parse_markup_hitachidsp(Markup::Node&);
|
||||
void parse_markup_necdsp(Markup::Node&);
|
||||
void parse_markup_epsonrtc(Markup::Node&);
|
||||
void parse_markup_sharprtc(Markup::Node&);
|
||||
void parse_markup_spc7110(Markup::Node&);
|
||||
void parse_markup_sdd1(Markup::Node&);
|
||||
void parse_markup_obc1(Markup::Node&);
|
||||
void parse_markup_msu1(Markup::Node&);
|
||||
};
|
||||
|
||||
extern Cartridge cartridge;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
void Cartridge::parse_markup(const char *markup) {
|
||||
mapping.reset();
|
||||
|
||||
XML::Document document(markup);
|
||||
auto document = Markup::Document(markup);
|
||||
auto &cartridge = document["cartridge"];
|
||||
region = cartridge["region"].data != "PAL" ? Region::NTSC : Region::PAL;
|
||||
|
||||
|
@ -13,6 +13,7 @@ void Cartridge::parse_markup(const char *markup) {
|
|||
parse_markup_bsxslot(cartridge["bsxslot"]);
|
||||
parse_markup_sufamiturbo(cartridge["sufamiturbo"]);
|
||||
parse_markup_nss(cartridge["nss"]);
|
||||
parse_markup_event(cartridge["event"]);
|
||||
parse_markup_sa1(cartridge["sa1"]);
|
||||
parse_markup_superfx(cartridge["superfx"]);
|
||||
parse_markup_armdsp(cartridge["armdsp"]);
|
||||
|
@ -28,40 +29,14 @@ void Cartridge::parse_markup(const char *markup) {
|
|||
|
||||
//
|
||||
|
||||
void Cartridge::parse_markup_map(Mapping &m, XML::Node &map) {
|
||||
m.offset = numeral(map["offset"].data);
|
||||
void Cartridge::parse_markup_map(Mapping &m, Markup::Node &map) {
|
||||
m.addr = map["address"].data;
|
||||
m.size = numeral(map["size"].data);
|
||||
|
||||
string data = map["mode"].data;
|
||||
if(data == "direct") m.mode = Bus::MapMode::Direct;
|
||||
if(data == "linear") m.mode = Bus::MapMode::Linear;
|
||||
if(data == "shadow") m.mode = Bus::MapMode::Shadow;
|
||||
|
||||
lstring part;
|
||||
part.split(":", map["address"].data);
|
||||
if(part.size() != 2) return;
|
||||
|
||||
lstring subpart;
|
||||
subpart.split("-", part[0]);
|
||||
if(subpart.size() == 1) {
|
||||
m.banklo = hex(subpart[0]);
|
||||
m.bankhi = m.banklo;
|
||||
} else if(subpart.size() == 2) {
|
||||
m.banklo = hex(subpart[0]);
|
||||
m.bankhi = hex(subpart[1]);
|
||||
}
|
||||
|
||||
subpart.split("-", part[1]);
|
||||
if(subpart.size() == 1) {
|
||||
m.addrlo = hex(subpart[0]);
|
||||
m.addrhi = m.addrlo;
|
||||
} else if(subpart.size() == 2) {
|
||||
m.addrlo = hex(subpart[0]);
|
||||
m.addrhi = hex(subpart[1]);
|
||||
}
|
||||
m.base = numeral(map["base"].data);
|
||||
m.mask = numeral(map["mask"].data);
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_memory(MappedRAM &ram, XML::Node &node, unsigned id, bool writable) {
|
||||
void Cartridge::parse_markup_memory(MappedRAM &ram, Markup::Node &node, unsigned id, bool writable) {
|
||||
string name = node["name"].data;
|
||||
unsigned size = numeral(node["size"].data);
|
||||
ram.map(allocate<uint8>(size, 0xff), size);
|
||||
|
@ -73,7 +48,7 @@ void Cartridge::parse_markup_memory(MappedRAM &ram, XML::Node &node, unsigned id
|
|||
|
||||
//
|
||||
|
||||
void Cartridge::parse_markup_cartridge(XML::Node &root) {
|
||||
void Cartridge::parse_markup_cartridge(Markup::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
|
||||
parse_markup_memory(rom, root["rom"], ID::ROM, false);
|
||||
|
@ -98,7 +73,7 @@ void Cartridge::parse_markup_cartridge(XML::Node &root) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_icd2(XML::Node &root) {
|
||||
void Cartridge::parse_markup_icd2(Markup::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_gb_slot = true;
|
||||
icd2.revision = max(1, numeral(root["revision"].data));
|
||||
|
@ -122,7 +97,7 @@ void Cartridge::parse_markup_icd2(XML::Node &root) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_bsx(XML::Node &root) {
|
||||
void Cartridge::parse_markup_bsx(Markup::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_bs_cart = true;
|
||||
has_bs_slot = true;
|
||||
|
@ -136,7 +111,8 @@ void Cartridge::parse_markup_bsx(XML::Node &root) {
|
|||
for(auto &node : root) {
|
||||
if(node.name != "map") continue;
|
||||
|
||||
if(node["id"].data == "rom" || node["id"].data == "ram") {
|
||||
if(node["id"].data == "rom"
|
||||
|| node["id"].data == "ram") {
|
||||
Mapping m({&BSXCartridge::mcu_read, &bsxcartridge}, {&BSXCartridge::mcu_write, &bsxcartridge});
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
|
@ -150,7 +126,7 @@ void Cartridge::parse_markup_bsx(XML::Node &root) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_bsxslot(XML::Node &root) {
|
||||
void Cartridge::parse_markup_bsxslot(Markup::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_bs_slot = true;
|
||||
|
||||
|
@ -169,7 +145,7 @@ void Cartridge::parse_markup_bsxslot(XML::Node &root) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_sufamiturbo(XML::Node &root) {
|
||||
void Cartridge::parse_markup_sufamiturbo(Markup::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_st_slots = true;
|
||||
|
||||
|
@ -206,7 +182,7 @@ void Cartridge::parse_markup_sufamiturbo(XML::Node &root) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_nss(XML::Node &root) {
|
||||
void Cartridge::parse_markup_nss(Markup::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_nss_dip = true;
|
||||
nss.dip = interface->dipSettings(root);
|
||||
|
@ -222,7 +198,65 @@ void Cartridge::parse_markup_nss(XML::Node &root) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_sa1(XML::Node &root) {
|
||||
void Cartridge::parse_markup_event(Markup::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_event = true;
|
||||
|
||||
for(auto &node : root) {
|
||||
if(node.name != "rom") continue;
|
||||
unsigned id = numeral(node["id"].data);
|
||||
if(id > 3) continue;
|
||||
parse_markup_memory(event.rom[id], node, ID::EventROM0 + id, false);
|
||||
}
|
||||
parse_markup_memory(event.ram, root["ram"], ID::EventRAM, true);
|
||||
|
||||
event.board = Event::Board::CampusChallenge92;
|
||||
if(root["name"].data == "Campus Challenge '92") event.board = Event::Board::CampusChallenge92;
|
||||
if(root["name"].data == "Powerfest '94") event.board = Event::Board::Powerfest94;
|
||||
|
||||
event.revision = root["revision"].data == "B" ? 2 : 1;
|
||||
lstring part = root["timer"].data.split<1>(":");
|
||||
if(part.size() == 1) event.timer = decimal(part(0));
|
||||
if(part.size() == 2) event.timer = decimal(part(0)) * 60 + decimal(part(1));
|
||||
|
||||
part = string{root["server"]["address"].data}.ltrim<1>("http://").split<1>("/");
|
||||
event.path = {"/", part(1)};
|
||||
part = part(0).split<1>(":");
|
||||
event.host = part(0);
|
||||
event.port = decimal(part(1)) ? decimal(part(1)) : 80;
|
||||
event.username = root["server"]["username"].data;
|
||||
event.password = root["server"]["password"].data;
|
||||
|
||||
for(auto &node : root) {
|
||||
if(node.name != "map") continue;
|
||||
|
||||
if(node["id"].data == "rom") {
|
||||
Mapping m({&Event::rom_read, &event}, [](unsigned, uint8) {});
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
if(node["id"].data == "ram") {
|
||||
Mapping m({&Event::ram_read, &event}, {&Event::ram_write, &event});
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
if(node["id"].data == "dr") {
|
||||
Mapping m([](unsigned) -> uint8 { return cpu.regs.mdr; }, {&Event::dr, &event});
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
if(node["id"].data == "sr") {
|
||||
Mapping m({&Event::sr, &event}, [](unsigned, uint8) {});
|
||||
parse_markup_map(m, node);
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_sa1(Markup::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_sa1 = true;
|
||||
|
||||
|
@ -260,7 +294,7 @@ void Cartridge::parse_markup_sa1(XML::Node &root) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_superfx(XML::Node &root) {
|
||||
void Cartridge::parse_markup_superfx(Markup::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_superfx = true;
|
||||
|
||||
|
@ -279,6 +313,7 @@ void Cartridge::parse_markup_superfx(XML::Node &root) {
|
|||
if(node["id"].data == "rom") {
|
||||
Mapping m(superfx.cpurom);
|
||||
parse_markup_map(m, node);
|
||||
if(m.size == 0) m.size = superfx.rom.size();
|
||||
mapping.append(m);
|
||||
}
|
||||
|
||||
|
@ -291,7 +326,7 @@ void Cartridge::parse_markup_superfx(XML::Node &root) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_armdsp(XML::Node &root) {
|
||||
void Cartridge::parse_markup_armdsp(Markup::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_armdsp = true;
|
||||
|
||||
|
@ -311,7 +346,7 @@ void Cartridge::parse_markup_armdsp(XML::Node &root) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_hitachidsp(XML::Node &root) {
|
||||
void Cartridge::parse_markup_hitachidsp(Markup::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_hitachidsp = true;
|
||||
|
||||
|
@ -338,12 +373,13 @@ void Cartridge::parse_markup_hitachidsp(XML::Node &root) {
|
|||
if(node["id"].data == "rom") {
|
||||
Mapping m({&HitachiDSP::rom_read, &hitachidsp}, {&HitachiDSP::rom_write, &hitachidsp});
|
||||
parse_markup_map(m, node);
|
||||
if(m.size == 0) m.size = hitachidsp.rom.size();
|
||||
mapping.append(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_necdsp(XML::Node &root) {
|
||||
void Cartridge::parse_markup_necdsp(Markup::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_necdsp = true;
|
||||
|
||||
|
@ -393,7 +429,7 @@ void Cartridge::parse_markup_necdsp(XML::Node &root) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_epsonrtc(XML::Node &root) {
|
||||
void Cartridge::parse_markup_epsonrtc(Markup::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_epsonrtc = true;
|
||||
|
||||
|
@ -412,7 +448,7 @@ void Cartridge::parse_markup_epsonrtc(XML::Node &root) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_sharprtc(XML::Node &root) {
|
||||
void Cartridge::parse_markup_sharprtc(Markup::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_sharprtc = true;
|
||||
|
||||
|
@ -431,7 +467,7 @@ void Cartridge::parse_markup_sharprtc(XML::Node &root) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_spc7110(XML::Node &root) {
|
||||
void Cartridge::parse_markup_spc7110(Markup::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_spc7110 = true;
|
||||
|
||||
|
@ -462,7 +498,7 @@ void Cartridge::parse_markup_spc7110(XML::Node &root) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_sdd1(XML::Node &root) {
|
||||
void Cartridge::parse_markup_sdd1(Markup::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_sdd1 = true;
|
||||
|
||||
|
@ -492,7 +528,7 @@ void Cartridge::parse_markup_sdd1(XML::Node &root) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_obc1(XML::Node &root) {
|
||||
void Cartridge::parse_markup_obc1(Markup::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_obc1 = true;
|
||||
|
||||
|
@ -509,7 +545,7 @@ void Cartridge::parse_markup_obc1(XML::Node &root) {
|
|||
}
|
||||
}
|
||||
|
||||
void Cartridge::parse_markup_msu1(XML::Node &root) {
|
||||
void Cartridge::parse_markup_msu1(Markup::Node &root) {
|
||||
if(root.exists() == false) return;
|
||||
has_msu1 = true;
|
||||
|
||||
|
@ -525,22 +561,19 @@ void Cartridge::parse_markup_msu1(XML::Node &root) {
|
|||
}
|
||||
|
||||
Cartridge::Mapping::Mapping() {
|
||||
mode = Bus::MapMode::Direct;
|
||||
banklo = bankhi = addrlo = addrhi = offset = size = 0;
|
||||
size = base = mask = 0;
|
||||
}
|
||||
|
||||
Cartridge::Mapping::Mapping(SuperFamicom::Memory &memory) {
|
||||
read = {&SuperFamicom::Memory::read, &memory};
|
||||
write = {&SuperFamicom::Memory::write, &memory};
|
||||
mode = Bus::MapMode::Direct;
|
||||
banklo = bankhi = addrlo = addrhi = offset = size = 0;
|
||||
reader = {&SuperFamicom::Memory::read, &memory};
|
||||
writer = {&SuperFamicom::Memory::write, &memory};
|
||||
size = base = mask = 0;
|
||||
}
|
||||
|
||||
Cartridge::Mapping::Mapping(const function<uint8 (unsigned)> &read_, const function<void (unsigned, uint8)> &write_) {
|
||||
read = read_;
|
||||
write = write_;
|
||||
mode = Bus::MapMode::Direct;
|
||||
banklo = bankhi = addrlo = addrhi = offset = size = 0;
|
||||
Cartridge::Mapping::Mapping(const function<uint8 (unsigned)> &reader, const function<void (unsigned, uint8)> &writer) {
|
||||
this->reader = reader;
|
||||
this->writer = writer;
|
||||
size = base = mask = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,8 +6,8 @@ void BSXSatellaview::init() {
|
|||
}
|
||||
|
||||
void BSXSatellaview::load() {
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2188, 0x219f, {&BSXSatellaview::mmio_read, &bsxsatellaview}, {&BSXSatellaview::mmio_write, &bsxsatellaview});
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2188, 0x219f, {&BSXSatellaview::mmio_read, &bsxsatellaview}, {&BSXSatellaview::mmio_write, &bsxsatellaview});
|
||||
bus.map({&BSXSatellaview::mmio_read, &bsxsatellaview}, {&BSXSatellaview::mmio_write, &bsxsatellaview}, 0x00, 0x3f, 0x2188, 0x219f);
|
||||
bus.map({&BSXSatellaview::mmio_read, &bsxsatellaview}, {&BSXSatellaview::mmio_write, &bsxsatellaview}, 0x80, 0xbf, 0x2188, 0x219f);
|
||||
}
|
||||
|
||||
void BSXSatellaview::unload() {
|
||||
|
|
|
@ -7,6 +7,7 @@ struct Coprocessor : Thread {
|
|||
#include <sfc/chip/bsx/bsx.hpp>
|
||||
#include <sfc/chip/sufamiturbo/sufamiturbo.hpp>
|
||||
#include <sfc/chip/nss/nss.hpp>
|
||||
#include <sfc/chip/event/event.hpp>
|
||||
|
||||
#include <sfc/chip/sa1/sa1.hpp>
|
||||
#include <sfc/chip/superfx/superfx.hpp>
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
#include <sfc/sfc.hpp>
|
||||
|
||||
#define EVENT_CPP
|
||||
namespace SuperFamicom {
|
||||
|
||||
Event event;
|
||||
|
||||
void Event::Enter() { event.enter(); }
|
||||
|
||||
void Event::enter() {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
}
|
||||
|
||||
step(1);
|
||||
synchronize_cpu();
|
||||
}
|
||||
|
||||
void Event::init() {
|
||||
}
|
||||
|
||||
void Event::load() {
|
||||
}
|
||||
|
||||
void Event::unload() {
|
||||
rom[0].reset();
|
||||
rom[1].reset();
|
||||
rom[2].reset();
|
||||
rom[3].reset();
|
||||
ram.reset();
|
||||
}
|
||||
|
||||
void Event::power() {
|
||||
}
|
||||
|
||||
void Event::reset() {
|
||||
create(Event::Enter, 1);
|
||||
}
|
||||
|
||||
//DSP-1
|
||||
uint8 Event::sr(unsigned addr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//DSP-1
|
||||
void Event::dr(unsigned addr, uint8 data) {
|
||||
}
|
||||
|
||||
//is there bank-switching?
|
||||
uint8 Event::rom_read(unsigned addr) {
|
||||
return cpu.regs.mdr;
|
||||
}
|
||||
|
||||
//is there read-protection?
|
||||
uint8 Event::ram_read(unsigned addr) {
|
||||
return cpu.regs.mdr;
|
||||
}
|
||||
|
||||
//is there write-protection?
|
||||
void Event::ram_write(unsigned addr, uint8 data) {
|
||||
}
|
||||
|
||||
void Event::serialize(serializer &s) {
|
||||
Thread::serialize(s);
|
||||
s.array(ram.data(), ram.size());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
//SNES-EVENT board emulation (skeleton):
|
||||
//* Campus Challenge '92
|
||||
//* Powerfest '94
|
||||
|
||||
struct Event : Coprocessor {
|
||||
MappedRAM rom[4];
|
||||
MappedRAM ram;
|
||||
|
||||
static void Enter();
|
||||
void enter();
|
||||
void init();
|
||||
void load();
|
||||
void unload();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 sr(unsigned);
|
||||
void dr(unsigned, uint8 data);
|
||||
uint8 rom_read(unsigned addr);
|
||||
uint8 ram_read(unsigned addr);
|
||||
void ram_write(unsigned addr, uint8 data);
|
||||
|
||||
void serialize(serializer&);
|
||||
|
||||
//private:
|
||||
enum class Board : unsigned { CampusChallenge92, Powerfest94 } board;
|
||||
unsigned revision;
|
||||
unsigned timer;
|
||||
|
||||
string host;
|
||||
unsigned port;
|
||||
string path;
|
||||
string username;
|
||||
string password;
|
||||
};
|
||||
|
||||
extern Event event;
|
|
@ -14,8 +14,8 @@ void SDD1::init() {
|
|||
void SDD1::load() {
|
||||
//hook S-CPU DMA MMIO registers to gather information for struct dma[];
|
||||
//buffer address and transfer size information for use in SDD1::mcu_read()
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, {&SDD1::read, &sdd1}, {&SDD1::write, &sdd1});
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, {&SDD1::read, &sdd1}, {&SDD1::write, &sdd1});
|
||||
bus.map({&SDD1::read, &sdd1}, {&SDD1::write, &sdd1}, 0x00, 0x3f, 0x4300, 0x437f);
|
||||
bus.map({&SDD1::read, &sdd1}, {&SDD1::write, &sdd1}, 0x80, 0xbf, 0x4300, 0x437f);
|
||||
}
|
||||
|
||||
void SDD1::unload() {
|
||||
|
|
|
@ -96,27 +96,27 @@ void CPU::op_step() {
|
|||
}
|
||||
|
||||
void CPU::enable() {
|
||||
function<uint8 (unsigned)> read = {&CPU::mmio_read, (CPU*)&cpu};
|
||||
function<void (unsigned, uint8)> write = {&CPU::mmio_write, (CPU*)&cpu};
|
||||
function<uint8 (unsigned)> reader = {&CPU::mmio_read, (CPU*)&cpu};
|
||||
function<void (unsigned, uint8)> writer = {&CPU::mmio_write, (CPU*)&cpu};
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2140, 0x2183, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2140, 0x2183, read, write);
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x2140, 0x2183);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x2140, 0x2183);
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, read, write);
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x4016, 0x4017);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x4016, 0x4017);
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4200, 0x421f, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4200, 0x421f, read, write);
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x4200, 0x421f);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x4200, 0x421f);
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, read, write);
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x4300, 0x437f);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x4300, 0x437f);
|
||||
|
||||
read = [](unsigned addr) { return cpu.wram[addr]; };
|
||||
write = [](unsigned addr, uint8 data) { cpu.wram[addr] = data; };
|
||||
reader = [](unsigned addr) { return cpu.wram[addr]; };
|
||||
writer = [](unsigned addr, uint8 data) { cpu.wram[addr] = data; };
|
||||
|
||||
bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff, read, write, 0x000000, 0x002000);
|
||||
bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff, read, write, 0x000000, 0x002000);
|
||||
bus.map(Bus::MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff, read, write);
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x0000, 0x1fff, 0x002000);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x0000, 0x1fff, 0x002000);
|
||||
bus.map(reader, writer, 0x7e, 0x7f, 0x0000, 0xffff, 0x020000);
|
||||
}
|
||||
|
||||
void CPU::power() {
|
||||
|
|
|
@ -29,6 +29,11 @@ unsigned Interface::group(unsigned id) {
|
|||
return 0;
|
||||
case ID::ROM:
|
||||
case ID::RAM:
|
||||
case ID::EventROM0:
|
||||
case ID::EventROM1:
|
||||
case ID::EventROM2:
|
||||
case ID::EventROM3:
|
||||
case ID::EventRAM:
|
||||
case ID::SA1ROM:
|
||||
case ID::SA1IRAM:
|
||||
case ID::SA1BWRAM:
|
||||
|
@ -97,6 +102,12 @@ void Interface::load(unsigned id, const stream &stream, const string &manifest)
|
|||
if(id == ID::ROM) cartridge.rom.read(stream);
|
||||
if(id == ID::RAM) cartridge.ram.read(stream);
|
||||
|
||||
if(id == ID::EventROM0) event.rom[0].read(stream);
|
||||
if(id == ID::EventROM1) event.rom[1].read(stream);
|
||||
if(id == ID::EventROM2) event.rom[2].read(stream);
|
||||
if(id == ID::EventROM3) event.rom[3].read(stream);
|
||||
if(id == ID::EventRAM) event.ram.read(stream);
|
||||
|
||||
if(id == ID::SA1ROM) sa1.rom.read(stream);
|
||||
if(id == ID::SA1IRAM) sa1.iram.read(stream);
|
||||
if(id == ID::SA1BWRAM) sa1.bwram.read(stream);
|
||||
|
@ -175,6 +186,7 @@ void Interface::load(unsigned id, const stream &stream, const string &manifest)
|
|||
|
||||
void Interface::save(unsigned id, const stream &stream) {
|
||||
if(id == ID::RAM) stream.write(cartridge.ram.data(), cartridge.ram.size());
|
||||
if(id == ID::EventRAM) stream.write(event.ram.data(), event.ram.size());
|
||||
if(id == ID::SA1IRAM) stream.write(sa1.iram.data(), sa1.iram.size());
|
||||
if(id == ID::SA1BWRAM) stream.write(sa1.bwram.data(), sa1.bwram.size());
|
||||
if(id == ID::SuperFXRAM) stream.write(superfx.ram.data(), superfx.ram.size());
|
||||
|
|
|
@ -18,6 +18,12 @@ struct ID {
|
|||
ROM,
|
||||
RAM,
|
||||
|
||||
EventROM0,
|
||||
EventROM1,
|
||||
EventROM2,
|
||||
EventROM3,
|
||||
EventRAM,
|
||||
|
||||
SA1ROM,
|
||||
SA1IRAM,
|
||||
SA1BWRAM,
|
||||
|
|
|
@ -73,6 +73,14 @@ unsigned Bus::mirror(unsigned addr, unsigned size) {
|
|||
return base;
|
||||
}
|
||||
|
||||
unsigned Bus::recode(unsigned addr, unsigned mask) {
|
||||
for(unsigned n = 0; n < 24; n++) {
|
||||
unsigned bit = 1 << n;
|
||||
if(mask & bit) addr = ((addr >> (n + 1)) << n) | (addr & (bit - 1));
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
uint8 Bus::read(unsigned addr) {
|
||||
if(cheat.override[addr]) return cheat.read(addr);
|
||||
return reader[lookup[addr]](target[addr]);
|
||||
|
|
|
@ -6,30 +6,26 @@ namespace SuperFamicom {
|
|||
Bus bus;
|
||||
|
||||
void Bus::map(
|
||||
MapMode mode,
|
||||
unsigned bank_lo, unsigned bank_hi,
|
||||
unsigned addr_lo, unsigned addr_hi,
|
||||
const function<uint8 (unsigned)> &rd,
|
||||
const function<void (unsigned, uint8)> &wr,
|
||||
unsigned base, unsigned length
|
||||
const function<uint8 (unsigned)> &reader,
|
||||
const function<void (unsigned, uint8)> &writer,
|
||||
unsigned banklo, unsigned bankhi,
|
||||
unsigned addrlo, unsigned addrhi,
|
||||
unsigned size, unsigned base, unsigned mask
|
||||
) {
|
||||
assert(bank_lo <= bank_hi && bank_lo <= 0xff);
|
||||
assert(addr_lo <= addr_hi && addr_lo <= 0xffff);
|
||||
assert(banklo <= bankhi && banklo <= 0xff);
|
||||
assert(addrlo <= addrhi && addrlo <= 0xffff);
|
||||
assert(idcount < 255);
|
||||
|
||||
unsigned id = idcount++;
|
||||
assert(id < 255);
|
||||
reader[id] = rd;
|
||||
writer[id] = wr;
|
||||
this->reader[id] = reader;
|
||||
this->writer[id] = writer;
|
||||
|
||||
if(length == 0) length = (bank_hi - bank_lo + 1) * (addr_hi - addr_lo + 1);
|
||||
|
||||
unsigned offset = 0;
|
||||
for(unsigned bank = bank_lo; bank <= bank_hi; bank++) {
|
||||
for(unsigned addr = addr_lo; addr <= addr_hi; addr++) {
|
||||
unsigned destaddr = (bank << 16) | addr;
|
||||
if(mode == MapMode::Linear) destaddr = mirror(base + offset++, length);
|
||||
if(mode == MapMode::Shadow) destaddr = mirror(base + destaddr, length);
|
||||
lookup[(bank << 16) | addr] = id;
|
||||
target[(bank << 16) | addr] = destaddr;
|
||||
for(unsigned bank = banklo; bank <= bankhi; bank++) {
|
||||
for(unsigned addr = addrlo; addr <= addrhi; addr++) {
|
||||
unsigned offset = recode(bank << 16 | addr, mask);
|
||||
if(size) offset = base + mirror(offset, size - base);
|
||||
lookup[bank << 16 | addr] = id;
|
||||
target[bank << 16 | addr] = offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,12 +35,25 @@ void Bus::map_reset() {
|
|||
function<void (unsigned, uint8)> writer = [](unsigned, uint8) {};
|
||||
|
||||
idcount = 0;
|
||||
map(MapMode::Direct, 0x00, 0xff, 0x0000, 0xffff, reader, writer);
|
||||
map(reader, writer, 0x00, 0xff, 0x0000, 0xffff);
|
||||
}
|
||||
|
||||
void Bus::map_xml() {
|
||||
for(auto &m : cartridge.mapping) {
|
||||
map(m.mode, m.banklo, m.bankhi, m.addrlo, m.addrhi, m.read, m.write, m.offset, m.size);
|
||||
lstring part = m.addr.split<1>(":");
|
||||
lstring banks = part(0).split(",");
|
||||
lstring addrs = part(1).split(",");
|
||||
for(auto &bank : banks) {
|
||||
for(auto &addr : addrs) {
|
||||
lstring bankpart = bank.split<1>("-");
|
||||
lstring addrpart = addr.split<1>("-");
|
||||
unsigned banklo = hex(bankpart(0));
|
||||
unsigned bankhi = hex(bankpart(1, bankpart(0)));
|
||||
unsigned addrlo = hex(addrpart(0));
|
||||
unsigned addrhi = hex(addrpart(1, addrpart(0)));
|
||||
map(m.reader, m.writer, banklo, bankhi, addrlo, addrhi, m.size, m.base, m.mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ private:
|
|||
|
||||
struct Bus {
|
||||
alwaysinline static unsigned mirror(unsigned addr, unsigned size);
|
||||
alwaysinline static unsigned recode(unsigned addr, unsigned mask);
|
||||
|
||||
alwaysinline uint8 read(unsigned addr);
|
||||
alwaysinline void write(unsigned addr, uint8 data);
|
||||
|
@ -55,14 +56,12 @@ struct Bus {
|
|||
function<uint8 (unsigned)> reader[256];
|
||||
function<void (unsigned, uint8)> writer[256];
|
||||
|
||||
enum class MapMode : unsigned { Direct, Linear, Shadow };
|
||||
void map(
|
||||
MapMode mode,
|
||||
unsigned bank_lo, unsigned bank_hi,
|
||||
unsigned addr_lo, unsigned addr_hi,
|
||||
const function<uint8 (unsigned)> &read,
|
||||
const function<void (unsigned, uint8)> &write,
|
||||
unsigned base = 0, unsigned length = 0
|
||||
const function<uint8 (unsigned)> &reader,
|
||||
const function<void (unsigned, uint8)> &writer,
|
||||
unsigned banklo, unsigned bankhi,
|
||||
unsigned addrlo, unsigned addrhi,
|
||||
unsigned size = 0, unsigned base = 0, unsigned mask = 0
|
||||
);
|
||||
|
||||
void map_reset();
|
||||
|
|
|
@ -79,11 +79,11 @@ void PPU::add_clocks(unsigned clocks) {
|
|||
}
|
||||
|
||||
void PPU::enable() {
|
||||
function<uint8 (unsigned)> read = { &PPU::mmio_read, (PPU*)&ppu };
|
||||
function<void (unsigned, uint8)> write = { &PPU::mmio_write, (PPU*)&ppu };
|
||||
function<uint8 (unsigned)> reader = { &PPU::mmio_read, (PPU*)&ppu };
|
||||
function<void (unsigned, uint8)> writer = { &PPU::mmio_write, (PPU*)&ppu };
|
||||
|
||||
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, read, write);
|
||||
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, read, write);
|
||||
bus.map(reader, writer, 0x00, 0x3f, 0x2100, 0x213f);
|
||||
bus.map(reader, writer, 0x80, 0xbf, 0x2100, 0x213f);
|
||||
}
|
||||
|
||||
void PPU::power() {
|
||||
|
|
|
@ -60,6 +60,7 @@ void System::serialize_all(serializer &s) {
|
|||
if(cartridge.has_gb_slot()) icd2.serialize(s);
|
||||
if(cartridge.has_bs_cart()) bsxcartridge.serialize(s);
|
||||
if(cartridge.has_st_slots()) sufamiturbo.serialize(s);
|
||||
if(cartridge.has_event()) event.serialize(s);
|
||||
if(cartridge.has_sa1()) sa1.serialize(s);
|
||||
if(cartridge.has_superfx()) superfx.serialize(s);
|
||||
if(cartridge.has_armdsp()) armdsp.serialize(s);
|
||||
|
|
|
@ -69,6 +69,7 @@ void System::init() {
|
|||
bsxcartridge.init();
|
||||
bsxflash.init();
|
||||
nss.init();
|
||||
event.init();
|
||||
sa1.init();
|
||||
superfx.init();
|
||||
armdsp.init();
|
||||
|
@ -124,6 +125,7 @@ void System::load() {
|
|||
if(cartridge.has_bs_slot()) bsxflash.load();
|
||||
if(cartridge.has_st_slots()) sufamiturbo.load();
|
||||
if(cartridge.has_nss_dip()) nss.load();
|
||||
if(cartridge.has_event()) event.load();
|
||||
if(cartridge.has_sa1()) sa1.load();
|
||||
if(cartridge.has_superfx()) superfx.load();
|
||||
if(cartridge.has_armdsp()) armdsp.load();
|
||||
|
@ -147,6 +149,7 @@ void System::unload() {
|
|||
if(cartridge.has_bs_slot()) bsxflash.unload();
|
||||
if(cartridge.has_st_slots()) sufamiturbo.unload();
|
||||
if(cartridge.has_nss_dip()) nss.unload();
|
||||
if(cartridge.has_event()) event.unload();
|
||||
if(cartridge.has_sa1()) sa1.unload();
|
||||
if(cartridge.has_superfx()) superfx.unload();
|
||||
if(cartridge.has_armdsp()) armdsp.unload();
|
||||
|
@ -173,6 +176,7 @@ void System::power() {
|
|||
if(cartridge.has_bs_cart()) bsxcartridge.power();
|
||||
if(cartridge.has_bs_slot()) bsxflash.power();
|
||||
if(cartridge.has_nss_dip()) nss.power();
|
||||
if(cartridge.has_event()) event.power();
|
||||
if(cartridge.has_sa1()) sa1.power();
|
||||
if(cartridge.has_superfx()) superfx.power();
|
||||
if(cartridge.has_armdsp()) armdsp.power();
|
||||
|
@ -199,6 +203,7 @@ void System::reset() {
|
|||
if(cartridge.has_bs_cart()) bsxcartridge.reset();
|
||||
if(cartridge.has_bs_slot()) bsxflash.reset();
|
||||
if(cartridge.has_nss_dip()) nss.reset();
|
||||
if(cartridge.has_event()) event.reset();
|
||||
if(cartridge.has_sa1()) sa1.reset();
|
||||
if(cartridge.has_superfx()) superfx.reset();
|
||||
if(cartridge.has_armdsp()) armdsp.reset();
|
||||
|
@ -212,6 +217,7 @@ void System::reset() {
|
|||
if(cartridge.has_msu1()) msu1.reset();
|
||||
|
||||
if(cartridge.has_gb_slot()) cpu.coprocessors.append(&icd2);
|
||||
if(cartridge.has_event()) cpu.coprocessors.append(&event);
|
||||
if(cartridge.has_sa1()) cpu.coprocessors.append(&sa1);
|
||||
if(cartridge.has_superfx()) cpu.coprocessors.append(&superfx);
|
||||
if(cartridge.has_armdsp()) cpu.coprocessors.append(&armdsp);
|
||||
|
|
|
@ -21,7 +21,7 @@ DipSwitches::DipSwitches() {
|
|||
onClose = accept.onActivate = [&] { quit = true; };
|
||||
}
|
||||
|
||||
unsigned DipSwitches::run(const XML::Node &node) {
|
||||
unsigned DipSwitches::run(const Markup::Node &node) {
|
||||
audio.clear();
|
||||
setModal(true);
|
||||
quit = false;
|
||||
|
|
|
@ -15,7 +15,7 @@ struct DipSwitches : Window {
|
|||
Widget spacer;
|
||||
Button accept;
|
||||
|
||||
unsigned run(const XML::Node &node);
|
||||
unsigned run(const Markup::Node &node);
|
||||
DipSwitches();
|
||||
|
||||
private:
|
||||
|
|
|
@ -107,7 +107,7 @@ int16_t Interface::inputPoll(unsigned port, unsigned device, unsigned input) {
|
|||
return inputManager->inputMap[guid]->poll();
|
||||
}
|
||||
|
||||
unsigned Interface::dipSettings(const XML::Node &node) {
|
||||
unsigned Interface::dipSettings(const Markup::Node &node) {
|
||||
return dipSwitches->run(node);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ struct Interface : Emulator::Interface::Bind {
|
|||
void videoRefresh(const uint32_t *data, unsigned pitch, unsigned width, unsigned height);
|
||||
void audioSample(int16_t lsample, int16_t rsample);
|
||||
int16_t inputPoll(unsigned port, unsigned device, unsigned input);
|
||||
unsigned dipSettings(const XML::Node &node);
|
||||
unsigned dipSettings(const Markup::Node &node);
|
||||
string path(unsigned group);
|
||||
void notify(const string &text);
|
||||
};
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
1 24 "../data/bsnes.Manifest"
|
||||
2 ICON DISCARDABLE "../data/bsnes.ico"
|
||||
1 24 "../data/higan.Manifest"
|
||||
2 ICON DISCARDABLE "../data/higan.ico"
|
||||
|
|
Loading…
Reference in New Issue