User and system reference for the Elektronika MK90.
Overview
MK90/Unix is a compact operating system for a 16 KiB MK90, booted from a 32 KiB 27C256 cartridge. It provides a Unix-style command shell, MKS2 files and directories, a text editor, cooperative multiprogramming, a two-process pipe and the on-device MBC-16 BASIC compiler.
This is the reference for the distributed 0.7 binary. Command names and BASIC keywords are shown exactly as entered. Firmware messages, command guides and this reference are in English.
Command, language and system entries, with offline search.
Quick start
With a writable, already formatted MKS2 data cartridge in SMP1:
mount /dev/smp1 /mnt/smp1
cp /mnt/smp0/demo.bas /mnt/smp1/demo.bas
cd /mnt/smp1
mbc demo.bas
./demo.mbx
For installation and first-time formatting, see Getting started.
Release scope
Area
Implemented in 0.7
Shell
33 names; space-separated arguments; a single two-stage pipeline.
Multiprogramming
Four fixed context slots: shell, foreground child and two background slots; cooperative scheduling.
Storage
SMP driver, fixed mountpoints and MKS2; one partition per supported-size volume.
BASIC
MBC-16 signed 16-bit integer subset, compiled to MBX1 bytecode.
Expansion
UART, floppy and CF drivers are not present.
The Unix-style interface does not imply Linux, POSIX, ELF or a general PDP-11 operating-system ABI. See Limits and compatibility.
Release and distribution
Official binaries are freeware; operating-system source code remains private. Copyright and distribution policy. The HTML manual works offline after extraction: open index.html. It uses local assets and does not need a server.
See the included validation report for this release’s CPU-model regression results. That model executes the generated PDP-11 instructions with 16 KiB RAM; it is not cycle-accurate and does not replace a test on the physical MK90.
mk90.commands
Command beep
Emit a short tone through the internal buzzer.
Synopsis
beep
Ordinary invocation: foreground child, PID 3; the shell waits. Not an allowed pipe producer.
Parameters
This command has no documented parameters.
Description
Uses the kernel’s bounded shared-controller transaction and then releases the controller. It accepts no pitch or duration argument.
Examples
beep
Limits and side effects
For programmable raw sound parameters in a BASIC application, use SOUND. For periodic background beeps, use RUN PULSE.
Status and diagnostics
Success is status 0. No command-specific status is added; shared ROM/controller failures remain possible. See the diagnostic reference.
Ordinary invocation: foreground child, PID 3; the shell waits. Allowed as a pipe producer. Also supported as a bare pipe consumer in PID 1 or 2.
Parameters
Parameter
Meaning
file
Regular MKS2 file, /dev/null, or /dev/console in the standalone form.
Description
Streams regular files in 256-byte blocks and yields between blocks. Output goes to the LCD console, or to the pipe when CAT is the producer. CAT does not implement a pager; use LESS for reading long text.
cat /dev/null produces immediate end-of-file. Standalone cat /dev/console echoes keyboard input until SU, then D; BK is converted to a newline.
On the right of a pipe, bare cat is a separate consumer process reading the FIFO; it takes no file argument. File checksums are validated on reaching EOF, so earlier data may already have been displayed before an error is discovered.
Examples
cat /mnt/smp1/demo.bas
cat /mnt/smp1/demo.bas | less
cat /dev/null
cat /dev/console
Limits and side effects
One file per invocation; no concatenation of multiple filenames. A console source is not allowed in a pipe. Control bytes are interpreted by the console, not displayed as a hex dump.
Shell builtin, PID 0. Not an allowed pipe producer.
Parameters
Parameter
Meaning
directory
Optional directory; omitting it selects the virtual root /, not a home directory.
Description
Resolves relative paths, absolute paths, ., .. and repeated slashes. Going above root stays at root.
CD is the one command marked as a shell builtin: it runs in PID 0 because its effect must remain in the parent shell. The prompt subsequently displays the normalized absolute directory.
Examples
cd /mnt/smp1
cd ..
cd /
Limits and side effects
No home directories, ~, cd - or environment variables. CD is not a pipe producer.
Ordinary invocation: foreground child, PID 3; the shell waits. Not an allowed pipe producer.
Parameters
Parameter
Meaning
source
Regular MKS2 file, or /dev/null for an empty source.
destination
File path, existing destination directory, /dev/null, or /dev/console.
Description
An existing directory receives the source basename. A file destination is replaced on successful completion; there is no overwrite confirmation. Copying uses a reader and the single writer handle, with 256-byte transfers and yields between sectors.
The source checksum must pass before the destination is published. A read failure, write failure or failed commit aborts the pending destination and preserves any previous target.
/dev/null as destination discards bytes while still reading and checking the source. A console destination prints them. An empty null source can create or truncate a regular file to zero bytes.
No recursive directory copy, wildcards, append or interactive console-to-file capture. Files need contiguous free space, including space for an uncommitted replacement. CP is not a pipe producer.
Ordinary invocation: foreground child, PID 3; the shell waits. Allowed as a pipe producer.
Parameters
This command has no documented parameters.
Description
Reads the year, month and day coherently and converts BCD/binary values for display. The two-digit year is the stored RTC value; no century interpretation is added.
Examples
date
Limits and side effects
Read-only; no calendar editing or date arithmetic.
List configured block-device slots and access flags.
Synopsis
devices
Ordinary invocation: foreground child, PID 3; the shell waits. Not an allowed pipe producer.
Parameters
This command has no documented parameters.
Description
Lists /dev/smp0, /dev/smp1, /dev/fd0 and /dev/cf0 with RO, RW or OFF. The boot slot is RO; the other SMP slot has a writable driver; floppy and CF are OFF.
This is a driver-table report. RW means a writable driver is configured, not that a physical module has been detected, mounted or tested.
Examples
devices
Limits and side effects
Does not probe XP1, enumerate UART hardware or measure cartridge capacity.
Status and diagnostics
Success is status 0. No command-specific status is added; shared ROM/controller failures remain possible. See the diagnostic reference.
Write up to three argument tokens to standard output.
Synopsis
echo [word [word [word]]]
Ordinary invocation: foreground child, PID 3; the shell waits. Allowed as a pipe producer.
Parameters
Parameter
Meaning
word
Optional space-separated token; at most three arguments are retained by the shell.
Description
Writes each retained token followed by one space, then a newline. Consecutive spaces in input do not preserve their original spacing. With no words, prints a newline.
Quotes have no shell quoting semantics. For example, quote characters remain literal characters in the retained tokens.
Examples
echo Hello MK90
echo Hello MK90 | cat
Limits and side effects
The four-token shell limit includes the command name; later tokens are ignored. No escapes, variable expansion, -n, output redirection or file creation.
Status and diagnostics
Success is status 0. No command-specific status is added; shared ROM/controller failures remain possible. See the diagnostic reference.
Open the text editor, with BASIC macros for .bas files.
Synopsis
edit [file]
Ordinary invocation: foreground child, PID 3; the shell waits. Not an allowed pipe producer.
Parameters
Parameter
Meaning
file
Optional existing or new regular file path; the parent must exist.
Description
Loads a named file, or starts it empty if absent. The editor retains its absolute pathname for saving. With no path, opens an unnamed RAM buffer; saving then reports status 16 rather than asking for a filename.
The buffer holds at most 1,280 bytes. The status row shows the filename, * when changed, [A]/[a], and BAS/FK as applicable. Save is SU, then S; exit is SU, then Q. Unsaved changes require a YES confirmation before discarding.
A case-insensitive .bas suffix enables factory-style FK word insertion. The inserted word remains editable text; it is not executed.
No save-as, undo, search/replace or syntax checking. Larger files are rejected rather than truncated. Opening a ROM file permits viewing/editing in RAM, but saving to ROM fails.
Ordinary invocation: foreground child, PID 3; the shell waits. Not an allowed pipe producer.
Parameters
Parameter
Meaning
program.mbx
Path to an MBX1 file; the explicit EXEC form validates content, not merely its suffix.
Description
Verifies the entire file checksum and its 16-byte header before execution. Initializes the 26 variables to zero and the pseudorandom seed to 1, then executes in the foreground child, PID 3.
The file remains open to protect its sectors while the runtime fetches bytecode in 256-byte pages. One additional data file can be opened by the program. The source BAS file is not needed.
The runtime polls keyboard and yields every 32 bytecode instructions. SU+C interrupts even an infinite GOTO loop. END, STOP, errors or interruption return to the shell and release owned handles.
In the shell, a first token not found in the command registry is tried as an executable path. Thus ./program.mbx works; exec ./program.mbx is the unambiguous explicit form. EXEC does not replace the parent shell as POSIX exec would.
Examples
exec /mnt/smp1/demo.mbx
./demo.mbx
Limits and side effects
No native machine-code file loader, command-line arguments to BASIC, concurrent BASIC instances or BASIC pipes. Missing paths and malformed MBX files return errors.
With no argument, prints the 33 registered names and the reminder help cmd. With one valid name, reads and verifies that command’s guide from the boot ROM.
HELP is dispatched as an ordinary foreground application, using the same registry as the other commands. Its on-device guide is deliberately short; this manual supplies the full reference.
Examples
help
help mbc
help ls
Limits and side effects
There is no on-device full-text search. A filename is not a help topic.
Ordinary invocation: foreground child, PID 3; the shell waits. Not an allowed pipe producer.
Parameters
Parameter
Meaning
pid
1 or 2; the slot must have been allocated.
Description
Sets the slot state to DONE and its recorded exit code to 130. It is a cooperative job-control operation, not a POSIX signal. A subsequent RUN may reuse the slot.
Examples
run count
kill 1
wait 1
Limits and side effects
PID 0 and PID 3 are not valid targets. There are no signal numbers, process groups or asynchronous kill commands typed while the shell is blocked in a foreground application.
Ordinary invocation: foreground child, PID 3; the shell waits. Also has a dedicated pipe-consumer form.
Parameters
Parameter
Meaning
file
One regular MKS2 file in the standalone form.
producer
An allowed pipe producer; the right-hand LESS takes no arguments.
Description
Uses constant-size buffers rather than loading the entire file. BK or space advances, lowercase b goes back in a file, and lowercase q or SU+C exits. The final page is marked (END).
Backward file navigation closes and reopens the reader, then scans from the beginning to the requested display page. It can therefore be slow on long files.
A pipe is not seekable: b is ignored there. Closing the pipe reader early wakes a blocked producer and terminates its output. At EOF, advancing in pipe mode exits; in file mode it remains at the end until a valid back or quit action.
Examples
less /mnt/smp1/demo.bas
cat /mnt/smp1/demo.bas | less
help | less
Limits and side effects
No search, line-number jump or arbitrary terminal control sequences. Letter controls are case-sensitive; switch to lowercase with R/L if necessary. File checksum verification is complete only when reading reaches EOF.
Ordinary invocation: foreground child, PID 3; the shell waits. Allowed as a pipe producer.
Parameters
Parameter
Meaning
path
Optional absolute or relative path; default is the current directory.
Description
For a regular file, prints its name and length in bytes. For a directory, prints its immediate children: directories have a trailing slash; files have their byte length.
The virtual directories /, /dev and /mnt have fixed listings. A name in /dev or /mnt is not proof that its hardware is available.
Normal volume listings pause after each eight entries. The [BK] prompt accepts a key to continue. In a pipeline this internal pause is disabled; the consumer controls paging. Entries follow inode order, without sorting.
Examples
ls
ls /mnt/smp1
ls /mnt/smp1/demo.bas
ls /mnt/smp1 | less
Limits and side effects
No options, recursive listing, glob expansion, timestamps or permission columns. Use the documented single-path form.
Ordinary invocation: foreground child, PID 3; the shell waits. Not an allowed pipe producer.
Parameters
Parameter
Meaning
source.bas
Regular source file with case-insensitive .bas suffix, on a volume where the output can be created.
Description
Performs two passes: first validates and measures bytecode and records line targets; then emits the executable. The output path replaces the source suffix with lowercase .mbx in the same directory.
A successful run clears the text console and reports the output pathname and length followed by B OK. The output is MBX1 bytecode, executed by the native runtime, not PDP-11 machine code.
The source is read in blocks; it need not fit the editor buffer. There are at most 64 non-empty source lines. Compilation uses the shared console buffers as workspace and yields between source lines. The display is not a live progress indicator.
The previous executable is preserved on a failed compile or failed publication. Use the language reference for the exact integer dialect.
Examples
cp /mnt/smp0/demo.bas /mnt/smp1/demo.bas
cd /mnt/smp1
mbc demo.bas
./demo.mbx
Limits and side effects
Not a complete implementation of the original MK90 BASIC. No real numbers, string variables, arrays or general Linux executable output. No compiler options, separate output-path argument, pipe use or background compilation. Compilation does not poll SU+C.
Create one directory on a mounted writable MKS2 volume.
Synopsis
mkdir path
Ordinary invocation: foreground child, PID 3; the shell waits. Not an allowed pipe producer.
Parameters
Parameter
Meaning
path
New directory path; its parent must already exist.
Description
Allocates one of the volume’s 16 shared file/directory inodes and records its parent. Directories use metadata only, without a data extent. A successful commit makes the new name visible.
Examples
mkdir /mnt/smp1/work
mkdir /mnt/smp1/work/src
Limits and side effects
No -p, recursive creation or permission argument. Virtual directories and the boot ROM cannot be extended. An existing target is an error.
Initialize one supported-size writable cartridge as MKS2.
Synopsis
mkfs device capacity
Ordinary invocation: foreground child, PID 3; the shell waits. Not an allowed pipe producer.
Parameters
Parameter
Meaning
device
Registered writable block device; the boot device is protected.
capacity
Capacity in KiB: exactly 8, 10, 16, 32 or 64.
Description
This is destructive formatting. The volume must be unmounted and not busy. After the prompt, enter YES and press BK; confirmation is case-insensitive. Any other answer cancels without formatting.
Checks for address aliasing between 2 KiB regions, creates the single-partition MKS2 layout, verifies writes, and writes the valid header last. A successful format also marks the volume mounted.
Use the actual hardware capacity. The parameter is not a partition size to apply arbitrarily to a smaller cartridge.
Examples
cd /
umount /mnt/smp1
mkfs /dev/smp1 10
Limits and side effects
The example is for a mounted 10 KiB cartridge whose existing content may be erased; skip UMOUNT if it is already unmounted. Formatting is unnecessary when upgrading an existing compatible MKS2 data cartridge. No EEPROM programming algorithm or BASIC-format conversion is supplied.
Ordinary invocation: foreground child, PID 3; the shell waits. Not an allowed pipe producer.
Parameters
Parameter
Meaning
device
One of the registered /dev block-device names.
mountpoint
The fixed mountpoint paired with that device; both arguments are required together.
Description
Without arguments, lists mounted paths and their RO/RW state. With two arguments, explicitly reads and validates the MKS2 header and metadata and sets that device’s mount bit.
The boot cartridge is registered as mounted and read-only at startup, with its filesystem inside the final 8 KiB of the 32 KiB ROM. Its metadata is read when needed. SMP1 data is mounted explicitly.
The stock BASIC format is not MKS2. A readable stock cartridge can therefore fail MOUNT while passing bus or ROM-switching diagnostics. Mounting never formats or imports it.
Examples
mount
mount /dev/smp1 /mnt/smp1
Limits and side effects
Fixed pairs only: smp0→/mnt/smp0, smp1→/mnt/smp1, fd0→/mnt/fd0, cf0→/mnt/cf0. The last two drivers are absent. No mount options or arbitrary mountpoints.
Ordinary invocation: foreground child, PID 3; the shell waits. Not an allowed pipe producer.
Parameters
Parameter
Meaning
source
Existing regular file on a writable volume.
destination
File path or an existing directory.
Description
Within one volume, changes the name and parent of the source inode in one metadata commit. Its data extent and inode index remain the same. An existing target file is replaced; identical source and target resolve to a no-op.
Across volumes, completes a verified copy first, then deletes the source. If source deletion fails after the copy, both copies can remain. This is not an atomic operation across two devices.
Moving from the boot ROM is rejected because removal of the source is not allowed; use CP to extract ROM files.
Examples
mv draft.txt final.txt
mv final.txt work
Limits and side effects
Regular files only; no moving directory trees, wildcard moves or overwrite confirmation. On the standard ROM-plus-one-data-cartridge setup, only the data cartridge is writable.
Ordinary invocation: foreground child, PID 3; the shell waits. Not an allowed pipe producer.
Parameters
This command has no documented parameters.
Description
This registered command only prints a help resource. To create a pipe, use the | operator between two command expressions, such as ls /mnt/smp1 | less.
The operator connects two separately scheduled contexts through a blocking 256-byte FIFO in RAM. It does not create a temporary file.
Examples
pipe
ls /mnt/smp1 | less
echo Hello | cat
Limits and side effects
Exactly one producer and one bare CAT or LESS consumer. No chains, named pipes, shell redirection or BASIC pipelines. One background slot must be available.
Display task slots, states, names and application counters.
Synopsis
ps
Ordinary invocation: foreground child, PID 3; the shell waits. Allowed as a pipe producer.
Parameters
This command has no documented parameters.
Description
Prints PID S NOME PASSI and one row for each non-free slot. NOME means “name”; PASSI means “steps”. The counter belongs to the application and is not CPU time.
While standalone PS runs, PID 0 normally appears as W (waiting for its child) and PID 3 as R with name ps. Finished background slots remain visible until reused. The scheduler also has I/O waiting states for pipe endpoints.
Examples
run count 5
ps
ps | less
Limits and side effects
No options or process tree. PID numbers are reusable slot indexes, not permanent job identities. For the full state table see the multiprogramming chapter.
Ordinary invocation: foreground child, PID 3; the shell waits. Not an allowed pipe producer.
Parameters
Parameter
Meaning
file
Existing regular file on a mounted writable volume.
Description
Removes the directory entry in a metadata commit. There is no extra confirmation. Data sectors can be reused when no metadata generation or open reader still references them.
Examples
rm /mnt/smp1/old.txt
Limits and side effects
No recursive deletion, wildcard expansion, trash or secure erasure. It does not remove directories.
Ordinary invocation: foreground child, PID 3; the shell waits. Not an allowed pipe producer.
Parameters
Parameter
Meaning
path
An existing empty directory on a writable volume.
Description
Checks that the directory has no children, is not the current directory or one of its ancestors, and is not a volume root. Removes the inode in a metadata commit.
Examples
cd /
rmdir /mnt/smp1/work/src
rmdir /mnt/smp1/work
Limits and side effects
No recursive deletion and no confirmation prompt. Use RM for regular files.
Check the full boot ROM and repeated cartridge switching.
Synopsis
romtest
Ordinary invocation: foreground child, PID 3; the shell waits. Not an allowed pipe producer.
Parameters
This command has no documented parameters.
Description
First compares distinct 32-byte markers at byte offsets 0x3FE0, 0x5FE0 and 0x7FE0, reporting 16, 24 and 32 KiB milestones.
Then reads all 128 sectors of the 32 KiB boot ROM and checks the 16-bit word sum. Before each ROM sector it selects the other slot and reads its first byte, exercising slot switching. The final success text is ROM 32K + SWITCH OK.
The operation is read-only and yields between ROM sectors. Use it to diagnose addressing and switching on the already wired 27C256 setup.
Examples
romtest
Limits and side effects
A responsive cartridge in the other slot is required for the switching phase. This does not read all of SMP1, validate its filesystem, prove its capacity or certify electrical timing. Earlier milestone success does not replace the final whole-ROM result.
Start one of the two built-in background worker types.
Synopsis
run count|pulse [count]
Ordinary invocation: foreground child, PID 3; the shell waits. Not an allowed pipe producer.
Parameters
Parameter
Meaning
count|pulse
COUNT increments a counter; PULSE also beeps on each step. Names are case-insensitive.
count
Optional number of steps, 1–9999. Omit it to run continuously.
Description
Allocates PID slot 1 or 2 and prints its number. Each worker first sleeps for 32 RTC ticks, increments its unsigned 16-bit counter, and, for PULSE, emits a beep. A finite worker exits with code zero after its requested steps.
One step is nominally one second, plus scheduling and work delay. It is not a precision stopwatch. A completed or faulted slot can be reused and its private data is cleared.
Examples
run count 10
run pulse 3
ps
wait 1
Limits and side effects
RUN does not launch arbitrary files, shell commands or BASIC programs in the background. At most two slots are available, and a pipeline consumes one. An explicit count of zero is invalid; omission selects continuous execution.
Suspend the foreground command while other tasks continue.
Synopsis
sleep seconds
Ordinary invocation: foreground child, PID 3; the shell waits. Not an allowed pipe producer.
Parameters
Parameter
Meaning
seconds
Decimal integer from 0 to 1023 inclusive.
Description
Converts whole seconds to 32 Hz RTC ticks and calls the cooperative sleep service. A value of zero yields without a timed delay.
The shell waits for this foreground child. Background workers still run, subject to cooperation. Waking occurs after the deadline when a runnable context can be selected.
Examples
run count 5
sleep 2
ps
Limits and side effects
No fractional durations. The sleep command does not poll for SU+C during its timed wait; it is not a general cancellable timer.
Ordinary invocation: foreground child, PID 3; the shell waits. Allowed as a pipe producer.
Parameters
This command has no documented parameters.
Description
Samples the clock around its update interval, retries an unstable read, and converts the configured binary/BCD and 12/24-hour representation to a 24-hour display.
The command reads the clock only. Set the clock through the original MK90 firmware.
Examples
time
time | cat
Limits and side effects
No time-setting, timezone or synchronization argument. The RTC does not supply timezone information.
Ordinary invocation: foreground child, PID 3; the shell waits. Not an allowed pipe producer.
Parameters
Parameter
Meaning
mountpoint
The root of a mounted volume, such as /mnt/smp1.
Description
Refuses to unmount a volume containing the current directory or an open file handle. Change to / first. Successful unmount does not delete data.
Writes are verified and committed by their owning operation; UMOUNT is not a delayed-write flush command. Before changing a physical cartridge, leave it, unmount it, and explicitly mount the replacement.
Examples
cd /
umount /mnt/smp1
Limits and side effects
No force option. Keep the boot ROM physically installed: the OS continues to load code and resources from it.
Ordinary invocation: foreground child, PID 3; the shell waits. Not an allowed pipe producer.
Parameters
Parameter
Meaning
pid
1 or 2, including a slot already in DONE or FAULT state.
Description
Allows the scheduler to run until the target is DONE or FAULT, then prints its recorded exit code. The WAIT command itself returns success after printing that code.
SU, then C cancels this wait without killing the target. A cancelled wait does not print a final target code.
Examples
run count 3
wait 1
ps
Limits and side effects
Cannot wait for an arbitrary PID or collect several jobs at once. The result belongs to the current occupant of the slot. BASIC WAIT has a different meaning and uses ticks.
Square brackets mark optional arguments; they are not typed. Alternatives in a synopsis are choices, not a literal pipe character. In an actual command line, | creates a pipeline. Commands are case-insensitive; paths are case-sensitive. Read the shell grammar.
mk90.guide
Getting started
From the 27C256 image to your first compiled BASIC program.
Requirements
Elektronika MK90 with 16 KiB RAM and the cartridge wiring already validated for the 27C256.
The 32,768-byte mk90_unix_v0.7_27c256.bin image, normally installed in SMP0.
A writable supported SMP data cartridge in SMP1 for saving files and compiling BASIC. A stock 10 KiB module is supported at the storage-driver level; it must contain MKS2 to mount.
Install and boot
Program the whole binary starting at EPROM offset zero, then use the programmer’s verify operation. The image is one 32 KiB layout, not four duplicate 8 KiB images. Start the cartridge from the original MK90 startup menu.
After the banner, the prompt begins at the virtual root: / $ . The boot slot remains physically identified as SMP0 or SMP1; no DOS drive-letter renaming occurs.
The bootstrap loads 8,762 bytes of resident code into RAM. Other applications and resources are read from the boot cartridge when needed. Leave that cartridge installed while the OS runs.
Use an existing MKS2 cartridge
devices
mount /dev/smp1 /mnt/smp1
cd /mnt/smp1
ls
Do not format a compatible data cartridge just to update the ROM. The MKS2 layout in 0.7 is compatible with the previous 0.5 release.
Prepare a new data cartridge
For an unmounted 10 KiB data cartridge:
cd /
mkfs /dev/smp1 10
Confirm with YES, then BK. If the volume is already mounted, first run umount /mnt/smp1 while outside it. A successful MKFS also mounts the volume. Valid capacity arguments are 8, 10, 16, 32 and 64 KiB; use the module’s actual size.
Compile the supplied demonstration
cp /mnt/smp0/demo.bas /mnt/smp1/demo.bas
cd /mnt/smp1
mbc demo.bas
./demo.mbx
The demonstration clears the display, prints five numbered lines and beeps. The compiler creates demo.mbx next to its source. Compilation directly in the read-only boot volume cannot create that output.
To change the source, run edit demo.bas. Save with SU, then S; exit with SU, then Q; compile again. Editor guide.
Try cooperative jobs and a pipe
run count 10
ps
sleep 2
ps
ls /mnt/smp1 | less
RUN prints the allocated PID. A pipeline needs at least one free or finished background slot. In LESS, BK/space advances; lowercase q exits. Enter the pipe character with V/N, then backslash.
If the ROM does not run correctly
Run romtest with a responsive cartridge in the other SMP slot to check the ROM and slot switching. A successful ROM test does not imply that the data cartridge has an MKS2 filesystem. See Diagnostics for the exact messages.
mk90.guide
Shell syntax
The actual command-line parser and dispatch rules.
Prompt and input
The prompt is the normalized current directory followed by $ . It starts as / $ . BK submits a line, backspace removes the previous character, and SU+C cancels the pending line.
The command line holds at most 95 characters plus a terminator. There is no history, cursor editing, completion or shell scripting language. Use EDIT to change a file.
Spaces split tokens; repeated spaces are skipped. A maximum of four tokens, including the command name, is retained on the producer or ordinary-command side. Additional tokens are silently ignored by the parser. Follow each command’s documented arity rather than relying on ignored arguments.
The single pipe is recognized even without surrounding spaces. The consumer must be bare CAT or LESS, with optional surrounding spaces and no arguments. More than one pipe, or a missing side, is invalid.
Case and paths
Registered command names and HELP topics are case-insensitive. Paths are case-sensitive: Note.txt and note.txt are different names. Use ASCII letters, digits, dot, hyphen and underscore in a component; the maximum is 12 characters.
Absolute paths start with /. Relative paths start at the current directory. ., .. and repeated slashes are normalized. No ~, home directory, PATH search or drive-letter alias is implemented.
Command and executable dispatch
A registered name selects its command record. CD runs in the shell itself. Other normal commands execute as PID 3 while PID 0 waits.
If the first token is not a registered name, the shell tries that token as an MBX executable path. It does not search a list of directories or infer a file extension. Prefer exec path.mbx or ./name.mbx for clarity. Arguments on the implicit executable form are not passed into BASIC.
run is reserved for the built-in COUNT and PULSE background workers. It does not execute a BAS file or an arbitrary application.
Syntax not implemented
Syntax
0.7 behavior
Quotes
No quoting or grouping; quote marks are ordinary token characters.
Backslash
No escape sequences; it is a keyboard character, with V/N producing |.
> or >>
No file redirection; these are ordinary token characters, not operators.
&
No background operator.
; or && or ||
No command lists or conditional execution. More than one | is rejected.
* or ?
No wildcard expansion.
$NAME or $(...)
No variables or command substitution.
Control-code overlap
The input interface exposes a small translated code set. Up-arrow and SU+C both produce code 3; down-arrow and SU+D both produce code 4. Consequently up-arrow also cancels a shell input line or a BASIC run, while down-arrow terminates standalone CAT /dev/console. The editor interprets codes 3 and 4 as vertical movement. These are actual 0.7 mappings, not a full terminal key protocol.
mk90.guide
Text editor
Named and unnamed buffers, movement, saving and BASIC insertion.
Open a buffer
Use edit path to load an existing regular file or create a new empty buffer at a missing filename. The parent directory must exist. Files longer than 1,280 bytes produce status 20 and are not truncated.
edit without a path is an unnamed scratch buffer. SU+S reports status 16; there is no save-as prompt. For persistent work, open a pathname at the start.
Editor controls
Key sequence
Action
Left / Right
Move one character within the buffer.
Up / Down
Move vertically by displayed rows, following line wrapping.
BK
Insert a line feed.
Backspace
Delete the character immediately before the cursor.
SU, then S
Save the current named file; stay in the editor.
SU, then Q
Exit; if changed, ask whether to discard.
R/L
Toggle lowercase/uppercase state.
FK, then a legend key
Insert its BASIC word in a .bas buffer.
Screen and status
The first row shows the basename, a star for unsaved changes, and case state [A] or [a]. BASIC buffers show BAS; an armed function-key prefix shows FK. An underscore marks the insertion position in the displayed text.
The body uses eight display rows and scrolls to keep the cursor visible. Long physical lines wrap to the 30-column console. Cursor motion follows this displayed layout.
Save and exit
Saving uses the transactional file writer. A successful save clears the changed flag. A failed save leaves the buffer available and does not publish a partial replacement.
SU+Q exits immediately if unchanged. Otherwise it asks SCARTARE? YES + BK (“Discard?”). YES, case-insensitive, discards; another answer returns to editing. A ROM file can be edited in RAM but cannot be saved in place.
BASIC mode
A .bas suffix, ignoring case, selects BASIC insertion. FK is a sequential prefix: press and release FK, then the desired legend key. Pressing FK again toggles the prefix off. An expansion inserts the whole word only if it fits; no partial keyword is inserted at the buffer limit.
For example, FK then R inserts RUN , and FK then P inserts PRINT . This is text entry, not command execution. Factory legends include words unsupported by MBC-16; see the full macro table.
The editor does not compile, execute, syntax-check, indent or colorize the buffer. Leave it, then use MBC and EXEC.
Limits
1,280 bytes total, including line feeds and inserted macro text.
Printable single-byte text; no Unicode editing or tab expansion.
No undo, selection, clipboard, search/replace, save-as or multiple open buffers.
SU+C is not an editor exit command: code 3 is used for up-arrow movement.
mk90.guide
MKS2 filesystem
Volumes, directories, names, allocation and verified publication.
Namespace
Path
Meaning
/
Virtual root; contains dev/ and mnt/.
/dev
Fixed device and stream names.
/mnt
Fixed registered mountpoints.
/mnt/smp0
SMP0 volume, or the boot ROM’s internal read-only volume when booting there.
/mnt/smp1
SMP1 volume; normally the writable data cartridge.
/mnt/fd0 and /mnt/cf0
Reserved mountpoints with no driver in 0.7.
/dev/console
Application-level keyboard/LCD stream supported by CAT/CP.
/dev/null
Application-level empty source/discard sink supported by CAT/CP.
Names and directories
Names are case-sensitive, 1–12 ASCII characters from letters, digits, dot, hyphen and underscore. The normalized path is at most 95 bytes. . and .. have their usual path-navigation meaning.
Each volume has 16 inodes total, shared by files and directories across the entire tree. A directory stores a parent link, not an independently sized table of 16 children. The volume root is implicit and does not consume an inode.
Directory contents have no timestamps, owner, group, permission bits, hard links or symbolic links. Empty directories use no data sectors; even an empty regular file reserves one 256-byte sector.
Capacity and file sizes
Volume size
Logical sectors
Data-area upper bound
8 KiB
32
6912 bytes
10 KiB
40
8960 bytes
16 KiB
64
15104 bytes
32 KiB
128
31488 bytes
64 KiB
256
64256 bytes
Sectors are 256 bytes. Five sectors are reserved for the header and two metadata copies. A file uses one contiguous extent and can be at most 64,256 bytes, subject to volume capacity, other files, metadata generations and free contiguous space.
The editor’s 1,280-byte limit is an application limit. CAT, CP and LESS stream larger files. MBC reads source blocks but independently limits a program to 64 non-empty source lines.
Verified writes and replacement
The file writer knows the final length before writing. It reserves a new extent that does not overlap either valid metadata generation or the sectors of an open reader. Data is written, reread and compared. Only a successful close publishes the new inode in the inactive metadata copy.
An interrupted or incomplete output does not publish a partial new file. An earlier version remains referenced if it existed. Both generations and pinned readers can temporarily keep old extents unavailable, so replacement may require more free space than the final file length.
Only one writer can be open. There are two owned handles total, allowing two readers or one reader plus one writer. A writer blocks conflicting filesystem mutations. This is neither journaling nor a general multiwriter filesystem.
Reading and recovery
MOUNT validates the header and metadata copies, then chooses the newest valid generation with modular 16-bit comparison. If one copy is invalid, it can use the other. Both invalid copies cause failure.
A regular file has a byte-sum checksum in its inode. Reading through EOF verifies it; closing early does not force a complete scan. An application can display earlier bytes before discovering a later checksum failure. The system does not automatically substitute an old file version for damaged data.
The checks detect many ordinary corruption cases but are not a cryptographic integrity mechanism or a complete validator for deliberately hostile images.
Operations and compatibility
MKDIR/RMDIR manage directories; RM removes one file; CP copies and replaces; MV renames within a volume or copies then removes across volumes. Cross-volume MV has no atomic transaction spanning both devices.
MKS2 has a single partition per volume and its own on-media format. It is not FAT, ext2, a Linux filesystem or the original MK90 BASIC cartridge format. No conversion or repair command is supplied. On-media format reference.
mk90.guide
Devices and expansion
Physical slot identity and the boundary of current driver support.
Device map
Index
Device
Mountpoint
Driver and role
0
/dev/smp0
/mnt/smp0
SMP block driver; normally the protected boot ROM.
1
/dev/smp1
/mnt/smp1
SMP block driver; normally the writable data cartridge.
2
/dev/fd0
/mnt/fd0
Reserved, OFF; no floppy driver.
3
/dev/cf0
/mnt/cf0
Reserved, OFF; no CompactFlash/IDE driver.
Boot-device mapping
The boot slot is marked read-only independently of whether it is SMP0 or SMP1. Its filesystem device exposes 32 logical sectors starting at physical sector 96, corresponding to EPROM offsets 0x6000–0x7FFF. The rest of the ROM contains the bootstrap, kernel, modules and resources.
The other SMP driver can address up to 256 logical 256-byte sectors, or 64 KiB. This driver bound is not an automatic capacity measurement. The mounted MKS2 header specifies a supported size, and formatting performs alias checks.
Console and null
CAT and CP implement the /dev/console and /dev/null stream cases themselves. These are not ordinary MKS2 files and are not accepted by the native regular-file OPEN service or BASIC OPEN.
CAT can echo console input until SU+D. CP can send a file to the console or null; it cannot capture an unknown-length console stream into a file.
Future XP1 support
The device abstraction carries a driver callback, physical unit, flags, a 32-bit logical capacity and a base LBA. This leaves room for later drivers without renaming the two physical SMP slots.
Version 0.7 does not include a PC16550, 16450, 68B50 or other UART driver, nor an XP1 bus probe. The UART command reports this state. A future expansion needs agreed hardware decoding and an implemented driver; the presence of a reserved name is not working hardware support.
mk90.system
Multiprogramming
Four fixed context slots with cooperative scheduling and explicit ownership.
Execution model
MK90/Unix 0.7 has one CPU and four task-control blocks. At most one context executes at a time. Other active tasks make progress when the running context calls a yield or a blocking operation that yields. There is no timer-driven preemption.
This is real context switching: registers, stack pointer, return program counter and supported processor status are saved and restored. It is deliberately smaller than a general Unix process model: there is no fork, address-space duplication, memory protection, arbitrary background command execution or dynamically allocated process table.
Context slots and ownership
PID
Role
Stack
Resources and lifetime
0
Shell/parser/dispatcher
Shared 512-byte foreground stack
Waits while PID 3 borrows the stack; CD runs here.
1
Background worker or pipe consumer
160 bytes, plus 32 private data bytes
Independent registers and stack; slot can be reused.
2
Background worker or pipe consumer
160 bytes, plus 32 private data bytes
Independent registers and stack; slot can be reused.
3
One foreground child
Same stack as PID 0
Runs an ordinary command or the single BASIC instance; parent is suspended.
One simple foreground command can coexist with both background workers. A pipeline needs one of slots 1/2 for its consumer and can coexist with at most one other worker. PIDs identify slots, not permanent process histories.
Foreground command lifecycle
The shell resolves and loads a command before starting its child. It saves its continuation, marks PID 0 WAIT_CHILD, initializes PID 3 and calls the entry point on the existing foreground stack. PID 0 is not runnable while PID 3 uses that stack.
The child can yield to PID 1/2. Returning normally or through task_exit restores the saved parent continuation, records the child result and changes its state to DONE. The kernel closes the child’s pipe writer, releases its readers and aborts uncommitted file writers. PID 0 becomes READY again.
This mechanism neither forks the shell nor gives the child a second 512-byte stack. The parent’s suspended frames and the child’s frames share the one bounded region. The next command reuses PID 3.
Scheduler algorithm
task_yield saves the context while interrupts are masked, then scans cyclically from the following TCB. A sleeping task whose deadline is due becomes READY. READY contexts with valid stacks can be selected; FREE, DONE, FAULT and blocked contexts are skipped.
If no context is ready, the scheduler enables interrupts and executes WAIT, then scans again. RTC and keyboard interrupts can wake the CPU; their handlers do not select a different task themselves.
The selection order is round-robin among eligible slots at yield points. It is not a fixed time slice and does not promise equal CPU time. A task that does not cooperate can delay every other task, even while timer interrupts continue.
Yield is suppressed during a shared-controller transaction or when the saved interrupt priority masks interrupts. The sleep service rejects those conditions before marking a task asleep. Native blocking APIs must not be called from interrupt handlers.
Task states
Value
PS letter
State
Meaning / transition
0
–
FREE
Not allocated; omitted from PS.
1
R
READY
Eligible for selection; the current running task uses this state too.
2
S
SLEEP
Deadline in RTC ticks; made READY by a later scheduler scan.
3
D
DONE
Finished; exit result retained until the slot is reused.
4
F
FAULT
Stack check failed in a background slot; exit result 1.
5
I
WAIT_READ
Pipe reader blocked until data or writer closure.
6
O
WAIT_WRITE
Pipe writer blocked until space or reader closure.
7
W
WAIT_CHILD
Shell cannot run while its foreground child borrows the stack.
RTC and timing
The kernel uses a nominal 32 Hz RTC tick, held in an unsigned 16-bit counter. The counter wraps every 65,536 ticks: 2,048 seconds. Deadlines are compared with modular signed differences, so a single sleep accepts at most 32,767 ticks.
The shell SLEEP command accepts 0–1023 whole seconds. BASIC WAIT accepts 0–32767 ticks. Zero means yield. Neither the conversion nor a deadline guarantees when a task actually resumes: controller work and other tasks can add latency.
COUNT and PULSE sleep for 32 ticks before each step, then do their work. Their counters are application progress, not elapsed-time measurements. PS does not show CPU percentages or accumulated CPU time.
Built-in background workers
RUN creates only COUNT or PULSE. An optional 1–9999 step limit gives a finite run; omission means continuous operation. PULSE calls the guarded buzzer API after incrementing its counter. On a tone I/O failure it exits with the returned error.
KILL accepts only PID 1 or 2 and marks the selected allocated slot DONE with result 130. It is not a signal facility. WAIT prints a target’s exit result when it becomes DONE/FAULT, or allows SU+C to abandon the wait without stopping the worker. A later RUN may overwrite the old slot history.
I/O and memory ownership
Only PID 0 and PID 3 may use the regular-file services; they never execute simultaneously. Background workers must use their own registers, stack and 32-byte data area and cannot touch shell buffers, load application modules or directly use filesystem, keyboard, LCD or shared-controller registers.
The registered pipe consumer is a controlled exception: its verified pager code remains loaded while it owns the keyboard/display, and it reads only the FIFO. It does not open files or overwrite a suspended producer’s sector buffer.
The application loader accepts the shell and the foreground child’s registered BASIC module family. It rejects ordinary background loads, and all replacement loads while a pipe is active. These restrictions preserve return addresses and code across yield points.
There is no MMU or protection boundary between native tasks. A trusted native task with an invalid pointer can still corrupt another subsystem. These contracts govern the built-in code; they are not a security sandbox.
Context frames and stack checks
A saved context, from its saved SP upward, contains R5, R4, R3, R2, R1, R0, PSW and PC. The supported PSW state is its low byte, including condition flags and interrupt priority. Trace mode and privileged modes of other PDP-11 models are not promised.
Each stack region has an A55A guard word. Checks require an aligned saved SP, at least 32 bytes above the lower bound, and room for the saved frame below the upper bound. The declared stack sizes include kernel and IRQ frames, not just application locals.
A bad background stack marks that slot FAULT. If it is the pipe consumer, its read endpoint closes and wakes the producer. A bad shared shell/foreground stack is fatal: the system displays a stack error and requires restart. Guard checks detect some corruption after it occurs; they do not prevent every invalid write.
BASIC participation
MBC compiles in PID 3 and yields between source lines. It reuses console text/shadow memory for the scanner and target table, so it does not render or poll keyboard during compilation. COUNT/PULSE remain compatible because they do not touch those buffers.
The MBX runtime also uses PID 3. Every 32 opcodes it calls the keyboard poll path, which renders, rescans input and yields. WAIT yields directly; keyboard input also cooperates. One BASIC instance may coexist with the native workers, but cannot be started with &, RUN or a pipe.
SU+C cancellation is checked at runtime polling/input points. A long WAIT or controller transaction must return before the next cancellation check; compilation has no SU+C polling loop.
One blocking byte FIFO connecting two independently scheduled contexts.
Supported syntax
producer [arguments] | cat
producer [arguments] | less
Allowed producers are help, ls, pwd, cat, echo, uname, mem, time, date and ps. The consumer must be bare CAT or LESS. Case-insensitive command matching applies on both sides.
There is one pipe system-wide, with exactly two stages. A free or finished slot 1/2 must be available for the consumer. MBC, EXEC, EDIT and other unlisted commands are rejected as producers. The PIPE command itself displays usage; it is not the operator.
Startup and lifetime
Step
Dispatcher / process action
1
PID 0 verifies the producer and loads the pager consumer module into its separate application window.
2
The dispatcher validates syntax, activates the pipe and creates its consumer in slot 1 or 2.
3
The consumer gets an initial yield to set up display state and wait for input.
4
The producer starts as foreground PID 3; PID 0 waits for its child.
5
Both endpoints run cooperatively. The consumer owns keyboard/display; the producer owns filesystem operations.
6
Producer completion closes the write endpoint. The consumer drains bytes and receives EOF.
7
PID 0 waits for consumer completion, clears the active pipe state, then resumes the prompt.
The native application windows stay loaded for the whole pipeline. While the active flag is set, the loader rejects replacement requests; a task cannot resume into overwritten code.
FIFO and blocking behavior
The ring buffer holds 256 bytes at RAM 0x0100–0x01FF, reusing bootstrap storage after the kernel has been loaded. Indices wrap modulo 256; an explicit count distinguishes a full ring from an empty one.
Writing to a full FIFO sets WAIT_WRITE and yields. Reading one byte makes room and wakes the writer. Reading an empty FIFO with an open writer sets WAIT_READ and yields. Writing a byte wakes the reader.
The producer’s normal putc/puts output is bound to the FIFO. The consumer receives bytes in order; no temporary file, batch spool or source-text substitution is involved. The ring operations themselves do not yield midway, and interrupt handlers do not modify it.
EOF, early close and errors
Closing the writer wakes a blocked reader. The reader receives all remaining bytes before EOF; EOF is a separate return value, not a reserved byte within the stream.
Closing the reader wakes a blocked writer with EPIPE, status 21. The producer’s output routine aborts its foreground command immediately, releases file handles and does not continue reading the rest of an unwanted file.
A normal early quit from LESS is treated as a successful user action: if the producer ended with EPIPE, the pipeline returns the consumer’s result. Other producer errors are reported after pipeline completion. On an ordinary non-EPIPE path, the returned pipeline status is the producer’s status, not a generalized combination of every process result.
Consumer task return closes its endpoint. A detected consumer stack fault also closes it and wakes the writer, preventing a producer from sleeping forever on a reader that can no longer run.
Paging and keyboard ownership
Piped LS suppresses its built-in eight-entry pause. The LESS consumer chooses when to stop for a page. BK or space advances; lowercase q or SU+C closes the consumer. There is no backward paging on a pipe. At the final page, an advance or quit action exits.
The CAT consumer simply forwards bytes to the console and yields frequently. A console-input CAT producer is disallowed, because the consumer owns keyboard/display during a pipeline.
Boundaries
One FIFO, one writer, one reader; no multi-stage chains or multiple simultaneous pipelines.
No named pipes, duplicated handles, stderr channel, tee, redirection to files, shell filters loaded from disk or arbitrary consumer arguments.
No fork, signals, process groups or detached pipelines. The foreground shell cannot accept a new command while the pipeline runs.
Other native workers can continue if a slot remains; there is no BASIC producer or consumer in this release.
Examples
ls /mnt/smp1 | less
cat /mnt/smp1/demo.bas | less
echo Hello MK90 | cat
help | less
ps | cat
Build-specific layout of the 16 KiB RAM and the 32 KiB cartridge.
Memory model
All addresses on this page are hexadecimal byte addresses; range ends are inclusive unless stated otherwise. The CPU executes native code from RAM. The SMP ROM is storage accessed through the controller, rather than an extra 32 KiB of CPU memory.
The kernel occupies 8,762 of the 8,768 bytes assigned to its resident area, leaving 6 bytes there. This is not 6 bytes of total system free RAM; the rest is assigned to fixed data, buffers, stacks and loadable module windows.
RAM layout
Range
Use
0000–00FF
Vectors; RTC at 0040, keyboard at 00C8.
0100–01FF
Bootstrap initially; then pipe FIFO or private MBC/EXEC scratch.
0200–05BF
120×64 monochrome framebuffer, 960 bytes.
0600–069B
Kernel and controller globals.
06A0–06EF
Two 40-byte file descriptors.
06F0–06FF
Process/module-cache state.
0700–071F
Keyboard queue storage.
0720–075F
Four 16-byte block-device records.
0760–07AF
Four 20-byte task-control blocks.
07B0–07EF
BASIC compiler/runtime state.
07F0–07FF
Pipe control, eight words.
0800–2A3F
Resident kernel area.
2A40–2C3F
512-byte active MKS2 metadata buffer.
2C40–2D3F
TMP/COPYBUF, 256-byte data scratch buffer.
2D40–2E3F
VERIFY; also runtime bytecode cache.
2E40–2F6B
Text console, 300 bytes.
2F6C–3097
Text shadow, 300 bytes.
30A0–30FF
Normalized path, 96 bytes.
3100–315F
Current directory, 96 bytes.
3160–316F
Filename scratch.
3180–319F / 31A0–323F
PID 1 private data / 160-byte stack.
3240–325F / 3260–32FF
PID 2 private data / 160-byte stack.
3300–37FF
Ordinary lower application window, 1,280 bytes.
3800–3CFF
Pager module or 1,280-byte editor buffer.
3D00–3DFF
Shell input/arguments and application paths; reused by BASIC.
3E00–3FFF
512-byte stack shared by PID 0 and PID 3.
BASIC overlays and workspace
In BASIC mode the application region is repartitioned: 3300–363F is an 832-byte lower phase, and 3640–3CFF is a 1,728-byte common module. These are alternate uses, not extra simultaneous windows.
During compilation, TEXT/SHADOW provide a 256-byte source cache and a 256-byte table of up to 64 line-number/offset pairs. The compiler restores the text console after releasing that workspace.
During execution, 3D00–3D33 holds A–Z, 3D40–3D9F holds a data pathname and 3DA0–3DDF holds eight FOR/GOSUB frames. The operand stack uses the foreground stack with an explicit limit of 16 values.
ROM layout
ROM byte range / offset
Purpose
0000–01FF
Bootstrap area.
0200 onward
Resident image, 8,762 bytes.
2480 onward, below 3D00
First region of verified native application modules.
3D00–3D7F
Additional EXEC help record.
3FDE
Whole-ROM checksum word.
3FE0 / 5FE0 / 7FE0
Distinct 32-byte addressing markers.
4000–4FFF
First 32 compact help records.
5000–577F
Thirty 64-byte checksummed English message records.
5800–5FDF
Additional verified BASIC compiler/runtime stages; marker at 5FE0.
6000–7FFF
8 KiB read-only MKS2 system volume; its data also contains module storage.
6500 onward
Remaining native modules in the system volume’s data area.
7D00–7EFF
FK keyword dictionary.
Module loading rules
The loader validates the module ID, native module ABI 3, destination window, size, ROM bounds and checksum. PID 0 can request normal loads. PID 3 can request only its registered BASIC family. Background contexts cannot load arbitrary modules.
Compiler phase changes pass through the upper common module, which restores the lower caller before returning. The runtime keeps fetch, arithmetic and control flow in the upper module; lower device/graphics/file phases always return to the stable dispatcher before another phase can replace them.
A native pipeline uses the ordinary lower window for its producer and the pager window for its consumer. The active pipe prevents every replacement load until both contexts have finished.
mk90.system
MKS2 on-media format
The partition header, mirrored directory records and file extents.
Conventions
Offsets in format tables are byte offsets. Multi-byte fields are little-endian words unless a byte range is stated. Sectors are 256 bytes. Supported volumes have 32, 40, 64, 128 or 256 sectors. The first data sector is 5.
Volume header: sector 0
Byte offset
Field
0–3
ASCII MKS2.
4
Version 2.
6
Checksum word: sum of all 128 words in the sector is zero modulo 65536.
8
Total sector count.
10
Partition count, fixed at 1.
12
First partition sector, fixed at 1.
14
Partition length, total sectors minus 1.
16
Partition type, fixed at 1.
18
First data sector, fixed at 5.
20
Sector size, fixed at 256.
22–255
Reserved.
Metadata generations
Copy A occupies sectors 1–2; copy B occupies sectors 3–4. Each 512-byte copy begins with ASCII DIR2, generation at byte 4 and checksum at byte 6. Bytes 8–63 are reserved. Sixteen 28-byte inodes follow at byte 64.
The sum of the 256 words of each metadata copy is zero modulo 65536. The newer valid generation is selected using signed modular subtraction; equal generations prefer A. Consecutive generation wrap from 65535 to 0 is supported.
Inode record
Byte offset
Field
0–13
Zero-terminated name, maximum 12 characters; zero padding.
14
Starting data sector; zero for a directory.
16
Unsigned file length, 0–64256; zero for a directory.
18
Sum of file bytes modulo 65536.
20
Type: 0 free, 1 regular file, 2 directory.
22
Parent: 0 for volume root, otherwise inode index 1–16.
24–27
Reserved.
Extents and validation
A regular file uses max(1, ceil(length / 256)) contiguous sectors. Metadata validation checks types, bounds, extents and parent chains. Names are created under the public filename restrictions; MOUNT is not a complete hostile-image validator.
New allocations avoid both generations and open readers. Data writes are reread and verified before publishing the inactive metadata copy. The valid header is written last during formatting. This design does not provide secure deletion or an automatic repair command.
MBX executables are ordinary MKS2 files; their file checksum lives in this inode, not in a separate MBX checksum field. MBX1 format.
mk90.guide
Limits and compatibility
A compact boundary reference for release 0.7.
Numeric limits
Resource
Limit
CPU RAM / boot ROM
16 KiB / 32 KiB.
Text / graphics
30×10 characters / 120×64 monochrome pixels.
Command input
95 characters; four retained tokens including command name.
Filename / normalized path
12 / 95 characters.
Volume sizes
8, 10, 16, 32, 64 KiB.
Inodes
16 per volume, shared by files and directories.
Regular file
64,256 bytes, subject to volume and contiguous-space limits.
File handles
Two total; one writer at a time.
Editor
1,280 bytes.
Contexts
Four fixed slots; PID 0 and 3 share a stack.
Background slots
Two; a pipeline uses one.
Pipe
One FIFO, 256 bytes, two stages.
Shell SLEEP
0–1023 seconds.
Native sleep / BASIC WAIT
0–32767 nominal 32 Hz ticks.
BASIC scalars / arrays
26 signed 16-bit scalars; 26 arrays sharing 76 elements.
BASIC source
64 non-empty lines; literal strings up to 95 bytes.
Unix-style naming does not provide a POSIX shell, fork/exec ABI, Linux syscalls or Unix on-disk filesystem.
MBC-16 is our structured integer BASIC, distinct from factory BASIC.
No floating point, string variables, DEF FN, transcendental functions, inline THEN statements or universal BASIC file syntax.
No arbitrary native executable-file loading, dynamic linking, multiple concurrent BASIC instances or BASIC pipelines.
No UART, floppy, CF/IDE driver, external video/audio interface or PS/2 keyboard driver.
Validation scope
The 0.7 verification covers the existing OS, task, stream, process and BASIC checks plus new structured-control, array and DATA tests. They execute generated instructions in the supplied CPU model with a 16 KiB RAM limit. They are not a physical-board certification or exact timing simulation.
This manual identifies the shipped ROM by SHA-256:
All rights reserved (C) 2026 Papadopol Lucian-Ioan l.i.papadopol@gmail.com
Binary distribution policy
MK90/Unix is distributed as proprietary freeware. The official compiled binaries are provided free of charge for use.
The operating-system source code remains private and is not included in the public distribution. No open-source license is granted. All rights not expressly granted by the copyright holder are reserved.
The public release package contains the compiled ROM and its documentation. BASIC examples in the manual illustrate application syntax and are not the source code of the operating system.
Permissions and contact
For redistribution, bundling or other permissions beyond free-of-charge use, contact Papadopol Lucian-Ioan at l.i.papadopol@gmail.com.
mk90.guide
Keyboard reference
Sequential prefixes, translated key codes and all FK expansions.
Prefix keys
Key
Behavior
SU
Toggle the control prefix; the next translated character is reduced to its control code.
V/N
Toggle a one-character shift prefix. Digits/punctuation select the implemented shifted symbols; backslash becomes |.
R/L
Toggle lowercase/uppercase; the editor displays [a]/[A].
FK
In a .bas editor buffer, arm/disarm one keyword insertion.
Use prefixes sequentially: press the prefix, then the next key. Repeated events of a held prefix are suppressed. Normal character repeats are supplied by RTC-paced controller rescanning, nominally up to eight per second; this is not a multi-key rollover or key-release API.
Context-specific controls
Context
Keys
Shell input
BK submits; backspace deletes; SU+C cancels the line.
Editor
Arrows move; BK inserts LF; SU+S saves; SU+Q exits.
LESS
BK/space forward; lowercase b back only in a file; lowercase q or SU+C exits.
CAT /dev/console
SU+D terminates input.
BASIC runtime
SU+C interrupts; INPUT uses BK to accept a number.
WAIT command
SU+C cancels the wait without killing its target.
Translated control codes
Value
Keys / event
0
No event returned by nonblocking INKEY.
1
Left arrow; also SU+A.
2
Right arrow; also SU+B.
3
Up arrow; also SU+C.
4
Down arrow; also SU+D.
8
Backspace (physical raw DBh).
9
Tab key; not a tab-expansion feature in the editor.
13
BK / Enter.
17
SU+Q.
19
SU+S.
30
FK event (physical raw DFh).
The runtime’s periodic cancellation poll consumes a key and only acts on code 3. It can therefore consume an ordinary key before a later INKEY expression observes it. INKEY is event polling, not a reliable held-key matrix or queued-message contract for every physical key.
Because arrow and SU codes overlap, up-arrow can cancel outside the editor and down-arrow can end console CAT. The table describes the actual translated API in this release.
Entering punctuation
V/N followed by backslash gives |; V/N followed by 2 gives a double quote; V/N followed by 8 gives (; V/N followed by 9 gives ); V/N followed by colon gives *; V/N followed by semicolon gives +.
V/N followed by comma gives <, minus gives =, period gives >, and slash gives ?. These combinations allow assignments and comparisons to be entered directly from the physical keyboard.
Complete FK expansion table
In the table, “key” is the normal 0.7 Latin-map character or control, and raw is the physical key byte in hexadecimal. Every word except a function ending in ( receives a trailing space. The factory-style table has 51 entries.
Insertion availability does not imply compiler support. In particular RUN, SAVE, LOAD, PLAY and the other unimplemented factory words are not silently accepted by MBC. They remain ordinary text in the editor.
Raw
Key
Inserted text
MBC-16 status
0B
A
AUTO
Factory legend; not an MBC-16 feature
0F
I
INPUT
Implemented
13
R
RUN
Factory legend; not an MBC-16 feature
17
[
RETURN
Implemented
23
1
SIN(
Factory legend; not an MBC-16 feature
27
6
COS(
Factory legend; not an MBC-16 feature
2B
B
DRAW
Factory legend; not an MBC-16 feature
2F
J
INIT
Factory legend; not an MBC-16 feature
33
S
STEP
Syntax keyword
37
]
RESTORE
Implemented
3B
Up arrow
DIS
Factory legend; not an MBC-16 feature
3F
Down arrow
GOSUB
Implemented
43
2
EXP(
Factory legend; not an MBC-16 feature
47
7
LOG(
Factory legend; not an MBC-16 feature
4B
W
WAIT
Implemented
4F
K
KILL
Factory legend; not an MBC-16 feature
53
T
SAVE
Factory legend; not an MBC-16 feature
57
X
REM
Implemented
5B
Left arrow
DEV
Factory legend; not an MBC-16 feature
63
3
ABS(
Implemented
67
8
SGN(
Factory legend; not an MBC-16 feature
6B
G
GOTO
Implemented
6F
L
LET
Implemented
73
U
STOP
Implemented
77
Y
READ
Implemented
7B
,
DEF FN
Factory legend; not an MBC-16 feature
83
4
SQR(
Factory legend; not an MBC-16 feature
87
9
ATN(
Factory legend; not an MBC-16 feature
8B
D
DATA
Implemented
8F
M
LIST
Factory legend; not an MBC-16 feature
93
F
FOR
Implemented
97
_
RANDOMIZE
Implemented
9B
.
DIM
Implemented
A3
5
INT(
Factory legend; not an MBC-16 feature
A7
0
RND(
Implemented
AB
E
END
Implemented
AF
N
NEXT
Implemented
B3
H
HELP
Factory legend; not an MBC-16 feature
B7
\
FILES
Factory legend; not an MBC-16 feature
BB
Right arrow
DELETE
Factory legend; not an MBC-16 feature
C3
:
LLIST
Factory legend; not an MBC-16 feature
C7
/
LFILES
Factory legend; not an MBC-16 feature
CB
V
EDIT
Factory legend; not an MBC-16 feature
CF
O
NAME
Factory legend; not an MBC-16 feature
D3
C
CLS
Implemented
D7
@
LOAD
Factory legend; not an MBC-16 feature
E3
;
LPRINT
Factory legend; not an MBC-16 feature
EB
Z
THEN
Syntax keyword
EF
P
PRINT
Implemented
F3
^
PLAY
Factory legend; not an MBC-16 feature
F7
Q
LOCATE
Implemented
mk90.guide
Diagnostics and status codes
Exact message text, return codes and practical interpretation.
Reading diagnostics
Shell diagnostics are in English. The table preserves the displayed strings and explains their meaning. BASIC normally reports BASIC @ line code; its line value is the BASIC line number, including automatically assigned numbers, not necessarily the physical file line.
The shell has no $? variable. WAIT prints a worker’s stored exit result; most commands print only an error message when needed. A missing unregistered command token is tried as an executable path, so a typo can produce NOT FOUND rather than UNKNOWN COMMAND.
BASIC runtime cancellation returns code 130 without the usual BASIC error banner. Some low-level errors, including a rejected WAIT, use the shared status values below.
Cancellation/termination: SU+C in BASIC or KILL result for a worker.
Status 0
Success.
Status 1
I/O ERROR: Controller/transfer error; also an incomplete writer close or rejected native sleep.
Status 2
WRITE VERIFICATION FAILED: A write could not be verified by rereading.
Status 3
VOLUME UNFORMATTED/ABSENT: No valid supported MKS2 header; absent/unformatted or incompatible volume.
Status 4
CORRUPT FILESYSTEM/DATA: Invalid metadata or a file-data checksum failure.
Status 5
READ ONLY: The target device is read-only or protected.
Status 6
NOT FOUND: The requested file, directory or path was not found.
Status 7
NO SPACE OR FREE INODES: No suitable free extent or inode.
Status 8
INVALID ARGUMENTS/NAME: Invalid argument, filename, handle or PID.
Status 9
IS A DIRECTORY: A directory was supplied where a regular file was required.
Status 10
NOT A DIRECTORY: A path component is not a directory.
Status 11
ALREADY EXISTS: The target already exists for an operation requiring a new name.
Status 12
DIRECTORY NOT EMPTY: RMDIR target contains children.
Status 13
ROM ERR @ : ROM resource/module/addressing validation failed; a location may follow.
Status 14
DEVICE ABSENT/NOT MOUNTED: Device has no driver or volume is not mounted.
Status 15
PATH BUSY: Busy resource, disallowed owner, protected current path or no free task slot.
Status 16
SAVE: OPEN EDIT WITH A PATH: Unnamed editor buffer: reopen EDIT with a pathname to save.
Status 17
LBA OUTSIDE DEVICE: Logical block address is outside device bounds.
Status 18
NOT A REGULAR FILE: Unsupported special path or non-regular-file operation.
Status 19
UNKNOWN COMMAND: Unknown registered command, for example an invalid HELP topic.
Status 20
FILE TOO LARGE FOR EDIT: The file exceeds the 1,280-byte editor limit.
Status 21
BROKEN PIPE: EPIPE: the pipe reader has closed.
Status 22
PIPE: INVALID SYNTAX/COMMAND: Invalid pipeline syntax, producer or consumer.
Status 32
BASIC @ line 32: Syntax error, unsupported word, duplicate/non-increasing line number or NUL in source.
Status 33
BASIC @ line 33: Compiler limit exceeded: literal, line table, expression depth, code length or related bound.
Status 34
BASIC @ line 34: GOTO/GOSUB/THEN destination line is absent.
Status 35
BASIC @ line 35: Invalid MBX header, opcode, variable index, fetch/branch bound or device argument.
Status 36
BASIC @ line 36: Invalid or exhausted operand/control stack; mismatched NEXT/RETURN.
Status 37
BASIC @ line 37: Division by zero, STEP 0 or invalid mathematical argument.
Status 38
BASIC @ line 38: Data-file state error or GET beyond EOF.
Status 39
BASIC @ line 39: Array not dimensioned, repeated DIM, invalid bound/index or exhausted array capacity.
Status 40
BASIC @ line 40: READ exhausted the numeric DATA stream.
Status 130
Cancellation/termination: SU+C in BASIC or KILL result for a worker.
Boot and fatal messages
Message
Interpretation
ROM ERR >8K
Extended resident load/check failed. The recovery path in the verified prefix stops; check the programmed image and cartridge addressing.
KEYBOARD BUS ERROR / RESTART MK90
Keyboard/shared-controller failure; the system has stopped and requests restart.
STACK ERR / RESTART
Shared shell/foreground stack check failed; the system has stopped.
RTC UNAVAILABLE
RTC sampling failed to obtain a stable value within its bounded retry loop.
Diagnostic cases
Observation
What to check
ROMTEST milestones pass but MOUNT fails
ROM addressing is separate from data format. Is the data cartridge MKS2, with a valid header and metadata?
DEVICES shows RW but access fails
RW describes the driver flags. It does not prove presence or capacity of the cartridge.
CP/MBC reports space exhausted despite a small output
Replacement uses a new contiguous extent; both metadata generations and open readers can retain older sectors.
Pipeline reports busy
One of background slots 1/2 is required by its consumer. Check PS and stop or wait for a worker.
FK inserts a word which MBC rejects
The editor includes factory legends; only the documented MBC-16 subset compiles.
RND restarts with the same sequence
The runtime deliberately starts its pseudorandom seed at 1 each execution.
Long WAIT does not stop immediately on SU+C
Cancellation is checked at runtime polling/input points, not within the sleep deadline wait.
mk90.api
Native API reference
Calling contracts for the services used by built-in native applications.
Version and calling convention
The native file/task/pipe API has build version 2. Native ROM modules use module ABI 3. These are not POSIX interfaces or stable numeric addresses across releases. This reference applies to the specific 0.7 image identified on the validation page.
Calls use PDP-11 JSR PC,@#entry and RTS PC. This public contract describes services; it does not publish the operating-system implementation or supply a loader for external native machine-code files. Built-in native extensions require integration into a new private firmware build.
Only shell/foreground owners use regular-file services. A task calling native routines must supply valid RAM pointers and preserve its own state across yields. There is no MMU to protect invalid caller buffers. Native blocking routines are not ISR-safe.
mk90.api
Task services
Cooperative task routines for resident workers and the registered pipe consumer.
R0 = PID 1/2, or 0 on rejection/full; R1–R5 preserved.
Allocates and initializes a background slot. Entry must be aligned and in the resident range, except the registered, verified pipe consumer while the pipe is active. Starts with R0 set to the argument, R1–R5 zero and interrupts enabled. Clears the slot’s private data; installs a return trampoline. FREE, DONE and FAULT slots may be reused. It is not a native-file loader.
task_yield
task_yield
No arguments
Contract
Value
Entry address
0x20C4
Returns
R0–R5, SP, PC and supported PSW state restored on resumption.
Saves the calling context, checks stacks and selects the next READY context. In a busy controller transaction or with masked interrupt priority, returns without switching. The call is cooperative and must not be made from an ISR.
task_sleep
task_sleep
R0 = 0–32767 ticks
Contract
Value
Entry address
0x21FA
Returns
R0 = 0 after the wait; 1 for an invalid duration or critical-section call. R1–R5 preserved.
Zero yields. Positive durations set a modular 16-bit deadline and put the caller in SLEEP before yielding. The scheduler makes it READY after the deadline; actual resumption depends on other tasks yielding.
task_self
task_self
No arguments
Contract
Value
Entry address
0x2328
Returns
R0 = address of the current task-control block.
Returns a descriptor pointer, not a numeric PID. The descriptor is internal; applications should not rewrite its scheduling fields.
task_data
task_data
No arguments
Contract
Value
Entry address
0x232E
Returns
R0 = private data address; R1 = 32. Both zero for PID 0/3.
Returns the fixed private area of a background slot. Its contents survive yields and are zeroed when the slot is reused. There is no heap allocation.
task_beep
task_beep
No arguments
Contract
Value
Entry address
0x2386
Returns
R0 = 0 success or 1 I/O error; R1–R5 preserved.
Provides the permitted buzzer path for background workers. It preserves the foreground controller-error state around the guarded tone transaction.
task_exit
task_exit
R0 = final result
Contract
Value
Entry address
0x22FE
Returns
Terminates PID 1/2 or restores the parent of PID 3; PID 0 receives error 1.
Closes an owned pipe read endpoint, records the final result and yields permanently for a worker. A normal RTS from a spawned worker reaches a trampoline that calls this routine. For PID 3, foreground cleanup restores the saved shell continuation.
Task-control block
Four 20-byte TCBs begin at 0x0760. Offsets are byte offsets; fields are little-endian words.
Offset
Field
0
State; see multiprogramming state table.
2
Saved stack pointer.
4
RTC wake deadline modulo 65536.
6 / 8
Stack lower / upper-exclusive bounds.
10
Pointer to resident ASCIIZ name.
12
Application counter, unsigned 16-bit.
14
COUNT/PULSE limit; zero means continuous.
16
Final result.
18
Scheduler-selection count, unsigned 16-bit with wrap.
file_open
R0 = ASCIIZ path; R1 = 1 read / 2 replace; R2 = final length for replacement
Contract
Value
Entry address
0x162E
Returns
R0 = status; R1 = handle 0/1 or FFFF on failure. R2–R5 preserved.
Only PID 0/3 may open regular MKS2 files. Paths are at most 95 bytes, components at most 12. Length is 0–64256 bytes subject to space. Two handles exist; only one writer may be open. A replacement reserves a new extent and does not publish the file until successful close.
file_read
file_read
R0 = handle; R1 = RAM buffer of at least 256 bytes
Reads the next sector; zero bytes means EOF on success. The full buffer capacity is required even for a short final sector. The running checksum counts only valid file bytes. At EOF a checksum mismatch returns status 4 and zero bytes; earlier bytes may already have reached the caller.
The count must be exactly min(256, remaining declared length), or zero after the length has been reached. The last sector is zero-padded outside its valid data; every write is reread and compared. There is no seek, append, arbitrary chunk-size API or implicit growth.
file_close
file_close
R0 = handle
Contract
Value
Entry address
0x191C
Returns
R0 = status; R1–R5 preserved.
Closes a valid handle even if commit fails. A complete, error-free writer publishes to the inactive metadata generation; an incomplete writer fails and preserves the former file. Closing a reader before EOF does not force checksum validation of unread content. A reader at EOF includes validation of the empty-file case.
file_abort
file_abort
R0 = handle
Contract
Value
Entry address
0x190C
Returns
R0 = status; R1–R5 preserved.
Releases an owned handle without publishing data or metadata. Use it for failed or interrupted output. Unpublished extents become allocatable when no generation or reader references them.
Ownership, buffer lifetime and publication
All operations check handle ownership; opens reject background PID 1/2. The file routines do not yield internally. A caller may yield between sectors, while retaining its pathname, handle and application-local state.
The shared TMP/COPYBUF for this build is 0x2C40–0x2D3F. Do not keep sector contents there across other calls that read metadata, paths or ROM resources. FILE_WRITE supports this scratch buffer as its source by preserving valid bytes before padding.
Both valid metadata generations and open readers protect referenced extents from allocation. Only close publishes a complete writer. A writer blocks other mutations; formatting/unmounting a volume with open handles is rejected. Preserve the original failure code while aborting other handles.
File descriptor
Two 40-byte records begin at 0x06A0 and 0x06C8. This internal layout is not an independently stable ABI.
Offset
Field
0
Mode: 0 free, 1 reader, 2 writer.
2
Owner TCB pointer.
4
Device index.
6
Byte position.
8
Persistent transfer error.
10
Running byte checksum modulo 65536.
12–39
Private 28-byte inode copy: name, extent, length, checksum, type and parent.
mk90.api
Pipe services
Dispatcher-bound endpoints of the single RAM byte FIFO.
Blocks in WAIT_WRITE while the FIFO is full. A read wakes the writer. Closing the reader wakes it with EPIPE. There is no caller-supplied descriptor or independently creatable pipe.
pipe_read
pipe_read
Current task owns reader endpoint
Contract
Value
Entry address
0x24A4
Returns
R0 = 0 success / 15 wrong owner; R1 = byte 0–255 or FFFF for EOF. R2–R5 preserved.
Blocks in WAIT_READ while the FIFO is empty and the writer remains open. Drains buffered data before returning EOF after writer closure.
pipe_close_read
pipe_close_read
Current task owns reader endpoint
Contract
Value
Entry address
0x250C
Returns
Registers preserved; non-owner close has no effect.
Clears the read endpoint and wakes a writer blocked for space. It is also called by task-return cleanup and by consumer stack-fault recovery.
pipe_close_write
pipe_close_write
Current task owns writer endpoint
Contract
Value
Entry address
0x2534
Returns
Registers preserved; non-owner close has no effect.
Clears the write endpoint and wakes an empty-buffer reader. Remaining data stays available to read before EOF.
Pipe control
The 256-byte FIFO is at 0x0100; its 16-byte control record is at 0x07F0. The dispatcher creates and binds endpoints; applications do not modify this record directly.
Checks driver presence, read-only flags, logical bounds and volume-base addition, then calls the registered driver with R5 pointing to its descriptor. The SMP driver restricts the physical byte-address space to 64 KiB. A 32-bit LBA interface does not imply 32-bit MKS2 file sizes or working external drivers.
Device descriptor
Four 16-byte records start at 0x0720. A zero callback means OFF.
Offset
Field
0
Driver callback.
2
Physical unit.
4
Physical sector-size descriptor field; SMP is 256.
6
Flags; bit 0 marks read-only.
8 / 10
Logical capacity, low / high word.
12 / 14
Volume base LBA, low / high word.
The block API transfer remains 256 bytes in this release. Reserved floppy/CF records do not provide a sector-size conversion driver. Device support.
mk90.basic.statements
Statement LET
Assign an integer to one variable.
Syntax
[LET] variable = expression
Parameters
Parameter
Meaning
variable
One letter A–Z, optionally followed by an array index in parentheses; case-insensitive.
expression
A numeric expression; stored as a signed 16-bit bit pattern.
Behavior
LET is optional. All 26 scalar variables start at zero on each execution. Array elements start at zero after DIM; a scalar and array of the same letter are independent. An indexed assignment evaluates the index before the right-hand side, then stores the result.
Example
10 A=2+3*4
20 LET B=A-1
30 PRINT A;",";B
Limits and diagnostics
Scalar names are single letters. DIM declares arrays; string variables and multi-letter names are outside this dialect.
Without a final separator, PRINT appends a newline. A trailing semicolon or comma suppresses the newline; a trailing comma still emits its one space.
Numbers are signed decimal values. An empty PRINT on its own physical line prints a blank line. This dialect has no tab zones or automatic spacing between items separated by semicolons.
Read one signed decimal integer from the keyboard.
Syntax
INPUT variable
Parameters
Parameter
Meaning
variable
Destination A–Z.
Behavior
Shows a question-mark prompt. Enter digits, optionally preceded by a minus sign, and confirm with BK. At least one digit is required; a bare BK does not complete input.
Accepted values range from −32767 to 32767. A digit which would overflow that range is ignored. Unsupported characters are ignored; a leading plus is not required. Keyboard waiting cooperates with native background tasks. SU+C cancels the program.
Example
10 INPUT A
20 PRINT "ENTERED ";A
30 END
Limits and diagnostics
One numeric variable only. No string input, prompt-list syntax, comma-separated input list or INPUT #file. Numeric backspace is not implemented; cancel and restart to correct a mistaken number.
Select a numbered destination or a structured block.
Syntax
IF expression THEN line-number
IF expression THEN
statements
[ELSE
statements]
ENDIF
Parameters
Parameter
Meaning
expression
Zero is false; every nonzero value is true.
Behavior
The numbered form remains compatible with earlier listings. The multiline form nests with loops and other IF blocks. THEN ends the header line; ELSE and ENDIF occupy separate lines. The compiler validates matching delimiters before publishing the executable.
Example
A=2
IF A THEN
PRINT "TRUE"
ELSE
PRINT "FALSE"
ENDIF
Limits and diagnostics
No inline THEN statement, ELSEIF, END IF spelling or implicit closing at EOF.
The compiler replaces the source line number with an executable byte offset. An absent target is compilation error 34. Runtime branch bounds are checked.
A GOTO does not unwind FOR or GOSUB frames. Avoid jumping into or out of active structured loops or subroutines in a way that leaves unmatched control frames.
Example
10 PRINT "AGAIN"
20 WAIT 32
30 GOTO 10
Limits and diagnostics
No computed GOTO, ON ... GOTO or labels made of names. SU+C stops an infinite loop at a runtime cancellation poll.
Pushes a return frame and jumps to the target. RETURN resumes at the following instruction, which may be after a colon on the caller’s line.
GOSUB and FOR share eight last-in, first-out control frames. Calls can nest within that combined limit. Variables are global; there are no parameters or automatic local variables.
Example
10 A=4
20 GOSUB 50
30 PRINT A
40 END
50 A=A+1
60 RETURN
Limits and diagnostics
No named subroutines or functions defined by the program. Finish nested FOR frames before returning from a subroutine.
The top control frame must be a GOSUB return frame. It is popped and execution resumes at its saved byte offset. An empty stack or a FOR frame at the top causes status 36.
Example
100 A=A+1
110 RETURN
Limits and diagnostics
No RETURN expression or return-line argument. This fragment must be entered through GOSUB.
Step expression, evaluated at entry; default 1, zero is an error.
Behavior
The loop includes the limit when the step reaches it exactly. Positive steps continue while the variable is at most the limit; negative steps continue while it is at least the limit.
If the initial range is empty, the runtime skips to the corresponding NEXT, including nested FOR/NEXT pairs, without executing the body. Otherwise a frame stores the loop variable, body location, limit and step.
At NEXT the variable is incremented and compared again. Signed overflow of that increment ends the loop. FOR and GOSUB share a maximum of eight active frames.
Example
10 FOR I=3 TO 1 STEP -1
20 PRINT I
30 NEXT I
40 END
Limits and diagnostics
NEXT must name the matching variable, and active loops must close in stack order. No variable lists, EXIT FOR or implicit stack unwinding on GOTO.
Adds the saved step. If the signed loop bound is still satisfied, resumes the loop body; otherwise pops the frame. A mismatched variable or wrong frame type is status 36.
After normal termination the variable contains its incremented value, typically one step beyond the bound. A signed-overflow exit retains the wrapped bit pattern.
Example
10 FOR I=1 TO 3
20 PRINT I
30 NEXT I
40 PRINT I
Limits and diagnostics
The variable is mandatory. NEXT I,J and an unnamed NEXT are not supported.
A colon inside the comment remains part of the comment. REM is a statement token, so separate it from following word text with whitespace. Comment-only lines count toward the 64 non-empty-line limit.
Example
10 REM This is a comment: still a comment
20 PRINT "HELLO"
30 END
Closes the one data file if open, releases the executable reader and returns control to the shell. A complete output is committed; an incomplete output produces an error and preserves the older file.
END and STOP have the same behavior; STOP does not retain a resumable program state. An END opcode is also appended by the compiler at end of source.
Example
10 PRINT "DONE"
20 END
Limits and diagnostics
No CONT or resume command. Completed earlier file closes remain persistent; errors and SU+C abort writers which have not been published.
Closes the one data file if open, releases the executable reader and returns control to the shell. A complete output is committed; an incomplete output produces an error and preserves the older file.
END and STOP have the same behavior; STOP does not retain a resumable program state. An END opcode is also appended by the compiler at end of source.
Example
10 PRINT "DONE"
20 STOP
Limits and diagnostics
No CONT or resume command. Completed earlier file closes remain persistent; errors and SU+C abort writers which have not been published.
Clear the complete LCD framebuffer and text console.
Syntax
CLS
Parameters
No parameters.
Behavior
Zeros all 960 framebuffer bytes, resets the 30×10 text buffer and invalidates the text shadow. Text output resumes at column 0, row 0. Unlike the shell’s text CLEAR, this includes pixels between glyph rows and the bottom graphics rows.
Coordinates are zero-based character cells; the first parameter is the column. Text can wrap and scroll the console as usual after this position. Out-of-range values cause runtime status 35.
Example
10 CLS
20 LOCATE 4,2
30 PRINT "MK90"
40 END
Limits and diagnostics
These are text coordinates, not the 120×64 pixel coordinates used by drawing statements.
Changes the addressed pixel through the framebuffer mapping, retaining other bits in its byte. The pixel operation does not redraw the entire display. Coordinates are bounded; invalid values give status 35.
Example
10 CLS
20 PSET 60,32
30 WAIT 32
40 END
Limits and diagnostics
Monochrome set operation; no color or drawing-mode argument. Text rendered over graphics may replace pixels in its glyph area.
Draw a monochrome segment between two pixel coordinates.
Syntax
LINE x1, y1, x2, y2
Parameters
Parameter
Meaning
x1, x2
Expressions, 0–119 inclusive.
y1, y2
Expressions, 0–63 inclusive.
Behavior
Validates both endpoints and draws an inclusive integer segment using incremental pixel operations. The line is set, not erased. No full framebuffer copy is needed for each pixel.
Example
10 CLS
20 LINE 0,0,119,63
30 LINE 0,63,119,0
40 END
Limits and diagnostics
No parentheses-pair syntax, color, box option, filled rectangle, clipping of off-screen endpoints or relative-coordinate mode.
Expression interpreted as an unsigned 16-bit value, 1–65535.
cycles
Expression in the inclusive range 0–256.
Behavior
The first value is a raw controller divisor. The second controls the driver’s bounded transfer loop. Zero cycles performs no waveform-data iterations and is not interpreted as an infinite duration.
The transaction releases the shared controller afterwards. Values outside the accepted bounds cause status 35.
Example
10 SOUND 800,8
20 WAIT 8
30 SOUND 600,8
40 END
Limits and diagnostics
The arguments are not frequency in hertz and duration in milliseconds. No music-string PLAY command or calibrated pitch/duration API is implemented. Use RTC waits for nominal timing between operations.
At the nominal 32 Hz rate, WAIT 32 requests one second. WAIT 0 yields without a timed wait. Other runnable native contexts may continue.
The deadline is modular and resumption depends on the scheduler. SU+C is checked after returning to a runtime polling point, not continuously inside this timed sleep.
Example
10 FOR I=1 TO 3
20 PRINT I
30 WAIT 32
40 NEXT I
50 END
Limits and diagnostics
This is a timer extension, not a port-mask WAIT statement found in some BASICs. The shell WAIT command waits for a PID and is different.
Literal MKS2 pathname; relative to the shell directory in which the program runs.
INPUT / OUTPUT
Binary read or exact-length replacement; no AS clause.
length
Output length expression interpreted as unsigned, 0–64256, subject to volume space.
Behavior
The executable already holds one of the two file handles, leaving one data handle. Close it before opening another file. INPUT requires an existing regular file; OUTPUT creates or replaces using a new extent.
OUTPUT does not publish until a successful CLOSE or END after exactly the declared length has been supplied. Every sector is verified. Failure preserves the former destination.
The pathname is a literal, not a string expression. File names and components preserve case. Controller and filesystem errors use the ordinary OS status codes.
Example
10 OPEN "bytes",OUTPUT,2
20 PUT 65
30 PUT 66
40 CLOSE
50 END
Limits and diagnostics
This comma-based syntax is an MBC-16 extension. No handles or #file numbers in BASIC, simultaneous data files, append, seek, text-file INPUT#/PRINT#, /dev/null or /dev/console.
Uses a 256-byte internal cache. Reading past EOF produces status 38; check the EOF expression before the next GET. The underlying file reader checks data integrity as it reaches EOF.
Example
10 OPEN "bytes",INPUT
20 IF EOF THEN 60
30 GET A
40 PRINT A
50 GOTO 20
60 CLOSE
70 END
Limits and diagnostics
Requires an INPUT data file. There is no file-number argument or string GET.
Accumulates bytes in a 256-byte buffer. Full sectors are sent to the verified writer; CLOSE or END flushes the final partial sector. The total supplied bytes must match the length declared in OPEN.
An out-of-range byte produces status 35. Too little or too much output prevents successful publication; previously committed file versions are preserved.
Example
10 OPEN "digits",OUTPUT,3
20 PUT 49:PUT 50:PUT 51
30 CLOSE
40 END
Limits and diagnostics
Requires an OUTPUT data file. This writes binary bytes, not decimal formatting or automatic line endings.
For OUTPUT, flushes pending bytes and commits only a complete, verified file. For INPUT, closes the reader. The executable’s own reader remains open until the program exits.
Calling CLOSE without an open data file is status 38. END/STOP automatically closes a data file; SU+C or errors abort unpublished output.
Runtime integer 0–75, subject to remaining total capacity.
Behavior
DIM A(9) allocates ten zeroed words, indexed 0 through 9. All arrays share 76 elements. An array may be dimensioned once per execution. Out-of-range access, missing DIM, repeated DIM or insufficient capacity returns status 39.
Example
DIM A(3)
FOR I=0 TO 3
A(I)=I*I
NEXT I
PRINT A(3)
Limits and diagnostics
One dimension and one declaration per statement. No REDIM, arrays of strings or implicit allocation.
Data is stored inline in the executable. Execution skips it. READ finds DATA in physical source order regardless of branches, including DATA after END.
Example
READ A,B
PRINT A;B
END
DATA -7,42
Limits and diagnostics
Numeric literals only; no expressions, quoted data or empty fields.
Each destination consumes one item. The data cursor is independent of the execution PC. Exhaustion returns status 40; previously assigned destinations remain assigned.
Example
DIM A(1)
READ A(0),A(1)
PRINT A(1)
END
DATA 12,34
Limits and diagnostics
Arrays must already be dimensioned. This is separate from file GET.
Absolute integer value, within the 16-bit representation.
Behavior
Negative values are negated; nonnegative values are retained. The exceptional value −32768 has no positive signed 16-bit representation and remains the bit pattern 8000h (displayed as −32768).
An integer from 0 to limit−1; limit must be 1–32767.
Behavior
The runtime starts from seed 1 for each program invocation. A nonzero 16-bit shift/XOR state is advanced and reduced modulo the positive limit. Re-running a program gives the same sequence.
This is not a real-valued RND function or a cryptographic generator. The range is bounded but no statistical uniformity guarantee is given.
Example
10 FOR I=1 TO 5
20 PRINT RND(6)+1
30 NEXT I
40 END
Limits and diagnostics
RANDOMIZE expression sets the seed reproducibly; seed zero is normalized to one. Nonpositive limits cause status 37.
The 16-bit tick pattern, displayed as a signed integer when printed.
Behavior
Advances at a nominal 32 ticks per second and wraps modulo 65536. Printed values become negative after bit 15 is set. Modular differences are useful over intervals shorter than 32768 ticks.
Example
10 A=TICKS
20 WAIT 32
30 PRINT TICKS-A
40 END
Limits and diagnostics
No parentheses. This counter is relative to OS initialization, not a date/time epoch or CPU-cycle counter.
Translated character/control code, or 0 when no event is available.
Behavior
Uses the OS nonblocking keyboard path, which also cooperates with the scheduler and display. It exposes events and repeats rather than a matrix of simultaneously held keys.
The runtime separately polls for cancellation every 32 opcodes. Those polls can consume ordinary events before INKEY sees them. Code 3 is also returned by up-arrow and used to cancel the runtime.
Example
10 A=INKEY
20 IF A=0 THEN 10
30 PRINT A
40 END
Limits and diagnostics
No trailing $ and no parentheses. It is not the string-valued INKEY$ found in other BASICs.
Reads the selected RTC component with bounded update checks and converts its configured BCD/binary representation. HOUR also converts 12-hour mode to 24-hour form.
Separate expressions are separate samples: HOUR, MINUTE and SECOND in one PRINT are not a guaranteed atomic timestamp across a rollover.
Example
10 PRINT HOUR
20 END
Limits and diagnostics
No parentheses or write form. RTC failure returns an OS I/O error.
Reads the selected RTC component with bounded update checks and converts its configured BCD/binary representation. HOUR also converts 12-hour mode to 24-hour form.
Separate expressions are separate samples: HOUR, MINUTE and SECOND in one PRINT are not a guaranteed atomic timestamp across a rollover.
Example
10 PRINT MINUTE
20 END
Limits and diagnostics
No parentheses or write form. RTC failure returns an OS I/O error.
Reads the selected RTC component with bounded update checks and converts its configured BCD/binary representation. HOUR also converts 12-hour mode to 24-hour form.
Separate expressions are separate samples: HOUR, MINUTE and SECOND in one PRINT are not a guaranteed atomic timestamp across a rollover.
Example
10 PRINT SECOND
20 END
Limits and diagnostics
No parentheses or write form. RTC failure returns an OS I/O error.
−1 after its final byte has been consumed, otherwise 0.
Behavior
Considers both unread bytes in the internal cache and the underlying file position. An empty input file reports EOF immediately. EOF does not consume a byte.
It requires a valid INPUT data handle. Use it before GET to avoid reading past the end.
Example
10 OPEN "bytes",INPUT
20 IF EOF THEN 60
30 GET A
40 PRINT A
50 GOTO 20
60 CLOSE
70 END
Limits and diagnostics
No file-number argument or parentheses. An invalid file state gives a data-file or handle error.
The complete implemented integer dialect, without assuming factory-BASIC compatibility.
Compile and execute
mbc name.bas
exec name.mbx
Both the compiler and runtime execute on the MK90. The compiler produces MBX1 bytecode with resolved expressions and branches. The runtime is native PDP-11 code; it does not need the original source while running.
MBC-16 is our structured integer BASIC dialect. It provides signed 16-bit scalars and arrays, literal strings, nested control blocks and inline numeric data. It does not claim compatibility with the factory BASIC or a standard BASIC certification. Unsupported syntax is rejected rather than ignored. The factory FK table can insert words which this dialect does not implement.
mk90.basic
Language syntax and expressions
Exact MBC-16 grammar, integer arithmetic and source limits.
Source files and line numbers
A source is a regular file whose suffix is .bas, ignoring case. Use single-byte ASCII syntax with LF or CRLF line endings. CR and tab are skipped as lexical whitespace; CR-only files do not provide statement-line boundaries. An embedded NUL is an error.
A non-empty line may begin with a decimal number from 1 to 65535. Numbers must be strictly increasing in physical source order; the compiler does not sort them. An unnumbered non-empty line receives the preceding number plus one, starting at 1. Empty lines do not consume a line-table entry.
At most 64 non-empty lines, including comment-only lines, can be compiled. Several statements can share a physical line using colons. Branches still target the start of a numbered line.
This grammar summarizes the common forms; the precedence table and individual statement pages provide the remaining rules. Keywords and A–Z are case-insensitive. Literal strings and pathnames retain their case. No implicit keyword concatenation or multi-letter variable names. IF/ELSE/ENDIF, WHILE/WEND and REPEAT/UNTIL provide multiline structured control; their delimiter rules are on the individual statement pages.
Numeric representation
Variables hold signed 16-bit values, −32768 through 32767, and initialize to zero on every run. Decimal literals may encode 0 through 65535; values with bit 15 set are interpreted as negative when used or printed. A leading sign is a unary operator.
Addition, subtraction and multiplication wrap modulo 65536. Division truncates toward zero. MOD has the dividend’s sign. For example -17/5 is −3 and -17 MOD 5 is −2. Division by zero is status 37.
Comparisons return −1 for true and 0 for false. IF tests any nonzero value as true. AND, OR and NOT are bitwise operators, without short-circuit evaluation. There is no floating point, exponent notation, hexadecimal-literal notation or string arithmetic.
NOT binds tightly in this dialect; parenthesize a comparison when negating its result.
5
* / MOD
Left-associative.
4
+ -
Left-associative.
3
= <> < <= > >=
Same precedence; evaluated left-associatively.
2
AND
Bitwise.
1
OR
Bitwise.
Use NOT (A=0) to negate a comparison. NOT A=0 means (NOT A)=0. Chained comparisons are arithmetic combinations of −1/0 results, not mathematical chained inequalities.
Literal strings
Only double-quoted literal strings are available, up to 95 bytes per literal. Empty literals are accepted. There is no escape convention for an embedded quote, no string variable and no concatenation operator; PRINT can place several literals or numeric expressions next to one another.
OPEN requires a literal pathname. Assignment and comparison symbols are available through the V/N prefix; see keyboard punctuation before attempting to type a new listing from scratch.
Control flow details
IF supports either THEN followed by a literal line number or a multiline THEN/ELSE/ENDIF block; inline THEN statements are not supported.
For legacy IF ... THEN number, following colon statements remain independent. Structured block delimiters occupy their own physical source lines.
GOTO/GOSUB targets must exist; destination offsets are resolved at compile time.
FOR/NEXT and GOSUB/RETURN share eight LIFO control frames. GOTO does not clean them up.
END and STOP both terminate; no resumable stop state exists.
A bare PRINT followed by a colon emits a newline.
Compiler and runtime limits
Resource
Bound
Scalars
26, A–Z.
Arrays
26 independent names; 76 signed-word elements in total; zero-based bounds.
Structured nesting
16 active blocks.
Forward branches
64 per program; ELSE uses an additional slot.
Non-empty source lines
64.
Line-number literals
1–65535, strictly increasing.
Literal integer
0–65535 before unary sign.
Literal string
95 bytes.
Expression parser depth
12; operators and nesting both contribute.
Operand stack
16 values.
FOR/GOSUB stack
Eight shared frames.
Source editor
1,280 bytes; the streaming compiler has a separate line limit.
Data files
One open in addition to the executable.
Reserved and unsupported forms
Recognized language words are: LET, PRINT, IF, THEN, GOTO, GOSUB, RETURN, FOR, TO, STEP, NEXT, INPUT, END, STOP, REM, CLS, BEEP, WAIT, LOCATE, PSET, PRESET, LINE, SOUND, TICKS, INKEY, ABS, RND, MOD, AND, OR, NOT, OPEN, AS, LEN, GET, PUT, CLOSE, EOF, HOUR, MINUTE, SECOND, PATH, OUTPUT, ELSE, ENDIF, WHILE, WEND, REPEAT, UNTIL, DIM, RANDOMIZE, DATA, READ, RESTORE. Recognition in the scanner does not make every word a usable statement. AS, LEN and PATH are reserved/internal tokens without a supported source form in 0.7.
Outside this dialect: string variables, real numbers, DEF FN, transcendental functions, RUN/LIST/SAVE/LOAD/PLAY as BASIC statements, file-number syntax, append/seek, named procedures and inline IF statements. Use the OS commands to edit, compile and launch files. DATA is numeric; READ accepts scalar or indexed destinations; RESTORE rewinds to the first datum.
mk90.basic
MBC compiler
Two-pass compilation on the MK90 and transactional executable creation.
Invocation and output
mbc program.bas
Takes exactly one pathname, which must end in .bas case-insensitively. Replaces the suffix with lowercase .mbx in the same directory. There is no output-name option. The output component must still fit the filesystem’s 12-character limit.
Copy a ROM source to a writable volume first. Successful compilation reports the output path and executable size, ending with B OK.
Passes
Phase
Work
Pass 1
Stream the source; tokenize; parse statements and expressions; count bytes; build up to 64 line-number/offset pairs.
Pass 2
Reopen the source; resolve numeric branch targets; emit the 16-byte MBX1 header and bytecode into the exact-length writer.
Publication
Validate source reads, flush output and close the writer. Only a successful close makes the new executable visible.
Expressions become stack operations; branch targets become byte offsets. The result is compiled bytecode, not the original source renamed with another extension.
Workspace and cooperation
The source is buffered in 256-byte blocks. The console TEXT/SHADOW area is temporarily used for scanner data and the target table. The compiler does not render a live screen or poll for keyboard cancellation while those buffers are in use.
It yields between source lines so compatible native workers can run. Parser/common services stay in an upper module while lower compiler phases are exchanged through a stable call gate. PID 0 remains suspended during the command.
Errors and preservation
Syntax and resource errors report BASIC @ line code. Status 32 is syntax, 33 a compiler limit, and 34 a missing branch target. File or ROM failures retain their OS code. On failure, handles are aborted and the console is restored.
The previous executable is preserved when a compile or publication fails. There is no partly compiled executable published under its name. Compilation still needs free contiguous space for the proposed output alongside protected older extents.
Workflow
edit /mnt/smp1/app.bas
mbc /mnt/smp1/app.bas
exec /mnt/smp1/app.mbx
Leave EDIT after saving before entering the compiler command. Compiler input is the saved file, not the editor’s unsaved buffer. Exact syntax · MBX1 format.
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.
mk90.basic
MBX1 executable format
The file header and opcode encoding for bytecode ABI 2, with ABI 1 execution support.
Header
Byte offset
Length
Value
0
4
ASCII MBX1.
4
2
Bytecode ABI: 2 for new output; EXEC also accepts 1.
6
2
Flags, 0.
8
2
Total file size, including header.
10
2
Variable count, 26.
12
2
Operand-stack limit, 16.
14
2
Reserved, 0.
Words are little-endian. The minimum accepted executable length is 17 bytes: the header and at least an instruction byte. The file-data checksum is the MKS2 inode checksum, not a field in this header. The entire file is checked before execution.
Encoding
Each opcode is one byte. Variable operands are zero-based, A=0 through Z=25. Immediate word operands and branch offsets are little-endian. Branch offsets count from the start of the file, so executable targets must be at least 16 and less than the total size.
LINE is an internal source-line marker used for error reporting; the source-language drawing LINE compiles to DRAW. KEY implements INKEY. STRING and PATH carry a length byte followed by data. All other opcodes have no inline operand unless listed below; their arguments come from the operand stack.
Opcode index
Decimal
Hex
Mnemonic
Inline operand
0
00
END
None
1
01
LINE
u16 source-line marker
2
02
CONST
u16 bit pattern
3
03
LOAD
u8 variable index
4
04
STORE
u8 variable index
5
05
ADD
None
6
06
SUB
None
7
07
MUL
None
8
08
DIV
None
9
09
MOD
None
10
0A
NEG
None
11
0B
EQ
None
12
0C
NE
None
13
0D
LT
None
14
0E
LE
None
15
0F
GT
None
16
10
GE
None
17
11
AND
None
18
12
OR
None
19
13
NOT
None
20
14
PRINT
None
21
15
STRING
u8 length, then literal bytes
22
16
NL
None
23
17
JMP
u16 byte offset
24
18
JNZ
u16 byte offset
25
19
CALL
u16 byte offset
26
1A
RET
None
27
1B
FOR
u8 variable index
28
1C
NEXT
u8 variable index
29
1D
INPUT
u8 variable index
30
1E
CLS
None
31
1F
BEEP
None
32
20
WAIT
None
33
21
LOCATE
None
34
22
PSET
None
35
23
PRESET
None
36
24
DRAW
None
37
25
SOUND
None
38
26
TICKS
None
39
27
KEY
None
40
28
ABS
None
41
29
RND
None
42
2A
OPENR
None
43
2B
OPENW
None
44
2C
GET
u8 variable index
45
2D
PUT
None
46
2E
CLOSE
None
47
2F
EOF
None
48
30
HOUR
None
49
31
MINUTE
None
50
32
SECOND
None
51
33
PATH
u8 length, then pathname bytes
52
34
AINIT
None
53
35
DIM
u8 array index
54
36
ALOAD
u8 array index
55
37
ASTORE
u8 array index
56
38
RANDOMIZE
None
57
39
DATUM
u16 literal bit pattern
58
3A
READ
None
59
3B
RESTORE
None
Compatibility
MBX1 is a format for this VM. It is not ELF, PDP-11 a.out, a native instruction stream or a tokenized factory-BASIC cartridge. Header and bounds validation do not establish full semantic validity for manually edited bytecode. New MBC output uses ABI 2 and begins with AINIT. Opcodes 0–51 retain their ABI 1 numbers; the new opcodes are appended. The older EXEC cannot run ABI 2. Another device must implement all opcode and device semantics it advertises. Use MBC from the matching release.
mk90.basic
Example programs
Complete listings for arithmetic, control flow, files, display and timing.
Using the examples
The HTML package includes eight complete ASCII BAS files under examples/. They illustrate the supported dialect and may be compiled once present on a writable MKS2 volume. The manual archive itself is not an SMP filesystem image.
The boot ROM includes its own demo.bas, so the first trial needs no file-transfer utility. For entering operators directly on the MK90, see keyboard punctuation. This release does not have a UART transfer command.
10 A=0
20 FOR I=1 TO 3
30 FOR J=2 TO 1 STEP -1
40 A=A+I*J
50 NEXT J
60 NEXT I
70 IF A=18 THEN 100
80 PRINT "UNEXPECTED"
90 END
100 PRINT "TOTAL ";A
110 END
Navigation, search, syntax conventions and offline use.
Navigation
The top bar switches between the overview, commands, system chapters, BASIC and native API. The left pane groups reference pages by package. The right pane lists sections on the current page. Previous/next links step through the reference pages.
The hierarchy shows all packages; the alphabetical index includes pages and native API routine names. Every command and BASIC statement has its own linked reference page, following a Javadoc-style organization.
Search
The search field searches page titles, summaries, keywords, sections and native API routine entries. Press the slash key to focus it, or Escape to dismiss its results. Results are links; the page remains usable if JavaScript is disabled.
Search is local to this manual. It does not contact a service or search files on the MK90.
Notation
Notation
Meaning
[argument]
Optional syntax; do not type the brackets.
count|pulse in a synopsis
Alternatives: select one. An actual | in a shell command line is the pipeline operator.
expression
An MBC-16 integer expression, not a literal word to type.
SU, then S
Sequential key presses.
0x1234 or memory-map ranges
Hexadecimal byte addresses. Other numeric limits are decimal unless marked.
Status code links
Jump to the shared diagnostic explanation.
Offline use and printing
Extract the HTML archive while retaining its directory structure and open index.html in a browser. All styles, scripts and search records are local; no web server, Java installation or internet connection is required.
Print any page with the browser’s print command. Navigation and search controls are omitted from print. The optional single-file edition contains the same reference text with internal links and embedded assets.
Documentation version
This manual describes the 0.7 binary identified by its SHA-256 on the validation page. It documents implemented behavior rather than proposed future capabilities. Copyright and release policy.
Index
Alphabetical index
Commands, BASIC syntax, system topics and native API routines.