	TITLE	"BIOS.DIO   HT68K BIOS: DISK I/O"
	PAGE
*************************** DISK I/O ********************************
DSKREAD1
	MOVEQ	#1,D0		;UNIT 1 READ
	LEA	DRV1PNTR,A1
	BRA.S	DISKR
DSKREAD2
	MOVEQ	#2,D0		;UNIT 2 READ
	LEA	DRV2PNTR,A1
	BRA.S	DISKR
DSKREAD3
	MOVEQ	#1,D0		;UNIT 3 READ
	LEA	DRV1PNTR,A1
	BRA.S	DISKR
DSKREAD4
	MOVEQ	#2,D0		;UNIT 4 READ
	LEA	DRV3PNTR,A1
	BRA.S	DISKR
DSKWRITE1
	MOVEQ	#1,D0		;UNIT 1 WRITE
	LEA	DRV1PNTR,A1
	BRA.S	DISKW

DSKWRITE2
	MOVEQ	#2,D0		;UNIT 2 WRITE
	LEA	DRV2PNTR,A1
	BRA.S	DISKW
DSKWRITE3
	MOVEQ	#1,D0		;UNIT 3 WRITE
	LEA	DRV1PNTR,A1
	BRA.S	DISKW
DSKWRITE4
	MOVEQ	#2,D0		;UNIT 4 WRITE
	LEA	DRV3PNTR,A1
	BRA.S	DISKW
	NOP
;--------------------------- COMMON DISK READ
DISKR
	LEA	VARS,A2
	MOVE.L	D0,DRIVE(A2)		;DRIVE NUMBER
	MOVE.L	(A4)+,BUFPN(A2)		;POINTER TO READ BUFFER
	MOVE.L	(A4)+,RECORD(A2)	;LOGICAL RECORD NUMBER
	CLR.B	RECORD(A2)		;CLEAR HIGH BYTE
	BSR	TRANSFORM		;LOGICAL TO PHYSICAL
	TST.B	DSKERR(A2)
	BNE.S	RDERR
	BSR	SEEK			;SEEK TRACK
	TST.B	DSKERR(A2)
	BNE.S	RDERR
	BSR	READSEC			;READ SECTOR
	TST.B	DSKERR(A2)
	BNE.S	RDERR
	MOVE.L	#00008000H,-(A4)	;READ SUCCEEDED
	RTS
RDERR	MOVE.L	#00008010H,-(A4)	;READ FAILED
	RTS
;--------------------------- COMMON DISK WRITE
DISKW
	LEA	VARS,A2
	MOVE.L	D0,DRIVE(A2)		;DRIVE NUMBER
	MOVE.L	(A4)+,BUFPN(A2)		;POINTER TO READ BUFFER
	MOVE.L	(A4)+,RECORD(A2)	;LOGICAL RECORD NUMBER
	CLR.B	RECORD(A2)		;GET RID OF UNIT NO.
	BSR	TRANSFORM		;LOGICAL TO PHYSICAL
	TST.B	DSKERR(A2)
	BNE.S	WRERR
	BSR	SEEK			;SEEK TRACK
	TST.B	DSKERR(A2)
	BNE.S	WRERR
	BSR	WRITSEC			;WRITE SECTOR
	TST.B	DSKERR(A2)
	BNE.S	WRERR
	MOVE.L	#00008000H,-(A4)	;WRITE SUCCEEDED
	RTS
WRERR	MOVE.L	#00008011H,-(A4)	;WRITE FAILED
	RTS
;------------------------------- DISK STATUS
DSKSTAT1
DSKSTAT2
DSKSTAT3
DSKSTAT4
	BTST.B	#4,FDMSR
	BNE.S	DSBUSY
	MOVE.L	#8000H,-(A4)	;CONTROLLER NOT BUSY
	RTS
DSBUSY	MOVE.L	#8100H,-(A4)	;DEVICE BUSY
	RTS
