0001 ;=============================================================== 0002 ; program VDUMP (filename) 0003 ; 0004 ; VDUMP takes the (unambiguous) name of any file and dumps the 0005 ; file to the console in physical, 128-byte records. 0006 ; 0007 ; Each record is displayed as two, 3-line groups, with the 0008 ; record number in hex appended to the first group. 0009 ; 0010 ; In the first line the data is shown in characters, with 0011 ; control characters in reverse video. The next two lines 0012 ; show the data in hex, with each byte's hex digits lined up 0013 ; vertically. 0014 ; ***************************************************** 0015 ; * This program was originally published in * 0016 ; * A PROGRAMMER'S NOTEBOOK * 0017 ; * Utilities for CP/M-80 * 0018 ; * by David E. Cortesi * 0019 ; * Copyright (C) Reston Publishing Company Inc. 1983 * 0020 ; ***************************************************** 0021 ;=============================================================== 0022 MACLIB CPMEQU ; standard equate-names 0023 MACLIB PROG ; important macros 0024 PROLOG ; enter, set up stack, go to Main 0025 ;=============================================================== 0026 ; The Global Variables... 0027 Record dw 0 ; record count 0028 Index db 0 ; index to next byte in Buffer 0029 Switch db 0 ; Normal/Reverse switch 0030 UsedNormal equ 00h ; values that may be in Switch. 0031 UsedRevers equ 80h 0032 ; 0033 ; The following constants are terminal-hardware-dependent. 0034 ; Substitute the sequence of characters that makes your 0035 ; terminal go reverse-video to normal-video and vice versa. 0036 ; End each sequence with '$', for writing via TypeMessage. 0037 ; 0038 NormalSeq: ; sequence that cancels reverse video 0039 db AsciiESC,'q','$' ; Heath H19, Zenith Z19 0040 ReversSeq: ; sequence that starts reverse video 0041 db AsciiESC,'p','$' ; Heath H19, Zenith Z19 0042 ; 0043 ; Two buffers for saving the hex displays, and their index: 0044 ; 0045 HexIndex: dw 0 0046 HexHi ds 64 ; 64 bytes, then... 0047 db '$' ; ...a dollar sign to end the string. 0048 HexLo ds 64 0049 db '$' 0050 ;=============================================================== 0051 ; the main program -- initialization 0052 Main: 0053 SERVICE BdosOpen,CpmFcb 0054 inr a ; error code FFh becomes 00h 0055 jz Nofile ; no file -- error code at end. 0056 SERVICE BdosSetBuffer,Buffer ; input to our Buffer 0057 mvi a,128 0058 sta Index ; Index := 128 (Buffer is empty) 0059 lxi h,1 0060 shld Record ; Record := 1 0061 mvi a,UsedNormal 0062 sta Switch ; Switch := UsedNormal 0063 lxi h,0 0064 shld HexIndex; HexIndex := 0 0065 ;=============================================================== 0066 ; the main program -- main loop 0067 ; 0068 call Getchar ; A := Getchar 0069 MainWhile: 0070 ora a ; check end-of-file flag in A 0071 jnz MainEnd 0072 ; 0073 call TypeCRLF; type a blank line 0074 mvi b,64 ; do 64 times (count in B) 0075 Main4: 0076 mov a,c ; put data byte in A, 0077 call Output ; ..write it. 0078 call Getchar ; C := next byte, A := flag 0079 DJNZ Main4 ; end do. 0080 ; 0081 call ShowRecord ; show the record number, 0082 call EndLine ; ..end the first line, 0083 TESTCON MainEnd ; ..see if we should quit. 0084 ; 0085 mvi b,64 ; set up for 2nd line. 0086 Main5: 0087 mov a,c ; get data byte, 0088 call Output ; ..write it. 0089 call Getchar ; flag gets set on the 128th call 0090 DJNZ Main5 ; end do. 0091 ; 0092 call EndLine ; end the 2nd line, 0093 lhld Record 0094 inx h 0095 shld Record ; Record := Record + 1 0096 TESTCON MainEnd ; ..see if we should quit. 0097 jmp MainWhile ; end while. 0098 ; 0099 MainEnd: 0100 call GoToNormal ; get terminal back to normal. 0101 ret ; back to prolog, do warm start. 0102 ;--------------------------------------------------------------- 0103 ; Getchar: return the next byte from the file in register C, 0104 ; and an end of file flag in register A. If the current 0105 ; record is exhausted, read another record into the buffer. 0106 ; 0107 ; Assumes: that Buffer is on a page boundary. 0108 ; Output: byte in C. End-of-file flag in A. 0109 ; Preserves: all but A, C, flags. 0110 ;--------------------------------------------------------------- 0111 Getchar: 0112 lda Index 0113 ora a ; Index > 127? 0114 jp Getchar2 ; ..no, continue 0115 ; ...the buffer is empty, read a record into it. 0116 SERVICE BdosRead,CpmFcb 0117 ora a ; non-zero if physical end of file. 0118 rnz ; quit, A nonzero, if true. 0119 ; otherwise continue, A=Index=00 0120 Getchar2: 0121 push h ; save caller's HL, form address 0122 mvi h,HIGH(Buffer) ; ..of data from page 0123 mov l,a ; ..plus Index (in A). 0124 mov c,m ; C := the byte 0125 inr a 0126 sta Index ; Index := Index + 1 0127 xra a ; return zero flag 0128 pop h 0129 ret ; end Getchar. 0130 ;--------------------------------------------------------------- 0131 ; Output sends the byte in A to the console. First stow the 0132 ; hex values of the byte for printing later. Then set off 0133 ; the high bit, because some word processors set Bit 7 in 0134 ; special-purpose carriage returns, etc. Then if the input is: 0135 ; 0136 ; a printable character, set normal video and type it. 0137 ; a control character, translate it to a printable one, 0138 ; set reverse video, and type it. 0139 ; 0140 ; Preserves: all. 0141 ;--------------------------------------------------------------- 0142 Output: 0143 push psw 0144 call StoreHex ; save the hex values. 0145 ani AsciiDEL ; turn off the high bit. 0146 cpi AsciiBlank ; if A<' ' (carry set), control. 0147 JRC Control 0148 cpi AsciiDEL ; likewise if it's a DEL 0149 JRZ Control 0150 ; ...printable, get into normal video 0151 call GoToNormal 0152 JMPR Output2 0153 Control:; ...fix control character, set up reverse video 0154 adi 40h ; make e.g. SUB into Z 0155 jp Control2 ; ..but DEL becomes BFh 0156 mvi a,'~' ; ..make that a tilde. 0157 Control2: 0158 call GoToReverse 0159 Output2: 0160 call Typechar ; type the character 0161 pop psw 0162 ret ; end Output. 0163 ;--------------------------------------------------------------- 0164 ; Get the terminal into normal video mode if it isn't. 0165 ;--------------------------------------------------------------- 0166 GoToNormal: 0167 push psw 0168 push d 0169 mvi a,UsedNormal 0170 lxi d,NormalSeq 0171 JMPR GoToEither 0172 ;--------------------------------------------------------------- 0173 ; Get the terminal into reverse video if it isn't. 0174 ;--------------------------------------------------------------- 0175 GoToReverse: 0176 push psw 0177 push d 0178 mvi a,UsedRevers 0179 lxi d,ReversSeq 0180 GoToEither: 0181 push h 0182 lxi h,Switch 0183 cmp m ; is it how we want it? 0184 mov m,a ; (it is now) 0185 pop h 0186 cnz TypeMessage ; send sequence if it wasn't 0187 pop d 0188 pop psw 0189 ret 0190 ;--------------------------------------------------------------- 0191 ; StoreHex saves the hex display of a byte in HexHi and HexLo. 0192 ;--------------------------------------------------------------- 0193 StoreHex: 0194 push h ; save the registers we'll use 0195 push d ; ..for indexing. 0196 push psw ; save the byte for the caller, 0197 push psw ; ..and for us, too. 0198 lhld HexIndex 0199 xchg ; DE := HexIndex 0200 call HexDisplayL ; put the left hex digit in A 0201 lxi h,HexHi 0202 dad d ; HL-->HexHi[HexIndex] 0203 mov m,a 0204 pop psw ; recover a copy of the data 0205 call HexDisplayR ; put the right hex digit in A 0206 lxi h,HexLo 0207 dad d ; HL-->HexLo[HexIndex] 0208 mov m,a 0209 inx d ; HexIndex := HexIndex + 1 0210 xchg 0211 shld HexIndex 0212 pop psw ; restore 0213 pop d ; the 0214 pop h ; registers 0215 ret 0216 ;--------------------------------------------------------------- 0217 ; Display the record number: the cursor is now in column 65. 0218 ; Type two spaces, then four hex digits of "Record". 0219 ;--------------------------------------------------------------- 0220 ShowRecord: 0221 call GoToNormal 0222 call TypeBlank 0223 call TypeBlank 0224 lhld Record 0225 call TypeXXXX ; TypeXXXX(Record) 0226 ret 0227 ;--------------------------------------------------------------- 0228 ; Endline ends the current 64-byte line of data by: typing 0229 ; CR, LF to end the screen line, then printing HexHi and HexLo 0230 ; each on its own line. Finally another blank line for 0231 ; visual separation. HexIndex is reset. 0232 ;--------------------------------------------------------------- 0233 EndLine: 0234 push d 0235 call GoToNormal ; avoid printing hex in reverse 0236 call TypeCRLF ; end the current line 0237 lxi d,HexHi 0238 call TypeMessage ; print the upper hex row 0239 call TypeCRLF ; ..and end it. 0240 lxi d,HexLo 0241 call TypeMessage ; print the lower hex row 0242 call TypeCRLF 0243 xchg ; save HL for a moment 0244 lxi h,0 ; ..while we clear HexIndex 0245 shld HexIndex 0246 xchg 0247 pop d ; type a blank, via a 0248 jmp TypeCRLF ; ..call-and-return to TypeCRLF 0249 ;--------------------------------------------------------------- 0250 ; Nofile: the input file doesn't exist. Abort with the 0251 ; message No File, avoiding the problems we had in FDUMP. 0252 ;--------------------------------------------------------------- 0253 Nofile: 0254 ABORT NoFileMsg 0255 NoFileMsg: db 'No File','$' 0256 ;=============================================================== 0257 ; the included subroutines... 0258 ; #include TypeSubs.Inc,TypeCommon -- TypeChar, -Message, etc. 0259 ; #include TypeSubs.Inc,TypeXXXX (includes HexDisplayL/R) 0260 ;=============================================================== 0261 ; The record buffer, at the end to make the .COM file smaller. 0262 ; Also on a page boundary, don't forget. 0263 ORGPAGE 0264 Buffer: ds 128 0265 ; 0266 ; For MP/M, the .HEX file should account for the full size of 0267 ; the program, so enable the next instruction: 0268 ; db 0 0269 END * CROSS-REFERENCE * def. val. symbol and uses * ---- 0020 ASCIIBLANK CPI-146 * ---- 007F ASCIIDEL ANI-145 CPI-148 * ---- 001B ASCIIESC DB-39 -41 * ---- 000F BDOSOPEN SERVICE-53 * ---- 0014 BDOSREAD SERVICE-116 * ---- 001A BDOSSETBUFFER SERVICE-56 * 0264 0400 BUFFER SERVICE-56 MVI-122 * 0153 02BE CONTROL JRC-147 JRZ-149 * 0157 02C5 CONTROL2 JP-155 * ---- 005C CPMFCB SERVICE-53 -116 * 0233 031D ENDLINE CALL-82 -92 * 0111 0285 GETCHAR CALL-68 -78 -89 * 0120 029C GETCHAR2 JP-114 * 0180 02DE GOTOEITHER JMPR-171 * 0166 02CD GOTONORMAL CALL-100 -151 -221 -235 * 0175 02D7 GOTOREVERSE CALL-158 * ---- 039A HEXDISPLAYL CALL-200 * ---- 039E HEXDISPLAYR CALL-205 * 0046 0162 HEXHI LXI-201 -237 * 0045 0160 HEXINDEX SHLD-64 LHLD-198 SHLD-211 -245 * 0048 01A3 HEXLO LXI-206 -240 * 0028 0158 INDEX STA-58 LDA-112 STA-126 * 0052 01E4 MAIN * 0075 0226 MAIN4 DJNZ-79 * 0086 0251 MAIN5 DJNZ-90 * 0099 0281 MAINEND JNZ-71 TESTCON-83 -96 * 0069 021D MAINWHILE JMP-97 * 0253 0342 NOFILE JZ-55 * 0255 034A NOFILEMSG ABORT-254 * 0038 015A NORMALSEQ LXI-170 * 0142 02A8 OUTPUT CALL-77 -88 * 0159 02C8 OUTPUT2 JMPR-152 * 0027 0156 RECORD SHLD-60 LHLD-93 SHLD-95 LHLD-224 * 0040 015D REVERSSEQ LXI-179 * 0220 030D SHOWRECORD CALL-81 * 0193 02EB STOREHEX CALL-144 * 0029 0159 SWITCH STA-62 LXI-182 * ---- 0352 TYPEBLANK CALL-222 -223 * ---- 0371 TYPECHAR CALL-160 * ---- 0358 TYPECRLF CALL-73 -236 -239 -242 JMP-248 * ---- 0368 TYPEMESSAGE CNZ-186 CALL-238 -241 * ---- 0380 TYPEXXXX CALL-225 * 0030 0000 USEDNORMAL MVI-61 -169 * 0031 0080 USEDREVERS MVI-178 * CENSUS OF OPCODE USAGE * * ABORT 1 ADI 1 ANI 1 * CALL 26 CMP 1 CNZ 1 * CPI 2 DAD 2 DB 7 * DJNZ 2 DS 3 DW 2 * END 1 EQU 2 INR 2 * INX 2 JMP 2 JMPR 2 * JNZ 1 JP 2 JRC 1 * JRZ 1 JZ 1 LDA 1 * LHLD 3 LXI 10 MACLIB 2 * MOV 7 MVI 8 ORA 3 * ORGPAGE 1 POP 10 PROLOG 1 * PUSH 12 RET 6 RNZ 1 * SERVICE 3 SHLD 5 STA 3 * TESTCON 2 XCHG 4 XRA 1