re(challenge): MISSION SELECT renders the cleared-stage mask, and a control run
With word A = 2 the screen lists Stage01 SELECTABLE, carrying a High Score and a
Best Time, and Stage02-Stage08 GREYED OUT. One cleared stage, one selectable
entry, at the bit index that names it -- the mask's meaning is now visible on
screen rather than inferred from disassembly.
Two runs, identical navigation, fresh boot each:
control word A 0x00000002 -> MISSION SELECT opens normally
poked word A 0xFFFFFFFF -> MmAllocatePhysicalMemoryEx fails on 128 MB,
guest throws, Xenia shows "Disc Read Error"
So last commit's heap failure was caused by the poke, and by a careless one:
0xFFFFFFFF claims stages that do not exist (0, 17, 24-31 in word A). Poking only
real story ids (0x0001FFFE = stages 1-16) does not blow the heap. That the list
screen changes behaviour with the mask is itself evidence word A feeds it.
Getting a trustworthy control took three tries, and every failure produced a
plausible wrong answer rather than an error:
1. the title-glyph oracle fired during the ATTRACT MOVIE, so A was pressed at
nothing and the run "reported 0 failures" for a screen it never reached;
2. Xvfb keeps the previous instance's framebuffer until the new one draws, so
a screenshot seconds after launch showed the OLD run -- "MAIN MENU reached
after 1s", against a process that no longer existed;
3. a single-pixel "is NEW GAME white?" test matched a white LOADING FLASH.
Fixes, all in challenge_probe.sh: blank the root and refuse screen oracles for
the first 40 s; identify a screen by a PATTERN of sampled points (white text AND
the dark panel behind it), not one pixel; require two consecutive samples. The
new oracle was validated offline against all six saved screenshots and accepts
exactly the one real main menu.
General lesson worth the words: a navigation oracle that can only fail by
returning the wrong screen will happily produce a whole run of confident,
meaningless results.
This commit is contained in:
BIN
docs/re/captures/mission-select-stage01-only.png
Normal file
BIN
docs/re/captures/mission-select-stage01-only.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
@@ -292,6 +292,24 @@ the running game and against a known progress state:
|
||||
|
||||
Both words were then poked (`0xFFFFFFFF` / `0x3F`) and read back OK.
|
||||
|
||||
**MISSION SELECT shows the mask directly** ([capture](captures/mission-select-stage01-only.png)).
|
||||
With word A = 2 the screen lists `Stage01` **selectable, with a High Score and Best
|
||||
Time**, and `Stage02`–`Stage08` **greyed out**. One cleared stage, one selectable
|
||||
entry, at the bit index that names it — the semantics are visible on screen, not
|
||||
inferred.
|
||||
|
||||
**And the mask drives that screen.** Two runs, identical navigation, fresh boot each:
|
||||
|
||||
| run | word A | MISSION SELECT |
|
||||
|---|---|---|
|
||||
| control | `0x00000002` (untouched) | opens; Stage01 selectable, rest greyed |
|
||||
| poked | `0xFFFFFFFF` | `MmAllocatePhysicalMemoryEx` fails on a 128 MB request, guest throws, Xenia shows "Disc Read Error" |
|
||||
|
||||
So the earlier failure was **caused by the poke**, and by a careless one: `0xFFFFFFFF`
|
||||
claims stages that do not exist (`0`, `17`, `24`–`31` in word A). Poking only real
|
||||
story ids (`0x0001FFFE` = stages 1–16) does **not** blow the heap. That the list
|
||||
screen changes behaviour with the mask is itself confirmation that word A feeds it.
|
||||
|
||||
**What the poke did not do (yet):** `EXTRAS` still shows only `MISSION SELECT /
|
||||
MOVIE THEATER / BACK` — no challenge entry — although the menu was built 26 s
|
||||
*after* the poke, so this is not staleness. Entering `MISSION SELECT` then failed,
|
||||
|
||||
Reference in New Issue
Block a user