;------------------------------- DISK CONTROL
DSKCNTRL1
	MOVEQ	#1,D0
	BRA.S	DISKCN
DSKCNTRL2
	MOVEQ	#2,D0
	BRA.S	DISKCN
DSKCNTRL3
	MOVEQ	#1,D0
	BRA.S	DISKCN
DSKCNTRL4
	MOVEQ	#2,D0
	BRA.S	DISKCN
	NOP
DISKCN	LEA	VARS,A2
	MOVE.L	D0,DRIVE(A2)
	CLR.L	SIDE(A2)
	BSR	BUSYWAIT	;COMPLETE PREVIOUS COMMAND
	BSR	SURFACE		;SELECT DISK DRIVE
	MOVE.L	(A4)+,D0	;GET CONTROL STRING LENGTH
	MOVEA.L	(A4)+,A0	;GET CONTROL STRING POINTER
	MOVE.L	#8000H,-(A4)	;CLEAN STATUS
DCWHIL	TST.L	D0		;WHILE NOT END OF STRING
	BNE.S	DCNEXT
	RTS
DCNEXT	MOVE.B	(A0)+,D1	;  GET CONTROL_CODE
	SUBQ.L	#1,D0		;  CASE CONTROL_CODE OF
	CMPI.B	#1,D1		;  01: (SCSI REZERO CODE)
	BNE.S	DCASE4
	MOVEM.L	#0101H,-(A4)	;      SAVE STRING INFO
	BSR	RESTORE		;      RESTORE DRIVE
	MOVEM.L	(A4)+,#8080H
	TST.B	DSKERR(A2)	;      IF ERROR
	BEQ.S	DCWHIL
	ORI.B	#10H,3(A4)	;        THEN MARK READ ERROR
	BRA.S	DCWHIL
DCASE4	CMPI.B	#4,D1		;  04: (SCSI FORMAT CODE)
	BNE.S	DCASEN
	MOVEM.L	#0101H,-(A4)	;      SAVE STRING INFO
;*****	BSR	FORMAT		;      FORMAT DRIVE
	MOVEM.L	(A4)+,#8080H
	TST.B	DSKERR(A2)	;      IF ERROR
	BEQ.S	DCWHIL
	ORI.B	#11H,3(A4)	;        THEN MARK WRITE ERROR
	BRA.S	DCWHIL
DCASEN	ORI.B	#17H,3(A4)	;  OTHER: REQUEST DENIED
	BRA.S	DCWHIL		;ENDCASE ENDWHILE
;------------------------------- DISK FLUSH
DSKFLSH1
DSKFLSH2
DSKFLSH3
DSKFLSH4
	RTS
;---------------------------- READ SECTOR
READSEC
	MOVE.B	#0AH,F8255	;TURN MOTOR ON
	MOVE.B	#0FFH,MTRONFG	;FLAG MOTOR ON
	BSR	BUSYWAIT	;COMPLETE ANY PENDING
	MOVE.L	#READREPS,REPS(A2)	;TRY SEVERAL TIMES IF ERROR
READ10	
	MOVEA.L	BUFPN(A2),A0	;BUFFER TO PUT DATA INTO
	MOVEQ	#0,D1
	MOVEQ	#1,D2
	MOVE.L	SECTOR(A2),D0	;SECTOR TO READ
	MOVE.B	D0,SECTCOM
	MOVE.L	A1,-(SP)
	MOVE.L	A2,-(SP)
	MOVE.L	A3,-(SP)	;SAVE REG TO USE DIFFERENTLY
	MOVE.L	A4,-(SP)
	MOVE.W	SR,-(SP)
	ORI.W	#0700H,SR	;DISABLE INTERRUPTS
	LEA	FDMSR,A1	;FLOPPY STATUS PORT
	LEA	FDDATA,A2	;FLOPPY DATA PORT
	LEA	COMMAND,A3	;COMMAND STRING ADDRESS
	LEA	STATDATA,A4	;STATUS DATA
	MOVEQ	#8,D3		;COMMAND LENGTH
	MOVE.L	#512,D4		;NUMBER OF BYTES TO MOVE
	MOVEQ	#7,D5		;NUMBER OF STATUS READS
	MOVE.B	COMREAD,COMMAND	;COMMAND INTO STRING
