Skip to content

TEC-OS103

Appendix C. Memory map ​

A memory address needs both a bank and a build identity. This reference pairs the map of one build with the source contracts for each region. Chapter 11 explains the program's memory limits. Chapter 15 explains resident state and its lifetime.

The address tables describe the tecos build at TEC-OS c4ec0f4, whose ROM SHA-256 is a65b6e4523b5f7bab612810370ec13d4c0056deeab574acda80ef9a8e5d358d1. It is the one image for every board. The starter card reserves four equal drive slots and mounts SYSTEM on A, WORK on B and PROJECTS on C. Its startup file installs the shell; table rows that describe the bare allocation layout explicitly exclude services. The resident workspace addresses come from build/tecos/tecos.d8.json. Other builds need their own symbol files for build-dependent addresses.

The CPU's address space ​

The 64 KiB CPU address space contains fixed RAM, a bank window and ROM (src/layout.asm:1-7):

AddressesContents
0000h–7FFFhFixed RAM
8000h–BFFFhEXPAND 0, replaced by EXPAND 1 while latch bit 2 is set
C000h–FFFFhROM

At reset the first 2 KiB of ROM also appear at 0000h–07FFh. The overlaid jump enters RSTENT in ROM. Cold boot then sets latch bit 0 to remove the overlay (src/reset.asm:1-13, src/boot.asm:22-40). The starter card's layout with EXPAND 0 selected and no service loaded is:

AddressesContents
0000h–00FFhPage zero
0100h–B6E8hTransient program area (TPA), 46,569 bytes
B6E9h–BFFFhBDOS entry jump and resident workspace in EXPAND 0
C000h–FFFFhROM

TEC-OS writes the system latch at port FFh from its shadow at 0040h, LATCHV. The ordinary EXPAND 0 value is 01h. With matrix Caps Lock on bit 7 is set, producing 81h. Temporary EXPAND 1 accesses set bit 2 and restore the shadow value afterwards (src/layout.asm:19-28, src/abi.inc:302-305, src/layout.asm:64-69, src/abi.inc:307-309, src/keyboard.asm:130-137, src/cache.asm:21-41). Warm boot writes 01h before selecting its resident stack (src/boot.asm:131-136).

The word at 0006h is the exclusive top of the TPA. Without a resident service it points to a three-byte BDOS entry stub below the allocation vectors. ALVINIT packs those vectors down from WSBASE and reserves the jump below the lowest vector (src/boot.asm:536-634). A format 1.1 card with a nonzero drive count reserves 256 bytes for each requested drive. Otherwise each mounted drive receives (DSM >> 3) + 1 bytes. A service lowers 0006h to its first page during installation. PZTOP is updated when its pages are committed (src/loader.asm:337-350, src/loader.asm:499-504).

These figures depend on the card and the services loaded:

CardVectorsWord at 0006hTPA
Starter card, four reserved drive slots1,024 bytesB6E9h46,569 bytes
Starter card with GLCD.SVC installed1,024 bytesB300h45,568 bytes
Starter card after STARTUP.CMD installs SHELL.SVC1,024 bytesA700h42,496 bytes
Starter card with SHELL.SVC and GLCD.SVC1,024 bytesA400h41,728 bytes
Two-volume reference, no drives field, no service320 bytesB9A9h47,273 bytes

The shell takes fifteen pages, and its last page holds its 256-byte history ring (docs/memory-map.md:8-22, docs/compatibility.md:3-16, docs/shell.md:22-30).

The ROM ​

The ROM occupies these ranges:

AddressesBytesContents
C000h–C002h3Reset jump, JP RSTENT
C003h–C00Ah8ROM table
C00Bh–C5D0h1,478Read-only data from ROMDATA up to ROMCODE, including FONT at C193h–C492h
C5D1h–FA1Ah13,386Code
FA1Bh–FFFFh1,509Unused

That is 14,875 of the 16,384 bytes (docs/memory-map.md:22-30).

The CCP's four files occupy DBB3h–E3BDh, 2,059 bytes, from CCPBAS. The BDOS's six files follow at BDOSBAS, E3BEh–F198h, 3,547 bytes (src/rom.asm:31-40).

The ROM copy of the BIOS jump table is data at BIOSBAS. Cold boot copies its 17 jumps to BF00h. Calls use the RAM table, whose entries can be replaced by resident hooks. Warm boot leaves that table intact (src/tables.asm:9-31, src/layout.asm:98-99, src/boot.asm:108-111).

Page zero ​

