pc-engine: add support for Games Express games + other fixes

Use the Games Express system card for the games that require it
Use System Card 1.0 for Altered Beast (this game is broken on other bios versions, even on hardwar
Fix CD-ROM pregap offset (Fixes Super Air Zonk, allows Games Express games to boot)
Fix PC-Engine Duo/Super CD-ROM Ram Enable Register
e)
このコミットが含まれているのは:
Luke Usher 2024-03-08 15:53:44 +00:00
コミット c9c1a0d532
15個のファイルの変更98行の追加26行の削除

ファイルの表示

@ -8,6 +8,7 @@ namespace Board {
#include "super-system-card.cpp"
#include "arcade-card-duo.cpp"
#include "arcade-card-pro.cpp"
#include "games-express.cpp"
#include "debugger.cpp"
auto Interface::load(Memory::Readable<n8>& memory, string name) -> bool {

31
ares/pce/cartridge/board/games-express.cpp ノーマルファイル
ファイルの表示

@ -0,0 +1,31 @@
struct GamesExpress : Interface {
using Interface::Interface;
Memory::Readable<n8> rom;
auto load() -> void override {
Interface::load(rom, "program.rom");
}
auto save() -> void override {
}
auto unload() -> void override {
}
auto read(n8 bank, n13 address, n8 data) -> n8 override {
if(bank >= 0x00 && bank <= 0x67) {
return rom.read(bank << 13 | address);
}
return data;
}
auto write(n8 bank, n13 address, n8 data) -> void override {
}
auto power() -> void override {
}
auto serialize(serializer& s) -> void override {
}
};

ファイルの表示

@ -27,6 +27,7 @@ auto Cartridge::connect() -> void {
if(information.board == "Super System Card") board = new Board::SuperSystemCard{*this};
if(information.board == "Arcade Card Duo") board = new Board::ArcadeCardDuo{*this};
if(information.board == "Arcade Card Pro") board = new Board::ArcadeCardPro{*this};
if(information.board == "Games Express") board = new Board::GamesExpress{*this};
if(!board) board = new Board::Interface{*this};
board->pak = pak;
board->load();

ファイルの表示

@ -32,7 +32,7 @@ auto PCD::Drive::read() -> bool {
//print("* ", reading() ? "data" : "cdda", " read ", lba, " to ", end - 1, "\n");
pcd.fd->seek(2448 * (abs(session->leadIn.lba) + lba));
pcd.fd->seek(2448 * (abs(session->leadIn.lba) + lba + 150));
pcd.fd->read({sector, 2448});
if(++lba == end) setInactive();
return true;

ファイルの表示

@ -3,7 +3,7 @@ auto PCD::read(n8 bank, n13 address, n8 data) -> n8 {
return bios.read(address);
}
if(bank >= 0x68 && bank <= 0x78 && Model::PCEngineDuo() && sramEnable()) {
if(bank >= 0x68 && bank <= 0x7f && Model::PCEngineDuo() && sramEnable) {
return sram.read(bank - 0x68 << 13 | address);
}
@ -19,7 +19,7 @@ auto PCD::read(n8 bank, n13 address, n8 data) -> n8 {
}
auto PCD::write(n8 bank, n13 address, n8 data) -> void {
if(bank >= 0x68 && bank <= 0x7f && Model::PCEngineDuo() && sramEnable()) {
if(bank >= 0x68 && bank <= 0x7f && Model::PCEngineDuo() && sramEnable) {
return sram.write(bank - 0x68 << 13 | address, data);
}
@ -146,7 +146,10 @@ auto PCD::readIO(n13 address, n8 data) -> n8 {
}
auto PCD::writeIO(n13 address, n8 data) -> void {
if(address == 0x18c0) io.sramEnable = io.sramEnable << 8 | data;
if(address == 0x18c0) {
io.sramEnable = io.sramEnable << 8 | data;
if(io.sramEnable == 0xaa55) sramEnable = 1; // Remains enabled until power cycle
}
if(address >= 0x18c4) return;
address = (n4)address;

ファイルの表示

@ -177,6 +177,7 @@ auto PCD::power() -> void {
fader.power();
clock = {};
io = {};
sramEnable = 0;
if(Model::PCEngineDuo()) {
if(auto fp = system.pak->read("bios.rom")) {

ファイルの表示

@ -28,7 +28,6 @@ struct PCD : Thread {
static auto Present() -> bool { return true; }
auto title() const -> string { return information.title; }
auto sramEnable() const -> bool { return io.sramEnable == 0xaa55; }
auto bramEnable() const -> bool { return io.bramEnable; }
//pcd.cpp
@ -313,6 +312,8 @@ private:
n1 bramEnable;
} io;
n1 sramEnable;
//unserialized:
struct Information {
string title;

ファイルの表示

@ -389,7 +389,7 @@ auto PCD::SCSI::commandGetDirectoryInformation() -> void {
mode = track->control;
}
}
auto [minute, second, frame] = CD::MSF::fromLBA(150 + lba);
auto [minute, second, frame] = CD::MSF::fromLBA(lba);
response.write(BCD::encode(minute));
response.write(BCD::encode(second));
response.write(BCD::encode(frame));
@ -406,7 +406,7 @@ auto PCD::SCSI::commandGetDirectoryInformation() -> void {
mode = track->control;
}
}
auto [minute, second, frame] = CD::MSF::fromLBA(150 + lba);
auto [minute, second, frame] = CD::MSF::fromLBA(lba);
response.write(lba >> 16);
response.write(lba >> 8);
response.write(lba >> 0);

ファイルの表示

@ -18,6 +18,7 @@ auto PCD::serialize(serializer& s) -> void {
s(io.cddaSampleSelect);
s(io.sramEnable);
s(io.bramEnable);
s(sramEnable);
}
auto PCD::Drive::serialize(serializer& s) -> void {

ファイルの表示

@ -1,4 +1,4 @@
static const string SerializerVersion = "v131";
static const string SerializerVersion = "v132";
auto System::serialize(bool synchronize) -> serializer {
if(synchronize) scheduler.enter(Scheduler::Mode::Synchronize);

ファイルの表示

@ -5,15 +5,17 @@ struct PCEngineCD : PCEngine {
auto pak(ares::Node::Object) -> shared_pointer<vfs::directory> override;
shared_pointer<mia::Pak> bios;
u32 regionID = 0;
u32 biosID = 0;
};
PCEngineCD::PCEngineCD() {
manufacturer = "NEC";
name = "PC Engine CD";
firmware.append({"BIOS", "US", "cadac2725711b3c442bcf237b02f5a5210c96f17625c35fa58f009e0ed39e4db"}); //NTSC-U
firmware.append({"BIOS", "Japan", "e11527b3b96ce112a037138988ca72fd117a6b0779c2480d9e03eaebece3d9ce"}); //NTSC-J
firmware.append({"System-Card 1.0", "Japan", "afe9f27f91ac918348555b86298b4f984643eafa2773196f2c5441ea84f0c3bb"});
firmware.append({"System Card 3.0", "Japan", "e11527b3b96ce112a037138988ca72fd117a6b0779c2480d9e03eaebece3d9ce"});
firmware.append({"System Card 3.0", "US", "cadac2725711b3c442bcf237b02f5a5210c96f17625c35fa58f009e0ed39e4db"});
firmware.append({"Games Express" , "Japan", "4b86bb96a48a4ca8375fc0109631d0b1d64f255a03b01de70594d40788ba6c3d"});
allocatePorts();
}
@ -24,18 +26,27 @@ auto PCEngineCD::load() -> bool {
auto region = Emulator::region();
//if statements below are ordered by lowest to highest priority
if(region == "NTSC-J") regionID = 1;
if(region == "NTSC-U") regionID = 0;
if(region == "NTSC-U") biosID = 2;
if(region == "NTSC-J") biosID = 1;
// Some games require a specific card to be inserted into the system
if(auto requiredCard = game->pak->attribute("card")) {
if(requiredCard == "System Card 1.0") {
biosID = 0;
} else if(requiredCard == "Games Express") {
biosID = 3;
}
}
bios = mia::Medium::create("PC Engine");
if(!bios->load(firmware[regionID].location)) return errorFirmware(firmware[regionID]), false;
if(!bios->load(firmware[biosID].location)) return errorFirmware(firmware[biosID]), false;
system = mia::System::create("PC Engine");
if(!system->load()) return false;
ares::PCEngine::option("Pixel Accuracy", settings.video.pixelAccuracy);
auto name = region == "NTSC-J" ? "PC Engine" : "TurboGrafx 16";
auto name = region == "NTSC-J" ? "PC Engine Duo" : "TurboDuo";
if(!ares::PCEngine::load(root, {"[NEC] ", name, " (", region, ")"})) return false;
if(auto port = root->find<ares::Node::Port>("Cartridge Slot")) {

ファイルの表示

@ -12,7 +12,7 @@ SuperGrafxCD::SuperGrafxCD() {
manufacturer = "NEC";
name = "SuperGrafx CD";
firmware.append({"BIOS", "Japan", "e11527b3b96ce112a037138988ca72fd117a6b0779c2480d9e03eaebece3d9ce"}); //NTSC-J
firmware.append({"System Card 3.0", "Japan", "e11527b3b96ce112a037138988ca72fd117a6b0779c2480d9e03eaebece3d9ce"}); //NTSC-J
allocatePorts();
}

ファイルの表示

@ -159,6 +159,7 @@ auto Settings::process(bool load) -> void {
bind(string, name, emulator->configuration.game);
for(auto& firmware : emulator->firmware) {
string name = {base, "/Firmware/", firmware.type, ".", firmware.region};
name.replace(" ", "-");
bind(string, name, firmware.location);
}
}

ファイルの表示

@ -17,7 +17,8 @@ auto PCEngineCD::load(string location) -> bool {
pak = new vfs::directory;
pak->setAttribute("title", document["game/title"].string());
pak->setAttribute("region", document["game/region"].string());
pak->setAttribute("audio", (bool)document["game/audio"]);
pak->setAttribute("card", document["game/card"].string());
pak->setAttribute("audio", (bool)document["game/audio"]);
pak->append("manifest.bml", manifest);
if(directory::exists(location)) {
pak->append("cd.rom", vfs::disk::open({location, "cd.rom"}, vfs::read));
@ -36,28 +37,42 @@ auto PCEngineCD::save(string location) -> bool {
}
auto PCEngineCD::analyze(string location) -> string {
vector<u8> sector;
vector<u8> sectors[2];
if(location.iendsWith(".cue")) {
sector = readDataSectorCUE(location, 0);
sectors[0] = readDataSectorCUE(location, 0); // NEC
sectors[1] = readDataSectorCUE(location, 16); // Games Express
} else if (location.iendsWith(".chd")) {
sector = readDataSectorCHD(location, 0);
sectors[0] = readDataSectorCHD(location, 0); // NEC
sectors[1] = readDataSectorCHD(location, 16); // Games Express
}
if(!sector) return CompactDisc::manifestAudio(location);
if(!sectors[0] && !sectors[1]) return CompactDisc::manifestAudio(location);
//yes, "Electronics" is spelled incorrectly in actual PC Engine CD games ...
if(memory::compare(sector.data() + 0x264, "NEC Home Electoronics", 21)) {
return CompactDisc::manifestAudio(location);
}
bool isNEC = sectors[0] && (memory::compare(sectors[0].data() + 0x264, "NEC Home Electoronics", 21) == 0);
bool isGamesExpress = sectors[1] &&(memory::compare(sectors[1].data() + 0x1, "CD001", 5) == 0);
//note: there is no method to determine the region for PC Engine CDs ...
if(!isGamesExpress && !isNEC) return CompactDisc::manifestAudio(location);
//note: there is no method to determine the region for PC Engine CDs from the data itself
string region = "NTSC-J";
if(location.ifind("(USA)")) region = "NTSC-U";
string card = "any";
//Altered Beast requires Card 1.0; Game doesn't specify its name in the header
//do our best to guess based on filename
if(location.ifind("Juuouki")) card = "System Card 1.0";
if(location.ifind("Juoki")) card = "System Card 1.0";
if(location.ifind("Altered Beast")) card = "System Card 1.0";
if(!isNEC && isGamesExpress) card = "Games Express";
string s;
s += "game\n";
s +={" name: ", Medium::name(location), "\n"};
s +={" title: ", Medium::name(location), "\n"};
s +={" region: ", region, "\n"};
s +={" card: ", card, "\n"};
return s;
}

ファイルの表示

@ -121,6 +121,12 @@ auto PCEngine::analyze(vector<u8>& data) -> string {
//TurboGrafx Super System Card 3.00
if(digest == "cadac2725711b3c442bcf237b02f5a5210c96f17625c35fa58f009e0ed39e4db") board = "Super System Card", region = "NTSC-U";
// Games Express (Blue)
if(digest == "4b86bb96a48a4ca8375fc0109631d0b1d64f255a03b01de70594d40788ba6c3d") board = "Games Express", region = "NTSC-J";
// Games Express (Green)
if(digest == "da173b20694c2b52087b099b8c44e471d3ee08a666c90d4afd997f8e1382add8") board = "Games Express", region = "NTSC-J";
string s;
s += "game\n";
s +={" sha256: ", digest, "\n"};