READ15	MOVE.B	(A3)+,(A2)	;START READ COMMAND
	DBEQ	D3,READ15	;LOOP LENGTH OF STRING
READ20	BTST.B	#8,(A1)		;TEST FOR DATA READY
	BEQ.S	READ20		;LOOP TILL NE ZERO
	MOVE.B	(A2),(A0)+	;  ELSE READ DATA
	DBEQ	D4,READ20	;ENDWHILE    (END OF CRITICAL LOOP)
READ25	BTST.B	#8,(A1)		;STATUS DATA
	BEQ.S	READ25		;LOOP TILL STATUS READY
	MOVE.B	(A2),(A4)+
	DBEQ	D5,READ25	;LOOP TILL ALL STATUS READ
READ30	MOVE.W	(SP)+,SR	;ENABLE INTERRUPTS
	MOVEA.L	(SP)+,A4
	MOVEA.L	(SP)+,A3	;RESTORE A REGISTERS
	MOVEA.L	(SP)+,A2
	MOVEA.L	(SP)+,A1
	SUBQ.L	#1,REPS(A2)
	MOVE.B	STATDATA,D0
	ANDI.B	#0C0H,D0	;TEST BIT 6 AND 7 ONLY
	MOVE.B	D0,DSKERR(A2)	;SAVE ANY ERRORS
	BEQ.S	READ40
	TST.L	REPS(A2)	;IF ERROR AND NOT TIME TO GIVE UP
	BGT	READ10		;  THEN TRY TO READ SECTOR AGAIN
READ40	RTS
;--------------------------- WRITE SECTOR
WRITSEC
	MOVE.B	#0AH,F8255	;TURN MOTORS ON
	MOVE.B	#0FFH,MTRONFG	;FLAG DRIVES ON
	BSR	BUSYWAIT	;COMPLETE ANY PENDING
	MOVE.L	#WRITREPS,REPS(A2)	;TRY SEVERAL TIMES IF ERROR
WRIT10	
	MOVEA.L	BUFPN(A2),A0	;BUFFER TO GET DATA FROM
	MOVEQ	#0,D1
	MOVEQ	#1,D2
	MOVE.L	SECTOR(A2),D0	;SECTOR TO WRITE
	MOVE.B	D0,SECTCOM
	MOVE.L	A1,-(SP)
	MOVE.L	A2,-(SP)
	MOVE.L	A3,-(SP)	;SAVE REG TO USE DIFFERENTLY
	MOVE.L	A4,-(SP)
	MOVE.W	SR,-(SP)
	ORI.W	#0700H,SR	;DISABLE INTERRUPTS
	LEA	FDMSR,A1	;FLOPPY STATUS PORT
	LEA	FDDATA,A2	;FLOPPY DATA PORT
	LEA	COMMAND,A3	;COMMAND STRING ADDRESS
	LEA	STATDATA,A4	;STATUS DATA
	MOVEQ	#8,D3		;COMMAND LENGTH
	MOVE.L	#512,D4		;NUMBER OF BYTES TO MOVE
	MOVEQ	#7,D5		;NUMBER OF STATUS READS
	MOVE.B	COMWRT,COMMAND	;SET COMMAND INSTRUCTION
WRIT15	MOVE.B	(A3)+,(A2)	;START WRITE COMMAND
	DBEQ	D3,WRIT15	;LOOP LENGTH OF STRING
