;DISKIO2/ASM
*TITLE	'DISKIO2 - RESIDENT DISK I/O PACKAGE'
;
;	DISOIO2 IS THE RESIDENT DISK I/O PACKAGE.
;	STANDARD R/S HARD/FLOPPY CONTROLLERS SUPPORTED.
;
;	THIS PACKAGE CONSISTS OF TEN ROUTINES:
;
;	0 -	$DCHECK - CHECK DRIVE READY
;	1 -	$DHOME	- HOME/INITIALIZE DRIVE
;	2 -	$DSEEK	- SEEK SPECIFIED ADDRESS
;	3 -	$DREAD	- READ SECTOR W/SEEK
;	4 -	$DVERF	- VERIFY SECTOR W/SEEK
;	5 -	$DWRITE - WRITE SECTOR W/SEEK
;	6 -	$SREAD	- READ SYSTEM SECTOR W/SEEK
;	7 -	$SWRITE - WRITE SYSTEM SECTOR W/SEEK
;	8 -	$DFORMT - FORMAT TRACK W/SEEK
;	9 -	$DWRTE1 - WRITE SECTOR W/AM
;
*EJECT
;	DISK DRIVER CONSTANTS
;
TIME	EQU	90		;TIME OUT 3 SEC
DCT	EQU	0FEH		;DCT IDENTIFIER
ERR8	EQU	8		;DRIVE NOT READY
ER67	EQU	67		;DRIVE NOT IN SYSTEM
ER97	EQU	97		;DIR UNREADABLE
;
;	HARDWARE ADDRESSING MODEL II
;
HD#D	EQU	0C8H		;HDC DATA REGISTER
HD#E	EQU	0C9H		;HDC ERROR REGISTER
HD#W	EQU	0C9H		;HDC WRITE PRECOMP
HD#X	EQU	0CAH		;HDC SECTOR COUNT
HD#S	EQU	0CBH		;HDC SECTOR REGISTER
HD#L	EQU	0CCH		;HDC CYLINDER LOW
HD#H	EQU	0CDH		;HDC CYLINDER HIGH
HD#Q	EQU	0CEH		;HDC SIZE/HEAD/DRIVE
HD#C	EQU	0CFH		;HDC COMMAND/STATUS
;
PIOAD	EQU	0E0H		;PRINTER/FDC INT STATUS
FD#C	EQU	0E4H		;FDC COMMAND/STATUS
FD#T	EQU	0E5H		;FDC TRACK REGISTER
FD#S	EQU	0E6H		;FDC SECTOR REGISTER
FD#D	EQU	0E7H		;FDC DATA REGISTER
DRSL	EQU	0EFH		;DRIVE,MODE,SIDE SEL
DMAC	EQU	0F8H		;DMA COMMAND/STATUS
;
;	FLOPPY DISK COMMANDS
;
FREST	EQU	00001000B	;RESTORE & HDLD
FSEEK	EQU	00011000B	;SEEK & HDLD
FREAD	EQU	10000000B	;READ SECTOR
FWRTE	EQU	10100000B	;WRITE SECTOR
FCLER	EQU	11010000B	;CLEAR FDC
FFRMT	EQU	11110000B	;FORMAT TRACK
;
;	WINCHESTER DISK COMMANDS
;
HREST	EQU	00010000B	;RESTORE & INIT
HREAD	EQU	00100000B	;READ SECTOR
HWRTE	EQU	00110000B	;WRITE SECTOR
HFRMT	EQU	01010000B	;FORMAT TRACK
HSEEK	EQU	01110000B	;SEEK ADDRESS
;
*EJECT
;	$DISKIO - I/O COMMAND PROCESSOR
;
;	ENT	 C =	DEVICE NUMBER
;
DISKIO	CALL	REGSAV		;SAVE ALL REGISTERS
	PUSH	AF		;SAVE CMD
	CALL	LOCDCT		;LOCATE DCT
	POP	AF		;GET CMD
	BIT	3,(IY+0)	;NILL?
	JR	Z,DISKIO1	;IF NOT
	LD	A,ER67		;DRIVE NOT IN SYSTEM
	RET
