mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-04-13 12:22:33 -05:00
Compare commits
12 Commits
daa396618d
...
8f29e0e85c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f29e0e85c | ||
|
|
f39b11955f | ||
|
|
83ccf17b11 | ||
|
|
56bff1d013 | ||
|
|
3bd9c0ebef | ||
|
|
3824193a11 | ||
|
|
2e21d64a08 | ||
|
|
0c5cde83e1 | ||
|
|
a08c730805 | ||
|
|
84decad08d | ||
|
|
f3de3ead20 | ||
|
|
463fca7e7d |
12
README.md
12
README.md
@@ -2,7 +2,7 @@
|
||||
|
||||
Complete BIOS and firmware packs for Batocera, BizHawk, EmuDeck, Lakka, Recalbox, RetroArch, RetroBat, RetroDECK, RetroPie, and RomM.
|
||||
|
||||
**7,245** verified files across **355** systems, ready to extract into your emulator's BIOS directory.
|
||||
**7,244** verified files across **387** systems, ready to extract into your emulator's BIOS directory.
|
||||
|
||||
## Quick Install
|
||||
|
||||
@@ -45,13 +45,13 @@ 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)
|
||||
- **355 systems** covered (NES, SNES, PlayStation, Saturn, Dreamcast, ...)
|
||||
- **7,245 files** verified with MD5, SHA1, CRC32 checksums
|
||||
- **387 systems** covered (NES, SNES, PlayStation, Saturn, Dreamcast, ...)
|
||||
- **7,244 files** verified with MD5, SHA1, CRC32 checksums
|
||||
- **9266 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 321+ more.
|
||||
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 353+ more.
|
||||
|
||||
Full list with per-file details: **[https://abdess.github.io/retrobios/](https://abdess.github.io/retrobios/)**
|
||||
|
||||
@@ -66,7 +66,7 @@ Full list with per-file details: **[https://abdess.github.io/retrobios/](https:/
|
||||
| Recalbox | 276/346 (79.8%) | 273 | 3 | 70 |
|
||||
| RetroArch | 443/448 (98.9%) | 443 | 0 | 5 |
|
||||
| RetroBat | 330/331 (99.7%) | 326 | 4 | 1 |
|
||||
| RetroDECK | 1958/2007 (97.6%) | 1876 | 82 | 49 |
|
||||
| RetroDECK | 1958/2007 (97.6%) | 1932 | 26 | 49 |
|
||||
| RetroPie | 443/448 (98.9%) | 443 | 0 | 5 |
|
||||
| RomM | 372/374 (99.5%) | 372 | 0 | 2 |
|
||||
|
||||
@@ -130,4 +130,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
||||
|
||||
This repository provides BIOS files for personal backup and archival purposes.
|
||||
|
||||
*Auto-generated on 2026-03-29T14:04:16Z*
|
||||
*Auto-generated on 2026-03-29T21:00:40Z*
|
||||
|
||||
BIN
bios/Atari/400-800/ROM_OS_B_NTSC
Normal file
BIN
bios/Atari/400-800/ROM_OS_B_NTSC
Normal file
Binary file not shown.
BIN
bios/Microsoft/MSX/share/systemroms/fs-5500_disk.rom
Normal file
BIN
bios/Microsoft/MSX/share/systemroms/fs-5500_disk.rom
Normal file
Binary file not shown.
582
database.json
582
database.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"generated_at": "2026-03-29T14:00:48Z",
|
||||
"total_files": 7245,
|
||||
"total_size": 9715681216,
|
||||
"generated_at": "2026-03-29T21:32:22Z",
|
||||
"total_files": 7239,
|
||||
"total_size": 8539795099,
|
||||
"files": {
|
||||
"520d3d1b5897800af47f92efd2444a26b7a7dead": {
|
||||
"path": "bios/3DO Company/3DO/3do_arcade_saot.bin",
|
||||
@@ -27064,8 +27064,8 @@
|
||||
"adler32": "9147003d"
|
||||
},
|
||||
"db1031585968cfc6ec2ecda5c9a5a52f61444a3b": {
|
||||
"path": "bios/Atari/400-800/.variants/ATARIOSB.ROM.0e86d61d",
|
||||
"name": "ATARIOSB.ROM",
|
||||
"path": "bios/Atari/400-800/ROM_OS_B_NTSC",
|
||||
"name": "ROM_OS_B_NTSC",
|
||||
"size": 10240,
|
||||
"sha1": "db1031585968cfc6ec2ecda5c9a5a52f61444a3b",
|
||||
"md5": "4177f386a3bac989a981d3fe3388cb6c",
|
||||
@@ -35283,6 +35283,16 @@
|
||||
"crc32": "5bf38e13",
|
||||
"adler32": "240e704d"
|
||||
},
|
||||
"78cd7f847e77fd8cd51a647efb2725ba93f4c471": {
|
||||
"path": "bios/Microsoft/MSX/share/systemroms/fs-5500_disk.rom",
|
||||
"name": "fs-5500_disk.rom",
|
||||
"size": 16384,
|
||||
"sha1": "78cd7f847e77fd8cd51a647efb2725ba93f4c471",
|
||||
"md5": "86269da485e852d9f581ac27f4ba32ff",
|
||||
"sha256": "954e13823e232e745bf527fc5b2d80d6dd55df28593f3d71fc2f4ba6a569ab21",
|
||||
"crc32": "1e7d6512",
|
||||
"adler32": "550f3e4c"
|
||||
},
|
||||
"3a9a942ed888dd641cddf8deada1879c454df3c6": {
|
||||
"path": "bios/Microsoft/MSX/share/systemroms/fs-5500_kanjibasic.rom",
|
||||
"name": "fs-5500_kanjibasic.rom",
|
||||
@@ -36133,16 +36143,6 @@
|
||||
"crc32": "c1815325",
|
||||
"adler32": "c48a690f"
|
||||
},
|
||||
"da39a3ee5e6b4b0d3255bfef95601890afd80709": {
|
||||
"path": "bios/NEC/PC-98/key.txt",
|
||||
"name": "key.txt",
|
||||
"size": 0,
|
||||
"sha1": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
|
||||
"md5": "d41d8cd98f00b204e9800998ecf8427e",
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"crc32": "00000000",
|
||||
"adler32": "00000001"
|
||||
},
|
||||
"3518193b8207bdebf22c1380c2db8c554baff329": {
|
||||
"path": "bios/NEC/PC-98/n88.rom",
|
||||
"name": "n88.rom",
|
||||
@@ -72392,66 +72392,6 @@
|
||||
"sha256": "7dc407fbccbf684dc677bed81120f45f0d3406ff7945eaf207a5c38b036c30e0",
|
||||
"crc32": "a42ef0fd",
|
||||
"adler32": "0d15827f"
|
||||
},
|
||||
"ac4b78d53c7a97da2451ca35498395d8dd1e3024": {
|
||||
"path": ".cache/large/Firmware.19.0.0.zip",
|
||||
"name": "Firmware.19.0.0.zip",
|
||||
"size": 338076508,
|
||||
"sha1": "ac4b78d53c7a97da2451ca35498395d8dd1e3024",
|
||||
"md5": "72d6c73306c7f0b76723f989e7e1bdd1",
|
||||
"sha256": "2f3791655e6c1b56f07a309b69ce8ea35d8412695599bbb6d4b0e29d1b044b66",
|
||||
"crc32": "77228c84",
|
||||
"adler32": "471a3291"
|
||||
},
|
||||
"add40c002084e8e25768671877b2aa603aaf5cb1": {
|
||||
"path": ".cache/large/maclc3.zip",
|
||||
"name": "maclc3.zip",
|
||||
"size": 189428461,
|
||||
"sha1": "add40c002084e8e25768671877b2aa603aaf5cb1",
|
||||
"md5": "aff722788800df5b22d5a07cf8e558ee",
|
||||
"sha256": "e663e456e88f475b3cacc06e75f50605e700789aa327b6648c627a560762a5d6",
|
||||
"crc32": "81f21918",
|
||||
"adler32": "dbd42440"
|
||||
},
|
||||
"b48f44194fe918aaaec5298861479512b581d661": {
|
||||
"path": ".cache/large/dsi_nand.bin",
|
||||
"name": "dsi_nand.bin",
|
||||
"size": 251658304,
|
||||
"sha1": "b48f44194fe918aaaec5298861479512b581d661",
|
||||
"md5": "dfafb1908da8f527df7a372e649b50be",
|
||||
"sha256": "f57d9bf00529bec35d58404faff029a193fd2ccda0a83403ec4e6cc32626721b",
|
||||
"crc32": "416bf51a",
|
||||
"adler32": "3b3e7d56"
|
||||
},
|
||||
"093f8698b54b78dcb701de2043f82639de51d63b": {
|
||||
"path": ".cache/large/PS3UPDAT.PUP",
|
||||
"name": "PS3UPDAT.PUP",
|
||||
"size": 206126236,
|
||||
"sha1": "093f8698b54b78dcb701de2043f82639de51d63b",
|
||||
"md5": "05fe32f5dc8c78acbcd84d36ee7fdc5b",
|
||||
"sha256": "69070a95780f59fc9e0d82bcf53eb9b28fd4ed4a7d54d0a40045f80422fd98d6",
|
||||
"crc32": "24bdb2db",
|
||||
"adler32": "1ec0b1c3"
|
||||
},
|
||||
"ed3a4cb264fff283209f10ae58c96c6090fed187": {
|
||||
"path": ".cache/large/PSP2UPDAT.PUP",
|
||||
"name": "PSP2UPDAT.PUP",
|
||||
"size": 56778752,
|
||||
"sha1": "ed3a4cb264fff283209f10ae58c96c6090fed187",
|
||||
"md5": "59dcf059d3328fb67be7e51f8aa33418",
|
||||
"sha256": "c3c03fc7363dd573d90e5157629bf11551f434b283cc898d9ffc71dd716b791c",
|
||||
"crc32": "082ecf86",
|
||||
"adler32": "620a2ff1"
|
||||
},
|
||||
"cc72dfcc964577cc29112ef368c28f55277c237c": {
|
||||
"path": ".cache/large/PSVUPDAT.PUP",
|
||||
"name": "PSVUPDAT.PUP",
|
||||
"size": 133834240,
|
||||
"sha1": "cc72dfcc964577cc29112ef368c28f55277c237c",
|
||||
"md5": "f2c7b12fe85496ec88a0391b514d6e3b",
|
||||
"sha256": "6ef6dc8da6db026f28647713e473486d770087a605c52a8d751bfca7478386cf",
|
||||
"crc32": "39075d41",
|
||||
"adler32": "75d71010"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
@@ -75984,6 +75924,7 @@
|
||||
"f873f1260b14f1468fa118778ae1c3d2": "c7a2c5baee6a9f0e1c6ee7d76944c0ab1886796c",
|
||||
"318b6aa76da71c54ccad7734356e1902": "f1525de4e0b60a6687156c2a96f8a8b2044b6c56",
|
||||
"5bf4fdfd3c3ffea3e573b386550cb3fa": "44e0dd215b2a9f0770dd76fb49187c05b083eed9",
|
||||
"86269da485e852d9f581ac27f4ba32ff": "78cd7f847e77fd8cd51a647efb2725ba93f4c471",
|
||||
"afbe6ba903453902540ae988cc89dc7b": "3a9a942ed888dd641cddf8deada1879c454df3c6",
|
||||
"090539674630c1338a90a1df943a93e2": "9ed3ab6d893632b9246e91b412cd5db519e7586b",
|
||||
"dcd5e2388115172f2fb48875b2089dbf": "4be8371f3b03e70ddaca495958345f3c4f8e2d36",
|
||||
@@ -76069,7 +76010,6 @@
|
||||
"38d32748ae49d1815b0614970849fd40": "78ba9960f135372825ab7244b5e4e73a810002ff",
|
||||
"8b52de9032ea62153dc783151306595f": "0877ffb4b4d1c18283468be3579b72ed8c22e3ac",
|
||||
"72ea51443070f0e9212bfc9b793ee28e": "a2fb11c000ed7c976520622cfb7940ed6ddc904e",
|
||||
"d41d8cd98f00b204e9800998ecf8427e": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
|
||||
"22be239bc0c4298bc0561252eed98633": "3518193b8207bdebf22c1380c2db8c554baff329",
|
||||
"e28fe3f520bea594350ea8fb00395370": "d1ae642aed4f0584eeb81ff50180db694e5101d4",
|
||||
"a8e298da7ac947669bcb1ff25cee0a83": "4ae4d37409ff99411a623da9f6a44192170a854e",
|
||||
@@ -79694,13 +79634,7 @@
|
||||
"a9082f02d4f93c1f6c4e428e06b834e8": "d07114a9f3490338a265fb30d16b052c8da3bb7d",
|
||||
"8d4abc7dd31a64f2ddd811c19ae8c09e": "b3730071e789877bea3373ffa59ca673a4b1f4c9",
|
||||
"6e7e391c629332cc9d29902b98e52f94": "48024e2f5943ed86cb1b8e9443603991cdb05808",
|
||||
"bbd27768c16e6077b1a90dc0eb8558a3": "24a487f22f3da292e179b3edd6c30222a8ff933d",
|
||||
"72d6c73306c7f0b76723f989e7e1bdd1": "ac4b78d53c7a97da2451ca35498395d8dd1e3024",
|
||||
"aff722788800df5b22d5a07cf8e558ee": "add40c002084e8e25768671877b2aa603aaf5cb1",
|
||||
"dfafb1908da8f527df7a372e649b50be": "b48f44194fe918aaaec5298861479512b581d661",
|
||||
"05fe32f5dc8c78acbcd84d36ee7fdc5b": "093f8698b54b78dcb701de2043f82639de51d63b",
|
||||
"59dcf059d3328fb67be7e51f8aa33418": "ed3a4cb264fff283209f10ae58c96c6090fed187",
|
||||
"f2c7b12fe85496ec88a0391b514d6e3b": "cc72dfcc964577cc29112ef368c28f55277c237c"
|
||||
"bbd27768c16e6077b1a90dc0eb8558a3": "24a487f22f3da292e179b3edd6c30222a8ff933d"
|
||||
},
|
||||
"by_name": {
|
||||
"3do_arcade_saot.bin": [
|
||||
@@ -79996,8 +79930,7 @@
|
||||
"1365b42d35d80feac9050caea8d6bd9d374fd1d2"
|
||||
],
|
||||
"maclc3.zip": [
|
||||
"f454095619834dbfb9e8de0111bb3ee5fc21622d",
|
||||
"add40c002084e8e25768671877b2aa603aaf5cb1"
|
||||
"f454095619834dbfb9e8de0111bb3ee5fc21622d"
|
||||
],
|
||||
"macos3.img": [
|
||||
"0546dd0fa34f4e6d913e4254ddb5350e1e42800c"
|
||||
@@ -87355,9 +87288,8 @@
|
||||
"1540OS3.V0": [
|
||||
"454fdd9005c43142f827e1e506bf75fda0fe2a65"
|
||||
],
|
||||
"ATARIOSB.ROM": [
|
||||
"db1031585968cfc6ec2ecda5c9a5a52f61444a3b",
|
||||
"f1f0741b1d34fb4350cf7cb8ab3b6ea11cdd8174"
|
||||
"ROM_OS_B_NTSC": [
|
||||
"db1031585968cfc6ec2ecda5c9a5a52f61444a3b"
|
||||
],
|
||||
"ATARIBAS.ROM": [
|
||||
"3693c9cb9bf3b41bae1150f7a8264992468fc8c0"
|
||||
@@ -87365,6 +87297,10 @@
|
||||
"ATARIOSA.ROM": [
|
||||
"6dd53356159a129ed12367beb3b24a771d41adb0"
|
||||
],
|
||||
"ATARIOSB.ROM": [
|
||||
"f1f0741b1d34fb4350cf7cb8ab3b6ea11cdd8174",
|
||||
"db1031585968cfc6ec2ecda5c9a5a52f61444a3b"
|
||||
],
|
||||
"ATARIXL.ROM": [
|
||||
"ae4f523ba08b6fd59f3cae515a2b2410bbd98f55"
|
||||
],
|
||||
@@ -89768,6 +89704,9 @@
|
||||
"fs-5500_basic-bios2.rom": [
|
||||
"44e0dd215b2a9f0770dd76fb49187c05b083eed9"
|
||||
],
|
||||
"fs-5500_disk.rom": [
|
||||
"78cd7f847e77fd8cd51a647efb2725ba93f4c471"
|
||||
],
|
||||
"fs-5500_kanjibasic.rom": [
|
||||
"3a9a942ed888dd641cddf8deada1879c454df3c6"
|
||||
],
|
||||
@@ -89999,9 +89938,6 @@
|
||||
"ide.rom": [
|
||||
"0877ffb4b4d1c18283468be3579b72ed8c22e3ac"
|
||||
],
|
||||
"key.txt": [
|
||||
"da39a3ee5e6b4b0d3255bfef95601890afd80709"
|
||||
],
|
||||
"n88_1.rom": [
|
||||
"4ae4d37409ff99411a623da9f6a44192170a854e"
|
||||
],
|
||||
@@ -99572,8 +99508,7 @@
|
||||
"41d8c5c89f72206b873633ff31bcf4f82608e5a4"
|
||||
],
|
||||
"PSP2UPDAT.PUP": [
|
||||
"3ae832c9800fcaa007eccfc48f24242967c111f8",
|
||||
"ed3a4cb264fff283209f10ae58c96c6090fed187"
|
||||
"3ae832c9800fcaa007eccfc48f24242967c111f8"
|
||||
],
|
||||
"coco.zip": [
|
||||
"567c5b5054552a2771eafa7966844a146f0dde96",
|
||||
@@ -99850,18 +99785,6 @@
|
||||
"Tortuga.dat": [
|
||||
"24a487f22f3da292e179b3edd6c30222a8ff933d"
|
||||
],
|
||||
"Firmware.19.0.0.zip": [
|
||||
"ac4b78d53c7a97da2451ca35498395d8dd1e3024"
|
||||
],
|
||||
"dsi_nand.bin": [
|
||||
"b48f44194fe918aaaec5298861479512b581d661"
|
||||
],
|
||||
"PS3UPDAT.PUP": [
|
||||
"093f8698b54b78dcb701de2043f82639de51d63b"
|
||||
],
|
||||
"PSVUPDAT.PUP": [
|
||||
"cc72dfcc964577cc29112ef368c28f55277c237c"
|
||||
],
|
||||
"goldstar_fc1_enc.bin": [
|
||||
"8ef7503c948314d242da47b7fdc272f68dac2aee"
|
||||
],
|
||||
@@ -100070,40 +99993,94 @@
|
||||
"2ae988416d74273b0213e0be6513eabc3d974d49"
|
||||
],
|
||||
"c64_geocable.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c",
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"cgenie_printer.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c",
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"dmv_k210.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c",
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"fdc37c93x.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c",
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"isa_lpt.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c",
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"pc_lpt.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c",
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"pofo_hpc101.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c",
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"sv802.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c",
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"vtech_printer.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c",
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"82c606.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"bk_ay.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"bk_covox.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"bk_printer.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"cocopakram.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"distomeb_rtime.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"electron_fbprint.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"fdc37c665gt.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"fdc37m707.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"isa_bblue2.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"it8703f_device.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"it8705f.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"pc87306.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"pc97338.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"psion_parallel.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"psion_3link_par.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"spectrum_kempcentrs.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"upc82c710.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"upc82c711.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"w83977tf.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"w83787f.zip": [
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c"
|
||||
],
|
||||
"atom_econet.zip": [
|
||||
"2d7d999e2acb4da55c26d1517934d39e7d0a0c86",
|
||||
@@ -100114,16 +100091,22 @@
|
||||
"eb7ff2179f102be63f217466f643bd93b4910f9e"
|
||||
],
|
||||
"c64_music64.zip": [
|
||||
"122dea22f51ad868ca111e045d2ae6d1bec4fc91",
|
||||
"1927797dd8fba39987906d8c90c8b182968783eb"
|
||||
"122dea22f51ad868ca111e045d2ae6d1bec4fc91"
|
||||
],
|
||||
"c64_sfxse.zip": [
|
||||
"122dea22f51ad868ca111e045d2ae6d1bec4fc91",
|
||||
"1927797dd8fba39987906d8c90c8b182968783eb"
|
||||
"122dea22f51ad868ca111e045d2ae6d1bec4fc91"
|
||||
],
|
||||
"c64_supercpu.zip": [
|
||||
"122dea22f51ad868ca111e045d2ae6d1bec4fc91",
|
||||
"1927797dd8fba39987906d8c90c8b182968783eb"
|
||||
"122dea22f51ad868ca111e045d2ae6d1bec4fc91"
|
||||
],
|
||||
"c64_buscard.zip": [
|
||||
"122dea22f51ad868ca111e045d2ae6d1bec4fc91"
|
||||
],
|
||||
"c64_ieee488.zip": [
|
||||
"122dea22f51ad868ca111e045d2ae6d1bec4fc91"
|
||||
],
|
||||
"c64_buscard2.zip": [
|
||||
"122dea22f51ad868ca111e045d2ae6d1bec4fc91"
|
||||
],
|
||||
"c64_swiftlink.zip": [
|
||||
"17409b32b33cd1474b1aa1417dd3467b15589e16",
|
||||
@@ -100282,24 +100265,19 @@
|
||||
"da272af2fb1da8883c539b19c1bda97c5301dc80"
|
||||
],
|
||||
"cpc_mface2.zip": [
|
||||
"d3b68c28975704af68fb2016e1fe611d10177495",
|
||||
"949b9b362e1dc615a2e5783016207ff0d87de465"
|
||||
"d3b68c28975704af68fb2016e1fe611d10177495"
|
||||
],
|
||||
"cpc_playcity.zip": [
|
||||
"d3b68c28975704af68fb2016e1fe611d10177495",
|
||||
"949b9b362e1dc615a2e5783016207ff0d87de465"
|
||||
"d3b68c28975704af68fb2016e1fe611d10177495"
|
||||
],
|
||||
"cpc_ser.zip": [
|
||||
"d3b68c28975704af68fb2016e1fe611d10177495",
|
||||
"949b9b362e1dc615a2e5783016207ff0d87de465"
|
||||
"d3b68c28975704af68fb2016e1fe611d10177495"
|
||||
],
|
||||
"cpc_serams.zip": [
|
||||
"d3b68c28975704af68fb2016e1fe611d10177495",
|
||||
"949b9b362e1dc615a2e5783016207ff0d87de465"
|
||||
"d3b68c28975704af68fb2016e1fe611d10177495"
|
||||
],
|
||||
"cpc_ssa1.zip": [
|
||||
"d3b68c28975704af68fb2016e1fe611d10177495",
|
||||
"949b9b362e1dc615a2e5783016207ff0d87de465"
|
||||
"d3b68c28975704af68fb2016e1fe611d10177495"
|
||||
],
|
||||
"d2fdc.zip": [
|
||||
"af56c948598291b284a528f3fce06b961dba55e3",
|
||||
@@ -100341,16 +100319,20 @@
|
||||
"75de4163ec975c736f71eff860d5d656e2806333"
|
||||
],
|
||||
"pofo_hpc104.zip": [
|
||||
"e92c1797f962812e911c85cbfd7f91169738e9ac",
|
||||
"9f9ab9a092e0936758ad2fb93a537533231468c8"
|
||||
"e92c1797f962812e911c85cbfd7f91169738e9ac"
|
||||
],
|
||||
"pofo_hpc104_2.zip": [
|
||||
"e92c1797f962812e911c85cbfd7f91169738e9ac",
|
||||
"9f9ab9a092e0936758ad2fb93a537533231468c8"
|
||||
"e92c1797f962812e911c85cbfd7f91169738e9ac"
|
||||
],
|
||||
"to7_io_line.zip": [
|
||||
"e92c1797f962812e911c85cbfd7f91169738e9ac"
|
||||
],
|
||||
"psion_serpar.zip": [
|
||||
"e92c1797f962812e911c85cbfd7f91169738e9ac"
|
||||
],
|
||||
"psion_siena_ssd.zip": [
|
||||
"e92c1797f962812e911c85cbfd7f91169738e9ac"
|
||||
],
|
||||
"isa_hdc_ec1841.zip": [
|
||||
"2561d3c19ab5fcf397a46af37cff1097555a7464"
|
||||
],
|
||||
@@ -100378,22 +100360,20 @@
|
||||
],
|
||||
"peribox_genmod.zip": [
|
||||
"827512b74c2d90c34a992036fb974ddd4e9454bd",
|
||||
"e037089e7f53382950a6e8d3939af2cae5d4a7d5"
|
||||
"b58fe2dbbc254d363c2ec4a459e6ec1d91b2ac86"
|
||||
],
|
||||
"peribox_sg.zip": [
|
||||
"0a6aa44fe3d86af0ecbf428b49fd8053e4da8e11",
|
||||
"e037089e7f53382950a6e8d3939af2cae5d4a7d5"
|
||||
"b58fe2dbbc254d363c2ec4a459e6ec1d91b2ac86"
|
||||
],
|
||||
"popn9.zip": [
|
||||
"207e34befb36e945bbbaf9012156b70a1be97819"
|
||||
],
|
||||
"ql_sqboard512.zip": [
|
||||
"ce84f25384217a1280f1fddbf8919967d6ddca14",
|
||||
"7e37e3dae0c4ddff1912bf02fca3fb2019326b78"
|
||||
"ce84f25384217a1280f1fddbf8919967d6ddca14"
|
||||
],
|
||||
"ql_sqmouse512.zip": [
|
||||
"ce84f25384217a1280f1fddbf8919967d6ddca14",
|
||||
"7e37e3dae0c4ddff1912bf02fca3fb2019326b78"
|
||||
"ce84f25384217a1280f1fddbf8919967d6ddca14"
|
||||
],
|
||||
"ql_trump256.zip": [
|
||||
"c34662ee1d51ae0ae2899f923694f1d8024559fa"
|
||||
@@ -100414,16 +100394,88 @@
|
||||
"634008f34b031c0e5d0186936c065e6e20808264"
|
||||
],
|
||||
"spectrum_intf1.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3",
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_melodik.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3",
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_uslot.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3",
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_betacbi.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_betaplus.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_betav3.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_betav2.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_beta128.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_betaclone.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_disciple.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_gamma.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_flpone.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_kempdisc.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_mface1.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_mface128v1.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_mface128.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_mface1v1.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_mface1v2.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_mface1v3.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_lprint3.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_mprint.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_speccydos.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_spdos.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_specmate.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_swiftdisc2.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_vtx5000.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_swiftdisc.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"spectrum_wafa.zip": [
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3"
|
||||
],
|
||||
"sv602.zip": [
|
||||
"befce08c839e414535478e4efd44e1b30dbec598",
|
||||
@@ -100603,6 +100655,12 @@
|
||||
"kvshared.wav": [
|
||||
"9adf10cdf1de833b194c7d8797ad1f041ad98dd3"
|
||||
],
|
||||
"atari_osb.rom": [
|
||||
"db1031585968cfc6ec2ecda5c9a5a52f61444a3b"
|
||||
],
|
||||
"atari_os_b.rom": [
|
||||
"db1031585968cfc6ec2ecda5c9a5a52f61444a3b"
|
||||
],
|
||||
"ROM_BASIC_C": [
|
||||
"3693c9cb9bf3b41bae1150f7a8264992468fc8c0"
|
||||
],
|
||||
@@ -102325,9 +102383,6 @@
|
||||
"custom0.sf2": [
|
||||
"286b2e1fb21cc79851da01666db6c0b0e88f25e3"
|
||||
],
|
||||
"Custom.dat": [
|
||||
"da39a3ee5e6b4b0d3255bfef95601890afd80709"
|
||||
],
|
||||
"tos106de.img": [
|
||||
"3b8cf5ffa41b252eb67f8824f94608fa4005d6dd"
|
||||
],
|
||||
@@ -102532,75 +102587,15 @@
|
||||
"MSX2R2.ROM": [
|
||||
"04990aa1c3a3fc7294ec884b81deaa89832df614"
|
||||
],
|
||||
"NATIONALDISK.rom": [
|
||||
"78cd7f847e77fd8cd51a647efb2725ba93f4c471"
|
||||
],
|
||||
"PHILIPSDISK.rom": [
|
||||
"c3efedda7ab947a06d9345f7b8261076fa7ceeef"
|
||||
],
|
||||
"flash.bin": [
|
||||
"94d44d7f9529ec1642ba3771ed3c5f756d5bc872"
|
||||
],
|
||||
"82c606.zip": [
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
],
|
||||
"bk_ay.zip": [
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
],
|
||||
"bk_covox.zip": [
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
],
|
||||
"bk_printer.zip": [
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
],
|
||||
"cocopakram.zip": [
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
],
|
||||
"distomeb_rtime.zip": [
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
],
|
||||
"electron_fbprint.zip": [
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
],
|
||||
"fdc37c665gt.zip": [
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
],
|
||||
"fdc37m707.zip": [
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
],
|
||||
"isa_bblue2.zip": [
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
],
|
||||
"it8703f_device.zip": [
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
],
|
||||
"it8705f.zip": [
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
],
|
||||
"pc87306.zip": [
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
],
|
||||
"pc97338.zip": [
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
],
|
||||
"psion_parallel.zip": [
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
],
|
||||
"psion_3link_par.zip": [
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
],
|
||||
"spectrum_kempcentrs.zip": [
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
],
|
||||
"upc82c710.zip": [
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
],
|
||||
"upc82c711.zip": [
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
],
|
||||
"w83977tf.zip": [
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
],
|
||||
"w83787f.zip": [
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea"
|
||||
],
|
||||
"a2bufgrapplerplusa.zip": [
|
||||
"7c54fb94853478d23ec155a8e38b76d830f52e46"
|
||||
],
|
||||
@@ -102838,15 +102833,6 @@
|
||||
"bbc_usersplit.zip": [
|
||||
"90f1c144839c5269ff8567dd6685ae356027f146"
|
||||
],
|
||||
"c64_buscard.zip": [
|
||||
"1927797dd8fba39987906d8c90c8b182968783eb"
|
||||
],
|
||||
"c64_ieee488.zip": [
|
||||
"1927797dd8fba39987906d8c90c8b182968783eb"
|
||||
],
|
||||
"c64_buscard2.zip": [
|
||||
"1927797dd8fba39987906d8c90c8b182968783eb"
|
||||
],
|
||||
"centronics_chessmec.zip": [
|
||||
"e908b954f3c4b25f59de1e17e51cbd020540c243"
|
||||
],
|
||||
@@ -103034,19 +103020,13 @@
|
||||
"eaabc1ef9448c297ef7cbae90278b265acd48169"
|
||||
],
|
||||
"peribox_ev1.zip": [
|
||||
"e037089e7f53382950a6e8d3939af2cae5d4a7d5"
|
||||
"b58fe2dbbc254d363c2ec4a459e6ec1d91b2ac86"
|
||||
],
|
||||
"ti99_iosplit.zip": [
|
||||
"e037089e7f53382950a6e8d3939af2cae5d4a7d5"
|
||||
"b58fe2dbbc254d363c2ec4a459e6ec1d91b2ac86"
|
||||
],
|
||||
"ti99_speechconn.zip": [
|
||||
"e037089e7f53382950a6e8d3939af2cae5d4a7d5"
|
||||
],
|
||||
"psion_serpar.zip": [
|
||||
"9f9ab9a092e0936758ad2fb93a537533231468c8"
|
||||
],
|
||||
"psion_siena_ssd.zip": [
|
||||
"9f9ab9a092e0936758ad2fb93a537533231468c8"
|
||||
"b58fe2dbbc254d363c2ec4a459e6ec1d91b2ac86"
|
||||
],
|
||||
"profighterqb.zip": [
|
||||
"631ccd946400978b10ee225e008eed199027fd8c"
|
||||
@@ -103075,81 +103055,6 @@
|
||||
"sis85c496_host.zip": [
|
||||
"7d3363b91d27ac3ff9fb91aee36d798a5331e2be"
|
||||
],
|
||||
"spectrum_betacbi.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_betaplus.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_betav3.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_betav2.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_beta128.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_betaclone.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_disciple.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_gamma.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_flpone.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_kempdisc.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_mface1.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_mface128v1.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_mface128.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_mface1v1.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_mface1v2.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_mface1v3.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_lprint3.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_mprint.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_speccydos.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_spdos.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_specmate.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_swiftdisc2.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_vtx5000.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_swiftdisc.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_wafa.zip": [
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19"
|
||||
],
|
||||
"spectrum_d80.zip": [
|
||||
"28fce4b27babe26a6bf5d139df489302764c5ad4"
|
||||
],
|
||||
@@ -103373,6 +103278,9 @@
|
||||
"MCX_Basic_21_AZERTY": [
|
||||
"c8fd92705fc42deb6a0ffac6274e27fd61ecd4cc"
|
||||
],
|
||||
"OPENBIOS.bin": [
|
||||
"389df7981873d9e6e46c84c20cd43af0e4226cf8"
|
||||
],
|
||||
"N88_0.ROM": [
|
||||
"d1ae642aed4f0584eeb81ff50180db694e5101d4"
|
||||
],
|
||||
@@ -103433,12 +103341,6 @@
|
||||
"EXDOS14.ROM": [
|
||||
"cb43ab3676b93c279f1ed8ffcb0d4dcd4b34e631"
|
||||
],
|
||||
"atari_osb.rom": [
|
||||
"db1031585968cfc6ec2ecda5c9a5a52f61444a3b"
|
||||
],
|
||||
"atari_os_b.rom": [
|
||||
"db1031585968cfc6ec2ecda5c9a5a52f61444a3b"
|
||||
],
|
||||
"FONT.BMP": [
|
||||
"b4f14e58030ed40fff2dc312b58ea4440bdf8cc5"
|
||||
],
|
||||
@@ -107023,6 +106925,7 @@
|
||||
"5ad03407": "c7a2c5baee6a9f0e1c6ee7d76944c0ab1886796c",
|
||||
"549f1d90": "f1525de4e0b60a6687156c2a96f8a8b2044b6c56",
|
||||
"5bf38e13": "44e0dd215b2a9f0770dd76fb49187c05b083eed9",
|
||||
"1e7d6512": "78cd7f847e77fd8cd51a647efb2725ba93f4c471",
|
||||
"b2db6bf5": "3a9a942ed888dd641cddf8deada1879c454df3c6",
|
||||
"956dc96d": "9ed3ab6d893632b9246e91b412cd5db519e7586b",
|
||||
"3c42c367": "4be8371f3b03e70ddaca495958345f3c4f8e2d36",
|
||||
@@ -107108,7 +107011,6 @@
|
||||
"456d9fc7": "78ba9960f135372825ab7244b5e4e73a810002ff",
|
||||
"d402842f": "0877ffb4b4d1c18283468be3579b72ed8c22e3ac",
|
||||
"c1815325": "a2fb11c000ed7c976520622cfb7940ed6ddc904e",
|
||||
"00000000": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
|
||||
"ffd68be0": "3518193b8207bdebf22c1380c2db8c554baff329",
|
||||
"61984bab": "d1ae642aed4f0584eeb81ff50180db694e5101d4",
|
||||
"7ad5d943": "4ae4d37409ff99411a623da9f6a44192170a854e",
|
||||
@@ -110733,13 +110635,7 @@
|
||||
"4a39a474": "d07114a9f3490338a265fb30d16b052c8da3bb7d",
|
||||
"bf1e4b9b": "b3730071e789877bea3373ffa59ca673a4b1f4c9",
|
||||
"e6b9ebfb": "48024e2f5943ed86cb1b8e9443603991cdb05808",
|
||||
"a42ef0fd": "24a487f22f3da292e179b3edd6c30222a8ff933d",
|
||||
"77228c84": "ac4b78d53c7a97da2451ca35498395d8dd1e3024",
|
||||
"81f21918": "add40c002084e8e25768671877b2aa603aaf5cb1",
|
||||
"416bf51a": "b48f44194fe918aaaec5298861479512b581d661",
|
||||
"24bdb2db": "093f8698b54b78dcb701de2043f82639de51d63b",
|
||||
"082ecf86": "ed3a4cb264fff283209f10ae58c96c6090fed187",
|
||||
"39075d41": "cc72dfcc964577cc29112ef368c28f55277c237c"
|
||||
"a42ef0fd": "24a487f22f3da292e179b3edd6c30222a8ff933d"
|
||||
},
|
||||
"by_path_suffix": {
|
||||
".variants/aa310.zip": [
|
||||
@@ -113916,9 +113812,6 @@
|
||||
".variants/1540OS3.V0": [
|
||||
"454fdd9005c43142f827e1e506bf75fda0fe2a65"
|
||||
],
|
||||
".variants/ATARIOSB.ROM.0e86d61d": [
|
||||
"db1031585968cfc6ec2ecda5c9a5a52f61444a3b"
|
||||
],
|
||||
"hatari/BOOT.ST": [
|
||||
"5bcabba35bb8fbfe5a65b85efccf5ed657388308"
|
||||
],
|
||||
@@ -115347,6 +115240,9 @@
|
||||
"share/systemroms/fs-5500_basic-bios2.rom": [
|
||||
"44e0dd215b2a9f0770dd76fb49187c05b083eed9"
|
||||
],
|
||||
"share/systemroms/fs-5500_disk.rom": [
|
||||
"78cd7f847e77fd8cd51a647efb2725ba93f4c471"
|
||||
],
|
||||
"share/systemroms/fs-5500_kanjibasic.rom": [
|
||||
"3a9a942ed888dd641cddf8deada1879c454df3c6"
|
||||
],
|
||||
@@ -124358,20 +124254,26 @@
|
||||
"e35eda0cc2c11da92c0a6c222f314d84e623b29e",
|
||||
"9ecb4cae3fe19cd3faef4a22fe5d3a189ac8810c",
|
||||
"3a5718ea19c8e4c900a77bfd6bee701597feaa56",
|
||||
"bbf1cb3e776129524d54d1f885c54d0f1b8d489c",
|
||||
"122dea22f51ad868ca111e045d2ae6d1bec4fc91",
|
||||
"17409b32b33cd1474b1aa1417dd3467b15589e16",
|
||||
"9ae8707d814dc197315fb1d49571209e48ab29f3",
|
||||
"893deaeff7ac79fbde19817678b63905d9f9b9cb",
|
||||
"da272af2fb1da8883c539b19c1bda97c5301dc80",
|
||||
"d3b68c28975704af68fb2016e1fe611d10177495",
|
||||
"af56c948598291b284a528f3fce06b961dba55e3",
|
||||
"d375f64dc02703eee6751bd9723978c6633348c9",
|
||||
"eda0107f44a9a5b15471aea99e847701f4899a96",
|
||||
"e92c1797f962812e911c85cbfd7f91169738e9ac",
|
||||
"87ecc7a33627b1fac62ffb87e79a5aa36fe746cf",
|
||||
"4fc37b52d4313ff57f5557c2c3191e885b0e3fcb",
|
||||
"4d217c4a72a4450b75faaf7da871e8fe7b64ff60",
|
||||
"ce84f25384217a1280f1fddbf8919967d6ddca14",
|
||||
"c34662ee1d51ae0ae2899f923694f1d8024559fa",
|
||||
"a0e6f65f2eca69c22c8d405af11c5d9c262efa1d",
|
||||
"b06ad209ef30db63711cc5bc46a5371465223ed0",
|
||||
"634008f34b031c0e5d0186936c065e6e20808264",
|
||||
"0cb430aea9354d8c151933a12c33fa2bb69c16d3",
|
||||
"9139c00e5986b7a86c7e8dcbce39986126ab7db4",
|
||||
"14a5ff2c8ca68d35a77ebfbc227ed9c8e19d7524",
|
||||
"c4d0f820dbfa135db40ce94c2253cae7814cf2f2",
|
||||
@@ -124399,6 +124301,7 @@
|
||||
"dc594fea200ce87d1bd33a4a1e73f0221b68b9eb",
|
||||
"afcc9c605420a2029b66e97e9f719f15ebb53d64",
|
||||
"82aeaace3231022fc158e96c9042745f6482aa93",
|
||||
"db1031585968cfc6ec2ecda5c9a5a52f61444a3b",
|
||||
"3693c9cb9bf3b41bae1150f7a8264992468fc8c0",
|
||||
"d9d134bb6b36907c615a594cc7688f7bfcef5b43",
|
||||
"5a140136a16d1d83e4ff32a19409ca376a8df874",
|
||||
@@ -124635,10 +124538,10 @@
|
||||
"e90f80a61d94c617850c415e12ad70ac41e66bb7",
|
||||
"df48902f5f12af8867ae1a87f255145f0e5e0774",
|
||||
"04990aa1c3a3fc7294ec884b81deaa89832df614",
|
||||
"78cd7f847e77fd8cd51a647efb2725ba93f4c471",
|
||||
"c3efedda7ab947a06d9345f7b8261076fa7ceeef",
|
||||
"94d44d7f9529ec1642ba3771ed3c5f756d5bc872",
|
||||
"f119506eaa3b4b70b9aa0dd83761e8cbe043d042",
|
||||
"b22847ad1d8c5ee0fff41b3bd31aab6cbf8778ea",
|
||||
"7c54fb94853478d23ec155a8e38b76d830f52e46",
|
||||
"1a1826d7962e6bf6b94fc1bc2b17b8633eaaa0f5",
|
||||
"270c84df833b196e214738bbe158f4ea2203c272",
|
||||
@@ -124653,12 +124556,10 @@
|
||||
"67b9199bc22c6fe2b3a4725ec291c158edd01151",
|
||||
"b1abcb49eded4fcafa76198b5f7efc65fcc940e6",
|
||||
"90f1c144839c5269ff8567dd6685ae356027f146",
|
||||
"1927797dd8fba39987906d8c90c8b182968783eb",
|
||||
"275b6409633ffaf3c3fa5e191de9aa7294b8cf64",
|
||||
"0013eb127aa3af9dee5a881c590af5ebda0edef5",
|
||||
"e908b954f3c4b25f59de1e17e51cbd020540c243",
|
||||
"2ed5c4f7350701a4eb279f7111e22f12afbf51b4",
|
||||
"949b9b362e1dc615a2e5783016207ff0d87de465",
|
||||
"9d73e22ee590cec56a8a1f0af0735b586f50602f",
|
||||
"e9aee50fcf87177493095237dc2446d67fe57252",
|
||||
"d5a80dd0b4ef0d22b533a3771f374dc446b63e11",
|
||||
@@ -124685,17 +124586,14 @@
|
||||
"18889ed623d8c635966de0947076066f3732d2aa",
|
||||
"06fc753d015b43ca1787f4cfd9331b1674202e64",
|
||||
"eaabc1ef9448c297ef7cbae90278b265acd48169",
|
||||
"e037089e7f53382950a6e8d3939af2cae5d4a7d5",
|
||||
"9f9ab9a092e0936758ad2fb93a537533231468c8",
|
||||
"b58fe2dbbc254d363c2ec4a459e6ec1d91b2ac86",
|
||||
"631ccd946400978b10ee225e008eed199027fd8c",
|
||||
"7e37e3dae0c4ddff1912bf02fca3fb2019326b78",
|
||||
"bf946b98e9314ac877e67af84c82418604f4bade",
|
||||
"bfa36e6517ba0744618e6778581beb85067be171",
|
||||
"134760c0544d633cb475ad58b87f92483826cb2a",
|
||||
"b8b8f5030a64769d27b784aeb5efca94cd72149a",
|
||||
"b32303333a66101a83d008af1a8c1966751ed156",
|
||||
"7d3363b91d27ac3ff9fb91aee36d798a5331e2be",
|
||||
"8aaa6099ccaa133cb8f54846f65348dff3851c19",
|
||||
"28fce4b27babe26a6bf5d139df489302764c5ad4",
|
||||
"d9d692484446ac37e992478d60d9478bfe1fd9a6",
|
||||
"423b488154c36a97a160cae7d43e79089ddee16d",
|
||||
@@ -124749,6 +124647,7 @@
|
||||
"9513091f37adf330f66a0c08f4e200344ad2e082",
|
||||
"36c30d0f198a1bffee88ef29d92f2401447a91f4",
|
||||
"c8fd92705fc42deb6a0ffac6274e27fd61ecd4cc",
|
||||
"389df7981873d9e6e46c84c20cd43af0e4226cf8",
|
||||
"d1ae642aed4f0584eeb81ff50180db694e5101d4",
|
||||
"4ae4d37409ff99411a623da9f6a44192170a854e",
|
||||
"e94278682ef9e9bbb82201f72c50382748dcea2a",
|
||||
@@ -124764,7 +124663,6 @@
|
||||
"05ba161aa8796c04f227eb2d52496943ada814f2",
|
||||
"388e3721b94cd074d6ba0eca8616523d2118a6c3",
|
||||
"cb43ab3676b93c279f1ed8ffcb0d4dcd4b34e631",
|
||||
"db1031585968cfc6ec2ecda5c9a5a52f61444a3b",
|
||||
"b4f14e58030ed40fff2dc312b58ea4440bdf8cc5",
|
||||
"c65592330c9dd84011151daed52f9aec926b7e56",
|
||||
"0877ffb4b4d1c18283468be3579b72ed8c22e3ac",
|
||||
@@ -124791,6 +124689,9 @@
|
||||
"samples/samesame.zip": [
|
||||
"cdb09d3ffaa867ff9e7387cf1934e9011565d546"
|
||||
],
|
||||
".variants/ATARIOSB.ROM.0e86d61d": [
|
||||
"db1031585968cfc6ec2ecda5c9a5a52f61444a3b"
|
||||
],
|
||||
"openmsx/COLECO.ROM": [
|
||||
"45bedc4cbdeac66c7df59e9e599195c778d86a92"
|
||||
],
|
||||
@@ -127206,9 +127107,6 @@
|
||||
"zc210/sf2/custom0.sf2": [
|
||||
"286b2e1fb21cc79851da01666db6c0b0e88f25e3"
|
||||
],
|
||||
"zc210/sfx/Custom.dat": [
|
||||
"da39a3ee5e6b4b0d3255bfef95601890afd80709"
|
||||
],
|
||||
"zc210/zcdata.dat": [
|
||||
"33b50cec88bc1569431a7885c0cc2692fddb004b"
|
||||
]
|
||||
|
||||
@@ -26,6 +26,7 @@ systems:
|
||||
- mega-cd
|
||||
- mega-cd-32x
|
||||
- mega-ld
|
||||
- laseractive
|
||||
- msx
|
||||
- msx2
|
||||
- neo-geo
|
||||
|
||||
@@ -7,7 +7,7 @@ profiled_date: "2026-03-23"
|
||||
core_version: "3.1.0"
|
||||
display_name: "Atari - 400/800/600XL/800XL/130XE/5200 (Atari800)"
|
||||
cores: [atari800]
|
||||
systems: [atari-400, atari-800, atari-800xl, atari-130xe, atari-5200, atari-xegs]
|
||||
systems: [atari-400-800, atari-5200]
|
||||
|
||||
# Atari800 emulates the Atari 8-bit family (400/800/XL/XE) and the 5200 console.
|
||||
# All BIOS files are optional -- the core ships built-in Altirra OS replacements
|
||||
@@ -43,7 +43,7 @@ files:
|
||||
note: >
|
||||
Atari 5200 BIOS (original). Mapped at $F800-$FFFF.
|
||||
Altirra 5200 OS is used when this file is absent.
|
||||
source_ref: "atari800/src/sysrom.c:101-102,254-255"
|
||||
source_ref: "atari800/src/sysrom.c:101-102,255"
|
||||
|
||||
# -- Atari BASIC ROM --
|
||||
# Atari BASIC interpreter (8 KB). Three known revisions:
|
||||
@@ -63,7 +63,7 @@ files:
|
||||
note: >
|
||||
Atari BASIC Rev C. Required for 400/800 software that needs BASIC.
|
||||
Altirra BASIC is used as fallback. Enable via core option atari800_opt2.
|
||||
source_ref: "atari800/src/sysrom.c:103-105,256"
|
||||
source_ref: "atari800/src/sysrom.c:103-105,257"
|
||||
|
||||
# -- Atari 400/800 OS A --
|
||||
# Original Atari 400/800 OS (10 KB). Two known CRC32 values:
|
||||
|
||||
@@ -3,18 +3,19 @@ type: libretro
|
||||
core_classification: community_fork
|
||||
source: "https://github.com/libretro/beetle-psx-libretro"
|
||||
upstream: "https://mednafen.github.io/"
|
||||
profiled_date: "2026-03-24"
|
||||
profiled_date: "2026-03-29"
|
||||
core_version: "v0.9.44.1"
|
||||
display_name: "Sony - PlayStation (Beetle PSX)"
|
||||
cores: [mednafen_psx, mednafen_psx_hw]
|
||||
cores: [beetle_psx, mednafen_psx, mednafen_psx_hw]
|
||||
systems: [sony-playstation]
|
||||
notes: >
|
||||
Region-based BIOS selection: the core picks JP/NA/EU firmware based on disc region.
|
||||
SHA1 validated with warning on mismatch (does not block loading).
|
||||
SHA1 and alternate filenames sourced from MAME psx.cpp (libretro.cpp:184).
|
||||
Override option allows using PSP or PS3 extracted PS1 BIOS as region-free alternative.
|
||||
SHA1 and alternate filenames sourced from MAME psx.cpp (libretro.cpp:186).
|
||||
Override option allows using PSP, PS3, or OpenBIOS as region-free alternative.
|
||||
Embedded OpenBIOS (512KB) compiled into the binary serves as HLE fallback when no BIOS found.
|
||||
"Skip BIOS" option patches BIOS ROM but causes compatibility issues.
|
||||
Upstream Mednafen loads the same 3 region BIOS; override BIOS are libretro additions.
|
||||
Upstream Mednafen loads the same 3 region BIOS; override BIOS and HLE fallback are libretro additions.
|
||||
|
||||
files:
|
||||
# -- Region: Japan (REGION_JP) --
|
||||
@@ -23,12 +24,13 @@ files:
|
||||
description: "SCPH-5500 (v3.0 09-09-96 J)"
|
||||
region: "NTSC-J"
|
||||
required: true
|
||||
hle_fallback: true
|
||||
size: 524288
|
||||
sha1: "b05def971d8ec59f346f2d9ac21fb742e3eb6917"
|
||||
md5: "8dd7d5296a650fac7319bce665a6a53c"
|
||||
validation: [sha1]
|
||||
mode: both
|
||||
source_ref: "libretro.cpp:252-256"
|
||||
source_ref: "libretro.cpp:261-269"
|
||||
aliases: ["SCPH5500.bin", "SCPH-5500.bin"]
|
||||
|
||||
# -- Region: North America (REGION_NA) --
|
||||
@@ -37,12 +39,13 @@ files:
|
||||
description: "SCPH-5501, 5503, 7003 (v3.0 11-18-96 A)"
|
||||
region: "NTSC-U"
|
||||
required: true
|
||||
hle_fallback: true
|
||||
size: 524288
|
||||
sha1: "0555c6fae8906f3f09baf5988f00e55f88e9f30b"
|
||||
md5: "490f666e1afb15b7362b406ed1cea246"
|
||||
validation: [sha1]
|
||||
mode: both
|
||||
source_ref: "libretro.cpp:258-270"
|
||||
source_ref: "libretro.cpp:271-289"
|
||||
aliases:
|
||||
- "SCPH5501.bin"
|
||||
- "SCPH-5501.bin"
|
||||
@@ -59,12 +62,13 @@ files:
|
||||
description: "SCPH-5502, 5552 (v3.0 01-06-97 E)"
|
||||
region: "PAL"
|
||||
required: true
|
||||
hle_fallback: true
|
||||
size: 524288
|
||||
sha1: "f6bc2d1f5eb6593de7d089c425ac681d6fffd3f0"
|
||||
md5: "32736f17079d0b2b7024407c39bd3050"
|
||||
validation: [sha1]
|
||||
mode: both
|
||||
source_ref: "libretro.cpp:272-282"
|
||||
source_ref: "libretro.cpp:291-305"
|
||||
aliases:
|
||||
- "SCPH5502.bin"
|
||||
- "SCPH-5502.bin"
|
||||
@@ -83,7 +87,7 @@ files:
|
||||
md5: "c53ca5908936d412331790f4426c6c33"
|
||||
validation: [sha1]
|
||||
mode: libretro
|
||||
source_ref: "libretro.cpp:190-195"
|
||||
source_ref: "libretro.cpp:192-198"
|
||||
aliases: ["PSXONPSP660.bin"]
|
||||
note: "override_bios=1. Falls back to region BIOS if not found."
|
||||
|
||||
@@ -96,6 +100,16 @@ files:
|
||||
md5: "81bbe60ba7a3d1cea1d48c14cbcc647b"
|
||||
validation: [sha1]
|
||||
mode: libretro
|
||||
source_ref: "libretro.cpp:198-203"
|
||||
source_ref: "libretro.cpp:200-206"
|
||||
aliases: ["PS1_ROM.bin"]
|
||||
note: "override_bios=2. Falls back to region BIOS if not found."
|
||||
|
||||
- name: "openbios.bin"
|
||||
description: "OpenBIOS (open-source PS1 HLE BIOS, region-free override)"
|
||||
region: "Auto"
|
||||
required: false
|
||||
size: 524288
|
||||
mode: libretro
|
||||
source_ref: "libretro.cpp:208-214"
|
||||
aliases: ["OPENBIOS.bin"]
|
||||
note: "override_bios=3. No SHA1 validation. Falls back to region BIOS if not found. Also embedded in binary as HLE fallback (libretro.cpp:2157-2159)."
|
||||
|
||||
@@ -7,10 +7,10 @@ profiled_date: "2026-03-23"
|
||||
core_version: "v1.0"
|
||||
display_name: "Dinothawr"
|
||||
cores: [dinothawr]
|
||||
systems: []
|
||||
systems: [dinothawr]
|
||||
|
||||
notes: |
|
||||
Puzzle game by the libretro team. Push blocks on ice.
|
||||
Puzzle game by the libretro team (Themaister, Agnes Heyer). Push blocks on ice.
|
||||
Game data (TMX levels, sprites, music) needed for the core to work.
|
||||
|
||||
Two loading modes:
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
emulator: GSplus
|
||||
type: standalone
|
||||
core_classification: community_fork
|
||||
source: "https://github.com/digarok/gsplus"
|
||||
upstream: "https://github.com/digarok/gsplus"
|
||||
profiled_date: "2026-03-26"
|
||||
upstream: "https://kegs.sourceforge.net/"
|
||||
profiled_date: "2026-03-29"
|
||||
core_version: "KEGS 1.38"
|
||||
display_name: "Apple - Apple IIGS (GSplus)"
|
||||
cores:
|
||||
- gsplus
|
||||
systems:
|
||||
- apple-iigs
|
||||
- apple-iie
|
||||
|
||||
notes: |
|
||||
Fork of KEGS (Kent's Emulated GS) by digarok. Cross-platform Apple IIGS
|
||||
@@ -28,7 +30,7 @@ files:
|
||||
aliases: [ROM.01, ROM.03, APPLE2GS.ROM, APPLE2GS.ROM2, xgs.rom, XGS.ROM, Rom03gd, 342-0077-b]
|
||||
required: true
|
||||
description: "Apple IIGS system ROM"
|
||||
source_ref: "config.c:131,403-407,1092-1149"
|
||||
source_ref: "config.c:131,403-406,1092-1149"
|
||||
note: "Accepted sizes: 32768 (Apple //e), 131072 (ROM 01), 262144 (ROM 03)"
|
||||
validation: [size]
|
||||
|
||||
@@ -39,5 +41,5 @@ files:
|
||||
size: 256
|
||||
description: "Disk II controller PROM (slot 6)"
|
||||
validation: [size]
|
||||
source_ref: "config.c:414-415,1188-1220"
|
||||
source_ref: "config.c:414-415,1168-1220"
|
||||
note: "Built-in PROM generated from XOR diffs against main ROM"
|
||||
|
||||
@@ -10,7 +10,7 @@ upstream: "https://github.com/PCSX2/pcsx2"
|
||||
profiled_date: "2026-03-25"
|
||||
core_version: "Git"
|
||||
display_name: "Sony - PlayStation 2 (LRPS2)"
|
||||
cores: [lrps2]
|
||||
cores: [lrps2, pcsx2]
|
||||
systems: [sony-playstation-2]
|
||||
|
||||
bios_directory: "pcsx2/bios/"
|
||||
|
||||
@@ -4,7 +4,7 @@ core_classification: official_port
|
||||
source: "https://github.com/libretro/mame"
|
||||
upstream: "https://github.com/mamedev/mame"
|
||||
logo: "https://raw.githubusercontent.com/mamedev/mame/master/docs/source/images/MAMElogo.svg"
|
||||
profiled_date: "2026-03-22"
|
||||
profiled_date: "2026-03-29"
|
||||
core_version: "0.286"
|
||||
display_name: "Arcade (MAME)"
|
||||
|
||||
@@ -43,13 +43,36 @@ systems:
|
||||
- konami-twinkle
|
||||
- panasonic-3do
|
||||
- hyper-neogeo64
|
||||
- apple2gs
|
||||
- apf-m1000
|
||||
- bally-astrocade
|
||||
- coleco-adam
|
||||
- crvision
|
||||
- entex-advision
|
||||
- sega-ai
|
||||
- sega-beena
|
||||
- bandai-rx78
|
||||
- camplynx
|
||||
- tiger-game-com
|
||||
- gamepark-gp32
|
||||
- gamate
|
||||
- gamepock
|
||||
- hartung-game-master
|
||||
- fm7
|
||||
- laser310
|
||||
- vtech-socrates
|
||||
- casio-loopy
|
||||
- casio-pv1000
|
||||
- casio-pv2000
|
||||
- pegasus
|
||||
- pcw
|
||||
- interton-vc4000
|
||||
- ti99
|
||||
- trs80
|
||||
|
||||
notes: |
|
||||
Rolling release tracking mamedev/mame upstream (currently 0.286).
|
||||
80 BIOS root sets + 3 system ROM sets (adam, advision, apfm1000). romload.cpp
|
||||
80 BIOS root sets + 24 system ROM sets (apple2gs, astrocade, adam, advision, apfm1000, beena, camplynx, casloopy, crvision, fm7, gamate, gamecom, gamepock, gmaster, gp32, laser310, pcw, pegasus, pv2000, rx78, segaai, socrates, ti99_4a, trs80). romload.cpp
|
||||
unmodified. No hiscore support.
|
||||
Paths under system_dir/mame/ (artwork, cheat, hash, ini, plugins,
|
||||
samples, crosshair). ROM search: content_dir + system_dir/mame/bios +
|
||||
@@ -59,6 +82,16 @@ notes: |
|
||||
renamed from legacy names (cpzn1 → coh1000c, atpsx → coh1000a, etc.).
|
||||
File structure uses vendor-based paths (src/mame/{vendor}/).
|
||||
|
||||
TI-99/4A: 6 machines in ti99_4x.cpp — ti99_4 parent (TI-99/4 1979),
|
||||
ti99_4e clone (Europe), ti99_4a parent (TI-99/4A 1981), ti99_4ae clone
|
||||
(Europe), ti99_4qi clone (QI version 1983), ti99_4ev clone (with EVPC
|
||||
1994). 5 ROMs per parent set: 3 GROMs (u500-u502) + 2 CPU ROMs
|
||||
(u610-u611, 16-bit interleaved). Speech Synthesizer sidecar device
|
||||
(speechsyn.cpp) with 2 TMS6100 vocabulary ROMs. Software list
|
||||
"ti99_cart". Peripheral Expansion Box with optional device ROMs (FDC,
|
||||
RS232, HFDC, P-Code, EVPC, etc.) — all PEB devices require user
|
||||
configuration, none loaded by default.
|
||||
|
||||
files:
|
||||
# SNK Neo Geo MVS/AES
|
||||
- name: neogeo.zip
|
||||
@@ -515,6 +548,92 @@ files:
|
||||
category: bios_zip
|
||||
source_ref: "src/mame/misc/xtom3d.cpp:996"
|
||||
|
||||
# Bally Astrocade
|
||||
- name: astrocde.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: astrocde
|
||||
source_ref: "src/mame/midway/astrohome.cpp:244-247"
|
||||
contents:
|
||||
- name: astro.bin
|
||||
description: "On-board BIOS ROM (Bally Professional Arcade)"
|
||||
size: 8192
|
||||
crc32: ebc77f3a
|
||||
|
||||
- name: astrocdl.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: astrocde
|
||||
source_ref: "src/mame/midway/astrohome.cpp:249-251"
|
||||
contents:
|
||||
- name: ballyhlc.bin
|
||||
description: "Bally Home Library Computer BIOS"
|
||||
size: 8192
|
||||
crc32: d7c517ba
|
||||
|
||||
- name: astrocdw.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: astrocde
|
||||
source_ref: "src/mame/midway/astrohome.cpp:254-257"
|
||||
contents:
|
||||
- name: bioswhit.bin
|
||||
description: "Bally Computer System BIOS"
|
||||
size: 8192
|
||||
crc32: 6eb53e79
|
||||
|
||||
# Apple IIgs
|
||||
- name: apple2gs.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: apple2gs
|
||||
source_ref: "src/mame/apple/apple2gs.cpp:3898-3912"
|
||||
contents:
|
||||
- name: 341s0632-2.bin
|
||||
description: "ADB microcontroller ROM (M50740/50741)"
|
||||
size: 4096
|
||||
crc32: e1c11fb0
|
||||
- name: 344s0047.bin
|
||||
description: "Mega II character ROM"
|
||||
size: 16384
|
||||
crc32: 2d541944
|
||||
- name: 341-0728
|
||||
description: "IIgs ROM03 FC-FD main CPU"
|
||||
size: 131072
|
||||
crc32: 8d410067
|
||||
- name: 341-0748
|
||||
description: "IIgs ROM03 FE-FF main CPU"
|
||||
size: 131072
|
||||
crc32: "18190283"
|
||||
|
||||
# Casio Loopy
|
||||
- name: casloopy.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: casio-loopy
|
||||
source_ref: "src/mame/casio/casloopy.cpp:2456-2462"
|
||||
contents:
|
||||
- name: hd6437021.lsi302
|
||||
description: "SH-1 CPU internal mask ROM"
|
||||
size: 32768
|
||||
crc32: 8c57ff9f
|
||||
- name: hn62434fa.lsi352
|
||||
description: "HN62434 sound/wave data mask ROM"
|
||||
size: 524288
|
||||
crc32: 8f51fa17
|
||||
|
||||
# Casio PV-2000
|
||||
- name: pv2000.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: casio-pv2000
|
||||
source_ref: "src/mame/casio/pv2000.cpp:416-419"
|
||||
contents:
|
||||
- name: hn613128pc64.bin
|
||||
description: "Z80 BASIC ROM"
|
||||
size: 16384
|
||||
crc32: 8f31f297
|
||||
|
||||
# Coleco Adam
|
||||
- name: adam.zip
|
||||
required: true
|
||||
@@ -661,3 +780,794 @@ files:
|
||||
size: 4096
|
||||
crc32: f320aba6
|
||||
|
||||
# Sega Advanced Pico BEENA
|
||||
- name: beena.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: sega-beena
|
||||
source_ref: "src/mame/sega/sega_beena.cpp:2233-2245"
|
||||
contents:
|
||||
- name: 9h0-0008.bios.ic1
|
||||
description: "SoC internal BIOS (ARM7, dumped via JTAG)"
|
||||
size: 131072
|
||||
crc32: 5471aaf8
|
||||
- name: 9h0-0008.midipcm.ic1
|
||||
description: "SoC MIDI synthesizer PCM data"
|
||||
size: 32768
|
||||
crc32: ed336d29
|
||||
|
||||
# Bandai RX-78
|
||||
- name: rx78.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: bandai-rx78
|
||||
source_ref: "src/mame/bandai/rx78.cpp:559"
|
||||
note: "MACHINE_NOT_WORKING."
|
||||
contents:
|
||||
- name: ipl.rom
|
||||
description: "IPL boot ROM"
|
||||
size: 8192
|
||||
crc32: a194ea53
|
||||
|
||||
# Sega AI Computer
|
||||
- name: segaai.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: sega-ai
|
||||
source_ref: "src/mame/sega/segaai.cpp:730-739"
|
||||
contents:
|
||||
- name: mpr-7689.ic5
|
||||
description: "OS ROM with SEGA PROLOG (128KB)"
|
||||
size: 131072
|
||||
crc32: 62402ac9
|
||||
- name: e000 8_24.ic3
|
||||
description: "EPROM bank E000"
|
||||
size: 65536
|
||||
crc32: c8b6a539
|
||||
- name: f000 7_21.ic4
|
||||
description: "EPROM bank F000"
|
||||
size: 65536
|
||||
crc32: 64d6cd8c
|
||||
- name: mpr-7619.ic14
|
||||
description: "UPD7759 speech ROM bank 0"
|
||||
size: 131072
|
||||
crc32: d1aea002
|
||||
- name: mpr-7620.ic15
|
||||
description: "UPD7759 speech ROM bank 1"
|
||||
size: 131072
|
||||
crc32: e042754b
|
||||
|
||||
- name: segaai_soundbox.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: sega-ai
|
||||
source_ref: "src/devices/bus/segaai/soundbox.cpp:152-155"
|
||||
note: "Sound Box expansion (AI-2002) with YM2151 FM + music keyboard"
|
||||
contents:
|
||||
- name: ai-snd-2002-cecb.bin
|
||||
description: "Sound Box expansion ROM"
|
||||
size: 65536
|
||||
crc32: ef2dabc0
|
||||
|
||||
# Camputers Lynx 48K
|
||||
- name: lynx48k.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: camplynx
|
||||
source_ref: "src/mame/camputers/camplynx.cpp:995-1004"
|
||||
contents:
|
||||
- name: lynx48-1.ic46
|
||||
description: "BASIC ROM bank 1 (Set1)"
|
||||
size: 8192
|
||||
crc32: 56feec44
|
||||
- name: lynx48-2.ic45
|
||||
description: "BASIC ROM bank 2 (Set1)"
|
||||
size: 8192
|
||||
crc32: d894562e
|
||||
- name: lynx4811.ic46
|
||||
description: "BASIC ROM bank 1 (Set2)"
|
||||
size: 8192
|
||||
crc32: a933e577
|
||||
- name: lynx4812.ic45
|
||||
description: "BASIC ROM bank 2 (Set2)"
|
||||
size: 8192
|
||||
crc32: 3d3fdd0e
|
||||
|
||||
# Camputers Lynx 96K
|
||||
- name: lynx96k.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: camplynx
|
||||
source_ref: "src/mame/camputers/camplynx.cpp:1006-1018"
|
||||
contents:
|
||||
- name: lynx9646.ic46
|
||||
description: "BASIC ROM bank 1"
|
||||
size: 8192
|
||||
crc32: f86c5514
|
||||
- name: lynx9645.ic45
|
||||
description: "BASIC ROM bank 2"
|
||||
size: 8192
|
||||
crc32: f596b9a3
|
||||
- name: lynx9644.ic44
|
||||
description: "Extension ROM (original)"
|
||||
size: 4096
|
||||
crc32: 4b96b0de
|
||||
- name: skorprom.ic44
|
||||
description: "Scorpion ROM v2.1 (RLUG)"
|
||||
size: 8192
|
||||
crc32: 698d3de9
|
||||
- name: danish96k3.ic44
|
||||
description: "Danish extension ROM"
|
||||
size: 8192
|
||||
crc32: 795c22ea
|
||||
- name: dosrom.rom
|
||||
description: "Floppy DOS ROM"
|
||||
size: 8192
|
||||
crc32: 011e106a
|
||||
|
||||
# Camputers Lynx 128K
|
||||
- name: lynx128k.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: camplynx
|
||||
source_ref: "src/mame/camputers/camplynx.cpp:1020-1026"
|
||||
contents:
|
||||
- name: lynx128-1.ic1
|
||||
description: "BASIC ROM bank 1"
|
||||
size: 8192
|
||||
crc32: 65d292ce
|
||||
- name: lynx128-2.ic2
|
||||
description: "BASIC ROM bank 2"
|
||||
size: 8192
|
||||
crc32: 23288773
|
||||
- name: lynx128-3.ic3
|
||||
description: "BASIC ROM bank 3"
|
||||
size: 8192
|
||||
crc32: 9827b9e9
|
||||
- name: dosrom.rom
|
||||
description: "Floppy DOS ROM"
|
||||
size: 8192
|
||||
crc32: 011e106a
|
||||
|
||||
# VTech CreatiVision
|
||||
- name: crvision.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: crvision
|
||||
source_ref: "src/mame/vtech/crvision.cpp:934-937"
|
||||
contents:
|
||||
- name: crvision.u20
|
||||
description: "Microsoft BASIC ROM"
|
||||
size: 2048
|
||||
crc32: c3c590c6
|
||||
|
||||
- name: fnvision.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: crvision
|
||||
source_ref: "src/mame/vtech/crvision.cpp:939-942"
|
||||
note: "FunVision clone with alternate BIOS"
|
||||
contents:
|
||||
- name: funboot.rom
|
||||
description: "FunVision alternate BIOS ROM"
|
||||
size: 2048
|
||||
crc32: "05602697"
|
||||
|
||||
- name: lasr2001.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: crvision
|
||||
source_ref: "src/mame/vtech/crvision.cpp:950-953"
|
||||
note: "VTech Laser 2001 home computer (CreatiVision successor)"
|
||||
contents:
|
||||
- name: laser2001.rom
|
||||
description: "Laser 2001 BASIC + OS ROM"
|
||||
size: 16384
|
||||
crc32: 4dc35c39
|
||||
|
||||
- name: manager.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: crvision
|
||||
source_ref: "src/mame/vtech/crvision.cpp:955-959"
|
||||
note: "Salora Manager (Finnish variant)"
|
||||
contents:
|
||||
- name: "01"
|
||||
description: "ROM bank 0-1"
|
||||
size: 8192
|
||||
crc32: 702f4cf5
|
||||
- name: "23"
|
||||
description: "ROM bank 2-3"
|
||||
size: 8192
|
||||
crc32: 46489d88
|
||||
|
||||
# VTech Laser 310 (VZ-300)
|
||||
- name: laser310.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: laser310
|
||||
source_ref: "src/mame/vtech/vtech1.cpp:602-608"
|
||||
note: "Z80-based home computer (1984). Clones: VZ-300, Laser 310 SHRG."
|
||||
contents:
|
||||
- name: vtechv20.u12
|
||||
description: "BASIC V2.0 ROM (default)"
|
||||
size: 16384
|
||||
crc32: 613de12c
|
||||
- name: vtechv21.u12
|
||||
description: "BASIC V2.1 ROM (hack)"
|
||||
size: 16384
|
||||
crc32: f7df980f
|
||||
|
||||
# VTech Socrates Educational Video System
|
||||
- name: socrates.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: vtech-socrates
|
||||
source_ref: "src/mame/vtech/socrates.cpp:1546-1596"
|
||||
note: "MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND. Clones: socratfc (French Canadian), profweis (German PAL)."
|
||||
contents:
|
||||
- name: 27-00817-000-000.u1
|
||||
description: "Main CPU ROM (256KB)"
|
||||
size: 262144
|
||||
crc32: 80f5aa20
|
||||
- name: speech_eng_internal.bin
|
||||
description: "TC8802AF speech chip internal data (optional, English)"
|
||||
size: 8192
|
||||
crc32: edc1fb3f
|
||||
- name: speech_eng_vsm1.bin
|
||||
description: "T6684F VSM serial ROM 1 (optional, English)"
|
||||
size: 16384
|
||||
crc32: 888e3ddd
|
||||
- name: speech_eng_vsm2.bin
|
||||
description: "T6684F VSM serial ROM 2 (optional, English)"
|
||||
size: 16384
|
||||
crc32: de4ac89d
|
||||
- name: speech_eng_vsm3.bin
|
||||
description: "T6684F VSM serial ROM 3 (optional, English)"
|
||||
size: 16384
|
||||
crc32: 972384aa
|
||||
|
||||
# Bit Corporation Gamate
|
||||
- name: gamate.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: gamate
|
||||
source_ref: "src/mame/bitcorp/gamate.cpp:228-234"
|
||||
contents:
|
||||
- name: gamate_bios_umc.bin
|
||||
description: "UMC/NCR ICASC00002 BIOS (default)"
|
||||
size: 4096
|
||||
crc32: "07090415"
|
||||
- name: gamate_bios_bit.bin
|
||||
description: "BIT ICASC00001 BIOS (1994)"
|
||||
size: 4096
|
||||
crc32: 03a5f3a7
|
||||
|
||||
# Epoch Game Pocket Computer
|
||||
- name: gamepock.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: gamepock
|
||||
source_ref: "src/mame/epoch/gamepock.cpp:248-251"
|
||||
contents:
|
||||
- name: egpcboot.bin
|
||||
description: "NEC uPD78C06AG internal ROM"
|
||||
size: 4096
|
||||
crc32: ee1ea65d
|
||||
|
||||
# Hartung Game Master
|
||||
- name: gmaster.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: hartung-game-master
|
||||
source_ref: "src/mame/handheld/gmaster.cpp:261-263"
|
||||
contents:
|
||||
- name: d78c11agf_e19.u1
|
||||
description: "NEC D78C11AGF internal ROM"
|
||||
size: 4096
|
||||
crc32: 05cc45e5
|
||||
|
||||
# Tiger game.com
|
||||
- name: gamecom.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: tiger-game-com
|
||||
source_ref: "src/mame/tiger/gamecom.cpp:293-299"
|
||||
contents:
|
||||
- name: internal.bin
|
||||
description: "SM8521 CPU internal ROM"
|
||||
size: 4096
|
||||
crc32: a0cec361
|
||||
- name: external.bin
|
||||
description: "External flash ROM (PDA software)"
|
||||
size: 262144
|
||||
crc32: e235a589
|
||||
|
||||
# GamePark GP32
|
||||
- name: gp32.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: gamepark-gp32
|
||||
source_ref: "src/mame/gamepark/gp32.cpp:1710-1727"
|
||||
contents:
|
||||
- name: gp32157e.bin
|
||||
description: "Firmware 1.5.7 (English, default)"
|
||||
size: 524288
|
||||
crc32: b1e35643
|
||||
- name: gp32100k.bin
|
||||
description: "Firmware 1.0.0 (Korean)"
|
||||
size: 524288
|
||||
crc32: d9925ac9
|
||||
- name: gp32156k.bin
|
||||
description: "Firmware 1.5.6 (Korean)"
|
||||
size: 524288
|
||||
crc32: "667fb1c8"
|
||||
- name: gp32166m.bin
|
||||
description: "Firmware 1.6.6 (European)"
|
||||
size: 524288
|
||||
crc32: "4548a840"
|
||||
- name: gp32mfv2.bin
|
||||
description: "Mr. Spiv Multi Firmware V2"
|
||||
size: 524288
|
||||
crc32: "7ddaaaeb"
|
||||
- name: x2c32.jed
|
||||
description: "32 Macrocell CoolRunner-II CPLD (JEDEC)"
|
||||
size: 15291
|
||||
crc32: eeec10d8
|
||||
|
||||
# Fujitsu FM-7 family
|
||||
- name: fm7.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: fm7
|
||||
source_ref: "src/mame/fujitsu/fm7.cpp:2188-2209"
|
||||
contents:
|
||||
- name: fbasic300.rom
|
||||
description: "F-BASIC 3.00 ROM"
|
||||
size: 31744
|
||||
crc32: 87c98494
|
||||
- name: subsys_c.rom
|
||||
description: "Sub-CPU system ROM"
|
||||
size: 10240
|
||||
crc32: 24cec93f
|
||||
- name: boot_bas.rom
|
||||
description: "Boot BASIC ROM"
|
||||
size: 512
|
||||
crc32: c70f0c74
|
||||
- name: boot_dos_a.rom
|
||||
description: "Boot DOS-A ROM"
|
||||
size: 512
|
||||
crc32: bf441864
|
||||
- name: kanji.rom
|
||||
description: "Kanji ROM (optional, JIS level 1)"
|
||||
size: 131072
|
||||
crc32: 62402ac9
|
||||
|
||||
- name: fm77av.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: fm7
|
||||
source_ref: "src/mame/fujitsu/fm7.cpp:2211-2232"
|
||||
contents:
|
||||
- name: initiate.rom
|
||||
description: "Initiate ROM (boot sequencer)"
|
||||
size: 8192
|
||||
crc32: 785cb06c
|
||||
- name: fbasic30.rom
|
||||
description: "F-BASIC 3.0 ROM"
|
||||
size: 31744
|
||||
crc32: a96d19b6
|
||||
- name: subsys_a.rom
|
||||
description: "Sub system A ROM"
|
||||
size: 8192
|
||||
crc32: e8014fbb
|
||||
- name: subsys_b.rom
|
||||
description: "Sub system B ROM"
|
||||
size: 8192
|
||||
crc32: 9be69fac
|
||||
- name: subsyscg.rom
|
||||
description: "Sub system CG ROM (character generator)"
|
||||
size: 8192
|
||||
crc32: e9f16c42
|
||||
|
||||
- name: fmnew7.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: fm7
|
||||
source_ref: "src/mame/fujitsu/fm7.cpp:2170-2186"
|
||||
note: "FM-NEW7 clone, inherits shared ROMs from fm7.zip parent"
|
||||
contents:
|
||||
- name: fbasic302.rom
|
||||
description: "F-BASIC 3.02 ROM"
|
||||
size: 31744
|
||||
crc32: a96d19b6
|
||||
- name: boot_dos.rom
|
||||
description: "Boot DOS ROM"
|
||||
size: 512
|
||||
crc32: 198614ff
|
||||
|
||||
# Technosys Aamber Pegasus
|
||||
- name: pegasus.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: pegasus
|
||||
source_ref: "src/mame/ausnz/pegasus.cpp:ROM_START"
|
||||
note: "6809-based home computer (1981, New Zealand). 8 monitor BIOS variants, 5 cartridge expansion slots."
|
||||
contents:
|
||||
- name: mon11_2674.bin
|
||||
description: "Monitor 1.1 r2674 (default)"
|
||||
size: 4096
|
||||
crc32: 1640ff7e
|
||||
- name: mon10_2569.bin
|
||||
description: "Monitor 1.0 r2569"
|
||||
size: 4096
|
||||
crc32: 910fc930
|
||||
- name: mon11_2569.bin
|
||||
description: "Monitor 1.1 r2569"
|
||||
size: 4096
|
||||
crc32: "07b92002"
|
||||
- name: mon11_2669.bin
|
||||
description: "Monitor 1.1 r2669"
|
||||
size: 4096
|
||||
crc32: f3ee23c8
|
||||
- name: mon22_2856.bin
|
||||
description: "Monitor 2.2 r2856"
|
||||
size: 4096
|
||||
crc32: 5f5f688a
|
||||
- name: mon22b_2856.bin
|
||||
description: "Monitor 2.2B r2856"
|
||||
size: 4096
|
||||
crc32: a47b0308
|
||||
- name: mon23_2601.bin
|
||||
description: "Monitor 2.3 r2601"
|
||||
size: 4096
|
||||
crc32: 0e024222
|
||||
- name: mon23a_2569.bin
|
||||
description: "Monitor 2.3A r2569"
|
||||
size: 4096
|
||||
crc32: 248e62c9
|
||||
- name: 6571.bin
|
||||
description: "MCM6571A character generator"
|
||||
size: 2048
|
||||
crc32: 5a25144b
|
||||
|
||||
# Amstrad PCW (Joyce)
|
||||
- name: pcw8256.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: pcw
|
||||
source_ref: "src/mame/amstrad/pcw.cpp:1402"
|
||||
note: |
|
||||
Amstrad PCW8256 parent ROM set. Z80-based word processor/computer (1985).
|
||||
6 machines: pcw8256 (parent), pcw8512, pcw9256, pcw9512, pcw9512+, pcw10.
|
||||
All MACHINE_NOT_WORKING. No main CPU ROM (boots from CP/M floppy).
|
||||
Printer MCU boot code copied into Z80 RAM at machine_reset.
|
||||
Clones pcw8512/pcw9256/pcw10 share parent ROMs. pcw9512/pcw9512+ use
|
||||
separate daisywheel printer MCU (pcw9512.zip).
|
||||
contents:
|
||||
- name: 40026.ic701
|
||||
description: "i8041 9-pin dot-matrix printer MCU"
|
||||
size: 1024
|
||||
crc32: ee8890ae
|
||||
- name: 40027.ic801
|
||||
description: "i8048 keyboard MCU"
|
||||
size: 1024
|
||||
crc32: "25260958"
|
||||
|
||||
- name: pcw9512.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: pcw
|
||||
source_ref: "src/mame/amstrad/pcw.cpp:1429"
|
||||
note: |
|
||||
Amstrad PCW9512 clone ROM set. Daisywheel printer variant (1987).
|
||||
Uses different printer MCU (40103.ic109) than 9-pin models.
|
||||
Keyboard MCU (40027.ic801) inherited from parent pcw8256.zip.
|
||||
contents:
|
||||
- name: 40103.ic109
|
||||
description: "i8041 daisywheel printer MCU"
|
||||
size: 8192
|
||||
crc32: a64d450a
|
||||
|
||||
# Tandy TRS-80 family
|
||||
# Model I (trs80.cpp): trs80 (Level I, parent, WORKING), trs80l2 (Level II, parent),
|
||||
# eg3003 (EACA Video Genie, parent), sys80/sys80p (clones), ht1080z/ht1080z2/ht108064 (clones).
|
||||
# Model III/4/4P (trs80m3.cpp): trs80m3 (parent), trs80m4/trs80m4p/cp500 (clones).
|
||||
# Z80-based home computers (1977-1983). Only trs80 (Level I) is MACHINE_SUPPORTS_SAVE;
|
||||
# all others MACHINE_NOT_WORKING. Software lists: trs80_cass, trs80_flop, trs80_quik.
|
||||
- name: trs80.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: trs80
|
||||
source_ref: "src/mame/trs/trs80.cpp:567-584"
|
||||
note: "TRS-80 Model I Level I Basic (1977). Only fully working TRS-80 machine in MAME."
|
||||
contents:
|
||||
- name: level1.rom
|
||||
description: "Level I BASIC ROM (4KB)"
|
||||
size: 4096
|
||||
crc32: 70d06dff
|
||||
- name: mcm6670p.z29
|
||||
description: "MCM6670P character generator ROM"
|
||||
size: 1024
|
||||
crc32: 0033f2b9
|
||||
|
||||
- name: trs80l2.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: trs80
|
||||
source_ref: "src/mame/trs/trs80.cpp:587-603"
|
||||
note: |
|
||||
TRS-80 Model I Level II Basic (1978). Separate parent machine from trs80 (Level I).
|
||||
2 BIOS variants: Radio Shack Level II and R/S L2 (alternate dumps).
|
||||
MACHINE_NOT_WORKING.
|
||||
contents:
|
||||
- name: rom-a.z1
|
||||
description: "Level II ROM A (default)"
|
||||
size: 4096
|
||||
crc32: 37c59db2
|
||||
- name: rom-b.z2
|
||||
description: "Level II ROM B (default)"
|
||||
size: 4096
|
||||
crc32: "05818718"
|
||||
- name: rom-c.z3
|
||||
description: "Level II ROM C (default)"
|
||||
size: 4096
|
||||
crc32: 306e5d66
|
||||
- name: rom-a_alt.z1
|
||||
description: "Level II ROM A (alternate dump)"
|
||||
size: 4096
|
||||
crc32: be46faf5
|
||||
- name: rom-b_alt.z2
|
||||
description: "Level II ROM B (alternate dump)"
|
||||
size: 4096
|
||||
crc32: 6c791c2d
|
||||
- name: rom-c_alt.z3
|
||||
description: "Level II ROM C (alternate dump)"
|
||||
size: 4096
|
||||
crc32: 55b3ad13
|
||||
- name: mcm6670p.z29
|
||||
description: "MCM6670P character generator ROM"
|
||||
size: 1024
|
||||
crc32: 0033f2b9
|
||||
|
||||
- name: eg3003.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: trs80
|
||||
source_ref: "src/mame/trs/trs80.cpp:608-617"
|
||||
note: |
|
||||
EACA Video Genie EG3003 (1980). TRS-80 Level II compatible clone.
|
||||
Parent for sys80/sys80p/ht1080z/ht1080z2/ht108064 clones.
|
||||
MACHINE_NOT_WORKING.
|
||||
contents:
|
||||
- name: 3001.z10
|
||||
description: "ROM A (BASIC part 1)"
|
||||
size: 4096
|
||||
crc32: 8f5214de
|
||||
- name: 3002.z11
|
||||
description: "ROM B (BASIC part 2)"
|
||||
size: 4096
|
||||
crc32: 46e88fbf
|
||||
- name: 3003.z12
|
||||
description: "ROM C (BASIC part 3)"
|
||||
size: 4096
|
||||
crc32: 306e5d66
|
||||
- name: tcs-ext.z13
|
||||
description: "TCS extension ROM"
|
||||
size: 2048
|
||||
crc32: 8f2ac112
|
||||
- name: tcs-ext.z25
|
||||
description: "TCS character generator ROM"
|
||||
size: 2048
|
||||
crc32: 150c5f1f
|
||||
|
||||
- name: sys80.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: trs80
|
||||
source_ref: "src/mame/trs/trs80.cpp:620-632"
|
||||
note: "EACA System-80 (1980). Clone of eg3003 with different extension ROM. sys80p (50 Hz) shares ROMs."
|
||||
contents:
|
||||
- name: sys80.z13
|
||||
description: "System-80 extension ROM"
|
||||
size: 2048
|
||||
crc32: 2a851e33
|
||||
- name: 2513.z25
|
||||
description: "Character generator ROM"
|
||||
size: 1024
|
||||
crc32: 0033f2b9
|
||||
|
||||
- name: ht1080z.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: trs80
|
||||
source_ref: "src/mame/trs/trs80.cpp:637-646"
|
||||
note: "Hiradastechnika HT-1080Z Series I (1983). Hungarian clone of eg3003."
|
||||
contents:
|
||||
- name: ht1080z.z25
|
||||
description: "HT-1080Z character generator ROM"
|
||||
size: 2048
|
||||
crc32: e8c59d4f
|
||||
|
||||
- name: ht1080z2.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: trs80
|
||||
source_ref: "src/mame/trs/trs80.cpp:649-658"
|
||||
note: "Hiradastechnika HT-1080Z Series II (1984). Clone of eg3003."
|
||||
contents:
|
||||
- name: ht1080z2.z13
|
||||
description: "HT-1080Z II extension ROM"
|
||||
size: 2048
|
||||
crc32: "07415ac6"
|
||||
- name: ht1080z2.z25
|
||||
description: "HT-1080Z II character generator ROM"
|
||||
size: 2048
|
||||
crc32: 6728f0ab
|
||||
|
||||
- name: ht108064.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: trs80
|
||||
source_ref: "src/mame/trs/trs80.cpp:661-670"
|
||||
note: "Hiradastechnika HT-1080Z/64 (1985). 64-column clone of eg3003."
|
||||
contents:
|
||||
- name: 3001_64.z10
|
||||
description: "ROM A (64-col BASIC part 1)"
|
||||
size: 4096
|
||||
crc32: 59ec132e
|
||||
- name: 3002_64.z11
|
||||
description: "ROM B (64-col BASIC part 2)"
|
||||
size: 4096
|
||||
crc32: a7a73e8c
|
||||
- name: ht108064.z13
|
||||
description: "HT-1080Z/64 extension ROM"
|
||||
size: 2048
|
||||
crc32: fc12bd28
|
||||
- name: ht108064.z25
|
||||
description: "HT-1080Z/64 character generator ROM"
|
||||
size: 2048
|
||||
crc32: e76b73a4
|
||||
|
||||
- name: trs80m3.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: trs80
|
||||
source_ref: "src/mame/trs/trs80m3.cpp:483-519"
|
||||
note: |
|
||||
TRS-80 Model III (1980). Parent for trs80m4/trs80m4p/cp500 clones.
|
||||
4 BIOS variants: Level 2 ROM C Rev C (default), Rev B, Network III v2 (student),
|
||||
Level 1. MACHINE_NOT_WORKING.
|
||||
contents:
|
||||
- name: 8041364.u104
|
||||
description: "Level 2 ROM A"
|
||||
size: 8192
|
||||
crc32: ec0c6daa
|
||||
- name: 8040332.u105
|
||||
description: "Level 2 ROM B"
|
||||
size: 4096
|
||||
crc32: ed4ee921
|
||||
- name: 8040316c.u106
|
||||
description: "Level 2 ROM C Rev C (default)"
|
||||
size: 2048
|
||||
crc32: c8f79433
|
||||
- name: 8040316b.u106
|
||||
description: "Level 2 ROM C Rev B"
|
||||
size: 2048
|
||||
crc32: 84a5702d
|
||||
- name: 276a.u106
|
||||
description: "Network III v2 ROM C"
|
||||
size: 2048
|
||||
crc32: 7d38720a
|
||||
- name: 8040032.u104
|
||||
description: "Level 1 BIOS"
|
||||
size: 4096
|
||||
crc32: 6418d641
|
||||
- name: 8044316a.u36
|
||||
description: "Character generator ROM (rev A)"
|
||||
size: 2048
|
||||
crc32: 444c8b60
|
||||
|
||||
- name: trs80m4.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: trs80
|
||||
source_ref: "src/mame/trs/trs80m3.cpp:522-528"
|
||||
note: |
|
||||
TRS-80 Model 4 (1980). Clone of trs80m3. BAD_DUMP combined ROM
|
||||
(should be split into 3 like trs80m3). MACHINE_NOT_WORKING.
|
||||
contents:
|
||||
- name: trs80m4.rom
|
||||
description: "Combined system ROM (BAD_DUMP)"
|
||||
size: 14336
|
||||
crc32: 1a92d54d
|
||||
- name: 8044316a.u36
|
||||
description: "Character generator ROM"
|
||||
size: 2048
|
||||
crc32: 444c8b60
|
||||
|
||||
- name: trs80m4p.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: trs80
|
||||
source_ref: "src/mame/trs/trs80m3.cpp:530-539"
|
||||
note: |
|
||||
TRS-80 Model 4P (1983). Clone of trs80m3. Completely different memory map;
|
||||
Model III ROMs loaded from boot disk, only a bootloader ROM on board.
|
||||
2 BIOS variants: gate array (default) and disk loader hack.
|
||||
MACHINE_NOT_WORKING.
|
||||
contents:
|
||||
- name: 8075332.u69
|
||||
description: "Bootloader ROM"
|
||||
size: 4096
|
||||
crc32: 3a738aa9
|
||||
- name: trs80m4p_loader_hack.rom
|
||||
description: "Disk loader hack ROM"
|
||||
size: 504
|
||||
crc32: 7ff336f4
|
||||
- name: 8049007.u103
|
||||
description: "Character generator ROM"
|
||||
size: 2048
|
||||
crc32: 1ac44bea
|
||||
|
||||
- name: cp500.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: trs80
|
||||
source_ref: "src/mame/trs/trs80m3.cpp:541-550"
|
||||
note: "Prologica CP-500 (1982). Brazilian TRS-80 Model III clone. MACHINE_NOT_WORKING."
|
||||
contents:
|
||||
- name: s_8407_cn62516n_cp500a_prologica_83.ci111
|
||||
description: "Combined system + boot ROM"
|
||||
size: 16384
|
||||
crc32: c2fc1b92
|
||||
- name: 100.105.ci36
|
||||
description: "Character generator ROM"
|
||||
size: 2048
|
||||
crc32: 1765931e
|
||||
|
||||
# TI-99/4A
|
||||
- name: ti99_4a.zip
|
||||
required: true
|
||||
category: bios_zip
|
||||
system: ti99
|
||||
source_ref: "src/mame/ti/ti99_4x.cpp:1153-1166"
|
||||
note: "TI-99/4A Home Computer (1981). Parent machine ROM set."
|
||||
contents:
|
||||
- name: 994a_grom0.u500
|
||||
description: "Console GROM 0"
|
||||
size: 6144
|
||||
crc32: 2445a5e8
|
||||
- name: 994a_grom1.u501
|
||||
description: "Console GROM 1"
|
||||
size: 6144
|
||||
crc32: b8f367ab
|
||||
- name: 994a_grom2.u502
|
||||
description: "Console GROM 2"
|
||||
size: 6144
|
||||
crc32: e0bb5341
|
||||
- name: 994a_rom_hb.u610
|
||||
description: "CPU ROM high byte"
|
||||
size: 4096
|
||||
crc32: ee859c5f
|
||||
- name: 994a_rom_lb.u611
|
||||
description: "CPU ROM low byte"
|
||||
size: 4096
|
||||
crc32: 37859301
|
||||
|
||||
- name: ti99_speech.zip
|
||||
required: false
|
||||
category: bios_zip
|
||||
system: ti99
|
||||
source_ref: "src/devices/bus/ti99/sidecar/speechsyn.cpp:242-246"
|
||||
note: "TI-99 Speech Synthesizer sidecar. 2 TMS6100 vocabulary ROMs."
|
||||
contents:
|
||||
- name: cd2325a.u2a
|
||||
description: "TMS6100 vocabulary ROM (bottom)"
|
||||
size: 16384
|
||||
crc32: 1f58b571
|
||||
- name: cd2326a.u2b
|
||||
description: "TMS6100 vocabulary ROM (top)"
|
||||
size: 16384
|
||||
crc32: 65d00401
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,13 +3,14 @@ type: libretro
|
||||
core_classification: community_fork
|
||||
source: "https://github.com/libretro/quasi88-libretro"
|
||||
upstream: "https://www.retropc.net/showzoh/quasi88/"
|
||||
profiled_date: "2026-03-25"
|
||||
profiled_date: "2026-03-29"
|
||||
core_version: "0.6.4"
|
||||
display_name: "NEC - PC-8000 / PC-8800 series (QUASI88)"
|
||||
cores:
|
||||
- quasi88
|
||||
systems:
|
||||
- pc-8801
|
||||
- nec-pc-88
|
||||
- nec-pc-80
|
||||
|
||||
# QUASI88 by Showzoh Fukunaga, libretro port by Celerizer.
|
||||
# Includes pseudo-BIOS (pbios_n88, pbios_disk) by cisc compiled into the core.
|
||||
@@ -35,6 +36,16 @@ systems:
|
||||
#
|
||||
# Upstream supports 2HD disk ROM (8 KB) via memory.c:356-368.
|
||||
# The libretro port reads only 2 KB (2D type) at libretro.c:552.
|
||||
#
|
||||
# font.rom divergence: libretro.c:566-571 loads 0x1000 bytes then
|
||||
# overwrites the buffer with kanji ROM + built-in graph. The font.rom
|
||||
# data is not actually used (bug). Upstream memory.c:427 loads FONT_SZ
|
||||
# (2048) and keeps the font data in the first half.
|
||||
#
|
||||
# OPNA rhythm samples (2608_BD.WAV etc.): loaded by upstream via
|
||||
# fmgen/opna.cpp:1271 LoadRhythmSample(), but osd_dir_rom() returns
|
||||
# NULL in the libretro port (dir_rom never initialized), so the samples
|
||||
# cannot be loaded. OPNA rhythm playback is silent in the libretro core.
|
||||
|
||||
notes: |
|
||||
Files go in <system_dir>/quasi88/ or directly in <system_dir>/.
|
||||
@@ -43,7 +54,8 @@ notes: |
|
||||
kanji display), real ROM files are needed.
|
||||
|
||||
Core option "quasi88_basic_mode" selects N88 V2, N88 V1H, N88 V1S,
|
||||
or N mode. Each mode requires its corresponding ROM.
|
||||
or N mode. Each mode requires its corresponding ROM. N mode emulates
|
||||
PC-8001 series (N-BASIC) and requires n88n.rom.
|
||||
|
||||
files:
|
||||
- name: n88.rom
|
||||
|
||||
66
emulators/ti99sim.yml
Normal file
66
emulators/ti99sim.yml
Normal file
@@ -0,0 +1,66 @@
|
||||
emulator: ti99sim
|
||||
display_name: "TI-99/Sim"
|
||||
type: standalone
|
||||
source: https://github.com/christianhaitian/ti99sim
|
||||
upstream: https://www.mrousseau.org/programs/ti99sim/
|
||||
profiled_date: "2026-03-29"
|
||||
core_version: "0.16.0"
|
||||
cores:
|
||||
- ti99sim
|
||||
|
||||
systems:
|
||||
- ti99
|
||||
|
||||
notes: |
|
||||
Marc Rousseau's TI-99/4A simulator (since 1993). Standalone only, no libretro port.
|
||||
Uses proprietary .ctg cartridge format for ROM packaging (CPU ROM + GROMs + RAM config).
|
||||
Raw ROM dumps must be converted to .ctg via the convert-ctg utility.
|
||||
File search order: CWD, CWD/console/ (v0.16.0) or CWD/roms/ (<=0.0.11),
|
||||
~/.ti99sim/console/, /opt/ti99sim/console/.
|
||||
v0.16.0 adds SHA1-based auto-discovery for device ROMs in the console/ directory.
|
||||
Recalbox packages ti99sim as a standalone emulator for the ti994a system.
|
||||
|
||||
files:
|
||||
- name: TI-994A.ctg
|
||||
required: true
|
||||
description: "Console ROM cartridge containing CPU ROMs, system GROMs, and RAM configuration"
|
||||
source_ref: "src/core/ti994a.cpp:122-131 (v0.16.0), src/sdl/main.cpp:407-411 (v0.0.11)"
|
||||
sha1: "0264512c7d9e7fa091a48e5c8734782ea031a52d"
|
||||
note: "SHA1 is of .ctg format. v0.16.0 also recognizes console v2.2 (sha1 16e275faae427465ba4dd4c2bf8569f6546d32dd)."
|
||||
|
||||
- name: spchrom.bin
|
||||
required: false
|
||||
size: 32768
|
||||
description: "TMS5220/TMS6100 Speech Synthesizer vocabulary ROM"
|
||||
source_ref: "src/core/tms5220.cpp:190-213 (v0.16.0), src/core/tms5220.cpp:194-213 (v0.0.11)"
|
||||
validation: [size]
|
||||
hle_fallback: true
|
||||
note: "Raw binary, not .ctg format. Must be exactly 32768 bytes. First byte must be 0xAA. Falls back to empty speech ROM if missing or invalid."
|
||||
|
||||
- name: ti-disk.ctg
|
||||
required: false
|
||||
description: "TI Disk Controller DSR ROM (CRU >1100)"
|
||||
source_ref: "src/core/device-support.cpp:52 (v0.16.0), src/sdl/main.cpp:452-476 (v0.0.11)"
|
||||
sha1: "ed91d48c1eaa8ca37d5055bcf67127ea51c4cad5"
|
||||
note: "SHA1 is of .ctg format. Disk emulation disabled without this file."
|
||||
|
||||
- name: "Gram Kracker.ctg"
|
||||
required: false
|
||||
description: "Miller Graphics Gram Kracker ROM manipulation peripheral"
|
||||
source_ref: "src/core/ti994a-gk.cpp:56 (v0.16.0), src/sdl/ti994a-sdl.cpp:78 (v0.0.11)"
|
||||
sha1: "a3bd5257c63e190800921b52dbe3ffa91ad91113"
|
||||
note: "SHA1 is of .ctg format. Gram Kracker features disabled without this file."
|
||||
|
||||
- name: ti-pcard.ctg
|
||||
required: false
|
||||
description: "TI P-Code Card (UCSD Pascal) DSR ROM"
|
||||
source_ref: "src/core/device-support.cpp:53 (v0.16.0)"
|
||||
sha1: "27aceb956262d3e3f97d938602dfaa91b53da59e"
|
||||
note: "SHA1 is of .ctg format. v0.16.0+ only."
|
||||
|
||||
- name: cf7+.ctg
|
||||
required: false
|
||||
description: "CF7+/nanoPEB CompactFlash interface DSR ROM"
|
||||
source_ref: "src/core/device-support.cpp:51 (v0.16.0)"
|
||||
sha1: "4d26e5ef0997ed2f3a56eb8104778bfe719b38f2"
|
||||
note: "SHA1 is of .ctg format. v0.16.0+ only."
|
||||
@@ -1,299 +1,58 @@
|
||||
# Vita3K emulator firmware profile
|
||||
# Generated from source analysis of https://github.com/Vita3K/Vita3K
|
||||
# Commit analyzed: HEAD as of 2026-03-17
|
||||
|
||||
emulator: Vita3K
|
||||
type: standalone
|
||||
source: "https://github.com/Vita3K/Vita3K"
|
||||
logo: "https://raw.githubusercontent.com/Vita3K/Vita3K/master/data/image/icon.png"
|
||||
profiled_date: "2026-03-18"
|
||||
upstream: "https://github.com/Vita3K/Vita3K"
|
||||
profiled_date: "2026-03-29"
|
||||
core_version: "0.2.1"
|
||||
display_name: "Vita3K (PS Vita)"
|
||||
systems: [sony-playstation-vita]
|
||||
|
||||
firmware_file: "PSVUPDAT.PUP"
|
||||
firmware_source: "https://www.playstation.com/en-us/support/hardware/psvita/system-software/"
|
||||
firmware_detection: "pup_decrypt"
|
||||
firmware_install: "decrypts PUP, extracts FAT/exFAT images into os0/, vs0/, sa0/, pd0/"
|
||||
# Standalone emulator, no libretro core exists.
|
||||
# Firmware PUP files are one-time installations: install_pup() decrypts and
|
||||
# extracts partition images (os0, vs0, sa0, pd0) into the emulator data directory.
|
||||
# The PUP file itself is deleted after extraction.
|
||||
# Three separate PUP packages exist on Sony servers:
|
||||
# 1. PSVUPDAT.PUP (main firmware) from psv.update.playstation.net
|
||||
# 2. PSP2UPDAT.PUP (font package) from psp2.update.playstation.net (sd_ prefix)
|
||||
# 3. PSP2UPDAT.PUP (preinst firmware) from psp2.update.playstation.net (pre_ prefix)
|
||||
# Vita3K uses hybrid LLE/HLE: some modules always loaded from firmware (libc,
|
||||
# libSceFt2, libpvf, libcdlg), others toggleable per-module via settings.
|
||||
|
||||
validation:
|
||||
method: "pup_decrypt_and_extract"
|
||||
source_ref: "vita3k/packages/src/pup.cpp:260-314"
|
||||
files:
|
||||
- name: PSVUPDAT.PUP
|
||||
path: "psvita/PSVUPDAT.PUP"
|
||||
required: true
|
||||
hle_fallback: true
|
||||
note: >
|
||||
PUP is decrypted using SCE keys (register_keys), then four filesystem images are
|
||||
extracted: os0.img (FAT), pd0.img (exFAT), sa0.img (FAT), vs0.img (FAT).
|
||||
Each image is mounted to its respective partition path.
|
||||
Main PS Vita firmware. Decrypted via SCE keys, extracts os0 (kernel),
|
||||
vs0 (system modules and apps), sa0 (fonts), pd0 (system data).
|
||||
Games load LLE modules from vs0/sys/external/*.suprx. Preload modules
|
||||
(libc, libSceFt2, libpvf) are always LLE. Without firmware most games fail.
|
||||
Some simple titles may run on HLE alone.
|
||||
source_ref: "vita3k/packages/src/pup.cpp:260-314, vita3k/module/src/load_module.cpp:142-161,187"
|
||||
|
||||
firmware_version:
|
||||
path: "PUP_DEC/PUP/version.txt"
|
||||
source_ref: "vita3k/packages/src/pup.cpp:303-309"
|
||||
note: "Read from version.txt inside the decrypted PUP during installation"
|
||||
|
||||
# Firmware partitions extracted from PSVUPDAT.PUP
|
||||
partitions:
|
||||
os0:
|
||||
image: "os0.img"
|
||||
filesystem: "FAT"
|
||||
source_ref: "vita3k/packages/src/pup.cpp:293"
|
||||
note: "Core OS partition. Contains kernel modules and low-level system components."
|
||||
|
||||
vs0:
|
||||
image: "vs0.img"
|
||||
filesystem: "FAT"
|
||||
source_ref: "vita3k/packages/src/pup.cpp:299"
|
||||
- name: PSP2UPDAT.PUP
|
||||
path: "psvita/PSP2UPDAT.PUP"
|
||||
required: false
|
||||
hle_fallback: true
|
||||
note: >
|
||||
Main system partition. Contains firmware modules (sys/external/*.suprx),
|
||||
system apps (app/), LiveArea resources, themes, and system configuration.
|
||||
directories:
|
||||
sys_external:
|
||||
path: "vs0/sys/external/"
|
||||
source_ref: "vita3k/modules/module_parent.cpp:332"
|
||||
note: >
|
||||
Primary firmware module directory. Modules are loaded as .suprx files.
|
||||
RPCS3-style LLE/HLE toggle: Vita3K can load real firmware modules (LLE)
|
||||
or use built-in reimplementations (HLE) per module.
|
||||
|
||||
app:
|
||||
path: "vs0/app/"
|
||||
note: "System applications (settings, browser, store, etc)"
|
||||
|
||||
data_internal:
|
||||
path: "vs0/data/internal/"
|
||||
note: "Internal system data: themes, LiveArea defaults"
|
||||
files:
|
||||
- {path: "theme/", purpose: "Default system themes"}
|
||||
- {path: "livearea/default/sce_sys/icon0.png", purpose: "Default app icon"}
|
||||
|
||||
sa0:
|
||||
image: "sa0.img"
|
||||
filesystem: "FAT"
|
||||
source_ref: "vita3k/packages/src/pup.cpp:297"
|
||||
note: "System assets partition. Contains firmware fonts (PVF files)."
|
||||
directories:
|
||||
fonts:
|
||||
path: "sa0/data/font/pvf/"
|
||||
source_ref: "vita3k/gui/src/gui.cpp:228-267"
|
||||
note: >
|
||||
PS Vita system fonts in PVF format (PlayStation Vita Font). Used for
|
||||
system UI, LiveArea, and games that use the sceFt2/libpvf font API.
|
||||
Without these, Vita3K falls back to bundled open-source fonts.
|
||||
files:
|
||||
- {name: "ltn0.pvf", type: "Latin Regular", required: true, note: "Primary UI font, checked at startup"}
|
||||
- {name: "jpn0.pvf", type: "Japanese", required: false}
|
||||
- {name: "kr0.pvf", type: "Korean", required: false}
|
||||
- {name: "cn0.pvf", type: "Chinese Simplified", required: false}
|
||||
|
||||
pd0:
|
||||
image: "pd0.img"
|
||||
filesystem: "exFAT"
|
||||
source_ref: "vita3k/packages/src/pup.cpp:295"
|
||||
note: "System data partition. Contains system BGM and other data."
|
||||
files:
|
||||
- {path: "data/systembgm/initialsetup.at9", purpose: "Initial setup background music"}
|
||||
|
||||
# Firmware modules (vs0/sys/external/*.suprx)
|
||||
firmware_modules:
|
||||
# Auto-LLE modules (loaded from firmware by default)
|
||||
auto_lle:
|
||||
source_ref: "vita3k/module/src/load_module.cpp:142-161"
|
||||
note: "These modules are automatically loaded via LLE when firmware is present"
|
||||
modules:
|
||||
- {id: "SCE_SYSMODULE_HTTP", libs: ["libhttp"]}
|
||||
- {id: "SCE_SYSMODULE_SSL", libs: ["libssl"]}
|
||||
- {id: "SCE_SYSMODULE_HTTPS", libs: ["libhttp", "libssl"]}
|
||||
- {id: "SCE_SYSMODULE_ULT", libs: ["libult"]}
|
||||
- {id: "SCE_SYSMODULE_SAS", libs: ["libsas"]}
|
||||
- {id: "SCE_SYSMODULE_PGF", libs: ["libpgf"]}
|
||||
- {id: "SCE_SYSMODULE_FIOS2", libs: ["libfios2"]}
|
||||
- {id: "SCE_SYSMODULE_SYSTEM_GESTURE", libs: ["libsystemgesture"]}
|
||||
- {id: "SCE_SYSMODULE_XML", libs: ["libSceXml"]}
|
||||
- {id: "SCE_SYSMODULE_SQLITE", libs: ["libSceSqlite"]}
|
||||
- {id: "SCE_SYSMODULE_RUDP", libs: ["librudp"]}
|
||||
- {id: "SCE_SYSMODULE_NET_ADHOC_MATCHING", libs: ["adhoc_matching"]}
|
||||
- {id: "SCE_SYSMODULE_MP4", libs: ["libscemp4"]}
|
||||
- {id: "SCE_SYSMODULE_ATRAC", libs: ["libatrac"]}
|
||||
- {id: "SCE_SYSMODULE_FACE", libs: ["libface"]}
|
||||
- {id: "SCE_SYSMODULE_SMART", libs: ["libsmart"]}
|
||||
- {id: "SCE_SYSMODULE_AVPLAYER", libs: ["libsceavplayer", "libscemp4"]}
|
||||
- {id: "SCE_SYSMODULE_JSON", libs: ["libSceJson"]}
|
||||
|
||||
# Always-LLE preload modules
|
||||
preload:
|
||||
source_ref: "vita3k/interface.cpp:497-504, vita3k/module/src/load_module.cpp:187"
|
||||
note: "These modules are always loaded from firmware (LLE), never HLE"
|
||||
modules:
|
||||
- {name: "libc", note: "C standard library"}
|
||||
- {name: "libSceFt2", note: "FreeType2 font engine"}
|
||||
- {name: "libpvf", note: "PlayStation Vita Font library"}
|
||||
- {name: "libcdlg", note: "Common dialog library"}
|
||||
|
||||
# All registered sysmodule mappings
|
||||
sysmodule_map:
|
||||
source_ref: "vita3k/module/src/load_module.cpp:25-109"
|
||||
note: "Complete mapping of SCE_SYSMODULE IDs to firmware library filenames"
|
||||
modules:
|
||||
# Networking
|
||||
- {id: "SCE_SYSMODULE_NET", libs: ["libnet", "libnetctl"]}
|
||||
- {id: "SCE_SYSMODULE_HTTP", libs: ["libhttp"]}
|
||||
- {id: "SCE_SYSMODULE_SSL", libs: ["libssl"]}
|
||||
- {id: "SCE_SYSMODULE_HTTPS", libs: ["libhttp", "libssl"]}
|
||||
# Performance / Threading
|
||||
- {id: "SCE_SYSMODULE_PERF", libs: ["libperf"]}
|
||||
- {id: "SCE_SYSMODULE_FIBER", libs: ["libfiber"]}
|
||||
- {id: "SCE_SYSMODULE_ULT", libs: ["libult"]}
|
||||
# Debug
|
||||
- {id: "SCE_SYSMODULE_DBG", libs: ["librazorcapture_es4", "librazorhud_es4"]}
|
||||
- {id: "SCE_SYSMODULE_RAZOR_CAPTURE", libs: ["librazorcapture_es4"]}
|
||||
- {id: "SCE_SYSMODULE_RAZOR_HUD", libs: ["librazorhud_es4"]}
|
||||
# Audio
|
||||
- {id: "SCE_SYSMODULE_NGS", libs: ["libngs"]}
|
||||
- {id: "SCE_SYSMODULE_SULPHA", libs: ["libsulpha"]}
|
||||
- {id: "SCE_SYSMODULE_SAS", libs: ["libsas"]}
|
||||
- {id: "SCE_SYSMODULE_AUDIOCODEC", libs: ["libaudiocodec"]}
|
||||
- {id: "SCE_SYSMODULE_AACENC", libs: ["libnaac"]}
|
||||
- {id: "SCE_SYSMODULE_ATRAC", libs: ["libatrac"]}
|
||||
- {id: "SCE_SYSMODULE_VOICE", libs: ["libvoice"]}
|
||||
- {id: "SCE_SYSMODULE_VOICEQOS", libs: ["libvoiceqos"]}
|
||||
# Font / Text
|
||||
- {id: "SCE_SYSMODULE_PGF", libs: ["libpgf"]}
|
||||
- {id: "SCE_SYSMODULE_IME", libs: ["libime"]}
|
||||
- {id: "SCE_SYSMODULE_HANDWRITING", libs: ["libhandwriting"]}
|
||||
# System
|
||||
- {id: "SCE_SYSMODULE_APPUTIL", libs: ["apputil"]}
|
||||
- {id: "SCE_SYSMODULE_FIOS2", libs: ["libfios2"]}
|
||||
- {id: "SCE_SYSMODULE_SYSTEM_GESTURE", libs: ["libsystemgesture"]}
|
||||
- {id: "SCE_SYSMODULE_LOCATION", libs: ["liblocation"]}
|
||||
- {id: "SCE_SYSMODULE_CLIPBOARD", libs: ["libclipboard"]}
|
||||
- {id: "SCE_SYSMODULE_TRIGGER_UTIL", libs: ["trigger_util"]}
|
||||
- {id: "SCE_SYSMODULE_LIVEAREA", libs: ["livearea_util"]}
|
||||
- {id: "SCE_SYSMODULE_BG_APP_UTIL", libs: ["bgapputil"]}
|
||||
- {id: "SCE_SYSMODULE_INCOMING_DIALOG", libs: ["incoming_dialog"]}
|
||||
- {id: "SCE_SYSMODULE_IPMI", libs: ["libipmi_nongame"]}
|
||||
- {id: "SCE_SYSMODULE_NOTIFICATION_UTIL", libs: ["notification_util"]}
|
||||
- {id: "SCE_SYSMODULE_SHUTTER_SOUND", libs: ["libSceShutterSound"]}
|
||||
- {id: "SCE_SYSMODULE_SCREEN_SHOT", libs: ["libSceScreenShot"]}
|
||||
# PlayStation Network
|
||||
- {id: "SCE_SYSMODULE_NP_BASIC", libs: ["np_basic"]}
|
||||
- {id: "SCE_SYSMODULE_NP", libs: ["np_common", "np_manager", "np_basic"]}
|
||||
- {id: "SCE_SYSMODULE_NP_COMMERCE2", libs: ["np_commerce2"]}
|
||||
- {id: "SCE_SYSMODULE_NP_UTILITY", libs: ["np_utility"]}
|
||||
- {id: "SCE_SYSMODULE_NP_MATCHING2", libs: ["np_matching2"]}
|
||||
- {id: "SCE_SYSMODULE_NP_SCORE_RANKING", libs: ["np_ranking"]}
|
||||
- {id: "SCE_SYSMODULE_NP_ACTIVITY", libs: ["np_activity_sdk"]}
|
||||
- {id: "SCE_SYSMODULE_NP_TROPHY", libs: ["np_trophy"]}
|
||||
- {id: "SCE_SYSMODULE_NP_MESSAGE", libs: ["np_message_padding", "np_message"]}
|
||||
- {id: "SCE_SYSMODULE_NP_PARTY", libs: ["np_party"]}
|
||||
- {id: "SCE_SYSMODULE_NP_TUS", libs: ["np_tus"]}
|
||||
- {id: "SCE_SYSMODULE_NP_SNS_FACEBOOK", libs: ["np_sns_facebook"]}
|
||||
- {id: "SCE_SYSMODULE_NP_SIGNALING", libs: ["np_signaling"]}
|
||||
- {id: "SCE_SYSMODULE_NP_WEBAPI", libs: ["np_webapi"]}
|
||||
# Media
|
||||
- {id: "SCE_SYSMODULE_MP4", libs: ["libscemp4"]}
|
||||
- {id: "SCE_SYSMODULE_AVPLAYER", libs: ["libsceavplayer", "libscemp4"]}
|
||||
- {id: "SCE_SYSMODULE_AVCDEC", libs: ["avcdec_for_player"]}
|
||||
- {id: "SCE_SYSMODULE_MP4_RECORDER", libs: ["libSceMp4Rec"]}
|
||||
- {id: "SCE_SYSMODULE_PHOTO_EXPORT", libs: ["libScePhotoExport"]}
|
||||
- {id: "SCE_SYSMODULE_VIDEO_EXPORT", libs: ["libSceVideoExport"]}
|
||||
- {id: "SCE_SYSMODULE_MUSIC_EXPORT", libs: ["libSceMusicExport"]}
|
||||
# Other
|
||||
- {id: "SCE_SYSMODULE_XML", libs: ["libSceXml"]}
|
||||
- {id: "SCE_SYSMODULE_JSON", libs: ["libSceJson"]}
|
||||
- {id: "SCE_SYSMODULE_SQLITE", libs: ["libSceSqlite"]}
|
||||
- {id: "SCE_SYSMODULE_RUDP", libs: ["librudp"]}
|
||||
- {id: "SCE_SYSMODULE_NET_ADHOC_MATCHING", libs: ["adhoc_matching"]}
|
||||
- {id: "SCE_SYSMODULE_PSPNET_ADHOC", libs: ["pspnet_adhoc"]}
|
||||
- {id: "SCE_SYSMODULE_FACE", libs: ["libface"]}
|
||||
- {id: "SCE_SYSMODULE_SMART", libs: ["libsmart"]}
|
||||
- {id: "SCE_SYSMODULE_MARLIN", libs: ["libmln"]}
|
||||
- {id: "SCE_SYSMODULE_MARLIN_DOWNLOADER", libs: ["libmlndownloader"]}
|
||||
- {id: "SCE_SYSMODULE_MARLIN_APP_LIB", libs: ["libmlnapplib"]}
|
||||
- {id: "SCE_SYSMODULE_TELEPHONY_UTIL", libs: ["libSceTelephonyUtil"]}
|
||||
- {id: "SCE_SYSMODULE_DTCP_IP", libs: ["libSceDtcpIp"]}
|
||||
- {id: "SCE_SYSMODULE_VIDEO_SEARCH_EMPR", libs: ["libSceVideoSearchEmpr"]}
|
||||
- {id: "SCE_SYSMODULE_BEISOBMF", libs: ["libSceBeisobmf"]}
|
||||
- {id: "SCE_SYSMODULE_BEMP2SYS", libs: ["libSceBemp2sys"]}
|
||||
- {id: "SCE_SYSMODULE_NEAR_UTIL", libs: ["libScenNearUtil"]}
|
||||
- {id: "SCE_SYSMODULE_NEAR_DIALOG_UTIL", libs: ["libSceNearDialogUtil"]}
|
||||
- {id: "SCE_SYSMODULE_LOCATION_EXTENSION", libs: ["liblocation_extension"]}
|
||||
- {id: "SCE_SYSMODULE_MAIL_API", libs: ["mail_api_for_local_libc"]}
|
||||
- {id: "SCE_SYSMODULE_TELEPORT_CLIENT", libs: ["libSceTeleportClient"]}
|
||||
- {id: "SCE_SYSMODULE_TELEPORT_SERVER", libs: ["libSceTeleportServer"]}
|
||||
- {id: "SCE_SYSMODULE_APPUTIL_EXT", libs: ["apputil_ext"]}
|
||||
- {id: "SCE_SYSMODULE_CODECENGINE_PERF", libs: ["libcodecengine_perf"]}
|
||||
|
||||
# Internal sysmodule mappings
|
||||
internal_modules:
|
||||
source_ref: "vita3k/module/src/load_module.cpp:114-136"
|
||||
modules:
|
||||
- {id: "SCE_SYSMODULE_INTERNAL_JPEG_ENC_ARM", libs: ["libscejpegencarm"]}
|
||||
- {id: "SCE_SYSMODULE_INTERNAL_AUDIOCODEC", libs: ["audiocodec"]}
|
||||
- {id: "SCE_SYSMODULE_INTERNAL_BXCE", libs: ["bXCe"]}
|
||||
- {id: "SCE_SYSMODULE_INTERNAL_INI_FILE_PROCESSOR", libs: ["ini_file_processor"]}
|
||||
- {id: "SCE_SYSMODULE_INTERNAL_NP_ACTIVITY_NET", libs: ["np_activity"]}
|
||||
- {id: "SCE_SYSMODULE_INTERNAL_PAF", libs: ["libpaf"]}
|
||||
- {id: "SCE_SYSMODULE_INTERNAL_SQLITE_VSH", libs: ["sqlite"]}
|
||||
- {id: "SCE_SYSMODULE_INTERNAL_DBUTIL", libs: ["dbutil"]}
|
||||
- {id: "SCE_SYSMODULE_INTERNAL_ACTIVITY_DB", libs: ["activity_db"]}
|
||||
- {id: "SCE_SYSMODULE_INTERNAL_COMMON_GUI_DIALOG", libs: ["common_gui_dialog"]}
|
||||
- {id: "SCE_SYSMODULE_INTERNAL_MSG_DIALOG", libs: ["libcdlg_msg"]}
|
||||
- {id: "SCE_SYSMODULE_INTERNAL_SAVEDATA_DIALOG", libs: ["libcdlg_savedata"]}
|
||||
- {id: "SCE_SYSMODULE_INTERNAL_IME_DIALOG", libs: ["libcdlg_ime"]}
|
||||
- {id: "SCE_SYSMODULE_INTERNAL_COMMON_DIALOG_MAIN", libs: ["libcdlg_main"]}
|
||||
- {id: "SCE_SYSMODULE_INTERNAL_DB_RECOVERY_UTILITY", libs: ["dbrecovery_utility"]}
|
||||
- {id: "SCE_SYSMODULE_INTERNAL_DRM_PSM_KDC", libs: ["psmkdc"]}
|
||||
- {id: "SCE_SYSMODULE_INTERNAL_LOCATION_INTERNAL", libs: ["liblocation_internal"]}
|
||||
|
||||
# IO device layout (full Vita filesystem)
|
||||
io_devices:
|
||||
source_ref: "vita3k/io/include/io/VitaIoDevice.h:22-50"
|
||||
firmware_partitions:
|
||||
- {device: "os0", purpose: "Core OS kernel modules"}
|
||||
- {device: "vs0", purpose: "System firmware modules and apps"}
|
||||
- {device: "sa0", purpose: "System assets (fonts)"}
|
||||
- {device: "pd0", purpose: "System data (BGM, resources)"}
|
||||
user_partitions:
|
||||
- {device: "ux0", purpose: "Main storage (memory card)"}
|
||||
- {device: "ur0", purpose: "Internal user storage"}
|
||||
- {device: "uma0", purpose: "USB mass storage (PSTV)"}
|
||||
- {device: "imc0", purpose: "Internal memory card (Slim)"}
|
||||
- {device: "grw0", purpose: "Game card (writable area)"}
|
||||
- {device: "gro0", purpose: "Game card (read-only area)"}
|
||||
app_partitions:
|
||||
- {device: "app0", purpose: "Current running application"}
|
||||
- {device: "addcont0", purpose: "Additional content (DLC)"}
|
||||
- {device: "savedata0", purpose: "Save data (slot 0)"}
|
||||
- {device: "savedata1", purpose: "Save data (slot 1)"}
|
||||
|
||||
# Fallback fonts when firmware is not installed
|
||||
fallback_fonts:
|
||||
source_ref: "vita3k/gui/src/gui.cpp:276-318"
|
||||
path: "data/fonts/"
|
||||
files:
|
||||
- {name: "mplus-1mn-bold.ttf", purpose: "Primary fallback monospaced font"}
|
||||
- {name: "SourceHanSansSC-Bold-Min.ttf", purpose: "Chinese fallback font"}
|
||||
- {name: "neodgm.ttf", purpose: "Korean fallback font"}
|
||||
note: "Open-source fonts bundled with Vita3K, used when firmware fonts (sa0) are not installed"
|
||||
Supplementary firmware font package. Populates sa0 partition with system
|
||||
fonts (PVF format) used by UI, LiveArea, and games via sceFt2/libpvf API.
|
||||
Vita3K bundles open-source fallback fonts (mplus-1mn-bold.ttf,
|
||||
SourceHanSansSC-Bold-Min.ttf, neodgm.ttf) when firmware fonts are missing.
|
||||
source_ref: "vita3k/gui/src/gui.cpp:228-267,276-318, vita3k/gui/src/initial_setup.cpp:96-97"
|
||||
|
||||
notes: |
|
||||
Vita3K requires the official PS Vita firmware (PSVUPDAT.PUP) from Sony for full
|
||||
compatibility. The firmware is decrypted using SCE keys and extracted into four
|
||||
partition images: os0 (kernel), vs0 (system), sa0 (assets), pd0 (data).
|
||||
|
||||
The most important firmware components are:
|
||||
1. vs0/sys/external/*.suprx - Firmware modules loaded by games
|
||||
2. sa0/data/font/pvf/*.pvf - System fonts (ltn0.pvf is checked at startup)
|
||||
3. vs0/data/internal/ - LiveArea resources and default themes
|
||||
|
||||
Vita3K uses a hybrid LLE/HLE approach:
|
||||
- Some modules (libc, libSceFt2, libpvf, libcdlg) are always loaded from firmware (LLE)
|
||||
- Others can be toggled between LLE and HLE per module via settings
|
||||
- Without firmware, many games will fail to load required modules
|
||||
|
||||
The module loading path is: first check app0:sce_module/{name}.suprx (game-bundled),
|
||||
then fall back to vs0:sys/external/{name}.suprx (firmware). This allows games to
|
||||
ship their own module versions.
|
||||
|
||||
CLI firmware install: vita3k --firmware /path/to/PSVUPDAT.PUP
|
||||
GUI: File > Install Firmware
|
||||
|
||||
Vita3K does not have a libretro core. It is standalone only.
|
||||
Standalone PS Vita emulator. No libretro core.
|
||||
Firmware installed via File > Install Firmware or CLI --firmware flag.
|
||||
PUP files validated by SCEUF magic header only (pup.cpp:119), no hash check.
|
||||
After install, four partitions are extracted:
|
||||
os0 (FAT, kernel modules), vs0 (FAT, system modules/apps),
|
||||
sa0 (FAT, fonts), pd0 (exFAT, system data/BGM).
|
||||
Module loading: app0:sce_module/{name}.suprx (game-bundled) then
|
||||
vs0:sys/external/{name}.suprx (firmware). Auto-LLE modules include
|
||||
libhttp, libssl, libult, libsas, libpgf, libfios2, libsystemgesture,
|
||||
libSceXml, libSceSqlite, librudp, libatrac, libface, libsmart,
|
||||
libsceavplayer, libSceJson, and more (load_module.cpp:142-161).
|
||||
A third optional preinst firmware PUP (pd0 partition: system BGM, resources)
|
||||
is available from Sony but not commonly required for game compatibility.
|
||||
|
||||
@@ -194,7 +194,7 @@ nav:
|
||||
- vitaQuakeII: emulators/vitaquake2.md
|
||||
- yabasanshiro: emulators/yabasanshiro.md
|
||||
- Yuzu: emulators/yuzu.md
|
||||
- Community forks (108):
|
||||
- Community forks (109):
|
||||
- EightyOne: emulators/81.md
|
||||
- a5200: emulators/a5200.md
|
||||
- Anarch: emulators/anarch.md
|
||||
@@ -236,6 +236,7 @@ nav:
|
||||
- Gambatte: emulators/gambatte.md
|
||||
- Genesis Plus GX: emulators/genesis_plus_gx.md
|
||||
- gpSP: emulators/gpsp.md
|
||||
- GSplus: emulators/gsplus.md
|
||||
- Handy: emulators/handy.md
|
||||
- higan (SFC Accuracy): emulators/higan_sfc.md
|
||||
- LRPS2: emulators/lrps2.md
|
||||
@@ -427,7 +428,7 @@ nav:
|
||||
- PCSX-ReARMed: emulators/pcsx_rearmed.md
|
||||
- Launchers (1):
|
||||
- Dolphin Launcher: emulators/dolphin_launcher.md
|
||||
- Other (25):
|
||||
- Other (24):
|
||||
- ares: emulators/ares.md
|
||||
- Beetle GBA (Mednafen): emulators/beetle_gba.md
|
||||
- BigPEmu: emulators/bigpemu.md
|
||||
@@ -436,7 +437,6 @@ nav:
|
||||
- Demul: emulators/demul.md
|
||||
- eka2l1: emulators/eka2l1.md
|
||||
- ep128emu-core: emulators/ep128emu.md
|
||||
- GSplus: emulators/gsplus.md
|
||||
- Lexaloffle: emulators/lexaloffle.md
|
||||
- Model 2 Emulator: emulators/model2.md
|
||||
- openMSX: emulators/openmsx.md
|
||||
|
||||
@@ -409,7 +409,7 @@ systems:
|
||||
required: true
|
||||
sha1: e5b2922ca137051059e4269b236d07a22c07bc84
|
||||
size: 524288
|
||||
nintendo-bsx:
|
||||
nintendo-satellaview:
|
||||
files:
|
||||
- name: Satellaview_BS-X.sfc
|
||||
destination: Satellaview_BS-X.sfc
|
||||
|
||||
@@ -6451,10 +6451,6 @@ systems:
|
||||
destination: bios/ROM_XEGAME
|
||||
required: false
|
||||
md5: d7eb37aec6960cba36bc500e0e5d00bc
|
||||
- name: ROM_400/800_CUSTOM
|
||||
destination: bios/ROM_400/800_CUSTOM
|
||||
required: false
|
||||
md5: a3e8d617c95d08031fe1b20d541434b2,7e5e4ce9508edef684ebe2c5a0e6f0d3
|
||||
- name: ROM_BASIC_A
|
||||
destination: bios/ROM_BASIC_A
|
||||
required: false
|
||||
|
||||
@@ -10,6 +10,7 @@ import hashlib
|
||||
import json
|
||||
import os
|
||||
import urllib.error
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
import zipfile
|
||||
import zlib
|
||||
@@ -32,27 +33,46 @@ def require_yaml():
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def compute_hashes(filepath: str | Path) -> dict[str, str]:
|
||||
"""Compute SHA1, MD5, SHA256, CRC32, Adler32 for a file."""
|
||||
sha1 = hashlib.sha1()
|
||||
md5 = hashlib.md5()
|
||||
sha256 = hashlib.sha256()
|
||||
_ALL_ALGORITHMS = frozenset({"sha1", "md5", "sha256", "crc32", "adler32"})
|
||||
|
||||
|
||||
def compute_hashes(
|
||||
filepath: str | Path,
|
||||
algorithms: frozenset[str] | None = None,
|
||||
) -> dict[str, str]:
|
||||
"""Compute file hashes. Pass *algorithms* to limit which are computed."""
|
||||
algos = algorithms or _ALL_ALGORITHMS
|
||||
sha1 = hashlib.sha1() if "sha1" in algos else None
|
||||
md5 = hashlib.md5() if "md5" in algos else None
|
||||
sha256 = hashlib.sha256() if "sha256" in algos else None
|
||||
do_crc = "crc32" in algos
|
||||
do_adler = "adler32" in algos
|
||||
crc = 0
|
||||
adler = 1 # zlib.adler32 initial value
|
||||
with open(filepath, "rb") as f:
|
||||
for chunk in iter(lambda: f.read(65536), b""):
|
||||
if sha1:
|
||||
sha1.update(chunk)
|
||||
if md5:
|
||||
md5.update(chunk)
|
||||
if sha256:
|
||||
sha256.update(chunk)
|
||||
if do_crc:
|
||||
crc = zlib.crc32(chunk, crc)
|
||||
if do_adler:
|
||||
adler = zlib.adler32(chunk, adler)
|
||||
return {
|
||||
"sha1": sha1.hexdigest(),
|
||||
"md5": md5.hexdigest(),
|
||||
"sha256": sha256.hexdigest(),
|
||||
"crc32": format(crc & 0xFFFFFFFF, "08x"),
|
||||
"adler32": format(adler & 0xFFFFFFFF, "08x"),
|
||||
}
|
||||
result: dict[str, str] = {}
|
||||
if sha1:
|
||||
result["sha1"] = sha1.hexdigest()
|
||||
if md5:
|
||||
result["md5"] = md5.hexdigest()
|
||||
if sha256:
|
||||
result["sha256"] = sha256.hexdigest()
|
||||
if do_crc:
|
||||
result["crc32"] = format(crc & 0xFFFFFFFF, "08x")
|
||||
if do_adler:
|
||||
result["adler32"] = format(adler & 0xFFFFFFFF, "08x")
|
||||
return result
|
||||
|
||||
|
||||
def load_database(db_path: str) -> dict:
|
||||
@@ -106,12 +126,20 @@ def parse_md5_list(raw: str) -> list[str]:
|
||||
return [m.strip().lower() for m in raw.split(",") if m.strip()] if raw else []
|
||||
|
||||
|
||||
_shared_yml_cache: dict[str, dict] = {}
|
||||
_platform_config_cache: dict[tuple[str, str], dict] = {}
|
||||
|
||||
|
||||
def load_platform_config(platform_name: str, platforms_dir: str = "platforms") -> dict:
|
||||
"""Load a platform config with inheritance and shared group resolution.
|
||||
|
||||
This is the SINGLE implementation used by generate_pack, generate_readme,
|
||||
verify, and auto_fetch. No other copy should exist.
|
||||
"""
|
||||
cache_key = (platform_name, os.path.realpath(platforms_dir))
|
||||
if cache_key in _platform_config_cache:
|
||||
return _platform_config_cache[cache_key]
|
||||
|
||||
if yaml is None:
|
||||
raise ImportError("PyYAML required: pip install pyyaml")
|
||||
|
||||
@@ -136,16 +164,14 @@ def load_platform_config(platform_name: str, platforms_dir: str = "platforms") -
|
||||
merged["systems"][sys_id] = override
|
||||
config = merged
|
||||
|
||||
# Resolve shared group includes (cached to avoid re-parsing per call)
|
||||
# Resolve shared group includes
|
||||
shared_path = os.path.join(platforms_dir, "_shared.yml")
|
||||
if os.path.exists(shared_path):
|
||||
if not hasattr(load_platform_config, "_shared_cache"):
|
||||
load_platform_config._shared_cache = {}
|
||||
cache_key = os.path.realpath(shared_path)
|
||||
if cache_key not in load_platform_config._shared_cache:
|
||||
shared_real = os.path.realpath(shared_path)
|
||||
if shared_real not in _shared_yml_cache:
|
||||
with open(shared_path) as f:
|
||||
load_platform_config._shared_cache[cache_key] = yaml.safe_load(f) or {}
|
||||
shared = load_platform_config._shared_cache[cache_key]
|
||||
_shared_yml_cache[shared_real] = yaml.safe_load(f) or {}
|
||||
shared = _shared_yml_cache[shared_real]
|
||||
shared_groups = shared.get("shared_groups", {})
|
||||
for system in config.get("systems", {}).values():
|
||||
for group_name in system.get("includes", []):
|
||||
@@ -165,6 +191,7 @@ def load_platform_config(platform_name: str, platforms_dir: str = "platforms") -
|
||||
system.setdefault("files", []).append(gf)
|
||||
existing.add(key)
|
||||
|
||||
_platform_config_cache[cache_key] = config
|
||||
return config
|
||||
|
||||
|
||||
@@ -444,7 +471,7 @@ def resolve_local_file(
|
||||
if valid:
|
||||
primary = [p for p, _ in valid if "/.variants/" not in p]
|
||||
return (primary[0] if primary else valid[0][0]), "hash_mismatch"
|
||||
# No candidate contains the zipped_file — fall through to step 5
|
||||
# No candidate contains the zipped_file -fall through to step 5
|
||||
else:
|
||||
primary = [p for p, _ in candidates if "/.variants/" not in p]
|
||||
return (primary[0] if primary else candidates[0][0]), "hash_mismatch"
|
||||
@@ -485,41 +512,45 @@ def resolve_local_file(
|
||||
candidate = os.path.join(cache_dir, try_name)
|
||||
if os.path.isfile(candidate):
|
||||
return candidate, "data_dir"
|
||||
# Basename walk: find file anywhere in cache tree
|
||||
# Basename walk: find file anywhere in cache tree (case-insensitive)
|
||||
basename_targets = {
|
||||
(n.rsplit("/", 1)[-1] if "/" in n else n)
|
||||
(n.rsplit("/", 1)[-1] if "/" in n else n).casefold()
|
||||
for n in names_to_try
|
||||
}
|
||||
for root, _dirs, fnames in os.walk(cache_dir):
|
||||
for fn in fnames:
|
||||
if fn in basename_targets:
|
||||
if fn.casefold() in basename_targets:
|
||||
return os.path.join(root, fn), "data_dir"
|
||||
|
||||
return None, "not_found"
|
||||
|
||||
|
||||
_mame_clone_map_cache: dict[str, str] | None = None
|
||||
|
||||
|
||||
def _get_mame_clone_map() -> dict[str, str]:
|
||||
"""Load and cache the MAME clone map (clone_name -> canonical_name)."""
|
||||
if not hasattr(_get_mame_clone_map, "_cache"):
|
||||
global _mame_clone_map_cache
|
||||
if _mame_clone_map_cache is not None:
|
||||
return _mame_clone_map_cache
|
||||
clone_path = os.path.join(
|
||||
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
|
||||
"_mame_clones.json",
|
||||
)
|
||||
if os.path.exists(clone_path):
|
||||
import json as _json
|
||||
with open(clone_path) as f:
|
||||
data = _json.load(f)
|
||||
_get_mame_clone_map._cache = {}
|
||||
data = json.load(f)
|
||||
_mame_clone_map_cache = {}
|
||||
for canonical, info in data.items():
|
||||
for clone in info.get("clones", []):
|
||||
_get_mame_clone_map._cache[clone] = canonical
|
||||
_mame_clone_map_cache[clone] = canonical
|
||||
else:
|
||||
_get_mame_clone_map._cache = {}
|
||||
return _get_mame_clone_map._cache
|
||||
_mame_clone_map_cache = {}
|
||||
return _mame_clone_map_cache
|
||||
|
||||
|
||||
def check_inside_zip(container: str, file_name: str, expected_md5: str) -> str:
|
||||
"""Check a ROM inside a ZIP — replicates Batocera checkInsideZip().
|
||||
"""Check a ROM inside a ZIP -replicates Batocera checkInsideZip().
|
||||
|
||||
Returns "ok", "untested", "not_in_zip", or "error".
|
||||
"""
|
||||
@@ -540,13 +571,32 @@ def check_inside_zip(container: str, file_name: str, expected_md5: str) -> str:
|
||||
return "error"
|
||||
|
||||
|
||||
_zip_contents_cache: tuple[frozenset[tuple[str, float]], dict] | None = None
|
||||
|
||||
|
||||
def build_zip_contents_index(db: dict, max_entry_size: int = 512 * 1024 * 1024) -> dict:
|
||||
"""Build {inner_rom_md5: zip_file_sha1} for ROMs inside ZIP files."""
|
||||
index: dict[str, str] = {}
|
||||
"""Build {inner_rom_md5: zip_file_sha1} for ROMs inside ZIP files.
|
||||
|
||||
Results are cached in-process; repeated calls with unchanged ZIPs return
|
||||
the cached index.
|
||||
"""
|
||||
global _zip_contents_cache
|
||||
|
||||
# Build fingerprint from ZIP paths + mtimes for cache invalidation
|
||||
zip_entries: list[tuple[str, str]] = []
|
||||
for sha1, entry in db.get("files", {}).items():
|
||||
path = entry["path"]
|
||||
if not path.endswith(".zip") or not os.path.exists(path):
|
||||
continue
|
||||
if path.endswith(".zip") and os.path.exists(path):
|
||||
zip_entries.append((path, sha1))
|
||||
|
||||
fingerprint = frozenset(
|
||||
(path, os.path.getmtime(path)) for path, _ in zip_entries
|
||||
)
|
||||
if _zip_contents_cache is not None and _zip_contents_cache[0] == fingerprint:
|
||||
return _zip_contents_cache[1]
|
||||
|
||||
index: dict[str, str] = {}
|
||||
for path, sha1 in zip_entries:
|
||||
try:
|
||||
with zipfile.ZipFile(path, "r") as zf:
|
||||
for info in zf.infolist():
|
||||
@@ -559,6 +609,8 @@ def build_zip_contents_index(db: dict, max_entry_size: int = 512 * 1024 * 1024)
|
||||
index[h.hexdigest()] = sha1
|
||||
except (zipfile.BadZipFile, OSError):
|
||||
continue
|
||||
|
||||
_zip_contents_cache = (fingerprint, index)
|
||||
return index
|
||||
|
||||
|
||||
@@ -713,7 +765,7 @@ MANUFACTURER_PREFIXES = (
|
||||
"snk-", "panasonic-", "nec-", "epoch-", "mattel-", "fairchild-",
|
||||
"hartung-", "tiger-", "magnavox-", "philips-", "bandai-", "casio-",
|
||||
"coleco-", "commodore-", "sharp-", "sinclair-", "atari-", "sammy-",
|
||||
"gce-", "texas-instruments-",
|
||||
"gce-", "interton-", "texas-instruments-",
|
||||
)
|
||||
|
||||
|
||||
@@ -732,14 +784,31 @@ def derive_manufacturer(system_id: str, system_data: dict) -> str:
|
||||
return "Other"
|
||||
|
||||
|
||||
# Abbreviations that normalization alone cannot resolve.
|
||||
# Maps platform-specific short names to canonical profile system IDs.
|
||||
SYSTEM_ALIASES: dict[str, str] = {
|
||||
"gmaster": "hartung-game-master",
|
||||
"n64dd": "nintendo-64dd",
|
||||
"neogeo64": "hyper-neogeo64",
|
||||
"psvita": "sony-playstation-vita",
|
||||
# Platform IDs missing the manufacturer-prefix hyphen
|
||||
"atari5200": "atari-5200",
|
||||
"atari7800": "atari-7800",
|
||||
"atarist": "atari-st",
|
||||
"sega32x": "sega-32x",
|
||||
"segastv": "sega-stv",
|
||||
}
|
||||
|
||||
|
||||
def _norm_system_id(sid: str) -> str:
|
||||
"""Normalize system ID for cross-platform matching.
|
||||
|
||||
Strips manufacturer prefixes and separators so that platform-specific
|
||||
IDs (e.g., "xbox", "nintendo-wiiu") match profile IDs
|
||||
(e.g., "microsoft-xbox", "nintendo-wii-u").
|
||||
Resolves known aliases, then strips manufacturer prefixes and separators
|
||||
so that platform-specific IDs (e.g., "xbox", "nintendo-wiiu") match
|
||||
profile IDs (e.g., "microsoft-xbox", "nintendo-wii-u").
|
||||
"""
|
||||
s = sid.lower().replace("_", "-")
|
||||
s = SYSTEM_ALIASES.get(s, s)
|
||||
for prefix in MANUFACTURER_PREFIXES:
|
||||
if s.startswith(prefix):
|
||||
s = s[len(prefix):]
|
||||
@@ -800,20 +869,20 @@ def filter_systems_by_target(
|
||||
plat_cores_here = norm_plat_system_cores.get(norm_key, set())
|
||||
|
||||
if not all_cores and not plat_cores_here:
|
||||
# No profile maps to this system — keep it
|
||||
# No profile maps to this system -keep it
|
||||
filtered[sys_id] = sys_data
|
||||
elif all_cores & expanded_target:
|
||||
# At least one core is on the target
|
||||
filtered[sys_id] = sys_data
|
||||
elif not plat_cores_here:
|
||||
# Platform resolution didn't find cores for this system — keep it
|
||||
# Platform resolution didn't find cores for this system -keep it
|
||||
filtered[sys_id] = sys_data
|
||||
# else: known cores exist but none are on the target — exclude
|
||||
# else: known cores exist but none are on the target -exclude
|
||||
return filtered
|
||||
|
||||
|
||||
|
||||
# Validation and mode filtering — extracted to validation.py for SoC.
|
||||
# Validation and mode filtering -extracted to validation.py for SoC.
|
||||
# Re-exported below for backward compatibility.
|
||||
|
||||
|
||||
@@ -842,31 +911,35 @@ def fetch_large_file(name: str, dest_dir: str = LARGE_FILES_CACHE,
|
||||
else:
|
||||
return cached
|
||||
|
||||
encoded_name = urllib.request.quote(name)
|
||||
encoded_name = urllib.parse.quote(name)
|
||||
url = f"https://github.com/{LARGE_FILES_REPO}/releases/download/{LARGE_FILES_RELEASE}/{encoded_name}"
|
||||
os.makedirs(dest_dir, exist_ok=True)
|
||||
tmp_path = cached + ".tmp"
|
||||
try:
|
||||
req = urllib.request.Request(url, headers={"User-Agent": "retrobios/1.0"})
|
||||
with urllib.request.urlopen(req, timeout=300) as resp:
|
||||
os.makedirs(dest_dir, exist_ok=True)
|
||||
with open(cached, "wb") as f:
|
||||
with open(tmp_path, "wb") as f:
|
||||
while True:
|
||||
chunk = resp.read(65536)
|
||||
if not chunk:
|
||||
break
|
||||
f.write(chunk)
|
||||
except (urllib.error.URLError, urllib.error.HTTPError):
|
||||
if os.path.exists(tmp_path):
|
||||
os.unlink(tmp_path)
|
||||
return None
|
||||
|
||||
if expected_sha1 or expected_md5:
|
||||
hashes = compute_hashes(cached)
|
||||
hashes = compute_hashes(tmp_path)
|
||||
if expected_sha1 and hashes["sha1"].lower() != expected_sha1.lower():
|
||||
os.unlink(cached)
|
||||
os.unlink(tmp_path)
|
||||
return None
|
||||
if expected_md5:
|
||||
md5_list = [m.strip().lower() for m in expected_md5.split(",") if m.strip()]
|
||||
if hashes["md5"].lower() not in md5_list:
|
||||
os.unlink(cached)
|
||||
os.unlink(tmp_path)
|
||||
return None
|
||||
os.replace(tmp_path, cached)
|
||||
return cached
|
||||
|
||||
|
||||
@@ -921,12 +994,31 @@ def list_platform_system_ids(platform_name: str, platforms_dir: str) -> None:
|
||||
|
||||
|
||||
|
||||
# Re-exports: validation and truth modules extracted for SoC.
|
||||
# Existing consumers import from common — these preserve that contract.
|
||||
from validation import ( # noqa: F401, E402
|
||||
_build_validation_index, _parse_validation, build_ground_truth,
|
||||
check_file_validation, filter_files_by_mode, validate_cli_modes,
|
||||
)
|
||||
from truth import ( # noqa: F401, E402
|
||||
diff_platform_truth, generate_platform_truth,
|
||||
)
|
||||
def build_target_cores_cache(
|
||||
platforms: list[str],
|
||||
target: str,
|
||||
platforms_dir: str,
|
||||
is_all: bool = False,
|
||||
) -> tuple[dict[str, set[str] | None], list[str]]:
|
||||
"""Build target cores cache for a list of platforms.
|
||||
|
||||
Returns (cache dict, list of platforms to keep after skipping failures).
|
||||
"""
|
||||
cache: dict[str, set[str] | None] = {}
|
||||
skip: list[str] = []
|
||||
for p in platforms:
|
||||
try:
|
||||
cache[p] = load_target_config(p, target, platforms_dir)
|
||||
except FileNotFoundError:
|
||||
if is_all:
|
||||
cache[p] = None
|
||||
else:
|
||||
raise
|
||||
except ValueError as e:
|
||||
if is_all:
|
||||
print(f"INFO: Skipping {p}: {e}")
|
||||
skip.append(p)
|
||||
else:
|
||||
raise
|
||||
kept = [p for p in platforms if p not in skip]
|
||||
return cache, kept
|
||||
|
||||
@@ -23,9 +23,7 @@ from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Key file parsing (keys.txt / aes_keys.txt format)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def parse_keys_file(path: str | Path) -> dict[str, dict[str, bytes]]:
|
||||
"""Parse a 3DS keys file with :AES, :RSA, :ECC sections.
|
||||
@@ -67,9 +65,7 @@ def find_keys_file(bios_dir: str | Path) -> Path | None:
|
||||
return None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Pure Python RSA-2048 PKCS1v15 SHA256 verification (zero dependencies)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _rsa_verify_pkcs1v15_sha256(
|
||||
message: bytes,
|
||||
@@ -79,7 +75,7 @@ def _rsa_verify_pkcs1v15_sha256(
|
||||
) -> bool:
|
||||
"""Verify RSA-2048 PKCS#1 v1.5 with SHA-256.
|
||||
|
||||
Pure Python — uses Python's native int for modular exponentiation.
|
||||
Pure Python -uses Python's native int for modular exponentiation.
|
||||
Reproduces CryptoPP::RSASS<PKCS1v15, SHA256>::Verifier.
|
||||
"""
|
||||
n = int.from_bytes(modulus, "big")
|
||||
@@ -124,9 +120,7 @@ def _rsa_verify_pkcs1v15_sha256(
|
||||
return em == expected_em
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# AES-128-CBC decryption (with fallback)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _aes_128_cbc_decrypt(data: bytes, key: bytes, iv: bytes) -> bytes:
|
||||
"""Decrypt AES-128-CBC without padding."""
|
||||
@@ -166,9 +160,7 @@ def _aes_128_cbc_decrypt(data: bytes, key: bytes, iv: bytes) -> bytes:
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# File verification functions
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def verify_secure_info_a(
|
||||
filepath: str | Path,
|
||||
@@ -347,7 +339,7 @@ def verify_otp(
|
||||
if computed_hash != stored_hash:
|
||||
return False, "SHA-256 hash mismatch (OTP corrupted)"
|
||||
|
||||
# --- ECC certificate verification (sect233r1) ---
|
||||
# ECC certificate verification (sect233r1)
|
||||
ecc_keys = keys.get("ECC", {})
|
||||
root_public_xy = ecc_keys.get("rootPublicXY")
|
||||
if not root_public_xy or len(root_public_xy) != 60:
|
||||
@@ -414,9 +406,7 @@ def verify_otp(
|
||||
return False, "decrypted, magic+SHA256 valid, but ECC cert signature invalid"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Unified verification interface for verify.py
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Map from (filename, validation_type) to verification function
|
||||
_CRYPTO_VERIFIERS: dict[str, Callable] = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Deduplicate bios/ directory — keep one canonical file per unique content.
|
||||
"""Deduplicate bios/ directory -keep one canonical file per unique content.
|
||||
|
||||
Usage:
|
||||
python scripts/dedup.py [--dry-run] [--bios-dir bios]
|
||||
@@ -11,7 +11,7 @@ Two types of deduplication:
|
||||
|
||||
2. MAME DEVICE CLONES: Different filenames with identical content in the same
|
||||
MAME directory (e.g., bbc_m87.zip and bbc_24bbc.zip are identical ZIPs).
|
||||
These are NOT aliases — MAME loads each by its unique name. Instead of
|
||||
These are NOT aliases -MAME loads each by its unique name. Instead of
|
||||
deleting, we create a _mame_clones.json mapping so generate_pack.py can
|
||||
pack all names from a single canonical file.
|
||||
|
||||
@@ -94,7 +94,7 @@ def deduplicate(bios_dir: str, dry_run: bool = False) -> dict:
|
||||
if len(paths) <= 1:
|
||||
continue
|
||||
|
||||
# Separate by filename — same name = true duplicate, different name = clone
|
||||
# Separate by filename -same name = true duplicate, different name = clone
|
||||
by_name: dict[str, list[str]] = defaultdict(list)
|
||||
for p in paths:
|
||||
by_name[os.path.basename(p)].append(p)
|
||||
@@ -106,7 +106,7 @@ def deduplicate(bios_dir: str, dry_run: bool = False) -> dict:
|
||||
name_paths.sort(key=path_priority)
|
||||
true_dupes_to_remove.extend(name_paths[1:])
|
||||
|
||||
# Different filenames, same content — need special handling
|
||||
# Different filenames, same content -need special handling
|
||||
unique_names = sorted(by_name.keys())
|
||||
if len(unique_names) > 1:
|
||||
# Check if these are all in MAME/Arcade dirs AND all ZIPs
|
||||
@@ -133,7 +133,7 @@ def deduplicate(bios_dir: str, dry_run: bool = False) -> dict:
|
||||
true_dupes_to_remove.append(p)
|
||||
else:
|
||||
# Non-MAME different names (e.g., 64DD_IPL_US.n64 vs IPL_USA.n64)
|
||||
# Keep ALL — each name may be needed by a different emulator
|
||||
# Keep ALL -each name may be needed by a different emulator
|
||||
# Only remove true duplicates (same name in multiple dirs)
|
||||
pass
|
||||
|
||||
@@ -143,7 +143,7 @@ def deduplicate(bios_dir: str, dry_run: bool = False) -> dict:
|
||||
# Find the best canonical across all paths
|
||||
all_paths = [p for p in paths if p not in true_dupes_to_remove]
|
||||
if not all_paths:
|
||||
# All copies were marked for removal — keep the best one
|
||||
# All copies were marked for removal -keep the best one
|
||||
all_paths_sorted = sorted(paths, key=path_priority)
|
||||
all_paths = [all_paths_sorted[0]]
|
||||
true_dupes_to_remove = [p for p in paths if p != all_paths[0]]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""Deterministic ZIP builder for MAME BIOS archives.
|
||||
|
||||
Creates byte-identical ZIP files from individual ROM atoms, enabling:
|
||||
- Reproducible builds: same ROMs → same ZIP hash, always
|
||||
- Reproducible builds: same ROMs -> same ZIP hash, always
|
||||
- Version-agnostic assembly: build neogeo.zip for any MAME version
|
||||
- Deduplication: store ROM atoms once, assemble any ZIP on demand
|
||||
|
||||
|
||||
@@ -141,8 +141,8 @@ def scan_bios_dir(bios_dir: Path, cache: dict, force: bool) -> tuple[dict, dict,
|
||||
def _path_suffix(rel_path: str) -> str:
|
||||
"""Extract the path suffix after bios/Manufacturer/Console/.
|
||||
|
||||
bios/Nintendo/GameCube/GC/USA/IPL.bin → GC/USA/IPL.bin
|
||||
bios/Sony/PlayStation/scph5501.bin → scph5501.bin
|
||||
bios/Nintendo/GameCube/GC/USA/IPL.bin -> GC/USA/IPL.bin
|
||||
bios/Sony/PlayStation/scph5501.bin -> scph5501.bin
|
||||
"""
|
||||
parts = rel_path.replace("\\", "/").split("/")
|
||||
# Skip: bios / Manufacturer / Console (3 segments)
|
||||
|
||||
@@ -27,9 +27,9 @@ from pathlib import Path
|
||||
sys.path.insert(0, os.path.dirname(__file__))
|
||||
from common import (
|
||||
MANUFACTURER_PREFIXES,
|
||||
build_zip_contents_index, check_inside_zip, compute_hashes,
|
||||
fetch_large_file, group_identical_platforms, list_emulator_profiles,
|
||||
list_platform_system_ids, list_registered_platforms,
|
||||
build_target_cores_cache, build_zip_contents_index, check_inside_zip,
|
||||
compute_hashes, fetch_large_file, group_identical_platforms,
|
||||
list_emulator_profiles, list_platform_system_ids, list_registered_platforms,
|
||||
filter_systems_by_target, list_system_ids, load_database,
|
||||
load_data_dir_registry, load_emulator_profiles, load_platform_config,
|
||||
md5_composite, require_yaml, resolve_local_file,
|
||||
@@ -248,7 +248,7 @@ def resolve_file(file_entry: dict, db: dict, bios_dir: str,
|
||||
if path and status != "hash_mismatch":
|
||||
return path, status
|
||||
|
||||
# Large files from GitHub release assets — tried when local file is
|
||||
# Large files from GitHub release assets -tried when local file is
|
||||
# missing OR has a hash mismatch (wrong variant on disk)
|
||||
name = file_entry.get("name", "")
|
||||
sha1 = file_entry.get("sha1")
|
||||
@@ -362,7 +362,7 @@ def _collect_emulator_extras(
|
||||
# Second pass: find alternative destinations for files already in the pack.
|
||||
# A file declared by the platform or emitted above may also be needed at a
|
||||
# different path by another core (e.g. neocd/ vs root, same_cdi/bios/ vs root).
|
||||
# Only adds a copy when the file is ALREADY covered at a different path —
|
||||
# Only adds a copy when the file is ALREADY covered at a different path -
|
||||
# never introduces a file that wasn't selected by the first pass.
|
||||
profiles = emu_profiles if emu_profiles is not None else load_emulator_profiles(emulators_dir)
|
||||
relevant = resolve_platform_cores(config, profiles, target_cores=target_cores)
|
||||
@@ -429,6 +429,202 @@ def _collect_emulator_extras(
|
||||
return extras
|
||||
|
||||
|
||||
def _build_readme(platform_name: str, platform_display: str,
|
||||
base_dest: str, total_files: int, num_systems: int) -> str:
|
||||
"""Build a personalized step-by-step README for each platform pack."""
|
||||
sep = "=" * 50
|
||||
header = (
|
||||
f"{sep}\n"
|
||||
f" RETROBIOS - {platform_display} BIOS Pack\n"
|
||||
f" {total_files} files for {num_systems} systems\n"
|
||||
f"{sep}\n\n"
|
||||
)
|
||||
|
||||
guides: dict[str, str] = {
|
||||
"retroarch": (
|
||||
"INSTALLATION GUIDE\n\n"
|
||||
" Option A: Automatic (recommended)\n"
|
||||
" ---------------------------------\n"
|
||||
" Run this in a terminal:\n\n"
|
||||
" curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh\n\n"
|
||||
" The script auto-detects your RetroArch install and copies\n"
|
||||
" files to the correct location.\n\n"
|
||||
" Option B: Manual (PC)\n"
|
||||
" ---------------------\n"
|
||||
" 1. Find your RetroArch system directory:\n"
|
||||
" - RetroArch > Settings > Directory > System/BIOS\n"
|
||||
" - Default: retroarch/system/\n"
|
||||
" 2. Open the \"system\" folder from this archive\n"
|
||||
" 3. Copy ALL contents into your system directory\n"
|
||||
" 4. Overwrite if asked\n\n"
|
||||
" Option C: Manual (handheld / SD card)\n"
|
||||
" -------------------------------------\n"
|
||||
" Anbernic, Retroid, Miyoo, Trimui, etc.:\n"
|
||||
" 1. Connect your SD card to your PC\n"
|
||||
" 2. Find the BIOS folder (usually BIOS/ or system/)\n"
|
||||
" 3. Copy ALL contents of \"system\" from this archive\n"
|
||||
" 4. Eject SD card and reboot your device\n\n"
|
||||
" Common paths by device:\n"
|
||||
" Anbernic (ArkOS/JELOS): BIOS/\n"
|
||||
" Retroid (RetroArch): RetroArch/system/\n"
|
||||
" Miyoo Mini (Onion OS): BIOS/\n"
|
||||
" Steam Deck (RetroArch): ~/.config/retroarch/system/\n\n"
|
||||
),
|
||||
"batocera": (
|
||||
"INSTALLATION GUIDE\n\n"
|
||||
" Option A: Automatic (recommended)\n"
|
||||
" ---------------------------------\n"
|
||||
" Open a terminal (F1 from Batocera menu) and run:\n\n"
|
||||
" curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh\n\n"
|
||||
" Option B: Manual (network share)\n"
|
||||
" --------------------------------\n"
|
||||
" 1. On your PC, open the Batocera network share:\n"
|
||||
" - Windows: \\\\BATOCERA\\share\\bios\\\n"
|
||||
" - Mac/Linux: smb://batocera/share/bios/\n"
|
||||
" 2. Open the \"bios\" folder from this archive\n"
|
||||
" 3. Copy ALL contents into the share\n"
|
||||
" 4. Overwrite if asked\n\n"
|
||||
" Option C: Manual (SD card)\n"
|
||||
" --------------------------\n"
|
||||
" 1. Put the SD card in your PC\n"
|
||||
" 2. Navigate to /userdata/bios/ on the SHARE partition\n"
|
||||
" 3. Copy ALL contents of \"bios\" from this archive\n\n"
|
||||
" NOTE: Dreamcast flash memory is named dc_nvmem.bin\n"
|
||||
" (if your setup asks for dc_flash.bin, same file).\n\n"
|
||||
),
|
||||
"recalbox": (
|
||||
"INSTALLATION GUIDE\n\n"
|
||||
" Option A: Automatic\n"
|
||||
" -------------------\n"
|
||||
" curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh\n\n"
|
||||
" Option B: Manual (network share)\n"
|
||||
" --------------------------------\n"
|
||||
" 1. On your PC, open the Recalbox network share:\n"
|
||||
" - Windows: \\\\RECALBOX\\share\\bios\\\n"
|
||||
" - Mac/Linux: smb://recalbox/share/bios/\n"
|
||||
" 2. Open the \"bios\" folder from this archive\n"
|
||||
" 3. Copy ALL contents into the share\n\n"
|
||||
" Option C: Manual (SD card)\n"
|
||||
" --------------------------\n"
|
||||
" 1. Put the SD card in your PC\n"
|
||||
" 2. Navigate to /recalbox/share/bios/\n"
|
||||
" 3. Copy ALL contents of \"bios\" from this archive\n\n"
|
||||
),
|
||||
"emudeck": (
|
||||
"INSTALLATION GUIDE (Steam Deck / Linux)\n\n"
|
||||
" Option A: Automatic (recommended)\n"
|
||||
" ---------------------------------\n"
|
||||
" Open Konsole (or any terminal) and run:\n\n"
|
||||
" curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh\n\n"
|
||||
" The script places BIOS files AND sets up standalone\n"
|
||||
" emulator keys automatically.\n\n"
|
||||
" Option B: Manual\n"
|
||||
" ----------------\n"
|
||||
" 1. Open Dolphin file manager\n"
|
||||
" 2. Navigate to ~/Emulation/bios/\n"
|
||||
" 3. Open the \"bios\" folder from this archive\n"
|
||||
" 4. Copy ALL contents into ~/Emulation/bios/\n\n"
|
||||
" STANDALONE EMULATORS (extra step)\n"
|
||||
" Switch and 3DS emulators need keys in specific folders:\n"
|
||||
" prod.keys -> ~/.local/share/yuzu/keys/\n"
|
||||
" prod.keys -> ~/.local/share/eden/keys/\n"
|
||||
" prod.keys -> ~/.config/Ryujinx/system/\n"
|
||||
" aes_keys.txt -> ~/Emulation/bios/citra/keys/\n"
|
||||
" The automatic installer handles this for you.\n\n"
|
||||
),
|
||||
"retrodeck": (
|
||||
"INSTALLATION GUIDE (Steam Deck / Linux)\n\n"
|
||||
" Option A: Automatic (recommended)\n"
|
||||
" ---------------------------------\n"
|
||||
" Open Konsole (or any terminal) and run:\n\n"
|
||||
" curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh\n\n"
|
||||
" Option B: Manual\n"
|
||||
" ----------------\n"
|
||||
" 1. Open Dolphin file manager\n"
|
||||
" 2. Show hidden files (Ctrl+H)\n"
|
||||
" 3. Navigate to ~/retrodeck/bios/\n"
|
||||
" 4. Open this archive and go into the top-level folder\n"
|
||||
" 5. Copy ALL contents into ~/retrodeck/bios/\n\n"
|
||||
" NOTE: RetroDECK uses its own BIOS checker. After\n"
|
||||
" copying, open RetroDECK > Tools > BIOS Checker to\n"
|
||||
" verify everything is detected.\n\n"
|
||||
),
|
||||
"retrobat": (
|
||||
"INSTALLATION GUIDE (Windows)\n\n"
|
||||
" Option A: Automatic (recommended)\n"
|
||||
" ---------------------------------\n"
|
||||
" Download and run install.bat from:\n"
|
||||
" https://github.com/Abdess/retrobios/releases\n\n"
|
||||
" Option B: Manual\n"
|
||||
" ----------------\n"
|
||||
" 1. Open your RetroBat installation folder\n"
|
||||
" 2. Navigate to the bios\\ subfolder\n"
|
||||
" (default: C:\\RetroBat\\bios\\)\n"
|
||||
" 3. Open the \"bios\" folder from this archive\n"
|
||||
" 4. Copy ALL contents into your bios\\ folder\n"
|
||||
" 5. Overwrite if asked\n\n"
|
||||
),
|
||||
"bizhawk": (
|
||||
"INSTALLATION GUIDE\n\n"
|
||||
" 1. Open your BizHawk installation folder\n"
|
||||
" 2. Navigate to the Firmware subfolder:\n"
|
||||
" - Windows: BizHawk\\Firmware\\\n"
|
||||
" - Linux: ~/.config/BizHawk/Firmware/\n"
|
||||
" 3. Open the \"Firmware\" folder from this archive\n"
|
||||
" 4. Copy ALL contents into your Firmware folder\n"
|
||||
" 5. In BizHawk: Config > Paths > Firmware should\n"
|
||||
" point to this folder\n\n"
|
||||
),
|
||||
"romm": (
|
||||
"INSTALLATION GUIDE (RomM server)\n\n"
|
||||
" 1. Locate your RomM library folder\n"
|
||||
" 2. Navigate to the bios/ subdirectory\n"
|
||||
" 3. Copy ALL contents of \"bios\" from this archive\n"
|
||||
" 4. Restart the RomM service to detect new files\n\n"
|
||||
),
|
||||
"retropie": (
|
||||
"INSTALLATION GUIDE (Raspberry Pi)\n\n"
|
||||
" Option A: Via network share\n"
|
||||
" --------------------------\n"
|
||||
" 1. On your PC, open: \\\\RETROPIE\\bios\\\n"
|
||||
" 2. Copy ALL contents of \"BIOS\" from this archive\n\n"
|
||||
" Option B: Via SSH\n"
|
||||
" -----------------\n"
|
||||
" 1. SSH into your Pi: ssh pi@retropie\n"
|
||||
" 2. Copy files to ~/RetroPie/BIOS/\n\n"
|
||||
" Option C: Via SD card\n"
|
||||
" ---------------------\n"
|
||||
" 1. Put the SD card in your PC\n"
|
||||
" 2. Navigate to /home/pi/RetroPie/BIOS/\n"
|
||||
" 3. Copy ALL contents of \"BIOS\" from this archive\n\n"
|
||||
),
|
||||
}
|
||||
|
||||
# Lakka uses same guide as RetroArch
|
||||
guides["lakka"] = guides["retroarch"]
|
||||
|
||||
guide = guides.get(platform_name, (
|
||||
f"INSTALLATION\n\n"
|
||||
f" 1. Open the \"{base_dest or 'files'}\" folder in this archive\n"
|
||||
f" 2. Copy ALL contents to your BIOS directory\n"
|
||||
f" 3. Overwrite if asked\n\n"
|
||||
))
|
||||
|
||||
footer = (
|
||||
"TROUBLESHOOTING\n\n"
|
||||
" - Core says BIOS missing? Check the exact filename\n"
|
||||
" and make sure it's in the right subfolder.\n"
|
||||
" - Wrong region? Some systems have regional BIOS\n"
|
||||
" variants (USA/EUR/JAP). All are included.\n"
|
||||
" - Need help? https://github.com/Abdess/retrobios/issues\n\n"
|
||||
f"{sep}\n"
|
||||
f" https://github.com/Abdess/retrobios\n"
|
||||
f"{sep}\n"
|
||||
)
|
||||
|
||||
return header + guide + footer
|
||||
|
||||
|
||||
def generate_pack(
|
||||
platform_name: str,
|
||||
platforms_dir: str,
|
||||
@@ -635,7 +831,7 @@ def generate_pack(
|
||||
|
||||
# Emulator-level validation: informational only for platform packs.
|
||||
# Platform verification (existence/md5) is the authority for pack status.
|
||||
# Emulator checks are supplementary — logged but don't downgrade.
|
||||
# Emulator checks are supplementary -logged but don't downgrade.
|
||||
# When a discrepancy is found, try to find a file satisfying both.
|
||||
if (file_status.get(dedup_key) == "ok"
|
||||
and local_path and validation_index):
|
||||
@@ -696,7 +892,7 @@ def generate_pack(
|
||||
if base_dest:
|
||||
full_dest = f"{base_dest}/{dest}"
|
||||
elif "/" not in dest:
|
||||
# Bare filename with empty base_destination — infer bios/ prefix
|
||||
# Bare filename with empty base_destination -infer bios/ prefix
|
||||
# to match platform conventions (RetroDECK: ~/retrodeck/bios/)
|
||||
full_dest = f"bios/{dest}"
|
||||
else:
|
||||
@@ -740,7 +936,7 @@ def generate_pack(
|
||||
continue
|
||||
local_path = entry.get("local_cache", "")
|
||||
if not local_path or not os.path.isdir(local_path):
|
||||
print(f" WARNING: data directory '{ref_key}' not cached at {local_path} — run refresh_data_dirs.py")
|
||||
print(f" WARNING: data directory '{ref_key}' not cached at {local_path} -run refresh_data_dirs.py")
|
||||
continue
|
||||
dd_dest = dd.get("destination", "")
|
||||
if base_dest and dd_dest:
|
||||
@@ -754,7 +950,7 @@ def generate_pack(
|
||||
src = os.path.join(root, fname)
|
||||
rel = os.path.relpath(src, local_path)
|
||||
full = f"{dd_prefix}/{rel}"
|
||||
if full in seen_destinations or full.lower() in seen_lower and case_insensitive:
|
||||
if full in seen_destinations or (full.lower() in seen_lower and case_insensitive):
|
||||
continue
|
||||
if _has_path_conflict(full, seen_destinations, seen_parents):
|
||||
continue
|
||||
@@ -765,66 +961,10 @@ def generate_pack(
|
||||
zf.write(src, full)
|
||||
total_files += 1
|
||||
|
||||
# README.txt for users
|
||||
extract_paths = {
|
||||
"retroarch": "system/", "lakka": "system/",
|
||||
"batocera": "/userdata/bios/", "recalbox": "/recalbox/share/bios/",
|
||||
"emudeck": "Emulation/bios/", "retrobat": "bios/",
|
||||
"retrodeck": "~/retrodeck/bios/", "romm": "bios/",
|
||||
"bizhawk": "Firmware/", "retropie": "BIOS/",
|
||||
}
|
||||
extract_to = extract_paths.get(platform_name, f"{base_dest}/")
|
||||
# README.txt for users -personalized step-by-step per platform
|
||||
num_systems = len(pack_systems)
|
||||
# Platform-specific notes
|
||||
platform_notes = {
|
||||
"emudeck": (
|
||||
"\nSTANDALONE EMULATORS\n"
|
||||
" Switch emulators (Yuzu, Eden, Ryujinx) and Citra need\n"
|
||||
" keys in their own folders, not in Emulation/bios/.\n"
|
||||
" Use the automatic installer to set this up, or copy\n"
|
||||
" manually:\n"
|
||||
" prod.keys -> ~/.local/share/yuzu/keys/\n"
|
||||
" prod.keys -> ~/.local/share/eden/keys/\n"
|
||||
" prod.keys -> ~/.config/Ryujinx/system/\n"
|
||||
" aes_keys.txt -> Emulation/bios/citra/keys/\n\n"
|
||||
),
|
||||
"retroarch": (
|
||||
"\nHANDHELDS (Anbernic, Retroid, Miyoo, etc.)\n"
|
||||
" Copy the contents of \"system/\" to your SD card's\n"
|
||||
" BIOS folder (usually BIOS/ or system/).\n\n"
|
||||
),
|
||||
"batocera": (
|
||||
"\nDREAMCAST NOTE\n"
|
||||
" The flash memory file is named dc_nvmem.bin\n"
|
||||
" (Flycast's canonical name). If your setup asks for\n"
|
||||
" dc_flash.bin, it serves the same purpose.\n\n"
|
||||
),
|
||||
}
|
||||
extra_notes = platform_notes.get(platform_name, "")
|
||||
# Lakka shares RetroArch notes
|
||||
if platform_name == "lakka":
|
||||
extra_notes = platform_notes.get("retroarch", "")
|
||||
|
||||
readme_text = (
|
||||
f"{'=' * 43}\n"
|
||||
f" RETROBIOS - {platform_display} BIOS Pack\n"
|
||||
f" {total_files} files for {num_systems} systems\n"
|
||||
f"{'=' * 43}\n\n"
|
||||
f"HOW TO INSTALL\n\n"
|
||||
f" 1. Open the \"{base_dest or 'files'}\" folder in this archive\n"
|
||||
f" 2. Select everything inside (Ctrl+A)\n"
|
||||
f" 3. Copy (Ctrl+C)\n"
|
||||
f" 4. Go to: {extract_to}\n"
|
||||
f" 5. Paste (Ctrl+V)\n\n"
|
||||
f"IMPORTANT\n"
|
||||
f" - Copy the FILES, not the folder itself\n"
|
||||
f" - If asked to replace, click Yes\n"
|
||||
f"{extra_notes}"
|
||||
f"AUTOMATIC INSTALL (recommended)\n"
|
||||
f" curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh\n\n"
|
||||
f"PROJECT: https://github.com/Abdess/retrobios\n"
|
||||
f"{'=' * 43}\n"
|
||||
)
|
||||
readme_text = _build_readme(platform_name, platform_display,
|
||||
base_dest, total_files, num_systems)
|
||||
zf.writestr("README.txt", readme_text)
|
||||
|
||||
files_ok = sum(1 for s in file_status.values() if s == "ok")
|
||||
@@ -843,7 +983,7 @@ def generate_pack(
|
||||
for key, reason in sorted(file_reasons.items()):
|
||||
status = file_status.get(key, "")
|
||||
label = "UNTESTED" if status == "untested" else "DISCREPANCY"
|
||||
print(f" {label}: {key} — {reason}")
|
||||
print(f" {label}: {key} -{reason}")
|
||||
for name in missing_files:
|
||||
print(f" MISSING: {name}")
|
||||
return zip_path
|
||||
@@ -871,7 +1011,7 @@ def _normalize_zip_for_pack(source_zip: str, dest_path: str, target_zf: zipfile.
|
||||
the normalized version into the pack.
|
||||
|
||||
This ensures:
|
||||
- Same ROMs → same ZIP hash in every pack build
|
||||
- Same ROMs -> same ZIP hash in every pack build
|
||||
- No dependency on how the user built their MAME ROM set
|
||||
- Bit-identical ZIPs across platforms and build times
|
||||
"""
|
||||
@@ -885,9 +1025,7 @@ def _normalize_zip_for_pack(source_zip: str, dest_path: str, target_zf: zipfile.
|
||||
os.unlink(tmp_path)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Emulator/system mode pack generation
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _resolve_destination(file_entry: dict, pack_structure: dict | None,
|
||||
standalone: bool) -> str:
|
||||
@@ -941,11 +1079,11 @@ def generate_emulator_pack(
|
||||
p = all_profiles[name]
|
||||
if p.get("type") == "alias":
|
||||
alias_of = p.get("alias_of", "?")
|
||||
print(f"Error: {name} is an alias of {alias_of} — use --emulator {alias_of}",
|
||||
print(f"Error: {name} is an alias of {alias_of} -use --emulator {alias_of}",
|
||||
file=sys.stderr)
|
||||
return None
|
||||
if p.get("type") == "launcher":
|
||||
print(f"Error: {name} is a launcher — use the emulator it launches",
|
||||
print(f"Error: {name} is a launcher -use the emulator it launches",
|
||||
file=sys.stderr)
|
||||
return None
|
||||
ptype = p.get("type", "libretro")
|
||||
@@ -1773,25 +1911,13 @@ def main():
|
||||
|
||||
target_cores_cache: dict[str, set[str] | None] = {}
|
||||
if args.target:
|
||||
from common import load_target_config
|
||||
skip = []
|
||||
for p in platforms:
|
||||
try:
|
||||
target_cores_cache[p] = load_target_config(p, args.target, args.platforms_dir)
|
||||
except FileNotFoundError:
|
||||
if args.all:
|
||||
target_cores_cache[p] = None
|
||||
else:
|
||||
print(f"ERROR: No target config for platform '{p}'", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
except ValueError as e:
|
||||
if args.all:
|
||||
print(f"INFO: Skipping {p}: {e}")
|
||||
skip.append(p)
|
||||
else:
|
||||
target_cores_cache, platforms = build_target_cores_cache(
|
||||
platforms, args.target, args.platforms_dir, is_all=args.all,
|
||||
)
|
||||
except (FileNotFoundError, ValueError) as e:
|
||||
print(f"ERROR: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
platforms = [p for p in platforms if p not in skip]
|
||||
|
||||
groups = group_identical_platforms(platforms, args.platforms_dir,
|
||||
target_cores_cache if args.target else None)
|
||||
@@ -1803,9 +1929,7 @@ def main():
|
||||
emu_profiles, target_cores_cache, system_filter)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Manifest generation (JSON inventory for install.py)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_GITIGNORE_ENTRIES: set[str] | None = None
|
||||
|
||||
@@ -2011,7 +2135,7 @@ def generate_manifest(
|
||||
if case_insensitive:
|
||||
seen_lower.add(full_dest.lower())
|
||||
|
||||
# No phase 3 (data directories) — skipped for manifest
|
||||
# No phase 3 (data directories) -skipped for manifest
|
||||
|
||||
now = __import__("datetime").datetime.now(
|
||||
__import__("datetime").timezone.utc
|
||||
@@ -2033,9 +2157,7 @@ def generate_manifest(
|
||||
return result
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Post-generation pack verification + manifest + SHA256SUMS
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def verify_pack(zip_path: str, db: dict,
|
||||
data_registry: dict | None = None) -> tuple[bool, dict]:
|
||||
@@ -2334,7 +2456,7 @@ def verify_pack_against_platform(
|
||||
|
||||
if full in zip_set or full.lower() in zip_lower:
|
||||
core_present += 1
|
||||
# Not an error if missing — some get deduped or filtered
|
||||
# Not an error if missing -some get deduped or filtered
|
||||
|
||||
checked = baseline_checked + core_checked
|
||||
present = baseline_present + core_present
|
||||
|
||||
@@ -189,9 +189,7 @@ def _status_icon(pct: float) -> str:
|
||||
return "partial"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Home page
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def generate_home(db: dict, coverages: dict, profiles: dict,
|
||||
registry: dict | None = None) -> str:
|
||||
@@ -303,9 +301,7 @@ def generate_home(db: dict, coverages: dict, profiles: dict,
|
||||
return "\n".join(lines) + "\n"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Platform pages
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def generate_platform_index(coverages: dict) -> str:
|
||||
lines = [
|
||||
@@ -478,9 +474,7 @@ def generate_platform_page(name: str, cov: dict, registry: dict | None = None,
|
||||
return "\n".join(lines) + "\n"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# System pages
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _group_by_manufacturer(db: dict) -> dict[str, dict[str, list]]:
|
||||
"""Group files by manufacturer -> console -> files."""
|
||||
@@ -572,9 +566,7 @@ def generate_system_page(
|
||||
return "\n".join(lines) + "\n"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Emulator pages
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def generate_emulators_index(profiles: dict) -> str:
|
||||
unique = {k: v for k, v in profiles.items() if v.get("type") not in ("alias", "test")}
|
||||
@@ -1011,9 +1003,7 @@ def generate_emulator_page(name: str, profile: dict, db: dict,
|
||||
return "\n".join(lines) + "\n"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Contributing page
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def generate_gap_analysis(
|
||||
profiles: dict,
|
||||
@@ -1367,9 +1357,7 @@ The CI automatically:
|
||||
"""
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Wiki pages
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def generate_wiki_index() -> str:
|
||||
"""Generate wiki landing page."""
|
||||
@@ -1924,9 +1912,7 @@ def generate_wiki_data_model(db: dict, profiles: dict) -> str:
|
||||
return "\n".join(lines) + "\n"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Build cross-reference indexes
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _build_platform_file_index(coverages: dict) -> dict[str, set]:
|
||||
"""Map platform_name -> set of declared file names."""
|
||||
@@ -1954,9 +1940,7 @@ def _build_emulator_file_index(profiles: dict) -> dict[str, dict]:
|
||||
return index
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# mkdocs.yml nav generator
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def generate_mkdocs_nav(
|
||||
coverages: dict,
|
||||
@@ -2028,9 +2012,7 @@ def generate_mkdocs_nav(
|
||||
]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Main
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Generate MkDocs site from project data")
|
||||
@@ -2053,14 +2035,12 @@ def main():
|
||||
for d in GENERATED_DIRS:
|
||||
(docs / d).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Load registry for platform metadata (logos, etc.)
|
||||
registry_path = Path(args.platforms_dir) / "_registry.yml"
|
||||
registry = {}
|
||||
if registry_path.exists():
|
||||
with open(registry_path) as f:
|
||||
registry = (yaml.safe_load(f) or {}).get("platforms", {})
|
||||
|
||||
# Load platform configs
|
||||
platform_names = list_registered_platforms(args.platforms_dir, include_archived=True)
|
||||
|
||||
print("Computing platform coverage...")
|
||||
@@ -2073,7 +2053,6 @@ def main():
|
||||
except FileNotFoundError as e:
|
||||
print(f" {name}: skipped ({e})", file=sys.stderr)
|
||||
|
||||
# Load emulator profiles
|
||||
print("Loading emulator profiles...")
|
||||
profiles = load_emulator_profiles(args.emulators_dir, skip_aliases=False)
|
||||
unique_count = sum(1 for p in profiles.values() if p.get("type") != "alias")
|
||||
|
||||
@@ -47,6 +47,24 @@ class ChangeSet:
|
||||
return ", ".join(parts) if parts else "no changes"
|
||||
|
||||
|
||||
MAX_RESPONSE_SIZE = 50 * 1024 * 1024 # 50 MB
|
||||
|
||||
|
||||
def _read_limited(resp: object, max_bytes: int = MAX_RESPONSE_SIZE) -> bytes:
|
||||
"""Read an HTTP response with a size limit to prevent OOM."""
|
||||
chunks: list[bytes] = []
|
||||
total = 0
|
||||
while True:
|
||||
chunk = resp.read(65536) # type: ignore[union-attr]
|
||||
if not chunk:
|
||||
break
|
||||
total += len(chunk)
|
||||
if total > max_bytes:
|
||||
raise ValueError(f"Response exceeds {max_bytes} byte limit")
|
||||
chunks.append(chunk)
|
||||
return b"".join(chunks)
|
||||
|
||||
|
||||
class BaseScraper(ABC):
|
||||
"""Abstract base class for platform BIOS requirement scrapers."""
|
||||
|
||||
@@ -63,7 +81,7 @@ class BaseScraper(ABC):
|
||||
try:
|
||||
req = urllib.request.Request(self.url, headers={"User-Agent": "retrobios-scraper/1.0"})
|
||||
with urllib.request.urlopen(req, timeout=30) as resp:
|
||||
self._raw_data = resp.read().decode("utf-8")
|
||||
self._raw_data = _read_limited(resp).decode("utf-8")
|
||||
return self._raw_data
|
||||
except urllib.error.URLError as e:
|
||||
raise ConnectionError(f"Failed to fetch {self.url}: {e}") from e
|
||||
|
||||
@@ -65,7 +65,7 @@ SYSTEM_ID_MAP: dict[str, str] = {
|
||||
"Amiga": "commodore-amiga",
|
||||
"AmstradCPC": "amstrad-cpc",
|
||||
"AppleII": "apple-ii",
|
||||
"BSX": "nintendo-bsx",
|
||||
"BSX": "nintendo-satellaview",
|
||||
"C64": "commodore-c64",
|
||||
"ChannelF": "fairchild-channel-f",
|
||||
"Coleco": "coleco-colecovision",
|
||||
|
||||
@@ -24,12 +24,12 @@ SOURCE_URL = (
|
||||
|
||||
# Libretro cores that expect BIOS files in a subdirectory of system/.
|
||||
# System.dat lists filenames flat; the scraper prepends the prefix.
|
||||
# ref: each core's libretro.c or equivalent — see platforms/README.md
|
||||
# ref: each core's libretro.c or equivalent -see platforms/README.md
|
||||
CORE_SUBDIR_MAP = {
|
||||
"nec-pc-98": "np2kai", # libretro-np2kai/sdl/libretro.c
|
||||
"sharp-x68000": "keropi", # px68k/libretro/libretro.c
|
||||
"sega-dreamcast": "dc", # flycast/shell/libretro/libretro.cpp
|
||||
"sega-dreamcast-arcade": "dc", # flycast — same subfolder
|
||||
"sega-dreamcast-arcade": "dc", # flycast -same subfolder
|
||||
}
|
||||
|
||||
SYSTEM_SLUG_MAP = {
|
||||
@@ -254,7 +254,7 @@ class Scraper(BaseScraper):
|
||||
|
||||
systems[req.system]["files"].append(entry)
|
||||
|
||||
# Systems not in System.dat but needed for RetroArch — added via
|
||||
# Systems not in System.dat but needed for RetroArch -added via
|
||||
# shared groups in _shared.yml. The includes directive is resolved
|
||||
# at load time by load_platform_config().
|
||||
EXTRA_SYSTEMS = {
|
||||
@@ -264,7 +264,7 @@ class Scraper(BaseScraper):
|
||||
"manufacturer": "NEC",
|
||||
"docs": "https://docs.libretro.com/library/quasi88/",
|
||||
},
|
||||
# ref: Vircon32/libretro.c — virtual console, single BIOS
|
||||
# ref: Vircon32/libretro.c -virtual console, single BIOS
|
||||
"vircon32": {
|
||||
"files": [
|
||||
{"name": "Vircon32Bios.v32", "destination": "Vircon32Bios.v32", "required": True},
|
||||
@@ -273,7 +273,7 @@ class Scraper(BaseScraper):
|
||||
"manufacturer": "Vircon",
|
||||
"docs": "https://docs.libretro.com/library/vircon32/",
|
||||
},
|
||||
# ref: xrick/src/sysvid.c, xrick/src/data.c — game data archive
|
||||
# ref: xrick/src/sysvid.c, xrick/src/data.c -game data archive
|
||||
"xrick": {
|
||||
"files": [
|
||||
{"name": "data.zip", "destination": "xrick/data.zip", "required": True},
|
||||
@@ -290,7 +290,7 @@ class Scraper(BaseScraper):
|
||||
# Arcade BIOS present in the repo but absent from System.dat.
|
||||
# FBNeo expects them in system/ or system/fbneo/.
|
||||
# ref: fbneo/src/burner/libretro/libretro.cpp
|
||||
# ref: fbneo/src/burner/libretro/libretro.cpp — search order:
|
||||
# ref: fbneo/src/burner/libretro/libretro.cpp -search order:
|
||||
# 1) romset dir 2) system/fbneo/ 3) system/
|
||||
EXTRA_ARCADE_FILES = [
|
||||
{"name": "namcoc69.zip", "destination": "namcoc69.zip", "required": True},
|
||||
@@ -329,33 +329,33 @@ class Scraper(BaseScraper):
|
||||
# Extra files missing from System.dat for specific systems.
|
||||
# Each traced to the core's source code.
|
||||
EXTRA_SYSTEM_FILES = {
|
||||
# melonDS DS DSi mode — ref: JesseTG/melonds-ds/src/libretro.cpp
|
||||
# melonDS DS DSi mode -ref: JesseTG/melonds-ds/src/libretro.cpp
|
||||
"nintendo-ds": [
|
||||
{"name": "dsi_bios7.bin", "destination": "dsi_bios7.bin", "required": True},
|
||||
{"name": "dsi_bios9.bin", "destination": "dsi_bios9.bin", "required": True},
|
||||
{"name": "dsi_firmware.bin", "destination": "dsi_firmware.bin", "required": True},
|
||||
{"name": "dsi_nand.bin", "destination": "dsi_nand.bin", "required": True},
|
||||
],
|
||||
# bsnes SGB naming — ref: bsnes/target-libretro/libretro.cpp
|
||||
# bsnes SGB naming -ref: bsnes/target-libretro/libretro.cpp
|
||||
"nintendo-sgb": [
|
||||
{"name": "sgb.boot.rom", "destination": "sgb.boot.rom", "required": False},
|
||||
],
|
||||
# JollyCV — ref: jollycv/libretro.c
|
||||
# JollyCV -ref: jollycv/libretro.c
|
||||
"coleco-colecovision": [
|
||||
{"name": "BIOS.col", "destination": "BIOS.col", "required": True},
|
||||
{"name": "coleco.rom", "destination": "coleco.rom", "required": True},
|
||||
{"name": "bioscv.rom", "destination": "bioscv.rom", "required": True},
|
||||
],
|
||||
# Kronos ST-V — ref: libretro-kronos/libretro/libretro.c
|
||||
# Kronos ST-V -ref: libretro-kronos/libretro/libretro.c
|
||||
"sega-saturn": [
|
||||
{"name": "stvbios.zip", "destination": "kronos/stvbios.zip", "required": True},
|
||||
],
|
||||
# PCSX ReARMed / Beetle PSX alt BIOS — ref: pcsx_rearmed/libpcsxcore/misc.c
|
||||
# PCSX ReARMed / Beetle PSX alt BIOS -ref: pcsx_rearmed/libpcsxcore/misc.c
|
||||
# docs say PSXONPSP660.bin (uppercase) but core accepts any case
|
||||
"sony-playstation": [
|
||||
{"name": "psxonpsp660.bin", "destination": "psxonpsp660.bin", "required": False},
|
||||
],
|
||||
# Dolphin GC — ref: DolphinLibretro/Boot.cpp:72-73,
|
||||
# Dolphin GC -ref: DolphinLibretro/Boot.cpp:72-73,
|
||||
# BootManager.cpp:200-217, CommonPaths.h:139 GC_IPL="IPL.bin"
|
||||
# Core searches system/dolphin-emu/Sys/ for data and BIOS.
|
||||
# System.dat gc-ntsc-*.bin names are NOT what Dolphin loads.
|
||||
@@ -364,15 +364,15 @@ class Scraper(BaseScraper):
|
||||
{"name": "gc-ntsc-12.bin", "destination": "dolphin-emu/Sys/GC/USA/IPL.bin", "required": False},
|
||||
{"name": "gc-pal-12.bin", "destination": "dolphin-emu/Sys/GC/EUR/IPL.bin", "required": False},
|
||||
{"name": "gc-ntsc-12.bin", "destination": "dolphin-emu/Sys/GC/JAP/IPL.bin", "required": False},
|
||||
# DSP firmware — ref: Source/Core/Core/HW/DSPLLE/DSPHost.cpp
|
||||
# DSP firmware -ref: Source/Core/Core/HW/DSPLLE/DSPHost.cpp
|
||||
{"name": "dsp_coef.bin", "destination": "dolphin-emu/Sys/GC/dsp_coef.bin", "required": True},
|
||||
{"name": "dsp_rom.bin", "destination": "dolphin-emu/Sys/GC/dsp_rom.bin", "required": True},
|
||||
# Fonts — ref: Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp
|
||||
# Fonts -ref: Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp
|
||||
{"name": "font_western.bin", "destination": "dolphin-emu/Sys/GC/font_western.bin", "required": False},
|
||||
{"name": "font_japanese.bin", "destination": "dolphin-emu/Sys/GC/font_japanese.bin", "required": False},
|
||||
],
|
||||
# minivmac casing — ref: minivmac/src/MYOSGLUE.c
|
||||
# doc says MacII.rom, repo has MacII.ROM — both work on case-insensitive FS
|
||||
# minivmac casing -ref: minivmac/src/MYOSGLUE.c
|
||||
# doc says MacII.rom, repo has MacII.ROM -both work on case-insensitive FS
|
||||
"apple-macintosh-ii": [
|
||||
{"name": "MacII.ROM", "destination": "MacII.ROM", "required": True},
|
||||
],
|
||||
@@ -398,7 +398,7 @@ class Scraper(BaseScraper):
|
||||
# Inject shared group references for systems that have core-specific
|
||||
# subdirectory requirements already defined in _shared.yml.
|
||||
# Note: fuse/ prefix NOT injected for sinclair-zx-spectrum.
|
||||
# Verified in fuse-libretro/src/compat/paths.c — core searches
|
||||
# Verified in fuse-libretro/src/compat/paths.c -core searches
|
||||
# system/ flat, not fuse/ subfolder. Docs are wrong on this.
|
||||
SYSTEM_SHARED_GROUPS = {
|
||||
"nec-pc-98": ["np2kai"],
|
||||
@@ -421,12 +421,12 @@ class Scraper(BaseScraper):
|
||||
{"ref": "ppsspp-assets", "destination": "PPSSPP"},
|
||||
],
|
||||
# single buildbot ZIP contains both Databases/ and Machines/
|
||||
# ref: libretro.c:1118-1119 — system_dir/Machines + system_dir/Databases
|
||||
# ref: libretro.c:1118-1119 -system_dir/Machines + system_dir/Databases
|
||||
"microsoft-msx": [
|
||||
{"ref": "bluemsx", "destination": ""},
|
||||
],
|
||||
# FreeIntv overlays — system/freeintv_overlays/<rom>.png
|
||||
# ref: FreeIntv/src/libretro.c:273 — stbi_load from system dir
|
||||
# FreeIntv overlays -system/freeintv_overlays/<rom>.png
|
||||
# ref: FreeIntv/src/libretro.c:273 -stbi_load from system dir
|
||||
# ZIP contains FreeIntvTS_Overlays/ subfolder, cache preserves it
|
||||
# pack destination maps cache root to system/freeintv_overlays
|
||||
# so final path is system/freeintv_overlays/FreeIntvTS_Overlays/<rom>.png
|
||||
|
||||
@@ -171,7 +171,7 @@ def _resolve_path(p: str) -> str:
|
||||
def _extract_bios_entries(component_val: dict) -> list[dict]:
|
||||
"""Extract BIOS entries from all three possible locations in a component.
|
||||
|
||||
No dedup here — dedup is done in fetch_requirements() with full
|
||||
No dedup here -dedup is done in fetch_requirements() with full
|
||||
(system, filename) key to avoid dropping valid same-filename entries
|
||||
across different systems.
|
||||
"""
|
||||
@@ -338,13 +338,13 @@ class Scraper(BaseScraper):
|
||||
if resolved.startswith("saves"):
|
||||
continue
|
||||
|
||||
# Build destination — default to bios/ if no path specified
|
||||
# Build destination -default to bios/ if no path specified
|
||||
if resolved:
|
||||
destination = f"{resolved}/{filename}"
|
||||
else:
|
||||
destination = f"bios/{filename}"
|
||||
|
||||
# MD5 handling — sanitize upstream errors
|
||||
# MD5 handling -sanitize upstream errors
|
||||
md5_raw = entry.get("md5", "")
|
||||
if isinstance(md5_raw, list):
|
||||
parts = [str(m).strip().lower() for m in md5_raw if m]
|
||||
|
||||
@@ -6,18 +6,20 @@ from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
import pkgutil
|
||||
from abc import ABC, abstractmethod
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class BaseTargetScraper:
|
||||
class BaseTargetScraper(ABC):
|
||||
"""Base class for target scrapers."""
|
||||
|
||||
def __init__(self, url: str = ""):
|
||||
self.url = url
|
||||
|
||||
@abstractmethod
|
||||
def fetch_targets(self) -> dict:
|
||||
"""Fetch targets and their core lists. Returns dict matching target YAML format."""
|
||||
raise NotImplementedError
|
||||
...
|
||||
|
||||
def write_output(self, data: dict, output_path: str) -> None:
|
||||
"""Write target data to YAML file."""
|
||||
|
||||
@@ -136,7 +136,7 @@ def _check_atom(tokens: list[str], pos: int, active: frozenset[str]) -> tuple[bo
|
||||
if tok.startswith('"'):
|
||||
pos += 1
|
||||
return True, pos
|
||||
# Unknown token — treat as true to avoid false negatives
|
||||
# Unknown token -treat as true to avoid false negatives
|
||||
pos += 1
|
||||
return True, pos
|
||||
|
||||
@@ -152,7 +152,7 @@ def _condition_holds(condition: str, active: frozenset[str]) -> bool:
|
||||
try:
|
||||
result, _ = _check_condition(tokens, 0, active)
|
||||
return result
|
||||
except Exception:
|
||||
except (IndexError, ValueError, TypeError):
|
||||
return True # conservative: include on parse failure
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"""Scraper for EmuDeck emulator targets.
|
||||
|
||||
Sources:
|
||||
SteamOS: dragoonDorise/EmuDeck — functions/EmuScripts/*.sh
|
||||
Windows: EmuDeck/emudeck-we — functions/EmuScripts/*.ps1
|
||||
SteamOS: dragoonDorise/EmuDeck -functions/EmuScripts/*.sh
|
||||
Windows: EmuDeck/emudeck-we -functions/EmuScripts/*.ps1
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ TARGETS: list[tuple[str, str, str]] = [
|
||||
("nintendo/wiiu/latest", "nintendo-wiiu", "ppc"),
|
||||
("playstation/ps2/latest", "playstation-ps2", "mips"),
|
||||
("playstation/psp/latest", "playstation-psp", "mips"),
|
||||
# vita: only VPK bundles on buildbot — cores listed via libretro-super recipes
|
||||
# vita: only VPK bundles on buildbot -cores listed via libretro-super recipes
|
||||
]
|
||||
|
||||
# Recipe-based targets: (recipe_path_under_RECIPE_BASE_URL, target_name, architecture)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Implements GF(2^233) field arithmetic, elliptic curve point operations,
|
||||
and ECDSA-SHA256 verification for Nintendo 3DS OTP certificate checking.
|
||||
|
||||
Zero external dependencies — uses only Python stdlib.
|
||||
Zero external dependencies -uses only Python stdlib.
|
||||
|
||||
Curve: sect233r1 (NIST B-233, SEC 2 v2)
|
||||
Field: GF(2^233) with irreducible polynomial t^233 + t^74 + 1
|
||||
@@ -13,9 +13,7 @@ from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# sect233r1 curve parameters (SEC 2 v2)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_M = 233
|
||||
_F = (1 << 233) | (1 << 74) | 1 # irreducible polynomial
|
||||
@@ -34,9 +32,7 @@ _N_BITLEN = _N.bit_length() # 233
|
||||
_H = 2
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# GF(2^233) field arithmetic
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _gf_reduce(a: int) -> int:
|
||||
"""Reduce polynomial a modulo t^233 + t^74 + 1."""
|
||||
@@ -85,7 +81,7 @@ def _gf_inv(a: int) -> int:
|
||||
q ^= 1 << shift
|
||||
temp ^= r << shift
|
||||
remainder = temp
|
||||
# Multiply q * s in GF(2)[x] (no reduction — working in polynomial ring)
|
||||
# Multiply q * s in GF(2)[x] (no reduction -working in polynomial ring)
|
||||
qs = 0
|
||||
qt = q
|
||||
st = s
|
||||
@@ -102,10 +98,8 @@ def _gf_inv(a: int) -> int:
|
||||
return _gf_reduce(old_s)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Elliptic curve point operations on sect233r1
|
||||
# y^2 + xy = x^3 + ax^2 + b (a=1)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Point at infinity
|
||||
_INF = None
|
||||
@@ -175,9 +169,7 @@ def _ec_mul(k: int, p: tuple[int, int] | None) -> tuple[int, int] | None:
|
||||
return result
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ECDSA-SHA256 verification
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _modinv(a: int, m: int) -> int:
|
||||
"""Modular inverse of a modulo m (integers, not GF(2^m))."""
|
||||
|
||||
@@ -217,7 +217,7 @@ def generate_platform_truth(
|
||||
sys_cov["profiled"].add(emu_name)
|
||||
|
||||
# Ensure all systems of resolved cores have entries (even with 0 files).
|
||||
# This documents that the system is covered — the core was analyzed and
|
||||
# This documents that the system is covered -the core was analyzed and
|
||||
# needs no external files for this system.
|
||||
for emu_name in cores_profiled:
|
||||
profile = profiles[emu_name]
|
||||
@@ -261,9 +261,7 @@ def generate_platform_truth(
|
||||
}
|
||||
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# Platform truth diffing
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
def _diff_system(truth_sys: dict, scraped_sys: dict) -> dict:
|
||||
"""Compare files between truth and scraped for a single system."""
|
||||
@@ -430,7 +428,7 @@ def diff_platform_truth(truth: dict, scraped: dict) -> dict:
|
||||
else:
|
||||
summary["systems_fully_covered"] += 1
|
||||
|
||||
# Truth systems not matched by any scraped system — all files missing
|
||||
# Truth systems not matched by any scraped system -all files missing
|
||||
for t_sid in sorted(truth_systems):
|
||||
if t_sid in matched_truth:
|
||||
continue
|
||||
|
||||
@@ -12,7 +12,7 @@ import os
|
||||
from common import compute_hashes
|
||||
|
||||
# Validation types that require console-specific cryptographic keys.
|
||||
# verify.py cannot reproduce these — size checks still apply if combined.
|
||||
# verify.py cannot reproduce these -size checks still apply if combined.
|
||||
_CRYPTO_CHECKS = frozenset({"signature", "crypto"})
|
||||
|
||||
# All reproducible validation types.
|
||||
@@ -85,7 +85,7 @@ def _build_validation_index(profiles: dict) -> dict[str, dict]:
|
||||
if f.get("max_size") is not None:
|
||||
cur = index[fname]["max_size"]
|
||||
index[fname]["max_size"] = max(cur, f["max_size"]) if cur is not None else f["max_size"]
|
||||
# Hash checks — collect all accepted hashes as sets (multiple valid
|
||||
# Hash checks -collect all accepted hashes as sets (multiple valid
|
||||
# versions of the same file, e.g. MT-32 ROM versions)
|
||||
if "crc32" in checks and f.get("crc32"):
|
||||
crc_val = f["crc32"]
|
||||
@@ -103,7 +103,7 @@ def _build_validation_index(profiles: dict) -> dict[str, dict]:
|
||||
index[fname][hash_type].add(str(h).lower())
|
||||
else:
|
||||
index[fname][hash_type].add(str(val).lower())
|
||||
# Adler32 — stored as known_hash_adler32 field (not in validation: list
|
||||
# Adler32 -stored as known_hash_adler32 field (not in validation: list
|
||||
# for Dolphin, but support it in both forms for future profiles)
|
||||
adler_val = f.get("known_hash_adler32") or f.get("adler32")
|
||||
if adler_val:
|
||||
@@ -186,7 +186,7 @@ def check_file_validation(
|
||||
return None
|
||||
checks = entry["checks"]
|
||||
|
||||
# Size checks — sizes is a set of accepted values
|
||||
# Size checks -sizes is a set of accepted values
|
||||
if "size" in checks:
|
||||
actual_size = os.path.getsize(local_path)
|
||||
if entry["sizes"] and actual_size not in entry["sizes"]:
|
||||
@@ -197,7 +197,7 @@ def check_file_validation(
|
||||
if entry["max_size"] is not None and actual_size > entry["max_size"]:
|
||||
return f"size too large: max {entry['max_size']}, got {actual_size}"
|
||||
|
||||
# Hash checks — compute once, reuse for all hash types.
|
||||
# Hash checks -compute once, reuse for all hash types.
|
||||
# Each hash field is a set of accepted values (multiple valid ROM versions).
|
||||
need_hashes = (
|
||||
any(h in checks and entry.get(h) for h in ("crc32", "md5", "sha1", "sha256"))
|
||||
|
||||
@@ -30,11 +30,11 @@ from pathlib import Path
|
||||
|
||||
sys.path.insert(0, os.path.dirname(__file__))
|
||||
from common import (
|
||||
build_zip_contents_index, check_inside_zip, compute_hashes,
|
||||
filter_systems_by_target, group_identical_platforms, list_emulator_profiles,
|
||||
list_system_ids, load_data_dir_registry, load_emulator_profiles,
|
||||
load_platform_config, md5sum, md5_composite, require_yaml, resolve_local_file,
|
||||
resolve_platform_cores,
|
||||
build_target_cores_cache, build_zip_contents_index, check_inside_zip,
|
||||
compute_hashes, filter_systems_by_target, group_identical_platforms,
|
||||
list_emulator_profiles, list_system_ids, load_data_dir_registry,
|
||||
load_emulator_profiles, load_platform_config, md5sum, md5_composite,
|
||||
require_yaml, resolve_local_file, resolve_platform_cores,
|
||||
)
|
||||
|
||||
yaml = require_yaml()
|
||||
@@ -47,9 +47,7 @@ DEFAULT_PLATFORMS_DIR = "platforms"
|
||||
DEFAULT_EMULATORS_DIR = "emulators"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Status model — aligned with Batocera BiosStatus (batocera-systems:967-969)
|
||||
# ---------------------------------------------------------------------------
|
||||
# Status model -aligned with Batocera BiosStatus (batocera-systems:967-969)
|
||||
|
||||
class Status:
|
||||
OK = "ok"
|
||||
@@ -68,15 +66,13 @@ _STATUS_ORDER = {Status.OK: 0, Status.UNTESTED: 1, Status.MISSING: 2}
|
||||
_SEVERITY_ORDER = {Severity.OK: 0, Severity.INFO: 1, Severity.WARNING: 2, Severity.CRITICAL: 3}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Verification functions
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def verify_entry_existence(
|
||||
file_entry: dict, local_path: str | None,
|
||||
validation_index: dict[str, dict] | None = None,
|
||||
) -> dict:
|
||||
"""RetroArch verification: path_is_valid() — file exists = OK."""
|
||||
"""RetroArch verification: path_is_valid() -file exists = OK."""
|
||||
name = file_entry.get("name", "")
|
||||
required = file_entry.get("required", True)
|
||||
if not local_path:
|
||||
@@ -96,7 +92,7 @@ def verify_entry_md5(
|
||||
local_path: str | None,
|
||||
resolve_status: str = "",
|
||||
) -> dict:
|
||||
"""MD5 verification — Batocera md5sum + Recalbox multi-hash + Md5Composite."""
|
||||
"""MD5 verification -Batocera md5sum + Recalbox multi-hash + Md5Composite."""
|
||||
name = file_entry.get("name", "")
|
||||
expected_md5 = file_entry.get("md5", "")
|
||||
zipped_file = file_entry.get("zipped_file")
|
||||
@@ -162,7 +158,7 @@ def verify_entry_sha1(
|
||||
file_entry: dict,
|
||||
local_path: str | None,
|
||||
) -> dict:
|
||||
"""SHA1 verification — BizHawk firmware hash check."""
|
||||
"""SHA1 verification -BizHawk firmware hash check."""
|
||||
name = file_entry.get("name", "")
|
||||
expected_sha1 = file_entry.get("sha1", "")
|
||||
required = file_entry.get("required", True)
|
||||
@@ -183,20 +179,18 @@ def verify_entry_sha1(
|
||||
"reason": f"expected {expected_sha1[:12]}… got {actual_sha1[:12]}…"}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Severity mapping per platform
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def compute_severity(
|
||||
status: str, required: bool, mode: str, hle_fallback: bool = False,
|
||||
) -> str:
|
||||
"""Map (status, required, verification_mode, hle_fallback) → severity.
|
||||
"""Map (status, required, verification_mode, hle_fallback) -> severity.
|
||||
|
||||
Based on native platform behavior + emulator HLE capability:
|
||||
- RetroArch (existence): required+missing = warning, optional+missing = info
|
||||
- Batocera/Recalbox/RetroBat/EmuDeck (md5): hash-based verification
|
||||
- BizHawk (sha1): same severity rules as md5
|
||||
- hle_fallback: core works without this file via HLE → always INFO when missing
|
||||
- hle_fallback: core works without this file via HLE -> always INFO when missing
|
||||
"""
|
||||
if status == Status.OK:
|
||||
return Severity.OK
|
||||
@@ -218,13 +212,9 @@ def compute_severity(
|
||||
return Severity.OK
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ZIP content index
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Cross-reference: undeclared files used by cores
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def _build_expected(file_entry: dict, checks: list[str]) -> dict:
|
||||
@@ -447,7 +437,7 @@ def find_exclusion_notes(
|
||||
})
|
||||
continue
|
||||
|
||||
# Count standalone-only files — but only report as excluded if the
|
||||
# Count standalone-only files -but only report as excluded if the
|
||||
# platform does NOT use this emulator in standalone mode
|
||||
standalone_set = set(str(c) for c in config.get("standalone_cores", []))
|
||||
is_standalone = emu_name in standalone_set or bool(
|
||||
@@ -466,9 +456,7 @@ def find_exclusion_notes(
|
||||
return notes
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Platform verification
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _find_best_variant(
|
||||
file_entry: dict, db: dict, current_path: str,
|
||||
@@ -504,6 +492,7 @@ def verify_platform(
|
||||
emu_profiles: dict | None = None,
|
||||
target_cores: set[str] | None = None,
|
||||
data_dir_registry: dict | None = None,
|
||||
supplemental_names: set[str] | None = None,
|
||||
) -> dict:
|
||||
"""Verify all BIOS files for a platform, including cross-reference gaps."""
|
||||
mode = config.get("verification_mode", "existence")
|
||||
@@ -601,10 +590,11 @@ def verify_platform(
|
||||
status_counts[s] = status_counts.get(s, 0) + 1
|
||||
|
||||
# Cross-reference undeclared files
|
||||
if supplemental_names is None:
|
||||
from cross_reference import _build_supplemental_index
|
||||
data_names = _build_supplemental_index()
|
||||
supplemental_names = _build_supplemental_index()
|
||||
undeclared = find_undeclared_files(config, emulators_dir, db, emu_profiles,
|
||||
target_cores=target_cores, data_names=data_names)
|
||||
target_cores=target_cores, data_names=supplemental_names)
|
||||
exclusions = find_exclusion_notes(config, emulators_dir, emu_profiles, target_cores=target_cores)
|
||||
|
||||
# Ground truth coverage
|
||||
@@ -638,9 +628,7 @@ def verify_platform(
|
||||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Output
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _format_ground_truth_aggregate(ground_truth: list[dict]) -> str:
|
||||
"""Format ground truth as a single aggregated line.
|
||||
@@ -696,7 +684,7 @@ def _print_detail_entries(details: list[dict], seen: set[str], verbose: bool) ->
|
||||
req = "required" if d.get("required", True) else "optional"
|
||||
hle = ", HLE available" if d.get("hle_fallback") else ""
|
||||
reason = d.get("reason", "")
|
||||
print(f" UNTESTED ({req}{hle}): {key} — {reason}")
|
||||
print(f" UNTESTED ({req}{hle}): {key} -{reason}")
|
||||
_print_ground_truth(d.get("ground_truth", []), verbose)
|
||||
for d in details:
|
||||
if d["status"] == Status.MISSING:
|
||||
@@ -715,7 +703,7 @@ def _print_detail_entries(details: list[dict], seen: set[str], verbose: bool) ->
|
||||
if key in seen:
|
||||
continue
|
||||
seen.add(key)
|
||||
print(f" DISCREPANCY: {key} — {disc}")
|
||||
print(f" DISCREPANCY: {key} -{disc}")
|
||||
_print_ground_truth(d.get("ground_truth", []), verbose)
|
||||
|
||||
if verbose:
|
||||
@@ -829,7 +817,7 @@ def print_platform_result(result: dict, group: list[str], verbose: bool = False)
|
||||
if exclusions:
|
||||
print(f" No external files ({len(exclusions)}):")
|
||||
for ex in exclusions:
|
||||
print(f" {ex['emulator']} — {ex['detail']} [{ex['reason']}]")
|
||||
print(f" {ex['emulator']} -{ex['detail']} [{ex['reason']}]")
|
||||
|
||||
gt_cov = result.get("ground_truth_coverage")
|
||||
if gt_cov and gt_cov["total"] > 0:
|
||||
@@ -839,9 +827,7 @@ def print_platform_result(result: dict, group: list[str], verbose: bool = False)
|
||||
print(f" {gt_cov['platform_only']} platform-only (no emulator profile)")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Emulator/system mode verification
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _effective_validation_label(details: list[dict], validation_index: dict) -> str:
|
||||
"""Determine the bracket label for the report.
|
||||
@@ -890,11 +876,11 @@ def verify_emulator(
|
||||
p = all_profiles[name]
|
||||
if p.get("type") == "alias":
|
||||
alias_of = p.get("alias_of", "?")
|
||||
print(f"Error: {name} is an alias of {alias_of} — use --emulator {alias_of}",
|
||||
print(f"Error: {name} is an alias of {alias_of} -use --emulator {alias_of}",
|
||||
file=sys.stderr)
|
||||
sys.exit(1)
|
||||
if p.get("type") == "launcher":
|
||||
print(f"Error: {name} is a launcher — use the emulator it launches",
|
||||
print(f"Error: {name} is a launcher -use the emulator it launches",
|
||||
file=sys.stderr)
|
||||
sys.exit(1)
|
||||
# Check standalone capability
|
||||
@@ -1115,7 +1101,7 @@ def print_emulator_result(result: dict, verbose: bool = False) -> None:
|
||||
req = "required" if d.get("required", True) else "optional"
|
||||
hle = ", HLE available" if d.get("hle_fallback") else ""
|
||||
reason = d.get("reason", "")
|
||||
print(f" UNTESTED ({req}{hle}): {d['name']} — {reason}")
|
||||
print(f" UNTESTED ({req}{hle}): {d['name']} -{reason}")
|
||||
gt = d.get("ground_truth", [])
|
||||
if gt:
|
||||
if verbose:
|
||||
@@ -1260,29 +1246,20 @@ def main():
|
||||
|
||||
target_cores_cache: dict[str, set[str] | None] = {}
|
||||
if args.target:
|
||||
from common import load_target_config
|
||||
skip = []
|
||||
for p in platforms:
|
||||
try:
|
||||
target_cores_cache[p] = load_target_config(p, args.target, args.platforms_dir)
|
||||
except FileNotFoundError:
|
||||
if args.all:
|
||||
target_cores_cache[p] = None
|
||||
else:
|
||||
print(f"ERROR: No target config for platform '{p}'", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
except ValueError as e:
|
||||
if args.all:
|
||||
print(f"INFO: Skipping {p}: {e}")
|
||||
skip.append(p)
|
||||
else:
|
||||
target_cores_cache, platforms = build_target_cores_cache(
|
||||
platforms, args.target, args.platforms_dir, is_all=args.all,
|
||||
)
|
||||
except (FileNotFoundError, ValueError) as e:
|
||||
print(f"ERROR: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
platforms = [p for p in platforms if p not in skip]
|
||||
|
||||
# Group identical platforms (same function as generate_pack)
|
||||
groups = group_identical_platforms(platforms, args.platforms_dir,
|
||||
target_cores_cache if args.target else None)
|
||||
from cross_reference import _build_supplemental_index
|
||||
suppl_names = _build_supplemental_index()
|
||||
|
||||
all_results = {}
|
||||
group_results: list[tuple[dict, list[str]]] = []
|
||||
for group_platforms, representative in groups:
|
||||
@@ -1291,6 +1268,7 @@ def main():
|
||||
result = verify_platform(
|
||||
config, db, args.emulators_dir, emu_profiles,
|
||||
target_cores=tc, data_dir_registry=data_registry,
|
||||
supplemental_names=suppl_names,
|
||||
)
|
||||
names = [load_platform_config(p, args.platforms_dir).get("platform", p) for p in group_platforms]
|
||||
group_results.append((result, names))
|
||||
|
||||
@@ -230,10 +230,10 @@ class TestE2E(unittest.TestCase):
|
||||
# Correct hash
|
||||
{"name": "correct_hash.bin", "destination": "correct_hash.bin",
|
||||
"md5": f["correct_hash.bin"]["md5"], "required": True},
|
||||
# Wrong hash on disk → untested
|
||||
# Wrong hash on disk ->untested
|
||||
{"name": "wrong_hash.bin", "destination": "wrong_hash.bin",
|
||||
"md5": "ffffffffffffffffffffffffffffffff", "required": True},
|
||||
# No MD5 → OK (existence within md5 platform)
|
||||
# No MD5 ->OK (existence within md5 platform)
|
||||
{"name": "no_md5.bin", "destination": "no_md5.bin", "required": False},
|
||||
# Missing required
|
||||
{"name": "gone_req.bin", "destination": "gone_req.bin",
|
||||
@@ -259,7 +259,7 @@ class TestE2E(unittest.TestCase):
|
||||
# Truncated MD5 (Batocera 29 chars)
|
||||
{"name": "truncated.bin", "destination": "truncated.bin",
|
||||
"md5": truncated_md5, "required": True},
|
||||
# Same destination from different entry → worst status wins
|
||||
# Same destination from different entry ->worst status wins
|
||||
{"name": "correct_hash.bin", "destination": "dedup_target.bin",
|
||||
"md5": f["correct_hash.bin"]["md5"], "required": True},
|
||||
{"name": "correct_hash.bin", "destination": "dedup_target.bin",
|
||||
@@ -367,7 +367,7 @@ class TestE2E(unittest.TestCase):
|
||||
with open(os.path.join(self.emulators_dir, "test_alias.yml"), "w") as fh:
|
||||
yaml.dump(alias, fh)
|
||||
|
||||
# Emulator with data_dir that matches platform → gaps suppressed
|
||||
# Emulator with data_dir that matches platform ->gaps suppressed
|
||||
emu_dd = {
|
||||
"emulator": "TestEmuDD",
|
||||
"type": "libretro",
|
||||
@@ -415,39 +415,39 @@ class TestE2E(unittest.TestCase):
|
||||
"type": "libretro",
|
||||
"systems": ["console-a", "sys-md5"],
|
||||
"files": [
|
||||
# Size validation — correct size (16 bytes = len(b"PRESENT_REQUIRED"))
|
||||
# Size validation -correct size (16 bytes = len(b"PRESENT_REQUIRED"))
|
||||
{"name": "present_req.bin", "required": True,
|
||||
"validation": ["size"], "size": 16,
|
||||
"source_ref": "test.c:10-20"},
|
||||
# Size validation — wrong expected size
|
||||
# Size validation -wrong expected size
|
||||
{"name": "present_opt.bin", "required": False,
|
||||
"validation": ["size"], "size": 9999},
|
||||
# CRC32 validation — correct crc32
|
||||
# CRC32 validation -correct crc32
|
||||
{"name": "correct_hash.bin", "required": True,
|
||||
"validation": ["crc32"], "crc32": "91d0b1d3",
|
||||
"source_ref": "hash.c:42"},
|
||||
# CRC32 validation — wrong crc32
|
||||
# CRC32 validation -wrong crc32
|
||||
{"name": "no_md5.bin", "required": False,
|
||||
"validation": ["crc32"], "crc32": "deadbeef"},
|
||||
# CRC32 starting with '0' (regression: lstrip("0x") bug)
|
||||
{"name": "leading_zero_crc.bin", "required": True,
|
||||
"validation": ["crc32"], "crc32": "0179e92e"},
|
||||
# MD5 validation — correct md5
|
||||
# MD5 validation -correct md5
|
||||
{"name": "correct_hash.bin", "required": True,
|
||||
"validation": ["md5"], "md5": "4a8db431e3b1a1acacec60e3424c4ce8"},
|
||||
# SHA1 validation — correct sha1
|
||||
# SHA1 validation -correct sha1
|
||||
{"name": "correct_hash.bin", "required": True,
|
||||
"validation": ["sha1"], "sha1": "a2ab6c95c5bbd191b9e87e8f4e85205a47be5764"},
|
||||
# MD5 validation — wrong md5
|
||||
# MD5 validation -wrong md5
|
||||
{"name": "alias_target.bin", "required": False,
|
||||
"validation": ["md5"], "md5": "0000000000000000000000000000dead"},
|
||||
# Adler32 — known_hash_adler32 field
|
||||
# Adler32 -known_hash_adler32 field
|
||||
{"name": "present_req.bin", "required": True,
|
||||
"known_hash_adler32": None}, # placeholder, set below
|
||||
# Min/max size range validation
|
||||
{"name": "present_req.bin", "required": True,
|
||||
"validation": ["size"], "min_size": 10, "max_size": 100},
|
||||
# Signature — crypto check we can't reproduce, but size applies
|
||||
# Signature -crypto check we can't reproduce, but size applies
|
||||
{"name": "correct_hash.bin", "required": True,
|
||||
"validation": ["size", "signature"], "size": 17},
|
||||
],
|
||||
@@ -491,7 +491,7 @@ class TestE2E(unittest.TestCase):
|
||||
yaml.dump(emu_subdir, fh)
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
# THE TEST — one method per feature area, all using same fixtures
|
||||
# THE TEST -one method per feature area, all using same fixtures
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
def test_01_resolve_sha1(self):
|
||||
@@ -676,7 +676,7 @@ class TestE2E(unittest.TestCase):
|
||||
profiles = load_emulator_profiles(self.emulators_dir)
|
||||
undeclared = find_undeclared_files(config, self.emulators_dir, self.db, profiles)
|
||||
names = {u["name"] for u in undeclared}
|
||||
# dd_covered.bin is a file entry, not data_dir content — still undeclared
|
||||
# dd_covered.bin is a file entry, not data_dir content -still undeclared
|
||||
self.assertIn("dd_covered.bin", names)
|
||||
|
||||
def test_44_cross_ref_skips_launchers(self):
|
||||
@@ -688,7 +688,7 @@ class TestE2E(unittest.TestCase):
|
||||
self.assertNotIn("launcher_bios.bin", names)
|
||||
|
||||
def test_45_hle_fallback_downgrades_severity(self):
|
||||
"""Missing file with hle_fallback=true → INFO severity, not CRITICAL."""
|
||||
"""Missing file with hle_fallback=true ->INFO severity, not CRITICAL."""
|
||||
from verify import compute_severity, Severity
|
||||
# required + missing + NO HLE = CRITICAL
|
||||
sev = compute_severity("missing", True, "md5", hle_fallback=False)
|
||||
@@ -723,7 +723,7 @@ class TestE2E(unittest.TestCase):
|
||||
groups = group_identical_platforms(
|
||||
["test_existence", "test_inherited"], self.platforms_dir
|
||||
)
|
||||
# Different base_destination → separate groups
|
||||
# Different base_destination ->separate groups
|
||||
self.assertEqual(len(groups), 2)
|
||||
|
||||
def test_51_platform_grouping_same(self):
|
||||
@@ -1064,7 +1064,7 @@ class TestE2E(unittest.TestCase):
|
||||
def test_95_verify_emulator_validation_applied(self):
|
||||
"""Emulator mode applies validation checks as primary verification."""
|
||||
result = verify_emulator(["test_validation"], self.emulators_dir, self.db)
|
||||
# present_opt.bin has wrong size → UNTESTED
|
||||
# present_opt.bin has wrong size ->UNTESTED
|
||||
for d in result["details"]:
|
||||
if d["name"] == "present_opt.bin":
|
||||
self.assertEqual(d["status"], Status.UNTESTED)
|
||||
@@ -1092,13 +1092,13 @@ class TestE2E(unittest.TestCase):
|
||||
def test_98_verify_emulator_validation_label(self):
|
||||
"""Validation label reflects the checks used."""
|
||||
result = verify_emulator(["test_validation"], self.emulators_dir, self.db)
|
||||
# test_validation has crc32, md5, sha1, size → all listed
|
||||
# test_validation has crc32, md5, sha1, size ->all listed
|
||||
self.assertEqual(result["verification_mode"], "crc32+md5+sha1+signature+size")
|
||||
|
||||
def test_99filter_files_by_mode(self):
|
||||
"""filter_files_by_mode correctly filters standalone/libretro."""
|
||||
files = [
|
||||
{"name": "a.bin"}, # no mode → both
|
||||
{"name": "a.bin"}, # no mode ->both
|
||||
{"name": "b.bin", "mode": "libretro"}, # libretro only
|
||||
{"name": "c.bin", "mode": "standalone"}, # standalone only
|
||||
{"name": "d.bin", "mode": "both"}, # explicit both
|
||||
@@ -1126,7 +1126,7 @@ class TestE2E(unittest.TestCase):
|
||||
self.assertTrue(len(notes) > 0)
|
||||
|
||||
def test_101_verify_emulator_severity_missing_required(self):
|
||||
"""Missing required file in emulator mode → WARNING severity."""
|
||||
"""Missing required file in emulator mode ->WARNING severity."""
|
||||
result = verify_emulator(["test_emu"], self.emulators_dir, self.db)
|
||||
# undeclared_req.bin is required and missing
|
||||
for d in result["details"]:
|
||||
@@ -1494,7 +1494,7 @@ class TestE2E(unittest.TestCase):
|
||||
|
||||
def test_112_build_ground_truth(self):
|
||||
"""build_ground_truth returns per-emulator detail for a filename."""
|
||||
from common import build_ground_truth
|
||||
from validation import build_ground_truth
|
||||
profiles = load_emulator_profiles(self.emulators_dir)
|
||||
index = _build_validation_index(profiles)
|
||||
gt = build_ground_truth("present_req.bin", index)
|
||||
@@ -1510,7 +1510,7 @@ class TestE2E(unittest.TestCase):
|
||||
|
||||
def test_113_build_ground_truth_empty(self):
|
||||
"""build_ground_truth returns [] for unknown filename."""
|
||||
from common import build_ground_truth
|
||||
from validation import build_ground_truth
|
||||
profiles = load_emulator_profiles(self.emulators_dir)
|
||||
index = _build_validation_index(profiles)
|
||||
gt = build_ground_truth("nonexistent.bin", index)
|
||||
@@ -1642,7 +1642,7 @@ class TestE2E(unittest.TestCase):
|
||||
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)
|
||||
# Simulate --json filtering (non-OK only) — ground_truth must survive
|
||||
# Simulate --json filtering (non-OK only) -ground_truth must survive
|
||||
filtered = [d for d in result["details"] if d["status"] != Status.OK]
|
||||
for d in filtered:
|
||||
self.assertIn("ground_truth", d)
|
||||
@@ -2426,7 +2426,7 @@ class TestE2E(unittest.TestCase):
|
||||
config = load_platform_config("test_archive_platform", self.platforms_dir)
|
||||
profiles = load_emulator_profiles(self.emulators_dir)
|
||||
undeclared = find_undeclared_files(config, self.emulators_dir, self.db, profiles)
|
||||
# test_archive.zip is declared → its archived ROMs should be skipped
|
||||
# test_archive.zip is declared ->its archived ROMs should be skipped
|
||||
archive_entries = [u for u in undeclared if u.get("archive") == "test_archive.zip"]
|
||||
self.assertEqual(len(archive_entries), 0)
|
||||
|
||||
@@ -3010,7 +3010,7 @@ class TestE2E(unittest.TestCase):
|
||||
|
||||
def test_104_diff_truth_normalized_system_ids(self):
|
||||
"""Diff matches systems with different ID formats via normalization."""
|
||||
from common import diff_platform_truth
|
||||
from truth import diff_platform_truth
|
||||
|
||||
truth = {
|
||||
"systems": {
|
||||
|
||||
Reference in New Issue
Block a user