These fixed addresses identify the current page-zero contracts (src/layout.asm:44-69, src/abi.inc:307-309, src/console.asm:54-65):

AddressContents
0000hJP BF03h, warm boot through the RAM BIOS table
0003hIOBYTE. TEC-OS applies its console field in bits 0 and 1
0004hCurrent drive in bits 0–3 and user number in bits 4–7
0005hJP through the word at 0006h, to the BDOS entry jump or lowest service page
0008h–0037hRestart vectors 1–6. Each defaults to seven zeros followed by RET, unless a JP target is strictly above PZTOP
0038hRestart 7 and mode 1 interrupt entry. Defaults to EI, RETI unless a qualifying JP remains
0040hLATCHV, the system latch shadow
0041h–004FhUnused by TEC-OS. A MON3.SVC session holds them while it runs and gives them back at EXIT or warm boot
0050hLoad-drive byte. 0 means current drive, 1 means A and so on
005ChFirst default file control block (FCB)
006ChSecond FCB, overlapping the first FCB's last 20 bytes
0080h–00FFhCommand tail and default DMA buffer

Cold boot clears page zero. PZINIT writes the entry jumps and stub at cold boot's end and on each warm boot. It leaves 0003h and 0004h unchanged (src/boot.asm:52-59, src/boot.asm:114-144, src/boot.asm:300-315). The restart sweep preserves the three bytes of a qualifying jump and clears its remaining five bytes. A target equal to PZTOP does not qualify. The default EI, RETI sequence at 0038h is written only when no qualifying jump remains there (src/boot.asm:332-382).

Service-page release clears the first byte of each claimed restart slot before the sweep. Successful unload and failure cleanup that releases the pages both use this rule. A failed INIT can retain its pages when a BIOS hook still targets them so failure alone does not imply slot release (src/loader.asm:97-126, src/loader.asm:436-475, src/loader.asm:520-540).

The CCP records the drive/user byte for its command prompt. Before program launch it writes both FCBs, then the command tail and default DMA address, then the load-drive byte (src/cpm/ccp.asm:306-324, src/cpm/ccpcmd.asm:392-440, src/cpm/ccp.asm:454-471). The second FCB reaches 008Fh so tail publication follows FCB parsing.

CP/M reserves 0040h–004Fh for BIOS scratch. TEC-OS uses only 0040h there. It is the resident state byte read while EXPAND 1 hides the upper workspace. Cold boot leaves the other 15 bytes zero. A MON3.SVC session holds them while it runs: the latch stub its restarts pass through, GO's return and a RETN. It gives them back at EXIT or warm boot. Console state is above the RAM BIOS table (src/layout.asm:64-69, src/abi.inc:307-309, src/ram.asm:411-428, docs/memory-map.md:32-39).

The resident workspace ​

The following tables give every address and size on the starter card. A row's clearing column names the boot sweeps that reach it. Other routines can still overwrite a retained field.

AddressesBytesContents
B6E9h–B6EBh3BDOS entry jump, JP BENTRY
B6ECh–BAEBh1,024Four 256-byte allocation-vector slots
BAECh–BCC9h478BIOS disk state/buffers, PICO console block, mount scratch and terminal state
BCCAh–BCF1h40BIOS stack
BCF2h–BE76h389CCP state and stack
BE77h–BEFFh137BDOS state and stack
BF00h–BF32h51RAM BIOS table, 17 jumps
BF33h–BFFFh205SD, cache, keyboard, display, loader, startup, chain and console state plus remaining mount scratch

The build places WSBASE so that the lower workspace ends immediately before BF00h. Its upper span starts after the 51-byte RAM BIOS table at BF33h (tools/build.mjs:218-248, src/ram.asm:295-297). These spans have fixed addresses across cards. The allocation vectors below WSBASE, at BAECh, vary with the card.

Cold boot clears the workspace from WSBASE up to but excluding WSEND. Warm boot clears CCPCLR up to but excluding BDOSRME, then sets the DMA address, command-buffer maximum and stack guard. It separately clears BUFOK (src/boot.asm:61-66, src/boot.asm:398-418). Those sweeps are BAECh–BFFFh and BDBCh–BEFFh respectively. Warm boot also writes retained fields outside its clearing span, including LATCHV and SVCBSY (src/boot.asm:131-144).

The BIOS's block ​

The declarations are at src/ram.asm:15-136.

