;	FIFWARE.ASM

;	26 OCT 76.	BRH. ADDED BOOTSTRAP LOADER.	
;	21 OCT 76.	BRH. MERGED PROGRAM INTO ONE FILE
;
; ******** FLOPPY INTERFACE FIRMWARE ********
;
; IFM RAM ADDRESSES
;		
PBAS	EQU	800H		;RAM STORAGE FOR COMMAND POINTERS
PTRK	EQU	PBAS+32		;PHYSICAL TRACK NUMBER
LTRK	EQU	PTRK+1		;LOGICAL TRACK NUMBER
SECT	EQU	LTRK+1		;SECTOR NUMBER
BUFA	EQU	SECT+1		;ADDRESS OF BUFFER IN MAIN MEMORY
FUNC	EQU	BUFA+2		;PRESENT FUNCTION IN 4 MSB
INTE	EQU	FUNC+1		;INTERRUPT FLAG (LATCH CONTENTS)
INTF	EQU	INTE+1		;INTERRUPTS: 1 FOR TESTING DRIVE,
				;  0 IF INTERRUPT IS FATAL ERROR .
RTRC	EQU	INTF+1		;RETRY COUNTER FOR ERROR PROCESSING
STPT	EQU	RTRC+1		;HOLDS STATUS BYTE ADDRESS
HDFL	EQU	STPT+2		;O IF HEAD UP, 1 IF DOWN,
				;  2 IF WAITING TO BE RAISED
DRV0	EQU	HDFL+1		;DRIVE TRACK LOCATION IN 7 LSB.
DRV1	EQU	DRV0+1		;  MSB IS 1 IF DRIVE IS SOFTWARE
DRV2	EQU	DRV1+1		;  WRITE PROTECTED.  7 LSB = 7F
DRV3	EQU	DRV2+1		;  IF DRIVE MUST BE RESTORED.
TDRV	EQU	DRV3+1		;DRIVE SELECT BIT FOR NEXT DRIVE
SDRV	EQU	TDRV+1		;DRIVE SELECT BIT FOR THIS DRIVE
DATB	EQU	SDRV+133	;TOP OF 133 BYTE DATA BUFFER
STAK	EQU	900H		;TOP OF STACK
RAM	EQU	900H		;START OF DEBUG RAM
;
; POWER UP ROUTINE
;
	ORG	0
	
	LXI	SP,STAK		;SET STACK POINTER
	SUB	A		;SET PARAMS FOR DRDY...
	STA	DRV0	
	STA	SDRV	
	MVI	B,1		;FORM DRIVE 0 ADDRESS...
	CALL	DRAD	
	CALL	DRDY		;CHECK TO SEE IF DRIVE 0 IS READY
	JNZ	SCLPH		;SKIP BOOTSTRAP IF NOT READY
	SUB	A		;RESET SYSTEM MEMORY BIT...
	STA	4006H	
	MOV	H,A		;ZERO HL ...
	MOV	L,A	
	MVI	A,0C3H		;GET JUMP OPCODE
	STA	8000H		;STORE AT 0 IN SYSTEM MEMORY
	SHLD	8001H		;STORE ADDRESS TO JUMP TO
	LXI	H,8080H		;START OF BOOT CODE IN SYSTEM
	LXI	D,SYSCM		;POINTER TO BOOT CODE IN PROM
	MVI	C,SYSLN		;LENGTH OF BOOT CODE
	CALL	DMOV		;TRANSFER CODE TO SYSTEM MEMORY
	MVI	A, SYSTR	;POP IN LO BYTE OF JUMP ADDRESS
	STA	8001H		;  SO SMPU JUMPS TO BOOT CODE
	JMP	SCLPH		;CONTINUE AT SCAN LOOP HEADER

	ORG	38H

INTR:	LDA	INTF
	ORA	A
	RNZ	
	MVI	C,91H
	JMP	AERX
;
; SYSTEM BOOT CODE
;
SYSCM:	DB	21H		;READ SECTOR COMMAND
STATS:	DB	00H		;STATUS BYTE
	DB	00H		;HI BYTE OF TRACK #
	DB	00H		;LO BYTE OF TRACK #
	DB	01H		;SECTOR #
	DW	0000H		;ADDRESS OF BUFFER
;
START:	SUB	A		;MAKE ZERO
	STA	SYSTA		;RESET STATUS BYTE
	OUT	0FDH		;EXECUTE POINTER ZERO
STAR0:	LDA	SYSTA		;GET STATUS BYTE
	ORA	A		;IS IT 0?
	JZ	SYST0		;LOOP AS LONG AS IT IS
	CPI	1		;STATUS OKAY?
	JZ	0		;JUMP INTO BOOTSTRAP IF SO
	CMA			;PUT ERROR CODE IN LIGHTS...
	OUT	0FFH
	JMP	SYSTR		;TRY TO BOOT AGAIN
