feat: add region filters and profiles

This commit is contained in:
Abdessamad Derraz committed 2026-08-09 14:15:56 +02:00
1 parent 1c537c3a30
commit 45f89cc6c0
51 files changed
+4592 -260

No files matched your search

+17 -17
View File
@@ -36,7 +36,7 @@ Pick your platform, download the ZIP, extract to the BIOS path.
|----------|------|-----------|----------|
| Batocera | 2.7 GB | `/userdata/bios/` | [Download](../../releases/latest) |
| BizHawk | 2.4 GB | `Firmware/` | [Download](../../releases/latest) |
| EmuDeck | 1.6 GB | `~/Emulation/bios/` | [Download](../../releases/latest) |
| EmuDeck | 1.7 GB | `~/Emulation/bios/` | [Download](../../releases/latest) |
| Lakka | 3.9 GB | `/storage/system/` | [Download](../../releases/latest) |
| MiSTer FPGA | 23 MB | `/media/fat/games/` | [Download](../../releases/latest) |
| ROCKNIX | 3.8 GB | `/storage/roms/bios/` | [Download](../../releases/latest) |
@@ -58,17 +58,17 @@ These are the files an emulator loads from disk instead of carrying inside itsel
Each file is checked the way your platform checks it. Most compare a checksum, the fingerprint of a file's contents, which catches a corrupt or unexpected copy. RetroArch, Lakka and RetroPie only look for the filename, because that is all their code does: the Coverage table says which applies to you. Independently of that, the collection records five fingerprints per file, and wherever an emulator's code states an expected size or hash, that value is read from its source and rechecked here.
- **91 files** the platforms' emulators load are not in the collection yet, named in the [gap analysis](https://abdess.github.io/retrobios/gaps/)
- **99 files** the platforms' emulators load are not in the collection yet, named in the [gap analysis](https://abdess.github.io/retrobios/gaps/)
- **12 platforms** supported with platform-specific verification
- **342 emulators** profiled from source (RetroArch cores + standalone)
- **412 systems** handled by those emulators (NES, SNES, PlayStation, Saturn, Dreamcast, ...)
- **354 emulators** profiled from source (RetroArch cores + standalone)
- **415 systems** handled by those emulators (NES, SNES, PlayStation, Saturn, Dreamcast, ...)
- **7,763 files**, each with its SHA1, MD5, SHA256, CRC32 and Adler-32 fingerprints: 2,478 system files, 2,746 arcade ROM sets, 2,539 game and engine data files
- **531 of 2,478 system files** matched to dump-preservation catalogs (No-Intro, Redump, TOSEC); arcade sets and engine data fall outside what those catalogs index
- **9854 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 378+ 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 381+ more.
Full list with per-file details: **[https://abdess.github.io/retrobios/](https://abdess.github.io/retrobios/)**
@@ -76,18 +76,18 @@ Full list with per-file details: **[https://abdess.github.io/retrobios/](https:/
| Platform | On its BIOS list | Files its emulators load | Checked by |
|----------|-----------------:|-------------------------:|------------|
| Batocera | 353/353 | 1,146/1,237 | MD5 hash |
| Batocera | 353/353 | 1,146/1,245 | MD5 hash |
| BizHawk | 118/118 | 367/368 | SHA1 hash |
| EmuDeck | 161/161 | 404/404 | MD5 hash |
| Lakka | 530/530 | 1,149/1,154 | file presence |
| EmuDeck | 161/161 | 405/405 | MD5 hash |
| Lakka | 530/530 | 1,150/1,155 | file presence |
| MiSTer FPGA | 65/65 | - | MD5 hash |
| ROCKNIX | 38/38 | 1,483/1,488 | MD5 hash |
| Recalbox | 346/346 | 716/721 | MD5 hash |
| RetroArch | 530/530 | 1,149/1,154 | file presence |
| RetroBat | 341/341 | 808/898 | MD5 hash |
| RetroDECK | 2,008/2,008 | 1,183/1,189 | MD5 hash |
| RetroPie * | 530/530 | 1,149/1,154 | file presence |
| RomM | 374/374 | 267/270 | MD5 hash |
| ROCKNIX | 38/38 | 1,484/1,489 | MD5 hash |
| Recalbox | 346/346 | 718/723 | MD5 hash |
| RetroArch | 530/530 | 1,150/1,155 | file presence |
| RetroBat | 341/341 | 808/906 | MD5 hash |
| RetroDECK | 2,008/2,008 | 1,184/1,198 | MD5 hash |
| RetroPie * | 530/530 | 1,150/1,155 | file presence |
| RomM | 374/374 | 268/271 | MD5 hash |
Each fraction is what the pack has over what is needed, counting required and optional files alike since both ship. The first column is the BIOS list the platform publishes. The second counts files its emulators load that this list never mentions, found by reading their source code, and it is routinely several times larger. A short fraction means files are still missing, and they are named in the [gap analysis](https://abdess.github.io/retrobios/gaps/).
That second number is a floor, not a ceiling: an emulator that accepts any file handed to it names none in its code, so nothing there can be counted.
@@ -127,7 +127,7 @@ The [documentation site](https://abdess.github.io/retrobios/) provides:
- **Per-emulator profiles** with source code references for every file
- **Per-system pages** showing which emulators and platforms cover each console
- **Gap analysis** identifying missing files and undeclared core requirements
- **Cross-reference** mapping files across 12 platforms and 342 emulators
- **Cross-reference** mapping files across 12 platforms and 354 emulators
## How it works
@@ -164,4 +164,4 @@ The scripts and tooling are released under the [MIT License](LICENSE).
The BIOS and firmware files are not covered by that license: they are third-party system software, preserved and provided for personal backup, archival, and interoperability with emulation software.
The legal reasoning is laid out in the [FAQ](https://abdess.github.io/retrobios/wiki/faq/#is-this-legal).
*Auto-generated on 2026-08-08T11:35:43Z*
*Auto-generated on 2026-08-08T16:19:01Z*
+4 -1
View File
@@ -1,5 +1,5 @@
{
"generated_at": "2026-08-08T07:33:54Z",
"generated_at": "2026-08-08T13:50:06Z",
"total_files": 7763,
"total_size": 10332160603,
"files": {
@@ -112964,6 +112964,9 @@
"342-0077-b": [
"e4fc7560b69d062cb2da5b1ffbe11cd1ca03cc37"
],
"Mac OS ROM": [
"e4fc7560b69d062cb2da5b1ffbe11cd1ca03cc37"
],
"fx-scsi.rom": [
"65482a23ac5c10a6095aee1db5824cca54ead6e5"
],
+1 -1
View File
@@ -28,7 +28,7 @@ notes: >
files:
- name: "lynxboot.img"
description: "Atari Lynx boot ROM"
region: "World"
region: [world]
required: true
size: 512
crc32: "0d973c9d"
+6 -6
View File
@@ -23,7 +23,7 @@ notes: >
files:
- name: "syscard3.pce"
description: "CD-ROM System Card 3.0 (Japan)"
region: "NTSC-J"
region: [japan]
required: true
sha1: "79f5ff55dd10187c7fd7b8daab0b3ffbd1f56a2c"
md5: "38179df8f4ac870017db21ebcbf53114"
@@ -32,7 +32,7 @@ files:
- name: "syscard3u.pce"
description: "CD-ROM System Card 3.0 (US / TurboGrafx-CD)"
region: "NTSC-U"
region: [north-america]
required: false
sha1: "d02611d99921986147c753df14c7349b31d71950"
md5: "0754f903b52e3b3342202bdafb13efa5"
@@ -41,7 +41,7 @@ files:
- name: "syscard2.pce"
description: "CD-ROM System Card 2.0 (Japan)"
region: "NTSC-J"
region: [japan]
required: false
sha1: "88da02e2503f7c32810f5d93a34849d470742b6d"
md5: "3cdd6614a918616bfc41c862e889dd79"
@@ -50,7 +50,7 @@ files:
- name: "syscard2u.pce"
description: "CD-ROM System Card 2.0 (US / TurboGrafx-CD)"
region: "NTSC-U"
region: [north-america]
required: false
sha1: "2bea3dac98f84b2f2f469fa77ea720b8770d598d"
md5: "94279f315e8b52904f65ab3108542afe"
@@ -59,7 +59,7 @@ files:
- name: "syscard1.pce"
description: "CD-ROM System Card 1.0 (Japan)"
region: "NTSC-J"
region: [japan]
required: false
sha1: "a39a66da7de6ba94ab84d04eef7afeec7d4ee66a"
md5: "2b7ccb3d86baa18f6402c176f3065082"
@@ -68,7 +68,7 @@ files:
- name: "gexpress.pce"
description: "Games Express CD Card"
region: "NTSC-J"
region: [japan]
required: false
sha1: "014881a959e045e00f4db8f52955200865d40280"
md5: "6d2cb14fc3e1f65ceb135633d1694122"
+7 -7
View File
@@ -30,7 +30,7 @@ files:
- name: "scph5500.bin"
description: "SCPH-5500 (v3.0 09-09-96 J)"
region: "NTSC-J"
region: [japan]
required: true
hle_fallback: true
size: 524288
@@ -43,7 +43,7 @@ files:
- name: "scph5903.bin"
description: "SCPH-5903 (System ROM Version 2.2 12/04/95 J), Video CD daughterboard"
region: "NTSC-J"
region: [japan]
required: false
size: 1048576
sha1: "15c94da3cc5a38a582429575af4198c487fe893c"
@@ -56,7 +56,7 @@ files:
- name: "scph5501.bin"
description: "SCPH-5501, 5503, 7003 (v3.0 11-18-96 A)"
region: "NTSC-U"
region: [north-america]
required: true
hle_fallback: true
size: 524288
@@ -79,7 +79,7 @@ files:
- name: "scph5502.bin"
description: "SCPH-5502, 5552 (v3.0 01-06-97 E)"
region: "PAL"
region: [europe]
required: true
hle_fallback: true
size: 524288
@@ -99,7 +99,7 @@ files:
- name: "psxonpsp660.bin"
description: "PSP embedded PS1 BIOS (region-free override)"
region: "Auto"
region: [world]
required: false
size: 524288
sha1: "96880d1ca92a016ff054be5159bb06fe03cb4e14"
@@ -112,7 +112,7 @@ files:
- name: "ps1_rom.bin"
description: "PS3 embedded PS1 BIOS, first 512KB extracted (region-free override)"
region: "Auto"
region: [world]
required: false
sha1: "c40146361eb8cf670b19fdc9759190257803cab7"
md5: "81bbe60ba7a3d1cea1d48c14cbcc647b"
@@ -124,7 +124,7 @@ files:
- name: "openbios.bin"
description: "OpenBIOS (open-source PS1 HLE BIOS, region-free override)"
region: "Auto"
region: [world]
required: false
size: 524288
mode: libretro
+10 -1
View File
@@ -10,7 +10,7 @@ core_version: "Git"
display_name: "Nintendo - GameCube / Wii (Dolphin)"
cores:
- dolphin
systems: [nintendo-gamecube, nintendo-wii]
systems: [nintendo-gamecube, nintendo-wii, sega-triforce]
# File paths are relative to Dolphin User directory:
# Standalone: User/GC/ and User/Wii/
@@ -101,6 +101,15 @@ files:
note: "Shift-JIS font for Japanese text. Free alternative bundled, real one from IPL dump preferred"
source_ref: "Source/Core/Common/CommonPaths.h:134, Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp:129,234"
# -- Triforce firmware --
# Loaded from User/Triforce/ only, no Sys fallback.
- name: "segaboot.gcm"
path: "Triforce/segaboot.gcm"
system: sega-triforce
required: true
note: "SegaBoot, the Triforce system disc image. Read on every Triforce boot, min(size, 2 MiB) copied into the firmware buffer, nothing validated"
source_ref: "Source/Core/Core/HW/DVD/AMMediaboard.cpp:159,512,531-551, Source/Core/Core/HW/DVD/DVDInterface.cpp:292-294, Source/Core/Core/System.h:147"
# -- GBA BIOS (for GC-GBA link) --
# Used by integrated mGBA core for GameCube-GBA connectivity.
# Loaded from User/GBA/gba_bios.bin (no Sys fallback).
+105 -105
View File
@@ -47,7 +47,7 @@ files:
- name: "scph1000.bin"
description: "SCPH-1000, DTL-H1000 (v1.0)"
region: "NTSC-J"
region: [japan]
required: false
md5: "239665b1a3dade1b5a52c06338011044"
region_check: true
@@ -57,7 +57,7 @@ files:
- name: "scph1001.bin"
description: "SCPH-1001, 5003, DTL-H1201, H3001 (v2.2 12-04-95 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "924e392ed05558ffdb115408c263dccf"
region_check: false
@@ -67,7 +67,7 @@ files:
- name: "scph1002a.bin"
description: "SCPH-1002, DTL-H1002 (v2.0 05-10-95 E)"
region: "PAL"
region: [europe]
required: false
md5: "54847e693405ffeb0359c6287434cbef"
region_check: false
@@ -77,7 +77,7 @@ files:
- name: "scph1002b.bin"
description: "SCPH-1002, DTL-H1102 (v2.1 07-17-95 E)"
region: "PAL"
region: [europe]
required: false
md5: "417b34706319da7cf001e76e40136c23"
region_check: false
@@ -87,7 +87,7 @@ files:
- name: "scph1002c.bin"
description: "SCPH-1002, DTL-H1202, H3002 (v2.2 12-04-95 E)"
region: "PAL"
region: [europe]
required: false
md5: "e2110b8a2b97a8e0b857a45d32f7e187"
region_check: false
@@ -97,7 +97,7 @@ files:
- name: "dtlh1100.bin"
description: "DTL-H1100 (v2.2 03-06-96 D)"
region: "NTSC-J"
region: [japan]
required: false
md5: "ca5cfc321f916756e3f0effbfaeba13b"
region_check: true
@@ -107,7 +107,7 @@ files:
- name: "scph3000.bin"
description: "SCPH-3000, DTL-H1000H (v1.1 01-22-95)"
region: "NTSC-J"
region: [japan]
required: false
md5: "849515939161e62f6b866f6853006780"
region_check: true
@@ -117,7 +117,7 @@ files:
- name: "scph1001_v20.bin"
description: "SCPH-1001, DTL-H1001 (v2.0 05-07-95 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "dc2b9bf8da62ec93e868cfd29f0d067d"
region_check: false
@@ -127,7 +127,7 @@ files:
- name: "scph3500.bin"
description: "SCPH-3500 (v2.1 07-17-95 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "cba733ceeff5aef5c32254f1d617fa62"
region_check: true
@@ -137,7 +137,7 @@ files:
- name: "scph1001_v21.bin"
description: "SCPH-1001, DTL-H1101 (v2.1 07-17-95 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "da27e8b6dab242d8f91a9b25d80c63b8"
region_check: false
@@ -147,7 +147,7 @@ files:
- name: "scph5000.bin"
description: "SCPH-5000, DTL-H1200, H3000 (v2.2 12-04-95 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "57a06303dfa9cf9351222dfcbb4a29d9"
region_check: true
@@ -157,7 +157,7 @@ files:
- name: "scph5500.bin"
description: "SCPH-5500 (v3.0 09-09-96 J)"
region: "NTSC-J"
region: [japan]
required: true
md5: "8dd7d5296a650fac7319bce665a6a53c"
region_check: true
@@ -167,7 +167,7 @@ files:
- name: "scph5501.bin"
description: "SCPH-5501, 5503, 7003 (v3.0 11-18-96 A)"
region: "NTSC-U"
region: [north-america]
required: true
md5: "490f666e1afb15b7362b406ed1cea246"
region_check: false
@@ -177,7 +177,7 @@ files:
- name: "scph5502.bin"
description: "SCPH-5502, 5552 (v3.0 01-06-97 E)"
region: "PAL"
region: [europe]
required: true
md5: "32736f17079d0b2b7024407c39bd3050"
region_check: false
@@ -187,7 +187,7 @@ files:
- name: "scph7000.bin"
description: "SCPH-7000, 7500, 9000 (v4.0 08-18-97 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "8e4c14f567745eff2f0408c8129f72a6"
region_check: true
@@ -197,7 +197,7 @@ files:
- name: "scph7000w.bin"
description: "SCPH-7000W (v4.1 11-14-97 A)"
region: "NTSC-J"
region: [japan]
required: false
md5: "b84be139db3ee6cbd075630aa20a6553"
region_check: false
@@ -207,7 +207,7 @@ files:
- name: "scph7001.bin"
description: "SCPH-7001, 7501, 7503, 9001, 9003, 9903 (v4.1 12-16-97 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "1e68c231d0896b7eadcad1d7d8e76129"
region_check: false
@@ -217,7 +217,7 @@ files:
- name: "scph7002.bin"
description: "SCPH-7002, 7502, 9002 (v4.1 12-16-97 E)"
region: "PAL"
region: [europe]
required: false
md5: "b9d9a0286c33dc6b7237bb13cd46fdee"
region_check: false
@@ -227,7 +227,7 @@ files:
- name: "scph100.bin"
description: "SCPH-100 (v4.3 03-11-00 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "8abc1b549a4a80954addc48ef02c4521"
region_check: true
@@ -237,7 +237,7 @@ files:
- name: "scph101_v44.bin"
description: "SCPH-101 (v4.4 03-24-00 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "9a09ab7e49b422c007e6d54d7c49b965"
region_check: false
@@ -247,7 +247,7 @@ files:
- name: "scph101_v45.bin"
description: "SCPH-101 (v4.5 05-25-00 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "6e3735ff4c7dc899ee98981385f6f3d0"
region_check: false
@@ -257,7 +257,7 @@ files:
- name: "scph102_v44.bin"
description: "SCPH-102 (v4.4 03-24-00 E)"
region: "PAL"
region: [europe]
required: false
md5: "b10f5e0e3d9eb60e5159690680b1e774"
region_check: true
@@ -267,7 +267,7 @@ files:
- name: "scph102_v45.bin"
description: "SCPH-102 (v4.5 05-25-00 E)"
region: "PAL"
region: [europe]
required: false
md5: "de93caec13d1a141a40a79f5c86168d6"
region_check: true
@@ -277,7 +277,7 @@ files:
- name: "scph1000r.bin"
description: "SCPH-1000R (v4.5 05-25-00 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "476d68a94ccec3b9c8303bbd1daf2810"
region_check: true
@@ -291,7 +291,7 @@ files:
- name: "ps2_scph18000.bin"
description: "PS2, SCPH-18000 (v5.0 10-27-00 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "d8f485717a5237285e4d7c5f881b7f32"
region_check: true
@@ -301,7 +301,7 @@ files:
- name: "ps2_scph30003.bin"
description: "PS2, SCPH-30003 (v5.0 09-02-00 E)"
region: "PAL"
region: [europe]
required: false
md5: "71f50ef4f4e17c163c78908e16244f7d"
region_check: true
@@ -311,7 +311,7 @@ files:
- name: "ps2_dtlh10000_0117.bin"
description: "PS2, DTL-H10000 (v5.0 01/17/00 T)"
region: "Auto"
region: [world]
required: false
md5: "32f2e4d5ff5ee11072a6bc45530f5765"
region_check: true
@@ -321,7 +321,7 @@ files:
- name: "ps2_scph10000_0117.bin"
description: "PS2, SCPH-10000 (v5.0 01/17/00 T)"
region: "Auto"
region: [world]
required: false
md5: "acf4730ceb38ac9d8c7d8e21f2614600"
region_check: true
@@ -331,7 +331,7 @@ files:
- name: "ps2_dtlh10000_0217.bin"
description: "PS2, DTL-H10000 (v5.0 02/17/00 T)"
region: "Auto"
region: [world]
required: false
md5: "acf9968c8f596d2b15f42272082513d1"
region_check: true
@@ -341,7 +341,7 @@ files:
- name: "ps2_scph10000_15000.bin"
description: "PS2, SCPH-10000/SCPH-15000 (v5.0 02/17/00 T)"
region: "Auto"
region: [world]
required: false
md5: "b1459d7446c69e3e97e6ace3ae23dd1c"
region_check: true
@@ -351,7 +351,7 @@ files:
- name: "ps2_dtlh10000_0224.bin"
description: "PS2, DTL-H10000 (v5.0 02/24/00 T)"
region: "Auto"
region: [world]
required: false
md5: "d3f1853a16c2ec18f3cd1ae655213308"
region_check: true
@@ -361,7 +361,7 @@ files:
- name: "ps2_dtlh30001.bin"
description: "PS2, DTL-H30001 (v5.0 07/27/00 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "63e6fd9b3c72e0d7b920e80cf76645cd"
region_check: true
@@ -371,7 +371,7 @@ files:
- name: "ps2_scph30001_0727.bin"
description: "PS2, SCPH-30001 (v5.0 07/27/00 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "a20c97c02210f16678ca3010127caf36"
region_check: true
@@ -381,7 +381,7 @@ files:
- name: "ps2_scph30001_0902.bin"
description: "PS2, SCPH-30001 (v5.0 09/02/00 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "8db2fbbac7413bf3e7154c1e0715e565"
region_check: true
@@ -391,7 +391,7 @@ files:
- name: "ps2_dtlh30002.bin"
description: "PS2, DTL-H30002 (v5.0 09/02/00 E)"
region: "PAL"
region: [europe]
required: false
md5: "91c87cb2f2eb6ce529a2360f80ce2457"
region_check: true
@@ -401,7 +401,7 @@ files:
- name: "ps2_dtlh30102_0902.bin"
description: "PS2, DTL-H30102 (v5.0 09/02/00 E)"
region: "PAL"
region: [europe]
required: false
md5: "3016b3dd42148a67e2c048595ca4d7ce"
region_check: true
@@ -411,7 +411,7 @@ files:
- name: "ps2_scph30002_0902.bin"
description: "PS2, SCPH-30002/SCPH-30003/SCPH-30004 (v5.0 09/02/00 E)"
region: "PAL"
region: [europe]
required: false
md5: "b7fa11e87d51752a98b38e3e691cbf17"
region_check: true
@@ -421,7 +421,7 @@ files:
- name: "ps2_scph18000_gh003.bin"
description: "PS2, SCPH-18000 (GH-003) (v5.0 10/27/00 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "f63bc530bd7ad7c026fcd6f7bd0d9525"
region_check: true
@@ -431,7 +431,7 @@ files:
- name: "ps2_scph18000_gh008.bin"
description: "PS2, SCPH-18000 (GH-008) (v5.0 10/27/00 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "cee06bd68c333fc5768244eae77e4495"
region_check: true
@@ -441,7 +441,7 @@ files:
- name: "ps2_dtlh30101.bin"
description: "PS2, DTL-H30101 (v5.0 12/28/00 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "0bf988e9c7aaa4c051805b0fa6eb3387"
region_check: true
@@ -451,7 +451,7 @@ files:
- name: "ps2_scph30001_35001.bin"
description: "PS2, SCPH-30001/SCPH-35001 (v5.0 12/28/00 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "8accc3c49ac45f5ae2c5db0adc854633"
region_check: true
@@ -461,7 +461,7 @@ files:
- name: "ps2_dtlh30102_1228.bin"
description: "PS2, DTL-H30102 (v5.0 12/28/00 E)"
region: "PAL"
region: [europe]
required: false
md5: "6f9a6feb749f0533aaae2cc45090b0ed"
region_check: true
@@ -471,7 +471,7 @@ files:
- name: "ps2_scph30002_1228.bin"
description: "PS2, SCPH-30002/SCPH-30003/SCPH-30004/SCHP-35002/SCPH-35003/SCPH-35004 (v5.0 12/28/00 E)"
region: "PAL"
region: [europe]
required: false
md5: "838544f12de9b0abc90811279ee223c8"
region_check: true
@@ -481,7 +481,7 @@ files:
- name: "ps2_dtlh30000.bin"
description: "PS2, DTL-H30000 (v5.0 01/18/01 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "bb6bbc850458fff08af30e969ffd0175"
region_check: true
@@ -491,7 +491,7 @@ files:
- name: "ps2_scph30000_35000.bin"
description: "PS2, SCPH-30000/SCPH-35000 (v5.0 01/18/01 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "815ac991d8bc3b364696bead3457de7d"
region_check: true
@@ -501,7 +501,7 @@ files:
- name: "ps2_scph30001r_0427.bin"
description: "PS2, SCPH-30001R (v5.0 04/27/01 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "b107b5710042abe887c0f6175f6e94bb"
region_check: true
@@ -511,7 +511,7 @@ files:
- name: "ps2_scph30000_0427.bin"
description: "PS2, SCPH-30000 (v5.0 04/27/01 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "ab55cceea548303c22c72570cfd4dd71"
region_check: true
@@ -521,7 +521,7 @@ files:
- name: "ps2_scph30001r_0704.bin"
description: "PS2, SCPH-30001R (v5.0 07/04/01 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "18bcaadb9ff74ed3add26cdf709fff2e"
region_check: true
@@ -531,7 +531,7 @@ files:
- name: "ps2_scph30002r_0704.bin"
description: "PS2, SCPH-30002R/SCPH-30003R/SCPH-30004R (v5.0 07/04/01 E)"
region: "PAL"
region: [europe]
required: false
md5: "491209dd815ceee9de02dbbc408c06d6"
region_check: true
@@ -541,7 +541,7 @@ files:
- name: "ps2_scph30001r_1004.bin"
description: "PS2, SCPH-30001R (v5.0 10/04/01 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "7200a03d51cacc4c14fcdfdbc4898431"
region_check: true
@@ -551,7 +551,7 @@ files:
- name: "ps2_scph30002r_1004.bin"
description: "PS2, SCPH-30002R/SCPH-30003R/SCPH-30004R (v5.0 10/04/01 E)"
region: "PAL"
region: [europe]
required: false
md5: "8359638e857c8bc18c3c18ac17d9cc3c"
region_check: true
@@ -561,7 +561,7 @@ files:
- name: "ps2_scph30005r.bin"
description: "PS2, SCPH-30005R/SCPH-30006R/SCPH-30007R (v5.0 07/30/01 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "352d2ff9b3f68be7e6fa7e6dd8389346"
region_check: true
@@ -571,7 +571,7 @@ files:
- name: "ps2_scph39001.bin"
description: "PS2, SCPH-39001 (v5.0 02/07/02 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "d5ce2c7d119f563ce04bc04dbc3a323e"
region_check: true
@@ -581,7 +581,7 @@ files:
- name: "ps2_scph39002.bin"
description: "PS2, SCPH-39002/SCPH-39003/SCPH-39004 (v5.0 03/19/02 E)"
region: "PAL"
region: [europe]
required: false
md5: "0d2228e6fd4fb639c9c39d077a9ec10c"
region_check: true
@@ -591,7 +591,7 @@ files:
- name: "ps2_scph37000_39000.bin"
description: "PS2, SCPH-37000/SCPH-39000 (v5.0 04/26/02 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "72da56fccb8fcd77bba16d1b6f479914"
region_check: true
@@ -601,7 +601,7 @@ files:
- name: "ps2_scph39008.bin"
description: "PS2, SCPH-39008 (v5.0 04/26/02 E)"
region: "PAL"
region: [europe]
required: false
md5: "5b1f47fbeb277c6be2fccdd6344ff2fd"
region_check: true
@@ -611,7 +611,7 @@ files:
- name: "ps2_scph39005.bin"
description: "PS2, SCPH-39005/SCPH-39006/SCPH-39007 (v5.0 04/26/02 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "315a4003535dfda689752cb25f24785c"
region_check: true
@@ -621,7 +621,7 @@ files:
- name: "ps2_dtlh50000.bin"
description: "PS2, DTL-H50000 (v5.0 02/06/03 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "54ecde087258557e2ddb5c3ddb004028"
region_check: true
@@ -631,7 +631,7 @@ files:
- name: "ps2_scph50000_55000.bin"
description: "PS2, SCPH-50000/SCPH-55000 (v5.0 02/06/03 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "312ad4816c232a9606e56f946bc0678a"
region_check: true
@@ -641,7 +641,7 @@ files:
- name: "ps2_dtlh50002.bin"
description: "PS2, DTL-H50002 (v5.0 02/27/03 E)"
region: "PAL"
region: [europe]
required: false
md5: "666018ffec65c5c7e04796081295c6c7"
region_check: true
@@ -651,7 +651,7 @@ files:
- name: "ps2_scph50002_0227.bin"
description: "PS2, SCPH-50002/SCPH-50003/SCPH-50004 (v5.0 02/27/03 E)"
region: "PAL"
region: [europe]
required: false
md5: "6e69920fa6eef8522a1d688a11e41bc6"
region_check: true
@@ -661,7 +661,7 @@ files:
- name: "ps2_dtlh50001_0325.bin"
description: "PS2, DTL-H50001 (v5.0 03/25/03 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "eb960de68f0c0f7f9fa083e9f79d0360"
region_check: true
@@ -671,7 +671,7 @@ files:
- name: "ps2_scph50001_0325.bin"
description: "PS2, SCPH-50001 (v5.0 03/25/03 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "8aa12ce243210128c5074552d3b86251"
region_check: true
@@ -681,7 +681,7 @@ files:
- name: "ps2_dtlh50009.bin"
description: "PS2, DTL-H50009 (v5.0 02/24/03 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "240d4c5ddd4b54069bdc4a3cd2faf99d"
region_check: true
@@ -691,7 +691,7 @@ files:
- name: "ps2_desr5000.bin"
description: "PS2, DESR-5000/DESR-5100/DESR-7000/DESR-7100 (v5.0 10/28/03 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "1c6cd089e6c83da618fbf2a081eb4888"
region_check: true
@@ -701,7 +701,7 @@ files:
- name: "ps2_scph55000_0623.bin"
description: "PS2, SCPH-55000 (v5.0 06/23/03 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "463d87789c555a4a7604e97d7db545d1"
region_check: true
@@ -711,7 +711,7 @@ files:
- name: "ps2_dtlh50001_0623.bin"
description: "PS2, DTL-H50001 (v5.0 06/23/03 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "ab9d49ad40ae49f19856ad187777b1b3"
region_check: true
@@ -721,7 +721,7 @@ files:
- name: "ps2_scph50001_0623.bin"
description: "PS2, SCPH-50001/SCPH-50010 (v5.0 06/23/03 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "35461cecaa51712b300b2d6798825048"
region_check: true
@@ -731,7 +731,7 @@ files:
- name: "ps2_scph50002_0623.bin"
description: "PS2, SCPH-50002/SCPH-50003/SCPH-50004 (v5.0 06/23/03 E)"
region: "PAL"
region: [europe]
required: false
md5: "bd6415094e1ce9e05daabe85de807666"
region_check: true
@@ -741,7 +741,7 @@ files:
- name: "ps2_scph50006.bin"
description: "PS2, SCPH-50006/SCPH-50007 (v5.0 06/23/03 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "2e70ad008d4ec8549aada8002fdf42fb"
region_check: true
@@ -751,7 +751,7 @@ files:
- name: "ps2_scph50005.bin"
description: "PS2, SCPH-50005 (v5.0 06/23/03 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "50d5b97b57d8c9b6534adcb46c2027d4"
region_check: true
@@ -761,7 +761,7 @@ files:
- name: "ps2_scph50008.bin"
description: "PS2, SCPH-50008 (v5.0 06/23/03 E)"
region: "PAL"
region: [europe]
required: false
md5: "b53d51edc7fc086685e31b811dc32aad"
region_check: true
@@ -771,7 +771,7 @@ files:
- name: "ps2_scph50009.bin"
description: "PS2, SCPH-50009 (v5.0 06/23/03 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "1b6e631b536247756287b916f9396872"
region_check: true
@@ -781,7 +781,7 @@ files:
- name: "ps2_scph50000_0822.bin"
description: "PS2, SCPH-50000 (v5.0 08/22/03 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "00da1b177096cfd2532c8fa22b43e667"
region_check: true
@@ -791,7 +791,7 @@ files:
- name: "ps2_scph50004_0822.bin"
description: "PS2, SCPH-50004 (v5.0 08/22/03 E)"
region: "PAL"
region: [europe]
required: false
md5: "afde410bd026c16be605a1ae4bd651fd"
region_check: true
@@ -801,7 +801,7 @@ files:
- name: "ps2_scph50011.bin"
description: "PS2, SCPH-50011 (v5.0 03/29/04 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "81f4336c1de607dd0865011c0447052e"
region_check: true
@@ -811,7 +811,7 @@ files:
- name: "ps2_scph70000.bin"
description: "PS2, SCPH-70000 (v5.0 06/14/04 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "0eee5d1c779aa50e94edd168b4ebf42e"
region_check: true
@@ -821,7 +821,7 @@ files:
- name: "ps2_scph70001.bin"
description: "PS2, SCPH-70001/SCPH-70011/SCPH-70012 (v5.0 06/14/04 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "d333558cc14561c1fdc334c75d5f37b7"
region_check: true
@@ -831,7 +831,7 @@ files:
- name: "ps2_scph70002.bin"
description: "PS2, SCPH-70002/SCPH-70003/SCPH-70004/SCPH-70008 (v5.0 06/14/04 E)"
region: "PAL"
region: [europe]
required: false
md5: "dc752f160044f2ed5fc1f4964db2a095"
region_check: true
@@ -841,7 +841,7 @@ files:
- name: "ps2_scph70002_alt.bin"
description: "PS2, SCPH-70002 (v5.0 06/14/04 E)"
region: "PAL"
region: [europe]
required: false
md5: "7ebb4fc5eab6f79a27d76ac9aad392b2"
region_check: true
@@ -851,7 +851,7 @@ files:
- name: "ps2_dtlh70002.bin"
description: "PS2, DTL-H70002 (v5.0 06/14/04 E)"
region: "PAL"
region: [europe]
required: false
md5: "63ead1d74893bf7f36880af81f68a82d"
region_check: true
@@ -861,7 +861,7 @@ files:
- name: "ps2_scph70005.bin"
description: "PS2, SCPH-70005/SCPH-70006/SCPH-70007 (v5.0 06/14/04 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "3e3e030c0f600442fa05b94f87a1e238"
region_check: true
@@ -871,7 +871,7 @@ files:
- name: "ps2_desr5500.bin"
description: "PS2, DESR-5500/DESR-5700/DESR-7500/DESR-7700 (v5.0 09/17/04 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "1ad977bb539fc9448a08ab276a836bbc"
region_check: true
@@ -881,7 +881,7 @@ files:
- name: "ps2_dtlh75000.bin"
description: "PS2, DTL-H75000 (v5.0 06/20/05 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "bf0078ba5e19d57eae18047407f3b6e5"
region_check: true
@@ -891,7 +891,7 @@ files:
- name: "ps2_scph75000.bin"
description: "PS2, SCPH-75000 (v5.0 06/20/05 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "eb4f40fcf4911ede39c1bbfe91e7a89a"
region_check: true
@@ -901,7 +901,7 @@ files:
- name: "ps2_dtlh75000a.bin"
description: "PS2, DTL-H75000A (v5.0 06/20/05 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "9959ad7a8685cad66206e7752ca23f8b"
region_check: true
@@ -911,7 +911,7 @@ files:
- name: "ps2_scph75001.bin"
description: "PS2, SCPH-75001/SCPH-75010 (v5.0 06/20/05 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "929a14baca1776b00869f983aa6e14d2"
region_check: true
@@ -921,7 +921,7 @@ files:
- name: "ps2_scph75002.bin"
description: "PS2, SCPH-75002/SCPH-75003/SCPH-75004/SCPH-75008 (v5.0 06/20/05 E)"
region: "PAL"
region: [europe]
required: false
md5: "573f7d4a430c32b3cc0fd0c41e104bbd"
region_check: true
@@ -931,7 +931,7 @@ files:
- name: "ps2_scph75006.bin"
description: "PS2, SCPH-75006 (v5.0 06/20/05 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "df63a604e8bff5b0599bd1a6c2721bd0"
region_check: true
@@ -941,7 +941,7 @@ files:
- name: "ps2_scph77000.bin"
description: "PS2, SCPH-77000 (v5.0 02/10/06 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "5b1ba4bb914406fae75ab8e38901684d"
region_check: true
@@ -951,7 +951,7 @@ files:
- name: "ps2_scph77001.bin"
description: "PS2, SCPH-77001/SCPH-77010 (v5.0 02/10/06 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "cb801b7920a7d536ba07b6534d2433ca"
region_check: true
@@ -961,7 +961,7 @@ files:
- name: "ps2_scph77002.bin"
description: "PS2, SCPH-77002/SCPH-77003/SCPH-77004/SCPH-77008 (v5.0 02/10/06 E)"
region: "PAL"
region: [europe]
required: false
md5: "af60e6d1a939019d55e5b330d24b1c25"
region_check: true
@@ -971,7 +971,7 @@ files:
- name: "ps2_scph77006.bin"
description: "PS2, SCPH-77006/SCPH-77007 (v5.0 02/10/06 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "549a66d0c698635ca9fa3ab012da7129"
region_check: true
@@ -981,7 +981,7 @@ files:
- name: "ps2_dtlh90000_j.bin"
description: "PS2, DTL-H90000 (v5.0 09/05/06 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "5e2014472c88f74f7547d8c2c60eca45"
region_check: true
@@ -991,7 +991,7 @@ files:
- name: "ps2_scph79000_90000.bin"
description: "PS2, SCPH-79000/SCPH-90000 (v5.0 09/05/06 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "5de9d0d730ff1e7ad122806335332524"
region_check: true
@@ -1001,7 +1001,7 @@ files:
- name: "ps2_dtlh90000_a.bin"
description: "PS2, DTL-H90000 (v5.0 09/05/06 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "21fe4cad111f7dc0f9af29477057f88d"
region_check: true
@@ -1011,7 +1011,7 @@ files:
- name: "ps2_scph79001_90001.bin"
description: "PS2, SCPH-79001/SCPH-79010/SCPH-90001 (v5.0 09/05/06 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "40c11c063b3b9409aa5e4058e984e30c"
region_check: true
@@ -1021,7 +1021,7 @@ files:
- name: "ps2_scph79002_90002.bin"
description: "PS2, SCPH-79002/SCPH-79003/SCPH-79004/SCPH-79008/SCPH-90002/SCPH-90003/SCPH-90004 (v5.0 09/05/06 E)"
region: "PAL"
region: [europe]
required: false
md5: "80bbb237a6af9c611df43b16b930b683"
region_check: true
@@ -1031,7 +1031,7 @@ files:
- name: "ps2_scph79006_90006.bin"
description: "PS2, SCPH-79006/SCPH-79007/SCPH-90006/SCPH-90007 (v5.0 09/05/06 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "c37bce95d32b2be480f87dd32704e664"
region_check: true
@@ -1041,7 +1041,7 @@ files:
- name: "ps2_scph90000_0220.bin"
description: "PS2, SCPH-90000 (v5.0 02/20/08 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "80ac46fa7e77b8ab4366e86948e54f83"
region_check: true
@@ -1051,7 +1051,7 @@ files:
- name: "ps2_scph90001_0220.bin"
description: "PS2, SCPH-90001/SCPH-90010 (v5.0 02/20/08 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "21038400dc633070a78ad53090c53017"
region_check: true
@@ -1061,7 +1061,7 @@ files:
- name: "ps2_scph90002_0220.bin"
description: "PS2, SCPH-90002/SCPH-90003/SCPH-90004/SCPH-90008 (v5.0 02/20/08 E)"
region: "PAL"
region: [europe]
required: false
md5: "dc69f0643a3030aaa4797501b483d6c4"
region_check: true
@@ -1071,7 +1071,7 @@ files:
- name: "ps2_scph90005_0220.bin"
description: "PS2, SCPH-90005/SCPH-90006/SCPH-90007 (v5.0 02/20/08 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "30d56e79d89fbddf10938fa67fe3f34e"
region_check: true
@@ -1081,7 +1081,7 @@ files:
- name: "ps2_kdl22px300.bin"
description: "PS2, KDL-22PX300 (v5.0 04/15/10 E)"
region: "PAL"
region: [europe]
required: false
md5: "93ea3bcee4252627919175ff1b16a1d9"
region_check: true
@@ -1094,7 +1094,7 @@ files:
- name: "openbios.bin"
description: "OpenBIOS"
region: "Auto"
region: [world]
required: false
md5: null
region_check: false
+1 -1
View File
@@ -37,7 +37,7 @@ notes: |
files:
- name: "lynxboot.img"
description: "Atari Lynx boot ROM"
region: "World"
region: [world]
required: true
size: 512
sha1: "e4ed47fae31693e016b081c6bda48da5b70d7ccb"
-2
View File
@@ -75,7 +75,6 @@ files:
- "Supercharger_BIOS.bin"
- "supercharger_bios.bin"
- "SUPERCHARGER_BIOS.bin"
region: "NTSC"
required: false
hle_fallback: true
size: 2048
@@ -89,7 +88,6 @@ files:
aliases:
- "Supercharger_BIOS_PAL.bin"
- "SUPERCHARGER_BIOS_PAL.bin"
region: "PAL"
required: false
hle_fallback: true
size: 2048
+6 -6
View File
@@ -25,28 +25,28 @@ notes: >
files:
- name: "syscard3.pce"
description: "CD-ROM System Card 3.0 (Japan)"
region: "NTSC-J"
region: [japan]
required: true
source_ref: "libretro.cpp:1051-1052, mednafen/settings.cpp:40"
note: "Default value for pce_cdbios option."
- name: "syscard2.pce"
description: "CD-ROM System Card 2.0 (Japan)"
region: "NTSC-J"
region: [japan]
required: false
source_ref: "libretro.cpp:1053-1054"
note: "pce_cdbios = 'System Card 2'."
- name: "syscard1.pce"
description: "CD-ROM System Card 1.0 (Japan)"
region: "NTSC-J"
region: [japan]
required: false
source_ref: "libretro.cpp:1055-1056"
note: "pce_cdbios = 'System Card 1'."
- name: "gexpress.pce"
description: "Games Express CD Card"
region: "NTSC-J"
region: [japan]
required: false
aliases: ["gecard.pce"]
source_ref: "libretro.cpp:1057-1058, mednafen/settings.cpp:41, mednafen/pce/pce.cpp:373-411"
@@ -54,14 +54,14 @@ files:
- name: "syscard3u.pce"
description: "CD-ROM System Card 3.0 (US / TurboGrafx-CD)"
region: "NTSC-U"
region: [north-america]
required: false
source_ref: "libretro.cpp:1059-1060"
note: "pce_cdbios = 'System Card 3 US'. Not in .info."
- name: "syscard2u.pce"
description: "CD-ROM System Card 2.0 (US / TurboGrafx-CD)"
region: "NTSC-U"
region: [north-america]
required: false
source_ref: "libretro.cpp:1061-1062"
note: "pce_cdbios = 'System Card 2 US'. Not in .info."
+6 -6
View File
@@ -23,28 +23,28 @@ notes: >
files:
- name: "syscard3.pce"
description: "CD-ROM System Card 3.0 (Japan)"
region: "NTSC-J"
region: [japan]
required: true
source_ref: "libretro.c:65, libretro.c:1896-1901"
note: "Default value for pce_fast_cdbios option."
- name: "syscard2.pce"
description: "CD-ROM System Card 2.0 (Japan)"
region: "NTSC-J"
region: [japan]
required: false
source_ref: "libretro.c:1903"
note: "pce_fast_cdbios = 'System Card 2'."
- name: "syscard1.pce"
description: "CD-ROM System Card 1.0 (Japan)"
region: "NTSC-J"
region: [japan]
required: false
source_ref: "libretro.c:1905"
note: "pce_fast_cdbios = 'System Card 1'."
- name: "gexpress.pce"
description: "Games Express CD Card"
region: "NTSC-J"
region: [japan]
required: false
aliases: ["gecard.pce"]
source_ref: "libretro.c:1906-1907"
@@ -52,14 +52,14 @@ files:
- name: "syscard3u.pce"
description: "CD-ROM System Card 3.0 (US / TurboGrafx-CD)"
region: "NTSC-U"
region: [north-america]
required: false
source_ref: "libretro.c:1908-1909"
note: "pce_fast_cdbios = 'System Card 3 US'. Not in .info."
- name: "syscard2u.pce"
description: "CD-ROM System Card 2.0 (US / TurboGrafx-CD)"
region: "NTSC-U"
region: [north-america]
required: false
source_ref: "libretro.c:1910-1911"
note: "pce_fast_cdbios = 'System Card 2 US'. Not in .info."
+4 -4
View File
@@ -27,28 +27,28 @@ notes: >
files:
- name: "syscard3.pce"
description: "CD-ROM System Card 3.0 (Japan)"
region: "NTSC-J"
region: [japan]
required: true
source_ref: "libretro.cpp:972-973, mednafen/settings.cpp:37"
note: "Default value for sgx_cdbios option."
- name: "syscard2.pce"
description: "CD-ROM System Card 2.0 (Japan)"
region: "NTSC-J"
region: [japan]
required: false
source_ref: "libretro.cpp:974-975"
note: "sgx_cdbios = 'System Card 2'."
- name: "syscard1.pce"
description: "CD-ROM System Card 1.0 (Japan)"
region: "NTSC-J"
region: [japan]
required: false
source_ref: "libretro.cpp:976-977"
note: "sgx_cdbios = 'System Card 1'."
- name: "gexpress.pce"
description: "Games Express CD Card"
region: "NTSC-J"
region: [japan]
required: false
source_ref: "libretro.cpp:978-979, mednafen/pce_fast/pce.cpp:330-367,453-454"
note: "sgx_cdbios = 'Games Express' or auto-detected via DetectGECD()."
+328
View File
@@ -0,0 +1,328 @@
emulator: Oricutron
type: standalone
core_classification: other
source: "https://github.com/pete-gordon/oricutron"
upstream: "https://www.petergordon.org.uk/oricutron/"
profiled_date: "2026-08-08"
source_commit: "002279fce9fa756d1d63cdc40ae97939eb7de7ed"
core_version: "1.2.0"
display_name: "Tangerine - Oric (Oricutron)"
cores:
- oricutron
systems:
- oric
- oricatmos
mode: standalone
notes: |
Oric-1, Oric-1 16K, Oric Atmos, Telestrat and Pravetz 8D emulator by Peter
Gordon. Recalbox packages it for its oricatmos system, ES-DE offers it for
oric alongside MAME and starts it with the working directory set to the
emulator directory.
ROM names are configured without the extension: load_rom appends ".rom"
(machine.c:1089-1093). The defaults are set in preinit_gui (gui.c:2283-2297)
behind ROMPREFIX, which is "roms/" everywhere except AmigaOS
("PROGDIR:roms/") and the emscripten build ("assets/roms/") (system.h:38-68).
A path read from oricutron.cfg goes through read_config_path
(main.c:341-347), which prepends the program directory resolved from argv[0]
(main.c:196-236), so a relative path resolves against the directory holding
the binary rather than the working directory.
The machine ROM is loaded by init_machine for the selected machine type and
a failure returns SDL_FALSE, after which the emulator exits
(main.c:1442-1446). The four disk controller ROMs are loaded once at startup
by load_diskroms (main.c:1407, machine.c:1249-1255) whatever the machine and
the drive setting; a failure only clears the matching flag and startup
continues. Of those flags only pravetzrom_valid is read afterwards
(machine.c:1055): the Microdisc, BD-500 and Jasmin buffers are mapped into
the CPU address space whether or not the file was read, so a missing file
leaves the selected controller running on zeroed memory.
Size is the only property the code checks. A machine ROM is rejected above
16384 bytes and is loaded right-aligned in its bank, so a shorter file is
accepted (machine.c:1101-1118). A disk controller ROM is read as one
fixed-length block, which fails when the file is shorter than that length
and ignores anything past it (machine.c:1120-1126). No hash is computed
anywhere in the tree.
Telestrat banks 0 to 4 hold RAM unless the config names a file for them
(machine.c:2029-2038). The Twilighte board is off by default and is switched
on with twilighte_board in oricutron.cfg (main.c:660). Its bank config is
opened as a bare relative path (oric_twilighte_board_plugin.c:132) and the
bank filenames in it are read with read_config_string rather than
read_config_path (oric_twilighte_board_plugin.c:174,182), so both resolve
against the working directory and not the program directory.
files:
- name: basic11b.rom
description: "Oric Atmos BASIC 1.1b ROM"
required: true
max_size: 16384
validation: [size]
source_ref: "gui.c:2283 (default roms/basic11b), main.c:553 (atmosrom), machine.c:2006-2007 (MACH_ATMOS)"
note: >
Atmos is the machine oricutron.cfg selects, so this is the ROM a stock
configuration needs. Also named by twilbankrom06 in the Twilighte board
config (plugins/twilighte_board/twilighte.cfg:3).
- name: basic10.rom
description: "Oric-1 BASIC 1.0 ROM"
required: true
max_size: 16384
validation: [size]
source_ref: "gui.c:2284 (default roms/basic10), main.c:554 (oric1rom), machine.c:1932-1933 (MACH_ORIC1_16K), machine.c:1969-1970 (MACH_ORIC1)"
note: "Serves both the 48K Oric-1 and the 16K Oric-1, selected with -m oric1 or -m o16k."
- name: pravetzt.rom
description: "Pravetz 8D BASIC ROM"
required: true
max_size: 16384
validation: [size]
source_ref: "gui.c:2288 (default roms/pravetzt), main.c:558 (pravetzrom), machine.c:2082-2083 (MACH_PRAVETZ)"
note: "Selected with -m pravetz. roms/pravetzt-1.0.pch and .sym ship for an earlier revision of this ROM."
- name: teleass.rom
description: "Telestrat TELEASS ROM, bank 5"
required: true
max_size: 16384
validation: [size]
source_ref: "gui.c:2295 (default roms/teleass), main.c:588-589 (telebank5), machine.c:2029-2033 (MACH_TELESTRAT)"
- name: hyperbas.rom
description: "Telestrat HYPER BASIC ROM, bank 6"
required: true
max_size: 16384
validation: [size]
source_ref: "gui.c:2296 (default roms/hyperbas), main.c:588-589 (telebank6), machine.c:2029-2033 (MACH_TELESTRAT)"
- name: telmon24.rom
description: "Telestrat TELEMON 2.4 ROM, bank 7"
required: true
max_size: 16384
validation: [size]
source_ref: "gui.c:2297 (default roms/telmon24), main.c:588-589 (telebank7), machine.c:2029-2033 (MACH_TELESTRAT)"
note: "Bank 7 is the bank mapped at reset (machine.c:2041-2043)."
- name: microdis.rom
description: "Microdisc disk controller ROM"
required: false
min_size: 8192
validation: [size]
source_ref: "gui.c:2285 (default roms/microdis), main.c:555 (mdiscrom), machine.c:1251, machine.c:904-911 (mapped at $E000)"
note: >
Conditional: needed for the Microdisc controller, which is the drive type
a disk image falls back to when none is given (main.c:1409-1410,
1488-1489). Loaded whatever the machine and not fatal, and
setup_for_microdisc raises romdis, so an absent file leaves the $E000
overlay reading zeroes.
- name: bd500.rom
description: "ByteDrive BD-500 disk controller ROM"
required: false
min_size: 8192
validation: [size]
source_ref: "gui.c:2286 (default roms/bd500), main.c:556 (bd500rom), machine.c:1252, machine.c:937-944 (mapped at $E000)"
note: >
Conditional: needed for the BD-500 controller, selected with -k bd500 or
by autodetecting a BD-500 image (main.c:1478-1481). Same non-fatal load
and same zeroed overlay as the Microdisc ROM. The rom16 and dos70 config
keys change how ROMDIS disables the chips (oricutron.cfg:98-106).
- name: jasmin.rom
description: "Jasmin disk controller ROM"
required: false
min_size: 2048
validation: [size]
source_ref: "gui.c:2287 (default roms/jasmin), main.c:557 (jasminrom), machine.c:1253, machine.c:836-844 (mapped at $F800)"
note: >
Conditional: needed for the Jasmin controller, selected with -k jasmin or
by autodetecting a Jasmin image (main.c:1468-1471). setup_for_jasmin
leaves romdis clear, so the machine still boots from its BASIC ROM.
- name: 8dos2.rom
description: "Pravetz 8D floppy controller boot PROM"
required: false
min_size: 512
validation: [size]
source_ref: "gui.c:2289 (default roms/8dos2), main.c:559 (pravetz8drom), machine.c:1254, machine.c:1053-1058 (mapped at $320-$3FF)"
note: >
Conditional: needed for the Pravetz 8D drive. The only disk ROM whose
load flag is read back, so the Pravetz machine boots without it and only
the drive is lost. oricutron.cfg:44-45 gives roms/8dos as the other
value for this key, and roms/8dos.sym ships for it.
- name: kernel.rom
description: "Orix kernel, Twilighte board ROM bank 7"
required: false
max_size: 16384
validation: [size]
source_ref: "plugins/twilighte_board/twilighte.cfg:2 (twilbankrom07), plugins/twilighte_board/oric_twilighte_board_plugin.c:167-216 (parse and load), plugins/twilighte_board/oric_twilighte_board_plugin.c:63-115 (load_rom_twilighte)"
note: >
Loaded only when twilighte_board is on (main.c:660). A configured bank
file that cannot be read makes twilighte_oric_init return NULL.
ReadMe.txt:506-519 records the copy in the tree as Orix v2022.1 and
points at repo.orix.oric.org for later builds.
- name: shell.rom
description: "Orix shell, Twilighte board ROM bank 5"
required: false
max_size: 16384
validation: [size]
source_ref: "plugins/twilighte_board/twilighte.cfg:4 (twilbankrom05), plugins/twilighte_board/oric_twilighte_board_plugin.c:167-216 (parse and load), plugins/twilighte_board/oric_twilighte_board_plugin.c:63-115 (load_rom_twilighte)"
note: >
Loaded only when twilighte_board is on (main.c:660). ReadMe.txt:506
names kernel.rom in bank 7 and shell.rom in bank 5 as the minimum
configuration for the board to start.
analysis:
gui_images:
source_ref: "gui.c:100-117 (gimgs table), gui.c:425-492 (gimg_load), gui.c:2464-2466 (init_gui)"
lookup: "program directory + IMAGEPREFIX, which is images/ everywhere except AmigaOS and the emscripten build (system.h:38-68)"
validation: "uncompressed 24-bit BMP, one plane, at the exact width and height declared in the table"
fatal: true
note: >
init_gui returns SDL_FALSE on the first image it cannot read and the
emulator exits (main.c:1416-1420). The set ships in the source tree and
in the binary releases, and packagers install it beside the binary:
the RetroDECK recipe copies the whole images directory
(RetroDECK/components archive_later/oricutron/component_recipe.json) and
the ES-DE guide has Linux users take images and roms out of the Windows
archive (USERGUIDE.md:3377-3391).
files:
- statusbar.bmp
- disk_ejected.bmp
- disk_idle.bmp
- disk_active.bmp
- disk_modified.bmp
- disk_modactive.bmp
- tape_ejected.bmp
- tape_pause.bmp
- tape_play.bmp
- tape_stop.bmp
- tape_record.bmp
- avirec.bmp
- gfx_oric1kbd.bmp
- gfx_atmoskbd.bmp
- gfx_pravetzkbd.bmp
conditional_entries:
note: >
gfx_oric1kbd.bmp sits behind WWW_NO_ORIC1 and gfx_pravetzkbd.bmp
behind WWW_NO_PRAVETZ (gui.c:112-118, gui.h:114-120), both of which
only cut down the emscripten build. A native build carries all
fifteen.
non_fatal:
- filename: winicon.bmp
source_ref: "gui.c:2306-2307"
note: "Read with SDL_LoadBMP and passed to SDL_COMPAT_WM_SetIcon, which takes a null surface."
unused:
- filename: status_bar.bmp
reason: "the gimgs table names statusbar.bmp; no code path reads this second file"
rom_sidecars:
note: >
Both sidecars are keyed on the ROM basename from the config, so renaming
or relocating a ROM moves them with it.
symbols:
pattern: "<rom basename>.sym"
source_ref: "machine.c:1129-1133 (load_rom), monitor.c:2676-2691 (mon_new_symbols)"
note: >
Read for all ten ROMs right after the ROM itself, with verbose off, so
an absent file is silent. Fills the debugger symbol tables and nothing
else. Compiled out under WWW_NO_MONITOR.
shipped:
- basic10.sym
- basic11b.sym
- pravetzt.sym
- teleass.sym
- telmon24.sym
- microdis.sym
- jasmin.sym
- bd500.sym
- 8dos2.sym
referenced_but_not_shipped:
- hyperbas.sym
patches:
pattern: "<rom basename>.pch"
source_ref: "machine.c:1726-1740 (load_patches), machine.c:1933,1970,2007,2033,2083 (call sites)"
note: >
Read for the machine ROMs only, never for the disk controller ROMs.
Carries the keyboard layout, the CLOAD/CSAVE filename decoding
addresses, the tape turbo hook addresses and any number of literal
byte patches. An absent file returns silently and leaves
pch_tt_available false (machine.c:1810-1815), so tape turbo stays off
and tapes load at real speed (tape.c:243, 1322-1462).
shipped:
- basic10.pch
- basic11b.pch
- pravetzt.pch
- telmon24.pch
referenced_but_not_shipped:
- teleass.pch
- hyperbas.pch
unconfigured_basenames:
note: >
These sidecars ship for ROM basenames no default config names. They
take effect only once a config key points at that basename, and each
one implies a ROM dump Oricutron can run.
files:
- filename: Bas122uk.pch
implies: "Oric BASIC 1.22 UK, as an atmosrom value"
- filename: Bas122fr.pch
implies: "Oric BASIC 1.22 French, as an atmosrom value"
- filename: Bas122de.pch
implies: "Oric BASIC 1.22 German, as an atmosrom value"
- filename: pravetzt-1.0.pch
implies: "Pravetz BASIC revision 1.0, as a pravetzrom value"
- filename: pravetzt-1.0.sym
implies: "Pravetz BASIC revision 1.0, as a pravetzrom value"
- filename: 8dos.sym
implies: "the earlier Pravetz 8-DOS boot PROM, offered as pravetz8drom in oricutron.cfg:44"
- filename: cumana.sym
implies: "a Cumana controller ROM; its symbols run from $F800, the window jasminrom feeds"
- filename: sedoric.sym
implies: "a Sedoric DOS ROM; its symbols name the Microdisc FDC registers at $310-$318"
unused_resources:
- filename: empty_orix.rom
reason: "no reference anywhere in the tree; not named by any config default nor by twilighte.cfg"
- filename: orixbank1.rom
reason: "no reference anywhere in the tree; loadable only once a twilbankromNN key names it"
- filename: orixbank2.rom
reason: "no reference anywhere in the tree; loadable only once a twilbankromNN key names it"
- filename: orixbank3.rom
reason: "no reference anywhere in the tree; loadable only once a twilbankromNN key names it"
- filename: orixbank4.rom
reason: "no reference anywhere in the tree; loadable only once a twilbankromNN key names it"
- filename: orixbank5.rom
reason: "no reference anywhere in the tree; loadable only once a twilbankromNN key names it"
- filename: orixbank6.rom
reason: "no reference anywhere in the tree; loadable only once a twilbankromNN key names it"
- filename: orixbank7.rom
reason: "no reference anywhere in the tree; loadable only once a twilbankromNN key names it"
user_supplied_paths:
note: "Named on the command line or in the config, with no fixed filename"
entries:
- what: "disk, tape and snapshot images"
source_ref: "main.c:1361-1504, oricutron.cfg:63-86"
- what: "debugger symbol file, -s or --symbols"
source_ref: "main.c:1533-1545"
- what: "breakpoint list, -r or --breakpoint with a leading colon"
source_ref: "main.c:1547-1574"
- what: "keyboard mapping, autoload_keyboard_mapping"
source_ref: "main.c:665 (config key), main.c:2188, keyboard.c:587-598, oricutron.cfg:220"
- what: "CH376 sdcard and usbdrive trees, telestrat mode"
source_ref: "plugins/ch376/ch376.c:1186, ReadMe.txt:512-514"
generated_files:
written_only:
- printer_out.txt
- "AVI captures"
- "snapshots"
- "tape captures"
- "debugger log and memory dumps"
note: "Produced by the emulator, none is user-supplied"
+71
View File
@@ -0,0 +1,71 @@
emulator: Parallel Launcher
type: standalone
core_classification: launcher
source: "https://gitlab.com/parallel-launcher/parallel-launcher"
upstream: "https://gitlab.com/parallel-launcher/parallel-n64"
profiled_date: "2026-08-08"
source_commit: "8f2924c213f7c98118ab5a86fc21c452b77a7057"
upstream_commit: "11574ac28d27faaaef4b5bc3c1ca50fb2ed98b83"
core_version: "9.0.5"
display_name: "Nintendo - Nintendo 64 (Parallel Launcher)"
cores:
- parallel-launcher
- ca.parallel_launcher.ParallelLauncher
systems:
- nintendo-64
- nintendo-64dd
notes: |
Qt front end that installs and drives its own RetroArch and its own fork of
ParaLLEl N64. RetroArch is fetched from buildbot.libretro.com as a stable
release archive (retroarch-updater.cpp:24-30). The core,
parallel_n64_next_libretro, is fetched from parallel-launcher.ca
(updates.cpp:190-213) into retro-data/cores. Core version at this profiling
is 2.28.
Neither lands in a user RetroArch install. The system directory the core
reads from is retro-data/system under the launcher's own data directory,
written into a private retroarch.cfg on every launch (retroarch.cpp:100-129).
RetroArch is spawned as `-L <core> --config <cfg> <rom>`
(retroarch.cpp:760-781). The launcher also rewrites the core's .info into
retro-data/info at every startup (main.cpp:149-156), which is how RetroArch
learns of the 64DD firmware entry.
Content is restricted to cartridge formats at every entry point: command line
and file associations take .z64 .n64 .v64 .bps (main.cpp:65-94), the add-ROM
dialog the same (main-window.cpp:607-616), the library scanner *.[nvz]64
(rom-finder.cpp:271-278), romhacking.com downloads .z64 (sync.cpp:238). A .bps
is patched to a cartridge ROM before launch (play.cpp:721-757). No --subsystem
argument is passed either, so neither route into the core's disk path opens:
the header check at libretro.c:545-548 and the cart-and-disk subsystem at
libretro.c:104-114.
Graphics plugin is chosen per ROM among ParaLLEl-RDP, Glide64, angrylion,
GLideN64, Rice, glN64 and OGRE (settings.hpp:13-22, retroarch.cpp:55-64).
Selecting glN64 also reads gles2n64.conf from the system directory root at
plugin init, and writes it out with defaults when it is absent
(glN64Config.c:246-254, Config_WriteConfig at glN64Config.c:95).
Three paths the fork computes but never reads. GLideN64 builds without
FreeType here, so the font file name it resolves for on-screen text is
assigned and dropped (TextDrawer.cpp:145-188). Its per-game ini is compiled in
as a header and the external copy is skipped because the launcher writes INI
Behaviour as disabled on every launch (retroarch.cpp:468,
Config_mupenplus.cpp:170-241, libretro.c:2030-2040). Rice's ini reader and
writer sit behind #if 0 (RiceConfig.cpp:453-463, Video.cpp:327-333).
files:
- name: "64DD_IPL.bin"
system: nintendo-64dd
required: false
description: "64DD IPL ROM"
note: "Read from the system directory root when disk content is loaded, with no size or hash check. The core drops into its dead-emulator loop when it is absent. Content counts as disk when its header carries a 64DD magic word, or when it arrives on the second slot of the cart-and-disk subsystem."
source_ref: "libretro/libretro.c:622-666"
- name: "gles2n64rom.conf"
system: nintendo-64
required: false
description: "glN64 per-ROM settings database"
note: "Read at plugin init when the glN64 graphics plugin is selected, keyed on the name in the ROM header. Global settings stand when absent."
source_ref: "gles2n64/src/glN64Config.c:185-228"
+121
View File
@@ -0,0 +1,121 @@
emulator: PCSX2 Legacy
type: standalone
core_classification: frozen_snapshot
bios_mode: agnostic
source: "https://github.com/PCSX2/pcsx2"
upstream: "https://github.com/PCSX2/pcsx2"
profiled_date: "2026-08-08"
source_commit: "aaaf29557fe63870ede815dd6d2e48a98279ca59"
core_version: "1.6.0"
display_name: "Sony - PlayStation 2 (PCSX2 Legacy)"
cores:
- pcsx2-legacy
- PCSX2-LEGACY
systems:
- sony-playstation-2
mode: standalone
notes: |
wxWidgets line, frozen at 1.6.0. Emulation is split across separate plugin
binaries loaded at runtime: GSdx, Spu2-X, LilyPad, cdvdGigaherz, DEV9ghzdrk,
USBnull and FWnull. Default BIOS folder is bios/ under the user documents
directory.
ref: pcsx2/gui/AppConfig.cpp:76-80, pcsx2/gui/AppConfig.cpp:192-195
BIOS selection lists every file in the folder with a *.* mask and keeps the
ones whose romdir carries a RESET entry followed by a readable ROMVER, which
supplies the version, the zone letter and the build date. Neither size nor
hash is checked; the length test that would reject small images is commented
out. A missing or zero-length image raises BiosLoadFailed.
ref: pcsx2/gui/Panels/BiosSelectorPanel.cpp:151-177,
pcsx2/ps2/BiosTools.cpp:74-167, pcsx2/ps2/BiosTools.cpp:325-341,
pcsx2/ps2/BiosTools.cpp:261-323
The three companion ROMs derive from the selected BIOS path. Each extension
is first appended to the full name, then substituted for the existing one, so
a BIOS at scph39001.bin is followed by scph39001.bin.rom1 then scph39001.rom1.
A missing companion is logged and skipped, and a read error is downgraded to a
warning. Every read is truncated to its destination region: 256 KB for rom1,
512 KB for rom2, 1.75 MB for erom.
ref: pcsx2/ps2/BiosTools.cpp:190-229, pcsx2/ps2/BiosTools.cpp:298-300,
pcsx2/MemoryTypes.h:21-24
The nvm and mec companions follow the same naming rule and are written with
defaults when absent, so neither is user-supplied: 1024 zero bytes plus an
iLink id for nvm, the four bytes 03 06 02 00 for mec.
ref: pcsx2/CDVD/CDVD.cpp:93-122, pcsx2/CDVD/CDVD.cpp:138-182
Two entries pair an XOR fold of the whole 4 MB ROM region with a ROMVER
version to select debugger thread offsets. They gate nothing and cover no
file on disk.
ref: pcsx2/ps2/BiosTools.cpp:57-62, pcsx2/ps2/BiosTools.cpp:175-181,
pcsx2/ps2/BiosTools.cpp:305-313
An IRX image is injected at ROM+0x3C0000 when one is named on the command
line. The path is whatever the user passes, so there is no fixed file.
ref: pcsx2/ps2/BiosTools.cpp:302-303, pcsx2/gui/AppInit.cpp:542
Shipped in the distribution tree and read from it: GameIndex.dbf, the
widescreen patch archive cheats_ws.zip, which is skipped when a cheats_ws
folder holds the patches, the pcsx2_Main and pcsx2_Iconized catalogs under
Langs, and the external shader pair shaders/GSdx.fx and
shaders/GSdx_FX_Settings.ini, off by default.
ref: pcsx2/gui/AppGameDatabase.h:53, pcsx2/gui/AppCoreThread.cpp:459-465,
pcsx2/gui/i18n.cpp:82-89, plugins/GSdx/GSdx.cpp:441-443
host.irx sits behind a comment. ps2hw.dat is read only by zerogs and
zzogl-pg, both gated on EXTRA_PLUGINS, which carries no default and is off,
and both absent from the Windows solution that builds the release. USBqemu
ships in the same disused solution and GSdx_legacy is gated on GSDX_LEGACY.
ref: pcsx2/ps2/BiosTools.cpp:296, cmake/SelectPcsx2Plugins.cmake:178-209,
cmake/BuildParameters.cmake:41-50, old_plugins.sln
files:
- name: ps2-0230a-20080220.bin
system: sony-playstation-2
required: true
description: "PS2 console BIOS"
note: "Any file in the BIOS folder whose romdir holds RESET and ROMVER is accepted, whatever its name or size. Naming convention ps2-VVVVr-YYYYMMDD.bin carries version, region and date."
source_ref: "pcsx2/ps2/BiosTools.cpp:261-323, pcsx2/ps2/BiosTools.cpp:74-167"
- name: rom1.bin
system: sony-playstation-2
required: false
max_size: 262144
description: "DVD player ROM"
note: "Tried as {bios}.rom1 then {biosbase}.rom1. Read into the 256 KB ROM1 region and truncated to it. Logged and skipped when absent."
source_ref: "pcsx2/ps2/BiosTools.cpp:190-229, pcsx2/ps2/BiosTools.cpp:298, pcsx2/MemoryTypes.h:22"
- name: ROM2.BIN
system: sony-playstation-2
required: false
max_size: 524288
description: "Chinese ROM extension"
note: "Tried as {bios}.rom2 then {biosbase}.rom2. Read into the 512 KB ROM2 region and truncated to it. Present on Chinese region consoles."
source_ref: "pcsx2/ps2/BiosTools.cpp:190-229, pcsx2/ps2/BiosTools.cpp:299, pcsx2/MemoryTypes.h:23"
- name: EROM.BIN
system: sony-playstation-2
required: false
max_size: 1835008
description: "DVD player extension ROM"
note: "Tried as {bios}.erom then {biosbase}.erom. Read into the 1.75 MB EROM region and truncated to it."
source_ref: "pcsx2/ps2/BiosTools.cpp:190-229, pcsx2/ps2/BiosTools.cpp:300, pcsx2/MemoryTypes.h:24"
- name: eeprom.dat
system: sony-playstation-2
required: false
hle_fallback: true
size: 64
description: "DEV9 network adapter EEPROM"
note: "Opened by the DEV9ghzdrk plugin from the working directory and mapped over 64 bytes. A compiled-in EEPROM holding the default MAC stands in when the file is missing or cannot be mapped."
source_ref: "plugins/dev9ghzdrk/DEV9.cpp:176-227, plugins/dev9ghzdrk/DEV9.cpp:71-81"
- name: flash.dat
system: sony-playstation-2
required: false
hle_fallback: true
max_size: 8650752
description: "DEV9 SmartMedia flash image"
note: "Opened by the DEV9ghzdrk plugin from the working directory at init and read as 1024 blocks of 16 pages of 512 bytes plus 16 ECC bytes. The card is filled with 0xFF when the file is absent or short."
source_ref: "plugins/dev9ghzdrk/flash.cpp:60-83, plugins/dev9ghzdrk/flash.cpp:21-28"
+169
View File
@@ -0,0 +1,169 @@
emulator: PCSX2x6
type: standalone
core_classification: enhanced_fork
bios_mode: agnostic
source: "https://github.com/PS2Homebrew-arcade/pcsx2x6"
upstream: "https://github.com/PCSX2/pcsx2"
profiled_date: "2026-08-08"
source_commit: "e69b265ef4bc98565deffb7c4a4b7d08143d4cf9"
upstream_commit: "5c611f85e13ba250a69c155c678482b219b10d48"
core_version: "v0.2.20"
display_name: "Namco - System 246 / 256 (PCSX2x6)"
cores:
- pcsx2x6
- PCSX2X6
systems:
- namco-system246
- namco-system256
notes: |
Namco System 246 and 256 arcade boards, which are Sony COH-H PlayStation 2
motherboards. The Namco hardware sits on the DEV9 bus: ATA and ATAPI media,
the ACCORE interrupt controller, JVS input, the expansion RAM board and the
settings SRAM. Super 256 is the 256 with a higher bus clock, selected by
platform=super256 in the game config.
ref: pcsx2/DEV9/ACATA.cpp, pcsx2/DEV9/ACCORE.cpp, pcsx2/DEV9/ACJV.cpp,
pcsx2/DEV9/ACRAM.cpp, pcsx2/DEV9/ACSRAM.cpp, pcsx2/VMManager.cpp:1382-1418
The BIOS must come from a COH-H board. A romver whose region letter is T
followed by Z is read as zone COH-H, region 11, and the EXTINFO serial names
the board: 20040519-145634 for System 256, 20021119-163841 for System 246
Rack C, 20000901-114731 for the COH-H A-000-010. Boot aborts when no image
loads.
ref: pcsx2/ps2/BiosTools.cpp:149-153, pcsx2/ps2/BiosTools.cpp:178-181,
pcsx2/VMManager.cpp:1657-1667
Detection is by content. The scan lists the BIOS folder with a * mask, keeps
files between 4 and 8 MB, and accepts the ones whose romdir carries a RESET
entry followed by a readable ROMVER; EXTINFO supplies the serial. The picker
in the settings window runs the same romdir test without the size filter, so
a manually selected image of any length is accepted. No name and no hash is
matched anywhere.
ref: pcsx2/ps2/BiosTools.cpp:16-17, pcsx2/ps2/BiosTools.cpp:80-207,
pcsx2/ps2/BiosTools.cpp:268-292,
pcsx2-qt/Settings/BIOSSettingsWidget.cpp:65-73
Companions derive from the selected BIOS path. Each extension is appended to
the full name first, then substituted for the existing one, so an image at
COH-H31100.rom0 is followed by COH-H31100.rom0.rom1 then COH-H31100.rom1.
The project's dumper writes that exact set from a live board: .rom0 of
0x400000, .rom1 of 0x400000, .rom2 of 0x80000, .nvm of 1024 bytes and .mec
of 4 bytes, all named after the board model.
ref: pcsx2/ps2/BiosTools.cpp:224-251, pcsx2/CDVD/CDVD.cpp:164-167,
biosdrain dump.c:32-36, biosdrain dump.c:70-120
A game is launched from an .acgame config in INI form. It names the boot elf,
the security dongle image in the memcards folder, an optional save card, the
CD/DVD/HDD image and the settings SRAM, and everything but the seven
character NM gameid can be resolved from the shipped database. Those files
are the game itself, one set per title.
ref: pcsx2/VMManager.cpp:1345-1490, pcsx2/VMManager.cpp:2667-2670,
pcsx2/DEV9/ACSRAM.cpp:17-40
The 256 regional signature normally comes from the iLinkId held in the nvm.
A 256Region entry in the .acgame feeds ASIA4, ASIA5 or JAPAN into the
mechacon read instead, which the Taiko games use to pick their region.
ref: pcsx2/CDVD/CDVD.cpp:2595-2608, pcsx2/VMManager.cpp:1371-1378
Read from the distribution tree and versioned with the build: the shader
sources every GS backend compiles at startup, the OSD fonts and fullscreen
UI textures, and the achievement notification sounds.
ref: pcsx2/GS/Renderers/Common/GSDevice.cpp:363-366,
pcsx2/ImGui/ImGuiFullscreen.cpp:300, pcsx2/ImGui/ImGuiFullscreen.cpp:396,
pcsx2/Achievements.cpp:1158, pcsx2/Achievements.cpp:1214,
pcsx2/Achievements.cpp:1339
files:
- name: COH-H31100.rom0
system: namco-system246
required: true
min_size: 4194304
max_size: 8388608
validation: [size]
description: "COH-H arcade board BIOS"
note: "Any image whose romdir holds RESET and ROMVER is accepted, whatever its name. The 4 to 8 MB range gates the folder scan; a manually selected image skips it. Named after the board model by the dumper, extension rom0."
source_ref: "pcsx2/ps2/BiosTools.cpp:268-292, pcsx2/ps2/BiosTools.cpp:80-207, pcsx2/ps2/BiosTools.cpp:327-379"
- name: COH-H31100.rom1
system: namco-system246
required: false
max_size: 4194304
description: "ROM1 board region"
note: "Tried as {bios}.rom1 then {biosbase}.rom1. Read into the 4 MB ROM1 region and truncated to it. Logged and skipped when absent. Mapped at 0xB0000000, where rom0:ACDEV declares rom1: on a COH-H."
source_ref: "pcsx2/ps2/BiosTools.cpp:224-251, pcsx2/ps2/BiosTools.cpp:376, pcsx2/MemoryTypes.h:14, pcsx2/Memory.cpp:416"
- name: COH-H31100.rom2
system: namco-system246
required: false
max_size: 4194304
description: "ROM2 board region"
note: "Tried as {bios}.rom2 then {biosbase}.rom2. Read into the 4 MB ROM2 region and truncated to it. The dumper reads 512 KB off the board."
source_ref: "pcsx2/ps2/BiosTools.cpp:224-251, pcsx2/ps2/BiosTools.cpp:377, pcsx2/MemoryTypes.h:15"
- name: COH-H31100.nvm
system: namco-system246
required: false
hle_fallback: true
size: 1024
description: "Board NVRAM"
note: "Read from the BIOS path with the extension replaced by nvm. Carries the iLinkId the 256 games read as a regional signature; a hardcoded id stands in when the file is missing or blank there. A default image is built when the file cannot be read."
source_ref: "pcsx2/CDVD/CDVD.cpp:47, pcsx2/CDVD/CDVD.cpp:140-178, pcsx2/CDVD/CDVD.cpp:2608"
- name: COH-H31100.mec
system: namco-system246
required: false
hle_fallback: true
size: 4
description: "Mechacon version"
note: "Read from the BIOS path with the extension replaced by mec. Written with 0x0104020A, the version of a COH-H31100, when absent."
source_ref: "pcsx2/CDVD/CDVD.cpp:51-52, pcsx2/CDVD/CDVD.cpp:196-209"
- name: eeprom.dat
system: namco-system246
required: false
hle_fallback: true
size: 64
description: "DEV9 EEPROM"
note: "Opened from the working directory at DEV9 init and mapped over 64 bytes. A compiled-in 64 byte image stands in when the file is missing or cannot be mapped."
source_ref: "pcsx2/DEV9/DEV9.cpp:67-77, pcsx2/DEV9/DEV9.cpp:116-167"
- name: flash.dat
system: namco-system246
required: false
hle_fallback: true
max_size: 8650752
description: "DEV9 SmartMedia flash image"
note: "Opened from the working directory at DEV9 init and read as 1024 blocks of 16 pages of 512 bytes plus 16 ECC bytes. The card is filled with 0xFF when the file is absent or short."
source_ref: "pcsx2/DEV9/flash.cpp:9-16, pcsx2/DEV9/flash.cpp:62-86, pcsx2/DEV9/DEV9.cpp:114"
- name: GameIndex.yaml
path: bin/resources/GameIndex.yaml
system: namco-system246
required: false
description: "Arcade game database"
note: "Keyed by NM gameid, one entry per arcade title, carrying the board variant, the media type, the boot program and the GS fixes. Supplies the platform and media values a minimal .acgame leaves out. Console error when missing."
source_ref: "pcsx2/GameDatabase.cpp:39, pcsx2/GameDatabase.cpp:979-990, pcsx2/VMManager.cpp:1385-1415"
- name: RedumpDatabase.yaml
path: bin/resources/RedumpDatabase.yaml
system: namco-system246
required: false
description: "Disc hash database"
note: "Read on demand to match a disc against its catalogue entry in the game summary. Console error when missing."
source_ref: "pcsx2/GameDatabase.cpp:1086, pcsx2/GameDatabase.cpp:1143-1152"
- name: patches.zip
path: bin/resources/patches.zip
system: namco-system246
required: false
description: "Bundled patch archive"
note: "Opened read-only from the resources folder. Built-in patches are unavailable and an on-screen error is shown when it cannot be opened. Fetched from the patches repository at build time, not committed."
source_ref: "pcsx2/Patch.cpp:117, pcsx2/Patch.cpp:289-315, .github/workflows/linux_build_qt.yml:129"
- name: game_controller_db.txt
path: bin/resources/game_controller_db.txt
system: namco-system246
required: false
description: "SDL controller mapping database"
note: "A copy in the user data root takes precedence over the one in resources. Fed to SDL as a hint; without either, SDL falls back to its built-in mappings and an error is logged."
source_ref: "pcsx2/Input/SDLInputSource.cpp:24, pcsx2/Input/SDLInputSource.cpp:614-629"
+7 -7
View File
@@ -24,7 +24,7 @@ files:
- name: "scph5500.bin"
description: "SCPH-5500 (v3.0 09-09-96 J)"
region: "NTSC-J"
region: [japan]
size: 524288
required: false
hle_fallback: true
@@ -36,7 +36,7 @@ files:
- name: "scph5501.bin"
description: "SCPH-5501 (v3.0 11-18-96 A)"
region: "NTSC-U"
region: [north-america]
size: 524288
required: false
hle_fallback: true
@@ -48,7 +48,7 @@ files:
- name: "scph5502.bin"
description: "SCPH-5502 (v3.0 01-06-97 E)"
region: "PAL"
region: [europe]
size: 524288
required: false
hle_fallback: true
@@ -60,7 +60,7 @@ files:
- name: "psxonpsp660.bin"
description: "PSP embedded PS1 BIOS (region detected at runtime)"
region: "Auto"
region: [world]
size: 524288
required: false
hle_fallback: true
@@ -70,7 +70,7 @@ files:
- name: "scph101.bin"
description: "SCPH-101 (v4.4 03-24-00 A) - PSone US"
region: "NTSC-U"
region: [north-america]
size: 524288
required: false
hle_fallback: true
@@ -80,7 +80,7 @@ files:
- name: "scph7001.bin"
description: "SCPH-7001 (v4.1 12-16-97 A)"
region: "NTSC-U"
region: [north-america]
size: 524288
required: false
hle_fallback: true
@@ -89,7 +89,7 @@ files:
- name: "scph1001.bin"
description: "SCPH-1001 (v2.2 12-04-95 A)"
region: "NTSC-U"
region: [north-america]
size: 524288
required: false
hle_fallback: true
+193
View File
@@ -0,0 +1,193 @@
emulator: PrBoom+
type: standalone
core_classification: game_engine
source: "https://github.com/coelckers/prboom-plus"
upstream: "https://github.com/coelckers/prboom-plus"
profiled_date: "2026-08-08"
source_commit: "969515162c5aebea4ad7a125ee178dcad3d576ad"
core_version: "2.6.66"
display_name: "Doom (PrBoom+)"
cores:
- prboom-plus
systems:
- doom
mode: standalone
notes: |
Doom source port forked from PrBoom, with the software and OpenGL renderers
in a single binary. FindIWADFile accepts doom2f, doom2, plutonia, tnt, doom,
doom1, doomu, freedoom2, freedoom1, freedm, hacx, chex, rekkrsa, bfgdoom2
and bfgdoom (d_main.c:144-165). ES-DE runs it as "prboom-plus -iwad <file>",
so the IWAD is content, not a system file.
prboom-plus.wad holds the engine's own lumps: the palette, the water
colormap, the sine, tangent and gamma tables, the HUD layouts, the status
bar digits, the crosshairs, the dog and plasma sprites, the GLSL shader
sources, and the DEHACKED patches applied to Chex Quest, the BFG Edition
and NERVE.WAD. M_LoadDefaults installs it as wad_files[0] and aborts with
"PrBoom-Plus.wad not found. Can't continue." when I_FindFile returns
nothing (m_misc.c:1723-1724). It loads even under -noload, which caps the
autoload loop at that one entry (d_main.c:1877-1879). Lumps coming from it
are tagged LUMP_PRBOOM so a PWAD can override them (w_wad.c:185-196).
The tree ships the inputs, not the file: data/CMakeLists.txt builds it with
the rdatawad tool from the raw palette, lumps, PPM graphics and WAV sounds
under data/, then installs it into PRBOOMDATADIR, which is
<prefix>/share/prboom-plus (CMakeLists.txt:188-189, data/CMakeLists.txt:370).
I_FindFile searches, in order: the config directory, the working directory,
PRBOOMDATADIR, $DOOMWADDIR, the build-time DOOMWADDIR, $HOME/doom, $HOME,
/usr/local/share/games/doom, /usr/share/games/doom, /usr/local/share/doom,
/usr/share/doom, then every entry of $DOOMWADPATH (SDL/i_system.c:437-449,
471-505). The working directory entry carries no prefix, so an absolute
name resolves on that pass. Existence is the only test, and the requested
extension is appended only when the name as written is missing
(SDL/i_system.c:532-538). The config directory is the directory holding the
binary on Windows (SDL/i_system.c:289-311), and ~/.prboom-plus or the
XDG path from SDL_GetPrefPath elsewhere (SDL/i_system.c:347-383). The macOS
build replaces the list with ~/Library/Application Support/PrBoom-Plus, the
bundle resource path, and the bare name (MAC/i_system.m:57-59, 117-142).
snd_midiplayer picks the MIDI backend and defaults to fluidsynth on Windows,
sdl elsewhere (m_misc.c:444-450). Only the sdl value leaves
use_experimental_music clear and routes MIDI through SDL_mixer
(SDL/i_sound.c:1662-1668, 1221-1225); every other value brings up the
in-tree players. Their init results are recorded once at startup
(SDL/i_sound.c:1383-1384) and consulted per song, a player that failed to
init being logged and passed over for the next entry of music_player_order
(SDL/i_sound.c:1511-1538). fluidsynth is the only one reading an external
file. The OPL2 player that follows it takes its instruments from the IWAD
GENMIDI lump (MUSIC/oplplayer.c:337-354).
files:
- name: "prboom-plus.wad"
system: doom
description: "PrBoom+ engine data WAD"
required: true
size: 357768
md5: "1164ae723c9181698cc41dde6a341132"
sha1: "8a799c6615702aac72016b784e30ea1abd3e197b"
crc32: "a4626dfa"
source_ref: "m_misc.c:1723-1724 (I_FindFile then I_Error), d_main.c:1873-1895 (autoload), w_wad.c:185-196 (LUMP_PRBOOM tagging), CMakeLists.txt:41 (PACKAGE_TARNAME), CMakeLists.txt:234-235 (WAD_DATA), data/CMakeLists.txt:364-370 (rdatawad build and install)"
note: >
The code checks existence only, then rejects a file whose header is
neither IWAD nor PWAD (w_wad.c:216-218). Hashes are those of the file
rdatawad produces from the data/ assets at this revision, which matches
the copy in the v2.6.66 release archive byte for byte. They identify the
2.6.66 build; other versions carry different lumps.
- name: "TimGM6mb.sf2"
system: doom
description: "General MIDI soundfont for the fluidsynth MIDI player"
required: false
hle_fallback: true
source_ref: "m_misc.c:445-446 (_WIN32 defaults for snd_midiplayer and snd_soundfont), MUSIC/flplayer.c:193-202 (I_FindFile2 then fluid_synth_sfload)"
note: >
Named by the Windows default of snd_soundfont, where snd_midiplayer also
defaults to fluidsynth, so a stock Windows configuration reads it. Any
soundfont works: the value is a config string and I_FindFile2 appends
.sf2 only when the name as written is missing. A load failure returns 0
from fl_init, and the song falls through to the next player on the list,
the built-in OPL2 synth.
- name: "default-GM.sf3"
system: doom
description: "General MIDI soundfont named by the non-Windows soundfont default"
required: false
hle_fallback: true
source_ref: "m_misc.c:448-449 (non-_WIN32 defaults, /usr/share/sounds/sf3/default-GM.sf3), MUSIC/flplayer.c:193-202 (I_FindFile2 then fluid_synth_sfload)"
note: >
The default is an absolute path, which resolves through the unprefixed
working directory entry of the search table. Reached once snd_midiplayer
is set away from its sdl default, since sdl keeps the fluidsynth player
out of the picture entirely. Same fallback to the OPL2 synth as the
Windows default.
analysis:
engine_wad_contents:
source_ref: "data/CMakeLists.txt:24-340 (rdatawad input lists), data/CMakeLists.txt:342-362 (WAD_SRC and WAD_CMDLINE)"
note: >
What rdatawad packs into prboom-plus.wad, in the order the command line
builds it.
palette: palette.rgb
lumps:
- "SWITCHES, ANIMATED"
- "the CR* colour translation tables"
colormaps: "WATERMAP, between C_START and C_END"
tables:
note: "Between B_START and B_END"
entries:
- "SINETABL, TANGTABL, TANTOANG, GAMMATBL"
- "CHEXDEH, BFGBEX, NERVEBEX"
- "GLSHADOW, GLFP, GLVP"
- "-PRBHUD-, read by hu_stuff.c:1144"
- "the M_* OpenGL automap icons listed in gl_map.c:48-68"
sounds: "DSDGSIT, DSDGATK, DSDGACT, DSDGDTH, DSDGPAIN"
graphics: "the DIG* status bar digits, STBR*, the BOX* frame pieces, STKEYS6-8, STCFN096, M_BUTT1/2, M_COLORS, M_PALNO, M_PALSEL, M_VBOX, CROSS1-3"
flats: "-N0_TEX-, between FF_START and FF_END"
sprites: "TNT1A0, the DOGS* frames, PLS1* and PLS2*, between SS_START and SS_END"
shader_override:
files:
- "shaders/glvp.txt"
- "shaders/glfp.txt"
source_ref: "gl_shader.c:144-152 (path built from I_DoomExeDir), gl_shader.c:84-129 (ReadLump)"
note: >
Read from the config directory when present. ReadLump falls back to the
GLVP and GLFP lumps in the ns_prboom namespace when the file is missing,
and those lumps are built into prboom-plus.wad
(data/CMakeLists.txt:60-61). No distribution ships the .txt form: it is
an override slot, and the shipped content is already covered by the WAD.
generated_files:
note: "Written by the program itself, none is user-supplied"
entries:
- filename: "prboom-plus.cfg"
source_ref: "m_misc.c:1586-1600 (BOOM_CFG, path from I_DoomExeDir), m_misc.c:1606 (read)"
- filename: "RGB2PAL.dat"
source_ref: "gl_hires.c:938-953 (read), gl_hires.c:962-967 (opened wb and written)"
note: >
A 24-bit RGB to palette lookup table built from V_GetPlaypal, so its
contents follow whichever IWAD is loaded. gl_hires.c:920-936 prefers
an RGB2PAL lump of the right length when a WAD supplies one.
- filename: "<hires image>.cache"
source_ref: "gl_hires.c:1144-1147 (read), gl_hires.c:1179 (gld_HiRes_WriteCache)"
note: "Keyed on the source image mtime and discarded when it differs."
- filename: "levelstat.txt"
source_ref: "e6y.c:968"
- filename: "levelinfo.txt"
source_ref: "d_main.c:1049-1060, behind GL_DOOM and PRBOOM_DEBUG"
- filename: "temp_a.nut, temp_v.nut"
source_ref: "m_misc.c:1065-1066 (cap_tempfile1, cap_tempfile2)"
user_supplied_paths:
note: "Named on the command line or in the config, with no fixed filename"
entries:
- what: "IWAD, -iwad or autodetected from the standard names"
source_ref: "d_main.c:144-165 (standard_iwads), d_main.c:977-990 (FindIWADFile)"
- what: "PWADs, -file"
source_ref: "d_main.c:1906-1927"
- what: "DEHACKED and BEX patches, -deh, plus the dehfile_1 and dehfile_2 config keys and the autoload directories"
source_ref: "d_main.c:2036-2055, d_main.c:2081-2099, m_misc.c:336-337"
- what: "extra autoloaded WADs, wadfile_1 and wadfile_2"
source_ref: "m_misc.c:334-335, d_main.c:1873-1895"
- what: "autoload directories, <config dir>/autoload/doom-all and one per IWAD"
source_ref: "d_main.c:1400-1414 (GetAutoloadBaseDir), d_main.c:1500-1519 (D_AutoloadIWadDir)"
- what: "demos, -playdemo, -fastdemo, -record"
source_ref: "r_demo.c:89-119, g_game.c:2570, g_game.c:3150"
- what: "external high resolution texture packs, under textures/, flats/ and patches/"
source_ref: "gl_hires.c:467-631 (hires_paths), gl_hires.c:703-719 (gl_texture_hires_dir or I_DoomExeDir)"
- what: "savegames, DOOMSAVEDIR or the config directory"
source_ref: "d_main.c:1019-1032, m_menu.c:957"
- what: "response files, @name"
source_ref: "d_main.c:1094-1112"
external_programs:
note: "Invoked as processes, not read as data files"
entries:
- what: "ffmpeg, video capture and muxing"
source_ref: "m_misc.c:1062-1064 (cap_soundcommand, cap_videocommand, cap_muxcommand)"
- what: "wget then unzip, fetching a WAD a game server asks for"
source_ref: "d_client.c:236-257 (execlp), doc/prboom-plus.6:200-206"
- what: "getwad_cmdline, run through system() when a needed WAD is missing"
source_ref: "r_demo.c:1641-1704 (D_TryGetWad), m_misc.c:1029 (default empty, so the path is inert until configured)"
+83
View File
@@ -0,0 +1,83 @@
emulator: puNES
type: standalone
core_classification: other
source: "https://github.com/punesemu/puNES"
upstream: "https://github.com/punesemu/puNES"
profiled_date: "2026-08-08"
source_commit: "2ed5b1b2cffcde48ff36f359091756d17d8fe193"
core_version: "0.112"
display_name: "Nintendo - NES / Famicom (puNES)"
cores:
- punes
systems:
- nintendo-nes
- nintendo-fds
mode: standalone
notes: |
Qt emulator of the NES, the Famicom and the Family Computer Disk System,
also playing NSF and NSFE music files. A cartridge boots with nothing
supplied: the 2A03, the PPU and every mapper are emulated in software.
Four names are fixed by the code. disksys.rom and gamegenie.rom share one
four-step lookup (src/core/fds.c:265-309, src/core/cheat.c:74-108): the path
recorded in the configuration, the working directory, the directory holding
the loaded image, then the bios folder of the data directory. nes20db.xml
and dip.cfg are read from the XDG data directories under a puNES
subdirectory, then the base of the data directory, then the application
directory (src/gui/nes20db.cpp:50-79, src/gui/dipswitch.cpp:61-85); the
installer writes both into the shared data directory
(CMakeLists.txt:227-228).
The data directory is the application directory under --portable,
%APPDATA%/puNES on Windows and ~/.local/share/puNES elsewhere
(src/gui/qt.cpp:561-575), so the bios folder is ~/.local/share/puNES/bios.
No length and no hash is ever compared. fds_load_bios computes a CRC32 of
the BIOS it loaded (src/core/fds.c:329) and the only reader of that value is
the log line at src/core/fds.c:502-503.
The iNES 1.0 game database is compiled in as src/core/database.h and carries
the Vs. System PPU type and the region, so Vs. System titles need no
external file. The uPD7756 ADPCM samples of mappers 018, 086 and 072 come
from the Misc ROM area of the NES 2.0 dump itself
(src/core/mappers/mapper_018.c:51, mapper_086.c:56, mapper_072.c:45).
loadWaveFiles, which would read <data>/samples/<name>/NN.wav
(src/core/mappers/waveFile.cpp:76-84), is declared and defined but called
from nowhere in the tree, so no wave file is ever opened.
Palettes, shaders, cheat imports and soft patches are opened from paths the
user picks in a file dialog and no name is fixed by the code, so they carry
no file entry here. A palette shorter than 192 bytes is refused and a
built-in table is used instead (src/core/palette.c:39-64,
src/video/gfx.c:323-334).
files:
- name: "disksys.rom"
system: nintendo-fds
description: "Family Computer Disk System BIOS"
required: true
size: 8192
source_ref: "src/core/fds.c:34,259-332 (fds_load_bios); src/core/fds.c:191-193 (caller); src/core/mappers/mapper_FDS.c:81 (mapping)"
note: "8192 bytes are read into PRG ROM and mapped at 0xE000. When none of the four locations holds the file, fds_load_bios logs FDS;bios not found and returns EXIT_ERROR, which the caller propagates, so the disk image does not load. A short read only logs FDS;error on reading bios."
- name: "gamegenie.rom"
system: nintendo-nes
description: "Game Genie ROM, booted in place of the cartridge to reach the code entry screen"
required: false
source_ref: "src/core/cheat.c:30,69-120 (gamegenie_check_rom_present),121-179 (gamegenie_load_rom); src/core/ines.c:97-99 (caller)"
note: "Loaded only while the cheat mode is set to Game Genie. The whole file is read, its length taken from the file itself. Absent, gamegenie_load_rom returns early and the cartridge boots directly."
- name: "nes20db.xml"
system: nintendo-nes
description: "NES 2.0 header database, matched by ROM hash"
required: false
source_ref: "src/gui/nes20db.cpp:31,49-81 (nes20db_search); src/core/ines.c:276-278, src/core/unif.c:316 (callers); CMakeLists.txt:227 (install)"
note: "Supplies mapper, submapper, mirroring, region, RAM sizes and Vs. System hardware for dumps whose own header is absent or wrong. A miss leaves info.mapper.nes20db.in_use false and the header carried by the ROM is used."
- name: "dip.cfg"
system: nintendo-nes
description: "DIP switch database for multicart and Vs. System boards, keyed by CRC32"
required: false
source_ref: "src/gui/dipswitch.cpp:30,60-86 (dipswitch_search); src/core/mappers.c:44 (caller); CMakeLists.txt:228 (install)"
note: "Read on every mapper init. A miss leaves dipswitch.used false, which mappers 001, 043, 045, 176, 215, 412 and 447 and the selection dialog at src/gui/qt.cpp:754 all guard on, so the board runs on its reset value."
+144
View File
@@ -0,0 +1,144 @@
emulator: Rosalie's Mupen GUI
type: standalone
core_classification: community_fork
source: "https://github.com/Rosalie241/RMG"
upstream: "https://github.com/Rosalie241/RMG"
profiled_date: "2026-08-08"
source_commit: "9dced048f747085f942f55941dd4304279acc145"
core_version: "v0.9.0"
display_name: "Nintendo - Nintendo 64 (Rosalie's Mupen GUI)"
cores:
- rosalies-mupen-gui
- RMG
- com.github.Rosalie241.RMG
systems:
- nintendo-64
- nintendo-64dd
mode: standalone
notes: |
Qt front end by Rosalie Wanders built around its own vendored fork of
mupen64plus-core, compiled with OSD=0, NEW_DYNAREC=1 and VULKAN=0
(Source/3rdParty/CMakeLists.txt:74-96). Forks of the RSP plugins hle, cxd4
and parallel, the video plugins GLideN64, parallel and angrylion-plus, and
the raphnetraw input plugin are vendored alongside it, plus RMG's own audio
and input plugins. ES-DE runs it as `--nogui -q <rom>` for both n64 and
n64dd. Against mupen64plus-core 6dca4c15 the media loader, the DD region
enum and load_dd_rom are unchanged; the fork diverges on SDL3, video
capture, netplay and the dynarec.
Cartridge boot needs no boot ROM. The PIF boot ROM is simulated
(device/pif/bootrom_hle.c:48, reached from r4300/interrupt.c:448,499) and the
CIC-NUS-6105 challenge is answered by an algorithm rather than a stored
table (device/pif/n64_cic_nus_6105.c:93).
Which 64DD IPL is used is not a user choice. scan_and_expand_disk_format
accepts a disk only when one of eight candidate blocks holds system data
carrying a known region word, and marks it development when that block sits
at index 2, 3, 10 or 11 (device/dd/disk.c:412-475). The core hands the
resulting region to the front end, which answers with one of three
configured paths, or with nothing when the region stayed unknown
(RMG-Core/MediaLoader.cpp:47-74). All three settings default to empty
(RMG-Core/Settings.cpp:284-292) and are filled from a file dialog filtered
on *.n64 (RMG/UserInterface/Dialog/SettingsDialog.cpp:1377-1390).
A bare .ndd or .d64 opens as a disk with no cartridge
(RMG-Core/Rom.cpp:111-133), which is the route ES-DE takes, so the IPL is
the only boot ROM and the core bails before starting when it is absent
(main/main.c:1723-1739). Passing a cartridge with --disk
(RMG/main.cpp:219,232,287) boots the cartridge and switches 64DD off instead.
Disk content inside a .zip or .7z is extracted to the user cache directory
first (RMG-Core/MediaLoader.cpp:164-215, RMG-Core/Archive.cpp:188-227).
Transfer Pak carts come from the input profile, which copies its GameboyRom
and GameboySave paths into the per player core settings
(RMG-Input/main.cpp:317-318,469-480, RMG-Core/MediaLoader.cpp:76-114). The
core rejects a ROM under 32 KiB and an unknown cart type byte at 0x147
(device/gb/gb_cart.c:999-1012) and fixes no name, size or hash, so neither
the cart nor its save carries an entry here.
Data the install places in the shared data directory (CMakeLists.txt:130-153;
/usr/share/RMG, or Data beside the executable for portable and Windows
builds, Directories.cpp:406-431): mupen64plus.ini, read as the ROM database
(main/rom.c:585-604) and used by GLideN64 to locate that same directory
(mupenplus/CommonAPIImpl_mupenplus.cpp:77-85); GLideN64.custom.ini, per ROM
overrides keyed on the uppercased header name
(mupenplus/Config_mupenplus.cpp:329-348); font.ttf, reached only after the
configured font name fails both as a system font path and as a full path
(TextDrawer.cpp:202-230); Cheats/<name>.cht, named from the header CRC pair
and country code, or from the ROM MD5 when all three are zero, and merged
with a user copy under the config directory
(RMG-Core/Cheats.cpp:82-116,579-598); InputProfileDB.json
(RMG-Input/Utilities/InputProfileDB.cpp:26-36); gamecontrollerdb.txt
(RMG-Input/main.cpp:1063-1069); and for VRU builds
vosk-model-small-en-us-0.15.zip, extracted into the user data directory when
any of the thirteen model files it checks for is missing
(RMG-Input/VRU.cpp:154-232). The published AppImage is the features-on build,
so the model ships with it (.github/workflows/build.yml:10,79,91).
Optional files with no canonical artifact: a .qss stylesheet under Styles in
the shared data directory (RMG/UserInterface/MainWindow.cpp:405-425), hi-res
texture packs under hires_texture in the user data directory
(GLideN64 Config.cpp:118-123), and alp_screen.vert and alp_screen.frag, which
angrylion-plus opens as working directory relative paths before falling back
to its embedded shaders (angrylion-plus output/vdac.c:120-175,257-258).
Written rather than obtained: mupen64plus.cfg in the config directory,
GLideN64.ini written there by the plugin settings pages and read back from
both that directory and the shared data directory
(GLideNUI/Config_GLideNUI.cpp:20-21,45-46, GLideNUI/Settings.cpp:352-368),
the mempak, eeprom, flashram and sram saves opened with default
content when absent (main/main.c:1712-1716), 64DD disk saves in the format
the SaveDiskFormat setting selects (main/main.c:1286-1298), savestates,
screenshots, the ROM browser header cache
(RMG-Core/CachedRomHeaderAndSettings.cpp:152), the GLideN64 texture cache and
texture dumps (GLideN64 Config.cpp:120-123) and the parallel-rdp pipeline
cache (video-parallel vulkan/device.cpp:760,834).
Two files in the tree this build never reads: the vendored core's
data/mupencheat.txt, which RMG neither installs nor parses since cheats use
its own .cht format and the core's cheat.c opens no file, and cxd4's
rsp_conf.bin, whose reader is the zilmar variant of update_conf behind
#if !defined(M64P_PLUGIN_API); the variant this build compiles takes settings
from the core config API and ignores its filename argument
(mupen64plus-rsp-cxd4/module.c:89-99,652-673).
files:
- name: "64DD_IPL_JP.n64"
aliases: ["64DD_IPL_v12_JPN.bin", "64DD_IPL.bin"]
system: nintendo-64dd
required: true
description: "64DD IPL ROM (Japanese retail)"
note: >
Selected when the disk system data holds the Japanese region word
0xe848d316, which covers the retail library. The path is set in the
settings dialog and no name is fixed by the code. Loaded whole, then
byteswapped after identifying the first word as one of 0x80270740 (z64),
0x40072780 (n64) or 0x27804007 (v64); any other value disables 64DD.
Size is not checked and no hash is computed.
source_ref: "Source/RMG-Core/MediaLoader.cpp:47-74, Source/RMG-Core/Settings.cpp:284-286, Source/3rdParty/mupen64plus-core/src/main/main.c:1190-1255, Source/3rdParty/mupen64plus-core/src/device/dd/disk.c:434-445"
- name: "64DD_IPL_US.n64"
aliases: ["64DD_IPL_USA.bin", "IPL_USA.n64"]
system: nintendo-64dd
required: true
description: "64DD IPL ROM (American retail)"
note: >
Selected when the disk system data holds the US region word 0x2263ee56.
The other two IPL settings are not consulted for such a disk, so no
substitution is possible. Same load path, format check and absence of
size or hash validation as the Japanese image.
source_ref: "Source/RMG-Core/MediaLoader.cpp:54-56, Source/RMG-Core/Settings.cpp:287-289, Source/3rdParty/mupen64plus-core/src/main/main.c:1190-1255, Source/3rdParty/mupen64plus-core/src/device/dd/disk.c:434-445"
- name: "64DD_IPL_DEV.n64"
aliases: ["64DD_IPL_DEV.bin", "IPL_DEV.n64"]
system: nintendo-64dd
required: true
description: "64DD IPL ROM (Japanese development)"
note: >
Selected when the disk system data holds the development region word
0x00000000, and also whenever the valid system data block sits at index
2, 3, 10 or 11, which is the development disk layout. Same load path,
format check and absence of size or hash validation as the Japanese
image.
source_ref: "Source/RMG-Core/MediaLoader.cpp:57-59, Source/RMG-Core/Settings.cpp:290-292, Source/3rdParty/mupen64plus-core/src/main/main.c:1190-1255, Source/3rdParty/mupen64plus-core/src/device/dd/disk.c:412-475"
+150
View File
@@ -0,0 +1,150 @@
emulator: ruffle
type: standalone
core_classification: game_engine
source: "https://github.com/ruffle-rs/ruffle"
upstream: "https://github.com/ruffle-rs/ruffle"
profiled_date: "2026-08-08"
source_commit: "f3a1263e164dc4cb56211ab1f113e1907730ce89"
core_version: "0.5.0"
display_name: "Adobe Flash (Ruffle)"
cores:
- ruffle
systems:
- flash
mode: standalone
notes: |
Flash Player and Adobe AIR runtime written in Rust, playing SWF files of any
ActionScript version, as a desktop binary or as a WebAssembly browser build.
Distribution is by nightly build: Batocera compiles the nightly-2026-01-31 tag
and installs ruffle_desktop as ruffle, RetroDECK pulls the rs.ruffle.Ruffle
Flathub build. ES-DE runs it as `ruffle --fullscreen <rom>`, Batocera as
`ruffle <rom>`, RetroBat as `ruffle.exe --graphics <renderer> --force-align
-q <quality> <rom>`, RetroDECK as `ruffle --graphics vulkan --config
/var/data/ruffle --save-directory <saves>/ruffle <rom>`. The ActionScript
class library is compiled by build_playerglobal into playerglobal_avm1.swf and
playerglobal_avm2.swf and linked into the binary from OUT_DIR
(core/src/avm1/globals.rs:89, core/src/avm2/globals.rs:546), so startup reads
nothing. Locale texts, wgsl shaders, the window icon and the OpenH264 license
are embedded the same way (desktop/src/gui/locale.rs:7-12,
desktop/src/app.rs:449, render/wgpu/src/shaders.rs:28-76).
H.264 video is the one external dependency. external_video is a default
feature and pulls ruffle_video_external with openh264
(desktop/Cargo.toml:26,83,90), and enable_openh264 defaults to true
(desktop/src/preferences.rs:283,307). OpenH264Codec::load first dlopens the
system sonames libopenh264.so.7, libopenh264.so.2.4.1 and libopenh264.so on
Linux, then falls back to <cache>/ruffle/video/ and fetches the Cisco binary
from ciscobinary.openh264.org bz2-compressed into it
(video/external/src/decoder/openh264.rs:53-56,109-133,173-191,
desktop/src/player.rs:234-241). Whether the library was already there or was
just downloaded, its SHA-256 is checked before loading and the size is read
only to format the mismatch message
(video/external/src/decoder/openh264.rs:135-146), and WelsGetCodecVersion must
answer 2.4.1 exactly (video/external/src/decoder/openh264.rs:46,153-166). The
cache root comes from dirs::cache_dir(), ~/.cache/ruffle by default, and
--cache-directory moves it (desktop/src/cli.rs:29-33,140). Without the library
the player still starts: ExternalVideoBackend wraps SoftwareVideoBackend, so
H.263, Screen Video and VP6 keep decoding and only H.264 streams fail
(video/external/src/backend.rs:41,51-69,73-80).
Text uses system fonts. fontdb::Database::load_system_fonts() fills the
database at startup (desktop/src/app.rs:418-419), and both the Flash device
fonts and the egui menu bar resolve family names against it, mmapping whatever
face the host answers with (desktop/src/backends/ui.rs:281-314,395-421,
desktop/src/gui/controller.rs:690-733). The families asked for are Times New
Roman, Arial, Courier New and their metric-compatible substitutes, plus the
CJK, Hebrew, Arabic and Thai faces (desktop/src/player.rs:361-412,
desktop/src/gui/controller.rs:569-641), and on Unix fontconfig sorts the
fallback chain (desktop/src/backends/ui.rs:318-329,460-472). No name, path,
size or hash is fixed anywhere. The compiled-in Noto Sans subset sits behind
the default_font feature, which the desktop build does not enable
(core/src/player.rs:82-83, core/Cargo.toml:82,96, desktop/Cargo.toml:22), so
an unmatched family leaves the run without that face rather than falling back
to a bundled one.
Files the player writes rather than expects: preferences.toml, bookmarks.toml
and recents.toml under --config, each defaulted when absent
(desktop/src/preferences.rs:53-95), .sol SharedObjects under --save-directory
(frontend-utils/src/backends/storage.rs:31-60), and the log file
(desktop/src/main.rs:156-166). ruffle-bundle.toml is the manifest inside a
.ruf bundle, which is content alongside the .swf rather than a runtime input
(frontend-utils/src/bundle/info.rs:11, frontend-utils/src/bundle.rs:42-53).
mms.cfg is not
implemented, the name appears only in an AVM2 error string
(core/src/avm2/error_messages.rs:237).
files:
# -- OpenH264 2.4.1 decoder, one build per OS and architecture --
- name: libopenh264-2.4.1-linux64.7.so
path: "video/libopenh264-2.4.1-linux64.7.so"
system: flash
required: false
description: "OpenH264 2.4.1 decoder library, Linux x86_64"
sha256: "1392d21466bc638e68151b716d5b2086d54cd812afd43253f1adb5b6e0185f51"
validation: [sha256]
source_ref: "video/external/src/decoder/openh264.rs:65-68, 104-146, 173-191"
- name: libopenh264-2.4.1-linux-arm64.7.so
path: "video/libopenh264-2.4.1-linux-arm64.7.so"
system: flash
required: false
description: "OpenH264 2.4.1 decoder library, Linux aarch64"
sha256: "e8ea7e42855ceb4a90e7bd0b3abeba0c58b5f97166e8b0a30eefd58e099557a4"
validation: [sha256]
source_ref: "video/external/src/decoder/openh264.rs:73-76, 104-146, 173-191"
- name: libopenh264-2.4.1-linux-arm.7.so
path: "video/libopenh264-2.4.1-linux-arm.7.so"
system: flash
required: false
description: "OpenH264 2.4.1 decoder library, Linux arm"
sha256: "fd1dfb27d30bb72e903c9d2b4c650104a4369d2e7ffe8a4a533e8db2e7e9b19e"
validation: [sha256]
source_ref: "video/external/src/decoder/openh264.rs:69-72, 104-146, 173-191"
- name: libopenh264-2.4.1-linux32.7.so
path: "video/libopenh264-2.4.1-linux32.7.so"
system: flash
required: false
description: "OpenH264 2.4.1 decoder library, Linux x86"
sha256: "b7cf0e407f99056d90cbf62787a34820a7595b2129b165319d50766e00a66704"
validation: [sha256]
source_ref: "video/external/src/decoder/openh264.rs:61-64, 104-146, 173-191"
- name: libopenh264-2.4.1-mac-arm64.dylib
path: "video/libopenh264-2.4.1-mac-arm64.dylib"
system: flash
required: false
description: "OpenH264 2.4.1 decoder library, macOS aarch64"
sha256: "213ff93831cfa3dd6d7ad0c3a3403a6ceedf4ac1341e1278b5b869d42fefb496"
validation: [sha256]
source_ref: "video/external/src/decoder/openh264.rs:81-84, 104-146, 173-191"
- name: libopenh264-2.4.1-mac-x64.dylib
path: "video/libopenh264-2.4.1-mac-x64.dylib"
system: flash
required: false
description: "OpenH264 2.4.1 decoder library, macOS x86_64"
sha256: "cc0ba518a63791c37571f3c851f0aa03a4fbda5410acc214ecd4f24f8d1c478e"
validation: [sha256]
source_ref: "video/external/src/decoder/openh264.rs:77-80, 104-146, 173-191"
- name: openh264-2.4.1-win64.dll
path: "video/openh264-2.4.1-win64.dll"
system: flash
required: false
description: "OpenH264 2.4.1 decoder library, Windows x86_64"
sha256: "081b0c081480d177cbfddfbc90b1613640e702f875897b30d8de195cde73dd34"
validation: [sha256]
source_ref: "video/external/src/decoder/openh264.rs:89-92, 104-146, 173-191"
- name: openh264-2.4.1-win32.dll
path: "video/openh264-2.4.1-win32.dll"
system: flash
required: false
description: "OpenH264 2.4.1 decoder library, Windows x86"
sha256: "83270149640469c994a62cc32a6d8c0413cd7b802b7f1f2f532159f5bdc1cedd"
validation: [sha256]
source_ref: "video/external/src/decoder/openh264.rs:85-88, 104-146, 173-191"
+22 -22
View File
@@ -26,7 +26,7 @@ files:
- name: "scph5500.bin"
description: "SCPH-5500 (v3.0 J)"
region: "NTSC-J"
region: [japan]
required: true
size: 524288
validation: [size, sha256]
@@ -38,7 +38,7 @@ files:
- name: "scph5501.bin"
description: "SCPH-5501 (v3.0 A)"
region: "NTSC-U"
region: [north-america]
required: true
size: 524288
validation: [size, sha256]
@@ -50,7 +50,7 @@ files:
- name: "scph5502.bin"
description: "SCPH-5502 (v3.0 E)"
region: "PAL"
region: [europe]
required: true
size: 524288
validation: [size, sha256]
@@ -63,7 +63,7 @@ files:
# Japan alternatives
- name: "scph1000.bin"
description: "SCPH-1000 (v1.0 J)"
region: "NTSC-J"
region: [japan]
required: false
size: 524288
validation: [size, sha256]
@@ -72,7 +72,7 @@ files:
- name: "scph_v11j.bin"
description: "v1.1 J"
region: "NTSC-J"
region: [japan]
required: false
size: 524288
validation: [size, sha256]
@@ -81,7 +81,7 @@ files:
- name: "scph3000.bin"
description: "SCPH-3000 (v2.1 J)"
region: "NTSC-J"
region: [japan]
required: false
size: 524288
validation: [size, sha256]
@@ -90,7 +90,7 @@ files:
- name: "scph3500.bin"
description: "SCPH-3500 (v2.2 J)"
region: "NTSC-J"
region: [japan]
required: false
size: 524288
validation: [size, sha256]
@@ -100,7 +100,7 @@ files:
- name: "scph5000.bin"
description: "v2.2 J (alt)"
region: "NTSC-J"
region: [japan]
required: false
size: 524288
validation: [size, sha256]
@@ -109,7 +109,7 @@ files:
- name: "scph7000.bin"
description: "SCPH-7000 (v4.0 J)"
region: "NTSC-J"
region: [japan]
required: false
size: 524288
validation: [size, sha256]
@@ -118,7 +118,7 @@ files:
- name: "scph7500.bin"
description: "SCPH-7500 (v4.1 J)"
region: "NTSC-J"
region: [japan]
required: false
size: 524288
validation: [size, sha256]
@@ -127,7 +127,7 @@ files:
- name: "scph9000.bin"
description: "SCPH-9000 (v4.3 J)"
region: "NTSC-J"
region: [japan]
required: false
size: 524288
validation: [size, sha256]
@@ -137,7 +137,7 @@ files:
# North America alternatives
- name: "scph1001.bin"
description: "SCPH-1001 (v2.0 A)"
region: "NTSC-U"
region: [north-america]
required: false
size: 524288
validation: [size, sha256]
@@ -146,7 +146,7 @@ files:
- name: "scph5001.bin"
description: "SCPH-5001 (v2.1 A)"
region: "NTSC-U"
region: [north-america]
required: false
size: 524288
validation: [size, sha256]
@@ -155,7 +155,7 @@ files:
- name: "scph_v22a.bin"
description: "v2.2 A"
region: "NTSC-U"
region: [north-america]
required: false
size: 524288
validation: [size, sha256]
@@ -164,7 +164,7 @@ files:
- name: "scph7001.bin"
description: "SCPH-7001 (v4.1 A)"
region: "NTSC-U"
region: [north-america]
required: false
size: 524288
validation: [size, sha256]
@@ -173,7 +173,7 @@ files:
- name: "scph101.bin"
description: "SCPH-101 (v4.5 A)"
region: "NTSC-U"
region: [north-america]
required: false
size: 524288
validation: [size, sha256]
@@ -183,7 +183,7 @@ files:
# Europe alternatives
- name: "scph1002.bin"
description: "SCPH-1002 (v2.0 E)"
region: "PAL"
region: [europe]
required: false
size: 524288
validation: [size, sha256]
@@ -192,7 +192,7 @@ files:
- name: "scph_v21e.bin"
description: "v2.1 E"
region: "PAL"
region: [europe]
required: false
size: 524288
validation: [size, sha256]
@@ -201,7 +201,7 @@ files:
- name: "scph_v22e.bin"
description: "v2.2 E"
region: "PAL"
region: [europe]
required: false
size: 524288
validation: [size, sha256]
@@ -210,7 +210,7 @@ files:
- name: "scph7002.bin"
description: "SCPH-7002 (v4.1 E)"
region: "PAL"
region: [europe]
required: false
size: 524288
validation: [size, sha256]
@@ -219,7 +219,7 @@ files:
- name: "scph102.bin"
description: "SCPH-102 (v4.4 E)"
region: "PAL"
region: [europe]
required: false
size: 524288
validation: [size, sha256]
@@ -228,7 +228,7 @@ files:
- name: "scph102_v45.bin"
description: "v4.5 E"
region: "PAL"
region: [europe]
required: false
size: 524288
validation: [size, sha256]
+279
View File
@@ -0,0 +1,279 @@
emulator: SDL2TRS
type: standalone
core_classification: community_fork
source: "https://gitlab.com/jengun/sdltrs"
upstream: "http://sdltrs.sourceforge.net"
profiled_date: "2026-08-08"
source_commit: "a9b30ff3cfe2b44ccff094fcd5d3c5b60e78b8a2"
core_version: "1.2.35"
display_name: "Tandy - TRS-80 (SDL2TRS)"
cores:
- sdl2trs
- sdltrs
systems:
- trs80
mode: standalone
notes: |
TRS-80 Model I, III, 4 and 4P emulator. Jens Guenther's GitLab tree continues
Mark Grebe's SDLTRS, itself an SDL port of Tim Mann's xtrs, whose licence
still ships as xtrs.LICENSE. The sdl2 branch builds the sdl2trs binary that
ES-DE and RetroDECK look for; master builds sdltrs for hosts without SDL2
(README.md:106-111). The branches diverge only in the display and paste code:
trs_cmd_rom.c and trs_memory.c are byte-identical between them.
Three ROM slots exist, one per model family, and trs_rom_init picks one from
trs_model. Model I takes romfile1, Model III and Model 4 share romfile3, and
Model 4P takes romfile4p (trs_cmd_rom.c:868-894). The defaults are level2.rom,
model3.rom and model4p.rom, each prefixed by ROM_PATH (trs_options.c:900-902).
ROM_PATH is a build define left empty unless a packager sets it
(trs_options.c:53-54, CMakeLists.txt:42), so a stock build resolves the names
against the working directory.
-rom, -r and -romfile write to the slot of the model selected at the moment
they are parsed (trs_options.c:611-622). Options are applied in command-line
order after the config file has been read (trs_options.c:1020-1040), so -m has
to come first to redirect them, and a model key in the config file otherwise
decides. -rom1, -rom3 and -rom4p address a slot directly. The GUI ROM browser
filters on .bin, .hex, .iii and .rom (trs_sdl_gui.h:63, trs_sdl_gui.c:2591-2597).
trs_load_rom sniffs the first byte. A colon means Intel hex, and load_hex
rejects the file on a line checksum mismatch. A 1 or a 5 on Model III or later
means a MODELA/III CMD file, rejected above 14 KB. Anything else is read as
raw binary with no check (trs_cmd_rom.c:720-767, 779-843), which is the path a
dump takes. No hash is computed anywhere in the tree. rom_write drops any byte
at or past MAX_ROM_SIZE, 18432 (trs_memory.c:63, 742-745), and trs_rom_size,
the extent of the plain ROM mapping, is capped at 14336 (trs_cmd_rom.c:896-898).
A failed load is not fatal. Model I and Model III/4 fall back to trs_fakerom,
which prints "You do not have a ROM image installed for Model" and spins.
Model 4P falls back to trs_rom4p, Pete Cervasio's free boot ROM, which boots
Model 4 operating systems from floppy (trs_cmd_rom.c:871-893). -stringy
overlays the built-in Exatron Stringy Floppy ROM at 0x3000 over the Model I
image (trs_cmd_rom.c:875-876), and -hdboot rewrites the loaded Model I ROM in
place to boot from a hard drive (trs_cmd_rom.c:447-610, 882-883).
The clones run off the same three slots and are recognised from the ROM data
rather than from an option (trs_clones.c:8-20, html/Features.html), so their
larger images load as a Model I or a Model III ROM. None has a filename of its
own anywhere in the tree.
files:
- name: level2.rom
description: "TRS-80 Model I ROM"
required: true
max_size: 18432
source_ref: "src/trs_options.c:81 (romfile1), src/trs_options.c:900 (default name), src/trs_cmd_rom.c:871-884 (trs_model 1)"
note: >
Model I is the model a stock configuration selects (trs_options.c:927), so
this is the slot an unconfigured run reads. Without it the machine runs the
compiled-in diagnostic stub and nothing else. max_size is the shared ROM
buffer ceiling: a longer file is truncated, never rejected, and only the
first 14336 bytes reach the plain memory map.
- name: model3.rom
description: "TRS-80 Model III and Model 4 ROM"
required: true
max_size: 18432
source_ref: "src/trs_options.c:82 (romfile3), src/trs_options.c:901 (default name), src/trs_cmd_rom.c:885-889 (trs_model 3 and 4)"
note: >
Serves Model III and Model 4 alike; the stub text spells out that Model 4
mode needs a Model 3 image (trs_cmd_rom.c:110-115). This is the one slot
that also accepts a MODELA/III CMD file, which html/index.html presents as
the substitute for a real Model III ROM. Same truncating ceiling as the
Model I slot.
- name: model4p.rom
description: "TRS-80 Model 4P boot ROM"
required: false
max_size: 18432
source_ref: "src/trs_options.c:83 (romfile4p), src/trs_options.c:902 (default name), src/trs_cmd_rom.c:890-893 (trs_model 5)"
note: >
Optional because the compiled-in replacement is a working boot ROM rather
than a stub. html/index.html states the free ROM boots only Model 4
operating systems, not Model III, and only from floppy, so the original
image is what restores Model III mode and hard-drive booting. Hard drive
unit 0 is tried before floppy by the Radio Shack ROM, and F2 held at boot
forces floppy (html/Features.html).
analysis:
embedded_roms:
mechanism: "Uint8 arrays in trs_cmd_rom.c, copied into the ROM buffer by trs_load_compiled_rom (trs_cmd_rom.c:769-777)"
extraction: "hashes computed from the decoded byte literals"
entries:
- symbol: trs_fakerom
role: "Fallback for Model I and Model III/4 when the slot cannot be read"
source_ref: "src/trs_cmd_rom.c:56-116, src/trs_cmd_rom.c:873,888"
load_address: 0
size: 461
crc32: 5f85edf9
md5: de9617738e7ee6633d305777e0ce6a15
sha1: 42736ddff1944fcd4631168d35f773fc824eeb9b
note: >
Writes "You do not have a ROM image installed for Model" plus the model
digit to the screen and halts on a JR -2. It runs no TRS-80 software,
which is why both slots it covers are required.
- symbol: trs_rom4p
role: "Fallback for Model 4P"
source_ref: "src/trs_cmd_rom.c:126-193, src/trs_cmd_rom.c:892"
load_address: 0
size: 518
crc32: 57ec35ee
md5: c8551e6aa36c4bea256d3073c7255ed5
sha1: 60d4ff043525256fa3072e59ba283a3cb98399f4
note: >
Pete Cervasio's free Model 4P boot ROM version 0.06, carried under a
copy-and-modify notice in the header. Reads and runs a boot sector and
reports CRC errors, a missing boot sector and an empty drive.
utilities/xtrsrom4p.z80 is its source and xtrsrom4p.README its manual.
- symbol: trs_romesf
role: "Exatron Stringy Floppy firmware, overlaid on the Model I image"
source_ref: "src/trs_cmd_rom.c:199-441, src/trs_cmd_rom.c:875-876"
load_address: 12288
size: 1920
crc32: 99e3fdc6
md5: 235d1eb412cfc5696aad8a0a2dc6c53a
sha1: b2612037600031b5290bace247951e1f99700b36
note: >
Loaded over 0x3000-0x377F whenever -stringy is set, on top of whatever
the Model I slot supplied, and leaves trs_rom_size at 0x3780. Taken
from the ESF Advanced Programmer's Guide and held to be public domain
by the header. utilities/esfrom.z80 is its source.
extended_rom_images:
note: >
The clones and the Holmes video card need images larger than a stock ROM,
and the memory mapper reads the extra regions straight out of the same
buffer. They arrive through romfile1 or romfile3 like any other image and
are recognised from the ROM data, so the emulator defines no filename for
them and no option selects them.
source_ref: "src/trs_clones.c:8-20 (clone table), src/trs_memory.c:63 (MAX_ROM_SIZE)"
layouts:
- machine: "Prologica CP-300, CP-500 and CP-500 M80"
slot: model3.rom
image_size: 16384
source_ref: "src/trs_cp500.c:1-22, src/trs_cp500.c:153-160, src/trs_memory.c:1052-1054"
note: >
14 KB of patched Model III ROM plus a 2 KB resident monitor read back
from 0x3800-0x3FFF and banked into 0x3000-0x37FF. README.md:21 and
html/Features.html name CP-300 and CP-500 for this 16 KB image.
- machine: "Holmes VID-80 (VX-3) on Model III"
slot: model3.rom
image_size: 18432
source_ref: "src/trs_memory.c:577-586, src/trs_memory.c:1057-1080"
note: "4 KB VID-80 ROM with the Model III ROM appended behind it; this pairing is what sets MAX_ROM_SIZE."
- machine: "TCS SpeedMaster, also sold as Genie IIs"
slot: level2.rom
image_size: 16384
source_ref: "src/trs_memory.c:1025-1048"
note: "BASIC at 0x0000-0x2FFF and a ROM card read from 0x1000-0x3FFF into 0x4000-0xBFFF. Needs -speedup tcs (html/Features.html)."
- machine: "Aster CT-80"
slot: level2.rom
image_size: 14336
source_ref: "src/trs_memory.c:962-994"
note: "BASIC at 0x0000-0x2FFF plus a 2 KB boot ROM at 0x3000-0x37FF, mirrored into 0xEC00 in CP/M mode."
- machine: "EACA EG 3200 Genie III"
slot: level2.rom
image_size: 14336
source_ref: "src/trs_memory.c:909-931"
note: "Bank 1 is read through trs_rom_size, so the 14 KB cap on the plain mapping is the ceiling."
- machine: "TCS Genie IIIs"
slot: level2.rom
image_size: 12288
source_ref: "src/trs_memory.c:932-961"
note: "Reads 0x0000-0x2FFF only; the rest of the address space is banked RAM, video and the HRG window."
- machine: "LNW Research LNW80/II"
slot: level2.rom
image_size: 12288
source_ref: "src/trs_memory.c:995-1024"
note: "Reads 0x0000-0x2FFF only. -speedup lnw sets the 4 MHz clock and the low 16 KB banking."
character_generators:
source_ref: "src/trs_chars.c:12 (trs_char_data), src/trs_options.c:404-436 (charset names), src/trs_sdl_interface.c:585"
note: >
Every character set is a compiled-in bitmap table selected by -charset1,
-charset3 and -charset4. The tree holds no external font file and reads
none. The sets cover the Model I generators, the Model III and Model 4
Katakana and international sets, and the Video Genie, System 80, HT-1080Z,
Meritum and Aster CT-80 clones.
frontend_conventions:
note: >
Two frontends fix names and paths the emulator itself does not know. Both
belong to the platform layer.
entries:
- frontend: ES-DE
source_ref: "resources/systems/linux/es_systems.xml:2211-2213, USERGUIDE.md:3334-3362"
note: >
Passes -rom %ROMPATH%/trs-80/level2.rom on all three launch commands
and -disk0 %ROMPATH%/trs-80/boot.dsk on the DOS Diskette one, with
boot.dsk documented as a copy of a TRS-80 DOS, NewDos/80 v2.0
recommended. No command passes -m, so the slot -rom writes to follows
the config file, which is Model I unless the user changed it, and
model3.rom and model4p.rom are never named. USERGUIDE.md:3338 records
that both filenames are case sensitive.
- frontend: RetroDECK
source_ref: "RetroDECK/components archive_later/sdl2trs/component_manifest.json"
note: >
Declares level1.rom, level2.rom, level3.rom, level4.rom, level4p.rom
and boot.dsk under $roms_path/trs-80. Of those the emulator opens only
level2.rom by default; level3.rom, level4.rom and level4p.rom are
renames of the model3.rom and model4p.rom slots, and level1.rom is a
Level I BASIC image for the Model I slot. The manifest hashes come
from the frontend, not from the emulator, which computes none.
shipped_content:
source_ref: "CMakeLists.txt:50, CMakeLists.txt:145-146"
files:
- diskimages/utility.dsk
- diskimages/cpmutil.dsk
note: >
Installed into the shared data directory by the emulator's own packaging
and carrying the IMPORT, EXPORT, SETTIME, XTRSHARD, XTRSMOUS and CP/M
helper programs whose sources sit in utilities/. No code path names them:
they reach the machine only when a user mounts them with -disk.
user_supplied_paths:
note: "Named on the command line, in the config file or in a disk set, with no fixed filename"
entries:
- what: "floppy images in drives 0-7, JV1, JV3 and DMK"
source_ref: "src/trs_options.c:589-594, src/trs_disk.c:789-921"
- what: "hard drive images, units 0-3"
source_ref: "src/trs_options.c:595-600, src/trs_hard.c:212-220, src/trs_hard.c:528-609"
- what: "cassette images, .cas, .cpt and .wav"
source_ref: "src/trs_options.c:583-588, src/trs_cassette.c:526-553"
- what: "stringy floppy wafers in drives 0-7, .esf"
source_ref: "src/trs_options.c:601-606, src/trs_stringy.c:278-316, src/trs_stringy.c:342-346"
- what: "disk set, a plain list of the paths above"
source_ref: "src/trs_options.c:607-610, src/trs_disk.c:3765-3802"
- what: "CMD program loaded straight into memory, from a bare argument"
source_ref: "src/trs_options.c:1014-1015, src/trs_cmd_rom.c:845-866"
- what: "serial port tty, defaulting to /dev/ttyS0 on Linux"
source_ref: "src/trs_uart.c:54-56, src/trs_uart.c:144-202"
generated_files:
written_and_read_back:
- filename: ".sdltrs.t8c"
source_ref: "src/trs_options.c:939-955, src/trs_options.c:1049"
note: "Configuration, written to the home directory on first run when none is found."
- filename: "<name>.t8s"
source_ref: "src/trs_state_save.c:38-66, src/trs_state_save.c:68-113"
note: "Emulator state, written and read by the GUI or a bare command-line argument."
- filename: "blank disk, wafer and hard drive images"
source_ref: "src/trs_mkdisk.c:192-308, src/trs_stringy.c:187-197"
written_only:
- filename: "trsprn####.txt"
source_ref: "src/trs_printer.c:60-81"
note: "Printer output, numbered up to 9999 in the printer directory."
- filename: "screenshots as BMP"
source_ref: "src/trs_sdl_gui.c:2673"
note: "Produced by the emulator, none is user-supplied"
+84
View File
@@ -0,0 +1,84 @@
emulator: SheepShaver
type: standalone
core_classification: other
source: "https://github.com/cebix/macemu"
upstream: "https://github.com/cebix/macemu"
profiled_date: "2026-08-08"
source_commit: "96e512bd6376e78a2869f16dcc8a9028bce5ee72"
core_version: "2.4"
display_name: "Apple - Macintosh PowerPC (SheepShaver)"
cores:
- sheepshaver
systems:
- apple-macintosh
mode: standalone
notes: |
PowerPC Macintosh emulator living in the macemu tree alongside Basilisk II,
version 2.4 (version.h:24-25). Runs MacOS 7.5.2 through 9.0.4 (README.md) on
a PCI PowerMac or NewWorld ROM image.
ROM loading (main_unix.cpp:581-613, main_windows.cpp:329-360): the path comes
from the "rom" prefs item (prefs_items.cpp:45). When that is empty, the file
named ROM is opened, then the file named Mac OS ROM (main_unix.cpp:162-163,
main_windows.cpp:58-59). Neither found raises STR_NO_ROM_FILE_ERR and
main_unix.cpp:987 aborts startup. The filename does not select the format:
both names go through the same decoder.
At most ROM_SIZE = 0x400000 bytes are read (cpu_emulation.h:30). DecodeROM
(rom_patches.cpp:148-200) accepts two forms. A read of exactly 4 MB is taken
as a plain image and copied as is. A buffer opening on <CHRP-BOOT> is
decompressed instead, either LZSS through the lzss-offset and lzss-size
constants (decode_lzss, rom_patches.cpp:80) or parcel by parcel through
parcels-offset and parcels-size (decode_parcels, rom_patches.cpp:123).
Anything else fails, and main_unix.cpp:602-609 picks the message from the
file size on disk: STR_ROM_SIZE_ERR when it is not 4 MB,
STR_ROM_FILE_READ_ERR otherwise (user_strings.cpp:66-67).
PatchROM (rom_patches.cpp:671-731), called from InitAll at main.cpp:161,
reads the nanokernel ID at offset 0x30d064 of the decoded image and accepts
Boot TNT, Boot Alchemy, Boot Zanzibar, Boot Gazelle, Boot Gossamer and
NewWorld (rom_patches.cpp:682-695). Any other string raises
STR_UNSUPPORTED_ROM_TYPE_ERR. The free space checks at
rom_patches.cpp:698-707 and the four patch passes at rom_patches.cpp:710-713
then rewrite the image in memory, and rom_patches.cpp:729 copies its last
megabyte past the 4 MB mark for the 68k emulator. Nothing is checksummed:
the ROM checksum at offset 0 is only printed by a debug build
(rom_patches.cpp:674).
MacOS itself and the applications live in disk images referenced by the
disk, floppy and cdrom prefs items, supplied by the user.
Two files are installed by the emulator's own Makefile into
$(datadir)/SheepShaver (Makefile.in:21,162-164) and read from there:
keycodes keycode to Mac keycode table, read only when the keycodes
prefs item is true, which defaults to false
(prefs_unix.cpp:117). Overridable with keycodefile.
configure.ac:754,775 picks ../SDL/keycodes or keycodes
according to the video backend. video_x.cpp:79,1200,
video_sdl2.cpp:97,1231
tunconfig script run to configure the tunN interface for ethernet.
Overridable with etherconfig. ether_unix.cpp:108,381
The SDL2 backend falls back to BasiliskII_keycodes in the same directory
(video_sdl2.cpp:98,1232).
The preferences file (.sheepshaver_prefs, prefs_unix.cpp:49;
SheepShaver_prefs, prefs_windows.cpp:66) and the NVRAM file
(.sheepshaver_nvram, xpram_unix.cpp:30; SheepShaver_nvram.dat,
xpram_windows.cpp:31) are written by the emulator when absent. Passing a
.sheepvm directory on the command line reads the preferences from inside it
instead (main_unix.cpp:371-384, prefs_unix.cpp:57-69).
files:
- name: ROM
aliases: ["Mac OS ROM"]
required: true
validation: [signature]
description: "PowerPC Macintosh ROM, 4 MB PCI PowerMac image or CHRP-BOOT Mac OS ROM"
source_ref: "src/Unix/main_unix.cpp:162-163,585-593,987, src/Windows/main_windows.cpp:58-59,330-344, src/rom_patches.cpp:148-200,671-695, src/main.cpp:161"
note: >
No size is enforced on its own: DecodeROM takes a 4 MB read as a plain
image and any other length only through the <CHRP-BOOT> header. The check
every accepted image passes is the nanokernel ID at offset 0x30d064 of
the decoded 4 MB image, which PatchROM matches against Boot TNT, Boot
Alchemy, Boot Zanzibar, Boot Gazelle, Boot Gossamer and NewWorld.
+167
View File
@@ -0,0 +1,167 @@
emulator: simple64
type: standalone
core_classification: community_fork
source: "https://github.com/simple64/simple64"
upstream: "https://github.com/simple64/simple64"
profiled_date: "2026-08-08"
source_commit: "d8c969c7b932e3d76e6a25549d76348839dbaefd"
core_version: "v2024.12.1"
display_name: "Nintendo - Nintendo 64 (simple64)"
cores:
- simple64
- simple64-gui
- io.github.simple64.simple64
systems:
- nintendo-64
mode: standalone
notes: |
Qt front end by Logan McNaughton over a vendored fork of mupen64plus-core,
with parallel-rsp and parallel-rdp as the only RSP and video plugins
(wiki, simple64-FAQ.md). The monorepo holds the core, the GUI, the SDL2 audio
plugin, the Qt and raphnetraw input plugins and both parallel components as
squashed subtrees (pull_repos.sh). The core is compiled with M64P_PARALLEL,
M64P_NETPLAY and NO_ASM, and its source list leaves out src/osd and every
dynarec (mupen64plus-core/CMakeLists.txt:26,28-104). ES-DE runs the release
binary as `--nogui <rom>`; the GUI registers only verbose, nogui and test
(simple64-gui/main.cpp:14-24). Development stopped and the repository was
archived in February 2025, five commits past v2024.12.1, touching only the
README, the build script and a netplay dialog.
Boot runs the real PIF ROM when one is present, which is where this fork
parts company with mupen64plus upstream: upstream keeps open_pif behind the
M64CMD_PIF_OPEN command with a caller supplied length and ships no such image
in data/, while simple64 opens the file itself at a fixed length and ships
both images. get_pif_path names pif.pal.rom for SYSTEM_PAL and pif.ntsc.rom
for SYSTEM_NTSC and SYSTEM_MPAL, then resolves it against the shared data
path (mupen64plus-core/src/main/main.c:1565-1580;
mupen64plus-core/src/api/config.c:1610-1625;
mupen64plus-core/src/osal/files_unix.c:150-170). The GUI passes the directory
holding the executable as that path (simple64-gui/mainwindow.cpp:986-988,
mupen64plus-core/src/api/frontend.c:59,90), and build.sh copies both images
there (build.sh:26), so a release install always carries them.
Absence is not fatal. The lookup returns NULL when the file is not found and
the result reaches fopen unchecked; on a failed open, open_pif is never
called and g_start_address keeps its initialiser 0xa4000040
(mupen64plus-core/src/main/main.c:112,1624-1633). A digest that matches none
of the four accepted values returns M64ERR_INPUT_INVALID, which main_run
discards, leaving the same address. pif_bootrom_hle_execute returns
immediately when the address is 0xbfc00000 and otherwise simulates IPL1 and
IPL2 in full, quiescing the RSP, PI, VI and AI, deriving s3 to s7 from pif24,
copying IPL3 into DMEM and planting the stub CIC x105 needs
(mupen64plus-core/src/device/pif/bootrom_hle.c:48-151). It runs on cold boot
and on both reset paths (mupen64plus-core/src/main/main.c:1977;
mupen64plus-core/src/device/r4300/interrupt.c:445,496). The CIC challenge
reads no file either: process_cic_challenge answers with the CIC-NUS-6105
algorithm (mupen64plus-core/src/device/pif/pif.c:252-260,
mupen64plus-core/src/device/pif/n64_cic_nus_6105.c).
64DD is not reachable. The GUI's media loader supplies only the two Game Boy
cartridge callbacks and leaves set_dd_rom_region, get_dd_rom and get_dd_disk
null, the two functions that would have answered being commented out
(simple64-gui/interface/common.cpp:129-163,240;
mupen64plus-core/src/api/m64p_types.h:186-221). load_dd_rom is only reached
after load_dd_disk succeeds, and load_dd_disk bails on a null callback, so
the IPL image the core can otherwise load and byteswap is never requested
(mupen64plus-core/src/main/main.c:1175-1247,1722-1736). No IPL entry follows
from that, and the system list carries no 64DD line.
Transfer Pak carts come from Player1GBROM and Player1GBRAM through
Player4GBROM and Player4GBRAM, filled by a file dialog
(simple64-gui/mainwindow.cpp:84-117,
simple64-gui/interface/common.cpp:87-127). The pair is a Game Boy cartridge
and its save, supplied by the player, and the code fixes no name, size or
hash for either, so neither carries an entry here.
The Voice Recognition Unit is the one asset the user has to go and get. The
core's VRU controller forwards every word command to the input plugin
(mupen64plus-core/src/device/controllers/vru_controller.c:147-235), and
setupVosk loads libvosk from beside the executable, then hands
vosk-model-small-en-us-0.15 under the user data directory to vosk_model_new
once conf/mfcc.conf is found inside it (simple64-input-qt/main.cpp:769-813).
Choosing "Emulate VRU" for controller 4 tests that same file and, when it is
missing, downloads
https://alphacephei.com/vosk/models/vosk-model-small-en-us-0.15.zip and
unpacks it there with 7za (simple64-input-qt/configdialog.cpp:22-62,93-115).
build.sh fetches only the Vosk library, never the model (build.sh:89-101,
158-160), so no release carries it.
Data the build places beside the executable: mupen64plus.ini, parsed as the
ROM database and keyed on MD5 then CRC pair, which supplies save type, player
count, rumble, Transfer Pak, Controller Pak, bio pak and expansion memory per
title (mupen64plus-core/src/main/rom.c:190-235,674-691; build.sh:25); and
cheats.json, pulled from simple64/cheat-parser at build time and read by
header CRC pair and country code (simple64-gui/cheats.cpp:230-239;
build.sh:106-111). Neither is hashed or version checked, romdatabase_open
logs and returns when the file is absent, and loadCheatData yields an empty
object, so both degrade rather than fail.
Two data files in the tree this build never reads: data/font.ttf, whose only
consumer is src/osd/osd.c, absent from the source list, leaving
osd_new_message as the inline no-op behind M64P_OSD
(mupen64plus-core/src/osd/osd.h:93,104,118-121); and data/mupencheat.txt,
referenced nowhere under src/ since cheats come from the GUI's own JSON. The
parallel-rdp shaders are compiled in through shaders/slangmosh.hpp rather
than loaded (parallel-rdp-standalone/parallel-rdp/rdp_renderer.cpp:36), and
the file reads in parallel-rsp/main.cpp belong to a test harness that sits
outside that plugin's CMake target.
Written rather than obtained: mupen64plus.cfg in the config directory and
simple64-gui.ini beside the executable
(simple64-gui/mainwindow.cpp:249), the Controller Pak, EEPROM, FlashRAM and
SRAM saves opened with default content when absent
(mupen64plus-core/src/main/main.c:1160-1173,1717-1720), the per ROM save
metadata (mupen64plus-core/src/main/rom.c:263,347), savestates and
screenshots (mupen64plus-core/src/main/screenshot.c:174), and the Discord
game SDK and Vosk shared libraries, which are resolved by name at runtime
and are code rather than data (simple64-gui/mainwindow.cpp:356,
simple64-input-qt/main.cpp:773).
files:
- name: "pif.ntsc.rom"
system: nintendo-64
required: false
hle_fallback: true
region: [world]
size: 1984
md5:
- "5c124e7948ada85da603a522782940d0"
- "4921d5f2165dee6e2496f4388c4c81da"
validation: [md5]
description: "PIF boot ROM (NTSC)"
note: >
Chosen for SYSTEM_NTSC and SYSTEM_MPAL. rom_country_code_to_system_type
returns SYSTEM_PAL only for country codes 0x44, 0x46, 0x49, 0x50, 0x53,
0x55, 0x58 and 0x59 and falls through to SYSTEM_NTSC for 0x37, 0x41,
0x45, 0x4a and, on its default arm, every other code, which is why the
region is recorded as world rather than an enumeration. main_run reads
1984 bytes, the size of the PIF ROM window, and open_pif digests exactly
that span, so the size given here is the length consumed rather than a
check the code performs. Two digests are accepted: the current one, which
is the image shipped in data/ and the No-Intro entry "[BIOS] Nintendo 64
- PIF (Japan, USA).bin" at 1984 bytes, and the digest of the earlier dump
kept for compatibility. On a match the image is byteswapped into PIF
memory and the reset vector moves to 0xbfc00000; on a mismatch the core
logs "Invalid PIF ROM" and boots through the HLE bootrom instead.
source_ref: "mupen64plus-core/src/main/main.c:1565-1580,1624-1633,2097-2135, mupen64plus-core/src/main/rom.c:502-525, mupen64plus-core/src/device/pif/pif.h:36"
- name: "pif.pal.rom"
system: nintendo-64
required: false
hle_fallback: true
region: [europe, australia]
size: 1984
md5:
- "d4232dc935cad0650ac2664d52281f3a"
- "2b6eec586faa43f3462333b844834554"
validation: [md5]
description: "PIF boot ROM (PAL)"
note: >
Chosen for SYSTEM_PAL, which covers the eight country codes 0x44 German,
0x46 French, 0x49 Italian, 0x50 European, 0x53 Spanish, 0x55 Australian,
0x58 and 0x59 European. Same read length, digest span and fallback as the
NTSC image. The current digest is the image shipped in data/ and the
No-Intro entry "[BIOS] Nintendo 64 - PIF (Europe).bin" at 1984 bytes; the
second value is the earlier dump the fork still accepts.
source_ref: "mupen64plus-core/src/main/main.c:1565-1580,1624-1633,2097-2135, mupen64plus-core/src/main/rom.c:502-525, mupen64plus-core/src/device/pif/pif.h:36"
+67
View File
@@ -0,0 +1,67 @@
emulator: solarus
type: standalone
core_classification: game_engine
source: "https://gitlab.com/solarus-games/solarus"
upstream: "https://gitlab.com/solarus-games/solarus"
profiled_date: "2026-08-08"
source_commit: "bc2707d1fba2ec1e6529857f87202a20998bff13"
core_version: "2.2.0"
display_name: "Solarus Game Engine"
cores:
- solarus
systems:
- solarus
mode: standalone
notes: |
2D action-RPG engine running quests scripted in Lua, built as libsolarus with
the solarus-run command-line player and the Qt Solarus Launcher on top. ES-DE
runs `solarus-run <rom>` on a single .solarus file, Batocera as `solarus-run
-fullscreen=yes -cursor-visible=no -lua-console=no -quit-combo=<hotkey>+<start>
-joypad-num<n>=<index> <rom>` off a bbecaf31 pin, RetroDECK ships the v2.0.3
solarus-launcher AppImage.
The quest arrives as the content argument. get_quest_path takes the last
non-option argv and otherwise falls back to SOLARUS_DEFAULT_QUEST, which
defaults to "." (MainLoop.cpp:108-121, cmake/AddOptions.cmake:8,
Common.h:119-123). open_quest mounts that path through PhysFS directly, then
tries <path>/data, <path>/data.solarus and <path>/data.solarus.zip, each both
relative and under PHYSFS_getBaseDir (QuestFiles.cpp:151-165), and the quest
counts as found once quest.dat resolves (QuestFiles.cpp:228-233). The rest
comes out of that mount: quest.dat and project_db.dat
(CurrentQuest.cpp:44,49), fonts under fonts/ as .png, .ttf, .otf, .ttc or .fon
(FontResource.cpp:65-101), shaders under shaders/ (Shader.cpp:113), tilesets,
sprites and music (Tileset.cpp:156-174, SpriteAnimationSet.cpp:48,
MusicSystem.cpp:136-142).
Startup reads one file from outside the quest. System::initialize probes
SDL_GetBasePath() then SOLARUS_DATADIR_PATH for gamecontrollerdb.txt and hands
whichever it finds to SDL through SDL_HINT_GAMECONTROLLERCONFIG_FILE
(System.cpp:71-99). The GLSL fallbacks are raw string literals in
DefaultShaders.h:57,114, and glad, hqx and snes_spc compile in from
third_party/.
Files the engine writes rather than expects: settings.dat and savegames under
the quest write directory named in quest.dat (Settings.cpp:149-166,240-280,
Savegame.cpp:114), the write root from SDL_GetPrefPath (QuestFiles.cpp:540),
and error.txt under SOLARUS_FILE_LOGGING (Logger.cpp:29-45). Batocera's
002-pad.patch adds a read of /userdata/system/configs/solarus/pads.ini, which
its own generator rewrites at every launch. The editor and launcher subtrees
build separately from the root CMakeLists, which adds only cli/, tests/ and
third_party/, and their assets are Qt resources compiled into those binaries
(editor/cmake/AddQtFiles.cmake:46-50, launcher/cmake/addTarget.cmake:30).
files:
- name: gamecontrollerdb.txt
system: solarus
category: game_data
required: false
description: "SDL gamepad mappings applied on top of the built-in table"
source_ref: "src/core/System.cpp:71-99, cmake/AddDefines.cmake:44-49, cmake/AddInstallTargets.cmake:23-28"
note: >-
Looked up next to the executable first, then under SOLARUS_DATADIR_PATH,
share/solarus by default (cmake/AddInstallDirs.cmake:14). Installed from
assets/gamecontrollerdb.txt when SOLARUS_GAMECONTROLLERDB_INSTALL is on,
which is the default (cmake/AddOptions.cmake:51), and carried in the
release archives (.gitlab-ci.yml:306). Both probes are guarded by an
existence test, and neither hitting leaves SDL on its built-in mappings.
+116
View File
@@ -0,0 +1,116 @@
emulator: SUPER ZSNES
type: standalone
core_classification: other
source: "https://www.zsnes.com"
upstream: "https://www.zsnes.com"
profiled_date: "2026-08-08"
core_version: "v0.230b"
display_name: "Nintendo - SNES / SFC (SUPER ZSNES)"
cores:
- superzsnes
- SUPERZSNES
systems:
- nintendo-snes
mode: standalone
notes: |
Super Famicom emulator by zsKnight and _Demo_, written from scratch with a
GPU-rendered PPU and unrelated to the ZSNES codebase. Shipped as binaries
only, for Windows, macOS, Linux and Android; the desktop builds are Unity
Mono, so the emulator is Assembly-CSharp.dll and the per-game tables are
serialized into the level0 scene. The Windows and Linux 0.230b builds carry
the same tables and the same emulation sources.
One NEC uPD7725 interpreter serves every cartridge whose header declares a
DSP. RomLoader.GetROMType reads the cartridge type byte at $FFD6 and returns
COProcessorType.DSP when the low nibble is 3 to 6 and the high nibble is 0,
or when the high nibble is F and the subtype byte at $FFBF is 1 or 2.
MainMemoryMap.InitSpecialChips builds the DSP1 object for that type alone.
The DSP1 constructor picks the filename from a table keyed on the CRC32 of
the 21 raw header title bytes, taken as Latin-1 and re-encoded UTF-8,
falling back to dsp1b.rom when no entry matches. Words are assembled little
endian, 2048 24-bit program words from offset 0 then 1024 16-bit data words
from offset 6144.
Three locations are tried in order: the folder holding the loaded ROM, the
Unity persistent data folder (ZEMU Software Inc./SUPERZSNES), then the
folder holding the executable. None of them goes through the srm and bps
path overrides. When all three miss, a "Need DSP ROM" dialog names the file
and the chip runs on a zero-filled 8192-byte buffer.
No other file is read. SA-1, SPC7110, S-RTC, Cx4, OBC-1, Super Game Boy and
the ST01x and ST018 enum entries build no chip, the SPC700 IPL is a 64-byte
array in CPUSPC700, and the enhancement data, the audio replacement data and
testgame.smc are Unity resources inside the build. Save RAM, save states,
cheats, bps patches and MSU-1 packs are all named after the loaded ROM.
files:
# NEC uPD7725 microcode, program and data ROM in one file.
# The name is chosen by CRC32 of the 21-byte header title; dsp1b.rom is the
# default when no entry in the table matches.
- name: "dsp1b.rom"
aliases: ["SNES_dsp1b.rom"]
system: nintendo-snes
description: "NEC uPD7725 DSP-1B microcode"
required: true
size: 8192
crc32: 465c4e1c
validation: [crc32]
source_ref: "Assets/Scripts/SpecialChips/DSP1.cs:88-89 (name and expected CRC32 1180454428), DSP1.cs:151-155 (compare, warn on mismatch), Assets/Scripts/SpecialChips/DSP1Core.cs:756-769 (8192-byte layout)"
note: "Default for every DSP cartridge with no table entry, so it covers DSP-1 and DSP-1A titles as well. A mismatched CRC32 warns and the data is used anyway."
- name: "dsp2.rom"
aliases: ["SNES_dsp2.rom"]
system: nintendo-snes
description: "NEC uPD7725 DSP-2 microcode"
required: true
size: 8192
source_ref: "Assets/Scripts/SpecialChips/DSP1.cs:98-114 (table lookup, no CRC32 check), SUPERZSNES_Data/level0 (VersionNo.dspDetections entry 1, title CRC32 0x84690f8b)"
note: "Selected for header title 'DUNGEON MASTER' (Dungeon Master)."
- name: "dsp3.rom"
aliases: ["SNES_dsp3.rom"]
system: nintendo-snes
description: "NEC uPD7725 DSP-3 microcode"
required: true
size: 8192
source_ref: "Assets/Scripts/SpecialChips/DSP1.cs:98-114 (table lookup, no CRC32 check), SUPERZSNES_Data/level0 (VersionNo.dspDetections entry 2, title CRC32 0xfa7f8076)"
note: "Selected for the half-width katakana header title of SD Gundam GX, 'SD' then $B6 $DE $DD $C0 $DE $D1 then 'GX'."
- name: "dsp4.rom"
aliases: ["SNES_dsp4.rom"]
system: nintendo-snes
description: "NEC uPD7725 DSP-4 microcode"
required: true
size: 8192
source_ref: "Assets/Scripts/SpecialChips/DSP1.cs:98-114 (table lookup, no CRC32 check), SUPERZSNES_Data/level0 (VersionNo.dspDetections entry 3, title CRC32 0x42578645)"
note: "Selected for header title 'TOP GEAR 3000' (Top Gear 3000)."
# Seta parts. The table routes their cartridges to the same uPD7725
# interpreter, which reads the first 8192 bytes and checks neither size nor
# hash.
- name: "st010.rom"
aliases: ["SNES_st010.rom"]
system: nintendo-snes
description: "Seta ST010 microcode"
required: true
source_ref: "Assets/Scripts/SpecialChips/DSP1.cs:98-114 (table lookup, no CRC32 check), SUPERZSNES_Data/level0 (VersionNo.dspDetections entry 4, title CRC32 0x04e7aca6)"
note: "Selected for header title 'F1 ROC II' with $00 as the 21st byte (F1 ROC II: Race of Champions)."
- name: "st011.rom"
aliases: ["SNES_st011.rom"]
system: nintendo-snes
description: "Seta ST011 microcode"
required: true
source_ref: "Assets/Scripts/SpecialChips/DSP1.cs:98-114 (table lookup, no CRC32 check), SUPERZSNES_Data/level0 (VersionNo.dspDetections entry 5, title CRC32 0xc96d71c1)"
note: "Selected for header title '2DAN MORITA SHOUGI' with $00 as the 21st byte (Hayazashi Nidan Morita Shougi)."
- name: "st018.rom"
aliases: ["SNES_st018.rom"]
system: nintendo-snes
description: "Seta ST018 firmware"
required: true
source_ref: "Assets/Scripts/SpecialChips/DSP1.cs:98-114 (table lookup, no CRC32 check), SUPERZSNES_Data/level0 (VersionNo.dspDetections entry 6, title CRC32 0x85885c5e)"
note: "Selected for header title 'NIDAN MORITASHOGI2' (Hayazashi Nidan Morita Shougi 2)."
+5 -5
View File
@@ -32,7 +32,7 @@ notes: |
files:
- name: "scph5500.bin"
description: "SCPH-5500 (v3.0 09-09-96 J)"
region: "NTSC-J"
region: [japan]
required: false
md5: "8dd7d5296a650fac7319bce665a6a53c"
size: 524288
@@ -42,7 +42,7 @@ files:
- name: "scph5501.bin"
description: "SCPH-5501, 5503, 7003 (v3.0 11-18-96 A)"
region: "NTSC-U"
region: [north-america]
required: false
md5: "490f666e1afb15b7362b406ed1cea246"
size: 524288
@@ -52,7 +52,7 @@ files:
- name: "scph5502.bin"
description: "SCPH-5502, 5552 (v3.0 01-06-97 E)"
region: "PAL"
region: [europe]
required: false
md5: "32736f17079d0b2b7024407c39bd3050"
size: 524288
@@ -62,7 +62,7 @@ files:
- name: "psxonpsp660.bin"
description: "PSP, SCPH-1000R (v4.5 05-25-00 J)"
region: "Auto"
region: [world]
required: false
md5: "c53ca5908936d412331790f4426c6c33"
size: 524288
@@ -72,7 +72,7 @@ files:
- name: "ps1_rom.bin"
description: "PS3 embedded PS1 BIOS (v5.0 06-23-03 A)"
region: "Auto"
region: [world]
required: false
md5: "81bbe60ba7a3d1cea1d48c14cbcc647b"
size: [524288, 4194304, 4089584]
+387
View File
@@ -0,0 +1,387 @@
emulator: Triforce
type: standalone
core_classification: enhanced_fork
source: "https://github.com/REG-Linux/dolphin-triforce"
upstream: "https://github.com/dolphin-emu/dolphin"
profiled_date: "2026-08-08"
source_commit: "5c456e8ff0da0235be2cf1d55ba7bb2115b0cae2"
core_version: "2407"
display_name: "Namco / Sega / Nintendo - Triforce (Dolphin Triforce)"
cores:
- triforce
- dolphin-triforce
systems:
- sega-triforce
- nintendo-wii-arcade
- nintendo-gamecube
- nintendo-wii
mode: standalone
notes: |
crediar's Dolphin fork, which adds the Triforce arcade boards (AM-Baseboard on
the serial interface, AM-Mediaboard on the disc interface) and the Wii Arcade
boards on top of GameCube and Wii emulation. The tree self-reports Dolphin 2407
(CMake/ScmRevGen.cmake:34-35) and builds DolphinQt. crediar publishes the source
on crediar.dev; the commit profiled here is the REG-Linux mirror of it, whose
Data/Sys tree matches the Hancock33 and ReaverTeknoGods mirrors byte for byte.
ES-DE looks for dolphin-emu-triforce on Linux and Triforce.exe or
Triforce/DolphinWX.exe on Windows, RetroBat installs it as dolphin-triforce.
segaboot.gcm is the Triforce firmware. DVDInterface::Init calls
AMMediaboard::Init only when EXI serial port 1 holds the AM Mediaboard, so the
read happens on every Triforce launch and never otherwise
(Source/Core/Core/HW/DVD/DVDInterface.cpp:289-294). Init resolves the file under
Sys/Triforce, with no User fallback, and copies min(file size, 2 MiB) into the
firmware buffer without checking anything
(Source/Core/Core/HW/DVD/AMMediaboard.cpp:215-233). A missing file raises a
modal alert and returns before the buffer is filled, leaving it at 0xFF. The
guest reads that buffer whenever the firmware is mapped
(Source/Core/Core/HW/DVD/AMMediaboard.cpp:1083-1090), which is how the Service
and Test menus are reached. The tree ships the copy documented below, SegaBoot
v3.11 with a RELSAB header, and the mediaboard answers GetSegaBootVersion for
both 3.09 and 3.11 layouts
(Source/Core/Core/HW/DVD/AMMediaboard.cpp:1268-1269, 1397-1398).
Triforce mode also swaps the GameCube boot ROM name: GetBootROMPath returns
IPL_TRI.bin instead of IPL.bin, User first then Sys
(Source/Core/Core/Config/MainSettings.cpp:614-625). Load_BS2 reads at most 2 MiB,
CRC32s what it read against a table of Redump dumps and accepts 0xD1883221 as
the Triforce revision (Source/Core/Core/Boot/Boot.cpp:391-436). On that match it
patches OSReport and maps SegaBoot as firmware so the guest IPL can chain into
it (Source/Core/Core/Boot/Boot.cpp:482-489). SkipIPL defaults to true
(Source/Core/Core/Config/MainSettings.cpp:37) and EmulatedBS2 otherwise copies
the disc straight into DIMM memory and clears the firmware mapping
(Source/Core/Core/Boot/Boot_BS2Emu.cpp:332-347), so games run without any IPL.
Boot ROM directories follow the legacy naming: GetDirectoryForRegion defaults to
RegionDirectoryStyle::Legacy (Source/Core/Core/Config/MainSettings.h:369-370) and
every boot ROM caller takes the default, so NTSC-J resolves to JAP. FindIPLDump
probes USA, EUR and JAP and stops there
(Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp:180-189).
Wii Arcade runs as IOSC console type RVA, reached three ways: the RVA expansion
device in slot A (Source/Core/Core/IOS/IOSC.cpp:213-218), an RVA.txt file in the
System Menu title data (Source/Core/Core/Boot/Boot_BS2Emu.cpp:387-397), or a
ticket issued by Root-CA10000000-XS10000000
(Source/Core/Core/IOS/ES/Formats.cpp:490-493). That console type switches to the
development common key and root key held in the binary
(Source/Core/Core/IOS/IOSC.cpp:603-615).
Save data the emulator creates on first run is keyed on the disc, so none of it
can be supplied: tridimm_<game-id>.bin and backup_<game-id>.bin
(Source/Core/Core/HW/DVD/AMMediaboard.cpp:201-202), the baseboard backup
tribackup_<game-id>.bin
(Source/Core/Core/HW/EXI/EXI_DeviceAMBaseboard.cpp:77-100), the card reader image
tricard_<game-id>.bin
(Source/Core/Core/HW/SI/SI_DeviceAMBaseboard.cpp:1147-1310), and the three Wii
Arcade SRAM images under User/Arcade, sized 0x1400, 0x1A40 and 0x8000 by game
type (Source/Core/Core/HW/EXI/EXI_DeviceRVA.cpp:1249-1285).
Recognised Triforce titles are F-Zero AX, F-Zero AX Monster Ride, Mario Kart
Arcade GP 1 and 2, Virtua Striker 3 and 4, Gekitou Pro Yakyuu and Key of Avalon
(Source/Core/Core/HW/DVD/AMMediaboard.h:25-36).
# Two roots. Paths starting with Sys/ are relative to the installation data
# directory returned by File::GetSysDirectory (Source/Core/Common/FileUtil.cpp:800),
# which is where the code looks and nowhere else. Every other path is relative to
# the user directory (GC/, GBA/, Wii/, Triforce/, Arcade/, Load/), which the code
# tries first, falling back to the same relative path under Sys/ for the GameCube
# boot ROMs and DSP ROMs.
files:
# -- Triforce firmware --
- name: "segaboot.gcm"
path: "Sys/Triforce/segaboot.gcm"
description: "SegaBoot, the Triforce system disc image held on the AM-Mediaboard"
system: sega-triforce
size: 2097152
sha1: "87918619c632ac9de270d4fdf396a57eb57fc620"
required: true
source_ref: "Source/Core/Core/HW/DVD/AMMediaboard.cpp:215-233, Source/Core/Core/HW/DVD/DVDInterface.cpp:289-294"
note: >
Read on every Triforce launch, Sys/Triforce only with no User fallback.
Nothing is validated, min(file size, 2 MiB) is copied into the firmware
buffer. The hash is the copy the fork's own Data/Sys tree carries, SegaBoot
v3.11.
# -- Triforce GameCube boot ROM --
# Region-specific directory, User/GC/<region>/ then Sys/GC/<region>/.
# One dump (Redump "Triforce (ARCADE BOOTROM)", DEV revision 1.0) serves every
# directory, the region only decides where the code looks.
- name: "IPL_TRI.bin"
path: "GC/USA/IPL_TRI.bin"
description: "Triforce boot ROM, NTSC-U directory"
system: sega-triforce
region: [north-america]
size: 2097152
crc32: "d1883221"
validation: [crc32]
required: false
hle_fallback: true
source_ref: "Source/Core/Common/CommonPaths.h:149, Source/Core/Core/Config/MainSettings.cpp:614-625, Source/Core/Core/Boot/Boot.cpp:400,415-436"
note: >
CRC32 is computed over the first 2 MiB and compared against the Redump
table, 0xD1883221 being the Triforce revision. An unknown value warns and
loading continues. A match also maps SegaBoot as firmware
(Source/Core/Core/Boot/Boot.cpp:482-489).
- name: "IPL_TRI.bin"
path: "GC/EUR/IPL_TRI.bin"
description: "Triforce boot ROM, PAL directory"
system: sega-triforce
region: [europe]
size: 2097152
crc32: "d1883221"
validation: [crc32]
required: false
hle_fallback: true
source_ref: "Source/Core/Core/Config/MainSettings.cpp:620-623"
- name: "IPL_TRI.bin"
path: "GC/JAP/IPL_TRI.bin"
description: "Triforce boot ROM, NTSC-J directory"
system: sega-triforce
region: [japan]
size: 2097152
crc32: "d1883221"
validation: [crc32]
required: false
hle_fallback: true
source_ref: "Source/Core/Core/Config/MainSettings.cpp:587-612,620-623"
note: "JAP is the directory the legacy naming style returns for NTSC-J."
# -- AM-Mediaboard system state --
- name: "trinetcfg.bin"
path: "Triforce/trinetcfg.bin"
description: "Mediaboard network configuration"
system: sega-triforce
required: false
unsourceable: "created empty by the emulator on first Triforce launch, written by the guest, no hardware dump equivalent"
source_ref: "Source/Core/Core/HW/DVD/AMMediaboard.cpp:169-177,198"
- name: "trinetctrl.bin"
path: "Triforce/trinetctrl.bin"
description: "Mediaboard network control block"
system: sega-triforce
required: false
unsourceable: "created empty by the emulator on first Triforce launch, written by the guest, no hardware dump equivalent"
source_ref: "Source/Core/Core/HW/DVD/AMMediaboard.cpp:169-177,199"
- name: "triextra.bin"
path: "Triforce/triextra.bin"
description: "Mediaboard extra settings block"
system: sega-triforce
required: false
unsourceable: "created empty by the emulator on first Triforce launch, written by the guest, no hardware dump equivalent"
source_ref: "Source/Core/Core/HW/DVD/AMMediaboard.cpp:169-177,200"
# -- Wii Arcade --
- name: "RVA.txt"
path: "Wii/title/00000001/00000002/data/RVA.txt"
description: "Marker that switches the emulated console to Wii Arcade mode"
system: nintendo-wii-arcade
required: false
unsourceable: "user-created marker inside the emulated NAND, only its presence is tested, no file is distributed"
source_ref: "Source/Core/Common/CommonPaths.h:165, Source/Core/Core/Boot/Boot_BS2Emu.cpp:387-397"
note: >
Opened for read inside the System Menu title data. Success sets console type
RVA and forces the RGB region settings. The RVA expansion device in slot A
reaches the same console type without it
(Source/Core/Core/IOS/IOSC.cpp:213-218).
# -- GameCube boot ROM --
# User/GC/<region>/ then Sys/GC/<region>/. Also the preferred source for the
# GameCube fonts when present.
- name: "IPL.bin"
path: "GC/USA/IPL.bin"
description: "GameCube NTSC-U boot ROM"
region: [north-america]
size: 2097152
required: false
hle_fallback: true
source_ref: "Source/Core/Common/CommonPaths.h:148, Source/Core/Core/Config/MainSettings.cpp:627-630, Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp:109-118,182-183"
note: "Needed to boot the GameCube menu and to take the fonts from a real dump."
- name: "IPL.bin"
path: "GC/EUR/IPL.bin"
description: "GameCube PAL boot ROM"
region: [europe]
size: 2097152
required: false
hle_fallback: true
source_ref: "Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp:184-185"
- name: "IPL.bin"
path: "GC/JAP/IPL.bin"
description: "GameCube NTSC-J boot ROM"
region: [japan]
size: 2097152
required: false
hle_fallback: true
source_ref: "Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp:186-187"
# -- DSP ROMs --
# User/GC/ then Sys/GC/. Used by DSP LLE, and dsp_coef.bin also by the HLE
# polyphase resampler.
- name: "dsp_rom.bin"
path: "GC/dsp_rom.bin"
description: "DSP instruction ROM"
size: 8192
validation: [size]
known_hash_adler32: "0x66f334fe"
adler32_byteswap: true
required: false
hle_fallback: true
source_ref: "Source/Core/Common/CommonPaths.h:145, Source/Core/Core/HW/DSPLLE/DSPLLE.cpp:87-105,109-118, Source/Core/Core/DSP/DSPCore.h:44, Source/Core/Core/DSP/DSPCore.cpp:36-38"
note: >
LoadDSPRom rejects any file whose length differs from DSP_IROM_BYTE_SIZE and
swaps every 16 bit word before storing it, so the Adler32 in the source is
taken over the swapped data (Source/Core/Core/HW/DSPLLE/DSPLLE.cpp:100-102).
The pair is matched against seven known sets, the first being the Nintendo
ROMs; a miss asks the user whether to stop
(Source/Core/Core/DSP/DSPCore.cpp:60-84).
- name: "dsp_coef.bin"
path: "GC/dsp_coef.bin"
description: "DSP coefficient ROM"
size: 4096
validation: [size]
known_hash_adler32: "0xf3b93527"
adler32_byteswap: true
required: false
hle_fallback: true
source_ref: "Source/Core/Common/CommonPaths.h:146, Source/Core/Core/HW/DSPLLE/DSPLLE.cpp:87-105,110-119, Source/Core/Core/DSP/DSPCore.h:58, Source/Core/Core/HW/DSPHLE/UCodes/AX.cpp:61-62"
note: >
Also read by the HLE AX ucode for polyphase resampling. Adler32 is taken over
the byte-swapped data (Source/Core/Core/HW/DSPLLE/DSPLLE.cpp:100-102).
# -- GameCube fonts --
# Sys/GC/ only. Skipped when an IPL dump is available, the fonts are then read
# out of the dump at 0x1aff00 and 0x1fcf00 instead.
- name: "font_western.bin"
path: "Sys/GC/font_western.bin"
description: "Windows-1252 font used by GameCube and Wii text rendering"
size: 9589
required: false
hle_fallback: true
source_ref: "Source/Core/Common/CommonPaths.h:142, Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp:131,203-247"
note: >
Size is the official font length the code reads from an IPL dump, 0x2575
(Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp:234-236). A standalone file is
read without any check.
- name: "font_japanese.bin"
path: "Sys/GC/font_japanese.bin"
description: "Shift-JIS font used by GameCube and Wii text rendering"
size: 303693
required: false
hle_fallback: true
source_ref: "Source/Core/Common/CommonPaths.h:143, Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp:130,203-247"
note: "Size is the official font length read from an IPL dump, 0x4a24d."
# -- GBA BIOS --
- name: "gba_bios.bin"
path: "GBA/gba_bios.bin"
description: "GBA BIOS for the GameCube to Game Boy Advance link"
required: false
hle_fallback: true
source_ref: "Source/Core/Common/CommonPaths.h:155, Source/Core/Common/FileUtil.cpp:917-919, Source/Core/Core/HW/GBACore.cpp:202-206,336-353"
note: >
Loaded into the integrated mGBA core, which fails to start without it. The
path is overridable by the Main.GBA BIOS setting
(Source/Core/Core/Config/MainSettings.cpp:361).
# -- Wii system files --
- name: "SYSCONF"
path: "Wii/shared2/sys/SYSCONF"
description: "Wii system configuration"
size: 16384
validation: [size]
required: false
hle_fallback: true
source_ref: "Source/Core/Common/CommonPaths.h:87,127, Source/Core/Core/SysConf.cpp:19,54-65"
note: >
SysConf::Load rejects any size other than SYSCONF_SIZE and falls back to
built-in defaults. Generated by the emulator, can come from a NAND backup
instead.
- name: "setting.txt"
path: "Wii/title/00000001/00000002/data/setting.txt"
description: "Wii region, area and serial settings"
size: 256
required: false
hle_fallback: true
source_ref: "Source/Core/Common/CommonPaths.h:163, Source/Core/Core/Boot/Boot_BS2Emu.cpp:412-424, Source/Core/Common/SettingsHandler.h:21,26"
note: >
Read into a fixed 256 byte buffer, then rewritten during Wii boot emulation
from the region settings table.
- name: "nand.bin"
path: null
description: "BootMii NAND backup, imported through the NAND importer"
required: false
hle_fallback: true
source_ref: "Source/Core/DiscIO/NANDImporter.cpp:26-40,42-57"
note: >
Accepted at 0x21000000 bytes, or 0x21000400 when the OTP and SEEPROM dump is
appended. Any other size is rejected.
- name: "keys.bin"
path: "Wii/keys.bin"
description: "OTP and SEEPROM dump holding the console keys"
size: 1024
required: false
hle_fallback: true
source_ref: "Source/Core/DiscIO/NANDImporter.cpp:19,76-88,288-298, Source/Core/Core/IOS/IOSC.cpp:639-665"
note: >
Asked for at import time when not appended to the NAND image, and written to
the Wii root. Read at every boot, absence falls back to the built-in default
key set.
- name: "clientca.pem"
path: "Wii/clientca.pem"
description: "SSL client certificate extracted from IOS13"
required: false
hle_fallback: true
source_ref: "Source/Core/DiscIO/NANDImporter.cpp:201-286"
note: "Located inside the IOS13 content during NAND import by its leading bytes."
- name: "clientcakey.pem"
path: "Wii/clientcakey.pem"
description: "SSL client private key extracted from IOS13"
required: false
hle_fallback: true
source_ref: "Source/Core/DiscIO/NANDImporter.cpp:237"
- name: "rootca.pem"
path: "Wii/rootca.pem"
description: "SSL root certificate extracted from IOS13"
required: false
hle_fallback: true
source_ref: "Source/Core/DiscIO/NANDImporter.cpp:238"
- name: "WiiSD.raw"
path: "Load/WiiSD.raw"
description: "Virtual SD card image for the Wii SD slot"
required: false
hle_fallback: true
source_ref: "Source/Core/Common/CommonPaths.h:160, Source/Core/Common/FileUtil.cpp:909"
note: "Created by the emulator, path overridable by the General WiiSDCardPath setting."
- name: "Wii System Menu"
path: null
description: "Wii System Menu WAD, installed into the emulated NAND"
required: false
hle_fallback: true
source_ref: "Source/Core/DolphinQt/MenuBar.cpp:290,1098-1112"
note: "Needed to boot the Wii Menu. Installed through Tools, Install WAD."
- name: "codehandler.bin"
path: "Sys/codehandler.bin"
description: "Gecko code handler used to apply cheat codes"
required: false
hle_fallback: true
source_ref: "Source/Core/Common/CommonPaths.h:167, Source/Core/Core/GeckoCode.cpp:121-134"
note: >
Read from the Sys root. Cheats are refused when it is missing and when it
exceeds the installer window.
+116
View File
@@ -0,0 +1,116 @@
emulator: veesem
type: standalone
core_classification: other
source: "https://github.com/sp1187/veesem"
upstream: "https://github.com/sp1187/veesem"
profiled_date: "2026-08-08"
source_commit: "42fb8f07e7418f16ccfb7364127aef2217dda641"
core_version: "0.2"
display_name: "VTech - V.Smile (veesem)"
cores:
- veesem
systems:
- vtech-vsmile
mode: standalone
notes: |
V.Smile emulator written from scratch on top of a SunPlus SPG200 (unSP)
implementation, distributed as source only. No distribution packages it;
ES-DE offers it for its vsmile system beside MAME and the MAME libretro
core, and finds it by the binary name or the com.github.sp1187.veesem
flatpak.
The system ROM has no fixed name and no search path. -sysrom takes a path
(main.cc:64-70) which is opened directly (ui.cc:191), and the open is the
only check the tree performs: the read asks for sizeof *sysrom, the
1024*1024-word buffer of vsmile.h:17, so a shorter file keeps the zeros the
buffer was value-initialised with and anything past 2 MiB is never reached.
No size test, no hash, no signature anywhere. Every word is passed through
SDL_SwapLE16 after the read (ui.cc:196-197), so the image is consumed as
little-endian 16-bit words.
Without -sysrom the buffer is synthesised instead: zero-filled, with 0x31
written into the odd word of each pair over 0xFFFC0-0xFFFDB, called a
"game-compatible dummy system ROM" in the code (ui.cc:198-204) and a "dummy
ROM without boot animation" in the README.
Nothing boots from the system ROM. Extmem::Reset leaves address_decode at 0
(extmem.cc:7-10), routing every external address to ROMCSB, and bank 0 stays
the cartridge under all three decode modes (extmem.cc:20-52). The CPU takes
its reset vector from 0xfff7 (cpu.cc:91), FIQ from 0xfff6, IRQs from
0xfff8+n and BREAK from 0xfff5 (cpu.cc:116,125,228), all inside bank 0, so
the vectors always come from the cartridge. The system ROM sits on CSB3
(vsmile.cc:198-200), reachable at 0x300000-0x3FFFFF only once cartridge code
selects decode mode 2 or 3.
Region is a jumper, not a file. The low nibble of Port C carries the region
code and bit 4 the VTech logo jumper (vsmile.cc:148-152), defaulting to 0xe
with the logo on (main.cc:44-45) and settable with -region and -novtech. One
system ROM image serves every region; the table at vsmile.cc:3-25 maps the
sixteen jumper values to the intro each revision produces, and names
revisions 1.00, 1.02 and 1.03.
files:
- name: vsmile_v103.bin
description: "V.Smile system ROM, revision 1.03"
required: false
hle_fallback: true
size: 2097152
source_ref: "src/main.cc:64-70 (-sysrom), src/ui/ui.cc:189-197 (load), src/core/vsmile/vsmile.h:17 (buffer), src/core/vsmile/vsmile.cc:198-200 (CSB3), src/core/vsmile/vsmile.cc:5,13 (jumper values for 1.03)"
note: >
Jumper 0x2 gives Italian and 0xa UK English without subtitle on this
revision, the two values 1.02 assigns the other way round.
- name: vsmile_v102.bin
description: "V.Smile system ROM, revision 1.02"
required: false
hle_fallback: true
size: 2097152
source_ref: "src/main.cc:64-70 (-sysrom), src/ui/ui.cc:189-197 (load), src/core/vsmile/vsmile.h:17 (buffer), src/core/vsmile/vsmile.cc:198-200 (CSB3), src/core/vsmile/vsmile.cc:4-9,13,17-18 (jumper values for 1.02+)"
note: >
The revision the "1.02+" entries describe: 0x0 and 0x1 suppress the
V.Smile screen, 0x3 to 0x5 select US English variants and 0xe and 0xf
carry the "Learning System" subtitle.
- name: vsmile_v100.bin
description: "V.Smile system ROM, revision 1.00"
required: false
hle_fallback: true
size: 2097152
source_ref: "src/main.cc:64-70 (-sysrom), src/ui/ui.cc:189-197 (load), src/core/vsmile/vsmile.h:17 (buffer), src/core/vsmile/vsmile.cc:198-200 (CSB3), src/core/vsmile/vsmile.cc:13,20-24 (jumper values and behaviour for 1.00)"
note: >
Its standard English subtitle is "TV Learning System", and with no
cartridge and a region code below 0x6 it shows a blinking blue VTech
logo in white.
analysis:
user_supplied_paths:
note: "Named on the command line, with no fixed filename"
entries:
- what: "cartridge ROM, the positional argument"
source_ref: "src/main.cc:119-126, src/ui/ui.cc:180-187"
note: >
Read into a 4M-word buffer and mapped over ROMCSB, CSB1 and CSB2
(vsmile.cc:168-190). The dual-ROM cartridges pair a 4 MiB ROM on the
first two banks with a 2 MiB ROM on CSB2, which the code reads from
the same dump at word 0x200000.
- what: "system ROM, -sysrom"
source_ref: "src/main.cc:64-70, src/ui/ui.cc:189-197"
generated_files:
- what: "Art Studio CSB2 NVRAM, -art-nvram FILE"
source_ref: "src/main.cc:71-77 (flag), src/ui/ui.cc:206-221 (read), src/ui/ui.cc:153-170 (write)"
note: >
Save data rather than a dump to obtain. The 128K-word buffer is
allocated before the stream is tested (ui.cc:210-211), so an absent or
unreadable file leaves a blank NVRAM, and -art on its own selects the
same cartridge type with no file at all (ui.cc:218-220). It backs the
drawing area of V.Smile Art Studio (vsmile.cc:180-196) and is flushed
to the same path when the machine is unloaded.
settings_storage:
source_ref: "src/ui/ui.cc:126"
note: >
io.IniFilename is nullptr, so Dear ImGui reads and writes no imgui.ini.
Every setting comes from the command line or the UI, and no other path
in the tree is opened.
+211
View File
@@ -0,0 +1,211 @@
emulator: visual-pinball
type: standalone
core_classification: game_engine
source: "https://github.com/vpinball/vpinball"
upstream: "https://github.com/vpinball/vpinball"
profiled_date: "2026-08-08"
source_commit: "afc7c38ffb1078076ec523c37b30055061c93ff1"
core_version: "10.8.0"
display_name: "Visual Pinball X"
cores:
- vpinball
- visual-pinball
systems:
- vpinball
mode: standalone
notes: |
Pinball table simulator. The table is the content: .vpx and .vpt files are
OLE Compound Documents holding the geometry, textures, sounds and a VBScript
program, read through POLE on non-Windows platforms. The standalone branch
ports the Windows original by embedding Wine's VBScript engine, stubbing COM
and ATL from Wine and ReactOS sources, and linking libpinmame, libaltsound,
libdmdutil, libdof and BASS in place of the Windows COM servers
(standalone/README.md:11-120). ES-DE finds VPinballX_BGFX or VPinballX_GL and
runs `<binary> -play <rom>`, Batocera builds the standalone tree at
3ec37c7f9a into /usr/bin/vpinball and runs `VPinballX_GL -PrefPath <dir> -Ini
<dir>/VPinballX.ini -Play <rom>`, RetroBat drives the Windows build with its
registered VPinMAME COM server.
Two path roots decide where everything is read from. m_szMyPath is the
install directory, m_szMyPrefPath is ~/.vpinball or whatever -PrefPath names,
and loading a table sets the working directory to the table's own folder
(main.cpp:408, src/parts/pintable.cpp:2497,11165). Batocera's 001-default-path.patch
redirects the PinMAME root from $HOME/.pinmame to <prefpath>/pinmame.
Table scripts pull their libraries through GetTextFile, which walks seven
locations in order: the working directory, then user/, scripts/ and tables/
under the install directory, then the same three under the preferences path
(src/parts/pintable.cpp:470-480, main.h:118-119, main.cpp:890-892). The
scripts/ directory the build ships carries the ~70 .vbs files tables include
by name, core.vbs and controller.vbs beside the per-manufacturer machine
scripts (WPC.vbs, sam.vbs, s11.vbs, zac.vbs and the rest), and the editor's
completion parser reads core.vbs over the same search order
(codeview.cpp:3233-3247, standalone/cmake/CMakeLists_gl-linux-x64.txt:698).
The same four roots are handed to table scripts as the UserDirectory,
TablesDirectory, MusicDirectory and ScriptsDirectory properties, each falling
back from the install directory to the table folder to the preferences path
(src/parts/pintable.cpp:484-560).
The rest of the install tree is read the same way and ships with the binary:
assets/ holds BallEnv.exr, AODither.webp and EnvMap.webp (pin3d.cpp:475-477),
the bumper and kicker textures (src/parts/bumper.cpp:246-290,
src/parts/kicker.cpp:273-319), TableSizes.csv, which the live UI reads to
guess the glass position of a table that does not declare one
(src/core/TableDB.cpp:11-14, LiveUI.cpp:1705-1706), vpx.html for the built-in
web server (standalone/inc/webserver/WebServer.cpp:32) and
Default_gamecontrollerdb.txt; shader10.8.0/ holds the .glfx and .fxh sources
compiled at runtime (src/renderer/Shader.cpp:1419); flexdmd/ holds the bitmap
fonts UltraDMD asks for by resource name, the FlexDMD.Resources. prefix being
stripped before the lookup (standalone/inc/flexdmd/UltraDMD.cpp:31-40,
standalone/inc/flexdmd/AssetManager.cpp:84-90,232).
Two parts of that tree ship without a reader on this target. The four starter
tables in assets/, blankTable.vpx, exampleTable.vpx, lightSeqTable.vpx and
strippedTable.vpx, are loaded only by InitBuiltinTable, whose body is one
`#ifndef __STANDALONE__` block (src/parts/pintable.cpp:1641-1663), and
docs/Changelog.txt is read by dialogs/AboutDialog.cpp:27-31, which is not in
the standalone source list at all.
PinMAME is where the emulation happens. Tables that recreate a real solid
state machine hand a ROM name to the controller, which resolves its root as
the pinmame folder beside the table, else the PinMAMEPath setting, else
$HOME/.pinmame (standalone/inc/vpinmame/VPinMAMEController.cpp:165-180). libpinmame then hangs roms,
nvram, samples, cfg, hi, inp, memcard and sta off that root
(pinmame src/libpinmame/libpinmame.cpp:816-823). Every ROM set is a game, one
zip per machine; PinMAME declares no BIOS root set anywhere in its tree, and
carries neither GAME_IS_BIOS_ROOT nor ROM_SYSTEM_BIOS, so nothing in the ROM
path is shared between machines.
Three shared data files sit outside that per-machine content and are listed
below. Two more that the MAME lineage would suggest are unreachable here. The
mechanical sample set named by pinmame_sample_names, "*pinmame" followed by
eighteen .wav members (pinmame src/wpc/wpcsam.c:31-57), is dead twice over:
readsamples returns before opening anything unless options.use_samples is set
(pinmame src/common.c:271), the two files that register that option live in
src/windows/config.c and src/unix/sound.c and neither is in the libpinmame
source list, and PinmameSetConfig zeroes the whole options struct
(pinmame src/libpinmame/libpinmame.cpp:807); independently, SAMPLESINTERFACE
is defined at pinmame src/wpc/wpcsam.h:23 and no driver in the tree
references it. history.dat and mameinfo.dat (pinmame src/datafile.c:619-623,
649-653) are read only by displayhistory, a page of the MAME on-screen menu
(pinmame src/usrintrf.c:2846-2851), and by the listing path in
pinmame src/info.c:820 which libpinmame never calls; VPX passes NULL for
fn_IsKeyPressed, the thirteenth member of PinmameConfig
(standalone/inc/vpinmame/VPinMAMEController.cpp:145-160, pinmame src/libpinmame/libpinmame.h:418-433),
so osd_is_key_pressed always answers 0
(pinmame src/libpinmame/libpinmame.cpp:355-361) and the menu cannot be opened.
The pinmame observations were read at f102dc6cce7eb51e64427dd0b52bed37dbd2adea.
files:
- name: gamecontrollerdb.txt
system: vpinball
category: game_data
required: false
description: "SDL game controller mappings applied at input init"
source_ref: "pininput.cpp:1027-1043"
note: >-
Read from the preferences path. When it is absent the install copy at
assets/Default_gamecontrollerdb.txt is copied there first, and a missing
source only logs. SDL_GameControllerAddMappingsFromFile returns a count
that is logged and never acted on, so neither an absent nor an unparsable
file stops startup; SDL keeps its built-in mappings. Standalone reads
controllers through the SDL game controller layer rather than the joystick
layer unless GamepadOverride is set to 0, which is what makes this file
the place a pinball cabinet's encoder gets described.
- name: hiscore.dat
system: vpinball
category: game_data
required: false
description: "MAME high score memory map database, read once per machine start"
source_ref: "pinmame src/hiscore.c:18,223-230, pinmame src/cpuexec.c:332-334,393,1755"
note: >-
hs_open is called unconditionally at the top of cpu_run for every PinMAME
machine, and the whole body sits behind `if (f)`, so an absent file is a
no-op. It resolves to a bare filename against the working directory, which
is the table's own folder: libpinmame sets paths for eight file types and
FILETYPE_HIGHSCORE_DB is not among them, and the option table that would
supply a default is linked only by the Windows COM build
(pinmame src/libpinmame/libpinmame.cpp:816-823,
pinmame src/libpinmame/fileio.c:140, pinmame src/win32com/VPinMAMEConfig.cpp:127).
- name: cheat.dat
system: vpinball
category: game_data
required: false
description: "MAME cheat database, read when the per-ROM ini enables cheats"
source_ref: "pinmame src/cheat.c:8434,8602-8614, pinmame src/mame.c:578-583, standalone/inc/vpinmame/VPinMAMEController.cpp:295-321"
note: >-
Off by default: PinmameSetConfig zeroes options, and VPX only turns it on
from the `cheat` key of <pinmame root>/ini/<romname>.ini, which it also
rewrites on every run. With it on, InitCheat loads the database and an
absent file leaves the menu showing "cheat database not found"
(pinmame src/cheat.c:2463). Same bare-filename resolution as hiscore.dat.
analysis:
shipped_with_the_binary:
note: >-
Copied into the build output next to the executable and installed as one
unit by every distribution, so they arrive with the emulator rather than
being sourced separately.
source_ref: "standalone/cmake/CMakeLists_gl-linux-x64.txt:695-720"
entries:
- what: "scripts/, the .vbs library tables include"
source_ref: "src/parts/pintable.cpp:470-480, main.h:118-119, main.cpp:890-892, codeview.cpp:3233-3247"
- what: "assets/, textures, TableSizes.csv, vpx.html, the two defaults"
source_ref: "pin3d.cpp:475-477, src/parts/bumper.cpp:246-290, src/parts/kicker.cpp:273-319, src/core/TableDB.cpp:11-14, LiveUI.cpp:1705-1706, standalone/inc/webserver/WebServer.cpp:32"
- what: "shader10.8.0/, .glfx and .fxh compiled at runtime"
source_ref: "src/renderer/Shader.cpp:1419"
- what: "flexdmd/, the bitmap fonts UltraDMD names as FlexDMD.Resources.*"
source_ref: "standalone/inc/flexdmd/UltraDMD.cpp:31-40, standalone/inc/flexdmd/AssetManager.cpp:84-90,232"
- what: "user/ and tables/, the two roots exposed to table scripts as directory properties"
source_ref: "src/parts/pintable.cpp:484-521"
shipped_without_a_reader:
note: "Copied into the build output but unreachable in the standalone binary"
entries:
- what: "assets/blankTable.vpx, exampleTable.vpx, lightSeqTable.vpx, strippedTable.vpx"
source_ref: "src/parts/pintable.cpp:1641-1663"
note: "InitBuiltinTable is one #ifndef __STANDALONE__ block; the editor's New Table entries are the only callers."
- what: "docs/Changelog.txt"
source_ref: "dialogs/AboutDialog.cpp:27-31, standalone/cmake/CMakeLists_gl-linux-x64.txt:52-693"
note: "The About dialog is not in the standalone source list."
user_supplied_paths:
note: "Per table, keyed on the table folder or the ROM name, with no fixed filename"
entries:
- what: "PinMAME ROM sets, <pinmame root>/roms/<romname>.zip"
source_ref: "standalone/inc/vpinmame/VPinMAMEController.cpp:165-180, pinmame src/libpinmame/libpinmame.cpp:816"
note: >-
One zip per machine. The root is the pinmame folder beside the table
when present, else the PinMAMEPath setting, else $HOME/.pinmame;
Batocera patches that last fallback to <prefpath>/pinmame.
- what: "backglass, <table basename>.directb2s"
source_ref: "standalone/inc/b2s/forms/FormBackglass.cpp:372-415"
note: "Version-checked against the B2S server on load; absence only warns."
- what: "Serum colorizations, <pinmame root>/AltColor/"
source_ref: "standalone/inc/vpinmame/VPinMAMEController.cpp:55-59"
note: "Handed to libdmdutil as a path when the AltColor setting is on and the directory exists."
- what: "alternative sound packages, under the PinMAME root by ROM name"
source_ref: "standalone/inc/vpinmame/VPinMAMEController.cpp:336-338"
- what: "PUP video packs, <table folder>/pupvideos"
source_ref: "standalone/inc/pup/PUPManager.cpp:12, standalone/inc/vpinmame/VPinMAMEController.cpp:61-65"
- what: "table music, music/ beside the install, the table or the preferences path"
source_ref: "src/audio/audioplayer.cpp:75-77, src/parts/pintable.cpp:524-545"
- what: "table sidecars, the .vbs script override and the per-table .ini"
source_ref: "src/parts/pintable.cpp:704,794"
generated_files:
- what: "VPinballX.ini, the settings file"
source_ref: "main.cpp:901-914"
note: >-
Created on first run under the preferences path, or read from beside the
binary when one is there. Batocera seeds it from
assets/Default_VPinballX.ini and rewrites it before every launch.
- what: "VPReg.ini, per-table settings; vpinball.log"
source_ref: "Logger.cpp:58, standalone/README.md:512-534"
- what: "PinMAME state: nvram/, cfg/, hi/, inp/, memcard/, sta/ and ini/"
source_ref: "pinmame src/libpinmame/libpinmame.cpp:817-823, standalone/inc/vpinmame/VPinMAMEController.cpp:186-198"
note: "The ini directory is created when missing; the others are written by PinMAME as the machine runs."
+12 -3
View File
@@ -4,7 +4,7 @@
"platform": "batocera",
"display_name": "Batocera",
"version": "1.0",
"generated": "2026-08-08T09:27:23Z",
"generated": "2026-08-08T15:53:07Z",
"base_destination": "bios",
"detect": [
{
@@ -236,8 +236,8 @@
}
}
],
"total_files": 1599,
"total_size": 2866042839,
"total_files": 1600,
"total_size": 2868139991,
"files": [
{
"dest": "panafz1.bin",
@@ -12241,6 +12241,15 @@
"Clock Signal (CLK)"
]
},
{
"dest": "Triforce/segaboot.gcm",
"sha1": "7297a11be143011ceb75a0720f96855003415a5d",
"size": 2097152,
"repo_path": "bios/Sega/Triforce/segaboot.gcm",
"cores": [
"Dolphin"
]
},
{
"dest": "GBA/gba_bios.bin",
"sha1": "300c20df6731a33952ded8c436f7f186d25d3492",
+12 -3
View File
@@ -4,7 +4,7 @@
"platform": "emudeck",
"display_name": "EmuDeck",
"version": "1.0",
"generated": "2026-08-08T08:00:05Z",
"generated": "2026-08-08T15:53:16Z",
"base_destination": "bios",
"detect": [
{
@@ -249,8 +249,8 @@
}
}
],
"total_files": 525,
"total_size": 1770429115,
"total_files": 526,
"total_size": 1772526267,
"files": [
{
"dest": "colecovision.rom",
@@ -1066,6 +1066,15 @@
"Dolphin"
]
},
{
"dest": "Triforce/segaboot.gcm",
"sha1": "7297a11be143011ceb75a0720f96855003415a5d",
"size": 2097152,
"repo_path": "bios/Sega/Triforce/segaboot.gcm",
"cores": [
"Dolphin"
]
},
{
"dest": "GBA/gba_bios.bin",
"sha1": "300c20df6731a33952ded8c436f7f186d25d3492",
+12 -3
View File
@@ -4,7 +4,7 @@
"platform": "lakka",
"display_name": "Lakka",
"version": "1.0",
"generated": "2026-08-08T09:27:56Z",
"generated": "2026-08-08T15:53:41Z",
"base_destination": "system",
"detect": [
{
@@ -15,8 +15,8 @@
}
],
"standalone_copies": [],
"total_files": 1684,
"total_size": 4207511677,
"total_files": 1685,
"total_size": 4209608829,
"files": [
{
"dest": "3do_arcade_saot.bin",
@@ -4739,6 +4739,15 @@
"DirectXBox"
]
},
{
"dest": "Triforce/segaboot.gcm",
"sha1": "7297a11be143011ceb75a0720f96855003415a5d",
"size": 2097152,
"repo_path": "bios/Sega/Triforce/segaboot.gcm",
"cores": [
"Dolphin"
]
},
{
"dest": "Wii/shared2/sys/SYSCONF",
"sha1": "3256c026284a24fb99d2ec1558d95db3b5dcc2e9",
+12 -3
View File
@@ -4,7 +4,7 @@
"platform": "recalbox",
"display_name": "Recalbox",
"version": "1.0",
"generated": "2026-08-08T11:34:11Z",
"generated": "2026-08-08T15:53:48Z",
"base_destination": "bios",
"detect": [
{
@@ -236,8 +236,8 @@
}
}
],
"total_files": 1186,
"total_size": 2495283065,
"total_files": 1187,
"total_size": 2497380217,
"files": [
{
"dest": "3do/panafz1.bin",
@@ -3718,6 +3718,15 @@
"Dolphin"
]
},
{
"dest": "Triforce/segaboot.gcm",
"sha1": "7297a11be143011ceb75a0720f96855003415a5d",
"size": 2097152,
"repo_path": "bios/Sega/Triforce/segaboot.gcm",
"cores": [
"Dolphin"
]
},
{
"dest": "Wii/shared2/sys/SYSCONF",
"sha1": "3256c026284a24fb99d2ec1558d95db3b5dcc2e9",
+12 -3
View File
@@ -4,7 +4,7 @@
"platform": "retroarch",
"display_name": "RetroArch",
"version": "1.0",
"generated": "2026-08-08T09:27:56Z",
"generated": "2026-08-08T15:53:41Z",
"base_destination": "system",
"detect": [
{
@@ -254,8 +254,8 @@
}
}
],
"total_files": 1684,
"total_size": 4207511677,
"total_files": 1685,
"total_size": 4209608829,
"files": [
{
"dest": "3do_arcade_saot.bin",
@@ -4978,6 +4978,15 @@
"DirectXBox"
]
},
{
"dest": "Triforce/segaboot.gcm",
"sha1": "7297a11be143011ceb75a0720f96855003415a5d",
"size": 2097152,
"repo_path": "bios/Sega/Triforce/segaboot.gcm",
"cores": [
"Dolphin"
]
},
{
"dest": "Wii/shared2/sys/SYSCONF",
"sha1": "3256c026284a24fb99d2ec1558d95db3b5dcc2e9",
+12 -3
View File
@@ -4,7 +4,7 @@
"platform": "retrobat",
"display_name": "RetroBat",
"version": "1.0",
"generated": "2026-08-08T08:00:44Z",
"generated": "2026-08-08T15:53:55Z",
"base_destination": "bios",
"detect": [
{
@@ -235,8 +235,8 @@
}
}
],
"total_files": 1232,
"total_size": 3279906783,
"total_files": 1233,
"total_size": 3282003935,
"files": [
{
"dest": "panafz1.bin",
@@ -8985,6 +8985,15 @@
"Dolphin"
]
},
{
"dest": "Triforce/segaboot.gcm",
"sha1": "7297a11be143011ceb75a0720f96855003415a5d",
"size": 2097152,
"repo_path": "bios/Sega/Triforce/segaboot.gcm",
"cores": [
"Dolphin"
]
},
{
"dest": "GBA/gba_bios.bin",
"sha1": "300c20df6731a33952ded8c436f7f186d25d3492",
+12 -3
View File
@@ -4,7 +4,7 @@
"platform": "rocknix",
"display_name": "ROCKNIX",
"version": "1.0",
"generated": "2026-08-08T11:34:39Z",
"generated": "2026-08-08T15:54:15Z",
"base_destination": "bios",
"detect": [
{
@@ -16,8 +16,8 @@
}
],
"standalone_copies": [],
"total_files": 1548,
"total_size": 4070944579,
"total_files": 1549,
"total_size": 4073041731,
"files": [
{
"dest": "xemu/bios/mcpx_1.0.bin",
@@ -2134,6 +2134,15 @@
"Dolphin"
]
},
{
"dest": "Triforce/segaboot.gcm",
"sha1": "7297a11be143011ceb75a0720f96855003415a5d",
"size": 2097152,
"repo_path": "bios/Sega/Triforce/segaboot.gcm",
"cores": [
"Dolphin"
]
},
{
"dest": "Wii/shared2/sys/SYSCONF",
"sha1": "3256c026284a24fb99d2ec1558d95db3b5dcc2e9",
+12 -3
View File
@@ -4,7 +4,7 @@
"platform": "romm",
"display_name": "RomM",
"version": "1.0",
"generated": "2026-08-08T09:28:33Z",
"generated": "2026-08-08T15:54:17Z",
"base_destination": "bios",
"detect": [
{
@@ -14,8 +14,8 @@
}
],
"standalone_copies": [],
"total_files": 544,
"total_size": 1488406530,
"total_files": 545,
"total_size": 1490503682,
"files": [
{
"dest": "3do/3do_arcade_saot.bin",
@@ -2725,6 +2725,15 @@
"Dolphin"
]
},
{
"dest": "ngc/Triforce/segaboot.gcm",
"sha1": "7297a11be143011ceb75a0720f96855003415a5d",
"size": 2097152,
"repo_path": "bios/Sega/Triforce/segaboot.gcm",
"cores": [
"Dolphin"
]
},
{
"dest": "ngc/Wii/shared2/sys/SYSCONF",
"sha1": "3256c026284a24fb99d2ec1558d95db3b5dcc2e9",
+16 -4
View File
@@ -250,7 +250,7 @@ nav:
- vitaQuakeII: emulators/vitaquake2.md
- yabasanshiro: emulators/yabasanshiro.md
- Yuzu: emulators/yuzu.md
- Community forks (114):
- Community forks (117):
- EightyOne: emulators/81.md
- a5200: emulators/a5200.md
- ACE-DL: emulators/ace-dl.md
@@ -335,8 +335,11 @@ nav:
- RACE (Neo Geo Pocket): emulators/race.md
- REminiscence: emulators/reminiscence.md
- RetroDream: emulators/retrodream.md
- Rosalie's Mupen GUI: emulators/rosalies-mupen-gui.md
- SAME CDi: emulators/same_cdi.md
- SDL2TRS: emulators/sdl2trs.md
- SimCoupe: emulators/simcp.md
- simple64: emulators/simple64.md
- Suyu: emulators/suyu.md
- swanstation: emulators/swanstation.md
- Syobon Action: emulators/syobonaction.md
@@ -408,7 +411,7 @@ nav:
- MicroW8: emulators/uw8.md
- uzem: emulators/uzem.md
- VirtualXT: emulators/virtualxt.md
- Game engines (27):
- Game engines (31):
- boom3: emulators/boom3.md
- Cannonball: emulators/cannonball.md
- ChaiLove: emulators/chailove.md
@@ -427,16 +430,20 @@ nav:
- OpenLara: emulators/openlara.md
- OpenTyrian: emulators/opentyrian.md
- PrBoom: emulators/prboom.md
- PrBoom+: emulators/prboom-plus.md
- PuzzleScript: emulators/puzzlescript.md
- Retro8: emulators/retro8.md
- ruffle: emulators/ruffle.md
- ScummVM: emulators/scummvm.md
- solarus: emulators/solarus.md
- Super Bros War: emulators/superbroswar.md
- TIC-80: emulators/tic80.md
- TyrQuake: emulators/tyrquake.md
- visual-pinball: emulators/visual-pinball.md
- WASM-4: emulators/wasm4.md
- XRick: emulators/xrick.md
- Zelda Classic v2.10: emulators/zc210.md
- Enhanced forks (22):
- Enhanced forks (23):
- A7800: emulators/a7800.md
- AdvanceMAME: emulators/advancemame.md
- bsnes-hd beta: emulators/bsnes_hd_beta.md
@@ -459,6 +466,7 @@ nav:
- PCSX2x6: emulators/pcsx2x6.md
- PrimeHack: emulators/primehack.md
- SMS Plus GX: emulators/smsplus.md
- Triforce: emulators/triforce.md
- Frozen snapshots (33):
- bnes: emulators/bnes.md
- bsnes 2014: emulators/bsnes2014.md
@@ -502,7 +510,7 @@ nav:
- Launchers (2):
- Dolphin Launcher: emulators/dolphin_launcher.md
- Parallel Launcher: emulators/parallel-launcher.md
- Other (33):
- Other (37):
- ares: emulators/ares.md
- Basilisk II: emulators/basiliskii.md
- Beetle GBA (Mednafen): emulators/beetle_gba.md
@@ -524,13 +532,17 @@ nav:
- Model 2 Emulator: emulators/model2.md
- openMSX: emulators/openmsx.md
- Oricutron: emulators/oricutron.md
- puNES: emulators/punes.md
- Redream: emulators/redream.md
- Ryujinx: emulators/ryujinx.md
- shadps4: emulators/shadps4.md
- SheepShaver: emulators/sheepshaver.md
- Supermodel: emulators/supermodel.md
- SUPER ZSNES: emulators/superzsnes.md
- ti99sim: emulators/ti99sim.md
- tsugaru: emulators/tsugaru.md
- VBA-M: emulators/vba_m.md
- veesem: emulators/veesem.md
- VICE: emulators/vice.md
- Vita3K: emulators/vita3k.md
- x16emu: emulators/x16emu.md
+17 -1
View File
@@ -129,7 +129,23 @@
{ "type": "object" }
]
},
"region": { "type": ["string", "array"] },
"region": {
"description": "Region the emulator code selects this file for, never the region of the dump.",
"type": "array",
"items": {
"enum": [
"world",
"north-america", "canada",
"latin-america", "brazil", "mexico", "argentina",
"europe", "uk", "france", "germany", "italy", "spain",
"netherlands", "portugal", "greece", "poland", "russia",
"sweden", "norway", "denmark", "finland",
"asia", "japan", "south-korea", "china", "taiwan",
"hong-kong", "singapore", "india", "asia-ntsc", "asia-pal",
"oceania", "australia", "new-zealand"
]
}
},
"contents": { "type": "array", "items": { "type": "object" } },
"source_ref": {
"description": "A dict splits core from upstream when the two diverge.",
+12 -12
View File
@@ -164,9 +164,16 @@ def md5_composite(filepath: str | Path) -> str:
return result
def parse_md5_list(raw: str) -> list[str]:
"""Parse comma-separated MD5 string into normalized lowercase list."""
return [m.strip().lower() for m in raw.split(",") if m.strip()] if raw else []
def parse_md5_list(raw: str | list | None) -> list[str]:
"""Normalize an md5 field into a lowercase list.
Platform YAMLs carry Recalbox multi-hash as one comma-separated string,
emulator profiles carry a YAML list. Both reach here.
"""
if not raw:
return []
values = raw if isinstance(raw, list) else str(raw).split(",")
return [str(m).strip().lower() for m in values if str(m).strip()]
_shared_yml_cache: dict[str, dict] = {}
@@ -436,11 +443,6 @@ def resolve_local_file(
exact, zip_exact, hash_mismatch, not_found.
"""
sha1 = file_entry.get("sha1")
md5_field = file_entry.get("md5", "") or ""
if isinstance(md5_field, list):
md5_raw = ",".join(str(m) for m in md5_field)
else:
md5_raw = str(md5_field)
name = file_entry.get("name", "")
zipped_file = file_entry.get("zipped_file")
aliases = file_entry.get("aliases", [])
@@ -461,9 +463,7 @@ def resolve_local_file(
if hint_base and hint_base not in names_to_try:
names_to_try.append(hint_base)
md5_list = (
[m.strip().lower() for m in md5_raw.split(",") if m.strip()] if md5_raw else []
)
md5_list = parse_md5_list(file_entry.get("md5"))
files_db = db.get("files", {})
by_md5 = db.get("indexes", {}).get("by_md5", {})
by_name = db.get("indexes", {}).get("by_name", {})
@@ -504,7 +504,7 @@ def resolve_local_file(
# declared size must confirm the match.
crc_raw = str(file_entry.get("crc32", "") or "").strip().lower()
declared_size = file_entry.get("size")
if crc_raw and declared_size and not zipped_file and not md5_raw:
if crc_raw and declared_size and not zipped_file and not md5_list:
by_crc32 = db.get("indexes", {}).get("by_crc32", {})
match = by_crc32.get(crc_raw)
if match and match in files_db:
+19 -5
View File
@@ -25,6 +25,7 @@ from common import (
load_emulator_profiles,
load_platform_config,
name_match_size_ok,
parse_md5_list,
require_yaml,
)
@@ -206,6 +207,7 @@ def cross_reference(
by_name = db.get("indexes", {}).get("by_name", {})
by_name_lower = {k.lower(): k for k in by_name}
by_md5 = db.get("indexes", {}).get("by_md5", {})
by_crc32 = db.get("indexes", {}).get("by_crc32", {})
by_path_suffix = db.get("indexes", {}).get("by_path_suffix", {})
db_files = db.get("files", {})
report = {}
@@ -331,13 +333,20 @@ def cross_reference(
path_field, by_name, by_name_lower,
data_names, by_path_suffix, f, db_files,
)
# Try the alternate names the emulator accepts, like
# resolve_local_file does
if source is None:
for alias in f.get("aliases") or []:
source = _resolve_source(
alias, by_name, by_name_lower,
data_names, by_path_suffix, f, db_files,
)
if source is not None:
break
# Try MD5 hash match
if source is None:
md5_raw = f.get("md5", "")
if md5_raw:
for md5_val in md5_raw.split(","):
md5_val = md5_val.strip().lower()
if md5_val and by_md5.get(md5_val):
for md5_val in parse_md5_list(f.get("md5")):
if by_md5.get(md5_val):
source = "bios"
break
# Try SHA1 hash match
@@ -345,6 +354,11 @@ def cross_reference(
sha1 = f.get("sha1", "")
if sha1 and sha1 in db_files:
source = "bios"
# Try CRC32 hash match
if source is None:
crc32 = str(f.get("crc32", "")).lower()
if crc32 and by_crc32.get(crc32):
source = "bios"
if source is None:
source = "missing"
+294 -19
View File
@@ -46,9 +46,11 @@ from common import (
load_database,
load_emulator_profiles,
load_platform_config,
parse_md5_list,
require_yaml,
resolve_local_file,
)
import region as region_mod
from deterministic_zip import rebuild_zip_deterministic
from validation import (
_build_validation_index,
@@ -291,15 +293,7 @@ def resolve_file(
name = file_entry.get("name", "")
sha1 = file_entry.get("sha1")
first_sha1 = (sha1[0] if sha1 else "") if isinstance(sha1, list) else (sha1 or "")
md5_raw = file_entry.get("md5", "")
if isinstance(md5_raw, list):
md5_list = [str(m).strip().lower() for m in md5_raw if str(m).strip()]
else:
md5_list = (
[m.strip().lower() for m in md5_raw.split(",") if m.strip()]
if md5_raw
else []
)
md5_list = parse_md5_list(file_entry.get("md5"))
first_md5 = md5_list[0] if md5_list else ""
cached = fetch_large_file(name, expected_sha1=first_sha1, expected_md5=first_md5)
if cached:
@@ -777,6 +771,8 @@ def _build_readme(
num_systems: int,
source: str = "full",
contributors: list[dict] | None = None,
regions: list[str] | None = None,
fallback_systems: list[str] | None = None,
) -> str:
"""Build a personalized step-by-step README for each platform pack."""
sep = "=" * 50
@@ -952,12 +948,22 @@ def _build_readme(
),
)
if regions:
region_help = (
" - Wrong region? This pack was filtered. Only the\n"
" best-matching BIOS was kept per system. Use the\n"
" unfiltered pack to play imports.\n"
)
else:
region_help = (
" - Wrong region? Some systems have regional BIOS\n"
" variants (USA/EUR/JAP). All are included.\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"
f"{region_help}"
" - Need help? https://github.com/Abdess/retrobios/issues\n\n"
f"{sep}\n"
f" https://github.com/Abdess/retrobios\n"
@@ -980,6 +986,30 @@ def _build_readme(
" Independent of platform scraper accuracy.\n\n"
)
region_info = ""
if regions:
pretty = ", ".join(
" ".join(w.title() for w in slug.split("-")) for slug in regions
)
region_info = (
"PACK TYPE: Region Filtered\n\n"
f" Region priority: {pretty}\n\n"
" Only the best-matching BIOS was kept for each system.\n"
)
if fallback_systems:
listed = "\n".join(f" {s}" for s in fallback_systems)
region_info += (
"\n These systems have no BIOS in those regions, so all\n"
" of theirs were kept:\n"
f"{listed}\n"
)
region_info += (
"\n This shrinks the pack. It does not change how cores pick\n"
" a BIOS: most already select per region from fixed filename\n"
" lists driven by the game's region. Loading imports from\n"
" another region may need the unfiltered pack.\n\n"
)
credits = ""
if contributors:
credits = "\nCONTRIBUTORS\n\n"
@@ -988,7 +1018,7 @@ def _build_readme(
credits += f" @{username}\n"
credits += "\n"
return header + source_info + guide + credits + footer
return header + source_info + region_info + guide + credits + footer
def _build_agnostic_rename_readme(
@@ -1028,6 +1058,7 @@ def generate_pack(
precomputed_extras: list[dict] | None = None,
source: str = "full",
flatten: bool = True,
regions: list[str] | None = None,
) -> str | None:
"""Generate a ZIP pack for a platform.
@@ -1045,6 +1076,7 @@ def generate_pack(
version_tag = f"_{version.replace(' ', '')}" if version else ""
req_tag = "_Required" if required_only else ""
source_tag = {"platform": "_Platform", "truth": "_Truth"}.get(source, "")
region_tag_str = f"_{region_mod.region_tag(regions)}" if regions else ""
sys_tag = ""
if system_filter:
@@ -1059,7 +1091,7 @@ def generate_pack(
display_parts.append("_".join(p.title() for p in parts if p))
sys_tag = "_" + "_".join(display_parts)
zip_name = f"{platform_display.replace(' ', '_')}{version_tag}{source_tag}{req_tag}_BIOS_Pack{sys_tag}.zip"
zip_name = f"{platform_display.replace(' ', '_')}{version_tag}{source_tag}{region_tag_str}{req_tag}_BIOS_Pack{sys_tag}.zip"
zip_path = os.path.join(output_dir, zip_name)
os.makedirs(output_dir, exist_ok=True)
@@ -1158,6 +1190,55 @@ def generate_pack(
if best is not None:
preferred_entries[full] = id(best)
# Region selection is decided once, over both the platform baseline and the
# core extras, so the two phases below consult a single set. Grouping uses a
# dedicated extras pass with an empty seen set: it only needs group
# membership, never destinations, and a superset of members is the safe
# direction. Runs only when --region is given.
region_drops: set[str] = set()
region_fallbacks: list[str] = []
if regions:
region_index = region_mod.build_region_index(emu_profiles or {})
region_groups: dict[str, list[tuple[str, str]]] = {}
for sys_id, system in pack_systems.items():
members = region_groups.setdefault(sys_id, [])
for file_entry in system.get("files", []):
dest = _sanitize_path(
file_entry.get("destination", file_entry.get("name", ""))
)
if dest:
members.append((dest, file_entry.get("name", "")))
if source != "platform":
emu_systems = {
n: list(p.get("systems", []))
for n, p in (emu_profiles or {}).items()
}
for fe in _collect_emulator_extras(
config,
emulators_dir,
db,
set(),
base_dest,
emu_profiles,
target_cores=target_cores,
include_all=(source == "truth"),
):
dest = _sanitize_path(fe.get("destination", fe.get("name", "")))
if not dest:
continue
for sys_id in emu_systems.get(
fe.get("source_emulator", ""), ["_extras"]
):
region_groups.setdefault(sys_id, []).append(
(dest, fe.get("name", ""))
)
region_drops = region_mod.resolve_region_drops(
region_groups, region_index, regions
)
region_fallbacks = region_mod.fallback_groups(
region_groups, region_index, regions
)
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
if source != "truth":
for sys_id, system in sorted(pack_systems.items()):
@@ -1165,6 +1246,8 @@ def generate_pack(
if required_only and file_entry.get("required") is False:
continue
dest = _sanitize_path(file_entry.get("destination", file_entry["name"]))
if region_drops and dest in region_drops:
continue
if not dest:
# EmuDeck-style entries (system:md5 whitelist, no filename).
fkey = f"{sys_id}/{file_entry.get('name', '')}"
@@ -1473,6 +1556,8 @@ def generate_pack(
if required_only and fe.get("required") is False:
continue
dest = _sanitize_path(fe.get("destination", fe["name"]))
if region_drops and dest in region_drops:
continue
if not dest:
continue
# Core extras: _collect_emulator_extras already adjusted
@@ -1572,6 +1657,8 @@ def generate_pack(
platform_name, platform_display, base_dest, total_files, num_systems,
source=source,
contributors=_pack_registry.get(platform_name, {}).get("contributed_by", []),
regions=regions,
fallback_systems=region_fallbacks,
)
zf.writestr("README.txt", readme_text)
@@ -1725,6 +1812,7 @@ def generate_emulator_pack(
standalone: bool = False,
zip_contents: dict | None = None,
required_only: bool = False,
regions: list[str] | None = None,
) -> str | None:
"""Generate a ZIP pack for specific emulator profiles."""
all_profiles = load_emulator_profiles(emulators_dir, skip_aliases=False)
@@ -1768,10 +1856,29 @@ def generate_emulator_pack(
# ZIP naming
display_names = [p.get("emulator", n).replace(" ", "") for n, p in selected]
zip_name = "_".join(display_names) + "_BIOS_Pack.zip"
region_tag_str = f"_{region_mod.region_tag(regions)}" if regions else ""
zip_name = "_".join(display_names) + f"{region_tag_str}_BIOS_Pack.zip"
zip_path = os.path.join(output_dir, zip_name)
os.makedirs(output_dir, exist_ok=True)
# One group per profile: a core's regional alternatives compete only with
# each other. Decided before the ZIP is opened so the loop below reads a
# single set.
region_drops: set[str] = set()
if regions:
region_index = region_mod.build_region_index(dict(selected))
region_groups: dict[str, list[tuple[str, str]]] = {}
for emu_name, profile in sorted(selected):
structure = profile.get("pack_structure")
members = region_groups.setdefault(emu_name, [])
for fe in filter_files_by_mode(profile.get("files", []), standalone):
dest = _resolve_destination(fe, structure, standalone)
if dest:
members.append((dest, fe.get("name", "")))
region_drops = region_mod.resolve_region_drops(
region_groups, region_index, regions
)
total_files = 0
missing_files = []
seen_destinations: set[str] = set()
@@ -1888,6 +1995,8 @@ def generate_emulator_pack(
dest = _resolve_destination(fe, pack_structure, standalone)
if not dest:
continue
if region_drops and dest in region_drops:
continue
if dest.lower() in seen_lower:
continue
@@ -1989,6 +2098,7 @@ def generate_system_pack(
standalone: bool = False,
zip_contents: dict | None = None,
required_only: bool = False,
regions: list[str] | None = None,
) -> str | None:
"""Generate a ZIP pack for all emulators supporting given system IDs."""
profiles = load_emulator_profiles(emulators_dir)
@@ -2036,6 +2146,7 @@ def generate_system_pack(
standalone,
zip_contents,
required_only=required_only,
regions=regions,
)
if result:
# Rename to system-based name
@@ -2092,6 +2203,7 @@ def generate_split_packs(
target_cores: set[str] | None = None,
required_only: bool = False,
source: str = "full",
regions: list[str] | None = None,
) -> list[str]:
"""Generate split packs (one ZIP per system or manufacturer)."""
config = load_platform_config(platform_name, platforms_dir)
@@ -2162,13 +2274,15 @@ def generate_split_packs(
system_filter=group_system_ids,
precomputed_extras=group_extras,
source=source,
regions=regions,
)
if zip_path:
version = config.get("version", config.get("dat_version", ""))
ver_tag = f"_{version.replace(' ', '')}" if version else ""
req_tag = "_Required" if required_only else ""
rgn_tag = f"_{region_mod.region_tag(regions)}" if regions else ""
safe_group = group_name.replace(" ", "_")
new_name = f"{platform_display.replace(' ', '_')}{ver_tag}{source_tag}{req_tag}_{safe_group}_BIOS_Pack.zip"
new_name = f"{platform_display.replace(' ', '_')}{ver_tag}{source_tag}{rgn_tag}{req_tag}_{safe_group}_BIOS_Pack.zip"
new_path = os.path.join(split_dir, new_name)
if new_path != zip_path:
os.rename(zip_path, new_path)
@@ -2399,6 +2513,8 @@ def _validate_args(args, parser):
parser.error("--manifest is incompatible with --emulator")
if args.manifest and args.split:
parser.error("--manifest is incompatible with --split")
if getattr(args, "region", None) and has_from_md5:
parser.error("--region and --from-md5 are mutually exclusive")
def _write_manifest_if_changed(path: str, manifest: dict) -> None:
@@ -2456,11 +2572,18 @@ def _run_manifest_mode(
emu_profiles=emu_profiles,
target_cores=tc,
source=source,
regions=getattr(args, "regions", None),
)
source_suffix = {"platform": "_platform", "truth": "_truth"}.get(source, "")
req_suffix = "_required" if required_only else ""
rgn = getattr(args, "regions", None)
region_suffix = (
f"_{region_mod.region_tag(rgn).lower()}" if rgn else ""
)
out_path = os.path.join(
args.output_dir, f"{representative}{source_suffix}{req_suffix}.json"
args.output_dir,
f"{representative}{source_suffix}{region_suffix}"
f"{req_suffix}.json",
)
_write_manifest_if_changed(out_path, manifest)
print(
@@ -2472,7 +2595,8 @@ def _run_manifest_mode(
if alias_plat != representative:
alias_path = os.path.join(
args.output_dir,
f"{alias_plat}{source_suffix}{req_suffix}.json",
f"{alias_plat}{source_suffix}{region_suffix}"
f"{req_suffix}.json",
)
alias_manifest = dict(manifest)
alias_manifest["platform"] = alias_plat
@@ -2518,6 +2642,8 @@ def _run_verify_packs(args):
sys.exit(1)
all_ok = True
verify_regions = getattr(args, "regions", None)
verify_profiles = load_emulator_profiles(args.emulators_dir)
for platform_name in platforms:
config = load_platform_config(platform_name, args.platforms_dir)
display = config.get("platform", platform_name).replace(" ", "_")
@@ -2561,6 +2687,43 @@ def _run_verify_packs(args):
os.path.join(extract_dir, base_dest)
)
region_drops: set[str] = set()
if verify_regions:
region_index = region_mod.build_region_index(verify_profiles)
region_groups: dict[str, list[tuple[str, str]]] = {}
for sys_id, sys_data in systems.items():
members = region_groups.setdefault(sys_id, [])
for fe in sys_data.get("files", []):
d = _sanitize_path(
fe.get("destination", fe.get("name", ""))
)
if d:
members.append((d, fe.get("name", "")))
# Core extras join the groups so a platform file dropped in
# favour of a better-ranked core file is not reported missing.
from verify import find_undeclared_files as _fud
emu_systems = {
n: list(p.get("systems", []))
for n, p in verify_profiles.items()
}
for u in _fud(
config, args.emulators_dir, verify_db, verify_profiles
):
if not u.get("in_repo"):
continue
raw = u.get("path") or u["name"]
d = _sanitize_path(
f"{raw}{u['name']}" if raw.endswith("/") else raw
)
if not d:
continue
for sid in emu_systems.get(u.get("emulator", ""), ["_extras"]):
region_groups.setdefault(sid, []).append((d, u["name"]))
region_drops = region_mod.resolve_region_drops(
region_groups, region_index, verify_regions
)
missing = []
hash_fail = []
ok = 0
@@ -2569,6 +2732,8 @@ def _run_verify_packs(args):
dest = fe.get("destination", fe.get("name", ""))
if not dest:
continue
if region_drops and _sanitize_path(dest) in region_drops:
continue
fp = (
os.path.join(extract_dir, base_dest, dest)
if base_dest and not is_flat
@@ -2733,6 +2898,7 @@ def _run_platform_packs(
target_cores=tc,
required_only=required_only,
source=source,
regions=getattr(args, "regions", None),
)
print(f" Split into {len(zip_paths)} packs")
else:
@@ -2751,6 +2917,7 @@ def _run_platform_packs(
required_only=required_only,
system_filter=system_filter,
source=source,
regions=getattr(args, "regions", None),
)
if not args.split and zip_path and aliases:
rep_cfg = load_platform_config(representative, args.platforms_dir)
@@ -2776,14 +2943,22 @@ def _run_platform_packs(
print("\nVerifying packs and generating manifests...")
skip_conf = bool(system_filter or args.split)
all_ok = verify_and_finalize_packs(
args.output_dir, db, skip_conformance=skip_conf, data_registry=data_registry
args.output_dir,
db,
skip_conformance=skip_conf,
data_registry=data_registry,
regions=getattr(args, "regions", None),
)
if args.split:
for entry in os.listdir(args.output_dir):
sub = os.path.join(args.output_dir, entry)
if os.path.isdir(sub) and entry.endswith("_Split"):
ok = verify_and_finalize_packs(
sub, db, skip_conformance=True, data_registry=data_registry
sub,
db,
skip_conformance=True,
data_registry=data_registry,
regions=getattr(args, "regions", None),
)
all_ok = all_ok and ok
if not all_ok:
@@ -2858,6 +3033,10 @@ def main():
help="Grouping for --split (default: system)",
)
parser.add_argument("--target", "-t", help="Hardware target (e.g., switch, rpi4)")
parser.add_argument(
"--region",
help="Region priority list, best first (e.g. us,eu,jp)",
)
parser.add_argument(
"--list-targets",
action="store_true",
@@ -2884,6 +3063,15 @@ def main():
)
args = parser.parse_args()
# Parsed before the quick-exit modes: --verify-packs returns early and
# still needs the region priority list to narrow its expectation.
args.regions = []
if args.region:
try:
args.regions = region_mod.parse_requested(args.region)
except ValueError as exc:
parser.error(str(exc))
# Quick-exit modes: --verify-packs alone = verify existing packs only
# Combined with --all-variants, generation runs first then verify
if args.verify_packs and not args.all_variants:
@@ -2975,6 +3163,7 @@ def main():
args.standalone,
zip_contents,
required_only=args.required_only,
regions=getattr(args, "regions", None),
):
sys.exit(1)
return
@@ -2991,6 +3180,7 @@ def main():
args.standalone,
zip_contents,
required_only=args.required_only,
regions=getattr(args, "regions", None),
):
sys.exit(1)
return
@@ -3112,6 +3302,7 @@ def generate_manifest(
emu_profiles: dict | None = None,
target_cores: set[str] | None = None,
source: str = "full",
regions: list[str] | None = None,
) -> dict:
"""Generate a JSON manifest for a platform (same resolution as generate_pack).
@@ -3157,6 +3348,45 @@ def generate_manifest(
manifest_files: list[dict] = []
total_size = 0
region_drops: set[str] = set()
if regions:
region_index = region_mod.build_region_index(emu_profiles)
region_groups: dict[str, list[tuple[str, str]]] = {}
for sys_id, system in pack_systems.items():
members = region_groups.setdefault(sys_id, [])
for file_entry in system.get("files", []):
d = _sanitize_path(
file_entry.get("destination", file_entry.get("name", ""))
)
if d:
members.append((d, file_entry.get("name", "")))
if source != "platform":
emu_systems = {
n: list(p.get("systems", [])) for n, p in emu_profiles.items()
}
for fe in _collect_emulator_extras(
config,
emulators_dir,
db,
set(),
base_dest,
emu_profiles,
target_cores=target_cores,
include_all=(source == "truth"),
):
d = _sanitize_path(fe.get("destination", fe.get("name", "")))
if not d:
continue
for sid in emu_systems.get(
fe.get("source_emulator", ""), ["_extras"]
):
region_groups.setdefault(sid, []).append(
(d, fe.get("name", ""))
)
region_drops = region_mod.resolve_region_drops(
region_groups, region_index, regions
)
# Phase 1: baseline files
if source != "truth":
for sys_id, system in sorted(pack_systems.items()):
@@ -3164,6 +3394,8 @@ def generate_manifest(
dest = _sanitize_path(file_entry.get("destination", file_entry["name"]))
if not dest:
continue
if region_drops and dest in region_drops:
continue
full_dest = f"{base_dest}/{dest}" if base_dest else dest
dedup_key = full_dest
@@ -3234,6 +3466,8 @@ def generate_manifest(
dest = _sanitize_path(fe.get("destination", fe["name"]))
if not dest:
continue
if region_drops and dest in region_drops:
continue
if extras_pfx:
if not dest.startswith(f"{extras_pfx}/"):
full_dest = f"{extras_pfx}/{dest}"
@@ -3703,9 +3937,13 @@ def verify_pack_against_platform(
db: dict | None = None,
emulators_dir: str = "emulators",
emu_profiles: dict | None = None,
regions: list[str] | None = None,
) -> tuple[bool, int, int, list[str]]:
"""Verify a pack ZIP against its platform config and core requirements.
A region priority list narrows the expectation to what the builder would
have packed, using the same selection function.
Checks:
1. Every baseline file declared by the platform exists in the ZIP
at the correct destination path
@@ -3729,6 +3967,37 @@ def verify_pack_against_platform(
if emu_profiles is None:
emu_profiles = load_emulator_profiles(emulators_dir)
region_drops: set[str] = set()
if regions:
region_index = region_mod.build_region_index(emu_profiles)
region_groups: dict[str, list[tuple[str, str]]] = {}
for sys_id, system in config.get("systems", {}).items():
members = region_groups.setdefault(sys_id, [])
for fe in system.get("files", []):
d = _sanitize_path(fe.get("destination", fe.get("name", "")))
if d:
members.append((d, fe.get("name", "")))
if db is not None:
from verify import find_undeclared_files as _fud
emu_systems = {
n: list(p.get("systems", [])) for n, p in emu_profiles.items()
}
for u in _fud(config, emulators_dir, db, emu_profiles):
if not u.get("in_repo"):
continue
raw = u.get("path") or u["name"]
d = _sanitize_path(
f"{raw}{u['name']}" if raw.endswith("/") else raw
)
if not d:
continue
for sys_id in emu_systems.get(u.get("emulator", ""), ["_extras"]):
region_groups.setdefault(sys_id, []).append((d, u["name"]))
region_drops = region_mod.resolve_region_drops(
region_groups, region_index, regions
)
with zipfile.ZipFile(zip_path, "r") as zf:
zip_set = set(zf.namelist())
zip_lower = {n.lower(): n for n in zip_set}
@@ -3779,6 +4048,8 @@ def verify_pack_against_platform(
dest = fe.get("destination", fe.get("name", ""))
if not dest:
continue
if region_drops and _sanitize_path(dest) in region_drops:
continue
expected = f"{base_dest}/{dest}" if base_dest and not is_flat else dest
baseline_checked += 1
@@ -3845,6 +4116,8 @@ def verify_pack_against_platform(
continue
raw_dest = u.get("path") or u["name"]
dest = f"{raw_dest}{u['name']}" if raw_dest.endswith("/") else raw_dest
if region_drops and _sanitize_path(dest) in region_drops:
continue
if extras_pfx and not (is_flat and extras_pfx == base_dest):
if not dest.startswith(f"{extras_pfx}/"):
full = f"{extras_pfx}/{dest}"
@@ -3889,6 +4162,7 @@ def verify_and_finalize_packs(
platforms_dir: str = "platforms",
skip_conformance: bool = False,
data_registry: dict | None = None,
regions: list[str] | None = None,
) -> bool:
"""Verify all packs, inject manifests, generate SHA256SUMS.
@@ -3953,6 +4227,7 @@ def verify_and_finalize_packs(
pname,
platforms_dir,
db=db,
regions=regions,
)
status = "OK" if p_ok else "FAILED"
print(
+3 -3
View File
@@ -31,6 +31,7 @@ from common import (
load_database,
load_emulator_profiles,
load_provenance_snapshots,
parse_md5_list,
require_yaml,
unique_emulator_profiles,
write_if_changed,
@@ -1479,9 +1480,8 @@ def generate_emulator_page(
return True
md5_raw = f.get("md5", "")
if md5_raw:
for md5_val in md5_raw.split(","):
md5_val = md5_val.strip().lower()
if md5_val and by_md5.get(md5_val):
for md5_val in parse_md5_list(md5_raw):
if by_md5.get(md5_val):
return True
sha1 = f.get("sha1", "")
if sha1 and sha1 in db_files:
+245
View File
@@ -0,0 +1,245 @@
"""Region vocabulary and ordered-priority selection for pack generation.
A file's region: value is the region the emulator code selects it for, not the
region of the dump. Signal standard has no field of its own; it survives only
inside slugs whose hardware register fuses the two axes (Saturn SMPC areas).
"""
from __future__ import annotations
WORLD = "world"
# Two levels only: super-region -> member territories.
REGION_TREE: dict[str, frozenset[str]] = {
"north-america": frozenset({"canada"}),
"latin-america": frozenset({"brazil", "mexico", "argentina"}),
"europe": frozenset(
{
"uk",
"france",
"germany",
"italy",
"spain",
"netherlands",
"portugal",
"greece",
"poland",
"russia",
"sweden",
"norway",
"denmark",
"finland",
}
),
"asia": frozenset(
{
"japan",
"south-korea",
"china",
"taiwan",
"hong-kong",
"singapore",
"india",
"asia-ntsc",
"asia-pal",
}
),
"oceania": frozenset({"australia", "new-zealand"}),
}
_PARENT: dict[str, str] = {
member: parent for parent, members in REGION_TREE.items() for member in members
}
REGIONS: frozenset[str] = frozenset({WORLD} | set(REGION_TREE) | set(_PARENT))
# Accepted on the CLI and for legacy profile values.
ALIASES: dict[str, str] = {
"jp": "japan",
"ntsc-j": "japan",
"us": "north-america",
"usa": "north-america",
"na": "north-america",
"ntsc-u": "north-america",
"eu": "europe",
"pal": "europe",
"kr": "south-korea",
"korea": "south-korea",
"auto": WORLD,
"gb": "uk",
}
def _canonical(raw: str) -> str:
"""Map one token to a canonical region slug."""
key = raw.strip().lower()
key = ALIASES.get(key, key)
if key not in REGIONS:
raise ValueError(f"unknown region: {raw!r}")
return key
def comparable(a: str, b: str) -> bool:
"""True when two regions are equal or in a parent/child relation."""
return a == b or _PARENT.get(a) == b or _PARENT.get(b) == a
def normalize_declared(raw: str | list | None) -> set[str]:
"""Normalise a profile region: value to canonical slugs."""
if raw is None:
return set()
values = raw if isinstance(raw, list) else [raw]
return {_canonical(str(v)) for v in values}
def parse_requested(raw: str) -> list[str]:
"""Parse a comma-separated --region value into an ordered priority list."""
out: list[str] = []
for part in raw.split(","):
if not part.strip():
continue
slug = _canonical(part)
if slug not in out:
out.append(slug)
if not out:
raise ValueError("--region requires at least one region")
return out
def rank(file_regions: set[str], requested: list[str]) -> int:
"""Priority index of a file, lower is better.
Returns len(requested) when no requested region is comparable, the implicit
lowest rank that keeps a group from ever being emptied.
"""
for i, req in enumerate(requested):
if any(comparable(req, fr) for fr in file_regions):
return i
return len(requested)
def region_tag(requested: list[str]) -> str:
"""Pack filename tag for a requested priority list."""
return "_".join(
"".join(part.title() for part in slug.split("-")) for slug in requested
)
def build_region_index(profiles: dict) -> dict[str, dict]:
"""Build a region lookup from emulator profiles.
Keyed by the entry's path when present, by name otherwise. Entries sharing a
key have their regions unioned, so an ambiguous lookup keeps more files
rather than fewer.
"""
index: dict[str, dict] = {}
for emu_name, profile in sorted(profiles.items()):
if profile.get("type") in ("launcher", "alias"):
continue
for f in profile.get("files") or []:
if not isinstance(f, dict):
continue
try:
regions = normalize_declared(f.get("region"))
except ValueError as exc:
raise ValueError(
f"{emu_name}: {f.get('name', '?')}: {exc}"
) from exc
if not regions:
continue
name = f.get("name", "")
path = f.get("path") or ""
# Path-keyed so same-named entries stay separate (Dolphin declares
# three IPL.bin), name-keyed so a candidate identified by name alone
# sees the union and is never dropped on ambiguity.
for key in {path, name} - {""}:
entry = index.setdefault(key, {"regions": set(), "emulators": []})
entry["regions"] |= regions
if emu_name not in entry["emulators"]:
entry["emulators"].append(emu_name)
return index
def lookup_regions(index: dict[str, dict], destination: str, name: str) -> set[str]:
"""Look a candidate file up in the region index.
Tries the full destination, then progressively shorter path suffixes, then
the bare name. Suffix matching bridges a platform entry whose destination
carries an extra prefix to the profile entry that declares the region.
"""
if destination:
entry = index.get(destination)
if entry:
return set(entry["regions"])
parts = destination.split("/")
for i in range(1, len(parts)):
entry = index.get("/".join(parts[i:]))
if entry:
return set(entry["regions"])
entry = index.get(name)
return set(entry["regions"]) if entry else set()
def _competing_ranks(
members: list[tuple[str, str]],
index: dict[str, dict],
requested: list[str],
) -> list[tuple[int, str]]:
"""Rank the members of a group that compete regionally.
Files with no declared region, and files declared world, are excluded: they
never compete and never drop.
"""
ranked: list[tuple[int, str]] = []
for destination, name in members:
regions = lookup_regions(index, destination, name)
if not regions or WORLD in regions:
continue
ranked.append((rank(regions, requested), destination))
return ranked
def resolve_region_drops(
groups: dict[str, list[tuple[str, str]]],
index: dict[str, dict],
requested: list[str],
) -> set[str]:
"""Destinations to skip for a requested region priority list.
Per group, only the best rank actually present survives. A destination kept
by any group is kept overall.
"""
if not requested:
return set()
keep: set[str] = set()
drop: set[str] = set()
for members in groups.values():
ranked = _competing_ranks(members, index, requested)
competing = {dest for _r, dest in ranked}
keep |= {dest for dest, _name in members if dest not in competing}
if not ranked:
continue
best = min(r for r, _ in ranked)
for r, destination in ranked:
if r == best:
keep.add(destination)
else:
drop.add(destination)
return drop - keep
def fallback_groups(
groups: dict[str, list[tuple[str, str]]],
index: dict[str, dict],
requested: list[str],
) -> list[str]:
"""Group IDs where no candidate matched, so the whole group was kept."""
if not requested:
return []
out: list[str] = []
for group_id, members in groups.items():
ranked = _competing_ranks(members, index, requested)
if ranked and min(r for r, _ in ranked) == len(requested):
out.append(group_id)
return sorted(out)
+211
View File
@@ -0,0 +1,211 @@
"""Cross-check profile region: values against dump-catalog provenance.
Advisory only. The emulator source decides what a region: value should be; this
reports where an independent catalogue disagrees, so a hand-written value gets a
second opinion before it is trusted.
Read the limits printed in the header before acting on anything here.
"""
from __future__ import annotations
import argparse
import collections
import json
import re
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
import region
from common import load_emulator_profiles, load_database
# No-Intro filename tokens: full English territory names.
NOINTRO = {
"World": "world",
"USA": "north-america",
"Canada": "canada",
"Europe": "europe",
"Japan": "japan",
"Asia": "asia",
"Korea": "south-korea",
"Brazil": "brazil",
"Taiwan": "taiwan",
"China": "china",
"Hong Kong": "hong-kong",
"France": "france",
"Germany": "germany",
"Spain": "spain",
"Italy": "italy",
"Netherlands": "netherlands",
"Sweden": "sweden",
"Norway": "norway",
"Denmark": "denmark",
"Finland": "finland",
"Australia": "australia",
"New Zealand": "new-zealand",
"Russia": "russia",
"UK": "uk",
"Portugal": "portugal",
"Greece": "greece",
"Poland": "poland",
"India": "india",
"Mexico": "mexico",
"Argentina": "argentina",
"Latin America": "latin-america",
}
_PAREN = re.compile(r"\(([^)]+)\)")
LIMITS = """Limits, read before trusting any line below.
TOSEC's country field is the country of ORIGIN, not the regional variant
(TOSEC Naming Convention v4, p.12). A Korean MSX ROM published by Microsoft
US is tagged (US). TOSEC names are therefore NOT read here.
Redump DATs carry no region at all: it exists in the redump.org database but
is never exported, so a Redump entry contributes nothing.
Only No-Intro filename tokens are usable, and only for the fraction of repo
files that carry one. Everything else is silent, not clean.
The emulator source decides. A disagreement is a prompt to reread the code,
never a correction to apply on its own.
"""
def tokens_from_name(name: str) -> set[str]:
"""Extract geography slugs from a No-Intro style DAT entry name."""
found: set[str] = set()
for group in _PAREN.findall(name):
for part in (p.strip() for p in group.split(",")):
slug = NOINTRO.get(part)
if slug:
found.add(slug)
return found
def catalog_regions(db: dict) -> dict[str, tuple[set[str], str]]:
"""Map SHA1 to (geography slugs, source label) from No-Intro provenance."""
out: dict[str, tuple[set[str], str]] = {}
for sha1, record in db["files"].items():
entry = (record.get("provenance") or {}).get("no-intro")
if not entry:
continue
name = entry.get("name", "")
found = tokens_from_name(name)
if found:
out[sha1] = (found, name)
return out
def resolve_sha1(file_entry: dict, db: dict) -> str | None:
"""Resolve a profile file entry to a repo SHA1, or None when ambiguous."""
files = db["files"]
indexes = db["indexes"]
declared = str(file_entry.get("sha1") or "").lower()
if declared and declared in files:
return declared
md5 = str(file_entry.get("md5") or "").lower()
if md5 and md5 in indexes["by_md5"]:
return indexes["by_md5"][md5]
hits = indexes["by_name"].get(file_entry.get("name", ""), [])
if isinstance(hits, str):
hits = [hits]
return hits[0] if len(hits) == 1 else None
def build_report(profiles: dict, db: dict) -> dict:
"""Compare every declared region: against the No-Intro catalogue."""
catalog = catalog_regions(db)
agree = 0
unchecked = 0
conflicts: list[dict] = []
vocabulary: collections.Counter = collections.Counter()
for slugs, _name in catalog.values():
vocabulary.update(slugs)
for emu_name, profile in sorted(profiles.items()):
if profile.get("type") in ("launcher", "alias"):
continue
for f in profile.get("files") or []:
if not isinstance(f, dict) or not f.get("region"):
continue
declared = region.normalize_declared(f["region"])
sha1 = resolve_sha1(f, db)
if not sha1 or sha1 not in catalog:
unchecked += 1
continue
found, name = catalog[sha1]
if region.WORLD in declared or any(
region.comparable(d, c) for d in declared for c in found
):
agree += 1
continue
conflicts.append(
{
"emulator": emu_name,
"file": f.get("name", ""),
"profile": sorted(declared),
"catalog": sorted(found),
"dat_name": name,
}
)
return {
"agree": agree,
"disagree": len(conflicts),
"unchecked": unchecked,
"catalog_files": len(catalog),
"repo_files": len(db["files"]),
"vocabulary": dict(vocabulary.most_common()),
"conflicts": conflicts,
}
def print_report(report: dict) -> None:
print(LIMITS)
print(
f"repo files: {report['repo_files']} "
f"with a usable No-Intro region token: {report['catalog_files']}"
)
print(
f"declared region: values -> agree {report['agree']}, "
f"disagree {report['disagree']}, no catalogue entry {report['unchecked']}"
)
if report["vocabulary"]:
print("\ncatalogue vocabulary present in this collection:")
for slug, count in report["vocabulary"].items():
print(f" {count:5d} {slug}")
if not report["conflicts"]:
print("\nNo disagreement.")
return
print("\nDISAGREEMENTS (reread the emulator source, do not apply blindly):\n")
for c in report["conflicts"]:
print(f" {c['emulator']}: {c['file']}")
print(f" profile: {c['profile']}")
print(f" catalogue: {c['catalog']} ({c['dat_name']})")
def main() -> int:
parser = argparse.ArgumentParser(
description="Cross-check profile region: values against No-Intro provenance"
)
parser.add_argument("--db", default="database.json", help="Path to database.json")
parser.add_argument("--emulators-dir", default="emulators")
parser.add_argument("--json", action="store_true", help="Machine-readable output")
args = parser.parse_args()
db = load_database(args.db)
profiles = load_emulator_profiles(args.emulators_dir)
report = build_report(profiles, db)
if args.json:
print(json.dumps(report, indent=2, sort_keys=True))
else:
print_report(report)
return 0
if __name__ == "__main__":
raise SystemExit(main())
+1 -1
View File
@@ -1495,7 +1495,7 @@ def print_emulator_result(result: dict, verbose: bool = False) -> None:
f" Ground truth: {gt_cov['with_validation']}/{gt_cov['total']} files have emulator validation ({pct}%)"
)
if gt_cov["platform_only"]:
print(f" {gt_cov['platform_only']} platform-only (no emulator profile)")
print(f" {gt_cov['platform_only']} without declared validation")
def main():
+318
View File
@@ -5335,6 +5335,324 @@ struct BurnDriver BurnDrvneogeo = {
self.assertLess(sizes[0], len(raw))
self.assertEqual(sizes[0], sizes[1])
# ---------------------------------------------------------------
# Region filter
# ---------------------------------------------------------------
def _region_profiles(self) -> dict:
return {
"rgncore": {
"emulator": "RegionCore",
"type": "libretro",
"systems": ["region-console"],
"files": [
{"name": "rgn_us.bin", "region": ["north-america"]},
{"name": "rgn_jp.bin", "region": ["japan"]},
{"name": "rgn_eu.bin", "region": ["europe"]},
{"name": "rgn_world.bin", "region": ["world"]},
{"name": "rgn_plain.bin"},
],
}
}
def _create_region_fixtures(self) -> None:
names = (
"rgn_us.bin",
"rgn_jp.bin",
"rgn_eu.bin",
"rgn_world.bin",
"rgn_plain.bin",
)
for name in names:
self._make_file(name, name.encode())
self.db = self._build_db()
config = {
"platform": "RegionPlat",
"verification_mode": "existence",
"systems": {
"region-console": {
"files": [
{
"name": n,
"destination": n,
"required": n
in ("rgn_us.bin", "rgn_jp.bin", "rgn_eu.bin"),
}
for n in names
]
}
},
}
with open(
os.path.join(self.platforms_dir, "regionplat.yml"), "w", encoding="utf-8"
) as fh:
yaml.safe_dump(config, fh)
def _region_pack(self, **kwargs) -> str:
from generate_pack import generate_pack
self._create_region_fixtures()
out = generate_pack(
"regionplat",
self.platforms_dir,
self.db,
self.bios_dir,
self.root,
emu_profiles=self._region_profiles(),
**kwargs,
)
self.assertIsNotNone(out)
return out
@staticmethod
def _names_in(zip_path: str) -> set[str]:
with zipfile.ZipFile(zip_path) as zf:
return {os.path.basename(n) for n in zf.namelist()}
def test_region_filter_drops_other_regions(self):
names = self._names_in(self._region_pack(regions=["north-america"]))
self.assertIn("rgn_us.bin", names)
self.assertNotIn("rgn_jp.bin", names)
self.assertNotIn("rgn_eu.bin", names)
def test_region_priority_selects_second_choice(self):
names = self._names_in(self._region_pack(regions=["oceania", "europe"]))
self.assertIn("rgn_eu.bin", names)
self.assertNotIn("rgn_us.bin", names)
self.assertNotIn("rgn_jp.bin", names)
def test_region_filter_keeps_group_with_no_match(self):
names = self._names_in(self._region_pack(regions=["oceania"]))
for expected in ("rgn_us.bin", "rgn_jp.bin", "rgn_eu.bin"):
self.assertIn(expected, names)
def test_region_filter_keeps_untagged_and_world(self):
names = self._names_in(self._region_pack(regions=["north-america"]))
self.assertIn("rgn_plain.bin", names)
self.assertIn("rgn_world.bin", names)
def test_region_tag_in_pack_name(self):
out = self._region_pack(regions=["north-america", "japan"])
self.assertIn("NorthAmerica_Japan", os.path.basename(out))
def test_no_region_argument_changes_nothing(self):
names = self._names_in(self._region_pack())
for expected in (
"rgn_us.bin",
"rgn_jp.bin",
"rgn_eu.bin",
"rgn_plain.bin",
"rgn_world.bin",
):
self.assertIn(expected, names)
def test_region_composes_with_required_only(self):
out = self._region_pack(regions=["north-america"], required_only=True)
names = self._names_in(out)
self.assertIn("rgn_us.bin", names)
self.assertNotIn("rgn_jp.bin", names)
self.assertNotIn("rgn_eu.bin", names)
self.assertIn("NorthAmerica", os.path.basename(out))
self.assertIn("Required", os.path.basename(out))
def test_region_composes_with_source_platform(self):
names = self._names_in(
self._region_pack(regions=["north-america"], source="platform")
)
self.assertIn("rgn_us.bin", names)
self.assertNotIn("rgn_jp.bin", names)
self.assertNotIn("rgn_eu.bin", names)
self.assertIn("rgn_world.bin", names)
self.assertIn("rgn_plain.bin", names)
def test_region_composes_with_split(self):
from generate_pack import generate_split_packs
self._create_region_fixtures()
paths = generate_split_packs(
"regionplat",
self.platforms_dir,
self.db,
self.bios_dir,
self.root,
emu_profiles=self._region_profiles(),
regions=["north-america"],
)
self.assertTrue(paths)
for p in paths:
self.assertIn("NorthAmerica", os.path.basename(p))
names = self._names_in(p)
self.assertNotIn("rgn_jp.bin", names)
self.assertNotIn("rgn_eu.bin", names)
def test_region_composes_with_manifest(self):
from generate_pack import generate_manifest
self._create_region_fixtures()
registry_path = os.path.join(self.platforms_dir, "_registry.yml")
if not os.path.exists(registry_path):
with open(registry_path, "w", encoding="utf-8") as fh:
yaml.safe_dump({"platforms": {}}, fh)
manifest = generate_manifest(
"regionplat",
self.platforms_dir,
self.db,
self.bios_dir,
registry_path,
emu_profiles=self._region_profiles(),
regions=["north-america"],
)
packed = {os.path.basename(f["dest"]) for f in manifest["files"]}
self.assertIn("rgn_us.bin", packed)
self.assertNotIn("rgn_jp.bin", packed)
self.assertNotIn("rgn_eu.bin", packed)
def test_manifest_without_region_keeps_every_variant(self):
from generate_pack import generate_manifest
self._create_region_fixtures()
registry_path = os.path.join(self.platforms_dir, "_registry.yml")
if not os.path.exists(registry_path):
with open(registry_path, "w", encoding="utf-8") as fh:
yaml.safe_dump({"platforms": {}}, fh)
manifest = generate_manifest(
"regionplat",
self.platforms_dir,
self.db,
self.bios_dir,
registry_path,
emu_profiles=self._region_profiles(),
)
packed = {os.path.basename(f["dest"]) for f in manifest["files"]}
for expected in ("rgn_us.bin", "rgn_jp.bin", "rgn_eu.bin"):
self.assertIn(expected, packed)
def test_region_composes_with_system_pack(self):
from generate_pack import generate_system_pack
self._create_region_fixtures()
os.makedirs(self.emulators_dir, exist_ok=True)
with open(
os.path.join(self.emulators_dir, "rgncore.yml"), "w", encoding="utf-8"
) as fh:
yaml.safe_dump(self._region_profiles()["rgncore"], fh)
out = generate_system_pack(
["region-console"],
self.emulators_dir,
self.db,
self.bios_dir,
self.root,
regions=["north-america"],
)
self.assertIsNotNone(out)
names = self._names_in(out)
self.assertIn("rgn_us.bin", names)
self.assertNotIn("rgn_jp.bin", names)
def test_readme_region_section_lists_fallback_systems(self):
from generate_pack import _build_readme
text = _build_readme(
"regionplat",
"RegionPlat",
"",
10,
2,
regions=["north-america"],
fallback_systems=["nintendo-fds"],
)
self.assertIn("PACK TYPE: Region Filtered", text)
self.assertIn("Region priority: North America", text)
self.assertIn("nintendo-fds", text)
self.assertIn("This pack was filtered", text)
self.assertNotIn("All are included", text)
def test_readme_without_region_keeps_the_regional_note(self):
from generate_pack import _build_readme
text = _build_readme("regionplat", "RegionPlat", "", 10, 2)
self.assertNotIn("PACK TYPE: Region Filtered", text)
self.assertIn("All are included", text)
def test_verify_agrees_with_region_filtered_pack(self):
from generate_pack import verify_pack_against_platform
out = self._region_pack(regions=["north-america"])
result = verify_pack_against_platform(
out,
"regionplat",
self.platforms_dir,
db=self.db,
emu_profiles=self._region_profiles(),
regions=["north-america"],
)
ok, _checked, _present, errors = result[:4]
self.assertTrue(ok, errors)
def test_verify_reports_the_gap_without_the_region_filter(self):
from generate_pack import verify_pack_against_platform
out = self._region_pack(regions=["north-america"])
result = verify_pack_against_platform(
out,
"regionplat",
self.platforms_dir,
db=self.db,
emu_profiles=self._region_profiles(),
)
ok, _checked, _present, errors = result[:4]
self.assertFalse(ok)
self.assertTrue(any("rgn_jp.bin" in e for e in errors), errors)
def test_region_composes_with_source_truth(self):
names = self._names_in(
self._region_pack(regions=["north-america"], source="truth")
)
self.assertIn("rgn_us.bin", names)
self.assertNotIn("rgn_jp.bin", names)
# ---- gap analysis resolves files the pack can already ship ----
@staticmethod
def _gap_db(repo_name: str, sha1: str, crc32: str) -> dict:
return {
"files": {sha1: {"path": f"bios/{repo_name}", "size": 8192}},
"indexes": {
"by_name": {repo_name: [sha1]},
"by_md5": {},
"by_crc32": {crc32: sha1},
"by_sha256": {},
"by_path_suffix": {},
},
}
def _gap_source(self, entry: dict, db: dict) -> str:
from cross_reference import cross_reference
report = cross_reference(
{"gapemu": {"emulator": "GapEmu", "systems": ["s"], "files": [entry]}},
{"s": set()},
db,
)
return report["gapemu"]["gap_details"][0]["source"]
def test_gap_analysis_resolves_by_alias(self):
"""A file stored under an alias is in the repo, not a sourcing target."""
db = self._gap_db("REPO_chip.rom", "a" * 40, "465c4e1c")
entry = {"name": "chip.rom", "aliases": ["REPO_chip.rom"], "required": True}
self.assertEqual(self._gap_source(entry, db), "bios")
def test_gap_analysis_resolves_by_crc32(self):
"""crc32 is the only hash some emulators declare."""
db = self._gap_db("REPO_chip.rom", "a" * 40, "465c4e1c")
entry = {"name": "chip.rom", "crc32": "465c4e1c", "required": True}
self.assertEqual(self._gap_source(entry, db), "bios")
def test_gap_analysis_reports_unknown_file_missing(self):
db = self._gap_db("REPO_chip.rom", "a" * 40, "465c4e1c")
entry = {"name": "chip.rom", "aliases": ["OTHER.rom"], "crc32": "deadbeef"}
self.assertEqual(self._gap_source(entry, db), "missing")
if __name__ == "__main__":
unittest.main()
+423
View File
@@ -0,0 +1,423 @@
"""Region vocabulary, hierarchy, and rank resolution."""
from __future__ import annotations
import os
import sys
import unittest
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "scripts"))
import region
class TestVocabulary(unittest.TestCase):
def test_world_is_a_region(self):
self.assertIn(region.WORLD, region.REGIONS)
def test_super_regions_and_members_are_all_regions(self):
for parent, members in region.REGION_TREE.items():
self.assertIn(parent, region.REGIONS)
for member in members:
self.assertIn(member, region.REGIONS)
def test_hierarchy_is_two_levels(self):
for members in region.REGION_TREE.values():
for member in members:
self.assertNotIn(member, region.REGION_TREE)
def test_no_member_has_two_parents(self):
seen: set[str] = set()
for members in region.REGION_TREE.values():
for member in members:
self.assertNotIn(member, seen)
seen.add(member)
class TestComparable(unittest.TestCase):
def test_equal(self):
self.assertTrue(region.comparable("japan", "japan"))
def test_parent_matches_child(self):
self.assertTrue(region.comparable("europe", "france"))
def test_child_matches_parent(self):
self.assertTrue(region.comparable("france", "europe"))
def test_siblings_do_not_match(self):
self.assertFalse(region.comparable("france", "germany"))
def test_disjoint_super_regions_do_not_match(self):
self.assertFalse(region.comparable("europe", "asia"))
def test_saturn_fused_slug_is_under_asia(self):
self.assertTrue(region.comparable("asia", "asia-ntsc"))
class TestNormalizeDeclared(unittest.TestCase):
def test_none_is_empty(self):
self.assertEqual(region.normalize_declared(None), set())
def test_list_passes_through(self):
self.assertEqual(region.normalize_declared(["japan"]), {"japan"})
def test_legacy_signal_string_maps_to_geography(self):
self.assertEqual(region.normalize_declared("NTSC-J"), {"japan"})
self.assertEqual(region.normalize_declared("NTSC-U"), {"north-america"})
self.assertEqual(region.normalize_declared("PAL"), {"europe"})
def test_legacy_auto_and_world_map_to_world(self):
self.assertEqual(region.normalize_declared("Auto"), {region.WORLD})
self.assertEqual(region.normalize_declared("World"), {region.WORLD})
def test_unknown_value_raises(self):
with self.assertRaises(ValueError):
region.normalize_declared("atlantis")
class TestParseRequested(unittest.TestCase):
def test_single_alias(self):
self.assertEqual(region.parse_requested("us"), ["north-america"])
def test_order_is_preserved(self):
self.assertEqual(
region.parse_requested("us,eu,jp"),
["north-america", "europe", "japan"],
)
def test_duplicates_collapse_keeping_first_position(self):
self.assertEqual(
region.parse_requested("us,usa,eu"), ["north-america", "europe"]
)
def test_whitespace_and_case_tolerated(self):
self.assertEqual(
region.parse_requested(" US , Eu "), ["north-america", "europe"]
)
def test_unknown_region_raises(self):
with self.assertRaises(ValueError):
region.parse_requested("us,atlantis")
def test_empty_raises(self):
with self.assertRaises(ValueError):
region.parse_requested(" ")
class TestRank(unittest.TestCase):
def test_exact_match_is_zero(self):
self.assertEqual(region.rank({"north-america"}, ["north-america"]), 0)
def test_second_choice_is_one(self):
self.assertEqual(region.rank({"europe"}, ["north-america", "europe"]), 1)
def test_no_match_is_lowest(self):
self.assertEqual(region.rank({"japan"}, ["north-america", "europe"]), 2)
def test_child_matches_requested_parent(self):
self.assertEqual(region.rank({"france"}, ["europe"]), 0)
def test_parent_matches_requested_child(self):
self.assertEqual(region.rank({"europe"}, ["france"]), 0)
def test_best_of_several_declared_regions_wins(self):
self.assertEqual(
region.rank({"japan", "north-america"}, ["north-america", "japan"]), 0
)
def test_empty_declared_is_lowest(self):
self.assertEqual(region.rank(set(), ["north-america"]), 1)
class TestRegionTag(unittest.TestCase):
def test_single(self):
self.assertEqual(region.region_tag(["north-america"]), "NorthAmerica")
def test_multiple_joined(self):
self.assertEqual(
region.region_tag(["north-america", "japan"]), "NorthAmerica_Japan"
)
class TestRegionIndex(unittest.TestCase):
def setUp(self):
self.profiles = {
"dolphin": {
"files": [
{
"name": "IPL.bin",
"path": "GC/USA/IPL.bin",
"region": ["north-america"],
},
{
"name": "IPL.bin",
"path": "GC/EUR/IPL.bin",
"region": ["europe"],
},
{
"name": "IPL.bin",
"path": "GC/JAP/IPL.bin",
"region": ["japan"],
},
{"name": "dsp_rom.bin"},
]
},
"beetle_psx": {
"files": [
{"name": "scph5501.bin", "region": "NTSC-U"},
{"name": "psxonpsp660.bin", "region": "Auto"},
]
},
"swanstation": {
"files": [{"name": "scph5501.bin", "region": "NTSC-U"}]
},
"launcher_profile": {
"type": "launcher",
"files": [{"name": "ignored.bin", "region": ["japan"]}],
},
}
self.index = region.build_region_index(self.profiles)
def test_path_keyed_entries_stay_separate(self):
self.assertEqual(
region.lookup_regions(self.index, "GC/USA/IPL.bin", "IPL.bin"),
{"north-america"},
)
self.assertEqual(
region.lookup_regions(self.index, "GC/JAP/IPL.bin", "IPL.bin"),
{"japan"},
)
def test_bare_name_lookup_unions_ambiguous_entries(self):
self.assertEqual(
region.lookup_regions(self.index, "", "IPL.bin"),
{"north-america", "europe", "japan"},
)
def test_destination_suffix_bridges_platform_entry(self):
self.assertEqual(
region.lookup_regions(
self.index, "dolphin-emu/GC/EUR/IPL.bin", "IPL.bin"
),
{"europe"},
)
def test_untagged_file_has_no_regions(self):
self.assertEqual(
region.lookup_regions(self.index, "dsp_rom.bin", "dsp_rom.bin"), set()
)
def test_unknown_file_has_no_regions(self):
self.assertEqual(
region.lookup_regions(self.index, "nope.bin", "nope.bin"), set()
)
def test_legacy_string_values_are_normalised(self):
self.assertEqual(
region.lookup_regions(self.index, "scph5501.bin", "scph5501.bin"),
{"north-america"},
)
self.assertEqual(
region.lookup_regions(self.index, "psxonpsp660.bin", "psxonpsp660.bin"),
{region.WORLD},
)
def test_two_profiles_agreeing_merge(self):
entry = self.index["scph5501.bin"]
self.assertEqual(entry["regions"], {"north-america"})
self.assertEqual(entry["emulators"], ["beetle_psx", "swanstation"])
def test_launcher_profiles_are_skipped(self):
self.assertEqual(
region.lookup_regions(self.index, "ignored.bin", "ignored.bin"), set()
)
def test_unknown_value_names_the_profile_and_file(self):
with self.assertRaises(ValueError) as ctx:
region.build_region_index(
{"badcore": {"files": [{"name": "x.bin", "region": ["atlantis"]}]}}
)
self.assertIn("badcore", str(ctx.exception))
self.assertIn("x.bin", str(ctx.exception))
class TestResolveRegionDrops(unittest.TestCase):
def setUp(self):
self.index = region.build_region_index(
{
"psx": {
"files": [
{"name": "scph5501.bin", "region": ["north-america"]},
{"name": "scph5500.bin", "region": ["japan"]},
{"name": "scph5502.bin", "region": ["europe"]},
{"name": "psxonpsp660.bin", "region": ["world"]},
{"name": "gamepad.cfg"},
]
},
"fds": {"files": [{"name": "disksys.rom", "region": ["japan"]}]},
"o2em": {"files": [{"name": "c52.bin", "region": ["france"]}]},
}
)
def _drops(self, groups, requested):
return region.resolve_region_drops(groups, self.index, requested)
def test_best_rank_wins_and_siblings_drop(self):
groups = {
"psx": [
("scph5501.bin", "scph5501.bin"),
("scph5500.bin", "scph5500.bin"),
("scph5502.bin", "scph5502.bin"),
]
}
self.assertEqual(
self._drops(groups, ["north-america"]),
{"scph5500.bin", "scph5502.bin"},
)
def test_priority_order_selects_second_choice(self):
groups = {
"psx": [
("scph5500.bin", "scph5500.bin"),
("scph5502.bin", "scph5502.bin"),
]
}
self.assertEqual(
self._drops(groups, ["north-america", "europe", "japan"]),
{"scph5500.bin"},
)
def test_group_with_no_match_is_kept_whole(self):
groups = {"fds": [("disksys.rom", "disksys.rom")]}
self.assertEqual(self._drops(groups, ["north-america"]), set())
def test_world_never_competes(self):
groups = {
"psx": [
("scph5501.bin", "scph5501.bin"),
("scph5500.bin", "scph5500.bin"),
("psxonpsp660.bin", "psxonpsp660.bin"),
]
}
self.assertEqual(self._drops(groups, ["north-america"]), {"scph5500.bin"})
def test_untagged_files_never_drop(self):
groups = {
"psx": [
("scph5501.bin", "scph5501.bin"),
("gamepad.cfg", "gamepad.cfg"),
("scph5500.bin", "scph5500.bin"),
]
}
self.assertEqual(self._drops(groups, ["north-america"]), {"scph5500.bin"})
def test_child_region_satisfies_requested_parent(self):
groups = {"o2em": [("c52.bin", "c52.bin")]}
self.assertEqual(self._drops(groups, ["europe"]), set())
def test_destination_kept_by_any_group_is_not_dropped(self):
groups = {
"psx": [
("scph5501.bin", "scph5501.bin"),
("scph5500.bin", "scph5500.bin"),
],
"psx-import": [("scph5500.bin", "scph5500.bin")],
}
self.assertEqual(self._drops(groups, ["north-america"]), set())
def test_no_requested_regions_drops_nothing(self):
groups = {"psx": [("scph5500.bin", "scph5500.bin")]}
self.assertEqual(self._drops(groups, []), set())
class TestFallbackGroups(unittest.TestCase):
def setUp(self):
self.index = region.build_region_index(
{
"psx": {
"files": [
{"name": "scph5501.bin", "region": ["north-america"]}
]
},
"fds": {"files": [{"name": "disksys.rom", "region": ["japan"]}]},
}
)
def test_only_unmatched_groups_are_reported(self):
groups = {
"psx": [("scph5501.bin", "scph5501.bin")],
"fds": [("disksys.rom", "disksys.rom")],
}
self.assertEqual(
region.fallback_groups(groups, self.index, ["north-america"]), ["fds"]
)
def test_no_requested_regions_reports_nothing(self):
groups = {"fds": [("disksys.rom", "disksys.rom")]}
self.assertEqual(region.fallback_groups(groups, self.index, []), [])
class TestProfileConformance(unittest.TestCase):
"""Every region: value in the repo is a list of canonical slugs."""
def setUp(self):
import glob
import yaml
self.repo_profiles = sorted(
glob.glob(
os.path.join(os.path.dirname(__file__), "..", "emulators", "*.yml")
)
)
if not self.repo_profiles:
self.skipTest("emulators/ not present")
self.yaml = yaml
def test_all_region_values_are_canonical_lists(self):
offenders: list[str] = []
for path in self.repo_profiles:
with open(path, encoding="utf-8") as fh:
profile = self.yaml.safe_load(fh) or {}
for f in profile.get("files") or []:
if not isinstance(f, dict) or "region" not in f:
continue
raw = f["region"]
if not isinstance(raw, list):
offenders.append(
f"{os.path.basename(path)}: {f.get('name')} not a list"
)
continue
for value in raw:
if value not in region.REGIONS:
offenders.append(
f"{os.path.basename(path)}: {f.get('name')} -> {value!r}"
)
self.assertEqual(offenders, [], "\n".join(offenders))
def test_index_builds_over_every_repo_profile(self):
profiles = {}
for path in self.repo_profiles:
with open(path, encoding="utf-8") as fh:
profiles[os.path.basename(path)[:-4]] = self.yaml.safe_load(fh) or {}
index = region.build_region_index(profiles)
self.assertGreater(len(index), 0)
class TestSchemaMatchesModule(unittest.TestCase):
def test_schema_enum_equals_module_regions(self):
import json
path = os.path.join(
os.path.dirname(__file__), "..", "schemas", "emulator.schema.json"
)
if not os.path.exists(path):
self.skipTest("schema not present")
with open(path, encoding="utf-8") as fh:
schema = json.load(fh)
node = schema["properties"]["files"]["items"]["properties"]["region"]
self.assertEqual(set(node["items"]["enum"]), set(region.REGIONS))
if __name__ == "__main__":
unittest.main()
+50
View File
@@ -56,6 +56,56 @@ What counts as "required" depends on the platform YAML. For existence-mode platf
For MD5-mode platforms (Batocera), all declared files are treated as required unless
explicitly marked optional.
### Region filtering
Keep one regional BIOS per system instead of all of them:
```bash
python scripts/generate_pack.py --platform retroarch --region us
python scripts/generate_pack.py --platform retroarch --region us,eu,jp
```
The list is an **ordered priority**, best first, the same model ROM managers use
for 1G1R. `--region us,eu,jp` means prefer North America, fall back to Europe,
fall back to Japan. It does not mean "keep all three": when a US BIOS exists for
a system, the European and Japanese ones are dropped.
Accepted names are territory slugs (`japan`, `north-america`, `europe`,
`south-korea`, `taiwan`, `brazil`, `france`...) plus short aliases (`jp`, `us`,
`eu`, `kr`) and the signal spellings (`ntsc-j`, `ntsc-u`, `pal`). Territories
nest, so `--region europe` keeps a BIOS declared `[france]`, and `--region france`
keeps one declared `[europe]`.
Three rules keep a filtered pack usable:
- **No system is ever emptied.** If nothing matches, the whole group is kept.
`--region us` still ships `disksys.rom`, because the Famicom Disk System has no
American BIOS.
- **Region-free files always survive.** `psxonpsp660.bin`, `ps1_rom.bin` and
`openbios.bin` are declared `[world]`; they add a capability rather than
competing regionally.
- **Untagged files always survive.** Most BIOS are not regional and carry no
`region:` at all.
What this does and does not do: it shrinks the pack. It does not change how cores
pick a BIOS. Most cores already select per region from fixed filename lists driven
by the game's region (PicoDrive in `libretro.c`, Genesis Plus GX in `loadrom.c`),
so a USA game already gets the US BIOS when it is present. Only cores that load a
single unqualified file change behaviour. Loading imports from another region may
need the unfiltered pack.
Verification takes the same flag, and needs it: a filtered pack checked without it
reports every dropped file as missing.
```bash
python scripts/generate_pack.py --platform recalbox --region us --verify-packs
```
`--region` composes with `--split`, `--target`, `--required-only`, `--source`,
`--emulator` and `--system`. It is mutually exclusive with `--from-md5`, which
selects by hash. `pipeline.py` never passes it, so the released packs stay
complete.
## Pack Source Variants