AddressesBytesNameContentsCleared by
BAECh1DSKCURSelected BIOS driveCold boot
BAEDh–BAF2h6DSKTRK, DSKSEC, DSKDMALast track, sector and DMA address set through the BIOSCold boot
BAF3h–BAF5h3BLKOFF, BLKSLOTBlock within the volume and 128-byte record within that blockCold boot
BAF6h–BAF9h4BUFOK, BUFDRV, BUFBLKValidity flag, drive and block of the write-cleared keyCold boot. Warm boot also clears BUFOK
BAFAh–BB19h32DRVTABFour drive entries, 8 bytes eachCold boot
BB1Ah–BB1Dh4DRVIDXVolume index + 1 for each drive, 0 for noneCold boot
BB1Eh–BB21h4DRVSLOTVector slot per drive, 0 for none, 1 for 64 bytes or 2 for 256Cold boot
BB22h–BB61h64DPHTABFour 16-byte DPHsCold boot
BB62h–BB63h2LOGINVBDOS logged-in drive vectorCold boot
BB64h–BBE3h128DIRBUFShared directory bufferCold boot
BBE4h–BBE5h2CSVDUMUnused check-vector placeholderCold boot
BBE6h–BBE7h2STUBADBDOS entry jump addressCold boot
BBE8h–BC46h95PIBLK to PIROWTPICO console table, width, registry record, pages, registers and row addressesCold boot
BC47h1MNTCNTMount/volume-service scratch countCold boot
BC48h–BC67h32MNBUFContainer header or descriptor copied from a cache lineCold boot
BC68h–BCB7h80LINEBUFDisplay-row scratch for terminal moves and LCD drive rowsCold boot
BCB8h–BCC5h14VPUTV to VFNVSeven display-table vectorsCold boot
BCC6h–BCC9h4VSTOP to CONMODScroll-region limits, PICO claim and applied console modeCold boot
BCCAh–BCF1h40BSTKBBIOS stack up to exclusive top BSTKCold boot

The write-cleared key identifies a block cleared for a new allocation rather than read from the card. Clearing BUFOK prevents reuse of the old key. A new type-2 write can still clear its block without a pre-read (src/bios.asm:298-358).

The CCP's block ​

The declarations are at src/ram.asm:141-202. CCPCLR is BDBCh. The FCBs and command buffer below it survive the warm clearing sweep for another chained piece.

AddressesBytesNameContentsCleared by
BCF2h–BD15h36CMDFCBCommand FCBCold boot
BD16h–BD39h36RENFCBSecond FCB for REN and COPYCold boot
BD3Ah1CMDBUFFunction 10 maximum, 127Cold boot. Warm boot writes 127
BD3Bh1CMDLENCommand-line lengthCold boot
BD3Ch–BDBBh128CMDTXTRetained command lineCold boot
BDBCh1BOOTDRVDrive selected for CCP entryCold and warm boot
BDBDh–BDCBh15CMDSTRT to ERAALLParser pointers and DIR, SAVE and ERA stateCold and warm boot
BDCCh–BE4Bh128LOADBUFCCP scratch recordCold and warm boot
BE4Ch–BE56h11STKGUARDCCP stack guard, A5h in each byteCold and warm boot. Warm boot then writes A5h
BE57h–BE76h32CSTKBASCCP stack up to exclusive top CSTKTOPCold and warm boot

Retention of the line does not guarantee that it runs. Without the shell the CCP runs a function 47 line whole. A failed warm-boot flush cancels the line, writing 2 to CHPOS after dropping failed cache lines (src/cache.asm:266-300, src/cache.asm:624-640). Chapter 22 explains the other cancellation paths.

The BDOS's block ​

The declarations are at src/ram.asm:209-288. Warm boot clears this whole block before setting the DMA address to 0080h.

AddressesBytesNameContentsCleared by
BE77h–BE7Bh5OLDSP, ERRMODE, PARAMCaller SP, function 45 error mode and caller DECold and warm boot
BE7Ch–BE7Fh4COLUMN, LISTEN, PENDING, PENDCHRConsole column, ^P list-copy flag and pending-character flag/byteCold and warm boot
BE80h–BE84h5LINPTR to HFLAGLine-input pointer and counts, and HFLAG, set for the shell's history lineCold and warm boot
BE85h–BE8Ah6CURDRV to DEFALVBound/default drive and default DPB/vector pointersCold and warm boot
BE8Bh1USERNOUser numberCold and warm boot
BE8Ch1WRFLAGCCP-set flag for its disk resetCold and warm boot
BE8Dh–BE8Eh2WARMVDrives whose allocation vectors need rebuilding to their markCold and warm boot
BE8Fh–BE90h2ROVECRead-only drive vectorCold and warm boot
BE91h–BE92h2CURDMADMA addressCold and warm boot. Warm boot then writes 0080h
BE93h–BE9Ch10DPHPTR to XLTPTRBound DPH, DPB, directory buffer, allocation vector and translation-table pointersCold and warm boot
BE9Dh–BEC9h45CURTRK to DIRSECDirectory search, allocation scan and file-position stateCold and warm boot
BECAh–BEFFh54STKBASEBDOS stack up to exclusive top STKTOPCold and warm boot