;
SYSLN	EQU	$-SYSCM
SYSTA	EQU	STATS-SYSCM+80H
SYSTR	EQU	START-SYSCM+80H
SYST0	EQU	STAR0-SYSCM+80H
;
; DEFAULT POINTERS
;
DEFP:	DW	00080H
	DW	01000H
	DW	02000H
	DW	03000H
	DW	04000H
	DW	05000H
	DW	06000H
	DW	07000H
	DW	08000H
	DW	09000H
	DW	0A000H
	DW	0B000H
	DW	0C000H
	DW	0D000H
	DW	0E000H
	DW	0F000H
;
; SCAN LOOP HEADER
;
SCLPH:	LXI	H,PBAS		;SET DEFAULT POINTERS...
	LXI	D,DEFP
	MVI	C,32
	CALL	DMOV
	SUB	A		;INITIALIZE VARIABLES...
	STA	HDFL
	STA	INTE
	STA	SDRV
	MVI	A,7FH
	LXI	H,DRV0
	MOV	M,A
	INX	H
	MOV	M,A
	INX	H
	MOV	M,A
	INX	H
	MOV	M,A
;
; MAIN SCAN LOOP
;
SCLP:	LDA	HDFL		;GET HEAD FLAG
	ORA	A
	JZ	SCL1		;JUMP IF HEAD NOT DOWN
SCL2:	LDA	1800H		;DOWN, CHECK COMMAND
	RAR
	JC	ACTN
	LDA	4004H		;NO, CHECK FOR INDEX
	ANI	2
	JZ	SCL2
	LDA	INTE		;YES, CLEAR IT AND
	ORI	80H		;MAINTAIN INTERRUPT FLAG
	STA	4006H
	LDA	HDFL		;SEE IF TIME TO RAISE
	INR	A
	STA	HDFL
	CPI	3
	JNZ	SCL2
	SUB	A		;YES
	STA	4005H
	STA	HDFL
SCL1:	MVI	B,0FH		;SET TO TEST ALL DRIVES
	LDA	1800H
	RAR
	JC	ACTN
	CALL	DRAD		;GET DRIVE ADDRESS
	JZ	SCL1		;JMP IF ALL DONE
	CALL	DRDY		;TEST THIS DRIVE
	JMP	SCL1+2
;
; ACTION JUMP MODULE - PERFORMS COMMON OPERATIONS
; VERIFIES COMMAND STRING, THEN JUMPS TO PROPER ROUTINE
;
ACTN:	SUB	A		;CLEAR INTERUPT FLAG
	STA	4006H
	STA	INTE
	LDA	1400H		;GET COMMAND WORD
	MOV	B,A
	ANI	0F0H		;GET TYPE
	JZ	ACT1		;OF COMMAND STRING
	ADI	0F0H
	JZ	ACT2		;POINTER SET
	ADI	0F0H
	JZ	ACT3		;RESTORE DRIVE
	ADI	0F0H
	JZ	ACT4		;SOFTWARE WRITE PROTECT
	ADI	0F0H	
	JZ	ACT5		;SOFTWARE WRITE ENABLE
	JMP	SCLP		;NOP FUNCTION
ACT2:   CALL	PADD		;POINTER ADDRESS
	CALL	RBYT		;LSB OF POINTER ADDRESS
	INX	H	
	CALL	RBYT		;MSB
	JMP	SCLP	
RBYT:   LDA	1800H		;WAIT
	RAR		
	JNC	RBYT	
	LDA	1400H		;DATA
	MOV	M,A		;SAVE
	RET		
PADD:   LXI	H,PBAS		;BASE ADDRESS
	MOV	A,B	
	ANI	0FH	
	RLC		
	MOV	C,A	
	MVI	B,0	
	DAD	B
	RET		
ACT3:	MVI	C,7FH		;RESTORE FLAG
	CALL	DRAD		;GET DRIVE ADDRESS
	JZ	SCLP	
	MOV	A,M	
	ORA	C		;SET NEW STATUS
	MOV	M,A	
	JMP	ACT3+2
ACT4:   MVI	C,80H		;PROTECT INDICATOR
	JMP	ACT3+2	
ACT5:   CALL	DRAD	
	JZ	SCLP	
	MOV	A,M	
	ANI	7FH		;CLEAR INDICATOR
	MOV	M,A	
	JMP	ACT5	
