*TITLE	'Model II Diskzap utility - 1.0'
;	Created: 24-Feb-80 - Revised: 15-MAR-82
;
EXIT	EQU	0		;NORMAL EXIT
SVC	EQU	8		;SVC EXECUTER
SETBRK	EQU	3		;SET/RESET BREAK
KBCHAR	EQU	4		;INPUT BYTE KBD
KBLINE	EQU	5		;INPUT LINE KBD
VDCHAR	EQU	8		;OUTPT BYTE DSP
PRCHAR	EQU	18		;OUTPT BYTE PRT
;
LOCDCB	EQU	032AH		;LOCATE DEVICE DCB
;
CRTA	EQU	0FCH		;VIDEO ADD REG
CRTD	EQU	0FDH		;VIDEO DATA REG
SELVD	EQU	0FFH		;VIDEO BANK SEL
VIDEO	EQU	0F800H		;VIDEO MEMORY
;
;	KBD/VIDEO CONTROL CODES
;
CURON	EQU	1		;TURN ON CURSOR
CUROF	EQU	2		;TURN OFF CURSOR
HOME	EQU	27		;HOME CURSOR/CLS
BREAK	EQU	27		;BREAK/ESC KEY
ENTER	EQU	13		;ENTER KEY
LFARR	EQU	28		;LEFT ARROW KEY
RTARR	EQU	29		;RIGHT ARROW KEY
UPARR	EQU	30		;UP ARROW KEY
DNARR	EQU	31		;DOWN ARROW KEY
;
BUFFER	EQU	4000H		;MAIN I/O BUFFER
BUFER1	EQU	4100H		;2ND I/O BUFFER
;
	ORG	3000H
;
;	PROGRAM ENTRY POINT HERE
;
ENTRY	LD	SP,ENTRY-4	;INIT STACK
	LD	A,SETBRK	;SETBRK
	LD	HL,0		;CLEAR
	RST	SVC		;DO IT!
	LD	A,SETBRK	;SETBRK
	LD	HL,START	;NEW ADD
	RST	SVC		;DO IT!
;
;	DISPLAY MENU AND GET SELECTION
;
START	LD	SP,ENTRY-4	;INIT STACK
	LD	HL,START
	PUSH	HL		;RET ADD ON STACK
;
	LD	HL,TITLE	;PROGRAM TITLE
	CALL	DSPLY		;OUTPUT
	LD	A,(SELECT)	;CURSOR SELECT
	LD	C,A		;C = OPT
	LD	HL,(POINT)	;VIDEO POINTER
	LD	A,4FH
	OUT	(CSEL),A	;DE-SEL DRIVE
;
GETSL1	LD	(POINT),HL	;CURSOR SEL
	LD	A,C		;SAVE CURR POINT
	LD	(SELECT),A	;SAVE CURR SELECT
	CALL	VDSEL		;SELECT VIDEO
	LD	(HL),'*'        ;DRAW CHAR
	CALL	VDOFF		;DE-SEL VIDEO
;
GETSL2	CALL	INKEY		;GET KBD
	CP	'O'             ;OUT?
	JP	Z,EXIT		;IF YES
	CP	UPARR		;UP ARROW?
	JR	NZ,GETSL3	;IF NOT
	LD	A,C		;GET POSITION
	DEC	A		;-1
	LD	DE,-80		;VIDEO OFFSET
;
GETSL4	JR	Z,GETSL2	;IF TOP/BOTTOM
;
	LD	C,A		;C = POSITION
	CALL	VDSEL		;SELECT VIDEO
	LD	(HL),' '        ;DRAW CHAR
	ADD	HL,DE		;ADJ VIDEO
	JR	GETSL1		;TRY AGAIN
;
GETSL3	CP	DNARR		;DOWN ARROW?
	JR	NZ,GETSL5	;IF NOT
	LD	A,C		;GET POS
	INC	A		;+ 1
	CP	8		;AT BOTTOM?
	LD	DE,80		;VIDEO OFFSET
	JR	GETSL4		;SKIP
;
GETSL5	CP	ENTER		;ENTER KEY?
	JR	NZ,GETSL2	;IF NOT
	DEC	C
	JP	Z,SET0
	DEC	C
	JP	Z,FILL
	DEC	C
	JP	Z,COPY
	DEC	C
	JP	Z,LPRINT
	DEC	C
	JP	Z,VERIFY
	DEC	C
	JP	Z,FORMAT
;
;
;	DISPLAY SECTOR ROUTINE
;
DISP	CALL	INPUT1		;DRIVE
	CALL	INPUT2		;CYLINDER
	CALL	INPUT3		;SECTOR
;
DISP1	CALL	READ		;READ SECTOR
	CALL	NZ,ERORC	;IF I/O ERROR
	RET	NZ		;IF NO CONTINUE
;
DISP2	CALL	DSPSEC		;DISPLAY SECTOR
;
;	GET SUB-SELECTION
;
SCAN	CALL	INKEY		;GET KBD
	CP	BREAK		;BREAK KEY?
	RET	Z		;IF YES
	CP	'M'             ;MODIFY MODE?
	JR	Z,MODIFY	;IF YES
	CP	'-'             ;DEC SEC?
	JR	NZ,DISP3	;IF NOT
	CALL	SECDN		;DO IT
	JR	DISP1		;TRY AGAIN
;
DISP3	CP	';'             ;INC SEC?
	JR	NZ,DISP4	;IF NOT
	CALL	SECUP		;DO IT
	JR	DISP1		;TRY AGAIN
;
DISP4	CP	'='             ;DEC CYL?
	JR	NZ,DISP5	;IF NOT
	CALL	CYLDN		;DO IT
	JR	DISP1		;TRY AGAIN
;
DISP5	CP	'+'             ;INC CYL?
	JR	NZ,SCAN 	;IF NOT
	CALL	CYLUP		;DO IT
	JR	DISP1		;TRY AGAIN
;
;	BACKSPACE TO PREVIOUS SECTOR
;
;	ENT	DE =	CYLINDER, SECTOR
;
SECDN	LD	A,(IY+1)	;1ST SECTOR
	CP	E		;AT 1ST?
	JR	Z,SECDN1	;IF NOT
	DEC	E		;BKSP
	RET
;
SECDN1	CALL	CYLDN		;BKSP CYL
	LD	A,(IY+3)	;A = SEC/CYL
	ADD	A,(IY+1)	;ADD OFFSET
	LD	E,A		;E = LAST SEC
	DEC	E		;CORRECT
	RET
;
;	BACKSPACE TO PREVIOUS CYLINDER
;
CYLDN	INC	D		;BKSP CYL
	DEC	D		;CYL 0?
	JR	Z,CYLDN1	;IF NOT
	DEC	D		;BKSP CYL
	CALL	Z,CCALC 	;AT 0
	RET
;
CYLDN1	LD	D,(IY+2)	;CYL/DRIVE
	DEC	D		;BKSP CYL
	CALL	CCALC		;GET CALC DATA
	RET
;
;	ADVANCE TO NEXT SECTOR
;
;	ENT	DE = CYLINDER, SECTOR
;
SECUP	LD	A,(IY+3)	;SEC/CYL
	ADD	A,(IY+1)	;ADD OFFSET
	DEC	A		;LAST SECTOR
	INC	E
	CP	E		;IN RANGE?
	RET	NC		;IF YES
;
SECUP1	CALL	CYLUP		;ADV CYL
	LD	E,(IY+1)	;E = 1ST SEC
	RET