Above the RAM BIOS table ​

The declarations are at src/ram.asm:295-458. These addresses lie above the warm clearing span. Cold-only clearing therefore describes storage lifetime, not an assurance that its value remains unchanged. The history and the rest of the startup file are the shell's, so no field here holds them. CPEND holds the pending block on a drive not logged, for the coalescing in Chapter 19 (src/ram.asm:303-319, src/ram.asm:399-404, docs/memory-map.md:60-69).

AddressesBytesNameContentsCleared by
BF33h–BF3Dh11SDBYTE to SDXBSD addressing flag, big-endian argument, little-endian block address, last error and cache-transfer bank selectorCold boot
BF3Eh–BF40h3CNEXT to CIFFReplacement index, BIOS write type and saved interrupt flagsCold boot
BF41h1CANYNonzero when a data line may be held behind on the logged driveCold boot
BF42h1CPENDThe coalesced pending block: its cache line plus one, 0 for noneCold boot
BF43h–BF49h7KBMASK to KBT2Matrix scan and pending arrow-sequence stateCold boot
BF4Ah–BF4Dh4PIVEC, GLVECConsole-table pointers, PIBLK for PICO or 0 when absent, and GLCD's tableCold boot
BF4Eh–BF51h4XMDST to MVRESTMVCOPY source/destination banks and remaining byte countCold boot
BF52h–BF53h2PZTOPCommitted top restored to 0006h by warm bootCold boot
BF54h–BF55h2PRGCODEFunction 108 program return codeCold boot
BF56h–BF5Ah5LOADTOP to SLDLExclusive loaded-record end, last service-loader record and relocation deltaCold boot
BF5Bh–BF63h9SVCBSY to SVCRALoader busy flag, registry head, lowest service page, generation, the shell's table SHOWN, failure code and INIT's ACold boot
BF64h1STFLAGFFh during a startup line, 0 during a typed lineCold boot
BF65h1STPOSStartup state: 0 untried, 1 a record waits, 80h doneCold boot
BF66h1CHPOSBit 0 a function 47 line in CMDTXT, bit 1 the rest of the line droppedCold boot
BF67h–BFE4h126HIFREEUnusedCold boot
BFE5h1RXFULLNonzero while a console byte is pending in RXCHARCold boot
BFE6h1RXCHARPending console byteCold boot
BFE7h1CONDEVDevice/switch status and LCD recovery-word ownership bitsCold boot
BFE8h1VROWTerminal cursor rowCold boot
BFE9h1VCOLTerminal cursor columnCold boot
BFEAh1VWIDVideo-console columns, 0 for serialCold boot
BFEBh1VHGTVideo-console rowsCold boot
BFECh1ESCSTEscape-parser stateCold boot
BFEDh1ESCP1First numeric escape parameterCold boot
BFEEh1ESCP2Second numeric escape parameterCold boot
BFEFh1KBLASTLast held matrix key, FFh for none. abi.inc publishes it for a service that scans the matrix, and the workspace label is KBSLOT (src/abi.inc:311-318)Cold boot
BFF0h1VATTR80h for reverse videoCold boot
BFF1h1VCURV1 while the cursor cell is drawn reversedCold boot
BFF2h–BFFFh14MNTBLK to MNTLNRemaining mount/volume-service scratchCold boot

CIFF occupies one byte; CANY uses the byte after it. The CCP sets HFLAG to FFh while the shell's LINE entry reads one line, so that line's function 10 call can use the history. SHOWN holds the address of the shell's entry table, 0 with no shell. CONDEV combines switch, probe and ownership state so its bits do not all prove device presence (src/ram.asm:229, src/ram.asm:382, src/ram.asm:315-323, src/cpm/ccp.asm:251-280, src/layout.asm:70-75, src/cpm/ccp.asm:156-158). SVCRA identifies a cause only when SVCRC is 1. Record-validation failure after successful INIT sets it to 0 (src/loader.asm:426-444). Chapter 25 explains those load outcomes.

