mk90.basic

BASIC runtime

Verified executable loading, bounded VM state and system I/O.

Load and initialization

EXEC opens the file, validates the 16-byte MBX1 header, checks its declared length, and reads the complete file through EOF to verify its inode checksum. Only then does it begin bytecode execution.

A–Z are zeroed, control/operand counts reset, and the pseudorandom seed set to 1. The executable reader remains open to keep its extent allocated. Source text is not retained or reparsed.

Bytecode execution

The VM fetches through a 256-byte cache. It checks fetch bounds, opcode range, variable indexes, branch bounds, operands and control stack. Multi-byte bytecode operands are decoded bytewise, so unaligned byte offsets are allowed.

The upper native module contains dispatch, fetch, arithmetic and control flow. Lower phases implement devices, graphics and files. Every phase completes in the upper dispatcher before a replacement module is loaded. Native dispatch pointers are part of the verified firmware, not supplied by the MBX program.

These are bounded runtime checks, not complete static proof of arbitrary bytecode. Branch range checking does not prove that a manually crafted target is an instruction boundary. Use executables produced by the matching compiler.

Scheduling and cancellation

The VM is the foreground PID 3. It checks keyboard and yields every 32 opcodes; WAIT and INPUT also cooperate. Native COUNT/PULSE workers can continue. The shell does not accept another command until the VM ends.

SU+C ends a loop at the next cancellation check, recording result 130 without printing a normal BASIC error banner. Up-arrow has the same translated code. A long WAIT or bounded I/O operation can delay the next check. The cancellation poll may consume other keys, so INKEY should not be treated as a lossless event queue.

Display, sound and RTC

PRINT/LOCATE use the text console. PSET/PRESET/LINE update individual framebuffer bits; CLS clears all pixels and the text state. Text rendering can subsequently replace graphics in its glyph area.

BEEP uses the standard tone; SOUND supplies raw divisor/cycle values. WAIT and TICKS use nominal RTC ticks, not emulator instruction counts. HOUR/MINUTE/SECOND read RTC components independently. No UART is exposed to BASIC.

Files and cache ownership

One data handle is available in addition to the executable reader. OPEN resolves ordinary MKS2 paths; GET/PUT buffer individual bytes into sector operations. Output has a declared final length and is published only on successful CLOSE or END.

The VM’s bytecode cache uses VERIFY. File calls which can change that scratch buffer invalidate the cache before another instruction fetch. TMP remains available to the data file. Device reads use the registered block abstraction with the executable’s pinned extent; BASIC has no raw sector-write instruction.

End and cleanup

END/STOP closes the data handle, committing only complete output. Runtime errors and SU+C abort an unpublished writer, release handles and restore the shell continuation. Files already closed successfully remain saved. An incomplete automatic close is reported as a failure, not silent success.

There is only one VM instance, no BASIC background launch, no pipe integration and no shared variable state between executions.