;                       --- DUMP ---
;
;                                       BY: S. J. SINGER
;
;       THIS PROGRAM IS AN IMPROVED DUMP UTILITY FOR CP/M. ANY CPM FILE
;MAY BE DUMPED TO THE CONSOLE IN A FORMAT SIMILAR TO THAT USED BY THE
;DDT DUMP COMMAND. IN ADDITION, ANY SECTOR OR GROUP OF SECTORS MAY
;BE DUMPED IN THE SAME FORMAT.
;       THE CURRENT VERSION OF DUMP SUPPORTS 4 DISK DRIVES DESIGNATED
;A, B, C, AND D RESPECTIVELY.
;
;                       -- OPERATION --
;
;       THE PROGRAM MAY BE RUN EITHER BY TYPING DUMP, OR DUMP FOLLOWED
;BY THE FILE NAME OR TRACK AND SECTOR. IF DUMP  IS TYPED THE PROGRAM
;RESPONDS WITH A HEADING FOLLOWED BY A '*' AND WAITS FOR MORE INPUT.
;OPERATION IN THIS MODE IS SIMILAR TO OTHER UTILITIES LIKE PIP OR DDT.
;       THE OPERATION DESIRED MAY THEN BE TYPED IN AS FOLLOWS:
;
;               DUMP FILE.NAM
;               DUMP A:FILE.NAM
;               DUMP B:FILE.NAM
;
;       OR DUMP MAY BE TYPED SEPARATELY AS:
;
;               DUMP
;
;               *FILE.NAM
;               *B:FILE.NAM     (THE * IS A PROGRAM PROMPT)
;
;       THE PROGRAM MAY ALSO BE USED TO DUMP DISK SECTORS DIRECTLY,
;DUMP ANY CP/M EIGHT SECTOR GROUP OR A MAP OF THE GROUP ALLOCATIONS FOR THE
;ENTIRE DISK.
;
;               DUMP TRACK 3 SECTOR 7
;               DUMP TRACK 5   SECTOR  3 - 9
;               DUMP TRACK   6   (DUMPS ALL 26 SECTORS)
;               DUMP GROUP  19
;               DUMP MAP
;
;       THE WORDS TRACK, SECTOR AND GROUP MAY BE ABREVIATED AS FOLLOWS
;
;               DUMP G 4
;               DUMP T 7 S 3-4
;               *TRACK 5 S 6
;               *SECTOR 2- 9  T 14
;
;
;               DUMP B:  TRACK 3
;               DUMP D: T 9   S 4-6
;               DUMP C:   G  5
;               DUMP B:MAP
;
;       NOTE THAT THE FORMAT IS QUITE FREE. SPACES ARE USUALLY IGNORED
;THEY ARE ONLY REQUIRED AFTER THE WORDS TRACK AND SECTOR OR T AND S,
;AND AFTER THE WORD DUMP.
;       A TRACK MAY ALSO BE DUMPED WITH ALL THE ADDRESS AND FORMATTING
;INFORMATION. THIS FEATURE IS USEFUL FOR RECOVERING "CRASHED" DISKS, AND
;FOR EVALUATING HARDWARE PROBLEMS OR MODIFICATIONS. UNFORTUNATELY THE TRACK
;READ FEATURE IS HARDWARE SPECIFIC AND NOT SUPPORTED BY CP/M. THE CODE
;CONTAINED IN THIS SECTION OF THE DUMP PROGRAM IS FOR THE WESTERN DIGITAL 1771
;AND TARBELL FLOPPY DISK CONTROLER. TO DUMP AN ENTIRE TRACK TYPE:
;
;               DUMP TRACK 5 FORMAT
;               *C:T  3    FORMAT
;
;       A LIMITED EDITING FEATURE IS INCLUDED IN THE DUMP UTILITY TO
;ALLOW CHANGING DATA ON THE DISK. THE EDIT FEATURE WORKS AS FOLLOWS.
;ANY SINGLE SECTOR ON EITHER DRIVE MAY BE EDITED BY REQUESTING DISPLAY
;OF THE SECTOR FOLLOWED BY THE WORD EDIT.
;
;               DUMP B:TRACK 4 SECTOR 2  EDIT
;
;       THE REQUESTED SECTOR WILL BE DISPLAYED FOLLOWED BY AN EDIT PROMPT
;
;       EDIT -
;
;       ENTER THE ADDRESS OF THE FIRST BYTE TO BE CHANGED. THE PROGRAM WILL
;RESPOND BY TYPING BACK THE ADDR ENTERED AND THE PRESENT CONTENTS OF THAT
;ADDRESS. TO CHANGE THE CONTENTS OF THE ADDRESS ENTER THE NEW BYTE FOLLOWED
;BY A CARRIAGE RETURN. THE PROGRAM WILL DISPLAY THE NEXT ADDRESS AND ITS
;CONTENTS. TO STOP ENTERING DATA TYPE A PERIOD. THE PROGRAM WILL REDISPLAY
;THE SECTOR SHOWING THE CHANGES MADE. THE EDIT FEATURE WORKS ALMOST EXACTLY
;LIKE THE S ENTRY FEATURE IN DDT. TYPING ONLY A CARRIAGE RETURN OMITS ENTRY.
;       TYPING A PERIOD MERELY REDISPLAYS THE SECTOR FROM MEMORY, IT DOES
;NOT CAUSE IT TO BE WRITTEN BACK ON THE DISK. WHEN EDITING IS COMPLETE,
;REDISPLAY THE SECTOR BY TYPING A PERIOD AND TYPE
;
;               WRITE           (WRITE SECTOR BACK TO SAME LOCATION)
;               WRITE T 3 S 4   (WRITE SECTOR TO SPECIFIED LOACTION)
;               WRITE  B:TRACK 5 SECTOR  7
;
;               STOP            (STOP EDITING WITHOUT WRITING ON DISK)
;
;       ALL EDIT ENTRIES MUST BE MADE IN HEX. ENTERING NON HEX CHARACTERS
;RESULTS IN AN ERROR MESSAGE. THE PERMISSABLE ADDRESS RANGE IS 0000 TO 007F.
;LARGER ADDRESSES GIVE AN ERROR MESSAGE. WHEN ENTERInG A GROUP OF BYTES THE
;ADDRESSES ARE COMPUTED MODULO 128, THE NEXT ADDRESS AFTER 007F IS 0000.
;       THE EDIT FEATURE SHOULD BE USED WITH CAUTION SINCE IT IS POSSIBLE
;TO EDIT CP/M TO "DEATH" BY CHANGING A SINGLE BYTE. ONE OCCASIONAL VALUABLE
;USE IS TO RESTORE FILES THAT HAVE BEEN ACCIDENTALLY ERASED. ERASING A FILE
;USING THE ERA COMMAND DOES NOT ERASE THE DATA FROM THE DISK, BUT ONLY ENTERS
;AN E5 INTO THE FIRST BYTE OF THE DIRECTORY. TO RESTORE A FILE, DISPLAY
;THE DIRECTORY BY DISPLAYING GROUPS 0 AND 1. FIND THE SECTOR CONTAINING THE
;NAME OF THE FILE TO BE RESTORED AND DISPLAY IT USING THE EDIT FEATURE
;CHANGE THE BYTE PRECEEDING THE FILE NAME FROM E5 TO 00 AND WRITE THE SECTOR
;BACK ON THE DISK. THIS WILL RESTORE THE FILE PROVIDED NONE OF THE SECTORS
;IN THE FILE WERE CHANGED AFTER THE FILE WAS "ERASED".
;
;       AN ADDITIONAL FEATURE OF DUMP IS THE ABILITY TO VALIDATE A DISK.
;
;               DUMP VALIDATE
;               DUMP A:VALIDATE
;               DUMP C:VALIDATE
;
;       THIS CAUSES THE ENTIRE DISK SELECTED TO BE READ ONE SECTOR AT A
;TIME. THE SECTOR NUMBER OF ANY SECTOR CAUSING A READ ERROR WILL BE DISPLAYED.
;WHEN VALIDATING THE PROGRAM READS EVERY FIFTH SECTOR FOR SPEED.
;
;       AS WITH OTHER CP/M UTILITIES ^S "FREEZES" THE DISPLAY, AND ^C
;RETURNS TO THE MONITOR. DUMP CONTAINS MANY ERROR AND CONSISTANCY
;CHECKS. THE RESULTING MESSAGES SHOULD BE SELF EXPLANATORY.
;
;       DUMP WAS ASSEMBLED USING THE CP/M MACRO ASSEMBLER, AND USES A LARGE
;NUMBER OF MACROS INCLUDED IN A LIBRARY CALLED MACRO.LIB
;
       MACLIB  MACRO           ;INCLUDE MACRO LIBRARY
       ORG     100H            ;SET PROG START
       LXI     H,0
       DAD     SP              ;GET STACK POINTER
       SHLD    OLDSTK
       LXI     SP,NEWSTK       ;SET UP NEW STACK
       DISKIO  ?DRIVE          ;GET CUPRENTLY LOGGED DRIVE NO
       STA     DRVNO           ;SAVE ORIGINAL DRIVE NUMBER
       STA     NEWDRV          ;ALSO SAVE IN NEW DRIVE NO
       LDA     81H             ;CONSOLE INPUT ALREADY HERE ?
       ORA     A
       JZ      SIGNON          ;BUFFER EMPTY, INPUT FROM CONSOLE
       LDA     80H             ;GET NO OF CHAR INPUT
       ORI     80H             ;ADD 128
       MOV     L,A             ;TO L
       XRA     A               ;ZERO
       MOV     H,A             ;HL CONTAINS ADDR OF END OF BUFFER