EXPAND 1 ​

These fixed bank addresses hold the cache (src/layout.asm:32-42, docs/memory-map.md:70-83):

AddressesBytesContents
8000h–BBFFh15,36030 cache lines of 512 bytes
BC00h–BC77h120CTAB, four-byte card-block key per line, FFFFFFFFh when empty
BC78h–BC7Fh8Unused
BC80h–BC9Dh30CDIRTY, one dirty byte per line
BC9Eh–BCFFh98Unused
BD00h–BFFFh768Unused. The host model watches it so that a stray write fails

The command history is in the shell's own pages, not in this bank (docs/shell.md:22-30).

Cold boot clears the whole bank and then marks every cache key empty (src/boot.asm:235-252). No BDOS or BIOS interface allocates a program range there. Direct latch access can expose the bank but the resident EXPAND 0 stacks disappear while it is selected. Cache routines exclude maskable interrupts and restore the latch before any stack operation (src/bios.asm:379-446, src/sd.asm:469-574, src/sd.asm:586-655).

A jump to 0000h with EXPAND 1 still selected reaches BF03h in that bank. With its normally cleared unused bytes, execution continues through zeros into the ROM at C000h. RSTENT distinguishes that entry from reset and warm boot selects EXPAND 0 before setting its stack. Modified bank contents can break that route. A program using the inherited stack also loses access to its return word while EXPAND 1 is visible (src/boot.asm:22-40, src/boot.asm:131-136, src/boot.asm:300-305, src/cpm/ccp.asm:464-471). Chapter 16 explains the exit paths and their limits.

The stacks ​

The stack reservations are defined by BOOTSTK, BIOSSTN, CCPSTN and BDOSSTN (src/layout.asm:94, src/layout.asm:113-115).

StackAddressesBytesUse
BootBelow 8000hCold boot until workspace clearing finishes
BIOSBCCAh–BCF1h40Warm boot
CCPBE57h–BE76h32CCP and a program's inherited stack, with 0000h pushed at launch
BDOSBECAh–BEFFh54BDOS functions and their BIOS calls, plus cold boot after workspace clearing

Cold boot switches from BOOTSTK to STKTOP after clearing the workspace. Console initialisation, banner, mount, drive listing and the diagnostic prompt use that BDOS stack before the CCP starts. Diagnostic retries set STKTOP again (src/boot.asm:35-68, src/boot.asm:79-113). A BDOS call saves caller SP in OLDSP, sets SP to STKTOP and restores caller SP on return (src/cpm/bdos.asm:124-129, src/cpm/bdos.asm:210-214).

Services run on their caller's stack. SVCLIM limits the combined additional use to 8 bytes on BDOS, 12 on BIOS and 6 on CCP (src/tables.asm:139-144, src/loader.asm:225-254). The host-model census measures bases of 30, 18 and 18 bytes respectively. Adding the declared limits gives 38/54, 30/40 and 24/32 bytes. The BDOS's census, its deepest use of all, is 32 bytes (docs/services.md:308-330). The shell runs its LINE and PAGE entries on its own 32-byte stack and declares 6 bytes of the BDOS's stack (docs/services.md:332-339). Chapter 15 explains their scope and Chapter 25 explains declaration checks.

Reproducing the figures ​

npm run media writes the summary into docs/memory-map.md from build/tecos/census.json and the build's symbol file (tools/media.mjs:66-98, tools/media.mjs:181-198, tools/media.mjs:291). Chapter 27 describes ROM/media construction. The lookup below reads build/tecos/tecos.d8.json after npm run build:

sh
node -e '
const s = JSON.parse(require("fs").readFileSync("build/tecos/tecos.d8.json", "utf8")).symbols;
for (const n of process.argv.slice(1)) {
  const x = s.find((y) => y.name === n);
  console.log(n, (x.address ?? x.value).toString(16).toUpperCase() + "h");
}' CMDTXT PRGCODE CHPOS

It prints:

text
CMDTXT BD3Ch
PRGCODE BF54h
CHPOS BF66h

A source change can move build-dependent addresses. Page zero, the cache addresses, RAM BIOS origin BF00h and ROM table origin C003h are fixed by the inspected contract (src/layout.asm:30-69, src/abi.inc:307-309, src/layout.asm:98-99, tools/build.mjs:237-248). A symbol lookup is valid for the artifact it reads so a later map needs that build's symbols and identity.

TEC-OS and Thorium documentation