;
;	ADVANCE TO NEXT CYLINDER
;
CYLUP	LD	A,(IY+2)	;CYL/DRIVE
	DEC	A
	INC	D
	CP	D		;IN RANGE?
	JR	C,CYLUP1	;IF NOT
	LD	A,D		;GET CYL
	DEC	A		;WAS IT 0?
	CALL	Z,CCALC 	;GET CALC DATA
	RET
;
CYLUP1	LD	D,0		;1ST CYL
	CALL	CCALC		;GET CALC DATA
	RET
;
;	MODIFY SECTOR CONTENTS
;
;	ENT	 C =	DRIVE NUMBER
;		DE =	CYLINDER, SECTOR
;		IY =>	DRIVE INFORMATION
;
;	USES	AF,HL
;
MODIFY	EXX			;SAVE DRV,CYL,SEC
	LD	HL,VIDEO+8	;INIT CURSOR
	LD	DE,BUFFER	;INIT BUFFER
;
MOD1	CALL	VDSEL		;SELECT VIDEO
	LD	A,(HL)		;GET CHAR
	SET	7,A		;REVERSE VIDEO
	LD	(HL),A		;SET CHAR
	INC	HL		;NEXT
	LD	A,(HL)		;GET CHAR
	SET	7,A		;REVERSE VIDEO
	LD	(HL),A		;SET CHAR
	DEC	HL		;CORRECT
	CALL	VDOFF		;DE-SEL VIDEO
;
MOD2	EXX			;GET DRV,CYL,SEC
	CALL	INKEY		;GET KBD
	CP	BREAK		;BREAK KEY?
	JP	Z,DISP1 	;IF YES
	CP	ENTER		;ENTER KEY?
	JR	NZ,MOD3 	;IF NOT
	CALL	WRITE		;WRITE SECTOR
	JP	Z,DISP2 	;NO ERROR
	PUSH	AF
	CALL	CLS		;CLEAR VIDEO
	POP	AF
	JP	ERROR		;POST ERROR
;
MOD3	EXX
	CP	'Z'             ;ZERO?
	JP	Z,ZRO		;IF YES
	CP	UPARR		;UP ARROW?
	JR	Z,UP		;IF YES
	CP	DNARR		;DOWN ARROW?
	JR	Z,DOWN		;IF YES
	CP	LFARR		;LEFT ARROW?
	JR	Z,LEFT		;IF YES
	CP	RTARR		;RIGHT ARROW?
	JR	Z,RIGHT 	;IF YES
	CALL	HEXCP		;HEX INPUT?
	JR	C,MOD2		;IF NOT
	CALL	VDSEL		;SELECT VIDEO
	LD	(HL),B		;VIDEO WITH HIGH NIB
	CALL	VDOFF		;DE-SEL VIDEO
	INC	HL		;VIDEO NEXT
	RLA			;MOVE TO HIGH NIB
	RLA
	RLA
	RLA
	LD	C,A		;SAVE HIGH NIB
;
MOD4	CALL	INKEY		;GET KBD
	CALL	HEXCP		;HEX INPUT?
	JR	C,MOD4		;IF NOT
	CALL	VDSEL		;SELECT VIDEO
	LD	(HL),B		;VIDEO WITH LOW NIB
	CALL	VDOFF		;DE-SEL VIDEO
	DEC	HL		;POS TO BEG OF BYTE
	ADD	A,C
	LD	(DE),A		;BUFFER WITH BYTE
;
RIGHT	LD	A,(IY+4)	;END BUFF
	DEC	A		;DEC
	CP	E		;AT END?
	JP	Z,MOD1		;IGNORE
	INC	E		;NEXT
	LD	A,E		;SET LOC
	AND	0FH		;NEXT LINE?
	JR	NZ,RIGHT1	;IF NOT
	LD	BC,43		;OFFSET
	ADD	HL,BC		;ADJ VIDEO
	JR	REDISP		;RE-DISPLAY
;
RIGHT1	INC	HL
	INC	HL		;ADJ VIDEO
	BIT	0,E		;ODD?
	JR	NZ,REDISP	;IF YES
	INC	HL		;SKIP
	JR	REDISP		;RE-DISPLAY
;
LEFT	LD	A,E		;CORRECT BUFFER
	OR	A		;AT BEG?
	JP	Z,MOD1		;IF YES
	DEC	A		;BKSP
	LD	E,A
	CPL
	AND	0FH		;BEG LINE?
	JR	NZ,LEFT1	;IF NOT
	LD	BC,-43		;OFFSET
	ADD	HL,BC		;ADJ VIDEO
	JR	REDISP		;RE-DISPLAY
;
LEFT1	DEC	HL
	DEC	HL		;CORRECT VIDEO
	BIT	0,E		;EVEN?
	JR	Z,REDISP	;IF YES
	DEC	HL		;SKIP
	JR	REDISP		;RE-DISPLAY
;
UP	LD	A,E		;DEC BUFF
	SUB	10H		;1 LINE
	JP	C,MOD1		;AT TOP!
	LD	E,A		;CORRECT
	LD	BC,-80		;OFFSET
	ADD	HL,BC		;ADJ VIDEO
	JR	REDISP		;RE-DISPLAY
;
DOWN	LD	A,(IY+4)	;SEC LENTH
	SUB	10H		;END BUFF
	CP	E		;PAST END?
	JP	Z,MOD1		;IGNORE
	JP	C,MOD1		;IGNORE
	LD	A,E		;DEC BUFF 1 LINE
	ADD	A,10H
	LD	E,A		;CORRECT
	LD	BC,80		;OFFSET
	ADD	HL,BC		;ADJUST VIDEO
	JR	REDISP		;RE-DISPLAY
;
;	ZERO BUFFER AT CURSOR
;
ZRO	PUSH	DE		;SAVE
	XOR	A		;CLEAR
ZRO1	LD	(DE),A		;ZERO!
	INC	E		;NEXT
	JR	NZ,ZRO1 	;TIL DONE
	POP	DE		;RESTORE
;
REDISP	EXX			;GET DRV,CYL,SEC
	CALL	DSPSEC		;RE-DISPLAY SECTOR
	EXX			;GET VID,BUF POINT
	JP	MOD1		;TRY AGAIN
;
;
;	SET DRIVE PARAMETERS ROUTINE
;
SET0	CALL	INPUT1		;DRIVE
	PUSH	HL
	POP	IY		;IY => INFO
;
;	INPUT SECTOR OFFSET
;
SET1	LD	B,1		;CHAR COUNT
	LD	HL,MES8 	;'Sector offset ?'
	CALL	INPUTX		;LINE INPUT
	JR	Z,SET2		;NULL INPUT
	CALL	DECBIN		;CONVERT
	JR	NZ,SET1 	;BAD DIGIT
	LD	A,L
	CP	2		;VALID?
	JR	NC,SET1 	;TRY AGAIN
	LD	(IY+1),A	;SAVE SEC OFFSET
;
;	INPUT TRK 0 SEC/TRACK
;
SET2	LD	B,2		;CHAR COUNT
	LD	HL,MES9 	;'TRK 0 sec/trk ?'
	CALL	INPUTX		;LINE INPUT
	JR	Z,SET3		;NULL INPUT
	CALL	DECBIN		;CONVERT
	JR	NZ,SET2 	;BAD DIGIT
	LD	A,L
	OR	A		;ZERO?
	JR	Z,SET2		;TRY AGAIN
	CP	80		;VALID?
	JR	NC,SET2 	;TRY AGAIN
	LD	(IY+6),A	;SAVE SEC/TRACK
