Skip to content

Nucleus Z80 Runtime and Backend Contract 0.108

← 7. Recoverable failure and traps · Contents · 9. Generated-code integrity →

8. System-service boundary

8.1 Stable services

CodeSource routineParameterSuccess result
0x00readInputByte()noneone u8
0x01writeOutputByte(value)u8none
0x02readStorageByte()noneone u8
0x03rewindStorageInput()nonenone
0x04writeStorageByte(value)u8none
0x05seekStorageOutput(offset)u16none

The codes identify the standard semantic service set in machine-readable tests and adapters. Generated programs call their entries in the RAM-resident runtime vector table. Each entry is one JP, and the runtime identity fixes the table's base, order, and offsets.

The target environment establishes the table before source execution. ROM startup copies it; a loaded image places it directly at its run address. Its initialized bytes come from the selected adapter runtime rather than from source declarations. The table also contains the terminal success, unhandled-failure, and trap entries required by Chapter 7 and the far-call and far-jump entries in Section 8.6. Runtime identity $0009 appends the packet gateway as ordinal 11; the preceding ordinals retain their identity $0008 positions. The complete twelve-entry vector is 36 bytes.

Every vector destination must remain callable under every bank selector. A banked target therefore binds these entries to fixed memory, always-visible RAM, or another adapter path whose behavior is independent of the currently selected bank.

Arithmetic and aggregate helpers remain ordinary local calls. They are not placed in the vector table.

8.1.1 Direct Z80 port access

readPort(port as u16) as u8 and writePort(port as u16, value as u8) compile to direct Z80 I/O instructions. They are infallible and have no runtime vector, service ID, recoverable status, provider binding, or writable runtime state.

The source port occupies the complete BC pair. IN A,(C) and OUT (C),A therefore place B on address lines A8 through A15 and C on A0 through A7. The backend emits these sequences after ordinary left-to-right argument evaluation:

OperationGenerated bytesEffect
retained readC1 ED 78 6F 26 00 E5pop BC, read, form HL = 00xx, push result
discarded readC1 ED 78pop BC and perform the read
writeE1 7D C1 ED 79pop value, pop BC, and write L

The retained read's zero high byte is part of the canonical u8 carrier contract. Port I/O is independent of the selected memory bank because the Z80 I/O address comes entirely from BC. A target that runs a Nucleus program must provide the hardware or emulated I/O behavior associated with those instructions.

8.1.2 Target-specific packet gateway

service(slot, packet) calls runtime-vector ordinal 11 with this provider ABI:

RegisterEntry value
Aexact source slot, zero through 255
HLaddress of the first packet byte
BCretained packet byte count

The provider may clobber AF, BC, DE, and HL. It preserves IX, IY, the hardware stack and return address, activation state, the selected bank, runtime vector and diagnostic state, and every byte outside the packet. It returns carry clear after valid dispatch. An unknown slot or invalid extent returns carry set with A = 0x07; the shared runtime gateway then enters the packet-service trap at the source statement before calling native code or changing the packet.

The runtime identity covers the slot contract as well as the vector position. A provider may bind slots to MON-3 RST gateways, CP/M BDOS, MSX BIOS, firmware, host callbacks, or another target-native mechanism. This is a bounded native call, not a recoverable standard service. Provider effects and packet mutations after valid dispatch begins are not transactional.

8.2 Stable service errors

CodeSource constantMeaning
0x01endOfInputNo input byte remains.
0x02inputFailureStandard input failed for another reason.
0x03outputFailureStandard output could not accept a byte.
0x04storageFailureA bulk-storage operation failed.

Every adapter returns a canonical byte code. It does not turn end of input into a trap or sentinel byte.

8.3 Stream behavior

Standard input begins at offset zero. A successful read returns the current byte and advances once; failure leaves the cursor unchanged. Standard output begins empty and appends successful bytes in call order; failure leaves it unchanged.

Bulk input begins at offset zero and can be rewound to zero. Bulk output begins with adapter-supplied bytes and a cursor at their end; the conformance harness supplies an empty output. A write overwrites below the end, appends at the end, and never inserts or truncates. A seek accepts an existing offset or the exact end. A seek beyond the end fails with storageFailure. Every failed service leaves its affected cursor and bytes unchanged.

8.4 Adapter freedom

A target may implement the services through CP/M, a monitor, ports, firmware, host callbacks, or tests. The binding must preserve bytes, call order, failure points, cursor state, and atomicity. No target address, port, file handle, or operating-system name enters Nucleus source semantics.

8.5 Runs and reset

Before each new run, the adapter restores every service input, output, and cursor to the initial state in Section 8.3. A new run therefore does not inherit bytes, cursors, else failures from an earlier run. The external execution interface identifies the reset execution as a distinct run.

Resuming or restarting generated code while retaining mutated service state is a debugger or target-specific continuation, not a new conforming run.

8.6 Banked calls

The source-part bank mapping lets the compiler classify each routine call as local or cross-bank. A local call uses ordinary CALL. A cross-bank call uses the far-call vector and supplies a compiler-generated destination bank ordinal and checked 16-bit target address through its private ABI. Source code exposes neither value.

The far-call adapter selects the destination bank, enters the ordinary Nucleus routine ABI, and installs a fixed-memory return path. Identity $0005 uses the selected-bank byte at writable-state offset eight and a sixteen-byte far-return arena after the saved root-frame words. Each live far call uses the zero-based slot ActivationDepth - 1: depth one selects slot zero, and the published depth-eight boundary selects the final slot. The slot retains both the return address and caller bank in always-visible state; neither value is inserted among hardware-stack arguments. The callee returns with an ordinary RET; the return path restores the caller's bank. The far-jump vector provides the corresponding non-returning transfer.

On TECM8 the adapter may implement these entries through the monitor's Tecm8FarCall and RST 10h facilities. Generated code never writes SYS_CTRL directly. Parameters, results, activation state, runtime vectors, and service state occupy always-visible RAM. Cross-bank aggregate traffic remains subject to Section 6.5.