feat: add FBNeo source parser for BIOS sets

This commit is contained in:
Abdessamad Derraz
2026-03-30 18:29:06 +02:00
parent caf6285a04
commit 00d7b57884
2 changed files with 317 additions and 0 deletions

View File

@@ -0,0 +1,127 @@
"""Parser for FBNeo source files to extract BIOS sets and ROM definitions.
Parses BurnRomInfo structs (static ROM arrays) and BurnDriver structs
(driver registration) from FBNeo C source files. BIOS sets are identified
by the BDF_BOARDROM flag in BurnDriver definitions.
"""
from __future__ import annotations
import os
import re
from pathlib import Path
_ROM_ENTRY_RE = re.compile(
r'\{\s*"([^"]+)"\s*,\s*(0x[\da-fA-F]+)\s*,\s*(0x[\da-fA-F]+)\s*,\s*([^}]+)\}',
)
_BURN_DRIVER_RE = re.compile(
r'struct\s+BurnDriver\s+BurnDrv(\w+)\s*=\s*\{(.*?)\};',
re.DOTALL,
)
_ROM_DESC_RE = re.compile(
r'static\s+struct\s+BurnRomInfo\s+(\w+)RomDesc\s*\[\s*\]\s*=\s*\{(.*?)\};',
re.DOTALL,
)
def find_bios_sets(source: str, filename: str) -> dict[str, dict]:
"""Find BDF_BOARDROM drivers in source code.
Returns a dict mapping set name to metadata:
{set_name: {"source_file": str, "source_line": int}}
"""
results: dict[str, dict] = {}
for match in _BURN_DRIVER_RE.finditer(source):
body = match.group(2)
if 'BDF_BOARDROM' not in body:
continue
# Set name is the first quoted string in the struct body
name_match = re.search(r'"([^"]+)"', body)
if not name_match:
continue
set_name = name_match.group(1)
line_num = source[:match.start()].count('\n') + 1
results[set_name] = {
'source_file': filename,
'source_line': line_num,
}
return results
def parse_rom_info(source: str, set_name: str) -> list[dict]:
"""Parse a BurnRomInfo array for the given set name.
Returns a list of dicts with keys: name, size, crc32.
Sentinel entries (empty name) are skipped.
"""
pattern = re.compile(
r'static\s+struct\s+BurnRomInfo\s+'
+ re.escape(set_name)
+ r'RomDesc\s*\[\s*\]\s*=\s*\{(.*?)\};',
re.DOTALL,
)
match = pattern.search(source)
if not match:
return []
body = match.group(1)
roms: list[dict] = []
for entry in _ROM_ENTRY_RE.finditer(body):
name = entry.group(1)
if not name:
continue
size = int(entry.group(2), 16)
crc32 = format(int(entry.group(3), 16), '08x')
roms.append({
'name': name,
'size': size,
'crc32': crc32,
})
return roms
def parse_fbneo_source_tree(base_path: str) -> dict[str, dict]:
"""Walk the FBNeo driver source tree and extract all BIOS sets.
Scans .cpp files under src/burn/drv/ for BDF_BOARDROM drivers,
then parses their associated BurnRomInfo arrays.
Returns a dict mapping set name to:
{source_file, source_line, roms: [{name, size, crc32}, ...]}
"""
drv_path = Path(base_path) / 'src' / 'burn' / 'drv'
if not drv_path.is_dir():
return {}
results: dict[str, dict] = {}
for root, _dirs, files in os.walk(drv_path):
for fname in files:
if not fname.endswith('.cpp'):
continue
filepath = Path(root) / fname
source = filepath.read_text(encoding='utf-8', errors='replace')
rel_path = str(filepath.relative_to(base_path))
bios_sets = find_bios_sets(source, rel_path)
for set_name, meta in bios_sets.items():
roms = parse_rom_info(source, set_name)
results[set_name] = {
'source_file': meta['source_file'],
'source_line': meta['source_line'],
'roms': roms,
}
return results