* DISK TEST UTILITY FOR THE SPHERE 6800 COMPUTER INTERFACED TO A
* PERTEC FD3712 (OR ICOM FD360) DUAL 8" DRIVE CABINET

* SPHERE EXECUTIVE EQUATES

EXEC	EQU	$FC14		;RE-ENTER EXEC
PUTCHR 	EQU	$FCBC		;OUTPUT FROM A
GETCHR 	EQU 	$FC4A		;INPUT FROM CONSOLE TO A

* FD3712 CONTROLLER COMMANDS

CSTATUS	EQU	$FF-$00 	;READ STATUS
CREAD	EQU	$FF-$03		;READ SECTOR
CWRITE	EQU	$FF-$05		;WRITE SECTOR
CRDCRC	EQU	$FF-$07		;VALIDATE SECTOR CRC
CSEEK	EQU	$FF-$09		;SEEK TO TRACK
CCLRERR	EQU	$FF-$0B		;CLEAR ERROR FLAGS
CRESTOR	EQU	$FF-$0D		;SEEK TO TRACK 0
CSETTRK	EQU	$FF-$11		;SET TRACK TO SEEK
CDRVSEC	EQU	$FF-$21		;SET UNIT AND SECTOR
CWRTBUF	EQU	$FF-$31		;WRITE BUFFER
CRDBUF	EQU	$FF-$80		;READ BUFFER (swap bits 6/7)
CRDNEXT	EQU	$FF-$81		;MOVE TO NEXT BYTE (swap bits 6/7)
CRESET	EQU	$FF-$41		;RESET CONTROLLER (swap bits 6/7)

* FD3712 CONTROLLER STATUS BITS

SBUSY	EQU	$01		;1=BUSY
SCRCERR	EQU	$08		;1=CRC ERROR
SNOTRDY	EQU	$20		;1=DRIVE NOT READY
SWRTPRO	EQU	$10		;1=WRITE PROTECTED
SERROR	EQU	$29		;ANY ERROR BIT EXCEPT WRITE PROTECT

* SPHERE PARALLEL I/O BOARD TO FD3712
*    X4 IS DATA IN FROM THE 3712 (E6 PORT A)
*    X5 IS COMMAND OUT TO 3712 (E6 PORT B)
*    X8 IS DATA OUT TO 3712 (E7 PORT B)
*    BITS 6/7 ARE SWAPPED BETWEEN SPHERE AND 3712
*    ALL BITS ARE INVERTED BETWEEN SPHERE AND 3712

X4DR	EQU	$F080		;DATA/DIRECTION
X4CSR	EQU	$F081		;CONTROL/STATUS FOR FDC DATA IN
X5DR	EQU	$F082		;DATA/DIRECTION
X5CSR	EQU	$F083		;CONTROL/STATUS FOR FDC CMD OUT
X7DR	EQU	$F084		;DATA/DIRECTION
X7CSR	EQU	$F085		;NOT CONNECTED/USED
X8DR	EQU	$F086		;DATA/DIRECTION
X8CSR	EQU	$F087		;CONTROL/STATUS FOR FDC DATA OUT

CMDOUT	EQU	X5DR		;FDC COMMAND OUT
DATAIN	EQU	X4DR		;FDC DATA/STATUS IN
DATAOUT	EQU	X8DR		;FDC DATA OUT

DDRENA	EQU	$30		;ACCESS DATA DIRECTION REGISTER
DRENA	EQU	$34		;ACCESS DATA REGISTER

CR	EQU	$0D

* ENTER PROGRAM AT $200

	ORG	$0200
	SEI			;ENSURE INTERRUPTS ARE DISABLED
	LDS	#$01FF		;STACK JUST BELOW ORIGIN

* INIT THE PIAS

	LDAA	#DDRENA		;A=ACCESS DATA DIRECTION REGISTER
	STAA	X4CSR		;DATA IN PORT
	CLR	X4DR		;0=ALL BITS ARE INPUTS
	
	LDAB	#DRENA		;ACCESS DATA REGISTER
	STAB	X4CSR		;DATA IN PORT
	STAB	X5CSR		;COMMAND PORT
	STAB	X7CSR		;X7 IS NOT USED
	STAB	X8CSR		;DATA OUT PORT

	LDAB	#$FF		;DATA VALUE TO ZERO (INVERTED)
	STAB	X5DR		;COMMAND PORT
	STAB	X7DR
	STAB	X8DR		;DATA OUT PORT

	STAA	X5CSR		;COMMAND PORT DDR
	STAA	X7CSR
	STAA	X8CSR		;DATA OUT PORT DDR
	STAB	X5DR		;COMMAND PORT IS OUTPUT
	STAB	X7DR
	STAB	X8DR		;DATA OUT PORT IS OUTPUT

	LDAA	#DRENA		;BACK TO DATA REGISTERS
	STAA	X5CSR		;COMMAND PORT
	STAA	X7CSR
	STAB	X8CSR		;DATA PORT

	LDAA	X4DR		;READ ALL DATA REGISTERS TO CLEAR
	LDAA	X5DR		;  ANY SPURIOUS INTERRUPS
	LDAA	X7DR
	LDAA	X8DR

	LDAA	#CRESET		;RESET THE 3712 CONTROLLER
	JSR	DOCMD

