	.IF	LISTF
	.LIST
	.PAGE
	.ELSE
	.NOLIST
	.ENDC
;****************************************************************************
;
;	Winchester Disk Driver - part 2
;
;	File:	SAGE.BIOSF.TEXT
;	Date:	 7-Jan-84
;	Issue:	2C
;
;
;	COPYRIGHT (c) 1983 SAGE Computer Technology
;	All Rights Reserved
;
;****************************************************************************
;
;	History:
;
;	2     23-Mar-83 Initial SAGE IV release.
;	2A    16-May-83 Added additional CRC check in read after write.
;	2B     2-Jun-83 Changed to self configurable number of heads.
;			Added interrupt driven seek.
;	2C     3-Aug-83 Improved seek error recovery.
;			Added recovery from read after write error detection.
;	2D     7-Jan-84 Added delays for CRC chip.
;
;****************************************************************************

;	Instruction to create delay without making a change
	.MACRO	DELAY
	ROR.B	#8,D0
	.ENDM

;****************************************************************************
;
;	Winchester foreground task dispatcher
;
;****************************************************************************

WDDISP
	BCLR	#FGWIN_B,FGTASKS+1 ;Clear foreground flag
	SUBQ.L	#6,SP		;Make room on stack for return info
	MOVE.L	D0,-(SP)
	MOVE.L	WG_CONT,D0	;Check continuation address
	BEQ.S	$10		;No continuation
	MOVE.W	10.(SP),4(SP)	;Move saved D0 on stack
	MOVE	SR,6(SP)	;Set up return to Winchester routine
	MOVE.L	D0,8(SP)
	MOVEQ	#0,D0
	MOVE.L	D0,WG_CONT	;Cancel further continuations
	MOVE.L	(SP)+,D0
	BRA	FGEXIT

;	False alarm
$10	MOVE.L	(SP)+,D0
	ADDQ.L	#6,SP
	BRA	FGEXIT


;****************************************************************************
;
;	Winchester task timeout
;
;****************************************************************************

WDTIMO
	BCLR	#1,WP_2B	;Disable winchester interrupt
	BSET	#FGWIN_B,FGTASKS+1 ;Set up foreground request
	RTS


;****************************************************************************
;
;	Winchester Seek Check Timeout
;
;****************************************************************************

WDSKTO
	BSET	#FGWIN_B,FGTASKS+1 ;Set up foreground request
	RTS

.PAGE
;****************************************************************************
;
;	Drive Initialization Start
;
;	Saves previous request (if not already init request).
;	Set up read of Device Map and Bad Track Map.
;
;****************************************************************************

WDINIT
	BTST	#5,WT_CTRL(A4)	;Check if formatting
	BNE.S	$110		;Bypass init for formatting
	TST.W	WI_TEST(A4)	;Check if any test mode flags
	BNE.S	$110		;Bypass init for test mode
	TST.B	WT_IMODE(A4)	;Check if already saved
	BNE.S	$10		;Already set up initialization
	MOVE.B	WT_DIR(A4),WX_DIR(A4)
	MOVE.B	WT_CHAN(A4),WX_CHAN(A4)
	MOVE.L	WT_LENG(A4),WX_LENG(A4)
	MOVE.L	WT_MEMA(A4),WX_MEMA(A4)
	MOVE.L	WT_LBN(A4),WX_LBN(A4)
	MOVE.W	WT_CTRL(A4),WX_CTRL(A4)
$10	CLR.B	WT_DIR(A4)	;Request read
	ANDI.B	#0F0H,WT_CHAN(A4) ;Force to logical channel 0 on device
	MOVEA.W #WINITL,A0	;Set up length of init data
	MOVE.L	A0,WT_LENG(A4)
	LEA	WI_MAP(A4),A0
	MOVE.L	A0,WT_MEMA(A4)	;Set up memory address
	CLR.L	WT_LBN(A4)	;Read from block 0
	CLR.W	WT_CTRL(A4)	;Control in zero
	MOVE.B	#1,WT_IMODE(A4) ;Set up initialize request