ACT1:   CALL	PADD	
	MOV	C,M		;CONVERT TO TRUE ADDRESS
	INX	H	
	MOV	H,M	
	MOV	L,C		;SECOND BYTE
	INX	H		;SAVE STATUS BYTE ADDRESS...
	SHLD	STPT	
	DCX	H	
	CALL	FADD		;TAKE CARE OF MSB
	MVI	C,0C1H		;SET FOR COMMAND STRING ERROR
	MOV	B,M		;COMMAND
	INX	H	
	MVI	A,0	
	ADD	M	
	JNZ	AERX		;STATUS BYTE NOT ZERO
	INX	H		;TRACK MSB MUST BE ZERO
	ADD	M	
	JNZ	AERX-4	
	INX	H	
	XCHG		
	CALL	DRAD
	JZ	AERX-1		;NO DRIVE SELECTED
	CALL	DRAD
	JNZ	AERX-2		;MORE THAN ONE
	LDAX	D		;TRACK NUMBER
	INX	D
	CPI	77
	JNC	AERX-4
	STA	PTRK		;SAVE
	STA	LTRK
	MOV     A,B		;COMMAND
	ANI	0F0H
	JZ	RDAL		;READ ALL
	CPI	0A1H
	JNC	AERX-3		;ILLEGAL TOO LARGE
	CPI	60H
	JC	$+8
	ADI	0A0H
	JZ	AERX-3
	STA	FUNC		;SAVE COMMAND
	CPI	30H
	JZ	ACT6		;JMP IF SECTOR NOT REQUIRED
	LDAX	D		;GET IT
	INX	D
	ORA	A
	JZ	AERX-5
	CPI	27
	JNC	AERX-5
	STA	SECT		;SAVE GOOD SECTOR VALUE
	LDA	FUNC		;SEE IF NEED BUFFER LOC
	CPI	21H
	JNC	ACT6
ACT7:   LDAX	D		;YES, GET IT
	STA	BUFA
	INX	D
	LDAX	D
	INX	D
	STA	BUFA+1
ACT6:   MOV	A,B		;ALL PROCESSED, SEE IF IBM SPECIAL
	CPI	6FH
	JC	ACTQ
	LDAX	D		;YES, GET LOGICAL TRACK
	ORA	A
	JNZ	AERX-7
	INX	D
	LDAX	D
	CPI	77
	JNC	AERX-7
	STA	LTRK		;SAVE IT
ACTQ:   MVI	C, 0A1H		;SET DRIVE TEST ERROR
	CALL	DRDY		;SEE IF DRIVE READY
	JNZ	AERX
	MOV	A,B		;OKAY, SEE IF WRITE
	ANI	10H
	JZ	ACT8
	LDA	4004H		;YES, CHECK HARDWARE PROTECT
	RAR	
	JNC	AERX-1
	MOV	A,M	
	RAL			;TEST SOFTWARE PROTECT		
	JC	AERX-2		;YES	
ACT8:   SUB	A		;SET PROCESSING FLAGS
	STA	RTRC		;CLEAR RETRY COUNTER
	STA	INTF		;SET INTERRUPT FLAG	
ACTD:	MOV	A,M		;NOW POSITION DRIVE	
	ANI	7FH		;GET PRESENT TRACK	
	MOV	D,A		;SAVE STATUS OF PROTECT	
	MOV	A,M	
	ANI	80H	
	MOV	M,A		;SEEK NEW TRACK	
	LDA	PTRK	
	ADD	M	
	MOV	M,A	
	LDA	PTRK	
	SUB	D		;GET DIFFERENCE	
	MVI	E,0		;SET FOR STEP IN	
	MOV	D,A	
	JZ	TSTH		;ALREADY ON TRACK
	JP	ACT9-4	
	MVI	E,8		;STEP OUT
	SUB	A	
	SUB	D	
	MOV	D,A	
	LDA	SDRV		;RAISE HEAD...	
	STA	4005H	
	NOP			;DELAY...	
	NOP		
ACT9:   DCR	D		;TEST FOR TIME TO LOAD HEAD	
	CZ	LDHD	
	MOV	A,E		;LOAD STEP REGISTER	
	STA	4006H	
	ADI	4		;NOW SET STEP BIT	
	STA	4006H	
	ANI	8		;CLEAR STEP BIT	
	ADI	0	
	STA	4006H	
ACTP:	EI			;INTERRUPT IF DRIVE GOES NOT READY		
	CALL	TMLD		;WAIT 6 MILLISECONDS	
	CALL	TMLD	
	CALL	TMLD	
	DCR	D		;SEE IF MORE REQUIRED	
	JP	ACT9+1	
	MVI	D,5		;WAIT 10 MILLISECONDS FOR HEAD	
	CALL	TMLD	
	DCR	D	
	JNZ	$-4