WRIT20	BTST.B	#8,(A1)		;TEST FOR DATA READY
	BEQ.S	WRIT20		;LOOP TILL NE ZERO
	MOVE.B	(A0)+,(A2)	;  ELSE WRITE DATA
	DBEQ	D4,WRIT20	;ENDWHILE    (END OF CRITICAL LOOP)
WRIT25	BTST.B	#8,(A1)		;STATUS DATA
	BEQ.S	WRIT25		;LOOP TILL STATUS READY
	MOVE.B	(A2),(A4)+
	DBEQ	D5,WRIT25	;LOOP TILL ALL STATUS READ
WRIT30	MOVE.W	(SP)+,SR	;ENABLE INTERRUPTS
	MOVEA.L	(SP)+,A4
	MOVEA.L	(SP)+,A3	;RESTORE A REGISTERS
	MOVEA.L	(SP)+,A2
	MOVEA.L	(SP)+,A1
	SUBQ.L	#1,REPS(A2)
	MOVE.B	STATDATA,D0
	ANDI.B	#0C0H,D0	;TEST BIT 6 AND 7 ONLY
	MOVE.B	D0,DSKERR(A2)	;SAVE ANY ERRORS
	BEQ.S	WRIT40
	TST.L	REPS(A2)	;IF ERROR AND NOT TIME TO GIVE UP
	BGT	WRIT10		;  THEN TRY TO WRITE SECTOR AGAIN
WRIT40	RTS
;--------------- CONVERT LOGICAL RECORD TO TRACK,SECTOR,SIDE
TRANSFORM
	MOVE.L	RECORD(A2),D0
	MOVE.L	TOTSECT(A1),D1	;SECTOR = RECORD MOD TOTSECT + 1
	DIVU	D1,D0
	CLR.W	D0
	SWAP	D0
	ADDQ.L	#1,D0
	MOVE.L	D0,SECTOR(A2)
	MOVE.L	TOTSIDE(A1),D0	;TRACK = RECORD / (TOTSIDE*TOTSECT)
	MOVE.L	TOTSECT(A1),D1
	MULU	D0,D1
	MOVE.L	RECORD(A2),D2
	DIVU	D1,D2
	CLR.L	D0
	MOVE.W	D2,D0
	MOVE.L	D0,TRACK(A2)
	CLR.W	D2		;SIDE=RECORD MOD (TOTSIDE*TOTSECT) / TOTSECT
	SWAP	D2
	MOVE.L	TOTSECT(A1),D1
	DIVU	D1,D2
	MOVE.W	D2,D0
	MOVE.L	D0,SIDE(A2)
	CLR.B	DSKERR(A2)
	MOVE.L	TRACK(A2),D0
	CMP.L	TOTRACK(A1),D0
	BLO.S	TRAN10		;IF TRACK >= TOTRACK
	MOVE.B	#10H,DSKERR(A2)	;  THEN RECORD NOT FOUND ERROR
TRAN10	RTS
;--------------------------- SEEK TRACK
SEEK
	BSR	SURFACE		;SELECT DISK AND SIDE
	MOVE.L	#SEEKREPS,REPS(A2)	;TRY SEVERAL TIMES IF ERROR
SEEK10	BSR	CYLINDER	;REPEAT POSITION HEAD
	TST.B	DSKERR(A2)
	BEQ.S	SEEK20		;IF NO ERROR THEN EXIT LOOP
	BSR	RESTORE		;ELSE RESTORE HEAD TO TRACK 00
	TST.B	DSKERR(A2)
	BNE.S	SEEK20
	SUBQ.L	#1,REPS(A2)
	BGT.S	SEEK10
	BRA.S	SEEK30		;UNTIL TIME TO GIVE UP
SEEK20	MOVE.L	CURDRIV(A2),D0	;IF SUCCESSFUL THEN CHANGE CURRENT TRACK
	LEA	CURTRAC(A2),A0
	MOVE.B	TRACCOM,-1(A0,D0)
