*----------------------------------------------------------------
*
* CP/68 disk driver for an Altair 680 connected to a Pertec
*    FD3712 through a UIO interface board. This code assumes
*    the PIAs on the UIO board and the FD3712 controller have
*    already been configured for use by the disk boot PROM.
*
*    Ver      Date		     Description
*    ---   ----------   -----------------------------------------
*    1.0   07/30/2022	Mike Douglas, Original
*
*----------------------------------------------------------------
PROMLOC	equ	$FC00		;boot and I/O PROM
RDSEC	equ	PROMLOC+9	;read sector routine
DOCMD	equ	PROMLOC+12	;execute 3712 command

* FCB Equates

FCBSTA	equ	5		STATUS 
FCBDBA	equ	7		DATA BUFFER ADDRESS
FCBDRV	equ	9		DRIVE#
FCBTRK	equ	10		TRACK# 
FCBSCT	equ	11		SECTOR# 

* User registers on the SWI stack

UA     equ	6		RETURN "A"
UXH    equ	7		X-REG (FCBADR)

* FD3712 controller commands

cSTATUS	equ	$00		;read status
cREAD	equ	$03		;read sector
cWRITE	equ	$05		;write sector
cRDCRC	equ	$07		;validate sector CRC
cSEEK	equ	$09		;seek to track
cCLRERR	equ	$0B		;clear error flags
cRESTOR	equ	$0D		;seek to track 0
cSETTRK	equ	$11		;set track to seek
cDRVSEC	equ	$21		;set unit and sector
cWRTBUF	equ	$31		;write buffer
cRDBUF	equ	$41		;read buffer
cRESET	equ	$81		;reset the controller

* FD3712 controller status bits

sBUSY	equ	$01		;1=busy
sCRCERR	equ	$08		;1=CRC error
sWRTPRT	equ	$10		;1=write protected
sNOTRDY	equ	$20		;1=drive not ready
sERROR	equ	$29		;any error bit except write protect

* UIO interface board
*   PIA #1 (IC-C) port A is status/data in
*   PIA #1 (IC-C) port B is command out
*   PIA #2 (IC-B) port A is not used
*   PIA #2 (IC-B) port B is data out
*
*   Command bit 0 (the execute bit) comes from the OR of
*   the data-out and data-in handshake lines from the PIAs.
*   CA2 from PIA #1 is the data-in handshake and CB2 from
*   PIA #2 is the data-out handshake.

UIOBASE	equ	$F000	 	;base address of UIO board
P1ACSR	equ	UIOBASE+$08	;control/status for FDC data in
DATAIN	equ	UIOBASE+$09	;FDC data/status in (IC-C port A)
CMDOUT	equ	UIOBASE+$0B	;FDC command out (IC-C port B)
DATAOUT	equ	UIOBASE+$0F	;FDC data out (IC-B port B)

HSOFF	equ	$3C		;auto handshake off
HSAUTO	equ	$2C		;auto handshake on
NUMTRK	equ	77		;number of tracks on disk

*--------------------------------------------------------------
* init - Initialize the disk driver
*--------------------------------------------------------------
	org	$1D5A		;match original entry point

init	ldaa	#$FF
	staa	curTrk		;track unknown
	staa	curDrv		;drive unknown
	rts
	
* Driver data storage

curTrk	rmb	1		;current track, else $FF if not known
curDrv	rmb	1		;drive num in select position (bits 7,6)
retries	rmb	1
saveX	rmb	2

*--------------------------------------------------------------
* readSec - Read a sector, A:B points to the FCB
*--------------------------------------------------------------
	org	$1D86		;match original entry point
	
readSec	bsr	selDrv		;select the drive
	bne	notRdy		;drive not ready

	jsr	seek		;seek and give sector num
	bne	dskErr

	ldaa	#5		;retry count
	staa	retries

rdRetry	ldx	saveX		;X->FCB
	ldx	FCBDBA,x	;X->buffer	
	jsr	RDSEC		;read sector (in boot PROM)
	beq	xferOk		;success	

	ldaa	#cCLRERR	;clear error in the controller
	jsr	DOCMD
	dec	retries
	bne	rdRetry		;retry
	