ZBFF:   INR     L
       JZ      START           ;REMAINDER OF BUFFER ZEROED
       MOV     M,A
       JMP     ZBFF            ;LOOP
SIGNON: PRINT   <CR,LF,'CP/M DUMP UTILITY (AUG 5 1978)',CR,LF>
       PRINT   <'COPYRIGHT 1978 BY S. J. SINGER',CR,LF>
NEWIN:  PRINT   <CR,LF,'*'>
       MVI     A,0FFH          ;SET SWITCH TO RETURN HERE AGAIN
       STA     INFLAG
       LXI     SP,NEWSTK       ;RESET STACK POINTER
       XRA     A
       STA     VALFLG          ;RESET VALIDATION ERROR FLAG
       LXI     H,0
       SHLD    LINE            ;SET LINE COUNT TO ZERO
       FILL    80H,0FFH        ;ZERO INPUT BUFFER
       INPUT   80H             ;READ FILE NAME
;
;  SELECT DISK DRIVE AND SET UP FILE CONTROL BLOCK
;
START:  FILL    FCB,FCB+32      ;ZERO FILE CONTROL BLOCK
       LXI     H,82H           ;POINT TO START OF INPUT BUFFER
       CALL    GETDRV          ;GET DRIVE NAME FROM INPUT BUFFER
       JNC     GETNAM          ;DEFAULT TO A IF NO DISK NAME
       STA     NEWDRV          ;SAVE DRIVE NAME
