re: read_freg counts SECONDS -- the 32 "flags" are a stopwatch bank
The open question was the unit, not the array. Following the writers of
[phase+88] settles it:
* sub_822710D0(phase, dt), called from ScriptPhase::Update, does
prev[i] = cur[i] then, only while [phase+120][i] == 1, cur[i] += dt --
so +88/+104/+120 are current / previous / running, 32 entries each.
* dt is seconds by a non-circular round trip: frames * (1/60) * 10000
-> clamp 3200 -> * 1e-4, in the timing singleton at [0x828F35B4].
The clamp is 0.32 s, a frame ceiling.
* 675/675 timeline kinds are indices their own phase starts (control
11.2 %), which is why kind is only ever 0 or 5.
Corrects isl-builtins.md twice: set_flag writes 0.0 not 1.0, and
clear_flag clears the running flag rather than the value. Confirms its
grouping of 8/9/93 as one family. Docs only -- all seven ISL artefacts
regenerate byte-identical.
This commit is contained in:
@@ -249,6 +249,50 @@ unknown, what evidence exists, and what the first step would be. Move an item in
|
||||
INFERRED from the 210/300/600/1200 gate values, exactly as before. 🟡 Also open:
|
||||
what writes `[phase+88]` — 73 writers in the ISL region alone.
|
||||
|
||||
* ✅🔴 **(2026-08-27) THE UNIT IS SETTLED — `read_freg` RETURNS SECONDS, and the
|
||||
three "flag" built-ins are a STOPWATCH BANK. [structures/isl-timers](structures/isl-timers.md).**
|
||||
Last iteration found what `read_freg` reads and said plainly it had *not*
|
||||
answered the item, which was the unit. Following the writers does.
|
||||
**`[phase+88]`, `[phase+104]`, `[phase+120]` are three parallel 32-entry
|
||||
arrays**, cleared together by the phase initialiser in one unrolled loop
|
||||
(bases 12/44/76/108, offsets 0…127). **`sub_822710D0(phase, dt)` — called from
|
||||
`ScriptPhase::Update` at `0x82263480` with Update's own float passed straight
|
||||
through — does `prev[i] = cur[i]` then `if running[i] == 1: cur[i] += dt`.**
|
||||
So `[phase+104]` is last frame's value and `[phase+120]` the running flag, and
|
||||
the walker's `prev <= t < cur` is "did timer `kind` cross `t` this frame".
|
||||
🔑 **`dt` is SECONDS, by a round trip that is not circular**: the frame loop
|
||||
`sub_821AA1B0` computes `frames × (1/60)` (`0x8289A0F8` = 0.016666668), turns
|
||||
it into integer ticks with `× 10000.0` (`0x820A13B4`), **clamps at 3200**, and
|
||||
`sub_821A49A8` scales back by `1e-4` (`0x8289A0FC`) into the timing singleton
|
||||
at `[0x828F35B4]` — `+8` for the script VM, `+16` for the flight code. Produced
|
||||
as seconds × 10⁴, consumed as × 10⁻⁴; the clamp is **0.32 s**, a frame ceiling.
|
||||
✅ **Refutation test, 675 / 675 vs an 11.2 % control**: if a timer only runs
|
||||
once started, every timeline `kind` must be an index its own phase starts —
|
||||
and every one is. That is also why `kind` is only ever 0 or 5: **every phase
|
||||
opens `set_flag(5); set_flag(0)`.** Artefact `data/isl-timers.txt`; all seven
|
||||
existing artefacts regenerate **byte-identical**.
|
||||
🔴 **Two corrections to `isl-builtins.md`.** `set_flag(i)` writes **`0.0`**,
|
||||
not `1.0` — the constant at `0x8209FD28` is literally zero, the same one the
|
||||
initialiser clears with; and `clear_flag(i)` does **not** zero the value, it
|
||||
clears `[phase+120][i]` only (all 133 sites disc-wide pass **−1** = all 32, in
|
||||
the teardown `reset_phase_threads ; timer_stop ; clear_flag(-1)`). So the
|
||||
family is start / read / stop, and the earlier "latch" reading was a timeout
|
||||
all along. ✅ The corpus's grouping of 8/9/93 is **confirmed** — `[phase+120]`
|
||||
is this family's *running* column, not a different array as last iteration's
|
||||
note allowed.
|
||||
⚠️ **The first run of the test scored 433/675 and looked like a real
|
||||
refutation** (misses all `kind = 0`, in a coherent block of stages). Cause:
|
||||
`isl.dis` defaults to `stop_at_ret=True`, so a `set_flag` at the *start* of a
|
||||
coroutine lost its operand staging to the preceding `ret`. Checked before
|
||||
believing — the corpus's own trap, paid again.
|
||||
🟡 Not settled: the **names** (`set_flag`/`read_freg`/`clear_flag` describe
|
||||
none of this, but 127/123/124 already hold `timer_set`/`timer_resume`/
|
||||
`timer_stop` for a different timer, so renaming is its own change); one
|
||||
exception, `read_freg(15)` in Stage 06 phase 1 has no `set_flag(15)` in that
|
||||
phase; the three scale fields `s24`/`s40`/`s44` (all 1.0 at construction) have
|
||||
no writer searched for — a game-speed setter would be one; and 31 `read_freg`
|
||||
sites index by a computed value rather than an immediate.
|
||||
|
||||
## ✅✅ SOLVED — the mission freeze was a modal sign-in dialog (2026-08-26)
|
||||
|
||||
`XamShowSigninUI` opens a modal dialog and `xeXamDispatchDialog` blocks the
|
||||
|
||||
@@ -98,6 +98,7 @@ files, which is how the same ground got covered twice.
|
||||
| [`structures/sound-pak-contents.md`](structures/sound-pak-contents.md) | Census of `sound.pak`, and the limit of the leading-region rule | ✅ CONFIRMED, 5 135/5 135 names hash into the TOC, **9 519/9 519** entries accounted for, and a full 4 114-bank manifest (408.3 min of audio) computed from PsuedoBytesPerSec without decoding; ⚠️ leading-region rule holds for 1 571/4 382 eng and 0/5 100 jpn |
|
||||
| [`structures/sound-cue-table.md`](structures/sound-cue-table.md) | The cue index in `tables.pak` — message id -> cue -> sound id -> `.slb` bank | ✅ CONFIRMED, 1 326/1 338 script message ids bind to a bank; SOUNDS and FILES agree on the same 12 absentees, 0 orphan files |
|
||||
| [`structures/cutscene-message-table.md`](structures/cutscene-message-table.md) | Cutscene dialogue — speaker, portrait, on-screen seconds, audio cue per page | ✅ CONFIRMED, field count = 9·PageCount+2 for all 7 PageCounts, 1 252/1 252 caption keys match, 138 ids close both ways |
|
||||
| [`structures/isl-timers.md`](structures/isl-timers.md) | A ScriptPhase owns 32 stopwatches, and they count seconds | ✅ CONFIRMED — the advance is read from `sub_822710D0`, the unit from |
|
||||
| [`structures/isl-message-dialogue-link.md`](structures/isl-message-dialogue-link.md) | Mission scripts as dialogue — built-in 64 -> message id -> caption text | ✅ CONFIRMED total, 2 683/2 683 call sites across all 28 stages resolve, no residue |
|
||||
| [`structures/mission-objective-counter.md`](structures/mission-objective-counter.md) | `REMAINING OB` — the mission's own objective counter, in RAM | ✅ CONFIRMED for one Stage 02 run: a big-endian u32 whose value |
|
||||
| [`structures/movie-subtitles.md`](structures/movie-subtitles.md) | Movie subtitles & the movie ↔ mission ↔ text chain | — |
|
||||
|
||||
61
docs/re/data/isl-timers.txt
Normal file
61
docs/re/data/isl-timers.txt
Normal file
@@ -0,0 +1,61 @@
|
||||
# The 32 per-phase stopwatches -- set_flag / read_freg / clear_flag vs the timeline
|
||||
|
||||
Written by hand from tools/re-capture/isl.py; see docs/re/structures/isl-timers.md.
|
||||
|
||||
Claim under test: `[phase+88][i]` only advances while `[phase+120][i] == 1`,
|
||||
and built-in 8 is the only thing that sets that flag. So every timeline
|
||||
entry's `kind` must be an index its own phase starts, or the entry is dead.
|
||||
|
||||
file phase set_flag(i) started read_freg(i) timeline kinds
|
||||
Stage01.ssb 1 [0, 5, 14] [0] {0: 27, 5: 3}
|
||||
Stage01.ssb 2 [0, 5, 14] [0] {0: 24, 5: 3}
|
||||
Stage02.ssb 1 [0, 5, 8] [0, 8] {0: 21, 5: 4}
|
||||
Stage02.ssb 2 [0, 5, 8, 14, 15] [0, 8] {0: 10, 5: 3}
|
||||
Stage02.ssb 3 [0, 5, 14, 15] [0] {0: 14, 5: 4}
|
||||
Stage03.ssb 1 [0, 5, 14] [0] {0: 16, 5: 4}
|
||||
Stage03.ssb 2 [0, 1, 5, 14] [0, 1, 14] {0: 29, 5: 3}
|
||||
Stage03.ssb 3 [0, 1, 5, 14, 15] [0, 1] {0: 14, 5: 3}
|
||||
Stage04.ssb 1 [0, 5, 14] [0, 14] {0: 8, 5: 3}
|
||||
Stage04.ssb 2 [0, 1, 5, 14] [0, 1] {0: 13, 5: 3}
|
||||
Stage05.ssb 1 [0, 1, 5] [0, 1] {0: 16, 5: 3}
|
||||
Stage05.ssb 2 [0, 5, 8] [0, 8] {0: 6, 5: 3}
|
||||
Stage06.ssb 1 [0, 5] [0, 15] {0: 18, 5: 3}
|
||||
Stage06.ssb 2 [0, 5, 14, 15] [0] {0: 6, 5: 3}
|
||||
Stage06.ssb 3 [0, 1, 5, 14, 15] [0, 1, 15] {0: 7, 5: 3}
|
||||
Stage07.ssb 1 [0, 5, 15] [0, 15] {0: 10, 5: 3}
|
||||
Stage07.ssb 2 [0, 5, 15] [0, 15] {0: 3, 5: 3}
|
||||
Stage08.ssb 1 [0, 1, 5, 15] [0, 1, 15] {0: 17, 5: 5}
|
||||
Stage08.ssb 2 [0, 5, 15] [0, 15] {0: 13, 5: 3}
|
||||
Stage09.ssb 1 [0, 5, 14, 15] [0] {0: 10, 5: 3}
|
||||
Stage09.ssb 2 [0, 5, 14] [0] {0: 7, 5: 3}
|
||||
Stage09.ssb 3 [0, 5, 14, 15] [0] {0: 11, 5: 3}
|
||||
Stage10.ssb 1 [0, 5, 14, 15] [0] {0: 8, 5: 3}
|
||||
Stage11.ssb 1 [0, 5] [0] {0: 14, 5: 3}
|
||||
Stage11.ssb 2 [0, 5, 15] [0, 15] {0: 5, 5: 3}
|
||||
Stage12.ssb 1 [0, 1, 5, 15] [0, 1, 15] {0: 17, 5: 3}
|
||||
Stage13.ssb 1 [0, 2, 5, 15] [0, 2, 15] {0: 25, 5: 3}
|
||||
Stage14.ssb 1 [0, 5, 15] [0, 15] {0: 8, 5: 3}
|
||||
Stage14.ssb 2 [0, 5, 15] [0, 15] {0: 11, 5: 3}
|
||||
Stage15.ssb 1 [0, 5, 15] [0, 15] {0: 20, 5: 3}
|
||||
Stage15.ssb 2 [0, 5, 10, 15] [0, 10, 15] {0: 21, 5: 3}
|
||||
Stage16.ssb 1 [0, 5] [0] {0: 17, 5: 3}
|
||||
Stage18.ssb 1 [0] [] {0: 3}
|
||||
Stage19.ssb 1 [0] [] {0: 3}
|
||||
Stage20.ssb 1 [0] [] {0: 3}
|
||||
Stage21.ssb 1 [0] [] {0: 3}
|
||||
Stage22.ssb 1 [0] [] {0: 3}
|
||||
Stage23.ssb 1 [0] [] {0: 3}
|
||||
Stage24.ssb 1 [0, 1, 5] [0, 1] {0: 11, 5: 3}
|
||||
Stage25.ssb 1 [0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21] [0, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21] {0: 14, 5: 3}
|
||||
Stage26.ssb 1 [0, 5] [0] {0: 22, 5: 3}
|
||||
Stage27.ssb 1 [0, 5] [0] {0: 16, 5: 3}
|
||||
Stage28.ssb 1 [0, 5] [0] {0: 5, 5: 3}
|
||||
Stage29.ssb 1 [0, 5] [0] {0: 24, 5: 3}
|
||||
|
||||
timeline entries whose kind is started in the same phase : 675 / 675 = 100.0%
|
||||
entry-weighted control (a random index in 0..31) : 11.2%
|
||||
read_freg indices started in the same phase : 82 yes / 1 no ['Stage06.ssb ph1 read_freg(15)']
|
||||
|
||||
set_flag argument histogram: {0: 44, 1: 10, 2: 1, 4: 2, 5: 38, 6: 2, 7: 2, 8: 5, 9: 2, 10: 4, 11: 2, 12: 1, 13: 1, 14: 21, 15: 24, 16: 1, 17: 3, 18: 3, 19: 2, 20: 2, 21: 2}
|
||||
read_freg argument histogram: {0: 105, 1: 13, 2: 2, 4: 1, 6: 2, 7: 2, 8: 5, 9: 2, 10: 3, 11: 2, 12: 3, 13: 1, 14: 5, 15: 28, 16: 1, 17: 3, 18: 3, 19: 2, 20: 2, 21: 2, None: 31}
|
||||
clear_flag argument histogram: {-1: 133}
|
||||
@@ -83,7 +83,7 @@ two tables already parsed in [mission-script-ssb](mission-script-ssb.md).
|
||||
| **33 / 34** | `global_counter0/1` | two global counters read straight into `[+164]` |
|
||||
| **132–134** | player gauges | speed/boost ratios and a player byte |
|
||||
| **73, 123–127** | timer family | start / resume / stop / reset / read elapsed / read limit |
|
||||
| **8 / 9 / 93** | `set_flag` / `read_freg` / `clear_flag` | latch a result into the 32-entry files |
|
||||
| **8 / 9 / 93** | `set_flag` / `read_freg` / `clear_flag` | start / read / stop one of 32 **stopwatches** — [isl-timers](isl-timers.md); the names predate the reading |
|
||||
| **100 / 115** | `reset_phase_threads` / `named_event` | ❌ 100 is **not** `push_trigger` — see below |
|
||||
|
||||
**The state machine is therefore:** a trigger fires a coroutine → the coroutine
|
||||
@@ -690,6 +690,33 @@ That closes the middle of the `set_flag → … → END_PHASE` chain: a conditio
|
||||
coroutine latches a flag, and another coroutine reads it back with `read_freg`
|
||||
and branches on it.
|
||||
|
||||
### 🔴 CORRECTION (2026-08-27) — it is not a latch, it is a STOPWATCH
|
||||
|
||||
Two things above are wrong, and the second follows from the first.
|
||||
Full reading in **[isl-timers](isl-timers.md)**.
|
||||
|
||||
* **`set_flag(i)` writes `0.0`, not `1.0`.** The constant it loads
|
||||
(`addis 0x820A ; addi -724 ; lfs f0,-4(r10)` → `0x8209FD28`) is literally
|
||||
`0.0` — the same constant the phase initialiser uses to clear the array.
|
||||
* **`clear_flag(i)` does not zero entry `i`.** It writes `[phase+120][i] = 0`
|
||||
only; the value in `[phase+88][i]` is left alone. All 133 call sites disc-wide
|
||||
pass **−1**, which clears all 32 flags.
|
||||
|
||||
The array is not a flag file. `sub_822710D0`, called every frame from
|
||||
`ScriptPhase::Update`, does `[phase+104][i] = [phase+88][i]` and then
|
||||
`[phase+88][i] += dt` **for every i whose `[phase+120][i] == 1`**. So:
|
||||
|
||||
```
|
||||
set_flag(i) -> START/RESTART timer i (value 0.0, running 1)
|
||||
read_freg(i) -> SECONDS since that start, as a double in [phase+176]
|
||||
clear_flag(i) -> STOP timer i (or all 32 for i = -1); value retained
|
||||
```
|
||||
|
||||
`dt` is seconds — `frames * (1/60) * 10000` ticks, clamped at 3200, scaled back
|
||||
by `1e-4`. The `set_flag → … → END_PHASE` chain is still real, but it is a
|
||||
*timeout*, not a latch: the condition coroutine starts a clock and a later one
|
||||
branches on how long it has run.
|
||||
|
||||
## 🟡 `op10` + `op13` look like a switch
|
||||
|
||||
Seen repeatedly, e.g. at `0x5774`:
|
||||
|
||||
@@ -143,8 +143,17 @@ inference from the layout; it is now a read.
|
||||
## 🟡 Not settled
|
||||
* **This is not what starts the unreachable code.** All 675 targets are already
|
||||
reachable — **0 are unreached run-starts** — so the ~15 % gap stands.
|
||||
* **What the six clocks are.** `kind` indexes arrays at `[phase+88]` and
|
||||
`[phase+104]`; only indices 0 and 5 are ever used by the data, and neither
|
||||
array's contents were traced to a source.
|
||||
* ~~**What the six clocks are.**~~ ✅ **SETTLED — [isl-timers](isl-timers.md).**
|
||||
The two arrays are a bank of **32 stopwatches**: `[phase+88]` is the current
|
||||
value, `[phase+104]` last frame's, `[phase+120]` a *running* flag, and
|
||||
`sub_822710D0` — called from `ScriptPhase::Update` — does
|
||||
`prev[i] = cur[i]; if running[i] then cur[i] += dt` every frame. Built-in 8
|
||||
starts a timer, 9 reads it, 93 stops it. So the walker's `prev <= t < cur`
|
||||
test is "did timer `kind` cross `t` this frame", and **`t` is in SECONDS** —
|
||||
`dt` is `frames * (1/60) * 10000` ticks scaled back by `1e-4`, clamped at
|
||||
3200 ticks = 0.32 s. That the numbers in the table *looked* like mission times
|
||||
is no longer the evidence. **675 / 675 timeline entries name a timer their own
|
||||
phase starts** (control 11.2 %), which is why `kind` is only ever 0 or 5:
|
||||
every phase opens `set_flag(5); set_flag(0)`.
|
||||
* **`sub_822737C8`**, which actually starts the routine, is not read — it is
|
||||
presumably the same spawner `start_coroutine` uses, but that is unchecked.
|
||||
|
||||
122
docs/re/structures/isl-timers.md
Normal file
122
docs/re/structures/isl-timers.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# ✅ A ScriptPhase owns 32 STOPWATCHES, and they count SECONDS
|
||||
|
||||
`read_freg`'s unit was the open question: the corpus knew the built-in returns a
|
||||
float out of `[phase+88]`, and that *seconds* was the unit had only ever been
|
||||
**inferred** from the values a mission compares it against (210, 300, 600, 1200).
|
||||
It is now read, end to end, from the code that advances it.
|
||||
|
||||
## The three parallel arrays
|
||||
|
||||
The phase initialiser `sub_82270DF8` clears three arrays in one unrolled loop
|
||||
(`0x82270EC0`–`0x82270FAC`), eight words per iteration, base `12, 44, 76, 108`
|
||||
— **32 entries each, offsets 0…127**:
|
||||
|
||||
| field | type | init | meaning |
|
||||
|---|---|---|---|
|
||||
| `[phase+88][i]` | f32 | 0.0 | the timer's **current** value |
|
||||
| `[phase+104][i]` | f32 | 0.0 | its value **last frame** |
|
||||
| `[phase+120][i]` | int | 0 | **1 = running** |
|
||||
|
||||
`sub_822700C0` clears the same three the same way (the phase reset).
|
||||
|
||||
## What advances them — `sub_822710D0(phase, dt)`
|
||||
|
||||
Called from **`ScriptPhase::Update` (`sub_82263408`) at `0x82263480`**, with
|
||||
Update's own float argument passed straight through (`fmr f30,f1` … `fmr f1,f30`).
|
||||
The body is the same eight-way unrolled shape, and per entry it is exactly:
|
||||
|
||||
```
|
||||
82271100 stfsx f0, r11, r9 ; prev[i] = cur[i] ([+104] <- [+88])
|
||||
82271104 lwz r10, 120(r31)
|
||||
8227110C cmpi cr6, 0, r10, 1
|
||||
82271110 bc 4, eq, ... ; skip unless running[i] == 1
|
||||
8227111C fadds f0, f31, f0 ; cur[i] += dt
|
||||
82271120 stfsx f0, r11, r10
|
||||
```
|
||||
|
||||
## The three built-ins are one family — start / read / stop
|
||||
|
||||
`isl-builtins.md` groups 8, 9 and 93 together; that grouping is **confirmed**, but
|
||||
the names are wrong. All three are inline in the dispatch switch `sub_82272220`,
|
||||
and all three bounds-check `0 <= local[0] < 32` — the array length above.
|
||||
|
||||
| built-in | corpus name | what it actually does |
|
||||
|---|---|---|
|
||||
| 8 | `set_flag` | `cur[i] = 0.0` (the constant at `0x8209FD28` is literally `0.0`) **and** `running[i] = 1` — *start / restart timer i*; returns 1 |
|
||||
| 9 | `read_freg` | returns `cur[i]` — as a **double** into `[phase+176]`, not `[phase+164]` |
|
||||
| 93 | `clear_flag` | `running[i] = 0`; **`i == -1` clears all 32** (`0x82273078`, loop to 128 step 4) — *stop*, without resetting the value |
|
||||
|
||||
`clear_flag` is called **133 times disc-wide and every one passes −1**, always in
|
||||
the sequence `reset_phase_threads ; timer_stop ; clear_flag(-1)` — a phase
|
||||
teardown. So `[phase+120]` is not "a different 32-entry array" belonging to some
|
||||
other family, as the previous iteration's note allowed for: it is the *running*
|
||||
column of this one.
|
||||
|
||||
## ✅ The unit: SECONDS, by four constants
|
||||
|
||||
`dt` comes from a 48-byte timing singleton at `[0x828F35B4]` (constructed by
|
||||
`sub_8231A830`), field `+8`. Its value is built in the frame loop
|
||||
`sub_821AA1B0` and in `sub_821A49A8`:
|
||||
|
||||
```
|
||||
821AA2F8 lfs f0, -24328(r11) ; 0x8289A0F8 = 0.016666668 == 1/60
|
||||
821AA300 fmuls f13, f31, f0 ; f31 = frames elapsed -> SECONDS
|
||||
821AA308 lfs f0, 5772(r25) ; 0x820A13B4 = 10000.0
|
||||
821AA30C fmuls f0, f13, f0
|
||||
821AA310 fctiwz f0, f0 ; ticks = round(seconds * 10000) [100 us]
|
||||
821AA32C cmpi cr6, 0, r29, 3200 ; clamp -> 0.32 s max frame
|
||||
821AA390 lfs f0, -24324(r11) ; 0x8289A0FC = 1e-4
|
||||
821AA398 fmuls f0, f13, f0
|
||||
821AA39C stfs f0, 12(r11) ; [obj+12] = ticks * 1e-4 -> SECONDS again
|
||||
```
|
||||
|
||||
and `sub_821A49A8` writes the two scaled copies the game actually reads —
|
||||
`[obj+16] = ticks·s24·1e-4·s44` and **`[obj+8] = ticks·s40·1e-4`**, where
|
||||
`s24 = s40 = s44 = 1.0` at construction (`0x8208583C`). `[obj+16]` is the field
|
||||
the flight/physics code reads (≈40 sites in `0x8238…`–`0x823B…`); `[obj+8]` is
|
||||
the one the script VM gets.
|
||||
|
||||
The round-trip is what makes this **non-circular**: the value is produced as
|
||||
`seconds × 10000` and consumed as `× 1e-4`. It is seconds on both ends, and the
|
||||
clamp is `3200` ticks = **0.32 s** — a frame-time ceiling, which is only a
|
||||
sensible number in seconds.
|
||||
|
||||
> ⇒ **`read_freg(i)` returns the number of SECONDS since `set_flag(i)`.**
|
||||
|
||||
## ✅ The refutation test — and it passes 675 / 675
|
||||
|
||||
If these really are stopwatches that only run once started, then every
|
||||
**timeline** entry ([isl-schedule](isl-schedule.md)) must name a timer its own
|
||||
phase starts — otherwise `cur` and `prev` both stay `0.0` and the walker's fire
|
||||
test `prev <= t < cur` can never be true, and the entry would be dead.
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| timeline entries whose `kind` is started by `set_flag` **in the same phase** | **675 / 675 = 100 %** |
|
||||
| entry-weighted control (a random index 0…31) | **11.2 %** |
|
||||
| `read_freg` indices started in the same phase | 82 / 83 |
|
||||
|
||||
Every phase opens with `set_flag(5)` and `set_flag(0)` — which is why `kind` only
|
||||
ever takes the values 0 and 5. Indices used disc-wide run 0…21, inside the
|
||||
bounds check.
|
||||
|
||||
⚠️ **The first run of this test scored 433/675 and was wrong.** `isl.dis`
|
||||
defaults to `stop_at_ret=True`, so a `set_flag` sitting at the *start* of a
|
||||
coroutine lost its operand staging to the preceding `ret` and came back
|
||||
unresolved. With `stop_at_ret=False` all 172 `set_flag` arguments resolve. The
|
||||
failure looked exactly like a real refutation (the misses were all `kind = 0`,
|
||||
in a coherent block of stages) — checked before believing.
|
||||
|
||||
## 🟡 What this leaves
|
||||
|
||||
* The **naming**. `set_flag` / `read_freg` / `clear_flag` describe none of this;
|
||||
`timer_start` / `timer_elapsed` / `timer_stop` would. They are not renamed here
|
||||
because built-ins 127/123/124 already hold `timer_set` / `timer_resume` /
|
||||
`timer_stop` in the corpus for a *different* timer, and untangling the two is
|
||||
its own change. Every artefact regenerates byte-identical as a result.
|
||||
* The **one exception**: `read_freg(15)` in Stage 06 phase 1 is not started by a
|
||||
`set_flag(15)` in that phase. Cross-phase carry-over or a start in the
|
||||
unreached code — not chased.
|
||||
* `s24` / `s40` / `s44` are never written after construction *in any site read
|
||||
here*; a game-speed or slow-motion setter was not searched for.
|
||||
* The 31 `read_freg` sites whose index is computed rather than immediate.
|
||||
Reference in New Issue
Block a user