This is a disassembly of TRSDOS v2.3’s SYS5/SYS file. SYS5/SYS handles DEBUG.
After a DEBUG ON command has been issued and processed by SYS1/SYS, the DEBUG flag is set. Following that, DEBUG will start when one of 3 things happens: [1] A break is pressed, [2] a CMD file is loaded, and [3] a TRAP instruction (RST 30) is reached.
The first thing DEBUG does is copy the two trap addresses, the display address, all the registers, stack pointer, and program counter as they were, so that they can be restored (since Debug will use them). The memory locations are:
- 405D-406E = First Trap Address
- 405F = Original Contents of the Trap Address
- 4060-4061 = Second Trap Address
- 4062 = Original Contents of the Second Address
- 4063-4064 = Display Address
- 4065-4066 = AF
- 4067-4068 = BC
- 4069-406A = DE
- 406B-406C = HL
- 406D-406E = AF’
- 406F-4070 = BC’
- 4071-4072 = DE’
- 4073-4074 = HL’
- 4075-4076 = IX
- 4077-4078 = IY
- 4079-407A = SP
- 407B-407C = PC
4E00 – Entry into SYS5/SYS
First we need to do a lot of pushing registers onto the stack. Why? Because we are running a program within a program, and the program within the program (DEBUG) still needs to be able to display and track the registers from the program that it is running upon!
Next, we have to save all the alternate registers to the stack as well
With all registered put into the stack, now we get down to business.
We are about to enter into a loop to restore the contents of the locations that had a trap
4E3E
OR D
4E4B – Command entry and parsing. This is the return point for almost all command subroutines
4E99 – Process the “X” Command.
The “X” command is “Register Display Mode”. A 128-byte block of memory will be displayed, starting with the next lower address which is an even multiple of 16. The next line on the display starting with PC is a list of the 16 bytes to be found beginning at the address specified by the PC register. The bottom two lines of the display are the Z-80 registers and their contents.
4E9A – Process the “S” Command.
The “S” command is “Memory Display Mode”. Only memory is displayed; no registers. In this mode, the Dxxxx starting address is actually rounded up to the nearest 256-byte page.
This routine is also fallen into by the “X” routine. If “S” was directly called, then Register A actually is stil holding an “S”, so the memory location will either be 0 or”S”.
4E9E – Process the “U” Command.
The “U” command is “Update”. Pressing U will cause the display to be updated continuously. This function will be of use if you have interrupt driven devices attached to your TRS-80, or for looking at the Model III real time clock, address 4040H. Press any key to exit this mode.
4EA8 – Process the “D” Command.
The “D” command is “Display Memory Contents” which will display a block of memory. If the user presses “D” then DEBUG will prompt with “ADDRESS = “. The user would enter the hexadecimal address of the beginning byte of the block of memory the user wishes to see followed by the Space Bar. If a mistake is made, the user should just type in the correct address as DEBUG will look only at the last four characters typed. The display will be either half- or full -screen , depending on the format currently specified by “X” or “S”
4EAE – Process the “;” command.
The “;” command increments the display address. The display address is modified by 16 in half-screen mode and 256 in full-screen mode.
4EC6 – Process the “-” Command.
The “-” command decrements the display address. The display address is modified by 16 in half-screen mode and 256 in full-screen mode.
4ECB – Process the “A” and “H” Command.
“A” and “H” affect the display mode. A will display in ASCII, H in Hex.
4ECF – SUBROUTINE to display the register values.
4EE5 – Display the register values plus the contents of the addresses they contain.
4F45 – This is the routine for a long display.
4F54 – Message Storage Area
4F80 – This routine processes a user instruction of “G” (GO)
The “G” command resumes running the program, either at a user specified address or wherever the PC was left off. Up to 2 trap addresses can also be specified; and those are put into a table. This neccesitates putting all the registers back.
At this point, we have gotten all the addresses we are going to get (either 1 with no comma, or 2)
At this point, we have gotten all the addresses we are going to get (either 1 with no comma, or 2), so next we must transfer the register calues from the Debug Register Storage Area to the stack.
The registers from the Debug Register Storage Area have all been put into the stack, so now we need to restore the values to the actual registers
4FCA – This SUBROUTINE is called because we have a valid address input to update the trap table address
4FDB – Process the “M” Command.
The “M” command modifies a memory location. Left and Right graphic bars are placed around the memory location being modified.
5011 – Process the “R” Command.
The “R” command modifies a register. Up to 3 characters are permitted to designate the register.
This is jumped to if we have matched the first character entered by the user against the first character of an entry in the Register Pair Table
If we are here, then all 3 characters entered by the user match a three character entry in the Register Pair Table.
5044
SUB A,B
505D – Process the “I” and “C” Commands.
The “I” and “C” commands single step through the program. “C” will run subroutines without requiring they be stepped through and “I” will step every single instruction. This is accomplished by replacing the next instruction with a trap and then executing “G”, so a lot of storing what is coming up and the putting it back happens.
But knowing how long the instruction to replace is is not very easy, and if the instruction was a jump, then the jump point actually needs to be replaced by the trap instead of the next instruction (since the “next” instruction isn’t the one going to be executed)! To figure all this out, there are 3 tables and 6 types which are pre-set to handle everything that can be thrown at DEBUG.
We are about to start a loop. HL will have been set along the way to point to one of 3 instruction tables: 5063 would have set it to Group 3 if it was in the IX or IY Instruction Set, 506E would have set it to Group 1 if it was in the Misc Instruction Set, and 5075 would have set it to Group 2 otherwise.
At this point, we have stopped checking the list, either because we found something or ran out of list to check.
50B7 – These routines are the various jump points from the above “C”/”I” routine OPCODE tests. In many cases, they build on each other.
If we are here, then the “C”/”I” routine felt that the opcode was a RET instruction. It is going to bleed down into the JP XXXX code, as it is the same, so long as the address is set. So it sets the address and then bleeds down.
If we are here, then the “C”/”I” routine felt that the opcode was a RET or a JP XXXX instruction.
If we are here, then the “C”/”I” routine felt that the opcode was a DJNZ or JR instruction.
If we are here, then the “C”/”I” routine felt that the opcode was a JP (IX/IY) instruction.
50D8 is the common jump point from all the above. Each routine above loaded HL with a specific address and then us it here.
50E0 – This set, and the two sets which follow, are referred to as INSTRUCTION LISTS. This is Group 1.
Each Instruction List entry consists of 3 bytes: Mask, Opcode, and Type/Length.
The Type is a code from 0-6 indicating where the address of the instruction might be found since that can vary greatly (think JP (HL) vs JP xxxx vs JP C, XXXX, etc).
- Type 0 – The next instruction follows the current instruction
- Type 1 – The next instruction address comes from HL. An example would be JP (HL)
- Type 2 – The next instruction conditionally comes from the operand. An example would be JP C, xxxx
- Type 3 – The jump is conditional. An example would be DJNZ xxxx
- Type 4 – The operand is provided. An example would be JP xxxx
- Type 5 – Conditional and indirect. An example would be RET or RET C
- Type 6 – Conditional and operand supplied. An example would be CALL NZ, xxxx or CALL xxxx
510E – This is INSTRUCTION LISTS group 2.
5115 – This is INSTRUCTION LISTS group 3.
5131 – Display => and then the contents of the address in the register
5165 – Display bars around the address being modified. On entry, HL points to the current display address.
5177
OR H
5180H is called for purposes of displaying the LEFT graphic bracket. The right graphic bracket is a hard jump to ROM.
518A – Get a character from the keyboard.
If we are here then the above routine found a carriage return.
51A3 – This routine is called when DEBUG wants get an address from the user. Will return Z set if there is an error. Result stored in HL.
51B1
51B2
51B3
ADD HL,HL
ADD HL,HL
ADD HL,HL
51BF – This SUBROUTINE is called only from 51AAH to test a character to make sure only A-F and 0-9 are present. CARRY FLAG is set if it is outside that range. Since that is how this routine is going to report an error, all of the value tests are set up so as to trigger or not trigger the CARRY FLAG.
51D0 – This SUBROUTINE displays the hex for the value POINTED TO by the HL register
51D4 – This SUBROUTINE displays the hex for the value HELD in the HL register
51D9H is the common jump point for both 51D0H and 51D4 once A contains the value to be dealt with.
51DB
51DC
51DD
RRA
RRA
RRA
51F2H, while part of the prior routine, is also a common call to display a blank.