DOWN:   MOVE    82H,80H,40H     ;SHIFT BUFFER DOWN TWO BYTES
;
;  SEARCH FOR DIRECT READ OF TRACK AND SECTOR OR VALIDATE
;
GETNAM: INSTR   82H,40H,'VALIDATE'
       JC      VALID           ;VALIDATE DISK
       INSTR   82H,40H,'GROUP'
       JC      GROUP           ;DISPLAY CPM 8 SECTOR GROUP
       INSTR   82H,40H,'G '    ;SEARCH FOR 'G'
       JC      GROUP           ;DISPLAY GROUP
       INSTR   82H,40H,'MAP'   ;ALLOCATION MAP
       JC      MAP             ;DISPLAY GROUP ALLOCATION MAP
       INSTR   82H,40H,'TRACK' ;SEARCH FOR TRACK
       JC      TRK1
       INSTR   82H,40H,'T '    ;SEARCH FOR 'T'
       JNC     FILNAM          ;NO TRACK GO TO READ FILE
TRK1:   SCAN                    ;FIND AND CONVERT NUMBER
       DECIN
       JC      INERR           ;INPUT ERROR ON CARRY
       STA     TRACK           ;SAVE TRACK NO
       INSTR   82H,40H,'FORMAT'        ;SEARCH FOR FORMAT
       JC      FORMAT          ;DUMP TRACK WITH ADDR INFO
       INSTR   82H,40H,'SECTOR'        ;SEARCH FOR SECTOR
       JC      SEC1
       INSTR   82H,40H,'S '    ;TRY 'S'
       JNC     WHLTRK          ;DUMP ENTIRE TRACK
SEC1:   SCAN
       DECIN
       JC      INERR           ;INPUT ERROR ON CARRY
       STA     BSEC            ;BEGINNING SECTOR
       STA     ESEC            ;SAVE IN END SECTOR ALSO
       XCHG                    ;SET BUFFER POINTER FOR SCAN
       SHLD    IPOINT          ;SAVE BUFFER POINTER FOR EDIT
       INSTR   ,40H,'-'        ;SEARCH FOR '-'
       JNC     EDIT            ;CHECK FOR EDITION OF SECTOR
       SCAN
       DECIN                   ;SCAN AND CONVERT ANOTHER NO
       JC      INERR           ;ERROR IF CARRY SET
       STA     ESEC            ;SAVE IN END SECTOR
       LXI     H,BSEC          ;POINTS TO BSEC
       CMP     M               ;COMPARE BEGIN AND END
       JP      DOREAD          ;OK IF END>=BEGIN
       MOV     B,A             ;OTHERWISE
       MOV     A,M             ;SWITCH THEM
       STA     ESEC
       MOV     M,B
DOREAD: CALL    RDISK0          ;READ DIRECT
       JMP     ENDFIL          ;BACK FOR MORE INPUT
EDIT:   LHLD    IPOINT          ;RESET BUFFER POINTER
       INSTR   ,40H,'EDIT'     ;CHECK EDIT FUNCTION
       JNC     DOREAD          ;GO TO DISPLAY SECTOR
       CALL    RDISK0          ;DISPLAY SECTOR
EDIT1:  PRINT   <CR,LF,'EDIT - '>
       FILL    INBUF,INBUF+29
       INPUT   INBUF,28                ;INPUT MAXIMUM 6 CHAR
       INSTR   INBUF,28,'WRITE'        ;WRITE EDITED SECTOR ON DISK?
       JC      WRTDSK          ;WRITE BUFFER BACK ON DISK
       INSTR   INBUF,28,'STOP' ;STOP EDITING WITHOUT WRITING?
       JC      ENDFIL          ;EXIT
       HEXIN   INBUF+2         ;CONV ASCII TO HEX
       JNC     CKLIM           ;IF NO ERROR, CHECK ADDR
       LDAX    D               ;GET ASCII CHAR
       CPI     '.'             ;CHECK FOR EXIT CHAR
       JZ      EDIT3           ;BACK FOR MORE EDITING
       JMP     ADERR           ;ADDRESS ERROR
CKLIM:  LXI     D,0080H         ;CHECK ADDR LIMIT
       CPHL
       JP      ADERR           ;ADDRESS ERROR
       SHLD    IPOINT          ;SAVE ADDRESS
       PRINT   CRLF,$
PTX:    HEXOUT  IPOINT+1
       HEXOUT  IPOINT          ;ECHO THE ADDRESS
       PRINT   SPACE,$
       LHLD    IPOINT          ;ECHO PRESENT CONTENTS
       LXI     D,0080H
       DAD     D               ;COMPUTE MEMORY ADDR
       MOV     A,M             ;GET BYTE FROM MEMORY
       HEXOUT
       PRINT   SPACE,$
       FILL    INBUF,INBUF+5   ;ZERO INPUT BUFFER
       INPUT   INBUF,4         ;INPUT 4 CHAR MAX
       HEXIN   INBUF+2         ;CONVERT
       JNC     EDIT2           ;HEX CHAR
       LDAX    D               ;GET ASCII CHAR
       CPI     '.'             ;PERIOD ENDS INPUT
       JZ      EDIT3           ;BACK FOR MORE EDITING
       JMP     HEXERR          ;ERROR NOT HEX CHAR