$100	BSR	WDCLTBL		;Clear tables
$110	RTS

;	Clear bad track and map tables
WDCLTBL
	MOVEM.L D0/A0,-(SP)
	LEA	WI_MAP(A4),A0	;Clear the map area
	MOVE.W	#WINITL-1,D0
$10	CLR.B	(A0)+
	DBF	D0,$10
	MOVEQ	#0,D0
	MOVE.B	WI_HEADS(A4),D0
	MULU	WI_NCYL(A4),D0	;Form number of tracks
	SUBQ.W	#1,D0
	MOVE.W	D0,WI_MAP+2(A4)
	MOVEM.L (SP)+,D0/A0
	RTS
	
;****************************************************************************
;
;	Drive Initialization Completion
;
;	Restores previous request.
;
;****************************************************************************

WDINITC
	MOVE.B	WX_DIR(A4),WT_DIR(A4)
	MOVE.B	WX_CHAN(A4),WT_CHAN(A4)
	MOVE.L	WX_LENG(A4),WT_LENG(A4)
	MOVE.L	WX_MEMA(A4),WT_MEMA(A4)
	MOVE.L	WX_LBN(A4),WT_LBN(A4)
	MOVE.W	WX_CTRL(A4),WT_CTRL(A4)
	CLR.B	WT_IMODE(A4)
	LEA	WI_MAP(A4),A0	;Check the map area
	TST.W	(A0)
	BNE.S	$5		;Not initialized properly
	MOVEQ	#0,D0
	MOVE.W	2(A0),D0	;Form number of tracks
	ADDQ.W	#1,D0
	DIVU	WI_NCYL(A4),D0	;Form number of heads
	SWAP	D0
	TST.W	D0		;Must divide evenly
	BNE.S	$5		;Not good configuration
	SWAP	D0
	CMPI.W	#16.,D0		;Check head limit
	BGT.S	$5		;Head number too big
	MOVE.B	D0,WI_HEADS(A4) ;Store derived number of heads
	RTS

$5	BSR	WDCLTBL		;Clear tables
	RTS
	


.PAGE
;****************************************************************************
;
;	Move data from controller buffer into memory
;
;****************************************************************************

WDMOVEI
	LEA	WP_DATA,A1	;Set up controller port address
	MOVEA.L WT_MEMA(A4),A2	;Set up buffer address
	BSET	#7,WP_2B	;Disable read latch output buffers
	MOVE.B	#0FH,WP_2CB	;Set up CPU access to controller buffer
	MOVE.B	#0DH,WP_2CB	;Strobe to clear address counter
	MOVE.B	#0CH,WP_2CB

;	Handle logical track number
	TST.B	(A1)		;Throw away two bytes
	DELAY
	TST.B	(A1)		; Why, we don't know
	DELAY
	
	MOVE.B	#3,WP_PGCC	;Reset PGC
	DELAY
	MOVE.B	#41H,WP_PGCM	;Set into read mode
	DELAY
	
	MOVE.B	(A1),D0		;High byte of track number
	LSL.W	#8,D0		;Left justify in word
	MOVE.B	(A1),D0		;Low byte of track number
	MOVE.W	D0,WS_RTRK(A4)	;Save track number

;	Handle ignoring leading information
	MOVE.W	WT_LEAD(A4),D2	;Check if any leading data
	BEQ.S	$20		;No leading data
	SUBQ.W	#1,D2		;Adjust for DB instruction
$10	TST.B	(A1)		;Advance counter
	DBF	D2,$10

;	Handle main data
$20	MOVE.W	WT_NUMB(A4),D2	;Get byte count
	SUBQ.W	#1,D2		;Adjust for DB instruction
$30	MOVE.B	(A1),(A2)+	;Get a byte of data
	DBF	D2,$30
	
