diff --git a/README.md b/README.md index 4814dbab5..c3213a1fe 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Some consoles need a small program, the **BIOS**, to start their games: PlayStat ## Install in one line -**Windows**: open the Start menu, type **PowerShell** and open it. Paste this line (right-click in the window) and press Enter. +**Windows**: open the Start menu, type **PowerShell** and open it. Paste this line (Ctrl+V or right-click in the window) and press Enter. ```powershell irm https://abdess.github.io/retrobios/i.ps1 | iex @@ -27,9 +27,9 @@ curl -fsSL https://abdess.github.io/retrobios/i | sh **A handheld, an SD card, or not sure?** [Pick the device](https://abdess.github.io/retrobios/which-pack/): its page gives the folder and the command. A muOS, Onion, spruceOS, MinUI, KNULLI, ROCKNIX, Lakka or MiSTer SD card plugged into the computer is found by itself. -![Recording of the one-line command in a terminal. The installer finds an ArkOS SD card with 6 games, plans 43 BIOS files (15.1 MB) for them, installs them and shows the summary.](docs_assets/demo/install.gif) +![Recording of the one-line command in a terminal, on a demonstration card. The installer finds an ArkOS SD card with 6 games, plans 43 BIOS files (15.1 MB) for them, installs them and shows the summary.](docs_assets/demo/install.gif) -The installer finds the setup and its BIOS folder, installs the files it needs (only what the games need when it finds them on the card) and checks each one. Its screen installs everything, or fewer under **Choose systems**. Arrow keys and Enter drive it, or a controller on a handheld. It sends nothing back ([what is counted](https://abdess.github.io/retrobios/wiki/privacy/)). Options go after the line in the form the [installer page](https://abdess.github.io/retrobios/wiki/installer/#passing-options) gives. +The installer finds the setup and its BIOS folder, installs the files it needs (only what the games need when it finds them on the card) and checks each one. Its screen installs everything, or fewer under **Choose systems**. Arrow keys and Enter drive it, or a controller on a handheld. It sends no report of its own ([what is counted](https://abdess.github.io/retrobios/wiki/privacy/)). Options go after the line in the form the [installer page](https://abdess.github.io/retrobios/wiki/installer/#passing-options) gives. First time? [The first install, step by step](https://abdess.github.io/retrobios/wiki/first-install/). A game does not start: [what to check](https://abdess.github.io/retrobios/wiki/troubleshooting/). Other questions: [FAQ](https://abdess.github.io/retrobios/wiki/faq/). @@ -57,12 +57,12 @@ Unzip into the BIOS folder, files straight in it. A big pack comes in parts (`Pa - Every console and the files it needs: [systems](https://abdess.github.io/retrobios/systems/) - Asking an AI assistant: it reads the site best from [llms.txt](https://abdess.github.io/retrobios/llms.txt) -## What makes it different +## How it is built -- **623 emulators profiled from their source code**: each file an emulator loads, its hash and the line of code that reads it +- **623 emulators profiled**, 589 from their source code and 34 closed-source builds from their binaries: 93% of the files they load cite the file and line that reads them - **18 setups**, each checked its own way: MD5 for Batocera and Recalbox, the file name for RetroArch, as their own code does - **532 systems**, 19,947 files in the collection, [what is still missing](https://abdess.github.io/retrobios/gaps/) named file by file -- Public data: [JSON, CSV and SQLite](https://abdess.github.io/retrobios/data/), MIT licensed +- Public data: [JSON, CSV and SQLite](https://abdess.github.io/retrobios/data/), the metadata under MIT
For developers: build a pack @@ -105,4 +105,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 project's legal position](https://abdess.github.io/retrobios/wiki/legal/). -*Auto-generated on 2026-11-09T06:27:53Z* +*Auto-generated on 2026-11-09T07:40:17Z* diff --git a/docs_assets/demo/demo.json b/docs_assets/demo/demo.json index f551f79c2..01fcbfc18 100644 --- a/docs_assets/demo/demo.json +++ b/docs_assets/demo/demo.json @@ -7,7 +7,7 @@ "systems": 6, "files": 43, "size": "15.1 MB", - "alt": "Recording of the one-line command in a terminal. The installer finds an ArkOS SD card with 6 games, plans 43 BIOS files (15.1 MB) for them, installs them and shows the summary." + "alt": "Recording of the one-line command in a terminal, on a demonstration card. The installer finds an ArkOS SD card with 6 games, plans 43 BIOS files (15.1 MB) for them, installs them and shows the summary." }, "handheld": { "width": 640, @@ -18,6 +18,6 @@ "files": 43, "size": "15.1 MB", "pad": "gptokeyb", - "alt": "Recording of the full-screen installer on the 640 by 480 screen of a handheld, started from the Tools menu of ArkOS. It finds the 6 games on the card, plans 43 BIOS files (15.1 MB) for them, installs them and shows the summary. The A button chooses, and the bottom line names the buttons." + "alt": "Recording of the full-screen installer on the 640 by 480 screen of a handheld, started from the Tools menu of ArkOS, on a demonstration card. It finds the 6 games on the card, plans 43 BIOS files (15.1 MB) for them, installs them and shows the summary. The A button chooses, and the bottom line names the buttons." } } diff --git a/scripts/generate_readme.py b/scripts/generate_readme.py index 9c6ec4084..ccb75a42a 100644 --- a/scripts/generate_readme.py +++ b/scripts/generate_readme.py @@ -581,6 +581,15 @@ def generate_readme(db: dict, platforms_dir: str, db_path: str = "database.json" load_emulator_profiles("emulators", skip_aliases=False) ) emulator_count = len(profiles) + profile_files = [f for prof in profiles.values() for f in prof.get("files") or [] + if isinstance(f, dict)] + # A citation counts when it names a line, `file.c:120`: a bare file name + # or a binary offset does not point at the code that reads the file. + cited_share = (round(100 * sum(1 for f in profile_files + if re.search(r"\.\w+:\d", str(f.get("source_ref") or ""))) + / len(profile_files)) if profile_files else 0) + closed_count = sum(1 for prof in profiles.values() + if str(prof.get("upstream") or "").startswith("closed")) comp = compute_composition(db) missing_total = len(set().union(*(c["missing_names"] for c in coverages.values()))) # The entries marked `unsourceable:` are never served by name, so a @@ -627,7 +636,7 @@ def generate_readme(db: dict, platforms_dir: str, db_path: str = "database.json" "## Install in one line", "", "**Windows**: open the Start menu, type **PowerShell** and open it. Paste this line" - " (right-click in the window) and press Enter.", + " (Ctrl+V or right-click in the window) and press Enter.", "", "```powershell", install_command("powershell"), @@ -649,8 +658,8 @@ def generate_readme(db: dict, platforms_dir: str, db_path: str = "database.json" "The installer finds the setup and its BIOS folder, installs the files it needs (only" " what the games need when it finds them on the card) and checks each one. Its screen" " installs everything, or fewer under **" + _installer_words().TUI_SYSTEMS_ROW + "**." - " Arrow keys and Enter drive it, or a controller on a handheld. It sends nothing back" - f" ([what is counted]({SITE_URL}wiki/privacy/)). Options go after the line in the" + " Arrow keys and Enter drive it, or a controller on a handheld. It sends no report of" + f" its own ([what is counted]({SITE_URL}wiki/privacy/)). Options go after the line in the" f" form the [installer page]({SITE_URL}wiki/installer/#passing-options) gives.", "", f"First time? [The first install, step by step]({SITE_URL}wiki/first-install/)." @@ -694,15 +703,16 @@ def generate_readme(db: dict, platforms_dir: str, db_path: str = "database.json" f"- Every console and the files it needs: [systems]({SITE_URL}systems/)", f"- Asking an AI assistant: it reads the site best from [llms.txt]({SITE_URL}llms.txt)", "", - "## What makes it different", + "## How it is built", "", - f"- **{emulator_count} emulators profiled from their source code**: each file an emulator" - " loads, its hash and the line of code that reads it", + f"- **{emulator_count} emulators profiled**, {emulator_count - closed_count} from their" + f" source code and {closed_count} closed-source builds from their binaries:" + f" {cited_share}% of the files they load cite the file and line that reads them", f"- **{len(coverages)} setups**, each checked its own way: MD5 for Batocera and Recalbox," " the file name for RetroArch, as their own code does", f"- **{len(system_ids)} systems**, {total_files:,} files in the collection," f" [what is still missing]({SITE_URL}gaps/) named file by file", - f"- Public data: [JSON, CSV and SQLite]({SITE_URL}data/), MIT licensed", + f"- Public data: [JSON, CSV and SQLite]({SITE_URL}data/), the metadata under MIT", "", "
", "For developers: build a pack", diff --git a/scripts/make_demo.py b/scripts/make_demo.py index 40346d8cc..e4ba1f212 100644 --- a/scripts/make_demo.py +++ b/scripts/make_demo.py @@ -349,10 +349,10 @@ def describe(variant: str, facts: dict) -> str: if variant == "handheld": return (f"Recording of the full-screen installer on the {facts['width']} by " f"{facts['height']} screen of a handheld, started from the Tools menu of " - f"{facts['setup']}. It finds the {facts['games']} games on the card, {plan} The " - "A button chooses, and the bottom line names the buttons.") - return (f"Recording of the one-line command in a terminal. The installer finds an " - f"{facts['setup']} SD card with {facts['games']} games, {plan}") + f"{facts['setup']}, on a demonstration card. It finds the {facts['games']} games " + f"on the card, {plan} The A button chooses, and the bottom line names the buttons.") + return (f"Recording of the one-line command in a terminal, on a demonstration card. The " + f"installer finds an {facts['setup']} SD card with {facts['games']} games, {plan}") def measure(session: Path, env: dict[str, str], variant: Variant = VARIANTS["default"]) -> dict: diff --git a/tests/test_site_privacy.py b/tests/test_site_privacy.py index bf2dae448..d23b8c31c 100644 --- a/tests/test_site_privacy.py +++ b/tests/test_site_privacy.py @@ -87,7 +87,7 @@ class ThePageSaysWhatIsCounted(unittest.TestCase): page = PRIVACY.read_text(encoding="utf-8") for said in ("No cookies", "Do Not Track", "Global Privacy Control", "copy button", "found nothing", "Did this page help?", - "The installer sends nothing back", "retrobios.goatcounter.com"): + "The installer sends no report of its own", "retrobios.goatcounter.com"): with self.subTest(said=said): self.assertIn(said, page) diff --git a/wiki/faq.md b/wiki/faq.md index a838639d0..e8aa98554 100644 --- a/wiki/faq.md +++ b/wiki/faq.md @@ -8,7 +8,9 @@ terms: ios, iphone, ipad ## Are BIOS files needed? { #do-i-need-bios-files } -- **Yes** for PlayStation 1 and 2, Saturn and Neo Geo. +- **Yes** for PlayStation 2 and Neo Geo. +- **Most emulators** for PlayStation 1 and Saturn. Some start games without + it, with a built-in replacement. - **Better with it** for Dreamcast. Some games need it. - **Usually not** for NES or Super Nintendo. @@ -63,7 +65,7 @@ Game sets must match the emulator's version: - It stops if the installer does not match its expected fingerprint, and checks each file. - It fills the BIOS folder, some save folders and a games cache. -- It never touches games or saves. +- It never touches games or save files. - It keeps each file it replaces in `retrobios-backup`, for `--restore`. Read them: [install.sh](https://github.com/Abdess/retrobios/blob/main/install.sh), @@ -78,7 +80,7 @@ and download their files. ## Why is there no ZIP for a setup? { #why-is-there-no-zip-for-my-setup } ZIPs are made for the setups most people download. The command installs every -setup's files and checks each one. `--dry-run` shows the list first. +file the collection holds for each setup and checks each one. `--dry-run` shows the list first. ## Fill an SD card from a computer? @@ -110,7 +112,8 @@ Fill it from a computer or point `--from-pack` at the ZIP: [Without a network](i ## Why is a file missing from the ZIP? -Some come with the emulator. +Some come with the emulator. Others are not in the collection yet: +[what is still missing](../gaps.md) names each one. ## A game shows a black screen { #my-game-shows-a-black-screen } diff --git a/wiki/first-install.md b/wiki/first-install.md index 8232b3521..dedd8285d 100644 --- a/wiki/first-install.md +++ b/wiki/first-install.md @@ -5,7 +5,7 @@ order: 30 # First install, step by step -From an empty BIOS folder to games that start. +From an empty BIOS folder to every BIOS file the setup's list names. **Needed:** internet and some free space. @@ -102,7 +102,8 @@ Esc or Ctrl+C stops, B on a handheld. Run again to resume. ## 5. Read the result -- **Done**: all files are in place. +- **Done**: every file the collection holds for this setup is in place. The + screen names any file it does not hold. - **Finished with errors**: run it again. It retries only those. - **Finished with files missing**: run it again online. - **Nothing installed**: the screen says why. See [If it stops](#if-it-stops). diff --git a/wiki/installer.md b/wiki/installer.md index 8125573fc..689e379ca 100644 --- a/wiki/installer.md +++ b/wiki/installer.md @@ -871,8 +871,9 @@ computer, one subfolder per system. A run that asks nothing (`--yes`, the card, and says so. `--all-files` installs the whole list instead, as does a run narrowed by name (`--system`, `--core`, `--region`, `--emulator`). -The rule is that every game must start. Per system, the run keeps what the -system's default core reads. One region is kept only where the game's own +Per system, the run keeps what the system's default core reads for the games +found. Another core can need more files: **Install everything** covers every +core. One region is kept only where the game's own content proves it: a cartridge's crc32 found in No-Intro, a disc serial found in Redump, or a header the core reads. A file name such as `(Europe)` proves nothing. Where a core forces a region by an option, falls back to another @@ -1021,7 +1022,8 @@ what the options name, everything by default. when every one does, and 1 when the check itself failed. What it lists is under [Why a file is refused](#why-a-file-is-refused). An install leaves a file with the expected hash untouched and replaces any other, the old one kept beside -the BIOS folder. Files the list does not name are never read, moved or deleted. +the BIOS folder. Files the list does not name are never moved or deleted. A file whose size +matches a listed one is read, to find a misplaced copy. ## Platform detection @@ -1338,8 +1340,9 @@ exits 1. Some files are read by a standalone emulator from its own data directory rather than from the platform's BIOS tree. `--standalone-copies` copies them -there after the install, and only then: without the flag nothing is written -outside the selected tree, apart from the files kept in `retrobios-backup`. +there after the install, and only then: without the flag a run writes only to the BIOS +folder, the save folders its list names, `retrobios-backup` and the +installer's cache folder. The manifest carries the list on the six platforms that declare one (Batocera, EmuDeck, Recalbox, RetroArch, RetroBat, RetroDECK). It has two diff --git a/wiki/legal.md b/wiki/legal.md index 219d1f134..7cd0dd89e 100644 --- a/wiki/legal.md +++ b/wiki/legal.md @@ -8,7 +8,9 @@ terms: license It depends on the country. Nothing here is legal advice. -- Making an emulator is legal in the US. EU law allows it under conditions. +- US courts held that copying code to build a compatible emulator can be fair + use (*Sega v. Accolade*, *Sony v. Connectix*). EU law allows it under + conditions. - Sharing BIOS files is not settled law. The strongest case is old consoles no longer sold. The weakest is encryption keys (Switch, 3DS, Wii U). - The files are here for personal backup and preservation. diff --git a/wiki/measurements.md b/wiki/measurements.md index f3a74e1c8..ae5d0114d 100644 --- a/wiki/measurements.md +++ b/wiki/measurements.md @@ -54,7 +54,9 @@ file under the BIOS name: zeros, half the file, or another region's BIOS. Each result is a full record in the [`measurements/`](https://github.com/Abdess/retrobios/tree/main/measurements) folder of this project. It names its method, the computer and the exact build -of the emulator. A record is never changed once added. +of the emulator. Records are added, not edited. A change to an existing record (scratch paths +removed on 2026-11-05 and 2026-11-06) is a commit of its own, visible in the +folder's history. The results so far ran on these computers: diff --git a/wiki/privacy.md b/wiki/privacy.md index 3de04c088..17158ce31 100644 --- a/wiki/privacy.md +++ b/wiki/privacy.md @@ -6,8 +6,8 @@ terms: privacy, cookies, analytics, tracking # What is counted -No cookies. No account. Nothing is stored on the device, and nothing -links a visit to a person. +No cookies. No account. The browser keeps the chosen setup, tab and theme in +its own storage, which is never sent. Nothing links a visit to a person. ## On this site @@ -35,7 +35,9 @@ These actions are counted the same way, with the page they happened on: as "other", without its words; - the answer to "Did this page help?". -Not sent: the screen size, the language, a search that found results. +The script adds neither the screen size nor the language, and nothing for a +search that found results. GoatCounter reads the headers a browser sends with +any request. The totals are kept two years and are public: [retrobios.goatcounter.com](https://retrobios.goatcounter.com). @@ -46,8 +48,9 @@ stops GoatCounter changes nothing on the site. ## The installer -The installer sends nothing back. It downloads files from GitHub, which sees -those requests as it sees any download. +The installer sends no report of its own. It downloads files from GitHub, +which sees those requests as it sees any download, with the Python or +PowerShell version in their header. ## Search engines diff --git a/wiki/reading-reports.md b/wiki/reading-reports.md index 654ee3a38..a442b116f 100644 --- a/wiki/reading-reports.md +++ b/wiki/reading-reports.md @@ -52,9 +52,9 @@ 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. | +| CRITICAL | Required file missing on an MD5 or SHA1 platform | The setup's own check fails. Whether the core starts without it is on the emulator's page. | +| 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 | The setup's check warns, or a file it does not read is absent. The emulator's page says what the core does without it. | +| INFO | Optional file missing on an existence-only platform, or a missing file the core covers with an HLE fallback | The profile records that the core runs without it. | | OK | File present and verified | No action needed. | The full mapping, including how `hle_fallback` overrides the platform mode, is diff --git a/wiki/troubleshooting.md b/wiki/troubleshooting.md index dac8412fc..9461e3680 100644 --- a/wiki/troubleshooting.md +++ b/wiki/troubleshooting.md @@ -38,7 +38,8 @@ Read the count line: ## 2. Fix the files -Without `--check`, it adds missing files and replaces wrong ones. +Without `--check`, it adds the missing files the collection holds and +replaces wrong ones. ## 3. Check the folder and the names diff --git a/wiki/verification-modes.md b/wiki/verification-modes.md index 286165b7c..59996121e 100644 --- a/wiki/verification-modes.md +++ b/wiki/verification-modes.md @@ -19,9 +19,11 @@ Example: `scph5501.bin`, MD5 `490f666e1afb15b7362b406ed1cea246`. Any file named This project's `verify.py` reproduces each setup's own check, so its report says what the setup itself would say. A missing file is then ranked by -**severity**: CRITICAL when the setup cannot start that console, WARNING when -it runs degraded or the file's version is in doubt, INFO when nothing visible -changes ([severity matrix](#severity-matrix)). +**severity**, from the setup's check mode and the `required` flag of its list: +CRITICAL for a required file missing where the setup checks hashes, WARNING +for a required file missing where it checks names, or a hash in doubt, INFO +for an optional file or one the core replaces with a built-in fallback +([severity matrix](#severity-matrix)). diff --git a/wiki/what-are-bios-files.md b/wiki/what-are-bios-files.md index 60fd35b65..15e26a961 100644 --- a/wiki/what-are-bios-files.md +++ b/wiki/what-are-bios-files.md @@ -26,8 +26,9 @@ If step 3 fails, the screen says "BIOS missing" or stays black. ## Which consoles need one? { #do-i-need-one } -- **Yes:** PlayStation 1 and 2, Saturn, Neo Geo, PC Engine CD and many home - computers. +- **Yes:** PlayStation 2, Neo Geo, PC Engine CD and many home computers. +- **Most emulators:** PlayStation 1 and Saturn. Some start games without it, + with a built-in replacement. The emulator's page says which. - **Better with it:** Dreamcast. Some games need it. - **Usually not:** NES, Super Nintendo, Mega Drive, Game Boy and Game Boy Advance. @@ -49,7 +50,8 @@ another for Europe. Some setups check each file's **hash**, a fingerprint of its contents. Batocera, Recalbox and EmuDeck report a version they do not expect. -The files here are the versions each setup expects. +Where the collection holds a file, it is the version each setup expects. +[What is still missing](../gaps.md) names the rest. ## Can a game start without it?