Skip to content

Commit

Permalink
pc-engine: add support for Games Express games + other fixes
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
LukeUsher committed Mar 8, 2024
1 parent d53fdb0 commit c9c1a0d
Show file tree
Hide file tree
Showing 15 changed files with 98 additions and 26 deletions.
1 change: 1 addition & 0 deletions ares/pce/cartridge/board/board.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
31 changes: 31 additions & 0 deletions ares/pce/cartridge/board/games-express.cpp
Original file line number Diff line number Diff line change
@@ -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 {
}
};
1 change: 1 addition & 0 deletions ares/pce/cartridge/cartridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion ares/pce/pcd/drive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
9 changes: 6 additions & 3 deletions ares/pce/pcd/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -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);
}

Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions ares/pce/pcd/pcd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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")) {
Expand Down
3 changes: 2 additions & 1 deletion ares/pce/pcd/pcd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -313,6 +312,8 @@ struct PCD : Thread {
n1 bramEnable;
} io;

n1 sramEnable;

//unserialized:
struct Information {
string title;
Expand Down
4 changes: 2 additions & 2 deletions ares/pce/pcd/scsi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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);
Expand Down
1 change: 1 addition & 0 deletions ares/pce/pcd/serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion ares/pce/system/serialization.cpp
Original file line number Diff line number Diff line change
@@ -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);
Expand Down
25 changes: 18 additions & 7 deletions desktop-ui/emulator/pc-engine-cd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand All @@ -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")) {
Expand Down
2 changes: 1 addition & 1 deletion desktop-ui/emulator/supergrafx-cd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
1 change: 1 addition & 0 deletions desktop-ui/settings/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
35 changes: 25 additions & 10 deletions mia/medium/pc-engine-cd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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);

if(!isGamesExpress && !isNEC) return CompactDisc::manifestAudio(location);

//note: there is no method to determine the region for PC Engine CDs ...
//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;
}
6 changes: 6 additions & 0 deletions mia/medium/pc-engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"};
Expand Down

0 comments on commit c9c1a0d

Please sign in to comment.