	.IF	LISTA
	.LIST
	.PAGE
	.ELSE
	.NOLIST
	.ENDC
;****************************************************************************
;
;	Floppy disk driver
;
;	File:	SAGE.BIOSA.TEXT
;	Date:	 6-Jun-83
;	Issue:	2A
;
;
;	COPYRIGHT (c) 1982, 1983 SAGE Computer Technology
;	All Rights Reservedcd
;
;****************************************************************************
;
;	History:
;
;	1     13-Jun-82 Initial release.
;	1A    11-Jul-82 Fixed physical sector problem with no transfer due
;			to zero length request.
;	1B     2-Aug-82 Added code for UNITCLEAR to do drive recalibrate.
;	1C    14-Aug-82 Prevent write when using double track stepping.
;	1D     3-Sep-82 Added Read after Write implementation.
;			Change SPT going to controller for NCI format.
;	1E     8-Sep-82 Remove error check for formatting.
;	1F    13-Sep-82 Fixed bugs in error recovery.
;	1G    26-Oct-82 Undo change 1C to allow write when using double
;			track stepping (good luck).
;	1H    18-Dec-82 Save first and last floppy errors.  Re-init
;			controller on diskette missing error.
;	2     23-Mar-83 Initial SAGE IV release.
;	2A     6-Jun-83 Fixed problem with using logical channel number.
;			Added asynchronous handling option.
;
;****************************************************************************


.PAGE
;****************************************************************************
;
;	Floppy Read Interrupt routine:
;
;	A routine in built in low RAM to utilized self modifyable code
;	with the Short direct addressing mode.
;
;	FDIOINT MOVE.B	FD_DATA,MEMORY	;Uses xxx.W,xxx.L addressing
;		ADDQ.L	#1,FDIOINT+4	;Advance MEMORY address
;		SUBQ.W	#1,FT_CTRB	;Decrement and check byte count
;		BEQ.S	$10		;Finished all bytes
;		RTE
;	$10	JMP	FDINTC		;Uses xxx.L addressing mode
;
;
;	Floppy Write Interrupt routine:
;
;	FDIOINT MOVE.B	MEMORY,FD_DATA	;Uses xxx.L,xxx.W addressing
;		ADDQ.L	#1,FDIOINT+2	;Advance MEMORY address
;		SUBQ.W	#1,FT_CTRB	;Decrement and check byte count
;		BEQ.S	$10		;Finished all bytes
;		RTE
;	$10	JMP	FDINTC		;Uses xxx.L addressing mode
;
;
;	Floppy Read after Write routine:
;
;	FDIOINT MOVE.B	FD_DATA,MEMORY	;Uses xxx.W,xxx.L addressing
;		NOP			;Space holder
;		NOP			;Space holder
;		SUBQ.W	#1,FT_CTRB	;Decrement and check byte count
;		BEQ.S	$10		;Finished all bytes
;		RTE
;	$10	JMP	FDINTC		;Uses xxx.L addressing mode
;
;****************************************************************************


;	Floppy read/write interrupt completion
FDINTC	MOVE.B	#1,F8255	;Strobe terminal count
	MOVE.B	#0,F8255
	MOVE.B	#5,SI8255	;Turn on foreground interrupt
	BSET	#FGFLOP_B,FGTASKS+1 ;Set up floppy foreground flag
	MOVE.B	#4,F8255	;Disable floppy interrupt
	PEA	FDNOINT		;Set up for no floppy interrupts
	MOVE.L	(A7)+,A6_TRAP
	RTE


.PAGE
;****************************************************************************
;
;	Floppy Data I/O Transfer.
;
;	Routine parameters:
;	  A4		Floppy drive table address
;			(set up in FDDISP from contents of FT_TBLA)
;	  FT_MEMA	Base memory address for transfer.
;	  FT_LENG	Number of bytes to transfer.
;	  FT_LBN	Base logical diskette block number for transfer.
;	  FT_DIR	Direction (0 = read, 1 = write, 2 = format,
;				   3 = read after write pass)
;
;****************************************************************************

FDIO	MOVE.B	FI_RTRY(A4),FT_RTRY ;Set up master retry count
	TST.B	FI_SIDE(A4)
	BNE.S	FDIO1		;Found drive equipped
	MOVE.B	#-11.,FS_ERR	;Set up error code
	BRA	FDIOXIT		;Get out of driver

;	Init or recalibrate re-entry point
FDIO1	LEA	$10,A0		;Set up return from FDINIT
	MOVE.L	A0,FTINIT_A
	BRA	FDINIT

