ec82764bef
RTL (GS rasterizer, EE core stub, platform bridge, LPDDR4B path), sim regression (272 TBs), docs, and tooling. Copyrighted PS2 content (BIOS, game code, GS dumps, and all dump-derived textures/traces) is excluded via .gitignore and stays local. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
191 lines
9.2 KiB
Markdown
191 lines
9.2 KiB
Markdown
# Ch269 closeout — HARD STOP: the BEQ treadmill is an artifact of our Ch215 shim
|
|
|
|
**Status:** Closed. Codex's hypothesis confirmed in one run.
|
|
**Verdict:** `v0_set_by_ch215_restore`.
|
|
|
|
> Every steady-state BEQ retire at PC=0xBFC52350 saw `$v0=1` set
|
|
> by `CH215_WAIT` — count=7 of 7. The treadmill BEQ is an
|
|
> artifact of our Ch215 jmp_buf restore shim, NOT a hidden BIOS
|
|
> load. **The post-Ch215 thunk-chain search Ch264..Ch268 is
|
|
> closed as a shim artifact.**
|
|
|
|
## The data, end to end
|
|
|
|
```
|
|
[ch269] V0_LINEAGE counters:
|
|
total $v0 changes since reset = 535323
|
|
$v0 changes in passes >= 1 = 462644
|
|
latch armed = 1
|
|
BEQ@0xBFC52350 retire_count = 9 (cap=16)
|
|
|
|
[ch269] LATCH_AT_BEQ:
|
|
[0] pass=0 $v0_at_BEQ=0x00000000 last_writer: cyc=293833 state_d1=EXECUTE pc=0xbfc4db80 v0=0x00000000 source=normal_retire
|
|
[1] pass=0 $v0_at_BEQ=0x00000001 last_writer: cyc=10194393 state_d1=CH215_WAIT pc=0x8003eec4 v0=0x00000001 source=CH215_RESTORE
|
|
[2] pass=1 $v0_at_BEQ=0x00000001 last_writer: cyc=20095043 state_d1=CH215_WAIT pc=0x8003eec4 v0=0x00000001 source=CH215_RESTORE
|
|
[3] pass=2 $v0_at_BEQ=0x00000001 last_writer: cyc=29995693 state_d1=CH215_WAIT pc=0x8003eec4 v0=0x00000001 source=CH215_RESTORE
|
|
[4] pass=3 $v0_at_BEQ=0x00000001 last_writer: cyc=39896343 state_d1=CH215_WAIT pc=0x8003eec4 v0=0x00000001 source=CH215_RESTORE
|
|
[5] pass=4 $v0_at_BEQ=0x00000001 last_writer: cyc=49796993 state_d1=CH215_WAIT pc=0x8003eec4 v0=0x00000001 source=CH215_RESTORE
|
|
[6] pass=5 $v0_at_BEQ=0x00000001 last_writer: cyc=59697643 state_d1=CH215_WAIT pc=0x8003eec4 v0=0x00000001 source=CH215_RESTORE
|
|
[7] pass=6 $v0_at_BEQ=0x00000001 last_writer: cyc=69598293 state_d1=CH215_WAIT pc=0x8003eec4 v0=0x00000001 source=CH215_RESTORE
|
|
[8] pass=7 $v0_at_BEQ=0x00000001 last_writer: cyc=79498943 state_d1=CH215_WAIT pc=0x8003eec4 v0=0x00000001 source=CH215_RESTORE
|
|
|
|
[ch269] SUMMARY (steady-state, pass>=1):
|
|
BEQ retires with $v0=1 = 7
|
|
... last writer from CH215 = 7
|
|
... last writer from normal = 0
|
|
```
|
|
|
|
Pass=0 retire [0] caught the **real BIOS setjmp() return**:
|
|
`$v0=0` from `pc=0xBFC4DB80` (EXECUTE state, normal retire).
|
|
That's the FIRST setjmp return — the path where the BEQ
|
|
takes. Then pass=0 retire [1] and all subsequent passes show
|
|
`$v0=1` from CH215_WAIT — our shim's longjmp simulation, every
|
|
10.0 M cycles like clockwork.
|
|
|
|
The cyc=10194393 → 20095043 → 29995693 → ... cadence is the
|
|
Ch215 restore firing once per Ch217 pass. The producer is
|
|
literally `regfile[2] <= 32'd1;` at
|
|
[ee_core_stub.sv:1280](rtl/ee/ee_core_stub.sv#L1280).
|
|
|
|
## What this closes
|
|
|
|
Chapters **Ch264..Ch268** were autopsying the longjmp-return
|
|
chain (callee → helper → dispatcher → kernel global) looking
|
|
for the "real polled gate." The premise was that BIOS was
|
|
gated on something the chain returned, and finding that
|
|
something would let us perturb it to break the treadmill.
|
|
|
|
That premise is now disproven:
|
|
- The BEQ at 0xBFC52350 is the post-setjmp/longjmp split.
|
|
- The reason it falls through every pass is OUR shim sets
|
|
`$v0=1`.
|
|
- The chain that runs after the BEQ does **internal
|
|
bookkeeping** (clearing 0xA000A8C8, doing INTC W1Cs) — its
|
|
output is incidental, never consumed as a gate value.
|
|
- The treadmill loops not because BIOS is waiting for a gate
|
|
to change, but because **our shim re-installs the same
|
|
longjmp context on every SYSCALL #8**.
|
|
|
|
The Ch264..Ch268 autopsies were genuinely informative (we
|
|
learned the chain's structure: three thunk-layers leading to
|
|
a leaf "clear and return"; we mapped 0xA000A8C8 as the cleared
|
|
buffer; we found I_STAT/I_MASK clears post-chain). But the
|
|
**search target was misplaced**: there is no hidden BIOS gate
|
|
in this chain because the chain itself is a no-op as far as
|
|
BIOS escape is concerned.
|
|
|
|
## What this leaves open
|
|
|
|
The **real** question, restated in light of Ch269:
|
|
|
|
> What would convince BIOS not to call SYSCALL #8 again?
|
|
|
|
The longjmp shim fires because SYSCALL #8 is invoked. If BIOS
|
|
stopped invoking it, the treadmill would break. Whatever
|
|
state SYSCALL #8 dispatches on (an exception table, a kernel
|
|
flag, an exception cause register) is what should change
|
|
between passes — and isn't, in our model.
|
|
|
|
This is **outside the scope of the BIOS-instruction-flow
|
|
autopsies**. It's a question about:
|
|
- The exception entry path that lands at SYSCALL #8
|
|
- The kernel handler that decides to re-issue SYSCALL #8 or
|
|
not
|
|
- The IOP/SBUS state that primes that handler
|
|
|
|
Codex's framing for what to do next:
|
|
|
|
1. **Stop the BIOS thunk recursion.** Done — Ch269 hard-stops
|
|
it.
|
|
2. **Treat Ch215 restore as an EXPERIMENT, not foundation.**
|
|
Future conclusions after Ch215 should be labeled "under
|
|
jmp_buf fallback semantics."
|
|
3. **Prefer subsystem modeling over hardcoded BIOS pokes.**
|
|
Ch261..Ch263 (IOP responder + INTC pulse + RAM mutation)
|
|
were the right pivot direction. Continue that line —
|
|
model a recurring IOP/SBUS responder with explicit state.
|
|
4. **Shorten chapter loops.** Ch269 itself is the model: one
|
|
question, one hard stop, one run.
|
|
|
|
## What Ch269 v2 fixed about Ch269 v1
|
|
|
|
Ch269 v1 used a 256-entry fill-from-boot array. The first
|
|
~256 `$v0` writes happen in pre-treadmill init (cycles
|
|
~6580+), so the array was full by the time the first Ch215
|
|
commit landed at cycle 10,194,393. Result: v1 reported
|
|
`v0_unchanged_in_steady_state` — a false negative caused by
|
|
instrumentation overflow, not by the underlying question.
|
|
|
|
Ch269 v2 uses a **live latch + print-at-trigger**: one
|
|
register holding the last-known `$v0` writer, refreshed every
|
|
cycle it changes, snapshotted at each PC=0xBFC52350 retire.
|
|
No depth, no overflow, no rerun. Plus pre-print
|
|
"V0_LINEAGE counters" (total changes / pass>=1 changes /
|
|
latch_armed / retire count) so a misarmed observer surfaces
|
|
immediately instead of after a 5-minute sim.
|
|
|
|
The lesson is saved as
|
|
[feedback_observer_design_for_lineage.md](file:///home/ubuntu/.claude/projects/-home-ubuntu-FPGA-Projects-retroDE-ps2/memory/feedback_observer_design_for_lineage.md):
|
|
**for "last X before event Y" questions, use a live latch +
|
|
print-at-trigger, not a fixed-depth fill-from-boot array.**
|
|
|
|
## Codex Ch269 acceptance — line-by-line
|
|
|
|
| Codex requirement | Status | Where |
|
|
|--------------------------------------------------------------------------------|--------|-------|
|
|
| Add $v0 write/commit observer around each pass | ✅ | live latch updates every cycle $v0 changes |
|
|
| Capture last $v0 writer before PC=0xBFC52350 | ✅ | latch snapshot at each BEQ retire |
|
|
| Classify as ch215_restore / normal retire / etc. | ✅ | state-lag by 1 cycle attributes the write to the FSM state that drove it |
|
|
| Print $v0 at: ch215 commit, first retire at 0xBFC52350, branch decision | ✅ | per-pass last_writer row shows cyc/state/pc/v0 at the writing instant; BEQ retire row shows $v0_at_BEQ |
|
|
| Expected verdict v0_set_by_ch215_restore | ✅ | confirmed: 7 of 7 steady-state retires |
|
|
| Hard stop on thunk-chain | ✅ | verdict explicitly states "post-Ch215 thunk-chain search Ch264..Ch268 is closed as a shim artifact" |
|
|
| Routine regression unaffected | ✅ | 157 / 157 with target off-by-default |
|
|
| One question, one run | ✅ | one build, one sim run, one verdict |
|
|
|
|
## Files changed
|
|
|
|
- `sim/tb/integration/tb_ee_core_bios_smoke.sv` — added
|
|
`\`ifdef CH269_V0_LINEAGE` block (v2: live latch + trigger
|
|
print, NOT v1's fill array). Two call sites
|
|
(`ch269_print_observer()`) in halt + timeout exits.
|
|
- `sim/Makefile` — new `tb_ee_core_bios_long_v0_lineage`
|
|
target.
|
|
|
|
## Regression
|
|
|
|
Full regression: 157 / 157 with `CH269_V0_LINEAGE` off by
|
|
default.
|
|
|
|
## Recommendation for Codex's next call
|
|
|
|
Per Codex's broader steering:
|
|
|
|
> Next substantive work should be either:
|
|
> - model a minimal recurring IOP/SBUS responder with
|
|
> explicit state, OR
|
|
> - step back to hardware-facing deliverables where progress
|
|
> is more directly testable.
|
|
|
|
**My read on Ch270 direction:** the Ch261..Ch263 work
|
|
already established that we can compose IOP-side state into
|
|
the EE map (the IOP responder + bridge + EE-visible
|
|
mutation chain). What's missing is the *recurring* part —
|
|
state that advances between Ch217 passes. A first try:
|
|
ramp the IOP responder's behavior so that each invocation
|
|
posts a slightly different value into a kernel-readable
|
|
location, and observe whether BIOS's SYSCALL #8 dispatch
|
|
behavior changes when that value progresses past some
|
|
threshold. That's harder to scope cleanly than Ch269 (it's
|
|
not a single-question chapter), but it's the path to a
|
|
genuine BIOS-state advance.
|
|
|
|
Alternatively the hardware-facing path: pivot to bringing
|
|
up something testable on real silicon (e.g., the OSD,
|
|
input → behavior, or VRAM read-back integrity on the
|
|
DE25-Nano) and treat the BIOS bringup as on-hold until the
|
|
IOP-side modeling matures. The user can pick which suits
|
|
their immediate priorities better.
|
|
|
|
**Standing by — and not recursing further down the
|
|
post-Ch215 BIOS thunk chain.**
|