	.IF	LISTE
	.LIST
	.PAGE
	.ELSE
	.NOLIST
	.ENDC
;****************************************************************************
;
;	Winchester Disk Driver - part 1
;
;	File:	SAGE.PROME.TEXT
;	Date:	28-Jul-83
;	Issue:	1A
;
;
;	COPYRIGHT (c) 1983 SAGE Computer Technology
;	All Rights Reserved
;
;****************************************************************************
;
;	History:
;
;	1     23-Mar-83 Initial SAGE IV release.
;	1A    28-Jul-83 Improved recalibrate procedure.
;
;****************************************************************************


;****************************************************************************
;
;	Error Codes:
;
;	 0	No error
;	-1	Could not initialized VCO.
;	-2	
;	-3	Recalibrate failure
;	-4	Drive not ready
;	-5	Missing address mark
;	-6	Timeout waiting for data
;	-7	Overrun (if detectable)
;	-8	CRC error
;	-9	Verify error (read after write)
;	-10.	Write protect violation
;	-11.	Address out of range
;	-12.	Wrong cylinder
;	-13.
;	-14.	Bad device number
;
;****************************************************************************



.PAGE
;****************************************************************************
;
;	Winchester Initialization
;
;****************************************************************************

WCINIT
	BSR	WVCOINIT
	CLR.B	WS_RCAL		;Force recalibrate
	ST	WG_INIT		;Force to look initialized
	RTS


.PAGE
;****************************************************************************
;
;	VCO Initialization
;
;	Uses: D0,D1,D2, A1
;
;****************************************************************************

WVCOINIT
	MOVEM.L D3-D5,-(SP)
	MOVE.B	#0,WP_2CB	;Force VCO to minimum frequency
	BSET	#0,WP_2B
	MOVEQ	#-128.,D0	;Start search in middle of range
	MOVEQ	#0,D2		;Timeout counter

$10	MOVE.B	D0,WP_DTOA	;Apply trial value to D/A converter
	MOVEQ	#50.,D1		;Delay for 100 microseconds
$20	DBF	D1,$20
	MOVEQ	#5-1,D5		;Set up success counter
	
$25	MOVE.B	#0B0H,WP_8253+6 ;Mode 0
	MOVE.B	#0,WP_8253+4	;Zero count
	MOVE.B	#0,WP_8253+4
	MOVE.W	#1740H,D1	;Wait 12 milliseconds
$30	DBF	D1,$30
	MOVE.B	#80H,WP_8253+6	;Latch data
	MOVEQ	#0,D3		;Clear high part
	MOVE.B	WP_8253+4,D3	;Read the counter data
	ROL.W	#8,D3
	MOVE.B	WP_8253+4,D3
	ROL.W	#8,D3
	NEG.W	D3		;Find VCO count
	DIVU	#12.,D3		;D3 will be frequency in KHZ
	MOVE.W	D3,VCOVAL	;Save value
	SUB.W	VCOCAL,D3	;Check against calibration value
	BEQ.S	$100		;Found exact match
	BGT.S	$80		;Freqency was too high
;	Frequency was too low
	NEG.W	D3		;Make difference positive
	CMPI.W	#2,D3
	BLE.S	$100		;Last value is in range
	ADDQ.B	#1,D2
	BEQ.S	$110		;Could not converge on value
	SUBQ.B	#1,D0
$70	BNE	$10		;Try next number

;	D/A converter to stops
	BRA.S	$110		;Value is out of range


;	Frequency was too high
$80	CMPI.W	#2,D3
	BLE.S	$100		;Last value is in range
	ADDQ.B	#1,D2
	BEQ.S	$110		;Could not converge on value
	ADDQ.B	#1,D0
	BRA	$70


 ;	Save good value
$100	DBF	D5,$25		;Check success counter
	ST	WG_INIT		;Set initialized flag

$110	MOVE.B	D0,WG_VCODA	;Save data reading
	MOVE.B	#1,WP_2CB	;Remove VCO force
	MOVE.W	#1740H,D0
$120	DBF	D0,$120
	MOVEM.L (SP)+,D3-D5
	RTS



.PAGE
;****************************************************************************
;
;	Calculate transfer parameters for Winchester
;
;	From:
;	  WT_LBN	Logical block number
;	  WT_LENG	Length of transfer
;	  WT_CTRL	Control information flags
;
;	Calculate:
;	  WT_CYL	Cylinder address
;	  WT_HEAD	Head address
;	  WT_LEAD	Number of bytes leading data in track
;	  WT_NUMB	Number of data bytes in track
;	  WT_TRAIL	Number of trailing bytes in track
;	  WT_LTN	Logical track number
;
;	Uses: D0,D1,D2,	 A1
;
;****************************************************************************