;
;	INPUT TRK 0 DENSITY
;
SET3	LD	B,1		;CHAR COUNT
	LD	HL,MES10	;'TRK 0 density ?'
	CALL	INPUTX		;LINE INPUT
	JR	Z,SET4		;NULL INPUT
	SET	6,(IY+0)	;ASSUME DDEN
	LD	A,(HL)		;GET INPUT
	RES	5,A		;IGNORE CASE
	CP	'D'             ;DDEN?
	JR	Z,SET4		;IF YES
	RES	6,(IY+0)	;SDEN
;
;	INPUT TRK 0 SEC LEN
;
SET4	LD	B,3		;CHAR COUNT
	LD	HL,MES14	;'TRK 0 sec len ?'
	CALL	INPUTX		;LINE INPUT
	JR	Z,SET6		;NULL INPUT
	CALL	DECBIN		;CONVERT
	JR	NZ,SET4 	;IF ERROR
	LD	DE,128		;128 BYTES
	SBC	HL,DE		;VALID?
	JR	Z,SET5		;IF YES
	JR	C,SET4		;INVALID
	SBC	HL,DE		;256 BYTES
	JR	NZ,SET4 	;IF NOT
	LD	DE,256		;VALID?
;
SET5	LD	(IY+7),E	;LSB LEN
	LD	(IY+8),D	;MSB LEN
;
;	INPUT SECTORS/TRACK
;
SET6	LD	B,2		;CHAR COUNT
	LD	HL,MES11	;'Sectors/track ?'
	CALL	INPUTX		;LINE INPUT
	JR	Z,SET7		;NULL INPUT
	CALL	DECBIN		;CONVERT
	JR	NZ,SET6 	;BAD DIGIT
	LD	A,L
	OR	A		;ZERO?
	JR	Z,SET6		;TRY AGAIN
	CP	80		;VALID?
	JR	NC,SET6 	;TRY AGAIN
	LD	(IY+3),A	;SAVE TRK 0 SEC/TRK
;
;	INPUT TRACK DENSITY
;
SET7	LD	B,1		;CHAR COUNT
	LD	HL,MES12	;'Track density ?'
	CALL	INPUTX		;LINE INPUT
	JR	Z,SET8		;NULL INPUT
	SET	7,(IY+0)	;ASSUME DDEN
	LD	A,(HL)		;GET INPUT
	RES	5,A		;IGNORE CASE
	CP	'D'             ;DDEN?
	JR	Z,SET8		;IF YES
	RES	7,(IY+0)	;SDEN
;
;	INPUT SECTOR LENTH
;
SET8	LD	B,3		;CHAR COUNT
	LD	HL,MES15	;'Sector lenth ?'
	CALL	INPUTX		;LINE INPUT
	RET	Z		;NULL INPUT
	CALL	DECBIN		;CONVERT
	JR	NZ,SET8 	;IF ERROR
	LD	DE,128		;128 BYTES
	SBC	HL,DE		;VALID?
	JR	Z,SET9		;IF YES
	JR	C,SET8		;INVALID
	SBC	HL,DE		;256 BYTES
	JR	NZ,SET8 	;IF NOT
	LD	DE,256		;VALID?
;
SET9	LD	(IY+4),E	;LSB LEN
	LD	(IY+5),D	;MSB LEN
	RET
;
;	FILL SECTOR ROUTINE
;
FILL	CALL	INPUT1		;DRIVE
	CALL	INPUT2		;CYLINDER
	CALL	INPUT3		;SECTOR
	CALL	INPUT4		;SECTOR COUNT
;
FILL1	LD	B,2		;CHAR COUNT
	LD	HL,MES7 	;'Fill data ?'
	CALL	INPUTX		;LINE INPUT
	LD	B,0		;DEFAULT
	JR	Z,FILL2 	;NULL INPUT
	CALL	HEXBIN		;CONVERT
	JR	NZ,FILL1	;BAD DIGIT
	LD	B,L		;B = DATA
;
FILL2	LD	HL,AM		;HL => AM
	LD	(HL),0		;INIT AM
;
	LD	HL,BUFFER	;I/O BUFFER
FILL3	LD	(HL),B		;FILL DATA
	INC	L		;NEXT
	JR	NZ,FILL3	;TIL DONE
;
FILL4	CALL	DTKSC		;DISP TRK,SEC
	CALL	WRITE		;WRITE SECTOR
	JP	NZ,ERROR	;I/O ERROR
	CALL	DEC		;NEXT
	JR	NZ,FILL4	;TIL DONE
	RET
;
;
;	COPY SECTOR ROUTINE
;
COPY	CALL	INPUT1		;DRIVE
	LD	HL,DRV1
	LD	(HL),C		;SAVE DRIVE
	CALL	INPUT2		;CYLINDER
	CALL	INPUT3		;SECTOR
	LD	(TKSEC1),DE	;SAVE CYL,SEC
;
	CALL	INPUT1		;DRIVE
	LD	HL,DRV2
	LD	(HL),C		;SAVE DRIVE
	CALL	INPUT2		;CYLINDER
	CALL	INPUT3		;SECTOR
	LD	(TKSEC2),DE	;SAVE CYL,SEC
;
	CALL	INPUT4		;SECTOR COUNT
;
;	SET-UP FOR SOURCE READ
;
COPY1	LD	HL,DRV1 	;HL => SOURCE DRIVE
	LD	C,(HL)		;C = SOURCE DRIVE
	LD	DE,(TKSEC1)	;SOURCE TRK,SEC
	CALL	CCALC		;IY => DRIVE INFO
	LD	A,(IY+3)	;SEC/TRACK
	LD	B,A		;B = COUNT
	LD	(SCNT),A	;SAVE COUNT
	LD	HL,(COUNT)	;GET COUNT
	LD	(COUNT2),HL	;SAVE COUNT
	LD	HL,BUFER1	;START BUFFER
	LD	IX,BUFFER	;START AM STORAGE
;
;	READ FROM SOURCE HERE
;
COPY2	CALL	DTKSC		;DISP TRK,SEC
	CALL	READ1		;READ SECTOR
	PUSH	BC		;SAVE COUNT
	CALL	NZ,ERORC	;I/O ERROR
	POP	BC		;GET COUNT
	RET	NZ		;IF NO CONTINUE
;
	PUSH	DE		;SAVE
	LD	E,(IY+4)	;LSB LEN
	LD	(IX+0),E
	LD	D,(IY+5)	;MSB LEN
	LD	(IX+1),D
	LD	A,(AM)		;GET AM
	LD	(IX+2),A	;SAVE
	ADD	HL,DE		;HL => NEXT BUFF
	LD	DE,3
	ADD	IX,DE		;CORRECT
	POP	DE		;RESTORE
;
	CALL	DEC		;NEXT SECTOR
	JR	Z,COPY3 	;DONE
	DJNZ	COPY2		;TIL DONE
;
COPY3	LD	(TKSEC1),DE	;SAVE TRK,SEC
;
;	SET-UP FOR DEST WRITE
;
	LD	HL,DRV2 	;HL => SOURCE DRIVE
	LD	C,(HL)		;C = SOURCE DRIVE
	LD	DE,(TKSEC2)	;SOURCE TRK,SEC
	CALL	CCALC		;IY => DEST INFO
	LD	A,(SCNT)	;GET COUNT
	LD	B,A		;B = COUNT
	LD	HL,(COUNT2)	;TEMP COUNT
	LD	(COUNT),HL	;TO COUNT
	LD	HL,BUFER1	;START BUFFER
	LD	IX,BUFFER	;START AM STORAGE
;
COPY4	CALL	DTKSC		;DISP TRK,SEC
	LD	A,(IX+2)	;GET AM
	LD	(AM),A		;SET AM
	CALL	WRITE1		;READ SECTOR
	JP	NZ,ERROR	;I/O ERROR
