8000 Threaded UI, idle-loop fast-forward, keep-awake, locked recovery points by knuckleslee · Pull Request #4 · infinition/capybara · GitHub
[go: up one dir, main page]

Skip to content

Threaded UI, idle-loop fast-forward, keep-awake, locked recovery points - #4

Open
knuckleslee wants to merge 3 commits into
infinition:mainfrom
knuckleslee:pr-features
Open

knuckleslee wants to merge 3 commits into
infinition:mainfrom
knuckleslee:pr-features

Conversation

@knuckleslee
Copy link
Copy Markdown

What

Runtime performance and usability work for the emulation loop and the interface (3 commits, see FEATURES.md for the user-facing description):

  • Threaded emulation: the machine runs on a worker thread and the UI draws from a mirror (src/fil.rs). Anything that needs the machine directly (inspection panel, open menu, serial link, local server) stops the worker and takes the machine back, so the original single-threaded path stays as the fallback.
  • Idle-loop fast-forward: a short backward branch with no store and registers identical to the previous pass is skipped by advancing the clock while peripherals are still serviced at their usual granularity; WFI is handled the same way.
  • Keep awake (menu entry, off by default, saved with the game): clears the firmware's idle count once a second of console time so the console does not decide to shut itself down.
  • Recovery points: written by a separate thread (taking one no longer stops the console) and lockable (a locked point escapes pruning and the age limit). Old indexes load with nothing locked. The rewind history now snapshots every two seconds of console time instead of twice a second.
  • Scene numbers are read from the scene descriptor instead of being deduced from the entry's position, which shifted every name by one on editions whose first descriptor has an unreadable name.
  • Small hot-path changes: burst PUSH/POP/LDM/STM use one region test when the burst fits in SRAM; Registers derives PartialEq/Eq.

Behaviour change (please read)

The fast-forward is on by default and changes default behaviour. The program reaches the same states, but the moment at which the firmware notices an event can shift by up to the maximum skip length, so step-count-driven headless runs will no longer match older logs step for step. In exchange the CPU load while idle drops a lot.

Step-exact behaviour is still available: it is disabled automatically while a serial link is open (a transfer protocol counting milliseconds needs it), and Cpu::step_exact() turns it off for tests and tools. There is no environment variable and no new setting.

I could not run a firmware regression for this branch against the upstream binary (no firmware in CI); the evidence is the test suites below plus tests/features_tests.rs, which compares the fast-forward core with the step-exact core on a polling loop.

How to test

cargo test --release: 17 + 17 + 66 + 4 + 3 tests pass; cargo build --release --all-targets builds; cargo build --release --bin capybara builds. New: tests/features_tests.rs (fast-forward ends in the same registers as the step-exact core and still leaves a loop whose polled value changes; keep-awake clears the idle count within a second; a locked recovery point survives reopening the journal and restores).

Risk / dependencies

Medium: touches app.rs, emulator/mod.rs and the CPU loop. Independent of #2 and #3 (it should merge without conflict with #3, which only touches labels and the UART1 data register in mmu/mod.rs; I did not rebase onto it). The keep-awake address is the one measured on one edition; other editions may count elsewhere.

🤖 Generated with Claude Code

knuckleslee and others added 3 commits October 17, 2026 01:55
The number was taken from the entry's position in the table, which is only
right when the name search starts at the first descriptor. On the edition
this was measured on, the first descriptor carries a broken name pointer, so
the run starts at the second one and every name from there on shifts by one
(the home and home-field screens were swapped, the download screen was
reported under its neighbour's name).

The number is written in the descriptor at +8 and is now read there. The
field is located as the one that fits in 16 bits and increases most often
from one entry to the next, the same way table_scenes_probe finds it, so the
probe and the interface cannot disagree. A perfectly increasing run is not
required: the table ends with a sentinel and an edition may have inserted a
screen. The base walks back only when the descriptors it uncovers carry the
numbers that would precede, so a misidentified field cannot shift the table
the other way.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…d recovery points

Threaded interface: the machine runs on its own thread and the interface
draws from a mirror of it (src/fil.rs), so a slow frame no longer slows the
console. Anything that needs the machine directly (inspection panel, open
menu, serial link, local server) stops the worker and takes the machine
back, which keeps the original single-threaded path as the fallback.

Idle-loop fast-forward: a short backward branch with no store and registers
identical to the previous pass is skipped by advancing the clock while the
peripherals are still serviced at their usual granularity; WFI is handled the
same way. This changes the default behaviour: events are noticed up to a
bounded number of cycles later, in exchange for a much lower CPU load. It is
switched off automatically while a serial link is open, and Cpu::step_exact()
turns it off for tests and tools.

Keep awake: clears the firmware's idle count once a second of console time
(what a button press does, without the press) so the console does not decide
to shut itself down. Off by default, saved with the game.

Recovery points: written by a separate thread, so taking one no longer stops
the console; a point can be locked so that pruning and the age limit leave it
alone. Indexes written by earlier versions load with nothing locked. The
rewind history snapshots every two seconds of console time instead of twice a
second, which removes a regular hitch.

Also adds PartialEq/Eq on Registers (used by the loop detector) and a few
hot-path adjustments in the Thumb decoders.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
FEATURES.md describes the worker thread, the idle-loop fast-forward (and how
to get step-exact behaviour), keep-awake, locked recovery points and scene
numbering. tests/features_tests.rs checks that the fast-forward ends in the
same registers as the step-exact core on a polling loop, that it still leaves
the loop when the polled value changes, that keep-awake clears the idle count
within a second, and that a locked recovery point survives reopening the
journal and restores.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

0