EDIT2:  LDA     INBUF+1         ;LOAD NO OF CHAR TYPED
       ORA     A
       JZ      EDITX           ;NO REPLACEMENT IF JUST CR
       MOV     A,L             ;CONVERTED CHAR BACK TO A
       LHLD    IPOINT          ;LOAD MEMORY BUFFER POINTER
       LXI     D,0080H         ;OFFSET
       DAD     D               ;CALC MEMORY ADDR
       MOV     M,A             ;STORE NEW INPUT TO MEMORY
EDITX:  PRINT   CRLF,$
       LDA     IPOINT          ;LEAST SIGNIFICANT HALF OF ADDR
       INR     A               ;INCR BY ONE
       ANI     7FH             ;COUNT MOD 128
       STA     IPOINT
       JMP     PTX             ;INPUT MORE DATA
EDIT3:  LXI     H,0
       SHLD    LINE            ;RESET LINE NO TO ZERO
       CALL    PRTSEC          ;PRINT BUFFER WITH HEADING
       JMP     EDIT1           ;BACK FOR ADDITIONAL EDITING
WRTDSK: INSTR   INBUF,29,'T '   ;CHANGED TRACK SPECIFICATION
       JC      WR1
       INSTR   INBUF,29,'TRACK '
       JNC     WRTDSK4         ;NO TRACK SPEC SO WRITE TO OLD ADDR
WR1:    SCAN                    ;LOOK FOR A NUMBER
       DECIN                   ;CONVERT IT TO BINARY
       JC      INERR           ;ERROR MESSAGE IF NOT DECIMAL NO
       STA     NTRK            ;SAVE IT
       INSTR   INBUF,29,'S '   ;CHANGED SECTOR SPECIFICATION
       JC      WR2
       INSTR   INBUF,29,'SECTOR '
       JNC     WRTDSK4         ;NO SECTOR NO SO WRITE TO OLD ADDR
WR2:    SCAN
       DECIN
       JC      INERR           ;ERROR IF NOT DECIMAL NO
       STA     NBSEC
       LXI     H,INBUF
       CALL    GETDRV          ;FIND DRIVE NUMBER IF SPECIFIED
       JNC     WR5
       STA     NEWDRV          ;SAVE DRIVE NO
WR5:    PRINT   <CR,LF,LF>
       PRINT   <'CAUTION - THIS COMMAND MOVES A SECTOR ON THE DISK'>
       PRINT   <CR,LF,'DO YOU WANT TO CONTINUE (Y/N) '>
       CHARIN                  ;GET A CHAR IN A
       CPI     'Y'
       JNZ     ENDFIL          ;STOP IF NOT 'Y'
       MOVE    80H,TRKBUF,128  ;SAVE BUFFER IN CASE OF READ
       SETSEC  NBSEC           ;SET NEW SECTOR NO
       SETTRK  NTRK            ;SET NEW TRACK NO
       LDA     NEWDRV
       MOV     E,A
       DISKIO  LOGIN           ;LOG IN SELECTED DRIVE
       MOVE    TRKBUF,80H,128  ;MOVE BUFFER BACK
WRTDSK4:CALLBIOS DWRITE         ;WRITE BUFFER BACK ON DISK
       JMP ENDFIL              ;EXIT
;
;  READ TRACK AND SECTOR DIRECT
;
RDISK0: CALL    FIXB
RDISK:  SETSEC  BSEC            ;SET SECTOR
       JC      BADSEC          ;WRONG SECTOR NO
TRK2:   SETTRK  TRACK           ;SET TRACK
       JC      BADTRK          ;WRONG TRACK NO
       LDA     NEWDRV
       MOV     E,A
       DISKIO  LOGIN                   ;SELECT NEW DEIVE IF SPECIFIED
       CALLBIOS DREAD          ;READ TRACK AND SECTOR
;
;  PRINT DRIVE, TRACK AND SECTOR HEADING
;
PRTSEC: PRINT   <CR,LF,'               DRIVE '>
       LDA     NEWDRV
       CALL    PRNDRV          ;PRINT DRIVE NAME
PRNTRK: PRINT   ' - TRACK '
       LXI     H,0
       LDA     TRACK
       MOV     L,A
       DECOUT
       PRINT   '  SECTOR '
       LXI     H,0
       LDA     BSEC
       MOV     L,A
       DECOUT
       PRINT   CRLF,$
       CALL    PRTBUF          ;PRINT IT
       LXI     H,BSEC          ;ADDR OF SECTOR NUMBER
       LDA     ESEC            ;END SECTOR NUMBER
       CMP     M               ;COMPARE THEM
       RZ                      ;EXIT IF THEY ARE EQUAL
       INR     M               ;INCR BSEC
       JMP     RDISK
;
;  DUMP ENTIRE TRACK IF NO SECTOR INPUT
;
WHLTRK: MVI     A,1             ;BEGIN SECTOR
       STA     BSEC
       MVI     A,26            ;END SECTOR
       STA     ESEC
       CALL    RDISK0          ;TO READ DISK
       JMP     ENDFIL          ;BACK FOR MORE INPUT
;
;  FILL IN FCB FOR NAMED FILE
;
FILNAM: FILFCB  FCB,82H ;FILL IN FCB NAME FROM INPUT BUFFER
       JC      NAMERR          ;ERROR IN FILE NAME
       MATCH   FCB+9,'COM'     ;TEST FOR COM FILE
       JNZ     SELDR
       LXI     H,100H
       SHLD    LINE            ;SET LINE NO. TO 100
