diff --git a/emulators/gam4980.yml b/emulators/gam4980.yml index 71aeec45..8d266bb1 100644 --- a/emulators/gam4980.yml +++ b/emulators/gam4980.yml @@ -16,14 +16,13 @@ systems: # Original code from https://codeberg.org/iyzsong/gam4980, based on the # BA4988 BBK simulator by Wuyun. Uses a 6502-based CPU with banked ROM access. # -# ROM loading (libretro.c:692-760, sys_init): +# ROM loading (src/libretro.c:707-746, sys_init): # Opens romdir/8.BIN and reads 0x200000 bytes (2 MB) into sys.rom_8 (font ROM). # Opens romdir/E.BIN and reads 0x200000 bytes (2 MB) into sys.rom_e (OS ROM). -# The upstream has error handling (error_msg + RETRO_ENVIRONMENT_SHUTDOWN on -# missing files). The fork (ThisBoringWorld) removed these checks -- crashes -# on missing files. +# A missing file shows "GAM4980: Missing 8.BIN" (or E.BIN) and the core +# shuts down through RETRO_ENVIRONMENT_SHUTDOWN. # -# Memory map (libretro.c:109-110, 300-305): +# Memory map (src/libretro.c:109-110, 302-305): # 0x800000-0x9FFFFF rom_8 (font ROM, 8.BIN) # 0xE00000-0xFFFFFF rom_e (OS ROM, E.BIN) # @@ -42,19 +41,19 @@ files: required: true system: bbk-longman-4980 note: "Font ROM (2 MB). Loaded at 0x800000." - source_ref: "libretro.c:716-718" + source_ref: "src/libretro.c:730-737" - name: "gam4980/E.BIN" size: 2097152 required: true system: bbk-longman-4980 note: "OS ROM (2 MB). Loaded at 0xE00000." - source_ref: "libretro.c:720-722" + source_ref: "src/libretro.c:739-746" platform_details: bios_mapping: target: "0x800000-0x9FFFFF (font), 0xE00000-0xFFFFFF (OS) in banked address space" - source_ref: "libretro.c:109-110, 300-305" + source_ref: "src/libretro.c:109-110, 302-305" note: | sys.rom_8 and sys.rom_e are flat 2 MB arrays. The CPU accesses them through bank-switched memory (PA() macro resolves virtual to physical @@ -62,7 +61,7 @@ platform_details: the banking system. load_path: - source_ref: "libretro.c:1173-1175" + source_ref: "src/libretro.c:1193-1197" note: | retro_init() builds the path as {system_directory}/gam4980/ and passes it to sys_init(). Files must be named exactly 8.BIN and diff --git a/scripts/profile_sync.py b/scripts/profile_sync.py index d7cb053f..fa610a97 100644 --- a/scripts/profile_sync.py +++ b/scripts/profile_sync.py @@ -2861,6 +2861,18 @@ def bump_commit( # Rewriting the pin to the value it already holds is not a bump, and # announcing it buries the profiles that did move. return False + if ( + document.get("source_commit") != report.head + and not cites_primary(report) + ): + # Every ref anchored in another repository: HEAD of this one was + # never compared with anything. gam4980's pin moved to the fork's + # HEAD while its bare libretro.c refs still described upstream. + print( + f"{path.stem}: no ref resolves in {report.repo}, its pin is not advanced", + file=sys.stderr, + ) + return False expected = dict(document) expected["source_commit"] = report.head new_text = _set_pin(text, document, "source_commit", report.head, "profiled_date") @@ -2873,6 +2885,22 @@ def bump_commit( return True +def cites_primary(report: ProfileReport) -> bool: + """Whether a ref resolved in the repository source_commit pins. + + A part attributed to another declared repository carries its slug; one + read in the primary carries none. A profile citing nothing proves + nothing either way and is not held back. + """ + if len(report.repos) < 2: + return True + parts = [ + part for entry in report.entries for part in entry.parts + if part.status != "EXTERNAL" + ] + return not parts or any(part.repo is None for part in parts) + + def _set_pin(text: str, document: dict, field: str, value: str, after: str) -> str: """Write *field* as *value*, replacing its line or adding one after *after*.""" current = document.get(field) diff --git a/tests/test_profile_sync.py b/tests/test_profile_sync.py index c03fd554..a76ab851 100644 --- a/tests/test_profile_sync.py +++ b/tests/test_profile_sync.py @@ -2772,6 +2772,24 @@ class TestBumpCommit(unittest.TestCase): self.assertEqual(profile_sync.pending_recale(report), 0) self.assertTrue(bump_commit(self.path, report)) + def test_refused_when_no_ref_reads_the_pinned_repository(self): + """gam4980: every bare libretro.c ref anchored in upstream, and the + bump wrote the fork's HEAD over refs that never described it.""" + def report(repo): + part = PartResult( + RefPart("libretro.c", 10, 12, "libretro.c:10-12"), "ANCHORED", + None, 10, 12, [], None, repo, + ) + return ProfileReport( + name="p", repo="fork/n", repos=["fork/n", "up/n"], pin="pin", + head="newhead", + entries=[EntryReport("a.bin", "libretro.c:10-12", "ANCHORED", [part])], + counts={"ANCHORED": 1}, + ) + self.assertFalse(bump_commit(self.path, report("up/n"))) + self.assertNotIn("newhead", self.path.read_text()) + self.assertTrue(bump_commit(self.path, report(None))) + def test_a_bump_alone_waits_for_the_recale(self): """lrps2 at 0 to review with two SHIFTED parts: --bump-commit run alone wrote the new pin over refs still on the old lines."""