;	
; HEAD IS NOW LOADED, WE'RE ON RIGHT TRACK
; AND WE'RE READY TO TAKE ACTION			
;  RECALL THAT POINTER TO STATUS LOCATION IS SAVED	
;  IN STPT, FUNCTION IS IN 4 MSB OF FUNC
;
ACTB:	DI			;DISABLE INTERRUPT UNTIL REQUIRED		
	LDA	FUNC	
	LXI	H,JMPT		;BASE OF TABLE
	RRC		
	RRC		
	RRC
	RRC	
	ANI	7
ACTA:	JNZ	$+4	
	PCHL			;JUMP TO ROUTINE
	INX	H	
	INX	H	
	INX	H	
	DCR	A	
	JMP	ACTA
;	
; FOLLOWING IS JUMP TABLE FOR ACTIONS 0 TO 5		
; NOTE THAT 7 TO 11 ARE SAME AS 0 TO 5 WITH DIFF LTRK
;		
JMPT:	JMP	RALL	
	JMP	WRIT	
	JMP	READ	
	JMP	FRMT	
	JMP	READ		;JUST IGNORE TRANSFER AT END
	JMP	WDSC	
; ERROR RETURN ROUTINE BASE ERROR IS IN C
	INR	C	
	INR	C	
	INR	C	
	INR	C	
	INR	C	
	INR	C	
	INR	C	
AERX:   LHLD	STPT		;GET STATUS BYTE ADDRESS
	CALL	FADD
	MOV	M,C
	DI			;INTERRUPTS OFF
	SUB	A		;CLEAR CONTROL REGISTERS
	STA	4005H	
	STA	HDFL	
	MVI	A,10H	
	STA	4006H		;SET INTERRUPT FLAG
	STA	INTE	
	LXI	SP,STAK		;RESET STACK POINTER
	JMP	SCLP	
RDAL:	STA	FUNC		;SET FUNCTION
	LDAX	D		;GET DEAAY
	INX	D	
	STA	SECT		;SAVE IT
	JMP	ACT7		;GO GET BUFFER LOG
TSTH:	LDA	HDFL		;SEE IF HEAD LOAD REQUIRED
	ORA	A	
	MVI	A,1		;ALREADY LOADED
	STA	HDFL		;RESET FLAG
	JNZ	ACTB		;GO PROCESS FUNCTION
	CALL	LDHD	
	JMP	ACTP
;	
; FORM DRIVE ADDRESS FOR DRIVE SELECTED IN 4 LSB OF B.		
;   CLEAR BIT OF DRIVE SELECTED. RETURN NON-ZERO IF
;   THERE WAS A DRIVE AND ZERO IF NONE WAS SELECTED.
;
DRAD:	MVI 	A,0FH		;SEE IF ANY
	ANA	B	
	RZ	
	MVI	A,1		;0?
	LXI	H,DRV0	
	ANA	B
	JNZ	DRAl
	MVI	A,2		;1?
	INX	H
	ANA	3
	JNZ	DRAl
	MVI	A,4		;2?
	INX	H
	ANA	B
	JNZ	DRAl
	MVI	A,8		;MUST BE 3
	INX	H
DRAl:   STA	TDRV		;SAVE SELECT BIT
	CMA			;CLEAR THIS BIT	
	ANA	B
	MOV	B,A
	INR	A		;SET FLAG
	RET
;	
; TEST DRIVE READY. RETURN NON-ZERO FLAG IF NOT READY.
; IF READY, PERFORM RESTORE IF FLAG SET (DRIVE TRACK = 7F).
;
DRDY:   MVI	A,1		;SEE IF SELECTED
	STA	INTF		;DRIVE IS READY
	LDA	TDRV		;SELECT DRIVE AND
	MOV	D,A		;SEE IF SAME AS LAST
	LDA	SDRV
	SUB	D
	JNZ	DRD6
	LDA	HDFL		;SAME SEE IF HEAD DOWN
	ORA	A
	JNZ	DRD5		;JUMP IF DOWN
DRD6:   SUB	A		;CLEAR HEAD FLAG
	STA	HDFL
	LDA	TDRV
	STA	4005H
DRD5:   EI	
	SUB	A		;IF DRIVE NOT READY, INTERRUPT
	DI			;  OCCURS AND RETURNS A 1 IN A	
	ORA	A
	JNZ	DRD1
	LDA	TDRV		;OKAY, SAVE DRIVE BIT
	STA	SDRV
	MOV	A,M		;CHECK FOR RESTORE FLAG
	ANI	7FH
	CPI	7FH
	JNZ	DRD2
	LDA	4004H		;YES, SEE IF OVER TRK 0
	ANI	4
	CNZ	STIN		;IF SO, STEP IN
	LDA	4004H		;STILL THERE?
	ANI	4
	RNZ			;RETURN DRIVE NO GOOD	
	MVI	D,77		;SET COUNT