dskErr	ldaa	#cCLRERR	;clear error in the controller
	jsr	DOCMD
	ldaa	#5		;code for disk I/O error
	bra	dskExit

notRdy	ldaa	#10		;code for disk not ready
	bra	dskExit
	
xferOk	clra			;code for success

dskExit	tsx			;X->SWI stack frame
	staa	UA,x		;update A (status) in SWI stack frame
	ldx	UXH,x		;X->FCB
	oraa	FCBSTA,x	;include new error bits
	staa	FCBSTA,x
	rts
	
*--------------------------------------------------------------
* selDrv - Select drive, A:B points to the FCB. Returns
*   non-zero status is drive not ready.
*--------------------------------------------------------------
selDrv	staa	saveX		;A:B points to the FCB
	stab	saveX+1
	ldx	saveX		;X->FCB

	ldab	FCBDRV,x	;B=drive number from FCB
	rorb			;put drive in upper two bits
	rorb
	rorb
	andb	#$C0		;keep drive bits only
	cmpb	curDrv		;different drive?
	beq	chkRdy		;same, see if ready

	stab	curDrv		;curDrv=drive num in select position	
	orab	#1		;include a valid sector number
	ldaa	#cDRVSEC	;select drive/and set sector
	jsr	DOCMD

	ldaa	#$FF		;track number isn't known
	staa	curTrk
	
chkRdy	ldaa	DATAIN		;get drive status
	coma			;data in is inverted
	bita	#sNOTRDY	;test ready bit
	rts

*--------------------------------------------------------------
* wrtSec - Write a sector, A:B points to the FCB
*--------------------------------------------------------------
	org	$1DF1		;match original entry point
wrtSec	bsr	selDrv		;select the drive
	bne	notRdy		;drive not ready
	
	bita	#sWRTPRT	;write protect?
	bne	dskErr		;yes, write protected
	
	bsr	seek		;seek and give sector num
	bne	dskErr

	ldx	FCBDBA,x	;X->buffer
	ldaa	#cWRTBUF	;set controller to write buffer mode
	staa	CMDOUT
	ldab	#128		;B=num bytes to transfer
	
wsLoop	ldaa	0,x		;(5) A=next byte from sector buffer
	staa	DATAOUT		;(5) give it to the controller
	inx			;(4)
	decb			;(2)
	bne	wsLoop		;(4)

	ldaa	#cWRITE		;issue write command
	jsr	DOCMD
	beq	xferOk		;success
	bra	dskErr		;else, error

*--------------------------------------------------------------
* seek - Seek to track and set sector number from the FCB.
*    X points to the FCB. Returns non-zero status if an
*    error occurs.
*--------------------------------------------------------------
seek	ldab	FCBSCT,x	;B=requested sector
	orab	curDrv		;form B=drive and sector
	ldaa	#cDRVSEC	;select drive and set sector
	jsr	DOCMD

	ldab	FCBTRK,x	;B=requested track
	cmpb	curTrk		;same track we're on?
	beq	seekRet		;yes, do nothing

	cmpb	#NUMTRK		;valid track?
	bhs	seekErr		;no
	stab	curTrk		;else save new current track
	beq	seek0		;use restore for track 0, not seek
	
	ldaa	#cSETTRK	;set desired track number
	jsr	DOCMD
	ldaa	#cSEEK		;seek to track
	jmp	DOCMD		;execute and return to caller

seek0	ldaa	#cRESTOR	;issue restore to track 0 command
	jmp	DOCMD		;execute and return to caller
	
seekErr	ldaa	#$FF		;exit with non-zero status
seekRet	rts
	
*--------------------------------------------------------------
* Patches to CP/68 to work with the Altair 680
*--------------------------------------------------------------
	org	$04C4		;console port at $F000
	fdb	$F000

	org	$0010		;SWI vector
	jmp	$0103		;jump into to CP/68

	org	$09A8		;EXIT command to monitor
	fdb	$FFD8		;jump to Altair monitor

	org	$0039		;console parameters

* back space, line-delete, con lines, con line, con width, nulls, tab
	fcb	$08,$15,0,1,0,0,$09

* full duplex, page LFs, pause off, escape, LP lines, LP line, LP width
	fcb	0,0,$FF,$1B,60,0,80

	end