;
	PUSH	DE		;SAVE
	LD	E,(IX+0)
	LD	D,(IX+1)	;SEC LEN
	ADD	HL,DE		;HL => NEXT BUFF
	LD	DE,3
	ADD	IX,DE		;CORRECT
	POP	DE		;RESTORE
;
	CALL	DEC		;NEXT SECTOR
	RET	Z		;DONE
	DJNZ	COPY4		;TIL DONE
	LD	(TKSEC2),DE	;UPD TRK,SEC
	JP	COPY1		;TIL DONE
;
;
;	PRINT SECTOR ROUTINE
;
LPRINT	CALL	INPUT1		;DRIVE
	CALL	INPUT2		;CYLINDER
	CALL	INPUT3		;SECTOR
	CALL	INPUT4		;SECTOR COUNT
;
LPRT1	CALL	READ		;READ SECTOR
	CALL	NZ,ERORC	;IF I/O ERROR
	RET	NZ		;IF NO CONTINUE
	CALL	DSPSEC		;DISPLAY SECTOR
;
	PUSH	BC		;SAVE
	LD	HL,VIDEO	;OUTPUT VIDEO
	CALL	VDSEL		;SELECT VIDEO
;
	LD	C,24		;LINES
LPRT2	LD	B,80		;CHARS/LINE
LPRT3	LD	A,(HL)		;GET CHAR
	INC	HL		;NEXT
	CP	80H		;GRAPHICS?
	JR	C,LPRT4 	;IF NOT
	LD	A,'.'           ;SUBSTITUTE
;
LPRT4	CALL	PRTCR		;OUTPUT
	DJNZ	LPRT3		;80 COLS
	LD	A,13		;EOT
	CALL	PRTCR		;IF EOL
	DEC	C		;DONE?
	JR	NZ,LPRT2	;TIL DONE
	LD	A,10		;L/F
	CALL	PRTCR		;OUTPUT
	CALL	VDOFF		;DE-SEL VIDEO
	POP	BC		;RESTORE
;
LPRT5	CALL	DEC		;NEXT
	JR	NZ,LPRT1	;TIL DONE
	RET
;
;
;	READ-VERIFY SECTOR ROUTINE
;
VERIFY	CALL	INPUT1		;DRIVE
	CALL	INPUT2		;CYLINDER
	CALL	INPUT3		;SECTOR
	CALL	INPUT4		;SECTOR COUNT
;
VER2	CALL	DTKSC		;DISP TRK,SEC
	LD	HL,BUFFER	;I/O BUFFER
	CALL	DVERF		;VERIFY
	JR	Z,VER1		;NO ERROR
	CALL	PRTERR		;PRINT ERROR
	CALL	INKEY		;SCAN KBD
	CP	BREAK		;BREAK KEY?
	RET	Z		;IF YES
;
VER1	CALL	DEC		;DEC COUNT
	JR	NZ,VER2 	;TIL DONE
	RET
;
;
;	FORMAT CYLINDER ROUTINE
;
FORMAT	CALL	INPUT1		;DRIVE
	CALL	INPUT2		;CYLINDER
	CALL	INPUT5		;CYLINDER COUNT
;
;	INPUT INTERLEAVE FACTOR
;
FORMT4	LD	B,2		;CHAR COUNT
	LD	HL,MES6 	;'Interleave factor ?'
	CALL	INPUTX		;LINE INPUT
	LD	B,1		;DEFAULT
	JR	Z,FORMT5	;IF NULL
	CALL	DECBIN		;CONVERT
	JR	NZ,FORMT4	;BAD DIGIT
	LD	B,L		;D = INTER
;
FORMT5	LD	E,0		;INIT SECTOR
	CALL	DHOME		;HOME DRIVE
;
FORMT6	CALL	DTKSC		;DISP TRK,SEC
	CALL	FCYL		;FORMAT CYL
	JP	NZ,ERROR	;IF ERROR
	CALL	CYLUP		;NEXT CYL
	CALL	DEC1		;DEC COUNT
	JR	NZ,FORMT6	;TIL DONE
	RET
;
;	SUBROUTINE TO SAVE REGISTERS
;
SAVER	POP	AF		;RET ADDRESS
;
	PUSH	BC		;SAVE REG
	PUSH	DE
	PUSH	HL
	PUSH	HL		;SAVE TEMP
	LD	HL,SAVER1
	EX	(SP),HL 	;PLACE RET, GET TEMP
	PUSH	AF		;RET ADD
	RET
;
SAVER1	POP	HL
	POP	DE
	POP	BC
	RET
;
;	SUBROUTINE TO CHECK IF ASCII CHAR WITHIN
;	HEX LIMITS AND CONVERT BINARY NIBBLE
;
HEXCP	LD	B,A		;SAVE ASCII
HEXCP1	SUB	30H
	RET	C
	CP	10
	JR	C,HEXCP2
	CP	17
	RET	C
	SUB	7
	CP	16
HEXCP2	CCF
	RET
;
;	SUBROUTINE TO DISPLAY DISK SECTOR ON VIDEO
;
;	ENT	DE =	CYLINDER, SECTOR
;		HL =>	BUFFER CONTAINING SECTOR
;		IY =>	DRIVE INFORMATION
;
;	USES	AF,HL
;
DSPSEC	CALL	SAVER		;SAVE REG
	LD	(TKSEC1),DE	;SAVE TRK,SEC
;
	CALL	VDSEL		;SELECT VIDEO
	LD	HL,BUFFER	;INIT BUF POINT
	LD	DE,VIDEO	;INIT VID POINT
;
DSPRC4	PUSH	DE		;SAVE VIDEO
	PUSH	HL		;SAVE BUFFER
	LD	B,8		;HEX WORD COUNT
	LD	A,(TKSEC1+1)	;CYLINDER NUM
	CALL	BINHEX
	LD	A,(TKSEC1+0)	;SECTOR NUM
	CALL	BINHEX
	LD	A,L		;BYTE NUMBER
	CALL	BINHEX
	LD	A,':'
	CALL	DSPBYT
;
DSPRC1	LD	A,' '
	CALL	DSPBYT
	LD	A,(HL)
	CALL	BINHEX
	INC	L
	LD	A,(HL)
	CALL	BINHEX
	INC	L
	DJNZ	DSPRC1
	LD	A,' '
	CALL	DSPBYT
	POP	HL		;RESTORE BUFFER POS
;
	LD	B,16		;ASCII BYTE COUNT
DSPRC2	LD	A,(HL)		;GET CHAR
	CP	' '             ;CTL?
	JR	C,DOT		;SKIP
	CP	0C0H		;SPACE COMP?
	JR	C,DSPRC3	;IF NOT
DOT	LD	A,'.'           ;REPLACE
DSPRC3	CALL	DSPBYT		;OUTPUT
	LD	A,(IY+4)	;END BUFF
	DEC	A
	CP	L		;AT END?
	JR	Z,DSPRC5	;IF YES
	INC	L		;NEXT
	DJNZ	DSPRC2		;NEXT LINE
	POP	DE		;DE => BEG LINE
;
	PUSH	HL		;SAVE BUFF
	LD	HL,80
	ADD	HL,DE		;HL => NEXT VIDEO
	EX	DE,HL		;DE => NEXT VIDEO
	POP	HL		;GET BUFF
	JR	DSPRC4		;TIL DONE
;
DSPRC5	POP	HL		;CLEAN STACK
	LD	DE,80
	ADD	HL,DE		;HL => NEXT LINE
DSPRC7	LD	(HL),' '        ;FILL BLANK
	INC	HL		;NEXT
	LD	A,H		;GET MSB
	INC	A		;1792 CHARS?
	JR	NZ,DSPRC7	;IF NOT
	CALL	VDOFF		;DE-SEL VIDEO
	RET
