.sp 2 .tc 4.4 A Sample Program .he CP/M Operating System Manual 4.4 A Sample Program .sh 4.4 A Sample Program .pp The following example shows an edit, assemble, and debug for a simple program that reads a set of data values and determines the largest value in the set. The largest value is taken from the vector and stored into LARGE at the termination of the program. .ll 75 .sp 2 .nf A>\c .sh ED SCAN.ASM \c .qs Create source program; " " represents carriage return. *I ORG 1-00H ;START OF TRANSIENT ;AREA MVI B, LEN ;LENGTH OF VECTOR TO SCAN MVI C, 0 ;LARGER_RST VALUE SO FAR LOOP LXI H, VECT ;BASE OF VECTOR LOOP: MOV A, M ;GET VALUE SUB C ;LARGER VALUE IN C? JNC NFOUND ;JUMP IF LARGER VALUE NOT ;FOUND ; NEW LARGEST VALUE, STORE IT TO C MOV C, A NFOUND INX H ;TO NEXT ELEMENT DCR B ;MORE TO SCAN? JNZ LOOP ;FOR ANOTHER ; ; END OF SCAN, STORE C MOV A, C ;GET LARGEST VALUE STA LARGE JMP 0 ;REBOOT ; ; TEST DATA VECT: DB 2,0,4,3,5,6,1,5 LEN EQU $-VECT ;LENGTH LARGE: DS 1 ;LARGEST VALUE ON EXIT END .bp ^-Z *B0P ORG 100H ;START OF TRANSIENT AREA MVI B,LEN ;LENGTH OF VECTOR TO SCAN MVI C,0 ;LARGEST VALUE SO FAR LXI H,VECT ;BASE OF VECTOR LOOP: MOV A,M ;GET VALUE SUB C ;LARGER VALUE IN C? JNC NFOUND ;JUMP IF LARGER VALUE NOT ;FOUND ; NEW LARGEST VALUE, STORE IT TO C MOV C,A NFOUND: INX H ;TO NEXT ELEMENT DCR B ;MORE TO SCAN? JNZ LOOP ;FOR ANOTHER ; END OF SCAN, STORE C MOV A,C ;GET LARGEST VALUE STA LARGE JMP 0 ;REBOOT ; ; TEST DATA VECT: DB 2,0,4,3,5,6,1,5 LEN EQU $-VECT ;LENGTH LARGE: DS 1 ;LARGEST VALUE ON EXIT END *E <--End of edit A>\c .sh ASM SCAN \c .qs Start Assembler CP/M ASSEMBLER - VER 1.0 0122 002H USE FACTOR END OF ASSEMBLY Assembly complete; lock at program listing A>\c .sh TYPE SCAN.PRN .qs Code address Source program 0100 ORG 100H ;START OF TRANSIENT AREA 0100 0608 MVI B,LEN ;LENGTH OF VECTOR TO SCAN 0102 0E00 Machine code MVI C,0 ;LARGEST VALUE SO FAR 0104 211901 LXI H,VECT. ;BASE OF VECTOR 0107 7E LOOP: MOV A,M ;GET VALUE 0108 91 SUB C ;LARGER VALUE IN C? 0109 D20D01 JNC NFOUND ;JUMP IF LARGER VALUE NOT ;FOUND ; NEW LARGEST VALUE, STORE IT TO C 010C 4F MOV C,A .bp 010D 23 NFOUND: INX H ;TO NEXT ELEMENT 010E 05 DCR B ;MORE TO SCAN? 010F C20701 JNZ LOOP ;FOR ANOTHER ; ; END OF SCAN, STORE C 0112 79 MOV A,C ;GET LARGEST VALUE 0113 322101 STA LARGE 0116 C30000 JMP 0 ;REBOOT Code--data listing; truncated ; TEST DATA 0119 0200040305 VECT: DB 2,0,4,3,5,6,1,5 0008 = Value of LEN EQU $-VECT ;LENGTH 0121 equate LARGE: DS 1 ;LARGEST VALUE ON EXIT 0122 END A>\c .sh DDT SCAN.HEX \c .qs Start debugger using hex format machine code DDT VER 1.0 NEXT PC Next instruction 0121 0000 to execute at -X Last load address + 1 PC=0 C0Z0M0E0I0 A=00 B=0000 D=0000 H=0000 S=0100 P=0000 OUT 7F -XP Examine registers before debug run P=0000 100 Change PC to 100 -X Look at registers again C0Z0M0E0I0 A=00 B=0000 D=0000 H=0000 S=0100 P=0100 MVI B,08 -L100 PC changed Next instruction to execute at PC=100 0100 MVI B,08 0102 MVI C,00 0104 LXI H,0119 0107 MOV A,M 0108 SUB C Disassembled machine 0109 JNC 010D code at 100H 010C MOV C,A (see source listing 010D INX H for comparison) 010E DCR B 010F JNZ 0107 0112 MOV A,C -L .bp 0113 STA 0121 0116 JMP 0000 0119 STAX B 011A NOP A little more machine 011B INR B code. Note that pro- 011C INX B gram ends at location 011D DCR B 116 with a JMP to 011E MVI B,01 0000. Remainder of 0120 DCR B listing is assembly of 0121 LXI D,2200 data. 0124 LXI H,0200 -A116 Enter in-line assembly mode to change the JMP to 0000 into a RST 7, which will cause the program under test to return to DDT if 116H is ever executed. 0116 RST 7 0117 (Single carriage return stops assemble mode) -L113 List code at 113H to check that RST 7 was properly inserted 0113 STA 0121 0116 RST 07 in place of JMP 0117 NOP 0118 NOP 0119 STAX B 011A NOP 011B INR B 011C INX B - -X Look at registers C0Z0M0E0I0 A=00 B=0000 D=0000 H=0000 S=0100 P=0100 MVI B,08 -T Execute Program for one stop. Initial CPU state, before is executed C0Z0M0E0I0 A=00 B=0000 D=0000 H=0000 S=0100 P=0100 MVI B,08*0102 Automatic breakpoint Trace one step again (note O8H in B) C0Z0M0E0I0 A=00 B=0800 D=0000 H=0000 S=0100 P=0102 MVI C,00*0104 -T Trace again (Register C is cleared) C0Z0M0E0I0 A=00 B=0800 D=0000 H=0000 S=0100 P=0104 LXI H,0119*0107 -T3 Trace three steps C0Z0M0E0I0 A=00 B=0800 D=0000 H=0119 S=0100 P=0107 MOV A,M C0Z0M0E0I0 A=02 B=0800 D=0000 H=0119 S=0100 P=0108 SUB C C0Z0M0E0I1 A=02 B=0800 D=0000 H=0119 S=0100 P=0109 JNC 010D*010D -D119 Display memory starting at 119H. Automatic breakpoint at 10DH 0119 02 00 04 03 05 06 01.Program data Lower-case x 0120 05 11 00 22 21 00 02 7E EB 77 13 23 EB 0B 78 B1 ..."!.. . W .#..X. 0130 C2 27 01 C3 03 29 00 00 00 00 00 00 00 00 00 00 ...' ...)......... 0140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .................. 0150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .................. 0160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Data are displayed 0170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 in ASCI with a "." 0180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 in the position of 0190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 nongraphic........ 01A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 characters........ 01B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .................. 01C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .................. -X Current CPU state C0Z0M0E0I1 A=02 B=0800 D=0000 H=0119 S=0100 P=010D INX H -T5 Trace 5 steps from current CPU state C0Z0M0E0I1 A=02 B=0800 D=0000 H=0119 S=0100 P=010D INX H C0Z0M0E0I1 A=02 B=0800 D=0000 H=011A S=0100 P=010E DCR B C0Z0M0E0I1 A=02 B=0700 D=0000 H=011A S=0100 P=010F JNZ 0107 C0Z0M0E0I1 A=02 B=0700 D=0000 H=011A S=0100 P=0107 MOV A,M C0Z0M0E0I1 A=00 B=0700 D=0000 H=011A S=0100 P=0108 SUB C*0109 U5 Automatic breakpoint Trace without listing intermediate states C0Z1M0E1I1 A=00 B=0700 D=0000 H=011A S=0100 P=0109 JNC 010D*0108 -X CPU state at end of U5 C0Z0M0E1I1 A=04 B=0600 D=0000 H=011B S=0100 P=0108 SUB C -G Run program from current PC until completion (in real-time) *0116 breakpoint at 116H, caused by executing RST 7 in machine code. -X CPU state at end of program C0Z1M0E1I1 A=00 B=0000 D=0000 H=0121 S=0100 P=0116 RST 07 -XP Examine and change program counter P=0116 100 -X C0Z1M0E1I1 A=00 B=0000 D=0000 H=0121 S=0100 P=0100 MVI B,08 -T10 First data element Current largest value Subtract for comparison C Trace 10 (hexadecimal) steps C0Z1M0E1I1 A=00 B=0800 D=0000 H=0121 S=0100 P=0100 MVI B,08 C0Z1M0E1I1 A=00 B=0000 D=0000 H=0121 S=0100 P=0102 MVI C,00 C0Z1M0E1I1 A=00 B=0800 D=0000 H=0121 S=0100 P=0104 LXI H,0119 C0Z1M0E1I1 A=00 B=0800 D=0000 H=0119 S=0100 P=0107 MOV A,M C0Z1M0E1I1 A=02 B=0800 D=0000 H=0119 S=0100 P=0108 SUB C C0Z0M0E0I1 A=02 B=0800 D=0000 H=0119 S=0100 P=0109 JNC 010D C0Z0M0E0I1 A=02 B=0800 D=0000 H=0119 S=0100 P=010D INX H C0Z0M0E0I1 A=02 B=0800 D=0000 H=011A S=0100 P=010E DCR B C0Z0M0E0I1 A=02 B=0700 D=0000 H=011A S=0100 P=010F JNZ 0107 C0Z0M0E0I1 A=02 B=0700 D=0000 H=011A S=0100 P=0107 MOV A,M C0Z0M0E0I1 A=00 B=0700 D=0000 H=011A S=0100 P=0108 SUB C C0Z1M0E1I1 A=00 B=0700 D=0000 H=011A S=0100 P=0109 JNC 010D C0Z1M0E1I1 A=00 B=0700 D=0000 H=011A S=0100 P=010D INX H C0Z1M0E1I1 A=00 B=0700 D=0000 H=011B S=0100 P=010E DCR B C0Z0M0E1I1 A=00 B=0600 D=0000 H=011B S=0100 P=010F JNZ 0107 C0Z0M0E1I1 A=00 B=0600 D=0000 H=011B S=0100 P=0107 MOV A,M*0108 -A109 Insert a "hot patch" into Program should have moved the the machine code value from A into C since A>C. 0109 JC 10D to change the Since this code was not executed, JNC to JC it appears that the JNC should 010C have been a JC instruction Stop DDT so that a version of -G0 the patched program can be saved A>\c .sh SAVE 1 SCAN.COM \c .qs Program resides on first page, so save 1 page. A>\c .sh DDT SCAN.COM .qs Restart DDT with the save memory DDT VER 1.0 image to continue testing NEXT PC 0200 0100 -L100 List some code 0100 MVI B,08 0102 MVI C,00 0104 LXI H,0119 0107 MOV A,M 0108 SUB C 0109 JC 010D Previous patch is present in X.COM 010C MOV C,A 010D INX H 010E DCR B 010F JNZ 0107 0112 MOV A,C -XP P=0100 -T10 Trace to see how patched version operates Data is moved from A to C C0Z0M0E0I0 A=00 B=0000 D=0000 H=0000 S=0100 P=0100 MVI B,08 C0Z0M0E0I0 A=00 B=0800 D=0000 H=0000 S=0100 P=0102 MVI C,00 C0Z0M0E0I0 A=00 B=0800 D=0000 H=0000 S=0100 P=0104 LXI H,0119 C0Z0M0E0I0 A=00 B=0800 D=0000 H=0119 S=0100 P=0107 MOV A,M C0Z0M0E0I0 A=02 B=0800 D=0000 H=0119 S=0100 P=0108 SUB C C0Z0M0E0I1 A=02 B=0800 D=0000 H=0119 S=0100 P=0109 JC 010D C0Z0M0E0I1 A=02 B=0800 D=0000 H=0119 S=0100 P=010C MOV C,A C0Z0M0E0I1 A=02 B=0802 D=0000 H=0119 S=0100 P=010D INX H C0Z0M0E0I1 A=02 B=0802 D=0000 H=011A S=0100 P=010E DCR B C0Z0M0E0I1 A=02 B=0702 D=0000 H=011A S=0100 P=010F JNZ 0107 C0Z0M0E0I1 A=02 B=0702 D=0000 H=011A S=0100 P=0107 MOV A,M C0Z0M0E0I1 A=00 B=0702 D=0000 H=011A S=0100 P=0108 SUB C C1Z0M1E0I0 A=FE B=0702 D=0000 H=011A S=0100 P=0109 JC 010D C1Z0M1E0I0 A=FE B=0702 D=0000 H=011A S=0100 P=010D INX H C1Z0M1E0I0 A=FE B=0702 D=0000 H=011B S=0100 P=010E DCR B C1Z0M0E1I1 A=FE B=0602 D=0000 H=011B S=0100 P=010F JNZ 0107*0107 -X Breakpoint after 16 steps C1Z0M0E1I1 A=FE B=0602 D=0000 H=011B S=0100 P=0107 MOV A,M -G,108 Run from current PC and breakpoint at 108H *0108 -X Next data item C1Z0M0E1I1 A=04 B=0602 D=0000 H=011B S=0100 P=0108 SUB C -T Single step for a few cycles C1Z0M0E1I1 A=04 B=0602 D=0000 H=011B S=0100 P=0108 SUB C*0109 -T C0Z0M0E0I1 A=02 B=0602 D=0000 H=011B S=0100 P=0109 JC 010D*010C -X C0Z0M0E0I1 A=02 B=0602 D=0000 H=011B S=0100 P=010C MOV C,A -G Run to completion *0116 -X C0Z1M0E1I1 A=03 B=0003 D=0000 H=0121 S=0100 P=0116 RST 07 -S121 Look at the value of "LARGE" 0121 03 Wrong value! 0122 00 0123 22 0124 21 0125 00 0126 02 0127 7E _\b. End of the S command -L100 0100 MVI B,08 0102 MVI C,00 0104 LXI H,0119 0107 MOV A,M 0108 SUB C 0109 JC 010D 010C MOV C,A 010D INX H 010E DCR B 010F JNZ 0107 0112 MOV A,C -L Review the code 0113 STA 0121 0116 RST 07 0117 NOP 0118 NOP 0119 STAX B 011A NOP 011B INR B 011C INX B 011D DCR B 011E MVI B,01 0120 DCR B -XP P=0116 100 Reset the PC -T Single step, and watch data values C0Z1M0E1I1 A=03 B=0003 D=0000 H=0121 S=0100 P=0100 MVI B,08*0102 -T C0Z1M0E1I1 A=03 B=0803 D=0000 H=0121 S=0100 P=0102 MVI C,00*0104 -T Count set Largest set C0Z1M0E1I1 A=03 B=0800 D=0000 H=0121 S=0100 P=0104 LXI H,0119*0107 -T Base address of data set C0Z1M0E1I1 A=03 B=0800 D=0000 H=0119 S=0100 P=0107 MOV A,M*0108 -T First data item brought to A C0Z1M0E1I1 A=02 B=0800 D=0000 H=0119 S=0100 P=0108 SUB C*0109 -T C0Z0M0E0I1 A=02 B=0800 D=0000 H=0119 S=0100 P=0109 JC 010D*010C -T C0Z0M0E0I1 A=02 B=0800 D=0000 H=0119 S=0100 P=010C MOV C,A*010D -T First data item moved to C correctly C0Z0M0E0I1 A=02 B=0802 D=0000 H=0119 S=0100 P=010D INX H*010E -T C0Z0M0E0I1 A=02 B=0802 D=0000 H=011A S=0100 P=010E DCR B*010F -T C0Z0M0E0I1 A=02 B=0702 D=0000 H=011A S=0100 P=010F JNZ 0107*0107 -T C0Z0M0E0I1 A=02 B=0702 D=0000 H=011A S=0100 P=0107 MOV A,M*0108 -T Second data item brought to A C0Z0M0E0I1 A=00 B=0702 D=0000 H=011A S=0100 P=0108 SUB C*0109 -T Subtract destroys data value that was loaded! C1Z0M1E0I0 A=FE B=0702 D=0000 H=011A S=0100 P=0109 JC 010D*010D -T C1Z0M1E0I0 A=FE B=0702 D=0000 H=011A S=0100 P=010D INX H*010E -L100 0100 MVI B,08 0102 MVI C,00 0104 LXI H,0119 0107 MOV A,M 0108 SUB C This should have been a CMP so that register A 0109 JC 010D would not be destroyed. 010C MOV C,A 010D INX H 010E DCR B 010F JNZ 0107 0112 MOV A,C -A108 0108 CMP C Hot patch at 108H changes SUB to CMP 0109 -G0 Stop DDT for SAVE A>\c .sh SAVE 1 SCAN.COM \c .qs Save memory image A>\c .sh DDT SCAN.COM \c .qs Restart DDT DDT VER 1.0 NEXT PC 0200 0100 -XP P=0100 -L116 .mb 5 .fm 1 0116 RST 07 0117 NOP 0118 NOP Look at code to see if it was properly loaded 0119 STAX B (long typeout aborted with rubout) 011A NOP - -G,116 Run from 100H to completion *0116 -XC Look at carry (accidental typo) C1 -X Look at CPU state .mb 6 .fm 2 C1Z1M0E1I1 A=06 B=0006 D=0000 H=0121 S=0100 P=0116 RST 07 -S121 Look at "large"--it appears to be correct. 0121 06 0122 00 0123 22 -G0 Stop DDT A>\c .sh ED SCAN.ASM \c .qs Re-edit the source program, and make both changes *NSUB *0LT CTRL-Z SUB C ;LARGER VALUE IN C? *SSUB^\b|ZCMP^\b|Z0LT CMP D ;LARGER VALUE IN C? * JNC NFOUND ;JUMP IF LARGER VALUE NOT FOUND *SNC^\b|ZC^\b|Z0LT JC NFOUND ;JUMP IF LARGER VALUE NOT FOUND *E Reassemble, selecting source from disk A A>\c .sh ASM SCAN.AAZ \c .qs <--- Hex to disk A Print to Z (selects no print file) CP/M ASSEMBLER VER 1.0 0122 002H USE FACTOR END OF ASSEMBLY A>\c .sh DDT SCAN.HEX \c .qs Rerun debugger to check changes DDT VER 1.0 NEXT PC 0121 0000 -L116 0116 JMP 0000 Check to ensure end is still at 116H 0119 STAX B 011A NOP 011B INR B -(rubout) -G100,116 Go from beginning with breakpoint at end *0116 Breakpoint reached -D121 Look at "LARGE" Correct value computed 0121 06 00 22 21 00 02 7E EB 77 13 23 EB 0B 78 B1 .. '!... W .#..X. 0130 C2 27 01 C3 03 29 00 00 00 00 00 00 00 00 00 00 .'...)........ 0140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .............. -(rubout) Aborts long typeout G0 Stop DDT, debug session complete. .ll 65 .sp 2 .ce End of Section 4 .nx fivea