;	Initialization completion entry point
$10	MOVE.B	#2,FTIO_P	;Set up local pass counter
	TST.B	FI_IGNOR(A4)
	BNE.S	$20		;Ignore errors
	TST.B	FS_ERR		;Check for errors
	BNE	FDIOERR		;Found error
$20	CLR.B	FS_ERR		;Make sure error cleared

;	Normal continuation (for new cylinder) or retry re-entry point
FDIO2	TST.L	FT_LENG		;See if any bytes to transfer
	BEQ	FDIOXIT		;Done with total transfer
	TST.B	FT_DIR		;Check for write
	BEQ.S	$10		;Was read
	BTST	#1,C8255+2	;Check for write protect
	BEQ.S	$3		;No write protect
$2	MOVE.B	#-10.,FS_ERR	;Set up write protect error
	BRA	FDIOERR

$3	CMPI.B	#2,FT_DIR	;Check if formatting
	BNE.S	$10		;Not formatting

;	Set up for formatting
	MOVE.W	FT_LENG+2,FT_TCTR ;Set up transfer length
	MOVE.B	FT_LBN,FT_CYL	;Set up cylinder number
	MOVE.B	FT_LBN+1,FT_HEAD ;Set up head number
	BRA.S	$20		;Bypass FDCALC

$10	BSR	FDCALC		;Calculate parameters
	BNE	FDIOXIT		;Transfer is out of range, terminate
$20	MOVE.B	#1,FT_STOP	;Allow stop check while waiting for seek
	LEA	FDIO3,A0	;Set up seek completion address
	MOVE.L	A0,FTSEEK_A
	BRA	FDSEEK		;Now seek the cylinder
	
;	Seek completion entry point
FDIO3	TST.B	FI_IGNOR(A4)
	BNE.S	$5		;Ignore errors
	TST.B	FS_ERR		;Check for errors
	BNE	FDIOERR		;Found error during seek
$5	CLR.B	FS_ERR		;Make sure error clear
	CLR.B	FT_STOP		;Prevent stop check during actual transfer
	LEA	FC_GCMD,A0	;Set up command buffer
	MOVE.W	#906H,D0	;Set up read command
	ADD.B	FI_MFM(A4),D0
	TST.B	FT_DIR		;Check direction
	BEQ.S	$10		;Was read direction
	CMPI.B	#2,FT_DIR
	BEQ	$60		;Set up format command
	CMPI.B	#3,FT_DIR
	BEQ.S	$10		;Was read after write pass
	SUBQ.W	#1,D0		;Change to write command
$10	MOVE.W	D0,(A0)+	;Set up I/O command
	MOVE.B	FT_HEAD,D0
	LSL.B	#2,D0
	ADD.B	FI_DRV(A4),D0
	MOVE.B	D0,(A0)+	;Set up head parameter
	MOVE.B	FT_CYL,(A0)+
	MOVE.B	FT_HEAD,(A0)+
	MOVE.B	FT_SSEC,(A0)+
$30	MOVE.W	FI_BPS(A4),D0	;Form code for BPS
	LSR.W	#8,D0
	MOVE.B	D0,(A0)+
	MOVE.B	FI_SPT(A4),(A0)+
	BTST	#1,FI_IBM(A4)	;Check for NCI format
	BEQ.S	$35		;Not NCI format
	ADDQ.B	#8,-1(A0)	;Adjust Sectors per Track to controller
$35	MOVE.B	FI_GAP3(A4),(A0)+
	MOVE.B	FI_DTL(A4),(A0)+
	LEA	FDIO4,A0	;Set up contination address
	MOVE.L	A0,FT_CONT
	MOVE.W	FT_TCTR,FT_CTRB ;Set up byte count
	LEA	FDIOINT,A0	;Set up interrupt routine address
	MOVE.B	FT_DIR,D0	;Check which direction
	BNE.S	$40		;Was write

;	Set up read interrupt routine
	MOVE.W	#13F8H,(A0)+	;Set up MOVEB  xxx.W,xxx.L
	MOVE.W	#FD_DATA,(A0)+	;Set up floppy port address
	MOVE.L	FT_MEMA,(A0)+	;Set up memory address
	MOVE.W	#52B8H,(A0)+	;Set up ADDQ.L #1,xxx.W
	MOVE.W	#FDIOINT+4,(A0) ;Set up ADDQL argument
	BRA.S	$50

