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
$2000environment; 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 page | CPU address at command entry | File 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:
| Section | CPU address | Mapping | Role |
|---|---|---|---|
| 0 | $0000-$0fff | DOT_KERNEL_ROM_PAGE | esxDOS-compatible restart kernel |
| A | $1000-$1fff | RAM page 0 ($c0) | staging alias for permanent RAM |
| B | $2000-$2fff | DOT_CODE_PAGE_0 | first 4 KiB of the dot command |
| 3 | $3000-$3fff | DOT_CODE_PAGE_1 | second command page |
The command begins at $2000. It receives the normal dot-command arguments:
HLpoints to the text after the command name, or is zero;BCpoints 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
$08accepts an esxDOS hook code and dispatches it to the dot bridge. - RST
$10invokes the 48K ROM character-output service. - RST
$18invokes an arbitrary 48K ROM routine specified by the word following the restart. - RST
$20terminates the dot environment and transfers control to the address inHL.
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-$3dffis 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_workspaceat$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
.tapprogram whose buffer is in$4000-$ffffcan pass that buffer directly to the regular esxDOS module: this region is unaffected by the low-16K mapping transition. - A
READorWRITEwhose 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.