;	Handle ignoring trailing information
	MOVE.W	WT_TRAIL(A4),D2 ;Check if any trailing data
	BEQ.S	$50		;No trailing data
	SUBQ.W	#1,D2		;Adjust for DB instruction
$40	TST.B	(A1)		;Access to generate CRC
	DBF	D2,$40

;	Now verify the CRC
$50	TST.B	(A1)		;Access CRC bytes
	DELAY
	TST.B	(A1)
	DELAY
	BTST	#0,WP_PGCC
	BNE.S	$100		;Failed CRC

;	Verify the logical track number
	MOVE.W	WS_RTRK(A4),D0
	CMP.W	WT_LTN(A4),D0
	BNE.S	$110		;Failed logical track number
	CLR.B	WS_ERR(A4)	;Indicate success
	RTS
	
;	CRC error
$100	MOVE.B	#-8,WS_ERR(A4)	;CRC Error
	RTS
	
;	Logical track number error
$110	SWAP	D0		;Clear high word
	CLR.W	D0
	SWAP	D0
	MOVEQ	#0,D2
	MOVE.B	WI_HEADS(A4),D2 ;Calculate cylinder
	DIVU	D2,D0
	MOVE.W	D0,WS_CCYL(A4)
	MOVE.B	#-12.,WS_ERR(A4) ;Wrong cylinder
	RTS


.PAGE
;****************************************************************************
;
;	Move data from memory into controller buffer
;
;****************************************************************************

WDMOVEO
	LEA	WP_DATA,A1	;Set up controller port address
	MOVEA.L WT_MEMA(A4),A2	;Set up buffer address
	BSET	#7,WP_2B	;Disable read latch output buffers
	MOVE.B	#0FH,WP_2CB	;Set up CPU access to controller buffer
	MOVE.B	#0DH,WP_2CB	;Strobe to clear address counter
	MOVE.B	#0CH,WP_2CB

;	Set up header
	MOVE.W	WI_HEADC(A4),D2 ;Set up header byte count
	SUBQ.W	#3,D2		;Adjust for DB and sync word
	MOVEQ	#0,D0
$10	MOVE.B	D0,(A1)
	DBF	D2,$10
	MOVE.B	WD_SYNC(A4),(A1) ;Apply sync bit
	MOVE.B	WD_SYNC+1(A4),(A1)
	MOVE.B	#3,WP_PGCC	;Reset PGC

;	Check out logical track number
	MOVE.W	WT_LTN(A4),D0	;Get logical track number
	BTST	#5,WT_CTRL(A4)	;Check for formatting
	BEQ.S	$20		;Not formatting

;	Handle case for formatting
	MOVE.B	#45H,WP_PGCM	;Set PGC into write mode
	ROL.W	#8,D0		;Fetch high byte
	MOVE.B	D0,(A1)		;Output high byte
	ROL.W	#8,D0		;Fetch low byte
	MOVE.B	D0,(A1)
	BRA.S	$30
	
;	Verify logical track number
$20	MOVE.B	#41H,WP_PGCM	;Set PGC into read mode
	DELAY
	MOVEQ	#0,D2
	MOVE.B	(A1),D2		;Fetch high byte
	ROL.W	#8,D2
	MOVE.B	(A1),D2		;Fetch low byte
	CMP.W	D0,D2
	BNE.S	$100		;Found mismatch
	
;	Handle leading bytes
$30	MOVE.W	WT_LEAD(A4),D2	;Get number of leading bytes
	BEQ.S	$50		;No leading bytes
	MOVE.B	#41H,WP_PGCM	;Set PGC into read mode
	DELAY
	SUBQ.W	#1,D2		;Adjust for DB instruction
$40	TST.B	(A1)		;Advance counter
	DBF	D2,$40
	
;	Handle memory to buffer transfer
$50	MOVE.W	WT_NUMB(A4),D2	;Get number of bytes to transfer
	MOVE.B	#45H,WP_PGCM	;Set PGC into write mode
	DELAY
	SUBQ.W	#1,D2		;Adjust for DB instruction