WDCALC
	MOVE.L	WT_LBN,D1	;Find logical track number on whole disk
	MOVEQ	#0,D0
	MOVE.B	WI_SPT,D0	;Get sectors per track
	MOVE.W	D0,D2
	SWAP	D1
	CMP.W	D0,D1
	BHI	$100		;Block number was too big
	SWAP	D1
	DIVU	D0,D1		;Logical track number
	
	SWAP	D1		;Find number of leading bytes
	MOVE.W	WI_BPS,D0	;Bytes per Sector
	MULU	D0,D2		;Bytes per Track
	MULU	D1,D0		;Number of leading bytes
	CLR.W	D1
	SWAP	D1
	SUB.W	D0,D2		;Bytes remaining on track
	EXT.L	D2
	MOVE.W	D0,WT_LEAD	;Number of leading bytes
	MOVE.L	WT_LENG,D0
	CMP.L	D0,D2
	BLT.S	$10		;Not enough data in track for total
	
	SUB.W	D0,D2		;Find trailing bytes
	MOVE.W	D2,WT_TRAIL	;Trailing data bytes
	
	MOVE.W	D0,WT_NUMB	;Number of data bytes
	BRA.S	$20

$10	MOVE.W	D2,WT_NUMB	;Number of data bytes
	CLR.W	WT_TRAIL	;Number of Trailing data bytes

;	Check for limit on logical device
$20	ADD.W	WI_BASE,D1	;Form mapped track number
	BCS.S	$100		;Track too large
	CMP.W	WI_TOP,D1
	BHI.S	$100		;Track too large
	
;	Now check for logical track in Bad Track table
	LEA	WI_BTTBL,A1	;Address bad track table
$30	MOVE.W	(A1)+,D0	;Get bad track number
	BEQ.S	$50		;No more bad tracks
	CMP.W	D0,D1
	BCS.S	$50		;Target track < Bad track
	ADDQ.W	#1,D1		;Skip a track
	BRA	$30

$50	MOVE.W	D1,WT_LTN	;Set up logical track number
	MOVEQ	#0,D0
	MOVE.B	WI_HEADS,D0
	DIVU	D0,D1		;Find cylinder number
	MOVE.W	D1,WT_CYL
	SWAP	D1
	MOVE.W	D1,WT_HEAD	;Head number
	CLR.B	D0		;EQ means success
	RTS

$100	MOVE.B	#-11.,WS_ERR	;Block number out of range
	RTS

$110	MOVE.B	#-14.,WS_ERR	;Bad device number
	RTS

.PAGE
;****************************************************************************
;
;	Winchester Recalibrate
;
;	Uses: D0
;
;****************************************************************************

WDRECAL
	MOVE.L	D2,-(SP)
	MOVE.W	#2000.,D2	;Max at 2000 cylinders
$10	BTST	#WB_TRK0,WP_1A
	BEQ.S	$30		;Recalibrate is done
	SUBQ.W	#1,D2
	BEQ.S	$20		;Recalibrate failure
	MOVE.B	#0CH,WP_1CB	;Step toward track zero
	MOVEQ	#1,D1		;Only 1 step
	BSR	WDSTEP		;Step the head
	TST.B	WS_ERR
	BNE	$110		;Found stepping error
	
	MOVEQ	#20.,D0		;Set up timeout
	SWAP	D0
$15	BTST	#WB_SKCMP,WP_1A ;Check if seek complete
	BEQ	$10		;Seek complete continue
	SUBQ.L	#1,D0
	BEQ.S	$20		;Timeout report error
	BRA	$15

;	Recalibrate failed
$20	MOVEQ	#-3,D0		;Recalibrate failure
	BRA	$100

;	Initial recalibrate is done, step out
$30	MOVE.B	#0DH,WP_1CB	;Now step away from track 0
	MOVEQ	#10.,D1		;Step ten
	BSR	WDSTEP
	TST.B	WS_ERR
	BNE	$110		;Found stepping error
	
	MOVEQ	#20.,D0		;Set up timeout
	SWAP	D0
$40	BTST	#WB_SKCMP,WP_1A ;Check if seek complete
	BEQ.S	$45
	SUBQ.L	#1,D0
	BEQ	$20		;Timeout report error
	BRA	$40
$45	BTST	#WB_TRK0,WP_1A
	BEQ	$20		;Should not be at track 0

;	Now recalibrate again
	MOVE.W	#2000.,D2	;Max at 2000 cylinders
$50	BTST	#WB_TRK0,WP_1A
	BEQ.S	$70		;Recalibrate is done
	SUBQ.W	#1,D2
	BEQ.S	$20		;Recalibrate failure
	MOVE.B	#0CH,WP_1CB	;Step toward track zero
	MOVEQ	#1,D1		;Only 1 step
	BSR	WDSTEP		;Step the head
	TST.B	WS_ERR
	BNE.S	$110		;Found stepping error
	
	MOVEQ	#20.,D0		;Set up timeout
	SWAP	D0
