Update to higan and icarus v095r15 release.

r13 and r14 weren't posted as individual releases, but their changelogs
were posted.

byuu says about r13:

    I'm not going to be posting WIPs for r13 and above for a while.

    The reason is that I'm working on the major manifest overhaul I've
    discussed previously on the icarus subforum.

    I'm recreating my boards database from scratch using the map files
    and the new map analyzer. The only games that will load are ones
    I've created board definitions for, and updated
    sfc/cartridge/markup.cpp to parse. Once I've finished all the
    boards, then I'll update the heuristics.

    Then finally, I'll sync the syntax changes over to the fc, gb, gba
    cores.

    Once that's done, I'll start posting WIPs again, along with a new
    build of icarus.

    But I'll still post changelogs as I work through things.

    Changelog (r13):
    - preservation: created new database-builder tool (merges
      region-specific databases with boards)
    - icarus: support new, external database format
      (~/.config/icarus/Database/(Super Famicom.bml, ...)
    - added 1A3B-(10,11,12); 1A3B-20

byuu says about r14:

    r14 work:

    I successfully created mappings for every board used in the US set.

    I also updated icarus' heuristics to use the new mappings, and
    created ones there for the boards that are only in the JP set.

    Then I patched icarus to support pulling games out of the database
    when it's used on a game folder to generate a manifest file.

    Then I updated a lot of code in higan/sfc to support the new mapping
    syntax. sfc/cartridge/markup.cpp is about half the size it used to
    be with the new mappings, and I was able to kill off both map/id and
    map/select entirely.

    Then I updated all four emulated systems (and both subsystems) to
    use "board" as the root node, and harmonized their syntax (made them
    all more consistent with each other.)

    Then I added a manifest viewer to the tools window+menu. It's kind
    of an advanced user feature, but oh well. No reason to coddle people
    when the feature is very useful for developers. The viewer will show
    all manifests in order when you load multi-cart games as well.

    Still not going to call any syntax 100% done right now, but
    thankfully with the new manifest-free folders, nobody will have to
    do anything to use the new format. Just download the new version and
    go.

    The Super Famicom Event stuff is currently broken (CC92/PF94
    boards). That's gonna be fun to support.

byuu says about r15:

    EDIT: small bug in icarus with heuristics. Edit
    core/super-famicom.cpp line 27:

	if(/*auto*/ markup = cartridge.markup) {

    Gotta remove that "auto" so that it returns valid markup.

    Resolved the final concerns I had with the new manifest format.

    Right now there are two things that are definitely broken: MCC (BS-X
    Town cart) and Event (CC '92 and PF'94).
    And there are a few things that are untested: SPC7110, EpsonRTC,
    SharpRTC, SDD1+RAM, SufamiTurbo, BS-X slotted carts.
This commit is contained in:
Tim Allen 2015-12-19 19:52:34 +11:00
parent 2c53d5fbc0
commit bd628de3cf
56 changed files with 787 additions and 14430 deletions

View File

@ -7,7 +7,7 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "higan"; static const string Name = "higan";
static const string Version = "095.12"; static const string Version = "095.15";
static const string Author = "byuu"; static const string Author = "byuu";
static const string License = "GPLv3"; static const string License = "GPLv3";
static const string Website = "http://byuu.org/"; static const string Website = "http://byuu.org/";

View File

@ -75,6 +75,7 @@ struct Interface {
template<typename... P> auto notify(P&&... p) -> void { return bind->notify({forward<P>(p)...}); } template<typename... P> auto notify(P&&... p) -> void { return bind->notify({forward<P>(p)...}); }
//information //information
virtual auto manifest() -> string = 0;
virtual auto title() -> string = 0; virtual auto title() -> string = 0;
virtual auto videoFrequency() -> double = 0; virtual auto videoFrequency() -> double = 0;
virtual auto audioFrequency() -> double = 0; virtual auto audioFrequency() -> double = 0;

View File

@ -21,15 +21,15 @@
Board::Board(Markup::Node& document) { Board::Board(Markup::Node& document) {
cartridge.board = this; cartridge.board = this;
auto cartridge = document["cartridge"]; auto board = document["board"];
information.type = cartridge["board/type"].text(); information.type = board["id"].text();
information.battery = (bool)cartridge["prg/ram/name"]; information.battery = (bool)board["prg/ram/name"];
auto prom = cartridge["prg/rom"]; auto prom = board["prg/rom"];
auto pram = cartridge["prg/ram"]; auto pram = board["prg/ram"];
auto crom = cartridge["chr/rom"]; auto crom = board["chr/rom"];
auto cram = cartridge["chr/ram"]; auto cram = board["chr/ram"];
prgrom.size = prom["size"].natural(); prgrom.size = prom["size"].natural();
prgram.size = pram["size"].natural(); prgram.size = pram["size"].natural();
@ -120,7 +120,7 @@ auto Board::load(string manifest) -> Board* {
auto document = BML::unserialize(manifest); auto document = BML::unserialize(manifest);
cartridge.information.title = document["information/title"].text(); cartridge.information.title = document["information/title"].text();
string type = document["cartridge/board/type"].text(); string type = document["board/id"].text();
if(type == "BANDAI-FCG" ) return new BandaiFCG(document); if(type == "BANDAI-FCG" ) return new BandaiFCG(document);

View File

@ -14,6 +14,10 @@ auto Cartridge::sha256() const -> string {
return _sha256; return _sha256;
} }
auto Cartridge::manifest() const -> string {
return information.markup;
}
auto Cartridge::title() const -> string { auto Cartridge::title() const -> string {
return information.title; return information.title;
} }

View File

@ -7,6 +7,7 @@ struct Cartridge : Thread {
auto loaded() const -> bool; auto loaded() const -> bool;
auto sha256() const -> string; auto sha256() const -> string;
auto manifest() const -> string;
auto title() const -> string; auto title() const -> string;
auto load() -> void; auto load() -> void;

View File

@ -43,6 +43,10 @@ Interface::Interface() {
} }
} }
auto Interface::manifest() -> string {
return cartridge.manifest();
}
auto Interface::title() -> string { auto Interface::title() -> string {
return cartridge.title(); return cartridge.title();
} }

View File

@ -27,6 +27,7 @@ struct ID {
struct Interface : Emulator::Interface { struct Interface : Emulator::Interface {
Interface(); Interface();
auto manifest() -> string;
auto title() -> string; auto title() -> string;
auto videoFrequency() -> double; auto videoFrequency() -> double;
auto audioFrequency() -> double; auto audioFrequency() -> double;

View File

@ -22,7 +22,11 @@ Cartridge::~Cartridge() {
unload(); unload();
} }
auto Cartridge::title() -> string { auto Cartridge::manifest() const -> string {
return information.markup;
}
auto Cartridge::title() const -> string {
return information.title; return information.title;
} }
@ -58,7 +62,7 @@ auto Cartridge::load(System::Revision revision) -> void {
auto document = BML::unserialize(information.markup); auto document = BML::unserialize(information.markup);
information.title = document["information/title"].text(); information.title = document["information/title"].text();
auto mapperid = document["cartridge/board/type"].text(); auto mapperid = document["board/mapper"].text();
if(mapperid == "none" ) information.mapper = Mapper::MBC0; if(mapperid == "none" ) information.mapper = Mapper::MBC0;
if(mapperid == "MBC1" ) information.mapper = Mapper::MBC1; if(mapperid == "MBC1" ) information.mapper = Mapper::MBC1;
if(mapperid == "MBC2" ) information.mapper = Mapper::MBC2; if(mapperid == "MBC2" ) information.mapper = Mapper::MBC2;
@ -71,8 +75,8 @@ auto Cartridge::load(System::Revision revision) -> void {
information.rtc = false; information.rtc = false;
information.rumble = false; information.rumble = false;
auto rom = document["cartridge/rom"]; auto rom = document["board/rom"];
auto ram = document["cartridge/ram"]; auto ram = document["board/ram"];
romsize = rom["size"].natural(); romsize = rom["size"].natural();
romdata = allocate<uint8>(romsize, 0xff); romdata = allocate<uint8>(romsize, 0xff);

View File

@ -53,7 +53,8 @@ struct Cartridge : MMIO, property<Cartridge> {
uint ramsize; uint ramsize;
} information; } information;
string title(); auto manifest() const -> string;
auto title() const -> string;
struct Memory { struct Memory {
uint id; uint id;

View File

@ -37,6 +37,10 @@ Interface::Interface() {
port.append({0, "Device", {device[0]}}); port.append({0, "Device", {device[0]}});
} }
auto Interface::manifest() -> string {
return cartridge.manifest();
}
auto Interface::title() -> string { auto Interface::title() -> string {
return cartridge.title(); return cartridge.title();
} }

View File

@ -29,6 +29,7 @@ struct ID {
struct Interface : Emulator::Interface { struct Interface : Emulator::Interface {
Interface(); Interface();
auto manifest() -> string;
auto title() -> string; auto title() -> string;
auto videoFrequency() -> double; auto videoFrequency() -> double;
auto audioFrequency() -> double; auto audioFrequency() -> double;

View File

@ -31,6 +31,10 @@ auto Cartridge::sha256() const -> string {
return information.sha256; return information.sha256;
} }
auto Cartridge::manifest() const -> string {
return information.markup;
}
auto Cartridge::title() const -> string { auto Cartridge::title() const -> string {
return information.title; return information.title;
} }
@ -45,48 +49,50 @@ auto Cartridge::load() -> void {
hasEEPROM = false; hasEEPROM = false;
hasFLASH = false; hasFLASH = false;
if(auto info = document["cartridge/mrom"]) { if(auto info = document["board/rom"]) {
mrom.size = min(32 * 1024 * 1024, info["size"].natural()); mrom.size = min(32 * 1024 * 1024, info["size"].natural());
interface->loadRequest(ID::MROM, info["name"].text(), true); interface->loadRequest(ID::MROM, info["name"].text(), true);
} }
if(auto info = document["cartridge/sram"]) { if(auto info = document["board/ram"]) {
hasSRAM = true; if(info["type"].text() == "sram") {
sram.size = min(32 * 1024, info["size"].natural()); hasSRAM = true;
sram.mask = sram.size - 1; sram.size = min(32 * 1024, info["size"].natural());
for(auto n : range(sram.size)) sram.data[n] = 0xff; sram.mask = sram.size - 1;
for(auto n : range(sram.size)) sram.data[n] = 0xff;
interface->loadRequest(ID::SRAM, info["name"].text(), false); interface->loadRequest(ID::SRAM, info["name"].text(), false);
memory.append({ID::SRAM, info["name"].text()}); memory.append({ID::SRAM, info["name"].text()});
} }
if(auto info = document["cartridge/eeprom"]) { if(info["type"].text() == "eeprom") {
hasEEPROM = true; hasEEPROM = true;
eeprom.size = min(8 * 1024, info["size"].natural()); eeprom.size = min(8 * 1024, info["size"].natural());
eeprom.bits = eeprom.size <= 512 ? 6 : 14; eeprom.bits = eeprom.size <= 512 ? 6 : 14;
if(eeprom.size == 0) eeprom.size = 8192, eeprom.bits = 0; //auto-detect size if(eeprom.size == 0) eeprom.size = 8192, eeprom.bits = 0; //auto-detect size
eeprom.mask = mrom.size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000; eeprom.mask = mrom.size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000;
eeprom.test = mrom.size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000; eeprom.test = mrom.size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
for(auto n : range(eeprom.size)) eeprom.data[n] = 0xff; for(auto n : range(eeprom.size)) eeprom.data[n] = 0xff;
interface->loadRequest(ID::EEPROM, info["name"].text(), false); interface->loadRequest(ID::EEPROM, info["name"].text(), false);
memory.append({ID::EEPROM, info["name"].text()}); memory.append({ID::EEPROM, info["name"].text()});
} }
if(auto info = document["cartridge/flash"]) { if(info["type"].text() == "flash") {
hasFLASH = true; hasFLASH = true;
flash.id = info["id"].natural(); flash.id = info["id"].natural();
flash.size = min(128 * 1024, info["size"].natural()); flash.size = min(128 * 1024, info["size"].natural());
for(auto n : range(flash.size)) flash.data[n] = 0xff; for(auto n : range(flash.size)) flash.data[n] = 0xff;
//if flash ID not provided; guess that it's a Macronix chip //if flash ID not provided; guess that it's a Macronix chip
//this will not work for all games; in which case, the ID must be specified manually //this will not work for all games; in which case, the ID must be specified manually
if(!flash.id && flash.size == 64 * 1024) flash.id = 0x1cc2; if(!flash.id && flash.size == 64 * 1024) flash.id = 0x1cc2;
if(!flash.id && flash.size == 128 * 1024) flash.id = 0x09c2; if(!flash.id && flash.size == 128 * 1024) flash.id = 0x09c2;
interface->loadRequest(ID::FLASH, info["name"].text(), false); interface->loadRequest(ID::FLASH, info["name"].text(), false);
memory.append({ID::FLASH, info["name"].text()}); memory.append({ID::FLASH, info["name"].text()});
}
} }
information.sha256 = Hash::SHA256(mrom.data, mrom.size).digest(); information.sha256 = Hash::SHA256(mrom.data, mrom.size).digest();

View File

@ -3,6 +3,7 @@ struct Cartridge {
auto loaded() const -> bool; auto loaded() const -> bool;
auto sha256() const -> string; auto sha256() const -> string;
auto manifest() const -> string;
auto title() const -> string; auto title() const -> string;
struct Information { struct Information {

View File

@ -37,6 +37,10 @@ Interface::Interface() {
port.append({0, "Device", {device[0]}}); port.append({0, "Device", {device[0]}});
} }
auto Interface::manifest() -> string {
return cartridge.manifest();
}
auto Interface::title() -> string { auto Interface::title() -> string {
return cartridge.title(); return cartridge.title();
} }

View File

@ -27,6 +27,7 @@ struct ID {
struct Interface : Emulator::Interface { struct Interface : Emulator::Interface {
Interface(); Interface();
auto manifest() -> string;
auto title() -> string; auto title() -> string;
auto videoFrequency() -> double; auto videoFrequency() -> double;
auto audioFrequency() -> double; auto audioFrequency() -> double;

View File

@ -22,6 +22,7 @@ auto mMenuCheckItem::onToggle(const function<void ()>& callback) -> type& {
auto mMenuCheckItem::setChecked(bool checked) -> type& { auto mMenuCheckItem::setChecked(bool checked) -> type& {
state.checked = checked; state.checked = checked;
signal(setChecked, checked); signal(setChecked, checked);
return *this;
} }
auto mMenuCheckItem::setText(const string& text) -> type& { auto mMenuCheckItem::setText(const string& text) -> type& {

View File

@ -9,7 +9,7 @@ Hotkey::Hotkey(const string& sequence) : state(new Hotkey::State) {
} }
Hotkey::operator bool() const { Hotkey::operator bool() const {
return state->sequence; return (bool)state->sequence;
} }
auto Hotkey::operator==(const Hotkey& source) const -> bool { auto Hotkey::operator==(const Hotkey& source) const -> bool {

View File

@ -9,6 +9,7 @@ auto pSizable::destruct() -> void {
} }
auto pSizable::minimumSize() const -> Size { auto pSizable::minimumSize() const -> Size {
return {0, 0};
} }
auto pSizable::setGeometry(Geometry geometry) -> void { auto pSizable::setGeometry(Geometry geometry) -> void {

View File

@ -1,13 +1,5 @@
namespace Database {
#include "../database/super-famicom.hpp"
#include "../database/bsx-satellaview.hpp"
#include "../database/sufami-turbo.hpp"
}
Icarus::Icarus() { Icarus::Icarus() {
database.superFamicom = BML::unserialize(Database::SuperFamicom); database.superFamicom = BML::unserialize(string::read(locate({configpath(), "icarus/"}, "Database/Super Famicom.bml")));
database.bsxSatellaview = BML::unserialize(Database::BsxSatellaview);
database.sufamiTurbo = BML::unserialize(Database::SufamiTurbo);
} }
auto Icarus::error() const -> string { auto Icarus::error() const -> string {

View File

@ -19,8 +19,8 @@ struct Icarus {
//super-famicom.cpp //super-famicom.cpp
auto superFamicomManifest(const string& location) -> string; auto superFamicomManifest(const string& location) -> string;
auto superFamicomManifest(vector<uint8_t>& buffer, const string& location) -> string; auto superFamicomManifest(vector<uint8_t>& buffer, const string& location) -> string;
auto superFamicomManifestScan(vector<Markup::Node>& roms, Markup::Node node) -> void;
auto superFamicomImport(vector<uint8_t>& buffer, const string& location) -> bool; auto superFamicomImport(vector<uint8_t>& buffer, const string& location) -> bool;
auto superFamicomImportScanManifest(vector<Markup::Node>& roms, Markup::Node node) -> void;
//game-boy.cpp //game-boy.cpp
auto gameBoyManifest(const string& location) -> string; auto gameBoyManifest(const string& location) -> string;

View File

@ -10,16 +10,36 @@ auto Icarus::superFamicomManifest(const string& location) -> string {
} }
auto Icarus::superFamicomManifest(vector<uint8_t>& buffer, const string& location) -> string { auto Icarus::superFamicomManifest(vector<uint8_t>& buffer, const string& location) -> string {
SuperFamicomCartridge cartridge{buffer.data(), buffer.size()}; string markup;
if(auto markup = cartridge.markup) {
markup.append("\n"); if(settings["icarus/UseDatabase"].boolean() && !markup) {
markup.append("information\n"); auto digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
markup.append(" sha256: ", Hash::SHA256(buffer.data(), buffer.size()).digest(), "\n"); for(auto node : database.superFamicom) {
markup.append(" title: ", prefixname(location), "\n"); if(node["sha256"].text() == digest) {
markup.append(" note: ", "heuristically generated by icarus\n"); markup.append(node.text(), "\n sha256: ", digest, "\n");
return markup; break;
}
}
} }
return "";
if(settings["icarus/UseHeuristics"].boolean() && !markup) {
SuperFamicomCartridge cartridge{buffer.data(), buffer.size()};
if(auto markup = cartridge.markup) {
markup.append("\n");
markup.append("information\n");
markup.append(" region: ", cartridge.region == SuperFamicomCartridge::Region::NTSC ? "NTSC" : "PAL", "\n");
markup.append(" title: ", prefixname(location), "\n");
markup.append(" sha256: ", Hash::SHA256(buffer.data(), buffer.size()).digest(), "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
}
}
return markup;
}
auto Icarus::superFamicomManifestScan(vector<Markup::Node>& roms, Markup::Node node) -> void {
if(node["name"].text().endsWith(".rom")) roms.append(node);
for(auto leaf : node) superFamicomManifestScan(roms, leaf);
} }
auto Icarus::superFamicomImport(vector<uint8_t>& buffer, const string& location) -> bool { auto Icarus::superFamicomImport(vector<uint8_t>& buffer, const string& location) -> bool {
@ -29,16 +49,13 @@ auto Icarus::superFamicomImport(vector<uint8_t>& buffer, const string& location)
//if(directory::exists(target)) return failure("game already exists"); //if(directory::exists(target)) return failure("game already exists");
string markup; string markup;
vector<Markup::Node> roms;
bool firmwareAppended = true; bool firmwareAppended = true;
if(settings["icarus/UseDatabase"].boolean() && !markup) { if(settings["icarus/UseDatabase"].boolean() && !markup) {
auto digest = Hash::SHA256(buffer.data(), buffer.size()).digest(); auto digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
for(auto node : database.superFamicom) { for(auto node : database.superFamicom) {
if(node.name() != "release") continue; if(node["sha256"].text() == digest) {
if(node["information/sha256"].text() == digest) { markup.append(node.text(), "\n sha256: ", digest, "\n");
markup.append(BML::serialize(node["cartridge"]), "\n");
markup.append(BML::serialize(node["information"]));
break; break;
} }
} }
@ -50,13 +67,16 @@ auto Icarus::superFamicomImport(vector<uint8_t>& buffer, const string& location)
firmwareAppended = cartridge.firmware_appended; firmwareAppended = cartridge.firmware_appended;
markup.append("\n"); markup.append("\n");
markup.append("information\n"); markup.append("information\n");
markup.append(" title: ", name, "\n"); markup.append(" region: ", cartridge.region == SuperFamicomCartridge::Region::NTSC ? "NTSC" : "PAL", "\n");
markup.append(" note: ", "heuristically generated by icarus\n"); markup.append(" title: ", name, "\n");
markup.append(" sha256: ", Hash::SHA256(buffer.data(), buffer.size()).digest(), "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
} }
} }
auto document = BML::unserialize(markup); auto document = BML::unserialize(markup);
superFamicomImportScanManifest(roms, document["cartridge"]); vector<Markup::Node> roms;
superFamicomManifestScan(roms, document["board"]);
for(auto rom : roms) { for(auto rom : roms) {
auto name = rom["name"].text(); auto name = rom["name"].text();
auto size = rom["size"].natural(); auto size = rom["size"].natural();
@ -68,7 +88,7 @@ auto Icarus::superFamicomImport(vector<uint8_t>& buffer, const string& location)
if(!directory::create(target)) return failure("library path unwritable"); if(!directory::create(target)) return failure("library path unwritable");
if(settings["icarus/CreateManifests"].boolean()) file::write({target, "manifest.bml"}, markup); if(settings["icarus/CreateManifests"].boolean()) file::write({target, "manifest.bml"}, markup);
unsigned offset = (buffer.size() & 0x7fff) == 512 ? 512 : 0; //skip header if present uint offset = (buffer.size() & 0x7fff) == 512 ? 512 : 0; //skip header if present
for(auto rom : roms) { for(auto rom : roms) {
auto name = rom["name"].text(); auto name = rom["name"].text();
auto size = rom["size"].natural(); auto size = rom["size"].natural();
@ -83,8 +103,3 @@ auto Icarus::superFamicomImport(vector<uint8_t>& buffer, const string& location)
} }
return success(); return success();
} }
auto Icarus::superFamicomImportScanManifest(vector<Markup::Node>& roms, Markup::Node node) -> void {
if(node.name() == "rom") roms.append(node);
for(auto leaf : node) superFamicomImportScanManifest(roms, leaf);
}

View File

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

View File

@ -1,162 +0,0 @@
string SufamiTurbo = R"(
database revision=2013-01-22
release
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
information
title: SDウルトラバトル
name: SD Ultra Battle - Ultraman Densetsu
region: JP
revision: 1.0
serial: SFT-0101-JPN
sha256: 2bb55214fb668ca603d7b944b14f105dfb10b987a8902d420fe4ae1cb69c1d4a
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
linkable
release
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
information
title: SDウルトラバトル
name: SD Ultra Battle - Seven Densetsu
region: JP
revision: 1.0
serial: SFT-0102-JPN
sha256: 2fec5f2bc7dee010af10569a3d2bc18715a79a126940800c3eade5abbd625e3f
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
linkable
release
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
information
title:
name: Poi Poi Ninja World
region: JP
revision: 1.0
serial: SFT-0103-JPN
sha256: 602b20b788640f5743487108a10f3f77bca5ce2d24208b25b1ca498a96eb0d69
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
linkable
release
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
information
title: SDガンダムジェネレーション
name: SD Gundam Generation - Ichinen Sensouki
region: JP
revision: 1.0
serial: SFT-0104-JPN
sha256: 3e82215bed08274874b30d461fc4a965c6bca932229da5d46d56e36f484d65eb
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
linkable
release
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
information
title: SDガンダムジェネレーション
name: SD Gundam Generation - Grips Senki
region: JP
revision: 1.0
serial: SFT-0105-JPN
sha256: 8547a08ed11fe408eac282a90ac46654bd2e5f49bda3aec8e5edf166a0a4b9af
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
linkable
release
cartridge
rom name=program.rom size=0x80000
information
title:
name: Gegege no Kitarou - Youkai Donjara
region: JP
revision: 1.0
serial: SFT-0106-JPN
sha256: d93b3a570e7cf343f680ab0768a50b77e3577f9c555007e2de3decd6bc4765c8
configuration
rom name=program.rom size=0x80000
release
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
information
title: SDガンダムジェネレーション
name: SD Gundam Generation - Axis Senki
region: JP
revision: 1.0
serial: SFT-0107-JPN
sha256: 2a9d7c9a61318861028a73ca03e32a48cff162d76cba36fbaab8690b212efe9b
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
linkable
release
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
information
title: SDガンダムジェネレーション
name: SD Gundam Generation - Babylonia Kenkoku Senki
region: JP
revision: 1.0
serial: SFT-0108-JPN
sha256: 60ac017c18f534e8cf24ca7f38e22ce92db95ea6c30b2d59d76f13c4f1c8a6e4
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
linkable
release
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
information
title: SDガンダムジェネレーション
name: SD Gundam Generation - Zanscar Senki
region: JP
revision: 1.0
serial: SFT-0110-JPN
sha256: 5951a58a91d8e397d0a237ccc2b1248e17c7312cb9cc11cbc350200a97b4e021
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x2000
linkable
release
cartridge linkable
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
information
title: SDガンダムジェネレーション
name: SD Gundam Generation - Colony Kakutouki
region: JP
revision: 1.0
serial: SFT-0111-JPN
sha256: e639b5d5d722432b6809ccc6801dc584e1a3016379f34b335ed2dfa73b1ebf69
configuration
rom name=program.rom size=0x80000
ram name=save.ram size=0x800
linkable
)";

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,6 @@ struct BsxSatellaviewCartridge {
}; };
BsxSatellaviewCartridge::BsxSatellaviewCartridge(const uint8_t* data, unsigned size) { BsxSatellaviewCartridge::BsxSatellaviewCartridge(const uint8_t* data, unsigned size) {
markup.append("cartridge\n"); markup.append("board\n");
markup.append(" rom name=program.rom size=0x", hex(size), " type=FlashROM\n"); markup.append(" rom type=flash name=program.rom size=0x", hex(size), "\n");
} }

View File

@ -1,18 +1,18 @@
struct FamicomCartridge { struct FamicomCartridge {
FamicomCartridge(const uint8_t* data, unsigned size); FamicomCartridge(const uint8* data, uint size);
string markup; string markup;
//private: //private:
unsigned mapper; uint mapper;
unsigned mirror; uint mirror;
unsigned prgrom; uint prgrom;
unsigned prgram; uint prgram;
unsigned chrrom; uint chrrom;
unsigned chrram; uint chrram;
}; };
FamicomCartridge::FamicomCartridge(const uint8_t* data, unsigned size) { FamicomCartridge::FamicomCartridge(const uint8* data, uint size) {
if(size < 16) return; if(size < 16) return;
if(data[0] != 'N') return; if(data[0] != 'N') return;
if(data[1] != 'E') return; if(data[1] != 'E') return;
@ -26,65 +26,65 @@ FamicomCartridge::FamicomCartridge(const uint8_t* data, unsigned size) {
prgram = 0u; prgram = 0u;
chrram = chrrom == 0u ? 8192u : 0u; chrram = chrrom == 0u ? 8192u : 0u;
markup.append("cartridge\n"); markup.append("board ");
switch(mapper) { switch(mapper) {
default: default:
markup.append(" board type=NES-NROM-256\n"); markup.append("id:NES-NROM-256\n");
markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n");
break; break;
case 1: case 1:
markup.append(" board type=NES-SXROM\n"); markup.append("id:NES-SXROM\n");
markup.append(" chip type=MMC1B2\n"); markup.append(" chip type=MMC1B2\n");
prgram = 8192; prgram = 8192;
break; break;
case 2: case 2:
markup.append(" board type=NES-UOROM\n"); markup.append("id:NES-UOROM\n");
markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n");
break; break;
case 3: case 3:
markup.append(" board type=NES-CNROM\n"); markup.append("id:NES-CNROM\n");
markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n");
break; break;
case 4: case 4:
//MMC3 //MMC3
markup.append(" board type=NES-TLROM\n"); markup.append("id:NES-TLROM\n");
markup.append(" chip type=MMC3B\n"); markup.append(" chip type=MMC3B\n");
prgram = 8192; prgram = 8192;
//MMC6 //MMC6
//markup.append(" board type=NES-HKROM\n"); //markup.append("id:NES-HKROM\n");
//markup.append(" chip type=MMC6n"); //markup.append(" chip type=MMC6n");
//prgram = 1024; //prgram = 1024;
break; break;
case 5: case 5:
markup.append(" board type=NES-ELROM\n"); markup.append("id:NES-ELROM\n");
markup.append(" chip type=MMC5\n"); markup.append(" chip type=MMC5\n");
prgram = 65536; prgram = 65536;
break; break;
case 7: case 7:
markup.append(" board type=NES-AOROM\n"); markup.append("id:NES-AOROM\n");
break; break;
case 9: case 9:
markup.append(" board type=NES-PNROM\n"); markup.append("id:NES-PNROM\n");
markup.append(" chip type=MMC2\n"); markup.append(" chip type=MMC2\n");
prgram = 8192; prgram = 8192;
break; break;
case 10: case 10:
markup.append(" board type=NES-FKROM\n"); markup.append("id:NES-FKROM\n");
markup.append(" chip type=MMC4\n"); markup.append(" chip type=MMC4\n");
prgram = 8192; prgram = 8192;
break; break;
case 16: case 16:
markup.append(" board type=BANDAI-FCG\n"); markup.append("id:BANDAI-FCG\n");
markup.append(" chip type=LZ93D50\n"); markup.append(" chip type=LZ93D50\n");
break; break;
@ -92,7 +92,7 @@ FamicomCartridge::FamicomCartridge(const uint8_t* data, unsigned size) {
case 23: case 23:
case 25: case 25:
//VRC4 //VRC4
markup.append(" board type=KONAMI-VRC-4\n"); markup.append("id:KONAMI-VRC-4\n");
markup.append(" chip type=VRC4\n"); markup.append(" chip type=VRC4\n");
markup.append(" pinout a0=1 a1=0\n"); markup.append(" pinout a0=1 a1=0\n");
prgram = 8192; prgram = 8192;
@ -100,52 +100,52 @@ FamicomCartridge::FamicomCartridge(const uint8_t* data, unsigned size) {
case 22: case 22:
//VRC2 //VRC2
markup.append(" board type=KONAMI-VRC-2\n"); markup.append("id:KONAMI-VRC-2\n");
markup.append(" chip type=VRC2\n"); markup.append(" chip type=VRC2\n");
markup.append(" pinout a0=0 a1=1\n"); markup.append(" pinout a0=0 a1=1\n");
break; break;
case 24: case 24:
markup.append(" board type=KONAMI-VRC-6\n"); markup.append("id:KONAMI-VRC-6\n");
markup.append(" chip type=VRC6\n"); markup.append(" chip type=VRC6\n");
break; break;
case 26: case 26:
markup.append(" board type=KONAMI-VRC-6\n"); markup.append("id:KONAMI-VRC-6\n");
markup.append(" chip type=VRC6\n"); markup.append(" chip type=VRC6\n");
prgram = 8192; prgram = 8192;
break; break;
case 34: case 34:
markup.append(" board type=NES-BNROM\n"); markup.append("id:NES-BNROM\n");
markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n");
break; break;
case 66: case 66:
markup.append(" board type=NES-GNROM\n"); markup.append("id:NES-GNROM\n");
markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n");
break; break;
case 69: case 69:
markup.append(" board type=SUNSOFT-5B\n"); markup.append("id:SUNSOFT-5B\n");
markup.append(" chip type=5B\n"); markup.append(" chip type=5B\n");
prgram = 8192; prgram = 8192;
break; break;
case 73: case 73:
markup.append(" board type=KONAMI-VRC-3\n"); markup.append("id:KONAMI-VRC-3\n");
markup.append(" chip type=VRC3\n"); markup.append(" chip type=VRC3\n");
markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n");
prgram = 8192; prgram = 8192;
break; break;
case 75: case 75:
markup.append(" board type=KONAMI-VRC-1\n"); markup.append("id:KONAMI-VRC-1\n");
markup.append(" chip type=VRC1\n"); markup.append(" chip type=VRC1\n");
break; break;
case 85: case 85:
markup.append(" board type=KONAMI-VRC-7\n"); markup.append("id:KONAMI-VRC-7\n");
markup.append(" chip type=VRC7\n"); markup.append(" chip type=VRC7\n");
prgram = 8192; prgram = 8192;
break; break;

View File

@ -37,14 +37,14 @@ GameBoyAdvanceCartridge::GameBoyAdvanceCartridge(const uint8_t *data, unsigned s
} }
identifiers = list.merge(","); identifiers = list.merge(",");
markup.append("cartridge\n"); markup.append("board\n");
markup.append(" mrom name=program.rom size=0x", hex(size), "\n"); markup.append(" rom type=mrom name=program.rom size=0x", hex(size), "\n");
if(0); if(0);
else if(identifiers.beginsWith("SRAM_V" )) markup.append(" sram name=save.ram size=0x8000\n"); else if(identifiers.beginsWith("SRAM_V" )) markup.append(" ram type=sram name=save.ram size=0x8000\n");
else if(identifiers.beginsWith("SRAM_F_V" )) markup.append(" sram name=save.ram size=0x8000\n"); else if(identifiers.beginsWith("SRAM_F_V" )) markup.append(" ram type=sram name=save.ram size=0x8000\n");
else if(identifiers.beginsWith("EEPROM_V" )) markup.append(" eeprom name=save.ram size=0x0\n"); else if(identifiers.beginsWith("EEPROM_V" )) markup.append(" ram type=eeprom name=save.ram size=0x0\n");
else if(identifiers.beginsWith("FLASH_V" )) markup.append(" flash name=save.ram size=0x10000\n"); else if(identifiers.beginsWith("FLASH_V" )) markup.append(" ram type=flash name=save.ram size=0x10000\n");
else if(identifiers.beginsWith("FLASH512_V")) markup.append(" flash name=save.ram size=0x10000\n"); else if(identifiers.beginsWith("FLASH512_V")) markup.append(" ram type=flash name=save.ram size=0x10000\n");
else if(identifiers.beginsWith("FLASH1M_V" )) markup.append(" flash name=save.ram size=0x20000\n"); else if(identifiers.beginsWith("FLASH1M_V" )) markup.append(" ram type=flash name=save.ram size=0x20000\n");
//if(identifiers.empty() == false) markup.append(" #detected: ", identifiers, "\n"); //if(identifiers) markup.append(" #detected: ", identifiers, "\n");
} }

View File

@ -100,8 +100,7 @@ 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
markup.append("cartridge\n"); markup.append("board mapper=", info.mapper, "\n");
markup.append(" board type=", info.mapper, "\n");
markup.append(" rom name=program.rom size=0x", hex(romsize), "\n"); markup.append(" rom name=program.rom size=0x", hex(romsize), "\n");
if(info.ramsize > 0) markup.append(" ram name=save.ram size=0x", hex(info.ramsize), "\n"); if(info.ramsize > 0) markup.append(" ram name=save.ram size=0x", hex(info.ramsize), "\n");
} }

View File

@ -11,7 +11,7 @@ SufamiTurboCartridge::SufamiTurboCartridge(const uint8_t* data, unsigned size) {
unsigned ramsize = data[0x37] * 0x800; //2KB unsigned ramsize = data[0x37] * 0x800; //2KB
bool linkable = data[0x35] != 0x00; //TODO: unconfirmed bool linkable = data[0x35] != 0x00; //TODO: unconfirmed
markup.append("cartridge", linkable ? " linkable" : "", "\n"); markup.append("board", linkable ? " linkable" : "", "\n");
markup.append(" rom name=program.rom size=0x", hex(romsize), "\n"); markup.append(" rom name=program.rom size=0x", hex(romsize), "\n");
if(ramsize) if(ramsize)
markup.append(" ram name=save.ram size=0x", hex(ramsize), "\n"); markup.append(" ram name=save.ram size=0x", hex(ramsize), "\n");

View File

@ -1,14 +1,14 @@
struct SuperFamicomCartridge { struct SuperFamicomCartridge {
SuperFamicomCartridge(const uint8_t *data, unsigned size); SuperFamicomCartridge(const uint8* data, uint size);
string markup; string markup;
//private: //private:
auto readHeader(const uint8_t *data, unsigned size) -> void; auto readHeader(const uint8* data, uint size) -> void;
auto findHeader(const uint8_t *data, unsigned size) -> unsigned; auto findHeader(const uint8* data, uint size) -> uint;
auto scoreHeader(const uint8_t *data, unsigned size, unsigned addr) -> unsigned; auto scoreHeader(const uint8* data, uint size, uint addr) -> uint;
enum HeaderField : unsigned { enum HeaderField : uint {
CartName = 0x00, CartName = 0x00,
Mapper = 0x15, Mapper = 0x15,
RomType = 0x16, RomType = 0x16,
@ -22,7 +22,7 @@ struct SuperFamicomCartridge {
ResetVector = 0x3c, ResetVector = 0x3c,
}; };
enum Mode : unsigned { enum Mode : uint {
ModeNormal, ModeNormal,
ModeBsxSlotted, ModeBsxSlotted,
ModeBsx, ModeBsx,
@ -30,7 +30,7 @@ struct SuperFamicomCartridge {
ModeSuperGameBoy, ModeSuperGameBoy,
}; };
enum Type : unsigned { enum Type : uint {
TypeNormal, TypeNormal,
TypeBsxSlotted, TypeBsxSlotted,
TypeBsxBios, TypeBsxBios,
@ -43,12 +43,12 @@ struct SuperFamicomCartridge {
TypeUnknown, TypeUnknown,
}; };
enum Region : unsigned { enum Region : uint {
NTSC, NTSC,
PAL, PAL,
}; };
enum MemoryMapper : unsigned { enum MemoryMapper : uint {
LoROM, LoROM,
HiROM, HiROM,
ExLoROM, ExLoROM,
@ -62,17 +62,17 @@ struct SuperFamicomCartridge {
STROM, STROM,
}; };
enum DSP1MemoryMapper : unsigned { enum DSP1MemoryMapper : uint {
DSP1Unmapped, DSP1Unmapped,
DSP1LoROM1MB, DSP1LoROM1MB,
DSP1LoROM2MB, DSP1LoROM2MB,
DSP1HiROM, DSP1HiROM,
}; };
bool loaded; //is a base cartridge inserted? bool loaded; //is a base cartridge inserted?
unsigned crc32; //crc32 of all cartridges (base+slot(s)) uint crc32; //crc32 of all cartridges (base+slot(s))
unsigned rom_size; uint rom_size;
unsigned ram_size; uint ram_size;
bool firmware_required; //true if firmware is required for emulation bool firmware_required; //true if firmware is required for emulation
bool firmware_appended; //true if firmware is present at end of data bool firmware_appended; //true if firmware is present at end of data
@ -100,7 +100,7 @@ struct SuperFamicomCartridge {
bool has_st018; bool has_st018;
}; };
SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) { SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
firmware_required = false; firmware_required = false;
firmware_appended = false; firmware_appended = false;
@ -116,7 +116,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size)
if(type == TypeSufamiTurbo) return; if(type == TypeSufamiTurbo) return;
const char* range = (rom_size > 0x200000) || (ram_size > 32 * 1024) ? "0000-7fff" : "0000-ffff"; const char* range = (rom_size > 0x200000) || (ram_size > 32 * 1024) ? "0000-7fff" : "0000-ffff";
markup.append("cartridge region=", region == NTSC ? "NTSC" : "PAL", "\n"); markup.append("board cic=", region == NTSC ? "411" : "413", "\n");
//detect appended firmware //detect appended firmware
@ -197,327 +197,310 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size)
if(type == TypeSuperGameBoy1Bios || type == TypeSuperGameBoy2Bios) { if(type == TypeSuperGameBoy1Bios || type == TypeSuperGameBoy2Bios) {
markup.append( markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n" " rom name=program.rom size=0x", hex(rom_size), "\n"
" map id=rom address=00-7f,80-ff:8000-ffff mask=0x8000\n" " map address=00-7d,80-ff:8000-ffff mask=0x8000\n"
" map address=40-7d,c0-ff:0000-7fff mask=0x8000\n"
" icd2 revision=1\n" " icd2 revision=1\n"
" rom name=sgb.boot.rom size=0x100\n" " map address=00-3f,80-bf:6000-67ff,7000-7fff\n"
" map id=io address=00-3f,80-bf:6000-7fff\n" " brom name=sgb.boot.rom size=0x100\n"
); );
} }
else if(has_cx4) { else if(has_cx4) {
markup.append( markup.append(
" hitachidsp model=HG51B169 frequency=20000000\n" " hitachidsp model=HG51B169 frequency=20000000\n"
" rom id=program name=program.rom size=0x", hex(rom_size), "\n" " map address=00-3f,80-bf:6c00-6fff,7c00-7fff\n"
" rom id=data name=cx4.data.rom size=0xc00\n" " rom name=program.rom size=0x", hex(rom_size), "\n"
" ram id=data size=0xc00\n" " map address=00-3f,80-bf:8000-ffff mask=0x8000\n"
" map id=io address=00-3f,80-bf:6000-7fff\n" " ram name=save.ram size=0\n"
" map id=rom address=00-7f,80-ff:8000-ffff mask=0x8000\n" " map address=70-77:0000-7fff mask=0x8000\n"
" map id=ram address=70-77:0000-7fff\n" " drom name=cx4.data.rom size=0xc00\n"
" dram name=cx4.data.ram size=0xc00 volatile\n"
" map address=00-3f,80-bf:6000-6bff,7000-7bff mask=0xf000\n"
); );
} }
else if(has_spc7110) { else if(has_spc7110) {
markup.append( markup.append(
" spc7110\n" " spc7110\n"
" rom id=program name=program.rom size=0x100000\n" " map address=00-3f,80-bf:4800-483f\n"
" rom id=data name=data.rom size=0x", hex(rom_size - 0x100000), "\n" " map address=50,58:0000-ffff\n"
" map=mcu address=00-3f,80-bf:8000-ffff mask=0x800000\n"
" map=mcu address=c0-ff:0000-ffff mask=0xc00000\n"
" prom name=program.rom size=0x100000\n"
" drom name=data.rom size=0x", hex(rom_size - 0x100000), "\n"
" ram name=save.ram size=0x", hex(ram_size), "\n" " ram name=save.ram size=0x", hex(ram_size), "\n"
" map id=io address=00-3f,80-bf:4800-483f\n" " map address=00-3f,80-bf:6000-7fff mask=0xe000\n"
" map id=io address=50:0000-ffff\n"
" map id=rom address=00-3f,80-bf:8000-ffff\n"
" map id=rom address=c0-ff:0000-ffff\n"
" map id=ram address=00-3f,80-bf:6000-7fff mask=0xe000\n"
); );
} }
else if(has_sdd1) { else if(has_sdd1) {
markup.append( markup.append(
" sdd1\n" " sdd1\n"
" map address=00-3f,80-bf:4800-4807\n"
" rom name=program.rom size=0x", hex(rom_size), "\n" " rom name=program.rom size=0x", hex(rom_size), "\n"
" map address=00-3f,80-bf:8000-ffff mask=0x808000\n"
" map address=c0-ff:0000-ffff\n"
); );
if(ram_size > 0) markup.append( if(ram_size > 0) markup.append(
" ram name=save.ram size=0x", hex(ram_size), "\n" " ram name=save.ram size=0x", hex(ram_size), "\n"
); " map address=20-3f,a0-bf:6000-7fff mask=0xe000\n"
markup.append( " map address=70-7d:0000-7fff mask=0x8000\n"
" map id=io address=00-3f,80-bf:4800-4807\n"
" map id=rom address=00-3f,80-bf:8000-ffff mask=0x8000\n"
" map id=rom address=c0-ff:0000-ffff\n"
);
if(ram_size > 0) markup.append(
" map id=ram address=20-3f,a0-bf:6000-7fff mask=0xe000\n"
" map id=ram address=70-7f:0000-7fff\n"
); );
} }
else if(mapper == LoROM) { else if(mapper == LoROM) {
markup.append( markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n" " rom name=program.rom size=0x", hex(rom_size), "\n"
" map address=00-7d,80-ff:8000-ffff mask=0x8000\n"
" map address=40-6d,c0-ef:0000-7fff mask=0x8000\n"
); );
if(ram_size > 0) markup.append( if(ram_size > 0) markup.append(
" ram name=save.ram size=0x", hex(ram_size), "\n" " ram name=save.ram size=0x", hex(ram_size), "\n"
); " map address=70-7d,f0-ff:", range, "\n"
markup.append(
" map id=rom address=00-7f,80-ff:8000-ffff mask=0x8000\n"
);
if(ram_size > 0) markup.append(
" map id=ram address=70-7f,f0-ff:", range, "\n"
); );
} }
else if(mapper == HiROM) { else if(mapper == HiROM) {
markup.append( markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n" " rom name=program.rom size=0x", hex(rom_size), "\n"
" map address=00-3f,80-bf:8000-ffff\n"
" map address=40-7f,c0-ff:0000-ffff\n"
); );
if(ram_size > 0) markup.append( if(ram_size > 0) markup.append(
" ram name=save.ram size=0x", hex(ram_size), "\n" " ram name=save.ram size=0x", hex(ram_size), "\n"
); " map address=10-3f,90-bf:6000-7fff mask=0xe000\n"
markup.append(
" map id=rom address=00-3f,80-bf:8000-ffff\n"
" map id=rom address=40-7f,c0-ff:0000-ffff\n"
);
if(ram_size > 0) markup.append(
" map id=ram address=10-3f,90-bf:6000-7fff mask=0xe000\n"
); );
} }
else if(mapper == ExLoROM) { else if(mapper == ExLoROM) {
markup.append( markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n" " rom name=program.rom size=0x", hex(rom_size), "\n"
" map address=00-3f,80-bf:8000-ffff mask=0x8000\n"
" map address=40-7d:0000-ffff\n"
); );
if(ram_size > 0) markup.append( if(ram_size > 0) markup.append(
" ram name=save.ram size=0x", hex(ram_size), "\n" " ram name=save.ram size=0x", hex(ram_size), "\n"
); " map address=20-3f,a0-bf:6000-7fff mask=0xe000\n"
markup.append( " map address=70-7d:0000-7fff mask=0x8000\n"
" map id=rom address=00-3f,80-bf:8000-ffff mask=0x8000\n"
" map id=rom address=40-7f:0000-ffff\n"
);
if(ram_size > 0) markup.append(
" map id=ram address=20-3f,a0-bf:6000-7fff\n"
" map id=ram address=70-7f:0000-7fff\n"
); );
} }
else if(mapper == ExHiROM) { else if(mapper == ExHiROM) {
markup.append( markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n" " rom name=program.rom size=0x", hex(rom_size), "\n"
" map address=00-3f:8000-ffff base=0x400000\n"
" map address=40-7d:0000-ffff base=0x400000\n"
" map address=80-bf:8000-ffff mask=0xc00000\n"
" map address=c0-ff:0000-ffff mask=0xc00000\n"
); );
if(ram_size > 0) markup.append( if(ram_size > 0) markup.append(
" ram name=save.ram size=0x", hex(ram_size), "\n" " ram name=save.ram size=0x", hex(ram_size), "\n"
); " map address=20-3f,a0-bf:6000-7fff mask=0xe000\n"
markup.append( " map address=70-7d:", range, "\n"
" map id=rom address=00-3f:8000-ffff base=0x400000\n"
" map id=rom address=40-7f:0000-ffff base=0x400000\n"
" map id=rom address=80-bf:8000-ffff mask=0xc00000\n"
" map id=rom address=c0-ff:0000-ffff mask=0xc00000\n"
);
if(ram_size > 0) markup.append(
" map id=ram address=20-3f,a0-bf:6000-7fff mask=0xe000\n"
" map id=ram address=70-7f:", range, "\n"
); );
} }
else if(mapper == SuperFXROM) { else if(mapper == SuperFXROM) {
markup.append( markup.append(
" superfx revision=3\n" " superfx\n"
" map address=00-3f,80-bf:3000-34ff\n"
" rom name=program.rom size=0x", hex(rom_size), "\n" " rom name=program.rom size=0x", hex(rom_size), "\n"
" map address=00-3f,80-bf:8000-ffff mask=0x8000\n"
" map address=40-5f,c0-df:0000-ffff\n"
); );
if(ram_size > 0) markup.append( if(ram_size > 0) markup.append(
" ram name=save.ram size=0x", hex(ram_size), "\n" " ram name=save.ram size=0x", hex(ram_size), "\n"
); " map address=00-3f,80-bf:6000-7fff size=0x2000\n"
markup.append( " map address=70-71,f0-f1:0000-ffff\n"
" map id=io address=00-3f,80-bf:3000-32ff\n"
" map id=rom address=00-3f,80-bf:8000-ffff mask=0x8000\n"
" map id=rom address=40-5f,c0-df:0000-ffff\n"
);
if(ram_size > 0) markup.append(
" map id=ram address=00-3f,80-bf:6000-7fff size=0x2000\n"
" map id=ram address=70-71,f0-f1:0000-ffff\n"
); );
} }
else if(mapper == SA1ROM) { else if(mapper == SA1ROM) {
markup.append( markup.append(
" sa1\n" " sa1\n"
" map address=00-3f,80-bf:2200-23ff\n"
" rom name=program.rom size=0x", hex(rom_size), "\n" " rom name=program.rom size=0x", hex(rom_size), "\n"
" map address=00-3f,80-bf:8000-ffff mask=0x408000\n"
" map address=c0-ff:0000-ffff\n"
); );
if(ram_size > 0) markup.append( if(ram_size > 0) markup.append(
" ram id=bitmap name=save.ram size=0x", hex(ram_size), "\n" " bwram name=save.ram size=0x", hex(ram_size), "\n"
" map address=00-3f,80-bf:6000-7fff size=0x2000\n"
" map address=40-4f:0000-ffff\n"
); );
markup.append( markup.append(
" ram id=internal size=0x800\n" " iram id=internal size=0x800 volatile\n"
" map id=io address=00-3f,80-bf:2200-23ff\n" " map address=00-3f,80-bf:3000-37ff size=0x800\n"
" map id=rom address=00-3f,80-bf:8000-ffff\n"
" map id=rom address=c0-ff:0000-ffff\n"
);
if(ram_size > 0) markup.append(
" map id=bwram address=00-3f,80-bf:6000-7fff\n"
" map id=bwram address=40-4f:0000-ffff\n"
);
markup.append(
" map id=iram address=00-3f,80-bf:3000-37ff\n"
); );
} }
else if(mapper == BSCLoROM) { else if(mapper == BSCLoROM) {
markup.append( markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n" " rom name=program.rom size=0x", hex(rom_size), "\n"
" map address=00-1f:8000-ffff base=0x000000 mask=0x8000\n"
" map address=20-3f:8000-ffff base=0x100000 mask=0x8000\n"
" map address=80-9f:8000-ffff base=0x200000 mask=0x8000\n"
" map address=a0-bf:8000-ffff base=0x100000 mask=0x8000\n"
" ram name=save.ram size=0x", hex(ram_size), "\n" " ram name=save.ram size=0x", hex(ram_size), "\n"
" map id=rom address=00-1f:8000-ffff base=0x000000 mask=0x8000\n" " map address=70-7d,f0-ff:0000-7fff mask=0x8000\n"
" map id=rom address=20-3f:8000-ffff base=0x100000 mask=0x8000\n"
" map id=rom address=80-9f:8000-ffff base=0x200000 mask=0x8000\n"
" map id=rom address=a0-bf:8000-ffff base=0x100000 mask=0x8000\n"
" map id=ram address=70-7f,f0-ff:0000-7fff\n"
" satellaview\n" " satellaview\n"
" map id=rom address=c0-ef:0000-ffff\n" " map address=c0-ef:0000-ffff\n"
); );
} }
else if(mapper == BSCHiROM) { else if(mapper == BSCHiROM) {
markup.append( markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n" " rom name=program.rom size=0x", hex(rom_size), "\n"
" map address=00-1f,80-9f:8000-ffff\n"
" map address=40-5f,c0-df:0000-ffff\n"
" ram name=save.ram size=0x", hex(ram_size), "\n" " ram name=save.ram size=0x", hex(ram_size), "\n"
" map id=rom address=00-1f,80-9f:8000-ffff\n" " map address=20-3f,a0-bf:6000-7fff\n"
" map id=rom address=40-5f,c0-df:0000-ffff\n"
" map id=ram address=20-3f,a0-bf:6000-7fff\n"
" satellaview\n" " satellaview\n"
" map id=rom address=20-3f,a0-bf:8000-ffff\n" " map address=20-3f,a0-bf:8000-ffff\n"
" map id=rom address=60-7f,e0-ff:0000-ffff\n" " map address=60-7f,e0-ff:0000-ffff\n"
); );
} }
else if(mapper == BSXROM) { else if(mapper == BSXROM) {
markup.append( markup.append(
" ram name=save.ram size=0x", hex(ram_size), "\n"
" map address=10-1f:5000-5fff mask=0xf000\n"
" mcc\n" " mcc\n"
" map address=00-0f:5000\n"
" map=mcu address=00-3f,80-bf:8000-ffff\n"
" map=mcu address=40-7d,c0-ff:0000-ffff\n"
" rom name=program.rom size=0x", hex(rom_size), "\n" " rom name=program.rom size=0x", hex(rom_size), "\n"
" ram id=save name=save.ram size=0x", hex(ram_size), "\n" " ram name=download.ram size=0x80000\n"
" ram id=download name=download.ram size=0x80000\n" " map address=00-3f,80-bf:6000-7fff mask=0xe000\n"
" map id=io address=00-3f,80-bf:5000-5fff\n"
" map id=rom address=00-3f,80-bf:8000-ffff\n"
" map id=rom address=40-7f,c0-ff:0000-ffff\n"
" map id=ram address=20-3f:6000-7fff\n"
); );
} }
else if(mapper == STROM) { else if(mapper == STROM) {
markup.append( markup.append(
" rom name=program.rom size=0x", hex(rom_size), "\n" " rom name=program.rom size=0x", hex(rom_size), "\n"
" map id=rom address=00-1f,80-9f:8000-ffff mask=0x8000\n" " map address=00-1f,80-9f:8000-ffff mask=0x8000\n"
" sufamiturbo\n" " sufamiturbo\n"
" map id=rom address=20-3f,a0-bf:8000-ffff mask=0x8000\n" " rom\n"
" map id=ram address=60-6f,e0-ef:0000-ffff\n" " map address=20-3f,a0-bf:8000-ffff mask=0x8000\n"
" ram\n"
" map address=60-6f,e0-ef:0000-ffff\n"
" sufamiturbo\n" " sufamiturbo\n"
" map id=rom address=40-5f,c0-df:0000-7fff mask=0x8000\n" " rom\n"
" map id=rom address=40-5f,c0-df:8000-ffff mask=0x8000\n" " map address=40-5f,c0-df:0000-7fff mask=0x8000\n"
" map id=ram address=70-7f,f0-ff:0000-ffff\n" " map address=40-5f,c0-df:8000-ffff mask=0x8000\n"
" ram\n"
" map address=70-7d,f0-ff:0000-ffff\n"
); );
} }
if(has_sharprtc) { if(has_sharprtc) {
markup.append( markup.append(
" sharprtc\n" " sharprtc\n"
" map address=00-3f,80-bf:2800-2801\n"
" ram name=rtc.ram size=0x10\n" " ram name=rtc.ram size=0x10\n"
" map id=io address=00-3f,80-bf:2800-2801\n"
); );
} }
if(has_epsonrtc) { if(has_epsonrtc) {
markup.append( markup.append(
" epsonrtc\n" " epsonrtc\n"
" map address=00-3f,80-bf:4840-4842\n"
" ram name=rtc.ram size=0x10\n" " ram name=rtc.ram size=0x10\n"
" map id=io address=00-3f,80-bf:4840-4842\n"
); );
} }
if(has_obc1) { if(has_obc1) {
markup.append( markup.append(
" obc1\n" " obc1\n"
" map address=00-3f,80-bf:6000-7fff mask=0xe000\n"
" ram name=save.ram size=0x2000\n" " ram name=save.ram size=0x2000\n"
" map id=io address=00-3f,80-bf:6000-7fff\n"
); );
} }
if(has_dsp1) { if(has_dsp1) {
markup.append( markup.append(
" necdsp model=uPD7725 frequency=8000000\n" " necdsp model=uPD7725 frequency=8000000\n"
" rom id=program name=dsp1b.program.rom size=0x1800\n"
" rom id=data name=dsp1b.data.rom size=0x800\n"
" ram id=data size=0x200\n"
); );
if(dsp1_mapper == DSP1LoROM1MB) markup.append( if(dsp1_mapper == DSP1LoROM1MB) markup.append(
" map id=io address=20-3f,a0-bf:8000-ffff select=0x4000\n" " map address=20-3f,a0-bf:8000-ffff mask=0x3fff\n"
); );
if(dsp1_mapper == DSP1LoROM2MB) markup.append( if(dsp1_mapper == DSP1LoROM2MB) markup.append(
" map id=io address=60-6f,e0-ef:0000-7fff select=0x4000\n" " map address=60-6f,e0-ef:0000-7fff mask=0x3fff\n"
); );
if(dsp1_mapper == DSP1HiROM) markup.append( if(dsp1_mapper == DSP1HiROM) markup.append(
" map id=io address=00-1f,80-9f:6000-7fff select=0x1000\n" " map address=00-1f,80-9f:6000-7fff mask=0xfff\n"
);
markup.append(
" prom name=dsp1b.program.rom size=0x1800\n"
" drom name=dsp1b.data.rom size=0x800\n"
" dram name=dsp1b.data.ram size=0x200 volatile\n"
); );
} }
if(has_dsp2) { if(has_dsp2) {
markup.append( markup.append(
" necdsp model=uPD7725 frequency=8000000\n" " necdsp model=uPD7725 frequency=8000000\n"
" rom id=program name=dsp2.program.rom size=0x1800\n" " map address=20-3f,a0-bf:8000-ffff mask=0x3fff\n"
" rom id=data name=dsp2.data.rom size=0x800\n" " prom name=dsp2.program.rom size=0x1800\n"
" ram id=data size=0x200\n" " drom name=dsp2.data.rom size=0x800\n"
" map id=io address=20-3f,a0-bf:8000-ffff select=0x4000\n" " dram name=dsp2.data.ram size=0x200 volatile\n"
); );
} }
if(has_dsp3) { if(has_dsp3) {
markup.append( markup.append(
" necdsp model=uPD7725 frequency=8000000\n" " necdsp model=uPD7725 frequency=8000000\n"
" rom id=program name=dsp3.program.rom size=0x1800\n" " map address=20-3f,a0-bf:8000-ffff mask=0x3fff\n"
" rom id=data name=dsp3.data.rom size=0x800\n" " prom name=dsp3.program.rom size=0x1800\n"
" ram id=data size=0x200\n" " drom name=dsp3.data.rom size=0x800\n"
" map id=io address=20-3f,a0-bf:8000-ffff select=0x4000\n" " dram name=dsp3.data.ram size=0x200 volatile\n"
); );
} }
if(has_dsp4) { if(has_dsp4) {
markup.append( markup.append(
" necdsp model=uPD7725 frequency=8000000\n" " necdsp model=uPD7725 frequency=8000000\n"
" rom id=program name=dsp4.program.rom size=0x1800\n" " map address=30-3f,b0-bf:8000-ffff mask=0x3fff\n"
" rom id=data name=dsp4.data.rom size=0x800\n" " prom name=dsp4.program.rom size=0x1800\n"
" ram id=data size=0x200\n" " drom name=dsp4.data.rom size=0x800\n"
" map id=io address=30-3f,b0-bf:8000-ffff select=0x4000\n" " dram name=dsp4.data.ram size=0x200 volatile\n"
); );
} }
if(has_st010) { if(has_st010) {
markup.append( markup.append(
" necdsp model=uPD96050 frequency=11000000\n" " necdsp model=uPD96050 frequency=11000000\n"
" rom id=program name=st010.program.rom size=0xc000\n" " map address=60-67,e0-e7:0000-3fff\n"
" rom id=data name=st010.data.rom size=0x1000\n" " prom name=st010.program.rom size=0xc000\n"
" ram id=data name=save.ram size=0x1000\n" " drom name=st010.data.rom size=0x1000\n"
" map id=io address=60-67,e0-e7:0000-3fff select=0x0001\n" " dram name=save.ram size=0x1000\n"
" map id=ram address=68-6f,e8-ef:0000-7fff\n" " map address=68-6f,e8-ef:0000-7fff mask=0x8000\n"
); );
} }
if(has_st011) { if(has_st011) {
markup.append( markup.append(
" necdsp model=uPD96050 frequency=15000000\n" " necdsp model=uPD96050 frequency=15000000\n"
" rom id=program name=st011.program.rom size=0xc000\n" " map address=60-67,e0-e7:0000-3fff\n"
" rom id=data name=st011.data.rom size=0x1000\n" " prom name=st011.program.rom size=0xc000\n"
" ram id=data name=save.ram size=0x1000\n" " drom name=st011.data.rom size=0x1000\n"
" map id=io address=60-67,e0-e7:0000-3fff select=0x0001\n" " dram name=save.ram size=0x1000\n"
" map id=ram address=68-6f,e8-ef:0000-7fff\n" " map address=68-6f,e8-ef:0000-7fff mask=0x8000\n"
); );
} }
if(has_st018) { if(has_st018) {
markup.append( markup.append(
" armdsp frequency=21477272\n" " armdsp frequency=21477272\n"
" rom id=program name=st018.program.rom size=0x20000\n" " map address=00-3f,80-bf:3800-38ff\n"
" rom id=data name=st018.data.rom size=0x8000\n" " prom name=st018.program.rom size=0x20000\n"
" ram name=save.ram size=0x4000\n" " drom name=st018.data.rom size=0x8000\n"
" map id=io address=00-3f,80-bf:3800-38ff\n" " dram name=save.ram size=0x4000\n"
); );
} }
} }
auto SuperFamicomCartridge::readHeader(const uint8_t *data, unsigned size) -> void { auto SuperFamicomCartridge::readHeader(const uint8* data, uint size) -> void {
type = TypeUnknown; type = TypeUnknown;
mapper = LoROM; mapper = LoROM;
dsp1_mapper = DSP1Unmapped; dsp1_mapper = DSP1Unmapped;
@ -559,12 +542,12 @@ auto SuperFamicomCartridge::readHeader(const uint8_t *data, unsigned size) -> vo
return; return;
} }
const unsigned index = findHeader(data, size); const uint index = findHeader(data, size);
const uint8_t mapperid = data[index + Mapper]; const uint8 mapperid = data[index + Mapper];
const uint8_t rom_type = data[index + RomType]; const uint8 rom_type = data[index + RomType];
const uint8_t rom_size = data[index + RomSize]; const uint8 rom_size = data[index + RomSize];
const uint8_t company = data[index + Company]; const uint8 company = data[index + Company];
const uint8_t regionid = data[index + CartRegion] & 0x7f; const uint8 regionid = data[index + CartRegion] & 0x7f;
ram_size = 1024 << (data[index + RamSize] & 7); ram_size = 1024 << (data[index + RamSize] & 7);
if(ram_size == 1024) ram_size = 0; //no RAM present if(ram_size == 1024) ram_size = 0; //no RAM present
@ -579,7 +562,7 @@ auto SuperFamicomCartridge::readHeader(const uint8_t *data, unsigned size) -> vo
if(data[index + 0x13] == 0x00 || data[index + 0x13] == 0xff) { if(data[index + 0x13] == 0x00 || data[index + 0x13] == 0xff) {
if(data[index + 0x14] == 0x00) { if(data[index + 0x14] == 0x00) {
const uint8_t n15 = data[index + 0x15]; const uint8 n15 = data[index + 0x15];
if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) { if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) {
if(data[index + 0x1a] == 0x33 || data[index + 0x1a] == 0xff) { if(data[index + 0x1a] == 0x33 || data[index + 0x1a] == 0xff) {
type = TypeBsx; type = TypeBsx;
@ -627,7 +610,7 @@ auto SuperFamicomCartridge::readHeader(const uint8_t *data, unsigned size) -> vo
//detect presence of BS-X flash cartridge connector (reads extended header information) //detect presence of BS-X flash cartridge connector (reads extended header information)
if(data[index - 14] == 'Z') { if(data[index - 14] == 'Z') {
if(data[index - 11] == 'J') { if(data[index - 11] == 'J') {
uint8_t n13 = data[index - 13]; uint8 n13 = data[index - 13];
if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) { if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) {
if(company == 0x33 || (data[index - 10] == 0x00 && data[index - 4] == 0x00)) { if(company == 0x33 || (data[index - 10] == 0x00 && data[index - 4] == 0x00)) {
has_bsx_slot = true; has_bsx_slot = true;
@ -746,10 +729,10 @@ auto SuperFamicomCartridge::readHeader(const uint8_t *data, unsigned size) -> vo
} }
} }
auto SuperFamicomCartridge::findHeader(const uint8_t *data, unsigned size) -> unsigned { auto SuperFamicomCartridge::findHeader(const uint8* data, uint size) -> uint {
unsigned score_lo = scoreHeader(data, size, 0x007fc0); uint score_lo = scoreHeader(data, size, 0x007fc0);
unsigned score_hi = scoreHeader(data, size, 0x00ffc0); uint score_hi = scoreHeader(data, size, 0x00ffc0);
unsigned score_ex = scoreHeader(data, size, 0x40ffc0); uint score_ex = scoreHeader(data, size, 0x40ffc0);
if(score_ex) score_ex += 4; //favor ExHiROM on images > 32mbits if(score_ex) score_ex += 4; //favor ExHiROM on images > 32mbits
if(score_lo >= score_hi && score_lo >= score_ex) { if(score_lo >= score_hi && score_lo >= score_ex) {
@ -761,16 +744,16 @@ auto SuperFamicomCartridge::findHeader(const uint8_t *data, unsigned size) -> un
} }
} }
auto SuperFamicomCartridge::scoreHeader(const uint8_t *data, unsigned size, unsigned addr) -> unsigned { auto SuperFamicomCartridge::scoreHeader(const uint8* data, uint size, uint addr) -> uint {
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;
uint16_t resetvector = data[addr + ResetVector] | (data[addr + ResetVector + 1] << 8); uint16 resetvector = data[addr + ResetVector] | (data[addr + ResetVector + 1] << 8);
uint16_t checksum = data[addr + Checksum ] | (data[addr + Checksum + 1] << 8); uint16 checksum = data[addr + Checksum ] | (data[addr + Checksum + 1] << 8);
uint16_t complement = data[addr + Complement ] | (data[addr + Complement + 1] << 8); uint16 complement = data[addr + Complement ] | (data[addr + Complement + 1] << 8);
uint8_t resetop = data[(addr & ~0x7fff) | (resetvector & 0x7fff)]; //first opcode executed upon reset uint8 resetop = data[(addr & ~0x7fff) | (resetvector & 0x7fff)]; //first opcode executed upon reset
uint8_t mapper = data[addr + Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit uint8 mapper = data[addr + Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit
//$00:[000-7fff] contains uninitialized RAM and MMIO. //$00:[000-7fff] contains uninitialized RAM and MMIO.
//reset vector must point to ROM at $00:[8000-ffff] to be considered valid. //reset vector must point to ROM at $00:[8000-ffff] to be considered valid.

View File

@ -152,7 +152,7 @@ struct InputJoypadDirectInput {
property.dwData = false; property.dwData = false;
device->SetProperty(DIPROP_AUTOCENTER, &property.diph); device->SetProperty(DIPROP_AUTOCENTER, &property.diph);
DWORD dwAxes[2] = {DIJOFS_X, DIJOFS_Y}; DWORD dwAxes[2] = {(DWORD)DIJOFS_X, (DWORD)DIJOFS_Y};
LONG lDirection[2] = {0, 0}; LONG lDirection[2] = {0, 0};
DICONSTANTFORCE force; DICONSTANTFORCE force;
force.lMagnitude = DI_FFNOMINALMAX; //full force force.lMagnitude = DI_FFNOMINALMAX; //full force

View File

@ -6,24 +6,52 @@ namespace SuperFamicom {
#include "serialization.cpp" #include "serialization.cpp"
Cartridge cartridge; Cartridge cartridge;
auto Cartridge::manifest() -> string {
string manifest = information.markup.cartridge;
if(information.markup.gameBoy) {
manifest.append("\n[Super Game Boy]\n");
manifest.append(information.markup.gameBoy);
}
if(information.markup.satellaview) {
manifest.append("\n[BS-X Satellaview]\n");
manifest.append(information.markup.satellaview);
}
if(information.markup.sufamiTurboA) {
manifest.append("\n[Sufami Turbo - Slot A]\n");
manifest.append(information.markup.sufamiTurboA);
}
if(information.markup.sufamiTurboB) {
manifest.append("\n[Sufami Turbo - Slot B]\n");
manifest.append(information.markup.sufamiTurboB);
}
return manifest;
}
auto Cartridge::title() -> string { auto Cartridge::title() -> string {
if(information.title.gameBoy.empty() == false) { string title = information.title.cartridge;
return {information.title.cartridge, " + ", information.title.gameBoy};
if(information.title.gameBoy) {
title.append(" + ", information.title.gameBoy);
} }
if(information.title.satellaview.empty() == false) { if(information.title.satellaview) {
return {information.title.cartridge, " + ", information.title.satellaview}; title.append(" + ", information.title.satellaview);
} }
if(information.title.sufamiTurboA.empty() == false) { if(information.title.sufamiTurboA) {
if(information.title.sufamiTurboB.empty() == true) { title.append(" + ", information.title.sufamiTurboA);
return {information.title.cartridge, " + ", information.title.sufamiTurboA};
} else {
return {information.title.cartridge, " + ", information.title.sufamiTurboA, " + ", information.title.sufamiTurboB};
}
} }
return information.title.cartridge; if(information.title.sufamiTurboB) {
title.append(" + ", information.title.sufamiTurboB);
}
return title;
} }
auto Cartridge::load() -> void { auto Cartridge::load() -> void {
@ -118,8 +146,8 @@ auto Cartridge::loadSuperGameBoy() -> void {
auto document = BML::unserialize(information.markup.gameBoy); auto document = BML::unserialize(information.markup.gameBoy);
information.title.gameBoy = document["information/title"].text(); information.title.gameBoy = document["information/title"].text();
auto rom = document["cartridge/rom"]; auto rom = document["board/rom"];
auto ram = document["cartridge/ram"]; auto ram = document["board/ram"];
GameBoy::cartridge.information.markup = information.markup.gameBoy; GameBoy::cartridge.information.markup = information.markup.gameBoy;
GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy); GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy);
@ -134,7 +162,7 @@ auto Cartridge::loadSatellaview() -> void {
auto document = BML::unserialize(information.markup.satellaview); auto document = BML::unserialize(information.markup.satellaview);
information.title.satellaview = document["information/title"].text(); information.title.satellaview = document["information/title"].text();
auto rom = document["cartridge/rom"]; auto rom = document["board/rom"];
if(rom["name"]) { if(rom["name"]) {
unsigned size = rom["size"].natural(); unsigned size = rom["size"].natural();
@ -150,8 +178,8 @@ auto Cartridge::loadSufamiTurboA() -> void {
auto document = BML::unserialize(information.markup.sufamiTurboA); auto document = BML::unserialize(information.markup.sufamiTurboA);
information.title.sufamiTurboA = document["information/title"].text(); information.title.sufamiTurboA = document["information/title"].text();
auto rom = document["cartridge/rom"]; auto rom = document["board/rom"];
auto ram = document["cartridge/ram"]; auto ram = document["board/ram"];
if(rom["name"]) { if(rom["name"]) {
unsigned size = rom["size"].natural(); unsigned size = rom["size"].natural();
@ -166,7 +194,7 @@ auto Cartridge::loadSufamiTurboA() -> void {
memory.append({ID::SufamiTurboSlotARAM, ram["name"].text()}); memory.append({ID::SufamiTurboSlotARAM, ram["name"].text()});
} }
if(document["cartridge/linkable"]) { if(document["board/linkable"]) {
interface->loadRequest(ID::SufamiTurboSlotB, "Sufami Turbo - Slot B", "st", false); interface->loadRequest(ID::SufamiTurboSlotB, "Sufami Turbo - Slot B", "st", false);
} }
} }
@ -176,8 +204,8 @@ auto Cartridge::loadSufamiTurboB() -> void {
auto document = BML::unserialize(information.markup.sufamiTurboB); auto document = BML::unserialize(information.markup.sufamiTurboB);
information.title.sufamiTurboB = document["information/title"].text(); information.title.sufamiTurboB = document["information/title"].text();
auto rom = document["cartridge/rom"]; auto rom = document["board/rom"];
auto ram = document["cartridge/ram"]; auto ram = document["board/ram"];
if(rom["name"]) { if(rom["name"]) {
unsigned size = rom["size"].natural(); unsigned size = rom["size"].natural();

View File

@ -1,8 +1,8 @@
struct Cartridge : property<Cartridge> { struct Cartridge : property<Cartridge> {
enum class Region : unsigned { NTSC, PAL }; enum class Region : unsigned { NTSC, PAL };
MappedRAM rom; Cartridge() = default;
MappedRAM ram; ~Cartridge() { unload(); }
auto loaded() const -> bool { return _loaded; } auto loaded() const -> bool { return _loaded; }
auto sha256() const -> string { return _sha256; } auto sha256() const -> string { return _sha256; }
@ -28,6 +28,17 @@ struct Cartridge : property<Cartridge> {
readonly<bool> hasSatellaviewSlot; readonly<bool> hasSatellaviewSlot;
readonly<bool> hasSufamiTurboSlots; readonly<bool> hasSufamiTurboSlots;
auto manifest() -> string;
auto title() -> string;
auto load() -> void;
auto unload() -> void;
auto serialize(serializer&) -> void;
MappedRAM rom;
MappedRAM ram;
struct Mapping { struct Mapping {
function<auto (uint, uint8) -> uint8> reader; function<auto (uint, uint8) -> uint8> reader;
function<auto (uint, uint8) -> void> writer; function<auto (uint, uint8) -> void> writer;
@ -66,16 +77,6 @@ struct Cartridge : property<Cartridge> {
} title; } title;
} information; } information;
Cartridge() = default;
~Cartridge() { unload(); }
auto title() -> string;
auto load() -> void;
auto unload() -> void;
auto serialize(serializer&) -> void;
private: private:
auto loadSuperGameBoy() -> void; auto loadSuperGameBoy() -> void;
auto loadSatellaview() -> void; auto loadSatellaview() -> void;
@ -85,10 +86,12 @@ private:
//markup.cpp //markup.cpp
auto parseMarkup(const string&) -> void; auto parseMarkup(const string&) -> void;
auto parseMarkupMap(Mapping&, Markup::Node) -> void; auto parseMarkupMap(Markup::Node, SuperFamicom::Memory&) -> void;
auto parseMarkupMap(Markup::Node, const function<uint8 (uint, uint8)>&, const function<void (uint, uint8)>&) -> void;
auto parseMarkupMemory(MappedRAM&, Markup::Node, unsigned id, bool writable) -> void; auto parseMarkupMemory(MappedRAM&, Markup::Node, unsigned id, bool writable) -> void;
auto parseMarkupCartridge(Markup::Node) -> void; auto parseMarkupROM(Markup::Node) -> void;
auto parseMarkupRAM(Markup::Node) -> void;
auto parseMarkupICD2(Markup::Node) -> void; auto parseMarkupICD2(Markup::Node) -> void;
auto parseMarkupMCC(Markup::Node) -> void; auto parseMarkupMCC(Markup::Node) -> void;
auto parseMarkupSatellaview(Markup::Node) -> void; auto parseMarkupSatellaview(Markup::Node) -> void;

View File

@ -10,68 +10,80 @@ Cartridge::Mapping::Mapping(const function<uint8 (uint, uint8)>& reader, const f
auto Cartridge::parseMarkup(const string& markup) -> void { auto Cartridge::parseMarkup(const string& markup) -> void {
auto document = BML::unserialize(markup); auto document = BML::unserialize(markup);
information.title.cartridge = document["information/title"].text(); auto information = document["information"];
auto board = document["board"];
auto cartridge = document["cartridge"]; this->information.title.cartridge = information["title"].text();
_region = cartridge["region"].text() != "PAL" ? Region::NTSC : Region::PAL; _region = board["cic"].text() == "413" ? Region::PAL : Region::NTSC;
mapping.reset(); mapping.reset();
if(auto node = cartridge) parseMarkupCartridge(node); if(auto node = board["rom"]) parseMarkupROM(node);
if(auto node = cartridge["icd2"]) parseMarkupICD2(node); if(auto node = board["ram"]) parseMarkupRAM(node);
if(auto node = cartridge["mcc"]) parseMarkupMCC(node); if(auto node = board["icd2"]) parseMarkupICD2(node);
if(auto node = cartridge["satellaview"]) parseMarkupSatellaview(node); if(auto node = board["mcc"]) parseMarkupMCC(node);
if(auto node = cartridge.find("sufamiturbo")) if(node(0)) parseMarkupSufamiTurbo(node(0), 0); if(auto node = board["satellaview"]) parseMarkupSatellaview(node);
if(auto node = cartridge.find("sufamiturbo")) if(node(1)) parseMarkupSufamiTurbo(node(1), 1); if(auto node = board.find("sufamiturbo")) if(node(0)) parseMarkupSufamiTurbo(node(0), 0);
if(auto node = cartridge["nss"]) parseMarkupNSS(node); if(auto node = board.find("sufamiturbo")) if(node(1)) parseMarkupSufamiTurbo(node(1), 1);
if(auto node = cartridge["event"]) parseMarkupEvent(node); if(auto node = board["nss"]) parseMarkupNSS(node);
if(auto node = cartridge["sa1"]) parseMarkupSA1(node); if(auto node = board["event"]) parseMarkupEvent(node);
if(auto node = cartridge["superfx"]) parseMarkupSuperFX(node); if(auto node = board["sa1"]) parseMarkupSA1(node);
if(auto node = cartridge["armdsp"]) parseMarkupARMDSP(node); if(auto node = board["superfx"]) parseMarkupSuperFX(node);
if(auto node = cartridge["hitachidsp"]) parseMarkupHitachiDSP(node, cartridge["board/type"].text().match("2DC*") ? 2 : 1); if(auto node = board["armdsp"]) parseMarkupARMDSP(node);
if(auto node = cartridge["necdsp"]) parseMarkupNECDSP(node); if(auto node = board["hitachidsp"]) parseMarkupHitachiDSP(node, document["information/board"].text().match("2DC*") ? 2 : 1);
if(auto node = cartridge["epsonrtc"]) parseMarkupEpsonRTC(node); if(auto node = board["necdsp"]) parseMarkupNECDSP(node);
if(auto node = cartridge["sharprtc"]) parseMarkupSharpRTC(node); if(auto node = board["epsonrtc"]) parseMarkupEpsonRTC(node);
if(auto node = cartridge["spc7110"]) parseMarkupSPC7110(node); if(auto node = board["sharprtc"]) parseMarkupSharpRTC(node);
if(auto node = cartridge["sdd1"]) parseMarkupSDD1(node); if(auto node = board["spc7110"]) parseMarkupSPC7110(node);
if(auto node = cartridge["obc1"]) parseMarkupOBC1(node); if(auto node = board["sdd1"]) parseMarkupSDD1(node);
if(auto node = cartridge["msu1"]) parseMarkupMSU1(node); if(auto node = board["obc1"]) parseMarkupOBC1(node);
if(auto node = board["msu1"]) parseMarkupMSU1(node);
} }
auto Cartridge::parseMarkupMap(Mapping& m, Markup::Node map) -> void { auto Cartridge::parseMarkupMap(Markup::Node map, SuperFamicom::Memory& memory) -> void {
Mapping m{memory};
m.addr = map["address"].text(); m.addr = map["address"].text();
m.size = map["size"].natural(); m.size = map["size"].natural();
m.base = map["base"].natural(); m.base = map["base"].natural();
m.mask = map["mask"].natural(); m.mask = map["mask"].natural();
if(m.size == 0) m.size = memory.size();
if(m.size != 0) mapping.append(m);
} }
auto Cartridge::parseMarkupMemory(MappedRAM& ram, Markup::Node node, unsigned id, bool writable) -> void { auto Cartridge::parseMarkupMap(
Markup::Node map,
const function<uint8 (uint, uint8)>& reader,
const function<void (uint, uint8)>& writer
) -> void {
Mapping m{reader, writer};
m.addr = map["address"].text();
m.size = map["size"].natural();
m.base = map["base"].natural();
m.mask = map["mask"].natural();
mapping.append(m);
}
auto Cartridge::parseMarkupMemory(MappedRAM& ram, Markup::Node node, uint id, bool writable) -> void {
string name = node["name"].text(); string name = node["name"].text();
unsigned size = node["size"].natural(); uint size = node["size"].natural();
bool save = !(bool)node["volatile"];
ram.map(allocate<uint8>(size, 0xff), size); ram.map(allocate<uint8>(size, 0xff), size);
if(name) { if(name) {
interface->loadRequest(id, name, !writable); //treat ROM as required; RAM as optional interface->loadRequest(id, name, !writable); //treat ROM as required; RAM as optional
if(writable) memory.append({id, name}); if(writable && save) memory.append({id, name});
} }
} }
auto Cartridge::parseMarkupCartridge(Markup::Node root) -> void { auto Cartridge::parseMarkupROM(Markup::Node root) -> void {
parseMarkupMemory(rom, root["rom"], ID::ROM, false); parseMarkupMemory(rom, root, ID::ROM, false);
parseMarkupMemory(ram, root["ram"], ID::RAM, true);
for(auto node : root.find("map")) { for(auto node : root.find("map")) {
if(node["id"].text() == "rom") { parseMarkupMap(node, rom);
Mapping m(rom); }
parseMarkupMap(m, node); }
if(m.size == 0) m.size = rom.size();
mapping.append(m);
}
if(node["id"].text() == "ram") { auto Cartridge::parseMarkupRAM(Markup::Node root) -> void {
Mapping m(ram); parseMarkupMemory(ram, root, ID::RAM, true);
parseMarkupMap(m, node); for(auto node : root.find("map")) {
if(m.size == 0) m.size = ram.size(); parseMarkupMap(node, ram);
mapping.append(m);
}
} }
} }
@ -83,15 +95,10 @@ auto Cartridge::parseMarkupICD2(Markup::Node root) -> void {
GameBoy::cartridge.load_empty(GameBoy::System::Revision::SuperGameBoy); GameBoy::cartridge.load_empty(GameBoy::System::Revision::SuperGameBoy);
interface->loadRequest(ID::SuperGameBoy, "Game Boy", "gb", false); interface->loadRequest(ID::SuperGameBoy, "Game Boy", "gb", false);
string bootROMName = root["rom/name"].text(); interface->loadRequest(ID::SuperGameBoyBootROM, root["brom"]["name"].text(), true);
interface->loadRequest(ID::SuperGameBoyBootROM, bootROMName, true);
for(auto node : root.find("map")) { for(auto node : root.find("map")) {
if(node["id"].text() == "io") { parseMarkupMap(node, {&ICD2::read, &icd2}, {&ICD2::write, &icd2});
Mapping m({&ICD2::read, &icd2}, {&ICD2::write, &icd2});
parseMarkupMap(m, node);
mapping.append(m);
}
} }
} }
@ -101,26 +108,19 @@ auto Cartridge::parseMarkupMCC(Markup::Node root) -> void {
interface->loadRequest(ID::Satellaview, "BS-X Satellaview", "bs", false); interface->loadRequest(ID::Satellaview, "BS-X Satellaview", "bs", false);
auto rom = root.find("rom"); parseMarkupMemory(mcc.rom, root["rom"], ID::MCCROM, false);
auto ram = root.find("ram"); parseMarkupMemory(mcc.ram, root["ram"], ID::MCCRAM, true);
parseMarkupMemory(mcc.rom, rom(0), ID::MCCROM, false);
parseMarkupMemory(mcc.ram, ram(0), ID::MCCRAM, true);
parseMarkupMemory(mcc.psram, ram(1), ID::MCCPSRAM, true);
for(auto node : root.find("map")) { for(auto node : root.find("map")) {
if(node["id"].text() == "rom" if(node.text() == "mcu") {
|| node["id"].text() == "ram") { parseMarkupMap(node, {&MCC::mcu_read, &mcc}, {&MCC::mcu_write, &mcc});
Mapping m({&MCC::mcu_read, &mcc}, {&MCC::mcu_write, &mcc}); } else {
parseMarkupMap(m, node); parseMarkupMap(node, {&MCC::read, &mcc}, {&MCC::write, &mcc});
mapping.append(m);
} }
}
if(node["id"].text() == "io") { for(auto node : root["ram"].find("map")) {
Mapping m({&MCC::mmio_read, &mcc}, {&MCC::mmio_write, &mcc}); parseMarkupMap(node, mcc.ram);
parseMarkupMap(m, node);
mapping.append(m);
}
} }
} }
@ -129,14 +129,9 @@ auto Cartridge::parseMarkupSatellaview(Markup::Node root) -> void {
interface->loadRequest(ID::Satellaview, "BS-X Satellaview", "bs", false); interface->loadRequest(ID::Satellaview, "BS-X Satellaview", "bs", false);
for(auto node : root.find("map")) { for(auto node : root["rom"].find("map")) {
if(node["id"].text() == "rom") { if(satellaviewcartridge.memory.size() == 0) continue;
if(satellaviewcartridge.memory.size() == 0) continue; parseMarkupMap(node, satellaviewcartridge);
Mapping m(satellaviewcartridge);
parseMarkupMap(m, node);
mapping.append(m);
}
} }
} }
@ -148,26 +143,16 @@ auto Cartridge::parseMarkupSufamiTurbo(Markup::Node root, bool slot) -> void {
interface->loadRequest(ID::SufamiTurboSlotA, "Sufami Turbo - Slot A", "st", false); interface->loadRequest(ID::SufamiTurboSlotA, "Sufami Turbo - Slot A", "st", false);
} }
for(auto node : root.find("map")) { for(auto node : root["rom"].find("map")) {
SufamiTurboCartridge& cart = (slot == 0 ? sufamiturboA : sufamiturboB); SufamiTurboCartridge& cart = (slot == 0 ? sufamiturboA : sufamiturboB);
if(cart.rom.size() == 0) continue;
parseMarkupMap(node, cart.rom);
}
if(node["id"].text() == "rom") { for(auto node : root["ram"].find("map")) {
if(cart.rom.size() == 0) continue; SufamiTurboCartridge& cart = (slot == 0 ? sufamiturboA : sufamiturboB);
if(cart.ram.size() == 0) continue;
Mapping m(cart.rom); parseMarkupMap(node, cart.ram);
parseMarkupMap(m, node);
if(m.size == 0) m.size = cart.rom.size();
if(m.size) mapping.append(m);
}
if(node["id"].text() == "ram") {
if(cart.ram.size() == 0) continue;
Mapping m(cart.ram);
parseMarkupMap(m, node);
if(m.size == 0) m.size = cart.ram.size();
if(m.size) mapping.append(m);
}
} }
} }
@ -176,21 +161,18 @@ auto Cartridge::parseMarkupNSS(Markup::Node root) -> void {
nss.dip = interface->dipSettings(root); nss.dip = interface->dipSettings(root);
for(auto node : root.find("map")) { for(auto node : root.find("map")) {
if(node["id"].text() == "io") { parseMarkupMap(node, {&NSS::read, &nss}, {&NSS::write, &nss});
Mapping m({&NSS::read, &nss}, {&NSS::write, &nss});
parseMarkupMap(m, node);
mapping.append(m);
}
} }
} }
auto Cartridge::parseMarkupEvent(Markup::Node root) -> void { auto Cartridge::parseMarkupEvent(Markup::Node root) -> void {
auto roms = root.find("rom");
if(roms.size() != 4) return;
hasEvent = true; hasEvent = true;
for(auto node : root.find("rom")) { for(uint n : range(4)) {
unsigned id = node["id"].natural(); parseMarkupMemory(event.rom[n], roms[n], ID::EventROM0 + n, false);
if(id > 3) continue;
parseMarkupMemory(event.rom[id], node, ID::EventROM0 + id, false);
} }
parseMarkupMemory(event.ram, root["ram"], ID::EventRAM, true); parseMarkupMemory(event.ram, root["ram"], ID::EventRAM, true);
@ -200,10 +182,15 @@ auto Cartridge::parseMarkupEvent(Markup::Node root) -> void {
event.revision = root["revision"].text() == "B" ? 2 : 1; event.revision = root["revision"].text() == "B" ? 2 : 1;
lstring part = root["timer"].text().split(":", 1L); lstring part = root["timer"].text().split(":", 1L);
if(part.size() == 1) event.timer = part(0).natural(); if(part.size() == 1) event.timer = part[0].natural();
if(part.size() == 2) event.timer = part(0).natural() * 60 + part(1).natural(); if(part.size() == 2) event.timer = part[0].natural() * 60 + part[1].natural();
for(auto node : root.find("map")) { for(auto node : root.find("map")) {
parseMarkupMap(node, {&Event::read, &event}, {&Event::write, &event});
}
/*
//todo: define and support markup for coprocessor/event
if(node["id"].text() == "rom") { if(node["id"].text() == "rom") {
Mapping m({&Event::rom_read, &event}, [](unsigned, uint8) {}); Mapping m({&Event::rom_read, &event}, [](unsigned, uint8) {});
parseMarkupMap(m, node); parseMarkupMap(m, node);
@ -227,159 +214,101 @@ auto Cartridge::parseMarkupEvent(Markup::Node root) -> void {
parseMarkupMap(m, node); parseMarkupMap(m, node);
mapping.append(m); mapping.append(m);
} }
} */
} }
auto Cartridge::parseMarkupSA1(Markup::Node root) -> void { auto Cartridge::parseMarkupSA1(Markup::Node root) -> void {
hasSA1 = true; hasSA1 = true;
auto rom = root.find("rom"); parseMarkupMemory(sa1.rom, root["rom"], ID::SA1ROM, false);
auto ram = root.find("ram"); parseMarkupMemory(sa1.bwram, root["bwram"], ID::SA1BWRAM, true);
parseMarkupMemory(sa1.iram, root["iram"], ID::SA1IRAM, true);
parseMarkupMemory(sa1.rom, rom(0), ID::SA1ROM, false);
parseMarkupMemory(sa1.bwram, ram(0), ID::SA1BWRAM, true);
parseMarkupMemory(sa1.iram, ram(1), ID::SA1IRAM, true);
for(auto node : root.find("map")) { for(auto node : root.find("map")) {
if(node["id"].text() == "io") { parseMarkupMap(node, {&SA1::mmio_read, &sa1}, {&SA1::mmio_write, &sa1});
Mapping m({&SA1::mmio_read, &sa1}, {&SA1::mmio_write, &sa1}); }
parseMarkupMap(m, node);
mapping.append(m);
}
if(node["id"].text() == "rom") { for(auto node : root["rom"].find("map")) {
Mapping m({&SA1::mmcrom_read, &sa1}, {&SA1::mmcrom_write, &sa1}); parseMarkupMap(node, {&SA1::mmcrom_read, &sa1}, {&SA1::mmcrom_write, &sa1});
parseMarkupMap(m, node); }
mapping.append(m);
}
if(node["id"].text() == "bwram") { for(auto node : root["bwram"].find("map")) {
Mapping m({&SA1::mmcbwram_read, &sa1}, {&SA1::mmcbwram_write, &sa1}); parseMarkupMap(node, {&SA1::mmcbwram_read, &sa1}, {&SA1::mmcbwram_write, &sa1});
parseMarkupMap(m, node); }
mapping.append(m);
}
if(node["id"].text() == "iram") { for(auto node : root["iram"].find("map")) {
Mapping m(sa1.cpuiram); parseMarkupMap(node, sa1.cpuiram);
parseMarkupMap(m, node);
if(m.size == 0) m.size = sa1.cpuiram.size();
mapping.append(m);
}
} }
} }
auto Cartridge::parseMarkupSuperFX(Markup::Node root) -> void { auto Cartridge::parseMarkupSuperFX(Markup::Node root) -> void {
hasSuperFX = true; hasSuperFX = true;
auto rom = root.find("rom"); parseMarkupMemory(superfx.rom, root["rom"], ID::SuperFXROM, false);
auto ram = root.find("ram"); parseMarkupMemory(superfx.ram, root["ram"], ID::SuperFXRAM, true);
parseMarkupMemory(superfx.rom, rom(0), ID::SuperFXROM, false);
parseMarkupMemory(superfx.ram, ram(0), ID::SuperFXRAM, true);
for(auto node : root.find("map")) { for(auto node : root.find("map")) {
if(node["id"].text() == "io") { parseMarkupMap(node, {&SuperFX::mmio_read, &superfx}, {&SuperFX::mmio_write, &superfx});
Mapping m({&SuperFX::mmio_read, &superfx}, {&SuperFX::mmio_write, &superfx}); }
parseMarkupMap(m, node);
mapping.append(m);
}
if(node["id"].text() == "rom") { for(auto node : root["rom"].find("map")) {
Mapping m(superfx.cpurom); parseMarkupMap(node, superfx.cpurom);
parseMarkupMap(m, node); }
if(m.size == 0) m.size = superfx.rom.size();
mapping.append(m);
}
if(node["id"].text() == "ram") { for(auto node : root["ram"].find("map")) {
Mapping m(superfx.cpuram); parseMarkupMap(node, superfx.cpuram);
parseMarkupMap(m, node);
if(m.size == 0) m.size = superfx.ram.size();
mapping.append(m);
}
} }
} }
auto Cartridge::parseMarkupARMDSP(Markup::Node root) -> void { auto Cartridge::parseMarkupARMDSP(Markup::Node root) -> void {
hasARMDSP = true; hasARMDSP = true;
auto rom = root.find("rom"); interface->loadRequest(ID::ArmDSPPROM, root["prom"]["name"].text(), true);
auto ram = root.find("ram"); interface->loadRequest(ID::ArmDSPDROM, root["drom"]["name"].text(), true);
interface->loadRequest(ID::ArmDSPRAM, root["dram"]["name"].text(), false);
string programROMName = rom(0)["name"].text(); memory.append({ID::ArmDSPRAM, root["dram"]["name"].text()});
string dataROMName = rom(1)["name"].text();
string dataRAMName = ram(0)["name"].text();
interface->loadRequest(ID::ArmDSPPROM, programROMName, true);
interface->loadRequest(ID::ArmDSPDROM, dataROMName, true);
if(dataRAMName.empty() == false) {
interface->loadRequest(ID::ArmDSPRAM, dataRAMName, false);
memory.append({ID::ArmDSPRAM, dataRAMName});
}
for(auto node : root.find("map")) { for(auto node : root.find("map")) {
if(node["id"].text() == "io") { parseMarkupMap(node, {&ArmDSP::mmio_read, &armdsp}, {&ArmDSP::mmio_write, &armdsp});
Mapping m({&ArmDSP::mmio_read, &armdsp}, {&ArmDSP::mmio_write, &armdsp});
parseMarkupMap(m, node);
mapping.append(m);
}
} }
} }
auto Cartridge::parseMarkupHitachiDSP(Markup::Node root, uint roms) -> void { auto Cartridge::parseMarkupHitachiDSP(Markup::Node root, uint roms) -> void {
hasHitachiDSP = true; hasHitachiDSP = true;
auto rom = root.find("rom"); hitachidsp.Frequency = root["frequency"].natural();
auto ram = root.find("ram"); if(hitachidsp.Frequency == 0) hitachidsp.frequency = 20000000;
hitachidsp.Roms = roms; //1 or 2
parseMarkupMemory(hitachidsp.rom, rom(0), ID::HitachiDSPROM, false);
parseMarkupMemory(hitachidsp.ram, ram(0), ID::HitachiDSPRAM, true);
for(auto& word : hitachidsp.dataROM) word = 0x000000; for(auto& word : hitachidsp.dataROM) word = 0x000000;
for(auto& word : hitachidsp.dataRAM) word = 0x00; for(auto& word : hitachidsp.dataRAM) word = 0x00;
hitachidsp.Frequency = root["frequency"].natural(); interface->loadRequest(ID::HitachiDSPDROM, root["drom"]["name"].text(), true);
if(hitachidsp.Frequency == 0) hitachidsp.frequency = 20000000; interface->loadRequest(ID::HitachiDSPDRAM, root["dram"]["name"].text(), false);
hitachidsp.Roms = roms;
string dataROMName = rom(1)["name"].text(); parseMarkupMemory(hitachidsp.rom, root["rom"], ID::HitachiDSPROM, false);
string dataRAMName = ram(1)["name"].text(); parseMarkupMemory(hitachidsp.ram, root["ram"], ID::HitachiDSPRAM, true);
interface->loadRequest(ID::HitachiDSPDROM, dataROMName, true);
if(dataRAMName.empty() == false) {
interface->loadRequest(ID::HitachiDSPDRAM, dataRAMName, false);
}
for(auto node : root.find("map")) { for(auto node : root.find("map")) {
if(node["id"].text() == "io") { parseMarkupMap(node, {&HitachiDSP::dsp_read, &hitachidsp}, {&HitachiDSP::dsp_write, &hitachidsp});
Mapping m({&HitachiDSP::dsp_read, &hitachidsp}, {&HitachiDSP::dsp_write, &hitachidsp}); }
parseMarkupMap(m, node);
mapping.append(m);
}
if(node["id"].text() == "rom") { for(auto node : root["rom"].find("map")) {
Mapping m({&HitachiDSP::rom_read, &hitachidsp}, {&HitachiDSP::rom_write, &hitachidsp}); parseMarkupMap(node, {&HitachiDSP::rom_read, &hitachidsp}, {&HitachiDSP::rom_write, &hitachidsp});
parseMarkupMap(m, node); }
if(m.size == 0) m.size = hitachidsp.rom.size();
mapping.append(m);
}
if(node["id"].text() == "ram") { for(auto node : root["ram"].find("map")) {
Mapping m({&HitachiDSP::ram_read, &hitachidsp}, {&HitachiDSP::ram_write, &hitachidsp}); parseMarkupMap(node, {&HitachiDSP::ram_read, &hitachidsp}, {&HitachiDSP::ram_write, &hitachidsp});
parseMarkupMap(m, node); }
if(m.size == 0) m.size = hitachidsp.ram.size();
mapping.append(m); for(auto node : root["dram"].find("map")) {
} parseMarkupMap(node, {&HitachiDSP::dram_read, &hitachidsp}, {&HitachiDSP::dram_write, &hitachidsp});
} }
} }
auto Cartridge::parseMarkupNECDSP(Markup::Node root) -> void { auto Cartridge::parseMarkupNECDSP(Markup::Node root) -> void {
hasNECDSP = true; hasNECDSP = true;
for(auto& word : necdsp.programROM) word = 0x000000;
for(auto& word : necdsp.dataROM) word = 0x0000;
for(auto& word : necdsp.dataRAM) word = 0x0000;
necdsp.frequency = root["frequency"].natural(); necdsp.frequency = root["frequency"].natural();
if(necdsp.frequency == 0) necdsp.frequency = 8000000; if(necdsp.frequency == 0) necdsp.frequency = 8000000;
necdsp.revision necdsp.revision
@ -387,137 +316,91 @@ auto Cartridge::parseMarkupNECDSP(Markup::Node root) -> void {
: root["model"].text() == "uPD96050" ? NECDSP::Revision::uPD96050 : root["model"].text() == "uPD96050" ? NECDSP::Revision::uPD96050
: NECDSP::Revision::uPD7725; : NECDSP::Revision::uPD7725;
auto rom = root.find("rom"); for(auto& word : necdsp.programROM) word = 0x000000;
auto ram = root.find("ram"); for(auto& word : necdsp.dataROM) word = 0x0000;
for(auto& word : necdsp.dataRAM) word = 0x0000;
string programROMName = rom(0)["name"].text();
string dataROMName = rom(1)["name"].text();
string dataRAMName = ram(0)["name"].text();
if(necdsp.revision == NECDSP::Revision::uPD7725) { if(necdsp.revision == NECDSP::Revision::uPD7725) {
interface->loadRequest(ID::Nec7725DSPPROM, programROMName, true); interface->loadRequest(ID::Nec7725DSPPROM, root["prom"]["name"].text(), true);
interface->loadRequest(ID::Nec7725DSPDROM, dataROMName, true); interface->loadRequest(ID::Nec7725DSPDROM, root["drom"]["name"].text(), true);
if(dataRAMName.empty() == false) { interface->loadRequest(ID::Nec7725DSPRAM, root["dram"]["name"].text(), false);
interface->loadRequest(ID::Nec7725DSPRAM, dataRAMName, false); memory.append({ID::Nec7725DSPRAM, root["dram"]["name"].text()});
memory.append({ID::Nec7725DSPRAM, dataRAMName});
}
} }
if(necdsp.revision == NECDSP::Revision::uPD96050) { if(necdsp.revision == NECDSP::Revision::uPD96050) {
interface->loadRequest(ID::Nec96050DSPPROM, programROMName, true); interface->loadRequest(ID::Nec96050DSPPROM, root["prom"]["name"].text(), true);
interface->loadRequest(ID::Nec96050DSPDROM, dataROMName, true); interface->loadRequest(ID::Nec96050DSPDROM, root["drom"]["name"].text(), true);
if(dataRAMName.empty() == false) { interface->loadRequest(ID::Nec96050DSPRAM, root["dram"]["name"].text(), false);
interface->loadRequest(ID::Nec96050DSPRAM, dataRAMName, false); memory.append({ID::Nec96050DSPRAM, root["dram"]["name"].text()});
memory.append({ID::Nec96050DSPRAM, dataRAMName});
}
} }
for(auto node : root.find("map")) { for(auto node : root.find("map")) {
if(node["id"].text() == "io") { parseMarkupMap(node, {&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp});
Mapping m({&NECDSP::read, &necdsp}, {&NECDSP::write, &necdsp}); }
parseMarkupMap(m, node);
mapping.append(m);
necdsp.Select = node["select"].natural();
}
if(node["id"].text() == "ram") { for(auto node : root["dram"].find("map")) {
Mapping m({&NECDSP::readRAM, &necdsp}, {&NECDSP::writeRAM, &necdsp}); parseMarkupMap(node, {&NECDSP::readRAM, &necdsp}, {&NECDSP::writeRAM, &necdsp});
parseMarkupMap(m, node);
mapping.append(m);
}
} }
} }
auto Cartridge::parseMarkupEpsonRTC(Markup::Node root) -> void { auto Cartridge::parseMarkupEpsonRTC(Markup::Node root) -> void {
hasEpsonRTC = true; hasEpsonRTC = true;
string name = root["ram/name"].text(); interface->loadRequest(ID::EpsonRTC, root["ram"]["name"].text(), false);
interface->loadRequest(ID::EpsonRTC, name, false); memory.append({ID::EpsonRTC, root["ram"]["name"].text()});
memory.append({ID::EpsonRTC, name});
for(auto node : root.find("map")) { for(auto node : root.find("map")) {
if(node["id"].text() == "io") { parseMarkupMap(node, {&EpsonRTC::read, &epsonrtc}, {&EpsonRTC::write, &epsonrtc});
Mapping m({&EpsonRTC::read, &epsonrtc}, {&EpsonRTC::write, &epsonrtc});
parseMarkupMap(m, node);
mapping.append(m);
}
} }
} }
auto Cartridge::parseMarkupSharpRTC(Markup::Node root) -> void { auto Cartridge::parseMarkupSharpRTC(Markup::Node root) -> void {
hasSharpRTC = true; hasSharpRTC = true;
string name = root["ram/name"].text(); interface->loadRequest(ID::SharpRTC, root["ram"]["name"].text(), false);
interface->loadRequest(ID::SharpRTC, name, false); memory.append({ID::SharpRTC, root["ram"]["name"].text()});
memory.append({ID::SharpRTC, name});
for(auto node : root.find("map")) { for(auto node : root.find("map")) {
if(node["id"].text() == "io") { parseMarkupMap(node, {&SharpRTC::read, &sharprtc}, {&SharpRTC::write, &sharprtc});
Mapping m({&SharpRTC::read, &sharprtc}, {&SharpRTC::write, &sharprtc});
parseMarkupMap(m, node);
mapping.append(m);
}
} }
} }
auto Cartridge::parseMarkupSPC7110(Markup::Node root) -> void { auto Cartridge::parseMarkupSPC7110(Markup::Node root) -> void {
hasSPC7110 = true; hasSPC7110 = true;
auto rom = root.find("rom"); parseMarkupMemory(spc7110.prom, root["prom"], ID::SPC7110PROM, false);
auto ram = root.find("ram"); parseMarkupMemory(spc7110.drom, root["drom"], ID::SPC7110DROM, false);
parseMarkupMemory(spc7110.ram, root["ram"], ID::SPC7110RAM, true);
parseMarkupMemory(spc7110.prom, rom(0), ID::SPC7110PROM, false);
parseMarkupMemory(spc7110.drom, rom(1), ID::SPC7110DROM, false);
parseMarkupMemory(spc7110.ram, ram(0), ID::SPC7110RAM, true);
for(auto node : root.find("map")) { for(auto node : root.find("map")) {
if(node["id"].text() == "io") { if(node.text() == "mcu") {
Mapping m({&SPC7110::read, &spc7110}, {&SPC7110::write, &spc7110}); parseMarkupMap(node, {&SPC7110::mcurom_read, &spc7110}, {&SPC7110::mcurom_write, &spc7110});
parseMarkupMap(m, node); } else {
mapping.append(m); parseMarkupMap(node, {&SPC7110::read, &spc7110}, {&SPC7110::write, &spc7110});
} }
}
if(node["id"].text() == "rom") { for(auto node : root["ram"].find("map")) {
Mapping m({&SPC7110::mcurom_read, &spc7110}, {&SPC7110::mcurom_write, &spc7110}); parseMarkupMap(node, {&SPC7110::mcuram_read, &spc7110}, {&SPC7110::mcuram_write, &spc7110});
parseMarkupMap(m, node);
mapping.append(m);
}
if(node["id"].text() == "ram") {
Mapping m({&SPC7110::mcuram_read, &spc7110}, {&SPC7110::mcuram_write, &spc7110});
parseMarkupMap(m, node);
mapping.append(m);
}
} }
} }
auto Cartridge::parseMarkupSDD1(Markup::Node root) -> void { auto Cartridge::parseMarkupSDD1(Markup::Node root) -> void {
hasSDD1 = true; hasSDD1 = true;
auto rom = root.find("rom"); parseMarkupMemory(sdd1.rom, root["rom"], ID::SDD1ROM, false);
auto ram = root.find("ram"); parseMarkupMemory(sdd1.ram, root["ram"], ID::SDD1RAM, true);
parseMarkupMemory(sdd1.rom, rom(0), ID::SDD1ROM, false);
parseMarkupMemory(sdd1.ram, ram(0), ID::SDD1RAM, true);
for(auto node : root.find("map")) { for(auto node : root.find("map")) {
if(node["id"].text() == "io") { parseMarkupMap(node, {&SDD1::read, &sdd1}, {&SDD1::write, &sdd1});
Mapping m({&SDD1::read, &sdd1}, {&SDD1::write, &sdd1}); }
parseMarkupMap(m, node);
mapping.append(m);
}
if(node["id"].text() == "rom") { for(auto node : root["rom"].find("map")) {
Mapping m({&SDD1::mcurom_read, &sdd1}, {&SDD1::mcurom_write, &sdd1}); parseMarkupMap(node, {&SDD1::mcurom_read, &sdd1}, {&SDD1::mcurom_write, &sdd1});
parseMarkupMap(m, node); }
mapping.append(m);
}
if(node["id"].text() == "ram") { for(auto node : root["ram"].find("map")) {
Mapping m({&SDD1::mcuram_read, &sdd1}, {&SDD1::mcuram_write, &sdd1}); parseMarkupMap(node, {&SDD1::mcuram_read, &sdd1}, {&SDD1::mcuram_write, &sdd1});
parseMarkupMap(m, node);
mapping.append(m);
}
} }
} }
@ -527,11 +410,7 @@ auto Cartridge::parseMarkupOBC1(Markup::Node root) -> void {
parseMarkupMemory(obc1.ram, root["ram"], ID::OBC1RAM, true); parseMarkupMemory(obc1.ram, root["ram"], ID::OBC1RAM, true);
for(auto node : root.find("map")) { for(auto node : root.find("map")) {
if(node["id"].text() == "io") { parseMarkupMap(node, {&OBC1::read, &obc1}, {&OBC1::write, &obc1});
Mapping m({&OBC1::read, &obc1}, {&OBC1::write, &obc1});
parseMarkupMap(m, node);
mapping.append(m);
}
} }
} }
@ -539,10 +418,6 @@ auto Cartridge::parseMarkupMSU1(Markup::Node root) -> void {
hasMSU1 = true; hasMSU1 = true;
for(auto node : root.find("map")) { for(auto node : root.find("map")) {
if(node["id"].text() == "io") { parseMarkupMap(node, {&MSU1::mmioRead, &msu1}, {&MSU1::mmioWrite, &msu1});
Mapping m({&MSU1::mmioRead, &msu1}, {&MSU1::mmioWrite, &msu1});
parseMarkupMap(m, node);
mapping.append(m);
}
} }
} }

View File

@ -116,6 +116,13 @@ auto Event::ram_write(uint addr, uint8 data) -> void {
return ram.write(bus.mirror(addr, ram.size()), data); return ram.write(bus.mirror(addr, ram.size()), data);
} }
auto Event::read(uint addr, uint8 data) -> uint8 {
return data;
}
auto Event::write(uint addr, uint8 data) -> void {
}
auto Event::serialize(serializer& s) -> void { auto Event::serialize(serializer& s) -> void {
Thread::serialize(s); Thread::serialize(s);
s.array(ram.data(), ram.size()); s.array(ram.data(), ram.size());

View File

@ -19,6 +19,9 @@ struct Event : Coprocessor {
auto ram_read(uint addr, uint8) -> uint8; auto ram_read(uint addr, uint8) -> uint8;
auto ram_write(uint addr, uint8 data) -> void; auto ram_write(uint addr, uint8 data) -> void;
auto read(uint addr, uint8 data) -> uint8;
auto write(uint addr, uint8 data) -> void;
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
MappedRAM rom[4]; MappedRAM rom[4];

View File

@ -25,6 +25,10 @@ struct HitachiDSP : Processor::HG51B, Coprocessor {
auto ram_read(uint addr, uint8 data) -> uint8; auto ram_read(uint addr, uint8 data) -> uint8;
auto ram_write(uint addr, uint8 data) -> void; auto ram_write(uint addr, uint8 data) -> void;
//HG51B data RAM read/write
auto dram_read(uint addr, uint8 data) -> uint8;
auto dram_write(uint addr, uint8 data) -> void;
//CPU MMIO read/write //CPU MMIO read/write
auto dsp_read(uint addr, uint8 data) -> uint8; auto dsp_read(uint addr, uint8 data) -> uint8;
auto dsp_write(uint addr, uint8 data) -> void; auto dsp_write(uint addr, uint8 data) -> void;

View File

@ -52,48 +52,55 @@ auto HitachiDSP::ram_write(uint addr, uint8 data) -> void {
return ram.write(bus.mirror(addr, ram.size()), data); return ram.write(bus.mirror(addr, ram.size()), data);
} }
auto HitachiDSP::dsp_read(uint addr, uint8) -> uint8 { auto HitachiDSP::dram_read(uint addr, uint8 data) -> uint8 {
addr &= 0x1fff; addr &= 0xfff;
if(addr >= 0xc00) return data;
return dataRAM[addr];
}
//Data RAM auto HitachiDSP::dram_write(uint addr, uint8 data) -> void {
if((addr >= 0x0000 && addr <= 0x0bff) || (addr >= 0x1000 && addr <= 0x1bff)) { addr &= 0xfff;
return dataRAM[addr & 0x0fff]; if(addr >= 0xc00) return;
} dataRAM[addr] = data;
}
auto HitachiDSP::dsp_read(uint addr, uint8) -> uint8 {
addr = 0x7c00 | (addr & 0x03ff);
//MMIO //MMIO
switch(addr) { switch(addr) {
case 0x1f40: return mmio.dma_source >> 0; case 0x7f40: return mmio.dma_source >> 0;
case 0x1f41: return mmio.dma_source >> 8; case 0x7f41: return mmio.dma_source >> 8;
case 0x1f42: return mmio.dma_source >> 16; case 0x7f42: return mmio.dma_source >> 16;
case 0x1f43: return mmio.dma_length >> 0; case 0x7f43: return mmio.dma_length >> 0;
case 0x1f44: return mmio.dma_length >> 8; case 0x7f44: return mmio.dma_length >> 8;
case 0x1f45: return mmio.dma_target >> 0; case 0x7f45: return mmio.dma_target >> 0;
case 0x1f46: return mmio.dma_target >> 8; case 0x7f46: return mmio.dma_target >> 8;
case 0x1f47: return mmio.dma_target >> 16; case 0x7f47: return mmio.dma_target >> 16;
case 0x1f48: return mmio.r1f48; case 0x7f48: return mmio.r1f48;
case 0x1f49: return mmio.program_offset >> 0; case 0x7f49: return mmio.program_offset >> 0;
case 0x1f4a: return mmio.program_offset >> 8; case 0x7f4a: return mmio.program_offset >> 8;
case 0x1f4b: return mmio.program_offset >> 16; case 0x7f4b: return mmio.program_offset >> 16;
case 0x1f4c: return mmio.r1f4c; case 0x7f4c: return mmio.r1f4c;
case 0x1f4d: return mmio.page_number >> 0; case 0x7f4d: return mmio.page_number >> 0;
case 0x1f4e: return mmio.page_number >> 8; case 0x7f4e: return mmio.page_number >> 8;
case 0x1f4f: return mmio.program_counter; case 0x7f4f: return mmio.program_counter;
case 0x1f50: return mmio.r1f50; case 0x7f50: return mmio.r1f50;
case 0x1f51: return mmio.r1f51; case 0x7f51: return mmio.r1f51;
case 0x1f52: return mmio.r1f52; case 0x7f52: return mmio.r1f52;
case 0x1f53: case 0x1f54: case 0x1f55: case 0x1f56: case 0x7f53: case 0x7f54: case 0x7f55: case 0x7f56:
case 0x1f57: case 0x1f58: case 0x1f59: case 0x1f5a: case 0x7f57: case 0x7f58: case 0x7f59: case 0x7f5a:
case 0x1f5b: case 0x1f5c: case 0x1f5d: case 0x1f5e: case 0x7f5b: case 0x7f5c: case 0x7f5d: case 0x7f5e:
case 0x1f5f: return ((regs.halt == false) << 6) | ((regs.halt == true) << 1); case 0x7f5f: return ((regs.halt == false) << 6) | ((regs.halt == true) << 1);
} }
//Vector //Vector
if(addr >= 0x1f60 && addr <= 0x1f7f) { if(addr >= 0x7f60 && addr <= 0x7f7f) {
return mmio.vector[addr & 0x1f]; return mmio.vector[addr & 0x1f];
} }
//GPRs //GPRs
if((addr >= 0x1f80 && addr <= 0x1faf) || (addr >= 0x1fc0 && addr <= 0x1fef)) { if((addr >= 0x7f80 && addr <= 0x7faf) || (addr >= 0x7fc0 && addr <= 0x7fef)) {
uint index = (addr & 0x3f) / 3; //0..15 uint index = (addr & 0x3f) / 3; //0..15
uint shift = ((addr & 0x3f) % 3) * 8; //0, 8, 16 uint shift = ((addr & 0x3f) % 3) * 8; //0, 8, 16
return regs.gpr[index] >> shift; return regs.gpr[index] >> shift;
@ -103,52 +110,46 @@ auto HitachiDSP::dsp_read(uint addr, uint8) -> uint8 {
} }
auto HitachiDSP::dsp_write(uint addr, uint8 data) -> void { auto HitachiDSP::dsp_write(uint addr, uint8 data) -> void {
addr &= 0x1fff; addr = 0x7c00 | (addr & 0x03ff);
//Data RAM
if((addr >= 0x0000 && addr <= 0x0bff) || (addr >= 0x1000 && addr <= 0x1bff)) {
dataRAM[addr & 0x0fff] = data;
return;
}
//MMIO //MMIO
switch(addr) { switch(addr) {
case 0x1f40: mmio.dma_source = (mmio.dma_source & 0xffff00) | (data << 0); return; case 0x7f40: mmio.dma_source = (mmio.dma_source & 0xffff00) | (data << 0); return;
case 0x1f41: mmio.dma_source = (mmio.dma_source & 0xff00ff) | (data << 8); return; case 0x7f41: mmio.dma_source = (mmio.dma_source & 0xff00ff) | (data << 8); return;
case 0x1f42: mmio.dma_source = (mmio.dma_source & 0x00ffff) | (data << 16); return; case 0x7f42: mmio.dma_source = (mmio.dma_source & 0x00ffff) | (data << 16); return;
case 0x1f43: mmio.dma_length = (mmio.dma_length & 0xff00) | (data << 0); return; case 0x7f43: mmio.dma_length = (mmio.dma_length & 0xff00) | (data << 0); return;
case 0x1f44: mmio.dma_length = (mmio.dma_length & 0x00ff) | (data << 8); return; case 0x7f44: mmio.dma_length = (mmio.dma_length & 0x00ff) | (data << 8); return;
case 0x1f45: mmio.dma_target = (mmio.dma_target & 0xffff00) | (data << 0); return; case 0x7f45: mmio.dma_target = (mmio.dma_target & 0xffff00) | (data << 0); return;
case 0x1f46: mmio.dma_target = (mmio.dma_target & 0xff00ff) | (data << 8); return; case 0x7f46: mmio.dma_target = (mmio.dma_target & 0xff00ff) | (data << 8); return;
case 0x1f47: mmio.dma_target = (mmio.dma_target & 0x00ffff) | (data << 16); case 0x7f47: mmio.dma_target = (mmio.dma_target & 0x00ffff) | (data << 16);
if(regs.halt) mmio.dma = true; if(regs.halt) mmio.dma = true;
return; return;
case 0x1f48: mmio.r1f48 = data & 0x01; return; case 0x7f48: mmio.r1f48 = data & 0x01; return;
case 0x1f49: mmio.program_offset = (mmio.program_offset & 0xffff00) | (data << 0); return; case 0x7f49: mmio.program_offset = (mmio.program_offset & 0xffff00) | (data << 0); return;
case 0x1f4a: mmio.program_offset = (mmio.program_offset & 0xff00ff) | (data << 8); return; case 0x7f4a: mmio.program_offset = (mmio.program_offset & 0xff00ff) | (data << 8); return;
case 0x1f4b: mmio.program_offset = (mmio.program_offset & 0x00ffff) | (data << 16); return; case 0x7f4b: mmio.program_offset = (mmio.program_offset & 0x00ffff) | (data << 16); return;
case 0x1f4c: mmio.r1f4c = data & 0x03; return; case 0x7f4c: mmio.r1f4c = data & 0x03; return;
case 0x1f4d: mmio.page_number = (mmio.page_number & 0x7f00) | ((data & 0xff) << 0); return; case 0x7f4d: mmio.page_number = (mmio.page_number & 0x7f00) | ((data & 0xff) << 0); return;
case 0x1f4e: mmio.page_number = (mmio.page_number & 0x00ff) | ((data & 0x7f) << 8); return; case 0x7f4e: mmio.page_number = (mmio.page_number & 0x00ff) | ((data & 0x7f) << 8); return;
case 0x1f4f: mmio.program_counter = data; case 0x7f4f: mmio.program_counter = data;
if(regs.halt) { if(regs.halt) {
regs.pc = mmio.page_number * 256 + mmio.program_counter; regs.pc = mmio.page_number * 256 + mmio.program_counter;
regs.halt = false; regs.halt = false;
} }
return; return;
case 0x1f50: mmio.r1f50 = data & 0x77; return; case 0x7f50: mmio.r1f50 = data & 0x77; return;
case 0x1f51: mmio.r1f51 = data & 0x01; return; case 0x7f51: mmio.r1f51 = data & 0x01; return;
case 0x1f52: mmio.r1f52 = data & 0x01; return; case 0x7f52: mmio.r1f52 = data & 0x01; return;
} }
//Vector //Vector
if(addr >= 0x1f60 && addr <= 0x1f7f) { if(addr >= 0x7f60 && addr <= 0x7f7f) {
mmio.vector[addr & 0x1f] = data; mmio.vector[addr & 0x1f] = data;
return; return;
} }
//GPRs //GPRs
if((addr >= 0x1f80 && addr <= 0x1faf) || (addr >= 0x1fc0 && addr <= 0x1fef)) { if((addr >= 0x7f80 && addr <= 0x7faf) || (addr >= 0x7fc0 && addr <= 0x7fef)) {
uint index = (addr & 0x3f) / 3; uint index = (addr & 0x3f) / 3;
switch((addr & 0x3f) % 3) { switch((addr & 0x3f) % 3) {
case 0: regs.gpr[index] = (regs.gpr[index] & 0xffff00) | (data << 0); return; case 0: regs.gpr[index] = (regs.gpr[index] & 0xffff00) | (data << 0); return;

View File

@ -14,7 +14,6 @@ auto MCC::load() -> void {
auto MCC::unload() -> void { auto MCC::unload() -> void {
rom.reset(); rom.reset();
ram.reset(); ram.reset();
psram.reset();
} }
auto MCC::power() -> void { auto MCC::power() -> void {
@ -24,25 +23,18 @@ auto MCC::reset() -> void {
for(auto n : range(16)) r[n] = 0x00; for(auto n : range(16)) r[n] = 0x00;
r[0x07] = 0x80; r[0x07] = 0x80;
r[0x08] = 0x80; r[0x08] = 0x80;
mmio_commit(); commit();
} }
auto MCC::memory_access(bool write, Memory& memory, uint addr, uint8 data) -> uint8 { auto MCC::memory_access(bool write, Memory& memory, uint addr, uint8 data) -> uint8 {
if(write == 0) return memory_read(memory, addr, data);
memory_write(memory, addr, data);
}
auto MCC::memory_read(Memory& memory, uint addr, uint8 data) -> uint8 {
addr = bus.mirror(addr, memory.size()); addr = bus.mirror(addr, memory.size());
return memory.read(addr, data); if(!write) {
return memory.read(addr, data);
} else {
memory.write(addr, data);
}
} }
auto MCC::memory_write(Memory& memory, uint addr, uint8 data) -> void {
addr = bus.mirror(addr, memory.size());
return memory.write(addr, data);
}
//mcu_access() allows mcu_read() and mcu_write() to share decoding logic
auto MCC::mcu_access(bool write, uint addr, uint8 data) -> uint8 { auto MCC::mcu_access(bool write, uint addr, uint8 data) -> uint8 {
if((addr & 0xe08000) == 0x008000) { //$00-1f:8000-ffff if((addr & 0xe08000) == 0x008000) { //$00-1f:8000-ffff
if(r07 == 1) { if(r07 == 1) {
@ -58,72 +50,60 @@ auto MCC::mcu_access(bool write, uint addr, uint8 data) -> uint8 {
} }
} }
if((addr & 0xe0e000) == 0x206000) { //$20-3f:6000-7fff
return memory_access(write, psram, addr, data);
}
if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff
if(r05 == 0) return memory_access(write, psram, addr & 0x0fffff, data); if(r05 == 0) return memory_access(write, ram, addr & 0x0fffff, data);
} }
if((addr & 0xf00000) == 0x500000) { //$50-5f:0000-ffff if((addr & 0xf00000) == 0x500000) { //$50-5f:0000-ffff
if(r06 == 0) return memory_access(write, psram, addr & 0x0fffff, data); if(r06 == 0) return memory_access(write, ram, addr & 0x0fffff, data);
} }
if((addr & 0xf00000) == 0x600000) { //$60-6f:0000-ffff if((addr & 0xf00000) == 0x600000) { //$60-6f:0000-ffff
if(r03 == 1) return memory_access(write, psram, addr & 0x0fffff, data); if(r03 == 1) return memory_access(write, ram, addr & 0x0fffff, data);
} }
if((addr & 0xf80000) == 0x700000) { //$70-77:0000-ffff if((addr & 0xf80000) == 0x700000) { //$70-77:0000-ffff
return memory_access(write, psram, addr & 0x07ffff, data); return memory_access(write, ram, addr & 0x07ffff, data);
} }
if(((addr & 0x408000) == 0x008000) //$00-3f|80-bf:8000-ffff if(((addr & 0x408000) == 0x008000) //$00-3f,80-bf:8000-ffff
|| ((addr & 0x400000) == 0x400000) //$40-7f|c0-ff:0000-ffff || ((addr & 0x400000) == 0x400000) //$40-7f,c0-ff:0000-ffff
) { ) {
if(r02 == 0) addr = ((addr & 0x7f0000) >> 1) | (addr & 0x7fff); if(r02 == 0) addr = ((addr & 0x7f0000) >> 1) | (addr & 0x7fff);
Memory& memory = (r01 == 0 ? (Memory&)satellaviewcartridge : (Memory&)psram); Memory& memory = (r01 == 0 ? (Memory&)satellaviewcartridge : (Memory&)ram);
return memory_access(write, memory, addr & 0x7fffff, data); return memory_access(write, memory, addr & 0x7fffff, data);
} }
return data;
}
auto MCC::mcu_read(uint addr, uint8 data) -> uint8 {
return mcu_access(0, addr, data);
}
auto MCC::mcu_write(uint addr, uint8 data) -> void {
mcu_access(1, addr, data);
}
auto MCC::mmio_read(uint addr, uint8 data) -> uint8 {
if((addr & 0xf0ffff) == 0x005000) { //$00-0f:5000
uint8 n = (addr >> 16) & 15;
return r[n];
}
if((addr & 0xf8f000) == 0x105000) { //$10-17:5000-5fff
return memory_read(ram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff), data);
}
return 0x00; return 0x00;
} }
auto MCC::mmio_write(uint addr, uint8 data) -> void { auto MCC::mcu_read(uint addr, uint8 data) -> uint8 {
return mcu_access(false, addr, data);
}
auto MCC::mcu_write(uint addr, uint8 data) -> void {
mcu_access(true, addr, data);
}
auto MCC::read(uint addr, uint8 data) -> uint8 {
if((addr & 0xf0ffff) == 0x005000) { //$00-0f:5000
uint8 n = (addr >> 16) & 15;
return r[n];
}
return data;
}
auto MCC::write(uint addr, uint8 data) -> void {
if((addr & 0xf0ffff) == 0x005000) { //$00-0f:5000 if((addr & 0xf0ffff) == 0x005000) { //$00-0f:5000
uint8 n = (addr >> 16) & 15; uint8 n = (addr >> 16) & 15;
r[n] = data; r[n] = data;
if(n == 0x0e && data & 0x80) mmio_commit(); if(n == 0x0e && data & 0x80) commit();
return; return;
} }
if((addr & 0xf8f000) == 0x105000) { //$10-17:5000-5fff
return memory_write(ram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff), data);
}
} }
auto MCC::mmio_commit() -> void { auto MCC::commit() -> void {
r00 = r[0x00] & 0x80; r00 = r[0x00] & 0x80;
r01 = r[0x01] & 0x80; r01 = r[0x01] & 0x80;
r02 = r[0x02] & 0x80; r02 = r[0x02] & 0x80;

View File

@ -3,7 +3,6 @@
struct MCC { struct MCC {
MappedRAM rom; MappedRAM rom;
MappedRAM ram; MappedRAM ram;
MappedRAM psram;
auto init() -> void; auto init() -> void;
auto load() -> void; auto load() -> void;
@ -12,16 +11,15 @@ struct MCC {
auto reset() -> void; auto reset() -> void;
auto memory_access(bool write, Memory& memory, uint addr, uint8 data) -> uint8; auto memory_access(bool write, Memory& memory, uint addr, uint8 data) -> uint8;
auto memory_read(Memory& memory, uint addr, uint8 data) -> uint8;
auto memory_write(Memory& memory, uint addr, uint8 data) -> void;
auto mcu_access(bool write, uint addr, uint8 data) -> uint8; auto mcu_access(bool write, uint addr, uint8 data) -> uint8;
auto mcu_read(uint addr, uint8 data) -> uint8; auto mcu_read(uint addr, uint8 data) -> uint8;
auto mcu_write(uint addr, uint8 data) -> void; auto mcu_write(uint addr, uint8 data) -> void;
auto mmio_read(uint addr, uint8 data) -> uint8; auto read(uint addr, uint8 data) -> uint8;
auto mmio_write(uint addr, uint8 data) -> void; auto write(uint addr, uint8 data) -> void;
auto mmio_commit() -> void;
auto commit() -> void;
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;

View File

@ -1,4 +1,3 @@
auto MCC::serialize(serializer& s) -> void { auto MCC::serialize(serializer& s) -> void {
s.array(ram.data(), ram.size()); s.array(ram.data(), ram.size());
s.array(psram.data(), psram.size());
} }

View File

@ -91,7 +91,7 @@ auto MSU1::reset() -> void {
auto MSU1::dataOpen() -> void { auto MSU1::dataOpen() -> void {
if(dataFile.open()) dataFile.close(); if(dataFile.open()) dataFile.close();
auto document = BML::unserialize(cartridge.information.markup.cartridge); auto document = BML::unserialize(cartridge.information.markup.cartridge);
string name = document["cartridge/msu1/rom/name"].text(); string name = document["board/msu1/rom/name"].text();
if(!name) name = "msu1.rom"; if(!name) name = "msu1.rom";
if(dataFile.open({interface->path(ID::SuperFamicom), name}, file::mode::read)) { if(dataFile.open({interface->path(ID::SuperFamicom), name}, file::mode::read)) {
dataFile.seek(mmio.dataReadOffset); dataFile.seek(mmio.dataReadOffset);
@ -102,7 +102,7 @@ auto MSU1::audioOpen() -> void {
if(audioFile.open()) audioFile.close(); if(audioFile.open()) audioFile.close();
auto document = BML::unserialize(cartridge.information.markup.cartridge); auto document = BML::unserialize(cartridge.information.markup.cartridge);
string name = {"track-", mmio.audioTrack, ".pcm"}; string name = {"track-", mmio.audioTrack, ".pcm"};
for(auto track : document.find("cartridge/msu1/track")) { for(auto track : document.find("board/msu1/track")) {
if(track["number"].natural() != mmio.audioTrack) continue; if(track["number"].natural() != mmio.audioTrack) continue;
name = track["name"].text(); name = track["name"].text();
break; break;

View File

@ -21,7 +21,7 @@ auto NECDSP::enter() -> void {
auto NECDSP::read(uint addr, uint8) -> uint8 { auto NECDSP::read(uint addr, uint8) -> uint8 {
cpu.synchronizeCoprocessors(); cpu.synchronizeCoprocessors();
if(addr & Select) { if(addr & 1) {
return uPD96050::readSR(); return uPD96050::readSR();
} else { } else {
return uPD96050::readDR(); return uPD96050::readDR();
@ -30,7 +30,7 @@ auto NECDSP::read(uint addr, uint8) -> uint8 {
auto NECDSP::write(uint addr, uint8 data) -> void { auto NECDSP::write(uint addr, uint8 data) -> void {
cpu.synchronizeCoprocessors(); cpu.synchronizeCoprocessors();
if(addr & Select) { if(addr & 1) {
return uPD96050::writeSR(data); return uPD96050::writeSR(data);
} else { } else {
return uPD96050::writeDR(data); return uPD96050::writeDR(data);

View File

@ -16,8 +16,6 @@ struct NECDSP : Processor::uPD96050, Coprocessor {
auto firmware() const -> vector<uint8>; auto firmware() const -> vector<uint8>;
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
unsigned Select;
}; };
extern NECDSP necdsp; extern NECDSP necdsp;

View File

@ -1,9 +1,10 @@
auto SA1::bus_read(uint addr, uint8 data) -> uint8 { auto SA1::bus_read(uint addr, uint8 data) -> uint8 {
if((addr & 0x40fe00) == 0x002200) { //$00-3f|80-bf:2200-23ff if((addr & 0x40fe00) == 0x002200) { //$00-3f,80-bf:2200-23ff
return mmio_read(addr, data); return mmio_read(addr, data);
} }
if((addr & 0x408000) == 0x008000) { //$00-3f|80-bf:8000-ffff if((addr & 0x408000) == 0x008000) { //$00-3f,80-bf:8000-ffff
addr = ((addr & 0x800000) >> 2) | ((addr & 0x3f0000) >> 1) | (addr & 0x7fff);
return mmcrom_read(addr, data); return mmcrom_read(addr, data);
} }
@ -11,16 +12,16 @@ auto SA1::bus_read(uint addr, uint8 data) -> uint8 {
return mmcrom_read(addr, data); return mmcrom_read(addr, data);
} }
if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff if((addr & 0x40e000) == 0x006000) { //$00-3f,80-bf:6000-7fff
return mmc_sa1_read(addr, data); return mmc_sa1_read(addr, data);
} }
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff if((addr & 0x40f800) == 0x000000) { //$00-3f,80-bf:0000-07ff
synchronizeCPU(); synchronizeCPU();
return iram.read(addr & 2047, data); return iram.read(addr & 2047, data);
} }
if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff if((addr & 0x40f800) == 0x003000) { //$00-3f,80-bf:3000-37ff
synchronizeCPU(); synchronizeCPU();
return iram.read(addr & 2047, data); return iram.read(addr & 2047, data);
} }
@ -40,20 +41,20 @@ auto SA1::bus_read(uint addr, uint8 data) -> uint8 {
} }
auto SA1::bus_write(uint addr, uint8 data) -> void { auto SA1::bus_write(uint addr, uint8 data) -> void {
if((addr & 0x40fe00) == 0x002200) { //$00-3f|80-bf:2200-23ff if((addr & 0x40fe00) == 0x002200) { //$00-3f,80-bf:2200-23ff
return mmio_write(addr, data); return mmio_write(addr, data);
} }
if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff if((addr & 0x40e000) == 0x006000) { //$00-3f,80-bf:6000-7fff
return mmc_sa1_write(addr, data); return mmc_sa1_write(addr, data);
} }
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff if((addr & 0x40f800) == 0x000000) { //$00-3f,80-bf:0000-07ff
synchronizeCPU(); synchronizeCPU();
return iram.write(addr & 2047, data); return iram.write(addr & 2047, data);
} }
if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff if((addr & 0x40f800) == 0x003000) { //$00-3f,80-bf:3000-37ff
synchronizeCPU(); synchronizeCPU();
return iram.write(addr & 2047, data); return iram.write(addr & 2047, data);
} }
@ -74,7 +75,8 @@ auto SA1::bus_write(uint addr, uint8 data) -> void {
//to avoid syncing the S-CPU and SA-1*; as both chips are able to access //to avoid syncing the S-CPU and SA-1*; as both chips are able to access
//these ports. //these ports.
auto SA1::vbr_read(uint addr, uint8 data) -> uint8 { auto SA1::vbr_read(uint addr, uint8 data) -> uint8 {
if((addr & 0x408000) == 0x008000) { //$00-3f|80-bf:8000-ffff if((addr & 0x408000) == 0x008000) { //$00-3f,80-bf:8000-ffff
addr = ((addr & 0x800000) >> 2) | ((addr & 0x3f0000) >> 1) | (addr & 0x7fff);
return mmcrom_read(addr, data); return mmcrom_read(addr, data);
} }
@ -82,7 +84,7 @@ auto SA1::vbr_read(uint addr, uint8 data) -> uint8 {
return mmcrom_read(addr, data); return mmcrom_read(addr, data);
} }
if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff if((addr & 0x40e000) == 0x006000) { //$00-3f,80-bf:6000-7fff
return bwram.read(addr & (bwram.size() - 1), data); return bwram.read(addr & (bwram.size() - 1), data);
} }
@ -90,11 +92,11 @@ auto SA1::vbr_read(uint addr, uint8 data) -> uint8 {
return bwram.read(addr & (bwram.size() - 1), data); return bwram.read(addr & (bwram.size() - 1), data);
} }
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff if((addr & 0x40f800) == 0x000000) { //$00-3f,80-bf:0000-07ff
return iram.read(addr & 2047, data); return iram.read(addr & 2047, data);
} }
if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff if((addr & 0x40f800) == 0x003000) { //$00-3f,80-bf:3000-37ff
return iram.read(addr & 2047, data); return iram.read(addr & 2047, data);
} }
@ -122,55 +124,42 @@ auto SA1::op_write(uint addr, uint8 data) -> void {
bus_write(addr, regs.mdr = data); bus_write(addr, regs.mdr = data);
} }
//note: addresses are translated prior to invoking this function:
//$00-3f,80-bf:8000-ffff mask=0x408000 => $00-3f:0000-ffff
//$c0-ff:0000-ffff mask=0
auto SA1::mmcrom_read(uint addr, uint8) -> uint8 { auto SA1::mmcrom_read(uint addr, uint8) -> uint8 {
if((addr & 0xffffe0) == 0x00ffe0) { //reset vector overrides
if(addr == 0xffea && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 0; if((addr & 0xffffe0) == 0x007fe0) { //$00:ffe0-ffef
if(addr == 0xffeb && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 8; if(addr == 0x7fea && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 0;
if(addr == 0xffee && sa1.mmio.cpu_ivsw) return sa1.mmio.siv >> 0; if(addr == 0x7feb && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 8;
if(addr == 0xffef && sa1.mmio.cpu_ivsw) return sa1.mmio.siv >> 8; if(addr == 0x7fee && sa1.mmio.cpu_ivsw) return sa1.mmio.siv >> 0;
if(addr == 0x7fef && sa1.mmio.cpu_ivsw) return sa1.mmio.siv >> 8;
} }
static auto read = [](uint addr) { static auto read = [](uint addr) {
return sa1.rom.read(bus.mirror(addr, sa1.rom.size())); return sa1.rom.read(bus.mirror(addr, sa1.rom.size()));
}; };
if((addr & 0xe08000) == 0x008000) { //$00-1f:8000-ffff bool lo = addr < 0x400000; //*bmode==0 only applies to $00-3f,80-bf:8000-ffff
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x007fff); addr &= 0x3fffff;
if(mmio.cbmode == 0) return read(0x000000 | addr);
return read((mmio.cb << 20) | addr);
}
if((addr & 0xe08000) == 0x208000) { //$20-3f:8000-ffff if(addr < 0x100000) { //$00-1f,8000-ffff; $c0-cf:0000-ffff
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x007fff); if(lo && mmio.cbmode == 0) return read(addr);
if(mmio.dbmode == 0) return read(0x100000 | addr);
return read((mmio.db << 20) | addr);
}
if((addr & 0xe08000) == 0x808000) { //$80-9f:8000-ffff
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x007fff);
if(mmio.ebmode == 0) return read(0x200000 | addr);
return read((mmio.eb << 20) | addr);
}
if((addr & 0xe08000) == 0xa08000) { //$a0-bf:8000-ffff
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x007fff);
if(mmio.fbmode == 0) return read(0x300000 | addr);
return read((mmio.fb << 20) | addr);
}
if((addr & 0xf00000) == 0xc00000) { //$c0-cf:0000-ffff
return read((mmio.cb << 20) | (addr & 0x0fffff)); return read((mmio.cb << 20) | (addr & 0x0fffff));
} }
if((addr & 0xf00000) == 0xd00000) { //$d0-df:0000-ffff if(addr < 0x200000) { //$20-3f,8000-ffff; $d0-df:0000-ffff
if(lo && mmio.dbmode == 0) return read(addr);
return read((mmio.db << 20) | (addr & 0x0fffff)); return read((mmio.db << 20) | (addr & 0x0fffff));
} }
if((addr & 0xf00000) == 0xe00000) { //$e0-ef:0000-ffff if(addr < 0x300000) { //$80-9f,8000-ffff; $e0-ef:0000-ffff
if(lo && mmio.ebmode == 0) return read(addr);
return read((mmio.eb << 20) | (addr & 0x0fffff)); return read((mmio.eb << 20) | (addr & 0x0fffff));
} }
if((addr & 0xf00000) == 0xf00000) { //$f0-ff:0000-ffff if(addr < 0x400000) { //$a0-bf,8000-ffff; $f0-ff:0000-ffff
if(lo && mmio.fbmode == 0) return read(addr);
return read((mmio.fb << 20) | (addr & 0x0fffff)); return read((mmio.fb << 20) | (addr & 0x0fffff));
} }
@ -181,7 +170,7 @@ auto SA1::mmcrom_write(uint addr, uint8 data) -> void {
} }
auto SA1::mmcbwram_read(uint addr, uint8 data) -> uint8 { auto SA1::mmcbwram_read(uint addr, uint8 data) -> uint8 {
if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff if(addr < 0x2000) { //$00-3f,80-bf:6000-7fff
cpu.synchronizeCoprocessors(); cpu.synchronizeCoprocessors();
addr = bus.mirror(mmio.sbm * 0x2000 + (addr & 0x1fff), cpubwram.size()); addr = bus.mirror(mmio.sbm * 0x2000 + (addr & 0x1fff), cpubwram.size());
return cpubwram.read(addr); return cpubwram.read(addr);
@ -195,7 +184,7 @@ auto SA1::mmcbwram_read(uint addr, uint8 data) -> uint8 {
} }
auto SA1::mmcbwram_write(uint addr, uint8 data) -> void { auto SA1::mmcbwram_write(uint addr, uint8 data) -> void {
if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff if(addr < 0x2000) { //$00-3f,80-bf:6000-7fff
cpu.synchronizeCoprocessors(); cpu.synchronizeCoprocessors();
addr = bus.mirror(mmio.sbm * 0x2000 + (addr & 0x1fff), cpubwram.size()); addr = bus.mirror(mmio.sbm * 0x2000 + (addr & 0x1fff), cpubwram.size());
return cpubwram.write(addr, data); return cpubwram.write(addr, data);

View File

@ -13,8 +13,8 @@ auto SDD1::init() -> void {
void SDD1::load() { void SDD1::load() {
//hook S-CPU DMA MMIO registers to gather information for struct dma[]; //hook S-CPU DMA MMIO registers to gather information for struct dma[];
//buffer address and transfer size information for use in SDD1::mcu_read() //buffer address and transfer size information for use in SDD1::mcu_read()
bus.map({&SDD1::read, &sdd1}, {&SDD1::write, &sdd1}, 0x00, 0x3f, 0x4300, 0x437f); bus.map({&SDD1::dma_read, &sdd1}, {&SDD1::dma_write, &sdd1}, 0x00, 0x3f, 0x4300, 0x437f);
bus.map({&SDD1::read, &sdd1}, {&SDD1::write, &sdd1}, 0x80, 0xbf, 0x4300, 0x437f); bus.map({&SDD1::dma_read, &sdd1}, {&SDD1::dma_write, &sdd1}, 0x80, 0xbf, 0x4300, 0x437f);
} }
auto SDD1::unload() -> void { auto SDD1::unload() -> void {
@ -42,11 +42,7 @@ auto SDD1::reset() -> void {
} }
auto SDD1::read(uint addr, uint8 data) -> uint8 { auto SDD1::read(uint addr, uint8 data) -> uint8 {
addr &= 0x40ffff; addr = 0x4800 | (addr & 7);
if((addr & 0x404380) == 0x4300) {
return cpu.mmio_read(addr, data);
}
switch(addr) { switch(addr) {
case 0x4804: return mmc[0] >> 20; case 0x4804: return mmc[0] >> 20;
@ -59,20 +55,7 @@ auto SDD1::read(uint addr, uint8 data) -> uint8 {
} }
auto SDD1::write(uint addr, uint8 data) -> void { auto SDD1::write(uint addr, uint8 data) -> void {
addr &= 0xffff; addr = 0x4800 | (addr & 7);
if((addr & 0x4380) == 0x4300) {
uint channel = (addr >> 4) & 7;
switch(addr & 15) {
case 2: dma[channel].addr = (dma[channel].addr & 0xffff00) + (data << 0); break;
case 3: dma[channel].addr = (dma[channel].addr & 0xff00ff) + (data << 8); break;
case 4: dma[channel].addr = (dma[channel].addr & 0x00ffff) + (data << 16); break;
case 5: dma[channel].size = (dma[channel].size & 0xff00) + (data << 0); break;
case 6: dma[channel].size = (dma[channel].size & 0x00ff) + (data << 8); break;
}
return cpu.mmio_write(addr, data);
}
switch(addr) { switch(addr) {
case 0x4800: sdd1_enable = data; break; case 0x4800: sdd1_enable = data; break;
@ -85,6 +68,23 @@ auto SDD1::write(uint addr, uint8 data) -> void {
} }
} }
auto SDD1::dma_read(uint addr, uint8 data) -> uint8 {
return cpu.mmio_read(addr, data);
}
auto SDD1::dma_write(uint addr, uint8 data) -> void {
uint channel = (addr >> 4) & 7;
switch(addr & 15) {
case 2: dma[channel].addr = (dma[channel].addr & 0xffff00) + (data << 0); break;
case 3: dma[channel].addr = (dma[channel].addr & 0xff00ff) + (data << 8); break;
case 4: dma[channel].addr = (dma[channel].addr & 0x00ffff) + (data << 16); break;
case 5: dma[channel].size = (dma[channel].size & 0xff00) + (data << 0); break;
case 6: dma[channel].size = (dma[channel].size & 0x00ff) + (data << 8); break;
}
return cpu.mmio_write(addr, data);
}
auto SDD1::mmc_read(uint addr) -> uint8 { auto SDD1::mmc_read(uint addr) -> uint8 {
return rom.read(mmc[(addr >> 20) & 3] + (addr & 0x0fffff)); return rom.read(mmc[(addr >> 20) & 3] + (addr & 0x0fffff));
} }
@ -108,13 +108,12 @@ auto SDD1::mmc_read(uint addr) -> uint8 {
//the actual S-DD1 transfer can occur on any channel, but it is most likely limited to //the actual S-DD1 transfer can occur on any channel, but it is most likely limited to
//one transfer per $420b write (for spooling purposes). however, this is not known for certain. //one transfer per $420b write (for spooling purposes). however, this is not known for certain.
auto SDD1::mcurom_read(uint addr, uint8) -> uint8 { auto SDD1::mcurom_read(uint addr, uint8) -> uint8 {
if(addr < 0x400000) { //(addr & 0x408000) == 0x008000) { //$00-3f|80-bf:8000-ffff //map address=00-3f,80-bf:8000-ffff mask=0x808000 => 00-1f:0000-ffff
if(addr < 0x200000) {
return rom.read(addr); return rom.read(addr);
//addr = ((addr & 0x7f0000) >> 1) | (addr & 0x7fff);
//return rom.read(addr);
} }
//$40-7f|c0-ff:0000-ffff (MMC) //map address=c0-ff:0000-ffff
if(sdd1_enable & xfer_enable) { if(sdd1_enable & xfer_enable) {
//at least one channel has S-DD1 decompression enabled ... //at least one channel has S-DD1 decompression enabled ...
for(auto n : range(8)) { for(auto n : range(8)) {
@ -148,7 +147,7 @@ auto SDD1::mcurom_write(uint addr, uint8 data) -> void {
} }
auto SDD1::mcuram_read(uint addr, uint8 data) -> uint8 { auto SDD1::mcuram_read(uint addr, uint8 data) -> uint8 {
if((addr & 0x60e000) == 0x006000) { //$00-3f|80-bf:6000-7fff if((addr & 0x60e000) == 0x006000) { //$00-3f,80-bf:6000-7fff
return ram.read(addr & 0x1fff, data); return ram.read(addr & 0x1fff, data);
} }
@ -160,7 +159,7 @@ auto SDD1::mcuram_read(uint addr, uint8 data) -> uint8 {
} }
auto SDD1::mcuram_write(uint addr, uint8 data) -> void { auto SDD1::mcuram_write(uint addr, uint8 data) -> void {
if((addr & 0x60e000) == 0x006000) { //$00-3f|80-bf:6000-7fff if((addr & 0x60e000) == 0x006000) { //$00-3f,80-bf:6000-7fff
return ram.write(addr & 0x1fff, data); return ram.write(addr & 0x1fff, data);
} }

View File

@ -8,6 +8,9 @@ struct SDD1 {
auto read(uint addr, uint8 data) -> uint8; auto read(uint addr, uint8 data) -> uint8;
auto write(uint addr, uint8 data) -> void; auto write(uint addr, uint8 data) -> void;
auto dma_read(uint addr, uint8 data) -> uint8;
auto dma_write(uint addr, uint8 data) -> void;
auto mmc_read(uint addr) -> uint8; auto mmc_read(uint addr) -> uint8;
auto mcurom_read(uint addr, uint8 data) -> uint8; auto mcurom_read(uint addr, uint8 data) -> uint8;

View File

@ -111,15 +111,14 @@ auto SPC7110::reset() -> void {
auto SPC7110::read(uint addr, uint8 data) -> uint8 { auto SPC7110::read(uint addr, uint8 data) -> uint8 {
cpu.synchronizeCoprocessors(); cpu.synchronizeCoprocessors();
if((addr & 0xff0000) == 0x500000) addr = 0x4800; if((addr & 0xff0000) == 0x500000) addr = 0x4800; //$50:0000-ffff == $4800
addr = 0x4800 | (addr & 0x3f); if((addr & 0xff0000) == 0x580000) addr = 0x4808; //$58:0000-ffff == $4808
addr = 0x4800 | (addr & 0x3f); //$00-3f,80-bf:4800-483f
switch(addr) { switch(addr) {
//================== //==================
//decompression unit //decompression unit
//================== //==================
case 0x4800: { case 0x4800: {
uint16 counter = r4809 | r480a << 8; uint16 counter = r4809 | r480a << 8;
counter--; counter--;
@ -143,7 +142,6 @@ auto SPC7110::read(uint addr, uint8 data) -> uint8 {
//============== //==============
//data port unit //data port unit
//============== //==============
case 0x4810: { case 0x4810: {
data = r4810; data = r4810;
data_port_increment_4810(); data_port_increment_4810();
@ -165,7 +163,6 @@ auto SPC7110::read(uint addr, uint8 data) -> uint8 {
//===================== //=====================
//arithmetic logic unit //arithmetic logic unit
//===================== //=====================
case 0x4820: return r4820; case 0x4820: return r4820;
case 0x4821: return r4821; case 0x4821: return r4821;
case 0x4822: return r4822; case 0x4822: return r4822;
@ -186,13 +183,11 @@ auto SPC7110::read(uint addr, uint8 data) -> uint8 {
//=================== //===================
//memory control unit //memory control unit
//=================== //===================
case 0x4830: return r4830; case 0x4830: return r4830;
case 0x4831: return r4831; case 0x4831: return r4831;
case 0x4832: return r4832; case 0x4832: return r4832;
case 0x4833: return r4833; case 0x4833: return r4833;
case 0x4834: return r4834; case 0x4834: return r4834;
} }
return data; return data;
@ -200,14 +195,14 @@ auto SPC7110::read(uint addr, uint8 data) -> uint8 {
auto SPC7110::write(uint addr, uint8 data) -> void { auto SPC7110::write(uint addr, uint8 data) -> void {
cpu.synchronizeCoprocessors(); cpu.synchronizeCoprocessors();
addr = 0x4800 | (addr & 0x3f); if((addr & 0xff0000) == 0x500000) addr = 0x4800; //$50:0000-ffff == $4800
if((addr & 0xff0000) == 0x580000) addr = 0x4808; //$58:0000-ffff == $4808
addr = 0x4800 | (addr & 0x3f); //$00-3f,80-bf:4800-483f
switch(addr) { switch(addr) {
//================== //==================
//decompression unit //decompression unit
//================== //==================
case 0x4801: r4801 = data; break; case 0x4801: r4801 = data; break;
case 0x4802: r4802 = data; break; case 0x4802: r4802 = data; break;
case 0x4803: r4803 = data; break; case 0x4803: r4803 = data; break;
@ -223,7 +218,6 @@ auto SPC7110::write(uint addr, uint8 data) -> void {
//============== //==============
//data port unit //data port unit
//============== //==============
case 0x4811: r4811 = data; break; case 0x4811: r4811 = data; break;
case 0x4812: r4812 = data; break; case 0x4812: r4812 = data; break;
case 0x4813: r4813 = data; data_port_read(); break; case 0x4813: r4813 = data; data_port_read(); break;
@ -236,7 +230,6 @@ auto SPC7110::write(uint addr, uint8 data) -> void {
//===================== //=====================
//arithmetic logic unit //arithmetic logic unit
//===================== //=====================
case 0x4820: r4820 = data; break; case 0x4820: r4820 = data; break;
case 0x4821: r4821 = data; break; case 0x4821: r4821 = data; break;
case 0x4822: r4822 = data; break; case 0x4822: r4822 = data; break;
@ -250,13 +243,11 @@ auto SPC7110::write(uint addr, uint8 data) -> void {
//=================== //===================
//memory control unit //memory control unit
//=================== //===================
case 0x4830: r4830 = data & 0x87; break; case 0x4830: r4830 = data & 0x87; break;
case 0x4831: r4831 = data & 0x07; break; case 0x4831: r4831 = data & 0x07; break;
case 0x4832: r4832 = data & 0x07; break; case 0x4832: r4832 = data & 0x07; break;
case 0x4833: r4833 = data & 0x07; break; case 0x4833: r4833 = data & 0x07; break;
case 0x4834: r4834 = data & 0x07; break; case 0x4834: r4834 = data & 0x07; break;
} }
} }
@ -264,12 +255,12 @@ auto SPC7110::write(uint addr, uint8 data) -> void {
//SPC7110::MCUROM //SPC7110::MCUROM
//=============== //===============
//map address=00-3f,80-bf:8000-ffff mask=0x800000 => 00-3f:8000-ffff
//map address=c0-ff:0000-ffff mask=0xc00000 => c0-ff:0000-ffff
auto SPC7110::mcurom_read(uint addr, uint8 data) -> uint8 { auto SPC7110::mcurom_read(uint addr, uint8 data) -> uint8 {
uint mask = (1 << (r4834 & 3)) - 1; //8mbit, 16mbit, 32mbit, 64mbit DROM uint mask = (1 << (r4834 & 3)) - 1; //8mbit, 16mbit, 32mbit, 64mbit DROM
if((addr & 0x708000) == 0x008000 //$00-0f|80-8f:8000-ffff if(addr < 0x100000) { //$00-0f,80-8f:8000-ffff; $c0-cf:0000-ffff
|| (addr & 0xf00000) == 0xc00000 // $c0-cf:0000-ffff
) {
addr &= 0x0fffff; addr &= 0x0fffff;
if(prom.size()) { //8mbit PROM if(prom.size()) { //8mbit PROM
return prom.read(bus.mirror(0x000000 + addr, prom.size())); return prom.read(bus.mirror(0x000000 + addr, prom.size()));
@ -278,9 +269,7 @@ auto SPC7110::mcurom_read(uint addr, uint8 data) -> uint8 {
return datarom_read(addr); return datarom_read(addr);
} }
if((addr & 0x708000) == 0x108000 //$10-1f|90-9f:8000-ffff if(addr < 0x200000) { //$10-1f,90-9f:8000-ffff; $d0-df:0000-ffff
|| (addr & 0xf00000) == 0xd00000 // $d0-df:0000-ffff
) {
addr &= 0x0fffff; addr &= 0x0fffff;
if(r4834 & 4) { //16mbit PROM if(r4834 & 4) { //16mbit PROM
return prom.read(bus.mirror(0x100000 + addr, prom.size())); return prom.read(bus.mirror(0x100000 + addr, prom.size()));
@ -289,17 +278,13 @@ auto SPC7110::mcurom_read(uint addr, uint8 data) -> uint8 {
return datarom_read(addr); return datarom_read(addr);
} }
if((addr & 0x708000) == 0x208000 //$20-2f|a0-af:8000-ffff if(addr < 0x300000) { //$20-2f,a0-af:8000-ffff; $e0-ef:0000-ffff
|| (addr & 0xf00000) == 0xe00000 // $e0-ef:0000-ffff
) {
addr &= 0x0fffff; addr &= 0x0fffff;
addr |= 0x100000 * (r4832 & 7); addr |= 0x100000 * (r4832 & 7);
return datarom_read(addr); return datarom_read(addr);
} }
if((addr & 0x708000) == 0x308000 //$30-3f|b0-bf:8000-ffff if(addr < 0x400000) { //$30-3f,b0-bf:8000-ffff; $f0-ff:0000-ffff
|| (addr & 0xf00000) == 0xf00000 // $f0-ff:0000-ffff
) {
addr &= 0x0fffff; addr &= 0x0fffff;
addr |= 0x100000 * (r4833 & 7); addr |= 0x100000 * (r4833 & 7);
return datarom_read(addr); return datarom_read(addr);
@ -315,21 +300,18 @@ auto SPC7110::mcurom_write(uint addr, uint8 data) -> void {
//SPC7110::MCURAM //SPC7110::MCURAM
//=============== //===============
//map address=00-3f,80-bf:6000-7fff mask=0x80e000 => 00-07:0000-ffff
auto SPC7110::mcuram_read(uint addr, uint8) -> uint8 { auto SPC7110::mcuram_read(uint addr, uint8) -> uint8 {
//$00-3f|80-bf:6000-7fff
if(r4830 & 0x80) { if(r4830 & 0x80) {
uint bank = (addr >> 16) & 0x3f; addr = bus.mirror(addr, ram.size());
addr = bus.mirror(bank * 0x2000 + (addr & 0x1fff), ram.size());
return ram.read(addr); return ram.read(addr);
} }
return 0x00; return 0x00;
} }
auto SPC7110::mcuram_write(uint addr, uint8 data) -> void { auto SPC7110::mcuram_write(uint addr, uint8 data) -> void {
//$00-3f|80-bf:6000-7fff
if(r4830 & 0x80) { if(r4830 & 0x80) {
uint bank = (addr >> 16) & 0x3f; addr = bus.mirror(addr, ram.size());
addr = bus.mirror(bank * 0x2000 + (addr & 0x1fff), ram.size());
ram.write(addr, data); ram.write(addr, data);
} }
} }

View File

@ -131,6 +131,10 @@ Interface::Interface() {
} }
} }
auto Interface::manifest() -> string {
return cartridge.manifest();
}
auto Interface::title() -> string { auto Interface::title() -> string {
return cartridge.title(); return cartridge.title();
} }
@ -196,7 +200,6 @@ auto Interface::group(uint id) -> uint {
case ID::SuperGameBoyBootROM: case ID::SuperGameBoyBootROM:
case ID::MCCROM: case ID::MCCROM:
case ID::MCCRAM: case ID::MCCRAM:
case ID::MCCPSRAM:
return 1; return 1;
case ID::SuperGameBoy: case ID::SuperGameBoy:
case ID::SuperGameBoyManifest: case ID::SuperGameBoyManifest:
@ -327,7 +330,6 @@ auto Interface::load(uint id, const stream& stream) -> void {
if(id == ID::MCCROM) mcc.rom.read(stream); if(id == ID::MCCROM) mcc.rom.read(stream);
if(id == ID::MCCRAM) mcc.ram.read(stream); if(id == ID::MCCRAM) mcc.ram.read(stream);
if(id == ID::MCCPSRAM) mcc.psram.read(stream);
if(id == ID::SuperGameBoyManifest) cartridge.information.markup.gameBoy = stream.text(); if(id == ID::SuperGameBoyManifest) cartridge.information.markup.gameBoy = stream.text();
@ -393,7 +395,6 @@ auto Interface::save(uint id, const stream& stream) -> void {
if(id == ID::SuperGameBoyRAM) stream.write(GameBoy::cartridge.ramdata, GameBoy::cartridge.ramsize); if(id == ID::SuperGameBoyRAM) stream.write(GameBoy::cartridge.ramdata, GameBoy::cartridge.ramsize);
if(id == ID::MCCRAM) stream.write(mcc.ram.data(), mcc.ram.size()); if(id == ID::MCCRAM) stream.write(mcc.ram.data(), mcc.ram.size());
if(id == ID::MCCPSRAM) stream.write(mcc.psram.data(), mcc.psram.size());
if(id == ID::SufamiTurboSlotARAM) stream.write(sufamiturboA.ram.data(), sufamiturboA.ram.size()); if(id == ID::SufamiTurboSlotARAM) stream.write(sufamiturboA.ram.data(), sufamiturboA.ram.size());
if(id == ID::SufamiTurboSlotBRAM) stream.write(sufamiturboB.ram.data(), sufamiturboB.ram.size()); if(id == ID::SufamiTurboSlotBRAM) stream.write(sufamiturboB.ram.data(), sufamiturboB.ram.size());

View File

@ -66,7 +66,6 @@ struct ID {
MCCROM, MCCROM,
MCCRAM, MCCRAM,
MCCPSRAM,
SuperGameBoyManifest, SuperGameBoyManifest,
SuperGameBoyROM, SuperGameBoyROM,
@ -93,6 +92,7 @@ struct ID {
struct Interface : Emulator::Interface { struct Interface : Emulator::Interface {
Interface(); Interface();
auto manifest() -> string;
auto title() -> string; auto title() -> string;
auto videoFrequency() -> double; auto videoFrequency() -> double;
auto audioFrequency() -> double; auto audioFrequency() -> double;

View File

@ -103,6 +103,7 @@ Presentation::Presentation() {
loadSlot5.setText("Slot 5").onActivate([&] { program->loadState(5); }); loadSlot5.setText("Slot 5").onActivate([&] { program->loadState(5); });
cheatEditor.setText("Cheat Editor").onActivate([&] { toolsManager->show(0); }); cheatEditor.setText("Cheat Editor").onActivate([&] { toolsManager->show(0); });
stateManager.setText("State Manager").onActivate([&] { toolsManager->show(1); }); stateManager.setText("State Manager").onActivate([&] { toolsManager->show(1); });
manifestViewer.setText("Manifest Viewer").onActivate([&] { toolsManager->show(2); });
statusBar.setFont(Font().setBold()); statusBar.setFont(Font().setBold());
statusBar.setVisible(settings["UserInterface/ShowStatusBar"].boolean()); statusBar.setVisible(settings["UserInterface/ShowStatusBar"].boolean());

View File

@ -59,6 +59,7 @@ struct Presentation : Window {
MenuSeparator toolsMenuSeparator{&toolsMenu}; MenuSeparator toolsMenuSeparator{&toolsMenu};
MenuItem cheatEditor{&toolsMenu}; MenuItem cheatEditor{&toolsMenu};
MenuItem stateManager{&toolsMenu}; MenuItem stateManager{&toolsMenu};
MenuItem manifestViewer{&toolsMenu};
FixedLayout layout{this}; FixedLayout layout{this};
Viewport viewport{&layout, Geometry{0, 0, 1, 1}}; Viewport viewport{&layout, Geometry{0, 0, 1, 1}};

View File

@ -33,6 +33,7 @@ auto Program::loadMedia(Emulator::Interface& emulator_, Emulator::Interface::Med
presentation->updateEmulator(); presentation->updateEmulator();
toolsManager->cheatEditor.loadCheats(); toolsManager->cheatEditor.loadCheats();
toolsManager->stateManager.doRefresh(); toolsManager->stateManager.doRefresh();
toolsManager->manifestViewer.doRefresh();
} }
auto Program::unloadMedia() -> void { auto Program::unloadMedia() -> void {

View File

@ -0,0 +1,12 @@
ManifestViewer::ManifestViewer(TabFrame* parent) : TabFrameItem(parent) {
setImage(Icon::Emblem::Text);
setText("Manifest Viewer");
layout.setMargin(5);
manifestView.setEditable(false).setFont(Font().setFamily(Font::Mono));
}
auto ManifestViewer::doRefresh() -> void {
manifestView.setText("");
if(emulator) manifestView.setText(emulator->manifest());
}

View File

@ -2,8 +2,10 @@
#include "cheat-database.cpp" #include "cheat-database.cpp"
#include "cheat-editor.cpp" #include "cheat-editor.cpp"
#include "state-manager.cpp" #include "state-manager.cpp"
#include "manifest-viewer.cpp"
CheatDatabase* cheatDatabase = nullptr; CheatDatabase* cheatDatabase = nullptr;
ToolsManager* toolsManager = nullptr; ToolsManager* toolsManager = nullptr;
ManifestViewer* manifestViewer = nullptr;
ToolsManager::ToolsManager() { ToolsManager::ToolsManager() {
toolsManager = this; toolsManager = this;

View File

@ -76,6 +76,14 @@ struct StateManager : TabFrameItem {
Button eraseButton{&controlLayout, Size{80, 0}}; Button eraseButton{&controlLayout, Size{80, 0}};
}; };
struct ManifestViewer : TabFrameItem {
ManifestViewer(TabFrame*);
auto doRefresh() -> void;
VerticalLayout layout{this};
TextEdit manifestView{&layout, Size{~0, ~0}};
};
struct ToolsManager : Window { struct ToolsManager : Window {
ToolsManager(); ToolsManager();
auto show(unsigned tool) -> void; auto show(unsigned tool) -> void;
@ -84,6 +92,7 @@ struct ToolsManager : Window {
TabFrame panel{&layout, Size{~0, ~0}}; TabFrame panel{&layout, Size{~0, ~0}};
CheatEditor cheatEditor{&panel}; CheatEditor cheatEditor{&panel};
StateManager stateManager{&panel}; StateManager stateManager{&panel};
ManifestViewer manifestViewer{&panel};
}; };
extern CheatDatabase* cheatDatabase; extern CheatDatabase* cheatDatabase;