* MENU LOOP

MENU	LDAA	#CCLRERR	;CLEAR ANY ERROR
	JSR	DOCMD

	LDX	#MMENU		;DISPLAY MENU, GET RESPONSE
	JSR	DSPMSG
	LDAA	SECNUM		;DISPLAY CURRENT SECTOR
	JSR	DSPBYTE
	LDX	#MMENU2
	JSR	DSPMSG
	JSR	GETCHR

	PSHA			;CR AFTER USER INPUT
	LDAA	#CR
	JSR	PUTCHR
	PULA

	CMPA	#'X		;EXIT?
	BEQ	EXIT

	CLRB			;SELECT DRIVE 0
	CMPA	#'A
	BEQ	SELDRV

	INCB			;SELECT DRIVE 1
	CMPA	#'B
	BEQ	SELDRV

	CMPA	#'H		;HOME
	BEQ	RESTORE

	CMPA	#'R		;READ NEXT SECTOR
	BEQ	READ

	CMPA	#'W		;WRITE SECTOR IN SECNUM
	BEQ	WRITE

	SUBA	#'1		;1-9?
	CMPA	#9
	BCC	MENU		;INVALID
	ADDA	#1		;ELSE, TRACK 1-9

* SEEK TO TRACK IN A, RESET SECNUM

	TAB
	LDAA	#CSETTRK	;SET DESIRED TRACK
	JSR	CMDDAT		;ISSUE COMMAND WITH DATA
	LDAA	#CSEEK		;DO THE SEEK
	JSR	DOCMD
	CLR	SECNUM
	BRA	MENU

* EXIT - EXIT TO MONITOR

EXIT	JMP	EXEC		;RE-ENTER MONITOR

* SELDRV - SELECT DRIVE IN B

SELDRV	RORB			;PUT IN UPPER TWO BITS
	RORB
	RORB
	ANDB	#$C0
	STAB	DRVNUM

	ORAB	#1		;FORM DRIVE WITH VALID SECTOR
	LDAA	#CDRVSEC
	JSR	CMDDAT		;ISSUE COMMAND WITH DATA
	BRA	MENU

* RESTORE - RESTORE TO TRACK 0, RESTART SECNUM

RESTORE	LDAA	#CRESTOR
	JSR	DOCMD
	CLR	SECNUM
	BRA	MENU

* READ - READ SECTOR SECNUM INTO RAM AT $0F00

READ	BSR	READSEC
	BRA	MENU

* WRITE - WRITE SECTOR SECNUM FROM RAM AT $0F00

WRITE	BSR	WRTSEC
	BRA	MENU

* READSEC - READ SECTOR SECNUM

READSEC	INC	SECNUM		;INCREMENT AND WRAP SECTOR NUMBER
	LDAB	SECNUM
	CMPB	#27
	BNE	RSSECOK
	CLR	SECNUM
	BRA	READSEC

RSSECOK	ORAB	DRVNUM		;FORM DRIVE:SECTOR
	LDAA	#CDRVSEC
	JSR	CMDDAT		;ISSUE COMMAND WITH DATA

	LDAA	#CREAD		;ISSUE READ COMMAND
	JSR	DOCMD
	BNE	RSEXIT		;ERROR

	LDX	#$0F00		;LOAD INTO RAM AT $0F00
	LDAB	#128		;B=NUM BYTES TO TRANSFER

RSLOOP	LDAA	#CRDBUF		;ENABLE READ BUFFER OUTPUT
	STAA	CMDOUT
	LDAA	DATAIN		;GET BYTE FROM FIFO
	STAA	0,X		;STORE IN SECTOR BUFFER
	INX
	LDAA	#CRDNEXT	;SHIFT TO NEXT BYTE
	STAA	CMDOUT
	DECB
	BNE	RSLOOP

	LDAA	#CSTATUS	;EXIT IN STATUS MODE
	STAA	CMDOUT
RSEXIT	RTS

* WRTSEC - WRITE SECTOR SECNUM FROM RAM AT $0F00

WRTSEC	LDAB	SECNUM
	ORAB	DRVNUM		;FORM DRIVE:SECTOR
	LDAA	#CDRVSEC
	JSR	CMDDAT		;ISSUE COMMAND WITH DATA

	LDX	#$0F00		;WRITE FROM RAM AT $0F00
	LDAB	#128		;B=NUM BYTES TO TRANSFER

