	.IF	LIST7
	.LIST
	.PAGE
	.ELSE
	.NOLIST
	.ENDC
;****************************************************************************
;
;	Floppy disk driver routines
;
;	File:	SAGE.PROM7.TEXT
;	Date:	23-Mar-83
;	Issue:	2
;
;	COPYRIGHT (c) 1982, 1983  SAGE Computer Technology
;	All Rights Reserved
;
;****************************************************************************
;
;	Release History:
;
;	1     13-Jun-82 Initial release.
;	2     23-Mar-83 Initial SAGE IV release.
;
;****************************************************************************
;
;	General Information:
;
;	All routines rely on the following register usage.
;
;	  A4 = pointer to base of Floppy Drive information.
;
;	Returned error codes (in FS_ERR )
;
;	  0  - No error
;	  1  - Controller failure
;	  2  - Invalid command
;	  3  - Recalibrate or Seek failure
;	  4  - Read ID timeout (probably no diskette)
;	  5  - Missing address mark
;	  6  - No data found
;	  7  - Overrun
;	  8  - CRC error
;	  9  - End of cylinder
;	  10.- Unknown error
;	  11.- Address out of range
;
;****************************************************************************


.PAGE
;****************************************************************************
;
;	Apply floppy disk command.
;
;	Input parameters:
;	  A1 = address for floppy disk command.
;	       First byte of data is command length.
;
;	Registers modified: D0
;
;	Stack depth: 16 bytes (including call).
;
;	Controller should always be ready for a command when routine is called.
;	The timeout delay is only a millisecond.  The routine will introduce
;	a 24 microsecond delay after writing each byte to allow proper
;	controller recovery.
;
;	The EQ condition will be set on successful command output.  Otherwise,
;	the NE condition will be set.  Errors are always a timeout on providing
;	information or a request by the controller to output information.
;
;****************************************************************************

FDCMD
	MOVEM.l D1-D2/A1,-(A7)	;Save working registers
	MOVE.B	(A1)+,D1	;Get command byte count
$10	MOVE.B	#DLY1-1,D2	;Set up 1 millisecond loop delay
$20	MOVE.B	FD_MSR,D0	;Get master status register from controller
	BTST	#7,D0		;Check for controller service request
	DBNE	D2,$20
	BEQ.S	$50		;Had timeout on reading controller
	BTST	#6,D0		;Check to make sure output request
	BNE.S	$50		;Request for input is not expected
	MOVE.B	(A1)+,FD_DATA	;Output command to controller
	MOVEQ	#DLY2-1,D2	;Set up 24 microsecond delay
$30	DBF	D2,$30
	SUBQ.B	#1,D1		;Check status byte count
	BNE.S	$10		;Back for more
;	Fall into exit code with EQ condition.

$40	MOVEM.L (A7)+,D1-D2/A1	;Restore working registers
	RTS

;	Failed timeout or data direction
$50	MOVE.B	#1,FS_ERR	;Controller error code
	BRA.S	$40		;Return


.PAGE
;****************************************************************************
;
;	Status requests.
;
;	  FDISTAT  - Read Interrupt Status
;			Updates FS_SR0 and FS_CYL.
;
;	  FDNSTAT  - Read Normal Read/Write Completion Status
;			Updates FS_SR0 thru FS_BPS.
;
;	Registers modified: D0
;
;	Stack depth:  20 bytes (including call) 
;
;****************************************************************************

FDISTAT
	MOVEM.L D1-D2/A1,-(A7)	;Save working registers D1,D2,A1
	LEA	FC_SIS,A1	;Apply command to sense interrupt status
	BSR	FDCMD
	BNE.S	$110		;Bad command application
	MOVEQ	#2,D1		;Status byte count
	LEA	FS_ISR0,A1	;Target address
	BSR.S	FDSTAT		;Get interrupt status
	BNE.S	$110		;Found a problem
	MOVE.B	FS_ISR0,D1	;Get status register 0
	ANDI.B	#0C0H,D1	;Check for good completion
	BEQ.S	$100		;Was good
	BTST	#6,D1		;Check which type of failure
	BEQ.S	$90		;Illegal command
	MOVEQ	#3,D1		;Indicate Recalibrate or Seek failure
	BRA.S	$100
	
$90	MOVEQ	#2,D1		;Indicate Invalid Command error
	
$100	MOVE.B	D1,FS_ERR	;Save floppy error information, sets condition
$110	MOVEM.L (A7)+,D1-D2/A1	;Restore working registers
	RTS


