fix: place openmsx system ROMs through filepool

openMSX reads share/systemroms below OPENMSX_HOME or ~/.openMSX and
every filepool entry by SHA1. The profile paths drop RetroBat's
openmsx/ prefix and declare those directories and the filepool.

Batocera's config_directories reads the filepool lines its generator
writes, KNULLI reuses it. RetroBat records OPENMSX_HOME, RetroPie the
moveConfigDir of ~/.openMSX that its systemroms link lies in, and the
configure --prefix of xroar that its roms link lies in.

Batocera and KNULLI system ROMs move from openmsx/share/systemroms to
openmsx/, beside the files their own lists declare, RetroPie's to
BIOS/openmsx, the folder linked as share/systemroms.
This commit is contained in:
Abdessamad Derraz committed 2026-11-09 19:32:00 +01:00
1 parent cd38b9ed10
commit e6dbbe69ed
13 files changed
+394 -60

No files matched your search

+45 -38
View File
@@ -1,5 +1,6 @@
emulator: openMSX
type: standalone
core_classification: other
source: "https://github.com/openMSX/openMSX"
upstream: "https://github.com/openMSX/openMSX"
profiled_date: "2026-03-26"
@@ -22,6 +23,11 @@ systems:
- msxturbor
- colecovision
- spectravideo
standalone_directories:
- "OPENMSX_HOME"
- "~/.openMSX"
standalone_pools:
filepool: "share/systemroms"
notes: |
Standalone MSX emulator supporting MSX1 through turboR, ColecoVision,
@@ -35,13 +41,14 @@ notes: |
looked up beside the machine's XML (src/memory/Rom.cc:121-170,
src/config/HardwareConfig.cc:279-280, src/file/FileContext.cc:152-156).
Files may be gzipped or individually zipped.
Each user data directory contributes share/systemroms, scanned
recursively (src/file/FilePool.cc:27, src/file/FilePoolCore.cc:369-385). RetroBat
sets OPENMSX_HOME to bios/openmsx and refuses to start a machine whose
ROMs are not in bios/openmsx/share/systemroms. RetroPie links
share/systemroms to BIOS/openmsx and Batocera adds bios/openmsx to the
pool, both scanned recursively, so openmsx/share/systemroms serves all
three.
The user directory is $OPENMSX_HOME, else ~/.openMSX, and its share/
subfolder is the user data directory unless $OPENMSX_USER_DATA names
another (src/file/FileOperations.cc:415-448). The pool starts with
systemroms below the user and the system data directories
(src/file/FilePool.cc:21-33), and each `filepool add -types system_rom`
entry is searched the same way, recursively, until a file of the SHA1 is
found (src/file/FilePool.cc:98-142, src/file/FilePoolCore.cc:244-264,
369-385).
Batocera configgen (openmsxGenerator.py) configures filepool paths
(/userdata/bios/Machines position 1, /userdata/bios/openmsx position 2)
@@ -67,7 +74,7 @@ files:
# Based on Philips NMS 8245 with extra hardware
# -------------------------------------------------------
- name: NMS8245SystemROM1.08.bin
path: "openmsx/share/systemroms/NMS8245SystemROM1.08.bin"
path: "share/systemroms/NMS8245SystemROM1.08.bin"
sha1: cc57c1dcd7249ea9f8e2547244592e7d97308ed0
required: true
size: 65536
@@ -76,7 +83,7 @@ files:
source_ref: "share/machines/Boosted_MSX2_EN.xml:24,65,111"
- name: fmpac.rom
path: "openmsx/share/systemroms/fmpac.rom"
path: "share/systemroms/fmpac.rom"
sha1: fec451b9256570a0e4869355a40329c57f40705f
required: true
description: "Panasonic SW-M004 FMPAC (FM-PAC) sound cartridge ROM"
@@ -84,7 +91,7 @@ files:
source_ref: "share/machines/Boosted_MSX2_EN.xml:83"
- name: phc-70fd2_basickun.rom
path: "openmsx/share/systemroms/phc-70fd2_basickun.rom"
path: "share/systemroms/phc-70fd2_basickun.rom"
sha1: 22b3191d865010264001b9d896186a9818478a6b
required: true
description: "Sanyo PHC-70FD2 MSX-BASIC Kun compiler ROM"
@@ -92,7 +99,7 @@ files:
source_ref: "share/machines/Boosted_MSX2_EN.xml:89, share/machines/Boosted_MSX2+_JP.xml:167, share/machines/Boosted_MSXturboR_with_IDE.xml:79"
- name: yrw801.rom
path: "openmsx/share/systemroms/yrw801.rom"
path: "share/systemroms/yrw801.rom"
sha1: 32760893ce06dbe3930627755ba065cc3d8ec6ca
required: true
description: "Yamaha YRW801 MoonSound wavetable ROM"
@@ -104,7 +111,7 @@ files:
# Based on Panasonic FS-A1WSX with extra hardware
# -------------------------------------------------------
- name: fs-a1wsx_basic-bios2p.rom
path: "openmsx/share/systemroms/fs-a1wsx_basic-bios2p.rom"
path: "share/systemroms/fs-a1wsx_basic-bios2p.rom"
sha1: f4433752d3bf876bfefb363c749d4d2e08a218b6
required: true
description: "FS-A1WSX MSX2+ BIOS and BASIC ROM"
@@ -112,7 +119,7 @@ files:
source_ref: "share/machines/Boosted_MSX2+_JP.xml:143"
- name: fs-a1wsx_fmbasic.rom
path: "openmsx/share/systemroms/fs-a1wsx_fmbasic.rom"
path: "share/systemroms/fs-a1wsx_fmbasic.rom"
sha1: aad42ba4289b33d8eed225d42cea930b7fc5c228
required: true
description: "FS-A1WSX MSX-MUSIC (OPLL) ROM"
@@ -121,7 +128,7 @@ files:
- name: fs-a1wsx_msx2psub.rom
installed_on: [retropie]
path: "openmsx/share/systemroms/fs-a1wsx_msx2psub.rom"
path: "share/systemroms/fs-a1wsx_msx2psub.rom"
sha1: fe0254cbfc11405b79e7c86c7769bd6322b04995
required: true
description: "FS-A1WSX MSX2+ Sub ROM"
@@ -130,7 +137,7 @@ files:
note: "RetroPie unpacks openmsxroms.tar.gz into the installed share/systemroms, which the file pool scans. This ROM is in it as MSX2PEXT.ROM and is found by its SHA1."
- name: fs-a1wsx_kanjibasic.rom
path: "openmsx/share/systemroms/fs-a1wsx_kanjibasic.rom"
path: "share/systemroms/fs-a1wsx_kanjibasic.rom"
sha1: dcc3a67732aa01c4f2ee8d1ad886444a4dbafe06
required: true
description: "FS-A1WSX Kanji Driver with BASIC ROM"
@@ -138,7 +145,7 @@ files:
source_ref: "share/machines/Boosted_MSX2+_JP.xml:225"
- name: fs-a1wsx_disk.rom
path: "openmsx/share/systemroms/fs-a1wsx_disk.rom"
path: "share/systemroms/fs-a1wsx_disk.rom"
sha1: 7ed7c55e0359737ac5e68d38cb6903f9e5d7c2b6
required: true
description: "FS-A1WSX FDC (TC8566AF) disk controller ROM"
@@ -146,7 +153,7 @@ files:
source_ref: "share/machines/Boosted_MSX2+_JP.xml:237"
- name: fs-a1wsx_firmware.rom
path: "openmsx/share/systemroms/fs-a1wsx_firmware.rom"
path: "share/systemroms/fs-a1wsx_firmware.rom"
sha1: 3330d9b6b76e3c4ccb7cf252496ed15d08b95d3f
required: true
description: "FS-A1WSX Panasonic firmware ROM"
@@ -154,7 +161,7 @@ files:
source_ref: "share/machines/Boosted_MSX2+_JP.xml:251"
- name: fs-a1wsx_kanjifont.rom
path: "openmsx/share/systemroms/fs-a1wsx_kanjifont.rom"
path: "share/systemroms/fs-a1wsx_kanjifont.rom"
sha1: 5aff2d9b6efc723bc395b0f96f0adfa83cc54a49
aliases: [fs-a1gt_kanjifont.rom]
required: true
@@ -168,7 +175,7 @@ files:
# Based on Panasonic FS-A1GT with IDE interface
# -------------------------------------------------------
- name: fs-a1gt_firmware.rom
path: "openmsx/share/systemroms/fs-a1gt_firmware.rom"
path: "share/systemroms/fs-a1gt_firmware.rom"
sha1:
- e779c338eb91a7dea3ff75f3fde76b8af22c4a3a
- 5fa3aa79aeba2c0441f349e78e9a16d9d64422ea
@@ -178,7 +185,7 @@ files:
source_ref: "share/machines/Boosted_MSXturboR_with_IDE.xml:23"
- name: ide250.dat
path: "openmsx/share/systemroms/ide250.dat"
path: "share/systemroms/ide250.dat"
sha1: 93e41c7d479bc90c1d1f6d081af20fd9924b8ada
required: true
description: "Sunrise IDE 2.50 interface ROM"
@@ -186,7 +193,7 @@ files:
source_ref: "share/machines/Boosted_MSXturboR_with_IDE.xml:49"
- name: ide250.zip
path: "openmsx/share/systemroms/ide250.zip"
path: "share/systemroms/ide250.zip"
required: false
description: "Sunrise IDE 2.50 distribution archive (IDE250.DAT, IDE250.TXT, IDEFLOAD.COM, IDEFLOAD.TXT)"
contents:
@@ -201,7 +208,7 @@ files:
# ColecoVision with built-in Super Game Module
# -------------------------------------------------------
- name: COLECO.ROM
path: "openmsx/share/systemroms/COLECO.ROM"
path: "share/systemroms/COLECO.ROM"
sha1: 45bedc4cbdeac66c7df59e9e599195c778d86a92
required: true
description: "ColecoVision system BIOS ROM"
@@ -212,7 +219,7 @@ files:
# Spectravideo_SVI-328 (spectravideo)
# -------------------------------------------------------
- name: svi-3x8_v111.rom
path: "openmsx/share/systemroms/svi-3x8_v111.rom"
path: "share/systemroms/svi-3x8_v111.rom"
sha1: 10349ce675f6d6d47f0976e39cb7188eba858d89
required: true
description: "SVI-328 BASIC v1.11 ROM"
@@ -224,7 +231,7 @@ files:
# MSX1 with LaserDisc controller
# -------------------------------------------------------
- name: px-7_basic-bios1.rom
path: "openmsx/share/systemroms/px-7_basic-bios1.rom"
path: "share/systemroms/px-7_basic-bios1.rom"
sha1: 302afb5d8be26c758309ca3df611ae69cced2821
required: true
description: "Pioneer PX-7 MSX1 BIOS and BASIC ROM"
@@ -232,7 +239,7 @@ files:
source_ref: "share/machines/Pioneer_PX-7.xml:67"
- name: px-7_pbasic.rom
path: "openmsx/share/systemroms/px-7_pbasic.rom"
path: "share/systemroms/px-7_pbasic.rom"
sha1: 665d805f96616e1037f1823050657b7849899283
required: true
description: "Pioneer PX-7 LaserDisc PBASIC controller ROM"
@@ -248,7 +255,7 @@ files:
# found does not start (src/memory/Rom.cc:173-184).
# -------------------------------------------------------
- name: cf-3300_basic-bios1.rom
path: "openmsx/share/systemroms/cf-3300_basic-bios1.rom"
path: "share/systemroms/cf-3300_basic-bios1.rom"
sha1: c7a2c5baee6a9f0e1c6ee7d76944c0ab1886796c
required: false
size: 32768
@@ -257,7 +264,7 @@ files:
source_ref: "share/machines/National_CF-3300.xml:51-52"
- name: cf-3300_disk.rom
path: "openmsx/share/systemroms/cf-3300_disk.rom"
path: "share/systemroms/cf-3300_disk.rom"
sha1: f1525de4e0b60a6687156c2a96f8a8b2044b6c56
required: false
size: 16384
@@ -266,7 +273,7 @@ files:
source_ref: "share/machines/National_CF-3300.xml:75-76"
- name: fs-5500_basic-bios2.rom
path: "openmsx/share/systemroms/fs-5500_basic-bios2.rom"
path: "share/systemroms/fs-5500_basic-bios2.rom"
sha1: 44e0dd215b2a9f0770dd76fb49187c05b083eed9
required: false
size: 32768
@@ -275,7 +282,7 @@ files:
source_ref: "share/machines/National_FS-5500F2.xml:76-77, share/machines/National_FS-5500F1.xml:78"
- name: fs-5500_msx2sub.rom
path: "openmsx/share/systemroms/fs-5500_msx2sub.rom"
path: "share/systemroms/fs-5500_msx2sub.rom"
sha1: 4be8371f3b03e70ddaca495958345f3c4f8e2d36
required: false
size: 16384
@@ -284,7 +291,7 @@ files:
source_ref: "share/machines/National_FS-5500F2.xml:100-101, share/machines/National_FS-5500F1.xml:102"
- name: fs-5500_kanjibasic.rom
path: "openmsx/share/systemroms/fs-5500_kanjibasic.rom"
path: "share/systemroms/fs-5500_kanjibasic.rom"
sha1: 3a9a942ed888dd641cddf8deada1879c454df3c6
required: false
size: 32768
@@ -293,7 +300,7 @@ files:
source_ref: "share/machines/National_FS-5500F2.xml:107-108, share/machines/National_FS-5500F1.xml:109"
- name: fs-5500_kanjifont.rom
path: "openmsx/share/systemroms/fs-5500_kanjifont.rom"
path: "share/systemroms/fs-5500_kanjifont.rom"
sha1: 9ed3ab6d893632b9246e91b412cd5db519e7586b
required: false
size: 131072
@@ -302,7 +309,7 @@ files:
source_ref: "share/machines/National_FS-5500F2.xml:20-21, share/machines/National_FS-5500F1.xml:22"
- name: fs-5500_superimp.rom
path: "openmsx/share/systemroms/fs-5500_superimp.rom"
path: "share/systemroms/fs-5500_superimp.rom"
sha1: b677a861b67e8763a11d5dcf52416b42493ade57
required: false
size: 32768
@@ -311,7 +318,7 @@ files:
source_ref: "share/machines/National_FS-5500F2.xml:117-118, share/machines/National_FS-5500F1.xml:119"
- name: nms8245_msx2sub.rom
path: "openmsx/share/systemroms/nms8245_msx2sub.rom"
path: "share/systemroms/nms8245_msx2sub.rom"
sha1:
- 5c1f9c7fb655e43d38e5dd1fcc6b942b2ff68b02
- e7905d16d2ccd57a013c122dc432106cd59ef52c
@@ -322,7 +329,7 @@ files:
source_ref: "share/machines/Philips_NMS_8245.xml:108-110"
- name: vg8020_basic-bios1.rom
path: "openmsx/share/systemroms/vg8020_basic-bios1.rom"
path: "share/systemroms/vg8020_basic-bios1.rom"
sha1: 829c00c3114f25b3dae5157c0a238b52a3ac37db
required: false
size: 32768
@@ -331,7 +338,7 @@ files:
source_ref: "share/machines/Philips_VG_8020.xml:53-54"
- name: svi-738_basic-bios1.rom
path: "openmsx/share/systemroms/svi-738_basic-bios1.rom"
path: "share/systemroms/svi-738_basic-bios1.rom"
sha1: c53b3f2c00f31683914f7452f3f4d94ae2929c0d
required: false
size: 32768
@@ -340,7 +347,7 @@ files:
source_ref: "share/machines/Spectravideo_SVI-738.xml:53-54"
- name: svi-738_se_basic-bios1.rom
path: "openmsx/share/systemroms/svi-738_se_basic-bios1.rom"
path: "share/systemroms/svi-738_se_basic-bios1.rom"
sha1: 87f4d0fa58cfe9cef818a3185df2735e6da6168c
required: false
size: 32768
@@ -349,7 +356,7 @@ files:
source_ref: "share/machines/Spectravideo_SVI-738_SE.xml:53-54"
- name: svi-738_rs232.rom
path: "openmsx/share/systemroms/svi-738_rs232.rom"
path: "share/systemroms/svi-738_rs232.rom"
sha1: 4e9384c9d137f0ab65ffc5a78f04cd8c9df6c8b7
required: false
size: 8192
@@ -358,7 +365,7 @@ files:
source_ref: "share/machines/Spectravideo_SVI-738.xml:76-77, share/machines/Spectravideo_SVI-738_SE.xml:76-77"
- name: svi-738_disk.rom
path: "openmsx/share/systemroms/svi-738_disk.rom"
path: "share/systemroms/svi-738_disk.rom"
sha1:
- 99a40266bc296cef1d432cb0caa8df1a7e570be4
- 55d5d1fd57d35384b821af62083f2a23d85580e6
+18
View File
@@ -6562,6 +6562,24 @@ launchers:
passes_to: environment FLYCAST_BIOS_PATH
fails_when_missing: false
source_ref: "package/batocera/core/batocera-configgen/configgen/configgen/generators/flycast/flycastGenerator.py:199"
- emulator: openmsx
build: standalone
kind: passes_path
names: []
search_dir: /userdata/bios/Machines
passes_to: "written: filepool add -path /userdata/bios/Machines -types system_rom\
\ -position 1"
fails_when_missing: false
source_ref: "package/batocera/core/batocera-configgen/configgen/configgen/generators/openmsx/openmsxGenerator.py:88"
- emulator: openmsx
build: standalone
kind: passes_path
names: []
search_dir: /userdata/bios/openmsx
passes_to: "written: filepool add -path /userdata/bios/openmsx -types system_rom\
\ -position 2"
fails_when_missing: false
source_ref: "package/batocera/core/batocera-configgen/configgen/configgen/generators/openmsx/openmsxGenerator.py:89"
- emulator: o2em
build: libretro
kind: core_option
+18 -18
View File
@@ -5685,6 +5685,24 @@ launchers:
passes_to: environment FLYCAST_BIOS_PATH
fails_when_missing: false
source_ref: "package/system/knulli-configgen/configgen/configgen/generators/flycast/flycastGenerator.py:239"
- emulator: openmsx
build: standalone
kind: passes_path
names: []
search_dir: /userdata/bios/Machines
passes_to: "written: filepool add -path /userdata/bios/Machines -types system_rom\
\ -position 1"
fails_when_missing: false
source_ref: "package/system/knulli-configgen/configgen/configgen/generators/openmsx/openmsxGenerator.py:95"
- emulator: openmsx
build: standalone
kind: passes_path
names: []
search_dir: /userdata/bios/openmsx
passes_to: "written: filepool add -path /userdata/bios/openmsx -types system_rom\
\ -position 2"
fails_when_missing: false
source_ref: "package/system/knulli-configgen/configgen/configgen/generators/openmsx/openmsxGenerator.py:96"
- emulator: lexaloffle
build: standalone
kind: fixed_name
@@ -6014,24 +6032,6 @@ launchers:
passes_to: command line -crosshairpath
fails_when_missing: false
source_ref: "package/system/knulli-configgen/configgen/configgen/generators/mame/mameGenerator.py:180"
- emulator: openmsx
build: standalone
kind: passes_path
names: []
search_dir: /userdata/bios/Machines
passes_to: "written: filepool add -path /userdata/bios/Machines -types system_rom\
\ -position 1"
fails_when_missing: false
source_ref: "package/system/knulli-configgen/configgen/configgen/generators/openmsx/openmsxGenerator.py:95"
- emulator: openmsx
build: standalone
kind: passes_path
names: []
search_dir: /userdata/bios/openmsx
passes_to: "written: filepool add -path /userdata/bios/openmsx -types system_rom\
\ -position 2"
fails_when_missing: false
source_ref: "package/system/knulli-configgen/configgen/configgen/generators/openmsx/openmsxGenerator.py:96"
- emulator: fpinball
build: standalone
kind: passes_path
+8
View File
@@ -4779,6 +4779,14 @@ launchers:
fails_when_missing: ApplicationException '<machine> machine has missing BIOS file
'<c>' in 'bios\openmsx\share\systemroms' folder.'
source_ref: "emulatorLauncher/Generators/OpenMSX.Generator.cs:156-159, 467"
- emulator: openmsx
build: standalone
kind: passes_path
names: []
search_dir: bios/openmsx
passes_to: environment OPENMSX_HOME
fails_when_missing: false
source_ref: "emulatorLauncher/Generators/OpenMSX.Generator.cs:51, 255"
- emulator: kronos
build: standalone
kind: fixed_name
+18
View File
@@ -778,6 +778,15 @@ launchers:
passes_to: $configdir/msx/openmsx/share/systemroms is a symlink to it
fails_when_missing: false
source_ref: "scriptmodules/emulators/openmsx.sh:77"
- emulator: openmsx
package: openmsx
build: standalone
kind: links
names: []
search_dir: $configdir/msx/openmsx
passes_to: $home/.openMSX is a symlink to it
fails_when_missing: false
source_ref: "scriptmodules/emulators/openmsx.sh:76"
- emulator: oricutron
package: oricutron
repo: "git https://github.com/HerbFargus/oricutron.git extras"
@@ -1269,6 +1278,15 @@ launchers:
passes_to: $md_inst/share/xroar/roms is a symlink to it
fails_when_missing: false
source_ref: "scriptmodules/emulators/xroar.sh:52"
- emulator: xroar
package: xroar
build: standalone
kind: passes_path
names: []
search_dir: $md_inst
passes_to: "${prefix} of configure --prefix"
fails_when_missing: false
source_ref: "scriptmodules/emulators/xroar.sh:37"
- emulator: yabasanshiro
package: yabasanshiro
repo: "git https://github.com/retropie/yabause.git pi4-1-9-0"
+54 -2
View File
@@ -15,7 +15,8 @@ launcher looks for nothing".
from __future__ import annotations
import ast
from collections.abc import Callable
import re
from collections.abc import Callable, Iterable
from typing import Any
from .configgen_launchers import (
@@ -898,6 +899,56 @@ def environment_directories(cg: Configgen) -> list[Launcher]:
return launchers
# Generators that hand the emulator a /userdata/bios directory through its
# configuration: a line written to the file it reads (openMSX's script.tcl
# filepool entries) or a key saved to it.
CONFIG_DIRECTORY_GENERATORS = ("openmsx.openmsxGenerator",)
def config_directories(
cg: Configgen, modules: Iterable[str] = CONFIG_DIRECTORY_GENERATORS
) -> list[Launcher]:
"""file.write("<line naming a BIOS directory>") and settings.save(key, <BIOS directory>)."""
prefix = cg.bios.rstrip("/")
inside = re.compile(rf"{re.escape(prefix)}(?:/[^\s\"';]*)?")
launchers = []
for module in modules:
src = cg.generator(module)
constants = dict(cg.paths)
for node in src.tree.body:
name = _assigned_name(node)
value = _path_value(getattr(node, "value", None), constants)
if name is not None and value is not None:
constants[name] = value
found: list[tuple[str, str, ast.Call]] = []
for call in _calls(src.tree, attr="write"):
text = call.args[0] if len(call.args) == 1 else None
if isinstance(text, ast.Constant) and isinstance(text.value, str):
line = text.value.strip()
named = inside.search(line)
if named:
found.append((named.group(0), f"written: {line}", call))
for call in _calls(src.tree, attr="save"):
if len(call.args) != 2 or not isinstance(call.args[0], ast.Constant):
continue
value = _path_value(call.args[1], constants)
if value is None and isinstance(call.args[1], ast.Constant):
value = str(call.args[1].value)
if value is not None and (value.rstrip("/") == prefix or value.startswith(prefix + "/")):
found.append((value, str(call.args[0].value), call))
if not found:
src.fail("hands no /userdata/bios directory through its config")
launchers.extend(
Launcher(
emulator=cg.emulator(module), build="standalone", kind="passes_path",
names=[], search_dir=directory, passes_to=passes_to,
source_ref=src.ref([src.span(call)]),
)
for directory, passes_to, call in found
)
return launchers
# libretro core options whose value names the BIOS file the core opens.
FILE_OPTIONS = (("_o2em_options", "o2em_bios"), ("_neocd_options", "neocd_bios"))
@@ -952,7 +1003,8 @@ def core_file_options(cg: Configgen) -> list[Launcher]:
EXTRACTORS: tuple[Callable[[Configgen], list[Launcher]], ...] = (
duckstation, duckstation_legacy, hatari, xemu, melonds, mupen64plus,
x16emu, gsplus, lexaloffle, environment_directories, core_file_options,
x16emu, gsplus, lexaloffle, environment_directories, config_directories,
core_file_options,
)
+12 -2
View File
@@ -31,6 +31,7 @@ import yaml
try:
from .batocera_launchers import (
Configgen,
config_directories,
_path_value,
_render,
_system_branches,
@@ -53,6 +54,7 @@ try:
except ImportError:
from batocera_launchers import ( # type: ignore[no-redef]
Configgen,
config_directories,
_path_value,
_render,
_system_branches,
@@ -84,9 +86,18 @@ PICO8_INSTALLER = "board/fsoverlay/usr/bin/knulli-install-pico8"
ES_FEATURES = "package/emulationstation/knulli-es-system/es_features.yml"
# Batocera's extractors that read KNULLI's generators unchanged.
# The generators of Batocera's config_directories that KNULLI keeps in the
# same shape: openMSX's filepool lines.
CONFIG_DIRECTORY_GENERATORS = ("openmsx.openmsxGenerator",)
def knulli_config_directories(cg: Configgen) -> list[Launcher]:
return config_directories(cg, CONFIG_DIRECTORY_GENERATORS)
SHARED = (
duckstation, duckstation_legacy, hatari, xemu, melonds, mupen64plus, x16emu,
environment_directories,
environment_directories, knulli_config_directories,
)
@@ -365,7 +376,6 @@ GENERIC_SITES = (
GenericSites("amiberry/amiberryGenerator.py", "passes_path"),
GenericSites("fsuae/fsuaeGenerator.py", "passes_path"),
GenericSites("mame/mameGenerator.py", "passes_path"),
GenericSites("openmsx/openmsxGenerator.py", "passes_path"),
GenericSites("fpinball/fpinballGenerator.py", "passes_path"),
GenericSites(
"libretro/libretroRetroarchCustom.py", "passes_path", "libretro", emulator="retroarch"
+23
View File
@@ -1279,6 +1279,29 @@ def openmsx(sources: dict[str, Source]) -> list[Record]:
)
if not records:
raise LauncherPatternMissing(src.path, "biosFiles entries")
# OPENMSX_HOME is the user directory: openMSX reads share/systemroms below it.
home = src.find(
rf'string (\w+) = Path\.Combine\({BIOS}, "([^"]+)"\);', "OPENMSX_HOME folder"
)
handed = src.find(
rf'ret\.EnvironmentVariables\["(OPENMSX_HOME)"\] = {home.group(1)};',
"OPENMSX_HOME environment", home.end(),
)
records.append(
_record(
"openmsx",
"standalone",
"passes_path",
[],
source_ref(
(src.path, [src.lines(home.start(), home.end()),
src.lines(handed.start(), handed.end())])
),
search_dir=f"bios/{home.group(2)}",
passes_to=f"environment {handed.group(1)}",
fails_when_missing=False,
)
)
return records
+49
View File
@@ -525,6 +525,7 @@ class PackageReader:
self._links(links)
self._outside_bios(events)
self._working_directory(events)
self._reaching_links(events)
return self.records
@staticmethod
@@ -828,6 +829,54 @@ class PackageReader:
)
def _reaching_links(self, events: list[Event]) -> None:
"""The directories outside the BIOS one that a whole-directory link lies in.
openmsx's moveConfigDir "$home/.openMSX" "$configdir/msx/openmsx"
puts the emulator's directory where the systemroms link to BIOS/openmsx
lies, and xroar's ./configure --prefix="$md_inst" builds the program
whose share/xroar/roms links to $biosdir. Neither line names the BIOS
directory, and each says where the link is read from.
"""
suffix = " is a symlink to it"
linked = [
record.passes_to.removesuffix(suffix).rstrip("/")
for record in self.records
if record.kind == "links" and not record.names
and (record.passes_to or "").endswith(suffix)
]
if not linked:
return
def holds(directory: str) -> bool:
directory = directory.strip("\"'").rstrip("/")
return bool(directory) and any(
path == directory or path.startswith(directory + "/") for path in linked
)
for event in events:
if event.heredoc or not event.words or _mentions_bios(event.raw):
continue
command = event.words[0][0]
if command == "moveConfigDir" and len(event.words) >= 3:
link, real = event.words[1][0], event.words[2][0]
if holds(real):
self.record(
"links", [], [(event.path, event.line)],
search_dir=real, passes_to=f"{link}{suffix}",
fails_when_missing=False, depends_on_option=self._depends(event),
)
elif command.endswith("configure"):
for word in event.words[1:]:
prefix = word[0].strip("\"'")
if prefix.startswith("--prefix=") and holds(prefix[len("--prefix="):]):
self.record(
"passes_path", [], [(event.path, event.line)],
search_dir=prefix[len("--prefix="):].strip("\"'"),
passes_to="${prefix} of configure --prefix",
fails_when_missing=False, depends_on_option=self._depends(event),
)
def _working_directory(self, events: list[Event]) -> None:
"""The folder a generated launch script enters before it runs the emulator."""
if self.package.id not in WORKING_DIRECTORY:
+44
View File
@@ -29,6 +29,7 @@ from scraper.batocera_launchers import ( # noqa: E402
Configgen,
Launcher,
LauncherShapeError,
config_directories,
duckstation,
extract_launchers,
hatari,
@@ -521,6 +522,49 @@ class LexaloffleBinaries(unittest.TestCase):
lexaloffle(lexaloffle_tree(text))
OPENMSX = f"{GENERATORS}/openmsx/openmsxGenerator.py"
OPENMSX_FILEPOOL = ''' def generate(self, system, rom):
with settings_tcl.open("a") as file:
file.write("filepool add -path /userdata/bios/Machines -types system_rom -position 1\\n")
file.write("filepool add -path /userdata/bios/openmsx -types system_rom -position 2\\n")'''
class ConfigDirectories(unittest.TestCase):
"""A BIOS directory written into the emulator's config, at batocera-43.1."""
def test_each_filepool_line_hands_its_directory(self):
cg = configgen({OPENMSX: placed({1: "class OpenmsxGenerator:", 86: OPENMSX_FILEPOOL})})
records = [r.entry() for r in config_directories(cg, ("openmsx.openmsxGenerator",))]
self.assertEqual(
[(r["emulator"], r["kind"], r["search_dir"], r["source_ref"]) for r in records],
[
("openmsx", "passes_path", "/userdata/bios/Machines", f"{OPENMSX}:88"),
("openmsx", "passes_path", "/userdata/bios/openmsx", f"{OPENMSX}:89"),
],
)
self.assertEqual(
records[1]["passes_to"],
"written: filepool add -path /userdata/bios/openmsx -types system_rom -position 2",
)
def test_a_saved_setting_hands_its_directory(self):
amiberry = f"{GENERATORS}/amiberry/amiberryGenerator.py"
text = placed({
1: "from pathlib import Path\n_BIOS_DIR = Path('/userdata/bios/amiga')",
10: "def generate():\n amiberryconf.save('rom_path', _BIOS_DIR)",
})
(record,) = config_directories(configgen({amiberry: text}), ("amiberry.amiberryGenerator",))
self.assertEqual(
(record.search_dir, record.passes_to, record.source_ref),
("/userdata/bios/amiga", "rom_path", f"{amiberry}:11"),
)
def test_a_generator_handing_no_bios_directory_raises(self):
cg = configgen({OPENMSX: "def generate():\n file.write('savestate x')\n"})
with self.assertRaises(LauncherShapeError):
config_directories(cg, ("openmsx.openmsxGenerator",))
class ExtractionNeverEmpty(unittest.TestCase):
def test_a_generator_of_unknown_shape_stops_the_whole_scrape(self):
find = DUCKSTATION_FIND.replace("def find_bios(", "def locate_bios(")
+12
View File
@@ -145,6 +145,9 @@ OPENMSX = """
{ "Philips_VG_8020", new string[] { "vg8020_basic-bios1.rom" } },
{ "Pioneer_PX-7", new string[] { "px-7_basic-bios1.rom", "px-7_pbasic.rom" } }
};
string sharePath = Path.Combine(AppConfig.GetFullPath("bios"), "openmsx");
ret.EnvironmentVariables["OPENMSX_HOME"] = sharePath;
"""
DUCKSTATION = """
@@ -390,12 +393,21 @@ class NamesInLauncherOrder(unittest.TestCase):
[
("-machine Philips_VG_8020", ["vg8020_basic-bios1.rom"]),
("-machine Pioneer_PX-7", ["px-7_basic-bios1.rom", "px-7_pbasic.rom"]),
("environment OPENMSX_HOME", []),
],
)
self.assertEqual(records[0]["search_dir"], "bios/openmsx/share/systemroms")
self.assertFalse(records[0]["case_insensitive"])
self.assertEqual(records[1]["source_ref"], f"{G}/OpenMSX.Generator.cs:1-4, 10")
def test_openmsx_home_is_handed_as_a_directory(self):
# OPENMSX_HOME is the user directory openMSX reads share/systemroms below.
records = rl.openmsx(_sources(**{f"{G}/OpenMSX.Generator.cs": OPENMSX}))
home = records[-1]
self.assertEqual(home["kind"], "passes_path")
self.assertEqual(home["search_dir"], "bios/openmsx")
self.assertEqual(home["source_ref"], f"{G}/OpenMSX.Generator.cs:13-14")
def test_duckstation_reads_the_standalone_feature_not_the_core(self):
search, option = rl.duckstation(
_sources(**{f"{G}/Duckstation.Generator.cs": DUCKSTATION, rl.FEATURES: FEATURES})
+53
View File
@@ -315,6 +315,59 @@ UAE4ALL = module("uae4all", """
""", 60)
OPENMSX = module("openmsx", """
function configure_openmsx() {
mkUserDir "$home/.openMSX/share/systemroms"
moveConfigDir "$home/.openMSX" "$configdir/msx/openmsx"
moveConfigDir "$configdir/msx/openmsx/share/systemroms" "$home/RetroPie/BIOS/openmsx"
moveConfigDir "$home/.unrelated" "$configdir/msx/other"
}
""", 74)
XROAR = module("xroar", """
function build_xroar() {
./configure --prefix="$md_inst" "${params[@]}"
}
function configure_xroar() {
mkdir -p "$md_inst/share/xroar"
ln -snf "$biosdir" "$md_inst/share/xroar/roms"
}
""", 36)
class ReachingLinks(unittest.TestCase):
"""The directory outside BIOS that a whole-directory link is read from."""
def test_openmsx_user_directory_holds_the_systemroms_link(self):
found = records({f"{EMULATORS}/openmsx.sh": OPENMSX}, "openmsx")
links = [r for r in found if r["kind"] == "links"]
self.assertEqual(
[(r["search_dir"], r["passes_to"], r["source_ref"]) for r in links],
[
(
"$home/RetroPie/BIOS/openmsx",
"$configdir/msx/openmsx/share/systemroms is a symlink to it",
f"{EMULATORS}/openmsx.sh:77",
),
(
"$configdir/msx/openmsx",
"$home/.openMSX is a symlink to it",
f"{EMULATORS}/openmsx.sh:76",
),
],
)
def test_xroar_install_prefix_holds_the_roms_link(self):
found = records({f"{EMULATORS}/xroar.sh": XROAR}, "xroar")
prefix = [r for r in found if r["kind"] == "passes_path"]
self.assertEqual(
[(r["search_dir"], r["passes_to"], r["source_ref"]) for r in prefix],
[("$md_inst", "${prefix} of configure --prefix", f"{EMULATORS}/xroar.sh:37")],
)
class WorkingDirectory(unittest.TestCase):
def test_drastic_reads_below_the_folder_its_script_enters(self):
found = records({f"{EMULATORS}/drastic.sh": DRASTIC}, "drastic")
+40
View File
@@ -497,3 +497,43 @@ class Scrapers(unittest.TestCase):
if __name__ == "__main__":
unittest.main()
class OpenmsxOnEachPlatform(unittest.TestCase):
"""openMSX finds system ROMs by SHA1 in share/systemroms below its user
directory and in every filepool entry. RetroBat sets OPENMSX_HOME to
bios/openmsx, RetroPie links share/systemroms of its user directory to
BIOS/openmsx, Batocera and KNULLI add bios/Machines and bios/openmsx to
the filepool and list their own files in bios/openmsx."""
EXPECTED = {
"batocera": {"share/systemroms": ("", "openmsx")},
"knulli": {"share/systemroms": ("", "openmsx")},
"retrobat": {"": ("", "openmsx")},
"retropie": {"share/systemroms": ("", "openmsx")},
}
@classmethod
def setUpClass(cls) -> None:
cls.profile = load_emulator_profiles(str(REPO_ROOT / "emulators"))["openmsx"]
def test_each_platform_hands_openmsx_its_folder(self) -> None:
for platform, expected in self.EXPECTED.items():
with self.subTest(platform=platform):
cfg = load_platform_config(platform, str(REPO_ROOT / "platforms"))
self.assertEqual(
standalone_bindings_for("openmsx", self.profile, standalone_set(cfg)),
expected,
)
def test_every_system_rom_lands_in_bios_openmsx(self) -> None:
for platform in self.EXPECTED:
with self.subTest(platform=platform):
cfg = load_platform_config(platform, str(REPO_ROOT / "platforms"))
(view, _standalone), = platform_layouts(
"openmsx", self.profile, standalone_set(cfg)
)
for entry in view["files"]:
self.assertNotIn("unplaced", entry)
self.assertTrue(
entry["standalone_path"].startswith("openmsx/"), entry["standalone_path"]
)