
	.IDENT	DRVNEW
;
	.INSERT EQUATE
;
CH1DMA	= 64H		; CHANNEL 1 DMA REGISTER (FDC)
CH1TC	= 65H		; CHANNEL 1 TERMINAL COUNT (FDC)
DMACTL	= 68H		; DMA COMMAND AND STATUS REGISTER
DMAMOD	= 6BH		; DMA MODE REGISTER
DMACLR	= 6DH		; DMA MASTER-CLEAR REGISTER
DMAMSK	= 6FH		; DMA MASK ALL CHANNELS REGISTER
DSKSEL	= 0A8H		; DISK SELECT PORT
FDCST	= 0A0H		; DISK CONTROLLER STATUS (uPD-765)
FDCDAT	= 0A2H		; DISK CONTROLLER DATA (uPD-765)
;
CH2EN1	= 10H		; DMA CHANNEL 2 ENABLE COMMAND #1
CH2EN3	= 0BH		; DMA CHANNEL 2 ENABLE COMMAND #3
DMAVFY	= 52H		; DMA VERIFY COMMAND
DMARD	= 56H		; DMA READ COMMAND
DMAWR	= 5AH		; DMA WRITE COMMAND
;
FDCSFY	= 03H		; FDC SPECIFY COMMAND
FDCSDS	= 04H		; FDC SENSE DRIVE STATUS COMMAND
FDCRCL	= 07H		; FDC RECALIBRATE COMMAND
FDCSIS	= 08H		; FDC SENSE INTERRUPT STATUS COMMAND
FDCRID	= 0AH		; FDC READ ID COMMAND
FDCFMT	= 0DH		; FDC FORMAT TRACK COMMAND
FDCSK	= 0FH		; FDC SEEK COMMAND
FDCWR	= 05H		; FDC WRITE COMMAND
FDCRD	= 06H		; FDC READ COMMAND
;
DSKENI	= 0F5H		; DISK CONTROLLER ENABLE INTERRUPTS
;
FDCMFM	= 6		; FDC DOUBLE-DENSITY BIT
FDCMT	= 7		; FDC MULTI-TRACK BIT
;
FDCBSY	= 4		; FDC BUSY STATUS
FDCSE	= 5		; FDC SEEK END
FDCOUT	= 6		; FDC OUTPUT MODE
FDCRDY	= 7		; FDC READY FOR DATA
;
SRT8Q	= 3		; 8 INCH FDD STEP RATE (3 MS-QUME)
SRT8S	= 8		; 8 INCH FDD STEP RATE (8 MS-SHUG)
SRT5P	= 1		; 5.25 INCH FDD STEP RATE (1 MS-PHIL)
;
HDLT	= 0   		; FDD HEAD LOAD TIME 
HDUT	= 0		; FDD HEAD UNLOAD TIME
;
ST0NR	= 3		; STATUS REGISTER 0 NOT READY
ST0EC	= 4		; STATUS REGISTER 0 EQUIPMENT CHECK
ST0SE	= 5		; STATUS REGISTER 0 SEEK END
;
ST1MA	= 0		; STATUS REGISTER 1 MISSING ADDRESS MARK
ST1NW	= 1		; STATUS REGISTER 1 NOT WRITABLE
ST1ND	= 2		; STATUS REGISTER 1 NO DATA
ST1OR	= 4		; STATUS REGISTER 1 OVER RUN
ST1DE	= 5		; STATUS REGISTER 1 DATA ERROR
;
ST3TS	= 3		; STATUS REGISTER 3 TWO SIDED
ST3T0	= 4		; STATUS REGISTER 3 TRACK 0
ST3RDY	= 5		; STATUS REGISTER 3 READY
ST3WP	= 6		; STATUS REGISTER 3 WRITE PROTECTED
;
TSD	= 2		; TWO-SIDED DISK BIT (TYPE CODE)
DDD	= 3		; DOUBLE DENSITY DISK BIT (TYPE CODE)
;
MINI	= 4		; MINI-FLOPPY DISK BIT (TYPE CODE)
;
SASIC2	=	00009H	; COPY OF SASI CONTROL PORT 2
IPLFLG	=	0000DH	; IPL-FLAG
PFLIV	=	00010H	; POWER FAILURE LINE INTERRUPT VECTOR
FDCIV	=	0001EH	; FLOPPY DISC CONTROLLER INTERRUPT VECTOR
LMPFLD	=	0004CH	; LAMP FIELD
CEBYTI	=	0005BH	; CONTROLLER ERROR BYTE INSIDE TEST
PBDFLG	=	0FFFEH	; POWER BREAKDOWN FLAG

	.LOC	.DATA.#


TRYCNT:	.BYTE	0	; 319D
IORWC:	.BYTE	0
IODMAC:	.BYTE	0

RETSP:	.WORD	0

Y31A2:	.BYTE	0
DRV0TR:	.BYTE	0
DRV1TR:	.BYTE	0

CURSEC:	.BYTE	0
CURADR:	.WORD	0

CURSC:	.BYTE	0
Y31A9:	.BYTE	0
Y31AA:	.BYTE	30H
Y31AB:	.BYTE	0
Y31AC:	.BYTE	0
Y31AD:	.BYTE	0
Y31AE:	.BYTE	0
Y31AF:	.BYTE	0
Y31B0:	.BYTE	0
MAXTRY:	.BYTE	0
Y31B2:	.BYTE	0
Y31B3:	.BYTE	0
Y31B4:	.BYTE	0
	.BYTE	0
	.BYTE	0
	.BYTE	0

DMXSPH:	.WORD	1
..DMXH:	.WORD	..DMXH
	.WORD	..DMXH

DWTSPH:	.WORD	0
..DWTH:	.WORD	..DWTH
	.WORD	..DWTH

IDINFO:
CYL:	.BYTE	0
HEAD:	.BYTE	0
REC:	.BYTE	0
SIZE:	.BYTE	0
EOT:	.BYTE	0
GPL:	.BYTE	0
DTL:	.BYTE	0

RESULT:
ST0R:	.BYTE	0
ST1R:	.BYTE	0
ST2R:	.BYTE	0
RCYL:	.BYTE	0
RHEAD:	.BYTE	0
RREC:	.BYTE	0
RSIZE:	.BYTE	0

MSTINT:	.BYTE	0
MSTOUT:	.BYTE	0
MSTIN:	.BYTE	0
ST3:	.BYTE	0
ST0:	.BYTE	0
MAXCNT:	.BYTE	20H
STD:	.BYTE	0
;
;
	.LOC	.PROG.#	; LOCATE IN PROGRAM AREA
;
FXDIN%::
FXDST%::
DSKIN%::LDA	IPLFLG	; IPL-FLAG AUF PMU80-3 PR]FEN
	BIT	7,A
	JRZ	A2646
	MVI	A,040H	; WENN PMU80-3, DANN 40H NACH 31D7H
	STA	MAXCNT
A2646:	LDA	PBDFLG	; POWER BREAKDOWN-FLAG PR]FEN
	CPI	0ABH
	JRNZ	A26A6	; WARTEN, BIS FLAG = 0ABH
	LDA	Y31AF
	BIT	1,A
	JRZ	A268C	; ]BLICHERWEISE SPRINGEN

; ***********************************************************************

	LHLD	.UND.#
	SHLD	Y31B4
 	MOV	A,M
	STA	Y31B2
	INX	H
	MOV	A,M
	STA	Y31B3
	ORA	A
	LBCD	Y31B2
	LXI	H,A2646
	DSBC	B
	JRNC	A2684
	LXI	B,A2DED+1
	LHLD	Y31B2
	DSBC	B
	JRNC	A2684
	LHLD	Y31B4
	LXI	B,T26EC
	MOV	M,C
	INX	H
	MOV	M,B
	JMPR	A26A6
