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 {
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 License = "GPLv3";
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)...}); }
//information
virtual auto manifest() -> string = 0;
virtual auto title() -> string = 0;
virtual auto videoFrequency() -> double = 0;
virtual auto audioFrequency() -> double = 0;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -31,6 +31,10 @@ auto Cartridge::sha256() const -> string {
return information.sha256;
}
auto Cartridge::manifest() const -> string {
return information.markup;
}
auto Cartridge::title() const -> string {
return information.title;
}
@ -45,48 +49,50 @@ auto Cartridge::load() -> void {
hasEEPROM = false;
hasFLASH = false;
if(auto info = document["cartridge/mrom"]) {
if(auto info = document["board/rom"]) {
mrom.size = min(32 * 1024 * 1024, info["size"].natural());
interface->loadRequest(ID::MROM, info["name"].text(), true);
}
if(auto info = document["cartridge/sram"]) {
hasSRAM = true;
sram.size = min(32 * 1024, info["size"].natural());
sram.mask = sram.size - 1;
for(auto n : range(sram.size)) sram.data[n] = 0xff;
if(auto info = document["board/ram"]) {
if(info["type"].text() == "sram") {
hasSRAM = true;
sram.size = min(32 * 1024, info["size"].natural());
sram.mask = sram.size - 1;
for(auto n : range(sram.size)) sram.data[n] = 0xff;
interface->loadRequest(ID::SRAM, info["name"].text(), false);
memory.append({ID::SRAM, info["name"].text()});
}
interface->loadRequest(ID::SRAM, info["name"].text(), false);
memory.append({ID::SRAM, info["name"].text()});
}
if(auto info = document["cartridge/eeprom"]) {
hasEEPROM = true;
eeprom.size = min(8 * 1024, info["size"].natural());
eeprom.bits = eeprom.size <= 512 ? 6 : 14;
if(eeprom.size == 0) eeprom.size = 8192, eeprom.bits = 0; //auto-detect size
eeprom.mask = mrom.size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000;
eeprom.test = mrom.size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
for(auto n : range(eeprom.size)) eeprom.data[n] = 0xff;
if(info["type"].text() == "eeprom") {
hasEEPROM = true;
eeprom.size = min(8 * 1024, info["size"].natural());
eeprom.bits = eeprom.size <= 512 ? 6 : 14;
if(eeprom.size == 0) eeprom.size = 8192, eeprom.bits = 0; //auto-detect size
eeprom.mask = mrom.size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000;
eeprom.test = mrom.size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
for(auto n : range(eeprom.size)) eeprom.data[n] = 0xff;
interface->loadRequest(ID::EEPROM, info["name"].text(), false);
memory.append({ID::EEPROM, info["name"].text()});
}
interface->loadRequest(ID::EEPROM, info["name"].text(), false);
memory.append({ID::EEPROM, info["name"].text()});
}
if(auto info = document["cartridge/flash"]) {
hasFLASH = true;
flash.id = info["id"].natural();
flash.size = min(128 * 1024, info["size"].natural());
for(auto n : range(flash.size)) flash.data[n] = 0xff;
if(info["type"].text() == "flash") {
hasFLASH = true;
flash.id = info["id"].natural();
flash.size = min(128 * 1024, info["size"].natural());
for(auto n : range(flash.size)) flash.data[n] = 0xff;
//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
if(!flash.id && flash.size == 64 * 1024) flash.id = 0x1cc2;
if(!flash.id && flash.size == 128 * 1024) flash.id = 0x09c2;
//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
if(!flash.id && flash.size == 64 * 1024) flash.id = 0x1cc2;
if(!flash.id && flash.size == 128 * 1024) flash.id = 0x09c2;
interface->loadRequest(ID::FLASH, info["name"].text(), false);
memory.append({ID::FLASH, info["name"].text()});
interface->loadRequest(ID::FLASH, info["name"].text(), false);
memory.append({ID::FLASH, info["name"].text()});
}
}
information.sha256 = Hash::SHA256(mrom.data, mrom.size).digest();

View File

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

View File

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

View File

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

View File

@ -22,6 +22,7 @@ auto mMenuCheckItem::onToggle(const function<void ()>& callback) -> type& {
auto mMenuCheckItem::setChecked(bool checked) -> type& {
state.checked = checked;
signal(setChecked, checked);
return *this;
}
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 {
return state->sequence;
return (bool)state->sequence;
}
auto Hotkey::operator==(const Hotkey& source) const -> bool {

View File

@ -9,6 +9,7 @@ auto pSizable::destruct() -> void {
}
auto pSizable::minimumSize() const -> Size {
return {0, 0};
}
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() {
database.superFamicom = BML::unserialize(Database::SuperFamicom);
database.bsxSatellaview = BML::unserialize(Database::BsxSatellaview);
database.sufamiTurbo = BML::unserialize(Database::SufamiTurbo);
database.superFamicom = BML::unserialize(string::read(locate({configpath(), "icarus/"}, "Database/Super Famicom.bml")));
}
auto Icarus::error() const -> string {

View File

@ -19,8 +19,8 @@ struct Icarus {
//super-famicom.cpp
auto superFamicomManifest(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 superFamicomImportScanManifest(vector<Markup::Node>& roms, Markup::Node node) -> void;
//game-boy.cpp
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 {
SuperFamicomCartridge cartridge{buffer.data(), buffer.size()};
if(auto markup = cartridge.markup) {
markup.append("\n");
markup.append("information\n");
markup.append(" sha256: ", Hash::SHA256(buffer.data(), buffer.size()).digest(), "\n");
markup.append(" title: ", prefixname(location), "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
return markup;
string markup;
if(settings["icarus/UseDatabase"].boolean() && !markup) {
auto digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
for(auto node : database.superFamicom) {
if(node["sha256"].text() == digest) {
markup.append(node.text(), "\n sha256: ", digest, "\n");
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 {
@ -29,16 +49,13 @@ auto Icarus::superFamicomImport(vector<uint8_t>& buffer, const string& location)
//if(directory::exists(target)) return failure("game already exists");
string markup;
vector<Markup::Node> roms;
bool firmwareAppended = true;
if(settings["icarus/UseDatabase"].boolean() && !markup) {
auto digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
for(auto node : database.superFamicom) {
if(node.name() != "release") continue;
if(node["information/sha256"].text() == digest) {
markup.append(BML::serialize(node["cartridge"]), "\n");
markup.append(BML::serialize(node["information"]));
if(node["sha256"].text() == digest) {
markup.append(node.text(), "\n sha256: ", digest, "\n");
break;
}
}
@ -50,13 +67,16 @@ auto Icarus::superFamicomImport(vector<uint8_t>& buffer, const string& location)
firmwareAppended = cartridge.firmware_appended;
markup.append("\n");
markup.append("information\n");
markup.append(" title: ", name, "\n");
markup.append(" note: ", "heuristically generated by icarus\n");
markup.append(" region: ", cartridge.region == SuperFamicomCartridge::Region::NTSC ? "NTSC" : "PAL", "\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);
superFamicomImportScanManifest(roms, document["cartridge"]);
vector<Markup::Node> roms;
superFamicomManifestScan(roms, document["board"]);
for(auto rom : roms) {
auto name = rom["name"].text();
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(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) {
auto name = rom["name"].text();
auto size = rom["size"].natural();
@ -83,8 +103,3 @@ auto Icarus::superFamicomImport(vector<uint8_t>& buffer, const string& location)
}
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) {
markup.append("cartridge\n");
markup.append(" rom name=program.rom size=0x", hex(size), " type=FlashROM\n");
markup.append("board\n");
markup.append(" rom type=flash name=program.rom size=0x", hex(size), "\n");
}

View File

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

View File

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

View File

@ -11,7 +11,7 @@ SufamiTurboCartridge::SufamiTurboCartridge(const uint8_t* data, unsigned size) {
unsigned ramsize = data[0x37] * 0x800; //2KB
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");
if(ramsize)
markup.append(" ram name=save.ram size=0x", hex(ramsize), "\n");

View File

@ -1,14 +1,14 @@
struct SuperFamicomCartridge {
SuperFamicomCartridge(const uint8_t *data, unsigned size);
SuperFamicomCartridge(const uint8* data, uint size);
string markup;
//private:
auto readHeader(const uint8_t *data, unsigned size) -> void;
auto findHeader(const uint8_t *data, unsigned size) -> unsigned;
auto scoreHeader(const uint8_t *data, unsigned size, unsigned addr) -> unsigned;
auto readHeader(const uint8* data, uint size) -> void;
auto findHeader(const uint8* data, uint size) -> uint;
auto scoreHeader(const uint8* data, uint size, uint addr) -> uint;
enum HeaderField : unsigned {
enum HeaderField : uint {
CartName = 0x00,
Mapper = 0x15,
RomType = 0x16,
@ -22,7 +22,7 @@ struct SuperFamicomCartridge {
ResetVector = 0x3c,
};
enum Mode : unsigned {
enum Mode : uint {
ModeNormal,
ModeBsxSlotted,
ModeBsx,
@ -30,7 +30,7 @@ struct SuperFamicomCartridge {
ModeSuperGameBoy,
};
enum Type : unsigned {
enum Type : uint {
TypeNormal,
TypeBsxSlotted,
TypeBsxBios,
@ -43,12 +43,12 @@ struct SuperFamicomCartridge {
TypeUnknown,
};
enum Region : unsigned {
enum Region : uint {
NTSC,
PAL,
};
enum MemoryMapper : unsigned {
enum MemoryMapper : uint {
LoROM,
HiROM,
ExLoROM,
@ -62,17 +62,17 @@ struct SuperFamicomCartridge {
STROM,
};
enum DSP1MemoryMapper : unsigned {
enum DSP1MemoryMapper : uint {
DSP1Unmapped,
DSP1LoROM1MB,
DSP1LoROM2MB,
DSP1HiROM,
};
bool loaded; //is a base cartridge inserted?
unsigned crc32; //crc32 of all cartridges (base+slot(s))
unsigned rom_size;
unsigned ram_size;
bool loaded; //is a base cartridge inserted?
uint crc32; //crc32 of all cartridges (base+slot(s))
uint rom_size;
uint ram_size;
bool firmware_required; //true if firmware is required for emulation
bool firmware_appended; //true if firmware is present at end of data
@ -100,7 +100,7 @@ struct SuperFamicomCartridge {
bool has_st018;
};
SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) {
SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
firmware_required = false;
firmware_appended = false;
@ -116,7 +116,7 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size)
if(type == TypeSufamiTurbo) return;
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
@ -197,327 +197,310 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size)
if(type == TypeSuperGameBoy1Bios || type == TypeSuperGameBoy2Bios) {
markup.append(
" 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"
" rom name=sgb.boot.rom size=0x100\n"
" map id=io address=00-3f,80-bf:6000-7fff\n"
" map address=00-3f,80-bf:6000-67ff,7000-7fff\n"
" brom name=sgb.boot.rom size=0x100\n"
);
}
else if(has_cx4) {
markup.append(
" hitachidsp model=HG51B169 frequency=20000000\n"
" rom id=program name=program.rom size=0x", hex(rom_size), "\n"
" rom id=data name=cx4.data.rom size=0xc00\n"
" ram id=data size=0xc00\n"
" map id=io address=00-3f,80-bf:6000-7fff\n"
" map id=rom address=00-7f,80-ff:8000-ffff mask=0x8000\n"
" map id=ram address=70-77:0000-7fff\n"
" map address=00-3f,80-bf:6c00-6fff,7c00-7fff\n"
" rom name=program.rom size=0x", hex(rom_size), "\n"
" map address=00-3f,80-bf:8000-ffff mask=0x8000\n"
" ram name=save.ram size=0\n"
" map address=70-77:0000-7fff mask=0x8000\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) {
markup.append(
" spc7110\n"
" rom id=program name=program.rom size=0x100000\n"
" rom id=data name=data.rom size=0x", hex(rom_size - 0x100000), "\n"
" map address=00-3f,80-bf:4800-483f\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"
" map id=io address=00-3f,80-bf:4800-483f\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"
" map address=00-3f,80-bf:6000-7fff mask=0xe000\n"
);
}
else if(has_sdd1) {
markup.append(
" sdd1\n"
" map address=00-3f,80-bf:4800-4807\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(
" ram name=save.ram size=0x", hex(ram_size), "\n"
);
markup.append(
" 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"
" map address=20-3f,a0-bf:6000-7fff mask=0xe000\n"
" map address=70-7d:0000-7fff mask=0x8000\n"
);
}
else if(mapper == LoROM) {
markup.append(
" 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(
" ram name=save.ram size=0x", hex(ram_size), "\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"
" map address=70-7d,f0-ff:", range, "\n"
);
}
else if(mapper == HiROM) {
markup.append(
" 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(
" ram name=save.ram size=0x", hex(ram_size), "\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"
" map address=10-3f,90-bf:6000-7fff mask=0xe000\n"
);
}
else if(mapper == ExLoROM) {
markup.append(
" 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(
" ram name=save.ram size=0x", hex(ram_size), "\n"
);
markup.append(
" 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"
" map address=20-3f,a0-bf:6000-7fff mask=0xe000\n"
" map address=70-7d:0000-7fff mask=0x8000\n"
);
}
else if(mapper == ExHiROM) {
markup.append(
" 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(
" ram name=save.ram size=0x", hex(ram_size), "\n"
);
markup.append(
" 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"
" map address=20-3f,a0-bf:6000-7fff mask=0xe000\n"
" map address=70-7d:", range, "\n"
);
}
else if(mapper == SuperFXROM) {
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"
" 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(
" ram name=save.ram size=0x", hex(ram_size), "\n"
);
markup.append(
" 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"
" map address=00-3f,80-bf:6000-7fff size=0x2000\n"
" map address=70-71,f0-f1:0000-ffff\n"
);
}
else if(mapper == SA1ROM) {
markup.append(
" sa1\n"
" map address=00-3f,80-bf:2200-23ff\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(
" 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(
" ram id=internal size=0x800\n"
" map id=io address=00-3f,80-bf:2200-23ff\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"
" iram id=internal size=0x800 volatile\n"
" map address=00-3f,80-bf:3000-37ff size=0x800\n"
);
}
else if(mapper == BSCLoROM) {
markup.append(
" 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"
" map id=rom address=00-1f:8000-ffff base=0x000000 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"
" map address=70-7d,f0-ff:0000-7fff mask=0x8000\n"
" satellaview\n"
" map id=rom address=c0-ef:0000-ffff\n"
" map address=c0-ef:0000-ffff\n"
);
}
else if(mapper == BSCHiROM) {
markup.append(
" 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"
" map id=rom address=00-1f,80-9f:8000-ffff\n"
" map id=rom address=40-5f,c0-df:0000-ffff\n"
" map id=ram address=20-3f,a0-bf:6000-7fff\n"
" map address=20-3f,a0-bf:6000-7fff\n"
" satellaview\n"
" map id=rom address=20-3f,a0-bf:8000-ffff\n"
" map id=rom address=60-7f,e0-ff:0000-ffff\n"
" map address=20-3f,a0-bf:8000-ffff\n"
" map address=60-7f,e0-ff:0000-ffff\n"
);
}
else if(mapper == BSXROM) {
markup.append(
" ram name=save.ram size=0x", hex(ram_size), "\n"
" map address=10-1f:5000-5fff mask=0xf000\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"
" ram id=save name=save.ram size=0x", hex(ram_size), "\n"
" ram id=download name=download.ram size=0x80000\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"
" ram name=download.ram size=0x80000\n"
" map address=00-3f,80-bf:6000-7fff mask=0xe000\n"
);
}
else if(mapper == STROM) {
markup.append(
" 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"
" map id=rom address=20-3f,a0-bf:8000-ffff mask=0x8000\n"
" map id=ram address=60-6f,e0-ef:0000-ffff\n"
" rom\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"
" map id=rom address=40-5f,c0-df:0000-7fff mask=0x8000\n"
" map id=rom address=40-5f,c0-df:8000-ffff mask=0x8000\n"
" map id=ram address=70-7f,f0-ff:0000-ffff\n"
" rom\n"
" map address=40-5f,c0-df:0000-7fff mask=0x8000\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) {
markup.append(
" sharprtc\n"
" map address=00-3f,80-bf:2800-2801\n"
" ram name=rtc.ram size=0x10\n"
" map id=io address=00-3f,80-bf:2800-2801\n"
);
}
if(has_epsonrtc) {
markup.append(
" epsonrtc\n"
" map address=00-3f,80-bf:4840-4842\n"
" ram name=rtc.ram size=0x10\n"
" map id=io address=00-3f,80-bf:4840-4842\n"
);
}
if(has_obc1) {
markup.append(
" obc1\n"
" map address=00-3f,80-bf:6000-7fff mask=0xe000\n"
" ram name=save.ram size=0x2000\n"
" map id=io address=00-3f,80-bf:6000-7fff\n"
);
}
if(has_dsp1) {
markup.append(
" 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(
" 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(
" 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(
" 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) {
markup.append(
" necdsp model=uPD7725 frequency=8000000\n"
" rom id=program name=dsp2.program.rom size=0x1800\n"
" rom id=data name=dsp2.data.rom size=0x800\n"
" ram id=data size=0x200\n"
" map id=io address=20-3f,a0-bf:8000-ffff select=0x4000\n"
" map address=20-3f,a0-bf:8000-ffff mask=0x3fff\n"
" prom name=dsp2.program.rom size=0x1800\n"
" drom name=dsp2.data.rom size=0x800\n"
" dram name=dsp2.data.ram size=0x200 volatile\n"
);
}
if(has_dsp3) {
markup.append(
" necdsp model=uPD7725 frequency=8000000\n"
" rom id=program name=dsp3.program.rom size=0x1800\n"
" rom id=data name=dsp3.data.rom size=0x800\n"
" ram id=data size=0x200\n"
" map id=io address=20-3f,a0-bf:8000-ffff select=0x4000\n"
" map address=20-3f,a0-bf:8000-ffff mask=0x3fff\n"
" prom name=dsp3.program.rom size=0x1800\n"
" drom name=dsp3.data.rom size=0x800\n"
" dram name=dsp3.data.ram size=0x200 volatile\n"
);
}
if(has_dsp4) {
markup.append(
" necdsp model=uPD7725 frequency=8000000\n"
" rom id=program name=dsp4.program.rom size=0x1800\n"
" rom id=data name=dsp4.data.rom size=0x800\n"
" ram id=data size=0x200\n"
" map id=io address=30-3f,b0-bf:8000-ffff select=0x4000\n"
" map address=30-3f,b0-bf:8000-ffff mask=0x3fff\n"
" prom name=dsp4.program.rom size=0x1800\n"
" drom name=dsp4.data.rom size=0x800\n"
" dram name=dsp4.data.ram size=0x200 volatile\n"
);
}
if(has_st010) {
markup.append(
" necdsp model=uPD96050 frequency=11000000\n"
" rom id=program name=st010.program.rom size=0xc000\n"
" rom id=data name=st010.data.rom size=0x1000\n"
" ram id=data name=save.ram size=0x1000\n"
" map id=io address=60-67,e0-e7:0000-3fff select=0x0001\n"
" map id=ram address=68-6f,e8-ef:0000-7fff\n"
" map address=60-67,e0-e7:0000-3fff\n"
" prom name=st010.program.rom size=0xc000\n"
" drom name=st010.data.rom size=0x1000\n"
" dram name=save.ram size=0x1000\n"
" map address=68-6f,e8-ef:0000-7fff mask=0x8000\n"
);
}
if(has_st011) {
markup.append(
" necdsp model=uPD96050 frequency=15000000\n"
" rom id=program name=st011.program.rom size=0xc000\n"
" rom id=data name=st011.data.rom size=0x1000\n"
" ram id=data name=save.ram size=0x1000\n"
" map id=io address=60-67,e0-e7:0000-3fff select=0x0001\n"
" map id=ram address=68-6f,e8-ef:0000-7fff\n"
" map address=60-67,e0-e7:0000-3fff\n"
" prom name=st011.program.rom size=0xc000\n"
" drom name=st011.data.rom size=0x1000\n"
" dram name=save.ram size=0x1000\n"
" map address=68-6f,e8-ef:0000-7fff mask=0x8000\n"
);
}
if(has_st018) {
markup.append(
" armdsp frequency=21477272\n"
" rom id=program name=st018.program.rom size=0x20000\n"
" rom id=data name=st018.data.rom size=0x8000\n"
" ram name=save.ram size=0x4000\n"
" map id=io address=00-3f,80-bf:3800-38ff\n"
" map address=00-3f,80-bf:3800-38ff\n"
" prom name=st018.program.rom size=0x20000\n"
" drom name=st018.data.rom size=0x8000\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;
mapper = LoROM;
dsp1_mapper = DSP1Unmapped;
@ -559,12 +542,12 @@ auto SuperFamicomCartridge::readHeader(const uint8_t *data, unsigned size) -> vo
return;
}
const unsigned index = findHeader(data, size);
const uint8_t mapperid = data[index + Mapper];
const uint8_t rom_type = data[index + RomType];
const uint8_t rom_size = data[index + RomSize];
const uint8_t company = data[index + Company];
const uint8_t regionid = data[index + CartRegion] & 0x7f;
const uint index = findHeader(data, size);
const uint8 mapperid = data[index + Mapper];
const uint8 rom_type = data[index + RomType];
const uint8 rom_size = data[index + RomSize];
const uint8 company = data[index + Company];
const uint8 regionid = data[index + CartRegion] & 0x7f;
ram_size = 1024 << (data[index + RamSize] & 7);
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 + 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(data[index + 0x1a] == 0x33 || data[index + 0x1a] == 0xff) {
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)
if(data[index - 14] == 'Z') {
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(company == 0x33 || (data[index - 10] == 0x00 && data[index - 4] == 0x00)) {
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 {
unsigned score_lo = scoreHeader(data, size, 0x007fc0);
unsigned score_hi = scoreHeader(data, size, 0x00ffc0);
unsigned score_ex = scoreHeader(data, size, 0x40ffc0);
auto SuperFamicomCartridge::findHeader(const uint8* data, uint size) -> uint {
uint score_lo = scoreHeader(data, size, 0x007fc0);
uint score_hi = scoreHeader(data, size, 0x00ffc0);
uint score_ex = scoreHeader(data, size, 0x40ffc0);
if(score_ex) score_ex += 4; //favor ExHiROM on images > 32mbits
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?
int score = 0;
uint16_t resetvector = data[addr + ResetVector] | (data[addr + ResetVector + 1] << 8);
uint16_t checksum = data[addr + Checksum ] | (data[addr + Checksum + 1] << 8);
uint16_t complement = data[addr + Complement ] | (data[addr + Complement + 1] << 8);
uint16 resetvector = data[addr + ResetVector] | (data[addr + ResetVector + 1] << 8);
uint16 checksum = data[addr + Checksum ] | (data[addr + Checksum + 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_t mapper = data[addr + Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit
uint8 resetop = data[(addr & ~0x7fff) | (resetvector & 0x7fff)]; //first opcode executed upon reset
uint8 mapper = data[addr + Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit
//$00:[000-7fff] contains uninitialized RAM and MMIO.
//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;
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};
DICONSTANTFORCE force;
force.lMagnitude = DI_FFNOMINALMAX; //full force

View File

@ -6,24 +6,52 @@ namespace SuperFamicom {
#include "serialization.cpp"
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 {
if(information.title.gameBoy.empty() == false) {
return {information.title.cartridge, " + ", information.title.gameBoy};
string title = information.title.cartridge;
if(information.title.gameBoy) {
title.append(" + ", information.title.gameBoy);
}
if(information.title.satellaview.empty() == false) {
return {information.title.cartridge, " + ", information.title.satellaview};
if(information.title.satellaview) {
title.append(" + ", information.title.satellaview);
}
if(information.title.sufamiTurboA.empty() == false) {
if(information.title.sufamiTurboB.empty() == true) {
return {information.title.cartridge, " + ", information.title.sufamiTurboA};
} else {
return {information.title.cartridge, " + ", information.title.sufamiTurboA, " + ", information.title.sufamiTurboB};
}
if(information.title.sufamiTurboA) {
title.append(" + ", information.title.sufamiTurboA);
}
return information.title.cartridge;
if(information.title.sufamiTurboB) {
title.append(" + ", information.title.sufamiTurboB);
}
return title;
}
auto Cartridge::load() -> void {
@ -118,8 +146,8 @@ auto Cartridge::loadSuperGameBoy() -> void {
auto document = BML::unserialize(information.markup.gameBoy);
information.title.gameBoy = document["information/title"].text();
auto rom = document["cartridge/rom"];
auto ram = document["cartridge/ram"];
auto rom = document["board/rom"];
auto ram = document["board/ram"];
GameBoy::cartridge.information.markup = information.markup.gameBoy;
GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy);
@ -134,7 +162,7 @@ auto Cartridge::loadSatellaview() -> void {
auto document = BML::unserialize(information.markup.satellaview);
information.title.satellaview = document["information/title"].text();
auto rom = document["cartridge/rom"];
auto rom = document["board/rom"];
if(rom["name"]) {
unsigned size = rom["size"].natural();
@ -150,8 +178,8 @@ auto Cartridge::loadSufamiTurboA() -> void {
auto document = BML::unserialize(information.markup.sufamiTurboA);
information.title.sufamiTurboA = document["information/title"].text();
auto rom = document["cartridge/rom"];
auto ram = document["cartridge/ram"];
auto rom = document["board/rom"];
auto ram = document["board/ram"];
if(rom["name"]) {
unsigned size = rom["size"].natural();
@ -166,7 +194,7 @@ auto Cartridge::loadSufamiTurboA() -> void {
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);
}
}
@ -176,8 +204,8 @@ auto Cartridge::loadSufamiTurboB() -> void {
auto document = BML::unserialize(information.markup.sufamiTurboB);
information.title.sufamiTurboB = document["information/title"].text();
auto rom = document["cartridge/rom"];
auto ram = document["cartridge/ram"];
auto rom = document["board/rom"];
auto ram = document["board/ram"];
if(rom["name"]) {
unsigned size = rom["size"].natural();

View File

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

View File

@ -116,6 +116,13 @@ auto Event::ram_write(uint addr, uint8 data) -> void {
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 {
Thread::serialize(s);
s.array(ram.data(), ram.size());

View File

@ -19,6 +19,9 @@ struct Event : Coprocessor {
auto ram_read(uint addr, uint8) -> uint8;
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;
MappedRAM rom[4];

View File

@ -25,6 +25,10 @@ struct HitachiDSP : Processor::HG51B, Coprocessor {
auto ram_read(uint addr, uint8 data) -> uint8;
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
auto dsp_read(uint addr, uint8 data) -> uint8;
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);
}
auto HitachiDSP::dsp_read(uint addr, uint8) -> uint8 {
addr &= 0x1fff;
auto HitachiDSP::dram_read(uint addr, uint8 data) -> uint8 {
addr &= 0xfff;
if(addr >= 0xc00) return data;
return dataRAM[addr];
}
//Data RAM
if((addr >= 0x0000 && addr <= 0x0bff) || (addr >= 0x1000 && addr <= 0x1bff)) {
return dataRAM[addr & 0x0fff];
}
auto HitachiDSP::dram_write(uint addr, uint8 data) -> void {
addr &= 0xfff;
if(addr >= 0xc00) return;
dataRAM[addr] = data;
}
auto HitachiDSP::dsp_read(uint addr, uint8) -> uint8 {
addr = 0x7c00 | (addr & 0x03ff);
//MMIO
switch(addr) {
case 0x1f40: return mmio.dma_source >> 0;
case 0x1f41: return mmio.dma_source >> 8;
case 0x1f42: return mmio.dma_source >> 16;
case 0x1f43: return mmio.dma_length >> 0;
case 0x1f44: return mmio.dma_length >> 8;
case 0x1f45: return mmio.dma_target >> 0;
case 0x1f46: return mmio.dma_target >> 8;
case 0x1f47: return mmio.dma_target >> 16;
case 0x1f48: return mmio.r1f48;
case 0x1f49: return mmio.program_offset >> 0;
case 0x1f4a: return mmio.program_offset >> 8;
case 0x1f4b: return mmio.program_offset >> 16;
case 0x1f4c: return mmio.r1f4c;
case 0x1f4d: return mmio.page_number >> 0;
case 0x1f4e: return mmio.page_number >> 8;
case 0x1f4f: return mmio.program_counter;
case 0x1f50: return mmio.r1f50;
case 0x1f51: return mmio.r1f51;
case 0x1f52: return mmio.r1f52;
case 0x1f53: case 0x1f54: case 0x1f55: case 0x1f56:
case 0x1f57: case 0x1f58: case 0x1f59: case 0x1f5a:
case 0x1f5b: case 0x1f5c: case 0x1f5d: case 0x1f5e:
case 0x1f5f: return ((regs.halt == false) << 6) | ((regs.halt == true) << 1);
case 0x7f40: return mmio.dma_source >> 0;
case 0x7f41: return mmio.dma_source >> 8;
case 0x7f42: return mmio.dma_source >> 16;
case 0x7f43: return mmio.dma_length >> 0;
case 0x7f44: return mmio.dma_length >> 8;
case 0x7f45: return mmio.dma_target >> 0;
case 0x7f46: return mmio.dma_target >> 8;
case 0x7f47: return mmio.dma_target >> 16;
case 0x7f48: return mmio.r1f48;
case 0x7f49: return mmio.program_offset >> 0;
case 0x7f4a: return mmio.program_offset >> 8;
case 0x7f4b: return mmio.program_offset >> 16;
case 0x7f4c: return mmio.r1f4c;
case 0x7f4d: return mmio.page_number >> 0;
case 0x7f4e: return mmio.page_number >> 8;
case 0x7f4f: return mmio.program_counter;
case 0x7f50: return mmio.r1f50;
case 0x7f51: return mmio.r1f51;
case 0x7f52: return mmio.r1f52;
case 0x7f53: case 0x7f54: case 0x7f55: case 0x7f56:
case 0x7f57: case 0x7f58: case 0x7f59: case 0x7f5a:
case 0x7f5b: case 0x7f5c: case 0x7f5d: case 0x7f5e:
case 0x7f5f: return ((regs.halt == false) << 6) | ((regs.halt == true) << 1);
}
//Vector
if(addr >= 0x1f60 && addr <= 0x1f7f) {
if(addr >= 0x7f60 && addr <= 0x7f7f) {
return mmio.vector[addr & 0x1f];
}
//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 shift = ((addr & 0x3f) % 3) * 8; //0, 8, 16
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 {
addr &= 0x1fff;
//Data RAM
if((addr >= 0x0000 && addr <= 0x0bff) || (addr >= 0x1000 && addr <= 0x1bff)) {
dataRAM[addr & 0x0fff] = data;
return;
}
addr = 0x7c00 | (addr & 0x03ff);
//MMIO
switch(addr) {
case 0x1f40: mmio.dma_source = (mmio.dma_source & 0xffff00) | (data << 0); return;
case 0x1f41: mmio.dma_source = (mmio.dma_source & 0xff00ff) | (data << 8); return;
case 0x1f42: mmio.dma_source = (mmio.dma_source & 0x00ffff) | (data << 16); return;
case 0x1f43: mmio.dma_length = (mmio.dma_length & 0xff00) | (data << 0); return;
case 0x1f44: mmio.dma_length = (mmio.dma_length & 0x00ff) | (data << 8); return;
case 0x1f45: mmio.dma_target = (mmio.dma_target & 0xffff00) | (data << 0); return;
case 0x1f46: mmio.dma_target = (mmio.dma_target & 0xff00ff) | (data << 8); return;
case 0x1f47: mmio.dma_target = (mmio.dma_target & 0x00ffff) | (data << 16);
case 0x7f40: mmio.dma_source = (mmio.dma_source & 0xffff00) | (data << 0); return;
case 0x7f41: mmio.dma_source = (mmio.dma_source & 0xff00ff) | (data << 8); return;
case 0x7f42: mmio.dma_source = (mmio.dma_source & 0x00ffff) | (data << 16); return;
case 0x7f43: mmio.dma_length = (mmio.dma_length & 0xff00) | (data << 0); return;
case 0x7f44: mmio.dma_length = (mmio.dma_length & 0x00ff) | (data << 8); return;
case 0x7f45: mmio.dma_target = (mmio.dma_target & 0xffff00) | (data << 0); return;
case 0x7f46: mmio.dma_target = (mmio.dma_target & 0xff00ff) | (data << 8); return;
case 0x7f47: mmio.dma_target = (mmio.dma_target & 0x00ffff) | (data << 16);
if(regs.halt) mmio.dma = true;
return;
case 0x1f48: mmio.r1f48 = data & 0x01; return;
case 0x1f49: mmio.program_offset = (mmio.program_offset & 0xffff00) | (data << 0); return;
case 0x1f4a: mmio.program_offset = (mmio.program_offset & 0xff00ff) | (data << 8); return;
case 0x1f4b: mmio.program_offset = (mmio.program_offset & 0x00ffff) | (data << 16); return;
case 0x1f4c: mmio.r1f4c = data & 0x03; return;
case 0x1f4d: 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 0x1f4f: mmio.program_counter = data;
case 0x7f48: mmio.r1f48 = data & 0x01; return;
case 0x7f49: mmio.program_offset = (mmio.program_offset & 0xffff00) | (data << 0); return;
case 0x7f4a: mmio.program_offset = (mmio.program_offset & 0xff00ff) | (data << 8); return;
case 0x7f4b: mmio.program_offset = (mmio.program_offset & 0x00ffff) | (data << 16); return;
case 0x7f4c: mmio.r1f4c = data & 0x03; return;
case 0x7f4d: mmio.page_number = (mmio.page_number & 0x7f00) | ((data & 0xff) << 0); return;
case 0x7f4e: mmio.page_number = (mmio.page_number & 0x00ff) | ((data & 0x7f) << 8); return;
case 0x7f4f: mmio.program_counter = data;
if(regs.halt) {
regs.pc = mmio.page_number * 256 + mmio.program_counter;
regs.halt = false;
}
return;
case 0x1f50: mmio.r1f50 = data & 0x77; return;
case 0x1f51: mmio.r1f51 = data & 0x01; return;
case 0x1f52: mmio.r1f52 = data & 0x01; return;
case 0x7f50: mmio.r1f50 = data & 0x77; return;
case 0x7f51: mmio.r1f51 = data & 0x01; return;
case 0x7f52: mmio.r1f52 = data & 0x01; return;
}
//Vector
if(addr >= 0x1f60 && addr <= 0x1f7f) {
if(addr >= 0x7f60 && addr <= 0x7f7f) {
mmio.vector[addr & 0x1f] = data;
return;
}
//GPRs
if((addr >= 0x1f80 && addr <= 0x1faf) || (addr >= 0x1fc0 && addr <= 0x1fef)) {
if((addr >= 0x7f80 && addr <= 0x7faf) || (addr >= 0x7fc0 && addr <= 0x7fef)) {
uint index = (addr & 0x3f) / 3;
switch((addr & 0x3f) % 3) {
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 {
rom.reset();
ram.reset();
psram.reset();
}
auto MCC::power() -> void {
@ -24,25 +23,18 @@ auto MCC::reset() -> void {
for(auto n : range(16)) r[n] = 0x00;
r[0x07] = 0x80;
r[0x08] = 0x80;
mmio_commit();
commit();
}
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());
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 {
if((addr & 0xe08000) == 0x008000) { //$00-1f:8000-ffff
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(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(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(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
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
|| ((addr & 0x400000) == 0x400000) //$40-7f|c0-ff:0000-ffff
if(((addr & 0x408000) == 0x008000) //$00-3f,80-bf:8000-ffff
|| ((addr & 0x400000) == 0x400000) //$40-7f,c0-ff:0000-ffff
) {
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 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;
}
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
uint8 n = (addr >> 16) & 15;
r[n] = data;
if(n == 0x0e && data & 0x80) mmio_commit();
if(n == 0x0e && data & 0x80) commit();
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;
r01 = r[0x01] & 0x80;
r02 = r[0x02] & 0x80;

View File

@ -3,7 +3,6 @@
struct MCC {
MappedRAM rom;
MappedRAM ram;
MappedRAM psram;
auto init() -> void;
auto load() -> void;
@ -12,16 +11,15 @@ struct MCC {
auto reset() -> void;
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_read(uint addr, uint8 data) -> uint8;
auto mcu_write(uint addr, uint8 data) -> void;
auto mmio_read(uint addr, uint8 data) -> uint8;
auto mmio_write(uint addr, uint8 data) -> void;
auto mmio_commit() -> void;
auto read(uint addr, uint8 data) -> uint8;
auto write(uint addr, uint8 data) -> void;
auto commit() -> void;
auto serialize(serializer&) -> void;

View File

@ -1,4 +1,3 @@
auto MCC::serialize(serializer& s) -> void {
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 {
if(dataFile.open()) dataFile.close();
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(dataFile.open({interface->path(ID::SuperFamicom), name}, file::mode::read)) {
dataFile.seek(mmio.dataReadOffset);
@ -102,7 +102,7 @@ auto MSU1::audioOpen() -> void {
if(audioFile.open()) audioFile.close();
auto document = BML::unserialize(cartridge.information.markup.cartridge);
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;
name = track["name"].text();
break;

View File

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

View File

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

View File

@ -1,9 +1,10 @@
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);
}
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);
}
@ -11,16 +12,16 @@ auto SA1::bus_read(uint addr, uint8 data) -> uint8 {
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);
}
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff
if((addr & 0x40f800) == 0x000000) { //$00-3f,80-bf:0000-07ff
synchronizeCPU();
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();
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 {
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);
}
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);
}
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff
if((addr & 0x40f800) == 0x000000) { //$00-3f,80-bf:0000-07ff
synchronizeCPU();
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();
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
//these ports.
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);
}
@ -82,7 +84,7 @@ auto SA1::vbr_read(uint addr, uint8 data) -> uint8 {
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);
}
@ -90,11 +92,11 @@ auto SA1::vbr_read(uint addr, uint8 data) -> uint8 {
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);
}
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);
}
@ -122,55 +124,42 @@ auto SA1::op_write(uint addr, uint8 data) -> void {
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 {
if((addr & 0xffffe0) == 0x00ffe0) {
if(addr == 0xffea && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 0;
if(addr == 0xffeb && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 8;
if(addr == 0xffee && sa1.mmio.cpu_ivsw) return sa1.mmio.siv >> 0;
if(addr == 0xffef && sa1.mmio.cpu_ivsw) return sa1.mmio.siv >> 8;
//reset vector overrides
if((addr & 0xffffe0) == 0x007fe0) { //$00:ffe0-ffef
if(addr == 0x7fea && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 0;
if(addr == 0x7feb && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 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) {
return sa1.rom.read(bus.mirror(addr, sa1.rom.size()));
};
if((addr & 0xe08000) == 0x008000) { //$00-1f:8000-ffff
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x007fff);
if(mmio.cbmode == 0) return read(0x000000 | addr);
return read((mmio.cb << 20) | addr);
}
bool lo = addr < 0x400000; //*bmode==0 only applies to $00-3f,80-bf:8000-ffff
addr &= 0x3fffff;
if((addr & 0xe08000) == 0x208000) { //$20-3f:8000-ffff
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x007fff);
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
if(addr < 0x100000) { //$00-1f,8000-ffff; $c0-cf:0000-ffff
if(lo && mmio.cbmode == 0) return read(addr);
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));
}
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));
}
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));
}
@ -181,7 +170,7 @@ auto SA1::mmcrom_write(uint addr, uint8 data) -> void {
}
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();
addr = bus.mirror(mmio.sbm * 0x2000 + (addr & 0x1fff), cpubwram.size());
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 {
if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff
if(addr < 0x2000) { //$00-3f,80-bf:6000-7fff
cpu.synchronizeCoprocessors();
addr = bus.mirror(mmio.sbm * 0x2000 + (addr & 0x1fff), cpubwram.size());
return cpubwram.write(addr, data);

View File

@ -13,8 +13,8 @@ auto SDD1::init() -> void {
void SDD1::load() {
//hook S-CPU DMA MMIO registers to gather information for struct dma[];
//buffer address and transfer size information for use in SDD1::mcu_read()
bus.map({&SDD1::read, &sdd1}, {&SDD1::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}, 0x00, 0x3f, 0x4300, 0x437f);
bus.map({&SDD1::dma_read, &sdd1}, {&SDD1::dma_write, &sdd1}, 0x80, 0xbf, 0x4300, 0x437f);
}
auto SDD1::unload() -> void {
@ -42,11 +42,7 @@ auto SDD1::reset() -> void {
}
auto SDD1::read(uint addr, uint8 data) -> uint8 {
addr &= 0x40ffff;
if((addr & 0x404380) == 0x4300) {
return cpu.mmio_read(addr, data);
}
addr = 0x4800 | (addr & 7);
switch(addr) {
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 {
addr &= 0xffff;
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);
}
addr = 0x4800 | (addr & 7);
switch(addr) {
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 {
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
//one transfer per $420b write (for spooling purposes). however, this is not known for certain.
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);
//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) {
//at least one channel has S-DD1 decompression enabled ...
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 {
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);
}
@ -160,7 +159,7 @@ auto SDD1::mcuram_read(uint addr, uint8 data) -> uint8 {
}
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);
}

View File

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

View File

@ -131,6 +131,10 @@ Interface::Interface() {
}
}
auto Interface::manifest() -> string {
return cartridge.manifest();
}
auto Interface::title() -> string {
return cartridge.title();
}
@ -196,7 +200,6 @@ auto Interface::group(uint id) -> uint {
case ID::SuperGameBoyBootROM:
case ID::MCCROM:
case ID::MCCRAM:
case ID::MCCPSRAM:
return 1;
case ID::SuperGameBoy:
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::MCCRAM) mcc.ram.read(stream);
if(id == ID::MCCPSRAM) mcc.psram.read(stream);
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::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::SufamiTurboSlotBRAM) stream.write(sufamiturboB.ram.data(), sufamiturboB.ram.size());

View File

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

View File

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

View File

@ -59,6 +59,7 @@ struct Presentation : Window {
MenuSeparator toolsMenuSeparator{&toolsMenu};
MenuItem cheatEditor{&toolsMenu};
MenuItem stateManager{&toolsMenu};
MenuItem manifestViewer{&toolsMenu};
FixedLayout layout{this};
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();
toolsManager->cheatEditor.loadCheats();
toolsManager->stateManager.doRefresh();
toolsManager->manifestViewer.doRefresh();
}
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-editor.cpp"
#include "state-manager.cpp"
#include "manifest-viewer.cpp"
CheatDatabase* cheatDatabase = nullptr;
ToolsManager* toolsManager = nullptr;
ManifestViewer* manifestViewer = nullptr;
ToolsManager::ToolsManager() {
toolsManager = this;

View File

@ -76,6 +76,14 @@ struct StateManager : TabFrameItem {
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 {
ToolsManager();
auto show(unsigned tool) -> void;
@ -84,6 +92,7 @@ struct ToolsManager : Window {
TabFrame panel{&layout, Size{~0, ~0}};
CheatEditor cheatEditor{&panel};
StateManager stateManager{&panel};
ManifestViewer manifestViewer{&panel};
};
extern CheatDatabase* cheatDatabase;