3 Commits
50 changed files with 2266 additions and 266 deletions

No files matched your search

+5 -9
View File
@@ -15,10 +15,6 @@ node_modules/
docs/
# Large files stored as GitHub Release assets (> 50MB)
bios/Arcade/Arcade/Firmware.19.0.0.zip
bios/Arcade/Arcade/maclc3.zip
bios/Nintendo/Nintendo DS/dsi_nand.bin
bios/Other/Batocera42/dsi_nand.bin
bios/Sony/PlayStation 3/PS3UPDAT.PUP
bios/Sony/PlayStation 3/.variants/PS3UPDAT.PUP.ed8ab192
bios/Sony/PlayStation Vita/PSVUPDAT.PUP
@@ -66,20 +62,20 @@ tmp/
# FBA2012 Toaplan samples (>100MB)
bios/Arcade/fba2012/samples/fireshrk.zip
bios/Arcade/fba2012/samples/ghox.zip
bios/Arcade/fba2012/samples/samesame.zip
bios/Arcade/fba2012/samples/tekipaki.zip
bios/Arcade/fba2012/samples/vimana.zip
bios/Arcade/fba2012/samples/fireshrk.zip
bios/Arcade/fba2012/samples/samesame.zip
bios/Arcade/fba2012/samples/vimana.zip
bios/Nintendo/Switch/Firmware_batocera43.zip
bios/Nintendo/DS/.variants/dsi_nand.bin.8b79a73c
# Wii NAND backup (528MB, fetched from large-files release)
bios/Nintendo/Wii/nand.bin
# FBNeo audio samples (97MB and 155MB, fetched from large-files release)
# FBNeo audio samples (96MB, 148MB and 199MB, fetched from large-files release)
bios/Other/fbneo/fbneo/samples/donpachi.zip
bios/Other/fbneo/fbneo/samples/sfz3mix.zip
bios/Other/fbneo/fbneo/samples/twotiger.zip
bios/Other/starboard/starboard-rootfs.tar.gz
bios/Other/cspect/cspect-next-8gb.zip
# Output-directory locks (artifact_lock)
.lock
+16 -16
View File
@@ -39,18 +39,18 @@ Every release ships `SHA256SUMS.txt` and a detached signature of it, checkable a
| Platform | Extracted size | Extract to | Download |
|----------|---------------:|-----------|----------|
| Batocera | 4.0 GB | `/userdata/bios/` | [Download](../../releases/latest) |
| BizHawk | 2.2 GB | `Firmware/` | [Download](../../releases/latest) |
| Batocera | 4.2 GB | `/userdata/bios/` | [Download](../../releases/latest) |
| BizHawk | 2.4 GB | `Firmware/` | [Download](../../releases/latest) |
| EmuDeck | 3.2 GB | `~/Emulation/bios/` | [Download](../../releases/latest) |
| Lakka | 5.5 GB | `/storage/system/` | [Download](../../releases/latest) |
| Lakka | 5.7 GB | `/storage/system/` | [Download](../../releases/latest) |
| MiSTer FPGA | 24 MB | `/media/fat/games/` | [Download](../../releases/latest) |
| ROCKNIX | 5.3 GB | `/storage/roms/bios/` | [Download](../../releases/latest) |
| Recalbox | 3.6 GB | `/recalbox/share/bios/` | [Download](../../releases/latest) |
| RetroArch | 5.5 GB | `system/` | [Download](../../releases/latest) |
| RetroBat | 4.4 GB | `bios/` | [Download](../../releases/latest) |
| RetroDECK | 6.2 GB | `~/retrodeck/` | [Download](../../releases/latest) |
| RetroPie * | 5.5 GB | `~/RetroPie/BIOS/` | [Download](../../releases/latest) |
| RomM | 1.3 GB | `bios/{platform_slug}/` | [Download](../../releases/latest) |
| ROCKNIX | 5.5 GB | `/storage/roms/bios/` | [Download](../../releases/latest) |
| Recalbox | 3.8 GB | `/recalbox/share/bios/` | [Download](../../releases/latest) |
| RetroArch | 5.7 GB | `system/` | [Download](../../releases/latest) |
| RetroBat | 4.6 GB | `bios/` | [Download](../../releases/latest) |
| RetroDECK | 6.4 GB | `~/retrodeck/` | [Download](../../releases/latest) |
| RetroPie * | 5.7 GB | `~/RetroPie/BIOS/` | [Download](../../releases/latest) |
| RomM | 1.5 GB | `bios/{platform_slug}/` | [Download](../../releases/latest) |
The RetroDECK pack already contains its own `bios/` folder, so it extracts into `~/retrodeck/` rather than into the BIOS folder.
@@ -65,11 +65,11 @@ Each file is checked the way your platform checks it. Most compare a checksum, t
- **6 files** the platforms' emulators load are still to be found, and 21 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/)
- **12 platforms** supported with platform-specific verification
- **449 emulators** profiled from source (RetroArch cores + standalone)
- **450 emulators** profiled from source (RetroArch cores + standalone)
- **470 systems** handled by those emulators (NES, SNES, PlayStation, Saturn, Dreamcast, ...)
- **10,330 files**, each with its SHA1, MD5, SHA256, CRC32 and Adler-32 fingerprints: 4,985 system files, 2,806 arcade ROM sets, 2,539 game and engine data files
- **553 of 4,985 system files** matched to dump-preservation catalogs (No-Intro, Redump, TOSEC); arcade sets and engine data fall outside what those catalogs index
- **12706 MB** total collection size
- **10,357 files**, each with its SHA1, MD5, SHA256, CRC32 and Adler-32 fingerprints: 5,012 system files, 2,806 arcade ROM sets, 2,539 game and engine data files
- **554 of 5,012 system files** matched to dump-preservation catalogs (No-Intro, Redump, TOSEC); arcade sets and engine data fall outside what those catalogs index
- **12909 MB** total collection size
## Supported systems
@@ -136,7 +136,7 @@ The [documentation site](https://abdess.github.io/retrobios/) provides:
- **Per-emulator profiles** with source code references for every file
- **Per-system pages** showing which emulators and platforms cover each console
- **Gap analysis** identifying missing files and undeclared core requirements
- **Cross-reference** mapping files across 12 platforms and 449 emulators
- **Cross-reference** mapping files across 12 platforms and 450 emulators
- **Versioned data access** through JSON, CSV and SQLite exports with published SHA-256 checksums
## How it works
@@ -174,4 +174,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-09-07T02:33:05Z*
*Auto-generated on 2026-09-14T03:24:09Z*
+1 -15
View File
@@ -173,20 +173,6 @@
"sha1": "2d7d999e2acb4da55c26d1517934d39e7d0a0c86",
"total_copies": 1
},
"bbb.zip": {
"clones": [
"aaa_long_name.zip"
],
"sha1": "0ebda75e11e0fdce192562b5bb65a00e3e3bf240",
"total_copies": 1
},
"bbc_m87.zip": {
"clones": [
"bbc_24bbc.zip"
],
"sha1": "0ebda75e11e0fdce192562b5bb65a00e3e3bf240",
"total_copies": 1
},
"beebsid.zip": {
"clones": [
"bbc_opus3.zip"
@@ -607,4 +593,4 @@
"sha1": "9139c00e5986b7a86c7e8dcbce39986126ab7db4",
"total_copies": 1
}
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+765 -19
View File
File diff suppressed because it is too large. Load diff
+664
View File
@@ -0,0 +1,664 @@
emulator: POM2
type: standalone
core_classification: other
source: "https://github.com/habib256/pom2"
upstream: "https://github.com/habib256/pom2"
profiled_date: "2026-09-14"
source_commit: "78aa14c1135ea9eaf3e68f09d624fab788aab236"
core_version: "0.9.2"
display_name: "Apple - Apple II (POM2)"
cores:
- pom2
systems:
- apple-ii
mode: standalone
notes: |
Apple ][, ][+, //e, //c and //c+ emulator by Arnaud Verhille, C++ with an
ImGui frontend, plus a browser build and a headless CLI. Nine machine
profiles (SystemProfile.cpp:32-300): Apple ][ Original, ][+, //e
Unenhanced, //e Enhanced, //c, //c Plus, and PAL variants of the //e
Unenhanced, //e Enhanced (the default) and //c (Le Chat Mauve).
Every file is looked up by a relative name through findResource
(ResourcePaths.cpp:173-246): the per-user data directory
(~/.local/share/POM2, ~/Library/Application Support/POM2,
%LOCALAPPDATA%\POM2), the executable directory, its parent,
../share/POM2, then the working directory and its two parents. The
first hit wins. Release packages ship the whole roms/ tree, the fonts and
the two photos (packaging/bundle.manifest).
Machine firmware is a probe chain per profile, first name found wins
(SystemProfile.cpp romProbeOrder, MainWindow_Slots.cpp:1458-1481):
][ Original apple2o.rom, apple2.rom
][+ apple2p.rom, apple2.rom
//e Unenhanced apple2e_unenh.rom, 342-0135-b.64.rom, apple2e.rom
//e Enhanced apple2e.rom
//c apple2c-32Kv0.rom, apple2c-16K.rom, 3420033a.256
//c Plus apple2cp.rom, apple2c-plus.rom, apple2c-32Kv0.rom
With no candidate the machine runs on a $D000-$FFFF stub and the Welcome
panel opens (MainWindow.cpp:318-326). A first run with no //e image falls
back to the ][+ chain (MainWindow.cpp:223-236). Memory::loadAppleIIRom
(Memory.cpp:174-224) maps 12 KB at $D000, 16 KB at $C000, skips the 4 KB
pad of a 20 KB ][+ dump, and slices a 32 KB dump by profile: //e images
carry the firmware in the upper half, //c and //c+ images are two firmware
banks with bank 0 in the lower half (SystemProfile.cpp:432).
Character generators follow charRomProbeOrder per profile, or the locale
picked in the toolbar (CharRomCatalog.cpp:42-79, MainWindow_Slots.cpp:
1489-1505). Memory::loadCharRom accepts 2 KB, 4 KB and 8 KB dumps
(Memory.cpp:313-345); an 8 KB dump is two 4 KB banks, loaded as one bank
or kept dual-bank with annunciator 2 selecting the live set.
Peripheral ROMs are read when the card is plugged (SlotCardFactory.cpp).
The Disk II carries the 341-0027-A boot PROM and the 16-sector P6
sequencer built in (DiskIICard.cpp:135-150). CFFA, Liron, Workstation and
the MC68705 mouse card leave the slot empty without their dump; Grappler+,
ThunderClock+ and TransWarp run a synthetic ROM instead. The catalogue
behind the ROM Status panel (RomCatalog.h) lists every name in probe
order with the size the loader enforces and, where POM2 vouches for a
dump, its CRC32; the panel hashes each present file
(RomStatus_ImGui.cpp:169-181, 306).
Help > Download missing ROMs (RomFetch.cpp:61-141) fetches 18 dumps with
curl from raw.githubusercontent.com/Abdess/retrobios and installs a
download only when its size, CRC32 and SHA-256 match the catalogue
(RomFetch.cpp:398-431); a present local file is re-checked with the same
gate (RomFetch.cpp:583-603). Unavailable in the browser build.
The floppy mechanical sounds are MAME's samples/floppy set, read from
roms/floppy_samples/ as two banks of ten WAV files prefixed 525_ and 35_
(FloppySoundDevice.cpp:80-118, MainWindow.cpp:335-348); a missing sample
is logged and the drive stays silent.
Media named by the code are not firmware and are not listed here: the
browser demo boots floppyemu/DIX.po (wasm/shell.html:89) or, when the
shell passes no disk, floppyemu/Total Replay v6.1.hdv (main.cpp:281-285);
the headless CLI mounts disks_5.4/dos33_master.dsk by default
(pom2_headless.cpp:263). Disk, tape and hard-disk images are browsed
from disks_5.4/, disks_3.5/, hdv/, floppyemu/, cassettes/ and
prodos_folder/ next to the executable.
files:
- name: "apple2o.rom"
path: "roms/apple2o.rom"
description: "Apple ][ Original monitor and Integer BASIC, $D000-$FFFF"
required: false
priority: 1
size: 12288
sha256: "68d9db6bb4c305d40c3fa89fa0f2d7b7f71516a9431e3138859f23bc5bddb2d1"
sha1: "78008be557f643e956a106121bcc182c0fb9ea6d"
validation: [size, sha256]
source_ref: "src/SystemProfile.cpp:38, src/Memory.cpp:174-224, src/RomFetch.cpp:61-63"
note: "First candidate of the Apple ][ Original profile; apple2.rom is probed next."
- name: "apple2.rom"
path: "roms/apple2.rom"
description: "Apple ][ generic 12 KB fallback, Autostart monitor and Applesoft"
required: false
priority: 2
size: 12288
sha256: "fc3e9d41e9428534a883df5aa10eb55b73ea53d2fcbb3ee4f39bed1b07a82905"
sha1: "33a24f5489ba9195b44be77d9afb2252594cb5c7"
validation: [size, sha256]
source_ref: "src/SystemProfile.cpp:38, src/SystemProfile.cpp:54, src/MainWindow_Slots.cpp:1470-1477, src/RomFetch.cpp:65-67"
note: "Probed after the profile image for the ][ and ][+ profiles. When it resolves in place of that image the loader logs that the ROM identity may not match the machine."
- name: "apple2p.rom"
path: "roms/apple2p.rom"
description: "Apple ][+ Autostart monitor and Applesoft, 4 KB pad then $C000-$FFFF"
required: false
priority: 1
size_options: [12288, 20480]
sha1: "29a53f3bb158b160433369e8e4a1d7cd5bf68ac6"
validation: [size]
source_ref: "src/SystemProfile.cpp:54, src/Memory.cpp:209-219, src/RomFetch.cpp:69-79"
note: "First candidate of the ][+ profile and of the first-run fallback (MainWindow.cpp:234). The loader drops the leading 4 KB of a 20 KB dump. The fetcher builds a 12 KB image from the six 2 KB chips of the MAME apple2p set and accepts either size as present; it carries no digest for this file."
- name: "apple2e.rom"
path: "roms/apple2e.rom"
description: "Apple //e Enhanced firmware, 32 KB dump with the 16 KB firmware in the upper half"
required: true
priority: 1
size: 32768
sha256: "c17bc38c75ba96c33a30c688a1efd60144811073423533fe7f8453cdd9457aab"
sha1: "d756eba578a6c5a4807510dfee30ee585c63755e"
validation: [size, sha256]
source_ref: "src/SystemProfile.cpp:101, src/SystemProfile.cpp:239-251, src/Memory.cpp:189-201, src/Memory.cpp:220-222, src/MainWindow.cpp:223-226, src/RomFetch.cpp:80-83"
note: "Sole candidate of the //e Enhanced profiles, NTSC and PAL, PAL being the default machine. Also the last fallback of the //e Unenhanced chain."
- name: "apple2e_unenh.rom"
path: "roms/apple2e_unenh.rom"
description: "Apple //e Unenhanced firmware, 4 KB internal $Cx00 ROM then $D000-$FFFF"
required: false
priority: 1
aliases: ["342-0135-b.64.rom"]
size: 16384
sha256: "1fb812584c6633fa16b77b20915986ed1178d1e6fc07a647f7ee8d4e6ab9d40b"
sha1: "61fa9254628e5bb7236fb474006116d67684d747"
validation: [size, sha256]
source_ref: "src/SystemProfile.cpp:78-79, src/SystemProfile.cpp:265-277, src/RomFetch.cpp:84-87"
note: "First candidate of the //e Unenhanced profiles; 342-0135-b.64.rom is probed second, apple2e.rom third."
- name: "apple2c-32Kv0.rom"
path: "roms/apple2c-32Kv0.rom"
description: "Apple //c two-bank firmware, bank 0 in the lower 16 KB"
required: false
priority: 1
size: 32768
crc32: "323952d1"
sha1: "fb0d644aafaff1352d0816bc8494f6c9913809d5"
source_ref: "src/SystemProfile.cpp:142-143, src/SystemProfile.cpp:204-205, src/SystemProfile.cpp:432-438, src/Memory.cpp:189-201, src/Memory.cpp:220-222"
note: "First candidate of the //c and //c PAL profiles, third of the //c Plus chain. Bank 0 is mapped at reset, the $C028 ROMBANK switch selects the other. Identical to 3420033a.256 with its first 256 bytes zeroed."
- name: "apple2c-16K.rom"
path: "roms/apple2c-16K.rom"
description: "Apple //c ROM 255, 16 KB, MAME apple2c a2c.128"
required: false
priority: 2
size: 16384
crc32: "f0edaa1b"
sha1: "1a9b8aca5e32bb702ddb7791daddd60a89655729"
source_ref: "src/SystemProfile.cpp:142-143, src/Memory.cpp:207-208"
note: "Second candidate of the //c chain, loaded at $C000."
- name: "3420033a.256"
path: "roms/3420033a.256"
description: "Apple //c ROM 0, UniDisk 3.5 firmware, MAME apple2c0 342-0033-A"
required: false
priority: 3
size: 32768
crc32: "c8b979b3"
sha1: "10767e96cc17bad0970afda3a4146564e6272ba1"
source_ref: "src/SystemProfile.cpp:142-143"
note: "Third candidate of the //c chain."
- name: "apple2cp.rom"
path: "roms/apple2cp.rom"
description: "Apple //c Plus two-bank firmware, MAME apple2cp 341-0625-a.256"
required: false
priority: 1
aliases: ["apple2c-plus.rom"]
size: 32768
crc32: "0b996420"
sha1: "1a27ae26966bbafd825d08ad1a24742d3e33557c"
source_ref: "src/SystemProfile.cpp:204-205, src/SystemProfile.cpp:432-438"
note: "First candidate of the //c Plus profile; apple2c-plus.rom is probed second and apple2c-32Kv0.rom third."
- name: "apple2_char.rom"
path: "roms/apple2_char.rom"
description: "Apple ][ and ][+ character generator, 2 KB uppercase set"
required: false
priority: 1
size: 2048
sha256: "08f5d22230481019844492dde0a29a018cb193712a9e4a43770a3870608f28de"
sha1: "f9d312f128c9557d9d6ac03bfad6c3ddf83e5659"
validation: [size, sha256]
source_ref: "src/SystemProfile.cpp:39, src/SystemProfile.cpp:55, src/CharRomCatalog.cpp:42-43, src/RomFetch.cpp:90-93, src/Memory.cpp:313-345"
note: "Sole candidate of the ][ and ][+ profiles and the last fallback of every //e-class chain."
- name: "apple2e_char.rom"
path: "roms/apple2e_char.rom"
description: "Apple //e Enhanced character generator 342-0265-A, 4 KB with MouseText"
required: false
priority: 1
aliases: ["apple2e_char_us.rom"]
size: 4096
sha256: "52c3b87900ac939f6525402cab1ccfd8f8259290fc6df54da48fb4c98ae3ed0f"
sha1: "b2b5d87f52693817fc747df087a4aa1ddcdb1f10"
validation: [size, sha256]
source_ref: "src/SystemProfile.cpp:105, src/SystemProfile.cpp:144, src/SystemProfile.cpp:206, src/CharRomCatalog.cpp:48-49, src/RomFetch.cpp:94-97, src/Memory.cpp:313-345"
note: "First candidate of the //e Enhanced, //c and //c Plus profiles; the same dump answers to apple2e_char_us.rom in the locale picker."
- name: "apple2e_char_us_unenh.rom"
path: "roms/apple2e_char_us_unenh.rom"
description: "Apple //e Unenhanced character generator 342-0133-A, 4 KB"
required: false
priority: 1
aliases: ["apple2e_char_2k.rom", "341-0265-a.chr.rom"]
size: 4096
sha256: "ed5bdd4afa509134e85f1d020685af7ff50e279226eb869a17825b471cc1634c"
sha1: "58ad0008df72896a18601e090ee0d58155ffa5be"
validation: [size, sha256]
source_ref: "src/SystemProfile.cpp:83-84, src/CharRomCatalog.cpp:50-51, src/RomFetch.cpp:98-101, src/Memory.cpp:313-345"
note: "The //e Unenhanced profile probes apple2e_char_2k.rom then 341-0265-a.chr.rom then apple2_char.rom; the same dump ships under both names."
- name: "apple2e_char_fr.rom"
path: "roms/apple2e_char_fr.rom"
description: "Apple //e French character generator, 4 KB"
required: false
aliases: ["apple2e_char_frca_unenh.rom"]
size: 4096
crc32: "ab0be706"
sha1: "42afb02aab4146f781ac52803a2733adc4da834e"
validation: [size]
source_ref: "src/CharRomCatalog.cpp:52-53, src/CharRomCatalog.cpp:56-57, src/CharRomCatalog.cpp:151-165, src/Memory.cpp:313-345"
note: "Locale picker entry. The same dump is also listed as the FR Canadian unenhanced set 341-0168-A."
- name: "apple2e_char_frca.rom"
path: "roms/apple2e_char_frca.rom"
description: "Apple //e French Canadian Enhanced character generator, 4 KB"
required: false
size: 4096
crc32: "2c8fc403"
sha1: "4043e0808af8be096660827445e41149d16c5c85"
validation: [size]
source_ref: "src/CharRomCatalog.cpp:54-55, src/CharRomCatalog.cpp:151-165, src/Memory.cpp:313-345"
note: "Locale picker entry; equals the low bank of 342-0274-a.e9."
- name: "apple2e_char_uk.rom"
path: "roms/apple2e_char_uk.rom"
description: "Apple //e UK Enhanced character generator 342-0273-A, 4 KB"
required: false
size: 4096
crc32: "dda11653"
sha1: "d19c2e2cc12b27d77edc403d5d0701186a4ed988"
validation: [size]
source_ref: "src/CharRomCatalog.cpp:58-59, src/CharRomCatalog.cpp:151-165, src/Memory.cpp:313-345"
note: "Locale picker entry."
- name: "apple2e_char_uk_unenh.rom"
path: "roms/apple2e_char_uk_unenh.rom"
description: "Apple //e UK Unenhanced character generator 341-0160-A, 4 KB"
required: false
size: 4096
crc32: "7a9a91ef"
sha1: "6ca9767e0f47f642d1caab6ed41b8f58c58bb9eb"
validation: [size]
source_ref: "src/CharRomCatalog.cpp:60-61, src/CharRomCatalog.cpp:151-165, src/Memory.cpp:313-345"
note: "Locale picker entry."
- name: "apple2e_char_de.rom"
path: "roms/apple2e_char_de.rom"
description: "Apple //e German character generator 341-0161-A, 4 KB"
required: false
size: 4096
crc32: "0d72f153"
sha1: "a7fd75ae8611572b0b4d99ad54562014b879dbbf"
validation: [size]
source_ref: "src/CharRomCatalog.cpp:62-63, src/CharRomCatalog.cpp:151-165, src/Memory.cpp:313-345"
note: "Locale picker entry."
- name: "apple2e_char_de_improved.rom"
path: "roms/apple2e_char_de_improved.rom"
description: "Apple //e German Improved character generator, 4 KB"
required: false
size: 4096
crc32: "d345d332"
sha1: "12ce44f02bd28c350e2b0723d94ab8d9066f8798"
validation: [size]
source_ref: "src/CharRomCatalog.cpp:64-65, src/CharRomCatalog.cpp:151-165, src/Memory.cpp:313-345"
note: "Locale picker entry."
- name: "342-0274-a.e9"
path: "roms/342-0274-a.e9"
description: "Apple //e international video ROM 342-0274-A, 8 KB, French Canadian bank then US bank, MAME apple2eefr"
required: false
size: 8192
crc32: "8f342081"
sha1: "c81c1bbf237e70f8c3e5eef3c8fd5bd9b9f54d1e"
validation: [size]
source_ref: "src/CharRomCatalog.cpp:73-76, src/CharRomCatalog.cpp:144-149, src/Memory.cpp:313-345"
note: "Locale picker entries select bank 0 or bank 1; loaded whole, both banks stay live and annunciator 2 picks the set."
- name: "apple2e_char_ft_blockascii.rom"
path: "roms/apple2e_char_ft_blockascii.rom"
description: "French Touch Block ASCII dual-bank character generator, 8 KB"
required: false
size: 8192
crc32: "1eae3944"
sha1: "f79815457437e50404f4f537d8aabe34bff3a220"
validation: [size]
source_ref: "src/CharRomCatalog.cpp:77-78, src/Memory.cpp:313-345"
note: "Locale picker entry loaded dual-bank: annunciator 2 flips between the text set and the block glyphs."
- name: "Videx Lower Case Chip ROM.bin"
path: "roms/Videx Lower Case Chip ROM.bin"
description: "Videx LOWER CASE CHIP character generator for the ][ and ][+, 2 KB"
required: false
size: 2048
crc32: "00f68076"
sha1: "447874fe0850c8add3fd5b13fa98f6648fe6f999"
validation: [size, crc32]
source_ref: "src/CharRomCatalog.cpp:44-45, src/RomCatalog.h:143-148, src/RomStatus_ImGui.cpp:306"
note: "Locale picker entry for the ][ and ][+ profiles; without it the picker keeps the stock uppercase set."
- name: "disk2.rom"
path: "roms/disk2.rom"
description: "Disk II 16-sector boot PROM 341-0027-A"
required: false
has_builtin: true
size: 256
sha256: "de1e3e035878bab43d0af8fe38f5839c527e9548647036598ee6fe7ec74d2a7d"
sha1: "d4181c9f046aafc3fb326b381baac809d9e38d16"
validation: [size, sha256]
source_ref: "src/SlotCardFactory.cpp:93-106, src/DiskIICard.cpp:135-140, src/DiskIICard.cpp:150-172, src/RomFetch.cpp:104-107"
note: "The card carries the same PROM built in; the file replaces it when present."
- name: "diskii_p6.rom"
path: "roms/diskii_p6.rom"
description: "Disk II 16-sector P6 logic state sequencer PROM 341-0028-A"
required: false
has_builtin: true
size: 256
sha256: "e5e30615040567c1e7a2d21599681f8dac820edbdcda177b816a64d74b3a12f2"
sha1: "bc39fbd5b9a8d2287ac5d0a42e639fc4d3c2f9d4"
validation: [size, sha256]
source_ref: "src/SlotCardFactory.cpp:93-106, src/DiskIICard.cpp:141-148, src/DiskIICard.cpp:175-197, src/DiskIICard.cpp:245-262, src/RomFetch.cpp:108-111"
note: "Loading the file switches the bit-level LSS path on for every image; without it the legacy 32-cycle nibble gate serves non-WOZ images and the built-in PROM serves WOZ images."
- name: "disk2_13.rom"
path: "roms/disk2_13.rom"
description: "Disk II 13-sector boot PROM 341-0009"
required: false
size: 256
sha256: "2d2599521fc5763d4e8c308c2ee7c5c4d5c93785b8fb9a4f7d0381dfd5eb60b6"
sha1: "afd060e6f35faf3bb0146fa889fc787adf56330a"
validation: [size, sha256]
source_ref: "src/SlotCardFactory.cpp:93-106, src/DiskIICard.cpp:203-220, src/RomCatalog.h:79-81, src/RomFetch.cpp:112-115"
note: "13-sector disks mount but cannot boot without it."
- name: "diskii_p6_13.rom"
path: "roms/diskii_p6_13.rom"
description: "Disk II 13-sector P6 logic state sequencer PROM 341-0010"
required: false
size: 256
sha256: "383c55f5333cbfde39dd41528186631e5aca2eddfec30716344f03b6a4d44655"
sha1: "e3d6d1c30653572b49ecc2dc54ce073978411a04"
validation: [size, sha256]
source_ref: "src/SlotCardFactory.cpp:93-106, src/DiskIICard.cpp:222-239, src/RomCatalog.h:82-84, src/RomFetch.cpp:116-119"
note: "Paired with disk2_13.rom; the card never switches to the 13-sector pair without both."
- name: "cffa20eec02.bin"
path: "roms/cffa20eec02.bin"
description: "CFFA 2.0 firmware, 65C02 build"
required: false
size: 4096
crc32: "fb3726f8"
sha1: "080ff88f19de22328e162954ee2b51ee65f9d5cd"
validation: [size, crc32]
source_ref: "src/SlotCardFactory.cpp:115-139, src/CffaCard.cpp:26-40, src/RomCatalog.h:103-106"
note: "Preferred when the CPU is a 65C02, the 6502 build is the fallback; the slot stays empty when neither is found."
- name: "cffa20ee02.bin"
path: "roms/cffa20ee02.bin"
description: "CFFA 2.0 firmware, 6502 build"
required: false
size: 4096
crc32: "3ecafce5"
sha256: "3d7f6918f9af3828f5a6299299a817df0d354ee62e547bc0238755de66162a88"
sha1: "d600692ed9626668233a22a48236af639410cb7b"
validation: [size, crc32, sha256]
source_ref: "src/SlotCardFactory.cpp:115-139, src/CffaCard.cpp:26-40, src/RomCatalog.h:107-110, src/RomFetch.cpp:122-126"
note: "Preferred on an NMOS 6502, fallback for a 65C02."
- name: "mouse_341-0270-c.bin"
path: "roms/mouse_341-0270-c.bin"
description: "AppleMouse II card slot EPROM 341-0270-C"
required: false
size: 2048
sha256: "7f8e50c0e8a409991264201f9300f109b872b68e09c43f3e6c26af35fd8b89af"
sha1: "3a9d881a8a8d30f55b9719aceebbcf717f829d6f"
validation: [size, sha256]
source_ref: "src/SlotCardFactory.cpp:51-83, src/SlotCardFactory.cpp:232-247, src/MouseCard.cpp:115-149, src/MouseCardAppleWin.cpp:87-100, src/RomFetch.cpp:127-130"
note: "Needed by both mouse cards: the MC68705 card also needs the MCU ROM, the AppleWin HLE card needs this one only."
- name: "mouse_341-0269.bin"
path: "roms/mouse_341-0269.bin"
description: "AppleMouse II card MC68705P3 MCU mask ROM 341-0269"
required: false
size: 2048
sha256: "66480812edad5f6bd70349949cf8bd8fbafee2dc8bf396541d4e78bac2629ec0"
sha1: "3a2baa6648efe4456d3ec3721216e57c64f7acfc"
validation: [size, sha256]
source_ref: "src/SlotCardFactory.cpp:51-83, src/MouseCard.cpp:146-149, src/M68705P3.cpp:85-104, src/RomFetch.cpp:131-134"
note: "The MC68705 mouse card leaves its slot empty without it."
- name: "grappler_plus.bin"
path: "roms/grappler_plus.bin"
description: "Orange Micro Grappler+ parallel printer EPROM 3.2"
required: false
aliases: ["grappler+.bin", "grappler.bin"]
size: 4096
sha256: "9be4dea7722ad8928aee64c2ae708f365a6d66c50a63bff8a3c1a4e7596d44c6"
sha1: "829072cc19a58b24d36c2af972abaad6f9ba35d9"
validation: [size, sha256]
source_ref: "src/SlotCardFactory.cpp:147-166, src/GrapplerCard.cpp:29-52, src/RomCatalog.h:113-118, src/RomFetch.cpp:135-138"
note: "Without it the card runs a stub ROM: PR#n prints, the graphics dump commands are absent."
- name: "ae_transwarp_1.4.bin"
path: "roms/ae_transwarp_1.4.bin"
description: "Applied Engineering TransWarp accelerator ROM v1.4, MAME warprom"
required: false
aliases: ["ae transwarp rom v1.4.bin"]
size: 4096
crc32: "afe37f55"
sha1: "7b75534e7895e04859a0b1337801c6eeb0cef52a"
validation: [size, crc32]
source_ref: "src/TranswarpCard.h:166, src/TranswarpCard.cpp:200-218, src/RomCatalog.h:119-125"
note: "Not shipped by POM2. The card accelerates without it and only shadows $F000-$FFFF with the speed-corrected monitor when the dump is present."
- name: "thunderclock_u9_v1.3.bin"
path: "roms/thunderclock_u9_v1.3.bin"
description: "Thunderware ThunderClock+ slot ROM rev 1.3, U9"
required: false
aliases: ["thunderclock_u9.bin", "thunderclock.rom", "Thunderware_REV_1.3_ROM_U9.bin"]
size_options: [256, 2048]
sha1: "60f434f5325899d7ea257a6e56e6f53eae65146a"
validation: [size]
source_ref: "src/ClockCard.cpp:469-524, src/RomCatalog.h:150-160"
note: "A 2 KB dump supplies the $C800 expansion ROM as well. The first four even bytes must read $08, $28, $58, $70, the ProDOS clock signature, or the synthetic ROM stays in place."
- name: "liron.rom"
path: "roms/liron.rom"
description: "Apple Liron SmartPort controller firmware, 4 KB"
required: false
size: 4096
sha1: "fa94ecc2aa23f336f7da9e18bc8f4a6cfbb4ea60"
validation: [size]
source_ref: "src/SlotCardFactory.cpp:194-220, src/LironCard.cpp:61-85, src/SmartPortCard.cpp:80-97, src/RomCatalog.h:87-90"
note: "The Liron card refuses to plug without it. The SmartPort 3.5 card loads it on machines with physical slots and otherwise presents a synthetic identity."
- name: "341-0358-A.bin"
path: "roms/341-0358-A.bin"
description: "Apple II Workstation Card firmware 341-0358-A, 64 KB"
required: false
aliases: ["341-0358-a.bin"]
size: 65536
crc32: "63819dcb"
sha1: "59c8e8c88bac5c31ada1306b412edfcf5912a720"
validation: [size, crc32]
source_ref: "src/SlotCardFactory.cpp:169-192, src/WorkstationCard.cpp:60-74, src/RomCatalog.h:133-142"
note: "The Workstation card leaves its slot empty without it; the card runs its own 65C02 on the upper 32 KB."
- name: "341-0438-a.bin"
path: "roms/341-0438-a.bin"
description: "Apple II 3.5 Disk Controller SuperDrive firmware 341-0438-A, MAME a2superdrive"
required: false
size: 32768
crc32: "c73ff25b"
sha1: "440c3f84176c7b9f542da0b6ddf4fb13ec326c46"
validation: [size, crc32, sha256]
source_ref: "src/RomCatalog.h:91-96, src/RomStatus_ImGui.cpp:169-181, src/RomFetch.cpp:139-141"
note: "No card reads it; the ROM Status panel and the fetch gate check it."
- name: "342-0326-a.f12"
path: "roms/342-0326-a.f12"
description: "Apple //e French keyboard decode ROM 342-0326-A, MAME apple2eefr"
required: false
size: 2048
crc32: "f04970a9"
sha1: "806a602195c18ffec637c03b6bb3405188b0dc1e"
validation: [size, crc32]
source_ref: "src/RomCatalog.h:97-102, src/RomStatus_ImGui.cpp:169-181, src/RomStatus_ImGui.cpp:306"
note: "Host keys are mapped directly, no keyboard decode ROM is emulated; the ROM Status panel checks the file only."
- name: "525_seek_2ms.wav"
path: "roms/floppy_samples/525_seek_2ms.wav"
description: "MAME floppy sample, 5.25 inch drive, 2 ms head seek"
category: game_data
required: false
size: 5336
sha1: "2d046a880476218685ed738fe8c8381962afd74a"
source_ref: "src/FloppySoundDevice.cpp:80-118, src/MainWindow.cpp:335-348"
note: "One of ten samples per drive bank; a missing sample is logged and that sound stays silent."
- name: "525_seek_6ms.wav"
path: "roms/floppy_samples/525_seek_6ms.wav"
description: "MAME floppy sample, 5.25 inch drive, 6 ms head seek"
category: game_data
required: false
size: 14860
sha1: "6f698055fa6e9da6c5ae3fd6fb05de76b92a45a9"
source_ref: "src/FloppySoundDevice.cpp:80-118, src/MainWindow.cpp:335-348"
- name: "525_seek_12ms.wav"
path: "roms/floppy_samples/525_seek_12ms.wav"
description: "MAME floppy sample, 5.25 inch drive, 12 ms head seek"
category: game_data
required: false
size: 22764
sha1: "fbbbb5e8724c076d194e66a4443d299d54a8efd6"
source_ref: "src/FloppySoundDevice.cpp:80-118, src/MainWindow.cpp:335-348"
- name: "525_seek_20ms.wav"
path: "roms/floppy_samples/525_seek_20ms.wav"
description: "MAME floppy sample, 5.25 inch drive, 20 ms head seek"
category: game_data
required: false
size: 30060
sha1: "b6cd14944454c743861196edb4fcab1cc9b586d4"
source_ref: "src/FloppySoundDevice.cpp:80-118, src/MainWindow.cpp:335-348"
- name: "525_spin_empty.wav"
path: "roms/floppy_samples/525_spin_empty.wav"
description: "MAME floppy sample, 5.25 inch drive, motor running, no disk"
category: game_data
required: false
size: 8864
sha1: "4b13701d9a7f8ab0f0827f17ba80b5c32b4e0fa7"
source_ref: "src/FloppySoundDevice.cpp:80-118, src/MainWindow.cpp:335-348"
- name: "525_spin_loaded.wav"
path: "roms/floppy_samples/525_spin_loaded.wav"
description: "MAME floppy sample, 5.25 inch drive, motor running, disk loaded"
category: game_data
required: false
size: 17708
sha1: "875f90538a3ff5db863ad4c384e1808841ddea9b"
source_ref: "src/FloppySoundDevice.cpp:80-118, src/MainWindow.cpp:335-348"
- name: "525_spin_start_empty.wav"
path: "roms/floppy_samples/525_spin_start_empty.wav"
description: "MAME floppy sample, 5.25 inch drive, motor start, no disk"
category: game_data
required: false
size: 11180
sha1: "b87d89c4b46c36dd78dec3dc5170ca61501e7cd9"
source_ref: "src/FloppySoundDevice.cpp:80-118, src/MainWindow.cpp:335-348"
- name: "525_spin_start_loaded.wav"
path: "roms/floppy_samples/525_spin_start_loaded.wav"
description: "MAME floppy sample, 5.25 inch drive, motor start, disk loaded"
category: game_data
required: false
size: 17708
sha1: "510476098848e2b5cdfe9f1608f8dfa3207fe9b4"
source_ref: "src/FloppySoundDevice.cpp:80-118, src/MainWindow.cpp:335-348"
- name: "525_spin_end.wav"
path: "roms/floppy_samples/525_spin_end.wav"
description: "MAME floppy sample, 5.25 inch drive, motor stop"
category: game_data
required: false
size: 8864
sha1: "f8d9b94c4d92d35d9ffb1117b693fc74a93f613f"
source_ref: "src/FloppySoundDevice.cpp:80-118, src/MainWindow.cpp:335-348"
- name: "525_step_1_1.wav"
path: "roms/floppy_samples/525_step_1_1.wav"
description: "MAME floppy sample, 5.25 inch drive, single track step"
category: game_data
required: false
size: 6628
sha1: "669ee98fb9fac4371c72ed0b60be1bc8470bc7f8"
source_ref: "src/FloppySoundDevice.cpp:80-118, src/MainWindow.cpp:335-348"
- name: "35_seek_2ms.wav"
path: "roms/floppy_samples/35_seek_2ms.wav"
description: "MAME floppy sample, 3.5 inch drive, 2 ms head seek"
category: game_data
required: false
size: 7450
sha1: "55caafbd19486b8d517e4b33a6fa65250df55e25"
source_ref: "src/FloppySoundDevice.cpp:80-118, src/MainWindow.cpp:335-348"
note: "One of ten samples per drive bank; a missing sample is logged and that sound stays silent."
- name: "35_seek_6ms.wav"
path: "roms/floppy_samples/35_seek_6ms.wav"
description: "MAME floppy sample, 3.5 inch drive, 6 ms head seek"
category: game_data
required: false
size: 22230
sha1: "87e5dec269e67497681c15849777ebfc301131c1"
source_ref: "src/FloppySoundDevice.cpp:80-118, src/MainWindow.cpp:335-348"
- name: "35_seek_12ms.wav"
path: "roms/floppy_samples/35_seek_12ms.wav"
description: "MAME floppy sample, 3.5 inch drive, 12 ms head seek"
category: game_data
required: false
size: 26540
sha1: "c6b34fc61496943134ac45cc836a24e743caf794"
source_ref: "src/FloppySoundDevice.cpp:80-118, src/MainWindow.cpp:335-348"
- name: "35_seek_20ms.wav"
path: "roms/floppy_samples/35_seek_20ms.wav"
description: "MAME floppy sample, 3.5 inch drive, 20 ms head seek"
category: game_data
required: false
size: 44144
sha1: "b2fe4c3a4185146a7d11483d92d4412dd79dbc78"
source_ref: "src/FloppySoundDevice.cpp:80-118, src/MainWindow.cpp:335-348"
- name: "35_spin_empty.wav"
path: "roms/floppy_samples/35_spin_empty.wav"
description: "MAME floppy sample, 3.5 inch drive, motor running, no disk"
category: game_data
required: false
size: 17708
sha1: "db04fc097bdd0411cff232f57525ded491b48c6c"
source_ref: "src/FloppySoundDevice.cpp:80-118, src/MainWindow.cpp:335-348"
- name: "35_spin_loaded.wav"
path: "roms/floppy_samples/35_spin_loaded.wav"
description: "MAME floppy sample, 3.5 inch drive, motor running, disk loaded"
category: game_data
required: false
size: 17708
sha1: "96ce04a5b02af0da6d311f06fc4906a3cf71c78f"
source_ref: "src/FloppySoundDevice.cpp:80-118, src/MainWindow.cpp:335-348"
- name: "35_spin_start_empty.wav"
path: "roms/floppy_samples/35_spin_start_empty.wav"
description: "MAME floppy sample, 3.5 inch drive, motor start, no disk"
category: game_data
required: false
size: 17708
sha1: "af770fd9261a8efee23d66cd39b27be7b2ab7853"
source_ref: "src/FloppySoundDevice.cpp:80-118, src/MainWindow.cpp:335-348"
- name: "35_spin_start_loaded.wav"
path: "roms/floppy_samples/35_spin_start_loaded.wav"
description: "MAME floppy sample, 3.5 inch drive, motor start, disk loaded"
category: game_data
required: false
size: 35308
sha1: "c82b1714378bf2507ed86dea1e9fe743c380abab"
source_ref: "src/FloppySoundDevice.cpp:80-118, src/MainWindow.cpp:335-348"
- name: "35_spin_end.wav"
path: "roms/floppy_samples/35_spin_end.wav"
description: "MAME floppy sample, 3.5 inch drive, motor stop"
category: game_data
required: false
size: 17684
sha1: "a8901b692de15eb7a9052f61283f0e7a2b63d67d"
source_ref: "src/FloppySoundDevice.cpp:80-118, src/MainWindow.cpp:335-348"
- name: "35_step_1_1.wav"
path: "roms/floppy_samples/35_step_1_1.wav"
description: "MAME floppy sample, 3.5 inch drive, single track step"
category: game_data
required: false
size: 6878
sha1: "40d756d0cb5f7998ca26ac1de142a96a83fa2b97"
source_ref: "src/FloppySoundDevice.cpp:80-118, src/MainWindow.cpp:335-348"
- name: "DejaVuSans.ttf"
path: "fonts/DejaVuSans.ttf"
description: "DejaVu Sans, the frontend text font"
category: game_data
required: false
bundled: true
unsourceable: "host program component shipped inside every POM2 package, not emulation data"
size: 759720
sha1: "3061cf7af25793a655a1ff5a509385f3620f3eb3"
source_ref: "src/main.cpp:522-535"
note: "Falls back to the system DejaVu, Arial Unicode or Segoe UI, then to the ImGui bitmap font."
- name: "fa-solid-900.ttf"
path: "fonts/fa-solid-900.ttf"
description: "Font Awesome 6 Free Solid, the frontend icon font"
category: game_data
required: false
bundled: true
unsourceable: "host program component shipped inside every POM2 package, not emulation data"
size: 426112
sha1: "0c8c9706abc0116f08b66d11a69da6aa9ef7e6bf"
source_ref: "src/main.cpp:582-600"
note: "Without it every icon renders as an empty box."
- name: "Apple_II_plus.jpg"
path: "pic/Apple_II_plus.jpg"
description: "Apple ][+ photograph shown in Help > About"
category: game_data
required: false
bundled: true
unsourceable: "host program component shipped inside every POM2 package, not emulation data"
size: 102046
sha1: "69358dd499148deae4112b49cedb7bec220584e2"
source_ref: "src/MainWindow_MiscPanels.cpp:621"
- name: "Keyboard_AppleIIe.jpeg"
path: "pic/Keyboard_AppleIIe.jpeg"
description: "Apple //e keyboard photograph the clickable keyboard window is built on"
category: game_data
required: false
bundled: true
unsourceable: "host program component shipped inside every POM2 package, not emulation data"
size: 794259
sha1: "a178f37661078739637ff7642cd6450c762993aa"
source_ref: "src/MainWindow_MiscPanels.cpp:480"
note: "The window hotspots are fractions of this image; without it the window has nothing to click."
+18 -16
View File
@@ -5,7 +5,7 @@
"platform": "batocera",
"display_name": "Batocera",
"version": "1.0",
"generated": "2026-09-05T09:26:20Z",
"generated": "2026-09-13T22:10:18Z",
"base_destination": "bios",
"detect": [
{
@@ -238,7 +238,7 @@
}
],
"total_files": 1832,
"total_size": 4314998020,
"total_size": 4522217423,
"total_omitted": 9,
"omitted_files": [
{
@@ -2271,10 +2271,10 @@
},
{
"dest": "firmware.bin",
"sha1": "5b2acbd499b39fb1af1b36ef7de5eb047d83401c",
"sha256": "7ea4f06ca110f8b7ff7c946f6e4e228d94977dadd4bb51570d14c68488edb32a",
"sha1": "cfe072921ee3fb93f688743f8beef89043c3e9ad",
"sha256": "57a1d6b43c1399d219ea18644240c4d4c6787c829f0a67ded216472867857cd0",
"size": 262144,
"repo_path": "bios/Arcade/Arcade/firmware.bin",
"repo_path": "bios/Nintendo/Nintendo DS/firmware.bin",
"cores": null
},
{
@@ -2311,10 +2311,10 @@
},
{
"dest": "dsi_firmware.bin",
"sha1": "93c0598b08192a1f630e5edb2cd9f60d1e3ea7b3",
"sha256": "1f89935da2888cd3e401af2774e06a6b587ca059e85f922826494f317d31c6ae",
"sha1": "d2a5af338f09c5cbdd5d7628db5b9c075c69b616",
"sha256": "1d7c771de535e6e07182fc9820ac32e76c6f0b5bcefd256a861fdfab144761ec",
"size": 131072,
"repo_path": "bios/Arcade/Arcade/dsi_firmware.bin",
"repo_path": "bios/Nintendo/Nintendo DS/dsi_firmware.bin",
"cores": null
},
{
@@ -8041,19 +8041,21 @@
},
{
"dest": "fbneo/samples/donpachi.zip",
"sha1": "c0c0b5db93a61276a6fe6842049cb53e564b8413",
"sha256": "a686ebf893d511b5b7667176cd6844593e914595a8bb9ab656b2c66969013b5c",
"size": 5641310,
"repo_path": "bios/Other/fbneo/donpachi.zip",
"sha1": "d380fb29287eb7fc9ff901a7653ad40785f7deb1",
"sha256": "78a237f1e2774eb396e2f14999f1270597e0767a392729e7a4539455888b6fe0",
"size": 208549253,
"repo_path": "bios/Other/fbneo/fbneo/samples/donpachi.zip",
"cores": [
"fbneo"
]
],
"storage": "release",
"release_asset": "donpachi.zip"
},
{
"dest": "fbneo/samples/sfz3mix.zip",
"sha1": "227815ce9e55db427d68e075182caffe6ad60ad1",
"sha256": "6a720035646b3488a047ab163a6975b7be82fe75c5eec88155c8503c93a631fe",
"size": 96705917,
"sha1": "e39ee9abb19076ef095f67469ca95ff5e7f600dc",
"sha256": "2c2e67ab762102f50df641280721164ddff0316e71081d5fa62f2a67365dea66",
"size": 101017377,
"repo_path": "bios/Other/fbneo/fbneo/samples/sfz3mix.zip",
"cores": [
"fbneo"
+18 -16
View File
@@ -5,7 +5,7 @@
"platform": "bizhawk",
"display_name": "BizHawk",
"version": "1.0",
"generated": "2026-09-05T09:26:20Z",
"generated": "2026-09-13T22:10:18Z",
"base_destination": "Firmware",
"detect": [
{
@@ -21,7 +21,7 @@
],
"standalone_copies": [],
"total_files": 539,
"total_size": 2328691103,
"total_size": 2535910506,
"total_omitted": 1,
"omitted_files": [
{
@@ -1464,19 +1464,21 @@
},
{
"dest": "fbneo/samples/donpachi.zip",
"sha1": "c0c0b5db93a61276a6fe6842049cb53e564b8413",
"sha256": "a686ebf893d511b5b7667176cd6844593e914595a8bb9ab656b2c66969013b5c",
"size": 5641310,
"repo_path": "bios/Other/fbneo/donpachi.zip",
"sha1": "d380fb29287eb7fc9ff901a7653ad40785f7deb1",
"sha256": "78a237f1e2774eb396e2f14999f1270597e0767a392729e7a4539455888b6fe0",
"size": 208549253,
"repo_path": "bios/Other/fbneo/fbneo/samples/donpachi.zip",
"cores": [
"fbneo"
]
],
"storage": "release",
"release_asset": "donpachi.zip"
},
{
"dest": "fbneo/samples/sfz3mix.zip",
"sha1": "227815ce9e55db427d68e075182caffe6ad60ad1",
"sha256": "6a720035646b3488a047ab163a6975b7be82fe75c5eec88155c8503c93a631fe",
"size": 96705917,
"sha1": "e39ee9abb19076ef095f67469ca95ff5e7f600dc",
"sha256": "2c2e67ab762102f50df641280721164ddff0316e71081d5fa62f2a67365dea66",
"size": 101017377,
"repo_path": "bios/Other/fbneo/fbneo/samples/sfz3mix.zip",
"cores": [
"fbneo"
@@ -3348,10 +3350,10 @@
},
{
"dest": "firmware.bin",
"sha1": "5b2acbd499b39fb1af1b36ef7de5eb047d83401c",
"sha256": "7ea4f06ca110f8b7ff7c946f6e4e228d94977dadd4bb51570d14c68488edb32a",
"sha1": "cfe072921ee3fb93f688743f8beef89043c3e9ad",
"sha256": "57a1d6b43c1399d219ea18644240c4d4c6787c829f0a67ded216472867857cd0",
"size": 262144,
"repo_path": "bios/Arcade/Arcade/firmware.bin",
"repo_path": "bios/Nintendo/Nintendo DS/firmware.bin",
"cores": [
"melonds"
]
@@ -3378,10 +3380,10 @@
},
{
"dest": "dsi_firmware.bin",
"sha1": "93c0598b08192a1f630e5edb2cd9f60d1e3ea7b3",
"sha256": "1f89935da2888cd3e401af2774e06a6b587ca059e85f922826494f317d31c6ae",
"sha1": "d2a5af338f09c5cbdd5d7628db5b9c075c69b616",
"sha256": "1d7c771de535e6e07182fc9820ac32e76c6f0b5bcefd256a861fdfab144761ec",
"size": 131072,
"repo_path": "bios/Arcade/Arcade/dsi_firmware.bin",
"repo_path": "bios/Nintendo/Nintendo DS/dsi_firmware.bin",
"cores": [
"melonds"
]
+7 -7
View File
@@ -5,7 +5,7 @@
"platform": "emudeck",
"display_name": "EmuDeck",
"version": "1.0",
"generated": "2026-09-03T20:45:52Z",
"generated": "2026-09-13T17:22:08Z",
"base_destination": "bios",
"detect": [
{
@@ -313,10 +313,10 @@
},
{
"dest": "firmware.bin",
"sha1": "5b2acbd499b39fb1af1b36ef7de5eb047d83401c",
"sha256": "7ea4f06ca110f8b7ff7c946f6e4e228d94977dadd4bb51570d14c68488edb32a",
"sha1": "cfe072921ee3fb93f688743f8beef89043c3e9ad",
"sha256": "57a1d6b43c1399d219ea18644240c4d4c6787c829f0a67ded216472867857cd0",
"size": 262144,
"repo_path": "bios/Arcade/Arcade/firmware.bin",
"repo_path": "bios/Nintendo/Nintendo DS/firmware.bin",
"cores": null
},
{
@@ -3991,10 +3991,10 @@
},
{
"dest": "dsi_firmware.bin",
"sha1": "93c0598b08192a1f630e5edb2cd9f60d1e3ea7b3",
"sha256": "1f89935da2888cd3e401af2774e06a6b587ca059e85f922826494f317d31c6ae",
"sha1": "d2a5af338f09c5cbdd5d7628db5b9c075c69b616",
"sha256": "1d7c771de535e6e07182fc9820ac32e76c6f0b5bcefd256a861fdfab144761ec",
"size": 131072,
"repo_path": "bios/Arcade/Arcade/dsi_firmware.bin",
"repo_path": "bios/Nintendo/Nintendo DS/dsi_firmware.bin",
"cores": [
"melonds"
]
+23 -23
View File
@@ -5,7 +5,7 @@
"platform": "lakka",
"display_name": "Lakka",
"version": "1.0",
"generated": "2026-09-05T09:26:20Z",
"generated": "2026-09-13T22:10:18Z",
"base_destination": "system",
"detect": [
{
@@ -17,7 +17,7 @@
],
"standalone_copies": [],
"total_files": 1871,
"total_size": 5865446694,
"total_size": 6072666103,
"total_omitted": 1,
"omitted_files": [
{
@@ -1626,10 +1626,10 @@
},
{
"dest": "dsi_firmware.bin",
"sha1": "93c0598b08192a1f630e5edb2cd9f60d1e3ea7b3",
"sha256": "1f89935da2888cd3e401af2774e06a6b587ca059e85f922826494f317d31c6ae",
"sha1": "d2a5af338f09c5cbdd5d7628db5b9c075c69b616",
"sha256": "1d7c771de535e6e07182fc9820ac32e76c6f0b5bcefd256a861fdfab144761ec",
"size": 131072,
"repo_path": "bios/Arcade/Arcade/dsi_firmware.bin",
"repo_path": "bios/Nintendo/Nintendo DS/dsi_firmware.bin",
"cores": null
},
{
@@ -6912,19 +6912,21 @@
},
{
"dest": "fbneo/samples/donpachi.zip",
"sha1": "c0c0b5db93a61276a6fe6842049cb53e564b8413",
"sha256": "a686ebf893d511b5b7667176cd6844593e914595a8bb9ab656b2c66969013b5c",
"size": 5641310,
"repo_path": "bios/Other/fbneo/donpachi.zip",
"sha1": "d380fb29287eb7fc9ff901a7653ad40785f7deb1",
"sha256": "78a237f1e2774eb396e2f14999f1270597e0767a392729e7a4539455888b6fe0",
"size": 208549253,
"repo_path": "bios/Other/fbneo/fbneo/samples/donpachi.zip",
"cores": [
"fbneo"
]
],
"storage": "release",
"release_asset": "donpachi.zip"
},
{
"dest": "fbneo/samples/sfz3mix.zip",
"sha1": "227815ce9e55db427d68e075182caffe6ad60ad1",
"sha256": "6a720035646b3488a047ab163a6975b7be82fe75c5eec88155c8503c93a631fe",
"size": 96705917,
"sha1": "e39ee9abb19076ef095f67469ca95ff5e7f600dc",
"sha256": "2c2e67ab762102f50df641280721164ddff0316e71081d5fa62f2a67365dea66",
"size": 101017377,
"repo_path": "bios/Other/fbneo/fbneo/samples/sfz3mix.zip",
"cores": [
"fbneo"
@@ -9368,10 +9370,10 @@
},
{
"dest": "d2fdc.zip",
"sha1": "bc39fbd5b9a8d2287ac5d0a42e639fc4d3c2f9d4",
"sha256": "e5e30615040567c1e7a2d21599681f8dac820edbdcda177b816a64d74b3a12f2",
"size": 256,
"repo_path": "bios/Apple/Apple II/DiskII/state-machine-16.rom",
"sha1": "af56c948598291b284a528f3fce06b961dba55e3",
"sha256": "69ee0f8f0862e1a623bcbe9870f9531f7976312f292a20d1aff7ed61b6085a69",
"size": 262,
"repo_path": "bios/Arcade/Arcade/a3fdc.zip",
"cores": [
"mamemess"
]
@@ -13380,9 +13382,7 @@
"repo_path": "bios/Other/sdlpal/sdlpal/5.avi",
"cores": [
"sdlpal"
],
"storage": "release",
"release_asset": "5.avi"
]
},
{
"dest": "sdlpal/6.avi",
@@ -15966,10 +15966,10 @@
},
{
"dest": "SkyEmu/firmware.bin",
"sha1": "5b2acbd499b39fb1af1b36ef7de5eb047d83401c",
"sha256": "7ea4f06ca110f8b7ff7c946f6e4e228d94977dadd4bb51570d14c68488edb32a",
"sha1": "cfe072921ee3fb93f688743f8beef89043c3e9ad",
"sha256": "57a1d6b43c1399d219ea18644240c4d4c6787c829f0a67ded216472867857cd0",
"size": 262144,
"repo_path": "bios/Arcade/Arcade/firmware.bin",
"repo_path": "bios/Nintendo/Nintendo DS/firmware.bin",
"cores": [
"skyemu"
]
+19 -17
View File
@@ -5,7 +5,7 @@
"platform": "recalbox",
"display_name": "Recalbox",
"version": "1.0",
"generated": "2026-09-05T09:26:20Z",
"generated": "2026-09-13T22:10:18Z",
"base_destination": "bios",
"detect": [
{
@@ -238,7 +238,7 @@
}
],
"total_files": 1328,
"total_size": 3900250204,
"total_size": 4107469613,
"total_omitted": 4,
"omitted_files": [
{
@@ -5927,19 +5927,21 @@
},
{
"dest": "fbneo/samples/donpachi.zip",
"sha1": "c0c0b5db93a61276a6fe6842049cb53e564b8413",
"sha256": "a686ebf893d511b5b7667176cd6844593e914595a8bb9ab656b2c66969013b5c",
"size": 5641310,
"repo_path": "bios/Other/fbneo/donpachi.zip",
"sha1": "d380fb29287eb7fc9ff901a7653ad40785f7deb1",
"sha256": "78a237f1e2774eb396e2f14999f1270597e0767a392729e7a4539455888b6fe0",
"size": 208549253,
"repo_path": "bios/Other/fbneo/fbneo/samples/donpachi.zip",
"cores": [
"fbneo"
]
],
"storage": "release",
"release_asset": "donpachi.zip"
},
{
"dest": "fbneo/samples/sfz3mix.zip",
"sha1": "227815ce9e55db427d68e075182caffe6ad60ad1",
"sha256": "6a720035646b3488a047ab163a6975b7be82fe75c5eec88155c8503c93a631fe",
"size": 96705917,
"sha1": "e39ee9abb19076ef095f67469ca95ff5e7f600dc",
"sha256": "2c2e67ab762102f50df641280721164ddff0316e71081d5fa62f2a67365dea66",
"size": 101017377,
"repo_path": "bios/Other/fbneo/fbneo/samples/sfz3mix.zip",
"cores": [
"fbneo"
@@ -8191,10 +8193,10 @@
},
{
"dest": "d2fdc.zip",
"sha1": "bc39fbd5b9a8d2287ac5d0a42e639fc4d3c2f9d4",
"sha256": "e5e30615040567c1e7a2d21599681f8dac820edbdcda177b816a64d74b3a12f2",
"size": 256,
"repo_path": "bios/Apple/Apple II/DiskII/state-machine-16.rom",
"sha1": "af56c948598291b284a528f3fce06b961dba55e3",
"sha256": "69ee0f8f0862e1a623bcbe9870f9531f7976312f292a20d1aff7ed61b6085a69",
"size": 262,
"repo_path": "bios/Arcade/Arcade/a3fdc.zip",
"cores": [
"mamemess"
]
@@ -8681,10 +8683,10 @@
},
{
"dest": "dsi_firmware.bin",
"sha1": "93c0598b08192a1f630e5edb2cd9f60d1e3ea7b3",
"sha256": "1f89935da2888cd3e401af2774e06a6b587ca059e85f922826494f317d31c6ae",
"sha1": "d2a5af338f09c5cbdd5d7628db5b9c075c69b616",
"sha256": "1d7c771de535e6e07182fc9820ac32e76c6f0b5bcefd256a861fdfab144761ec",
"size": 131072,
"repo_path": "bios/Arcade/Arcade/dsi_firmware.bin",
"repo_path": "bios/Nintendo/Nintendo DS/dsi_firmware.bin",
"cores": [
"melonds"
]
+23 -23
View File
@@ -5,7 +5,7 @@
"platform": "retroarch",
"display_name": "RetroArch",
"version": "1.0",
"generated": "2026-09-05T09:26:20Z",
"generated": "2026-09-13T22:10:18Z",
"base_destination": "system",
"detect": [
{
@@ -256,7 +256,7 @@
}
],
"total_files": 1871,
"total_size": 5865446694,
"total_size": 6072666103,
"total_omitted": 1,
"omitted_files": [
{
@@ -1865,10 +1865,10 @@
},
{
"dest": "dsi_firmware.bin",
"sha1": "93c0598b08192a1f630e5edb2cd9f60d1e3ea7b3",
"sha256": "1f89935da2888cd3e401af2774e06a6b587ca059e85f922826494f317d31c6ae",
"sha1": "d2a5af338f09c5cbdd5d7628db5b9c075c69b616",
"sha256": "1d7c771de535e6e07182fc9820ac32e76c6f0b5bcefd256a861fdfab144761ec",
"size": 131072,
"repo_path": "bios/Arcade/Arcade/dsi_firmware.bin",
"repo_path": "bios/Nintendo/Nintendo DS/dsi_firmware.bin",
"cores": null
},
{
@@ -7151,19 +7151,21 @@
},
{
"dest": "fbneo/samples/donpachi.zip",
"sha1": "c0c0b5db93a61276a6fe6842049cb53e564b8413",
"sha256": "a686ebf893d511b5b7667176cd6844593e914595a8bb9ab656b2c66969013b5c",
"size": 5641310,
"repo_path": "bios/Other/fbneo/donpachi.zip",
"sha1": "d380fb29287eb7fc9ff901a7653ad40785f7deb1",
"sha256": "78a237f1e2774eb396e2f14999f1270597e0767a392729e7a4539455888b6fe0",
"size": 208549253,
"repo_path": "bios/Other/fbneo/fbneo/samples/donpachi.zip",
"cores": [
"fbneo"
]
],
"storage": "release",
"release_asset": "donpachi.zip"
},
{
"dest": "fbneo/samples/sfz3mix.zip",
"sha1": "227815ce9e55db427d68e075182caffe6ad60ad1",
"sha256": "6a720035646b3488a047ab163a6975b7be82fe75c5eec88155c8503c93a631fe",
"size": 96705917,
"sha1": "e39ee9abb19076ef095f67469ca95ff5e7f600dc",
"sha256": "2c2e67ab762102f50df641280721164ddff0316e71081d5fa62f2a67365dea66",
"size": 101017377,
"repo_path": "bios/Other/fbneo/fbneo/samples/sfz3mix.zip",
"cores": [
"fbneo"
@@ -9607,10 +9609,10 @@
},
{
"dest": "d2fdc.zip",
"sha1": "bc39fbd5b9a8d2287ac5d0a42e639fc4d3c2f9d4",
"sha256": "e5e30615040567c1e7a2d21599681f8dac820edbdcda177b816a64d74b3a12f2",
"size": 256,
"repo_path": "bios/Apple/Apple II/DiskII/state-machine-16.rom",
"sha1": "af56c948598291b284a528f3fce06b961dba55e3",
"sha256": "69ee0f8f0862e1a623bcbe9870f9531f7976312f292a20d1aff7ed61b6085a69",
"size": 262,
"repo_path": "bios/Arcade/Arcade/a3fdc.zip",
"cores": [
"mamemess"
]
@@ -13619,9 +13621,7 @@
"repo_path": "bios/Other/sdlpal/sdlpal/5.avi",
"cores": [
"sdlpal"
],
"storage": "release",
"release_asset": "5.avi"
]
},
{
"dest": "sdlpal/6.avi",
@@ -16205,10 +16205,10 @@
},
{
"dest": "SkyEmu/firmware.bin",
"sha1": "5b2acbd499b39fb1af1b36ef7de5eb047d83401c",
"sha256": "7ea4f06ca110f8b7ff7c946f6e4e228d94977dadd4bb51570d14c68488edb32a",
"sha1": "cfe072921ee3fb93f688743f8beef89043c3e9ad",
"sha256": "57a1d6b43c1399d219ea18644240c4d4c6787c829f0a67ded216472867857cd0",
"size": 262144,
"repo_path": "bios/Arcade/Arcade/firmware.bin",
"repo_path": "bios/Nintendo/Nintendo DS/firmware.bin",
"cores": [
"skyemu"
]
+22 -20
View File
@@ -5,7 +5,7 @@
"platform": "retrobat",
"display_name": "RetroBat",
"version": "1.0",
"generated": "2026-09-05T09:26:20Z",
"generated": "2026-09-13T22:10:18Z",
"base_destination": "bios",
"detect": [
{
@@ -237,7 +237,7 @@
}
],
"total_files": 1464,
"total_size": 4733583386,
"total_size": 4940802795,
"total_omitted": 3,
"omitted_files": [
{
@@ -514,10 +514,10 @@
},
{
"dest": "d2fdc.zip",
"sha1": "bc39fbd5b9a8d2287ac5d0a42e639fc4d3c2f9d4",
"sha256": "e5e30615040567c1e7a2d21599681f8dac820edbdcda177b816a64d74b3a12f2",
"size": 256,
"repo_path": "bios/Apple/Apple II/DiskII/state-machine-16.rom",
"sha1": "af56c948598291b284a528f3fce06b961dba55e3",
"sha256": "69ee0f8f0862e1a623bcbe9870f9531f7976312f292a20d1aff7ed61b6085a69",
"size": 262,
"repo_path": "bios/Arcade/Arcade/a3fdc.zip",
"cores": null
},
{
@@ -2282,10 +2282,10 @@
},
{
"dest": "firmware.bin",
"sha1": "5b2acbd499b39fb1af1b36ef7de5eb047d83401c",
"sha256": "7ea4f06ca110f8b7ff7c946f6e4e228d94977dadd4bb51570d14c68488edb32a",
"sha1": "cfe072921ee3fb93f688743f8beef89043c3e9ad",
"sha256": "57a1d6b43c1399d219ea18644240c4d4c6787c829f0a67ded216472867857cd0",
"size": 262144,
"repo_path": "bios/Arcade/Arcade/firmware.bin",
"repo_path": "bios/Nintendo/Nintendo DS/firmware.bin",
"cores": null
},
{
@@ -2322,10 +2322,10 @@
},
{
"dest": "dsi_firmware.bin",
"sha1": "93c0598b08192a1f630e5edb2cd9f60d1e3ea7b3",
"sha256": "1f89935da2888cd3e401af2774e06a6b587ca059e85f922826494f317d31c6ae",
"sha1": "d2a5af338f09c5cbdd5d7628db5b9c075c69b616",
"sha256": "1d7c771de535e6e07182fc9820ac32e76c6f0b5bcefd256a861fdfab144761ec",
"size": 131072,
"repo_path": "bios/Arcade/Arcade/dsi_firmware.bin",
"repo_path": "bios/Nintendo/Nintendo DS/dsi_firmware.bin",
"cores": null
},
{
@@ -5430,19 +5430,21 @@
},
{
"dest": "fbneo/samples/donpachi.zip",
"sha1": "c0c0b5db93a61276a6fe6842049cb53e564b8413",
"sha256": "a686ebf893d511b5b7667176cd6844593e914595a8bb9ab656b2c66969013b5c",
"size": 5641310,
"repo_path": "bios/Other/fbneo/donpachi.zip",
"sha1": "d380fb29287eb7fc9ff901a7653ad40785f7deb1",
"sha256": "78a237f1e2774eb396e2f14999f1270597e0767a392729e7a4539455888b6fe0",
"size": 208549253,
"repo_path": "bios/Other/fbneo/fbneo/samples/donpachi.zip",
"cores": [
"fbneo"
]
],
"storage": "release",
"release_asset": "donpachi.zip"
},
{
"dest": "fbneo/samples/sfz3mix.zip",
"sha1": "227815ce9e55db427d68e075182caffe6ad60ad1",
"sha256": "6a720035646b3488a047ab163a6975b7be82fe75c5eec88155c8503c93a631fe",
"size": 96705917,
"sha1": "e39ee9abb19076ef095f67469ca95ff5e7f600dc",
"sha256": "2c2e67ab762102f50df641280721164ddff0316e71081d5fa62f2a67365dea66",
"size": 101017377,
"repo_path": "bios/Other/fbneo/fbneo/samples/sfz3mix.zip",
"cores": [
"fbneo"
+19 -19
View File
@@ -5,7 +5,7 @@
"platform": "retrodeck",
"display_name": "RetroDECK",
"version": "1.0",
"generated": "2026-09-05T09:26:20Z",
"generated": "2026-09-13T22:10:18Z",
"base_destination": "",
"detect": [
{
@@ -238,7 +238,7 @@
}
],
"total_files": 3515,
"total_size": 6656314549,
"total_size": 6863533952,
"total_omitted": 4,
"omitted_files": [
{
@@ -19433,19 +19433,21 @@
},
{
"dest": "bios/fbneo/samples/donpachi.zip",
"sha1": "c0c0b5db93a61276a6fe6842049cb53e564b8413",
"sha256": "a686ebf893d511b5b7667176cd6844593e914595a8bb9ab656b2c66969013b5c",
"size": 5641310,
"repo_path": "bios/Other/fbneo/donpachi.zip",
"sha1": "d380fb29287eb7fc9ff901a7653ad40785f7deb1",
"sha256": "78a237f1e2774eb396e2f14999f1270597e0767a392729e7a4539455888b6fe0",
"size": 208549253,
"repo_path": "bios/Other/fbneo/fbneo/samples/donpachi.zip",
"cores": [
"fbneo"
]
],
"storage": "release",
"release_asset": "donpachi.zip"
},
{
"dest": "bios/fbneo/samples/sfz3mix.zip",
"sha1": "227815ce9e55db427d68e075182caffe6ad60ad1",
"sha256": "6a720035646b3488a047ab163a6975b7be82fe75c5eec88155c8503c93a631fe",
"size": 96705917,
"sha1": "e39ee9abb19076ef095f67469ca95ff5e7f600dc",
"sha256": "2c2e67ab762102f50df641280721164ddff0316e71081d5fa62f2a67365dea66",
"size": 101017377,
"repo_path": "bios/Other/fbneo/fbneo/samples/sfz3mix.zip",
"cores": [
"fbneo"
@@ -21549,10 +21551,10 @@
},
{
"dest": "bios/dsi_firmware.bin",
"sha1": "93c0598b08192a1f630e5edb2cd9f60d1e3ea7b3",
"sha256": "1f89935da2888cd3e401af2774e06a6b587ca059e85f922826494f317d31c6ae",
"sha1": "d2a5af338f09c5cbdd5d7628db5b9c075c69b616",
"sha256": "1d7c771de535e6e07182fc9820ac32e76c6f0b5bcefd256a861fdfab144761ec",
"size": 131072,
"repo_path": "bios/Arcade/Arcade/dsi_firmware.bin",
"repo_path": "bios/Nintendo/Nintendo DS/dsi_firmware.bin",
"cores": [
"melonds"
]
@@ -25815,9 +25817,7 @@
"repo_path": "bios/Other/sdlpal/sdlpal/5.avi",
"cores": [
"sdlpal"
],
"storage": "release",
"release_asset": "5.avi"
]
},
{
"dest": "bios/sdlpal/6.avi",
@@ -29865,10 +29865,10 @@
},
{
"dest": "bios/SkyEmu/firmware.bin",
"sha1": "5b2acbd499b39fb1af1b36ef7de5eb047d83401c",
"sha256": "7ea4f06ca110f8b7ff7c946f6e4e228d94977dadd4bb51570d14c68488edb32a",
"sha1": "cfe072921ee3fb93f688743f8beef89043c3e9ad",
"sha256": "57a1d6b43c1399d219ea18644240c4d4c6787c829f0a67ded216472867857cd0",
"size": 262144,
"repo_path": "bios/Arcade/Arcade/firmware.bin",
"repo_path": "bios/Nintendo/Nintendo DS/firmware.bin",
"cores": [
"skyemu"
]
+23 -23
View File
@@ -5,7 +5,7 @@
"platform": "retropie",
"display_name": "RetroPie",
"version": "1.0",
"generated": "2026-09-05T09:26:20Z",
"generated": "2026-09-13T22:10:18Z",
"base_destination": "system",
"detect": [
{
@@ -16,7 +16,7 @@
],
"standalone_copies": [],
"total_files": 1871,
"total_size": 5865446694,
"total_size": 6072666103,
"total_omitted": 1,
"omitted_files": [
{
@@ -1625,10 +1625,10 @@
},
{
"dest": "dsi_firmware.bin",
"sha1": "93c0598b08192a1f630e5edb2cd9f60d1e3ea7b3",
"sha256": "1f89935da2888cd3e401af2774e06a6b587ca059e85f922826494f317d31c6ae",
"sha1": "d2a5af338f09c5cbdd5d7628db5b9c075c69b616",
"sha256": "1d7c771de535e6e07182fc9820ac32e76c6f0b5bcefd256a861fdfab144761ec",
"size": 131072,
"repo_path": "bios/Arcade/Arcade/dsi_firmware.bin",
"repo_path": "bios/Nintendo/Nintendo DS/dsi_firmware.bin",
"cores": null
},
{
@@ -6911,19 +6911,21 @@
},
{
"dest": "fbneo/samples/donpachi.zip",
"sha1": "c0c0b5db93a61276a6fe6842049cb53e564b8413",
"sha256": "a686ebf893d511b5b7667176cd6844593e914595a8bb9ab656b2c66969013b5c",
"size": 5641310,
"repo_path": "bios/Other/fbneo/donpachi.zip",
"sha1": "d380fb29287eb7fc9ff901a7653ad40785f7deb1",
"sha256": "78a237f1e2774eb396e2f14999f1270597e0767a392729e7a4539455888b6fe0",
"size": 208549253,
"repo_path": "bios/Other/fbneo/fbneo/samples/donpachi.zip",
"cores": [
"fbneo"
]
],
"storage": "release",
"release_asset": "donpachi.zip"
},
{
"dest": "fbneo/samples/sfz3mix.zip",
"sha1": "227815ce9e55db427d68e075182caffe6ad60ad1",
"sha256": "6a720035646b3488a047ab163a6975b7be82fe75c5eec88155c8503c93a631fe",
"size": 96705917,
"sha1": "e39ee9abb19076ef095f67469ca95ff5e7f600dc",
"sha256": "2c2e67ab762102f50df641280721164ddff0316e71081d5fa62f2a67365dea66",
"size": 101017377,
"repo_path": "bios/Other/fbneo/fbneo/samples/sfz3mix.zip",
"cores": [
"fbneo"
@@ -9367,10 +9369,10 @@
},
{
"dest": "d2fdc.zip",
"sha1": "bc39fbd5b9a8d2287ac5d0a42e639fc4d3c2f9d4",
"sha256": "e5e30615040567c1e7a2d21599681f8dac820edbdcda177b816a64d74b3a12f2",
"size": 256,
"repo_path": "bios/Apple/Apple II/DiskII/state-machine-16.rom",
"sha1": "af56c948598291b284a528f3fce06b961dba55e3",
"sha256": "69ee0f8f0862e1a623bcbe9870f9531f7976312f292a20d1aff7ed61b6085a69",
"size": 262,
"repo_path": "bios/Arcade/Arcade/a3fdc.zip",
"cores": [
"mamemess"
]
@@ -13379,9 +13381,7 @@
"repo_path": "bios/Other/sdlpal/sdlpal/5.avi",
"cores": [
"sdlpal"
],
"storage": "release",
"release_asset": "5.avi"
]
},
{
"dest": "sdlpal/6.avi",
@@ -15965,10 +15965,10 @@
},
{
"dest": "SkyEmu/firmware.bin",
"sha1": "5b2acbd499b39fb1af1b36ef7de5eb047d83401c",
"sha256": "7ea4f06ca110f8b7ff7c946f6e4e228d94977dadd4bb51570d14c68488edb32a",
"sha1": "cfe072921ee3fb93f688743f8beef89043c3e9ad",
"sha256": "57a1d6b43c1399d219ea18644240c4d4c6787c829f0a67ded216472867857cd0",
"size": 262144,
"repo_path": "bios/Arcade/Arcade/firmware.bin",
"repo_path": "bios/Nintendo/Nintendo DS/firmware.bin",
"cores": [
"skyemu"
]
+20 -20
View File
@@ -5,7 +5,7 @@
"platform": "rocknix",
"display_name": "ROCKNIX",
"version": "1.0",
"generated": "2026-09-05T09:26:20Z",
"generated": "2026-09-13T22:10:18Z",
"base_destination": "bios",
"detect": [
{
@@ -18,7 +18,7 @@
],
"standalone_copies": [],
"total_files": 1738,
"total_size": 5743476850,
"total_size": 5950696259,
"total_omitted": 1,
"omitted_files": [
{
@@ -4015,19 +4015,21 @@
},
{
"dest": "fbneo/samples/donpachi.zip",
"sha1": "c0c0b5db93a61276a6fe6842049cb53e564b8413",
"sha256": "a686ebf893d511b5b7667176cd6844593e914595a8bb9ab656b2c66969013b5c",
"size": 5641310,
"repo_path": "bios/Other/fbneo/donpachi.zip",
"sha1": "d380fb29287eb7fc9ff901a7653ad40785f7deb1",
"sha256": "78a237f1e2774eb396e2f14999f1270597e0767a392729e7a4539455888b6fe0",
"size": 208549253,
"repo_path": "bios/Other/fbneo/fbneo/samples/donpachi.zip",
"cores": [
"fbneo"
]
],
"storage": "release",
"release_asset": "donpachi.zip"
},
{
"dest": "fbneo/samples/sfz3mix.zip",
"sha1": "227815ce9e55db427d68e075182caffe6ad60ad1",
"sha256": "6a720035646b3488a047ab163a6975b7be82fe75c5eec88155c8503c93a631fe",
"size": 96705917,
"sha1": "e39ee9abb19076ef095f67469ca95ff5e7f600dc",
"sha256": "2c2e67ab762102f50df641280721164ddff0316e71081d5fa62f2a67365dea66",
"size": 101017377,
"repo_path": "bios/Other/fbneo/fbneo/samples/sfz3mix.zip",
"cores": [
"fbneo"
@@ -7211,10 +7213,10 @@
},
{
"dest": "d2fdc.zip",
"sha1": "bc39fbd5b9a8d2287ac5d0a42e639fc4d3c2f9d4",
"sha256": "e5e30615040567c1e7a2d21599681f8dac820edbdcda177b816a64d74b3a12f2",
"size": 256,
"repo_path": "bios/Apple/Apple II/DiskII/state-machine-16.rom",
"sha1": "af56c948598291b284a528f3fce06b961dba55e3",
"sha256": "69ee0f8f0862e1a623bcbe9870f9531f7976312f292a20d1aff7ed61b6085a69",
"size": 262,
"repo_path": "bios/Arcade/Arcade/a3fdc.zip",
"cores": [
"mamemess"
]
@@ -12543,9 +12545,7 @@
"repo_path": "bios/Other/sdlpal/sdlpal/5.avi",
"cores": [
"sdlpal"
],
"storage": "release",
"release_asset": "5.avi"
]
},
{
"dest": "sdlpal/6.avi",
@@ -15389,10 +15389,10 @@
},
{
"dest": "SkyEmu/firmware.bin",
"sha1": "5b2acbd499b39fb1af1b36ef7de5eb047d83401c",
"sha256": "7ea4f06ca110f8b7ff7c946f6e4e228d94977dadd4bb51570d14c68488edb32a",
"sha1": "cfe072921ee3fb93f688743f8beef89043c3e9ad",
"sha256": "57a1d6b43c1399d219ea18644240c4d4c6787c829f0a67ded216472867857cd0",
"size": 262144,
"repo_path": "bios/Arcade/Arcade/firmware.bin",
"repo_path": "bios/Nintendo/Nintendo DS/firmware.bin",
"cores": [
"skyemu"
]
+15 -13
View File
@@ -5,7 +5,7 @@
"platform": "romm",
"display_name": "RomM",
"version": "1.0",
"generated": "2026-09-03T20:45:52Z",
"generated": "2026-09-13T22:10:18Z",
"base_destination": "bios",
"detect": [
{
@@ -16,7 +16,7 @@
],
"standalone_copies": [],
"total_files": 615,
"total_size": 1366505831,
"total_size": 1573725234,
"total_omitted": 0,
"omitted_files": [],
"files": [
@@ -3332,19 +3332,21 @@
},
{
"dest": "colecovision/fbneo/samples/donpachi.zip",
"sha1": "c0c0b5db93a61276a6fe6842049cb53e564b8413",
"sha256": "a686ebf893d511b5b7667176cd6844593e914595a8bb9ab656b2c66969013b5c",
"size": 5641310,
"repo_path": "bios/Other/fbneo/donpachi.zip",
"sha1": "d380fb29287eb7fc9ff901a7653ad40785f7deb1",
"sha256": "78a237f1e2774eb396e2f14999f1270597e0767a392729e7a4539455888b6fe0",
"size": 208549253,
"repo_path": "bios/Other/fbneo/fbneo/samples/donpachi.zip",
"cores": [
"fbneo"
]
],
"storage": "release",
"release_asset": "donpachi.zip"
},
{
"dest": "colecovision/fbneo/samples/sfz3mix.zip",
"sha1": "227815ce9e55db427d68e075182caffe6ad60ad1",
"sha256": "6a720035646b3488a047ab163a6975b7be82fe75c5eec88155c8503c93a631fe",
"size": 96705917,
"sha1": "e39ee9abb19076ef095f67469ca95ff5e7f600dc",
"sha256": "2c2e67ab762102f50df641280721164ddff0316e71081d5fa62f2a67365dea66",
"size": 101017377,
"repo_path": "bios/Other/fbneo/fbneo/samples/sfz3mix.zip",
"cores": [
"fbneo"
@@ -3808,10 +3810,10 @@
},
{
"dest": "nds/dsi_firmware.bin",
"sha1": "93c0598b08192a1f630e5edb2cd9f60d1e3ea7b3",
"sha256": "1f89935da2888cd3e401af2774e06a6b587ca059e85f922826494f317d31c6ae",
"sha1": "d2a5af338f09c5cbdd5d7628db5b9c075c69b616",
"sha256": "1d7c771de535e6e07182fc9820ac32e76c6f0b5bcefd256a861fdfab144761ec",
"size": 131072,
"repo_path": "bios/Arcade/Arcade/dsi_firmware.bin",
"repo_path": "bios/Nintendo/Nintendo DS/dsi_firmware.bin",
"cores": [
"melonds"
]
+2 -1
View File
@@ -601,7 +601,7 @@ nav:
- Dolphin Launcher: emulators/dolphin_launcher.md
- Parallel Launcher: emulators/parallel-launcher.md
- SWF Player: emulators/swf-player.md
- Other (56):
- Other (57):
- ares: emulators/ares.md
- Basilisk II: emulators/basiliskii.md
- beebem: emulators/beebem.md
@@ -635,6 +635,7 @@ nav:
- Oricutron: emulators/oricutron.md
- Pizza Boy SC: emulators/pizza-boy-sc.md
- Plastic: emulators/plastic.md
- POM2: emulators/pom2.md
- project64: emulators/project64.md
- puNES: emulators/punes.md
- Real3DOPlayer: emulators/real3doplayer.md
+336
View File
@@ -0,0 +1,336 @@
#!/usr/bin/env python3
"""Compare the large-files release with the files the collection keeps out of git.
Every gitignored file under bios/ is served to the installer as an asset of
the large-files release, and install.py refuses a download whose
Content-Length differs from the manifest size. The manifest size is that of
the local copy, so an asset uploaded before the local file was rebuilt fails
every install of it until it is uploaded again.
Usage:
python scripts/check_release_assets.py
python scripts/check_release_assets.py --json
"""
from __future__ import annotations
import argparse
import hashlib
import json
import os
import re
import subprocess
import sys
sys.path.insert(0, os.path.dirname(__file__))
from common import load_database
from largefiles import LARGE_FILES_RELEASE, LARGE_FILES_REPO
Finding = tuple[str, str, int, int | None]
def expected_assets(db: dict, gitignore_text: str) -> dict[str, int]:
"""Map each gitignored database path to the size the manifests carry."""
ignored = {
line.strip()
for line in gitignore_text.splitlines()
if line.strip().startswith("bios/")
}
return {
entry["path"]: entry["size"]
for entry in db.get("files", {}).values()
if entry.get("path") in ignored
}
def _asset_names(path: str) -> list[str]:
"""Names the release may publish a file under.
GitHub rewrites spaces to dots in asset names, so a file whose name
carries spaces is published under the dotted form.
"""
name = os.path.basename(path)
return [name, name.replace(" ", ".")] if " " in name else [name]
def compare(
expected: dict[str, int], assets: dict[str, int], notes_current: bool = True
) -> list[Finding]:
"""Files the release lacks or serves at another size, sorted by kind.
A release description that no longer matches what render_notes() would
write is a finding of its own: the page is what a reader checks a
download against.
"""
findings: list[Finding] = []
if not notes_current:
findings.append(("notes", "release description", 0, None))
for path, size in sorted(expected.items()):
published = next(
(assets[name] for name in _asset_names(path) if name in assets), None
)
if published is None:
findings.append(("missing", path, size, None))
elif published != size:
findings.append(("size", path, size, published))
return sorted(findings)
ASSET_URL = f"https://github.com/{LARGE_FILES_REPO}/releases/download/{LARGE_FILES_RELEASE}/"
NOT_INDEXED = "Not indexed"
SECTIONS = (
"Console firmware",
"Arcade",
"Computer",
"Game engine data",
"Virtual machine firmware",
"Other",
NOT_INDEXED,
)
_ROW = re.compile(
r"^\| \[(?P<name>[^\]]+)\]\([^)]*\) \| (?P<desc>[^|]*?) \| [^|]* \|"
r"(?: `(?P<sha1>[0-9a-f]{40})` \|)?$",
re.M,
)
_HEADING = re.compile(r"^## (.+)$", re.M)
def parse_notes(body: str) -> dict[str, tuple[str, str, str]]:
"""Name -> (section, description, sha1) for every row of a release page."""
rows: dict[str, tuple[str, str, str]] = {}
section = ""
for line in body.splitlines():
heading = _HEADING.match(line)
if heading:
section = heading.group(1).strip()
continue
row = _ROW.match(line)
if row:
rows[row.group("name")] = (
section, row.group("desc").strip(), row.group("sha1") or ""
)
return rows
def _section_for(path: str) -> str:
parts = path.split("/")
top = parts[1] if len(parts) > 1 else ""
if top in ("Nintendo", "Sony", "Sega", "Microsoft", "NEC", "SNK"):
return "Console firmware"
if top == "Arcade" or "/samples/" in path:
return "Arcade"
if top == "QEMU":
return "Virtual machine firmware"
if top in ("RPG Maker", "ScummVM"):
return "Game engine data"
if top in ("Apple", "Commodore", "Atari", "Sinclair", "Amstrad"):
return "Computer"
return "Other"
def _mib(size: int) -> str:
return f"{round(size / 1048576)} MB"
def render_notes(
db: dict,
gitignore_text: str,
assets: dict[str, int],
previous: str,
descriptions: dict[str, str],
bundles: dict[str, str],
cache_sha1: dict[str, str],
) -> str:
"""The release page, from what the release actually serves.
Every asset gets one row. A file the database indexes carries its
database SHA1; a data-directory bundle carries the hash of its cached
copy when one exists; anything else is listed apart with its size only,
so the page never vouches for bytes nobody indexed. Descriptions and
sections already written by hand are kept by name.
"""
known = parse_notes(previous)
ignored = {
line.strip()
for line in gitignore_text.splitlines()
if line.strip().startswith("bios/")
}
indexed: dict[str, tuple[str, str]] = {}
for sha1, entry in db.get("files", {}).items():
path = entry.get("path", "")
if path in ignored:
name = os.path.basename(path)
for candidate in (name, name.replace(" ", ".")):
indexed[candidate] = (sha1, path)
rows: dict[str, list[tuple[int, str]]] = {section: [] for section in SECTIONS}
for name, size in assets.items():
section, description, previous_sha1 = known.get(name, ("", "", ""))
if name in indexed:
sha1, path = indexed[name]
section = section if section in SECTIONS[:-1] else _section_for(path)
stem = name.split(".")[0] + "." + name.split(".")[1] if name.count(".") > 1 else name
description = description or descriptions.get(name) or descriptions.get(stem) or path
elif name in bundles:
sha1 = cache_sha1.get(name, previous_sha1)
section = section if section in SECTIONS[:-1] else "Game engine data"
description = description or bundles[name]
else:
sha1 = ""
section = NOT_INDEXED
description = description or name
link = f"[{name}]({ASSET_URL}{name})"
if section == NOT_INDEXED:
line = f"| {link} | {description} | {_mib(size)} |"
else:
line = f"| {link} | {description} | {_mib(size)} | `{sha1}` |"
rows[section].append((-size, line))
out = [
"Files too large for the git repository (GitHub 100MB limit), plus game engine data packs.",
"Downloaded automatically by `generate_pack.py` when not present locally.",
"Manual: `gh release download large-files`",
]
for section in SECTIONS:
if not rows[section]:
continue
out += ["", f"## {section}", ""]
if section == NOT_INDEXED:
out += [
"Assets the collection does not index: no database entry names them, "
"so no hash is vouched for here.",
"",
"| File | Description | Size |",
"|------|-------------|-----:|",
]
else:
out += ["| File | Description | Size | SHA1 |", "|------|-------------|-----:|------|"]
out += [line for _, line in sorted(rows[section])]
total = sum(assets.values())
out += ["", f"{len(assets)} files, {total / 1073741824:.1f} GB total. Verify a download with `sha1sum <file>`.", ""]
return "\n".join(out)
def profile_descriptions(emulators_dir: str = "emulators") -> dict[str, str]:
"""Name -> description, from the first profile that declares the file."""
from common import load_emulator_profiles
found: dict[str, str] = {}
for profile in load_emulator_profiles(emulators_dir).values():
for entry in profile.get("files", []):
name = str(entry.get("name") or "")
if name and entry.get("description"):
found.setdefault(name, str(entry["description"]))
return found
def registry_bundles(registry_path: str = "platforms/_data_dirs.yml") -> dict[str, str]:
"""Asset name -> description for data directories served from the release."""
from common import yaml_load
with open(registry_path, encoding="utf-8") as handle:
registry = yaml_load(handle) or {}
bundles: dict[str, str] = {}
for entry in (registry.get("data_directories") or registry).values():
if not isinstance(entry, dict):
continue
url = str(entry.get("source_url") or "")
if url.startswith(ASSET_URL):
bundles[url[len(ASSET_URL):]] = str(entry.get("description") or "")
return bundles
def cache_hashes(names: set[str], cache_dir: str = ".cache/large") -> dict[str, str]:
"""SHA1 of the cached copy of each named asset that the cache holds."""
hashes: dict[str, str] = {}
for name in names:
path = os.path.join(cache_dir, name)
if os.path.isfile(path):
digest = hashlib.sha1()
with open(path, "rb") as handle:
for chunk in iter(lambda: handle.read(1 << 20), b""):
digest.update(chunk)
hashes[name] = digest.hexdigest()
return hashes
def fetch_release() -> tuple[dict[str, int], str]:
"""Name and size of every asset of the large-files release, and its page."""
result = subprocess.run(
[
"gh", "release", "view", LARGE_FILES_RELEASE,
"-R", LARGE_FILES_REPO, "--json", "assets,body",
],
capture_output=True, text=True, check=True,
)
data = json.loads(result.stdout)
return {a["name"]: a["size"] for a in data["assets"]}, data.get("body", "")
def fetch_assets() -> dict[str, int]:
"""Name and size of every asset of the large-files release."""
result = subprocess.run(
[
"gh", "release", "view", LARGE_FILES_RELEASE,
"-R", LARGE_FILES_REPO, "--json", "assets",
],
capture_output=True, text=True, check=True,
)
return {a["name"]: a["size"] for a in json.loads(result.stdout)["assets"]}
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__.split("\n")[0])
parser.add_argument("--db", default="database.json")
parser.add_argument("--gitignore", default=".gitignore")
parser.add_argument("--json", action="store_true")
parser.add_argument(
"--notes", metavar="FILE",
help="write the release page rendered from the collection to FILE",
)
args = parser.parse_args()
with open(args.gitignore, encoding="utf-8") as handle:
gitignore_text = handle.read()
db = load_database(args.db)
expected = expected_assets(db, gitignore_text)
try:
assets, body = fetch_release()
except (subprocess.CalledProcessError, FileNotFoundError, KeyError) as exc:
print(f"ERROR: cannot list release assets: {exc}", file=sys.stderr)
return 2
bundles = registry_bundles()
rendered = render_notes(
db, gitignore_text, assets, body, profile_descriptions(), bundles,
cache_hashes(set(bundles)),
)
if args.notes:
with open(args.notes, "w", encoding="utf-8") as handle:
handle.write(rendered)
findings = compare(expected, assets, notes_current=rendered.strip() == body.strip())
if args.json:
print(json.dumps(
[
{"kind": kind, "path": path, "expected": size, "published": published}
for kind, path, size, published in findings
],
indent=2,
))
else:
print(f"{len(expected)} gitignored files, {len(assets)} release assets")
for kind, path, size, published in findings:
if kind == "missing":
print(f" MISSING {path} ({size} bytes)")
elif kind == "size":
print(f" SIZE {path}: local {size} != release {published}")
else:
print(" NOTES release description differs from the rendered page"
" (--notes FILE, then gh release edit large-files --notes-file FILE)")
if not findings:
print(" release assets and description match the collection")
return 1 if findings else 0
if __name__ == "__main__":
sys.exit(main())
+6 -1
View File
@@ -230,7 +230,12 @@ def deduplicate(bios_dir: str, dry_run: bool = False) -> dict:
# Write MAME clone mapping
if mame_clones:
clone_path = "_mame_clones.json"
# Beside the scanned tree, where get_mame_clone_map() reads it for
# the real layout. A path relative to the working directory let a
# scan of a fixture tree rewrite the repository's own map.
clone_path = os.path.join(
os.path.dirname(os.path.abspath(bios_dir)), "_mame_clones.json"
)
# A group is only visible while both copies are on disk, and this run
# has just deleted the clone. Writing only what was seen this time
# therefore erases every mapping an earlier run recorded, and the
+11 -8
View File
@@ -2707,13 +2707,16 @@ def _load_gitignore_entries(repo_root: str) -> set[str]:
return entries
def _is_large_file(local_path: str, repo_root: str) -> bool:
"""Check if a file is a large file (>50MB or in .gitignore)."""
if local_path and os.path.exists(local_path):
if os.path.getsize(local_path) > 50_000_000:
return True
def _is_release_asset(local_path: str, repo_root: str) -> bool:
"""Whether the installer fetches this file from the large-files release.
The repository serves every committed file from its raw URL; only the
files kept out of git live as release assets, and .gitignore is the
ledger of those. Size is not the criterion: a committed file over 50 MB
is still served by the repository, and announcing it as a release asset
sends the installer to an asset nobody uploaded.
"""
gitignore = _load_gitignore_entries(repo_root)
# Check if the path relative to repo root is in .gitignore
try:
rel = os.path.relpath(local_path, repo_root)
except ValueError:
@@ -2826,7 +2829,7 @@ def _manifest_core_entries(
"cores": [source_emu] if source_emu else [],
}
if _is_large_file(local_path or "", repo_root):
if _is_release_asset(local_path or "", repo_root):
entry["storage"] = "release"
entry["release_asset"] = (
os.path.basename(local_path) if local_path else fe["name"]
@@ -3021,7 +3024,7 @@ def generate_manifest(
sha256 = hashes["sha256"]
repo_path = _get_repo_path(sha1, db) if sha1 else ""
is_release_asset = _is_large_file(local_path or "", repo_root)
is_release_asset = _is_release_asset(local_path or "", repo_root)
# An entry needs somewhere to be fetched from. Resolution can
# land on a file the database does not index -- a data
+15
View File
@@ -6,6 +6,7 @@ Steps:
1b. provenance_report.py (dump-catalog coverage from provenance/)
1c. romset_recipes.py (archive identification, reconstruction targets)
2. refresh_data_dirs.py (update Dolphin Sys, PPSSPP, etc.)
2b2. check_release_assets.py (large-files release vs gitignored files, online)
3. verify.py --all (check all platforms)
4. generate_pack.py --all (build ZIP packs)
4b. generate install manifests
@@ -346,6 +347,20 @@ def main():
elif args.check_buildbot:
print("\n--- 2b check buildbot system: SKIPPED (--offline) ---")
# Step 2b2: The release must serve the bytes the manifests describe. The
# installer compares Content-Length with the manifest size, so an asset
# uploaded before its local file was rebuilt fails every install of it.
if not args.offline:
ok, _ = run(
[sys.executable, "scripts/check_release_assets.py"],
"2b2 check release assets",
)
results["check_release_assets"] = ok
all_ok = all_ok and ok
else:
print("\n--- 2b2 check release assets: SKIPPED (--offline) ---")
results["check_release_assets"] = SKIPPED
# Step 2c: Generate truth YAMLs
# A targeted run writes its model in a subdirectory of its own, and the
# diff has to read the same one or it compares a narrowed model against
+205
View File
@@ -1184,6 +1184,211 @@ class EveryManifestEntryIsFetchable(unittest.TestCase):
for entry in data.get("omitted_files", []):
self.assertIn(entry.get("reason"), allowed)
def _manifests(self) -> list[Path]:
paths = sorted((ROOT / "install").glob("*.json"))
paths += sorted((ROOT / "install" / "targets").glob("*.json"))
self.assertTrue(paths, "no install manifests to check")
return paths
def test_repo_paths_name_the_file_the_database_holds(self):
"""A manifest written before a file moved sends the installer to 404.
database.json is regenerated whenever a file is refiled; the manifests
are a separate artefact and were left behind once (the two DS
firmware dumps of the 7 September refile). The installer fetches
repo_path from raw.githubusercontent.com, so a stale one is a
download that can never succeed.
"""
database = ROOT / "database.json"
if not database.is_file():
self.skipTest("database.json not generated")
files = json.loads(database.read_text(encoding="utf-8"))["files"]
for path in self._manifests():
with self.subTest(manifest=path.name):
data = json.loads(path.read_text(encoding="utf-8"))
stale = [
(entry["dest"], entry["repo_path"], files.get(entry["sha1"], {}).get("path"))
for entry in data.get("files", [])
if entry.get("repo_path")
and files.get(entry.get("sha1", ""), {}).get("path") != entry["repo_path"]
]
self.assertEqual(stale, [], f"{path.name} names moved files: {stale[:3]}")
def test_release_entries_are_exactly_the_files_git_does_not_hold(self):
"""The installer has two sources, and the manifest must pick the right one.
A committed file is served by the repository; a gitignored one by
the large-files release. Marking a committed file as a release asset
sends the installer to an asset nobody uploaded (sdlpal/5.avi, 83 MB
in git, was announced as release asset `5.avi`). Marking a gitignored
file as a repo file sends it to a raw URL that has no content.
"""
tracked = set(
subprocess.run(
["git", "ls-files", "-z", "--", "bios"],
capture_output=True, text=True, cwd=ROOT, check=True,
).stdout.split("\0")
)
if not tracked:
self.skipTest("not a git checkout")
for path in self._manifests():
with self.subTest(manifest=path.name):
data = json.loads(path.read_text(encoding="utf-8"))
wrong = []
for entry in data.get("files", []):
repo_path = entry.get("repo_path")
if not repo_path:
continue
committed = repo_path in tracked
if bool(entry.get("release_asset")) == committed:
wrong.append((entry["dest"], repo_path, "committed" if committed else "gitignored"))
self.assertEqual(wrong, [], f"{path.name} picks the wrong source: {wrong[:3]}")
class ReleaseAssetCriterion(unittest.TestCase):
"""What decides whether the installer fetches from the release is git, not size.
Files over 50 MB are supposed to be gitignored and uploaded to the
large-files release, but four committed files break that rule and one of
them reached a manifest as a release asset that does not exist. The
truthful question is whether the repository serves the bytes, and the
ledger of what it does not serve is .gitignore.
"""
def _repo(self, directory: str, ignored: str) -> str:
Path(directory, ".gitignore").write_text(ignored + "\n", encoding="utf-8")
return directory
def test_a_large_committed_file_is_served_by_the_repository(self):
from scripts import generate_pack
with tempfile.TemporaryDirectory(dir=TMP_ROOT) as directory:
root = self._repo(directory, "bios/elsewhere.bin")
big = Path(root, "bios", "big.avi")
big.parent.mkdir()
with big.open("wb") as handle:
handle.truncate(60_000_000)
generate_pack._GITIGNORE_ENTRIES = None
try:
self.assertFalse(generate_pack._is_release_asset(str(big), root))
finally:
generate_pack._GITIGNORE_ENTRIES = None
def test_a_gitignored_file_is_served_by_the_release_whatever_its_size(self):
from scripts import generate_pack
with tempfile.TemporaryDirectory(dir=TMP_ROOT) as directory:
root = self._repo(directory, "bios/small.zip")
small = Path(root, "bios", "small.zip")
small.parent.mkdir()
small.write_bytes(b"PK")
generate_pack._GITIGNORE_ENTRIES = None
try:
self.assertTrue(generate_pack._is_release_asset(str(small), root))
finally:
generate_pack._GITIGNORE_ENTRIES = None
class ReleaseAssetsMatchTheCollection(unittest.TestCase):
"""The bytes the release serves must be the bytes the manifests describe.
install.py checks Content-Length against the manifest size before it
downloads, and the manifest size is that of the local copy. Both FBNeo
sample archives were rebuilt locally after their upload and never
re-uploaded: same members, different container, every install of them
failed. The comparison is offline here on a fixture; the script runs it
against the live release.
"""
def test_missing_and_resized_assets_are_reported_and_nothing_else(self):
from scripts import check_release_assets
expected = {
"bios/Other/fbneo/fbneo/samples/twotiger.zip": 154985212,
"bios/Arcade/MAME/MAME 0.174 Arcade XML.dat": 53677408,
"bios/Other/sdlpal/sdlpal/5.avi": 82833972,
}
assets = {
"twotiger.zip": 154888877,
"MAME.0.174.Arcade.XML.dat": 53677408,
"unrelated.zip": 1,
}
findings = check_release_assets.compare(expected, assets)
self.assertEqual(
findings,
[
("missing", "bios/Other/sdlpal/sdlpal/5.avi", 82833972, None),
("size", "bios/Other/fbneo/fbneo/samples/twotiger.zip", 154985212, 154888877),
],
)
def test_expected_assets_are_the_gitignored_database_entries(self):
from scripts import check_release_assets
db = {
"files": {
"a" * 40: {"path": "bios/Other/x/big.zip", "size": 10},
"b" * 40: {"path": "bios/Other/x/small.bin", "size": 2},
}
}
gitignore = "# large\nbios/Other/x/big.zip\ntmp/\n"
self.assertEqual(
check_release_assets.expected_assets(db, gitignore),
{"bios/Other/x/big.zip": 10},
)
def test_release_notes_are_rendered_from_the_collection(self):
"""The release page is written by hand and drifts; it is rendered instead.
Three assets had no row, three rows carried the SHA1 of an asset
that had since been replaced, and the footer counted 41 files for 44.
Hand-written descriptions survive by name; a new row takes its
description from the profile that declares the file; an asset the
collection does not index is listed apart, with its size only.
"""
from scripts import check_release_assets
db = {"files": {
"a" * 40: {"path": "bios/Nintendo/Wii/nand.bin", "size": 553649152},
"b" * 40: {"path": "bios/Other/fbneo/fbneo/samples/twotiger.zip", "size": 154985212},
"c" * 40: {"path": "bios/Other/x/small.bin", "size": 2},
}}
gitignore = "bios/Nintendo/Wii/nand.bin\nbios/Other/fbneo/fbneo/samples/twotiger.zip\n"
assets = {"nand.bin": 553649152, "twotiger.zip": 154985212,
"sdlpal-data.zip": 140773720, "whoopee.zip": 222665810}
previous = (
"## Arcade\n\n| File | Description | Size | SHA1 |\n|---|---|---|---|\n"
"| [twotiger.zip](u) | Two Tigers samples | 148 MB | `" + "0" * 40 + "` |\n"
"| [whoopee.zip](u) | Toaplan Whoopee samples | 212 MB | `" + "9" * 40 + "` |\n"
)
descriptions = {"nand.bin": "BootMii NAND backup"}
bundles = {"sdlpal-data.zip": "SDLPAL Chinese Paladin game data (.mkf archives)"}
body = check_release_assets.render_notes(
db, gitignore, assets, previous, descriptions, bundles, {"sdlpal-data.zip": "d" * 40}
)
self.assertIn("| [twotiger.zip](https://github.com/Abdess/retrobios/releases/download/large-files/twotiger.zip) | Two Tigers samples | 148 MB | `" + "b" * 40 + "` |", body)
self.assertIn("| [nand.bin](https://github.com/Abdess/retrobios/releases/download/large-files/nand.bin) | BootMii NAND backup | 528 MB | `" + "a" * 40 + "` |", body)
self.assertIn("| [sdlpal-data.zip](https://github.com/Abdess/retrobios/releases/download/large-files/sdlpal-data.zip) | SDLPAL Chinese Paladin game data (.mkf archives) | 134 MB | `" + "d" * 40 + "` |", body)
self.assertIn("## Not indexed", body)
self.assertIn("| [whoopee.zip](https://github.com/Abdess/retrobios/releases/download/large-files/whoopee.zip) | Toaplan Whoopee samples | 212 MB |", body)
self.assertNotIn("9" * 40, body)
self.assertNotIn("small.bin", body)
self.assertIn("4 files, 1.0 GB total", body)
self.assertEqual(body.index("## Console firmware"), min(
body.index(h) for h in ("## Console firmware", "## Arcade", "## Not indexed")
))
def test_stale_notes_are_a_finding(self):
from scripts import check_release_assets
findings = check_release_assets.compare({}, {}, notes_current=False)
self.assertEqual(findings, [("notes", "release description", 0, None)])
def test_pipeline_runs_the_check_online_and_marks_it_skipped_offline(self):
source = (ROOT / "scripts" / "pipeline.py").read_text(encoding="utf-8")
self.assertIn("check_release_assets.py", source)
self.assertIn('results["check_release_assets"] = SKIPPED', source)
class PreservedBytesAreNeverNormalised(unittest.TestCase):
"""git must not rewrite a preserved file's line endings.
+17
View File
@@ -204,6 +204,23 @@ class CloneMapSurvivesASecondRun(_Bios):
path = Path(self._tmp.name) / "_mame_clones.json"
return json.loads(path.read_text()) if path.exists() else {}
def test_the_map_is_written_beside_the_scanned_tree_not_the_cwd(self):
"""A test or a run from another directory must not touch the repo's map.
The map was written to the working directory. The test suite runs
from the repo root, so a fixture scan of a temporary tree rewrote the
committed _mame_clones.json with two fixture entries, and a later
rewrite left 2 of its 71 parents.
"""
elsewhere = Path(self._tmp.name) / "elsewhere"
elsewhere.mkdir()
os.chdir(elsewhere)
self.write("Arcade/MAME/bbc_m87.zip")
self.write("Arcade/MAME/bbc_24bbc.zip")
self.run_dedup()
self.assertFalse((elsewhere / "_mame_clones.json").exists())
self.assertIn("bbc_m87.zip", self._map())
def test_a_recorded_mapping_survives_a_later_run(self):
self.write("Arcade/MAME/bbc_m87.zip")
self.write("Arcade/MAME/bbc_24bbc.zip")
+16
View File
@@ -132,6 +132,22 @@ gh release upload large-files "bios/Sony/PS3/PS3UPDAT.PUP#PS3UPDAT.PUP"
**Local cache.** `generate_pack.py` calls `fetch_large_file()` which downloads
from the release and caches in `.cache/large/` for subsequent runs.
**Check.** The installer refuses a download whose `Content-Length` differs
from the manifest size, and the manifest size is that of the local file. A
file rebuilt locally after its upload therefore fails every install until it
is uploaded again (`--clobber`). `python scripts/check_release_assets.py`
compares every gitignored `bios/` path in the database with the asset of the
same name, and the release page with the one it renders from the collection;
the online pipeline runs it as step 2b2. To refresh the page:
```bash
python scripts/check_release_assets.py --notes tmp/notes.md
gh release edit large-files --notes-file tmp/notes.md
```
An asset no database entry names is listed on the page under "Not indexed",
with its size only: the collection vouches for no hash it does not hold.
## Cutting a release
Releasing is deliberate and local. Nothing on GitHub builds a pack: the