Update to v082r29 release.

byuu says:

I doubt anyone is going to like these changes, but oh well.

The base height output for NES+SNES is now always 256x240. The Enable
Overscan option blanks out borders around the screen. This eliminates
the need for an overscan software filter. For NES, it's 16px from the
top and bottom, and 8px from the left and right. Anything less and you
get scrolling artifacts in countless games. For the SNES, it's only 16px
from the top and bottom. Main point is that most NTSC SNES games are
224-height games, so you'll have black borders. Oh well, hack the source
if you want. Game Boy overscan option does nothing.

Everything except for the cheats.xml file now uses BML markup. I need to
write a converter for cheats.xml still. Cut the SNES board parsing code
in half, 30KB->16KB. Much cleaner now.
Took the opportunity to fix a mistake I made back with the XML spec: all
numbers are integers, but can be prefixed with 0x to become hexadecimal.
Before, offset/size values defaulted to hex-mode even without a prefix,
unlike frequency/etc values.

The XML shaders have gone in their own direction anyway, with most being
multi-pass and incompatible with bsnes. So that said, please don't
extend the BML functionality from your end. But f eel free to add to the
XML spec, since other emulators now use that as well. And don't
misunderstand, I love the work that's being done there. It's pretty
awesome to see multi-pass shader capabilities, and the RAM watching
stuff is just amazing.
If there are any really awesome single-pass shaders that people would
like, I can convert it from XML and include it with future releases.
On that topic, I removed the watercolor/hdr-tv ones from the binary
packages (still in the source archive) ... they are neat, but not very
useful for actual gaming.
If we had more than one, I'd remove the Direct3D sepia one. Not going to
use shaders from a certain bipolar manic, because I'd never hear the end
of it if I did :/

Oh, one change I think people will like: MSU1 no longer requires
a memory map specification, so MSU1 authors won't have to keep updating
to my newer revisions of board markups. Basically, if there's not
a board with an msu1 section, it'll check if "gamename.msu" exists. If
it does, MSU1 gets mapped to 00-3f,80-bf:2000-2007. If all you want is
music, make a blank, zero-byte gamename.msu file.
This commit is contained in:
Tim Allen 2011-10-04 22:55:39 +11:00
parent b629a46779
commit 21f9fe4cd5
23 changed files with 1038 additions and 1414 deletions

View File