$60	MOVE.B	(A2)+,(A1)	;Get the memory data
	DBF	D2,$60

;	Handle the trailing bytes
	MOVE.W	WT_TRAIL(A4),D2 ;Get number of trailing bytes
	BEQ.S	$80		;No trailing bytes
	MOVE.B	#41H,WP_PGCM	;Set PGC into read mode
	DELAY
	SUBQ.W	#1,D2		;Adjust for DB instruction
$70	TST.B	(A1)		;Accumulate checksum
	DBF	D2,$70
	
;	Read back and store the new CRC
$80	MOVE.B	WP_PGCB,D0	;First block check character
	DELAY
	MOVE.B	WP_PGCB,D2	;Second block check character
	DELAY
	MOVE.B	D0,(A1)		;Send out first block check character
	DELAY
	MOVE.B	D2,(A1)		;Send out second block check character
	MOVE.B	D0,WT_CRC(A4)	;Save written CRC
	MOVE.B	D2,WT_CRC+1(A4)
	MOVE.W	#128-1,D2	;Set up trailing nulls
	MOVEQ	#0,D0
$90	MOVE.B	D0,(A1)
	DBF	D2,$90
	CLR.B	WS_ERR(A4)	;Indicate no error
	RTS
	
;	Error detected on logical track number
$100	MOVEQ	#0,D0
	MOVE.B	WI_HEADS(A4),D0 ;Calculate cylinder
	DIVU	D0,D2
	MOVE.W	D2,WS_CCYL(A4)	;Update current cylinder
	MOVE.B	#-12.,WS_ERR(A4) ;Wrong cylinder number
	RTS

.PAGE
;****************************************************************************
;
;	Move data from Pre-Read buffer into controller buffer
;
;****************************************************************************

WDMOVEP
	LEA	WP_DATA,A1	;Set up controller port address
	LEA	WT_RBWB,A2	;Read before Write buffer address
	BSET	#7,WP_2B	;Disable read latch output buffers
	MOVE.B	#0FH,WP_2CB	;Set up CPU access to controller buffer
	MOVE.B	#0DH,WP_2CB	;Strobe to clear address counter
	MOVE.B	#0CH,WP_2CB

;	Set up header
	MOVE.W	WI_HEADC(A4),D2 ;Set up header byte count
	SUBQ.W	#3,D2		;Adjust for DB and sync word
	MOVEQ	#0,D0
$10	MOVE.B	D0,(A1)
	DBF	D2,$10
	MOVE.B	WD_SYNC(A4),(A1) ;Apply sync bit
	MOVE.B	WD_SYNC+1(A4),(A1)

;	Store logical track number
	MOVE.W	WT_LTN(A4),D0	;Get logical track number
	ROL.W	#8,D0		;Fetch high byte
	MOVE.B	D0,(A1)		;Output high byte
	ROL.W	#8,D0		;Fetch low byte
	MOVE.B	D0,(A1)

;	Handle memory to buffer transfer
	MOVE.W	WT_LEAD(A4),D2	;Get number of leading bytes
	ADD.W	WT_NUMB(A4),D2	;Get number of bytes to transfer
	ADD.W	WT_TRAIL(A4),D2 ;Get number of training bytes
	SUBQ.W	#1,D2		;Adjust for DB instruction
$60	MOVE.B	(A2)+,(A1)	;Get the memory data
	DBF	D2,$60
	RTS
	

.PAGE
;****************************************************************************
;
;	Check data in controller buffer
;
;****************************************************************************

WDVERIFY
	LEA	WP_DATA,A1	;Set up controller port address
	BSET	#7,WP_2B	;Disable read latch output buffers
	MOVE.B	#0FH,WP_2CB	;Set up CPU access to controller buffer
	MOVE.B	#0DH,WP_2CB	;Strobe to clear address counter
	MOVE.B	#0CH,WP_2CB