SELDR:  LDA     NEWDRV          ;SELECT NEW DRIVE
       MOV     E,A
       DISKIO  LOGIN
       DISKIO  OPEN,FCB        ;0PEN FILE
       CPI     255             ;CHECK FILE PRESENT
       JZ      OPNERR          ;EXIT IF ERROR
RDFILE: DISKIO  READ,FCB        ;READ A BLOCK
       ORA     A               ;ZERO INDICATES SUCESSFUL READ
       JNZ     ENDFIL          ;1 INDICATES EOF
       CALL    PRTBUF          ;DO PRINT SUBROUTINE
       JMP     RDFILE          ;BACK FOR NEXT BLOCK
ENDFIL: PRINT   CRLF,$
       LDA     DRVNO           ;RESTORE LOGGED DRIVE NO
       MOV     E,A
       DISKIO  LOGIN
       LDA     INFLAG          ;SEE WHERE TO GO
       ORA     A
       JZ      MONITOR
       JMP     NEWIN
;
;
;  PRTBUF - PRINT BUFFER IN HEX AND ASCII
;
PRTBUF: MVI     B,8             ;8 LINES
       LXI     H,80H           ;INITIAL BUFFER POINTER
       SHLD    IPOINT          ;STORAGE FOR POINTER
BPRN:   LHLD    IPOINT          ;LOAD POINTER
       MVI     C,16            ;CHAR PER LINE
       LDA     LINE+1          ;LINE NUMBER
       SAVE    B,H
       HEXOUT
       LDA     LINE            ;SECOND TWO DIGITS
       HEXOUT
       PRINT   '  '
       RESTORE H,B
PLOOP:  MOV     A,M             ;GET A BYTE
       SAVE    B,H
       HEXOUT
       PRINT   SPACE,$
       RESTORE H,B
       INX     H               ;INCR MEMORY POINTER
       MOV     A,C
       CPI     9               ;CHECK 8 CHAR
       JNZ     DECC            ;SKIP IF NOT
       SAVE    B,H
       PRINT   SPACE,$
       RESTORE H,B
DECC:   DCR     C               ;DECR CHAR COUNT
       JNZ     PLOOP           ;PRINT SOME MORE
       SAVE    B
       PRINT   SPACE,$
       RESTORE B
       LHLD    IPOINT          ;RESET POINTER FOR ASCII
       MVI     C,10H           ;RESET CHAR COUNT
PLOOP1: MOV     A,M             ;GET A BYTE
       ANI     7FH             ;MASK OFF HIGH BIT
       CPI     7FH             ;DELETE CODE
       JZ      PERIOD          ;PRINT PERIOD FOR DELETE
       CPI     20H             ;TEST FOR CONTROL CHAR
       JP      SKIPX           ;SKIP SUBSTITUTION
PERIOD: MVI     A,2EH           ;ASCII PERIOD
SKIPX:  SAVE    B,H
       CHAROUT                 ;PRINT IT SAVE REGS
       RESTORE H,B
       INX     H               ;INCR MEMORY POINTER
       MOV     A,C
       CPI     9               ;CHECK 8 CHAR
       JNZ     DECC2
       SAVE    B,H
       PRINT   SPACE,$
       RESTORE H,B
DECC2:  DCR     C               ;DECR CHAR COUNT
       JNZ     PLOOP1          ;PRINT SOME MORE
       SAVE    B
       PRINT   CRLF,$          ;CARRIAGE RETURN
       CALL    PRNCON          ;PRINT CONTROL?
       POP     B
       INDEX   LINE,16         ;INCR LINE NO BY 16
       DCR     B               ;DECR   LINE COUNT
       RZ                      ;RETURN IF LINE COUNT ZERO
       INDEX   IPOINT,16       ;INCR POINTER BY 16
       JMP     BPRN            ;LOOP BACK
;
;    THIS SECTION VALIDATES A DISK
;
VALID:  MVI     A,1             ;START WITH SECTOR 1
       STA     SNUM
       XRA     A               ;START WITH TRACK 0
       STA     TNUM
       LDA     NEWDRV          ;SELECT NEW DRIVE
       MOV     E,A
       DISKIO  LOGIN
RS0:    SETTRK  TNUM
       JC      BADTRK
RS1:    SETSEC  SNUM
       JC      BADSEC
       CALLBIOS DREAD
       ORA     A
       CNZ     VALERR          ;ERROR IF NOT ZERO
       CALL    PRNCON          ;ESCAPE ON CONTROL C
       LDA     SNUM            ;SECTOR NO
       ADI     5               ;INCR BY 5
       STA     SNUM            ;STORE IT BACK
       SBI     27              ;CALC SECTOR MOD 26
       JM      RS1             ;SECTOR OK IF MINUS
       INR     A               ;SECTOR MOD 26
       STA     SNUM            ;STORE IT BACK
       CPI     1               ;ARE WE BACK TO ONE YET
       JNZ     RS1             ;READ SOME MORE
       LDA     TNUM            ;TRACK NUMBER
       INR     A               ;INCR BY ONE
       CPI     77              ;CHECK LIMIT
       JZ      VALOUT          ;TO EXIT
       STA     TNUM            ;STORE BACK TRACK NO
       JMP     RS0             ;BACK TO READ ROUTINE