@ -16,7 +16,7 @@ namespace GameBoy {
#include "serialization.cpp"
Cartridge cartridge;
void Cartridge::load(const string &xml, const uint8_t *data, unsigned size) {
void Cartridge::load(const string &markup, const uint8_t *data, unsigned size) {
if(size == 0) size = 32768;
romdata = allocate<uint8>(romsize = size, 0xff);
if(data) memcpy(romdata, data, size);
@ -33,42 +33,24 @@ void Cartridge::load(const string &xml, const uint8_t *data, unsigned size) {
info.romsize = 0;
info.ramsize = 0;
xml_element document = xml_parse(xml);
for(auto &head : document.element) {
if(head.name == "cartridge") {
for(auto &attr : head.attribute) {
if(attr.name == "mapper") {
if(attr.content == "none") info.mapper = Mapper::MBC0;
if(attr.content == "MBC1") info.mapper = Mapper::MBC1;
if(attr.content == "MBC2") info.mapper = Mapper::MBC2;
if(attr.content == "MBC3") info.mapper = Mapper::MBC3;
if(attr.content == "MBC5") info.mapper = Mapper::MBC5;
if(attr.content == "MMM01") info.mapper = Mapper::MMM01;
if(attr.content == "HuC1") info.mapper = Mapper::HuC1;
if(attr.content == "HuC3") info.mapper = Mapper::HuC3;
}
BML::Document document(markup);
if(attr.name == "rtc") info.rtc = (attr.content == "true" ? true : false);
if(attr.name == "rumble") info.rumble = (attr.content == "true" ? true : false);
}
auto &mapperid = document["cartridge"]["mapper"].value;
if(mapperid == "none" ) info.mapper = Mapper::MBC0;
if(mapperid == "MBC1" ) info.mapper = Mapper::MBC1;
if(mapperid == "MBC2" ) info.mapper = Mapper::MBC2;
if(mapperid == "MBC3" ) info.mapper = Mapper::MBC3;
if(mapperid == "MBC5" ) info.mapper = Mapper::MBC5;
if(mapperid == "MMM01") info.mapper = Mapper::MMM01;
if(mapperid == "HuC1" ) info.mapper = Mapper::HuC1;
if(mapperid == "HuC3" ) info.mapper = Mapper::HuC3;
for(auto &elem : head.element) {
if(elem.name == "rom") {
for(auto &attr : elem.attribute) {
if(attr.name == "size") info.romsize = hex(attr.content);
}
}
info.rtc = document["cartridge"]["rtc"].exists();
info.rumble = document["cartridge"]["rumble"].exists();
if(elem.name == "ram") {
info.ram = true;
for(auto &attr : elem.attribute) {
if(attr.name == "size") info.ramsize = hex(attr.content);
if(attr.name == "battery") info.battery = (attr.content == "true" ? true : false);
}
}
}
}
}
info.romsize = hex(document["cartridge"]["rom"]["size"].value);
info.ramsize = hex(document["cartridge"]["ram"]["size"].value);
info.battery = document["cartridge"]["ram"]["non-volatile"].exists();
switch(info.mapper) { default:
case Mapper::MBC0: mapper = &mbc0; break;

View File

@ -45,7 +45,7 @@ struct Cartridge : MMIO, property<Cartridge> {
MMIO *mapper;
bool bootrom_enable;
void load(const string &xml, const uint8_t *data, unsigned size);
void load(const string &markup, const uint8_t *data, unsigned size);
void unload();
uint8 rom_read(unsigned addr);

View File

@ -29,8 +29,8 @@ bool Interface::cartridgeLoaded() {
return cartridge.loaded();
}
void Interface::loadCartridge(const string &xml, const uint8_t *data, unsigned size) {
cartridge.load(xml, data, size);
void Interface::loadCartridge(const string &markup, const uint8_t *data, unsigned size) {
cartridge.load(markup, data, size);
system.power();
}

View File

@ -10,7 +10,7 @@ public:
virtual void initialize(Interface*);
virtual bool cartridgeLoaded();
virtual void loadCartridge(const string &xml, const uint8_t *data, unsigned size);
virtual void loadCartridge(const string &markup, const uint8_t *data, unsigned size);
virtual void unloadCartridge();
enum class Memory : unsigned {

View File

@ -5,7 +5,7 @@ namespace nall {
class GameBoyCartridge {
public:
string xml;
string markup;
inline GameBoyCartridge(uint8_t *data, unsigned size);
//private:
@ -22,7 +22,7 @@ public:
};
GameBoyCartridge::GameBoyCartridge(uint8_t *romdata, unsigned romsize) {
xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
markup = "";
if(romsize < 0x4000) return;
info.mapper = "unknown";
@ -100,18 +100,15 @@ GameBoyCartridge::GameBoyCartridge(uint8_t *romdata, unsigned romsize) {
if(info.mapper == "MBC2") info.ramsize = 512; //512 x 4-bit
xml.append("<cartridge mapper='", info.mapper, "'");
if(info.rtc) xml.append(" rtc='true'");
if(info.rumble) xml.append(" rumble='true'");
xml.append(">\n");
markup.append("cartridge mapper=", info.mapper);
if(info.rtc) markup.append(" rtc");
if(info.rumble) markup.append(" rumble");
markup.append("\n");
xml.append(" <rom size='", hex(romsize), "'/>\n"); //TODO: trust/check info.romsize?
markup.append("\t" "rom size=", hex(romsize), "\n"); //TODO: trust/check info.romsize?
if(info.ramsize > 0)
xml.append(" <ram size='", hex(info.ramsize), "' battery='", info.battery, "'/>\n");
xml.append("</cartridge>\n");
xml.transform("'", "\"");
markup.append("\t" "ram size=", hex(info.ramsize), info.battery ? " non-volatile\n" : "\n");
}
}

View File

@ -3,10 +3,10 @@
namespace nall {
class SNESCartridge {
class SnesCartridge {
public:
string xmlMemoryMap;
inline SNESCartridge(const uint8_t *data, unsigned size);
string markup;
inline SnesCartridge(const uint8_t *data, unsigned size);
//private:
inline void read_header(const uint8_t *data, unsigned size);
@ -105,436 +105,346 @@ public:
bool has_st018;
};
SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
#define T "\t"
SnesCartridge::SnesCartridge(const uint8_t *data, unsigned size) {
read_header(data, size);
string xml = "<?xml version='1.0' encoding='UTF-8'?>\n";
string xml;
markup = "";
if(type == TypeBsx) {
xml.append("<cartridge/>");
xmlMemoryMap = xml.transform("'", "\"");
markup.append("cartridge");
return;
}
if(type == TypeSufamiTurbo) {
xml.append("<cartridge/>");
xmlMemoryMap = xml.transform("'", "\"");
markup.append("cartridge");
return;
}
if(type == TypeGameBoy) {
xml.append("<cartridge rtc='", gameboy_has_rtc(data, size), "'>\n");
markup.append("cartridge rtc=", gameboy_has_rtc(data, size), "\n");
if(gameboy_ram_size(data, size) > 0) {
xml.append(" <ram size='0x", hex(gameboy_ram_size(data, size)), "'/>\n");
markup.append(T "ram size=0x", hex(gameboy_ram_size(data, size)), "\n");
}
xml.append("</cartridge>\n");
xmlMemoryMap = xml.transform("'", "\"");
return;
}
xml.append("<cartridge");
if(region == NTSC) {
xml.append(" region='NTSC'");
} else {
xml.append(" region='PAL'");
}
xml.append(">\n");
markup.append("cartridge region=", region == NTSC ? "NTSC\n" : "PAL\n");
if(type == TypeSuperGameBoy1Bios) {
xml.append(" <rom>\n");
xml.append(" <map mode='linear' address='00-7f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='80-ff:8000-ffff'/>\n");
xml.append(" </rom>\n");
xml.append(" <icd2 revision='1'>\n");
xml.append(" <map address='00-3f:6000-7fff'/>\n");
xml.append(" <map address='80-bf:6000-7fff'/>\n");
xml.append(" </icd2>\n");
markup.append(T "rom\n");
markup.append(T T "map mode=linear address=00-7f:8000-ffff\n");
markup.append(T T "map mode=linear address=80-ff:8000-ffff\n");
markup.append(T "icd2 revision=1\n");
markup.append(T T "map address=00-3f:6000-7fff\n");
markup.append(T T "map address=80-bf:6000-7fff\n");
} else if(type == TypeSuperGameBoy2Bios) {
xml.append(" <rom>\n");
xml.append(" <map mode='linear' address='00-7f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='80-ff:8000-ffff'/>\n");
xml.append(" </rom>\n");
xml.append(" <icd2 revision='2'>\n");
xml.append(" <map address='00-3f:6000-7fff'/>\n");
xml.append(" <map address='80-bf:6000-7fff'/>\n");
xml.append(" </icd2>\n");
markup.append(T "rom\n");
markup.append(T T "map mode=linear address=00-7f:8000-ffff\n");
markup.append(T T "map mode=linear address=80-ff:8000-ffff\n");
markup.append(T "icd2 revision=1\n");
markup.append(T T "map address=00-3f:6000-7fff\n");
markup.append(T T "map address=80-bf:6000-7fff\n");
} else if(has_cx4) {
xml.append(" <hitachidsp model='HG51B169' frequency='20000000' firmware='cx4.bin' sha256='ae8d4d1961b93421ff00b3caa1d0f0ce7783e749772a3369c36b3dbf0d37ef18'>\n");
xml.append(" <rom>\n");
xml.append(" <map mode='linear' address='00-7f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='80-ff:8000-ffff'/>\n");
xml.append(" </rom>\n");
xml.append(" <mmio>\n");
xml.append(" <map address='00-3f:6000-7fff'/>\n");
xml.append(" <map address='80-bf:6000-7fff'/>\n");
xml.append(" </mmio>\n");
xml.append(" </hitachidsp>\n");
markup.append(T "hitachidsp model=HG51B169 frequency=20000000 firmware=cx4.bin sha256=ae8d4d1961b93421ff00b3caa1d0f0ce7783e749772a3369c36b3dbf0d37ef18\n");
markup.append(T T "rom\n");
markup.append(T T T "map mode=linear address=00-7f:8000-ffff\n");
markup.append(T T T "map mode=linear address=80-ff:8000-ffff\n");
markup.append(T T "mmio\n");
markup.append(T T T "map address=00-3f:6000-7fff\n");
markup.append(T T T "map address=80-bf:6000-7fff\n");
} else if(has_spc7110) {
xml.append(" <rom>\n");
xml.append(" <map mode='shadow' address='00-0f:8000-ffff'/>\n");
xml.append(" <map mode='shadow' address='80-bf:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='c0-cf:0000-ffff'/>\n");
xml.append(" </rom>\n");
markup.append(T "rom\n");
markup.append(T T "map mode=shadow address=00-0f:8000-ffff\n");
markup.append(T T "map mode=shadow address=80-bf:8000-ffff\n");
markup.append(T T "map mode=linear address=c0-cf:0000-ffff\n");
xml.append(" <spc7110>\n");
xml.append(" <mcu>\n");
xml.append(" <map address='d0-ff:0000-ffff' offset='0x100000' size='0x", hex(size - 0x100000), "'/>\n");
xml.append(" </mcu>\n");
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
xml.append(" <map mode='linear' address='00:6000-7fff'/>\n");
xml.append(" <map mode='linear' address='30:6000-7fff'/>\n");
xml.append(" </ram>\n");
xml.append(" <mmio>\n");
xml.append(" <map address='00-3f:4800-483f'/>\n");
xml.append(" <map address='80-bf:4800-483f'/>\n");
xml.append(" </mmio>\n");
markup.append(T "spc7110\n");
markup.append(T T "mcu\n");
markup.append(T T T "map address=d0-ff:0000-ffff offset=0x100000 size=0x", hex(size - 0x100000), "\n");
markup.append(T T "ram size=0x", hex(ram_size), "\n");
markup.append(T T T "map mode=linear address=00:6000-7fff\n");
markup.append(T T T "map mode=linear address=30:6000-7fff\n");
markup.append(T T "mmio\n");
markup.append(T T T "map address=00-3f:4800-483f\n");
markup.append(T T T "map address=80-bf:4800-483f\n");
if(has_spc7110rtc) {
xml.append(" <rtc>\n");
xml.append(" <map address='00-3f:4840-4842'/>\n");
xml.append(" <map address='80-bf:4840-4842'/>\n");
xml.append(" </rtc>\n");
markup.append(T T "rtc\n");
markup.append(T T T "map address=00-3f:4840-4842\n");
markup.append(T T T "map address=80-bf:4840-4842\n");
}
xml.append(" <dcu>\n");
xml.append(" <map address='50:0000-ffff'/>\n");
xml.append(" </dcu>\n");
xml.append(" </spc7110>\n");
markup.append(T T "dcu\n");
markup.append(T T T "map address=50:0000-ffff\n");
} else if(mapper == LoROM) {
xml.append(" <rom>\n");
xml.append(" <map mode='linear' address='00-7f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='80-ff:8000-ffff'/>\n");
xml.append(" </rom>\n");
markup.append(T "rom\n");
markup.append(T T "map mode=linear address=00-7f:8000-ffff\n");
markup.append(T T "map mode=linear address=80-ff:8000-ffff\n");
if(ram_size > 0) {
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
xml.append(" <map mode='linear' address='20-3f:6000-7fff'/>\n");
xml.append(" <map mode='linear' address='a0-bf:6000-7fff'/>\n");
markup.append(T "ram size=0x", hex(ram_size), "\n");
markup.append(T T "map mode=linear address=20-3f:6000-7fff\n");
markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n");
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
xml.append(" <map mode='linear' address='70-7f:0000-7fff'/>\n");
xml.append(" <map mode='linear' address='f0-ff:0000-7fff'/>\n");
markup.append(T T "map mode=linear address=70-7f:0000-7fff\n");
markup.append(T T "map mode=linear address=f0-ff:0000-7fff\n");
} else {
xml.append(" <map mode='linear' address='70-7f:0000-ffff'/>\n");
xml.append(" <map mode='linear' address='f0-ff:0000-ffff'/>\n");
markup.append(T T "map mode=linear address=70-7f:0000-ffff\n");
markup.append(T T "map mode=linear address=f0-ff:0000-ffff\n");
}
xml.append(" </ram>\n");
}
} else if(mapper == HiROM) {
xml.append(" <rom>\n");
xml.append(" <map mode='shadow' address='00-3f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='40-7f:0000-ffff'/>\n");
xml.append(" <map mode='shadow' address='80-bf:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='c0-ff:0000-ffff'/>\n");
xml.append(" </rom>\n");
markup.append(T "rom\n");
markup.append(T T "map mode=shadow address=00-3f:8000-ffff\n");
markup.append(T T "map mode=linear address=40-7f:0000-ffff\n");
markup.append(T T "map mode=shadow address=80-bf:8000-ffff\n");
markup.append(T T "map mode=linear address=c0-ff:0000-ffff\n");
if(ram_size > 0) {
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
xml.append(" <map mode='linear' address='20-3f:6000-7fff'/>\n");
xml.append(" <map mode='linear' address='a0-bf:6000-7fff'/>\n");
markup.append(T "ram size=0x", hex(ram_size), "\n");
markup.append(T T "map mode=linear address=20-3f:6000-7fff\n");
markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n");
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
xml.append(" <map mode='linear' address='70-7f:0000-7fff'/>\n");
markup.append(T T "map mode=linear address=70-7f:0000-7fff\n");
} else {
xml.append(" <map mode='linear' address='70-7f:0000-ffff'/>\n");
markup.append(T T "map mode=linear address=70-7f:0000-ffff\n");
}
xml.append(" </ram>\n");
}
} else if(mapper == ExLoROM) {
xml.append(" <rom>\n");
xml.append(" <map mode='linear' address='00-3f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='40-7f:0000-ffff'/>\n");
xml.append(" <map mode='linear' address='80-bf:8000-ffff'/>\n");
xml.append(" </rom>\n");
markup.append(T "rom\n");
markup.append(T T "map mode=linear address=00-3f:8000-ffff\n");
markup.append(T T "map mode=linear address=40-7f:0000-ffff\n");
markup.append(T T "map mode=linear address=80-bf:8000-ffff\n");
if(ram_size > 0) {
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
xml.append(" <map mode='linear' address='20-3f:6000-7fff'/>\n");
xml.append(" <map mode='linear' address='a0-bf:6000-7fff'/>\n");
xml.append(" <map mode='linear' address='70-7f:0000-7fff'/>\n");
xml.append(" </ram>\n");
markup.append(T "ram size=0x", hex(ram_size), "\n");
markup.append(T T "map mode=linear address=20-3f:6000-7fff\n");
markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n");
markup.append(T T "map mode=linear address=70-7f:0000-7fff\n");
}
} else if(mapper == ExHiROM) {
xml.append(" <rom>\n");
xml.append(" <map mode='shadow' address='00-3f:8000-ffff' offset='0x400000'/>\n");
xml.append(" <map mode='linear' address='40-7f:0000-ffff' offset='0x400000'/>\n");
xml.append(" <map mode='shadow' address='80-bf:8000-ffff' offset='0x000000'/>\n");
xml.append(" <map mode='linear' address='c0-ff:0000-ffff' offset='0x000000'/>\n");
xml.append(" </rom>\n");
markup.append(T "rom\n");
markup.append(T T "map mode=shadow address=00-3f:8000-ffff offset=0x400000\n");
markup.append(T T "map mode=linear address=40-7f:0000-ffff offset=0x400000\n");
markup.append(T T "map mode=shadow address=80-bf:8000-ffff offset=0x000000\n");
markup.append(T T "map mode=linear address=c0-ff:0000-ffff offset=0x000000\n");
if(ram_size > 0) {
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
xml.append(" <map mode='linear' address='20-3f:6000-7fff'/>\n");
xml.append(" <map mode='linear' address='a0-bf:6000-7fff'/>\n");
markup.append(T "ram size=0x", hex(ram_size), "\n");
markup.append(T T "map mode=linear address=20-3f:6000-7fff\n");
markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n");
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
xml.append(" <map mode='linear' address='70-7f:0000-7fff'/>\n");
markup.append(T T "map mode=linear address=70-7f:0000-7fff\n");
} else {
xml.append(" <map mode='linear' address='70-7f:0000-ffff'/>\n");
markup.append(T T "map mode=linear address=70-7f:0000-ffff\n");
}
xml.append(" </ram>\n");
}
} else if(mapper == SuperFXROM) {
xml.append(" <superfx revision='2'>\n");
xml.append(" <rom>\n");
xml.append(" <map mode='linear' address='00-3f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='40-5f:0000-ffff'/>\n");
xml.append(" <map mode='linear' address='80-bf:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='c0-df:0000-ffff'/>\n");
xml.append(" </rom>\n");
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
xml.append(" <map mode='linear' address='00-3f:6000-7fff' size='0x2000'/>\n");
xml.append(" <map mode='linear' address='60-7f:0000-ffff'/>\n");
xml.append(" <map mode='linear' address='80-bf:6000-7fff' size='0x2000'/>\n");
xml.append(" <map mode='linear' address='e0-ff:0000-ffff'/>\n");
xml.append(" </ram>\n");
xml.append(" <mmio>\n");
xml.append(" <map address='00-3f:3000-32ff'/>\n");
xml.append(" <map address='80-bf:3000-32ff'/>\n");
xml.append(" </mmio>\n");
xml.append(" </superfx>\n");
markup.append(T "superfx revision=2\n");
markup.append(T T "rom\n");
markup.append(T T T "map mode=linear address=00-3f:8000-ffff\n");
markup.append(T T T "map mode=linear address=40-5f:0000-ffff\n");
markup.append(T T T "map mode=linear address=80-bf:8000-ffff\n");
markup.append(T T T "map mode=linear address=c0-df:0000-ffff\n");
markup.append(T T "ram size=0x", hex(ram_size), "\n");
markup.append(T T T "map mode=linear address=00-3f:6000-7fff size=0x2000\n");
markup.append(T T T "map mode=linear address=60-7f:0000-ffff\n");
markup.append(T T T "map mode=linear address=80-bf:6000-7fff size=0x2000\n");
markup.append(T T T "map mode=linear address=e0-ff:0000-ffff\n");
markup.append(T T "mmio\n");
markup.append(T T T "map address=00-3f:3000-32ff\n");
markup.append(T T T "map address=80-bf:3000-32ff\n");
} else if(mapper == SA1ROM) {
xml.append(" <sa1>\n");
xml.append(" <mcu>\n");
xml.append(" <rom>\n");
xml.append(" <map mode='direct' address='00-3f:8000-ffff'/>\n");
xml.append(" <map mode='direct' address='80-bf:8000-ffff'/>\n");
xml.append(" <map mode='direct' address='c0-ff:0000-ffff'/>\n");
xml.append(" </rom>\n");
xml.append(" <ram>\n");
xml.append(" <map mode='direct' address='00-3f:6000-7fff'/>\n");
xml.append(" <map mode='direct' address='80-bf:6000-7fff'/>\n");
xml.append(" </ram>\n");
xml.append(" </mcu>\n");
xml.append(" <iram size='0x800'>\n");
xml.append(" <map mode='linear' address='00-3f:3000-37ff'/>\n");
xml.append(" <map mode='linear' address='80-bf:3000-37ff'/>\n");
xml.append(" </iram>\n");
xml.append(" <bwram size='0x", hex(ram_size), "'>\n");
xml.append(" <map mode='linear' address='40-4f:0000-ffff'/>\n");
xml.append(" </bwram>\n");
xml.append(" <mmio>\n");
xml.append(" <map address='00-3f:2200-23ff'/>\n");
xml.append(" <map address='80-bf:2200-23ff'/>\n");
xml.append(" </mmio>\n");
xml.append(" </sa1>\n");
markup.append(T "sa1\n");
markup.append(T T "mcu\n");
markup.append(T T T "rom\n");
markup.append(T T T T "map mode=direct address=00-3f:8000-ffff\n");
markup.append(T T T T "map mode=direct address=80-bf:8000-ffff\n");
markup.append(T T T T "map mode=direct address=c0-ff:0000-ffff\n");
markup.append(T T T "ram\n");
markup.append(T T T T "map mode=direct address=00-3f:6000-7fff\n");
markup.append(T T T T "map mode=direct address=80-bf:6000-7fff\n");
markup.append(T T "iram size=0x800\n");
markup.append(T T T "map mode=linear address=00-3f:3000-37ff\n");
markup.append(T T T "map mode=linear address=80-bf:3000-37ff\n");
markup.append(T T "bwram size=0x", hex(ram_size), "\n");
markup.append(T T T "map mode=linear address=40-4f:0000-ffff\n");
markup.append(T T "mmio\n");
markup.append(T T T "map address=00-3f:2200-23ff\n");
markup.append(T T T "map address=80-bf:2200-23ff\n");
} else if(mapper == BSCLoROM) {
xml.append(" <rom>\n");
xml.append(" <map mode='linear' address='00-1f:8000-ffff' offset='0x000000'/>\n");
xml.append(" <map mode='linear' address='20-3f:8000-ffff' offset='0x100000'/>\n");
xml.append(" <map mode='linear' address='80-9f:8000-ffff' offset='0x200000'/>\n");
xml.append(" <map mode='linear' address='a0-bf:8000-ffff' offset='0x100000'/>\n");
xml.append(" </rom>\n");
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
xml.append(" <map mode='linear' address='70-7f:0000-7fff'/>\n");
xml.append(" <map mode='linear' address='f0-ff:0000-7fff'/>\n");
xml.append(" </ram>\n");
xml.append(" <bsx>\n");
xml.append(" <slot>\n");
xml.append(" <map mode='linear' address='c0-ef:0000-ffff'/>\n");
xml.append(" </slot>\n");
xml.append(" </bsx>\n");
markup.append(T "rom\n");
markup.append(T T "map mode=linear address=00-1f:8000-ffff offset=0x000000\n");
markup.append(T T "map mode=linear address=20-3f:8000-ffff offset=0x100000\n");
markup.append(T T "map mode=linear address=80-9f:8000-ffff offset=0x200000\n");
markup.append(T T "map mode=linear address=a0-bf:8000-ffff offset=0x100000\n");
markup.append(T "ram size=0x", hex(ram_size), "\n");
markup.append(T T "map mode=linear address=70-7f:0000-7fff\n");
markup.append(T T "map mode=linear address=f0-ff:0000-7fff\n");
markup.append(T "bsx\n");
markup.append(T T "slot\n");
markup.append(T T T "map mode=linear address=c0-ef:0000-ffff\n");
} else if(mapper == BSCHiROM) {
xml.append(" <rom>\n");
xml.append(" <map mode='shadow' address='00-1f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='40-5f:0000-ffff'/>\n");
xml.append(" <map mode='shadow' address='80-9f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='c0-df:0000-ffff'/>\n");
xml.append(" </rom>\n");
xml.append(" <ram size='0x", hex(ram_size), "'>\n");
xml.append(" <map mode='linear' address='20-3f:6000-7fff'/>\n");
xml.append(" <map mode='linear' address='a0-bf:6000-7fff'/>\n");
xml.append(" </ram>\n");
xml.append(" <bsx>\n");
xml.append(" <slot>\n");
xml.append(" <map mode='shadow' address='20-3f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='60-7f:0000-ffff'/>\n");
xml.append(" <map mode='shadow' address='a0-bf:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='e0-ff:0000-ffff'/>\n");
xml.append(" </slot>\n");
xml.append(" </bsx>\n");
markup.append(T "rom\n");
markup.append(T T "map mode=shadow address=00-1f:8000-ffff\n");
markup.append(T T "map mode=linear address=40-5f:0000-ffff\n");
markup.append(T T "map mode=shadow address=80-9f:8000-ffff\n");
markup.append(T T "map mode=linear address=c0-df:0000-ffff\n");
markup.append(T "ram size=0x", hex(ram_size), "\n");
markup.append(T T "map mode=linear address=20-3f:6000-7fff\n");
markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n");
markup.append(T "bsx\n");
markup.append(T T "slot\n");
markup.append(T T T "map mode=shadow address=20-3f:8000-ffff\n");
markup.append(T T T "map mode=linear address=60-7f:0000-ffff\n");
markup.append(T T T "map mode=shadow address=a0-bf:8000-ffff\n");
markup.append(T T T "map mode=linear address=e0-ff:0000-ffff\n");
} else if(mapper == BSXROM) {
xml.append(" <bsx>\n");
xml.append(" <mcu>\n");
xml.append(" <map address='00-3f:8000-ffff'/>\n");
xml.append(" <map address='80-bf:8000-ffff'/>\n");
xml.append(" <map address='40-7f:0000-ffff'/>\n");
xml.append(" <map address='c0-ff:0000-ffff'/>\n");
xml.append(" <map address='20-3f:6000-7fff'/>\n");
xml.append(" </mcu>\n");
xml.append(" <mmio>\n");
xml.append(" <map address='00-3f:5000-5fff'/>\n");
xml.append(" <map address='80-bf:5000-5fff'/>\n");
xml.append(" </mmio>\n");
xml.append(" </bsx>\n");
markup.append(T "bsx\n");
markup.append(T T "mcu\n");
markup.append(T T T "map address=00-3f:8000-ffff\n");
markup.append(T T T "map address=80-bf:8000-ffff\n");
markup.append(T T T "map address=40-7f:0000-ffff\n");
markup.append(T T T "map address=c0-ff:0000-ffff\n");
markup.append(T T T "map address=20-3f:6000-7fff\n");
markup.append(T T "mmio\n");
markup.append(T T T "map address=00-3f:5000-5fff\n");
markup.append(T T T "map address=80-bf:5000-5fff\n");
} else if(mapper == STROM) {
xml.append(" <rom>\n");
xml.append(" <map mode='linear' address='00-1f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='80-9f:8000-ffff'/>\n");
xml.append(" </rom>\n");
xml.append(" <sufamiturbo>\n");
xml.append(" <slot id='A'>\n");
xml.append(" <rom>\n");
xml.append(" <map mode='linear' address='20-3f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='a0-bf:8000-ffff'/>\n");
xml.append(" </rom>\n");
xml.append(" <ram size='0x20000'>\n");
xml.append(" <map mode='linear' address='60-63:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='e0-e3:8000-ffff'/>\n");
xml.append(" </ram>\n");
xml.append(" </slot>\n");
xml.append(" <slot id='B'>\n");
xml.append(" <rom>\n");
xml.append(" <map mode='linear' address='40-5f:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='c0-df:8000-ffff'/>\n");
xml.append(" </rom>\n");
xml.append(" <ram size='0x20000'>\n");
xml.append(" <map mode='linear' address='70-73:8000-ffff'/>\n");
xml.append(" <map mode='linear' address='f0-f3:8000-ffff'/>\n");
xml.append(" </ram>\n");
xml.append(" </slot>\n");
xml.append(" </sufamiturbo>\n");
markup.append(T "rom\n");
markup.append(T T "map mode=linear address=00-1f:8000-ffff\n");
markup.append(T T "map mode=linear address=80-9f:8000-ffff\n");
markup.append(T "sufamiturbo\n");
markup.append(T T "slot id=A\n");
markup.append(T T T "rom\n");
markup.append(T T T T "map mode=linear address=20-3f:8000-ffff\n");
markup.append(T T T T "map mode=linear address=a0-bf:8000-ffff\n");
markup.append(T T T "ram size=0x20000\n");
markup.append(T T T T "map mode=linear address=60-63:8000-ffff\n");
markup.append(T T T T "map mode=linear address=e0-e3:8000-ffff\n");
markup.append(T T "slot id=B\n");
markup.append(T T T "rom\n");
markup.append(T T T T "map mode=linear address=40-5f:8000-ffff\n");
markup.append(T T T T "map mode=linear address=c0-df:8000-ffff\n");
markup.append(T T T "ram size=0x20000\n");
markup.append(T T T T "map mode=linear address=70-73:8000-ffff\n");
markup.append(T T T T "map mode=linear address=f0-f3:8000-ffff\n");
}
if(has_srtc) {
xml.append(" <srtc>\n");
xml.append(" <map address='00-3f:2800-2801'/>\n");
xml.append(" <map address='80-bf:2800-2801'/>\n");
xml.append(" </srtc>\n");
markup.append(T "srtc\n");
markup.append(T T "map address=00-3f:2800-2801\n");
markup.append(T T "map address=80-bf:2800-2801\n");
}
if(has_sdd1) {
xml.append(" <sdd1>\n");
xml.append(" <mcu>\n");
xml.append(" <map address='c0-ff:0000-ffff'/>\n");
xml.append(" </mcu>\n");
xml.append(" <mmio>\n");
xml.append(" <map address='00-3f:4800-4807'/>\n");
xml.append(" <map address='80-bf:4800-4807'/>\n");
xml.append(" </mmio>\n");
xml.append(" </sdd1>\n");
markup.append(T "sdd1\n");
markup.append(T T "mcu\n");
markup.append(T T T "map address=c0-ff:0000-ffff\n");
markup.append(T T "mmio\n");
markup.append(T T T "map address=00-3f:4800-4807\n");
markup.append(T T T "map address=80-bf:4800-4807\n");
}
if(has_dsp1) {
xml.append(" <necdsp model='uPD7725' frequency='8000000' firmware='dsp1b.bin' sha256='4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c'>\n");
markup.append(T "necdsp model=uPD7725 frequency=8000000 firmware=dsp1b.bin sha256=4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c\n");
if(dsp1_mapper == DSP1LoROM1MB) {
xml.append(" <dr>\n");
xml.append(" <map address='20-3f:8000-bfff'/>\n");
xml.append(" <map address='a0-bf:8000-bfff'/>\n");
xml.append(" </dr>\n");
xml.append(" <sr>\n");
xml.append(" <map address='20-3f:c000-ffff'/>\n");
xml.append(" <map address='a0-bf:c000-ffff'/>\n");
xml.append(" </sr>\n");
markup.append(T T "dr\n");
markup.append(T T T "map address=20-3f:8000-bfff\n");
markup.append(T T T "map address=a0-bf:8000-bfff\n");
markup.append(T T "sr\n");
markup.append(T T T "map address=20-3f:c000-ffff\n");
markup.append(T T T "map address=a0-bf:c000-ffff\n");
} else if(dsp1_mapper == DSP1LoROM2MB) {
xml.append(" <dr>\n");
xml.append(" <map address='60-6f:0000-3fff'/>\n");
xml.append(" <map address='e0-ef:0000-3fff'/>\n");
xml.append(" </dr>\n");
xml.append(" <sr>\n");
xml.append(" <map address='60-6f:4000-7fff'/>\n");
xml.append(" <map address='e0-ef:4000-7fff'/>\n");
xml.append(" </sr>\n");
markup.append(T T "dr\n");
markup.append(T T T "map address=60-6f:0000-3fff\n");
markup.append(T T T "map address=e0-ef:0000-3fff\n");
markup.append(T T "sr\n");
markup.append(T T T "map address=60-6f:4000-7fff\n");
markup.append(T T T "map address=e0-ef:4000-7fff\n");
} else if(dsp1_mapper == DSP1HiROM) {
xml.append(" <dr>\n");
xml.append(" <map address='00-1f:6000-6fff'/>\n");
xml.append(" <map address='80-9f:6000-6fff'/>\n");
xml.append(" </dr>\n");
xml.append(" <sr>\n");
xml.append(" <map address='00-1f:7000-7fff'/>\n");
xml.append(" <map address='80-9f:7000-7fff'/>\n");
xml.append(" </sr>\n");
markup.append(T T "dr\n");
markup.append(T T T "map address=00-1f:6000-6fff\n");
markup.append(T T T "map address=80-9f:6000-6fff\n");
markup.append(T T "sr\n");
markup.append(T T T "map address=00-1f:7000-7fff\n");
markup.append(T T T "map address=80-9f:7000-7fff\n");
}
xml.append(" </necdsp>\n");
}
if(has_dsp2) {
xml.append(" <necdsp model='uPD7725' frequency='8000000' firmware='dsp2.bin' sha256='5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1'>\n");
xml.append(" <dr>\n");
xml.append(" <map address='20-3f:8000-bfff'/>\n");
xml.append(" <map address='a0-bf:8000-bfff'/>\n");
xml.append(" </dr>\n");
xml.append(" <sr>\n");
xml.append(" <map address='20-3f:c000-ffff'/>\n");
xml.append(" <map address='a0-bf:c000-ffff'/>\n");
xml.append(" </sr>\n");
xml.append(" </necdsp>\n");
markup.append(T "necdsp model=uPD7725 frequency=8000000 firmware=dsp2.bin sha256=5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1\n");
markup.append(T T "dr\n");
markup.append(T T T "map address=20-3f:8000-bfff\n");
markup.append(T T T "map address=a0-bf:8000-bfff\n");
markup.append(T T "sr\n");
markup.append(T T T "map address=20-3f:c000-ffff\n");
markup.append(T T T "map address=a0-bf:c000-ffff\n");
}
if(has_dsp3) {
xml.append(" <necdsp model='uPD7725' frequency='8000000' firmware='dsp3.bin' sha256='2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90'>\n");
xml.append(" <dr>\n");
xml.append(" <map address='20-3f:8000-bfff'/>\n");
xml.append(" <map address='a0-bf:8000-bfff'/>\n");
xml.append(" </dr>\n");
xml.append(" <sr>\n");
xml.append(" <map address='20-3f:c000-ffff'/>\n");
xml.append(" <map address='a0-bf:c000-ffff'/>\n");
xml.append(" </sr>\n");
xml.append(" </necdsp>\n");
markup.append(T "necdsp model=uPD7725 frequency=8000000 firmware=dsp3.bin sha256=2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90\n");
markup.append(T T "dr\n");
markup.append(T T T "map address=20-3f:8000-bfff\n");
markup.append(T T T "map address=a0-bf:8000-bfff\n");
markup.append(T T "sr\n");
markup.append(T T T "map address=20-3f:c000-ffff\n");
markup.append(T T T "map address=a0-bf:c000-ffff\n");
}
if(has_dsp4) {
xml.append(" <necdsp model='uPD7725' frequency='8000000' firmware='dsp4.bin' sha256='63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a'>\n");
xml.append(" <dr>\n");
xml.append(" <map address='30-3f:8000-bfff'/>\n");
xml.append(" <map address='b0-bf:8000-bfff'/>\n");
xml.append(" </dr>\n");
xml.append(" <sr>\n");
xml.append(" <map address='30-3f:c000-ffff'/>\n");
xml.append(" <map address='b0-bf:c000-ffff'/>\n");
xml.append(" </sr>\n");
xml.append(" </necdsp>\n");
markup.append(T "necdsp model=uPD7725 frequency=8000000 firmware=dsp4.bin sha256=63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a\n");
markup.append(T T "dr\n");
markup.append(T T T "map address=30-3f:8000-bfff\n");
markup.append(T T T "map address=b0-bf:8000-bfff\n");
markup.append(T T "sr\n");
markup.append(T T T "map address=30-3f:c000-ffff\n");
markup.append(T T T "map address=b0-bf:c000-ffff\n");
}
if(has_obc1) {
xml.append(" <obc1>\n");
xml.append(" <map address='00-3f:6000-7fff'/>\n");
xml.append(" <map address='80-bf:6000-7fff'/>\n");
xml.append(" </obc1>\n");
markup.append(T "obc1\n");
markup.append(T T "map address=00-3f:6000-7fff\n");
markup.append(T T "map address=80-bf:6000-7fff\n");
}
if(has_st010) {
xml.append(" <necdsp model='uPD96050' frequency='10000000' firmware='st0010.bin' sha256='55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e'>\n");
xml.append(" <dr>\n");
xml.append(" <map address='60:0000'/>\n");
xml.append(" <map address='e0:0000'/>\n");
xml.append(" </dr>\n");
xml.append(" <sr>\n");
xml.append(" <map address='60:0001'/>\n");
xml.append(" <map address='e0:0001'/>\n");
xml.append(" </sr>\n");
xml.append(" <dp>\n");
xml.append(" <map address='68-6f:0000-0fff'/>\n");
xml.append(" <map address='e8-ef:0000-0fff'/>\n");
xml.append(" </dp>\n");
xml.append(" </necdsp>\n");
markup.append(T "necdsp model=uPD96050 frequency=10000000 firmware=st0010.bin sha256=55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e\n");
markup.append(T T "dr\n");
markup.append(T T T "map address=60:0000\n");
markup.append(T T T "map address=e0:0000\n");
markup.append(T T "sr\n");
markup.append(T T T "map address=60:0001\n");
markup.append(T T T "map address=e0:0001\n");
markup.append(T T "dp\n");
markup.append(T T T "map address=68-6f:0000-0fff\n");
markup.append(T T T "map address=e8-ef:0000-0fff\n");
}
if(has_st011) {
xml.append(" <necdsp model='uPD96050' frequency='15000000' firmware='st0011.bin' sha256='651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e'>\n");
xml.append(" <dr>\n");
xml.append(" <map address='60:0000'/>\n");
xml.append(" <map address='e0:0000'/>\n");
xml.append(" </dr>\n");
xml.append(" <sr>\n");
xml.append(" <map address='60:0001'/>\n");
xml.append(" <map address='e0:0001'/>\n");
xml.append(" </sr>\n");
xml.append(" <dp>\n");
xml.append(" <map address='68-6f:0000-0fff'/>\n");
xml.append(" <map address='e8-ef:0000-0fff'/>\n");
xml.append(" </dp>\n");
xml.append(" </necdsp>\n");
markup.append(T "necdsp model=uPD96050 frequency=15000000 firmware=st0011.bin sha256=651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e\n");
markup.append(T T "dr\n");
markup.append(T T T "map address=60:0000\n");
markup.append(T T T "map address=e0:0000\n");
markup.append(T T "sr\n");
markup.append(T T T "map address=60:0001\n");
markup.append(T T T "map address=e0:0001\n");
markup.append(T T "dp\n");
markup.append(T T T "map address=68-6f:0000-0fff\n");
markup.append(T T T "map address=e8-ef:0000-0fff\n");
}
if(has_st018) {
xml.append(" <setarisc firmware='ST-0018'>\n");
xml.append(" <map address='00-3f:3800-38ff'/>\n");
xml.append(" <map address='80-bf:3800-38ff'/>\n");
xml.append(" </setarisc>\n");
markup.append(T "setarisc firmware=ST-0018\n");
markup.append(T T "map address=00-3f:3800-38ff\n");
markup.append(T T "map address=80-bf:3800-38ff\n");
}
xml.append("</cartridge>\n");
xmlMemoryMap = xml.transform("'", "\"");
}
void SNESCartridge::read_header(const uint8_t *data, unsigned size) {
#undef T
void SnesCartridge::read_header(const uint8_t *data, unsigned size) {
type = TypeUnknown;
mapper = LoROM;
dsp1_mapper = DSP1Unmapped;
@ -762,7 +672,7 @@ void SNESCartridge::read_header(const uint8_t *data, unsigned size) {
}
}
unsigned SNESCartridge::find_header(const uint8_t *data, unsigned size) {
unsigned SnesCartridge::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);
@ -777,7 +687,7 @@ unsigned SNESCartridge::find_header(const uint8_t *data, unsigned size) {
}
}
unsigned SNESCartridge::score_header(const uint8_t *data, unsigned size, unsigned addr) {
unsigned SnesCartridge::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;
@ -858,7 +768,7 @@ unsigned SNESCartridge::score_header(const uint8_t *data, unsigned size, unsigne
return score;
}
unsigned SNESCartridge::gameboy_ram_size(const uint8_t *data, unsigned size) {
unsigned SnesCartridge::gameboy_ram_size(const uint8_t *data, unsigned size) {
if(size < 512) return 0;
switch(data[0x0149]) {
case 0x00: return 0 * 1024;
@ -871,7 +781,7 @@ unsigned SNESCartridge::gameboy_ram_size(const uint8_t *data, unsigned size) {
}
}
bool SNESCartridge::gameboy_has_rtc(const uint8_t *data, unsigned size) {
bool SnesCartridge::gameboy_has_rtc(const uint8_t *data, unsigned size) {
if(size < 512) return false;
if(data[0x0147] == 0x0f ||data[0x0147] == 0x10) return true;
return false;

View File

@ -1,124 +1,97 @@
#ifdef NALL_STRING_INTERNAL_HPP
//BML v1.0 parser
//revision 0.03
//revision 0.05
namespace nall {
namespace BML {
inline static string encode(const char *s) {
inline static string indent(const char *s, unsigned depth) {
array<char> output;
while(*s) {
char c = *s++;
(c == '\n') ? output.append("{lf}", 4) :
(c == '{') ? output.append("{lb}", 4) :
(c == '}') ? output.append("{rb}", 4) :
output.append(c);
}
output.append(0);
do {
for(unsigned n = 0; n < depth; n++) output.append('\t');
do output.append(*s); while(*s && *s++ != '\n');
} while(*s);
return output.get();
}
struct Node {
cstring name;
cstring value;
signed depth;
private:
linear_vector<Node> children;
inline bool valid(char p) const {
if(p >= 'A' && p <= 'Z') return true;
if(p >= 'a' && p <= 'z') return true;
if(p >= '0' && p <= '9') return true;
if(p == '-' || p == '.') return true;
return false;
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) {
inline unsigned parseDepth(char *&p) {
while(*p == '\n' || *p == '#') {
while(*p != '\n') *p++ = 0;
*p++ = 0; //'\n'
}
unsigned depth = 0;
while(*p == '\t') depth++, p++;
while(p[depth] == '\t') depth++;
return depth;
}
inline void parseName(char *&p) {
if(valid(*p)) {
name = p;
while(valid(*p)) p++;
}
if(valid(*p) == false) throw "Missing node name";
name = p;
while(valid(*p)) p++;
}
inline void parseValue(char *&p) {
*p++ = 0; //'{'
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(*p) {
if(*p == '\n') throw "Unclosed node value";
if(*p == '}') break;
if(*p == '{') {
if(*(p + 1) == 'l' && *(p + 2) == 'b' && *(p + 3) == '}') *w++ = '{', p += 4;
else if(*(p + 1) == 'r' && *(p + 2) == 'b' && *(p + 3) == '}') *w++ = '}', p += 4;
else if(*(p + 1) == 'l' && *(p + 2) == 'f' && *(p + 3) == '}') *w++ = '\n', p += 4;
else throw "Unrecognized escape sequence";
continue;
}
*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;
}
if(*p != '}') throw "Unclosed node value";
*w = *p++ = 0; //'}'
*(w - 1) = 0; //'\n'
}
inline void parseLine(char *&p) {
depth = parseDepth(p);
unsigned depth = parseDepth(p);
while(*p == '\t') p++;
parseName(p);
bool multiLine = false;
if(*p == ':') {
multiLine = true;
*p++ = 0;
} else if(*p == '{') {
parseValue(p);
if(*p != ' ' && *p != '\n') throw "Invalid character after first node value";
}
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 == '{') node.parseValue(p);
if(*p != ' ' && *p != '\n') throw "Invalid character after node";
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(*p == 0) throw "Missing line feed";
while(*p == '\n') *p++ = 0;
if(multiLine) return parseBlock(p, depth);
if(multiLine == false) {
while(parseDepth(p) > depth) {
Node node;
node.parseLine(p);
children.append(node);
}
} else {
value = p;
char *w = p;
while(parseDepth(p) > depth) {
p += depth + 1;
while(*p && *p != '\n') *w++ = *p++;
if(*p != '\n') throw "Multi-line value missing line feed";
*w++ = *p++;
}
*(w - 1) = 0;
if(value == p) value = p - 1; //no text data copied, point it back at null data
*(p - 1) = 0;
while(parseDepth(p) > depth) {
Node node;
node.parseLine(p);
children.append(node);
}
}
inline void parse(char *&p) {
while(*p) {
while(*p == '\n') *p++ = 0;
Node node;
node.parseLine(p);
children.append(node);
@ -135,41 +108,41 @@ public:
return node;
}
inline bool exists() const {
return name;
}
inline bool load(const char *document) {
if(document == nullptr) return false;
char *p = strdup(document);
name = nullptr;
value = p;
try {
parse(p);
} catch(const char *error) {
free((void*)(const char*)value);
children.reset();
return false;
}
depth = -1;
return true;
}
inline void constructor() {
depth = 0;
name = "";
value = "";
}
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;
};
inline Node() { constructor(); }
inline Node(const char *document) { constructor(); load(document); }
inline ~Node() { if(depth == -1) free((void*)(const char*)value); }
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;
};
}

View File

@ -102,7 +102,7 @@ Board::~Board() {
}
Board* Board::load(const string &markup, const uint8_t *data, unsigned size) {
BML::Node document(markup);
BML::Document document(markup);
auto &board = document["cartridge"]["board"];
string type = board["type"].value;

View File

@ -20,65 +20,65 @@ static string iNES(const uint8_t *data, unsigned size) {
switch(mapper) {
default:
output.append("\tboard type{NES-NROM-256}\n");
output.append("\t\tmirror{", mirror == 0 ? "horizontal" : "vertical", "}\n");
output.append("\tboard type:NES-NROM-256\n");
output.append("\t\tmirror:", mirror == 0 ? "horizontal" : "vertical", "\n");
break;
case 1:
output.append("\tboard type{NES-SXROM}\n");
output.append("\t\tchip type{MMC1B2}\n");
output.append("\tboard type:NES-SXROM\n");
output.append("\t\tchip type:MMC1B2\n");
prgram = 8192;
break;
case 2:
output.append("\tboard type{NES-UOROM}\n");
output.append("\t\tmirror{", mirror == 0 ? "horizontal" : "vertical", "}\n");
output.append("\tboard type:NES-UOROM\n");
output.append("\t\tmirror:", mirror == 0 ? "horizontal" : "vertical", "\n");
break;
case 3:
output.append("\tboard type{NES-CNROM}\n");
output.append("\t\tmirror{", mirror == 0 ? "horizontal" : "vertical", "}\n");
output.append("\tboard type:NES-CNROM\n");
output.append("\t\tmirror:", mirror == 0 ? "horizontal" : "vertical", "\n");
break;
case 4:
output.append("\tboard type{NES-TLROM}\n");
output.append("\t\tchip type{MMC3B}\n");
output.append("\tboard type:NES-TLROM\n");
output.append("\t\tchip type:MMC3B\n");
prgram = 8192;
break;
case 7:
output.append("\tboard type{NES-AOROM}\n");
output.append("\tboard type:NES-AOROM\n");
break;
case 16:
output.append("\tboard type{BANDAI-FCG}\n");
output.append("\t\tchip type{LZ93D50}\n");
output.append("\tboard type:BANDAI-FCG\n");
output.append("\t\tchip type:LZ93D50\n");
break;
case 24:
output.append("\tboard type{KONAMI-VRC-6}\n");
output.append("\t\tchip type{VRC6}\n");
output.append("\tboard type:KONAMI-VRC-6\n");
output.append("\t\tchip type:VRC6\n");
break;
case 26:
output.append("\tboard type{KONAMI-VRC-6}\n");
output.append("\t\tchip type{VRC6}\n");
output.append("\tboard type:KONAMI-VRC-6\n");
output.append("\t\tchip type:VRC6\n");
prgram = 8192;
break;
case 34:
output.append("\tboard type{NES-BNROM}\n");
output.append("\t\tmirror{", mirror == 0 ? "horizontal" : "vertical", "}\n");
output.append("\tboard type:NES-BNROM\n");
output.append("\t\tmirror:", mirror == 0 ? "horizontal" : "vertical", "\n");
break;
case 66:
output.append("\tboard type{NES-GNROM}\n");
output.append("\t\tmirror{", mirror == 0 ? "horizontal" : "vertical", "}\n");
output.append("\tboard type:NES-GNROM\n");
output.append("\t\tmirror:", mirror == 0 ? "horizontal" : "vertical", "\n");
break;
}
output.append("\t\tprg rom{", prgrom, "} ram{", prgram, "}\n");
output.append("\t\tchr rom{", chrrom, "} ram{", chrram, "}\n");
output.append("\t\tprg rom=", prgrom, " ram=", prgram, "\n");
output.append("\t\tchr rom=", chrrom, " ram=", chrram, "\n");
print(output, "\n");

View File

@ -24,7 +24,7 @@ public:
LPDIRECT3DTEXTURE9 texture;
LPDIRECT3DSURFACE9 surface;
LPD3DXEFFECT effect;
string shader_source_xml;
string shader_source_markup;
bool lost;
unsigned iwidth, iheight;
@ -268,7 +268,7 @@ public:
//failure to do so causes scaling issues on some video drivers.
if(state.width != rd.right || state.height != rd.bottom) {
init();
set_shader(shader_source_xml);
set_shader(shader_source_markup);
return;
}
@ -336,26 +336,14 @@ public:
}
if(!source || !*source) {
shader_source_xml = "";
shader_source_markup = "";
return;
}
shader_source_xml = source;
shader_source_markup = source;
bool is_hlsl = false;
string shader_source;
xml_element document = xml_parse(shader_source_xml);
for(auto &head : document.element) {
if(head.name == "shader") {
for(auto &attribute : head.attribute) {
if(attribute.name == "language" && attribute.content == "HLSL") is_hlsl = true;
}
for(auto &element : head.element) {
if(element.name == "source") {
if(is_hlsl) shader_source = element.parse();
}
}
}
}
BML::Document document(shader_source_markup);
bool is_hlsl = document["shader"]["language"].value == "HLSL";
string shader_source = document["shader"].value;
if(shader_source == "") return;
HMODULE d3dx;

View File

@ -136,29 +136,11 @@ public:
}
if(source) {
bool is_glsl = false;
fragmentfilter = 0;
string fragment_source;
string vertex_source;
xml_element document = xml_parse(source);
for(auto &head : document.element) {
if(head.name == "shader") {
for(auto &attribute : head.attribute) {
if(attribute.name == "language" && attribute.content == "GLSL") is_glsl = true;
}
for(auto &element : head.element) {
if(element.name == "fragment") {
for(auto &attribute : element.attribute) {
if(attribute.name == "filter") fragmentfilter = attribute.content == "linear" ? 1 : 0;
}
fragment_source = element.parse();
} else if(element.name == "vertex") {
vertex_source = element.parse();
}
}
}
}
BML::Document document(source);
bool is_glsl = document["shader"]["language"].value == "GLSL";
fragmentfilter = document["shader"]["fragment"]["filter"].value == "linear" ? 1 : 0;
string fragment_source = document["shader"]["fragment"].value;
string vertex_source = document["shader"]["vertex"].value;
if(is_glsl) {
if(fragment_source != "") set_fragment_shader(fragment_source);

View File

@ -6,12 +6,12 @@
#define CARTRIDGE_CPP
namespace SNES {
#include "xml.cpp"
#include "markup.cpp"
#include "serialization.cpp"
Cartridge cartridge;
void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
void Cartridge::load(Mode cartridge_mode, const char *markup) {
mode = cartridge_mode;
region = Region::NTSC;
ram_size = 0;
@ -33,8 +33,8 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
nvram.reset();
parse_xml(xml_list);
//print(xml_list[0], "\n\n");
parse_markup(markup);
print(markup, "\n\n");
if(ram_size > 0) {
ram.map(allocate<uint8>(ram_size, 0xff), ram_size);

View File

@ -82,7 +82,7 @@ struct Cartridge : property<Cartridge> {
} nss;
} information;
void load(Mode, const lstring&);
void load(Mode, const char*);
void unload();
void serialize(serializer&);
@ -90,35 +90,27 @@ struct Cartridge : property<Cartridge> {
~Cartridge();
private:
void parse_xml(const lstring&);
void parse_xml_cartridge(const char*);
void parse_xml_bsx(const char*);
void parse_xml_sufami_turbo(const char*, bool);
void parse_xml_gameboy(const char*);
void parse_markup(const char*);
unsigned parse_markup_integer(cstring&);
void parse_markup_map(Mapping&, BML::Node&);
void xml_parse_rom(xml_element&);
void xml_parse_ram(xml_element&);
void xml_parse_nss(xml_element&);
void xml_parse_icd2(xml_element&);
void xml_parse_superfx(xml_element&);
void xml_parse_sa1(xml_element&);
void xml_parse_necdsp(xml_element&);
void xml_parse_hitachidsp(xml_element&);
void xml_parse_bsx(xml_element&);
void xml_parse_sufamiturbo(xml_element&);
void xml_parse_supergameboy(xml_element&);
void xml_parse_srtc(xml_element&);
void xml_parse_sdd1(xml_element&);
void xml_parse_spc7110(xml_element&);
void xml_parse_obc1(xml_element&);
void xml_parse_setarisc(xml_element&);
void xml_parse_msu1(xml_element&);
void xml_parse_link(xml_element&);
unsigned xml_parse_hex(const string&);
unsigned xml_parse_unsigned(const string&);
void xml_parse_address(Mapping&, const string&);
void xml_parse_mode(Mapping&, const string&);
void parse_markup_rom(BML::Node&);
void parse_markup_ram(BML::Node&);
void parse_markup_nss(BML::Node&);
void parse_markup_icd2(BML::Node&);
void parse_markup_superfx(BML::Node&);
void parse_markup_sa1(BML::Node&);
void parse_markup_necdsp(BML::Node&);
void parse_markup_hitachidsp(BML::Node&);
void parse_markup_bsx(BML::Node&);
void parse_markup_sufamiturbo(BML::Node&);
void parse_markup_srtc(BML::Node&);
void parse_markup_sdd1(BML::Node&);
void parse_markup_spc7110(BML::Node&);
void parse_markup_obc1(BML::Node&);
void parse_markup_setarisc(BML::Node&);
void parse_markup_msu1(BML::Node&);
void parse_markup_link(BML::Node&);
};
extern Cartridge cartridge;

557
bsnes/snes/cartridge/markup.cpp Executable file
View File

@ -0,0 +1,557 @@
#ifdef CARTRIDGE_CPP
void Cartridge::parse_markup(const char *markup) {
mapping.reset();
information.nss.setting.reset();
BML::Document document(markup);
auto &cartridge = document["cartridge"];
region = cartridge["region"].value != "PAL" ? Region::NTSC : Region::PAL;
parse_markup_rom(cartridge["rom"]);
parse_markup_ram(cartridge["ram"]);
parse_markup_nss(cartridge["nss"]);
parse_markup_icd2(cartridge["icd2"]);
parse_markup_sa1(cartridge["sa1"]);
parse_markup_superfx(cartridge["superfx"]);
parse_markup_necdsp(cartridge["necdsp"]);
parse_markup_hitachidsp(cartridge["hitachidsp"]);
parse_markup_bsx(cartridge["bsx"]);
parse_markup_sufamiturbo(cartridge["sufamiturbo"]);
parse_markup_srtc(cartridge["srtc"]);
parse_markup_sdd1(cartridge["sdd1"]);
parse_markup_spc7110(cartridge["spc7110"]);
parse_markup_obc1(cartridge["obc1"]);
parse_markup_setarisc(cartridge["setarisc"]);
parse_markup_msu1(cartridge["msu1"]);
parse_markup_link(cartridge["link"]);
}
//
unsigned Cartridge::parse_markup_integer(cstring &data) {
if(strbegin(data, "0x")) return hex(data);
return decimal(data);
}
void Cartridge::parse_markup_map(Mapping &m, BML::Node &map) {
m.offset = parse_markup_integer(map["offset"].value);
m.size = parse_markup_integer(map["size"].value);
string data = map["mode"].value;
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"].value);
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]);
}
}
//
void Cartridge::parse_markup_rom(BML::Node &root) {
if(root.exists() == false) return;
for(auto &node : root) {
if(node.name != "map") continue;
Mapping m(rom);
parse_markup_map(m, node);
if(m.size == 0) m.size = rom.size();
mapping.append(m);
}
}
void Cartridge::parse_markup_ram(BML::Node &root) {
if(root.exists() == false) return;
ram_size = parse_markup_integer(root["size"].value);
for(auto &node : root) {
Mapping m(ram);
parse_markup_map(m, node);
if(m.size == 0) m.size = ram_size;
mapping.append(m);
}
}
void Cartridge::parse_markup_nss(BML::Node &root) {
if(root.exists() == false) return;
has_nss_dip = true;
for(auto &node : root) {
if(node.name != "setting") continue;
unsigned number = information.nss.setting.size();
if(number >= 16) break; //more than 16 DIP switches is not physically possible
information.nss.option[number].reset();
information.nss.setting[number] = node["name"].value;
for(auto &leaf : node) {
if(leaf.name != "option") continue;
string name = leaf["name"].value;
unsigned value = parse_markup_integer(leaf["value"].value);
information.nss.option[number].append({ hex<4>(value), ":", name });
}
}
}
void Cartridge::parse_markup_icd2(BML::Node &root) {
if(root.exists() == false) return;
if(mode != Mode::SuperGameBoy) return;
icd2.revision = max(1, parse_markup_integer(root["revision"].value));
for(auto &node : root) {
if(node.name != "map") continue;
Mapping m({ &ICD2::read, &icd2 }, { &ICD2::write, &icd2 });
parse_markup_map(m, node);
mapping.append(m);
}
}
void Cartridge::parse_markup_superfx(BML::Node &root) {
if(root.exists() == false) return;
has_superfx = true;
for(auto &node : root) {
if(node.name == "rom") {
for(auto &leaf : node) {
if(leaf.name != "map") continue;
Mapping m(superfx.rom);
parse_markup_map(m, leaf);
mapping.append(m);
}
}
if(node.name == "ram") {
for(auto &leaf : node) {
if(leaf.name == "size") {
ram_size = parse_markup_integer(leaf.value);
continue;
}
if(leaf.name != "map") continue;
Mapping m(superfx.ram);
parse_markup_map(m, leaf);
if(m.size == 0) m.size = ram_size;
mapping.append(m);
}
}
if(node.name == "mmio") {
for(auto &leaf : node) {
if(leaf.name != "map") continue;
Mapping m({ &SuperFX::mmio_read, &superfx }, { &SuperFX::mmio_write, &superfx });
parse_markup_map(m, leaf);
mapping.append(m);
}
}
}
}
void Cartridge::parse_markup_sa1(BML::Node &root) {
if(root.exists() == false) return;
has_sa1 = true;
auto &mcurom = root["mcu"]["rom"];
auto &mcuram = root["mcu"]["ram"];
auto &iram = root["iram"];
auto &bwram = root["bwram"];
auto &mmio = root["mmio"];
for(auto &node : mcurom) {
if(node.name != "map") continue;
Mapping m({ &SA1::mmc_read, &sa1 }, { &SA1::mmc_write, &sa1 });
parse_markup_map(m, node);
mapping.append(m);
}
for(auto &node : mcuram) {
if(node.name != "map") continue;
Mapping m({ &SA1::mmc_cpu_read, &sa1 }, { &SA1::mmc_cpu_write, &sa1 });
parse_markup_map(m, node);
mapping.append(m);
}
for(auto &node : iram) {
if(node.name != "map") continue;
Mapping m(sa1.cpuiram);
parse_markup_map(m, node);
if(m.size == 0) m.size = 2048;
mapping.append(m);
}
ram_size = parse_markup_integer(bwram["size"].value);
for(auto &node : bwram) {
if(node.name != "map") continue;
Mapping m(sa1.cpubwram);
parse_markup_map(m, node);
if(m.size == 0) m.size = ram_size;
mapping.append(m);
}
for(auto &node : mmio) {
if(node.name != "map") continue;
Mapping m({ &SA1::mmio_read, &sa1 }, { &SA1::mmio_write, &sa1 });
parse_markup_map(m, node);
mapping.append(m);
}
}
void Cartridge::parse_markup_necdsp(BML::Node &root) {
if(root.exists() == false) return;
has_necdsp = true;
for(unsigned n = 0; n < 16384; n++) necdsp.programROM[n] = 0x000000;
for(unsigned n = 0; n < 2048; n++) necdsp.dataROM[n] = 0x0000;
necdsp.frequency = parse_markup_integer(root["frequency"].value);
if(necdsp.frequency == 0) necdsp.frequency = 8000000;
necdsp.revision
= root["model"].value == "uPD7725" ? NECDSP::Revision::uPD7725
: root["model"].value == "uPD96050" ? NECDSP::Revision::uPD96050
: NECDSP::Revision::uPD7725;
string firmware = root["firmware"].value;
string sha256 = root["sha256"].value;
string path = { dir(interface->path(Slot::Base, ".dsp")), firmware };
unsigned promsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 2048 : 16384);
unsigned dromsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 1024 : 2048);
unsigned filesize = promsize * 3 + dromsize * 2;
file fp;
if(fp.open(path, file::mode::read) == false) {
interface->message({ "Warning: NEC DSP firmware ", firmware, " is missing." });
} else if(fp.size() != filesize) {
interface->message({ "Warning: NEC DSP firmware ", firmware, " is of the wrong file size." });
fp.close();
} else {
for(unsigned n = 0; n < promsize; n++) necdsp.programROM[n] = fp.readm(3);
for(unsigned n = 0; n < dromsize; n++) necdsp.dataROM[n] = fp.readm(2);
if(sha256 != "") {
//XML file specified SHA256 sum for program. Verify file matches the hash.
fp.seek(0);
uint8_t data[filesize];
fp.read(data, filesize);
if(sha256 != nall::sha256(data, filesize)) {
interface->message({ "Warning: NEC DSP firmware ", firmware, " SHA256 sum is incorrect." });
}
}
fp.close();
}
for(auto &node : root) {
if(node.name == "dr") {
for(auto &leaf : node) {
Mapping m({ &NECDSP::dr_read, &necdsp }, { &NECDSP::dr_write, &necdsp });
parse_markup_map(m, leaf);
mapping.append(m);
}
}
if(node.name == "sr") {
for(auto &leaf : node) {
Mapping m({ &NECDSP::sr_read, &necdsp }, { &NECDSP::sr_write, &necdsp });
parse_markup_map(m, leaf);
mapping.append(m);
}
}
if(node.name == "dp") {
for(auto &leaf : node) {
Mapping m({ &NECDSP::dp_read, &necdsp }, { &NECDSP::dp_write, &necdsp });
parse_markup_map(m, leaf);
mapping.append(m);
}
}
}
}
void Cartridge::parse_markup_hitachidsp(BML::Node &root) {
if(root.exists() == false) return;
has_hitachidsp = true;
for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = 0x000000;
hitachidsp.frequency = parse_markup_integer(root["frequency"].value);
if(hitachidsp.frequency == 0) hitachidsp.frequency = 20000000;
string firmware = root["firmware"].value;
string sha256 = root["sha256"].value;
string path = { dir(interface->path(Slot::Base, ".dsp")), firmware };
file fp;
if(fp.open(path, file::mode::read) == false) {
interface->message({ "Warning: Hitachi DSP firmware ", firmware, " is missing." });
} else if(fp.size() != 1024 * 3) {
interface->message({ "Warning: Hitachi DSP firmware ", firmware, " is of the wrong file size." });
fp.close();
} else {
for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = fp.readl(3);
if(sha256 != "") {
//XML file specified SHA256 sum for program. Verify file matches the hash.
fp.seek(0);
uint8 data[3072];
fp.read(data, 3072);
if(sha256 != nall::sha256(data, 3072)) {
interface->message({ "Warning: Hitachi DSP firmware ", firmware, " SHA256 sum is incorrect." });
}
}
fp.close();
}
for(auto &node : root) {
if(node.name == "rom") {
for(auto &leaf : node) {
if(leaf.name != "map") continue;
Mapping m({ &HitachiDSP::rom_read, &hitachidsp }, { &HitachiDSP::rom_write, &hitachidsp });
parse_markup_map(m, leaf);
mapping.append(m);
}
}
if(node.name == "mmio") {
for(auto &leaf : node) {
Mapping m({ &HitachiDSP::dsp_read, &hitachidsp }, { &HitachiDSP::dsp_write, &hitachidsp });
parse_markup_map(m, leaf);
mapping.append(m);
}
}
}
}
void Cartridge::parse_markup_bsx(BML::Node &root) {
if(root.exists() == false) return;
if(mode != Mode::BsxSlotted && mode != Mode::Bsx) return;
for(auto &node : root["slot"]) {
if(node.name != "map") continue;
Mapping m(bsxflash.memory);
parse_markup_map(m, node);
mapping.append(m);
}
for(auto &node : root["mmio"]) {
if(node.name != "map") continue;
Mapping m({ &BSXCartridge::mmio_read, &bsxcartridge }, { &BSXCartridge::mmio_write, &bsxcartridge });
parse_markup_map(m, node);
mapping.append(m);
}
for(auto &node : root["mcu"]) {
if(node.name != "map") continue;
Mapping m({ &BSXCartridge::mcu_read, &bsxcartridge }, { &BSXCartridge::mcu_write, &bsxcartridge });
parse_markup_map(m, node);
mapping.append(m);
}
}
void Cartridge::parse_markup_sufamiturbo(BML::Node &root) {
if(root.exists() == false) return;
if(mode != Mode::SufamiTurbo) return;
for(auto &slot : root) {
if(slot.name != "slot") continue;
bool slotid = slot["id"].value == "A" ? 0 : slot["id"].value == "B" ? 1 : 0;
for(auto &node : slot) {
if(node.name == "rom") {
for(auto &leaf : node) {
if(leaf.name != "map") continue;
Memory &memory = slotid == 0 ? sufamiturbo.slotA.rom : sufamiturbo.slotB.rom;
Mapping m(memory);
parse_markup_map(m, leaf);
if(m.size == 0) m.size = memory.size();
if(m.size) mapping.append(m);
}
}
if(node.name == "ram") {
unsigned ram_size = parse_markup_integer(node["size"].value);
for(auto &leaf : node) {
if(leaf.name != "map") continue;
Memory &memory = slotid == 0 ? sufamiturbo.slotA.ram : sufamiturbo.slotB.ram;
Mapping m(memory);
parse_markup_map(m, leaf);
if(m.size == 0) m.size = ram_size;
if(m.size) mapping.append(m);
}
}
}
}
}
void Cartridge::parse_markup_srtc(BML::Node &root) {
if(root.exists() == false) return;
has_srtc = true;
for(auto &node : root) {
if(node.name != "map") continue;
Mapping m({ &SRTC::read, &srtc }, { &SRTC::write, &srtc });
parse_markup_map(m, node);
mapping.append(m);
}
}
void Cartridge::parse_markup_sdd1(BML::Node &root) {
if(root.exists() == false) return;
has_sdd1 = true;
for(auto &node : root["mmio"]) {
if(node.name != "map") continue;
Mapping m({ &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
parse_markup_map(m, node);
mapping.append(m);
}
for(auto &node : root["mcu"]) {
if(node.name != "map") continue;
Mapping m({ &SDD1::mcu_read, &sdd1 }, { &SDD1::mcu_write, &sdd1 });
parse_markup_map(m, node);
mapping.append(m);
}
}
void Cartridge::parse_markup_spc7110(BML::Node &root) {
if(root.exists() == false) return;
has_spc7110 = true;
auto &ram = root["ram"];
auto &mmio = root["mmio"];
auto &mcu = root["mcu"];
auto &dcu = root["dcu"];
auto &rtc = root["rtc"];
ram_size = parse_markup_integer(ram["size"].value);
for(auto &node : ram) {
if(node.name != "map") continue;
Mapping m({ &SPC7110::ram_read, &spc7110 }, { &SPC7110::ram_write, &spc7110 });
parse_markup_map(m, node);
mapping.append(m);
}
for(auto &node : mmio) {
if(node.name != "map") continue;
Mapping m({ &SPC7110::mmio_read, &spc7110 }, { &SPC7110::mmio_write, &spc7110 });
parse_markup_map(m, node);
mapping.append(m);
}
spc7110.data_rom_offset = parse_markup_integer(mcu["offset"].value);
if(spc7110.data_rom_offset == 0) spc7110.data_rom_offset = 0x100000;
for(auto &node : mcu) {
if(node.name != "map") continue;
Mapping m({ &SPC7110::mcu_read, &spc7110 }, { &SPC7110::mcu_write, &spc7110 });
parse_markup_map(m, node);
mapping.append(m);
}
for(auto &node : dcu) {
if(node.name != "map") continue;
Mapping m({ &SPC7110::dcu_read, &spc7110 }, { &SPC7110::dcu_write, &spc7110 });
parse_markup_map(m, node);
mapping.append(m);
}
for(auto &node : rtc) {
if(node.name != "map") continue;
Mapping m({ &SPC7110::mmio_read, &spc7110 }, { &SPC7110::mmio_write, &spc7110 });
parse_markup_map(m, node);
mapping.append(m);
}
}
void Cartridge::parse_markup_obc1(BML::Node &root) {
if(root.exists() == false) return;
has_obc1 = true;
for(auto &node : root) {
if(node.name != "map") continue;
Mapping m({ &OBC1::read, &obc1 }, { &OBC1::write, &obc1 });
parse_markup_map(m, node);
mapping.append(m);
}
}
void Cartridge::parse_markup_setarisc(BML::Node &root) {
if(root.exists() == false) return;
has_st0018 = true;
for(auto &node : root) {
if(node.name != "map") continue;
Mapping m({ &ST0018::mmio_read, &st0018 }, { &ST0018::mmio_write, &st0018 });
parse_markup_map(m, node);
mapping.append(m);
}
}
void Cartridge::parse_markup_msu1(BML::Node &root) {
if(root.exists() == false) {
has_msu1 = file::exists(interface->path(Cartridge::Slot::Base, ".msu"));
if(has_msu1) {
Mapping m({ &MSU1::mmio_read, &msu1 }, { &MSU1::mmio_write, &msu1 });
m.banklo = 0x00, m.bankhi = 0x3f, m.addrlo = 0x2000, m.addrhi = 0x2007;
mapping.append(m);
m.banklo = 0x80, m.bankhi = 0xbf, m.addrlo = 0x2000, m.addrhi = 0x2007;
mapping.append(m);
}
return;
}
has_msu1 = true;
for(auto &node : root) {
if(node.name != "map") continue;
Mapping m({ &MSU1::mmio_read, &msu1 }, { &MSU1::mmio_write, &msu1 });
parse_markup_map(m, node);
mapping.append(m);
}
}
void Cartridge::parse_markup_link(BML::Node &root) {
if(root.exists() == false) return;
has_link = true;
link.frequency = max(1, parse_markup_integer(root["frequency"].value));
link.program = root["program"].value;
for(auto &node : root) {
if(node.name != "map") continue;
Mapping m({ &Link::read, &link }, { &Link::write, &link });
parse_markup_map(m, node);
mapping.append(m);
}
}
Cartridge::Mapping::Mapping() {
mode = Bus::MapMode::Direct;
banklo = bankhi = addrlo = addrhi = offset = size = 0;
}
Cartridge::Mapping::Mapping(Memory &memory) {
read = { &Memory::read, &memory };
write = { &Memory::write, &memory };
mode = Bus::MapMode::Direct;
banklo = bankhi = addrlo = addrhi = offset = size = 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;
}
#endif

View File

@ -1,765 +0,0 @@
#ifdef CARTRIDGE_CPP
void Cartridge::parse_xml(const lstring &list) {
mapping.reset();
parse_xml_cartridge(list[0]);
if(mode == Mode::BsxSlotted) {
parse_xml_bsx(list[1]);
} else if(mode == Mode::Bsx) {
parse_xml_bsx(list[1]);
} else if(mode == Mode::SufamiTurbo) {
parse_xml_sufami_turbo(list[1], 0);
parse_xml_sufami_turbo(list[2], 1);
} else if(mode == Mode::SuperGameBoy) {
parse_xml_gameboy(list[1]);
}
}
void Cartridge::parse_xml_cartridge(const char *data) {
//reset cartridge information
information.nss.setting.reset();
xml_element document = xml_parse(data);
if(document.element.size() == 0) return;
for(auto &head : document.element) {
if(head.name == "cartridge") {
for(auto &attr : head.attribute) {
if(attr.name == "region") {
if(attr.content == "NTSC") region = Region::NTSC;
if(attr.content == "PAL") region = Region::PAL;
}
}
for(auto &node : head.element) {
if(node.name == "rom") xml_parse_rom(node);
if(node.name == "ram") xml_parse_ram(node);
if(node.name == "nss") xml_parse_nss(node);
if(node.name == "icd2") xml_parse_icd2(node);
if(node.name == "superfx") xml_parse_superfx(node);
if(node.name == "sa1") xml_parse_sa1(node);
if(node.name == "necdsp") xml_parse_necdsp(node);
if(node.name == "hitachidsp") xml_parse_hitachidsp(node);
if(node.name == "bsx") xml_parse_bsx(node);
if(node.name == "sufamiturbo") xml_parse_sufamiturbo(node);
if(node.name == "srtc") xml_parse_srtc(node);
if(node.name == "sdd1") xml_parse_sdd1(node);
if(node.name == "spc7110") xml_parse_spc7110(node);
if(node.name == "obc1") xml_parse_obc1(node);
if(node.name == "setarisc") xml_parse_setarisc(node);
if(node.name == "msu1") xml_parse_msu1(node);
if(node.name == "link") xml_parse_link(node);
}
}
}
}
void Cartridge::parse_xml_bsx(const char *data) {
has_bsx_slot = true;
}
void Cartridge::parse_xml_sufami_turbo(const char *data, bool slot) {
}
void Cartridge::parse_xml_gameboy(const char *data) {
}
void Cartridge::xml_parse_rom(xml_element &root) {
for(auto &leaf : root.element) {
if(leaf.name == "map") {
Mapping m(rom);
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
}
if(m.size == 0) m.size = rom.size();
mapping.append(m);
}
}
}
void Cartridge::xml_parse_ram(xml_element &root) {
for(auto &attr : root.attribute) {
if(attr.name == "size") ram_size = xml_parse_hex(attr.content);
}
for(auto &leaf : root.element) {
if(leaf.name == "map") {
Mapping m(ram);
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
}
if(m.size == 0) m.size = ram_size;
mapping.append(m);
}
}
}
void Cartridge::xml_parse_nss(xml_element &root) {
has_nss_dip = true;
for(auto &node : root.element) {
if(node.name == "setting") {
unsigned number = information.nss.setting.size();
if(number >= 16) break; //more than 16 DIP switches is not possible
information.nss.option[number].reset();
for(auto &attr : node.attribute) {
if(attr.name == "name") {
information.nss.setting[number] = attr.parse();
}
}
for(auto &leaf : node.element) {
string name;
unsigned value = 0x0000;
for(auto &attr : leaf.attribute) {
if(attr.name == "name") name = attr.parse();
if(attr.name == "value") value = (uint16)xml_parse_hex(attr.content);
}
information.nss.option[number].append({ hex<4>(value), ":", name });
}
}
}
}
void Cartridge::xml_parse_icd2(xml_element &root) {
if(mode != Mode::SuperGameBoy) return;
icd2.revision = 1;
for(auto &attr : root.attribute) {
if(attr.name == "revision") {
if(attr.content == "1") icd2.revision = 1;
if(attr.content == "2") icd2.revision = 2;
}
}
for(auto &node : root.element) {
if(node.name == "map") {
Mapping m({ &ICD2::read, &icd2 }, { &ICD2::write, &icd2 });
for(auto &attr : node.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
void Cartridge::xml_parse_superfx(xml_element &root) {
has_superfx = true;
for(auto &node : root.element) {
if(node.name == "rom") {
for(auto &leaf : node.element) {
if(leaf.name == "map") {
Mapping m(superfx.rom);
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
}
mapping.append(m);
}
}
} else if(node.name == "ram") {
for(auto &attr : node.attribute) {
if(attr.name == "size") ram_size = xml_parse_hex(attr.content);
}
for(auto &leaf : node.element) {
if(leaf.name == "map") {
Mapping m(superfx.ram);
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
}
if(m.size == 0) m.size = ram_size;
mapping.append(m);
}
}
} else if(node.name == "mmio") {
for(auto &leaf : node.element) {
if(leaf.name == "map") {
Mapping m({ &SuperFX::mmio_read, &superfx }, { &SuperFX::mmio_write, &superfx });
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
}
}
void Cartridge::xml_parse_sa1(xml_element &root) {
has_sa1 = true;
for(auto &node : root.element) {
if(node.name == "mcu") {
for(auto &subnode : node.element) {
if(subnode.name == "rom") {
for(auto &leaf : subnode.element) {
if(leaf.name == "map") {
Mapping m({ &SA1::mmc_read, &sa1 }, { &SA1::mmc_write, &sa1 });
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
}
mapping.append(m);
}
}
} else if(subnode.name == "ram") {
for(auto &leaf : subnode.element) {
if(leaf.name == "map") {
Mapping m({ &SA1::mmc_cpu_read, &sa1 }, { &SA1::mmc_cpu_write, &sa1 });
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
}
} else if(node.name == "iram") {
for(auto &leaf : node.element) {
if(leaf.name == "map") {
Mapping m(sa1.cpuiram);
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
}
if(m.size == 0) m.size = 2048;
mapping.append(m);
}
}
} else if(node.name == "bwram") {
for(auto &attr : node.attribute) {
if(attr.name == "size") ram_size = xml_parse_hex(attr.content);
}
for(auto &leaf : node.element) {
if(leaf.name == "map") {
Mapping m(sa1.cpubwram);
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
}
if(m.size == 0) m.size = ram_size;
mapping.append(m);
}
}
} else if(node.name == "mmio") {
for(auto &leaf : node.element) {
if(leaf.name == "map") {
Mapping m({ &SA1::mmio_read, &sa1 }, { &SA1::mmio_write, &sa1 });
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
}
}
void Cartridge::xml_parse_necdsp(xml_element &root) {
has_necdsp = true;
necdsp.revision = NECDSP::Revision::uPD7725;
necdsp.frequency = 8000000;
for(unsigned n = 0; n < 16384; n++) necdsp.programROM[n] = 0x000000;
for(unsigned n = 0; n < 2048; n++) necdsp.dataROM[n] = 0x0000;
string firmware, sha256;
for(auto &attr : root.attribute) {
if(attr.name == "model") {
if(attr.content == "uPD7725" ) necdsp.revision = NECDSP::Revision::uPD7725;
if(attr.content == "uPD96050") necdsp.revision = NECDSP::Revision::uPD96050;
} else if(attr.name == "frequency") {
necdsp.frequency = xml_parse_unsigned(attr.content);
} else if(attr.name == "firmware") {
firmware = attr.content;
} else if(attr.name == "sha256") {
sha256 = attr.content;
}
}
string path = { dir(interface->path(Slot::Base, ".dsp")), firmware };
unsigned promsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 2048 : 16384);
unsigned dromsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 1024 : 2048);
unsigned filesize = promsize * 3 + dromsize * 2;
file fp;
if(fp.open(path, file::mode::read) == false) {
interface->message({ "Warning: NEC DSP firmware ", firmware, " is missing." });
} else if(fp.size() != filesize) {
interface->message({ "Warning: NEC DSP firmware ", firmware, " is of the wrong file size." });
fp.close();
} else {
for(unsigned n = 0; n < promsize; n++) necdsp.programROM[n] = fp.readm(3);
for(unsigned n = 0; n < dromsize; n++) necdsp.dataROM[n] = fp.readm(2);
if(sha256 != "") {
//XML file specified SHA256 sum for program. Verify file matches the hash.
fp.seek(0);
uint8_t data[filesize];
fp.read(data, filesize);
if(sha256 != nall::sha256(data, filesize)) {
interface->message({ "Warning: Hitachi DSP firmware ", firmware, " SHA256 sum is incorrect." });
}
}
fp.close();
}
for(auto &node : root.element) {
if(node.name == "dr") {
for(auto &leaf : node.element) {
if(leaf.name == "map") {
Mapping m({ &NECDSP::dr_read, &necdsp }, { &NECDSP::dr_write, &necdsp });
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
} else if(node.name == "sr") {
for(auto &leaf : node.element) {
if(leaf.name == "map") {
Mapping m({ &NECDSP::sr_read, &necdsp }, { &NECDSP::sr_write, &necdsp });
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
} else if(node.name == "dp") {
for(auto &leaf : node.element) {
if(leaf.name == "map") {
Mapping m({ &NECDSP::dp_read, &necdsp }, { &NECDSP::dp_write, &necdsp });
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
}
}
void Cartridge::xml_parse_hitachidsp(xml_element &root) {
has_hitachidsp = true;
hitachidsp.frequency = 20000000;
for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = 0x000000;
string firmware, sha256;
for(auto &attr : root.attribute) {
if(attr.name == "frequency") {
hitachidsp.frequency = xml_parse_unsigned(attr.content);
} else if(attr.name == "firmware") {
firmware = attr.content;
} else if(attr.name == "sha256") {
sha256 = attr.content;
}
}
string path = { dir(interface->path(Slot::Base, ".dsp")), firmware };
file fp;
if(fp.open(path, file::mode::read) == false) {
interface->message({ "Warning: Hitachi DSP firmware ", firmware, " is missing." });
} else if(fp.size() != 1024 * 3) {
interface->message({ "Warning: Hitachi DSP firmware ", firmware, " is of the wrong file size." });
fp.close();
} else {
for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = fp.readl(3);
if(sha256 != "") {
//XML file specified SHA256 sum for program. Verify file matches the hash.
fp.seek(0);
uint8 data[3072];
fp.read(data, 3072);
if(sha256 != nall::sha256(data, 3072)) {
interface->message({ "Warning: Hitachi DSP firmware ", firmware, " SHA256 sum is incorrect." });
}
}
fp.close();
}
for(auto &node : root.element) {
if(node.name == "rom") {
for(auto &leaf : node.element) {
if(leaf.name == "map") {
Mapping m({ &HitachiDSP::rom_read, &hitachidsp }, { &HitachiDSP::rom_write, &hitachidsp });
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
}
mapping.append(m);
}
}
}
if(node.name == "mmio") {
for(auto &leaf : node.element) {
Mapping m({ &HitachiDSP::dsp_read, &hitachidsp }, { &HitachiDSP::dsp_write, &hitachidsp });
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
}
void Cartridge::xml_parse_bsx(xml_element &root) {
if(mode != Mode::BsxSlotted && mode != Mode::Bsx) return;
for(auto &node : root.element) {
if(node.name == "slot") {
for(auto &leaf : node.element) {
if(leaf.name == "map") {
Mapping m(bsxflash.memory);
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
}
mapping.append(m);
}
}
} else if(node.name == "mcu") {
for(auto &leaf : node.element) {
if(leaf.name == "map") {
Mapping m({ &BSXCartridge::mcu_read, &bsxcartridge }, { &BSXCartridge::mcu_write, &bsxcartridge });
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
} else if(node.name == "mmio") {
for(auto &leaf : node.element) {
if(leaf.name == "map") {
Mapping m({ &BSXCartridge::mmio_read, &bsxcartridge }, { &BSXCartridge::mmio_write, &bsxcartridge });
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
}
}
void Cartridge::xml_parse_sufamiturbo(xml_element &root) {
if(mode != Mode::SufamiTurbo) return;
for(auto &node : root.element) {
if(node.name == "slot") {
bool slotid = 0;
for(auto &attr : node.attribute) {
if(attr.name == "id") {
if(attr.content == "A") slotid = 0;
if(attr.content == "B") slotid = 1;
}
}
for(auto &slot : node.element) {
if(slot.name == "rom") {
for(auto &leaf : slot.element) {
if(leaf.name == "map") {
Memory &memory = slotid == 0 ? sufamiturbo.slotA.rom : sufamiturbo.slotB.rom;
Mapping m(memory);
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
}
if(m.size == 0) m.size = memory.size();
if(m.size) mapping.append(m);
}
}
} else if(slot.name == "ram") {
unsigned ram_size = 0;
for(auto &attr : slot.attribute) {
if(attr.name == "size") ram_size = xml_parse_hex(attr.content);
}
for(auto &leaf : slot.element) {
if(leaf.name == "map") {
Memory &memory = slotid == 0 ? sufamiturbo.slotA.ram : sufamiturbo.slotB.ram;
Mapping m(memory);
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
}
if(m.size == 0) m.size = ram_size;
if(m.size) mapping.append(m);
}
}
}
}
}
}
}
void Cartridge::xml_parse_srtc(xml_element &root) {
has_srtc = true;
for(auto &node : root.element) {
if(node.name == "map") {
Mapping m({ &SRTC::read, &srtc }, { &SRTC::write, &srtc });
for(auto &attr : node.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
void Cartridge::xml_parse_sdd1(xml_element &root) {
has_sdd1 = true;
for(auto &node : root.element) {
if(node.name == "mcu") {
for(auto &leaf : node.element) {
if(leaf.name == "map") {
Mapping m({ &SDD1::mcu_read, &sdd1 }, { &SDD1::mcu_write, &sdd1 });
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
} else if(node.name == "mmio") {
for(auto &leaf : node.element) {
if(leaf.name == "map") {
Mapping m({ &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
}
}
void Cartridge::xml_parse_spc7110(xml_element &root) {
has_spc7110 = true;
spc7110.data_rom_offset = 0x100000;
for(auto &node : root.element) {
if(node.name == "dcu") {
for(auto &leaf : node.element) {
if(leaf.name == "map") {
Mapping m({ &SPC7110::dcu_read, &spc7110 }, { &SPC7110::dcu_write, &spc7110 });
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
} else if(node.name == "mcu") {
for(auto &leaf : node.element) {
if(leaf.name == "map") {
Mapping m({ &SPC7110::mcu_read, &spc7110 }, { &SPC7110::mcu_write, &spc7110 });
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "offset") spc7110.data_rom_offset = xml_parse_hex(attr.content);
}
mapping.append(m);
}
}
} else if(node.name == "mmio") {
for(auto &leaf : node.element) {
if(leaf.name == "map") {
Mapping m({ &SPC7110::mmio_read, &spc7110 }, { &SPC7110::mmio_write, &spc7110 });
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
} else if(node.name == "ram") {
for(auto &attr : node.attribute) {
if(attr.name == "size") ram_size = xml_parse_hex(attr.content);
}
for(auto &leaf : node.element) {
if(leaf.name == "map") {
Mapping m({ &SPC7110::ram_read, &spc7110 }, { &SPC7110::ram_write, &spc7110 });
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = xml_parse_hex(attr.content);
if(attr.name == "size") m.size = xml_parse_hex(attr.content);
}
mapping.append(m);
}
}
} else if(node.name == "rtc") {
has_spc7110rtc = true;
for(auto &leaf : node.element) {
if(leaf.name == "map") {
Mapping m({ &SPC7110::mmio_read, &spc7110 }, { &SPC7110::mmio_write, &spc7110 });
for(auto &attr : leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
}
}
void Cartridge::xml_parse_obc1(xml_element &root) {
has_obc1 = true;
for(auto &node : root.element) {
if(node.name == "map") {
Mapping m({ &OBC1::read, &obc1 }, { &OBC1::write, &obc1 });
for(auto &attr : node.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
void Cartridge::xml_parse_setarisc(xml_element &root) {
has_st0018 = true;
for(auto &node : root.element) {
if(node.name == "map") {
Mapping m({ &ST0018::mmio_read, &st0018 }, { &ST0018::mmio_write, &st0018 });
for(auto &attr : node.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
void Cartridge::xml_parse_msu1(xml_element &root) {
has_msu1 = true;
for(auto &node : root.element) {
if(node.name == "map") {
Mapping m({ &MSU1::mmio_read, &msu1 }, { &MSU1::mmio_write, &msu1 });
for(auto &attr : node.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
void Cartridge::xml_parse_link(xml_element &root) {
has_link = true;
link.frequency = 1;
link.program = "";
for(auto &attr : root.attribute) {
if(attr.name == "frequency") link.frequency = xml_parse_unsigned(attr.content);
if(attr.name == "program") link.program = attr.content;
}
for(auto &node : root.element) {
if(node.name == "map") {
Mapping m({ &Link::read, &link }, { &Link::write, &link });
for(auto &attr : node.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
unsigned Cartridge::xml_parse_hex(const string &s) {
return hex(s);
}
unsigned Cartridge::xml_parse_unsigned(const string &s) {
if(s.beginswith("0x")) return hex(s);
return integer(s);
}
void Cartridge::xml_parse_address(Mapping &m, const string &data) {
lstring part;
part.split(":", 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]);
}
}
void Cartridge::xml_parse_mode(Mapping &m, const string& data) {
if(data == "direct") m.mode = Bus::MapMode::Direct;
else if(data == "linear") m.mode = Bus::MapMode::Linear;
else if(data == "shadow") m.mode = Bus::MapMode::Shadow;
}
Cartridge::Mapping::Mapping() {
mode = Bus::MapMode::Direct;
banklo = bankhi = addrlo = addrhi = offset = size = 0;
}
Cartridge::Mapping::Mapping(Memory &memory) {
read = { &Memory::read, &memory };
write = { &Memory::write, &memory };
mode = Bus::MapMode::Direct;
banklo = bankhi = addrlo = addrhi = offset = size = 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;
}
#endif

View File

@ -29,21 +29,21 @@ bool Interface::cartridgeLoaded() {
void Interface::loadCartridge(const CartridgeData &base) {
cartridge.rom.copy(base.data, base.size);
cartridge.load(Cartridge::Mode::Normal, { base.xml });
cartridge.load(Cartridge::Mode::Normal, base.markup);
system.power();
}
void Interface::loadSatellaviewSlottedCartridge(const CartridgeData &base, const CartridgeData &slot) {
cartridge.rom.copy(base.data, base.size);
if(slot.data) bsxflash.memory.copy(slot.data, slot.size);
cartridge.load(Cartridge::Mode::BsxSlotted, { base.xml, slot.xml });
cartridge.load(Cartridge::Mode::BsxSlotted, base.markup);
system.power();
}
void Interface::loadSatellaviewCartridge(const CartridgeData &base, const CartridgeData &slot) {
cartridge.rom.copy(base.data, base.size);
if(slot.data) bsxflash.memory.copy(slot.data, slot.size);
cartridge.load(Cartridge::Mode::Bsx, { base.xml, slot.xml });
cartridge.load(Cartridge::Mode::Bsx, base.markup);
system.power();
}
@ -51,14 +51,14 @@ void Interface::loadSufamiTurboCartridge(const CartridgeData &base, const Cartri
cartridge.rom.copy(base.data, base.size);
if(slotA.data) sufamiturbo.slotA.rom.copy(slotA.data, slotA.size);
if(slotB.data) sufamiturbo.slotB.rom.copy(slotB.data, slotB.size);
cartridge.load(Cartridge::Mode::SufamiTurbo, { base.xml, slotA.xml, slotB.xml });
cartridge.load(Cartridge::Mode::SufamiTurbo, base.markup);
system.power();
}
void Interface::loadSuperGameBoyCartridge(const CartridgeData &base, const CartridgeData &slot) {
cartridge.rom.copy(base.data, base.size);
GameBoy::cartridge.load(slot.xml, slot.data, slot.size);
cartridge.load(Cartridge::Mode::SuperGameBoy, { base.xml, "" });
GameBoy::cartridge.load(slot.markup, slot.data, slot.size);
cartridge.load(Cartridge::Mode::SuperGameBoy, base.markup);
system.power();
}

View File

@ -8,7 +8,7 @@ struct Interface {
virtual void connect(bool port, Input::Device device);
struct CartridgeData {
string xml;
string markup;
const uint8_t *data;
unsigned size;
};

View File

@ -7,7 +7,7 @@ bool InterfaceGameBoy::loadCartridge(const string &filename) {
interface->baseName = nall::basename(filename);
GameBoyCartridge info(data, size);
GameBoy::Interface::loadCartridge(info.xml, data, size);
GameBoy::Interface::loadCartridge(info.markup, data, size);
delete[] data;
if(GameBoy::Interface::memorySize(GameBoy::Interface::Memory::RAM) > 0) {

View File

@ -71,13 +71,7 @@ bool InterfaceNES::loadState(const string &filename) {
void InterfaceNES::videoRefresh(const uint16_t *data) {
static uint16_t output[256 * 240];
unsigned height = 240;
if(config->video.enableOverscan == false) {
height = 224;
data += 8 * 256;
}
for(unsigned y = 0; y < height; y++) {
for(unsigned y = 0; y < 240; y++) {
const uint16_t *sp = data + y * 256;
uint16_t *dp = output + y * 256;
for(unsigned x = 0; x < 256; x++) {
@ -86,7 +80,19 @@ void InterfaceNES::videoRefresh(const uint16_t *data) {
}
}
interface->videoRefresh(output, 256 * 2, 256, height);
if(config->video.enableOverscan == false) {
for(unsigned y = 0; y < 240; y++) {
uint16_t *dp = output + y * 256;
if(y < 16 || y >= 224) {
memset(dp, 0, 256 * 2);
} else {
memset(dp + 0, 0, 8 * 2);
memset(dp + 248, 0, 8 * 2);
}
}
}
interface->videoRefresh(output, 256 * 2, 256, 240);
}
void InterfaceNES::audioSample(int16_t sample) {

View File

@ -30,11 +30,11 @@ bool InterfaceSNES::loadCartridge(const string &basename) {
interface->baseName = nall::basename(basename);
interface->slotName = { nall::basename(basename) };
string xml;
xml.readfile({ interface->baseName, ".xml" });
if(xml == "") xml = SNESCartridge(data, size).xmlMemoryMap;
string markup;
markup.readfile({ interface->baseName, ".bml" });
if(markup == "") markup = SnesCartridge(data, size).markup;
SNES::Interface::loadCartridge({ xml, data, size });
SNES::Interface::loadCartridge({ markup, data, size });
delete[] data;
loadMemory();
@ -53,11 +53,11 @@ bool InterfaceSNES::loadSatellaviewSlottedCartridge(const string &basename, cons
if(data[1]) interface->baseName.append("+", nall::basename(notdir(slotname)));
interface->slotName = { nall::basename(basename), nall::basename(slotname) };
string xml;
xml.readfile({ interface->baseName, ".xml" });
if(xml == "") xml = SNESCartridge(data[0], size[0]).xmlMemoryMap;
string markup;
markup.readfile({ interface->baseName, ".bml" });
if(markup == "") markup = SnesCartridge(data[0], size[0]).markup;
SNES::Interface::loadSatellaviewSlottedCartridge({ xml, data[0], size[0] }, { "", data[1], size[1] });
SNES::Interface::loadSatellaviewSlottedCartridge({ markup, data[0], size[0] }, { "", data[1], size[1] });
delete[] data[0];
if(data[1]) delete[] data[1];
@ -77,11 +77,11 @@ bool InterfaceSNES::loadSatellaviewCartridge(const string &basename, const strin
if(data[1]) interface->baseName.append("+", nall::basename(notdir(slotname)));
interface->slotName = { nall::basename(basename), nall::basename(slotname) };
string xml;
xml.readfile({ interface->baseName, ".xml" });
if(xml == "") xml = SNESCartridge(data[0], size[0]).xmlMemoryMap;
string markup;
markup.readfile({ interface->baseName, ".bml" });
if(markup == "") markup = SnesCartridge(data[0], size[0]).markup;
SNES::Interface::loadSatellaviewCartridge({ xml, data[0], size[0] }, { "", data[1], size[1] });
SNES::Interface::loadSatellaviewCartridge({ markup, data[0], size[0] }, { "", data[1], size[1] });
delete[] data[0];
if(data[1]) delete[] data[1];
@ -104,11 +104,11 @@ bool InterfaceSNES::loadSufamiTurboCartridge(const string &basename, const strin
else if(data[2]) interface->baseName = nall::basename(slotBname);
interface->slotName = { nall::basename(basename), nall::basename(slotAname), nall::basename(slotBname) };
string xml;
xml.readfile({ interface->baseName, ".xml" });
if(xml == "") xml = SNESCartridge(data[0], size[0]).xmlMemoryMap;
string markup;
markup.readfile({ interface->baseName, ".bml" });
if(markup == "") markup = SnesCartridge(data[0], size[0]).markup;
SNES::Interface::loadSufamiTurboCartridge({ xml, data[0], size[0] }, { "", data[1], size[1] }, { "", data[2], size[2] });
SNES::Interface::loadSufamiTurboCartridge({ markup, data[0], size[0] }, { "", data[1], size[1] }, { "", data[2], size[2] });
delete[] data[0];
if(data[1]) delete[] data[1];
if(data[2]) delete[] data[2];
@ -129,14 +129,14 @@ bool InterfaceSNES::loadSuperGameBoyCartridge(const string &basename, const stri
if(data[1]) interface->baseName = nall::basename(slotname);
interface->slotName = { nall::basename(basename), nall::basename(slotname) };
string xml;
xml.readfile({ interface->baseName, ".xml" });
if(xml == "") xml = SNESCartridge(data[0], size[0]).xmlMemoryMap;
string markup;
markup.readfile({ interface->baseName, ".bml" });
if(markup == "") markup = SnesCartridge(data[0], size[0]).markup;
string gbXml;
gbXml.readfile({ nall::basename(slotname), ".xml" });
if(gbXml == "") gbXml = GameBoyCartridge(data[1], size[1]).xml;
SNES::Interface::loadSuperGameBoyCartridge({ xml, data[0], size[0] }, { gbXml, data[1], size[1] });
string gbMarkup;
gbMarkup.readfile({ nall::basename(slotname), ".bml" });
if(gbMarkup == "") gbMarkup = GameBoyCartridge(data[1], size[1]).markup;
SNES::Interface::loadSuperGameBoyCartridge({ markup, data[0], size[0] }, { gbMarkup, data[1], size[1] });
delete[] data[0];
if(data[1]) delete[] data[1];
@ -194,21 +194,14 @@ bool InterfaceSNES::loadState(const string &filename) {
//
void InterfaceSNES::videoRefresh(const uint32_t *data, bool hires, bool interlace, bool overscan) {
static uint16_t output[512 * 478];
static uint16_t output[512 * 480];
unsigned width = 256 << hires;
unsigned height = (config->video.enableOverscan ? 240 : 224) << interlace;
unsigned height = 240 << interlace;
unsigned pitch = 1024 >> interlace;
//data[] = scanline { 8 (blank) + 240 (video) + 8 (blank) }
//first line of video data is not rendered (effectively blank as well)
if(config->video.enableOverscan) {
if(overscan == false) data += 1 * 1024; // 8 + 224 + 8
if(overscan == true ) data += 9 * 1024; // 0 + 240 + 0
} else {
if(overscan == false) data += 9 * 1024; // 0 + 224 + 0
if(overscan == true ) data += 16 * 1024; //-8 + 224 + -8
}
if(overscan == false) data += 1 * 1024; // 8 + 224 + 8
if(overscan == true ) data += 9 * 1024; // 0 + 240 + 0
for(unsigned y = 0; y < height; y++) {
const uint32_t *sp = data + y * pitch;
@ -218,6 +211,15 @@ void InterfaceSNES::videoRefresh(const uint32_t *data, bool hires, bool interlac
}
}
if(config->video.enableOverscan == false) {
unsigned mask = 8 << interlace;
for(unsigned y = 0; y < height; y++) {
if(y < mask || y >= height - mask) {
memset(output + y * 512, 0, width * 2);
}
}
}
interface->videoRefresh(output, 512 * 2, width, height);
}

View File

@ -49,7 +49,7 @@ Application::Application(int argc, char **argv) {
inputManager = new InputManager;
utility = new Utility;
title = "bsnes v082.28";
title = "bsnes v082.29";
string fontFamily = Intrinsics::platform() == Intrinsics::Platform::Windows ? "Tahoma, " : "Sans, ";
normalFont = { fontFamily, "8" };

View File

@ -129,7 +129,7 @@ bool CheatEditor::load(const string &filename) {
if(data.readfile(filename) == false) return false;
unsigned n = 0;
BML::Node document(data);
BML::Document document(data);
for(auto &cheat : document["cartridge"]) {
if(cheat.name != "cheat") continue;
cheatList.setChecked(n, cheat["enable"].exists());
@ -161,11 +161,11 @@ bool CheatEditor::save(const string &filename) {
file fp;
if(fp.open(filename, file::mode::write) == false) return false;
fp.print("cartridge sha256{", interface->sha256(), "}\n");
fp.print("cartridge sha256:", interface->sha256(), "\n");
for(unsigned n = 0; n <= lastSave; n++) {
fp.print("\tcheat", cheatList.checked(n) ? " enable" : "", "\n");
fp.print("\t\tdescription{", BML::encode(cheatText[n][Desc]), "}\n");
fp.print("\t\tcode{", BML::encode(cheatText[n][Code]), "}\n");
fp.print("\t\tdescription:", cheatText[n][Desc], "\n");
fp.print("\t\tcode:", cheatText[n][Code], "\n");
}
fp.close();

View File

@ -43,14 +43,14 @@ void Utility::resizeMainWindow(bool shrink) {
unsigned width = geometry.width, height = geometry.height;
switch(interface->mode()) {
case Interface::Mode::NES: width = 256, height = config->video.enableOverscan ? 240 : 224; break;
case Interface::Mode::SNES: width = 256, height = config->video.enableOverscan ? 240 : 224; break;
case Interface::Mode::NES: width = 256, height = 240; break;
case Interface::Mode::SNES: width = 256, height = 240; break;
case Interface::Mode::GameBoy: width = 160, height = 144; break;
}
if(config->video.correctAspectRatio) {
if(interface->mode() != Interface::Mode::GameBoy) {
width = (double)width * (config->video.enableOverscan ? 1.225 : 1.149);
width = (double)width * 1.226;
}
}