TRS-80 DOS - PerCom MicroDOS Version 2.20 for the Model I - Resident OS Disassembled
Page Customization
Page Index
Resident OS Image (4400H-55FFH)
Other Navigation
Introduction/Summary:
PerCom MicroDOS 2.20 Resident OS Disassembly (Model I)
The PerCom MicroDOS resident operating system is the 4,608-byte image that the boot sector loads from the chain T0/S1 -> T0/S9 -> T1/S0 -> T1/S9 into RAM starting at 4400H. After the final sector is read, the boot sector at 42BAH executes a JP NZ,4400H, and the three bytes at 4400H (C3 27 47 = JP 4727H) hand control to the resident's initialization routine.
MicroDOS sits between Level II BASIC and the user. It does not replace BASIC; it intercepts BASIC. The initialization routine at 4727H performs five jobs in sequence: (1) it copies 39 bytes of the BASIC ROM error-message table from 18F7H to 4080H (creating an editable copy that MicroDOS can extend with its own error messages); (2) it sets up a comma-separator parsing template at 41E5H; (3) it copies the 147-byte JP-table at 4694H down to 4152H, where the empty entries land on top of the Level II BASIC RST 28H hook addresses (400CH, 4015H) and convert them into MicroDOS DOS-call entries; (4) it initializes the string-storage and byte-storage pointers at 5A00H and 5A64H respectively; and (5) it relocates the stack to 41F8H, prints the PerCom MicroDOS banner via the Level II BASIC ROM 28A7H string-output routine, hooks the keyboard input vector at 4016H to 478FH, and finally jumps to 00B5H to enter Level II BASIC.
From that point on, every keypress comes through 4016H to MicroDOS' keyboard-driver hook at 478FH, which feeds either a stored AUTO-LOAD command sequence (initially "LOAD 30,R" from 44A5H) or a normal keyboard scan into BASIC. Every disk-related BASIC keyword (CMD, CALL, GET, PUT, GETVAL, AND, etc.) is dispatched through the relocated jump table at 4152H, which arranges the entries so that BASIC's reserved-word table indices land on either MicroDOS's own handlers (CMD, F, I, H, K, M, etc.) or on the original Level II BASIC handlers via JP 0043H (a stub that returns "FC Error" for unsupported keywords).
The disk I/O subsystem at 4BCDH (read sector) and 4C44H (verify sector) drives the WD1771 FDC at 37ECH-37EFH using the same alternate-register trick as the boot sector: BC' holds 4300H (the sector buffer), DE' holds 37ECH (FDC command/status), and HL' holds 37EFH (FDC data). The FDC routines re-execute EXX whenever they need to access the FDC, and again to switch back. The sector address is held in 448DH-448EH (a 16-bit logical sector number), and the drive is selected from a one-hot mask at 448CH (01H, 02H, 04H, or 08H).
The custom error message table starting at 52F1H extends the Level II BASIC error list with twelve MicroDOS-specific errors: BAD FILE DATA, FEATURE NOT IMPLEMENTED, INVALID DRIVE NUMBER, INVALID SECTOR NUMBER, DISK READ/WRITE ERROR, DISK WRITE PROTECTED, DISK OVERFLOW, DISK MISSING OR DOOR OPEN, FIELD OVERFLOW, FUNCTION DEFINITION ERROR, INVALID FIELD BUFFER NUMBER, DISK DRIVE NOT AVAILABLE, DISK SEEK ERROR, and CAN'T FORMAT DISK. These messages are reached via JP 19A2H with the error code in Register E.
The 4,608-byte image is laid out as four functional regions. The first region (4400H-4593H) is mostly data: the JP entry at 4400H, the MICRODOS startup banner at 4401H, an internal symbol table at 4459H listing five Level II BASIC variable addresses (CRLNUM, PRGEND, ARREND, ACCUM, and a fifth at 4506H), the AUTO-LOAD command string at 44A5H, three small data tables at 4490H-44A4H used by the FCB system, and the PerCom copyright banner at 4527H. The second region (4594H-4670H) is an embedded copy of the boot sector code, present so that a SYSTEM call or external reload can invoke the loader without re-reading T0/S0. The third region (4671H-46FFH) contains the boot-sector-style data block (TRACK, SECTOR, DISK ERROR, NO MICRODOS, $STEPL) followed by the 147-byte dispatch table that gets relocated to 4152H. The fourth region (4727H-55FFH) is the actual MicroDOS code: the entry routine, the keyboard hook, the BASIC token interceptor, the file directory walker, the disk I/O subsystem, the FCB management routines, and the BASIC error message table extension.
From the user's perspective, MicroDOS appears as an extended BASIC. After the banner prints, the system displays the standard "MEMORY SIZE?" prompt (because 00B5H is the Level II BASIC cold-start entry that ran after MEMORY SIZE prompts), then the BASIC READY prompt. Typing a BASIC command works as it did under cassette Level II BASIC. Typing CMD"D" or CALL DIR (or whichever keyword Stutsman implemented for directory listing) routes through the dispatch table at 4152H and produces a MicroDOS-specific behavior. Disk file operations use MicroDOS's own FCB at 448CH-449FH and its own sector-chain file format (the same chained-sector mechanism used by the boot sector to load the OS itself).
Memory Map
The resident occupies the entire RAM region 4400H-55FFH. After initialization, MicroDOS additionally uses 4080H-40A6H (relocated BASIC error table), 4152H-41E4H (relocated DOS supervisor / dispatch jump table), 41E5H-41E7H (comma-separator template), 41F8H (stack), 5A00H+ (string storage), and 5A64H+ (byte storage).
| Address Range | Label | Contents |
|---|---|---|
| 4400H-4402H(3 bytes) | ENTRY | JP 4727H. The first three bytes of the resident image, executed by the boot sector's final JP NZ,4400H. Hands control to the initialization routine. |
| 4403H-4458H(86 bytes) | BANNER1 | The startup banner string, decoded as bytes: "MICRODOSA SIMPLE, POWERFUL DOS\rWRITTEN BY JAMES W. STUTSMAN\rFOR PERCOM DATA COMPANY\r\r\0". The leading byte at 4403H is M (4DH), used by the FCB system as a default signature byte. The string is never displayed; it is a build-time signature embedded by Stutsman to identify the OS image. |
| 4459H-4505H(173 bytes) | SYMTAB | Built-in symbol table holding five label/address pairs in source-listing format: "CRLNUM EQU 40ECH ;CURRENT LINE NUMBER", "&PRGEND EQU 40FBH ;END OF SIMPLE VARIABLES", "ARREND EQU 40FDH ;END OF ARRAYS", "ACCUM EQU 4121H ;NUMBER ACCUMULATOR", and a fifth entry "NUMBER ACCUMULATOR" at 4506H. Used by the SYM/CALL command (4E55H dispatch entry) to convert symbolic names to addresses. |
| 4488H-448BH(4 bytes) | FCBHDR | FCB header bytes 01 00 01 FF. Marks an unallocated FCB slot. |
| 448CH(1 byte) | DRVSEL | Drive select mask (one-hot). 01H=Drive 0, 02H=Drive 1, 04H=Drive 2, 08H=Drive 3. Written to 37E1H (drive select latch) by the FDC routines. Initialized to 01H (Drive 0) by 4780H. |
| 448DH-448EH(2 bytes) | SECTOR | Current logical sector number (16-bit). Hi byte at 448DH = track number, lo byte at 448EH = sector number within track. Used by the FDC routines at 4D44H to seek the head and select the sector. |
| 448FH(1 byte) | BUFOFF | Buffer offset / chain-marker storage. Holds the chain-marker byte read from the first byte of each sector during a sector-chain walk. FFH means continuation, any other value N means end-of-chain with N data bytes. |
| 4490H-4491H(2 bytes) | BUFPTR | Pointer into the 256-byte sector buffer at 4300H. Points to the next byte to read from the chain. Initialized to 4301H (skipping the chain-marker byte at offset 0) by 4929H. |
| 4492H-4493H(2 bytes) | RECNO | Record number / record byte count. Used by the file allocation and disk-space-checking routines at 4B20H and 4CA1H. |
| 4494H(1 byte) | FDCFLG | FDC flags / step-rate. Bits 0-1 hold the WD1771 stepping rate (00=3ms, 01=6ms, 10=10ms, 11=15ms). Bit 7 may be a write-protect flag. |
| 4495H(1 byte) | FDCSTAT | Saved FDC status from the last command. Written by 48F7H (Type I error save) and 4BEEH (Type II error save). Read by 490FH to test for write-protect on disk command failure. |
| 4496H(1 byte) | FDCCKSUM | Running checksum / accumulator used by FORMAT operations to verify a track's data after writing. |
| 4497H-449AH(4 bytes) | STEPRATE | Step-rate selection table. Four bytes selecting the FDC step-rate command for each of the four drives. |
| 449BH-44A4H(10 bytes) | FORMTBL | Format-track parameter table. 10 bytes used by the FORMAT routine at 4CA1H to lay down sector ID fields. |
| 44A5H-44ADH(9 bytes) | AUTOCMD | The default AUTO-LOAD command string "LOAD 30,R" terminated by a 0DH carriage return. The keyboard input hook at 478FH feeds this string to BASIC one byte at a time on first boot, causing MicroDOS to automatically execute LOAD 30,R after the BASIC READY prompt appears. Once exhausted, the hook switches to live keyboard input. |
| 44AEH-4525H(120 bytes) | SYMTAB2 | More entries in the built-in symbol table: "EQU 40FBH ;END OF SIMPLE VARIABLES", "ARREND EQU 40FDH ;END OF ARRAYS", "ACCUM EQU 4121H ;NUMBER ACCUMULATOR", with NEG-encoded source-listing characters interspersed. |
| 4527H-457FH(89 bytes) | BANNER2 | The PerCom MicroDOS user banner: "[D]PERCOM MICRODOS VERSION 2.20\rCOPYRIGHT (C) 1979 PERCOM DATA COMPANY\rALL RIGHTS RESERVED\r\0". The leading 'D' at 4527H is a stray byte used by the symbol-table tail; the actual displayed string starts at 4528H. Output by 4761H-4766H via Level II BASIC ROM 28A7H. |
| 4581H-4593H(19 bytes) | LSUMSG | The string "LAST SECTOR USED =" terminated by 00H. Used by the format/disk-space routines to display the last allocated sector number. |
| 4594H-4670H(221 bytes) | BOOTCOPY | An exact copy of the boot sector code from 4200H-42DCH, embedded in the resident image. Provides a re-entry point for SYSTEM calls or external relocators to re-load the OS without reading T0/S0. The code is identical to the boot sector but executes from 4594H instead of 4200H, so the internal references (e.g., LD HL,42F1H at 45A9H) still point at the original boot sector data area at 42xxH; this means BOOTCOPY only works correctly if the original boot sector is still resident at 4200H, which is the normal case. |
| 4671H(1 byte) | PADBYTE | One pad byte (00H) separating the boot copy from the data block. |
| 4672H-4674H(3 bytes) | DEFM_HEAD | The bytes 01 17 E8, encoding LD BC,0E817H but used as the lead-in for the DISK ERROR string (17H E8H = HOME and a graphics marker). Same as the boot sector's 42DDH-42DFH region. |
| 4675H-467FH(11 bytes) | DISKERR2 | The string "DISK ERROR" terminated by 00H. A second copy of the boot sector's DISK ERROR string. Used by the embedded boot copy at 4636H (which jumps to 4671H, not 42DEH). |
| 4680H-468DH(14 bytes) | NOMDOS2 | The string "NO MICRODOS" preceded by 17H E8H and terminated by 00H. Same content as the boot sector's NO MICRODOS message. |
| 468EH-4693H(6 bytes) | STEPL | The six bytes "$STEPL" - a residual symbol-table label from the source listing, never read at runtime. Companion to the boot sector's "$STEPH". |
| 4694H-4726H(147 bytes) | JTABLE | The 49-entry JP-table relocated to 4152H by the init routine at 4741H-474BH. Each entry is 3 bytes (C3 lo hi). After relocation, the table at 4152H provides the BASIC token dispatch for MicroDOS keywords. Many entries are JP 0043H (the Level II BASIC ROM VDPRT video output trampoline at 0043H, used as a filler for unsupported keywords) and JP 012DH (the Level II BASIC ROM NAVERR routine that displays L3 error 2CH). |
| 4727H-478CH(102 bytes) | INIT | The MicroDOS initialization routine. Sets up RAM, hooks the keyboard, prints the banner, and JPs to BASIC. |
| 478FH-47A2H(20 bytes) | KBDHOOK | Keyboard input hook. While the auto-command string at 44A5H still has bytes left, returns one byte at a time from the AUTOCMD pointer. When exhausted, re-points the keyboard hook to 47A3H (live keyboard scanner) and falls through. |
| 47A3H-47C8H(38 bytes) | KBDSCAN | Live keyboard scanner. Walks the keyboard memory at 3801H, 3802H, 3804H, 3808H, 3810H, 3820H, 3840H, 3880H, computes the row offset, and falls through to the Level II BASIC ROM key-decode routine at 03FBH. |
| 47C9H-485FH(151 bytes) | BASTOK | BASIC token dispatcher. Interprets the byte after a CMD/CALL token as a single-letter command (F, I, H, K, M, etc.) and dispatches to the appropriate MicroDOS routine. Implements F (FETCH), I (INPUT), H (HEX), K (KILL), and M (MERGE) - the AUTO-LOAD-related operations. |
| 4870H-4905H(150 bytes) | FILEIO | Sector-chain file load routine. Walks the chained-sector format used by MicroDOS files: each sector starts with a length-or-continuation byte (FFH = continue, else N = final with N data bytes), and the file ends when a non-FFH marker is found. |
| 491BH-499DH(131 bytes) | RAMOPS | RAM management: copy regions, allocate file space, walk through memory looking for free zones. |
| 49AEH-4A47H(154 bytes) | FCBOPS | FCB allocation, file directory walk, and CMD-line parsing for OPEN/CREATE/READ. |
| 4A4AH-4ABFH(118 bytes) | DIRWALK | File directory walker. Reads the chained directory record format and decodes filenames. |
| 4AAEH-4AFAH(77 bytes) | OPENRD | Open file for read - locates the file in the directory and prepares the FCB. |
| 4AFBH-4B58H(94 bytes) | NUMPARSE | Numeric argument parser. Handles drive-number and record-number arguments to disk commands. |
| 4B59H-4BCCH(116 bytes) | FILESPEC | Filespec parser. Accepts either a quoted string ("FILENAME") or a BASIC string variable, and resolves it to a buffer pointer. |
| 4BCDH-4C90H(196 bytes) | SECREAD | FDC sector read routine. Issues WD1771 Read Sector (88H), polls for DRQ, and transfers bytes into the buffer. |
| 4C91H-4D43H(179 bytes) | FORMAT | Disk format routine. Lays down sector IDs and writes data fields for an entire track. |
| 4D44H-4DE2H(159 bytes) | FDCSEEK | FDC seek and drive-select routine. Selects the drive, sets the step-rate, seeks the head to the target track, sets the sector register, and prepares for a read or write command. |
| 4DE3H-4E18H(54 bytes) | FDCCMD | FDC command issue routine. Same general structure as the boot sector's 42B9H, but with hooks for write commands and error reporting. |
| 4E19H-4E5DH(69 bytes) | ERREXIT | Error exit jump table. 16 single-byte error codes loaded into Register E and JPed to 19A2H (the Level II BASIC ROM error handler) to display the corresponding MicroDOS error message from the table at 52F1H. |
| 4E66H-4F11H(172 bytes) | STRMOV | String move and assignment. Used by LET-style statements involving disk strings. |
| 4F12H-4FB6H(165 bytes) | BASIC | BASIC keyword handlers: WRITE, READ, FIELD, CLOSE - the disk-file-related BASIC statements. |
| 4FB7H-505FH(169 bytes) | NUMIO | Numeric I/O: convert numbers to/from disk files, handle field formats. |
| 5060H-52F0H(657 bytes) | UTILS | Utility routines: string compare, copy, length, hex digit decode, and miscellaneous BASIC support. |
| 52F1H-5577H(647 bytes) | ERRMSG | BASIC error message table. Re-implements the Level II BASIC ROM messages at 18C9H and adds 13 MicroDOS-specific messages. Each message is a NUL-terminated ASCII string, located by index from Register E via JP 19A2H. |
| 5578H-558DH(22 bytes) | ERRJMP | Error code jump indirection table. 11 entries of LD E,4AH style instructions, each providing a unique error code via Register E. |
| 558EH-55B3H(38 bytes) | MISCRT | Miscellaneous tail routines: string termination, string-to-string move, and an alternative entry to 4977H. |
| 55B4H-55FFH(76 bytes) | CMDTBL | The CMD/CALL token name table. NUL-terminated ASCII command names ("AND PROCESSING", "GETVAL", "GETARGUME...") used by the symbol-table parser. The final 0DH-and-NUL-terminated string at 55ECH is "GET ARGUME" (truncated by the end of the image at 55FFH). |
Self-Modifying Workspace Variables
MicroDOS uses both internal storage within its image (in the FCB area at 448CH-449FH) and external low-RAM workspace (4080H-40A7H, populated by the init routine). The list below is keyed by address. All entries marked Self-Modifying Code show their initial values from the source disassembly and the runtime values they take after initialization.
| Address | Bytes | Description |
|---|---|---|
| 4080H-40A6H | 39 | Relocated BASIC Error Table A copy of the Level II BASIC ROM error message table at 18F7H, written here at 472DH-4731H. MicroDOS extends this in-RAM copy with disk-specific error messages, which is why the error handler at 19A2H sees both ROM and MicroDOS messages. |
| 40A0H | 2 | Byte Storage Pointer Set to 5A64H by the init routine at 474CH-474EH. Marks the start of MicroDOS's byte-storage area for compiled BASIC variables. |
| 40A4H | 2 | String Storage Pointer Set to 5A01H by the init routine at 4752H-4759H (loads HL=5A00H, writes 00H, increments HL, stores HL). Marks the start of the string storage area. |
| 40A7H | 2 | Comma Separator Template Pointer Set to 41E8H by the init routine at 473EH. Points just past the three-byte separator template stored at 41E5H-41E7H, which holds 3AH ":" 00H NUL 2CH ",". |
| 4016H | 2 | Self-Modifying Code The Level II BASIC ROM keyboard input vector. Init routine at 4767H-476CH writes 478FH here, hooking MicroDOS into BASIC's keyboard input. Once the AUTO-LOAD string is exhausted, 47A0H rewrites this to 47A3H (live keyboard scan). |
| 4152H-41E4H | 147 | Relocated Dispatch Table A copy of the JP-table at 4694H, written here at 4747H-474BH. After relocation, this table provides the RST 28H-style DOS-call dispatch for every BASIC keyword that MicroDOS overrides. |
| 41E5H-41E7H | 3 | Comma Separator Template Holds the bytes 3A 00 2C (":" NUL ","), written by the init routine at 4732H-473DH. Used by the argument parser at 4B59H to recognize statement separators in BASIC commands. |
| 41F8H | (stack) | Stack Top Set by the init routine at 475BH (LD SP,41F8H). Stack grows downward into the unused RAM at 41F7H and below. Note this is 4 bytes lower than the boot sector's 41FCH, freeing 4 bytes for an additional level of nested CALL. |
| 4495H | 1 | Self-Modifying Code FDC saved status. Written by 48F7H whenever a Type-I FDC operation completes (saves the status register before issuing FORCE INTERRUPT D0H), and by 4BEEH whenever a Type-II operation completes. Read by 490FH to test bit 7 (write protect / not ready) when reporting an error. |
| 4496H | 1 | Self-Modifying Code FORMAT routine running checksum. Written by 487CH (cleared at start of FORMAT), updated by 489CH-48B2H during the format-and-verify pass. |
| 4497H-449AH | 4 | Self-Modifying Code FORMAT/SEEK step-rate selector. Written by 4775H-4778H during init (LD HL,FFFFH stored to both 4497H and 4499H sets bytes 4497H-449AH all to FFH). Used as a per-drive step-rate selector at 4D44H-4D54H (right-rotated and tested for carry to find the matching drive bit). |
| 448CH | 1 | Self-Modifying Code Drive-select mask. Init routine at 4780H-4783H writes 01H (drive 0). Modified by drive-selection commands and by the FCB allocation routines. |
| 448DH | 1 | Self-Modifying Code Track number for next FDC operation. Cleared to 00H by 4926H. Written to 37EFH (FDC data register) by FDCSEEK at 4D6EH-4D6FH. |
| 448EH | 1 | Self-Modifying Code Sector number for next FDC operation. Initialized to 01H by 4933H (the file-load context init). Written to 37EEH (FDC sector register) by FDCSEEK at 4D77H-4D7AH. |
| 448FH | 1 | Self-Modifying Code Chain marker / buffer offset. Written by the file load routine at 491DH-4923H whenever a new sector is read (captures the marker byte). Read by 4A6CH-4A70H to drive the chain-walker decisions. |
| 4490H-4491H | 2 | Self-Modifying Code Buffer pointer (16-bit). Written to (4490H) by 4923H to hold the address of the next byte to read from the buffer. Used in EX DE,HL operations at 4490H-4491H to advance through the buffer. |
| 4492H-4493H | 2 | Self-Modifying Code Record number / record byte count. Written by 4B20H during file allocation; read by 4CA1H during FORMAT to determine the number of bytes per sector. Used as a 16-bit value at NUMPARSE. |
| 4494H | 1 | Self-Modifying Code FDC flags. Bit 0 set when a file is being written; bit 6 (tested at 4BFFH and 4C9AH) indicates write-protect on the current drive. |
| 5A00H | 1 | String storage initial sentinel. Set to 00H by 4755H. Marks the start of the heap that MicroDOS uses for BASIC string variables. |
| 5A01H+ | variable | Active string storage. Each entry is a length-prefixed string. The pointer at 40A4H tracks the next free byte. |
| 5A64H+ | variable | Byte storage / variable area. Each entry is a 4-byte BASIC variable record (header byte + 3 bytes of value). The pointer at 40A0H tracks the next free record. |
Major Routines
| Address | Function / Entry-Exit |
|---|---|
| 4727H | Initialization Entry Point (INIT) The first executable code in the resident image. Copies the BASIC error table to 4080H, writes the comma-separator template at 41E5H, copies the dispatch table to 4152H, sets up the string and byte storage pointers at 5A00H/5A64H, relocates the stack to 41F8H, displays the banner via 28A7H, hooks the keyboard at 4016H, and JPs to 00B5H to enter Level II BASIC. |
| 478FH | Keyboard Input Hook (KBDHOOK) Replacement for the BASIC ROM keyboard read at 0049H. Reads from the AUTO-LOAD command string at 44A5H one byte at a time. Returns the byte in Register A. When the string is exhausted (NUL byte read), rewrites the keyboard hook at 4016H to point at 47A3H (the live keyboard scanner) and falls through. |
| 47A3H | Live Keyboard Scanner (KBDSCAN) Scans the keyboard memory rows at 3801H, 3802H, 3804H, 3808H, 3810H, 3820H, 3840H, 3880H. For each row, computes the bit-mask of pressed keys and transitions to the Level II BASIC ROM key-decode routine at 03FBH. Returns Z if no keys are pressed. |
| 47C9H | BASIC Token Dispatcher (BASTOK) Called via the relocated dispatch table for CMD/CALL with a string argument. Reads the first character of the argument, compares against F (4FETCH), I (4INPUT), H (4HEX), K (4KILL), and M (4MERGE), and JPs to the matching handler. Default exit is JP 1E4AH (Illegal Function Call). |
| 4870H | Sector Chain Loader (FILEIO) Reads a sector-chain file. Initializes the FCB header at 4488H-448FH, calls FDCSEEK at 4D44H to position the head, reads the first sector via SECREAD at 4BCDH, and walks the chain marker by marker. Each sector is read into the buffer at 4300H, the marker byte is captured at 448FH, and the data is appended to the destination buffer. |
| 491BH | SYSTEM Re-Init Helper (RAMOPS) Reads a single byte from 4594H (the embedded boot copy entry point), saves it to 448FH, sets up the buffer pointer to 4595H, and calls 4BF6H to write the byte. Used by the SYSTEM-call re-initialization path. |
| 4941H | OPEN File Handler (FCBOPS entry) Routes from the dispatch table at 4152H entry for the OPEN keyword. Calls 4AFBH to extract the filespec (a quoted string or string variable), then performs directory lookup and FCB initialization. |
| 49AEH | OPEN-Existing-File Handler Specifically for the variant that opens an existing file (versus CREATE-new). Reads the FCB number from the BASIC argument list, looks up the file, and prepares the FCB for sequential read. |
| 49F6H | CREATE File Handler Creates a new file in the directory. Sets up an empty FCB, allocates a starting sector via 4977H, writes the directory entry, and prepares the FCB for sequential write. |
| 4AAEH | READ Sector Handler Routes from the GET keyword. Reads a numeric record number, calls FDCSEEK at 4D44H, calls SECREAD at 4BCDH. On success, copies the sector buffer to the BASIC string variable. |
| 4AE4H | WRITE Sector Handler Routes from the PUT keyword. Reads a numeric record number, copies the BASIC string buffer into the 256-byte sector buffer, calls FDCSEEK and the FDC Write command. |
| 4AFBH | Filespec Parser (FILESPEC entry) Calls Level II BASIC ROM 2337H to fetch a parameter, then calls 2819H (typeflag check) and FILESPEC at 4B10H. Returns with HL pointing at the resolved filename buffer. |
| 4B10H | Drive-Number Argument Parser Subtracts 2710H (10000 decimal) from HL repeatedly, counting iterations to extract the drive digit. Result in Register A. Falls through to record-number parser at 4B49H. |
| 4B49H | Record Number Validator Validates that Register E is less than 04H (max drive number 3). If valid, computes the drive-select mask via the (1 << drive) pattern (set A=80H, RLCA repeated drive+1 times) and stores it at 448CH. |
| 4B59H | Filespec Resolver Accepts a quoted string ("#" prefix means a file-buffer reference) or a BASIC string variable. Calls 260DH (VARPTR) and 0AF4H (which at this offset is part of MOVEA / MOVEB) to resolve the variable. |
| 4BCDH | Read Sector via FDC (SECREAD) Issues WD1771 Read Sector command (88H), polls for DRQ, transfers 256 bytes from 37EFH (FDC data register) into the buffer at BC' (4300H). On success, sets BC=4300H and returns; on error (status & 9CH), saves status at 4495H and returns with FDC at FORCE INTERRUPT. |
| 4C44H | Verify Sector (Compare-after-Write) Reads sector and compares against buffer. Returns NC if all bytes match (verify success), C if mismatch. |
| 4C6DH | Read Sector for Compare Issues Read Sector but discards the data, only checking for clean read status. Used by Verify to ensure the sector exists before doing a compare. |
| 4C91H | FORMAT Track (FORMAT) Writes a complete track including sector ID fields and data fields. Used by the FORMAT command. Writes 1771 Format Track command (F4H), then streams the track image with all sector IDs. |
| 4D44H | FDC Seek and Drive-Select (FDCSEEK) Reads the drive-select mask from 448CH, finds which drive is selected (RRA-and-test-carry pattern), retrieves the per-drive step-rate, sets the FDC track and sector registers, and issues the WD1771 Seek command. Equivalent in function to the boot sector's 4275H, but supports four drives and per-drive step rates. |
| 4D89H | Restore-then-Seek (Track 0 Calibration) If a Seek fails, calls Restore (00H) to return the head to Track 0, then re-issues the Seek. Used to recover from misaligned heads. |
| 4DACH | FDC Restore Command Issues WD1771 Restore (00H or 03H based on step-rate). Returns Z if Track 0 reached, NZ if seek error. |
| 4DE3H | Send FDC Command (FDCCMD) Equivalent to the boot sector's 42B9H. Saves the command on the stack, waits for the FDC not-busy, restores the command, writes it via DE' (37ECH), and polls for completion. Re-asserts drive select at 37E1H during the polling loop. |
| 4E19H-4E5DH | Error Code Jump Table (ERREXIT) 16 LD E,nn / JP 19A2H pairs, each providing a unique error code (4AH=BAD FILE DATA, 4EH=FEATURE NOT IMPLEMENTED, etc.). Called from the FDC error paths and the BASIC keyword handlers when an unsupported operation is requested. |
| 4E66H | String Move and Pad (STRMOV) Copies a length-prefixed string from a BASIC string variable into a destination buffer. Pads with spaces if the destination is longer than the source. |
| 4F12H, 4F16H, 4F1AH | WRITE Statement Handlers Three entry points for the BASIC WRITE statement variants: PRINT#, PRINT#USING, PUT. Each loads a different command-code-byte into Register A and then jumps to 4F1CH (the common write dispatcher). |
| 4F2DH, 4F31H, 4F35H | READ Statement Handlers Three entry points for the BASIC READ statement variants: GET, INPUT#, FIELD. Same pattern as WRITE: each loads a command-code byte and jumps to 4F37H. |
| 4F4CH, 4F4FH | OPEN Mode Handlers Two entries differing in whether the file is opened in append mode (FFH) or sequential read/write mode (00H). |
Cross-References and Analysis Notes
The resident OS depends on the following Level II BASIC ROM routines: 0033H (display char), 0040H (keyboard line input - via the relocated table), 0043H (VDPRT - Video Display Output trampoline; jumps to 0434H to print character in Register C), 0049H (keyboard scan - replaced by the hook at 4016H), 0060H (timing delay), 00B5H (BASIC entry after MEMORY SIZE prompt), 012DH (NAVERR - loads error code 2CH and jumps to error handler at 19A2H), 01C9H (CLS), 03FBH (key-decode dispatch), 0AF4H (MOVEA: move memory block, related to 09D6H), 18F7H (just past the end of the BASIC error message table at 18F6H - source for the relocated copy), 1955H (BASIC RUN initialization), 1997H (Syntax Error), 19A2H (Error Handler with code in Register E), 1A19H (BASIC READY entry), 1AF8H (write line pointers), 1B2CH (find line by number), 1B4DH (reset BASIC pointers), 1B5DH (BASIC initialization), 1B8FH (STKINI: initialize BASIC pointers, stack, and variables), 1C3DH (?), 1D1EH (run BASIC statement), 1E17H (?), 1E4AH (Illegal Function Call), 197AH (?), 23xxH range (parameter parsing), 28A7H (output 0/22H-terminated string), 29D7H (READY: BASIC READY prompt and command loop entry), 2819H (CPHLDE: 16-bit compare HL against DE), 2857H (STRINI: initialize/create new string entry), 285DH (STRSPA: check string space, garbage collect if needed), 2BE4H (FNDVAR: scan variable table for variable address), 2A2BH (?), 260DH (VARPTR), 09FFH (?), 09F7H (move number to SA), and 558CH (an internal MicroDOS routine called from outside the resident code, suggesting cross-disassembly references).
The resident does not depend on the boot sector being resident at 4200H during normal operation; the embedded boot copy at 4594H-4670H is purely a re-init path that the user must explicitly invoke (via SYSTEM/D or similar) to re-load the OS. During steady-state BASIC operation, only 4400H-4593H (data) and 4727H-55FFH (code/data) are reached.
The "WRITE# is the wrong name; use PUT" convention does not apply here because MicroDOS uses GET/PUT terminology only for random-access binary files (matching NEWDOS/80 and disk extensions of Microsoft BASIC), not as a wholesale replacement. The resident does not implement the WRITE# / READ# keywords; the dispatch table at 4152H simply doesn't route those tokens to MicroDOS code.
The custom error message table at 52F1H-5577H differs from the Level II BASIC ROM table at 18C9H-18F6H in three ways: (1) the strings are full ASCII rather than the ROM's two-letter abbreviations (e.g., "OUT OF MEMORY" instead of "OM"); (2) MicroDOS adds 13 disk-specific messages that the ROM lacks; and (3) the messages are accessed via the relocated copy at 4080H, not directly from 52F1H, so the table at 52F1H is the source data, while the actual lookup table that 19A2H walks is at 4080H.
Disassembly:
Track 0 / Sector 1 (4400H - 44FEH)
4400H - ENTRY - JP to Initialization Routine
When the boot sector at 42BAH executes JP NZ,4400H (the resident is in place because the chain marker on the final sector was non-FFH), the very first three bytes of the resident image take control. This is a forward jump to the initialization routine at 4727H. The 86 bytes immediately following the JP are not executable code; they are the build-time signature banner. The byte at 4403H (4DH = 'M') is also referenced by the FCB system as a default file-record signature, which is why Stutsman placed the M character at this specific offset.
4403H - BANNER1 - Build Signature Banner (DATA)
86-byte build-time signature string. Never displayed at runtime. The string reads "MICRODOS / A SIMPLE, POWERFUL DOS / WRITTEN BY JAMES W. STUTSMAN / FOR PERCOM DATA COMPANY", with carriage returns (0DH) between the lines and a NUL terminator at 4458H. The byte at 4403H (4DH = 'M') doubles as the FCB default-record signature byte, which is why this specific 'M' must remain at this specific address even though the banner is never printed.
4459H - SYMTAB - Built-in Symbol Table (DATA)
A 109-byte source-listing-format symbol table. Each entry is a label name followed by EQU and a hex address, then a semicolon-prefixed comment. The five entries provided are: CRLNUM (40ECH = current line number), PRGEND (40FBH = end of simple variables), ARREND (40FDH = end of arrays), and ACCUM (4121H = number accumulator). The table is data, not code, and would be referenced by a SYM/CALL command (dispatch entry 4E55H) for symbolic-name-to-address conversion.
Current Line Number Section
Program End and FCB Section
Auto-Load String Section
Continuation
Track 0 / Sector 2 (44FFH - 45FDH) - boundary falls within preceding SYMTAB2 row at 44AE-4525
4526H - AUTOPTR - Auto-Load Pointer (DATA)
Two bytes of pointer storage written by the init routine at 476DH-4772H to hold 44A5H (the start of the auto-load command string). The keyboard input hook at 478FH reads from this pointer and increments it.
Pointer to the next byte of the auto-load command string. Initialized to 44A5H by 476DH-4772H of the init routine. Read and incremented by the keyboard input hook at 478FH-4794H. When the byte read is NUL, the hook re-points the keyboard vector at 4016H and stops feeding auto-load characters.
4527H - BANNER2 - PerCom MicroDOS User Banner (DATA)
The user-visible banner printed by 4761H-4766H during initialization. The leading byte at 4527H is the high byte of the AUTOPTR (44H), but it is also the first byte of a string when read by 28A7H starting at 4527H instead of 4528H. The init routine specifically loads HL=4528H to skip the byte at 4527H, so the actual displayed banner is "PERCOM MICRODOS VERSION 2.20\rCOPYRIGHT (C) 1979 PERCOM DATA COMPANY\rALL RIGHTS RESERVED\r".
4581H - LSUMSG - Last Sector Used Message (DATA)
A 19-byte NUL-terminated string used by the format/disk-space utility commands. Output via 28A7H when the user runs a sector-allocation status command.
4594H - BOOTCOPY - Embedded Copy of Boot Sector Code
An exact 221-byte copy of the boot sector code from 4200H-42DCH. Provided so that a SYSTEM-call re-entry can restart the OS load sequence without reading T0/S0 from disk. The code is byte-for-byte identical to the boot sector, including the FE 00 placeholder at the entry point. Note: the absolute references inside this copy (e.g., LD HL,42F1H at 45A9H, LD HL,42DEH at 45CEH, CALL 424CH at 45A6H) all still point at the original boot sector data area at 42xxH, which means BOOTCOPY only works correctly if the original boot sector is still resident at 4200H. This is the normal case during steady-state operation; the boot sector RAM at 4200H-42FFH is never overwritten by BASIC unless the user explicitly POKEs there.
NOTE: 01C9H is the Level II BASIC ROM CLS routine. It clears the screen and homes the cursor.
NOTE: 424CH is the BOOT sector Read Sector routine. It reads Track 0 / Sector 1 (the first OS sector) into the buffer at 4300H. This call only works if the boot sector is still resident at 4200H-42FFH; if the boot RAM has been overwritten, BOOTCOPY fails.
NOTE: 42A7H is the BOOT sector NO MICRODOS error handler at the original location. Triggers the "NO MICRODOS" message and reboot path. This jump only works if the original boot sector is still resident.
NOTE: 42D4H is the BOOT sector NUL-terminated string print routine. This is a print of the buffer contents (the loaded sector, which begins with "MICRODOS"-prefixed text after the chain-marker).
NOTE: 424CH reads (TRACK,SECTOR) from 42DDH/42DEH and fills the buffer at 4300H.
Track 0 / Sector 3 (45FEH - 46FCH) - boundary falls within preceding BOOTCOPY main loop at 45CEH-45DEH
45E0H - BOOTCOPY Read Sector Subroutine
Internal subroutine of BOOTCOPY equivalent to the boot sector's 424CH-4274H routine. Issues an FDC Read Sector command and transfers data into the buffer. Note: this routine is independent of the boot sector's 424CH; it is invoked only from within BOOTCOPY (via 45A6H) when BOOTCOPY runs.
NOTE: 4275H is the BOOT sector Seek/Drive-Select routine. Reads track and sector from 42DDH/42DEH, selects drive 0, and issues a Seek command. Returns Z if the seek succeeded.
| 1771 FDC Command: 88H (10001000) | Function Description | ||||||||
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | Summary of Bits | |
| 1 | 0 | 0 | m | b | E | 0 | 0 | Command=Read Sector Bit 7-5: Read Command (100) m: 0=Single Record, 1=Multiple Records b: 1=IBM format, 0=Non-IBM Format E: 0=Assume Head Already Engaged, no Delay, 1=Enable HLD, HLT, and 10ms Delay Remainder: Unused (00) | |
NOTE: 42B9H writes the command in Register A to the FDC Command register at 37ECH and waits for the busy flag to clear.
| 1771 FDC Command: D0H (11010000) | Function Description | ||||||||
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | Summary of Bits | |
| 1 | 1 | 0 | 1 | I3 | I2 | I1 | I0 | Command=Force Interrupt Bit 7-4: Command Code (1101) I3: 1=Interrupt Immediately I2: 1=Interrupt on the next Index Pulse I1: 1=Interrupt the next time Ready goes to Not Ready I0: 1=Interrupt the next time Not Ready goes to Ready All 0: Terminate without interrupt | |
4609H - BOOTCOPY Seek and Drive-Select Subroutine
Internal subroutine of BOOTCOPY equivalent to the boot sector's 4275H-42A1H. Selects drive 0, sets the FDC track and sector registers, and issues a Seek command. Note this is independent of the boot sector's actual 4275H; it serves the BOOTCOPY data flow only.
NOTE: 0060H is the Level II BASIC ROM DELAY routine. It loops BC times, providing a calibrated delay. With BC=0000H, this is approximately 65,536 iterations - a long enough wait for an unselected drive to spin up.
| 1771 FDC Command: 17H (00010111) | Function Description | ||||||||
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | Summary of Bits | |
| 0 | 0 | 0 | 1 | h | V | r1 | r0 | Command=Seek Bit 7-4: Command Code (0001) h: 1=Enable Head Load/Settle, 0=No delay V: 1=Verify Destination Track ID, 0=No verification r1, r0: Stepping Motor Rate (00=3ms, 01=6ms, 10=10ms, 11=15ms) | |
NOTE: 42B9H writes the command in Register A to 37ECH and waits for the FDC busy flag to clear.
NOTE: 42C7H polls the FDC status register at 37ECH until bit 0 (busy) clears.
4636H - BOOTCOPY Disk Error Handler
Internal disk-error handler for BOOTCOPY. Equivalent to the boot sector's 42A2H, but uses BOOTCOPY's own copies of the DISK ERROR and NO MICRODOS messages at 4675H and 4682H. Displays the message, waits for any keypress, and reboots.
NOTE: 01C9H is the Level II BASIC ROM CLS routine. Clears the screen and homes the cursor.
NOTE: 42D4H walks the byte stream at HL, calling 0033H for each non-zero byte and returning when a zero byte is reached.
NOTE: 002BH is the Level II BASIC ROM KBDSCN routine. Returns Register A with the ASCII code of the pressed key (0 if no key).
464DH - BOOTCOPY Send FDC Command Subroutine
Internal Send-FDC-Command subroutine of BOOTCOPY, equivalent to the boot sector's 42B9H. Saves the command, waits for FDC not-busy, restores the command, writes it through the alternate DE' (37ECH), and polls bit 0 (busy) until cleared.
NOTE: 42C7H polls 37ECH until bit 0 (busy) clears, re-asserting drive select at 37E1H during each poll.
465BH - BOOTCOPY Wait for FDC Not Busy Subroutine
Internal wait-for-FDC-not-busy loop, equivalent to the boot sector's 42C7H. Re-asserts drive 0 select on each iteration to defeat the Model I one-shot drive-select latch.
4668H - BOOTCOPY Print NUL-Terminated String Subroutine
Internal NUL-terminated string print routine, equivalent to the boot sector's 42D4H. Walks bytes pointed at by HL, displays each via 0033H, and returns on a zero byte.
NOTE: 0033H is the Level II BASIC ROM VDCHAR routine. Displays the character in Register A at the cursor position and advances the cursor.
4671H - BOOTCOPY Data Block (DATA)
29 bytes of data containing the BOOTCOPY's own copies of the DISK ERROR and NO MICRODOS messages, plus the $STEPL residual symbol. These bytes are reachable by the BOOTCOPY error path (which actually targets 42xxH addresses, so these copies are never read at runtime; they exist as a build-time consequence of copying the entire boot sector).
4694H - JTABLE - BASIC Token Dispatch Table (DATA)
A 147-byte table of 49 JP instructions (3 bytes each = C3 lo hi). The init routine at 4741H-474BH copies this entire table to RAM at 4152H, where it overlaps the BASIC RST 28H hook addresses (400CH, 4015H) and provides MicroDOS keyword dispatch. Each entry corresponds to one BASIC reserved-word index. Entries that point to JP 0043H or JP 012DH are no-op slots reserved for keywords that MicroDOS does not implement (the original Level II BASIC handler handles them). Entries pointing into the 4940H-4ECBH range are MicroDOS handlers.
NOTE: 012DH is in the Level II BASIC ROM area; on entry, this skips to the original BASIC handler for the corresponding keyword.
NOTE: 0043H is the Level II BASIC ROM VDPRT entry. It jumps to 0434H to print the character held in Register C. Used here as a default placeholder slot for BASIC reserved-word indices that MicroDOS does not override; if the BASIC dispatcher falls through to one of these entries, the resulting behavior depends on the C register at the time.
Track 0 / Sector 4 (46FDH - 47FBH) - boundary falls within preceding JTABLE rows at 46EE-4724
4727H - INIT - MicroDOS Initialization
The first executable code of the resident OS, reached via JP 4727H from the entry trampoline at 4400H. Performs five jobs in sequence: (1) copies 39 bytes of post-error-table data from the Level II BASIC ROM at 18F7H to RAM at 4080H; (2) sets up a 3-byte separator template at 41E5H and points 40A7H at it; (3) copies the 147-byte JTABLE from 4694H down to RAM at 4152H; (4) initializes the byte-storage and string-storage pointers at 5A64H and 5A00H; (5) relocates the stack to 41F8H, prints the user banner via 28A7H, hooks the keyboard input vector at 4016H to KBDHOOK at 478FH, sets the AUTOPTR at 4526H to the auto-load string at 44A5H, initializes FCB defaults, and JPs to BASIC's 00B5H.
NOTE: 1B8FH is the Level II BASIC ROM STKINI routine. Initializes BASIC pointers, stack, and variables.
NOTE: 28A7H is the Level II BASIC ROM OUTSTR routine. Outputs a string starting at HL, terminated by either a 00H NUL or a 22H quote. Uses the device selected by 409CH (defaults to video).
NOTE: 00B5H is the Level II BASIC cold-start entry that goes directly to the BASIC READY prompt. At this point, the screen shows the MicroDOS banner followed by READY, and the keyboard hook at 4016H is feeding the auto-load string "LOAD 30,R" to BASIC.
478FH - KBDHOOK - Keyboard Input Hook
Replacement for the BASIC keyboard input call at (4016H), installed by the init routine at 4767H-476CH. Reads one byte from the AUTOPTR location at 4526H, increments AUTOPTR, and returns the byte to BASIC as if the user had typed it. When the byte read is NUL, the hook re-points 4016H to point at KBDSCAN at 47A3H.
47A3H - KBDSCAN - Live Keyboard Scanner
The live keyboard scanner, installed at 4016H once the auto-load string has been exhausted. Walks through the 8 keyboard memory rows by left-rotating Register C from 01H through 80H: 3801H, 3802H, 3804H, 3808H, 3810H, 3820H, 3840H, 3880H. For each row, reads the keyboard memory, computes the bit-mask of newly-pressed keys (XORing with the previous-frame state), and either continues scanning (if no keys are newly pressed) or transfers control to the Level II BASIC ROM key-decode routine at 03FBH with the row number in Register D and the keypress mask in Register A.
NOTE: 0060H is the Level II BASIC ROM DELAY routine. Loops BC times, providing a calibrated delay (debounce here).
NOTE: 03FBH is the Level II BASIC ROM keyboard key-decode and dispatch routine. Entry: A = keypress bitmask, D = row number. Returns the ASCII code of the pressed key in Register A.
47C9H - BASTOK - BASIC Token Dispatcher
Reached via JTABLE entry 11 (4152H+33 = 4175H, which is C3 C9 47 = JP 47C9H) when BASIC encounters the CMD/CALL token followed by a string argument. Reads the first character of the string argument, compares it against F (FETCH), I (INPUT), H (HEX), K (KILL), and M (MERGE), and JPs to the matching handler at 47F2H, 4818H, 4802H, 482BH, or 4841H respectively. Default exit is JP 1E4AH (Illegal Function Call).
NOTE: 2337H gets a general (string, integer, single, or double precision) parameter in the accumulator and sets the type flag (40AFH) accordingly.
NOTE: 29D7H is the Level II BASIC ROM READY-related routine. After the parameter parser, this prepares the string argument for processing.
NOTE: 1997H is the Level II BASIC ROM SN ERROR routine.
NOTE: 1E4AH is the Level II BASIC ROM FCERR routine, which prints "FC Error".
47F2H - FETCH Command (CMD"F")
Handles CMD"F" (FETCH). Skips a comma, parses an address argument via 4B3FH, validates it via RST 10H, then calls 4870H (the file-load routine) to fetch a file at the parsed address.
NOTE: RST 08H is the Level II BASIC ROM SYNTAX check. HL points to byte to be checked; the proper byte (2CH = ',') follows the RST 08H instruction.
NOTE: RST 10H advances HL past spaces and tabs, returning the next significant byte.
Track 0 / Sector 5 (47FCH - 48FAH) - boundary falls within preceding FETCH block at 47FCH (PUSH HL row)
4802H - HEX Command (CMD"H")
Handles CMD"H" (HEX dump or HEX-related operation). Calls 2337H to fetch a parameter, validates with RST 10H, parses additional context via 4851H.
4818H - INPUT Command (CMD"I")
Handles CMD"I" (INPUT-related, file-input). Same general pattern as FETCH but additionally calls 491BH after the file load to perform the BASIC line-pointer relink.
482BH - KILL Command (CMD"K")
Handles CMD"K" (KILL/delete file). Uses the symbol table at 44A5H as a destination buffer (the auto-load string area is reused after init since the auto-load completes before the user issues commands).
4841H - MERGE Command (CMD"M")
Handles CMD"M" (MERGE). Loads a file using FILEIO at 4870H, then performs MERGE-style line-pointer integration via 491BH.
4851H - String-Copy-To-Destination Helper
Copies a BASIC string descriptor's data into a destination buffer at DE. HL points at the BASIC string descriptor (length byte + 2-byte data pointer). Caps the length at 80H (128 bytes). Translates 0AH (line feed) to 0DH (carriage return) during the copy. NUL-terminates the destination.
4870H - FILEIO - File Format/Initialize Routine
Reached from the FETCH and INPUT command handlers at 47FDH and 4823H. The name FILEIO is a misnomer in the original continuation file - this is actually the FORMAT-and-write routine, used to lay down a chain of sectors. Clears the SECTOR variable at 448DH-448EH, fetches a record byte count from RECNO at 4492H, calls FORMAT at 4C91H repeatedly, and uses the verify routine at 48BCH to confirm written data.
GOSUB to FORMAT at 4C91H, which lays down sector ID fields and data fields for one track.
Store Register B (=00H after DJNZ exit) to the address held in Register Pair HL (=448DH), resetting the track byte to 00H for the verify pass.
GOSUB to the verify-track routine at 48BCH, which reads back the track and counts errors.
DECrement the byte at the address held in Register Pair HL (=448DH) by 1, since the loop overshot by one (DJNZ exits with one extra increment).
48BCH - Verify Track Routine
Reads back all sectors of a track and counts errors. Called from the FORMAT loop after each track is written. Returns Z if all sectors verify clean, NZ with error count in Register A if any failed.
Save Register Pair BC (loop counter and bad-sector count) onto the stack.
Copy Register C (the bad-sector count for this track) into Register A.
48DAH - ERREXIT2 - Error Code Setup Table (Variant 2)
Eight 4-byte entries. Each entry loads Register E with a unique error code (2EH, 30H, 34H, 32H, 38H, 42H, 44H) and JRs to either 4918H (final-error JP 19A2H) or 48F4H (the FDC FORCE INTERRUPT path that saves status before erroring). These entry points are reached by JP from various FDC error paths in the disk I/O routines.
Track 0 / Sector 6 (48FBH - 49F9H) - boundary falls within preceding ERREXIT2 table at 48F4H
48F4H - FDC FORCE INTERRUPT Pre-Error Path
Common entry from the 48E6H, 48EAH, 48EEH, 48F2H error setups. Saves the current FDC status to 4495H, issues a FORCE INTERRUPT (D0H) to terminate any in-progress operation, marks the offending drive's step-rate entry as FFH, then either tests for write-protect or falls through to the error JP at 4918H.
Rotate Register A right circularly. Bit 0 becomes bit 7 and the C FLAG.
Set the byte at the address held in Register Pair HL (the matching step-rate entry for the selected drive) to FFH, marking that drive's step-rate as "needs recalibration".
NOTE: 19A2H is the Level II BASIC ROM ERROR routine. Displays the error message indexed by Register E.
NOTE: 19A2H is the Level II BASIC ROM ERROR handler.
491BH - SYSTEM Re-Init / Line-Pointer Relink
Reached from the INPUT handler at 4826H, the MERGE handler at 484CH, and from the file-load post-processing path. Loads the byte at 4594H (the embedded boot copy entry, used as a 1-byte signature), saves it to 448FH (the chain marker variable), and sets up the buffer pointer at 4490H to 4595H. Then clears the SECTOR variable, calls 4BF6H (the chain-walker write-back), advances 448EH to 01H (sector 1), and computes the loaded-program length (5600H - 4400H = 1200H) for the BASIC line-pointer relink call at 4968H.
4941H - OPEN/CALL Argument Handler
JTABLE entry 26 routes here for the BASIC OPEN keyword. Calls FILESPEC parser at 4AFBH to fetch a string argument, validates the line ending via RST 10H, then computes the gap between the current string-storage pointer at 40A4H and the string-area top at 40F9H. Calls 4968H to display the gap as a numeric value (probably "FREE BYTES = NN").
NOTE: 28A7H is the Level II BASIC ROM OUTSTR routine.
NOTE: 0FBDH is the Level II BASIC ROM CSAASC routine. Converts the value in the software accumulator to ASCII and places it in the buffer at 4130H, with HL=4130H on return.
4968H - Display Gap as Decimal Number / Allocate Loop
A multipurpose routine reached from 491BH (with HL = image length) and 4954H (with HL = free-byte count). Calls 559EH to display the high byte of HL, then loops calling 497DH and 498FH to walk the chain marker chain.
4977H - Chain Tail Allocation
Final step of a chain allocation: stores BC into HL via the chain-marker-write helper. Reached as a branch target from 55A4H (an alternate entry from the misc-routines tail block).
497DH - Chain Marker Write Helper
Writes Register C (the chain marker byte) to 448FH and Register Pair DE (the buffer pointer) to 4490H, then calls 4BF6H (the actual disk write). After the write, recomputes HL = HL - BC for the caller's gap-tracking.
498FH - Sector Advance Helper
Advances the SECTOR variable at 448DH-448EH to the next track/sector. INC H (track byte), check against record limit at 4492H; if past limit, INC L (the sector wraps), check against limit at 4493H; if both exceeded, raise error 36H ("Disk Overflow").
NOTE: 19A2H is the Level II BASIC ROM ERROR routine.
49AEH - LOAD/RUN Handler (JTABLE entry 18)
Reached via JTABLE entry 18 (4152H+54 = 4188H = JP 49AEH) for the LOAD-and-optionally-RUN keyword. Calls the FILESPEC parser at 4AFBH to fetch the filename argument. Then optionally reads a R suffix (which turns the LOAD into a LOAD-and-RUN), reinitializes the BASIC pointers via 1B4DH, walks through the loaded program updating BASIC line pointers, and finally either returns to the BASIC READY prompt at 1A19H or executes the program via JP 1D1EH.
NOTE: RST 10H advances HL past spaces and tabs, returning the next significant byte.
NOTE: RST 08H is the Level II BASIC ROM SYNTAX check. HL points to the byte being checked; the proper byte (2CH = ',') follows the RST 08H instruction.
NOTE: 1997H is the Level II BASIC ROM SN ERROR routine.
NOTE: 1B4DH is the Level II BASIC ROM NEW routine entry, which resets the BASIC pointers (clears variables, resets line pointers). Required before loading a new program.
ADD Register Pair DE to HL. After the ADD, HL is the current write pointer into the BASIC program area.
GOSUB to ROM 1AF8H.
NOTE: 1AF8H is the Level II BASIC ROM routine that writes line pointers from the start of the BASIC program, linking the loaded BASIC text into a runnable program.
NOTE: 1B5DH is the Level II BASIC ROM RUN initialization. Sets up the run-time environment so the loaded program can execute.
NOTE: 1A19H is the Level II BASIC ROM BASIC entry point that displays READY.
NOTE: 1D1EH is the Level II BASIC ROM RUNSTM routine. HL points at the next statement to execute; control transfers into the BASIC interpreter loop.
Track 0 / Sector 7 (49FAH - 4AF8H) - boundary falls within preceding LOAD/RUN handler at 49FAH (DEC HL row)
49F6H - SAVE Handler (JTABLE entry 19)
Reached via JTABLE entry 19 (4152H+57 = 418BH = JP 49F6H) for the SAVE keyword. POPs the stale return address that the BASIC dispatcher pushed (because SAVE handles its own argument processing differently from LOAD). Calls FILESPEC parser at 4AFBH, validates end-of-statement, initializes the buffer with FFH chain markers, and enters a directory-scan loop calling DIRWALK at 4A4AH to find the file's directory entry. When found, allocates new disk space, writes the BASIC program contents using the chained-sector format, and finally re-runs the file allocation routines via 4A45H.
GOSUB to DIRWALK at 4A4AH to read the next directory entry. Returns Z if no more entries (end of directory), NZ with DE pointing at the entry data otherwise.
NOTE: 1B2CH is the Level II BASIC ROM FNDLIN routine. Searches for the BASIC line number held in DE; on exit, BC contains the address of that line in the program.
NOTE: 2BE4H is the Level II BASIC ROM FNDVAR routine. Scans the variable table for the address of a specific variable. Called conditionally to handle variable-name lookup when the line was found.
NOTE: 1955H is the Level II BASIC ROM OMERR (Out of Memory) error check routine. Verifies enough RAM is available for the proposed allocation; raises "OM Error" if not.
Load Register A with the byte at HL (the next byte of the source).
Restore Register Pair DE from the stack.
NOTE: 1AF8H is the Level II BASIC ROM line-pointer-link routine.
NOTE: 1A19H is the Level II BASIC ROM READY entry. The SAVE has completed; control returns to the user prompt.
4A4AH - DIRWALK - Directory Walker
Reads the next directory record from the file directory. Each directory record begins with a 4-byte header (loaded into BC=0004H, then read via 4A6CH), followed by a variable-length name field. Returns Z if end-of-directory reached, NZ with DE=line number, A=count if a record was successfully read.
GOSUB to 4A6CH to fetch the next filename byte into Register A.
INCrement Register A by 1. Since A was 0 (NUL), A is now 01H, ensuring the NZ flag is set on return.
4A6CH - Chain-Byte-Fetch Helper
Fetches one byte from the chained sector buffer. Decrements the byte counter at 448FH; if it reaches zero, calls 4A82H to read the next sector before fetching. Returns the byte in Register A and updates the buffer pointer at 4490H.
4A82H - Read Next Sector and Test Marker
Reads the next sector into the buffer at 4300H, captures the chain-marker byte, and updates the bytes-remaining counter at 448FH and the buffer pointer at 4490H. If the chain marker is FFH (continuation), returns with A holding the byte count. If non-FFH (end-of-chain), takes the special-case path through 4AA6H.
4AAEH - APPEND/Field Handler (JTABLE entry 15)
Reached via JTABLE entry 15 (4152H+45 = 417FH = JP 4AAEH) for the APPEND or FIELD-style keyword. Calls FILESPEC parser at 4B59H, validates a comma, fetches another argument via 4AFBH, validates end-of-statement, then reads a byte from the chain and stores it. If the byte exceeds Register C (the limit), enters the multi-step processing path that calls 55A7H, copies 3 bytes from 40D3H, and updates 4490H from 40D4H.
4AE4H - PUT Handler (JTABLE entry 16)
Reached via JTABLE entry 16 (4152H+48 = 4182H = JP 4AE4H) for the PUT keyword. Calls FILESPEC parser at 4B59H, validates a comma, fetches a numeric argument via 4AFBH, validates end-of-statement, swaps DE and HL, reads a byte from (HL), stores at 448FH, calls the chain-write at 4BF6H.
Track 0 / Sector 8 (4AF9H - 4BF7H) - boundary falls at end of preceding PUT handler row at 4AF9H
4AFBH - FILESPEC Parser (Quoted String or Numeric)
Reached from many keyword handlers including FETCH, INPUT, MERGE, KILL, LOAD/RUN, SAVE, APPEND, PUT. Calls Level II BASIC ROM 2337H to fetch a parameter into the accumulator, sets the type-flag at 40AFH to 02H (single-precision), invokes Level II BASIC ROM 2819H (16-bit compare HL:DE), then calls 4B10H (drive-number argument parser). On exit, HL points just past the parameter and DE points at the resolved buffer.
NOTE: 2337H is the Level II BASIC ROM general-parameter parser. Gets a string, integer, single, or double precision parameter and sets the type flag at 40AFH.
NOTE: 2819H is the Level II BASIC ROM CPHLDE routine. Performs a 16-bit comparison of HL against DE. Used here to ensure the parsed value is in the valid range.
4B10H - Drive-Number/Record-Number Parser
Splits a 16-bit numeric argument into a drive number (high digit) and record number (low digits). Subtracts 2710H (10000 decimal) from HL repeatedly, counting iterations. When the subtraction goes negative, the iteration count is the drive number and the residue is the record number. Falls through to 4B49H to validate the drive number.
SUBtract Register Pair DE from HL with carry borrow. Successive subtractions count down by 10000.
LOOP BACK to 4B14H to subtract again.
Work In Progress
This page is being built incrementally. The disassembly through 49ADH has been completed. The remaining 1,747 bytes (49AEH-55FFH) cover the OPEN-existing-file handler, CREATE-file handler, the directory walker (4A4AH), the OPENRD/WRITE handlers, the FILESPEC parser, the SECREAD/FORMAT/FDCSEEK/FDCCMD routines, the ERREXIT jump tables, the BASIC keyword handlers, the NUMIO routines, the utility functions, and the BASIC error message table at 52F1H-5577H. Track/sector boundaries to be inserted: T0/S7 at 49FAH, T0/S8 at 4AF9H, T0/S9 at 4BF8H, T1/S0 at 4CF7H, T1/S1 at 4DF6H, T1/S2 at 4EF5H, T1/S3 at 4FF4H, T1/S4 at 50F3H, T1/S5 at 51F2H, T1/S6 at 52F1H, T1/S7 at 53F0H, T1/S8 at 54EFH, T1/S9 at 55EEH.