;	Read normal read/write completion status
FDNSTAT
	MOVEM.L D1-D2/A1,-(A7)	;Save working registers
	MOVEQ	#7,D1		;Status byte count
	LEA	FS_SR0,A1	;Target address
	CLR.B	(A1)
	BSR.S	FDSTAT		;Get interrupt status
	BNE.S	$110		;Found a problem
	MOVE.B	FS_SR0,D1	;Get status register 0
	ANDI.B	#0C0H,D1	;Check for good completion
	BEQ.S	$100		;Was good
	BTST	#6,D1		;Check error type
	BEQ.S	$90		;Invalid command
	
	MOVEQ	#5,D1		;Indicate missing address error
	MOVE.B	FS_SR1,D0	;Get main error flags
	LSR.B	#1,D0
	BCS.S	$100		;Was address mark error
	MOVEQ	#6,D1
	LSR.B	#2,D0
	BCS.S	$100		;Was missing data error
	MOVEQ	#7,D1
	LSR.B	#2,D0
	BCS.S	$100		;Was overrun error
	MOVEQ	#8,D1
	LSR.B	#1,D0
	BCS.S	$100		;Was CRC error
	MOVEQ	#9,D1
	LSR.B	#2,D0
	BCS.S	$100		;Was end of cylinder
	MOVEQ	#10.,D1		;Unknown error
	BRA.S	$100
	
$90	MOVEQ	#2,D1		;Indicate Invalid Command error
	
$100	MOVE.B	D1,FS_ERR	;Save floppy error information, sets condition
$110	MOVEM.L (A7)+,D1-D2/A1	;Restore working registers
	RTS


.PAGE
;****************************************************************************
;
;	Read floppy disk status.
;	  (only used by FDISTAT & FDNSTAT)
;
;	Input parameters:
;	  A1 = address for floppy disk status.
;	  D1 = status byte count.
;
;	Registers modified: D0, D1, D2, A1.
;
;	Stack depth: 4 bytes (including call).
;
;	Controller should always be ready with status when routine is called.
;	The exeception is when a partial sector transfer is being made and the
;	remainder of the sector must be read or written.  Thus the timeout
;	delay is set to 25 milliseconds.  The routine will introduce
;	a 24 microsecond delay after reading each byte to allow proper
;	controller recovery.
;
;	The EQ condition will be set on successful status read.	 Otherwise,
;	the NE condition will be set.  Errors are always a timeout on providing
;	information or a request by the controller for information.
;
;****************************************************************************

FDSTAT
$10	MOVE.W	#DLY1*25.,D2	;Set up 25 millisecond loop delay
$20	MOVE.B	FD_MSR,D0	;Get master status register from controller
	BTST	#7,D0		;Check for controller service request
	DBNE	D2,$20
	BEQ.S	$50		;Had timeout on reading controller
	BTST	#6,D0		;Check to make sure output request
	BEQ.S	$50		;Request for input is not expected
	MOVE.B	FD_DATA,(A1)+	;Fetch status data from controller
	MOVEQ	#DLY2-1,D2	;Set up 24 microsecond delay
$30	DBF	D2,$30
	SUBQ.B	#1,D1		;Check status byte count
	BNE.S	$10		;Back for more
;	Fall into exit code with EQ condition.

$40	RTS

;	Failed timeout or data direction
$50	MOVE.B	#1,FS_ERR	;Force NE condition
	RTS			;Return


.PAGE
;****************************************************************************
;
;	Load/Store floppy disk data.
;
;	Input parameters:
;	  A1 = address for floppy disk data.
;	  D1 = byte count of data.
;	  D2 = 0 for reading, 1 for writing
;
;	Registers modified: D0, A1
;
;	Stack depth: 36 bytes (including call).
;
;	The EQ condition will be set on successful data read.  Otherwise,
;	the NE condition will be set.  Errors are always a timeout on providing
;	information or a request by the controller for information.
;
;****************************************************************************

FDLOAD
	MOVE.L	D1,-(A7)	;Save working register
$10	MOVEQ	#DLY3,D0	;Set up 1 second loop delay
	SWAP	D0
$20	BTST	#0,C8255+2	;Check for controller interrupt
	BNE.S	$30		;Found interrupt
	SUBQ.L	#1,D0
	BNE.S	$20		;Try again
;	Had timeout on reading controller
	MOVE.B	#2,F8255	;Set up Drive Not Ready
	MOVE.B	#4,FS_ERR
	BRA.S	$40

;	Process request for data transfer
$30	TST.B	D2		;Check direction
	BNE.S	$50		;Was write
	MOVE.B	FD_DATA,(A1)+	;Fetch data byte from controller
	SUBQ.W	#1,D1		;Check data byte count
	BNE.S	$10		;Back for more

