TRS-80 DOS - NEWDOS/80 v2.0 for the Model I - SYS11/SYS Disassembled
Page Customization
Page Index
SYS11/SYS
Other Navigation
Introduction/Summary
NEWDOS/80 v2.0 SYS11/SYS Disassembly - BASIC RENUM, Second Part (Model I)
SYS11/SYS finishes the BASIC command RENUM, which SYS13 starts. It loads at 4D0CH-51F3H (1,256 bytes in five load records, transfer address 4D0CH), so the twelve bytes 4D00H-4D0BH that SYS13 filled with the RENUM parameters survive the load. SYS13 loads it with RST 28H code 2DH (function 1 of directory slot 0DH, SYS13 51CAH); 51A2H-51F3H are unused zero bytes.
The page shows every byte of the file once, in address order. Calls into BASIC/CMD (5700H up) are linked only where the BASIC page has a row with the right bytes at that address.
How RENUM Works
- SYS13 (50FEH) reads up to four numbers (the first new number, the increment, the first and the last old line of the range; defaults 10, 10, 0 and 65529) and the options U and X, walks the program, writes each renumbered line's new number into the line's link field and counts the lines. A line 0 gives CAN'T PROCESS LINE 0, a new number above 65529 SEQ # OVERFLOW.
- SYS11 builds a table of 128 line addresses at 64CAH (every C-th line) for fast searches (4D0CH) and checks that the new numbers keep the lines in order (5073H).
- First pass (4D28H): every line number referred to after GOTO, GOSUB, THEN, ELSE, RUN, RESUME, ON ... GOTO/GOSUB, ON ERROR GOTO, ERL, LIST, LLIST and after the second comma of GET and PUT is looked up (4EC3H), and the change in the text's length is added up. Problems are listed under ERROR LINES as number/letter: X a number was expected, S a number above 65529 or a line 0, U the line does not exist (with option X only inside the range). With option U, or after any error, RENUM stops here and the program keeps its numbers.
- The program is moved up by its maximum growth plus 256 bytes and the stack is moved to the top of memory (4F97H). The second pass copies the program back down with the new numbers in the text.
- The renumbered lines are moved to where their new numbers belong, in pieces as large as the free memory allows (4FFDH), the new numbers are copied into the line number fields, DONE is shown and the ROM rebuilds the links (1AE9H).
Variables
Locations inside SYS11 whose contents change while it runs:
| Address Range | Purpose |
|---|---|
| 4D4CH-4D4DH 2 bytes | The next line table entry the second pass checks (operand of 4D4BH; set to 64CAH at 4FEAH, moved on at 4D65H). |
| 4DE4H 1 byte | The ON flag: 01H after ON, where a list of line numbers may follow GOTO or GOSUB (operand of 4DE3H; written at 4DA8H). |
| 4DEDH-4DEEH 2 bytes | The old number of the line being scanned, shown in error reports (operand of 4DECH; written at 4D78H). |
| 4E81H 1 byte | 01H when line 0 is allowed (after RESUME or ON ERROR), else 00H (operand of the OR at 4E80H; written at 4DA4H, 4DD1H). |
| 4EF6H-4EF7H 2 bytes | The output address of the line being copied in the second pass; after it, the program's end (operand of 4EF5H; written at 4D34H, 5007H). |
| 4F01H-4F02H 2 bytes | The input address of the line being copied (operand of 4F00H; written at 4D38H). |
| 4FA6H 1 byte | The errors flag: bit 0 set once an error has been reported, so ERROR LINES is printed once and RENUM stops after the first pass (operand of 4FA5H; set at 4F65H). |
| 5014H-5015H 2 bytes | The start of the block of renumbered lines (operand of 5013H; written at 507BH). |
| 5035H-5036H 2 bytes | The place the block goes (operand of 5034H; written at 50CAH). |
| 50C0H-50C1H 2 bytes | The new number of the line after the block (operand of 50BFH; written at 5087H). |
| 50C8H-50C9H 2 bytes | The new number of the line at the place (operand of 50C7H; written at 50AFH). |
| 50F2H-50F3H 2 bytes | The block's length, 0000H if it stays in place (operand of 50F1H; written at 50CDH). |
| 50F7H-50F8H 2 bytes | What is left of the block to move (operand of 50F6H; written at 5117H). |
| 5121H 1 byte | The pass flag: 00H in the first pass, 01H in the second, when 5120H copies every byte it reads (operand of 5120H; written at 4FDBH). |
| 515AH-515BH 2 bytes | The growth total: how many bytes longer the text is so far in this pass (operand of 5159H; cleared at 4D30H, written at 5163H). |
| 515EH-515FH 2 bytes | The number of digits of the number being replaced (operand of 515DH; written at 4E73H). |
| 5168H-5169H 2 bytes | The highest growth total, the room the second pass needs (operand of 5167H; written at 516CH, read at 4FB7H). |
Locations outside SYS11 that it reads or writes:
| Address Range | Purpose |
|---|---|
| 4020H-4021H 2 bytes | The ROM's cursor address in the video memory: its column decides a new line (4F70H), and error numbers are written straight to it (4F7AH-4F81H). |
| 40A4H-40A5H 2 bytes | The ROM's pointer to the first program line. |
| 40B1H-40B2H 2 bytes | The ROM's top of memory pointer: the program moved up must stay 256 bytes below it, and the stack moves there (4FCCH, 50F9H). |
| 40F9H-40FAH 2 bytes | The ROM's pointer to the end of the program (written at 5003H). |
| 4D00H-4D0BH 12 bytes | SYS13's parameters: 4D00H next new number, 4D02H increment, 4D04H first old line, 4D06H last old line, 4D08H last new number given, 4D0AH option U, 4D0BH option X. |
| 5D51H-5D56H 6 bytes | In BASIC/CMD: the digit buffer of BASIC 5D27H, also the target of 5153H when only the digit count is wanted. |
| 64CAH-65C9H 256 bytes | The table of 128 line addresses, in BASIC/CMD's start-up code (no longer needed). |
Disassembly
4D0CH - RENUM, Second Part: the Line Table
SYS13 does the first part of RENUM (SYS13 50FEH): it reads the parameters into 4D00H-4D0BH, checks them, puts each renumbered line's new number into the line's link field (the first two bytes of the line), counts the lines and loads SYS11 with LD A,2DH / RST 28H (SYS13 51CAH). SYS11 loads at 4D0CH, so SYS13's parameter bytes 4D00H-4D0BH stay in memory: 4D00H the next new number, 4D02H the increment, 4D04H-4D07H the first and last old line number of the range, 4D08H the last new number given, 4D0AH option U, 4D0BH option X. The dispatcher enters at 4D0CH (the transfer address) with Register Pair HL = the first program line (40A4H), Register Pair DE = 64CAH, Register B = 80H and Register C = the number of lines per table entry (the line count / 128, rounded up). This part builds a table of 128 line addresses at 64CAH-65C9H (inside BASIC/CMD's start-up code, no longer needed), every C-th line, for the searches at 4EC3H.
TABLE LOOP
Register Pair DE (swapped with HL) = the table entry, Register Pair HL = the line, Register B = the entries left, Register C = the lines per entry.
4D28H - Scan the Program
The main loop, used twice. In the first pass (5121H = 00H) every line number referred to in the text is looked up and the growth of the text is added up (515AH, the highest value in 5168H); errors are listed. In the second pass (5121H = 01H) the program has been moved up in memory (4FABH) and is copied back down byte by byte from Register Pair HL (input) to Register Pair BC (output), with every reference replaced by the new number (5120H copies each byte it reads).
Store Register Pair DE (0000H) at 515AH, the operand of 5159H: the text's growth total starts at 0.
LINE LOOP
Register Pair HL = the input pointer at the line, Register Pair BC = the output pointer.
Store Register Pair BC (this line's output address) at 4EF6H, the operand of 4EF5H.
Store Register Pair HL (this line's input address) at 4F01H, the operand of 4F00H.
Load Register Pair HL with the next table entry to check; the operand 4D4CH (0000H in the file) is set to 64CAH at 4FEAH and moved on at 4D65H.
Store Register Pair HL (the next entry) at 4D4CH, the operand of 4D4BH.
Store Register Pair DE (the old number) at 4DEDH, the operand of 4DECH, for error reports.
SKIP A STRING
Register E = the closing quote.
SKIP DATA
DATA (88H): the bytes up to a colon or the line's end are skipped (copied in the second pass).
Store Register A at 4E81H, the operand of the OR at 4E80H: 00H = line 0 not allowed (01H after RESUME or ON ERROR).
Store Register A at 4DE4H, the operand of 4DE3H: the ON flag (01H after ON, where a list of line numbers may follow GOTO or GOSUB).
STATEMENT LOOP
Each byte is looked up in the token table at 4E8AH; the table's handler deals with the line numbers that may follow.
TABLE SEARCH
Register Pair HL walks the table: handler address, byte value; the table is in ascending order of the byte.
Store Register A (01H) at 4E81H: line 0 is allowed (RESUME 0).
Load Register A with the ON flag; the operand 4DE4H (00H in the file) is stored at 4DA8H.
Load Register Pair DE with the old number of the current line; the operand 4DEDH (0000H in the file) is stored at 4D78H.
SKIP THE STATEMENT
4E40H returns only for bytes inside the statement; at its end it goes on at 4E10H.
FIND THE SECOND COMMA
Register E = the parenthesis level, Register D = the outer commas still to pass.
4E4CH - Replace a Line Number
Reads the decimal number at Register Pair HL (blanks between the digits are allowed, as RST 10H skips them) and looks it up. The number is written again (second pass) as the new line number, or unchanged if the line does not exist. Line 0 is only accepted after RESUME or ON ERROR GOTO. Entered with Register Pair BC = the output pointer; returns with Register Pair HL after the number.
DIGIT LOOP
Register Pair DE = the number so far, Register Pair BC = the digits counted, Register A = the digit character.
Store Register Pair BC (the number of digits) at 515EH, the operand of 515DH, for the growth count.
Line 0: OR Register A (00H) with the flag in the operand 4E81H (00H in the file; 01H after RESUME or ON ERROR, stored at 4DA4H and 4DD1H).
4E8AH - Token Table
Data, not code: three bytes per entry, the handler's address and the byte (token) it handles, in ascending order of the byte. A byte that is not in the table is read past. The FFH entry ends the table.
4EC3H - Find a Line
Looks for the line with the old number in Register Pair DE. A binary search over the 128 table entries finds the last one whose line number is not above DE; from there the lines are walked. Returns Register Pair HL = the line, and Register Pair DE = the contents of its link field (the new number), with the Z FLAG set if the line exists. Otherwise NZ, with HL and DE for the next higher line (DE = 0000H at the end of the program).
BINARY SEARCH
Register Pair HL = the table entry, Register Pair BC = the step (halved each time), Register Pair DE = the number wanted.
LINE WALK
Register Pair HL = the line, Register Pair DE = the number wanted.
Load Register Pair BC with the output address of the line being copied; the operand 4EF6H (0000H in the file) is stored at 4D34H and 5007H.
It is the line being copied, not complete at its output address yet: load Register Pair HL with its input address instead; the operand 4F01H (0000H in the file) is stored at 4D38H.
4F22H - Write the New Number
Register Pair DE = the old number. A reference to a line that does not exist gives error letter U (with option X only if it lies inside the renumbered range); the old number is then written back unchanged.
4F54H - Report an Error
Called from 4DEFH with Register A = the error letter (X, S or U) and Register Pair DE = the line number to show; 4F22H enters at 4F57H with Register Pair AF, the output pointer and the input pointer already on the stack. The first report prints ERROR LINES; each report then shows the number, a slash and the letter. An error in the second pass means the text is already partly rewritten, so it goes to FATAL ERROR at 50E4H instead.
Set bit 0 of the byte at Register Pair HL (4FA6H, the errors flag) so 4FA5H loads 01H and the heading is printed only once.
4F97H - End of the First Pass
4D3FH jumps here when the scan reaches the program's end marker. With option U, or after an error was listed, RENUM stops here: the lines keep their numbers and BASIC rebuilds the links. Otherwise the program is moved up in memory by the text's maximum growth plus 256 bytes, the stack is moved to the top of memory, and the second pass copies the program back down with the new numbers.
Load Register A with the errors flag, the operand 4FA6H (00H in the file, set to 01H at 4F65H when the first error is reported).
Load Register Pair HL with the highest growth total of the text, the operand 5168H (0000H in the file, stored at 516CH): how many bytes longer the text gets at worst while it is rewritten.
Store Register A (01H) at 5121H, the operand of 5120H: from now on 5120H copies every byte it reads to the output.
Store Register Pair HL (64CAH) at 4D4CH, the operand of 4D4BH: the second pass checks the table entries from the first one.
TABLE LOOP
Register Pair HL = the table entry, Register Pair BC = the distance, Register E = the entries left. Every line address in the table is moved by the same distance as the program.
4FFDH - End of the Second Pass
4F9BH jumps here when the second pass reaches the end marker, with Register Pair HL = the marker in the moved copy and Register Pair BC = the output pointer. The text is rewritten. The renumbered lines (the block) are moved to where their new numbers belong, the new numbers are copied from the link fields into the line number fields, DONE is shown and the ROM rebuilds the links.
Store Register Pair BC at 4EF6H, the operand of 4EF5H, so the line searches made by 5073H compare against the program's end rather than a line being copied.
MOVE THE BLOCK TO THE END
Register Pair BC = the piece's length. Each piece is copied to the end of the program and the rest of the program is moved down over it, until the whole block sits at the end.
Load Register Pair HL with the start of the block, the operand 5014H (0000H in the file, stored at 507BH).
INSERT THE BLOCK
Register Pair BC = the piece's length. Each piece is taken from the end of the program and put into a gap opened at the place the block goes.
Load Register Pair DE with the place the block goes, the operand 5035H (0000H in the file, stored at 50CAH).
COPY THE NEW NUMBERS
Register Pair HL = the line, Register Pair DE = its link field (the new number SYS13 put there, or 0000H at the end).
5073H - Where the Block Goes
Called from 4D25H (before the first pass) and 500BH (after the second). Finds the lines of the renumbered range (the block, from the first old number in 4D04H to the last in 4D06H) and the line their new numbers must go before: the first line whose number is not below the block's first new number. If the block's last new number (4D08H) is not below that line's new number, the renumbering would put the lines out of order: error 8CH SEQ # OVERFLOW (FATAL ERROR in the second pass). Stores the block's start (5014H), the place (5035H) and the length (50F2H, 0000H if the block stays where it is).
Store Register Pair HL (the block's first line) at 5014H, the operand of 5013H.
Store Register Pair DE (the new number of the line after the block) at 50C0H, the operand of 50BFH.
FIND THE PLACE
Register Pair HL = the line, Register Pair DE = the block's first new number. The walk stops at the first line whose (old) number is not below it.
Store Register Pair DE (the new number of the line at the place) at 50C8H, the operand of 50C7H.
The block stays where it is: load Register Pair DE with the new number of the line after the block, the operand 50C0H (0000H in the file, stored at 5087H).
Load Register Pair DE with the new number of the line at the place, the operand 50C8H (0000H in the file, stored at 50AFH).
Store Register Pair HL (the place, adjusted for the block's removal when it lies above) at 5035H, the operand of 5034H.
Store Register Pair BC (the block's length, or 0000H) at 50F2H, the operand of 50F1H.
50F1H - The Next Piece to Move
The block is moved through the free memory between the end of the program (40F9H) and 256 bytes below the top of memory (40B1H). 50F1H starts with the block's whole length, 50F6H goes on with what is left. Returns Register Pair BC = the piece to move, with the Z FLAG set if none; less than 256 free bytes is OUT OF MEMORY.
Load Register Pair DE with the block's length, the operand 50F2H (0000H in the file, stored at 50CDH).
Load Register Pair DE with what is left of the block, the operand 50F7H (0000H in the file, stored at 5117H).
Store Register Pair HL (what is left after this piece) at 50F7H, the operand of 50F6H.
511DH - Reading the Text
5120H reads the next byte of the program at Register Pair HL and, in the second pass, also copies it to the output at Register Pair BC. 512EH skips blanks (spaces, 09H and 0AH), copying them in the second pass; 513BH also returns the CARRY FLAG if a digit follows, without reading it.
Load Register A with the pass flag, the operand 5121H (00H in the file for the first pass; set to 01H at 4FDBH for the second).
5147H - Print a Message
Prints the text at Register Pair HL up to its 03H end byte and starts a new line.
5153H - Put Out a Number
Converts Register Pair DE to decimal (BASIC 5D27H, leading zeros dropped) and copies the digits to Register Pair BC; 5153H points Register Pair BC at BASIC's own digit buffer 5D51H, so only the count matters. The difference between the new and the old number of digits is added to the growth total (515AH), whose highest value is kept in 5168H.
Load Register Pair HL with the growth total, the operand 515AH (0000H in the file, cleared at 4D30H at the start of each pass).
Load Register Pair DE with the old number's digit count, the operand 515EH (0000H in the file, stored at 4E73H).
Store Register Pair HL (the growth total) at 515AH, the operand of 5159H.
Load Register Pair DE with the highest growth total so far, the operand 5168H (0000H in the file, read at 4FB7H).
Store Register Pair HL (the new highest growth total) at 5168H, the operand of 5167H.
5170H - Messages
519DH - Compare After Taking the Block Out
Called from 50B8H with Register Pair HL = the place, Register Pair BC = the block's length and Register Pair DE = the block's start.