;
DISKIO1 PUSH	HL		;SAVE
	LD	L,(IY+1)
	LD	H,(IY+2)	;HL => DRIVER
	EX	(SP),HL 	;RESTORE
	RET			;GO!
;
;	FLOPPY/HARD DRIVER ENTRY
;
FHCODE	PUSH	HL		;SAVE BUFFER
	LD	HL,DTABLE	;ROUTINE TABLE
	ADD	A,A		;* 2
	ADD	A,L
	LD	L,A		;HL => ENTRY
	JR	NC,$+3
	INC	H
	LD	A,(HL)		;LSB
	INC	HL		;NEXT
	LD	H,(HL)		;MSB
	LD	L,A		;HL => ROUTINE
	EX	(SP),HL 	;RESTORE BUFFER
	RET			;GO!
;
DTABLE	DEFW	DCHECK		;CHECK DRIVE READY
	DEFW	DHOME		;HOME/INIT DRIVE
	DEFW	DSEEK		;SEEK ADDRESS
	DEFW	DREAD		;READ SECTOR
	DEFW	DVERF		;VERIFY SECTOR
	DEFW	DWRITE		;WRITE SECTOR
	DEFW	SREAD		;READ SYSTEM SECTOR
	DEFW	SWRITE		;WRITE SYSTEM SECTOR
	DEFW	DFORM		;FORMAT TRACK
	DEFW	DWRIT1		;WRITE SECTOR W/SYS
;
*EJECT
;	$SREAD - READ SYSTEM SECTOR
;
;	ENT	 E =	SECTOR (0-3 IF DCT ASSUMED)
;		IY =>	DCT (ASSUMED)
;		HL =>	I/O BUFFER
;
;	EXT	IY =>	 CORRECT DCT
;
SREAD	BIT	0,(IY+5)	;LOG DISK?
	CALL	NZ,SREAD3	;IF YES
	RET	NZ		;IF ERROR
	LD	D,(IY+18)	;DIR CYLINDER
	BIT	6,(IY+13)	;DIRECTORY PROT?
	JR	NZ,SREAD2	;IF YES
	LD	A,3		;DREAD
	RST	IODISK		;DO IT!
	RET
;
SREAD2	LD	A,4		;DVERF
	RST	IODISK		;DO IT!
	SUB	56		;HAVE DIR?
	RET	Z		;IF YES
	SET	0,(IY+5)	;FORCE LOG-IN
	JR	SREAD		;TRY-AGAIN
;
SREAD3	CALL	REGSAV		;SAVE REGISTERS
	LD	DE,0<8+2	;CYL,SEC
	LD	B,D		;BE =SECTOR
	LD	A,1		;DHOME
	RST	IODISK		;HOME DRIVE
	RES	7,(IY+13)	;START SDEN
	LD	A,4		;DVERF
	RST	IODISK		;DO IT!
	JR	Z,SREAD4	;IF OK
	SET	7,(IY+13)	;TRY DDEN
	LD	A,4		;DVERF
	RST	IODISK		;TRY AGAIN
	RET	NZ		;IF ERROR
;
SREAD4	LD	A,(HL)		;GET 1ST CHAR
	CP	'D'             ;'DCT' ?
	LD	A,ER97		;UNKNOWN DISK
	RET	NZ		;IF ERROR
	RES	0,(IY+5)	;DISK LOGGED
	INC	HL		;NEXT
	INC	HL
	INC	HL		;HL => DATA
	LD	DE,13		;OFFSET
	ADD	IY,DE		;IY => DCT PERISH
	PUSH	IY
	POP	DE		;DE => DCT PERISH
	LD	BC,10		;COUNT
	LDIR			;MOVE!
	XOR	A		;NO ERROR
	RET