VALOUT: LDA     VALFLG          ;CHECK ERROR FLAG
       ORA     A
       JNZ     ENDFIL
       PRINT   <CR,LF,'SUCCESSFUL VALIDATION DRIVE '>
       LDA     NEWDRV
       CALL    PRNDRV          ;PRINT DRIVE LABEL
       JMP     ENDFIL
VALERR: PRINT   <CR,LF,'ERROR - TRACK '>
       LDA     TNUM
       LXI     H,0
       MOV     L,A
       DECOUT
       PRINT   '  SECTOR '
       LXI     H,0
       LDA     SNUM
       MOV     L,A
       DECOUT
       PRINT   CRLF,$
       MVI     A,-1
       STA     VALFLG          ;SET ERROR FLAG
       RET
;
;
;  TRACK READ AND DUMP FORMATTING INFORMATION AS WELL AS DATA
;
FORMAT: CALL    FIXB
       SETTRK  TRACK           ;SET TRACK NO
       JC      BADTRK          ;WRONG TRACK NO
       LDA     NEWDRV
       MOV     E,A
       DISKIO  LOGIN           ;SELECT NEW DRIVE IF SELECTED
       LXI     H,TRKBUF        ;BUFFER ADDR TO HL
       LXI     D,0             ;BYTE COUNT
       MVI     A,0E4H          ;READ TRACK CMND FOR TARBELL CONTROLER
       OUT     0F8H            ;SEND CMND TO 1771
F1:     IN      0FCH            ;WAIT FOR DRQ OR INTRQ
       ORA     A
       JP      PTRK            ;TO PRINT ROUTINE
       IN      0FBH            ;READ DISK DATA
       MOV     M,A             ;STORE IT IN BUFFER
       INX     H               ;INCR MEMORY POINTER
       INX     D               ;INCR BYTE COUNT
       JMP     F1              ;KEEP READING TILL INTERRUPT
PTRK:   XCHG                    ;BYTE COUNT TO HL
       SHLD    BYTECNT         ;SAVE BYTES READ FROM TRACK
       PRINT   <CR,LF,'                     DRIVE '>
       LDA     NEWDRV          ;DRIVE NO
       CALL    PRNDRV          ;PRINT IT
PTRK0:  PRINT   ' TRACK '
       LXI     H,0
       LDA     TRACK
       MOV     L,A
       DECOUT                  ;PRINT TRACK NO
       PRINT   CRLF,$
PTRK2:  LHLD    BYTECNT         ;COUNT OF BYTES IN BUFFER
       XCHG                    ;MOVE IT TO DE
       LXI     H,TRKBUF        ;ADDR OF TRACK BUFFER
PTRK3:  MVI     C,16            ;CHAR PER LINE
       LDA     LINE+1          ;LINE NO
       SAV                     ;PUSH REGISTERS
       HEXOUT
       LDA     LINE
       HEXOUT
       PRINT   '  '
       RES                     ;POP REGISTERS
PTRK4:  MOV     A,M             ;GET A BYTE
       SAV
       HEXOUT
       PRINT   SPACE,$
       RES
       MOV     A,C
       CPI     9               ;CHECK IF 8 CHAR PRINTED
       JNZ     PTRK5
       SAV
       PRINT   SPACE,$
       RES
PTRK5:  DCX     D               ;DECR BYTE COUNT
       MOV     A,D
       ORA     E
       JZ      ENDFIL          ;BYE
       INX     H               ;BUFFER POINTER
       DCR     C               ;BYTES PER LINE
       JNZ     PTRK4           ;LOOP TILL END OF LINE
       SAV
       PRINT   CRLF,$
       CALL    PRNCON          ;PRINT CONTROL
       INDEX   LINE,16         ;INCR LINE COUNT
       RES
       JMP     PTRK3
;
;  PRINT CONTROL AND ESCAPE
;
PRNCON: MVI     C,11
       CALL    5
       ANI
1
       RZ                      ;RETURN
       CHARIN                  ;READ CONSOLE
       CPI     3               ;TEST FOR CONTROL C
       JZ      ENDFIL          ;EXIT IF CONTROL C
       RET
;
;    THIS SECTION DISPLAYS A CPM GROUP OF 8 SECTORS
;
GROUP:  SCAN                    ;GET THE GROUP NO
       DECIN                   ;CONVERT TO BINARY
       JC      INERR           ;INPUT ERROR IF CARRY SET
       STA     G               ;SAVE GROUP NO
       ADI     13              ;CHECK LEGAL RANGE
       JC      BADGRP
       XRA     A
       STA     S               ;SET SECTOR COUNT TO 0
       CALL    FIXB            ;RESTORE DRIVE B IF SELECTED
GRP1:   CALL    GRPTS           ;CONVERT TO TRACK AND SECTOR
       CALL    RDISK           ;PRINT THE SECTOR
       LDA     S               ;CHECK SECTOR�COUNT
       INR     A
       STA     S               ;INCR S BY 1
       CPI     8               ;CHECK LIMIT
       JNZ     GRP1            ;PRINT ANOTHER SECTOR
       JMP     ENDFIL          ;BACK FOR MORE INPUT
;
;   GRPTS  CONVERT CPM GROUP AND SECTOR NUMBER TO TRK AND SEC
;
GRPTS:  MVI     H,0             ;ZERO H
       LDA     G               ;GROUP NO
       MOV     L,A             ;TO L
       MOV     D,H             ;ZERO   D
       DAD     H
       DAD     H
       DAD     H               ;SHIFT LEFT 3
       LDA     S               ;GET SECTOR NO
       MOV     E,A             ;TO DE
       DAD     D               ;HL HAS G*8+S
       LXI     D,-26           ;DIVISOR
       MVI     A,1             ;CONTAINS DIVIDEND