;	Set up write interrupt routine
$40	CMPI.B	#3,D0
	BEQ.S	$47		;Set up routine for read after write
	MOVE.W	#11F9H,(A0)+	;Set up MOVEB  xxx.L,xxx.W
	MOVE.L	FT_MEMA,(A0)+	;Set up memory address
	MOVE.W	#FD_DATA,(A0)+	;Set up floppy port address
	MOVE.W	#52B8H,(A0)+	;Set up ADDQ.L #1,xxx.W
	MOVE.W	#FDIOINT+2,(A0) ;Set up ADDQL argument

;	Check for write precompensation
	MOVE.B	FI_NCYL(A4),D0	;Check if half way through cylinders
	LSR.B	#1,D0
	CMP.B	FT_CYL,D0
	BLE.S	$45		;Precompensation is required
	MOVE.B	#0DH,F8255	;Set up for no precompensation
	BRA.S	$50
$45	MOVE.B	#0CH,F8255	;Apply precompensation control
	BRA.S	$50
	
;	Set up read after write routine
$47	MOVE.W	#13F8H,(A0)+	;Set up MOVEB  xxx.W,xxx.L
	MOVE.W	#FD_DATA,(A0)+	;Set up floppy port address
	MOVE.L	#FT_RAWL,(A0)+	;Set up memory address
	MOVE.W	#4E71H,(A0)+	;Set up NOP
	MOVE.W	#4E71H,(A0)	;Set up NOP

$50	LEA	FDIOINT,A0
	MOVE.L	A0,A6_TRAP	;Store interrupt routine address
	LEA	FC_GCMD,A0	;Re-establish command address
	MOVE.B	#5,F8255	;Enable floppy interrupt
	BSR	FDCMD		;Apply command
	BNE	FDIOERR		;Trouble applying command
	LEA	FT_SCHED,A0	;Set up I/O transfer timeout
	CLR.L	D0
	MOVE.W	#32000.,D0	;Allow .5 second
	MOVE.L	D0,8(A0)
	BSR	ESCHED		;Enter the schedule
	BRA	FDEXIT		;Get out of the floppy foreground
	
;	Set up format command
$60	MOVE.W	#60DH,D0	;Number of bytes & command
	ADD.B	FI_MFM(A4),D0
	MOVE.W	D0,(A0)+
	MOVE.B	FT_HEAD,D0
	LSL.B	#2,D0
	ADD.B	FI_DRV(A4),D0
	MOVE.B	D0,(A0)+	;Set up head parameter
	BRA	$30
	
	
;	Data transfer completion entry point
FDIO4	LEA	FT_SCHED,A0	;Cancel the timeout schedule
	BSR	CSCHED
	MOVE.B	FT_DIR,D0	;Check if was write
	BEQ.S	$15		;Not write
	CMPI.B	#3,D0
	BEQ.S	$15		;Was read after write pass
	MOVE.W	#800.,D0	;Set up 1 millisecond delay after write
$10	DBF	D0,$10		;  to prevent premature step pulse
$15	BSR	FDNSTAT		;Get status
	TST.B	FI_IGNOR(A4)
	BNE.S	$20		;Ignore errors
	MOVE.B	FS_ERR,D0	;Check for transfer errors
	BNE.S	FDIOERR		;Found error during transfer
$20	CLR.B	FS_ERR
	MOVE.B	FT_DIR,D0
	CMPI.B	#1,D0
	BNE.S	$30		;Not write command
	BTST	#2,FI_IBM(A4)	;Check for read after write flag
	BEQ.S	$40		;No read after write requested
	MOVE.B	#3,FT_DIR	;Set up read after write pass
	BRA	FDIO3
	
$30	CMPI.B	#3,D0		;Check for read after write pass
	BNE.S	$40		;Not read after write pass
	MOVE.B	#1,FT_DIR	;Change back to write for next pass

$40	MOVEQ	#0,D0
	MOVE.W	FT_TCTR,D0	;Set up byte count
	ADD.L	D0,FT_MEMA	;Update address
	SUB.L	D0,FT_LENG	;Update length
	DIVU	#512.,D0	;Calculate number of blocks
	ADD.W	D0,FT_LBN	;Update logical block number
	BRA	FDIO2		;Back for more

;	Process failures
FDIOERR MOVE.B	FS_ERR,FI_LERR(A4) ;Save last floppy error
	TST.B	FI_FERR(A4)	;Check if any previous errors
	BNE.S	$1		;Had previous errors
	MOVE.B	FS_ERR,FI_FERR(A4) ;Save first floppy error
