CP/M SYMBOLIC INSTRUCTION DEBUGGER USER'S GUIDE {NB This is an old SID - for CP/M Version 1.3. However I doubt much changed in later SID's. } DIGITAL RESEARCH S I D Symbolic Instruction Debugger USER'S GUIDE Copyright (c) 1978 and 1981 Digital Research P.O. Box 579 801 Lighthouse Avenue Pacific Grove, CA 93950 (408) 649-3896 TWX 910 360 5001 All Rights Reserved COPYRIGHT Copyright (c) 1978 and 1981 by Digital Research. All rights reserved. No Part of this publication may be reproduced, transmitted, transcribed, stored in a retrieval system, or translated into any language or computer language, in any form or by any means, electronic, mechanical, magnetic, optical, chemical, manual or otherwise, without the prior written permission of Digital Research, Post Office Box 579, Pacific Grove, California, 93950. DISCLAIMER Digital Research makes no representations or warranties with resr)ect to the contents hereof and specifically disclaims any implied warranties of merchantability or fitness for any particular purpose. Further, Digital Research reserves the right to revise this r)ublication and to make changes from time to time in the content hereof without obligation of Digital Research to notify any person of such revision or changes. TRADEMARKS CP/M is a registered trademark of Digital Research. SID and MAC are trademarks of Digital Research. The SID USER'S GUIDE was Prepared using the Digital Research TEX Text Formatter. ********************************** * Third Printing: Januarv 1981 * ********************************** TABLE OF CONTENTS SECTION PAGE 1. SID OPERATION UNDER CPM 1 1.1. SID Startup 1 1.2. SID Command Input 5 2. SID SYMBOLIC EXPRESSIONS 8 2.1. Literal Hexadecimal Numbers 8 2.2. Literal Decimal Numbers 8 2.3. Literal Character Values 9 2.4. Symbolic References 9 2.5. Qualified Symbols 10 2.6. Symbolic Operators 11 2.7. Sample Symbolic Expressions 12 3. SID COMMANDS 14 3.1. The Assemble (A) Command 14 3.2. The Call (C) Command 15 3.3. The Display Memory (D) Command 16 3.4. The Fill Memory (F) Command 18 3.5. The Go (G) Command 19 3.6. The Hexadecimal Value (H) Command 21 3.7 The Input Line (I) Command 22 3.8. The List Code (L) Command 25 3.9. The Move Memory (M) Command 27 3.10. The Pass Counter (P) Command 27 3.11. The Read Code/Symbols (R) Command 30 3.12. The Set Memory (S) Command 34 3.13. The Trace Mode (T) Command 36 3.14. The Untrace Mode (U) Command 38 3.15. The Examine CPU State (X) Command 39 4. SID UTILITIES 42 4.1. Utility Operation 42 4.2. The HIST Utility 43 4.3. The TRACE Utility 45 5. SID SAMPLE DEBUGGING SESSIONS 50 1. SID OPERATION UNDER CP/M The CP/M symbolic debugger, called SID, expands upon the features of the CP/M standard debugger described in the manual "CP/M Dynamic Debugging Tool (DDT) User's Guide" and provides greatly enhanced facilities for assembly level program checkout. Specifically, SID includes real-time breakpoints, fully monitored execution, symbolic disassembly, assembly, and memory display and fill functions. Further, SID operates with 'utilities" which can be dynamically loaded with SID to provide traceback and histogram facilities. The various functions of SID are given in the sections which follow. 1.1. SID Startup. The SID program is initiated by typing one of the following commands: (a) SID (b) SID x.y (c) SID X.HEX (d) SID X.UTL (e) SID x.y u.v (f) SID * u.v In each case, SID loads into the topmost portion of the Transient Procram Area (TPA) and overlays the Console Command Processor portion of CP/M (see the "CP/M Interface Guide" and "CP/M Alteration Guide" for a discussion of memory use conventions). Memory organization before SID is loaded is shown in Figure 1, while Figure 2 shows the memory configuration after SID is loaded and relocated. Due to the relocation process, SID is independent of the exact memory size which CP/M manages in a particular computer configuration. ---------------- (High Memory) | | | BDOS | | | ---------------- | | | CCP | ---------------- | | | | | TPA | | | ---------------- (Low Memory) | JMP BDOS | ---------------- Figure 1. Memory Configuration Before SID Loads. 1 SID Users Guide Section 1 ---------------- | | | BDOS | | | ---------------- | | | SID | | | | JMP BDOS | ---------------- | | | TPA | | | ---------------- | JMP SID 1 | ---------------- Figure 2. Memory Configuration After SID Loads. After loading and relocating, SID alters the BDOS entry address to reflect the reduced memory size, as shown in Figure 2, and frees the lower portion of the TPA for use by the program under test. Note that although SID occupies only 6K of upper memory when operating, the self-relocation process necessitates a minimum 20K CP/M system for initial setup, leaving about 10K for the test program. Command form (a) above loads and executes SID without loading a test program into the TPA. This form is often used when the operator wishes to examine memory or write and test simple programs using the built-in assembly features of SID. Form (b) above is similar to (a) except that the program given by x.y is automatically loaded for subsequent test. Note that although x.y is loaded into the TPA, it is not executed until SID r)asses program control to the program under test using one of the commands C (Call), G (Go), T (Trace), or U (Untrace). It is the programmer's responsibility to ensure there is enough space in the TPA to hold the test program as well as the de6ugger. If the program x.y does not exist on the diskette or cannot be loaded, the standard "?' error response is issued by SID. If no load error occurs, the SID response is: NEXT PC END nnnn pppp eeee where nnnn, pppp, and eeee are hexadecimal values which indicate the next free address following the loaded program, the initial value of the program counter, and the logical end of the TPA, respectively. Thus, nnnn is normally the beginning of the data area of the Drogram under test, pppp is the starting program counter (set to the beginning of the TPA), and eeee is the last memory location available to the test program, as shown in Figure 3. Although x.y usually 2 SID Users Guide Section 1 contains machine code, the operator can name an ASCII file, in which case these program addresses are less meaningful. ---------------- | | | BDOS | | | ---------------- | SID | ---------------- eeee: |(Free SDace) | | | nnnn: | | ---------------- | | | (Test | pppp: | program) | ---------------- | JMP SID | ---------------- Figure 3. memory Configuration After Test Program Load. Command form (c) is similar to form (b) except that the test program is assumed to be in Intel 'hex" format, as directly produced by ASM or MAC. In this case, the initial program counter is obtained from the last record of the hex file unless this value is zero, in which case the program counter is set to the beginning of the TPA. As discussed in the ASM and MAC manuals, the program counter value can be given on the 'END' statement in the source program. Again, it is the programmer's responsibility to ensure that the hex records do not overlay portions of the SID debuqger or CP/M Operating System. If the hex file does not exist, or if errors occur in the hex format, the "?" response is issued by SID. Otherwise, the principal program locations shown in the previous paragraph are listed at the console. Command form (d) is used when a SID utility function is to be included. In this case, SID is first loaded and relocated as above. The utility function is then loaded into the TPA. Utility functions are also self-relocating and immediately move to the top of the TPA, placing themselves directly below the SID program. The BDOS entry address is changed to reflect the reduced TPA, as shown in Figure 4. Generally, the utility program.prints sign-on information and may or may not prompt for input from the console. Exact details of utility or)eration are given in the section entitled "SID Utilities." 3 SID Users Guide Section 1 ---------------- | BDOS | ---------------- | SID | ---------------- | UTL | | JMP BDOS | ---------------- | | | TPA | | | ---------------- | JMP UTL | ---------------- Figure 4. Memory Configuration Following Utility Load. Command form (e) is similar to (c), except that the symbol table given by u.v is loaded with the program x.y. Symbol information is loaded from the base of SID downward toward the program under test, as shown in Figure 5. ---------------- | BDOS | ---------------- | SID | ---------------- | (UTL If | | Present) | ---------------- | | | SYMBOLS | | | | JMP BDOS | ---------------- | Free Space | ---------------- | | | Test Program | | | ---------------- | JMP SYMBOLS | ---------------- Figure 5. Memory Configuration Following Symbol Load. The symbol table is in the format produced by the CP/M Macro Assembler. In particular, the symbol table must be a sequence of address and symbol name pairs, where the address consists of four hexadecimal digits, separated by a space from the symbol which takes on this address value. The symbol consists of up to 16 graphic ASCII characters terminated by one or more tabs (ctl-I) or a carriage return line feed sequence. Note that the operator can optionally create or alter a symbol table using the CP/M editor, as 4 SID Users Guide Section 1 long as this format is followed (see the manual "ED: the CP/M Context Editor" for editing details). The response following program load will be as shown in command form (b) above, giving essential program locations. When SID begins symbol load, the message: SYMBOLS is printed indicating that any subsequent error is due to the symbol load process. In particular, the "?" error following the SYMBOLS response is due to a non-existent or incorrectly formatted symbol file. Examples of typical commands which start the SID program are shown below. COMMAND FORM COMMAND EXAMPLE (a) SID (b) SID DUMP.COM (b) SID DUMP.ASM (c) SID SAMPLE.HEX (c) SID DUMP.HEX (d) SID TRACE.UTL (a) SID HIST.UTL (e) SID DUMP.COM DUMP.SYM (e) SID DUMP.HEX DUMP.SYM (e) SID TEST.COM TEST.ZOT (f) SID * DUMP.SYM 1.2. SID Command Input. Command input to SID consists of a series of "command lines" which direct the actions of the SID program. These commands allow display of memory and CPU registers, and direct the execution and breakpoint operations during test program debugging. SID prompts the console for input by typing "#" when ready to accept the next command. Each command is based upon a single letter, followed by optional parameters, and terminated by a carriage return. Note that all standard line editing features of CP/M are available, with a maximum of 64 command command characters. The CP/M line editing functions are: 5 SID Users Guide Section 1 ctl-C CP/M system reboot, return to CCP ctl-E Physical end-of-line ctl-P Print console output (on/off toggle) ctl-R Retype current inidut line ctl-S Stop/start console outidut ctl~U Delete current input line cti-x (Same as ctl-U) ctl-Z End of console inout (not used in SID) rubout Delete and echo last character where the "ctl" function indicates that the control key is held down while the particular function key is depressed. Note further that the ctl-R, ctl-U, and ctl-X keys cause CP/M to type a "#" at the end of the line to indicate that the line is being discarded. Various SID commands produce long typeouts at the console (see the "D" command which displays memory, for example). In this case, the operator can abort the typeout before it completes by typing any key at the console (a "return" suffices). The single letter commands which direct the actions of SID are typed at the beginning of the command line. The valid commands are summarized below (lower case command letters are translated to upper case automatically): A Assemble directly to memory C Call to memory location from SID D Display memory in hex and ASCII F Fill memory with constant value G Go to test program for execution H Hexadecimal arithmetic I InDut CCP command line L List 8080 mnemonic instructions M Move memory block p Pass point set, reset, and display R Read test program and symbol table S Set memory to data values T Trace test program execution U Untrace (monitor) test program X Examine state of CPU registers Although the details of each of the commands are given in later sections, nearly all of the commands accept parameters following the letter which governs the command actions. The parameters may be counters or memory addresses, and may appear in both literal and symbolic form, but eventually reduce to values in the range 0-65535 (four hexadecimal digits). As an examole, the "display memory' command can take the form Dssss,eeee 6 SID Users Guide Section 1 where D is the command letter, and ssss and eeee are "command parameters" which give the starting and ending addresses for the display, respectively. In their simplest form, ssss and eeee can be literal hexadecimal values, such as D100,300 which instructs SID to print the hexadecimal and ASCII values contained in memory locations 0100 through 0300. Although the operator can usually refer to program listings to obtain absolute machine addresses, SID supports more comprehensive mechanisms for quick access to machine addresses through orogram symbols. In particular, the command parameters can consist of "symbolic expressions" which are described fully in the following section. 7 2. SID SYMBOLIC EXPRESSIONS An important facility of SID is the ability to reference absolute machine addresses through symbolic expressions. Symbolic expressions may involve names obtained from the program under test which are included in the "SYM" file produced by the CP/M Macro Assembler, or may consist of literal values in hexadecimal, decimal, or ASCII character string form. These values can then be combined with various ooerators to provide access to subscripted and indirectly addressed data or program areas. The purpose of this section is to completely describe symbolic expressions so that they may be incorporated as command parameters in the individual command forms which follow this section. 2.1. Literal Hexadecimal Numbers. SID normally accepts and displays values in the hexadecimal number base to form 16-bit values from up to four hexadecimal digits. The valid hexadecimal digits consist of the decimal digits 0 through 9 along with the hexadecimal digits A, B, C, D, E, and F, corresponding to the decimal values 10 through 15, respectively. Note that SID translates lower case hexadecimal digits to upper case outside of string apostrophes. A literal hexadecimal number in SID consists of one or more contiguous hexadecimal digits. If four digits are typed then the leftmost digit is most significant, while the rightmost digit is least significant. If the number contains more than four digits, the rightmost four are taken as significant, and the remaining leftmost digits are discarded. The values to the left below produce the hexadecimal and decimal values shown following the "#" to the right below. INPUT VALUE HEXADECIMAL DECIMAL 1 0001 #1 100 0100 #256 fffe FFFE #65534 10000 0000 #0 38001 8001 #32769 2.2. Literal Decimal Numbers. Although SID's normal number base is hexadecimal, the operator can override this base on input by preceding the number by a "#" symbol which indicates that the following number is in the decimal base. In this case, the number which follows must consist of one or more decimal digits (0 through 9) with the most significant digit on the left and the least significant digit on the right. Decimal values are padded or truncated according to the rules of hexadecimal numbers, as described above, by converting the decimal number to the equivalent hexadecimal value. 8 SID Users Guide Section 2 The input values shown to the left below produce the internal hexadecimal values shown to the right below: INPUT VALUE HEXADECIMAL VALUE #9 0009 #10 OOOA #256 0100 #65535 FFFF #65545 0009 2.3. Literal Character Values. As an operator convenience, SID also accepts one or more graphic ASCII characters enclosed in string apostrophes (') as literal values in expressions. Characters remain as typed within the paired apostrophes (i.e., no case translation occurs) with the leftmost character treated as the most significant, and the rightmost character treated as least significant. Each character is translated internally to its two hexadecimal digit ASCII encoded form. Similar to hexadecimal numbers, character strings of length one are padded on the left with zero, while strings of length greater than two are truncated to the rightmost two characters, discarding the leftmost remaining characters. Note that the enclosing apostrophes are not included in the character string, nor are they included in the character count, with one exception. In order to include the possibility of writing strings which include apostrophes, a pair of contiguous apostrophes are reduced to a single apostrophe and included in the string as a normal graphic character. The strings shown to the left below produce the hexadecimal values shown to the right below. (For these examples, note that upper case ASCII alphabetics begin at the encoded hexadecimal value 41, lower case alphabetics begin at 61, a space is hexadecimal 20, and an apostrophe is encoded as hexadecimal 60). INPUT STRING HEXADECIMAL VALUE 'A' 0041 'AB' 4142 'ABC' 4243 'aA' 6141 '''' 0060 '''''' 6060 ' A' 2041 'A ' 4120 2.4. Symbolic References. Given that a symbol table is present during a SID debugging session, the operator may reference values 9 SID Users Guide Section 2 associated with symbols through three forms of a symbol reference: (a) .s (b) @s (c) =S where s represents a sequence of one to sixteen characters which match a symbol in the table. Form (a) produces the address value (i.e., the value associated with the symbol in the table) corresponding to the symbol s. Form (b) produces the double precision 16-bit "word" value contained in the two memory locations given by .s, while form (c) results in the single precision 8-bit 'byte" value at s in memory. Suppose, for example, that the input symbol table contains two symbols, and appears as: 0100 GAMMA 0102 DELTA Further, suppose that memory starting at 0100 contains the following byte data values: 0100: 02, 0101: 3E, 0102: 4D, 0103: 22 Based upon this symbol table and these memory values, the symbol references shown to the left below produce the hexadecimal values shown to the right below. Recall that 16-bit 8080 memory values are stored with the least significant byte first, and thus the word values at 0100 and 0102 are 3E02 and 224D, respectively. SYMBOL REFERENCE HEXADECIMAL VALUE .GAMMA 0100 .DELTA 0102 @GAMMA 3E02 @DELTA 2240 =GAMMA 0002 =DELTA 0040 2.5. Qualified Symbols. It should be noted that duplicate symbols can occur in the symbol table due to separately assembled or compiled modules which independently use the same name for differing subroutines or data areas. Further, block structured languages, such as PL/M, allow nested name definitions which are identical, but non-conflicting. Thus, SID allows reference to "qualified symbols" which take the form Sl/S2/ . . . /Sn where Sl through Sn represent symbols which are present in the table during a oarticular session. SID always searches the symbol table from the first to 10 SID Users Guide Section 2 last symbol, in the order the symbols appear in the input file. In the case of a qualified symbol, SID begins by matching the first Sl symbol, then scans for a match with symbol S2, continuing until symbol Sn is matched. If this search and match procedure is not successful, SID prints the "?" response to the console. Suppose, for examr)le, that the symbol table appears as 0100 A 0300 B 0200 A 3E00 C 20F0 A 0102 A in the input file, with memory initialized as shown in the previous section. The unqualified and qualified symbol references shown to the left below produce the hexadecimal values shown to the right below. SYMBOL REFERENCE HEXADECIMAL VALUE .A 0100 @A 3E02 .A/A 0200 .C/A/A 0102 =C/A/A 0040 @B/A/A 20F0 2.6. Symbolic Operators. Literal numbers, strings, and symbol references can be combined into symbolic expressions using unary and binary #C + 01 and " - " delimiters. The entire sequence of numbers, symbols, and operators must be written without imbedded blanks. Further, the sequence is evaluated from left-to-right, producing a four digit hexadecimal value at each step in the evaluation. Overflow and underflow are both ignored as the evaluation proceeds. The final value becomes the command parameter, whose interpretation depends upon the particular command letter which precedes it. When placed between two operands, the "+" indicates addition of the previously accumulated value. The value of the following literal or symbolic value is added, and becomes the new accumulated value to this point in the evaluation. If the expression begins with a unary "+" then the immediately preceding (completed) symbolic expression is taken as the initial accumulated value (zero is assumed at SID startup). For example, the command: DFEOO+#128,+5 contains the first expression "FEOO+#128" which adds FEOO and (decimal) 128 to produce FE80 as the starting value for this display command. The second expression +5 begins with a unary "+" which indicates that the previous expression value (FE80) is to be used as the base for this symbolic expression, producing the value FE85 for the end of the display operation. Thus, the command given above is equivalent to: 11 SID Users Guide Section 2 DFE8O,FE85 The "-" symbol causes SID to subtract the literal number or symbol reference from the 16-bit value accumulated thusfar in the symbolic expression. If the expression begins with a minus sign, then the initial accumulated value is taken as zero. That is, -X is computed as 0-x where x is any valid symbolic expression. The command: DFFOO-200,-#512 for example, is equivalent to the simple command DFDOO,FEOO A special up-arrow operator, denoted by "^" is present in SID to denote the top-of-stack in the program under test. In general, a secuence of n up-arrow operators extracts the nth stacked item in the test program, but does not change the test program stack content or stack pointer. This particular operator is used most often in conjunction with the G (Go) command to set a breakpoint at a return from a subroutine during test, and is described fully under the G command. 2.7. Sample Symbolic Expressions. The formulation of SID symbolic expressions is most often closely related to the program structures in the program under test. Suppose we wish to debug a sorting program which contains the data items listed below:_ LIST: names the base of a table of byte values to sort, assuming there are no more than, 255 elements, denoted by LIST(O), LIST(1), ... , LIST(255). N: is a byte variable which gives the actual number of items in LIST, where the value of N is less than 256. The items to sort are stored in LIST(O) through LIST(N-1). I: is the byte subscript which indicates the next item to compare in the sorting process. That is, LIST(I) is the next item to place in sequence, where I is in the range 0 through N-1. Given these data areas, the command D.LIST,+255 for example, displays the entire area reserved for sorting: LIST(O), LIST(1), LIST(255) 12 SID Users Guide Section 2 The command D.LIST,+=I displays the LIST vector up to and including the next item to sort: LIST (0) , LIST (1) LIST (I) The command: D.LIST+=I,+0 displays only LIST(I). Finally, the command: D.LIST,+=N-1 displays only the area of LIST which holds active items to sort: LIST (0) , LIST (1) LIST (N-1) The exact manner in which symbolic expressions are used within SID is dependent upon the individual command which is issued by the operator These commands are listed in some detail in the section which follows. 13 3. SID COMMANDS. SID commands are entered at the console following the prompt, and direct the debugging process by allowing alteration and display of machine functions as well as controlling execution of the program under test. The commands which SID accepts are listed and described in alohabetical order in the sections which follow. 3.1. The Assemble (A) Command. The A command allows the operator to insert 8080 machine code and operands into the current memory image using standard intel mnemonics, along with symbolic references to operands. The command forms are: (a) As (b) A (c) -A where s represents any valid symbolic expression. Form (a) begins inline assembly at the address given by s, where each successive address is displayed until a null line (i.e., a single carriage return) is typed by the operator. Form (b) is equivalent to (a), except the starting address for the assembly is taken from the last assembled, listed, or traced address (see the "L", "T", and "U" commands). The following command sequence, for example, assembles a short program into the transient program area (note that each command line is terminated by a carriage return): A100 begin assembly at 0100 0100 MVI A,10 load A with hex 10 0102 DCR A decrement A register 0103 JNZ 100 loop until zero 0106 RST 7 return to debugger 0107 single carriage return As each successive address is Promoted, the operator may either enter a mnemonic instruction, or return to SID command mode by entering a single carriage return (a single "." is also accepted to terminate inline assembly to be consistent with the "S" command). Delimiter characters which are acceptable between mnemonic and operand fields include space or tab sequences. Invalid mnemonics or ill-formed operand fields produce "?" errors. In this case, control returns back to command mode, where the operator can proceed with another command line, or simply return to assembly mode by tyoing a single "A" since the assumed starting address is automatically taken from the last assembled address. 14 SID Users Guide Section 3 The assembler/disassembler portion of SID is a separate module, and can be removed to increase the available debugging space. Thus, form (c) is entered to remove the module, returning approximately 1 1/2 K bytes. Since the entire SID debugger requires approximately 6 K bytes, this reduces SID requirements to about 4 1/2 K bytes. When the assembler/disassembler module is removed in this manner, the A and L commands are effectively removed. Further, the trace and untrace functions display only the hexadecimal codes, and the traceback utility displays only hexadecimal addresses. Any existing symbol information is also discarded at this point, although such information can be reloaded (see the "I" and "R" commands). Examples of valid assemble commands are shown below: A100 A#100 A.CRLF+5 A@GAMMA+@X-=I A+30 Given that the command A100 has been entered, the following interaction could take place between SID and the operator: SID PROMPT OPERATOR INPUT 0100 MVI C,.A-.B 0102 LXI H,.SOURCE 0105 LXI D,+100 0108 MOV A,M 0109 INX H 010A STAX D 010B INX D 010C DCR C 010D JNZ 108 0110 ("return" only) where A, B, and SOURCE are symbols which are active in the symbol table. In this case, SID computes the address difference between A and B as the operand for the MVI instruction. The LXI H Operand becomes the address of SOURCE, while the LXI D instruction receives the operand value .SOURCE+100 since .SOURCE was the immediately proceeding symbolic expression value. This particular program segment would mo@e a block of memory determined by the address values of the corresponding symbols. 3.2. The Call (C) Command. The C command performs a call to an absolute location in memory, without disturbing the register state of the program under test. The forms are: 15 SID Users Guide Section 3 (a) Cs (b) Cs,b (c) Cs,b,d Although the C command is designed for use with SID utilities, it can be used to perform calls on test program subroutines to perform program initialization, or to make CP/M BDOS calls which initialize various system parameters before executing the test program. Form (a) above performs a call on absolute location s, where s is a symbolic expression. In this case, registers BC = 0000 and DE = 0000 in the call. Normal exit from the subroutine is through execution of a RET instruction which returns control to SID, followed by a normal system prompt. Form (b) above is equivalent to (a), except that the BC register pair is set to the value of expression b, while DE is set to 0000. Form (c) is similar to (b): the BC register pair is set to the value b while the DE pair is set to the value of d. Several examples of valid C commands are shown below. Refer also to the SID utility discussion for examples of the C command in utility initialization, data collection, and display functions. C100 C#4096 C.DISPLAY C@JMPVEC+=X C.CRLF,#34 C.CRLF,@X,+=X 3.3. The Display Memory (D) Command. The D command is used to display selected segments of memory in both byte (8-bit) and word (16-bit) formats. The display appears in both byte and ASCII form in the output. The forms of the D command are: (a) Ds (b) Ds,f (c) D (d) D,f (e) DWs (f) DWs,f (g) DW (h) DW,f Forms (a) through (d) display memory in byte format, while forms (e) through (h) display memory in word format. The byte format display appears as: aaaa bb bb bb . . . bb cc . . . cc 16 SID Users Guide Section 3 where aaaa is the base address of the display line and the sequence of (up to) 16 bb oairs represents the hexadecimal representation of the data stored starting at address aaaa. The sequence of c's represent the same data area displayed in ASCII format, where possible. A period (.) is displayed as a place holder when the data item does not correspond to a graphic character. Byte mode displays are "normalized" to address boundaries which are a multiple of 16. That is, if the starting address aaaa is not a multiple of 16, then the display line is printed to the next boundary address which is a multiple of 16. Each display line which follows contains 16 data elements until the last display line is encountered. Command forms (e) through (h) display in word mode which is similar to the byte mode display described above, except that the data elements are printed in a double byte format: aaaa wwww wwww . . . wwww cc . . . cc where aaaa is the starting address for the display line and the sequence of (up to 8) wwww's represent the data items which are stored in memory beginning at aaaa. Similar to the byte mode display, the sequence of c's represent the decoded ASCII characters starting at address aaaa. As in the byte mode display, a period is displayed as a place holder when the character in that position is non-graphic. Contrary to the byte mode display, address normalization to modulo 16 address boundaries does not occur in the word mode display. Recall that 8080 double words are stored with the least significant byte first, and thus the word mode display reverses each byte pair so that the individual data items are displayed as four digit hexadecimal numbers with the most significant digits in the high order positions. Command form (a) displays memory in byte format starting at location s for 1/2 of a standard CRT screen (12 lines). This form of the command is useful when the operator wishes to view a segment of memory beginning at a particular Dosition, with an indefinite ending address. Command form (b) is similar to (a), but soecifies a particular ending address. In this case, the start address is taken as s with the display continuing through address f. Recall that excessively long typeouts can be aborted by depressing any keyboard character, such as a return. Form (c) is similar to (a) and (b), exceot the starting address for the display is taken from the last displayed address, or from the value of the memory address registers (HL) in the case that no previous display has occurred since the last breakpoint. It is often convenient, for example, to use form (a) to display a segment of memory, followed by a 17 SID Users Guide Section 3 sequence of D commands of form (c) to continue the display. Each D command displays another 1/2 screen of memory. Command form (d) is similar to (b) exceot the starting address is taken automatically as described in form (c) above. Assume, for example, that decimal values 1 through 256 are stored in memory starting at hexadecimal address 0100. The command: D100,12A will produce the expanded form of the display shown below: 0100 01 02 03 04 (etc.) OE OF 10 .. (etc.) .. 0110 11 12 13 14 (etc.) 1E 1F 20 .. (etc.) . 0120 21 22 23 24 (etc.) 29 2A 2B !"#$%&'()*+ Command forms (e) through (h) parallel the byte display formats given by (a) through (h) , except that the display is given in word format. Form (e) displays in word format from location s for 1/2 screen, while form (f) displays from location s through location f. Form (g) displays from the last display location, or from HL if there has been an immediately preceding breakpoint with no intervening display. Form (h) is similar to (g), but displays through location f. The command: DW100,128 for example, Droduces the expanded form of the following output lines: 0100 0201 0403 (etc.) OEOD 10OF .. (etc.) .. 0110 1211 1413 (etc.) 1E1D 201F .. (etc.) . 0120 2221 2423 (etc.) 2928 2B2A !"#$%&'()*+ Examples of valid D commands are: DF3F D#100,#200 D.GAMMA,.DELTA+#30 D.GAMMA DW@ALPHA,+#100 3.4. The Fill Memory (F) Command. The F command fills memory with a constant byte value, and takes the form: Fs,f,d where s is the starting address for the fill, f is the ending (inclusive) address for the fill, and d is the 8-bit data item to store in locations s through f. It is the 18 SID Users Guide Section 3 operator's responsibility to not fill memory locations which are occupied by the resident Portions of CP/M, including areas reserved for SID. Examples of valid F commands are: F100,3FF,FF F.GAMMA,+#100,#23 F@ALPHA,+=I,=X 3.5. The GO (G) Command. The G command is used to pass Program control to a program under test. Execution proceeds in real-time from the address specified by the G command. That is, the G command releases processor control from SID to the program under test. Execution does not return to SID until a break or pass point is reached (see the "P" command for a discussion of Pass points). The operator can force a return to SID, however, by interrupting the processor with a "restart 7" (RST 7), provided by the program under test, or forced by external hardware such as front Panel control switches, if available. The several G command forms are: (a) G (b) Gp (c) G,a (d) Gp,a (e) G,a,b (f) Gp,a,b (g) -G (h) -Gp (i) -G,a (j) -Gp,a (k) -G,a,b (l) -G,p,a,b Forms (a) through (f) start test proqram execution with symbolic features enabled, while forms (g) through (l) are identical in function, but disable the symbolic features of SID. In particular, form (a) starts test program execution from the program counter (PC) given in the machine state of the program under test (see the "X" command for machine state display). In this case, no breakpoints are set in the test program. Form (b) is similar to (a) , but initializes the test program's PC to p before starting execution. Again, no breakpoints are set in the test program. Similar to (a), form (c) starts execution from the current value of PC but sets a breakpoint at location a. The test program receives control and runs in real-time until the address a is encountered. Note that control will return to SID upon encountering a pass point or RST 7, as described above. Upon encountering the breakpoint address a, the break address is printed at the console in the form: *a .s 19 SID Users Guide Section 3 where s is the first symbol in the table which matches address a, if it exists. Note that the temporary breakpoint at address a is automatically cleared when SID returns to command mode (see the "P" command for permanent breakpoints). Form (d) combines the functions of (b) and (c): the test program PC is set to the address p and a temporary breakpoint is set at location a. As above, the breakpoint is cleared when location a is encountered. It should be noted that an immediate breakpoint will alwavs occur if p = a. If this is not desired, however, the operator can use the trace function to single step past the current address, followed by a G command (see the "G" command for actions of the trace facility). Form (e) extends the breakpoint facility bv allowing two temporary break addresses at a and b. Program execution begins at the current PC and continues until either address a or b is encountered. Both temporary break addresses are cleared when SID returns to command mode. Form (f) is similar to (e), except the initial value of PC is set to location p before starting the test program. It should be noted that the instruction at a breakpoint address is not executed when the G command is used. Suppose, for example, that a subroutine named TYPEOUT is located at address 0302 in a test Program, consisting of the machine code: TYPEOUT: 0302 MOV C,A 0303 MVI C,2 0305 JMP 0005 Suppose further that the operator is testing a program which makes calls on the TYPEOUT subroutine where a break address is to be set. The command: G,.TYPEOUT is entered by the operator. Test program\execution proceeds from the current PC value and stops when the@TYPEOUT subroutine is reached, with the breakpoint message *0302 .TYPEOUT indicating that control has returned from the test program to the SID debugger. At this point the program counter of the test program is at location 0302 (i.e., .TYPEOUT), and the instruction at this location has not yet been executed. 20 SID Users Guide Section 3 The operator can execute through the TYPEOUT subroutine using any of the commands G, T, or U. One useful command in this situation is G,^ which continues execution from 0302, and sets a breakpoint at the topmost stacked element (given by "^"). Since the topmost stacked element must be the subroutine return address, this particular G command has the effect of executing the TYPEOUT subroutine, with a break upon return to the instruction following the original call to TYPEOUT. Command forms (g) through (l) correspond directly to functions (a) through (f), except that pass points are not displayed until the corresponding pass counters reach 1 (see the "P" command for details of intermediate pass point display). Note that the essential difference between the G command and the U (Untrace) command is that execution proceeds unmonitored in real-time with the G command, while each instruction is executed in single-step mode when the U command is used. Fully-monitored execution under the U command has the advantage that the operator can regain control at any point in the test program execution. However, execution time of the test program is seriously degraded in Untrace mode since automatic breakpoints are set and cleared following each instruction. Examples of valid G commands are: G100 G100,103 G.CRLF,.PRINT,#1024 G@JMPVEC+=I,.ENDC,.ERRC G,.ERRSUB G,.ERRSUB,+30 -G100,+10,+10 3.6. The Hexadecimal Value (H) Command. The H command is used to perform hexadecimal computations including number base conversion operations. The forms of the H command are: (a) Ha,b (b) Ha (c) H Form (a) computes the hexadecimal sum and difference using the two operands, resulting in the display: ssss dddd where ssss is the sum a+b, and dddd is the difference a-b, 21 SID Users Guide Section 3 ignoring overflow and underflow conditions. Form (b) is used to perform number and character conversion, where a is a symbolic expression. The display format in this case is: hhhh #ddddd 'c' .s where hhhh is the four digit hexadecimal value of a, #ddddd is the (up to) six digit decimal value of a, c is the ASCII value of a when a is graphic, and s is the first symbol in the table which matches the value a, when such a symbol exists. Assume, for example, that the symbol GAMMA is located at address 0100, as in previous examples. The H commands shown to the left below result in the displays shown to the right below: COMMAND RESULTING DISPLAY H0,1 0001 FFFF H41 0041 #65 'A' H100 0100 #256 .GAMMA H.GAMMA 0100 #256 .GAMMA H=GAMMA 0001 #1 H@GAMMA 0201 #513 HFF+@GAMMA 0100 #256 .GAMMA H'A' 0041 #65 'A' H'A'+=GAMMA 0042 #66 'B' Command form (c) prints the complete list of symbols along with their corresponding address values. The list is printed from the first to last symbol loaded, and can be aborted during typeout by depressing any keyboard character. 3.7. The Input Line (I) Command. When testing programs which run in the CP/M environment, it is often useful to simulate the command line which is normally prepared by the CCP upon program load. The form of the I command is: Iccccc ... ccc where the secuence of c's reoresent ASCII characters which would normally follow the test program name in the CCP command line. For example, the CP/M "DUMP" program is normally started in CCP command mode by typing: DUMP X.COM which causes the CCP to search for and load the DUMP.COM file, and pass the file name "X.COM" as a parameter to the DUMP program. In particular, the CCP initializes two default file control blocks, along with a default command line which contains the characters following the DUMP command. 22 SID Users Guide Section 3 In order to trace and debug a program such as DUMP, the SID program would normally be invoked by typing: SID DUMP.COM which loads the command file containing the DUMP machine code. If the symbol table is available, the SID invocation would be: SID DUMP.COM DUMP.SYM In either case, SID loads the DUMP program and prompts the console for a command. In order to simulate the CCP's command line preparation, the operator would then type: IX.COM where the "I" denotes the Input command, which is followed by the simulated command line. The operator may then commence the debug run with default areas properly setup. The I command specifically initializes the default file control block in low memory, labelled DFCB1, which is normally located at 005C. The file control block which is initialized by the I command is complete in the sense that the program can simply address DFCB1 and perform and open, make, or delete operation without further initialization. As a convenience, a second file name is initialized at location DFCB2, which is at address DFCB1+0010 (hexadecimal). It is the programmer's responsibility to move the second drive number, file name, and file type to another region of memory before performing file operations at DFCB1 since the 16-byte region at DFCB2 will be immediately overwritten by any file operation. Further, the default buffer, labelled DBUFF, is initialized to contain the entire command line with a preceding blank character. In a standard CP/M system, the DBUFF area is assumed to be located start at 0080 and end at 00FF. Note, however, that the I command restricts the simulated CCP command line to 63 characters since SID's line buffer is used in the simulation. Given an I command of the form: I dl:fl.tl d2:f2.tl where dl: and d2: are (optional) drive identifiers, fl and f2 are (up to eight character) file names, and tl and t2 are (up to three character optional) file types, two default file control block names are prepared in the form: DFCB1: dl' fl' tl' 00 00 00 00 DFCB2: d2' f2' t2' 00 00 00 00 00 (current record field) 23 SID Users Guide Section 3 If dl: is empty in the original command line, then dl' = 00 (which automatically selects the default drive) , otherwise if dl = A, B, C, or D, then dl' = 01, 02, 03, or 04, respectively, which properly initializes the file control block for automatic disk selection. Field fl' is initialized to the ASCII file name/given by fl, Dadded to an eight character field with ASCII blanks. Similarly, tl' is initialized to the ASCII file type, padded with blanks in a field of length three. Lower case alohabetics in dl, fl, and tl are translated to upider case in dl', fl', and tl', respectively. Names which exceed their respective length fields are truncated on the right. Finally, the extent field is zeroed in preparation for a BDOS call to open or make the file. The second default file control block given by d2, f2, and t2 is prepared in a similar fashion and stored starting at location 006C. Note that the current record field at location 007C is also initialized to 00. If any of the fields f1, t1, f2, and t2 are not included in the command line, their corresponding fields in the default file control blocks are filled with blanks. Ambiguous references which use the **n or "?" character are processed in the same manner as in the CCP: the "*" symbol in a name or type field causes the field to be right- filled with "?' characters. The input lines shown below illustrate the default area initialization which takes place for various unambiguous and ambiguous file names. The areas shown to the right give the hexadecimal values which begin at the labelled addresses, where ASCII values A, B, C, and D have the hexadecimal values 41, 42, 43, and 44, respectively. Further, the special characters ":", ".", "*" , and "?" have the ASCII encoded values 3A, 2E, 2A, and 3F, while an ASCII space has the hexadecimal value 20: COMMAND LINE DEFAULT DATA AREA INITIALIZATION I DFCB1: 00 20 20 20 20 20 20 20 20 20 20 20 00 00 00 00 DFCB2: 00 20 20 20 20 20 20 20 20 20 20 20 00 00 00 00 00 00 DBUFF: 00 00 24 SID Users Guide Section 3 I A.B DFCBI: 00 41 20 20 20 20 20 20 20 42 20 20 00 00 00 00 DFCB2: 00 20 20 20 20 20 20 20 20 20 20 20 00 00 00 00 00 00 DBUFF: 05 20 20 41 2E 42 00 IA:B.C b:d.e DFCB1: 01 42 20 20 20 20 20 20 20 43 20 20 00 00 00 00 DFCB2: 02 44 20 20 20 20 20 20 20 45 20 20 00 00 00 00 00 00 DBUFF: 0B 41 3A 42 2E 43 20 42 3A 44 2E 45 00 I AA*.B?C D: DFCB1: 00 41 41 3F 3F 3F 3F 3F 3F 42 3F 43 00 00 00 00 DFCB2: 04 20 20 20 20 20 20 20 20 20 20 20 00 00 00 00 00 00 DBUFF: OC 20 20 41 41 2A 2E 42 3F 43 20 44 3A 00 Note that the I command is used in conjunction with the R command to read program files and symbol tables after SID has initially loaded. Details of the use of I in this situation are given with the R command which follows. Additional valid I commands are given below: I x.dat Ix.inp y.out Ia:x.inp b:y.out $-p ITEST.COM I TEST.HEX TEST.SYM 3.8. The List Code (L) Command. The L command disassembles machine code in the memory of the machine, with symbolic labels and operands placed in the appropriate fields, where possible. The forms of the L command are: 25 SID Users Guide Section 3 (a) Ls (b) Ls,f (c) L (d) -Ls (e) -Ls,f (f) -L Form (a) lists disassembled machine code starting at symbolic location s for 1/2 CRT screen (12 lines). Form (b) specifies an exact range for disassembly: s specifies the starting location, and f gives the final disassembly location. Form (c) is similar to (a), but disassembles from the last listed, assembled (see the A command), traced (see the T and U commands), or break address (see the G and P commands). Since form (c) also lists 1/2 CRT screen, it is often used following form (a) to continue the disassembly process through another segment of the oroaram. Forms (d) through (f) parallel (a) through (c) but disable the symbolic features of SID. In particular, the minus prefix prevents any symbol lookup operations during the disassembly. The format of the L command output is: sssss: aaaa oocode operand .ttttt where "sssss:" represent a symbol which labels the program location given by the hexadecimal address aaaa, when the symbol exists. The "opcode" field gives the 8080 mnemonic for the instruction at location aaaa, and the 'operand" field, when present, gives the hexadecimal values which follow the opcode in memory. The symbol ".ttttt" is printed when the instruction references a memory address which matches a symbol in the table. Note that instructions may directly reference memory through their operand fields (e.g., CALL, JMP, LDA, LHLD), while other instructions imply a memory address (e.g., STAX B, LDAX D). Instructions which reference memory, such as INR M, are listed with the memory operand in the form: opcode m =hh where "opcode" is the memory referencing instruction, and hh is the hexadecimal value contained in the memory address given by the HL register pair before the operation takes place. When the operation code at the list address is not a valid 8080 mnemonic, the output form is: ??= hh where hh is the hexadecimal value of the invalid operation code. 26 SID Users Guide Section 3 Several valid L commands are listed below. L100 L#1024,#1034 L.CRLF L@ICALL,+30 -L.PRBUFF+=I,+ A 3.9. The Move Memory (M) Command. The M command allows the operator to move blocks of data values from one area of memor y to another. The form of the M command is: Ms,h,d where s is the start address of the move operation, h is the high (last) address of the move, and d is the starting destination address to receive the data. Data moves one byte at a time from the start address to the destination address. Each time a byte value is moved, the start and destination addresses are incremented by one. The move process terminates when the start address increments past the final f address. The command: M100,1FF,3000 for example, replicates the entire block of memory from 0100 through 01FF at the destination area from 3000 through 3OFF in memory. The data block from 0100 through 01FF remains intact. Note that data areas may overlap in the move process: the command M100,1FF,101 shows an instance where the value at location 0100 is propagated throughout the entire block from 0101 through 0200. A number of valid M commands are listed below: M-100,FFDO,100 M.X,+=Z,.Y M.GAMMA,+FF,.DELTA M@ALPHA+=X,+#50,+100 3.10. The Pass Counter (P) Command. The P command allows the operator to set and clear "pass points" and "pass counts" in the program under test. 27 SID Users Guide Section 3 The forms of the P command are: (a) Pp (b) Pp, c (c) P (d) -Pp (e) -P A"pass point" is a program location to monitor during execution of t6e test program. Similar to a temoorary breakpoint (see the G command), a Dass r>oint causes SID to stop execution of the test program each time an active pass point is reached. Unlike a temporary breakpoint, a pass point is not automatically cleared each time it is reached during execution. Further, unlike a temporary breakpoint, a pass point break occurs after the instruction as the pass address is executed. In this way, the operator can simply continue the execution of the test program under control of a G command until the next pass point is executed, or until a temporary breakpoint is reache@. Each pass point can have an optional "pass count" which defaults to the value 1. The pass count enhances this facility by allowing several passes through a pass point before the break actually occurs. In particular, a pass count in the range 1-FF (decimal 1 through 255) can be associated with a particular pass point. Each time a pass point is executed, its corresponding pass count is decremented. The decrementing process proceeds until the pass count reaches 1, at which time the break address is printed and execution of the test program stops. When a pass count reaches 1, the pass point becomes a permanent break address which halts execution each time the instruction is executed. Note that a pass count does not change once it has reached 1. Form (a) sets a pass point at address p with a pass count of 1, causing address p to become a permanent breakpoint. Form (b) is similar, except that the pass count is initialized to c. Up to eight distinct pass points can be actively set at any particular time. Form (c) displays these active pass points in the format: cc oppp sssss where cc is the hexadecimal value of the pass count which is currently associated with the pass address pppp, and sssss is a symbol which matches the address pppp, if such a symbol exists. Form (d) clears the pass point at address p, while form (e) clears all active pass points. Note that the command: Pp,0 28 SID Users Guide Section 3 is equivalent to form (d). Each time a pass point is encountered, SID prints the pass information in the format: cc PASS pppp .sssss where cc is the current pass count at pass point pppp (cc is decremented when greater than 1). As above, the symbol sssss corresponding to address pppp is printed when possible. The special command forms "-G" and "-U" can be used to disable the intermediate pass trace as the counters are decremented down to 1. Suppose, for example, the TYPEOUT subroutine is a part of a program under test, as shown in the G command above. The command: P.TYPEOUT,#30 is issued by the operator. The effect of this particular P command is to set a pass point at the location labelled by "TYPEOUT" which is assumed to exist in the symbol table. The pass count is set to decimal 30, which allows the pass point to execute 30 times before a breakpoint is taken. Given that the pass point at TYPEOUT is in effect, the command: G starts execution of the test program with no temporary breakpoint. Each time the ass point is executed, the pass trace: 1E PASS 0302 TYPEOUT (register trace) 1D PASS 0302 @.TYPEOUT (register trace) 1C PASS 0302 TYPEOUT (register trace) . . . 01 PASS 0302 TYPEOUT (register trace) *303 where the "register trace" shows the state of the CPU registers before the "MOV C,A" at TYPEOUT is executed (see the "X" command for register display format). Note that the final breakpoint address is 0303, which follows the "MOV" instruction at the pass address 0302. The operator can depress any keyboard character during the pass point trace, and SID will immediately stop execution following the instruction at the pass point address. If instead, the command 29 SID Users Guide Section 3 -G had been issued above, the intermediate pass traces would not appear at the console. In this particular case, only the final trace: 01 PASS 0302 TYPEOUT (register trace) *303 is printed. Although the intermediate pass traces are not displayed, the operator can abort execution by depressing a keyboard character: if an intermediate pass point is encountered with trace disabled, SID aborts execution and returns control to the keyboard. Temporary breakpoints can also be set while pass points are in effect. That is, commands such as Ga,b Ga,b,c G,b G,b,c can be issued which intermix with the permanent breakpoints which are set with the P command. Note, however, that permanent breakpoints override the temporary breakpoints which are given by b and c when they occur at the same address. Further, T and U command can be used to trace sections of the test program while permanent breakpoints are in effect. in this case, the pass counts decrement as described above, with a break taken when the count reaches 1. Valid P commands are shown below: P100,FF P.BDOS P@ICALL+30,#20 -P.CRLF 3.11. The Read Code/Symbols (R) Command. The R command is used in conjunction with the I command to read program segments, symbol tables, and utility functions into the transient program area. The forms of the R command are: (a) R (b) Rd The 1 command is first used to set the file names which will be involved in the read operation. Form (a) reads the program and/or symbol table given by the I command without applying an offset to the load addresses. Form (b) adds the displacement value d to each program load address and/or symbol table address. Note that this addition takes place without overflow checks so that negative bias values can be 30 SID Users Guide Section 3 applied. As a simple case, the usual initiation of SID: SID X.COM could be replaced by the sequence of commands: SID Starts SID without a test program IX.COM Initialize the input line R Read the test program to memory The response from SID in this case is exactly the same as the normal initialization, with the "NEXT PC END" message as described in Section 1. A program and symbol file can be read by preceding the R command with an I command of the form: I x.y u.v where x.y is the program to load, and u.v is the symbol table file. Note that y is usually the type "COM", x is usually the same as u, and v is usually the type "SYM". Thus, a typical command sequence of this form would be IDUMP.COM DUMP.SYM R which reads the DUMP.COM program file into the Transient Program Area, and loads the symbol table with the information given by DUMP.SYM. Programs with file type "HEX" load into the locations specified in the Intel formatted hexadecimal records, while programs with file type "UTL" are assumed to be SID utility functions which load and relocate automatically. All other file types are assumed absolute, and load starting at the base of the transient area. Utility functions automatically remove any existing symbol information when they relocate, but in all other cases the symbol load operations are cumulative. In particular the special input form: I* u.v R skips the program load since there is an asterisk in the program name position, and loads only the symbol table file. Thus, a secuence of the above form could be used to load the symbol tables for selective portions of a large program which was initially developed in small modules. Suppose, for example, that a report generation program has been developed using MAC, which consists of the several modules: 31 SID Users Guide Section 3 IOMOD.ASM I/0 Module SORT.ASM File Sorting Module MERGE.ASM File merge Module FORMAT.ASM Report Format Module MAIN.ASM Main Program Module DATA.ASM Common Data Definitions Suppose further that each module has been separately assembled using MAC, resulting in several "HEX" and "SYM" files corresponding to the individual program segments. The program segments have been brought together using SID to form a memory image by typing the sequence of commands: SID Start the SID program IIOMOD.HEX Initialize IOMOD R Read I/0 Module ISORT.HEX Initialize SORT R Read Sort Module IMERGE.HEX Initialize MERGE R Read Merge Module IFORMAT.HEX Initialize FORMAT R Read Format Module IMAIN.HEX Initialize MAIN R Read Main Module IDATA.HEX Initialize DATA Area R Read Initialized Data Following this sequence, the Transient Program Area contains the complete memory image of the report generation program. Suppose the information printed following the last R command is: NEXT PC END 1B3E 0100 8E00 which indicates that the high memory address is 1B3E. Using the H command: H1B the operator finds that 1B (hexadecimal) pages is the same as 27 (decimal) pages. At this point, the operator returns to CCP mode by typing either a control-C (warm start), or "G0" command, which leaves the memory image intact. The command: SAVE 27 REPORT.COM is then issued to create a memory image file on the diskette. The operator then re-enters SID using a command of the form: SID REPORT.COM to load the entire module for testing. Individual portions 32 SID Users Guide Section 3 of the report generator can then be symbolically accessed by selectively loading symbol tables from the original modules. For example, the MAIN and SORT modules could be debugged by subsequently loading the corresponding symbol information: I* MAIN.SYM R I* SORT.SYM R which readies the symbol information for subsequent debugging. Individual segments of the report generator are then tested and reassembled. If an error is found in the SORT module, for example, the SORT.ASM file is edited to make necessary changes, and the module is reassembled with MAC, resulting in new "HEX" and "SYM" files for the SORT module only. Given that enough "expansion" area has been provided following the SORT module, SID is reinitiated and the SORT module is included: SID REPORT.COM ISORT.HEX SORT.SYM R which overlays the changed SORT module in the original report generator memory image. The operator may then load addition symbol tables by typing I and R commands such as: I* MAIN.SYM R I* DATA.SYM R in order to access symbols in the SORT, MAIN, and DATA modules. Note that several symbol table files can be concatenated using the PIP program (see the "CP/M Features and Facilities" manual for PIP operation) in command mode. For example, the PIP command: PIP NOBUGS.SYM=IOMOD.SYM,SORT.SYM,MERGE.SYM,FORMAT.SYM creates a file called NOBUGS.SYM which holds the symbols for IOMOD, SORT, MERGE, and FORMAT. The SID command: SID REPORT.COM NOBUGS.SYM loads the memory image for the report generator, along with the symbol tables for these particular modules. Additional symbol files can then be selectively loaded using I and R commands. The symbol file for the entire memory image can then be constructed using the PIP command: PIP REPORT.SYM=NOBUGS.SYM,MAIN.SYM,DATA.SYM 33 SID Users Guide Section 3 which allows the operator. to type SID REPORT.COM REPORT.SYM in order to load the memory image for the report generator, along with the entire symbol table. Recall, however, that the symbol table is always searched in load-order, and thus symbol names which are the same in two module must be distinguished using qualified symbolic names (see Section 1). As mentioned above, form (b) allows a displacement value d to be added to each program address and symbol value. The displacement value has no effect, however, when the program is a SID utility (file type "UTL"). The commands IDUMP.HEX DUMP.SYM R1000 for example, cause the DUMP program to be loaded 1000 (hexadecimal) locations above its normal origin, with properly adjusted symbol addresses. Note that the bias value can be any symbolic expression, and thus the command: R-200 first produces a (two's complement) negative number which is added to each address. Since overflow from a 16-bit counter is ignored, this R command has the effect of loading the program 200 (hexadecimal) locations below the normal load address, with symbol addresses biased by this same amount. Error reporting during the R command is limited to the standard "?' response, which indicates that either the program or symbol file does not exist, or the program or symbol file is improperly formed. Similar to the SID startup messages, the response SYMBOLS occurs following program load, and appears before the symbol load. Thus, a error before the SYMBOLS response indicates that the error occurred during the program load, while the "?" error after the SYMBOLS message indicates that an error occurred during the symbol file load operation. The exact position of a symbol file error can be found by subsequently using the H command to view the portion of the symbol table which was actually loaded. 3.12. The Set Memory (S) Command. The S command allows the operator to enter data into main memory. The forms of the S command are: 34 SID Users Guide Section 3 (a) Ss (b) SWs Form (a) allows data to be entered at location s in byte (8-bit) or character string mode, while form (b) is used to store word (16-bit) mode data items. In either case, the SID program proceeds to prompt the console with successive addresses, starting at location s, along with the data item presently located at that address. As each line prompt occurs, the operator has the option of typing a single carriage return or typing a symbolic expression (followed by a carriage return) which is evaluated and becomes the new data item at that location. If a single carriage return is typed, then the data element at that location remains unchanged. The S command terminates whenever an invalid data item is detected, or when the operator types a single "." followed by a carriage return. Form (a) allows single byte data, and produces the standard "?" when a double byte value is entered with a non-zero high order byte. In addition, form (a) also allows long ASCII string data to be entered in the format: "ccccc . . . ccccc where the sequence of c's represent graphic ASCII characters to be entered at the prompted location. No translation from lower to upper case takes place during entry. Further, the next prompted address is automatically set to the first unfilled location following the input string. A valid input sequence following the command: S100 is shown below, where the SID prompt is given on the left, and the oderator's input lines are shown to the right, where "cr" denotes the carriage return key. SID PROMPT OPERATOR INPUT 0100 C3 34cr 0101 24 #254cr 0102 CF cr 0103 4B "ASCIIcr 0108 6E =X+5cr 0109 E2 '%'cr 010A D4 cr A valid double byte input sequence following the command SW.X+#30 is shown below: 35 SID Users Guide Section 3 SID PROMPT OPERATOR INPUT 2300 006D 44Fcr 2302 4F32 @GAMMAcr 2304 33E2 cr 2306 FF11 X+=1-#20cr 2308 348F .cr 3.13. The Trace Mode (T) Command. The T command allows the operator to single or multiple step a test program while viewing the CPU registers as they change. In addition, the T command can be used in conjunction with SID utilities to collect test program data for later display (see the section entitled "SID Utilities"). The forms of the T command are: (a) Tn (b) T (c) Tn,c (d) T,c (e) -T (with options a - d) (f) TW (with options a - d) (g) -TW (with otions a- d) Form (a) traces program execution from the current value of the program counter PC (see the 'X' command for PC value as well as the format of the CPU state disolay). Form (b) is the trivial case of (a), with an assumed single step count of n = 1. In either case, the SID program displays the register state, along with the decoded instruction (assuming "-A" is not in effect) before each instruction is executed. For example, the command: T4 traces four program steps, producing the format: (register state 1) opcode 1 label: (register state 2) opcode 2 label: (register state 3) opcode 3 label: (register state 4) opcode 4 *bbbb showing the register state before each corresponding operation code is executed. Each operation code is written in the same format as in the L and X commands, with interspersed symbolic operands decoded wherever possible. The interspersed labels show program addresses when they occur in the flow of execution. The final break address, denoted by "*bbbb" above, shows the value of the program counter after opcode 4 is executed. 36 SID Users Guide Section 3 The CPU state can optionally be displayed at this point by typing the single character "X" command. Forms (c) and (d) are used only in conjunction with the SID utilities, and automatically perform a CALL c after each instruction executes. The value of c corresponds to a utility entry address for data collection. Details of the use of these forms are given in sections which follow. Note, however, that form (d) is equivalent to (c) with a single step count of n = 1. Forms given by (e) parallel (a) through (e), but the preceding minus sign disables the symbolic features of SID. In particular, neither the symbolic operands nor the symbolic labels are decoded in the trace process. This option increases the operation of SID slightly in trace mode when large symbol tables are present. Forms given by (f) parallel (a) through (d), but perform a "trace without call" function. It is often useful, for example, to trace mainline program code, but not trace into the subroutines which are called from the mainline execution. The TW command performs this function by running the test program in real time whenever a subroutine is entered, returning to fully traced mode upon return to the current subroutine level. If a return operation takes place at the current level (i.e., a RET is executed in fully traced mode), then tracing continues at the encompassing subroutine or mainline program level. For example, suppose the mainline and subroutine structure shown below exists in a particular program: MAINLINE SUBROUTINE 1 SUBROUTINE 2 ... SUBROUTINE n . . . Sl: MOV A,C S2: MOV A,D Sn: MOV A,L CALL Sl . . . . . . . . . MOV B,C CALL S2 . . . . . . MOV C,D MOV C,E CALL S3 ... MOV C,L . . . MOV D,E MOV D,H MOV D,L . . . . . . . . . . . . JMP 0000 RET RET RET Suppose further that the test orogram is stooped within subroutine Sl before the call to subroutine S2. The command: T#100 would have the effect of tracing from Sl through S2, S3, and so-forth until level Sn is encountered. Although this form of the trace could be useful, it is often more enlightening to trace only at a particular subroutine level, and view the effects of the subroutine levels above S1. in this manner, an offending subroutine is often easily discovered without tracing non-essential program flows. If instead, the command: 37 SID Users Guide Section 3 TW#100 is typed while at subroutine level S1, all subsequent levels from S2 and beyond are executed in real time as if a "G" command had been Performed at each CALL within Sl. Upon executing the RET instruction within Sl, tracing resumes at the mainline level. Any subroutine calls following CALL Sl at the main level are not subsequently traced. Forms given by (9) parallel (a) through (d), but disable the symbolic features of SID in the same manner as form (e). `It should be noted that SID allows tracing up to Read Only Memory (ROM) program code. At the point ROM is entered, SID stops the trace operation, and runs the ROM code in real time. An automatic breakpoint is set which intercepts program control when ROM code is exited. The assumption, however, is that ROM code was entered via a subroutine call (CALL or RST n), or via a PCHL or JMP instruction. In any case, the return address following the ROM execution is taken as the topmost address in the test program's stack. Note further that SID does not trace execution of calls through the BDOS code, since these operations are often quite lengthy, and may occassionally require real time operation to perform various disk functions. Thus, entry to the BDOS is intercepted by SID, and resumed following completion of the BDOS function. Tracing can be aborted at any time by depressing a keyboard character. Do not use the RST instruction to terminate trace functions. Valid trace commands are,shown below: T100 T#30,.COLLECT -TW=I,3E03 3.14. The Untrace Mode (U) Command. The U command is similar to the T command given above, except that the CPU register state is not displayed at each step. Instead, the test program runs fully monitored so that program execution can be aborted at any time, or for the collection of data for a SID utility function. The forms of the U command parallel the T command: 38 SID Users Guide Section 3 (a) Un (b) U (c) Un,c (d) U,c (e) -U (with options a - d) (f) UW (with options a - d) (g) -UW (with options a - d) Forms (a) through (d) perform the analogous functions of the "T" command forms (a) through (d), without disz)laying the register state at each step. Forms given by (e) differ from the T command, however: instead of disabling the symbolic features, command forms -Un -U -Un,c -U,c disable the intermediate pass point display (see the "P" command), until the corresponding pass counts reach 1. Forms given by (f) correspond to the "T" command exactly, except that the trace display is disabled. In this case, the current subroutine level is run fully monitored, but higher subroutine levels run in real time. Forms given by (g) are similar to (f), but disable the pass point display, as described above. Similar to the T command, execution can be aborted in untrace mode by depressing any keyboard character. The break address is displayed, and control returns to SID command mode. Valid U commands are given below: UFFFF U#10000,.COLLECT UW=GAMMA,.COLLECT 3.15. The Examine CPU State (X) Command. The X command allows the operator to examine and alter the CPU state of the program under test. The forms of the X command are: (a) X (b) Xf (c) Xr Form (a) displays the entire CPU state in the format: CZMEI A=aa B=bbbb D-dddd H-hhhh S=ssss P=pppp op sym where C, Z, M, E, and I represent the true or false conditions of 39 SID Users Guide Section 3 the CPU carry, zero, minus, even parity, and interdigit carry, respectively. If the position contains a "-" then the corresponding flag is false, otherwise the flag letter is printed. The byte value aa is the value of the A register, while the double byte values bbbb, dddd, hhhh, ssss, and pppp, give the 16-bit values of the BC, DE, HL, Stack Pointer, and Program Counter, respectively. The field marked "op" gives the decoded mnemonic instruction at location pppp, unless "-A" is in effect, in which case the hexadecimal value of the operation code is printed. The "sym" field contains a decoded operand, when possible. Refer to the L command for the format of the symbolic instruction decoding. The single letter "X" command might result in a display of the form: C-M-- A=03 B=34EF D=2000 H=334E S=4323 P=0100 LDA 0223 .Q which, for example, indicates that the carry and minus flags are true, while the zero, even parity, and interdigit carry flags are false. Further, the A register contains 03, while the B, C, D, E, H, and L registers contain the hexadecimal values 34, EF, 20, 00, 33, and 4E, respectively. The value of the Stack Pointer register is 4323, and the Program Counter is at location 0100. The next instruction to execute at location 0100 is an accumulator load (LDA) from location 0233. Further, the first symbol in the table which matches address 0233 is Q. Form (b) allows the operator to change the state of the CPU flags. In this case, f must be one of the condition code letters C, Z, M, E, or I. The present state of the flag is displayed (either the flag letter if true, or a "-" if false). The operator can optionally type a single carriage return, which leaves the flag in its present state, or may type a 1 to set the flag true, or a 0 to reset the flag to false. Given that the carry flag is true, for example, the command XC produces the SID response C followed by a space, indicating that the carry is currently set, awaiting possible change by the operator. Enter a carriage return to leave the flag set, or a 0 to reset the carry to false. Similarly, if the zero flag is false, the command XZ produces the SID response - 40 SID Users Guide Section 3 indicating that the zero flag is false. Enter a carriage return if the state is to remain unchanged, or a 1 to set the zero flag to true. Form (c) allows alteration of the individual CPU registers, where r is one of the register names A, B, D, H, S, or P. In this case, the current content of the register is displayed, and the console is Prompted for input. If the operator types a single carriage return, the data value remains unchanged. Otherwise, the symbolic expression typed by the operator is evaluated and becomes the new value of the register. Only byte values are acceptable when the "XA" form is used, while double byte values are accepted in the remaining forms. Note that the BC, DE, and HL registers must be altered as a pair. The SID interaction shown below is typical when the A register is altered: XA 03 45cr where the "XA" is typed by the operator, the "03" is printed by SID as the value of the A register, and "45" is typed by the operator as a replacement for A's value. The "cr" represents the carriage return key in this example, and in the examples which follow. The following interactions with SID provide additional examples in the format described above: XB 34EF cr (data remains unchanged) XD 2000 2300 (D)changes to 23) XH 334E .GAMMA XS 4323 @STKPTR+#100 41 4. SID UTILITIES. SID Utilities are special programs which operate with SID to provide additional debugging facilities. As described in Section l., a SID Utility is loaded by initially typing SID X.UTL where x is the name of a utility program, described in the sections which follow. Upon initiation, the utility program loads, relocates, and prompts the console for any necessary parameters. The operator then collects necessary program test data (using the U or T command), and displays the information using a call to the utility display subroutine. The mechanisms for system initialization, data collection, and data display are given in detail below. 4.1. Utility Operation. A particular SID utility loads into memory in much the same manner as a normal test program. The utilities, however, automatically move themselves into high memory, occupying the region directly below the SID program, as described in Section 1. The utility load operation can be accomplished by simply typing the utility name with the SID command as shown above, or can be loaded during the SID execution, as described in the I and R commands. Recall, however, that all existing symbol information is removed when the utility loads, and must therefore be reinitialized if required for the debugging run. Normally, a SID utility has three primary entry points: one for utility (re)initialization, called INITIAL, one for data collection, called COLLECT, and one for data display, called DISPLAY. After loading, the utility sets up these symbols in the table, and types the entry point addresses in the format: .INITIAL - iiii .COLLECT - cccc .DISPLAY - dddd where iiii, cccc, and dddd are the hexadecimal addresses of the three entry points. Note, however, that the three symbolic names are equivalent to these three addresses. Following initial sign on, the utility may prompt the console for additional debugging parameters. After the interaction is complete, the operator may use the I and R commands to load test programs and symbol tables in order to proceed with the debug session. During the debug run, data collection takes place by running the test program in monitored mode using the U or T 42 SID Users Guide Section 4 commands. Either of the commands UFFFF,.COLLECT or UFFFF,cccc direct the SID program to run the test program from the current Program Counter, for a maximum of 65535 (FFFF hexadecimal) steps, with a call to the data collection entry point of the utility program. Each instruction breakpoint sends information to the utility program, where it is tabulated for later display. Note that in this particular case, the operator would most likely stop the untrace mode by depressing the return key before the sequence of 65535 steps completes. Following a series of data collection operations, the utility DISPLAY entry point can be called to print the accumulated data. Either of the command forms which follow accomplish this function: C.DISPLAY or Cdddd The operator may then resume the data collection process, as described above, followed by additional display operations. At any point, the operator can reinitialize the utility by typing either C.INITIAL or Ciiii which causes reinitialization of the utility tables. The utility may then prompt for additional parameters to complete the reinitialization process. Note that loading and executing more than one utility function during a debugging session may produce unpredictable results. The functions of the SID utilities are presented individually in the remaining sections. 4.2. The HIST Utility. The HIST Utility creates a histogram (bar graph) of the relative frequency of execution in selected program segments of a program under test. The purpose of the HIST utility is to allow the operator to monitor "hot spots" in the test program where the program is executing most frequently. After initial signon, as described in the previous section, the HIST utility prompts the input console with TYPE HISTOGRAM BOUNDS The operator must respond with two symbolic expressions, 43 SID Users Guide Section 4 separated by a comma: llll,hhhh where llll is the lowest address to monitor, and hhhh is the highest address. In order to collect histogram information, the operator must use one of the command forms Tn,c T,c TWn,c TW,c -Tn,c -T,c -TWn,c -TW,c Un,c U,C UWn,c UW,c -Un,c -U,c -UWn,c -UW,c where c is either COLLECT, or the address corresponding to the COLLECT entry point. Although all of these commands are optional, the single form UN,.COLLECT is nearly always used since the trace output is disabled, the test program is fully monitored, and data collection takes place at each program step. Following a series of data collection operations, the histogram is displayed by typing C.DISPLAY or Cdddd and the histogram is printed in the format: HISTOGRAM: ADDR RELATIVE FREQUENCY, MAXIMUM VALUE = mmmm aaaa ***** bbbb ******* cccc ********* xxxx *********** yyyy ********************************************* zzzz ****** where addresses aaaa through zzzz span the range from the low to high address range given in the initialization of HIST. The maximum value mmmm is the largest number of instructions accumulated at any of the displayed addresses, and the asterisks represent the bar graph of relative instruction frequencies, scaled according to the maximum value mmmm. The address range is automatically scaled over 64 difference address slots (aaaa, bbbb, ... zzzz, above), with a maximum of 64 asterisks in any particular bar of the graph. Given the above display, for example, the "hot spot" is around the address range xxxx to zzzz. In this case, it would be worthwhile reinitializing the HIST utility by typing C.INITIAL or Ciiii 44 SID Users Guide Section 4 The HIST initialization prompt and response should then be TYPE HISTOGRAM BOUNDS xxxx,zzzz The operator may then rerun the test program using the command UFFFF,.COLLECT After leaving enough time for the test program to reach "steady state," the operator then interrupts program execution by typing a return during the monitored execution. The display function is then reinvoked to expand the region between xxxx and zzzz, resulting in a more refined view of the frquently executed region. The L command can subsequently be used to determine the exact instructions which are most frequently executed. If possible, the sequence of instructions can be somewhat improved, with an overall improvement in program performance. 4.3. The TRACE Utility. The TRACE utility is used to obtain a backtrace of the instructions which lead to a particular break address in a program under test. A program may have an error condition, for example, which arises from a sequence of instructions which are difficult to find under normal testing. In this case, TRACE can be used to collect program addresses as the test program executes, and display these addresses and instructions in most recent to least recent order when requested by the operator. Normal invocation of SID with the TRACE utility is: SID TRACE.UTL with the normal utility response: INITIAL = iiii COLLECT = cccc DISPLAY = dddd In this case, the TRACE utility also prints the message: READY FOR SYMBOLIC BACKTRACE which indicates that the assembler/disassembler portion of SID is present, and will be used to disassemble instructions when the backtrace is requested. The operator may then proceed to load a test program with optional symbol table. The DUMP program, for example, could be loaded by subsequently typing: 45 SID Users Guide Section 4 IDUMP.COM DUMP.SYM R with the usual "NEXT PC END" response indicating that the test program is loaded. At this point, the SID debugger is executing in high memory, along with the TRACE utility. The test program is present in low memory, ready for execution. The simplest backtrace is obtained by typing one of the U or T command forms shown with the HIST utility. In particular, a U command of the form: U#500,.COLLECT executes 500 (decimal) program steps, and then automatically stops program execution. The operator may then obtain a backtrace to the stop address by typing: C.DISPLAY which causes TRACE to display the label, address, and mnemonic information in the form: label-255: addr-255 opcode-255 sym-255 label -254: addr-254 opcode-254 sym-254 label-253: addr-253 opcode-253 sym-253 . . . . . . . . . label-000: addr-000 opcode-000 sym-000 where label-255 down through label-000 represent the decoded symbolic labels corresponding to addresses given by addr-255 down through addr-000, when the symbolic labels exist. Opcode-255 down through opcode-000 represent the mnemonic operation codes corresponding to the backtraced addresses, and sym-255 down through sym-000 denote the symbolic operands corresponding to the operation codes, when the symbols exist. The operation codes are displayed in the same format as the list command. Note that in this display, the most recently executed instruction is at location addr-255, while the least recently executed instruction is at location addr-000. TRACE will account for up to 256 instructions, which accumulate in T or U mode. The accumulated instructions are not affected by the DISPLAY function, but are cleared by a call to reinitialize: C.INITIAL Full benefit of the TRACE utility requires concurrent use of TRACE with pass points (see the "P" command). In particular, pass points are first set at program locations which are of interest in the backtrace. The program is then 46 SID Users Guide Section 4 run to an intermediate location where the test begins. At this intermediate test point, the U command is used to execute the test program in fully monitored mode, with data collection at the COLLECT entry point of TRACE. Upon encountering one of the pass points in U mode, program execution breaks, and the operator regains control in SID command mode. The DISPLAY function of TRACE is then invoked to obtain the required backtrace information. As an example of this process, suppose the DUMP program is in memory with the TRACE utility, as shown above. Suppose further that the operator wishes to view the actions of the DUMP program on the first call to BDOS (i.e., the first call from DUMP to the CP/M Basic Disk Operating System, through location 0005). Assuming the symbol table is loaded, the operator first types: P.BDOS which sets a pass point at the BDOS entry, with corresponding pass count = 1. The operator then executes DUMP in monitored mode, collecting data at each instruction: UFFFF,.COLLECT The untrace count of FFFF (65535) instructions is, of course, too many in this case, but the assumption is that the DUMP program will stop at the BDOS call before the instruction count is exceeded (if it does not, the operator can depress any keyboard character to force a program stop). In this case, the DUMP program executes only a few instructions before the BDOS call, resulting in the break information: 01 PASS 0005 .BDOS -ZEI A-80 B=0014 D-OOSC H=OOOO S=0249 P=0005 JMP CCDF *CCDF showing the pass count 1, pass address 0005, symbolic location BDOS, register state, and break address. Since execution to this point was monitored, and data was collected, the TRACE function can be invoked: C.DISPLAY which results in the display: 47 SID Users Guide Section 4 BDOS: 0005 JMP CCDF 01CA CALL 0005 .BDOS 01C8 MVI C,0F 01C5 LXI D,005C .FCB 01C2 STA 007C .FCBCR SETUP: 01C1 XRA A 010A CALL 01C1 .SETUP 0107 LXI SP,0257 .STKTOP 0104 SHLD 0215 .OLDSP 0103 DAD SP 0100 LXI H,0000 Note that in this particular case, only 11 instructions were executed before the BDOS call, and thus the full 256 instruction capacity had not been exceeded. In fact, the backtrace shown above gives the complete history of the DUMP execution, from the first instruction at address 0100. The operator may then proceed to execute the DUMP program further by simply typing: UFFFF,.COLLECT with a break at the following call on BDOS. Given that the program execution is to stop on the 20th call on BDOS, the operator can type the pass command: P.BDOS,#20 to set the pass count at 20 (decimal). The command: UFFFF,.COLLECT can be entered if intermediate passes are to be traced. Alternatively, the command: -UFFFF,.COLLECT can be typed to disable intermediate traces. In either case, execution stops at the 20th BDOS call, and the operator can enter the display command: C.DISPLAY to view the trace to this particular BDOS call. Note that long typeouts can be aborted by typing any keyboard character during the display. Further, the ctl-S key freezes the display during output. Finally, recall that "C.DISPLAY" can be issued any number of times to reproduce the backtrace since the command does not clear the TRACE buffer. The TRACE utility can also be used when the 48 SID Users Guide Section 4 disassembler module is not present. In this case, the instruction addresses are listed in the trace, while the mnemonics are not included. For example, the sequence of commands shown below loads the TRACE utility without the disassembler module, followed by the DUMP program without its symbol table: SID Load the SID Program -A Remove the Disassembler ITRACE.UTL Ready the TRACE Utility R Read the TRACE Utility IDUMP.COM Load the DUMP Program In this case, the TRACE utility prints the sign on message: "-A" IN EFFECT, ADDRESS BACKTRACE The backtrace information is subsequently displayed in the format: addr-255 addr-254 addr-253 . . . addr-248 addr-247 addr-246 addr-245 . . . addr-240 . . . addr-007 addr-006 addr-005 . . . addr-000 49 5. SID SAMPLE DEBUGGING SESSIONS. This section contains several examples of SID debugging sessions. The examples are based upon a "bubble sort" of a list of byte values. The bubble sort program is first listed in its first undebugged form. A series of test, edit, and reassembly processes are shown which result in a final debugged program. In each case, the operator interaction with CP/M, ED, MAC, or SID is shown in normal type, while comments on each of the processes are given alongside in italics. {Plain ASCII in this file.} The dialogue which follows contains the following sequence of operations: (1) TYPE SORT.PRN Lists initial SORT program (2) TYPE SORT.SYM Shows the SORT symbol table (3) TYPE SORT.HEX Shows the SORT HEX file (4) SID SORT.HEX SORT.SYM lst debugging session (5) ED SORT.ASM lst re-edit of SORT :Drogram (6) MAC SORT lst reassembly of SORT (7) TYPE SORT.SYM Shows new symbol table (8) SID SORT.HEX SORT.SYM 2nd debugging session (9) ED SORT.ASM 2nd re-edit of SORT program (10) MAC SORT 2nd reassembly of SORT (11) SID SORT.HEX SORT.SYM 3rd debugging session (12) ED SORT.ASM 3rd re-edit of SORT (13) MAC SORT 3rd reassembly of SORT (14) LOAD SORT Create a COM file for SORT (15) SID SORT.COM SORT.SYM 4th debugging session (16) SID SORT.COM SORT.SYM Re~entry to SID for debugging (17) SID SORT.COM SORT.SYM Re-entry to SID for debugging (18) SID SORT.COM SORT.SYM Re-entry to SID for debugging (19) ED SORT.ASM 4th re-edit of SORT (20) MAC SORT 4th reassembly of SORT (21) SID SORT.HEX SORT.SYM 5th debugging session (22) ED SORT.ASM 5th re-edit of SORT (23) MAC SORT 5th reassembly of SORT (24) SID SORT.HEX SORT.SYM 6th debugging session (25) ED SORT.ASM 6th (last) re-edit of SORT (26) MAC SORT $+S 6th (last) reassembly Following the debugging sessions, the final corrected SORT program is given in its debugged form. Three separate debugging sessions are then shown which use the HIST and TRACE utilities to monitor the execution of the tested SORT program. The operations shown here include: (27) SID HIST.UTL Load the HIST Utility (28) SID TRACE.UTL Load the TRACE Utility (29) SID Load SID, TRACE follows As a final example, a simple program which calls the 50 SID Users Guide Section 5 BDOS is listed, followed by a single debugging session. The purpose of this particular example is to show the actions of SID when subroutines are traced, followed by Calls on the CP/M BDOS. The operations in this case are: (30) TYPE IO.PRN List the IO program (31) SID IO.HEX IO.SYM Enter SID for debugging 51 SID Users Guide Section 5 [1] TYPE SORT.PRN ; SORT PROGRAM IN CP/M ASSEMBLY LANGUAGE ; ELEMENTS OF 'LIST' ARE PLACED INTO ; DESCENDING ORDER USING BUBBLE SORT ; 0100 ORG 100H ;BEGINNING OF TPA 0000 = REBOOT EQU 0000H ;CP/M REBOOT LOCATION ; 0100 213801 SORT: LXI H,SW 0103 3601 MVI M,l ;SW = 1 0105 213901 LXI H,I ;INDEX TO SORT LIST 0108 3600 MVI M,0 ;I = 0 ; ; COMPARE I WITH ARRAY SIZE COMP: ;HL ADDRESS INDEX I 010A 3A6201 LDA N ;LENGTH OF VECTOR 0100 BE CMP M ;CHECK FOR N=I 010E C21901 JNZ CONT ;CONTINUE IF UNEQUAL ; ; END OF ONE PASS THROUGH LIST 0111 213801 LXI H,SW ;NO SWITCHES? 0114 7E MOV A,M ;FILL A WITH SW 0115 B7 ORA A ;SET FLAGS ; END OF SORT PROCESS, REBOOT 0116 C30000 STOP: JMP REBOOT ;RESTART CCP ; ; CONTINUE THIS PASS CONT: ; ADDRESSING I, S0 LOAD LIST(I) 0119 SF MOV E,A ;LOW(I) TO E REGISTER 011A 1600 MVI D,0 ;HIGH(I) = 0 011C 215A01 LXI H,LIST ;BASE OF LIST 011F 19 DAD D ;ADDR LIST(I) 0120 7E MOV A.M ;LIST(I) IN A REGISTER 0121 23 INX H ;ADDR OF LIST(I+1) 0122 BE CMP M ;LIST(I):LIST(I+1) 0123 DA3101 JC INCI ;SKIP IF PROPER ORDER ; ; CHECK FOR LIST(I) = LIST(1+1) 0126 CA3101 JZ INCI ;SKIP IF EQUAL ; ; ITEMS ARE OUT OF ORDER, SWITCH 0129 4E MOV C,M ;OLD LIST(I+1) TO C 012A 77 MOV M,A ;NEW LIST*I+1) TO M 012B 2B DCX H ;ADRR LIST(I) 012C 71 MOV M,C ;NEW LIST(I) TO M ; 012D 213801 LXI H,SW ;SWITCH COUNT IS SW 0130 34 INR M ;SW = SW + 1 ; INCI: ;INCREMENT INDEX I 0131 213901 LXI H,I 0134 34 INR M ;I = I + 1 0135 C30A01 JMP COMP ;TO COMPARE I WITH N-1 ; ; DATA AREAS 0138 SW: DS 1 ;SWITCH COUNT 0139 DS 1 ;INDEX 013A DS 32 ;16 LEVEL STACK STACK: ; 015A 0503040A08LIST: DB 5,3,4,10,8,130,10,4 0162 08 DB $-LIST ;LENGTH OF LIST 0163 END 52 SID Users Guide Section 5 Section 5 [2] TYPE SORT.SYM 010A COMP 0119 CONT 0139 I 0131 INCI 0I5A LIST 0162 N 0000 REBOOT 0100 SORT 015A STACK 0116 STOP 0138 SW [3] TYPE SORT.HEX :10010000213801360121390136003A6201BEC21997 :10011000012138017EB7C300005F1600215A011982 :100120007E23BEDA3101CA31014E772B71213801AD :080130003421390134C30A0136 :09015A000503040A08820A0408E6 :0000000000 [4] SID SORT.HEX SORT.SYM Start SID with HEX and SYM files SID VERS 1.4 SYMBOLS NEXT PC END 0163 0100 55B7 Next free address is 163, Program Counter is 100 #D.LIST,+=N-1 and end of TPA is 55B7 015A: 05 03 04 0A 08 82...... 0160: OA 04 .. Display initial list of items to sort #G,.STOP Execute test program until "STOP" symbol address encountered *0116 .STOP Now at the STOP address examine data list: #D.LIST,+=N-1 015A: 05 03 04 OA 08 82...... Hasn't changed! 0160: OA 04 .. #XP where is the program counter? P=0116 100 reset PC back to beginning and try again with trace on: #TJO ----- A=01 B=0000 D=0008 H=0138 S=0100 P=0100 LXI H,0138 .SW ----- A=01 B=0000 D=0008 H=0138 S=0100 P=0103 MVI M,01 SW SW=1 ----- A=01 B=0000 D=0008 H=0138 S=0100 P=0105 LXI H,0139 .I I=0 ----- A=01 B=0000 D=0008 H=0139 S=0100 P=0108 MVI M,00 .I COMP: ----- A=01 B=0000 D=0008 H=0139 S=0100 P=010A LDA 0162 .N N=I? ----- A=08 B=0000 D=0008 H=0139 S=0100 P=010D CMP M-00 .I ----I A=08 B=0000 D=0008 H=0139 S=0100 P=010E JNZ 0119 .CONT CONT: No, so compare ----I A=08 B=0000 D=0008 H=0139 S=0100 P=0119 MOV E,A LIST(i), LIST(i+1) ----I A=08 B=0000 D=0008 H=0139 S=0100 P=011A MVI D,00 ----I A=08 B=0000 D=0008 H=0139 S=0100 P=011C LXI H,015A .LIST ----I A=08 B=0000 D=0008 H=015A S=0100 P=011F DAD D ----I A=08 B=0000 D=0008 H=0162 S=0100 P=0120 MOV A,M .N What's this? ----I A=08 B=0000 D=0008 H=0162 S=0100 P=0121 INX H Why did we ----I A=08 B=0000 D=0008 H=0163 S=0100 P=0122 CMP M=58 fetch N? C-M-I A=08 B=0000 D=0008 H=0163 S=0100 P=0123 JC 0131 .INCI INCI: C-M-I A.08 B=0000 D=0008 H=0163 S=0100 P=0131 LXI 4,0139 .I *0134 Looks like we've discovered a bug! We have here entered at "CONT" #GO with N in the accumulator, rather than I, which is expected! [5] ED SORT.ASM Back to the editor to make the changes Bring all the text into memory *V Enter Verify mode for line numbers, then find the place to change 1: *FADDRESSING 28: *OLT 28: ; ADDRESSING I, S0 LOAD LIST(I) 28: *KT Delete the line 28: MOV E,A ;LOW(I) TO E REGISTER 28: *I 29: LDA I ;LOAD I TO A REGISTER Insert the change 29: ctl-Z 29: *E Terminate the editing session 53 SID Users Guide Section 5 [6] MAC SORT CP/PM MACRO ASSEM 2.0 0166 Re-assemble the SORT program 001H USE FACIOR ENO OF ASSEMBLY [7] TYPE SORT.SYM Here's the symbol table. 010A COMP 0119 CONT 013C I 0134 INCI 015D LIST 0165 N 0000 REBOOT 0100 SORT 015D STACK 0116 STOP 0138 SW [8] SID SORT.HEX SORT.SYM SID VERS 1.4 Let's try again, load the HEX and SYM files SYMBOLS NEXT PC END 0166 0100 55B7 #P.STOP Set a "pass point", at STOP to prevent reboot #G Start (unmonitored) execution 01 PASS 0116 .STOP We mode it to the STOP label, check values ----- A=7C B=0008 D=0081 H=0138 S=0100 P=0116 JMP 0000 .REBOOT *0000 .REBOOT #H=N What's the value of the byte variable N? 0082 #130 130? Very strange! How did that happen? D.LIST,+7 Oh well, let's look at the data values: 015D: 03 04 05 They are almost sorted, looks like we have 0160: 08 OA OA 04 08..... some trouble near the end of the vector, #ISORT.HEX lets reload the machine code and try #R again. NEXT PC END 0166 0100 55B7 #XP P=0100 Program counter remains at 0100, what #P are the active pass points? 01 0116 .STOP The one at STOP remains set, let's also #P.SORT,FF monitor the SORT loop point, but not #G break right away. FF PASS 0100 .SORT Here's the first time through SORT ----- A=7C B=0008 D=0081 H=013B S=0100 P=0100 LXI H,013B .SW 01 PASS 0116 .STOP It stopped immediately! It doesn't look good! ----- A=79 B=0008 D=0081 H=013B S=0100 P=0116 JMP 0000 .REBOOT *0000 .REBOOT We know there should have been several loops #ISORT.HEX through the SORT label, since the data is #R unordered. Let's try again - reload the code NEXT PC END (note that the reload is necessarv here, since 0166 0100 55B7 the data is initialized in the code area). #P 01 0116 .STOP What active pass points exist? FE 0100 .SORT Wait a minute - referring back to the #GO original listing, it appears that the code preceding the STOP label is incomplete: there should be a conditional lump back to the SORT label - mavbe that's why the program never makes it back! 54 SID Users Guide Section 5 [9] ED SORT.ASM Oh well, back to the editor for a *#AV quick fix. Append all text (#A), and .1: *FSTOP: enter Verify mode (V). rhen find STOP. 24: *OLT 24: STOP: JMP REBOOT ;RESTART CCP 24: *- Go up one line 23: ; END OF SORT PROCESS, REBOOT 23: *I and enter insert mode (I) 23: JNZ CONT ;CONTINUE IF NOT EQUAL 24: ; ctl-Z, and "return" 25: E 26: wait, I forgot the ctl-Z. now I've got the E command in 26: *- my input buffer. Type the ctl-Z, go back up one line, 25: E delete the E, then end the edit 25: *KT 25: ; END OF SORT PROCESS, REBOOT 25: *E OK, we mode the change, now re-a:3emble [10] MAC SORT Invoke the macro assembler with SORT as input. CP/M MACRO ASSEM 2.0 0169 . 001H USE FACTOR END OF ASSEMBLY [11] SID SORT.HEX SORT.SYM Here we go again, I sure hope this is the SID VERS 1.4 last time (but it probably isn't). SYMBOLS NEXT PC END 0169 0100 55B7 #P.SORT,FF Set a pass point at sort, with a high count. P.STOP also set a pass point at STOP with count 1, this #P will stop the first time through FF 0100 .SORT 01 0119 .STOP #G Execute the test program FF PASS 0100 .SORT First time through SORT label: ----- A=00 B=0000 D=0000 H=0000 S=0100 P=0100 LXI H,013E .SW 01 PASS 0119 .STOP Stopped cgain! Arrggh! -Z-E- A=00 B=006A D=0007 H=013E S=0100 P=0119 JMP 0000 .REBOOT *0000 .REBOOT Let's look at some values H=N 0008 #8 N=8, looks better than last time #D.LIST,+=N 0160: 01 01 03 04 04 05 07 08 08 ......... These values look a bit #ISORT.HEX strange?! Try again: #R NEXT PC END 0169 0100 55B7 #D.LIST,+=N-1 Machine code reloaded, display initial values.. 0160: 05 03 04 OA 08 82 OA 04 ......... #L.CONT CONT: Let's take a look at the process of switching 011C LDA 013F .I two data items - the code appears down below 011F MOV E,A the 'CONT' label, so we'll disassemble a 0120 MVI 0,00 portion of the program. 0122 LXI H,0160 .LIST 0125 DAD D 0126 MOV A,M 0127 INX H 0128 CMP M 0129 JC 0137 .INCI 012C JZ 0137 .INCI 012F MOV C,M Here's where the switch occurs, let's set a pass #P12F,FF point here and watch the data addresses: #P FE 0100 .SORT 01 Ol19 .STOP FF 012F 55 SID Users Guide Section 5 #G FE PASS 0100 .SORT Here's the first pass through SORT -Z-P- A=00 B=006A D=0007 H=013E S=0100 P=0100 LXI H,013E .SW FF PASS 012F Switching at address 161, looks OK! ----I A=05 B=006A D=0000 H=0161 S=0100 P=012F MOV C,M FE PASS 012F Switching at 162. looks good. ----I A=05 B=0003 D=0001 H=0162 S=0100 P=012F MOV C,M FD PASS 012F 164 is the next to switch. looks good. ----I A=OA B=0004 D=0003 H=0164 S=0100 P=012F MOV C,M FC PASS 012F 166 is probably the next one. ---E- A=82 B=0008 D=0005 H=0156 S=0160 P=012F MOV C,M *0130 So what's wrong? This section of # code seems to work. #-P Clear all the pass points, and reload #ISORT.HEX the machine code for another test. *R NEXT PC END 0169 0100 55B7 #L.CONT+5 0121 NOP 0122 LXI H.0160 .LIST 0125 DAD D 0126 MOV A,M Here's the code where the element 0127 INX H switching occurs, lets watch the 0128 CMP M program switch the first element: 0129 JC 0137 .INCI 012C JZ 0137 .INCI 012F MOV C,M 0130 MOV M,A 0131 DCX H #G,129 *0129 OK, here we are, ready to test And #T10 switch, if necessary. ----I A=05 B=0000 D=0000 H=0161 S=0100 P=0129 JC 0137 .INCI ----I A=05 B=0000 D=0000 H=0161 S=0100 P=012C JZ 0137 .INCI ----I A=05 B=0000 D=0000 H=0161 S=0100 P=012F MOV C,M ----I A=05 B=0003 D=0000 H=0161 S=0100 P=0130 MOV M,A ----I A=05 B=0003 D=0000 H=0161 S=0100 P=0131 DCX H ----I A=05 B=0003 D=0000 M=0160 S=0100 P=0132 MOV M,C .LIST ----I A=05 B=0003 D=0000 H=0160 S=0100 P=0133 LXI H,013E .SW ----I A=05 B=0003 D=0000 M=013E S=0100 P=0136 INR M=01 .SW *0137 .INCI Well, that went nicely - elements switched, SW=1 #0.LIST,+7 0160: 03 05 04 OA 08 82 OA 04 .... #H=I The data looks good at this point. 0000 .REBOOT #0 #G,.INCI Proceed to the INCI label *0137 .INCI Here we are, let's look at the data: #0.LIST,+7 0160: 03 05 04 0A 08 82 0A 04 ....... #H=I 0000 .REBOOT #0 Looks good, trace past the label and break #T ----- A=05 B=0003 D=0000 H=013E S=0100 P=0137 LXI H,013F .I *013A #G,.INCI *0137 .INCI Here we are (again), how's the data? #D.LIST.+=I 0160: 03 04 ... Looks good, proceed past INCI #T ---E- A=05 B=0004 D=0001 H=013E S=0100 P=0137 LXI H,013F .I *013A And loop again . . . #G,.INC: #0137 .INCI Here we are (again), how's the data? #D.LIST,+=I 0160: 03 04 05 ... Looks good, this is getting monotonous, lets go for it! Stop at either SORT or STOP #0119 .STOP Egad! Here we at the the ST0P label. Why #D.LIST,+=I aren't we making it back to SORT? 0160: 01 01 03 04 04 05 07 08 08 ....... # Tsk! Tsk! The data's messed up again. 56 SID Users Guide Section 5 #ISORT.HEX Let's reload and try again. #R NEXT PC END 0169 0100 55B7 #L136,+3 0136 INR M Here's where the swltch count is incremented INCI: 0137 LXI H,013F .I 013A #G,136 Execute the program and break at SW = SW + 1 *0136 #D.LIST,+=I Look at data values: 0160: 03 . #U Use U to move past break address ----I A=05 B=0003 D=0000 H=013E S=0100 P=0136 INR M=01 .SW *0137 .INCI It's actually easier to use the pass point feature #P136 if we want to view the action of the INR M, #G since the P command stops execution after the pass point is executed. 01 PASS 0136 ----I A=05 B=0004 D=0001 H=013E S=0100 P=0136 INR M=02 .SW *0137 .INCI SW = 2, looks good. #D.LIST,+=I 0160: 03 04 Data values look good. #S.N Let's change N to a smaller value so the program 0168 08 4 doesn't loop so many times: 4 is a good number. 0169 0A End input with "." #G "GO" to pass point 01 PASS 0136 Here we are. switch value is incremented: ----I A=0A B=0008 D=0003 H=013E S=0100 P=0126 INR M=03 .SW *0137 .INCI Stopped at next instruction. #D.LIST,+=I 0160: 03 04 05 08 .... Data values so far. #H=SW 0004 #4 SW value at this point is 4. #TFFFF Let's watch it run for a few steps: ----- A=0A B=0008 D=0003 H=013E S=0100 P=0137 LXI H,013F .I ----- A=0A B=0008 0=0003 H=013F S=0100 P=013A INR M=03 .I ----- A=0A B=0008 D=0003 H=013F S=0100 P=013B IMP 010A .COMP COMP: ----- A=0A B=0008 D=0003 H=013F S=0100 P=010A LDA 0168 .N ----- A=04 B=0008 D=0003 H=013F S=0100 P=010D CMP M=04 .I -Z-EI A=04 B=0008 D=0003 H=013F S=0100 P=010E JNZ 011C .CONT -Z-El A=04 B=0008 D=0003 H=013F S=0100 P=0111 LXI H,013E .SW &Z-El A=04 B=0008 D=0003 H=013E S=0100 P=0114 MOV A,M .SW -Z-EI A=04 B=0008 D=0003 H=013E S=0100 P=0115 ORA A ----- A=04 B=0008 0=0003 H=013E S=0100 P=0116 JNZ 011C .CONT CONT: ----- A=04 B=0008 D=0003 H=013E S=0100 P=011C LDA 013F .I *011F Very interesting! We seem to be *GO going back to "CONT" rather than "SORT". Let's go back to the editor and fix it up. [12] ED SORT.ASM *#AVFORA This is a simple change: append all text, enter line 22: *OLT verify mode, find "ORA" and make the change: 22: ORA A ;SET FLAGS 22: * "return" to move down one line 23: JNZ CONT ;CONTINUE IF NOT EQUAL 23: *SCONT!ZSORT!ZOLT Substitute SORT for CONT 23: JNZ SORT ;CONTINUE IF NOT EQUAL 23. * "return" to move down another line 24: ; 24: * "return" again. 25: ; END OF SORT PROCESS, REBOOT 25: *E End the edit 57 SID Users Guide Section 5 [13] .MAC SORT CP/M MACRO ASSEM 2.0 0169 Call out MAC for another assembly 001H USE FACTOR END OF ASSEM@LY [14] LOAD SORT Just for a little variation, we'll create a FIRST AODRESS 0100 SORT.COM file for testing under SID. LAST ADORESS 0168 BYTES READ 0047 RECORDS WRITTEN 01 [15] SID SORT.COM SORT.SYM SID VERS 1.4 Back to SID, using the COM and SYM files SYMBOLS NEXT PC END 0180 0100 55B7 #P.STOP Set a pass point at STOP to prevent reboot #D.LIST,+=N-1 Her's the original data: 0160: 05 03 04 0A 08 82 0A 04 ........ #G Unmonitored GO Oops! We didn't get control back, there must be on infinite loop - we can get control back by 63K CP/M VERS 1.3 forcing a front panel RST 7 (interrupt 7), or simply bail-out with a cold start. [16] SID SORT.COM SORT.SYM SID VERS 1.4 Let's start again, but be a little more selective SYMBOLS in setting breakpoints. NEXT PC END 0180 0100 55B7 #P.STOP Set a pass point at STOP, as before #P.SORT,FF and one at SORT with a Pass count of 255. #-G GO with pass trace disabled. 01 PASS 0100 Stopped with 255 passes through SORT - too many! ----- A=01 B=006A D=00FF H=013E S=0100 P=0100 LXI H,013E *0103 #D.LIST,+=N-1 How's the data? 0160: 03 #H=N Hmmm... looks like n was destroyed. 0000 .REBOOT #0 #H=I 0000 .REBOOT #0 #G,.COMP There's a good possibility that we're running off the end of the LIST vector into the variable N, 010A .COMP lets stop at the COMP label and watch the end test. #T5 ----- A=01 B=006A D=00FF H=013F S=0100 P=010A LDA 0168 .N ----- A=00 B=006A D=00FF H=013F S=0100 P=0100 CMP M-00 .I -Z-El A=00 B=006A D=00FF H=013F S=0100 P=010E JNZ 011C .CONT -Z-EI A=00 B=006A D=00FF H=013F S=0100 P=0111 LXI H,013E .SW -Z-El A=00 B=006A D=00FF H=013E S=0100 P=0114 MOV A,M .SW *0115 Hey. this isn't going to work! We'll be comparing #GO LIST(N-1) with LIST(N), but the last LIST element is at LIST(N-1). Let's try a quick fix. 58 SID Users Guide Section 5 [17] SID SORT.COM SORT.SYM SID VERS 1.4 Let's re-enter SID with a clean memory SYMBOLS image, and look at the machine code NEXT PC END below the 'COMP' label. 0180 0100 55B7 #L.COMP COMP: 010A LDA 0168 .N Here's the reference to N - let's change this 0100 CMP M to N1 with a "hot patch" in memory, to see 010E JNZ 011C .CONT if it works, then we'll go back to the 0111 LXI H,013E .SW origiNal source program and make the 0114 MOV A,M necessary changes. We're not using the area #AIOA of memory starting at 0200, so patch a lump 010A JMP 200 over the LDA instruction, and fix-up some 010D patch code. #A200 0200 LDA .N Replace the LDA instruction which now has JMP 200. 0203 DCR A N-1 in accumulator (N better be 2 or larger!) 0204 CMP M and compare with memory (HL addresses I), 0205 JNZ .CONT jump to CONT if continuing, otherwise 0208 JMP 111 jump back to the next instruction in sequence 0208 after the patch. #P205,FF Set a pass point to watch the JNZ take place #P.STOP and catch any returns to the CCP. #Plll,FF Set a pass point at the patch return addrem #S.N Reduce the size of V for this test to 4. 0168 08 4 0169 00 #G Everything is ready, let's go... FF PASS 0205 First pass through the patch code: ---EI A=03 B=0000 D=0000 H=013F S=0100 P=0205 JNZ 011C .CONT FE PASS 0205 Went to CONT that time, second pass: ----I A=03 B=0003 D=0000 H=013F S=0100 P=0205 JNZ 011C .CONT FD PASS 0205 Went to CONT again, next pass: ----I A=03 B=0004 D=0001 H=013F S=0100 P=0205 JNZ 011C .CONT FC PASS 0205 And so-forth.. -Z-EI A=03 B=0004 D=0002 H=013F S=0100 P=0205 JNZ 011C .CONT FF PASS Oll1 Must be the end of one cycle: -Z-EI A=03 B=0004 D=0002 H=013F S=0100 P=0111 LXI H,013E .SW FB PASS 0205 Now back through the patch code: ---EI A=03 B=0004 D=0002 H=013F S=0100 P=0205 JNZ 011C .CONT FA PASS 0205 ----I A=03 B=0004 D=0000 H=013F S=0100 P=0205 JNZ 011C .CONT F9 PASS 0205 ----I A=03 B=0004 D=0001 H=013F S=0100 P=0205 JNZ 011C .CONT F8 PASS 0205 -Z-EI A=03 B=0004 D=0002 H=013F S=0100 P=0205 JNZ OJJC .CONT FE PASS 0111 -Z-EI A=03 B=0004 D=0002 H=013F S=0100 P=0111 LXI H,013E .SW *0114 This is getting monontonous again, so #D.LIST,+=N-1 push the "return" key to stop the action. 0160: 03 04 05 OA .... Data looks good, run in monitored mode: -UFFFF -Z-EI A=03 B=0004 D=0002 H=013E S=0100 P=0114 MOV A,M *0138 Push the 'return' kev to abort early. #H=N Value of N is still 4 (that's nice!) 0004 #4 Value of I is currently 2. This program #H=1 should have stopped, but didn't for some 0002 #2 reason. 59 SID Users Guide Section 5 [18] SID SORT.COM SORT.SYM SID VERS 1.4 Lets trv another approach. Suppose we SYMBOLS a r we'll set NEXT PC END ifea@v trar'vsioarl"faPn@ 0180 0100 5587 LIST(O) = 0, LIST(1) = 1 #5.,4 016808 2 016900 #S.LIST 016005 0 016103 1 016204 . P.STOP Things are ready to go, run completely traced.. #TFFFF ----- A=00 B=0000 D=0000 H=0000 S=0100 P=0100 LXI H,013E .SW ----- A=00 B=0000 D=0000 H=013E S=0100 P=0103 MVI M,01 .SW ----- A=00 B=0000 D=0000 H=013E S=0100 P=0105 LXI H,013F .1 ----- A=00 B=0000 D=0000 H=013F S=0100 P=0108 MVI M,00 .I COMP: ----- A=00 B=0000 D=0000 H=013F S=0100 P=010A LDA 0168 .N ----- A=02 B=0000 D=0000 H=013F S=0100 P=0100 CMP M=00 .I ----I A=02 B=0000 D=0000 H=013F S=0100 P=010E JNZ 011C .CONT CONT: ----I A=02 B=0000 D=0000 H=013F S=0100 P=011C LDA 013F .I ----I A=00 B=0000 D=0000 H=013F S=0100 P=011F MOV E,A ----I A=00 B=0000 D=0000 H=013F S=0100 P=0120 MVI D,00 ----I A=00 B=0000 D=0000 H=013F S=0100 P=0122 LXI H,0160 .LIST ----I A=00 B=0000 D=0000 H=0160 S=0100 P=0125 DAD D ----I A=00 B=0000 D=0000 H=0160 S=0100 P=0126 MOV A,M .LIST ----I A=00 B=0000 D=0000 H=0160 S=0100 P=0127 INX H ----I A=00 B=0000 D=0000 H=0161 S=0100 P=0128 CMP M=01 C-ME- A=00 B=0000 D=0000 H=0161 S=0100 P=0129 JC 0137 .INCI INCI- Not switched! C-ME- A=00 B=0000 D=0000 H=0161 S=0100 P=0137 LXI H,013F .I C-ME- A=00 B=0000 D=0000 H=013F S=0100 P=013A INR M=00 .I C---- A=00 B=0000 D=0000 H=013F S=0100 P=0l3B JMP 010A .COMP COMP: C---- A=00 B=0000 D=0000 H=013F S=0100 P=010A LDA 0168 .N C---- A=02 B=0000 D=0000 H=013F S=0100 P=0100 CMP M=01 .I ----I A=02 B=0000 D=0000 H=013F S=0100 P=010E JNZ 011C .CONT CONT: ----I A=02 B=0000 D=0000 H=013F S=0100 P=011C LDA 013F .I ----I A=01 B=0000 D=0000 H=013F S=0100 P=011F MOV E,A ----I A=01 B=0000 D=0001 H=013F S=0100 P=0120 MVI D,00 ----I A=01 B=0000 D=0001 H=013F S=0100 P=0122 LXI H,0160 .LIST ----I A=01 B=0000 D=0001 H=0160 S=0100 P=0125 DAD D ----I A=01 B=0000 D=0001 H=0161 S=0100 P=0126 MOV A,M ----I A=01 B=0000 D=0001 M=0161 S=0100 P=0127 INX H ----I A=01 B=0000 D=0001 H=0162 S=0100 P=0128 CMP M=04 C-M-- A=01 B=0000 D=0001 H=0162 S=0100 P=0129 JC 0137 .INCI INCI: Not switched (again)! C-M-- A=01 B=0000,D=0001 H=0162 S=0100 P=0137 LXI H,013F .I C-M-- A=01 B=0000 D=0001 H=013F S=0100 P=013A INR M=01 .I C---- A=01 B=0000 D=0001 H=013F S=0100 P=0138 JMP 010A .COMP COMP: C---- A=01 B=0000 D=0001 H=013F S=0100 P=010A LDA 0168 .N C---- A=02 B=0000 D=0001 H=013F S=0100 P=0100 JMP M=02 .I -Z-EI A=02 B=0000 D=0001 H=013F S=0100 P=010E JNZ 011C .CONT -Z-EI A=02 B=0000 D=0001 H=013F S=0100 P=0111 LXI H,013E .SW -Z-El A=02 B=0000 D=0001 H=013E S=0100 P=0114 MOV A,M .SW -Z-EI A=01 B=0000 D=0001 H=013E S=0100 P=0115 ORA A ----- A=01 B=0000 D.0001 H=013E S=0100 P=0116 JNZ 0100 .SORT SORT: No items were switched - SW not set to 0! ----- A=01 B=0000 D.0001 H=013E S=0100 P=0100 LXI H,313E .SW *0103 60 SID Users Guide Section 5 [19] ED SORT.ASM *#AVFSORT:!ZOLT Back to the editor-change the 8: SORT: LXI H,SW entry code to initialize SW 8: *- 7: ; 7: *2 9: MVI M,1 ;SW = 1 9: *2S1!ZO!ZOLT 9: MVI M,0 ;SW = 0 9: *- 8: SORT: LXI H,SW 8- *I 8: MVI A,1 9: STA SW ;SW = 1 FIRST TIME THRU 10: 10: *E [20] MAC SORT CP/M MACRO ASSEM 2.0 016E Re-assemble, again 001H USE FACTOR END OF ASSEMBLY [21] SID SORT.HEX SORT.SYM SID VERS 1.4 We've fixed the SW initialization problem, which SYMBOLS should halt the program at the proper time, but NEXT PC END we may still have a problem with the end of 016E 0100 55B7 LIST test (remember that "hot patch"?). #D.LIST,+=N Here's the initial data: 0165: 05 03 04 0A 08 82 0A 04 08 ......... #G,.STOP GO, unmonitored to the STOP (how's that for *011E STOP confidence?). #D.LIST,+=N We made it, here's the data: 0165: 03 04 04 05 08 08 0A 0A 0B 7B 82 ........... 0170: E6 . Data is sorted in ascending order, but there's too #ISORT.NEX much of it! We still have the problem that N is #R altered during execution. NEXT PC END Let's reload and make sure we know what the 016E 0100 55B7 problem is- #P.SORT Set a pass point at SORT, check N #G 01 PASS 0105 .SORT Here's the first pass through SORT: -Z-E- A=01 B=0004 D=000A H=0143 S=0100 P=0105 LXI H,0143 .SW *0108 Break at 0108, check value of N: #H=N 0008 #8 #G OK initially, continue the execution with G. 01 PASS 0105 .SORT We have passed through the data once: ----- A=75 B=002A D=007A H=0143 S=0100 P=0105 LXI H,0143 .SW *0108 #H=N 007B #123 N has been altered, which we expected, since we #ISORT.HEX are testing LIST(N-1) against LIST(N) and performing #R a switch if unordered. NEXT PC END 016E 0100 55B7 Let's reload and scope in on the problem: #G,.INCI Stop at the point where I becomes I + 1: 01 PASS 0105 .SORT Oops! The initial pass point is still set. ----- A=01 B=002A D=007A H=0143 S=0100 P=0105 LXI H,0143 .SW *0108 Clear all pass points. #-P #G,.INCI Now, try agaim *013C .INCI Stopped at first entry to INCI, check value of N: #H=N N is still 8, looks good. 0008 #8 #G,.CONT Go to the CONT label, then stop at INCI. *0121 CONT #G,.INCI 61 SID Users Guide Section 5 *013C .INCI Back at INCI now. Check value of N #H=N 0008 #8 Remains at 8. If we keep this up. we'll be typing #P.INCI,6 break addresses all day. We can run the next few passes #-G through INCI automatically by setting a pass count (use 6 in this case). then run with -C to disable intermediate 01 PASS 013C traces. We now stop 6 iterations Later.. ---E- A=82 B=0004 D=0006 H=0143 S=0100 P=013C LXI H,0144 *013F #H=N Check N: remains at 8, then 0008 #8 check I to compare passes: I=0,1,2,3,4,5,6 has been #H=1 executed. We are now about to set I = 7, but the test 0006 #6 at COMP is "JNZ" which allows execution one too many times (which we already know about). [22] ED SORT.ASM *#AV Back to the editor, change the end of LIST test 1: *FLDA to compare I with N-1 rather than N. 17: *OLT 17: LDA N ;LENGTH OF VECTOR 17: * "return" to go to next line 18: CMP M ;CHECK FOR N=I 18: *I Insert the instruction before the "CMP" opcode. 18: DCR A ;N-1 IN A REGISTER 19: (NOTE THAT N MUST BE 2 OR LARGER) 20: ctl-Z 20: *F*I Now a little clean-up work - there is a typo in 49: *OT a comment line at address 012A in the listing: 49: MOV M,A ;NEW LIST*I*-C-DI(!ZOLT 49: MOV M,A ;NEW LIST(I+1) TO M Looks better now. 49: *F32 We are not using the 8080 stack, so get rid of it. 64: *OLT 64: DS 32 ;16 LEVEL STACK 64: *2KT 64: ; 64: *E Complete the edit. [23] MAC SORT CP/M MACRO ASSEM 2.0 014F Reassemble the source program. OO1H USE FACTOR END OF ASSEMBLY [24] SID SORT.HEX SORT.SYM SID VERS 1.4 Back to SID - this should be the last time! SYMBOLS NEXT PC END 014F 0100 55BF #D.LIST,+=N Initial data: 0146: 05 03 04 0A 08 82 0A 04 08 ......... #G,STOP ? Ok, ok. Let's try it with an "address reference" to #G,.STOP the Label STOP: *011F .STOP That's better, now look at the data: #D.LIST,+=N hooray! It's finally sorted. 0146: 03 04 04 05 08 0A 0A 82 08 .......... #H=N 0008 #8 Is N ok? Yes, it's still 8. #GO Hold it! The data is in ascending order. but it is supposed to be in descending order! This will be an easy fix. 62 SID Users Guide Section 5 [25] ED SORT.ASM *#A *T ; SORT PROGRAM IN CP/M ASSEMBLY LANGUAGE * ; ELEMENTS OF 'LIST' ARE PLACED INTO * ; DESCENDING ORDER USING BUBBLE SORT *SDES!ZASC!ZOLT ; ASCENDING ORDER USING BUBBLE SORT *SCC!ZC!ZOLT ; ASCENDING ORDER USING BUBBLE SORT *E Took care of that problem. [26] MAC SORT $+S @ P/M MACRO ASSEM 2.0 014F Re-assemble with the svmbol table option. 001H USE FACTOR END OF ASSEMBLY At this point, we have checked-out this particular SORT program using this particular set of data items. This does not, of course, mean that the program is fully debugged. There could be cases which are not tested properly since we have not inciuded all boundary conditions (the data items 00 and FF, for example, should be included). Further, there ore program segments which could be incorrect, but which have no negative effects on the program. The @tialization of SW to the value 1 before the label SORT, for example, does not affect the program, but is superfluous. We now have a program which appears to w@ but must undergo further tests before it is considered a production program. 63 Section 5 SID Users Guide Section 5 ; SORT PROGRAM IN CP/M ASSEMBLY LANGUAGE ; ELEMENTS OF 'LIST' ARE PLACED INTO ; ASCENDING ORDER USING BUBBLE SORT ; 0100 ORG 100H ;BEGINNING OF TPA 0000 = REBOOT EQU 0000H ;CP/M REBOOT LOCATION ; 0100 3E01 MVI A,1 0102 324401 STA SW ;SW = 1 FIRST TIME THRU 0105 214401 SORT: LXI H,SW 0108 3600 MVI M,0 ;SW = 0 010A 214501 LXI H,I ;INDEX TO SORT LIST 010D 3600 MVI M,0 ;I = 0 ; ; COMPARE 1 WITH ARRAY SIZE COMP: ;HL ADDRESS INDEX I 01OF 3A4E01 LDA M ;LENGTH OF VECTOR 0112 30 DCR A ;N-1 IN A REGISTER ; (NOTE THAT N MUST BE 2 OR LARGER) 0113 BE CMP M ;CHECK FOR N=I 0114 C22201 JNZ CONT ;CONTINUE IF UNEQUAL ; ; END OF ONE PASS THROUGH LIST 0117 214401 LXI H,SW ;NO SWITCHES? 011A 7E MOV A,M ;FILL A WITH SW 0118 B7 ORA A ;SET FLAGS 011C C20501 JNZ SORT ;CONTINUE IF NOT EQUAL ; ;END OF SORT PROCESS, REBOOT 011F C30000 STOP: JMP REBOOT ;RESTART CCP ; ; CONTINUE THIS PASS CONT: 0122 3A4501 LDA I ;LOAD I TO A REGISTER 0125 5F MOV E,A ;LOW(I) TO E REGISTER 0126 1600 MVI D,0 ;HIGH(I) = 0 0128 214601 LXI H,LIST ;BASE OF LIST 012B 19 DAD D ;ADDR LIST(I) 012C 7E MOV A,M ;LIST(I) IN A REGISTER 0120 23 INX H ;ADDR OF LIST(I+1) 012E BE CMP M ;LIST(I):LIST(I-I) 012F DA3D01 JC INCI ;SKIP IF PROPER ORDER ; ; CHECK FOR LIST(I) = LIST(I+1) 0132 CA3D01 JZ INCI ;SKIP IF EQUAL ; ; ITEMS ARE OUT OF ORDER, SWITCH 0135 4E MOV C,M ;OLD LIST(I+1) TO C 0136 77 MOV M,A ;NEW LIST(I+1) TO M 0137 28 DCX H ;ADDR LIST(I) 0138 71 MOV M,C ;NEW LIST(I) TO M ; 0139 214401 LXI H,SW ;SWITCH COUNT IS SW 013C 34 INR M ;SW = SW = 1 ; INCI: ;INCREMENT INDEX I 0130 214501 LXI H,I 0140 34 INR M ;I = I + 1 0141 C3OF01 JMP COMP ;TO COMPARE I WITH N-1 ; ; DATA AREAS 0144 SW: DS 1 ;SWITCH COUNT 0145 I: DS 1 ;INDEX ; 0146 0503040A08LIST: DB 5,3,4,10, 8,130,10,4 014E 08 N: DB $-LIST ;LENGTH OF LIST 014F END 010F COMP 0122 CONT 0145 I 0130 INCI 0146 LIST 014E N 0000 REBOOT 0105 SORT 011F STOP 0144 SW 64 SID Users Guide Section 5 SID HIST.UTL Start SID with he HIST utility SID VERS 1.4 TYPE HISTOGRAM BOUNDS 100,200 Monitor 0100 through 0200. .INITIAL = 522. .COLLECT = 5224 Entry Point addresses in HIST. .DISPLAY = 5227 #ISORT.HEX SORT.SYM Load the SORT program with symbols. #R SYMBOLS Program loaded. now loading symbols. NEXT PC END 0600 0100 51B7 #P.STOP Permanent break at STOP address. #P.SORT,3 Execute to "Steady state" conditions by #-G passing the SORT label three times before break. "-G" prevents intermediate pass traces. 01 PASS 0100 ----- A=02 B=0004 D=0006 H=013F S=0100 P=0100 LXI H,013F *0103 We're now at the third pass through SORT. #-P.SORT Remove the pass point at SORT, run monitored #UFFF,.COLLECT from this point for 0FFF steps, collect data. ----- A=02 B=0004 D=0006 H=013F S=0100 P=0103 MVI M,01 .SW *0127 Stopped after OFFF steps, display collected data: #C.DISPLAY HISTOGRAM: ADDR RELATIVE FREQUENCY, LARGEST VALUE = 0309 0100 ***** 0104 ** 0108 ********************** most frequently executed address.. 010C *********************************************************** 0110 ** 0114 ******* .... 011C ***************** 0120 **************************************************** 0124 ********************************** 0128 **************************************************** 012C ***** 0130 0134 0138 ********************************** 013C ***************** .... 0200 * #L1OC What's happening at the most frequently executed address? 010C LXI B,BE30 01OF JNZ 011D .CONT This is where the end of LIST test takes place, 0112 LX! H 013F .SW so it is reasonable that this segment of code would 0115 MOV A,M be executed heavily. We could improve performance 0116 ORA A by reducing the length of this segment. The value 0117 jNZ 0100 .SORT of N-1 could, for example, be maintained in register STOP: C throughout the computations, while the value of 011A JMP 0000 .REBOOT I could be kept in register E, with 00 in D. #L11C There is also heavy execution around location 011C. 011C NOP CONT: 0110 LDA 0140 .I This is where we go on each element comparison 0120 M0V E,A whether we switch elements or not. 0121 MVI D,00 0123 LXI H,0161 .LIST 0126 DAD D 0127 MOV A,M 0128 INX H 0129 CMP M 012A JC 0138 .INCI 012D JZ 0138 .INCI #GO 65 SID Users Guide Section 5 [28] SID TRACE.UTL Load the TRACE utility with STD. SID VERS 1.4 INITIAL = 5321 COLLECT = 5324 TRACE entry points. DISPLAY = 5327 READY FOR SYMBOLIC BACKTRACE Indicates that assembler/disassembter is present. #ISORT.HEX SORT.SYM Ready the SORT program and symbol table. #R Load program and symbols to memory. SYMBOLS NEXT PC END 0600 0100 52B7 #P.STOP Permanent break at the STOP label. #P.CONT,3 Pass through CONT three times before stopping. #UFFFF,.COLLECT Untrace mode, print intermediate pass points. ----- A=00 B=0000 D=0000 H=0000 S=0100 P=0100 LXI H,013F .SW 03 PASS 011D .CONT ----I A=07 B=0000 D=0000 H=0140 S=0100 P=011D LDA 0140 .I 02 PASS 011D .CONT ---EI A=07 B=0003 D=0000 H=0140 S=0100 P=011D LDA 0140 .I 01 PASS 011D CONT ---EI A=07 B=0004 D=0001 H=0140 S=0100 P=011D LDA 0140 .I *0120 Stopped on the third pass. #C.DISPLAY Display the backtrace from CONT. BACKTIRACE: CONT: Most recently executed instruction. 011D LDA 0140 .I OIOF JNZ 011D .CONT OIOE CMP M 0100 DCR A COMP: 010A LDA 0169 .N 013C JMP 010A .COMP 0138 INR M INCI: 0138 LXI H,0140 .I 0137 INR M 0134 LXI H,013F .SW 0133 MOV M,C 0132 DCX H 0131 MOV M,A 0130 MOV C,M 0120 JZ 0138 .INCI 012A JC 0138 .INCI 0129 CMP M 0128 INX H 0127 MOV A,M 0126 DAD D 0123 LXI H,0161 .LIST 0121 MVI D,00 0120 MOV E,A CONT: 0110 LDA 0140 .I OIOF JNZ 011D .CONT 010E CMP M 010D DCR A COMP: Least recently executed instruction. 010A LDA 0169 .N (aborted with "return") #GO 66 SID Users Guide Section 5 [29] SID Start SID without loading any programs. SID VERS 1.4 #-A Remove assembler/disassembler package. #ITRACE.UTL Ready the TRACE utility. #R Read the TRACE package to memory. INITIAL - 5921 COLLECT - 5924 TRACE entry point addresses. DISPLAY - 5927 "-A" IN EFFECT, ADDRESS BACKTRACE No assembler/disassembler present. #ISORT.HEX SORT.SYM Ready the SORT program #R Read to memory. SYMBOLS NEXT PC END 0600 0100 58B7 #P.STOP Permanent break at STOP address, #P.CONT,3 pass point at CONT with pass count 3 #-UFFFF,.COLLECT Run monitored, collect data, no intermediate ----- A=00 B=0000 D=0000 H=0000 S=0100 P=0100 21 013F pass information. 01 PASS 011D ---EI A=07 B=0004 D=0001 H=0140 S=0100 P=0110 3A 0140 *0120 Stopped on third pass through CONT #C.DISPLAY BACKTRACE. most recent addresses 011D 010F 010E OIOD 010A 013C 013B 0138 0137 0134 0133 0132 0131 0130 012D 012A 0129 0128 0127 0126 0123 0121 0120 011D 010F 010E 0100 010A O11C 0138 0138 0137 0134 0133 0132 0131 0130 0120 012A 0129 0128 0127 0126 0123 0121 0120 0110 01OF 010E 0100 010A 0108 0105 0103 0100 Least recent address. #GO [30] TYPE IO.PRN ;SIMPLE BDOS OUTPUT PROGRAM 0100 ORG 100H ;BEGINNING OF TPA 0000 = REBOOT EQU OOOOH ;REBOOT ENTRY POINT 0005 = BOOS EQU 0005H ;BOOS ENTRY POINT 0002 = CONOUT EQU 2 ;CONSOLE OUTPUT # ; 0100 315401 LXI SP,STACK;LOCAL STACK 0103 C31501 JMP START ;START EXECUTION ; WRCHAR: ;WRITE CHARACTER FROM REGISTER A 0106 0E02 MVI C,CONOUT;CONSOLE OUTPUT # 0108 5F MOV E,A ;CHARACTE T0 E 0109 C30500 JMP BD0S ;RET THROUGH BOOS ; WRMSG: ;WRITE MESSAGE STARTING AT HL 'TIL 00 010C 7E MOV A,M ;NEXT CHARACTER 0100 B7 ORA A ;00? 010E C8 RZ ;RETURN IF S0 01OF CD0601 CALL WRCHAR ;OTHERWISE WRITE IT 0112 C30C01 JMP WRMSG ;FOR ANOTHER CHARACTER ; START: ;BEGINNING OF MAIN PROGRAM 0115 212A01 LXI H,WALLAMSG ;PART 1 OF MESSAGE 0118 CD0C01 CALL WRMSG ;WRITE IT 0118 212A01 LXI H,WALLAMSG ;PART 2 OF MESSAGE 011E CD0C01 CALL WRMSG ;WRITE IT 0121 213001 LXI H,WASHMSG ;PART 3 OF MESSAGE 0124 CDOC31 CALL WRMSG 0127 C30000 STOP: JMP REBOOT ;STOP THE PROGRAM ; ; DATA AREAS WALLAMSG: 012A 57414C4C41 DB 'WALLA ' WASHMSG: 0130 57415348 DB 'WASH' 0134 DS 32 ;16 LEVEL STACK STACK: 0154 END 67 SID Users Guide Section 5 [31] SID IO.HEX IO.SYM SID VERS 1.4 Load the test program ustng the HEX and SYM files. SYMBOLS NEXT PC END 0134 0100 55A9 #G,.WRMSG GO from 0100 to the first call on WRMSG *010C .WRMSG Now trace from the WRMSG subroutine: #T100 ----- A=00 B=0000 D=0000 H=012A S=0152 P=010C MOV A,M .WALLAMSG ----- A=57 B=0000 D=0000 H=012A S=0152 P=0100 ORA A ----- A=57 B=0000 D=0000 H=012A S=0152 P=OIOE RZ ----- A=57 B=0000 D=0000 H=012A S=0152 P=OIOF CALL 0106 .WRCHAR First WRCHAR. call to WRCHAR ----- A=57 B=0000 D=0000 H=012A S=0150 P=0106 MVI C,02 with 57 (="W") ----- A=57 B=0002 D=0000 H=012A S=0150 0=0108 MOV E,A ----- A=57 B=0002 D=0057 H=012A S=0150 P=0109 JMP 0005 .BOOS BDOS: Call to BDOS ----- A=57 B=0002 D=0057 H=012A S=0150 P=0005 JMP 55AA Function # 2, ----- A=57 B=0002 D=0057 H=012A S=0150 P=55AA JMP 5CA4 Character "W" ----- A=57 B=0002 D=0057 H=012A S=0150 P=5CA4 XTHL ----- A=57 B=0002 D=0057 H=0112 S=0150 P=5CA5 SHLD 6D52 (SID code to ----- A=57 B=0002 D=0057 H=0112 S=0150 P=5CA8 XTHL intercept call) ----- A=57 B=0002 D=0057 H=012A S=0150 P=SCA9 JMP 6E06W = first character -Z-E- A=00 B=0000 D=0200 H=793B S=0152 P=0112 JMP 010C .WRMSG now we're WRMSG: back to our -Z-E- A=00 B=0000 D=0200 H=7938 S=0152 P=010C MOV A,M program, with -Z-E- A=00 B=0000 D=0200 H=7938 S=0152 P=010D ORA A another CALL. -Z-E- A=00 B=0000 D=0200 H=7938 S=0152 P=010E RZ -Z-E- A=00 B=0000 D=0200 H=7938 S=0154 P=011B LXI H,012A .WALLAMSG -Z-E- A=00 B=0000 D=0200 H=012A 5=0154 P=011E CALL 010C .WRMSG WRMSG: -Z-E- A=00 B=0000 D=0200 H=012A S=0152 P=010C MOV A,M .WALLAMSG -Z-E- A=57 B=0000 D=0200 H=012A S=0152 P=010D ORA A ----- A=57 B=0000 D=0200 H=012A S=0152 P=010E RZ ----- A=57 B=0000 D=0200 H=012A S=0152 P=010F CALL 0106 .WRCHAR WRCHAR: ----- A=57 B=0000 D=0200 H=012A S=0150 P=0106 MOV C,02 ----- A=57 B=0002 D=0200 H=012A S=0150 P=0108 MOV E,A abort with "return" *0109 #G,.WRMSG GO, skip traces W Should be ALLA ..., what happened? *010C .WRMSG #TW100 Trace without call: -Z-E- A=00 B=0000 D=0200 H=793B S=0152 P=010C MOV A,M -Z-E- A=00 B=0000 D=0200 H=793B S=0152 P=0100 ORA A -Z-E- A=00 B=0000 D=0200 H=793B S=0152 P=010E RZ -Z-E- A=00 B=0000 D=0200 H=793B S=0154 P=0121 LXI H,0130 .WASHMSG -Z-E- A=00 B=0000 D=0200 H=0130 S=0154 P=0124 CALL 010C .WRMSGW STOP: Called WRMSG, printed another "W" and stopped! -Z-E- A=00 B=C000 D=0200 H=793B S=0154 P=0127 JMP 0000 .REBOOT REBOOT: abort with "return" so we can restart. -Z-E- A=00 B=0000 D=0200 H=793B S=0154 P=0000 JMP 7A03 *7A03 # It appears that the WRMSG routine is not saving the HL register pair, nor is HL being incremented on each loop. 68 SID Users Guide Section 5 #A10F 010F JMP 200 We'll put a "hot patch" at the end of the WRMSG 0112 subroutine to save the HL pair, call the WRCHAR #A200 subroutine, restore the HL pair, then increment HL. 0200 PUSH H We're not using the region above 200. so place patch 0201 CALL .WRCHAR in this region. 0204 POP H 0205 INX H 0206 JMP WRMSG 0209 #G100,.WRMSG Ok, now restart the program and stop at the first call to WRMSG. *010C WRMSG Here we are. HL addresses the message to print, which #D is the default display address follow" a breakpoint: 012A: 57 41 4C 4C 41 20 WALLA= message to print. 0130: 57 41 53 48 56 45 52 53 20 31 2E 34 24 31 00 02 WASHVERS 1.4$1.. #TW100 Trace without calls: shows only the activity in WRMSG. ----- A=00 B=0000 D=0000 H=012A S=0152 P=010C MOV A,M .WALLAMSG ----- A=57 B=0000 D=0000 H=012A S=0152 P=0100 ORA A first character ----- A=57 B=0000 D=0000 H=012A S=0152 P=010E RZ is 57 = "W" ----- A=57 B=0000 D=0000 H=012A S=0152 P=010F JMP 0200 Now in patch ----- A=57 B=0000 D=0000 H=012A S=0152 P=0200 PUSH H area. ----- A=57 B=0000 D=0000 H=012A S=0150 P=0201 CALL 0106 .WRCHARW = character -Z-E- A=00 B=0000 D=0200 H=793B S=0150 P=0204 POP H -Z-E- A=00 B=0000 D=0200 H=012A S=0152 P=0205 INX H Move to next -Z-E- A=00 B=0000 D=0200 H=0128 S=0152 P=0206 JMP 010C .WRMSG character WRMSG: Looping beck. -Z-E- A=00 B=0000 D=0200 H=0129 S=0152 P=010C MOV A,M -Z-E- A=41 B=0000 D=0200 H=0129 S=0152 P=0100 ORA A ---E- A=41 B=0000 D=0200 H=0128 S=0152 P=010E RZ ---E- A=41 B=0000 D=0200 H=0123 S=0152 P=010F JMP 0200 ---E- A=41 B=0000 D=0200 H=0128 S=0152 P=0200 PUSH H Here's the next ---E- A=41 B=0000 D=0200 H=0129 S=0150 P=0201 CALL 0106 .WRCHARA character -Z-E- A=00 B=0000 D=0200 H=793B S=0150 P=0204 POP H (="A") -Z-E- A=00 B=5000 D=0200 4=012B S=0152 P=0205 INX H -Z-E- A=00 B=0000 D=0200 4=012C S=0152 P=0206 JMP 010C .WRMSG WRMSG: -Z-E- A=00 B=0000 D=0200 H=012C S=0152 P=010C MOV A,M *010D Abort with "return" #P.STOP Set a permanent break at STOP, then GO from #G100 the beginning of the program: WALLA WASHVERS 1.4$1WALLA WASHVERS 1 4$1WASHVERS 1.4$1 01 PASS 0127 STOP Things look better, -but "00" byte missing on messages. -Z-E- A=00 B=0000 D=0200 H=013E S=0154 P=0127 JMP 0000 .REBOOT *0000 REBOOT *S.WALLAMSG+4 Place a 00 bvte at the end of each message. 012E 41 (leave this value, 41 = "A" in WALLA) 012F 20 0 (changed to 00 from blank) 013057 #S.WASHMSG+4 Place 00 byte at the end of the second message. 0134 56 0 0135 45 #G100 Break at STOP remains set, GO from the beginning. WALLAWALLAWASH Looks good. we now have enough information to 01 PASS 0127 STOP go back and change the source program using ED. -Z-E- A=00 B=0000 D=0200 H=0134 S=0154 P=0127 JMP 0000 .REB00T #0000 REBOOT #GO 69