;
;	SUBROUTNE TO CONVERT BINARY TO ASCII HEX
;
;	ENT	A =	BINARY BYTE
;		DE =>	ASCII HEX
;
BINHEX	PUSH	AF		;SAVE
	RRA			; / 2
	RRA			; / 4
	RRA			; / 8
	RRA			; / 16
	CALL	HEX1		;CONVERT
	POP	AF		;RESTORE
HEX1	AND	0FH		;LOW NIBBLE
	ADD	A,90H
	DAA
	ADC	A,40H
	DAA
;
DSPBYT	LD	(DE),A		;SAVE DIGIT
	INC	DE		;NEXT
	RET
;
;	SUBROUTINE TO SCAN KBD AND WAIT
;
INKEY	CALL	KEYBD		;SCAN KBD
	OR	A		;NULL?
	JR	Z,INKEY 	;IF YES
	CP	'a'             ;LC?
	RET	C		;IF NOT
	CP	'z'+1           ;LC?
	RET	NC		;IF NOT
	RES	5,A		;UC
	RET
;
;	SUBROUTINE TO SCAN KEYBOARD
;
KEYBD	PUSH	BC		;SAVE
	LD	B,0		;INIT
	LD	A,KBCHAR	;SAVE
	RST	SVC		;DO IT!
	LD	A,B		;GET CHAR
	OR	A		;NULL?
	POP	BC		;RESTORE
	RET
;
;	SUBROUTINE TO CLEAR SCREEN
;
CLS	LD	A,HOME		;CLEAR SCREEN
;
;	SUBROUTINE TO DISPLAY CHAR
;
DSP	PUSH	AF		;SAVE REG
	PUSH	BC
	LD	B,A		;B = CHAR
	LD	A,VDCHAR
	RST	SVC		;DO IT!
	POP	BC		;RESTORE REG
	POP	AF
	RET
;
;	SUBROUTINE TO OUTPUT BYTE TO PRINTER
;
PRTCR	PUSH	AF		;SAVE
	PUSH	BC
	LD	B,A		;B = CHAR
	LD	A,PRCHAR
	RST	SVC		;DO IT!
	POP	BC		;RESTORE
	POP	AF
	RET
;
;	LINE INPUT ROUTINE
;
KEYIN	PUSH	BC		;SAVE BUFF
	PUSH	HL
	LD	A,CURON 	;CUR ON
	CALL	DSP
	LD	A,KBLINE	;LINE INPUT
	RST	SVC		;DO IT!
	INC	C
	DEC	C		;C/R INPT?
	JR	NZ,KEYIN1	;IF YES
	LD	C,B
	LD	B,0		;BC = INPUT LEN
	ADD	HL,BC		;HL => END INPUT
	LD	(HL),13 	;FORCE EOT
KEYIN1	LD	A,CUROF 	;CUR OFF
	CALL	DSP		;DO IT!
	POP	HL		;GET BUFF
	POP	BC
	RET
;
;	SELECT/DE-SEL VIDEO RAM
;
VDSEL	PUSH	AF		;SAVE
	LD	A,(VDMSK)	;VIDEO MASK
	OR	80H		;BANK
	OUT	(SELVD),A	;SWITCH VIDEO
	POP	AF		;RESTORE
	RET
;
VDOFF	PUSH	AF		;SAVE
	LD	A,(VDMSK)	;VIDEO MASK
	OUT	(SELVD),A	;DE-SEL VIDEO
	POP	AF		;RESTORE
	RET
;
;	POSITION CURSOR ROUTINE
;
;	ENT	HL =	CURSOR POS
;
PTCUR	PUSH	IX
	LD	A,1
	CALL	LOCDCB
	LD	(IX+11),L
	LD	(IX+12),H
	POP	IX
	RET
;
;	ADVANCE TO NEXT SECTOR AND DEC COUNTER
;
;	ENT	DE =	CYLINDER, SECTOR
;
DEC	CALL	SECUP		;ADV SECTOR
;
DEC1	PUSH	HL		;SAVE
	LD	HL,(COUNT)	;GET COUNT
	DEC	HL		;DEC COUNT
	LD	(COUNT),HL	;SAVE COUNT
	LD	A,H
	OR	L		;COUNT ZERO?
	POP	HL		;RESTORE
	RET	Z		;IF YES
	CALL	KEYBD		;GET KBD
	CP	BREAK		;BREAK KEY?
	RET			;RET WITH STAT
;
;	DISPLAY DRIVE, TRACK, SECTOR
;
;	ENT	 C =	DRIVE NUMBER
;		DE =	TRACK,SECTOR
;
DTKSC	PUSH	HL		;SAVE
	EX	DE,HL		;HL = TRK,SEC
	LD	A,C		;GET DRIVE
	AND	3
	OR	'0'             ;ASCII
	LD	(MES98+6),A	;DRIVE SET
	LD	A,H
	LD	DE,MES98+15
	CALL	BINHEX		;CYLINDER SET
	LD	A,L
	LD	DE,MES98+26
	CALL	BINHEX		;SECTOR SET
	EX	DE,HL		;DE = TRK,SEC
	LD	HL,MES98	;CYL X, SEC X
	CALL	DSPLYX		;OUTPUT!
	POP	HL		;RESTORE
	RET
;
;	POST ERROR MESSAGE ROUTINES
;
;	ENT	 A =	ERROR CODE
;		 C =	DRIVE NUMBER
;		DE =	TRACK,SECTOR
;
ERORC	LD	B,A		;B = CODE
	CALL	SAVER		;SAVE REG
	CALL	CLS		;CLEAR VIDEO
	LD	A,B		;GET CODE
	CALL	PRTERR		;PRINT ERROR
	LD	HL,MES99	;'Continue ?'
	CALL	DSPLY		;DSPLY, NO SAVER
	LD	B,3		;CHAR COUNT
	LD	HL,INPBUF
	CALL	KEYIN		;INPUT KBD LINE
	LD	A,(HL)		;GET INPUT
	RES	5,A		;IGNORE CASE
	CP	'Y'             ;YES?
	RET	Z
	CP	'C'             ;CONTINUE?
	RET
;
ERROR	CALL	PRTERR		;PRINT ERROR
	JP	INKEY		;WAIT FOR KEY
;
;	LOCATE ERROR MESSAGE HERE
;
;	ENT	 A =	ERROR CODE
;
PRTERR	PUSH	BC		;SAVE REG
	PUSH	AF
	CALL	DTKSC		;DISP TRK,SEC
	POP	BC		;B = CODE
	LD	HL,ERRMES	;ERROR LIST
PRTER2	LD	A,(HL)		;GET CHAR
	OR	A		;NEW MESSAGE?
	INC	HL		;NEXT
	JR	NZ,PRTER2	;IF NOT
	DJNZ	PRTER2		;TIL CORRECT MES
	CALL	DSPLY		;OUTPUT
	POP	BC		;RESTORE
	RET
;
;	PRINT LINE HANDLERS
;
;	ENT	HL => ASCII STRING
;
DSPLYX	CALL	SAVER		;SAVE REG
	CALL	VDSEL		;SEL VIDEO
	LD	DE,VIDEO+880	;START POS
DSPLX1	LD	A,(HL)		;GET CHAR
	OR	A		;EOT?
	JR	Z,DSPLX2	;SKIP
	LDI			;MOVE TO VIDEO
	JR	DSPLX1		;TIL DONE
DSPLX2	EX	DE,HL		;HL => CURSOR
	CALL	PTCUR		;POSN CURSOR
