MEGA65 / mega65-rom-public

MEGA65 ROM public issue reporting
4 stars 0 forks source link

SYS option to leave BASIC IRQ enabled during the call #144

Open dansanderson opened 3 days ago

dansanderson commented 3 days ago

When a BASIC program calls a machine code routine with SYS, the SYS call pauses the BASIC IRQ routines for music, sound, and sprite movement animation so that it can change the MAP from the BASIC MAP to the SYS MAP. This is managed with a KERNAL variable flag that indicates whether the BASIC MAP is present, needed to prevent the KERNAL IRQ handler from calling the BASIC IRQ routines when not using the BASIC MAP.

Gurce noticed this while writing a demo that uses both BASIC PLAY music and machine code helper routines. As a workaround, he experimented with changing the KERNAL IRQ to read MAP via a Hyppo call, set the BASIC MAP, call the BASIC IRQ routines, then restore the previous MAP. This was successful enough that we could consider a version of this as an opt-in feature for the SYS command.

Proposal: Implement a new argument to the SYS command that would signal to the KERNAL IRQ handler to use this MAP-flipping behavior. Instead of skipping the BASIC IRQs, the KERNAL IRQ handler would change MAPs to execute the BASIC IRQs, then change back. Without the argument or with its default value, SYS would behave as before, pausing BASIC IRQs.

Important: Gurce discovered that the Hyppo call that provides access to the MAP register is broken in core v0.96. As of this writing, there is a fix for this on the development branch of mega65-core. This fix would be a dependency for this feature request.

Today, SYS is all positional arguments, so the smallest change to add this flag would be:

SYS <addr>,<a>,<x>,<y>,<z>,<s>,<interrupt-mode>

SYS $C050,,,,,,1

Given that there is another feature request for SYS on the table that adds an "offset" argument, we might want to consider a new syntax for SYS that accepts optional keyword-style arguments. We can't just add this to SYS, so I propose SYS TO as a keyword prefix for this syntax:

SYS TO <addr>,A<a>,X<x>,Y<y>,Z<z>,S<s>,O<offset>,I<interrupt-mode>

SYS TO $C050,I1

Alternatives considered We could make this MAP-flipping behavior non-optional, and just have this be what the KERNAL IRQ handler does always. I'm concerned that this would impinge on the expectations of the common case where an ML program is bootstrapped by a SYS call, but it otherwise doesn't need or expect the BASIC IRQ routines to run. Pure ML programs don't otherwise have a documented way to disable the IRQ-driven multimedia features of BASIC65. I'm vaguely concerned about the performance impact, but mostly I'm just worried that it's already difficult to reason about the way the KERNAL manipulates MAP. So I'm wary of making it the default.

A more limited version of this that wouldn't require MAP flipping would be a flag that tells SYS to keep the BASIC MAP throughout the entire ML routine, and keep BASIC IRQs active. This would put tight restrictions around the ML code: it could only live in $1600-$1EFF, the only 16-bit address range available to ML code with the BASIC MAP active. This was infeasible in the case of Gurce's demo.

We could do nothing, and just document that BASIC music, sound, and sprite graphics will pause during SYS calls. This keeps things relatively simple, in exchange for restricting mixing BASIC and ML for games and demos. I'm personally in favor of a feature like this to support BASIC+ML being a gradual learning ramp for programmers. Enhancing a BASIC program with small ML routines is a great way to learn ML.