TRS-80 DOS - NEWDOS/80 v2.0 for the Model III - SYS14/SYS Disassembled
Page Customization
Page Index
SYS14/SYS
Other Navigation
Introduction/Summary
NEWDOS/80 v2.0 SYS14/SYS Disassembly - ROUTE, CLEAR, CREATE, ERROR, LIST and PRINT (Model III)
SYS14/SYS holds six library commands: ROUTE (device routing), CLEAR (routes, timer and named routine queues, HIMEM and memory), CREATE (make a file and pre-allocate its records), ERROR (show a DOS error message), and LIST and PRINT (show a text file on the display or the printer). Its five load records fill 4D00H-51E7H of the overlay area (1,256 bytes) and its transfer address is 4D00H; 5187H-51E7H are 00H.
The page shows every byte of the file once, in address order.
Commands
SYS1/SYS's command table gives every one of these commands the RST 28H code F0H (function 7 of directory slot 10H) with a sub-function in Register C.
| Sub-Function | Command |
|---|---|
| 1 | ROUTE, 4D4DH |
| 2 | CREATE (SYS1/SYS parses the filespec into 4480H), 4F8EH |
| 3 | Not a command: the return to SYS14/SYS after a DOS routine or another overlay was called through 4D27H, 4D37H |
| 4 | CLEAR, 5071H |
| 5 and 6 | LIST 50EAH and PRINT 50E5H (SYS1/SYS opens the file in 4480H and leaves the command line pointer on the stack) |
| 7 | ERROR, shown through SYS4/SYS code 66H, 4D39H |
Any other code or sub-function gives error 2AH. CREATE opens its file through SYS2/SYS and writes its last sector through SYS0/SYS 4439H, both of which may load another overlay over SYS14/SYS; 4D27H pushes the word F003H and the SYS0/SYS return point 4978H first, so that SYS14/SYS is loaded again at sub-function 3 and returns to the caller.
Numbers (ERROR's message number, MM=, LRL=, REC=, START=, END=, MEM= and LIST's line numbers) are read by 4EEFH: decimal, or hexadecimal ended by H. Every bad value is error 2FH (BAD PARAMETER(S)), and an unknown word or a bad separator error 34H (ILLEGAL KEYWORD OR SEPARATOR OR TERMINATOR).
Routes
A route entry is 7 bytes: +0 the routed device's DCB, +2 that DCB's own type byte, +3 the link to the next entry (0000H after the last, FFFFH for a free entry), +5 the target DCB. The chain starts at 4A81H, the operand SYS0/SYS's device code reads, and every routed DCB has the type byte C0H. Named targets take one of SYS0/SYS's six entries at 42D6H-42FFH (when all six are in use the error is 3BH, Insufficient Memory). An MM=addr target is a block of the user's at 5200H or above: SYS14/SYS puts the route entry at addr, a DCB at addr + 08H with the driver address addr + 10H at addr + 09H, and the user's routine starts at addr + 10H.
| Name | DCB | Use |
|---|---|---|
| KB | 4015H | Keyboard; input; routed or target |
| DO | 401DH | Display; output; routed or target |
| PR | 4025H | Printer; output; routed or target |
| RI | 41E5H | RS-232 input; input; routed or target |
| RO | 41EDH | RS-232 output; output; routed or target |
| RC | 41F5H | RS-232 initialization; output; routed or target |
| NL | 4CA1H | Nothing in, nothing out; input and output; target only |
| MM=addr | addr + 08H | The user's routine at addr + 10H; input and output; target only |
An input device takes only input targets and an output device only output targets (error 2FH). ROUTE,dev first ends dev's routes; each target then gets a new entry at the end of the chain. ROUTE alone lists the entries, one line each (4E32H always skips the code that would put several targets of one device on one line).
CREATE
The options (LRL=1-256, REC=n, ASE=Y/N, ASC=Y/N) are collected on the stack. The file is opened or made through SYS2/SYS code 44H; FPDE byte 1 gets bit 7 for ASE=N (no extension) and bit 6 for ASC=N (no deallocation by the close), with bits 5-7 cleared otherwise, and FPDE byte 4 gets the LRL. With REC, the byte count REC x LRL is worked out by SYS0/SYS 4C42H, the last sector is written with 428BH bit 1 set (SYS2/SYS then allocates every granule needed and no extra ones), every sector is then written with 00H from a buffer at 4D4DH-4E4CH (ROUTE's own code), and the end of file is set to the byte count. Without REC the end of file is set to 0. The close (SYS0/SYS 4428H) writes it to the directory.
Variables
Memory Outside SYS14/SYS
| Address Size | Contents |
|---|---|
| 3840H 1 byte | Keyboard Row Bit 0 ENTER, bit 3 up arrow, bit 6 right arrow: LIST and PRINT pause and stop (5127H, 512EH, 513AH). |
| 4015H, 401DH, 4025H 24 bytes | Device Control Blocks Keyboard, display and printer DCBs (8 bytes each); byte 0 is the type, set to C0H while routed (4DD7H) and put back by 4EB6H. |
| 41E5H, 41EDH, 41F5H 24 bytes | RS-232 Device Control Blocks RS-232 input, output and initialization DCBs (8 bytes each), the devices RI, RO and RC. |
| 4058H-4059H 2 bytes | Named Routine Queue Head of the queue of named routines; CLEAR stores 0000H (5091H). |
| 428BH 1 byte | Overlay Flags Bit 1 set around CREATE's allocation (5020H, 5025H): SYS2/SYS takes no extra granules. |
| 4290H 1 byte | Option AX The highest character code LIST and PRINT show as it is (514EH). |
| 42C9H-42CAH 2 bytes | Top of Memory Found at reset; CLEAR's highest HIMEM (509AH). |
| 42D6H-42FFH 42 bytes | Route Entries Six 7-byte entries for named targets (4DB3H), link FFFFH when free (4EBBH). |
| 4300H-43FFH 256 bytes | DOS Sector Buffer The directory sector with CREATE's FPDE (4FE2H, 4FFBH); LIST's file buffer (50FFH). |
| 4411H-4412H 2 bytes | HIMEM Set by CLEAR (50AAH). |
| 4480H-449FH 32 bytes | DOS FCB The CREATE, LIST or PRINT file: 4483H buffer (502AH, 5102H), 4488H end of file low byte (504AH), 448AH-448BH NEXT sector (5013H, 5037H), 448CH-448DH end of file sector (5047H). |
| 4584H-4585H 2 bytes | Timer Chain Head of SYS0/SYS's timer chain; CLEAR stores 0000H (5097H). |
| 4A81H-4A82H 2 bytes | Route Chain Head The operand in SYS0/SYS that holds the first route entry (4E0AH, 4DE7H, 4E94H). |
SYS14/SYS Buffers
| Address Size | Contents |
|---|---|
| 4D4DH-4E4CH 256 bytes | CREATE Buffer SYS14/SYS's own ROUTE code, zeroed and used as the sector buffer of CREATE (5027H-5031H). |
| 4F48H-4F4DH 6 bytes | Hexadecimal Text "0000H" and 03H: an MM block's address is written here by SYS0/SYS 44D2H (4E8DH). |
Operands Changed at Run Time
| Address Size | Contents |
|---|---|
| 4D34H-4D35H 2 bytes | Routine Called by 4D27H The operand of JP Z at 4D33H: 0000H in the file, 4439H after 501AH. |
| 4DA5H 1 byte | Routed Device's Attribute The operand of AND at 4DA4H, stored at 4D61H. |
| 4DCEH-4DCFH 2 bytes | Routed DCB The operand of LD DE at 4DCDH, stored at 4D64H. |
| 4DD9H 1 byte | Routed DCB's Type Byte The operand of LD A at 4DD8H, stored at 4D6DH. |
| 4DE2H-4DE3H 2 bytes | Target DCB The operand of LD DE at 4DE1H, stored at 4DABH. |
| 509EH-509FH 2 bytes | MEM The operand of LD DE at 509DH: FFFFH in the file, MEM= stored at 5081H. |
| 50AEH-50AFH 2 bytes | END The operand of LD DE at 50ADH: FFFFH in the file, END= stored at 5081H. |
| 50B5H-50B6H 2 bytes | START The operand of LD HL at 50B4H: 5200H in the file, START= stored at 5081H. |
| 5182H 1 byte | Output Routine The low byte of the CALL at 5181H: 33H (display) in the file, 3BH (printer) after PRINT's 50E7H. |
Outside Routines and Addresses
| Address | Contents |
|---|---|
| 0013H, 0033H, 003BH | ROM: read a byte from a control block (5145H), display a character (4E44H, 4E4BH, 4E79H, 5181H), print a character (5181H after PRINT). |
| RST 18H | ROM: compare Register Pair HL with Register Pair DE (4D44H, 50A6H, 50B0H, 50BEH, 50C5H). |
| 4409H | SYS0/SYS: the DOS error exit (4EECH, 4F0FH). |
| 4428H, 4439H | SYS0/SYS: close (504DH), write the sector at NEXT (5017H, 503BH). |
| 44D2H, 4467H | SYS0/SYS: a word as four hexadecimal digits (4E8DH), display a message (4E1CH, 4E91H). |
| 48C4H, 48F0H | SYS0/SYS: write the directory sector (4FFBH), read the FPDE of an open FCB (4FE2H). |
| 4978H | SYS0/SYS: the function chain return that brings SYS14/SYS back (4D2CH). |
| 4BC5H | SYS0/SYS: the dispatcher's return address, dropped at 4D37H and 50EAH. |
| 4C42H | SYS0/SYS: multiply Register Pair HL by Register A (5009H). |
| 4C6AH, 4C7AH | SYS0/SYS: compare a word (4ED7H), test for the end of the line or a separator (4D3CH, 4D71H, 4DFCH, 4F93H, 5085H, 50ECH, 5177H). |
| 4CA1H | SYS0/SYS: the NL device control block (4F7AH). |
| 44H, 66H | RST 28H codes used: SYS2/SYS open new or existing (4FD3H), SYS4/SYS display an error message (4D49H). |
Disassembly
4D00H - Function Dispatcher
SYS14/SYS (directory slot 10H) is loaded by the SYS0/SYS RST 28H dispatcher (4B67H) into 4D00H-51E7H and entered at 4D00H by the CALL at 4BC2H, with Register A = the RST 28H code, Register C = the sub-function, and the return address 4BC5H (the dispatcher's tail) on top of the stack. The only code it accepts is F0H (function 7 of slot 10H), which SYS1/SYS's command table gives to ROUTE (sub-function 1), CREATE (2), CLEAR (4), LIST (5), PRINT (6) and ERROR (7). Sub-function 3 is never in the command table: it is the word F003H that 4D27H pushes so that SYS0/SYS 4978H brings SYS14/SYS back after a DOS routine or another overlay has run. Register Pair HL points at the command line after the command word.
4D27H - Call a DOS Routine or Another Overlay and Come Back
Either call may load another overlay into 4D00H-51FFH over SYS14/SYS, so the word F003H (code F0H, sub-function 3) and the SYS0/SYS return point 4978H are pushed first. When the routine or the overlay returns to 4978H with the Z FLAG, SYS0/SYS pops F003H into Register A and Register C and issues RST 28H, which reloads SYS14/SYS if it was overwritten and enters it at sub-function 3 (4D37H); that drops the dispatcher's return address and returns to the caller of 4D27H or 4D28H with Register Pairs DE and HL as the routine left them. With the NZ FLAG, 4978H goes to the DOS error exit 4409H instead. 4D27H calls the SYS0/SYS routine whose address is in the operand 4D34H (only 4439H, stored at 501AH); 4D28H runs RST 28H with the code in Register A (only 44H, SYS2/SYS's open, from 4FD8H).
If the Z FLAG is set (Register A = 00H), JUMP to the SYS0/SYS routine whose address is the operand 4D34H-4D35H: 0000H in the file, 4439H (write the sector at NEXT) after 501AH stores it. The routine returns to 4978H.
4D39H - ERROR Command
ERROR,n displays the message of DOS error n (0-63) and returns to DOS READY. Register Pair HL points at n in the command line. The message is shown by SYS4/SYS function 3 (code 66H), which displays it whatever the DOS state and, since bit 7 of n is clear, leaves through 402DH to DOS READY.
4D4DH - ROUTE Command
ROUTE alone lists the routes. ROUTE,CLEAR ends every route. ROUTE,dev[,dev2][,dev3]... first ends the routes of dev, then routes dev to (an output device) or from (an input device) each device after it. The names are those of the table at 4F53H: KB (4015H), DO (401DH), PR (4025H), RI (41E5H), RO (41EDH) and RC (41F5H) may be routed; KB, DO, PR, RI, RO, RC, NL (4CA1H) and MM=addr may be targets; an input device may only use an input target and an output device only an output target (NL and MM= serve both). A route is a 7-byte entry: +0 the routed DCB, +2 its own type byte, +3 the link to the next entry (0000H ends the chain, FFFFH marks a free entry), +5 the target DCB. Entries for named targets come from SYS0/SYS's six entries at 42D6H-42FFH; an MM=addr target keeps its entry in the first bytes of its own block. The chain starts at the operand 4A81H in SYS0/SYS, and a routed DCB's type byte is set to C0H, which makes SYS0/SYS's device code (4A80H) follow the chain. Interrupts are disabled while the chain changes. This code area 4D4DH-4E4CH is also the zeroed sector buffer of CREATE (5027H).
Store Register A (the routed device's attribute byte: C1H for an input device, C2H for an output device) at 4DA5H, the operand of the AND 00H at 4DA4H that checks each target's direction.
Store Register Pair DE (the routed device's DCB address) at 4DCEH-4DCFH, the operand of the LD DE,0000H at 4DCDH that writes it into each new route entry.
Store Register A (the DCB's own type byte) at 4DD9H, the operand of the LD A,00H at 4DD8H, so that each new route entry keeps it at +2 for 4E94H to put back.
Target Loop
The command line pointer is on top of the stack; each pass takes one target device.
AND Register A (the target's attribute byte) with the operand at 4DA5H: 00H in the file, the routed device's attribute byte after 4D61H stores it. The bits both devices share remain.
Store Register Pair DE (the target DCB) at 4DE2H-4DE3H, the operand of the LD DE,0000H at 4DE1H that writes it into the entry. 4D9EH comes here for MM=.
Find a Free Entry
Register Pair HL steps 7 bytes at a time through the entries at 42D6H, 42DDH, 42E4H, 42EBH, 42F2H and 42F9H; a free one has the link FFFFH at +3.
Load Register Pair DE with the routed device's DCB address: the operand 4DCEH-4DCFH (0000H in the file) was stored at 4D64H. 4DB1H comes here for MM= with Register Pair HL = the block.
Load Register A with the routed DCB's own type byte: the operand 4DD9H (00H in the file) was stored at 4D6DH.
Load Register Pair DE with the target DCB: the operand 4DE2H-4DE3H (0000H in the file) was stored at 4DABH.
Find the End of the Chain
Register Pair DE = the entry whose link (at +3) is looked at; 4A7EH stands for the chain head 4A81H.
4DFCH - ROUTE,CLEAR
ROUTE,CLEAR must end the command line; every route of every device then ends. CLEAR's command code calls 4E01H for the same work.
4E0AH - List the Routes
ROUTE alone shows one line per route entry, in chain order from the head at 4A81H: the routed device's name, the word TO and the target's name. A named device's name comes from the table at 4F53H; any other DCB is shown as MM= and the address of its block in hexadecimal.
Entry Loop
Register Pair HL = the route entry to show.
4E56H - Display a Device Name
Register Pair DE = a DCB address. The device table at 4F53H is searched for an entry whose word is that DCB; its name is displayed. A DCB that is not in the table belongs to an MM= block (its DCB is at block + 08H), so MM= is displayed followed by the block's address as four hexadecimal digits and H.
Table Search Loop
Register Pair HL = the start of the entry, which is also saved on the stack.
Display the Name
Register Pair HL = the name, which ends with 00H.
4E94H - End the Routes of a Device
Register Pair DE = the DCB whose routes end, or 0000H to end every route. The chain is walked from the head at 4A81H; each matching entry is unlinked, marked free (link FFFFH) and its routed DCB gets its own type byte back (entry +2). Register Pair BC always holds the address of the link that points at the entry being looked at. Interrupts are disabled by the callers (4D4DH, 4E01H).
Chain Loop
Register Pair HL = two bytes before a link (an entry's +1, or 4A7FH for the head).
4EC6H - Look Up a Word in a Table
4EC6H looks up the name at Register Pair HL in the device table at 4F53H; 4EC9H takes the table in Register Pair BC (CREATE's 5050H, CLEAR's 50CAH). Each table entry is a word ended by 00H followed by three bytes (an attribute or flag byte and a 16-bit value); a 00H ends the table. On a match it returns Register A = the byte after the 00H, Register Pair DE = the 16-bit value and Register Pair HL past the word in the command line. A word not in the table leaves through 4EE9H with error 34H.
Search Loop
Register Pair BC = the table entry, Register Pair HL = the word in the command line, Register D = the bytes after each 00H.
4EE9H - Error Exits
4EE9H gives error 34H; 4EEBH leaves with the error code already in Register A. Both enable interrupts, since ROUTE may have disabled them, and go to the SYS0/SYS error exit 4409H, which shows the message (or hands the error to SYS1/SYS under DOS-CALL or a chain file).
4EEFH - Read a Number
Reads a number at Register Pair HL into Register Pair DE: decimal digits, or hexadecimal digits ended by H. The digits are first read as decimal; if a letter A-H follows them, the number is read again from its start as hexadecimal, and must then end with H. No digit, a missing H or a value above FFFFH is error 2FH. Register Pair HL returns past the number. Used by ERROR (4D39H), ROUTE's MM= (4D84H), CREATE's LRL= and REC= (4FBAH, 4FC8H), CLEAR's options (507DH) and LIST's parameters (5172H).
4F12H - Read Digits
Register Pair HL = the text, Register B bit 0 = hexadecimal. The digits are added up in Register Pair DE (times 10, or times 16, plus the digit); Register A collects every carry out of bit 15, and any carry is error 2FH. Bit 1 of Register B is set when a digit is read. Returns at the first character that is not a digit, with Register Pair HL pointing at it.
Digit Loop
Register Pair HL = the next character, Register Pair DE = the value so far.
4F48H - Texts and the Device Table (Data)
The hexadecimal text buffer of 4E89H, the text shown between two device names, and the device table of ROUTE. Each device entry is the name, 00H, an attribute byte and the DCB address. Attribute bits: 7 may be routed, 6 may be a target, 5 an address follows (MM=), 4 the word CLEAR, 1 output, 0 input.
4F8EH - CREATE Command
CREATE,filespec[,LRL=n][,REC=n][,ASE=Y/N][,ASC=Y/N]. SYS1/SYS has parsed the filespec into the FCB at 4480H without opening it; Register Pair HL points at the command line after it. The options are collected on the stack: a word with the ASE/ASC flags (Register C: bit 7 ASE=N, bit 6 ASC=N) and the LRL (Register B, 00H for 256), and below it the number of records (0000H when REC is not given). The file is then opened, made if it does not exist, through SYS2/SYS; its FPDE gets the LRL and the ASE/ASC bits; with REC the whole file is allocated by writing its last sector, every sector is then written with zeros, and the end of file is set to REC times LRL bytes. Without REC the end of file is set to 0. The file is closed through SYS0/SYS 4428H.
Option Loop
Register Pair HL = the command line; the option word is on top of the stack, the number of records below it.
Store Register Pair HL (4439H) at 4D34H-4D35H, the operand of the JP Z at 4D33H, so that 4D27H calls the sector write.
Clear the Buffer
Register Pair HL = the buffer byte, Register B counts 256 bytes.
Write Loop
Register Pair BC = the sectors still to write; each write moves NEXT on by one sector. Every granule is already allocated, so these writes do not load another overlay.
5050H - CREATE Option Table (Data)
Read by 4EC9H from 4F9BH. Each entry: the option word with its = sign, 00H, the flag byte (bit 7 ASE, bit 6 ASC) and the address of the handler 4FA3H jumps to.
5071H - CLEAR Command
CLEAR[,START=a][,END=b][,MEM=c]. Every option stores its number straight into the operand it sets (509EH MEM, 50AEH END, 50B5H START). CLEAR then ends every route, empties the queue of named routines (4058H) and the timer chain (4584H), sets HIMEM (4411H) to MEM or to the top of memory found at reset (42C9H), whichever is lower (MEM below 7000H is error 2FH), and fills START (default 5200H, never lower) to the lower of END and HIMEM with 00H.
Option Loop
Register Pair HL = the command line at the next option.
Store Register E (the low byte of the number) at Register Pair HL, the operand at 50B5H (START), 50AEH (END) or 509EH (MEM).
Load Register Pair DE with MEM: the operand 509EH-509FH holds FFFFH in the file and the MEM= value after 5081H stores it.
Load Register Pair DE with END: the operand 50AEH-50AFH holds FFFFH in the file and the END= value after 5081H stores it.
Load Register Pair HL with START: the operand 50B5H-50B6H holds 5200H in the file and the START= value after 5081H stores it. 50B1H comes here.
Fill Loop
Register Pair HL = the byte cleared, Register Pair DE = the last byte to clear.
50CAH - CLEAR Option Table (Data)
Read by 4EC9H from 5076H. Each entry: the option word with its = sign, 00H, a flag byte of 00H and the address of the operand that the option's number is stored in (5081H).
50E5H - LIST and PRINT Commands
LIST,filespec[,start-line[,line-count]] shows a text file on the display; PRINT does the same on the printer. SYS1/SYS has opened the file in the FCB at 4480H and left the command line pointer on the stack below the dispatcher's return address 4BC5H. A line ends with a carriage return (0DH). Bit 7 of each byte is cleared; a byte above option AX (4290H) or below 20H, other than the carriage return, is shown as a period. The keys are looked at after each line and after every 256 characters: the up arrow or the right arrow pauses, then ENTER goes on and the up arrow stops; the up arrow held while a byte is read stops at once. The end of the file ends the listing; another read error is reported.
Store Register A (3BH) at 5182H, the low byte of the operand of the CALL 0033H at 5181H: every character now goes to the ROM printer routine 003BH instead of the display routine 0033H.
Skip Lines
Register Pair BC = the start line; one line is skipped for each count above 1.
Show Loop
Register Pair DE = the lines still to show, Register C = the characters left before the next key check.
Pause
Wait until ENTER or the up arrow is pressed.
513AH - Read a Character of the File
Returns the next byte of the file in Register A, ready to show: bit 7 cleared, and a period for a byte above option AX (4290H) or a control character other than the carriage return. The up arrow, or the end of the file, ends the whole command from here (5169H drops this routine's return address). Another read error leaves through 4EEBH.
516FH - Read a LIST Parameter
Called with the flags of SYS0/SYS 4C7AH. Reads a start line or a line count into Register Pair DE (0 is error 2FH) and returns the flags of 4C7AH for the character after it.
517DH - Output a Character
517DH sends a carriage return, 517FH the character in Register A, to the display through the ROM routine 0033H, or to the printer through 003BH once PRINT has changed the operand at 5182H. Register Pairs AF and DE are kept.
GOSUB to the ROM routine at 0033H, which displays the character in Register A; the operand's low byte at 5182H is 33H in the file and 3BH after PRINT's 50E7H, which sends it to the printer through 003BH instead.
5187H - End of the File
The rest of the last load record.