DSPLX3	LD	(HL),' '        ;BLANK
	INC	HL		;NEXT
	LD	A,L
	AND	4FH		;EOL?
	CP	40H
	JR	NZ,DSPLX3	;TIL EOL
	CALL	VDOFF		;DE-SEL VIDEO
	RET
;
DSPLY	LD	A,(HL)		;GET CHAR
	OR	A		;EOT?
	RET	Z		;EXIT
	CALL	DSP		;OUTPUT
	INC	HL		;NEXT
	JR	DSPLY		;TIL DONE
;
;	INPUT KEYBOARD LINE
;
;	ENT	HL =>	PROMPT MESSAGE
;
INPUTX	CALL	DSPLYX		;PROMPT
	LD	A,' '
	CALL	DSP
	LD	A,'?'
	CALL	DSP
	LD	A,' '
	CALL	DSP
	LD	HL,INPBUF	;HL => INPUT BUFF
	CALL	KEYIN		;DO INPUT
	LD	A,(HL)		;GET UNPUT
	CP	13		;NULL?
	RET
;
;	SUBROUTINE TO INPUT DRIVE
;
INPUT1	LD	B,1		;CHAR COUNT
	LD	HL,MES1 	;'Drive ?'
	CALL	INPUTX		;LINE INPUT
	LD	A,0		;DEFAULT
	JR	Z,INPT11	;GET GENERAL DATA
	CALL	DECBIN		;CONVERT
	JR	NZ,INPUT1	;BAD DIGIT
	LD	A,L		;GET RESULT
	CP	4		;LEGAL?
	JR	NC,INPUT1	;IF NOT
INPT11	LD	C,A		;C = DRIVE
	JP	GCALC		;GET GENERAL DATA
;
;	SUBROUTINE TO INPUT CYLINDER
;
INPUT2	LD	B,2		;CHAR COUNT
	LD	HL,MES2 	;'Cylinder ?'
	CALL	INPUTX		;LINE INPUT
	LD	D,0		;DEFAULT
	JP	Z,CCALC 	;GET CALC DATA
	CALL	HEXBIN		;CONVERT
	JR	NZ,INPUT2	;BAD DIGIT
	LD	D,L		;D = CYLINDER
	JP	CCALC		;GET CALC DATA
;
;	SUBROUTINE TO INPUT SECTOR
;
INPUT3	LD	B,2		;CHAR COUNT
	LD	HL,MES3 	;Sector ?'
	CALL	INPUTX		;LINE INPUT
	LD	E,(IY+1)	;DEFAULT
	RET	Z
	CALL	HEXBIN		;CONVERT
	JR	NZ,INPUT3	;BAD DIGIT
	LD	E,L		;E = SECTOR
	RET
;
;	SUBROUTINE TO INPUT SECTOR COUNT
;
INPUT4	LD	HL,1		;DEFAULT
	LD	(COUNT),HL	;INIT DEFAULT
;
INPT41	LD	B,5		;CHAR COUNT
	LD	HL,MES4 	;'Sector count ?'
	CALL	INPUTX		;LINE INPUT
	RET	Z		;NULL INPUT
	CALL	DECBIN		;CONV TO BIN
	JR	NZ,INPT41	;BAD DIGIT
	LD	A,H
	OR	L		;ZERO?
	JR	Z,INPT41	;TRY AGAIN
	LD	(COUNT),HL	;SAVE COUNT
	RET
;
;	SUBROUTINE TO INPUT CYLINDER COUNT
;
INPUT5	LD	HL,1		;DEFAULT
	LD	(COUNT),HL	;INIT DEFAULT
;
INPT51	LD	B,3		;CHAR COUNT
	LD	HL,MES5 	;'Cylinder count?'
	CALL	INPUTX		;LINE INPUT
	RET	Z		;NULL INPUT
	CALL	DECBIN		;CONVERT
	JR	NZ,INPT51	;BAD DIGIT
	LD	A,H
	OR	L		;ZERO?
	JR	Z,INPT51	;TRY AGAIN
	LD	(COUNT),HL	;SAVE COUNT
	RET
;
;	SUBROUTINE TO CONVERT ASCII HEX TO BINARY
;
;	ENT	HL =>	ASCII HEX TEXT
;
;	EXT	HL =	BINARY WORD
;
HEXBIN	CALL	SAVER		;SAVE REG
	EX	DE,HL		;DE => ASCII
	LD	HL,0		;INIT RESULT
;
HEXBN2	LD	A,(DE)		;GET CHAR
	INC	DE		;NEXT
	CP	13		;EOT?
	JR	Z,HEXBN4	;IF YES
	CALL	HEXCP1		;VALID HEX?
	JR	NC,HEXBN1	;IF YES
;
HEXBN4	POP	DE		;TEMP
	EX	(SP),HL 	;SAVE RESULT
	PUSH	DE		;REPLACE
	RET			;EXIT
;
HEXBN1	ADD	HL,HL		; * 2
	ADD	HL,HL		; * 4
	ADD	HL,HL		; * 8
	ADD	HL,HL		; * 16
	LD	B,0
	LD	C,A		;BC = DIGIT
	ADD	HL,BC		;ADD DIGIT
	JR	HEXBN2		;TRY AGAIN
;
;	SUBROUTINE TO CONVERT ASCII DECIMAL TO BINARY
;
;	ENT	HL =>	ASCII DECIMAL TEXT
;
;	EXT	HL =	BINARY WORD
;
DECBIN	CALL	SAVER		;SAVE REG
	EX	DE,HL		;DE => ASCII
	LD	HL,0		;INIT RESULT
;
DECBN2	LD	A,(DE)		;GET CHAR
	INC	DE		;NEXT
	CP	13		;EOT?
	JR	Z,DECBN4	;IF NOT
;
	SUB	'0'             ;KILL ASCII
	JR	C,DECBN4	;BAD DIGIT
	CP	10		;VALID?
	JR	C,DECBN1	;IF YES
	OR	A		;NZ STATUS
;
DECBN4	POP	DE		;TEMP
	EX	(SP),HL 	;SAVE RESULT
	PUSH	DE		;REPLACE
	RET
;
DECBN1	LD	B,H
	LD	C,L		;BC = RESULT
	ADD	HL,HL		; * 2
	ADD	HL,HL		; * 4
	ADD	HL,BC		; * 5
	ADD	HL,HL		; * 10
	LD	B,0
	LD	C,A		;BC = DIGIT
	ADD	HL,BC		;ADD DIGIT
	JR	DECBN2		;TRY AGAIN
;
;	GET CURRENT DRIVE INFO
;
;	ENT	 C =	DRIVE NUMBER
;		 D =	TRACK NUMBER
;
;	EXT	 C =	DRIVE + DEN
;		IY =>	CURRENT DRIVE INFO
;
CCALC	PUSH	HL		;SAVE REG
	PUSH	DE
	PUSH	BC
;
	PUSH	DE		;SAVE TRACK
	CALL	GCALC		;GET ALL INFO
	LD	A,(HL)		;A = FLAGS
	INC	HL		;NEXT
	LD	DE,CDATA+1	;CURRENT DATA
	LD	BC,5		;COUNT
	LDIR			;COPY DATA
	POP	DE		;GET TRACK
	INC	D
	DEC	D		;TRACK 0?
	JR	NZ,CALC1	;IF NOT
	RLCA			;TRK 0 TO BIT 7
	LD	DE,CDATA+3	;CURRENT DATA
	LD	BC,3		;COUNT
	LDIR			;COPY DATA
;
CALC1	POP	BC		;RESTORE REG
	POP	DE
	POP	HL
