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" #include "serialization.cpp"
Cartridge cartridge; 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; if(size == 0) size = 32768;
romdata = allocate<uint8>(romsize = size, 0xff); romdata = allocate<uint8>(romsize = size, 0xff);
if(data) memcpy(romdata, data, size); 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.romsize = 0;
info.ramsize = 0; info.ramsize = 0;
xml_element document = xml_parse(xml); BML::Document document(markup);
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;
}
if(attr.name == "rtc") info.rtc = (attr.content == "true" ? true : false); auto &mapperid = document["cartridge"]["mapper"].value;
if(attr.name == "rumble") info.rumble = (attr.content == "true" ? true : false); 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) { info.rtc = document["cartridge"]["rtc"].exists();
if(elem.name == "rom") { info.rumble = document["cartridge"]["rumble"].exists();
for(auto &attr : elem.attribute) {
if(attr.name == "size") info.romsize = hex(attr.content);
}
}
if(elem.name == "ram") { info.romsize = hex(document["cartridge"]["rom"]["size"].value);
info.ram = true; info.ramsize = hex(document["cartridge"]["ram"]["size"].value);
for(auto &attr : elem.attribute) { info.battery = document["cartridge"]["ram"]["non-volatile"].exists();
if(attr.name == "size") info.ramsize = hex(attr.content);
if(attr.name == "battery") info.battery = (attr.content == "true" ? true : false);
}
}
}
}
}
switch(info.mapper) { default: switch(info.mapper) { default:
case Mapper::MBC0: mapper = &mbc0; break; case Mapper::MBC0: mapper = &mbc0; break;

View File

@ -45,7 +45,7 @@ struct Cartridge : MMIO, property<Cartridge> {
MMIO *mapper; MMIO *mapper;
bool bootrom_enable; 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(); void unload();
uint8 rom_read(unsigned addr); uint8 rom_read(unsigned addr);

View File

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

View File

@ -10,7 +10,7 @@ public:
virtual void initialize(Interface*); virtual void initialize(Interface*);
virtual bool cartridgeLoaded(); 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(); virtual void unloadCartridge();
enum class Memory : unsigned { enum class Memory : unsigned {

View File

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

View File

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

View File

@ -1,124 +1,97 @@
#ifdef NALL_STRING_INTERNAL_HPP #ifdef NALL_STRING_INTERNAL_HPP
//BML v1.0 parser //BML v1.0 parser
//revision 0.03 //revision 0.05
namespace nall { namespace nall {
namespace BML { namespace BML {
inline static string encode(const char *s) { inline static string indent(const char *s, unsigned depth) {
array<char> output; array<char> output;
while(*s) { do {
char c = *s++; for(unsigned n = 0; n < depth; n++) output.append('\t');
(c == '\n') ? output.append("{lf}", 4) : do output.append(*s); while(*s && *s++ != '\n');
(c == '{') ? output.append("{lb}", 4) : } while(*s);
(c == '}') ? output.append("{rb}", 4) :
output.append(c);
}
output.append(0);
return output.get(); return output.get();
} }
struct Node { struct Node {
cstring name; cstring name;
cstring value; cstring value;
signed depth;
private: private:
linear_vector<Node> children; linear_vector<Node> children;
inline bool valid(char p) const { inline bool valid(char p) const { //A-Za-z0-9-.
if(p >= 'A' && p <= 'Z') return true; return p - 'A' < 26u | p - 'a' < 26u | p - '0' < 10u | p - '-' < 2u;
if(p >= 'a' && p <= 'z') return true;
if(p >= '0' && p <= '9') return true;
if(p == '-' || p == '.') return true;
return false;
} }
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; unsigned depth = 0;
while(*p == '\t') depth++, p++; while(p[depth] == '\t') depth++;
return depth; return depth;
} }
inline void parseName(char *&p) { inline void parseName(char *&p) {
if(valid(*p)) { if(valid(*p) == false) throw "Missing node name";
name = p; name = p;
while(valid(*p)) p++; while(valid(*p)) p++;
}
} }
inline void parseValue(char *&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; value = p;
char *w = p; char *w = p;
while(*p) { while(parseDepth(p) > depth) {
if(*p == '\n') throw "Unclosed node value"; p += depth + 1;
if(*p == '}') break; while(*p && *p != '\n') *w++ = *p++;
if(*p == '{') { if(*p && *p != '\n') throw "Multi-line value missing line feed";
if(*(p + 1) == 'l' && *(p + 2) == 'b' && *(p + 3) == '}') *w++ = '{', p += 4; *w++ = *p;
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++;
} }
*(w - 1) = 0; //'\n'
if(*p != '}') throw "Unclosed node value";
*w = *p++ = 0; //'}'
} }
inline void parseLine(char *&p) { inline void parseLine(char *&p) {
depth = parseDepth(p); unsigned depth = parseDepth(p);
while(*p == '\t') p++; while(*p == '\t') p++;
parseName(p); parseName(p);
bool multiLine = false; bool multiLine = *p == '~';
if(*p == ':') { if(multiLine) *p++ = 0;
multiLine = true; else if(*p == ':' || *p == '=') parseValue(p);
*p++ = 0; if(*p && *p != ' ' && *p != '\n') throw "Invalid character encountered";
} else if(*p == '{') {
parseValue(p);
if(*p != ' ' && *p != '\n') throw "Invalid character after first node value";
}
while(*p == ' ') { while(*p == ' ') {
*p++ = 0; *p++ = 0;
Node node; Node node;
node.parseName(p); node.parseName(p);
if(*p == '{') node.parseValue(p); if(*p == ':' || *p == '=') node.parseValue(p);
if(*p != ' ' && *p != '\n') throw "Invalid character after node"; if(*p && *p != ' ' && *p != '\n') throw "Invalid character after node";
if(*p == '\n') *p++ = 0;
children.append(node); children.append(node);
} }
if(*p == 0) throw "Missing line feed"; if(multiLine) return parseBlock(p, depth);
while(*p == '\n') *p++ = 0;
if(multiLine == false) { while(parseDepth(p) > depth) {
while(parseDepth(p) > depth) { Node node;
Node node; node.parseLine(p);
node.parseLine(p); children.append(node);
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;
} }
} }
inline void parse(char *&p) { inline void parse(char *&p) {
while(*p) { while(*p) {
while(*p == '\n') *p++ = 0;
Node node; Node node;
node.parseLine(p); node.parseLine(p);
children.append(node); children.append(node);
@ -135,41 +108,41 @@ public:
return node; return node;
} }
inline bool exists() const { inline bool exists() const { return name; }
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 = "";
}
unsigned size() const { return children.size(); } unsigned size() const { return children.size(); }
Node* begin() { return children.begin(); } Node* begin() { return children.begin(); }
Node* end() { return children.end(); } Node* end() { return children.end(); }
const Node* begin() const { return children.begin(); } const Node* begin() const { return children.begin(); }
const Node* end() const { return children.end(); } const Node* end() const { return children.end(); }
inline Node() : name(""), value("") {}
friend class Document;
};
inline Node() { constructor(); } struct Document : Node {
inline Node(const char *document) { constructor(); load(document); } cstring error;
inline ~Node() { if(depth == -1) free((void*)(const char*)value); }
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) { 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"]; auto &board = document["cartridge"]["board"];
string type = board["type"].value; string type = board["type"].value;

View File

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

View File

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

View File

@ -136,29 +136,11 @@ public:
} }
if(source) { if(source) {
bool is_glsl = false; BML::Document document(source);
fragmentfilter = 0; bool is_glsl = document["shader"]["language"].value == "GLSL";
string fragment_source; fragmentfilter = document["shader"]["fragment"]["filter"].value == "linear" ? 1 : 0;
string vertex_source; string fragment_source = document["shader"]["fragment"].value;
string vertex_source = document["shader"]["vertex"].value;
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();
}
}
}
}
if(is_glsl) { if(is_glsl) {
if(fragment_source != "") set_fragment_shader(fragment_source); if(fragment_source != "") set_fragment_shader(fragment_source);

View File

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

View File

@ -82,7 +82,7 @@ struct Cartridge : property<Cartridge> {
} nss; } nss;
} information; } information;
void load(Mode, const lstring&); void load(Mode, const char*);
void unload(); void unload();
void serialize(serializer&); void serialize(serializer&);
@ -90,35 +90,27 @@ struct Cartridge : property<Cartridge> {
~Cartridge(); ~Cartridge();
private: private:
void parse_xml(const lstring&); void parse_markup(const char*);
void parse_xml_cartridge(const char*); unsigned parse_markup_integer(cstring&);
void parse_xml_bsx(const char*); void parse_markup_map(Mapping&, BML::Node&);
void parse_xml_sufami_turbo(const char*, bool);
void parse_xml_gameboy(const char*);
void xml_parse_rom(xml_element&); void parse_markup_rom(BML::Node&);
void xml_parse_ram(xml_element&); void parse_markup_ram(BML::Node&);
void xml_parse_nss(xml_element&); void parse_markup_nss(BML::Node&);
void xml_parse_icd2(xml_element&); void parse_markup_icd2(BML::Node&);
void xml_parse_superfx(xml_element&); void parse_markup_superfx(BML::Node&);
void xml_parse_sa1(xml_element&); void parse_markup_sa1(BML::Node&);
void xml_parse_necdsp(xml_element&); void parse_markup_necdsp(BML::Node&);
void xml_parse_hitachidsp(xml_element&); void parse_markup_hitachidsp(BML::Node&);
void xml_parse_bsx(xml_element&); void parse_markup_bsx(BML::Node&);
void xml_parse_sufamiturbo(xml_element&); void parse_markup_sufamiturbo(BML::Node&);
void xml_parse_supergameboy(xml_element&); void parse_markup_srtc(BML::Node&);
void xml_parse_srtc(xml_element&); void parse_markup_sdd1(BML::Node&);
void xml_parse_sdd1(xml_element&); void parse_markup_spc7110(BML::Node&);
void xml_parse_spc7110(xml_element&); void parse_markup_obc1(BML::Node&);
void xml_parse_obc1(xml_element&); void parse_markup_setarisc(BML::Node&);
void xml_parse_setarisc(xml_element&); void parse_markup_msu1(BML::Node&);
void xml_parse_msu1(xml_element&); void parse_markup_link(BML::Node&);
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&);
}; };
extern Cartridge cartridge; 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) { void Interface::loadCartridge(const CartridgeData &base) {
cartridge.rom.copy(base.data, base.size); cartridge.rom.copy(base.data, base.size);
cartridge.load(Cartridge::Mode::Normal, { base.xml }); cartridge.load(Cartridge::Mode::Normal, base.markup);
system.power(); system.power();
} }
void Interface::loadSatellaviewSlottedCartridge(const CartridgeData &base, const CartridgeData &slot) { void Interface::loadSatellaviewSlottedCartridge(const CartridgeData &base, const CartridgeData &slot) {
cartridge.rom.copy(base.data, base.size); cartridge.rom.copy(base.data, base.size);
if(slot.data) bsxflash.memory.copy(slot.data, slot.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(); system.power();
} }
void Interface::loadSatellaviewCartridge(const CartridgeData &base, const CartridgeData &slot) { void Interface::loadSatellaviewCartridge(const CartridgeData &base, const CartridgeData &slot) {
cartridge.rom.copy(base.data, base.size); cartridge.rom.copy(base.data, base.size);
if(slot.data) bsxflash.memory.copy(slot.data, slot.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(); system.power();
} }
@ -51,14 +51,14 @@ void Interface::loadSufamiTurboCartridge(const CartridgeData &base, const Cartri
cartridge.rom.copy(base.data, base.size); cartridge.rom.copy(base.data, base.size);
if(slotA.data) sufamiturbo.slotA.rom.copy(slotA.data, slotA.size); if(slotA.data) sufamiturbo.slotA.rom.copy(slotA.data, slotA.size);
if(slotB.data) sufamiturbo.slotB.rom.copy(slotB.data, slotB.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(); system.power();
} }
void Interface::loadSuperGameBoyCartridge(const CartridgeData &base, const CartridgeData &slot) { void Interface::loadSuperGameBoyCartridge(const CartridgeData &base, const CartridgeData &slot) {
cartridge.rom.copy(base.data, base.size); cartridge.rom.copy(base.data, base.size);
GameBoy::cartridge.load(slot.xml, slot.data, slot.size); GameBoy::cartridge.load(slot.markup, slot.data, slot.size);
cartridge.load(Cartridge::Mode::SuperGameBoy, { base.xml, "" }); cartridge.load(Cartridge::Mode::SuperGameBoy, base.markup);
system.power(); system.power();
} }

View File

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

View File

@ -7,7 +7,7 @@ bool InterfaceGameBoy::loadCartridge(const string &filename) {
interface->baseName = nall::basename(filename); interface->baseName = nall::basename(filename);
GameBoyCartridge info(data, size); GameBoyCartridge info(data, size);
GameBoy::Interface::loadCartridge(info.xml, data, size); GameBoy::Interface::loadCartridge(info.markup, data, size);
delete[] data; delete[] data;
if(GameBoy::Interface::memorySize(GameBoy::Interface::Memory::RAM) > 0) { 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) { void InterfaceNES::videoRefresh(const uint16_t *data) {
static uint16_t output[256 * 240]; static uint16_t output[256 * 240];
unsigned height = 240; for(unsigned y = 0; y < 240; y++) {
if(config->video.enableOverscan == false) {
height = 224;
data += 8 * 256;
}
for(unsigned y = 0; y < height; y++) {
const uint16_t *sp = data + y * 256; const uint16_t *sp = data + y * 256;
uint16_t *dp = output + y * 256; uint16_t *dp = output + y * 256;
for(unsigned x = 0; x < 256; x++) { 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) { void InterfaceNES::audioSample(int16_t sample) {

View File

@ -30,11 +30,11 @@ bool InterfaceSNES::loadCartridge(const string &basename) {
interface->baseName = nall::basename(basename); interface->baseName = nall::basename(basename);
interface->slotName = { nall::basename(basename) }; interface->slotName = { nall::basename(basename) };
string xml; string markup;
xml.readfile({ interface->baseName, ".xml" }); markup.readfile({ interface->baseName, ".bml" });
if(xml == "") xml = SNESCartridge(data, size).xmlMemoryMap; if(markup == "") markup = SnesCartridge(data, size).markup;
SNES::Interface::loadCartridge({ xml, data, size }); SNES::Interface::loadCartridge({ markup, data, size });
delete[] data; delete[] data;
loadMemory(); loadMemory();
@ -53,11 +53,11 @@ bool InterfaceSNES::loadSatellaviewSlottedCartridge(const string &basename, cons
if(data[1]) interface->baseName.append("+", nall::basename(notdir(slotname))); if(data[1]) interface->baseName.append("+", nall::basename(notdir(slotname)));
interface->slotName = { nall::basename(basename), nall::basename(slotname) }; interface->slotName = { nall::basename(basename), nall::basename(slotname) };
string xml; string markup;
xml.readfile({ interface->baseName, ".xml" }); markup.readfile({ interface->baseName, ".bml" });
if(xml == "") xml = SNESCartridge(data[0], size[0]).xmlMemoryMap; 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]; delete[] data[0];
if(data[1]) delete[] data[1]; 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))); if(data[1]) interface->baseName.append("+", nall::basename(notdir(slotname)));
interface->slotName = { nall::basename(basename), nall::basename(slotname) }; interface->slotName = { nall::basename(basename), nall::basename(slotname) };
string xml; string markup;
xml.readfile({ interface->baseName, ".xml" }); markup.readfile({ interface->baseName, ".bml" });
if(xml == "") xml = SNESCartridge(data[0], size[0]).xmlMemoryMap; 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]; delete[] data[0];
if(data[1]) delete[] data[1]; 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); else if(data[2]) interface->baseName = nall::basename(slotBname);
interface->slotName = { nall::basename(basename), nall::basename(slotAname), nall::basename(slotBname) }; interface->slotName = { nall::basename(basename), nall::basename(slotAname), nall::basename(slotBname) };
string xml; string markup;
xml.readfile({ interface->baseName, ".xml" }); markup.readfile({ interface->baseName, ".bml" });
if(xml == "") xml = SNESCartridge(data[0], size[0]).xmlMemoryMap; 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]; delete[] data[0];
if(data[1]) delete[] data[1]; if(data[1]) delete[] data[1];
if(data[2]) delete[] data[2]; 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); if(data[1]) interface->baseName = nall::basename(slotname);
interface->slotName = { nall::basename(basename), nall::basename(slotname) }; interface->slotName = { nall::basename(basename), nall::basename(slotname) };
string xml; string markup;
xml.readfile({ interface->baseName, ".xml" }); markup.readfile({ interface->baseName, ".bml" });
if(xml == "") xml = SNESCartridge(data[0], size[0]).xmlMemoryMap; if(markup == "") markup = SnesCartridge(data[0], size[0]).markup;
string gbXml; string gbMarkup;
gbXml.readfile({ nall::basename(slotname), ".xml" }); gbMarkup.readfile({ nall::basename(slotname), ".bml" });
if(gbXml == "") gbXml = GameBoyCartridge(data[1], size[1]).xml; if(gbMarkup == "") gbMarkup = GameBoyCartridge(data[1], size[1]).markup;
SNES::Interface::loadSuperGameBoyCartridge({ xml, data[0], size[0] }, { gbXml, data[1], size[1] }); SNES::Interface::loadSuperGameBoyCartridge({ markup, data[0], size[0] }, { gbMarkup, data[1], size[1] });
delete[] data[0]; delete[] data[0];
if(data[1]) delete[] data[1]; 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) { 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 width = 256 << hires;
unsigned height = (config->video.enableOverscan ? 240 : 224) << interlace; unsigned height = 240 << interlace;
unsigned pitch = 1024 >> interlace; unsigned pitch = 1024 >> interlace;
//data[] = scanline { 8 (blank) + 240 (video) + 8 (blank) } if(overscan == false) data += 1 * 1024; // 8 + 224 + 8
//first line of video data is not rendered (effectively blank as well) if(overscan == true ) data += 9 * 1024; // 0 + 240 + 0
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
}
for(unsigned y = 0; y < height; y++) { for(unsigned y = 0; y < height; y++) {
const uint32_t *sp = data + y * pitch; 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); interface->videoRefresh(output, 512 * 2, width, height);
} }

View File

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

View File

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

View File

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