Skip to content

NMI break-to-monitor support (freeze / inspect / resume)#37

Open
mbrukner wants to merge 1 commit into
wildbitscomputing:masterfrom
mbrukner:pr/nmi-break-monitor
Open

NMI break-to-monitor support (freeze / inspect / resume)#37
mbrukner wants to merge 1 commit into
wildbitscomputing:masterfrom
mbrukner:pr/nmi-break-monitor

Conversation

@mbrukner

Copy link
Copy Markdown

Adds a hardware-NMI (RESTORE key + Foenix modifier) break-to-monitor dispatch, letting a debugger freeze any running program, inspect it, and resume it exactly. Two files change: f256/jr.asm (the hw_nmi dispatch, replacing the old debug stub) and kernel/kernel.asm (a one-line-guarded timebase freeze in tick).

What it does

hw_nmi:

  • Gates on the Foenix modifier; has a nested-break guard; declines a break into the monitor itself (when the victim's slot 5 is the monitor's reserved RAM bank).
  • Freezes the victim: saves registers/SP/MMU/io, and saves+clears the text/color screen into reserved RAM banks.
  • Copies the two-bank monitor image from flash into reserved RAM banks, maps both into the victim's LUT slots 4+5, and JSRs the fixed break entry under the victim's map (so the monitor sees the victim's address space).
  • On resume: restores the victim's slots, screen, io/MMU/SP/registers and RTIs back exactly.

Resume transparency

Two subtleties are handled so resume is invisible to the victim:

  • Kernel timers: tick checks platform.nmi_in_progress and skips the timebase advance + delay.dispatch while a break is active, so the victim's one-shot frame timers don't count down, expire, and get freed underneath it. The keyboard scan that follows tick in the frame IRQ still runs, so the monitor keeps input.
  • Free-running VIA IRQ: on resume, a stuck VIA T1 interrupt flag is cleared so the edge-triggered interrupt controller latches the victim's next timer tick (otherwise a game clocking itself off VIA T1 in continuous mode hangs on resume).

Testing

Hardware-verified on the F256K2: break into games (incl. VIA-timer- and kernel-timer-driven), DOS, and SuperBASIC; inspect and resume with no visible disturbance.

Notes

  • The reserved RAM banks are kept off-limits to SuperBASIC (its MaxPhysPage is lowered in that project).
  • Native-mode NMI frame handling is out of scope (all current F256 software runs in emulation mode).

Adds a hardware-NMI (RESTORE key + Foenix modifier) break-to-monitor
dispatch, letting a debugger freeze any running program, inspect it, and
resume it exactly.

hw_nmi (f256/jr.asm):
- Gate on the Foenix modifier; nested-break guard; decline a break into the
  monitor itself (victim's slot 5 is the monitor's reserved RAM bank).
- Freeze the victim: save registers/SP/MMU/io, and save+clear the text and
  color screen into reserved RAM banks.
- Copy the two-bank monitor image from flash into reserved RAM banks, map
  both into the victim's LUT slots 4+5, and JSR the fixed break entry under
  the victim's map so the monitor sees the victim's address space.
- On resume: restore the victim's slots, screen, io/MMU/SP/registers and
  RTI back exactly. Resume is transparent to the victim's timers and a
  free-running VIA IRQ:
    * kernel.tick freezes the timebase while a break is active, so the
      victim's frame timers do not expire and get freed underneath it;
    * on resume, a stuck VIA T1 interrupt flag is cleared so the
      edge-triggered interrupt controller latches the victim's next tick.

kernel/kernel.asm: tick checks platform.nmi_in_progress and skips the
timebase advance and delay.dispatch while a break handler is active; the
keyboard scan that follows in the frame IRQ still runs.

Hardware-verified on the F256K2.

Signed-off-by: Matthias Brukner <mbrukner@gmail.com>
@mbrukner
mbrukner force-pushed the pr/nmi-break-monitor branch from 5b4f936 to 0b69ed0 Compare July 17, 2026 12:41
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