WSLOOP	LDAA	0,X		;A=NEXT BYTE FROM SECTOR BUFFER
	STAA	DATAOUT		;GIVE IT TO THE CONTROLLER
	INX
	LDAA	#CWRTBUF	;LATCH BYTE INTO THE CONTROLLER
	STAA	CMDOUT
	LDAA	#CSTATUS
	STAA	CMDOUT
	DECB
	BNE	WSLOOP

	LDAA	#CWRITE		;ISSUE WRITE COMMAND
	BSR	DOCMD
	RTS

* CMDDAT - WRITE B TO THE FDC DATA REGISTER AND THEN A TO THE
*   FDC COMMAND REGISTER. WAIT FOR THE COMMAND TO COMPLETE AND
*   RETURN THE STATUS REGISTER IN A. THE STATUS IS PRE-TESTED
*   WITH ALL ERROR BITS (OTHER THAN WRITE PROTECT).
*
*   THE DATA VALUE IN B IS INVERTED AND BITS 6/7 SWAPPED TO
*   ACCOUNT FOR THE SPHERE/FD3712 INTERFACE WIRING. AFTER THE
*   COMMAND EXECUTES, THE DATA PORT OUTPUT IS IDLED HIGH TO
*   REDUCE CURRENT LOAD ON THE 6821. THE COMMAND PORT ALSO
*   IDLES HIGH DUE SINCE THE STATUS COMMAND IS WRITTEN LAST.

CMDDAT	STAB	TEMP		;SWAP BITS 6 AND 7
	ASLB
	EORB	TEMP		;BIT 7 = 6 XOR 7
	ASRB			;BIT 6 = BIT 7
	ANDB	#$C0		;XOR MASK ALONE
	EORB	TEMP		;FINISH SWAP
	COMB			;DATA IS INVERTED	
	STAB	DATAOUT		;SET DATA OUT

DOCMD	STAA	CMDOUT		;GIVE COMMAND BYTE TO CONTROLLER
	LDAB	#CSTATUS	;STATUS COMMAND CLEARS BIT 0
	STAB	CMDOUT

WTCMD	LDAA	DATAIN		;WAIT FOR NOT BUSY
	BITA	#SBUSY
	BEQ	WTCMD		;STILL BUSY (INVERTED)

	STAB	DATAOUT		;IDLE DATA OUT ALL HIGH	
	COMA			;DATA IN IS INVERTED
	BITA	#SERROR		;TEST ERROR BITS
DCRTS	RTS

* DSPBYTE - DISPLAY THE BYTE IN A

DSPBYTE	PSHA			;SAVE BYTE TO DISPLAY
	LSRA			;GET UPPER NIBBLE ALONE
	LSRA
	LSRA
	LSRA
	BSR	DSPNIB		;DISPLAY THE NIBBLE

	PULA			;GET BACK ORIGINAL BYTE
	ANDA	#$0F		;GET LOWER NIBBLE ALONE

DSPNIB	ADDA	#'0		;CONVERT TO ASCII
	CMPA	#'9		;0-9?
	BLS	DNEXIT
	ADDA	#7		;ELSE, A-F TO 'A' TO 'F'
DNEXIT	JMP	PUTCHR		;DISPLAY THE DIGIT AND EXIT

* DSPMSG - DISPLAY NULL TERMINATED STRING POINTED TO BY X

DSPMSG	LDAA	0,X		;GET NEXT CHARACTER
	BEQ	DCRTS		;ZERO = END OF STRING
	STX	TEMP
	JSR	PUTCHR		;ELSE, DISPLAY CHARACTER
	LDX	TEMP
	INX
	BRA	DSPMSG

* MESSAGES

MMENU	FCB	CR,CR
	FCC	'=== FD3712 UTILITY ==='
	FCB	CR,CR
	FCC	'A) SELECT DRIVE 0'
	FCB	CR
	FCC	'B) SELECT DRIVE 1'
	FCB	CR
	FCC	'H) HOME (TO TRACK 0)'
	FCB	CR
	FCC	'1-9) SEEK TRACK 1-9' 
	FCB	CR
	FCC	'R) READ NEXT SECTOR TO $0F00'
	FCB	CR
	FCC	'W) WRITE SECTOR FROM $0F00'
	FCB	CR
	FCC	'X) EXIT TO MONITOR'
	FCB	CR
	FCC	'(CURRENT SECTOR IS '
	FCB	0

MMENU2	FCC	')'
	FCB	CR,CR
	FCC	'INPUT SELECTION: '
	FCB	0

DRVNUM	FCB	0
SECNUM	FCB	0
TEMP	RMB	2

	END