;
*EJECT
;	$DCHECK - CHECK DRIVE READY
;
;	ENT	IY =>	DCT
;
;	EXT	Z SET IF DRIVE READY
;		C SET IF WRITE PROT
;
DCHECK	BIT	5,(IY+5)	;HD?
	JR	Z,DCHEK0	;IF NOT
	LD	B,0
	LD	E,B		;BE = SECTOR
	CALL	UPTASK		;UPDATE TASK FILE
	IN	A,(HD#C)	;GET STATUS
	CPL			;INVERT
	AND	40H		;READY?
	JR	Z,DCHEK3	;TEST WP
	RET			;NOT AVAIL
;
DCHEK0	CALL	DSEL		;DRIVE SELECT
	CALL	DCLR		;CLEAR
	LD	HL,12629	;1 REV + 1 SEC
;
DCHEK1	CALL	CHKINX		;START WITH INDEX
	JR	NZ,DCHEK1
DCHEK2	CALL	CHKINX		;WAIT FOR INDEX TO PASS
	JR	Z,DCHEK2
DCHEK3	OR	(IY+5)		;GET SOFT WP
	RLCA			;WP TO 7
	AND	80H		;WP ONLY
	ADD	A,A		;WP TO CRY
	RET
;
CHKINX	DEC	HL		;NEXT
	LD	A,H		;TIME
	OR	L		;OUT?
	JR	Z,CHKIN2	;IF YES
	IN	A,(FD#C)	;GET STATUS
	BIT	1,A		;INDEX?
	RET
;
CHKIN2	POP	HL		;IGNORE CHKINX CALLER
	OR	ERR8		;NOT AVAIL
	RET
;
*EJECT
;	$DHOME - SEEK TRACK 0
;
;	ENT	IY =>	DCT
;
DHOME	BIT	5,(IY+5)	;HD?
	LD	(IY+11),0	;HEAD AT 0
	JR	Z,DHOME1	;IF NOT
	LD	A,HREST+3	;STEP
	CALL	HFCNW		;HOME
	LD	A,(IY+6)	;GET STEP
	OR	HREST		;RESTORE CMD
	JP	HFCNW		;ISSUE CMD
;
DHOME1	CALL	DSEL		;SEL DRIVE
	LD	A,(IY+6)	;GET CMD
	OR	FREST		;RESTORE CMD
	JP	DFCNW		;ISSUE CMD & WAIT
;
*EJECT
;	$DSEEK - DISK SEEK FUNCTION
;
;	ENT	DE =	CYL,SEC
;		IY =>	DCT
;
DSEEK	BIT	5,(IY+5)	;HD?
	JR	Z,DSEEK0	;IF NOT
	LD	A,(IY+6)	;STEP RATE
	OR	HSEEK		;SEEK COMMAND
	CALL	HFCNW		;ISSUE CMD
	LD	(IY+11),D	;SET CYL
	RET			;SEEK COMMAND
;
;	SET SECTOR & SELECT SIDE
;
DSEEK0	CALL	DSEL		;MAKE SURE SEL
	PUSH	DE		;SAVE
	LD	HL,SELMSK	;SELECT MASK
	SET	6,(HL)		;SIDE 0
	LD	A,E		;GET SECTOR
	SUB	(IY+16) 	;1ST SIDE?
	JR	C,DSEEK1	;IF YES
	RES	6,(HL)		;SIDE 1
	LD	E,A		;CORRECT
DSEEK1	LD	A,(IY+10)	;SECTOR OFFSET
	ADD	A,E		;+ SEC
	OUT	(FD#S),A	;SET SECTOR
	CALL	DSELX		;SEL SIDE
	POP	DE
;
;	SEEK TRACK IF NEEDED
;
	IN	A,(FD#T)	;GET TRACK
	SUB	D		;AT TRACK?
	RET	Z		;IF YES
;
	BIT	2,(IY+5)	;SKIP?
	JR	Z,DSEEK2	;IF NOT
	IN	A,(FD#T)	;GET TRACK
	ADD	A,A		;* 2
	OUT	(FD#T),A	;SET TRACK
DSEEK2	LD	A,D		;GET TRACK
	BIT	2,(IY+5)	;SKIP?
	JR	Z,DSEEK3	;IF NOT
	ADD	A,A		;* 2
DSEEK3	OUT	(FD#D),A	;SET TRACK
	LD	A,(IY+6)	;STEP RATE
	OR	FSEEK		;SEEK CMD
	CALL	DFCNW		;ISSUE CMD
	PUSH	AF		;SAVE STAT
	LD	(IY+11),D	;SET HEAD LOCATION
	LD	A,D		;GET TRACK
	OUT	(FD#T),A	;SET TRACK
	POP	AF		;GET STATUS
	RET
;
*EJECT
;	READ SECTOR ROUTINES
;
;	ENT	 B =	LSN HIGH
;		 E =	LSN LOW
;		 D =	CYLINDER
;		HL =>	I/O BUFFER
;		IY =>	DCT
;
DREAD	CALL	DIOP
	DEFB	FREAD		;FDC READ
	DEFB	HREAD		;HDC READ
	DEFB	5		;RETRY COUNT
	DEFB	51		;ERROR OFFSET
	DEFB	1		;I/O TYPE
;
DVERF	CALL	DIOP
	DEFB	FREAD		;FDC READ
	DEFB	HREAD		;HDC READ
	DEFB	1		;RETRY COUNT
	DEFB	51		;ERROR OFFSET
	DEFB	1		;I/O TYPE
;
;	WRITE SECTOR ROUTINES
;
;	ENT	 B =	LSN HIGH
;		 E =	LSN LOW
;		 D =	CYLINDER
;		HL =>	I/O BUFFER
;		IY =>	DCT
;
DWRITE	CALL	DIOP
	DEFB	FWRTE		;FDC WRITE
	DEFB	HWRTE		;HDC WRITE
	DEFB	5		;RETRY COUNT
	DEFB	59		;ERROR OFFSET
	DEFB	2		;I/O TYPE
;
SWRITE	LD	D,(IY+18)	;DIR TRACK
DWRIT1	CALL	DIOP
	DEFB	FWRTE+1 	;FDC WRITE
	DEFB	HWRTE		;HDC WRITE
	DEFB	5		;RETRY COUNT
	DEFB	59		;ERROR OFFSET
	DEFB	2		;I/O TYPE
;
;	FORMAT TRACK ROUTINE
;
;	ENT	 B =	LSN HIGH
;		 E =	LSN LOW
;		 D =	CYLINDER
;		HL =>	I/O BUFFER
;		IY =>	DCT
;
DFORM	CALL	DIOP
	DEFB	FFRMT		;FDC FORMAT
	DEFB	HFRMT		;HDC FORMAT
	DEFB	1		;RETRY COUNT
	DEFB	59		;ERROR OFFSET
	DEFB	4		;I/O TYPE
;
*EJECT
;	DISK I/O OPERATION
;
;	ENT	 B =	LSN HIGH
;		 E =	LSN LOW
;		 D =	CYLINDER
;		HL =>	I/O BUFFER
;		IY =>	DRIVE CONTROL TABLE
;		SP =>	FDC FUNCTION
;		SP+1 => RETRY COUNT
;		SP+2 => ERROR CODE OFFSET
;		SP+3 => XFER OPCODE
;
DIOP	POP	IX		;IX => INFO
	BIT	0,(IX+4)	;INPUT?
	JR	NZ,$+10 	;IF YES
	LD	A,(IY+5)	;GET FLAGS
	AND	40H		;WP?
	JP	NZ,DIOERR	;ERROR!
	BIT	5,(IY+5)	;HD?
	JR	Z,DIOP4 	;IF NOT
;
;	WINCHESTER I/O ROUTINE
;
DIOP1	PUSH	HL		;SAVE BUFFER
	CALL	UPTASK		;UPDATE TASK FILE
	CALL	CHKPHY		;CHECK PHY SEC
	POP	HL		;GET BUFFER
	LD	BC,0<8+HD#D	;COUNT & DATA REG
	LD	A,(IX+4)	;I/O TYPE
	RRCA			;INPUT?
	JR	C,DIOP2 	;IF YES
	JR	Z,DIOPA 	;REC-LOADED
	RRCA
	RRCA			;FORMAT?
	JR	C,DIOPA 	;IF YES
;
;	HD OUTPUT OPERATION
;
	LD	A,HREAD 	;READ FOR UPDATE
	OUT	(HD#C),A	;DO IT!
	CALL	HBUSY		;WAIT TIL READY
;
DIOPA	LD	A,(IX+1)	;HDC COMMAND
	OUT	(HD#C),A	;ISSUE CMD
	BIT	0,E		;ODD SECTOR?
	CALL	NZ,DSKIP	;SKIP 256
	OTIR			;WRITE DATA
	BIT	0,E		;GET STAT
	CALL	Z,DSKIP 	;SKIP 256
	CALL	HBUSY		;WAIT TIL READY
	JR	DIOP3		;ALL DONE!
;
;	HD INPUT OPERATION
;
DIOP2	LD	A,(IX+1)	;HDC COMMAND
	OUT	(HD#C),A	;ISSUE CMD
	CALL	HBUSY		;WAIT TIL READY
	BIT	0,E		;ODD SECTOR?
	CALL	NZ,DSKIP	;SKIP 256
	INIR			;READ DATA
;
;	GET HD ERROR STATUS
;
DIOP3	IN	A,(HD#E)	;GET ERROR CODE
	LD	B,A		;B = CODE
	IN	A,(HD#C)	;GET STATUS
	AND	1		;ERROR?
	RET	Z		;IF NOT
	LD	A,(IX+3)	;ERROR OFFSET
	ADD	A,49		;100+
	JR	DIOER1		;SKIP
;
DSKIP	IN	A,(C)		;READ DATA
	DJNZ	$-2		;TIL DONE
	RET
;
;	FLOPPY DISK I/O ROUTINE
;
DIOP4	LD	B,(IX+2)	;RE-TRY COUNT
	LD	(DMARD+9),HL	;DMA BUFF1
	LD	(DMAWD+3),HL	;DMA BUFF2
;
DIOP5	PUSH	BC		;SAVE CNT,DRV
	LD	HL,DMARD	;DMA READ DATA
	BIT	0,(IX+4)	;INPUT?
	JR	NZ,$+5		;GO
	LD	HL,DMAWD	;DMA WRITE DATA
	LD	BC,15<8+DMAC	;COUNT & DMA REG
	OTIR			;INIT DMA
	POP	BC		;GET CNT,DRV
;
;	SEEK REQUESTED TRACK
;
	CALL	DSEEK		;SEEK TRACK
	JR	NZ,DIOERR	;SEEK ERROR
;
;	FD DATA TRANSFER HERE
;
	LD	HL,FLAGK1	;MISC FLAGS
	CALL	DCLR		;GET STATUS
	BIT	5,A		;HL?
	LD	A,(IX+0)	;GET CMD
	JR	NZ,$+4		;IF YES
	OR	4		;15MS DELAY
	OUT	(FD#C),A	;ISSUE CMD
	SET	4,(HL)		;NO RTC VID SEL
	LD	A,87H		;DMA CMD
	OUT	(DMAC),A	;ISSUE CMD
	CALL	WAIT		;140 uS
;
DIOP8	IN	A,(FD#C)	;GET FDC INT
	AND	81H		;RDY,BSY
	DEC	A		;BUSY?
	JR	Z,DIOP8 	;IF YES
	LD	A,83H		;DMA TERM
	OUT	(DMAC),A	;ISSUE CMD
	RES	4,(HL)		;RTC VID SEL OK
;
;	GET FD ERROR STATUS
;
	IN	A,(FD#C)	;GET STATUS
	AND	0FDH		;I/O ERROR?
	RET	Z		;IF NOT
	DEC	B		;RETRY?
	JR	Z,DIOERR	;IF NOT
	BIT	2,A		;LOST DATA?
	JR	NZ,DIOP5	;IF YES - SKIP HOME
	CP	20H		;DAM OR WRITE FAULT?
	JR	Z,DIOERR	;IF YES - SKIP RETRY
	CP	40H		;WRITE PROT?
	JR	Z,DIOERR	;IF YES - SKIP RETRY
	CALL	DHOME		;HOME DRIVE
	JR	DIOP5		;TRY AGAIN
;
;	CONVERT ERROR CODE
;
DIOERR	LD	B,A		;B = CODE
	LD	A,(IX+3)	;ERROR OFFSET
DIOER1	RRC	B		;BIT TO CRY
	RET	C		;ANY?
	INC	A		;ERROR CODE
	JR	DIOER1		;TIL FOUND
;
*EJECT
;	FLOPPY DRIVE SELECT ROUTINE
;
;	ENT	IY =>	DCT
;
DSEL	PUSH	BC		;SAVE REG
	CALL	DCONV		;GET SEL/DEN
	LD	BC,CURDRV	;CURRENT DRIVE NUM
	LD	A,(BC)		;BINARY DRIVE
	CP	(IY+12) 	;AT DRIVE?
	JR	Z,DSEL2 	;IF YES
	LD	A,(IY+12)
	LD	(BC),A		;SET DRIVE
	LD	A,(IY+11)	;GET HEAD LOC
	OUT	(FD#T),A	;SET TRACK
;
;	OPTIONAL HEAD-LOAD DELAY
;
	BIT	3,(IY+5)	;HEAD LOAD?
	JR	Z,DSEL2 	;IF NOT
	CALL	DSELX		;SEL DRIVE
	CALL	DCLR		;CLEAR
	BIT	5,A		;HEAD LOADED?
	LD	BC,2400 	;15 MS
	CALL	NZ,DELAY	;HL ON SEL
;
;	OPTIONAL MOTOR-ON DELAY
;
DSEL2	BIT	4,(IY+5)	;MOTOR DELAY?
	JR	Z,DSEL3 	;IF NOT
	CALL	DSELX		;SELECT DRIVE
	IN	A,(FD#C)	;GET STATUS
	RLCA			;READY?
	JR	NC,DSEL3	;IF YES
	LD	BC,0		;DELAY
	CALL	DELAY		;426 MS
	CALL	DELAY		;852 MS
;
DSEL3	CALL	DSELX		;SELECT DRIVE
	POP	BC		;RESTORE
	RET
;
DSELX	LD	A,TIME		;TIME RESET
	LD	(DATAK0),A	;RESET TIMEOUT
	LD	A,(SELMSK)	;GET SEL MASK
	OUT	(DRSL),A	;SEL DRIVE/MODES
	RET
;
;	SELECT DRIVE & MODES
;
;	ENT	IY =>	DCT
;
DCONV	LD	A,(IY+12)	;GET DRIVE
	AND	3		;NUMBER ONLY
	RLCA
	RLCA
	RLCA
	OR	87H		;CONV TO INST
	LD	(BIT),A 	;PLACE INST
	LD	A,(IY+13)	;GET DENSITY
	AND	80H		;DEN ONLY
	OR	7FH		;NILL
BIT	EQU	$+1
	RES	0,A		;SEL BIT
	LD	(SELMSK),A	;SET MASK
	RET
;
*EJECT
;	ISSUE FD FUNCTION AND WAIT
;
;	ENT	 A =	DISK FUNCTION
;		IY =>	DCT
;
DFCNW	CALL	DFCN		;ISSUE CMD
DFCNW2	IN	A,(FD#C)	;GET STATUS
	RRCA			;BUSY?
	CALL	C,DSELX 	;SEL DRIVE
	JR	C,DFCNW2	;WAIT
	PUSH	BC		;SAVE
	LD	BC,2400 	;15MS
	CALL	DELAY		;DELAY
	POP	BC		;RESTORE
	IN	A,(FD#C)	;CLR INTRQ
	AND	98H		;RDY,SEEK,CRC
	RET
;
;	CLEAR FDC AND GET STATUS
;
DCLR	LD	A,FCLER 	;FORCE CLEAR
	CALL	DFCN		;ISSUE CMD
	CALL	DFCN		;ISSUE CMD
	IN	A,(FD#C)	;GET STATUS
	RET
;
;	ISSUE FDC COMMAND & WAIT
;
;	ENT	 A = DISK FUNCTION
;
DFCN	OUT	(FD#C),A	;ISSUE CMD
WAIT	PUSH	BC		;SAVE
	LD	B,14		;140uS
	DJNZ	$		;DELAY
	POP	BC		;RESTORE
	RET
;
;	CHECK IF HD SECTOR LOADED
;
;	ENT	 D =	CYLINDER
;		 E =	SECTOR LSB
;		 B =	SECTOR MSB
;		 C =	DRIVE
;
CHKPHY	PUSH	DE		;SAVE REG
	RES	0,E		;512 BYTE SECTORS
	LD	HL,(CHADD+0)	;SECTOR,DRIVE
	LD	(CHADD+0),BC	;SET NEW
	OR	A		;CLR CRY
	SBC	HL,BC		;MATCH?
	LD	HL,(CHADD+2)	;SECTOR CYL
	LD	(CHADD+2),DE	;SET NEW
	JR	NZ,$+4		;NO MATCH
	SBC	HL,DE		;MATCH?
	POP	DE		;RESTORE REG
	RET
;
CHADD	BYTES	4,-1		;TEMP STORAGE
;
*EJECT
;	UPDATE HARD DISK TASK FILE
;
;	ENT	 B =	LSN HIGH
;		 E =	LSN LOW
;		 D =	CYLINDER NUMBER
;		IY =>	DCT
;
UPTASK	LD	A,(IY+8)	;CYL OFFSET
	ADD	A,D		;CYLINDER
	OUT	(HD#L),A	;SET CYL LOW
	LD	A,(IY+9)	;CYL OFFSET
	ADC	A,0		;MSB
	OUT	(HD#H),A	;SET CYL HIGH
	LD	H,B
	LD	L,E		;HL = SECTOR
	LD	A,(IY+16)	;SEC/TRACK
	CALL	DDIVD		;GET SRFCE,SEC
	SRL	A		;/2 (512 BYTE SEC)
	ADD	A,(IY+10)	;SECTOR OFFSET
	OUT	(HD#S),A	;SET SECTOR
	LD	A,(IY+12)	;BINARY DRIVE
	RLCA
	RLCA
	RLCA			;TO BITS 3-5
	OR	20H		;+SIZE
	ADD	A,(IY+7)	;HEAD OFFSET
	ADD	A,L		;+ HEAD
	OUT	(HD#Q),A	;SET SIZE/DRIVE/HEAD
	RET
;
;	ISSUE HD FUNCTION & WAIT
;
;	ENT	 A =	DISK FUNCTION
;		IY =>	DCT
;
HFCNW	PUSH	AF		;SAVE CMD
	CALL	UPTASK		;UPDATE TASK FILE
	POP	AF		;GET CMD
	OUT	(HD#C),A	;ISSUE CMD
	CALL	HBUSY		;WAIT TIL READY
	IN	A,(HD#C)	;GET STATUS
	AND	1		;ERROR?
	RET	Z		;IF NOT
	IN	A,(HD#E)	;A = ERROR
	RET
;
;	WAIT FOR HDC READY
;
HBUSY	IN	A,(HD#C)	;HDC STATUS
	RLCA			;BUSY?
	JR	C,HBUSY 	;WAIT
	RET
;
*EJECT
;	DMA READ INITIALIZE DATA
;
DMARD	DEFB	0C3H		;WR6 - RESET
	DEFB	08BH		;WR6 - CLEAR STATUS
	DEFB	069H		;WR0 - PORTA ADD FOLLOWS
	DEFB	FD#D		;FDC DATA REGISTER
	DEFW	10672		;BLOCK LENGTH
	DEFB	03CH		;WR1 - PORTA FIXED, I/O
	DEFB	010H		;WR2 - PORTB INC,MEMORY
	DEFB	08DH		;WR4 - BYTE, PORTB FOLLOWS
	DEFW	0000		;BUFFER ADDRESS
	DEFB	08AH		;WR5 - STOP,RDY HIGH
	DEFB	0CFH		;WR6 - LOAD START,CLEAR CNT
	DEFB	005H		;WR0 - PORTA -> PORTB
	DEFB	0CFH		;WR6 - LOAD START,CLEAR CNT
;
;	DMA WRITE INITIALIZE DATA
;
DMAWD	DEFB	0C3H		;MASTER RESET
	DEFB	08BH		;CLEAR EOB STATUS
	DEFB	079H		;PORTA ADD FOLLOWS
	DEFW	0000		;BUFFER ADDRESS
	DEFW	10672		;BLOCK LENGTH
	DEFB	014H		;WR1 - PORTA INC, MEMORY
	DEFB	028H		;WR2 - PORTB FIXED, I/O
	DEFB	085H		;WR4 - BYTE, PORTB FOLLOWS
	DEFB	FD#D		;FDC DATA REGISTER
	DEFB	08AH		;WR5 - STOP,RDY HIGH
	DEFB	0CFH		;WR6 - LOAD START,CLEAR CNT
	DEFB	005H		;WR0 - PORTA -> PORTB
	DEFB	0CFH		;WR6 - LOAD START,CLEAR CNT
 