Skip to main content

Dot Command Design

This document defines the Spectranext design for classic esxDOS-compatible dot commands on a stock 48K Spectrum. It is a design document: names such as DOT_KERNEL_ROM_PAGE and DOT_HANDLER_PAGE describe roles, not final page numbers.

The design has two goals:

  • execute a standard dot command in its expected $2000 environment; and
  • let that command make esxDOS calls while retaining the existing Spectranet VFS and the regular esxDOS compatibility module.

The classic esxDOS command image starts at $2000 and has 7.5 KiB of code/data, $2000-$3dff. The command owns that memory and may use it for writable variables. $3e00-$3fff is reserved for the loader's NUL-terminated command line and is not general DOT storage.

1. Loading a dot command

The BASIC-extension command parser recognises a command name beginning with .. It resolves the command in /sys/dot, opens the file through the normal VFS, and validates that its length does not exceed $1e00 bytes.

The loader reserves two 4 KiB RAM pages for the command:

RAM pageCPU address at command entryFile bytes
DOT_CODE_PAGE_0$2000-$2fff$0000-$0fff
DOT_CODE_PAGE_1$3000-$3fff$1000-$1dff

The loader copies the command line without its leading dot into the unused tail at $3e00-$3fff, with a NUL terminator. The loader retains the command file handle only if support for streamed, larger commands is later added; it is not required for the base 7.5 KiB command format.

Before entering the command, the loader records the command's two RAM pages, the original Spectrum stack pointer, and the command-line pointers in dedicated dot-kernel state.

2. Dot-command entry environment

At entry, the following map is active:

SectionCPU addressMappingRole
0$0000-$0fffDOT_KERNEL_ROM_PAGEesxDOS-compatible restart kernel
A$1000-$1fffRAM page 0 ($c0)staging alias for permanent RAM
B$2000-$2fffDOT_CODE_PAGE_0first 4 KiB of the dot command
3$3000-$3fffDOT_CODE_PAGE_1second command page

The command begins at $2000. It receives the normal dot-command arguments:

  • HL points to the text after the command name, or is zero;
  • BC points to the complete command line without the leading dot.

For an esxDOS RST $08 hook, dot commands pass pointer parameters in HL where an ordinary esxDOS caller would use IX. This agrees with the NextZXOS dot-command ABI, while preserving the classic 7.5 KiB image limit used here.

Page A is deliberately RAM page 0. It aliases permanent Spectranet RAM when that same page is later mapped into section 3:

page A = RAM 0:  $1d00
section 3 = RAM 0: $3d00 (buf_workspace)

This alias is the staging bridge; it avoids a second pathname copy.

3. esxDOS kernel pieces

DOT_KERNEL_ROM_PAGE contains the fixed restart vectors used while a dot command is active.

  • RST $08 accepts an esxDOS hook code and dispatches it to the dot bridge.
  • RST $10 invokes the 48K ROM character-output service.
  • RST $18 invokes an arbitrary 48K ROM routine specified by the word following the restart.
  • RST $20 terminates the dot environment and transfers control to the address in HL.

The kernel must contain only code that is safe while sections B and 3 are being remapped. In particular, it cannot keep persistent state in page A or in the command pages.

The existing esxdos.module remains a normal Spectranet ROM module, with its usual module header and MODULECALL entry point. The dot kernel is not a second VFS implementation: it marshals a call and then invokes that module.

4. Servicing an esxDOS call from a dot command

The following is the required path for a pathname-based call such as F_OPEN, where the command's pathname is at $2800.

dot command                 dot kernel / bridge                 Spectranet
----------- ------------------- ----------
RST $08, F_OPEN ───────► copy $2800 → $1d00
map section 3 = RAM 0
($1d00 now aliases $3d00)
move to temporary C0 stack
map B = DOT_HANDLER_PAGE
enter normal Spectranet section 0
module-call
esxdos.module
VFS OPEN HL=$3d00
restore dot section 0, B and 3
◄──── restore original stack and RET

The bridge handler is aligned to execute at $2000. It is therefore safe to change section 0 from the dot kernel ROM to normal Spectranet ROM while it is running. It calls the ordinary esxdos.module, which in turn calls the normal VFS entry points.

The VFS dispatcher already saves the caller's page B, pages the filesystem module, and restores the caller page B before returning. Consequently it can return safely to DOT_HANDLER_PAGE; no special VFS copy is required.

Marshalling rules

  • A short input string or structure in $2000-$3dff is copied through page A before either command page is replaced.
  • After section 3 becomes RAM 0, the staged bytes are addressed through their permanent-RAM alias, normally buf_workspace at $3d00.
  • The bridge must retain its own saved mappings and temporary stack in a reserved permanent-RAM area. A dot command is allowed to relocate its stack into its own code/data image, so that original stack cannot remain active after B or 3 is changed.
  • A .tap program whose buffer is in $4000-$ffff can pass that buffer directly to the regular esxDOS module: this region is unaffected by the low-16K mapping transition.
  • A READ or WRITE whose user buffer is in dot memory cannot be passed directly to VFS. The bridge transfers it in bounded chunks through permanent RAM, copying into the dot buffer after a read or before a write.

The exit path switches section 0 back to the dot kernel before changing B or 3 back to the command pages. It then restores the original stack pointer and executes RET. No code running from B may page out its own page and continue executing there.

5. RST $10, RST $18, and RST $20

These restarts are part of the dot environment rather than ordinary Spectranet API calls.

RST $10: 48K ROM character output

The kernel implements RST $10 as the standard 48K ROM print service with the character in A. It temporarily restores the 48K ROM mapping, calls the ROM routine, and restores the dot map on return. A=$80 is not valid for this service.

RST $18: call a 48K ROM routine

RST $18 is followed by DEFW address. The kernel consumes the address, temporarily maps the 48K BASIC ROM, calls the requested routine, and restores the dot environment on return. BASIC errors use the normal dot-command error path unless an M_ERRH handler has been installed.

RST $20: leave dot mode and bootstrap code

With HL containing a destination address, RST $20 is non-returning. The kernel ends the dot environment, restores the standard Spectrum/48K ROM mapping, restores a valid non-dot stack, and jumps to HL. It must not merely JP (HL): doing so would leave the dot mapping present and prevent normal ROM, interrupt, and later dot-command operation.

Stack restriction for external calls

For RST $10, RST $18, and the M_P3DOS esxDOS hook, the command stack must not remain inside the command pages while the external ROM is active. The kernel therefore uses its temporary permanent-RAM stack for the complete transition. This is also required for any bridge call that changes B or 3.

References