# Design notes found by inspection - these MUST be honoured by the SwiftLink driver ## 1. The NMI handler has to survive the I/O area being banked out The game keeps its "game film" / saved-game buffer in the RAM *underneath* the I/O area, at `$D000-$DFF0`. `readFilmByte` ($5866) and `writeFilmByte` ($5893) in `disassembly/game/mainProgram0800.s` therefore do this around every single byte: sei ; NMI is NOT blocked by this - see below stx CIA2_ICR ; disable every CIA2 interrupt source (written twice as a guard) stx CIA2_ICR ldx #$34 ; bank RAM in over the whole $D000-$DFFF I/O area stx CPU_PORT lda (filmPtr),y ; touch the film buffer inc CPU_PORT ; back to $35, I/O visible again ldx ciaIcrShadow ; $E033 - the module's copy of the CIA2 mask it wants stx CIA2_ICR ; re-enable the modem's NMI sources cli For the stock driver this is airtight: its UART interrupt *is* a CIA2 interrupt, so disabling CIA2 sources really does stop it firing while the registers are hidden. **A SwiftLink interrupt is not a CIA2 interrupt.** Nothing in that sequence stops the ACIA asserting NMI, and `sei` does not mask NMI. So the handler can and will fire while `$01 = $34`, at which point `$DE00-$DE03` are ordinary RAM and the handler would read garbage, lose the received byte and possibly wedge the receiver. **Requirement:** the SwiftLink NMI handler must be bank-safe. On entry save `$01`, force it to `$35` so the ACIA is visible, do the work, then restore the saved value before `RTI`. Do this before touching any ACIA register. Remember `$01` is also the 6510 port used for the tape motor and character-ROM banking, so save and restore the whole byte, do not just write `$35` and `$34` back. **Also:** `$E033` (`ciaIcrShadow`) is still written into `CIA2_ICR` by those two routines, so it must hold a value that is correct for this driver. This driver wants no CIA2 interrupts at all, so it should hold `$7F` (clear every CIA2 source). Set it at run time - its stored byte in the module image is inside the frozen region and must not change. ## 2. Prefer base $DE00, and never index into the ACIA page by accident `loadBaudParameters` ($E353) in the stock module writes its three bytes with `sta $DF59,y` where Y is $FD/$FE/$FF, so the effective addresses are $E056-$E058. That is fine on the stock hardware, but an indexed *store* on a 6502 performs a dummy READ from the un-carried address first - here `$DF56`, `$DF57` and `$DF58`. With a SwiftLink strapped to `$DF00` those land on the ACIA's mirrored registers, and `$DF58` mirrors the **data register**, whose read consumes a received byte and clears RDRF. The replacement for `loadBaudParameters` must not use that trick. Address `$E056-$E058` directly. More generally: default the driver to `$DE00`, and document that `$DF00` is second choice. ## 3. The game also copies pages across `$D000-$DF00` `mapGenerator6F00.s` walks a source and a destination page over `$D000..$DF00` ($7F66, $816E) for the film snapshot. Those go through the same bank-out dance. Nothing extra to do, but it is another reason the handler must be bank-safe rather than relying on interrupts being masked.