TRS-80 DOS - VTOS 4.0.2 for the Model I - SYS9/SYS Disassembled
Page Customization
Page Index
SYS9/SYS
Other Navigation
Introduction/Summary
VTOS 4.0.2 SYS9/SYS Disassembly - The Extended DEBUG Commands (Model I)
SYS9/SYS adds commands to the DEBUG monitor of SYS5/SYS. DEBUG (EXT) (SYS6/SYS member 6, 523EH) issues request 8BH; the request handler loads SYS9/SYS at 4E00H (directory entry code 23H) and calls it. It copies its command reader (4E27H-51F3H, 973 bytes) to the top of memory, lowers the top of memory 4049H below it and puts the copy's address at 4310H, where every request below 80H goes. SYS5/SYS hands each key that is not one of its own commands to RST 28H (its 4E97H), so the copy gets the key and runs the extended command, using SYS5/SYS's routines for keys, hex numbers and hex output and its cells for the addresses. The manual: "An extended DEBUG facility may be loaded into high memory by setting the 'EXT' flag."
The file starts with a record of type 05H (the name SYS9), a record of type 1FH holding the copyright notice of Randolph Cook (1980) and four load blocks that fill 4E00H-51F3H, 1012 bytes; the last record gives the transfer address 4E00H, and one byte 03H follows it, which the loader never reads. The file carries no patch. The rows show the command reader at its file addresses; it runs from the copy, and its relative jumps land on the rows of this page. Its calls to 518AH, 51A3H, 51D0H, 51D4H, 51D9H and 51F2H go to SYS5/SYS, which is in memory whenever the copy is entered from DEBUG, not to this file's rows at those addresses.
The Installation
RST 28H with Register A = 40H (4E26H) asks whatever 4310H points at; the copied reader answers 40H with 00H, SYS0/SYS's default 4C2FH returns Register A unchanged. Only when the answer is not 00H is the reader copied (4E07H): the old contents of 4310H go into the operand of JP NZ at 5134H first, so that keys the reader does not know go on to them.
The Commands
Numbers are hex, typed with SYS5/SYS's 51A3H: ended by a space, a comma or ENTER, only the last four digits counting, and a key that is not a hex digit ends the command. Where a field may be left empty, SYS9/SYS shows the value it takes instead.
| Keys | What the Code Does |
|---|---|
| B source,dest,count | Block move with LDIR, low addresses first (defaults: the display address 4063H, the M address 4060H, 0100H) (4E38H). |
| E address | Enter bytes in hex from the address (default the M address); a space or a comma with no digits keeps a byte, ENTER ends (4E84H). |
| F start,end,byte | Fill from the start to the end, the end included; an end of FFFFH never stops (4EB7H). |
| J | The saved program counter 407BH plus 1 (4ED7H). |
| L address,byte | Locate the next byte (defaults: the M address plus 1, the last byte, 4062H); always found, at 4062H when nowhere else (4EE3H). |
| N address | Next block: the address (default the M address) plus the byte after it plus 2, a byte 00H counting 256 (4F2AH). |
| O | O and ENTER: VTOS READY (402DH) (4E2DH). |
| P start,end | Print memory in hex and characters, 16 bytes a line; an end of FFF1H-FFFFH never stops (5132H). |
| Q port or Q port,value | Read a port and show it, or write a value to it (4F4AH). |
| T address | Type characters into memory (4F6EH). |
| V first,second,count | Compare two blocks up to the first difference (4FADH). |
| W address,word | Search for a word, low byte first (defaults: the M address plus 2, the last word in 4062H and 405FH) (5008H). |
| 0-7,cyl,sec,o,addr,count | Move sectors between a drive and memory: R read, W write, an asterisk write with the directory's data mark (505EH). |
Points to Note
SYS9/SYS keeps its values in SYS5/SYS's cells: the M address 4060H-4061H, the display address 4063H-4064H, 4062H (the byte of L, the low byte of W, the sector count) and 405FH (the high byte of W, the sectors of a cylinder). 4062H and 405FH are the saved bytes of SYS5/SYS's breakpoint slots: an entry into DEBUG clears only the slot addresses (405DH-405EH, 4060H-4061H), so these values stay, and a G with breakpoints puts the replaced bytes there, which then become the defaults of L and W.
W leaves the M address on the byte before the word found, the opcode when the word is the operand of a three byte instruction (5052H); the next W starts after the word's low byte.
L and W show the low byte of a typed start, or the start itself, as the value searched for when that value is not typed; the search uses the last value, 4062H and 405FH (4F0EH, 503CH). L never fails: 4062H holds the byte searched for, so CPIR over all 65536 addresses finds it there at worst.
F with a start equal to or above the end stores nothing; otherwise the end is included, since every compare after the first subtracts the carry of the one before (4ECFH). With an end of FFFFH the address wraps to 0000H, still below the end, and F fills all memory, SYS5/SYS and the copy itself included.
N takes the byte after the address as an unsigned length, so on a JR with a jump back it moves forward (4F37H).
P goes on while the next line's address is below the end, so an end that is the first byte of a line is not printed, although the manual says the end is printed (51E4H); an end of FFF1H-FFFFH wraps and never stops, and no key is tested.
In the disk command a failed sector shows its error code between two asterisks and, after any key, the next sector is done (5119H); BREAK does not stop it. R takes the code 06H as a good read, which covers the data marks FAH and F8H. The separators after the drive and the operation take any key, so a digit typed there is lost. An address field left empty takes the last number read; with nothing typed in any field it is the value Register Pair HL held before, Register H being the sectors of a track (for instance 0A4BH): a read there goes into the ROM, a write sends the ROM's bytes to the disk.
The test at 5134H sends every request below 80H that is not one of the reader's codes to the address 4310H held before; the ROM's keyboard routine passes BREAK (01H) this way, so the copy runs outside DEBUG too. Requests with the codes of its commands reach the reader whoever makes them, and its calls into SYS5/SYS are only good while SYS5/SYS is in memory.
Lowering the top of memory once, SYS9/SYS leaves 03CDH bytes in use for good; DEBUG (EXT) again finds the reader there and copies nothing.
Memory Map
Load Areas
| Addresses Size | Contents |
|---|---|
| 4E00H-4E26H 39 bytes | Installation The test through 4310H, the copy to the top of memory, 4310H pointed at it. |
| 4E27H-4E2CH 6 bytes | @ The answer 00H to the test. |
| 4E2DH-4E37H 11 bytes | O VTOS READY after ENTER. |
| 4E38H-4E83H 76 bytes | B Block move. |
| 4E84H-4EB6H 51 bytes | E Enter bytes. |
| 4EB7H-4ED6H 32 bytes | F Fill. |
| 4ED7H-4EE2H 12 bytes | J The program counter plus 1. |
| 4EE3H-4F29H 71 bytes | L Locate a byte. |
| 4F2AH-4F49H 32 bytes | N Next block. |
| 4F4AH-4F6DH 36 bytes | Q Read or write a port. |
| 4F6EH-4FACH 63 bytes | T Type characters. |
| 4FADH-5007H 91 bytes | V Compare two blocks. |
| 5008H-505DH 86 bytes | W Search for a word. |
| 505EH-5131H 212 bytes | 0-7 Sectors to or from a drive. |
| 5132H-51F3H 194 bytes | P Print memory; other keys to the old hook. |
Variables
SYS9/SYS Cells
| Address Size | Contents |
|---|---|
| 5135H-5136H 2 bytes | Old Hook Operand of JP NZ,0000H at 5134H: 0000H in the file; the contents of 4310H before the installation (4E0AH), normally 4C2FH. |
Memory Outside the File
| Address Size | Contents |
|---|---|
| 4049H-404AH 2 bytes | Top of Memory Lowered by 03CDH (4E14H); the copy lies just above the new value. |
| 4310H-4311H 2 bytes | Low Request Hook Read at 4E07H, set to the copy at 4E22H: requests below 80H go to the copy. |
| 405EH 1 byte | SYS5/SYS Screen Mode 53H (S) stored after a sector read (50FEH). |
| 405FH 1 byte | SYS5/SYS Slot 2 Byte The high byte of the word of W (5037H) and the sectors of a cylinder of the disk command (5088H). |
| 4060H-4061H 2 bytes | M Address Default and result of B, E, L, N, T, V, W; the start of the page of the address after a sector read. |
| 4062H 1 byte | SYS5/SYS Slot 1 Byte The byte of L (4F09H), the low byte of W (5033H), the count of sectors (50ABH, 50C6H). |
| 4063H-4064H 2 bytes | Display Address The source of B, the first block of V, the 64 byte block of the M address after L, N, W; the start of the page of the address after a sector read. |
| 407BH-407CH 2 bytes | Saved Program Counter Plus 1 for J (4EDBH). |
Outside Routines
| Address | Contents |
|---|---|
| 518AH | SYS5/SYS: wait for a key and show it, ENTER not shown and other keys below 20H ignored (ENTER: Z and C; space or comma: Z). |
| 51A3H | SYS5/SYS: read a hex number into Register Pair HL (NZ digits typed, C ENTER; a key that is not a hex digit, a space, a comma or ENTER ends the command). |
| 51D0H | SYS5/SYS: show the byte at Register Pair HL in hex, Register Pair HL plus 1. |
| 51D4H | SYS5/SYS: show Register Pair HL as four hex digits. |
| 51D9H | SYS5/SYS: show Register A as two hex digits. |
| 51F2H | SYS5/SYS: show a space. |
| 478FH | SYS0/SYS: Index Register IY = the drive code table of drive Register C. |
| 4763H, 4768H, 4777H | SYS0/SYS: driver functions 0DH (write), 0EH (write with FAH), 09H (read). |
| 0033H, 003BH | ROM: send Register A to the display, to the printer. |
Disassembly
4E00H - Entry: Install the Extended Commands
SYS9/SYS is loaded at 4E00H by the request handler of SYS0/SYS (4C31H) for a request code whose bits 3-0 are BH (directory entry code 23H); DEBUG with EXT (SYS6/SYS member 6, its 523EH) issues 8BH. The code does not look at the request code. It first asks whether the extended commands are already in memory: RST 28H with Register A = 40H (a request below 80H) goes to the routine whose address is at 4310H, and the copied command reader answers 40H with Register A = 00H, while SYS0/SYS's default 4C2FH returns Register A unchanged. When they are not there, the top of memory 4049H is lowered by 03CDH bytes, the command reader 4E27H-51F3H is copied just above the new top, and 4310H is pointed at the copy; the old contents of 4310H are kept as the operand at 5135H, where the copy sends every key it does not know.
4E27H - The Command Reader
Copied to the top of memory by 4E1FH and run there; the rows show it at its file addresses, and its relative jumps land on the rows of this page. SYS5/SYS's command loop sends every key that is not one of its own commands to RST 28H (its 4E97H) with 4E4BH, its command loop, pushed as the return address; for a key below 80H the request handler jumps through 4310H to here with Register A = the key. Each command ends with RET to SYS5/SYS's 4E4BH, which shows the display again. The calls to 518AH (a key), 51A3H (a hex number), 51D0H, 51D4H and 51D9H (hex digits) and 51F2H (a space) are SYS5/SYS's routines, which are in memory at 4E00H whenever the copy is entered from DEBUG. Numbers are hex, ended by a space, a comma or ENTER. Some fields have a default when no digits are typed, which most commands show in its place (V not after ENTER; F, P, Q and the disk command have none).
4E2DH - O: Return to VTOS
O followed by ENTER leaves DEBUG for VTOS READY; any other key after O goes back to the monitor.
4E38H - B: Block Move
B source,destination,count: copies count bytes (default 0100H; 0000H moves 65536) from the source (default the display address 4063H) to the destination (default the M address 4060H) with LDIR, low addresses first; a destination above the source and inside the block repeats its first bytes. The M address is left just past the destination block. ENTER right after the source drops the command.
4E84H - E: Enter Bytes
E address: shows each byte from the address (default the M address 4060H) followed by a minus sign; a hex number typed replaces it (its low byte), a space or comma with no digits keeps it; ENTER ends the command after its byte. The M address follows the byte being changed.
4EB7H - F: Fill
F start,end,byte: stores the byte at every address from the start to the end, the end included; a start equal to or above the end stores nothing, and an end of FFFFH never stops (4ED5H). Each field must be typed: a field with no digits drops the command.
4ED7H - J: Jump Over a Byte
Adds 1 to the saved program counter 407BH: the program will go on one byte further.
4EE3H - L: Locate a Byte
L address,byte: searches memory for the byte (default the last byte searched, at 4062H) from the address (default the M address plus 1, so that L alone finds the next one) through all 65536 addresses; since 4062H holds the byte, it is always found, at 4062H when nowhere else. The M address 4060H is then the byte and the display address 4063H the start of its 64 byte block, the four memory lines of SYS5/SYS's display. When an address is typed and the byte is not, the value shown as the byte is the low byte of the address, while the search uses 4062H.
4F2AH - N: Next Block
N address: takes the byte after the address (default the M address 4060H) as a length and moves the M address past it: the new M address is the address plus the length plus 2, with a length 00H taken as 256. On a record of a load module (type, length) this is the next record. The length is not taken as signed, so on a JR with a jump back it moves forward. The display address goes to the start of the 64 byte block of the new M address.
4F4AH - Q: Query or Set a Port
Q port ENTER: reads the port with IN and shows = and the value, then waits for a key. Q port,value: writes the low byte of the value to the port with OUT. A field with no digits drops the command.
4F6EH - T: Type Text Into Memory
T address: shows each byte from the address (default the M address 4060H) as a character (bit 7 cleared, then a period for codes below 20H) after a space, then a minus sign, and waits for a key: a space keeps the byte, ENTER ends the command, any other key (a comma too) is stored as it is. The M address follows the byte.
4FADH - V: Verify Two Blocks
V first,second,count: compares count bytes (default 0000H, 65536) at the first address (default the display address 4063H) with those at the second (default the M address 4060H), stopping at the first difference. 4063H and 4060H are left at the two bytes that differ, or just past the blocks when they are equal.
5008H - W: Search for a Word
W address,word: searches memory from the address (default the M address plus 2) for the word, low byte first (default the last word searched, kept at 4062H low and 405FH high); after a low byte whose high byte differs, CPIR goes on with the count it has left, so the search can run past 65536 bytes. Found: the M address 4060H is the byte before the word (the opcode when the word is the operand of a CALL, JP or LD) and the display address 4063H the start of its 64 byte block; the default start of the next W, the M address plus 2, is the byte after the word's low byte. When an address is typed and the word is not, the value shown as the word is the address, while the search uses 4062H and 405FH.
505EH - 0-7: Sectors to or From a Disk
d,cylinder,sector,o,address,count: d is the drive 0-7 (the key itself), o the operation: R reads, W writes with the ordinary data mark, an asterisk writes with the directory's data mark FAH; any other key (a space or a comma too) only counts the sectors. The cylinder defaults to the directory cylinder (drive code table +09H). With a sector, count sectors (default 1) are moved from that sector on; with no sector, a whole cylinder from sector 0 (the sectors of a cylinder, doubled for a drive with two sides). Each sector takes the next 256 bytes of memory from the address; after the last sector of a cylinder the next cylinder follows. A failed sector shows its error code between two asterisks and waits for a key, then the next sector is done. After R the display address and the M address are set to the start of the 256 byte page of the address and the full screen display is chosen. The count is kept in 4062H and the sectors of a cylinder in 405FH, SYS5/SYS's cells. ENTER after the drive, the cylinder or the sector drops the command; a key that is not a hex digit in a number field ends it in SYS5/SYS.
5132H - P: Print Memory
P start,end: prints on the printer (ROM 003BH) lines of 16 bytes from the start rounded down to a multiple of 16: four hex digits of the address, two spaces, the 16 bytes in hex with a space after each and one more after the 4th, 8th and 12th, then one more space (two before the characters) and the 16 bytes as characters (a period for codes below 20H and from 80H up). Lines go on while the next line's address is below the end, so an end that is the first byte of a line is not printed. Two carriage returns come first and three after. An end of FFF1H-FFFFH never stops the listing (51E7H). Both fields must be typed. A key that is no command at all goes on at 5134H to the routine 4310H held before SYS9/SYS was put in, normally SYS0/SYS's 4C2FH, which returns to the monitor.
If the NZ FLAG is set (no command of SYS9/SYS), JUMP to the address that 4310H held before (the operand 5135H-5136H, 0000H in the file, stored at 4E0AH).