;
A2684:	XRA	A
	SET	3,A
	STA	Y31AF
	JMPR	A26A6

;**************************************************************************

A268C:	LDA	Y31AF
	BIT	2,A
	JRZ	A26A6

	XRA	A
	STA	FLEXD5#
	SET	3,A
	STA	Y31AF
	LXI	H,DWTSPH	; SEMAPHORE
	CALL	SIGNAL#
	XRA	A
	STA	Y31AD

A26A6:	LXI	H,CEBYTI
	BIT	0,M
	JRNZ	A26E0

	LXI	H,DSKISR	; ABH[NGIG VOM IPL-FLAG DISK-INTERRUPT-ADRESSE
	LDA	IPLFLG		; ENTWEDER AUF FDCIV ODER PFLIV SCHREIBEN
	BIT	7,A
	JRZ	A26BC
	SHLD	PFLIV
	JMPR	A26BF
;
A26BC:	SHLD	FDCIV
A26BF:	MVI	A,03CH
	OUT	082H	; SASI-SCHNITTSTELLE INAKTIV LEGEN
	STA	SASIC2
	MVI	A,035H
	OUT	0A8H	; MOTOR 1, 2 ON; ENABLE INTERFACE, ENABLE FDC
	STA	Y31A9
	MVI	A,00BH
	OUT	0AAH	; TEST-LED OFF, R/W-TEST RESET
	MVI	A,003H	; FDC INITIALISIEREN
	CALL	CMDRDY	; .
	MVI	A,0FFH	; .
	CALL	CMDRDY	; .
	MVI	A,002H	; .
	CALL	CMDRDY	; .
A26E0:	RET
;
DSKDR%::LXI	H,DMXSPH	; GET MUTUAL EXCLUSION SEMAPHORE
	CALL	WAIT#		; DISPATCH IF NECESSARY
	LXI	H,Y31AF
	SET	1,M	; TREIBER BEREITS AUFGERUFEN
T26EC:	XRA	A
	STA	Y31B0	; CLEAR ERROR FLAGS
	MOV	A,PDRFCN(X)	; GET PD REQ FUNCTION NUMBER
	ANI	0F0H
	CPI	0F0H	; FIXED DISK ACCESS?
	JRNZ	A26FE	; IF NOT, CONTINUE
	CALL	XXFXD	; CALL FIXED DISK DRIVER (?)
	JMPR	A2701
;
A26FE:	CALL	XXDD	; CALL DISK DRIVER
A2701:	PUSH	PSW	; SAVE RETURN CODE
	XRA	A
	STA	Y31AF	; RESET ACTION FLAGS
	LXI	H,DMXSPH	; GET MUTUAL EXCLUSION SEMAPHORE
	CALL	SIGNAL#	; SIGNAL PROCESS AS READY
	POP	PSW	; RESTORE RETURN CODE
	RET		; DONE
;
XXFXD:	EI
	MVI	A,001H
	STA	MAXTRY
	SSPD	RETSP	; SAVE ERROR RETURN STACK POINTER
	LXI	H,CEBYTI
	BIT	0,M
	JNZ	A2766
	MOV	A,PDRFCN(X)	; GET FUNCTION NUMBER
	ANI	00FH
	ORA	A	; PD REQ FUNCTION NUMBER=0?
	JZ	RDDSK	; IF SO, CONTINUE
	DCR	A	; PDR FUNCTION NUMBER=1?
	JZ	WRDSK	; IF SO, CONTINUE
	DCR	A	; PDR FUNCTION NUMBER=2?
	JZ	RETDST	; IF SO, CONTINUE
	DCR	A	; PDR FUNCTION NUMBER=3?
	PUSH	PSW	; SAVE RESULT
	CALL	A2760
	POP	PSW	; RESTORE RESULT
	JZ	RETRDY	; IF SO, CONTINUE
	DCR	A	; PDR FUNCTION NUMBER=4?
	JRZ	A2746	; IF SO, CONTINUE
	DCR	A	; PDR FUNCTION NUMBER=5?
	JRZ	A274C	; IF SO, CONTINUE
	DCR	A	; PDR FUNCTION NUMBER=6?
	JRZ	A2755	; IF SO, CONTINUE
	MVI	A,080H
	RET		; ELSE DONE
;
A2746:	MOV	B,PDRDRV(X)
	JMP	RECAL
;
A274C:	MOV	B,PDRDRV(X)
	MOV	C,PDRTRK(X)
	JMP	SEEKTR
;
A2755:	MOV	A,PDRDRV(X)
	STA	Y31A2
	MVI	A,04AH
	JMP	READID
;
A2760:	PUSH	B
	CALL	MTRON
	POP	B
	RET
;
A2766:	MOV	A,PDRFCN(X)
	ANI	00FH
	CPI	002H
	JRZ	A277A
	CPI	003H
	JRZ	A277A
	CPI	006H
	JRZ	A277D
	MVI	A,0FFH
	RET
;
A277A:	MVI	A,000H
	RET
;
A277D:	ORA	A
	RET
;
XXDD:	EI
	MVI	A,008H
	STA	MAXTRY	; SET MAX TRY COUNT
	SSPD	RETSP	; SAVE ERROR RETURN STACK POINTER
	LXI	H,CEBYTI
	BIT	0,M
	JNZ	FATAL

	MOV	A,PDRFCN(X)	; GET PD REQ FUNCTION NUMBER
	ORA	A	; PDR FUNCTION NUMBER=0?
	JRZ	RDDSK	; IF SO, CONTINUE
	DCR	A	; PDR FUNCTION NUMBER=1?
	JRZ	WRDSK	; IF SO, CONTINUE
	DCR	A	; PDR FUNCTION NUMBER=2?
	JZ	RETDST	; IF SO, CONTINUE
	DCR	A	; PDR FUNCTION NUMBER=3?
	JZ	RETRDY	; IF SO, CONTINUE
	DCR	A	; PDR FUNCTION NUMBER=4?
	JZ	FMTDSK	; IF SO, CONTINUE
	DCR	A	; PDR FUNCTION NUMBER=5?
	JZ	DEFFMT	; IF SO, CONTINUE
	MVI	A,080H	; ELSE, RETURN 'FUNCTION NOT IMPLEMENTED'
	RET		; DONE
;
DEFFMT:	MOV	L,PDRDST(X)
	MOV	H,PDRDST+1(X)
	LXI	D,YSRFMT#+2
	LXI	B,15
	LDIR
	LHLD	YSRFMT#+13
	MOV	A,L
	ORA	H
	RZ
	XCHG
	LXI	H,YSRTAB#
	SHLD	YSRFMT#+13
	XCHG
	LBCD	YSRFMT#+7
	LDIR
	XRA	A
	RET
;
RDDSK:	CALL	XXLEDS	; TURN ON APPROPRIATE IN-USE-LAMP
	LDA	MAXTRY	; GET MAX TRY COUNT
	STA	TRYCNT	; SET TRY COUNT
	MOV	L,PDRTC(X)	; GET LSB OF TRANSFER COUNT
	MOV	A,PDRTC+1(X)	; GET MSB OF TRANSFER COUNT
	ORA	L	; NO. OF BYTES FOR TRANSFER =0?
	JRZ	..A  	; IF SO, CONTINUE
..RD:	MVI	A,FDCRD	; GET FDC READ COMMAND
	MVI	C,DMARD	; GET DMA READ COMMAND
	CALL	DSKCOM	; CALL COMON CODE
..A:	CZ	XXLEDR	; IF NO ERRORS, TURN OFF IN-USE LAMP
	RZ		; NO ERRORS, RET A=0
	CALL	RETRY	; ERRORS, RECALIBRATE
	JMPR	..RD	; TRY AGAIN
;
XXLEDR:	PUSH	PSW	; SAVE RETURN STATUS
	LDA	Y31A9	; GET OLD CONTROL PORT 1 SETTING
	OUT	0A8H	; SET CONTROL PORT 1
	POP	PSW	; RESTORE RETURN STATUS
	RET		; DONE
;
WRDSK:	CALL	XXLEDS	; TURN ON APPRORIATE IN-USE-LAMP
	LDA	MAXTRY	; GET MAX TRY COUNT
	STA	TRYCNT	; SET TRY COUNT
	MOV	L,PDRTC(X)	; GET LSB OF TRANSFER COUNT
	MOV	A,PDRTC+1(X)	; GET MSB OF TRANSFER COUNT
	ORA	L	; TRANSFER COUNT =0?
	JRZ	..A  	; IF SO, CONTINUE
..WR: 	MVI	A,FDCWR	; ELSE GET FDC WRITE COMMAND
	MVI	C,DMAWR	; GET DMA WRITE COMMAND
	CALL	DSKCOM	; CALL COMMON CODE
	JRNZ	..RT	; IF ERRORS, RETRY
	MVI	A,FDCRD	; ELSE GET FDC READ COMMAND
	MVI	C,DMAVFY   ; GET DMA VERIFY COMMAND
	CALL	DSKCOM	; CALL COMMON CODE
..A:	CZ	XXLEDR	; IF NO ERRORS, TURN OFF IN-USE-LAMP
	RZ		; NO ERRORS, RET A=0
..RT:	CALL	RETRY	; ERRORS, RECALIBRATE
	JMPR	..WR 	; TRY AGAIN
;
XXLEDS:	MOV	A,PDRDRV(X)	; GET DRIVE NUMBER
	ORA	A	; DRIVE 0 SELECTED?
	LDA	Y31A9	; GET LAST SETTING OF CONTROL PORT 1
	SET	6,A	; TURN ON IN-USE-LAMP OF DRIVE 0
	JRZ	A2809	; IF DRIVE 0 SELECTED, CONTINUE
	RES	6,A	; ELSE TURN OFF IN-USE-LAMP OF DRIVE 0 AND
	SET	7,A	; TURN ON LAMP OF DRIVE 1
A2809:	STA	Y31AC	; SAVE NEW CONTROL PORT 1 STATUS
	OUT	0A8H	; SET CONTROL PORT 1
	RET		; DONE
;
FMTDSK:	CALL	XXLEDS
	MOV	A,PDRTRK(X)   ; GET PD REQ TRACK NUMBER
	ORA	A	; PD REQ TRACK NUMBER=0?
	JRNZ	..NTR0	; IF NOT, CONTINUE
	MOV	A,PDRDRV(X)
	MOV	B,A
	CALL	RECAL
..NTR0:	LDA	MAXTRY	; GET MAX TRY COUNT
	STA	TRYCNT	; SET TRY COUNT
..FMT:	CALL	SEEK	; SELECT DISK AND SEEK
	MVI	A,DMAWR	; GET DMA WRITE COMMAND
	STA	IODMAC	; SET DMA COMMAND
	MOV	L,PDRTC(X)   ; GET PD REQ TRANSFER COUNT
	MOV	H,PDRTC+1(X)
	MOV	E,PDRDMA(X)   ; GET PD REQ DMA ADDRESS
	MOV	D,PDRDMA+1(X)
	CALL	DMANIT	; INITIALIZE DMA CONTROLLER
	MVI	A,FDCFMT   ; GET FORMAT TRACK COMMAND
	BIT	7,PDRSEC(X)   ; DOUBLE DENSITY FLAG SET?
	JRZ	..SD	; IF NOT, CONTINUE
	SET	FDCMFM,A   ; ELSE, SET DOUBLE DENSITY BIT
..SD:	CALL	A2DE2
	CALL	CMDRDY	; SEND FORMAT COMMAND TO FDC
	LDA	Y31B0
	BIT	0,A
	JRNZ	..E  
	MOV	A,PDRDRV(X)   ; GET PD REQ DRIVE NUMBER
	BIT	7,PDRSEC+1(X)   ; HEAD NUMBER ONE FLAG SET?
	JRZ	..HD0	; IF NOT, CONTINUE
	SET	2,A	; ELSE, SET HEAD ONE BIT
..HD0:	CALL	CMDRDY	; OUTPUT UNIT NUMBER TO FDC
	LDA	Y31B0
	BIT	0,A
	JRNZ	..E  
	MOV	A,PDRSEC(X)   ; GET PD REQ SECTOR (LSB)
	ANI	3	; EXTRACT FORMAT SECTOR SIZE
	CALL	CMDRDY	; OUTPUT FORMAT SECTOR SIZE TO FDC
	LDA	Y31B0
	BIT	0,A
	JRNZ	..E  
	MOV	A,PDRSC(X)   ; GET PD REQ SECTOR COUNT	
	CALL	CMDRDY	; OUTPUT SECTORS/TRACK TO FDC
	LDA	Y31B0
	BIT	0,A
	JRNZ	..E  
	MOV	A,PDRSEC+1(X)   ; GET PD REQ SECTOR (MSB)
	ANI	7FH	; EXTRACT FORMAT GAP LENGTH
	CALL	CMDRDY	; OUTPUT FORMAT GAP LENGTH TO FDC
	LDA	Y31B0
	BIT	0,A
	JRNZ	..E  
	MVI	A,0E5H	; GET FORMAT FILLER BYTE
	CALL	CMDRDY	; OUTPUT FORMAT FILLER BYTE TO FDC
	LDA	Y31B0
	BIT	0,A
	JRNZ	..E  
	CALL	WTINT	; WAIT FOR INTERRUPT
	LDA	ST0R	; GET STATUS REGISTER 0
..R:	ANI	0C0H	; ANY ERRORS?
	JZ	..A	; NO ERRORS, RET A=0
	CALL	RETRY	; ERRORS, RECALIBRATE
	JMP	..FMT
..A:	CALL	XXLEDR
	XRA	A
	RET
;
..E:	MVI	A,0C0H
	JMPR	..R
;
RETDST:	CALL	MTRON	; TURN DRIVE MOTOR ON
	CALL	RETRDY	; RETURN READY STATUS
	ORA	A	; DRIVE READY?
	JZ	A2891	; IF NOT, RETURN ERROR STATUS

	CALL	A29CC
	XRA	A
	STA	STD
	MOV	A,PDRDRV(X)
	MOV	B,A
	CALL	RECAL
	JNZ	A2891
	MOV	A,PDRDRV(X)
	MOV	B,A
	STA	Y31A2
	MVI	C,001H
	CALL	SEEKTR
	MOV	B,PDRDRV(X)
	MVI	C,001H
	JRZ	A2839
	MVI	C,0FFH
A2839:	CALL	UPDTRK
	JNZ	A2891
	MVI	C,000H	
	CALL	A28AA	; ATTEMPT TO FIND DISK DENSITY
	JRZ	..A  	; IF DENSITY FOUND, CONTINUE
	MOV	A,PDRDRV(X)
	MOV	B,A
	STA	Y31A2
	MVI	C,002H
	CALL	SEEKTR
	MOV	B,PDRDRV(X)
	MVI	C,001H
	JRZ	..B  
	MVI	C,0FFH
..B:	CALL	UPDTRK
	JNZ	A2891
	MVI	C,0
	CALL	A28AA
	JRNZ	A2891
	SET	6,C
	PUSH	PSW
	MVI	A,0FFH
	STA	STD
	POP	PSW
..A:	ORA	C	; ADD SECTOR SIZE TO TYPE CODE
	MOV	C,A
	MVI	A,0FFH
	STA	RHEAD
	MVI	A,00AH	; GET FDC READ ID COMMAND
	BIT	3,C	; DOUBLE DENSITY BIT SET?
	JRZ	A2854	; IF NOT, CONTINUE
	SET	6,A	; ELSE, SET MFM BIT
A2854:	LXI	H,Y31A2	; GET READ ID DISK
	SET	2,M	; SET HEAD BIT
	CALL	A28B9	; ATTEMPT TO READ ID ON BACK SIDE
	JRZ	A286D	; IF READABLE, CONTINUE
	MVI	A,00AH	; ELSE, TRY AGAIN
	BIT	3,C
	JRZ	A2866
	SET	6,A
A2866:	CALL	A28B9
	JRZ	A286D
	JMPR	A287A
;
A286D:	LDA	RHEAD
	CPI	000H
	JRZ	A287A
	CPI	001H
	JRNZ	A2891
	SET	2,C
A287A:	SET	4,C
	SET	5,C
	MOV	A,PDRDRV(X)
	LXI	D,DSTBLS#
	ANA	A
	JZ	A2881
	LXI	D,YSRFMT#
A2881:	MOV	A,C	; GET DISK TYPE CODE
	LXI	H,DTCO# ; GET OFFSET TO DISK TYPE CODE
	DAD	D	; CALC DISK TYPE CODE ADDRESS
	CMP	M	; DISK SPEC TABLE FOUND?
	JRZ	A2894	; IF SO, CONTINUE
	XCHG		; DISK SPEC TABLE ADDRESS TO HL-REG
	MOV	E,M	; GET DISK SPEC TABLE LINK POINTER
	INX	H	
	MOV	D,M
	MOV	A,D
	ORA	E	; END OF LIST?
	JRNZ	A2881	; IF NOT, CONTINUE
A2891:	MVI	A,000H	; ELSE, SET RETURN CODE=0
	RET		; DONE
;
A2894:	INX	D	; ADVANCE PAST LINK POINTER
	INX	D
	MOV	PDRDST(X),E   ; SET DISK SPEC TABLE ADDRESS
	MOV	PDRDST+1(X),D
	XCHG
	LXI	D,RESADR#
	DAD	D
	LXI	D,RESULT
	MOV	M,E
	INX	H
	MOV	M,D
	MVI	A,0FFH	; SET RETURN CODE=0FFH
	RET		; DONE
;
A28AA:	MVI	A,FDCRID   ; GET FDC READ ID COMMAND (SD)
	CALL	A28B9	; ATTEMPT TO READ SINGLE-DENSITY
	RZ		; IF SINGLE-DENSITY, DONE
	MVI	A,FDCRID!1<FDCMFM   ; GET FDC READ ID COMMAND (DD)
	CALL	A28B9	; ATTEMPT TO READ DOUBLE-DENSITY
	RNZ		; IF UNABLE, DONE
	SET	DDD,C	; SET DOUBLE-DENSITY DISK BIT
	RET		; DONE
;
A28B9:	PUSH	B	; SAVE BC
	CALL	READID	; READ DISK ID
	POP	B	; RESTORE BC
	RET		; DONE
;
RETRDY:	MOV	A,PDRDRV(X)	; GET PD REQ DISK NUMBER
	CPI	002H	; TEST FOR VALID DRIVE NUMBER
	JRNC	A28D8	; IF NOT VALID, CONTINUE
	LXI	H,Y31A9	; GET FDC STATUS
	ORA	A	; DRIVE 0 SELECTED?
	JRNZ	A28D0	; IF NOT, CONTINUE
	BIT	4,M	; ELSE, CHECK DRIVE 0 STATUS
	JMPR	A28D2	; CONTINUE
;
A28D0:	BIT	5,M	; CHECK DRIVE 1 STATUS
A28D2:	JRZ	A28D8	; IF DRIVE NOT PRESENT RETURN A=0
	CALL	A28DB	; ELSE SENSE DRIVE STATUS
	RET
;
A28D8:	MVI	A,000H
	RET
;
A28DB:	CALL	SENSDS	; SENSE DRIVE STATUS
	LDA	ST3	; GET STATUS REGISTER 3
	BIT	5,A	; DRIVE READY?
	MVI	A,000H	; PRESET RETURN CODE=0
	RZ		; IF DRIVE NOT READY, DONE
	CMA		; ELSE, SET RETURN CODE=0FFH
	RET		; DONE
;
MTRON:	DI		; DISABLE INTERRUPT
	LXI	H,Y31A9	; GET OLD CONTROL PORT 1 STATUS
	MOV	A,PDRDRV(X)	; GET DRIVE NUMBER
	ORA	A	; DRIVE 0 SELECTED?
	JRNZ	A2901	; IF NOT, CONTINUE
	BIT	4,M	; ELSE WAS MOTOR OF DRIVE 0 ON?
	PUSH	PSW	; SAVE RESULT
	LXI	H,Y31AA	
	RES	4,M	; RESET MOTOR ON BIT IN CONTROL PORT 1 BUFFER #1
	POP	PSW	; RESTORE RESULT
	EI		; ENABLE INTERRUPT
	CZ	A2910	; IF MOTOR WAS OFF, TURN MOTOR ON
	JMPR	A290E	; ELSE DONE
;
A2901:	BIT	5,M	; WAS MOTOR OF DRIVE 1 ON?
	PUSH	PSW	; SAVE RESULT
	LXI	H,Y31AA
	RES	5,M	; RESET MOTOR ON BIT IN CONTROL PORT 1 BUFFER #1
	POP	PSW	; RESTORE RESULT
	EI		; ENABLE INTERRUPT
	CZ	A2921	; IF MOTOR WAS OFF, TURN MOTOR ON
A290E:	EI		; ENABLE INTERRUPT
	RET		; DONE
;
A2910:	LDA	Y31A9	; GET OLD CONTROL PORT 1 STATUS
	SET	4,A	; SET DRIVE 0 MOTOR ON BIT
	STA	Y31A9	; UPDATE CONTROL PORT 1 STATUS
	OUT	0A8H	; SET CONTROL PORT 1 TO MOTOR DRIVE 0 ON
	LXI	H,0002DH	; GET MOTOR ON DELAY
	CALL	DELAY#	; DELAY 45 TICKS
	RET		; DONE
;
A2921:	LDA	Y31A9	; GET OLD CONTROL PORT 1 STATUS
	SET	5,A	; SET DRIVE 1 MOTOR ON BIT
	STA	Y31A9	; UPDATE CONTROL PORT 1 STATUS
	OUT	0A8H	; SET CONTROL PORT 1 TO MOTOR DRIVE 1 ON
	LXI	H,0002DH	; GET MOTOR ON DELAY
	CALL	DELAY#	; DELAY 45 TICKS
	RET		; DONE
;
; >> NO EXECUTION PATH TO HERE <<
MOTDRV::LDA	Y31AB
	ORA	A
	RZ
	LDA	Y31A9
	LXI	H,Y31AA
	BIT	4,M
	JRZ	A2943
	RES	4,A
A2943:	SET	4,M
	BIT	5,M
	JRZ	A294B
	RES	5,A
A294B:	SET	5,M
	STA	Y31A9
	OUT	0A8H
	RET
;
DSKCOM:	PUSH	PSW	; SAVE FDC READ/WRITE COMMAND
	PUSH	B	; SAVE DMA COMMAND
	CALL	MTRON	; TURN MOTOR ON
	PUSH	H
	PUSH	D
	CALL	GETTCA
	XRA	A
	STA	STD
	BIT	6,M
	JRZ	..A
	CMA
	STA	STD
..A:	POP	D
	POP	H
	POP	B	; RESTORE DMA COMMAND
	POP	PSW	; RESTORE FDC READ/WRITE COMMAND
	STA	IORWC	; SET FDC READ/WRITE COMMAND
	MOV	A,C	; GET DMA COMMAND
	STA	IODMAC	; SET DMA COMMAND
	MOV	A,PDRSEC(X)	; GET PD REQ SECTOR NUMBER
	STA	CURSEC	; SET CURRENT SECTOR
	MOV	L,PDRDMA(X)	; GET PD REQ DMA ADDRESS
	MOV	H,PDRDMA+1(X)
	SHLD	CURADR	; SET PD REQ CURRENT DMA ADDRESS
	MOV	A,PDRSC(X)	; GET PD REQ SECTOR COUNT
	STA	CURSC	; SET CURRENT SECTOR COUNT
	CALL	SEEK	; SELECT DISK AND SEEK
..RWL:	CALL	SETID	; SET UP SECTOR ID INFO
	CALL	SETUP	; SETUP READ/WRITE DMA
	CALL	DMANIT
	CALL	CMDOUT	; SEND SECTOR ID INFO TO FDC
	CALL	WTINT	; WAIT FOR INTERRUPT

	CALL	GETXLT	; GET TRANSLATION TABLE ADDRESS
	JRZ	..NI	; IF TRANSLATION NOT REQUIRED, CONTINUE
	LXI	H,CURSEC   ; ELSE, GET CURRENT SECTOR NUMBER
	INR	M	; INCREMENT CURRENT SECTOR
	CALL	CALCSS	; CALC SECTOR SIZE
	XCHG		; SECTOR SIZE TO DE-REGISTER
	LHLD	CURADR	; GET CURRENT DMA ADDRESS
	DAD	D	; CALC NEXT DMA ADDRESS
	SHLD 	CURADR	; UPDATE CURRENT DMA ADDRESS
	LXI	H,CURSC	; GET CURRENT SECTOR COUNT
	DCR	M	; DECREMENT CURRENT SECTOR COUNT
	JRNZ	..RWL	; IF TRANSFER NOT COMPLETE, CONTINUE

..NI:	LDA	ST0R	; GET I/O ERROR STATUS
	ANI	0C0H	; EXTRACT COMPLETION STATUS
	RET		; DONE
;
RETRY:	MOV	B,PDRDRV(X)   ; GET PD REQ DRIVE NUMBER
	CALL	RECAL	; RECALIBRATE DRIVE
	JRZ	A2999	; IF NO ERRORS, CONTINUE
	JMP	FATAL	; ELSE FATAL ERROR
;
A2999:	LXI	H,TRYCNT   ; GET RETRY COUNT
	DCR	M	; DECREMENT RETRY COUNT
	RNZ		; IF OT EXHAUSTED, TRY AGAIN
	JMP	FATAL	; ELSE FATAL ERROR
;
READID:	CALL	A2DE2
	CALL	CMDRDY
	LDA	Y31B0
	BIT	0,A
	JRNZ	A29C7
	LDA	Y31A2
	CALL	CMDRDY
	LDA	Y31B0
	BIT	0,A
	JRNZ	A29C7
	CALL	WTINT
	LDA	ST0R
A29C1:	ANI	0C0H
	LDA	RSIZE
	RET
;
A29C7:	EI
	MVI	A,0C0H
	JMPR	A29C1
;
A29CC:	MOV	A,PDRDRV(X)	; GET PDR DISK NUMBER
	ORA	A
	LDA	Y31AD
	JRNZ	A29E3
	BIT	0,A
	JRNZ	A29EF
	CALL	A29F0
	SET	0,A
	STA	Y31AD
	JMPR	A29EF
;
A29E3:	BIT	1,A
	JRNZ	A29EF
	CALL	A29F0
	SET	1,A
	STA	Y31AD
A29EF:	RET
;
A29F0:	PUSH	PSW
	MOV	B,PDRDRV(X)
	MVI	C,005H
	CALL	SEEKTR
	MOV	B,PDRDRV(X)
	MVI	C,005H
	JRZ	A2A02
	MVI	C,0FFH
A2A02:	CALL	UPDTRK
	JRZ	A2A0A
	JMP	FATAL
;
A2A0A:	POP	PSW
	RET
;
RECAL:	CALL	A29CC
	PUSH	B	; SAVE DRIVE NUMBER
	MVI	A,FDCRCL   ; GET FDC RECALIBRATE COMMAND
	CALL	A2DE2
	CALL	CMDRDY	; OUTPUT COMMAND TO FDC
	LDA	Y31B0
	BIT	0,A
	JRNZ	A2A76
	POP	B	; GET DRIVE NUMBER
	PUSH	B	; SAVE DRIVE NUMBER
	MOV	A,B	; GET CONTROLLER DISK
	CALL	CMDRDY	; OUTPUT IT TO FDC
	LDA	Y31B0
	BIT	0,A
	JRNZ	A2A76
	CALL	WTINT	; WAIT FOR INTERRUPT
	LDA	ST0	; GET STATUS REGISTER 0
	ANI	0C0H!1<FDCSE	; EXTRACT COMPLETION STATUS
	CPI	1<FDCSE	; ANY ERRORS?
	POP	B
	MVI	C,000H	; SET TRACK NUMBER =0
	CZ	UPDTRK	; IF NOT, UPDATE CURRENT TRACK NUMBER
	CZ	A2A7C   ; IF NOT, DELAY 2 TICKS
	RZ		; IF NOT, DONE
	PUSH	B	; SAVE DRIVE AND TRACK NUMBER
	MVI	A,FDCRCL   ; GET FDC RECALIBRATE COMMAND
	CALL	A2DE2
	CALL	CMDRDY	; OUTPUT COMMAND TO FDC
	LDA	Y31B0
	BIT	0,A
	JRNZ	A2A76
	POP	B	; GET DRIVE AND TRACK NUMBER
	MOV	A,B	; GET CONTROLLER DISK
	CALL	CMDRDY	; OUTPUT IT TO FDC
	LDA	Y31B0
	BIT	0,A
	JRNZ	A2A77
	CALL	WTINT	; WAIT FOR INTERRUPT
	LDA	ST0	; GET STATUS REGISTER 0
A2A62:	ANI	0C0H!1<FDCSE   ; EXTRACT COMPLETION STATUS
	CPI	1<FDCSE	; ANY ERRORS?
	MOV	B,PDRDRV(X)   ; GET PD REQ DRIVE NUMBER
	MVI	C,000H	; SET TRACK NUMBER =0
	JRZ	A2A6F	; IF NO ERRORS, CONTINUE
	MVI	C,0FFH	; ELSE, SET INVALID TRACK NUMBER
A2A6F:	CALL	UPDTRK	; UPDATE CURRENT TRACK NUMBER
	CZ	A2A7C	; DELAY 2 TICKS
	RET
;
A2A76:	POP	B
A2A77:	EI
	MVI	A,0C0H
	JMPR	A2A62
;
A2A7C:	PUSH	PSW
	LXI	H,00002H
	CALL	DELAY#	; DELAY 2 TICKS
	LDA	Y31AF
	BIT	3,A
	JNZ	A2DCB
	POP	PSW
	RET
;
SENSDS:	MVI	A,004H	; GET FDC SENSE DRIVE STATUS COMMAND

	CALL	A2DE2
	CALL	CMDRDY	; OUTPUT COMMAND TO FDC
	LDA	Y31B0
	BIT	0,A
	JRNZ	A2AB8

	MOV	A,PDRDRV(X)	; GET PD REQ DISK NUMBER
	CALL	CMDRDY	; OUTPUT IT TO FDC
	LDA	Y31B0
	BIT	0,A
	JRNZ	A2AB8

	CALL	DATAIN	; GET STATUS REGISTER 3
	STA	ST3	; SAVE STATUS REGISTER 3
	LDA	Y31B0
	BIT	0,A
	JRNZ	A2AB8

	EI
	RET
;
A2AB8:	EI
	XRA	A
	RET
;
SEEK:	MOV	B,PDRDRV(X)	; GET PD REQ DISK NUMBER
	MOV	C,PDRTRK(X)	; GET PDREQ TRACK NUMBER
	CALL	SEEKTR	; SEEK TRACK
	RZ		; IF NO ERRORS, DONE
	JMP	FATAL	; CONTINUE
;
SEEKTR:	PUSH	B	; SAVE TRACK NUMBER AND DRIVE NUMBER
	MOV	A,B	; GET DRIVE NUMBER
	CPI	000H	; DRIVE 0 SELECTED?
	LXI	H,DRV0TR	; PRESET HL= DRIVE 0 CURRENT TRACK NUMBER
	JRZ	A2AD2	; IF SO, CONTINUE
	INX	H	; ELSE SET HL= DRIVE 1 CURRENT TRACK NUMBER
A2AD2:	MOV	A,C	; GET TRACK NUMBER
	CMP	M	; TRACK NUMBER = CURRENT TRACK NUMBER?
	MVI	A,000H	
	STA	ST0R	; CLEAR I/O ERROR STATUS
	JRZ	A2B2F	; IF SO, RESTORE TRACK AND DRIVE NUMBER AND RETURN
	MVI	A,FDCSK	; ELSE GET FDC SEEK-COMMAND
	CALL	A2DE2	; IF ...-FLAG SET, RESTART DISK OPERATION
	CALL	CMDRDY	; OUTPUT COMMAND TO FDC
	LDA	Y31B0	; GET ERROR FLAGS
	BIT	0,A	; SESCO OK?
	JRNZ	A2B29	; IF NOT, CONTINUE
	POP	B	; RESTORE BC
	PUSH	B	; SAVE BC
	MOV	A,B	; GET DRIVE NUMBER
	CALL	CMDRDY	; OUTPUT DRIVE NUMBER TO FDC
	LDA	Y31B0	; GET ERROR FLAGS
	BIT	0,A	; SESCO OK?
	JRNZ	A2B29	; IF NOT, CONTINUE
	POP	B	; RESTORE CODE AND DRIVE NUMBER
	PUSH	B
	LDA	STD	; GET SINGLE TRACK DENSITY FLAG
	ANA	A	; 48 TPI DRIVE?
	JRZ	..A	; IF NOT, CONTINUE
	SLAR	C	; ELSE, MULTIPLY TRACK NUMBER BY TWO
..A:	MOV	A,C	; GET TRACK NUMBER
	CALL	CMDRDY	; OUTPUT TRACK NUMBER TO FDC
	POP	B
	LDA	Y31B0	; GET ERROR FLAGS
	BIT	0,A	; SESCO OK?
	JRNZ	A2B2A	; IF NOT, CONTINUE
	CALL	WTINT	; WAIT FOR INTERRUPT
	LXI	H,00002H   
	CALL	DELAY#	; DELAY 2 TICKS
	LDA	Y31AF	; GET ACTION FLAGS
	BIT	3,A	; ...-FLAG SET?
	JNZ	A2DCB	; IF SO, CONTINUE
	LDA	ST0	; GET STATUS REGISTER 0
A2B17:	ANI	0C0H!1<FDCSE   ; EXTRACT COMPLETION STATUS
	CPI	1<FDCSE	; ANY ERRORS?
	MOV	B,PDRDRV(X)	; GET PD REQ DRIVE NUMBER
	MOV	C,PDRTRK(X)	; GET PD REQ TRACK NUMBER
	JRZ	A2B25	; IF NOT, CONTINUE
	MVI	C,0FFH	; ELSE, SET INVALID TRACK NUMBER
A2B25:	CALL	UPDTRK	; UPDATE CURRENT TRACK NUMBER
	RET		; DONE
;
A2B29:	POP	B
A2B2A:	EI
	MVI	A,0C0H
	JMPR	A2B17
;
A2B2F:	POP	B
	RET
;
UPDTRK:	PUSH	PSW	; SAVE RETURN STATUS
	LXI	H,DRV0TR   ; PRESET HL= DRIVE 0 CURRENT TRACK NUMBER
	MOV	A,B	; GET PD REQ DRIVE NUMBER
	ORA	A	; DRIVE 0 SELECTED?
	JRZ	A2B3A	; IF SO, CONTINUE
	INX	H	; ELSE, SET HL= DRIVE 1 CURRENT TRACK NUMBER
A2B3A:	MOV	M,C	; UPDATE CURRENT TRACK NUMBER
	POP	PSW	; RESTORE RETURN STATUS
	RET		; DONE
;
SETUP:	CALL	GETXLT	; GET TRANSLATION TABLE ADDRESS
	MOV	L,PDRTC(X)   ; GET PD REQ TRANSFER COUNT
	MOV	H,PDRTC+1(X)
	JRZ	..NI	; IF NO TRANSLATION RQRD, CONTINUE
	CALL	CALCSS
..NI:	LDED	CURADR	; GET CURRENT DMA ADDRESS
	RET
;
DMANIT:	DI		; DISABLE INTERRUPTS
	MVI	A,006H
	OUT	06AH	; CHANNEL 2 MASKIEREN
	MVI	A,011H
	OUT	068H	; MEMORY TO MEMORY ENABLE, ROTATING PRIORITY
	DCX	H
	OUT	06CH	; CLEAR BYTE F/F
	MOV	A,L
	OUT	065H	; SET TERMINAL COUNT LOW BYTE
	MOV	A,H
	OUT	065H	; SET TERMINAL COUNT HIGH BYTE
	MOV	A,E
	OUT	064H	; SET DMA ADDRESS LOW BYTE
	MOV	A,D
	OUT	064H	; SET DMA ADDRESS HIGH BYTE
	LDA	IODMAC
	OUT	06BH	; SET MODE REGISTER
	MVI	A,002H
	OUT	06AH	; CLEAR CHANNEL 2 MASK BIT
	EI		; ENABLE INTERRUPTS
	RET		; DONE
;
SETID:	MOV	A,PDRTRK(X)   ; GET PD REQ TRACK NUMBER
	STA	CYL	; SET CYLINDER
	LDA	CURSEC	; GET CURRENT SECTOR
	MOV	C,A	; SECTOR NUMBER TO C-REG

	CALL	GETXLT	; GET TRANSLATION TABLE ADDRESS
	JRZ	..NI	; IF TRANSLATION NOT REQUIRED, CONTINUE
	MVI	B,0	; ELSE, MAKE SECTOR NUMBER DOUBLE LENGTH
	DAD	B	; INDEX INTO TRANSLATION TABLE
	MOV	C,M	; GET TRANSLATED SECTOR NUMBER

..NI:	INR	C	; CONVERT SECTOR TO BASE 1
	MOV	B,SECTRK(X)   ; GET NUMBER OF SECTORS/TRACK
	CALL	GETTCA	; GET DISK TYPE CODE ADDRESS
	BIT	TSD,M	; TWO SIDED DISK?
	JRZ	..SSD 	; IF NOT, CONTINUE
	SRLR	B	; ELSE, CALC NUMBER OF SECTORS/SIDE
..SSD:	MOV	A,B	; GET NUMBER OF SECTORS/SIDE
	STA	EOT	; SET END OF TRACK SECTOR NUMBER
	CMP	C	; FRONT SIDE OF DISK?
	MVI	A,000H	; PRESET FOR FRONT SIDE
	JRNC	..FS 	; IF FRONT SIDE, CONTINUE
	MOV	A,C	; GET SECTOR NUMBER
	SUB	B	; SUBTRACT ONE SIDES WORTH
	MOV	C,A	; TO C-REG
	MVI	A,001H	; GET HEAD #1
..FS: 	STA	HEAD	; SET HEAD NUMBER
	MOV	A,C	; GET SECTOR NUMBER
	STA	REC	; SET SECTOR NUMBER
	MOV	A,SECSIZ(X)   ; GET RECORD SIZE
	STA	SIZE	; SET RECORD SIZE
	ORA	A	; N=0?
	MVI	A,080H	; PRESET DTL=128
	JRZ	..N0 	; IF N=0, CONTINUE
	MVI	A,0FFH	; ELSE, DTL=0FFH
..N0:	STA	DTL	; SET DATA LENGTH
	CALL	GETDST	; GET DST ADDRESS
	LXI	D,GAPLEN#   ; GET OFFSET TO GAP LENGTH
	DAD	D	; CALC GAP LENGTH ADDRESS
	MOV	A,M	; GET GAP LENGTH
	STA	GPL	; SET GAP LENGTH
	RET		; DONE
;
CMDOUT:	CALL	GETTCA	; GET DISK TYPE CODE ADDRESS
	LDA	IORWC	; GET READ/WRITE COMMAND
	BIT	DDD,M	; DOUBLE DENSITY DISK?
	JRZ	..SD 	; IF NOT, SINGLE DENSITY
	SET	FDCMFM,A   ; ELSE, SET DOUBLE DENSITY BIT
..SD:	BIT	TSD,M	; TWO SIDED DISK?
	JRZ	..SS 	; IF NOT, SINGLE SIDED
	SET	FDCMT,A	; ELSE, SET MULTI-TRACK BIT
..SS:	CALL	A2DE2	
	CALL	CMDRDY	; SEND COMMAND TO FDC
	LDA	Y31B0
	BIT	0,A
	JRNZ	A2BFC
	MOV	A,PDRDRV(X)   ; GET PD REQ DISK NUMBER
	LXI	H,HEAD	; GET HEAD NUMBER
	BIT	0,M	; HEAD #0?
	JRZ	..FS 	; IF SO, CONTINUE
	SET	2,A	; ELSE, SET HEAD #1 BIT IN I/O DISK
..FS:	CALL	CMDRDY	; OUTPUT IT TO FDC
	LDA	Y31B0
	BIT	0,A
	JRNZ	A2BFC
	LXI	H,IDINFO   ; GET SECTOR ID IFO
	MVI	A,0	; PRESET AKKU = TRACK-OFFSET
	MVI	A,0
	ADD	M	; ADD TRACK NUMBER
	CALL	CMDRDY
	LDA	Y31B0
	BIT	0,A
	JRNZ	A2BFC
	INX	H
	MVI	B,006H	; B=LENGTH OF ID INFO
..IDL:	MOV	A,M	; GET BYTE FROM LIST
	CALL	CMDRDY	; OUTPUT BYTE TO FDC
	LDA	Y31B0
	BIT	0,A
	JRNZ	A2BFC
	INX	H	; INCREMENT POINTER
	DJNZ	..IDL	; OUTPUT ENTIRE LIST
	RET		; DONE
;
A2BFC:	EI
	JMP	FATAL
;
DATAIN:	PUSH	B	; SAVE
	LDA	MAXCNT	; GET TRY COUNT
	MOV	B,A
A2C05:	IN	0A0H	; GET FDC STATUS
	STA	MSTIN	; SAVE FDC STATUS
	RLC		; TEST FDC FOR READY
	JRNC	A2C12	; IF NOT, TRY AGAIN
	RLC		; TEST FDC DIRECTION
	JRNC	A2C12	; IF WRONG, TRY AGAIN
	JMPR	A2C1A	; ELSE READ DATA BYTE
;
A2C12:	DJNZ	A2C05	; TRY SEVERAL TIMES
	CALL	A2D8A	; NO SUCCESS, CALL ERROR HANDLER
	POP	B	; RESTORE
	JMPR	A2C1D	; DONE
;
A2C1A:	IN	0A2H	; GET FDC DATA BYTE
	POP	B	; RESTORE
A2C1D:	RET		; DONE
;
CMDRDY:	MOV	C,A	; GET CODE
	PUSH	B	; SAVE CODE
	LDA	MAXCNT	; GET MAX TRY COUNT
	MOV	B,A	; B IS COUNTER
A2C24:	IN	0A0H	; READ MAIN STATUS REGISTER OF FDC
	STA	MSTOUT	; SAVE RESULT
	RLC		; REQUEST FOR MASTER?
	JRNC	FDCERR	; IF NOT, CONTINUE
	RLC		; ELSE TRANSFER FROM FDC TO PROCESSOR?
	JRC	FDCERR	; IF SO, CONTINUE
	JMPR	OUTCOM	; ELSE OUTPUT CODE TO FDC
;
FDCERR:	DJNZ	A2C24	; TRY SEVERAL TIMES
	CALL	A2D8A	; NO SUCCESS, CALL ERROR HANDLER
	POP	B	; RESTORE CODE AND DRIVE NUMBER
	JMPR	A2C3D	; DONE
;
OUTCOM:	POP	B	; RESTORE CODE AND DRIVE NUMBER
	MOV	A,C	; GET CODE
	OUT	0A2H	; OUTPUT CODE TO FDC
A2C3D:	RET		; DONE
;
WTINT:	LXI	H,DWTSPH
	XRA	A
	SET	2,A
	STA	Y31AF
	MVI	A,002H
	STA	FLEXD5#
	CALL	WAIT#
	DI
	LDA	Y31AF
	BIT	3,A
	JNZ	A2DCB
	LDA	Y31AE
	ORA	A
	JRZ	A2C6D
	XRA	A
	STA	Y31AE
	CALL	A26A6
	MVI	A,0FFH
	STA	ST0R
	STA	ST0
A2C6D:	EI
	RET
;
; >> NO EXECUTION PATH TO HERE <<
FD5TOT::CALL	A2C84
	MVI	A,0FFH
	STA	Y31AE
	LXI	H,DWTSPH	; SEMAPHORE
	CALL	SIGNAL#
	XRA	A
	SET	1,A
	STA	Y31AF
	RET
;
A2C84:	MVI	A,034H	; PREPARE INTERFACE BYTE
	OUT	0A8H	; SET CONTROL PORT 1, MOTOR 1&2 ON, ENABLE INTERFACE
	MVI	B,005H	; DELAY =5
A2C8A:	DJNZ	A2C8A	; WAIT
	RET		; DONE
;
DSKISR:	SSPD	INTSP#	; SAVE INTERRUPT STACK POINTER
	LXI	SP,INTSTK#   ; SET UP AUX STACK
	PUSH	PSW	; SAVE REGISTERS
	PUSH	B
	PUSH	D
	PUSH	H
..RQM1:	LDA	MAXCNT	; GET MAXCOUNT
	MOV	B,A
..RQML:	IN	FDCST	; GET FDC STATUS
	STA	MSTINT	; SAVE MAIN STATUS REGISTER
	BIT	FDCRDY,A	; FDC READY FOR CONVERSATION?
	JRNZ	..A  	; IF SO, CONTINUE
	DJNZ	..RQML	; ELSE, TRY MAXCOUNT TIMES
	CALL	A2D33
	JMPR	A2D19
;
..A:	BIT	FDCOUT,A   ; FDC IN OUTPUT MODE?
	JRNZ	..RW 	; IF SO, PROCESS
	MVI	A,FDCSIS   ; GET SENSE INTERRUPT STATUS CMD
	OUT	FDCDAT	; OUTPUT IT TO FDC DATA REGISTER
	CALL	DATIN1	; GET STATUS REGISTER 0
	PUSH	PSW	; SAVE STATUS REGISTER 0
	LDA	Y31B0
	BIT	0,A
	CNZ	A2D33
	JRNZ	A2D18
	POP	PSW	; GET STATUS REGISTER 0
	MOV	C,A	; SAVE IT IN C-REG
	ANI	0C0H	; EXTRACT COMPLETION STATUS
	CPI	080H	; INTERRUPT STACK EMPTY?
	JRZ	A2D28	; IF SO, DONE
	CALL	DATIN1	; GET PRESENT CYLINDER NUMBER
	PUSH	PSW	; SAVE PRESENT CYLINDER NUMBER
	LDA	Y31B0
	BIT	0,A
	CNZ	A2D33
	JRNZ	A2D18
	POP	PSW	; GET PRESENT CYLINDER NUMBER
	BIT	ST0SE,C	; READY LINE CHANGE STATE?
	JRZ	..RQM1	; IF SO, IGNORE
	STA	RCYL	; ELSE, SAVE PCN
	XRA	A	
	STA	FLEXD5#
	MOV	A,C	; GET STATUS REGISTER 0
	STA	ST0	; SAVE IT
	JMPR	..SIGC	; CONTINUE
;
..RW:	LXI	H,RESULT   ; GET RESULT TABLE
	MVI	B,007H	; GET LENGTH OF RESULT PHASE
..RL:	CALL	DATIN1	; GET RESULT BYTE FROM FDC
	PUSH	PSW	; SAVE RESULT BYTE
	LDA	Y31B0
	BIT	0,A
	CNZ	A2D33
	JRNZ	A2D18
	POP	PSW	; GET RESULT BYTE
	MOV	M,A	; STORE IN RESULT AREA
	INX	H	; INCREMENT POINTER
	DJNZ	..RL 	; READ ALL SEVEN BYTES
	XRA	A
	STA	FLEXD5#
	MVI	A,006H
	OUT	06AH
..SIGC:	LXI	H,DWTSPH   ; GET DISK WAIT SEMAPHORE
	CALL	SIGNAL#	; SIGNAL PROCESS AS READY
	XRA	A	
	SET	1,A
	STA	Y31AF
	JMPR	..RQM1
;
A2D18:	POP	PSW
A2D19:	LXI	H,0000DH
	BIT	7,M
	JRZ	A2D28
	MVI	A,008H
	OUT	022H
	MVI	A,020H
	OUT	022H
A2D28:	POP	H	; RESTORE REGISTERS
	POP	D
	POP	B
	POP	PSW
	LSPD	INTSP#
	EI
	RETI
;
A2D33:	PUSH	PSW
	LDA	Y31AF
	BIT	2,A
	JRZ	A2D46
	RES	2,A
	STA	Y31AF
	LXI	H,DWTSPH	; SEMAPHORE
	CALL	SIGNAL#
A2D46:	MVI	A,0FFH
	STA	ST0R
	STA	ST0
	POP	PSW
	RET
;
DATIN1:	PUSH	B
	LDA	MAXCNT
	MOV	B,A
A2D55:	IN	0A0H
	STA	MSTIN
	RLC
	JRNC	A2D62
	RLC
	JRNC	A2D62
	JMPR	A2D6C
;
A2D62:	DJNZ	A2D55
	LXI	H,Y31B0
	SET	0,M
	POP	B
	JMPR	A2D6F
;
A2D6C:	IN	0A2H
	POP	B
A2D6F:	RET
;
CALCSS:	LXI	H,128	; GET 128 BYTE SECTOR LENGTH
	MOV	A,SECSIZ(X)   ; GET SECTOR SIZE
..SL:	DCR	A	; DECREMENT SECTOR SIZE
	RM		; IF UNDERFLOW, DONE
	DAD	H	; ELSE, SHIFT SECTOR SIZE LEFT
	JMPR	..SL	; CONTINUE
;
GETXLT:	CALL	GETDST	; GET DST ADDRESS
	LXI	D,XLTBL#   ; GET OFFSET TO TRANSLATION TABLE
	DAD	D	; CALC TRANSLATION TABLE ADDRESS
	MOV	E,M	; GET TRANSLATION TABLE ADDRESS
	INX	H
	MOV	D,M
	XCHG		; TRANSLATION TABLE ADDRESS TO HL-REGISTER
	MOV	A,H
	ORA	L	; TRANSLATION REQUIRED?
	RET		; DONE
;
GETTCA:	CALL	GETDST
	LXI	D,TYPCOD#
	DAD	D
	RET
;
GETDST:	MOV	L,PDRDST(X)
	MOV	H,PDRDST+1(X)
	RET
;
A2D8A:	PUSH	PSW	; SAVE STATUS
	LXI	H,Y31B0	; GET ERROR FLAGS
	BIT	1,M	; FIRST ATTEMPT?
	JRNZ	A2D9E	; IF NOT, CONTINUE
	SET	1,M	; ELSE SET CMDRDY-ERROR BIT
	CALL	A2C84	; TRY TO ENABLE INTERFACE
	CALL	A26A6	; RE-INITIALIZE SESCO
	POP	PSW	; RESTORE STATUS
	JMP	A2DCB	; RESTART DISK-ACCESS
;
A2D9E:	SET	0,M	; SET FATAL-ERROR BIT
	LXI	H,CEBYTI	; GET ADDRESS OF CONTROLLER ERROR BYTE
	SET	0,M	; SET CONTROLLER-ERROR BIT
	LDA	LMPFLD	; GET STATUS OF OPERATOR PANEL
	CPI	0FFH	; ALL LED'S OFF?
	JRNZ	A2DB3	; IF NOT, CONTINUE
	MVI	A,01CH	; SESCO DEFECT
	OUT	088H	; OUTPUT INFORMATION TO OPERATOR PANEL
	STA	LMPFLD	; UPDATE OPERATOR PANEL STATUS
A2DB3:	POP	PSW	; RESTORE STATUS
	RET		; DONE
;
FATAL:	LSPD	RETSP
	XRA	A
	STA	Y31AF
	CALL	XXLEDR
	MOV	A,PDRFCN(X)
	DCR	A
	DCR	A
	RZ
	DCR	A
	RZ
	MVI	A,0FFH
	RET
;
A2DCB:	XRA	A
	SET	1,A
	STA	Y31AF
	LSPD	RETSP
	MOV	A,PDRFCN(X)
	ANI	0F0H
	CPI	0F0H
	JZ	XXFXD
	JMP	XXDD
;
A2DE2:	DI		; DISABLE INTERRUPT
	PUSH	PSW	; SAVE STATUS
	LDA	Y31AF	; GET ACTION FLAGS
	BIT	3,A	; ...-BIT SET?
	JNZ	A2DCB	; IF SO, RESTART DISK OPERATION
	POP	PSW	; ELSE RESTORE STATUS
A2DED:	RET		; DONE
	.END