;
	LD	IY,CDATA	;IY => CALC DATA
	AND	80H		;DEN ONLY
	LD	(IY+0),A	;SET DEN
	RES	7,C		;IGNORE DEN
	OR	C		;SET DEN
	LD	C,A		;C = DRIVE+DEN
	RET
;
;	RETURN DRIVE INFORMATION
;
GCALC	LD	HL,GDATA	;HL => INFO
	LD	A,C		;GET DRIVE
	AND	3		;DRIVE ONLY
	LD	C,A		;C = DRIVE
	ADD	A,A		;* 2
	ADD	A,A		;* 4
	ADD	A,A		;* 8
	ADD	A,C		;* 9
	ADD	A,L
	LD	L,A		;HL => DRIVE
	RET	NC		;RETURN
	INC	H		;CORRECT
	RET
;
;	SINGLE PRECISION MULTIPLY
;
;	ENT	 E =	MULTIPLICAND
;		 A =	MULTIPLIER
;
;	EXT	 A =	RESULT
;
SMULT	PUSH	BC
	LD	D,A
	XOR	A
	LD	B,8
SMULT1	ADD	A,A
	SLA	E
	JR	NC,SMULT2
	ADD	A,D
SMULT2	DJNZ	SMULT1
	POP	BC
	RET
;
;	SINGLE PRECISION DIVIDE
;
;	ENT	 E =	DIVIDEND
;		 A =	DIVISOR
;
;	EXT	 A =	QUOTIENT
;		 E =	REMAINDER
;
SDIVD	PUSH	BC
	LD	C,A
	LD	B,8
	XOR	A
SDIVD1	SLA	E
	RLA
	CP	C
	JR	C,SDIVD2
	SUB	C
	INC	E
SDIVD2	DJNZ	SDIVD1
	LD	C,A
	LD	A,E
	LD	E,C
	POP	BC
	RET
;
;	READ SECTOR & GET AM
;
;	ENT	 C =	DRIVE INFO
;		DE =	TRACK,SECTOR
;
READ	PUSH	HL		;SAVE
	LD	HL,BUFFER	;I/O BUFFER
	CALL	READ1		;READ SECTOR
	POP	HL		;RESTORE REG
	RET
;
READ1	CALL	DREAD		;DO IT!
	JR	Z,READ2 	;NO ERRORS
	CP	6		;AM?
	RET	NZ		;IF NOT
	SUB	5		;AM
READ2	LD	(AM),A		;SET AM
	XOR	A		;NO ERROR
	RET
;
;	WRITE SECTOR WITH AM
;
;	ENT	 C =	DRIVE INFO
;		DE =	TRACK,SECTOR
;
WRITE	PUSH	HL		;SAVE
	LD	HL,BUFFER	;I/O BUFFER
	CALL	WRITE1		;WRITE W/AM
	POP	HL		;RESTORE
	RET
;
WRITE1	LD	A,(AM)		;GET AM
	ADD	A,CWRT1 	;WRITE CMD
	LD	(DWRITE+3),A	;SET CMD
	JP	DWRITE		;WRITE SECTOR
;
;	FORMAT CYLINDER ROUTINE
;
;	ENT	 C =	DRIVE NUMBER
;		 B =	INTERLEAVE
;		 D =	CYLINDER NUMBER
;		IY =>	DRIVE INFORMATION
;
;	INITIALIZE FORMAT INFO
;
FCYL	PUSH	BC		;SAVE REG
	PUSH	DE
	LD	A,C		;GET DRIVE
	RLCA
	RLCA
	RLCA			;BIT 6 TO 0
	AND	1		;BIT 0 ONLY
	LD	(SID1),A	;SET SIDE
	LD	A,D		;GET TRACK
	LD	(CYL1),A	;SET CYL
;
	PUSH	DE		;SAVE
	LD	C,(IY+3)	;SEC/TRK
	LD	E,D		;E = TRACK
	LD	A,B		;A = INTER
	ADD	A,A		;* 2
	ADD	A,B		;* 3
	CALL	SMULT		;TRACK * INTER
	LD	E,A		;E = TRK * INTER
	LD	A,C		;A = SEC/TRK
	CALL	SDIVD		;TRACK/INTER
	LD	A,E		;A = OFFSET
	POP	DE		;RESTORE
	LD	D,B		;D = INTERLEAVE
;
;	CALC SECTOR INTERLEAVE
;
	LD	HL,BUFFER	;HL => SEC BUFFER
	LD	B,C		;B = SEC/TRK
;
FCYL2	LD	(HL),-1 	;DUMMY
	INC	L		;NEXT
	DJNZ	FCYL2		;TIL DONE
	LD	E,0		;INIT SEC
	LD	B,C		;SEC/TRK
;
FCYL4	CP	C		;END TRK?
	JR	C,FCYL5 	;IF NOT
	SUB	C		;CORRECT
;
FCYL5	PUSH	DE		;SAVE
	LD	HL,BUFFER	;HL => SEC TABLE
	LD	E,A
	LD	D,0		;DE = SEC
	ADD	HL,DE		;HL => SEC
	POP	DE		;RESTORE
	BIT	7,(HL)		;UNUSED?
	JR	NZ,FCYL6	;IF YES
	INC	A		;NEXT
	JR	FCYL4		;TRY AGAIN
;
FCYL6	LD	(HL),E		;SET SECTOR
	INC	E		;NEXT
	ADD	A,D		;ADD INTERLEAVE
	DJNZ	FCYL4		;TIL DONE
	POP	DE		;RESTORE REG
	POP	BC
;
;	ACTUAL TRACK FORMAT
;
FTRK0	PUSH	BC		;SAVE REG
	PUSH	DE
	LD	C,(IY+3)	;SEC/TRK
	LD	HL,STBL 	;SDEN FORMAT TBL
	BIT	7,(IY+0)	;SDEN?
	JR	Z,FTRK4 	;IF YES
	LD	HL,DTBL 	;DDEN FORMAT TBL
;
;	LAYOUT FORMAT TRACK
;
FTRK4	LD	DE,BUFFER	;INTERLEAVE
	PUSH	DE		;SAVE SEC SEQ
	EX	DE,HL		;DE => FORMAT TABLE
	LD	HL,BUFER1	;I/O BUFFER
	CALL	SET		;GAP 1
	LD	(TBL),DE	;SAVE TABLE POS
;
TBL	EQU	$+1
FTRK5	LD	DE,0		;TABLE POS
	CALL	SET		;GAP 1 & 3
	CALL	SET		;GAP 1 & 3
;
	LD	(HL),0FEH	;ID AM
	INC	HL		;NEXT
CYL1	EQU	$+1
	LD	(HL),0		;CYLINDER NUM
	INC	HL		;NEXT
SID1	EQU	$+1
	LD	(HL),0		;SIDE NUM
	INC	HL		;NEXT
;
	EX	(SP),HL 	;HL => SEC NUM
	LD	A,(IY+1)	;SECTOR OFFSET
	ADD	A,(HL)		;GET SEC
	INC	HL		;NEXT
	EX	(SP),HL 	;RESTORE
;
	LD	(HL),A		;SECTOR NUM
	INC	HL		;NEXT
	LD	A,(IY+5)	;GET LENTH
	LD	(HL),A		;SECTOR LEN
	INC	HL		;NEXT
	LD	(HL),0F7H	;2 CRC'S
	INC	HL		;NEXT
;
	CALL	SET		;GAP 2
	CALL	SET		;GAP 2
	CALL	SET		;GAP 2
