	.IF	LIST7
	.LIST
	.PAGE
	.ELSE
	.NOLIST
	.ENDC
;****************************************************************************
;
;	Floppy disk driver routines
;
;	File:	SAGE.BIOS7.TEXT
;	Date:	23-Mar-83
;	Issue:	2
;
;
;	COPYRIGHT (c) 1982, 1983 SAGE Computer Technology
;	All Rights Reserved
;
;****************************************************************************
;
;	History:
;
;	1     13-Jun-82 Initial release.
;	1A    11-Jul-82 Fixed bug with length in physical sector mode.
;	1B    20-Jul-82 Added "Network Consulting" sector number format.
;	1C    13-Aug-82 Fixed bug with IBM format routine in FDCALC.
;	1D     3-Sep-82 More problems with FDCALC using IBM format.
;			Also changes for first sector of NCI format.
;	1E    13-Sep-82 Modified to handle lost status in transfer.
;	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 (equipment check)
;	 -4  - No Diskette (as a result of read/write timeout #1)
;	 -5  - Missing address mark
;	 -6  - No data found
;	 -7  - Overrun
;	 -8  - CRC error
;	 -9  - End of cylinder
;	 -10.- Write Protect Violation
;	 -11.- Address out of range
;	 -12.- Wrong Cylinder
;	 -13.- Illegal BPS code of floppy
;	 -14.- Illegal device number (Only issued from higher level protocall)
;	 -15.- Illegal request (Only issued from higher level protocall)
;
;	 -97.- Unknown error
;	 -98.- Probably error detected in transfer (transient state).
;
;****************************************************************************

.PAGE
;****************************************************************************
;
;	Floppy foreground task dispatcher & exit routines
;
;	Sets up working environment for major floppy processes with
;	A4 = address of drive table, and D0, A0, and A4 preserved.
;
;****************************************************************************

FDDISP
	BCLR	#FGFLOP_B,FGTASKS+1 ;Clear foreground flag
	MOVEM.L D0/A0/A4,-(A7)	;Save working registers
	MOVEA.L FT_TBLA,A4	;Set up working table address
	MOVEA.L FT_CONT,A0	;Jump to continuation routine
	JMP	(A0)

FDEXIT
	MOVEM.L (A7)+,D0/A0/A4	;Restore working registers
	BRA	FGEXIT		;Now get out of foreground

.PAGE
;****************************************************************************
;
;	Apply floppy disk command.
;
;	Input parameters:
;	  A0 = address for floppy disk command.
;	       First byte of data is command length.
;
;	Registers modified: D0, A0
;
;	Controller should be ready for a command within 250 milliseconds
;	when routine is called.	 The routine will introduce
;	a 12 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,-(A7)	;Save working registers
	MOVE.B	(A0)+,D1	;Get command byte count
$10	MOVE.W	#DLY1*250.,D2	;Set up 250 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	(A0)+,FD_DATA	;Output command to controller
	MOVEQ	#DLY2-1,D2	;Set up 12 microsecond delay
$30	DBNE	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	;Restore working registers
	RTS

;	Failed timeout or data direction
$50	MOVE.B	#-1,FS_ERR	;Force NE condition
	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, A0
;
;****************************************************************************

FDISTAT
	LEA	FC_SIS,A0	;Set up sense interrupt status command
	BSR	FDCMD
	CMPI.B	#-1,FS_ERR
	BEQ.S	$30		;Found controller lockup
	MOVEM.L D1-D2,-(A7)	;Save working registers
	MOVEQ	#2,D1		;Status byte count
	LEA	FS_ISR0,A0	;Target address
	CLR.B	(A0)
	BSR	FDSTAT		;Get interrupt status
	BNE.S	$20		;Found a problem, condition already set
	CLR.B	D0
	MOVE.B	FS_ISR0,D1	;Get status register 0
	ANDI.B	#0D0H,D1	;Check for good completion
	BEQ.S	$10		;Was good
	MOVEQ	#-3,D0		;Set up code for equipment check
	BTST	#4,D1
	BNE.S	$10		;Indicate equipment check
	BTST	#7,D1
	BEQ.S	$10		;Abnormal termination (same as equip check)
	MOVEQ	#-2,D0
	BTST	#6,D1
	BEQ.S	$10		;Invalid command
	MOVEQ	#-1,D0		;This timeout is controller failure
	
$10	MOVE.B	D0,FS_ERR	;Save floppy error information, sets condition
$20	MOVEM.L (A7)+,D1-D2	;Restore working registers D2, D1
$30	RTS


;	Read normal read/write completion status
FDNSTAT
	MOVEM.L D1-D2,-(A7)	;Save working registers
	MOVEQ	#7,D1		;Status byte count
	LEA	FS_SR0,A0	;Target address
	CLR.B	(A0)
	BSR.S	FDSTAT		;Get status
	TST.B	FS_ERR
	BNE.S	$90		;Found a problem, condition already set
	CLR.B	D0
	MOVE.B	FS_SR0,D1	;Get status register 0
	ANDI.B	#0C0H,D1	;Check for good completion
	BEQ.S	$100		;Was good
	MOVEQ	#-2,D0
	CMPI.B	#80H,D1
	BEQ.S	$100		;Set up illegal command error
	
	MOVEQ	#-5,D0		;Indicate missing address error
	MOVE.B	FS_SR1,D1	;Get main error flags
	LSR.B	#1,D1
	BCS.S	$100		;Was address mark error
	MOVEQ	#-10.,D0
	LSR.B	#1,D1
	BCS.S	$100		;Write protect violation
	MOVEQ	#-6,D0
	LSR.B	#1,D1
	BCS.S	$50		;Was missing data error
	MOVEQ	#-7,D0
	LSR.B	#2,D1
	BCS.S	$100		;Was overrun error
	MOVEQ	#-8,D0
	LSR.B	#1,D1
	BCS.S	$100		;Was CRC error
	MOVEQ	#-9,D0
	LSR.B	#2,D1
	BCS.S	$100		;Was end of cylinder
	MOVEQ	#-97.,D0	;Unknown error
	BRA.S	$100
	
;	Check for wrong cylinder
$50	BTST	#4,FS_SR2
	BEQ.S	$100		;Just No Data error
	MOVEQ	#-12.,D0	;Wrong cylinder error

$100	MOVE.B	D0,FS_ERR	;Save floppy error information, sets condition
$90	MOVEM.L (A7)+,D1-D2	;Restore working registers
	RTS


.PAGE
;****************************************************************************
;
;	Read floppy disk status.
;	  (only used by FDISTAT & FDNSTAT)
;
;	Input parameters:
;	  A0 = address for floppy disk status.
;	  D1 = status byte count.
;
;	Registers modified: D0, D1, D2, A0.
;
;	Controller should always be ready with status when routine is called.
;	The exception to this rule is when a partial sector transfer is made
;	when the remainder of the sector must be processed by the controller.
;	The timeout delay is set to 250 milliseconds.  The routine will introduce
;	a 12 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*250.,D2	 ;Set up 250 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,(A0)+	;Fetch status data from controller
	MOVEQ	#DLY2-1,D2	;Set up 12 microsecond delay
$30	DBNE	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	CMPI.B	#-98.,FS_ERR	;Check for probable error during transfer
	BNE.S	$70		;Was controller lockup
	CMPI.B	#1,D1
	BNE.S	$70		;Not just one byte short
	MOVEQ	#6-1,D1		;Move all bytes down
$60	MOVE.B	-1(A0),(A0)
	SUBQ.L	#1,A0
	DBF	D1,$60
	MOVE.B	#40H,(A0)	;Set up normal error indicator
	CLR.B	FS_ERR		;No error at low level
	RTS
	
$70	MOVE.B	#-1,FS_ERR	;Force NE condition
	RTS			;Return

.PAGE
;****************************************************************************
;
;	Calculate current floppy parameters.
;
;	  Cylinder address.
;	  Head address.
;	  Starting sector address.
;	  Transfer byte count.
;
;	  Alternate calculation if FT_PHYS is set
;	  gives one physical sector.
;
;	Routine uses register: D0
;
;****************************************************************************

FDCALC
	MOVE.L	D1,-(A7)	;Save working register D1
	TST.B	FI_SIDE(A4)	;See if drive is equipped
	BEQ	$30		;Drive not equipped
	CLR.L	D0
	CLR.L	D1
	TST.B	FT_PHYS		;Check for physical sector flag
	BNE	$100		;Was physical sector address request
	MOVE.W	#512.,D0	;Find sectors per block
	DIVU	FI_BPS(A4),D0	;D0 = Sectors per block

	MOVE.W	FT_LBN,D1	;Find logical sector number on total disk
	MULU	D0,D1		;D1 = logical sector number

	CLR.L	D0
	MOVE.B	FI_SPT(A4),D0	;Get sectors per track
	DIVU	D0,D1		;Form logical track number
	CLR.B	D0		;Set up default head number
	BTST	#0,FI_SIDE(A4)	;Check how many sides
	BNE.S	$10		;Single sided drive, Cylinder = Track
	
	BTST	#0,FI_IBM(A4)	;Check for IBM track format
	BEQ.S	$5		;Not IBM track format
	
	CMP.B	FI_NCYL(A4),D1	;Check if half way
	BEQ.S	$3		;Cylinder is track on second half
	BLS.S	$10		;Cylinder is track on first half
	
$3	NEG.B	D1		;Cylinder := (2*NCYL)-track-1
	SUBQ.B	#1,D1		;  on second half of diskette
	ADD.B	FI_NCYL(A4),D1
	ADD.B	FI_NCYL(A4),D1
	MOVEQ	#1,D0		;Head := 1
	BRA.S	$10
	
$5	LSR.W	#1,D1		;Form cylinder number
	ROXL.L	#1,D0		;Form head number
$10	MOVE.B	D0,FT_HEAD	;Save head address
	MOVE.B	D1,FT_CYL	;Save cylinder address
	CMP.B	FI_NCYL(A4),D1	;Check cylinder limit
	BHI.S	$30		;Address to big
	BEQ.S	$30		;Address still to big
	
	SWAP	D1		;Access sector number
	TST.W	FT_LBN		;Check if logical block 0
	BNE.S	$15		;Not block 0
	BTST	#1,FI_IBM(A4)	;Check for NCI format
	BEQ.S	$15		;Not NCI format
	MOVEQ	#1,D0		;First block of NCI is normal
	BRA.S	$17		;  and must be split out
	
$15	MOVE.B	FI_SPT(A4),D0
	SUB.B	D1,D0		;Number of sectors left in track
$17	MULU	FI_BPS(A4),D0	;Number of bytes left in track
	CMP.L	FT_LENG,D0	;Check how many bytes needed
	BLE.S	$20		;Use whole remainder of track
	MOVE.L	FT_LENG,D0	;Only need part of track
$20
	ADDQ.B	#1,D1
	MOVE.B	D1,FT_SSEC	;Save first sector number (one based)
	MOVE.W	D0,FT_TCTR	;Save byte count for this transfer
	BTST	#1,FI_IBM(A4)	;Check for "Network Consulting" sector numbers
	BEQ.S	$27		;No special sector numbers
	TST.W	FT_LBN
	BEQ.S	$27		;Don't bias logical block 0
	ADDQ.B	#8,FT_SSEC	;Offset for sectors 9 to 18
$27	MOVE.L	(A7)+,D1	;Restore working register D1
	CLR.B	D0		;EQ means success
	RTS

;	Address is out of range
$30	MOVE.L	(A7)+,D1	;Restore working register D1
	MOVE.B	#-11.,FS_ERR	;Indicate error (NE)
	RTS

;	Set up for single physical sector transfer
$100	MOVE.W	FT_LBN,D1	;Logical block number is physical sector
	MOVE.B	FI_SPT(A4),D0
	DIVU	D0,D1		;Physical sector Div (Sectors per Track)
	SWAP	D1
	ADDQ.B	#1,D1		;Form sector number
	MOVE.B	D1,FT_SSEC	;Save starting (and only) sector
	CLR.W	D1
	SWAP	D1
	MOVE.B	FI_SIDE(A4),D0
	DIVU	D0,D1		;Track Div (Number of sides)
	CMP.B	FI_NCYL(A4),D1
	BGE.S	$30		;Address is too big
	MOVE.B	D1,FT_CYL	;Save cylinder address
	SWAP	D1
	MOVE.B	D1,FT_HEAD	;Save head address
	MOVE.W	FI_BPS(A4),D0	;Only transfer one sector
	MOVE.L	D0,FT_LENG
	MOVE.W	D0,FT_TCTR	;Save byte count for this transfer
	BRA.S	$27

;	Floppy command to sense interrupt status
FC_SIS	.BYTE	1		;Number of bytes in command
	.BYTE	8		;Command byte

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