DIV:    DAD     D               ;SUB 26
       INR     A
       JC      DIV             ;LOOP TILL MINUS
       LXI     D,TABLE+26      ;INDEX INTO TABLE
       DAD     D
       STA     TRACK           ;STORE TRACK NO
       MOV     A,M             ;GET SECTOR NO
       STA     BSEC            ;SAVE IN BEGINNING SECTOR
       STA     ESEC            ;SAVE IN END SECTOR TOO
       RET
;
;    THIS ROUTINE DISPLAYS THE DISK SECTOR ALLOCATION MAP
;
MAP:    LDA     NEWDRV
       MOV     E,A
       DISKIO  LOGIN           ;LOG IN SELECTED DRIVE
       DISKIO  ?ALLOC          ;GET POINTER TO ALLOCATION MAP
       MOV     H,B
       MOV     L,A             ;TO HL
       SHLD    IPOINT          ;SAVE MAP POINTER
       LXI     H,0             ;ZERO HL
       SHLD    G               ;ZERO COUNT OF UNUSED GROUPS
       PRINT   <CR,LF,LF,'             GROUP ALLOCATION MAP DRIVE - '>
       LDA     NEWDRV          ;LOGGED DRIVE
       CALL    PRNDRV          ;PRINT DRIVE NAME
       PRINT   CRLF2,$
MAP1:   LHLD    IPOINT          ;POINTER TO DISK ALLOCATION MAP
       MVI     D,8             ;NO OF LINES
MAP2:   MVI     C,4             ;WORDS PER LINE
MAPX:   SAV
       PRINT   '            '
       RES
MAP3:   MVI     B,8             ;BITS PER WORD
       MOV     A,M             ;GET A BYTE FROM ALLOC MAP
MAP4:   RAL                     ;SHIFT LEFT THRU CARRY
       SAVE    B,D,H,PSW
       JC      MAP5            ;PRINT A ONE
       PRINT   '0'             ;PRINT A ZERO
       LDA     G               ;UNUSED GROUPS
       INR     A               ;ADD 1
       STA     G               ;STORE IT BACK
       JMP     MAP6
MAP5:   PRINT   '1'             ;PRINT A ONE
MAP6:   RESTORE PSW,H,D,B
       PUSH    PSW             ;SAVE BIT MAP BYTE
       MOV     A,B             ;BIT COUNT
       CPI     7
       JNZ     MAPY
       MOV     A,C             ;WORD COUNT
       CPI     2
       JNZ     MAPY
       MOV     A,D             ;LINE COUNT
       CPI     1
       JNZ     MAPY
       POP     PSW
       JMP     MAP7            ;TO PRINT UNUSED GROUPS
MAPY:   POP     PSW
       DCR     B               ;DCR BIT COUNT
       JNZ     MAP4            ;PRINT MORE BITS
       DCR     C               ;DECR WORD COUNT
       INX     H               ;INCR ALLOC MAP POINTER
       JNZ     MAP3
       SAV
       PRINT   CRLF,$
       RES
       DCR     D               ;DECR LINE COUNT
       JMP     MAP2
MAP7:   PRINT   <CR,LF,LF,'          '>
       DECOUT  G               ;PRINT NO OF UNUSED SECTORS
       PRINT   <' GROUPS REMAINING ON DISK OUT OF 243',CR,LF>
       JMP     ENDFIL          ;EXIT
;
;    THIS ROUTINE SORTS AND DISPLAYS THE DIRECTORY
;       (NOT IMPLEMENTED IN THIS VERSION)
;
DIR:    JMP     ENDFIL          ;EXIT
;
;    THIS ROUTINE RESTORES DRIVE B
;
FIXB:   LDA     NEWDRV          ;CHECK DRIVE NO
       ORA     A
       RZ                      ;RETURN IF DRIVE A
       LDA     NEWDRV          ;SELECT DRIVE B
       MOV     E,A
       DISKIO  LOGIN
       XRA     A
       STA     TNUM            ;SELECT TRACK ZERO
       INR     A               ;SELECT SECTOR 1
       STA     SNUM
       SETSEC  SNUM
       SETTRK  TNUM
       CALLBIOS DHOME          ;HOME DRIVES
       CALLBIOS DREAD          ;READ TRACK ZERO DIRECT
       RET
;
;  ERROR AND EXIT ROUTINES
;
;
INERR:  PRINT   <CR,LF,'INPUT ERROR'>
       JMP     ENDFIL
;
BADSEC: PRINT   <CR,LF,'INCORRECT SECTOR NUMBER'>
       JMP     ENDFIL
;
BADTRK: PRINT   <CR,LF,'INCORRECT TRACK NUMBER'>
       JMP     ENDFIL
;
BADGRP: PRINT   <CR,LF,'INCORRECT GROUP NUMBER (GREATER THAN 242)'>
       JMP     ENDFIL
;
OPNERR: LDA     NEWDRV          ;CURRENT DRIVE NO
       ORA     A
       JNZ     OPNER1
       PRINT   <CR,LF,'NO FILE BY THAT NAME ON DRIVE A'>
       JMP     ENDFIL
OPNER1: PRINT   <CR,LF,'NO FILE BY THAT NAME ON DRIVE B'>
       JMP     ENDFIL
;
RDERR:  PRINT   <CR,LF,'DISK DEAD ERROR'>
       JMP     MONITOR
