6 Commits

Author SHA1 Message Date
Abdessamad Derraz 44dc946217 docs: add romm to platform references 2026-03-25 23:19:52 +01:00
Abdessamad Derraz d2cc9b8f29 feat: add doom engine wad files, emulatorjs base config 2026-03-25 23:12:53 +01:00
Roël Couwenberg 32b391ef69 feat: Addition of a RomM package (#37)
* feat: Initial addition of the RomM scraper and package

* docs: Added RomM to the verification modes table

* chore: Clean up scraper by removing workaround code from main() and an unused system translation map
2026-03-25 19:24:59 +01:00
Abdessamad Derraz 1ad10eddb7 feat: include platform version in pack filenames 2026-03-25 18:55:35 +01:00
Abdessamad Derraz 69131f4ad1 fix: emulator validation is informational, not a platform failure 2026-03-25 17:34:56 +01:00
Abdessamad Derraz c61d40d8ef docs: rewrite readme for clarity and discoverability 2026-03-25 17:18:43 +01:00
36 changed files with 3748 additions and 388 deletions
+1
View File
@@ -112,6 +112,7 @@ jobs:
| RetroBat | RetroBat_BIOS_Pack.zip | bios/ |
| RetroDECK | RetroDECK_BIOS_Pack.zip | ~/retrodeck/bios/ |
| EmuDeck | EmuDeck_BIOS_Pack.zip | Emulation/bios/ |
| RomM | RomM_BIOS_Pack.zip | bios/{platform_slug}/ |
### Changes
${CHANGES}
+49 -33
View File
@@ -1,37 +1,41 @@
# RetroBIOS
Source-verified BIOS and firmware packs for retrogaming platforms.
Complete BIOS and firmware packs for RetroArch, Batocera, Recalbox, Lakka, RetroPie, EmuDeck, RetroBat, RetroDECK, and RomM.
Documentation and metadata can drift from what emulators actually load at runtime.
To keep packs accurate, each file here is checked against the emulator's source code:
what the code opens, what hashes it expects, what happens when a file is missing.
306 emulators profiled, 8 platforms cross-referenced,
6,733 files verified.
**6,748** verified files across **294** systems, ready to extract into your emulator's BIOS directory.
### How it works
## Download BIOS packs
1. **Read emulator source code** - identify every file the code loads, its expected hash and size
2. **Cross-reference with platforms** - match against what RetroArch, Batocera, Recalbox and others declare
3. **Build packs** - for each platform, include its baseline files plus what its cores need
4. **Verify** - run each platform's native checks (MD5, existence) and emulator-level validation (CRC32, size)
Pick your platform, download the ZIP, extract to the BIOS path.
When a platform and an emulator disagree on a file, the discrepancy is reported.
When a variant in the repo satisfies both, it is preferred automatically.
| Platform | BIOS files | Extract to | Download |
|----------|-----------|-----------|----------|
| Batocera | 359 | `/userdata/bios/` | [Download](../../releases/latest) |
| EmuDeck | 161 | `Emulation/bios/` | [Download](../../releases/latest) |
| Lakka | 448 | `system/` | [Download](../../releases/latest) |
| Recalbox | 346 | `/recalbox/share/bios/` | [Download](../../releases/latest) |
| RetroArch | 448 | `system/` | [Download](../../releases/latest) |
| RetroBat | 331 | `bios/` | [Download](../../releases/latest) |
| RetroDECK | 2007 | `~/retrodeck/bios/` | [Download](../../releases/latest) |
| RetroPie | 448 | `BIOS/` | [Download](../../releases/latest) |
| RomM | 374 | `bios/{platform_slug}/` | [Download](../../releases/latest) |
> **6,733** files | **5043.6 MB** | **8** platforms | **306** emulator profiles
## What's included
## Download
BIOS, firmware, and system files for consoles from Atari to PlayStation 3.
Each file is checked against the emulator's source code to match what the code actually loads at runtime.
| Platform | Files | Verification | Pack |
|----------|-------|-------------|------|
| Batocera | 359 | md5 | [Download](../../releases/latest) |
| EmuDeck | 161 | md5 | [Download](../../releases/latest) |
| Lakka | 448 | existence | [Download](../../releases/latest) |
| Recalbox | 346 | md5 | [Download](../../releases/latest) |
| RetroArch | 448 | existence | [Download](../../releases/latest) |
| RetroBat | 331 | md5 | [Download](../../releases/latest) |
| RetroDECK | 2007 | md5 | [Download](../../releases/latest) |
| RetroPie | 448 | existence | [Download](../../releases/latest) |
- **9 platforms** supported with platform-specific verification
- **306 emulators** profiled from source (RetroArch cores + standalone)
- **294 systems** covered (NES, SNES, PlayStation, Saturn, Dreamcast, ...)
- **6,748 files** verified with MD5, SHA1, CRC32 checksums
- **5251 MB** total collection size
## Supported systems
NES, SNES, Nintendo 64, GameCube, Wii, Game Boy, Game Boy Advance, Nintendo DS, Nintendo 3DS, Switch, PlayStation, PlayStation 2, PlayStation 3, PSP, PS Vita, Mega Drive, Saturn, Dreamcast, Game Gear, Master System, Neo Geo, Atari 2600, Atari 7800, Atari Lynx, Atari ST, MSX, PC Engine, TurboGrafx-16, ColecoVision, Intellivision, Commodore 64, Amiga, ZX Spectrum, Arcade (MAME), and 260+ more.
Full list with per-file details: **[https://abdess.github.io/retrobios/](https://abdess.github.io/retrobios/)**
## Coverage
@@ -39,19 +43,31 @@ When a variant in the repo satisfies both, it is preferred automatically.
|----------|----------|----------|----------|---------|
| Batocera | 359/359 (100.0%) | 358 | 1 | 0 |
| EmuDeck | 161/161 (100.0%) | 161 | 0 | 0 |
| Lakka | 448/448 (100.0%) | 440 | 8 | 0 |
| Recalbox | 346/346 (100.0%) | 341 | 5 | 0 |
| RetroArch | 448/448 (100.0%) | 440 | 8 | 0 |
| RetroBat | 331/331 (100.0%) | 330 | 1 | 0 |
| RetroDECK | 2007/2007 (100.0%) | 2001 | 6 | 0 |
| RetroPie | 448/448 (100.0%) | 440 | 8 | 0 |
| Lakka | 448/448 (100.0%) | 448 | 0 | 0 |
| Recalbox | 346/346 (100.0%) | 346 | 0 | 0 |
| RetroArch | 448/448 (100.0%) | 448 | 0 | 0 |
| RetroBat | 331/331 (100.0%) | 331 | 0 | 0 |
| RetroDECK | 2007/2007 (100.0%) | 2007 | 0 | 0 |
| RetroPie | 448/448 (100.0%) | 448 | 0 | 0 |
| RomM | 374/374 (100.0%) | 359 | 15 | 0 |
## How it works
Documentation and metadata can drift from what emulators actually load.
To keep packs accurate, each file is checked against the emulator's source code.
1. **Read emulator source code** - trace every file the code loads, its expected hash and size
2. **Cross-reference with platforms** - match against what each platform declares
3. **Build packs** - include baseline files plus what each platform's cores need
4. **Verify** - run platform-native checks and emulator-level validation
## Documentation
Full file listings, platform coverage, emulator profiles, and gap analysis: **[https://abdess.github.io/retrobios/](https://abdess.github.io/retrobios/)**
Per-file hashes, emulator profiles, gap analysis, cross-reference: **[https://abdess.github.io/retrobios/](https://abdess.github.io/retrobios/)**
## Contributors
<a href="https://github.com/PixNyb"><img src="https://avatars.githubusercontent.com/u/40770831?v=4" width="50" title="PixNyb"></a>
<a href="https://github.com/monster-penguin"><img src="https://avatars.githubusercontent.com/u/266009589?v=4" width="50" title="monster-penguin"></a>
@@ -63,4 +79,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
This repository provides BIOS files for personal backup and archival purposes.
*Auto-generated on 2026-03-25T15:42:07Z*
*Auto-generated on 2026-03-25T22:12:06Z*
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+476 -248
View File
@@ -1,7 +1,7 @@
{
"generated_at": "2026-03-25T15:41:49Z",
"total_files": 6733,
"total_size": 5288644732,
"generated_at": "2026-03-25T22:06:53Z",
"total_files": 6748,
"total_size": 5505760050,
"files": {
"520d3d1b5897800af47f92efd2444a26b7a7dead": {
"path": "bios/3DO Company/3DO/3do_arcade_saot.bin",
@@ -27713,6 +27713,156 @@
"crc32": "0636e0be",
"adler32": "0ca77de6"
},
"eca9cff1014ce5081804e193588d96c6ddb35432": {
"path": "bios/Id Software/Doom/CHEX.WAD",
"name": "CHEX.WAD",
"size": 12361532,
"sha1": "eca9cff1014ce5081804e193588d96c6ddb35432",
"md5": "25485721882b050afa96a56e5758dd52",
"sha256": "d8eb5277918883f490fb1a4be3c9a8588df2dbaee6dc4beb8df4929148bbffb1",
"crc32": "298dd5b5",
"adler32": "4026602b"
},
"7742089b4468a736cadb659a7deca3320fe6dcbd": {
"path": "bios/Id Software/Doom/DOOM.WAD",
"name": "DOOM.WAD",
"size": 11159840,
"sha1": "7742089b4468a736cadb659a7deca3320fe6dcbd",
"md5": "1cd63c5ddff1bf8ce844237f580e9cf3",
"sha256": "ff2c301b8719465a6e386a512bfa319931b7f64ea517d337c5a47afe03951902",
"crc32": "723e60f9",
"adler32": "e85f4707"
},
"5b2e249b9c5133ec987b3ea77596381dc0d6bc1d": {
"path": "bios/Id Software/Doom/DOOM1.WAD",
"name": "DOOM1.WAD",
"size": 4196020,
"sha1": "5b2e249b9c5133ec987b3ea77596381dc0d6bc1d",
"md5": "f0cefca49926d00903cf57551d901abe",
"sha256": "1d7d43be501e67d927e415e0b8f3e29c3bf33075e859721816f652a526cac771",
"crc32": "162b696a",
"adler32": "3bca9a2a"
},
"7ec7652fcfce8ddc6e801839291f0e28ef1d5ae7": {
"path": "bios/Id Software/Doom/DOOM2.WAD",
"name": "DOOM2.WAD",
"size": 14604584,
"sha1": "7ec7652fcfce8ddc6e801839291f0e28ef1d5ae7",
"md5": "25e1459ca71d321525f84628f45ca8cd",
"sha256": "10d67824b11025ddd9198e8cfc87ca335ee6e2d3e63af4180fa9b8a471893255",
"crc32": "ec8725db",
"adler32": "03bcce6c"
},
"d510c877031bbd5f3d198581a2c8651e09b9861f": {
"path": "bios/Id Software/Doom/DOOM2F.WAD",
"name": "DOOM2F.WAD",
"size": 14607420,
"sha1": "d510c877031bbd5f3d198581a2c8651e09b9861f",
"md5": "3cb02349b3df649c86290907eed64e7b",
"sha256": "ab6d457050daee95fb763040f753fce44a4852883dafdb520b00cc8426e6bda0",
"crc32": "27eaae69",
"adler32": "13e6449b"
},
"ae363db8cd5645e1753d9bacc82cc0724e8e7f21": {
"path": "bios/Id Software/Doom/DOOM64.WAD",
"name": "DOOM64.WAD",
"size": 15103284,
"sha1": "ae363db8cd5645e1753d9bacc82cc0724e8e7f21",
"md5": "e16e17f59afe7b3297f53ebe7e9de815",
"sha256": "902e88504c55cb8f6e03774ba57a272565a65332f08578c3c6fa68972766db2e",
"crc32": "cb10a53d",
"adler32": "1d624237"
},
"f489d479371df32f6d280a0cb23b59a35ba2b833": {
"path": "bios/Id Software/Doom/HERETIC.WAD",
"name": "HERETIC.WAD",
"size": 14189976,
"sha1": "f489d479371df32f6d280a0cb23b59a35ba2b833",
"md5": "66d686b1ed6d35ff103f15dbd30e0341",
"sha256": "12541f82e1d326b456b89411f8c54b895e775a611580f66b78558e898b2eaafa",
"crc32": "5b16049e",
"adler32": "065166bc"
},
"b4c50ca9bea07f7c35250a1a11906091971c05ae": {
"path": "bios/Id Software/Doom/HERETIC1.WAD",
"name": "HERETIC1.WAD",
"size": 5120920,
"sha1": "b4c50ca9bea07f7c35250a1a11906091971c05ae",
"md5": "ae779722390ec32fa37b0d361f7d82f8",
"sha256": "3ab2f21828877e49e5eb3220785aaf8798050b7c4132003b5db7b8f3678bede4",
"crc32": "22d3f0ca",
"adler32": "6110f0ac"
},
"081f6a2024643b54ef4a436a85508539b6d20a1e": {
"path": "bios/Id Software/Doom/HEXDD.WAD",
"name": "HEXDD.WAD",
"size": 4440584,
"sha1": "081f6a2024643b54ef4a436a85508539b6d20a1e",
"md5": "78d5898e99e220e4de64edaa0e479593",
"sha256": "ea5e34c9f7eb677c593f125a0c45db2aaf2d98b8f6e9d50bd683a655aeec531f",
"crc32": "fd5eb11d",
"adler32": "6b8e0546"
},
"4b53832f0733c1e29e5f1de2428e5475e891af29": {
"path": "bios/Id Software/Doom/HEXEN.WAD",
"name": "HEXEN.WAD",
"size": 20083672,
"sha1": "4b53832f0733c1e29e5f1de2428e5475e891af29",
"md5": "abb033caf81e26f12a2103e1fa25453f",
"sha256": "f74b857076b3ffe2597d0e05bdecc687496e6e8a9582d7a47db681e0e78e4001",
"crc32": "dca9114c",
"adler32": "7ebb3585"
},
"90361e2a538d2388506657252ae41aceeb1ba360": {
"path": "bios/Id Software/Doom/PLUTONIA.WAD",
"name": "PLUTONIA.WAD",
"size": 17420824,
"sha1": "90361e2a538d2388506657252ae41aceeb1ba360",
"md5": "75c8cf89566741fa9d22447604053bd7",
"sha256": "a83b00c636fa3308286e76b1b3153fc14507caf994b0450770421260b08efed8",
"crc32": "48d1453c",
"adler32": "63916b81"
},
"bc0a110bf27aee89a0b2fc8111e2391ede891b8d": {
"path": "bios/Id Software/Doom/STRIFE0.WAD",
"name": "STRIFE0.WAD",
"size": 9934413,
"sha1": "bc0a110bf27aee89a0b2fc8111e2391ede891b8d",
"md5": "bb545b9c4eca0ff92c14d466b3294023",
"sha256": "f7f557657cbfd5c7eacaaf9d8aaf3e80512467b51ebfb7c567078ef9bf648ef8",
"crc32": "93c144dd",
"adler32": "70416de4"
},
"64c13b951a845ca7f8081f68138a6181557458d1": {
"path": "bios/Id Software/Doom/STRIFE1.WAD",
"name": "STRIFE1.WAD",
"size": 28377364,
"sha1": "64c13b951a845ca7f8081f68138a6181557458d1",
"md5": "2fed2031a5b03892106e0f117f17901f",
"sha256": "81e4d4402853392fbf2ebf52f9c19cf97754a84f6dd3e5919036241de1ffe52a",
"crc32": "4234ace5",
"adler32": "a0bc562a"
},
"9fbc66aedef7fe3bae0986cdb9323d2b8db4c9d3": {
"path": "bios/Id Software/Doom/TNT.WAD",
"name": "TNT.WAD",
"size": 18195736,
"sha1": "9fbc66aedef7fe3bae0986cdb9323d2b8db4c9d3",
"md5": "4e158d9953c79ccf97bd0663244cc6b6",
"sha256": "c0a9c29d023af2737953663d0e03177d9b7b7b64146c158dcc2a07f9ec18f353",
"crc32": "903dcc27",
"adler32": "cd062fca"
},
"ec6883100d807b894a98f426d024d22c77b63e7f": {
"path": "bios/Id Software/Doom/VOICES.WAD",
"name": "VOICES.WAD",
"size": 27319149,
"sha1": "ec6883100d807b894a98f426d024d22c77b63e7f",
"md5": "082234d6a3f7086424856478b5aa9e95",
"sha256": "3f7a9c37a23dc30bb3b8415e782ea6c78d59e6b2ed4b50ae255ff0365349110c",
"crc32": "cd12ebcf",
"adler32": "28b023c9"
},
"5f4aed208301449c2e9514edfd325fe9dead76fa": {
"path": "bios/Id Software/Doom/prboom.wad",
"name": "prboom.wad",
@@ -70107,6 +70257,21 @@
"8ecd11275ad418d302cd358b408b01ec": "10f1a7204f69b82a18bc94a3010c9660aec0c802",
"ec2a977f0c0645dd284010160caec636": "c0ee6f9443fa82c0fef5d497b3e76aa3077f1865",
"19d55c537767a7424a8e376d62fc2ac0": "72c60172fb1ba77c9b24b06b7755f0a16f0b3a13",
"25485721882b050afa96a56e5758dd52": "eca9cff1014ce5081804e193588d96c6ddb35432",
"1cd63c5ddff1bf8ce844237f580e9cf3": "7742089b4468a736cadb659a7deca3320fe6dcbd",
"f0cefca49926d00903cf57551d901abe": "5b2e249b9c5133ec987b3ea77596381dc0d6bc1d",
"25e1459ca71d321525f84628f45ca8cd": "7ec7652fcfce8ddc6e801839291f0e28ef1d5ae7",
"3cb02349b3df649c86290907eed64e7b": "d510c877031bbd5f3d198581a2c8651e09b9861f",
"e16e17f59afe7b3297f53ebe7e9de815": "ae363db8cd5645e1753d9bacc82cc0724e8e7f21",
"66d686b1ed6d35ff103f15dbd30e0341": "f489d479371df32f6d280a0cb23b59a35ba2b833",
"ae779722390ec32fa37b0d361f7d82f8": "b4c50ca9bea07f7c35250a1a11906091971c05ae",
"78d5898e99e220e4de64edaa0e479593": "081f6a2024643b54ef4a436a85508539b6d20a1e",
"abb033caf81e26f12a2103e1fa25453f": "4b53832f0733c1e29e5f1de2428e5475e891af29",
"75c8cf89566741fa9d22447604053bd7": "90361e2a538d2388506657252ae41aceeb1ba360",
"bb545b9c4eca0ff92c14d466b3294023": "bc0a110bf27aee89a0b2fc8111e2391ede891b8d",
"2fed2031a5b03892106e0f117f17901f": "64c13b951a845ca7f8081f68138a6181557458d1",
"4e158d9953c79ccf97bd0663244cc6b6": "9fbc66aedef7fe3bae0986cdb9323d2b8db4c9d3",
"082234d6a3f7086424856478b5aa9e95": "ec6883100d807b894a98f426d024d22c77b63e7f",
"72ae1b47820fcc93cc0df9c428d0face": "5f4aed208301449c2e9514edfd325fe9dead76fa",
"dbaa5c4e20a11000d1c4db3a2a28f374": "f3f2a11f3ecd91cd62d74c3acfad68a4cc6ddbd9",
"c011b428819eea4a80b455c245a5a04d": "9259b87edfe9b9f6d0749788a75a6ccf158f50aa",
@@ -82071,6 +82236,51 @@
"ALI1429G.AMW": [
"72c60172fb1ba77c9b24b06b7755f0a16f0b3a13"
],
"CHEX.WAD": [
"eca9cff1014ce5081804e193588d96c6ddb35432"
],
"DOOM.WAD": [
"7742089b4468a736cadb659a7deca3320fe6dcbd"
],
"DOOM1.WAD": [
"5b2e249b9c5133ec987b3ea77596381dc0d6bc1d"
],
"DOOM2.WAD": [
"7ec7652fcfce8ddc6e801839291f0e28ef1d5ae7"
],
"DOOM2F.WAD": [
"d510c877031bbd5f3d198581a2c8651e09b9861f"
],
"DOOM64.WAD": [
"ae363db8cd5645e1753d9bacc82cc0724e8e7f21"
],
"HERETIC.WAD": [
"f489d479371df32f6d280a0cb23b59a35ba2b833"
],
"HERETIC1.WAD": [
"b4c50ca9bea07f7c35250a1a11906091971c05ae"
],
"HEXDD.WAD": [
"081f6a2024643b54ef4a436a85508539b6d20a1e"
],
"HEXEN.WAD": [
"4b53832f0733c1e29e5f1de2428e5475e891af29"
],
"PLUTONIA.WAD": [
"90361e2a538d2388506657252ae41aceeb1ba360"
],
"STRIFE0.WAD": [
"bc0a110bf27aee89a0b2fc8111e2391ede891b8d"
],
"STRIFE1.WAD": [
"64c13b951a845ca7f8081f68138a6181557458d1"
],
"TNT.WAD": [
"9fbc66aedef7fe3bae0986cdb9323d2b8db4c9d3"
],
"VOICES.WAD": [
"ec6883100d807b894a98f426d024d22c77b63e7f"
],
"prboom.wad": [
"5f4aed208301449c2e9514edfd325fe9dead76fa"
],
@@ -93221,6 +93431,207 @@
"SCPH-70004_BIOS_V12_EUR_200.ROM2": [
"1bae895fbdd658cfb56c53cc2139282cc1e778de"
],
"tos100uk.img": [
"9a6e4c88533a9eaa4d55cdc040e47443e0226eb2"
],
"tos106de.img": [
"3b8cf5ffa41b252eb67f8824f94608fa4005d6dd"
],
"tos206us.img": [
"ee58768bdfc602c9b14942ce5481e97dd24e7c83"
],
"saturn_bios.bin": [
"2b8cb4f87580683eb4d760e4ed210813d667f0a2",
"df94c5b4d47eb3cc404d88b33a8fda237eaf4720"
],
"sega-saturn:af5828fdff51384f99b3c4926be27762": [
"2b8cb4f87580683eb4d760e4ed210813d667f0a2"
],
"bios7.bin": [
"24f67bdea115a2c847c8813a262502ee1607b7df"
],
"bios9.bin": [
"bfaac75f101c135e32e2aaf541de6b1be4c8c62d"
],
"dsi_bios7.bin": [
"a3aa751eb6bdaaf8a827ba9e03576a6f1ab0f547"
],
"dsi_bios9.bin": [
"7bf549b8be9e48ab0cdc9b0fdadd49a5131f97eb"
],
"gb_bios.bin": [
"4ed31ec6b0b175bb109c0eb5fd3d193da823339f",
"1db57a1e8b6e4096f811587f9eab0c6675fd9755"
],
"dmg0_rom.bin": [
"4ed31ec6b0b175bb109c0eb5fd3d193da823339f",
"1db57a1e8b6e4096f811587f9eab0c6675fd9755"
],
"sgb_bios.bin": [
"aa2f50a77dfb4823da96ba99309085a3c6278515",
"369e6eb5e0c975eaa52a4a3f6ee07b2a3c3c16de",
"f282b3aaf98f8423dab7d77f1aa0192be630f2fb"
],
"sgb1.boot.rom": [
"aa2f50a77dfb4823da96ba99309085a3c6278515"
],
"SGB1.sfc": [
"973e10840db683cf3faf61bd443090786b3a9f04"
],
"SGB1.sfc/program.rom": [
"973e10840db683cf3faf61bd443090786b3a9f04"
],
"SGB2.sfc": [
"e5b2922ca137051059e4269b236d07a22c07bc84"
],
"SGB2.sfc/program.rom": [
"e5b2922ca137051059e4269b236d07a22c07bc84"
],
"fs-a1gt_kanjifont.rom": [
"5aff2d9b6efc723bc395b0f96f0adfa83cc54a49"
],
"fs-a1wsx_kanjifont.rom": [
"5aff2d9b6efc723bc395b0f96f0adfa83cc54a49"
],
"yrw801.rom": [
"32760893ce06dbe3930627755ba065cc3d8ec6ca"
],
"fs-a1wsx_msx2psub.rom": [
"fe0254cbfc11405b79e7c86c7769bd6322b04995"
],
"MSX2PEXT.rom": [
"fe0254cbfc11405b79e7c86c7769bd6322b04995"
],
"fs-a1wsx_kanjibasic.rom": [
"dcc3a67732aa01c4f2ee8d1ad886444a4dbafe06"
],
"fs-a1wsx_disk.rom": [
"7ed7c55e0359737ac5e68d38cb6903f9e5d7c2b6"
],
"kick37350.A600": [
"02843c4253bbd29aba535b0aa3bd9a85034ecde4"
],
"amiga-os-120.rom": [
"11f9e62cf299f72184835b7b2a70a16333fc0d88"
],
"Kickstart v1.2 rev 33.180 (1986)(Commodore)(A500-A2000)[!].rom": [
"11f9e62cf299f72184835b7b2a70a16333fc0d88"
],
"Kickstart v1.2 rev 33.180 (1986)(Commodore)(A500-A1000-A2000).rom": [
"11f9e62cf299f72184835b7b2a70a16333fc0d88"
],
"amiga-os-130.rom": [
"891e9a547772fe0c6c19b610baf8bc4ea7fcb785"
],
"Kickstart v1.3 rev 34.5 (1987)(Commodore)(A500-A1000-A2000-CDTV)[!].rom": [
"891e9a547772fe0c6c19b610baf8bc4ea7fcb785"
],
"Kickstart v1.3 rev 34.5 (1987)(Commodore)(A500-A1000-A2000-CDTV).rom": [
"891e9a547772fe0c6c19b610baf8bc4ea7fcb785"
],
"amiga-os-204.rom": [
"c5839f5cb98a7a8947065c3ed2f14f5f42e334a1"
],
"Kickstart v2.04 rev 37.175 (1991)(Commodore)(A500+)[!].rom": [
"c5839f5cb98a7a8947065c3ed2f14f5f42e334a1"
],
"Kickstart v2.04 rev 37.175 (1991)(Commodore)(A500+).rom": [
"c5839f5cb98a7a8947065c3ed2f14f5f42e334a1"
],
"amiga-os-310-a600.rom": [
"3b7f1493b27e212830f989f26ca76c02049f09ca"
],
"Kickstart v3.1 rev 40.63 (1993)(Commodore)(A500-A600-A2000)[!].rom": [
"3b7f1493b27e212830f989f26ca76c02049f09ca"
],
"Kickstart v3.1 rev 40.63 (1993)(Commodore)(A500-A600-A2000).rom": [
"3b7f1493b27e212830f989f26ca76c02049f09ca"
],
"amiga-ext-130-cdtv.rom": [
"7ba40ffa17e500ed9fed041f3424bd81d9c907be"
],
"amiga-os-130-cdtv-ext.rom": [
"7ba40ffa17e500ed9fed041f3424bd81d9c907be"
],
"CDTV Extended-ROM v1.0 (1991)(Commodore)(CDTV)[!].rom": [
"7ba40ffa17e500ed9fed041f3424bd81d9c907be"
],
"CDTV Extended-ROM v1.0 (1992)(Commodore)(CDTV).rom": [
"7ba40ffa17e500ed9fed041f3424bd81d9c907be"
],
"amiga-os-300-a1200.rom": [
"70033828182fffc7ed106e5373a8b89dda76faa5"
],
"Kickstart v3.0 rev 39.106 (1992)(Commodore)(A1200)[!].rom": [
"70033828182fffc7ed106e5373a8b89dda76faa5"
],
"amiga-os-310-a1200.rom": [
"e21545723fe8374e91342617604f1b3d703094f1"
],
"AmigaVision.rom": [
"e21545723fe8374e91342617604f1b3d703094f1"
],
"Kickstart v3.1 rev 40.68 (1993)(Commodore)(A1200)[!].rom": [
"e21545723fe8374e91342617604f1b3d703094f1"
],
"Kickstart v3.1 rev 40.68 (1993)(Commodore)(A1200).rom": [
"e21545723fe8374e91342617604f1b3d703094f1"
],
"amiga-os-310-a4000.rom": [
"5fe04842d04a489720f0f4bb0e46948199406f49"
],
"Kickstart v3.1 rev 40.68 (1993)(Commodore)(A4000).rom": [
"5fe04842d04a489720f0f4bb0e46948199406f49"
],
"amiga-os-310-cd32.rom": [
"3525be8887f79b5929e017b42380a79edfee542d"
],
"Kickstart v3.1 rev 40.60 (1993)(Commodore)(CD32).rom": [
"3525be8887f79b5929e017b42380a79edfee542d"
],
"amiga-ext-310-cd32.rom": [
"5bef3d628ce59cc02a66e6e4ae0da48f60e78f7f"
],
"amiga-os-310-cd32-ext.rom": [
"5bef3d628ce59cc02a66e6e4ae0da48f60e78f7f"
],
"CD32 Extended-ROM rev 40.60 (1993)(Commodore)(CD32).rom": [
"5bef3d628ce59cc02a66e6e4ae0da48f60e78f7f"
],
"custom0.sf2": [
"286b2e1fb21cc79851da01666db6c0b0e88f25e3"
],
"colecovision.rom": [
"45bedc4cbdeac66c7df59e9e599195c778d86a92"
],
"coleco.rom": [
"45bedc4cbdeac66c7df59e9e599195c778d86a92"
],
"boot.rom": [
"45bedc4cbdeac66c7df59e9e599195c778d86a92"
],
"d2fdc.zip": [
"bc39fbd5b9a8d2287ac5d0a42e639fc4d3c2f9d4",
"af56c948598291b284a528f3fce06b961dba55e3"
],
"basic11.rom": [
"9451a1a09d8f75944dbd6f91193fc360f1de80ac"
],
"basic21.bin": [
"03bbb386cf530e804363acdfc1d13e64cf28af2e"
],
"exos21.bin": [
"55315b20fecb4441a07ee4bc5dc7153f396e0a2e"
],
"EXOS21.ROM": [
"55315b20fecb4441a07ee4bc5dc7153f396e0a2e"
],
"zx48.rom": [
"5ea7c2b824672e914525d1d5c419d71b84a426a2"
],
"zxs:48.rom": [
"5ea7c2b824672e914525d1d5c419d71b84a426a2"
],
"sony-playstation:239665b1a3dade1b5a52c06338011044": [
"343883a7b555646da8cee54aadd2795b6e7dd070"
],
@@ -93353,6 +93764,9 @@
"sony-playstation:c53ca5908936d412331790f4426c6c33": [
"96880d1ca92a016ff054be5159bb06fe03cb4e14"
],
"PSXONPSP660.BIN": [
"96880d1ca92a016ff054be5159bb06fe03cb4e14"
],
"PSXONPSP660.bin": [
"96880d1ca92a016ff054be5159bb06fe03cb4e14"
],
@@ -93632,13 +94046,6 @@
"sega-mega-cd:baca1df271d7c11fe50087c0358f4eb5": [
"2b125c0545afa089b617f2558e686ea723bdc06e"
],
"sega-saturn:af5828fdff51384f99b3c4926be27762": [
"2b8cb4f87580683eb4d760e4ed210813d667f0a2"
],
"saturn_bios.bin": [
"2b8cb4f87580683eb4d760e4ed210813d667f0a2",
"df94c5b4d47eb3cc404d88b33a8fda237eaf4720"
],
"sega-saturn:85ec9ca47d8f6807718151cbcca8b964": [
"df94c5b4d47eb3cc404d88b33a8fda237eaf4720"
],
@@ -93660,200 +94067,6 @@
"sega-saturn:0306c0e408d6682dd2d86324bd4ac661": [
"8c031bf9908fd0142fdd10a9cdd79389f8a3f2fc"
],
"tos100uk.img": [
"9a6e4c88533a9eaa4d55cdc040e47443e0226eb2"
],
"tos106de.img": [
"3b8cf5ffa41b252eb67f8824f94608fa4005d6dd"
],
"tos206us.img": [
"ee58768bdfc602c9b14942ce5481e97dd24e7c83"
],
"bios7.bin": [
"24f67bdea115a2c847c8813a262502ee1607b7df"
],
"bios9.bin": [
"bfaac75f101c135e32e2aaf541de6b1be4c8c62d"
],
"dsi_bios7.bin": [
"a3aa751eb6bdaaf8a827ba9e03576a6f1ab0f547"
],
"dsi_bios9.bin": [
"7bf549b8be9e48ab0cdc9b0fdadd49a5131f97eb"
],
"gb_bios.bin": [
"4ed31ec6b0b175bb109c0eb5fd3d193da823339f",
"1db57a1e8b6e4096f811587f9eab0c6675fd9755"
],
"dmg0_rom.bin": [
"4ed31ec6b0b175bb109c0eb5fd3d193da823339f",
"1db57a1e8b6e4096f811587f9eab0c6675fd9755"
],
"sgb_bios.bin": [
"aa2f50a77dfb4823da96ba99309085a3c6278515",
"369e6eb5e0c975eaa52a4a3f6ee07b2a3c3c16de",
"f282b3aaf98f8423dab7d77f1aa0192be630f2fb"
],
"sgb1.boot.rom": [
"aa2f50a77dfb4823da96ba99309085a3c6278515"
],
"SGB1.sfc": [
"973e10840db683cf3faf61bd443090786b3a9f04"
],
"SGB1.sfc/program.rom": [
"973e10840db683cf3faf61bd443090786b3a9f04"
],
"SGB2.sfc": [
"e5b2922ca137051059e4269b236d07a22c07bc84"
],
"SGB2.sfc/program.rom": [
"e5b2922ca137051059e4269b236d07a22c07bc84"
],
"fs-a1gt_kanjifont.rom": [
"5aff2d9b6efc723bc395b0f96f0adfa83cc54a49"
],
"fs-a1wsx_kanjifont.rom": [
"5aff2d9b6efc723bc395b0f96f0adfa83cc54a49"
],
"yrw801.rom": [
"32760893ce06dbe3930627755ba065cc3d8ec6ca"
],
"fs-a1wsx_msx2psub.rom": [
"fe0254cbfc11405b79e7c86c7769bd6322b04995"
],
"MSX2PEXT.rom": [
"fe0254cbfc11405b79e7c86c7769bd6322b04995"
],
"fs-a1wsx_kanjibasic.rom": [
"dcc3a67732aa01c4f2ee8d1ad886444a4dbafe06"
],
"fs-a1wsx_disk.rom": [
"7ed7c55e0359737ac5e68d38cb6903f9e5d7c2b6"
],
"kick37350.A600": [
"02843c4253bbd29aba535b0aa3bd9a85034ecde4"
],
"amiga-os-120.rom": [
"11f9e62cf299f72184835b7b2a70a16333fc0d88"
],
"Kickstart v1.2 rev 33.180 (1986)(Commodore)(A500-A2000)[!].rom": [
"11f9e62cf299f72184835b7b2a70a16333fc0d88"
],
"Kickstart v1.2 rev 33.180 (1986)(Commodore)(A500-A1000-A2000).rom": [
"11f9e62cf299f72184835b7b2a70a16333fc0d88"
],
"amiga-os-130.rom": [
"891e9a547772fe0c6c19b610baf8bc4ea7fcb785"
],
"Kickstart v1.3 rev 34.5 (1987)(Commodore)(A500-A1000-A2000-CDTV)[!].rom": [
"891e9a547772fe0c6c19b610baf8bc4ea7fcb785"
],
"Kickstart v1.3 rev 34.5 (1987)(Commodore)(A500-A1000-A2000-CDTV).rom": [
"891e9a547772fe0c6c19b610baf8bc4ea7fcb785"
],
"amiga-os-204.rom": [
"c5839f5cb98a7a8947065c3ed2f14f5f42e334a1"
],
"Kickstart v2.04 rev 37.175 (1991)(Commodore)(A500+)[!].rom": [
"c5839f5cb98a7a8947065c3ed2f14f5f42e334a1"
],
"Kickstart v2.04 rev 37.175 (1991)(Commodore)(A500+).rom": [
"c5839f5cb98a7a8947065c3ed2f14f5f42e334a1"
],
"amiga-os-310-a600.rom": [
"3b7f1493b27e212830f989f26ca76c02049f09ca"
],
"Kickstart v3.1 rev 40.63 (1993)(Commodore)(A500-A600-A2000)[!].rom": [
"3b7f1493b27e212830f989f26ca76c02049f09ca"
],
"Kickstart v3.1 rev 40.63 (1993)(Commodore)(A500-A600-A2000).rom": [
"3b7f1493b27e212830f989f26ca76c02049f09ca"
],
"amiga-ext-130-cdtv.rom": [
"7ba40ffa17e500ed9fed041f3424bd81d9c907be"
],
"amiga-os-130-cdtv-ext.rom": [
"7ba40ffa17e500ed9fed041f3424bd81d9c907be"
],
"CDTV Extended-ROM v1.0 (1991)(Commodore)(CDTV)[!].rom": [
"7ba40ffa17e500ed9fed041f3424bd81d9c907be"
],
"CDTV Extended-ROM v1.0 (1992)(Commodore)(CDTV).rom": [
"7ba40ffa17e500ed9fed041f3424bd81d9c907be"
],
"amiga-os-300-a1200.rom": [
"70033828182fffc7ed106e5373a8b89dda76faa5"
],
"Kickstart v3.0 rev 39.106 (1992)(Commodore)(A1200)[!].rom": [
"70033828182fffc7ed106e5373a8b89dda76faa5"
],
"amiga-os-310-a1200.rom": [
"e21545723fe8374e91342617604f1b3d703094f1"
],
"AmigaVision.rom": [
"e21545723fe8374e91342617604f1b3d703094f1"
],
"Kickstart v3.1 rev 40.68 (1993)(Commodore)(A1200)[!].rom": [
"e21545723fe8374e91342617604f1b3d703094f1"
],
"Kickstart v3.1 rev 40.68 (1993)(Commodore)(A1200).rom": [
"e21545723fe8374e91342617604f1b3d703094f1"
],
"amiga-os-310-a4000.rom": [
"5fe04842d04a489720f0f4bb0e46948199406f49"
],
"Kickstart v3.1 rev 40.68 (1993)(Commodore)(A4000).rom": [
"5fe04842d04a489720f0f4bb0e46948199406f49"
],
"amiga-os-310-cd32.rom": [
"3525be8887f79b5929e017b42380a79edfee542d"
],
"Kickstart v3.1 rev 40.60 (1993)(Commodore)(CD32).rom": [
"3525be8887f79b5929e017b42380a79edfee542d"
],
"amiga-ext-310-cd32.rom": [
"5bef3d628ce59cc02a66e6e4ae0da48f60e78f7f"
],
"amiga-os-310-cd32-ext.rom": [
"5bef3d628ce59cc02a66e6e4ae0da48f60e78f7f"
],
"CD32 Extended-ROM rev 40.60 (1993)(Commodore)(CD32).rom": [
"5bef3d628ce59cc02a66e6e4ae0da48f60e78f7f"
],
"custom0.sf2": [
"286b2e1fb21cc79851da01666db6c0b0e88f25e3"
],
"colecovision.rom": [
"45bedc4cbdeac66c7df59e9e599195c778d86a92"
],
"coleco.rom": [
"45bedc4cbdeac66c7df59e9e599195c778d86a92"
],
"boot.rom": [
"45bedc4cbdeac66c7df59e9e599195c778d86a92"
],
"d2fdc.zip": [
"bc39fbd5b9a8d2287ac5d0a42e639fc4d3c2f9d4",
"af56c948598291b284a528f3fce06b961dba55e3"
],
"basic11.rom": [
"9451a1a09d8f75944dbd6f91193fc360f1de80ac"
],
"basic21.bin": [
"03bbb386cf530e804363acdfc1d13e64cf28af2e"
],
"exos21.bin": [
"55315b20fecb4441a07ee4bc5dc7153f396e0a2e"
],
"EXOS21.ROM": [
"55315b20fecb4441a07ee4bc5dc7153f396e0a2e"
],
"zx48.rom": [
"5ea7c2b824672e914525d1d5c419d71b84a426a2"
],
"zxs:48.rom": [
"5ea7c2b824672e914525d1d5c419d71b84a426a2"
],
"apple2gs1.rom": [
"e4fc7560b69d062cb2da5b1ffbe11cd1ca03cc37"
],
@@ -93900,12 +94113,6 @@
"d64tano.rom": [
"1983b4fb398e3dd9668d424c666c5a0b3f1e2b69"
],
"d64_1.rom": [
"f119506eaa3b4b70b9aa0dd83761e8cbe043d042"
],
"fs-5500_disk.rom": [
"78cd7f847e77fd8cd51a647efb2725ba93f4c471"
],
"pcfxbios.bin": [
"1a77fd83e337f906aecab27a1604db064cf10074"
],
@@ -93919,6 +94126,12 @@
"plus3e-3.rom": [
"65f031caa8148a5493afe42c41f4929deab26b4e"
],
"d64_1.rom": [
"f119506eaa3b4b70b9aa0dd83761e8cbe043d042"
],
"fs-5500_disk.rom": [
"78cd7f847e77fd8cd51a647efb2725ba93f4c471"
],
"a1000kbd_fr.zip": [
"93d36de4d5d376c521a9ca99722f659e60d177f2"
],
@@ -98129,6 +98342,21 @@
"0f3e6586": "10f1a7204f69b82a18bc94a3010c9660aec0c802",
"e75945f3": "c0ee6f9443fa82c0fef5d497b3e76aa3077f1865",
"0636e0be": "72c60172fb1ba77c9b24b06b7755f0a16f0b3a13",
"298dd5b5": "eca9cff1014ce5081804e193588d96c6ddb35432",
"723e60f9": "7742089b4468a736cadb659a7deca3320fe6dcbd",
"162b696a": "5b2e249b9c5133ec987b3ea77596381dc0d6bc1d",
"ec8725db": "7ec7652fcfce8ddc6e801839291f0e28ef1d5ae7",
"27eaae69": "d510c877031bbd5f3d198581a2c8651e09b9861f",
"cb10a53d": "ae363db8cd5645e1753d9bacc82cc0724e8e7f21",
"5b16049e": "f489d479371df32f6d280a0cb23b59a35ba2b833",
"22d3f0ca": "b4c50ca9bea07f7c35250a1a11906091971c05ae",
"fd5eb11d": "081f6a2024643b54ef4a436a85508539b6d20a1e",
"dca9114c": "4b53832f0733c1e29e5f1de2428e5475e891af29",
"48d1453c": "90361e2a538d2388506657252ae41aceeb1ba360",
"93c144dd": "bc0a110bf27aee89a0b2fc8111e2391ede891b8d",
"4234ace5": "64c13b951a845ca7f8081f68138a6181557458d1",
"903dcc27": "9fbc66aedef7fe3bae0986cdb9323d2b8db4c9d3",
"cd12ebcf": "ec6883100d807b894a98f426d024d22c77b63e7f",
"a5751b99": "5f4aed208301449c2e9514edfd325fe9dead76fa",
"7f9a2c1e": "f3f2a11f3ecd91cd62d74c3acfad68a4cc6ddbd9",
"26dc3fba": "9259b87edfe9b9f6d0749788a75a6ccf158f50aa",
@@ -115312,6 +115540,42 @@
"1c1a0d8c9f4c446ccd7470516b215ddca5052fb2",
"80080644289ed93d71a1103992a154cc9802b2fa",
"434bc0b4eb4827da0773ec0795aadc5162569a07",
"9a6e4c88533a9eaa4d55cdc040e47443e0226eb2",
"3b8cf5ffa41b252eb67f8824f94608fa4005d6dd",
"ee58768bdfc602c9b14942ce5481e97dd24e7c83",
"2b8cb4f87580683eb4d760e4ed210813d667f0a2",
"24f67bdea115a2c847c8813a262502ee1607b7df",
"bfaac75f101c135e32e2aaf541de6b1be4c8c62d",
"a3aa751eb6bdaaf8a827ba9e03576a6f1ab0f547",
"7bf549b8be9e48ab0cdc9b0fdadd49a5131f97eb",
"4ed31ec6b0b175bb109c0eb5fd3d193da823339f",
"aa2f50a77dfb4823da96ba99309085a3c6278515",
"973e10840db683cf3faf61bd443090786b3a9f04",
"e5b2922ca137051059e4269b236d07a22c07bc84",
"5aff2d9b6efc723bc395b0f96f0adfa83cc54a49",
"32760893ce06dbe3930627755ba065cc3d8ec6ca",
"fe0254cbfc11405b79e7c86c7769bd6322b04995",
"dcc3a67732aa01c4f2ee8d1ad886444a4dbafe06",
"7ed7c55e0359737ac5e68d38cb6903f9e5d7c2b6",
"02843c4253bbd29aba535b0aa3bd9a85034ecde4",
"11f9e62cf299f72184835b7b2a70a16333fc0d88",
"891e9a547772fe0c6c19b610baf8bc4ea7fcb785",
"c5839f5cb98a7a8947065c3ed2f14f5f42e334a1",
"3b7f1493b27e212830f989f26ca76c02049f09ca",
"7ba40ffa17e500ed9fed041f3424bd81d9c907be",
"70033828182fffc7ed106e5373a8b89dda76faa5",
"e21545723fe8374e91342617604f1b3d703094f1",
"5fe04842d04a489720f0f4bb0e46948199406f49",
"3525be8887f79b5929e017b42380a79edfee542d",
"5bef3d628ce59cc02a66e6e4ae0da48f60e78f7f",
"44620f57a25f0bcac2b57ca2b0f1ebad3bf305d3",
"286b2e1fb21cc79851da01666db6c0b0e88f25e3",
"45bedc4cbdeac66c7df59e9e599195c778d86a92",
"bc39fbd5b9a8d2287ac5d0a42e639fc4d3c2f9d4",
"9451a1a09d8f75944dbd6f91193fc360f1de80ac",
"03bbb386cf530e804363acdfc1d13e64cf28af2e",
"55315b20fecb4441a07ee4bc5dc7153f396e0a2e",
"5ea7c2b824672e914525d1d5c419d71b84a426a2",
"343883a7b555646da8cee54aadd2795b6e7dd070",
"1a8d6f9453111b1d317bb7dae300495fbf54600c",
"b06f4a861f74270be819aa2a07db8d0563a7cc4e",
@@ -115427,7 +115691,6 @@
"f5f60f03501908962446ee02fc27d98694dd157d",
"328a3228c29fba244b9db2055adc1ec4f7a87e6b",
"2b125c0545afa089b617f2558e686ea723bdc06e",
"2b8cb4f87580683eb4d760e4ed210813d667f0a2",
"df94c5b4d47eb3cc404d88b33a8fda237eaf4720",
"3bb41feb82838ab9a35601ac666de5aacfd17a58",
"faa8ea183a6d7bbe5d4e03bb1332519800d3fbc3",
@@ -115435,41 +115698,6 @@
"49d8493008fa715ca0c94d99817a5439d6f2c796",
"8a22710e09ce75f39625894366cafe503ed1942d",
"8c031bf9908fd0142fdd10a9cdd79389f8a3f2fc",
"9a6e4c88533a9eaa4d55cdc040e47443e0226eb2",
"3b8cf5ffa41b252eb67f8824f94608fa4005d6dd",
"ee58768bdfc602c9b14942ce5481e97dd24e7c83",
"24f67bdea115a2c847c8813a262502ee1607b7df",
"bfaac75f101c135e32e2aaf541de6b1be4c8c62d",
"a3aa751eb6bdaaf8a827ba9e03576a6f1ab0f547",
"7bf549b8be9e48ab0cdc9b0fdadd49a5131f97eb",
"4ed31ec6b0b175bb109c0eb5fd3d193da823339f",
"aa2f50a77dfb4823da96ba99309085a3c6278515",
"973e10840db683cf3faf61bd443090786b3a9f04",
"e5b2922ca137051059e4269b236d07a22c07bc84",
"5aff2d9b6efc723bc395b0f96f0adfa83cc54a49",
"32760893ce06dbe3930627755ba065cc3d8ec6ca",
"fe0254cbfc11405b79e7c86c7769bd6322b04995",
"dcc3a67732aa01c4f2ee8d1ad886444a4dbafe06",
"7ed7c55e0359737ac5e68d38cb6903f9e5d7c2b6",
"02843c4253bbd29aba535b0aa3bd9a85034ecde4",
"11f9e62cf299f72184835b7b2a70a16333fc0d88",
"891e9a547772fe0c6c19b610baf8bc4ea7fcb785",
"c5839f5cb98a7a8947065c3ed2f14f5f42e334a1",
"3b7f1493b27e212830f989f26ca76c02049f09ca",
"7ba40ffa17e500ed9fed041f3424bd81d9c907be",
"70033828182fffc7ed106e5373a8b89dda76faa5",
"e21545723fe8374e91342617604f1b3d703094f1",
"5fe04842d04a489720f0f4bb0e46948199406f49",
"3525be8887f79b5929e017b42380a79edfee542d",
"5bef3d628ce59cc02a66e6e4ae0da48f60e78f7f",
"44620f57a25f0bcac2b57ca2b0f1ebad3bf305d3",
"286b2e1fb21cc79851da01666db6c0b0e88f25e3",
"45bedc4cbdeac66c7df59e9e599195c778d86a92",
"bc39fbd5b9a8d2287ac5d0a42e639fc4d3c2f9d4",
"9451a1a09d8f75944dbd6f91193fc360f1de80ac",
"03bbb386cf530e804363acdfc1d13e64cf28af2e",
"55315b20fecb4441a07ee4bc5dc7153f396e0a2e",
"5ea7c2b824672e914525d1d5c419d71b84a426a2",
"e4fc7560b69d062cb2da5b1ffbe11cd1ca03cc37",
"bc32bc0e8902946663998f56aea52be597d9e361",
"014881a959e045e00f4db8f52955200865d40280",
@@ -115479,12 +115707,12 @@
"04990aa1c3a3fc7294ec884b81deaa89832df614",
"e3c8986bb1d44269c4587b04f1ca27a70b0aaa2e",
"1983b4fb398e3dd9668d424c666c5a0b3f1e2b69",
"f119506eaa3b4b70b9aa0dd83761e8cbe043d042",
"78cd7f847e77fd8cd51a647efb2725ba93f4c471",
"1a77fd83e337f906aecab27a1604db064cf10074",
"93407ea10d2f30ab96a314d8eca44fe160aea734",
"94d44d7f9529ec1642ba3771ed3c5f756d5bc872",
"65f031caa8148a5493afe42c41f4929deab26b4e",
"f119506eaa3b4b70b9aa0dd83761e8cbe043d042",
"78cd7f847e77fd8cd51a647efb2725ba93f4c471",
"93d36de4d5d376c521a9ca99722f659e60d177f2",
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea",
"e35eda0cc2c11da92c0a6c222f314d84e623b29e",
+1
View File
@@ -54,6 +54,7 @@ nav:
- RetroBat: platforms/retrobat.md
- RetroDECK: platforms/retrodeck.md
- RetroPie: platforms/retropie.md
- RomM: platforms/romm.md
- Systems:
- Overview: systems/index.md
- 3DO Company: systems/3do-company.md
+2
View File
@@ -93,3 +93,5 @@ Full libretro docs: `https://docs.libretro.com/library/<core>/`
| RetroBat | md5 | MD5 check via JSON config | `batocera-systems.json` |
| EmuDeck | md5 | MD5 whitelist per system | `checkBIOS.sh` |
| Recalbox | md5 | multi-hash comma-separated | `es_bios.xml` + `Bios.cpp` |
| RetroDECK | md5 | MD5 per file via component manifests | `api_data_processing.sh` |
| RomM | md5 | size + any hash (MD5/SHA1/CRC32) | `firmware.py` |
+11
View File
@@ -86,6 +86,17 @@ platforms:
# Each component/<name>/component_manifest.json declares BIOS requirements
# Scraper enumerates top-level dirs via GitHub API, fetches each manifest directly
romm:
config: romm.yml
status: active
logo: "https://avatars.githubusercontent.com/u/168586850"
scraper: romm
source_url: "https://raw.githubusercontent.com/rommapp/romm/master/backend/models/fixtures/known_bios_files.json"
source_format: json
hash_type: sha1
schedule: monthly
inherits_from: emulatorjs # cores inherited from emulatorjs.yml
retropie:
config: retropie.yml
status: archived # Last release: v4.8 (March 2022) - no update in 4 years
+57
View File
@@ -0,0 +1,57 @@
# EmulatorJS base config (not a standalone platform).
# Provides the core list for platforms that use EmulatorJS as their emulation engine.
# Source: emulatorjs/emulatorjs data/src/consts.js + emulatorjs/build cores.json
# RomM mapping: rommapp/romm frontend/src/utils/index.ts (_EJS_CORES_MAP)
platform: EmulatorJS
version: "4.2.3"
homepage: "https://emulatorjs.org"
source: "https://github.com/emulatorjs/emulatorjs"
cores:
- a5200
- beetle_vb
- cap32
- crocods
- desmume
- desmume2015
- dosbox_pure
- fbalpha2012_cps1
- fbalpha2012_cps2
- fbneo
- fceumm
- freeintv
- fuse
- gambatte
- gearcoleco
- genesis_plus_gx
- handy
- mame2003
- mame2003_plus
- mednafen_ngp
- mednafen_pce
- mednafen_pcfx
- mednafen_psx_hw
- mednafen_wswan
- melonds
- mgba
- mupen64plus_next
- nestopia
- opera
- parallel_n64
- pcsx_rearmed
- picodrive
- ppsspp
- prboom
- prosystem
- puae
- same_cdi
- smsplus
- snes9x
- stella2014
- vice_x128
- vice_x64
- vice_x64sc
- vice_xpet
- vice_xplus4
- vice_xvic
- virtualjaguar
- yabause
+2731
View File
File diff suppressed because it is too large Load Diff
+4 -5
View File
@@ -26,7 +26,7 @@ import urllib.error
from pathlib import Path
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from common import load_database, load_platform_config
from common import list_registered_platforms, load_database, load_platform_config
try:
import yaml
@@ -381,10 +381,9 @@ def main():
db = load_database(args.db)
if args.all:
platforms = []
for f in Path(args.platforms_dir).glob("*.yml"):
if not f.name.startswith("_"):
platforms.append(f.stem)
platforms = list_registered_platforms(
args.platforms_dir, include_archived=True,
)
elif args.platform:
platforms = [args.platform]
else:
+25
View File
@@ -167,6 +167,31 @@ def load_data_dir_registry(platforms_dir: str = "platforms") -> dict:
return data.get("data_directories", {})
def list_registered_platforms(
platforms_dir: str = "platforms",
include_archived: bool = False,
) -> list[str]:
"""List platforms registered in _registry.yml.
Only registered platforms generate packs and appear in CI.
Unregistered YAMLs (e.g., emulatorjs.yml) are base configs for inheritance.
"""
registry_path = os.path.join(platforms_dir, "_registry.yml")
if not os.path.exists(registry_path):
return []
with open(registry_path) as f:
registry = yaml.safe_load(f) or {}
platforms = []
for name, meta in sorted(registry.get("platforms", {}).items()):
status = meta.get("status", "active")
if status == "archived" and not include_archived:
continue
config_path = os.path.join(platforms_dir, meta.get("config", f"{name}.yml"))
if os.path.exists(config_path):
platforms.append(name)
return platforms
def resolve_local_file(
file_entry: dict,
db: dict,
+3 -5
View File
@@ -25,7 +25,7 @@ except ImportError:
sys.exit(1)
sys.path.insert(0, os.path.dirname(__file__))
from common import load_database, load_emulator_profiles, load_platform_config
from common import list_registered_platforms, load_database, load_emulator_profiles, load_platform_config
DEFAULT_EMULATORS_DIR = "emulators"
DEFAULT_PLATFORMS_DIR = "platforms"
@@ -36,10 +36,8 @@ def load_platform_files(platforms_dir: str) -> tuple[dict[str, set[str]], dict[s
"""Load all platform configs and collect declared filenames + data_directories per system."""
declared = {}
platform_data_dirs = {}
for f in sorted(Path(platforms_dir).glob("*.yml")):
if f.name.startswith("_"):
continue
config = load_platform_config(f.stem, platforms_dir)
for platform_name in list_registered_platforms(platforms_dir, include_archived=True):
config = load_platform_config(platform_name, platforms_dir)
for sys_id, system in config.get("systems", {}).items():
for fe in system.get("files", []):
name = fe.get("name", "")
+3 -4
View File
@@ -18,7 +18,7 @@ from datetime import datetime, timezone
from pathlib import Path
sys.path.insert(0, os.path.dirname(__file__))
from common import compute_hashes
from common import compute_hashes, list_registered_platforms
CACHE_DIR = ".cache"
CACHE_FILE = os.path.join(CACHE_DIR, "db_cache.json")
@@ -353,9 +353,8 @@ def _collect_all_aliases(files: dict) -> dict:
if platforms_dir.is_dir():
try:
import yaml
for config_file in platforms_dir.glob("*.yml"):
if config_file.name.startswith("_"):
continue
for platform_name in list_registered_platforms(str(platforms_dir), include_archived=True):
config_file = platforms_dir / f"{platform_name}.yml"
try:
with open(config_file) as f:
config = yaml.safe_load(f) or {}
+16 -15
View File
@@ -27,9 +27,10 @@ sys.path.insert(0, os.path.dirname(__file__))
from common import (
_build_validation_index, build_zip_contents_index, check_file_validation,
check_inside_zip, compute_hashes, fetch_large_file, filter_files_by_mode,
group_identical_platforms, list_emulator_profiles, list_system_ids,
load_database, load_data_dir_registry, load_emulator_profiles,
load_platform_config, md5_composite, resolve_local_file,
group_identical_platforms, list_emulator_profiles, list_registered_platforms,
list_system_ids, load_database, load_data_dir_registry,
load_emulator_profiles, load_platform_config, md5_composite,
resolve_local_file,
)
from deterministic_zip import rebuild_zip_deterministic
@@ -241,7 +242,9 @@ def generate_pack(
platform_display = config.get("platform", platform_name)
base_dest = config.get("base_destination", "")
zip_name = f"{platform_display.replace(' ', '_')}_BIOS_Pack.zip"
version = config.get("version", config.get("dat_version", ""))
version_tag = f"_{version.replace(' ', '')}" if version else ""
zip_name = f"{platform_display.replace(' ', '_')}{version_tag}_BIOS_Pack.zip"
zip_path = os.path.join(output_dir, zip_name)
os.makedirs(output_dir, exist_ok=True)
@@ -818,13 +821,8 @@ def generate_system_pack(
def list_platforms(platforms_dir: str) -> list[str]:
"""List available platform names from YAML files."""
platforms = []
for f in sorted(Path(platforms_dir).glob("*.yml")):
if f.name.startswith("_"):
continue
platforms.append(f.stem)
return platforms
"""List available platform names from registry."""
return list_registered_platforms(platforms_dir, include_archived=True)
def main():
@@ -899,9 +897,9 @@ def main():
# Platform mode (existing)
if args.all:
sys.path.insert(0, os.path.dirname(__file__))
from list_platforms import list_platforms as _list_active
platforms = _list_active(include_archived=args.include_archived)
platforms = list_registered_platforms(
args.platforms_dir, include_archived=args.include_archived,
)
elif args.platform:
platforms = [args.platform]
else:
@@ -937,8 +935,11 @@ def main():
emu_profiles=emu_profiles,
)
if zip_path and variants:
rep_cfg = load_platform_config(representative, args.platforms_dir)
ver = rep_cfg.get("version", rep_cfg.get("dat_version", ""))
ver_tag = f"_{ver.replace(' ', '')}" if ver else ""
all_names = [load_platform_config(p, args.platforms_dir).get("platform", p) for p in group_platforms]
combined = "_".join(n.replace(" ", "") for n in all_names) + "_BIOS_Pack.zip"
combined = "_".join(n.replace(" ", "") for n in all_names) + f"{ver_tag}_BIOS_Pack.zip"
new_path = os.path.join(os.path.dirname(zip_path), combined)
if new_path != zip_path:
os.rename(zip_path, new_path)
+80 -27
View File
@@ -18,7 +18,7 @@ from datetime import datetime, timezone
from pathlib import Path
sys.path.insert(0, os.path.dirname(__file__))
from common import load_database, load_platform_config
from common import list_registered_platforms, load_database, load_platform_config
from verify import verify_platform
def compute_coverage(platform_name: str, platforms_dir: str, db: dict) -> dict:
@@ -80,10 +80,7 @@ def generate_readme(db: dict, platforms_dir: str) -> str:
size_mb = total_size / (1024 * 1024)
ts = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
platform_names = sorted(
p.stem for p in Path(platforms_dir).glob("*.yml")
if not p.name.startswith("_")
)
platform_names = list_registered_platforms(platforms_dir, include_archived=True)
coverages = {}
for name in platform_names:
@@ -96,42 +93,88 @@ def generate_readme(db: dict, platforms_dir: str) -> str:
1 for f in Path("emulators").glob("*.yml")
) if Path("emulators").exists() else 0
# Count systems from emulator profiles
system_ids: set[str] = set()
emu_dir = Path("emulators")
if emu_dir.exists():
try:
import yaml
for f in emu_dir.glob("*.yml"):
with open(f) as fh:
p = yaml.safe_load(fh) or {}
system_ids.update(p.get("systems", []))
except ImportError:
pass
lines = [
"# RetroBIOS",
"",
"Source-verified BIOS and firmware packs for retrogaming platforms.",
f"Complete BIOS and firmware packs for RetroArch, Batocera, Recalbox, Lakka,"
f" RetroPie, EmuDeck, RetroBat, and RetroDECK.",
"",
"Documentation and metadata can drift from what emulators actually load at runtime.",
"To keep packs accurate, each file here is checked against the emulator's source code:",
"what the code opens, what hashes it expects, what happens when a file is missing.",
f"{emulator_count} emulators profiled, {len(coverages)} platforms cross-referenced,",
f"{total_files:,} files verified.",
f"**{total_files:,}** verified files across **{len(system_ids)}** systems,"
f" ready to extract into your emulator's BIOS directory.",
"",
"### How it works",
"## Download BIOS packs",
"",
"1. **Read emulator source code** - identify every file the code loads, its expected hash and size",
"2. **Cross-reference with platforms** - match against what RetroArch, Batocera, Recalbox and others declare",
"3. **Build packs** - for each platform, include its baseline files plus what its cores need",
"4. **Verify** - run each platform's native checks (MD5, existence) and emulator-level validation (CRC32, size)",
"Pick your platform, download the ZIP, extract to the BIOS path.",
"",
"When a platform and an emulator disagree on a file, the discrepancy is reported.",
"When a variant in the repo satisfies both, it is preferred automatically.",
"",
f"> **{total_files:,}** files | **{size_mb:.1f} MB** | **{len(coverages)}** platforms | **{emulator_count}** emulator profiles",
"",
"## Download",
"",
"| Platform | Files | Verification | Pack |",
"|----------|-------|-------------|------|",
"| Platform | BIOS files | Extract to | Download |",
"|----------|-----------|-----------|----------|",
]
extract_paths = {
"RetroArch": "`system/`",
"Lakka": "`system/`",
"Batocera": "`/userdata/bios/`",
"Recalbox": "`/recalbox/share/bios/`",
"RetroBat": "`bios/`",
"RetroPie": "`BIOS/`",
"RetroDECK": "`~/retrodeck/bios/`",
"EmuDeck": "`Emulation/bios/`",
"RomM": "`bios/{platform_slug}/`",
}
for name, cov in sorted(coverages.items(), key=lambda x: x[1]["platform"]):
display = cov["platform"]
path = extract_paths.get(display, "")
lines.append(
f"| {cov['platform']} | {cov['total']} | {cov['mode']} | "
f"| {display} | {cov['total']} | {path} | "
f"[Download]({RELEASE_URL}) |"
)
lines.extend([
"",
"## What's included",
"",
"BIOS, firmware, and system files for consoles from Atari to PlayStation 3.",
f"Each file is checked against the emulator's source code to match what the"
f" code actually loads at runtime.",
"",
f"- **{len(coverages)} platforms** supported with platform-specific verification",
f"- **{emulator_count} emulators** profiled from source (RetroArch cores + standalone)",
f"- **{len(system_ids)} systems** covered (NES, SNES, PlayStation, Saturn, Dreamcast, ...)",
f"- **{total_files:,} files** verified with MD5, SHA1, CRC32 checksums",
f"- **{size_mb:.0f} MB** total collection size",
"",
"## Supported systems",
"",
])
# Show well-known systems for SEO, link to full list
well_known = [
"NES", "SNES", "Nintendo 64", "GameCube", "Wii", "Game Boy", "Game Boy Advance",
"Nintendo DS", "Nintendo 3DS", "Switch",
"PlayStation", "PlayStation 2", "PlayStation 3", "PSP", "PS Vita",
"Mega Drive", "Saturn", "Dreamcast", "Game Gear", "Master System",
"Neo Geo", "Atari 2600", "Atari 7800", "Atari Lynx", "Atari ST",
"MSX", "PC Engine", "TurboGrafx-16", "ColecoVision", "Intellivision",
"Commodore 64", "Amiga", "ZX Spectrum", "Arcade (MAME)",
]
lines.extend([
", ".join(well_known) + f", and {len(system_ids) - len(well_known)}+ more.",
"",
f"Full list with per-file details: **[{SITE_URL}]({SITE_URL})**",
"",
"## Coverage",
"",
@@ -147,10 +190,20 @@ def generate_readme(db: dict, platforms_dir: str) -> str:
)
lines.extend([
"",
"## How it works",
"",
"Documentation and metadata can drift from what emulators actually load.",
"To keep packs accurate, each file is checked against the emulator's source code.",
"",
"1. **Read emulator source code** - trace every file the code loads, its expected hash and size",
"2. **Cross-reference with platforms** - match against what each platform declares",
"3. **Build packs** - include baseline files plus what each platform's cores need",
"4. **Verify** - run platform-native checks and emulator-level validation",
"",
"## Documentation",
"",
f"Full file listings, platform coverage, emulator profiles, and gap analysis: **[{SITE_URL}]({SITE_URL})**",
f"Per-file hashes, emulator profiles, gap analysis, cross-reference: **[{SITE_URL}]({SITE_URL})**",
"",
])
+2 -5
View File
@@ -26,7 +26,7 @@ except ImportError:
sys.exit(1)
sys.path.insert(0, os.path.dirname(__file__))
from common import load_database, load_emulator_profiles, load_platform_config
from common import list_registered_platforms, load_database, load_emulator_profiles, load_platform_config
from generate_readme import compute_coverage
from verify import verify_platform
@@ -2044,10 +2044,7 @@ def main():
registry = (yaml.safe_load(f) or {}).get("platforms", {})
# Load platform configs
platform_names = [
p.stem for p in Path(args.platforms_dir).glob("*.yml")
if not p.name.startswith("_")
]
platform_names = list_registered_platforms(args.platforms_dir, include_archived=True)
print("Computing platform coverage...")
coverages = {}
+3 -32
View File
@@ -17,45 +17,16 @@ import argparse
import json
import os
import sys
from pathlib import Path
try:
import yaml
except ImportError:
yaml = None
sys.path.insert(0, os.path.dirname(__file__))
from common import list_registered_platforms
PLATFORMS_DIR = "platforms"
def _load_registry(platforms_dir: str = PLATFORMS_DIR) -> dict:
"""Load _registry.yml if available."""
registry_path = Path(platforms_dir) / "_registry.yml"
if yaml and registry_path.exists():
with open(registry_path) as f:
return yaml.safe_load(f) or {}
return {}
def list_platforms(include_archived: bool = False) -> list[str]:
"""List platform config files, filtering by status from _registry.yml."""
platforms_dir = Path(PLATFORMS_DIR)
if not platforms_dir.is_dir():
return []
registry = _load_registry(str(platforms_dir))
registry_platforms = registry.get("platforms", {})
platforms = []
for f in sorted(platforms_dir.glob("*.yml")):
if f.name.startswith("_"):
continue
name = f.stem
status = registry_platforms.get(name, {}).get("status", "active")
if status == "archived" and not include_archived:
continue
platforms.append(name)
return platforms
return list_registered_platforms(PLATFORMS_DIR, include_archived=include_archived)
def main():
+224
View File
@@ -0,0 +1,224 @@
#!/usr/bin/env python3
"""Scraper for RomM BIOS requirements.
Source: https://github.com/rommapp/romm
Format: JSON fixture mapping "slug:filename" to {size, crc, md5, sha1}
Hash: SHA1 primary (all four hashes available per entry)
RomM stores known BIOS hashes in known_bios_files.json. At startup, the
fixture is loaded into Redis. When scanning or uploading firmware, RomM
verifies: file size must match AND at least one hash (MD5, SHA1, CRC32)
must match (firmware.py:verify_file_hashes).
RomM hashes files as opaque blobs (no ZIP content inspection). Arcade
BIOS ZIPs are matched by their container hash, which varies by MAME
version and ZIP tool. This is a known limitation (rommapp/romm#2888).
Folder structure: {library}/bios/{platform_slug}/{filename} (flat).
Slugs are IGDB-style platform identifiers.
"""
from __future__ import annotations
import json
import sys
try:
from .base_scraper import BaseScraper, BiosRequirement, fetch_github_latest_version
except ImportError:
from base_scraper import BaseScraper, BiosRequirement, fetch_github_latest_version
PLATFORM_NAME = "romm"
SOURCE_URL = (
"https://raw.githubusercontent.com/rommapp/romm/"
"master/backend/models/fixtures/known_bios_files.json"
)
GITHUB_REPO = "rommapp/romm"
# IGDB slug -> retrobios system ID
SLUG_MAP: dict[str, str] = {
"3do": "3do",
"64dd": "nintendo-64dd",
"acpc": "amstrad-cpc",
"amiga": "commodore-amiga",
"arcade": "arcade",
"atari-st": "atari-st",
"atari5200": "atari-5200",
"atari7800": "atari-7800",
"atari8bit": "atari-400-800",
"colecovision": "coleco-colecovision",
"dc": "sega-dreamcast",
"doom": "doom",
"enterprise": "enterprise-64-128",
"fairchild-channel-f": "fairchild-channel-f",
"fds": "nintendo-fds",
"gamegear": "sega-game-gear",
"gb": "nintendo-gb",
"gba": "nintendo-gba",
"gbc": "nintendo-gbc",
"genesis": "sega-mega-drive",
"intellivision": "mattel-intellivision",
"j2me": "j2me",
"lynx": "atari-lynx",
"mac": "apple-macintosh-ii",
"msx": "microsoft-msx",
"msx2": "microsoft-msx",
"nds": "nintendo-ds",
"neo-geo-cd": "snk-neogeo-cd",
"nes": "nintendo-nes",
"ngc": "nintendo-gamecube",
"odyssey-2-slash-videopac-g7000": "magnavox-odyssey2",
"pc-9800-series": "nec-pc-98",
"pc-fx": "nec-pc-fx",
"pokemon-mini": "nintendo-pokemon-mini",
"ps2": "sony-playstation-2",
"psp": "sony-psp",
"psx": "sony-playstation",
"satellaview": "nintendo-satellaview",
"saturn": "sega-saturn",
"scummvm": "scummvm",
"segacd": "sega-mega-cd",
"sharp-x68000": "sharp-x68000",
"sms": "sega-master-system",
"snes": "nintendo-snes",
"sufami-turbo": "nintendo-sufami-turbo",
"super-gb": "nintendo-sgb",
"tg16": "nec-pc-engine",
"tvc": "videoton-tvc",
"videopac-g7400": "philips-videopac",
"wolfenstein": "wolfenstein-3d",
"x1": "sharp-x1",
"xbox": "microsoft-xbox",
"zxs": "sinclair-zx-spectrum",
}
class Scraper(BaseScraper):
"""Scraper for RomM known_bios_files.json."""
def __init__(self, url: str = SOURCE_URL):
super().__init__(url=url)
self._parsed: dict | None = None
def _parse_json(self) -> dict:
if self._parsed is not None:
return self._parsed
raw = self._fetch_raw()
try:
self._parsed = json.loads(raw)
except json.JSONDecodeError as e:
raise ValueError(f"Failed to parse JSON: {e}") from e
return self._parsed
def fetch_requirements(self) -> list[BiosRequirement]:
"""Parse known_bios_files.json and return BIOS requirements."""
raw = self._fetch_raw()
if not self.validate_format(raw):
raise ValueError("known_bios_files.json format validation failed")
data = self._parse_json()
requirements = []
for key, entry in data.items():
if ":" not in key:
continue
igdb_slug, filename = key.split(":", 1)
system = SLUG_MAP.get(igdb_slug)
if not system:
print(f"Warning: unmapped IGDB slug '{igdb_slug}'", file=sys.stderr)
continue
sha1 = (entry.get("sha1") or "").strip() or None
md5 = (entry.get("md5") or "").strip() or None
crc32 = (entry.get("crc") or "").strip() or None
size = int(entry["size"]) if entry.get("size") else None
requirements.append(BiosRequirement(
name=filename,
system=system,
sha1=sha1,
md5=md5,
crc32=crc32,
size=size,
destination=f"{igdb_slug}/{filename}",
required=True,
))
return requirements
def validate_format(self, raw_data: str) -> bool:
"""Validate that raw_data is a JSON dict with slug:filename keys."""
try:
data = json.loads(raw_data)
except (json.JSONDecodeError, TypeError):
return False
if not isinstance(data, dict):
return False
for key in list(data.keys())[:5]:
if ":" not in key:
return False
_, entry = key.split(":", 1), data[key]
if not isinstance(data[key], dict):
return False
if "md5" not in data[key] and "sha1" not in data[key]:
return False
return len(data) > 0
def generate_platform_yaml(self) -> dict:
"""Generate a platform YAML config dict from scraped data."""
requirements = self.fetch_requirements()
systems: dict[str, dict] = {}
for req in requirements:
if req.system not in systems:
systems[req.system] = {"files": []}
entry: dict = {
"name": req.name,
"destination": req.destination,
"required": req.required,
}
if req.sha1:
entry["sha1"] = req.sha1
if req.md5:
entry["md5"] = req.md5
if req.crc32:
entry["crc32"] = req.crc32
if req.size:
entry["size"] = req.size
systems[req.system]["files"].append(entry)
version = ""
tag = fetch_github_latest_version(GITHUB_REPO)
if tag:
version = tag
return {
"inherits": "emulatorjs",
"platform": "RomM",
"version": version,
"homepage": "https://romm.app",
"source": SOURCE_URL,
"base_destination": "bios",
"hash_type": "sha1",
"verification_mode": "md5",
"systems": systems,
}
def main():
from scripts.scraper.base_scraper import scraper_cli
scraper_cli(Scraper, "Scrape RomM BIOS requirements")
if __name__ == "__main__":
main()
+3 -4
View File
@@ -25,7 +25,7 @@ import sys
from pathlib import Path
sys.path.insert(0, os.path.dirname(__file__))
from common import compute_hashes, load_database as _load_database
from common import compute_hashes, list_registered_platforms, load_database as _load_database
try:
import yaml
@@ -107,9 +107,8 @@ def load_platform_hashes(platforms_dir: str) -> dict:
if not os.path.isdir(platforms_dir) or yaml is None:
return known
for f in Path(platforms_dir).glob("*.yml"):
if f.name.startswith("_"):
continue
for name in list_registered_platforms(platforms_dir, include_archived=True):
f = Path(platforms_dir) / f"{name}.yml"
with open(f) as fh:
try:
config = yaml.safe_load(fh) or {}
+51 -6
View File
@@ -80,12 +80,14 @@ def verify_entry_existence(
required = file_entry.get("required", True)
if not local_path:
return {"name": name, "status": Status.MISSING, "required": required}
result = {"name": name, "status": Status.OK, "required": required}
if validation_index:
reason = check_file_validation(local_path, name, validation_index)
if reason:
return {"name": name, "status": Status.UNTESTED, "required": required,
"path": local_path, "reason": reason}
return {"name": name, "status": Status.OK, "required": required}
ventry = validation_index.get(name, {})
emus = ", ".join(ventry.get("emulators", []))
result["discrepancy"] = f"file present (OK) but {emus} says {reason}"
return result
def verify_entry_md5(
@@ -318,6 +320,34 @@ def find_exclusion_notes(
# Platform verification
# ---------------------------------------------------------------------------
def _find_best_variant(
file_entry: dict, db: dict, current_path: str,
validation_index: dict,
) -> str | None:
"""Search for a repo file that passes both platform MD5 and emulator validation."""
fname = file_entry.get("name", "")
if not fname or fname not in validation_index:
return None
md5_expected = file_entry.get("md5", "")
md5_set = {m.strip().lower() for m in md5_expected.split(",") if m.strip()} if md5_expected else set()
by_name = db.get("indexes", {}).get("by_name", {})
files_db = db.get("files", {})
for sha1 in by_name.get(fname, []):
candidate = files_db.get(sha1, {})
path = candidate.get("path", "")
if not path or not os.path.exists(path) or os.path.realpath(path) == os.path.realpath(current_path):
continue
if md5_set and candidate.get("md5", "").lower() not in md5_set:
continue
reason = check_file_validation(path, fname, validation_index)
if reason is None:
return path
return None
def verify_platform(
config: dict, db: dict,
emulators_dir: str = DEFAULT_EMULATORS_DIR,
@@ -361,13 +391,20 @@ def verify_platform(
)
else:
result = verify_entry_md5(file_entry, local_path, resolve_status)
# Apply emulator-level validation on top of MD5 check
# Emulator-level validation: informational for platform packs.
# Platform verification (MD5) is the authority. Emulator
# mismatches are reported as discrepancies, not failures.
if result["status"] == Status.OK and local_path and validation_index:
fname = file_entry.get("name", "")
reason = check_file_validation(local_path, fname, validation_index)
if reason:
result["status"] = Status.UNTESTED
result["reason"] = reason
better = _find_best_variant(
file_entry, db, local_path, validation_index,
)
if not better:
ventry = validation_index.get(fname, {})
emus = ", ".join(ventry.get("emulators", []))
result["discrepancy"] = f"{platform} says OK but {emus} says {reason}"
result["system"] = sys_id
result["hle_fallback"] = hle_index.get(file_entry.get("name", ""), False)
details.append(result)
@@ -470,6 +507,14 @@ def print_platform_result(result: dict, group: list[str]) -> None:
req = "required" if d.get("required", True) else "optional"
hle = ", HLE available" if d.get("hle_fallback") else ""
print(f" MISSING ({req}{hle}): {key}")
for d in result["details"]:
disc = d.get("discrepancy")
if disc:
key = f"{d['system']}/{d['name']}"
if key in seen_details:
continue
seen_details.add(key)
print(f" DISCREPANCY: {key}{disc}")
# Cross-reference: undeclared files used by cores
undeclared = result.get("undeclared_files", [])
+4 -4
View File
@@ -763,15 +763,15 @@ class TestE2E(unittest.TestCase):
self.assertIn("crc32 mismatch", reason)
def test_75_validation_applied_in_existence_mode(self):
"""Existence platform downgrades OK to UNTESTED when validation fails."""
"""Existence mode reports discrepancy when validation fails, keeps OK."""
config = load_platform_config("test_existence", self.platforms_dir)
profiles = load_emulator_profiles(self.emulators_dir)
result = verify_platform(config, self.db, self.emulators_dir, profiles)
# present_opt.bin exists but has wrong expected size → UNTESTED
# present_opt.bin exists but has wrong expected size - OK with discrepancy
for d in result["details"]:
if d["name"] == "present_opt.bin":
self.assertEqual(d["status"], Status.UNTESTED)
self.assertIn("size mismatch", d.get("reason", ""))
self.assertEqual(d["status"], Status.OK)
self.assertIn("size mismatch", d.get("discrepancy", ""))
break
else:
self.fail("present_opt.bin not found in details")
+2
View File
@@ -43,6 +43,8 @@ Verification modes per platform:
| Batocera, RetroBat | md5 | MD5 hash match |
| Recalbox | md5 | MD5 multi-hash, 3 severity levels |
| EmuDeck | md5 | MD5 whitelist per system |
| RetroDECK | md5 | MD5 per file via component manifests |
| RomM | md5 | size + any hash (MD5/SHA1/CRC32) |
### generate_pack.py