$1	MOVE.B	#3,F8255	;Set drive ready signal on
	CMPI.B	#3,FT_DIR
	BNE.S	$2		;Not read after write pass
	MOVE.B	#1,FT_DIR	;Change back to write request
$2	SUBQ.B	#1,FT_RTRY	;Check master retry count
	BLE.S	FDIOXIT		;No more retries
	MOVE.B	FS_ERR,D0	;Check error type
	CMPI.B	#-7,D0
	BEQ.S	$40		;Overrun - standard retry
	CMPI.B	#-12.,D0
	BNE.S	$10		;Not wrong cylinder
$5	CLR.B	FI_RCAL(A4)	;Set up recalibrate retry
$7	ADDQ.B	#1,FI_SOFTE(A4) ;Count soft error
	BRA	FDIO1

$10	CMPI.B	#-4,D0
	BHI.S	$20		;Controller failure - need full reset
	CMPI.B	#-97.,D0
	BHI.S	$30		;Not controller failure
$20	CLR.B	FS_INIT		;Request full initialization
	BRA	$7

$30	CMPI.B	#-5,D0
	BHI.S	$50		;Don't retry -4
	CMPI.B	#-10.,D0
	BLS.S	FDIOXIT		;Don't retry -10,-11,-13
	SUBQ.B	#1,FTIO_P	;Check local pass count
	BLE.S	$5		;Do recalibrate retry
$40	ADDQ.B	#1,FI_SOFTE(A4) ;Count soft error
	CLR.B	FS_ERR		;Clear error flag
	BRA	FDIO2		;Do standard internal retry

$50	CLR.B	FS_INIT		;Force controller reinitialization
				;Fall into FDIOXIT


;	Done with transfer request
FDIOXIT BSR	DESELECT	;Deselect drive (may not physically turn
				;  off the select line)
	LEA	FDEXIT,A0	;Set up default floppy continuation
	MOVE.L	A0,FT_CONT
	CLR.B	FT_BUSY		;Set transfer completion flag for background
	BTST	#0,FT_ASY	;Check for asynchronous transfer
	BEQ.S	$10		;Not asynchronous
	MOVE.B	ATCHTBL+49.,D0
	BEQ.S	$10		;Not attached
	MOVEQ	#0,D0
	MOVE.B	FS_ERR,D0
	SWAP	D0
	MOVE.W	#49.,D0
	JSR	SIGEVENT
$10	BRA	FDEXIT		;Get out of floppy foreground


;	Set up I/O operation
WTCHAN4
	MOVE.L	A1,-(A7)	;Save working register
	LEA	FI_DRV0,A1
	BRA.S	WTCHAN5X
WTCHAN5
	MOVE.L	A1,-(A7)	;Save working register
	LEA	FI_DRV1,A1
WTCHAN5X
	MOVE.B	#1,D0		;Set up write direction
	BTST	#5,14.(A0)	;Check for formatting
	BEQ.S	CHAN45		;No formatting
	MOVE.B	#2,D0		;Set up format code
	BRA.S	CHAN45

;	Write floppy configuration
WCFCH4
	MOVE.L	A2,-(A7)	;Save an address register
	LEA	FI_DRV0,A2
	BRA.S	WCFCH5X

WCFCH5
	MOVE.L	A2,-(A7)	;Save an address register
	LEA	FI_DRV1,A2
	
WCFCH5X MOVEQ	#8-1,D0
$10	MOVE.L	(A1)+,(A2)+	;Move in floppy parameters
	DBF	D0,$10
	CLR.B	FS_INIT		;Force an initialization
	MOVEA.L (A7)+,A2	;Restore address register
	RTS


;	Read floppy configuration
RCFCH4
	MOVE.L	A2,-(A7)	;Save an address register
	LEA	FI_DRV0,A2
	BRA.S	RCFCH5X

RCFCH5
	MOVE.L	A2,-(A7)	;Save an address register
	LEA	FI_DRV1,A2
	
RCFCH5X MOVEQ	#8-1,D0
$10	MOVE.L	(A2)+,(A1)+	;Move in floppy parameters
	DBF	D0,$10
	MOVEA.L (A7)+,A2	;Restore address register
	RTS


RDCHAN4
	MOVE.L	A1,-(A7)	;Save working register
	LEA	FI_DRV0,A1
	BRA.S	RDCHAN5X

RDCHAN5
	MOVE.L	A1,-(A7)	;Save working register
	LEA	FI_DRV1,A1
RDCHAN5X
	CLR.B	D0		;Set up read direction