;	Handle header bytes if read before write
	CMPI.B	#1,WT_TYPE(A4)
	BNE.S	$15		;not read before write
	MOVE.W	WI_HEADC(A4),D2 ;Set up header byte count
	SUBQ.W	#1,D2		;Adjust for DB instruction
$10	TST.B	(A1)
	DBF	D2,$10
	BRA.S	$20

;	Ignore unknown word
$15	TST.B	(A1)
	DELAY
	TST.B	(A1)
	DELAY
	

;	Handle logical track number
$20	MOVE.B	#3,WP_PGCC	;Reset PGC
	DELAY
	MOVE.B	#41H,WP_PGCM	;Set into read mode
	DELAY
	MOVE.B	(A1),D0		;High byte of track number
	LSL.W	#8,D0		;Left justify in word
	MOVE.B	(A1),D0		;Low byte of track number
	MOVE.W	D0,WS_RTRK(A4)	;Save track number

;	Process complete buffer
	MOVE.W	WT_LEAD(A4),D2
	ADD.W	WT_NUMB(A4),D2
	ADD.W	WT_TRAIL(A4),D2
	SUBQ.W	#1,D2		;Adjust for DB instruction
	CMPI.B	#1,WT_TYPE(A4)
	BNE.S	$30		;Not read before write
	LEA	WT_RBWB,A0	;Set up buffer address
$25	MOVE.B	(A1),(A0)+	;Accumulate CRC, and save data
	DBF	D2,$25
	BRA.S	$35
	
$30	TST.B	(A1)		;Accumulate CRC
	DBF	D2,$30

;	Now verify the checksum
$35	MOVE.B	(A1),D0		;Access CRC
	DELAY
	MOVE.B	(A1),D2
	DELAY
	BTST	#0,WP_PGCC
	BNE.S	$100		;Failed CRC
	CMPI.B	#3,WT_TYPE(A4)	;Check if read after write
	BNE.S	$40		;Not read after write
	CMP.B	WT_CRC(A4),D0
	BNE.S	$100		;CRC was wrong
	CMP.B	WT_CRC+1(A4),D2
	BNE.S	$100		;CRC was wrong

;	Verify the logical track number
$40	MOVE.W	WS_RTRK(A4),D0	;Check against read track number
	CMP.W	WT_LTN(A4),D0
	BNE.S	$110		;Failed logical track number
	CLR.B	WS_ERR(A4)	;Indicate success
	RTS
	
;	Checksum error
$100	MOVE.B	#-8,WS_ERR(A4)	;CRC Error
	RTS
	
;	Logical track number error
$110	SWAP	D0		;Clear high word
	CLR.W	D0
	SWAP	D0
	MOVEQ	#0,D2
	MOVE.B	WI_HEADS(A4),D2 ;Calculate cylinder
	DIVU	D2,D0
	MOVE.W	D0,WS_CCYL(A4)
	MOVE.B	#-12.,WS_ERR(A4) ;Wrong cylinder
	RTS

.PAGE
;****************************************************************************
;
;	Move data from controller buffer to disk
;
;****************************************************************************

WDWRITE
	MOVE.W	WI_PCOMP(A4),D0 ;Check if beyond precomp track
	CMP.W	WT_CYL(A4),D0
	BLE.S	$3		;Precompensation is required
	
	MOVE.B	#6,WP_2CB	;Set up for no precompensation
	BRA.S	$4
	
