.PAGE 80,63 ;DISK EXAMINE/MODIFY UTILITY. ; This utility allows the user to examine absolute ;addresses on a disk. Additionally he may alter, character by ;charater, the contents of any given sector. Entire sectors ;may be moved from the bufer onto the disk. ; All I/O is done through the BIOS for CPM. There are ;no calls made to the BDOS. ; ;D.A. BARKER, January 1980. ; .PABS .SALL .OPSYN .BLKB,DS .OPSYN .BYTE,DB .OPSYN .WORD,DW ; .IDENT LOOK .PROGID EXAM,1,2 ; ; ; ***************** ; * MISC. EQUATES * ; ***************** ; TEST = 0 CR = 0DH LF = 0AH DMADD = 80H QUIT = 0 ;USE CPM ENTRY ESC = 1BH MAXDRV = 2 NSECS = 26 MAXGP = 243 ; ; ************************* ; * I/0 ENTRY DEFINITIONS * ; ************************* ; COUT = 12 ;THE FOLLOWING ARE BIOS JUMP TABLE KEYIN = 9 ; ENTRY POINTS FOR THE VARIOUS .SETDMA = 36 ; ROUTINES .SELDSK = 27 .SETTRK = 30 .SETSEC = 33 .READ = 39 .WRITE = 42 ; ; ********************** ; * STRING DEFINITIONS * ; ********************** ; .DEFINE ST1 =[ -- LOOK -- VERSION 1.3 -- D. A. BARKER OCT. 21, 1980 ] .DEFINE ST2 =[ Drive:] .DEFINE ST3 =[ Track:] .DEFINE ST4 =[ Sector:] .DEFINE ST4.5 =[ Group:] .DEFINE ST5 =[ Display is from:] .DEFINE ST6 =[ Auto-read is:] ; ; ********************* ; * MACRO DEFINITIONS * ; ********************* ; ; CURSOR ADDRESSING ; This routine should produce the sequence of characters ;necessary to position the cursor. The third parameter should ;not require alteration. ; .DEFINE XY [ROW,COL,Z(0)] = [ DB ROW,COL .IFE Z, DB 0 ] ; ; INVERTING A STRING VALUE ; This routine sets the MSB of each character of the ;argument string. This is used for inverse video when the ;IObyte has been altered to accept inverse video rather than ;xy-addressing ; ; I/O FUNCTIONS ; Setup and do a BIOS function (FUNC). ; .DEFINE GODO [FUNC] = [ PUSH H PUSH D LXI D,FUNC CALL IOCALL POP D POP H ] ; .DEFINE TYPE = [CALL TYPEX] ; .DEFINE PRINT = [CALL PRNTMSG] ; .DEFINE XYPR = [CALL POSPR] ; ; GETKEY will set the zero flag if an Escape is typed. ; .DEFINE GETKEY = [CALL GK] ; ; THE MAIN PROGRAM BEGINS ; .LOC 0100H ;MAKE IT A CPM TRANSIENT ; EXAM: INIT: LXI B,DMADD ;THIS WILL NEVER CHANGE GODO .SETDMA LXI H,100H SHLD DSKTBL LXI D,DSKTBL+2 LXI H,DSKTBL LXI B,10 LDIR ;INITIALIZE VARIOUS POINTERS ; LXI H,DMADD MVI M,0 LXI D,DMADD+1 LXI B,127 LDIR ;CLEAR THE BUFFER AREA ; CLEAR: CALL CLRSC ; CALL WHITE ;INVERT THE VIDEO PRINT .ASCII ST1 ;PRINTING THE HEADER DB CR,LF ;BLOCK AND STATUS DISPLAYS .ASCII ST2 .ASCII ST3 .ASCII ST4 .ASCII ST4.5 .ASCII / / DB CR,LF .ASCII ST5 .ASCII ST6 .ASCII / / DB 0 CALL BLACK REENT: LXI SP,STACK ;ENTRY HERE WILL UPDATE ALL XYPR ; STATUS DISPLAYS XY [1,@ST2] LHLD DRIVE MVI A,'A' ADD L TYPE XYPR XY [1,@ST2+@ST3] MVI H,0 DAD H LXI D,DSKTBL DAD D MOV A,M CALL HEXOUT XYPR XY [1,@ST2+@ST3+@ST4] INX H MOV A,M CALL HEXOUT ; XYPR XY [1,@ST2+@ST3+@ST4+@ST4.5] PUSH H MOV A,M LXI H,GPTBL+NSECS LXI B,NSECS CCDR ;BC NOW CONTAINS LOGICAL SECTOR # POP H DCX H MOV L,M MVI H,0 DCR L DCR L ;TRACK-2 JP .VALID ;JMP IF TRACK > 1 PRINT .ASCIZ /SYS*/ JMPR .NTV ; NOW MULTIPLY HL BY 26 .VALID: DAD H ;X2 PUSH H POP D DAD H ;X4 DAD H ;X8 XCHG DAD D XCHG ;DE IS NOW X10 DAD H ;X16 DAD D ;X26 DAD B ;HL NOW THE TOTAL SECTOR NUMBER ;NOW DIVIDE BY 8 MOV A,L ANI 0F8H ORA H RRC RRC RRC CALL HEXOUT MVI A,':' TYPE MOV A,L ;GET REMAINDER ANI 7 ADI '1' ;ADD ASCII BIAS & INCREMENT TYPE ; .NTV: LDA AUTONO ORA A ;CHECK FOR AUTO-READ JNZ RDSK ;JUMP IF AUTO-READ ; XYPR XY [2,@ST5,1] .ASCIZ / BUFFER/ JMPR LP RDRTN: XYPR ;EVERY DISK READ OR WRITE WILL XY [2,@ST5,1] ; RETURN HERE AND UPDATE THE .ASCIZ / DISK / ; SECOND STATUS LINE LP: LXI H,AUTONO XYPR XY [2,@ST5+@ST6] MOV A,M ORA A JRZ ..OFF PRINT .ASCIZ / ON / JMPR ..ON ..OFF: PRINT .ASCIZ / OFF/ ..ON: CALL SPIT ;SPIT THE BUFFER ONTO THE SCREEN ; ; ********************* ; * COMMAND PROCESSOR * ; ********************* ; GETCOM: XYPR XY [15,0] CALL ERAL ;ERASE THE PROMPT LINE GETKEY ;GET THE COMMAND CHARACTER LXI H,CMDADD-1 LXI B,CMDADD-CMDTBL+1 CCDR ;SCAN THE TABLE BACKWARDS LXI H,CMDADD DAD B DAD B ;HL NOW POINTS TO THE ROUTINE'S ADDRESS MOV E,M INX H MOV D,M PUSH D ;SO A 'RET' WILL GO TO THE ROUTINE SETUP: LHLD DRIVE MOV C,L MVI H,0 DAD H LXI D,DSKTBL DAD D ;HL POINT TO CURRENT DISK'S TRACK LOC. LXI D,0 RET ;GO EXECUTE THE CHOSEN ROUTINE ; ; ********************* ; * THE COMMAND TABLE * ; ********************* ; CMDTBL: .ASCII /DTSIO+-GNLRWAHCQM?/[3] CMDADD: DW INFO,SELDRV,SELTRK,SELSEC,STPIN DW STPOUT,NXSEC,LSTSEC,GROUP,NXGP DW LSTGP,READ,WRITE,ASC,HXCMD DW CLEAR,QUIT,MODE,INFO,QUIT ; SELDRV: CALL ERAL PRINT .ASCIZ /DRIVE NUMBER?/ MVI E,0 ;FOR THE GHX ROUTINE CALL GHX CPI MAXDRV JRNC SELDRV STA DRIVE JMP REENT ; SELTRK: CALL ERAL PRINT .ASCIZ /DESIRED TRACK?/ CALL GETHEX CPI 77 ;MAXIMUM TRACK NUMBER + 1 JRNC SELTRK MOV M,A JMP REENT ; SELSEC: CALL ERAL PRINT .ASCIZ /DESIRED SECTOR?/ CALL GETHEX ORA A JRZ SELSEC CPI NSECS+1 JRNC SELSEC INX H ;POINT TO CURRENT DRIVE'S SECTOR LOC. MOV M,A JMP REENT ; NXSEC: INX H MOV A,M INR A CPI NSECS+1 JRNC ..NXT MOV M,A JMP REENT ;STAY ON SAME TRACK ..NXT: MVI A,1 MOV M,A DCX H ;POINT TO CURRENT TRACK LOCATION JMPR STPIN ; LSTSEC: INX H MOV A,M DCR A ORA A JRZ ..LST MOV M,A JMP REENT ;STAY ON THE SAME TRACK ..LST: ADI 26 MOV M,A DCX H ;POINT TO CURRENT TRACK LOCATION JMPR STPOUT ; NXGP: INX H ;GET PRESENT SECTOR # MOV A,M LXI B,NSECS XCHG ;PUT SECTOR TABLE POINTER IN DE LXI H,GPTBL+1 ;POINT TO 2ND ENTRY OF THIS TABLE CCIR ;SEARCH FOR THE PRESENT SECTOR MOV A,M ;GET THE NEXT SECTOR XCHG ;POINT HL TO THE TABLE MOV M,A JPE REENT ;ODD PARITY MEANS END OF TABLE DCX H STPIN: MOV A,M CPI 76 ;MAXIMUM TRACK NUMBER JNC REENT INR M JMP REENT ; LSTGP: INX H MOV A,M LXI B,NSECS XCHG LXI H,GPTBL+NSECS CCDR MOV A,M XCHG MOV M,A JPE REENT DCX H STPOUT: MOV A,M ORA A JZ REENT DCR M JMP REENT ; ; ********************* ; * SECTOR SKEW TABLE * ; ********************* ; Assuming a sector interleave of 6 sectors ; GPTBL: DB 22,1,7,13,19,25,5,11,17 DB 23,3,9,15,21,2,8,14,20 DB 26,6,12,18,24,4,10,16,22,1 ; GROUP: CALL ERAL PRINT .ASCIZ /GROUP NUMBER?/ CALL GETHEX CPI MAXGP+1 JRNC GROUP MVI A,0FFH XCHG ;HL CONTAIN THE GROUP NUMBER DAD H ;MULTIPLY # BY 8 DAD H DAD H LXI B,-NSECS ..AGN: INR A ;DIVIDE THE # BY NSECS DAD B JRC ..AGN ADI 2 ;QUOTIENT PLUS 2 IS NEW TRACK # STAX D DSBC B ;HL IS THE LOGICAL SECTOR NUMBER LXI B,GPTBL+1 DAD B ;(HL) IS NOW THE PHYSICAL SECTOR # MOV A,M INX D STAX D JMP REENT ; MODE: LDA AUTONO ;TOGGLE THE AUTO-READ MODE INR A ANI 1 STA AUTONO JNZ RDSK JMP RDRTN ; ASC: CALL ERAL PRINT .ASCIZ /ASCII BYTE NUMBER?/ CALL GETHEX CPI 80H JRNC ASC ..AGN: CALL MCUR ;Position the cursor on the screen. CALL ACUR CALL MCUR0 JRNC ..AGN MOV M,A ;Update the DMA buffer. MVI C,1 ;Ready to advance by one. CALL RESTO JMPR ..AGN ; HXCMD: CALL ERAL PRINT .ASCIZ /HEX BYTE NUMBER?/ CALL GETHEX CPI 80H JRNC HXCMD ..AGN: CALL MCUR CALL HCUR CALL MCUR0 JRNC ..AGN CALL HEXFIL MVI C,0 JRZ ..FWD MOV M,A INR C ..FWD: CALL RESTO JMPR ..AGN ; MCUR: MOV E,A ;THE CURSOR POINTER MVI D,0 LXI H,DMADD DAD D ;HL TO THE CP IN THE BUFFER CALL HCUR ;POSITION THE HEX CURSOR CALL BTYPE CALL BTYPE CALL ACUR ;THE ASCII CURSOR JMP BTYPE MCUR0: GETKEY JZ GIT ;LEAVE ON AN 'ESC' MVI C,-1 CPI 'H'-40H ;MOVE LEFT? RC JRZ RESTO MVI C,10H CPI 'J'-40H RC JRZ RESTO MVI C,1 CPI 'L'-40H JRZ RESTO CMC RC MVI C,-10H RESTO: PUSH B CALL RS POP B MOV A,E ADD C ANI 7FH ;INSURE IN SECTOR RET ; RS: CALL HCUR MOV A,M CALL HEXOUT CALL ACUR MOV A,M ANI 7FH CPI 20H JRNC ..FW MVI A,'.' ..FW: CPI 0FFH JRNZ ..AGN MVI A,'.' ..AGN: TYPE RET ; HCUR: PUSH D MOV A,E RRC RRC RRC RRC ANI 0FH ADI 5 MOV D,A MOV A,E ANI 0FH RLC MOV E,A CALL DEXY MOV A,D POP D MOV D,A RET ACUR: PUSH D MOV A,E ANI 0FH ADI 24H MOV E,A CALL DEXY POP D RET ; GIT: CALL RS LXI H,0 SHLD AUTONO JMP REENT ; HEXFIL: CALL HEXIT RZ MOV B,A ..AGN: GETKEY RZ CPI CR JRZ ..XIT CALL HEXIT JRC ..AGN RLCR B RLCR B RLCR B RLCR B ORA B MOV B,A XRA A INR A ;JUST TO CLEAR Z-FLAG ..XIT: MOV A,B RET ; RDSK: CALL SETUP READ: CALL IOSET XYPR XY [13,0] GODO .READ .IFN TEST, [ ORA A JZ RDRTN XYPR XY [15,0,1] .ASCIZ / ERROR ON READ!! / GETKEY ] JMP RDRTN WRITE: CALL IOSET XYPR XY [13,0] GODO .WRITE JMP RDRTN IOSET: GODO .SELDSK MOV C,M GODO .SETTRK INX H MOV C,M GODO .SETSEC RET ; INFO: CALL CLRSC ;SPLASH THE HELP TEXT TO THE SCREEN XYPR XY [0,24,1] .ASCII /COMMAND SUMMARY/[CR][LF] .ASCII /D: select Drive (0,1,2,3) / .ASCII /R: Read the current sector/[CR][LF] .ASCII /T: select Track (0 - 4C) / .ASCII /W: Write buffer to disk/[CR][LF] .ASCII /S: select Sector (1 - 26) / .ASCII /M: toggle the auto-read Mode/[CR][LF] .ASCII /I: step In /[CR][LF] .ASCII /O: step Out / .ASCII /A: ASCII fill the buffer/[CR][LF] .ASCII / / .ASCII /H: Hex fill the buffer/[CR][LF] .ASCII /+: next physical sector /[CR][LF] .ASCII /-: last physical sector / .ASCII /^H: move cursor left/[CR][LF] .ASCII / / .ASCII /^L: move cursor right /[CR][LF] .ASCII /The following 3 commands / .ASCII /^J: move cursor down /[CR][LF] .ASCII /assume sector interleave of 6 / .ASCII /^K: move cursor up /[CR][LF] .ASCII /G: Group selection / .ASCII /C: re-initialize the screen /[CR][LF] .ASCII /N: Next logical sector / .ASCII /Q: exit to CPM/[CR][LF] .ASCII /L: Last logical sector / .ASCII /^C: " " "/[CR][LF][0] XYPR XY [15,17,1] .ASCIZ /Esc: general command Escape./ GETKEY JMP CLEAR ; ; ********************* ; * MISC. SUBROUTINES * ; ********************* ; ; IOCALL: LHLD 1 ;PICK UP THE BASE OF THE BIOS MVI L,0 DAD D PCHL ;GO TO THE REQUESTED ROUTINE ; BTYPE: MVI A,'_' TYPEX: MOV C,A GODO [COUT] RET ; POSPR: XTHL MOV D,M INX H MOV E,M CALL DEXY JMPR POSPR1 PRNTMSG: XTHL MOV A,M ZAGN: TYPE POSPR1: INX H MOV A,M ORA A JRNZ ZAGN INX H XTHL RET ; HEXOUT: PUSH B ;SAVE BC MVI B,1 ;ITERATION COUNT MOV C,A RAR RAR RAR RAR ..AGN: ANI 0FH PUSH B ADI '0' CPI '9'+1 JRC ..OUT ADI 7 ..OUT: TYPE POP B DCR B JRNZ ..DUN MOV A,C JMPR ..AGN ..DUN: POP B RET ; ; READ HEX VALUES IN FROM THE KEYBOARD ; GETHEX: GETKEY JZ REENT CALL HEXIT JRC GETHEX MOV E,A MOV A,C TYPE GHX: GETKEY JZ REENT CPI CR JRZ ..EX CALL HEXIT JRC GHX RLCR E RLCR E RLCR E RLCR E ORA E MOV E,A MOV A,C TYPE ..EX: MOV A,E RET ; ; CONVERT THE CONTENTS OF THE ACCUMULATOR TO ; HEXIDECIMAL. SET CARRY ON ILLEGAL CHARACTERS ; HEXIT: MOV C,A SUI 30H RC CPI 0AH CMC RNC SUI 7 CPI 0AH RC CPI 10H CMC RET GK: GODO KEYIN CPI ESC RET ; ; ************************************** ; * DISPLAY THE CONTENTS OF THE BUFFER * ; ************************************** ; SPIT: XYPR XY [5,0] LXI H,DMADD MVI B,8 ;FOR 8 ROWS OF INFO PUSH H ..BGN: MVI C,10H ;FOR 16 COLUMNS OF INFO LXI H,..BUF XTHL ;HL TO BUFFER AND STACK TO ..BUF ..AGN: MOV A,M CALL HEXOUT MOV A,M ANI 7FH CPI 7FH JRZ ..BD CPI ' ' JRNC ..OK ..BD: MVI A,'.' ..OK: XTHL ;GET THE ..BUF POSITION. MOV M,A INX H XTHL INX H ;ADVANCE IN THE BUFFER DCR C ;SEE IF THERE IS MORE ON THIS LINE JRNZ ..AGN XTHL PRINT .ASCII / / ..BUF: DS 10H DB CR,LF,0 DCR B ;MORE FROM THIS SECTOR? JRNZ ..BGN POP H RET DSKTBL: DS 8 ;ROOM ENOUGH FOR 4 DRIVES DRIVE: DS 1 ;CURRENT DRIVE AUTONO: DS 1 ;AUTO OR MANUAL READ DS 32 STACK: DS 1 CLRSC: PRINT .ASCIZ [ESC]/E/[0][0] RET BLACK: PRINT .ASCIZ [ESC]/q/[0][0] RET WHITE: PRINT .ASCIZ [ESC]/p/[0][0] RET ERAL: PRINT .ASCIZ [CR][ESC]/l/[0][0] RET DEXY: MVI A,ESC TYPE MVI A,'Y' TYPE MOV A,D ;THE ROW NUMBER ADI 20H TYPE MOV A,E ;THE COLUMN NUMBER ADI 20H TYPE RET .END EXAM