Path: blob/master/libsnes/bsnes/snes/cartridge/markup.cpp
2 views
#ifdef CARTRIDGE_CPP12void Cartridge::parse_markup(const char *markup) {3mapping.reset();4information.nss.setting.reset();56XML::Document document(markup);7auto &cartridge = document["cartridge"];8region = cartridge["region"].data != "PAL" ? Region::NTSC : Region::PAL;910parse_markup_rom(cartridge["rom"]);11parse_markup_ram(cartridge["ram"]);12parse_markup_nss(cartridge["nss"]);13parse_markup_icd2(cartridge["icd2"]);14parse_markup_sa1(cartridge["sa1"]);15parse_markup_superfx(cartridge["superfx"]);16parse_markup_necdsp(cartridge["necdsp"]);17parse_markup_hitachidsp(cartridge["hitachidsp"]);18parse_markup_armdsp(cartridge["armdsp"]);19parse_markup_bsx(cartridge["bsx"]);20parse_markup_sufamiturbo(cartridge["sufamiturbo"]);21parse_markup_srtc(cartridge["srtc"]);22parse_markup_sdd1(cartridge["sdd1"]);23parse_markup_spc7110(cartridge["spc7110"]);24parse_markup_obc1(cartridge["obc1"]);25parse_markup_msu1(cartridge["msu1"]);26parse_markup_link(cartridge["link"]);27}2829//3031void Cartridge::parse_markup_map(Mapping &m, XML::Node &map) {32m.offset = numeral(map["offset"].data);33m.size = numeral(map["size"].data);3435string data = map["mode"].data;36if(data == "direct") m.mode = Bus::MapMode::Direct;37if(data == "linear") m.mode = Bus::MapMode::Linear;38if(data == "shadow") m.mode = Bus::MapMode::Shadow;3940lstring part;41part.split(":", map["address"].data);42if(part.size() != 2) return;4344lstring subpart;45subpart.split("-", part[0]);46if(subpart.size() == 1) {47m.banklo = hex(subpart[0]);48m.bankhi = m.banklo;49} else if(subpart.size() == 2) {50m.banklo = hex(subpart[0]);51m.bankhi = hex(subpart[1]);52}5354subpart.split("-", part[1]);55if(subpart.size() == 1) {56m.addrlo = hex(subpart[0]);57m.addrhi = m.addrlo;58} else if(subpart.size() == 2) {59m.addrlo = hex(subpart[0]);60m.addrhi = hex(subpart[1]);61}62}6364uint8 Cartridge::rom_read(unsigned addr)65{66cdlInfo.set(eCDLog_AddrType_CARTROM, addr);67return rom.read(addr);68}69void Cartridge::rom_write(unsigned addr, uint8 n)70{71rom.write(addr,n);72}7374uint8 Cartridge::ram_read(unsigned addr)75{76cdlInfo.set(eCDLog_AddrType_CARTRAM, addr);77return ram.read(addr);78}79void Cartridge::ram_write(unsigned addr, uint8 n)80{81ram.write(addr, n);82}8384void Cartridge::parse_markup_rom(XML::Node &root) {85if(root.exists() == false) return;86for(auto &node : root) {87if(node.name != "map") continue;88Mapping m({&Cartridge::rom_read, this}, {&Cartridge::rom_write, this});89parse_markup_map(m, node);90if(m.size == 0) m.size = rom.size();91mapping.append(m);92}93}9495void Cartridge::parse_markup_ram(XML::Node &root) {96if(root.exists() == false) return;97ram_size = numeral(root["size"].data);98for(auto &node : root) {99Mapping m({ &Cartridge::ram_read, this }, { &Cartridge::ram_write, this });100parse_markup_map(m, node);101if(m.size == 0) m.size = ram_size;102mapping.append(m);103}104}105106void Cartridge::parse_markup_nss(XML::Node &root) {107if(root.exists() == false) return;108has_nss_dip = true;109for(auto &node : root) {110if(node.name != "setting") continue;111unsigned number = information.nss.setting.size();112if(number >= 16) break; //more than 16 DIP switches is not physically possible113114information.nss.option[number].reset();115information.nss.setting.append(node["name"].data);116for(auto &leaf : node) {117if(leaf.name != "option") continue;118string name = leaf["name"].data;119unsigned value = numeral(leaf["value"].data);120information.nss.option[number].append({ hex<4>(value), ":", name });121}122}123}124125void Cartridge::parse_markup_icd2(XML::Node &root) {126#if defined(GAMEBOY)127if(root.exists() == false) return;128if(mode.value != Mode::SuperGameBoy) return;129130icd2.revision = max(1, numeral(root["revision"].data));131132for(auto &node : root) {133if(node.name != "map") continue;134Mapping m({ &ICD2::read, &icd2 }, { &ICD2::write, &icd2 });135parse_markup_map(m, node);136mapping.append(m);137}138#endif139}140141void Cartridge::parse_markup_superfx(XML::Node &root) {142if(root.exists() == false) return;143has_superfx = true;144145for(auto &node : root) {146if(node.name == "rom") {147for(auto &leaf : node) {148if(leaf.name != "map") continue;149Mapping m(superfx.rom);150parse_markup_map(m, leaf);151mapping.append(m);152}153}154if(node.name == "ram") {155for(auto &leaf : node) {156if(leaf.name == "size") {157ram_size = numeral(leaf.data);158continue;159}160if(leaf.name != "map") continue;161Mapping m(superfx.ram);162parse_markup_map(m, leaf);163if(m.size == 0) m.size = ram_size;164mapping.append(m);165}166}167if(node.name == "mmio") {168for(auto &leaf : node) {169if(leaf.name != "map") continue;170Mapping m({ &SuperFX::mmio_read, &superfx }, { &SuperFX::mmio_write, &superfx });171parse_markup_map(m, leaf);172mapping.append(m);173}174}175}176}177178void Cartridge::parse_markup_sa1(XML::Node &root) {179if(root.exists() == false) return;180has_sa1 = true;181182auto &mcurom = root["mcu"]["rom"];183auto &mcuram = root["mcu"]["ram"];184auto &iram = root["iram"];185auto &bwram = root["bwram"];186auto &mmio = root["mmio"];187188for(auto &node : mcurom) {189if(node.name != "map") continue;190Mapping m({ &SA1::mmc_read, &sa1 }, { &SA1::mmc_write, &sa1 });191parse_markup_map(m, node);192mapping.append(m);193}194195for(auto &node : mcuram) {196if(node.name != "map") continue;197Mapping m({ &SA1::mmc_cpu_read, &sa1 }, { &SA1::mmc_cpu_write, &sa1 });198parse_markup_map(m, node);199mapping.append(m);200}201202for(auto &node : iram) {203if(node.name != "map") continue;204Mapping m(sa1.cpuiram);205parse_markup_map(m, node);206if(m.size == 0) m.size = 2048;207mapping.append(m);208}209210ram_size = numeral(bwram["size"].data);211for(auto &node : bwram) {212if(node.name != "map") continue;213Mapping m(sa1.cpubwram);214parse_markup_map(m, node);215if(m.size == 0) m.size = ram_size;216mapping.append(m);217}218219for(auto &node : mmio) {220if(node.name != "map") continue;221Mapping m({ &SA1::mmio_read, &sa1 }, { &SA1::mmio_write, &sa1 });222parse_markup_map(m, node);223mapping.append(m);224}225}226227void Cartridge::parse_markup_necdsp(XML::Node &root) {228if(root.exists() == false) return;229has_necdsp = true;230231for(unsigned n = 0; n < 16384; n++) necdsp.programROM[n] = 0x000000;232for(unsigned n = 0; n < 2048; n++) necdsp.dataROM[n] = 0x0000;233234necdsp.frequency = numeral(root["frequency"].data);235if(necdsp.frequency == 0) necdsp.frequency = 8000000;236necdsp.revision237= root["model"].data == "uPD7725" ? NECDSP::Revision::uPD7725238: root["model"].data == "uPD96050" ? NECDSP::Revision::uPD96050239: NECDSP::Revision::uPD7725;240string firmware = root["firmware"].data;241string sha256 = root["sha256"].data;242243string path = interface()->path(Slot::Base, firmware);244unsigned promsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 2048 : 16384);245unsigned dromsize = (necdsp.revision == NECDSP::Revision::uPD7725 ? 1024 : 2048);246unsigned filesize = promsize * 3 + dromsize * 2;247248file fp;249if(fp.open(path, file::mode::read) == false) {250interface()->message({ "Warning: NEC DSP firmware ", firmware, " is missing." });251} else if(fp.size() != filesize) {252interface()->message({ "Warning: NEC DSP firmware ", firmware, " is of the wrong file size." });253fp.close();254} else {255for(unsigned n = 0; n < promsize; n++) necdsp.programROM[n] = fp.readl(3);256for(unsigned n = 0; n < dromsize; n++) necdsp.dataROM[n] = fp.readl(2);257258if(!sha256.empty()) {259//XML file specified SHA256 sum for program. Verify file matches the hash.260fp.seek(0);261//uint8_t data[filesize]; //test262uint8_t *data = (uint8_t*)alloca(filesize);263fp.read(data, filesize);264265if(sha256 != nall::sha256(data, filesize)) {266interface()->message({ "Warning: NEC DSP firmware ", firmware, " SHA256 sum is incorrect." });267}268}269270fp.close();271}272273for(auto &node : root) {274if(node.name == "dr") {275for(auto &leaf : node) {276Mapping m({ &NECDSP::dr_read, &necdsp }, { &NECDSP::dr_write, &necdsp });277parse_markup_map(m, leaf);278mapping.append(m);279}280}281if(node.name == "sr") {282for(auto &leaf : node) {283Mapping m({ &NECDSP::sr_read, &necdsp }, { &NECDSP::sr_write, &necdsp });284parse_markup_map(m, leaf);285mapping.append(m);286}287}288if(node.name == "dp") {289for(auto &leaf : node) {290Mapping m({ &NECDSP::dp_read, &necdsp }, { &NECDSP::dp_write, &necdsp });291parse_markup_map(m, leaf);292mapping.append(m);293}294}295}296}297298void Cartridge::parse_markup_hitachidsp(XML::Node &root) {299if(root.exists() == false) return;300has_hitachidsp = true;301302for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = 0x000000;303304hitachidsp.frequency = numeral(root["frequency"].data);305if(hitachidsp.frequency == 0) hitachidsp.frequency = 20000000;306string firmware = root["firmware"].data;307string sha256 = root["sha256"].data;308309string path = interface()->path(Slot::Base, firmware);310file fp;311if(fp.open(path, file::mode::read) == false) {312interface()->message({ "Warning: Hitachi DSP firmware ", firmware, " is missing." });313} else if(fp.size() != 1024 * 3) {314interface()->message({ "Warning: Hitachi DSP firmware ", firmware, " is of the wrong file size." });315fp.close();316} else {317for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = fp.readl(3);318319if(!sha256.empty()) {320//XML file specified SHA256 sum for program. Verify file matches the hash.321fp.seek(0);322uint8 data[3072];323fp.read(data, 3072);324325if(sha256 != nall::sha256(data, 3072)) {326interface()->message({ "Warning: Hitachi DSP firmware ", firmware, " SHA256 sum is incorrect." });327}328}329330fp.close();331}332333for(auto &node : root) {334if(node.name == "rom") {335for(auto &leaf : node) {336if(leaf.name != "map") continue;337Mapping m({ &HitachiDSP::rom_read, &hitachidsp }, { &HitachiDSP::rom_write, &hitachidsp });338parse_markup_map(m, leaf);339mapping.append(m);340}341}342if(node.name == "mmio") {343for(auto &leaf : node) {344Mapping m({ &HitachiDSP::dsp_read, &hitachidsp }, { &HitachiDSP::dsp_write, &hitachidsp });345parse_markup_map(m, leaf);346mapping.append(m);347}348}349}350}351352void Cartridge::parse_markup_armdsp(XML::Node &root) {353if(root.exists() == false) return;354has_armdsp = true;355356string firmware = root["firmware"].data;357string sha256 = root["sha256"].data;358359string path = interface()->path(Slot::Base, firmware);360file fp;361if(fp.open(path, file::mode::read) == false) {362interface()->message({ "Warning: ARM DSP firmware ", firmware, " is missing." });363} else if(fp.size() != 160 * 1024) {364interface()->message({ "Warning: ARM DSP firmware ", firmware, " is of the wrong file size." });365fp.close();366} else {367fp.read(armdsp.firmware, fp.size());368369if(!sha256.empty()) {370if(sha256 != nall::sha256(armdsp.firmware, fp.size())) {371interface()->message({ "Warning: ARM DSP firmware ", firmware, " SHA256 sum is incorrect." });372}373}374375fp.close();376}377378for(auto &node : root) {379if(node.name != "map") continue;380Mapping m({ &ArmDSP::mmio_read, &armdsp }, { &ArmDSP::mmio_write, &armdsp });381parse_markup_map(m, node);382mapping.append(m);383}384}385386void Cartridge::parse_markup_bsx(XML::Node &root) {387if(root.exists() == false) return;388if(mode.value != Mode::BsxSlotted && mode.value != Mode::Bsx) return;389has_bsx_slot = true;390391for(auto &node : root["slot"]) {392if(node.name != "map") continue;393Mapping m(bsxflash.memory);394parse_markup_map(m, node);395mapping.append(m);396}397398for(auto &node : root["mmio"]) {399if(node.name != "map") continue;400Mapping m({ &BSXCartridge::mmio_read, &bsxcartridge }, { &BSXCartridge::mmio_write, &bsxcartridge });401parse_markup_map(m, node);402mapping.append(m);403}404405for(auto &node : root["mcu"]) {406if(node.name != "map") continue;407Mapping m({ &BSXCartridge::mcu_read, &bsxcartridge }, { &BSXCartridge::mcu_write, &bsxcartridge });408parse_markup_map(m, node);409mapping.append(m);410}411}412413void Cartridge::parse_markup_sufamiturbo(XML::Node &root) {414if(root.exists() == false) return;415if(mode.value != Mode::SufamiTurbo) return;416417for(auto &slot : root) {418if(slot.name != "slot") continue;419bool slotid = slot["id"].data == "A" ? 0 : slot["id"].data == "B" ? 1 : 0;420for(auto &node : slot) {421if(node.name == "rom") {422for(auto &leaf : node) {423if(leaf.name != "map") continue;424Memory &memory = slotid == 0 ? sufamiturbo.slotA.rom : sufamiturbo.slotB.rom;425Mapping m(memory);426parse_markup_map(m, leaf);427if(m.size == 0) m.size = memory.size();428if(m.size) mapping.append(m);429}430}431if(node.name == "ram") {432unsigned ram_size = numeral(node["size"].data);433for(auto &leaf : node) {434if(leaf.name != "map") continue;435Memory &memory = slotid == 0 ? sufamiturbo.slotA.ram : sufamiturbo.slotB.ram;436Mapping m(memory);437parse_markup_map(m, leaf);438if(m.size == 0) m.size = ram_size;439if(m.size) mapping.append(m);440}441}442}443}444}445446void Cartridge::parse_markup_srtc(XML::Node &root) {447if(root.exists() == false) return;448has_srtc = true;449450for(auto &node : root) {451if(node.name != "map") continue;452Mapping m({ &SRTC::read, &srtc }, { &SRTC::write, &srtc });453parse_markup_map(m, node);454mapping.append(m);455}456}457458void Cartridge::parse_markup_sdd1(XML::Node &root) {459if(root.exists() == false) return;460has_sdd1 = true;461462for(auto &node : root["mmio"]) {463if(node.name != "map") continue;464Mapping m({ &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });465parse_markup_map(m, node);466mapping.append(m);467}468469for(auto &node : root["mcu"]) {470if(node.name != "map") continue;471Mapping m({ &SDD1::mcu_read, &sdd1 }, { &SDD1::mcu_write, &sdd1 });472parse_markup_map(m, node);473mapping.append(m);474}475}476477void Cartridge::parse_markup_spc7110(XML::Node &root) {478if(root.exists() == false) return;479has_spc7110 = true;480has_spc7110rtc = root["rtc"].exists();481482auto &ram = root["ram"];483auto &mmio = root["mmio"];484auto &mcu = root["mcu"];485auto &dcu = root["dcu"];486auto &rtc = root["rtc"];487488ram_size = numeral(ram["size"].data);489for(auto &node : ram) {490if(node.name != "map") continue;491Mapping m({ &SPC7110::ram_read, &spc7110 }, { &SPC7110::ram_write, &spc7110 });492parse_markup_map(m, node);493mapping.append(m);494}495496for(auto &node : mmio) {497if(node.name != "map") continue;498Mapping m({ &SPC7110::mmio_read, &spc7110 }, { &SPC7110::mmio_write, &spc7110 });499parse_markup_map(m, node);500mapping.append(m);501}502503spc7110.data_rom_offset = numeral(mcu["offset"].data);504if(spc7110.data_rom_offset == 0) spc7110.data_rom_offset = 0x100000;505for(auto &node : mcu) {506if(node.name != "map") continue;507Mapping m({ &SPC7110::mcu_read, &spc7110 }, { &SPC7110::mcu_write, &spc7110 });508parse_markup_map(m, node);509mapping.append(m);510}511512for(auto &node : dcu) {513if(node.name != "map") continue;514Mapping m({ &SPC7110::dcu_read, &spc7110 }, { &SPC7110::dcu_write, &spc7110 });515parse_markup_map(m, node);516mapping.append(m);517}518519for(auto &node : rtc) {520if(node.name != "map") continue;521Mapping m({ &SPC7110::mmio_read, &spc7110 }, { &SPC7110::mmio_write, &spc7110 });522parse_markup_map(m, node);523mapping.append(m);524}525}526527void Cartridge::parse_markup_obc1(XML::Node &root) {528if(root.exists() == false) return;529has_obc1 = true;530531for(auto &node : root) {532if(node.name != "map") continue;533Mapping m({ &OBC1::read, &obc1 }, { &OBC1::write, &obc1 });534parse_markup_map(m, node);535mapping.append(m);536}537}538539void Cartridge::parse_markup_msu1(XML::Node &root) {540if(root.exists() == false) {541has_msu1 = file::exists(interface()->path(Cartridge::Slot::Base, "msu1.rom"));542if(has_msu1) {543Mapping m({ &MSU1::mmio_read, &msu1 }, { &MSU1::mmio_write, &msu1 });544m.banklo = 0x00, m.bankhi = 0x3f, m.addrlo = 0x2000, m.addrhi = 0x2007;545mapping.append(m);546m.banklo = 0x80, m.bankhi = 0xbf, m.addrlo = 0x2000, m.addrhi = 0x2007;547mapping.append(m);548}549return;550}551552has_msu1 = true;553554for(auto &node : root) {555if(node.name != "map") continue;556Mapping m({ &MSU1::mmio_read, &msu1 }, { &MSU1::mmio_write, &msu1 });557parse_markup_map(m, node);558mapping.append(m);559}560}561562void Cartridge::parse_markup_link(XML::Node &root) {563if(root.exists() == false) return;564has_link = true;565566link.frequency = max(1, numeral(root["frequency"].data));567link.program = root["program"].data;568569for(auto &node : root) {570if(node.name != "map") continue;571Mapping m({ &Link::read, &link }, { &Link::write, &link });572parse_markup_map(m, node);573mapping.append(m);574}575}576577Cartridge::Mapping::Mapping() {578mode = Bus::MapMode::Direct;579banklo = bankhi = addrlo = addrhi = offset = size = 0;580}581582Cartridge::Mapping::Mapping(Memory &memory) {583read = { &Memory::read, &memory };584write = { &Memory::write, &memory };585mode = Bus::MapMode::Direct;586banklo = bankhi = addrlo = addrhi = offset = size = 0;587}588589Cartridge::Mapping::Mapping(const function<uint8 (unsigned)> &read_, const function<void (unsigned, uint8)> &write_) {590read = read_;591write = write_;592mode = Bus::MapMode::Direct;593banklo = bankhi = addrlo = addrhi = offset = size = 0;594}595596#endif597598599