$3	MOVE.B	#7,WP_2CB	;Apply precompensation
$4	BSET	#7,WP_2B	;Disable the read latch output buffers
	BCLR	#6,WP_2B	;Enable the write buffer
	MOVE.B	#4,WP_2CB	;Enable Ram outputs
	MOVE.B	#0DH,WP_2CB	;Strobe to clear address counter
	MOVE.B	#0CH,WP_2CB
	MOVE.B	#0EH,WP_2CB	;Set up buffer access to disk
	MOVE.B	#9,WP_2CB	;Enable the write
	MOVE.B	#3,WP_2CB	;Set R/W mode mux to write
	MOVE.B	#0BH,WP_2CB	;Strobe the Enable Index signal
	MOVE.B	#0AH,WP_2CB
	BSET	#1,WP_2B	;Enable winchester interrupt
	RTS
	
	
.PAGE
;****************************************************************************
;
;	Move data from disk to controller buffer
;
;****************************************************************************

WDREAD
	MOVE.B	#2,WP_2CB	;Set the R/W mux to read
	MOVE.B	#8,WP_2CB	;Disable write enable
	BSET	#6,WP_2B	;Disable the write data buffer
	BCLR	#7,WP_2B	;Enable read latch & shift register output
	
;	Set up buffer address counter
	MOVE.B	#0DH,WP_2CB	;Strobe to clear address counter
	MOVE.B	#0CH,WP_2CB
	CMPI.B	#1,WT_TYPE(A4)	;Check for read before write
	BNE.S	$20		;Not read before write
	LEA	WP_DATA,A1	;Set up controller port address
	MOVE.W	WI_HEADC(A4),D2 ;Set up header byte count
	SUBQ.W	#3,D2		;Adjust for DB and unknown word
$10	TST.B	(A1)		;Advance buffer counter
	DBF	D2,$10
$20	MOVE.B	#0EH,WP_2CB	;Set up disk mode for controller buffer
	
	MOVE	#2500H,SR	;Disable most interrupts
;	Load 8253 counters
	MOVE.B	#30H,WP_8253+6	;Set counter 0 into mode 0
	MOVE.B	#70H,WP_8253+6	;Set counter 1 into mode 0
	MOVE.W	WI_LOWC(A4),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
	MOVE.W	WI_HIGHC(A4),D0
	MOVE.B	D0,WP_8253+2	;Low count on counter 1
	LSR.W	#8,D0
	MOVE.B	D0,WP_8253+2	;High count on counter 1
	MOVE.B	#0BH,WP_2CB	;Strobe the Enable Index signal
	MOVE.B	#0AH,WP_2CB
	BSET	#1,WP_2B	;Enable winchester interrupt
	MOVE	#2000H,SR	;Re-enable interrupts
	RTS

.PAGE
;****************************************************************************
;
;	Read/Write controller buffer.
;
;****************************************************************************

WDTEST1
	LEA	WP_DATA,A1	;Set up controller port address
	MOVEA.L WT_MEMA(A4),A2	;Set up buffer address
	BSET	#7,WP_2B	;Disable read latch output buffers
	MOVE.B	#0FH,WP_2CB	;Set up CPU access to controller buffer
	MOVE.B	#0DH,WP_2CB	;Strobe to clear address counter
	MOVE.B	#0CH,WP_2CB
	MOVE.B	#3,WP_PGCC	;Reset PGC
	MOVE.L	WT_LENG(A4),D1	;Get number of bytes to transfer
	SUBQ.W	#1,D1		;Correct for DB instruction
	TST.B	WT_DIR(A4)
	BNE.S	$30		;Write direction
	
;	Perform read of buffer
	MOVE.B	#41H,WP_PGCM	;Set PGC into read mode
	DELAY
$10	MOVE.B	(A1),(A2)+
	DBF	D1,$10

;	Save CRC value
$20	MOVE.B	WP_PGCB,D0	;Get CRC value
	LSL.W	#8,D0
	MOVE.B	WP_PGCB,D0
	MOVE.W	D0,WI_CRC(A4)	;Save CRC value
	RTS

;	Perform write to buffer
$30	MOVE.B	#45H,WP_PGCM	;Set PGC into write mode
	DELAY
$40	MOVE.B	(A2)+,(A1)
	DBF	D1,$40
	BRA	$20		;Handle CRC

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