diff --git a/emulators/dolphin.yml b/emulators/dolphin.yml index ff58f6d0..1ba1d8c7 100644 --- a/emulators/dolphin.yml +++ b/emulators/dolphin.yml @@ -10,6 +10,7 @@ core_version: "Git" display_name: "Nintendo - GameCube / Wii (Dolphin)" cores: - dolphin + - "dolphin-gui" systems: [nintendo-gamecube, nintendo-wii, sega-triforce] # path: is where the libretro core reads a file, standalone_path: where the diff --git a/emulators/eightyone.yml b/emulators/eightyone.yml new file mode 100644 index 00000000..ae543c87 --- /dev/null +++ b/emulators/eightyone.yml @@ -0,0 +1,56 @@ +emulator: EightyOne (Recalbox) +type: libretro +core_classification: community_fork +source: "https://gitlab.com/recalbox/packages/recalbox-cores/libretro-eightyone" +upstream: "https://github.com/charlierobson/EightyOne" +profiled_date: "2026-10-17" +source_commit: "39ea0cc26453f4026458cfff62f10223a6bb1724" +core_version: "v1.2" +display_name: "Sinclair - ZX81 / ZX Spectrum (EightyOne, Recalbox)" +cores: ["eightyone"] +systems: + - sinclair-zx81 + - sinclair-zx80 + - sinclair-zx-spectrum + - jupiter-ace + - timex-ts1500 + - timex-tc2048 + - timex-ts2068 + - lambda-8300 + - ringo-r470 + - microdigital-tk85 + +notes: | + Recalbox port of EightyOne, vendored under 81/ and built with CMake. + Machines: ZX80, ZX81, ZX97LE, TS1000, TS1500, TK85, Lambda 8300, + Ringo R470, Spectrum 16K/48K/+/128K/+2/+2A/+3, TC2048, TC2068, TS2068, + Jupiter ACE. + ref: libretro/libretro_core.cpp:876-1074 + + The ROM directory is /eightyone/ with ROMs/, FDCs/ and IDEs/ + subfolders. + ref: libretro/libretro_core.cpp:2620-2631 + + 86 machine, interface, IDE, graphics and speech ROMs are compiled in as + zlib-compressed arrays and looked up by basename. + ref: libretro/eo_roms.cpp:16-103, libretro/eo_roms.cpp:106-128 + + memory_load, memoryLoadToAddress and font_load query the embedded table + before opening any path, and every ROM name the core requests is in that + table, so no ROM is read from the system directory. + ref: 81/Source/zx81/snap.cpp:1189-1199, 81/Source/zx81/snap.cpp:1285-1299, 81/Source/zx81/snap.cpp:1317-1328, 81/Source/zx81config.cpp:161-210, 81/Source/zx81config.cpp:259-284 + + Didaktik D40/D80 tests for eightyone/FDCs/didaktik.gama.rom and stores its + full path in CurRom when present; memory_load reduces the path to its + basename and serves the embedded copy. + ref: libretro/libretro_core.cpp:2953-2968, 81/Source/Spectrum/spec48.cpp:361-362 + + ZXpand writes zxpand-eeprom.bin (256 bytes of 0xFF) under the ROM + directory when it is absent. + ref: 81/Source/zxpand/smbsd.cpp:75-98 + + Digitalker is a stub and its SSR ROM loader is not compiled; CapsImg is + linked statically. + ref: libretro/eo_stubs.cpp:67-68, CMakeLists.txt:267-291 + +files: [] diff --git a/emulators/exel-hence.yml b/emulators/exel-hence.yml new file mode 100644 index 00000000..85b3e385 --- /dev/null +++ b/emulators/exel-hence.yml @@ -0,0 +1,34 @@ +emulator: Exel-Hence +type: libretro +core_classification: pure_libretro +source: "https://gitlab.com/recalbox/packages/recalbox-cores/libretro-exel-hence" +upstream: "https://gitlab.com/recalbox/packages/recalbox-cores/libretro-exel-hence" +profiled_date: "2026-10-17" +source_commit: "213328332cbfd8121e018493443e223a7a780961" +core_version: "v0.9" +display_name: "Exelvision - EXL 100 (Exel-Hence)" +cores: + - "exel-hence" +systems: + - "exelvision-exl100" + +notes: | + Exelvision EXL 100 emulator written as a libretro core by Recalbox. + + retro_load_game() asks for the system directory and hands it to + Exl100LoadRoms() (ref: src/libretro.c:710-734), which ignores it: the + main and sub CPU BIOS images are unpacked from arrays compiled into the + core (ref: src/exl100.c:1163-1181). The images are raw DEFLATE streams + XOR'd against a rotating key and inflated at load time + (ref: src/exl100_bios.c:56-101). Both arrays are present in the + shipped header (ref: src/exl100_bios.h:6703-6704). Exelmemoria, the + ExelBASIC and ExelBASIC+ cartridges and the ExelDisk DOS come from the same embedded + tables (ref: src/libretro.c:508, 533, 562). + + The only file opened by name is a sidecar next to a .cram content file, + cram.txt or .txt, scanned for a CALL EXEC or RUN + line to auto-start the program (ref: src/libretro.c:614-686). It + belongs to the content. + +exclusion_note: "BIOS, BASIC cartridges and ExelDisk DOS compiled into the core; the system directory is never read" +files: [] diff --git a/emulators/flycast.yml b/emulators/flycast.yml index 831c6a13..8ef285db 100644 --- a/emulators/flycast.yml +++ b/emulators/flycast.yml @@ -12,6 +12,7 @@ cores: - flycast - flycast_dev - flycastvl + - "flycast-next" systems: - sega-dreamcast - sega-naomi diff --git a/emulators/frotz.yml b/emulators/frotz.yml new file mode 100644 index 00000000..62623cad --- /dev/null +++ b/emulators/frotz.yml @@ -0,0 +1,33 @@ +emulator: Frotz +type: standalone +core_classification: game_engine +source: "https://gitlab.com/DavidGriffith/frotz" +upstream: "https://gitlab.com/DavidGriffith/frotz" +profiled_date: "2026-10-17" +source_commit: "2f17d64f23f3d6e68cd676d35c9d1789e17bc9fc" +core_version: "2.55pre" +display_name: "Infocom Z-Machine (SDL Frotz)" +cores: + - "frotz" +systems: + - "zmachine" + +notes: | + Z-machine interpreter for Infocom and Inform story files (versions 1 + to 8). Recalbox builds the SDL front end, sfrotz, and launches it with + a generated config file and the story file. + + sf_initfonts() builds the text and fixed-width fonts from the bitmap + compiled into sf_deffont.c (ref: src/sdl/sf_deffont.c:22) and the + character graphics font from SF_font3 (ref: src/sdl/sf_fonts.c:979-989). + TrueType fonts are loaded only when the config file names them under + [Fonts] (ref: src/sdl/sf_resource.c:402-413), and a font that fails to + load is reported and skipped (ref: src/sdl/sf_fonts.c:959-973). No + default font path exists. + + Pictures and sounds come from the story's Blorb data or from loose + resource files under the [Resources] Dir setting, "./" by default + (ref: src/sdl/sf_resource.c:75, 415). Both belong to the game. + +exclusion_note: "fonts compiled into the binary; external TrueType fonts only when the user config names them" +files: [] diff --git a/emulators/genesis_plus_gx.yml b/emulators/genesis_plus_gx.yml index 41b5395e..68c9949c 100644 --- a/emulators/genesis_plus_gx.yml +++ b/emulators/genesis_plus_gx.yml @@ -12,6 +12,7 @@ cores: - genesisplusgx - genesisplusgx-expanded - genplus + - "genesisplusgx_ex" systems: - sega-megadrive - sega-megacd diff --git a/emulators/hypseus-singe.yml b/emulators/hypseus-singe.yml index 14da2f43..0b40c89d 100644 --- a/emulators/hypseus-singe.yml +++ b/emulators/hypseus-singe.yml @@ -10,6 +10,7 @@ display_name: "Arcade (Hypseus Singe)" cores: - hypseus-singe - hypseus + - "hypseus_singe" systems: - arcade-laserdisc mode: standalone diff --git a/emulators/julius.yml b/emulators/julius.yml new file mode 100644 index 00000000..5fdb2c20 --- /dev/null +++ b/emulators/julius.yml @@ -0,0 +1,108 @@ +emulator: Julius +type: standalone +core_classification: game_engine +source: "https://github.com/bvschaik/julius" +upstream: "https://github.com/bvschaik/julius" +profiled_date: "2026-10-17" +source_commit: "33c777019b2640b847b73815c3b4344cf7bd9576" +core_version: "1.7.0" +display_name: "Caesar III (Julius)" +cores: + - "julius" +systems: + - "caesar3" + +notes: | + Open-source reimplementation of Impressions Games' Caesar III engine. + It reads every graphic, text, sound and scenario from an installed copy + of the game; nothing is bundled. + + The data directory is the command-line argument. pre_init() makes it + the base path and runs game_pre_init(); a missing directory shows + "Julius requires the original files from Caesar 3" and exits + (ref: src/platform/julius.c:488-501, 580-586). File lookups are + case-corrected inside that directory. + + Startup loads, in order, the text and message files c3.eng and + c3_mm.eng (c3.rus and c3_mm.rus as the alternative pair) + (ref: src/game/game.c:48-63, src/core/lang.c:141-165), the central + climate graphics c3.sg2 and c3.555, the barbarian enemy graphics + goths.sg2 and goths.555, and c3_model.txt (ref: src/game/game.c:79-104). + Any of them missing aborts init. The_empire.555 is loaded with the + climate graphics; a wrong size is logged and the game continues + (ref: src/core/image.c:283-293, 323). The other climates, enemies, + sounds, videos and scenario maps are opened from the same directory on + demand. + + Recalbox lists Caesar III under roms/ports/Caesar3 with c3.exe as the + entry and patches config and save paths into /recalbox/share. + +files: + - name: "caesar3/" + type: directory + path: "caesar3/" + system: "caesar3" + category: game_data + required: true + description: "Caesar III install directory" + source_ref: "src/platform/julius.c:488-501" + note: "Given on the command line; every game file is opened by name inside it." + - name: "c3.eng" + path: "caesar3/c3.eng" + system: "caesar3" + category: game_data + required: true + description: "Caesar III interface text" + source_ref: "src/core/lang.c:23, 74-80, 141-165" + note: "Rejected when outside MIN_TEXT_SIZE..MAX_TEXT_SIZE. c3.rus replaces it on a Russian install." + - name: "c3_mm.eng" + path: "caesar3/c3_mm.eng" + system: "caesar3" + category: game_data + required: true + description: "Caesar III message text" + source_ref: "src/core/lang.c:24, 129-150, 160-165" + note: "Loaded as a pair with c3.eng; c3_mm.rus replaces it on a Russian install." + - name: "c3.sg2" + path: "caesar3/c3.sg2" + system: "caesar3" + category: game_data + required: true + description: "Main graphics index, central climate" + source_ref: "src/core/image.c:48-52, 295-306, src/game/game.c:83-86" + - name: "c3.555" + path: "caesar3/c3.555" + system: "caesar3" + category: game_data + required: true + description: "Main graphics bitmaps, central climate" + source_ref: "src/core/image.c:53-57, 314-317, src/game/game.c:83-86" + - name: "goths.sg2" + path: "caesar3/goths.sg2" + system: "caesar3" + category: game_data + required: true + description: "Barbarian enemy graphics index" + source_ref: "src/core/image.c:79, 667-675, src/game/game.c:87-90" + - name: "goths.555" + path: "caesar3/goths.555" + system: "caesar3" + category: game_data + required: true + description: "Barbarian enemy graphics bitmaps" + source_ref: "src/core/image.c:101, 681-684, src/game/game.c:87-90" + - name: "c3_model.txt" + path: "caesar3/c3_model.txt" + system: "caesar3" + category: game_data + required: true + description: "Building cost and desirability model" + source_ref: "src/building/model.c:83-88, src/game/game.c:101-104" + - name: "The_empire.555" + path: "caesar3/The_empire.555" + system: "caesar3" + category: game_data + required: false + description: "Empire map bitmap" + source_ref: "src/core/image.c:68, 283-293" + note: "A short read is logged and the empire map stays blank." diff --git a/emulators/lexaloffle.yml b/emulators/lexaloffle.yml index 8ad178fa..1b05a8f2 100644 --- a/emulators/lexaloffle.yml +++ b/emulators/lexaloffle.yml @@ -7,6 +7,7 @@ cores: - lexaloffle - "pico-8" - vox_official + - "pico8" systems: - pico8 - voxatron diff --git a/emulators/lrps2.yml b/emulators/lrps2.yml index f2f2f8b3..baee9ab5 100644 --- a/emulators/lrps2.yml +++ b/emulators/lrps2.yml @@ -12,7 +12,7 @@ profiled_date: "2026-03-25" source_commit: "6eabf2242d451ee2e6d52b1e3f10efb77143ed05" core_version: "Git" display_name: "Sony - PlayStation 2 (LRPS2)" -cores: [lrps2, pcsx2] +cores: [lrps2, pcsx2, "ps2"] systems: [sony-playstation-2] bios_directory: "pcsx2/bios/" diff --git a/emulators/mednafen_stv.yml b/emulators/mednafen_stv.yml new file mode 100644 index 00000000..788b2110 --- /dev/null +++ b/emulators/mednafen_stv.yml @@ -0,0 +1,124 @@ +emulator: Mednafen STV +type: libretro +core_classification: community_fork +source: "https://github.com/beudbeud/libretro-stv" +upstream: "https://mednafen.github.io/" +profiled_date: "2026-10-17" +source_commit: "2e42ef0c5d8238c170bcf182e68951c214fc6867" +core_version: "v1.2.1" +display_name: "Sega - ST-V (Mednafen STV)" +cores: + - "mednafen_stv" +systems: + - "sega-stv" + - "sega-saturn" + +notes: | + Libretro core by beudbeud built on the Saturn/ST-V module of Mednafen + 1.32.1, with an Asia ST-V BIOS setting and a stvbios.zip fallback added + to ss.cpp. Recalbox runs it for ST-V; the loader also accepts Saturn + disc images (cue, toc, ccd, chd, m3u). + + retro_init() points filesys.path_firmware at the frontend system + directory and names the BIOS of every region + (ref: libretro/libretro.cpp:615-641). The ST-V BIOS is picked by SMPC + area: Japan, Asia NTSC, Europe PAL, and North America for every other + area (ref: mednafen/ss/ss.cpp:1436-1446, mednafen/ss/smpc.h:32-40). + A Saturn disc takes sega_101.bin for Japan and Asia NTSC and + mpr-17933.bin otherwise (ref: mednafen/ss/ss.cpp:1447-1453). + + The loose file is tried first and must be exactly 524288 bytes; when it + is missing or the wrong size, the same name is looked up at the root of + stvbios.zip in the system directory, then without the leading slash + (ref: mednafen/ss/ss.cpp:1455-1491). With ss.bios_sanity on, the + default, a file named like one of the five Saturn BIOS images must + match its SHA-256; the ST-V images are not in that table and only the + size check applies (ref: mednafen/ss/ss.cpp:1493-1540, 2549). + + Saturn games that need the KoF 95 or Ultraman ROM cartridge, and the + Action Replay 4M Plus cart type, open their ROM from the firmware + directory under the default names below + (ref: mednafen/ss/ss.cpp:1348-1350, 1404-1412, 2542-2544). + +files: + - name: "epr-20091.ic8" + system: "sega-stv" + region: [japan] + required: true + size: 524288 + validation: [size] + description: "ST-V BIOS (Japan)" + source_ref: "libretro/libretro.cpp:636, mednafen/ss/ss.cpp:1438-1439, 1462-1468" + - name: "epr-19854.ic8" + system: "sega-stv" + region: [asia-ntsc] + required: true + size: 524288 + validation: [size] + description: "ST-V BIOS (Asia/Taiwan)" + source_ref: "libretro/libretro.cpp:637, mednafen/ss/ss.cpp:1440-1441, 1462-1468" + - name: "epr-17952a.ic8" + system: "sega-stv" + region: [north-america, latin-america, brazil, south-korea, asia-pal] + required: true + size: 524288 + validation: [size] + description: "ST-V BIOS (North America)" + source_ref: "libretro/libretro.cpp:638, mednafen/ss/ss.cpp:1444-1445, 1462-1468" + note: "Used for every SMPC area other than Japan, Asia NTSC and Europe PAL." + - name: "epr-17954a.ic8" + system: "sega-stv" + region: [europe] + required: true + size: 524288 + validation: [size] + description: "ST-V BIOS (Europe)" + source_ref: "libretro/libretro.cpp:639, mednafen/ss/ss.cpp:1442-1443, 1462-1468" + - name: "stvbios.zip" + system: "sega-stv" + category: bios_zip + required: false + description: "ST-V BIOS archive" + source_ref: "mednafen/ss/ss.cpp:1472-1491" + note: "Read only when the loose BIOS file is missing or not 524288 bytes. The member is found by the BIOS file name; its size is not checked." + contents: + - name: "epr-20091.ic8" + - name: "epr-19854.ic8" + - name: "epr-17952a.ic8" + - name: "epr-17954a.ic8" + - name: "sega_101.bin" + system: "sega-saturn" + region: [japan, asia-ntsc] + required: true + size: 524288 + sha256: "dcfef4b99605f872b6c3b6d05c045385cdea3d1b702906a0ed930df7bcb7deac" + validation: [size, sha256] + description: "Saturn BIOS (Japan)" + source_ref: "libretro/libretro.cpp:640, mednafen/ss/ss.cpp:1449-1450, 1507, 1520-1521" + - name: "mpr-17933.bin" + system: "sega-saturn" + region: [north-america, latin-america, brazil, south-korea, asia-pal, europe] + required: true + size: 524288 + sha256: "96e106f740ab448cf89f0dd49dfbac7fe5391cb6bd6e14ad5e3061c13330266f" + validation: [size, sha256] + description: "Saturn BIOS (North America/Europe)" + source_ref: "libretro/libretro.cpp:641, mednafen/ss/ss.cpp:1451-1452, 1509, 1520-1521" + - name: "mpr-18811-mx.ic1" + system: "sega-saturn" + required: false + description: "The King of Fighters '95 ROM cartridge" + source_ref: "mednafen/ss/ss.cpp:1348, 1404-1412, 2542" + note: "Opened only for the game that needs the cart; that game does not start without it." + - name: "mpr-19367-mx.ic1" + system: "sega-saturn" + required: false + description: "Ultraman ROM cartridge" + source_ref: "mednafen/ss/ss.cpp:1349, 1404-1412, 2543" + note: "Opened only for the game that needs the cart; that game does not start without it." + - name: "satar4mp.bin" + system: "sega-saturn" + required: false + description: "Action Replay 4M Plus firmware" + source_ref: "mednafen/ss/ss.cpp:1350, 1404-1412, 2544" + note: "Opened only when the Action Replay 4M Plus cart type is selected." diff --git a/emulators/rb5000.yml b/emulators/rb5000.yml new file mode 100644 index 00000000..d564d285 --- /dev/null +++ b/emulators/rb5000.yml @@ -0,0 +1,41 @@ +emulator: RB5000 +type: standalone + libretro +core_classification: official_port +source: + standalone: "https://gitlab.com/recalbox/packages/standalone/rb5000" + libretro: "https://gitlab.com/recalbox/packages/recalbox-cores/libretro-rb5000" +upstream: "https://gitlab.com/recalbox/packages/standalone/rb5000" +profiled_date: "2026-10-17" +source_commit: + standalone: "8c75a4b48a5222b0332d0508600f8ddc7ac1191c" + libretro: "7464996aa0cb1be77abf495dc901117e1af36e02" +core_version: + standalone: "v1.1" + libretro: "v0.9" +display_name: "Philips - VG 5000 (RB5000)" +cores: + - "rb5000" +systems: + - "philips-vg5k" + +notes: | + Philips VG 5000 emulator by Recalbox, a C++ fork of Daniel Coulom's + DCVG5K v2. The standalone build and the libretro core live in + two repositories and share the same Engine. + + The 16 KB system ROM is not a file. It is encoded in the + Video::sPixels image table compiled into the binary, one ROM bit per + entry as bit 0 XOR bit 5 (ref: source/Data.cpp:2). The Engine + constructor copies that table into sMirror (ref: source/Engine.cpp:54) + and Z80ReadW() rebuilds each ROM byte from eight table entries the + first time the CPU reads it, caching it in mMemory + (ref: source/Engine.cpp:379-389). The libretro core carries the same + table and decoder. + + The libretro core can map a user cartridge file over 0x0000-0x3FFF + when one is configured (ref: source/Engine.cpp:302-316); that file is + content. The on-screen display font is an Ubuntu TTF from the host + system fonts directory (ref: source/Video.cpp:90-92). + +exclusion_note: "VG 5000 system ROM is encoded in a compiled-in image table and decoded on first access; no file is read" +files: [] diff --git a/emulators/reicast.yml b/emulators/reicast.yml new file mode 100644 index 00000000..ee4826ed --- /dev/null +++ b/emulators/reicast.yml @@ -0,0 +1,63 @@ +emulator: Reicast +type: standalone +core_classification: community_fork +source: "https://github.com/reicast/reicast-emulator" +upstream: "https://github.com/reicast/reicast-emulator" +profiled_date: "2026-10-17" +source_commit: "ad61f95dd6b4c6218846a25de6194550311a5d28" +core_version: "Git" +display_name: "Sega - Dreamcast (Reicast)" +cores: + - "reicast" +systems: + - "sega-dreamcast" + +notes: | + Dreamcast emulator descended from nullDC. The Linux build is compiled + for one platform; the default is dreamcast, which sets the ROM prefix + dc_, a 2 MB boot ROM, a 128 KB flash and NVR_OPTIONAL 0 + (ref: core/types.h:209-217). + + LoadRomFiles() tries dc_boot.bin, dc_boot.bin.bin, dc_bios.bin and + dc_bios.bin.bin for the boot ROM, then dc_nvmem.bin, dc_flash_wb.bin, + dc_flash.bin and dc_flash.bin.bin for the flash + (ref: core/hw/holly/sb_mem.cpp:30-51). Each candidate is accepted + when a full chip's worth of bytes can be read from it + (ref: core/hw/flashrom/flashrom.h:39-49, 61-99). No hash is checked. + With NVR_OPTIONAL 0 a missing flash fails LoadRomFiles() the same way + a missing boot ROM does. + + When LoadRomFiles() fails, or the reios setting is on, the core starts + its HLE BIOS instead and loads only the flash, if present + (ref: core/nullDC.cpp:183-200, core/hw/holly/sb_mem.cpp:58-64). + + Upstream resolves the directory as /data/, the data dir + being $XDG_DATA_HOME/reicast or ~/.local/share/reicast, then each + $XDG_DATA_DIRS entry plus /reicast (ref: core/stdclass.cpp:83-100, + core/linux-dist/main.cpp:287-326, 355-379). Recalbox patches + nullDC.cpp to read and write both files in /recalbox/share/bios/dc/, + which is the path given below. + +files: + - name: "dc_boot.bin" + path: "dc/dc_boot.bin" + aliases: ["dc_boot.bin.bin", "dc_bios.bin", "dc_bios.bin.bin"] + system: "sega-dreamcast" + required: false + hle_fallback: true + min_size: 2097152 + validation: [size] + description: "Dreamcast boot ROM" + source_ref: "core/hw/holly/sb_mem.cpp:20, 30-36, core/types.h:211, 215" + note: "First of the four names that reads 2097152 bytes wins. Missing, the HLE BIOS runs." + - name: "dc_nvmem.bin" + path: "dc/dc_nvmem.bin" + aliases: ["dc_flash_wb.bin", "dc_flash.bin", "dc_flash.bin.bin"] + system: "sega-dreamcast" + required: false + hle_fallback: true + min_size: 131072 + validation: [size] + description: "Dreamcast flash memory" + source_ref: "core/hw/holly/sb_mem.cpp:22-23, 37-48, 58-64, core/types.h:212, 217" + note: "Written back as dc_nvmem.bin on exit. Missing, LoadRomFiles() fails even with a boot ROM present and the HLE BIOS runs." diff --git a/emulators/sugarbox2.yml b/emulators/sugarbox2.yml new file mode 100644 index 00000000..8d584c42 --- /dev/null +++ b/emulators/sugarbox2.yml @@ -0,0 +1,36 @@ +emulator: Sugarbox2 +type: libretro +core_classification: community_fork +source: "https://gitlab.com/recalbox/packages/recalbox-cores/libretro-sugarbox2" +upstream: "https://github.com/Tom1975/SugarboxV2" +profiled_date: "2026-10-17" +source_commit: "6b565a43a25e4dfb69867f7e927a707e15ea460f" +core_version: "v0.9" +display_name: "Amstrad - CPC / GX4000 (Sugarbox2)" +cores: + - "sugarbox2" +systems: + - "amstrad-cpc" + +notes: | + Libretro core by Recalbox wrapping Tom1975's SugarboxV2 + (CPC 464, 664, 6128, 464+, 6128+ and GX-4000). Recalbox 10.1.1 builds + tag v1.5 from a token-gated copy of this repository; the public + repository carries v0.9 only, which is the revision read here. + + Every ROM is compiled into the core as a zlib stream: OS and BASIC for + each model and language, AMSDOS, the Plus cartridge plus_en.cpr, the + CP/M Plus, FutureOS, SymbOS and utility expansion ROMs, 57 blobs in all + (ref: libretro/RomData.h:1-15). + rom_uncompress() inflates them when the machine is built + (ref: libretro/LibretroCore.cpp:1098-1107) and they are handed to the + memory map directly, never through a path + (ref: libretro/LibretroCore.cpp:1173-1174). + + The keyboard map files the engine reads are written from embedded data + into the save directory, only when missing: CONF/KeyboardMaps.ini and + Keyboards/101_keyboard_linux + (ref: libretro/LibretroCore.cpp:1477-1502, 2169-2173). + +exclusion_note: "all CPC, Plus and GX-4000 ROMs compiled into the core as zlib blobs; keyboard maps written by the core into the save directory" +files: [] diff --git a/emulators/vice_x64sc.yml b/emulators/vice_x64sc.yml index 9d96f1bb..a45aafd2 100644 --- a/emulators/vice_x64sc.yml +++ b/emulators/vice_x64sc.yml @@ -7,7 +7,7 @@ profiled_date: "2026-03-25" source_commit: "f63b56688f3133a2bb17499db9eebb7ab81df5f5" core_version: "3.10" display_name: "Commodore - C64 (VICE x64sc, accurate)" -cores: [vice_x64sc] +cores: [vice_x64sc, "x64sx"] systems: [commodore-c64] notes: > Cycle-accurate C64 emulator using the viciisc VIC-II implementation. diff --git a/emulators/vvvvvv.yml b/emulators/vvvvvv.yml new file mode 100644 index 00000000..26cbf29b --- /dev/null +++ b/emulators/vvvvvv.yml @@ -0,0 +1,50 @@ +emulator: VVVVVV +type: standalone +core_classification: game_engine +source: "https://github.com/TerryCavanagh/VVVVVV" +upstream: "https://github.com/TerryCavanagh/VVVVVV" +profiled_date: "2026-10-17" +source_commit: "a0bd2f3da42da2f5249e2a4892e2b48b51b2fd86" +core_version: "v2.5" +display_name: "VVVVVV" +cores: + - "vvvvvv" +systems: + - "vvvvvv" + +notes: | + Terry Cavanagh's VVVVVV game, desktop build. The source release holds + the engine, the level data, the language files and the fonts; graphics, + music and sounds are in data.zip, which is not in the repository. + + FILESYSTEM_init() mounts data.zip from the -assets argument, or from + the binary's directory when no argument is given, and exits with a + "data.zip missing!" message box when the mount fails + (ref: desktop_version/src/FileSystemUtils.cpp:318-346). Recalbox + passes -assets /recalbox/share/roms/ports/vvvvvv/data.zip. The game + accepts the data.zip of the retail release or of the free Make and + Play Edition (ref: desktop_version/src/FileSystemUtils.cpp:332-335). + + The lang/ and fonts/ directories are mounted ahead of data.zip from + the binary's directory (ref: desktop_version/src/FileSystemUtils.cpp:81-177, + 312-315); Recalbox installs them from the source tree beside the + binary. gamecontrollerdb.txt is read from the binary's directory when + present (ref: desktop_version/src/FileSystemUtils.cpp:349-353). + +files: + - name: "data.zip" + system: "vvvvvv" + category: game_data + path: "data.zip" + required: true + unsourceable: "game data the collection does not hold; a same-named archive of another game must not stand in" + description: "VVVVVV game assets (graphics, music, sounds)" + source_ref: "desktop_version/src/FileSystemUtils.cpp:318-346, desktop_version/src/main.cpp:433-438" + note: "Path given by -assets, otherwise data.zip next to the binary. Retail and Make and Play Edition archives are both accepted; the code checks neither size nor hash." + - name: "gamecontrollerdb.txt" + system: "vvvvvv" + path: "gamecontrollerdb.txt" + required: false + description: "SDL game controller mappings" + source_ref: "desktop_version/src/FileSystemUtils.cpp:349-353" + note: "Read from the binary's directory; a missing file is logged and ignored." diff --git a/platforms/_registry.yml b/platforms/_registry.yml index c1def9da..c859ba68 100644 --- a/platforms/_registry.yml +++ b/platforms/_registry.yml @@ -211,8 +211,8 @@ platforms: # Bios.cpp:64-68 hashes a .zip with Zip::Md5Composite, never its bytes zip_digest: composite schedule: monthly - target_scraper: null - target_source: null + target_scraper: recalbox_targets + target_source: https://gitlab.com/recalbox/recalbox/-/tree/master/configs install: detect: - os: linux diff --git a/platforms/targets/_overrides.yml b/platforms/targets/_overrides.yml index dec39866..43968547 100644 --- a/platforms/targets/_overrides.yml +++ b/platforms/targets/_overrides.yml @@ -128,3 +128,27 @@ rocknix: - wine amd64: aliases: [x86_64, pc] + +recalbox: + targets: + _default: + # system.ini names a mupen64plus video plugin as the core of the + # mupen64plus emulator; mupenGenerator.py loads it with --gfx + # mupen64plus-video-.so. Plugins, not emulators. + remove_cores: + - glide64mk2 # mupen64plus-video-glide64mk2 + - gliden64 # GLideN64 video plugin + - n64_gles2 # mupen64plus-video-gles2n64 + - rice # mupen64plus-video-rice + - rice_gles2 # mupen64plus-video-gles2rice + # Recalbox names its boards by defconfig (configs/recalbox-_defconfig). + rpi3: + aliases: [rpi3b] + rpi4_64: + aliases: [rpi4, rpi400] + rpi5_64: + aliases: [rpi5] + rpizero2: + aliases: [rpi-zero2] + x86_64: + aliases: [pc] diff --git a/platforms/targets/recalbox.yml b/platforms/targets/recalbox.yml new file mode 100644 index 00000000..29785233 --- /dev/null +++ b/platforms/targets/recalbox.yml @@ -0,0 +1,1204 @@ +platform: recalbox +source: https://gitlab.com/recalbox/recalbox/-/tree/10.1.1/configs +scraped_at: '2026-10-17T13:18:19Z' +targets: + odroidgo2: + architecture: aarch64 + cores: + - '2048' + - '81' + - a5200 + - advancemame + - amiberry + - applewin + - arduous + - atari800 + - b2 + - beebem + - bk + - bluemsx + - cannonball + - cap32 + - crocods + - daphne + - dice + - dinothawr + - dirksimple + - dosbox + - dosbox_pure + - duckstation + - easyrpg + - ecwolf + - eightyone + - emuscv + - exel-hence + - fake08 + - fbneo + - fceumm + - flycast + - fmsx + - freechaf + - freeintv + - frotz + - fuse + - gambatte + - gearcoleco + - geargrafx + - gearsystem + - genesisplusgx + - genesisplusgx_ex + - genesisplusgxwide + - geolith + - glide64mk2 + - gong + - gpsp + - gsplus + - gw + - handy + - hatari + - hatarib + - holani + - hypseus_singe + - imageviewer + - julius + - lowresnx + - lutro + - m2000 + - mame2003 + - mame2003_plus + - mame2010 + - mame2015 + - mednafen_lynx + - mednafen_ngp + - mednafen_pce_fast + - mednafen_supergrafx + - mednafen_vb + - mednafen_wswan + - mesen + - mesen_s + - meteor + - mgba + - minivmac + - mojozork + - mrboom + - mu + - mupen64plus + - mupen64plus_next + - neocd + - nestopia + - np2kai + - nxengine + - o2em + - openbor + - opera + - oricutron + - parallel_n64 + - pcsx_rearmed + - pd777 + - pico8 + - picodrive + - pokemini + - potator + - ppsspp + - prboom + - prosystem + - puae + - puae2021 + - px68k + - quasi88 + - quicknes + - race + - rb5000 + - reminiscence + - retro8 + - rice + - sameboy + - sameduck + - scummvm + - sdlpop + - simcoupe + - snes9x + - snes9x2002 + - snes9x2005 + - snes9x2010 + - solarus + - stella + - stella2014 + - sugarbox2 + - swanstation + - tamalibretro + - tgbdual + - theodore + - thepowdertoy + - ti99sim + - tic80 + - tyrquake + - uae4arm + - uzem + - vecx + - vice + - vice_x128 + - vice_x64 + - vice_x64sc + - vice_xcbm2 + - vice_xcbm5x0 + - vice_xpet + - vice_xplus4 + - vice_xscpu64 + - vice_xvic + - vircon32 + - vitaquake2 + - vvvvvv + - wasm4 + - x1 + - x128 + - x64 + - x64sx + - xcbm2 + - xcbm5x0 + - xpet + - xplus4 + - xrick + - xroar + - xscpu64 + - xvic + - yabasanshiro + rg353x: + architecture: aarch64 + cores: + - '2048' + - '81' + - a5200 + - advancemame + - amiberry + - applewin + - arduous + - atari800 + - b2 + - beebem + - bk + - bluemsx + - bsnes + - bsneshd + - cannonball + - cap32 + - cdi2015 + - crocods + - daphne + - dice + - dinothawr + - dirksimple + - dosbox + - dosbox_pure + - duckstation + - easyrpg + - ecwolf + - eightyone + - emuscv + - exel-hence + - fake08 + - fbneo + - fceumm + - flycast + - fmsx + - freechaf + - freeintv + - frotz + - fuse + - gambatte + - gearcoleco + - geargrafx + - gearsystem + - genesisplusgx + - genesisplusgx_ex + - genesisplusgxwide + - geolith + - glide64mk2 + - gong + - gpsp + - gsplus + - gw + - handy + - hatari + - hatarib + - holani + - hypseus_singe + - imageviewer + - julius + - lowresnx + - lutro + - m2000 + - mame2003 + - mame2003_plus + - mame2010 + - mame2015 + - mednafen_lynx + - mednafen_ngp + - mednafen_pce_fast + - mednafen_pcfx + - mednafen_psx + - mednafen_supafaust + - mednafen_supergrafx + - mednafen_vb + - mednafen_wswan + - mesen + - mesen_s + - meteor + - mgba + - minivmac + - mojozork + - mrboom + - mu + - mupen64plus + - mupen64plus_next + - neocd + - nestopia + - np2kai + - nxengine + - o2em + - openbor + - opera + - oricutron + - parallel_n64 + - pcsx_rearmed + - pd777 + - pico8 + - picodrive + - pokemini + - potator + - ppsspp + - prboom + - prosystem + - puae + - puae2021 + - px68k + - quasi88 + - quicknes + - race + - rb5000 + - reminiscence + - retro8 + - rice + - sameboy + - sameduck + - scummvm + - sdlpop + - simcoupe + - snes9x + - snes9x2002 + - snes9x2005 + - snes9x2010 + - solarus + - stella + - stella2014 + - sugarbox2 + - swanstation + - tamalibretro + - tgbdual + - theodore + - thepowdertoy + - ti99sim + - tic80 + - tyrquake + - uae4arm + - uzem + - vecx + - vice + - vice_x128 + - vice_x64 + - vice_x64sc + - vice_xcbm2 + - vice_xcbm5x0 + - vice_xpet + - vice_xplus4 + - vice_xscpu64 + - vice_xvic + - vircon32 + - virtualjaguar + - vitaquake2 + - vvvvvv + - wasm4 + - x1 + - x128 + - x64 + - x64sx + - xcbm2 + - xcbm5x0 + - xpet + - xplus4 + - xrick + - xroar + - xscpu64 + - xvic + - yabasanshiro + - ymir + rpi3: + architecture: armhf + cores: + - '2048' + - '81' + - a5200 + - advancemame + - amiberry + - applewin + - arduous + - atari800 + - b2 + - beebem + - bk + - bluemsx + - cannonball + - cap32 + - crocods + - daphne + - dice + - dinothawr + - dirksimple + - dosbox + - dosbox_pure + - duckstation + - easyrpg + - ecwolf + - eightyone + - emuscv + - exel-hence + - fake08 + - fbneo + - fceumm + - flycast + - flycast-next + - fmsx + - freechaf + - freeintv + - frotz + - fuse + - gambatte + - gearcoleco + - geargrafx + - gearsystem + - genesisplusgx + - genesisplusgxwide + - geolith + - glide64mk2 + - gliden64 + - gong + - gpsp + - gsplus + - gw + - handy + - hatari + - hatarib + - holani + - hypseus_singe + - imageviewer + - julius + - lowresnx + - lutro + - m2000 + - mame2000 + - mame2003 + - mame2003_plus + - mame2010 + - mame2015 + - mednafen_lynx + - mednafen_ngp + - mednafen_pce_fast + - mednafen_supafaust + - mednafen_supergrafx + - mednafen_vb + - mednafen_wswan + - meteor + - mgba + - minivmac + - mojozork + - moonlight + - mrboom + - mu + - mupen64plus + - mupen64plus_next + - n64_gles2 + - neocd + - nestopia + - np2kai + - nxengine + - o2em + - openbor + - opera + - oricutron + - parallel_n64 + - pcsx_rearmed + - pd777 + - pico8 + - picodrive + - pokemini + - potator + - ppsspp + - prboom + - prosystem + - puae + - puae2021 + - px68k + - quasi88 + - quicknes + - race + - rb5000 + - reicast + - reminiscence + - retro8 + - rice + - rice_gles2 + - sameboy + - sameduck + - scummvm + - sdlpop + - simcoupe + - snes9x + - snes9x2005 + - snes9x2010 + - solarus + - stella + - stella2014 + - sugarbox2 + - swanstation + - tamalibretro + - tgbdual + - theodore + - thepowdertoy + - ti99sim + - tic80 + - tyrquake + - uae4arm + - uzem + - vecx + - vice + - vice_x128 + - vice_x64 + - vice_x64sc + - vice_xcbm2 + - vice_xcbm5x0 + - vice_xpet + - vice_xplus4 + - vice_xscpu64 + - vice_xvic + - vircon32 + - vvvvvv + - wasm4 + - x1 + - x128 + - x64 + - x64sx + - xcbm2 + - xcbm5x0 + - xpet + - xplus4 + - xrick + - xroar + - xscpu64 + - xvic + rpi4_64: + architecture: aarch64 + cores: + - '2048' + - '81' + - a5200 + - advancemame + - amiberry + - applewin + - arduous + - atari800 + - b2 + - beebem + - bk + - bluemsx + - bsnes + - bsneshd + - cannonball + - cap32 + - cdi2015 + - corsixth + - crocods + - daphne + - dice + - dinothawr + - dirksimple + - dosbox + - dosbox_pure + - duckstation + - easyrpg + - ecwolf + - eightyone + - emuscv + - exel-hence + - fake08 + - fbneo + - fceumm + - flycast + - flycast-next + - fmsx + - freechaf + - freeintv + - frotz + - fuse + - gambatte + - gearcoleco + - geargrafx + - gearsystem + - genesisplusgx + - genesisplusgx_ex + - genesisplusgxwide + - geolith + - glide64mk2 + - gong + - gpsp + - gsplus + - gw + - handy + - hatari + - hatarib + - holani + - hypseus_singe + - imageviewer + - julius + - lowresnx + - lutro + - m2000 + - mame0258 + - mame0278 + - mame2003 + - mame2003_plus + - mame2010 + - mame2015 + - mednafen_lynx + - mednafen_ngp + - mednafen_pce_fast + - mednafen_pcfx + - mednafen_psx + - mednafen_saturn + - mednafen_supafaust + - mednafen_supergrafx + - mednafen_vb + - mednafen_wswan + - melonds + - mesen + - mesen_s + - meteor + - mgba + - minivmac + - mojozork + - moonlight + - mrboom + - mu + - mupen64plus + - mupen64plus_next + - neocd + - nestopia + - np2kai + - nxengine + - o2em + - openbor + - opera + - oricutron + - parallel_n64 + - pcsx_rearmed + - pd777 + - pico8 + - picodrive + - pokemini + - potator + - ppsspp + - prboom + - prosystem + - puae + - puae2021 + - px68k + - quasi88 + - quicknes + - race + - rb5000 + - reminiscence + - retro8 + - rice + - sameboy + - sameduck + - scummvm + - sdlpop + - simcoupe + - snes9x + - snes9x2002 + - snes9x2005 + - snes9x2010 + - solarus + - stella + - stella2014 + - sugarbox2 + - swanstation + - tamalibretro + - tgbdual + - theodore + - thepowdertoy + - ti99sim + - tic80 + - tyrquake + - uae4arm + - uzem + - vecx + - vice + - vice_x128 + - vice_x64 + - vice_x64sc + - vice_xcbm2 + - vice_xcbm5x0 + - vice_xpet + - vice_xplus4 + - vice_xscpu64 + - vice_xvic + - vircon32 + - virtualjaguar + - vitaquake2 + - vvvvvv + - wasm4 + - x1 + - x128 + - x64 + - x64sx + - xcbm2 + - xcbm5x0 + - xpet + - xplus4 + - xrick + - xroar + - xscpu64 + - xvic + - yabasanshiro + - ymir + rpi5_64: + architecture: aarch64 + cores: + - '2048' + - '81' + - a5200 + - amiberry + - applewin + - arduous + - atari800 + - b2 + - beebem + - bk + - bluemsx + - bsnes + - bsneshd + - cannonball + - cap32 + - cdi2015 + - corsixth + - craft + - crocods + - daphne + - dice + - dinothawr + - dirksimple + - dolphin + - dolphin-gui + - dosbox + - dosbox_pure + - duckstation + - easyrpg + - ecwolf + - eightyone + - emuscv + - exel-hence + - fake08 + - fbneo + - fceumm + - flycast + - flycast-next + - fmsx + - freechaf + - freeintv + - frotz + - fuse + - gambatte + - gearcoleco + - geargrafx + - gearsystem + - genesisplusgx + - genesisplusgx_ex + - genesisplusgxwide + - geolith + - glide64mk2 + - gong + - gpsp + - gsplus + - gw + - handy + - hatari + - hatarib + - holani + - hypseus_singe + - imageviewer + - julius + - lowresnx + - lutro + - m2000 + - mame0258 + - mame0278 + - mame2003_plus + - mednafen_lynx + - mednafen_ngp + - mednafen_pce_fast + - mednafen_pcfx + - mednafen_psx + - mednafen_saturn + - mednafen_stv + - mednafen_supafaust + - mednafen_supergrafx + - mednafen_vb + - mednafen_wswan + - melonds + - mesen + - mesen_s + - meteor + - mgba + - minivmac + - mojozork + - moonlight + - mrboom + - mu + - mupen64plus + - mupen64plus_next + - neocd + - nestopia + - np2kai + - nxengine + - o2em + - openbor + - openlara + - opera + - oricutron + - parallel_n64 + - pcsx_rearmed + - pd777 + - pico8 + - picodrive + - pokemini + - potator + - ppsspp + - prboom + - prosystem + - puae + - px68k + - quasi88 + - quicknes + - race + - rb5000 + - reminiscence + - retro8 + - rice + - sameboy + - sameduck + - scummvm + - sdlpop + - simcoupe + - snes9x + - snes9x2002 + - snes9x2005 + - snes9x2010 + - solarus + - stella + - stella2014 + - sugarbox2 + - supermodel + - swanstation + - tamalibretro + - tgbdual + - theodore + - thepowdertoy + - ti99sim + - tic80 + - tyrquake + - uae4arm + - uzem + - vecx + - vice + - vice_x128 + - vice_x64 + - vice_x64sc + - vice_xcbm2 + - vice_xcbm5x0 + - vice_xpet + - vice_xplus4 + - vice_xscpu64 + - vice_xvic + - vircon32 + - virtualjaguar + - vitaquake2 + - vpinball + - vvvvvv + - wasm4 + - x1 + - x128 + - x64 + - x64sx + - xcbm2 + - xcbm5x0 + - xpet + - xplus4 + - xrick + - xroar + - xscpu64 + - xvic + - yabasanshiro + - ymir + rpizero2: + architecture: armhf + cores: + - '2048' + - '81' + - a5200 + - advancemame + - amiberry + - applewin + - arduous + - atari800 + - b2 + - beebem + - bk + - bluemsx + - cannonball + - cap32 + - crocods + - daphne + - dice + - dinothawr + - dirksimple + - dosbox + - dosbox_pure + - duckstation + - easyrpg + - ecwolf + - eightyone + - emuscv + - exel-hence + - fake08 + - fbneo + - fceumm + - flycast + - flycast-next + - fmsx + - freechaf + - freeintv + - frotz + - fuse + - gambatte + - gearcoleco + - geargrafx + - gearsystem + - genesisplusgx + - genesisplusgxwide + - geolith + - glide64mk2 + - gliden64 + - gong + - gpsp + - gsplus + - gw + - handy + - hatari + - hatarib + - holani + - hypseus_singe + - imageviewer + - julius + - lowresnx + - lutro + - m2000 + - mame2000 + - mame2003 + - mame2003_plus + - mame2010 + - mame2015 + - mednafen_lynx + - mednafen_ngp + - mednafen_pce_fast + - mednafen_supafaust + - mednafen_supergrafx + - mednafen_vb + - mednafen_wswan + - meteor + - mgba + - mojozork + - moonlight + - mrboom + - mu + - mupen64plus + - mupen64plus_next + - n64_gles2 + - neocd + - nestopia + - np2kai + - nxengine + - o2em + - openbor + - opera + - oricutron + - parallel_n64 + - pcsx_rearmed + - pd777 + - pico8 + - picodrive + - pokemini + - potator + - ppsspp + - prboom + - prosystem + - puae + - puae2021 + - px68k + - quasi88 + - quicknes + - race + - rb5000 + - reicast + - reminiscence + - retro8 + - rice + - rice_gles2 + - sameboy + - sameduck + - scummvm + - sdlpop + - simcoupe + - snes9x + - snes9x2005 + - snes9x2010 + - solarus + - stella + - stella2014 + - sugarbox2 + - swanstation + - tamalibretro + - tgbdual + - theodore + - thepowdertoy + - ti99sim + - tic80 + - tyrquake + - uae4arm + - uzem + - vecx + - vice + - vice_x128 + - vice_x64 + - vice_x64sc + - vice_xcbm2 + - vice_xcbm5x0 + - vice_xpet + - vice_xplus4 + - vice_xscpu64 + - vice_xvic + - vircon32 + - vvvvvv + - wasm4 + - x1 + - x128 + - x64 + - x64sx + - xcbm2 + - xcbm5x0 + - xpet + - xplus4 + - xrick + - xroar + - xscpu64 + - xvic + x86_64: + architecture: x86_64 + cores: + - '2048' + - '81' + - a5200 + - amiberry + - applewin + - arduous + - atari800 + - b2 + - beebem + - bk + - bluemsx + - boom3 + - bsnes + - bsneshd + - cannonball + - cap32 + - cdi2015 + - corsixth + - craft + - crocods + - daphne + - desmume + - dice + - dinothawr + - dirksimple + - dolphin + - dolphin-gui + - dosbox + - dosbox_pure + - duckstation + - easyrpg + - ecwolf + - eightyone + - emuscv + - exel-hence + - fake08 + - fbneo + - fceumm + - flycast + - flycast-next + - fmsx + - freechaf + - freeintv + - frotz + - fuse + - gambatte + - gearcoleco + - geargrafx + - gearsystem + - genesisplusgx + - genesisplusgx_ex + - genesisplusgxwide + - geolith + - glide64mk2 + - gong + - gpsp + - gsplus + - gw + - handy + - hatari + - hatarib + - holani + - hypseus_singe + - imageviewer + - julius + - kronos + - lowresnx + - lutro + - m2000 + - mame0258 + - mame0278 + - mame2003 + - mame2003_plus + - mame2010 + - mame2015 + - mednafen_lynx + - mednafen_ngp + - mednafen_pce_fast + - mednafen_pcfx + - mednafen_psx + - mednafen_psx_hw + - mednafen_saturn + - mednafen_stv + - mednafen_supafaust + - mednafen_supergrafx + - mednafen_vb + - mednafen_wswan + - melonds + - mesen + - mesen_s + - meteor + - mgba + - minivmac + - mojozork + - moonlight + - mrboom + - mu + - mupen64plus + - mupen64plus_next + - neocd + - nestopia + - np2kai + - nxengine + - o2em + - openbor + - openlara + - opera + - oricutron + - parallel_n64 + - pcsx2 + - pcsx_rearmed + - pd777 + - pico8 + - picodrive + - pokemini + - potator + - ppsspp + - prboom + - prosystem + - ps2 + - puae + - px68k + - quasi88 + - quicknes + - race + - rb5000 + - reminiscence + - retro8 + - rice + - same_cdi + - sameboy + - sameduck + - scummvm + - sdlpop + - simcoupe + - snes9x + - snes9x2002 + - snes9x2005 + - snes9x2010 + - solarus + - stella + - stella2014 + - sugarbox2 + - supermodel + - swanstation + - tamalibretro + - tgbdual + - theodore + - thepowdertoy + - ti99sim + - tic80 + - tyrquake + - uzem + - vecx + - vice + - vice_x128 + - vice_x64 + - vice_x64sc + - vice_xcbm2 + - vice_xcbm5x0 + - vice_xpet + - vice_xplus4 + - vice_xscpu64 + - vice_xvic + - vircon32 + - virtualjaguar + - vitaquake2 + - vitaquake3 + - vitavoyager + - vpinball + - vvvvvv + - wasm4 + - x1 + - x128 + - x64 + - x64sx + - xcbm2 + - xcbm5x0 + - xemu + - xpet + - xplus4 + - xrick + - xroar + - xscpu64 + - xvic + - yabasanshiro + - yabause + - ymir diff --git a/scripts/scraper/recalbox_scraper.py b/scripts/scraper/recalbox_scraper.py index 4d7e21b0..e7a3fa26 100644 --- a/scripts/scraper/recalbox_scraper.py +++ b/scripts/scraper/recalbox_scraper.py @@ -117,18 +117,14 @@ BLOBS_QUERY = ( BLOBS_PER_QUERY = 50 -def system_ini_cores(text: str) -> tuple[set[str], set[str]]: - """The cores one Recalbox system.ini offers, and those run standalone. +def _ini_sections(text: str) -> dict[str, dict[str, str]]: + """Sections and their key = value lines of one Recalbox system.ini. - Each ``[core.N]`` section (or its board override ``[core.N.]``) - names an ``emulator`` and a ``core``: ``libretro`` with the core's name, - or a standalone emulator. es_bios.xml only names the cores that need a - BIOS, so read alone it left most of Recalbox's cores outside the pack. + Recalbox's .ini files are not strict INI (a value can run on a bare + line), so only sections and key = value lines are read. """ import re - # Recalbox's .ini files are not strict INI (a value can run on a bare - # line), so only sections and key = value lines are read. sections: dict[str, dict[str, str]] = {} current: dict[str, str] | None = None for raw in text.splitlines(): @@ -142,25 +138,64 @@ def system_ini_cores(text: str) -> tuple[set[str], set[str]]: if current is not None and "=" in line: key, value = line.split("=", 1) current[key.strip()] = value.strip().strip('"') + return sections + + +def _core_names(values: dict[str, str]) -> tuple[set[str], set[str]]: + """(cores, standalone) one [core.N] section names.""" + emulator = values.get("emulator", "") + core = values.get("core", "") + if emulator == "libretro": + return ({core} if core else set()), set() + if not emulator: + return set(), set() + names = {emulator} | ({core} if core and core != emulator else set()) + return names, set(names) + + +def system_ini_cores(text: str) -> tuple[set[str], set[str]]: + """The cores one Recalbox system.ini offers, and those run standalone. + + Each ``[core.N]`` section (or its board override ``[core.N.]``) + names an ``emulator`` and a ``core``: ``libretro`` with the core's name, + or a standalone emulator. es_bios.xml only names the cores that need a + BIOS, so read alone it left most of Recalbox's cores outside the pack. + """ + import re + cores: set[str] = set() standalone: set[str] = set() - for section, values in sections.items(): + for section, values in _ini_sections(text).items(): if not re.fullmatch(r"core\.\d+(\.[\w-]+)?", section): continue - emulator = values.get("emulator", "") - core = values.get("core", "") - if emulator == "libretro": - if core: - cores.add(core) - elif emulator: - cores.add(emulator) - standalone.add(emulator) - if core and core != emulator: - cores.add(core) - standalone.add(core) + found, alone = _core_names(values) + cores |= found + standalone |= alone return cores, standalone +def board_cores(text: str, board: str, enabled: set[str]) -> set[str]: + """The cores of one system.ini a board's image builds. + + A core is built when the Buildroot package its section names is enabled + in the board's defconfig. ``[core.N.]`` replaces the section on + that board and ``package.`` its package. + """ + import re + + sections = _ini_sections(text) + cores: set[str] = set() + for section, values in sections.items(): + match = re.fullmatch(r"core\.(\d+)", section) + if not match: + continue + values = sections.get(f"{section}.{board}", values) + package = values.get(f"package.{board}", values.get("package", "")) + if package in enabled: + cores |= _core_names(values)[0] + return cores + + class Scraper(BaseScraper): """Scraper for Recalbox es_bios.xml.""" diff --git a/scripts/scraper/targets/recalbox_targets_scraper.py b/scripts/scraper/targets/recalbox_targets_scraper.py new file mode 100644 index 00000000..5382848a --- /dev/null +++ b/scripts/scraper/targets/recalbox_targets_scraper.py @@ -0,0 +1,126 @@ +"""Scraper for Recalbox per-board emulator availability. + +Sources (recalbox/recalbox on GitLab, at the tag platforms/recalbox.yml names): + - configs/recalbox-_defconfig -- the Buildroot packages each image + enables, one `BR2_PACKAGE_=y` line per emulator package + - package/recalbox-romfs2/systems//system.ini -- the cores of each + system, each `[core.N]` naming the package that builds it, with board + overrides (`package.`, `[core.N.]`) + +Recalbox runs on Raspberry Pi 3 to 5, two handhelds and x86_64: without a +target list, a Pi 3 pack carried the firmware of emulators only x86_64 builds. +""" + +from __future__ import annotations + +import argparse +import json +import re +import sys +from datetime import datetime, timezone + +import yaml + +from . import BaseTargetScraper + +PLATFORM_NAME = "recalbox" + +CONFIGS_TREE_URL = ( + "https://gitlab.com/api/v4/projects/recalbox%2Frecalbox/repository/tree" + "?path=configs&ref={tag}&per_page=100" +) +DEFCONFIG_URL = "https://gitlab.com/recalbox/recalbox/-/raw/{tag}/configs/{name}" +_DEFCONFIG_RE = re.compile(r"^recalbox-(\w+)_defconfig$") +_ENABLED_RE = re.compile(r"^(BR2_PACKAGE_\w+)=y\s*$", re.MULTILINE) + +try: + from ..base_scraper import fetch_bytes + from ..recalbox_scraper import SYSTEMS_TREE_URL, Scraper as PlatformScraper, board_cores +except ImportError: + from scraper.base_scraper import fetch_bytes + from scraper.recalbox_scraper import SYSTEMS_TREE_URL, Scraper as PlatformScraper, board_cores + + +def enabled_packages(defconfig: str) -> set[str]: + """The Buildroot packages a defconfig turns on.""" + return set(_ENABLED_RE.findall(defconfig)) + + +def defconfig_arch(defconfig: str) -> str: + """The architecture a defconfig builds for, from its Buildroot arch symbol.""" + for symbol, arch in (("BR2_x86_64", "x86_64"), ("BR2_aarch64", "aarch64"), + ("BR2_arm", "armhf")): + if re.search(rf"^{symbol}=y\s*$", defconfig, re.MULTILINE): + return arch + raise RuntimeError("defconfig names no BR2_x86_64, BR2_aarch64 or BR2_arm") + + +class Scraper(BaseTargetScraper): + """Per-board core lists from Recalbox's defconfigs and system.ini files.""" + + def __init__(self, url: str = "https://gitlab.com/recalbox/recalbox"): + super().__init__(url=url) + + def fetch_targets(self) -> dict: + platform = PlatformScraper() + tag = platform.tag + listing = json.loads(fetch_bytes(CONFIGS_TREE_URL.format(tag=tag))) + boards = { + match.group(1): item["name"] + for item in listing + if (match := _DEFCONFIG_RE.match(item.get("name", ""))) + } + if not boards: + raise RuntimeError(f"no recalbox-*_defconfig in configs/ at {tag}") + + systems: list[str] = [] + page = 1 + while True: + entries = json.loads(fetch_bytes(SYSTEMS_TREE_URL.format(tag=tag, page=page))) + systems += [e["name"] for e in entries + if e.get("type") == "tree" and not e["name"].startswith(".")] + if len(entries) < 100: + break + page += 1 + inis = platform._system_inis(systems) + + targets: dict[str, dict] = {} + for board, name in sorted(boards.items()): + defconfig = fetch_bytes(DEFCONFIG_URL.format(tag=tag, name=name)).decode("utf-8") + enabled = enabled_packages(defconfig) + cores: set[str] = set() + for text in inis: + cores |= board_cores(text, board, enabled) + arch = defconfig_arch(defconfig) + targets[board] = {"architecture": arch, "cores": sorted(cores)} + print(f" {board} ({arch}): {len(cores)} cores", file=sys.stderr) + + return { + "platform": PLATFORM_NAME, + "source": f"{self.url}/-/tree/{tag}/configs", + "scraped_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), + "targets": targets, + } + + +def main() -> None: + parser = argparse.ArgumentParser(description="Scrape Recalbox per-board cores") + parser.add_argument("--dry-run", action="store_true", help="Show target summary") + parser.add_argument("--output", "-o", help="Output YAML file") + args = parser.parse_args() + + scraper = Scraper() + data = scraper.fetch_targets() + if args.dry_run: + for name, info in data["targets"].items(): + print(f" {name} ({info['architecture']}): {len(info['cores'])} cores") + return + if args.output: + scraper.write_output(data, args.output) + print(f"Written to {args.output}") + return + print(yaml.dump(data, default_flow_style=False, sort_keys=False)) + + +if __name__ == "__main__": + main() diff --git a/tests/test_target_scrapers.py b/tests/test_target_scrapers.py index 15a0bbe8..5ec4c0a6 100644 --- a/tests/test_target_scrapers.py +++ b/tests/test_target_scrapers.py @@ -233,6 +233,40 @@ class RocknixPerDevice(unittest.TestCase): ["ecwolf-lr", "prboom-lr", "vitaquake3-lr"]) +class RecalboxPerBoard(unittest.TestCase): + """Recalbox had no target list: a Raspberry Pi 3 pack carried the + firmware of emulators only its x86_64 image builds.""" + + SYSTEM_INI = ( + "[core.0]\npackage = BR2_PACKAGE_PCSX2\nemulator = \"pcsx2\"\ncore = \"pcsx2\"\n" + "[core.1]\npackage = BR2_PACKAGE_LIBRETRO_PCSX_REARMED\nemulator = \"libretro\"\n" + "core = \"pcsx_rearmed\"\npackage.rpi3 = BR2_PACKAGE_LIBRETRO_PCSX_REARMED_NEON\n" + "[core.2]\npackage = BR2_PACKAGE_LIBRETRO_SWANSTATION\nemulator = \"libretro\"\n" + "core = \"swanstation\"\n" + "[core.2.rpi3]\npackage = BR2_PACKAGE_LIBRETRO_DUCKSTATION\nemulator = \"libretro\"\n" + "core = \"duckstation\"\n" + ) + + def test_a_board_gets_the_cores_its_defconfig_builds(self): + from scraper.recalbox_scraper import board_cores # noqa: PLC0415 + from scraper.targets.recalbox_targets_scraper import ( # noqa: PLC0415 + defconfig_arch, + enabled_packages, + ) + + x86 = enabled_packages("BR2_x86_64=y\nBR2_PACKAGE_PCSX2=y\n" + "BR2_PACKAGE_LIBRETRO_PCSX_REARMED=y\n" + "BR2_PACKAGE_LIBRETRO_SWANSTATION=y\n# BR2_PACKAGE_X is not set\n") + self.assertEqual(board_cores(self.SYSTEM_INI, "x86_64", x86), + {"pcsx2", "pcsx_rearmed", "swanstation"}) + rpi3 = enabled_packages("BR2_arm=y\nBR2_PACKAGE_LIBRETRO_PCSX_REARMED_NEON=y\n" + "BR2_PACKAGE_LIBRETRO_DUCKSTATION=y\n") + self.assertEqual(board_cores(self.SYSTEM_INI, "rpi3", rpi3), + {"pcsx_rearmed", "duckstation"}) + self.assertEqual(defconfig_arch("BR2_arm=y\n"), "armhf") + self.assertEqual(defconfig_arch("BR2_aarch64=y\n"), "aarch64") + + class RetroPieModuleFlags(unittest.TestCase): """The RetroPie target list read flags as requirements and libretro alone.