$60	BTST	#WB_SKCMP,WP_1A ;Check if seek complete
	BEQ	$50		;Seek complete continue
	SUBQ.L	#1,D0
	BEQ	$20		;Timeout report error
	BRA	$60

$70	MOVE.W	#9500.,D0	;Head settle time
$80	DBF	D0,$80
	CLR.B	D0		;EQ means recalibrate good
	CLR.W	WS_CCYL		;Clear current cylinder number
	ST	WS_RCAL		;Indicate recalibrated
$100	MOVE.B	D0,WS_ERR
$110	MOVE.L	(SP)+,D2
	RTS

.PAGE
;****************************************************************************
;
;	Winchester Seek
;
;	Uses: D0,D1
;
;****************************************************************************

WDSEEK
	BTST	#WB_SKCMP,WP_1A ;Check if seek complete
	BNE.S	$200		;Seek is not complete
	TST.B	WS_RCAL		;Check for recalibrate
	BNE.S	$10		;No recalibrate
	BSR	WDRECAL		;Recalibrate the drive
	BNE.S	$110		;Recalibrate error
$10	MOVE.B	WP_1C,D0	;Set up head number
	ANDI.B	#0F8H,D0
	OR.W	WT_HEAD,D0
	MOVE.B	D0,WP_1C
	MOVE.W	WS_CCYL,D1	;Get current cylinder number
	SUB.W	WT_CYL,D1	;New cylinder number
	BEQ.S	$100		;Already at cylinder
	BGT.S	$20		;Current cylinder > new cylinder
;	Current cylinder is < new cylinder
	NEG.W	D1		;Make number positive
	MOVE.B	#0DH,WP_1CB	;Step to higher track
	BRA.S	$30

;	Current cylinder is > new cylinder
$20	MOVE.B	#0CH,WP_1CB	;Step to lower track
$30	BSR	WDSTEP		;Step the drive
	TST.B	WS_ERR
	BNE.S	$110		;Found stepping error
	MOVEQ	#-1,D1		;Step timeout
$45	ROR.B	#8,D1		;Just for delay
	BTST	#WB_SKCMP,WP_1A ;Check for seek complete
	DBEQ	D1,$45
	BNE.S	$200		;Seek timeout
	
	MOVE.W	WT_CYL,WS_CCYL	;Update current cylinder
$100	MOVEQ	#0,D0		;No error
$105	MOVE.B	D0,WS_ERR	;EQ indicates success
$110	RTS

;	Seek is not complete
$200	MOVEQ	#-3,D0
	BRA	$105

.PAGE
;****************************************************************************
;
;	Winchester Drive select
;
;	Uses: D0
;
;****************************************************************************

WDSELECT
	MOVE.B	WP_1B,D0	;Get previous value
	ANDI.B	#0F0H,D0
	OR.B	WI_SELCT,D0
	MOVE.B	D0,WP_1B
$100	RTS


;****************************************************************************
;
;	Winchester Drive Step
;
;	D1 = Step count
;
;****************************************************************************

WDSTEP
	MOVEM.L D0-D2,-(SP)
	LSL.W	#1,D1		;Multiply step count by 2
	SUBQ.W	#1,D1		; and subtract 1
	MOVE.B	#36H,WP_8253+6	;Set counter 0 int mode 3
	MOVE.B	#0B0H,WP_8253+6 ;Set counter 2 into mode 0
	MOVE.W	WI_STPCT,D0
	MOVE.B	D0,WP_8253	;Low count on counter 0
	LSR.W	#8,D0
	MOVE.B	D0,WP_8253	;High count on counter 0
	MOVEQ	#24.,D2
$1	DBF	D2,$1
	MOVE.B	D1,WP_8253+4	;Low count on counter 2
	ROR.W	#8,D1
	MOVE.B	D1,WP_8253+4	;High count on counter 2
	MOVEQ	#24.,D2
$2	DBF	D2,$2
	BCLR	#0,WP_2B	;Enable stepping
	MOVE.W	#2284.,D2	;4 Milliseconds
$3	DBF	D2,$3
	MOVEQ	#12,D1		;Timeout count
	SWAP	D1
$10	MOVE.B	#80H,WP_8253+6	;Latch counter
	MOVE.B	WP_8253+4,D0	;Check count
	ROL.W	#8,D0
	MOVE.B	WP_8253+4,D0
	ROL.W	#8,D0
	BEQ.S	$20		;Done
	BMI.S	$20		;Done
	SUBQ.L	#1,D1
	BNE	$10		;Try checking again
	MOVE.B	#-3,WS_ERR	;Step timeout failure
	
$20	BSET	#0,WP_2B	;Disable stepping
	MOVEM.L (SP)+,D0-D2
	RTS

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