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)
このコミットが含まれているのは:
コミット
c9c1a0d532
|
@ -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 {
|
||||
|
|
|
@ -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"};
|
||||
|
|
読み込み中…
新しいイシューから参照