DRD3:   CALL	STOU		;STEP OUT
	LDA	4004H		;THERE?
	ANI	4
	JNZ	DRD4
	DCR	D		;NO, MAX TRIES?
	JNZ	DRD3
	INR	D		;SET NON-ZERO FLAG
	RET
DRD4:   MVI  	A,80H		;THERE, SET TRACK 0
	ANA  	M
	MOV  	M,A
DRD2:   SUB  	A		;SET ZERO FLAG
	RET
DRD1:   SUB  	A		;NOT READY, CLEAR HEAD FLAG
	STA  	HDFL
	MVI  	A,80H		;SET RESTORE FLAG
	ANA  	M
	ADI  	7FH
	MOV  	M,A
	RET
;
; STEP HEAD IN
;
STIN:  SUB 	A
	JMP  	STOU+2
;
; STEP HEAD OUT
;
STOU:   MVI  	A,8
	STA  	4006H
	ADI  	4		;ADD STEP BIT
	STA	4006H
	ANI  	8
	ADI  	0
	STA  	4006H
	MVI  	D,6		;WAIT 12 MILLISECONDS
STO1:   CALL 	TMLD
	DCR  	D
	JNZ  	STO1
	RET
;
; LOAD HEAD ROUTINE. SET > 43 BIT IF REQUIRED
;
LDHD:   MOV  	A,M		;GET TRACK
	ANI  	7FH
	CPI  	44
	CMC
	MVI  	A,80H
	RAR
	RRC
	RRC
	MOV  	C,A
	LDA  	SDRV		;GET SELECT BIT
	ADD  	C
	STA  	4005H
	MVI  	A,1		;SET HEAD DOWN FLAG
	STA  	HDFL
	RET
TMLD:	CALL 	MLDL		;TWO MILLISECONDS IS
	CALL 	MLDL		;ONE PLUS ONE
	RET
MLDL:	MVI 	A,131
	DCR  	A
	JNZ  	$-1
	RET
;
; MOVE C BYTES FROM D TO H
;
DMOV:   LDAX 	D
	MOV  	M,A
	INX 	D
	INX  	H
	DCR  	C
	JNZ	DMOV
	RET	
FADD:	MOV	A,H		;SET MEMORY BIT FOR TRANSFER
	ANI	80H
	RRC	
	RRC	
	STA	4006H
	MOV	A,H		;SET BIT 15 FOR INTERNAL
	ORI	80H
	MOV	H,A
	RET	
;		
CRCU	EQU	48H
CRCL	EQU	29H
;
; COMPUTE CRC FROM BUFFER POINTED TO BY PAIR D
; BUFFER LENGTH IS IN C
;  
CRCC:	LXI	H, 0FFFFH	;PRESET CRC VALUE
	LDAX	D		;GET A BYTE
	CALL	CRC1		;DO ONE BYTE
	INX	D
	DCR	C
	JNZ	CRCC+3
	RET	
CRC1:	PUSH	B		;COMPUTE FOR ONE BYTE
	PUSH	D
	XRA	H
	MOV	B,A
	RLC	
	RLC	
	RLC	
	RLC	
	XRA	B
	MOV	C,A
	ANI	0F0H
	MOV	D,A
	ADD	C
	MOV	E,A
	MOV	A,D
	ACI	0
	XRA	L
	MOV	H,A
	MOV	A,B
	ANI	0F0H
	MOV	B,A
	XRA	E
	MOV	L,A
	MOV	A,B
	RRC	
	RRC	
	RRC	
	XRA	H
	MOV	H,A
	POP	D
	POP	B
	RET
;	
; READ ALL LOOP... INTERLEAVE CLOCK AND DATA (64 BYTES WORTH)
;
RALL:	MVI	C,64		;BYTE COUNTER
	MVI	A,80H		;INHIBIT INDEX INTERRUPT
	STA	4006H
	LXI	SP,DATB+1	;SET DATA AREA
	EI	
RAL1:   LDA	4004H		;WAIT FOR INDEX
	ANI	2
	JZ	RAL1
	LDA	SECT
	CPI	0
	JZ	RAL2
	MOV	D,A
	CALL	MLDL
	DCR	D
	JNZ	$-4
RAL2:   MVI	A,1		;SYNC PLO
	STA	4006H
	SUB	A
	ADI	0		;DELAY 12 MICROSECONDS
	ADI	0
	STA	4006H