SEEK30	RTS
;--------------------------- SELECT DISK SURFACE (DRIVE+SIDE)
SURFACE
	MOVE.L	DRIVE(A2),D0	;DRIVE TO READ/WRITE
	MOVE.L	CURDRIV(A2),D1
	CMP.L	D1,D0
	BEQ.S	SURF10		;IF CURRENT DRIVE <> DRIVE NEEDED THEN
	LEA	CURTRAC(A2),A0
	MOVE.B	TRACCOM,-1(A0,D1)	;SAVE CURRENT TRACK
	MOVE.L	D0,CURDRIV(A2)		;SWITCH DRIVES (SOFTWARE)
	MOVE.B	-1(A0,D0),TRACCOM	;GET CURRENT TRACK  ENDIF
SURF10	MOVE.Q	#6,D0			;SWITCH DRIVES (HARDWARE)
	TST.B	DRIVE(A2)		;SEE WHICH DRIVE
	BEQ.S	SURF20			;BRANCH IF DRIVE 0
	ADDQ.B	#2,D0			;SELECT DRV 1 INSTEAD
SURF20	MOVE.B	D0,F8255		;OUTPUT TO PORT
	MOVE.B	#7,D0			;START TO UNSELECT DRVIES
	TST.B	DRIVE(A2)
	BNE.S	SURF30			;BRANCH IF DRIVE NOT 0
	ADDQ.B	#2,D0
SURF30	MOVE.B	D0,F8255
	BCLR	#2,COMMAND+1		;SET SIDE TO 0
	TST.B	SIDE(A2)
	BEQ.S	SURF40			;BRANCH IF SIDE = 0
	BSET	#2,COMMAND+1		;SET SIDE = 1
SURF40	MOVE.B	SIDE(A2),COMMAND+3	;HEAD BYTE IN COMMAND STRING
	RTS
;--------------------------- SELECT DISK CYLINDER (POSITION HEAD)
CYLINDER
	BSR	BUSYWAIT	;COMPLETE ANY PENDING
	MOVE.L	TRACK(A2),D0	;TRACK TO SEEK
	TST.B	DBLSTEP(A1)	;NZ MEANS DOUBLE STEP
	BEQ.S	CYL10
	ADD.Q	TRACK(A2),D0	;DOUBLE TRACK COUNT
CYL10	MOVE.B	SEEKCMD,FDDATA	;ISSUE SEEK COMMAND
	MOVE.B	SEEKCMD+1,FDDATA
	MOVE.B	D0,FDDATA	;ISSUE TRACK NUMBER
	BSR	STATDELAY	;WAIT FOR VALID STATUS
	BSR	BUSYWAIT	;WAIT UNTIL DONE
	RTS
;--------------------------- RESTORE HEAD TO TRACK 00
RESTORE
	BSR	BUSYWAIT	;COMPLETE ANY PENDING
	BSR	SURFACE		;SELECT DISK
	MOVE.B	RESCMD,FDDATA	;START RESTORE
	MOVE.B	RESCMD+1,FDDATA
	BSR	STATDELAY	;WAIT FOR VALID STATUS
	BSR	BUSYWAIT	;WAIT UNTIL DONE
	RTS
;--------------------------- WAIT FOR TYPE ONE COMMAND TO FINISH
BUSYWAIT
	BTST	#0,FDMSR	;REPEAT READ STATUS
	BNE.S	BUSYWAIT	;UNTIL NOT BUSY
BUSYW1	BTST	#4,FDMSR
	BNE.S	BUSYW1
	RTS
;--------------------------- DELAY BETWEEN COMMAND WRITE & STATUS READ
STATDELAY
	MOVEQ	#6,D0		;14us @ 8MHz = 112 clocks
STAT10	DBRA	D0,STAT10	;10 clocks per loop
	RTS			;52 clocks overhead

	END	;BIOS.DIO