NAMERR: PRINT   <CR,LF,'ERROR IN FILE NAME'>
       JMP     ENDFIL
;
ADERR:  PRINT   <CR,LF,LF,'ADDRESS ERROR'>
       JMP     EDIT1           ;ADDRESS ERROR ON EDIT
;
HEXERR: PRINT   <CR,LF,'  ERROR - HEX INPUT ONLY',CR,LF>
       JMP     PTX
;
MONITOR: PRINT  CRLF,$
       LDA     DRVNO           ;RESTORE LOGGED DRIVE NO
       MOV     E,A
       DISKIO  LOGIN
       LHLD    OLDSTK
       SPHL                    ;RESET OLD STACK POINTER
       RET
;
;    GETDRV  SEARCH COMMAND STRING FOR DRIVE NAME AND RETURN CODE
;    A:=0 B:=1 C:=2 D:=3   CARRY SET IF DRIVE PRESENT
;    GETDRV IS CALLED WITH HL POINTING TO STARTING POSITION FOR SEARCH
;
GETDRV: SAV                     ;SAVE REGS
       LXI     D,DSKNAME       ;POINT TO NAME TABLE
       MVI     C,0             ;DRIVE NUMBER
GD1:    SAV
       MVI     B,40H           ;STRING LENGTH
       MVI     C,2             ;SUBSTRING LENGTH
       INSTR
       RES
       JC      GD3             ;FOUND NAME ON CARRY
       MOV     A,C             ;DRIVE NO TO A
       CPI     3               ;CHECK LIMIT
       JZ      GD3
       INR     C               ;INCR DRIVE NO
       INX     D
       INX     D               ;POINT TO NEXT NAME
       JMP     GD1             ;LOOP FOR 4 DRIVES
GD3:    MOV     A,C             ;DRIVE NO TO A
       RES
       RET
;
DSKNAME:DB      'A:'            ;TABLE OF DISK NAMES
       DB      'B:'
       DB      'C:'
       DB      'D:'
;
;    PRNDRV  PRINT DRIVE NAME CORRESPONDING TO CODE IN A REG
;    0=A 1=B 2=C 3=D  >3 ERROR
;
PRNDRV: SAV
       CPI     4               ;CHECK RANGE
       JP      PRDR3           ;ERROR IF > 3
       ADI     'A'             ;CALC LETTER TO PRINT
       CHAROUT                 ;PRINT IT
PRDR1:  RES
       RET
PRDR3:  PRINT   <CR,LF,'ERROR - DRIVE NUMBER GREATER THAN 3',CR,LF>
       JMP     PRDR1
;
;
;
;   DATA ALLOCATIONS
;
FCB     EQU     5CH             ;FILE CONTROL BLOCK
SPACE:  DB      ' $'            ;ASCII SPACE
CRLF:   DB      0DH,0AH,24H     ;ASCII CR LF
CRLF2:  DB      0DH,0AH,0AH,'$' ;ASCII CR LF LF
I:      DW      0               ;PSEUDO INDEX REGISTER
LINE:   DW      0               ;LINE NUMBER FOR LISTING
IPOINT: DW      00              ;VARIABLE BUFFER POINTER
INBUF:  DS      30              ;USED AS CONSOLE INPUT BUFFER
LASTIN: DB      0               ;LAST CONSOLE INPUT CHAR
INFLAG: DB      0               ;FLAG, RET FOR MORE CONSOLE INPUT
DRVNO:  DB      0               ;STORAGE FOR ORIGINALLY LOGGED DRIVE
NEWDRV: DB      0               ;STORAGE FOR NEW DRIVE NO
NBSEC:  DB      0               ;TEMPORARY STORAGE FOR SECTOR NO
NTRK:   DB      0               ;TEMPORARY STORAGE FOR TRACK NO
TRACK:  DB      0               ;SELECTED TRACK
BSEC:   DB      0               ;SELECTED BEGINNING SECTOR
ESEC:   DB      0               ;SELECTED ENDING SECTOR
TNUM:   DB      0               ;TRACK NO FOR VALIDATE
SNUM:   DB      0               ;SECTOR NO FOR VALIDATE
VALFLG: DB      0               ;VALIDATION ERROR FLAG
G:      DB      0               ;CPM GROUP NO
S:      DB      0               ;SECTOR NO WITHIN GROUP G
COUNT:  DB      0               ;COUNT OF DIRECTORY ENTRIES
OLDSTK: DW      0               ;STORAGE FOR OLD STACK POINTER
ENDSTK: DS      24              ;STORAGE FOR NEW STACK
NEWSTK: DW      0               ;NEW STACK
INB:    DW      0               ;STORES POINTER TO INPUT BUFFER AREA
OUTB:   DW      0               ;STORES POINTER TO DIRECTORY BUFFER AREA
BYTECNT:DW      0               ;BYTE COUNT FOR TRACK READ
TABLE:  DB      01H             ;SECTOR LOOK UP TABLE
       DB      07H
       DB      0DH
       DB      13H
       DB      19H
       DB      05H
       DB      0BH
       DB      11H
       DB      17H
       DB      03H
       DB      09H
       DB      0FH
       DB      15H
       DB      02H
       DB      08H
       DB      0EH
       DB      14H
       DB      1AH
       DB      06H
       DB      0CH
       DB      12H
       DB      18H
       DB      04H
       DB      0AH
       DB      10H
       DB      16H
TRKBUF: DW      0               ;START OF TRACK BUFFER
       END