mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-23 20:29:06 -05:00
chore: merge the site funnel
This commit is contained in:
commit
db1d679e4e
31 files changed
+3049
-1951
No files matched your search
@@ -87,17 +87,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 check that the file is present under its name without reading its contents (`path_is_valid` in RetroArch's `core_info.c`), and MinUI, NextUI and MyMinUI hand each core its folder without opening a file in it: 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.
|
||||
|
||||
- **962 files** the platforms' emulators load are still to be found, and 137 more cannot be sourced at all (per-user keys, user-filled slots, dumps nobody has made). Both are named in the [gap analysis](https://abdess.github.io/retrobios/gaps/)
|
||||
- **936 files** the platforms' emulators load are still to be found, and 137 more cannot be sourced at all (per-user keys, user-filled slots, dumps nobody has made). Both are named in the [gap analysis](https://abdess.github.io/retrobios/gaps/)
|
||||
- **18 platforms** supported with platform-specific verification
|
||||
- **624 emulators** profiled from source (RetroArch cores + standalone)
|
||||
- **541 systems** handled by those emulators (NES, SNES, PlayStation, Saturn, Dreamcast, ...)
|
||||
- **19,707 files in the collection**, each with its SHA1, MD5, SHA256, CRC32 and Adler-32 fingerprints: 5,780 system files, 2,986 arcade ROM sets, 10,941 game and engine data files. That is every platform and emulator together, so no pack holds them all: each carries what its own emulators load, counted in the download table
|
||||
- **555 of 5,780 system files** matched to dump-preservation catalogs (No-Intro, Redump, TOSEC). Arcade sets and engine data fall outside what those catalogs index
|
||||
- **609 emulators** profiled from source (RetroArch cores + standalone)
|
||||
- **534 systems** handled by those emulators (NES, SNES, PlayStation, Saturn, Dreamcast, ...)
|
||||
- **19,595 files in the collection**, each with its SHA1, MD5, SHA256, CRC32 and Adler-32 fingerprints: 5,500 system files, 2,872 arcade ROM sets, 11,223 game and engine data files. That is every platform and emulator together, so no pack holds them all: each carries what its own emulators load, counted in the download table
|
||||
- **555 of 5,500 system files** matched to dump-preservation catalogs (No-Intro, Redump, TOSEC). Arcade sets and engine data fall outside what those catalogs index
|
||||
- **15.7 GB** for the whole collection
|
||||
|
||||
## 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 507+ 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 500+ more.
|
||||
|
||||
Full list with per-file details: **[https://abdess.github.io/retrobios/](https://abdess.github.io/retrobios/)**
|
||||
|
||||
@@ -105,23 +105,23 @@ Full list with per-file details: **[https://abdess.github.io/retrobios/](https:/
|
||||
|
||||
| Platform | On its BIOS list | Files its emulators load | Checked by |
|
||||
|----------|-----------------:|-------------------------:|------------|
|
||||
| AmberELEC | 414/434 | 4,551/4,654 | MD5 hash |
|
||||
| Batocera | 353/353 | 13,944/15,038 | MD5 hash |
|
||||
| AmberELEC | 414/434 | 4,550/4,647 | MD5 hash |
|
||||
| Batocera | 353/353 | 13,941/15,029 | MD5 hash |
|
||||
| BizHawk | 118/118 | - | SHA1 hash |
|
||||
| EmuDeck | 168/168 | 8,173/8,249 | MD5 hash |
|
||||
| EmuELEC | 544/572 | 4,598/9,948 | MD5 hash |
|
||||
| KNULLI | 290/290 | 8,897/15,095 | MD5 hash |
|
||||
| EmuELEC | 544/572 | 4,593/9,911 | MD5 hash |
|
||||
| KNULLI | 290/290 | 8,897/15,085 | MD5 hash |
|
||||
| Lakka | 532/532 | 7,600/7,659 | file presence |
|
||||
| MiSTer FPGA | 81/81 | - | MD5 hash |
|
||||
| MinUI | 0/0 | 78/79 | file presence |
|
||||
| MyMinUI | 0/0 | 347/354 | file presence |
|
||||
| NextUI | 0/0 | 343/348 | file presence |
|
||||
| ROCKNIX | 38/38 | 7,095/8,369 | MD5 hash |
|
||||
| Recalbox | 351/351 | 2,749/2,919 | MD5 hash |
|
||||
| ROCKNIX | 38/38 | 7,092/8,360 | MD5 hash |
|
||||
| Recalbox | 351/351 | 2,746/2,910 | MD5 hash |
|
||||
| RetroArch | 526/526 | 7,609/7,650 | file presence |
|
||||
| RetroBat | 348/348 | 4,729/9,194 | MD5 hash |
|
||||
| RetroDECK | 2,007/2,008 | 6,273/6,524 | MD5 hash |
|
||||
| RetroPie * | 532/532 | 7,882/12,406 | file presence |
|
||||
| RetroPie * | 532/532 | 7,879/12,395 | file presence |
|
||||
| RomM | 383/383 | 83/846 | 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/).
|
||||
@@ -170,14 +170,14 @@ 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 18 platforms and 624 emulators
|
||||
- **Cross-reference** mapping files across 18 platforms and 609 emulators
|
||||
- **Versioned data access** through JSON, CSV and SQLite exports with published SHA-256 checksums
|
||||
|
||||
## How it works
|
||||
|
||||
A platform's BIOS list and an emulator's code are maintained separately. Each list is compared with the emulator source code, file by file where a profile exists, and where the two differ the code decides.
|
||||
|
||||
Hashes document what emulator code loads and accepts, not dump provenance. That boundary, and how it relates to preservation catalogs such as No-Intro, is drawn in the [FAQ](https://abdess.github.io/retrobios/wiki/faq/#are-these-files-verified-against-original-hardware-dumps).
|
||||
Hashes document what emulator code loads and accepts, not dump provenance. That boundary, and how it relates to preservation catalogs such as No-Intro, is drawn in the [technical questions](https://abdess.github.io/retrobios/wiki/technical-faq/#are-these-files-verified-against-original-hardware-dumps).
|
||||
|
||||
1. **Read emulator source code**: trace every file the code loads, its expected hash and size
|
||||
2. **Cross-reference with platforms**: match against what each platform declares
|
||||
@@ -208,4 +208,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. [NOTICE](NOTICE) sets out their status and how to ask for a file to be removed.
|
||||
The reasoning, and where it is weakest, is in the [FAQ](https://abdess.github.io/retrobios/wiki/faq/#is-this-legal).
|
||||
|
||||
*Auto-generated on 2026-10-22T09:56:04Z*
|
||||
*Auto-generated on 2026-10-22T09:50:58Z*
|
||||
+723
-770
File diff suppressed because it is too large.
Load diff
@@ -181,6 +181,7 @@ platforms:
|
||||
retroarch:
|
||||
config: retroarch.yml
|
||||
status: active
|
||||
device_group: computer
|
||||
extract_to: system/
|
||||
logo: https://raw.githubusercontent.com/libretro/RetroArch/master/media/retroarch-vector_invader-only.svg
|
||||
scraper: libretro
|
||||
@@ -476,6 +477,7 @@ platforms:
|
||||
batocera:
|
||||
config: batocera.yml
|
||||
status: active
|
||||
device_group: gaming-os
|
||||
extract_to: /userdata/bios/
|
||||
logo: https://raw.githubusercontent.com/batocera-linux/batocera-emulationstation/master/resources/splash_batocera.svg
|
||||
scraper: batocera
|
||||
@@ -498,6 +500,7 @@ platforms:
|
||||
recalbox:
|
||||
config: recalbox.yml
|
||||
status: active
|
||||
device_group: gaming-os
|
||||
extract_to: /recalbox/share/bios/
|
||||
logo: https://raw.githubusercontent.com/homarr-labs/dashboard-icons/main/svg/recalbox.svg
|
||||
scraper: recalbox
|
||||
@@ -525,6 +528,7 @@ platforms:
|
||||
retrobat:
|
||||
config: retrobat.yml
|
||||
status: active
|
||||
device_group: computer
|
||||
extract_to: bios/
|
||||
logo: https://raw.githubusercontent.com/RetroBat-Official/retrobat/main/system/resources/retrobat_logo_notext.png
|
||||
scraper: retrobat
|
||||
@@ -557,6 +561,7 @@ platforms:
|
||||
emudeck:
|
||||
config: emudeck.yml
|
||||
status: active
|
||||
device_group: computer
|
||||
extract_to: ~/Emulation/bios/
|
||||
logo: https://raw.githubusercontent.com/dragoonDorise/EmuDeck/main/icons/EmuDeck.png
|
||||
scraper: emudeck
|
||||
@@ -606,6 +611,7 @@ platforms:
|
||||
lakka:
|
||||
config: lakka.yml
|
||||
status: active
|
||||
device_group: gaming-os
|
||||
extract_to: /storage/system/
|
||||
logo: https://raw.githubusercontent.com/libretro/retroarch-assets/master/src/xmb/flatui/lakka.svg
|
||||
scraper: libretro
|
||||
@@ -629,6 +635,7 @@ platforms:
|
||||
retrodeck:
|
||||
config: retrodeck.yml
|
||||
status: active
|
||||
device_group: computer
|
||||
extract_to: ~/retrodeck/
|
||||
logo: https://raw.githubusercontent.com/RetroDECK/RetroDECK/main/res/icon.svg
|
||||
scraper: retrodeck
|
||||
@@ -664,6 +671,7 @@ platforms:
|
||||
romm:
|
||||
config: romm.yml
|
||||
status: active
|
||||
device_group: server
|
||||
extract_to: library/bios/
|
||||
logo: https://avatars.githubusercontent.com/u/168586850
|
||||
scraper: romm
|
||||
@@ -726,6 +734,7 @@ platforms:
|
||||
rocknix:
|
||||
config: rocknix.yml
|
||||
status: active
|
||||
device_group: handheld
|
||||
extract_to: /storage/roms/bios/
|
||||
logo: https://avatars.githubusercontent.com/u/152618023
|
||||
scraper: rocknix
|
||||
@@ -750,6 +759,7 @@ platforms:
|
||||
amberelec:
|
||||
config: amberelec.yml
|
||||
status: active
|
||||
device_group: handheld
|
||||
extract_to: /storage/roms/
|
||||
logo: https://avatars.githubusercontent.com/u/102820909
|
||||
scraper: amberelec
|
||||
@@ -786,6 +796,7 @@ platforms:
|
||||
emuelec:
|
||||
config: emuelec.yml
|
||||
status: active
|
||||
device_group: handheld
|
||||
extract_to: /storage/roms/
|
||||
logo: https://avatars.githubusercontent.com/u/57574835
|
||||
scraper: emuelec
|
||||
@@ -813,6 +824,7 @@ platforms:
|
||||
knulli:
|
||||
config: knulli.yml
|
||||
status: active
|
||||
device_group: handheld
|
||||
extract_to: /userdata/bios/
|
||||
logo: https://avatars.githubusercontent.com/u/166268572
|
||||
scraper: knulli
|
||||
@@ -842,6 +854,7 @@ platforms:
|
||||
retropie:
|
||||
config: retropie.yml
|
||||
status: archived
|
||||
device_group: gaming-os
|
||||
extract_to: ~/RetroPie/BIOS/
|
||||
logo: https://avatars.githubusercontent.com/u/11378204
|
||||
scraper: retropie
|
||||
@@ -861,6 +874,7 @@ platforms:
|
||||
bizhawk:
|
||||
config: bizhawk.yml
|
||||
status: active
|
||||
device_group: computer
|
||||
extract_to: Firmware/
|
||||
logo: https://avatars.githubusercontent.com/u/11743303
|
||||
scraper: bizhawk
|
||||
@@ -896,6 +910,7 @@ platforms:
|
||||
misterfpga:
|
||||
config: misterfpga.yml
|
||||
status: active
|
||||
device_group: fpga
|
||||
extract_to: /media/fat/games/
|
||||
logo: https://avatars.githubusercontent.com/u/47264183
|
||||
scraper: misterfpga
|
||||
@@ -921,6 +936,7 @@ platforms:
|
||||
minui:
|
||||
config: minui.yml
|
||||
status: active
|
||||
device_group: handheld
|
||||
# The card root: minarch hands each core SDCARD_PATH/Bios/<TAG>
|
||||
# (workspace/all/minarch/minarch.c:2943).
|
||||
extract_to: <SD card>/
|
||||
@@ -950,6 +966,7 @@ platforms:
|
||||
nextui:
|
||||
config: nextui.yml
|
||||
status: active
|
||||
device_group: handheld
|
||||
# minarch hands each core SDCARD_PATH/Bios/<TAG>
|
||||
# (workspace/all/minarch/ma_core.c:76).
|
||||
extract_to: <SD card>/
|
||||
@@ -977,6 +994,7 @@ platforms:
|
||||
myminui:
|
||||
config: myminui.yml
|
||||
status: active
|
||||
device_group: handheld
|
||||
# minarch hands each core SDCARD_PATH/Bios/<TAG>
|
||||
# (workspace/all/minarch/minarch.c:3532).
|
||||
extract_to: <SD card>/
|
||||
|
||||
@@ -2003,6 +2003,7 @@ GAME_DATA_TOPS = (
|
||||
"3D Realms",
|
||||
"Apogee",
|
||||
"Blizzard",
|
||||
"Bungie",
|
||||
"Crack dot Com",
|
||||
"Electronic Arts",
|
||||
"Epic MegaGames",
|
||||
|
||||
@@ -659,7 +659,7 @@ def generate_readme(db: dict, platforms_dir: str) -> str:
|
||||
"Hashes document what emulator code loads and accepts, not dump"
|
||||
" provenance. That boundary, and how it relates to preservation"
|
||||
" catalogs such as No-Intro, is drawn in the"
|
||||
f" [FAQ]({SITE_URL}wiki/faq/"
|
||||
f" [technical questions]({SITE_URL}wiki/technical-faq/"
|
||||
"#are-these-files-verified-against-original-hardware-dumps).",
|
||||
"",
|
||||
"1. **Read emulator source code**: trace every file the code loads, its expected hash and size",
|
||||
|
||||
+783
-504
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,430 @@
|
||||
"""The guide part of the site: where each setup keeps its BIOS files.
|
||||
|
||||
A platform page opens on what someone holding the device needs: the folder,
|
||||
the command, the pack, how to check. The registry says which group of
|
||||
devices a platform belongs to (`device_group`), so the device picker and the
|
||||
navigation list every registered platform. The prose below is per platform,
|
||||
and a test holds that every registered platform has an entry.
|
||||
|
||||
Every path here is one the installer detects, the registry records or the
|
||||
platform documents. Menu labels of third-party software are named only where
|
||||
this project already relies on them.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
INSTALL_BASE = "https://raw.githubusercontent.com/Abdess/retrobios/main"
|
||||
|
||||
# Order of the groups on the picker, in the navigation and on the home page.
|
||||
DEVICE_GROUPS: dict[str, tuple[str, str]] = {
|
||||
"computer": (
|
||||
"Computers and Steam Deck",
|
||||
"An emulator app on a Windows, Mac or Linux computer, or on a Steam Deck.",
|
||||
),
|
||||
"gaming-os": (
|
||||
"Game systems for PCs and small boards",
|
||||
"A system that starts straight into a game menu, installed on a PC, a "
|
||||
"Raspberry Pi or another single-board computer.",
|
||||
),
|
||||
"handheld": (
|
||||
"Handhelds and TV boxes",
|
||||
"A handheld console or a TV box, and the system it starts when you turn it on.",
|
||||
),
|
||||
"fpga": (
|
||||
"MiSTer FPGA",
|
||||
"A MiSTer board, which recreates console hardware in a chip instead of "
|
||||
"emulating it in software.",
|
||||
),
|
||||
"server": (
|
||||
"Self-hosted game library",
|
||||
"A RomM server, which plays your games in a web browser.",
|
||||
),
|
||||
}
|
||||
|
||||
# Section anchors on the device picker. Two keep the anchors the page had
|
||||
# before it was grouped by device, which links outside the site may use.
|
||||
GROUP_ANCHORS = {
|
||||
"computer": "computers-and-steam-deck",
|
||||
"gaming-os": "game-systems",
|
||||
"handheld": "handhelds",
|
||||
"fpga": "fpga",
|
||||
"server": "self-hosted",
|
||||
}
|
||||
|
||||
# Setups that are not platforms of their own: they run one, and use its pack.
|
||||
# (setup, what it is, platform it uses, runs on, BIOS folder)
|
||||
ALSO_RUNS: dict[str, tuple[tuple[str, str, str, str, str], ...]] = {
|
||||
"computer": (
|
||||
("LaunchBox", "A game library and launcher. It starts RetroArch or "
|
||||
"standalone emulators.", "retroarch", "Windows",
|
||||
"The folder of the RetroArch it starts"),
|
||||
),
|
||||
"handheld": (
|
||||
("Android (Retroid Pocket, AYN Odin and others)", "RetroArch for Android.",
|
||||
"retroarch", "Android", "`RetroArch/system/` on the internal storage"),
|
||||
),
|
||||
}
|
||||
|
||||
# Ways to run the installer. Each tab names how to open a terminal there,
|
||||
# the shell the command is written for, and the options it needs.
|
||||
TERMINALS: dict[str, tuple[str, str, str]] = {
|
||||
"windows": (
|
||||
"Windows",
|
||||
"Open the Start menu, type **PowerShell** and open it. Paste the line "
|
||||
"and press Enter.",
|
||||
"powershell",
|
||||
),
|
||||
"macos": (
|
||||
"macOS",
|
||||
"Open **Terminal**, in Applications then Utilities. Paste the line and "
|
||||
"press Return.",
|
||||
"sh",
|
||||
),
|
||||
"linux": (
|
||||
"Linux",
|
||||
"Open a terminal. Paste the line and press Enter.",
|
||||
"sh",
|
||||
),
|
||||
"steamdeck": (
|
||||
"Steam Deck",
|
||||
"Switch to Desktop Mode and open **Konsole**, the terminal. Paste the "
|
||||
"line with Ctrl+Shift+V and press Enter.",
|
||||
"sh",
|
||||
),
|
||||
"android": (
|
||||
"Android (Termux)",
|
||||
"Install **Termux**, then run `pkg install python` and "
|
||||
"`termux-setup-storage` once. Paste the line and press Enter.",
|
||||
"sh",
|
||||
),
|
||||
"device": (
|
||||
"On the device",
|
||||
"Open a terminal on the device, or connect to it from a computer on the "
|
||||
"same network with SSH. Paste the line and press Enter.",
|
||||
"sh",
|
||||
),
|
||||
"server": (
|
||||
"On the server",
|
||||
"Open a terminal on the machine that holds the RomM library. Give "
|
||||
"`--dest` the `bios` folder of that library.",
|
||||
"sh",
|
||||
),
|
||||
}
|
||||
|
||||
# Windows users of a card frontend run the PowerShell form with a drive letter.
|
||||
CARD_TERMINALS = ("macos", "linux", "windows")
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Guide:
|
||||
"""What a platform page says before its file reference."""
|
||||
|
||||
summary: str
|
||||
folders: tuple[tuple[str, str], ...]
|
||||
run: tuple[str, ...]
|
||||
notes: tuple[str, ...] = ()
|
||||
dest: str = ""
|
||||
on_card: bool = False
|
||||
extra_args: dict[str, str] = field(default_factory=dict)
|
||||
|
||||
|
||||
GUIDES: dict[str, Guide] = {
|
||||
"retroarch": Guide(
|
||||
summary="A multi-system emulator. It loads a different core for each console.",
|
||||
folders=(
|
||||
("Windows, installer or portable build", "`system\\` next to `retroarch.exe`"),
|
||||
("Windows, Microsoft Store build",
|
||||
"`%LOCALAPPDATA%\\Packages\\1e4cf179-f3c2-404f-b9f3-cb2070a5aad8_*\\LocalState\\system\\`"),
|
||||
("macOS", "`~/Documents/RetroArch/system/`"),
|
||||
("macOS, Steam or portable build", "`~/Library/Application Support/RetroArch/system/`"),
|
||||
("Linux", "`~/.config/retroarch/system/`"),
|
||||
("Linux Flatpak and Steam Deck", "`~/.var/app/org.libretro.RetroArch/config/retroarch/system/`"),
|
||||
("Android", "`RetroArch/system/` on the internal storage"),
|
||||
("Nintendo Switch", "`retroarch/cores/system/` on the SD card"),
|
||||
),
|
||||
run=("windows", "macos", "linux", "steamdeck", "android"),
|
||||
notes=(
|
||||
"RetroArch shows the folder it reads in **Settings > Directory > "
|
||||
"System/BIOS**. The same value is the `system_directory` line of "
|
||||
"`retroarch.cfg`.",
|
||||
"On Windows, `retroarch.cfg` is read next to `retroarch.exe` first, "
|
||||
"then from `%APPDATA%\\RetroArch\\`. A `system_directory` left at its "
|
||||
"default is the `system` folder next to `retroarch.exe` (`:\\system` "
|
||||
"in RetroArch's `frontend/drivers/platform_win32.c`, where `:` stands "
|
||||
"for the folder of the program).",
|
||||
"LaunchBox and other launchers that start RetroArch use the folder "
|
||||
"RetroArch itself reads.",
|
||||
),
|
||||
),
|
||||
"batocera": Guide(
|
||||
summary="A system that starts straight into a game menu. It runs on PCs, "
|
||||
"Raspberry Pi boards and handhelds.",
|
||||
folders=(
|
||||
("On Batocera", "`/userdata/bios/`"),
|
||||
("From Windows, over the network", "`\\\\BATOCERA\\share\\bios\\`"),
|
||||
("From macOS or Linux, over the network", "`smb://batocera/share/bios/`"),
|
||||
),
|
||||
run=("device",),
|
||||
notes=(
|
||||
"From a computer on the same network, the network folder is the "
|
||||
"easiest way in: download the pack and extract it there.",
|
||||
),
|
||||
),
|
||||
"recalbox": Guide(
|
||||
summary="A system that starts straight into a game menu and sets up its "
|
||||
"emulators itself.",
|
||||
folders=(
|
||||
("On Recalbox", "`/recalbox/share/bios/`"),
|
||||
("From Windows, over the network", "`\\\\RECALBOX\\share\\bios\\`"),
|
||||
),
|
||||
run=("device",),
|
||||
notes=(
|
||||
"From a computer on the same network, download the pack and extract "
|
||||
"it into the network folder.",
|
||||
),
|
||||
),
|
||||
"retrobat": Guide(
|
||||
summary="A Windows frontend built on EmulationStation. It comes with "
|
||||
"RetroArch and standalone emulators.",
|
||||
folders=(
|
||||
("Inside the RetroBat folder", "`bios\\`"),
|
||||
("Default install", "`C:\\RetroBat\\bios\\`"),
|
||||
),
|
||||
run=("windows",),
|
||||
notes=(
|
||||
"RetroBat records its own folder each time it starts, and the "
|
||||
"installer reads it there, wherever RetroBat was installed.",
|
||||
),
|
||||
),
|
||||
"emudeck": Guide(
|
||||
summary="Installs and sets up many emulators, and adds each game to the "
|
||||
"Steam library.",
|
||||
folders=(
|
||||
("Steam Deck and Linux", "`~/Emulation/bios/`"),
|
||||
("Windows, by default", "`C:\\Emulation\\bios\\`"),
|
||||
("macOS", "`~/Emulation/bios/`"),
|
||||
),
|
||||
run=("steamdeck", "linux", "windows", "macos"),
|
||||
notes=(
|
||||
"The `bios` folder sits inside the Emulation folder chosen in "
|
||||
"EmuDeck. When EmuDeck was set up on an SD card, that folder is on "
|
||||
"the card. The installer reads the location from EmuDeck's settings "
|
||||
"(`emulationPath` in `~/.config/EmuDeck/settings.sh`).",
|
||||
),
|
||||
),
|
||||
"lakka": Guide(
|
||||
summary="A system built around RetroArch. It starts straight into the "
|
||||
"RetroArch menu.",
|
||||
folders=(("On Lakka", "`/storage/system/`"),),
|
||||
run=("device",),
|
||||
notes=("The folder is reachable over SSH and over the network share.",),
|
||||
),
|
||||
"retrodeck": Guide(
|
||||
summary="One app with its emulators included, installed from Flathub "
|
||||
"or Discover.",
|
||||
folders=(
|
||||
("Steam Deck and Linux", "`~/retrodeck/bios/`"),
|
||||
("Installed on a microSD card", "for example `/run/media/mmcblk0p1/retrodeck/bios/`"),
|
||||
),
|
||||
run=("steamdeck", "linux"),
|
||||
),
|
||||
"romm": Guide(
|
||||
summary="A web-based game library. It plays games in the browser "
|
||||
"through EmulatorJS.",
|
||||
folders=(
|
||||
("In the RomM library", "`bios/`, one subfolder per platform"),
|
||||
("With `firmware: \"{platform}/bios\"` in `config.yml`",
|
||||
"`<platform>/bios/` for each platform"),
|
||||
),
|
||||
run=("server",),
|
||||
dest="/path/to/library/bios",
|
||||
notes=("BIOS files can also be managed in RomM's web interface.",),
|
||||
),
|
||||
"rocknix": Guide(
|
||||
summary="A Linux system for ARM and x86 handhelds, among them the "
|
||||
"RG35XX (H700) and the RG552 (RK3399).",
|
||||
folders=(("On ROCKNIX", "`/storage/roms/bios/`"),),
|
||||
run=("device",),
|
||||
notes=("The folder is reachable over SSH and over the network share.",),
|
||||
),
|
||||
"amberelec": Guide(
|
||||
summary="A Linux system for Anbernic handhelds: RG351P, RG351V, "
|
||||
"RG351MP, RG353, RG503 and RG552.",
|
||||
folders=(("On AmberELEC", "`/storage/roms/`"),),
|
||||
run=("device",),
|
||||
notes=(
|
||||
"The AmberELEC list names files under `/storage/roms`: `bios/` for "
|
||||
"most, `neogeo/` for the rest. The pack holds those folders, so it "
|
||||
"is extracted into `/storage/roms/` itself.",
|
||||
),
|
||||
),
|
||||
"emuelec": Guide(
|
||||
summary="A Linux system for Amlogic TV boxes, the Odroid Go Advance, "
|
||||
"GameForce and RK356x devices.",
|
||||
folders=(("On EmuELEC", "`/storage/roms/`"),),
|
||||
run=("device",),
|
||||
notes=(
|
||||
"The EmuELEC list names files under `/storage/roms`: `bios/` for "
|
||||
"most, `neogeo/` and `ports/` for the rest. The pack holds those "
|
||||
"folders, so it is extracted into `/storage/roms/` itself.",
|
||||
),
|
||||
),
|
||||
"knulli": Guide(
|
||||
summary="A system for handhelds based on Batocera, among them the "
|
||||
"RG35XX family (H700) and the TrimUI Smart Pro.",
|
||||
folders=(("On KNULLI", "`/userdata/bios/`"),),
|
||||
run=("device",),
|
||||
),
|
||||
"retropie": Guide(
|
||||
summary="Scripts that install RetroArch and standalone emulators on "
|
||||
"Raspberry Pi OS.",
|
||||
folders=(("On the Raspberry Pi", "`~/RetroPie/BIOS/`"),),
|
||||
run=("device",),
|
||||
notes=(
|
||||
"Use the RetroPie pack, not the RetroArch one. RetroPie also "
|
||||
"installs standalone emulators (openMSX, PCSX2, XRoar, Amiberry and "
|
||||
"others) whose files only the RetroPie pack carries.",
|
||||
"A stock RetroPie 4.8 image ships Python 3.7, older than the "
|
||||
"installer needs. On it, download the RetroPie pack and extract it "
|
||||
"into `~/RetroPie/BIOS/`.",
|
||||
"RetroPie is archived in this project: its configuration is kept and "
|
||||
"its pack is still built, but its upstream list is no longer read "
|
||||
"again on a schedule.",
|
||||
),
|
||||
),
|
||||
"bizhawk": Guide(
|
||||
summary="A multi-system emulator with rerecording and debugging tools, "
|
||||
"hosted by TASVideos.",
|
||||
folders=(
|
||||
("Inside the BizHawk folder", "`Firmware\\`"),
|
||||
("Default place the installer looks", "`%USERPROFILE%\\BizHawk\\Firmware\\`"),
|
||||
),
|
||||
run=("windows", "linux"),
|
||||
),
|
||||
"misterfpga": Guide(
|
||||
summary="FPGA cores that recreate console hardware on a DE10-Nano board.",
|
||||
folders=(("On the MiSTer SD card", "`/media/fat/games/`, one subfolder per core"),),
|
||||
run=("device",),
|
||||
notes=(
|
||||
"Each file goes in the subfolder of its core, for example "
|
||||
"`/media/fat/games/3DO/boot.rom`. Only the files the MiSTer BIOS "
|
||||
"database lists with a download address are in the pack. The others "
|
||||
"come with the MiSTer distribution and install themselves.",
|
||||
),
|
||||
),
|
||||
"minui": Guide(
|
||||
summary="A frontend for handhelds that runs from the SD card.",
|
||||
folders=(("On the SD card", "`Bios/<TAG>/`, one folder per console"),),
|
||||
run=CARD_TERMINALS,
|
||||
on_card=True,
|
||||
notes=(
|
||||
"MinUI gives each console its own folder, named after the tag in "
|
||||
"parentheses of the Roms folder the game sits in. A game in "
|
||||
"`Roms/Sony PlayStation (PS)/` runs with `Bios/PS/` as its BIOS "
|
||||
"folder, one in `Roms/Game Boy (GB)/` with `Bios/GB/` (MinUI "
|
||||
"`workspace/all/minarch/minarch.c:2943`). The pack holds the `Bios/` "
|
||||
"folder: extract it at the root of the card.",
|
||||
"Without `--platform`, the installer reads the release name MinUI "
|
||||
"writes in `.system/version.txt` on the card. A console started by a "
|
||||
"standalone program instead of a libretro core (DraStic for NDS, "
|
||||
"native PICO-8) is not covered.",
|
||||
),
|
||||
),
|
||||
"nextui": Guide(
|
||||
summary="A frontend for handhelds derived from MinUI. It runs from the SD card.",
|
||||
folders=(("On the SD card", "`Bios/<TAG>/`, one folder per console"),),
|
||||
run=CARD_TERMINALS,
|
||||
on_card=True,
|
||||
notes=(
|
||||
"NextUI gives each console its own folder, named after the tag in "
|
||||
"parentheses of the Roms folder the game sits in: `Bios/PS/` for "
|
||||
"`Roms/Sony PlayStation (PS)/` (NextUI "
|
||||
"`workspace/all/minarch/ma_core.c:76`). The pack holds the `Bios/` "
|
||||
"folder: extract it at the root of the card.",
|
||||
),
|
||||
),
|
||||
"myminui": Guide(
|
||||
summary="A frontend for handhelds derived from MinUI. It runs from the SD card.",
|
||||
folders=(("On the SD card", "`Bios/<TAG>/`, one folder per console"),),
|
||||
run=CARD_TERMINALS,
|
||||
on_card=True,
|
||||
notes=(
|
||||
"MyMinUI gives each console its own folder, named after the tag in "
|
||||
"parentheses of the Roms folder the game sits in: `Bios/PS/` for "
|
||||
"`Roms/Sony PlayStation (PS)/` (MyMinUI "
|
||||
"`workspace/all/minarch/minarch.c:3532`). The pack holds the `Bios/` "
|
||||
"folder: extract it at the root of the card.",
|
||||
),
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def install_command(shell: str, args: str = "") -> str:
|
||||
"""The one-liner for a shell, with installer options when given.
|
||||
|
||||
PowerShell passes options only through a scriptblock: `irm ... | iex`
|
||||
takes none.
|
||||
"""
|
||||
if shell == "sh":
|
||||
return f"curl -fsSL {INSTALL_BASE}/install.sh | sh" + (f" -s -- {args}" if args else "")
|
||||
if args:
|
||||
return f"&([scriptblock]::Create((irm {INSTALL_BASE}/install.ps1))) {args}"
|
||||
return f"irm {INSTALL_BASE}/install.ps1 | iex"
|
||||
|
||||
|
||||
def _fence(shell: str, command: str, indent: str) -> list[str]:
|
||||
return [f"{indent}```{shell}", f"{indent}{command}", f"{indent}```"]
|
||||
|
||||
|
||||
def terminal_tabs(
|
||||
tabs: tuple[str, ...], args: dict[str, str], indent: str = "", steps: bool = True,
|
||||
) -> list[str]:
|
||||
"""Content tabs, one per place the command runs, each with how to open
|
||||
the terminal there. Tab labels are shared across the site, so the reader's
|
||||
choice carries from page to page."""
|
||||
lines: list[str] = []
|
||||
for key in tabs:
|
||||
label, how, shell = TERMINALS[key]
|
||||
lines += [f'{indent}=== "{label}"', ""]
|
||||
if steps:
|
||||
lines += [f"{indent} {how}", ""]
|
||||
lines += _fence(shell, install_command(shell, args.get(key, "")), indent + " ")
|
||||
lines.append("")
|
||||
return lines
|
||||
|
||||
|
||||
def platform_args(name: str, guide: Guide) -> dict[str, str]:
|
||||
"""The options of the command on a platform page, per tab."""
|
||||
args: dict[str, str] = {}
|
||||
for key in guide.run:
|
||||
if guide.on_card:
|
||||
card = "E:\\" if key == "windows" else "/path/to/card"
|
||||
args[key] = f"--platform {name} --dest {card}"
|
||||
elif guide.dest:
|
||||
args[key] = f"--platform {name} --dest {guide.dest}"
|
||||
else:
|
||||
args[key] = f"--platform {name}"
|
||||
return args
|
||||
|
||||
|
||||
TRUST_NOTE = (
|
||||
"The line downloads a small script from this project on GitHub. The script "
|
||||
"checks the installer against a fingerprint it carries, then the installer "
|
||||
"downloads the files your setup needs and checks each one before saving it. "
|
||||
"It writes only inside your BIOS folder. A BIOS file whose contents differ "
|
||||
"from the expected one is replaced with a checked copy, and files it does "
|
||||
"not know are never moved or deleted. Games and saves are never touched."
|
||||
)
|
||||
|
||||
|
||||
def trust_box(prefix: str, indent: str = "") -> list[str]:
|
||||
"""What the command does, under every command on a guide page."""
|
||||
return [
|
||||
f'{indent}??? note "What this command does"',
|
||||
"",
|
||||
f"{indent} {TRUST_NOTE} "
|
||||
f"[Read the script first]({prefix}wiki/faq.md#is-piping-the-installer-into-a-shell-safe).",
|
||||
"",
|
||||
]
|
||||
@@ -20,6 +20,10 @@ _produced: set[str] = set()
|
||||
def _record(path: str | Path) -> None:
|
||||
_produced.add(os.path.realpath(str(path)))
|
||||
|
||||
# The reader level label the decoration pass puts above a page's title.
|
||||
LEVEL_LABEL_START = '<span class="rb-level '
|
||||
|
||||
|
||||
def _undecorated(markdown: str) -> str:
|
||||
"""Return a page body without the front matter the decoration pass adds."""
|
||||
if markdown.startswith("---\n") and "generated_by: retrobios-site" in markdown[:300]:
|
||||
@@ -29,6 +33,8 @@ def _undecorated(markdown: str) -> str:
|
||||
script_end = markdown.find("</script>\n\n")
|
||||
if markdown.startswith('<script type="application/ld+json">') and script_end != -1:
|
||||
markdown = markdown[script_end + len("</script>\n\n"):]
|
||||
if markdown.startswith(LEVEL_LABEL_START):
|
||||
markdown = markdown[markdown.find("\n\n") + 2:]
|
||||
return markdown
|
||||
|
||||
def write_if_changed(path: str, content: str) -> bool:
|
||||
|
||||
+19
-2
@@ -730,7 +730,8 @@ class RetroArchWindowsSystemFolder(unittest.TestCase):
|
||||
"""Getting started gave %APPDATA%\\RetroArch\\system for the Windows
|
||||
installer. RetroArch's default is `:\\system`, the folder of
|
||||
retroarch.exe (platform_win32.c). %APPDATA% is where a retroarch.cfg
|
||||
can live, and install.py reads it there."""
|
||||
can live, and install.py reads it there. The RetroArch page of the site
|
||||
states the folder now, from the guide data."""
|
||||
|
||||
def test_page_and_installer_agree(self):
|
||||
import install
|
||||
@@ -738,10 +739,26 @@ class RetroArchWindowsSystemFolder(unittest.TestCase):
|
||||
source = inspect.getsource(install)
|
||||
self.assertIn('ra_dir or exe_dir / "system"', source)
|
||||
self.assertTrue(str(install._os_default_dests("windows")["retroarch"]).replace("\\", "/").endswith("/system"))
|
||||
section = _section(_page("getting-started.md"), "RetroArch")
|
||||
from siteguides import GUIDES
|
||||
|
||||
guide = GUIDES["retroarch"]
|
||||
section = "\n".join([*(path for _label, path in guide.folders), *guide.notes])
|
||||
self.assertNotIn("%APPDATA%\\RetroArch\\system", section)
|
||||
self.assertIn("`system\\` next to `retroarch.exe`", section)
|
||||
|
||||
def test_the_macos_folder_is_the_installers(self):
|
||||
"""The site gave Application Support/RetroArch/system for macOS. A
|
||||
RetroArch left at its defaults reads ~/Documents/RetroArch/system
|
||||
(platform_darwin.m), Application Support only for a portable or
|
||||
Steam build, and install.py looks there in that order."""
|
||||
import install
|
||||
from siteguides import GUIDES
|
||||
|
||||
source = inspect.getsource(install._macos_retroarch_base)
|
||||
self.assertIn('Path.home() / "Documents" / "RetroArch"', source)
|
||||
folders = dict(GUIDES["retroarch"].folders)
|
||||
self.assertEqual(folders["macOS"], "`~/Documents/RetroArch/system/`")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
+17
-11
@@ -75,22 +75,25 @@ def _which_pack() -> str:
|
||||
|
||||
class TheDownloadTablesFollowTheRegistry(unittest.TestCase):
|
||||
"""EmuDeck has a Windows edition the installer detects, and the Windows
|
||||
table of the download page left it out."""
|
||||
table of the download page left it out. The page is grouped by device
|
||||
now: the row of each platform names every system it is detected on."""
|
||||
|
||||
def test_every_detected_system_lists_the_platform(self):
|
||||
import yaml # noqa: PLC0415
|
||||
|
||||
from common import load_platform_config # noqa: PLC0415
|
||||
|
||||
registry = yaml.safe_load(_read("platforms/_registry.yml"))
|
||||
names = {"retroarch": "RetroArch", "retrobat": "RetroBat", "emudeck": "EmuDeck",
|
||||
"bizhawk": "BizHawk"}
|
||||
page = _which_pack()
|
||||
for os_name, heading in (("windows", "### Windows"), ("darwin", "### macOS")):
|
||||
table = _section(page, heading)
|
||||
for os_name, label in (("windows", "Windows"), ("darwin", "macOS")):
|
||||
for platform, entry in registry["platforms"].items():
|
||||
systems = {rule["os"] for rule in (entry.get("install") or {}).get("detect", [])}
|
||||
if os_name in systems:
|
||||
name = load_platform_config(platform, "platforms")["platform"]
|
||||
row = next(line for line in page.splitlines()
|
||||
if line.startswith(f"| [{name}]("))
|
||||
with self.subTest(os=os_name, platform=platform):
|
||||
self.assertIn(f"[{names[platform]}](", table)
|
||||
self.assertIn(label, row.split(" | ")[2])
|
||||
|
||||
|
||||
class DownloadLinksNameTheFile(unittest.TestCase):
|
||||
@@ -159,9 +162,10 @@ class DownloadLinksNameTheFile(unittest.TestCase):
|
||||
for asset in pack["assets"]:
|
||||
self.assertIn(f"/releases/download/{RECORD['tag']}/{asset})", page)
|
||||
|
||||
def test_a_platform_the_release_lacks_has_no_row(self):
|
||||
def test_a_platform_the_release_lacks_links_no_release(self):
|
||||
"""KNULLI, AmberELEC and EmuELEC were registered after the recorded
|
||||
release: a row for them linked a release page holding no such pack."""
|
||||
release: a row for them linked a release page holding no such pack.
|
||||
Every platform is on the picker now, so the row offers the command."""
|
||||
if not RECORD.get("packs"):
|
||||
self.skipTest("release.json is not written")
|
||||
from common import list_registered_platforms, load_platform_config
|
||||
@@ -172,8 +176,10 @@ class DownloadLinksNameTheFile(unittest.TestCase):
|
||||
if pack_for(key, RECORD) is not None:
|
||||
continue
|
||||
label = load_platform_config(key, "platforms").get("platform", key)
|
||||
row = next(line for line in page.splitlines() if line.startswith(f"| [{label}]("))
|
||||
with self.subTest(platform=key):
|
||||
self.assertNotIn(f"| [{label}](", page)
|
||||
self.assertNotIn("/releases/", row)
|
||||
self.assertIn(f"Not in {RECORD['tag']}: [use the command](platforms/{key}.md#install)", row)
|
||||
|
||||
|
||||
class SlicesLeaveWithTheirRelease(unittest.TestCase):
|
||||
@@ -205,7 +211,7 @@ class EndUsersCheckTheirOwnFolder(unittest.TestCase):
|
||||
("wiki/troubleshooting.md", "## Game won't start / black screen"),
|
||||
("wiki/faq.md", "## My game shows a black screen"),
|
||||
("wiki/faq.md", "## How do I know which BIOS I need?"),
|
||||
("wiki/getting-started.md", "## Checking what you installed"),
|
||||
("wiki/troubleshooting.md", "## Checking what you installed"),
|
||||
)
|
||||
|
||||
def test_user_sections_never_send_to_verify(self):
|
||||
@@ -263,7 +269,7 @@ class ShownOutputIsPrintedOutput(unittest.TestCase):
|
||||
self.assertIn(literal, source)
|
||||
|
||||
def test_samples_match_a_shape(self):
|
||||
section = _section(_read("wiki/troubleshooting.md"), "### Reading the output")
|
||||
section = _section(_read("wiki/verification-modes.md"), "### Reading the output")
|
||||
blocks = re.findall(r"```\n(.*?)```", section, re.DOTALL)
|
||||
self.assertTrue(blocks)
|
||||
for block in blocks:
|
||||
|
||||
@@ -902,8 +902,13 @@ class TheOneLinerIsWhereUsersLand(unittest.TestCase):
|
||||
"verified": 0, "missing": 0, "details": [], "config": {"systems": {}}}
|
||||
page = generate_site.generate_platform_page("batocera", cov)
|
||||
self.assertIn("install.sh | sh -s -- --platform batocera", page)
|
||||
self.assertIn("install.ps1))) --platform batocera", page)
|
||||
self.assertLess(page.index("--platform batocera"), page.index("md-button"))
|
||||
# Batocera runs the command on the device itself. A platform detected
|
||||
# on Windows gets the PowerShell form.
|
||||
cov = dict(cov, platform="RetroArch", mode="existence")
|
||||
page = generate_site.generate_platform_page("retroarch", cov)
|
||||
self.assertIn("install.ps1))) --platform retroarch", page)
|
||||
self.assertIn("install.sh | sh -s -- --platform retroarch", page)
|
||||
|
||||
entry = {"name": "a.bin", "sha1": "a" * 40, "md5": "b" * 32, "size": 3,
|
||||
"path": "bios/Recalbox/MSX/a.bin"}
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
"""The site reads as a funnel, from someone who knows nothing to a contributor.
|
||||
|
||||
Five tabs in reading order, every registered platform reachable from the
|
||||
device picker, a level on every page, and no page for beginners sending its
|
||||
reader two levels deeper without saying so.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
||||
|
||||
import generate_site # noqa: E402
|
||||
from common import list_registered_platforms, load_platform_config, load_platform_registry # noqa: E402
|
||||
from siteguides import DEVICE_GROUPS, GROUP_ANCHORS, GUIDES # noqa: E402
|
||||
|
||||
DOCS = REPO_ROOT / "docs"
|
||||
ORDER = list(generate_site.LEVELS)
|
||||
LINK = re.compile(r"\[[^\]]*\]\(([^)\s#]+\.md)(?:#[^)]*)?\)")
|
||||
FENCED = re.compile(r"^\s*```.*?^\s*```", re.S | re.M)
|
||||
|
||||
|
||||
def _registered() -> list[str]:
|
||||
return list_registered_platforms(str(REPO_ROOT / "platforms"), include_archived=True)
|
||||
|
||||
|
||||
def _which_pack() -> str:
|
||||
with contextlib.chdir(REPO_ROOT):
|
||||
return generate_site.generate_which_pack()
|
||||
|
||||
|
||||
def _docs_pages() -> list[Path]:
|
||||
if not DOCS.is_dir() or not (DOCS / "index.md").is_file():
|
||||
if os.environ.get("CI"):
|
||||
raise AssertionError("CI generates docs/ before the suite")
|
||||
raise unittest.SkipTest("docs/ not generated (python scripts/generate_site.py)")
|
||||
skipped = set(generate_site.LOCAL_NOTE_DIRS)
|
||||
return [p for p in sorted(DOCS.rglob("*.md"))
|
||||
if not set(p.relative_to(DOCS).parts[:-1]) & skipped]
|
||||
|
||||
|
||||
def _level(page: Path) -> str:
|
||||
return str(generate_site._front_matter(page.read_text(encoding="utf-8")).get("level") or "")
|
||||
|
||||
|
||||
class FiveTabs(unittest.TestCase):
|
||||
"""Twelve tabs put the walkthrough at position eleven, under "Wiki"."""
|
||||
|
||||
def test_the_tabs_in_reading_order(self):
|
||||
nav = generate_site.generate_mkdocs_nav({}, {}, {}, {})
|
||||
self.assertEqual(
|
||||
[next(iter(tab)) for tab in nav],
|
||||
["Start here", "Your setup", "Explore", "Reference", "Contribute"],
|
||||
)
|
||||
|
||||
def test_each_tab_opens_on_an_index_or_a_first_page(self):
|
||||
nav = generate_site.generate_mkdocs_nav({}, {}, {}, {})
|
||||
tabs = {next(iter(tab)): next(iter(tab.values())) for tab in nav}
|
||||
self.assertEqual(tabs["Start here"][0], "index.md")
|
||||
self.assertEqual(tabs["Your setup"][0], "platforms/index.md")
|
||||
self.assertEqual(tabs["Reference"][0], "wiki/index.md")
|
||||
self.assertEqual(tabs["Contribute"][0], "contributing.md")
|
||||
|
||||
def test_the_breadcrumbs_are_on(self):
|
||||
source = (REPO_ROOT / "scripts" / "generate_site.py").read_text(encoding="utf-8")
|
||||
self.assertIn(" - navigation.path\n", source)
|
||||
|
||||
|
||||
class EveryPlatformOnThePicker(unittest.TestCase):
|
||||
"""KNULLI, MinUI, AmberELEC, EmuELEC, NextUI and MyMinUI were on no table
|
||||
of the download page: a hand-written list leaves out what it forgets."""
|
||||
|
||||
def test_every_platform_has_a_group_and_a_guide(self):
|
||||
registry = load_platform_registry(str(REPO_ROOT / "platforms"))
|
||||
for key in _registered():
|
||||
with self.subTest(platform=key):
|
||||
self.assertIn(registry[key].get("device_group"), DEVICE_GROUPS)
|
||||
self.assertIn(key, GUIDES)
|
||||
|
||||
def test_every_group_has_an_anchor(self):
|
||||
self.assertEqual(set(GROUP_ANCHORS), set(DEVICE_GROUPS))
|
||||
|
||||
def test_every_platform_has_a_row(self):
|
||||
page = _which_pack()
|
||||
for key in _registered():
|
||||
name = load_platform_config(key, str(REPO_ROOT / "platforms"))["platform"]
|
||||
with self.subTest(platform=key):
|
||||
self.assertIn(f"| [{name}](platforms/{key}.md) |", page)
|
||||
|
||||
def test_every_platform_is_in_the_navigation_of_its_group(self):
|
||||
registry = load_platform_registry(str(REPO_ROOT / "platforms"))
|
||||
coverages = {
|
||||
key: {"platform": load_platform_config(key, str(REPO_ROOT / "platforms"))["platform"]}
|
||||
for key in _registered()
|
||||
}
|
||||
nav = generate_site.generate_mkdocs_nav(coverages, {}, {}, registry)
|
||||
setup = next(tab["Your setup"] for tab in nav if "Your setup" in tab)
|
||||
groups = {next(iter(item)): next(iter(item.values()))
|
||||
for item in setup if isinstance(item, dict)}
|
||||
for key in coverages:
|
||||
label = DEVICE_GROUPS[registry[key]["device_group"]][0]
|
||||
with self.subTest(platform=key):
|
||||
self.assertIn({coverages[key]["platform"]: f"platforms/{key}.md"}, groups[label])
|
||||
|
||||
def test_handheld_systems_that_run_retroarch_are_named(self):
|
||||
"""muOS, ArkOS and the rest are detected as RetroArch by the
|
||||
installer and were named on no page a user reads."""
|
||||
page = _which_pack()
|
||||
self.assertIn("| muOS | [RetroArch](platforms/retroarch.md) | `/run/muos/storage/bios` |", page)
|
||||
self.assertNotIn("| TrimUI |", page)
|
||||
|
||||
|
||||
class SampleCoresLeaveTheNavigation(unittest.TestCase):
|
||||
"""13 libretro sample cores (testsw, testgl_ff...) sat in the emulators
|
||||
navigation among the cores people look up."""
|
||||
|
||||
def test_a_core_with_no_system_and_no_file_is_left_out(self):
|
||||
profiles = {
|
||||
"testsw": {"emulator": "testsw", "type": "libretro", "systems": []},
|
||||
"duckstation": {"emulator": "DuckStation", "type": "standalone",
|
||||
"systems": ["sony-playstation"], "files": [{"name": "a.bin"}]},
|
||||
"zx": {"emulator": "zx81", "type": "libretro", "systems": ["sinclair-zx81"]},
|
||||
}
|
||||
nav = generate_site._emulator_nav(profiles)
|
||||
self.assertEqual(nav[0], "emulators/index.md")
|
||||
groups = {next(iter(group)): next(iter(group.values())) for group in nav[1:]}
|
||||
self.assertEqual(groups, {
|
||||
"D to F": [{"DuckStation": "emulators/duckstation.md"}],
|
||||
"V to Z": [{"zx81": "emulators/zx.md"}],
|
||||
})
|
||||
|
||||
|
||||
class EveryPageHasALevel(unittest.TestCase):
|
||||
def test_wiki_sources_declare_one(self):
|
||||
for page in sorted((REPO_ROOT / "wiki").glob("*.md")):
|
||||
level = generate_site._front_matter(page.read_text(encoding="utf-8")).get("level")
|
||||
with self.subTest(page=page.name):
|
||||
self.assertIn(level, generate_site.LEVELS)
|
||||
|
||||
def test_every_generated_page_has_one_and_its_label(self):
|
||||
for page in _docs_pages():
|
||||
text = page.read_text(encoding="utf-8")
|
||||
level = _level(page)
|
||||
with self.subTest(page=str(page.relative_to(DOCS))):
|
||||
self.assertIn(level, generate_site.LEVELS)
|
||||
self.assertIn(generate_site.level_label(level), text)
|
||||
|
||||
def test_the_decoration_keeps_an_authored_level(self):
|
||||
with tempfile.TemporaryDirectory(dir=REPO_ROOT / "tmp") as tmp:
|
||||
page = Path(tmp) / "wiki" / "faq.md"
|
||||
page.parent.mkdir()
|
||||
page.write_text("---\nlevel: start\n---\n\n# FAQ\n\nQuestions people ask first.\n")
|
||||
generate_site.decorate_markdown_pages(Path(tmp))
|
||||
generate_site.decorate_markdown_pages(Path(tmp))
|
||||
text = page.read_text()
|
||||
self.assertEqual(text.count("level: start"), 1)
|
||||
self.assertEqual(text.count(generate_site.level_label("start")), 1)
|
||||
self.assertIn(" boost: 5\n", text)
|
||||
self.assertIn("# FAQ\n", text)
|
||||
|
||||
|
||||
class DeepLinksCarryALabel(unittest.TestCase):
|
||||
"""A beginner page sent its reader to Tools and Architecture as the next
|
||||
step. A link from a start or setup page to a page two levels deeper or
|
||||
more says what it leads to, with that page's level label before it on
|
||||
its line, or in the heading of its section ("## Reference: ...")."""
|
||||
|
||||
def test_start_and_setup_pages(self):
|
||||
pages = _docs_pages()
|
||||
levels = {page: _level(page) for page in pages}
|
||||
offenders = []
|
||||
for page, level in levels.items():
|
||||
if level not in ("start", "setup"):
|
||||
continue
|
||||
text = FENCED.sub("", page.read_text(encoding="utf-8"))
|
||||
heading = ""
|
||||
for line in text.splitlines():
|
||||
if re.match(r"#{1,3} ", line):
|
||||
heading = line.lstrip("#").strip()
|
||||
for match in LINK.finditer(line):
|
||||
target = (page.parent / match.group(1)).resolve()
|
||||
if target not in levels:
|
||||
continue
|
||||
deeper = levels[target]
|
||||
if ORDER.index(deeper) - ORDER.index(level) < 2:
|
||||
continue
|
||||
label = f"{generate_site.LEVELS[deeper]}:"
|
||||
if label not in line[: match.start()] and not heading.startswith(label):
|
||||
offenders.append(f"{page.relative_to(DOCS)}: {match.group(0)}")
|
||||
self.assertEqual(offenders, [], "\n".join(offenders[:30]))
|
||||
|
||||
|
||||
class GuidePagesEndOnANextStep(unittest.TestCase):
|
||||
def test_home_picker_and_platform_page(self):
|
||||
for page in ("index.md", "which-pack.md", "platforms/batocera.md",
|
||||
"wiki/first-install.md", "wiki/troubleshooting.md",
|
||||
"wiki/what-are-bios-files.md", "wiki/faq.md"):
|
||||
path = DOCS / page if page.startswith(("index", "which", "platforms")) else REPO_ROOT / page
|
||||
if not path.is_file():
|
||||
_docs_pages()
|
||||
with self.subTest(page=page):
|
||||
text = path.read_text(encoding="utf-8")
|
||||
self.assertTrue('!!! tip "Next"' in text or "## What comes next" in text)
|
||||
|
||||
def test_the_platform_page_opens_on_its_guide(self):
|
||||
"""The folder came after four counters and a metadata table, and was
|
||||
the pack-relative `bios/` where Batocera reads /userdata/bios/."""
|
||||
text = (DOCS / "platforms" / "batocera.md").read_text(encoding="utf-8") \
|
||||
if (DOCS / "platforms" / "batocera.md").is_file() else _docs_pages()
|
||||
order = [text.index(h) for h in (
|
||||
"## Where the files go", "## Install", "## Download", "## How to check",
|
||||
"## Reference: every file by system",
|
||||
)]
|
||||
self.assertEqual(order, sorted(order))
|
||||
self.assertLess(text.index("`/userdata/bios/`"), text.index("rb-stat-value"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
level: contribute
|
||||
---
|
||||
|
||||
# Adding a platform
|
||||
|
||||
How to add support for a new retrogaming platform (e.g. a frontend like Batocera,
|
||||
@@ -146,6 +150,7 @@ platforms:
|
||||
myplatform:
|
||||
config: myplatform.yml # platform YAML filename in platforms/
|
||||
status: active # active or archived
|
||||
device_group: handheld # computer, gaming-os, handheld, fpga or server
|
||||
scraper: myplatform # matches PLATFORM_NAME, null if hand-maintained
|
||||
schedule: weekly # re-scrape cadence, run by hand: weekly, monthly, or null
|
||||
source_url: https://... # upstream data URL
|
||||
@@ -159,6 +164,13 @@ platforms:
|
||||
- core_b
|
||||
```
|
||||
|
||||
`device_group` places the platform among the devices a reader picks from: on
|
||||
the site's "Get your files" page, in the "Your setup" navigation and on the home
|
||||
page. The groups and their labels are `DEVICE_GROUPS` in
|
||||
`scripts/siteguides.py`, and the same file holds the platform's guide text
|
||||
(what it is, where its BIOS folder is, where the install command runs). A
|
||||
test fails when a registered platform has no group or no guide.
|
||||
|
||||
A platform without a scraper (`scraper: null`, `schedule: null`) keeps its YAML
|
||||
as a hand-maintained file. Every registered platform has a scraper today, so
|
||||
none is edited by hand: RetroPie inherits RetroArch's file set and its scraper
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
level: contribute
|
||||
---
|
||||
|
||||
# Adding a scraper
|
||||
|
||||
How to create or modify a scraper for fetching BIOS requirements from upstream
|
||||
|
||||
+20
-1
@@ -1,7 +1,26 @@
|
||||
# Advanced usage
|
||||
---
|
||||
level: reference
|
||||
---
|
||||
|
||||
# Build your own packs
|
||||
|
||||
Fine-grained control over pack generation, hardware filtering, truth analysis, and verification.
|
||||
|
||||
The [latest release](https://github.com/Abdess/retrobios/releases/latest)
|
||||
carries one pack for each platform, and that pack holds everything the
|
||||
platform runs: the BIOS list it publishes, plus every file its emulator cores
|
||||
load, read from their source code. There is no lighter variant to choose,
|
||||
because a pack that leaves out a file a core needs means a game that does not
|
||||
boot, with no message saying why. It is not a guarantee either: source
|
||||
profiles can document files nobody has dumped or that only the user can
|
||||
provide, all of them visible in the [gap analysis](../gaps.md).
|
||||
|
||||
From a clone of the repository, `python scripts/generate_pack.py --platform
|
||||
retroarch --region us` builds a narrower pack, `--required-only` the bare
|
||||
minimum each core needs to start, and `--no-game-data` keeps the firmware and
|
||||
leaves out the files a game reads. `--help` lists every way to build your own,
|
||||
and the sections below describe each one.
|
||||
|
||||
## Custom packs
|
||||
|
||||
### Build from hash
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
level: reference
|
||||
---
|
||||
|
||||
# Architecture
|
||||
|
||||
## Principles
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
# Community tools
|
||||
---
|
||||
level: reference
|
||||
---
|
||||
|
||||
# Projects using this data
|
||||
|
||||
Projects built on RetroBIOS data.
|
||||
|
||||
|
||||
+90
-127
@@ -1,89 +1,19 @@
|
||||
---
|
||||
level: start
|
||||
---
|
||||
|
||||
# FAQ
|
||||
|
||||
## My game shows a black screen
|
||||
The questions people ask before installing anything. Questions about how files
|
||||
are identified and checked are in the
|
||||
Reference: [technical questions](technical-faq.md).
|
||||
|
||||
Most likely a missing or incorrect BIOS file. Check what is in the BIOS folder:
|
||||
## Do I need BIOS files?
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh -s -- --check
|
||||
```
|
||||
|
||||
The count it ends on says what is wrong. A number after `wrong hash` means a
|
||||
file is there whose contents the platform will reject, so it is the wrong
|
||||
version or a bad dump, and running the install again replaces it. Files that
|
||||
are absent are counted as needing downloading.
|
||||
|
||||
Some cores also support HLE (see below), so a missing BIOS may not always be the cause. Check the emulator's logs for error messages.
|
||||
|
||||
## What's the difference between required and optional?
|
||||
|
||||
**Required** means the emulator will not start games for that system without the file. **Optional** means the emulator works without it, but with reduced accuracy or missing features (e.g., boot screen animation, wrong font rendering, or degraded audio).
|
||||
|
||||
In verification output, missing required files appear as CRITICAL or WARNING depending on the platform. Missing optional files appear as WARNING or INFO.
|
||||
|
||||
## What's HLE?
|
||||
|
||||
HLE (High-Level Emulation) is a software reimplementation of what the original BIOS does. Some cores can boot games without a real BIOS file by using their built-in HLE fallback. The trade-off is lower accuracy: some games may have glitches or fail to boot entirely.
|
||||
|
||||
When a core has HLE support, the verification tool lowers the severity of a missing BIOS to INFO. The file is still included in packs because the real BIOS gives better results.
|
||||
|
||||
## Why are there multiple hashes for the same file?
|
||||
|
||||
Two main reasons:
|
||||
|
||||
1. **Regional variants.** The same filename (e.g., `IPL.bin` for GameCube) exists in different versions for USA, Europe, and Japan. Each region has a different hash.
|
||||
2. **Revision differences.** Console manufacturers released updated BIOS versions over time. A PlayStation SCPH-5501 BIOS differs from a SCPH-7001.
|
||||
|
||||
Platforms that verify by MD5 accept specific hashes. If yours doesn't match any known hash, it may be a bad dump or an uncommon revision.
|
||||
|
||||
A filename is never allowed to stand in for a declared hash. When a file entry
|
||||
carries a hash, resolution matches on content and reports `hash_mismatch` if the
|
||||
only same-named copy disagrees. What happens next depends on the platform: an
|
||||
MD5 or SHA1 platform would reject the file, so the pack omits it and says why,
|
||||
while an existence platform only checks presence, so the file ships and the divergence
|
||||
is reported instead.
|
||||
|
||||
## Why are there files that aren't BIOS?
|
||||
|
||||
A file earns its place when an emulator loads it from disk and does not bundle it. That covers actual BIOS ROMs, console firmware, arcade BIOS sets, and also game data like `prboom.wad` for the PrBoom core or soundfonts for EasyRPG.
|
||||
|
||||
This follows the platforms themselves: Batocera lists `prboom.wad` in its BIOS checker, and libretro declares these files in the `firmware` field of its core info. The word "BIOS" is their vocabulary for "external file the emulator needs". Files are tagged by category (`bios`, `game_data`, `bios_zip`) in the emulator profiles, so the distinction stays visible.
|
||||
|
||||
## Are these files verified against original hardware dumps?
|
||||
|
||||
No, and that is a deliberate boundary. The hashes here document what
|
||||
emulator code loads and accepts, read from the source. When several
|
||||
revisions or regions pass, all of them are kept (`.variants/` in the
|
||||
repository, per-emulator pages list each one), and the pack ships the
|
||||
variant satisfying the most checks, logging any conflict it cannot
|
||||
resolve.
|
||||
|
||||
Whether a file byte-matches the original hardware ROM is a different
|
||||
question, answered by dump-preservation catalogs such as No-Intro,
|
||||
Redump, and TOSEC, not by emulator code. The collection is
|
||||
cross-referenced against their DATs: files matching a catalog entry
|
||||
carry a verified dump badge on the system pages, and catalog entries
|
||||
absent from the collection are tracked as acquisition targets. When
|
||||
the two views differ, this project follows the code, because that is
|
||||
what decides whether your emulator boots.
|
||||
|
||||
The [dump provenance](../provenance.md) page has the current coverage
|
||||
per catalog and the full list of catalogued dumps still missing.
|
||||
|
||||
## Which MAME version do the arcade BIOS sets match?
|
||||
|
||||
Arcade BIOS sets are coupled to the romset version, so there is one
|
||||
profile per MAME core generation: MAME 2000 (0.37b5), MAME 2003 (0.78),
|
||||
MAME 2003-Plus, MAME 2009 (0.135u4), MAME 2010 (0.139), MAME 2015
|
||||
(0.160), MAME 2016 (0.174), and current MAME (0.289), each read from that
|
||||
version's own source tree, because the BIOS root sets differ between
|
||||
versions. Derivatives and ports carry their own profiles on top of those
|
||||
generations: `mamearcade`, `mamemess`, `mame2003_midway`, the three
|
||||
`mame4droid` drops, `advancemame`, `groovymame` and `hbmame`. Recalbox
|
||||
compiles two MAME versions of its own, 0.258 and 0.278, profiled as
|
||||
`mame0258` and `mame0278`. The pack
|
||||
ships the sets matching the core you run, and a generic unversioned arcade
|
||||
pack cannot do that.
|
||||
For many consoles, yes: PlayStation, PlayStation 2, Saturn, Mega-CD, Neo Geo,
|
||||
Dreamcast and many home computers. For cartridge consoles such as the NES or
|
||||
the Super Nintendo, usually not. [What BIOS files are](what-are-bios-files.md)
|
||||
explains why, console by console.
|
||||
|
||||
## How do I know which BIOS I need?
|
||||
|
||||
@@ -117,7 +47,23 @@ curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh -o
|
||||
less install.sh && sh install.sh
|
||||
```
|
||||
|
||||
See [Installer](installer.md) for the full behaviour.
|
||||
Details: [All installer options](installer.md), with the full behaviour.
|
||||
|
||||
## Will the installer change my other files?
|
||||
|
||||
No. It writes only inside the BIOS folder, and games and saves are never
|
||||
touched. Inside that folder, a BIOS file whose contents differ from the
|
||||
expected one is replaced with a checked copy. Files the installer does not
|
||||
know are never read, moved or deleted. Copies into the folders of standalone
|
||||
emulators happen only when you ask for them with `--standalone-copies`.
|
||||
|
||||
## What if Windows or an antivirus blocks the command?
|
||||
|
||||
The PowerShell execution policy governs script files, and the PowerShell line
|
||||
writes none, so the policy does not block it. Where a security tool still
|
||||
blocks it, download the pack of your setup from
|
||||
[Get your files](../which-pack.md) and extract it into the BIOS folder: it holds
|
||||
the same files.
|
||||
|
||||
## Can I run the installer again?
|
||||
|
||||
@@ -127,6 +73,11 @@ replaced by the verified copy, and files the manifest does not name are never
|
||||
read, moved or deleted. `--check` does the same inspection and exits without
|
||||
writing.
|
||||
|
||||
## Can I undo it?
|
||||
|
||||
Yes. Delete the files from your BIOS folder. The installer changed nothing
|
||||
outside that folder.
|
||||
|
||||
## Can I install onto an SD card or another machine's drive?
|
||||
|
||||
Yes, `--dest` takes any path and the one-liner forwards arguments:
|
||||
@@ -140,7 +91,17 @@ curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh \
|
||||
RetroArch on Switch, `RetroArch/system` on Android.
|
||||
|
||||
On Windows the arguments need a script block, since `iex` would read them as
|
||||
its own. The form is on the [Installer](installer.md#passing-options) page.
|
||||
its own. Details: [the Windows form](installer.md#passing-options).
|
||||
|
||||
## Can I use BIOS from one platform on another?
|
||||
|
||||
Yes. BIOS files are console-specific, not platform-specific. A PlayStation BIOS works in RetroArch, Batocera, Recalbox, and any other platform that emulates PlayStation. The only differences between platforms are:
|
||||
|
||||
- **Where the file goes** (each platform has its own BIOS directory)
|
||||
- **What filename is expected** (usually the same, occasionally different)
|
||||
- **How verification works** (MD5 check vs. existence check)
|
||||
|
||||
The packs differ per platform because each platform declares its own set of supported systems and expected files.
|
||||
|
||||
## Why is a file the emulator reads not in the pack?
|
||||
|
||||
@@ -153,6 +114,47 @@ a standalone PPSSPP pack does not. When a platform's own package installs data
|
||||
beside a core (Batocera with blueMSX), that platform's pack leaves it out too. The
|
||||
emulator's page on the site marks these files as installed with the emulator.
|
||||
|
||||
## How often are packs updated?
|
||||
|
||||
Upstream sources (libretro System.dat, batocera-systems, etc.) are re-scraped by hand and the diff is reviewed before it lands. Releases happen as needed when new BIOS files are added or profiles are updated.
|
||||
|
||||
## What's the difference between required and optional?
|
||||
|
||||
**Required** means the emulator will not start games for that system without
|
||||
the file. **Optional** means the emulator works without it, but with reduced
|
||||
accuracy or missing features (e.g., boot screen animation, wrong font
|
||||
rendering, or degraded audio).
|
||||
|
||||
## What's HLE?
|
||||
|
||||
HLE (High-Level Emulation) is a software reimplementation of what the original
|
||||
BIOS does. Some cores can boot games without a real BIOS file by using their
|
||||
built-in HLE fallback. The trade-off is lower accuracy: some games may have
|
||||
glitches or fail to boot entirely. The file is still included in packs because
|
||||
the real BIOS gives better results.
|
||||
|
||||
## What's a hash?
|
||||
|
||||
A hash is a fingerprint computed from a file's contents. If even one byte
|
||||
differs, the hash changes completely. Batocera, Recalbox, EmuDeck and several
|
||||
other setups compare the MD5 hash of each BIOS file with their list and refuse
|
||||
a file that does not match. RetroArch only checks that the file is there. The
|
||||
kinds of hash and where each is used are in the
|
||||
Reference: [technical questions](technical-faq.md#whats-a-hashchecksum).
|
||||
|
||||
## Are these files verified against original hardware dumps?
|
||||
|
||||
The hashes here come from what emulator code loads and accepts. Whether a file
|
||||
matches a catalogued dump of the original chip is a separate question, and the
|
||||
system pages mark the files that do. The full answer is in the
|
||||
Reference: [technical questions](technical-faq.md#are-these-files-verified-against-original-hardware-dumps).
|
||||
|
||||
## My game shows a black screen
|
||||
|
||||
Most often a BIOS file is missing, or is not the version the emulator expects.
|
||||
[When a game does not start](troubleshooting.md) goes through it step by step,
|
||||
starting with a check of what is in your BIOS folder.
|
||||
|
||||
## Is this legal?
|
||||
|
||||
Redistributing firmware is not settled law, and this page does not pretend otherwise. What follows is the reasoning the project acts on, with the strength of each argument stated plainly so anyone can weigh it. None of it is legal advice, and none of it has been tested in court.
|
||||
@@ -196,47 +198,8 @@ Age is not what decides inclusion here: availability is. Firmware distribution d
|
||||
|
||||
The project tries to archive files while they are still available rather than after they have become rare. "Retro" is a moving window: the PlayStation 2 was current hardware when its BIOS was first preserved, and today's consoles will be tomorrow's retro systems. A file is included for the same reason at any age: an emulator needs it, and nothing guarantees it stays available.
|
||||
|
||||
## What's a hash/checksum?
|
||||
!!! tip "Next"
|
||||
|
||||
A hash is a fixed-length fingerprint computed from a file's contents. If even one byte differs, the hash changes completely. Every file in the database carries these:
|
||||
|
||||
| Type | Length | Example | Used for |
|
||||
|------|--------|---------|----------|
|
||||
| SHA1 | 40 hex chars | `10155d8d6e6e832d8ea1571511e40dfb15fede05` | database primary key, BizHawk, installer downloads |
|
||||
| MD5 | 32 hex chars | `924e392ed05558ffdb115408c263dccf` | most platform verification |
|
||||
| SHA256 | 64 hex chars | `9a1c...` | emulator profiles whose upstream publishes SHA256 |
|
||||
| CRC32 | 8 hex chars | `2F468B96` | ROM-set matching, arcade DATs |
|
||||
|
||||
Emulator profiles add Adler-32 where the code checks it, which is how Dolphin
|
||||
checks its DSP ROMs (`dsp_rom.bin` and `dsp_coef.bin`, hashed byte-swapped).
|
||||
`IPL.bin` is not one of them: Dolphin loads it without a hash check.
|
||||
|
||||
Verification uses whichever one the platform itself uses: MD5 for Batocera,
|
||||
RetroBat, Recalbox, EmuDeck, RetroDECK, RomM, ROCKNIX, KNULLI, AmberELEC, EmuELEC
|
||||
and MiSTer FPGA, SHA1 for
|
||||
BizHawk, and nothing at all for RetroArch, Lakka and RetroPie, which only check
|
||||
that the file exists.
|
||||
|
||||
## Why does my verification report say UNTESTED?
|
||||
|
||||
`untested` means the file exists on disk but its hash does not match the expected value. This happens on MD5 and SHA1 platforms (Batocera, Recalbox, BizHawk, ROCKNIX, MiSTer FPGA, and the rest) when the file is present but contains different data than what the platform declares.
|
||||
|
||||
On existence-mode platforms (RetroArch, Lakka, RetroPie, MinUI, NextUI, MyMinUI), files are never `untested` because the platform only checks presence, not content. Those files show as `ok` if present, whatever they contain.
|
||||
|
||||
Running `verify.py --emulator <core> --verbose` shows the emulator-level ground truth, which can confirm whether the file's hash matches what the source code expects. The platform report applies the same check on its own: `verify.py --platform retroarch` prints a `DISCREPANCY` line for every file the platform accepts and a profiled emulator rejects.
|
||||
|
||||
It reaches only as far as the profiles do. Files no profile states a value for are platform-only, and nothing can be said about their content. The footer of the platform report gives that ratio as `Ground truth: N/M files have emulator validation`.
|
||||
|
||||
## Can I use BIOS from one platform on another?
|
||||
|
||||
Yes. BIOS files are console-specific, not platform-specific. A PlayStation BIOS works in RetroArch, Batocera, Recalbox, and any other platform that emulates PlayStation. The only differences between platforms are:
|
||||
|
||||
- **Where the file goes** (each platform has its own BIOS directory)
|
||||
- **What filename is expected** (usually the same, occasionally different)
|
||||
- **How verification works** (MD5 check vs. existence check)
|
||||
|
||||
The packs differ per platform because each platform declares its own set of supported systems and expected files.
|
||||
|
||||
## How often are packs updated?
|
||||
|
||||
Upstream sources (libretro System.dat, batocera-systems, etc.) are re-scraped by hand and the diff is reviewed before it lands. Releases happen as needed when new BIOS files are added or profiles are updated.
|
||||
- [Get your files](../which-pack.md)
|
||||
- [When a game does not start](troubleshooting.md)
|
||||
- [Glossary](glossary.md)
|
||||
+35
-6
@@ -1,3 +1,7 @@
|
||||
---
|
||||
level: start
|
||||
---
|
||||
|
||||
# First install
|
||||
|
||||
One path, from an empty BIOS folder to files the emulator can read. Every step
|
||||
@@ -6,6 +10,8 @@ shows what the screen looks like when it worked.
|
||||
If something on this page does not match what happens, the last section covers
|
||||
the cases that come up.
|
||||
|
||||
<!-- image: install-flow -->
|
||||
|
||||
## Before starting
|
||||
|
||||
Three things, and a few minutes:
|
||||
@@ -25,6 +31,11 @@ touched.
|
||||
|
||||
## Step 1. Run the command
|
||||
|
||||
The command runs in a terminal. On Windows, open the Start menu, type
|
||||
PowerShell and open it. On a Mac, open Terminal from Applications, then
|
||||
Utilities. On a Steam Deck, switch to Desktop Mode and open Konsole. Paste the
|
||||
line and press Enter.
|
||||
|
||||
On Linux, macOS, a Steam Deck, or a handheld running Batocera, Recalbox,
|
||||
KNULLI, ROCKNIX, AmberELEC, EmuELEC or Lakka:
|
||||
|
||||
@@ -75,6 +86,19 @@ SHA-256 the command checked before running it.
|
||||
That path is the one thing worth reading twice. If it is not where the emulator
|
||||
keeps its BIOS files, stop with Ctrl+C and see the last section.
|
||||
|
||||
At a terminal, the installer then asks what to install:
|
||||
|
||||
```
|
||||
Enter) install everything
|
||||
i) only what the installed cores read
|
||||
c) choose systems, cores and regions
|
||||
q) quit
|
||||
```
|
||||
|
||||
Enter installs everything, which is what the rest of this page shows. **c**
|
||||
lets you pick consoles, emulator cores and regions. The **i** line appears
|
||||
only when the installer finds emulator cores installed.
|
||||
|
||||
## Step 3. Let it work
|
||||
|
||||
The examples on this page follow the Batocera list as published on 2026-10-21.
|
||||
@@ -181,8 +205,8 @@ curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh \
|
||||
| sh -s -- --platform retroarch --dest /path/to/system
|
||||
```
|
||||
|
||||
The accepted names come from `--list-platforms`. For where each platform keeps
|
||||
its BIOS folder, see [Getting started](getting-started.md).
|
||||
The accepted names come from `--list-platforms`. The page of each setup,
|
||||
listed on [Get your files](../which-pack.md), gives its BIOS folder.
|
||||
|
||||
### Error: Python 3.8 or newer is required.
|
||||
|
||||
@@ -222,11 +246,16 @@ much is free. `--dest` installs to another drive.
|
||||
|
||||
A file can be in place and still be the wrong one for that game, or the console
|
||||
may need a file that nobody has dumped yet.
|
||||
[Troubleshooting](troubleshooting.md) goes through that case.
|
||||
[When a game does not start](troubleshooting.md) goes through that case.
|
||||
|
||||
## What comes next
|
||||
|
||||
- [Troubleshooting](troubleshooting.md), when a game does not start
|
||||
- The page of your setup, from [Get your files](../which-pack.md): where its
|
||||
folder is and how the setup itself checks the files
|
||||
- [When a game does not start](troubleshooting.md)
|
||||
- [FAQ](faq.md), for what the words mean and why a pack is this large
|
||||
- [Installer](installer.md), for every option, what it detects and what it is
|
||||
allowed to write
|
||||
- Details: [All installer options](installer.md), for every option, what it
|
||||
detects and what it is allowed to write
|
||||
|
||||
To remove what the installer wrote, delete the files from the BIOS folder.
|
||||
Nothing outside it was changed.
|
||||
+15
-299
@@ -1,312 +1,28 @@
|
||||
---
|
||||
level: start
|
||||
---
|
||||
|
||||
# Getting started
|
||||
|
||||
What this page held now lives on the pages written for each step.
|
||||
|
||||
## What are BIOS files?
|
||||
|
||||
BIOS files are firmware dumps from original console hardware. Emulators need them to boot games for systems that relied on built-in software (PlayStation, Saturn, Dreamcast, etc.). Without the correct BIOS, the emulator either refuses to start the game or falls back to less accurate software emulation.
|
||||
[What BIOS files are](what-are-bios-files.md) explains what they do, and which
|
||||
consoles need them.
|
||||
|
||||
## Installation
|
||||
|
||||
Three ways to get BIOS files in place. The installer is the one to use,
|
||||
and the two sections after it are for when it cannot run. For a walkthrough of a
|
||||
first install with what each step prints, see
|
||||
[First install](first-install.md).
|
||||
|
||||
### Option 1: the installer (recommended)
|
||||
|
||||
One command, nothing to clone. The bootstrap verifies `install.py` against the
|
||||
SHA-256 embedded in it, then the installer detects the platform and its BIOS
|
||||
directory, downloads only what is missing or incorrect, checks size and
|
||||
SHA-256/SHA-1 before writing, and installs each file atomically.
|
||||
|
||||
```bash
|
||||
# Linux / macOS / Steam Deck
|
||||
curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh
|
||||
|
||||
# Windows (PowerShell)
|
||||
irm https://raw.githubusercontent.com/Abdess/retrobios/main/install.ps1 | iex
|
||||
|
||||
# Android, from Termux, after pkg install python and termux-setup-storage
|
||||
curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh
|
||||
```
|
||||
|
||||
Running `install.py` directly works the same way and needs nothing beyond
|
||||
Python 3.8+, the floor both bootstraps enforce before they hand over:
|
||||
|
||||
```bash
|
||||
python install.py
|
||||
```
|
||||
|
||||
Override detection when needed:
|
||||
|
||||
```bash
|
||||
python install.py --platform retroarch --dest ~/custom/bios
|
||||
python install.py --target switch # keep only files for that hardware
|
||||
python install.py --list-systems # systems a platform holds, with sizes
|
||||
python install.py --system sony-playstation,nintendo-gba
|
||||
python install.py --region us,eu,jp # one BIOS per region, best first
|
||||
python install.py --no-input # ask nothing, even at a terminal
|
||||
python install.py --check # verify existing files, download nothing
|
||||
python install.py --list-platforms # supported platforms and what was detected
|
||||
python install.py --list-targets # hardware targets for a platform
|
||||
python install.py --jobs 4 # parallel downloads (default 8)
|
||||
python install.py --verbose
|
||||
python install.py --standalone-copies # opt in to extra standalone-emulator paths
|
||||
```
|
||||
|
||||
The default flow writes inside the detected platform tree only. Copies into
|
||||
separate standalone-emulator directories are opt-in, so discovery cannot cause
|
||||
unexpected writes elsewhere on the machine. Entries the collection cannot
|
||||
satisfy are reported as safely omitted and the run continues. The installer
|
||||
never substitutes a same-named file for one a hash-verifying platform would
|
||||
reject.
|
||||
|
||||
Arguments pass through the one-liner too, which is how you target an SD card
|
||||
mounted on another machine:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh \
|
||||
| sh -s -- --platform retroarch --dest /path/to/sdcard/retroarch/cores/system
|
||||
```
|
||||
|
||||
`--dest` is the BIOS folder itself, so on a card it names that folder on the
|
||||
card: `retroarch/cores/system` for RetroArch on Switch, `RetroArch/system` on
|
||||
Android.
|
||||
|
||||
PowerShell needs another form, the environment overrides and the detection
|
||||
rules are listed per platform, and the trust boundary is described in full on
|
||||
the [Installer](installer.md) page.
|
||||
|
||||
### Option 2: download.sh (Linux/macOS, from a clone)
|
||||
|
||||
Downloads a whole pack rather than the missing files. Needs `curl` and `unzip`:
|
||||
|
||||
```bash
|
||||
bash scripts/download.sh retroarch ~/RetroArch/system/
|
||||
bash scripts/download.sh --list # show available packs
|
||||
```
|
||||
|
||||
A pack published in several parts is downloaded part by part and checked
|
||||
against the SHA-256 the release publishes before anything is extracted.
|
||||
`python scripts/download.py` does the same on Windows.
|
||||
|
||||
### Option 3: manual download
|
||||
|
||||
1. Go to the [releases page](https://github.com/Abdess/retrobios/releases)
|
||||
2. Download the ZIP pack for your platform
|
||||
3. Extract to the BIOS directory listed below
|
||||
|
||||
A pack over 2 GB comes in several parts (`Pack.part1of2.zip`,
|
||||
`Pack.part2of2.zip`), and every part is needed. Each part is an ordinary ZIP:
|
||||
extract them all into the same folder. See [Download](../which-pack.md) for
|
||||
the per-setup instructions.
|
||||
[Get your files](../which-pack.md) gives the command and the packs for every
|
||||
setup. [First install, step by step](first-install.md) shows what each step of
|
||||
the command prints.
|
||||
|
||||
## BIOS directory by platform
|
||||
|
||||
### RetroArch
|
||||
|
||||
RetroArch uses the `system_directory` setting in `retroarch.cfg`. Default locations:
|
||||
|
||||
| OS | Default path |
|
||||
|----|-------------|
|
||||
| Windows (installer or portable .7z) | `system\` next to `retroarch.exe` |
|
||||
| Windows (UWP/MSIX package) | `%LOCALAPPDATA%\Packages\1e4cf179-f3c2-404f-b9f3-cb2070a5aad8_*\LocalState\system\` |
|
||||
| Linux | `~/.config/retroarch/system/` |
|
||||
| Linux (Flatpak) | `~/.var/app/org.libretro.RetroArch/config/retroarch/system/` |
|
||||
| macOS | `~/Library/Application Support/RetroArch/system/` |
|
||||
| Steam Deck (Flatpak) | `~/.var/app/org.libretro.RetroArch/config/retroarch/system/` |
|
||||
| Android | `/storage/emulated/0/RetroArch/system/` |
|
||||
|
||||
On Windows, `retroarch.cfg` is read beside `retroarch.exe` first, then from
|
||||
`%APPDATA%\RetroArch\`. Either way, a `system_directory` left at its default is
|
||||
the `system` folder beside `retroarch.exe` (`:\system` in RetroArch's
|
||||
`frontend/drivers/platform_win32.c`, where `:` stands for the folder of the
|
||||
executable).
|
||||
|
||||
To check your actual path: open RetroArch, go to **Settings > Directory > System/BIOS**, or look for `system_directory` in `retroarch.cfg`.
|
||||
|
||||
### Batocera
|
||||
|
||||
```
|
||||
/userdata/bios/
|
||||
```
|
||||
|
||||
Accessible via network share at `\\BATOCERA\share\bios\` (Windows) or `smb://batocera/share/bios/` (macOS/Linux).
|
||||
|
||||
### Recalbox
|
||||
|
||||
```
|
||||
/recalbox/share/bios/
|
||||
```
|
||||
|
||||
Accessible via network share at `\\RECALBOX\share\bios\`.
|
||||
|
||||
### RetroBat
|
||||
|
||||
```
|
||||
bios/
|
||||
```
|
||||
|
||||
Relative to the RetroBat installation directory (e.g., `C:\RetroBat\bios\`).
|
||||
|
||||
### RetroDECK
|
||||
|
||||
```
|
||||
~/retrodeck/bios/
|
||||
```
|
||||
|
||||
On a MicroSD install the root moves, e.g. `/run/media/mmcblk0p1/retrodeck/bios/`.
|
||||
|
||||
The RetroDECK pack is the exception to "extract into the BIOS directory": its
|
||||
entries already start with `bios/` (and one with `roms/`), so extract it into
|
||||
`~/retrodeck/` and the files land in the right place. Extracting into
|
||||
`~/retrodeck/bios/` would create `~/retrodeck/bios/bios/`.
|
||||
|
||||
### EmuDeck
|
||||
|
||||
```
|
||||
Emulation/bios/
|
||||
```
|
||||
|
||||
Located inside your Emulation folder. On Steam Deck, typically `~/Emulation/bios/`.
|
||||
|
||||
### Lakka
|
||||
|
||||
```
|
||||
/storage/system/
|
||||
```
|
||||
|
||||
Accessible via SSH or Samba.
|
||||
|
||||
### RetroPie
|
||||
|
||||
```
|
||||
~/RetroPie/BIOS/
|
||||
```
|
||||
|
||||
RetroPie is archived in this project: its configuration is kept and packs are
|
||||
still built, but the upstream data is no longer scraped on a schedule. Use the
|
||||
RetroPie pack, not the RetroArch one: RetroPie inherits RetroArch's systems
|
||||
but also installs standalone emulators (openMSX, PCSX2, XRoar, Amiberry and
|
||||
others) whose files only the RetroPie pack carries, laid out for
|
||||
`~/RetroPie/BIOS/` rather than RetroArch's `system/`.
|
||||
|
||||
### ROCKNIX
|
||||
|
||||
```
|
||||
/storage/roms/bios/
|
||||
```
|
||||
|
||||
Accessible via SSH or Samba, like Lakka.
|
||||
|
||||
### KNULLI
|
||||
|
||||
```
|
||||
/userdata/bios/
|
||||
```
|
||||
|
||||
### AmberELEC and EmuELEC
|
||||
|
||||
```
|
||||
/storage/roms/
|
||||
```
|
||||
|
||||
Their BIOS lists name files under `/storage/roms`: `bios/` for most, and
|
||||
`neogeo/` (and `ports/` on EmuELEC) for the rest. The pack holds those
|
||||
folders, so it is extracted into `/storage/roms/` itself.
|
||||
|
||||
### MiSTer FPGA
|
||||
|
||||
```
|
||||
/media/fat/games/
|
||||
```
|
||||
|
||||
Files go under the per-core subdirectory the MiSTer BIOS database declares
|
||||
(e.g. `/media/fat/games/3DO/boot.rom`). Only the entries the BIOS database
|
||||
lists with a download URL are in scope: the rest ship with the MiSTer
|
||||
distribution and install themselves.
|
||||
|
||||
### MinUI, NextUI and MyMinUI
|
||||
|
||||
```
|
||||
<SD card>/Bios/<TAG>/
|
||||
```
|
||||
|
||||
These frontends give each core a folder of its own, named after the tag in
|
||||
parentheses of the Roms folder the game sits in: a game in
|
||||
`Roms/Sony PlayStation (PS)/` runs with `Bios/PS/` as its system directory, one
|
||||
in `Roms/Game Boy (GB)/` with `Bios/GB/` (MinUI
|
||||
`workspace/all/minarch/minarch.c:2943`, NextUI
|
||||
`workspace/all/minarch/ma_core.c:76`, MyMinUI
|
||||
`workspace/all/minarch/minarch.c:3532`). The pack holds the `Bios/` folder:
|
||||
extract it at the root of the card. A core started from two tags (Gambatte for
|
||||
GB and GBC) gets its files in both folders.
|
||||
|
||||
The installer runs on the computer the card is mounted on, with the card's root
|
||||
as `--dest`:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh -s -- --platform minui --dest /media/$USER/CARD
|
||||
```
|
||||
|
||||
Without `--platform`, it reads the release name the frontend writes in
|
||||
`.system/version.txt` on the card. A pak that starts a standalone program
|
||||
instead of a libretro core (DraStic for NDS, native PICO-8) is not covered.
|
||||
|
||||
### BizHawk
|
||||
|
||||
```
|
||||
Firmware/
|
||||
```
|
||||
|
||||
Relative to the BizHawk installation directory.
|
||||
|
||||
### RomM
|
||||
|
||||
BIOS files live in the RomM library under `bios/{platform_slug}/`, one
|
||||
subfolder per system, and are managed through the web interface. Check the
|
||||
[RomM documentation](https://github.com/rommapp/romm) for setup details.
|
||||
The page of each setup opens on where its files go. All setups are on
|
||||
[Get your files](../which-pack.md), grouped by the device they run on.
|
||||
|
||||
## Checking what you installed
|
||||
|
||||
`--check` reads the BIOS folder, hashes what is there and writes nothing:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh -s -- --check
|
||||
```
|
||||
|
||||
It ends on a count:
|
||||
|
||||
```
|
||||
Checking existing files...
|
||||
5865/5865 present (5865 verified, 0 wrong hash)
|
||||
|
||||
All files up to date.
|
||||
```
|
||||
|
||||
`0 wrong hash` is the line that matters. A number there means a file is present
|
||||
whose contents the platform will reject, which is how a wrong revision or a bad
|
||||
dump shows up.
|
||||
|
||||
The installer's `--check` hashes every file against the list on every
|
||||
platform, so it catches a wrong revision even where the frontend would not:
|
||||
RetroArch, Lakka, RetroPie, MinUI, NextUI and MyMinUI only check that a file
|
||||
exists, while Batocera, RetroBat, Recalbox, EmuDeck, RetroDECK, RomM, ROCKNIX,
|
||||
KNULLI, AmberELEC, EmuELEC and MiSTer FPGA compare
|
||||
MD5 and BizHawk compares SHA1.
|
||||
|
||||
For a single system, or the files a single emulator core reads (`--list-systems`
|
||||
and `--list-cores` give the names):
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh -s -- --check --system sony-playstation
|
||||
curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh -s -- --check --emulator beetle_psx
|
||||
```
|
||||
|
||||
`--verbose` names every file still to fetch, wrong hashes included. See [Installer](installer.md)
|
||||
for every option, and [Tools](tools.md) for the repository's own scripts.
|
||||
|
||||
## Next steps
|
||||
|
||||
- [FAQ](faq.md) - common questions and troubleshooting
|
||||
- [Tools](tools.md) - all available scripts and options
|
||||
- [Architecture](architecture.md) - how the project works internally
|
||||
[When a game does not start](troubleshooting.md#checking-what-you-installed)
|
||||
shows how to check the files in your BIOS folder.
|
||||
@@ -0,0 +1,153 @@
|
||||
---
|
||||
level: start
|
||||
---
|
||||
|
||||
# Glossary
|
||||
|
||||
The first part holds the words anyone meets when setting up BIOS files. The
|
||||
second part holds the words this project uses in its reference pages.
|
||||
|
||||
## Words you will meet
|
||||
|
||||
**BIOS, or firmware**
|
||||
: A small program built into a console. Many emulators need a copy of it to
|
||||
start games. [What BIOS files are](what-are-bios-files.md) says more.
|
||||
|
||||
**Emulator**
|
||||
: A program that lets a computer, a phone or a handheld act like an older
|
||||
console.
|
||||
|
||||
**Core**
|
||||
: One emulator inside RetroArch. RetroArch loads a different core for each
|
||||
console.
|
||||
|
||||
**Frontend**
|
||||
: The menu you pick and start games from, such as EmulationStation, MinUI or
|
||||
the RetroArch menu. It starts the emulator for you.
|
||||
|
||||
**Setup, or platform**
|
||||
: The software you play with: RetroArch, Batocera, EmuDeck, KNULLI and the
|
||||
others. Each one keeps its BIOS files in a folder of its own.
|
||||
|
||||
**BIOS folder**
|
||||
: The folder where your setup looks for BIOS files. Its place depends on the
|
||||
setup, and the page of each setup gives it.
|
||||
|
||||
**Pack**
|
||||
: One ZIP file with every BIOS file a setup uses. A pack over 2 GB comes in
|
||||
several parts, and every part is needed.
|
||||
|
||||
**Installer**
|
||||
: A small program started by one line pasted into a terminal. It finds your
|
||||
BIOS folder and downloads only the files that are missing.
|
||||
|
||||
**Terminal, or command line**
|
||||
: A window where you type commands. On Windows it is PowerShell, on a Mac it
|
||||
is Terminal, on a Steam Deck it is Konsole.
|
||||
|
||||
**Hash, or checksum (MD5, SHA1)**
|
||||
: A fingerprint of a file's contents. Two files with the same hash hold the
|
||||
same bytes. Some setups use it to refuse a file that is not the expected
|
||||
version.
|
||||
|
||||
**Region**
|
||||
: The market a console was sold in, such as Japan, North America or Europe.
|
||||
Some emulators pick the BIOS of the same region as the game.
|
||||
|
||||
**Required and optional**
|
||||
: Required: the emulator does not start games without the file. Optional:
|
||||
games start without it, with small differences such as a missing start-up
|
||||
screen.
|
||||
|
||||
**HLE**
|
||||
: High-level emulation: code in the emulator that stands in for the BIOS.
|
||||
Many games work with it, some glitch or do not start.
|
||||
|
||||
**Game data**
|
||||
: Files of a game that a game engine reads, such as the data of Doom or
|
||||
Diablo. They come from your own copy of the game, and their absence does not
|
||||
affect any console.
|
||||
|
||||
## Project terms
|
||||
|
||||
**Profile**
|
||||
: A YAML file in `emulators/` that documents what one emulator loads, read
|
||||
from its source code.
|
||||
|
||||
**Ground truth**
|
||||
: The emulator's source code, the reference every profile is checked against.
|
||||
|
||||
**System**
|
||||
: A console or computer being emulated, named by an id such as
|
||||
`sony-playstation` or `nintendo-gba`.
|
||||
|
||||
**Verification mode**
|
||||
: How a setup checks a file: by its name only (existence), by MD5 or by SHA1.
|
||||
Reference: [How each platform checks files](verification-modes.md).
|
||||
|
||||
**Status**
|
||||
: The outcome of one file check: `ok`, `untested` (present, but not the
|
||||
expected hash) or `missing`.
|
||||
|
||||
**Severity**
|
||||
: How much a check result matters: OK, INFO (negligible), WARNING (degraded),
|
||||
CRITICAL (the emulator cannot start games).
|
||||
|
||||
**Discrepancy**
|
||||
: A file that passes the setup's own check but fails the emulator's size or
|
||||
hash check.
|
||||
|
||||
**hle_fallback**
|
||||
: A flag on a profile entry: the emulator has HLE for this file, so its
|
||||
absence is reported at INFO.
|
||||
|
||||
**Variant**
|
||||
: Another version of a BIOS file (a revision, a region or another dump), kept
|
||||
in `.variants/` in the repository.
|
||||
|
||||
**Cross-reference**
|
||||
: The comparison of emulator profiles with a setup's own list, which finds the
|
||||
files the setup's emulators load and its list does not name.
|
||||
|
||||
**Shared group**
|
||||
: A group of files in `_shared.yml` that several setups include, with the
|
||||
folder an emulator expects.
|
||||
|
||||
**Data directory**
|
||||
: A whole folder an emulator needs, such as Dolphin's `Sys/` or the PPSSPP
|
||||
assets, kept in `data/` and not indexed in the database.
|
||||
|
||||
**Storage tier**
|
||||
: Where a file comes from: `embedded` (in `bios/`), `external` (downloaded at
|
||||
build time) or `user_provided`.
|
||||
|
||||
**Target**
|
||||
: A hardware architecture a setup runs on, such as `switch`, `rpi4` or
|
||||
`x86_64`.
|
||||
|
||||
**Manifest**
|
||||
: The JSON list of files per setup in `install/`, which the installer reads.
|
||||
|
||||
**Scraper**
|
||||
: A script that reads a setup's own BIOS list (System.dat, es_bios.xml and
|
||||
others) into this project's format.
|
||||
|
||||
**Exporter**
|
||||
: A script that writes the project's data back in a setup's own format.
|
||||
|
||||
**Truth**
|
||||
: A setup's file list generated from the emulator profiles, compared with the
|
||||
list the setup publishes.
|
||||
|
||||
**Dump catalog**
|
||||
: A preservation project (Redump, No-Intro, TOSEC) that publishes lists of
|
||||
verified hardware dumps.
|
||||
|
||||
**Provenance**
|
||||
: The catalogs that list a file, joined to the database by hash. It informs,
|
||||
it never overrides the emulator code.
|
||||
|
||||
!!! tip "Next"
|
||||
|
||||
- [What BIOS files are](what-are-bios-files.md)
|
||||
- [Get your files](../which-pack.md)
|
||||
+40
-56
@@ -1,75 +1,59 @@
|
||||
# Wiki
|
||||
---
|
||||
level: reference
|
||||
---
|
||||
|
||||
Technical documentation for the RetroBIOS toolchain.
|
||||
# Reference
|
||||
|
||||
Pages are grouped by what you came to do. **For users** walks through
|
||||
installing and checking files. **Technical reference** describes how the
|
||||
toolchain behaves, one subject per page. **For contributors** is task-oriented:
|
||||
each page takes one job from start to finish.
|
||||
These pages describe how the files are checked, what the data holds and how the
|
||||
toolchain works. To set up BIOS files on a device, start with
|
||||
[Get your files](../which-pack.md).
|
||||
|
||||
## For users
|
||||
## How the files are checked
|
||||
|
||||
- **[First install](first-install.md)** - one path from an empty folder to working files, with what each step prints
|
||||
- **[Getting started](getting-started.md)** - installation, BIOS directory paths per platform, verification
|
||||
- **[Installer](installer.md)** - the one-liner in full: bootstrap, options, environment overrides, platform detection, trust boundary
|
||||
- **[Troubleshooting](troubleshooting.md)** - diagnosis by symptom: missing BIOS, hash mismatch, pack issues
|
||||
- **[FAQ](faq.md)** - common questions, hash explanations
|
||||
- **[How each platform checks files](verification-modes.md)** - existence, MD5 and SHA1 modes, severity matrix, resolution chain, reading `verify.py` output
|
||||
- **[What the packs do not hold](../gaps.md)** - files emulators load that no pack can carry yet, by platform and by emulator
|
||||
- **[Cross-reference](../cross-reference.md)** - files the emulators of a platform load and its own list does not name
|
||||
- **[Dump provenance](../provenance.md)** - how the collection lines up against the No-Intro, Redump and TOSEC catalogs
|
||||
- **[Updated platform files](../exports.md)** - each platform's own file, with the changes the emulator source supports
|
||||
- **[Technical questions](technical-faq.md)** - multiple hashes, MAME versions, UNTESTED, dump verification
|
||||
|
||||
If you just want to download BIOS packs, see the [home page](../index.md).
|
||||
## Data
|
||||
|
||||
## Technical reference
|
||||
|
||||
- **[Architecture](architecture.md)** - directory structure, data flow, platform inheritance, pack grouping, security, edge cases, CI workflows
|
||||
- **[Tools](tools.md)** - CLI reference for every script, pipeline usage, scrapers
|
||||
- **[Advanced usage](advanced-usage.md)** - custom packs, region filtering, one file per slot, target filtering, truth generation, emulator verification, offline workflow
|
||||
- **[Verification modes](verification-modes.md)** - how each platform verifies BIOS files, severity matrix, resolution chain
|
||||
- **[Data and API](../data.md)** - JSON, CSV and SQLite exports with their checksums
|
||||
- **[Find a file by its SHA1](../files/index.md)** - the permanent address of a file by its contents
|
||||
- **[Data model](data-model.md)** - database.json structure, indexes, file resolution order, YAML formats
|
||||
|
||||
See also [dump provenance](../provenance.md) for how the collection lines up
|
||||
against the No-Intro, Redump and TOSEC catalogs.
|
||||
## The toolchain
|
||||
|
||||
- **[Architecture](architecture.md)** - directory structure, data flow, platform inheritance, pack grouping, security, edge cases, CI workflows
|
||||
- **[Build your own packs](advanced-usage.md)** - custom packs, region filtering, one file per slot, target filtering, truth generation, emulator verification, offline workflow
|
||||
- **[Command-line tools](tools.md)** - every script, pipeline usage, scrapers
|
||||
- **[Projects using this data](community-tools.md)** - projects built on RetroBIOS data
|
||||
|
||||
## Methodology
|
||||
|
||||
Platform lists are checked against emulator source code, file by file where a
|
||||
profile exists. Documentation and metadata can differ from what a program does
|
||||
at run time, so the source is the primary reference:
|
||||
|
||||
1. **Upstream emulator source**: what the original project loads (Dolphin,
|
||||
PCSX2, Mednafen and others)
|
||||
2. **Libretro core source**: the RetroArch port, which may adapt paths or add
|
||||
files
|
||||
3. **`.info` declarations**: metadata that platforms rely on, checked against
|
||||
the two above
|
||||
|
||||
## For contributors
|
||||
|
||||
- **[Profiling guide](profiling.md)** - create an emulator profile from source code, YAML field reference
|
||||
- **[Profiling an emulator](profiling.md)** - create an emulator profile from source code, YAML field reference
|
||||
- **[Adding a platform](adding-a-platform.md)** - scraper, registry, YAML config, exporter, target scraper, install detection
|
||||
- **[Adding a scraper](adding-a-scraper.md)** - plugin architecture, BaseScraper, parsers, target scrapers
|
||||
- **[Testing guide](testing-guide.md)** - run tests, fixture pattern, how to add tests, CI integration
|
||||
- **[Testing](testing-guide.md)** - run tests, fixture pattern, how to add tests, CI integration
|
||||
- **[Release process](release-process.md)** - CI workflows, large files, manual release
|
||||
|
||||
See [contributing](../contributing.md) for submission guidelines.
|
||||
|
||||
## Community
|
||||
|
||||
- **[Community tools](community-tools.md)** - projects built on RetroBIOS data
|
||||
|
||||
## Glossary
|
||||
|
||||
- **BIOS** - firmware burned into console hardware, needed by emulators that rely on original boot code
|
||||
- **firmware** - system software loaded by a console at boot, used interchangeably with BIOS in this project
|
||||
- **HLE** - High-Level Emulation: software reimplementation of BIOS functions, avoids needing the original file
|
||||
- **hash** - fixed-length fingerprint of a file's contents. This project uses MD5, SHA1, SHA256, CRC32, and Adler-32
|
||||
- **platform** - a distribution that packages emulators (RetroArch, Batocera, Recalbox, EmuDeck, etc.)
|
||||
- **core** - an emulator packaged as a libretro plugin, loaded by RetroArch or compatible frontends
|
||||
- **profile** - a YAML file in `emulators/` documenting one core's BIOS requirements, verified against source code
|
||||
- **system** - a game console or computer being emulated (e.g. sony-playstation, nintendo-gameboy-advance)
|
||||
- **pack** - a ZIP archive containing all BIOS files needed by a specific platform
|
||||
- **ground truth** - the emulator's source code, treated as the authoritative reference for BIOS requirements
|
||||
- **cross-reference** - comparison of emulator profiles against platform configs to find undeclared files
|
||||
- **scraper** - a script that fetches BIOS requirement data from an upstream source (System.dat, es_bios.xml, etc.)
|
||||
- **exporter** - a script that converts ground truth data back into a platform's native format
|
||||
- **target** - a hardware architecture that a platform runs on (e.g. switch, rpi4, x86_64, steamos)
|
||||
- **region** - the territory an emulator's code branches on to select a file. `--region` builds a pack from an ordered priority list, `--one-per-slot` keeps one file per system and region
|
||||
- **variant** - an alternative version of a BIOS file (different revision, region, or dump), stored in `.variants/`
|
||||
- **required** - a file the core needs to function, determined by source code behavior
|
||||
- **optional** - a file the core functions without, possibly with reduced accuracy or missing features
|
||||
- **hle_fallback** - flag on a file indicating the core has an HLE path, and absence is downgraded to INFO severity
|
||||
- **severity** - the urgency of a verification result: OK (verified), INFO (negligible), WARNING (degraded), CRITICAL (broken)
|
||||
- **status** - the outcome of a single file check: `ok`, `untested` (present, hash not the expected one), or `missing`
|
||||
- **discrepancy** - a file that passes the platform check but fails the emulator's own size or hash validation
|
||||
- **shared group** - a file group in `_shared.yml` that several platforms include, carrying the destination a core expects
|
||||
- **data directory** - a whole directory tree a core needs (Dolphin `Sys/`, PPSSPP assets), cached in `data/`, not indexed in the database
|
||||
- **storage tier** - where a file comes from: `embedded` (in `bios/`), `external` (downloaded at build), `user_provided`
|
||||
- **truth** - platform-shaped data generated from emulator profiles, used to diff against what the platform declares
|
||||
- **dump catalog** - a preservation project (Redump, No-Intro, TOSEC) publishing DATs of verified hardware dumps
|
||||
- **provenance** - the catalogs that list a file, joined into the database by hash. An annotation, never an authority
|
||||
- **manifest** - the JSON file list per platform in `install/`, consumed by `install.py`
|
||||
The words these pages use, from BIOS to provenance, are in the
|
||||
[glossary](glossary.md).
|
||||
+7
-3
@@ -1,9 +1,13 @@
|
||||
# Installer
|
||||
---
|
||||
level: explore
|
||||
---
|
||||
|
||||
# All installer options
|
||||
|
||||
Reference for `install.sh`, `install.ps1` and `install.py`: what the one-liner
|
||||
runs, what it detects, where the bytes come from and what it is allowed to
|
||||
write. For BIOS directory paths per platform, see
|
||||
[Getting started](getting-started.md).
|
||||
write. For the BIOS folder of each setup, see
|
||||
[Get your files](../which-pack.md).
|
||||
|
||||
## One line
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
level: contribute
|
||||
---
|
||||
|
||||
# Profiling guide
|
||||
|
||||
How to create an emulator profile from source code.
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
level: contribute
|
||||
---
|
||||
|
||||
# Release process
|
||||
|
||||
Two GitHub workflows check pull requests and publish the site. Releases are
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
---
|
||||
level: reference
|
||||
---
|
||||
|
||||
# Technical questions
|
||||
|
||||
Questions about how the files are identified and checked. The questions asked
|
||||
before installing are in the [FAQ](faq.md).
|
||||
|
||||
## How is a missing file ranked?
|
||||
|
||||
In verification output, missing required files appear as CRITICAL or WARNING
|
||||
depending on the platform. Missing optional files appear as WARNING or INFO.
|
||||
|
||||
When a core has HLE support, the verification tool lowers the severity of a
|
||||
missing BIOS to INFO. The file is still included in packs because the real BIOS
|
||||
gives better results. The full table is the
|
||||
[severity matrix](verification-modes.md#severity-matrix).
|
||||
|
||||
## Why are there multiple hashes for the same file?
|
||||
|
||||
Two main reasons:
|
||||
|
||||
1. **Regional variants.** The same filename (e.g., `IPL.bin` for GameCube) exists in different versions for USA, Europe, and Japan. Each region has a different hash.
|
||||
2. **Revision differences.** Console manufacturers released updated BIOS versions over time. A PlayStation SCPH-5501 BIOS differs from a SCPH-7001.
|
||||
|
||||
Platforms that verify by MD5 accept specific hashes. If yours doesn't match any known hash, it may be a bad dump or an uncommon revision.
|
||||
|
||||
A filename is never allowed to stand in for a declared hash. When a file entry
|
||||
carries a hash, resolution matches on content and reports `hash_mismatch` if the
|
||||
only same-named copy disagrees. What happens next depends on the platform: an
|
||||
MD5 or SHA1 platform would reject the file, so the pack omits it and says why,
|
||||
while an existence platform only checks presence, so the file ships and the divergence
|
||||
is reported instead.
|
||||
|
||||
## Why are there files that aren't BIOS?
|
||||
|
||||
A file earns its place when an emulator loads it from disk and does not bundle it. That covers actual BIOS ROMs, console firmware, arcade BIOS sets, and also game data like `prboom.wad` for the PrBoom core or soundfonts for EasyRPG.
|
||||
|
||||
This follows the platforms themselves: Batocera lists `prboom.wad` in its BIOS checker, and libretro declares these files in the `firmware` field of its core info. The word "BIOS" is their vocabulary for "external file the emulator needs". Files are tagged by category (`bios`, `game_data`, `bios_zip`) in the emulator profiles, so the distinction stays visible.
|
||||
|
||||
## Are these files verified against original hardware dumps?
|
||||
|
||||
No, and that is a deliberate boundary. The hashes here document what
|
||||
emulator code loads and accepts, read from the source. When several
|
||||
revisions or regions pass, all of them are kept (`.variants/` in the
|
||||
repository, per-emulator pages list each one), and the pack ships the
|
||||
variant satisfying the most checks, logging any conflict it cannot
|
||||
resolve.
|
||||
|
||||
Whether a file byte-matches the original hardware ROM is a different
|
||||
question, answered by dump-preservation catalogs such as No-Intro,
|
||||
Redump, and TOSEC, not by emulator code. The collection is
|
||||
cross-referenced against their DATs: files matching a catalog entry
|
||||
carry a verified dump badge on the system pages, and catalog entries
|
||||
absent from the collection are tracked as acquisition targets. When
|
||||
the two views differ, this project follows the code, because that is
|
||||
what decides whether your emulator boots.
|
||||
|
||||
The [dump provenance](../provenance.md) page has the current coverage
|
||||
per catalog and the full list of catalogued dumps still missing.
|
||||
|
||||
## Which MAME version do the arcade BIOS sets match?
|
||||
|
||||
Arcade BIOS sets are coupled to the romset version, so there is one
|
||||
profile per MAME core generation: MAME 2000 (0.37b5), MAME 2003 (0.78),
|
||||
MAME 2003-Plus, MAME 2009 (0.135u4), MAME 2010 (0.139), MAME 2015
|
||||
(0.160), MAME 2016 (0.174), and current MAME (0.289), each read from that
|
||||
version's own source tree, because the BIOS root sets differ between
|
||||
versions. Derivatives and ports carry their own profiles on top of those
|
||||
generations: `mamearcade`, `mamemess`, `mame2003_midway`, the three
|
||||
`mame4droid` drops, `advancemame`, `groovymame` and `hbmame`. Recalbox
|
||||
compiles two MAME versions of its own, 0.258 and 0.278, profiled as
|
||||
`mame0258` and `mame0278`. The pack
|
||||
ships the sets matching the core you run, and a generic unversioned arcade
|
||||
pack cannot do that.
|
||||
|
||||
## What's a hash/checksum?
|
||||
|
||||
A hash is a fixed-length fingerprint computed from a file's contents. If even one byte differs, the hash changes completely. Every file in the database carries these:
|
||||
|
||||
| Type | Length | Example | Used for |
|
||||
|------|--------|---------|----------|
|
||||
| SHA1 | 40 hex chars | `10155d8d6e6e832d8ea1571511e40dfb15fede05` | database primary key, BizHawk, installer downloads |
|
||||
| MD5 | 32 hex chars | `924e392ed05558ffdb115408c263dccf` | most platform verification |
|
||||
| SHA256 | 64 hex chars | `9a1c...` | emulator profiles whose upstream publishes SHA256 |
|
||||
| CRC32 | 8 hex chars | `2F468B96` | ROM-set matching, arcade DATs |
|
||||
|
||||
Emulator profiles add Adler-32 where the code checks it, which is how Dolphin
|
||||
checks its DSP ROMs (`dsp_rom.bin` and `dsp_coef.bin`, hashed byte-swapped).
|
||||
`IPL.bin` is not one of them: Dolphin loads it without a hash check.
|
||||
|
||||
Verification uses whichever one the platform itself uses: MD5 for Batocera,
|
||||
RetroBat, Recalbox, EmuDeck, RetroDECK, RomM, ROCKNIX, KNULLI, AmberELEC, EmuELEC
|
||||
and MiSTer FPGA, SHA1 for
|
||||
BizHawk, and nothing at all for RetroArch, Lakka and RetroPie, which only check
|
||||
that the file exists.
|
||||
|
||||
## Why does my verification report say UNTESTED?
|
||||
|
||||
`untested` means the file exists on disk but its hash does not match the expected value. This happens on MD5 and SHA1 platforms (Batocera, Recalbox, BizHawk, ROCKNIX, MiSTer FPGA, and the rest) when the file is present but contains different data than what the platform declares.
|
||||
|
||||
On existence-mode platforms (RetroArch, Lakka, RetroPie, MinUI, NextUI, MyMinUI), files are never `untested` because the platform only checks presence, not content. Those files show as `ok` if present, whatever they contain.
|
||||
|
||||
Running `verify.py --emulator <core> --verbose` shows the emulator-level ground truth, which can confirm whether the file's hash matches what the source code expects. The platform report applies the same check on its own: `verify.py --platform retroarch` prints a `DISCREPANCY` line for every file the platform accepts and a profiled emulator rejects.
|
||||
|
||||
It reaches only as far as the profiles do. Files no profile states a value for are platform-only, and nothing can be said about their content. The footer of the platform report gives that ratio as `Ground truth: N/M files have emulator validation`.
|
||||
|
||||
!!! tip "Next"
|
||||
|
||||
- [Reference index](index.md), every reference page in one list
|
||||
- For contributors: [How to contribute](../contributing.md)
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
level: contribute
|
||||
---
|
||||
|
||||
# Testing guide
|
||||
|
||||
The suite is discovered dynamically across focused modules, so its exact count
|
||||
@@ -47,7 +51,7 @@ Every module in `tests/`, by the area it guards.
|
||||
| Handheld port | stubbed PortMaster dialogs, fake installer | `test_port` |
|
||||
| Truth and native export | synthetic + cached originals | `test_export_counts`, `test_export_native_layer`, `test_export_report`, `test_exporters`, `test_truth_data_dir_readers`, `test_truth_diff`, `test_truth_layout` |
|
||||
| Scrapers, upstream and provenance | inline sources, synthetic | `test_check_freshness`, `test_dedup`, `test_elec_scrapers`, `test_fbneo_parser`, `test_find_pinned_revision`, `test_hash_merge`, `test_launchers`, `test_launchers_emudeck`, `test_launchers_recalbox`, `test_launchers_retrobat`, `test_launchers_retrodeck`, `test_launchers_retropie`, `test_launchers_rocknix`, `test_mame_devices`, `test_mame_parser`, `test_mame_ref_audit`, `test_profile_sync`, `test_provenance`, `test_refresh_data_dirs`, `test_refresh_failures`, `test_refresh_stale`, `test_retrodeck_scraper_errors`, `test_romset_recipes`, `test_scraper_contract`, `test_upstream`, `test_upstream_index` |
|
||||
| Site, docs and repository contracts | rendered pages, sources | `test_contributing_text`, `test_data_dir_refs`, `test_dataclass_defaults`, `test_doc_pages`, `test_doc_surfaces`, `test_optional_dependencies`, `test_prose_style`, `test_site_availability`, `test_site_cores`, `test_site_emulator_page`, `test_site_exports`, `test_site_platform_hashes`, `test_site_render`, `test_site_system_links`, `test_site_validation`, `test_site_write`, `test_validate_pr`, `test_validate_pr_flow`, `test_validate_pr_hashes`, `test_workflow_paths` |
|
||||
| Site, docs and repository contracts | rendered pages, sources | `test_contributing_text`, `test_data_dir_refs`, `test_dataclass_defaults`, `test_doc_pages`, `test_doc_surfaces`, `test_optional_dependencies`, `test_prose_style`, `test_site_availability`, `test_site_cores`, `test_site_emulator_page`, `test_site_exports`, `test_site_funnel`, `test_site_platform_hashes`, `test_site_render`, `test_site_system_links`, `test_site_validation`, `test_site_write`, `test_validate_pr`, `test_validate_pr_flow`, `test_validate_pr_hashes`, `test_workflow_paths` |
|
||||
|
||||
## Test architecture
|
||||
|
||||
|
||||
+5
-1
@@ -1,4 +1,8 @@
|
||||
# Tools
|
||||
---
|
||||
level: reference
|
||||
---
|
||||
|
||||
# Command-line tools
|
||||
|
||||
All tools are Python scripts in `scripts/`. They need Python 3.9 or newer and `pyyaml`,
|
||||
and only `validate_schemas.py` also needs `jsonschema[format-nongpl]`. `install.py`
|
||||
|
||||
+63
-150
@@ -1,4 +1,11 @@
|
||||
# Troubleshooting
|
||||
---
|
||||
level: start
|
||||
---
|
||||
|
||||
# When a game does not start
|
||||
|
||||
Start here when a game does not start, or says that a BIOS file is missing.
|
||||
Each section is one check, in the order that finds the cause soonest.
|
||||
|
||||
## Game won't start / black screen
|
||||
|
||||
@@ -48,6 +55,45 @@ North American games on cores that enforce region matching. Check the emulator
|
||||
profile for your core to see which regions are supported and which files
|
||||
correspond to each.
|
||||
|
||||
## Checking what you installed
|
||||
|
||||
`--check` reads the BIOS folder, hashes what is there and writes nothing:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh -s -- --check
|
||||
```
|
||||
|
||||
It ends on a count:
|
||||
|
||||
```
|
||||
Checking existing files...
|
||||
5865/5865 present (5865 verified, 0 wrong hash)
|
||||
|
||||
All files up to date.
|
||||
```
|
||||
|
||||
`0 wrong hash` is the line that matters. A number there means a file is present
|
||||
whose contents the platform will reject, which is how a wrong revision or a bad
|
||||
dump shows up.
|
||||
|
||||
The installer's `--check` hashes every file against the list on every
|
||||
platform, so it catches a wrong revision even where the frontend would not:
|
||||
RetroArch, Lakka, RetroPie, MinUI, NextUI and MyMinUI only check that a file
|
||||
exists, while Batocera, RetroBat, Recalbox, EmuDeck, RetroDECK, RomM, ROCKNIX,
|
||||
KNULLI, AmberELEC, EmuELEC and MiSTer FPGA compare
|
||||
MD5 and BizHawk compares SHA1.
|
||||
|
||||
For a single system, or the files a single emulator core reads (`--list-systems`
|
||||
and `--list-cores` give the names):
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh -s -- --check --system sony-playstation
|
||||
curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh -s -- --check --emulator beetle_psx
|
||||
```
|
||||
|
||||
`--verbose` names every file still to fetch, wrong hashes included.
|
||||
Details: [All installer options](installer.md).
|
||||
|
||||
## BIOS not found by emulator
|
||||
|
||||
The file exists on disk, but the emulator reports it as missing.
|
||||
@@ -100,11 +146,8 @@ name per file: `BIOS.col`, never `bios.col` beside it, since extracting both on
|
||||
Windows or macOS would overwrite one with the other. On Linux, Mesen-CE opens
|
||||
`bios.col` and NP2kai opens the lowercase `np2kai/2608_*.wav`, which the pack
|
||||
only holds as `BIOS.col` and `2608_*.WAV`. The installer checks whether the
|
||||
BIOS directory keeps case and, if it does, also fetches these names. If you
|
||||
extract the ZIP on Linux by hand, take the Lakka pack instead: it is the
|
||||
RetroArch pack with both spellings. Releases up to v2026.10.10 have no Lakka
|
||||
pack of their own (`RetroArch_Lakka_*_BIOS_Pack.zip` serves both and holds one
|
||||
spelling), so with those use the installer.
|
||||
BIOS directory keeps case and, if it does, also fetches these names. On Linux, use the installer
|
||||
rather than extracting the ZIP by hand.
|
||||
|
||||
The reverse happens on Batocera and Recalbox, whose lists hold both spellings
|
||||
because their systems keep case: NP2kai reads `np2kai/bios.rom` and
|
||||
@@ -113,149 +156,6 @@ because their systems keep case: NP2kai reads `np2kai/bios.rom` and
|
||||
installer checks the folder first, keeps one file per name there and lists
|
||||
the ones it left out.
|
||||
|
||||
## Hash mismatch / UNTESTED
|
||||
|
||||
This section and the two after it are about this repository's own tools, run
|
||||
from a clone. `scripts/verify.py` checks the collection in `bios/` against each
|
||||
platform, never your BIOS folder: for that, use `--check` above.
|
||||
|
||||
`verify.py` reports `UNTESTED` for a file of the collection that was hashed
|
||||
and does not match what the platform declares. The line gives the reason:
|
||||
|
||||
```
|
||||
UNTESTED (required): nintendo-ds/dsifirmware.bin: declared hash contradicted by the local file
|
||||
```
|
||||
|
||||
The system page on the site lists every known version of the file with its
|
||||
expected MD5 and SHA1.
|
||||
|
||||
### Existence-mode platforms never report UNTESTED
|
||||
|
||||
On RetroArch, Lakka and RetroPie, the platform check only asks whether the file
|
||||
is there, so the only outcomes are OK and MISSING. `verify.py` adds the emulator
|
||||
ground truth from the profiles and flags a `DISCREPANCY` when a file passes the
|
||||
platform check but fails the emulator's own size or hash validation.
|
||||
|
||||
### The .variants/ directory
|
||||
|
||||
When multiple versions of the same BIOS exist (different revisions, regions, or
|
||||
dumps), the primary version lives in the main directory and alternatives live in
|
||||
`.variants/`. `verify.py` checks the primary file first, then falls back to
|
||||
variants when resolving by hash.
|
||||
|
||||
If your file matches a variant hash but not the primary, it's a valid BIOS --
|
||||
just not the preferred version. Some cores accept multiple versions.
|
||||
|
||||
## Pack is missing files
|
||||
|
||||
A generated pack doesn't contain all the files you expected.
|
||||
|
||||
### Severity levels
|
||||
|
||||
`verify.py` assigns a severity to each issue, counted under `severity_counts`
|
||||
in its `--json` output. Not all missing files are equally important:
|
||||
|
||||
| Severity | Meaning | Action needed |
|
||||
|----------|---------|---------------|
|
||||
| CRITICAL | Required file missing on an MD5 or SHA1 platform | Must fix. Core won't function. |
|
||||
| WARNING | Optional file missing on an MD5 or SHA1 platform, hash mismatch (UNTESTED) on any hash platform, or a required file missing on an existence platform | Core works but with reduced functionality, or runs on content nobody verified. |
|
||||
| INFO | Optional file missing on an existence-only platform, or a missing file the core covers with an HLE fallback | Core works fine, BIOS improves accuracy. |
|
||||
| OK | File present and verified | No action needed. |
|
||||
|
||||
The full mapping, including how `hle_fallback` overrides the platform mode, is
|
||||
in [verification modes](verification-modes.md#severity-matrix).
|
||||
|
||||
Focus on CRITICAL issues first. WARNING files improve the experience but aren't
|
||||
strictly necessary. INFO files are nice to have.
|
||||
|
||||
### Large files (release assets)
|
||||
|
||||
Files like PS3UPDAT.PUP, PSVUPDAT.PUP, and Switch firmware are too large for the
|
||||
git repository. They are stored as GitHub release assets under the `large-files`
|
||||
release and downloaded at build time.
|
||||
|
||||
If a pack build fails to include these, check your network connection. In offline
|
||||
mode (`--offline`), large files are only included if already cached locally in
|
||||
`.cache/large/`.
|
||||
|
||||
### Data directories
|
||||
|
||||
Some cores need entire directory trees rather than individual files (e.g. Dolphin's
|
||||
`Sys/` directory, PPSSPP's `assets/`). These are fetched by `refresh_data_dirs.py`
|
||||
from upstream repositories.
|
||||
|
||||
In offline mode, data directories are only included if already cached in `data/`.
|
||||
Run `python scripts/refresh_data_dirs.py` to fetch them.
|
||||
|
||||
## verify.py reports errors
|
||||
|
||||
How to read and interpret `verify.py` output.
|
||||
|
||||
### Status codes
|
||||
|
||||
| Status | Meaning |
|
||||
|--------|---------|
|
||||
| `OK` | File present, hash matches (or existence check passed) |
|
||||
| `UNTESTED` | File present, hash not confirmed against the expected value |
|
||||
| `MISSING` | File not found in the repository |
|
||||
| `DISCREPANCY` | The platform check passes, an emulator's own check fails |
|
||||
|
||||
### Reading the output
|
||||
|
||||
The first line counts the platform's files and names its check. Under it come
|
||||
the entries that need attention, one per line as `STATUS (required|optional):
|
||||
system/file`, followed by a reason where there is one, then the counts of the
|
||||
files the emulator cores add. From `python scripts/verify.py --platform retrodeck`:
|
||||
|
||||
```
|
||||
RetroDECK: 2007/2008 OK, 1 untested [md5]
|
||||
UNTESTED (required): nintendo-ds/dsifirmware.bin: declared hash contradicted by the local file
|
||||
DISCREPANCY: nintendo-snes/sgb2.boot.rom: RetroDECK says OK but supersnes9x says size mismatch: got 524288, accepted [256]
|
||||
supersnes9x [size]
|
||||
Core files: 1495 in pack, 0 required missing, 1 optional missing
|
||||
```
|
||||
|
||||
`--verbose` also lists the passing entries that an emulator validates, with
|
||||
the check and the source lines behind it:
|
||||
|
||||
```
|
||||
Recalbox: 351/351 OK [md5]
|
||||
OK (required): macintosh/MacII.ROM
|
||||
minivmac validates size=262144 [minivmac/cfg/CNFGRAPI.h:32, minivmac/src/OSGLUERETRO.c:781]
|
||||
```
|
||||
|
||||
### Cross-reference section
|
||||
|
||||
After per-file results, `verify.py` prints a cross-reference report. This lists
|
||||
files that emulator cores need but that the platform YAML doesn't declare. These
|
||||
files are still included in packs automatically, but the report helps identify
|
||||
gaps in platform coverage data.
|
||||
|
||||
The cross-reference uses `resolve_platform_cores()` to determine which emulator
|
||||
profiles are relevant for each platform, then checks whether each profile's files
|
||||
appear in the platform config.
|
||||
|
||||
### Filtering output
|
||||
|
||||
```bash
|
||||
# By platform
|
||||
python scripts/verify.py --platform batocera
|
||||
|
||||
# By emulator core
|
||||
python scripts/verify.py --emulator beetle_psx
|
||||
|
||||
# By system
|
||||
python scripts/verify.py --system sony-playstation
|
||||
|
||||
# By hardware target
|
||||
python scripts/verify.py --platform retroarch --target switch
|
||||
|
||||
# JSON for scripted processing: the entries that need attention
|
||||
python scripts/verify.py --platform retroarch --json
|
||||
# every entry, passing ones included, with its ground truth
|
||||
python scripts/verify.py --platform retroarch --json --verbose
|
||||
```
|
||||
|
||||
## Installation script fails
|
||||
|
||||
Problems with `install.py`, `install.sh`, or `download.sh`.
|
||||
@@ -317,7 +217,7 @@ checked before anything is downloaded, so a "No file list" message comes from
|
||||
the revision: `RETROBIOS_REF` naming a tag that does not exist, or one older
|
||||
than the platform. Unset it, or pick a tag from the releases page. What a tag
|
||||
holds and for how long is under
|
||||
[environment overrides](installer.md#environment-overrides).
|
||||
Details: [environment overrides](installer.md#environment-overrides).
|
||||
|
||||
### Manual pack not found in release
|
||||
|
||||
@@ -346,3 +246,16 @@ many there are.
|
||||
it against the release's checksums before extracting. Both stage inside the
|
||||
destination directory, never in `/tmp`, which is a RAM disk on most of these
|
||||
systems.
|
||||
## Checks of the collection itself
|
||||
|
||||
<span id="hash-mismatch-untested"></span><span id="pack-is-missing-files"></span><span id="verifypy-reports-errors"></span>
|
||||
|
||||
`scripts/verify.py` checks this project's own collection against each
|
||||
platform, from a clone of the repository. It never reads your BIOS folder.
|
||||
Reference: [Reading verify.py output](verification-modes.md#hash-mismatch-untested).
|
||||
|
||||
!!! tip "Next"
|
||||
|
||||
- The page of your setup, from [Get your files](../which-pack.md): its folder
|
||||
and how to check it
|
||||
- [FAQ](faq.md), for the questions people ask before installing
|
||||
+148
-1
@@ -1,4 +1,8 @@
|
||||
# Verification modes
|
||||
---
|
||||
level: reference
|
||||
---
|
||||
|
||||
# How each platform checks files
|
||||
|
||||
Each platform verifies BIOS files differently. `verify.py` replicates the native behavior
|
||||
of each platform so that verification results match what the platform itself would report.
|
||||
@@ -413,3 +417,146 @@ name or any name the emulator's hashes reach. If found, it ships. If not, the
|
||||
Batocera-verified file ships and the discrepancy stays visible in verification
|
||||
and gap reporting.
|
||||
|
||||
## Hash mismatch / UNTESTED
|
||||
|
||||
This section and the two after it are about this repository's own tools, run
|
||||
from a clone. `scripts/verify.py` checks the collection in `bios/` against each
|
||||
platform, never your BIOS folder: for that, use the installer's `--check`
|
||||
([When a game does not start](troubleshooting.md)).
|
||||
|
||||
`verify.py` reports `UNTESTED` for a file of the collection that was hashed
|
||||
and does not match what the platform declares. The line gives the reason:
|
||||
|
||||
```
|
||||
UNTESTED (required): nintendo-ds/dsifirmware.bin: declared hash contradicted by the local file
|
||||
```
|
||||
|
||||
The system page on the site lists every known version of the file with its
|
||||
expected MD5 and SHA1.
|
||||
|
||||
### Existence-mode platforms never report UNTESTED
|
||||
|
||||
On RetroArch, Lakka and RetroPie, the platform check only asks whether the file
|
||||
is there, so the only outcomes are OK and MISSING. `verify.py` adds the emulator
|
||||
ground truth from the profiles and flags a `DISCREPANCY` when a file passes the
|
||||
platform check but fails the emulator's own size or hash validation.
|
||||
|
||||
### The .variants/ directory
|
||||
|
||||
When multiple versions of the same BIOS exist (different revisions, regions, or
|
||||
dumps), the primary version lives in the main directory and alternatives live in
|
||||
`.variants/`. `verify.py` checks the primary file first, then falls back to
|
||||
variants when resolving by hash.
|
||||
|
||||
If your file matches a variant hash but not the primary, it's a valid BIOS --
|
||||
just not the preferred version. Some cores accept multiple versions.
|
||||
|
||||
## Pack is missing files
|
||||
|
||||
A generated pack doesn't contain all the files you expected.
|
||||
|
||||
### Severity levels
|
||||
|
||||
`verify.py` assigns a severity to each issue, counted under `severity_counts`
|
||||
in its `--json` output. Not all missing files are equally important:
|
||||
|
||||
| Severity | Meaning | Action needed |
|
||||
|----------|---------|---------------|
|
||||
| CRITICAL | Required file missing on an MD5 or SHA1 platform | Must fix. Core won't function. |
|
||||
| WARNING | Optional file missing on an MD5 or SHA1 platform, hash mismatch (UNTESTED) on any hash platform, or a required file missing on an existence platform | Core works but with reduced functionality, or runs on content nobody verified. |
|
||||
| INFO | Optional file missing on an existence-only platform, or a missing file the core covers with an HLE fallback | Core works fine, BIOS improves accuracy. |
|
||||
| OK | File present and verified | No action needed. |
|
||||
|
||||
The full mapping, including how `hle_fallback` overrides the platform mode, is
|
||||
in [severity matrix](#severity-matrix).
|
||||
|
||||
Focus on CRITICAL issues first. WARNING files improve the experience but aren't
|
||||
strictly necessary. INFO files are nice to have.
|
||||
|
||||
### Large files (release assets)
|
||||
|
||||
Files like PS3UPDAT.PUP, PSVUPDAT.PUP, and Switch firmware are too large for the
|
||||
git repository. They are stored as GitHub release assets under the `large-files`
|
||||
release and downloaded at build time.
|
||||
|
||||
If a pack build fails to include these, check your network connection. In offline
|
||||
mode (`--offline`), large files are only included if already cached locally in
|
||||
`.cache/large/`.
|
||||
|
||||
### Data directories
|
||||
|
||||
Some cores need entire directory trees rather than individual files (e.g. Dolphin's
|
||||
`Sys/` directory, PPSSPP's `assets/`). These are fetched by `refresh_data_dirs.py`
|
||||
from upstream repositories.
|
||||
|
||||
In offline mode, data directories are only included if already cached in `data/`.
|
||||
Run `python scripts/refresh_data_dirs.py` to fetch them.
|
||||
|
||||
## verify.py reports errors
|
||||
|
||||
How to read and interpret `verify.py` output.
|
||||
|
||||
### Status codes
|
||||
|
||||
| Status | Meaning |
|
||||
|--------|---------|
|
||||
| `OK` | File present, hash matches (or existence check passed) |
|
||||
| `UNTESTED` | File present, hash not confirmed against the expected value |
|
||||
| `MISSING` | File not found in the repository |
|
||||
| `DISCREPANCY` | The platform check passes, an emulator's own check fails |
|
||||
|
||||
### Reading the output
|
||||
|
||||
The first line counts the platform's files and names its check. Under it come
|
||||
the entries that need attention, one per line as `STATUS (required|optional):
|
||||
system/file`, followed by a reason where there is one, then the counts of the
|
||||
files the emulator cores add. From `python scripts/verify.py --platform retrodeck`:
|
||||
|
||||
```
|
||||
RetroDECK: 2007/2008 OK, 1 untested [md5]
|
||||
UNTESTED (required): nintendo-ds/dsifirmware.bin: declared hash contradicted by the local file
|
||||
DISCREPANCY: nintendo-snes/sgb2.boot.rom: RetroDECK says OK but supersnes9x says size mismatch: got 524288, accepted [256]
|
||||
supersnes9x [size]
|
||||
Core files: 1495 in pack, 0 required missing, 1 optional missing
|
||||
```
|
||||
|
||||
`--verbose` also lists the passing entries that an emulator validates, with
|
||||
the check and the source lines behind it:
|
||||
|
||||
```
|
||||
Recalbox: 351/351 OK [md5]
|
||||
OK (required): macintosh/MacII.ROM
|
||||
minivmac validates size=262144 [minivmac/cfg/CNFGRAPI.h:32, minivmac/src/OSGLUERETRO.c:781]
|
||||
```
|
||||
|
||||
### Cross-reference section
|
||||
|
||||
After per-file results, `verify.py` prints a cross-reference report. This lists
|
||||
files that emulator cores need but that the platform YAML doesn't declare. These
|
||||
files are still included in packs automatically, but the report helps identify
|
||||
gaps in platform coverage data.
|
||||
|
||||
The cross-reference uses `resolve_platform_cores()` to determine which emulator
|
||||
profiles are relevant for each platform, then checks whether each profile's files
|
||||
appear in the platform config.
|
||||
|
||||
### Filtering output
|
||||
|
||||
```bash
|
||||
# By platform
|
||||
python scripts/verify.py --platform batocera
|
||||
|
||||
# By emulator core
|
||||
python scripts/verify.py --emulator beetle_psx
|
||||
|
||||
# By system
|
||||
python scripts/verify.py --system sony-playstation
|
||||
|
||||
# By hardware target
|
||||
python scripts/verify.py --platform retroarch --target switch
|
||||
|
||||
# JSON for scripted processing: the entries that need attention
|
||||
python scripts/verify.py --platform retroarch --json
|
||||
# every entry, passing ones included, with its ground truth
|
||||
python scripts/verify.py --platform retroarch --json --verbose
|
||||
```
|
||||
@@ -0,0 +1,76 @@
|
||||
---
|
||||
level: start
|
||||
---
|
||||
|
||||
# What BIOS files are
|
||||
|
||||
Many consoles have a small program built into them. It runs when the console
|
||||
is switched on, sets up the hardware and then starts the game. That program is
|
||||
called the BIOS, or the firmware.
|
||||
|
||||
An emulator recreates a console in software. To start the games of many
|
||||
consoles, it needs a copy of that built-in program. The copy is a file, and
|
||||
that file is what people call a BIOS file.
|
||||
|
||||
<!-- image: bios-chain -->
|
||||
|
||||
## How the pieces fit together
|
||||
|
||||
1. You pick a game in the **frontend**, the menu you play from (EmulationStation,
|
||||
the RetroArch menu, MinUI and others).
|
||||
2. The frontend starts an **emulator** for that console.
|
||||
3. The emulator reads the **BIOS file** from the **BIOS folder** of your setup.
|
||||
4. The game starts.
|
||||
|
||||
When the file is not in the folder, or is not the version the emulator expects,
|
||||
step 3 fails. The emulator then says that a BIOS is missing, or the game stays
|
||||
on a black screen.
|
||||
|
||||
## Do I need them?
|
||||
|
||||
It depends on the console.
|
||||
|
||||
- **Usually yes** for consoles that start every game through their own
|
||||
program: PlayStation, PlayStation 2, Saturn, Mega-CD, PC Engine CD, Neo Geo,
|
||||
Dreamcast, and many home computers.
|
||||
- **Usually not** for cartridge consoles such as the NES, the Super Nintendo,
|
||||
the Mega Drive, the Game Boy and the Game Boy Advance. Their emulators start
|
||||
the games without one. Some can use one to show the original start-up screen.
|
||||
- **Add-ons need their own**, even on those consoles: the Famicom Disk System
|
||||
and the Mega-CD each have a BIOS.
|
||||
|
||||
Some emulators can stand in for the BIOS with code of their own. This is called
|
||||
HLE, for high-level emulation. It works for many games, but some glitch or do
|
||||
not start. The real file gives the best results, so the packs include it.
|
||||
|
||||
Details: [the files each console needs](../systems/index.md), with the
|
||||
emulators that read them.
|
||||
|
||||
## Where they go
|
||||
|
||||
Each setup keeps its BIOS files in a folder of its own: `system` for RetroArch,
|
||||
`/userdata/bios` on Batocera, `Emulation/bios` with EmuDeck. The page of your
|
||||
setup gives the exact folder.
|
||||
|
||||
The name matters. An emulator looks for an exact name, such as `scph5501.bin`
|
||||
for a PlayStation, and a file with another name is not found.
|
||||
|
||||
## Why the right version matters
|
||||
|
||||
Two files with the same name can hold different versions: one per region, or
|
||||
a newer revision of the same chip. Some setups, among them Batocera, Recalbox
|
||||
and EmuDeck, compare a fingerprint of the file's contents, called a hash, and
|
||||
refuse a version they do not list. RetroBIOS gives each setup the versions it
|
||||
expects.
|
||||
|
||||
## Is it legal?
|
||||
|
||||
Laws on copying console firmware differ by country, and the question is not
|
||||
settled. The [project's position](faq.md#is-this-legal) explains where it
|
||||
stands, where its arguments are weakest, and how to ask for a file to be
|
||||
removed.
|
||||
|
||||
!!! tip "Next"
|
||||
|
||||
- [Get your files](../which-pack.md), for the setup you play on
|
||||
- [Glossary](glossary.md), every word these pages use
|
||||
Reference in new issue
Block a user