;			--- 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