;	Terminate transfer
$40	MOVE.B	#1,F8255	;Strobe terminal count
	MOVE.B	#0,F8255
	BSR	FDNSTAT		;Get read result status
	MOVE.L	(A7)+,D1	;Restore working register
	TST.B	FS_ERR		;Set up error flag
	RTS

;	Process write request
$50	MOVE.B	(A1)+,FD_DATA	;Output data byte to controller
	SUBQ.W	#1,D1		;Check data byte count
	BNE.S	$10		;Back for more
	BRA.S	$40		;Done


.PAGE
;****************************************************************************
;
;	Recalibrate floppy drive
;
;	Registers modified: D0
;
;	Stack depth:  36 bytes (including call).
;
;	Routine retries once if a seek error occurs on a 96 TPI drive
;	in case was over 77 tracks from track 0.
;
;	The EQ condition will be set on a successful recalibrate.  Otherwise,
;	the NE condition will be set.
;
;****************************************************************************

FDRECAL
	MOVEM.L D1-D2/A1,-(A7)	;Save working registers
	MOVEQ	#2-1,D1		;Retry counter for 96 TPI case
$5	LEA	FC_RCAL,A1	;Load command address
	BSR	FDCMD		;Apply command
	BNE.S	$30		;Problem with command

;	Wait for completion, 478 milliseconds should be worst case but
;	1 second is allowed.
	MOVEQ	#DLY4,D2
	SWAP	D2
$10	BTST	#0,C8255+2
	BNE.S	$20		;Seek is done
	SUBQ.L	#1,D2		;Check timeout
	BNE.S	$10		;Back for another check

;	timed out probably no drive
	MOVE.B	#4,FS_ERR
	BRA.S	$30		;NE condition

;	Recalibrate is done
$20	CLR.B	FI_CCYL(A4)	;Indicate current cylinder at 0
	BSR	FDISTAT		;Get status bytes
	BEQ.S	$30		;Successful recalibrate
	CMPI.B	#3,FS_ERR	;Check if recalibrate error
	BNE.S	$30		;Not recalibrate error, just return
	CMPI.B	#80.,FI_NCYL(A4) ;Check if 96 TPI drive
	BNE.S	$30		;Not 96 TPI, just return
	DBF	D1,$5		;Retry if count not up
	MOVEQ	#3,D0		;Condition NE indicates error
$30	MOVEM.L (A7)+,D1-D2/A1	;Restore working registers
	RTS

.PAGE
;****************************************************************************
;
;	Floppy Drive Seek
;
;	Registers modified: none
;
;	Stack depth:  52 bytes (including call).
;
;	Routine retries twice by recalibrating if a seek error occurs.
;
;	The EQ condition will be set on a successful seek.  Otherwise,
;	the NE condition will be set.
;
;****************************************************************************

FDSEEK
	MOVEM.L D1-D2/A1,-(A7)	;Save working registers
	MOVEQ	#3-1,D1		;Retry counter
$10	MOVE.B	FT_CYL,D0	;Get desired cylinder
	CMP.B	FI_CCYL(A4),D0	;See if there already
	BEQ.S	$50		;Already there, nothing to do
	LEA	FC_GCMD,A1	;Set up command buffer address
	MOVE.W	#30FH,(A1)	;Set up Seek command
	CLR.B	2(A1)
	MOVE.B	FT_CYL,3(A1)	;Set up cylinder parameter
	BSR	FDCMD		;Apply command
	BNE.S	$50		;Problem with command

;	Wait for completion, 478 milliseconds should be worst case but
;	1 second is allowed.
	MOVEQ	#DLY4,D2
	SWAP	D2
$20	BTST	#0,C8255+2	;Check main status register
	BNE.S	$30		;Seek is done
	SUBQ.L	#1,D2		;Check for timeout
	BNE.S	$20		;Back for another check

;	Timed out, probably no diskette
	MOVE.B	#4,FS_ERR	;No diskette error code
	BRA.S	$50		;NE condition
     
$30	BSR	FDISTAT		;Get status bytes
	BNE.S	$40		;Unsuccessful seek
	MOVE.B	FT_CYL,FI_CCYL(A4) ;Set up current cylinder address
	CLR.B	D0		;EQ means success
	BRA.S	$50

;	Problem with seek, should recalibrate
$40	BSR	FDRECAL
	BNE.S	$50		;Failed recalibrate too, give up
	DBF	D1,$10		;Check retry counter and retry
	MOVEQ	#3,D0		;Condition NE indicates failure
$50	MOVEM.L (A7)+,D1-D2/A1	;Restore working registers
	RTS
     

	.BLOCK	8.		;Expansion space

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