CHAN45	MOVE	#2700H,SR	;Disable interrupts
	TST.B	FT_BUSY		;Check if busy
	BEQ.S	$5		;Not busy
	STOP	#2000H		;Enable interrupts and stop
	BRA	CHAN45		;Try again
	
$5	ST	FT_BUSY		;Set up drive busy
	MOVE	#2000H,SR	;Re-enable interrupts
	MOVE.B	D0,FT_DIR	;Set up direction request
	MOVE.L	A1,FT_TBLA	;Set up floppy table address
	MOVE.L	4(A0),FT_LENG	;Set up length of transfer
	MOVE.L	8(A0),FT_MEMA	;Set up memory address for transfer
	MOVE.W	12.(A0),FT_LBN	;Set up logical block number for transfer
	MOVE.B	15.(A0),FT_ASY	;Set up asynchronous transfer flag
	CLR.B	FT_PHYS		;Default to no physical sector transfer
	BTST	#1,15.(A0)	;Check for physical sector flag
	BEQ	$15		;No physical sector flag
	MOVE.B	#1,FT_PHYS	;Set physical sector flag
	MOVEQ	#1,D0		;Force length to 1 byte to fool driver
	MOVE.L	D0,FT_LENG	;  FDCALC will override length later.
$15	MOVE.B	#1,FT_STOP	;Set up flag to stop if no floppy completion
	LEA	FDIO,A1		;Set up floppy routine address
	MOVE.L	A1,FT_CONT
	BSET	#FGFLOP_B,FGTASKS+1 ;Set floppy foreground flag
	MOVEA.L (A7)+,A1	;Restore working register
	MOVE.B	#5,SI8255	;Set up foreground interrupt
	BTST	#0,15.(A0)	;Check for asynchronous transfer
	BEQ.S	$20		;Not asynchronous
	RTS

;	Processor should set up floppy transfer in foreground

$20	TST.B	FT_STOP		;Check which type of test
	BNE.S	$100		;Do test with stop on failure
	TST.B	FT_BUSY		;Check if transfer done
	BNE.S	$20		;Transfer is not done
$30	MOVE.B	FS_ERR,D0	;Return error code
	EXT.W	D0
	MOVE.W	D0,2(A0)
	RTS



;	Perform floppy done test with stop on not done
$100	MOVE	#2700H,SR	;First disable interrupts
	TST.B	FT_BUSY		;Check if done
	BNE.S	$110		;Was not done
	MOVE	#2000H,SR	;Re-enable interrupts
	BRA.S	$30		;Found completion

$110	STOP	#2000H		;Enable interrupts and stop
	BRA.S	$20		;Test again


;	Floppy initialization
INCHAN4 MOVE.L	A0,-(A7)
	LEA	FI_DRV0,A0
	BRA.S	INCHN45

INCHAN5 MOVE.L	A0,-(A7)
	LEA	FI_DRV1,A0
INCHN45 CLR.B	FI_RCAL(A0)	;Force next access to recalibrate
	MOVEA.L (A7)+,A0
	RTS


;	Floppy status request
STCHAN4 MOVE.L	A3,-(A7)	;Save register
	LEA	FI_DRV0,A3
	BRA.S	STCHN45

STCHAN5 MOVE.L	A3,-(A7)	;Save register
	LEA	FI_DRV1,A3

STCHN45 CLR.W	(A1)		;Number of bytes buffered
	MOVE.W	FI_BPS(A3),2(A1) ;Number of bytes per sector
	CLR.W	D0
	MOVE.B	FI_SPT(A3),D0	;Number of sectors per track
	MOVE.W	D0,4(A1)
	MOVE.B	FI_NCYL(A3),D0	;Number of tracks per disk
	CMPI.B	#2,FI_SIDE(A3)	;Check if double sided
	BNE.S	$10		;Not double sided drive
	ASL.W	#1,D0
$10	MOVE.W	D0,6(A1)	;Store number of tracks per disk
	CLR.W	D0
	MOVE.B	FT_BUSY,D0
	MOVE.W	D0,50.(A1)	;Save busy flag
	MOVE.B	FS_ERR,D0
	MOVE.W	D0,52.(A1)	;Save current error
	MOVE.B	FI_FERR(A3),D0
	MOVE.W	D0,56.(A1)	;Save first error code
	MOVE.B	FI_LERR(A3),D0
	MOVE.W	D0,58.(A1)	;Save last error code
	MOVEA.L (A7)+,A3	;Restore register
	RTS

                                                                                                                                                                                                                                                                 