fix: cross-reference checks data/ directories for false positives

_find_in_repo and _name_in_index now scan data/ in addition to
bios/ via database.json. Eliminates 129 false positives from
game data migrated to data/ (OpenTyrian, ScummVM, SDLPAL, Cave
Story, Syobon Action). True missing: 782 -> 653.
This commit is contained in:
Abdessamad Derraz
2026-03-28 17:31:22 +01:00
parent 3d5d5b601c
commit 3092d73122
4 changed files with 117 additions and 31 deletions

View File

@@ -2,7 +2,7 @@
Complete BIOS and firmware packs for Batocera, BizHawk, EmuDeck, Lakka, Recalbox, RetroArch, RetroBat, RetroDECK, RetroPie, and RomM.
**7,529** verified files across **352** systems, ready to extract into your emulator's BIOS directory.
**7,532** verified files across **352** systems, ready to extract into your emulator's BIOS directory.
## Download BIOS packs
@@ -29,8 +29,8 @@ Each file is checked against the emulator's source code to match what the code a
- **10 platforms** supported with platform-specific verification
- **328 emulators** profiled from source (RetroArch cores + standalone)
- **352 systems** covered (NES, SNES, PlayStation, Saturn, Dreamcast, ...)
- **7,529 files** verified with MD5, SHA1, CRC32 checksums
- **8108 MB** total collection size
- **7,532 files** verified with MD5, SHA1, CRC32 checksums
- **8112 MB** total collection size
## Supported systems
@@ -49,7 +49,7 @@ Full list with per-file details: **[https://abdess.github.io/retrobios/](https:/
| Recalbox | 346/346 (100.0%) | 346 | 0 | 0 |
| RetroArch | 448/448 (100.0%) | 448 | 0 | 0 |
| RetroBat | 331/331 (100.0%) | 330 | 1 | 0 |
| RetroDECK | 2007/2007 (100.0%) | 2000 | 7 | 0 |
| RetroDECK | 2007/2007 (100.0%) | 1999 | 8 | 0 |
| RetroPie | 448/448 (100.0%) | 448 | 0 | 0 |
| RomM | 374/374 (100.0%) | 372 | 2 | 0 |
@@ -113,4 +113,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
This repository provides BIOS files for personal backup and archival purposes.
*Auto-generated on 2026-03-28T14:47:06Z*
*Auto-generated on 2026-03-28T16:30:00Z*

View File

@@ -1,7 +1,7 @@
{
"generated_at": "2026-03-28T15:49:38Z",
"total_files": 7529,
"total_size": 8501557419,
"generated_at": "2026-03-28T16:29:37Z",
"total_files": 7532,
"total_size": 8505965231,
"files": {
"520d3d1b5897800af47f92efd2444a26b7a7dead": {
"path": "bios/3DO Company/3DO/3do_arcade_saot.bin",
@@ -27243,6 +27243,16 @@
"crc32": "4a1f42af",
"adler32": "5b3adbba"
},
"5bcabba35bb8fbfe5a65b85efccf5ed657388308": {
"path": "bios/Atari/ST/hatari/BOOT.ST",
"name": "BOOT.ST",
"size": 737280,
"sha1": "5bcabba35bb8fbfe5a65b85efccf5ed657388308",
"md5": "cd6408638f9dbef45cbbd5d0b6060c60",
"sha256": "e2a0f8ce40fabd275f485eb4c1f59c5213ba0202d1b1c44ca8fdae60f112a8d5",
"crc32": "ca5e7999",
"adler32": "0b2b27eb"
},
"ee58768bdfc602c9b14942ce5481e97dd24e7c83": {
"path": "bios/Atari/ST/megaste.img",
"name": "megaste.img",
@@ -70553,15 +70563,15 @@
"crc32": "f90f0089",
"adler32": "3d4fc9b3"
},
"ae5557ed313b6708bb7c2aee0944e39335a8f814": {
"bebbc4db8ee3c97a9fe02c879ce149bac2c4a498": {
"path": "bios/Sega/Saturn/stvbios.zip",
"name": "stvbios.zip",
"size": 2699371,
"sha1": "ae5557ed313b6708bb7c2aee0944e39335a8f814",
"md5": "14c3c8f5cdc4dc0531228bd344afcf89",
"sha256": "2387d5a84527b0e083f177e60ba21311c964fa420dd1c3317e4976bf6d388b76",
"crc32": "ad4ed8d9",
"adler32": "9743d9ce"
"size": 5321327,
"sha1": "bebbc4db8ee3c97a9fe02c879ce149bac2c4a498",
"md5": "ea4d0ffe1feb88f53f675ac6d0cd9685",
"sha256": "a450943c69a10fd72509cfd211eea323104f966158838b865b59bbaa627094cd",
"crc32": "a8a8860f",
"adler32": "922c0afb"
},
"4154e11959f3d5639b11d7902b3a393a99fb5776": {
"path": "bios/Sega/Saturn/vsaturn.bin",
@@ -71823,6 +71833,26 @@
"crc32": "0dcce9d7",
"adler32": "41fe280a"
},
"91cb6e3f9871454a0127ecb928ed7f1237742ea1": {
"path": "bios/Sony/PlayStation/ps2_scph30003.bin",
"name": "ps2_scph30003.bin",
"size": 524288,
"sha1": "91cb6e3f9871454a0127ecb928ed7f1237742ea1",
"md5": "71f50ef4f4e17c163c78908e16244f7d",
"sha256": "a42c16a9be754f8f665c56611bd3a83eabb231c818b8de64744d0ea1a1d0e74d",
"crc32": "b6f00238",
"adler32": "1537f711"
},
"3bbf6335b226932ee5a83d516acb0fafc62ac3ce": {
"path": "bios/Sony/PlayStation/ps2_scph70002_alt.bin",
"name": "ps2_scph70002_alt.bin",
"size": 524288,
"sha1": "3bbf6335b226932ee5a83d516acb0fafc62ac3ce",
"md5": "7ebb4fc5eab6f79a27d76ac9aad392b2",
"sha256": "7f7dd27cbddba7067fca250ef02b81dc5fe50083e8c20b83017343df6a34d411",
"crc32": "0c1a95f9",
"adler32": "c15c34af"
},
"96880d1ca92a016ff054be5159bb06fe03cb4e14": {
"path": "bios/Sony/PlayStation/psxonpsp660.bin",
"name": "psxonpsp660.bin",
@@ -78020,6 +78050,7 @@
"fcd403db69f54290b51035d82f835e7b": "e4ed47fae31693e016b081c6bda48da5b70d7ccb",
"e2c861c588fca2d0cf6be3df3aaf05f2": "bfcc01ae105fa4cee47890c09ebad9e3775395a4",
"b338bacb2fc453bab61bcc1e2cf5076b": "7157f6a8aff275cfbb5ea6aa8e788dda8a977e56",
"cd6408638f9dbef45cbbd5d0b6060c60": "5bcabba35bb8fbfe5a65b85efccf5ed657388308",
"c9093f27159e7d13ac0d1501a95e53d4": "ee58768bdfc602c9b14942ce5481e97dd24e7c83",
"c87a52c277f7952b41c639fc7bf0a43b": "9a6e4c88533a9eaa4d55cdc040e47443e0226eb2",
"992bac38e01633a529121a2a65f0779e": "3b8cf5ffa41b252eb67f8824f94608fa4005d6dd",
@@ -82351,7 +82382,7 @@
"74570fed4d44b2682b560c8cd44b8b6a": "7b23b53d62de0f29a23e423d0fe751dfb469c2fa",
"af5828fdff51384f99b3c4926be27762": "2b8cb4f87580683eb4d760e4ed210813d667f0a2",
"f273555d7d91e8a5a6bfd9bcf066331c": "3bb41feb82838ab9a35601ac666de5aacfd17a58",
"14c3c8f5cdc4dc0531228bd344afcf89": "ae5557ed313b6708bb7c2aee0944e39335a8f814",
"ea4d0ffe1feb88f53f675ac6d0cd9685": "bebbc4db8ee3c97a9fe02c879ce149bac2c4a498",
"ac4e4b6522e200c0d23d371a8cecbfd3": "4154e11959f3d5639b11d7902b3a393a99fb5776",
"d063803adcced52217989bd825d69eb8": "c3cb7227e4dbc2af861e76d00cb59726105a2e4c",
"2ef01c0e93f7ee3a0a4b139aa14728b9": "7297a11be143011ceb75a0720f96855003415a5d",
@@ -82478,6 +82509,8 @@
"57a06303dfa9cf9351222dfcbb4a29d9": "ffa7f9a7fb19d773a0c3985a541c8e5623d2c30d",
"81bbe60ba7a3d1cea1d48c14cbcc647b": "c40146361eb8cf670b19fdc9759190257803cab7",
"d8f485717a5237285e4d7c5f881b7f32": "d7d6be084f51354bc951d8fa2d8d912aa70abc5e",
"71f50ef4f4e17c163c78908e16244f7d": "91cb6e3f9871454a0127ecb928ed7f1237742ea1",
"7ebb4fc5eab6f79a27d76ac9aad392b2": "3bbf6335b226932ee5a83d516acb0fafc62ac3ce",
"c53ca5908936d412331790f4426c6c33": "96880d1ca92a016ff054be5159bb06fe03cb4e14",
"8abc1b549a4a80954addc48ef02c4521": "339a48f4fcf63e10b5b867b8c93cfd40945faf6c",
"239665b1a3dade1b5a52c06338011044": "343883a7b555646da8cee54aadd2795b6e7dd070",
@@ -85239,7 +85272,7 @@
"7783ab663bb1a8d62ff60d583674355c2af556b1",
"999ed28cfbf18103a4963b0d3797af3dcf67db05",
"106cc72e61b11f4ae492fedc64be1dafe277a626",
"ae5557ed313b6708bb7c2aee0944e39335a8f814"
"bebbc4db8ee3c97a9fe02c879ce149bac2c4a498"
],
"su2000.zip": [
"2e50b96a1d37e9407209e291d5f549233287ac77",
@@ -90534,6 +90567,9 @@
"falcon.img": [
"7157f6a8aff275cfbb5ea6aa8e788dda8a977e56"
],
"BOOT.ST": [
"5bcabba35bb8fbfe5a65b85efccf5ed657388308"
],
"megaste.img": [
"ee58768bdfc602c9b14942ce5481e97dd24e7c83"
],
@@ -102438,6 +102474,12 @@
"ps2-50j.bin": [
"d7d6be084f51354bc951d8fa2d8d912aa70abc5e"
],
"ps2_scph30003.bin": [
"91cb6e3f9871454a0127ecb928ed7f1237742ea1"
],
"ps2_scph70002_alt.bin": [
"3bbf6335b226932ee5a83d516acb0fafc62ac3ce"
],
"psxonpsp660.bin": [
"96880d1ca92a016ff054be5159bb06fe03cb4e14"
],
@@ -105364,6 +105406,9 @@
"VT-DOS12-DISK.ROM": [
"072c6160d4e7d406f5d8f5b1b66066c797d35561"
],
"custom0.sf2": [
"286b2e1fb21cc79851da01666db6c0b0e88f25e3"
],
"tos106de.img": [
"3b8cf5ffa41b252eb67f8824f94608fa4005d6dd"
],
@@ -105382,9 +105427,6 @@
"Kickstart v3.0 rev 39.106 (1992)(Commodore)(A1200)[!].rom": [
"70033828182fffc7ed106e5373a8b89dda76faa5"
],
"custom0.sf2": [
"286b2e1fb21cc79851da01666db6c0b0e88f25e3"
],
"basic11.rom": [
"9451a1a09d8f75944dbd6f91193fc360f1de80ac"
],
@@ -109453,6 +109495,7 @@
"0d973c9d": "e4ed47fae31693e016b081c6bda48da5b70d7ccb",
"dbfa7ceb": "bfcc01ae105fa4cee47890c09ebad9e3775395a4",
"4a1f42af": "7157f6a8aff275cfbb5ea6aa8e788dda8a977e56",
"ca5e7999": "5bcabba35bb8fbfe5a65b85efccf5ed657388308",
"3f2f840f": "ee58768bdfc602c9b14942ce5481e97dd24e7c83",
"1a586c64": "9a6e4c88533a9eaa4d55cdc040e47443e0226eb2",
"7c67c5c9": "3b8cf5ffa41b252eb67f8824f94608fa4005d6dd",
@@ -113784,7 +113827,7 @@
"b3c63c25": "7b23b53d62de0f29a23e423d0fe751dfb469c2fa",
"2aba43c2": "2b8cb4f87580683eb4d760e4ed210813d667f0a2",
"f90f0089": "3bb41feb82838ab9a35601ac666de5aacfd17a58",
"ad4ed8d9": "ae5557ed313b6708bb7c2aee0944e39335a8f814",
"a8a8860f": "bebbc4db8ee3c97a9fe02c879ce149bac2c4a498",
"e4d61811": "4154e11959f3d5639b11d7902b3a393a99fb5776",
"d1883221": "c3cb7227e4dbc2af861e76d00cb59726105a2e4c",
"0dd4c0d5": "7297a11be143011ceb75a0720f96855003415a5d",
@@ -113911,6 +113954,8 @@
"24fc7e17": "ffa7f9a7fb19d773a0c3985a541c8e5623d2c30d",
"2f53b852": "c40146361eb8cf670b19fdc9759190257803cab7",
"0dcce9d7": "d7d6be084f51354bc951d8fa2d8d912aa70abc5e",
"b6f00238": "91cb6e3f9871454a0127ecb928ed7f1237742ea1",
"0c1a95f9": "3bbf6335b226932ee5a83d516acb0fafc62ac3ce",
"5660f34f": "96880d1ca92a016ff054be5159bb06fe03cb4e14",
"f2af798b": "339a48f4fcf63e10b5b867b8c93cfd40945faf6c",
"3b601fc8": "343883a7b555646da8cee54aadd2795b6e7dd070",
@@ -117428,6 +117473,9 @@
".variants/ATARIOSB.ROM.0e86d61d": [
"db1031585968cfc6ec2ecda5c9a5a52f61444a3b"
],
"hatari/BOOT.ST": [
"5bcabba35bb8fbfe5a65b85efccf5ed657388308"
],
"tos/emutos.img": [
"7f22e9b1de07d2466d17cf23187775c246ce9566"
],
@@ -128717,12 +128765,12 @@
"abf119cf947ea32defd08b29a8a25d75f6bd4987",
"f2572ee83d09fc08f4de4a62f101c8bb301a9505",
"072c6160d4e7d406f5d8f5b1b66066c797d35561",
"286b2e1fb21cc79851da01666db6c0b0e88f25e3",
"3b8cf5ffa41b252eb67f8824f94608fa4005d6dd",
"ee58768bdfc602c9b14942ce5481e97dd24e7c83",
"2b8cb4f87580683eb4d760e4ed210813d667f0a2",
"70033828182fffc7ed106e5373a8b89dda76faa5",
"44620f57a25f0bcac2b57ca2b0f1ebad3bf305d3",
"286b2e1fb21cc79851da01666db6c0b0e88f25e3",
"bc39fbd5b9a8d2287ac5d0a42e639fc4d3c2f9d4",
"9451a1a09d8f75944dbd6f91193fc360f1de80ac",
"03bbb386cf530e804363acdfc1d13e64cf28af2e",
@@ -131429,6 +131477,12 @@
],
".variants/scph101.bin.9a09ab7e": [
"7771d6e90980408f753891648685def6dd42ef6d"
],
"zc210/sf2/custom0.sf2": [
"286b2e1fb21cc79851da01666db6c0b0e88f25e3"
],
"zc210/zcdata.dat": [
"33b50cec88bc1569431a7885c0cc2692fddb004b"
]
}
}

View File

@@ -50,7 +50,21 @@ def load_platform_files(platforms_dir: str) -> tuple[dict[str, set[str]], dict[s
return declared, platform_data_dirs
def _find_in_repo(fname: str, by_name: dict[str, list], by_name_lower: dict[str, str]) -> bool:
def _build_data_dir_index(data_root: str = "data") -> set[str]:
"""Build a set of filenames available in data/ directories."""
names: set[str] = set()
root_path = Path(data_root)
if not root_path.is_dir():
return names
for fpath in root_path.rglob("*"):
if fpath.is_file() and not fpath.name.startswith("."):
names.add(fpath.name)
names.add(fpath.name.lower())
return names
def _find_in_repo(fname: str, by_name: dict[str, list], by_name_lower: dict[str, str],
data_names: set[str] | None = None) -> bool:
if fname in by_name:
return True
basename = fname.rsplit("/", 1)[-1] if "/" in fname else None
@@ -63,6 +77,11 @@ def _find_in_repo(fname: str, by_name: dict[str, list], by_name_lower: dict[str,
key = basename.lower()
if key in by_name_lower:
return True
if data_names:
if fname in data_names or key in data_names:
return True
if basename and (basename in data_names or basename.lower() in data_names):
return True
return False
@@ -71,12 +90,14 @@ def cross_reference(
declared: dict[str, set[str]],
db: dict,
platform_data_dirs: dict[str, set[str]] | None = None,
data_names: set[str] | None = None,
) -> dict:
"""Compare emulator profiles against platform declarations.
Returns a report with gaps (files emulators need but platforms don't list)
and coverage stats. Files covered by matching data_directories between
emulator profile and platform config are not reported as gaps.
Checks both bios/ (via database) and data/ (via data_names index).
"""
platform_data_dirs = platform_data_dirs or {}
by_name = db.get("indexes", {}).get("by_name", {})
@@ -106,7 +127,7 @@ def cross_reference(
continue
in_platform = fname in platform_names
in_repo = _find_in_repo(fname, by_name, by_name_lower)
in_repo = _find_in_repo(fname, by_name, by_name_lower, data_names)
entry = {
"name": fname,
@@ -205,7 +226,8 @@ def main():
declared, plat_data_dirs = load_platform_files(args.platforms_dir)
db = load_database(args.db)
report = cross_reference(profiles, declared, db, plat_data_dirs)
data_names = _build_data_dir_index()
report = cross_reference(profiles, declared, db, plat_data_dirs, data_names)
if args.json:
print(json.dumps(report, indent=2))

View File

@@ -246,8 +246,9 @@ def _build_expected(file_entry: dict, checks: list[str]) -> dict:
expected["adler32"] = adler_val
return expected
def _name_in_index(name: str, by_name: dict, by_path_suffix: dict | None = None) -> bool:
"""Check if a name is resolvable in the database indexes."""
def _name_in_index(name: str, by_name: dict, by_path_suffix: dict | None = None,
data_names: set[str] | None = None) -> bool:
"""Check if a name is resolvable in the database indexes or data directories."""
if name in by_name:
return True
basename = name.rsplit("/", 1)[-1]
@@ -255,6 +256,11 @@ def _name_in_index(name: str, by_name: dict, by_path_suffix: dict | None = None)
return True
if by_path_suffix and name in by_path_suffix:
return True
if data_names:
if name in data_names or name.lower() in data_names:
return True
if basename != name and (basename in data_names or basename.lower() in data_names):
return True
return False
@@ -264,6 +270,7 @@ def find_undeclared_files(
db: dict,
emu_profiles: dict | None = None,
target_cores: set[str] | None = None,
data_names: set[str] | None = None,
) -> list[dict]:
"""Find files needed by cores but not declared in platform config."""
# Collect all filenames declared by this platform
@@ -333,7 +340,7 @@ def find_undeclared_files(
# Archived files are grouped by archive
if archive:
if archive not in archive_entries:
in_repo = _name_in_index(archive, by_name, by_path_suffix)
in_repo = _name_in_index(archive, by_name, by_path_suffix, data_names)
archive_entries[archive] = {
"emulator": profile.get("emulator", emu_name),
"name": archive,
@@ -364,10 +371,10 @@ def find_undeclared_files(
dest = f.get("path") or fname
# Resolution: try name, then path basename, then path_suffix
in_repo = _name_in_index(fname, by_name, by_path_suffix)
in_repo = _name_in_index(fname, by_name, by_path_suffix, data_names)
if not in_repo and dest != fname:
path_base = dest.rsplit("/", 1)[-1]
in_repo = _name_in_index(path_base, by_name, by_path_suffix)
in_repo = _name_in_index(path_base, by_name, by_path_suffix, data_names)
checks = _parse_validation(f.get("validation"))
undeclared.append({
@@ -587,7 +594,10 @@ def verify_platform(
status_counts[s] = status_counts.get(s, 0) + 1
# Cross-reference undeclared files
undeclared = find_undeclared_files(config, emulators_dir, db, emu_profiles, target_cores=target_cores)
from cross_reference import _build_data_dir_index
data_names = _build_data_dir_index()
undeclared = find_undeclared_files(config, emulators_dir, db, emu_profiles,
target_cores=target_cores, data_names=data_names)
exclusions = find_exclusion_notes(config, emulators_dir, emu_profiles, target_cores=target_cores)
# Ground truth coverage