;
	LD	(HL),0FBH	;DATA AM
	INC	HL		;NEXT
	LD	A,0E5H		;DATA 0-F4 ONLY
	LD	B,(IY+4)	;DATA LENTH
	CALL	STF1		;FILL SECTOR
	LD	(HL),0F7H	;2 CRC'S
	INC	HL		;NEXT
;
	CALL	SET		;GAP 3
	DEC	C		;NEXT SECTOR
	JR	NZ,FTRK5	;TIL DONE
;
	EX	DE,HL		;SWAP
	LD	A,(HL)		;GET GAP 4
FTRK6	LD	HL,BUFER1+10671 ;END FORMAT BUFF
	SBC	HL,DE		;DONE?
	JR	C,FTRK7 	;IF YES
	LD	(DE),A		;FILL BUFF
	INC	DE		;NEXT
	JP	FTRK6		;TIL DONE
;
FTRK7	POP	DE		;CLEAN STACK
	POP	DE		;RESTORE REG
	POP	BC
;
;	WRITE FORMATTED BUFFER
;
	LD	E,0		;INIT SECTOR
	LD	HL,BUFER1	;I/O BUFFER
	JP	DFORM		;FORMAT
;
;	SUBROUTINE TO SET GAPS
;
SET	LD	A,(DE)		;DATA LENTH
	INC	DE		;NEXT
	LD	B,A		;B = DATA LENTH
	LD	A,(DE)		;DATA BYTE
	INC	DE		;NEXT
STF1	LD	(HL),A		;WRITE DATA
	INC	HL		;NEXT
	DJNZ	STF1		;TIL DONE
	RET
;
;	CURRENT DRIVE CALC DATA
;
CDATA	DEFB	0		;FLAGS
	DEFB	0		;SECTOR OFFSET
	DEFB	0		;TRACK COUNT
	DEFB	0		;SECTORS/TRACK
	DEFW	0		;SECTOR LENTH
;
;	TABLE OF DRIVE CALC DATA
;
GDATA	DEFB	80H		;FLAGS DDEN & SDEN
	DEFB	1		;SECTOR OFFSET
	DEFB	77		;TRACKS/DRIVE
	DEFB	26		;SECTORS/TRACK
	DEFW	256		;SECTOR LENTH
	DEFB	26		;TRK 0 SEC/TRK
	DEFW	128		;TRK 0 SEC LEN
;
	DEFB	80H		;FLAGS DDEN & SDEN
	DEFB	1		;SECTOR OFFSET
	DEFB	77		;TRACKS/DRIVE
	DEFB	26		;SECTORS/TRACK
	DEFW	256		;SECTOR LENTH
	DEFB	26		;TRK 0 SEC/TRK
	DEFW	128		;TRK 0 SEC LEN
;
	DEFB	80H		;FLAGS DDEN & SDEN
	DEFB	1		;SECTOR OFFSET
	DEFB	77		;TRACKS/DRIVE
	DEFB	26		;SECTORS/TRACK
	DEFW	256		;SECTOR LENTH
	DEFB	26		;TRK 0 SEC/TRK
	DEFW	128		;TRK 0 SEC LEN
;
	DEFB	80H		;FLAGS DDEN & SDEN
	DEFB	1		;SECTOR OFFSET
	DEFB	77		;TRACKS/DRIVE
	DEFB	26		;SECTORS/TRACK
	DEFW	256		;SECTOR LENTH
	DEFB	26		;TRK 0 SEC/TRK
	DEFW	128		;TRK 0 SEC LEN
;
;	SINGLE DENSITY FORMAT TABLE
;
STBL	DEFB	31
	DEFB	0FFH		;GAP 1
;
	DEFB	3
	DEFB	00H		;GAP 1 & 3
	DEFB	3
	DEFB	00H		;GAP 1 & 3
;
	DEFB	11
	DEFB	0FFH		;GAP 2
	DEFB	3
	DEFB	00H		;GAP 2
	DEFB	3
	DEFB	00H		;GAP 2
;
	DEFB	11
	DEFB	0FFH		;GAP 3
;
	DEFB	0FFH		;GAP 4
;
;	DOUBLE DENSITY FORMAT TABLE
;
DTBL	DEFB	62
	DEFB	4EH		;GAP 1
;
	DEFB	8
	DEFB	00H		;GAP 1 & 3
	DEFB	3
	DEFB	0F5H		;GAP 1 & 3
;
	DEFB	22
	DEFB	4EH		;GAP 2
	DEFB	12
	DEFB	00H		;GAP 2
	DEFB	3
	DEFB	0F5H		;GAP 2
;
	DEFB	24
	DEFB	4EH		;GAP 3
;
	DEFB	4EH		;GAP 4
;
*INCL	IOPACK2 		;I/O PACKAGE
;
;
;	MESSAGES AND TEXT
;
TITLE	DEFB	HOME
	DEFB	CUROF
	DEFM	'Model II Diskzap utility - Ver 1.0'
	DEFB	13
	DEFM	'Copyright (c) 1982, Micro-Systems Software Inc.'
	DEFB	13
	DEFB	13
	DEFM	'   Set'
	DEFB	13
	DEFM	'   Fill'
	DEFB	13
	DEFM	'   Copy'
	DEFB	13
	DEFM	'   Print'
	DEFB	13
	DEFM	'   Verify'
	DEFB	13
	DEFM	'   Format'
	DEFB	13
	DEFM	'   Display'
	DEFB	0
;
MES1	DEFM	'Drive'
	DEFB	0
MES2	DEFM	'Track'
	DEFB	0
MES3	DEFM	'Sector'
	DEFB	0
MES4	DEFM	'Sector count'
	DEFB	0
MES5	DEFM	'Track count'
	DEFB	0
MES6	DEFM	'Interleave factor'
	DEFB	0
MES7	DEFM	'Fill data'
	DEFB	0
MES8	DEFM	'Sector offset'
	DEFB	0
MES9	DEFM	'TRK 0 sec/trk'
	DEFB	0
MES10	DEFM	'TRK 0 density'
	DEFB	0
MES11	DEFM	'Sectors/track'
	DEFB	0
MES12	DEFM	'Track density'
	DEFB	0
MES14	DEFM	'TRK 0 sec len'
	DEFB	0
MES15	DEFM	'Sector lenth'
	DEFB	0
;
MES98	DEFM	'Drive 0, Track 00, Sector 00   '
	DEFB	0
;
MES99	DEFM	' continue ? '
	DEFB	0
;
ERRMES	DEFB	0
	DEFM	'H/W FAULT!'
	DEFB	0
	DEFM	'?'
	DEFB	0
	DEFM	'LOST DATA!'
	DEFB	0
	DEFM	'CRC ERROR!'
	DEFB	0
	DEFM	'SECTOR NOT FOUND!'
	DEFB	0
	DEFM	'AM/WRITE FAULT!'
	DEFB	0
	DEFM	'WRITE PROTECTED!'
	DEFB	0
	DEFM	'NOT READY!'
	DEFB	0
;
;	VARIABLES AND DATA
;
VDMSK	DEFB	1		;VIDEO MASK
SELECT	DEFB	1		;CURRENT OPTION
POINT	DEFW	VIDEO+240+1	;CURRENT POINTER
;
AM	DEFS	1		;CURRENT AM
SCNT	DEFS	1		;SECTOR COUNT
DRV1	DEFS	1		;SOURCE DRIVE
DRV2	DEFS	1		;DEST DRIVE
COUNT	DEFS	2		;CURRENT COUNT
COUNT2	DEFS	2		;TEMP COUNT
TKSEC1	DEFS	2		;CURRENT TRK,SEC
TKSEC2	DEFS	2		;CURRENT TRK,SEC
INPBUF	DEFS	5		;INPUT BUFFER
;
	END	ENTRY
 