# PT2 Report Aftermath ROM Trace This note tracks what the ROM does after the RCP emits an autonomous serial report from the `F870` report queue. ## Core Model The RCP report path is: ```text 3E54 / 4046 enqueue selector into F870 3FD3 checks send gates BAF2 dequeues/stages a report from F870 and E800 BA26 sends the six-byte SCI1 frame BB46-BB51 arms the continuation/resend aftermath ``` The important consequence is that `BAF2` does not advance the report consumer cursor. The emitted report remains outstanding until the host sends a valid continuation command. ## Report Queue | RAM | Role | | --- | --- | | `F870` | autonomous serial-report word ring | | `F9B0` | producer cursor | | `F9B5` | consumer/outstanding cursor | Producer paths: - `H'3E54`: when `R2.7` is set, deduplicates and appends `R3` to `F870`, then advances `F9B0`. - `H'4046-H'4070`: when heartbeat/report cadence expires and the report queue is empty, appends selector `0x0000` to `F870`. Consumer path: - `H'BAF2` compares `F9B5` against `F9B0`. - If equal, no report is pending. - If different, it reads selector `F870[ F9B5 ]`, reads the report value from `E800[selector]`, stages the outgoing frame, and calls `BA26`. - `BAF2` leaves `F9B5` unchanged. Only continuation command `4`, `5`, or `6` advances `F9B5`, and only when `FAA2.3` is still set. ## Report Send Gates `H'3FD3` allows `BAF2` only when: - `FAA2 == 0`. - `F9C0 == 0`. - If `FAA5.7` is set, `F9C3 == 0`, meaning no partial RX frame is currently being assembled. This means host RX traffic can block report sending while a session is active. ## Aftermath Window After `BA26` sends the report frame, `H'BB46-H'BB51` arms the report aftermath: | Address | Write | Meaning | | --- | --- | --- | | `H'BB00` | set `FAA2.3` | queued report needs continuation | | `H'BB46` | `F9C6 = 0x01F4` | resend spacing countdown | | `H'BB4C` | `F9C8 = 0x14` | resend/retry budget | | `H'BB51` | `FAA3 = 0x80` | live resend/window marker | While this is live, valid RX frames enter the continuation dispatcher because `FAA2 != 0`. ## Clean Continuation Consume Commands `4`, `5`, and `6` all share the same report-consume pattern: ```text if FAA2.3 set: F9B5 += 1 clear F9B5.7 clear FAA3 clear FAA2 ``` Handler addresses: | Command | Handler | Consume block | | --- | --- | --- | | `4` | `H'BD0E` | `H'BD67-H'BD79` | | `5` | `H'BD80` | `H'BDC2-H'BDD4` | | `6` | `H'BDDB` | `H'BDED-H'BDFF` | The ROM does not appear to require the continuation ACK selector to match the emitted report selector. The consume test is `FAA2.3`, not selector equality. ## Non-Clean Paths Low commands `0/1/2/3` while `FAA2.3` is live: - `H'BC5C` clears `FAA2.3`. - If the bit was set, `H'BC63` clears `FAA3`. - `H'BC67` re-enters initial dispatch. - This does not advance `F9B5`. Command `7`: - Retransmits the previous finalized TX frame through `H'BE05-H'BE25`. - Does not clear `FAA2/FAA3`. - Does not advance `F9B5`. TX/RX overlap interlock: - At `H'BA84-H'BAA7`, TXI checks `FAA2.3 && FAA5.7 && F9C3 != 0`. - If true, it clears `FAA2.3`, clears `FAA3`, disables TXI, and loads `F9C0=0x1F`. - This collapses the report window without consuming `F9B5`. - Bench implication: starting a host frame before the RCP has finished TX can destroy the very continuation window being targeted. ## Resend And Expiry `H'BE9E-H'BEE8` manages the unconsumed report aftermath: - Masks `FAA3` with `FAA5.7`. - If the session gate is gone, `FAA3` becomes zero and `FAA2` is cleared. - If `FAA3.7` is live and `F9C6 != 0`, it waits. - If `F9C6 == 0` and `F9C8 != 0`, it decrements `F9C8`, reloads `F9C6=0x01F4`, clears `F9C3`, and calls `BA26` to resend the same finalized frame. - If `F9C8 == 0`, it clears `F9C5`, forcing the broader session timeout path. So an unconsumed report can be resent repeatedly, then eventually force the session watchdog to expire. ## Session Timeout `F9C5` is the broad active-session watchdog: - A complete six-byte RX frame reloads `F9C5=0x14` at `H'BB9E`. - FRT2 decrements `F9C5` at `H'BF31-H'BF37`. - `H'3FEF` observes expiry, clears `F9B5/F9B0`, clears `FAA5.7`, and if the gate was previously live calls `H'400C`. - `H'400C -> H'4075 -> H'4217` clears broad session/display state and redraws `CONNECT:NOT ACT`. Related timers: | RAM | Role | | --- | --- | | `F9C0` | post-TX/report-send gate; decremented by FRT1 | | `F9C1` | RX inter-byte timer; partial-frame timeout | | `F9C4` | heartbeat/report enqueue cadence | | `F9C5` | active serial-session watchdog | | `F9C6/F9C8` | unconsumed report resend spacing/budget | ## Fake-CCU Implications Best pure report ACK: ```text 05 00 40 00 00 1F ``` Rationale: - Command `5` consumes the report cursor when `FAA2.3` is live. - Selector `0x0040` is not one of the known command-5 special side-effect selectors. - Value bytes are ignored by the generic command-5 consume path. Same-selector command-5 ACKs are plausible for human readability, but not ROM-required: ```text 05 00 00 00 00 5F ; ACK selector 0x0000 05 00 02 00 00 5D ; ACK selector 0x0002 05 00 07 00 00 58 ; ACK selector 0x0007 05 00 15 00 00 4A ; ACK selector 0x0015 05 01 0F 00 00 51 ; ACK selector 0x008F ``` Use command `4` only when the host intentionally wants to refresh primary/current state while consuming: ```text 04 00 00 80 00 DE ; selector-zero active refresh ``` Use command `6` only when the host intentionally wants to refresh secondary feature gates while consuming: ```text 06 00 15 00 01 48 ; E400[0x0015] = 1 06 01 0F 18 00 4A ; E400[0x008F] = 0x1800 ``` Avoid command-5 special selectors as generic ACKs unless the side effect is desired: ```text 05 00 6C 00 00 33 ; COPY completion/exit sibling 05 00 6D 00 00 32 ; COPY IN PROGRESS/start 05 00 6E 00 00 31 ; special accepted, later handler is cleanup/no-op-like ``` ## Proposed Normal Loop A plausible fake-CCU report loop is: 1. Keep the serial format at `38400 8E1`. 2. Seed active state, especially selector zero. 3. Listen for a complete RCP TX frame. 4. Wait until the RCP frame is fully transmitted. 5. Quickly send a command-5 generic ACK before `F9C6/F9C8` resend handling starts. 6. Continue sending enough valid six-byte frames to reload `F9C5` before session expiry. 7. Add command-4/command-6 state refreshes only when we intentionally want to update lamps, displays, or menu gates. This is the current best ROM-supported path for maintaining `CONNECT: OK` without accidentally consuming the report incorrectly or triggering COPY/menu side effects. ## Emulator Check Reactive emulator testing supports this model: - Seeded active state with command `0`, selector zero value `0x8080`. - Waited for a report window where `FAA2.3` and `FAA3.7` were set and SCI1 TXI was idle. - Sent `05 00 40 00 00 1F`. - The ACK path reached the command-5 consume block and advanced `F9B5`, then cleared `FAA3` and `FAA2`. - Repeating that reactive loop 12 times kept the emulated LCD at `CONNECT: OK`. Observed clean consume shape after each ACK: ```text before: FAA2=08 FAA3=80 F9B5=N after: FAA2=00 FAA3=00 F9B5=N+1 ``` A fixed-delay or extra-guard strategy was less reliable. In one run, waiting an additional 1 ms after TX idle before sending the ACK only consumed two reports before falling back to `CONNECT:NOT ACT`. That result should not be overfit as an exact real-device limit, but it reinforces the ROM timing lesson: ACK as a reaction to a finished frame, not as a loose periodic delay.