RAL4:   LHLD	4002H		;GET 64 BYTES WORTH
	PUSH	H
	DCR	C
	JNZ	RAL4
RAL7:   LHLD	BUFA		;MOVE TO MAIN MEMORY
	CALL	FADD
	LXI	D,DATB
	MVI	C,128
RAL5:   LDAX	D
	DCX	D
	MOV	M,A
	INX	H
	DCR	C
	JNZ	RAL5
RAL6:   LHLD	STPT		;SUCCESSFUL RETURN
	CALL	FADD
	DI	
	INR	M
	MVI	A,10H		;SET INTERRUPT FLAG
	STA	4006H
	STA	INTE		;AND SAVE THE SET VALUE
	LXI	SP,STAK		;RESET STACK POINTER
	JMP	SCLP		;WAIT FOR MORE
;
; ROUTINE TO SYNC ON START OF SECTOR
; EXITS AFTER TEN BYTES OF ZEROES FOLLOWING HEADER
;
SYNC:   CALL	HDRC		;COMPUTE CRC FOR HEADER
	PUSH	H		;SAVE FOR LATER
SYN2:   SUB	A		;CLEAR INDEX COUNTER
	STA	INTE
	LXI	D,4002H		;REGISTER ADDRESS
	LDA	LTRK		;SET FOR FAST CHECKING
	MOV	C,A
	LDA	SECT
	MOV	B,A
	LXI	SP,STAK-4	;WHERE CRC IS STORED
	LDA	4004H		;TEST FOR INDEX
	ANI	2
	JZ	SYN1
	MVI	A,80H		;CLEAR IT
	STA	4006H
	LDA	INTE		;YES, SEE IF SECOND
	INR	A
	STA	INTE
	CPI	3
	JNZ	SYN1
	MVI	C,93H		;SECOND SET ERROR
SYN4:	CALL	RTRY		;SEE IF RETRY COUNT EXPIRED
	JMP	SYN2		;RETURN SAYS TRY AGAIN
SYN1:	MVI	A,1		;SYNC PLO
	STA	4006H
	SUB	A
	XTHL	
	XTHL	
	ADI	0
	STA	4006H
	EI	
	MVI	A,0C7H		;WAIT FOR CHARACTER
	LHLD	4000H
	CMP	H
	JNZ	SYN2+4		;CLOCK PATTERN CHECK
	INR	L		;DATA SHOULD BE FC
	LDAX	D		;GET TRACK
	SUB	C
	JNZ	SYN3		;NOT SAME - WRONG TRACK?
	INR	L		;COMPLETE DATA BYTE CHECK
	XCHG	
	MOV	C,M		;GET ZERO BYTE
	JNZ	SYN2+4		;JMP IF DATA BYTE NOT CORRECT
	POP	D		;GET CRC BYTES
	MOV	A,M		;GET SECTOR
	SUB	B		;CORRECT?
	JNZ	SYN2+4
	MOV	A,C		;YES
	ORA	M		;LAST ZERO BYTE
	MVI	C,95H
	JNZ	SYN4		;JUMP ON FORMAT ERROR
	MOV	A,M		;CRC BYTE 1
	SUB	D		;CHECK IT
	JNZ	$+5
	MOV	A,E
	SUB	M		;CHECK CRC BYTE 2
	MVI	C,94H
	JNZ	SYN4		;JUMP ON ERROR
	MOV	A,M		;OKAY, WAIT TEN BYTES
	MVI	C,9	
	MOV	A,M
	DCR	C
	JNZ	$-2
	RET			;RETURN OKAY	
SYN3:	INR	L		;SEE IF DATA BYTE CORRECT
	JNZ	SYN2+4
	DI			;YES, THERE IS TRACK ADDRESS ERROR	
	LDA	SDRV		;SET DRIVE FOR RESTORE
	MOV	B,A
	LXI	SP,STAK		;CORRECT SP
	CALL	DRAD	
	MVI	A,80H	
	ANA	M	
	ADI	7FH	
	MOV	M,A	
	MVI	C,92H		;SEE IF RETRY DONE
	CALL	RTRY	
	CALL	DRDY		;OKAY, POSITION DRIVE AGAIN
	JZ	ACTD		;OVER 0 THEN GO AGAIN
	MVI	C,91H		;DRIVE INOPERABLE
	JMP	AERX
