diff --git a/README.md b/README.md index 3893ca6..d58546e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ + # NeoCD-Libretro ## Introduction @@ -37,40 +38,40 @@ Copy `neocd_libretro.info` to folder `RetroArch/info` To function NeoCD need a BIOS from a Front Loading, Top Loading or CDZ machine. The BIOS files should be installed in a `neocd` folder under RetroArch's system folder. -The hashes are given to help you verify the files have not been tampered with, the emulator doesn't verify them. +> **📓 Note:** The hashes are given to help you verify the files have not been tampered with, the emulator doesn't verify them. -The needed files are: +#### Zoom ROM -|Description | Filename | SHA1 | -|------------|-----------|------------------------------------------| -| Y Zoom ROM | ng-lo.rom | 2b1c719531dac9bb503f22644e6e4236b91e7cfc | +> **📓 Note:** Need one in the following table + +|Description | Filename | SHA1 | +|-------------------|-----------|------------------------------------------| +| Y Zoom ROM | ng-lo.rom | 2b1c719531dac9bb503f22644e6e4236b91e7cfc | +| Y Zoom ROM (MAME) | 000-lo.lo | 5992277debadeb64d1c1c64b0a92d9293eaf7e4a | + +#### BIOS > **📓 Note:** You need at least one in the following table. If several BIOSes are available, it will be possible to choose which to run in the Core Options Menu. The files will be automatically byte swapped if needed. -| Description | Filename | SHA1 | -|----------------------------|--------------|------------------------------------------| -| Front Loader BIOS | neocd_f.rom | a5f4a7a627b3083c979f6ebe1fabc5d2df6d083b | -| Front Loader BIOS (SMKDAN) | neocd_sf.rom | c99c44a43bded1bff4570b30b74975601bd3f94e | -| Top Loader BIOS | neocd_t.rom | cc92b54a18a8bff6e595aabe8e5c360ba9e62eb5 | -| Top Loader BIOS (SMKDAN) | neocd_st.rom | d463b3a322b9674f9e227a21e43898019ce0e642 | -| CDZ BIOS | neocd_z.rom | b0f1c4fa8d4492a04431805f6537138b842b549f | -| CDZ BIOS (SMKDAN) | neocd_sz.rom | 41ca1c031b844a46387be783ac862c76e65afbb3 | - -| Description | Filename | Byte Swapped SHA1 | -|----------------------------|--------------|------------------------------------------| -| Front Loader BIOS | neocd_f.rom | 53bc1f283cdf00fa2efbb79f2e36d4c8038d743a | -| Front Loader BIOS (SMKDAN) | neocd_sf.rom | 4a94719ee5d0e3f2b981498f70efc1b8f1cef325 | -| Top Loader BIOS | neocd_t.rom | 235f4d1d74364415910f73c10ae5482d90b4274f | -| Top Loader BIOS (SMKDAN) | neocd_st.rom | 19729b51bdab60c42aafef6e20ea9234c7eb8410 | -| CDZ BIOS | neocd_z.rom | 7bb26d1e5d1e930515219cb18bcde5b7b23e2eda | -| CDZ BIOS (SMKDAN) | neocd_sz.rom | 6a947457031dd3a702a296862446d7485aa89dbb | +| Description | Filename | SHA1 | +|----------------------------|----------------|------------------------------------------| +| Front Loader BIOS | neocd_f.rom | a5f4a7a627b3083c979f6ebe1fabc5d2df6d083b | +| Front Loader BIOS (SMKDAN) | neocd_sf.rom | c99c44a43bded1bff4570b30b74975601bd3f94e | +| Top Loader BIOS | neocd_t.rom | cc92b54a18a8bff6e595aabe8e5c360ba9e62eb5 | +| Top Loader BIOS (SMKDAN) | neocd_st.rom | d463b3a322b9674f9e227a21e43898019ce0e642 | +| CDZ BIOS | neocd_z.rom | b0f1c4fa8d4492a04431805f6537138b842b549f | +| CDZ BIOS (SMKDAN) | neocd_sz.rom | 41ca1c031b844a46387be783ac862c76e65afbb3 | +| Front Loader BIOS (MAME) | front-sp1.bin | 53bc1f283cdf00fa2efbb79f2e36d4c8038d743a | +| Top Loader BIOS (MAME) | top-sp1.bin | 235f4d1d74364415910f73c10ae5482d90b4274f | +| CDZ BIOS (MAME) | neocd.bin | 7bb26d1e5d1e930515219cb18bcde5b7b23e2eda | +| Universe 3.2 | uni-bioscd.rom | 5158b728e62b391fb69493743dcf7abbc62abc82 | ### CD Images In the era of modern computers and portable devices, CD-ROMs are no longer convenient. Additionally I believe it is not possible to read the TOC of protected games without special drivers. As a result, NeoCD now exclusively run using CD-ROM images. -NeoCD accepts as input a cue sheet file (CUE) or a MAME CHD file. The image can be either of "single file" type (CUE, BIN) or "multiple files" type (CUE,ISO,[WAV/FLAC/OGG]). +NeoCD accepts as input a cue sheet file (CUE) or a MAME CHD file. CUE images can be either of "single file" type (CUE, BIN) or "multiple files" type (CUE,ISO,[WAV/FLAC/OGG]). > **🎶 Supported audio formats are:** Wave (.wav), FLAC (.flac) or Ogg Vorbis (.ogg) @@ -90,6 +91,7 @@ NeoCD accepts as input a cue sheet file (CUE) or a MAME CHD file. The image can * libFLAC * libogg * libvorbis +* zlib * MSYS (Windows) The project uses custom cmake finders in the folder `cmakescripts` to locate the libraries. @@ -106,8 +108,8 @@ The project uses custom cmake finders in the folder `cmakescripts` to locate the ## Tested platforms -* x64 / Windows / GCC 8.2 -* x64 / Arch Linux / GCC 8.2 +* x64 / Windows / GCC 9.1 +* x64 / Arch Linux / GCC 9.1 * Raspberry Pi 3 / Arch Linux / GCC 8.2 ## Known problems diff --git a/retroarch/libneocd_libretro.info b/retroarch/libneocd_libretro.info index 856247a..e6d6f21 100644 --- a/retroarch/libneocd_libretro.info +++ b/retroarch/libneocd_libretro.info @@ -10,7 +10,7 @@ license = "LGPLv3" display_version = "2019" supports_no_game = "false" -firmware_count = 7 +firmware_count = 12 firmware0_desc = "Front Loader BIOS" firmware0_path = "neocd/neocd_f.rom" firmware0_opt = "true" @@ -31,4 +31,19 @@ firmware5_path = "neocd/neocd_sz.rom" firmware5_opt = "true" firmware6_desc = "Y-ZOOM ROM" firmware6_path = "neocd/ng-lo.rom" -firmware6_opt = "false" +firmware6_opt = "true" +firmware7_desc = "Y-ZOOM ROM (MAME)" +firmware7_path = "neocd/000-lo.lo" +firmware7_opt = "true" +firmware8_desc = "Front Loader BIOS (MAME)" +firmware8_path = "neocd/front-sp1.bin" +firmware8_opt = "true" +firmware9_desc = "Top Loader BIOS (MAME)" +firmware9_path = "neocd/top-sp1.bin" +firmware9_opt = "true" +firmware10_desc = "CDZ BIOS (MAME)" +firmware10_path = "neocd/neocd.bin" +firmware10_opt = "true" +firmware11_desc = "Universe BIOS" +firmware11_path = "neocd/uni-bioscd.rom" +firmware11_opt = "true" diff --git a/src/cdrom.cpp b/src/cdrom.cpp index 3887376..cc06318 100644 --- a/src/cdrom.cpp +++ b/src/cdrom.cpp @@ -227,10 +227,13 @@ void Cdrom::readData(char* buffer) uint32_t trackOffset = m_currentPosition - m_currentTrack->startSector; - if (m_file->isChd()) - trackOffset *= 2352; - else if (m_currentTrack->trackType == CdromToc::TrackType::Mode1_2048) - trackOffset *= 2048; + if (m_currentTrack->trackType == CdromToc::TrackType::Mode1_2048) + { + if (m_file->isChd()) + trackOffset *= 2352; + else + trackOffset *= 2048; + } else if (m_currentTrack->trackType == CdromToc::TrackType::Mode1_2352) trackOffset = (trackOffset * 2352) + 16; diff --git a/src/cdromtoc.cpp b/src/cdromtoc.cpp index b26ee38..b718450 100644 --- a/src/cdromtoc.cpp +++ b/src/cdromtoc.cpp @@ -432,6 +432,9 @@ bool CdromToc::loadChd(const std::string& filename) // Current position on the CD uint32_t cdPosition = 0; + // Used to fix some weird CHD behavior + bool previousWasData = true; + // Scan metadata for(uint32_t idx = 0; idx < 99; ++idx) { @@ -450,9 +453,6 @@ bool CdromToc::loadChd(const std::string& filename) // Length of the postgap (index 2) uint32_t postgapLength; - // True is pregap / postgap have associated data in the data file, otherwise they're just silence - bool gapsInDataFile = false; - // True if the metadata is in V2 format bool v2Metadata = true; @@ -489,17 +489,12 @@ bool CdromToc::loadChd(const std::string& filename) // Get pre / post gap length from metadata pregapLength = std::stoul(match[5].str()); postgapLength = std::stoul(match[8].str()); - - // If PGTYPE starts with 'V' the pregap data is in the CHD - std::string pgType = match[6]; - gapsInDataFile = !pgType.empty() && (pgType[0] == 'V'); } else { // Old metadata don't have pre / post gap info so set it to zero pregapLength = 0; postgapLength = 0; - gapsInDataFile = false; } //Get the track number and length from metadata @@ -532,13 +527,16 @@ bool CdromToc::loadChd(const std::string& filename) // Create the pregap entry (index 0) if (pregapLength) { - if (gapsInDataFile) + m_toc.push_back({ -1, { static_cast(trackNumber), 0 }, TrackType::Silence, 0, cdPosition, 0, pregapLength }); + + // CHD WEIRDNESS: If the previous track was data don't move the chd position + if (!previousWasData) { - m_toc.push_back({ 0, { static_cast(trackNumber), 0 }, TrackType::AudioPCM, 0, cdPosition, static_cast(chdPosition) * 2352, pregapLength }); chdPosition += pregapLength; + + // Shorten the track accordingly + trackLength -= pregapLength; } - else - m_toc.push_back({ -1, { static_cast(trackNumber), 0 }, TrackType::Silence, 0, cdPosition, 0, pregapLength }); cdPosition += pregapLength; } @@ -551,16 +549,11 @@ bool CdromToc::loadChd(const std::string& filename) // Create the post gap entry (index 2) if (postgapLength) { - if (gapsInDataFile) - { - m_toc.push_back({ 0, { static_cast(trackNumber), 2 }, TrackType::AudioPCM, 0, cdPosition, static_cast(chdPosition) * 2352, postgapLength }); - chdPosition += postgapLength; - } - else - m_toc.push_back({ -1, { static_cast(trackNumber), 2 }, TrackType::Silence, 0, cdPosition, 0, postgapLength }); - + m_toc.push_back({ -1, { static_cast(trackNumber), 2 }, TrackType::Silence, 0, cdPosition, 0, postgapLength }); cdPosition += postgapLength; } + + previousWasData = !(trackType == TrackType::AudioPCM); } m_totalSectors = cdPosition; diff --git a/src/libretro.cpp b/src/libretro.cpp index a003065..57786db 100644 --- a/src/libretro.cpp +++ b/src/libretro.cpp @@ -1,39 +1,40 @@ -#include "neogeocd.h" -#include "timeprofiler.h" - #include #include #include #include #include +#include #include -class BiosListEntry -{ -public: - BiosListEntry(const std::string& f, const std::string& d, NeoGeoCD::BiosType t) : - filename(f), - description(d), - type(t) - { } +#include "neogeocd.h" +#include "timeprofiler.h" - std::string filename; - std::string description; +struct BiosListEntry +{ + const char* filename; + const char* description; NeoGeoCD::BiosType type; + bool isSMKDan; + bool isUniverse; }; -static const char* BIOS_F_FILENAME = "neocd_f.rom"; -static const char* BIOS_F_DESCRIPTION = "Front Loader"; -static const char* BIOS_SF_FILENAME = "neocd_sf.rom"; -static const char* BIOS_SF_DESCRIPTION = "Front Loader (SMKDAN)"; -static const char* BIOS_T_FILENAME = "neocd_t.rom"; -static const char* BIOS_T_DESCRIPTION = "Top Loader"; -static const char* BIOS_ST_FILENAME = "neocd_st.rom"; -static const char* BIOS_ST_DESCRIPTION = "Top Loader (SMKDAN)"; -static const char* BIOS_Z_FILENAME = "neocd_z.rom"; -static const char* BIOS_Z_DESCRIPTION = "CDZ"; -static const char* BIOS_SZ_FILENAME = "neocd_sz.rom"; -static const char* BIOS_SZ_DESCRIPTION = "CDZ (SMKDAN)"; +static const std::initializer_list KNOWN_BIOSES{ + { "neocd_f.rom", "Front Loader", NeoGeoCD::FrontLoader, false, false }, + { "neocd_sf.rom", "Front Loader (SMKDAN)", NeoGeoCD::FrontLoader, true, false }, + { "front-sp1.bin", "Front Loader (MAME)", NeoGeoCD::FrontLoader, false, false }, + { "neocd_t.rom", "Top Loader", NeoGeoCD::TopLoader, false, false }, + { "neocd_st.rom", "Top Loader (SMKDAN)", NeoGeoCD::TopLoader, true, false }, + { "top-sp1.bin", "Top Loader (MAME)", NeoGeoCD::TopLoader, false, false }, + { "neocd_z.rom", "CDZ", NeoGeoCD::CDZ, false, false }, + { "neocd_sz.rom", "CDZ (SMKDAN)", NeoGeoCD::CDZ, true, false }, + { "neocd.bin", "CDZ (MAME)", NeoGeoCD::CDZ, false, false }, + { "uni-bioscd.rom", "Universe 3.2", NeoGeoCD::CDZ, false, true } +}; + +static const std::initializer_list KNOWN_ZOOM_ROMS{ + { "ng-lo.rom" }, + { "000-lo.lo" } +}; static const char* REGION_VARIABLE = "neocd_region"; static const char* BIOS_VARIABLE = "neocd_bios"; @@ -122,23 +123,11 @@ static void lookForBIOS() { biosList.clear(); - if (fileExists(makeSystemPath(BIOS_F_FILENAME))) - biosList.emplace_back(BiosListEntry(BIOS_F_FILENAME, BIOS_F_DESCRIPTION, NeoGeoCD::FrontLoader)); - - if (fileExists(makeSystemPath(BIOS_SF_FILENAME))) - biosList.emplace_back(BiosListEntry(BIOS_SF_FILENAME, BIOS_SF_DESCRIPTION, NeoGeoCD::FrontLoader)); - - if (fileExists(makeSystemPath(BIOS_T_FILENAME))) - biosList.emplace_back(BiosListEntry(BIOS_T_FILENAME, BIOS_T_DESCRIPTION, NeoGeoCD::TopLoader)); - - if (fileExists(makeSystemPath(BIOS_ST_FILENAME))) - biosList.emplace_back(BiosListEntry(BIOS_ST_FILENAME, BIOS_ST_DESCRIPTION, NeoGeoCD::TopLoader)); - - if (fileExists(makeSystemPath(BIOS_Z_FILENAME))) - biosList.emplace_back(BiosListEntry(BIOS_Z_FILENAME, BIOS_Z_DESCRIPTION, NeoGeoCD::CDZ)); - - if (fileExists(makeSystemPath(BIOS_SZ_FILENAME))) - biosList.emplace_back(BiosListEntry(BIOS_SZ_FILENAME, BIOS_SZ_DESCRIPTION, NeoGeoCD::CDZ)); + for(const BiosListEntry& entry : KNOWN_BIOSES) + { + if (fileExists(makeSystemPath(entry.filename))) + biosList.push_back(entry); + } } static bool loadYZoomROM() @@ -146,11 +135,17 @@ static bool loadYZoomROM() std::ifstream file; std::string filename; - filename = makeSystemPath("ng-lo.rom"); - file.open(filename, std::ios::in | std::ios::binary); + for(const char* rom_name : KNOWN_ZOOM_ROMS) + { + filename = makeSystemPath(rom_name); + file.open(filename, std::ios::in | std::ios::binary); + if (file.is_open()) + break; + } + if (!file.is_open()) { - LOG(LOG_ERROR, "Could not load Y Zoom ROM %s\n", filename.c_str()); + LOG(LOG_ERROR, "Could not load Y Zoom ROM\n"); return false; } @@ -158,7 +153,7 @@ static bool loadYZoomROM() if (file.gcount() < Memory::YZOOMROM_SIZE) { - LOG(LOG_ERROR, "ng-lo.rom should be exactly 65536 bytes!\n"); + LOG(LOG_ERROR, "Y ZOOM ROM should be at least 65536 bytes!\n"); return false; } @@ -195,12 +190,13 @@ static void disableSMKDANChecksum(uint32_t address) static void patchBIOS() { - bool isSMKDan = (biosList[biosIndex].filename == BIOS_SZ_FILENAME) - || (biosList[biosIndex].filename == BIOS_SF_FILENAME) - || (biosList[biosIndex].filename == BIOS_ST_FILENAME); + const BiosListEntry& entry = biosList[biosIndex]; if (neocd.biosType == NeoGeoCD::FrontLoader) { + // Patch the CD Recognition + patchROM_16(0xC10B64, 0x4E71); + // Speed hacks to avoid busy looping if (cdSpeedHack) { @@ -211,11 +207,14 @@ static void patchBIOS() } // If SMKDan, disable the BIOS checksum - if (isSMKDan) + if (entry.isSMKDan) disableSMKDANChecksum(0xC23EBE); } else if (neocd.biosType == NeoGeoCD::TopLoader) { + // Patch the CD Recognition + patchROM_16(0xC10436, 0x4E71); + // Speed hacks to avoid busy looping if (cdSpeedHack) { @@ -226,12 +225,13 @@ static void patchBIOS() } // If SMKDan, disable the BIOS checksum - if (isSMKDan) + if (entry.isSMKDan) disableSMKDANChecksum(0xC23FBE); } else if (neocd.biosType == NeoGeoCD::CDZ) { - // Patch the CD Recognition (It's done in the CD-ROM firmware, can't emulate) + // Patch the CD Recognition + patchROM_16(0xC0EB82, 0x4E71); patchROM_16(0xC0D280, 0x4E71); // Speed hacks to avoid busy looping @@ -245,7 +245,7 @@ static void patchBIOS() } // If SMKDan, disable the BIOS checksum - if (isSMKDan) + if (entry.isSMKDan) disableSMKDANChecksum(0xC62BF4); } } @@ -301,7 +301,7 @@ static int biosDescriptionToIndex(const char* description) { for (int result = 0; result < biosList.size(); ++result) { - if (!strcmp(description, biosList[result].description.c_str())) + if (!strcmp(description, biosList[result].description)) return result; }