;	
; ROUTINE TO WRITE A DATA BLOCK
;
WRIT:	LHLD	BUFA		;FIRST GET DATA
	CALL	FADD	
	LXI	D,DATB-132	
	PUSH	D	
	XCHG		
	MVI	M, 0FBH		;DATA HEADER FOR CRC
	INX	H	
	MVI	C,128	
	CALL	DMOV	
	POP	D		;GET DATA ADDRESS AGAIN
	MVI	C,129	
	CALL	CRCC	
	MOV	A,H		;SAVE IT
	STAX	D	
	INX	D	
	MOV	A,L
	STAX	D
	INX	D	
	SUB	A		;TRAILING ZERO
	STAX	D	
	CALL	SYNC		;FIND PROPER SECTOR
	LXI	H,4007H		;SET WRITE ADDRESS
	LXI	B, 542H		;SET COUNTERS
	LXI	SP,DATB-131	
	POP	D		;GET FIRST DATA BYTES
	MVI	A,2		;SET WRITE ENABLE
	STA	4006H	
	SUB	A		;WRITE ZERO BYTES
	DCR	B	
	MOV	M,A	
	JNZ	$-2	
	MVI	A,0FBH		;WRITE DATA INDEX MARK
	STA	401FH	
	JMP	$+5		;START DATA LOOP
WRT2:   MOV	M,D	
	POP	D		;GET NEXT TWO BYTES OF DATA
	DCR	C		;SEE IF DONE
	MOV	M,E		;WRITE DATA BYTE
	JNZ	WRT2	
	MOV	M,E		;WAIT FOR ZERO BYTE
	SUB	A		;CLEAR WRITE ENABLE
	STA	4006H
	JMP	RAL6		;SUCCESSFUL RETURN
;
; ROUTINE TO WRITE DELETED DATA ADDRESS MARK
;	
WDSC:	CALL	SYNC		;FIND SECTOR
	LXI	H,4007H		;DATA WRITE REGISTER
	LXI	B,501H		;SET COUNTERS	
	INR	A		;EQUALIZE TIME WITH WRITE	
	INR	A		
	INR	A		
	INR	A		
	MVI	A, 2		;SET WRITE ENABLE	
	STA	4006H		
	SUB	A		
	DCR	B		;WRITE ZERO BYTES	
	MOV	M,A		
	JNZ	$-2		
	MVI	A,0F8H		;WRITE DELETED DATA HEADER	
	STA	401FH		
	SUB	A		;TRAILING HEADER	
	MOV	M,A		
	STA	4006H		;CLEAR WRITE ENABLE	
	JMP	RAL6		;SUCCESSFUL RETURN	
HDRC:   LXI	H,0FFFFH	;COMPUTE HEADER CRC	
	MVI	A,0FEH		;ADDRESS INDEX MARK	
	CALL	CRC1		
	LDA	LTRK		;TRACK ADDRESS	
	CALL	CRC1		
	SUB	A		;ZERO BYTE	
	CALL	CRC1	
	LDA	SECT		;SECTOR NUMBER	
	CALL	CRC1
	SUB	A		;ZERO BYTE	
	CALL	CRC1		;IT IS ALL COMPUTED IN H,L NOW
	RET
;			
; ROUTINE TO READ A SECTOR OF DATA
;		
READ:	CALL	SYNC		;FIND SECTOR	
	LXI	D,4002H		;DATA READ ADDRESS	
	LXI	B,641H		;SET COUNTERS	
	LXI	SP,DATB+1	;SET DATA BUFFER READ POINTER	
	DCR	B		;DELAY PAST HEAD TURN ON AREA	
	JNZ	$-1		
	MVI	A, 1		;SYNC PLO	
	STA	4006H		
	SUB	A		
	XTHL			
	XTHL			
	XTHL			
	XTHL			
	STA	4006H		
	MVI	A,0C7H		;SET UP FOR TESTING DATA	
	MVI	B,0FBH		;ADDRESS MARK	
	LHLD	4000H		;READ IT FROM DISK	
	SUB	H		;CHECK CLOCK PATTERN	
	JNZ	RED1		
	XCHG			
	MOV	D,M		;GET FIRST DATA BYTE	
	MOV	A,E		;TEST DATA FROM INDEX MARK	
	SUB	B		
	JNZ	RED4		;JMP TO SEE IF DELETED DATA	
RED2:   MOV	E,M		;ALL OKAY, GET ANOTHER DATA BYTE
	PUSH	D		;STORE TWO OF THEM	
	DCR	C		
	MOV	D,M		;GET NEXT BYTE
	JNZ  	RED2		;LOOP UNTIL DONE
	MOV  	E,M		;THIS IS SECOND OF CRC BYTES
	PUSH 	D		;SAVE THEM
	DI			;ALL DONE
	LXI  	SP,STAK	
	LXI  	H,0FFFFH	;NOW CHECK CRC		
	LXI 	D,DATB	
	MVI  	C,130	
	MVI 	A,0FBH		;FIRST DO HEADER DATA
	CALL 	CRC1	
RED3:	LDAX 	D		;GET DATA BYTE
	CALL 	CRC1	
	DCX  	D	
	DCR  	C		;SEE IF DONE
	JNZ  	RED3	
	MOV  	A,H		;SEE IF CRC CORRECT
	ORA 	L	
	JNZ  	RED1
	LDA  	FUNC		;QKAY, SEE IF CHECK READ
	ANI  	0F0H	
	CPI  	20H	
	JZ   	RAL7		;GO MORE DATA IFF READ
	JMP  	RAL6		;SUCCESSFUL RETURN IF CHECK READ
RED4:	ADI  	3			;TEST FOR DELETED DATA
	JNZ  	RED1	
	MVI  	C,97H		;YES, SET ERROR
	JMP  	AERX		;  AND RETURN
RED1:	MVI  	C,96H		;CRC ERROR
	DI	
	CALL 	RTRY		;SEE IF TRY AGAIN
	JMP  	READ		;YES
;
; TEST RETRY COUNTER. RETURN IF TIME TO TRY AGAIN
;
RTRY:	LDA  	RTRC		;INCREMENT RETRY COUNTER
	INR  	A	
	STA  	RTRC	
	CPI  	11		;SEE IF ALL DONE
	RNZ	
	JMP  	AERX		;TRIED MAX TIMES, SO QUIT
;
; ROUTINE TO FORMAT A TRACK OF A DISKETTE
;
FRMT:	MVI  	A,26		;COMPUTE AND SAVE HEADER
	STA  	SECT		;CRC VALUES FOR ALL 26 SECTORS
	LXI  	D,DATB	
FRM1:	CALL 	HDRC	
	MOV  	A,L	
	STAX 	D	
	DCX  	D	
	MOV  	A,H	
	STAX 	D	
	DCX  	D		;CRC SAVED
	LDA  	SECT		;SET NEXT SECTOR
	DCR  	A	
	STA  	SECT	
	JNZ  	FRM1		;LOOP UNTIL 26 DONE
	INX  	D		;SET D TO CRC OF FIRST SECTOR
	LXI  	H,4007H		;WRITE REGISTER
	LXI  	B,12CH		;SET COUNTERS
	MVI  	A,80H	
	STA  	4006H		;WAIT FOR INDEX
	EI	
	LDA	4004H
	ANI	2
	JZ	$-5
	MVI	A,82H		;SET WRITE ENABLE
	STA	4006H
	SUB	A		;SET ZERO BYTES
	MOV	M,A
	DCR	C		;WRITE GAP 4
	JNZ	$-2
	MOV	M,A
	MVI	A, 0FCH		;WRITE INDEX ADDRESS MARK
	STA	4017H
FRM2:	SUB	A		;DO A SECTOR'S WORTH
	MVI	C,30		;FOR GAP 1
	MOV	M,A	
	DCR	C
	JNZ	$-2
	MOV	M,A		;LAST BYTE
	MVI	A,0FEH		;ID ADDRESS MARK
	STA	401FH
	LDA	LTRK		;TRACK ADDRESS
	MOV	M,A
	SUB	A		;ZERO BYTE
	MOV	M,A
	MVI	C,16		;SET COUNT FOR GAP 2
	MOV	M,B		;SECTOR NUMBER
	MOV	M,A		;ZERO BYTE
	LDAX	D		;CRC BYTE 1
	INX	D
	MOV	M,A
	LDAX	D		;CRC BYTE 2
	INX	D
	MOV	M,A
	SUB	A		;ZERO BYTES FOR GAP 2
	DCR	C
	JNZ	$-3
	MOV	M,A		;LAST BYTE
	MVI	A, 0FBH		;DATA ADDRESS MARK
	STA	401FH
	SUB	A		;DATA BYTES FOR SECTOR ARE ALL ZERO
	MVI	C,127		;NUMBER BYTES LESS ONE
	MOV	M,A		;WRITE ONE
	DCR	C
	JNZ	$-2
	MOV	M,A		;LAST BYTE
	MVI	A,CRCU
	MOV	M,A
	MVI	A,CRCL
	MOV	M,A
	INR	B		;ADVANCE SECTOR NUMBER
	MVI	A,27
	SUB	B
	MOV	M,C		;WRITE ZERO BYTE
	JNZ	FRM2		;LOOP TILL DONE
FRM4:	LDA	4004H		;WRITE ZEROES TO INDEX
	MOV	M,C
	ANI	2
	JNZ	FRM3
	MOV	M,C
	JMP	FRM4
FRM3:	SUB	A		;CLEAR WRITE ENABLE
	STA	4006H
	JMP	RAL6

	END
